From 0a60f6cf8965586a1b6cfdd68852f236337aee3b Mon Sep 17 00:00:00 2001 From: baiywt Date: Wed, 8 Nov 2023 14:18:25 +0800 Subject: [PATCH] net: wireless: rockchip_wlan: bcmdhd: Update to 101.10.591.x --- .../rkwifi/bcmdhd.101.10.591.x.rk.7z | Bin 0 -> 2105332 bytes .../rockchip_wlan/rkwifi/bcmdhd/Kconfig | 24 +- .../rockchip_wlan/rkwifi/bcmdhd/Makefile | 233 +- .../rockchip_wlan/rkwifi/bcmdhd/aiutils.c | 47 +- .../rkwifi/bcmdhd/bcm_app_utils.c | 42 +- .../rkwifi/bcmdhd/bcm_l2_filter.c | 766 - .../rockchip_wlan/rkwifi/bcmdhd/bcmbloom.c | 13 +- .../rockchip_wlan/rkwifi/bcmdhd/bcmevent.c | 48 +- .../rkwifi/bcmdhd/bcminternal-android.mk | 88 - .../rkwifi/bcmdhd/bcminternal.mk | 60 - .../rockchip_wlan/rkwifi/bcmdhd/bcmsdh.c | 15 +- .../rkwifi/bcmdhd/bcmsdh_linux.c | 71 +- .../rkwifi/bcmdhd/bcmsdh_sdmmc.c | 394 +- .../rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c | 12 +- .../rockchip_wlan/rkwifi/bcmdhd/bcmsdspi.h | 147 - .../rkwifi/bcmdhd/bcmsdspi_linux.c | 433 - .../rockchip_wlan/rkwifi/bcmdhd/bcmsdstd.c | 298 +- .../rockchip_wlan/rkwifi/bcmdhd/bcmsdstd.h | 7 +- .../rkwifi/bcmdhd/bcmsdstd_linux.c | 9 +- .../rockchip_wlan/rkwifi/bcmdhd/bcmspibrcm.c | 1922 --- .../rockchip_wlan/rkwifi/bcmdhd/bcmsrom.c | 6365 -------- .../rockchip_wlan/rkwifi/bcmdhd/bcmstdlib.c | 1251 -- .../rockchip_wlan/rkwifi/bcmdhd/bcmstdlib_s.c | 21 +- .../rockchip_wlan/rkwifi/bcmdhd/bcmutils.c | 900 +- .../rkwifi/bcmdhd/bcmwifi_channels.c | 357 +- .../rkwifi/bcmdhd/bcmwifi_monitor.c | 1071 -- .../rkwifi/bcmdhd/bcmwifi_radiotap.c | 2 +- .../rkwifi/bcmdhd/bcmwifi_rates.c | 607 - .../rkwifi/bcmdhd/bcmwifi_rspec.c | 274 - .../rockchip_wlan/rkwifi/bcmdhd/bcmwpa.c | 2648 ---- .../rockchip_wlan/rkwifi/bcmdhd/bcmxtlv.c | 21 +- .../rockchip_wlan/rkwifi/bcmdhd/dbus.c | 1193 +- .../rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c | 338 +- .../rkwifi/bcmdhd/dbus_usb_linux.c | 1961 ++- .../rockchip_wlan/rkwifi/bcmdhd/dhd.h | 1362 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_bitpack.c | 228 - .../rockchip_wlan/rkwifi/bcmdhd/dhd_bitpack.h | 2 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h | 59 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_buzzz.h | 224 - .../rockchip_wlan/rkwifi/bcmdhd/dhd_ccode.c | 14 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c | 155 +- .../rkwifi/bcmdhd/dhd_cfg80211.c | 50 +- .../rkwifi/bcmdhd/dhd_cfg80211.h | 6 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_common.c | 3240 +++-- .../rockchip_wlan/rkwifi/bcmdhd/dhd_config.c | 1338 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_config.h | 78 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_csi.c | 900 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_csi.h | 440 +- .../rkwifi/bcmdhd/dhd_custom_cis.c | 2010 --- .../rkwifi/bcmdhd/dhd_custom_exynos.c | 333 - .../rkwifi/bcmdhd/dhd_custom_gpio.c | 341 +- .../rkwifi/bcmdhd/dhd_custom_hikey.c | 90 +- .../rkwifi/bcmdhd/dhd_custom_memprealloc.c | 174 +- .../rkwifi/bcmdhd/dhd_custom_msm.c | 283 - .../rkwifi/bcmdhd/dhd_custom_sec.c | 1040 -- .../rockchip_wlan/rkwifi/bcmdhd/dhd_dbg.h | 508 +- .../rkwifi/bcmdhd/dhd_dbg_ring.c | 112 +- .../rkwifi/bcmdhd/dhd_dbg_ring.h | 20 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_debug.c | 1253 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_debug.h | 98 +- .../rkwifi/bcmdhd/dhd_debug_linux.c | 200 +- .../rkwifi/bcmdhd/dhd_event_log_filter.c | 170 +- .../rkwifi/bcmdhd/dhd_event_log_filter.h | 2 +- .../rkwifi/bcmdhd/dhd_flowring.c | 206 +- .../rkwifi/bcmdhd/dhd_flowring.h | 59 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_fwtrace.c | 563 - .../rockchip_wlan/rkwifi/bcmdhd/dhd_fwtrace.h | 55 - .../rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c | 162 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c | 13 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_ip.h | 6 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c | 12046 ++++------------ .../rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h | 301 +- .../rkwifi/bcmdhd/dhd_linux_exportfs.c | 1284 +- .../rkwifi/bcmdhd/dhd_linux_lb.c | 266 +- .../rkwifi/bcmdhd/dhd_linux_pktdump.c | 311 +- .../rkwifi/bcmdhd/dhd_linux_pktdump.h | 29 +- .../rkwifi/bcmdhd/dhd_linux_platdev.c | 348 +- .../rkwifi/bcmdhd/dhd_linux_priv.h | 160 +- .../rkwifi/bcmdhd/dhd_linux_rx.c | 1691 +++ .../rkwifi/bcmdhd/dhd_linux_sched.c | 23 +- .../rkwifi/bcmdhd/dhd_linux_sock_qos.c | 1034 -- .../rkwifi/bcmdhd/dhd_linux_sock_qos.h | 64 +- .../rkwifi/bcmdhd/dhd_linux_tx.c | 1290 ++ .../rkwifi/bcmdhd/dhd_linux_tx.h | 49 + .../rkwifi/bcmdhd/dhd_linux_wq.c | 2 +- .../rkwifi/bcmdhd/dhd_linux_wq.h | 7 +- .../rkwifi/bcmdhd/dhd_log_dump.c | 2480 ++++ .../rkwifi/bcmdhd/dhd_log_dump.h | 402 + .../rockchip_wlan/rkwifi/bcmdhd/dhd_macdbg.c | 746 - .../rockchip_wlan/rkwifi/bcmdhd/dhd_macdbg.h | 34 - .../rockchip_wlan/rkwifi/bcmdhd/dhd_mschdbg.c | 12 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_mschdbg.h | 4 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c | 4662 +++--- .../rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c | 5140 ++++--- .../rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h | 270 +- .../rkwifi/bcmdhd/dhd_pcie_linux.c | 1106 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_pktlog.c | 443 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_pktlog.h | 18 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_plat.h | 51 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c | 180 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_pno.h | 15 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_proto.h | 100 +- .../rkwifi/bcmdhd/dhd_qos_algo.h | 90 - .../rockchip_wlan/rkwifi/bcmdhd/dhd_rtt.c | 1139 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_rtt.h | 14 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c | 1497 +- .../rkwifi/bcmdhd/dhd_sec_feature.h | 226 - .../rkwifi/bcmdhd/dhd_static_buf.c | 336 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_statlog.c | 4 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_statlog.h | 2 +- .../rkwifi/bcmdhd/dhd_timesync.c | 1239 -- .../rkwifi/bcmdhd/dhd_timesync.h | 68 - .../rockchip_wlan/rkwifi/bcmdhd/dhd_wet.c | 1187 -- .../rockchip_wlan/rkwifi/bcmdhd/dhd_wet.h | 60 - .../rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c | 249 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h | 17 +- .../rockchip_wlan/rkwifi/bcmdhd/frag.c | 91 +- .../rkwifi/bcmdhd/ftdi_sio_external.h | 39 - .../rockchip_wlan/rkwifi/bcmdhd/fwpkg_utils.c | 391 + .../rockchip_wlan/rkwifi/bcmdhd/hnd_pktpool.c | 449 +- .../rockchip_wlan/rkwifi/bcmdhd/hnd_pktq.c | 128 +- .../rockchip_wlan/rkwifi/bcmdhd/hndlhl.c | 1241 -- .../rockchip_wlan/rkwifi/bcmdhd/hndmem.c | 423 - .../rockchip_wlan/rkwifi/bcmdhd/hndpmu.c | 444 +- .../rkwifi/bcmdhd/include/802.11.h | 4493 +----- .../rkwifi/bcmdhd/include/802.11ac.h | 487 + .../rkwifi/bcmdhd/include/802.11ah.h | 4 +- .../rkwifi/bcmdhd/include/802.11ax.h | 135 +- .../rkwifi/bcmdhd/include/802.11az.h | 637 + .../rkwifi/bcmdhd/include/802.11brcm.h | 348 + .../rkwifi/bcmdhd/include/802.11cust.h | 76 + .../rkwifi/bcmdhd/include/802.11e.h | 133 - .../rkwifi/bcmdhd/include/802.11k.h | 928 ++ .../rkwifi/bcmdhd/include/802.11n.h | 384 + .../rkwifi/bcmdhd/include/802.11owe.h | 62 + .../rkwifi/bcmdhd/include/802.11r.h | 55 - .../rkwifi/bcmdhd/include/802.11s.h | 27 +- .../rkwifi/bcmdhd/include/802.11u.h | 200 + .../rkwifi/bcmdhd/include/802.11v.h | 794 + .../bcmdhd/include/{bcmspi.h => 802.11w.h} | 43 +- .../rkwifi/bcmdhd/include/802.11wapi.h | 70 + .../rkwifi/bcmdhd/include/802.11wfa.h | 245 + .../rkwifi/bcmdhd/include/802.11z.h | 142 + .../rkwifi/bcmdhd/include/802.1d.h | 2 +- .../rkwifi/bcmdhd/include/802.3.h | 2 +- .../rkwifi/bcmdhd/include/aidmp.h | 2 +- .../rkwifi/bcmdhd/include/bcm_fwtrace.h | 111 - .../rkwifi/bcmdhd/include/bcm_l2_filter.h | 99 - .../rkwifi/bcmdhd/include/bcm_mpool_pub.h | 8 +- .../rkwifi/bcmdhd/include/bcm_ring.h | 4 +- .../rkwifi/bcmdhd/include/bcmarp.h | 2 +- .../rkwifi/bcmdhd/include/bcmbloom.h | 2 +- .../rkwifi/bcmdhd/include/bcmcdc.h | 2 +- .../rkwifi/bcmdhd/include/bcmdefs.h | 346 +- .../rkwifi/bcmdhd/include/bcmdevs.h | 58 +- .../rkwifi/bcmdhd/include/bcmdevs_legacy.h | 26 +- .../rkwifi/bcmdhd/include/bcmdhcp.h | 4 +- .../rkwifi/bcmdhd/include/bcmendian.h | 2 +- .../rkwifi/bcmdhd/include/bcmerror.h | 436 +- .../rkwifi/bcmdhd/include/bcmeth.h | 2 +- .../rkwifi/bcmdhd/include/bcmevent.h | 629 +- .../rkwifi/bcmdhd/include/bcmicmp.h | 2 +- .../rkwifi/bcmdhd/include/bcmigmp.h | 74 + .../rkwifi/bcmdhd/include/bcmiov.h | 110 +- .../rkwifi/bcmdhd/include/bcmip.h | 15 +- .../rkwifi/bcmdhd/include/bcmipv6.h | 2 +- .../rkwifi/bcmdhd/include/bcmmsgbuf.h | 171 +- .../rkwifi/bcmdhd/include/bcmnvram.h | 2 +- .../rkwifi/bcmdhd/include/bcmpcie.h | 65 +- .../rkwifi/bcmdhd/include/bcmpcispi.h | 204 - .../rkwifi/bcmdhd/include/bcmperf.h | 2 +- .../rkwifi/bcmdhd/include/bcmproto.h | 2 +- .../rkwifi/bcmdhd/include/bcmrand.h | 2 +- .../rkwifi/bcmdhd/include/bcmsdbus.h | 6 +- .../rkwifi/bcmdhd/include/bcmsdh.h | 13 +- .../rkwifi/bcmdhd/include/bcmsdh_sdmmc.h | 5 +- .../rkwifi/bcmdhd/include/bcmsdpcm.h | 2 +- .../rkwifi/bcmdhd/include/bcmspibrcm.h | 165 - .../rkwifi/bcmdhd/include/bcmsrom.h | 72 - .../rkwifi/bcmdhd/include/bcmsrom_fmt.h | 2 +- .../rkwifi/bcmdhd/include/bcmsrom_tbl.h | 1303 -- .../rkwifi/bcmdhd/include/bcmstdlib_s.h | 6 +- .../rkwifi/bcmdhd/include/bcmtcp.h | 2 +- .../rkwifi/bcmdhd/include/bcmtlv.h | 17 +- .../rkwifi/bcmdhd/include/bcmudp.h | 2 +- .../rkwifi/bcmdhd/include/bcmutils.h | 476 +- .../rkwifi/bcmdhd/include/bcmwifi_channels.h | 116 +- .../rkwifi/bcmdhd/include/bcmwifi_monitor.h | 98 - .../rkwifi/bcmdhd/include/bcmwifi_radiotap.h | 2 +- .../rkwifi/bcmdhd/include/bcmwifi_rates.h | 2 +- .../rkwifi/bcmdhd/include/bcmwifi_rspec.h | 2 +- .../rkwifi/bcmdhd/include/bcmwpa.h | 634 - .../rkwifi/bcmdhd/include/bootrommem.h | 97 + .../rkwifi/bcmdhd/include/brcm_nl80211.h | 6 +- .../rockchip_wlan/rkwifi/bcmdhd/include/d11.h | 6055 -------- .../rkwifi/bcmdhd/include/d11_cfg.h | 115 - .../rkwifi/bcmdhd/include/d11reglist_proto.h | 66 - .../rkwifi/bcmdhd/include/d11regs.h | 180 - .../rkwifi/bcmdhd/include/dbus.h | 43 +- .../rkwifi/bcmdhd/include/dhd_daemon.h | 2 +- .../rkwifi/bcmdhd/include/dhdioctl.h | 118 +- .../rkwifi/bcmdhd/include/dngl_rtlv.h | 39 +- .../rkwifi/bcmdhd/include/dngl_stats.h | 355 +- .../rkwifi/bcmdhd/include/dngl_wlhdr.h | 39 - .../rkwifi/bcmdhd/include/dnglevent.h | 20 +- .../rkwifi/bcmdhd/include/dnglioctl.h | 2 +- .../rockchip_wlan/rkwifi/bcmdhd/include/eap.h | 121 - .../rkwifi/bcmdhd/include/eapol.h | 111 +- .../rkwifi/bcmdhd/include/epivers.h | 22 +- .../rockchip_wlan/rkwifi/bcmdhd/include/etd.h | 91 +- .../rkwifi/bcmdhd/include/ethernet.h | 19 +- .../rkwifi/bcmdhd/include/event_log.h | 231 +- .../rkwifi/bcmdhd/include/event_log_payload.h | 1120 +- .../rkwifi/bcmdhd/include/event_log_set.h | 311 +- .../rkwifi/bcmdhd/include/event_log_tag.h | 168 +- .../rkwifi/bcmdhd/include/event_trace.h | 2 +- .../rkwifi/bcmdhd/include/fils.h | 44 +- .../rkwifi/bcmdhd/include/frag.h | 46 + .../rkwifi/bcmdhd/include/fwpkg_utils.h | 80 + .../rkwifi/bcmdhd/include/hnd_armtrap.h | 2 +- .../rkwifi/bcmdhd/include/hnd_cons.h | 4 +- .../rkwifi/bcmdhd/include/hnd_debug.h | 19 +- .../rkwifi/bcmdhd/include/hnd_pktpool.h | 59 +- .../rkwifi/bcmdhd/include/hnd_pktq.h | 9 +- .../rkwifi/bcmdhd/include/hnd_trap.h | 2 +- .../rkwifi/bcmdhd/include/hndchipc.h | 2 +- .../rkwifi/bcmdhd/include/hndd11.h | 121 - .../rkwifi/bcmdhd/include/hnddma.h | 338 - .../rkwifi/bcmdhd/include/hndlhl.h | 6 +- .../rkwifi/bcmdhd/include/hndmem.h | 74 - .../rkwifi/bcmdhd/include/hndoobr.h | 7 +- .../rkwifi/bcmdhd/include/hndpmu.h | 5 +- .../rkwifi/bcmdhd/include/hndsoc.h | 2 +- .../bcmdhd/include/ieee80211_radiotap.h | 33 +- .../rkwifi/bcmdhd/include/linux_osl.h | 362 +- .../rkwifi/bcmdhd/include/linux_pkt.h | 58 +- .../bcmdhd/{frag.h => include/linuxerrmap.h} | 16 +- .../rkwifi/bcmdhd/include/linuxver.h | 155 +- .../rkwifi/bcmdhd/include/lpflags.h | 2 +- .../rockchip_wlan/rkwifi/bcmdhd/include/mbo.h | 16 +- .../rkwifi/bcmdhd/include/miniopt.h | 73 - .../rkwifi/bcmdhd/include/monitor.h | 230 - .../rockchip_wlan/rkwifi/bcmdhd/include/msf.h | 60 - .../rkwifi/bcmdhd/include/msgtrace.h | 9 +- .../rockchip_wlan/rkwifi/bcmdhd/include/nan.h | 465 +- .../rockchip_wlan/rkwifi/bcmdhd/include/nci.h | 96 - .../rockchip_wlan/rkwifi/bcmdhd/include/osl.h | 120 +- .../rkwifi/bcmdhd/include/osl_decl.h | 2 +- .../rkwifi/bcmdhd/include/osl_ext.h | 2 +- .../rockchip_wlan/rkwifi/bcmdhd/include/p2p.h | 163 +- .../bcmdhd/include/packed_section_end.h | 2 +- .../bcmdhd/include/packed_section_start.h | 2 +- .../rkwifi/bcmdhd/include/pcicfg.h | 9 +- .../rkwifi/bcmdhd/include/pcie_core.h | 36 +- .../bcmdhd/include/phy_event_log_payload.h | 3430 +++++ .../rkwifi/bcmdhd/include/sbchipc.h | 92 +- .../rkwifi/bcmdhd/include/sbconfig.h | 2 +- .../rkwifi/bcmdhd/include/sbgci.h | 2 +- .../rkwifi/bcmdhd/include/sbhndarm.h | 2 +- .../rkwifi/bcmdhd/include/sbhnddma.h | 2 +- .../rkwifi/bcmdhd/include/sbhndpio.h | 2 +- .../rkwifi/bcmdhd/include/sbpcmcia.h | 2 +- .../rkwifi/bcmdhd/include/sbsdio.h | 2 +- .../rkwifi/bcmdhd/include/sbsdpcmdev.h | 2 +- .../rkwifi/bcmdhd/include/sbsocram.h | 2 +- .../rkwifi/bcmdhd/include/sbsprom.h | 236 - .../rkwifi/bcmdhd/include/sbsysmem.h | 2 +- .../rkwifi/bcmdhd/include/sdio.h | 6 +- .../rkwifi/bcmdhd/include/sdioh.h | 2 +- .../rkwifi/bcmdhd/include/sdiovar.h | 2 +- .../rkwifi/bcmdhd/include/sdspi.h | 72 - .../rkwifi/bcmdhd/include/siutils.h | 19 +- .../rkwifi/bcmdhd/include/spid.h | 164 - .../rkwifi/bcmdhd/include/trxhdr.h | 2 +- .../rkwifi/bcmdhd/include/typedefs.h | 38 +- .../rkwifi/bcmdhd/include/usbrdl.h | 110 +- .../rkwifi/bcmdhd/include/vlan.h | 2 +- .../rkwifi/bcmdhd/include/wl_bam.h | 11 +- .../rkwifi/bcmdhd/include/wl_bigdata.h | 81 - .../rkwifi/bcmdhd/include/wldev_common.h | 10 +- .../rkwifi/bcmdhd/include/wlfc_proto.h | 74 +- .../rkwifi/bcmdhd/include/wlioctl.h | 11610 +++++++++++---- .../rkwifi/bcmdhd/include/wlioctl_defs.h | 306 +- .../rkwifi/bcmdhd/include/wlioctl_utils.h | 2 +- .../rockchip_wlan/rkwifi/bcmdhd/include/wpa.h | 50 +- .../rockchip_wlan/rkwifi/bcmdhd/include/wps.h | 379 - .../rockchip_wlan/rkwifi/bcmdhd/linux_osl.c | 794 +- .../rkwifi/bcmdhd/linux_osl_priv.h | 10 +- .../rockchip_wlan/rkwifi/bcmdhd/linux_pkt.c | 70 +- .../rockchip_wlan/rkwifi/bcmdhd/linuxerrmap.c | 128 + .../rockchip_wlan/rkwifi/bcmdhd/nciutils.c | 3095 ---- .../rockchip_wlan/rkwifi/bcmdhd/pcie_core.c | 5 +- .../rockchip_wlan/rkwifi/bcmdhd/pom.h | 70 - .../rkwifi/bcmdhd/rk_dhd_pcie_linux.h | 1 + .../rockchip_wlan/rkwifi/bcmdhd/sbutils.c | 13 +- .../rockchip_wlan/rkwifi/bcmdhd/siutils.c | 675 +- .../rkwifi/bcmdhd/siutils_priv.h | 10 +- .../rkwifi/bcmdhd/wb_regon_coordinator.c | 124 +- .../rockchip_wlan/rkwifi/bcmdhd/wifi_stats.h | 140 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_android.c | 8476 +++-------- .../rockchip_wlan/rkwifi/bcmdhd/wl_android.h | 32 +- .../rkwifi/bcmdhd/wl_android_ext.c | 665 +- .../rkwifi/bcmdhd/wl_android_ext.h | 64 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_bam.c | 349 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_bigdata.c | 575 - .../rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c | 8959 +++++++++--- .../rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h | 1121 +- .../rkwifi/bcmdhd/wl_cfg_btcoex.c | 439 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_cfgnan.c | 1424 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_cfgnan.h | 71 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c | 440 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h | 82 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_cfgscan.c | 2984 +++- .../rockchip_wlan/rkwifi/bcmdhd/wl_cfgscan.h | 64 +- .../rkwifi/bcmdhd/wl_cfgvendor.c | 4706 +++++- .../rkwifi/bcmdhd/wl_cfgvendor.h | 473 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_cfgvif.c | 1981 ++- .../rockchip_wlan/rkwifi/bcmdhd/wl_cfgvif.h | 66 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_dbg.h | 1544 -- .../rockchip_wlan/rkwifi/bcmdhd/wl_escan.c | 296 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_escan.h | 138 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_event.c | 5 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_event.h | 0 .../rockchip_wlan/rkwifi/bcmdhd/wl_export.h | 285 - .../rockchip_wlan/rkwifi/bcmdhd/wl_ext_genl.c | 1 - .../rockchip_wlan/rkwifi/bcmdhd/wl_iapsta.c | 1757 ++- .../rockchip_wlan/rkwifi/bcmdhd/wl_iapsta.h | 14 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_iw.c | 301 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_iw.h | 1 - .../rkwifi/bcmdhd/wl_linux_mon.c | 2 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_roam.c | 106 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_timer.c | 611 + .../rockchip_wlan/rkwifi/bcmdhd/wl_timer.h | 8 + .../rockchip_wlan/rkwifi/bcmdhd/wlc_types.h | 714 - .../rkwifi/bcmdhd/wldev_common.c | 113 +- 335 files changed, 78480 insertions(+), 90214 deletions(-) create mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd.101.10.591.x.rk.7z mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/aiutils.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcm_app_utils.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcm_l2_filter.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmbloom.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmevent.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcminternal-android.mk delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcminternal.mk mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdspi.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdspi_linux.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd_linux.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmspibrcm.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsrom.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmstdlib.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmstdlib_s.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmutils.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_channels.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_monitor.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_radiotap.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_rates.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_rspec.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwpa.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmxtlv.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bitpack.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bitpack.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_buzzz.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ccode.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_common.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_csi.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_csi.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_cis.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_exynos.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_gpio.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_hikey.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_memprealloc.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_msm.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_sec.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg_ring.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg_ring.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug_linux.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_event_log_filter.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_event_log_filter.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_flowring.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_flowring.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_fwtrace.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_fwtrace.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_exportfs.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_lb.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_pktdump.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_pktdump.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_priv.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_rx.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sched.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sock_qos.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sock_qos.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_tx.c create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_tx.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_log_dump.c create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_log_dump.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_macdbg.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_macdbg.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_mschdbg.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_mschdbg.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pktlog.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pktlog.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_plat.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_proto.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_qos_algo.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_rtt.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_rtt.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sec_feature.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_statlog.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_statlog.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_timesync.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_timesync.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wet.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wet.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/frag.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/ftdi_sio_external.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/fwpkg_utils.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hnd_pktpool.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hnd_pktq.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hndlhl.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hndmem.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hndpmu.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ac.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ah.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ax.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11az.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11brcm.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11cust.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11e.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11k.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11n.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11owe.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11r.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11s.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11u.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11v.h rename drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/{bcmspi.h => 802.11w.h} (53%) mode change 100755 => 100644 create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11wapi.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11wfa.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11z.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.1d.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.3.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/aidmp.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_fwtrace.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_l2_filter.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_mpool_pub.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_ring.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmarp.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmbloom.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmcdc.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdefs.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs_legacy.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdhcp.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmendian.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmerror.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmeth.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmevent.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmicmp.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmigmp.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmiov.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmip.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmipv6.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmmsgbuf.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmnvram.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmpcie.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmpcispi.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmperf.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmproto.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmrand.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdbus.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdh.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdh_sdmmc.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdpcm.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmspibrcm.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsrom.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsrom_fmt.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsrom_tbl.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmstdlib_s.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmtcp.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmtlv.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmudp.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmutils.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_channels.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_monitor.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_radiotap.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_rates.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_rspec.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwpa.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bootrommem.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/brcm_nl80211.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11_cfg.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11reglist_proto.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11regs.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dbus.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dhd_daemon.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dhdioctl.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_rtlv.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_stats.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_wlhdr.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dnglevent.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dnglioctl.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/eap.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/eapol.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/epivers.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/etd.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/ethernet.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_payload.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_set.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_tag.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_trace.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/fils.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/frag.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/fwpkg_utils.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_armtrap.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_cons.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_debug.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_pktpool.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_pktq.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_trap.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndchipc.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndd11.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnddma.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndlhl.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndmem.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndoobr.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndpmu.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndsoc.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/ieee80211_radiotap.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_pkt.h rename drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/{frag.h => include/linuxerrmap.h} (74%) mode change 100755 => 100644 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linuxver.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/lpflags.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/mbo.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/miniopt.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/monitor.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/msf.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/msgtrace.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/nan.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/nci.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl_decl.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl_ext.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/p2p.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/packed_section_end.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/packed_section_start.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/pcicfg.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/pcie_core.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/phy_event_log_payload.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbconfig.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbgci.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhndarm.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhnddma.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhndpio.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbpcmcia.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsdio.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsdpcmdev.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsocram.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsprom.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsysmem.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdio.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdioh.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdiovar.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdspi.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/siutils.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/spid.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/trxhdr.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/typedefs.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/vlan.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wl_bam.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wl_bigdata.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wldev_common.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlfc_proto.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl_defs.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl_utils.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wpa.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wps.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl_priv.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_pkt.c create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linuxerrmap.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/nciutils.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/pcie_core.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/pom.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/sbutils.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils_priv.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wb_regon_coordinator.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wifi_stats.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_bam.c delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_bigdata.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgnan.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgnan.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgscan.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgscan.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvif.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvif.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_dbg.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_event.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_event.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_export.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_ext_genl.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iapsta.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iapsta.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_linux_mon.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_roam.c create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_timer.c create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_timer.h delete mode 100755 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wlc_types.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wldev_common.c diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd.101.10.591.x.rk.7z b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd.101.10.591.x.rk.7z new file mode 100755 index 0000000000000000000000000000000000000000..8b5947e18247e469b220e161fde42a6149821551 GIT binary patch literal 2105332 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 z zS6!l#=v4c%EyR8g` zG*#7H3qa2Xr0s`K^K-*e+*EMoLD^g<+oK0A4}-V5yw}}e6lb4`@xbi;OH6MRLh`=A zTK$`Dq!9HvS~g?9&g2?ohtV|I8EI+k)%P()(~hm$MlErlX?>L@5G=5&v{jt@*#@ZP zWl=9x&!K^7V$!DgeXu>!8D}=N;d!&NxJG-s#LCFB9%SAWD7bTG&z}cvD3y)@yJegC zjlg25jUdQ)P{Qg+L94|sKO1o2boxa0R4t9ZKxuP#DCVLCe1OVu`6(xF)K6Xex!Uus zZ%p<(h@yA6FggwutLhAT9lS0IMsl>oJBkna?*Uo5<>mJPir7q{>+H`cktjJE;g0-# z#K&>I5{GZ8C<)s(x=+nn(zN1Z%c>#EjcI!!(`TpyMTqw{sxji{=Qq>q0=DX&ah2)g z{(wu-V~ao)=~P;*w>&#eO1_mLzS^}fnYr9%72l>YR2U?nH;uj5=#7=4`%wIyv=lQ1 zS##BoFjLM5Nk#IUOJs z%%Cp%uGs=owhzPZ+bW(O>UOPpO}%^^*P@R^os8&!C&J7ClN|4TfCP>k|2;t4mWl{SN^Hu8tR>1qiwDlP9V%#7mN7d_#W`#9o@@N2aYKHzjB;?_5AVvm(y4M) zI1xX_bA0E)yqOUN7=Wgay{!k?Y&Y~%ftZ>jEr*0hO)F}66p~{ZneSq|>@LAlfchoC zub5ufAc$suS}#sFHtR|l*TpGh>WjUs8fXmZ$ddCu;<@k*nsl|@MxD*f|F-m8`S>Uh zXYQbfy!*NVXfH8L(Z5eu6)I0XItmSP1Xa1QH_;;Mle-IQwP`dMcnf3ed! zPGt9gLJlYtgcVZOHGL>1WN52DdB8d-FM5iofYS4y3-G)3HM0(Km#=_}3GTCz7Ao|{ zX4=^KZtaAy9dNB2xk-#JBcM9!a2RtR0TN_lzb}tO*z%kbQW4-7@BMmUA%G?X{2NNG z!eCUzlhOQVZ-!cPn()8=W_4H`1M2XTaj5x;_y+MM-NQYfd3!!w`;Iqp`XLLej5#M4 zpGjZIw*8$Q>46&b1(vjQH(x8a#l%4uqZD2r)p`4Ke6ROjMpQh#m?^BOz!y3Dtc_jS zG~&_j-1TJzX2~3rpaYFf)Z#QaNLYwf-Y=?aCO20$n?$c8jK!x&P1{r9`Rg?G zDuNSR?ZF_~C9&9|{bE?T;n9yN>FfolW6EKda+^{saovtB!FGk@pN~-^;pu;){iRh^ zhq{zA$wI+fVD<)JI0dr99Pam76wyl2bou?Y#kr&%$Ezw@9gEO;*!u`G*(LLrdH|_*r zsKI-@@(7-)BKtOVKp(sQd8?=SL zvI;1xx#OSg>&&6}LP}&x5dl;yjl_=W4IXT<(r5&FROzJ9!I1pNye9q|z%SB}mp3lj zv8k%5E>zHM%d?-3UrQ!B3G?u%rxiQyqMxE_@X;!|_a_o2ANZJNeLKDl%v9Yhzd^OYdgVH1}}oA2UTg~beows51m_pd?YEh;^xwV zQO@S&C~l_k6lcCoH|%~PaT9ap=!WQxy{NL%WW>SP{b8Co`N<(puJ;&UF$NfnOs>B* z%!nt}?P4WFz8p@e?w2eZQkjerHKEDyVg$liah%9Sm}4RS!nwsLpa5A1`cAd?1#kJ@ z_-UN@gtU`A*nt-B>|_d9txmR@NBr`pF$jb+JX#u_KZmAAGJq9a=fJTsXZvIPi#{_G zdt%%+h0iHpX%K(oe!w1Mj;aWP(iIG)EQ_-eg=S~vsD%K{Q!EL+Im;7O>|ndygv)}ax02dN z9^j1u$YFFRCx*LO8lF@h?Z`BeqQl=^sR$8QD5`PuuciOMGk7F|+$B#=eVn^2ISKIl z4|BIZRhRQ7eyi2@RgZQOO6JNBiDAhZK0B-c3D8N#chBkh+0m{6^p}qx0&H6xoZ1aB zF{pxSfW#W4TtY92O@lK*{>*6pAPBqj`&vy$MEfWVK&D4x@Y1aamC}}LC1z>PNjnyT z$covcht%t)_Njidjys3s?jf&%wHb6VPI@1wqE75->rLuzf?a2#cF(3a+*^D+6}!$e z<*Ncffy{&qnjQ5y#VM>@8>(^$D_@go^d{$b1kq9;gHBD%1ZPnF0SBGMK)9ujj-@0u zl3Dc2UN#Ax8lT3IRP)T3uY~Ti*xHB=mPREkrch zFVrDB)YmMB@lJDvD6n%zh~)80Q-b%_VZwbh)rj-TMraU7Yg^k7kmVY4tlBea^7Xh; zG9r2E5-hA&ocoQW-g~^(2s2weu<28)K@o(YCJ+?pp+1Bc5JaWA9yjo}yg+V>ZPH}4 zSu1I}geE=Z7{6rSR>MQKUYpX*voM^QUo1=a*I-7D^u-6AW}?`G zEMi-{Hc4HxTRPi_AmS}k-{Q9YUK6hAN1N!*WwIUg&F|NvS~+{}W224*L8^BdeVqy% zoXwj3-8wM*AJ&Mn-RGw05oZX{leL-ijSp3YnIqGAA@z|7UdQn8?1xHB++L@1ut|t~ z+&ufeQ50b=t>1hbV0WcvY&%$Y!C*Ikjd@R$?*|XL;9fU3`1KPf4&~KV0A9&MUIJGq zRm5a{FX0BDW*!GuKWNjV3Yc(&OlAl;`BHzc(?!Fcs}g4YWtq9`X_z7$5`}4Xk5jq4 ztFB!h91_5PO`)d>HVy-rP=8R+Ls>3#4zUbz%MPp=z?>hILz_9I1xioc^sDowiU~FY62hiRyI5j1Ob769QX3?<_kw z# zWaXeU#5OG>?*vU${NG+kde6Ba{3|&{l!c3_Zu1uD@RN+X-xKY^CchWTv}Jw9W!A>9 zv*lZ3`oS@n4s_4oB%J_#jk+mgG+K*0JdkuiS1sVjQq`l;58&Ph)(vxM~DqJ-zr_?cg|TdJ7_`Ha zpj5yw_=Tx(E4HoivPHer`TPbxN)XpCpn2Y!bvf@-fsHV5_}#A zHlQ#U!i8%Ra28ZTcZN*qBfV59Ia3_6PMPgNJI1+PrJ=YJg9Yq|_sQ|p^>K{g6xBVL zr_@(%LQMF_U^>6}_ML3@4wzg?otY#5J07G?1lK}1-iOe1#5Yv-j!gO}$b7i%Nti`5 zrUx;RPTC4*?HQcoqC^c}S_BKLGAW~aYD%XYlMKSV0On!cT}qSt812t^RfKQEaW~dP zTp+%D;IrYURLY2B9txZRIFck7K!>+&-@#B-0Z71TqwjwpF}NfR3GJ&CrZ48JEmBn! zK?eWc`vn*Wy1{(EuNtxH=RR)7XMMAgEZ4`w24o}c?D`K%A`-81)?*W|r2BuYPW^?$b>$FomL5`s+rMiY_qNgnG0 zc-n?0CI>k%ove6nMYPsyX@)2TYZX+zc`ge{ z2S%5pp%S;V3@JUp2?JsH?AuX{l+nz`&GD=Z=)H-u4lsepyAY}C<8$Q6-+k*285MCl zdT?#+YSA92Es+c^nOUUrghbMO*UR&P6j~C_x|C{>ZnePKp@^oG5m*-UcMcqC9d^k| zR#$CI4#;N-9jFG8z8PATG8P!FdWNEK-Au#4SKrFJ*08Fqp(MN7c)x5QEN1V(>1W-W zt;*qVWTef`qE@eYkq*aFqvMzc;*=p)ddN%?NcXTR30DREdb+aLUqGTvz8sq8 zA1stI9W8S~n>F%GE(?G-O=#M~$CwVf0bg>`!wAn>>rBn;c3%7l&VFh%ZRH2&c9f$K zbOMbi71TNc7~esvA{8k8j{M1}37YI63rR7hl)VaRE!5>r z@@Jf;ID9+PS<;?4yke9j$QX#;0U321HohIwDSu+MJf^jc!6Uc0Z|HRyU2W^GIwJE2 z@{U(5M(v74V#_+N_8ga1_m}iBp;&lTN?XQR8`i77E{^{KI zxRD2-3?v58h*fQ*S}PQ$?kf00XRO_ZI?ap$p*W=CX*Exl;#8`%)j=&|=*4gUUE)74 z!*8)u&PaL+3O5!3v)b8ohZ)BaGAE zGRA#rdxw1K4R0?wQ*oY7?RByR_F2N(Zgx|X6LO&hK`w$441)@xFchzg&zgFxM8#FM z!s^7!jb3Q$^n2V)ASme^+@6MGWGz{dWnp%7z5B^DW&()VUf_w9*5y2Kzh_xSZRHH3 zd>>;X4iujl`y{g&(V!PcqKao#w%R8_V!;4if%dq7y<0l z49EZv$Z)}ly_g{eE{a;XwCRl?zf0HQ;#9MQ=l%t^U~Dt6-n}m|o{(*_t~l*FjFPN^ z-FFp;&@D9vcbVb$rQGUD1-)A?gC_Okg=W+56RG=k0o3RE-V_okTTEBzP_tMKia*()?&>AD$!hU#bvU7z$!B%HDEO7^^OsoWiSOE2=G*;I;B`)nqd zdmj^F3oi(bhW4W(5rI`7$m-u~1_@OiP7TA_!YWsL_l&hdB7ji0#n#3?TZ`o9S}OY0VGwBPq5_XF`I%kp2k`U=W9CQn$s?<*xsvo zCj)bQ=qnzy_4W;^X)_e+X4vzOfMC?R{-i_GvXMP6ddRQeDS%Lb7}(X&+0JLXg*V`| zT*1E_)&mG+KN+4)EBTm|cSjQ7(Vg!IqU~o4u6aymndpy=a#kU;sg8hD?x5UNh4h%z z!t@6U+FT$N1&s;lF(jToecOIHBy3(uS-0KWXaCVMbCb&TbWLcMR#VPn(J^%3_$+z@jSsR z;eXR~>fq#aWJN5XIL_Jt4<{JJkprs>2$y+K#Fe#*E7VWUasn6t0a^$!wu%X^E54xR zq5DLDhUKMYMOv=zl!Uo}Tm$BSc9ehKwK3LRDL3(T^BE8{h)H<2F}l&NJ4l5_=q1ym zrhE4(tcw^jvMj)!)k#k0kcE7t--!*5NarhkR$g7pV2UjGuu{5_gjbQ%r(HDJVm1YnS(*g(t`T$4GVECbWGMo}#2#9Rgm znbUS4go{j0H9)Po5W{e!D}-qMyG+pLaw}PvPutND0sCidIgLiI53SXkh4~oevQoC$ zOpmO#-a%Wlkio(LCdu2^gCiy-yX5^ocDP;>55K7~cv~nO$PaZTG2h9Pje6Qed>#}+ zb?^|y1Uq~*X)rgjuBKtn_z7a@sqEW?I64mfnN%W-M}=pW=c*7v(+Dv^GWNVERq;W6 zhdoB>Qy-95sX5aq@q2hf>NgoynfVY4Z$(d>w}+YRl8H8Sx6v%X>iCBf6=TseyPDV9 zT_yVnJ?=@v$sH=cFo|c=a2hHN)!Kf&Kbc9c58Xo`{BZml_C163KvPTB(f>*Cyh`c@ zZ>ubsP{+R7+aCl5S6qN~6}nu{_(KcpyNQYMPWimi=Y~}YfooR@npwKiceCy95{@+3 zj*E~xS#bUT8!hOEY>=Uy(0^h*E|WRpP4HhWZ~3NZCnI7nlrTQ7_}*sD#gkTJIq>E* zEhY#+vefhap7#%bhh*#gO}Y|!Pac%}rDdETVfQshgwJA&Yn)-yrhpjEXx|f=yzt{R z6o=W`y{B>!)P}jnbB^^}-Is2ybZj7`yiz@)$cRb2sAr(J2f6qpgz&mPjPeb33eGS( zf^u^Oy5|eYDrJfWSyK7updcl34L_*VA;sq9D_;&3aE6gg;#j3?Il36!tKh#9F+!%3 z&0Cm%8r9B6dg>d46^*UH<+;fKFR{XLDDEp=s)uruEYi(T6@>XA55N#@#CZ_7?Z6cm zMvj5$RLF6Eaj(*@?=`I;6d69KO{QOe`OKS&59g*=+ilL~6>i)4(TlgGbr!%Pvy#q^ zF7P2uH)jH}XqKESdvl&vU=E+9o^;Frv&1h)-1f;P!K7WXzUxxquN_#IyUsexKvwXP z9JcqEq@(4*>=v(m4}!aM*ah16%*#XJnEu4VO}ZDO-a187=@mBeuXU+16LO$RRV zgIc5i|DrEW$QFMQa75s?Em6Rp^dcQMj6+=yCaD!4Bw=itzLDXmU>6)y2qx_|-H@h< z`xnO^0hQ21VYf>BJh0VLk7RU1KO~Z+WmFi(0p|=fj~TJ&3%S8Wy)V*acy%WEq$~w~ zFVeXW`q`7_c{LrXkw?!bd3(wu%lSJDFT|KP*|3^)Vrt-(MNSY1Y0bJ#hWlO{a%|s3 z#5gY9WV>0DFy$Z&&HddHvw)@ZsNDTCnjlfA5d)emHawDu=9;^;n-yu&S_mj(oTQSW zw8jw{l}w=L;pci7s~L`X-~SQ4L1uXF*_2PSP-^M(b=0Ulhj8>fl(ho_tRGKX3-m5-}hhdFYyp2@0nz4-NSsy z5rN1Kh)}DqL1p>@uD|D0kyzP?zB9LTQ{jc&!&Rn4<21Qihuuny{*CfI*fu7Hh^bT5>@O8%8w zr^nzdCWhLxk>hQqk-9s(rF|RtRoZNP1%3ZVN4Hv=3Zm$MOf&jOC^LW3_6K@Y28xL} z@!yAyCA!5scn}PRqIP+ej00}-4U@3dzpjAAp-qgJXL@WApiRi%E%GmnG59~gA~Esh zyJWBMFyT?hPbRkWyc}#PO6k}IN_MYw@q4(U{U4V=rkc^owpy8>%>W0jb$8b%N9$9F-I$^lmyp)*S#F=Y zU+P-bLLHkZ(u0zMuQWgbrPmxRnYUhpcxQto^850(<}Hsv!Cep4Sh*my@e<0T-8|#2w^>fGwh<;}f4x_v6)5$8@pStE8hO&F+%Br~P0vn0mX2 z#C|b`ZNvTP6ceys`k(f8IjyR0Ba8#%mCDgb@g#d`jumWBl^mQ)9fyBtsI5&o`7ZG} zQ#~mQGO%LwGtJAvJmo|!5>Jz8YI#1^09GE85e)~C6(3R5Z2lyD1|54s za5TAB7^FfufkX2=$sl@Prdgk|C~mpD&cfJX3Y-=tsTur@-bR-hf%`V~*Dq8LA<{3} zqp+0qLj{pTgn@FK7o2&@y<&O3C22|Sa-kS2V1n`*)5KEu=bR2!;kNk!I0@ZkZ+1ux zM~-}H(1xbO(Rx?pICYLI?-V}JtFcdh(XBqz#ZtWV8z{e!$F~D|`>|^ZBDi@e)r*&00)aWbUBW_^*;Ad3fIla8Q#qL`(Nxou$3O zssB?uvUCHoNxxq6iL{RSjmY!?bm1*)p}Yme7|$rnZvSCWa$FaXgO*ao37fgVkqH%c zfk8oQO6(7PG^R}8!aT5OxJ_(lT!6gmx8`4K6z=jmdYsANgA^Bt^wi@KaK*4xXsKHC zvA+*>tDH`-A*dBAODtikC{@s1XKqlK{C0zk?}I_b&!6y?jySn zdu12>`g(I&tpT8L0h$Ijwa>tJC7<5v&<6p-ARh;25eI-qXHvvh{;&+i0~65ZyYgxF z|DYIe;tJQj!8}j!8&^;uUEB+8B}PjHx2&{PgXeN1kk#9q(Xw86Fh9H)p+AZJz&_fk z6Ddpy8lX2?62z*2Xdaw9R;FDOQTyV!#O!LZpRw_xRz#&zoAF#I-O#*G{-&IitIoKQ z{Sc%qn{zy0Nggyj-+Ctyb53Z`^x+cXB{h9;z2kvIi6AzO@6%!IJHsC zd8$-75FsV1khy?P7xaFYD`_Y5y9}SQh@hxZP@%J6p|Vtdg*fu2)@Oyd4|GwPv5WhzMC1Ih4Uf?8NaO+A7AuyUv=r^BYB zvl$DAP5UYDY%UH?^(0&z0Ul5DiByAo9DJLNwKH7jW828bTge4pLx>NG553s_72~0B zjx>^HdGiboZbY>AKrUOB-Sf3cw*5qROt|);@A28f;^F0bVo-%f5seJU_|N_2F~8D| zTmXx}4|3X~6z-h^&#)C7uUHecZxdKSl4`*?}6YEAx=4QBrylr6&P3y z1y`g_KVu}ziX_se!Ml#vJUlTqgY>yDn)CS(9tNupp`Wycuoerax~PSA#4LnbG{PTc z^LM7=NQDq|lm*|&W8_#h_Vg7N1iP!eyjOfDJkhmx4KnW@oum%?+$&31G=k@q6{979 ziAN`-A?84auS?du<2br2uMzk2GA?)3V(C9O4I@AC`XhN;=eLn}4AR!#-h>^v!spFN zXl?YdtFkSi!gl{y7tp*VE#`$yVotemMDwsqIP&rrHnEnJA=cSYgTB1_Q`eJve56*V zuJ$G)qR;D^@E8_?T1>3|rNcJAYVO+ZGLetT2df#G~|N~xgi$#Pc$a$%N6%4)bN z@h7oF9bB#P!6FMaQ~F0?<&lL@mFQB2(P2Gfs)qn8FMt4@OEaVFpn4HxcRhGW%y;bG zn}jF7-+{#}3d2KWECYym$+=z)(w&WDQw=;C!f)eT$ z4R;wnc08J1uYHrtB9*sm|G}B=c^u$uE)wWiC1n^y_F<4j+&%|uW2o`Q-We9q`JzLq z5I^{O^)XZ+_WWxRwkN|EfpsgShb_kp!Jy$R_dR+DaY2r8NZ}t0vx`VKqbfhf9BBDf zv~%(*m54%%^24>e0A9u2${{7!EzFHig!Xnya$9yB1$H^ydhG8)0Lmps&oK^xWkX@i zcpe-G(^*{9G%0(AvARl$<0^{T=2wVd(2Y{y%j{%67k|+|G--4X*}xTg3sJH7X0Dbe z9;GW&H$!NXfnGq?4}hkI^+{Pan9k*wdtcl1c1V@Ng*S=nQWSo?rE?RhcDI8QhV=>o#X{4ibqHhio@8*nK1t3f7!NeJaRLuP{?tHE) z822Ky+J5bL^SxMMv`ItcD@-1w~26)>E__k zp`Jig0e^->fkD5Ow79nApjX8&pPme-k2kdAVLX24tS0>^pHIl{v1Nqq9!4byeWc^>;xQ4 zgpM=l^|enI6hzVZgyDESCHri)G^F?v1xyZD0XJa;NwKM|7RKp0T7KhBbI(9$LrEL! zBTUC9iQ{X476|G(z-OfbJeHC(r`1i5W z)kRPiv?hjnU|GA4FHyDMT1Xm?7#26VAmt*~ST^2kE$JS`K{tR3D&#YMwW*|=`q@6W zlMYS};FywQc7_oN*&$K)YT~nlaW>(_`s^_g3bSi#rpjbKe1ygepCVWPI7FA1#CIM} zC}aOWx;S4fyg|-b^vamcM~22$wd0Ka=;ORV0P5Ab`HBs&EgDqcx36i;^q?$G;cDcr@ z%zmcjXv*lNtY0@jTl`L#im%*&roVN5@_p(b9Esvo`;dsPimPfU3sL{8eRUS|5uL#M zKibgzUX6I(r^Z&XV}J5E|E%IAv1*Aq*voXWlrrcUf>ycKB-4$m)pOv}tYCKnppk{} zv|qaZ0Y*}_c9>{8>6hwMoGKO^lGkgO;lE8D*_4!9GDueEb({*Z=nlk9&=R{sOEQ9X zI}cHB^fF zhL`f#Xsob>|--yTtXy&UCk3(U( zW>a;+`K#=Q_`CjHTB9n$-T9_mD95w{H0&o#7f;OZwhr+y(W&;J=+9C^f0Ve|=qkJq z4s|*xyq8x{OX||a^o#ebhrIolT&T+}#zX`KPc@PN;dT?d@?aypajWtmz2n@#I+_Qf z%@MbY1c=^6cTKx|#fVWY*?Kmp-XDI)S*_RWTEs#NyQiLCc0XO4Mx@ZjOj=)kp8yD@Cx4KWR|<1W&=2iIr-Gr&j~nCkzpZ z+=0hU>T(bL!=7mxsEn19+mCt5vA~1;888OR17S53DA7+REhp>(d@urn-&onrx z&~NqQjttg6N%?44jK;Gm!9sRi8HhP+`(lhd0VlnvEU&mMfajY7XB}5F@%IR4zMk-5 ziW9-8?xcaRO}w1tBo=pnCQd5I`Hj~d1LVq@lMI9cTDW%V0LRJ2pB@*6$c`k^*QQ$N zp)92YJl#IZi0?2Fzs2=%7+KZ+Ds;h8?vJn$E9s7)_jIAQ9Clp*v_rn0I<@h9(oO@> zTNt|pk@DYxE5}}Z8aa+Lfc&_?FY$1OZ+Z@;Rr?kwjn(c>V1TPJc%xPD8I4i4aRLTU`twe3JEXG)d?G0Dv>QWaL)qn0uj{O`|jy69E| z6LUSk--xGMOAgbY*jf}b6aDIw0VCU((+unyl@QWREpKV$%kqmBUOk8MMmR#PwSqH0 zG2_LiD+uFfw2EeienxPu6Ge#LHGXFJA6{tUN_Ft^RfIx6R2_vIL4<}S-f{eXR)pP} zra@9kgN;y`z0$fLk85AAV*@qY#|t_!|JD7ZM*MNl;q-+kwr1`7$z4;2 zeU>Zjs{W-H=skAYjZ8EQ9=Ntqk>$mcS4&xe`YHoq(nHiho_jL1YE8tL^!&EQ@0v>Nc=qb*t-y%00I_tAh3m={-X5Urr@aeT>ijxprB6W3P53w5Sm3fC;Y55YGp{!lI4mc5V(oM!&)KSCO(2^n-Ju z6}ScDUBLwdP{+n|X9QK&!Hf|E1_B+IXi2GKJaUjWvE{g}9jKRkY5Iqv9gz*NZDwG4 z{Dn+*VhUMx*JbaTA8G8|0((57Oj|wlCM^6m;mIun$#%gS(c~l_e7c;7575^q7dp0o zd_Ujj2LRlPyz|EvPRzt)Tx_B0Nl{jTrv!88Brs`u;}=l#iKTs2cy605dBnP06u0F; zevXxZsOfc!DyoTMrhXJTI$Ok_FzSAFs!i64Cbo`*S5Is_BPQzGN#2_uwF5A5t+gCL z1om^AC&u6=XHDClu7WM?+SES06N%|F00a+4VZQ60=+18B;a(-(`+qNLMCJ~VWW&K%j8mn9He1(yIk&rb6iS$p zhIndHhqS8GOn@-aNg42sOZRzf9qboeiIfxP-qH+7XFuLm zE^GsdcaxQcnKO?m9CH-WaA}l4@%4=ZR2V5SU-(V0>rg@|L*^P76D3MmyRs2#Z^bC_ z?Jv+!CP9ZYg+FKQU`URtOO`Gu2r8 z;ZY;=M~FaEK&!l%Vg^XWMvk(6YV>C(k5z)>1T3^}OlwpwkWe^7LIvXhzzh8{ z`1%j)_+a;SB9Gx^&#DMXWejr*jqWT0B03DQyp5&pYcV8@f;9J&`pYrxN&-`F^UMzpZu=3sFa zHc>YAgCSzI-v{u0am;)MHm9>G?hEYY&_*Gvuh*T*4=(gKBvfbHq=QssnmR?H zDuYPR93dO$M5$bme0l`JkQK6b!n z72`J(SW40uY=a7v!4@#-I{}tj8QM%qf?tiGY|Pr3-He_>{x!C(&|(&DKEb*{(DweX z=3Hc+*86(W+v$cp#N%p2>9)i(Y$uw6A;CHVK`~BoMF>m7O7xX7W402vPCn&~)!X z&z-7iX|)j9@NY#~0b1X};ggMfVauA%mwvWBNHoM5!U=?b>&ykfHer(of9elLLih8S z#7ztCRawl68VDO4aGq3Ih_n_-ob$dR3|UsMX-Q$FM#qoxvMceI$LO!6Kxp5j>nErLM3One7Ld$YAF-`! zHs|q|E$}@A)D*A94wIs?JJS-A7-VJ+HLYZq{r6=}Q!!}qWp?PW)ylPVXWUbiB-`dA z$kP@`kPmDpn;2?(f`j1(NS>kPb7nNafmhTJ%a`ETlCGd`S140+?u3OX@x^|M{?33f zCnP~-_Gd3dmF-4O+mGeQ)zrOfGL|1qW?4K^pTS>NAvoq^7ySR4SQ1aOip`W*r_0b{ zVz7`K78FF96@{$b*C48tNDz;-X12?d&1Xg=%@($Zl0eJe=ON8YNE2P{zL*BAF@WO- zxa;Spi#LE#S15r6wcG+zTJQrLZDFkV$ba7B0Fqn$1}U z_dWJYdAgGr|8#98be)O!V{&v&dO`aK{}E_f@_wX|4cLVMrVZ6fQ=_q_0*}DC{n|;M~mg{3<0=e(yp$o>3ooI3^r=VkNfkMe2&~|_h zDq#0QjpAMNdu9$8zn^nL0nXLaTLe%#2e5T07X!Xbsk;iIiQ9^5UpO}`B5|Mh=zQ=W z3Zs2b3&>z$2LBD4;s$JvBe6I?l-gQqy1eoZMvhx6M3S(M@$agJ@tIjQhCo_!wdnfO zc<-cfnm(|@2B*`cD8x*UNIT841R-x?#(gYA=~_%xS|BH&tM^HLD@2}TqSFClkCK*s zeV#DEmfLbIW<#ZfoYgiRs=m$#o!^VjB<@nY%O(qdpZz>Jo8c)p61AeEJCijXc?#QU`_ajPjSLF9|!78Q021nCw3D zr4U2wptzFkidj9n0_&$Vs~-InwfH}a?O`IfH3tnYEEGWdq;w{e32+@*2%{o>*v8Ix z=(BL^O#0!gcMGtj;H}S7&*K1kpWcyu-<0`=PYES~D`W%d@IMQ__+fDKX$z=Leh{26 zm;L{Aw&Hk~SBg5;H z;Wm#4jaeDyphpW8;UQB+-7O_TrO=4UH41$PJ3rghWP?|sJhl^2Hc=Bi?Hg3wxf>ks zZ@~~MGAH-4qRJ{j

SXhG#HZ-Ls4XoM{D^tdW<_uYDZ3tgRuc50dGMamOGtsNd3{ zjdB9qTks5t{dBV3Iz8VLXyxiF%|MrPZGVV%8uRv@cHu^9y;28A>;@z_Ge*&x3fB{Hm;AObEu3}lAx#ybOz8NSqzjiHz+r`tQqmsUj4u{+x8i5^&HOLS#UxPSwQBbX zjR4s!*~WzT=ov=b)($-M%;C~TY3^GEPEAN^OE%r~A&A|!c9R(xi_x^`xxF?MD&Vld zl5qVjl|KMzRC2}b!*+&T2CFruI)GLt0}kZ8AJad+_4QX*K39jyvheX^4A>ve;M7|f zPX$w&A75D4Mduh5 z5&F?#NY^D*KaE{pya{V?Ui8?IA^%pHr>Lb*mM9$w?5Y+FdmH+}rLvmD!%>ao%0`V_ z&+3`FdeWa2v1rEDA7wg; z4w7e>9=5|Ix)^B7ZZs9t{;sy$Y-wNKc#taQJYMVlSYU})SF3Tm7_{voF}r|UK?3Ak zoFXGah7(w>Txl=4Q-N5mOVLDOcYvXG_DkUaQEmhKSqHMt${%boeF}?kcG^x^$?_$) zITg)Y?|gJDz5nm^4yb!m@jg11^)Z>|CTbZwu{^uvVj_L8bdr@v(E?JAmr+|=?;Jr4 zEe>(mGT4>>ZosEMeEGr(Ih zPKeQ&U)2XPVup90qiq9uW;-}0$z9xhJ(b&**>tL?iyH#!P@4|o-YUalbe7v@t?J#^ z7Px+RD37^EcV$S`fO3>H51s^wh#9vDnvsJ=sRK@oaa47mIe!b*@dQC4zp0kIVzxO~ zwmHk*Lv?m~QbhM$$i%OxT|lUjmXQoj$so=)AjyhhsO99(`;i zCDoYJH5jNSme&Xu#Q@;SskJAMF2Izc@DbI>boETdjXtq6$N3z98<4fLy5arsj!eGz zx>`b>;!^fZ`GNiIOz+d{nPJ)fb_eyLws5Kv8{POr2+FynD(Ht>)IxnocRV30HNQF3 zIHaou9yW)!EXtMBb7tt=`N%Bh%oBezb7WNUGpg2u27ee);fz{@X$+RDVJnvH)ivg$ z3*sGO*23h<Q2#o3p~20dODS%vO*boomH+R5lZPIl)) zzL%^4`kDFa15r~XB0h9cT3we||KQFr@g;25_vDBsD_Z70f4VcHSi@+^%jJINyzq4T z5BG5lKgZ<*p(b?UKG&NF__Yakopxu<{U}v%0cj_9kUQd(UHzc}t|qDZv+vzvW?>*e^`&JM1q&zz#+{ z8yLamqFJ#Lp1nf?m%{jkS;te*DK{a?(r9N;!H3HfNTM5nZ);D)?OsTehfMA`4U_%| zAwdKx62g=oAT*$iSo1t%k?r>usXAL!hHlkaR2V)pHWf2H_YB((H_g=6_7qo7x}TSF zNZ3Z0DeJO@!1HI&7?{|?V>qd_!Vc8u84`5+xpnLZAu?&O_6*BXZoK(^(Nff0Rfa}J z03IOe7T(EidFElQSm#Fkd8#;sny8)4rvRz zAoN!wUnuKFLp7dEv+RqXc5UC6gs}DwBX=?*Tr`IUin7MO;EoxBfIFa1R}c;R8HDMj zfK)TFh$c$MzZ>%Be)+xYGdLff>5?*euGmF=xlq&xVk6Tr>eMQMD74?$y}5IRPH5kQ z^@)?PxTi1^-NS-?xG7L~e%;IYEuGC|D=_l?&Y_On){k2SZUC zuSHd`fiMWtY+f#f^TB!RoJa934rwM$&=sX&6$4t(s`in zW5+NnYSz@I?k`6p+SsMaYpViLmYq2~GzT@(!yNOEwq+a>{eLpJa)Oe`MpR-@cWhW_ z$mr}@MUiyUWBvg<>7Rv2C%q-9zdXpMX_x?Z3=krPC)b|83_E#I;tTMFCb@!Cyt_HD@z;bn+j zi(ovC_McF+O^*A@=kJ~7I~sk%3_%Gc^fYom48a#gB%weFPACYai7A9_-gTS=IXOhj zwTT*qUMDOBKdlxhEM-3*;{8R_*XAUBq7sfuC3YtR$z8o<2`;0ww0#TT;<)^tk~zue1!Ez=uVlwpSlo7?@j=_fity5u;=ouF-?XZy6xyj1=P-6 z(KuQD3ww>)95hq$NTlu?a}1S@S5H?6 zGZjJgS5KTL``GF`))?V=Uvx!Vd(oP!35XPiVg7@GgO5OpQ)G`hnI_6w7Izbf%`^;H z7?=hg^DER2n* zg}%lRxi8SQs)mqfR2R}w5%Z-az8%-l=)|nwykT48QnD&I4H9HF5Yts_@h}_o)OUMu zR#b9^;Exx=qj(|>c* zoGIe9JjMMNFCSnP@d#}BIce1UF3rl4KH7Fr#DenO);{qBUvC9?K$B|lg%&qG)3S6A z#EKeIy_ zk0tZq!Un^Gu8ga*%J~;OF|YY&vtZ|qnUZmUx%l|8-vq)AI8-w>5m{w%`?IipQp1V8 zspY`7B{%)DM)?Qw7{5N^$O_=57c`1=+53#odam-i4n>5LphptFSFTjgJ@KpLgA5Vp zmuuYbS?}E@BHh++f4Te*BJ*+xR5`nlTHE>M)H`kQLdigh8EN~Qm?bY%h*uJZCa~+^ z<7VQ^4Ry(sS>vwW(5>hXB#PZ70xhrR7!qGd;I#s4R=jLyNfXBmE{iI@&PUN|$DmjQ zDKg89vuMk+a5Q2Yp`eY&g|76@I998imp`OaML_}zct*qGg2U-gV;=`jLHPycKv~B% zJR7NXCBR*k?m1C)=BWhQ7c~7$kLqA<_>_osBVhG$))n+o0IMAyP*cf_;3I&sm-&NNijc{c?yw{{t4nF7qbo z22PcXh>zqT1+f1dZ0i#HuAOu`8}Iv%V!epf{mslKLYGa#__zzO7KM5G#{?&S9QKI^ zTLX9i#}O8RuSH{qRx-XkeA_!NRiGSl{f!a`hC5ta;Z7x~OvPw<5e(?bN1L`O&hZTf z263{en7m5X|MW7_!+Ie1z2&vM?*Gt z44q!dCO{fnPPX|ZE6#Jgzj2(lre{|RvqY8YR0rsWGqbO%1O1Ar&o=PPDWhl>!S<86 zs|^}mXG?g~D4&uwL=1FqsWqNa#GtMXkwIgD=2-z=9m`lW@%%|;lfH$SyQf}g!Yn2M zC0a{|_PJnvY(v(99Q0CJ?EiVVayp$r^mLa;QX9Su@`x?ChipT)t_Hs)S;@Wfcy(?L zZb2-aO`aO-RhE6}7jxk#1|yLzYoONaV@>JKHl%%N^db;bPLYzcsFkt=n37;);}YTX>hxES`^)P;+d*pQo~qqTiE^;v@XuJnJW|Qs(ECE1-!a zg2|qOOWCnggAT2^*jJO|AZsugi9gT!B;v_2QauY2K+h5 zfD5Y&j=Wm$>)o4MqGTb)*hHRWEZf_NgEzQK4Ru5vVpHBtqnr-Sa{26$8+LN}AmzeZ z+C}XzG=7>*Y@p=~dYBFq`H6RHY3?14fAK(6t48@_r+*>Cx!p1|XrpG>E-|x)Rx+=b zWI?;}#xh-noFge808_HGsE0hW5c9ylS|>Yw)bysTt%ENN!WdZ8z?KOnoA|o|(UJw_ zfrAz3_pkZ;v8U;qP2CGMlCPuN!jK6UGY}1DDu_$&w8HJ65sP1R`Y?3IBxyDKW^i;5 z$fd`fl<5e9#>2TUS`_W|bqe%tb+OTVzh4rDNZ9bAIKN=(69|&>Xw zsvN^l3TS@gR^*W{2*v6}VP-7lg^PN9h*+QvY=4yZQ14CAv(AsmR?xZj^b;p@7}ce@ zC>Qmz0~`)pEP?f|J6WeT1v+!jp|#@O|3A^Lm})?)t?P|q{sk01(<{38>&S`xYs>d0 zxNtc;r_Evi;ps}N(FtSdR=SM9M;Da#tMUqYV&*9i03!AhtxBmq>L==n6o298Fmx}* zJ{bQJ|6it)0ft8~ZP5r6#(@lssy($0OF;VXZ8WG4>Jlf<8C2AGTbFKU5r}V^YXjwB zlog&0``;8ZSL=+W44v9}EaV7fTbcJK`fLTC?eEuEu6j|Zk&Kec{<9ZkPv!0;^CjDmPvj@ukb0%Zw$pI^_JaL3rsR{c zq;$ojq=c1hdsU2yr#ANSSQKEa$6#&xjTmV1lN+RMj@eLeH?$_oj6mgvmdeHE13_7+P2_pXgLYv1`k2rzU%q|~oCMQQ#u7V+3YDtd!`S%Rd z!Bs0zi*$)W2||ZHjyHfOk_9s_<0GSF=_d$~Sq%Uwz14La}#*Iq4u$5zB_GVuEGI5CGBD&-c z@lSw>5+LWQ`o?VJ8>I`MYf6hd4&fyc0E;Q3a(zee_l!6t^5;e1P5YpiFe8$V1Uldz z_EjCy?Gas$$Njw6EG$!z3Dk~=vb7o*ZmJRl&7r?6g83>sg;CUtd&H|Rz{}#{OQK>s za4J+Z*Al{E<}EE)`;cGgDO9Fpj*dRSdc4Vby+Kw6{Jl@*aGw^@*kstQqr>TCDm{0! z+i`|R5VemV>@3ODoKg?wkAaitm+lLU+q1uXPLU%KrA$c&jZ`oJDZ&ZQ6|o3nqfg&N z2l|j}Rcny}gim$>UvlI;S%8Iy-Qp&w6XV35lN|O}Z89G|EiJmyY4t<)TBxE*NiN1! z>tUL17N&e=vzzPRtF@Jrv{LLYws}YBpJQWc7E3WQv(J2y>XzfP{lBZXEChqn(RxGL zNfgW$j>lIzU$4*k`Tfm#`4)tO&WS7!1V;;zJIH~D!*>J6U6h+K-8AFq>~*|O^X0v} z2}}Y*DTs*6{_Mdph|&^M1Tc=6<1fD;Pf4-9Gn5cp;q>7YC~kA>^OG<(-(0?q-X_4b zsqc5>v7Uv<&#(n=VzXysnaIZ7)wWgbyb5C&2Eq7JhGbXU0dAHibVF_YYFo3-PGZ8X zE2SrvpZ)P}_NFKqHzY7C0W5ba%2JhK^60N^dSReh;CZ1JRhsA8O)k7uP}(M?^@Dw= z0w>E6ndA*aNNw;5vOINu3z|yK1>qRn;tkf7&S$I;U<|&Km(qi;nqo(7qP)cdgt0WG z%W@{ue1OWHdj&RvcwWN&WfQ|b9AJse^t<$Ulp=E)Ey%6^mVr?N(3dE?Ne2wJL5Qer z(e!CBoz{R+tlVDPiil9;XC*L3_r)+bOY=Hhf`73z6|n$3DV~p;vPGo>2x2%$xn+Qf z8dO$Vv3$ggVY^fAAA(0G^r6&mDW1A9kyGkhvPlkG=j47u&iGaP2zq8|8B8VoW^bGyBnw_j^x0~qR1tZdkI2t}%; ziv+{FH$hCY;Zj#9M6m#|RMmcM#*!#>!F)u}#zOAU)ly6Z7d)R6Iok747*jFEw+NjV z#hN}h!J|j+2-ZoIFVgxE0G&-Hg@_%F!x(Otd(p>KZR^d^vn2uHN$jss zDu@Cr%S(1}xVD)(_WC(bw<>5eWk@-+uj_}a7M=JNSOMnqr9V7L1Q3_1Qorw(3^L#9 z(^qY|7kpKtWWgoQlxT^yh6T4y!XxpCR5z!z|kALv@HD!0`jS5pd)6L z+u605Pgf<`d5!b#cb_Dmo2muC|E(0QE5jqwu(=V@tO>)gNI*N{etuiwp3h5tD0B-* zoIH-}+BM9Qb8+15y1{ii7XMjQFUX%Z93s!x$q}~}q8!P~QqtXfKP2;|D3vmHQ+Q0> z_=Sl<{@xzGKcF1VNgScnw@_+OLCAM0PV+E@_JRITo0o;eI#A%m4F5|Unq~F;$1)kq zfUH1YUmBfk6{ETTf}bXk8AFieWy={3gy%i3Rlr@kUb&*W-5VC>L4%;;yd^vnPT!=% z$hNusse7c#NgHT>qM^WinnAJ0QA>LZ=Itj+uYzB$8u@vKpMX_=DF{3z<{=fea zT|;`wCMUt6$92B-MPN{}bS7*Si?CbJ&Pe6?GW$+jV)N40BMDh>?5`btouQTpH`l?M zoIy9ggqNmM-D82i8}x1g^C*N3O09m4Gf=mS8kAf@t}V!!zC29#?Kx(GA@LzYcPByO zZk5i5`;5|;oLG~4wk8)1nFuHQ2CeEB2Hn z#8^{&5=U7!U@wrYJk0!KK)eo>k4)xVfZgXOVBbhyQk`hkjO9{EMv3PH>#R!%kCne6 z=g%28uf^OHG(EJ|8t5*zl-G23OlgX7JsHO(=>-paYdnLv5Nz=6qPNmH$>wd751;RO zk0(0}R&DA5Hc5-vSKFi|xQqPaZ)=WM0hX6J(|=f$WPam~R%5f=)VM7rDlQ?DSF1VW z@0!7qBLDH*(u^`425|gjj4!SbinC2Q+I3XOmxFW z^w>OWpKz7cnd%Pt=qco9E_*3RdDr`f+l*5gV@PEgRf0%4H8rG#IG~N7=2MM9`fz>3 zbZHvd(VpA4`~N2kfm<5;-zT0Cy(-im2{F)CH%V=sl8M*tYTrlcRl!BUtD+wP719p$ zonxhe(4WOxxGFaY%Hr?Rq1uws|8X%47gX)nQy5SMy+RWl=~EgvIXrdR zn7!XD>HU!a&DK?fAiKCk?P(;dmMV1Y%$HL6o_R}s5g;Ypy(LD)C+ny*6+@U zMxU0XM>Nckk@bGqv6~rXEj_^z5rIx`&|6uW@nMoNHD8@=VQX5Ji*yK|aWIznL1NJE7hYdPMIP0%bv1WVk=D$SVpT zwndR}-n-7&N@^Y&YCI33d>+5)p1_qzPHJ4DR4aGC;pN5 z$JGSBeJ1W!vIf3z%N(J>>{z*9;V(iaZmTw)>GWf1a zsb)~}-u$Bxy>}8*3u^%{D~qCl|A;HE-tbHmzssB8Dl#?5cL$to-=Mo^@*qJ4PKM*q z@w>^okoGM5@v0RJ1__s>WrJMNoL~B5g>pq_;Adj@`im&W6rCAlXww|CqIiuBr1r z!JHvMtcvPU*WdJKkY*O`J4ngg%(8FWCa4v>9|AQ1THHO!p09i+`x`hQoTFxV+Zj-8 z$%4P*wzrl>qx@eymP935(qtJ?qaim^hskXQsiDaqP1#hqV#Cbj*u60;(1A5$&9vJm z{b-0QKQ&d%;1mWr+S;mm2t6w2-0pJVrvF=y&B*yE`LV$qOvo^6(6DDD(ZN&% zL5p7f2}`DGnNN4}H}Rx^#bVW^(c#xl@hdan?4pzV1=MmP=9Z?$gW0qDS$mKqPo>$g zsyrMU4F?o1#WnTMEkklx?=P2JFaq)~!Z95!D;ttn1&dyY=q$rgw=r9xIGJL;aSKnw zA`SsNv#kvk172}rEU%!d+%3n06mzBd$#l{qpMC=<|iLPZM&C7J-$nu4h1u^^5HncjAJ&QBNV_6Fj6OvpWVFk1x zXWn5vuSE~qQ}5zRm%yA3OGa82-X8i6^;B!dj)>>~m!eP}HnsmCn376zA0UidM~hjI z0d-kN^!v5mXzUIk_0Eb`zGh6QNg?J#PeCa7=wAN^pQXuAI9`}iOf5N`fa2c9Ki{K5 zYaCMpjvltxLUA24UZy|2r|`Ld%=ER|pl`BEEXsi-MqTxK*Di+?066)E^>SZ>%!y1K z*{-4#UWX!sq6oV23B%rb`({4XNxF*FI&pt?r@9j9^vYZ%L_f+x3Zuc<8QB^fH;I};6{djlTLz2BGx{v?5Qpt<_Z6Qfx;iusA76!Q^Fd+c|;26_kL~ILW06v+1iy}z@*`-kwy8Lx4 zAS;mCIGO`A)8bf#;E7oC0x=J7Iz4oOYlSQXtv_E?SR~MAu1<#j`# zE@SzFSl$Ew^p@)%&P-V!c!R_4Vs{fCc2k80vy+vxR0}dZLEDrvdQi@NyreFJu7m=@~7g8_<4B}xNk-yD!jN;dnQjYBi9Dz~2VdModMxGuL%(Fvw{ zDp$DG$QGs(_jnfbv(coV3{2gF_%2g7*N4y!N77$+k$EK<-i6|0!a*|RoBX(d7A;Cs z4R$9a4em(^2sNhxLkX6Xd8Ypjm|~z@tfXIr2#Ac;vmX_WBO9N%&Syd|tMUv2XOdef z?pY-q;+0>WImP`XX@TPrGYrYFHn zU3V2|1!%y_j~`kfy8eWvhyS*kr|tEmh5uCp%9>53KG>#!G}WEL$z-I-4P#1Ju#|JY z8k_HWJD1ddmc^HysJEY1=MK?I+~XWt5pDdc(n{&f7>csxZg3DEFTzCsmVT?ZHx=cz zf@NjDGVqvo0MbWGPABFkIp&*awb>xAkpZUJBO{xHm(5S-KX;d?#1R%G7AqfSH0U5Y z1&ynoi$y{Fgj^L7vb*eYXIfdfepbt)ALJeX3^}1+M4e*PKlt4C{3*)B@)LTCxiRtG z11{w6kh1Wo4A&Au_3Z|fez5}K(bJA}Cg&WfnD`&Fqq9{}#qZ(xH&g8ADewi2&V>A= z!Q|Mb7f#JEvs9mzWJkz30pP&yDukgmY)MX`4z?xfDqWE?3bJ~yY1vI9oPcl0X?mdi zIl9aY938#H(=&h?^p8;gujWZPPqX3bCbo8Vc83%8?a5?4Ah5<`c7E7_I~OjevAz>~ zY5Vm;v=BA#y2L|SDm~+U+xwt#96R2yRom-nJ>L*BZ!?@V*=+_1j_!{t-q!ETUJ|Uy zU}&Rncqdsx&ZfcYYD0F{Do<5}U>Dd(S~7qCCZ>N>B( zS&p+k$*17~YJ16e6ivL5hH_7`9M6*ik1zYeP#%nnt%}RhAAwx;oXZlI|LiB-s zD&I!nL2~I+?adl~USlD^A-VXCVK;zLF!gCqEx}$Y*DEDC2mx>mxYx!ZQunSQndu&0 zEd8PUF`=ZgG|>wdp|DgaJ~?YH;riUn#3wgG`aY?28yGsyHjsc$0g58n3_|zTQ%y^FZ_ypHl4ND z6fN^zpO^*m>TJiD8bekZUXRg5_CtX9I9^{d5&8nGv{Ai>FXztE#wKJVf2T6T$56I6 zI>6kQP7=MJ>%)SS`~k)xOzDfNLYo9|NKH*$yL#N2nMau~0_Keg-T^)6eK=`Lg&E%0 zo9@FIr^91NDMT|iG48yr<`V1>7}$W0`thu=>Vbuq;BO#nrz&9?ybyugn_gbRZgD6p>IdZ;QhiqP$uME!TdM7R zy**fHcQm|puaRk)wOAN|sEZ8U^TEF@xbLMt=KFdw7*zBP0yp>A1V8f!T9p~cEgHnz z(TlKeE(@PqCUmcb3`HN0&2KRxNpGN(h@hX6bbK&*-2HxKd9)BVPX+S^_r9C+4i$X3 zf`kI=xindr+GZ&PlQyTvwAZ1A&vbt>7Xc_K#2a6>XMumBE0%6Qb>f@nqt%Qw_MSgZ zLc_|y9scgeHKs42L7s?=@v`EaOfP<}cNUZ>Fn@=%hgTQrxSdKSKd& zck#D~WCXFPu@==FpO7GT-4W15Z6)Q;hQJBItuTyZQ?7#y661)J0@D`V_Q{zf&#Xp0 z6J0tV0>V;oNz&;yO6=JYb-0@NAV1i2Trt*OZ@F{4nrffFUh=RCe@QB^YRF&cY4Luh ziFW1~JCijSl*0o&iK$DiKvrp9L~6sE`4F+p%rIQ{oj+(?dG!e6Eo-e?ZaR&X72?<~dF2c%e;nigcVP2h2l-t_h^t=bUTgy&^UMeR zNkjVM9T|~@ZGYzJ$4jn{7tRxyDE^EZ1Y~Zj6R>QJ>pJB z+g`Am1LSEYlK;POf8BA$z9W^~&Gk5CqG|9DGl;6^+%d%ZXNqGsvN?E;5o5E*(2G;z zdAhggSf?C*tAUpG&(J-EI8srzS7%io6Gn(Yx<&u#OCE|>p7CU=20ppY{LeW%COGv; zb7q@pS#3E|-^54JL!!6!h@>5Q_8}JPza0U9%xz3bmeW(I5`BT(j2c%38ASV6a(GB@ z;U~W=#(Wy2&NdLA@aUe4=(sa%A`k;wUHx_`3tu+CCWmfC(4ikA_IUod$E>e2}rERH)RRQX--`=ioe0lZ4MbXy`nJh-@n zAcn}jT`ROHJHr2{rIVpSEN`B&ZWSL~q<5|TOH~;*o8A#uY5WFQ?ork}kh}22w z^4TXbU-kekFs4!^WN%fi&i(k$baq{hV;rtxBC9&TOXxki0)ywas=TA^THUDz!Q`x& zKII6@6dsH}cLTXu*6?xOO>;%bbr|zNFf*Uk0n$?m(P zrGRPF29xXIxKvQ^%C$|rL>TZ-)UzabbHt7$H__rC^AznIqS^grifhmq+aZJwU}{s$ zoeO{}QD$qTPYHrB(HraCD_fyWpPS{GD0LGzYD#cNHARsr&z)zrA;Ed$0N>O?f{us$ z7pa>++b|h!$)aVuWN80pg-?5%ZQ>g3z$)@nkQcDEb+07P3e@1qE8Poht6z{Ww7udj z3tzpNVYPVaa>q5$#MIY0!hy|uehON?#95T-ttA%e=&T+dhLyzFvMZbtg*mtlRS#V|Mohyt>n2^&Mys1jl)K_9OKgdS*&yZEthxEgn zKx?2X=S-S6UyWn>@k71Qu7fdUIwXI%kmPd?SGk>p2Mf+u`&}@g&o8rCEMLRM>KqZQ z)QLPYsGIf^{DQ}AC1!vcA9piw*xA#SMX0ODG?i(Ey7Pg2NNo9 z)b(OB7QxAJU9g5DuF4zpapNPsvk#suc+n)Q*_t7cMC){OpeF>>_Qb%EaDhW_~ zO>>d4I*i~x)88dz0xpNVast9S1u;pqfg+A#>B1A3e=UzX>48!%1^_2%MovW7*q&^s zx&<}RF5?MDq48`_Qrf_^!e%owz0#~v)qjd7(JpQebw7|1P&FxmcC>D=7!hCs9o|?K zOxEP-uO)8LB-z7B-y#cbR3|`zQpdyff9VQ^BR45147~=%%bkUbI3qW>d_?5S zt_&rteu=}T@P!}OG!7x?xjqyQ00#q!!&Dh~gdi{Mk72AAwt~mTz_I91si=^%BUKo# zYVe8LD3krltK=gTf*#5HrhEL=m&Uf?QmlOMSn8D6iGkX_Pp^< z4SEn=7@$EgRac5mlP;nY8*v^hRb05L$6ja?RY7p6Ai23$gNOTLO8e>pcg&c#)F}mQ z((FDBWnICQ_nrYXKieBj{FpxiT6^j63ITqiacqO+SoJz}7S`A}Y+nL9#&#X)$z&oH zNmUad&bDEF7Sfz)=5Tg}Mr=d{?n(1??|kI1zYQ|5*m2&REL^u3;l;6JZYiTcNdSwt zf%?pJ7XQMF>gy03Y5SJE&eHG8&_WQlR@bHqn#BH1F{RWDmTvtGb@zCbN|(#YE0h<2 zfBHlS6c&NFI`~ku{Z#A0J5Ycm3;vH5L~+Mq!e$&X71UioYGDru(JWYzv&g8r<{X63 z$q&GKUaKWU<;e4B$2ZK75ewN=r+iV2bzwR)p1hI!8}2$c#Bd!uK!=z_%=eLq#qC&4 zTq1*{*y;w?CFcG*xG%h3hF}P2jVlV10*lNn(NK9OFmw3WN)%>ywo@0ZT*#ga4KQ;C zKt%RX+mi;ouXr}NXOZKbmp6}YoMdFJLSK;~0(#e4?cbURTPpqrsu1SKcW;=;9Z8|x zSV>!4FzzMz!+|r`fx>v{`f-acGvW%Dz7JiHnbUh7Ka%6t(s7cyDw>MD>Sa%>ws*-6=2M!hH|dt7@ED^U227JZ1G54+%2>pWwm-in&6HACVM@$kxv zX+pELEy1pmhg+Z6nU;x;5*$N?)j#pUdfp&rsA90^KPG*3KL3E+_h`|P(L{O`!a1tH zwl}rkZx&T(PE%SMx>P8#;2fRX_?Hz1xE_eOdPL?z4 z1>v4_1z9?L!jU^(fu9z!ow8^6(p8>YpTxrX@hpsbk`rz|ox1VK!1N-g?09mqwsaju z@s9iNZl}g8yp>DTfJ?kDU*&&>sA#+d#btHajr##Z;3g0Bf##kM3g#i#J`NcV)JUec zDkEhcb(h=B!3ZcI3-LBaZ+I5o-oZZ9JkDY`drE6~c8^_Rkq*GzN0~{g!&}m~yPDSt z$8Z(aL#@fDW*Y%~&`fxLRyp{_<{O)9PpbWwMmsBBFt4uH%0T{AVyis-YIf^twBga@ z7K#<#+Reh#IYp-LeD!Yc(T_wh<4|fgo0{{IUGdzlL#rqZ!6q_naYufb;T&Vp%T0vh zN2Y$Gs3DQdJCyM|6CK_kHA9YoTie=GnXq}A?z07{?lZpT)j6(ETL>IF?JXC{EbMPG zp#+IHcPFkYsRo&o4?>+(4cT&AtoO?^nA&mGS`{ ze5@nru7cXzXCgbSx(8k%(PWDb-X>K0i#^+u)3&~yFd1{hK2w=r`~{T%-2>H-sHj5E zg?}+wW527_8KZYA-kT#>>~W)${!n=UXL~ATgjq!SYX>PofUaio0YT&iX7f0X0&e~M z+6YyI#N|NiblVs156f&k6b7|Bzzjc_;u4h#P^cVQ=D_%kx2R0pP&Og3d@#k4)6L%H z8`9$TP#Uq30*vo9p67CuInE8X_83r6yZ=jM26iC%8jnnM-$D4-lt%mrGjOI#x|~`eOpb|3YlvMe*2@z^6#c?G`eY` z^tJ{@UtOWc@NFOl&;J%mM)2GFX-M$z^fEeC>a)$Ma180GECJ7nx?+V|QkrT;?3k%I=x&9e+h?Jw;}S#LD)qZ zq8%{)1G4d^-BCZzvKH_>{er8XnLh58wZLVN)6i6%7JFY3%A1bJafgR>Vs$P$$3Q{k zHe*9A7l4l2Yix-}I^wI**hwy#d;z>P`Pqx5*HHN_ymLW#x-tUQ5ZGmp7&NU~Bzv8h z-W)~;73zM;>3jpd!IE~ZTqdvXW_=$<5ySoT$m0o4SIhp6!SF@Z_&h7oUabf#i6}CR z6jFIK%!b=C9y$VJ^8Z zRa?7u3mhr#X~_+f{p+t<*gu0v0Cy|Q^V$T8@gwB*B_}S4ugBki%=%mGQ&o+t6p&f1 z(r+J30bBA{>#|yOW~_7R2D<>fm2Mk$y6TfRl}a_zYl^&!tbksAv=m+9Tz~R_X>x~= zlfNsG+J7V3CBq6qeSy!LOgmWNakTcQXH#@*@^#glxgx;ghpy~;eYmhs$|fLK8itS^ zcEG_pJd!sEn#@9#0v?G_&PYe`I2|K}7>r->QS<@mAd0`1B41DGj+{C_cRNXsOkDS4 zc6gmZtNlEVK1|lt5(da&@*lX$d4qz+J|EYFn%R51&OYK9l z@^Ph589ahE3%{R~Z$#p0fccU*{sJzZ5Clm(;l&SnW;A1_FbcVQmd?)v0kbd?)yMCA zZ*J@4v-=y8ihfa?cLNAr%_Xn0JqokHx18z|fL(X;$3zRdPLUlrX`_Psjlz5-?^u&^_;l_;`7&wA`AzuNI^S8y+d)QOAlf()>9~)y}wb4q4IHF5Qv&`8MX)$V50d&I@(q#Jm@$F-+ z2_uS=U_g07&W&}Yg=`&j-GZ!sp^ja`0eiVD@YxB2OdZbiAU&Sf0##HJMF zX*u4dHEhmy|3s2z(_t6b=|EaD`zPW;LpK?7?gEG^gGNv$h>c-BUNw;iN~UR=jXLeP zN<19+j5&_~Gc~q;f)^D?jRaL>@ey{-0viUpVynuoMW@t0h(zjk!SUcybc5>?DOTBq zec>bPk;`_Dry`7gXM#G>Pk%CW3?`j~39w=ClU6`Q!k$X>4M|JvbyND7#Sng4F<4&W ztFne?-|V8C&uXnT=x0Mg!})>>Ww9IJT9_)A!+p$OFa*I2=>TZad+EB&|d%K4wwc^W{F7^C~<=GB6l42rekh-*! zY9R_t#?$)xc;qwLlKga{(^BY-^bOL$Stkn}>Dr`}op83Z5R8@k~$> zS<58>YMO&PX_+^n_x&;(g;{N$UcP@+}0w5^cfD7|}owW{S0ielX!m}-`= z!EECdnQO{>F6%Lg|H0x(`*s69nEGsN0ffkmiWZyhxzYe3>8F5Ck~OM2F?+& zo7!{yLiem@t+#j4+O&=&Zz_Gi?jC(rzJpQmD@`JS=0~&+5x3}wk0A5k>sh*S$SFb? z@*#+upyL+ZF~m>y#Ds3?VILi{ZX%g8&G&PAM(cAF>E@Xo2;Gpid^%m)z}*SOe+Yw0 zA99L29KeG;7km+@`lxC7)ebS)1Fo=m)VmPJ>;E+74Vq-8PLK=47>rwQPxYmeXofo> z-nSJZ4#cA`%8?H{1}U64WW_T{9pu0>yM)I&!D>#ar@}P7p7CqYJhlpj(x>%sN{A?i z-)~#-*+L@G`hNJgmCRFB6TM4-MHiWuDg%olN~+Pew{9%96PS&Ox=)h(am)h)4iN>V{lc zYeApzf7=wilf}Ns`^I2I1)c36Q1beAL&N2#XXfz*B3*TbCwD(={X#D5>_#12Y1H!C z#Q6Ok9JDQD>E{`!VDYGojL0@3nlwyNZCaGkWvQQKp2{&_lu*h_h(;JTslH&p#aART z=&d3^mu5O?WV(QUT@~~xU4qqJCINcJsf1^3UBgv%KrF|FTM*7`^WR#JIQFh)1Twa_ z^<*5PAvmr5eSAp44Y{5Q{FEvp^~MAeZbMrxw9&&?+87;i!uTzc%)$?A`?TKHALwDL$(QHpkv3`B`Cw$ak%{mZ-~$V5A&Bq0{*5QYP*e9y ziD;2Mh^aA4jgyLNT|c~dOJ3<)CT)wrYq3grolqTYeS5cvyoBCy7pNj?|l=>L+A-Cs?lXq+lr|ftr6!X?JfYwZ2 zrvB31>+~ZRF#~*G&|SsKm+F3~YzZ4F=cseaPVXp}>OA`GnqY-Ta9sB!Jbt8wO=EQi zu>{$G{KI%WWPakk;T8C_Innd{4S*m_Q3h2kXlVSCxrrX{cT7^*Peq)tjH28G)EEG> zED?U7T8#uUbADz|(cdZ3qzwW2q(>JuN zW?WBiGoXe(tC8@Cj*r<9eVVZxhR9AB6rZ3y6$q9+~DIt)e&!1H?sbi|{e zs&E6|)A|W ztgQ0?=t;(()C7Y|UZqBSnujp-~-fM<<#%upHRn zu|@8#rFA_{K;w(xB$&E?J~h3b{SMeVyv6v48Zp$3TRH2i$}HFD&9708f8;K+3!!v# z+1=1px_B*dGg}`k7-nrkW-uaJgE>NyveSk;ef8!=b_bPr@4m2y^rRJ?4o@~P9ZhbG zTL@p(h^#0NAewsQNrFy=Ft$S%wjnNLU2;+IV*ss_`NgZv2L}N6C>Af-S>@m)car-e z#gK}}x58Qjk276u0PVeJud8@B1UtmB9cc$R%?u>w(Ck-G zE$*d?9O4%ZtgFCtxh%_ml!&+2-6F6Wp@YJVH~Yv>aSvXYZ(K?FARDCV57B26H#?J( zzbpbEOH?rAB=XYSYdRWhgYm2G8$pWwVHe>G*BteZQ*M(J-RI+%+*iQs`zPxmZ(IMD zV8-*|m(CM+95d3!`-k_zUth*cyU>>dR7G4xGXa4TOqU8Ql^=29f4eU z*?kTfl^sv*Pfl`5sD;N^@i6#@rHcLs4A`uAhh1rCU0cee%wYQ$$7s@Q1PBi)dWhe(DjQn`qBf+VbimJb<`m9#&iAG2(hk9UwWe~vK2=7 zZ@1D(qZ7kLHF1Tm5qCTe5zo#?eTUr%jOQN(lNQ3o=VnbA@Wn)R?Q}f)p-?#DS;FLb z9gclYj~5&zzK?iSlZBl1zF9&84U}f@b?x*Y=fqWVhaBnA)esuvXiPd|h1-I|yeEj3097X)Zj^N22IN z7cE|wpav{jf{d-g#D8JA3+02f)>=0dDd}<9U6bMBq`Ps3Ci0@bQQ*U$%MQGV(O8N2 z=jT~tr-{T}0dEp(hPAW}l=-y+uL94$OPl;WdooA{qlik_||eKY&QIiJ{A(})KY zZ1){S7@Y0;+s73Pr-|6KIo6^VjLUr9Mi-D3j^*fazWAK#B1gvNEIAdI2||r_q>t*bPI;mv?sdp^TQhM zs?82KVR`G=tt5Yv{@gOo9V|{#lyT3wa&L+F+r01Xj0)Uz&8t1$Vctyz{&cC8bm%4F z4R^Cm!#8xvpe@pWL0AcFb+zz=JH{g5*`6H77F45=C|3^!@*?>48laBQxAx0jFF+dK zJdUTxDe)t2M=O}QPk6y0)%8tHQ6X12=cVkrryvauLJW~EmLz~g#=J4)%y5I2hEted z3y(0Mpf*9yk11Ld^dGJn$DYXgfREu|w8QRlS3&v3&XmzaF%AFsqWTOoajT%mKZsfy z@7H)LBZkV^SuUHOUw@-Wqxd2=sgsW@+Zq`_GK0UIjyuiC7x@5Z=?{Zt1b~&ZeKi-Y z!Bw^#dx6SLv>Lvq_@%XC(gL1h#nheL&6|L=4*8lgAuh`S{;QeQj3ecQMM3&?G1o#O zXk#W1R?v&NvE{_@tJaooGyJHd(336-f#*bcN|^{R#sNcR#J@hpxo0;Amp!^9t3-vQ z3>~|6ks!%rgRBl5BMbz%(RT6lY$U!)G>{?scQ>m(#tS0C=M_(nLnuc|iaO!;pts~) zt7-#p0!k3ZP$C8Z(JVTcSTnQIeAZw~^NQifDy6yaUuSg}jJlH#DQ+@Yl;kg$E@N%3loGC%=Bb8xF|l&-gW5gnLH@d!9Rb{`JNdXgc$5WJsS)y znqe^!xnw9j)I9m(wyS5Zy;zM(h-vD?AMNZv~t@-KvRgD;9-vpKsI~R zWioIUIgZ?Eozz~Z*nM@*hl9XQdBkPw+bB4)nLs4xFRqmC_dCYk?TU~WVD*yT=kj@b z)u;!~A@hB=jN&ZGGUDH@bRaV^QUp4RUA!36d`4p$k zWwvHo2dc2tw;Dp?Df)2l@wA;K54rh&`*dDQ4NXm$jn^IxO2#*!N4wVLr`C2g9$z0EXZF0L>E z`_YwJK>RlyMk%-2R(%sKM{&k9;K6|Ha@dREdvR-vNvy{g!JKqWy$pSyU&(r)ivwwFj zm!Y0%mnj@oKy*c+U@dR8%KF4w5lcDnI@G&tEs|k3c^5cjgnN}@E=u;uMta5uAR=!I zHTqd5DUBTh1_a=>+1>_wApjRe9|XjzMn8(+D-I?t=LxXD!22f&( zi`v2bZ;}PDc4MX57|AbCV7h*Gb+~ia-yMJpYxg_+Y@_g=jgZfB;x)AN=!*&=aVE4u zI>QOsOu3RA1f#`&rJDxNfdn((?HBWG=C7XROoQioJ=Bz6>ngRY2y?~aEy%-u2wE;e zH*Wy`nR=X5#K#jyTOrFPr|j&-5%(oPVP*=)DgdGy({nbvE(zj?FwPTvwM;rhceM*A zx0UQA&*r=mPV3;w4s>xS`$Ak;Pyi1}!+h4`H0(1ja@Ks!wAQM@#Jtd9__UN|EvntvSj74Sv1mGr%rVV1P*@wIYhzH_ z=BI-P-J;B0lHfs?aKw5wKzhGXv2F9`9KN_mpM((;dd(YF%gKxQ+gXvfs_;WO#v&Pz z9Or4>Ea%OY;uvfV{j~Fz$XGsyTRaM8>=TdNEU+xNyr5&s9eTKShRy3FHaZW6eDr}7 z^j;(`3Gj!hil02ZIoki@hJ{d;bd=ml^6t%+=$9fj`^=4BMY|HWP*pdiPX+PodhRnA z9C=rq!D{84qIWyE6BJX(Qm!pwPFuLE>)wO$F4U2Cx`Pqg7z`QSA|u-b6+rFuE)VX! z75YqAMw|~6QmJp(+w!>7$XNM0HvDZ@lRKj5wFX)DVU#nj+>*^3H-LLjrllie0)p3bNmfjPfb)Q=a)U9 zbdQLYR1#xDtnuv@6_TjbgQmIoEV=KQ_8x*4`a@mntcTClU~UeM-N{zv5-ANs)bq70 zAN3je?EJ{y@qy#*1=yB!4^~%Mu-Qv5$A)Ht#{r~yFUhtEzf~WWri8;(&!d=)%?4}3 z<5ooO`1mb#2G5zNCsa0lI*0b0f_9=8e#epH5p_x-Ln0zF*?ZA_xXtsRAZ#HM+JlM`0rtOvv)9G5;P6CkBRgy1&bx zHLE)}=Q7WP>4%XuZOz>Q+BAjMgp`v%hkgG zLs^HHsubH2p_o^*U9GCXiM-cR{9L+SW8a~KdKH%!kR!POL9>nv!}`J}k0ay%3eZ)} z)L?+=v+<7Lir@g{V`h$=xybUA5PM$PnE}{dwbQ3QcLYMX@+t4*F=nMpYNuRDJP`p| zYg=WBM)mzm7q*0}QaFGEfA+lheDVJ{l_6C(9uD`WvnJsu{yxQ+NWBr6A%<)o^#VPdwQYFPKL@d4%RK^1$=(_3_^af6}{U5e?Oqp@auuQ?=m9c-N$Z zcG)w()TIV`e+iuImk!ZtMN<5Rjh!(2hmH@kQe?SCL=Y<}wfTKyTaG6qHEz^|zyl^b zCi+geP@wqYBj}7H3BXbn?4YB0>j^54HVH02T#H8%88x6EWApgAOF3rCFoZ=rg2j{= z)g8_lKRgd8mSMzbX5PS?>Qs*PN5-uI6I`A^&le5T!dnAR^G$ zTM>g$1CY+!$x~$;^{2|_zlRO?5$KtX)D(x?qZ~PL0D*y)wX_4-=6w9VOtD{yUWcM# zhEM%i+%p@l`7uKldqdpKSTMf`U^Xd(I>oQ zI_cx601ds_^imF6dzGYyTA(T?+@jfXUJLNs?nUyKZeblsY3^tSjl9j0#eXSvj+L#c zKBrZG4!=jpSGG_!4jn+7;DI---^kE&of-?+^71NIi+q={gEXS#2RTjXb=5S9RdOxd zhg7hYqXHttoeYtsQhipW|c3;R73@60; zoRk@!F^_B(s_1x~#+L;b^P6j|qKeud!}Y;YGgM1#_+ZJG);a3BT^p~Z>z;5ICVb)) zkL+=A_fjtiHgCkYG=l+}>4$WB#EN)phlqmGd(r#26Oyhr!koN5(yX|tn7BNB)N9DP zLA6n)MQ&<4mqlKO`%Ob_HXqdfbCCNSo`Z~(gEB!oOam*AYt#2yTcE-}hC^uQhIJ~A zef5r(q&VyA1@ZF0zblQPl3({Wl5jw8eJV9Mp3DZCn^QY3vOoDX@(cyXpUGXZ`QHb; zPM9m8^tB8T9A94AQabiojN1|(tVlCvOQRxq?hAID2P81$dH_HF&;0o)y^6^Et~paj z#vq1tNDbNBI0;#Bx3!Bl_Bb(^!fOo*&>P#V)D62HNbQZ1ICbSXrwqW_RZ}eq`;{i`y8+r^dJXYPR#6ih&H;b1Ol{URk0YJB{_i?q6)m zr!YsZNRw8!Hce?l&OH)TB^d4k1w+Bkt~g80KpdbwM7R3J!6P9UcMrq@?QDyVy1Gki zPV8fa=Cry??3**nX*$lZkvfjM=YI6##weP3gU2VF+sjaSn$#7Mf6`YV-=fPQeirCr zWQgOBanf#j&r6#iH1Mvo78XcOpQt8C55=Cpy{6UxG*Tj#9*uUeD9gSSElA!UqW%%G z>A8+~aTci_TQ1YnlX{6l?(#TqY;ZrsEj3f8O&mz0+Z_GeN+)~8sdr}zM`p06blF`Y zenBxsH8LKPJAGQM&I+glh=Bw~VWM}edwU?`ZV#}HoWNN{3#6{Lo6Vfg{qtUnNzzZV?~SIXwX^arr1mG)K>>Vl zbW|xR_FbE&gAJlT8QibxgNAVvbK-|%-jvA2ZH1|u01}#qnt+`KEGA z-dYt~yf!ohS4Hz>@6K{c*dNBGbxye)r0Itf)~^!u;prM-WNwo2NVQSQ+p<_8UV8VXV?H73 z2wLWLE&k>Ww6iG=#*+;bD%zwdc$V>R8anL?@i-p8qMB&rPF+ixWdNMySjqf=V*p+Q zx+mEU2W}JWLB1Tw&cxPlBQ*9Zw?eF7}*a92=cu><0y7RYo= zE#KZdAqIQTE7K58Ke80UwjFQVv*wy|KKl=gWo_C-f94_v>dFJMSoTp`FtK{mT{|Ad zRj?4gfyn8zM^20TNNR^>b1|JTJl=HNE z5R5W>p|+2%^*+U{maZ=zU0ESuao-ZxsK zW~!STteYC)S}^4VEn0^7mv~dvv2AF$ba1NbK#1=`ffTm1CbNVlMVTa0jceNBz@{G@ z#w1%!=(SGb3m4R(MV($tp4THo-oHPRwEL1+GCuxzLRT(yj+KOa<2Ed z{2P@G70K0o%VocZsx4H*>gt5HGnC8NXM?oIjWQOosaQI;xL?oqsP z^L8A*m)k|pGaFmUuJsX#H04(L9h_Pq+|nuIw#^m`?rBJJRni|WIbX(^WdnRSl8;>0 z1sNJ%3za*cKPFV3n&Gc=BMMii6l8HrB`6-itZ3Oii3m1a+D&@Cn9=4g>>|RADEtpI zsbJ~>iKYtEdbHS>NKa{2bywvMTr<=T|KCmh#gU2}* zwYfR~M?Ir&v#A<vF{%)>c->H1{lKKkTCN3Fge9HmTYqoFwd#-p5L)ow3FvBD& zp+-aqN!myq1UUT42lm-+k>{sQ#X-l_sMEj6cDjb!O z1LtXVya77jRQao&(K6$+*It)HTVXI!+UUF?X-IeRzh7h>hOu6td#&G;i++vHSu*Us zIBjsE;AZw$w_@gO89^;AU=qO_Pq1W=gFrPbd`oLU@}pjs1g!DR5|3=ro-7%0z9@o* zVv>|zJ6;lpIFyV+Lm7}43T5Ow?7|G}WFYoody#b{8?%snX5&?HY|13eZJ4Si9g>A5 zEI`_GI{5AN(I&zhSH_X{kV2*Z`dK)-{vD~D`EA3Gv#i%)0QBJUeZ21GDq&0N2rRHRzud-ZX zm%k7#w}I{aZgG35Bo~%q6`v={^aQkj!B&awTHPxTW(ShV4FKb&&l)E-cSgo|e$M&t zN;R7RcWY$|E{aECt;In$fcRI^| z!b|croG&~$Vu^D2^`>&x3KpDMt0l%l@>K}ckEGa?C5d8z39IqI-ViFZ?$i-gt2!W9 z{ter6=D#1ZAAuTrU~7Omru(6@1H4G#LKUE@r?5jV`gvPf@5g6MX*f+Y&aXvov=;m_ zw5l1@L}H=w3$42t^3Nm+2y8CnHL0vi%w=7X&sODpt$`mN4#dv_ky{F|C@GSsQ$1cV%ZZ0h+e1RV_63oF zei-8yTJVVqLRitHe2%xcrKfr#m21s0&PC#0By}aKE)Jos1DP3HY+UN9z!51efvUtl zC-z*Fj9Vy_Zv`iE*j#>_q*HCvoW2DfrZO(2#qT&0G*hMl)xfFBUfhb1r?=lf4m(qj z5!Rd>-!)ETcO34%(Y>Js$2}IK*=pYfx#;d+-%1%F(66H2oo<)4cMC+ivAFfdJg?w@ z7zGGmY3lBuuizIPjsdq0L-|R#-?zvneI9zBuq6t&xtTTL)8|C?m8uf6Uc*Fn*LI@N zmrD^_wm#BmCoJZqA=eq5O-74M6M$;2c+j^5lij*1MsUvSUooEDK0Zk}nhaunm&LF6VXc>qm7Z^i;!NZCq+E~M!os)bm zHx6t4uF4i$OgRQDn*S;M(nlSMp3g8nss&X6PT5(phkyAVB>wxNA#;enBBEl%;My|@ zHt9EeE9G`f9-3l79c4v#94rUnqw51GemWt@vf1Y;EhNe%2C>4W=RS$@y-1h6d!RT@ zc7Wjp3t0>ZbPPsY&cCNt05L%T!l6vMlTDfDMte%gwipkXB;geP2fx_$Z+}{4Zgbni z^l3!II05rr|BN=N9|e(s4QHRdz7C1^lbF(w_7v@9KM|Tn{GTtYXNNwW*Mcb2d54l? zI26&^EQ*NWM-E|_4fP4nG276s-X!ojoyQ2d07DLG7I=z0?G$ z8+tY^J#A0khLyJXS=YyOjC?#&F)DG;MW6ES4jCACjeLWS7>y0S1xZ1MfPQ4EM9r>F zhDFy71`ki9qSdW78^H8aOCK`36*FFxX}CQy2)W?VJ^{~&k*oJJ8Hz90WI`(Y)zrQn zPv&8y=sIbargK9$lQN{=w~)FYbk>*d0)CRovT0FZ#oTd=X4mb4_?r4E1Eo5g)IAI5 zF(n2r?Xze?jhHoKzdnYHht_D(Z|^^hS2y_&$d_{c?x9MEydXQ5#xF4LAp6)S^0hmF z%O6SF2dNQD8op?qsy%^zQ1HokmKh3kO1H#aAZeF`Sz{2tH?Lh$9NMEzfYQjti_@_k zcuY=!rgjvPj;2!+l~=x`B-&9kq>x(jcopoq9njgywxxs3FMryJ*RB&$f*HiL|II zWQb_FMr4Q!EssWy)L~hU23v_H66MH5)OHSlgSAJa?D$ZEKgt%~3bVg5^ImiUlTK0I zzzzR1ZDq)8re-zEv^Dk;Ot`_UH)hLq{kAxr$7aDfnm&(LXosMS=bnL> z9iC(sYy2p2>4tnv=SN|{_Yg_ZhY;nLl-9+n9%N`Zu^N5Im6{d|#{CsGCOSfl$FyuF zH!54~92}mtkX7u{o3O6i!RLnK2l$$T_hSTiZ|yye@{YRp(key0epFp2=R51y7!o#H zXeKp5O&AFIkq?7xxSaf-{NE0ws;f}Ic!X!R6U-CSsslOcnGa)bHd6>_bDzb)8S*$# zQ3iw!-je#;V5~lx_v+gfZ!O?r%eY8Xc?%8K6o2KpWw)sF7g!ZPImuANL)toe%`7@{ z$qNMTOBeuc=YqgW#vrW97cm||N^2s|5 z`-N{ar<5c_51bF0rJnCH#Hlu^9s!Ai9mbg-F69U9kt@r**JVH0b~g?j9+_ke9X!ey zn6txM_JQlHG*OuXN7c{V%+A3o;})%J?t}+%t>y}bw;|DzH641qh zoOGS_OCNqo$ z&xx^cGC&>VyOpD&R$+?fI~;ni5&Ngd+~|Z>$Y?m7=;uHoZ{+d2O-TY89kwq@geCr? z<866Pq?*NuO0Y^6oj|HX#AV9%kFMKAT81KljUIK$`P|(RKj@M;O3@}%zPd>$ z^iEH!isPIztu{ubU8<$54d4D>XJWP*kuiY}cHlizP$6BIze3u#&*5D8JhJ%oQ9DTc zr>pI?X1VsEX^E(MXnC#c;Qt3g(Lauty$eQ;&>w_TE~R8Q<5ncP({&~k@Po^uC434S z3W+fR)1_4ho$Kb%qm^(iMaQ`fc2N(B1$EH6@t|m(mxa7SzRUyK9wd0Y(m5D&^gs zYi+a`VD_$N$bih}Tt?Dpm4TjKGBHwv^+pR(pFes-QIfu+eQ~7dMCKQezF-ZAqRWUZ z#F)OqqHPFVTWqa(sy$}FS@Qk zWtmFj$QsYz6cwy#MA?dO$a1M^C;LNPUfJ3`fO(r{Tc^rBg54x@__G!SWxSUVs2Q}g zLvY$lLwN5zhH)R*3+3?40P-7m(=X+xQWhqO`SP-Bv>;CW64Q7eGmFC0mNC7Faz+Y( z9$dG|!g2d3a8zpMc+*|ga;8JMw^GUDhaMmOr5D%aU2C7Hu?#cS^@ZD2Ix2qht`5&5 zjCC8cE*0Zv51Il}#JO7MRX{NxO`}RTs3uTARc!>(k73o5w|7zq?yw=;moILI3c>s< z;Lk;}W#h%(kkAzV(`HZ(#VG36EriX5p(?6?^tTXYPjiq{BH+UO9hcF$Xjv?;PsD5% zw8+SOJGpi-Knh4*^#wKAy|6IRgV9F{reC)Hxb!T)eNor=|=hU zT~kDY*KP@j`Sq5vde26unXm;8CInyfd@;dME!Ri=a(K64!uszOH~qInA2*ReKdkAg z(6dtS9Tl;&&d1<%V({!AYY?da@;f0rn$tyoS190&%VS?H+9!*A%{^3K+lRYl^7Yy2 zQZ5Cvqa@ccRR#_J6akQHwm6aA7@5Q9auz~@iV81>AAWn2#g&xNMz~WuYudH|xMzi0 z6k~9+eTF$sX7GxdbZ1}Gn-60;ZhR3rqe@V4zMzb}Qe=a0U7P*VmF@WIgV~RH^2?y~ zcwIhqyCTr|s&ef?P~XMC@!~=F!JmGm1#(f;s7#C4=QELtgzRyMn3?^c$N!yoL&Dn4 zW-w_1h!ozRfn!BR@c%f{V}ab|Ba9l@^3M%Z%ex-WUqejO1;$S+Ao6HGqR;f$dNk7d zEZ%?$)fRshNr5*Bbfu?Bjo8w#e>9o^@?8@S)YZ7QD5MWOGlh?kxCU*sZi;C`w&prd zD>n)R5iCj}(x6MGf2@dz89-A3sTp}FO@wW^4-*M$DvJ5}a*9dUK{#?nftnf5RF#;l7O8AH*4n3rj8 zMv`NIgv7PD!&UO|7RJo6Qj@L$%nDq>yuRa`OBv^8Cr|Y2#s9=s@`#TcpImElG~BS; z6yy5eT@I2zT~bEBxG3U`H#Q? z{xw15-nDAIDwI{_0Hc+akUHs{FWA8rLhpe82YX(S>4{($R_upi`0l zusaia!`V}o$ngGrBsXh9Zn7}Pr(c_wi2enSE~XpkJ4p8ASuC|+Uro1~3JzBR2jPJr zvtiz)q0pg*U8c9PED)=l-*PuCutyBe?)mxtx`)$*Jz000t1JX+ZUFrIQADKH%Dcp2 zr+((3i$E4#_PR4(R_0JeNVoUVa7?{ysae(R z$R&{P-7t$SqP`Rj$y`IUDhfM!QBmq!r6bYTFNa0ye$gKxZ|mYs zT@~V|`xRv3n=eE|rW=aQ;xeePFRJfcY?Y|-oAu}Ny*xjG@cXG1Nh$n?6Q`fjTcJTt zJ#;A3OZCn4VJs3}3doBBQk8|L)V_>2<=N#;_n%)?7eX`(;Gp5n%bdM!TtWxo!XYli zcw4iG>KMVLOX)S%n$p(z8{27kzwfU#LW_*5PKLYC*9K6MnJcopd#50VS%Y{9h#2VF zk2hY@CA{E@Azuo?LIl*i+D0B?0)0;ZOW~iN(E(;FS(pJrvxOkHfeABZ(f^ zS{~qn?PBvP!rqj!`COQ~0S&y{9-3RBSrr5B<*2yAuvT$`Q?PW35y|E>EbsXwn%D{R z$6bpqD*W;KSag;5`I8>Gnw%X|2(v9cR=;Y79sQt$39M|Fo2*tJbUnSe+-TVN%_TUe z?^@qGXdlUb>%$v_up!C z%j5XnOF?vNnW8+rY5cci4*T((OF+yoQu`s643`E^R`$fjMyuE=6X+-3eQ2}qDDk*g z*mFeU33$m4jX$o;V)Q6=*wn-LAICO7QnjnMQuV}a#~~f~bVce#3cf(u7lBEC*h)99 zT!Kw)@zXI-V<1qpKe69xibiNy`@B)J!}UV6Bk_hObb6h3#D}DY*6ua-87SxOxKooK z*2X_~_e8k-o1%NR$PupD{(mX@q{E%Tmy=oROTX8Yfk+lkfsxr`m1$`xAGPmjGg1)L zF%%K6Y0N>C^NW>N)zad4U86Ito+9bhO%xgv5gm`(U3?H;!VPh(k9AhfM!FQqpk4^$ zn=2E62EBN0Q0@H?WZkcljV@#Tez&IXwo#gP=P>NDyTDH})PBvq<0w?R_w&;*(9p*F zIAzDMPHyz**86@YvyN=GVxt4NLv4qK4tB|@_6UXHD%;C)ddc2a2$g?Udoi`XL;sit zI78^@sM|iKK^w6;Dg6nmq@&_2uw1x)fCWOz$~f*I>zN)V>D*BQmi_fZ_MmKVVr|q{ zbMzsTY(}dxCD8EbMZ*~YxFQon8o2kT+WSs?{D zgdTB%0^rz>+*r;*=1bU^-i$L2pEi+CI^oqFVe%v61-uv6lE9Of89W*cq%B>)Shoez z@fjBeA2$w{+@KabU2%$=jj%AbQ&LtHkF~w(>4cu|CC&qV%f@8 zVXm+d7dg@I0qj=Vph=h9(t2 z9vjGb%wa4@NzTGqSEqt&8I_xryDDSM2);9vKy_nd??Itd{^YXJ=;BKa4h9jMY9Yw+ z@)+UN%7*ftWidh1cl%LuO85P)zKdrSq*Z2sZMhX%B2Pl~c_{X<&sLrjk%wz?bV;x{ z?l*bZKE*0b`RVM`S;4+9Jo~~;2xi{u*dO9bW@^$u0u~!e(EXZ_1vkkriHgs)VX8*0 zWI9M-^W#6W!^ll<16y7LG?P%$K=ZwpU#{BJNA-0~7`vX^N$q%mHIfVEjmjhgc zgdSs8t=N%iQZa>2e#IOEzex7t3Twg!jisXY>d7Dii=$7eewV+#r%>7tS1)sK_xAk$Z=>Y2fQMc_DsF_J9k@ z&ff@vB8GELe7k2K5_;LSdyH~t^i26Hq+VVUpGQBYI7qX6({)LBKzyhog_C`a^pV#d z0-kqiNL9Z#!@kc_71kg7aE}(hTwQYtBYVi>z=6d*%h`n|Q@Z9|xw|yYB-@Dj?ytsD z$ZJ79b*i3jmU%4m)B7H5F=v=mih%1(QFNG#)LQLf?vfGx?=DzW@JV<*U8Tx?1R!H` z5u-ah&6Kj28|agu86NT~7y<6UQbQ)Cq<;I$Bb#PB$yLHMdsqP_J_Bf#hZd||Y?07f zm)cqM*0#Q7LuF(>Zy1PnbEdvbw*KTuTx6Q(FFa@z=VjSkEwXL4S87Qy0L>x*5qAgE zkfNxvPo*UFkuh=Itz7Hpeym|>$m|sMs=1Oe0>7877x@nw4SVjZ8|6Ya55jOJ?nCo1 z5xU!pN z8%CSh*H|nUNx?Uro)Wi$xIfI<0_m3z6kZjUK!ff26P^kqQELaag%`@obf*n-#f4tynp{lIoAf`U34-+AIW5xN!h#RI zVSWYFIOSG5UCurOq{Fx&i*91+Ay=C2Jbox+AgjwK_$4J@Q@g9bYhQY$hS#qcHfJOE ztB{obz-Z=Wt)O||2{x2rC2mvOr?m?P%*Hr2`g2W97veLey)n>L=(UkYIgQg$k{c{_ zqEcuOm!6P+3J>i{zD5%TUWo%MBw6UyG-d~e;aVOem;-um1#4i*GwM@Ema8>F9Jr-w zQcg|Q!s|xhEl^;Q?>e4iq6qbPiCD|q!n6cR5*BxaYn;~iL^ukHZ||9O4SYFZ-m)=7S=NJjecqu@L2Y)Z4eRucs}Ukdz**4AZ>#X}EBi z9~+?H(kAEd{0ts!f@e&+Q{({ncK_f$z;UJaj(B>RS%}iXoe`~#b+n_`ANhb78Nzh0 z#mS$+6D&9*xH0fIHMbJS9+)x`2S|e-u~nnE`q+8Sos=Vh;uvzqOaI7bg({UxeVoSn zMN@>bbOCoXCMpI)Z1>8|ArgOxiM$ahOb=PHxv30ShZDqX#UO@YaBAL~IPJ)zg-)dC zMYgA1vW zge&Juz`e(=U})O%+Wj5gC6~`1A_PK-Yv%(Dfhc-j-h_o!B+y$yuhoh@y&r|=&hu$_ z%2?86jk0te4WYl_0NxDkb+~;sR7-eIK*qB_M1rw3;ArhTdFe*>OwH1k_d@OVrRrW> zJH}CNt;aFqw9^q_4_c*ysk+c7A;2JS{PG@Cl8_ zIERl_DTO9ET?02l7HDmcmLnOxL?vO?Do9G(n?*l74rgOfRq3F;CtT9J%S(^j`z+sg zn2t$+rGR2k+L)MUXWKK|7FWlZV9&&kyX4~Y_A_~57kW-#Pj;Q!!0hX}Rj}?~7S|B5 zeHV?lC5Gi09yu>wB*xhZX4L~Ice~Ex`oo@g^o210_0)Ls zWDNthET-LKZw29gWhIau_=D&80wtzbpPlM;%CPGt^v&VwsvOd>{)y03!H(^W+evuY zyYZ-#-8qT(yj2TT(ymPJv=<-%0&N%~{`WnD+lfOq25To0hK28-;wP;B*<`75-iif! zL1O6qxX~uEs^g~ZOJbo+&rhY-yt38ykMR3(JffP19v+B={VFA* zTj;f`4I_U={SL!exKJR$6BE3d@jMKa5#hSz%LYx~GU{)0l6Di8I?WHt+C++IZJ{X; z7vm85Yq#*1H{xA!;=3BB_!0$%^hQUE%w&kh_*j3GDc$V~cpyXz5y7?rb(go;@z!-) z+@9_Z2#N>--H*VO()V5^;yW_mr$czSo zh>^ck2mqXTRBCi!WD&>xfd}7~yM#=D7nObM&~i8@s$_Jzdn}1@{*bLua{KnwRezuT zwS{HrGylY_JG-th=Sh6EBqD0=A$rI~_9rnB_%$q^lp3d z`YLgYq0*bEh=hH@vYqj=Ox24y^rqtQZ%RJ*c!0-CRq z8BakISN{vm-eXP3gN)}O@>7`D=o-@T()9I;HZv3;d?;_MF>xgfUQ_aE>2nBez7F;U z9f)@hup58v3oieE5jn>PC>z!Vb6xf0bO=(WQO4gIAwlzpNeUrGPp_0cBgrhrY z(@yy-`u1F9JWF0TEv@|(Y|{}yi4ZEYvFKNl+y=1&eh^bN|8dgY6^47>tjisfigl0| z;O%;#;QO`>GVpbtZEwKl#0AXT&AG8|&-s~txS0$N;op=O+|;F*o49Ngkgq0Tpq>@i zJx9IMKg^C~F;9AV&*GMtCEp+6+~%J?wNTV0O-D}xG0R@9l09$-qg7V|W0*H4tng8V zhAs7aA_Z}1L$LC1AzcohvWxYhoKYjFV&2<4%|n$&qyKsS^~7L_8kxh_qEfDjrI@kc zBH(8s%39=c6y!1Oz@%($AlSZ5WDSmNkQMtX!^6ylC(_Rb>b$_kYQShwa zOlEcUNPfj}G+GLR+q-mn$;a8Ukc6E8ofE1M3qL;4l_bjCAS3JIs2W;TnBfMB=d#H@ z;r!L;W?fFX-E&n*!9aZI9%2F`Kn{jDlp^xho1bgxPrQF)Q)E@!xr)hVhm22_vJj!i z^_Dt~#brf+xismi-1)NKKrs7V&_;#=Rr7N1qA6G^_y2RlUbTWlW3QuvnTsIutretM zM1+0{4yjEL#awy86cgEHBiYESS)`2sk?Pv3sWKGyFF;RycW%D(J;{b|A>sC%W!Jt1 zajHVXLkj<;tHliVe61^G^~c~FvT|r6lxMc7`8?RZTs&N-9M4`UkZ1HfDGi`Y!6k>& z?QX@5f=v3LtPu@w4=NlMC{6sPhG7nt2~gm|#+jt=w^M?$N_}cvNdT@o$|&!(zD21@ zXx^Y0X;fbQr?{6d5E_^h{eudk&7Plvi$q|go~E!hRO|N2KZ`V4-jL^ynoj&!!Lv0( z{6``-0ry+7cSms9fdX;{ed?$d2Xo~2Qu%TDtYwAKOk~}t^OPZ_H>%9~ayj#AqJcEz zz1EY}k`PmzmD|q~47{dEs)1$k&-8IC!r5?8uW#qiFC8hRBeB-Fqk_)_T$<3_-sy{&0eg%zvFkFB4ILgY<$Y zKn3n!O$zN#wq}~PYgy(!62LOm{xt42&mOjs`f)Zucta15Y9yr`zU6$(I(;}r6 zw}-Bp?`Et(K7H*BT9N8i7>ZZlHJ97s_sX3R0|b}w8~$pCZ9)vO2TC9T%W4Z&I&G$4 zmKvYU{#GdyZA2BqHdg)p4E+^?wyxUD)%Ua?!SwYl9&HyU87b+$hWLMW^SgkEyjhS! z45`(2zBE>ausnMuc5doMAG7nk>cJ2d?;Mu29cjr8TOda_=6~(g6+k z%$I~Du4T5wWv^kJ8l^Gf)JRT`zLDU-_Q|Q7(g5LQ*}4>0r5R^nl>IR!;mwWCTsWF5 z|LxZMJdu2Rj7)>TEdXf%<=CfA_**OZT}Xq#*kJd36!5eU?hoLsopAoj)h_Ce+kjej z0^i`&elB8V;mro}W9-|NvWKO@@ZREL%@+{ypfb_Yd-_#L) zU>^}Y(Lh#4)TgLwJ_o?dus&3rX?U31A_?_zh2mBl@zIa@it&D|3tt+ray!h zY_P+rPi^;TG&}FZvEmwULAKpImo4iD-N%ecLi;j0NRU=7I(ymN^Yf88{(O58TV zg}XbOIXl)k(Ar^YQI@hipMf)N{}^WrihOeL$5CH%YQ}7&r);oB!epIhb)oB+5I;Pf zIJ_$NIo?7pg_L_5u5*S~?fRVD3mR=_yO<`3PakL2onetmw3f4t_WJF}sJ~8`Y$Uz} zQ3Zv{QD!bR8&dVe2u*pyT#sa)9O_pRkjHyrprf<~xv4x7a;D80VgS%GRGKx1`6%8e zRu|kn^KFn`Ix8)(cArx<|J-HY_o&;rCelIH|FWu6EDI>K4kEC6`v|&0K z!5I=N?j8>*nhJmc#Oo5-B1pTS@G!7gd$jrvr0Wh#(PIA3Fdx$D)=35`JC@UJ6Vzck*hHj2KWB0mF276F8s;{<9|uFa}=-``5H98VxsQxRkem`GlgTW zk2)(dJeIixD?%5(8ICwI6DXT!i@o%y^IVExs#`dmUa0HrdB8r-PrJcRr)ix4Ye#(0 zyPDshA&yQ6>Bj}SO1kUX$RpS%6KclEq{4w2FJX0%hW0mMZ)hXM6 zSJw0G3NLgB6`;+-CzwgA;EUA>;GERf2mf}8W+ELJdTbqbWUPytUBg|P&y5?ywNSN<{H%b3syk?kzn#_8*K%IeIa0gMNtxRrtxkASmK6|7ptD3exKJ>NUx2{Uqd1{QT6jq9ZQ(tB*jle4o z;4zx*4tDU-QT#WyQWyw+#LB2GCs!4bC^|y9v9$>TC&@W}x&d@=^8!eN|1gR$36tTr za_uU@S3aq(irp+T!hrj%Rhq>4dgdh(EHI}TVV+HIg$T4kDaL5^Ast}B86v9vUS6Js zfr}0BwPp- z@k)C(ZAB9Rf;wvq;1L-|rm@InXhH}q0b_a_b1+?TZ82UU(`#p2uaj=pK|r#cK%<2{ zLk_;NX=;lp*Hj=~jY0S=+9v`Y zec}?}WGHD`bA4j_?BCn6JA z5!P3Re?sI5b!$pa(E~t6vu6G@(i6HiOXFXo%wN}82ImJtclB5|TLwg0x$o3uZrqrw z&Jh+?*9wk=ESEp)tW;vhh6w1SA!`}3xX{j7Xs|a$3@?)A9j1|q$=-RrnD@s$#B2~s z7$m6kpP1#vw-LRNR+NEg+2dQ=4{@)O%Z+Zde(vFi`rOVG^;Bq32LqXz_@ugykLG#wwv`oZ9w|y}$X@ubW(yk_ z6dItc|I4ez!iXC$3LD0xCA0?t;sYPROHbr37o3S?LCUw+HJnYUfk_AqUQgo&B@2e6 zwH+Y7Z2Gk$NIgjlk==OpkH&=RA>byv^w0QWTu{aGIsut-ztzy+h)-Csd@A5aa^ zeB#DsL*;eDl8%GrtRrW zH&KoeUW?_}R@Qb~t%>3kk^DtB%Op&hhR}=AkX=8Dkg8sa`q2HgQr~4$rk@Mz$WBdsM8*j`CQNWF^&e?CV za>EDz(O(fx1dr4d&U=kxxEp)J3s)frlRi}*Jmg6bp zC?>?AGF0}3Y`nbT{pSN@{>*k{cr{_$Y{GEBN3dU`dJz`w22_dGrR*pH|Fil>RX!!7 z$fch@n`1Et?82qJ+*jXeVUE&N{>x=iU=r}|`_wn62W9QuezHgWZNPk1l<|H9DLs#V534N8hl)g90Ea}qmJcenc)X?-O zxJJ_wL6q@;hiGq*J?@Y=mSXB*6#EQb&!wOA>sv%ori0;8svALc`0LuynSuZ~H%qlz z;o&>DiSw{yQX=jeI5{FIBs-AyrtW7SN99&nll7r#YW{X@Ke2Kvo;rNrl5R)u`yrlW zz=Qyr;>ko%z#FZFk{_g)d2u&OG$O_a&>m>ejW$e+b^SPVxg9tuy<+`;Ti^UcMVU7m zxm8{ftb`(0OD4xmD#b-H^4;;5Vk`2bpAMGFJ+MT7cFz)As!e(2oxo18gsBST%*421 zZNAYWhX2L1B1Mbcvl~gwD42T(Uov~ONLcxti3{fA8e&9`M~mb{caCOrBv zKRgS{Bgl_eHi#3AH^F(O@wniDLdFX>**Fi?DA~IqqYEexkR{}Kez+Bi?P(wo2JK4W zOQj-_9#tJ1i|-`bRYEg)G-glc2!b*~s@=JBPiDZ*=V81;6qqk5Ff8gijaLwUNLXfn zGONeGR~wqstsEQm|Fe+wl{CatPT}|=!cD6r7_1deZ5A29QPLK?v* znm8&rD))F z%Q->dm4(_!wo_wq{1I0b_b;zL1icJEFEd%dcH(BQny&C^dX&0oS%+4j(P}Vldl^6%VZ4K@H4M2 z($em(5htt~`U5Lm?oEG|D`SrH1kiMGCrl{99cuH)vHhh0_bnE>Bf(0vOVQq8m{R<%sa&P7d@pP8?(lZxxNoWy~Mo`?HV zethrbpmJx?c;p_`H3=TWaG$>aeRcgHdJQlH>E}u&0nS0qBHDpOS(V zdv4Q?yNFKQpnrp$N5=EVG>{eFXYkw^Q_bJ#L#$SBg|o z0ErDtjTjIZBF58ik% zi(qSKGHjA{J4l*|pXT6Xr!@!O`s)EIi7MYM>gN!4mcmKRoXqi1l?;x~?L zf@4mYmcb@1I+u~hRT~ZK-}t=1+ne>V6I?fBr7P zm1TC=8RF>p_uE~91;6fM0rWkI+fQy*KvidWKN~_iK*DD;Rxj<^C6iUkefY50P5$yt z*43SBr)e$p2hi0J91Oa~6tAsZpl?;)(#>vO>$^xFf5}UBDB7xB-jGCVsL%uKMxQQS zqZu{7xfS0Ns3|YMSlw}$S<;3EWkONfU`7V=9Hh){R(je>96%n6pdeVFV-W1TJ8t)Y zLS-6v4u=w14ajA)RzjL^AEpUgy1Ul(L|BMP$0C_Jwr_NK@ewmwDIt{+Z2h|~ z!O3ot{dp{ntuG~GFcH4`{q^bIodT>Ya44vM&-ZXmh|!=QCsyZgJ^&00i&fB97$p=~ zlYw-kqUh*+7E)t~gG`dGEop*M+?74~^xZ$v0BCNF;n?b=qi(NFf>1=b zdE>}%-Z~1TIt6j)K_nuu;Yc{XJ#4k?#oC1vJe$E`R8s2FE~WL(0dH*>eJviX1Ugq6r8kO$yVd}FY@E2znYd{g5Gam&@d{1hMS&CZ{~f;gnGCE0St zobSbqFgDXXJ2dZRwYOcU%j@VRF2-W<%L5*wMto~#NBu4ICI2`a=m$zMP|!I%YqY@1V1=1 zbLffFA^r*Qg0FV3BGM4%AYM%mk-VMvN@8t%MMkZn6 zB8aX=Xn1_`JXp$jAm9@Ud~%Tic5YOne;$wAjO)%11RhY(HNM~)Fw{M3>Bh>9hq0h# zL~>(uj8w$|mBoqj@YH?V1y_q+%W?D+pCQ^TWuYk<_NK=7Jr_a` zUz4|hNQk$qK?yCeXtr2tF~?<&wOBb~rkP@@|l5D>s)saj{*wf_?^4A)L%!Pcs@7J%5% z+XyeRIFkZTSD{9}w6C8sBh`6g=Xw)`{&Hj918)pGWvB(qLPq{o4*YdCqOa!UuP9X-4zj`qQT(E3W3Vj-yNkNXrM#DjQ)?TF# zKB%1`x9xim`L77b<&4s=gWV{%b*VjeKjV~)n91SgCP+rrY`;yP_jTuV4KTG8~I1rz78F(`C@+1P#iDjnN z)#H0AfpewABWX-^uV>*bic<1!-pJ5mC^DC@)*XVs0@|9Qx6S0akjvhjiR_BtahK?L z>MnQvffh7j9Sa;Wojc?Nu~af=`n4}sYxYl*t1o$v29IO>O~ALjV5Mm(|Is_$CZA}A zL6G@n3_+pn-l-8EZkM*J&*gUJ@5_Re;)_6nUReYQ*>2!deZ=$XV;(U{{pv~qQ|t?( zxDOr12r@*JH)bu9=f^9xI2_2o)=s|;?;&xr3M$!V>L$*zx6ZJ_dBc@EEsR{x5{WxQ z6t?#r`AV4}rVJ8#y(u_}*izBu^Kl%BL!@HpBTCP(L^VO8JXtZBdnWJNp}&rv2(Q}O zxiwgYi!&paY_*)9S= zeJ2gJUx%I`$T17@9smNoH zAZ5$wkD(91tYq#;vRJg((x_PJ9nti|maWDb=GWUWyrs7_6&>Sl8if>^fait@mqexY zuIC~2p*xV|)$nPSX-?hHg=8MA8fOe_1DiSsUO7;If}Z}JfXRf|OUU@2Ua+o> z>4k>SYiUaQ_yz29Y{`1mE5G|x(WJ+Pogs@gl+s?eXGaUnK@x2ojt?%$x z{26B$6YQN_p8Chwr3?Al4UVcT$*I>+P>A9InVnX(v#Ew3iX|t+YKqO_4xE-87100M z5d9>UcZj3+;mnQQ+b-FrXSjaAkx>9bQiliLdNh$>pk*o2mTW92U6LBk@i5*3%1TFQ zJz~G2)NUq*Aaf6FW-cq0`C#iAgS=*Amy2|c+^S>{92?~^s&{(PuLXFn zl8;$Quy=wclk(Qg3A`Ntx@Q65fc|06K?0PA=jpDEKXB`@;BLt1N!V3GG9+GCb!y29 z?YEQW_X zOx#Urs)*GtGha;I};{oy@E6{7^2X|JTDiW`Wv)3 zs*6=B?}>ifhhuaQk7!nwe~s@y^ch%H+YN~^7KOzWsr-sQqAanD{vliPpaE3>cdBD4m0>C;~p^MQ;rOPWh(oHOL%Q3ZS?V96$9W4!BiT3o zG?6m|)Vm#gR)qS*gY7m-YD+RzzH%;3*_=}koGM(Wk{9L-s{-hh-u3T5Q2A7q191?} z$IPzhzcDYuL;?OM5w|ooCXCc$-ncD%V4K;>XJ)=8*nl0`FYW7fGB^G!jJvYe2J zE8~?o6wO#pm3pCw>qq!?pK=PrP~x0C)c7Ln)gX&iH5rsTJ;>=CqgwV@e>%AVoX3Z_ zxyw>IvmX6+sL2q4&3U3UAibl(>918q0hQAsWwz&j0X zLPtP-c~(+Y{Q_Dp(bv+AUvels-W$1p-xebciY=l0foP?y&TYFqPOy%-QOTfzHtES4 z?}-(?9utqG=6+Qw88jN9Bakj#L1p5dsOYj+o^gKedmQVwg z!!75m%$M6&L-S;-<%eUIBSa`XS3OjJnd2?Z#wu;wi$khC6GwbGI>=TFKMtR(#=f7_ zd$$~#c3t^yT5Y1h)bM~prYi+VkbtLX6*phH8{q))ae(?NB++koATJ|GP?tl{ZXk&; zaE`WWVTj7_VV@)OYllrcs7Emw^u4(ak-qj9YTs-?!Ii=a3+oy8cu0qa!v^vWPcgA2 zT=`08pk}grVNOO}DOV7vwhYXk=}A)*PPKLfiuTYwuo0h znUcSES28P`ko1@osWvm@0h2ld`XCK&&SgnWs{Fjg0QieMA^9@z z_iR%~)VMC6)<83-F*VFdtsZ5yO=P|IZsuSn1>MEK|1M5Qc`T77k8NI| z5Q36Hkp9v}IZuX{_0w?oxO^wmPmHHNnZ*3dX=Uqy$-qf=4#S)_F90d@at%_L zEZmQ>Tvb8qWn;Z+S>m!u*{Kog&T+LPba^`uv2G$?zqPE7_3l6kI=Kc2sk$YJyqNRR z4*(#k{?#-9VW10u9w>OdCN@1i3@X%*)3+B6St_%@sEM3n8{qZ>^yEIY%s- z9f_1l+UZc9xm#rU&$ew{4NJ#_)RO*mDyWcG5xqE9tthK3aA9inHK^40Kupty#J#(G z?b$*pr5&M{N7nKUe(v);7+pkh>886r&$k1A;vK0@qU8gXtWKk8kJc{JFC$k0zOK_W+a%{$&v1T*p;ZWJsEoV zPQEAW`+yVr_lqyYK{(8h8rKmEs3x6;zzXg_r;6h1aHq74a8He{8wW8Nm~GwJysF$F zYU|=;5576Y%er5oOqPNbD3tXc4H)m@_QWFa4v#@$Yd5w5ulrh$sJb1Ka^HcCY{%`w z|N9`w7q-H9<-8lDMOL3E`J_}hy_16&$lMh-D%m}o0_+a@CAefydf55)A&D;%$DQD8 zZ?z0TY5^D(<&E1@*OfiDy!&I7R!ihuJkpwLgj(j!ur`ZV2|Cl2#P!$L0S^BT9EWF* zd!7}T&AGS*6(cOygygZMIp3LFhHH3<6*YL=-o>YwaO$Pn=~f9sfLvtOr(Eqk`VIoZ zgVW*0K?grzz3<`iZTO4&r;0c)m$F3@p%9vE?)z#!#f|T)T+74x0qf;Xsba7ob`j2*GMBj~qjdJN7vpnMHOejg9+dGxL+~gQy@wdH*lS`RU zk*jyGYtyDn6?NPL4j85n(1k=qjiHdtcpN^A+=DjmqNih}&15X`DNKbML{WQVE{=fD zIwB!sWhYzdxL$-PcKQ- zjR}o`I5!Ghd4tg?K#vMKuvux8yU-w4dl{d*W;r*v8NG9n@f*QL{S6`P4Q0*jf$R#Q zwm_CB+*Hrlw+DLX>X((PKGeeWsh6hgecS-a%u&$~tUe{z&O|%6#%1>fj`$ zQ6C%<%Jrtwe!?MHG+Jk@o{#Zzu<6gBlUH;+7I14Q<|*)v<#^VS^C7acbKy|jzNp}syfT>TtfX6&%XMOn>2%$uO5uoNT#E_MNc}@4Lbv}R4#qHSS)lB| zx^7)PP_a@|ayXjOcc{^i5UaAE9CfhYT9h)foi3Ios)uEICoj`h@gN}mOD*wcKRZAc0SQn(} z(E}b*T)4Ko0xuekBfr!@VEGI1OwiG)j%nCHSvjYnSgZ9Ud1hvg!vHmt&}z`O@wdZ# zkDD9D$xBK{I8=K?rnky=v{o08fMvC|^QAD^F0)$lu5V_GtprVTZaC<;Rf9PZiD$b9 zgjisGso8(P!gbOWLo<}#h@I}a4Ty0^EH-48h}_Du@C|NAnV zMGGW^wQjms`BIP7K$StgeeZ^wkf9b7K%buU*S?srj7!1DqS>lMSS*s#UV6B3WGBo# zU?Af^QVr=?33WJAsHrYCm;ecMD!5@cl-N5&xxw8ZMXCrxBL1Q0|Y(=b0h56eZNmo{3DH#Bp@6o zrKrFXn`RFpXJc9+mCC%$b_UPBRju;0Qwc*o-qtwX90CXqMgea$Ap9<3-7 zq3EiOq^X$3_;$cbTi8qezp$rVW@|(Ou0|YY2gpnhomd-`ZBnejY_4R)qV5us(1}6y za_r!8$5VjsxHw^4Z8-aF&ige{Dx(#?#vH(PNp(az_G#sUcan!%VaK@w5^ZcBH$J>g zSP#dVf4V;d2puIOlyc)A)*H+xQduu4Y4S~QQ8-luo9~3G;V-LYYAT6RE*B8kCbJ?s zx+doQPI~M)5MJjVImt7cb+JCA`rZ=>@jXJ7D5Vu{dL=|RfF8JwLV$;0TsxO$#toVZGGLj(o zulQAJ4NXJa>~0LVo`r}KsBQ7{0^ZW=>~m5la!KF(nnB)^T=2)0SsU-CHhu4zAoeAC zTj|<1H&L})O3xt9RKUJVq^*C*K8}gJTT)RnULz#fy%)>RLCzoxmoO6})U=Oedv%dq zl@nR1SInVa>#Uycd^qd^`ul)3T&s)OJ7Dn&rIHTwgkm?pDk;^+rR{zD^Jf4$Aj9?1hTOZoe z$MH7) zm! z3+mWGd!e8vpKS}snH?RCUUs6Rl5N@l@7^Kq5E zXma9Ii{3LqN{RT>H&?gU?0%_UYyr~skoF**HV8AJOC?CaoAbY6bII&%Hm676+Afc) zMh?Ii!z5gAqt9{ndU8f1oCHViG~fCPchWmOxG({#JLU1wuyC+Sqk zkD~mNnj@zx$q}g8S8xPbS`%OtG~w$)k%I44`t?#?~{^RA-<$KmS#MzgS{ zF&+K7W#a(fhw90(gTImBMj80~u41+v>o$YeC||4~+|eLSmMN+P8-lxEx_6T%+1E?o z?@|BzakuynU9W z{O@-+eXmU=EhKwd*)>e$We&_)0BwCp;ECee9DuAOOYBs$M&;s9Y%2vZuVB1+1vXoD z*rNNM34C975TV6qu=YpsO#Sgr*Z~e%g6}#ORarF-kfd{>;EwSzNs30v9IjAOr!oT9 z>D>Lw3gNj1Dp0{-bU@g0y!VK(Y@1zI6TKRf+LFXK1Vc99{Q58X)x zE(}6wFM%N5+_(W!lc=-L-j?dK$kYDh28k(-njA$nb!w{@ySx-i7KHFS6R|<(__UTl ztF32e<)av9r^|fAG8(CLba*)?ftB#5(Uo}|$kS~fDW<@lPi@?8#=R+htI*2|7bZM(#5w8s=ovNx)~^=%hXLSpTZKu>SaF%-5a zgr2EHWRy6qLMH=LEK_DucI{{7y|e#A$N3>8hZ9i>(GfEQFn;i$8J%2vJaweSCA5 z*0Io0&XKYZ6kLf01olY^M`CdCGJ;+rBSNpJ=jU+&fZy+yF)(bZVP9Yj_!B@nD8aJVYfo+Fd1nS!?7wp-vQaD~D9ydk~ zKdiSImG0zj#!iP|K!5qh^ozEId*4W%Orc4|PCrMiJ*U~i=knIEV5kHe+4J82ybO@b z;W^L)v{V8t!=)LINUQ#Yau`ZUlE-hi(BPMI#$40OOo^>|NoSm{J8`VNl)_?`0ZL@* z9_y}OybBBC4~S0VQVeht;`a|o{F#Z9c*M?FyE3y|pMnwJ6|ug^Bac##JVcRNl11j> z$ALjfHDHZLHH6P!uc7`6iDtH$ai$sF>y}$?hkbn^;M5%N`f^YNuPI^?e$wm3`Y9nR z((52J`I+<|vD!loIa91G%%llHM+%#TA_Zv&?OX7mM!hSSz|SyPBsbHi$I6szAbB}} zs%ETh5xw0N;Wy1wqs*7IQRLn-fa>Ku^+Q8X3Ky*JY=A&wP=gKQLk%F*jZMm-yT%}OtT+TN z?}C~zYN}~R1!k1j9RO4@m&jD&D~lNLHfn{MqpiOIEP1rN|e%!y(Fg6ds1UHBnLCe?cOp@|GTS4ZZe9R zNoWSurvkf)68UNw2VyAAzPp|EYUG)oBS2J{R+Jhh?{j9L|1T1pVkbHIQc1UJGsQl$ zW)wr2l}kk8j-ORxzdkD)!4@MNd^w;>a+wp$FE_7dbe~d0Z+V%=4p~-610ZSU;0l?g zj{Tt?1!|Q3j}A1udm*OL0DT;Z1j~KZOQM2;HM{bQo?!V+fv~$^FU8#;ZR$m?HQ$FR z%F`*zoLZM8m;Us)##M6flAf zhR^=RO%x?GVV_lwenj_T2w>dR0A!`dU9024SnOcex(J8sJ{W zd#Ua;w5JE zPdP_Vwauy>e_=S{NWRz{RxF<%V9)MkDgadVo8XNbxUi691mX8kDD~jU;9%5PsPXi= z(zwA1>gnGmmgpmj`{IoZ{W9U{sMa7a6yO0J7ljvPPBoDO=F#}n?dnF3|unq+HP41M`UA5CQ{VV4miL%Qdq5HhZ1 z)STd0>va378k9y(2DVp4>(?Ej9Mgv8sk76Q??*6@J1L3BTUpL3nNpS)8xoYsP=Gvq z1+K#~J{a-TjKB<`5P!J2RBzCYKQ~sGd`VsUlHhY2rx$!|=KS-T1$VjVuZF zM4eqR-owI}bSQ)9aG*W9{wULhL>9Bq#*t2b19!tA;`3Ff+0eLHF8)?=0_O7i>1&eu zsa$2lhjr>V+f;P@EOM8$*f8Pr665&JWn7EL5$+5$v_HbD-G3JyE0$n?(p$}JhyBZn zc9ZKc%wYxM(50pWSzll3@Wt2UJ>TS2MmNV&Vm^Qj2a~Nxt>|Pd-OFC|VFOzE;dqhv z5RXzh6p~F|X14CHQD!rPY_oCb+;*|~1mQj`)2JOVLSjk$Emd=)zZ_M*y3Zmj-D|)v zC{F0RJuo6hFg?7A68kpu*UokmP7gToGd*%KKLD$vF^j`xd07_7nPf$2Z}|zVQ-25* z?mD+`+5PO=wY-_zz4L(`dk?zSZ!CC+l;DRkaEXa?(tgW8Z!@0rK~-}o zjb}FX^Do2lh}S41&@>e{CQ*<8e=7#GDp7(EI*1y-b&F-3A56?#$p>iDxH?Nn^Ktxk zVoGLhNlEj+^x4fssBcgUb2M500xBJXoyePl5a*=_l0!*F2Lyk>6NADN2Gxq7R+RbY z6G7n*C-$J7KCbM64(J<=f$>H3({|N1ve^BKC#BW{K=nYxRGoiVbm~63C2ZC}JywSmyNXGBs-YbnKr3`*csEm=^&y?Gu%P zc9=Xd)hr_g8mqX)0kpcFw5M6MH@9AOWwt08co~rmB5Yf7bEsApZHvXrRyJuu1+IR` z#TDbxQ_6|*Y(7TdKOHXC{`WECaw0>$qOY8K-X3VgA8!Zwyj zW3Lqrb5TM?TQ`Am4IW384@b9V=adt1;lTHl_^k-RuWz+lijw5Ql?tI-NEM1@@P(L6 z>bZ9fnKnwEn}A{R#V}RY>2f9*PS%H(3QDhG8YcAG z%sYta;Q36WuD5T5(AtIN$6^*&niI-^rgny%k71;8u_h z657AZaJ=kL0gAnvIJ4wW0Mjn0vrk9V!r53heZW5w+<+m*$V|UXkqoN3^v%~2vY9BP zMxxGdGUtL`W3^gGirtdE3fe4BiH%Bg>$eRW(2n>v%`!wVBQR1PIRZASL< zFAC-W3Q0}iW;vcRv{fgR!G9TDQ?2znXzbtY`mdr|JSkh>A=mXgM00ePMl)fmF&5fp z_S7!mtc5bTZ%MIc3{C8UvUSE|avi{U(%bvw#5aTpClLh$-Q;a1w(SP;Df4v6_aPa!i z+VUTRZO%yT@~xOiJMFgbyQ#FVH@ZYVs0$TRQuP#uCTK!T0P)CqU6Ph!?szZk0Z7rT zRnO|kl>YV!-OMsN57JQ74OxbZK&aA##mw~sHoD01^L|FB?%42?H^n)c=QsH;}!Bjo&pRKhnRHhUY*8?l5V4*qnv|r)NI_?<(scY@RtZ+zsoiOQVlk@N|nb4 z*t~)aW&nc+F-SS@=;uwOxSop|8UD3+zL#*$)kA-T5rPQuMpnjLX<7_K@_>0PH z92zb>GEk2}T$kK1HsP@8|5=0jP$T1YJDfxUag7Vf8Pv>;$|Ul&i#gA$qUXK}@&EYF zbgfin#ll`fr0%gO-f`B+P*9m7d7oSKFL*Tj*WBQvIepadKc1lu zCiifqDDDF?`<$R65jO!)^4}xp{v?eAGw<5Q|HAi}PLqoI>?T&I2V6JdC&4Yrz1lUOs`Si}rG=xPNQ8XkwxM?4|?au&;Si zFeQZXEtR_8up&gd_eboCg9k{h&m42$<`>M^0yJFb)^4^?yj?|(v4gM@v#BL<0ba(N zRfEr#lpj1f9i4AZUT)wTC@vdkZ=5p&@X~XaZhIyVb?gPU*r9$bUas~>t*Bz?T!4<- z_^D>dR6H@dEXXX)vGuOT0+Qs9n!a_LP=hw0ClmB)`(dnlM9tyVhnK?an1_a`AW>>A z#?Sr9Y540r{fvv^+YdHe=}@AW(RtC<#%1yinc8yb1Zp>26iGU%IGKYV*I7@9H# zvvfmVv)q0>)?2e&GqttoiP;AUUSR{%Xd@+hjv6XrWd?k|2B-7;@`#oK$zMEzdXT*L zy7aunlDNumd_$_bGO=$(s6xSrl*N$e^p!b?*XS2Bze|lS@p>@+o@1W=ETyc}`ib)| zBkTYUu?5!|L?nw)DW&RJ6?p?0Ne=wa|9SGoNIT^4el2*MNQ%^&y zTN!`#Dyo`-8TKhJt^&qoE5_2V#Ynq=fpvfBNk~8%WJ~X;Y|++R?1?j&OzAfyYTh-T zv^`I}1YKjinwS~!wS?oCsFnjBr%-DupBjP4`!mdYTrWxv$NUAIN#WTtOWI00p-h0~ zLyA|dFXb8Q8_7EfusXJRjwF)Z?OVjRm;=A=Vr?|CFlW{O&91#_{i>3C0c&y37?xm} zX)Uyy*ON9F73&ddu9x#*1b!g}SjL4Xl~CDHu3Rt>$%rLCS30$HqzLnE;#LM1Y14Nu zcIhcx@C1Rg#Y+`0BC2vdZX-xq3mkh}v`y!3D0qaCoW361M7Z(`YaNpNQDb$FEuGQ` zBZ3~&<3?ij^p})%$IlYI4Fxo2C+O|)~VZ)x~p>|aB(K}#(|8`-{!G-m!xi%U3Fld7f>v}{%_;XCIcwKGvK5ME8X zsA@hJV|7);lkWPT7$spA&nw7L;=D1;Yqrj3=`#q=9W2T@Dtr|tN;cJKVJT+!GJ9u9 z0<>}RRMJ+cE~t3}MyB1C*SyCv#$YnIa_8}FX^ao9qLF$W3$Ty`Mfcu9WgO*l&V z3y=B;i~3~H5Xkbv+;i7dyuHR=p8qW6bb~^b1RU{tr?U2PkMwhwj_(|fhP<0CXEU}0 zH`vB%?BeLyU;k%DICE!%a^&QbHhV4h!rEJSQkZhAfaYKp3J5ibym#*HBFpECyA((U zj9uK-krmO2!N}1U zhfI@%_)dNa?p}+#O7jrMS|#ZJH2ABgUi6C6<%aC(3{3G;q!D z?bxim+2m0Ya`_GJ%Erx7C<9i7 zM#|hm@Ar0zJ4tj-@ki5oGzWxua`1AWF2E|OATyK$XcS60$&HEfmK~hr<=V+-3R7$` z8(`oyD@PBYWxFN!aRb|`cBktk{*!pcJ9173;v&sy)W=&z8Oe0nM*1C>`#AnKih2nc zdth=y^gbBnc_wbkN=sj52zYgMVYr%Ei0~|Qb?7iE)9u9r1p9QJr~7$Ei46ShSsEN=XLuChnGt+lDw7UC~|L)+2NS?IMnN>L9rhr?aH&Gi!su z#QvCoN2($CR&C)1`Jx12TWu+!gUSjITR-qK17c_son zYe9#%C{9 zP}GO>H7AmdzmE*5_@6b1{5b2EtS~#z0qRlW;thhB+bJ!r)^Aqk3PN9B2^&6fy!rgO z-0;MMxmrP>h2+$_VMpSdfE8JRIy2MS=}W^3uFp(JFd94h$Foi#G#F_-yfS?6)^A*u zF(_>GxbdS}%VAfmhfj0@KU!v{oL15q(a{Ts7TwFLZ2pMPq@;=1p((o$C;eh~P^j6S zqO$pMmb#v4&8~dhsD~bkV$AxWD>v=WmPoj}=xi%zSLpl$lJV`YX_u3ubveVc8|1q^ zB$ym>r4s`T2zDQeJGC5cr!UghOR4#ni#{V%oE8F_>`9NL%GW@;=&PEljv;!E0zZ`v zaJv#uN6SJ%ESy-?kO1fg9t8onoXo4J+6#ip+9$hmwYdx)@WGN>Fl#wT0Y^rg5Xy{?WBE7Te2Eh@uT`sIt>EOWaZJ*~)T5PsWPj z-tr9=D5t#y18_bb=?y<=3QOQX*B2%|88Vt9L6-VH#UEw#lb;YK{d|M#O@yNk`$I}Q zD91>`Dy2su9yT{;0bJB%h02cV(G05EwYLYPZp(V85SxU(%C za=RFn%-z+qNr7MIfa6tKn5k2#GPu0E)5|p*w6vI!N{_`IYJry`j_*r;4z2ds;!Zaa z6(@|a2Q~KRS)dzcC+3`>%yBFU=x)J|zZYI&;(Cng(9r^hGqg<685mIVXoM-F6YTp% z{dUB^{AAspk+t84JU8v7^3;$0c+c_;d33PT2pgOnRcU!6OtR0+{|?1rVAflu&>Y*t z-V44qjY;qr)Q*DxEL(R=FLN(U9YKOsVBX0;IExQiE12Ea?SH^FP5wMGsZ2(x8a zXD#0Tb$TbN)$cm-T1{ig3>^r*PL)tNb&PaG-Q7S?l;FgyEJ~+4RoLie7PW^oHpg-Hh(l5+*&iiXG$!0pq7zKUTVJUVL>Y7N-t3pc^UfkOd3;_Wsk>`noc zqp!lvZ{uOb@t^iY)DbK;B{%eS&5ZmbspB{@6^GJyc(y(D|z^7+0*JZ?$S z@1kGUITb;UYl^Fn1w7%i?sHqv+XZ;?qca#tZnIz9Mu@PDk5o7wd1$wi7+Bn8WC8L} z)h@EUZthK&LV5ZvGsF@Wp;UPnaWPFWM*BE!SBCMUi0CT6|4{b_Z0s(x-;f+2aha4k zP~yHOSpY#cCf@+QM3hgk7Ise zWSN4~j|T&R7V!>C`gQWr7-lprqtdv4*5T+0{5Cv*4#3%Wy{Hi4L0Q|JQ}o^;SAfch zD(_Squ5a{9SO0ACb2)|vk1`UV8G1v9m4{$*w>hWxH=t~>!l@6J*x9#rl3%|6|6O7OVAwe|*YM@8@Hpeea14C7pPXjvB5WI-(KM8tek zRGPAr1wB;#Itiz}J^rdDiDZGJ*A3ypuK1m*6whU_CJ?mNrY;x2>A!BGFG~{w!@*Bo z`0PPukmn^0RNIz(wuavcU8?ue&G4Ay*@){K4??OV&Fbf17%KH$v(fZvxRJj?rylw3 z#1MASNbCy7-ed|;lRUgjQQumvYBvY7*0y0G5~5PZcL~jONsg^{8hfB7E)Uk-Luv3o zL^l{J`2368WfAtK&Ue>e+EN`|q6{U%h#>V zq0JM4LF#_9^YBXOuq;{`fg_W;xxf)k@O+j*x$7`A(2Dc->T@OliIH05=bQFQK_;T#2MC|O!biEEV0d(z1&#U{xd^7sVvQrq}! z4@&`*oCzv?tJxr%VIpP}@^ROd@-vOq{p=-f-3iqxQ*M4*CDgB{^wmsg+; zih|!}RCqA;IW-B4fMwMqUo`7)y253`21~y5>K_JSx%fvA1s9;9XdYN}ET#!bO3iG&+)7hsFD$dLooKF`flRTw0uGB$h*e)Ri{xSXweWv*aiY+nK z&7oRo0zdn1`-#lfOTv2Gewt4zF^cf_233tYLOc|I$WF6OMvjQRedt{AWI8)-|A9iT zzkpK&pe=W*hd*PsVo1vYG3GX`1Gi0IOcn%ge>Rn3v)Os!tC5#D><=1jzb+ z=^tnYU+R`aW8GY1GKwQpp@!-IfI*=459>b*wRPXzHg1&tB8+aoKIeOkDhmv@72cJ3F2m{U4#a}MsA`4$7Nej zOt60(^c*_^&r^nAI_+wK2@xeDPgwJ>Qqu_WfU;C{j`!VD6N*@m%z5|_HOcfiKc)1{ z=s8!cL`w#bf?H2xQ19iY#P)0#MCHEa|D+>BjK54RDZ;+1z}{*jrxJG@O+VDsC)2lX zV^i5x=%ul4$6%1zxGn;4!>Dr_E5g^D<2jYU{f>_fJJO+^LyWbLuzN5I!LT(I3Ji59 z7}H(FP_L!(@iFj+R|mL6BfWVvqau76;s><(kPNa8G%-7+YY zEFGAS@T$kHRi5IUlnL`{Q@Q}&L-!ER*ck1{(0mWqbdVydZ5RJ~&UA=dy_+*gD4Q}H z7g>6%pe6@+<4eB?wl6U(Zm6vTnHb!hLvrX3B|k))3;5tolm&ZFM{8XzVb)l`zGe4l z@AzsO%?3Fh>tqYaNZ|}&Ej9WFPzbxDerz5S({91M-LJ$*Zwp3;F*=-F)_Bv{vrgmf zwPGqaVV|H;&+PCL4in2B8`Ui$ElC++ys{!+1*JN{lGzQEv^1p7DFTcjW&Kjom(4mVjrt7u5HgAl ziNA9(2JQ4BnFaZ?f+kh{T^>Y?S7a zag7QnA74T^<=olkoy2ZWu9MevV>akov;QB;lC%{_#~m_jS8_59RE4sQ=D%YSW@q$` zcyI`*N2zfk1{gTK+cao+HYzO8=+yAqCrk#|d4v46+^f?i{xlEtbzoU-wQ5qBU_2Ck zGNpWjJJEd_7#f2W_XAgktZ)mH-nbD`S)NY=Zf`y~D|1r2{_;a|2@q%4fq2*jiS``4 zaE3Tp`^58phE?0Jkve`8&QD}6$6fsA zRj_ppg2t#~S|8~+xG@&;R;xuy)^B?~@%X~_@%b)P*pJz^IBcg4h zRe~(^&6&jVgjk-3vEc1BT*f^DV4Uf_Y*xA^uKg==Mi$`+Mt1CIqaBgsw6h~LKu64_ z1Js>)d&T0HONAxGuWK1tZC!=;FdWu(=z(;I<7E=p=iLf2H1`iPs2QrHgW@>)jRV)F zY34N!i`Vlh!t*I?C=!a3j0!w_w1;SBgPXu9qAB|S_-3m1T=mKHJR~sW{StP+A&GJl zRIKXA6k*YWtuTx~-k^<*|SlL3)5KirWpGVgXX+;+w$Vo5JCu_~< zWRplDd=@=JL-|JgEa%_NU2Ri>n}OuG3@jyFLDC!n8p_Q47Mc^SO06}m`kyJT^F~t2 z^-1o+*DJ|7@yZz_J5G2DjoRfnTZ^_}aiv!-UmMMY}UF?x85b^AReW}Q z@o%2#uSM?ebc{dXyf|r!$DV-Rx?&fK$bWUN7599U3b{4m?WxC>GlKmfaZ&21bh>(R0ozCEIA{D>P<8q8or6);bFlR^SMB4OPp&1AdKzpmBUH zwe(fqH8&qb56o>}XpE?N)lpMVLXC&km>J{MTcjH;l^)aucfBvBhN^kDBC0RH)dF~L z=(hlB{{+&TZrp>l9W+Sy|Z}MWc=rbB&9~7X1N> zFQjL^XI5I>r|VxBKnI(cYPn8}-C{}AK@voKkbaE6zhO?jQM7&+J2)kJLSq)Y9gBx9 z_Sb{qvp4=!7HsBZCs7(Nx-+sEJuSLzw)6!_#*E5Q|i;D&x&*Sqha4SYD z()DW&);Km4Z(${&lRwF-@kUL1U)IeC<=;HC$y23SCr9-s5U$B>=0A_Msh!5!lEM>D zpFX68$vrRPrZ>~uk>zBOuO8NsND6{!KI-xot5#<6wvlrO2Qp8>3cmlFU`!nU!{bNa zmueQp z!%Uo|AYVKOf6!@|+T63#MMO7XTG^8N3#|^U%Gx{xvZjG)eLCr&6-rAxgCL+6vX0-5 zdw>BGTAV7QmeIYI`zf}!7kASPxmtoCk$l?+*0|u|gU}cukGtP+EzSyUW!FomSq$ta|En2i) z_P(3hDj=x6$sw$NJC~u|T7~6{AN&F2#on^kFqR{fFcUv^RQRa5z{)q(sm|3g&$Y~D zLdYZs>2SAEh=6D|SCbRv$0D!>c!;#phWDrNg+oVA7vvt|vDWr;tNued!X_z@GHwY{ zVr~OXb1FpC)Es()4q!3@JP#|Rq(RmtPW@8)UwVY9HcHv^45A@2vfng($tW5BBSpV& zm_!~(9ATx;-(o7l!Zx9h%wPk;n_z!fE@cLn6wcm@k!e4O`dE$x9JV* zw%wqIzg`L&ZhFs^r2#iZpTUXY(A{t-88oK&YpYl<*%;COvGFg_rGW5mi2^27p(bLP zrdP2SDx2iNxDYe!X)h4t3S^6ZlrtH>*nYtgk3OE3p7;0HNph;|py_ znil}>1?oj|O#dhV?Ov&jJlT}g`d0W-ryeCNy1^Q7>8|b)6p+=#hCce!$i8cSjR%Db zLWy|Q$O!)S=4bom!nW#=X4^|oI2%-}aYzLPO~Ynjs$O(v6O6}m$bWR^iB17j`J`&blo+APqa2gfY#O`_^|s#>nw%7oyCVKX(57e2#9Yj1->SsT$#yScbCUO!5@g@F55vbZa>Z&4{lx9Ic46=nf%VOURuP53Sa@xBkotR^BPWVJjp>* z7zp;)Bm7hWrvqhYw)G5gw5G?&ySk6kyWI>CI>(xE!^frl&B=t9ofm(uCrm#W&PZ6P zmk=sN-faI&u&=-vS!J~E>(q_Bajhu9!*n88f z&qOGHBmE__m$yfCNmD~kO<&6~& zGWHVsXN^Fy+~L(h#;9VuSnUALjPA2JLMX58%@dG6^v-Gfv9HY08CsDD9MEPC8wfs@ z7b(hvtxgxUP6oX*3k|l-uPx6YjgKl24&_-&-iby=p(>+o&s_(APhd^G84D2e{~a#y zP#2+vIOau;J={#r2C~BD)-?BRS|HkHE8;_mLqzrD6DimscbED|ZS&F&&2dl?1qtn& z8q5!Tk?`$Y_a-6J0kp5$PJE5FQ_ZnNzY0MHlsaegCvTIsLFA%!?n4()K=>15izo;=DWV zp-Cc-{G+9@5;0c-rQm*&p&=@fYK|4HGH^ue9iq|L)1xzEh3Pn!8DkhZ-`xe>kyaFN zce0>uee2~=;N8TLiGTFfVD;i8z_%FB`YL6qa6+u9U;_^T)PZNUXo>25c%pdE;$&-4 z;gA^+#ET|D0V&fEoK7ewx7JUhiiO70pjgGUh)ZZHwlkQA&JOgjOl*Y^`cmiO=zaR7 z-in4C3x_^pAT!>58ens^y5XG8^8!)?sH-?`RH)q!$vfWGDXC@L7O=4OKMMJ}b??-f zY~&z$WM_N;Mx6s`R0jS3bJd>%v<>hJx3 z*lK4cc4z@2e|IW-{&m)nc`T{Ohz;Q&=a=e5#{{VVYAGQ5$&s<#HN$wNtDVl?kV_9f`!DEVd79XJT-r913*IxoT zpffbV23;Df3KlI{#*NzU_dBPURZzIGp(akKz9Y!G4_eE|8Wugw#ote|9xZ8W2r}Oo z+;+>?#sf`{=~17tLQ6oxWc53L9N__-Pfg**HnL_7@iK6b7Q4lM))S@#f17zjj?I6Z zPXXiW(V5*2U9Krr_@B9T<~0vcb4z+amX#jg{fMD>3WVG4;2;3;gv04SqTY5D5BTAh zTq@>l2Ar6>z)k44Pqkn=q7j!m9$Psb3t&5rT}@I*1ok`u!5mg z))tntwqzF0ixnq6Yey`~Ly zc0M^ar*k1VI&v>^HhF^cjA!-$Awb^0L)}ghDUi8K%xXE5Eumg)#kkNJAB*lPl|4M_ z%YhP@Us><0ug}j*Oo;E=7Wu*tj;3546JdoI+Lw--E09hLAtmU35F;qsrGIYI8-E#M zNl@|bTGH+jhz?hM*-ST0;}bQqmRA<)(FAlGBDwq>kHF-Qer>`MLXe4sgOl0_5a^qX z^kO;|fQq4#DKR%e4=CC@Jo{LFD+Ll%6jdomgwO}Agx=a%8ex4XG=4mpo2C`xPcKnh zH51TUaTB)PF4i0HIA%^LAWLXKF)1s+c^jp*v%0w)03g?E{E?^9lUTXNsRq7ub8R}{ zR0GGvZI9=fjZ7X}f_+1eD7Q0E^Q!8Js%sbjouY-QO4G-NC{d(fV$(!^v1VLQ3$B*+ zXre~i(joMnvFAI=gb;Vb{-^CLKr3la~l$*MF(6N$&D>sxOGH#8g&w5-mP9-~IB^QAo;@ffO=hYsM!{0^8M7>* zmFG71G@}7jCTC0J?vt{-$ZnuCZiSF%Lnd!O+0va4<&C`F|It+kmo-%gQBBqFC?ojKxJ&^L5)h1tk8hmctvB3i_Y%0YK*C7W^$mw{xmJD?J%MKx8t; zfD<{S#kTR&X1WPmm7B8f*WLcV$mx$cI#cmHP*yn7S7D^T>vd0S1Re7?W!(aXn_WBb z5Z@n^k^+TMF@RvA*^`4$bPY|6g^*LwWHSNs0BKuL7+j5*fPmt+2HR!&jacMzstzUL z9_Q3^1@`EYxulMZdew$x5W*PhEipo#-fR$a(LKY}n9x&8h02mCvMLq;D)cwEy|l+< zyk5nha>{4yc6U{_@?c!2v>rii^{|4>uB?B$RX7~T}%v<>yz%giMdi}k}JPL2HF4fDY;NUfs0XBllI(eE16<$ z43g(_FN$#yDm_PLusyo3zIlELPERe*WqS0oikP71LTd8QwOQ&)1n*gXC&2*&_Ak#{7k=#*hZA) zD?5CB6a=wnlb1rZ{lC4UKoI%ayL)NKB7ji{k>ldeV$DlRbRp)Fqt3dYh|M%q8YY2z z|9~@>{V}sV@W6Y$&Neq4Y)~tm1;a<@6XEUvM;wc@j78oTmN45!T-1^Vu9vKkXRB;I zFd32Q0%I;~^0yc)YM&2IqjU#9Az3x&R!w9CKHZJg^R=G zL`;~oZxQ}2q6}1$5o3^U#56*wq9@UI+w?z(IxXQ1kyp6mSY4a!jC@G*eG6!1YWJbxmlJl#GJol683ocQF&tQKjK-8~`OOBT;KOb?J2^R*-E z`rww<9U9=LjMW2K8^s`)3y>h(5!|Qb^Ga5yk2#QKM*ODLd~QcspBh$zMm1Vj(5@SM zcn{qqx;}l&Y20ti^64H5s232cfXUR1D|U&9d`GOVI=T1Q>U5DzMJZn9Nf!eSUMm=j z?ak^=0yWpaqq4?dkvqDrC@&ERUI#0^#NA@tSk(!&HE;^hszocm-rayMeed(zmY%gg zT19NNr|Li}`oQmv6VljiC1fBKkHNCkZ~i$5UvvGPgz_mg$}fpq54>D-k;$_>lrkC{ zsARj)><$-sZ~u}R$>XBBMyKZhT*2NachH}r{{CG;9B3wh0>^*rCZIUXE1Fq`js`B**1IoVE)LH_&cFO> zj>#vV<|R6TR)AY~bST5B(_9q!MSD!im0Hcq%Xse+MASdUpJ4g=IMr10xuVDYdXr3B z>I&>Bj;w2SX-<6IyDFY;s9xyXHBPyuT>q7sxqXNfX)HcWGjJa3TxaCbfYd~EatIG> zZfy$GOPUkrS&F&TEjRF)dEeS54W+0H78<_D$9sJ zpaVUm4HZ5VA$nZEWVs4ASXx3dr#NLRQn+QIcu_KNc^L3@R3{$KH=m6lxtr&>680=% zKYJn~^CR-_Iui9!fpSVFwqJVlrtx0Z%Mvu~#wki;5132ia7oxLXw&N6gNLpi_~Fip zZn{%&!VvV2!9>y3*rXjPinpxGb`gYjYL2$3M#A9p4lXMqaajilt1+6J{36qyFGi{T zEbUtE)N5^|3|6*jGmjX}Ofco#M4A~f2on~qtKx?! zLO8)7j)97luZpZYGP|x|Wj8_Mn2dW(;t}1Eg2>>6XsfYy6Pm8Egn1bJ%RH0|y&8Az zA$22Kn~y06>@^t+y>}b=eoII1)z`0uuyH@j#g0hrvGPGA+5N|$)dTrqqVs3>^V4wFvcAHScOVI~mKEZ%`CKgE+-qkz$ zr3FrhRGjlTfI{1T{p$eYEhK}P52 zf-^iFWyLiw9Xu7fX5y`SGB8^%Hn$n-qR|`++;|>_l{{ZHnH;(^^SUseqK__9-VT4%N%Q z#KgjxQm&8IkRSQACCFN_5ZL1i&Xk>FzT=O;I_f4mI5l;40iG({e`fE)M-KyKa7<)D zxV+q8o=++mU`4BlF<4IO-VKAH5rV>(NONbLg1dOf5WYk0!lo;lYtJ<3L7|JNre?JU zd4?mHs-1mfoG%L{WY$53Z`*lj+MI?_JDnvNz`{MNBIMUMg-#`-yu_R_kumD@Wg!_4 z6Y;LfIgC!AOtFfnVV!QWobaOJ*1*H|@W9#a8pA`+jGpf2=$Fz+s4aHB<-`ISU^#k` zVARmSD{Vg;NiE1oq!js6O3Q;zB1@Ut>Tm)4ggS(?Bx()A(@d29OgUHdNDbdw z8_s?5FKx4{cy0y-kiKuE1Y1zKbnV%Uo>-7bitVM+!~EdG-(@`E>|wBT_6*#uZ* zR8lHp1>%?7%dzQXG2imPkn`Hwt5wfv3ChoIN50b`k$g6$C7ZsEgkEe2K3@I>@dIih70Sa3EV zhog7H7!+ICcCXfk#m&;+Qh9{V-W-Ajy=uKBdqtMuwJ=BG<7~Z!2#K}S<38{mIkORy zcIz2)-Ey5ll&yG5^o;+}hOEdfX0O10V{m~&^*cV{MOOS>bjEn@5(u(#fY+^zYe>5# z%+Rk(N*1Q7P9KMOBpw%3jD_)4#1BLbC7}A67J zidm}bl z@q1dPS;>D_tJqv}aj0>}b-Q%z$`}7A@p?mWk}eCZ{D?1Z&?90NG!tH_XgtD|`opvl zbN>hZ0Vl0Fr@l*TRd-5?L|R8L+yuOQSsP(RT;udTSrwPgE6|<>;vU6hrv@5s9ZJ!$ z&@ZYVB5)aU{xSefD-sJC`vP0w%Rh|(k`LP)5?7pXi{G~KiPd$VFhyC;1s~r3ZoAB(kcMKL7XD0{NMtfr zC?x4atVOAxtZwS9NDjKP^7*M-_RD@LjWqoAQ76VD``eJI@E2rs4HzK@sct|gIexDl z(S{x7iw4dVWc}J1h8!6t2LbB4$%fx$t_$#!cEpGl;ZnwSQ9}M!_A20~qL4sgH^k$b z-O$bG3hNAkpo4^)f)U2-xgD4FU^GANRDB=TtU*%W%A;4wTCIlVUr?TL;z{8AR<89i zf~cqNgL?ciNWG4NS>#c0H+jPK78aeC&EpeKwuyrZ?k=w#l;Lax!1l()pQJy7oqrJ4 z@Ig;nH$7oJP07?e2I#t|b!i4YYDM-2 z(#N*uQr*Rt?#+}euyr(7Sn&VaBpNpG_+m(phA@~*Q+a$O%w8F!kN9KHgB~0DB(Zj5 z0r!I0X>-QQ;<7wjkQWL2!Nnumzi*XRFms0SNeoRmVZ%tw3vc8oLM6+MqX!{bw@NAr zrMCn{g2ET2pO9l8kI2aN3&7+x?!ERpR%R&Yj_-l(jj#S_KnC?E`c}C>iSHWC;&z>B4wdP51Ol~p=r6E(Lp~18 zJ}lh*-y_TgB=g67$eofKIt8Gi*PRE9M=kZ$RjzR1n|Nh+&QOHkGcO++{hGoH0&+5g zXAW|2+-(fq%92@U8jt3+0Z2qNm)w|0pQ4<w>8{aVodm+T2H~R2*#Xbiv^@|b`@>Yfe~P?Xxzz^a zX4rCQR(o!6@e@Bu;pJn2KpGLcbeU%mSLlGb&V zW3M2?r6EC_BIGnC^3pDpysPb@KIHRF%-W72S-cahiwq{4*k@$fEqHi|zbgGn1xa$a z;;?Rmjfj8>#AO&pZbmn(yUL*5+^Kq4FBhl)u#>dk9M^zVo~f|~CICdyRVp%6% z(u8Y!&ozb+*>Exb&0&snkpFu!q8SP5F|1iJrm+7w{#MG&0i_3V{X>uN3Gxo&p6)w- z4W31P;VnVVgI6h|=p@~m2>|r1rNk6Dx_Pqij&g3I@Y+wTU#8ydt$#3Din~G^oyVh_R=$76p*EuCaEoh&#YF1DqV*omb8sAwCJb)8OTJ7mhdD_ z!pU%O+8e}6_Fs~R%gD4YiqH#h4k3<)20zbLo4i9)`wtKa57K58Y}O=*TScPI$U(Y_ z(i=Q+$ZN9_N|#3K7x5(6)b=oas1~OzdJ;EkY=8Td74Zn;Qa{pvKz)gieGeU!_@9C` z_H*-+E{-z028Fn|T{!Z4{>KxJJFshU9_!U2q8dzjJRzwZzD)wL!9c_l z2N8u|CU2OG`lB{rWlfvHB26C_Xf_|MlS@IF<^6xpk3`e`(|oUcXxz0fOZz&DFIDFF zx2_nzn%8Cmq#hZi2G8<^_%dFGMh{YH*$(?Zpsw1YYuxTpyU~^8)T4WGKaz9Y?3hIg}11oDDpGDf5>= zDqX+>ML<<7Obp;J8GVIPUiV9ajR2xo2$iq@UxT^`k3Q9xotbzG%-S*No+#h_pgm{l zeHb86y252kdYSp#+}@C*)!>ZgRns7e5XKi~@=+`1Px6Kv{PFr8+4>0LN>+K&J?ff9 zpI44Ynto1R6SZNnL^(w?XeC%xMsP^k4J(?fm(=Fs0CctKj*PME$sEXG14_)TKF@uepP z`RR0zQ+<#s2c93to1(^>j9`^)vu0S0!`_C(|6r%f%wfmDirx9-eJk5qTxgCB2A&r{ zy_YQir*5@Y7B5V67NBl_VFA2*8iDf3!77M;)A#6uEEUR%U&!V8Q*sc%DC`im?=fXh z!f2EJHoU3l)79v3W`2=5Zz00MY~rH_oafm3{I71OE!8+*Y4?ysxoHO?YA>rbZp7w> zMjmcemHwj}D4Bj0=Gm}5y2gUR`fmNXWgjl<4J9?&gT9LN*_mIVMdwR0+xcWch6%pL z_V3hUjo3l=IyY%0L^aO*8CNn9PZwUromp-%yvB!n|FOFW z(T$;sBo8$BOvL392S=Cx`L<>u9k`_~14DRpz0!J^+;hpy6Orb_i`%G(kz!XT*F;X~aoKPJXkh1A}Ta=|4yY@piXpKa55CtILFplX7`I7>Ep=dS?f} z`>23m_ex0OOCT)TwuPF0X_xSws)<5GFG*5f4ZYv^vw`(*v2uI%fn~MuIYM64zsf+U zn7)ya0I&aydGYtSbygKS$eP>pz(aLs&1x%Hs(%GHnDmH|dMfD}e=_lXr_!S67`IgP zLaPDl-bcat0gW|HP^}0h-{l!D7TprqPmOmGMA>N)Tpvu~V7~B3+k2XMv|Ln3P05OO z*6Uc1F3P+gJ449BSood}75>Z7tM4FMAJ+tRuAG|ZE^;vneKytGYH61f(eM~u(&^lv z_=tIQg)}`a1DGQ3_lz@3C%jxgg$s2mXpcrurH_I3vT=}Dnok^o9a z0S_^(0}mMdk0kl+4^*gsTN!)Z z0r@(2kkhOde>{>QTBpJff5xCJ&DPoMg^FHITw{~a)$8z}Q|Zo)>bAdp%Q|0o=yy)G z12uCq%vO~6dr*8Qv0HEN5FN5SpS9$XgGod6X}cSuX-M2w?S(z^c@$Isis%i+t2o4# zG@Z{99g>Zl%^i2s6q8J+cCu1#ASn%}W$-W!mG73(a57s7EG33tlE1lV=FwpyKLKI{ z0ouW?%l^E}7@08m>poaNrKDs!*)L-Pv+xpRUlrRowu-Uw^ige<5oJk=$a?E3&Kda^ z@d^uQ6=L~^qUF7cI(kV{t8og3g=IjT^ETz6%W~ z&q%ZObYF3bkWZ_Rt;4f`HvdpEqX1Y&Qba80pUGSXyGiHRl@Lw{us7VbQf*Fe;sy{~e;+c;T}-f^kqKqSpcf^iAB7^ZsnaK)9wit7(6H9y2K zt@L?a(}abUS^bN}j3G(3H`Rc;9t=hy8W-fb0Qyx5=XN*kP7=G%a@_N*6kGao&)}Zn zz;hE)@YZWOz<-^BUZk>X6Nt3ATY|sJS<`4T8MUK?h}`Clb-Y6)Z98aRGKjf((uMh)As= z(iysk-W)U}*ejrlT+$?Ycz^>MzItInoS&ilvFGGC)$?WhT3_m?m7Gi6=|%`$26ZL% z$P#JOf-qpDX@d>do-}xtbF%&^r0hCT8V9q{ftb`8@#|i1RCFM5oTHbPc=(`j(-L%+ z?Ezz@PGWxKDtv&0_+SK(Fm^1G{(gsnGbvPVSN`0F$|D1Px-}nWiTWv1G|N%l7y+2! zo5Ez-V!&JJ6iRpuWY-Bl#=|N?|Nj`YR}Z?NJvd%d+LPQs>=uza?*5QVD^e&Ck5Z1m$T2nnq*caOj>^;`4OU4;>_Mtn6t>5a0y~e7~Kl(>jkw=j zlvP|7P76ZJ%^r4c9VtQZ%{!5h)w38*X0qiHH_BU$(qR{h0 zdr#B`lqYrZgNdW!^3O^G88-^Ll-KxnkWV$u$j=rh5me`;XKyLjk}-Mphi`CJmR})g z$)j@<%TLpg+xPb~fip4-ARdDV`jxT5^Elijqw36xH0K5MT|f?iHD6IX_(mknO@=YG z=g8Y+lN97=xWusikrnHu;zH9>IOHWL2$IWzK*#|Tuyh!cSi*#qf{*EV3}&2eeI)07 zIz#~m>16MDZ=Swzvv^S%h-dSU>@-yMe1QvRN2N$9e`V^=H3~BFkVCy-72`tv6qr(K zY1pA~+lO^jIML$QHSRL*2TB@#8Jd*&?Dh$ZZ8BW?&=A~XQPQgkBqb9tX8}uF=7(jM zR-0I8HmW!R;pEbRS6o83b2#(AF!<PFv^g*YIKt`-XR#l){4jv;b7ZIV_dJVZ5*u z!eeCcqUusO@UchfJ<;&5_Upjakw`#Y+*l=&2h@SE+N8i;CKS`V{SAmxa}njVQyLSC z@AzU-jxnDKOqpI~6kIgfUO`A<&cWmhykV0u?tj57&;>TvZhMW>2@6*R;NXh<>ch5k z@?1fq=*c`vR|*gS>T@S=)^9vPC(ZQ{o@eiGwLB9AjYRA9)KV=_*p(MRYsxU(1RQ@v zzqmNhz2QqAmzKgwekSiTP~8qd%(^5P2uFy2cU#ZJVi!n>=`p5{Gfpu6b79!=u)u{* zlD)3|O_yNJIso2K3X^ycH4V-(D8Q=cW6yQy>DIa+=8GG&HV;j4tqo_&y^=MzT!-?y z^~0UNB(8ADewB$K({|>4?jQUGEpWK3@1th9D|k zTpk-*liJMZ=|{QzFo^KDT9x6?K~$@@CEti8{2mByRrkT68w6+f*Qk}9ET~KSQ!q8B8K~@Zu4n+` z6j#7b;?e#URj*pR`=*mmim_9xL0!)82>Y>XZ)WJiGGr!f5+^gxctlPDR7e4(R!GnU z`d_enrCh^(vW?xas8Vvw!FGpnnIa$voZ1b+tKz9?L5#h-;qGx(?EcWOQs1&e#B5_M z^PZg==@<*ebYSvKmE0H+qB_E`Z@5`I#vJiC`#_((_Nak!2H@8)a_&+lTo@L)4v%jN z?SuvqXPXu-{k=YcPEVP68t@8ESN~8`J9KDV-`1VqQyo} zK_t_-SwQ~ahqi5eTw9+_>nWa+#J>Ez1`W_i`bkDiHro?3r}A4S*u8iIZ&@X#Sh-91 zs>1LV*;ilJWSthO11)`LVW0&SoY(DuOuby-X{H1)avCT3CN{5a!P=hkynCbMlgy&D z-8->~orcr4Mnm%n7-pS$Wzy*_FjTFcxzH@y4g5~S<2+=X24jtti58d2Df~~;4dI-#U+FVhdtPkEoHOQH+;}aC$^W;cnGX4JQfv~t= z!=i%e-=8qC5Dwl`Cai@9hc7#crZ^?)-ekRhYu6;0(t&+n0k_p6UkLJ!kQJWJ=s3=& zwThE$IzSjyc00A%mL8eFzA0R!;9DP7PJy4vZk@@%6I2*t>y$<2{K5lM>VlDT6Ukeq zysev3e^ty9T*I%!Upt#Ib1OEwNwVAjt|>hKkE8-hLG|U`4l*Lw<>%Mh)clCbeSlm4 z#T=7erDCck>bZX_rO;6_E*0~)3ncNBWW`KZ>)ZttL|K65Wm!e~fBS4B;b(QWqQQH0 z-+o|i(CpraIkf|PTzmPwOGb-7iIUYkDunQL32T$$h_^To^7fB2b@68m(}26aNyXuS z{`s94l9w&IVB-+dA4#2e?*Ok}=KDM%j}&P$1Sddo?koPA4v@aF?HU*-r|i5WB?>r^ z0arD|;duoTCNuRlm_XsN4F8X8NO76jZ1zWnh8SU=_x9C{xS-C9e;Hpf5qv3Dy!kGq z7VBBptXXX5z4K9Ij=jF%@D)5=@|9x@ZZ`Xc&|{6z$wn6#G`vpXA-=)K>vk-s;99K+p0(lI6->6Fqd;RZyp~!hE5{!T7P6Fbq!UESrq%E+ z34t=I*j*pd0{t(u+J3NhJHi99Yh8$V*LXKCc5pYOgTF_I1{vQEK>~EFR|+g@#G<=S zaVCCcUg`T$x~z1sO^^U_C9AT1RA^^VQq<5xbJY{l2^u6j%5R0q;1Jk^=&moxt^Ai? z(S3Y3ml@(NGC`ew&?6av`~jz;nBc$#tG90IQ7qRJpQrH|WGua%5(u9iM5TtPfF2Ncl*Yy=nGQu{c}3lCQgwA;o@+DT=-+DVbav^I8~*m+sp(z z0dnx@a(m{zH+?Xm7Qdm<(zktJqUbcsg4<1}D7xw>zp37T$WMPy%f*@6_90CZvY8&;75l( zI#eW%UTZ|G>ePtPr+Zh1)`ah1EzTpz*G>db4OVum^gSvRQ1teSOJX_9GZ1PtN4ec5 zxTK%(NOQ!W38~>z{j0ad3iRzXE8$U&557#MOeNcv*-vJn5jlWRryO#P)DB`x)(TaA zurI(zY^5rSyRMRBt1N(AF$Cjjy-Q+HTPw1-Y+=7Pn5rH^7k?_a%|jxBB>PBt{(gIa z5xW~0CV|BBT2USG5Z46{@P=-(F zA2=Z$b`flE!QhGu;!e4Ld{V0kjVS&zHgS`QRW*+pALN!^MAE_ExY#;N!O=?|IowG5 zW^U!#kl;FzqXRMdoPEJ1ODFlf^rCRFbfD? zS-g7??R;YcY+fku;BMYu8)cU4^lT^uBRr8T*-yA#zgBYp2tggH6S#pj2w&DTgyUC% z-}*8rZJd@NEA%RM-RG%+y!8%j6BtXEzVUpv7(3bEKxBhCSkd`UN*Fk1rXD(bp`#;9 zkfUFiRTYe=BYtV<`J;OCUZ0@r3`zF*E6juR3<=8@v=^x;L{f*D2+3@OS7~=>Wc6a) z*MX5shh0ev*O)@?!&H_JMWIj4-4UQ^G71^n6FCr&jy(!Q%3;-=P~r&iqz&IglR_=v zLk|EM>WuX78tZ-duDD)U_A1|AqUB8*MXVg81!=te{Js7^*ju#{gS*Im-mmp$+=htN z%3M=rjmKYN1cGJ_tIyg3{hJ?~B(8FQcDNd!-4qPM^( zdVEgU+BmoI@29X5IX@Gg`j$Iw79|+~1@LJK-=meJGo3U1#wRReL`5rW8fe{vZ@wnJga) z+EfgKdzKkoB{wZk`F4JOY0EH zk%m$a)tsF@8dJy63(ggd_I=cvC+^jx95?46#H>8zfx9~6nH<|)#E@FtM0ON{E9dI& zLJ&16ePlgJgNETX+J25XS!Z#JEok!b*yTNSamXqC7k=9~u}%8K5Ji43P29qF$RjVK z31Qq(>kycE!Acus-6Exk&t8myc7%3eT10ZpUiX@afwgWJCY)SDH@28N4eq3>j5-P8 zPKN|toQ$f~FrsdS|58v&LKtC=KG-|A&%es$R78D-dsZt&9#YinS{DOQ>&Q8Q_;ztq zXy}1zoSPYzfC`vJ+*?Yo*+}vJPWj>k?2x$h@bg-P z&eAYmll7ac)6xsKcl@PX)8@7dNx`A1asYoI@+ks9?sEUiMXOoNHL`aoC(D{g-UNhz zZJ90Mav;pbKs8Jf6j!~^McUC5@|dXc>DjGSxU_&q!s&WsL10oHTcTnXpINkaP-~Rp zCf~vad`8C;)VJ$MZ!N`AcTWg|c!pMQGdAk2&H#f%$v!ud_N?9A*reI`oRfYOozS&t zdq7$-AF}f9qpAzMfCBz!tdI9%pg@LguIv}CJVa`luDUg_z%7bL2Rd)FK{N#It_@BC ziBN%5p4BPTV*MkNq5qIyDN~cQrg_8eX05YN!B*8qw4Cw5s`39uWXr_%pgKCS22?Un z6=u1p>dgy zMQmH}bD~Nkm~%oI*SBo_Z4U=Qk<_6N#TIU$XjP#V@%a1F5j|55F)(~u%fpD>?owm# zP^`=C>iTwkPa4C;o67?PD){sI%@HrhiT(@{8oO>^;2YraxF;>}v-}B@)FWjr6M@03 zFx85l$|xcCy6Q)^UdoJ?yj(qEmI$M>!U3Sj1eQh_x7G9{enihEVQ_*ywri4g>-M!M zz2ltm))uj&;eJa4Vu}kSUalm5a#}bnj5d`)zoEVY=14&o9&9^q4@f+;c&8LY6H=CHGP$~OetvB-H6iVM`Mo2jSJ zXP|SC>KX3p@=t}jHDaqGiXl43ybf4dUD@kSv%A(F)7bEmpBl~Jc$MST0R4R-bSi7;J{DQ2# zLfGPlE1<67_s?YxI8ue@>3e%ZMr_-!>=ITnm_O3R@)|t51SRGC6EA=6*)H|qnp*%Q zqd27F=)TIcyc1Iwm{Tbi-zmZ{l0Q!s8R&ca9(rsoiii2si3&jQ%mzf8c+6qzHSmfY z4Jn9?8|N>QrxZS}c2$R!Q z#%U+O!9Jtk$`3hI$=!LkpPQOc**NBz5E7wf&kN#hPDiwfEn!tRq)DlElPWaSVxHfG zR5uG!F@+$`S}Ia?-TQ<#7XmJP_T%ha0;okmf40{Va_{5!ZwLywDKgCVmRQ&JNQ`vf z`CW<3q#$tmXaNpf3LJ{bMChn5Qy{6|^VRGoT(V@92Nv@L(Z$zW7>oBs(qDDr2{&m> z==NK6|54=JCq+atNm!j3Cj{4u;(`I<>`xaUlR1d_bTTnFa^zo58d>6Iwo6s|@P1S( zbG4~#SSk&E)4(1$Neyf(AD9b|S;?SPMH^Q#iHAnYYkY>#o-i_b^hN63`U?1wX9{A1 zOg!MTjMJ7CL9eyyK=~|fTu%LcK$RF4OExwH>=k_8*DxqG7cXwju4jQ$h$D$LRg@^O zJC$m$QTg?NyjwaS?5Y|+oA&g|yn`M{%Sg*0wkm}waD{IcZ!FEDc5@sd%t!y4X~}>) z8ANk(CGkP)aAgi6jV~N2b0NqcP60JUkvY}tS2Mm|CsAf7F#4aPjYgmVPEUFy85K)g zhJW^XUzjcaF(gl^y*cTwvkzzbMPRo&R(qhMI{Sd5#1%Xl_kyk-^wA)30+DXW>;iO0 zK~y4;u!9D2J*HkH4dC%Sa7r0hCNzQ$cQALwNYGM!7-PS_%8_j z>i_GwA8n4jEfhBXP+Nr@H)(WFX}T@8r?6FAE0~(qn3?(VMuV14*BF#HhAj0Y-a=GC z@xeFSxd{DXOAVLG-W_GXAR8HY-AV!soVfNbU~=#{bazY8>m zZ!t|T(a+-^zLi7u6`ygry97t%hthF!RupIqf48=6VLx|DM!~m4DL* z;R9W&6jid@KR5?e8-v}G1%vQCky}pT}H4m^bw1&RVz^_^l=~* zssS+VkpdlkETdDglzVYz*9}EI0`0%!53Er48{u0VdM8>vtCw;wH=5?moyC5OZlw%e z=7hDd7|OEFcXSp7n~!(jWp=&rWJis8W4KcT2RYdy_5LFkE0y<&B$ z!PM>kie1{hKtNTDK}#~1$a*d{P}cWlKe%6ejdj_=;=Il9z2og&$B1*Ec9Y)!D6Zm0 z2s!A&OmTZEm{303N!2%gT3!hY=h%G>qx0^M&Ls=Mf}di`mQS0^rD9b|bW-~B$84C# zc^f^TfY&D5P7zxD2c+S$GzV_x0IM3WL;ERVG0(TTUf#<+Xo$+%**X{1jwe4(l8bVY zgO2yqlnZkQu`9Yl5IzRf1DPK%@}oVWyZ^Tj?a}p(@G%qqHryH|_L+T04h2od~cq+)$haQ1ipSuj}R3xUY<{P z`ddg}g!zx`QCuS;nH$jddEw%{ZFT#d$@N%Ne7EKO33|D+p~RpEnR!wz*isk2O=Q^S zY`xdZYLo3hq1o-Sn9n&@7ovCG9bw;L`g~w69WvmSA0yI6FKPsdg`?H6cl0&5^P@u= z`A~+%p+UehTI%#r_cU7#JAF+R*k?YR%()SCq<^cMB>;;Pspy8X5^CSyiVUA!TVwWs z-r`8o0G%gmJ#J*_MSxMf4v``l_am5zCi=s)H}+i5l@7w)zn_D3B9o_5>s4(zbW%QZ z);%7RNIu#=2||rZ4tWr%NtS;m*hk*`EMovd=h_d>_V8$A#^*4zbHHd026I{BSy(wuP8R3X5sfwdcN}c6* zU2GNXGFaTXd1bU2-jKD(O}3a;*d1Eh$5u^T!~k40N7@i|qJpOlKK?pRJJYrXlLbo` zAxO|{5*Rn598T^F+AM$6=waSGBsc9>YD{)X7=_4>ZW{6T&|K>%?uqKtVKuBO8RAY$ z3M!xGYhB=PLVpyY87weJHdEyhem65KTOIs7BH~fy$SJSH!PyDxzp%oaXvC1Uv@~A^ zAHU?doy8B~gQ;~$l476%RB;$Siht|56M(tTo{ zvf-h3?l|oV8^9=x!UEjCtQQK)Qw_x$gpb-KtrQU=@z;-E*CWhx{`E}aD>2igxX2kK zFMtw1=hP4vTKC2A9Qpf>6xBT1vi-Vw{iq>YkGKK1YWiuh>C|~tR@HL7{eEkv0w&uB ziAhh(NAixtcW2+N+lEB6Z&PI*&ZphLcZ#VpvMenaDQrs)##OB3O&-SvJ%UDG z99*&_1eaM}Dz+4KcGOyqfDtdbfg3vicC3ibZ%<1(W@%ryntOZg5FA~cVoQ1WZJ?=m zK^GpF>Ym8gjt1B@fDa(1gV_n}+Vj7VikB(9V*VfN$7f4B`FmU~zHW)5&e@t(`0Fgq zDD@?u0m{Q-wTp$Kaw1g(3Z`@3xt6>;(fQkIAYjv2G!PA&^xmeKC_a1ju+kUp$;ojK zeZ_JhgmJ5mi>_aqT#UCTKRuZ9{WvIA&|LhcJY_}T}e$gXYR*kpH~bSR>R?03I5;D4G3 zEY1bXgq($Rwc}YA(8LBgL*k#ZR%c1A;4G-*)r#DY;Ic*{&Z!|^h;NZ?g(SkJ zaJorEOWs^7N~cYp=ebV2jiAm&C=S{aSWv~9kM7@d)x*FUD{j>ZqN_&ao#qtDq_(x? zn3*mnPS0})+%UI(cX5JZe001N$61_jdG}uheu3jgr0|3{;yE9JU!=fjT9@Sg{(FjJ z3G#KCjhsnpqKl2CE8J2;*MmbLV{A<+zXnU@*k$=Gs5RozWruz9C1xAc5+*CN{UqRB z|51VnlyH+)G89I6HluZ$4U)U;$p_oC!EUR`aZS!9!TxN1$xcSWE=X;lnRw6b3>O9QZC9btVGO=vcAB7J9?$5l0JJ&QkR#q3%V&&i2hb`79?R@z%x5cr?oTIUKG zHgL34SrDp)y)CN<$q8(_?%VE{9N0oF=f_rXj7B$O86@p#94@#q_nU z*Kmvojk47xv;R-~UQse_>4%cl;CbPXT-Z&7&1rlCtn+MfQj6$f9@3p*;T@1{(uv*6 zHnZ;6qVLe`W|}5fdb$@Uz$wqMe;)1+dIljdpu{rB@G~kjYp|xyUIt9$W%(2(b=8$e z92lBi-W4I4L$i3t#;axdRDHkE`DBJ25hoed7gN-96sb7V(!Mzt^y^ajT{~NVK3of; z1~dm=E2xgM2O^pA^bXxy7XyW+T|4vYm1_?B1bk%8dx6$w7_Ks!%s^J5K>Xg;bve!- zH+j+h;lQi*3Q3?sC0*3g)cIMt)nLBCTY^!s1i1U-ug^SNRK}~x7{6#8$f@TD6&X)P zA(^m9>Rl3eVu64% zkaD92wT{=W`*Rx+rJ*Y!Cqk|36|@Jx__er_Fkbh3f&kOSw){vrYL-7o1lcx8008t- zrT7cmV+}Nd7UbLNTRIsdHD z4)VLE6w{uAD-(<`4>V}aoHn4Pzr_6T<&C=(9#5But{XNDoG&9JEr)lP{~3l2{lb&B zmFCO7P96I2boII3Q46H=l<#|X5f|@dE3RqVhXFL^4IU%jt;^)ZeU$wU8K#q6zViiq7w_0+XH<~)#u`OK zoC5+;b4Y*!?-WF-&+K-Ydj$#ZaK_HEsWF}nJc!#dqN)W!?runm%d4id=Bn7B`JT~i?hT7E6kp?5j#7y3d zXp0K_z`zJJv#h^0U(dhap=ryDhW6N`bHlr_9!bFawvLQO(a=fYk3FpCF6;FJ&Rdz< zxcSxXx@lp0NF|bR16|31vzj-%YO2ZyV$hGx{{i^oK?Ih5;giG_D=zqfldXanFu&5) zn*ExnHR_{AjS4LGC>krEdAZHcEgbiOP-Dq2LPxShqJ8JZd|Lr;x1hgCBfSfE6)nB` zI47wQtSD&v&|>N`&EeE+nLA@S+23UMVM6f{9L8(1USpJR9EPTB{9x)~iO z8+u6?M+auCO^?G38e3|aE_V4@Z>sD9?Ly|eExtq&Zo6=?jZos6qUqr^-mYQ0C>SLd zyz-=Ij4#mPY+~mwC2hAocL3-o!BhC@pCF58qh&vI2F|T4sGxq@*l+zB#DlmBr6a67 zvF`P$uHg0Pz5SMIf+oEa;3H|&|5?J+4QoCdp63znLS*M`5OX_K4?U$|?OP-rO0Vl5>&R&aR|2E(^T^z- zw>LvFAd8|mpMJ0f=$8(Pzg?c5$&hDt=0e15ZpHu9=&YWH68EnP*(LWt)MyID`wOD$ zcF)%uLmtZnPKIyB6p30pfhO`!h)XuGVM#4FQoh;*9>k~CZi-#f<|}5yp~U3biHPof z(80l`kJ1sBjXhc?TIPWsR`$p_9TzjAsBx*ecnyCUw~a_sU288}mv=(f-1Xc3J8wM4 zpv={xAMR>MFzlLGy6TCa#q3=`X{1gHpy=y(^qF9bdDe!Wz}&iP5yRU|(HIY_8c$&E z#iZSjzW#hZw~HC`8hEoWGZTUpWj98KW-<4LpksmtDC2!_F~0K&csp>Fsc)xX`E~cC zkm(1fv_oYEhUOZLiKJkxTx#y`hTVL2omeSl|8KI9c+M9HVKd)@X1C<9syNU`bWEH# zkrB>$G+}NHyni;(G~tcc%y#^C1B#s`yw^B>o?2n#S+sqq)fMyjl#Sg`*MWEGi(zTG5j)>|DiE`%B-$S+R# zi;uiA7AKe+Pp6iZchf&vJzLV{FMKSvph2SjRPa)o%E{YMHaeHi`sHom0id3Q!(pSf zaN&nYj>_sM1s);G!5MedTmWSGKBYD$Z7i(eCCVMyIuYjs*0hM4|4fNf%OP>b%Hs?C z4KS4U2m?w`m*F|$DZ6aV2o_y~<;?wOg0iW|AJ>y-<=ha6!8dmElD=Dnqo{Dgz(L`m zjzpHaa!6T96?M2ds~q(0fx@a{wT;*eg+WRtXLnVIc)o3&l+ShQ5(0yoX2z-jpAUT6 zK$lTvGQ%$EC9Un^6uc)r5WYGq@C~3S8mtnD;N@UD9*emEV%>=r-#&3(;PvIo&flw+@WOW^{* z)DLH1HHX7(I=O_Dt*B6*PactM9SXlzVQeUt&ZxMdM2B{x6&XvNE>I#~tdC2A8ev6- z_z=b}lA!MdA^2V@-43Eh)>gCxI>gyvvXRHxz_LWfVBQ zJENHk)AL{54V<(qn8vunmwZ0(^tX(!y>t$F5G?)@4A%$+K(-y*!sWIg-WkD z6S~G5!;+F*5HUaVKLm1e+__faYyUD;7^0}U0kO@~NYQdc8ABe&LN6Tll%*?w@8PcG zM^c_iOgg*VjFV=8|%|<`D=g2bQc(69mtht!6YkBgoJ#D6Is{e{v2?Zi(gUb7JZD zrtD*5ES}C}LR3=U3Df-wl>7bJVPJ=k#;$^gB-GGfLVkKZqh&j$gJxR`$E2tpo4Ga_ zb1yOCJg7+j-DlS{|C7QG!+Uv;k)C!V5jLyC^@$Mx3|%I<;YtBVvPl&WS&|_8 z4cQxBlqkw=2C#-3EDK=SwOZldn3artRfoQ}-1=7DfcfSF8W6uzJqM>JkxmQuytx^Z z@Ef=c7SzBQ1ha%lhAq7wU%BRMAI-G$N3NZqBnJ{XG{Bh~uS9vo`#&S0Vf$Z1#KJI) zGeI^JIetY3BKcPtF zk*g(Ba7k<8CaW~^NRxy15VVrNuFz7QZXxdo_jU`Ja4V74x24r5jT&}jP`jJ(!(lKZ zf%S`4Sk_(NML8a$ifXsa)_CFOE$ zc~B_u96?Y)^=F_xDS9Ls7HI`*hDPEq+FUxJawzNl1|C{3?O918c}MpbW?NGzX6~n` zn}EEDQJiCqa5PkNPA3}p%|yo-+(dpdMs^Pp@~~SU(}Wu@A?CMoHntVR$V@O4JJxc# zZ|THEsVL%BQ{m+GdG>>Q>A)CC!lhYyMg{^V85;3S3FJxDh|UtrkQru*H) zfY2OFVwHXZUO_TX*EsVWi0>_;y!Mx=(R-cz_Q!GL-uB!N>Cxq*aJPR0oi&|f`9V!b z!ijuq#t_K@c$w9~v=u9-oZq3Mz(ZVNCT7((Sq`wOOQ2MP`959tge$>jG%_^-dE4w2 zVJx*g@tK>=c-Tp}ul=5%5X z+@kR`GM-$k>Rvt}?Dy#S43AHfv?(@tljX+w#gHgCd05F6|5YJ_PxKg62mzBj;1z11 zw*6smtz9bO*XOmAb?VL%)vpZ&Jh?Y8@~#&*Z(q1iDye1?r0_*f6w2x)79+736m~!| zL=d#IL%X^z@-MILb27U*soM+C0NI6l%~XT?6x!-aifakVEI#^Mm!s}l??pNtI@WmP zUkSyvfok(yEhZdp>S63V=os#wf?I78H%5>gx4z}94A;!=xQnJ;jix(Enr0FV?&+D>LEQ+`}J&8yMN77NVUAF9HJuOixR_b zGBW?UbNTmNLTiptBMGIpmI>2%vLWK*S+qT#D}0aO-??!QWGGo7{Td7+N6Gb7=ZBsn ze^DFbGgt!xRNpL!ZJR6;CKkIfZD0aZ@H%^|3eIN%VdPP?u1W??V5$Ropm0W2K75yO z&UJlz1PhT3A)1&b$AK@+PC;bCkA?bak&rWu#}No{2;unZMr4o=$q z>)Zb#KaLO`)e!|9?#{poxdc#l*+*Hd=O21ajr%Sdpm>FJ13)Pd(+9hwUc3!`Beef7 z2>Z5;){9q)|F1~YFNC(hfO)o;%N|I5yHac}RyZ{I4<$d4%9B3b$6Ito{bk#8pz$># zW2dIY>cDZNuvc`$PNzwL*?v(8qs+JRLlsTB0#cVoe86&=N`IIc_aNd7og5ujlNILv*859IZfsvp zUtL91AK8|X75Vl+Q0IbueT1+B2d$|3`GUUL=^~)SL*;Z->$c#1?iR;w;cPG%)xDFj z@%fhY-|KD&s&&VYu9&}sUT-WdQf}OSnY5t!aSM3m3gbQf8kOdh>5>&sL&Qd!VMxnV4?(Pi;| zg=ykyzJ7ntJ>t&e@dDP%6H!x4qRblFH#%9Ia0ztjTb_r83s-Cx9*&QJ%R^>&5Ix~X zuTl`$!YDCHFl>WOFyG#y2UZO^oX-idw4iGa(W-#9c!mb23W?ZZ2|dnmt5z^!&mh5c zU;2KNJbMRw=Xl~OC2K?v(Y^X-2Xa87!&>?liu6UzTQBx2%wYcnf2)9#8*tFw%$Dc) z>HXbLd@|!fcADz9cOSNmXF&nSF}t?a9zOO~OdQa5)&L^o%KY4qg(b)oYo&T%I7BdR zcV{L8(~^s9R>}*?3Fl_b?jmB3M0A-qdBWgqjg%C*voVhWis##3op1mrE{@rJqxi)% z>}G%AaC=W1^z_`tVvt++@o9b*TSa6_bPaDH!VNoGK5}VL=uK2qflJn;M%BEGp z2*yr+WQk3(|J%t`bwSHiOyuXpZ3BK2njEWdir0>-4szV8fm}#69f#?Sv|=cRPEAd+ zyJXA3P{1b!jW_-qrMAyf_2_{`WYD->)B+v){+-9#NY~gg`;=;G?SLY!O5;M6Wd;uZ z3@^;~Uvw_p^8jL(?&2-LpR<}@!<0pqLeJIy5>MH5V3V`V(xbR0O zvoB=?;lh$j?$n&10VqiT(iX*X*OnJO8tB1m$U)g>Wi0TIEpO^g;61xAlt=0qwB6nV){m7V*#h(TDSnn7FcL@V%^oSE1{iUd0a`W-J;yG za2eHEE{e4FfIpwA^3T{I1%lr1tzutE^aJ>GoLEuw@Vyg?7M{|3e=8ahJ7D<`=PTxI2p= zP0!6K;`vlPD1-*9{CaeMC!~*bkS^Oaf;gBkD(>VB52q$e{wNU)AEu{KwEk&6 z5L=k5IQsz;*#kfzGROBg%9aj=^w2LIgYJdd0*0sfuX2FQx%Bsa!%Ctu z5tR1s(Uk|v6iX+La_QyFv=jZ^*t(*SDrA2;Mqzh@+s;&cPGf2)Zv zk7&)POHO)zhTb5VtxqoK(WI&V0a7E)6HPp===n4l zoeH>1KZL=VlLh(Voifv=uSsV-DF>Gw?TTZaBHRpOyCCn%P@&$;;kt}__R&(e9*h*> zV+MyvD}$=sCQyLHy08RYQLGFx^6U9#Q`WJvOXO?UxBVg0m)Eu@pD}U5Ge9Nj47rn9 zDHQqCYJPB8#Adt=1r-@3p(kc5h=63Y4|3$%5ldCsuvC?drYQFJWPc4H(s_8|ttS$3 z;S;QQBy+5+I{;F+a<}H8^cSo*YfBSGJcY|InpxumF>+6D$Y$VCePFpN)`}@{H(@qz z$ZI%p1xDz*mDw2_B1)sB=?v;}fK>oOe>OK_$w|LOu!9j=`434sX@8ASd{P=#4ZBrOlxBB)P$NW+X*`!nxEsHpS9+M_# z`5P*IOSwkPE4JU@v`fN;_9XN_Umgc;fe`=3m%vDH9Ez!rJ^x+HSJf z*)zyC*_iK2^xEO+i+~5>6Vi4Y>CHM^Bj&Emc*kexgI*%t+S{IR2bzl-bL@PBy|r+s z)~i&E$%7=V#xWdkTMuG=-cNb<5}NJ7wId?3VzuewSIQB@N*|w^?{j4|`F5?D{+eaW zK$gjDF_p7{l{~Be2wPU5<;j#PBz?KfKQz&OoYOuKizR{)H^$o4fmFh@Pg-;KLb5IL z>tQpGko38=qXT8xwnJJ@fy;YrDgI)+2Om0frQ{<;w%UITh|a#S$XWP(Nyg>%Oq=y< zigltHHzMl%N5~hto>{EP%D@N}f6Z*Y*m;E!0ie&RuC{is==~fC6_*!5Yqvw92Ue&? zG(bk4sqzJ0eXMzB8CoGl_#qFOM72mzlERG947Gr0EK9B9t|9>+26Gv9X9CBql8lVW zr>J&{b-S`Dhr3YdIg=Ld%d3K6{)ROFdonCOsu6Pvg?ks1W2Fq~+Ee43lV=CLk*VSQ z1eh`k{L6DcZT)D?8q_M73=jUQGAQlk%N6|!QDlLhIKROulk2ICqkpw-{&VqG+PgY} zQ|QZ0Xp9v-d5xmMHt!RBu}9zf2+Bx{#96L#_m_2cU1pc|cui-R{3?Z4PD{9_>#iGT zK6mm=eV^Gbj%_aue$dW;;2IN(SC(w~=SC!Cc-aIN6D4(W3dKE$a5XE@AOEXhNBILC z+vrt-m@?)eb88_<5o~!=wu=evzFO87x+hyS$?!KyxnZ3jMQ;~mjE^P*x-721(wBDk z82?o*a;BA5#g^1EP9v@urX$jjiA#MS0rDgvAJ@B$o0pW{q%r_IwH-QZFi^ z3{mQtV+wfn-i-Sij zc&(M>3Z8YA=OELmi>fRFE^lU^rK79v2}Fr4 zbU|g_k|q!{pMh#!m?ukm@4JHDZQFDF_H1WGs?OEBZ8lfN@p`pTDXO!+jgQbOz)u(w zP}wh}l&q}c$jvotzIT8F8^2J^mN|ogCP2W~f$z4W!VO*m^wO!_ z-yE(FvC9YrocV7cWHit$<(RK7raU#UfB-*sn-Y{^x#-Ojn~CHK zIyEHmQ|UJVT$!B}{X;LM<3${S{Z8g!slV}YzZT2vTNese;p5V{j0>g2pzm6y_`7ow zX4u0M_x{jxHJw_DisjWAyzFT%trtuNrcQ#Y@K?tqOiJMC1^L<>H`*xdrRG99`dBXvDQkP#hfcH8fNTFR4q-zcJ28BXM)}d{X;sg8Q;T` zxSmtPP=wj5wp^Iw3kwknQ)6roND`~Ht$Ep`^`1bJ=bFkfEuaR(nfos|F%*`M7;KsR zv+A)yXt4^3`dMTRpO%35>-|9k=U@ZJ}M|}KVFhd2k* z|D#LTRO_4-?7U@y-j*&aENhKSAGT4BAgMcb&%+2REx)AEPD#U}5UU38M`(ySd)N9K z>~9smftPLrJzf>TW?(as2u|ue30`k}^MAzUv>hXn?@xlYSRhlA#p9kf*q$w~4+fBAA2Orqt9+509im6evVnEiZ z8Cg*Wc1ZRxS)q{Xt#f>60~YUBv|2S9H#w=l9B36l^$6_;26^l2X6~>MIz9ksDv1E^ zy*gBcYLNK!c_!C(L%$^%ftnZp%Cr)vgEE1|?2vx|Sx}6nqZAf7eCL#cQS47VdfmUr z;D{uwpnU)3xG~!jPw}Ntt+!MnMNR~xC*o0f=+{tbQG5c%k~z7JZKav$R%552teyTQxj zhT52=8h}t;P+CjxhelwwF|c4=_Y49s6<|A8V@p2xY*g;Dg928FKVz0iwJ#k>mMEkK zW7iTrL7<$q1RtBkGd%+A7@jy4>(OAa{yDMUZ`@;nwYZsFiug~S_<>^7dFsVM&D#zV4@i&7`MeL*{J4ZFf@9Ib`G;O(mvaK0KW2} zT+-xd1z5Mj5#v~C(=*2Y$Z0oaGjQq)Q&1}{V(FRbkDQ7W@a{YL5GX%<5MC4lv8Z|l zBN(V`RsiB&%jZ*XGyBuz5?6MffQXS8<}HgeQ75Dqzck4*hINMPE3qv2^1yj4MHzB3*>y(QPYc# z3o?6-^JNk3Mocn$PW{n62F_@+$#v0$y5=CKk%pRRUL(1%l2s9K;B*Y~Xhj_0QNrRb zN(y?S&;kemKqUeCwJo(A9a|GYm^H zFGn~0#|Lvcng67%%Lo<92Bc|!luQD*T=%^5MSQpDpu!{UT)^iL*x|S-WQ98@dL;OW zGuLHv$eGAe0NH+Sl0;hyv1duCL;vQZPpI;xF3+n|W;=n_;$(uW{I*4~zGTW}0K?)$ z8yo(D9AL%1m(}JG$DK_NI|>xTu3^XXr;I4b5Fov$q}41eSQHxO>jGW2Z ze&JiKE*Lc)7^f-EKwXp`uLEFQ8kcnj!4@$%Cy5>0CF8#VlZ10UpXKZMVr1i~!p%T8$-NoUL z-{Ss$^x+qB9@s@k#nRItl$8tF``W7QT)>xXfgbJ>4k|qa45lsBsp6oJPZ#UgApk7a z3pMKDp#){O@%tG46N4Wfw)(HJN?c?M&r%3rJwHG`l*u)?Pz9@nvf*VthP(&-Z6I3{ z0e)rJSNjg>|6S_?aeh0aAxw4M6LHx>ao2S3Rd02Uv5wZi36Fn4~*qW*1 z$z4#H{rx+&w<9ypxzlG`gKN!hTHQu0z1CT3<);}Ywo;yy#;c9I_Dn!7(VXtBFKPbZ zd^0?#ePfe%p!#7QUbYT0&h0bM?o09vb#H_nydbBQ<_B$B`QsciJd(tKUSZmMfKfm2 z&(NaxAy`eO9wuVC_Z*!-84GX#8Kf%6uE&KV*h>2u`!h3BSPx3Ix#`x^ zM6PJ!=Igqk{BWUBVyOfMoHQnfYaFz8-tt49FTNUvMhr|55!SH7*bx^}62N(ba{=PC zU5piI{Hp_{kf|#zv2xA6p!DaDQ#>Z(s4p7?n{*3-b_jSHN@4MSD0N142pOd*@cN&u zknKO>1J}0EjLLO$a!=BRKaM~_eb-UK3cp6*rs%cBWwJ9cbQoZ_v;iUQ$nt(8)nw;$Ggo%&`=9*3GvA zPswOwKFm^Y&I9>f`J9-SPe-quAnimpWShYn5>$!2Qroy(h+d%DHp0>+YDH)d{j92B0oOhgKSWMhm(O6975i@Vu zH`Dyo;-A`k91tWfK@rKs`9+@qu7>GgDLiNGih}L6vsAQk`*jF?2QtdU{NZtQ{1Af* zr=q}%UUvU=zye{0E_bbrX;@A>pUB5P0cv_@@@AapEJZ=n=7{<)3 zs0)S^Qs~W9*a-TU5F6o+=IBZIKGzOEeHVk}LB7Y$BRUcr-6pJ?k5a#!#m!gA5D>74 zk}*m$*-xeL_|=x6k_AMn9E10S%DYaznFD3N+1M$_@;Wh$T3j6h8EE}N#2+|269&s25Uh%tF@o710t9L@wgdKUC{a)d^PALk zyxoqs+|#|+^@aKL23@a=CkjM20 z21%es=E&9BHkXWM&tnVViw6*;rQ1fWF?9!7sGAMs`^}Ocz@zMkc8)4AtRx9&s%mb3 zjD5Z=GHWU^_kG+U*1 zOIzXeS52RR{AeK`1gD(v%IT<=fSbDG9W7dgpd$sPt@97H*hZJ7i@&JPl?S}|C{VXL z$I)ME(nL2skq#(2l!GOjWO%2<6WVl#GMWLz3b`?TT3Y z4or7TvgWj$K@TKbOcl&fD~Lmg-3Jp(Y%J2-lDDXx*+#GwXS9DT?AU%_aS>D|$Pgi%al0n1_IlCZ^2c^B$|V@3yiWQ+c=F|Ol7iuQdpOty$H&kVVrR3YzWIV|El`Iq&zwF1&}y zDYyoEpMoe0zuY*+mPlCE8Q&9xELM}9M-NG^#FraC?wkKZ;yRb6t3^gx?wgEyYb_pu z>lpl~`*KsA+y{n-8TFlrpxocE9VYUX14#IJYjkUp_X^2shbKwA-?ML&E+)3MnqcA< zpiz_PvLC(qg~}@4t3SpD1`m46^KXl=^sP-3bL2Yu;if-TV1zWfGKpwPfcXu19wa~S zRDduZNS}%v*fMm*2t40K>!=SK%mxHbR^XZR8OJwzar?<{p1qV-u8 z08Gd+7%jXUV7B-8!M73#(KEmM+m%cL83~z8{NI5;bL#Te>+~TmCRS!@m>bxN3$~It z&EoD$$9JDE#nnst={?ZZsRsNn_tpi2Ta?;kwqQ*8qOdGG&CU zF9W0(ts2~VuhL!wqu^tp+{l+d17}LS178Cid>7Jnzk=AlCIhHk9g9*?#J5f5N7{_IckDm#M-)=!)?LP6lHK?iq}GX_8DZ$LQ;V)Z6-N2z^ET5je= z!+aFk4@e06@!Sv9+Xnh}ST+rmQ1!}B~3DQjGY^57`xNp8&xasK2It#R~ zb3!%$F2O2jbZwJRsyVulk$2JONyi!v@H^mq3!Rf!jR%BknhK&SBSc4*U_6f5c)vSz zNB`Yl?tB&*Iw7JVp>io zYBE>0Fy^h{Nd8z#MMUk875B6xQuI?;8HwiLHUXid2X%u98F}zPy~pv$DwgWN=nBM0 zY=KT?jI|AV=>K9)OCL__kRRY3o?Rr>Al}2SA+z*QNf)8*#)n>&TT-Zwb9Gm8bHN5{ z>5Ce)gQ*qmIeYvb;B-1E9pzIVMYS+W^|s3|Oyb+(zL`X+29jAJU?w_6zT=rIC!6*I zn$q9S@m)L$5&$z3_~jn>>_&6(Xioa+FR)qi?vqFDWicHn#zMh}p8bm6?;*GRsuX%t zxp|NxH7ary3|uGy+>q+64Il2LheG?Bke+5#v6eCq-@8+zvR51JR;@8)qv3V4fg$c? zMq9HjSX?icQ=9N`N9bz!S^+OEW;t|P7CbTfVP&;D+s<%49a((B`pA&q?XjmoTdhBt z@d<67U~9b1q6A+++0Eg0iC5D`vHraGv3d#=USYWbVXv9_1#|wy;o%l&S>W_^b4=k_ zR)}1nJz`Fn7QGh=C<@B3iXzQ+)I$(4G%fdy>G57Uw!<0q7&9ijooKW#Pq=AGbqI~% z{436S;@Eb*aJiZwus(%L!H9PVU;cjp{tpRY;LDo-R8YPl%me4ECO+ljh_{gQXEKd4 zryQ&I)wv{l0;q5gF$MOz$!e-h0Oq>i&op4UE#pKdE<0?=3}X2Zh9$*+4jQ<0aaH>_ zBq+4DmHIC^lYON0QS`de)1zk2qK-Va%HIw2=U1^Qq|oQR$LtcvkcFlo1x)2l?>aDf zRIAo<2LDO9w>;5lM{Ey_$vh_i+X@%wmfH`#;UM|bvSoIA*0jZq(u!;2tA>UZZOu;{$1D0W&Q7EUH@VmiipvDLWw-4j+C4XDHp6_sI{l9;Ndg~9@NyGx^8*-oi za$a}dBl+ov!8r^01>f3~mQVSh#jBih?WKKTXm|3fXCx~@AavU|a8nEUa==h5{L9yM zAq()mz0F_-oGLH@Lx@z8##q~Z?Fsod=qo2AY*9@~;X=0JCjMcFIl7?=jeYC$=tWzE zc&35&m9cvHsyLFR_at#_;oKg&GkWnp){bq~e-;f=A$RRC$$C;ZB-a5)NXe8gfw4(-ztj$lGe!CVFUoOCw@)dEb(!ZTQfE)_ zZ z*8+$_1GA$pKaU@Bd+p3jin)qx6zdVEnuqnCa>$kh0Jhxc4r*(_fOl`& zZQnT>Um~W;--TC_SYBg>{RRVA42AKmcO}O%K({A|MPW^KebMhmDtzU@!l@A&t;8{i z9cLV~Re$q$=gN-dRz9ZA963&kg)7X7X8BOcVyP{7uwdGw1xLDkdJ3uAGJ>}!>-fGN z2q^`0;A9glbOv8$_`=WyFBkKtB5?P zJswai(JWYwkrc++`&A&Uju*zpR%SgPOFEpi+g{xgk)ubg=QhvcBm9t1v>Z>BC|~ls89w) zQxh?pu@Geu}q2Q>m zRXDGh{yzHLd-NDSE}Vh4@c#TKc?&^qdyE4S3ZkF6`0kWAVDfV zWnU5Z-~J6_l#3ed38if3QXPKT=Tm=f3B8)<3oe_9y0R%w$C3P+B;aBX&?r>u1h5JlS?IEpdCm%23$# zaD_>5m>7geK7)$ZwE{0mYFt)ipfZcs9CJd5#GO2R`u}o9@UovFKUG3AzS99R3LuZf zSqn%yVuMmRznW7v1TA}jn|1MdX7HykIVM#D6NIiWh|I06@ca({1Vju0)HrM(MuH=d z;~89;@4a*L=ex1rhv5p!YLRL(K2L!84w^0BqJ?tKlv0T3i()v6B6yRXy}rH~6dF_v z?@k~&KLtO7PfTWiauL!P6>DWKR_Xp%2mV+uhkz2@WRQaRqkvIx*lYI z%5SRh`(DmpA;-w-2~WlUauUxY6tpa{nRyg_8yQYyc-K>lrQH#4r$rKqYEcdSNPdX# z{I4T#n4fS{sK?VH$4snwD_BpQhzJ73Pmce3qMUeD201*q_Sq8N|$<=^(WMYU-W`-Wy>}c)`x2sG_so zPkc{?th^BBbu-SEannmGi^yh5F(1;CW+UAa7L6;RH3U-b^6Pe|wrU=AQlU1n?QR3=ww#H9*S0fVboq&%R)GG+RQ#F_sUs z=U8G~%fo(%oT0)1M_;yCOpevqt81NAeK0)f+0klrX8j)LZhU9(RZ*9|2JgHbK)S9N z8H07lpPjCo{Iw~qy)gwP2PrKGX)GOUx=TI(e!|&m zRRcwFC?>-W;HZ+ycXB}VJ@Cyfa&^ij0}QxJE0M+vN(x!{P`<7;8p6p7FCDu2%BYgM zlA&T$(&|M`MsY?vn!6*eWn?+fMFb|LXvzd#4D$nSV4gh&oBsasRvC!j%+puFe`ZdG)Cc&->BvCJ5y>iA(ot`<_-wVnBdbt79Ac~*4g z@?0qjnb(w3Ked`8dhnk$K6mcP(zXu*ZMHd>t%6aBvG^|8tvuJlH^MYaGQ=iYRr9YG zqP{6`n*;{n>q#sak`&@iO==%6BO;|G-mQVpaOJ!8qI*=h$;H?3@pA}5b<>%TPjqrh z`8!~`kLTzqWu|`Ta^7b5RIW_tmW(fDQyYdQ=vZMmWr~At^Mh-!YIG+cHQK~CsJaXB zUm~o4BdiW%g+$*wxue0@S$`4v@{eM&>@45r3xj^L%U|56#pKJ0rSHrAy{ zJE#sDem*8yG&D$Vn@ksde$N;Lb&7(gtJ1VHildoOW=)^W0O0tod(#Qnb3B)&V~CfQ zaGgI(f+$VroZk!9T*Xd-oYez(va9X&D=J!4z)5SZ1=+_vGJ9y!3KpIPvQH46ZRfy7 z9A=(G@Dh|oMZsCS94#7VHt_5UOrlI5JWrK|{QYz$0J7>syyCiPq#P2_rrLgn@Al9F zWY7JKAK&8rPAZdzE)>+-mf-Fmdf1BpTkA=(BW(-k`sxv(CH`(#3r~B2gqL7dXwO(1 z>Dm^N@nrUqT?gKt5m^{c@u11}uEH^@D6l9GwaEZSa8;AJs5s$Kng4J>0zuCZMbtB|d1BKoCye&jTsZ++@9RN*% z4)Yersbxf=p>;YfO3t~%7tV&l`u8>>vF_E8;(@>rmlFC?#P*Gvo_vhRqXM7^_Eput z=MrG4;=j2dxmy4QIXE_1b~cyn{C3=2iuiWEDY-3iMxv z37E~0B@c~qDL{>g@LKKUTG39Cn_KY#{g+k91~B7x`qNhItBZlX)4x{xCVf*Y6n; z=G#L7?W{KY6|6~y4ceXGQ>>R`s5*1&;a!4IYd&`93Qlbc?XTqbiYRL_@tWcy+(-U! zhnS*_Pxh*Wb3(?JX!7c$xQK>jeV@UF364(2m)*9{E5O^c9WN#E{FOcPk#q)_f&{uu z6#xITN#NdvKM{6Nr%vX#z-7150FY}~ZTTjDXzbG;r+f(OUeWcEGKG&kKHtz26|6Y} zbOU|USkZG8wC5Ha{bdPKFft9nt~9mOBCZ<`-dw_s6Ke;utD}UWg;v59RS{Q^%LSvt zidj}ofH$hVbgiX;dA;zPs3XHgZ|=I&fzb2mYMH(ZT#b}CqS0MH);MG$^bVuG&85H@ zcDP@WA_WXN^HOUriZhxmBy4KNH*fRCH>{zpBipfjFP1>qyc}M6hW-&w_Q2*Wz)|h5 zjW-JepW*hy9ViK_0PED8XB5YkKN6}J8)zOA=drP=XaRMavzQBR5%DDyNaR5$7>)-8 z*#jT~QC%77{?a7ZBxen#i=I9|3nOa%PBZ(8x^*&4#8^G2B!1-8eT|pH9Yk#r_}Y5* zqv`P!_MSy<5k7SFtQFyEs3PT@KM}fNwMW@SR={=Ls5|3>O}hs;$1DZy&X)}|FREKu zQvSRt{r(`f1$$nm1K`7J6k(a_

r3;+svtUfE&@kWAc*W9~CoYi+NCQH46lTsDkP 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 z z-oEeU5nbS9tNa32k3*ZfP#>KPH-OKKZ1X2#>lD0fUYysA!u~3RKGw7Vf5}7JHE6?V z)q4y>$9W@eWjWvE|8&uY{m8P25L*K8(cStHiSk9V^Y_{9N@tVm!{AXleyOF2z4#s= zy&LGY(Z~!2P+~vZ99~71;?FXQ&%Z!j?bXKc{BD&fVaX7vaMVu&F|6=Db|P!pJTxCw za6!2JEYwJRV^=M7?f;sIa#U_phwc!&>rlm>is0sUVp;2o`jN47l!!)798>kd+-Vl4`}YRL}7#% zN1tz$#z&pVXE}t)Jk+uKv+$jlBOV{6CL}q(#Qg(v^Wx1g734T zQw|oRxZ2zeuS~@JrBp>$j#K-|#HTf@l4Yc53y*m=jIWqKk%s3$-RriwL{ikKVA0=U zHQRi;-2&@%hU=VhWE?L_(= zUUR^uLao^A&PB>Z)4{8vo$aNSt>*?{|#Ls2G5P0{Ary6#jEE^>o>D5nS+%p%Rra$uq zJE4s3Sr)d-C(igBR}ZVgjlT7bY=fK zh@mDO$l4CmKEj@H|0y2WdoO1vg;oDo6N=KM=A{f*5c!3#8RiyUxLp8(A>Be$hCKCGq1gNK)$o8%khy^i{oBsUcG^Oqa(&p_Oo*mU)*gijUA8z_$t{eHehGU8n(HsuhGyKR65P$u zG$LD2Ba$W5T|K+aILteFD4j-s=D8qR;UTyi}$;zIPjNpN#=8no_{gHh!a ziBq~f4s2zNf=~~&RBGHO%Sd^ih-Li}#)v$yVirc7jb>9={dB2{rZ9E%P}O9`;KZmD z;=okGNV^^$*LvOT7X~j;mE_;j6XCVR7T!7JVSe`~PUS($9_8kOLDtc?z%ISga@Zs9 z>=Z-b;_uQjg}8px4)^8JN~OP; zbqa@xjWLMwG0BT#k(EOzDy}^g>iy*l5BsUAh-LW4yZ-vXe;h|T23F}Hq7E(~4#6e8 z*eQMAWjK9bEv8ZcNOyNVns%y05hXfc6ju08!(C9$=MJb*eH9%nGrVWJ%*S`*omZ~m ziMVA;ni?3>(P?z8))rFrVd6^|?7%Q*=*HR>RZjNZ*SC0i;d+;yjnt}UNce6BbJ(c3 z4uMfMQW%)X)yqLEL2^kf28;l3uGik&1)wDYW5Pwxp!~Z?Btpmd`5|@b#JtgW^1*P_ zJnYnN8iR2^10)4qLF)sGL*(p+glo|u5<^;0*;1mVDLsB37WEe9$EhbjoA1`G8raP3 z%#}osn>R3#lGC^l#~*)mN6CN7mt|J&leF0Q+&LuRW?g%lX8w34-)R9?1lBsSW)w~o zo%q7!-4S;Ok~&%z0<&ck-gHg1x^6%nF9~l>^4HWww1Uc4fY3MUmyRA;crsQgQID0C zD^X0#N-QAZ;DA?^+1gn0QUnT#XI2l;%vN~ig*fBq zHcN}$w%=neX{5~3{&p<(TzL7z82%4BLyy&(qOp_AJu`j6*hl9HZ;fWJ7YH2kh};nb zSu)rv_mR293+xNY>jA9&v&mw@!PvfKZ6Lf!p`U3HV`xRDy7_L^qWbzY+QozHvN9XE z)G}ja5X$kb)P;-O9{`=VJ)wWpz&>LbxZ&(D!#PDRN5BRTcH!rg+#_d2G|HDg3a5AfdOyJ z);4F|0EiX+nE7HfMv@l&WV5f=a5K$tZ|R+`7Enx4~=w1kWD#) ziDq4x6!;a2d8n}2k*L@Rccnd+=fzcZkSflB%?u51&P|N>pB3cF+qcT!w|@-;({(34 zoU4G@Rdj3_7b4l_>k0+wLnn@uq{FwJ22*N&7X7Hl#F8whq?&T5>=BqJw?G3P(fY7& zJ{~-JC1Kt^Mio||M=Fp=rJtPTST#RJ20n0phZ?O6+afA<=(&K7$So1kiEYJ|$UY`> z5orysj^j!7OL9$a6!#xP^t6NZ}qPD#)=w{WnT4dynkx%;$~k5)ARaKaT%c zy1a#%UF>VW0EOq#Te3d%VVj24b++ZF!^7nL^WC^*hb3rK44Ze|Q}s6%VHv7Y&M-mq zdgy&~!E2!V`hTuNSt-Gw0wnE%p}z6*{ViUYjGpoj%q~U$kuXy3B3;#~2C?pl;!X9p zVI$Ih=I0H|7ZR>eoRO3}3RA}|(whn&+mjC^6I6AY=>4|UBE4JahJ3Knq}xywe5snv za>}5ZY>4}P64qAthR}@A%StyZE=Ir>^Z)^jkaI?fIue`Da3uD^w6a;p_H`)%WN7RW z2NhShEc4!?n7Y4CqJrG4?z4pn!Ov8OvS}R~k@P93Q?+!?_nuSLAWhg;zi``7G9@)i zP7#Mlp)kfB0RDkOrj;))=Z3m-!yV|@{#E;De8hv&7{ zJOGQ|Q2t(Zo_1%o85Yw3yA0Av|7t=aYILb9(+A6>-qg$6cHci0EIttWpV$7}HvS%3 zMWatY9$c3;w&@|n_D*ifx~(54)!%>-girSioqj^Gi58PM`3o!KzTD`S#b?_#h#e+` z74tu(!+zydvF=`+EIo`8yHu0iphou-*4oF*#xe;(ZB%WZg89*J*RlK;QMh9>%G6+I zfS&yD`40&aADYy~0U#P({e}XJb<=8mN<_i6bJ(U@n>Vs-CwBfDo2(+1+)j9*Ngd&P zTTn!AmX?)fS@eiSbfuzCgPor3IRM>jyA=Wt)U%ISfu!2NV}F+1Iw&vSda(N- zt9@i2Y#&F}rADkEzM33vxOt-|IPk^$XR8Ml7T)Q00?rFD+>&BHlJzPf+{iskpUzee z1J!=XNzWY@6?RPa=vxMaYzM2w1JNrl7P3hh#^D&4h2xA$yuUtLOjEP^%e4T>-U=3T zpFly+S3BC!kr0y06N{h;Cv6u$iT{*F9RI<56-^rBnL0*@VJEhVeAEky+O3{_5GHIdYe|m-mTB}qyE6E%| z1p{}8XyHY=F(9h^UH49 ztLPrOVk<(TlK>-xj;DD~WyflhqNiJ40=ZWpPPUj3W0veq{A#l2j7lPgl7LQ7BAbM? z{3#qsT(@hNhPn%$$tr?Hm}IvuH=^g>nGPhIt89FmdktTH^E@Qf(;v0jHVp6U<;92 z{2RPQAnK9wF#ppud0)IO@gBY-nQs6zuaL}LM#z7VJgQ8*FTS&vi_s%qZ>vQXGwei> zU%fFLZ6{)Ov+d@qX-wxWy?P^KF>pJOF~?QUj1HYN8BfBiW^-`gBT}=*!)zHP8sp3@ z6OYtjBT21le^~%>X|BgG7cF-ZM({sY5hlD=3^~<}$>|OMA=B(J?zxpOrKHq}{hxDHH~(s08AjLAUZ zZ%rkg`7S%R3~CZ@GRUsG#-SF!ON-d*U@>Hbm(Jh~0NcCIeaxk8&?F;XCkPuzcVMcu zFXi~U%vvO{sxmOazsj`l>=f1dRw7Q;gNWcf?KSZ*tMAO!Q%?8Eay@Mf(rt74q;P_n*%9a6hX%M zxT_w-D#^4`>(n#$)WnDF0lc2N=}c6mtxg5dM)w@JHJ0e;q!0<0BQLb2i! zSy3T{x$6yvKgZ8w=)U`ol-YW_B+^H%L1n)?z_+RQ66x3rmMsbRdF^@J^-W&mzG~I6 zgieTlPqD4emUwnumqot0jH2r1R@$r=UF-ndA%%D+*|Cq&Uz5%g$dFSA#zE+N#xPY& zSgQx)gjgisNv^{U-vR=3`cdwk71N8@o9{9d79R77m z^A_3)XPuDYOeo|#sOjW{1}u$Gu$nar6>#h zJvh^+oNTu-_aQ`1pz zxCaHxzh~#C1MIOg51rcBNt}`&TwaI@%8Qz(W4iscDun5{$7EYHbVK(~+ zQx16x$sPI@E|{>#$Gju$l$N&ad1le0kfXSP*!iW5v^tvVO*)RnIj3)nLNtYNia0T+ zPO_K=?95qt?}JkfSijL%F$Z?ak3W757g@-W8%~Uyrf@a_pPe~r5IC?sJ5>!yh`EJ& zV8(7dxurD9va}wT>&6Q5J!hVOk7^CAE@>VoZzoJbcd->%GHLf%1Ak zQKqI8%8gZMB%>C7onx_(b|4U^Q}AZ;98@#BCU~mtVN9AX%`+yvN-spU3l zA<{O)l=}^z2fO~_I6@_BJ%=9)Z5tsv?5u#zAKdaV%bZ_#%umcHC01c3a;22NTGLOZ zfaX1%*az(&S>K4k9D2E9W%Spk?cl82(kQraX2Ml4%|o8(aP6yl_<_N35GG_}`qDe^ zH~pTMNu!~msTUU_XmYqA<3Yi9=Rxyz#B#U z_2+Kt=BIjktb?7ZeBOOX*v}@CVl^uW*FX2`4lt31+MoEg-@c z{uD@lgXR4vH+KSjCbK#mec3#@Jktqs+~-1_JO7#dUij}4a-J)Wz=ut= zsKsG!JyPKzqkDKv;DX9(NgqiW;t;u*sQ-oO*)Oqr!}~eKyj(7YaW^*b_FuN*UXZNY z@EzqLPALDb5x68WKa#wf>jTcN@7)y?xZ5fluMTawb!>N;jW~rn=Tvk; zcvUQc>?S`or^`N%h}RUh+l=4x0>O7$MUEg;*;3F=xWdLo{Zsu0(0c=n@a>f}8Q4B# zM2i~$?rY2~%4eO7)`K`QWl9X_y?<73iUz*ObaCcao2C6!g(kNp8-pMV%G`4`UzOSG zBE7g5I!lT;zNx$ROHf?#`=!quHkdiAtRe_48O;SDzoR*fLax?ic+qznlXBCY3!IIKG!%6f99zxNy< zp!^ZwPN=p&2t1)Xk+JU73pHwE4a9FRhxupLjphQf5;lrPK$Z@4;&(*zlm|#@PR!Q# za$kdoWffLqbL~Wv3N~Y-3`2_%>W1)%6oZHcIK<$PpM)!+_SGIgXC}2Nc&xi7+ z^{z8V9AzDFRiPcSS3lQyIv8RVFrsb-Sz zE%wev;1iEPB28T|)*vZhYVih(chWT&msHJeIWc+H$ z=OlBqya|I~1yjtsS^8w;@@4Z<&v8zypP|Ruq!I@*%JXYDpiFUx=%L7y5O@kaHQw~d z@YX_huH$bQVPo4c+;w0YXQyNhoU}2>o3sq7S9|xy3ZBJvDUUpE3se1E)#P)Td?J-b z-?*cWlWPm~V`Ddn#ON%RIdh%?TWbmVg64mt84fGJ6|nCd#&aana@lpl<&kuS)qo-1 zSgLs|Vy4>V&Y|U<-_@kjJ8bU3wFpIIhcWjbcaebFb7XTH6)ltgbo2 z+?Sb8_g$VGu6=V?#Q?yNv0ZsNpPP{zdEX*3R{h9|(!ef-l6TukJwbm#pIZ1;LVn1q z=>+Ayqiu#X@L++6S>EqXye5Y$yGSt<9Fe~>$J(DGQnfsnYfG!8mzw5emm!-XPk z`;2cJYICV)FJP1JUkOV3#+SB?+dKJ!6|->H zC&$?qTd-JhZ6*?8w2G3(jR>-y3v(9qVWy1Hg}5&V<1DbllUTZ>{GJ*AleJ}$`G9yP zgV4EMuvzHC7Sb5g;vy4nlEr@T)>CER?uU4NsuKv(T+QZ2)7P+>Ar!`^Y-2bo!C;{x zB<}AymhQ)pYmhf#nm9g83yHT^6`Yb~pT)!_ZkXVivTo?MgUuZn z#x3YzQ6Q%4aAbqvv{Q4MtKaX?UMT>(#_>6}MEW^6QF)8#ZRt$vej9 zecL)@559MiAjZrDR`Ei4quPmJ-&Z{<8mDpEil=uvPuhqVMt`I(9ckqRP|hKrR+~os zXCfExd~UZ;J}Yf%)e7+3PTZCT8tu^AP)3Lf0zB10=a&i%`L#PP zikyw z6@ly~>CEr#1B#RwH_52`$$9FuN!>E5)S{djN&!re?AUc`e4*#%tWmsE^S5OQ@vC>5 z&7fQy=;)q?7$QwpW8)}0xTzPJv`u-VdQdKE7GAIhIEZu?KZIY{g-o-;qFAK#Ak%ZV zUxi-WC%_%BeF`~-=?`8Y7Qlo<@SmMaz!aIi2veZZym4eoq>89eY`P*?E;@?p;|Fvl4Mi^m%W3Fq%aEdPfyZ5-J_lX!aD%N{fnZJe8`LfIPU*f^amk34vlDj7{rcLYKPLBweHe4 zYrwVs_#0yjJf9~cJEiVJc81*XtdGRa1>vJGOV2>gO1oLt8%kRxRbYf)!~6wftgNTZ zu#zv(I(Mf`yAgiNnDu>REN_ z-P~p73NvFHp>3$;tQx7YaQ!}^#zeOoQ_tH{blr1bFE1gs)9hbV!3M$o zi`!EEJR-rq>AVg^wiZQ?F(LG{0bM7nYf5ZNTYc5CDTi6&@1b!3? zw$VXXjIPT6p5pQ&q35EUsw9;4%EJve!oQMlNzhka>8E*LTn+%@72A?KBZW}WdcWmN z%7jG64R172BOf%Rw$!S*6U z60LbZ9vGkVgENpGj|m?R(k-J}{E@EyO8U2E()3Av`DHNBu6K4y7};UUA0-*y!2ya* z0#iph+|Gu_{zTrkS(*GJ67!vtiR)uX4#UDlO*Zl?xsmvx+-woO?Nav2Yc4RhAn3oF z*{ftl<^r|62$-dby0ab=ao$uUr7L@a(-9`%=n!YTdL3oTRZbq#!HAsPq1goo2-S*J z*4awR=S-ZFP_${5;}Y>2OPo2rS}E6*lCVO5X$>P$rg(S}V@}AI+5J0&4|occXIcS6 zBuTPKR99QUe7>yMS_X^nN%z1_$~BzwS?rQ}H8xNRDBJuxwX)ETV}G4gld$KS!Cm!($8xKH=gF7|UTr+g52T{E*J_gHQ}Ork#VQcGpYJadHWwA>`Q}?X)4sKm z#X4ZBaPskADv9m|XwHU_=nS)d--QEn8+slDe`Z{)K~85HDhFZ?aKFE{iQEWgbEgh( zMBlKXEDs>YZ&OY25i!(Y84slikew52l8twbLtV=FrJu)dt3QZa9(4rTi<0})vRk7;YcWB`6BlnVE z7qTOIg<4@M;;7|~1-LCE%`HzFKwoS+l?X4Jl%%ADrx#xxZSPM3=j0 z4%mNhYcHh=qnrK%Xr#-`qTE>$beby3zrib+U{hk#*eS-Y%;!)RDyPQJ#yuV3Npmq# zZ-{f?Uwo+RcbbT!1^;dYv+tpoI?nQ}VAkurb_jQ?)m$Rpx!V7i3aGF(wazQ4w+@B4 z7jB~|O~>`BpCmOZN0coLrT^+bHew<*wU{(nt+Nwfo58PG6NYyx4q8ic(^UKO_*5_RM zdngbWUqN#x!)-HnkR)}su39Ntlmq(=GL0I`a4UQMqPHOt;8eCtZ!)BTGOvpFIakZ_ z26l=`***ReVlNCsQ+g{;IwoJ=s+pUkbx3aD(++C6vp=&QfN$$>*D{O^7}LwZ8J)a8 z#ysep6tp1Eh(~4VeH#lmy6!W7=1z>!KAw89S7JBzqqn16o-cpDSWlkN3FI6>ydj`( zHV;9Ck4gh<>O5LC>wF7&r)Hb7Xv29n#$i8TseZ43)*hYdAE$i}E`$s+Cwb5aZ9_LK zyK?6#;-6ixiIW*(!m}&n)$9YHmdIMJ`7E%1g-@qATI5Vu87KMdlrt#I!4U}GM^fqp zUKuAMF|U#uoH9m3yW+)$P*|(*YeG-dGcWKz*NJmI?hJUp!L`JeJID5COn)eZ-o3F` zPB{n^sb<4k+Wj`}_4@ME_5P($a*rBv=aktVOjO2l$=83*P>8s_MIZ> zcFsGkCHXM8(%%k+t(<$V{m^G?pLpL@rAP2twL=)TKeyPFQTx)cC1d=TP=aM|QOp zW|w2n7`;vf*~f2xvPZb`<)vdllSYF4hq}*9y!`lpK5+rDnB2PMV=_y6L^8!*`w8*j z6hJ$95n4ukTUqRR=noFgKDO-@Vwn6`agr?3pUW zo&`u!sj9t-Ds-xUT{d{68wcW*&yf9}ujZ7#km7N1j_oBPWWdYw5tKQ#Z>oBr1Tq~b zK>pIZ0&-b$^uwtt#(XjBBPFR~pX^ZYfwIEJqwu9)>23pB@&+$K#PoTTX!`W(;1`4t z>Zh$Wk!)ll37vfdeF;Le0!-PJc!`$nVIJfDbxq+c2d--kmJ1tX1+6{P`jnkql!JmT z6NzP<+&?~QZ#og}a{pG$wZi>w_KcW!E{!3{hSZrJfNI8+h=|ImE1+K19zB*Q%)M$Q z84QY{UB_m7_0>^Ad36W>sC|UCXrmfBsY^6TVuhS-KSmjVcuEcwjxbycU<6?aRSMc) zJLq;ops&ctT5I}wlS};N8mD`n{5Y_?U@95vM5GfL6GOK0LXCJs<(bARf5NqQA+)cA zN=bfGFmgb=H1_?U)ztX|q-&KRSy%$;%<(kQKu{EPv1#jInF)3c+Jz%QY=9VtqzjgY ztSVn?Ba`HNUsirI_+f93+p=AqIfp=F*&1ELM?k8`ULG@1#@$*{6tu-2pTMNi2}@eN zo8>7umHD6)=x}RJhKc~f4k8Gv$`=k*#SNP$x_vr>V=cTX>M7nz<(1_`cH=xQU1Y7; z4`K{Gi(kk1Td`vm0Zg^M-CO||rte7DJEmG| zu_=Jx1W}0I*#^;4wjG^)91{+pW!uS5ytBaTy`4!3D)hHlGZ2gNQX=R>@&5_DNCBz=6@6H{unZ zu5MO-kV5_vA62C`m^tK{MQd}4EC(nsBPF<(0c&?2ami1P=3i7|YphhS`}xfDsp&D^ z4J$S>aXs`xZOPopHBk3a6)E=Px%1nlOoOZ5V<9lfpVA1)s|c4Hzcx5jiKbL09}jn! zt(hO@pZe~3sx(W1ATAuwc#l2el(|MLxqo-nwW3YZEN}wEvR#(M|A)sgdbRa;-&_=G zudl^?_yDAC(dr2D`?rON}4GbpB9dbWCl_?kNBxsVU;Xyn3(TUYt)C0OL>p^> zVa!^Fmad}?7Y|p8clV-l54Hf6ZLZ`u&$s!RGnkz+Jp)P9=hA_`C>x@X4Pa8*EoPxO zZ#UDUZmw8-&uBK*fU>Yac05%>EYjMSyJEQxl#xG`xoeaqPaNR~Cq0?@jIRsFAT)p^ z@Wm0@_S4MqbrBedE$g8k4Ee}WryE}zD8HT7w?ZmZ!Hw)4@4s(!+SI8+3F##^af@`5RWEo0TVryJy1IJ4!-JO zT*^iuU*qWysza7nSkuZHX*^kd(zSLdhvGMGiK7jvU3!QInHc6A_4H!cG|yQgPbb8O zXAh+e3kG8=PZ2{hjo-6(Qj4HZdV|MZ>Yq@4lup^!+MH+4hd!T600`7l)%rV;UAYUL zCEbPfEHmwS|vLpgIQW=yGBcWzTd3%0=p zuZ4$2=UzOGBuAB>F}?}QG9K$$$yC*FU5~uTO;XlHj?jh1wi-yhhf%IWz0SW@SFeT# zKfeM_>tMhTpY9{xVTS!ST zNsKmX0gCYD2^J~R8irPCrJCr@XUtb^-18oKokN&&u!2jb!GW6xdAIz}^jIz?b#-GO<4& z6eZ|#f--e~Ih@vRpR?AnApP7|2FH_Jj+095)$^*|`gqeJ)Sr#D*II1=+#XBZtA=B$ zD|l(W^f@eQhwKQW?fg!%Qhhv0>$e-S z95ON^^d5ykZ6vg<_f+>Gf3YQ8WMHKlm%1+R`s%l&s^vA%Iu5$50sD;?m4Gr~aZ_!F zrI&f*`)y*k7DVlI?7Qs-S0gkGf}Q-rAZHZwJZ|oatKNC54KhIDlcd3Jq~_zY_`DL& zANk&OLjI!mJ>SvM5Q~l=)0CL5h*^@r`8)Mv{X?#B z>Hx?jKOA@|N&h;5z9v+7v;>;jZZdE*;R0qGfbJ3$$08~Ai?%KvU!eYE{$8^+K}G46 z5aVpQ=FaNUsW;SzO2Xiz2oIv;CE*(laEXSO;{N|1rR+>{30hB-U0P(&vb`7Ls^g!| zf$vl>Czo{2DJd%1M}MND%CH2tZ-I$Ee{Wj`w+{=>KTIR2JElVcmA{>O#eR323;KSL z5|X!~W0!(_lxK>gb^+gEPa#xZcAoYAt`Gb07^O6_S#_yDP|4K%kIii&%P++at1Ol^ zVjY~lr1%OCN67EBMi-u>h%#zv4YZ-ceJwC;#0W$(iJ_rlG9(6gdyc-8XGf1hEc9S{ z>37!fZCGuK&#UDy5n-hYeni;E}KSSpP`nmBXz8K#`cuRNFUglVW(0tTagh$llxccy;Q z8h|C$S~ZFX_V%m5It}%*3lwa*&KsRn`X22W^w|t%NZkEFQUqK$bglAnhf?rW`r`u#&k98%Y#b zadx;=pK<_O>v_pp9dsP?;)B27clgqoaRTA%Od znQP=j7igwE{ThaqN4iNE4o8814okR=Cg|o0@M~VDxb5 z;oB2JW4Czyfi``GtQQ_7wo2Jq$|PUxY!$`%Z-+TGmoRm*{&TzmFY8DIVFuu$^Fg}c z-=&&edMYLWcSixfpa3&K%)hW&1#6c^E`|pQB#R8!)Hh%Y9!W^lA;DJ=@*v}%;Hg8p zjEF~&*9}K$=KEJ}=>(0bV%u-~uK;JHS^H$xUBM8*^@)-U9^@eNz%UVEdZ5yMx=%DC z;d%P)d6}d4B`(cSal+*9zi!1EF#RzGxAcd^YCV?(*7K47PsYn>Q3M@*))&wAgRA?6 zbl;)XmlSb)51FAtN&*i-^Ut*E4#Zl+ESfH+Nn3*go^nzUt$~f)Txcl&hhMuMthxEJ zg^FjLQp6ZGtjzw`DaoRJr=YaOls4D}y&0MZ9lTnrk;#09DFlLWV10~JhUzZwV3=Vw z)B2gDAcZq4B?xb<@vOMO{`=%2Nzw&jjcS{A6w{VC;ITCxO*3vJT6o*Z?;7_9kD|~Y z+n_&7UB8u?7+ftuY(g!?uoJReO9k{J*nLswm#bC-yed$AVv!R=9NnfR(lkalGu#SI ztg31P*JP?a*Y+Kn#vLK@#9t-NtW24<){cY34_&-|#ONE|&GAtzzTON`6`=4UB%$kZ zLUSl$Jc1H;1oF;xF0ooszCM{{8gn)PA92kWttxxNa;a577a}T9<(sra_0iw>kXj`_ zG5$6-{V(492$~3}70}VydWKFKo>3m6aOiLQf=phADgL9$9t>%@=`!Afu_tpWjt;PP+u zUrY1hkMA9kzmsc~EEGrQ7h!atq@)aOQqp9m54(WvCDIrgjNeHRKqlN1X!QRG9)DuNjo5e$$r~vnGu;H{if&rii18gV4YTn? zYOy`dPqih5hSY%PCxT<(v*6H;Rv@Fm&l1LU=tI#cIS6+W{a z9}Uq!+wh>VYep9nM~@3MM%@gA!?Y_UeQ1j=tb9X5&g9KW?o!+}5P3Xzu;T^RsEFL3 zVf$z7vn(boGPiwviXUE7=^ys(IJ_?Jl{XXN%4`MeRqZXT1OoP{D)Ar!6D1+C{rM1( z*FUqAjQQQCN@2&&^ApTQ4>hK%apjHn;YJjia zlQDHINVLUU#}&>GzBDbO(7>d_r3$FFx()Ta|I|h>I^zw0zS=3@y9^BwcTIxQ6J~eU z`SaPBjIJ~X*msiI_Z>Ouu!!+x0ef#l7!`kp*pvH_YMm3jo02 zzjXQp8xgYphZUdFEt_M$NSI`FCGv6nKa0}2Is_8r>*=n@3H+dRmSIut^T z+Y~(f^7Qlw@ur{9sh@qgZ5naW&K)0Qa#YIK^e(uc!Gt-mVwPJ}IfmD@B(gmA@n^dU zMLe#f5g@RJf|JW#fX-~0IwAlFrbK>H^8m7g?gWKAgnTu6}rv)zMppxZXjFh$7^+?m8` z$PrR>eOSTO$zg!<9x|tHK2vbHdS6J+La__^#mQ@ z>EamDs+#>|mSraqLMT>9rq=qmhz>S1swPShc_8)UN+yVXQ$7hdBz_L>FDeXy)66d;e4|Q@h$Jtr+KS;xt^iHlOMqH7 zLx?(sHdLg76P0s00=l8w961#1Ok$Ju+WT)2u-SxNQbF*7VEZ4(7y<$;(zWhmVc;@y zs|t~nfCB&8E#~N*hRQf@U)BlMg+j(a9STv8<~xpC#n+iOhTwdw&or69o2@-N<(QWs z@y2E{3E52<^m%SO(R9lNa~ArnM1q@v3|qtCw0D+q1)g{_t#M#r?t1S9ytsI0^T{q> zAS5zqKTP66smnxTz~qKT8DsvTIw1)o6Uam=FY zXBGHdTn&VRv~UcEJ)#w^S*#Kwx1u04ps5H^xQSQ_O{7`InxbU{x&g2+HlfJWPKkik zxb=E$?3y^)kIzGpn1L06dl+w=1{%l=1w$yHaSTT_tqEX(s8xG2#(g>6$HukSfk>L3 zfUe9Hp08hHd?qMt(dlC2ic?ARR5zCx=8jxa>)91|oY9oNEXf2-9~f6r%sS{%gz*g0 zLhCKU;UT$wGhW&W3t1M-Gfn{lA|6H^**_L)2)Tc15nilysB%| z9P2`OXZJb68eqvf7k0csSeZ7HwQ?j5B*fWu`Rpq8CJa|Y411xsp=_gvWP&R$A4E(3 zd)KBnRhAgwkK&iA#NG13Whz_HoGQrQFfi8$4w;-E;(h^~r?Yjt8mdQ{pn!uRl6gA! z2^#MIzKlXET-5q@aZVITOI52zOzIQQz)C2n@6TxiTdRbleG7=F+gUDsmk5cNhZ-_x9akq0cnq1@+5keqv2U8;O zTbzybP&nt$a4L1B1eW&lf8Lamkqq`iVRCd{PwZeRZ+&bcMLBJ-G-T7zie}F%C!Pdg zsS2y(*&>(g=3}4n@v#=xxObF76RdD*trFS06_2drbr+i=doV!7;0cRWFC=}C^i6K8 zg#-1yJ*G|GIk=JZY+>=tM`P`QIRA zJ~Air^&SI$EZhRV?D*jaNT8iRy+#a-Nk12Xo*PhrwW09D`_;f{6(Ma`PAPXIdhJy( zLEG!P7D&1E(vkoC@tA8Qt)4@}<}8)29AsDeFee8&h9t?XX}W}v|GPSr#IYE-JLhEQ z%t+H^|8(?zM~3nyg|wGObk(}GRqprA<*}34wjLb3rZ?c$S8MEx1ypeMpK>%UcAC^| zoXH1u8PX@xbQz2np7E4umxl_ty3yG8{y29*y`dqQTd{duYz|>*gJI?dRx|4B0CAe9 z(8xgthm?d^)GvvwhUnpXU#OD@eaU~rpwSB_Wc{w1)kxy^<9)(AO{$L{avGNm{^vvN1e`ch# z$GOvG<0h!?JCRS$nq$OVV1BIo<1m3dDdi@o#^Ob(hf-+|$2atxMGXn-j$-5DkZc|K z$XA>yS6r+GYBay@PELJf05$7S8L$sKN?}bzxJvi>u6p9`EhFo?%uG2_f6_2e-zST(9%o+5cwuG&f} zoAi%hBy3IC=9n`HHL*8ez!(E}scgrLoo!JT8ZL&cTUg+ZV^rt|(f_L};(%JB@$r0@0=?dHgR-(>5qv2S*skE5%)8 zi-u|{HUAcgG#jXhx(UKd$}Q%=IOnUjm~NfOuoKPd#ZDg0o-X!6&L?@npPpHBc8pes z)g$8Zwj|#DpZU;#2SuK&ZfDba8g6!BF?M-rWePm`_Mpkh+@pvE)GSBA*yEHKy;Y?^ zSQ?R)#le&*b&pksY{N@L8X?R58o4A^SDGAm8^q&TD7s9xv_?k|asMO>r@yC4C0#TM z?RHwlxBfg&dzufOUI`B&(VX3@#t}@_B26>GnQ+`O2b#-uy>JOch!%>- zo&qIaE(F!BQ%o!=2zAntGgQH)fR^fvFwfyllvX@dpdLmgiMDb4W(wVK#c0&acxEL{ z(OdF2;3ddZ*Vs>lgs?|0ano>aF9}p4Iw6pQ;eO0T(T>UWnTldkAHP{EZpe2xXklWfQJA?zyx3>a>rDj=dXFgL>KAk% zH;HN>R3zp5PL5TFyZsg!MycI^wyA>T)A+lJiiZA7{s!FRqGfqh4_?2@2<;ZcOwgU@ z&Us>6h*#GeJ2m=}ZYwDfEY3b4X+~3eF6P0>ba?Xh6_J_m-mm&fpLLE|>;4uzjX6Y}6-=w~YTN_Lfd??U}SQ>2p0i5+5|s1NoLJ ze$vhi?=m}dGpg<^CNRyTAHUH@#G@}bVJO4 zunhpcqzcJYf{bJ+g&@sTBJV8Id(fe5!?F8K&)btWGt~aMWi{zt4dV>_X9J&E1mhSL&nHSVolU@E`RFPo5x7R9*x$|C#~NUe+Q zg&ZhWnfJXDRl??^M;%k71@oadFqSTESTP)TKDOg?^@1$Tr`ZNkI<*b}$m2N7@xB*i z%;p6CF*)Z&&9Y1+H`zwj4Gs}Qe$in>Jve1t28{MSsU1|afr~T&CcD(p`2X?n6qtH)VHO^iYP2UsM;fl^1JF2++MS9Ma#okRPP#@}&;(a?{rC z5&piLQ31p5MfMh>lik8i7GUZ3@Iks@#+hD0Mf19ZKaYcgdLw? zU_32XjCs95nFBqbyAl9Wj9>vU#k8ddo=H$?qT_}ICq=UpwW4Q3k>SBwNgqh1VK|Y9 zMG~F8CyYgMm&0~rrj5B!3rQ$t8nylQO>?6U5&7-YqC`j%^ z*w%!lN7Tfym}YSPKkxQ#k+r*;c4Q}DGy%Sc3DerG3x9;+ri>bup={_v(oDgNnS61B zPf)}SDGBtqO1dPn=;`9yYiNGUeuEMmxgX=iKVRpYbpSdBcDd;a&{YJY7t6!r=2w2r zzu)NBpqkyhmF@izw8F+2+-(;pjdd2WI+tO-)h#79C=VqIE-d#PNQnUI*F|@2C>2Y$i#wFazO?!#&Js6s5jvIYC90 z1r!)ss3K*61@TplGg9IoDdQp}@}WgF1c9jpCb>*gS1=^oaXQ3BJJUV$g(8TE{ib}s zvI(Q-&2)*%@dCyMeo*%3Ho?AaK23drm41fG3OA$bZ45vQPpG%>0b0CbiJ&pjJosevTpu@b#YIf6qC{9o|?D zVI?HAikVC;R(bk~O_Qw+01;ZJk5055rsm%0)0EVd&boK=fKX57%#6rQiRVY35d^mF zDL6gtf9Cw<>{YIowjD~2l9GNGxQ~Il2LWEvX!^U3D=|2UH-BaCqdBCE7+I3|^9bU> zN63BM(r50MAZ&s|(CZHfxBoMG-Z=3tnJSW=2tQ%?ierTp>3hhxBrBnMg(~(_Nnyzd zLpLDz`I<*|(NmCC@|k;xDr=y8*&7^3&_9K9?80249{w6C!ON5&vpm+(M6w>Eas~L? z+c4N4Ag4z#*=rQWL3*axuLFPephmRF)@s&VxInTXVl65;(JerS#laY`nhBv^+lO&WMfP4+!{VJ2C9IsHhRRUs${AW?f6?)fhJ z%b-lmKDSvHNs+IwDNsm-;(^eUCls^}T1xB5U*78o&oL6twm6wiS8G+LD>WK1V;LwiU|_`(6-NbSlch-3In4*&tpNQ1hhnKN87a)xuGo3nS0Cjd?jPV#R}O z=wW_?n_MxsTh`|`?=d?^&pBDgX_O`$zmTH=*~8)@wbG#EUPpw3!njL^`hly=q!4j= z2s+0hQh;7)Y$Wity_V84V!i?dR;%IIra=JJC~Q?GI# zCEiWR0=70XcOD^O8zMJXt=Z?+lC)^XOZZ5YKyzbtkkUZHcQ*MuK#w~5=eqk(R;d1T&Kb3e z2k1LS?ID7)EKWyw2igW>w=T89w)4=n$PLc}55YdlOHI?MMBVaB?A&krW#?i!LTcqe zl(_w(ess$QlvN~_t_@0+KUl5`Qm<}hV{qet2~h4U-#v#du}}>rk^QxGLy}c@fJtw1 zVZ2EhrHRJ}!iTO*hP5u>{zPSA`!)1!^F-~J;6TW}M;T)b!e47LfuUbizM=)I?~3W* zh!2qkySwM7{xPYGoA>gWOq@>K9&jhaRu5j#pLl)g_aG&p!|1SQ%g8@Xf|30;;NS+K zYoBYgh&fen>CR*cM1G73%P=-}E-61wTmbKpb+cUk7L=mcM-|&BvVmFs5aj#fcL*1E zGGoByZd9AmfyFm;L(3yx;_WO~gUy%`BISQ6kJ_hc)4JRLMl_y)CeHkld0lB%375~X zy04n~r8TK6nh`SZIuQ!`_l;Nz>M50}#GoN-)!eecsw-CgAS-npd0^>mlCL0+U0e}J zbUcVB2;zH;k5*#k)&-s@@8pnWaPNOi#n!g5~GYqB_(kbl-%ksLN{vZ7E zY2*h234kiq&MMCH+DJGSZotm0?4jPLG2_p{ z^h|7Zn-HyHZi!7yZoM;W0HW^p`3}K#a)D_z~4N_RN3ygR(;V_NwW0 ze0`>hK}`p8uE6#oEC4gkt$}Re; zc@xh&k5ymIe_KE1Kt%AjT$f#`q9oZ?&ZQNiz=B|}s_cXkfY`?^LE0zH)5XK(e#E|Z zF=4%6k;gxNEEW9rj3qRPSTVqW^C1eNpY>&vzt4tR7vTxCR9GIg+?}HSKHU8~f5Mi| zQWB}^LIek~rIE9kA_lr0h5Rpaq!xJ}QWoA1r<5m%#8!Idjd5f#CHghI5+HR)(geD~ z&H<{&r|(|>6@Ea`Ao{&O4tN^ps|k2YHL&>3?0dg0Jyz}ot# z@jxg+hBDqwHs8%X%UW z>$1Bggg23S_)fof&47-TPvC%|4=h6)3114mf*~wJhO)V?1yUO%bz0&MdIc;B{Q`Wl zbDSdlcl&Jl6!Z`o5Q(>rG0f_Zhe`!zFZaJ za>HO9zC8haW6&wSS0bt}02(Ne?4bBv?Nv3Y-Rqb9F1l4%Ch<@}XX1 zx;mk!8A5F}@w<%XLV59W4a90>_(^7M!gt;TiF6R0eGWwa&}h_t3BdbQ{3av3s?aXT z$kF@Yr>I{FM6N}NNxj8;@>bOHBR@gLTEqQP+bz0_%E1K|1s=fhR5rnU<>Zzb6`wIdF=6@}}QGkeHV1FM#xj1Y26nta{P>KjCyjF}meU}JB|LTuCt&Aoqw@E}6yWc)sVLI`3#=Z(C<{Co zYA>XrEb9bX=xg|l5Nw!eP3o65!HNykZt6Gp%QfMkPBiU+Ji7SjP~%g!=x^aW9Cy0C zXpYtXEL5I{g8S#RAVx_fM|!;wVKV&6-HT@&@W%`8{!u<__z|RWvx``373DEb|CY+T z*`%wLgSFH=6c#qP$Qmzb3pNI!0ix@^bPwA>MrPPp)ryH4uQi1GIjoU>ftiLn9>E&) zczQ!s{S}$$hk14DrxThzHTf`@%)YnS6v>jxe~2dDf9hAyK8**K911QWV|Zx6#!E0? zZj8%fl|HVLNX>u^iQg?Eous<2UUjKIUr)W6}S@b zzjSm^2SPoTt_SoqE>icQSEJ=Oy?cpk0fA?(lfI#5m&B|6;3>bZ4J}kciG*C@b=dD3 zk|GXx&dpm1{l%qdS;{ZKyNLt?EYzWVT^c@Y;%+v-`8=V=`YQkv^DXt2bX?~FDf3dbqg(RmlE zk1`d@xkWxaKu5d5?G@L&@$ciMun^Nq=8N*zu2|RIsc-DMiG_b}@B03W8@Ip5%E}o~ zshlcmZsXf(S@%v5PAg?d%1a%gYjvddV9qNkPy5EH0?VkDWN`=;DeDLQPU|`3D4x<4 zEX|n^insK8QnRgwShV7>GoEhKM=(HrCDUD2;&(wAn{u5SE0lRif6i?GU3k zT$;Ud6+2dbX?Wmy3&4i1AB62xmc~`hujPoe+}vR;XD`1{TNYCf$Z#W5br9M3W~|3# zI-;i7DKq|xn5)4x!QjlYG>#8ZnF2a44fGTLCxS$^BKf0c;f$U~zEl@lcUkpy7~7sz zkta$z`T{*OZp5^2G8{14+jzbAwdB}aNb*W?Wi*L6tmKZ$l2Dh~GHL%OJb4ydO_S3; zTGNV{MM$jO4R!}MNu&0wM&XoIdsi@@TlLFPaluKGgcOEH#`$M(wE$e!DoC;~QA3&; z@&dm7tp53e&zIX4K;_&;>4!6{U6I-gze#!~cv(vMh8xJaPV8q>gyNmNb`=j#_5EWy67l3Po&J$pVZLu_mIVOR-L_D;a82o~a@cO(*5~wX9mAJta>uqduBsaXIiH0$18LVn#>nq^yfNGWj#n zJhqAN$&dbrqUt;17@aWS5FY*zTF5~fc_;!v=1)vV$n zv*vB_8|qJ0~5PK~eC$jDXR&@LnXd=PP&St|3~W|wc0^KaeAxR zJd{djb4s_>$fiMWXy)I<6OPTnXehwO0wx8rEvgLbe z1i;O1R=v?u_FvhuzzW_zQuGjR_lal#>or~Wp z^}m~vK2IFIQtVPqR_wCbNt%W=Ww_jG^O}vsBUDk2dvsnwg=@H)fx0SC(9_IlKALkC9?B2e_;?0jd{9;IAfI7ld^yNsG6qAYlbcQXDgknWTWVX$Qi@a#2iJGAME zEdhAilUnSEF&1+v@dZyB{LJbBniaPi(s5IXc!S7|>n=<99QCb=GVW9Fisi$N+5HSo zvV?9e$w}Y=lkyip(=d{mwO900k0P7jIg|K>Y$V39>NKa?R{x7W{Ic6_#5twN^W2q! zH@dxYOLfC5U{I0!8vq{(Y|a&x@mK#V_k+L63o=k>6QF0;i;||^9#lvjoqI;8%l?4% zPQfdE4uEqPbUlcCV2*wp$h*Xm13AwE4dIkW}>Jd`L){QAPN@2KS{6(Y8FX(wBwpU10^di}ED`@#npEBC-`i!oC-x@RkFS5`n- z0>yI09*lz-iIw1Ba#R85Hb*FolT%T>o4^XB8oNbwCW(jgCFR-`Y^{9^K4ouVCpC8( ze6e+$G4P~1_1MY<5yfmvImDAh2W~ikMO3yUqf~Pu_=_@R5LPOFF>K(D4@h5IUID@i5<1?=j<0>=in+bjb4u8FY!B^G{T5Xk&gDAG)TEl1`xF$z@wtmd{ ziv;%2lxh_h9GWjBLR7GE{x-RBC;$GhTjuDXx+QN5!14>}MycVz-YbUdQ-K10M1Lt( z=gWrZL2*bw4im?dlb`f|Gi*Oma}ezYam6(^Qea@=jY;{EktLd9tdqV{tL-q<9nBr+d2J8%=7)jlz>i>);_yFJcF*640WH;0SP0v8zE5G2B?k* z2ZjN5@dGGQYOohvhlmQzzbi%nCpevLx*B*(`}Vn!WLdih4^SVUhnfXr152Kul&znn zYHtOEuJ$%Z7;RPk!Q)DXj!fjqKTSb9LOlbo==SnodI%*a=#Y^YQZ}eFs@QBpj^14} zi-5szGbds`)8Fxe8ULgp;e@pB4+s*3Z`9 zDu)n`r4HoSi(2yGxG=fR@aI@Gu`3a-|CVZ@yymyqd3RI0#r=_CO}diM2%)oKVdpd? zE-TNt!O`WM;}?9kPFJl8OIrm{vc7 z78Xa+%Wz?zHQ`h#X!+e`)4du2(pAA7_251G#t10&#%G+v7S2$v#o>j!MHov`gcrKkRuKJ#g6V zK4#eLl_>&2hgc4>g-TUg_6#!t&34-*Y`#vd?20f=`cmy)K7>u1T*j!#3%pfy#g9K^ zW|(le0DcV>UbIr=TM*3;+AE1SC7`Jv;ISNnV9H!>RM&k0>@uExsom@PDwQMk6zp6j z-v0d(KYB=?A3?mxwIAAM-0{#ik_(J~TWRTCKkxCC9Tp`}?Qd~S_QWNJR?;PbK{8d2 zbe5GYeP4YryIXLpBcd>LbgxP001+~JM(XuTJ6`a$WEt_dR)MlcE#OYWG&hn!Qo&4y zlo}#0Tx3>D60b~?t8?*&fbchK`5;?N`C7>q;HC+X^w2zo7Oj58UW1=FR3QXNL(lmU zc^kmg1NM?98wR!mf*$e?NO5#^HqU?7Y_1BG5;g7B@>|2bscqw3!E8DKnx|)-BVt!m zvtTp=xy3uCB^&u-S%7)Q1jOQlv3#YfRW)~$H0I~Ij|8iX4~u6tPUVYGI0^F3c(pY1 z43*WYa4XJo8{@<%6*}yeeSj0d+{gA)#lX_!zbzXIdT6yRlI>Baa3@6jkjdw-9W91r zYd}okGlDH~&#@6!GtPP%03wp%21LA<35Wr0I6{7n;)w+(H=|xER(l_yIkl9Lawyq| zE1lt2G}L5yM`cTIWf_44wAw`hYrV;YR99|N8ElsR2ECx2`uXJ5auTQ`=5}fH5b>&c zW^%xo@c588pKGZ-W<}ur^V%-%=gneO9 zq;sleRQ~602Au2g`>axP8`2gt^TM=YFg^RqrVy^}z!Hf&kb6-Aq4A&JdB@ z&W8b{)V?$fE?RMoMisY*AS8s6n@&i4j{m=;7ndS++}|W`q0=Z;xMx{k!;;FX=pnBu z_TCZsx{Q{f`_2|U;D!2`UoW+9Kh~{1V0C!=#E+->KqNw(1}nyN$_1$<0%ewe%;(*G z6~De>C02u<;96+~2W#r6FQ>+xG$VGUiG$#h5e9N9BBXvfZ)OSC^FHgIP9loVA)7h~ zrS`{TOF8@jgQ^YqLx2ZK6SH=bz%{5M5>>Qbn-B}KvMa^$$g|NZ_Ume{3>#dH!Hkob zh%0P3f|fM|_s$3x&hVLircSqt(>V{D{-F$~JwVUYM|sHE@af<+Q`%lo;KHt!@-(<2 z#Sk60lk_t%Fs35C!!a7BfXf7AA+>X`@QznBFG`^=5ANIWrxMTIe=>!DkfKR}*;i(Z zRHER!^+m4t4 zU@ACeEl!~+boh$Bjc)dCmp}Mm**6Ft)M7Xry8l#CqBZTRSRG>SGbu$oeWE!vq`@; zqvf~F>Fb{)i&3wH^HUXF)BFp$^?FU@=AD2be8!3bO zIO`FQizr=x6;8-5q_0JXC2(U#mqKrk&%gkmz5h&d7|o{^?RZ@=jKBO-2X7G5olJiL z-f6hFwrR?()$^rvLN7Zq)%ZjQx}8UeL+SHL1AFd^vUY4&zoB^u+S3$msUlse#o4dk zg?~yDS`d(3Rv?}-Hn-pCbz3k$j=aCjZ;!a4|Bnj{qc<8UE--{a7^++;PdVatVS}5~ zN^xbW2+;Kw#mmv{<>{`|;~tUG77lNH>S#lBq8b#TT#!B;PRX%9^NKuQSr)zyseFA2 z(gDb=vIf815xWTRALvGF3_@{u65k$U?No%6va^XT8g&WZq7C*JNbP~(!_ipK$!?4tH7F^4L z?DR9My=1sJTrS@j9`K9nf^(XnFb;LnAM)!8kIa^fw^DeKE{=BU%95je>oly%Zsm@i zWAGy+(_}BRelTrLr+j7VLlvt-EC>j-RMz37{$K~?x$vZe)ObZ8>5%Oo(Rc%#pg6TA zcXXqiIH0aK$wSqr9WoP7TkwAx?n1#dl>%i!~5J9-lV zo6bOg$QB;6rm84A$7wFi#g}vCk>65%f;%DwTs*w>_y2Etv=P4Y6wt{XgQZy?L!QdMzI8RfJ*+M8l_d z>N+nFJt$czp3pZfz1ZaVV{fqWYTcWSE2skgE#<{{nvyuvF6zpM7AHFtVVq{&@WPpw zb6OzQ(>pRO#=@K*{`=EpG5c{%`MLl z`=hJ*;g<#kS1V5!2(p*!Sq@*C^N?P@?)_-p38%EU>Cx`j?fL_073kwjH>Fa*@@Zm= z`D)vy$Ja*C9a-%_^%yvRy*%`bqgMk|cw-0|ErtF8H27(_#O4J-|b1DN0G((`2_D`$c^U>uQ>9IK=##6Rg9804G zdv34ychKly9v}DlJzqH#EfEU%BGv4YlF-a4M6g%uDj4;}QAG*QmO%23HsNUM^K+8l zQJ!@H4RRMJL;xSy7Q8q%>tr3Rr&@t}ve8ojIatK|kq&7%^4DXWo*Fw=PV;(ZC*eZ55fSF2X$6?A6-5!+(5W-*7An`ruy(k(?@a}8kD5f z_PMVaxuXF^#0BXzNZOd*LtH&3CF#QFFC9mKgwT;In~Kb6645ZHv`4_T8WRRh2Zt2v znrTu%9uBF|9lkVbOUaklbKfVhr?&+V;$4m=)1p#@F{6cjgIiJG&e92aF4-dA)R(w_ zj6G7ae$dqjH7Y$Ph_kfv5wVatsUbjUU)zMRx1yjfUMI<2{RyuK%;;?~FR84$meUtn znbPDT>}by)X#aCg1F)^pDkU!;0Q3q3$UNbflJqqs<}^r|PAQ;9h*LBQ51{bv#t2vu zWJ;CZNoWM3Kv)$Y)bu$M?Q(e?`t7uV#;>ru2OT5ZHjwz%^mQG#_cRS;lE#^E92a8E zx%q@3ck~sD13F$$1H%l~As^C|bGBKIcA7Ua+%HqUd7bk(uxMA=d`QapG}F!K@7m_B z{u}>i;6AM{LZHPsHItUhAi>%dYhG%WL~L%c5qy}ahiw_XYlnsmH4j3!Am=A+gkgx% zAaYq*geTkR!XSr|Y7Dn^P2#nJ53C3M1EO9du7{kzd^dl4gQ`tX#Sww7YxjX#BAfQ( zXP0)|kIM@$M_-cKE0I&aPEJZ)0TjRF>mEvH1keXO53(t&MvuUW%FilAZjXP_$9^;&N;g`?9fPk8;pL;&w$!)f<6m- zRrk(ok|K~!8|y@dMl0YIDGWMN$sV1abqCeMgI5?_Wuagc_ABK94$C{%1%4y2X=lYO06x?joaWwl$d8yRxT!#gu zCbNR8YTr{`OQCs0V@Kn?%>@(YThJoN29f;81^^GVRjFEhOv69mzuFYelM!r!`&#k4nN=0WqUya!|E+ z{+C(%edjv)A3Yv(Gp&7mB;8%n6!?805*tVRfVyv`xHf!o2NgRy9+7#!RuzBxe>Y!z zD8eZEme3cW?G_4IM__Us?BCY=+kg8II{kBCVogdKS#l z(D^@iz2P3}Bp~Q)nttfzRAYpc&(jw|tN-wc5=et5u}Nhc$4XAkiBZVYa&gTn${ZCl zH>E)(Ms!4ngXRJ(yB2Bpn9`^qPHkJ4EKms5I;OOtJqAWayTs%Ps+DHXuc50y>JJM7 z7-~8K81;05Bo}?rkMVEO_^dalO{3Qin~|Dtw1Aa^>lm@e7a$G3sJMW9&&Ihy{K354 zZe8QUTo~eE0#{!(XtmaV&EcGMeswP$Cd8y&@Od?8gw+JShkd$EU_W<_l9eeK$C|!H z{hLjN{lXrQCk$OPKQKLawe=`iHHx1Mk(8{RpqTPmazhU_A@>nw2wQNtuI5lWAzUcl1@7#P_cWT>2cdc}G%~D#`kv73O{xAip z4D2Bjvk=a+BDWnW-XyWjwbud-o-o~A0Lo+BfHl!PBD5jtsajS?&n3M8UsHaWUDz7K z@u-WZ$V;4f)c!N7mipwkP}V_nGsCfc0NUy)$wZ${^ynUZ}ujjlcb)vg0)k zXdj#uQzx&D)BrT{!U1x?@I5N!l7vQ#B}7^e*5?_0Xt2`~;N$ys@ejNeixb zPJdQ-&^~gW4lX_>?!R--!&g*8N+{(*9gF%%5*$|nA*;Y=yzfB06XKP(>)D_79a5C! zrxA)vXsaICe73p_x3!(vegD|KW5I(xntq$ z=1_$cIR^Y#suW=DP1TV;^rjA`(cElmHNeHn7#bR{4c~~__qIHKy&&{@0qda{U&FxL z4?H2PJ!wVATbg-z#N{qKf;>96g#bZ7zQ0fB=MDvT69~nGhsebwedPG#M;3UKanxO{ zShCu@>Yy;$zUUcpcm@z5HH#o~ZvF`?*fTv_e;(U~yq+{Imu=<&j3Ih}V-Nm-=?-!2 z&|v zrJRYF2Lf5%i6bm6de;VeJL|6k=_}GouOb_c(2yx3WMS{!^Of$ES^o8$M|KV75uy=g z^|!cq0oLhBg01ZR!KGhYOPxM*I`mH%nSVv5JggC}1S+<1`T_Eoazrpzf(4Ugyx|Q= zadhiTxW;{7{$Aka;#U>JUyPuOvZ*tXT#)bS6nCllz(jB_g*Bo-u89Rt{(JKUrp0h9 z+66I~biSEf)zJAPVa!AYAnR9HPEKqI06TH~R3zl2mq3DrwAYWjap=WK2uU)J0Li+W z6m%^qBaIuIIkkT7nLO}^uhk8I+8ExXj@LzMyJEM3n^#q=X+x;r6m(Lt$;%We7($A< z7WZ3WIqw17;1*(#v)EEj7n*mYf5RVIf6O;lnfCIS?j`QRo4TaWJ05a#?}6M9$j=NV zoWEIv=`B7|MLDASi1T0Flrqm(>)A$;!=&fxs~A-5Y-YtMkE008JF6&sztMl6gQWsl zf8{;$K{cO_5bYh;4d1|)iWlXj90>h~DjelJ%*@wp zFMcK$J=}689%LEc-(#y8TVE-OZMZj7`7>OXqX69s;lb>Kv>7B@rzV-VUUohVKlcq@ z%PE3fOcoh}Bdmws-cdBnXpgzVUcw&-bvK32{_$74+rgnkB}~(OXI$;=0zu zIC}n9or-ilF$pI=h`!LMZ;=g|NdwSIwC}+b%%WT~1tBWn9ntx<(rcw^+UnH_`|Px4bOrU;jdkLlf>=S3B-1_Y zMOwYn%?2SZGbz+}f%EbJyFjXNwZYw1{-~17KOf)Oj=O<};PP*(tJxkVp0f>7#eOaOPOV%iKwKH*1pNvNZ$MGXJydOvW zFp`eP@9!{)8cm*i!X#Z8t5x`eenw6(7%sFQ8am@j>2nweq!yU8xe1%+w1**ll6w*X z9uL8&RgGh~!c|olYJ-@^-MWC_LVaS%Thj*4%BEuOSA97Y)#5SsoM6^-b7l+-mU|+f zW9bkN^zCtV>a9?1b`rh*?z(%$eBo5^b#uiaOuUL$JelHXSfhZk;OS_6P!A#5Z9D)7u^_4EzSMn^i-i0UA z9HaZ=dcI8;S_W{&dRuabt{XHDh%f|30}!dAE{3nJEe_JQ^x-wy@T^6)MO^n;=|mT^ zj{j1c3rwjyh9}8K2Y4w_hCRnwdoxy}+dkUetY2Do*3 zO|{(r8}6*|ZZxA4qlGahqOmgltjRw{a*I~m)GlSbc0>6tX^nksgO^%janh(urqua; zUk@dv2o{o%J3XIt{VDE@O4a-Ocnp)9^L}Lq#`*rDQ)wDlVAZGUk4QQpO}0OEvg}|# z_ga2VX$X5*>l|1nS!Y2Gbxvv>k0{mv`B>Mh1q?L{q~NdSiHPvWzFzfWXi= zxKa7@ZilA^HU~$CKH)d+nvfv6w!xQ!B`g}YeMIT6o(x$RE=+9GFgg+0k4yfVaZa`; z%MssCk)DyxGcL&+!2Na2nHEmv_y_O=>q%NK41ik)sKR0Pj#s`k9BuGFXkFsNvPxKP9>@> z{b|Bzz36Tfq)quNy1;=-p~i@E)X07Vj(OwD-P$Im_bLwYZ^Sav3G%FJzMH|$I~rda zq7CX2)IXX7D=9`_5ac=B>4rRm5DKN#7=9e%c+Ux1W;ua1zLG#&g4gA|3Yp7sYJ<$$ zU>u@$;r3jXll@4KdNron(Mn)6?SI<}7*5 zb#u}fYXwL2jSy+cq!JQv0*I?8#$NOUO^5%clC$>nqWI^>RjTs{T-AWkzf5SWsCtH@ z%1z#rf(vT&=7K+A)_o1g=nr<;aF-*GkVF%3ECOv^71%rzS&0?-YFMf3>I5!GXa_sgL+<~WI!eVo< zN*&C~?Wn6-4aVX&tqB@Kd*ZLK4~HiI>W~v_sx^P`qopijZ*ltHvX@@pgf|*Lvn6p$ zlKo~&0b=qZeKkta08~g;#;=)z@5B6q*3<`byT0Mz<7LK>D#oyTiu9=B0`Tg*hoC8*uoOoxm4)G$bO2OcYTh)INAHP&AX`)w>7SJB4bzPB|z zc{-z`gNGAo?i+95IqmA-7M-!A%)@ErO_t+}F?t?8Y+sk;bY>cizqG>AqvlY6=SP#E z>81??G-fK!Y^mx{SSQfK8~x5%wm+e@yR2-@JaUsq?^%JaPS-cPw!-%Kwyd54@d)%` z><1JaN2Z3-_o0aFE|sB4-|-h7Sr_rUP|kuO$b*(mHE+?Z0km^GRr)=;q8d-tQO>dh zUd$D@E{&`fL(gm|BWu|oDz13z&44TH|8PPf^`orxAWH{E`{q5ZOmOkCv8XMyqjz6o zR-HcYHdhdN{U-!)W)=|Edjv?7Lf^g~aMUh`cWL&|9sj{~!M?0fnK2mlIJxJLF|J7P zl}Zw6>mx8c#h-mi3N$AC z#`#zI=~*qxf_dZiV}f*ncHXT^5|A2H=gufT^d0rL{>5`KLg0BB!p^O_xl~pgHw&n> z&bTBTS2MJh1^xLQ7W8bb-3U?+_O;6TgPY7g@ks{%R%Pr&?hw!UeKEx(a)p{9m-w0*Yi+0!~`m=sWW65E#kILSR|khv{-Yv#%FVR7rth0z?ZoD$2c%%utftmsB3e`0t+tjL-u(XH z-K9kKb$Bq@Y13#}PUnY00v+|TCFCygGQ@=QQykOf51sI`4fk;cTtWfwV>W1eqd;PUIX+R|tDM*fYdENJiF+4d zYcxKf>nosX%j0CG1w0RQCb(l8tL*3i@-#M{o3E~ zXug3i{1}UemN*43EHv$X9S=)YgY(X7B>UKk+T~~aOdz+2=DKn`!RVb1&JeWC;P#R) zUH~{vpe3vPuJ~U~w)cKrNdTxC^V9Z-;S~wZ#RnOs3$NPv?u|!Lsf8c>VuP(2N&Vvx zuN-VegzWL(n~YN)d9AcqR0l@ad^>6;5mS-G5KfkDiKmeo8aSBQx%TgmsHgB{-cH0_ zE0yVEM^SdWDM(dY18HU}nYwIXbi0MPNE|dhRBf`O`ur|hOT_m_zD_LFh@1^1Z~9Q9 zRr2^4SPlxqrG)>Be?_z_hl_#{Mr|cKXHGy1G|4dAC?GXgI9e&+4Zc<>W4!+b^!?8# zWTa6+0JLD(9-v;cfFQWEW_ZU<%5Ig!ap994mUpznw4Bq{<-I^sh#7Z8{RU|E@=U<( z&(@6zU7Qgzd4U*(M|4=}nS{gn)iq9~Zm|qT4iK>nD=0sRn=9So z@(L%Xv*SxYBnTO$Xm3EpvtI*#1FYJRT2jC?JHIbxK>*h9LhCIPv<-<6Zt;4 zO)>m56yGK9V)9*-mH;TQ<38K%`V-|u6RI7%0L+-Vlg77SyIf{wycq-l&Xt4?A7zj>W;RW9cl9DmM+$N2QRU z_2Q9`*GDz=<4_EOMz`ygs6Lu&gW%u-8;x+AhvT%+C{(qYDFaWYyGw*ZXq!1Co`b>R z{0UVEf%6$H_6mMq4`ePpN;A{Eqf5s5OZ|PRvt>_C=_0u8K2rbE1ggs;7L7h<7Jd+~ z*2EN1g}<`sUb~($-`*Yu_Ufw%lkDK#xPgv#v52dO7VocROKX(pztzld@QZl~yx&MS zbECSk29nlyJjn)Gm-{?Gm>{>Z8btB84n#%0Bz`o;%`(cB@LG?8t9TN5+B5$r5ltEOjb3uIIlw#%17^GiOQlsjN`UzFVWkx9q);l#hyYh$eZRe&XiKmJ+P4?vA5&oxAAUaq zLeee`J)E11aepNm*DkWgt_Sm23LU2X(@ARlzgNGN^vrSgnqpp_fbRGGurkIT>udS^ zDopydDEu=NPj`j^C**Ltks7ufEGi5;(QGKPno#I|y~aO)v8k3=iCC^r8?Qv51Wbu3 zBLKXlLQ(~v8en%gl2)*j3*5eVS47k3@_IxaukoS*5{DGygG3IwQf_6ef3rjUdEX;) zD2v)5(&X{K9`{$X*4+R$1F#rZM}pH8t5sO&kjR+rmmJPV>k!0F>9s&W?(lF1n{umR zs&MJ?$y4;=1mR?RiycND!D&VfFN{ubcLEEY7Hc>*AW=F(T!I8$XPw#!Wv0nC4rbdZ zWVE_ZH=Ojv@g`ah=SlnGEQ$7z^M--~f$|p=S)w2knRMUCsTlnT~h4IQ3V)%|F_o4aA?g!gDz}vGbP)3+PT%w{T18Z zPh`*M#q~ltiMT_M!u5v8yZQAJsTLIdSmZ^n-3gKZl3T@(IYDt})4ojKert3ghgdly zv)^z0*qlRL1$Ocu)N|dm``5hJ$c?_xCM35WEDn8XGAQ15baDbvUe@T`CUGg2%NW-3 zAuKY}r1>wGX9>8t5Jm)BH-8#hXNkQ>%HQfrm{cc|Doq}Ef}y4b%LbFYVRdc;6adKl zxq%@PFs;fYmPAKd|NV)fJ1`R(Vj01RBx0dIbCqQnO+TJA|7xd8P0*J8_uiTB7<(|V zq(^u{5VYsHjT+&!lH1E779DJIDt+_glnn0~dwSS&Iaa)rNy^9qD6O~X>ys$VFFQYU zBL;-SeXdD5tIs=+tBON%p|5Jy2C>&M28Ye4;njY(vRxH_OJXpD1m?+`qi8=#Iny>& zfFJXTDd4a#DjYR>6W2CvLq&|8MLv^d?8=EiNoc(Lxm~Nf*~Jb~Jk@m#!d% zt4Wg;R9)+3a@w(&J&&$7XWW#aC?mRX&lwBaxiu*nMcOPW! z$DmsOWCIe@pD&g+PAbuo;UFcyF@RvhO20-BxdD@E*k#*==Zc?qYT5&DpFW5cNH!eL zMOV&Y56FZv*P%w`222a?P#SPE{z9qhJhVfLbN}5om7Rr7Gf6~g9M#X% zC~d(`H-rF%fvmGObxNw8`@)gi>40+G6#|5Q@>-$8U~F56<+ud}!+^g3$rs?N$1H8t zr{rYRKJp4*I;nEm-w_A3kTrSo`0-A%)g=&cIzKZJWR>ME@iE=xF&0u^NbwLj_Dz`P z-@sc3e}s>BAP)|n!?a!^$%T3uUK4DbkUkWU6zBIC{IqVht4I6{0)&)k1w@o=T@l#; zT2{lsZYw2?S~`r$502!+p=eEl+FP!fT^nIXq&s?cZxfd&!V^psm=ceLT>eq57 z=l`)2A#o>H+_s{Ma6;cyDZsjj1a@}GXLny?nBIATx~`taUee|EP9wEeDPt8*^s4Kh zs{ThNxgpd~af#Y6(X@^yj2%!S#m=Pq?n(em820(Xr=R4c{VaE9X?uPUJ+11?R5)Jo z`dTR~3(0os5*kf<|ClWcPYGskj?X@0DC+vm;ux!mN|=)Xw2YTjuIgq!cB+q9s*Typ zXv($GOK8)$D${O?#Bn_F2mYnxt0HqcP{y-U5Il4{;qdLFRh;M$4^sO_VQ5?I)9 zSS#9(2-GS+sV9UqM7mAa?$gmihEvfvD&zy^A#&w-082%VVZTT_7J;OWsP4K@HEc7@ zg_+pe%Aqsmi>}Q4vrleeZdQP&B#^e=@ctdCc#l#MkQ(->$0a?jle{zLd~BwCHD_KIJdog-VLt zPZKsX9qT!tov(bAzDy`EsMh4`?#8=(RkCaX6Ob_ebw;jFPc|(Wx_4tgd28A>yCN78 z$L}1-|CBcJAS;T`Ya2R4ac_foc~+nufTb(soy}n}>Xs~8vS>}Nfqeh1=vp1Nn9Br2 zzx}{5mQO2BCaYXGEq58f!ZAY}uf-c)tp$a9rh0(GUfKR$1?Cg!6(yMvP^PGB? z!@dp3m~adnw^c(by?DLcIa%GzP?OM?W;+s9#bTZdjE=|?mWa%~PfdewPs!Sb|BA&w z*PBSViB)@Lu5hW#*~iJhr{u`IGF2#AVFp`8QvPUZH`pvZz$SIQ8G}cUJ2sqAUijw# zwQ450gCy^tTFNK6qZpnDLkKs0#T%B${~(*Q5bkJuOCjZq|cdJ#Vw%fqU zDVcMd1V@+j&nfa}XT5T&_`{Cqr7_fWi%mzHKruHC1e{C27}T=!kUBjbOXH6;frW*U5(No)Tqt-FQ9Z6;nx))xrPS)mAtPlrcRgi5l3X z#=yV;W4|SYMP?1)h*?j~n&6r{x{~1shJ5K3HA#kH@QQVWgP~SY?d_&@T^jvt*2vB7 z1#WRpkOhDISlvE;&EiJBL~KXv`{!_i!sy=D*%w?thnk>K*nCf2*W9!>JlH!BLvZS3knB zRrH-3!-p@i`K|xqRIU{clwIVaIy%K+Dd7YJ0gW=Hs{~yt!?e^@ezO4yqjY*LfNOx+ z1Nhc!_WzhpW;5}I*-B34Umlp}SJaFD9%@iEd^;bJ8V`*-G;b*n+vL%R}*uW4-Fww58wwM_<2)j{m_1Xu5@@c0>W@fAK32T{T7MP?6@PDIF{RDEV6e)g` zoMvL($O@L_d*%t&I-nkPPUG&~#Tm*iieGT{f==Hhj`l*$6F5jz0fhsfQVl5FCo<t-G?&}4zo$0bLI z>I~KkVkfZ@TNZH^qhzf2m&AP-u7+3;I=H6=!PdCprgtOKHj?KOcQI7gO41YW5FFccy2aQa)9;RBTTu!nX>9ONfFBFb6Y%RCQDN&p)D{9C2cG0w zAzdj+iAUyoeh8rXUstz0t-|$Wh7bDb)mp?FYSGjyuhTa1{_s0Ro*0iK?iiFgb*l(y zG4O@iId@KSf2(3MBWBn5D&ND(aBqofVb`3$+@-RmGk%`@A?!v_w*~1pL;6}crhQGt z6W`>z9$OMU=fW4*CcYiQS;{L9edcOpYy+3*^u2lxPTlm7D@VeoI@LBiQ39h zAKkyB%g)nfQp7tKx#r=sXv1ounL?g%4Izf4r-K$o!kjuQRURbLVoC5j<`+(zbExxv zIThNJWT+$@-Lh$YV1~H%1l{E2{~#)4FQ2{&x4~ZBV3_-q`V{iEA3L4V6y}f=De@mU zU#kh;b&`5iLgM`pxJGF^?J=$dk{ zg6i`8^%nuZBt$^RX~1FDP8Cn&lC!>^fmwvEs5;C$VSMx{ge;75Tp?28^u51i0t-(3HLvkhFYF<_~}JBAp|z1|2w5(b=Mmq z`*Y3zxMC)VgVySr7UqdRl=w2X26DoQb)3|t8PwD`F^qB$iLy=DWT*x9v;bYrA1iO8 zayT6Nmis&a)Dp7l$d^t?gb?vqc|35~(Y*HKSa@lVxoA*`-s>Z!q<*G}I(wQ;Z?0>w z2@k$B45yn*!Hw)`1h-&GB3UjUKxcN1^)>-(ai8&XhN25?Ytnm=MLQoZT8*m>H!6x) zH$vbOb6-265DfJ>JlYu4ot%RSJ{-ZzcNHWB8OXsA>`JjSiU4#Iup8&MlQo-2oGgLP zVLOQ}7svub4^Q$N7_F|llseUh^aug>{|Ro=+auvtO_y#Fc1vWs2#3)1^YIDZXVMc6PQEiutCp7m&C zZ**Ahw_PZ6YE!plH?$3tQZYjFCe1P486K|<)F;m)yRprVH@!p>1~9O z0zHKvqSR!#!l6T+wF_~3MLKaG`rG(-3bl+=C#Gu9DPC@e5&Vkw{T+kvDs^LlOS6ck z`DG!rrT*il{(#u2b#9OqqY{{zXN+&C(S-e;7(Kw2FV?-$4hN3vJuF?}F#BeEVM(y3 z0}ah6h0>;YE;0g< z`xyefk56bTi!V0FR7TZdAdJs#s5UqG_p$Hn0lbt0ykU+@FpS;O)*M$lk1nLc#G}_h z=>9D_qk~a(!GB(8e#kNy_k~7VvQhb~MIRVJQN*8fCUA{ooh}!w8sz)yr97+gwt{t2 z4URQ_ZFlnEm_OuZ?E%}M0HTW6ZY_nZ|2RH_KXQ+2m5k--*yYNu>}e-;R%!-%C?XQ+gEnaK?JbYSmC`NZGfy|KF zI|AuZZou)eQm89^TgZl+B(rfDuC%sQxk{qnQzovWkXovR(6}YILDkWyh}U_9tSH;{ zPdbP}@A%SLQ$M|NY?U~7AX55?0uB{A4x6U<`8q_lbiRI(czArW_0-zIAN|Edrg9(i zjd;>z?xo{DhM5LRs-?}Fq!suIwHfCECT5dNPK-Rk@6Bcpx`Q+p!BZs~iY##8)VK0P zcxOU0fXkT0ENdqCP6)3!f%PNn_loJ0bx|2rXEx|lo3oTl8s&nAqztb2^u*IsAnG5y zZ&YwWfV-CoNP=CUajAmp%GATCM3H>8-Za~STNrLgAhODzjTR;v`(4m9UbK`lDEo&~ zpg2i#*RW$9s5hx_zQ46VmFFoZMMU#{*iE&*SKOjNt#DjpOp3G{zb|2#b_i5??AdRr zAPUqg7bAU6dU)??y`hq)FPBzB5pgZ&10rUV6QGw>eG?5MB#D4@pm0=Mi&yYk;EJ<* z@)JGPr?FTp5Ar5$3OHc~hxn$`p3KmfHFA3&KfHu*Ota&8-M-sUP#OR$N(MunVuqAh z0>|~Qltt&Uku2w*vdS9t%6-MYup=kO>IJfl(P<6Jm z%QSJ5lJ8Z7dxD9LBEfXtY#b5@!GZ&@5U)|<`b`20MA`Lz z3G?u~sN8zpar>Kb*yo23O5!>4Bx^|2^H{TYVZ1TKpgp^K4 zvhZ9FqW(02%+Iz>P3WIEbnPwtWaGeb`s?xVq1@FAbuoiuPPN%Km1WZ8K{;BqmIMvx z-#;IzC9lkuIRWT^EqKE2LZmwiBGw|*fCQ}m(%hAPmjZvYu7rO5(i$_bwNTvu%S$8@ zcuj|+kb^RCNM}8(KvsyhbndS%7?$d+QF~8LWP!JPCTM@TE;L`^FG5vVNR7I%zNvnx zIkQdwGUz^+1r%JT(wA75Z$ZG0lm?v?na>HM5`G_rbCKr;Koh(kx?@>ZBt+r3?QQ)cd zx#A{5*}+Niu>n{Ap)qf+0RLFC-jDGJ33I$s`7wybmfPNd;bv)hrz2YmIsSG&HjEv1 zFZ3h1b-dg+ItqZZ5=lGa$Qbhg@Oo{Bx;M61te!-1NJv>yH8~^^N5pG{C@s>#{k~(TIVH2;ecR?Xw@c0POh&8j*A&k-~X_wwB zb(_er{JrT=32T9cmX^ji-k&e@UET5>*6{*Qu#pUx+aBryEBC^x4&CRkXI7#4m;L3< zlVv=(o&4Nk_DnSK6uq7UcvVTY_`8w8xS%2%06KITLA4HE6o0euk;;edIv+-A@gFVfP%41-lF`2{ zy6CCQH%S;>wD~i-4zxaARagidLDeoq>)E%~&gKFt0phW*3`QrTy$Rg8t@2QA%+cfO z)T9yk``9lAGzmT|hIT&y4&ET=9D*-(419!E=H>ZaU{0TxN?ekwS2nb?K~4oHlE;{^ z-DsjTZt=C4H{WI1W=8PlALAH4^zEr-hC4e)awRfmS}=N8pUHNo0n?CY&-iu6fw`t3 zeF2ahb}h)jl)r!Yh5?IC?(aA{8mxW?MilM#X@iYW_edDG`TL(#Yod7?*f!bG7t9zL z%Xpr`H5O9~_w8Sg6-wCE2jMHv{`df*<5v^R?yIL+j)d&qPetSm|M^U zSf~iv*GB@;2^F-1(R#DrBnH;!)@2qK;A;i)#7gl}-ZMC(++aq07PInW3Z>m)60$?;ms6n5^ zNmn!p96e{S<50v&AbRsVr4iA%e=y4ve<{$(vL{dtCdwY5+%E%argIp|N});zER{_z z2}rVA>;}WR7)!yDuFS!YM?)V!yvgof;1dXbQwmPrrqesVmvt zg1)%g9w(Om+9AkPZcB$MTL3{liJ`JUmIiwzt8aXkFwOaJ^*1nrH;4JR#sI#s2}aw{ zl2t03%955PVB|%eukwOaupp)c{|@)CF^3~?00rZSDFM7z82YbJoWfG;%0e8I5}FUf zL1$y2qP|LvSptSW+fgShF@sGLqge72z?c8^fsiF{1WoSYc;{B6uodoaJA!HY>p!&7 zfc7b#k?T2?+mg98mK{_B*2;%UbVNEIypi2IJ`1=d8hKv9L5pOOZNxnAL=P%7#W%RA|ENRP++cU@Fv zdaEUz>7BAHXL}2&aI-*n*28Yh?hB`-tMT((l|H=+t&?P23NQiQ%r)uHUAh&d(6)$}K=#v-ThxA-wxx|4t zkqi-B(xajn5O^HB*5|(+t;tI)VT*ZWlJ1G?jT$k(j#fGawGE^j>!Yn6H4~L=wD=8LM^g5xg!^9@z8mlqoB*eOMdYX&GSOV^DoQ&+1^pLSy=}^)-Cj?J&fO zN;iDyp$MTvxY&a?fq;Lj3ntswH8lr9aSiM_sl0JYH7ckd@-EZAlFJs@1$hYs%@$TE zc7$BzOb~xl$)%w{hM7hN0wH9O_;*Aba6+%cK zJ(i5BoFz@fmnUG7k0!z0ibc8%iy9zGhfnlhWZ3*^wM)AlZ6WF;wHFZqxS=2ryX_z< zdmnxv3n+8vc9sw5&%rSpyO;u$hH>kwAEdoE0AyDx-0&T=u!H3KbHvBNLe4n{mh+8Y z$&1UCYRq7)pu8g2Vq8sKp5Dq7#D0Z#ydZ9fLjug4#SNDQn^9gwg{+50k>Izb5-uIN zyfYDY^Ko9sWiov}3N$Kw*+K3vkD7oVy@<>-z@9?velP#WGs}WF{Jfsz+Niu=O`|Dw zi6$0xf!Ew9H*8{d$J(_TdatQaaHq&;-l;y!y9VY%FKAI1$SUVuBcZ`3NS>l z7FzZ`&<1%d*}R(U9qRiM52V+RYM735Bad>|E|>-z{C&2JEGyNaqd$nh+v-viq(XP9 zwY+rSHiKKOSxu!7g7*wQ{9QqY>5~G^8b#v45SoDiTWC+cxXCRMU5Z11eL!A}{Ahqa zUbq!gMH24sxQ0;jyBnO(TNZ>YRRM9d}5t@q$2{>-V_!IvDbIt{XYAv)yZA#i zjrs*EShr$>YMpav`34ug$DY`!eN)>7fY}6iVafm~BWMuuo}II8m3fj}f{nBX_qg_c zhG=VI}t!ljyudvxpad$ zGLILm{qRTE?(yz-!nkDK#bjz3W}5JQpJ9Wx700+q9kB^ahUf!*21E(@Ed4*D;K}jT z$r2pTtSpD5Q1~jq#Krs~<#W=6{g1}Z7a^Hez9QkEhGQ1t`U85XL@)*%v1}DLng?2M z#+bed`Qlucn^WJBKC+F&U0Jl(N@Nwc%xTfT>v4)Ht1Tt$S+$RnTc!ZEoBE?(&0#{{ zb}TO`9~cCF8D2BjL}CL1`nU0D1I^~4*wP>)@<_;z-;F{-+WhgO$F=`0;Y?Uv}Nw*D( z&@jdR3o%^I-sWCFdB&(|EF39Sb`n3xPN${1u_d&5qV=r2ynh=+xzG$#L)mXEAQMy-;g*{?if z@F^^7g;G>9vS;jTZe*bx&kMMkxO9-k>Bvh0u_qhL`Syl50{gzKL9M1Ht+V((Oh|U) zGESM^Dj=+ZC%fgXG`R~aDs5G9h_UwUt%`}X?GiQg3~gDPit{+Tox?>4 zFK#|g_FIg(l!yr~YB=KtPzr>7ohYp)^Q)&cuasCc@vU-WxM)+2yC>_!puuZ!>4QB$ ze6sSr2~oqBJ7F!=>BtifMzqi0^A-%x0uxwatp zzBUb^vS+!G_$fOhCmzZtpRU(e&2Q*yXY5H#0h3>@y8zejOpf|!8wv&4NF3O17HPP7 zK8kOR`Iyc-xK&}PHwAycw;6>IF|Shz%e&FmVMU~`z1@o1@#()bz#t=V?+u#da+2N4En}fJpXdx_%?#nin+e1%g7k zce5z5=>u1k8le3lkJ^Lt+~%SujdpoZjZr8i(uh5J*_wjXXF(d(%8}s6~6pv?2XC<~_ZmI81pl`{t{ukU@a zFg6pUR-*rk0jfyzfsSNUz4OWrB*g(-Gh2TJEefG9s%4LLHSDsbgz`XYRz6x^^_DBd zNh8Ozk%E7bsw}7Fql>lZ0`y#B=QxDz@ja|r!eW+>oFSt~3ZV-&S(s1)*@h{HE^0kU zzGCH!n++3EFcOUhx8Kyq%cdY)<}jEa+qLd%akVdLBiOh99Xh*@Prl2wvCuWYfe5-lDl?wgt0r2`ZS@Kh(mh($+uih$e9r z+Yqa%UN>&TqLaA459xsAG%4TfxIkjJlx>cv2mUmuj?o}MR$h>rr^QXrp>tzz6*oW# zU8?|Y8;O}2PtpHo5cib|KAf!n2Q_O=Cy1UR7MZz|YJI-1CB`-1ssgq>Y;Ai7Yjv$V z$G;fOF(6#skl1B!FxHuy-oQ?v4J$igG5*=3OKKyyS#F^nm*!)%p4b8CPdDHMrwI6s zTO$rr(a5TRCxknL2sZ!cYVdWQ{Zg%Vs39^>#t<~hT37*A#?6t>1E!_1Y?kxB89T67Lex;>A3 zUKn!{k~`DOjOQavCW&V#4CRL$sg0w60M>;2nNS-+(AVijU(Im(Pl^;?n7`Mp5eyd{rsIbjsbOXA0@W+!O3zY1GtRl7{1 zPA@yH|J4N%B9eBFqKPNSTtsJ;)L&f%d0w`-J&v$8H#9))QNcd8ti=B%bb{>q7l#Hz z5=phEyNevYn0JrM6Cm_qPM$>xTH>+TwQ-2PSGY%RfH~|5I*8Pcu%jY^v_+J85BOhQ986O23tOqr z8$`RR<^|N&QPWcvLxgAJj4gg0G>TmoT%_Bk#<;yWTy#|$TKD4T=6F$h;$nS+UaILJ zqr4mm?Ucbv!u`31Qhee0&h#xa=k+uUT<^C{I3PcB=uxeWM3G0G}w*VoNQzI)4}>$#7* ziS+bJz-Dp4CPCpqQfayG6XlLLoSoy3nlqj}+AzGZX8TnO^Q-5##r*}{zY4X#Mlj3O z2z&ngW<25$C?KUAny;uZUt%&)?8`Jo(R%0Ybln|6f2MeTp#NNJ?f;KV2ec*nos@QH|U0SKlbN27Ed?~#C$+$Dv&+p7wOk}j=rQo&o}Mb;`iGYF*y`_L)#_rQ z@`id7=l{Lduw0;o+EvbZGgY*;(tV%1G40zikUDCH$s1SwIf9@GZ~sWtY@*#{4+HG4 zifr;&XDoE)7y+Fs7x}Lp1Yj5qWv~+1|xV>@N+&$*swu z%%;UjW1y>yxU;B9%!xm0LB&>p1GFEsF(nK5;q2R1r~F_cGZsl%mOKm6t%?~K-%$VB z%&o&i5dQMU=A+khF?$D)Egp*i9oI}F{YxY<`;(<%Jvt~XPtY4G8GMr+x$>*>hFKzJ z#+xfwKF?|;-OW7Or?3DJ_uA$v`?NL=YKvIkdg;N14*M3Y9k0&W zGYcSS_L-1~(|#W4+gh~@7@PRL6SK6j*u{`SN9<*&^ zjkOIP?t)S%gaJ%qA*gvOs4&w;>EK3S-gwxnA@SwlT2|KEy)Zq=KiqH5;q9q{BTVZf z>Y)DTpJod`asDq2B;FG|tj4I%zfF>0UvsQ`Wue&wjt=R&sd@yrUe=~(>2aWgDpRPC zw>uPmL;86n?Ryx=EZ*Vou8wN6)NO@^(|xLx3Jj6YB#jfCdszBnCK7G4Rrs$VETC&7fn z6-dfCgeN?n`i@e?AtD<-xxL4b6NjwBB)Q4kf5$-3 zCFmvxJdY$Ywd11G;<*o7NQ%DRvjWnNW+iS=ysqEHX=oIemPfc~yFCv7Ih zPnRxwC40Ll67We-bJbEsM1$Fo=?^pzK6uhqJvD4x)9M^l{I6&wa@_gcob$kc%#kCE z#YQg=Z#sH;f(UC`h0K-gtWLAQqf`{qg$8Qcf13JsyY6x9HFwWdVG0pd;rq4n-HXnu z2LdyzH-VpaJ=iZAg-CAL?=Ce;7dv+jEpNJznew@1k4y~FA4n$l92q>ZT|(}_2M}$T zd#)eNj)R@Q$=x>X;wZeG9~F<`&I0p~RVUB!qhw|I_XilqX%IRg=GYM9}rCFVPPchE;MIY$9l$v?I3*{_&W^cQ(|<6u2*4yn+K11fE8b83Q{SqO>R3d zKyDh7n&+ljX2>xr#RyPtyK-9= zG_G&BoivZNoFH7CzJvt~);N7-M4HGxi&7RW)Ww^ZM;>EO-x2Cw$}oDMt5|sH-kL)Y z6)w&gS=mrcR3jWY-3{hz+cAF(|6~CgHpWsaBr&)X5KfsOfN7^ULSOVbdnp1Y{HWyQ z?o$tZY#Nmio+2TH$l@rafDLGVsrx_zoYD@F&h-X%*lh=|HZa4lL_>AHITP6%kEbw!@dHt;$Cx z;S~rGBxFv8HT;zkYffl;USk5iC~HH~+W|>)p{$2$CzTb#dv5W%PG*w|fJPp%>qQPM ze#5!(Dk-sLarRj}LAWDy-u_s9CJ z@NU8I=bswxnC}YPZK;aTh^|gGXWT`ibKdT!#2?>NSi1ANbY^*m4Jjj)@6CsMML#06^q*x119HURnQi8PO_Oh|RA zDMkK3K+~K?tbuCW7TSJW_sGmTPsacb#cs`Po~FtM-k=JZyAsFRfAT=~wcWWuU2Dm# zT11|1)?$ZD=(aV}GYnj&-#qo4Z5ALE{%aQw6#ai;Vr4C8s^%&R$o;!$E3ALerl(pyO3}Y#1S9C%H;!*9_z|zUqfU$m)Xq;W6DTp&cyn zF7tSQ{7xir=j2NX^&)iob|Gz}&D){eVY=AcG8w6(Hw_c(TvG2IKT9|WdN`1wXr|=m zfe^K@tHo2br(D$5*BQ>XOB(zl7fi2I!W4#1h_KE>eR#Gsh6>+-QgjDuKe-7Vz9Ul^ zzDVgflJZ>@5Kc&+LmSV$t`{)g;qBZDy)YJ8WJB8PQUMN1%h9XU_4lu*V|Kdp)}CS+ zO!JOQgto##B({O8o)mv}6`K%yalESB>a$c}(NSYJ2;i=Jj)e;b{-q8E?Y@mCPbaiBIa22 zi*KcFTinCqHq@}{XAzoOkO%gNa#uovdRL+s-IwEKpx+~5(2R9Xs5YqiwCLoC%`aAj zmTmO$bZGca`%*mJP0h)SpO(@>ERLE$Ym<8!J3O^rpMJ+hAIKQykt^iFv?Nz7TWo zO28N|fXv>_R0DNZC0!>WXDQtJKBMLw`hM{jA{*&a*+L&_AHy6$fJTBh6K_L`6jF?Ez2R`uv2m z8QjeeG>A^I?7;k5{>#PdD&$Y}$?n}V1rm}_fEAG)VQLnDTuP^&L;kbAS)JlOcM|Hm zl@Vrfa1;9e#XjO1GMq}UiuV5-gv|G_CR*ipWK@aF^_$^4$@)}M4DcZuzEDFaP$uRg zV@d4(vs2f|D1A=%#D%Sp+#~j*DMrVOn6()^^}~k4F0y1<;7T0y_cwab7k}4%b>UBx z#m)xfDzxmY)lm0GOJNafcbNW)o<%>Xqi=O{M=vfvG5%W;we*gxe&M4GvLC%igLQ?J zzOK)s%uwov8|SGdXaUD;hMG(@zMLyO{R!oT!%3G8Fl%vgze8eG8gtK0TL8${XdMRr zr8{m+x8$cgAmyWr;hT{C6yy`7YXi!+$=m*3;c5pFgbiUTdwuXW28Eka2mD2)rytMC zXG}}o6*`SA09yS7mb6`oKyTGoX3phe-{JT#Wgl^La|J>n zkDo0Fko-C#z4-geUC*54c64NEHsck13Zypu}SRD`_bPOV&4TQOI4GKt z4!YXFFDMVhLDkg0JRz=#tU`ATgzZH0LI_GNL0GD0RmL1EGgOGSSb%r_L9Q|Ib3Q%C zElG)+0%DVy*y#LPzGHD~hte|{R+u#VY(p(-OY&2m+V$2~!wsX|wOx{*Xl#(n1}#=7 zi2U!w9n;ijrK#E>oXs95t#WMn$Oi{Ds&{O`4qIK>OdBwDNvVSt%Rk0|%i9mL$=YNi z-sU59$$ofB0s6BXR+^>S|DYyglVN`Z#%Mtn->Gj7i$FsiNgIWcv?r5@D0By&vF)8= z+!ybe8HdQAcbA!!_vyPkDrYu#wq6x2HOThPR1dF;sx8ucbyKWKP@W#uHQ;RQbGR@2 zhAgw`^dYIfM+qj~@CY8~<|cVpfY$FV&!fAMk;DB}z7F4_8`_%M0l7vN?0{I003Kc1 z@q}$9L!PHXOS66nEJjs}mOH>cJ7VR!jiRg&X}cvFY#u5F4FgEr5>m2$E4BO*St5?J zo|*P~|9*Sowf-|Q3Xf3X8F~dfqB-fIzIbkUGHePR9la#Qk~*NXBwQglhkBaFIk^*w z__K?XLJp8uUI-6Mi(i5W4+eV?@lX=L+!cpHN`lSiWrRZk)C_UZulqg_h$X`w^5EKi zws}|_%q^<7VlE}6{9oFzH$$>Ry_fVZbd|PvB|im3fnZ)CjtSGXTNx2tU}P07BoRMO zMIP13suw3*tv;{yOywZIDpT=Bw;PYGm_ENHT;#bw;m${YaS+S1#VuwZpo0o&|Fo7c z`p_I-3?1zyzfWvFVE3sC4Yx*+?i_`4B8k&I{!lAZCO|W1jHxRWI!3R zlKHS44vX(AFN zV^w91LgY(lLyuBHr8Sz~)21Ie-)ppf6F8%FUW?cnCWB~ki{R$0K%6^iDbVfsKH2m`r(jHIU#4ny4n6J`gP=Zy!i;FjQi{9yr z!~P16WQT+sk)XR*2&^ae9I(N)pU}5@jSQCg72I3?bmX}Cu(YQka&_gN-jQ;K$B(4x zT9&N3YD|pvVHy0hmm(n7?4iTdNImL$4Z1`^D8$U;&`|NSi2a@ z3+gtH_$AAWDla9G_k}@>egT|m`^4GoSIV8X)|i`cFo-Y5nh07h!}cazz1jyCnY|~o zT!+;`CE;PdgFA#b8Ps8h$G=?u4zh<7&89I+Cj~}C`4W}167Dj+g1ch-+fTs=<|OKC z1pn(S%-b{^u5#3q7cVUl!H!p?_==2<>vKFfln3)c!c@t;J^)12RyVL^RMD2 z3y$A^bnzdtWYnAF5tgUre65sA5W%6Ds6KuUPe0mFe+%eU7Y*qBqb}QG75HVw7IiO+ zCFd+hbPT{i%=r2ChN~XA9GxWfZtfYYQI=RCzm%_Em<)wP?>TzWOd%6;8_I9|6i(W*s z;~!s6LGd2?32PPzW=^BS_Bo(sl#a?wOE+XvusERpBXO=VAQ(X}u0~E3 z6I{g~`ARF&XG1gNBh`_^s*%bR*~J7MBq9WMkcm+!&LSWh9RN|iH4-S2#%un5QELq` zxsM9Lgk|gi-aWX*G(~Fxp1~12yY~Tck&M15)Fkunh=xPN(+OL4p+XYQm(2aIdwup( zSY2Rd(&CHRAsKiD3-Bp7EZ1#WWCV;hvZqdx^a8^>CxOnrUvj*ljmOAwMvru|>X21t zqnPfWBkGrsyrjucGzk}G>PXTS)*I!>R8#*Yl|;F?%)yBNvOum5!5n*?zp^>dJ+QB< zd~*TdwUKc7$TZ~2Q6nsBJ5MOgpP>gF83YypYnNx8ggD| z>`)sJ6)w&Si$>Ir@#M|WLxkM&+ugZ(bQST7Kzxpk=*d?LgIU2%9RV zlyTj2f%JJa51Ezc3FElsaO(Mgv$AAslS|YAh3_Yv|FmbmfbwnN^{74slAZ4!6${+5k^V3R0(IM<64gR zYf`1slm_o?S8_Kl%Z10Z$Aoh4!)w3TQ0j zVlF4vG%06%mW2hhO_EDqwx9cZ~F}weyy*JM4EKV#?fPdyEuK%UWgB|+2JXZOq&;2IANbS$tB7>lD=A!2^RrkYa& zoSFDG!3&AybSuXrbF%V18(dN?vwRYpVtJk=Cl0c$g#1sYD>5mEV`r=Q>P3eS;8mk; zdq1kY7%7K#)tUF7to-xK)b^{y00=;db@7{5Qgy`PlzswnXAdbdms=or5OADj>{brt zIT6G=uOYDy{AkNCm3r638lYHsLi8=awp0Ub0hGa2jU5JFs)ST}u&SHq zcd9_f9#YSR8!L8tw-viN)*zi>U`w@CD48%u-vA*y`#SnTHbsd$-Y2Rc4l z9nCdo#BHyy$7$!$$~`vY^}At^!SG_|p3pd5Nr5Nuvtqf5O14&qV~`VG@<~0o0yAyO zuXrh~P`Ss_07<3yv`ZfxbC=NaB0<3m=$;xa_b)4eK%Is$Fkg4x&i^!WeGNzio5wD{ z)b`<7O8==~Kd{7VI=RGXVUxSUlk$o49Zbv+oXsqfvc%JSN%+nXDOLrzQv<%e&Ta+_ zYifp~EMJ5cnDgw9MK(rBdhcTIWN^aDT-aV}d5)LnK`uG71{wdthv3r2{IM!tvxXZ~ z30`!9wv!dM|6H`JaoI*3MK2>MZ7Q>^odCBTB+Jgd0*U2NFQc)A=l{T!AP>COR8@ic zhrv;x=xTntJN0Pb4GEWXS+2CsDhmqkd)LHs#>O*)nN`9Kj5m4xzX;bF8OG#55>Y47^L!6WVO%xq$R> zTY8k6`~RZKRL#SiUnLeYzBIpYn(0sI(y=yf3_H^6>zAXCQzA#3x>($Nat`ePg=zBX z4u{e!*!#a|M?GLwtEr->$wg-%)xW&>x4||OkkQH~r#Dg~j$8v}2O{@@J&l-bdX4ns zMlk7Pn_I2SC`4~bR8vY5`qYHs%dPh_mSx^;QZpEh*@I`e6p9!Mpze9&5|1~u_Plqx34JY%?wK#F0bllC zkO)-}?>r?&_gStp9e2WSmjy6Jg>Ol6g@?}3(W;l47VQD^b=8&!1M{l2*Pi8z#k-Hl z0tPBkIlKrxT#A_^))6P>N4Fp6ubtkWoa5ph!&a(LX2oKCN_E>x;F+H)9H*&arUNz{ zoeS*JAsrJ!Z`X>#1>YYvf+4+U?@3BxAS zW{E+XvV3FtNjy6vY-_QuDvs2rU&i191Kk|q;g3K7iMFyrD~YqfXcoWHW|{^&6_q7< zlpbu2$ROch6gCu9S;BHB5j+3>Mb55X9TrWV?WRs`%^DHN+zjAa&Sy3^d3{4W)yZZL zb98;h5m;sN6$`nh$ug|jUj6z7u21T=)b`2hC6OmR#znP45u-+T#yny({4|lDDMb(# z2U3plTr+;O3O35NcN-T)-iEV>qMSGkBpb3O>6Mg)Q1a7<6`7Vv0m?g?^z-!VBHzdIb;LX;vAz(y*MF%@g5x;}%ZN+Hk_298Pq>Jvh zzneN(9F@it9KNfVOGz>9;A&U+E)dX^C7yotzF^44r!6UN`s2W{c39b(_>fOIlZBUuSw9YI8a>6M7ZodUc1 zoik|lsDbBNfe=}_F;+_ocM@|uMxelxjjQg#ncbSlP2b)M(tVCn!X^a9@r9Ot2HB~ zHMpf-GU4LAtROK7WhB>3hsG@z?a+%bMZ`*`%V81`-dqu*!Kb|y?0z7qEm#NUAsZ@O zr7TF6T)|NEdf5*mBU!WeK{Cn1{q%jO)g5-V*B+oUbi21i{h9voM$4;m)p!bxLLd5V zMsSns|94r_nhPkW(9pimrP)*n!JWCV+m*)t6Y&4q`(3$BHF&hf228{!$;?*GufyPn zysKGmUWtrr$rt4IqX(bMfs%bfNDhVC@YBeg7gh)}&;q|co%+)0u+B_*ITkw!{{ZgQ zR(=lSI04G{$w})p4=PD7SlCBR^0W+Yfe~A76UC~zGF_s4e1`7tbx3tbXqk(Man=E= zFuWL7-5{;UZ<4O2{y-s@&#WqcApHHaO}v#= z3)P1ul~9;pG}Z3*7ryWBcy5=COL2p69k9lb+m{AJpj}}XsE9d)8A_RcE&o(Qa8y#U zU*R`G;b3FbX5w3h9uyq3!m=VGVTHtew(EA$*wYG`VP;Gb6c!wQtU|(LXEpw<)5#hz z6udpKFiSjjndIx%k$pPN`md$ie?{!7(BAo!fzcwT$HOPOi|`WcSM_jr>azN{9hO3I z&NqW6O-?!#Cje%Nch3!N=l~(SbzeR~F@tT1ZYq_3avH79zx4yZ02%*nknQ6E{kavE zy8SorucN^U!t=|LH(FY?-l0VYYiO!QF_8V2MOwX)pXfkvrU&Sb5F3OE9MzD*hAE7+ zH@5YYoNfrR^&)5}8M&w*N&Zi0!IkcxXL<@EbqgvGqBQ_`Vm}yd^(y$uc{J2YQ%5nv z*x|1z9~<%X$tLehoYsUeR(GOUXC;^k?AI@374d$dss;f3_;<qdb7DU8p_laEWP)WPtKS(JLZ88FEiiwa zi!|XPiVEgdN_0Z4`MW4kJOSiVoP4Sm^rtZ5;a2r6%37hB*k7T&=&yvxfz+Gk%Cv^G z#UoyAjPI^im)lF6XRP_96=z)bs#;y_y)B^cUFaGTA`g@3f|h_eptlsz)cZ;1-`*8|J{he3E#ooiMQ@52>0 zFyuZM77Q>~!1>7vE98~EGO}UYN^r(4(=L(`){Ow<4LB2UWtm zP{ji_kh)id1aBg<(&Ss94UwzRd^2pqj5UH?D2<$&9#1!^DLNF9y*JFa%ju* z76cqJAPypbBZCQb?iEl+7Kw=yiT5lGKZLHdYVQQ4d-4IH_oa#jbvGjnfq{112p%S~ zC-5iTKmK}TDD5o&Fl71e+U5#--6UFEWFW@T6cxO7>N{?`NZq%^IhYftV9*zW08iH} zv~>f3(;N3aO?q~=dFm?0hYH28$D_xhdtAjR9U-3|SOF@a)^2$>d4=JM{JcP$qKvt%XJ0 zfV#n~RVS!B0zbWLud=n@o9O)C|67a%kY17xDnRfxR2ubIX(TT=iJ_ufG|UKq`}73D zMHceAQCw%=M!8nZBQpwTrmG^jc#q_ep(nce&ajaPjCLv#P(l>(M_5S{|1TH)W#A5) zHFTnAhWuTEfpAJS%0E?F6wqS=fA(cpg#^YZ89e_ga;TbXtGsn%;@+0I#b?EQF`%Dt zNu=FuMYru9TffU2Lf|Zr#WP38QSKcqAEANNK!5k3V`?NtHOF)+fV90N_Dw8ZP$xp_lm6ufNmp8(Ap9JBJF~-IELLTXO}#Ti zyPwMq4VUKSHRbe+knO+=tLY=^5O8Z*_dNqzI!?gElobs$qO=ix-aIUVjFMv6xSV)Kx_N9 z&}Wz-4mybW%h5xftVtQn{!Av?crFWb5+fL!L^6llcW2k1T@AZ9EJSwS0y*6CjX6!h z%l-~mpDHQzR-xlZ)@P1Jkya!X$@v@bz~&L-sy71n$C2O8thCe_=&di_$}Oqq7Q+e~LFhPJWN3 ze&0aLN;6=l5r9cwbUj~AI1akI&cHx7bU~!2qBgV*Gk3tH)9hL{hlaFgCK7&Xz-CMf z6Uxu?PndGB8ZdZGuVO0nfsa@)SC zXT_OHRQ%F^mt7)tg~iy)R}!qb0RZ+r$DlF3+hwnxF%e5%O{d{E9f$s9)+!kjl%YF< zbrs4meOKl@Nf?C02NqRqZlq%#^^|)FnSSr5PLc^`dmx5lKNM)$$I2q?>n2MB(+LxGq3{n!bLFLJezWy z>{hu0rSh@TRb|qG)`IG1P)7~Td<&|1QRKvr6!#cC`t`y|sa+Cub|m_x4`-&2#1oKe z>(-r6z4-=(4G@HSzLU~tR)h}b(W1&Yh9m%qO~PQDX!Mt%Nndfddyz_=`h_VQr>os7 z*{-2VIN-BApcj!)#>Yp&wZvj&KrkY|k8}CG?ocyc=t#;re5^LZrNGa)6LA9*w8G|c znqiJW6|VVD3I45U=#~FU{Db$pN6@Rd8Q>rRXt^v$18Ew;BfGmqA$q*d2{0RzL%eh- zz&oiKP#2HMaZnL!!7ehS;g}{%OCn^HbMAX3!#Dvt+mEoaW_%rV0NC*dZV`Uge*_cI z7n;RjgN{rf)TsjIf5~^;G`*{@$J3MzYW7zVceC>c=n#HQ@Fg=XyY2VpbJG&=hoA8X zdqrNr2$g10`V!fOVsj>mY|i~A=#!IZ$u}D3F76LU2!3LM*{QRCA8qo;Sj^` zmncIajuec2Y*9GT#m;$RI1RH2oh$|hw-<$T(a04-oSYiw;JsO(phQQmbY@N{3sv*` zn;yqfnUaulGc%*s>`Uu!fA01@`wTfN=%(?+wyCnENmKvGtcZ-9ZK!@v>O1&6{R`M$9+X6nFk7jC`ePZ zwqt@)!V$}HNsPRv4B0sH7H;sZTNKNqWVKpvOb<`hBLQDuvZN|Icue@JQg2u&~O zTy$pwN+D)ncC{2G=CDFKco$jziP zhLE;qUyH_o2JbSX)8Je|*Jr9!8?xM$KN4ybS1Ajn()yLts8|8WIw>?45qCgini_Uq zlfTDyYkX5d@~Y+3@B&2DjfedK50t>t_9&vNOHwZ+E4Lr&Dwg*)9A1k@k-bmMIr5-F znRQu5^R{d;O2?-XmYd?19{lMlXUzc0Tz~w5f$xD<}mr&{}`Y0X?^nL zvH^}t-JRJoTRp>mndxDA89kBzaxZ+N)g~H}ZB7SuGrIbJlZy|z&uTj3JC%gaXt<(u)4=2lg;b!NXzJ<@W85f-# zLdBTw-c4hyN|?->HMmDH2gDtWRT)TLkTooMj>^Y~a;4Dm({16CYpeq%@p{2p;7%5d7Z z(&1B6*>VXEr*5dX!nR-S4F#-CbPU|IM@k{%S4*w7v=11ixa11*{m+aF>#*xVN|Vm& zzLZrgFK6JCAAgnWQVk;uV3jd|6$rv_`at6nk+jGn0EtOLw57i>(EJb-Pdqa0lGzwa zVClNqXVC;h{k|qOwpXC(7c>OOv*woe*`aY7+EVwaSh`$N{-!6P#*BvBHDHaBApXt} zl};~pY5tmBF}`3Ie7RR3gXgig ztjgc1pWXtgwXwEorR4dEHT)C`o%=Nwl5N#(R;+@NQu?(m6DrLop6;v4B>0lG8~$;^RQAQF7yJddsVJ z7i%J{XI9nq!7@*Mis#x#f>Hro?*uaO2ifod%_uqf*;wjXWl12Me3UN|rut8UJWa?9 z(LAc{c?9nR-3Zj!ij)OTi-OrC3GwcgiS|H`Ndb!{Lq&>pmJRb_H|8bOn1@8T#=$&f47b-9ow~e~pH_WPainYRLbWrfEC^uGq`BHU3=7CrPIr!c zfziS!?Zv3Hf~t6Yp>FkQiIapUN>J)SJPG5az%HCLxud4U-pl-4Z1KO$IZ1WaG)Tq>zQ7 z%kp(UyEas^Q_3E=!YJX&ZlyCqVt8^rs`Z}{`dzDH0%82s=51sDZHAiR?Frevph7M& zNvfHDhGTB!b^a9%#@lnne>Oa!9z!)WOTswPZaU1vw;!N4W8izk7cRz5y;##Sf5Roh zs8WG{(}f&X!@3vf>ztVFfCeVwA8FEkn_Yo3TN6s3u^@!GBb4H@KD z!DY;O@cS$3acK=tdouN)-k3rTHk|v9`MZ-+=)nRttEWL1`-2$LZiPn{&vOi^^rsKe z#98KBsQAKVWI;$#%Q>L+SBbJ#x5VS8T6k2iHJgbrnDM;n?#hF)zXR*f@@U=RSj4Gq zRWHL``;2^R(OT${=9p^3ali(DI3&MFMaE@rg7Pq29`HyBPaPEbG~$!R#dGGkbO2=D zJ-`|jZi8s61CEnc540~mJ(siz|A#pE{aY{O4iLi;osi*D2+WX^jIlfI?3Vd90(A7+s`3xhAHpA8E#y`ES=`1W z)!5dtbTgM~}}u4)J>DIRCN@E$U>1QgfF^EdmcUZfp^ATrpQ& zaDT@EMv{{oi92}U`}qeV9~~3FSQC&yqjDzmwu4P=pc&y%SrGo(bs+WT_@%$5ABk%P zD_qb$$^LA}oxE@n_< zr3pmYLLw#hy+Y4j-vB_%M!5GVu3N77Dmk<0BqwO?f<>MSx1R$~#d2Fib(B_A^2T?4 z{Qi)^dc727vQvhSSV+}6HcA%4j+_aBCFz9Lcd{mW{?fE&Dv1IXWdd-R<3FncNbmT- zd-U^LrENTNoy)w{QU@6U2=&5XmlUR0WRathVH6xz7+0YLCP-sx7;KwxiNPngxlfY7 z?4N;nC@JUA`a}QL4=7-G7;{GQ6r4pp^JzBk@Br*P0gdi5ilUAebSe;Z`&XU(IV6re zu6N5>kFtl)K`j$>+;~&szfC&9?K*s*rnC$< zZ_tB12W(x#4&N>q9)i;nb$JiTR;joaZo(425{v3*uCS3oyM`qjwjqUH?6(Ij2@npM zdhqNWwJY ziKG>F+CsXBPK8c>!;h05VnuYwd1K23CM+#3j7$*!8F+<%EvfISNhXpN44Wj^0CCb2 z8TpC=yxs^?uAz_(Lz-%i0B=Jj4njgcrG987t#8&OUh{4HDrzFA3ghybP;z~SWFc>E z_9*`vzD$@qet2i;g$<>%H=j=EJZQu^I`|i?qb5ip0cJ^+s4x`=`|hq%v%p9NNjie1 zz>-@jeUIDUq|tqQgyJj&1)1j#aOmcjn+7B1eY%J+PY9%eIw`i`_T8+qOigXLAGv0& zqkYlbuSVL(up?#X43S){sw;#>A0x!R zf^;0~a76ARvCLS_xSiC|b*NN;1Ho1tRD5k)9J@ zrS7z$sTD!+sZ_-Oalx(hR*&2stNEyDt#-Qbs6+etmefj^>eEgwQ%?#-Z-@XHJR#sD za5KtxUo1Gz4z1;4Sth_2JN>Oxpf)|_;cD$0)6#2mv4O*<=g^#yBzR{QRY=s(fAG*R zTlvNhkA47XNWGyOrb<;jb-wh)sxU^nRcMzS9SEJnAN7Vv%P`$(RUkWcR+1U8%TER#Y^fF(QtMwVjSU1@4C(_Vpw?C zN6sdQ?d84VXSY;Qehm4P22{xi}GR{G5I9FRsA_ zM94b_eL(2M50!eQQQN~RPR-of8k1(XM5zvGb-P&A*#pB!l~OA#)Kjt?ekU7tM;WV5>&=ChGLeT0YB1$Y;whYBQzLO>pIBS8=a zuJPwl_)3yq619Az;;#sFI~#YE*?HFj&1AniRJR4f;7=jj6TpqKvt21-$tPA)ij$>9 z6F(liGahpKj(AgT0ZD4yZJ@OjA}HL_&B_MCcS18L3)dOKAti?f?G5cZVekRo-?a_} zOtn=t<->bZgVEv>=kIq2>$2o(1tf;czut4ESfyJIS(HLJUs4NjH?)I9c^`2W049KR zOHj$LouLE~pp$iTu@oKE@F<{_YhZL~(}_%cOs`a}Wm%bQNS15&P0IKeZg1nZ=4-!o zPwCURx{dD?3`Ek9HWKF9XH~MQMw05D(GQPf*e?5)K2rk{x(r~U-TF|@Z8G+WU4;)> z;3ELPL{9lT_9C#+Vz`2ty~i7rZ?{hbU;gvOG9Xr|k$i0!I`D0P{6;()g=&)F7rM46 zu$(#w;oP8oFFwiwi9}#^h=i|inXeHn)4K54gY}eHS$P+0VW0e&)i<9CWJpP<+|`AT za8;8;^mfjgy@rSdkayE5V06gWez|}I`{g^92t3*aXzf6{sPhr|w-dk0=Ia>cpc!Q2 z6HC|kY27Wlvx$g7+G5_WLe`K9!aGH}GEh%lHDGbrkye)*_4^~bMRl%N&BP@Yp!H0Z zP!{tE?$rS^OWQHq!IZU_y}c9OTEBwTsjYOXE@2q8*x%jNC`E;ANu_pm&uNpK{P5?4 zlNt668x6L&78SUdW}vtY3`J>&87zqfyKfB|8HWMc1e)hjzgZiQOLtZSkf!FlzFPmt zXtv>o7UAP}g3fJYVlus@$`l;r_W0K0&4>=jm*Ch=cf`z}MS}-V0_gV)mW7Xm4fGl! zcI#84^m3j~1qJ-%8NJN!O-6eT367&8hNJE6a2-xE7e&W9#zP;MK{q=jzNlX_3lMm8 zd%Axtsn3?SS2~SczDEISDT2L?{oNrdXnsg|5PQK|8noB`Jgahkf|w~ng(Ll6qUj;d~yI_bo*N2Z5P$?#)$QtFu!_bqqLDJ zAg>a}J(MfJRHkuCo?4F`82uS0e%MCOe6UR$#je@Wj6TKsiQL`7_Z>t)6A{)CH)@Ca zM5JI~1%4u3Sk}}Z?umQ0s#Ohxi0yo`KEDqPY>=CP;bq&eR%z#1=DX%V0Mac@A9h|j zGP?WtIunbh$OC-8%xDQKl(~lTU)TUOK+3=Ofg#1pnc$3q!$$9H=_~x+F6o@_HQ@E$ z&dIv7LzKGMJz|r|>DEIHUB=n)$d?E5AWTu?n;fbni9S&L>c(0*ATa(VX!+8a9AT5I z8xNkG&g+5f-!6R+S63M%dfS*pvSj@@1i*FV5ZQZd`j;nf8P-kc zl!=#(TmzOR6~mN-CDxGOJ|>)ME&qxBEkb020=GrzZ;@{c@&XeTq1#p+l7u3cVcC@9 zXjHuFP5uxaG>zT!onoy!3x=MdadB4TV=|dW{j4$f>k_ zL(FlGY4$}L+W5X`eOK5=TI|57TMKx_nRuVv`c&!<+ub~}a*9lTuZ~kzs}0gP3bkt! zb}XfVvI7;c$?_dvz8rit&b2^O?2CZ;!tS@ch0b6`Az<*~hgjpz{bkE4eO-}E?_E3G zf{?*W#Nd9Lv~cMmVnyepIN+O~RfIv9M$dhbs=Lma#^1Wrq{Hn2N5Wfv zWQC4v(D<=id($NMm-R@1e>EGS|4`!RjlxkhR*X?Mm#KUF)60mCyG|ew(*6=LXis!; zN!i-R3EUABL&hHwu1_rQ7Syo*ycOEy*0n}VapC!H&y$?yVV>G;Oyo7zc8ETliy6lH z^BL$6vbFkU?b#})iDmYUFNxDi((-_zWL~T%wtux(4KO>wAXygZVEl@(eNA3ylN$}2 z<72)bjhAKIGm=+%=YP9dCL6l7SZ`ZUT8Fa{Fu=T)6-%KGTFq+t;c})vLaESg&L}Nt zn?0bpxg}=%N+B8XR4yCC?MkPzRm*#Sp-4dsYsofdu^d?9D&o`TUL@lLAbW;P#H*9w z8T9;F$^SUqmH!#3r_49f*$52Zzj2@Xt2WJ4Lb<%ylFddkLmJt}A$g4f|FsPei zB@;1>`xe3}#X-gw-qfS+8eBjG@a6~;q`KO&-l;m#;9r`G*WmW2Oj%dNcH~Q5IL8Ib z6gkcR++P(=8El@B?Mlbk{sPn@y@lKtxH2?*v3>QO@$X@raeZUH3RAugL3(BoR7QEW z4T~p;9t_MPYdp844F|#n%7nZ**{zhT?=Ms+nZhEfRVoFLxr$^!dv=c?Pm8iUd{~;J zXHEC&n#FDlHaS3+Tdn6TB33`)Cqk|rE!5envnp->`VL((Hs#7obr8Uby0fzXlBzpm z{5N_SdkIYjDUo3H>-Z)0@YKy9PcBK5W+&KkHgujLNDF0eh`?5Na~2>d!|>t?bU-d) zgqd%xVtI=J{G?*vlhnap)OKyZa`s+5GQSx8K(mDz4}($7$5KGh`$%TvbisQ>byhO|uh?jm;|Og@mntyYu)Py<&;@It;Duh%(16{_>j^5c+hoza8`r}8fW ztv|9c=S(`uLtKZj;{zfYAb&JoCEI!pnux1UG58opo76*cFpFEo;q>J|^{wx_qQp3g zol)0H3!PoueMmSU+)t!XNKS@B=mr3+SYypp1G3H)FVZ{16c6dx;z~avEujTYC=-<* zJVMY}4ACAkSXg54>6x{BJtDoTZQF|NUAjTr?GNmM0t)WSlo!#1cCD*Iu!?D83mp!29Pv7;4qi1sR5X2ran5M&RHQnk|xJqADy#5lWlD zk1yhIyh#x4AR6Qud@#rEgT!0S{@Ao2_Ym7nuIr@o;|_FwFos`1!RUe5SO7Vm8cV9h zKULnUp_4Ohh0W!%ixiZ(rS>noQ@l|BAEX-r`(0ytv3BObqzoLpt`#nB+ZjsOy@3oq z;az@X2rR`;hP(QWMAUAJEz$t7x;4QkYnA`+FD zCzG+J)NOgle-Mvy{BUnrY%VI}<=Z`sZ+K8qD@Bvmvmp~lc@6!=Y|af3O<+g>y2XX+ zH6cV*^6fwCc(7J=WHi>k$cVB{;tQf7tyL{yjV9gHlVh+{y$9OB;;X>0~YW|t! zqqN|dj*R_AX;FpIIM}xW>6b(c=c$t~g_50a8DlaKV$DFqsKb{Sg3x(P5g1F*6>b@#85br?S zkqfI?^*`w>`qe|Zz!!Wlx(7ieruRq4@RUtj^8<_~fZmp6tv0SNhu(57m$w{3Vk&rR zI=eZuus$SNN0qD!v`8($*6<^mj$W`Il+}#aigCu4DfTF^@+eHFx<+V?G>BG*;;&?X+#G< z8HQ_yXi2t1ddv-g33;?1m3KJy?zLGQ-9XtOkoWj7T}U2kwhC*yl;N)-Z1Af7?p~UZ z9w36fr)p6H*vK{lV!nZ9GxYy!cAE+WNF0u+iHE4$epYF1S;U>tO*{3c>MC1lUCYg` z{gOJ`5<)ZO5AhnE<6|GZln$p|cD=xq?Kd(4cdsuLv<`>677l^XWBg6Z%=CNyibK;eQ=OsOgF#)#-KOZYccU zY5YePlzf8--Z<@I406Db{*s&q15k6%H}$f&a!j@t1k$LuDsCx9$tWzrXXq%=Jq&Ec zggFk@P?0Xnk*As6=(gE94`Xn)2v?n>8sAymu|p25)K2SE8b|)9?u^t5U`M_3hhu(7 z?E~v4ftnO=hJ-UG*G%8@KI>3f*+cftkAWfrP*KYYZ*NC99_cgu69@3bsKCx;%G{N6)g_3od7@-|jhd zX>l-$z6o_dt#XmV%)HiLd;4F*>t#jElO;!Q5U{m;$Q|^Y-#1tD8^SG779w0>tjII%TDRePCx`g^+fGd?S$?)iF;g=FY|nkpufXL z80-00yjOOXkzTu@ARO1RM+2+(sO{K?rWzD+gTy-^@Cf5cgThFne2in#Q|>aa;t{>M zw6LVscf`(AWiaUoE}X?_C32iZXY++=-@8h(_UImyaw*p05a|u&ga2_?shnolC&Imv z4UpyD3LW9-!l=Uz%QH(JOjDPfJo57g$E=?*TxhZ*(z%dw0Cbf+n}2q9#p3~c=CD~8 zNNLRW2r8c4XBh#I7%G10_IXnP{IKANff@WrNuxmluy!!t^jY$X%QQ5 zt1VRr`GnHr>NvTF$l2#+ZkSADUW94K{@V+scHZ^pjp8Ff8oa#b3S4vPQUMeseN~Ng z%;P;sTuS0Nz>3HnDs6e^FdMbGKOHBK(=%irNcRfq#bP7FGNXQrDc)iGYa>q}&0#%$ z%;+(h)YjKrk?AfwKF7NwA8;{)PNhw|z&vV-8AOlsvM?uR@~tL<#CdVZ8RsZ)1Vbr~ z5LO*c_~-~d*;JDB&6ns6m18Z49oGS|(7bFJ)RK3u?8DUIoJzT+8g%=Vh2@qZ&%Lh< z4|A(^RbnXZL1c&>LvpV)xHRkY&Xzn}Qv+i|`qoK|*bYc}mI4)ZXn}|B@peZ+Z45^V zB4#Aw8QOX6fG3)j{#XC=z^R9}GaEQu zxI8)-XEsi}aMA$_4*zDmVhIR@N{5sB0lZV_J-8OnL6S3=(|dwUZWT(&=h>P9CAaV^ zf$&>|LcZy7{P>PYG|CJYJo_1OHuaK7%tQFn8T|sdvBb4D;n!2pH%)f=IZ`NWI4C}SB-R2c}G5X zf&hq5s#4w^Cu|?!_xQqB0@kY)ZwyBKStLg7tZHV47Jc{o(`fuXe>EQ;iQkZp?1q*I zN;gw>236dm%&(l%3!!PNc%F^<80>-O&&*&k|~zPU%{p9HYTHr zh~3%WBM*1)aB5U}Ubib);GfT|1T*W%Jv|Q;K+|6tvTPCmmx}pys?+=Byv|e+Q#F39 z?(>QTmRtXKka_CF(u(Zl@&gwgq()@z^)Qe6)aQRnxzuwQ(2Vy2pC~}EFe}v0`r1C( z{g4-<&E?DBOoH)GwiRYJ6n|<|%&zY_R;=48TAQhSy#P_|-Ty-Sq4m0kNC}Ja&*Kdw z=FyVH>Y?@V5Zc~bINE4pgu;Aab`>YQvIGu9PC${^j`2hl4S=6tIem ztQ*oyBHF667b`7I8&I*4ho*G6iKI50hch30bpm+6xN-7(e`u$!9fCVzd-rd%AR>M$ zkU6s*7D!JVd5I?bc%jlq6cr&3d>Cf-PHitEywr?L9yh3DW!cXJT>Olw_okeETwgm1 zs1)Qyc$AqA(~E}PiDJhe?KuKpKM@1HI7?q!%r2(-GTzkG=1;p}ok{GeYPe$C+8d>@ ziJJSZ)&Y9l2|F-64 z?eSBaq}}mQ!348QII5BRlzpEb4iEnyn^vtosE8l8@4@i)Kp0H$-&N0a5z_V*5H96X zcO*fzNP(SqdpzNr#eL(EY{);-TW=wJQ|nB}pKKK&kMl(fce&4&z<}BKM7;njh_>LL zXnmFUjH^?3&T-r}aQ5_!NDrk>90ye>XB?>B(M)0#wsekkc6Y1OMC z?0HCbjYFz_#gQ~#g9M%M1D{123o#J?#hMoi4Jrz0=S!ui_CE!NDbK~sxAN+wDXNR7 z8nlbN^tIa}5KTkug$)3a>^S`kiYjvNkp~~629~gDE;9|Osw8|~4*6+`gbFV?JB^akS)5^lIR>wz#j_7lG@!FIzo7XR?^0vQTf|(F%FJSWK z;rllVd!UT!CB7jT(jHhx8(>U2(I9^1V(OI8PRJ*<7Gt zqN_H5ASlv`9JZ0En)MMl5Yn_LIei|u`OoGY`_sZo*TM^r7TX_`L_T@>FUoMTQ2M{O z$N4k1V z?H8{%1Uq|c5LUE10PI)KvPM=xIb&UJ>{6M|EsLpVTt0sL zA{z6HB>9|Vd;vQb=52eA+7hD2d!0WqTMityHJV*r3)d0ESQq5BB=c*x!3>_F&hV*i&Cb&Lp zP;exd>dQ8sxqd9`<$}UH^A8DB<-5%D#hPXQtcWt)e2uN`yQ&C5Uvt@8K+4|$TIy~&of5>k97+Zcp?owc0*hS4JcAj zTaf=Ct+NO?&dx69#PF!yjZOUQ(|OF1yvynUO+_7EELDiY_MlvrQnPZVk=}vAGua{$ zaYa1~${z+syiQwkCf?;%K~+Louc0tSM~aX%%KKd|t_}~Du{#8WT2JkC`uaI~-NLMO zBJUrAhkG;3Oi!D+gH^Go`!i!#K#F|R!8#x_p$@tFm7mAq@t)cuwT_6ue3nv>xq(;N znZn>z;AReIdrl()l0YC9v#&JpNQ61RgBP7~g)$rpe>I&uVK^8>fQw)J+D|U~3|^;4 z2U}4Q&+{`M^Uu1EKz}T-{Z})uIZzYDrA#XG*;b+d2Z+TGa5&109+Q1}J4Qg+|Fl5_ zmPGZ~C=0_H(70uHC6bQUlQk6vaTx04eg@E(a=@vcKTY^9N7+1A!Bk4kWOYyIND&*L2fMT+e8z0^c1LVEmFp#mtiVT zEjz~=9lL!3lfbvmu7+f37F_-Oe?RiAqU_O#8oOWJ&&a;azNGk9f&J$OQ#BO(Y5#c3 zU0Sr6UJ3<(;x4&9{yB=mv1+uPq@FrFed<6_){IqFcuFpGX}*1akWz~U2%RT&)=GiSnEW7Ccdt%D%m!j8`8T=x#EBRCSJIO+R!mr%P4z|KcA>`irA+&)z2LsI)*oqv13ah_-NEt$Bd3|6m2lX=8r_y zSb*ntdf$!J$^UzKaO_luiqLxuLSJ0i-rk||wdJmR&P8h`e8cr(4!i;Yd^$Kd%$1og zt0rw&1 z-kS?PsKFKQEY46!ykprSo&|K|L+DAEy}NfeO;@)zV`p2Uq)|hE7Z_bo_|b0F9y?6O z-rr%l9p^B%1uz&w7#G3a8opf7MnAR{BXJP>yVB~}Y^vU-dw1Vy`Bp281FMC@o}GjR z1YCyVl5C9V}TeM-a972B$437z#+LMJYN3N`85o)tecmvW6WAw_oaL^ zvAIbSo;ugSg%wXed6UqR2Z>6~m5cFCxQ;Dn;MCP7eFgLDX|6hV%XK7ByeYiTlPMfj7v{Y zUqtWEU`NTTnWf*MesH;0ZHx772$@82{Ca5YR}ZT&L7c(?mr0Ss`>SEC7sY z{q)&YO+w6KakGn*AvT0}9kNoJ%yQJ#kI#8;w$FsDsr=GwQhzm{R(jdL`(df$C%KT0B=esK$ zviQ*Ccw*gk88ydS5wMz?imv_h7>#ls`DHF9;d%;beCPG^O3JUPqYOe{ zUgi;>BB&x}JZ?&!x_hTha)ecR6VB`)IioK!H=8GNxR3<0vc&OFCrKB@eA1FD955q_ z(_w`@mpP(?&D+7pyX&asam2l~hMA^s9ARB_4hyTLgtLtTrP3u_f>g4Go80S{<4}Vn zBkannX2e67M&GV+kn_Pe3emaxh~(~n4$C-v1u4ziUTSJGeCilI6flpn<$4U;5`7)T z&Tue2&2FGTIP8f840Z*s#-4%XPGD4KLH-2}&;pmYE9Ei1DyP{VL}1cR-)u76w}^to zk5byDcJT z5v(C8z98uXkau_*{5LEaI6(NXb`QVAQ#x*y92&}66@hG8$NhNM_SfKVHVr~6g}XWj zFQS@;CqWXlYY^c7cf}|f@UIPw!~fk-_;lqx`lGmMh-3_JKd2V5zFTqReL5SLQzPv$WQe*qS*dMB5RDlM*H6Gx9Vo@5k zLsZ`Ui=Z$Spd((cQVz50PxN<)Q)d-=1S`LCS|{2UF2J9wTG*R&?b8$Q$dR0h0vSNpAEZvgUe~nDq_2aqS(CJuLEYa*XlxqH*keH;`!lpb24V~_{JAvl_IVYdh$ zT1+#SRM}phw#K#+QCdBiTB&-lZOH9{hF%9(L`V+Dmv6S-rhs<2{ZoMa%*M!Jq^Zi{ zBaHHn?cvyDjPiP1`xK4D>AYccf=AH^Z<&Ff3Uie4a6wG^A7(0fuH#$bcoQe%^w?m6tb4+6z&cN)?Ti5!s)l{9^CVJW9&k(H*q@SVvhd1A5P5fN-TApf%-$iT{` zQtl{|*WSwJXsg1mOT8yJes?EDb}1ETNM8bu07>K<-hQl*msU3KLcpt^6hLX+TSUWb z98a-5v+G-XQthj3i9V68ZmnGgTz-siQ6|D6c=8p#=gRYR=xT~C!^+bHfQ(EeMOjRA zunzk#D-qtNntm(W>cyR=3gze%$!zAOEHNiII{1#{1s$;%>>&SERw%Yb;K?MR5-3T$ z3_Iq$dCVGJkwb=+y0&EGp_^b%4=G?4LOt0qx^0ZO~y zQeeV~f;h5}XfHxhkA6~hVc3$XG9l3bB3UE2b#oCvUj8^0GvhD|@ z$0Nx=fIsv!bQsX^?!fO->VYt$nor`ollVQRJ()-r)wpBV_>VgULhNlMc@?T3!0EIb!n=-}b!f(qC)I#k1}{ zr5}Dh%c;d=vVDo0?jfDI55A13*n`P*+H)!aloH0Y)vnsowun*cOkaE8U`?dC1kKgX z#K0UT*wFc`MF-R3kYy^6^ecb2^ay#{n4fEPCN`8)lHR#B2RVFIpJ%=p@l2~0Mnvaa za6UcBb?E^wxkXvh+1FE2-C=vAke*S!JUmNOhyXGzLbe0i_+%FhK_d3e;ri7*+hjK~-~yLcV+w1YcVUT}Rd z&|Isj%nN4E>R>gR1@iS8_J6qO7|1AFVh%d!7Goq6O_3j}+G?Nh9ZfJX`C5D!kN27K z3oD0Fk;7o)3F$l*>Knr&_I@|g$;=`;b7sFqX_%$(cG0LbYvQ5kmUi-D~R z)@BbYe2EcpOi#IH(S2_eFEV%rjb(lY!i1}BVmfBie4sHWMaT^1W%MkbWRY(aMSq&y zVv-^`wwm$;k-;m&Nyew_PApGx+gLKQiyuE`+bZk>aON_%hC)xDhojxnLj=q*8IY$bUL6lI`O?Ko-rT_eLb_%c6znd!h7n0ID7Q5rRRbl$6KEUM0@DF0Vk4q~6% zyqcxT-|a^6_~_inav_)EyB@dj%;9|w5$ZC*_y{#Dx_gc&yEh|-3kH9?vzlBRiWg@b z{yQ-h8wvSmafJu`Z^d(UulEE1&r+@BM1vLzY{%g$5(tDtmDKU@N0>CDiBP6+3fQ9< zh$CQ=nR($_{JDVP5cPGJ-FKk0m=;wW+e>LJs(u@Pzvz+f^Sb z6UD^ej@q#gAHX+Ij_U!C))#cJ2W!lv{`C<;BUzHJ7vG05K<1H1;q%N|@J zO|+e z3LY@7Rq7c~BKjaCr*6E@{mt)_c*?*BAwk&^?Nmn>RRfA*E=#ASGgkZm15!yj<7&^5 zWW!*};}%3yx)qyr3jr=%g^##2=Ah2s;5Q#fC-H!ofd%s3g;F$QK|5!YBlEqJoW`AJ z^l3d1`@m-`1BMaPWCOXo$i1Iri8POL!#W6|$Nm=|-q*V*r$JM&MggZ;QVXBB%GZ!+ z53Xn|FCD#A-OJ2#jc|ACrJ<=<+imiK!w8_Gc_Tnq^yv<{tfEw3pJNdj!o5^nT{EZ( zLGSIJHSZ@>&l|G1v!nKZ0kmCxb&evU;Y}eJoQa!YYR9|Bd|fii*_ehz7V;5tmi*ml z6SFqARk=TQLU|zRerJ>-#)Q|8$CF>1C0!+=>#~WeE4N*!e2I*xRaE^82e9lEs@bLg z8xqj-14{$Dnyi2SXrE{Q`&?)RXDX= z#E`xQ_^zu}O^#uQ1Zo?a=H~^xaVt|wrqP|zz6g`;FICpGR6s7Q8DJ_iYICMhZ)gaF za2}8H%Yk@$A{&Q;Ln-f*`j4l3ULi8(tb@n_w(~aRshIb@LDYALLj7_E(Z()RMZ|f7I$1L?D^zyMUMR zl2c^EdkA=28o=~#XKp{ful21L(n0dSB0VVt8!=mImX0?P3&NB=04gUVf$6Qk;c4f% z`p-xNpkFlAc*ftStOn(ybnkJ{CcZqxi-;ORrL)h9aAu#`#GpcrrJvF;{3Nw&WGtPg z`tjjctT~u@a8^^S_y#MpS3gIEzsR0)zY0S=`qK&$k6ll zCwAV6+ZDTII)@A!iBOpp(C>NkTQEXfAL)2JPO}DfDdPuYUoar1pC_~iTymNvGA)*= zuwtmSiK74D<*-&e#3&;T*d&R8dx^gj@K=Y6iQc3s_M>D)Witn!*L9V1gYl{xR-KisqBP+WP1y=(WP+SZoT(8Bt5Hrd1 z%6O&!>nWoX-78r2uE(lUI{xRN z-=Uu618-^hpQ!b$(F82b$jD|SQlQ@}u^1=Zg z%c201N#qaD)0!*sCPixajwq~qJqmdNOk|Qr6tkQ!P(22Sb)>GrEpPAd^!Ae<5{Jid zS@tYg#HRb<_^ruNk$So-x+J83>XO-1E1?yJEriu>m^%(QIH;n@-CAU4#_#aBns8}B~w5NsQq%f&m=!Xo~V zo1i-1031DB=Y2(FI&lnH9p9}r;^-oPus)Pmk;XNp{5`{N8b!K5UDE8xHIiSmbPlEJ zS-)!VC4iZSnLAzNxSLZ<)A1K4WxS-jXv)9XO~7RLQAsg)iTO&zPFgV$If?}Lzv%3A zuPLWeJqPSiPWuyZGpHAyZLjpxYj<_4s_ z{M8gP54}OUY{0wr6a=R7i$oC&4aEAT*e^0(cBVLXPmAO&!UH)%S6O3c)()$ltI_31iT1$ zaU{57wnYWxsrk1m6mLSn8B%-9hoB6TT{hEa+Y}UIt#4b;EZ6m|@g$>MUih%Mmjj_u_o3MFINp^}$Wk5Qy())~Q1co8vmu6mxf~|6 zwk0KZS-moL;5FdF!l;dlF{KY9&`@jPqKpP~H7{(>=?|$C*@6`X4w#|Q@s5ZjvekNM z@|E1y1RF8?>40SrxNH~4+|NC;xL+Gll$^)aN7Zgy-WR>&iWNXA{=0OO273_PXL zUDfmL4M^Z3wg%I)^4Hobd#mL$OXa1LH3GRRd&NFka~VPMBx-0U%qG2i?{2!1cj_2yf5WKB{734z>)#E-PU zmPYe7_vDKm^mxbvc}nuAr{n(#5+z<9;TwVNszao4zjL*H5$~;GzO5X#h$0!hp#sqU&N%Me~7A z3QX8f#n7^OYM+|Rr6?jEI>+`SIR`hR>5X{7C2>aT{9}*Z>_xa7xoZJWQowDn0_aPJ z#D>y%{USF|e7V9U5AN*QfQ>l&{g$ZIf+0I00;q^b*qP02d?I6Y%ksy>vJ!lK$5y?< z6C-V==ORN1Q$ts5)!KKEg!VJ)7;}BiUWW9tX9Gkt z-wgd*A41wx#K99jNHz0faD7!M*1nSWE#It5+X41Sx+)3flO}2$rrc*#o!M2A|Ce4Q zmKE_n#Cseq<;fMGl2rmWnO9Xbu0FhK%ZJ4*_NhQqwkycX#-94by1oN_dJK0Z7$XMj zmSU1r!9l*$B%ejk#gHfm8rgIM)dhvOp}4F5ZN46mwyW%#@1zg?&h4P5|-9=@Y4oMYl&T-9mP!d{|Jac!I<2hGaTJ8rjM~fT)8qh!3UY&o)`!l}Z#4Ya}NZ z8$58iTp(6m1R~9U6jHtyI5V-v+1GH(r0)EohB?fV`-1KFCg<_RDV-CUxl^o81O+(+ z4L?kC&BNY;LQ(t|O7E)nvVe=#ZR~zSxU-jXe!4rKc`KyKEj35Pr4YM$>jzibDQPG zEBZ$0V7@Vt+N&u{T5v}6u$iP=R<_T5;YVoUD+Ujb01+9oI2EK=<;rY2ghq=0kFf=@ zZ1e=tW=^61;*(1Z z$1dn*dcG)kO}I1f`7%A>nu&*3l|v?mP~JVJGX(< zi*Ls?Xlo$reorGa(4J95o;$rdip3M+4#}DAcazKNOnE{J4rgTAF5wPwTIP;f-)o%P zL{9%H5Nu=}2go4kT|N&TL#N0LelCvx(IxIc$?#$(I#d%C(`n46Et+Xz3o zUAHNi(RhEQnl0S=4mnC~D1~w{kI+&ghHkj?;1$ag{I1yUQ&{R4UCPgO_?&J4R`zhy z4M$!?gav@|Fe$Hoh81v-iXe{%_s!=<6wPSRLgv|Vvz2eEXL;hgv}Gy!ZQ{=%V>M$! zS~lVOTaoegrf;lOw&fQMmS8*yeied4wTt=JakgA?Q)l2^9U%BSsCwR*%eRhI_ItDXB4QA!>6>mjCHYmoWG1>JB}IZ*5$+713y z_Ro~*_RTOOyL`YL7;&|m3gF`Rm`3SJoY}xyH03TvC+Qr~$h+7OyZfOz2M+k{2JXHz zaz>R6U1W7S)@P>pRAL*0uvP$K?9jPn!Lk|8$3nc7HqgG>aXubG+b(?R2To<~_BJlU z$p@%1Y}PG6 zd$Kgq&g8RvnYXt-NsKVkg(IP6F`j$+AH;v#HR`_Y^G@3rNtUP3mFr^T`w`+?fPWLF zWaE4}9C~{Na`{MV99#^ExOVU~d^kSi2*4^bUwxixfXQ0XVosz+D;-_RgC0rzaFYZj zwwRLo%atN5?XY8|;Vhf`z1BbbfN(E*D!OR7H-&samMxMhN`iWc=FmSvTS)rA_$Vh$ z>wB`!v)lGb%8o3L1CwXf_SD?yz-~7+l@3qWetKj)Bde5{x~{ctm}1VIG1o{lql(&N zr??C=4SCq=<3I7`RAtteZxg{?skzpaW*-wn?mWlvI$Jn8X0{|$dy+lsAt5vVZ(wJ~uu7&UzkGs&Q*G(j_PbTwPgr)joQdKz0n?Q2 z*JG>*_?hUeU#``;DBlrnF3RMI@#z28Oj;1!5zCSIafM3_EC}sO);pjaNI7+Zb{n{{oW|?7XNhWgb8efodZ4B$i z3tMInI@wI|nJJwkA8^9i$VkyVxoxt!*UvU_#}{4c5}+4If*YAB#1HSpa2wLDbWB7x z`OBvm8_Z-DSloFBO7n-cNs+N*1brVbO;?2^$CpZ->3KxXVO zQrH@5RNGaYyO4J;r07<*X~b2CTAu>zU6ruT^U9_qe0)gAB6pKl8pVi!b^_qS_6$OOTdd1;I_OFK*u$R{qJL?Z5|>hP)2IO047R8Qly@_z((B5yd%^6ML7T66o5 z^%eF{mr!)@0-OCU>cO$5upFwEn|zMA?Ae!QoN~fd_!AY0!#tWi%ux**Rs{CHA{j~| zz0A*F>^F2FGAC%AZpu~ITroy@9;_`vw^I)u9>?* zsLI`fE&&urxsB&A6Tx{@iHzRHe)M>U4losifOjYkZn_J~hJuYYa9mIdqz`wH4Mpd@ zm^Sep+O-+E0>#SJo5s}lC^)|p5ZGeeKrp?xao%6GPjOCP2QDYPqx?sX^006u|1>h< zeN;{!Ok|R6u?Sfe7f5vyvO4=7!w&3Hdd-BI|v1L5hX$)f>u z&WyFTfTrUUS|*NnA5e=}kD);XNX!!!r}4tf=&TJ|88!7TkC5LrE8A>Di~*2!JQZnP zVSO7;9Q?8L;4tKUbmAOy7&06K6X!ED8aCSlO$?m$3T8hwZ7#Ru{N~XV`dIzymoDH= zj~8!A^_VvJYGh*%QASTT)Q`P1?^mWF={K)rTEGOJ!p%DodPit>aKj^A7^=o0?s%qJ zFRLMik2@dU+LAlJK;ZJ)M(%^d$C=~i%;oHQ=dWT`1eB^TRam(y=o`0KJ(Gf?>c-p& zSKmTZWKRa&dqVd?DYFiI^x}O9JE)+bK3GFRT|iNa;n*rS0*s#Y zK$Z1rq6FTsL<_ub1FV>Auzcd`vwI*eWwaxG2~`}{hA-G2 zvQ+IV%P6ekgXHZOAtL4_feW-K=uO?$=U!^eu&yKYQxUgSa%rM&JF@ z`bK>?qY{7CdP-l=hXenhMn%=hgLI&IIbgK5odV>hXaDZ%p79&f5}uBK4D;u@0_X_F zfV{9eEJSog+eI=g)!*=Yryb`8a#Y!33-#zOm*uTmXW`TV#l@T7k8xvD-s zO~;4(W7i{08&CxH4KPBC+iPWod8$=mm(e%X$Aj+5?TSm1=r0)Y8d+WZ11vv_t${M( z0up&ME2sVCsQVlHI5nsba_6Z8WxN-2Yv9Lf9_mTxfRCX1!!uvavbV!q+^nv#;58n0 zuTZZss{w*!E>zcD_k6^MslqCo$_!{HK$h%VrD1DnsS&9)IgUFo=oD7rf+PCE_H;_Ve+Le4#Np(&k z+`i<8X}pa%^*zFyJ9}c!s`>@-kxu~o+BQYi4R$$B6ZVHcp<@8pOxcN)AA|=yd4~nSoQi;!$h(;8@ zIfp1oRDnWxx5ipi!W-EB{jlfu6zy%<9Fnd|7_eT`aG28D#&NJAflVx}V8dT>V2C2v zM?>yxWddD^QU}yywzt%sCf*h-+F7TTXT}fwJ?{cP1%XLk`aD_;Q}+`*Wq@figpx}1jbHN3&imM*1s22wbqt77j1s8te#U3o7$%tQ?GF)=~YliI{o z7FQ0a&-ia*KvEqSK%j+Hs5!xuaOXfo2gNow7i5y_07O8$zoef&M`Az+LMpPv$FM}* ztPRw_o>*;`xT~$^i=jc^Fulbs7Yvx64b)ZgQ>rCKrv;LOimFs*OeSCMK$((6Wc1rT zaAXC9>`~)~9l`>Nq|mkSfJ;F>F`0?OHj2-;MdUvS4zAncq;E%2bJd#{A~9JuZ+eY! zg^~OEHM{7+u%mv)2tq9{k%-}8Tt|Bz6&YzY4k^MNxZit^6x64QvzXWSt)glMvCsst zib2*C`hhPeMS8A2N1`Ld#C|UE6=ZAj+s_|N4$si&&HBYWTe~iIrh6~SE+{tWN5Pk*vxR5o)>QEyr$CC5>37e>8{ zqGEDF{*HVK?PnG1S&@h5dW&c# znJBPDd-#p;ZGM>^q`j;hkq-c;n_D?HEnp76B^dnL+KM16Q@^Tf1ZP-t6BdEI`LmJ6 z`$*&P9u@%R*da`#>7s2TMu`FH(S}8*UhK;j_+JFZ`(rH()#ykeZ_rKg^FX`Ixxk2Q zXz;&E0r2-#rMMoM`?`Csf#QG4;Yag$bqz%<56>FRqQJB*S|K`gp#VLIL7y=F+T904 z0H-1e`q)Q9NgwuNB|E=&loj{Lp9;tVES{LqMf}gjU=86*1K7 zRf0fgZ3aey>RmLxVLDpg9x|kIbA_=TgH>R*&?~O#> zTR9!Ivr&MgTWurnXCMBztHVL%@nk+of(6(`Y-H3he&vGu+MRo@&^*+G_~)H~xwY#2 zB!f37{e+YD6+QIXsPrXvHwaxED|bLv!PM%zb5pUbPn>Fajy9#N@smCmC@`lnQs=6o zRmvHa85u_ve0LiM`OchxwSK6>bJex-+TI2_{)a7-8kvQlz@bRU ztXA!T0uYHj(Wl8q@ikFCo8_Q!^=hMH+@~iBpi!BSAmiq-h5)PRFLGu5XhuNJX!Ldb z%WbfPXJ3E@4@_>9=KP^5s-Av&qvLsE_UbJOcU=!&pb!6^tbR{C$G^XD#p`vDtzG@> zCXh84(Y{PVZt6#VNC7b#3Sxavm?kA{q^uM;CLixx;om-AbJJ5YIyV76>}-t`NP5V~ z1ybHnXTiiz5`ZKMce!71lW0@QYA@Rm7~*a(KjnT;Y=pMGwA&CfNM-#z@$ZLeWmfX> z31NQGZ#*3v+6(+t8{>yXniGp1?{yI_FBus?RN%JWv;Glo?C-%SXmwQRuS6?12j9&n zgIU#665e3>*4jNuHW7jW&)#w_U>YBObNo@7!5Q1UQXIO3=^N$h8f_IjI9Uqv7W0eM zu>)L*7yn8c?)+Yq&u*`hY&EF2kja>;##TL>*ouFgxY|Y?5`sdIf(mHdCsq2{`GS;i zP$5&Q_QFlFzaIdjwevnNM@+;bLkEjX2||cU6i$x4HhvY=9M(A)BU)A4FaOxnJX`AA zbL9x5SjdB@YERUc1=52EW@LP!Vkh7?nO=MTm4}E>*?rB#-wuuK$049 z!yd5LiFBEEC&=5%|L*tA8gQ>fCxIQ+mL9E-6^Wt9)mC&FqrRpttL|&X*o!4i#}=eU ziqq2W5}?z7cWg{JwQ5L~WhQOo%>i*vUJ}kOQ-$%2IAaJB*F~u>(30IQ$c9EzNgyuA zH2l$qRO7Af^Ne*rx~RWXb7JaIKbNaAhw+L4*EDb(6X)6z{ry;-%E3K|>old$nfzO~JHgNWO4V2o_YfhA6?@4U#c_ffK@GIcO77pz zmnU*ZW2C6rn5|=;-%Smo+w|L>74OU~WgtY2K_CgmG(hCc3)07agNu~Od=ACvz|90W;w9NxF!5sw|Fzf@vPv!t#l75TsI?lBSQ&-A?5Rh? zL0^Zl;}wPL?;t6wQXH2H3}*F{v1LwOmLKf2`IU(LsaAEwI}Pw0Alqnm#llp_a}lhJ zxk;4}Pno+(4xX1&iFrO-AYV~H{vm_0@P#LAe{N#Y*bAzD_cdCx12UeOfZmh_M3u%* zKWKMOmIFE9Bab?_Q5q!;zJi!UOLR^s)V_%mJvKpP* z1aFj(Z{ZN0PzY@tkmJp4KCZ1qkMD~`-0JS77P)ws&wUEl0yrBV;&Ct|G?SOA9;f%& zE`^}g-^{6V;4Pm_%Z7Pb!Sg*jFV;yA1Yun4;O7qb%KB56b1e0E^eMn=hL0$wm93`j_$psvchvXeaT@Mj=fl^{Loa^2Q&0So5Jlt`4z)vlT+u`86mLH>A@XH#+ zq}iL>;=WYrJgDv^h|j=Ua!&-E`4Vi`A;gR@U@G>*(uvPF3QJ>h{|3o0XR>Ef@3ND# z=kyl&TH|85zb)2_F{7J<9K7P(C7&M*O+8!%0<1ZnFVg7r$$P{5?CqgW;RfA-ePK1u zio6;Am)Y;i!m_$~g3}f}6*NNrYq!$n{eax+#ObA{v2)Dq11;T0W_MxriF_uvKqhN` zSXHNcKXho2b$Rey{ko%H8wP9UBr2{*_B**Yb|XKDnS4H>a6jz|gLQ9EMza(}y0jfP z*i|x3HK$pUYGU`dcy@POH|Xc7f3u8b;{CTFC=)?k-L{I!259=P`K>U^cx0&;L6Ziy zA5`v--slG_Hx8088x5oKn()cSJVtRW zf9KK7EO7sTEscId`gDY&R@OYUOPxK4G+$msBr8Nr*o`E)FVMbFxNDCZCAuf_K1pKD zMWW&>UNS=HNhh3v5FpGbKw?#CV zPo$EI1c*V=FPAk`sqcHTZ*RHi4!DM%t%@Au8XtJ5x^fN7tDSa93_AMv&M2aRKffe* z`>zyMW{Y(PIi;up{&*&Dvej0I_C5@2@k<<)OATKE_HHm4k?}zCQd?=568-{mHHt$PHNv+=arIF(C6e)$$IH4?zRqA3_SXy zmGe4`i}Y2r!`rlRKw_D!#z%fKqbCDu_b%z4Ji~k%AZby#aXAWBBlf{@z`OUg!5~QH zfkjj~xgOQI&>|UeQfXy4g_2{R)Yaf8mm@^FryZb_9w|s^ztISq&yPt zFtjMKz66<*#cGLQ_Gm=_Kvr}<3?xu>1*YR#V#b+L`!MBF^7#H8trG5TR2ob<{JU?h zq7`mr!Z^DnDIcmL(3+J)%mVo$Qi|~zzDiU{FMpX+z&TPdaSqfPE}9s&3W8)~8+wA9 zu0AShfnB`ghR<;rQ||WrmNh@t*yMlkVU0ESk}>c(c2}_D&zY? z586+yNhc>CGPpqdA0?UaDecmf-2t{$x4@}ZL|rg6=X#uxq?&jAFXC_;>p#Qs-kTa3 zJ-YwV?=*}iw#j8>L0>#aFrY^``wJmrAhhOalWpU`!TH$E(9$Ga?z=W8Ok^y9`_pwU zGyH>zGkdwJ&nW}-noi$a>Fb0zh6+6|Ntca%r8LlhD5+Tr){o(P`$l^`ToQMRWlw1G z%>}Z*3<9I@-dzTy2!6-$8~?$!3^tGhjMD=erGT>E51;%QjcKs|->mQ;_HcIcfWFWU zxiDkoV49~nA8un5!+Gy-UlBj^$N;HuFPg2>7#9=1I-xm$t8LKIF@M2J?DFq3*V%|y zBnaRIS&tm#qXDg|6kOgVt-apuO?Cr-^RPLDNTBqLUd)(4{5*^3VG6JIW;dAy-h|?? zea>zt6uXXdm5yI8EW|{+YEAIs^Pndv&ZoV%3-gk(codOsgB)C(*Zd7CO=Q(~D@IvN zsi;JN7EapDRDe~nJ$+{pqs3(6I`2)6wYJe4%ef)*P9M6PrZsbB4t62oLl39+`4v8a z-;Q%DHD}tVhfU){X+tQ%tgUbsXC3k|JfkI|{YPjQxgPSto8nZXz>0rB`;H2b={hsd z+nad0aHp&&0@>{MW)7g}wM@>58Y5Er=@<4pc50Rq~Ypno;*BnC@ zI93+S#6;u~JSW|v5hRs*jdX~Z6{Or5e#$4bqj>W8;>OPqD_csG2o|fYXss~8`>;jW zpeCj4=MiM|n^M$)6dk(N^ZtKO>iV>Z_I!sNd|UAD4SGUO6{x zWXnj=e3OPeB6X@r#+P%v54Gy3zSWcdI7Iwd^*DUK_c0hx!vS3oTZMqx{4wMz zFZMYRto2nOgm@gSaP(RDowI zE&dS67(&sl_Gn+dJEh!yW_#geZumO9q6mCr!Y1W6{vO$Mj0!7vO4vupLw`|D6f2CQ zLYPdCE(Ejut&g?~CTQ&!x50;OBA*IUxdvU z!Z8s(x5*zo6)&7OaS@YFn!sIYI2p@bv|=c7wd|@@sGJ|(`4z~BQNjL9sB%T>&EoSm zuF*G)e9CU3b41N(k?%qOS_m{ou{_iL%NVJFg?GGhP``s~(fVy^RStZO?(7g$SWLsVhUlsq4U z3n4xAFhgG*R=R8p(}6e@6hY+-xSzHA4^Ls~gOfe5h19lo7B_2KTuQ>pmBU8p{8 zbeFgi)#SFU5)YG^Rz5pTT^1nu;W`0(Zc5m6rWyLzywv%B$oxb+Ua)^0=&41f4=d8YPm01U03TM(%*zXQMUwo6HP zZS?%QVygzR%#E=RLJkQcpefnBj|SeNTQW2{;yp#un_53Eni0wpSTW0`C7HGJ$i@d$ zq;NVDofKV!|D+5nqeC^Kip)E@tr|iHJt&-hC9&p(`!0%1sOZi*(AY^yUaI15KN?^) z9N55Ybhr&ZRNkd2XArZ%oxl`#iItP55o<@O#ws9^AlyScP^Y?S%X=LxZD2<6ec?$R zk}y~g^CPUN_}RfTQy;4Ld*aoJ_L$m}o$L8b-H?fo9t%lj29G^g**oSAyH9@P(Pr{Mr~r4?tLr-jTXtmGoLOC=d6_q34{f~a}adB z7D@H!;%~Q!wd1Vj2pn#B${uBD$3E@n47>~H;j2#_UqG-{Ww@dpQdZRUq)2dUpEWH~ z_92$N%5aq|rn-8lk zWx7TYw9v&IMl||of#S{n0K<`B!z=)yhq}VRd-m|JHkQDn;t(wFX zzFH<)h45HcKq?P@kzweuK^ZliDJxhVjHm1*lklg<1!5b3JZuH#=nMCt z%eVAu*r+1pS}&jw;4%HNq|{m{zemY1080f%CB!g9D{*aSo6I{lolD2sxlTcQSHrTn-|t}yedSyZaX^b4Np8}zN|l2s;RDWm@qd9O$hR! zt6~+I^n4n&>@VMcu78&Rfv*ZOR>$1%6NhP;L2Gnl&Yg(sK;onhzs(sJSz&NR$pP_N zi3h)*SM+av4#jxNapZTl7{Vi`&&@PJ8vF8yL(0iZfVR6MG{hPBy(SGOgVDY8mIp9b z;1=p^s?Gj_V=7af`{*^`@$c@z;>Y5__vx^XOqoQIiwZTwF5f9v%YP$G+_FC;bv-Jb z$+`vl`Wtd7YP=8g-*47`o}VLF8(IA`JDM#ytpoZEMBJmDo8=Q!EEjYc{1evMr+1sg z{lDs5UZ+Ak3mp>6(4IX%cDRugpFHkvoaN+$UeBeAVfk&Hn;D;nTf1+pY3Ep(^I&3s zfT1|O0!HIuAJ-z-t`Cg}I*LoU3VS<|`$_93IOX`!^B;Gm)XzMh^(o=Ypc;OsPbI@G zOvhjAZw8uaw|l^uilU1d%s;k5$PB=od;Et_gZ^LKq=5&?dG{+P6~$H*&_8g9E-rrV zEGJLK$Cdz%D20VoHF7pQ`vxpZ#nJV;K0*uS+p-Jik-mf&RwHtf^$t-bXU%W+eLR+3 z#RBb??r5_en)VC)_|4?5T@at$^&mPU`)$JXH#4d-l4|1ax5BcLupkg&Yf=?{uo`In(Gf zZ+_G-8E-coh4NskBI_udExpNc;<{QC`{P4f=Y7*LtU;Pe9QNK#X=ri*Kcp=o8vCST z$s>^Bn_^Nu4JsQ<+;MXQ^0TDYn15!==SO()TtCZO2pWGB87%S29an+!#v^|$5RFd; zEuS@0B%XJQQH2>$2R`Rhsw`{Bc4}{ZyGH}A^d!;^_Hs!!ooq?a8gPI$4>@PTgGu4& zC(z1DUQnHVfD>+?vM0a~@TAF<%#Agj?v;g(=sm!ep^ha+13l;d?a&r#Qh>~f)lKxY zem-{2Sjw%UTOc&d!wc zT|jniU5)y^m^q~rR$*}V|8~U7^pO)}(L{s_Th)&lTMI?`z9n`02HTR-mpzr<_VxeE z2-JFTmv((qSOwM{)|XQ%{Z{Oebm!qRD8q5$y4h#enk@LTR@1#3yQIdqk|b|W+M0sk z^@vgUvf&^XXt#AlS31TjG3ZLlxm^g`HcRjvm}R3qJ+Iq(wKGTCB%unY&x5m81yJoH z*KMmdVL##kX-uYTtctLJ5(MfiD*zTiNy_U$jWpNgHmHkS9;cuwQQt>=$Sslk`Iu^} z9~cAK9hGcOTqUEKYdu#ONUU2k!;M|aVhid+CS9T+il~JN*86vz79#oGa&PY_G8Px9 zj*{!8$C2XJ*P(6%QW@w7Av#8a5u=`SV?=a2uuX;X&Fw_sp{#K=6^?4G!-G#kczDD{ z?40x>=NhduUmS^JREP~>8|X;@s(2o#ZRR`-`K0=(R?mWO@b z)c)XLY09ojTbzrRyVS#OP&wgj%k%31<@hZ=E3Q z_toXZ-~N|I5^Ancq3k0rd2!-2_g2JfV&kSfDDjvU8t63fBvbJ4%4oOa5rMly+ako` zr&Vx``8~TRWZ(jx*IfcPPdlsPcCP7+2TgUrNP8n`PjgK||n$Qb98^YWg;f=e)|zW&x4*gzFqipIhA(jgeh=idKU^BNdplZE53h z74)#farmACGpcPe;1kH|rbrbxR+5)GV~K)1aUVHvy%4jFOV{oF3V!hOhc+Rt0QEH;CthDu1xRpTv=~T7Rca1Z|M!IZmE3SFKB~{r1y67 zj74c8M~lY%Z{EYzd-}b{7+X?Tr^WZW_Aw>vDC|6op+UNBdlBwU96EmPxbQqo?%g(A zwS&Bi0Sz!;oc?hf*bZ*Suf|FtxbIzBlYOAF)iaXb2;%lQc$2J=f>$V3UbJ->)Bx>q z_3_u9Fao%#$S<8bW;7sDo+_9f2TAEi1YXUdhSVK_!KmT}iz2xXEj_&%3LK$y>5c-G zUP&(1$PEVu%4%_cgLAXEsrbLm`PPNdIKNFr_?AXRxXu;FL6esqaVdQ2v z?s<~&B``dkop?=!=+4Ork-{U+OyUmov zT`FxgU$=^73}$Jef=9D{e~#mJ5|%tp;rnkENlSzYU>%<)z_Ax~6j_Qm%62ZXZp_vP z5#^_Z*2(Ls4aaRtykoruIzA#dW-BK77I64<7HOq)8toL3hF!17OeqN zS=2&BN0N*CzD`JWfWBHI`oV=s zfGb(!#rpq0b`G&5CQNKZ4_r|^SD#)tOj&U*{Y~Gs`SZc!3U?4vn>s5*GOAv=l=AiZ zry@BIKJ4Ii3$@$JlU0YhSom~XCU!Gsazx{YMe3x7H)m8U{OV{W#<=(?(AVHw%!dQA+ACQ+i(wjJhMJnITTTQhWZY7Cc%wAMqQtM zDT@l#5j?(|S$@E500Ezc4~(LtC*obb2O3b>`uN}IY>HcEn3!laEz1UUPO<$Y66CF& z4$HOBd^%a*wL>)jo%Ov4eG4&hNzu1_KE0crZ1b6^WA6!rQ)!v}_B6wiJqERU!;p+I zuc9@*p`in-PS;3Vl?`G2xqy~Q)|FMJ^*0HY1Iskv;@haYb{2u*?G%kHIjf)dIYJ8u z6CMvv5paT3!SkJ8@71Sdk-9@UBaYuQC%?1P4;M7$A)|68hn397_i2j&Xf#-!dKR-$ zr8a-{Ijf`aG5lRd!Gf2>Hk(5>UJ`^rnbqGG{2| zVI|b@`q0-BmHr6RJdx~a@8}xWd9x1ZqtOT7Ezf|24KO}78&wJUbMCj`-a#Kjo+OWV z*+T7fF}W1x1^ilRnGT}h z&Vlar{PsIjeF@TGT0ag-?1-!l-3q>8(qbdK;y}2-AiAyC^Z1a5N-dU8n<=#tr6XU< zp6F`YN|crdYX+%hTnpSIcGClj)EE2UL}gE3xKzdYY(1KC{=EZe;=@`MmUYTpBNlXE zXBv7Lm-!;l%c8LE#83?_;mO~NJaEO)94l3!_qnYdSyQbf(jL*?aY`=C==ahVC zMh^(w&(K`DK$YGHHiUK?H_&N28m&0o(OSxq-G15*YP;!uQ}^F#)(Pic%Fi|$H~K%9 z?3oMW&0I+MdkJYp{O$LLxpS15^neWHAE8FeT^=(7B|CV~iN5sB*QkzinHLZg5hBGIT+aZ(S_n-C0ldPwkN;FI*n zu@T|MT4zh5mAIEJ;+d!Lv*GKWhQIsE!$GH(5vm7&kB?lAFqyi2T!G7gY0_Mb3tpZFQ5}nj-TJ(v3FO%$&Feo6bY7Nq&;uMo-ORYz zKsQAqY7R3L4f*N9HiwOF0ej{riH84vX7+RKFys2jCwTN5#FKo<%ZXA+ill`DZZ1?a zt4cbcYPS65;2!D72=kOyZFoVbLj7Y)5N{CA({Edu2r&-*=_lIlfeJ^!X^7AVjEYia zOVF+rdEen?=wnb~ErFlCSe`S+f`HM?!~QAowTqJo2u`%!H}&sl<4*gMeX}W6jPB z*?Mqa&4k{g_)x6ZNXy#7>&Tu0#%Vlq!mz&QA5vPQr@1HQz^9u%Qqu5!zpE5z9yfO> zu5mcv%K_n5vy}DT{Hd;-E$njZYc1nP3;RCRXwSqrdw>PbO=1f?e5Uwunt4MHP%La2 z?&Ye3df;CXF;v;IryLmvWM=gk^Q~PjUnJ#$&QV2|^-mPpbgO2{T7p3lT_3^{(Cziv zRdnG_cCg3M2Pn`S*$>K+`K2zT%sT}pyrFJwd&fIf2t9W=J4kg5%aEw1$aKK#Mg5ko zJ?+p3a&ybE0Fc6-8*Q^b7oB_V7euXfm@5I5Lpp&6L>Dz_^hTb=nCv7}2ux4?ISIV$&*sae9~e+#z-NOs4> zh+-(C1GPd^LAc4%n`HqyZhT$1aty|ougGBivjJvbWg77_y2~Sa&K_+VN5?^02giqP zQtRa{qm)qyiuX!nts7xf!g(0Y1t`mAv(q?}l!StGyhQ3|c^92(Y?JO$T%#XzU5w{4 zL*Iko-kk?ZG#pe6oEZ+ny9Au(ycSrD(y zWba0v8M7HFzzvX6uN#Mgwgy7U=agI?b{fTPI};XKS42c_y8X6oyt8R?pTWpUjT>Az zzvQU4az%dO%k_JD`8lSMlaHQHqfoxDJc)Dam4~H62YYPNu%uWLo9uCFHYaD>TCpz| zzc@tG?O0Y#rS%UUJw+1RDkyi1Zs;H$?0HwSQOMXbKJ#Z9kAcvnjsEl-rvrlx7tZ%k zX|4X@Cigchcc2DHka+IEks?}sRlD(B64HY_AGK28yVadxszoS?X2b2DziWP;4ovtm6Nf;Dhv}Vp1*AVh>Ml}bquUc&vw%*4g&?5*vwF~Y?(5~k& z2fgsFHug0U@F2(BK5<+tdlku91C7uHgjqUz8Ml|8v=C)vD`ZlilScxITr&84UUos71Yk zV~Fkk@JZ=xsMl%s`QNfd;aX)VhSj~MwjJHrYEL8$N{%N>2yp4P@KPr&93@>(nyv-~ z5++ss4)+hUR!~q_#BuNQDlcwa>Z7Cj1Mr;JTA*>b zZ*l#V_*!D1OqNbw0FYi_%Y5GiR?HU8dWaNpsj0OkmaPUW=8AOC+~Q5Y?Y}zvazg+}rv5wy>|F!Hlz^5yCP#s5&r&;`l&dip-8jX6K2w^JYE=Q!5M97pz*LEJu{Dnnwm}UEfy3zM()=ZofaT zmsb}u4aC0Af>CkAiXDo8W|nX~uew!K`b-2vx^Co@e|Yzr zCN7MZb^PqS^x8jRMNZ>R;8YS@+)|dZCeB|JJ8jSmsik;f_%j?UA#?cW1WsoJ_08D@s`#ijvdLi4}Rie^85G(8WAX@h=gN+qt>|--^DDB zhEA(n(QQgwK5^QZQ%6!QRkK)#pHLhHR^-f-*BziE6x-Vomy6m%n7LE37wh=|ie=;p zM+pJ7`?ze*&V@8?80V|kBzNWEgY_79@2{ja6RdTo{cs69`upAbdHdy%XSCe&yBh<= zDc!X`vyH8Fsn`sq(TcuZ3TAc~T5>%RZrOCwRj#u%5@T5fsogVV_xB07Ol&H9>EC9$aop<`0bW8#mWG zFAN#NdRJk|wxA0TkEYNk)1K;rVOnlYAyDg`Hc)yARtl}Z!*K8`kQ-xPC2X6*qethF zAl~RZ6|+;)zqkrVrmk3goyW0TbJf~@4mEnJ_M>*QhgB4hBX_PmGi|A#VrjcW!XO4z zUQ~w*gYqqP{uMRFp(b3#V|oczX?$H-$Hi_OB8ov{I8UtZ&u`9DI18+4jG{)98ISZ zeg`mUp^W*#PTuf6jS)$_vXs%wF1~TBG%@;x96J_m8}wf8x7j+I!ayD4>q8!I!FNFs zQ#2tPGb84XuFWv!A=;io3cM#x02J`A=>QOuwWSuMAskKO%f8zv*z3Jsldr{tq92A0 zxsaneG2rb*OCu2xpN^HdRg{Zs9f2ka+a!ez{kHVCaVKU@#^8#&ASJHgo2E=b0-#F| z4|~WJI>HF}E|}nWlpjMFIg`Q8eSj9nYnY>aK|({Iy4}0KCa{L{`^7HUxF921$%ic- zB@7us*Uec08t0^2M_j-N>2*^H2O33#;5COeAJ+urEMBbuxUe)aOm7OdDQ#Kc$M1mP=5mmLD+=K47CHS%DoUwOFYMKz zGO49Pi@X4_eDL3!1;xSTSLo28`B<7PQ((gT=+%k@YmTEp`JjrqGf#m|^~UPdhe7m< zzAEnQAO>R&la`TioC@oi!B#GB=#)JX+_ZhABChINq{U|lw7p=lU_zfKMuJ943lW4F zZSBz!8g~pEeU9d#(g5vQmUveKS<7 zZuXl%hB@7{WGreqB?nSAN1=9z03=OJ+KS#=EnOu{pYVhWbREgodzsomc^$7$&>PK& z>g~5w8VBu`%X;~McpcT(-K4U7M!?gROlDa$9o0?+sdFE`A{4Mo3&0+9DQklz^P&E<1n%d>LsN6)n9V2&T3(bU_{oF-j7Vm{gFPqOsB&EnioP+fj65B=tL;}Y8a z(}JmfLy*;g{QSJFKQQY{1KB@VkyNL#O=>6GV?8=$U28D{(onA zNqgIQFlR8Q7=1F0b~BGUemLlv+V3ec`-`bctr@(hVMA1He1KeRrJG}-Z(kjgInE8oL|GB`M2f`{Mro1xnL z5VNF{RDfOkkr@^vWoE-`Xu zkXeXEQ8bj^bUKg!nq=*kqmB2bfpCw`B2g^c0pjwa~6l~_abf!!Im0-K-jLN=Z6SR}i2NQUm$ z)6Vqf2Ookes$5I${pO8@jSZ;ek){1R3tRSYl3YHS8M$Eof;c`Uo7$J>l@ShpP1pry zPi*BZ{vuMx^_lD;8~c);r;5C*&?Z9!$*&Hy6#C1&i{{s)s@aevK)n&yMo?WdirF&K z@WLETZ%*}uWM{VwC+KE++FVSOkvzQ_ajeXk-uKR1gjyC6=>3WRNC%s^k;W3TRC1%ctYdI%&i5b$t0Pe>sX8k171LaR*q_V>gki-B@{rC@2ZJO#s1R4^XYY75_ardZ|(#jc3k_Kwepc(3$vVCc3 z**K0O`{Bl?EZQO^A}Mtl77*9$Nz5C04ULDf1EScFgwvJMG3C1((K;ccag(a7VqmXo zw>7EP$2f-Dd6)&EvjgblXYL*L>BmYUPr?)7Y+miiGxT9FfbN@5PSP< z1j7kjhLpVZy^#=~iWKUYe;paTJQy&U`COL~X5iT%KNVmBd~mgJ<1I=2gNw{3(8;XQ z@umJtjUjOUV{}pSAdS2v+sz^GIJHOf<*c@YE@grtdzRY9TMH4==K3?uf9@U$&pbEn zU;3$*RaiL4l-N~n;akp}-apd>z_$;4LedvLS8Gt#IU=KOnNy~<` zgDN&1F%Jq810n_;W9nW${#|>N26`X8 zesA&4e#24oU+JIod&F4mTRr-WR@T`wq0VJ_iQ$sJVaje=_^NdXgv(GG%N(;7DiH~U z3xG|w@|8K(1xE6bXoxz5&i-RDS{`<{m{R^1*M=+DeM{zHZA#>5IMThL$XjZHaM-N# z-(c+o>g-m)`q2@b2TaYDG1M`}niP}%r43f_9?|`VwS%IqCl5gWp@XG*p@>7yR>}y! zW$}a{T(t{u*av4?Txj@O77c73C*}N=P^Puz9AZ9kwbSza-BO-%`1siI_0ZE)hLy4< zwv%||d+$}zmLN1*>4q>K-%dZ5jSO69L{=!+Fg3$<2UbfYh9~7^Z*Vpm&CK#kLx0JO z8@u2V>9R~qRkcTHiI-se!Er=%kVP6>X&PJ{Cf}QDRUa7d$#4^jb>GC(un1hfyaZV1 zP146rBj?k|&O046!oMyGkg zTO|nwOGObTZmQAq(+fQWHo`0xtVd4WmBa%-Q;?DDe7qcZEoR^7E+Y$$M>j|8YPtdG z9Q(1$62h-52#E~>&lyvQ{-*UJJ4|JdBYb6ORInn=s3CG#M3btT6*RYhE}#Mx=C*(7Fqr+V5m)Qt&@5q*(G~;VGSa__Mt! zBI`%@7QHlW1 z9;j||^lSQ(y=XqDYp9A2Uq7B`ySmEj+%&7+;JQW~*x(HcY47zo-AZNp72H6}|2|>A z{-I>Zh-jNn)(VBgSx>MgL85ZxWv9AQR~IQ3mZCnhzg6$n8qfql>vkJmOnl6q?Wfcw>D5Po`2!KmgO@-ou5OKkF|M!5ak<@i?Czg^^$mh`%r)Dla zh-GP9d;O6{rhx!ZW!VK;P$nV)_>Z?4D;cNsWj#emE68j6H(D<9Qv3ig* zE3q?0ZC)`=lsBCRpJXefWTU%lYi)uHL~$_=tXMMZbGKS= zX_!31+w4{1H>r-^fI)>%v-0I z4AP=>w?`=5*`x25%EAfWZ?}XQT=$vK>N1Y`$avZs-bAB3>d8D5H1Y&<7NQSOWKJzcSsT8&%|D4WJ!ZZj2Ss_7M|B!M zG-DAf+TXU`a^+4hf|ZEmGSh}eHjj@{ExX&i&vvxuch1#)8YR-0hlD^sO^R4fO3O}t zf`@0v-X^ft+MOr@V7t1`W>$Z-p3uz1a!h{Xcb%Bn^*`h%8G8w*}xs8O8UzCpH^#_^K~lP#uKG?V9$?4`P@d+wJ3Eae-EmX1DxBbECAc9k8A_ zT}XndbAa+mHVwL88mjBqs9d5-GnXumt>v6YuO##DSk*`y_Tq+I!VJuhNSZ&Fy)GKbaJIEDLS*->Y!05I4aoeeYS&eAbn6E$ABz0Ewf{Fcj8#dLK_PS{w0 zj{It(1o^;MrvPKPV-^;Py{6w~J-d?X5Pt?^vFQa6$QqUC5D6L@6wHI(;|nz zLGdUEegHW@#=og%5%?^rb`7Qg_@VJ6BDjpD%GAd2l1+H$z+PrcTSSj>L(pq-nY1dF z(w_(N0EK&jV$Mik+`Nse`M!?)7+oZP2W^S)_)qgVw@YPiH^FHr7 z%_D)WP#+>WsXA;MIuvXGhW0A5`O#E2oETgLsjxQeqfI#)sRCrUU72v!F z-~R)D7$7^E`S$KBPF`71pO`d38q;lgR8aqy#&ZwAjhp}%@Bo2(D1YK+0bL;{hMD`B z=T3?tEpu3<+(`rToEx`&O=UiKEVs zdL~z{J#~z!wIOxdiyhSLo#%mEQ)a?i>wPrlO;inzI3ARc$;U}3lr2LsY-~sK^2Ud7 zS<{iM!5fj5wN(xmFy5=69^o%Ju@02c{L~)UJ&PuAeym1Zg#+$df35d>?G&Y05Q|jWC5Z5fsn=cZE;D(&^n?7inH&WGl z28hC}9$B=U1)4tnVb!=f!A;Og3ia=Y-OP9nWw{n<0-f32OU+o&;sXD=TfFL35^onk z?aJHSLtzh8C-LSxk(pDG=CI)cYhnA_3a%BLSCWiLz!gyrOBVOp&}moQxS+84k=F#; zq{CJ|n8M0++&dpf?|N+O(mQ>XhPw2&Hw>e=K$5dkOvqGF+lP`KIMsCKX1KTbu(|fE zrr83BChS#6)84sM%tHlAu(C~A==fJRe|q@nANRF7>=)Y|dy$^wMQ)3_|<;`W=uOIZInBd*rWta=wZSzhs`<8{u5zUV?kJ zTEWJyu@q@bet-Sv$@GaYw^a-hZMiYZmIMGc-ZFzN}P3V zy(cW|2;u8L8h@{sL|YD*0gVSsgp3_KP(WCl^T?z|z59brhc#`5djZV&GUB5*HQ@t; zl0u#FejbBa&?lZ-k-%`bY8Vg5wUx{Aj!dsCi-XpIQ@>w2)hM^)*U-gkyitXC+#=eQ zBB3N6O}zMmn@8!u3S@8W`FF}^E5GL^syqGF1BufbnQ;g+Tb-wp)wFA@Ft@}XKhay? zL5zDCc0~v)t**}UJUqDU2w$aqTZ)}--wT|5U6YKq?6p>qyN7SFbp{;uMKGc{gl;E}3LZ8ft0Evsk*2 zZ|sI46?JweG2gRGWncmt=UkEsE&3*BWH> zwj2)r;qY6!HI{l;Yp3c%8F9T$nG-_D@<7q!8;s~@%obZb(4q}IN zOFk6?4VbR?nmKiYo!1y`Jn0(Y`MS#)S$P@!Iaql_wWP2LToxC&#-bMV_W={eCXD=A z4{J%prT*OH53l=*P4c*ih7+(%4pk`H3F4~&(H!Yar^|Iw`jGVX{(e>k@LxBaT#wxlBOA0QSj=Ab|w<$iFNCVVRi6MEqd z?-}i%F!jj%*u}j{@z>8|5^24|vqU0Coq|D^sQ&4S5F5~os;%lHgESfA{I{d-(7qg7B{mt*q9TXime53UPsbp?WgxCZGd&^bryLE^=LhNeAA+zdqU+#~R7wvbb zT3}|gXZQ;xnyy3)ko&k^A+fC2i|5AANfes3xx<4Dj*i>0hd? zvM6}Yqb0wg+*gnV_&GzaNmE!Na6n(eqzpF_0^q4suwxV0hL0uwNdwy2#cRRXQM-Hn z>==i@YwcBRjN?iwl{yGf`qI}~3pSCK6~?9@7d4h2zO=luv+F3(f_7^)?;5n27cOJE z!f$DyTo`XYLbquo)NS5>{TQA^2~1AR0sp7fZb~4%KC&9ql1Q!}c3Z{s|7Q|XX(@ZD zQN3)#44fDF-li0S{hJb*jOvEh(Vk7W@A2<9Jw?wIUc|$h*B&O@)s=_WC{FAYa7=?D zP);7WmEwSlJv0wPcUzp4;^-PNs0pq?yV%jnd8!#J@+jlpCEA6g6MV(+9g5{Wz`+kt z!u2ffOID#)a;@*HctO2fIhd3}xA%175YSgHXg!je6~NZ5lR6mFd9NeGDg>~)JsK66 z8yj!!1g*oj{(neCWB~uWp)=1M10l`NyKy!4Tt{A0OP9g8u;^X>gz%Bm=!c4~G@FYU zkJX33@VyW>h2Tm@XW18r_YG^khvfqm(~u>p^4ZYur~FNL;)copzrPM31m4OE&<_qN z)$V$z{JV~)+%z(i6tqUc4TusrdnTg_Hf<3Vb!W6QS&19bXkE1GQ>58{SqbCx;MahO z>G5uK{2>pjUaf|uV3Ml}!KciTx1kz#;TaO{o_mC^%tg&+RyA2gispdIT`e=euxQ-q zAUxNV{}93i+h%3!3rQ~zZjR5`PKiby+IOL_DC$$4aE|H*Y!*Jaql@;jL+Y%_X(W2z zupRi6I-L&t^%<7N#wy{49q13ie3jTqGe9({7XmAzTHOIUu817P8kZhKw5Qei`l^e`dO>N;>Ti|B(%%jr z{6FwKpTN)onT61*L2SubB4z(26p|B@NVitEa6C}=v(KKx@@lRuR}K-cMhmxqLpqdd z5P>KLcZlKvgv!IF{+i_y)!JF+C?7}j^|^(l0hA48Qr-#-fPeCW_nD615Knc@lwtf< z_Z6I3`Zb4j&D@3+&I;`u`#P?jl=xw&5eE35*@JQ|eO@ufYlXaD#Jk0gzu$efwarZ8 zJh>mt**1on+(aB=SLXD36Q)L-dh{N5z)tb^{G))mLP?qy#&9jH3!AzDaZOfCaM8|w zNsqOxigh(kmC;B4MadaFQ;@13?q=orvN$Gw<*gA?053`E%jXhx0vMzXSyx;h4EkOK z&bX>pH&?g>#4xEa#lj_-`S~MMAH1m(x6k}5kTOtWm3-x8ax0 zUV$*v-8uOh7icCpw*cVxzJ2SsiQ$rz$RmlguSL=%9n`GO2*r|3TKV*jHTsnou+wd* zb4W}Z<<0S8vGf6ZF2hZ0pG@s~```2D2>4=_AsLU&nxgwig}?Tze!1T}i#k~~$S-Bm zW)pSl^axCSMU3P2>f^Te(UK*QLD3kv?A7bnOu%^_IzFEuoGtBZHNrx)(9tICrqg)I zdy<~2L)%L?sDGu=VtXCjcme$6Vo5Hc@FewBLq8NG29snOm^R$RO*S%gJ;DJ`;C2Xd zW=HJnLHvP;i~_Gk$;J~d>Pjj45EaN<1M*43A2weYF@c`_gi1KF=3fd+k^CI=sX|m) zlI=b7xH+9*sztT(j`gXM@RCgFKm~%8E@WF3BuRp{MtrvPGW}3cNnqU^`h_0PMxL@L zl6c_=GwKveGJhf|H>z5uV%mQXvZ2rzn!eCt@gpX=w}wz}@-v+}5tsfQUSOJ-4xxA@ z_20#%IcLcik;g*fD7vI&9L%m2*s0Chf1Ey>l#>Pe4Bf=m$JM1tTWkkN9$n2L*;*@` zE;VnKNY%m3snh8687>9<%BEy%ck15i8JFboTNYn$hfQlws5Oxp0L}GFG*lwqJfwM3 z`KPu(Kd)#72&nXFB=DiMxE>ih9wql+6f{j7%4ytU0)A+)B2}!=|6I39vLeOrW$R|G z90mq@M!bkr-?r1%k%|zo_mnA04kxBN z5o!TPpJDcoQ!Pk_wkSO6CXn%<{#iAOcx70%q5kVPea?r4R^`wq!sGS>R*GGLNf&K( zJpr5qk#i6Lk)TMn3$zpynWwEz?K4~jK=VoPiaeLaNz|e>JGn-F4?Y;|pGT)Sql`TH z5XLf~q?dQT2n5LjC5eT0{03a2*GC|TV|2Ur2dbvV%;Y?JJhU7DOGCoB+Oz5%A)GpO zU(HQ~JBK%DzzVn@JVZrR+)#1I9$iqr{Kg+4`p8v?`f+8qX-x>(42VrYuOL z)VP8CV9!Mu!_3o%uP`<4)XvKuG1(QhH|`D>=tz71eTH+1e{!Xij*{ch!4BtBrq5T@ zDp*a9zI$xh-r|h@I*v+P7W2~?;urdzqzX_|btFFwEDz4B;>7+lG9Ncl zK4xUDHp-&p-MjB&= zi1vKno!#D$a%_oMOso7$5aA3rcS?VIPSAU>>{F}lhCt}q$TrQD-<~O_5%r2duy4y> zRLfq;?_-*-t)*nPw8!?ZxdCcd_q61XlDRS)S{l6i*H7+}gc!`96r+)a_&|j(n9wa? zXNT%_Z@P!5et;P)?N3^F^2FIt?PJu>M6`(Z<}Zcpw2Hk``ex*DsP}z-hJS(wgbVhY zdywP>b>iPWX?p3Cp{zq|Ut#25Ot$K^oJH%0VsgnU-CboDw+7xYVmRZ9HH0!w*!?3z z=apP1UUW#MYHHf?h3@y9N02>h&sneRS!@-MgFM1s2HG3g7A# z-!G4l73tXbGHhbfyZLNmYl}^=Cv|E?pw3VEU{VR~#p}>=Wjp696n^bEq&_`~O51y4 zgRgNipYtA}d?PEeqBZ}T+ys^UYOilXVM~>ZiTBE|xBf7Y41#+Xh!yC7uz%f40Wa2- zau%df^qJgrmifR#Z#F(6RhK~;`n`uUS}k8D#FE{liY8%LIDC>cGil<6LRp)KMG=Tn z(J5!f3=oA`<)R9O8aPN>=15joLJ!RL9|G&WUfEC5H{o*uE^`N-oLU z0Mx!HV@weQ5C|=LoY+XXlK9`syoF#v$#g%#fNfpQRFdjasAeCi4Y&a^*!ta|LxO5V zQd|s|Qws9~4#eR(%j!i6Dd;EssB31@QiTd2M-1j>a zsESz9%?b%M`)&T;rsySsUqm^8^rYw(XL0Wx#88H%=`Mqm%EpL5q@-mYhqdpHl~5wE zKuEi^C!8X_9PdWn{zypTX}n^v6D#e|7EGm_Tw3M;0S-a6qHis5CeGv$}n@IK>DV$Lo#taxIXG|r` z)5RrEqJ7xpI#`YeI>_i3Znu%QsEz^cO@6p(_G$5SWio0Q?y|secR^y#%5PA{g)QmF z20d8YcMp#FuZ25+SKM7~>U}Kiu^-zcdZY%&e%>0ak zMfo}(l{#7*Z)}GXH)i=`;3c^(sgvz*iUf=aBL2!O+bQTbXi`w&K{UwCPDBU@bWU-T zFQ-=#w-_U2;$FX67$e-~))Mx3*vhJE$!LFFX+%MOC3lR~(HdG}QHxqxoPd>1JpBJF z4L7m92MDipu8d`ryI2#AB~|VA%bn5% z7LFl(Xyh;j36tYwsFw61B*2hg4J;%`uPq9(G>snyk8&%KGj89sJA253FCV2E-TXSl z_v|AgN?qjaK;)eOe#9Ju>sqg(H^|qe10C=TjHU z%V+^Z)phdk`#uC#R;P_zL2jWC1OgnSgPQ~$1D-+8C>?d3Y z9P$@&F{Va1ZTVHrhVQW--o!P?l^`e86=Ao6db|JX3Fzxn4j?ap{e%eS{WLMr2*&Np zta6_4!qBFWza1|*>JZJw+zT#jLoR^<3wPe#T&aX#p1{dQw>V$%Wi(2PCcjk(!3kWHKw|DT{j^a<}!q8X}2CfZ$j5<>JkBAosuQRB$;fhoi0Q ziHPo+0i<+avK)(H+yx9HSTgf;9ZLHTiEW-pyc3syH_k3+o7k#^_H%Hyd7)H(4XNt{ z*5gEY@$|mWV{O!SU$N{w_p~;1mZlKtjer&GNo{ntV{Dkks2C_W{j0O&R2`R872}Ak z9uI&@K!X-5m9Tu36~&|#<5@gWwF(b}&!o)tO_REp!Za(G3dZ#f?(_+G4Xe=J+7uSWl_!% zr$Sk{QBwvjB3T34eXIN8=VWGpg!LV7Q(?2a^&N|g<#eDTB+MVuDTRb zESL%$zjb5DK}|IC_W)rzw0!~R5jOOR$xBN1am~4+tZ*!Y%i?f2w;4|RvosP+#XE5E{yjBte`am@XHE_S=3t1^7o!-~vMs`aoP+1>KM_-&)MLkoiVzh`G@~in3yYN`-x1bk6*_*|i?_AR6PmC6WTJ`tfl ztT+sH11b}2Ccxx5El*O_29SG^@BYcE0IGQ01807&QSqYAs-W@_`tRpSYs1^T+jFI_ zRnY64p0U+w#%>?h>3fs9-mnLl`t)BM-H#fM1=xbg+ASowFn~Bjh}THxsb^2kvGsp; z);%D&Zt2PbUbMjzAZR|St{e~!eMO&jtR#epfxWuu0|37DMI}|z>)TY;62Y9Ro#?oH zU@DZ{pH<%yV#2}@?Lx<{wW~rZfw=yi_I{g?@S7Bc?zQ?Nst18Sip;>ed=YydCMQ_H zUXUGXT5iH|Wt3O_0;~tUjDoANre8GLPLZVDZ** zNqLp&UV#xqGJXkJOQb_OMKX&emvva!|AroQb!Pr<>7C;P24+*9>qmZG-;`$0=(^_H?UFc?g3M5>u({$pJqPdSd+2z~6v~5b6i(tV5eJ4T zUFU&>Ye9rBK_65Ylq zpvTI=R#Rbq2RvOq&(g3+hx8ZF&uwJBtm$xYir7}mud_Wiq~to+{Ms-l>r z%7vxC5%omB@#yH2qCEfLFNF+1D4F?f=E_tE7@5lbN?r3HOOgaV>EBFAPoGgGGVK7f z<}z@iqz(LaimvcOuf{u-Aomiumd{2F3V!if3;Q17WOu2L@@ZooNQo)fxHML$E~zex z^5Tv|j)yP?V-?>KNZ?{sdVX9JgZ&wND>6@wwGXrK&Qr0T$2G3~{@Q@sN3Ca+md$`U zYFae-e$G@FCzG+5|JyWBlr5{$At=`0)|$VQ@~+6e+R)Da8N1vol_&5YVjFP(v|yCR zE$`76Tsby!$PIw$G5r%PB_W;$7BF923Es*&{LZD@lXlX5fZ(Fo&&}6{@Oo89UYom4 z)vJr^nQlW7qhgs740TAO!1a%eIn}2C8JCxsYp17t1V!FUU(L}c{q1TG(_t{oiFZZ3W0e3O3zV8x|V@2B-?RO10m6G%82g; zQ=8d1lTdiE9)<>6AMSy<`-tBKYbWFCte1D;P!vDCq;1o?2om3(k7{Q4E=MaRRn|&b z>O82;mP!3*@BO5a#9tJVk*-4&-D` zX*Dd^x#z$Jt5@wd3OsgEuV+qJ_thph79Y`8SeE4uo4h?<_GQ+DmX8JXBsP!2-aB)7 zN;ZGi6z6kKZ3wnEYDrhkHPL=^>xs6>uX|Q^dubq{nPOTOhL~6kTr& zcSKKFNGw-N=o_R7!R31j-lCE;lbYKhu$k>ID|6wsU7LP0TTeqHrBX)U1(W-R8QPffua> zMH%Vt$@&MGSGSI0y-P}U-nziHx1(R;d2FQE>OHz(-Ek6|QjfyWCU*NRuV;`M(*_Ek znbh|F@7~*YgDd6B9vMga)6pq#m+TyQACsmx18sur-Abge%c|gcTV`Ph9cCQ(|AGC! z)krCnR+LzNM?TF?$QUO{4ijJad@+9Xiqm|Q zP(E7K^)O`M=*|?0(6LQ9VXR*egL5J07i$k_4a=V;|E`OOq6qm}$tg&KASJ*0Zt|6Ji`8|FBsF3*#l{E*2XlqE zA|ooxQwKr*(awlNF4*y^Y=6$Z&iWK&A3&mgjPp|H%ADP*>%t^^q8J7G7Eu-TZK0^p?%xP7+&3?9&>bcj0!~=}3QNQ8s$?Xo6)K63h(HH7=?os7e-QnK40R zn?1tkC(l2Kqih`It+ziiaXb1-1c<8q>E#;-VEMxEI?8tt}fUTD-+z@bVU;2Ao) z3u0n2>E}KTwLP7|dI)aD20KU!{msIwFvBNPJq7Chl+$}rbEE4IJbA&aWlvqjh(~2u zrw(Yf0uP1$H#q-8@Cc0rekNKr1{Z>wfulPa8g>4{qSKAcgf`^|2>2jo5sIjgATvnr zx?pnoFoxZqCA?I-`?9sIpxPPYlE!@|dSgq+SG7a+qk+f9<8<}Jt2%Jij3N3`3Cn95 zyhPi}v#pKN+k<^)gmxqz-Q(xMbdHP_lN`B}~i_bBRHnjjQ@_4&5Hp>b9GfKC^YhdPYdlZepLDyS%{nEhc6cpwU~vDI0Hx66xMb1jqoUt*chtRS>h!^#tF~xtW`3 zMQ>R-F}1V+Sw58b#LV~w*-)li>}En6-Y#ymg9EZoB*XVYAQ(t{Y2vr59XS~#q834O zGF8dSU`_u(He5JxR*cuJ`WD)%$oK!!)*?f=di<;bCzQrAs3%;>sVR5XjnHhOrBTHT z#OYQ3_m6?i0lA@Y$t0x`#@DpXsIWk$+1C3bqM$EYC6S-nUfUhDhjS&)41OSR+f zndg%Td-Q`&gi&^#dg>qxhN>&w@W~zsYSfHRU*935@7=hm!d=?n!U!Iu%|Zq3@GQEG zkr69wB3bF>edu;a3x!g$#t7{5FFDs=;qj|{4emH(qYqf05nR_L!(@J z;(O#2)Lvlh;IGX&=@ptlDod1C-THAzo!XK}v$9|9BtYU+;0z#-jC?zgn)O|$!u&3j zcs9yrQq3yRi2PYpJ#aj%&=cLrcQbE@9?1C~uVrxgjj!vJh3T+I6zG9JyZkhys{2{4 zU${cSk5b#?HnHYfpGxu)nK&0mql8+y+jBz_@}c%zs)r_syr`Q7n6Es>3`nu2npToo zwvX~w7J0ICI_t;H!b)PcY;pVD$?}=%>{tty+NwQTNWuK}b~48l<7+C3gJ)@Z;DqNn zEejk+i@Isv5XkfKE9dWb!CHkxqAy1^Ues{@qaA%~m7-iPcG+8C{pm6|-sF$6*IPt; zeHfaGgiL@AN#xN18k*QBr8l-~tq-mL z#uy$!*@bjC>D(03r1C3~#xCKr3D-jvuW_a#lwqtr2^^DYXT@ZF^NILBiyY5yeX z#l6xS&6Ha%mgtEHYLdK#I2WG!-)5b{P}G?|a1K2Kr|r`f`m5VG;;qYF$z$JKnUoK1 z@y#6$4o}DgD7b%tg*`Mtk=mMllo5>kyY>hns3JDuXYx>DLlv$78H6DduXKLuKJdo_ zk_U+*as<3_r+ZApEm;amg|zBp4q zcfQSLf6DtqRUf9-D&m64ezv*_Fw%iXnQxyN(KLlpWRk%Q0@z7%>lUmS2AGjOB8

  • !&PT&P|oM%C3S>*$?pI+Ov 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�c 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

    XC@OZTsd&%*;t#1Sa~BO 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

    PIhZDgs$D0^x@l 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

    ^QD>ecEJ4R^lD0yz^l$lF@b%$3KAvg~~oeT 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�z#<3T6;ck%g`diwQGx$lDLB=r=S+P9{hi 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

    ;r*R)L+-tPkzX_ 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

    6iS5_wNypx-zWSBA8uYnd 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

    #VT_+xD%cFK~!Y- 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

    $6`;e%ah!Nw%hip>T?a4* zGlfo)UdKFzShUA}>D2m6+{3)c1?N_hSxBrF+YSVvq1I8mc$GtjQ-4A-mIoFHV*l>) z#4^Cy2MqDse~e6$W_bWR)m3lo!&o{OT;a=bF|F=xnX_@pM_Y1@nOhbs+UuOxH`Ud{7BLy}vwXr7%jBg^4| z?qm9ZLHspN>yjSh=8k^q*&zgHYyOF}XA*Mr(cPqsBL`|(A0C{I-F}3U1Dfth(eU@H z_2B_mEFz957MaB+bL+Ur?vO@UN_a6%J#aX{(k3VImYyr|%+``#e@*r#e{#OLguSp- zCc%n3wh~2Ou({SPv#{_N!k1Q$#8UOOC$1cJ5Q|`z1N`r@rF)NbpmZAMqn4YQ>Tc{n zPDA<$D)?|rLyx550+~?elyk3rZcmQoMwIg$ZZ)PL$4vs~4VSs6Ul@bFH0BRwL;6q~ z9q37FLvsnrpKTI?=DvXnC1Yzek@Aj}eP^`#4AMA2_XUC`=SyXvC`w&_9mp0hv`#^M zfQhatb}BWc)TLlmfhVfO_R(>%ZmM`bpq+!+BeuQZfMTQ+eTLkZm-tFk+BD-R;E7LQ zLWhd)qDd+V^2Wfc8lEOp!5LnEU*MT69L zs-}T5JZ@mKD?6yv5oo30gPfGr1aoFFu&!JnVc)<3ee|5;65UnW?O}>9pI~BQU?ng_ znxJIz_iPm?OlkV+vByX95oU(REF7ZrAPn08e{=)~)6vuqgI7fVOi=y-x0NBT{9ale zly|iLQeadOAE^n&F}9Wb<; zmee`bxrx7b80||2q89wffy9kh_~2%rho-|MGO`r2=DnUTR=E5mg~_}F;!emrTRoV8 zSs1ffR)Z4Q7r9r5V(jJX)d4_|fBJaoqCZzkcT z2ly8r&3I_2GSH2gw?N$pRYl4le)SW*nmW_?k+HM){NTLOnQMon;%1t12-?e4jNCSL zaxVxiu=j<_RLbU*NITm)sGmg-9?n;W+kiYWNpyno7fK^;G+GtVbqG@@g#Rp_4Q?b5 zWgg~c>LFI(6Iaqjgyz`C&lakgCZwUbP_g&!o1@Cc%EKT44+FXr$V=m4KR3(0L?h;2lxX3;>5gY)BXM0975-Rf zq3qZsUx6l<6NWIEusD~ebqL?b=c3*GFlvau>W-Rt&>9+tt>~_GfxBO9htTv>u3acO zYqABvvp=`n^XZHl*^YP_@l6C%HMmBua$^6<@+Ax!0X0^o!nHfyEGs;VG2nV2U4?FV zQi!a$YxV$r7R%C+On}C^zB<|aHU$78T^8oS6f8&1J*&b_7{{d#rEybd$tT|A<;JAQa8=tCg2@RW*38r;R#~kY*Uady%a@xA;aZ2hLw&z< z_$*5;)j#?w136HqT=uLCzsjPXd;m9!IhpmAzG<{m)NKl(5LHPbsv>>>=z2t`%jI3x zw^-AMC+F*5_Er2_DA<4bGXY$M=scY~DN}7i;uB8bnz5KGj72o4Z+Kg-tK@tmqry38 zgoHdAsN`+(GC<&?3F*)lv)NP=YyeQrpN3sjw`Cn!sP1p)S%OKH3OL`1DR6m@$7mn*nQgbHC4>*r8W3|-t9p9OsQjg-cDkA5<38{^tCnFpL zX2{(6hQhtEUweA2N(RH`3y2w?NQKtKW5;)yrrNMHWZ6KCSIQbNtU}2V0iiRjpI`Bc zC73v=!&>wDhfjXLAZFSTS!yiX>Lg)|3sI$+6?j--bL|I)0dVcC{XVX zK!NL?mQ8%}1ivT3U3-f?*;hSOMzlE|LJRdS2yE?2kOGdHkf5EHeLK!>G7c7Ez(qzX z0?6(pw?4{m$s+4f^I|!lcAl8YaeAii4Y-oPFv^uV(H<>%yBLVVy^8>n%O^kMs7XOS$vDPUlVfNg9TqBzw4B4S@4Xo=$-K>Iz4 z;C_s0D0%KDM_`VgziX*~F3?0C*nNAdn1xzO(sw#EMZ5YKvff=<^aWpPJGfmIqGIOg z)s->t7@=n5d3U?CGhP)DCQ2)%09<@PM+RBOJF4&9)F(|!U^oFWKn=9;nX~qy>fTt` zW^d&uH`Fm9XpJ+5Di}LD)w6pqh7m_Z87;LshJnky z^KpY_HH^w4G&RI|OydX;lU=L$sx6dCwU|bsNDp>CYJf`Aa*>$0yQ_#Sb2V)Xb|>%nMWq{6`@Uz$&ra*L5)e_^vT0BNG1p_-T5c8Gu?ZL zrhSw>5wurmINq=ms2GCjU=z(<5f@Ft=2DP=?LNe+RUF+hOeS+lOr?j7O@A^4PVzvP zJR5{$m37kRAcWhOi~jC;s2@~L%hL`Gj$xV~=vwvpFAM^p&FNZZhWB}w{T`P4-s!{{ zu%q!!oq!BFaFD^Pfn*UoAZ*;ThXjcKFYEa&F0L^h@J<7XFIPD3XAKKH#4-?=aBJ|h)qfRE^#;B~*$qWC7RN*a z_PyF0Z72-K2 zQFil0Um*urcTeh2EL9`Sk;41A7JqGW>%bZlj=ox$LjfZ(gE9SLJXf7Eo^rvK%3Hfz zfV|vv)Ft-9|#1vH%{il6TvK@xw-fd-NoUwKG5T~E=#+a=gLCP;=ZSQl_$U_H!d{R546 znR@vEJeM{0DY@LO8Y6HGlW=J`6)kby2Xts*nvZUfge=~TQH}UsA0y4^^vpXoedFfj zbUH6(>*nqDasg`sS5?t`^j1zD%Aoy;>>Pjg{)5O$zubuBH-Gy?f^mm@gz|Q;jO681 zaO=1f6cyr25PSidCs}23PV0nOY+n)EnL7MHh~Xm*-Y5XJ>CekmKE zAiK%Z4^9juFRYC+5eUEY2^ew?KjsiZW%E~>x;Mg0(o>kOjd5OUAO!jO-`NrpBQ%Zg z=?6W?dwa9}`HBP7?sgPP*yn6c0C~T#+|zLk)M<^FEGR~Lci4e@&{(owSUeb3dX{;7 zUyd&p;M4U(w|@n?KC$L4rV+(pGTOUF04_y{M@?VzA`5c)vYG(FK?tJ!L+*U%orll}i@`FS;@?02AG} zg*hvRuW#!}hAA&DVhL<$V%EXC73j#M21JS*+K(B9Wr2yi$H7I3to!!X&bI9EA!gzI zU(`a>+|&yN%?Z^U|0I0LSc==>tvZX; z>SkXLY+_*{5v(EXevQDu?XVb(7CL~*W0x|@%<+WL?c-jKv#>a+5|DV zJe;syK(ElNZSNu{?{xFe_Sl4KV;*Bj`AA z;}hO7bPqm5ncAjmZuXR6z&UX$cOK?7O8E$6fsXq)4KSP(n(Xr@G#G(_e3UM=p#!u~ z1MMr4d*wGJht=|VSz*FDB;^6X1}&<7SPFHiz*|W~qVaP22-jS22<7e)hIO1#!T-)g z?LvzuF+68ygiWWa0XT;Cb^}{H4i}9$z?J7bVZu9?`pF?GqP@tgv&E4BFD94V~7o+g>hs0}Q$> z%mTf1Ei)7CT+*2{DI1M-g;{ZXLk~-I2Ub?LV<6b3f{9hTdIL@pt&25_U&M(Ni|d&S zZPGoY{Sa>s2Ku<-rF_Eo9-dAnBa*st66;=}IkC@$0D6b2@(s&b0A1z*QJdrSQ&m0c zCYOkK45svLLJ5w!Zb_Q6en;+#kpmhy0)Kob29*qu1_KL8go^jD2{QiUeGG?{92lJ! zB_*-6>@3U+9D{@s39Ry}H6Tt7rM1z$9Fz6OD$@hXnISV}Wv>nCPvyNhz*VGK`ODSI zv*wj|lnK>10)-qN97Rw<4^}=7Y8Ad3Y6VQg2^E%ZI2M{(??yK;>Ll^8#v$$n8dSp9 z?0T}$emDu6s+9wL*{^d6eC}ysBCAN7@FkpImOsFGcuRnIFvspEoq=V*Y}?#{(F%hkoQy2BIX2BBZ>I3i^_c6a@Aa+y);aem>gpaIn0ZYuB7MYX}+$a?Dr4_0(5{@3bm=R&@~ zX-AsNe^t&C=oy~AqTPUJ3dsTuG*7>~5opbDc)zs9%~N0!aRI#O3rxd|*nNdnU=mxC zg)lOPIalx6v@07aid1DireY08<#tK<@JJLKO>C)gf2|$3;Wl(>d7O5k$%dWZwP9KX z<6CY>jtnM_a;iEq+Mn8y(=3B^L`baiZYGR#LtA#m81&ctje%mT1xQ$-z%0jB>Uh0@ z^)z6~@&BgcOrc#XMjn#bP6o*oYV)PoZIP7W=ZdGT4NHc5vhs)<1$6Oj>E)PVPD-C( z^;C+_o@+YGi*j-Qj-PbQ<6p)?tn$mb7+a!u-%tQfdUYph&FW(kv3}vWFp;Rp+bd7<}7{c*q>QE*sVq;?7%EmSX`} z2KYz4O&ZEhCh5t55V>P5C{%^Wh;92u+)=VLqD%^y*fyz$%Qz%uBjMgRDb1 zVY&Shwon9;+q$0bEjaXtv`H#G(rH_rB=pthjA?mIz1KxF^A^M5PIPZ7sBATEB}dIq z(3`y-&7g=``F@yg=KJxogV+EpCDwO0z{TWq{gX)jKo)z(^WJZM1rI=6=K6FUpjP6wmO6 z2H_s7lR~~cC@Ceam+-~Wl;X8|NDl%VrgnIaEx%!{HAgffx+HmBdf;}TB`(>dF}bNA zrV~VfWx4UAX>6xswwH^u_9Yc`?g#?|=mbBzp_q+jN!ef32v1pz)bJd~GhvI;o}dO+ ze=CP9_Q?W7EWSK>DGRxK95J#vZKOahH8&^#)~<0& zZ^xk~9;hy7G*Hm_81@^_A5b#*Yh`k+{Vt@RbRq5AzTZs=48^MIdMvD2(X786*Y7sS z2G85S>cHZuVU*ULU8x0IQyOvOb6fO063WN#0KD+li|%*JLC6Xr1()!z0fDPc;R0sE z;>#igPX0^eKz6ijfZtWOLw*v7#K~Y(yScR2`*b$Nup7@8$l-Fl56vtHzy%BM2&E;H+R?@Xun4 zS9|xOMXCYj81wWdZyu_njv;%kpLmVZFXdUq$|qJud?ms;_8m;|euJU6Z0;c~kNXD0 zJd$f$CwiH8#_^9#(VW=jNrj~XV*^c`DdcnI6CF9eH(c8cFM^XL>zge`?8R7f*pWsj zNrbXlFZO$DS_voMD{4$#n%tN`1BJ~7jL<`isz+vb8*`oM56i}QX`L^?syzdko9NCy z8^MpK(Dt>0iaN2<4Rl&)4ZQ|x20|n7GyWJfz{RcHqxTCruWRTjk zpMVehgyFO2WV7*9;PJfMtnz_Z+@Rhc`WGFS5}Y=gkbq)o;t35u7K{^d|~T=(_18B|L|t0*r_;B$3+qU)_*j&-^~EY!%0H;ni|P3Ezk$le*Au}bV@L~ z#wMziMVYZ*hF}*VTj;YSd{{!dZxMm=NlarVdz_VQ zN@*lm2?l(Ai+DWJCC?Lt_kG(BsSCjJ&Fn#{X6Iu#a@T>k(tb9o)%lVRHuds|bf66n ztU`1dPhGl0`yv6B=sb6Fjr~j#==ujo(%zZ^|ELW4nZ946&S@H=X=w9L+#?mrVegR zN&u0tw2Ye{8A>8A;F$EjU`>iL_!0~^z7mXu+`kE170#PhWbHN?ZDksEXpHSA$*j4Q zyn||G?0_Wgixe~mqvn%;4j3@5mOgSTKql10htXMxTa8?Eek~{Q*3#oR3U5HgZPAPq^YAK0JE5Fok7XmB3gMsg_`1epl}F9cIijP*TA#O{GCk zA1x0sXv9x`qDB)bgMoAQM~gtpdQHtH3xsy2J`}zuwc?I(qzg?JG)w!m{>PwAE*ckY z%&hM=O}?_5=L-U@cpHw4@&ZZmDNmLJXel3m$@eE+y+2wmwy$LlbfHv}uS_kB)*0SW zXFwpoFK5z(Jd+LJoi%L|L)>nQ#Q+1+&E$;`=Pzvh3en`n+3O`k^6)}hfjABI^oao; zbzhQ86hL~X)IAYyB!`YH^xn@HZ@yS+LcP>+ROdOn2zBKpVE~u~IzW(x&N1Y>gw#1M zpGM^N0i#G=Hlo{-y!zkDr&a*UG0-WCw>#%D9WC}7YAt-jMMW_u37P&qfdGTEz(TaY zOJ(Q9rgF0Lc>eRg>L6{=Z#yA`-l4h6W2I-pPVgc!Ps>IQ))iIQwy;~)nKx#rL{ui! zJcX-Mi_+6WaF^E%7vmZQ&;Qo3Z$O6!iX&}@)Fuw1G53@NC-NfgGEv*fJaLQbHML`y zGR(U7i_6YUuSCr#GmhI1PQLti^6KxxZpAFBtKLopebl!TR^QoNZsRwVc?sidpn&*wqEHf*MjFig!hc)%a+wQ~TX%f5pd(IpAFz4=+ zfRQfZ{MZ5A%Sm_qm-X|P#Y@aQNE|{O;Y5l97~*nfME!egts^~~oltq?B19dZouhEC-8>>~E&8*voL5?tpJ|cLMG7%R(*5OU=S^e*Vu0os-b5!0Sj0sl;*o&=$eP09bakfa>qwd?X0a3syr`A< zNNVn~oySey@cXTyX%M=tTgu3*t5Sib5HLgt9!NPb4|!P`;vfl`Br&4HD1Yy6$b8sn8Hl;TKAVgmF&9D*3 z2}Te@m}z?pPB5}%4txr7=E?shrIhNbn^IG~vqW~Ed zBP9{8)w&w{iO#)5Ro#_(7wYvA?~j@;)px?_Yc!<^{-i)4X}_fkqz;(z0fsHjbSVzn zA;n{iy56*mWu|xxP98`~kS&O{OykPR@pTH)Jr4{B#vVF`u0xN~YS~ARXCp@Q>QDR@ zeg#&A3QbP!bJ6ZGikA%>6>sr#6e{$^NJj6$AX3Fd9C1JZj}`ywSNi}DMhA)YL_^Pe z*^F0nsNDgQ;;f0a!?csOXj!uNh_ZubH#&rLIr~LqXSNgGgO)A$y~41 z^T#NgBUsS!N}(BCqFO*r1%Q(j=BH*YKay6ro%sS`QyEI+B616`j>s@>@|_c#ZTKj@ zd<->=`T|9K5_lWFpCpWFf)C|I^UX615XuFc;j|idB89}O_-y-ovJuqyCs8hpK@>xJ zG_otG&{DDFFG9i&&Cu%IbtPBU34t<>%}s3LDX`_?v11B|SqGM^s=y8X9P$mSr^w@b z+_nM-=MWEjpd>x)wZkI3rKN-gT?t}DZ=D{F>od@GH640|4W$2O+D0E1V46v=D1J36JKo80g} zq2M%4^V{{yreH*KBSNJG`&41>@R|-YMSUaRAWidL?P^2Hwm3-N&z;jiGkp(i_}3%X zLRQk0}f2^%9)$u0P-T967o zCk-Arv78^v)41zL629ZajMdB;lq)W0vFr!U!qn^msd@VQk0R`u*rYWzKnW$`|4ewB zQI$J#TPv2u@YpcN_)8Ve=r+L}BF0dKB1f5&8w1=e9U~U(ItH?9Q-$2CQu895uM&|V zqAD?&OHb<{;TxED7_lalsdSh5SkD4ZjMWEA?abNeg_E^m!c^uW(lx=`uKI6;R}3ji z9t6pTk#}~`L4jWD2&0Ob`qN$$G4-cc5%e%}62UATbPJOYjE?^~S4`D7b|Q^wW5Edz zs+s34nWYJ`NBKlS#h7Da@<8q!52!n2yTsn#k;pnRe5xQ}`o8%@X6BapF=u%gB8J!frW z$HsC3ML%bf7=@HqUwGOh-Z*d3bOhNk=Zo8ybO5Y{m^E-P&_gqfI{2OD3Vcf|w-YCY zr zl$+C{_=gXEH8^N&T-lX_2`*lXD18Z&yf@0QQ`Lx^RrUMCdbU=Ms++Wj@y17(nQ~~E z?cr~BYn>HDe>QKH`+Ew<@QaL}D=mr>Kv8MKGqYHQl~@-hd-5pZ_2oI??(?F6*SQA#3UD73MlwZqn@5zHEd1#kx-j+@hZYQW|7!s%ILXR@Dvszoyp zomKLC+0N39QZ{Pu2eH>=?pcf2`X#E~EG!Bx-GZ&TgnR97y(S9BD{|BLxq^_Kc*BDz#Vf1@Q%Rhmc*Hx!?g8WQcXihlT`jN3?2VZ;Z z(#j|3vsc0H%^N_{m(%#?$=q2hH`2FKO5tAPzGmLt_6Qv|GS-P=M)t!+qvP0>ihlns z{xOHvW!86Mq_KccQRN&$ucM1@lYuycwTk|GvIL9_;*HQ4I~&l z7J4gmwMk>~v#bA`h388|Zi#`VleW%-W#*<#H8M7;uiQr5_5pOr+uEx>d5|SX{Ad?T z6;)q$9smTx8@7b*{&`2r4_kfIH}!HZ1+6QvBcOI9g{1LKO)(7zj9<265&wN+Ziia; zw7_@uTh^D94k6E0F!0u9%xOyk&(f181lW&`H5X&{@TmF2@qGm;2TdT3)wO!jO>2>7$9{miGTSF2Q9bs7Pg2n7 zz8-S~7jdXTz#){Djs^s$2pNRy%_4$n!h80>| zHHrM|4;!#~fe-M@$q-V}87GkCoiQiJwq2cy#J&1s> z9W20;*~K!tAY1r;ywKjzMX;;}WJi6=St-}y-E=U;bJgAWl=j!%p22NsemnM&s%5nV z;}WgQ(FtuEC@0Sc=++dq3uCvZH8f(baK56W(A3>S6^=4S=x>&{P&Ot(oB|q{US4d8 zp}DlOcQXrSTZCbK0JsWu>JUsugD-VzqUCV^-2L%?kdKq%DVq4@qlfv}Qk#pSxOys) zCNlFgO1}%s!l6V(viq`+9)RM=H}V~ZoA*?TE-HACZ{}i*8?R6VC3FF?@0!GYzsGC#7XHSq$U1_c5U28_yEkR$aKWl71HLZyP(E9p-_ zThq)L#q#og&;5*E^XtFr2J!cfpm-2sP(dB4#+qj?4cmaaZ}nJND8XBC)NaLMVL% zA4n3iAfeNMqr)62Q7iP8A_I1b+Ib1sme;N+fVET8MBBo9JS|YSh;G-3h0xekeNMnp^_Igxd zr#)fkpTISIx-f7{r?}9{`MpZ0L=4msPRJbbucYgQjZlQ^&C~6T@={fHsOD9orXkKE z4Im==mhCoWfJnBJXS6V%O5-t#@qC|IQ>c-oAeRG3nB6&~&XOl7pCV-)lqczwaqM5} zLI6#Vx^xnHzB+(ZZId4CPC)y4J2yr@9!=BYnal;n)NqLAQEY!Q!k7o(_pupHb_k~U z9a-Jziap8ln?mI-o?de#T-^Lrj?}r#{hpPMNs<#Mk%=I-!G|Vml|Cx&-^Xt0DsiwW zOqDDsFR(4i5cpgYClL0^^rPG0&ZNIRNH#hEWMI=Yz$^L9)&P^$n5QA7w5lLKmt>GP zL+Y{cRaS_7l%?sMFf25zwPLd3K7S!v6P{8FWUwFKWNDZdb2v{e+xYkS7E-+IkOjAj zBFiDIz6r$e?1wGlzj$dNH&9?Pke&K?9LHNl#9!T&F^5bVgfVhJQ5vF)16FrwgtSR~ zoU@49=OxK4K)EdR_6i>}yhl9rF$$kj-1(h4vEbp;WS8hu;q+>?{^TjUf;`MbMc4pIF{Fg*(tssU%Zpm|$p^!OX`B(P?u*N1NYRGcyXk#d`Z0zEWd+|MNqIZV;-7p%mFLoob5+kl zaWlTup~P}?`M?t4=J2PmjhXijr$r1i@8PMSm!)9fkg$qvYs`v zst;NDn`K-!S*&sUpHiAQ0KkRB>4#G!3u~LWV1RVxnvgihsyjE(h$mj;r_C1PB= z)KUX5gD}^0cE@s&&z^6P4GOAW_q?+!a+r5aP>M)RKnjzLZEJ^^ae*LaGFPAIfe@{p zss6xP&~@~tjvK24$}y1(z4i11DvoEhS1Z~2?y0gM5-6)N2nn(Q6Xz>mI$YfeV7dq% z0^RY~+|VbUOlPW;B#>`3QX)S++k+7vB703xCX;{|J)8R6Jm*==j!g){L8gcY9xL}K zbuM}UmEeSl$wP)+UI`Io$xUxk>d6<7zM_3;`3$FLnX6?@T(t{I_N_k@HIanY8Gdm) zsnHue>ir_LfsL;Q!X#{HK03=4B~>Eo8iEx=oYk^3+i==+L_^IoE<QhU*N8E zvZ1FW?zOz;XxryU+f1$giYk6Y2MMiYj8fmcVeC84h(_Ley{~(c30}m`b7%?=lLNqN zT)pfBYMbjpaOE&}{z!Jz@}4E|(>jyWm#kg)wfZb;j%e6P$biP$I3xJY$^02W9uR!P z(yac%#uD-QLfcN1{r6AGNcTFGP~%inq=?6XWRG-%^e_lLHh{xK#+LouyrBuExJzmX znSyEGT>vHw#il+_|K)J!MYe(FfR_VSf}~A!@gdQ^G&dSS9PDy~VJkzPe1UO;B;gT> z5ERIGyB0`hF=@VuAN!R?zs3gKt^or>NEHq&;SiKvI8I(-EeE}01++P0nG(=N&2X87 z>m{UFFft=Ua$NVyPwwOwAhnjEACMq-fi9CJArQ)& zowHZ^YvL8Qv1%~~%pg57VK0TOO8f-3aZx2qK1H~R66tB^_CQXrUslDh2YTNPf~!v( zG;0>sG)zYjJm{(#GF!BMY;}rl70yi@RwXn@V}7S1K*fmDsnbDvyzB8=0bP6jzn-kH3Kr$tQc)K%q zGLJAfQce4R4 z(rw8?m$8o95$$IGRtySAS$q=2oIa~EoiwCAwAsR6s)e&gaoP-%_dMl7z%J#*DaP?4 zqw-~&=53HEfl_LGc05|6lov*tFIgo$;n%U**v1dv$03DItzU{^0$o5}XyN|6DO|Vt z@BFMC18AI1@9s^X<^z|!pdh)c)Ii;3S)Hd|WGq_IrKK*5#dFEk{Yo1CN|{NieV`qP zS+|??u`$c^bmOA!>%E-}nLQY*GDOhJ-V<{)MzEx!0|N2+g%bqEAn;lHZj*B!504*4 zJ*G?+f zRWwp`M8R~foX&86z3Sc5Mvvl~34=TQdKWk_|1vtdYvbS6*W5MlfMN**Xt!$AaA4Tu zp_X-2+meMaGyyLJ^ON-u@K2^(glIkQ@{)CiWqFaJ`&9g8gtQczupJEo96CxAum{sy|nYI|phIlP@_ZvTg{Mc-2aq>k=B zST&zDThQd84j5~-sLJM!{R+&H%hxE!W|ukVQLK$~;3#Y@H2p`UKL%|1y+@{sUA#DY z)qaf)#Kz~5R$C?E(1N?1{;Ia*@GbiU1J4VDErvw=sk7ns@!>=Fmxr{jA`^Afte>H1Jn z6X|ekpypRp#aORVYwo9AsyxwJ0!XAxHUzXUZRO3B%k3;DUgv8bAX|(A~kv8BFrNhCIc`-48;Npy%;xDN^2t5e?=hKH&&9& z9^~2B1je59aNa?H$h`Z}s}#W)>JIF4X*HkJ3&Cx5rVyJ~s@ej&r1_+5!rwe6p)HW9NL06Kw5`;{ z&H@4$^i)yyr#7a57R=r+>fpi3-c7ryE*RdGfj8dU!q;N5ZMs12dwDFlkxWmn^WiBH zfS`4Tc6mNfcuNe&L#SIZs5BEW5Sa;{&5*bUb6|5xU)fOZom2<6pfg-Yxr){F>X|TQr;Ln%GxP1 z<)n8Qu;?aVomwjfXI|QksEIz8peurKV%~_RJ#ULlF3+jH36fiZj-xRY z3Gb`>6vzB-Dm^e_sVs5laGyy(6O#!1?(5T^nGRpNetBJUuU}|l-BB$1l;hl0Asvkq zhT9Tc4BQwqTM)CeBd8QJtRD9s!UQ{^#dviL6*T(nD<&B729uw>e5U%K2b#fSzv^$a`yZ z9uhatG9M%)^K+ z&D^De-i#oM%^+4?2R<04>wK7L6d^au#?caLg+q;@vNTzATxi*pvd4ot_CHlBDD45R zt^uBlh1Y6BTf@2g8Ks>9J}O$1Jf+Xc=jfzp(%o)L^NU@C!YGt+CjuqhA1kHYZM>87 z=6v*1vKdP4jjtgdL$yWcs1Bd5^v5Zxb=e*_V@s-bTxS_AtADcoqyqSZHbdnzdv;`( zV~+34^9AtxL4w&5Q*phQ#!leu{)=g9b-xx-L473SM23e~eTQhp4PsL-LIsy~KO6p4 zpe}w3E@{R-G+0zi1G-gFCiUehhh&cNXOf8{mRGpqZ}`ydlB6WN$lC zJ5RL!Rzt`3ZYu+N-J2#`p?+&bURnG;y+2wqQNIl$?Nma6B2lxE*pPj|LegL+ITwgv zOxbf|Feo>5nuBY^Lj%2POg#fX@hJje@|SL2%)%?|$uN`zzUpG)dbS!tjK+-Sz1$lB z59h|&O}K^-Ow&i&wB~6uKPpU_;DVn8(H$Px+JWmOMzW|!W4&=ghzh76S_&Gr0@Sz0 zQeD9sw{gp;`x^W{v%SbS?%0OQ`m%?t&z?a2WcAPWc~s}J(u9vCpYbkR>`Jjuy-{oz zPAP#y<@wiVrt46Dmr2D;JOH5hsaNffrtp^P=%=TKKsW+N}UB8(`f6~M-FIRL(ROf=qFOz9gR zQf7gH>v{-deRg+L`BEHI<&?=r1u&-jV|d?~>j=LZtyYhV>~nm;@YQqDnOq6GPR!9n zV@5uspod?&ko6lf!?Sqpt=D46j~hfYVEz0@JJ0Tr_ksIs}F_{SG^xHa(~$*D6C z9&U4F%5)vv##Sp5dw&8^^I}6Z3jAX*qo;yeSs67f0XZSfSJ!6R2b+%+C&uu~ z%**OLCAFXpuyFgz=ann&HdtGQd&PK|m#s@q&=(Jg!GFt=BSVZ_sV1%2xG?+v7z`Tj z05<)#2MWZMw0aZ~_=*+ps^C zt{$X`nQ|-nnwTmRm&@&;<9~&Cj#c6j&G<%)6RW()D=K92ZH{BX+V_EARd}Cg@yYjX zsK}pU%fyr!q;%kC=MK>|TK9JKtgK@*)20YaE(~B*)6!!3f02iBiaYTmraGAyP0@v! z-z!0eaUzgBewJ8brN_ioTQ zCqMh1fc6zXjPkfqol*`bX!nf&qDSejgtK=wp`k7=pUM9#5+>?8G|_NT669<{<+W1q zP#PJHgY`?qLeSCxal{eAeGOG|z=e&vJAPfgXmFMh8oi+I6S5KS2grUzbBCbQw4+&r zdTIb1tD9Hb-a-l^!F!xvm2@hvn{s)nMh~ceSCrH2Td21vg%06KhrVL=8C)%XIty>&&(t+rE=3-6pc{e# zR;{_Lcb8EfXaE&n_HM`|YB#0Usj}=uN2B&zeGW#MfdB#`YNPY}^+U3;ZARb{sh50NDJs!_R#elR zv3DG6ZP5^-g!6KcKUIb74MT50YY2yMQE#SPL2 zxJekwsjTLRP?kQ%8p}6YxZ`kbeC0Fo3`{8^+|Q~Zkc`)Y_GlqL>77o=cff*>zF%9R z3EJeL0vB=Su<l7sR%=>LkQnJ6TNEX#nu#ybQ^fWW-V33eVAMTqHby}ZKC9aI`iS6-Wf+*z)72|`pq83I4$RNg@0HR$FE<%jP# zO4gYfQqC+H?CN~ej@B=g%Wz}&_pxC35CS|EM6%>wU5Qa7fG!;1{|eh)p)B?62&C z{uhIEFC3g z2Eq8g{591_NVkKTvN6f?cTLm>Fj|QdMz6B}9c%*BrhJEdnd;WmO(XpzW~jN(ERUGF zq-5YosQo?oO@V0>4KCcC!*>s01+ScGnOZJq5l%6`U0k~3hg)lONH{NQ41%zThH(Y? zhn9flcu1MN$$O71`fq_^FVfb3=Dwl)LcjfD2H?E#b!^1fg2fqt(%G$;eCNNqp;26Y z^X%LTcl~le_o@g|$jVS9vylOY(frtrUxMaz#!FeFWsZ&G)lkt_GR?)b4K7FS|! zp?|am=_DwO3n=)%3iw9gzsw#XR>`~G{1Wb**=7+Y5+ezqMir@I9d1xM4lndXqWN+j>aFl-u8W}x3``^3$-S44^B1W$WC!4~^jSgK^lCS(FZQ^iQ7CU#P2PL=3=seR#$Ot;#O@lG>y-J!*s1OoY zQj>)j0`fzxFR@}g<{$84y2o#fDzsWe!Wtc>l;|S_ET-k|yLsq!v4U+B>~h}`=86^Y zLsVuBX&g`=K;uA%?d0EOl&15{NhW~XDNNs6fVO0#XQs%1YJ@$(&J;R;O zN4QC)l=bIfOjtN_3fIXqlw+6r@}NqI@!_($su8>rFmNnpv*+!S%T0O?H%eNAX#>7= zc+pPA9vg*u6B!^y%0bJt&rO2_ed-M0;kl*cXi!3TE@O&iCb@_rI@o#~k;X>Xd?Q7Q zgt--z8OOE#C?f7DKG78j7Z#xemeHCydZKSD;XvWbyUL+#+`g}N&98|LB5^YiCP-if z=}|+0_ZM}eOaTRT4Dz+EPWk4CFD~%pe}WoWeoa$6|>)Sq!XO zPfXldY7_OD*<3B5#4ks)UhUSu04p4TFof{-Z`%sWo|4^g(o^DkK;Ck3Ptm7D?Q)8N zRfK2N1I9jT^dNZ2VB1H0!8vL}(tn0YH{!xULJDmPy}I~I;-I1q9^n->%6k4l-2YrG zM3c3b>BBCdO!1O~jL)HB2~Lb=Qh2rSF9)Ug|D$kuF@jfys>t;O5PGE?<7`YTcu)*k ze_i7hf2fZo_;fuZfv79H(0Mt=yIz2Nq7gTu*H0xjpFhAbi`x!S_&2FvF{1S6X$u5w zZ@!VU!^M3=$zS@_-?i@8VAo!=5-FJz%{>sn2dga&pm58Jdc@q`&$f^|p|KOO4| zbx8m{>4&E}9W`h*AYB)+iKgj(ph(t-;lyC^^?kK((yoGUG8O>y7>N7v{G<@V}k;<_F65p*GpN_l6AqE{34HQhEqd@zy2w8BObU+43dCs~x}8!SkE)zxw6u zT9`Lm8MFCn3r~ssL@>6csE?3bM zvk!X<_mwnuTTT-I8S*$zg}sK2-dTI4w3G%PE^ft zzhjO=ys@ZxuB?R312o4;mTVyj}cjBlCIu0y3+Rh ziy%1#vhO_b1&Hy#_>AfFDGE)KW!uydN`uD}bK5WQnw&%#&fLG514SpyJ^t%P+OT;P z5@FRtEKMVGm+>H`FtoSeiZ*#lXuHo+?&vdlPmgeNpKi^I} zE1zv9jPk<;hPlGSP$QPrKR6bc?P`jREI508zk{J_M}*)-f(ha1SXDXW)Qy!GnGKj- z6n=wNVy!zGH>{=UzoD|~@vwcH!_DWd)Pp1v<11TKAKTdpd}Vh>)aa@#{=qNQZ!E|* zed&dM9(S>lG>~fll--#!N;_2U`=Y(>cuf{HuPUe{sjc|y7=_UK4X~NQLuGN7cHZV( z*47YxYV%rb$X=)~#t1I5p>&H$#6#Q-2P(cg93IxWoc@BhiI3C>(!Dl{7(91i-?j!BD#-0W4`-{>+O1xAIKS-IK(-( zzWDgcl*$81{(8Va^~nYm2ee+g0{zHC3OM!0OWZ0PR!nY|jRo<;>sMY^JOWApT-P7D z2V-e?3rev*(Bs`ADY$uVj#jjGd$s_MPUcDNE(5jriXU4ib?N$a8|Qp<$h6c+m&)@p zlT^?kXb;OtU83T{V0bQ*?)c&o8NnN;zPKDK%`|VusGZEXKm7O6U2EY-A=hV<=37~_ z7DFC%8(S&CZbMob&nh=!Qo6%+7x&9SAo_>VSaWzjJxCo)R^RLFtdUVA+-aV2!rbQ= zAJT=&Q}cFjtWfZqo1dAAy+aZ)YpKy328x@UU;=r3Pd9N3ZI+2I?Sydx5Du(T1!!aZ zV_WdufTiI18oZIbk!qAu2-W#~2G)^iOdLXfxuADBxFo`4Y zxb-B4T^=ryI%w;a_sST`EB?wFfOt<;KPX7*s))SCQ850A^Tdvlz4&k5rn-9H{dD&v zYG!}2-P}wS;?yB~_2d;{QU!LiAw>oJ}X` z-qI2aO}n~H22*2Msfahp<@EJ7yN$FimHHRXP+W4M{rBZ zRGRQh+m-X(+-~5fJ@!bJX!E#(2EM6_-qtdvrfVcPTX2zp4CH}z8+fJ8@zxqFLE+fy^?Vp_NH<@R;c@%Ro0dey*)3(j#dHP@IjHBP;iW!oc z|2Rbp#r>DB-(0Rha@D~GH?UBDFTG$z@sJm}F@73vwAeb}qY(<3R$|Jl-XBsxe?6~> zxi7!91{v2NUPUT*nIoY`QZ#bY7&r@`?jlqYPWDCKaafw~)TNK`9PHf-$goq@B>(j` zICyT}*zJe87K$65eQt<>+{lQE^wzog zA}^T7ZVbnt9FM%c*q@VhCV@%3E19Iu<0{`}-sJ@*-@4?c0E+DI#|IOb^@ zBSw1oJettTc2#j@)ZJDwShnT)bAp^oSuja^ew6t~AKanH^x^+BL@#zFAp^dr5DeEe z%&-~EY!D$nyU+c3iOI2v%7@R7*P{7l3?j;*NK+G^N(sO!FY5FDI|+d%lj+zi1oa{2 zFRqF&n_&j>ByowPnc?Q2y-V!QRWzLkrh_nnB!%!+Zs-t%dk_dUVwlb7#^m0L}Kru*YCp~ zQ2l>kAb8Riz3U${rhd+=47Zw=jXW8~xa$YpO!c0eHM3`0Wo(pkPfcsQ`;)8E7vh{j zk;IsmJV~Q=pW+If*;T6(F_W>41En|td%F**=IHtRG^s0=?LWU!2MFZfWEB}c9bp;^ zdN(EL+$vK6(fU`lLzp}Syo>L+lwb;lmUOs=>3?9yATl1>j8H=aflqxGP?}zNFgYbA z@T2O+E6a65oL$>GQbmk9TM$6QwDF1VdRk(=kIPP}8l6QSH8qj+_uoX>FUwty^Fm*9 z^GwtPm?`JW_{r?Vi%Bu9Xs_+d`zkTL|DPJWCgY2Iy{myiVl!akakRtsBIfVC3weWc){sRRHF&Oi9D>;J;jIG=jD$19 zO`0#a$a#xQjWn}olw08^_Lyb2M^J9jokAWotwPy(U@Ga4DSG2$stvt#^-ZAsO(5YQ zTuxzN&_#w;t*zeeP(?nGvQo_d#A8c!Y7(o+H!dxmE}3~xQh;n?CovkdjiO}@sW4A( z#VVAwF#-^%=t+{dx>o&PMUs7Z;4<2C(^ell1s3j1M%4CtDj>T+2|0`T>5wQ=hmH*W zV=;x3_&I=7%WMPYM=E#_*+Gd3drHdb!x`eu^-IRd#2uo5OM^k5+Od_3fJ- z)7k{&(EQxy0FK(t@TTgzW@ORSY4f@ zI1$u;DP2VN`WfEMtm^4yy`yci6X{(b5iZ)*_;n|%Q@6tr_*NGpOFo3NpZ&N^?-}tK zP1xKPQip$xcs$Me{Yok>2Zv+bn4++w&=m|Ost$hyYyu_R*vn1w;7kmt!G>8Hl<0VK z=WeFp^DprM3O(_KeM9pn+nQo;IB> zmyiX8Cue6wKXbgZ`bK_1)TZ;i69hkF;6gv@BI**ItCeJn&5wptu;`T*eL*GL4_dT6 z{kDaKYn_MK`M3$1<);Y_D;2rCD7EYn(*_x&QBd+0rR+ThV*=g^YzjiL3(-@Ck7PM_t)=}_) z9hnqcJN7Tb8s3Ds&-NsF)T`}<<25>XvJ6=miWE};TbVXYbais{w^$IPUXki1?|0y@@VJWMw3c{XULhg#fhU_O&55_>u;01@k zb`B+rfIckaX5)AQxJ!LBz^gF6)#>$|So?qZ*#+otKYPh{t+ps-3*<6%DqT@Cx)?ZQ zi?9qXM6E|myk=6uLc75%j7itf%cm2_!hJSrRPZZNu?!DnMuFn1dDi?*Pksf#&(h3F z5bG{4kW%Ver0C;DQSej^UOk$LLZUe+En%A&cEat@o@Jn(e^g%AW|WIE?dla&uwwhLdSs?*GCnfky8Che(?Vg7mM>z%BRH$jnFf zhjkoq0DkK|80b)-X)gm{?I5m-QCJs@Ds{;%`H#0vYaZgk-Rc(cO1c||BIRvc;sU=I zb@a8aU6-25h<}&O=5Ay_fnu((CrK=p;6zvx?v}#^$8iZM*^74DM8s);=?ty!XlioN z4<_%?S;?0Z`9q+MN?Jn}jJ?9}H+Pgh8*{U<-W5rw(0~gI0eE{d;K_|>ewL(}mTNs5 zO@jezA8DVrdK$ded&oZd6_mv#@DW9s;f$J)-wCp`v{3C0U9TiP)W$F0Oo{h@Nu-$v z9M^6y`FZH-)&8NpjmUs9Ay*ZKtWniN+J09b51+*W7DC8S3HK4Il zP3zA|8p76rFfr?0%}9}!z56@V*e&*8wWU{c|T6q~z>;)#$C&uv5`D=y6v!YIG?6uct1t_7e!y-mI1efM0!2xeL+Yw6>SI}Rvhw0LfkN5o6q(> zcz~WbC{7~RP1`+fR-4otaq@{yti5UQzLl|A{7L|R0{-el?C6|7tEP9A&td5AMfzD;RO+7)MChXpy>czr2 z^X4{A#eLo&5l3XDDFZaI4YW>t!h=&gNr!$80=M#~RA$Pj7a>@oxIv#GVhw@2;;xu6+l`L@Ht>Im(FW9MD+Ft-kY z&VdPyU;P;6$-d`F6hnJu2dnB<84Y-tpb1yIfGqLMCvm9rekp5;LVzS_23od8NJMAh zzpYVHxyTk(Ov+MR{|2>=E4ARFR3GgRN4K<|f!_ z!zBQEypvCJpB0%FOo*LD!aae^$#6MzYrL{E?yAa0G}fW_HU;JM=OExqvUA z45s();s<#bIdj>j4Ps}{MpU(&^})S)ac zoytojQ)yR@&(a?ECJ9{j8Xd-BxXko){a^GX=r|i`SUbh>_HP5@b-tR0rci9;>9_mn8d=~+{u8jJLF9UfdTW2`GB@k0(^ z74X}t^`wL6{PS}uW*X9mbAWLv$d<=%Z)&WEnWB}!FZ;jqJkldHY6tNjYl?~X!<@UU zab=-VdONRMU-pD5ld>N6FxOW*rG@_y-_)Mkq`>^yryXjDO=Oi2jQI5eUD@y_Lo;VV zDygcR^B-zy@y?HMFUQsFvTs95BQ#vdvF9pNR}83lo^z!9+e$|!f94OKYec$fZvRP0 zIyxFt#kbVs)zp9cTy0HtH>G>;`!Z{hg%Bn*6>kMo4>l{dh>H~<2wVqu{>+1q_Z%AE z1JirurgQO8g!oH|CHA6^2VQw?%nOw@>?Xs|yq>3x=IM6xrFxPDh0sLlt|X|Uf1hEf z-sloIgZTIKBXW4$R0rHW2wXw8(aij*axK3WDwtkCtN*0*RdsR^I|b^BUKm<<+YIUQ z`>OxZld8f!D@s}F_It!+FM8iapD$@t#DWJaD3e9ejgIy~(`$=SqBtRwhhpgXJ7?AL z>z&Jwv9o|3a8ZLiON-6+K^hv-+&jq5y4lg|_F=>Sy{{H3;VM?wT*n#nMz(*9`{jLu z`LdbtGW}?|2YLeFt2MA&KuSh-P)Z;cT&y&O~u%$@GO z(CEVouk5(u%fzNCwRFaKRu)c8SnF>m`XcwA9WLmSuJy(ys^g%- z>8d{S3JfiQX_%K9oNV13V$oF5r(Dr0wwQmX`%LD0I0n8~HNan^A)tg!;nQCSZ}0Ez zb6zE_xv!`k;qE674bbS+{=4If@8t=xsL671SlP8FCK9ATx&veFO({#`G#|4HfG25_ zGLOLeG`aLeAQDqBF>l?#){pLjTm? znNL7X|E8dy0i|@2DARakPIM*vWtvMf504}TdhYt6fvvicXL#`Hwnt0-x0}ghiWsV{Sv&H1L<}O#h~Av{3N)}&>fejUM?UNbh{TVu&*3K-pdw)E zcGDs~tX1iI59`}0cl{kXJXnqoiKqSy$yp~sg;3)-idw3I=|)>%WsQnJzTVheYssrS z%F!@f5XOily_(=`&TN5aRu7K5ki|Vh&ag3}NE6VqsK}$Hg^hp>h-+2GrbECP>m|vL zT)n$Wp;>p=ukt$=D#%Z|7_ zcQ2sSvssgfb;8Z91RHzsnq2J@K_kbeHzmR?F4ywvDE8>Nj=bAKv}x>kePZo#{TC}l zcM2+|d~pY+KMQ1Uhl4R<>Lj0mI6yCqVeXaZs>{hBl*Ym}s_8Yj!m8@&cC#C$LFJjU z2ij>5(%aJdlf${*TB64Ibnw2zd@~{V=_K9+9(?Xq&SR_*2Cgx?$N9 z<@oveP=go4Q2ERT7p3zknQBE4v^)++9!|$REPSDi&*EiS*p4hA@#Fjezo98ofbtKz2O#rluy3Rfm$x` zN*<7*OB>rSgyBx!#LJEZMU&6vE=M{_>FrH*TA_EaaA~^uR>i|e$}9Jw{tORksM=Jp zeU@;az-%D`75eY5Nyto&55xdSUR1N73^wgEeyhK|#D@+~>&qx3U;bPDa;GZ}XBf^J zkf+-X>D61?NdPv*24f%73BNX7|>J;_rS4FMFLcg`u7t9@CZ~ zcBRDx4Z2jb{VGF=hMhjkX&L)Le`RS>J)uh17A82qSM!lsuUyns9v>vJQm|!_PscFX8Bht;G}Il(Ba8G)$Lbj;%_;r93N0(SxuV})sWj!>qB69O-60e>GlUB- zvZeljE;E*PwXCO?bT{N>HrmS)6^Ff!@7Mk#hZ; zFlEt-GsSYX*vm=2;9H$x*vFQ%s04i1k-in>lJm$X*4~RIJ4AjLt&TR?jD8MZjU=Ef z*ha_jTr(C#2XEIePY|xQ`pp_i0lEQKFB4^v3Ex7DJd!cWQO~WJQeZ_TjvQV@*WzAH zfPKl(PYj9(@yY4fv7g{&Mn)mJ&LHDs={9$3XOdANoG&`;&65le(B?OZ2nxa99UYQg zAu4xArYZ*&tGm+zMb*+s{Pq2}kz42IXXx8hkcie3CKY%1&eU60F#Lnl ztU*}}b%szJdtLUD*>1-=-QM9f9bOs!&w$SFUmC#?{+uG{ksFi}@#)jE>>rUk>zF>Ai1 z!68M;ufe=X(ds>pwf?llAS<+|1~M@2|sDa&hl zE0PQkZlJcKbeDxwvPIL4>i}qon&hXx?Bs9ibJYiX6qwI?io&Xg&xdQ+cxXsTNnj#r zmRVSaFWXNraaK!e^Fik2A^UKPln6OxXngy8oJEjyP!k#{QuXcwtPGj5*l z*F~y+pRpQEkREW-6igLttK%)q|l3FRf%X*;wOQ4Fff zWU5z}a@wY?RlLI+k{aFle04!IY>ClOUr-8T1YhpgJTH_gVJpaP127X$fup4b6vWc& z^`Iap|ER#R^dxHzB+)KZ^4xU}oXG_F2`llii^H4C$uAjWh{)X#m6UF@w)G-K*H?ys+D8Y=|Mm$7z7gSL`m68bdDt< zDq483J-mXebcxKkbIc~zuA8eUo1-0ahnPFM+>yx4o35>y-ot^yj|eIbWgMnS+nE62 zowP;6Sr?G?R?l!A?D7*GHWZJZC{joR#U%4dWG`MKFJefsw3hug1THN9M_<@Wp_C@D zBgPIBh^RoOKynHuYj+naDbKyhskNZ{&SNr5{xf-Z+daxpn9swXOYowG5}pBVIy|ak zLH^x^IhOH2d6L##-$?MX!9Dq96JHQVc)>3&6vpi&6P{)CvWr<)=^{Cp^5+h9Xx#_x z7=ewg$}t^YkgQ9(qU`U_7|HNP3w22{safdqVSA;8g#6U0bBhCyo$UZp{p;!&;;&ls zj|_|6S^TU-#ll@*tIduBFMQ;@2cC9;TdwY%F=uWurypkc?HVf{mg$h=V?Z|ayoLWm zs{-`X72_Q!S@*amtwfYaE&bK|Bo}rQFa5A)l#O^k&T+c zOeJnF=mldP=3!S2Hj?ka%n02<$f*X*EoR26MGTW~D%5{SK`11~IulkiumHnQyv|Vf zCXMVzi8X^B)LIx~tAd?26Ek(vwoDdHl8yvfn_vWIAUr0M*J1)XT#yHOLu-M%IUO&CMaQy@^zgyCWy@pFbZEf5#?%(?(GczZs5)dd7ZtmLODAxx zZvB}i0l0O_pRF`qxD5(lBs(@k1%Z(JDeC+%0461XQp0&7QhXGPLqiJ2j`|}w%CnVH zfUw7LcND0Qp5N)q|Li}EpCzNnIuEN>U-<8;m4-%V+h6~_?F^mMn6A}7oBKl~&pR5X z9{Zs=t(Lb?fLMfX_o~-$=}XFaEi(&{hB)L_d7NHIGFc$mqnEtN*wakzXs4lOYW7C{ z8{(1{;#=|ID#W?Qr3~%7$&Hr%4>u{Um54e1L#;@DF%B;PGQM^wZw=JtkAKQFTO;Zz zQ>}IyG7XHzSSQhcX@IkY^kpf@k(;sjhJBxNL3Il)#*-#Np+oVtoY3@UZ8~lF$U%dJ z8+f^LdJl@%%71}%tG__<2D!8VZu|R?O@3i!o2)hQs?#Ni9D+^n)-!ySiQ>tqm7GW; zDJlZ|Z>p>Vy5*@d?q)QgC?O@w-MQ*VfLc&(F@|%-c6LTgrGR4pK=F7lw%@9>3^x;Z5u_le`JU)NgQYZY2C7Cr2)v{N2ZxG?}^02jfn+}`={ z%V-J@NtKrNmeYN)^L}lk3mxS|p)y(^De3-02C(aaWC;FAY zjK?0$ry&8#Gra3?8fBERdNmF=n>;W9d4=-9pZpqlI*mt2HjZcT>@AROrwduebiTg@ z7jb6?L<8b*sik`rE7GlP9<>D+`5ogJ3iG++vk&o6+I$tvmksJIsqM6&)y(6CJx?ZS z>2BB>Jok%{mW$K{!8&>7nGOEvVHAPjN)oFMBHTc+vi%A&vHoxaNj+=S_l&MgQbcsn zy=n2$d{mYfmYg8-zVRkk<;T8*V}`4_*W4I2R(dtiPC&ci7^uB{5eM)uQ_4L@Wt#U}LUvSCWAOf(-Z#TNFMF!d!T^-9GdU!O+1S(O%Mu z)>s}*oQ4_!cNlR6PA99%6sFDP7I^|g_>JhQ1wgG{ zfT62x-s#%}y=JL1FfRGPWom^a3a_;YsiV!A4bdm=?aX(`Oo~y}W08`cs_*=Am0iei z^T!x?Vx5xt|K_5iq{JgM@fQA&JXJ}8^d`Jm9%d~l^H=MVcXRr1J4=r&uKF0stJIOEiY%m?a%|ZO>AcnQO$k2G3RdtEh@IgFuuHJKH|cpo|bSKTER4vqu7}i?@IO!$i0#df#y+h zSDcqpI%6VCX}oDl)UCiP@$oIZ3*m-;Z)?=53hXaL&X5-iY2w=)?_ps6{&8nNyNcaEUi zT7|m2;mu^RJK=IM9G+*XPCk7e?CdV%9MWKYGEiPjH5PdPS{b|^DJ|cWL^V`WOgQhqPhK1~R zo#ZbhiQF=}s*?zle9M`zMs0P4)(ME<;}Ofew4aGsi>wT?d(rEZGU1rlicXe8WeWM! ziLEPsFdO?hHb6yXyC4h;8on?pftjIZQjG0x+gG7j6v}r4x-!y0M$RGOK+Aat{EE<;+&V4F)Iga#uBZ0$Q`EA(`L#x7;5Bu66+)ONj{%sltL9$2Z2yR47I@KN==tLaXni?XBy137ocR3^j^H#iU z%>U0+lS?jtf>z0kB2(gcOllMC5lw9SZj{NgJ!%8=!*k!{^n{-=Nylk^F@ZHPnqas`UJlA!* zn&h`YlZhFR8};yHpA_FbEU93X#!v8%9YKev2z*Hbv0bzpP2+yoBt_s-s zJCMoZCKOZ?v+UJ*kEiUduOB22<7BIWT93&!+|lE2qOPMaJjCVc~~TCo|aC z3Ot3Lgl&Jrs$_H)T@lsjP8a0*u;6@TYE&?$Bn&t3UdTmKbh3v)_r0Y5V>_HbCXFDR z+b*-rR1xdA9y}X)VhY2wcju}=f46NT^C1Y_16V@s3vcXTwJfJ+%hM*WyNT+J+hJ$( zOY9t*2v;P0#r84@ z^rHEej6`j`_;SUQsOB71-=p;`)K-h%$s*uDQ|K$@FY~799));Uvop~USQgS!ZpRIi z<`55}InZY8qFb}gOhjq`Im~mI^>=W1X!QTMwJX^h+&UPVs5bD$Xs>R(! ztVTYo#cQzmR=(;vI<$eD(ImtPH?^mtX{AJ3i~bwpy0^4Rv4MwtY+_--Q4ELRp&7C9z8Fn)4mhl$ z9S3VphUmF$pwGVQyo*!y@wTZH2BcDD(D7LFJ7|lQCAH`H&r0C|X74GOyu)1aDK35H%*}Invh9 zj)&+x>4A7aJ|vL3qcNGA?O59z{MEdiao}a>$1htXbMT#k4(HuvZRMHq9tdWt3oMbaQkGiQe}Id=+=x=Up)^(>S>5VwyX)y z`_lO)1EGpx=$GHv&zHLvCLN+Ot)%i-Q%fzNWkl2zo$FvXOd%3v1ckxUjK}lC^O5by zn&Cr3S7adLZ$Z%RH-ffo;*Ix*6}X#y>CS-lFm{iW4mnCOuHsT`ZCYH`=ONb{dnj6E z4((SC%aJxmp+a$-K%jSe2>(kEk0DG1cfJ_tvVVr+;)5S*Ag{k@R`bLPAo5@`Hk6nD z^M0+&?u*A!W`@~xOxI4BH6(o<+vZRvARr#yw!AUe(7R(yql9RmO4Nh|!J7}IO_Wct z4f0r~V}ev0(S`1b@0|$OjBxB_hqr{rt|P_4dy%3?Ri?l-ih9ozceQ1mFmXeXYL?{8 z)p-n|pyWF?C^ZUN$(IA|d3i(;_dOlQ2^@{GHQNNQVwAEdZX_EkAbs3+Xo&+09I6lf z+(?QU)!}G(25`9J9KJqVeUM@hXsqC2y&`PL_m(%qeF4e(PM|kS;<}OhELU(3m1E~f z3Uzb^6zmk$I`pp_vXI!}bxM>q^d6O9gAuKEu?#mL7zq!)`<`?LazOLT;$@d3P-*dO z*dBuMsa>e9*}ZOk#uyLWWiyj1`;KD0=#gy-#uj2tf%Gl9t6+_}2DG()o#?;+R&nW| z4RoC~TE&Y?q@7i%(wuh#C@eQyCN*=M%NTCYTCx7Qf9@P;F~J0z-+4r2wC_u46t%8* z4QGPs;GI`V4L2co?8jFhb$HFR+sb5NvE&@{vW+i@REe>d6Ca~#y-Kavsf5m2Jqdvd z_q&B~-bAO(b-ll zDAnyYechaRUi7bE^yMdd%_b7`t1MpwRIJV6trwn(3ZG9tW-@La0W9P69E*uT^zTq5 z8+{j=!szUBrO&jqQWC)oxJ)8-^S7?r>KjIcs`?GF(bye}rg`Z?xAKYW6u^x!_~&L{ z$vcTK4YGUFn20>;6cfU@@1|YGd6{=X2?UftYzU8n!fECjxm7rz2pM?N#=@pysoh|B61P;FrMJLbT_3JeB z@X@8wvf%=6r9Ezb-8!f7p!aE67h0|&Z{76qz01j)vVXh0PzjDR4Rwk?*fELq>@dY; z5EAiEY_08ZD=&V)Z4)$uDWMqV4S>VzR2V%<2fe?jOJ|}wMquXMRTsDyiJp*$r&%d@4}ncDi(LMYfK{U0iW^ z(L+@@i9H$eUaJSG?^gi0LMb)c@RuNe ztqTG%KkN8Zz;<^c>=;ZkNmd6QQ6aU|Ear&&s5cR(IwqV9}WFe@)~d__Mkm zA#F1k;5@~zep{j&*MRd1JV2Yh>WUI5t%*ngW=R90^&L!yfyIU5Ir89TMIZNG~t-*fU}1u z3!p|X&2wY~VuUc~!Lj&AD(}XzyxzyA#Acx+Y?m&NFD{XzXMy(vPVwBN@Y%a89DCx;69Z>Pb9$VNae zDC#u-?(}sV!%DLWWj{yV)m4Jq8Gh&OBQIbXM_nn-jwAG`w8kk$0%?8K72<Q1;Lm{z8M8dhelt@+_S|)$1~eT5ht|JR9Q^kA}G?pVHVrFv2m>b3TlGm1pOf( zffKHnf03a$D3e}wT(KmyosGjp(sUIeVcR5ZxoiKUeD{+i0FIOL339!~nroyDseBlI zG@clYg@J0N`<3^HaLCC{T8?I z0ZvZy$9|x1Y_y7b-~nvoDe=Rkz^GJq4F9~`C~PGBIx&Os4ef%lU@^(L0ou%Yf-tsr zgWP-95{Z$_;sc7zWM1Ch%?>XvTfnSCubi%o77;vz%0_7u%BEF2Fl%|3YOqx$zyiwM z<@VvEbwgB0cwZ2Ql_$OHR57n-~Wuh~Wb|%tszv3s<&HPrW&Vd}yBU(IQ9^fWl zl(idB@#J4Wj`@k7wZ)p=fmt?oiB&*+vcja0c>Y*qmMC4RS_+tu1zuC=ie?D?W_Pa{ zO73pr2+d%wFihhNEtZ5#Lfu^DQzT|JIU4q4K8dgW-24{jI0}a~Pj<+_*#e#;jLcuV z-F=fDwcC}L5_G~}pA?#-=(7UvIf*zm@905{CVb6I*-zil6Qy?s@AOBtSK8OSVz%HR zbwz|j+hTlK9(Xz>!Kt;ImDGj#>C$prs{-Z&^$NCI5_Y*bcQiv-C|0NOQK5A@WZTGe zFt!EEeu$}>uv0sF?q?4&SG3Ob77wJX-&A+mTi0N_#jHM)~M16ZJs`UvI$2#(;CMI56aNh6ZX40k}zGcs@x~u$WVLh0hQ)ukee?zAlOmJKF?>mPN&Oi1tl9lyk_^}t zZ;Lu%#Ku|-fj@w|{AK4^5d)=1^0v<{IfH+TUcjIRlPLf0m$ieo0wXfs#Baj&wOJp^i+GQw-PMBg={(ZI}_fq{^=qidn zI+t;>Nh4~#Kd^;|FpNmCQ0`fphwoSfT5M=Cm|z)elqUizG>iiKNGHe!&(P zYGcLY?_5R1jo+M&>svKSXFLHV?%j#K-t_LJ{#aBp(;5LlQ;( zH~mVwLBQnps63#_uyZ^m>E49~pQlotniH`vOBT!oW9*rMW#Qhl4MY`EiWiK1E)kdvtI8om8Gt`U-yNLS49 zTVI^@jYWl`!F>sgNtVnD$8SGy@}d2i*{F3oCX|BXDWa%HqCVy2VVXk_gEKQe;^Rd8 zmP}!|QC^CxwO>)Q`8wsO(~T*uwiDG^dLg4}WI3coFo;4jMbAAP!`_`j{_Hm+6P4J>f=x4by)BuEtl2WC-EAbBj-i zaM4|?|HwRKGisr(Hv}4C8M_|3NKSpo*krIGA2~{mWsp^qG`YSljp}dn+qrt-GnVl_ z2x>qx{7z>Mm&a~X{*iM^Y`1@A1eoAv#0A&HJAN|VsU4-=E^tyz&I6ur_Xv5Tc>-J` z(2693AAV-^24tgB0IgF@{aNUQMjsc}ve)kRdfqwcAP1}zf2|4|Dmht;pREkdqPb@O zPP67qTQ@Bb^feAvi_y$A<^_1iEjtbtw0wJ6*P6g9T;|BkxzN|T%^g~JOxIcON-Y6@ zkQLNJdTShB>vNO8B5$mMT-`&4h|*svs9#<0E$}sDEG$Z%K}!4zFC!a1^<;(s7R=N` zjG>3(i$RKysp6HGT1ebMDjum^IoMus%qgX7Sohdf+RV*vyP0{2OyTjChgKA*4ZKMfon%C#F z`%Ic!T%|qD&f7&YJ6C&q#&Ro9M-Yww(k4`mau}>)NGwxpaf!P^UbnZyL*`r+Wi7Xh z0UEsEl5w+b-bEem;)wbJ{|Fvh~O=x(C( zajCAy5CCAJMP$N{^JtT8Oe}~vv)RuvI<;NPSriyWkmz1=l{DT;5NiNRai41iuR(o* z7BxEaVEO8ES-Gak@DBLv(Vl5NAEHN@+q=JFGM(Y)5jQw+4{?)xYl>)7?w9*qP`GH| zy&0@&D@2>cOPjU0_75w<;S9m>cli2t$;syvwDB?fE++w(i4Sm57 zwFMsN;GAU-$ggs8AkJJRhOxoVY|ho$v^e5tdl1Hb2ZW>kIq*%@>l4L z^G%PEH}~*>_P3P&iB?nnRruz&fFVXI*g;}k-`<(@CL*IZ&YTCnRFmHP_kez)o_LY8 zO?(Xm&O(jhfu~|K%c$UC+#7F8p>5r33jkGt-p&Ndj%!D6>_mlf%f$|}c{t!0+98Jd zyV@uLGeY99?0uPMgTI|#_#zGh- zm2rLAcog|PWY^ixBaXtjU(YvzK9qiS|WgSMTP%B6?&AApIp>}k~d1%mx_@t>#t{HCNPXJ?5LRQ z>7x!JV|yUKMD^!O_ll4T7ysf?rcs(L>XhH`UcQ5sa5!O|naYF2y@SEB zO*N@Anw8Pl$ANFn2$0+;{2rr?sI4Dj1=IDm(wghYrn^dqGu3A9*%k5y1|5pik%Ve%F>R(L;v}Jp$9NBz6bx55?vyi^8~*EL7Kk@uIDX-5Y6`f@B)Cx#vdX% ztk*=#`YlFtc-+RC-I47JwlHRL;vR7>D9SYz=V+rtX*6Wew(MO|KUbbS$wIUj?aOl;ia>T@h4PUA6+9OQ_9e-xb8&}#H z8L3bL@TZz34?|Ddf>sF*4{C1v`Xpg9acqEjr+JUBYJVLpxDlJCvFW?;Sn)I)R>+Ks z>O~^8V<2bA^id8b#E;`VDjIXU8MW9KkU*UadRw5ehiEM@Irdeg2`Dt2E;GQt4?rPr zp-~LZgD5N#g#C`-%Dnu4i6wvV2qj-GWXf%tR$kk?$f8!nXTppMjGHt-QeW&!L26cg ztlYs+_(|==Uxa4M%MnDi0qtu}1Nc{+`9na+iW^n48I&x@j;6*>SQ1Gm%`#VP+lkA4PA0tg>RH+8ddi~!hd1k*?x^M+}YJ{Hx zxEhSRW!&ik(Ivzv+aFCtbc7R6K~qlYb@(A&URQU{Y5SFB{uy+zY~)#EVT`0xns_+0(sBJD8zk2z{3%d$y4P zT;EeA$|O)KDKIy5QXpb|$P{8#Oi}owtb^NC-MGB}P6{8pHl|0sx-ocZbI9nIc1;&W zZARUb?cGi-mGizS$!(wEAlbgP7E*ZAWFEPRbPY2Hc{$!%BoAyM$(7N+;ufvYN!JY1 zYV{_L=_r?>>~XSckjNPm2TRx|8Xq>>x4BklEP3T$T9L@Vz4@`1{U@w>oUoGM43K zR-vTQ!fCJGg180(DQnV^Dv2`!ZL71)CeskgjdwtgB&N#!EwNl3w!(h-z>-WX=l{f9@Hi3Iu4Pwg(lc>jNJwyp6ny~;L z$r4-q!~q<}ebei0BX{Yu8lpIaAg8wstm>8~RSo~XNKa9a4_lI9k&%}9;lF>YF`8O- zp?_TI(jsyPOqDbBBSfNaQT`ds-R-!UD)|b$x9$U}JSBxOe z{FecD4WWxupXA7NDI*1{B|KsUsnglqIHKa7M%aH+Ox4vq27hJf+MLr2^(3V{CJ_?% zcl&!w=GD$nbVv_J*$PLbUZYdEbP?2P%$A$Nit7+;{zfIcp$~%uY?Ld=0+bNKX8!8j z$K-r(mCpCgyg({}PF{W^qye{}e0;^cA11s~FBIm(vW8(A75IPUkaC=12(CBYBDrQC z!>rC^(QkMiC@yS89-tXV@MEXAZ`FCkUKq4G`hnJ!rZFENtKlgV5&nVFA!85?mFQBy z?N}-lzm8o#Sxy~svBOhi$|59|ru4Tui64+n8hYLlB>ZvSPEXi3%x#1Jx%R&Xd=pO% zOAb9SBzL3%asHX_(Y5)i4`tCEY&Aet9k_8q6bZM-`W=&>#B^umE_3U(6 ztS86<(?)kVZX=F&EoASWRTNBcDNHOU_Y}Z+?9s`Fqa4>UJA;sYS_h@q;KUJmHXL1N zgQ7|I7`SC{DW%QiDIjg@wl#jDpuAeyG4|Taofk2-dc9#=GepHip|MW$l}!W5>mr##Iah?dCPvfJiUUdfYcq8m7o`n8c`J;y8=slF88{zYy!J?4nA|q z>pd`>PfpVffb8(uWyq%9&~29hD%6s+V5YHlG@+!q@Z`S<-J9k3U>Bp$PWqt&Pu3&E z$Jk@Amv0*mqJCm2w#)wK;j06owv`#M?Gm#$q~fLtQ@7~ zD?7T`Hqm-;)L1mEN_-r{rvo}~9Nx*=LNq~jEM5jo(Fc!Bj#Zqoh++puY90D;qeZFvzb9 zqti0OShRZps^3k@3N0$?!I!8_DUrYIuwNl9vMV3g>_#P2y$qAyK3;udEk%96-wZC1 zsmGZO(n*-k)_f}2*x0+pgg=F6J=4czu$D>v1BAA$2dl3Kw}bQ(&o*4OSdnVDlb9!U2tdz~;-;Ko~&es`f|ln$RB zJjIXNhm*RF$-#^wM}>O;y#0+p2>xQ*X6EC!pJ*5T1_9wYg;$LjYK(EiSLypsgdo$& zoB0Rnbi9!d7*~@7nYFI^7)RdUbJhT$CMbuS;;2NxtHgu_33R$@Ga4xuDBpfN4 zlCe*-nUQe%XqaNKIr71TTt#46Vam!FzzR{@spzFm$UT?V>S?G&455Vzn%a9DELNad zZ%a#gmUX{*z<8;{o`o04meSG`I3>{2njzVStT^ zJ2BB}pBvM4B-a;P6>%~#0dAr8gDZ`?z&vOOTo>H92ZQLqD(c3v*uOa4(4_QP9*|Aq zrV?zn;D3JO#AHgKaPVxm|%sbN&oN!lX8CguA+ z#2AWBkxh$PeS|^f*k^-}fp35nEuD8Zwfv+0$8!$8M)dMXsg`l_|gusb@UF3#~C%);jbAVi+GA#wRSzfz-82 z^XJ)vP&oPmF_Lpud-5Tt#T2Nc0NxPwRgQZ<91%qORxs?0ehrIL7dcL5@L=hb+r7N} zWdiKyB(Osy*Bk4=yFl`38uD2Ff8bupS)BM{ujjpraq@1J%SpamZR9Z^D*j6kbx>YE zV~Y~6n}ZtHoZ!srMp54;us*wXF}mvt&`?3M(rVb@IqVpv;^VHQbWvN3Va86uri((Q zpa{rG9i!L5gAm+IsXzxhq6plHx@MMbc2^4K#^ZVWWDOo7_HE?GDD^GuUf~-gmVG2Q>ndEq&l_qH{2G1kFf z+3}>@2wmaQE22TR29LZ}Sx8B;aHz6-0YCg6TB+{Y14ODP_(>IL*fnI||MoZOY7Cyg z@i*zYNwhB#24c#>2Qr8(KqxW)w?C9oB~073;ECNi-8_O{r|rS|BALoMq%NI zjg8EK=CuYXw;1EPPu9Dvoja$0Byb@MOx1whzjI8az`W!!>Ie^ey|%fGaIdj zhFTCC`y7mqUeYF)T&3?OA47zA>c2e`$T7cG!lgyx+EcuV;mCWx3&CcoMvR#4iaB;4 z0h~fyqf*9hcd;6IWhVGW%XipJbUN%pdVUd6)!&RtVvm?!elI-Uz{&`4pH}}CQ$k6a z$j^g?3TKgCIE&xP%n1F}>Z-byp1OqzZdR^p>(B=v+NzgS1GentDrDQi?k=ud9HkX=+I|^g___s!+d{1z`^Y@&uG6*837O?^*VYvxIIs@QY^ho8)nCt@1&4vO z>>tz_NY;#fyNn@Y}augDyJP8FTO0wjFdnws<4@m1mr7CMwmNET{H!?snX#Y?YbteRS~mz{PbZ zhFN7`ue4nfudhpv`qaEEU*ltUf01)k+7IE33$OOQ9!HZjN5<(eaG;X7*~9CQD`{+e ztM;nqD?x$=jryVzy*1=}v>#sc1;&z10D7^hj^vSmpaG6I`I0S=yH9kF_SZgIeIV0c zircRI^z8+c&z3qp5KinD5nFepGR`j98VMw^+XIj|XAwoc^IIf(S%~a%=q&)jRT}+B z?K2=#D`F_iFI3_tg1Z4;?mkO&Jj)l8iem8ySN~e&xwCib@VoX55}JeQ2sYBp|+(fJveqO@E`~!Lb+_ z;W6hEn2qtP8}0we%m=UAC+6qe&?kbd;+vmT&IJT|9PRLE9`-8{^=tW#FFg04^7K+d zGf?5TB2hN!oo!Uc3wK65P?T^%7i?Ek>156X>uhsY!V=)#-GqtN7y@_%xhr;!`*9+m zqG<|>8K%wz<~DQ4D{~9ETMj>%>ePug!>tY((OBjiwMp4qN)pHr32m`f-U8!d=q+?E z?4$XUg5zyx%K{g8#M|mZ(sCNt;4jEOM3~ZIOnYxzHL_~0DPQQR^$+#6gq@x1r(dol z2hL&S-D*eFQu>l7zh0#oo1r6zNOF4CKSxA4N8)`JJJ<~mqGMaP`$At6Dt)n~J2BUk zo~|akpqnAXdf_O^8(Z6r6Y3CiQ6}5Wfl~uzzY3#=`_@kw?tf>a4XRLjG?6u%3)WRI zBzjfLex8cRqBtL5)0+CLv4&Yp@92)vWswY7 zHM^rkC(~$ODpPansEhW)x20jurZ6P|G&1oFuIRf<=N{Rk`ubo<2=|yr{mOT`GY#u5 zo3~81!!dfF7gEjK%$U<808|V~O=XAg7)xfvguZ>bZaNiK|50(|?l}Ot;9KZ6n`S?- zPEm}i&mb1F!T6=Dwz_Axa$@ENheCM6RnG!Rj_pMJ`MFUS**Z1nW}AW`&G7%I(E_w+ z_#nw)v{8M(kyTmje}tMEr`Q%CW2VuY0k9YybCdXy04peWVhwyTBinH%9kGhKhVzIK zvRL!?_QZLO9kn|x^ew48o7>anRXIM%x|7r5R&XV#{nG zzW=jj;eM4kb$5tM-gq0y@$IR}Uq7${KokZKy8KtPaUd0#_v zdqjQ+JjKi|RSN|@TnN2LRkF@J-lXVS5=08?=)!(vT)$=LVefxy<2~!4JfWeEqFYjv z+F~3^FhyFZc$fWFEW-@H84OVGEH4P@ROAyGp!zmgEbsaDv(K@6*IfVgEfkHfZ#?FV zG*(&ttX&;y*kJo={o<+d90n?lt3v!=cY{+dAmgdntnxWy7LSc?o1N6Udb4EVx#6Q?Z98oO+J=WKm=hDqd&R&5VxtsqSc4#&YbUyo1dS!HoC-@-AU zinrEfz19Gx{%?o(Ka54mpaGZVcsQpc1oB2{gbq6uvtyYk*@X4_sIv?t?}VDWX&buV z`5QH#(LF%(V`mAv&dFuK-m*s=qU}LLVUG-i4c{M__A7d6}cDa?tXR zGlpna#ro|^C|l{8Yy@dLm(Y!fwT`yh*gM1vyXr|r)u{#&d^HKQ<$?bMdJdL%5FE_h zMO#%h*-FqZ-+4c)C}IbA-~pi_VM)?Pe%n|Haw@UePR4C+$`6KH63(gL|C)Xa)VIQ3 zIvWsHHlXIcnkg}!?_!O559mr$cNO3EoRz0xdpQ}ZP@1L#Z084`)yaNJ-bn941XaU< znMuj&Oks}%0k^bXYQ*Dy87q)El86^^Q>}TgZN97m1Tm!8a{0!e2>BjOB z%p(q#_fsInKAA{3{XO|5$nxCC9a(!3nb;gXmwEw#Jj%=#360Pqx9hS?iUmGaLiCT) z6cq+Tu!cFR8Wl>Sd3v}cZ}||sJ=aoA$6Th(pjYpt76#*ph%qp;}*O%C`w#BQ|5%iG<%5mGuDyYEZ z3ryONne<+s<8H=5k#sjqIf%zuE7pq^#MqVjRGD}r^iEdfRL|6M^4iq%06uz1$x>FM zSmPY=pb_nS7(S3Z8P%H;N6TL4mKb;$FR%7_XSZ>Esp;+CWmbSMqtppUPIoSyMl+I1F~xx^0eOx|N`cwNL&i{>Xf zDDj9}xBalnVw}f%oz)2juzk7yzrA~-Wl3a(HRQ7BF*S5rpP{@$>r1^>O*uBPF}K9Q zgBsErV<=+3Fm#Y66_Yp~@5p=QIz}`I7{eMJudJajGnD?JbWf>>+KAEcWyuNey`HB4 zI6_S2@d1emWIco)O*)2io1_ffKb?s4r$O4uK3wX`=fQwU^yAqW8d|Yk#feG!4AkQ5 z>QX1EWiJt_>?WSBp=dJAf5D=CZVFp?T231W$8}AP;s%zqp+|i~?s=StyFwFZVPg}s z6xr9UOp_(^B1`mUA}VaSg)A{2UR1TE;s;2@+dB&;{J>x0nd#eTeN`-Q<82BhjbbP; zWxCdly|SkIWM=awsP6IqAa1HlMC3=|h3|+)UnQtS`u(!s=rJE)%4$u3S>%#>u}*+{ zDb3~T$L}(*i!L10na~SgG}T@*9BBeb@`1 zUPN8K$Xm%)w*GSuL@WQFy-HfmthB;TaOk#qWz&$DT0#T-0tD3Mvh*#q&Q0%+XkpT% z_ZDph?;_fLwhxXKCoQv1hST-8D(1mAyTaHs+Jobg)Ih;EGkesf##hn4q}n*Fm?tohT7& zkQCscaCh_N&XwKE$Ir6t4Mt7a;`U zGd)Mk!bjP3vDc~3w+l}i;xsMGbV?se`KUm2q7-kph*)GMGJbn3|xSGI|4GAPbW;q2Pz6B)a~~T0)=b_01k6`G z`f)(^-S!8Ux+iPnYFwF9-F%3)?&I@mCCmde7M4ss}xrT<_PYz(3ybt|Ckq0(R8O$9|H zpL}8@D}SP8B9pFwOgq*Qo3#xLylgI3r$+?Y9~U-%>&KyjIOD5d{8ferAIUz9w2HhI56ip2!>8s9SM2v z8GoX@QG0#D&}uIP-meeO=BwI6x4L+T(zC0XA!fPINod1q2l!Hc=;D$eZdXW^5#6sV0N$mgwAumI@f=zr>KvQr)2b#ZJ-T)3&L7{`Pw4}K37&X<#O#OWNXprOKb*Fzf zxqq4S3meBldU}52bjK6_Nfm%+DGjN-TB)@)3B%3WoCp`#_U)0xE~HVIgDzE%<@IUz zHL-#wlw1VkUksBX7tl{@{Jb}4;wnq)&@dI&7gX-+syBt6*PoI}0AQ|)e~y*DE1y;% zfjEIF)=&q!p=F%Q$3ZYC@OZ3BT;COO|CFl?$6D?bQGP>zy*OMKq1vHAmv6-Du(^J_ zUIT8OYZ=GFWFQZ2_mN(Wg%mdVrW84kqgiKA)PXh|)-LSS0H3HFH2q&fRs3AGfW?s;Fp0&$9;A@4- zT}(YiBsEb%HKgyG5_{oM5bGMB1o`Mc$u8cr(#}l^gRGnRwZ=z)T870mgi-w^mG%}C z$DfkF)043b$xyzt!>#oC7u)Sa@jx4^U$WVRhvlWC_ULqVr=!DGnyx9vh4fJuX)^Zu z#=SA4r?1uukypj&AV8poz15M>gH7*ni2W$c$p9Y2VFJm^56_6sVL2gafWm!+aYO02 zZDW;@^jesog=j$40Cg&FY*>VjGwomsd|ST=oa?;HxW*98h-##0%NRIJTl3SY5j=sK zs)B(bX-Yz%J&mhCE8_dajD`>^X*9(28`P6CuDRSJC@Kjoc_9wCL%Dc;iD$Zf$RKX@ zIH1?RWY8o3yXj;u3v{XT<@rVt7s=I}*8@SzhwO0aoj8VMyr&ADXpoE<3*S{ol+4$R zLZ1l;AM7M->i3G3rAZoh0e-4`uv`O~b=*Q8_ok4^JUIZzCax18eD+m zm3ZvFQnE=AG^(Uvk%Y(ropUgDmck0o`gDXg;XgVl4e2wn$;3R><@SBUqS*Jgbm1x7 zxy|2X>lJUFswFtr=DP!iblIE~)&%~EQnp;{Aj%CPaOYxn!3PE~qIp_b1rUPcsBia4 zo@$_;_ z@eC*jms6zt=`;8He*)RNz)7fau1Lpm!`iVMevt*PQ`7-02C29p9Cw6B9_LafMlimE zrNl-)E8VCD(#cgf5=SjkNFskCQf^@JJ?Gopx*vG&p(3|V7_K?Od*WC4?_4SN#}oqU?`H^7HYsrQFu^3pm0_C z=f>6`yDdL*1mW%==!$>K*^J)z^v|g-mb!k;-^;=MSHL0v5i1F60vt*z&;Exh z3|7KKOQTLy{UIj{6Tpe#KXdLTGAyzf@=~I-a7=Lp!tN>W_a$!|Ec(S4+wI=@fS^D| z7e*vhA=CGt=mVu|>CbpiJ`AwKMG+$aC@U$yn#&eEk);u4PRXY zLAMifM+ETE8WFpn$9w>TvfkUPhR7)ZW`2 ze`-d*f3ifNlQfi7S0$mf8WPdn4tMzjq(6jMl z;%FO>FyS94p;4Es%vVN5UZOda7ZliHx5K@;F#J~#d^^&>3?f?NCeVWovjg)nl^*OZ zYcCQKtt(4AtYPkDBfHON2ZZnOb7Z~##C13s89m8~h0VofeTBn^KnsX0su!?Jacv@| zE6+X8tij)S0$H&$HpENqw~t}WV~$ML68GW|_9M?j6{+zn%#hS{@)z1s80L&zBfp@A z8Pt8HRf$HS-FA&dSYr(L99+T0QMrC1_p*VoJx;lDa;y}{xrGIYNkRVLl&Qo={V386 zbGQKf82M7#cdM&bW2QTG6xYn{pnP{Ep95%|7BM51pc`r&l&RUw(j7_fC@<1l<@9<8 zqSF}nzVp0}m`$Oo$d<^WvA2V!v~Nk4;yKyX-l&1o%+eXdX@dDKe|0EkOCa-3p{);j@Kj!tj4=#&Gi4V7=MNwlPjIj zaR*q4L>yVC`KMD0&wCP7=Vu9GgY)3Y-6r~xcw17dOgx@V!Ta1_q1e$G+E%A-~;%5 zq3sQ4PF3E!#$n<(WW6$gNoK#f{}&%Ryy(F!>Noub(yLOpi~e=x>^K}&?W6N+eqs8= zejH_HJz?R~uU`?g1_!8v@Tj}ZZm@`4*?`&H^Fa*=yr4K*h_^THnX&RDohvAc{lT=o ztn*2jZ~|~^H7ZjF8D^60vCRl>8+R?=T#}ro$jf#mH@f}KPX5FegzjYjUsYjj@l11S z8oSzplbw4fHrIEfN%b+cc;(e&HHIE0lkopDk50cxkY*}CP)JP6oE&94;Ub`Ju1`h-WdaGT?Kedu)h+ z??iq49D`lTuE@>VT%3^zn^K+R6EMt^C=qXm7&C&z`@>Z`P>&ygJB9D*W${(bAs9ia zdA~4uU+f|9e24`8 zNO0-5mm=m>mV=-L#}L}|>zAcCZ{Z9#Cp=%uWS{fTP=hTsZ}+#;KL9*&?QHfXmzwf- z2=3*gmdredG1@L3t}#H^1ZM1Bz=Sn^K~4Uhz8)wsAT>Rqqv1!|`em!fp`M#VX^e@{ zzDc{L!o8~jsS_k7ze4d9^iU;L!-4$7oKKyXh_U8VlZfF*8zI$Y1qH2|tR-&2{WRzO8Y8B`175x2;) z@?Ocgau1rIxQGFqGHV$Wl1_-taA&T7Y&m=C?S_75gPXN@>_axkGgY9Ak0E*`P??vU zwtVQx4o8xB1^?#jGdPwb6L-Widw@G33O>`fv;eB0q((fQxl%5pu#?S)9WyTRZhzmjcm^tT$ws3>VM-7Me`%VD<+Mz>e6%7(E;%)T@=`CWu3*xmKlC>JklI z{h=)aj_GaTc)a*=9MDIVeF-s-ezA`0SQ3N4s3;{*)LIKCg>}AMqz)Z8bqutR-sCl2{&;c}XA}N+koaVRV8YBN z#FmxiKLf7nRfiS2Cr4=r`t^)`kD&V#8%_s+ASTCcYS!k?7BKfUB@! z!Mc5IuspFA8QeDvVoZi3kF5!?7-z};)g!(U$HMo6$noWLZITf;LIoRPXLO)4$Am(>Ft z)QV9Y(v@?VWMa4@G*8Q3ZXx3oVcOhr2Lseg<3D*D16~Hv5Mlg+pkh!1s;SqTy6S3s z^)}X)Q#R|8<6^$Y@S%8I30IcECO#j=GaP!7QsYVK<(9SQHD#}9f_vb@gy31P^r0Fdsm&*4zY3iQ zeqL9g@lzeH6P(HD&_X3$9&=x4SmaALI!Ye?cd*hln7JealT_nN&(i&^cCuv3&WJK`GWIF*v3}BA-!^u{+EKG~47A(UI3(VE9ef41fxNz6&@QTkCVC z@a#+UJjS*%E)xn^CX5G}y&thzDgU}c$aC$$FtY8LrJ^KZd!9VkZFK1-A@CVLO&sXQ&}w5r%<@6zx*2(`JY@T3cT%UTipMs(ms! z$%q{!DO|xK1U}aXwXsjUEdpF;?W7AtBc|A3kzaMfF{EK-6iPVdLDXyAn1Es zzBR?PvAi#6%`hg!pGakhjHmzwh?BS|tLdXdeNagc7{N?Yc`B|X!J=)Oz zsq{>!PSbHfqapL9SD(o;2xV=;mi7v3n!TY_d-+SaAB zwwY|}JAa&DC$%z^{Mip2B8ZPV4xN^6k|3E@Y^mmLzYGS|%%!-OQT#^rk5CbCTQUNSo{=r()WoTlhT|{-e0umHj95LY~=WHwq*`M^3KsG5DJF==GP5mFmATr>Ra>y4|78VG!9= z{n?zCN$A|x)g(;&nF43jLxptiFb;_fiBnfQTv(LLiwHSBA|xxCgw)hQn}b>5?SX1F zfd|VCf$1kT{0zdsm87Pdd_FP2J~q@d-&V(8+IL$HJ8>*Jz_vLFVUXH$RcN+U@@nOp$;Wp59T3g_2J*_``{Y-HzO!h(zJv7f$ zFFEm5n7OA;J0tF){p(NG9g{3 z`S$NgM@nk!9^iIGrOf?#lA+=Gf|Du27j)Cw^Y4eYLC|_CB<~q9K zbSce70N=#yyj5Ie#|M!1ULgk~QtkRZPV7eOm=MdS24=scZCNp^41dO3N)=DNHIbk; z883W9+eT~w8(h8CldtD;?aXJ|wU*9<>g?14JZsw=>~x0HsE z07$ajz*%6zCaWJwqL~U$mb`JDH?!yJqbRi`07s5I@q2X&;Q787c`;mRiZC!EAjXqcaaCxx?MUl-e4Iys+|)${A|;(FMUK z%gm++sO_!W!eq^wj#C?fJy$C{b{kS%gm>eQDj-~S-U_i+bKC~FA>Gh>OLL1!d?RlT ztD&(JYhkO+&lj|Yx_L?D;0Qzb@ay-2482!;|-d0B(=rJ%Zmx)@ziza3=KtzXfWlAc?YaXS7rm7bHvEfVQ?w{5J$jix1Q(%jg5w}CSE*lC; z09@*UphC*Zu~xhlj(-FBKCOGX>fPS{j)AgZrO$m5a4K2V^-iiiB{v8{*vcI0IYl~c zWBD%+L0!*(-Zea2Y7OA$u9?L(a!Sq}QGXqycl${NeosaC_zx;3a(=lX-A{tHxKWLR zOGuVGQXxrWF2tMg8L?Ql9!<<9btyo0T{Qc>Qgsir!)-kgWOH6w(fL9 zNPzuU669^XuxBb*A$8jNXyqk|!nY1p44?^o@MNfSf-qYLLoI z#5+S>xu{Np2r_1_%FQ~zf*szoiYND-5ejX1hxqMhS-&=)xQ7i+?C%=_m6MmVNVfZoa#}l3 zII-9PgJ#lKh*}j>>~LqxkaRziMGm$j;AViq%EDb)McoT^{R)pD0=3y>HD)AIi9XmO zd#yCbfWy7BgMq2tsM}}BXDFm!(yusNh7}IHYN&2EUYP0t`flcNr#lG>04)8dz{arM zklx;B^q>Oxt;`3cO{;P<1P1J?I@Q_)j4;IxIS0}&xZ}7ePc)NuQ4m4YZ6Nx=06_7o zgC1B#yX}&GeTns?sDW_8f31*wV^JF;fI1^$aiSNU19^F3M_Yd`6$2~3O!;O_lOO0e z0k<7-KC@OV!KxkE+lW68iSzMW(~QVT7SldEFcvGvzEkI3kHXmeZysaz*UJ;wx2aEa z) z%EXg7V_6~~a6{wi-r|F1Zfffl)+BIG$8>|kNTkxh#wjl!^SZ ziT44)BFZeQW>-w`P)R)ICu6Z7v!1`}=+xHM9w1sc^@HDyxYge~-Ft(0M`3UT zJpkG4k6O(+AU=|D!n!?|QPaCH&aN~!^~aY1)<|N0Vdqu3}Rz@JI`IA^@w#h~LxP!_+j^0l>)-sgm8#~Fxh5^$8!;;nSoMUH; zvK<~%oagz|QtziL_1q@9_m1eKCxS3)Ayt2T*vDJW)aJRGaz+gM%C{%tu4|corKwe*0RwVS%ay4-+2*|0&EQ!#>D+rYk6f zimWtxcIX1@>aAU^yC}!-Z#KRJWXKUFijW z>2)=x0ur0Ng3M^2Zpwtdh^arnhu79S1?|5D zq+4MDCw(p^_)5kjY0E2oKG#+;$OSLmw-`$%k@dNTeQsMS@B3)^S6yTYQ+1OLtCF2A ze~ozNy!xbvQZE@N!H={@J71#%0wbWCie`E{A0O}gK}1Rd;6S1>D2$wHQv4i^`7dSd z@hAN@;pF95o*6e#aBy9}BbGQLJXIs7pJ?O-RdPPWRTqIcitt)VOWB}Fh%A2Yw>KVJJAHVy2Qts?8RSH93X=fiSUWQUG|B3MlGHFs*&FBZ=ut8)eX#d zDcOu+xe%dn`8|lc=dl>ORV6>L;r$c-q0&jFevM^)qp3lLJeJx1Ug*1q!<&yT!0QC@fu<|MASrBd7hTH zG@*s(n~cuiN^|9zjA11j=g)#lDwPfO*Jq6%*XQK!oL&Pxmi2un3WCfonpZ~joW z(;U#KD?Lk#ZBrd&hc6kts6yO3+*>)l=0eC?jN03EoW}q14g-7wT3OFLcUT#hPLczJ zz%{$?t%dXh93YrXTA!)J%jm5HjC@yscZMApgAYo)(_3de#LdsB1=)4T+vXd-wPH@l zPet+4>H{rQ(TQYg7B!ierS)Ii-VkG8FdGGjN4Xs)N1+&_GBVb{)t=HAYI3;t>CocE zauQ(lng%>Pm)^;ag^FE6tkGmnd%(cWOzb8Fd^3TodkG$pQ;UxdhNmXo$N0+DvSU(C zZ@W^9Qp~S3aPvD1n(O_B6A!!*zrF?Y~mf>BRvh6LRt`>mJ|b`j(eiUsz|6U zF}X)DHPhp$7rUncqewG*^e^M|DI%rEFP88KK?v^=>c9V(MX_5&6_ss zf5;Zw+0m|UtCQG9-21#Mct~J~ju5o&(NQCx3q^z|s#E{_Pz%EXQiw^O?fp+UJe2QY z2lI^{;lLY2oVin-VG{_imKshFCUx7sfSlMF9YSl>x_i;K=;X&n^9r{6EXMdOX`PFJbJ$D-3KB?+fs+uB@?OdDOxVoYwtBHKPcuJzweGJr`kNTUi zOr0lX;W7(WlB?^EA+ph6rZd4_t0gu-|Hnf|2OxQ5V(*%Iv{NNe=;HhKd|s1sqgk?) zuG+nJKh2&q5V8S$0cw@kEECR7OOcWI3WK?)J_4WO}DY99)4d%Nt_Gp1bo3Mdnu zxgK7rDWy;TlC#7{2^xJKhYjWPIua(p+p1vT=s=}zqOAF_47eZT!|k^)8#iRoEb(6S z5?7Qe#5bFAY_gYYY&Tbt<%!;>?7y2F_X7LxC-iZ)#1&iXF8=Jg6Le_68G9QL4~{zS zoq0rDHYo4<$(_O>voelwg#V&Ot;H;1LEG}3aV9gztwQ>2Lbe#@>ZGxyDO_#o`kDn-?;HrI^98gg)ddJ(ym21DdpgHUP!y<6ij3G1EFd=8@*@*wrEnd?sf5 zh-KH2HN^M0Cc@CVs0I9s`tXwM?XTlvDj4*29%3=YuL*kg1^yZSK$wlZ6K?V~u$cPv zOD`deL5RhaQ~;4ep!@sj+QFE<^4=&WVwYOGS@G%h7u{NZ(eM2a??O&7$IG18>|^oUl`s;>uDuOrP| zh0FRld~WK#Qm)}pQ*)wL5kmu!ZmcmP2k8N;ZD1Rd*J zp2F?6lv1yD_y=@%W=$!Z$!=Rm;D~k4pcg*}NO4&1;4w$u6BjOY3XzYtumgSI3l>QR ztyQwdi&Pr~&zo;~hqjjXeLh|n@ijuxTBJ&eDooB(U~evx^clZew>YulsdDC*IERc?9oWCJPHZy>}$tdtJ9m`@|V72&ccAq0I;rtseer$XhIH2|U zJ36AF?Zk!dbc92sPr`pN(GzJVzk7!>svB1=vQ}9jQ4oE4f=vC}y#Q>xznvg7d&j6rVR2TSV#WGOJ29qnlfCTZOT}X>^B8%r8K&6!fme0;Y1vNydh? zq&(2ad97Oq+fR;P=S3T4(+lM>XW=+r;fS>b$(n8|ZOV+hyB9||sXpY&9)l~lFB~Vi zyYx=gqlu_U8r|FMpAoi@=FQPr`zPl7?RK*myR&>i7XOW)csDEPViYF7LCTL6t_kPJ_JP~uOaXi5 zH!$+b6I6YzYjG`PZ;?VT&ytGx{VRus-ugglw*8mc1GwXIGB#v-Ng)akcYpZ?2cF6) zr`u$eS#qE-8r=|o!UrK~US$AIHYlfb20TNzih)_^Jj6-!VVfMbX@DA2&PamPT+B~) zmXtW_Z(?R45jMU}pcKOK)!E9QRtS=rMpb6YS|}jzZ&@wb{DDO8EZmtw6l;-mLNaMg zWz10t2O~oU342z0(vwD2L^Vo0J_%GDQ?vpi?@9#Mo+4vezGiqaZ*h+V48-Pz9&wgp z_4=^FhQioJNQ)yUV6&K0_Sie|9J68opvr&uCO>KhJnTCKg1-6KqKP7j0OD5h&GcrM zxUXrwoVq(Tx~mO^ZPwz?TL2>l1(W5a`;%_s!;#CXo#kOrd&RYk!spr5*I;{5Iv07K zQaJ^ikX}_Upe65_0@o|xbRek--aK!12VjE%@OPz6 z7tDzuPY-JdI9X&Z_>NX)MH`78KI5+aE{39)yE~CrUBD6pjoax>;y(ONe3NLi%r{6H zRwfXDp?OXElHl5wgzD>5)CTn!vo6EI?UzD8YTE<*bhplSv5O5{y-icl{|Q)|y7@$foJeT}*g8fhaI_@d0KvZOfUJrm?d9 zzHP!-+}JNTMfNrWY7>4SlX2r?#kG|W_qG$o!$KAD^T#%< za4#*^b=iH}IT|J|-7m5}w+u=oAdzCG3;FdA(H8q@d;<8C6;fc4mZe$j5go**Ek61l z(CqzEXz*783kQrMDN0`D=VLUo2IG{}`cfUo5H-Ni#%SUiB7ctU$$^I6xAOp1# zlk1qMY4^KoJ30t*yoldo|6)f-O6>)ex>lnE_Qg%(dZarDO}u&YL(fO>#eGT=Q9`7w zD!+af=#AUxl8zz{~@M>%VLR=Z81f2P6Cx&BReC zZ`6G5q7n3rSTb~3q_m#cty{#e(%x|8jhRx3U>K1E8|Nc`{Tv`b5GayFz zr3Z+DHX%m1leWFSrv#0p?Cl|UCO5(Ac*+@etyZf*2i@SR7C&C2*n5Cv46Os#uY{e+ z&F?4`CdKuVxpDNd&pGn&kK`<7CN07iw}j>A55p*hwXygfIXwrRwKffoU>)k>`lWQz zgdmz}EpHavSLtP$b@?-&5Kj0^H37 zY}NZi`wZs`iW&&(h5m=59Q7rkLyu4Xo6SAZ+*G3(39freMXdVvP+4CMwF|EF@B~`P zaua2NK`<*Bi~s*lcFReo<FL_ ztWdF=5QOsXiV=+m!LaQ$X1+oJ5|dzFeaF#z%HuH#+-c8w<+UoAE|R^*n99=fXJd!cTDS4x^xa`S-}6)OncCSX>IT?ZyM_aU>C@6N4t z1J)(Lz0YPM9;%)!@H{F9)xR638IRaaZ+C0aIN>gM6m2*do@4=54;=Fw60cF^0vL@R zJ-0k@puT*i6^aiI-vqGe9`~+xWG>4W@3+*?F~yT%FpXppg?4K`>Nx}cr=?apEs0a* zu$nY`_*vd?Y|2*=QD<22db zUlz`enr3V2f*;#G^sC^UY$ZqWdzK8~I~L0OUc!FtW}UanocfuYNKW;pE~#AupZ89$ zh#TL9`Zl#?LDVZ77KH;lfbaik8EvCY_I~(n@tV6A5FwCa_1%o2cCT6fX=&9;oFa3n zh?;a5v+U5y0OnRd7D0;be4=!#W1Y{|3qF0vM4lW3=0KM1wp#*<#X#vck&glll$qqq z<=XdQb2nA6VSm@)`q>74b8o#HNqT;K`w9x^>YRaUNwLSOvdQ=;lOd)8?W_A4s><#P z2^3|VI93)H+5=b#befoo-RVp+b%=i3{d?+3Spa$?MGh1)X(m77n56fK^+NDz%~IUq z%F_oX@K>p+lw&j#I0b%}nYj8yG z;E3w4;Wl&AR3+GVH*Bg9FfS90a&~JemMU9s#xzLq>|<@M`!va_7C<*6}MD`qR)AK-{qQ$U)DY zSN({298vislHC}*pH%tC(+{XP|KKJb0Z&?XPjf_hRZ;t0?J1)#v~-p~wodE+P!j(4 zXqiTn?lLa2y3cj#i zP!PbQ<8ZkvXC)lrM#A7MsZ`MO3jTF#$GMhlctM6sc%L`ghZFe;X@4PFr)krwlnnTC z^O*JkJOR(8KsPb235V45Oz&s_SX|u@<~-`!usn<@=M7*fZxUnEf;r4>($D`9=9$c! zo?aFKvA$y|Kz-5f%1<`A24mJbg;XWpzU;6TDh=H2rC9b`B3H9_RA%xMCGZSqfc;v4 zHf7^+kwxT4qrWX&gDLAUaL*XzSvznDpYkw?WK{YXS7b9p*8|Fw#oJV}3((9uZ+@Og zk{D|iGJ^6#y4@Z5E#47LOssx_q|Q5h>f1el)T-WhuT4U)8O$@InqaVQ;7YNcrcudMSG)}WNfi%AdkE6%vmA{t#j;tzTgT8J z00oP9#}1B@#X~`)wfEW*vT?dD%F^XHUog6#IEm$y<(#_lzG~m>@*}c_PwjaU2pcq~ zRCfke<^BASz+kw0Kd?qISe{0-iT4rWbkc=X4LObR{8N4EsQaJiIIpMz{S<52(uo%3 z=95lD$uP~=#y_Fso$<{IjX?jN1W8T7eFn755VbW}qHc(-`uEMi;t3J^CKZ}g4nZA} zmUgpom^;ZDY1OMBO*ZEKF=h?4B6LerA5Z|fC&?6sue=e!Wx-|K^5D_7X){mwhX&aP zVwPQ0Nax{-<=d{~TRl4UcmR8@S1R>_Y537H>yySG`IA#pK5mqy-LU>A?^F7l0E(MS zoh;h_3ZLZ<_b51|ad?PUih=8adwYHqp1L%suZB(}t7cwIL9}RlW@@_2UG{a~5ZFw@ zIh)>cX7%Sdd3p-6Ac?wA;X1IxsphO|%Zm4QrIH)lnz}N*iuf>FAZK3omm6uGKsvSh zB3sQ*2}j27eOH``K?i)O@a?t+@YW9|X-urKM(ILc(Fx~Yr!m&I( z3y83jk#jlHRT!SG_Hn^~mE@^$(-%adz`9&*R78R+U{kwSSC#wBmeJ9PxEm2|tG?S< zLy>I)j=LMdtKjtXSHGcQBLfq#-{(XhoSG?Md&v)#!z6v}GkBV_Ql{Q%|2xD0r3WQJ z7ob@^R1;w;t-a(fdt8aa3|+6GXZnzy ziMLAsclgQ6Q_WnLI;!eYRTcn-M7$RS~V76hhkMV&yjZJ_&NT~f4h z4n%o!{NJu^SH{p2-U!l)$j!IfW5naH%=n8trb;Hi6y++3n*}u$1wcaAHHp&1AjHjy zVyphAnl_n5pXX41h|pO8H9*S0AiSe|Y7psV=}Y@jt5V;{;70<8*$8qDo%UO~lpix7 z1$1@ZN|z~xQ#GR1zgQgU4)z?yyXMGe&8YuYdDA3o)q2ng zTrgM_X&3m{2#caMdDQH577$L`J~eEcF(_HmYwMhng{Z)X(G}Mp07?}##G(q3>WXqH zFI7N}f|Zs+l`2owANlo3xONznodln89!+kT&nuoTXPV0~4FS1EWA9h5S4U$Pmo z`19J(DyTZUD}c^18bo+~d*+Y#-870I6C%L=-tz$bu7Sg99k3(5#pF_%^K!U*QHt*j zalMr0s?e;4@AbZY&G1eqtn{w)h#(4oZ|nh~PML^~?B-FeEXC1{%0AW0a(3JGHxqD& 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�VMw$ski(!#@M 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

    BomS@Wd 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�xJtjA1BS=sRY&?7*kYb+An18aZAye&) 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

    ^c60{NWNfOm=e_N>Jl%s+XAQ{m_ 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

    `~t-Lb821@~uVk*QLw- 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 z%0D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

    -;urNFt@Y1`jSqO4r9rahXmBL`*Xyz^ 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ℑ_O)QE2f$8B_{VA)$}Bs@QN;%2W4 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�VBakQCDG5ugt6TKnb9h*+Nys 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 z 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%0DpcRj}Re4~V@4Z#ZdrJPWY(_%%Hx;LEu#&+|~ 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

    HKD-I3yps(2whAm zD$ax86t6;66q9}vl;}l$f)@YLE-c>8!}MU$uueVsF260G*zWzv&@?BEC!JM|ROqHj zNv^zZ${WROUZF$oZgRJ1c6ZG}my65k~*l{93PTaQ-+C}IGtdhY4 z>=7=(MHqz4xNy{>6-}WfCTijLi{F%XOD*`}@DJ6*Qon10D{g<=m^sj)Pe%SL^nlK{ z&7T8HI2)9+&%Qy(F=&EPFz3+*HyB6d{~v}^lm;tqy{7+F;97D|$WV@~0T2IZ9kqf! z{j^u~f=#U%j0f!39+%Lkf=`N4ULF zcsWG4h{x*^If2=ov!{a-2`fbB5|aA}9~)`SKwNThPr-9;k=Or8oQshxAEux5{WY@b zY1`um$*0^qTKS%rX2Kh*g`I@<`_A$E-3mZqeVr1ABQV5GFjWKZp=tbt_5A#_04k_| zpa2V)WPNy=(bKz2<$T15K<*iG_i|7gZI|cp4HTE5vkUH9F%ZIi0}D{2^blZd(7RNH z4nF^pHD#0{td$GJ$+kpw%53r;k}O82S*NAhX+n&KTuo*-A9%E$6o4pqXMTS%yzua zcO(LrsL_7(wQP|^bLYeJ_+=}3$`SVUQi&#r9_%FOT|2irBZDn{Ds#%p@*2cztA19^ z%rLMT&~wh=O1#>7Co#NT4j*asVm?ba#Gtlsw#gdSBP_ zV^sT3N{eJ^GF1uM6c;i(06Jr?E$_ zLLEvd?9jn*Aqylu4D!4mtg>V!)RBSJkCc0m!Wb&JQXt85oY&|61k7Ea8}U$eyPa9 zjL*Gk>r$>G1uKDfiyXnRD0{vaneDXm;?`J`E0GL>b0SXBqCrw~Hzd|XX^nWFOS$G} zF-mXt&@KBGG(+}9g%CzIe36Cnd-QNB_yn=*f{>&xSZtmCAGKLqMpt68Jq=ex?W(&$ zGu=4FYs3Lk)!C`s&1k~anIdAneHNF>wn*m~o8w1@tOtHJV~Kp@E*hVLB9%Jy#;WZe zd`#;=#Jp0UTg~}c76PN8w`vE92VRR{#ZE4wp4R>6%h`K<=H6drdtY?UxL^tD6K*Lv z|HNQoyf5-h$b+s?ULs?&2vQrC;{ljiy@_U>)o-KRhC1zxU$5IODY>jzaqVz5j@vJo2wIMrqpFO)#|0%_0v^a{E z>oM6iO)6`LSl)#Eo_+BeH>{j1wXddm|B9GkT~iWtZZ&?xx@1>XvK-p(cto z46gO_qBUn2fZJ-#olnMj``x*;i8rYcUC_fZjl017o3YI|8MLQ?HjcL?EROQm>`13C zP@iHgw}${ZcKw?nT$X@i2TLhA*-~InxAz`AKL-sl`P?s?43`yK(keg41f3(@F`8%GQso;ZQmhN@5(LVdz-sy0w9!G9mIL{{!wh706}tY4Oe#`05JPzT;{Cf zwH3kj#wVC?u*bcLt)GO%FXlUkvDAK)vzZu^*uXqZ24ITk5~8Q7f}heGan z;p^GXtp6}T_T_x%bm~OpJSG2ll?v?gC~dG*DN9*aLR$Ad+Fx|z^!S*fkE_#O4#w5) z-wa$t#u%`HPMa^?4O4PK>7*!P1K+{uL9``J3tII-fsV*1M=d}|hJP)+ysg2BkG}S~ z#@*nMl~Wy(&bYK7e)@(~q2up8g1+>t!_M1kUoX(8@ih9HO)Lk6DTQs(P5Y zlo%W?z`w73WujRCHlGY;pfcw6ym#o7PUa{s2lxV1Q2Jp>9|N%M&B4SQbg`_fnpF`u zFokh;23-(P>gM9VwMxAo%X%y!+}yl7>9X#!oDQ#D1TZT&KS66*N#kXs4^#v;@6J_g zBg%3KBV+)$0^}Cj3hu;vR;aD}s>oqeNh*<24o7lcW@+KZ64&u%Q^b97`$OsP+l0&p zA)oLAs>wlab$Up#`5OXnPguqM11EA;QwrZEm@rGW#~*$nJS(BukgII)G)E*@8gX!~ z0@7dUXBzz^QG0GxpEWJQEV3)JX1~4bha86Ndu6t8_uRKwWp5LXIodL~2=9(dj8?#VmDZ-Tx z1mVO|r{*ex9JKxGDC5(zEdMrz)L9yI%&uNv8@F?@D&^#PO1G`SJc;#@jUaIsv3MwM2_vu5OcZb>z{Ww$_ zlJ6*?K&_r+2E=7uB-<_(O_US}N9(L6 z_>NgDWp$O7P{o)P{UQv*xFL(l(5RJ{t15|auh;iVUq@#Uex^JBeEeV#`>o%!I^rko z%ND6YE6sJ846EFqoU93(ATdHwj#7z=r@4N|qG6`w8u8-6Yy6J-&0Ju0{zbDQd^}^^ zGa5|b&5~4Bn=Vj&wB79~g-Vf|ka)=IsCrlx6*z~Ifwf9KP>E$^lL7Q}1l(R_@46Kz zcr5eYaRAFMLGdVG$f-r5X=Ra3WtKs_p3t=*Q=ej!t1WIs3cnsm4}YP`YVm6`e9|jW zwnE_dtpPU%I$rb5J2}@DDxky=5LJ@Vjah?i8Gx;e*!sfTMIf^xQ<0a;o~hYf zudp&Of>^*^E5FbI`#T1=S|qjg_lb3&!~ZV(7;_Q!fTP*};%WG%V#DdGJ2@F|VNrwg zV9P!?3vjS00XcH}J#^VlQ<+6_#-Y;>3|6fQwjAN0ZjB!HLg00NLBvP95JgJFHg9Bs z?W{)%+*@~rTvH0N>6xR+hoQo~|@6V0i@7QK9cgEbQ6 z%pJihe8eVS)Gc~z`x$Zh$1_7H^9Y10lqcB#t8mkTnh@May};^IV4WqYXP(OB8qXkr@WcVS2jX6XPA4yjmnkb9ZNj0nUN(1XY2Sv{9W?1$kJ#n65e~}_ z2w|*Pe)}$L(9{S9r(?)HgSUG3+N&LATF`0*7HZLH_~evH7K`E*(9FOXX*d=QcuezS zOW6_ss)${q{hyk*aL2Axb+HPw!5YmP$-IbW5HWB>M`j*o(P8s)bs5_E^)&Je)4j0? z!t{p?QmyY!w5uvFp_Hn=%Y6HS6(e(PPzIkzE|}a5*6)w+k_KUbZLZR1@pj=Wjz`t3 zJDni)!Za~1KmAgC%?Uor?VZ-^7L`!7k{~rgX;C(7uNfh(C`=!$s94bo`mTEsJA|jn zbED|XBeo&*e3Sq8NV*4Azx{EUj@A#(W(FlVzl3t9`gL7JW1m%*w*}7!Ijdk}7ni!Y z0FsNjIdm5!eEI-N-Pg&jZt|5-#(Hap@Uvn5um0w0>1~OP@FUXcP|O_aAzsy+I`%T+}|X zzRaUUl8Y3Z4>!~Lu{8-%xs=wh7Zk7ku}^IDost|v+N%XxwH1@D9kbg`59#d6D^#mt zi9#JEL%9lF7Hf(=I)l3u8vmDbuYAe<(ogFvK(+4vOk+0=EyBshhS!G!nmhh1{F(6ak% z{)4`88A78dE2{5Ty84H#eg?pY0)@`sj_!~5p|Qp=l)-?$K>0dMy)k|;pm?)WB{_QO zCsn@@DnXT(HJ``Gaqlg5KceOoF)*Vl?&!cY`oAFWHK0X9?N2SVj_=Nu{JgDxq(zZ# zAKu+>)9*42R*)ujyc;9a?z%qx0E4cYBQ_!lb71>r+>hsxh|*T-QbQGtI3dA>s4J73 zTtAPR>6v$FA8+=X(9$EKe|da3$P;lh%?veO2eNi?PX1*NPQ2tC{uEMQTvmU;eB{Ig~ z_M60jI&t=kcT=WUm}JHZ$I<_lzuf*lYo8NR3O3CX{zT+Ht`>3MoO8OvVR^QfGeqJC zMCy#w`Kc=UjcGz!8^~UY}! zopN&NoXUz*TMsj}H=cK<0yQuY!)0?wFRdJ|A4m3{i3NZ!x~&YS2@JSP1h=O z3FqSil=0%<;%CTk7+H>_8X)t*f05fdHhK<&3+U{n46&hK6q%lvdZbBxMap;t2zd4} zd`ShJih!_{jEO6HJuTi>P&JPlKxuElGO+ujH%&!@ryTXrU_+d#5g!H}gFQvD-l2h8 zK6plEuyl(C7)^i-m{2m+=JqPVQ>w@tqvf~}@5M7k099P@TyUS7eO1w*5(;+p=S}dC z@}`Whf9Anz#j{WogETffCKJe7{VB1Cb}+8ocMqQd1q1u&EzUSTdpmIny&{Q!Qp+L^ zOj0Ov@ZW+rN~_eN?!>`N#OoXwndo@IzYT8nISKop!4HnEcx^)vo=m7K--#MCyu|$+ zDiFdnM>)cL+i;lC5VPa~rke${@q3MHQ{|+S0efU=5*vPUVzI%qxQ9{7xYZaHr2cwj zEVdb({UG*$Q4`bUQY`JP91%E?`0Ma^@+hXR`r#4D)$|>g2EiS#$Z_7se_RA|^cWq_ z-i!;%{7CUswa{YWy%%TcR9LIEw5P(R^|Vn4_}7jXVms2s#uL85IVd^kB+w(KmED+s zBMk4Q&k(sR0KErghm|Mnhe3T~hATHd3ReAe7YgV(bzl-ar>ZyKwS&G#-led9`FmFM z>Ov(rUlQZ<>Bl-~;<($`s`@LeVWw>ut1k562_1IMHj_b-r3p06#R4huLU6Z7B^E?P2#<%?4YSXl_5;D9ZsL|%m#s%Zj!d!ql-qm9y*wQt(&9s=JdR9=V?$GrC zicw>RMMpZ58_jzM z-h6%kew4IkRQ(I6GL?HEs!%gyxKHBfv962?n-Ci}-XCMuJzcC_5MPPEgjdy{?~As7 zs@Izg^j`t&j)W$y64s*qLhGNc38__*F~uYd7%Wi_#(oK`I?1Cw_v4$M(c-E+fc!j1 zh^Lie9kWQnJB++A@Pk>xETZ`lO)t{U8gSt=wf zg;|9H>~gU0M@wG%XoifKl-apUaA20klSTj-NH_=>IQ3b8o{f%Q2-<5k?uGUeGY&R>}^BxYsd$4lG8BhxGGfE^Q#It{T6T;IBw_&kY z*S1TPy%@9Ji$3#Cu^QWz5UGFBe3Tz{0SRF-0B5TrRfbG8*S(q}w$mMRxssq2(0O$B zhmwX4OjIC*A>$`{gbYl5QPQBE{R?DkS69@t8neYd1=jEen>F9oVzRt8NT*<3Qur<7 z!?eh@rI5IK9gP)7T(1b#kTnvC5=w6$<$%Il8@axcl+upOu=qdJLv(+88=_2PdM)`x zI%18PHuzW|Hzg@-=*{Tw(9N`3yo61mG<%*)#885l!;?T4w|=2>~nN zjocy>#fxI!N2d7XFM z*w?f~9ax*S6ojZp|6N2j@t(Smr9Q5L@Q?K}64!?au>_v1Eru(bqDSU;n%hpFW`s!D z9!re2`t#Xbn+Kye)8-j{MexgObcD5~J0Uj%Ti+R5bc<4aw<))C*RmXH{XTiv?^Zdu zEwAiC0Y_y>hTQ|c8&OECFU`oDo2zNut>aTbzCpM^iyB%surjk543oo zqyr}x1$%P5^B5tg2u}#yHFGrj#{89Fm79wH#0I?@Bp$Pr^DxZOs{9>+jpB zL?|-;cpEpfMFP|XL^qJNlyROX?aF`YwXvjhHnDAr2W(MhGGW89iNto`$i##^0C*Re zAAf&SL|*5(An5c75*2G=h+{=j%rZc|pBURL=qZ6Vh2>wF;R7uHT2a=aX1f{SoM3!j zZsKQXH$AHP&!+#CfkhZh`FKqQVVA*sRcgVB5~i9%G)HdX?DqOeEiK&std%=+eNeY` zsr0IAqwixQ;}Z~wO0!dY_1=ti_MV z{2Wg5G{eA7eYW~|ts7(Dg};u11>nm%&m0TPpV5t7us0({ElTWpt}rZ#dd}^fS-2c- zjGEijTH@dR@Fp<+R@=BK!)5_vqS(3aFaDaAA7u^~tghPnp;vyn8FNgPg&(9+#07hb zgn@Rf9))Kh77XEVSJooqi?f&B0`8vc`%Qq5Y3 z%rOHVwD%Na3O+GMYTO!hT59ZLT80mU{t*f ziP!{$D7Q!qp|I!nZ<9a4e<)PU5RN@LOuFMr#oc@RCwp~xJwN%sT*A91b9G1q!;Y#c-S6j{7plJ|phlTNp-Z?(`WbALG64&2yidE2JK$D)WlIdFqCZD9NnJ&f(W9foPom(1 zFa_kl$NYk)hC4}v23T>Rr(dXw>Lcj(^M(K3oV227P0T>YAhXhU;oiT_-4CX76*c6` zsA_sDqgRalah=j(uJZaYN_2mho|DGn=i7#niXbMMwUdr<&e`@c0&ZV|l8!MIFM zypQPE^{dhjDel17-^SN;!9jE8Qe)8Z4+2pv7jhrV??&-!rEXn+(Xa&jmp87O`8+D% z5Ak*m7-bln5W>4u2psER_zJH~RtnUhig$yl0+Tp2&}oe>?k%~fsJ3)RpPFVhR#^dK zX&Tc`=iPUcM60tEi-^P^!~|rUc=dZ@HSe`_3Wg@_H;ze7Lq#qMSNbnoF;sR|qIQ78 z_`dp-XsuDEh(0y?x{RrEId2#>rzD42OrqXnXa#U~NR~hpx)P#0?AGv3lkw_S25onL z=g{Pl-LA%G_6%Ch{085^7wqkvzjd3uI<+#L-jcgG7b^uczd)pxoYS*xk%NYw__YvM%y*09r+D~NUCgMs>wz8jca==#+eEQ`6{kjfgYaM;~G6! z3dw36ztmZaAtboY(`n%BD58F}Pm`#SiLhZw$d$rBB*@q8uU-CzHDsCgLKl!n?$S?6 zpbfVhVH&B(TT)d_K%Ir1EeEG9c7>Y@59AHwyPJ<3*4Oh3;c}=J(#n%X?%L7v@Er6L z1X7~YxI^*9oHMHHloG>wf9|wH=&x%jp%?pI{?kjHVcb9qG;xr`ji$7K4zvuEq_&56 zXwcr&i0r@~b7V!Ghcw=W&;PMriUqd%iDOC2(8P*`Zz z3a-0E0XpMFm3AW7`$m3wq39f~)AhV5R18jWTFuonMOlCBnU}2c@9evyQ0geZz1sJho`k|=ilwvNkD>w=^n zYeZ>|8IRrHBcS?XHW+qa#}1I3sk#p{o;P3R^nbP??OxWVq|(>{HABVQ3rov#9lMz2 z1=hU}y^w!rSwsY%@ExMKkDD%_FH!;xG#BsjsZJ-FxLK)B55DyRSA6{mw+pOMS=L$w#qQL$ z2>-3RY~p-0gfUGEtY0<~O&$CChN^5U+M6eKF|6tvFQ9KBVmkR3^_`fp15-)}`K3O` znxVHXRxlae?p8kkBE|y&v!@P6-iyG;ww9r+e=1QSI-6(M4)AkSJ2OoBGgXz%Kyk^{ zxRD1%)a2+-BoFT;cVg2)BaM;mjkIRIr|c-Q{2lvi`OQu+7W4Qxw_2jc@Ow)fpICJs zzGAtux=f?^xk_p3v!^pKz*S-9M$XRo!Oi0}SrKhPr})WK+(#p(azL5dC|n}ov0T%s zoMk%vH>dk5Aa1n}t{QqfIt&K=lhQg_dL2Ad#ioKk+eZXtb|w)t282?U%-Ez4l}fr| zFLygfWlE-C+l&(jiyG`pl;#pO{V>GFYt4nV2FpuA==W>T(YN}@7f$VN5NEHq&OTAj zVL3|*F0!%5_;13*+)KqJ|EN59br%Gy@Wo=IIL^p1Z$(&MRtxyhtIvWTb%rdc-0X1W z|814e6m8^m77r?5T}H|sr;7-S17&(2n7<;&$l0F|0ORLuGZ;z5-K1aNR2^<`GAk>& z(@6+yNk}Rc+>o?*sms^w?p8Hqfu2T5y+tv#`u!Ee-1yu?)sCd!lj_S^+IE`rw466- zr23mal<~J%ZWUUBA9Zrk5O6uuD6eUKDliEYJ)ejes+acMit{bCE%QnKkjm##sQoPi@=x9 z>`>>us#RViMM#lN&mEFCFgmimL6k$6M$yf0`~?<>FTv?N(BW1p{4?4yr#-%#gU(PHjP3*TLd|Sk`sO3JO8iW(V1zklY@P<@!bYmul zU^rM(wP~iHrb!kw2}S0(H4G}=Y<4?5D$J%}f|0+KZ&#uRg=^Tx+-I|VY^E;8mMO60S!eS{f31}aH07WL&lX;{%a8sVNw#J-lJLK0t9|a zTR&vN76VIW#K+p#l%ZPOA?wffAMLFjSRg{3YzIM~L8^tYDJ-rOcNbxo^NmyWz?uFE zpV|Mdt&3SL4XYL5kJP8A6|sce8Cv3i^X7jQk7C?>bVZ5(`vmB?p0N7eyvvFS(9;P2 zCdq;ItJ*dp*)F2}LCbzEXvy*M4r`iPA=O7PB2wF1exd4prsI3~vf!^fUFr+MlW#;*c*4P%XxDyo(*o+aN2|KDcy zIYjQZzvfkjFYTtD`yCLJoTQ@MB=zhMi!!(!&q5-orIBW#)TBg%QHi9Or|sw`4SpaXhLw&3!pNENbQ% z0zkn@hsexlDn4i=he&F}`G zqAnrUtu2LmMo;yPPG#jHTCy*YAr;88UA&xA7cB9hw-v0$)Re-rdSEM*O|V zz%ryfk(z*QKYQibuDhCN*~~ul&M!7fe#~8o<)h{K&X8F~!kzw7x7O9JuUgr zC^JKKc4f4^_x!{P^4)Y62dJx zv9(>p#xrX;S4;nFRXu}*+_W=sGI6&$r$AZ6+wsSy1gby`#cK~g9yZGPw!8n2kH_}) z-PL;D#h$7p%A~_C(6!W6aMlUBF}kn$5&V5zN#7!JZJ+lmY9V$aLjQq8F;~!MWX9T6 z#vD~tbSeeiHA5s$IgJ3H;#h12wAnubVhFga{D8{F8RpDnRrKYQChi+y1}ldf&P#nT z4DXJ^bElINKsVHti$^CpQy^sx45?@;dJ+>VAbA++Xrnx_0%Vy}%uQ$1)~6@!&X^=5 z9@WMq;LZmhupqmcr(60_e}2fkDoIbv4xyQktla_ZxqZGli<#Y-vlx|wzx1wVracp{ zE-TV-uvV%^5X!$}s4y)ywni<}hCYl|!28Fd zGr)vQH*uW$t06zxC{Zyaz9hq9GSNQmdL?HMOU%Rnj&04Sf}BXQPVG0-G*vvUD#^S= z@OWbWSONKTNS;w6altw_VQ59JuWH9Mn2&Gr?u5V?y%;wx|Lvlo=qi`5AXPLL2c z%4v{*Zapyq`)NZcP4IQDx}Dq0qI_wH?MUi6qO^j?U7n)HPt77kUB5Sh{BdhSxJ^3M zV3FX}_S!br2=5pUnScfkxYD^VNo|VIqNgkn4KI;97q;yO0oGBVOaZ0YwGK1osUg{kiWWG_Lf% z=_${_Fc-be8W$O2dp4u7C}OKhacq5IR237Wd8!>YSU<$#V#5>?OdJ4p--@J8=NK~K&kL|I!6k8smVnk^k;RAQZSa8g^06B{$7qY za41k*|I-sq%^c^#94h;Nfj%A3tu*`pC;!?a2DuNfe9C*9zifoA2#(3$aCJ%s@Pz z#?Q{C8S8p6YJ=hF5Mv&$jn5emsL|0>{5k0^|1b_MTOUkj4eEl9ezzm@2=v;Qyth1v z9I$D!y^9+1^*VdBwUW+8TJ`2b-BW3;7q9Ks-!q4)+>zraNbE!0R-plbRsw(cn-q~~ zq_#Km43kg$lC|ngG@h;Q=i#?k(e6xpmvc}pjL7Mhh5|l99WID41g9MKULS3r@s~-( zSEl&L%)!k}q!}QjdsU*vW2ikUR`l;%!~au^L2#l%qd-&Ui6#9StZa^vK_2i)Na&KA z{m3>h@&kkL?W9^YCDs3}cne|*Ohi7Do6^G6Z63&Y5ET~=SB|LT2HZ#7WAqH|=uD~b znwJoTaQ%)*ive-UGZ6rPT}rG&M+<%-9ex}1t-gZ8Y3lh$rA5@B=mwz$1Tj2X2qwT} z{c~CM+I`nSH3ot3*v##!nP7w%13t2bk=X**wgr~8zwx*g37<4SWb_!7an+P>gkKhwOiU=|GI0!NThr2Ryi}V z!GbBmVCt%}FQ4)Fd_w8u5|F@zXJ_56CqJp6y4ghvB*A&Sru8kVnBFAXlcJad*wiM;7F=D6}&!Pz>Zz z^cqfJNdm-YzTLT=q+(N$f@>CNugdC+hrjZ$Qph`Oa-7=kEwu}iLp^1vy)4>Tw&n<+ z(bmR^l;rbs!$OV?GKFSmzR?JUUK&^um5uCu{cf<5`5F^1H#ogPg%X0=m(I1n@an#) zUy0cQg&Pg~rWBG0W`W}lW*~t3CQhX3q4_C-Rz_=XcAv34LVsfzy3<^;Q%}E`IE?p` zczew;Spk|U*qteXvtjoGBF0y>QLOOA&+JjT>(TT6xfo`{hCYtI(yLwq$lJpm;+N^w zi*B9ni3W9;lv#u+k0})0l}A5Cs=m~}_=@7UWv^(|zD-RINaLxa<1#o?nM5EV>Wff zI9X`UuhJ(ZiZ@pv&Ulxn1BwDeu~5`Te7!<;aI@`kDjN_}kf*?oKGPbQujh@n1Qd?^ z<$eDEFFZ{aO=4EEu6j^$5Tm_dmKR03BQo)^Gc?G;my@b8SN80v&i)dn65eke$m=~I zXZ4&(_zd$Ir%@aZz`O)Uq*S6curNcar(ttgJ}`2mPkMqb}VpPUIyRo%Iwfb(cz`IpDWLU zZ$!U@O+xEzr2Pd>ON5bqvld*&q_a$W_u0AUtM{43z)TetKddTU*OpgRZ;&tM$RyF-as>R`H$A4ZGMZ{N3;Db~}%7m%KSd+Ds`tbWA^D>FcIN%ifv(E|u} zVtIXhDN}Q@4vuj$zY|xpfUmAqk#FRGB|(2YltHneo+nzhNpq8g)?VBtAxOg!`0N*R zo?2KRCG+s`v@_Crg;^^!M>@z>;N{T<(iDQJM3&9V{r1}dW!T<{2GR~$5BfA;G+|?o z8eEkj`nJ!P0zO#Zoul$#xTf!*I=A_aW%gIM|K15soD9z-b}W&BLpox*l~8ZoJ_UEp zTXkbp;P#o_gy4!DJpmvk=@_;(znh^aFbge{4FTOwCAH z?PR92uScm6z$Sr-C&BLjK9~`zargoR|5_i0)dru*bn5r5c_`rj)|4s!PBRt1`f5=6SGhYYK1#T!sK_ zh*E1CU_oDUj=(8T2b29qmc%-UM-whC|GW7bt%!_A{#(-`07=6;LJiCKe0rjf^=!G{ z(h4pGoUjEj9nYu~Lm%MuEtn>~Sh_iKf4(@opg`0^fxlu`q?1|tW?u%s$yVx0>!=4T z-lh2mjHUalaxHM)NqXpnx4@2lVAlsGfkJ>?_-BPwEd{$Z?HNTdB7h#!k$TK@*h<>W zUlHf}i-UOZ6Evc)55kIp+K4h2*5Gp+a(v?%**=JnGz!IetuEj|_dVjZG zTssB9hUzwnz%DMwOv5@!Ue^c0S$h;2412D1wX(bJg;7^F!d0;%SWeU))#Vch48cz(`_xexhgSJAA{>!5bJX`s=$VSeAufA^qOmHs| z+}W4!J{Y?hmTV5^_!}l(ANvF>r;}QTmC-z@Ug28VvLnIEHiPi0@ulSsNl}&*O076> zb+wSOiJh;wKp-DJWGnu(wZgLc>#%wEVv=j`sLF8k_d6_m1e;tYl>=x^py6-=v7l7{ zMV(d4x&@IOvydg~dI^~9pgDzv?qGzOF+Fdq;3tdKGQ3|yWrQdEW(`Q$S;s#BThmCP zT`F;#G5@BBV&tAW<*~ZLb|L>BCdhqeK-^?fOI63P4w=n^P<8Zc`Db4+EW1car-;ey zSY^&|z%^^1#ic%iFXR379}k&e@9EkT>Hh22a^e6HmqD_g2utQkqVwakh`itFPSI`h z;EGbJnuQ>cq>^6JLDabuyZpYDUh!-0?nnA)jdh1;27y z)oW5t+v>ydE)iy;H6-I<*J-1a6WfNdDTp4@<91m|QR&a84DVzeD3RV$aq}#FwAJ~k zt&mGL8Ml(kbeIu8PImr>VcNXVWkZRr4+EpOB%zWXkO*gjoziRS+V86x!0%&E^f z4^gE2C)+?GZzeW}U~0p~FsTOT6>gIJ>!Z;O95>3|hx0px<2Q@3e9-g!`WyzSV~voC zirtBUfhqu42K+Jpg+ar}?li5+c}{m3Rj&`}EIePuwg0^F;PYWU#}83J)nqYjy*5%6 zOWyy#^`M5o(O~phoTYYl7C|}Gv&4a7ln(lo;0A?<>oav`Cq)f!;F zk2WCD_F!7!q>0Ccar|cq*f^IH{?KMpI~XlU;vXCKmF4SBV_G@mdGWg zWA5IdMRmPm!byDl*|#%H#TGc-udJ9TWvg}SykmqOK!=e6OUvW`^B15qJhb5Q+AIX* z@gLyn4R|@=QP`wjd5x6?&5L%u^7%Af+h79bi2%rHf>T3aC6;HP028vsj;6mntsmcV z3H56*88nZ{->-+RQnSa6T%f>5pUW+8dQr|9^#?27tH6lr(UxPWqa>WqPs{vI)op;z z%3c<2A3*IbX$)*$qnWQnNa?co9={D^u~p&%Y$PES@p)(l$XuhMGt9O1W}@*m3pbbK zfW6}TStaBk>WKNmXo#iBLDLZPsWF4N`I6+Bc8JfoZfk1l)o@DEd(tgTp?_V<%ZUpU zvKUBZMDt8SE_BsZ*)N2Kdr*hwlbh%Do*kOG-|RSMB{XvC1AWxaY|WD6G}EE^_&yr` z-3(Oco_>A3n(1#d=LnVhlIKsOx;Yl8`cDq8Qb$h4EdIlYM0W(d17gNXIZ=~QHV?kO znW04o`qd&=zGUe1%H8AGt!*WvkuNfot+a!N2(MjUI zC-FFFfPCy1bS5Iw+kX+QSmFKZekx5>>s8iTJ)69&_mwI&=h!-k*-@c$RoeDnJOX^t zDf?$D0_Mx^iHVQ7 z%Cy-whd1gG78Ia3Vc31B2CKk{TRtwoiJT^xX5-lS0p+D#<-IC_^bpmzE6m&-bx7%R zFU|-ud?_fan~D}q?`_SZ|8|ieOLhv*NR`4~A*fe=3v3GxU&fsW0fw**I87=~#~BNY zw%e`nl`gcMF2&YCVYh#~a(NuA(Jha+_(xO2{nz`hKG2pPAZ7+UxDan6PWsc9mvLs| zAflyt=VhIn`;6K=a!jp6A=xSWy`lL-)!9^b>*LHV0d^wHc2Y>gannw|IhyZPG4ckY z5oWQ!??#EX1I`T@iJ&}R7Y{tX?`h4DNN=`Dn7qh6YVn8K#Dxt*oOsO?Pywz)^O_qR z&0m>`Lmk#5VNfkjA{!{>_QGOmVxnTXH@mG|^u4`k&7WH+8Ho$UXR|$G#J#T_u_grP zeE+z4#BFqfEQ*ODM*V`h4_}@Tqpt5x!9OZY^pt99W)#CgkEz7H(K-7yp2m%rLt5Lf z6T(q17-eOBtvd#qTbIJRje5be3AcSQVcL>JFpNMA7Hk4x*R^KOK-wvEN3lRA_V`p# zd00@JcgIy%CMEMR-(5BS@YZi#Z_I8#gBe2YW`CBl;q^&%#U3^(e|uVFC7r&-w`gJmIba9z^s1}X zhu8+#=|Nhw?AlY^QLHbK^NC4YZ*c#;e|wy`)Ypzph1i!GqYoftx18{7&5sifj3O~W z39E&Q(Wv4PQ1@0^zPjX9*l}8B^6tI|vNTaYGb3gbdNi(}oYMd?P=5zYW~~~a9B8`u zQ$t21;Cqer!w-kwET}kML>yP$wa)Pl7gkMtbZU6s`nwHRy$-e_JQ74>rR@~S988_H z2Ao8cHdR>rjfUf@Z4NCkv5%ezlt^k!0tSjW{A(V0`e7vl4XriEfIzzIN0$6?M(vyoS) zC-m!)ng~KGvN6DR#;h~pBGFL!o9dt)=i>US-VG9pc;{iQ#PsCW6pl7%Gt`{S=Q|+O zY;?haRr#A&@G0$Fxmy zd_=E~xF2fQ=fZUPC<~uT5Xgi`NvXNQg{0MhasQfX{D~@!heAr_4>el9xkd`9dWu{u zZ)+cnFtrxs$(k!L9fCjrooriM3SM-<+S|rBaiR$dytIxP`@>t1{d2GIQyI> zV;Z<7v4({VedW|O?;9?V?oM7x?u?hVOv6WyW}v3gBZ1`cAT(jPj!U3H_VoRH?d+ze zW(+Ft?T#3%H~^&uM6ET7`V&!SAA;GSSxLd?W2XdSQZz4Kx~>``I#bT>_Ka&P;~!l< z3~LSER$H{8 zu#9O+x&+D8?!KC=M`2Zmopf4&LQO;5w|EwH7(}Qu6o1lI6SbSRIA^iRR6;!Ee!dSk z=DNtb&_T=2UynquXf^&*{2GfoE&<*cR!)1n&0-H_o| zN!=^x=h}*Ko|>11>)NG0QACvB z>QlOFIGjwXvR$4ck~r_Qsb``~H`NUBePORG8|%YdJy>glaWi1pXRY4h241RZ<1m)= zbenBqN?i;}bT4i&OEV+h58f8UwTEuq3N!jw5Lq<(@iNNwjvSYb=#8qvcvxo+%DI9kXbkbN&Y#=t{=b{OYCLDVy3q7crvU=_l=+BP;*db=Q(t_TT!}A4XZ@!Apcc z6B5cIP^Xu(d-mH%!98biRTgp;;jz`&u-Y#ux+!m*>u$zsWM4*R$+G(kAeBRZ*KVEo zOH9uX$1SuL;}tPQ?xKTGBtcUgQADa_7OI93tcG)D4HYzV7}gwyaWK34yf(V=Ix6$Y zQRO0z-jrfrxewrqSUWZRdT2ns=C*&MNr)mJLqh&kv*8#oguJzz(0|FKKXC|V$s{VR z6vpG;kX?Xr<0qetN8tIAMl2(o4LY0m;|)S(~at=ykq4S9jvY^;c+v_Rr*nG3N=?{+sJWWRaiDV z4Py6eDQ%Pk3DB}P`<}SPTlW0pQ!EXsk7!m$@67DHp>SNb|AllfTy`UCnb(G*m1@mA znQ6y-HBOPO!gA_v$$q^juH)6x4~*$L6Am@sr?9f1n%{yOA2z(J z=?diX%#prMwFw4LlpWuBhE)grS%LMBG_%B)uw8K@?jSUq?a!D)SEX&CViz5W$zXuR zVtGTLjJI@+?ISnN`mCv&p_}~-A>nz-iy?i;*1+2&0sNjo*OZ3QB|%}EnSFUximv9s z_q#K#2}vYzeDP4tCp#~(U(5R=bfe0tOD+euoYAhtvyD4jh)T8SE$j(20$mzub4c?^ z2MKBo3AB#-RN*+7ckqW#r4iAvk8>suJS#$3u9RD0p{5B3<#_Nkd8r@u(~4dUmT+U7 z{DV*G;b@0=v%A2M7cFW6u3x2>pkERqtvIj!$J60eI?O&_yK-rY@X%O7@&ybR7hxc};|gGJh%ij5ylv32bK&p7XHRersZ+wcjNAJ8n@$>da=gBkp_TCj zT^+fmzMfrxIq(Cw?qsl{D)0v#CVG+g(7GluKZFJ)ODqFX`E+eawEYc{s@fzv57lDj zFBuYLv+6-gu&SvonT5)E?VnGC^)q3@dUvJrv`L`A0F#g&V!AA)nBy=IRof6mBbx0a z6_Yc;_sM~KZE~V-R;To;B9--v7}*X3uk({YT`_PeHZH#lb~?-5by*cw7R&7~2h$`6 zaUu>MiorWaQ6Pp-`Ivg^tjnRAtU%>-oWYaJxAUkqjaBX*3i^|yQGE>FPH7MmeJE9V zt`hWM)O+*wK1*OpiI|! z9Br*PQ`8K%mY;c~Yv2GiThO*<6k^t11MQ=mD2ez09Ab&4Y?y;iN;)tK$$I2%Z}#@*e~M0W&wytX!p@D$x^hF!)mAmCKNZZ5IyFw?}LPR%8q}eQQH1{1p={5K#Kd`ljubLWV{2XsYpE+JQ_d!+wsR z9Nj_qK&}b=1-Wtfy9l=N?}S_6rwNK)S4=2YS8HWuFS|IsAic2}2N1nXq16+|Vzg-E zRuQ?Ddq10s*zBoX)A)90ZSXEQ!SH)LXagb)V#34!t7K~Ok0@NU*=aQ~!U#0L8!7`C5%P%CKz zsC`Vkbn2=veN{pBdE%;_9A+evi<7!UY1+evpUIyu>urh3qS70PLMVp)@lUm|i)}dK zqcLg(b6;weVyZWDfZIbl<3>@-7cJ(G!;cjsG~cKxF5 z=HX?i&OH^YR=f{ILkz`+zJjPs2csvFo7)IX-=#wU%law($M3%GIDf<6%Hf85AT*W# z6`FO-bee2-0SM6W<6HYN1vEA(Xnv2cZUGzzl2mLFQ1|hDpK{mdM_=IYGSPdh=lIFNAiDdu_g(vX6hUO=7cebK#+X1;!xzdJ zG4|L$zeGPBNYb)JpRkEWT1MXSr5pfEwxHmg1x6JhJn;w6I8;NePC<3W-eHtZ*`p(#}DntEQ|meI>~v2u@TKj=8={=OH?u^Z)&JktbE^<%#c z&R;b^K49*B*n~cXt*jmuIA(emYKlWkn3hp9Up{j(%dNODeBQt>O?gqOz_B$dzzHTMA7(9?J-5Nj`JP+t%H0~%0-Vr$CqDFk-%1cYt99LS$ zJ(2!HwcH-t9RD0@(1`y~Hb=bMQ)u=_3yCHOCuv~v<@Y|}mb0OTnO#jwV(A9$$q5;j zZHXAY?>W4%UafrQf}OS~Q$i$Ru^5-13 zl6XRP`$3^sE*@bXD2b|uv{)*7&BU(xoq9eRwYU{Hg_j3hwM4$qL$Ar6xYKM!ZC{>1 z1v$xDNLK#@t+bg0IXBa(jmOQm6eIVOj+@LUztyesOl>o?3;TL*GPY7Aac*QFC%p?V z6Xx4)sbMlNA4$;oerSq*QQ$XN`UpAEm`s3>s0wCeeGNX(Kc>y!ix~JqF%*-D!rDlfnTnC+Y z*<`QkynC2!Du{NRdHD_I?6VCy_H9Na7(okGmD)x0p`PiICV2)WM=JW6)~=5ru9$~E zk@hfsfr#2Ze_4Z=$m5p8=|q2#tfuYXNiX@$=yn*J%G(yUB~OjDAk9o#!cPvWI{5hB z4;KE0U?E7siatE@c||D%zC7+A}jiV#A)G)P(Z{^Xlw%?c_O4CiWUV!K%K`uiC~-f_8@*nDei6Ie!VquSIG5Wav50K$K)29z|ocPgkCj6C}QhyaoBK*B5MX)Z2Zz2D3>Ar3PfzYagzE`zx9+ry$YIUNUb6Uwvo#DkTfTIqo`<#)3G^H@+rnJx>d@rnvE?f~=1P67a?sXlI^al; z5#T$Xm1bkjOGDIu*$O)P)hTj$dea@n`FKO}Mww z$@m+AYOZ7_z~8*XXOuD!jxBME$Z#I_nek1cWyNAhkQ5z{{Rp~Q9Rn+%Usat661T!^HOw|Cv$?3w!>U}(kxCJzh8|Lmqkw z#Zi}7Faznx8dEN%m z$;uxW&zOAE8aS3BxY#jv0o4W0)TVUhn8ZKYITxu}?@l^|I7ZV?{6X?HTkT0(i|!6dYxf#wcx+B6;hh z=&nNSG%O|ib28CqLep!#@Uj`^nJ@5*^a8})(tg=4qRp&L{bI~y z2t%I40}-N@U*8Eyd>Z?=WD*Z)*pLJ1;cFbS>_<%NG@g&n$4eYWP#$mAwwxt!_i|~I;NBckgugQmR6fAFfx%#pb2a>X`AOFv zv$SsOFxEq|UV;y+Yzss~SVRK3q7krx!+wImw;#HMGa(RIE|8wsWJiUIm+@|4Cd49x5$VI5oq$_yab$r0( z=^=x^PPVHy*-%Nfl@y()n{TNfVw>hBfXnc2&Ql7zeyYU#UC}am zLW?a%h;HAA+Zv(%>vf>pVkjMn{Sq}~#MVA_ov-f}C zsB}aiRW22@N`->ryRxHZyb$p%^PzY^dN%q5@G&L@Y{g}ycp9lGn)}#+SLXTyK-`cM zi3WT>_eU#;Caw`;4(8VvwDpSf;jm^I5TD5}%rAfUzRj4* zTA*f9BnQA!ZtiQOM=w98xl4g+6nEnD?k{Xrnw$PSk50C*o*;PWdbyt}uy^Un3A-Dl z9d>60u%hB^3f#U&uT{YLn?J<`8Q>SdMkBZg zK5LEo=#mm4fCp3^fg9}F5!a^iXaZ!@X9|!^^Tqp$4DTk5AHB7y=y52fHiWX)VEg>s z9!jDfW-0s4jn5zy5%bkzDJZZOa&MY2U%cI#9VPp23(VF|H2c&!mxzNLmw23G00g#A zhjbdQbdsJ&8>JO!tk99gt6j;uKVy|AjciU_BTQ0sX^&Z3e?7PUyL&S@J**3xau=rwGfc>%jT2}~ zjj*lSs6IGHrb@Hm_}~DNt`{422=C?)j+KotqM~X8|6`iEfQ>`SPQl|^q?hw3il#um z>L#`!FZOb+g|-%i_|c>Pgd_RlCjc{z4+%m|O@Ig-Ls}?jPQa3%ERE*^f2Uykami8UJOls*ozCFdVEl|`lFXAmMu$9& zY1AJ)*!Nl-&bs+{iw~65gaQ~sVEirb8$AtRoa&JD#DLmmm<~wcxDsJlZ@HG_b>itV z#&X1MQ)OPOD6ug${D23e}0quxh6l#0vK11&TR` zB4{8O=4-m!5RyatO2pb9$&u17AHKkbf;d4plY~;i$OJU8wB=sRcdxP4SUPlhEAmf{ zSesZc0BlBl!TjC5ZB@rrFWD8cvbVH=dx=LkA@bV-76jj1?v^CC?KhH4v1mUmBR^J! zUjuXIn|`5+PIMy1@EIB!B^LAYremf}AbB&f(sM&X;4ltC&Inn^>OP+h@|TICD7VX6 ztAy3r7YRWcO+)vI?{;Iql!DY2r;y<+Rr_ZCq(06=E@_id8bdL1bWK?ZJhuX@>N3Q& z3QAz<(Dz_sze`NW@VF>p%zk+a69wNvP$UeiqNt8w55G5^g?>UL3b~~8tV}DXC(;x0 z9_7sxS2}E2lWokf1kTYrUsGD0m(fXi2w5v-B!6RgTHB$tHm?3lxS9e71~bl~#XyMq z8$MmRYBQ#E^#TbkbVw@+wb-v~NGnFLFzj~7ob2wC^UUTQ(hF@3gWPAGld^kfJ7id0 z*}jLx^fIq5^yXn|i<29or&u3Z=;Yc4^gF}TZy0fI8J(3Ula+jgqwJ{XYfJ_|flE=j z{v%axT6&GrLlVd7yGcXUew+1?aZ|YogDCnWj`Ain+M>9u0vah1kyZFkyYaJ4Uomes zZsG34u#85-z!H4yyc##+Bg{B8PdN<`KdKItyeHSaY+!dYhD}{{PeACnQ0@Rj>HRxI z4BU;}leVMyw00&dIIuU{$C1uy<=qW(flM>JSbrp@enwWvX z0M#D>I^#I8FL}N1Em#p(OPlFX6nQs7{}&&9xzf;Kn2Bik9p{OXui^&-ci}D%{R*P9 zA$oz9GsQVrceE)O=ksjpOwY!RZtyUBrah}ao8LU5m#lhtR**WqbXZOhcUiW^CFmI7 zA>`YS{I`0UpUH+Ltaxoi4J+DAdMzyq(CROmLG0}n&pv=in~XG2E*HE6ag9hf6NwQ5 zkM_XhxRp$Ntx4^OOkB1*aq5K-+K#GeJ&_7mPf|Bg&^c+1Pd(rnr3kvq@s~TlvL!)^ zXq+*cQn8RN*ufqZLwZEp>UY%qUnjoRGrG6`hp zTPFfW(ePcg1vv{?tUukQd5SqeVWjfEkWCiRX^=>5Lufz!JsK=gyDK$XgIVUAhH=Fz zO3cUAIkK$y9m1Q>VsJekc+Ozmm>ms~6&o^9YX6z0ykyKL!1C8wc6o)(CxEr0i8i-X z%TdxU_9u#*jy}XpL({b3k@WWUF`)Ebch27bJB8%+CZZIIT7!;z_}vw8zXjf~)*vCN zFrKolW75-%t4z6dYR`%1^|1xryqt0TxzUNz2|nN8xMiZxg}Pcw3p*?NQkm~!xU@>n z(E9u<@LwlEz5RumglfX!D)1S7L}(!=m7?IgYCyu5+im0V&{|R%@K%q#;Wt6H!iAq1 zsz6xxto^zpbaD*j4vQw9mceiL3n1taARTf7DF1r+WC?28u3dKr9R!pikBx_!9c6Af z;!kCsnea>YHvNb9Yy|NCD&J^J(iURCHuQiL)u|y|;=j`M`Bq}Sr(w!(aTW|k8)@|L z@2?v?aRp#y9y+qUCT%92S1rQ1W#yzqxPP&6Y$#s&{1cZy8Ui&M=MIdXYp1}%PkqLm zW7%ui-XZ;L(}Wf%@V5R6zi+O}RaWpBPy7{&f}O+@f2`zVeryis^uU%pg!J1+L!T1? zjNZ5`AUUgqWyyf&c^C;s-E>*GFy&v^qH`KUC|LD_`C;{_A_WGoe)SGpz4V&xg~^fj zW!eVB6}ETu{%1jrGz&P#!ZowuH!-zfNrt#xXYTPhoFknS*XEA3put1s+A}kCFUm%@ zgc5<=(a1@2^9rP=d0VIzKlEk}=0CAh=>;BZO%DN8+43~2k*GAzB#Q%}4W3)o>U((Q z-F1$@1|4n9Pvy&cNBnZ-A`+P)h$Q*uvwkg)a~fcEl9-^FH5}&eR||^&-#9~JFI{bf zf;}C*h7t3e92VR00-NtQ78pr>K4*=rEL;RvyDc=>P(#AZ0KfxU@l2(;j^R%$N>9gW zIGy!GV~Pd`)JmQ)c?VjJ$cOo4-h7xA+RJBFnI-DsM1oDaDaF`Chq8f)sNyG_ohXwld5f_aki6kUVkm{3U8aKAQ%uda4h>HA-5}v2pVn$ie^&l8TcGV z~#!)CAgmkdz|3;4_(hE}rwe4uIHPRbU|8O^=d|*8#E~Vx&Pr$n!^X+tBv5n;NJEG z8_0FP@%wYxbl90o@xEIFd|=UWsGo^pw%Wxu;01!LB)-}0ZVc&{f5T7Q{K%CqDqS8$ ze!YU_TH^=?2w3*H_6%0TUqxqu`T|3_v<+`}j37DlaM)#)0L4*Nv}032r(5)YSLr)i zCRAWjVGB-R45}^QJJG3B@53}#LWFmxha+80^R0&2wFzKQCk%z5?`$Mz3p<;H6$>V% z*@Kjdo&$?-qD-Ni6I!C>*>c0T3u~!YqDTgGZI32=#v3>xqO>Ai6@=b}I``K(9KC3e zx6eC&KQ8>A#!n9>GJQ%k!Ol0aSV{XX$kwR8tYs&u6l@C^v-^wnzMD(6s3(uLUA+^i(6J>~iAn? z2NPtT8sjYvdAKwS@Q|mEimV~)P`6+iakzcVNMw05htAr&){plds4iXQhRRVf#p&OY z>a+$_CL=LheuktTJ>IvumZ2Ttsg}t%^j5{tt;GK-MJFm&Qr|ALt zcE{Sp;$oI2MURzI&ezRh?7G`&TmZJ&;q9GeU;LN1FmyATDa_Z-FQn%}wL~DLlna`@ z#xE&R?91{@VLg2FJD6gnTJHN>>%;&ln$u8KXrSs_y>;PMJwXMA-aP8Y$pM0zgG?IV zwU7XZeQn?d08axz>JkGK;)Y`r;(He>BHr#ig8FH59$jw@Yv#7}C zQaUJrOO3KOFV6}|l@Y`kJ6v_8CCOhKA#z2e8T6wu2{a$hljzmLOKz!rl{N!j5Z$@q z7>yOLWaYu5p9f+RO*M!R6$-AqZJP5aS{&hTZWO4x!-{0bF9c8M<^&2Zi3KKCDuhkF zeE!QKFrZm^hh7nLcIW(!qX!miHQ$@wDInoBA7SVjVKfnrg@8^i2?X|PdZ2rh%a6G^w6yOaY;r&q`FFU zHt^4e6fI%Enf#AVSqBbu^xLZsx}|pPVhJnv0#KMFFLbU9Z2Ir`)I{?G9zrKW7gnxd z<6~n3G2?yHuH4`l=job65t`7xX_yYZuLPm|7hOGJ%p%eO&s1i!b^h*hC*Gh_V9-CY zzjhK$5+K&bKszJ315I=KYD`^ZOy4cIq#cX)tEJ+0HtPKpm5N<(Z zvE=+c35y&l5pE2ex3YzQxnPytyCliORlp*lB7w>oj+|bXgJ}Nxj+T1chmBScMeB77 z61v-T;Knw~8a+*%C71c1j-h1v|Ig0u4ez?&`z6yGa8$WuRP`a&j@l)+ggjw=DhByYOT(*xD=7 zUQ$P{d~!@w+}8yAU;gSbe%cS;3vV#iwt?+a#__2oT zDJW3h>R$ZSONL-#O{+oW5#N7`n=B6STF~TD%Xj<_empqATOvNCzT1cRT1iwFhHRX? z8ZiQ0fXY(%iLkH8-n~K^!nog9>i zjl%!<3b@yLzB1QkPK`A9y+vVx0u)7}-BK^oO_907~RpZ_7NJLh#SY#aT#Z;g-J&k|w|DJ}UEWxy5#+N|Z zkfVQOHj*}Xe0|>g@q-^^$z8%j@?`ALUg>M#5ko5=o4)%^E-y>7(x4Qq`nsbJC z%2_?a{x}W47TB%F{A`J*$_3tVxlt&WJI6HBX8wIuZ*gKdX&w*GmijD1*OR7}Ur{G% z%G9`fMaofW<==XhH?U3O;j4D#|0CWTpF=}_e5KtI^_TVv@C=~AJ4fYM@k5=QNoIvJ zX(d-(=k_-En888-m49F;ASfqQ`ER(D)t|PNtbN#!Q;nM%ZyGbYb$oo)i`l#pmf!iK zFh4?+QKm<|wSs5pu4TV#zpMCcjw(BU@uC=I<`fEUvE#h20m7Zhdh6DEg|VJb93kCl zOHOc?v1@{`t7AfpHEWG`{B{~R!X5F#lT*(6ni*MNl@2C%3V_?-u9e*lF6ME3y^Y)a zF1O2YWt5EYC+(N(LKEZo6mx_4V{LNP*8W!A#4qYV;LK-vb{)id6v8QenSX{k-Yfw# z?nMqS;})Ez%i428bF6vepTlAc1+LYsQ2>}qmWNIKeluQ#=zN(5upa(W=5VzRm$b~ve8>uY_f7Jdo{HGv4rOx*GcbKTLc2F57Xb_i4oCNpSDU!|0RW(p z^da*?ET^>MU*A_5;bz(|X#iLIZIs4Ml2MU$BK1EQ5R2>+4mY&eRX@HAOkr-3JTUi$ z8kqtl7VfAg)v{(v&s01{5FI5%6=kib3qZl915n{4d{$FSjEB}zo2{C!($1;a&uTC+ zrAtRF!Qihv7rSc(8i5Tm2m8Gm&_MPU`B8y zT;lj@_g?9S=BSeu{?<2${+>8%y3uX#VnG4lqe%pP2+Ubxq{PTOu2uGd9n%-YfjDPI z4y|86eCDqY}g)?t)JCYsc$$U;E?Z86GTBLB^z* zfT~8(F>+YnVN8@GTp||pX;bJo{&E#>ftf--QUB;nv;qgmvL`M)4}x(DZD&%(7F;8l zS2SMo0`F$X&ZwOSPT&!zvfO<=eS>`g8v)F)f zPVH?MO(*EuT>xWu4`K+g%F0RXW4W_=`5>}wXY1vdpU%z z$k-i$?a`NCpYggwKU~AwYwE1H8z&@%(7jB7oSY`WP5413&9gfujyn zhj6n=D_t{XR|NC%UF%l;+UEYaXLjV-bmJ7RaT{wFQx-6Dwes%9`ckSmv!Ac+g3hP0 z!Ke59J~My*?I|u1|BYdns){5=?3T{aC4_O%?j_56-lP55%+oJUlTtMwPQsv{~O=#+^;Zj4H*ASHwmye zprg#6dy>&AIn!J$-pV&*r=O7oY;(E3nO1c~)M`32lkSQuN*6Wm#)SR93D7p<{J0mW zhMDI5+xU1Ij3(nSJ#*u&Ue$U<2$%U!q=50>t3;jcygR7lmUD1o!xt;BRi*)K{k>}B zI8nQ*gm!DIj2nDctdr%IS4V=@W+>0mr%Y*?1VIl*I?zGvH9DLRV}aVn2IjH1a59VU zSCqAUFa@{5@fc@h?o0SsbKDvA&z&ZA@m@6;%bP-CiMrQJfbR?l1VITn?VIB(tr9^j zDr`s#!Pf5O<_&|j9p0es+Cr^Jw?V&nft3AP6(iey)&r6XP0p*UU$=HwEAF6ZgFDC_ zEzMD?ZS#r(sb6YwGn0n_uCA3nB`I6EwUhZVP3C+l{qYn+xzP0Mf8SbdJs9|`8_k>Wtx`8?}TOF;%|14Ps&MPaqGHvf5- zL&Oz38E2UZq8x}+*uYi~Hs_fYf-CUogu7XXMqPrxS`SF#jGae&{M|qlhZYYl@Fqof z0SAh7oM9N{tf`&`brexcjwtA4Q=W%fKWlZf20+Y*$Mv;o_pZppWp ztEZ+gvR`uTBwa;kEYHPq1e%b2y)U`j|Fyx`w#jn1?EVM4t-!TO^1YRhU|p1g&yFh9 z?~_7Ef2WKPBe~SdWZpXKP#daDtH@eU>zFF5Uwkb3tUo$}(b&FSABRYMJ&IwS1gcWX zvLPHOc$&A_*QBe)w{3<*whw7_Wkjz`Mn^QOpcNpYa49~aLoQ<}G(Q-pWI4hffXo6p z0zwDSPhV`XXBx(M^EO&K$pL7a)6KVhVN5Cuc3lQR@GpC>#VA`X*4Ov7s2Lok?>=Q_ zYge?df1Ca2TvGt4Dcea zBJ^tbcOh(-TTkim=_Ujb$(c*|?sf_URNI5!DDLXLM5FMA+*n+UD7ml?V@li77-{a#{EI{xz17gC`&;7HOgyw*t&AF^ zU$I7%hhjJ+?+v@|L++ks?jym^5yCja5gHL2SlH*8aEQ-{TLXkpJq;soA^#5%q2HC6 zkmjrAXaqZyt8N3KHUNE~#~_&fq&y4GLGaT6)XjyWbX~fc*#r(P=I)n@_NFbBjS}zXB~hW7bcB^58Wgc!M{oYn+14o* z-N`VDP$;X@fZfff?GwzKi@C%%YdJ4dq-BRHoURq3h#+wKN>Iv=IT(?TRXksl^e1$T zWMxQD#7!{OUZUt@w~|JGZH34I^^B_XIfca`bYM)9+jBo zV+NH&+fM?+z3%Ve;^W1`N`)j*_>ImmqZu8NNAf4wp_NdCX}eZG{;vTVe zAWmI#lKE}NxVBr*nDq3uVO|J3bKzj_^6_b7HtJ-^Sdz%&Hq#LjF=TsQ8af6Q%Nzl!r-`4Ea$WAlY0U zXwRxV@y+?*mvnK&Z7!MMLG64}&ZmDxAXqYj-y!a!3&x(>SKrsuKOK}&+2<^}sGOr! zUnsDVqCdx2b#{^1N)`VN8)^XQjzw=0&UBwB^?(wJAOT_F%TV1YDfL+x#F4_*$cuXQY4V?>zRg?0Xds!4``uxZ-s#{SDSq2;B2T(F558kl1qTx?|#%d zLACIUBFz8=kjLF)+*vk_3sX9`zsk+E&5_MHgB9Q0NPQj9fR&;#A5z z5k)bq30W~{T*_)lKhonsWZ@Vj-gMaj9P@2?z+t>YsY}0B(AdUWIQ1*irm#cCe_c?~ zQ-kXdx6tljM5DTs9RiVV#88S1%OSNz+4B(Qw}#GQ1xs|j|20}qsY|^f{RHYB8RN+U zg98MtlgSOW0f5u?CM4UXsm=-n?au_i>V1W}c~<^}c@cQrRj|en7YX5He8S^XS(5{9H|iiyP4z9c##;1uz#cWAsCOqpV~~w~e*UcqBbvB}aSE zC}rQ!Yw$E(8)5D5RUTHAYAuRTNy6%)-wg0 z5qTOw-ei0vaD673j)C?fXcZguFVC!^dRkBFd+iPYs8%nr(Su3@PNOkKO6%-xY<&GY zoyP}bpHex82A`4{6Wwx6-8-+p#OdHEB7Uvi>jVSut@D9bXq6WmzOI?XxI!n>6k|3z zLQP&gU(-z;H9>1T2puWf@sJfBZFG3s7oq#L+KPb3j+~jzRG*YDFIQeg(oO)4iOR`e z;9hJ9?aVR9QtpArn~J$2mS}b8COMT7*)@he17Wmd=wASa5GNyRU?~o0YCZ-tNoj)o zu{AE0f=}*M{a9bojWC?XpC%pN>95QR1UuF+HuF(h{+{nmj?$AQJ!?{6BFQdo91g*n;IPhEn}~K4+RHoJD&stApvIc>w0F6kQwFN5(kST{`T^6M8RfT zA^$JVZV|%{w|cnttr$A{?E4mi5|8S)=L8}n6tSBqcal8H7#%Wl(u_lB#-t(ozn5Oi zKt~Y9ZVap)k6l-%!_B!7Px}f0JwU?08=GGOOgv1yLujv!_e5O+zgekf@JFn0|X=1%m@8g+#XfS)(pqYm0$I)tOBW zheJ69+30Rk7BL8a)~4GG?`{e``5>@2@~7>o6lYj^px9SEz$xgC(r z6p+ynt`n?@C+a~_^Np+G?{P+48&gD+-3dnZpOw9cb?v%}K~Z7Huit7x4CGj3t^cG1 z!sAPG*Ne{2I=d~0rxNo4d_L_>0xys%r+AA%GDo08ws6urOYorbm*Q9!jp+HO)$n8e zxytZm2*&GOVocT^ue1FMINhh&e&!nC2js_(l8XdQ_ zbaxpA9>1nDyuHbu&_=B6+Z76S1AFn2WGHg?2kyHP@ynUn+KI%F7vz!^kK5Ge+b&e2 zVq?)bvdmz9X@O+Jg5zU|yN-O`K-5<}3Y**Csp(|F>~Ci4l^2RbxEcfS;bN$UJq?D$ zC(Z;D`~eC?O9D^_Os8${@f~HoVnC+U2I|&5I&}+1iZaeY!RVdy1P812)Y_ZTbOyf; z&};UZWG=?lrK+_}7L*oCpFYU)-ot@0Td78w;iWxXh7ET-wA{UwM*^PhVY^E3Kb23R6d3w0A1(pTWlS+?ZL6{p z8#4aq=2wR=TW<6_2Yz$ycc5MF-h4>(2sZE{#8WjMlC;Xv`1pWHW@?8p3p9tSU6(^QNCpE4)aRraB-JIMXn1sd*kwYp8& zza!x5rJzh`@)~ue!kk@%5^R^=3h7l8#Id4u`B$kdlS#6hxDqSh{7J&Q%*T+X@{Aqq zx_v(bzTE8w)FEcId8+68nS`)cEG8h55Wmfs?^q_=VTZNNEo#C;&Md6CQq$v&40oPT zw(jD~$D5K=5)rHl6aZH8_G`~uy%`LAJUBlJg-ZEu;pMsJHEjfLUQ&rt=cnFwpQ?5O1ON3ZBh1O zWbKY7N6jDt#jyo7aNf7iwk_@voUUH4PR9eFEQj~xlL&v6w*!q z>=Y!+4UU3*RVIrRN5};VO?JP^YLpGEihcj{RIE4O-Cw1SgWZwUfJra(pz7YGN8B{O z9nv8HGF%)ikzIy-v0QLXTR7@<1@{K5&#esV^BABAM4YxZsugRm?S(@o+rP7$$ba5i z<*9&7mJwW65qbG=;+;*=M zyrUqAw5w$+eA0-%j;W_CvsN<_FpaVtx6RQCGKGYt{bYk`_4%WS^B~F58n+=Vm*(f| zal|eoC4}=b;N~^qAO)yaBX0E$<8+APr1y8Po&lwNKL$$F45MvY#oHG3LpJRfO=&L(SxKiA8C0Pl~|by|s5;tbB_qe=uo-N=x~6c$C$gcq zh^ zM1BAUqj#*kPmvM^n+{@;Zjw%B**vL*AEspXMQ5KW|MQ;|PSyZOX}J($U@Ub>Lf9Qk zCzxY>Yd*JF=xyew=(L_##I$?Dbcw`>Va2ryMnoIBALx#yh0DWeqwR-0;0tYWMJPUr zY1ATc*czrL!rSYv1K(V@G155RYBHE-R&wrh@B4t-nU3YufKgC(`$5Qnum)Z+vZ2R+ z#cadvsQ@mwE$^(zrdw~V)VRqy_TE7bxLR=Gs@4wD1cfdSsD^r0$X92pZ@_{Ub3X^X zxm{Bt9}YfIlQA7=MGsmip%94yV&cOkGYO&w>iRfTbbla@ehMFwI{a4vExpqxA5o~CH_Z9PLNDb>Eso7m?~#t}K9n<>)NcO-nV`+0TP+teT0LSJ2df;HHN zOD{8?2P8TywvK?1F(j&2Wo@A>OoKPF)C%GT2@OXE^hnR|dM#bzw1Kz5Y}|;NH54Kd z^}n6mxdV{Gd7JUOyGJW%R59u$U{3~EG}F^Ftx{H`L-H7JY6?)_xY3(N=qY&^+fqF%3>1bpXGY1e4;Xk5QoCkE77E*| zgi~(3vcyv*BL{bV51X(5TikzOiNwvq^UrunwtE}x350~%dpsaieW#;aof&`S^aS$e z1*JKXiwm0adz^UH|2mg^Gz>r`4@6@7OfLR*I9kNy2fB+3E*MFvlJxkl0)SLJ!#^{B z#g#Uf+h-?J1;T!sqnDMUS%ekuxqyIYl`{+dBIA#}pV(2*{GT4guyJbmNQ9*I;<9-s zB@sG){$J5&a*IK|8h3AtsiWH#7KnHJqYg{$Nz56mEd9R-pv*gi zyfrodQEF3^fA2w%;CHqEg#r6#mC6aKRHI}=xbW}v#zUB@B8?y$_vh2~y5+ZT7AGrS z)A@3*S5|&hf9fsJ-bvL$K7ZXhuA|O-!6{3lj5jT_diUf+1JblgGyc%o;@gI@!7fHj z^ucQaKED)C87*c`E~KeDR{(X}ul+eq?CS+_qG`6dtfM|P#D2G9)aozbV38nvH$}7( z#y2xXoZ0N|Rd8`Pl8vOIgm+SNW2R zT%jsSsjoJ;71_nQ#-|1R#&Uu0oY6KfNATL)^x=E+?N^if@$ zvPZM_h3wSmgwp4X#X%G1=I2{zmBF@|Vb5)}j2XDGSHebKRex1D4Ik=WTE%7un}j0; zkfg;J5N@S{LTZ#%cX2d+lMq5v&yb9_^p8^fw5jnVV+_Z5GFkWs=@K+#dz#+l1;tS@ zz!uLoZ7n-B4I+vE3IYyi5#LXzw)DQ-;)DNmv?t*hrceTgUxaMFp>m8 zG$7;x7r2S;j&mk?M}0c2`$xu`ODf(&t%B^Q?$SExTyE95^GwKo;6QitK= zU5)~F)PxwtA>7PG3IffSv{2qfRZ#Rp#inrd{vSV`b3Ixl+eEESL@%um-r8RgA|v5# z{^Q7glWxe9PiV&tCqT?xPeZQmWSiAp>knl?h%-&>;2Ncl;!CrXp=p<%>v+hnG+2fn zN%PK`s)MoJhzj|4euQX!y&2tN;sS?bej$R&koOT*j#@E16`l&lBf$79=1|^*7uNf{ z?=k)DWP>MZ&;O_{B(PrwZVnsI&U?sUlB`Aim0mbb*1H7=E~4SNd1QVdOL*X@4?c;L z%BQh$1=*@OmxX%aPc#^VoWM;MxjIqwY@`GE4aR-7s_<1HEW@bbN@~Jvj%^Y*{SOK$ zJN?jR26-K9b*XfMnezwc6c;NT_>d2oaYmuc-6UtSKJNJz(mlaXq*F~XV3_sp*PLBebi`Cnq_r!U24(Cw?*__#hJ#{24P=yK1x@D#-Zr(~B<6d&Cq3D@-dyw9&W=^N^K(FcEI@*9J`J{&!PwmYU@z1! zo9Xf^gnTE=16PZ;5996mi0TR6mTrDl5HE+mtsqzfb`~13G@BCq15TUP)5tlkA=TXW zg}*!pujlC!p~?xna^txG9_>az5`1k&kf#zAW#AaSf_ap-_9^Bc?rMztHo#*`R}CRb zkX2qBbmf9J-Ba>O`)30~p}mEs{#8Ms@y>dfFP`1T>c zIEn^Lmx%n$z(v<|=x@j|_2!SK&C^b!V@&z78C8R_k7!T(JTq%%5azbl!2sgK(ORr6 zLdNYG@N4HqNh=d|#o$M!7WtTwuW>KOEmjL)>=Nmh^yHJRr(^a_H4|AL$ z2SUQtPW&c*;U%-k-JlP`Im@umlM5527s>V0)A-|UvdP5QLu0Z5+_O;1i?XP6bRn`c zl^x~l)2v_^E{utw} zIV(cuGnh1|deMURBJeK2l?@Q?gWRB)Nff<63OtrmJxFN%vhnkghx|3-T7c(iDQhh> z$vQi`e_knsy^u3Y5QIg^0I{>pqe8@}kzAa*z-8e}=$Z}axaM3i2I6{jrn8O>`w9~g z$R^koW2^tg+dI|{9MIr}>!UPVH^cs-j*J7C8B@F(r8aa{9c9F%DQi~Rth4^-Nt9<8 zlX7xdjxq%g-rNzj7}V1;`EqJ;x7n z>3&?=9C$^e?vRX0U#Ffis103)`2>`0+FlbAr;cD+?ZFhX#>Ks0(a=k^c;sUds|onO zvr!`D&flEex{WbFJV?R~X(z*6j68e68oM;(xRm>#*y~uKNgKy*kdYQdsrR~f{$c4% z^B3{c>*`W@DqJGg%{wUpaQ&9q4AC9DD6G@@cU1bF1f zDJZyjHH+!Utc}IQJ}Ryn{6;~lpPwB!NWgxH-4jUF1RHw($ErhXlOM(Rh|hp(*Ipy& z=kJI&EVL%T1~J5;4|(t-#zF%iRMLZ_em&E<+Ke)o(EfyGR#oYih=#2A%P$!szux1T?SNDq_hv!rG$B*6&|?7vtm|8D;z~ zluI?1ug8FRRH0q%&i#iAwL(IC5TdR7=%hww#^?#HYGoPrQ@VF#L63V-o)f6c{!CIS zXd2%Cy{-V7f%ka#z&Wgy!YZ;dT(LId4>%q_$(Sx+8zYi&;N$rAKPU?WdIKm5cV?)U z_=Qy()qJO>Qx+(GPm43-T(gJHC%_KUOu_`l8aM0=+X-$I-u;z2B(aN1k zAoH=BHy+$c0e~J&%(1S+xyb^PG9k;mPP%NS<(;8j%>^qMH1Pyis|wRGeBW)E7+a!c z7iu!`Sg=~J(<*SGo2sF8ds>R(rEBm30>z%H42D)&2Z9uV8)J&uPX4@q2o&30?Q?yJcntb2gY24H1_LYt z(wJh+J>b6+-_D{IlbUMJ9S8CbWWlgC`!EY;^h~Vm2@3_1MI?9MK}DGIu8KyFy?vBc zDv`T!A>XYOX`GMnXL~|pst)x@r4rrOzW;4Q>{+Y4!ReVKzyH=2?6H}&?)o&k@_V2C z`Z5!wXg7+LN*Q^e%me47k@8Q=ce(&tV1U#^j*I@Y(3dfunhH3iSHD;k#;SDTZ3h5Z z@OXe5Upr4Y0`-VH4BYfR-$pH;H)t>%9pCJs@C z6)Pl)mi{WEriwqU&S}4%iUe`+dT(gNG{eC+*rj)c0v=jpI08pl%H^bOMZ9biJKxfl zTs>w1Qy7?%oupvEpr0Gv(fd;fo zHhky^)%9Wu$60yZaRk~op+Yi;*R&9_ceP=NrR0hAsSMjMea7_ZkAj``PSGV*zFO~p zKMI}#N${B$BB#ToQOJyR?(N39B@1IclKBaz%hx{*q9kDNAmY?!oOV^1R1F>aEdUNa zj_~DBw~)ZdZ-+-k^mWo{8iCB-h3vEk+ZlKS5E0eeK`at{xJlI0uR^y_r)7Q1(;g&6ArsPOqX27 z;~gf~9_MA&hn$0b2O|66>`l6f;(Zz|D=s*o(&tHs&srE)|WT}B~h(oeK>$vV8-olqqGyT4eveN z8#uA%r)#B8C*4i`c0h z##(f9#<1olu>z6e;1W3H<@3^9i4wZ3);cYHglNvoZeLQuXZsZ(81}z-exfKQKwv?7 z^?2_A8B}G}ZG5KZ`$PYt77pX~cy7m3&Pjod49L(n&fczmfE%uW(&8)7i+{+zB&KTI zDrl~s{wMm!9yLB}fZfEOQEkoI-lU+yN<>90a!4gxMXJ9lo(rlXI+74jgdMQ-!CJE8 zfScQ{A4hgX2UM+V7Y<=Q3G53Vsvej?)4%J_5*mN@9u#UvD~ZH-&B>oNWVa~pw1S@J ze-Q5!x7WrO4>>ZQIw63NNNQ(YC&^cDY2+!g zdQ3jN28r-=JlC%H9H|2Pum~C84JeHOt!N@>Ph-8_zln}T`W;Kp5_TFi#YUV|VFQVj zK{-?&OFmU&7R`0pwzQvgqn^ZwRALf9KO4!+feq^v58uQ3MoE~a4ah`F#Aro1i;xqz zj9qqdVvI0R!wzquk=9?`^6kj+uImF0oxcR&FL%K0OOb|TdTs-IiMugC7F(rpxiORX zG8<3lm7Fpb;t;3&^S1q9Q;Al*lxH$n-V;5b6c$Wgq>QmI`~IOiIqqhJo2tG~EOC`o zz#(%T1SN}XiR)%;z0ehDq*e^g?TABVvO%}CxaG0M9sOSoAQ-U5okTH<;IoXd>74Z$ zHST!&Q(K%W2%6l5uj(fB^%8%DJo4(2!@mG20z^Mci~9BG62Ho-1H%*wY!+*M1DaSP z1E{{Tq6V~uB;|H_)EX(r4czks=uj^JT?-03#~^%>Kr1)%Jqb&pA>kVkQwmxC>uoS% z;Xt`S(OGwc|Gs@A?5VlAFs3De*=jmYzWJh$O)!1ngwE%WA|j+K-DqZx1S^~x@M9Zh z(?OSR26H)kqD7^I`1|14-SR-zAfw~pl6G;i%0{AXkR^ZMIH_{xCD+|1?*4mRY-*V~ zo{UV{-S)!X>GtWrly|vl(_u{2VRn7+U-HvlA5!|h+)bW_Kj_vC%hCW?p1|haKE^W1 z?rjzqcp+fGbf|4F2}$Zn^1!(sVtaS3;81&m?zhX{OQdL=z3+b6buj8g?V$yp`xZ266p22;V)$ z3cy?%K2YA+P}0&}j`)3rut3kQbd))Ug=80VZrc<$tmIElbhq-v^C5>YYlqL*g28nJ z{H#D+*Aslk1=a?u9%2SEcOTw|8FwSeqSQ9kup+hd9yKNa|BfB4x=; z*0xscTUYnmGQ2jf8HL5VM%YyN=l~)*@p`VbXQl%&inAbDfvxUHJWIGZT0f!w11Sc7 z@OyYy>V-h6kzU5#To$DlDb%_W%>u0LrR7I-L;HxCj(0oFRbPZs5x7}F*Iasj;@JNv zyJ&WvsRDT6!nq1+f~a9%0)ag7YX*VsS$#i#0#Z*qh4m5D-D?##VIRH`#hNnsZ8r50 zNZGk+wo}oT?(g$=SokZ@B~*uFaW&GfXr%lklLXU^N=K{CI};t z(MXkXJ)|#Ha85(Fs2fy_pW;mG+YW;l&2*WHg6p4zfNhj2u!~*ZcSY9Y>BJRH7L9VX z-K`;<5}nJ9U$uND+uZ9=Zxw2+Nqv#gPUj4)2ry{}B!^<3p#7@$D~*!TVf1K>@a-!J z@op4kO>B;#q3MYKf<|K3`ixS+2JFeAu&O`dN`*z2uz$$IIq-m1f)Qv!8AjuRcnY;* zL^t5O!%PQIWEX}_1oWAYK%4^*;-f{Nx)VC>h^}PuOd$@ zF}auA?8HZ(1NSzWWm<&;>4|j)AF3R8pCHkj=dHc`AqhWBVhu9byjiV_% zctXfc!J-{bx5X%{n(Z+25_{#*;yVYGCceo9vfqBAkI#$mW^6YjBtp#GJ{_I@q3}@S zGwUft5^^PFQkw!{0_*}h3%3#`i@w8NMqixNr6z~};`nJ;5$JgsC=jR!hh3)`1cIlwxgZ+~dbVLM@e-1!3YRl_?%caV+vp7oC0LuAj^Nf-6oKMTA z^y?z|c2qX`rA6DniU!iYa830n)7eYa{eOYw0ez$CmZf#H%^)RHb*NDaWs`wy&cNFSrhvhhCdHhk_H!@>ul`alg;@{rkrDCR00-H_%r-J*Lv1fNo@db2C>b zmcTQc{sSEYEOT}m`6Xl3Dg-}Y%G1KioqF6j@H0Bms2n0K>Wuq>O3Ma3d#hJ$_IIf<`6OUT_L~a!}UJ!mpgd>Zrulq;Ne(>Uk`LN5I7!NJ#)V)Nw2u4zd;C`C1mh?~P5rh}cIP>$aan$lj65Dpq zW2_%7J6~(qD+CjOeTG~kRN0j)i2j07qaOSTnzDcjUoXM~1h*R_cf zlsb`NaCnu%`szuQyVF+Ppveeg_I_`@BH^V>NaWzKWiu8eOkOD!Ztf|q;?}zmRs_G9 zB=&&5Bl+fd1GE713Okj0rz$&A(aua240YAC0CUU4)S4WG$auzPl-K$B&dvFH+A zs8Bxhii^)`l=-?)%}0BQh)@@(6!f|=mh32qQAK5Mcpc`{vRTwl;y9j{658(Sd5b%+ zvPMt-5ZJKGh+uCHK61%zLfUz`&$r;A+lw%Ffpla6+Vn&$AnkGzoh7d_f|1UKpLia# zQ$>1K>{*{R4cVGaf|fR`BjZCpL#%Dru1QxI7G&dhd9wTOI(YY>JQ#>l(uRk@ zrv`fE^Y^`=o}ScJ{1}V-Rs;%Q;nadZ->A8r69Xpc)eYbEB3q_1Y95%R!U;{Wd!ztd z&?89o_&M}FpQ#&RQKJWy3pUTNv@%guN1(dVimD4Vk=C&!6h|ze8k3o;nJs-v zPX=Y;=MuZXO0%%2i|k5xk@f#^uS=lW@x=NPHC-GTEY7vYBa?7kolkj*I;Bs-UZ#%| zVB@@%B$3qqZuMWnR~E3tU^_>$s+lc=GVrD}))3HTbhP$UqCMtnJKPn0pz+%*%*%cUM~p zosaAG4P6L7Im~$C%OytjT%rkuc@PCZ{%OM{;nw{61Bc@CfDlcjxIC+|ekqY03rKIJ z?M|WosG4QV`PB-y`e8h{6Z`ILKDN(^YYy0Hhip*eCKp7x^JwE`t?E*L!EWZ(_BTS3 z_6q~h+c=zx2|ja9QFLKXl_a|fHeVrjy(=8h?B&2nUD*~_UZmNf zH(s93hkAm~J_rob|#P&y0z(F4~Nz(uRO18_|mOY)n5MrXEMT;R4v3lA$&)unUa6 zoiBLMX8fv80|W zE}Z#A+&djQhvoigzBd2%4m~M-D)eIiiejdfxlIDf14a!A5nlLrBETe$BWD%>=nhpE z#nSK-^~lxf12bA83TkRAqN{kYxQi-5cgkHW9vg4sqBSu&Ct8RL$m(3g!NsN_YO*!2 zXI=`#u~xzU!^AI}KTD780jiBHg^X3Ta*z(yx0Xk6O+KhwNjOVeSY1;(d(UgvpC`d~ zT2cFHsJNK?C~$PxYMa!Cl)^{Top*Jm8t*GU8-wz{&`R#CK~mxF9R@ZG0b}JTJG{5$ zb$G{oCR(ijd#OL1=AC}jjLiI-dE>SZ{b$ME@>eDt;d}*BAD^la^hD)P=y~~0XjHbH zEu{U7+^YRLG4SaDvoVguSwaY%)Z0P>x0^UD(6f}yI`}~=s9&i#P(pB{NY_IrO9}1A zRh>*bX7?>O$#s_{(_MqtS>WP#FKDhdX&IX%=}@{TT(6g4o;NXV?|JH3M@;Pio$OoH)4uRY zSz!LY8fN6yF~uKhYiE|9&otJOJ4zo(6#k;Kq_eb7s8P4|apxDWDoz<`nz3?5KR0E! zZS>#NrUHeGz3DiNtqUQE?7O3$FH~v z@KnjhHudnSJq{^gqz zLe7e7o3Ic3e5OD^FcWqZ-S{RUB_CZxg7CEMKou;kua9d#NelnAMSuzqmSkKciqh%llUy{|{Ao*mm( zybiQ@G^!WfycWA2x@ClTgSEM2 z+b6;ImaWQs$a;!eAZe>SYk2hA$ zXRxno6uXe)iJaJxLe3%cql*tzvx5J(&1>$YE7k%WopSw$^El%>b=6$D>>(wvy6ceP0Hq0tjri-F6l~$k)fd~78z`5QUP>Y4if!v z@%X3T0jzUgSlV@ex;W?_4DwD!K+CjRr9jU#loOXF_edrZYdqRkfp7kN+l|8wOI3c% z^%p+|m@Xw_tGy8Ubr`7=B;ERSvHohJ2g{?!D^~L1C2QwIp@joOv^epQOQzg=11E*Y zP0A&DI_Ya@Yy=J*ga<$3pr;C|g^S!B_rwLY`_X(BKkPH-(Y8qB7FZT@+Hoc6YAQy|nLpp8(a~LK3N^a$4cUxg8!DtQgBJ z*U#B!!ekIemTt9R^DpZF(roTB)oJsHE&|$SVls}q7(#{7*ShW`kTgWQHW3L;J=x%X zC9MtQC=idR1mZy13u?uuRRC4=6jy@X?e8`cf)*dbm+>B)0ztd6(LJIEVAbvoXA*QTOWT7OyImuPjKwH|JjCeFzS z+1dofaX&3^w{_Y2M-i4{|9olMmH8}o) zac-ln?S<~vgyU)+0?lGX6JTuO;q8C~(7c)3wnPpTou?$~F5b_|SsaWQ!TD0*Wg)am zf$JRA#=LTe;$EoSZ@*RyVp{bqj$Lxi$K>sZH?ldROA_73oszGBmJY6$*Q^g#%X&R7 zv2yFTFZiy&xl}C0wEpfKX%E8qF8bQkE35Ni9kp8<*@wMPbD$fPhKVsBf#{|>KSElp zy~qCs22&nW2Na4nK0ogxYh(1{e@2KWPwsSTzc#0gL3b{N{Kn!4?}b%Et{_}$8eP4D6se4tyi z_b-ATAMDN%S%(&zKSG+762N^^tAeJugxmR+9rq#tu|4DP;}s8%!c$rbUyRgWdkt6k zPy;DjMCzv1J(e_##M~(bx3%+yxCs^a=r{;ff#I!ZM#tQbq==zmCxa*`;3Wrsd!`>L zM&UKAW7(@%GL%;cl_myV;{2+N8W(W2mo>}9(M*F)ft6iwMmGtMtD5KB+v!@7jV$&p zaC^&a16&T2bsNo04{cr^FugszUdTVhE24@Wb)F#YucUdOhM2wm^t?7KBV^1!@nI^6 z6#Gag_W86Y9&~{dYx`3WU{{xrQ_2o4m;;-$6p$`#2nK>B?aR;QBw8CMy0p>$oX9zR zhSk=5CdTXCTA_?72RiDIppb!E+1u&rQcl${Qms-?m(4$Tisn7WnInB{lVm#rxx`6Df_xiAupEt2wWSEl0wc{zX)yl{h1(=x;s6z}P3jTJ!7E zYf*0moOae3{^rEu2_kbXv4 z4ISURF57PTc2BHryZ0-j=AchMz8wE6Guy8qBF>%_ORz&ud~8_?JhP#pva<@#nT7Zi>iB>7VRKT2K@9DZU z_J5II=pr1a{Rhd+$q28hOk@A*sshJM$DDxPnt{tRy{Y4F4xTgHxg}R}Fs+|PUtv#t z$Jk=34J|qInZTW4a)~)U>Z7`w1J-PMbrA(LAR_t5?rC4INa zc;x|bLD#*BBS)5sA_F0l2_b2j{9isJ?svbJzA1wJnuVJ*k1SIOTc>hoEn zL9&%o&?S^ZQ+s5+2!J(2;E5#TtZ}jj722dK$ zw9i*4ydW%@J?CG!+7hbZipzDe7(-Blmlxp%Y6H0qk;9z5g2o@h5cvZpJCfiZrn?UC z2#SLjI*#mv)!_|jmo{Jybp-S#?N!pxRVXx9-~x`1TJv8_)GYs_aIT?^9Q1M$}YD73^O8~j?JF2F9Ex_c|Px6~HzmhW}?!@oHQ4n=wS8Dc-BIiJ@z2 zzXhSc>=<35Mq%UY{X2Fhgb>Vay*O=<(Jk2vEm8)*_#||~h~LXOCp6TEPfn5w`FzhY z`qOWkh@KT*ojkfFq(f@DR-g1~s<&i>lwRk-cC#%qF>9A^ay_%=4U;27b8|~Sj5ZT_ ztL5VP{1=&OSW3@-uvYwAelCH_TT9atox$CrR9RJW?G4@*Pb5f!6r0?XPg6qjQ6f=? zta^C+B;#`5C=V2oPdxln;@eXy-#y^?dcf5m^oz~1GlG+BNL` zasgqloZ?UOc7W|3l#^~6ad(PjvQQy3$*F!CK0CoRfz}S{Aedw;DKct^j4zS1{iwVP z#IIDZdfONBKH*wddRKrWK~M6&|3rMh%D~>tr7KHYWI$hvG)*wjvr?=eTo*EjD|)}b z*q<(=L#4oT4065Kr}lZG|6V~<$c%Ij@7WvD;q zV$EdB;vYYhn*-*-q&Gb~oQNqT{0R#joA@YD`2HT?qXawwq*yr7 z3md!Op}(i3v-=)n_V>1qtV&n1&EdKVwoPJ{DW zx47r7hkVNsM2ZJeI$b}Pt=nj^sfHr z=VTmnr^=Yt0e|kX8H-bdp1o~1G^{x3ucQN&*WHP;>7jW5yJm&JD@sjB}3 z1a}+e(M!3V2OBc-hl3wM=CO?h7Xu=Uev*HjMDJR%hSp!b5~r?NGUgqwfA^WDGdj7@ z%dF{oUau<=oF(LxfsQ%gimqXWI5ItvWTTG(NRcK;RFtu%l6R5N;~1B+t6{{ZPZ$uf z@LJDB;H1=b;;CQ|kqa3rIeBU9IzT_1{gAKTWvZy;qH(e7@O~-UXb*<+?AdAX!AMU^ zvjo4lhCvI&;a2Qi0$hQM(IJntS_@W!5&W&GruVHw4LL;wb>N*>khyY|28|cs zwvG0N9HcT?xj?zu0L#t;jy?7fhEedi;eN|@J*ol}8NBuKztpk!3#+CrP}Dwjd!%im zOvdM^#T4@$*6bUnqLDQ8ri@w-;D;vtna$htMcN5DFz?JLN{F^&M^4ctHajBA_u_7s zYi9k@F!0WFHy6r|t=jza9khh5KbAJ$l{&D4&o`#|FhPsn9Xl^0#)>Y>p+B^ZkFv2p56Rg`aUN(3y@eRF{gTMMMx4c728%V| zW-6$x$-H4^!%R%f%%8|&qLy$rFZD#`*oQh$2l^IWP#9+ycvTF6iVUuosJ{k(4X^_U zTaKxhjpJ)O(7UF&^>BX5D@7qP3j;j@zC1@rj-aV00Drc=b_fza8C9GuN2<~J4OH@u zl-g!C6FFTNrXB;gR+Gn7+K7;-@Qlq+4mKH+~KxLGRl77_Z8(mTm3`N?ZJ4fF2{aH;)tAGG#M*=LN3pGLexdJAtJMI z^Asgo7LP*|sADJkj)adh=99Vak`o2IEy8DNtom91+!cTlaI?qpNfH_1p3a;(r>o0S zhY7e#F%3>SPZ-mZ8G^FnZK8dr*rSA-oX)im9m`$GW(qM5@HGz>2TGT8V@t5!Xa+p8 z>}Jdx@`Z9=eU+N|kqM7q-Vjp>AuOl`8u%_Uc`--{)`{^04w zOzu)vL(GomfKhRp&ER3td`4J0(&Trt&Q3fXmH>^MJ7k>MaQ~p@RmO|`cy(l3Mu#ok zXLC1;k-#(i%8Ue~v{p=)KL{S&X8xlOKldwQF~R^A^$$=`?5TUDG&%Xkl;zwPzOX6O zSb#8^6;eY99&M_S7NXWl-i?iOZlzU_3*NY@PLGV2S7TJ>oU*rXGDYUt6&4AaT<7^Z zbx@Sx`w+oP2MeH!LK$~BrTs{6zce?LdM%|*3lOE#O2nm=R@5jEf295|RJay*ag3pv zJNx$^-SEdO&2kxL*n&uJl?`weQZoC;b89}w|1Iz%FTSBI{(_zx5%@)nZaFi$_*2Sb zO9q2Yq24fAi|;-l56#%V26(Xbuxw)nVJFh+Ku`Aecr{8tN8GLRYkLkzVq%&me5_KyD> zH^y-B%+cxjhJE9!E|ib;yIP-?#fNVmddOeuGOn>GO5Gu zLzXmsnOPU=>t9NHors7<2^%25enzmr?%P(younolg0C0Dzp$=O!~&FlD6 z6Ee&}zU(e7MPA@RHpOp7#gt+-()G_bq{sLmn1H9DsfM2ls@@)*bs35M zt9efl=o|>fe!_<&aa;^PF5VHXAq1>usn+{*{EpXjRTa+1 z%n{(k#d#-VhW(b$M0{oZ0KVyXj0d7s6SK67~M@DxNZt4!VvAN>uQ<$t1Aw z06ZkK7M~;B&hHuB0mf2)5x~z3GkMd!l#zJZZdUAP z7Yx)zGVFoWR7-7+r~|(XcU8rr4eaa8d^g$7l7ZDabNtDPe|DX-5Ke6g!?q$yULVPCl{6} zt-Q^KvA9G6E^=FvLW;)26Ipzbm!V4$9Fsbr!BZI0NH>c-+soZ!nYeZHpXgVPFwf+; z*FGRBcdV18haI7m`Q-yw}l}i$=plocYgkO^XHp<9>?j`17{gXHO9W`;l0Ted&W=E)!gN&;I z(_L~6$s^mcR_>SBS?h_s&5L9gwoPwOYUIr&rAjjSrtwL_<2&dDG|S%~vn_M^GrTRC z^XqY&SgW4!sj??Ps|2W2Qse}6TcwD9MMG0mt;vaWK;%2R@Vkk(nBZZ@$yLN%X|c&; z*W3bI0q$O>dF95dJBD!^qhs`**y70f3;FI$$fp~|)W0&AWbz5cB86@-oMUcTvjfzG z8#j3a zJ}&z>$(YFj6Dc&nw-c#>-s5>xIJv1IMVTLGji`VjtRlcR5T!+-yO;fA5SzTX-EVn} zhiI0%DX8FmkEV8G3;|dTfB*=yL%ntcqpEjmiXdxbt3Je4WzkCM3>RL0r{ZQ$E22Q0 zoHHlqey*Os8+mWGEi7H|Y6R~#xyUsX)D=)gdCKm|Sq!*v1!~zSXQss#{I?OMD$DKbL43I28Ka@G z-@9NUJt?G`j+k=O08i|XWzrQOXLA3%3X@l}t@L>=C%IGdPr6QpU3aoYgId?!eH8DeRCtHFGmK7YF#7=HgzK|6wplRRtVFtA<>-*7So{Of1i$?8=5B>p|ul zqs(lI|V^KBEFC$ZPR+jP%7(o^nLKop7c_9WjA7E-{gApCxx(wx#uXH zQkUuuS|kqhU;(j3Pt;f0^HoULLbC5DSC6p*ci=oj5k?~EbuiQ#hbzwLp^a`AR_{n5 z4RNIx?iRK*A|3W_R4l9b4%&SMQsEU7HcTeX)Z)Z@fIEYvTV} zfm=UpY4t#_C5DwPrq^Nbslu!;SuF=x|A!;682kH|W6^b%M$BzZ(-4Zj7O?fwxMK|< zi?a9)x2#G>0@z)uKY6w9Z^wCB0oH7f;OT4y+5CJ4(|a4;*|`yH78bGI1_iHWcop$j zW;yhLekE+NY`#t2Rn4Nb_%1{ej5yW)6$^h(OlJv7oXFs``5MU5|d{G95duHomDwb%e zI_UW&{F!Q<57hH00}{1q>S!c}Rjif>;zOm^;^jC37+wMxVDA&LYPR>@l35belkv;% z!?`=gGziq4qj)XmX%)fDdKR!>vfh!3mGkliR;eOPDX1^{)1QpYS`>YOdd=58_;#+T zKoCVR;*OMWbK2w_BUCB3_lBnZI}w#Jble>qr}rjwB6N*NT{zxfA!9T!ajkKL{acwH ztwh+o!p7ccMJG;cD6{3%;FZZ%*WsbC%8|DxIYnHkVcczHX@MdH70}iAb8-u!bK#C#8*IyetlpKPkPoHKPO$X=shEWh7idd^h$55`1jf zOxe-w6;~u$-rw!el~tHMCp17ef>8!SCvwj~v3e@x9kC`jVrz|Ht%VCFDp`GoJ9zt# zX8if)P%&8&kw7MlBtxxoulv`R{INdq*bj=yBVfZ0%WWC^GVpZDy(~3f9{-gaA(wgN zmSF0= zO-4NuCCt#hy7HaffxP>e<|jOlc_6H1lAy7_ONNq4DmAJRZSMMOB-iB4_zu@;z|%!l z1G!!*GD`ukWkctU3W#LLD(!4-t%Iw|b4ci|3l42(BU9o4%FWHDo0X&02iWhZ4i#zQ zbz~)d8`j?Pm{deft%kb<*9T1BY=}jEu5&_Un>~`}xvm4F5c0CRY5F1%2FT#N>9o@F zAJOZFgm_AqG9{52M8%UsR<)zbR!3K8Ebw$!R$0S+Ei2KE-lbr-^2Om}Uww1qA?I}B za+$PFZZF?KMW^T_B2r7wn~GUg^^l(SIt`dd7xO*%ZvhurEG--qm*dNQh5gMN;nQ#g zD#+f0Mx5WOcEnbweLkTj+SjAOf6k${^~CCyU<=Kz)HTn3EQ7a=+5nniceoGs8V2Xw zY=m^?y}@7nX5F)PF8kRZ3a`0=fF}NDYQ3wZIjl7#?TXX71Aydylep}4mLQMlbVf$n z9sXPlP%^;1eJ@UshsrVNYYiv;IKu3)jtR&G!oWfSP8(jnlsXA;@V8x{8Rriz^2f|a zB|D@l^`18%M>wWPK+Mc_OK>+dfJBuJn#&f z83`RP4fU=v8{FUXZ0%06cfnh(x4q)o%Tom=gTNS|$; z9V){K(-0&?&7*4jw8p-VU;s_i^3H7-dd3AMR5f;S)9fzRy|4laM5Zs!{ZGnKT8{ms zJq#nv_jyTfw??zzb0~LlWG!*Ad|_H=OLp$gXz1nVN3>GQI3p>M_MJEQCoBPm5$JUH zVB2e4_92y729bxkP<`iW9Q$r*)cD@$vSpIkYdi(gFs^^Jsv1U#EngA7%`xYy;SB=( z?cNb%*v)+2Z(xk@vJaFACEhaW=q*D?A))<8|29afTG#6ne$?F63CrSzaRUJWQA6n_ z#-z46%neyEa7Oyj-$BrBu(GEMY8$wk~R>8HKHiXd)VQZ!J-r6{MI|o3*~eo(U{wY z_EX!%MmbJ6q!ptkUxoCzvT_dT(%I&ipJTOB85sWfSU1*q7BS?s5DU`fCYI6Y4%(v)*OLpXC+2ww&XWH z$_!=aSb#pVG35g1tr`#|SL!RT3M9>Y7^hS73l_~iQ-krhp;%=KU;h~%+ts-#`GLPQ`7ufX7MI@ z%Ch(?Z94M)D{YYM#lBdJBT?)Su|pNmV+?@Drrl1)!o3;Y3b25ga&HQfJB>3s^BS1O zZmVTob0Tp*+m&_F6#Y&#b1(A;?uJnGkufa3SI2bG?QMLmH8m^28X*7D35VZn)hAna z*U>wFa|(vM-&-Zx3Cg=76D>P`j2m3}#ji57yU)bIaE5ggWxQ%d9 zt8%q4-8O3!BY^hb)RT^MsM>gqr~A=ib@Pl~!fkMaxOTvwk(K|dLZm^gAsL<R z_@D9+Y%`>Y)R~O2_F0?i?+Vu9xlppZZ|zFh&F?HN#QuT}IrI;S`hZ?5WBR{)xO;~h z==E*&xpb57TAyX#d0pvYSAG6^D$|6=u$|QE>_>A^3?~-GZ=am!Ew{&E~#-bQ>#9d(9?y#z?7XasU)(u&#TiDSB z;s+Q!eB`%JbpXAP=NU}If0m;9M%%~sRv8%Kp$U2N&a=?BpN@3X-3L*cM=zx`$%2#L zSg4*SyLnek;qi^*eYD2I0fHQCDa4>0dFlDNsy6Z02D(A@Ij4-N-@bo;{h~skGaW^b z-N6ViLBng}T~HdjtP8YK2K&U<*(lE_$}|=5aTXsBkC3(ackeaxM1rmXRBm*JeVimW z*+Ah6K|{138>L;nP3BWtDVsaJrf_&F!|fyRHE@T=*@~S zegESKempbsm=q5W5UTtm}RAo1Y)o9s~;JR@V+@2ZnbWNUJlF6+V%Dh!n8d*tX2J8=^^; zgvMhEaXJd}Ly+(AlOD-Aa$ng~PG35CFn|u^zt+`dJNta_btlBgSza7auRiMtJYech zk;N(IDY^R0oMN=EK4f{UbOQfmObDHG@L7yuFkfY?oQ+fYjF@vf3PRZ*(BvDSVH4^R z@&iC5AndLe)?9nn0d)%?l^&@pi6 ze%OTwJ`^YBq;SS`zhSc2j(Z389)@?3HuZ|ny%bGq8O6s4oJ^r5p76w3X$#P(u;%sZ zSx+hSW{y)?_+$cV3@tvf{W~1>sOLYg^=+Xwd7VZGd6aCrG6A{kcP6BnDL(Oibe41) zPd#z`7*8&ntNIm}4=-lUEn(sevM>1=?~U^Lo(3 zBfLzvqM2J_{id{r-B{^%$o8YMXKR?MX{5x1cte#fvH)G#)*&EulB(7#pk;-;$E!)! z$;|5u$mAY!ptr*o`%y~EjfcIK=Ddr7CYs#7xV%T#oz8_iAGa2Br{zi%^nSQ#vwIXT za$s3=!jaIRy9FCb?0&J@^SwLx(SSVw_0wC#ZC zf*_r4brhCRzfqc3+12|a6aVYCL<$PU8{g>UigxB^GI0<`8Dh)Q%kNKi4!u10Mi+y6 z=w)P$f2EP0-R-U(qFSQkxCI?wE%etk%E5Lo+Kl)ue1N^=8R@rEi{JOzu@uAbKg0JWht4P52hd2& zh~8MCAfR-zCJ}6b)Z>!rQR-Q--oaA7cD2mJ-3f~vkcpt*T;N$~>Ef=zGuQzYk=aEr z-{ap|x8Z7!+&?6@s;He@uz-CfGT(Q~^WttE%E2N!`|as{SfcM!hGx%dP{CuMMoP*V z^hTpg=4C7VE>*tPdGoBLd&uA%ze)z*Q1Mp9(&PBNi{lYn7Bj=G6v+p(Hi&bVz&e3@ z=Ro|ya4WZu5+#>wac}sbqVTPT%RtvnF95RgT37XR)HGX3I*Bg_Ufw2MrA0`k;QW9Hib$1_0R@WBJ82%m9rQdm8Jc$C!{&bsnc&&>Ye8Q7Dc9-FL=Pw-kP7wHhO$89uudR*J07ko`RKxv=t< zRvj2M&+JKXpF>2lwwN!Cbqe2yIIhy(*zcIH%&#!cIESy~d4N3^Z-pmpgM=;zN>zci zs~r2psh#ABdto%sXlfB3Vox$;Ha-~|+eMf7%Z`aP*md`WqY1?{*p55MT(s$+WLj``*sTHF1w*&cH6{=`;ho#4Q&Bai z3&D845SII!j7sn!jRcS>AkZy>S5+SgG3@7Sn-%NnxbD#!yLSUneR9KdOxm+~QpZ2g zJnmCgw&wH(WT@QLC=hw?6YVUyw(D|6!6*!zD4rXlQ8558sJw|7Tpl%SY|8BkLtgIb zAGV6$mCC5~7UtN~bmv2qC6dl7yNKfz;j})?+gRc4jrwdl2mEMXPpu7N!Y<`E*MS~L zU-+6*3x~s)*pWGpXN2t|_uALEDb1HTH8vySt%7y>j-pQ$qEIUK7TBGrpiZau6U}I8 zyl5r>mEcOlfhHj+BtWVYK_KZkgfAS!G60?(kqViTk#3I~7Moxpq;U4P9fX-uh%67c zjmQPlK*{dQ1o4HdG+QW#;sd`Td`U*ug;cs7a)*&fy;b;XM{kJ&o;2DI`1g0WXHay$ zEHV*bG8!CPbzx4ZJ%(peaut5_!`bPU$=~>E4*qx8s|HMKNuRA7-6bNx z-tElh`ldox|H@sIgDuJM2Q{tDoV}BXA*TynDb;Zb_^O{a9RY;)dXa98jfevN2u;jW zHL|Gyqg<9G#-n^kXa_AK!n&&H1LJMq1a4Jw0E^WYdk%Eiq89! z&4RDcW0tskoap@P-git~uxLiixFy;k`p+2)JK)6C3(Wn9==ra=YDac8gEHE9ml(_S z^a8~@J~9X0We4SIx-#S5V%E|Az+u@ZrYHC&tc299NGhj4bC5y^0uqZkP8?WkMI<2) zb4rMdS3mmIP%5ydKr(|&H6O5e8Hs43XhtLiC)`Gb0o{`{Gup*qT~yGhN6-P=lPz#f zpfbz_Q#WA+6#lOub}}mLEp8_^Hv0Oa13^r!hE0&BFz&oTiTJ>{Z>ZoHR)pm_w27-u z`;Ku>z(Cp9G;5u^5Hn#3VU7ihnl&HSEdJoReBb$IK8|*apkRK5|5XSRd4^ zURL2)PRN}O0o2Ja--6v~Y?bGP44ZArOkrds2@1l(RjA~-SB+~ffVbUM#ZCKbqAh-G z1~Zns-qKGfQp~y6^vey@kFxuKuSQojC(wNPD+j?hP~gy%_{AOqpyMaOY|ndewy9CD zTQe&5TQd>^W~(!}1YjFHX>G=^PG|b7Ux0f{2GcdMV)bfK>WssGm^IyYEizS%&W=nc zwW9gh1*6eD0oK16vwqN1i{>;Mil+~7tpxVu^c=lg!Kgy%Xrkj(hcRxf>GpE1H zZmD;4^*f*TP^#D_-vMo{BUmRnr@@W6I<32B6pw~y#W><#bLTi^xc-9eSYf)~bfu&V>8$f16H6AGKV_GsJyJP>(Q4~7>YKUEcF_XZ7TH>>e& zMoVNdCCn&qd_l^d02F(~qcx;;p>*kx zea6hll!_QY@5wP17#sf^?&EC#Z)uEv+?P1%!fs&grtR&w9LH*CV64ma7gPFG>HvU^+KwNo!&D01{8BCQ@=b?W);$b;{HBRVd$V zpgrQkg$?JHAYHD8*9&H!27JFX_n3lfZ`6=>sVDRRxcboT+#!zO8P1h}{z$1%Ok26E z^&Q4a;3@{f>Q5q);g0BZRGQx(N|FZAfi_y2qvBi=Lx!F5tdyJPlI=5ftBYS9uhU>~ zBPz^cZimzYr>QHi{1W>_DZnZ_2VYBbOdLn%s;bpunF@N_j3&@>rDv9 zJ6yV8I8#v>;p3)yaz_Ii3xHm0O-PIR?%wSNbgq_!s**ads<)E3{?~{x!!Q`2$f?!9&Mu(2qwzq*&JFYo|LdvP>|e7vih*i9PR9o>5M43S z=F&?6R7~;^kyiV-^K0iz>ETSqK2m0Zs>nG!v}4U`zUfDl5ixY-HB=N6l45^j92DeK66-E|z>UPdeKCnR^ap$y9 z*6+jr!UlG?Px^$SZ4AA0c?%Llr{rfG+dxHhSOy!(_7}W1olx|_ELsQup$uC8G&wzP z>k{#uY42}zGYD*iu5?t=j=QepvOLonMF#*r{dI_*@6o}0&4rX2!r zoa=iN?PMi>VC3u!kQL}viY9WU)$;4R$%|a(1I-9|T6|K+(%i0hk3etjhkN>Fpm;gN z1nqEYHcbvc$pPQ?0hQd>uQH);0{+>Np3c9}M`^LCx(O9~vIV<%{(7Tx_b0DNj@}vd zV9JtafkN3e4qwr=Y0LxrO7zy=)FP8;nWx{Ar(QU9dh}8?q_>RA$+zbRel}OyK854k zZD?wJp)sG8}l4g81^>s`TSw&{tWS8;7kgQHxQ3BhE< z`}FJF8{H>jVQJRlf?@$vf)Ul(SAX8vFk}PKZ%i%*ch`$JQ7PI^Dk}g)CkukcdCDbT z8j>t)rWT`L0%#6+>swgJI3h|^dMS}NVvsckKzrthqg;Sw)ShRn2KZgE=UjHZIl^Cv z&hgSP(j*&onyflU(Cf};8N9!8z)+a}fMpj*viX7h;>EMk46|hgO6^_1qI-y-SH+G^ zAQ-t`p#G@BXfA`AAOhfg!ik zcD|a`B2rxf59otjhQDg)>aSd1)vg=W(N&lVGyJ7zq`oPynuykjatW1}z~O!SXFWLA zyyf~0=knJ$(y7TXSs6vWe*etOORO`vq-H0!xS^=#tQxv& zECYsmtBai~)9|ZZMDc`F*;n(~f1v7Si&(K`xJn-6)F4R4FfuLe%<|m8m3PXPRn6#z zj?&$VmB|pYC(W&zPBiuGtm17CpAikwN*T{S`nQ7O6HGR2$HD`#<$bv&y!s)5yZMv# zAyN=nhcXfwpD#boUF3&2nNri#Eku5(Y5pzY`+7IQ994Ah^vPIbf?hpG*8ckGZ&)pG zq+u9k;;;2z51S10==r+R{e5JlFo7%B_IQX(vRt7(Qr*iuHd%1dfPt<<+N_uO#h5|B z0?;;yS95}l5q#0dTH=dv*$BU$CVsQqKQAeo&>GTgL@cF zd!m%gKXWX(a_U7V5wRDHsW$gB*8U!G(c(Me@__=SEq5m%_JD}ib2=>e|LMajTk`Fz z3qC9TmOrx@@}SWUen_X=+n{Z0&MKsE6LG@jPwW0>c<`G) zp93?30=^~i3BB}9c3E*!aNomCF03HnmxxN#p4%+jHD6bFm+`qEy|OKrp9AEek2{P| zaw@<^B-fvW`_TO#m)gG0ANPT+7G#~6sQ{JqB#TCSnzaPa!KCF^_6j7ub85EE ze6GYk3$|d1z`i?d=@c=~T9rlBiIOUp@6U}(9Sal3QUF@_;>ct8(4f-lUd8suz~h}Lps$nRDWMtpI2gMEV5p^T;zP|6RX zP2eEH!8Ie9w2f(hd!KhKg(wdkDDI5fx7alfzO!pMDBmp)z2QT~_YGfi8CKpBQ&Oon zPTE-(@h?TTlE}%_FVasSf&CnkMt(h=!PE-PSyC0=U!N$QUNWy-5~E;aSk(?cnskh~gDaHV))V)| zlu~7MF+K#1nyebzuUN?u;88@gJWbD&%N~|>ZN+pmeIxBfxbgK8dk*7D(-4vsf-D|p zWbJ;vvwoNJGixDUONEVOz$W+JuG2vK`d&{CI4807`IlC|Hk zc94Wm3*m$!1G_jf_iJRZv;%NVh#k~wJ%Vso6ss%te%Y*xl*HSV@gzDSI<8#ns^=u& zZXoBNk*li)s8GnKndlS+G-CFDU_Iw}jT@nh1x}%LS*P)bY#&k-=@niSm@~EDVfp?K zi<+TuiVEB=L2A6#=Z*_}Dy$V6;uC4zypI|Hg-P7e&5cf=n+x11u>vXrV)o-06?JeZ z=M1HWiDaTk(_|*`SwINFcU?++8e9e%7G#b@BroD$Y3T&S9b$^vgm}!rs7dG-@N_rO z=4uC7lEuji8HM*5p4fNa*215(%!yP?dlKdEp~5u^F{*3^OXce^_h31qWd->R#7EgE zb_us^rGL^igy>4rm=#qqB}53E%HoBo$P?l*_Ln~lGJk$<4A!8vtG}|eNEqt8>_02M4JBlS zXTzs4r%3*5k^3&$S6P8Y3Xrmeq~lDUc72m56Uu1Hd>s=&ov5r~GPX8mA18hzK3R{w z7B96Rd;}-9YBa3(CU<|pM=FSb?Se(uHLH*)C_%Jf6_O}C^!m5R05>!CH6R*R9s6pf z^GP&sQO8ChVCV+36a4u|HHvF3SQNEONX^D>JdK_WkZn#|lqE>4EzZJPPAiFH5GazldjFQqwV=S_we+gsp@HjwMg=6@M>^2amz4w$ z_X~F5N`mxQ8(!`@DF9{ZIt1p>QK)}U+FP2jbXaZ^&JkSd%ofTFqtavPBKh2j(x2Ww z801w%=SretO&Wuvdljirb`?`wJ~3^$eF<`aV|l=EN@v-V_O@spS<*_ICWWBp&xGNMz8Nl_I)O8xdtxjzDeNT2w!uVd-ZXlzeql3) zDygG0Zvs%lkmnA}C@vv>Hdb|C`fVkfb_ZU9=a^#ZSbkL>;=6A^sOy>GfU~A!mzO3l zrNnTT1;;FHpATkZTD7LK%NMCEGrcF#UlCuzj%WK`P>8vNiZItb@5|~}3mO@~%aSQw zp;&Z1pr&?e_2#5nK?3s_WVplGr?g6+s;KND@4p|`Xwozw@VMvF;NPL#eX{A)SF|r-8=6yvjRd_Hj%b$1tR{=Z$obL=F#X znKt;f0<#}BvHQuwJMP-xWiRLgoi2#ogKaZ^r(x$#>ZW;sLxXYTlE9(s|jmH5`LSv zCVRHT;tRM1P78|90T`}#@9CrnOH*0Z-GwhFZ3p)%I+-Po;KaSpaSWNz>LJv%i6;pX zPKbr^fZ6GKDgH*+6jR2PM&6+mjn2XZ$r;Y!+k1tqRi5SVasp`Wgi+M)h3bE<8?4R2JpL#^UP=MZ2&eu@1(1`AL_152`1wiLyJF+w09)`;ng)7)0aM z6L&$2oFkByB(h_$5W1_Yss37-9=|;AFQ&5oN0Y#$D?u<-XWQ9*ZE4=gd$nWKS&5B` zYWnp&35J|fkZ=_@DXt}1bI^~QE3AkQC@#EgjNs94?S7rclPxyL;vcLukR@;8P6=Ars4v5~;nrE)rg^8D9Z-TgJ0 z*xxs>SZ^(B_ZwfhmfYCl3D*2sBeI2SM6w=z22BVneW=SWN!-Ba9Lsw6Q#Ez^g5%oE zK3l<;;@t$y_IdPjt>5Ix0=Hp2$dM#~mWDDM&Zgj+_Q%Z6gE?;XigPQ2S(|$yngD-jQ`{;Z)sS;=*U&EYf|!OVPJ`DgXX}-1Z9}3{tU|%O1qO_Z1BW@~d--zG=-O`Bh-KZK5O28O;dZZsQfbRR zH{|OhGLVTq1IM60flpxGPE8d~G`{IV9tov>?a+ywo@kWOo$QW$W#57(nW4@dyBaOz z5g$|~mI}A^ypnOdERlnmd!l_=GF87)x@Jc&)9nuA?MDiw9gEBa@;hahE3AR@e^dSt z@nc1YN@mf9x)CMu z75E_lfD1oCJB}hxD*H7V%OoXj)aVR06dUoBO1sdePZl1tfnDP+>Ic*zCNOOkac@9| zT*^0M-I-EZp}9wQfr?in#&u+%4<8TVnk~yw*k1Z|B-BL8YjuuagtNSiEv1OJQl-OW z9*IO3L>BTv@W+>+7C$kJFa(qmP0}Qf$mhCUG$L3;CKkn+X;$z?`T%P!wEh8Q_> z32FU>L^l!}Ya!tKp&2VfV2OYOUJm3E{1pO2lLI6z^ z3rDxWjQprKpi(lKm6J(m#6pDPco5RX{9@kx zfRmKt3LMj<_1GE|Y`A|&ftGGNvyr4$;)}9cHXyoR9$Seg33an7VBD^l`5S^AX}-UR z2xlmVcDkDj1Kp93%$KWKtvCbn@zfusXdoDpeDj~t~-pytQ>%9-rRuoYOxvDfRyrb1X zHZG43`jn;ki2r`C&vDw}#ZKV?dYZ)CLQW%iI#X?T0MVvs2C~{{ypIY*VU_T+hnVp} z)N>Ug?CbJ8Y)m@b{h+WJJy!%>CTwcVHaf?wX3d4ppwHeAcV-M$gFe_*AsG~LBK#~P zJW8dIj*{s%Rq4M(Bfq+ao)a`nM$+LV>+BEQWlDHEUGdSI2tyaqJ*t>Rv@B-_L<&K$ zxshecPz8Am-owkL?En8_5@@m;S;*k z5OA3+Qk9Yyo$YlZo^Lop<|!7(vl&+%OYm>@qM2-U%VP;EF(v&yu?v~@#WQqvBnrGb zu75D1C}L78V(gT%R7{OJO~G#!P6W!vix}QzSp~+g7th#zMHKUHp6wzK!4NM6fQny% zMNZfegBrX4!T#Vn*|?-ardx8jN8Cm-Y_jkLVCd10Wf0)5HPsNjah;xuW1mo4BjU#C zaUuc&gCfdN860gzWTU0s2}DF^NGRtZtk1;nt>$PoFEm)PNb-6N$@ssR^z#*CAWdQH z;j=2&G=*S)AH^ZS+D~o9=NXp9+zj=^uYcbNeIX&dq6vWAZ~+SBj*7n+C2z~?w(HaFTFLY2eHXO7?wl79j3O%pIZ2f)%PvfP*{=euu5k0?wC+$2?Sy;N$9l)+?@SI zhWIR&`(VZZ9B!Ax*Lp6mSK^yD#KZ}i*^1D-#hO$Ho5f|;8}E`4O6?45g+%MeNmID} z_ZMr|fImbgjL1@PsaFY%f3uAi)n}`r&L?!`oyaXHQv;@h>vArNRor&APMj$Su`8LX+sBc_%~vxJlOeG!V1< zSR%pubpUg2H$V}W`6qn!E3pb2&zie!q+L^MUOGJMarItdneT@i$n|oQ;H@b54vw4q>rdKHT-TUfh0+>v-;#Oz)W1govY={lwWW9 zEmneW1cdNGjSzEBq^`5m0Y05n9kHqdlP%v(N6cB;(R;LG7}Y-?wz6)%xEf3@@c0RC z6K>P`t7Ch8@8H%Ocp3|(rVc2Pl2gp&Tg9xm2?Om*LF}%LYkK;4+f!8+2+7D<`khwFk*%+()f^Nv|M0pkIOf`h`>TrEWhWE)0O6{RyR;I&zu2F) zO}*&VE?d>P&n150`6sjjDqI9@wyceTksAGz`$Q_9N`h2&~Fjx5R}F! zE(?whv3yk6Dom6XAdfEpnq&G`${{YG!Tz|6?__El`dq-j?zR;uhl?9wH%*4f%cl(3AfO&1EkuSJNt4y1AK`@z7hNms8*n~ip)R_#6=V9y z{MwtyD6;)>m(Ivb^srQ+Nkvpp)5I(hNN%|X{Bz%ArwVe3I%Ol8voaj#dn-mWrgjM_ z3KOIpr^ZjED28;eJvZ`7wjoVoKmZ664|K_COKH>-2F}8aaUZWn_uNu*?=b`{t)UA) zI}$~)Ko%;`r`a_JoF^1DpV*p%)~SUX`C(EYj^y{{n}Jn09Z4luayVYqUr%4E1=D8Y z(8CnAe0P^>fp*li1BF+V8bY)O{v!7bg@ID#Hr0$ktCw#QNpd?o=F`w5oZy?2!44lWm43pxVU%*Zptg@*u~dNpt0Ve>Tmz1rRjrAK%~(BqwF}IA{YU=WI2EoNs+nWbf+ux(wd8Zo_?$TIpCxacffb` z7?8Z%(UgZd@$G-Bx8O^!c7Czwt{>~;qq{PxGx5-~@@5;@^8wn!`JsiSTxT5@d?WV;fco~2>)Ctxr zamA2vNM-5%0g^X*{*_zp^^B?FsX?x-P;k?Rlzh)AJ~xOr@C40m@LWak=Yl7KD_7T3 zYJu6M;?=@#eAwjRbqi$KtljOz)&-4&D&{N2*?@{yD3;kjBUF<4V#-3d7sqbB?;;f1 zAHRm>q-h3;ScA~6pezvcuswMqzU;p~_Dv`R<=cPer>37gm z0|=)rz*~G!1yWf)O#R6RN@ABVkY|tqGZHK~H&L*vjJU+=LJxq7D^q{q%6C94CCbTLV zDcZ2{T2YTN?^2Bn+ZCnZ9wF2vYZzVY(EWZC5PwieS3LjaVkDJQ7hIw|cI3@88?FRX zTNw#S;p9Z16u{5uKUeq|!?`y~EyFA6d1WBWKq9UdZ;sQeM_UuU?xJos9c~yaI3D5) z7zSu~q${m??)x+6e@~86_-QEo+2mM5f^J?i5@m*KP*)W{3DP%rCN+QJUV+qjnVs(( z_b*j`Z=%)9-1ybo|GEh;0=&=s)~jgr7E`bP>=;Mr%Fn=Z`$Yy2x5OxbUGN&PYl(^M zWkXH%A}1eeJW>m)VQZ1vOuq1#gyj{Eat! z%NpJ62@^#KGrOp6@Bwq@+RV$t50^0?L$#JaykaF{V$fm~Fb>l!Iv5{*LSS)BsC7$+ zEv}{s6(8!((A8Y&%89GpmNO(~KJO^$h6)@}CHHur-vk5Pez{z^1GBwAU7uIHDX}+T z$i8Lu4NEdf4MvTK5hPdB_PIw2%&f+$O$VoVsGn<0F;|&fhU-Dso6=4n^2olujU3Ei zaP;DgCFi0`hiL4ZxEckc=?cYVrvS}|k}fX3IE0Bw$CmfG;4zC8B@Lm14a2kBw_hy+ zO(;GS%W-^yh4CK|x_P{4;(;_tJKVhkB;cDC`Q72kv7TYII%TW^iZfpX^XQ5jq?f;A zgYfv1MD~jArW2)LDlNEgO{Mq71Mu=?$6Xft5d6;RY+fzKgr?OY9t?jXl@+ZafG|)!CNkHF z{xupz?GKH(ugHWv>RzZ=yXF8xbq+&}aP>E)?ua9FZS}pX0#i+pk~AVKBnULZoA|q? z6(Kt(1Xg~lT|%=HRYp2LJP7_up?%F@{t>u-^xY%lxmVg$7&ki?&hIywLfSQaiS~0 z#c7=A)&$a{+5LGMp~(?1tK4-{ z{_S{`+?<;8@6vRXw~fLdX#(#YfxdQwG9V~Dd?YmYU0euW+Rx6{K z)6rN+ts%CS!KP_%grP7jw}YpisLg)G0D@T=&9xuTh!^CU3SU6~%7a(Pog9TJh@>|O z#D-Qdw>Oe0-BOgg%nckUBnG1Dntk6rzBMu8pt}9a?1@N`r*1eOeb0vP1ZhndbAbJf zap8t^1xG0snc+V?hIM>1HqMn|4jcXAk;qKBY{GHtvwz4N!y=Mx@6OK`-J^&G{Xtg@ ze#B)5s3sAFt{r4k*_W&uKZWv6>LWeGUrYs*Q1?dNo5Bsxkhz-(GBU5*q^D7;PMrsY zaC`3+K8z~HWy&&m!=~1*R}XeO*t^<7tPVdH5j$|wwPhzG(4}w*oHuvY`rpPH2+&lh zrGZ_xtepkEGpAPj_(!r}JUK5LkFmb148u@9@Q^{SIvms&DzBL_oiJ)eF)$1@Ffy>1 z(y`I{m*y8rvnCYGiPd?Nm*o^kyMQhb|O zet)4E4YsHZ0I;&7$aut43{yLVC(8n2L1%PH8?z?m>2@t0Avz$5tfo2O(_|5mOh}i< z3}J(e=&iON&MK(=Tp8Hu!h!d@cYkm1nrcR7hAf1PI77P-OQ$Q&=a3~DYxTp!_*C1% z5s!^JT7pddV&T6;b-2l=R;vf0;OK7X@ECIlD=~!z3Tv`@%YRA+1PX8bs>d!vKDKBn zs4)AvlX274zY|OgEy|anMCvb2i8l(&zKEg`mRrqj2>9X^uwRpni}_(rvQvUv%g9S zKO|3B@WAUJ2^bvMC14A;MD><6gOM2~*0*lDI-Bz=DH`t&AU8-4qkk{O(AqgZIX-dq z0Kp&tkdjazraRsPeO}WlnKsKLN~YStnP*QUfXc~vEIFA+WmVm_Qs!7?THHVb_2EwmOS0al_`B27H*N?oJe0sJC*Wz-GLF)9Jndn%_Hd%JVq9m zWo}yx8Ud!4niDf-nxs`jDD5k1GuA59Y)3g@>VUWd1-Xk_GF<$c99xd8&p8;lxI&`QG9+TFnC~YDO*Q?t}8G=t`iL@{oBN!4D>N-7?7BN^k29cQfl*{WK*|* zXcBMkiBG_?)Cz4;{A|tbW$3EC_;0M=)DVqQ51-caVu}ClmG@@~bxz$?H}FoAlhpMy zxEeA1kfLMG`H>xLVt#@+BP(*^w@5He^9eBL{s?b1$1XLobShs&Q_Cy_I@isP>Tv|` z*T5#>PpvL|mD|{#22XWcBe9Hx_YTEa=mS^+&R|sMaXRQ~7*q)~`(#-WORA$Ds)GNM zSApami=TM&O~<(%Ql{4eueM|cJ_liJL^=0wk=B7@_kTH*$S|#fNZI~l9s2v;WkohJ zgV@3*U#AaoNsnZzFm=2R2#r=sYdQIz)AQl|@^`x_gK6d$$aR6OG=_J#W-$NKV?JrI zp}YIbj-~JP8S(S*Ep^o27n)PkivA(`3U18DumGo6?D1!N^xtyfQ22W_cy(As)7e6e zF6Zcfn2#kj$dr%Pno;gaV;pj+@V6ErUd6cWJQ1~u2H)byM7GSNVu;PD6L$``F)k&R zs6h3Sy1rHOZh0S_-8w&i_7^iUKqKDgzfjjK$gr^BceDb%U;Ia8P%77@v*<)ms-857 zs>uf12Z=Nvl;S>aM?4&anG*pcL)AxLff%gG&tJQ4uj>qB$><$%43ksaYcuc&XolUD ze=ai;-8iD!HEH;V)=;aj)G+KsuW(+O-&mH`45@ek6&Wb0eXL!^knRGe8tvrs+awZ% zHPW3bg7%H}i-xp5gVG&fWIe{-Lh3JJ)5fFtfBu}&g?U|eB56{^r7SrhHdCw$NseX& zg7vz`3(P9>-iYR@X5aceg3xT;8Bin*N5&CZ(^Znn580E+m*X)0EG)UXOFP+8xUn%sC8I!O(>>-evakz3xx0TP5<<@*Nx@IbnesiK=GY`Q3q3utWFi1KR9f^?9UWQF8k zjS%A)t{i@>yUfK1Oo5u7J?^!EN=C4y=?ufCFbVC~N^1x_#Y}DBO*K}({2`g=U-Pj& zxxXvr6Q8%bDYe3Kk4*^qtUcw%x+avrN)lZ)Xke{tbFM0%xx?YRRY?b)0rs%NAxI2a zOg}+x#E*Eng$1M499~?Xpd0%=Imel}_zv1##m?q^H1i8(Pkk7gZpe_J?V)rgf^ zxReKap$WyPT(1l};ITn?fJX&>h~KPO!>&MkJE{%OZVc)^(TV%QUDRT9G?$Oi`Z#IR3 zk#oGh{X?Nb04zrV4t^TsnuRRXcsz`G({Q#kP%ox>kE3H&bnrT!u z8rCKmg8rp+PB!EY84oWAb#f)bQR z`aTPHyszkXu^PtgG!~CzuC9tp9y_KvFO5X=N7SHo!WXF*FWU%r4;hYb|$$11$SgBaB7kc$ch)^n{_{Vj{+=d(O{w9+$XI16fB# z20Ob8pzZjNUMmL$U4}8+I*Qn*fJgLz4%#?OS7rTxREg5$_PWit8}%dR30UY)<=qh@ z4PlH#SsSe_)tm=qo#Dd;Umd~LmnW&Y9FeMRRvFL-K0D+s9&RTuPQeXbeyhM@33-># z16qCgBp^=oErUe)WzDNQtTwuot-(_ni>oe-<$d z?Yo$tVc3XeCc&;0YhpKnU8)abxj2H#*dpTN3<%NHq|QYzE8?N$07{emn(-RTpmUb8 z1vYrv*$us0f9>33aZWN|7%0L{iSP-gx!Bg#fTgX!M|&AtXnB- zb+}Jcz3tJv!t$9MoAa@o+({k2jqBnP6+nr<2bHtk8?&$eZ6m$XoEO@=FSHw7sQVvn zAB4yu+M&rQfWR?ldFP;68+g6zH8HCv)D(HjTsZ?M4ERq#T_kR~v|e*djT<$daug5E z(hRVItSZ>O{3F$mqAcP$E$4OHI!?q5&tdf<4YJaUecAA(xVc0jK zz_JzT!6K%3NYS_bQmvgSjq2MHL*sxArNJ>WZP9_rZ_~Ia9e`;gv=!r*#X}zfQsrE> zPHV67!Nl`fDyo4u)(YP>g_Urs0iXzBLF?i?=yCIG_W^zr49gCzPAN#r{q6`Fg_DrBr)`Ey7VYHp(mlGPg*-zi<2y4)1iDY=#~kx`1#t zVePtA6m{!BgiJxyin;7&_|CcUo1As&Nq6qvvfoMMmZakqL(2TwV2L=PGUXb{O0fYK zZes)#8*^dD{^R(3N7mB6tgr39N+tlU=G^^Nmagn|Pm}cx1c*uR-H{Qv}W!eX~gb=ZqNPe9NPK zq|%+~kGWr=_j$*l;JxyCT#DiGgpdM}}T7cR=WlO%=9%(K;%}6lDvfMLDVRJfP|KWHteQ5kwES z&_|RM`+N>hF~<2a=qlC?db>LJ{Yp53t~e{O^2abyD_LMOp?gveL8D=z+;@;c*AjcT ztMW-cPdK*%ZgGsVxYCB;*1nWW)ATUEaF=xuSc}Q!tB2AQ` zY>s;I!heW5j?|grgk0l1Q{L+chh6Hj=rCQy(^wGr5m<*p|2pl{CS%S!<0kL6gz&<> z$D^c4i_fl8MMXe<*%xa70E0eW|5xN>%_?2QQUC;jRP9{3zago0@Z@IYXVsLefifG{ zWcvk4emsQ1ICk4Ro2L(?yw4pnP#DDFgBYyiBOTM1x;m+IlZmkpK_st?b6XAIl%9*Y zt4}S8BmKyPrmAmz_6+FT-#~@$OkEw@D>CJ5B_DRDjLl(CMeZ(TFB{ z}+FTmoqd(3Z=O?w%P9$(=3Gz!&&Q6iaWY41{$HM(6V0^0DaLf!RdLd z%H!$0TQ62Baxr9#Ze>0-ABW2wqSeJk`)xwrTy0vpGA9C=t}}m|Y8>N~ef}kd?c*eq zBW7A1vDGMP)+M;HPRk0y4|B9DfY@wUo2+BXYD2dGIV=mEx0@vuPv93Mh@mOGt~YWw zNb|nfQN`gO?z(}NfTQUF^;$}f*S>Wa52xfl^>lf1IhKc-vEU?E#zqtz=3FSwL zRk6B26k8pI5U=VSe|^uZ4ZA|Ao%1!Q25vHu4T$(ZTrR{3%OZ!lPx_^8aFa``_od1m z0lJAIu2YD*+UdzVza64L;^aZlAy(%ra<>|YLz8L<7)t~AVyS={tGYG;o(n^$hC@4xrX{7 zC0RJU$b@bD5UlGm{8#9^!_e0%u`HG&Y#fzVA>`F)Zs<78B5sA1v_<{u5Dn&r&)JPU zgREKDzSX5719Mqi3!k-xjs519Zva?CJ$Pe0bM`ms@cRD`sF^|HVEU7IA^XJ%# zX4SY<`Jmk1Vq#dd2Y-dJ=Nu+ii+3jk(8qWmxk4hNTZ|*ZiD8=wXz!InR*KwXGxhAI zAZKfb*!_|%loR*$tB{5Oao-Iw4OHh*TAh&}(zw56*}NMT=8*~{G^=w4BSENddP5n!0V89m z`{C^IU`MNy_;*80S%E(s&%4^k&T~Mx`H`a+(SiE=cst8vDU$bl9n0>;OCEwGa;#$W z*$mu8ul_Cg=wH~q{`V!7AND$0iTd#Y?fSe=Ja@q0Yx&a)GMhL+o3Fp;!A9LyRbN>* zZBOEd@JMsr4*SRh%R&&cb?coeo~`tHgA;RnBPJj#@|k=rqNg4>R=2!~Fx$%`g9V3g zOERuHhr*pj_Nbg4#<^&$;A`IuGjW2!fL)OCyA-mPHZ8hQF=zv_aKacyVF|i(dh7p# z9o)DOP+GGF{r2dmK#RAX{J6c$dS%9hsU<#$x?r9D9=aU78YkzcG*VU(e4styFa@Wb0dEkLjarOI`&AUf8|FaS z$?S-iYWVU=Lz?NpmvEmtyc!hg)bcp^7X<_-)|%=f&+=JNqXVrhO^Wa|fe{c|Wl z7wz39$EizOw)6*c0p&YH7-;__B}FUEPAPttIOR`d;0s4|xaqEX6*tio0E&@G@nR*Q zHjEP#F$TIAVWbsCEIN)Jb|bnnds6BlBe_jfQ+zhCzy1XVTKq!u3xc(wuO6{sDa|Mk z?{p-#iMzzV2X^DCrEFi%5ApwqdS2IkLVyjr;Xe~Rh8j>gnH!dStqH_Huk@Q>nG~G9 zsK>~D=ve==TTKBp74P*W;_k6z6-~?ZdsxBW_F4}!_7Gi^VRp53vzry(bQO=XnT0)? zB?m|mj{MwkoEo+XJ!nyv3fGYsuj7>+>O!pxK|aIiV;JISI-|p;3MIXDDpYw|InG$X zoP`9fVAzK+W0yBs@dL8YvF+UnZ$NKsbGLh$W; zjP*CA+>)$qm#g7GrBmYd0qP3d)t{Dv5!W2oMV5YueXjO)M=Bg4r@~*n-dFBx*3Iwg zMe@M#c#8n^J+chd%{-+FL0KzwNTYDLg``ZTcc>V-F4F%XIkp%Hz7z6X!~!a#5rYnSLSoiZ60WOb`gk9X$m%CnQM8Lgxc-L>Tx@WHTx#91SrTbzhBvA`a{)ygoBXDD_dljXut}v(>5TOQow@Ky( zy>?#4pp*0sYrTJZ4@+%Gq#X;OD?(2G#cVHAy>yulr+QEAA{ShF*AFT~W0E$=p)A-# zb-sKKCIp_Nz7c2dhHG}p8G`qulTxVZR_hD{`U8-h>Z(S&SAM9jHH(veAG6wfli)%= z9KN&*@)qsg2*Eux^Kal#MUd_;*rZmg6Rwe*9N%r; z*2nXp*uW`<^Xso7Zl96FRUltTo~%2Z=lY{m2p;ANuCo+Z(f}Muxn~@O@&wx3tNZ7& zVa=tVcpwSPet_dm z)xQqu-^BK+D-MT~F!A-w06IUpgireXT?g3;VpWCAn;-JLA9LC2)XedA^^7`F1cx)l zqMghJmO_thSuLzvDjwmhW0h-4wL41L)5T`<@$cjnYMZl~1?(7I1IYR=lwKg%nmpzwP(3U9=|DBcR;mnI*+{k|)Q92@*;mAyV54R+D@X!fASBZG^)5rE^ zvH4hz-=*OmKL~PC>K7al?UaWnC1xqJrvBw%cvZsTNa1^9$!So)e5+y~1s(AL|32bL zY+e;UzaCSIxGYh`le0EK*N@NpvQPZhWXs)ZR3Ur;+m8co32O`X@ddshh{j}NZ+HO{rKy& z8YI-M@6BfkO+%%pP1*|&y-S$>cW;Ck?(n)6WOSRlvjsf?Lzl5U9H@y5Jmj8YP7Vp^ z`t`~gwQoKr-OG!(?$W!C!xX_Bgbz!JNfLqYqIG=-#YG9D!L5pE>l4!2XjE1fg9GH@0)v@AVr6{mv{x5|mku(Bfe9HAz?{#Ib~t0C(cMYCMU#Bwpk6CA4m(n6NBrS2AfA z(g>i749qB&fHE^HWc|lXh+aX(@Ck~Sz<<^1<&<{k$PWFF~PVl zDJChT3wJbn;B0X1HnA_hJF<|20GStOT#(A54#ZiD?0pXmq?%O*HXWTG`m$1MS-!ig zkI#C*$m7k2M#muyxMPz7>nFlS;Pem@7$+S_5KCXO!89SN$Q$#7j{V=;F@ z0DmjPM!^3X6f-GlHo?wd4&Ck}c}a|-W6Vm{<*Uciw3?(?;a!fjubeE2S!L?iHP@VE zqZ%HMTsi}u?P+RRu9^lRb3UsX>TV zy!R;Rq@KlMJb1U={<-~(b)`EumoCx0-9Y=}(&*sSGsq*Tx%_p~nDp1eqWcOwrRi)n zo+^ zR_wGRw@#$+_}VyAJ95c}9&bq1W2}vxzSY);}p!4~(h^pIX~c^WxhP`}!IAU z4WI`El=CJmIx<|VU18+L2md;HN(*49VZ&ZXW#vq4I6uV=ssn_Q0S)tk3iFNhgIU+o zLYB{HXu#?hCq~byPMSVI-*(utLwQ%%q~bytOFOGuygf+iwJ8p+VVg-I6oVN-3|z^&>Fi zk-Y>7IrGHBMu1F#45=5Q+w3Fw2SQ~!*Cu~IrMqSOcRLs>3s0I1AGYq|e5i+%U*xPo@0VtlV)TnI%@cxQO+gbqzJ{gIO<^TRh*oUY>>O8fsr}Y;)!3r0f zs@$~t&maj!udOdvdzr)P%XoVbr@ap9@x1~_jcr~HFnjsW{Tv(WP;g|nxMHL}-MZ#9 zG>{}>?E|;(_i1h6ZV7B%`LO;x`Xun<%%FMoU3K* z_62o*_vquc-*T?nc0^P4Sfy6_vly;-K^EH@x1e-A%KpQZdVe}_n~`@{l97z*@$cEY z8RvVN2?z9J4F)+&Me}ItuoX36uecDj%EG9=Ep~%fn*8||AzxNaGVbI@_>R#f*Ko- zr545}rq?YHUg!DCfqW~@Flv~Noq?>?a=!E@vGqd&L%+jUrOmoUJgtTMF&gZh*+ZPB zv~=RisNAZ1Z-e@|MXSuN^{4tk?&#&`(KP~h|I8q%4~bFL(>2T?B&C9qjOeMT%Dlxk z^apLvVCvbr*p#aQs4`5}am)MbjGo}LTCYKTv>>G*dtwTk^)<5Dc-p=Su@jrN8bO*^j(vX41J5=eV@pCwu_(D+dOo{%Ai3IZJFe*Z}O zlx$e%glMHm180c6HTt~|K2Jcuj?PFQ_|&nCp`G$hZG9rF4$;558{P5qg-_M#90t|E zd=`fko?7Pksp}(Yu|2-_a&e{|cPE;;odIT!6$lpZc?uT6bF0{YDXsnf-sM zf~n`J9_$fDI6E~Zjbr@=Co>L$wbY$npdtvjO(Wo*FC}V2&`UXg1v!bm=>c4v{J7;a zN~s09BT8#$$s)D-bUTmnZ#@gjqkd?6is57Z+&!k3ppZe|m&1w}E%xkiTYFgYzrz+! zb*x|SJZ|#Z%zy*=A)y4652VwKwsCQA+SO=*I6>YhAk-tCZP^nrjNx zwJ~Yb|BpYHD4*whyV9bHETon7MY5d1?9m!vWk@4z6jzpuMWczmq88UVbBxcj3Yk2W zpHjXa;s1&KYIq9a`kiY>_+yuHFQbA*tMw4$4P3b6+7`rT2x@o%BC?lwc zrYF38m3!BvrWTlr_o&gH>W@c3Ad6NeXpKdYm49~6BFF%v5Djdk!&Z=e@Bj?HkarAR zS;Np@UsYDV&V^=Hw`kKdZ~DDY7?F&Ld-hW66m1Z77f<8+JT2TgQgP}U_bUp!t-(A3 zHuCMjw3P{ujHHgmv>yX$td2P-<#u-+Ijrk?dEETvVtREW-Z)trN+3MJy558@f+btj zFB2m!SGgW%cn+~z=qf!});X#~kELOG`D@5nho6hR-xg7vgnkPGd7d zP*kg<*zXynd&e`UQOm{<{=StZaUznl@rsnk4eU#>iGNe94qVJZKvM@V4wKDhlFMv{ zYQ^e0(1qrV21;5UQ(mZWCpAW8dKkJkX3-8LQm0N@7xj-XNnj@vs}v~C(meWl)Hc#hbV zdfX)B2^O_K81pdSDc(*fky4w8T8&g~&|Yz2fLm-6h|!}VZbsF_d;QnMw9uHl&Ky); z0fGkCj4dqqWIIlbYMyYzQ3Q*_r+y(tN?|2yjv>BMnHhcWgxk z#@84kUQI2?19FSZFvJrRnwvh{JB)Z)El~!H0^7*!Z+L1>tBm<;$qND%Wm@}9pdJ(v zE?DHtK%hfW5Mq*tM2*vp%$jPPAc2pzB`d^klFFYI#<7Swuxg$60tLW9waBC%m5^ki z%d{6R;^aZIe|#HP_~DlU@c(bJq~7Nkl1rCAV0Y_x{qP{rz^6%jjvseXYLx?1^KOhi zT7Yof4NF&=(Wk^g{n&REf!-6n??%4hT9smvdM{WenT&2E28995C;j5Im!p)4ky zJXT$7XFi@+5c93{iPRH%eZ9w+cdRk*y*vxBshIHl9i6AR=JajAkQyr0l4wYrtv3-V zvLg(y{M%6g*2p=;4Lb2Uf&Co+r{%eW)2|o%^ka!~WOH z9Cn4bZ~NJrZcB24|Ke$eff1ie1);g1h%xHZGeoMCKrYK6lPFwOa91BtBU&`0U!1g} zt`D)?JkaREqE1reL=i|xiyE-|qHJs$SV-zG&(|Z74RqG8N(h&Dev2;yj^@}G^gJE= ztxbc>yX-5dqU&m&_g7LqO}~22#=OVGH-=B?S@Xmty_*H-pOgQWSCloz?%vVSg_|pB zdvy7=_NtBnc>SY`RW*2lXNBzo;~EqtH61>R%gN^vQ(oR1DzQlJxGIbSdnJGjM~Tc> z`bo||zDoiPwEgUfmrILK689>g1JD*_SP`^deefu>i@IDOZd-H9{?n|*y6IG|hY&zu9l^@PoU6Q+K*h~w zbf6DyhgYU-w#w1T>|VEL6Ra>&@o+Hk=scTK4*`DJ$pE58G_tW{F1iOdj*C~QMzw4h zUUce0BTKlLgB96B2rvt|Nv=5j#FL6tY&~GkJKhaQd_4_VbN>vw)Ob(D&So*>-oNh( zS$4WpYb=MLd*x!%g+899tedJNpE|G1{xHZM7oQL2NuZ(US*}w3+|e^U-fPU7Xa{I} z^0i>1@>2GbF0xd&+PVWW5~vL$C9`vE_KyL|FOUX0p1+gp>89y9gL9|bm7KP=l1_~M zA|NltBkm2HKhZ3-O?ucj^Yy+QIZX-hVF&Au3X-1CR*6qo2#^Be$AT5m|0a|HLr><$_IJ()UW#Kfj6qU;wRn-ILZ5RU! zea;Y#KC&{ks!ab4^Y4g4l8XJ#$TY`AW5nM$YmE*PZjOQ0LaAWLXbv_dq!%$|VY&oI zc$W1!srA!X9vkL!`sk@rgjz_iKsc1LS6R*FFawOff&o32+U-kpI1V=qA78U^H7~R@ zIYfmh^X$UDDT|5(P@Te0bVdTREi=E~E<2{Rqf8o}-JT9$B7w`s`C#nrE}Zv_pRsJPh!$T{%iIxl;VV=hD@*Ovr(jfbkln8G3=(L|liianQDnH=l-}zWHS8%Eq90JZFDhPI5qz(G- zOXK0@5a+Z{nfnzGLIY68cb5`mFw(TH`#*gJs*Z@Yic(rTuz?mL2 z>E8!p_7@yZT{**czO@+vowk^xr5@V}-S0zkxFiGm{dAp@87yo(0&NgB)=)Y{#r(Ct zwNMj8VA5X`7y0i>+%&55Jt^SNpQ-&<4IW_;rVHc(|BQ6E{B8KAWnfjaFxo7 z37ct_d>&;FpP&g#G}EDX5FbE4KR{mmQq%5NS{7tRlStX-mw}O*yQnwq-BS;7;71gg zzt!0-fn66(e@Wn`YKKy?QLkBjya$ztJ0ANaJPo5+&jFIqvhRTFR?B+IFcI56AEN7s z>C~sv^2lZm+x41!bYr}>#Q!MyT*Xz+|DGvnGpW&VvmD?s4PVPAIO$%>+f^C2J8;@> z#3ORCkI$dos747_eF1<1!e63o&_KS-i&J;g>&|@11v=8pGXf!|kYZv3C~rBv zmon0^pnW9tWlBgYU`t{hcF8m#b=Yi&V9-KmzJi|EkzojAohjQ?CIO_?8wDm(7LNQc zIiWbVU)gt^|JTDEn;H5zk^*YnJfm!J6+zp{_#88d(?ZkC|9*IpU@N~q&}h@W5Yr{? z4F-ndmRr9GiPT;}tHB0yu}cCdzYl#D+pa^Zpi!$D(=7wd7(3ev%}%P^w9*Byij(4F zZoHIpd6ej6>^);4133-3`-NL8oB~e2)FRc1I4|c_u$H2{4_i&!d#)`tjSEhzO0CR$ zYO>ZW{!IQ~$Zb(p`+#_=CkneIKkI3a51#%$rqRFuo<31ob?IFO)Fi7EN~g6e%A&Pj z+mrkt^RP=`6J;mHXH{MDNock%82?kNNV5mCBGA#r4~`VWC7h8|97?WM`ZSTbzW)=a6Gi|b=_=C+_7qV956J%Oo(0viIG!-^k5ZS`0;Hk7SCZMqd9R*~OE zdarmF<9<-?buGhxcr84W(5}};wGGz<^m^`u6!ztUT+|VKT{M=|j&05ik{r%-?2r=( zo#|^`P``+aQrkOXC(p}6&PGeGZ=;seo4qk_>Alc ztQSJHh=0Sj1j40l;{4NdKXBFxb-}$3LMIo&)s65~l&-xFoiF@>b;+ax9;64US}M4$8&S7;Ty5Q7YyLJp~O^5RGbmzPQNGt5uwz#lo@wR%&i zW$k74{8K5ThRQfDcCXi-ylATP5Czxbq5=>WPMZf0jQfAi5t&zdb#L5D2yV$~2$8jR z<*4CWOz(Jw<;HmA)hSBKQpD;wCT!cuu+U|Wnd7_4ycUsMvOGsW8ocvl7aKVRgHbrm zt#9q2pTi&|my{XIuRK+J_Rpbs!)f0qh37CpiC|pCmm^YEDkUUflUUrfDa}yPOGqmo z-4^5l(o6L6RVUieeK;}pDg95u@f)CaG~{ix4T4t3sTT$ot2`RDtkLDSq)VfJ4xRd@wrNB%CQRbnz~+xxWArvmr5ID!>gB z!8qD}-HigEJ;T>vLqC3_pTDOB*>-x>N)~4Q78RC`uK*7PO|-UM^)J*a@be2qfWp~G+z$^{P6(Q>zqOvoRCj@tzczslg8+5&|sPM(z?@+pW{}Yf&fZNw<5c{Y8*LywPKylT^lrD;Q-txU3ny)y zlMydwQtYe=PF<)P)JX_DQT}zX$4~@SS~7L+x3j3}Tjm?M;E0byA7v1p>9s!i1|4ir z+}smjof!8T|CjfB73k{%3r=`nWaYVDaR5*52f`SQG^BfOOk>;GjIVl2I)VygzZ07+6mwP3EDLT`4nP;d%{?dIJ%2DLOx8imn)o<-8Mr zqbd25esM(3?uL6TGkRlVDTFIs61Lgkv}LXYd62f7xiS81nh=pw*D?jvi>peJ(n~HA zjiC3sVwKS8@zY$SC#V+xOZ-mQeFcvjhVn*bZZRzA=;3Q8O0LFot1Y`OMtacYl=q@L zOOU8#rCr;NJqg&h289q+VFl6<@G@>}Od9*%hwDoVfqIBSuH_MsJHzKL3H=nXI+83d zQxpGDwJ_P0ZUzfE_D`#@JeL#?%RI25{`|jpJpV|Pe8lnbT@GFImr zVzksNpU!WL3L1+M&$pM!BX*EgZopBqVw)i(Pwh%s8lic-r88w->H3pO9(daxYiiP( zY_-gc`$?PA5IwGajdDyC5_oAVmph*EAg&}=j(Z5LmAs##_EUZA zLO=GtnPDSnf3sJ2PVz&CvYi{*$LEIc&`U7Y*>!^#3*G2`@fV1IEIqKgZz|IiTiwDO zY1fBciMa)IYEn+c^^n9^Xk1y>(7#_)U1d<;o(p9X=73>aQXj|5BL%7jm8hQQddOsU%pN zF+L6_Zk!+IQdK_4ce*>@5v+*ff)T5Sk0A<40Xiv`2)qEs&MF_>@# zlXhZVD>uoDLK&O7PRqipV#V8P6KjIE{En~ACpKPW#zrI_>hz3J%YnDq3+7+ECa!D? zf0%b`>lvXTDQ{H+r*Rp<<4cV+0$8c-Fn3!8lIiV@d-TvD+=sK8Sxm7xbSkidyx!sU z_+Nj7n_HrS`IPV1YrY83B(K+fZ^(Mk6;aBaUz63Z59-lz)zbg{%=4++Ynw<9$~X5? zuUiKY2?D|{)vG$NvNHZeEZM1bMu29w<~b68yM}(;X#vyb9yLdm(_f(cKd`5nY~8`g z43h7nJIw#d9xZdG8mMcIDWoj4JTw3m(2*YtwkG+3{R}d(6@x^gG~px)rgwNh$+bFt zhl&*-%FC;H`d?2o97`w7M?t{?i4ZkD#dp zmoT<+TPn;@WpM5LI5y}0qfvK&oE7&fjCKcGfIQuPK1FYtf8@LXuC9Go*iR&Rq*{Nj zvf7r-$gC7DvN_6C5K%1#r#wC8!;Xv-*KxtoAl;MWveb%ldos=2`dP$X28mfs(NQ|4MCeULN`vL0!FPnE zPo!aL@zT`$|%NxA(|; zrS3*FA#tW3JUTm+)ftn%9Ikb-x9=7L=s)c)O?)K zFX%`{7%R>SO6K3B<3IG-`z``T*zJ*46}sL%odn4wupkZ_{_WDycY}4|keG$$b-Bbv z&-h}+xugWdtdsWM^0!A>y>Oof$aHDg_xtD$oLV!(A}mMF$yES)`Ey^Cj?yu)Q#^je z>%WhK4n&0uqmK^Z#l@4YULQ9V=*iIBpibzD;&jjC&`L@AvBxy`q*995W@Q8v8@2d1n6zmx|ifmQpW@7 zovXkY8m`Z7v{YhVoDvW#U5zTfTl{aTP;E zS5?;T*G3II@c+{LRf3p2^emDcf1LS&%f0DUc%f5hWVQ|}fDK(?Qeq?oe@8L$^l2KI z6Oa%_bikC4%~cmN?%z!CO<*DTE%-Ev!K-%7f-M@{v(ti>6vy64awwzL#> zC{cTw2?Ih(MCYm4vb;`GT>{k7${m^N*A`-Oyo`UDYr8*HvRQ8N#*Zro5k=WII16Org+t3W!?s+8CFNM^4Wy6fnRrT>YxPES-XN=D*KHw|QCS zlnlT!^C!fmFE-d2h^Vvnt$HROiJTXU5d~Q5XoHJqVI>~OhmV~T?zQ>8m2hji@-_(= zq9nB>-Vj}Yi%-*er8PG8I}hWi;{)Gxb7PU>mLEK<>4Nc%2N4=AETQeWx)=~0QOP)X z%>0?IsEoN{ajv8F4n+Zq2Nbf`6#ObV?<}FFSGZ>CWPauxD*P$Pq2Bs?!=`NA7ngJFIbCl0W2IhoQJVJ9b_tl802Y_q)vn6~j zdOV#s@pfOp8jh%evbFL0mOftf*k?i~A1%y#jps4&hf=ZR9P$l+Nz)TjnY?-iqN4oy zAReh_{_ibnPT?Z!Bbp0Apf|!Cx_%dAI8DvVz8i(dGVi<`L1`~=qKLh_AEJjY@ zE|6EQz0~*zvq7Z=X6_+NZPqbb(d*y3Y~}_9)lCK(gp~d4(_`$>##(?b<6C<20UrhRmJH+zt5aWnjlZmw5{3_ z)o^5he zq~EihCMBRmcn1H3h$ot)Y44wEjA-}ZJln!P?eI)^W|tnR+~3s z=w?^D95S6>!oHLr4GodXKXFBoG*{XBgr@%?hLsWH?LExn!ryur^d^;A%5?wwbxbJu zzA$U*#&+t17a$8qy$>~YY2cK(^pdQVt`cr%(6*1mP8|%LO?T_T;6U95)$=v=saI*f zExyWk&<}g0XPk{}@@M&>!1Q?cb>BrsjU;Ufy|oEK&r%XVjd0lKX2`MSCRkSnc*m#p zs2E*tK>?|BHJ}r1MhPl-t`^HLzK9jITwdC#Y#_}qguguqK-_kcg<3>ZXaH&F$3RgL z)U+mhHUnPpVR zRQ3N8teI`yh&U~cZJ-I#hsU9?ZHrK~RjEyb`N^^4#KLzi{+?{cYofMh(|-rNe_U+h z{G*q_@5mqaBN4GBU|0=$kBzQ*kuvoq)5jbNILA^uhpzQ11q+lr3$HikAWwQeRjgPc zl;+qLqo`CdB+QVJST`IG>%?nz*bQ$TH&A-KczO`OBL^F^{ z5$%Pi2h)n_(27Oo`WMbC)sr4)h>8#dG$KN_NJDSsf3rIPF2-Q&uef^!g9J^J|&(B&G;MHVmB4LBrkdrvPK@H*Gq%rZMQT{wnu1Odm=24uwE1e_j|i4!La6) zz2!996m7PYoyq>`(CQpvK#g7b@4G9`tt8+vd??A|5dsAr)Fi$zLJ@kSPS8+X^tghq znT`SEBWe$3@)B67YGWIj%<8Mg#(^pkPoUapCCwTwrU#PwUv;Y8p-9NYIa_b<$wkT5 z`i~gPXP358h zGevtvK2mFK_8grXIC-U?G=a6a%|^p>;lG49pi+?Ntfze`*=Bq9*B?x6yUn&Yicdm; zmR2bo+Li$+uSH3t7;C)4fOYc>4eRaBZdBj*jt%f!V+phzirLxc9vyNYQAiMpR`8n@4ABBWEt>Hb_iWHZ3=%{RFKo;o@OAQM;B9PK63 zyJijj&}#>4wo-r{E+m}%rPQLR*BT;NBlftybV$lnm9_vF96-szbJZc)oDSTxawp=? zIdT5B--x;N!3~tMS8crtAba)@eGgwJjz^qnID3Ujav&a&cL;2C&x11osRM1K<`ORz z4*S%}iF|dzeDHAdV3uk6{;0OWaOZ1Dq;pl(5H$vR>`6m*JW?Wd_| z)Z*|9A}dY<96U5k!GG|FGGD`cmCX7Fdkn52VY7V;*)xGBb0ksq#98>X3}?c2`zCc{ zLnh2%`Dsx!A7S_@U*Mrl`}y@}`~R!uRoA#TwD+c)d(0G?Q2jv-)7_1U4Zz4qZlx3W zFJ_HmoQ$LNTEiRiDjAS@1)RDc-3I$x?Ow?o@40cymIpf_7NR$D+c|XLQM)h06h*HDtv8NNJ0mwP1D#{QaTzdwKAlB&<>6)<%XD{A`86H%$Y*> zk_xPR>pYZ_3Sh*;1TQ5sb6p-45CEEODH#dnF2fPd5GeLb$MMJEo!I*KpB`(YX@+ zu7f=^lDC0pZlt>coRv=KA@p4O;&HqpKZOuy29{F2Yq2@R;~hQF)~U<=0>MZVyG5rd9LdK zw2xYdU$NM6%11S>aEw$AlVv>GTO2={U4sM(n=1BIQxUDg-l#6l&BY9LYHqoI8dC|R zF{*QEV0e(VD^i^;>zq~nJ=m6HNn(;j^Y`F9Ys<`MigJ!s+lC?=N~4zF<)9vk7n6>X z_Eg)?M{zKSV7E<8ic1LxD59fANBAsYNCoO2$lZP3iUa6gs$}0V!N0SWY18-cjQy>; zheS=~!fP_yh>&K&%Ne#&rO;O89f)n=YYrn{ZAAz0d7)azDPQ^jVu;f|En;-%TQW(P z>4c7y3qS6&Vl3tX@}(g`uX#{o=I(N%)h~mFmRJ+H{p(cM;*!S=_FDs{yRU3i=lTYx zk4X=v_a$2K_IDx=XV8Pqu0<|((J>}oE6IC{hJlHH>A;>F=UGP3u`6b#roG)wPx<(d zzM2h*xKd%}#x*oo<|w5r^m!5~gEszb23a>*VrVc;A4~-nJdEw21L2F~Iv((!;+T=UwZhgcPBE>eV8Pw8F@j;bPC_>2#Uco!LJt zEiHdr3zpWkpUWEE4a36n`!p(>YKYRS)|&J6cgrA7fU2$F1g0`0afD zk0u}pMA%m6H^g>JXcAQ|e+2v&lP*dpF72iVZoUR~af=*C00odcGG}Ld8%dwKExrtT z3p$cexCr5{{w8=}FizoU%3IzDBLSVRCPI9Xot-9dI?oGJFJi=d>n!g2H^Jfa+$HA@ z`_!BM2`qT0HmFMtEpR7RtxS#>7@{mpmCzdCrIb;S|50g=`4lV!SrK)w8V)_v_x&jh zlk{I5XbBZX?JHK8acnAaAhjy1cK#p1DS9@OO>z zCYBROHcol7&Vq#f&as}0+5c4#3!EyH8^$Om8XfysOGP4yz{Q(+!WxV0??HeGyju6P zdOM*T6RY_uh0n9H-9bghwyAfzK*mR7%FdkhmOQ~)>{tDtdAi;$yB}PG9$yEL!+DxZ#a5K7b)quPO5M4M>08GzlR5p8qa}e z9lpz>*(|CHtu%W}$QxAVrS0kRzP|?V&32Y;nL+!tp{zbof$Z(pn6}n&UBWxTC=hb+ za<&$UZnO&S!b|~DxscEDJ=&NUj#w3xcBre}!eGV`{cx7SJzv!bQekVJyoKPW?~13} zsabZyiYZQ@!_te9%qO@u?~YRIZR$kT4&x&J<~3eEQ_m6Yx#uu}p1G4;6w9WqcU~K!eX8Ah+V;p5AuAdN zP=52MeBN!1x@HS=FO-(N6Uv&m!hxw(DE-xzz{+0U=bO!vO)_bT)rNNQ`LR#CjD& zTUi=KCHL_k5JHdMW@a3__(SIDFVDQQvVm+b_q;Xd3ePUrqUomG zw0PFhnLVNO0$7!l%v}G4POq*;3@Pc%{X65`+EM(F2=RX3>D;YYylO24LnshOv;7m% z&pl9}{#&i=7(EMy3vgVKQsc}-HxYM1D`8;1Zt?X_@vQugwwRPPXa_djT{V6969|EK z#QN_ta^W9TiZk&pkbNRR{uKTZEck5Hn!ZeU_nu#7;%CKi;dZ|2<*#pLaXWc?2(EgiEs%bGHpU-28((nW( zC+P86XIi0O`6mPPjYhX@cb98}b@&&r+e31ntS@lbv|doX=E#>I7J&o_-gxhIM%Ggu zwZ+ZZdi@tV)#X0$pdzl;s4Jmfli77HOe3!NdH4Gtg%L}fOi;+#x!qnBX~X>cA4oJN z8C@vx_>GBzcztOZTMs@I*ZK%@y`Gc}t9V%=w1)azIU@$Z^oLqOkOF*@;Okkae#fYR zkwuNCo_Tc?v{0!sz}BCL_l&o1N?iMKlR4#ZvO3PUH{Tt<@koOeM*>hjl_q4|r&_}s z6n~soHbr#X5Ogv;^~S*4*`C=Sp2+Wzx5qYPu=+gJ>*GX5bpi-ishzt+&U#yp2)Nz|@ z<-A!11wGA6=;mth?bdo!m|YK5;*FiDbz^3qbskyIzj$y$vgW)Xgc?54T^ z;b^~HqRI0Wl7ALwbi+)p7s5A zBqJAzEm~pI0;H!yK;p&2~K$iISVodac z0IBnJaeYeKr_kQ973a?JRA25gP1jM#+%j8|pfjL@(kS8e&PuRaS2DwsMRoti&^PGQ zgUS)QaRLKY^FdYE{u4D%#Z82hu7n17bX{rc<-Cf-j%apHdE>$ID@YS#-;J27xmucx z{-7&gST8+GK_JtDZ_?%lIKn+UZ=ZWO1_6>k9diP)BF#iY|E*6V z7S8@LSl>aP0G<#3Bo*a*6ZL(C+Bl0<;W|QUD_b`)Kh87Aq#S1d6K4OJws|pg5jinw zv)aW9W2%2-L|-N%DU>Z2(;erhN|14D*WQT*1>6H|@7B2lX*$+Wy$k9PK*YDH<@wIG zfkQ2x!Px}^M@peRi&x!HC1(PXyW!A<6345vhO*79bI~F-c_1@IB6tH>p!TuT17xVu$z7B>?6Pj4X zRDNlDKmAd%jN>Mp@hECYRp?gN0LO7vzV?4E9LQmK@anD_w|rFW8*!-SLx58V^klKc z80f3nE?~GreM<{Mt~?ayRs7pa(94 ziEnSWw?BR7J|`qPnBDWGX6z`@m&WG#6(K~+sQCzypai(JD<@D_Mt7t7R7&ftkQud@ z;gCj8lpwV(ACj0A2&Vbj<^<51PJ>p^Mv8z`mp334i`|JmPb~?8f#`!e45h#SA03^M zYxHMZMQE#ft3(D6CkkfGxwyGcje$R{ShC+)P1o+9GDK_%Ub*3J2Gpe=&f|2)jB661 z27RTe%%KKRa`y55%|Ic*TI+s1Ma}3YOOCZva2u4(k!C5O8H813do?h5M^WC3M7xRQ zO4j?E1JU>|D^3!NqVf7Sj=0$8#Cz)avOJ}YT)EuG2>Lb880 zJ6A1v!b1FpO5SdN>Pv>ZT3@ya)z)kIEG3Fu=X1ZpJ3X%-m9Y>uHACG3UHkV4C%5dr zqFQkAjwG_V5NOzz&sH%oPPuNl5Ti6Ju%Eo^H*}&ibm?qj+cl`zQbpfl$;?=?$k5J$ ztnbXHjJz&HA0d>5gECym$qFrJ9Y%*ZCU(C@a%dih$NLcq>7*>(Vegvv&Gp^c7~Q@m z+u{79yz%m@YV#Gg!yS5qtUaQ!cDmuIF-X8Y1sq~j%)USu7(Uuai32e=Dxd7T?Be3C zDU}lHGN5$T$1uXGti#FenKb8^S?BSX+Q#jTp%u3I3%>6y*D+&7Y&YzP*8x0psaOY%P>4ekE zFc4MYhz)-(AUZ|?b>pN&-L9e)v&>+_#}Mo00_LD+_tX28pK zoY6I~y~zFzt6q#ouQ9q&~bWF);eCY?iQ2)=|&>2j6s zOqM=GJ61o6WszV2Xs2fejD-tmzIiQBRif(Tx3rHfC(Vku6xF@DV0#M@jtq5_Vdc~c zYIG#O)SR)U>zR;tqhMu!@TL1f#@?u~y0DwJn;ITyXes0bL4N@!O^VF{JylBL#{vzSI7!bCXfBcKD@>#Bh{49 zJqlbJD_4M}z=w|65Kk_;nolXi*LFfo(_9U|E9D+JU{2;w;@x3Gh5cmc%F)nyj5PD# zJ<+W%0v?O?Zz&~OygiiM6_-tbj#YN@(Vbxe9Zs%dJ^|&;)V{CbC1r=JN(lq_sCmX; zd`n?Ynz8iUlp}wurQ^NdfX>jR2KYCT;3k2bO#h^(@aks&b&Z075&uu@$)E?p901?N zsq=E*2I3TS!)srpu+O7;kk9!Us+5zZ;Kd-O?Qewdet?XLbf#^=mZly4#@NS2+? zVhr1Amq?Df@)^l!bvaw;&dce9rZbTt<4-)_SF|>StEkD_t@-dzZ=V$&IZRC!+u`58 zdw+`2G(6+$E2+vnxMH@ma*$_N@EW9glWyK}o3HdBXjC8ejG_)yE1seclFq|wwQRpN zI;Jv1B33(hxxW`XucNkfPb-2C(yCx9vjh{GW@VhF8rIwyWK=9btWAysAGI+FUx~_b%Wygf{1Jq6N@Z)uDoK~?T;T@$PA6kNQqj`M6r)` zy4dboD(-0FWn6#cy$$ObuMn+IvNQ>;9*7$i{5f+6n>YSU&6ja<`3k-^1nuC8%c`y$ zJ^6}JHN}U+WId!Bc{$sWk6}qsgn?Aqq#Nwcx16mgoaf?k_@6JLV_Z||19t$yt7ML> z7q3v9{oaf66SibR>Ex-NJNei%4Ff9}(W(T= z5#e!~-N+WP&PKvJiNR%_L4|J_oLwuDqIy9jB8lif4pCf!WorbVzm03~sZg}`Gs9>) zO=jT(%oWZ=;x3ln27<0<9wAq%SEQ6EERjauNcQ)c_9II2H{x=P4pM@&g{dZpsMynE zeIDhENzL5XOEQqA4{lh!oSJ94f5qpUj(+C zK;(FM=f#j?``mwNJR#ZqmWKsKZ8**>nuZVGS~ws-L_VU|?gRX%)9!5C+vqPB`~|6A z5d+dn+J0NcpaD1Hgwn*ugaEtIU zSCw7!6kL!YI*pQ~<;+iuzFj^W0@FF83%J>~4%|GuQf7h04-2oN-{CI^8?4dtqnHhz z_*%`>09K(ooq7TgQrQ(rb^h2?3L~n^qMF(;kJ%-JBW2BKkg9u4oJ_*=DA8Lgr9qM8 z2^p6%6PPG`V=0e1f(2+T4TMXWJKbXf=(&{cB%k;7(OIz>NP&Z26u!8&3vh*o-+a5a zs85Mj1B#K7y_1%QD0~{y7#7;&XFZHJC72T>8N6=ENcI6hnG6#JVPHZ1e6wOqw!gYl ztX>tY^jH{5a6na9R{9u+{UZ%7(|m3QY9p;s;jq&NVAbWA(JO;omrH@!IZ&XGT_I@~ z0-dc&j4>!V=0uVk19cZiA(@v_NC+m!AGU6nZEC|v$HT48lLM0QpwjR2Y_YriUqS2k z${=EEVs+}<)2@O=YULv^VuHm78 zMT&Cg*tA7@9+4tcQDS1mi-HJ|%z~N|{}SlJQ9pW>^UfIH{bov3LKmesto{`B9qC!^ zibUKY)UFJw7x^NF{PZg_g0bC4K=CfjbQ%Gz=NLrXjN}r&!+X1~`bPYQ@Ox>>{%^LB zzbzkGwP$n}Xp)RrOH?sS*CS`p!d;`1n}XtWAXV~dk=FKYSxbZ-B&t%HdJv`BW1hT9 zJ(FPGO?<@P&>6UQ^O&-cDJBtnKCR!@66Q*|?pkVbrJ;whz+5%T=7MSi zfbTJ;F5nec0&R1>q3<9n5>?F*?QK5Z0e$)Xzh6qfpbXqyKp}q;$LH-BYbsP{Yl8NH zB3-^@IpBFwhw}?5o2r@pwAQ30m@8^w`Ew5hrtt`LJ zl1=RE#51{j32qJbb3+z+$=E!;D2W&Rvc9+h&(L|Qr-QUy6J*B6OW(f~rhxwMUhOnu z0nTs73(esrqIqWB8f5Z>VQh}iEiT_A#ZQSw2|39Mx20~xk{HCMQU;9wrwbJ`59cvm zFP*V9?m7Hcv-~!D48x1UyswXhztolvsF~%-d{7Dd%ZK=^mC-)|`z?4O4#<zTLpjuOP-*BD%rJ!47od{%|-co{mcBLiDJYUy-8 zhz^!CT_H5p0`9L_jiHJC)^!nQ;w^Mz{19@`jHZ*Ho>cepO@(v4SEoMIOfaOhtgxapH3!*OeWiHM%@iMVBBu4S+!T+}h$ zNDA_C5wT(gNvx*NGNM?F{dMJSkYrj}cfJ(?A2R{+8iin*U_K-2SABdX8Uw1xYW{Vk z-^nXhE#e+HWwYRlZxsxvh1C8#Go1lY9Fq)!&M|qIcg&0cMkohxYj>!>7DS%@R)3ZN z{3E;xr19hvaB)ar+g<*@v9D1;l|+fAIX@VbVLb(Kif<&VF+_ms{_x_=*9>yY5k_z< z(>MgJ>-@{9;C&6yI!;eL>ddeUXw|uqn|0P%{eT>Y$G>Qgqm-4S*~+oocYRzf8OgQm z4NaWy-ZZ91_=}#8s>DCr8$3iNI~vz-Mx3kUYq6ze+I{azov@ZC=(DTi3I#M1S!J63 z{5C&_?N-{tY`l!7XH05o;q4qraP;9=+hJ1mj@R<4lfs_HyU|M6{jLiIZy3tlA@{&r zk_iayLDl>Yi-Ua8qe}IHFrXmNg+(QrH5kV^(pqahw3MM@Z=zZ13KZm(5@YbiQd95H zx4#H9@wk7F3KsQn$w|A$I7SxB(EnGCn0l+8xU`+Z<~g-zqE69del>Pzk^G`V0Wy8J z6N}sPz9nWDv+XNSqCAScPa+8bSuvS3tR$jTk-Y22v*bV!of=IQ{$X&(&60Eg$+TD- z*$t}v>~?UTP*9sf$+Uy}78)kaurN%~;XEb*Fy;$rj8saNN(2LW{Y3wwsbVQg>DN5& z@0m=PrZ3L>X&p8-__bILzc?2AvnnVb=@1$yZIocZF7=qr7jGB;5X)oQQR3&UrPc|* z2gd521T7X)Az|riJ%i-Z(V;z z-I!nauF1n}!jxD*tETjG37&8*MvJ>pY!O^aJ1v*C#+Qh5>VX^i_0|rHQ3i$i)S)|R z(|92#e6an=m8c}c^rWa} zouz2!g?9l|b)vxxD-*qnKI|F_#e9$rp2bfA&m1}Jys<#Yyi+;WIGI2set>=={;N4%OPSCl;8{u=&10! z*i&(8vjCYK7h{AHKJ_Q8(y=Iz95@V`(iG+6BPYqZ=a;3DiwsW|@5*KzN7HqM#wo z)fE~d-xWm8`sMk`90x+S?vVj8y+wx|S zAEvUClBJcuE5qw1haN|y$=ZL5?6Y7f6wqbXs86E7XwaE$*5U>q?D1TbghxJRAGxMN zs%bB@()<3EWCJ*jf$Y|QvbVjsG1*`j9%B?VZ1##uVOJ^04Z#n1%PkY&C7w~;WySTj?p)p^D{ zG9M0ptNp^y1yrp|PxOBkpy$G{>6un$Ph-a2HvjT`S>*cjfKg!V&!9%If)R_aZi;t* zu8**gLyF2XG`0;cZ1g^mfVRsY*s+RtQm5njWdjkNUOQw6b-qtU04j+?sI-=|cO`ap zZlG~5%sGgjv{Rx+uL7kZu$#RLv1-J!%n~Z=Po_=J-s7LWdaHTtl|ULS`PA!YobsJQgyv^={VLulAz{*%Bxufqpr%8FB(!b>-1B7zW zo({gH1nok<26uE~Rz{h3j!L>r5!B1_BdMW6SI}L)lHjp28o?9+>ZMpCt!~+Jr7Zl2 z<9JFgXqQf%YM(&JQY$;! zYvhH&!dNWm|J}gnQz&{aZ;G+$-#fmUx);qr7<90~t~Tc^ZvckTl@@+!5!7vqZIr=b zVEzwC=?_7X0Sz=XlBrPIk72ivRGOsc@#CIf5s_`uq+VE)y zy}XMhCZL>gd9B###U!VXJ7l2$)CYdR{*fDq+znK71X#)IeR3PEwd~C>g5_#|!AN!V zx`&L@oe>ohg#W@V5Fk6^Zw8O)p^Nw>`#S!61J4+osFWFzsN!&%8VAwN(8SOLK|Q7i z@?x(Y?*|gkCciKH#+d8VG1`ay(9o!yf<~2cY1NM)Lxa7o9GYjQX+G)6~XcX$$pdTZG07itx zinc%6FBmG%-UW{%-#DhN+TotwKq(0>f>1k9t-wl9jUm5{+$o!){pe>!rny=oWC1Sz zPfpv1qAt=Q^spbZ&Q{JpN|n6W;No`;?2a2o44(I-kXMeE zl6Kj6h>!qU$7A8<(Lq4qsu8#Y$@aq3M(%>9KV?7MhmUWk*Dw;(_T6XFJ6`?q;Y{u% zHwgiX2C?1?GA)3qPI(11W}dyMwo*mZw~X#+a~K8nih| zuvKTe9DKjKCXE#&z#tQ?!$fXKU+Ia;d2&XhA}SRzTjRNky|#Hk+vx)?95n!q5Iz&6Fhjhg1w1|Js1uWW-2 zI38OsK)we6%t+J39g{^jI&JUY z0)fmn9^yL8B401dcd-Or3QkE!JO$bt?xPt!AG1C42o~q}) zoZlk~_I+V{sS2sqfs&RHe{yR51*yuqF>NjK7OpX#=boScGbo1FD5bG;+$kuR$Z{}2 zdapu?c>0D|Pqym4RuT86W^HwYe;Qus?I~d^aL9ShqAI(k$Hd@jhSH!q^;2n9!HC=@ zNE}Gvjn}moah_#yX#k&{SBBOMOp(eE8jJ4=fH3GnyDwBDRrnu~nzPRzsx0B9EdS|Z zpkXe;MrDtYq{>!rvicF2mFym-2HtD(i+5pDA(UB6!Vc3F?_UcBF~ob~FXeTW*wiHg zRGI*DwfV9TSIdiyce$}NU}W=QB_K+5H|<^g&sv!uE!_irA!yH(Hl>qxs4#aFrFfvr zG^mT~4e$H~*^QHm2X|U;ZyiK}IJhhAd%zj~)~&_HdmImIaN_@HosJ$?7&|5@4%P1i-kGH#V5lUCHc5Mv2aJYWyT^gtJ-g zc`&A2h1|QfV{$xny?bep-xF*ZvE7>1-BE410`zV!czWqc79%iZk5+ofFVjnjl^CLi zaSagTJagW+!5h#Myr1~Y1TuA?fZ?oTmfefjdT2Crra#5DdN5PrAL6{iW9==@@Vp~- z(IDZjtrN3fT$sX41U?UYDs{l6GX0`;h+L}QhR*#v3r5zP+)eiYrhG3Msd+J3g{bRu zf~hCzNegLx(r(nBUWHOpRe&t+&p@@6YcIaL?BnPl&=anDjyZgVYT8@6BEjB zKzH#NLSZ|R&kH7kNC_0UDO>vn}VOOxT! zO4#P-ve2`>4WXe;7B6{dW1&t>XTQgswRW~pz+KS*MDmcG*Ytgu(-veH#kzj%_K4j z6aIsh6O&$*k^-s7DogAnXVUs(=5K$j%3tcBbMMKd02RG@-0k-e9Q&4DN8bv686sUD z&Gf&?_=eex`CsF#t98#kt26%Y$+`{r2+Z0gunh0}PmKZkw(@?A~*U-Sh4M3t8SP2%6-{kcDRL7IdJyy$SsIs7QeMf|l{ZD3Bu@=(O*{y8d8Jmr|XVMn> zrb6jH-Qi#^M>!ynS8uFnR*M)V`Njsi)5MTyjjTDP+JfO?!Xy^pc;M;#dF370H+^QUQND;DNqT`qy&(H>FAOQ zwuYR-!Uoho*PL!G1kv|ZH`ox7xHQ2&?WZ@}jDUCHiQn{(?puc~ADHhsCm(wN^>y3< z16(ZVshK{8j$j?gSJc8pMQVNby&zT;;!dMz_^)L{|uP zPX2|j2X3ojQA1|%vaip+gqZzu#vG~dKZf$-6enz4-BNsRkX?$Gs~h2zO>4ndQclT*7WWs9=9r{oWz>wfNl@|Ba}Qq~r{WM-WZk%zvx&%{M&RS1iUr~j>lfG6Zdim( z$CTUf)C_IeNXcil^E>i4ZX&8PDMJ|36_A-$`-%z&4M1R8X<}U6W&M@))zM*e5vAJT z>|lVqH|9svln|~yslQ-FQVPKkmbHo+xFt=J>0`u$72(E8Q*CeUq2klv^jy8x62WMD zN!)faDL-_GrCsSII}bJ$1z*EEmRr^479J~6Xu{m&dr_T?-;&q1X=2eK`^2nKT$B;k z-(EOO*d1bc>og~ob?2b;*l56G8M3TA8^+8|bshnit-Fov+Oce}V*DT!E|t0(0ksR{ zYIrUUWPsU=ntNY4OynIHn0FPxgzvF7!}JX8@w(m3r2t9UHz`ekmDTkltc?g1EdTO) z)JbR~JR(*}wvl$~s@14SH-J3I9M)bd<5Eii76n8k}G8Q z)HpcB>Dk;o`=Nu(TzQkz?hP&jLstH0JXcK)+*h|dMA}l=%0E=a zFTq6L26m5>bF55aWlt2kPud(@Q-5$}Z!zuY`BlHpr+6mQ0YvcC=ZgcmwC zEqz^*7I$YUi#v2}8htYTD3+dZ7>EnrI&KYntjt!>fBj;+^4;WqbAGHruq76Md3};n zHMZ-hEUp?iZdBXP)hTh?5FUR=EU}6>F93=MwS(E2;`iv}YJj~U!gPhJetTz-S52BZ z$lPQQ9tX2C%+d$V!F$CttiO57ePC?C(Vl*k1|PAmB{--Weo~5NT*pDMuugYj-`sUb z0Z{-{Y4!)#x0GXg{gCmZQfQakuh&f;_5hfl7NOcY*lU`eIq#Bt9F5O;?Kk!}74&AF z@kX6oqJ*~2M9zW_U!h1V7032l9$-MOK^wNONRQ33PjjZsBAbcMh*kkKS|}_i^{Pt9 z!m#Q|Xb{OyVFd48&R+M)8XQ68@4QP=E~-mYuWj>%{(Hg~!PSpamnrhb508!f?gF%| zyAFnroj?ktiKc-sCpP5?+DSQ!B43|q{|%CMn)Ic`s_V~l*#GtVmi-?83S6x)h_L3O z+-I5Z%s?Tu?;jIN{NOta_?Ffi8EkTYPko^w#3iV-n9PU)N0)hmbWZ9p#LvCQ3L+D7 zn23gJN)sZ+U?{Df(}#$`joN*beWe0nD1Obv(#Us|m8!O7+btq1E$Tq3np51eSf`uv z@n$=|BNZo#fsznku`jI@U)x8;T4>5{`@9=A!W@=j&0Zgo(7Ezy{6cz zSUr8OTA4CK9@Cm>>sG1hU7dkGFt-;cuDN0Hu-nO(MCo@{*)71PfAMzn2XhY%vAXj` zde*Kn5olW-^&SVt=*Vg(iecH<;}}T^^Tno$m>Ad@upe~y6qMFyk>Bwai-s3G{ENSJ zaP(GtC%T4OXJOPx3joVQpWGoVr&N0tS2DE=#B8}*7e$$mUa-FZ5d2u-@M#*@>Gc{K zU!8F#=l{gYKL8@}=~3EvB{fsHd?evu2$o&3Go(q~CGmRjUX&dAKp?#8^LP{N9akt; z30=0zKH*!V*(wURy}A^T-`@1SiYRUO1$Y_9)0w#%!yT8n>t!j&xH0Y78?ykOvu2=w zC@sMXYA$EI&DZap-hcstfSlG!MxIM`3{n}WrF67T1z=P07u!L%w=|@LV(Fz#&L|1H zavsd^zcGq8Jg| z;bxf~S{EjZmH5A#HHGu6tGirq1_csYaZ6g|q_6yGxu|ID%MX?q%KJI9-;h^hc!}{U z>aYIXz`87fL~LarZ3!LtcZSqgl&ENG0pARdw201ONzwn%JvAny|Ke5PS%fX9#L7Xh|LJxpAW0XS(O?V4=(B1_ z`{kpelo!p*_2duCQF`o*c=B>Gst2|G0jleLiFl0ONr@6^<;I{RwD*BxtU5D-cSA38 zo&-Ys!gRjqu;}jMgl)>*z=Ga!&;wWSOo@XJWOT`7v87)_9npQJVmR!)1}Fe{u#jHl zV0RSgsg*WvuD2{(>?rh)y%{tFk!g;!g!>k61PE|`xyxCBD+*K7fUE`|k) zaxQSGg?hx`a>Re}Rti$`g*9t=p?_n9lVHQo{7(|(2i9p?tl&=rNT3y;?`nAQeWS^Y zhjE}76OjJ{3z&5g9wQ8b@3&b20?h;|hCmi4c=OrCWH%B?7m@Uq;41jPe!3G7x3 z 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 i35$EfB*mtz_Mlv0Y%AmqyPY_4BrI+ literal 0 HcmV?d00001 diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig old mode 100755 new mode 100644 index 973373e61608..b5f1b53c9929 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig @@ -1,6 +1,27 @@ -# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2023, Broadcom. +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to you +# under the terms of the GNU General Public License version 2 (the "GPL"), +# available at http://www.broadcom.com/licenses/GPLv2.php, with the +# following added to such license: +# +# As a special exception, the copyright holders of this software give you +# permission to link this software with independent modules, and to copy and +# distribute the resulting executable under terms of your choice, provided that +# you also meet, for each linked independent module, the terms and conditions of +# the license of that module. An independent module is a module which is not +# derived from this software. The special exception does not apply to any +# modifications of the software. +# +# +# <> +# + config BCMDHD tristate "Broadcom FullMAC wireless cards support" + default m help This module adds support for wireless adapters based on Broadcom FullMAC chipset. @@ -51,7 +72,6 @@ choice config BCMDHD_OOB depends on BCMDHD && BCMDHD_SDIO bool "Out-of-Band Interrupt" - default y help Interrupt from WL_HOST_WAKE. config BCMDHD_SDIO_IRQ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile old mode 100755 new mode 100644 index efc77d7ffae0..3dc1e81d3520 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile @@ -1,8 +1,27 @@ -# SPDX-License-Identifier: GPL-2.0 # bcmdhd +# +# Copyright (C) 2023, Broadcom. +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to you +# under the terms of the GNU General Public License version 2 (the "GPL"), +# available at http://www.broadcom.com/licenses/GPLv2.php, with the +# following added to such license: +# +# As a special exception, the copyright holders of this software give you +# permission to link this software with independent modules, and to copy and +# distribute the resulting executable under terms of your choice, provided that +# you also meet, for each linked independent module, the terms and conditions of +# the license of that module. An independent module is a module which is not +# derived from this software. The special exception does not apply to any +# modifications of the software. +# +# +# <> +# MODULE_NAME := bcmdhd -CONFIG_BCMDHD ?= m +CONFIG_AP6XXX ?= m #CONFIG_BCMDHD_SDIO := y #CONFIG_BCMDHD_PCIE := y @@ -14,47 +33,52 @@ CONFIG_BCMDHD_OOB := y CONFIG_BCMDHD_PROPTXSTATUS := y CONFIG_BCMDHD_AG := y CONFIG_DHD_USE_STATIC_BUF := y -#CONFIG_BCMDHD_STATIC_BUF_IN_DHD := y -CONFIG_BCMDHD_ANDROID_VERSION := 12 +CONFIG_BCMDHD_STATIC_BUF_IN_DHD := y +CONFIG_BCMDHD_ANDROID_VERSION := 14 CONFIG_BCMDHD_AUTO_SELECT := y CONFIG_BCMDHD_DEBUG := y +#CONFIG_BCMDHD_RECONNECT := y #CONFIG_BCMDHD_TIMESTAMP := y #CONFIG_BCMDHD_WAPI := y #CONFIG_BCMDHD_RANDOM_MAC := y CONFIG_BCMDHD_REQUEST_FW := y -#CONFIG_BCMDHD_MULTIPLE_DRIVER := y +#CONFIG_BCMDHD_FW_SIGNATURE := y #CONFIG_BCMDHD_DWDS := y CONFIG_BCMDHD_TPUT := y +#CONFIG_BCMDHD_MULTIPLE_DRIVER := y +#CONFIG_BCMDHD_ADAPTER_INDEX := 0 + CONFIG_MACH_PLATFORM := y #CONFIG_BCMDHD_DTS := y -DHDCFLAGS = -Wall -Wstrict-prototypes -Wno-date-time \ - -Wno-implicit-fallthrough -Wno-declaration-after-statement \ - -Wno-vla -Wno-vla-extension \ - -Dlinux -DLINUX -DBCMDRIVER \ +DHDCFLAGS = -Wall -Wstrict-prototypes -Wno-date-time -Wno-strict-prototypes \ + -Wno-uninitialized -Wno-unused-but-set-variable -Wno-address \ + -Dlinux -DLINUX -DBCMDRIVER -DBCMUTILS_ERR_CODES \ -DBCMDONGLEHOST -DBCMDMA32 -DBCMFILEIMAGE \ -DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DGET_OTP_MAC_ENABLE \ -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DSUPPORT_PM2_ONLY \ + -DPKTPRIO_OVERRIDE \ -DKEEP_ALIVE -DPKT_FILTER_SUPPORT -DDHDTCPACK_SUPPRESS \ -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -DOEM_ANDROID \ -DMULTIPLE_SUPPLICANT -DTSQ_MULTIPLIER -DMFP -DDHD_8021X_DUMP \ -DPOWERUP_MAX_RETRY=0 -DIFACE_HANG_FORCE_DEV_CLOSE -DWAIT_DEQUEUE \ - -DUSE_NEW_RSPEC_DEFS -DBCM_USE_PLATFORM_STRLCPY \ + -DUSE_NEW_RSPEC_DEFS \ -DWL_EXT_IAPSTA -DWL_ESCAN -DCCODE_LIST -DSUSPEND_EVENT \ - -DEAPOL_RESEND -DEAPOL_DYNAMATIC_RESEND -DWL_SCHED_SCAN \ - -DENABLE_INSMOD_NO_FW_LOAD -Wframe-larger-than=2048 \ - -DSCHED_SCAN_DELAYED_WORK -DDHD_PNO_FLAG + -DKEY_INSTALL_CHECK \ + -DENABLE_INSMOD_NO_FW_LOAD -DHDOFILES = aiutils.o siutils.o sbutils.o bcmutils.o bcmwifi_channels.o \ +DHDOFILES = aiutils.o siutils.o sbutils.o \ + bcmutils.o bcmwifi_channels.o bcmxtlv.o bcm_app_utils.o bcmstdlib_s.o \ dhd_linux.o dhd_linux_platdev.o dhd_linux_sched.o dhd_pno.o \ dhd_common.o dhd_ip.o dhd_linux_wq.o dhd_custom_gpio.o \ bcmevent.o hndpmu.o linux_osl.o wldev_common.o wl_android.o \ dhd_debug_linux.o dhd_debug.o dhd_mschdbg.o dhd_dbg_ring.o \ - hnd_pktq.o hnd_pktpool.o bcmxtlv.o linux_pkt.o bcmstdlib_s.o frag.o \ - dhd_linux_exportfs.o dhd_linux_pktdump.o dhd_mschdbg.o \ + hnd_pktq.o hnd_pktpool.o linux_pkt.o frag.o \ + dhd_linux_exportfs.o dhd_linux_pktdump.o dhd_mschdbg.o linuxerrmap.o \ + dhd_linux_tx.o dhd_linux_rx.o fwpkg_utils.o \ dhd_config.o dhd_ccode.o wl_event.o wl_android_ext.o \ - wl_iapsta.o wl_escan.o + wl_iapsta.o wl_escan.o wl_timer.o ifneq ($(CONFIG_WIRELESS_EXT),) DHDOFILES += wl_iw.o @@ -63,39 +87,49 @@ endif ifneq ($(CONFIG_CFG80211),) DHDOFILES += wl_cfg80211.o wl_cfgscan.o wl_cfgp2p.o DHDOFILES += wl_linux_mon.o wl_cfg_btcoex.o wl_cfgvendor.o - DHDOFILES += dhd_cfg80211.o wl_cfgvif.o + DHDOFILES += dhd_cfg80211.o wl_cfgvif.o wl_roam.o DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT -# DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS + DHDCFLAGS += -DWL_CFG80211_GON_COLLISION + DHDCFLAGS += -DWL_CAP_HE -DWL_6G_BAND -DWL_5P9G +# DHDCFLAGS += -DCONFIG_6GHZ_BKPORT + DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES DHDCFLAGS += -DESCAN_RESULT_PATCH -DESCAN_BUF_OVERFLOW_MGMT DHDCFLAGS += -DVSDB -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST DHDCFLAGS += -DWLTDLS -DMIRACAST_AMPDU_SIZE=8 - DHDCFLAGS += -DWL_VIRTUAL_APSTA - DHDCFLAGS += -DPNO_SUPPORT -DEXPLICIT_DISCIF_CLEANUP +# DHDCFLAGS += -DHOSTAPD_BW_SUPPORT + DHDCFLAGS += -DWL_VIRTUAL_APSTA -DSTA_MGMT -DSOFTAP_UAPSD_OFF + DHDCFLAGS += -DWL_SOFTAP_ACS + DHDCFLAGS += -DNUM_SCB_MAX_PROBE=3 + DHDCFLAGS += -DWL_SCB_TIMEOUT=10 + DHDCFLAGS += -DEXPLICIT_DISCIF_CLEANUP DHDCFLAGS += -DDHD_USE_SCAN_WAKELOCK DHDCFLAGS += -DSPECIFIC_MAC_GEN_SCHEME DHDCFLAGS += -DWL_IFACE_MGMT - DHDCFLAGS += -DWLFBT -DWL_GCMP_SUPPORT - DHDCFLAGS += -DWL_EXT_RECONNECT - DHDCFLAGS += -DDHD_LOSSLESS_ROAMING + DHDCFLAGS += -DSUPPORT_RSSI_SUM_REPORT + DHDCFLAGS += -DWLFBT -DWL_GCMP_SUPPORT -DWL_OWE -DWL_SAE_FT + DHDCFLAGS += -DROAM_CHANNEL_CACHE -DDHD_LOSSLESS_ROAMING +# DHDCFLAGS += -DWL_CFGVENDOR_SEND_HANG_EVENT DHDCFLAGS += -DGTK_OFFLOAD_SUPPORT - DHDCFLAGS += -DRESTART_AP_WAR -# DHDCFLAGS += -DWL_STATIC_IF - DHDCFLAGS += -DWL_CLIENT_SAE -DWL_OWE + #DHDCFLAGS += -DWL_STATIC_IF #-DDHD_MAX_STATIC_IFS=2 + DHDCFLAGS += -DWL_CLIENT_SAE + DHDCFLAGS += -DCONNECT_INFO_WAR -DWL_ROAM_WAR + DHDCFLAGS += -DVNDR_IE_WAR + DHDCFLAGS += -DRESTART_AP_WAR -DRXF0OVFL_REINIT_WAR endif #BCMDHD_SDIO ifneq ($(CONFIG_BCMDHD_SDIO),) -BUS_TYPE := "sdio" -DHDCFLAGS += -DBCMSDIO -DMMC_SDIO_ABORT -DMMC_SW_RESET -DBCMLXSDMMC \ - -DUSE_SDIOFIFO_IOVAR -DSDTEST \ - -DBDC -DDHD_USE_IDLECOUNT -DCUSTOM_SDIO_F2_BLKSIZE=256 \ - -DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT -DRXFRAME_THREAD \ - -DDHDENABLE_TAILPAD -DSUPPORT_P2P_GO_PS \ +BUS_TYPE := sdio +DHDCFLAGS += -DBCMSDIO -DMMC_SDIO_ABORT -DUSE_SDIOFIFO_IOVAR -DBCMLXSDMMC \ + -DSDTEST -DBDC -DDHD_USE_IDLECOUNT -DCUSTOM_SDIO_F2_BLKSIZE=256 \ + -DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT -DBCMSDIOH_STATIC_COPY_BUF \ + -DRXFRAME_THREAD -DDHDENABLE_TAILPAD -DSUPPORT_P2P_GO_PS \ -DBCMSDIO_RXLIM_POST -DBCMSDIO_TXSEQ_SYNC -DCONSOLE_DPC \ -DBCMSDIO_INTSTATUS_WAR +DHDCFLAGS += -DMMC_HW_RESET #-DMMC_SW_RESET #-DBUS_POWER_RESTORE ifeq ($(CONFIG_BCMDHD_OOB),y) DHDCFLAGS += -DOOB_INTR_ONLY -DCUSTOMER_OOB -DHW_OOB ifeq ($(CONFIG_BCMDHD_DISABLE_WOWLAN),y) @@ -110,15 +144,24 @@ endif #BCMDHD_PCIE ifneq ($(CONFIG_BCMDHD_PCIE),) -BUS_TYPE := "pcie" -DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1 \ - -DDONGLE_ENABLE_ISOLATION -DHDCFLAGS += -DDHD_LB -DDHD_LB_RXP -DDHD_LB_STATS -DDHD_LB_TXP -#DHDCFLAGS += -DDHD_PKTID_AUDIT_ENABLED -DHDCFLAGS += -DINSMOD_FW_LOAD -DHDCFLAGS += -DCHIP_INTR_CONTROL -#DHDCFLAGS += -DDHD_PCIE_RUNTIMEPM -DMAX_IDLE_COUNT=11 -DCUSTOM_DHD_RUNTIME_MS=100 -DHDCFLAGS += -DDHD_CONTROL_PCIE_ASPM_WIFI_TURNON +BUS_TYPE := pcie + DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1 + DHDCFLAGS += -DDONGLE_ENABLE_ISOLATION + DHDCFLAGS += -DDHD_LB -DDHD_LB_RXP -DDHD_LB_STATS -DDHD_LB_TXP + DHDCFLAGS += -DDHD_LB_PRIMARY_CPUS=0xF0 -DDHD_LB_SECONDARY_CPUS=0x0E +# DHDCFLAGS += -DDHD_PKTID_AUDIT_ENABLED + DHDCFLAGS += -DEAPOL_PKT_PRIO -DENABLE_DHD_GRO + DHDCFLAGS += -DDHD_SKIP_DONGLE_RESET_IN_ATTACH + DHDCFLAGS += -DDHD_DONGLE_TRAP_IN_DETACH + DHDCFLAGS += -DFORCE_DONGLE_RESET_IN_DEVRESET_ON + DHDCFLAGS += -DDHD_USE_COHERENT_MEM_FOR_RING + DHDCFLAGS += -DCHECK_TRAP_ROT + DHDCFLAGS += -DINSMOD_FW_LOAD + DHDCFLAGS += -DCONFIG_HAS_WAKELOCK #-DDHD_DEBUG_WAKE_LOCK + DHDCFLAGS += -DDHD_PACKET_TIMEOUT_MS=50 -DMAX_TX_TIMEOUT=50 +ifeq ($(CONFIG_AP6XXX),y) + DHDCFLAGS += -DWAKEUP_KSOFTIRQD_POST_NAPI_SCHEDULE +endif ifeq ($(CONFIG_BCMDHD_OOB),y) DHDCFLAGS += -DCUSTOMER_OOB -DBCMPCIE_OOB_HOST_WAKE -DHW_OOB endif @@ -131,10 +174,16 @@ endif #BCMDHD_USB ifneq ($(CONFIG_BCMDHD_USB),) -BUS_TYPE := "usb" +BUS_TYPE := usb DHDCFLAGS += -DUSBOS_TX_THREAD -DBCMDBUS -DBCMTRXV2 -DDBUS_USB_LOOPBACK \ -DBDC -DHDCFLAGS += -DBCM_REQUEST_FW -DEXTERNAL_FW_PATH +DHDCFLAGS += -DINSMOD_FW_LOAD +DHDCFLAGS += -DBCM_REQUEST_FW +DHDCFLAGS += -DSHOW_LOGTRACE +DHDCFLAGS += -DWL_EXT_WOWL +ifneq ($(CONFIG_BCMDHD_REQUEST_FW),y) + DHDCFLAGS += -DEXTERNAL_FW_PATH +endif ifneq ($(CONFIG_BCMDHD_CUSB),) DHDCFLAGS += -DBCMUSBDEV_COMPOSITE CONFIG_BCMDHD_NO_POWER_OFF := y @@ -149,9 +198,17 @@ endif ifeq ($(CONFIG_BCMDHD_MULTIPLE_DRIVER),y) DHDCFLAGS += -DBCMDHD_MDRIVER +ifneq ($(CONFIG_BCMDHD_ADAPTER_INDEX),) + CONFIG_BCMDHD_STATIC_BUF_IN_DHD := y + MODULE_NAME := dhd$(BUS_TYPE)_$(CONFIG_BCMDHD_ADAPTER_INDEX) + DHDCFLAGS += -DADAPTER_IDX=$(CONFIG_BCMDHD_ADAPTER_INDEX) + DHDCFLAGS += -DBUS_TYPE=\"-$(BUS_TYPE)-$(CONFIG_BCMDHD_ADAPTER_INDEX)\" + DHDCFLAGS += -DDHD_LOG_PREFIX=\"[dhd-$(BUS_TYPE)-$(CONFIG_BCMDHD_ADAPTER_INDEX)]\" +else + MODULE_NAME := dhd$(BUS_TYPE) DHDCFLAGS += -DBUS_TYPE=\"-$(BUS_TYPE)\" DHDCFLAGS += -DDHD_LOG_PREFIX=\"[dhd-$(BUS_TYPE)]\" - MODULE_NAME := dhd$(BUS_TYPE) +endif else DHDCFLAGS += -DBUS_TYPE=\"\" endif @@ -165,9 +222,11 @@ endif ifeq ($(CONFIG_BCMDHD_PROPTXSTATUS),y) ifneq ($(CONFIG_BCMDHD_USB),) DHDCFLAGS += -DPROP_TXSTATUS + DHDCFLAGS += -DLIMIT_BORROW -DBULK_DEQUEUE endif ifneq ($(CONFIG_BCMDHD_SDIO),) DHDCFLAGS += -DPROP_TXSTATUS -DPROPTX_MAXCOUNT + DHDCFLAGS += -DLIMIT_BORROW -DBULK_DEQUEUE endif ifneq ($(CONFIG_CFG80211),) DHDCFLAGS += -DPROP_TXSTATUS_VSDB @@ -183,18 +242,22 @@ endif ifneq ($(CONFIG_BCMDHD_ANDROID_VERSION),) DHDCFLAGS += -DANDROID_VERSION=$(CONFIG_BCMDHD_ANDROID_VERSION) DHDCFLAGS += -DDHD_NOTIFY_MAC_CHANGED + DHDCFLAGS += -DANDROID_BKPORT ifneq ($(CONFIG_CFG80211),) - DHDCFLAGS += -DGSCAN_SUPPORT -DRTT_SUPPORT - DHDCFLAGS += -DWL_SAR_TX_POWER -# DHDCFLAGS += -DLINKSTAT_SUPPORT - DHDCFLAGS += -DCUSTOM_COUNTRY_CODE -DDHD_GET_VALID_CHANNELS - DHDCFLAGS += -DDEBUGABILITY -DDBG_PKT_MON -# DHDCFLAGS += -DDHD_LOG_DUMP - DHDCFLAGS += -DDHD_FW_COREDUMP + DHDCFLAGS += -DPNO_SUPPORT + DHDCFLAGS += -DWL_SCHED_SCAN DHDCFLAGS += -DWL_P2P_RAND + DHDCFLAGS += -DGSCAN_SUPPORT -DRTT_SUPPORT + DHDCFLAGS += -DLINKSTAT_SUPPORT -DLINKSTAT_EXT_SUPPORT + DHDCFLAGS += -DCUSTOM_COUNTRY_CODE -DDHD_GET_VALID_CHANNELS + DHDCFLAGS += -DDEBUGABILITY -DDEBUGABILITY_DISABLE_MEMDUMP -DDBG_PKT_MON + DHDCFLAGS += -DDHD_LOG_DUMP -DDHD_FW_COREDUMP +# DHDCFLAGS += -DDHD_PKT_LOGGING_DBGRING DHDCFLAGS += -DAPF -DNDO_CONFIG_SUPPORT -DRSSI_MONITOR_SUPPORT - DHDCFLAGS += -DDHD_WAKE_STATUS -DWL_LATENCY_MODE - DHDOFILES += dhd_rtt.o bcm_app_utils.o + DHDCFLAGS += -DDHD_WAKE_STATUS + DHDCFLAGS += -DWL_LATENCY_MODE + DHDOFILES += dhd_rtt.o + DHDOFILES += dhd_log_dump.o endif else DHDCFLAGS += -DANDROID_VERSION=0 @@ -210,6 +273,7 @@ ifeq ($(CONFIG_BCMDHD_DEBUG),y) DHDCFLAGS += -DPKT_STATICS DHDCFLAGS += -DKSO_DEBUG # DHDCFLAGS += -DDHD_PKTDUMP_TOFW +# DHDCFLAGS += -DDHD_DUMP_FILE_WRITE_FROM_KERNEL endif # For Debug2 @@ -221,11 +285,15 @@ ifneq ($(CONFIG_BCMDHD_PCIE),) DHDCFLAGS += -DEWP_EDL DHDCFLAGS += -DDNGL_EVENT_SUPPORT DHDCFLAGS += -DDHD_SSSR_DUMP + DHDCFLAGS += -DDHD_MEM_STATS + DHDCFLAGS += -DDHD_FLOW_RING_STATUS_TRACE + DHDCFLAGS += -DDNGL_AXI_ERROR_LOGGING endif + DHDOFILES += dhd_log_dump.o endif # MESH support for kernel 3.10 later -ifeq ($(CONFIG_WL_MESH),y) +ifeq ($(CONFIG_BCMDHD_WLMESH),y) DHDCFLAGS += -DWLMESH ifneq ($(CONFIG_CFG80211),) DHDCFLAGS += -DWLMESH_CFG80211 @@ -253,7 +321,7 @@ ifneq ($(CONFIG_CFG80211),) ifneq ($(CONFIG_BCMDHD_SDIO),) DHDCFLAGS += -DRXF_DEQUEUE_ON_BUSY endif - DHDCFLAGS += -DWL_STATIC_IF + #DHDCFLAGS += -DWL_STATIC_IF endif endif @@ -263,10 +331,19 @@ ifeq ($(CONFIG_CSI_SUPPORT),y) DHDOFILES += dhd_csi.o endif +# For CONNECTION_IMPROVE +ifeq ($(CONFIG_BCMDHD_RECONNECT),y) + DHDCFLAGS += -DEAPOL_RESEND -DEAPOL_RESEND_M4 +ifneq ($(CONFIG_CFG80211),) + DHDCFLAGS += -DWL_EXT_RECONNECT -DWL_REASSOC_BCAST + DHDCFLAGS += -DWL_EXT_DISCONNECT_RECONNECT +endif +endif + # For TPUT_IMPROVE ifeq ($(CONFIG_BCMDHD_TPUT),y) DHDCFLAGS += -DDHD_TPUT_PATCH - DHDCFLAGS += -DTCPACK_INFO_MAXNUM=10 -DTCPDATA_INFO_MAXNUM=10 + DHDCFLAGS += -DTCPACK_INFO_MAXNUM=40 -DTCPDATA_INFO_MAXNUM=40 ifneq ($(CONFIG_BCMDHD_SDIO),) DHDCFLAGS += -DDYNAMIC_MAX_HDR_READ DHDCFLAGS :=$(filter-out -DSDTEST,$(DHDCFLAGS)) @@ -301,20 +378,29 @@ endif # For NAN ifneq ($(CONFIG_BCMDHD_NAN),) - DHDCFLAGS += -DWL_NAN -DWL_NAN_DISC_CACHE + DHDCFLAGS += -DWL_NAN -DWL_NAN_DISC_CACHE -DWL_NANP2P -DWL_NAN_ENABLE_MERGE DHDOFILES += wl_cfgnan.o bcmbloom.o endif # For Module auto-selection ifeq ($(CONFIG_BCMDHD_AUTO_SELECT),y) DHDCFLAGS += -DUPDATE_MODULE_NAME +ifeq ($(CONFIG_BCMDHD_REQUEST_FW),y) +# DHDCFLAGS += -DFW_AMPAK_PATH="\"ampak\"" +# DHDCFLAGS += -DMODULE_PATH +endif ifneq ($(CONFIG_BCMDHD_SDIO),) DHDCFLAGS += -DGET_OTP_MODULE_NAME -DCOMPAT_OLD_MODULE endif endif +ifeq ($(CONFIG_AP6XXX),y) + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC + DHDCFLAGS += -DBCM_USE_PLATFORM_STRLCPY +endif ifeq ($(CONFIG_AP6XXX),m) DHDCFLAGS += -DBCMDHD_MODULAR + DHDCFLAGS += -DBOARD_MODULAR_INIT endif ifeq ($(CONFIG_MACH_PLATFORM),y) @@ -324,19 +410,36 @@ ifeq ($(CONFIG_BCMDHD_DTS),y) endif DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT DHDCFLAGS += -DCUSTOMER_HW_ROCKCHIP +# DHDCFLAGS += -DCUSTOMER_HW_ROCKCHIP_RK3588 + DHDCFLAGS += -DBCM_USE_PLATFORM_STRLCPY +endif + +ifneq ($(CONFIG_BCMDHD_PCIE),) +ifneq ($(filter -DCUSTOMER_HW_ROCKCHIP_RK3588, $(DHDCFLAGS)),) + DHDCFLAGS += -DDHD_CONTROL_PCIE_ASPM_WIFI_TURNON +endif endif ifeq ($(CONFIG_BCMDHD_REQUEST_FW),y) DHDCFLAGS += -DDHD_LINUX_STD_FW_API + DHDCFLAGS += -DDHD_REQUEST_FW_PATH DHDCFLAGS += -DDHD_FW_NAME="\"fw_bcmdhd.bin\"" DHDCFLAGS += -DDHD_NVRAM_NAME="\"nvram.txt\"" DHDCFLAGS += -DDHD_CLM_NAME="\"clm_bcmdhd.blob\"" + DHDCFLAGS += -DDHD_CONFIG_NAME="\"config.txt\"" else + DHDCFLAGS += -DDHD_SUPPORT_VFS_CALL ifeq ($(CONFIG_BCMDHD_FW_PATH),) - DHDCFLAGS += -DCONFIG_BCMDHD_FW_PATH="\"/system/etc/firmware/fw_bcmdhd.bin\"" - DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH="\"/system/etc/firmware/nvram.txt\"" - DHDCFLAGS += -DCONFIG_BCMDHD_CLM_PATH="\"/system/etc/firmware/clm_bcmdhd.blob\"" + DHDCFLAGS += -DCONFIG_BCMDHD_FW_PATH="\"/vendor/etc/firmware/fw_bcmdhd.bin\"" + DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH="\"/vendor/etc/firmware/nvram.txt\"" + DHDCFLAGS += -DCONFIG_BCMDHD_CLM_PATH="\"/vendor/etc/firmware/clm_bcmdhd.blob\"" endif + DHDCFLAGS += -DCONFIG_BCMDHD_CONFIG_PATH="\"/vendor/etc/firmware/config.txt\"" +endif + +ifeq ($(CONFIG_BCMDHD_FW_SIGNATURE),y) + DHDCFLAGS += -DFW_SIGNATURE + DHDCFLAGS += -DBL_HEAP_START_GAP_SIZE=0x1000 -DBL_HEAP_SIZE=0x10000 endif ifeq ($(CONFIG_BCMDHD_AG),y) @@ -352,7 +455,12 @@ else endif DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -DENHANCED_STATIC_BUF DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF +ifneq ($(filter -DDHD_LOG_DUMP, $(DHDCFLAGS)),) DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP +endif +ifneq ($(filter -DDHD_FW_COREDUMP, $(DHDCFLAGS)),) + DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP +endif ifneq ($(CONFIG_BCMDHD_PCIE),) DHDCFLAGS += -DDHD_USE_STATIC_CTRLBUF endif @@ -363,8 +471,7 @@ BCMDHD_ROOT = $(src) #$(warning "BCMDHD_ROOT=$(BCMDHD_ROOT)") EXTRA_CFLAGS = $(DHDCFLAGS) EXTRA_CFLAGS += -DDHD_COMPILED=\"$(BCMDHD_ROOT)\" -EXTRA_CFLAGS += -I$(srctree)/$(BCMDHD_ROOT)/include/ -I$(srctree)/$(BCMDHD_ROOT)/ -EXTRA_CFLAGS += $(call cc-disable-warning, unused-but-set-variable) +EXTRA_CFLAGS += -I$(BCMDHD_ROOT)/include/ -I$(BCMDHD_ROOT)/ ifeq ($(CONFIG_AP6XXX),m) EXTRA_LDFLAGS += --strip-debug endif diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/aiutils.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/aiutils.c old mode 100755 new mode 100644 index b8b9555eb105..c3cb8bc2c062 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/aiutils.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/aiutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -52,7 +52,7 @@ static bool ai_get_apb_bridge(const si_t *sih, uint32 coreidx, uint32 *apb_id, uint32 *apb_coreunit); #endif /* AXI_TIMEOUTS_NIC */ -#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) +#if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC) static void ai_reset_axi_to(const si_info_t *sii, aidmp_t *ai); #endif /* defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) */ @@ -169,7 +169,7 @@ get_asd(const si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *ad /* Parse the enumeration rom to identify all cores */ void -BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid) +ai_scan(si_t *sih, void *regs, uint devid) { si_info_t *sii = SI_INFO(sih); si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; @@ -177,6 +177,7 @@ BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid) uint32 erombase, *eromptr, *eromlim; axi_wrapper_t * axi_wrapper = sii->axi_wrapper; + SI_MSG_DBG_REG(("%s: Enter\n", __FUNCTION__)); BCM_REFERENCE(devid); erombase = R_REG(sii->osh, &cc->eromptr); @@ -225,6 +226,7 @@ BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid) cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI); if (cia == (ER_END | ER_VALID)) { SI_VMSG(("Found END of erom after %d cores\n", sii->numcores)); + SI_MSG_DBG_REG(("%s: Exit\n", __FUNCTION__)); return; } @@ -423,6 +425,11 @@ BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid) /* cache APB bridge wrapper address for set/clear timeout */ if ((mfg == MFGID_ARM) && (cid == APB_BRIDGE_ID)) { ASSERT(sii->num_br < SI_MAXBR); + if (sii->num_br >= SI_MAXBR) { + SI_ERROR(("bridge number %d is overflowed\n", sii->num_br)); + goto error; + } + sii->br_wrapba[sii->num_br++] = addrl; } @@ -474,6 +481,7 @@ BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid) error: sii->numcores = 0; + SI_MSG_DBG_REG(("%s: Exit\n", __FUNCTION__)); return; } @@ -612,8 +620,10 @@ BCMPOSTTRAPFN(_ai_setcoreidx)(si_t *sih, uint coreidx, uint use_wrapn) sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); /* point bar0 window */ - ai_corereg(sih, sih->buscoreidx, PCIE_TER_BAR0_WIN, ~0, addr); - ai_corereg(sih, sih->buscoreidx, PCIE_TER_BAR0_WRAPPER, ~0, wrap); + ai_corereg(sih, sih->buscoreidx, + PCIE_TER_BAR0_WIN_REG(sih->buscorerev), ~0, addr); + ai_corereg(sih, sih->buscoreidx, + PCIE_TER_BAR0_WRAPPER_REG(sih->buscorerev), ~0, wrap); break; default: /* other slices */ @@ -643,6 +653,10 @@ BCMPOSTTRAPFN(_ai_setcoreidx)(si_t *sih, uint coreidx, uint use_wrapn) sii->curidx = coreidx; + if (regs) { + SI_MSG_DBG_REG(("%s: %d\n", __FUNCTION__, coreidx)); + } + return regs; } @@ -1755,7 +1769,7 @@ ai_update_backplane_timeouts(const si_t *sih, bool enable, uint32 timeout_exp, u #endif /* AXI_TIMEOUTS || AXI_TIMEOUTS_NIC */ } -#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) +#if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC) /* slave error is ignored, so account for those cases */ static uint32 si_ignore_errlog_cnt = 0; @@ -1824,12 +1838,6 @@ BCMPOSTTRAPFN(ai_ignore_errlog)(const si_info_t *sii, const aidmp_t *ai, extd_axi_id_mask = TRUE; ignore_errsts_2 = AIELS_DECODE; break; -#ifdef USE_HOSTMEM - case BCM43602_CHIP_ID: - axi_id = BCM43602_BT_AXI_ID; - address_check = FALSE; - break; -#endif /* USE_HOSTMEM */ default: return FALSE; } @@ -1946,7 +1954,7 @@ ai_clear_backplane_to_fast(si_t *sih, void *addr) } #endif /* AXI_TIMEOUTS_NIC */ -#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) +#if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC) static bool g_disable_backplane_logs = FALSE; static uint32 last_axi_error = AXI_WRAP_STS_NONE; @@ -2086,11 +2094,6 @@ BCMPOSTTRAPFN(ai_clear_backplane_to_per_core)(si_t *sih, uint coreid, uint coreu case AIELS_DECODE: SI_PRINT(("AXI decode error\n")); -#ifdef USE_HOSTMEM - /* Ignore known cases of CR4 prefetch abort bugs */ - if ((errlog_id & (BCM_AXI_ID_MASK | BCM_AXI_ACCESS_TYPE_MASK)) != - (BCM43xx_AXI_ACCESS_TYPE_PREFETCH | BCM43xx_CR4_AXI_ID)) -#endif { ret |= AXI_WRAP_STS_DECODE_ERR; } @@ -2236,7 +2239,7 @@ uint32 BCMPOSTTRAPFN(ai_clear_backplane_to)(si_t *sih) { uint32 ret = 0; -#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) +#if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC) const si_info_t *sii = SI_INFO(sih); aidmp_t *ai; uint32 i; @@ -2490,7 +2493,7 @@ BCMPOSTTRAPRAMFN(ai_get_wrapper_base_addr)(uint32 **offset) } uint32 -BCMATTACHFN(ai_wrapper_dump_buf_size)(const si_t *sih) +ai_wrapper_dump_buf_size(const si_t *sih) { uint32 buf_size = 0; uint32 wrapper_count = 0; @@ -2539,7 +2542,7 @@ uint32 BCMPOSTTRAPFN(ai_wrapper_dump_last_timeout)(const si_t *sih, uint32 *error, uint32 *core, uint32 *ba, uchar *p) { -#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) +#if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC) uint32 *p32; uint32 wrap_ba = last_axi_error_wrap; uint i; @@ -2590,7 +2593,7 @@ BCMPOSTTRAPFN(ai_wrapper_dump_binary)(const si_t *sih, uchar *p) bool BCMPOSTTRAPFN(ai_check_enable_backplane_log)(const si_t *sih) { -#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) +#if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC) if (g_disable_backplane_logs) { return FALSE; } diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcm_app_utils.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcm_app_utils.c old mode 100755 new mode 100644 index 62d050739ea8..7f8d553b9988 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcm_app_utils.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcm_app_utils.c @@ -3,7 +3,7 @@ * Contents are wifi-specific, used by any kernel or app-level * software that might want wifi things as it grows. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -28,7 +28,9 @@ #ifdef BCMDRIVER #include #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) +#ifndef tolower #define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) +#endif /* tolower */ #else /* BCMDRIVER */ #include #include @@ -40,7 +42,7 @@ #endif /* BCMDRIVER */ #include -#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) +#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL) || defined(_CONSOLE)) #include /* For wlexe/Makefile.wlm_dll */ #endif @@ -109,33 +111,7 @@ cca_info(uint8 *bitmap, int num_bits, int *left, int *bit_pos) static uint8 spec_to_chan(chanspec_t chspec) { - uint8 center_ch, edge, primary, sb; - - center_ch = CHSPEC_CHANNEL(chspec); - - if (CHSPEC_IS20(chspec)) { - return center_ch; - } else { - /* the lower edge of the wide channel is half the bw from - * the center channel. - */ - if (CHSPEC_IS40(chspec)) { - edge = center_ch - CH_20MHZ_APART; - } else { - /* must be 80MHz (until we support more) */ - ASSERT(CHSPEC_IS80(chspec)); - edge = center_ch - CH_40MHZ_APART; - } - - /* find the channel number of the lowest 20MHz primary channel */ - primary = edge + CH_10MHZ_APART; - - /* select the actual subband */ - sb = (chspec & WL_CHANSPEC_CTL_SB_MASK) >> WL_CHANSPEC_CTL_SB_SHIFT; - primary = primary + sb * CH_20MHZ_APART; - - return primary; - } + return wf_chspec_primary20_chan(chspec); } /* @@ -161,7 +137,7 @@ cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chans return BCME_NOMEM; } - memset(bitmap, 0, bitmap_sz); + bzero(bitmap, bitmap_sz); /* Initially, all channels are up for consideration */ for (i = 0; i < num_chans; i++) { if (input[i]->chanspec) @@ -1180,8 +1156,8 @@ wl_cntbuf_to_xtlv_format(void *ctx, void *cntbuf, int buflen, uint32 corerev) } #ifdef BCMDRIVER - wlccnt = MALLOC(osh, sizeof(*wlccnt)); - macstat = MALLOC(osh, WL_CNT_MCST_STRUCT_SZ); + wlccnt = MALLOCZ(osh, sizeof(*wlccnt)); + macstat = MALLOCZ(osh, WL_CNT_MCST_STRUCT_SZ); #else wlccnt = (wl_cnt_wlc_t *)malloc(sizeof(*wlccnt)); macstat = (uint32 *)malloc(WL_CNT_MCST_STRUCT_SZ); @@ -1251,7 +1227,7 @@ wl_cntbuf_to_xtlv_format(void *ctx, void *cntbuf, int buflen, uint32 corerev) xtlv_desc[2].len = 0; xtlv_desc[2].ptr = NULL; - memset(cntbuf, 0, buflen); + bzero(cntbuf, buflen); res = bcm_pack_xtlv_buf_from_mem(&xtlvbuf_p, &xtlvbuflen, xtlv_desc, BCM_XTLV_OPTION_ALIGN32); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcm_l2_filter.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcm_l2_filter.c deleted file mode 100755 index 5a5ca2c1e6d9..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcm_l2_filter.c +++ /dev/null @@ -1,766 +0,0 @@ -/* - * L2 Filter handling functions - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include <802.11.h> -#include - -#ifdef BCMDBG_ERR -#define L2_FILTER_ERROR(args) printf args -#else -#define L2_FILTER_ERROR(args) -#endif /* BCMDBG_ERR */ - -#ifdef BCMDBG_MSG -#define L2_FILTER_MSG(args) printf args -#else -#define L2_FILTER_MSG(args) -#endif /* BCMDBG_msg */ - -struct arp_table { - parp_entry_t *parp_table[BCM_PARP_TABLE_SIZE]; /* proxyarp entries in cache table */ - parp_entry_t *parp_candidate_list; /* proxyarp entries in candidate list */ - uint8 parp_smac[ETHER_ADDR_LEN]; /* L2 SMAC from DHCP Req */ - uint8 parp_cmac[ETHER_ADDR_LEN]; /* Bootp Client MAC from DHCP Req */ -}; -#ifdef DHD_DUMP_ARPTABLE -void bcm_l2_parp_dump_table(arp_table_t* arp_tbl); - -void -bcm_l2_parp_dump_table(arp_table_t* arp_tbl) -{ - parp_entry_t *entry; - uint16 idx, ip_len; - arp_table_t *ptable; - ip_len = IPV4_ADDR_LEN; - ptable = arp_tbl; - for (idx = 0; idx < BCM_PARP_TABLE_SIZE; idx++) { - entry = ptable->parp_table[idx]; - while (entry) { - printf("Cached entries..\n"); - printf("%d: %d.%d.%d.%d", idx, entry->ip.data[0], entry->ip.data[1], - entry->ip.data[2], entry->ip.data[3]); - printf("%02x:%02x:%02x:%02x:%02x:%02x", entry->ea.octet[0], - entry->ea.octet[1], entry->ea.octet[2], entry->ea.octet[3], - entry->ea.octet[4], entry->ea.octet[5]); - printf("\n"); - entry = entry->next; - } - } - entry = ptable->parp_candidate_list; - while (entry) { - printf("Candidate entries..\n"); - printf("%d.%d.%d.%d", entry->ip.data[0], entry->ip.data[1], - entry->ip.data[2], entry->ip.data[3]); - printf("%02x:%02x:%02x:%02x:%02x:%02x", entry->ea.octet[0], - entry->ea.octet[1], entry->ea.octet[2], entry->ea.octet[3], - entry->ea.octet[4], entry->ea.octet[5]); - - printf("\n"); - entry = entry->next; - } -} -#endif /* DHD_DUMP_ARPTABLE */ - -arp_table_t* init_l2_filter_arp_table(osl_t* osh) -{ - return ((arp_table_t*)MALLOCZ(osh, sizeof(arp_table_t))); -} - -void deinit_l2_filter_arp_table(osl_t* osh, arp_table_t* ptable) -{ - MFREE(osh, ptable, sizeof(arp_table_t)); -} -/* returns 0 if gratuitous ARP or unsolicited neighbour advertisement */ -int -bcm_l2_filter_gratuitous_arp(osl_t *osh, void *pktbuf) -{ - uint8 *frame = PKTDATA(osh, pktbuf); - uint16 ethertype; - int send_ip_offset, target_ip_offset; - int iplen; - int minlen; - uint8 *data; - int datalen; - bool snap; - - if (get_pkt_ether_type(osh, pktbuf, &data, &datalen, ðertype, &snap) != BCME_OK) - return BCME_ERROR; - - if (!ETHER_ISBCAST(frame + ETHER_DEST_OFFSET) && - bcmp(ðer_ipv6_mcast, frame + ETHER_DEST_OFFSET, sizeof(ether_ipv6_mcast))) { - return BCME_ERROR; - } - - if (ethertype == ETHER_TYPE_ARP) { - L2_FILTER_MSG(("bcm_l2_filter_gratuitous_arp: ARP RX data : %p: datalen : %d\n", - data, datalen)); - send_ip_offset = ARP_SRC_IP_OFFSET; - target_ip_offset = ARP_TGT_IP_OFFSET; - iplen = IPV4_ADDR_LEN; - minlen = ARP_DATA_LEN; - } else if (ethertype == ETHER_TYPE_IPV6) { - send_ip_offset = NEIGHBOR_ADVERTISE_SRC_IPV6_OFFSET; - target_ip_offset = NEIGHBOR_ADVERTISE_TGT_IPV6_OFFSET; - iplen = IPV6_ADDR_LEN; - minlen = target_ip_offset + iplen; - - /* check for neighbour advertisement */ - if (datalen >= minlen && (data[IPV6_NEXT_HDR_OFFSET] != IP_PROT_ICMP6 || - data[NEIGHBOR_ADVERTISE_TYPE_OFFSET] != NEIGHBOR_ADVERTISE_TYPE)) - return BCME_ERROR; - - /* Dont drop Unsolicitated NA fm AP with allnode mcast dest addr (HS2-4.5.E) */ - if (datalen >= minlen && - (data[IPV6_NEXT_HDR_OFFSET] == IP_PROT_ICMP6) && - (data[NEIGHBOR_ADVERTISE_TYPE_OFFSET] == NEIGHBOR_ADVERTISE_TYPE) && - (data[NEIGHBOR_ADVERTISE_OPTION_OFFSET] == OPT_TYPE_TGT_LINK_ADDR)) { - L2_FILTER_MSG(("Unsolicitated Neighbour Advertisement from AP " - "with allnode mcast dest addr tx'ed (%d)\n", datalen)); - return -1; - } - - } else { - return BCME_ERROR; - } - - if (datalen < minlen) { - L2_FILTER_MSG(("BCM: dhd_gratuitous_arp: truncated packet (%d)\n", datalen)); - return BCME_ERROR; - } - - if (bcmp(data + send_ip_offset, data + target_ip_offset, iplen) == 0) { - L2_FILTER_MSG((" returning BCME_OK in bcm_l2_filter_gratuitous_arp\n")); - return BCME_OK; - } - - return BCME_ERROR; -} -int -get_pkt_ether_type(osl_t *osh, void *pktbuf, - uint8 **data_ptr, int *len_ptr, uint16 *et_ptr, bool *snap_ptr) -{ - uint8 *frame = PKTDATA(osh, pktbuf); - int length = PKTLEN(osh, pktbuf); - uint8 *pt; /* Pointer to type field */ - uint16 ethertype; - bool snap = FALSE; - /* Process Ethernet II or SNAP-encapsulated 802.3 frames */ - if (length < ETHER_HDR_LEN) { - L2_FILTER_MSG(("BCM: get_pkt_ether_type: short eth frame (%d)\n", - length)); - return BCME_ERROR; - } else if (ntoh16_ua(frame + ETHER_TYPE_OFFSET) >= ETHER_TYPE_MIN) { - /* Frame is Ethernet II */ - pt = frame + ETHER_TYPE_OFFSET; - } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN && - !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) { - pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN; - snap = TRUE; - } else { - L2_FILTER_MSG((" get_pkt_ether_type: non-SNAP 802.3 frame\n")); - return BCME_ERROR; - } - - ethertype = ntoh16_ua(pt); - - /* Skip VLAN tag, if any */ - if (ethertype == ETHER_TYPE_8021Q) { - pt += VLAN_TAG_LEN; - - if ((pt + ETHER_TYPE_LEN) > (frame + length)) { - L2_FILTER_MSG(("BCM: get_pkt_ether_type: short VLAN frame (%d)\n", - length)); - return BCME_ERROR; - } - ethertype = ntoh16_ua(pt); - } - *data_ptr = pt + ETHER_TYPE_LEN; - *len_ptr = length - (int32)(pt + ETHER_TYPE_LEN - frame); - *et_ptr = ethertype; - *snap_ptr = snap; - return BCME_OK; -} - -int -get_pkt_ip_type(osl_t *osh, void *pktbuf, - uint8 **data_ptr, int *len_ptr, uint8 *prot_ptr) -{ - struct ipv4_hdr *iph; /* IP frame pointer */ - int iplen; /* IP frame length */ - uint16 ethertype, iphdrlen, ippktlen; - uint16 iph_frag; - uint8 prot; - bool snap; - - if (get_pkt_ether_type(osh, pktbuf, (uint8 **)&iph, - &iplen, ðertype, &snap) != 0) - return BCME_ERROR; - - if (ethertype != ETHER_TYPE_IP) { - return BCME_ERROR; - } - - /* We support IPv4 only */ - if (iplen < IPV4_OPTIONS_OFFSET || (IP_VER(iph) != IP_VER_4)) { - return BCME_ERROR; - } - - /* Header length sanity */ - iphdrlen = IPV4_HLEN(iph); - - /* - * Packet length sanity; sometimes we receive eth-frame size bigger - * than the IP content, which results in a bad tcp chksum - */ - ippktlen = ntoh16(iph->tot_len); - if (ippktlen < iplen) { - L2_FILTER_MSG(("get_pkt_ip_type: extra frame length ignored\n")); - iplen = ippktlen; - } else if (ippktlen > iplen) { - L2_FILTER_MSG(("get_pkt_ip_type: truncated IP packet (%d)\n", - ippktlen - iplen)); - return BCME_ERROR; - } - - if (iphdrlen < IPV4_OPTIONS_OFFSET || iphdrlen > iplen) { - L2_FILTER_ERROR((" get_pkt_ip_type: IP-header-len (%d) out of range (%d-%d)\n", - iphdrlen, IPV4_OPTIONS_OFFSET, iplen)); - return BCME_ERROR; - } - - /* - * We don't handle fragmented IP packets. A first frag is indicated by the MF - * (more frag) bit and a subsequent frag is indicated by a non-zero frag offset. - */ - iph_frag = ntoh16(iph->frag); - - if ((iph_frag & IPV4_FRAG_MORE) || (iph_frag & IPV4_FRAG_OFFSET_MASK) != 0) { - L2_FILTER_ERROR(("get_pkt_ip_type: IP fragment not handled\n")); - return BCME_ERROR; - } - prot = IPV4_PROT(iph); - *data_ptr = (((uint8 *)iph) + iphdrlen); - *len_ptr = iplen - iphdrlen; - *prot_ptr = prot; - return BCME_OK; -} - -/* Check if packet type is ICMP ECHO */ -int bcm_l2_filter_block_ping(osl_t *osh, void *pktbuf) -{ - struct bcmicmp_hdr *icmph; - int udpl; - uint8 prot; - - if (get_pkt_ip_type(osh, pktbuf, (uint8 **)&icmph, &udpl, &prot) != 0) - return BCME_ERROR; - if (prot == IP_PROT_ICMP) { - if (icmph->type == ICMP_TYPE_ECHO_REQUEST) - return BCME_OK; - } - return BCME_ERROR; -} - -int bcm_l2_filter_get_mac_addr_dhcp_pkt(osl_t *osh, void *pktbuf, - int ifidx, uint8** mac_addr) -{ - uint8 *eh = PKTDATA(osh, pktbuf); - uint8 *udph; - uint8 *dhcp; - int udpl; - int dhcpl; - uint16 port; - uint8 prot; - - if (!ETHER_ISMULTI(eh + ETHER_DEST_OFFSET)) - return BCME_ERROR; - if (get_pkt_ip_type(osh, pktbuf, &udph, &udpl, &prot) != 0) - return BCME_ERROR; - if (prot != IP_PROT_UDP) - return BCME_ERROR; - /* check frame length, at least UDP_HDR_LEN */ - if (udpl < UDP_HDR_LEN) { - L2_FILTER_MSG(("BCM: bcm_l2_filter_get_mac_addr_dhcp_pkt: short UDP frame," - " ignored\n")); - return BCME_ERROR; - } - port = ntoh16_ua(udph + UDP_DEST_PORT_OFFSET); - /* only process DHCP packets from server to client */ - if (port != DHCP_PORT_CLIENT) - return BCME_ERROR; - - dhcp = udph + UDP_HDR_LEN; - dhcpl = udpl - UDP_HDR_LEN; - - if (dhcpl < DHCP_CHADDR_OFFSET + ETHER_ADDR_LEN) { - L2_FILTER_MSG(("BCM: bcm_l2_filter_get_mac_addr_dhcp_pkt: short DHCP frame," - " ignored\n")); - return BCME_ERROR; - } - /* only process DHCP reply(offer/ack) packets */ - if (*(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REPLY) - return BCME_ERROR; - /* chaddr = dhcp + DHCP_CHADDR_OFFSET; */ - *mac_addr = dhcp + DHCP_CHADDR_OFFSET; - return BCME_OK; -} -/* modify the mac address for IP, in arp table */ -int -bcm_l2_filter_parp_modifyentry(arp_table_t* arp_tbl, struct ether_addr *ea, - uint8 *ip, uint8 ip_ver, bool cached, unsigned int entry_tickcnt) -{ - parp_entry_t *entry; - uint8 idx, ip_len; - arp_table_t *ptable; - - if (ip_ver == IP_VER_4 && !IPV4_ADDR_NULL(ip) && !IPV4_ADDR_BCAST(ip)) { - idx = BCM_PARP_TABLE_INDEX(ip[IPV4_ADDR_LEN - 1]); - ip_len = IPV4_ADDR_LEN; - } - else if (ip_ver == IP_VER_6 && !IPV6_ADDR_NULL(ip)) { - idx = BCM_PARP_TABLE_INDEX(ip[IPV6_ADDR_LEN - 1]); - ip_len = IPV6_ADDR_LEN; - } - else { - return BCME_ERROR; - } - - ptable = arp_tbl; - if (cached) { - entry = ptable->parp_table[idx]; - } else { - entry = ptable->parp_candidate_list; - } - while (entry) { - if (bcmp(entry->ip.data, ip, ip_len) == 0) { - /* entry matches, overwrite mac content and return */ - bcopy((void *)ea, (void *)&entry->ea, ETHER_ADDR_LEN); - entry->used = entry_tickcnt; -#ifdef DHD_DUMP_ARPTABLE - bcm_l2_parp_dump_table(arp_tbl); -#endif - return BCME_OK; - } - entry = entry->next; - } -#ifdef DHD_DUMP_ARPTABLE - bcm_l2_parp_dump_table(arp_tbl); -#endif - return BCME_ERROR; -} - -/* Add the IP entry in ARP table based on Cached argument, if cached argument is - * non zero positive value: it adds to parp_table, else adds to - * parp_candidate_list - */ -int -bcm_l2_filter_parp_addentry(osl_t *osh, arp_table_t* arp_tbl, struct ether_addr *ea, - uint8 *ip, uint8 ip_ver, bool cached, unsigned int entry_tickcnt) -{ - parp_entry_t *entry; - uint8 idx, ip_len; - arp_table_t *ptable; - - if (ip_ver == IP_VER_4 && !IPV4_ADDR_NULL(ip) && !IPV4_ADDR_BCAST(ip)) { - idx = BCM_PARP_TABLE_INDEX(ip[IPV4_ADDR_LEN - 1]); - ip_len = IPV4_ADDR_LEN; - } - else if (ip_ver == IP_VER_6 && !IPV6_ADDR_NULL(ip)) { - idx = BCM_PARP_TABLE_INDEX(ip[IPV6_ADDR_LEN - 1]); - ip_len = IPV6_ADDR_LEN; - } - else { - return BCME_ERROR; - } - - if ((entry = MALLOCZ(osh, sizeof(parp_entry_t) + ip_len)) == NULL) { - L2_FILTER_MSG(("Allocating new parp_entry for IPv%d failed!!\n", ip_ver)); - return BCME_NOMEM; - } - - bcopy((void *)ea, (void *)&entry->ea, ETHER_ADDR_LEN); - entry->used = entry_tickcnt; - entry->ip.id = ip_ver; - entry->ip.len = ip_len; - bcopy(ip, entry->ip.data, ip_len); - ptable = arp_tbl; - if (cached) { - entry->next = ptable->parp_table[idx]; - ptable->parp_table[idx] = entry; - } else { - entry->next = ptable->parp_candidate_list; - ptable->parp_candidate_list = entry; - } -#ifdef DHD_DUMP_ARPTABLE - bcm_l2_parp_dump_table(arp_tbl); -#endif - return BCME_OK; -} - -/* Delete the IP entry in ARP table based on Cached argument, if cached argument is - * non zero positive value: it delete from parp_table, else delete from - * parp_candidate_list - */ -int -bcm_l2_filter_parp_delentry(osl_t* osh, arp_table_t *arp_tbl, struct ether_addr *ea, - uint8 *ip, uint8 ip_ver, bool cached) -{ - parp_entry_t *entry, *prev = NULL; - uint8 idx, ip_len; - arp_table_t *ptable; - - if (ip_ver == IP_VER_4) { - idx = BCM_PARP_TABLE_INDEX(ip[IPV4_ADDR_LEN - 1]); - ip_len = IPV4_ADDR_LEN; - } - else if (ip_ver == IP_VER_6) { - idx = BCM_PARP_TABLE_INDEX(ip[IPV6_ADDR_LEN - 1]); - ip_len = IPV6_ADDR_LEN; - } - else { - return BCME_ERROR; - } - ptable = arp_tbl; - if (cached) { - entry = ptable->parp_table[idx]; - } else { - entry = ptable->parp_candidate_list; - } - while (entry) { - if (entry->ip.id == ip_ver && - bcmp(entry->ip.data, ip, ip_len) == 0 && - bcmp(&entry->ea, ea, ETHER_ADDR_LEN) == 0) { - if (prev == NULL) { - if (cached) { - ptable->parp_table[idx] = entry->next; - } else { - ptable->parp_candidate_list = entry->next; - } - } else { - prev->next = entry->next; - } - break; - } - prev = entry; - entry = entry->next; - } - if (entry != NULL) - MFREE(osh, entry, sizeof(parp_entry_t) + ip_len); -#ifdef DHD_DUMP_ARPTABLE - bcm_l2_parp_dump_table(arp_tbl); -#endif - return BCME_OK; -} - -/* search the IP entry in ARP table based on Cached argument, if cached argument is - * non zero positive value: it searches from parp_table, else search from - * parp_candidate_list - */ -parp_entry_t * -bcm_l2_filter_parp_findentry(arp_table_t* arp_tbl, uint8 *ip, uint8 ip_ver, bool cached, - unsigned int entry_tickcnt) -{ - parp_entry_t *entry; - uint8 idx, ip_len; - arp_table_t *ptable; - - if (ip_ver == IP_VER_4) { - idx = BCM_PARP_TABLE_INDEX(ip[IPV4_ADDR_LEN - 1]); - ip_len = IPV4_ADDR_LEN; - } else if (ip_ver == IP_VER_6) { - idx = BCM_PARP_TABLE_INDEX(ip[IPV6_ADDR_LEN - 1]); - ip_len = IPV6_ADDR_LEN; - } else { - return NULL; - } - ptable = arp_tbl; - if (cached) { - entry = ptable->parp_table[idx]; - } else { - entry = ptable->parp_candidate_list; - } - while (entry) { - if (entry->ip.id == ip_ver && bcmp(entry->ip.data, ip, ip_len) == 0) { - /* time stamp of adding the station entry to arp table for ifp */ - entry->used = entry_tickcnt; - break; - } - entry = entry->next; - } - return entry; -} - -/* update arp table entries for every proxy arp enable interface */ -void -bcm_l2_filter_arp_table_update(osl_t *osh, arp_table_t* arp_tbl, bool all, uint8 *del_ea, - bool periodic, unsigned int tickcnt) -{ - parp_entry_t *prev, *entry, *delentry; - uint8 idx, ip_ver; - struct ether_addr ea; - uint8 ip[IPV6_ADDR_LEN]; - arp_table_t *ptable; - - ptable = arp_tbl; - for (idx = 0; idx < BCM_PARP_TABLE_SIZE; idx++) { - entry = ptable->parp_table[idx]; - while (entry) { - /* check if the entry need to be removed */ - if (all || (periodic && BCM_PARP_IS_TIMEOUT(tickcnt, entry)) || - (del_ea != NULL && !bcmp(del_ea, &entry->ea, ETHER_ADDR_LEN))) { - /* copy frame here */ - ip_ver = entry->ip.id; - bcopy(entry->ip.data, ip, entry->ip.len); - bcopy(&entry->ea, &ea, ETHER_ADDR_LEN); - entry = entry->next; - bcm_l2_filter_parp_delentry(osh, ptable, &ea, ip, ip_ver, TRUE); - } - else { - entry = entry->next; - } - } - } - - /* remove candidate or promote to real entry */ - prev = delentry = NULL; - entry = ptable->parp_candidate_list; - while (entry) { - /* remove candidate */ - if (all || (periodic && BCM_PARP_ANNOUNCE_WAIT_REACH(tickcnt, entry)) || - (del_ea != NULL && !bcmp(del_ea, (uint8 *)&entry->ea, ETHER_ADDR_LEN))) { - bool promote = (periodic && BCM_PARP_ANNOUNCE_WAIT_REACH(tickcnt, entry)) ? - TRUE: FALSE; - parp_entry_t *node = NULL; - - ip_ver = entry->ip.id; - - if (prev == NULL) - ptable->parp_candidate_list = entry->next; - else - prev->next = entry->next; - - node = bcm_l2_filter_parp_findentry(ptable, - entry->ip.data, IP_VER_6, TRUE, tickcnt); - if (promote && node == NULL) { - bcm_l2_filter_parp_addentry(osh, ptable, &entry->ea, - entry->ip.data, entry->ip.id, TRUE, tickcnt); - } - MFREE(osh, entry, sizeof(parp_entry_t) + entry->ip.len); - if (prev == NULL) { - entry = ptable->parp_candidate_list; - } else { - entry = prev->next; - } - } - else { - prev = entry; - entry = entry->next; - } - } -} -/* create 42 byte ARP packet for ARP response, aligned the Buffer */ -void * -bcm_l2_filter_proxyarp_alloc_reply(osl_t* osh, uint16 pktlen, struct ether_addr *src_ea, - struct ether_addr *dst_ea, uint16 ea_type, bool snap, void **p) -{ - void *pkt; - uint8 *frame; - - /* adjust pktlen since skb->data is aligned to 2 */ - pktlen += ALIGN_ADJ_BUFLEN; - - if ((pkt = PKTGET(osh, pktlen, FALSE)) == NULL) { - L2_FILTER_ERROR(("bcm_l2_filter_proxyarp_alloc_reply: PKTGET failed\n")); - return NULL; - } - /* adjust for pkt->data aligned */ - PKTPULL(osh, pkt, ALIGN_ADJ_BUFLEN); - frame = PKTDATA(osh, pkt); - - /* Create 14-byte eth header, plus snap header if applicable */ - bcopy(src_ea, frame + ETHER_SRC_OFFSET, ETHER_ADDR_LEN); - bcopy(dst_ea, frame + ETHER_DEST_OFFSET, ETHER_ADDR_LEN); - if (snap) { - hton16_ua_store(pktlen, frame + ETHER_TYPE_OFFSET); - bcopy(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN); - hton16_ua_store(ea_type, frame + ETHER_HDR_LEN + SNAP_HDR_LEN); - } else - hton16_ua_store(ea_type, frame + ETHER_TYPE_OFFSET); - - *p = (void *)(frame + ETHER_HDR_LEN + (snap ? SNAP_HDR_LEN + ETHER_TYPE_LEN : 0)); - return pkt; -} -/* copy the smac entry from parp_table */ -void bcm_l2_filter_parp_get_smac(arp_table_t* ptable, void* smac) -{ - bcopy(ptable->parp_smac, smac, ETHER_ADDR_LEN); -} -/* copy the cmac entry from parp_table */ -void bcm_l2_filter_parp_get_cmac(arp_table_t* ptable, void* cmac) -{ - bcopy(ptable->parp_cmac, cmac, ETHER_ADDR_LEN); -} -/* copy the smac entry to smac entry in parp_table */ -void bcm_l2_filter_parp_set_smac(arp_table_t* ptable, void* smac) -{ - bcopy(smac, ptable->parp_smac, ETHER_ADDR_LEN); -} -/* copy the cmac entry to cmac entry in parp_table */ -void bcm_l2_filter_parp_set_cmac(arp_table_t* ptable, void* cmac) -{ - bcopy(cmac, ptable->parp_cmac, ETHER_ADDR_LEN); -} - -uint16 -calc_checksum(uint8 *src_ipa, uint8 *dst_ipa, uint32 ul_len, uint8 prot, uint8 *ul_data) -{ - uint16 *startpos; - uint32 sum = 0; - int i; - uint16 answer = 0; - - if (src_ipa) { - uint8 ph[8] = {0, }; - for (i = 0; i < (IPV6_ADDR_LEN / 2); i++) { - sum += *((uint16 *)src_ipa); - src_ipa += 2; - } - - for (i = 0; i < (IPV6_ADDR_LEN / 2); i++) { - sum += *((uint16 *)dst_ipa); - dst_ipa += 2; - } - - *((uint32 *)ph) = hton32(ul_len); - *((uint32 *)(ph+4)) = 0; - ph[7] = prot; - startpos = (uint16 *)ph; - for (i = 0; i < 4; i++) { - sum += *startpos++; - } - } - - startpos = (uint16 *)ul_data; - while (ul_len > 1) { - sum += *startpos++; - ul_len -= 2; - } - - if (ul_len == 1) { - *((uint8 *)(&answer)) = *((uint8 *)startpos); - sum += answer; - } - - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - answer = ~sum; - - return answer; -} -/* - * The length of the option including - * the type and length fields in units of 8 octets - */ -bcm_tlv_t * -parse_nd_options(void *buf, int buflen, uint key) -{ - bcm_tlv_t *elt; - int totlen; - - elt = (bcm_tlv_t*)buf; - totlen = buflen; - - /* find tagged parameter */ - while (totlen >= TLV_HDR_LEN) { - int len = elt->len * 8; - - /* validate remaining totlen */ - if ((elt->id == key) && - (totlen >= len)) - return (elt); - - elt = (bcm_tlv_t*)((uint8*)elt + len); - totlen -= len; - } - - return NULL; -} - -/* returns 0 if tdls set up request or tdls discovery request */ -int -bcm_l2_filter_block_tdls(osl_t *osh, void *pktbuf) -{ - uint16 ethertype; - uint8 *data; - int datalen; - bool snap; - uint8 action_field; - - if (get_pkt_ether_type(osh, pktbuf, &data, &datalen, ðertype, &snap) != BCME_OK) - return BCME_ERROR; - - if (ethertype != ETHER_TYPE_89_0D) - return BCME_ERROR; - - /* validate payload type */ - if (datalen < TDLS_PAYLOAD_TYPE_LEN + 2) { - L2_FILTER_ERROR(("bcm_l2_filter_block_tdls: wrong length for 89-0d eth frame %d\n", - datalen)); - return BCME_ERROR; - } - - /* validate payload type */ - if (*data != TDLS_PAYLOAD_TYPE) { - L2_FILTER_ERROR(("bcm_l2_filter_block_tdls: wrong payload type for 89-0d" - " eth frame %d\n", - *data)); - return BCME_ERROR; - } - data += TDLS_PAYLOAD_TYPE_LEN; - - /* validate TDLS action category */ - if (*data != TDLS_ACTION_CATEGORY_CODE) { - L2_FILTER_ERROR(("bcm_l2_filter_block_tdls: wrong TDLS Category %d\n", *data)); - return BCME_ERROR; - } - data++; - - action_field = *data; - - if ((action_field == TDLS_SETUP_REQ) || (action_field == TDLS_DISCOVERY_REQ)) - return BCME_OK; - - return BCME_ERROR; -} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmbloom.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmbloom.c old mode 100755 new mode 100644 index 2fe8a4a58511..a062531413b9 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmbloom.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmbloom.c @@ -1,7 +1,7 @@ /* * Bloom filter support * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -24,16 +24,13 @@ #include #include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)) -#include -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0) */ - #ifdef BCMDRIVER #include #include #else /* !BCMDRIVER */ #include #include +#include #ifndef ASSERT #define ASSERT(exp) #endif @@ -71,7 +68,7 @@ bcm_bloom_create(bcm_bloom_alloc_t alloc_cb, err = BCME_NOMEM; goto done; } - memset(bp, 0, sizeof(*bp)); + bzero(bp, sizeof(*bp)); bp->cb_ctx = cb_ctx; bp->max_hash = max_hash; @@ -80,7 +77,7 @@ bcm_bloom_create(bcm_bloom_alloc_t alloc_cb, err = BCME_NOMEM; goto done; } - memset(bp->hash, 0, sizeof(*bp->hash) * max_hash); + bzero(bp->hash, sizeof(*bp->hash) * max_hash); if (filter_size > 0) { bp->filter = (*alloc_cb)(cb_ctx, filter_size); @@ -89,7 +86,7 @@ bcm_bloom_create(bcm_bloom_alloc_t alloc_cb, goto done; } bp->filter_size = filter_size; - memset(bp->filter, 0, filter_size); + bzero(bp->filter, filter_size); } *bloom = bp; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmevent.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmevent.c old mode 100755 new mode 100644 index a8cafcb5405a..25054456f58e --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmevent.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmevent.c @@ -1,7 +1,7 @@ /* * bcmevent read-only data shared by kernel or app layers * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -28,6 +28,7 @@ #include #include #include <802.11.h> +#include <802.11brcm.h> /* Table of event name strings for UIs and debugging dumps */ typedef struct { @@ -179,9 +180,6 @@ static const bcmevent_name_str_t bcmevent_names[] = { #endif BCMEVENT_NAME(WLC_E_PSTA_PRIMARY_INTF_IND), BCMEVENT_NAME(WLC_E_TXFAIL_THRESH), -#ifdef WLAIBSS - BCMEVENT_NAME(WLC_E_AIBSS_TXFAIL), -#endif /* WLAIBSS */ #ifdef GSCAN_SUPPORT BCMEVENT_NAME(WLC_E_PFN_GSCAN_FULL_RESULT), BCMEVENT_NAME(WLC_E_PFN_SSID_EXT), @@ -189,21 +187,12 @@ static const bcmevent_name_str_t bcmevent_names[] = { #ifdef WLBSSLOAD_REPORT BCMEVENT_NAME(WLC_E_BSS_LOAD), #endif -#if defined(BT_WIFI_HANDOVER) || defined(WL_TBOW) - BCMEVENT_NAME(WLC_E_BT_WIFI_HANDOVER_REQ), -#endif #ifdef WLFBT BCMEVENT_NAME(WLC_E_FBT), #endif /* WLFBT */ BCMEVENT_NAME(WLC_E_AUTHORIZED), BCMEVENT_NAME(WLC_E_PROBREQ_MSG_RX), -#ifdef WLAWDL - BCMEVENT_NAME(WLC_E_AWDL_AW), - BCMEVENT_NAME(WLC_E_AWDL_ROLE), - BCMEVENT_NAME(WLC_E_AWDL_EVENT), -#endif /* WLAWDL */ - BCMEVENT_NAME(WLC_E_CSA_START_IND), BCMEVENT_NAME(WLC_E_CSA_DONE_IND), BCMEVENT_NAME(WLC_E_CSA_FAILURE_IND), @@ -237,14 +226,27 @@ static const bcmevent_name_str_t bcmevent_names[] = { BCMEVENT_NAME(WLC_E_ROAM_CACHE_UPDATE), BCMEVENT_NAME(WLC_E_AP_BCN_DRIFT), BCMEVENT_NAME(WLC_E_PFN_SCAN_ALLGONE_EXT), -#ifdef WL_CLIENT_SAE - BCMEVENT_NAME(WLC_E_AUTH_START), -#endif /* WL_CLIENT_SAE */ #ifdef WL_TWT - BCMEVENT_NAME(WLC_E_TWT_SETUP), - BCMEVENT_NAME(WLC_E_TWT_TEARDOWN), - BCMEVENT_NAME(WLC_E_TWT_INFO_FRM) + BCMEVENT_NAME(WLC_E_TWT), #endif /* WL_TWT */ + BCMEVENT_NAME(WLC_E_AMT), + BCMEVENT_NAME(WLC_E_ROAM_SCAN_RESULT), +#if defined(XRAPI) + BCMEVENT_NAME(WLC_E_XR_SOFTAP_PSMODE), +#endif /* XRAPI */ +#ifdef WL_SIB_COEX + BCMEVENT_NAME(WLC_E_SIB), +#endif /* WL_SIB_COEX */ + BCMEVENT_NAME(WLC_E_MSCS), + BCMEVENT_NAME(WLC_E_RXDMA_RECOVERY_ATMPT), +#ifdef WL_SCHED_SCAN + BCMEVENT_NAME(WLC_E_PFN_PARTIAL_RESULT), +#endif /* WL_SCHED_SCAN */ + BCMEVENT_NAME(WLC_E_MLO_LINK_INFO), + BCMEVENT_NAME(WLC_E_C2C), + BCMEVENT_NAME(WLC_E_BCN_TSF), + BCMEVENT_NAME(WLC_E_OWE_INFO), + BCMEVENT_NAME(WLC_E_ULMU_DISABLED_REASON_UPD), }; const char *bcmevent_get_name(uint event_type) @@ -396,7 +398,8 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, if (out_event) { /* ensure BRCM event pkt aligned */ - memcpy(&out_event->event, &bcm_event->event, sizeof(wl_event_msg_t)); + (void)memcpy_s(&out_event->event, sizeof(out_event->event), + &bcm_event->event, sizeof(out_event->event)); } break; @@ -424,8 +427,9 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, if (out_event) { /* ensure BRCM dngl event pkt aligned */ - memcpy(&out_event->dngl_event, &((bcm_dngl_event_t *)pktdata)->dngl_event, - sizeof(bcm_dngl_event_msg_t)); + (void)memcpy_s(&out_event->dngl_event, sizeof(out_event->dngl_event), + &((bcm_dngl_event_t *)pktdata)->dngl_event, + sizeof(out_event->dngl_event)); } break; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcminternal-android.mk b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcminternal-android.mk deleted file mode 100755 index 4fecfadd269f..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcminternal-android.mk +++ /dev/null @@ -1,88 +0,0 @@ -# -# Broadcom Proprietary and Confidential. Copyright (C) 2020, -# All Rights Reserved. -# -# This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; -# the contents of this file may not be disclosed to third parties, -# copied or duplicated in any form, in whole or in part, without -# the prior written permission of Broadcom. -# -# -# <> - -# This file should be seen only by internal builds because it will -# be mentioned only in internal filelists like brcm.flist. -# See extended comment bcminternal.mk for details. - -BCMINTERNAL := 1 - -BCMINTERNAL_DFLAGS += -DDHD_NO_MOG - -ifneq ($(CONFIG_BCMDHD_PCIE),) - # Enable Register access via dhd IOVAR - BCMINTERNAL_DFLAGS += -DDHD_PCIE_REG_ACCESS - # latency timestamping - BCMINTERNAL_DFLAGS += -DDHD_PKTTS - # Traffic Pattern Analysis on Socket Flow - BCMINTERNAL_DFLAGS += -DDHD_QOS_ON_SOCK_FLOW - # QoS unit testing support - BCMINTERNAL_DFLAGS += -DDHD_QOS_ON_SOCK_FLOW_UT - # Auto QOS - BCMINTERNAL_DFLAGS += -DWL_AUTO_QOS - - ifneq ($(filter -DCUSTOMER_HW4, $(DHDCFLAGS)),) - # These will be moved to hw4 Makefile for 4389b0 - BCMINTERNAL_DFLAGS += -DWBRC - BCMINTERNAL_DFLAGS += -DWLAN_ACCEL_BOOT - BCMINTERNAL_DFLAGS += -DDHD_HTPUT_TUNABLES - # BCMINTERNAL_DFLAGS += -DDHD_FIS_DUMP - # SCAN TYPES, if kernel < 4.17 ..back port support required - ifneq ($(CONFIG_CFG80211_SCANTYPE_BKPORT),) - DHDCFLAGS += -DWL_SCAN_TYPE - endif - # Jig builds - # No reset during dhd attach - BCMINTERNAL_DFLAGS += -DDHD_SKIP_DONGLE_RESET_IN_ATTACH - # Dongle Isolation will ensure no resets devreset ON/OFF - BCMINTERNAL_DFLAGS += -DDONGLE_ENABLE_ISOLATION - # Quiesce dongle using DB7 trap - BCMINTERNAL_DFLAGS += -DDHD_DONGLE_TRAP_IN_DETACH - # Collect socram during dongle init failurs for internal builds - BCMINTERNAL_DFLAGS += -DDEBUG_DNGL_INIT_FAIL - # Dongle reset during Wifi ON to keep in sane state - BCMINTERNAL_DFLAGS += -DFORCE_DONGLE_RESET_IN_DEVRESET_ON - # Perform Backplane Reset else FLR will happen - # BCMINTERNAL_DFLAGS += -DDHD_USE_BP_RESET_SS_CTRL - BCMINTERNAL_DFLAGS += -DWIFI_TURNOFF_DELAY=10 - - endif - - # NCI_BUS support - BCMINTERNAL_DFLAGS += -DSOCI_NCI_BUS -endif - - -BCMINTERNAL_DFLAGS += -DDHD_BUS_MEM_ACCESS - -# Support multiple chips -BCMINTERNAL_DFLAGS += -DSUPPORT_MULTIPLE_CHIPS - -# Support unreleased chips -BCMINTERNAL_DFLAGS += -DUNRELEASEDCHIP - -# Collect socram if readshared fails -BCMINTERNAL_DFLAGS += -DDEBUG_DNGL_INIT_FAIL - -# Force enable memdump value to DUMP_MEMFILE if it is disabled -BCMINTERNAL_DFLAGS += -DDHD_INIT_DEFAULT_MEMDUMP - -ifneq ($(filter -DDHD_QOS_ON_SOCK_FLOW,$(BCMINTERNAL_DFLAGS)),) -BCMINTERNAL_DHDOFILES += dhd_linux_sock_qos.o -endif -ifneq ($(filter -DSOCI_NCI_BUS,$(BCMINTERNAL_DFLAGS)),) -BCMINTERNAL_DHDOFILES += nciutils.o -endif -ifneq ($(filter -DWBRC,$(BCMINTERNAL_DFLAGS)),) -BCMINTERNAL_DHDOFILES += wb_regon_coordinator.o -endif -# vim: filetype=make shiftwidth=2 diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcminternal.mk b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcminternal.mk deleted file mode 100755 index eb940210734f..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcminternal.mk +++ /dev/null @@ -1,60 +0,0 @@ -# -# Broadcom Proprietary and Confidential. Copyright (C) 2020, -# All Rights Reserved. -# -# This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; -# the contents of this file may not be disclosed to third parties, -# copied or duplicated in any form, in whole or in part, without -# the prior written permission of Broadcom. -# -# -# <> - -# This file should be seen only by internal builds because it will -# be mentioned only in internal filelists like brcm.flist. The idea -# is that it will be conditionally included by makefiles using the -# "-include" syntax, with the result that internal builds will see -# this file and set BCMINTERNAL which will eventually result in a -# -DBCMINTERNAL option passed to the compiler along with possible -# other effects. External builds will never see it and it will be -# silently ignored. -# -# Any settings which should not be exposed to customers may be -# placed here. For instance, if we were working on a super-secret -# new feature in supersecret.c we could set a variable here like -# BCMINTERNAL_OBJECTS := supersecret.o -# and later say -# OBJECTS += $(BCMINTERNAL_OBJECTS) -# within the main makefile. -# -# The key point is that this file is never shipped to customers -# because it's present only in internal filelists so anything -# here is private. - -BCMINTERNAL := 1 - -BCMINTERNAL_DFLAGS += -DBCMINTERNAL -BCMINTERNAL_DFLAGS += -DDHD_NO_MOG - -# Support unreleased chips -BCMINTERNAL_DFLAGS += -DUNRELEASEDCHIP - -ifneq ($(findstring -fwtrace,-$(TARGET)-),) - BCMINTERNAL_DFLAGS += -DDHD_FWTRACE - BCMINTERNAL_CFILES += dhd_fwtrace.c -endif - -# support only for SDIO MFG Fedora builds -ifneq ($(findstring -sdstd-,-$(TARGET)-),) - ifneq ($(findstring -mfgtest-,-$(TARGET)-),) - BCMINTERNAL_DFLAGS += -DDHD_SPROM - BCMINTERNAL_CFILES += bcmsrom.c bcmotp.c - endif -endif - -ifneq ($(findstring -pciefd-,$(TARGET)-),) -# NCI_BUS support -BCMINTERNAL_DFLAGS += -DSOCI_NCI_BUS -DBOOKER_NIC400_INF -BCMINTERNAL_CFILES += nciutils.c -endif -# vim: filetype=make shiftwidth=2 diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh.c old mode 100755 new mode 100644 index 538f0562069c..f22350c030c2 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh.c @@ -2,7 +2,7 @@ * BCMSDH interface glue * implement bcmsdh API for SDIOH driver * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -46,7 +46,7 @@ #include /* SDIO device core hardware definitions. */ #include /* SDIO Device and Protocol Specs */ -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) #include #endif /* defined (BT_OVER_SDIO) */ @@ -56,7 +56,7 @@ const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL; /* local copy of bcm sd handler */ bcmsdh_info_t * l_bcmsdh = NULL; -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) struct sdio_func *func_f3 = NULL; static f3intr_handler processf3intr = NULL; static dhd_hang_notification process_dhd_hang_notification = NULL; @@ -78,7 +78,7 @@ bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable) } #endif -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) void bcmsdh_btsdio_process_hang_state(dhd_hang_state_t new_state) { bool state_change = false; @@ -358,9 +358,6 @@ bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err) return data; } -#ifdef BCMSDH_MODULE -EXPORT_SYMBOL(bcmsdh_cfg_read); -#endif void bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err) @@ -391,9 +388,6 @@ bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err) BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, fnc_num, addr, data)); } -#ifdef BCMSDH_MODULE -EXPORT_SYMBOL(bcmsdh_cfg_write); -#endif uint32 bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err) @@ -498,7 +492,6 @@ bcmsdh_cisaddr_read(void *sdh, uint func, uint8 *cisd, uint32 offset) return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); } - int bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set) { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c old mode 100755 new mode 100644 index 5bd32c5ca493..88bf3469a547 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c @@ -1,7 +1,7 @@ /* * SDIO access interface for drivers - linux specific (pci only) * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -95,23 +95,6 @@ bool bcmsdh_chipmatch(uint16 vendor, uint16 device) { /* Add other vendors and devices as required */ -#ifdef BCMINTERNAL -#ifdef BCMSDIOH_BCM - if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) { - return (TRUE); - } - if (device == BCM_SDIOH_ID && vendor == VENDOR_BROADCOM) { - return (TRUE); - } - if (device == BCM4710_DEVICE_ID && vendor == VENDOR_BROADCOM) { - return (TRUE); - } - /* For now still accept the old devid */ - if (device == 0x4380 && vendor == VENDOR_BROADCOM) { - return (TRUE); - } -#endif /* BCMSDIOH_BCM */ -#endif /* BCMINTERNAL */ #ifdef BCMSDIOH_STD /* Check for Arasan host controller */ @@ -142,12 +125,6 @@ bcmsdh_chipmatch(uint16 vendor, uint16 device) return (TRUE); } -#ifdef BCMINTERNAL - /* Check for Jinvani (C-Guys) host controller */ - if (device == JINVANI_SDIOH_ID && vendor == VENDOR_JINVANI) { - return (TRUE); - } -#endif /* BCMINTERNAL */ #endif /* BCMSDIOH_STD */ #ifdef BCMSDIOH_SPI /* This is the PciSpiHost. */ @@ -156,28 +133,8 @@ bcmsdh_chipmatch(uint16 vendor, uint16 device) return (TRUE); } -#ifdef BCMINTERNAL - /* This is the SPI Host for QT. */ - if (device == BCM_SPIH_ID && vendor == VENDOR_BROADCOM) { - printf("Found SPI Host Controller\n"); - return (TRUE); - } -#endif /* BCMINTERNAL */ #endif /* BCMSDIOH_SPI */ -#ifdef BCMINTERNAL - /* - * XXX - This is a hack to get the GPL SdioLinux driver to load on Arasan/x86 - * This is accomplished by installing a PciSpiHost into the system alongside the - * Arasan controller. The PciSpiHost is just used to get BCMSDH loaded. - */ -#ifdef BCMSDH_FD - if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) { - printf("Found SdioLinux Host Controller\n"); - return (TRUE); - } -#endif /* BCMSDH_FD */ -#endif /* BCMINTERNAL */ return (FALSE); } @@ -271,15 +228,37 @@ int bcmsdh_set_get_wake(bcmsdh_info_t *bcmsdh, int flag) bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; unsigned long flags; #endif - int ret = 0; + int ret; #if defined(OOB_INTR_ONLY) spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags); +#endif ret = bcmsdh->pkt_wake; bcmsdh->total_wake_count += flag; bcmsdh->pkt_wake = flag; +#if defined(OOB_INTR_ONLY) + spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags); +#endif + return ret; +} + +int bcmsdh_get_wake(bcmsdh_info_t *bcmsdh) +{ +#if defined(OOB_INTR_ONLY) + bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; + unsigned long flags; +#endif + int ret; + +#if defined(OOB_INTR_ONLY) + spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags); +#endif + + ret = bcmsdh->pkt_wake; + +#if defined(OOB_INTR_ONLY) spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags); #endif return ret; @@ -566,7 +545,7 @@ EXPORT_SYMBOL(bcmsdh_intr_dereg); EXPORT_SYMBOL(bcmsdh_intr_pending); #endif -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) EXPORT_SYMBOL(bcmsdh_btsdio_interface_init); #endif /* defined (BT_OVER_SDIO) */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c old mode 100755 new mode 100644 index 2ac448c5d25f..7f7362c97bf1 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -43,7 +43,7 @@ #include #include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_PM_SLEEP) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) #include extern volatile bool dhd_mmc_suspend; #endif @@ -82,9 +82,23 @@ static void IRQHandler(struct sdio_func *func); static void IRQHandlerF2(struct sdio_func *func); #endif /* !defined(OOB_INTR_ONLY) */ static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); -#if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(BUS_POWER_RESTORE) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) && defined(MMC_SW_RESET) +#if defined(ENABLE_INSMOD_NO_FW_LOAD) +#if defined(MMC_SW_RESET) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0) +extern int mmc_sw_reset(struct mmc_card *card); +#else extern int mmc_sw_reset(struct mmc_host *host); +#endif +#elif defined(MMC_HW_RESET) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) +extern int mmc_hw_reset(struct mmc_card *card); +#else +extern int mmc_hw_reset(struct mmc_host *host); +#endif +#elif defined(BUS_POWER_RESTORE) && \ +LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) +#undef MMC_SW_RESET +#undef MMC_HW_RESET #else extern int sdio_reset_comm(struct mmc_card *card); #endif @@ -103,13 +117,15 @@ extern PBCMSDH_SDMMC_INSTANCE gInstance; #define CUSTOM_SDIO_F1_BLKSIZE DEFAULT_SDIO_F1_BLKSIZE #endif +#define COPY_BUF_SIZE (SDPCM_MAXGLOM_SIZE * 1600) + #define MAX_IO_RW_EXTENDED_BLK 511 uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE; uint sd_f1_blocksize = CUSTOM_SDIO_F1_BLKSIZE; -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) uint sd_f3_blocksize = 64; #endif /* defined (BT_OVER_SDIO) */ @@ -139,7 +155,7 @@ static int sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data); #endif /* NOTYET */ -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) extern void sdioh_sdmmc_card_enable_func_f3(sdioh_info_t *sd, struct sdio_func *func) { @@ -148,6 +164,8 @@ void sdioh_sdmmc_card_enable_func_f3(sdioh_info_t *sd, struct sdio_func *func) } #endif /* defined (BT_OVER_SDIO) */ +void sdmmc_set_timing(sdioh_info_t *sd, uint8 timing); +uint8 sdmmc_get_timing(sdioh_info_t *sd); void sdmmc_set_clock_rate(sdioh_info_t *sd, uint hz); uint sdmmc_get_clock_rate(sdioh_info_t *sd); void sdmmc_set_clock_divisor(sdioh_info_t *sd, uint sd_div); @@ -182,12 +200,49 @@ sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd) err_ret = sdio_enable_func(sd->func[1]); sdio_release_host(sd->func[1]); if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x\n", err_ret)); + sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: %d\n", err_ret)); } return FALSE; } +/* + * Set standard CCCR driver strength. Default value is type B. + * Type: Value, driver strength + * A: 0x10, x1.5 + * B: 0x00, x1 + * C: 0x20, x0.75 + * D: 0x30, x0.5 + */ +int +sdioh_set_driver_strength(struct sdio_func *func, uint8 level) +{ + int reg; + int err = 0; + + sdio_claim_host(func); + reg = sdio_readb(func, SDIOD_CCCR_DRIVER_STRENGTH, &err); + if (err) { + sd_err(("sd_ds error for read SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n", err)); + goto done; + } else { + sd_info(("SYNA: sd_ds get cccr driver strength 0x%x\n", reg)); + } + + reg = ((reg & 0xf) | level); + sdio_writeb(func, reg, SDIOD_CCCR_DRIVER_STRENGTH, &err); + + if (err) { + sd_err(("sd_ds error for write SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n", err)); + goto done; + } else { + sd_info(("SYNA: sd_ds set cccr driver strength 0x%x\n", reg)); + } +done: + sdio_release_host(func); + return err; +} + /* * Public entry points & extern's */ @@ -209,6 +264,14 @@ sdioh_attach(osl_t *osh, struct sdio_func *func) return NULL; } bzero((char *)sd, sizeof(sdioh_info_t)); +#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF) + sd->copy_buf = MALLOC(osh, COPY_BUF_SIZE); + if (sd->copy_buf == NULL) { + sd_err(("%s: MALLOC of %d-byte copy_buf failed\n", + __FUNCTION__, COPY_BUF_SIZE)); + goto fail; + } +#endif sd->osh = osh; sd->fake_func0.num = 0; sd->fake_func0.card = func->card; @@ -224,7 +287,7 @@ sdioh_attach(osl_t *osh, struct sdio_func *func) sd->func[func->num] = func; #endif -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) sd->func[3] = NULL; #endif /* defined (BT_OVER_SDIO) */ @@ -273,6 +336,9 @@ sdioh_attach(osl_t *osh, struct sdio_func *func) return sd; fail: +#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF) + MFREE(sd->osh, sd->copy_buf, COPY_BUF_SIZE); +#endif MFREE(sd->osh, sd, sizeof(sdioh_info_t)); return NULL; } @@ -301,6 +367,9 @@ sdioh_detach(osl_t *osh, sdioh_info_t *sd) sd->func[1] = NULL; sd->func[2] = NULL; +#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF) + MFREE(sd->osh, sd->copy_buf, COPY_BUF_SIZE); +#endif MFREE(sd->osh, sd, sizeof(sdioh_info_t)); } return SDIOH_API_RC_SUCCESS; @@ -329,7 +398,7 @@ sdioh_enable_func_intr(sdioh_info_t *sd) /* Enable F1 and F2 interrupts, clear master enable */ reg &= ~INTR_CTL_MASTER_EN; reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) reg |= (INTR_CTL_FUNC3_EN); #endif /* defined (BT_OVER_SDIO) */ sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err); @@ -357,7 +426,8 @@ sdioh_disable_func_intr(sdioh_info_t *sd) sdio_claim_host(sd->func[0]); reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err); if (err) { - sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); + sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x (ignore when remove)\n", + __FUNCTION__, err)); sdio_release_host(sd->func[0]); return SDIOH_API_RC_FAIL; } @@ -483,7 +553,8 @@ enum { IOV_HCIREGS, IOV_POWER, IOV_CLOCK, - IOV_RXCHAIN + IOV_RXCHAIN, + IOV_DS }; const bcm_iovar_t sdioh_iovars[] = { @@ -494,10 +565,6 @@ const bcm_iovar_t sdioh_iovars[] = { {"sd_ints", IOV_USEINTS, 0, 0, IOVT_BOOL, 0 }, {"sd_numints", IOV_NUMINTS, 0, 0, IOVT_UINT32, 0 }, {"sd_numlocalints", IOV_NUMLOCALINTS, 0, 0, IOVT_UINT32, 0 }, -#ifdef BCMINTERNAL - {"sd_hostreg", IOV_HOSTREG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_devreg", IOV_DEVREG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) }, -#endif /* BCMINTERNAL */ {"sd_divisor", IOV_DIVISOR, 0, 0, IOVT_UINT32, 0 }, {"sd_power", IOV_POWER, 0, 0, IOVT_UINT32, 0 }, {"sd_clock", IOV_CLOCK, 0, 0, IOVT_UINT32, 0 }, @@ -507,6 +574,7 @@ const bcm_iovar_t sdioh_iovars[] = { #ifdef BCMDBG {"sd_hciregs", IOV_HCIREGS, 0, 0, IOVT_BUFFER, 0 }, #endif + {"sd_ds", IOV_DS, 0, 0, IOVT_UINT32, 0 }, {NULL, 0, 0, 0, 0, 0 } }; @@ -721,88 +789,52 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name, int_val = (int32)0; bcopy(&int_val, arg, val_size); break; -#ifdef BCMINTERNAL - case IOV_GVAL(IOV_HOSTREG): + + case IOV_GVAL(IOV_DS): { - /* XXX Should copy for alignment reasons */ - sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 reg2; + int err; - if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { - sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); - bcmerror = BCME_BADARG; - break; + sdio_claim_host(si->func[0]); + reg2 = sdio_readb(si->func[0], SDIOD_CCCR_DRIVER_STRENGTH, &err); + if (err) { + sd_err(("sd_ds error for read SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n", err)); + bcmerror = BCME_SDIO_ERROR; + } else { + sd_trace(("sd_ds get cccr driver strength 0x%x\n", reg2)); } + sdio_release_host(si->func[0]); - sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__, - (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), - sd_ptr->offset)); - if (sd_ptr->offset & 1) - int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */ - else if (sd_ptr->offset & 2) - int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */ - else - int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */ - + int_val = (int)reg2; bcopy(&int_val, arg, sizeof(int_val)); break; } - case IOV_SVAL(IOV_HOSTREG): + case IOV_SVAL(IOV_DS): { - /* XXX Should copy for alignment reasons */ - sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 type; + int err; - if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { - sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); + if (int_val == 0) { + type = 0x0; + } else if (int_val == 1) { + type = 0x10; + } else if (int_val == 2) { + type = 0x20; + } else if (int_val == 3) { + type = 0x30; + } else { bcmerror = BCME_BADARG; break; } - sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value, - (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), - sd_ptr->offset)); - break; - } - - case IOV_GVAL(IOV_DEVREG): - { - /* XXX Should copy for alignment reasons */ - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data = 0; - - if ((uint)sd_ptr->func > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - - if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - - int_val = (int)data; - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_DEVREG): - { - /* XXX Should copy for alignment reasons */ - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data = (uint8)sd_ptr->value; - - if ((uint)sd_ptr->func > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - - if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; + err = sdioh_set_driver_strength(si->func[0], type); + if (err) { + sd_err(("sd_ds error write SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n", err)); } break; } -#endif /* BCMINTERNAL */ + default: bcmerror = BCME_UNSUPPORTED; break; @@ -949,7 +981,7 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by * as a special case. */ if (regaddr == SDIOD_CCCR_IOEN) { -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) do { if (sd->func[3]) { sd_info(("bcmsdh_sdmmc F3: *byte 0x%x\n", *byte)); @@ -1014,7 +1046,7 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by } sdio_release_host(sd->func[2]); } -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) } while (0); #endif /* defined (BT_OVER_SDIO) */ } @@ -1206,7 +1238,7 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint add if (err_ret) #endif /* MMC_SDIO_ABORT */ { - sd_err(("bcmsdh_sdmmc: Failed to %s word F%d:@0x%05x=%02x, Err: 0x%08x\n", + sd_err(("bcmsdh_sdmmc: Failed to %s word F%d:@0x%05x=%02x, Err: %d\n", rw ? "Write" : "Read", func, addr, *word, err_ret)); } } @@ -1356,7 +1388,8 @@ sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func return SDIOH_API_RC_FAIL; } } - } else if(sd->txglom_mode == SDPCM_TXGLOM_CPY) { + } + else if(sd->txglom_mode == SDPCM_TXGLOM_CPY) { for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { ttl_len += PKTLEN(sd->osh, pnext); } @@ -1365,16 +1398,20 @@ sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext); pkt_len = PKTLEN(sd->osh, pnext); - if (!localbuf) { +#ifdef BCMSDIOH_STATIC_COPY_BUF + if (ttl_len <= COPY_BUF_SIZE) + localbuf = sd->copy_buf; +#else localbuf = (uint8 *)MALLOC(sd->osh, ttl_len); +#endif if (localbuf == NULL) { - sd_err(("%s: %s TXGLOM: localbuf malloc FAILED\n", - __FUNCTION__, (write) ? "TX" : "RX")); + sd_err(("%s: %s localbuf malloc FAILED ttl_len=%d\n", + __FUNCTION__, (write) ? "TX" : "RX", ttl_len)); + ttl_len -= pkt_len; goto txglomfail; } } - bcopy(buf, (localbuf + local_plen), pkt_len); local_plen += pkt_len; if (PKTNEXT(sd->osh, pnext)) @@ -1419,8 +1456,10 @@ txglomfail: return SDIOH_API_RC_FAIL; } +#ifndef BCMSDIOH_STATIC_COPY_BUF if (localbuf) MFREE(sd->osh, localbuf, ttl_len); +#endif #ifndef PKT_STATICS if (sd_msglevel & SDH_COST_VAL) @@ -1746,21 +1785,44 @@ sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsiz } #endif /* NOTUSED */ -#if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(BUS_POWER_RESTORE) +#if defined(ENABLE_INSMOD_NO_FW_LOAD) static int sdio_sw_reset(sdioh_info_t *sd) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) && defined(MMC_SW_RESET) - struct mmc_host *host = sd->func[0]->card->host; -#endif + struct mmc_card *card = sd->func[0]->card; int err = 0; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) && defined(MMC_SW_RESET) - printf("%s: Enter\n", __FUNCTION__); +#if defined(MMC_SW_RESET) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) + /* MMC_SW_RESET */ + printf("%s: call mmc_sw_reset\n", __FUNCTION__); sdio_claim_host(sd->func[0]); - err = mmc_sw_reset(host); - sdio_release_host(sd->func[0]); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0) + err = mmc_sw_reset(card); #else - err = sdio_reset_comm(sd->func[0]->card); + err = mmc_sw_reset(card->host); +#endif + sdio_release_host(sd->func[0]); +#elif defined(MMC_HW_RESET) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) + /* MMC_HW_RESET */ + printf("%s: call mmc_hw_reset\n", __FUNCTION__); + sdio_claim_host(sd->func[0]); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) + while (atomic_read(&card->sdio_funcs_probed) > 1) { + atomic_dec(&card->sdio_funcs_probed); + } +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) + err = mmc_hw_reset(card); +#else + err = mmc_hw_reset(card->host); +#endif + sdio_release_host(sd->func[0]); +#elif defined(BUS_POWER_RESTORE) && \ +LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) + printf("%s: call mmc_power_restore_host\n", __FUNCTION__); + mmc_power_restore_host(card->host); +#else + /* sdio_reset_comm */ + err = sdio_reset_comm(card); #endif if (err) @@ -1786,60 +1848,60 @@ sdioh_start(sdioh_info_t *sd, int stage) sdio access will come in way */ if (sd->func[0]) { - if (stage == 0) { - /* Since the power to the chip is killed, we will have - re enumerate the device again. Set the block size - and enable the fucntion 1 for in preparation for - downloading the code - */ - /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux - 2.6.27. The implementation prior to that is buggy, and needs broadcom's - patch for it - */ -#if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(BUS_POWER_RESTORE) - if ((ret = sdio_sw_reset(sd))) { - sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); - return ret; - } else + if (stage == 0) { + /* Since the power to the chip is killed, we will have + re enumerate the device again. Set the block size + and enable the fucntion 1 for in preparation for + downloading the code + */ + /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux + 2.6.27. The implementation prior to that is buggy, and needs broadcom's + patch for it + */ +#if defined(ENABLE_INSMOD_NO_FW_LOAD) + if ((ret = sdio_sw_reset(sd))) { + sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); + return ret; + } else #endif - { - sd->num_funcs = 2; - sd->sd_blockmode = TRUE; - sd->use_client_ints = TRUE; - sd->client_block_size[0] = 64; + { + sd->num_funcs = 2; + sd->sd_blockmode = TRUE; + sd->use_client_ints = TRUE; + sd->client_block_size[0] = 64; - if (sd->func[1]) { - /* Claim host controller */ - sdio_claim_host(sd->func[1]); + if (sd->func[1]) { + /* Claim host controller */ + sdio_claim_host(sd->func[1]); - sd->client_block_size[1] = 64; - ret = sdio_set_block_size(sd->func[1], 64); - if (ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F1 " - "blocksize(%d)\n", ret)); + sd->client_block_size[1] = 64; + ret = sdio_set_block_size(sd->func[1], 64); + if (ret) { + sd_err(("bcmsdh_sdmmc: Failed to set F1 " + "blocksize(%d)\n", ret)); + } + + /* Release host controller F1 */ + sdio_release_host(sd->func[1]); } - /* Release host controller F1 */ - sdio_release_host(sd->func[1]); - } + if (sd->func[2]) { + /* Claim host controller F2 */ + sdio_claim_host(sd->func[2]); - if (sd->func[2]) { - /* Claim host controller F2 */ - sdio_claim_host(sd->func[2]); + sd->client_block_size[2] = sd_f2_blocksize; + printf("%s: set sd_f2_blocksize %d\n", __FUNCTION__, sd_f2_blocksize); + ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); + if (ret) { + sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize" + " to %d(%d)\n", sd_f2_blocksize, ret)); + } - sd->client_block_size[2] = sd_f2_blocksize; - printf("%s: set sd_f2_blocksize %d\n", __FUNCTION__, sd_f2_blocksize); - ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); - if (ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F2 " - "blocksize to %d(%d)\n", sd_f2_blocksize, ret)); + /* Release host controller F2 */ + sdio_release_host(sd->func[2]); } - /* Release host controller F2 */ - sdio_release_host(sd->func[2]); - } - - sdioh_sdmmc_card_enablefuncs(sd); + sdioh_sdmmc_card_enablefuncs(sd); } } else { #if !defined(OOB_INTR_ONLY) @@ -1856,8 +1918,7 @@ sdioh_start(sdioh_info_t *sd, int stage) bcmsdh_oob_intr_set(sd->bcmsdh, TRUE); #endif /* !defined(OOB_INTR_ONLY) */ } - } - else + } else sd_err(("%s Failed\n", __FUNCTION__)); #endif /* defined(OEM_ANDROID) */ @@ -1894,10 +1955,20 @@ sdioh_stop(sdioh_info_t *sd) } else sd_err(("%s Failed\n", __FUNCTION__)); -#endif /* defined(OEM_ANDROID) */ +#if !defined(MMC_SW_RESET) && !defined(MMC_HW_RESET) +#if defined(BUS_POWER_RESTORE) && \ +LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) + if (sd->func[0]) { + struct mmc_card *card = sd->func[0]->card; + printf("%s: call mmc_power_save_host\n", __FUNCTION__); + mmc_power_save_host(card->host); + } +#endif +#endif #if !defined(OOB_INTR_ONLY) sdio_claim_host_unlock_local(sd); #endif +#endif /* defined(OEM_ANDROID) */ return (0); } @@ -1907,16 +1978,6 @@ sdioh_waitlockfree(sdioh_info_t *sd) return (1); } -#ifdef BCMINTERNAL -extern SDIOH_API_RC -sdioh_test_diag(sdioh_info_t *sd) -{ - sd_trace(("%s: Enter\n", __FUNCTION__)); - sd_trace(("%s: Exit\n", __FUNCTION__)); - return (0); -} -#endif /* BCMINTERNAL */ - SDIOH_API_RC sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) { @@ -1941,6 +2002,29 @@ sdioh_gpio_init(sdioh_info_t *sd) return SDIOH_API_RC_FAIL; } +uint8 +sdmmc_get_timing(sdioh_info_t *sd) +{ + struct sdio_func *sdio_func = sd->func[0]; + struct mmc_host *host = sdio_func->card->host; + return host->ios.timing; +} + +void +sdmmc_set_timing(sdioh_info_t *sd, uint8 timing) +{ + struct sdio_func *sdio_func = sd->func[0]; + struct mmc_host *host = sdio_func->card->host; + struct mmc_ios *ios = &host->ios; + + mmc_host_clk_hold(host); + DHD_INFO(("%s: Before change: sd current timing is %u\n", __FUNCTION__, ios->timing)); + ios->timing = timing; + host->ops->set_ios(host, ios); + DHD_ERROR(("%s: After change: sd timing is %u\n", __FUNCTION__, ios->timing)); + mmc_host_clk_release(host); +} + uint sdmmc_get_clock_rate(sdioh_info_t *sd) { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c old mode 100755 new mode 100644 index 1dfb408fbf1b..a386b836cc57 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -91,8 +91,12 @@ static int sdioh_probe(struct sdio_func *func) adapter->bus_num = host_idx; adapter->slot_num = rca; adapter->sdio_func = func; - } else + } else { sd_err(("can't find adapter info for this chip\n")); +#ifdef ADAPTER_IDX + goto fail; +#endif + } #ifdef WL_CFG80211 wl_cfg80211_set_parent_dev(&func->dev); @@ -198,6 +202,7 @@ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM4362_CHIP_ID) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43751_CHIP_ID) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43752_CHIP_ID) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43756_CHIP_ID) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43012_CHIP_ID) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43014_CHIP_ID) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43014_D11N_ID) }, @@ -207,6 +212,9 @@ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43013_D11N_ID) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43013_D11N2G_ID) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43013_D11N5G_ID) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_ANY_ID) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM4381_CHIP_ID) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM4382_CHIP_ID) }, { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, { 0, 0, 0, 0 /* end: all zeroes */ }, diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdspi.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdspi.h deleted file mode 100755 index 9a29370072e3..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdspi.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id: bcmsdspi.h 833013 2019-08-02 16:26:31Z jl904071 $ - */ -#ifndef _BCM_SD_SPI_H -#define _BCM_SD_SPI_H - -/* global msglevel for debug messages - bitvals come from sdiovar.h */ - -#ifdef BCMDBG -#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) -#define sd_trace(x) do { if (sd_msglevel & SDH_TRACE_VAL) printf x; } while (0) -#define sd_info(x) do { if (sd_msglevel & SDH_INFO_VAL) printf x; } while (0) -#define sd_debug(x) do { if (sd_msglevel & SDH_DEBUG_VAL) printf x; } while (0) -#define sd_data(x) do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0) -#define sd_ctrl(x) do { if (sd_msglevel & SDH_CTRL_VAL) printf x; } while (0) -#else -#define sd_err(x) -#define sd_trace(x) -#define sd_info(x) -#define sd_debug(x) -#define sd_data(x) -#define sd_ctrl(x) -#endif - -#ifdef BCMPERFSTATS -#define sd_log(x) do { if (sd_msglevel & SDH_LOG_VAL) bcmlog x; } while (0) -#else -#define sd_log(x) -#endif - -#define SDIOH_ASSERT(exp) \ - do { if (!(exp)) \ - printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ - } while (0) - -#define BLOCK_SIZE_4318 64 -#define BLOCK_SIZE_4328 512 - -/* internal return code */ -#define SUCCESS 0 -#undef ERROR -#define ERROR 1 - -/* private bus modes */ -#define SDIOH_MODE_SPI 0 - -#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ -#define USE_MULTIBLOCK 0x4 - -struct sdioh_info { - uint cfg_bar; /* pci cfg address for bar */ - uint32 caps; /* cached value of capabilities reg */ - uint bar0; /* BAR0 for PCI Device */ - osl_t *osh; /* osh handler */ - void *controller; /* Pointer to SPI Controller's private data struct */ - - uint lockcount; /* nest count of sdspi_lock() calls */ - bool client_intr_enabled; /* interrupt connnected flag */ - bool intr_handler_valid; /* client driver interrupt handler valid */ - sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ - void *intr_handler_arg; /* argument to call interrupt handler */ - bool initialized; /* card initialized */ - uint32 target_dev; /* Target device ID */ - uint32 intmask; /* Current active interrupts */ - void *sdos_info; /* Pointer to per-OS private data */ - - uint32 controller_type; /* Host controller type */ - uint8 version; /* Host Controller Spec Compliance Version */ - uint irq; /* Client irq */ - uint32 intrcount; /* Client interrupts */ - uint32 local_intrcount; /* Controller interrupts */ - bool host_init_done; /* Controller initted */ - bool card_init_done; /* Client SDIO interface initted */ - bool polled_mode; /* polling for command completion */ - - bool sd_use_dma; /* DMA on CMD53 */ - bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ - /* Must be on for sd_multiblock to be effective */ - bool use_client_ints; /* If this is false, make sure to restore */ - bool got_hcint; /* Host Controller interrupt. */ - /* polling hack in wl_linux.c:wl_timer() */ - int adapter_slot; /* Maybe dealing with multiple slots/controllers */ - int sd_mode; /* SD1/SD4/SPI */ - int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ - uint32 data_xfer_count; /* Current register transfer size */ - uint32 cmd53_wr_data; /* Used to pass CMD53 write data */ - uint32 card_response; /* Used to pass back response status byte */ - uint32 card_rsp_data; /* Used to pass back response data word */ - uint16 card_rca; /* Current Address */ - uint8 num_funcs; /* Supported funcs on client */ - uint32 com_cis_ptr; - uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; - void *dma_buf; - ulong dma_phys; - int r_cnt; /* rx count */ - int t_cnt; /* tx_count */ -}; - -/************************************************************ - * Internal interfaces: per-port references into bcmsdspi.c - */ - -/* Global message bits */ -extern uint sd_msglevel; - -/************************************************************** - * Internal interfaces: bcmsdspi.c references to per-port code - */ - -/* Register mapping routines */ -extern uint32 *spi_reg_map(osl_t *osh, uintptr addr, int size); -extern void spi_reg_unmap(osl_t *osh, uintptr addr, int size); - -/* Interrupt (de)registration routines */ -extern int spi_register_irq(sdioh_info_t *sd, uint irq); -extern void spi_free_irq(uint irq, sdioh_info_t *sd); - -/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ -extern void spi_lock(sdioh_info_t *sd); -extern void spi_unlock(sdioh_info_t *sd); - -/* Allocate/init/free per-OS private data */ -extern int spi_osinit(sdioh_info_t *sd); -extern void spi_osfree(sdioh_info_t *sd); - -#endif /* _BCM_SD_SPI_H */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdspi_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdspi_linux.c deleted file mode 100755 index b77168271663..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdspi_linux.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Broadcom SPI Host Controller Driver - Linux Per-port - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - */ - -#include -#include - -#include /* bcmsdh to/from specific controller APIs */ -#include /* to get msglevel bit values */ - -#ifdef BCMSPI_ANDROID -#include -#include -#include -#else -#include -#include /* SDIO Device and Protocol Specs */ -#include /* request_irq(), free_irq() */ -#include -#include -#endif /* BCMSPI_ANDROID */ - -#ifndef BCMSPI_ANDROID -extern uint sd_crc; -module_param(sd_crc, uint, 0); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define KERNEL26 -#endif -#endif /* !BCMSPI_ANDROID */ - -struct sdos_info { - sdioh_info_t *sd; - spinlock_t lock; -#ifndef BCMSPI_ANDROID - wait_queue_head_t intr_wait_queue; -#endif /* !BCMSPI_ANDROID */ -}; - -#ifndef BCMSPI_ANDROID -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define BLOCKABLE() (!in_atomic()) -#else -#define BLOCKABLE() (!in_interrupt()) /* XXX Doesn't handle CONFIG_PREEMPT? */ -#endif - -/* Interrupt handler */ -static irqreturn_t -sdspi_isr(int irq, void *dev_id -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -, struct pt_regs *ptregs -#endif -) -{ - sdioh_info_t *sd; - struct sdos_info *sdos; - bool ours; - - sd = (sdioh_info_t *)dev_id; - sd->local_intrcount++; - - if (!sd->card_init_done) { - sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq)); - return IRQ_RETVAL(FALSE); - } else { - ours = spi_check_client_intr(sd, NULL); - - /* For local interrupts, wake the waiting process */ - if (ours && sd->got_hcint) { - sdos = (struct sdos_info *)sd->sdos_info; - wake_up_interruptible(&sdos->intr_wait_queue); - } - - return IRQ_RETVAL(ours); - } -} -#endif /* !BCMSPI_ANDROID */ - -#ifdef BCMSPI_ANDROID -static struct spi_device *gBCMSPI = NULL; - -extern int bcmsdh_probe(struct device *dev); -extern int bcmsdh_remove(struct device *dev); - -static int bcmsdh_spi_probe(struct spi_device *spi_dev) -{ - int ret = 0; - - gBCMSPI = spi_dev; - -#ifdef SPI_PIO_32BIT_RW - spi_dev->bits_per_word = 32; -#else - spi_dev->bits_per_word = 8; -#endif /* SPI_PIO_32BIT_RW */ - ret = spi_setup(spi_dev); - - if (ret) { - sd_err(("bcmsdh_spi_probe: spi_setup fail with %d\n", ret)); - } - sd_err(("bcmsdh_spi_probe: spi_setup with %d, bits_per_word=%d\n", - ret, spi_dev->bits_per_word)); - ret = bcmsdh_probe(&spi_dev->dev); - - return ret; -} - -static int bcmsdh_spi_remove(struct spi_device *spi_dev) -{ - int ret = 0; - - ret = bcmsdh_remove(&spi_dev->dev); - gBCMSPI = NULL; - - return ret; -} - -static struct spi_driver bcmsdh_spi_driver = { - .probe = bcmsdh_spi_probe, - .remove = bcmsdh_spi_remove, - .driver = { - .name = "wlan_spi", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, -}; - -/* - * module init -*/ -int bcmsdh_register_client_driver(void) -{ - int error = 0; - sd_trace(("bcmsdh_gspi: %s Enter\n", __FUNCTION__)); - - error = spi_register_driver(&bcmsdh_spi_driver); - - return error; -} - -/* - * module cleanup -*/ -void bcmsdh_unregister_client_driver(void) -{ - sd_trace(("%s Enter\n", __FUNCTION__)); - spi_unregister_driver(&bcmsdh_spi_driver); -} -#endif /* BCMSPI_ANDROID */ - -/* Register with Linux for interrupts */ -int -spi_register_irq(sdioh_info_t *sd, uint irq) -{ -#ifndef BCMSPI_ANDROID - sd_trace(("Entering %s: irq == %d\n", __FUNCTION__, irq)); - if (request_irq(irq, sdspi_isr, IRQF_SHARED, "bcmsdspi", sd) < 0) { - sd_err(("%s: request_irq() failed\n", __FUNCTION__)); - return ERROR; - } -#endif /* !BCMSPI_ANDROID */ - return SUCCESS; -} - -/* Free Linux irq */ -void -spi_free_irq(uint irq, sdioh_info_t *sd) -{ -#ifndef BCMSPI_ANDROID - free_irq(irq, sd); -#endif /* !BCMSPI_ANDROID */ -} - -/* Map Host controller registers */ -#ifndef BCMSPI_ANDROID -uint32 * -spi_reg_map(osl_t *osh, uintptr addr, int size) -{ - return (uint32 *)REG_MAP(addr, size); -} - -void -spi_reg_unmap(osl_t *osh, uintptr addr, int size) -{ - REG_UNMAP((void*)(uintptr)addr); -} -#endif /* !BCMSPI_ANDROID */ - -int -spi_osinit(sdioh_info_t *sd) -{ - struct sdos_info *sdos; - - sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info)); - sd->sdos_info = (void*)sdos; - if (sdos == NULL) - return BCME_NOMEM; - - sdos->sd = sd; - spin_lock_init(&sdos->lock); -#ifndef BCMSPI_ANDROID - init_waitqueue_head(&sdos->intr_wait_queue); -#endif /* !BCMSPI_ANDROID */ - return BCME_OK; -} - -void -spi_osfree(sdioh_info_t *sd) -{ - struct sdos_info *sdos; - ASSERT(sd && sd->sdos_info); - - sdos = (struct sdos_info *)sd->sdos_info; - MFREE(sd->osh, sdos, sizeof(struct sdos_info)); -} - -/* Interrupt enable/disable */ -SDIOH_API_RC -sdioh_interrupt_set(sdioh_info_t *sd, bool enable) -{ - ulong flags; - struct sdos_info *sdos; - - sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); - - sdos = (struct sdos_info *)sd->sdos_info; - ASSERT(sdos); - - if (!(sd->host_init_done && sd->card_init_done)) { - sd_err(("%s: Card & Host are not initted - bailing\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - -#ifndef BCMSPI_ANDROID - if (enable && !(sd->intr_handler && sd->intr_handler_arg)) { - sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } -#endif /* !BCMSPI_ANDROID */ - - /* Ensure atomicity for enable/disable calls */ - spin_lock_irqsave(&sdos->lock, flags); - - sd->client_intr_enabled = enable; -#ifndef BCMSPI_ANDROID - if (enable && !sd->lockcount) - spi_devintr_on(sd); - else - spi_devintr_off(sd); -#endif /* !BCMSPI_ANDROID */ - - spin_unlock_irqrestore(&sdos->lock, flags); - - return SDIOH_API_RC_SUCCESS; -} - -/* Protect against reentrancy (disable device interrupts while executing) */ -void -spi_lock(sdioh_info_t *sd) -{ - ulong flags; - struct sdos_info *sdos; - - sdos = (struct sdos_info *)sd->sdos_info; - ASSERT(sdos); - - sd_trace(("%s: %d\n", __FUNCTION__, sd->lockcount)); - - spin_lock_irqsave(&sdos->lock, flags); - if (sd->lockcount) { - sd_err(("%s: Already locked!\n", __FUNCTION__)); - ASSERT(sd->lockcount == 0); - } -#ifdef BCMSPI_ANDROID - if (sd->client_intr_enabled) - bcmsdh_oob_intr_set(0); -#else - spi_devintr_off(sd); -#endif /* BCMSPI_ANDROID */ - sd->lockcount++; - spin_unlock_irqrestore(&sdos->lock, flags); -} - -/* Enable client interrupt */ -void -spi_unlock(sdioh_info_t *sd) -{ - ulong flags; - struct sdos_info *sdos; - - sd_trace(("%s: %d, %d\n", __FUNCTION__, sd->lockcount, sd->client_intr_enabled)); - ASSERT(sd->lockcount > 0); - - sdos = (struct sdos_info *)sd->sdos_info; - ASSERT(sdos); - - spin_lock_irqsave(&sdos->lock, flags); - if (--sd->lockcount == 0 && sd->client_intr_enabled) { -#ifdef BCMSPI_ANDROID - bcmsdh_oob_intr_set(1); -#else - spi_devintr_on(sd); -#endif /* BCMSPI_ANDROID */ - } - spin_unlock_irqrestore(&sdos->lock, flags); -} - -#ifndef BCMSPI_ANDROID -void spi_waitbits(sdioh_info_t *sd, bool yield) -{ -#ifndef BCMSDYIELD - ASSERT(!yield); -#endif - sd_trace(("%s: yield %d canblock %d\n", - __FUNCTION__, yield, BLOCKABLE())); - - /* Clear the "interrupt happened" flag and last intrstatus */ - sd->got_hcint = FALSE; - -#ifdef BCMSDYIELD - if (yield && BLOCKABLE()) { - struct sdos_info *sdos; - sdos = (struct sdos_info *)sd->sdos_info; - /* Wait for the indication, the interrupt will be masked when the ISR fires. */ - wait_event_interruptible(sdos->intr_wait_queue, (sd->got_hcint)); - } else -#endif /* BCMSDYIELD */ - { - spi_spinbits(sd); - } - -} -#else /* !BCMSPI_ANDROID */ -int bcmgspi_dump = 0; /* Set to dump complete trace of all SPI bus transactions */ - -static void -hexdump(char *pfx, unsigned char *msg, int msglen) -{ - int i, col; - char buf[80]; - - ASSERT(strlen(pfx) + 49 <= sizeof(buf)); - - col = 0; - - for (i = 0; i < msglen; i++, col++) { - if (col % 16 == 0) - strcpy(buf, pfx); - sprintf(buf + strlen(buf), "%02x", msg[i]); - if ((col + 1) % 16 == 0) - printf("%s\n", buf); - else - sprintf(buf + strlen(buf), " "); - } - - if (col % 16 != 0) - printf("%s\n", buf); -} - -/* Send/Receive an SPI Packet */ -void -spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen) -{ - int write = 0; - int tx_len = 0; - struct spi_message msg; - struct spi_transfer t[2]; - - spi_message_init(&msg); - memset(t, 0, 2*sizeof(struct spi_transfer)); - - if (sd->wordlen == 2) -#if !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW)) - write = msg_out[2] & 0x80; /* XXX bit 7: read:0, write :1 */ -#else - write = msg_out[1] & 0x80; /* XXX bit 7: read:0, write :1 */ -#endif /* !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW)) */ - if (sd->wordlen == 4) -#if !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW)) - write = msg_out[0] & 0x80; /* XXX bit 7: read:0, write :1 */ -#else - write = msg_out[3] & 0x80; /* XXX bit 7: read:0, write :1 */ -#endif /* !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW)) */ - - if (bcmgspi_dump) { - hexdump(" OUT: ", msg_out, msglen); - } - - tx_len = write ? msglen-4 : 4; - - sd_trace(("spi_sendrecv: %s, wordlen %d, cmd : 0x%02x 0x%02x 0x%02x 0x%02x\n", - write ? "WR" : "RD", sd->wordlen, - msg_out[0], msg_out[1], msg_out[2], msg_out[3])); - - t[0].tx_buf = (char *)&msg_out[0]; - t[0].rx_buf = 0; - t[0].len = tx_len; - - spi_message_add_tail(&t[0], &msg); - - t[1].rx_buf = (char *)&msg_in[tx_len]; - t[1].tx_buf = 0; - t[1].len = msglen-tx_len; - - spi_message_add_tail(&t[1], &msg); - spi_sync(gBCMSPI, &msg); - - if (bcmgspi_dump) { - hexdump(" IN : ", msg_in, msglen); - } -} -#endif /* !BCMSPI_ANDROID */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd.c old mode 100755 new mode 100644 index b58de6263902..7783751d7ad5 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd.c @@ -1,7 +1,7 @@ /* * 'Standard' SDIO HOST CONTROLLER driver * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -134,38 +134,46 @@ uint32 sd3_autoselect_uhsi_max = 0; * All has DrvStr as 'B' [val:0] and CLKGEN as 0. */ static unsigned short presetval_sw_table[] = { - 0x0520, /* initialization: DrvStr:'B' [0]; CLKGen:0; + 0x0520, /* initialization: DrvStr:'B' [0]; CLKGen:0; * SDCLKFreqSel: 520 [division: 320*2 = 640: ~400 KHz] */ 0x0008, /* default speed:DrvStr:'B' [0]; CLKGen:0; * SDCLKFreqSel: 8 [division: 6*2 = 12: ~25 MHz] */ - 0x0004, /* High speed: DrvStr:'B' [0]; CLKGen:0; + 0x0004, /* High speed: DrvStr:'B' [0]; CLKGen:0; * SDCLKFreqSel: 4 [division: 3*2 = 6: ~50 MHz] */ - 0x0008, /* SDR12: DrvStr:'B' [0]; CLKGen:0; + 0x0008, /* SDR12: DrvStr:'B' [0]; CLKGen:0; * SDCLKFreqSel: 8 [division: 6*2 = 12: ~25 MHz] */ - 0x0004, /* SDR25: DrvStr:'B' [0]; CLKGen:0; + 0x0004, /* SDR25: DrvStr:'B' [0]; CLKGen:0; * SDCLKFreqSel: 4 [division: 3*2 = 6: ~50 MHz] */ - 0x0001, /* SDR50: DrvStr:'B' [0]; CLKGen:0; + 0x0001, /* SDR50: DrvStr:'B' [0]; CLKGen:0; * SDCLKFreqSel: 2 [division: 1*2 = 2: ~100 MHz] */ - 0x0001, /* SDR104: DrvStr:'B' [0]; CLKGen:0; + 0x0001, /* SDR104: DrvStr:'B' [0]; CLKGen:0; SDCLKFreqSel: 1 [no division: ~255/~208 MHz] */ - 0x0002 /* DDR50: DrvStr:'B' [0]; CLKGen:0; + 0x0002 /* DDR50: DrvStr:'B' [0]; CLKGen:0; SDCLKFreqSel: 4 [division: 3*2 = 6: ~50 MHz] */ }; +#ifdef BCMFPGA_HW +/* + * Voltage switch, clock tuning and preset are not supported in + * FPGA which operates at 6.25Mhz. + */ +bool sd3_sw_override1 = TRUE; +#else /* This is to have software overrides to the hardware. Info follows: - For override [1]: Preset registers: not supported + For override [1]: Preset registers: not supported Voltage switch: not supported Clock Tuning: not supported */ bool sd3_sw_override1 = FALSE; +#endif /* BCMFPGA_HW */ bool sd3_sw_read_magic_bytes = FALSE; #define SD3_TUNING_REQD(sd, sd_uhsimode) ((sd_uhsimode != SD3CLKMODE_DISABLED) && \ @@ -248,14 +256,6 @@ static bool sdstd_3_get_matching_drvstrn(sdioh_info_t *sd, static int sdstd_3_clock_wrapper(sdioh_info_t *sd); static int sdstd_clock_wrapper(sdioh_info_t *sd); -#ifdef BCMINTERNAL -#ifdef NOTUSED -static int parse_caps(uint32 caps_reg, char *buf, int len); -static int parse_state(uint32 state_reg, char *buf, int len); -static void cis_fetch(sdioh_info_t *sd, int func, char *data, int len); -#endif /* NOTUSED */ -#endif /* BCMINTERNAL */ - #ifdef BCMDBG static void print_regs(sdioh_info_t *sd); #endif @@ -321,25 +321,6 @@ sdstd_wreg(sdioh_info_t *sd, uint reg, uint32 data) sd_ctrl(("32: W Reg 0x%02x, Data 0x%x\n", reg, data)); } -#ifdef BCMINTERNAL -#ifdef NOTUSED -static void -sdstd_or_reg(sdioh_info_t *sd, uint reg, uint32 val) -{ - volatile uint32 data = *(volatile uint32 *)(sd->mem_space + reg); - data |= val; - *(volatile uint32 *)(sd->mem_space + reg) = (volatile uint32)data; -} -static void -sdstd_mod_reg(sdioh_info_t *sd, uint reg, uint32 mask, uint32 val) -{ - volatile uint32 data = *(volatile uint32 *)(sd->mem_space + reg); - data &= ~mask; - data |= (val & mask); - *(volatile uint32 *)(sd->mem_space + reg) = (volatile uint32)data; -} -#endif /* NOTUSED */ -#endif /* BCMINTERNAL */ /* 8 bit PCI regs */ static inline void @@ -545,7 +526,8 @@ enum { IOV_CLOCK, IOV_UHSIMOD, IOV_TUNEMOD, - IOV_TUNEDIS + IOV_TUNEDIS, + IOV_DS }; const bcm_iovar_t sdioh_iovars[] = { @@ -575,6 +557,7 @@ const bcm_iovar_t sdioh_iovars[] = { #endif {"tuning_mode", IOV_TUNEMOD, 0, 0, IOVT_UINT32, 0}, {"sd3_tuning_disable", IOV_TUNEDIS, 0, 0, IOVT_BOOL, 0}, + {"sd_ds", IOV_DS, 0, 0, IOVT_UINT32, 0}, {NULL, 0, 0, 0, 0, 0 } }; @@ -1024,6 +1007,58 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name, si->sd3_tuning_disable = (bool)int_val; break; + case IOV_GVAL(IOV_DS): + { + uint32 drvstrn; + int status; + + status = sdstd_card_regread(si, 0, SDIOD_CCCR_DRIVER_STRENGTH, 1, &drvstrn); + if (status != BCME_OK) { + sd_err(("sd_ds error for read SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n", + status)); + bcmerror = BCME_SDIO_ERROR; + } else { + sd_err(("sd_ds get cccr driver strength 0x%x\n", drvstrn)); + } + int_val = (uint32)drvstrn; + bcopy(&int_val, arg, val_size); + break; + } + + case IOV_SVAL(IOV_DS): + { + uint32 drvstrn; + int status; + + status = sdstd_card_regread(si, 0, SDIOD_CCCR_DRIVER_STRENGTH, 1, &drvstrn); + if (status != BCME_OK) { + sd_err(("sd_ds error for read SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n", + status)); + bcmerror = BCME_SDIO_ERROR; + } else { + sd_err(("sd_ds get cccr driver strength 0x%x\n", drvstrn)); + } + + if (int_val == 0) { + drvstrn = ((drvstrn & 0xf) | 0x0); + } else if (int_val == 1) { + drvstrn = ((drvstrn & 0xf) | 0x10); + } else if (int_val == 2) { + drvstrn = ((drvstrn & 0xf) | 0x20); + } else if (int_val == 3) { + drvstrn = ((drvstrn & 0xf) | 0x30); + } else { + bcmerror = BCME_BADARG; + break; + } + + status = sdstd_card_regwrite(si, 0, SDIOD_CCCR_DRIVER_STRENGTH, 1, drvstrn); + if (status != BCME_OK) { + sd_err(("sd_ds error write SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n", status)); + } + break; + } + default: bcmerror = BCME_UNSUPPORTED; break; @@ -1834,15 +1869,6 @@ sdstd_check_errs(sdioh_info_t *sdioh_info, uint32 cmd, uint32 arg) return ERROR; } -#ifdef BCMINTERNAL -extern SDIOH_API_RC -sdioh_test_diag(sdioh_info_t *sd) -{ - sd_err(("%s: Implement me\n", __FUNCTION__)); - return (0); -} -#endif /* BCMINTERNAL */ - /* * Private/Static work routines */ @@ -1988,12 +2014,6 @@ sdstd_host_init(sdioh_info_t *sd) __FUNCTION__)); sd->controller_type = SDIOH_TYPE_JMICRON; detect_slots = TRUE; -#ifdef BCMINTERNAL - } else if ((OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_VID, 4) & 0xFFFF) == VENDOR_JINVANI) { - sd_info(("%s: Found Jinvani Standard SDIO Host Controller\n", __FUNCTION__)); - detect_slots = FALSE; - sd->controller_type = SDIOH_TYPE_JINVANI_GOLD; -#endif /* BCMINTERNAL */ } else { return ERROR; } @@ -2127,46 +2147,6 @@ sdstd_host_init(sdioh_info_t *sd) sdstd_set_dma_mode(sd, sd->sd_dma_mode); -#if defined(BCMINTERNAL) - if (OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_VID, 4) == - ((SDIOH_FPGA_ID << 16) | VENDOR_BROADCOM)) { - sd_err(("* * * SDIO20H FPGA Build Date: 0x%04x\n", sdstd_rreg(sd, 0x110))); - } - - if (GFIELD(sd->caps, CAP_MAXBLOCK) == 0x3) { - sd_info(("SD HOST CAPS: Max block size is INVALID\n")); - } else { - sd_info(("SD HOST CAPS: Max block size is %d bytes\n", - 512 << GFIELD(sd->caps, CAP_MAXBLOCK))); - } - - sd_info(("SD HOST CAPS: 64-bit DMA is %ssupported.\n", - GFIELD(sd->caps, CAP_64BIT_HOST) ? "" : "not ")); - sd_info(("SD HOST CAPS: Suspend/Resume is %ssupported.\n", - GFIELD(sd->caps, CAP_SUSPEND) ? "" : "not ")); - - sd_err(("SD HOST CAPS: SD Host supports ")); - if (GFIELD(sd->caps, CAP_VOLT_3_3)) { - sd_err(("3.3V")); - if (GFIELD(sd->curr_caps, CAP_CURR_3_3)) { - sd_err(("@%dmA\n", 4*GFIELD(sd->curr_caps, CAP_CURR_3_3))); - } - } - if (GFIELD(sd->caps, CAP_VOLT_3_0)) { - sd_err((", 3.0V")); - if (GFIELD(sd->curr_caps, CAP_CURR_3_0)) { - sd_err(("@%dmA\n", 4*GFIELD(sd->curr_caps, CAP_CURR_3_0))); - } - } - if (GFIELD(sd->caps, CAP_VOLT_1_8)) { - sd_err((", 1.8V")); - if (GFIELD(sd->curr_caps, CAP_CURR_1_8)) { - sd_err(("@%dmA\n", 4*GFIELD(sd->curr_caps, CAP_CURR_1_8))); - } - } - sd_err(("\n")); -#endif /* defined(BCMINTERNAL) */ - sdstd_reset(sd, 1, 0); /* Read SD4/SD1 mode */ @@ -2257,15 +2237,6 @@ sdstd_client_init(sdioh_info_t *sd) uint32 regdata; uint16 powerstat = 0; -#ifdef BCMINTERNAL -#ifdef NOTUSED - /* Handy routine to dump capabilities. */ - static char caps_buf[500]; - parse_caps(sd->caps, caps_buf, 500); - sd_err((caps_buf)); -#endif /* NOTUSED */ -#endif /* BCMINTERNAL */ - sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); /* Clear any pending ints */ @@ -2433,11 +2404,24 @@ sdstd_client_init(sdioh_info_t *sd) static int sdstd_clock_wrapper(sdioh_info_t *sd) { + uint ret = 0; sd_trace(("%s:Enter\n", __FUNCTION__)); /* After configuring for High-Speed mode, set the desired clock rate. */ sdstd_set_highspeed_mode(sd, (bool)sd_hiok); - if (FALSE == sdstd_start_clock(sd, (uint16)sd_divisor)) { +#ifdef BCMFPGA_HW + /* + * To make the SDIO clock 6.25Mhz for FPGA divide the + * standard clock with 8 insted of default 2. 50Mhz/8 = 6.25Mhz + * sdstd_clock_wrapper() is used to start clock for default and + * high speed only. + */ + sd_err(("%s set 6.25Mhz clock speed for FPGA default or high speed\n", __FUNCTION__)); + ret = sdstd_start_clock(sd, ((uint16)sd_divisor * 4)); +#else + ret = sdstd_start_clock(sd, (uint16)sd_divisor); +#endif /* BCMFPGA_HW */ + if (ret != TRUE) { sd_err(("sdstd_start_clock failed\n")); return ERROR; } @@ -2693,6 +2677,7 @@ sdstd_3_set_highspeed_uhsi_mode(sdioh_info_t *sd, int sd3ClkMode) uint8 hc_reg8; uint16 val1 = 0, presetval = 0; uint32 regdata; + uint32 ret = 0; sd3_trace(("sd3: %s:enter:clkmode:%d\n", __FUNCTION__, sd3ClkMode)); @@ -2780,9 +2765,19 @@ sdstd_3_set_highspeed_uhsi_mode(sdioh_info_t *sd, int sd3ClkMode) sdstd_wreg16(sd, SD3_HostCntrl2, val1); sd_err(("%s:HostCtrl2 final value:0x%x\n", __FUNCTION__, val1)); - +#ifdef BCMFPGA_HW + /* + * To make the SDIO clock 6.25Mhz for FPGA divide the + * standard clock with 0x20. 208Mhz/32 = 6.25Mhz + * this function is invoked to start clock for UHSI mode only + */ + sd_err(("%s set 6.25Mhz clock speed for UHSI speed\n", __FUNCTION__)); + ret = sdstd_start_clock(sd, 0x20); +#else + ret = sdstd_start_clock(sd, GFIELD(presetval, PRESET_CLK_DIV)); +#endif /* BCMFPGA_HW */ + if (ret != TRUE) { /* start clock : clk will be enabled inside. */ - if (FALSE == sdstd_start_clock(sd, GFIELD(presetval, PRESET_CLK_DIV))) { sd_err(("sdstd_start_clock failed\n")); return ERROR; } @@ -3143,16 +3138,6 @@ sdstd_set_highspeed_mode(sdioh_info_t *sd, bool HSMode) reg8 = sdstd_rreg8(sd, SD_HostCntrl); -#ifdef BCMINTERNAL - /* The Jinvani SD Gold Host forces the highest clock rate in high-speed mode */ - /* Only enable high-speed mode if the SD clock divisor is 1. */ - if (sd->controller_type == SDIOH_TYPE_JINVANI_GOLD) { - if (sd_divisor != 1) { - HSMode = FALSE; - } - } -#endif /* BCMINTERNAL */ - if (HSMode == TRUE) { if (sd_hiok && (GFIELD(sd->caps, CAP_HIGHSPEED)) == 0) { sd_err(("Host Controller does not support hi-speed mode.\n")); @@ -3409,61 +3394,6 @@ print_regs(sdioh_info_t *sd) } #endif /* BCMDBG */ -#ifdef BCMINTERNAL -#ifdef NOTUSED -static int -parse_state(uint32 state, char *buf, int len) -{ - char *data = buf; - - sd_err(("Parsing state 0x%x\n", state)); - if (!len) { - return (0); - } - - data += sprintf(data, "cmd_inhibit %d\n", GFIELD(state, PRES_CMD_INHIBIT)); - data += sprintf(data, "dat_inhibit %d\n", GFIELD(state, PRES_DAT_INHIBIT)); - data += sprintf(data, "dat_busy %d\n", GFIELD(state, PRES_DAT_BUSY)); - data += sprintf(data, "write_active %d\n", GFIELD(state, PRES_WRITE_ACTIVE)); - data += sprintf(data, "read_active %d\n", GFIELD(state, PRES_READ_ACTIVE)); - data += sprintf(data, "write_data_rdy %d\n", GFIELD(state, PRES_WRITE_DATA_RDY)); - data += sprintf(data, "read_data_rdy %d\n", GFIELD(state, PRES_READ_DATA_RDY)); - data += sprintf(data, "card_present %d\n", GFIELD(state, PRES_CARD_PRESENT)); - data += sprintf(data, "card_stable %d\n", GFIELD(state, PRES_CARD_STABLE)); - data += sprintf(data, "card_present_raw %d\n", GFIELD(state, PRES_CARD_PRESENT_RAW)); - data += sprintf(data, "write_enabled %d\n", GFIELD(state, PRES_WRITE_ENABLED)); - data += sprintf(data, "cmd_signal %d\n", GFIELD(state, PRES_CMD_SIGNAL)); - - return (data - buf); -} - -static int -parse_caps(uint32 cap, char *buf, int len) -{ - int block = 0xbeef; - char *data = buf; - - data += sprintf(data, "TimeOut Clock Freq:\t%d\n", GFIELD(cap, CAP_TO_CLKFREQ)); - data += sprintf(data, "TimeOut Clock Unit:\t%d\n", GFIELD(cap, CAP_TO_CLKUNIT)); - data += sprintf(data, "Base Clock:\t\t%d\n", GFIELD(cap, CAP_BASECLK)); - switch (GFIELD(cap, CAP_MAXBLOCK)) { - case 0: block = 512; break; - case 1: block = 1024; break; - case 2: block = 2048; break; - case 3: block = 0; break; - } - data += sprintf(data, "Max Block Size:\t\t%d\n", block); - data += sprintf(data, "Support High Speed:\t%d\n", GFIELD(cap, CAP_HIGHSPEED)); - data += sprintf(data, "Support DMA:\t\t%d\n", GFIELD(cap, CAP_DMA)); - data += sprintf(data, "Support Suspend:\t%d\n", GFIELD(cap, CAP_SUSPEND)); - data += sprintf(data, "Support 3.3 Volts:\t%d\n", GFIELD(cap, CAP_VOLT_3_3)); - data += sprintf(data, "Support 3.0 Volts:\t%d\n", GFIELD(cap, CAP_VOLT_3_0)); - data += sprintf(data, "Support 1.8 Volts:\t%d\n", GFIELD(cap, CAP_VOLT_1_8)); - return (data - buf); -} -#endif /* NOTUSED */ -#endif /* BCMINTERNAL */ - /* XXX Per SDIO Host Controller Spec section 3.2.1 Note: for 2.x HC, new_sd_divisor should be a power of 2, but for 3.0 HC, new_sd_divisor should be a multiple of 2. @@ -3507,11 +3437,6 @@ sdstd_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor) new_sd_divisor = 256; divisor = (new_sd_divisor >> 1) << 8; } -#ifdef BCMINTERNAL - if (sd->controller_type == SDIOH_TYPE_JINVANI_GOLD) { - divisor = (new_sd_divisor >> 2) << 8; - } -#endif /* BCMINTERNAL */ sd_info(("Clock control is 0x%x\n", sdstd_rreg16(sd, SD_ClockCntrl))); if (sd->host_UHSISupported) { @@ -3848,6 +3773,7 @@ voltsel: * val1 = SFIELD(val1, HOSTCtrl2_1_8SIG_EN, 1); * sdstd_wreg16(sd, SD3_HostCntrl2, val1); */ + sd_info(("%s: Not sdio3.0: host_UHSISupported: %d; HC volts=%d\n", __FUNCTION__, sd->host_UHSISupported, volts)); } @@ -5143,30 +5069,6 @@ sdioh_sdio_reset(sdioh_info_t *si) return sdstd_client_init(si); } -#ifdef BCMINTERNAL -#ifdef NOTUSED -static void -cis_fetch(sdioh_info_t *sd, int func, char *data, int len) -{ - int count; - int offset; - char *end = data + len; - uint32 foo; - - for (count = 0; count < 512 && data < end; count++) { - offset = sd->func_cis_ptr[func] + count; - if (sdstd_card_regread (sd, func, offset, 1, &foo) < 0) { - sd_err(("%s: regread failed\n", __FUNCTION__)); - return; - } - data += sprintf(data, "%.2x ", foo & 0xff); - if (((count+1) % 16) == 0) - data += sprintf(data, "\n"); - } -} -#endif /* NOTUSED */ -#endif /* BCMINTERNAL */ - static void sd_map_dma(sdioh_info_t * sd) { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd.h old mode 100755 new mode 100644 index e0d19e2ade0f..de742ed544a9 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd.h @@ -1,7 +1,7 @@ /* * 'Standard' SDIO HOST CONTROLLER driver * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -20,7 +20,7 @@ * * <> * - * $Id: bcmsdstd.h 833030 2019-08-02 17:22:42Z jl904071 $ + * $Id: bcmsdstd.h 833030 2019-08-02 17:22:42Z $ */ #ifndef _BCM_SD_STD_H #define _BCM_SD_STD_H @@ -80,9 +80,6 @@ extern void sdstd_osfree(sdioh_info_t *sd); #define SDIOH_TYPE_ARASAN_HDK 1 #define SDIOH_TYPE_BCM27XX 2 -#ifdef BCMINTERNAL -#define SDIOH_TYPE_JINVANI_GOLD 3 -#endif #define SDIOH_TYPE_TI_PCIXX21 4 /* TI PCIxx21 Standard Host Controller */ #define SDIOH_TYPE_RICOH_R5C822 5 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter */ #define SDIOH_TYPE_JMICRON 6 /* JMicron Standard SDIO Host Controller */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd_linux.c old mode 100755 new mode 100644 index be635ae898f7..11d3f09f37d6 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd_linux.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdstd_linux.c @@ -1,7 +1,7 @@ /* * 'Standard' SDIO HOST CONTROLLER driver - linux portion * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -515,8 +515,15 @@ static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = { class: 0, class_mask: 0, driver_data: 0, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) + override_only: 0, +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) */ }, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) + { 0, 0, 0, 0, 0, 0, 0, 0} +#else { 0, 0, 0, 0, 0, 0, 0} +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) */ }; MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmspibrcm.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmspibrcm.c deleted file mode 100755 index e58d0cff9eae..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmspibrcm.c +++ /dev/null @@ -1,1922 +0,0 @@ -/* - * Broadcom BCMSDH to gSPI Protocol Conversion Layer - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - */ - -#ifdef BCMDONGLEHOST -#define HSMODE -#else -#endif /* BCMDONGLEHOST */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include /* SDIO device core hardware definitions. */ -#include - -#include /* bcmsdh to/from specific controller APIs */ -#include /* ioctl/iovars */ -#include /* SDIO Device and Protocol Specs */ - -#if defined(linux) -#include -#endif - -/* XXX Quick NDIS hack */ -#ifdef NDIS -#define inline __inline -#define PCI_CFG_VID 0 -#define PCI_CFG_BAR0 0x10 -#endif - -#include -#ifdef BCMSPI_ANDROID -extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen); -#else -#include -#endif /* BCMSPI_ANDROID */ - -/* these are for the older cores... for newer cores we have control for each of them */ -#define F0_RESPONSE_DELAY 16 -#define F1_RESPONSE_DELAY 16 -#define F2_RESPONSE_DELAY F0_RESPONSE_DELAY - -#define GSPI_F0_RESP_DELAY 0 -#define GSPI_F1_RESP_DELAY F1_RESPONSE_DELAY -#define GSPI_F2_RESP_DELAY 0 -#define GSPI_F3_RESP_DELAY 0 - -#define CMDLEN 4 - -/* Globals */ -#if defined(BCMDBG) || defined(DHD_DEBUG) -uint sd_msglevel = SDH_ERROR_VAL; -#else -uint sd_msglevel = 0; -#endif /* BCMDBG || DHD_DEBUG */ - -uint sd_hiok = FALSE; /* Use hi-speed mode if available? */ -uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */ -uint sd_f2_blocksize = 64; /* Default blocksize */ - -uint sd_divisor = 2; -uint sd_power = 1; /* Default to SD Slot powered ON */ -uint sd_clock = 1; /* Default to SD Clock turned ON */ -uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */ -uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */ - -uint8 spi_outbuf[SPI_MAX_PKT_LEN]; -uint8 spi_inbuf[SPI_MAX_PKT_LEN]; - -/* 128bytes buffer is enough to clear data-not-available and program response-delay F0 bits - * assuming we will not exceed F0 response delay > 100 bytes at 48MHz. - */ -#define BUF2_PKT_LEN 128 -uint8 spi_outbuf2[BUF2_PKT_LEN]; -uint8 spi_inbuf2[BUF2_PKT_LEN]; -#ifdef BCMSPI_ANDROID -uint *dhd_spi_lockcount = NULL; -#endif /* BCMSPI_ANDROID */ - -#if !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW)) -#define SPISWAP_WD4(x) bcmswap32(x); -#define SPISWAP_WD2(x) (bcmswap16(x & 0xffff)) | \ - (bcmswap16((x & 0xffff0000) >> 16) << 16); -#else -/* XXX Some SPI host controller changes endianness when writing/reading -* to/from SPI device TX/RX register in case the bits_per_word is more than 1 byte. -*/ -#define SPISWAP_WD4(x) x; -#define SPISWAP_WD2(x) bcmswap32by16(x); -#endif - -/* Prototypes */ -static bool bcmspi_test_card(sdioh_info_t *sd); -static bool bcmspi_host_device_init_adapt(sdioh_info_t *sd); -static int bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode); -static int bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, - uint32 *data, uint32 datalen); -static int bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, - int regsize, uint32 *data); -static int bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, - int regsize, uint32 data); -static int bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, - uint8 *data); -static int bcmspi_driver_init(sdioh_info_t *sd); -static int bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, - uint32 addr, int nbytes, uint32 *data); -static int bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, - uint32 *data); -static void bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer); -static int bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg); - -/* - * Public entry points & extern's - */ -extern sdioh_info_t * -sdioh_attach(osl_t *osh, void *bar0, uint irq) -{ - sdioh_info_t *sd; - - sd_trace(("%s\n", __FUNCTION__)); - if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { - sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh))); - return NULL; - } - bzero((char *)sd, sizeof(sdioh_info_t)); - sd->osh = osh; - if (spi_osinit(sd) != 0) { - sd_err(("%s: spi_osinit() failed\n", __FUNCTION__)); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return NULL; - } - -#ifndef BCMSPI_ANDROID - sd->bar0 = bar0; -#endif /* !BCMSPI_ANDROID */ - sd->irq = irq; -#ifndef BCMSPI_ANDROID - sd->intr_handler = NULL; - sd->intr_handler_arg = NULL; - sd->intr_handler_valid = FALSE; -#endif /* !BCMSPI_ANDROID */ - - /* Set defaults */ - sd->use_client_ints = TRUE; - sd->sd_use_dma = FALSE; /* DMA Not supported */ - - /* Spi device default is 16bit mode, change to 4 when device is changed to 32bit - * mode - */ - sd->wordlen = 2; - -#ifdef BCMSPI_ANDROID - dhd_spi_lockcount = &sd->lockcount; -#endif /* BCMSPI_ANDROID */ - -#ifndef BCMSPI_ANDROID - if (!spi_hw_attach(sd)) { - sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__)); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } -#endif /* !BCMSPI_ANDROID */ - - if (bcmspi_driver_init(sd) != SUCCESS) { - sd_err(("%s: bcmspi_driver_init() failed()\n", __FUNCTION__)); -#ifndef BCMSPI_ANDROID - spi_hw_detach(sd); -#endif /* !BCMSPI_ANDROID */ - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } - - if (spi_register_irq(sd, irq) != SUCCESS) { - sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq)); -#ifndef BCMSPI_ANDROID - spi_hw_detach(sd); -#endif /* !BCMSPI_ANDROID */ - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } - - sd_trace(("%s: Done\n", __FUNCTION__)); - - return sd; -} - -extern SDIOH_API_RC -sdioh_detach(osl_t *osh, sdioh_info_t *sd) -{ - sd_trace(("%s\n", __FUNCTION__)); - if (sd) { - sd_err(("%s: detaching from hardware\n", __FUNCTION__)); - spi_free_irq(sd->irq, sd); -#ifndef BCMSPI_ANDROID - spi_hw_detach(sd); -#endif /* !BCMSPI_ANDROID */ - spi_osfree(sd); -#ifdef BCMSPI_ANDROID - dhd_spi_lockcount = NULL; -#endif /* !BCMSPI_ANDROID */ - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - } - return SDIOH_API_RC_SUCCESS; -} - -/* Configure callback to client when we recieve client interrupt */ -extern SDIOH_API_RC -sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); -#if !defined(OOB_INTR_ONLY) - sd->intr_handler = fn; - sd->intr_handler_arg = argh; - sd->intr_handler_valid = TRUE; -#endif /* !defined(OOB_INTR_ONLY) */ - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_deregister(sdioh_info_t *sd) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); -#if !defined(OOB_INTR_ONLY) - sd->intr_handler_valid = FALSE; - sd->intr_handler = NULL; - sd->intr_handler_arg = NULL; -#endif /* !defined(OOB_INTR_ONLY) */ - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) -{ -#ifndef BCMSPI_ANDROID - sd_trace(("%s: Entering\n", __FUNCTION__)); - *onoff = sd->client_intr_enabled; -#endif /* !BCMSPI_ANDROID */ - return SDIOH_API_RC_SUCCESS; -} - -#if defined(DHD_DEBUG) || defined(BCMDBG) -extern bool -sdioh_interrupt_pending(sdioh_info_t *sd) -{ - return 0; -} -#endif - -/* Provide dstatus bits of spi-transaction for dhd layers. */ -extern uint32 -sdioh_get_dstatus(sdioh_info_t *sd) -{ - return sd->card_dstatus; -} - -extern void -sdioh_chipinfo(sdioh_info_t *sd, uint32 chip, uint32 chiprev) -{ - sd->chip = chip; - sd->chiprev = chiprev; -} - -extern void -sdioh_dwordmode(sdioh_info_t *sd, bool set) -{ - uint8 reg = 0; - int status; - - if ((status = sdioh_request_byte(sd, SDIOH_READ, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != - SUCCESS) { - sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); - return; - } - - if (set) { - reg |= DWORD_PKT_LEN_EN; - sd->dwordmode = TRUE; - sd->client_block_size[SPI_FUNC_2] = 4096; /* h2spi's limit is 4KB, we support 8KB */ - } else { - reg &= ~DWORD_PKT_LEN_EN; - sd->dwordmode = FALSE; - sd->client_block_size[SPI_FUNC_2] = 2048; - } - - if ((status = sdioh_request_byte(sd, SDIOH_WRITE, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != - SUCCESS) { - sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); - return; - } -} - -uint -sdioh_query_iofnum(sdioh_info_t *sd) -{ - return sd->num_funcs; -} - -/* IOVar table */ -enum { - IOV_MSGLEVEL = 1, - IOV_BLOCKMODE, - IOV_BLOCKSIZE, - IOV_DMA, - IOV_USEINTS, - IOV_NUMINTS, - IOV_NUMLOCALINTS, - IOV_HOSTREG, - IOV_DEVREG, - IOV_DIVISOR, - IOV_SDMODE, - IOV_HISPEED, - IOV_HCIREGS, - IOV_POWER, - IOV_CLOCK, - IOV_SPIERRSTATS, - IOV_RESP_DELAY_ALL -}; - -const bcm_iovar_t sdioh_iovars[] = { - {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, - {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ - {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, - {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, - {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, - {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, - {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, - {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, - {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, - {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, - {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0}, -#ifdef BCMDBG - {"sd_hciregs", IOV_HCIREGS, 0, IOVT_BUFFER, 0 }, -#endif - {"spi_errstats", IOV_SPIERRSTATS, 0, IOVT_BUFFER, sizeof(struct spierrstats_t) }, - {"spi_respdelay", IOV_RESP_DELAY_ALL, 0, IOVT_BOOL, 0 }, - {NULL, 0, 0, 0, 0 } -}; - -int -sdioh_iovar_op(sdioh_info_t *si, const char *name, - void *params, int plen, void *arg, uint len, bool set) -{ - const bcm_iovar_t *vi = NULL; - int bcmerror = 0; - uint val_size; - int32 int_val = 0; - bool bool_val; - uint32 actionid; -/* - sdioh_regs_t *regs; -*/ - - ASSERT(name); - ASSERT(len >= 0); - - /* Get must have return space; Set does not take qualifiers */ - ASSERT(set || (arg && len)); - ASSERT(!set || (!params && !plen)); - - sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); - - if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { - bcmerror = BCME_UNSUPPORTED; - goto exit; - } - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) - goto exit; - - /* XXX Copied from dhd, copied from wl; certainly overkill here? */ - /* Set up params so get and set can share the convenience variables */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - val_size = sizeof(int); - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - bool_val = (int_val != 0) ? TRUE : FALSE; - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - switch (actionid) { - case IOV_GVAL(IOV_MSGLEVEL): - int_val = (int32)sd_msglevel; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MSGLEVEL): - sd_msglevel = int_val; - break; - - case IOV_GVAL(IOV_BLOCKSIZE): - if ((uint32)int_val > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - int_val = (int32)si->client_block_size[int_val]; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_DMA): - int_val = (int32)si->sd_use_dma; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DMA): - si->sd_use_dma = (bool)int_val; - break; - - case IOV_GVAL(IOV_USEINTS): - int_val = (int32)si->use_client_ints; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_USEINTS): - break; - - case IOV_GVAL(IOV_DIVISOR): - int_val = (uint32)sd_divisor; - bcopy(&int_val, arg, val_size); - break; - -#ifndef BCMSPI_ANDROID - case IOV_SVAL(IOV_DIVISOR): - sd_divisor = int_val; - if (!spi_start_clock(si, (uint16)sd_divisor)) { - sd_err(("%s: set clock failed\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - } - break; -#endif /* !BCMSPI_ANDROID */ - - case IOV_GVAL(IOV_POWER): - int_val = (uint32)sd_power; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_POWER): - sd_power = int_val; - break; - - case IOV_GVAL(IOV_CLOCK): - int_val = (uint32)sd_clock; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_CLOCK): - sd_clock = int_val; - break; - - case IOV_GVAL(IOV_SDMODE): - int_val = (uint32)sd_sdmode; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDMODE): - sd_sdmode = int_val; - break; - - case IOV_GVAL(IOV_HISPEED): - int_val = (uint32)sd_hiok; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_HISPEED): - sd_hiok = int_val; - - if (!bcmspi_set_highspeed_mode(si, (bool)sd_hiok)) { - sd_err(("%s: Failed changing highspeed mode to %d.\n", - __FUNCTION__, sd_hiok)); - bcmerror = BCME_ERROR; - return ERROR; - } - break; - - case IOV_GVAL(IOV_NUMINTS): - int_val = (int32)si->intrcount; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_NUMLOCALINTS): - int_val = (int32)si->local_intrcount; - bcopy(&int_val, arg, val_size); - break; - case IOV_GVAL(IOV_DEVREG): - { - /* XXX Should copy for alignment reasons */ - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data; - - if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - - int_val = (int)data; - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_DEVREG): - { - /* XXX Should copy for alignment reasons */ - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data = (uint8)sd_ptr->value; - - if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - break; - } - -#ifdef BCMDBG - case IOV_GVAL(IOV_HCIREGS): - { - struct bcmstrbuf b; - bcm_binit(&b, arg, len); - - spi_lock(si); - bcm_bprintf(&b, "Unsupported\n"); - spi_unlock(si); - - if (!b.size) - bcmerror = BCME_BUFTOOSHORT; - break; - } -#endif /* BCMDBG */ - - case IOV_GVAL(IOV_SPIERRSTATS): - { - bcopy(&si->spierrstats, arg, sizeof(struct spierrstats_t)); - break; - } - - case IOV_SVAL(IOV_SPIERRSTATS): - { - bzero(&si->spierrstats, sizeof(struct spierrstats_t)); - break; - } - - case IOV_GVAL(IOV_RESP_DELAY_ALL): - int_val = (int32)si->resp_delay_all; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_RESP_DELAY_ALL): - si->resp_delay_all = (bool)int_val; - int_val = STATUS_ENABLE|INTR_WITH_STATUS; - if (si->resp_delay_all) - int_val |= RESP_DELAY_ALL; - else { - if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_RESPONSE_DELAY, 1, - F1_RESPONSE_DELAY) != SUCCESS) { - sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - break; - } - } - - if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, int_val) - != SUCCESS) { - sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - break; - } - break; - - default: - bcmerror = BCME_UNSUPPORTED; - break; - } -exit: - - /* XXX Remove protective lock after clients all clean... */ - return bcmerror; -} - -extern SDIOH_API_RC -sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - SDIOH_API_RC status; - /* No lock needed since sdioh_request_byte does locking */ - status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); - return status; -} - -extern SDIOH_API_RC -sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - /* No lock needed since sdioh_request_byte does locking */ - SDIOH_API_RC status; - - /* WAR for gSPI for PR55208: Read SFC_WF_TERM before write for write to be - * successful on address SBSDIO_FUNC1_FRAMECTRL. - */ - if ((fnc_num == SPI_FUNC_1) && (addr == SBSDIO_FUNC1_FRAMECTRL)) { - uint8 dummy_data; - status = sdioh_cfg_read(sd, fnc_num, addr, &dummy_data); - if (status) { - sd_err(("sdioh_cfg_read() failed.\n")); - return status; - } - } - - status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); - return status; -} - -extern SDIOH_API_RC -sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) -{ - uint32 count; - int offset; - uint32 cis_byte; - uint16 *cis = (uint16 *)cisd; - uint bar0 = SI_ENUM_BASE(sd->sih); - int status; - uint8 data; - - sd_trace(("%s: Func %d\n", __FUNCTION__, func)); - - spi_lock(sd); - - /* Set sb window address to 0x18000000 */ - data = (bar0 >> 8) & SBSDIO_SBADDRLOW_MASK; - status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, &data); - if (status == SUCCESS) { - data = (bar0 >> 16) & SBSDIO_SBADDRMID_MASK; - status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, &data); - } else { - sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); - spi_unlock(sd); - return (BCME_ERROR); - } - if (status == SUCCESS) { - data = (bar0 >> 24) & SBSDIO_SBADDRHIGH_MASK; - status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, &data); - } else { - sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); - spi_unlock(sd); - return (BCME_ERROR); - } - - offset = CC_SROM_OTP; /* OTP offset in chipcommon. */ - for (count = 0; count < length/2; count++) { - if (bcmspi_card_regread (sd, SDIO_FUNC_1, offset, 2, &cis_byte) < 0) { - sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); - spi_unlock(sd); - return (BCME_ERROR); - } - - *cis = (uint16)cis_byte; - cis++; - offset += 2; - } - - spi_unlock(sd); - - return (BCME_OK); -} - -extern SDIOH_API_RC -sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) -{ - int status; - uint32 cmd_arg; - uint32 dstatus; - uint32 data = (uint32)(*byte); - - spi_lock(sd); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, rw == SDIOH_READ ? 0 : 1); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); - - if (rw == SDIOH_READ) { - sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr)); - } else { - sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr, data)); - } - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) { - spi_unlock(sd); - return status; - } - - if (rw == SDIOH_READ) { - *byte = (uint8)data; - sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *byte)); - } - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus=0x%x\n", dstatus)); - - spi_unlock(sd); - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, - uint32 *word, uint nbytes) -{ - int status; - - spi_lock(sd); - - if (rw == SDIOH_READ) - status = bcmspi_card_regread(sd, func, addr, nbytes, word); - else - status = bcmspi_card_regwrite(sd, func, addr, nbytes, *word); - - spi_unlock(sd); - return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - -extern SDIOH_API_RC -sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func, - uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) -{ - int len; - int buflen = (int)buflen_u; - bool fifo = (fix_inc == SDIOH_DATA_FIX); - - spi_lock(sd); - - ASSERT(reg_width == 4); - ASSERT(buflen_u < (1 << 30)); - ASSERT(sd->client_block_size[func]); - - sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n", - __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W', - buflen_u, sd->r_cnt, sd->t_cnt, pkt)); - - /* Break buffer down into blocksize chunks. */ - while (buflen > 0) { - len = MIN(sd->client_block_size[func], buflen); - if (bcmspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) { - sd_err(("%s: bcmspi_card_buf %s failed\n", - __FUNCTION__, rw == SDIOH_READ ? "Read" : "Write")); - spi_unlock(sd); - return SDIOH_API_RC_FAIL; - } - buffer += len; - buflen -= len; - if (!fifo) - addr += len; - } - spi_unlock(sd); - return SDIOH_API_RC_SUCCESS; -} - -/* This function allows write to gspi bus when another rd/wr function is deep down the call stack. - * Its main aim is to have simpler spi writes rather than recursive writes. - * e.g. When there is a need to program response delay on the fly after detecting the SPI-func - * this call will allow to program the response delay. - */ -static int -bcmspi_card_byterewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 byte) -{ - uint32 cmd_arg; - uint32 datalen = 1; - uint32 hostlen; - - cmd_arg = 0; - - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, datalen); - - sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); - -#ifdef BCMDBG - /* Fill up buffers with a value that generates known dutycycle on MOSI/MISO lines. */ - memset(spi_outbuf2, 0xee, BUF2_PKT_LEN); - memset(spi_inbuf2, 0xee, BUF2_PKT_LEN); -#endif /* BCMDBG */ - - /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen - * according to the wordlen mode(16/32bit) the device is in. - */ - ASSERT(sd->wordlen == 4 || sd->wordlen == 2); - datalen = ROUNDUP(datalen, sd->wordlen); - - /* Start by copying command in the spi-outbuffer */ - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)spi_outbuf2 = SPISWAP_WD4(cmd_arg); - if (datalen & 0x3) - datalen += (4 - (datalen & 0x3)); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)spi_outbuf2 = SPISWAP_WD2(cmd_arg); - if (datalen & 0x1) - datalen++; - } else { - sd_err(("%s: Host is %d bit spid, could not create SPI command.\n", - __FUNCTION__, 8 * sd->wordlen)); - return ERROR; - } - - /* for Write, put the data into the output buffer */ - if (datalen != 0) { - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD4(byte); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD2(byte); - } - } - - /* +4 for cmd, +4 for dstatus */ - hostlen = datalen + 8; - hostlen += (4 - (hostlen & 0x3)); - spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, hostlen); - - /* Last 4bytes are dstatus. Device is configured to return status bits. */ - if (sd->wordlen == 4) { /* 32bit spid */ - sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else { - sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", - __FUNCTION__, 8 * sd->wordlen)); - return ERROR; - } - - if (sd->card_dstatus) - sd_trace(("dstatus after byte rewrite = 0x%x\n", sd->card_dstatus)); - - return (BCME_OK); -} - -/* Program the response delay corresponding to the spi function */ -static int -bcmspi_prog_resp_delay(sdioh_info_t *sd, int func, uint8 resp_delay) -{ - if (sd->resp_delay_all == FALSE) - return (BCME_OK); - - if (sd->prev_fun == func) - return (BCME_OK); - - if (F0_RESPONSE_DELAY == F1_RESPONSE_DELAY) - return (BCME_OK); - - bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_RESPONSE_DELAY, resp_delay); - - /* Remember function for which to avoid reprogramming resp-delay in next iteration */ - sd->prev_fun = func; - - return (BCME_OK); - -} - -#define GSPI_RESYNC_PATTERN 0x0 - -/* A resync pattern is a 32bit MOSI line with all zeros. Its a special command in gSPI. - * It resets the spi-bkplane logic so that all F1 related ping-pong buffer logic is - * synchronised and all queued resuests are cancelled. - */ -static int -bcmspi_resync_f1(sdioh_info_t *sd) -{ - uint32 cmd_arg = GSPI_RESYNC_PATTERN, data = 0, datalen = 0; - -#ifdef BCMDBG - /* Fill up buffers with a value that generates known dutycycle on MOSI/MISO lines. */ - memset(spi_outbuf2, 0xee, BUF2_PKT_LEN); - memset(spi_inbuf2, 0xee, BUF2_PKT_LEN); -#endif /* BCMDBG */ - - /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen - * according to the wordlen mode(16/32bit) the device is in. - */ - ASSERT(sd->wordlen == 4 || sd->wordlen == 2); - datalen = ROUNDUP(datalen, sd->wordlen); - - /* Start by copying command in the spi-outbuffer */ - *(uint32 *)spi_outbuf2 = cmd_arg; - - /* for Write, put the data into the output buffer */ - *(uint32 *)&spi_outbuf2[CMDLEN] = data; - - /* +4 for cmd, +4 for dstatus */ - spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, datalen + 8); - - /* Last 4bytes are dstatus. Device is configured to return status bits. */ - if (sd->wordlen == 4) { /* 32bit spid */ - sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else { - sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", - __FUNCTION__, 8 * sd->wordlen)); - return ERROR; - } - - if (sd->card_dstatus) - sd_trace(("dstatus after resync pattern write = 0x%x\n", sd->card_dstatus)); - - return (BCME_OK); -} - -uint32 dstatus_count = 0; - -static int -bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg) -{ - uint32 dstatus = sd->card_dstatus; - struct spierrstats_t *spierrstats = &sd->spierrstats; - int err = SUCCESS; - - sd_trace(("cmd = 0x%x, dstatus = 0x%x\n", cmd_arg, dstatus)); - - /* Store dstatus of last few gSPI transactions */ - spierrstats->dstatus[dstatus_count % NUM_PREV_TRANSACTIONS] = dstatus; - spierrstats->spicmd[dstatus_count % NUM_PREV_TRANSACTIONS] = cmd_arg; - dstatus_count++; - - if (sd->card_init_done == FALSE) - return err; - - if (dstatus & STATUS_DATA_NOT_AVAILABLE) { - spierrstats->dna++; - sd_trace(("Read data not available on F1 addr = 0x%x\n", - GFIELD(cmd_arg, SPI_REG_ADDR))); - /* Clear dna bit */ - bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, DATA_UNAVAILABLE); - } - - if (dstatus & STATUS_UNDERFLOW) { - spierrstats->rdunderflow++; - sd_err(("FIFO underflow happened due to current F2 read command.\n")); - } - - if (dstatus & STATUS_OVERFLOW) { - spierrstats->wroverflow++; - sd_err(("FIFO overflow happened due to current (F1/F2) write command.\n")); - bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, F1_OVERFLOW); - bcmspi_resync_f1(sd); - sd_err(("Recovering from F1 FIFO overflow.\n")); - } - - if (dstatus & STATUS_F2_INTR) { - spierrstats->f2interrupt++; - sd_trace(("Interrupt from F2. SW should clear corresponding IntStatus bits\n")); - } - - if (dstatus & STATUS_F3_INTR) { - spierrstats->f3interrupt++; - sd_err(("Interrupt from F3. SW should clear corresponding IntStatus bits\n")); - } - - if (dstatus & STATUS_HOST_CMD_DATA_ERR) { - spierrstats->hostcmddataerr++; - sd_err(("Error in CMD or Host data, detected by CRC/Checksum (optional)\n")); - } - - if (dstatus & STATUS_F2_PKT_AVAILABLE) { - spierrstats->f2pktavailable++; - sd_trace(("Packet is available/ready in F2 TX FIFO\n")); - sd_trace(("Packet length = %d\n", sd->dwordmode ? - ((dstatus & STATUS_F2_PKT_LEN_MASK) >> (STATUS_F2_PKT_LEN_SHIFT - 2)) : - ((dstatus & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT))); - } - - if (dstatus & STATUS_F3_PKT_AVAILABLE) { - spierrstats->f3pktavailable++; - sd_err(("Packet is available/ready in F3 TX FIFO\n")); - sd_err(("Packet length = %d\n", - (dstatus & STATUS_F3_PKT_LEN_MASK) >> STATUS_F3_PKT_LEN_SHIFT)); - } - - return err; -} - -extern int -sdioh_abort(sdioh_info_t *sd, uint func) -{ - return 0; -} - -int -sdioh_start(sdioh_info_t *sd, int stage) -{ - return SUCCESS; -} - -int -sdioh_stop(sdioh_info_t *sd) -{ - return SUCCESS; -} - -int -sdioh_waitlockfree(sdioh_info_t *sd) -{ - return SUCCESS; -} - -#ifdef BCMINTERNAL -extern SDIOH_API_RC -sdioh_test_diag(sdioh_info_t *sd) -{ - sd_err(("%s: Implement me\n", __FUNCTION__)); - return (0); -} -#endif /* BCMINTERNAL */ - -/* - * Private/Static work routines - */ -static int -bcmspi_host_init(sdioh_info_t *sd) -{ - - /* Default power on mode */ - sd->sd_mode = SDIOH_MODE_SPI; - sd->polled_mode = TRUE; - sd->host_init_done = TRUE; - sd->card_init_done = FALSE; - sd->adapter_slot = 1; - - return (SUCCESS); -} - -static int -get_client_blocksize(sdioh_info_t *sd) -{ - uint32 regdata[2]; - int status; - - /* Find F1/F2/F3 max packet size */ - if ((status = bcmspi_card_regread(sd, 0, SPID_F1_INFO_REG, - 8, regdata)) != SUCCESS) { - return status; - } - - sd_trace(("pkt_size regdata[0] = 0x%x, regdata[1] = 0x%x\n", - regdata[0], regdata[1])); - - sd->client_block_size[1] = (regdata[0] & F1_MAX_PKT_SIZE) >> 2; - sd_trace(("Func1 blocksize = %d\n", sd->client_block_size[1])); - ASSERT(sd->client_block_size[1] == BLOCK_SIZE_F1); - - sd->client_block_size[2] = ((regdata[0] >> 16) & F2_MAX_PKT_SIZE) >> 2; - sd_trace(("Func2 blocksize = %d\n", sd->client_block_size[2])); - ASSERT(sd->client_block_size[2] == BLOCK_SIZE_F2); - - sd->client_block_size[3] = (regdata[1] & F3_MAX_PKT_SIZE) >> 2; - sd_trace(("Func3 blocksize = %d\n", sd->client_block_size[3])); - ASSERT(sd->client_block_size[3] == BLOCK_SIZE_F3); - - return 0; -} - -static int -bcmspi_client_init(sdioh_info_t *sd) -{ - uint32 status_en_reg = 0; - sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); - -#ifndef BCMSPI_ANDROID -#ifdef HSMODE - if (!spi_start_clock(sd, (uint16)sd_divisor)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } -#else - /* Start at ~400KHz clock rate for initialization */ - if (!spi_start_clock(sd, 128)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } -#endif /* HSMODE */ -#endif /* !BCMSPI_ANDROID */ - - if (!bcmspi_host_device_init_adapt(sd)) { - sd_err(("bcmspi_host_device_init_adapt failed\n")); - return ERROR; - } - - if (!bcmspi_test_card(sd)) { - sd_err(("bcmspi_test_card failed\n")); - return ERROR; - } - - sd->num_funcs = SPI_MAX_IOFUNCS; - - get_client_blocksize(sd); - - /* Apply resync pattern cmd with all zeros to reset spi-bkplane F1 logic */ - bcmspi_resync_f1(sd); - - sd->dwordmode = FALSE; - - bcmspi_card_regread(sd, 0, SPID_STATUS_ENABLE, 1, &status_en_reg); - - sd_trace(("%s: Enabling interrupt with dstatus \n", __FUNCTION__)); - status_en_reg |= INTR_WITH_STATUS; - - if (bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, - status_en_reg & 0xff) != SUCCESS) { - sd_err(("%s: Unable to set response delay for all fun's.\n", __FUNCTION__)); - return ERROR; - } - -#ifndef HSMODE -#ifndef BCMSPI_ANDROID - /* After configuring for High-Speed mode, set the desired clock rate. */ - if (!spi_start_clock(sd, 4)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } -#endif /* !BCMSPI_ANDROID */ -#endif /* HSMODE */ - - /* check to see if the response delay needs to be programmed properly */ - { - uint32 f1_respdelay = 0; - bcmspi_card_regread(sd, 0, SPID_RESP_DELAY_F1, 1, &f1_respdelay); - if ((f1_respdelay == 0) || (f1_respdelay == 0xFF)) { - /* older sdiodevice core and has no separte resp delay for each of */ - sd_err(("older corerev < 4 so use the same resp delay for all funcs\n")); - sd->resp_delay_new = FALSE; - } - else { - /* older sdiodevice core and has no separte resp delay for each of */ - int ret_val; - sd->resp_delay_new = TRUE; - sd_err(("new corerev >= 4 so set the resp delay for each of the funcs\n")); - sd_trace(("resp delay for funcs f0(%d), f1(%d), f2(%d), f3(%d)\n", - GSPI_F0_RESP_DELAY, GSPI_F1_RESP_DELAY, - GSPI_F2_RESP_DELAY, GSPI_F3_RESP_DELAY)); - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F0, 1, - GSPI_F0_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F0\n", __FUNCTION__)); - return ERROR; - } - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F1, 1, - GSPI_F1_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F1\n", __FUNCTION__)); - return ERROR; - } - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F2, 1, - GSPI_F2_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); - return ERROR; - } - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F3, 1, - GSPI_F3_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); - return ERROR; - } - } - } - -/* XXX:Cleanup after finding a common place in dhd or bcmsdh layer to do this */ -#ifndef BCMDONGLEHOST - if ((status = bcmspi_card_regwrite(sd, 1, SBSDIO_FUNC1_SBADDRLOW, 4, - SB_ENUM_BASE >> 8)) != SUCCESS) - return FALSE; -#endif - sd->card_init_done = TRUE; - -#ifdef BCMDBG - { - uint8 regbuf[32]; - int j; - bzero(regbuf, 32); - /* Read default F0 registers */ - sd_trace(("Reading default values of first 32(8bit) F0 spid regs again before" - " quitting init.\n")); - bcmspi_card_regread(sd, 0, SPID_CONFIG, 32, (uint32 *)regbuf); - for (j = 0; j < 32; j++) - sd_trace(("regbuf[%d]=0x%x \n", j, regbuf[j])); - sd_trace(("\n")); - } -#endif /* BCMDBG */ - /* get the device rev to program the prop respdelays */ - - return SUCCESS; -} - -/* XXX What is clock rate at high and low speeds ? */ -static int -bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode) -{ - uint32 regdata; - int status; - - if ((status = bcmspi_card_regread(sd, 0, SPID_CONFIG, - 4, ®data)) != SUCCESS) - return status; - - sd_trace(("In %s spih-ctrl = 0x%x \n", __FUNCTION__, regdata)); - - if (hsmode == TRUE) { - sd_trace(("Attempting to enable High-Speed mode.\n")); - - if (regdata & HIGH_SPEED_MODE) { - sd_trace(("Device is already in High-Speed mode.\n")); - return status; - } else { - regdata |= HIGH_SPEED_MODE; - sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); - if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, - 4, regdata)) != SUCCESS) { - return status; - } - } - } else { - sd_trace(("Attempting to disable High-Speed mode.\n")); - - if (regdata & HIGH_SPEED_MODE) { - regdata &= ~HIGH_SPEED_MODE; - sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); - if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, - 4, regdata)) != SUCCESS) - return status; - } - else { - sd_trace(("Device is already in Low-Speed mode.\n")); - return status; - } - } -#ifndef BCMSPI_ANDROID - spi_controller_highspeed_mode(sd, hsmode); -#endif /* !BCMSPI_ANDROID */ - - return TRUE; -} - -#define bcmspi_find_curr_mode(sd) { \ - sd->wordlen = 2; \ - status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ - regdata &= 0xff; \ - if ((regdata == 0xad) || (regdata == 0x5b) || \ - (regdata == 0x5d) || (regdata == 0x5a)) \ - break; \ - sd->wordlen = 4; \ - status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ - regdata &= 0xff; \ - if ((regdata == 0xad) || (regdata == 0x5b) || \ - (regdata == 0x5d) || (regdata == 0x5a)) \ - break; \ - sd_trace(("Silicon testability issue: regdata = 0x%x." \ - " Expected 0xad, 0x5a, 0x5b or 0x5d.\n", regdata)); \ - OSL_DELAY(100000); \ -} - -#define INIT_ADAPT_LOOP 100 - -/* Adapt clock-phase-speed-bitwidth between host and device */ -static bool -bcmspi_host_device_init_adapt(sdioh_info_t *sd) -{ - uint32 wrregdata, regdata = 0; - int status; - int i; -#ifdef BCMDBG - int j; - uint8 regbuf[32]; - bzero(regbuf, 32); -#endif /* BCMDBG */ - - /* Due to a silicon testability issue, the first command from the Host - * to the device will get corrupted (first bit will be lost). So the - * Host should poll the device with a safe read request. ie: The Host - * should try to read F0 addr 0x14 using the Fixed address mode - * (This will prevent a unintended write command to be detected by device) - */ - for (i = 0; i < INIT_ADAPT_LOOP; i++) { - /* If device was not power-cycled it will stay in 32bit mode with - * response-delay-all bit set. Alternate the iteration so that - * read either with or without response-delay for F0 to succeed. - */ - bcmspi_find_curr_mode(sd); - sd->resp_delay_all = (i & 0x1) ? TRUE : FALSE; - - bcmspi_find_curr_mode(sd); - sd->dwordmode = TRUE; - - bcmspi_find_curr_mode(sd); - sd->dwordmode = FALSE; - } - - /* Bail out, device not detected */ - if (i == INIT_ADAPT_LOOP) - return FALSE; - - /* Softreset the spid logic */ - if ((sd->dwordmode) || (sd->wordlen == 4)) { - bcmspi_card_regwrite(sd, 0, SPID_RESET_BP, 1, RESET_ON_WLAN_BP_RESET|RESET_SPI); - bcmspi_card_regread(sd, 0, SPID_RESET_BP, 1, ®data); - sd_trace(("reset reg read = 0x%x\n", regdata)); - sd_trace(("dwordmode = %d, wordlen = %d, resp_delay_all = %d\n", sd->dwordmode, - sd->wordlen, sd->resp_delay_all)); - /* Restore default state after softreset */ - sd->wordlen = 2; - sd->dwordmode = FALSE; - } - - if (sd->wordlen == 4) { - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != - SUCCESS) - return FALSE; - if (regdata == TEST_RO_DATA_32BIT_LE) { - sd_trace(("Spid is already in 32bit LE mode. Value read = 0x%x\n", - regdata)); - sd_trace(("Spid power was left on.\n")); - } else { - sd_err(("Spid power was left on but signature read failed." - " Value read = 0x%x\n", regdata)); - return FALSE; - } - } else { - sd->wordlen = 2; - -#define CTRL_REG_DEFAULT 0x00010430 /* according to the host m/c */ - - wrregdata = (CTRL_REG_DEFAULT); - - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) - return FALSE; - sd_trace(("(we are still in 16bit mode) 32bit READ LE regdata = 0x%x\n", regdata)); - -#ifndef HSMODE - wrregdata |= (CLOCK_PHASE | CLOCK_POLARITY); - wrregdata &= ~HIGH_SPEED_MODE; - bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); -#endif /* HSMODE */ - - for (i = 0; i < INIT_ADAPT_LOOP; i++) { - if ((regdata == 0xfdda7d5b) || (regdata == 0xfdda7d5a)) { - sd_trace(("0xfeedbead was leftshifted by 1-bit.\n")); - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, - ®data)) != SUCCESS) - return FALSE; - } - OSL_DELAY(1000); - } - -#if defined(CHANGE_SPI_INTR_POLARITY_ACTIVE_HIGH) - /* Change to host controller intr-polarity of active-high */ - /* XXX With intr-polarity active-high, host platform does not go into suspend mode - * since the pin is asserted high. - */ - wrregdata |= INTR_POLARITY; -#else - /* Change to host controller intr-polarity of active-low */ - wrregdata &= ~INTR_POLARITY; -#endif /* CHANGE_SPI_INTR_POLARITY_ACTIVE_HIGH */ - - sd_trace(("(we are still in 16bit mode) 32bit Write LE reg-ctrl-data = 0x%x\n", - wrregdata)); - /* Change to 32bit mode */ - wrregdata |= WORD_LENGTH_32; - bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); - - /* Change command/data packaging in 32bit LE mode */ - sd->wordlen = 4; - - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) - return FALSE; - - if (regdata == TEST_RO_DATA_32BIT_LE) { - sd_trace(("Read spid passed. Value read = 0x%x\n", regdata)); - sd_trace(("Spid had power-on cycle OR spi was soft-resetted \n")); - } else { - sd_err(("Stale spid reg values read as it was kept powered. Value read =" - "0x%x\n", regdata)); - return FALSE; - } - } - -#ifdef BCMDBG - /* Read default F0 registers */ - sd_trace(("Reading default values of first 32(8bit) F0 spid regs\n")); - bcmspi_card_regread(sd, 0, SPID_CONFIG, 32, (uint32 *)regbuf); - for (j = 0; j < 32; j++) - sd_trace(("regbuf[%d]=0x%x \n", j, regbuf[j])); - sd_trace(("\n")); -#endif /* BCMDBG */ - - return TRUE; -} - -static bool -bcmspi_test_card(sdioh_info_t *sd) -{ - uint32 regdata; - int status; -#ifdef BCMDBG - uint8 regbuf[32]; - bzero(regbuf, 32); -#endif /* BCMDBG */ - - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) - return FALSE; - - if (regdata == (TEST_RO_DATA_32BIT_LE)) - sd_trace(("32bit LE regdata = 0x%x\n", regdata)); - else { - sd_trace(("Incorrect 32bit LE regdata = 0x%x\n", regdata)); - return FALSE; - } - -#define RW_PATTERN1 0xA0A1A2A3 -#define RW_PATTERN2 0x4B5B6B7B - - regdata = RW_PATTERN1; - if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) - return FALSE; - regdata = 0; - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) - return FALSE; - if (regdata != RW_PATTERN1) { - sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", - RW_PATTERN1, regdata)); - return FALSE; - } else - sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); - - regdata = RW_PATTERN2; - if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) - return FALSE; - regdata = 0; - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) - return FALSE; - if (regdata != RW_PATTERN2) { - sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", - RW_PATTERN2, regdata)); - return FALSE; - } else - sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); - - return TRUE; -} - -static int -bcmspi_driver_init(sdioh_info_t *sd) -{ - sd_trace(("%s\n", __FUNCTION__)); - if ((bcmspi_host_init(sd)) != SUCCESS) { - return ERROR; - } - - if (bcmspi_client_init(sd) != SUCCESS) { - return ERROR; - } - - return SUCCESS; -} - -/* Read device reg */ -static int -bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) -{ - int status; - uint32 cmd_arg, dstatus; - - ASSERT(regsize); - - if (func == 2) - sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); - - sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", - __FUNCTION__, cmd_arg, func, regaddr, regsize)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) - return status; - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus =0x%x\n", dstatus)); - - return SUCCESS; -} - -static int -bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) -{ - - int status; - uint32 cmd_arg; - uint32 dstatus; - - ASSERT(regsize); - - if (func == 2) - sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); /* Fixed access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize); - - sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", - __FUNCTION__, cmd_arg, func, regaddr, regsize)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) - return status; - - sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *data)); - - bcmspi_cmd_getdstatus(sd, &dstatus); - sd_trace(("dstatus =0x%x\n", dstatus)); - return SUCCESS; -} - -/* write a device register */ -static int -bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) -{ - int status; - uint32 cmd_arg, dstatus; - - ASSERT(regsize); - - cmd_arg = 0; - - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); - - sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d data=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr, regsize, data)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, regsize)) != SUCCESS) - return status; - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus=0x%x\n", dstatus)); - - return SUCCESS; -} - -/* write a device register - 1 byte */ -static int -bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 *byte) -{ - int status; - uint32 cmd_arg; - uint32 dstatus; - uint32 data = (uint32)(*byte); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); - - sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr, data)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) - return status; - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus =0x%x\n", dstatus)); - - return SUCCESS; -} - -void -bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer) -{ - *dstatus_buffer = sd->card_dstatus; -} - -/* 'data' is of type uint32 whereas other buffers are of type uint8 */ -static int -bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, - uint32 *data, uint32 datalen) -{ - uint32 i, j; - uint8 resp_delay = 0; - int err = SUCCESS; - uint32 hostlen; - uint32 spilen = 0; - uint32 dstatus_idx = 0; - uint16 templen, buslen, len, *ptr = NULL; - - sd_trace(("spi cmd = 0x%x\n", cmd_arg)); -#ifdef BCMDBG - /* Fill up buffer with known pattern */ - memset(spi_outbuf, 0xee, SPI_MAX_PKT_LEN); - memset(spi_inbuf, 0xee, SPI_MAX_PKT_LEN); -#endif /* BCMDBG */ - - /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen - * according to the wordlen mode(16/32bit) the device is in. - */ - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)spi_outbuf = SPISWAP_WD4(cmd_arg); - if (datalen & 0x3) - datalen += (4 - (datalen & 0x3)); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)spi_outbuf = SPISWAP_WD2(cmd_arg); - if (datalen & 0x1) - datalen++; - if (datalen < 4) - datalen = ROUNDUP(datalen, 4); - } else { - sd_err(("Host is %d bit spid, could not create SPI command.\n", - 8 * sd->wordlen)); - return ERROR; - } - - /* for Write, put the data into the output buffer */ - if (GFIELD(cmd_arg, SPI_RW_FLAG) == 1) { - /* We send len field of hw-header always a mod16 size, both from host and dongle */ - if (datalen != 0) { - for (i = 0; i < datalen/4; i++) { - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = - SPISWAP_WD4(data[i]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = - SPISWAP_WD2(data[i]); - } - } - } - } - - /* Append resp-delay number of bytes and clock them out for F0/1/2 reads. */ - if ((GFIELD(cmd_arg, SPI_RW_FLAG) == 0)) { - int func = GFIELD(cmd_arg, SPI_FUNCTION); - switch (func) { - case 0: - if (sd->resp_delay_new) - resp_delay = GSPI_F0_RESP_DELAY; - else - resp_delay = sd->resp_delay_all ? F0_RESPONSE_DELAY : 0; - break; - case 1: - if (sd->resp_delay_new) - resp_delay = GSPI_F1_RESP_DELAY; - else - resp_delay = F1_RESPONSE_DELAY; - break; - case 2: - if (sd->resp_delay_new) - resp_delay = GSPI_F2_RESP_DELAY; - else - resp_delay = sd->resp_delay_all ? F2_RESPONSE_DELAY : 0; - break; - default: - ASSERT(0); - break; - } - /* Program response delay */ - if (sd->resp_delay_new == FALSE) - bcmspi_prog_resp_delay(sd, func, resp_delay); - } - - /* +4 for cmd and +4 for dstatus */ - hostlen = datalen + 8 + resp_delay; - hostlen += dstatus_idx; -#ifdef BCMSPI_ANDROID - if (hostlen%4) { - sd_err(("Unaligned data len %d, hostlen %d\n", - datalen, hostlen)); -#endif /* BCMSPI_ANDROID */ - hostlen += (4 - (hostlen & 0x3)); -#ifdef BCMSPI_ANDROID - } -#endif /* BCMSPI_ANDROID */ -#ifdef BCMDBG - if ((GFIELD(cmd_arg, SPI_RW_FLAG) == 1) && - (sd->dwordmode) && - (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { - sd_trace(("len/~len/spilen/hostlen=0x%x/0x%x/0x%x/0x%x\n", - *ptr, ~*(ptr+1), spilen, hostlen)); - } -#endif /* BCMDBG */ - spi_sendrecv(sd, spi_outbuf, spi_inbuf, hostlen); - - /* for Read, get the data into the input buffer */ - if (datalen != 0) { - if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) { /* if read cmd */ - for (j = 0; j < datalen/4; j++) { - if (sd->wordlen == 4) { /* 32bit spid */ - data[j] = SPISWAP_WD4(*(uint32 *)&spi_inbuf[j * 4 + - CMDLEN + resp_delay]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - data[j] = SPISWAP_WD2(*(uint32 *)&spi_inbuf[j * 4 + - CMDLEN + resp_delay]); - } - } - } - } - - dstatus_idx += (datalen + CMDLEN + resp_delay); - /* Last 4bytes are dstatus. Device is configured to return status bits. */ - if (sd->wordlen == 4) { /* 32bit spid */ - sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf[dstatus_idx]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf[dstatus_idx]); - } else { - sd_err(("Host is %d bit machine, could not read SPI dstatus.\n", - 8 * sd->wordlen)); - return ERROR; - } - if (sd->card_dstatus == 0xffffffff) { - sd_err(("looks like not a GSPI device or device is not powered.\n")); - } - - err = bcmspi_update_stats(sd, cmd_arg); -#ifdef BCMDBG - if (err) - prhex("Overflowing frame", (uint8 *)data, datalen); -#endif /* BCMDBG */ - - return err; - -} - -static int -bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, - uint32 addr, int nbytes, uint32 *data) -{ - int status; - uint32 cmd_arg; - bool write = rw == SDIOH_READ ? 0 : 1; - uint retries = 0; - - bool enable; - uint32 spilen; - - cmd_arg = 0; - - ASSERT(nbytes); - ASSERT(nbytes <= sd->client_block_size[func]); - - if (write) sd->t_cnt++; else sd->r_cnt++; - - if (func == 2) { - /* Frame len check limited by gSPI. */ - if ((nbytes > 2000) && write) { - sd_trace((">2KB write: F2 wr of %d bytes\n", nbytes)); -#ifdef BCMDBG - prhex("Host for gSPI", (uint8 *)data, 32); -#endif /* BCMDBG */ - } - /* ASSERT(nbytes <= 2048); Fix bigger len gspi issue and uncomment. */ - /* If F2 fifo on device is not ready to receive data, don't do F2 transfer */ - if (write) { - uint32 dstatus; - /* check F2 ready with cached one */ - bcmspi_cmd_getdstatus(sd, &dstatus); - if ((dstatus & STATUS_F2_RX_READY) == 0) { - retries = WAIT_F2RXFIFORDY; - enable = 0; - while (retries-- && !enable) { - OSL_DELAY(WAIT_F2RXFIFORDY_DELAY * 1000); - bcmspi_card_regread(sd, SPI_FUNC_0, SPID_STATUS_REG, 4, - &dstatus); - if (dstatus & STATUS_F2_RX_READY) - enable = TRUE; - } - if (!enable) { - struct spierrstats_t *spierrstats = &sd->spierrstats; - spierrstats->f2rxnotready++; - sd_err(("F2 FIFO is not ready to receive data.\n")); - return ERROR; - } - sd_trace(("No of retries on F2 ready %d\n", - (WAIT_F2RXFIFORDY - retries))); - } - } - } - - /* F2 transfers happen on 0 addr */ - addr = (func == 2) ? 0 : addr; - - /* In pio mode buffer is read using fixed address fifo in func 1 */ - if ((func == 1) && (fifo)) - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); - else - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); - - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, addr); - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, write); - spilen = sd->data_xfer_count = MIN(sd->client_block_size[func], nbytes); - if ((sd->dwordmode == TRUE) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { - /* convert len to mod4 size */ - spilen = spilen + ((spilen & 0x3) ? (4 - (spilen & 0x3)): 0); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); - } else - cmd_arg = SFIELD(cmd_arg, SPI_LEN, spilen); - - if ((func == 2) && (fifo == 1)) { - sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", - __FUNCTION__, write ? "Wr" : "Rd", func, "INCR", - addr, nbytes, sd->r_cnt, sd->t_cnt)); - } - - sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); - sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", - __FUNCTION__, write ? "Wd" : "Rd", func, "INCR", - addr, nbytes, sd->r_cnt, sd->t_cnt)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, nbytes)) != SUCCESS) { - sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, - (write ? "write" : "read"))); - return status; - } - - /* gSPI expects that hw-header-len is equal to spi-command-len */ - if ((func == 2) && (rw == SDIOH_WRITE) && (sd->dwordmode == FALSE)) { - ASSERT((uint16)sd->data_xfer_count == (uint16)(*data & 0xffff)); - ASSERT((uint16)sd->data_xfer_count == (uint16)(~((*data & 0xffff0000) >> 16))); - } - - if ((nbytes > 2000) && !write) { - sd_trace((">2KB read: F2 rd of %d bytes\n", nbytes)); -#ifdef BCMDBG - prhex("Host for gSPI", (uint8 *)data, 32); -#endif /* BCMDBG */ - } - - return SUCCESS; -} - -/* Reset and re-initialize the device */ -int -sdioh_sdio_reset(sdioh_info_t *si) -{ - si->card_init_done = FALSE; - return bcmspi_client_init(si); -} - -SDIOH_API_RC -sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) -{ - return SDIOH_API_RC_FAIL; -} - -SDIOH_API_RC -sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) -{ - return SDIOH_API_RC_FAIL; -} - -bool -sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) -{ - return FALSE; -} - -SDIOH_API_RC -sdioh_gpio_init(sdioh_info_t *sd) -{ - return SDIOH_API_RC_FAIL; -} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsrom.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsrom.c deleted file mode 100755 index c17a2dc2c7ab..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsrom.c +++ /dev/null @@ -1,6365 +0,0 @@ -/* - * Routines to access SPROM and to parse SROM/CIS variables. - * - * Despite its file name, OTP contents is also parsed in this file. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -/* - * List of non obvious preprocessor defines used in this file and their meaning: - * DONGLEBUILD : building firmware that runs on the dongle's CPU - * BCM_DONGLEVARS : NVRAM variables can be read from OTP/S(P)ROM. - * When host may supply nvram vars in addition to the ones in OTP/SROM: - * BCMHOSTVARS : full nic / full dongle - * BCMDONGLEHOST : defined when building DHD, code executes on the host in a dongle environment. - * DHD_SPROM : defined when building a DHD that supports reading/writing to SPROM - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef BCMSDIO -#include -#include -#endif -#ifdef BCMSPI -#include -#endif - -#include -#include -#ifndef BCMUSBDEV_COMPOSITE -#define BCMUSBDEV_COMPOSITE -#endif -#if defined(BCMUSBDEV) || defined(BCMSDIO) || defined(BCMSDIODEV) -#include -#include -#include -#endif - -#if defined(WLTEST) || defined (DHD_SPROM) || defined (BCMDBG) -#include -#endif -#include /* for sprom content groking */ - -#include -#ifdef EVENT_LOG_COMPILE -#include -#endif - -#if defined(EVENT_LOG_COMPILE) && defined(BCMDBG_ERR) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define BS_ERROR(args) EVENT_LOG_RA(EVENT_LOG_TAG_BSROM_ERROR, args) -#else -#define BS_ERROR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_BSROM_ERROR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#elif defined(BCMDBG_ERR) || defined(WLTEST) -#define BS_ERROR(args) printf args -#else -#define BS_ERROR(args) -#endif /* defined(BCMDBG_ERR) && defined(ERR_USE_EVENT_LOG) */ - -#if defined(BCMPCIEDEV_SROM_FORMAT) && defined(WLC_TXCAL) -static bool BCMATTACHDATA(is_caldata_prsnt) = FALSE; -static uint16 BCMATTACHDATA(caldata_array)[SROM_MAX / 2]; -static uint8 BCMATTACHDATA(srom_sromrev); -#endif - -static const char BCMATTACHDATA(rstr_uuidstr)[] = - "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X"; -static const char BCMATTACHDATA(rstr_paddr)[] = "pa%d=0x%%x"; -static const char BCMATTACHDATA(rstr_pdata)[] = "pd%d=0x%%x"; -static const char BCMATTACHDATA(rstr_pdatah)[] = "pdh%d=0x%%x"; -static const char BCMATTACHDATA(rstr_pdatal)[] = "pdl%d=0x%%x"; -static const char BCMATTACHDATA(rstr_gci_ccreg_entry)[] = "gcr%d=0x%%x"; -static const char BCMATTACHDATA(rstr_hex)[] = "0x%x"; - -/** curmap: contains host start address of PCI BAR0 window */ -static volatile uint8* srom_offset(si_t *sih, volatile void *curmap) -{ - if (sih->ccrev <= 31) - return (volatile uint8*)curmap + PCI_BAR0_SPROM_OFFSET; - if ((sih->cccaps & CC_CAP_SROM) == 0) - return NULL; - - if (BUSTYPE(sih->bustype) == SI_BUS) - return (uint8 *)((uintptr)SI_ENUM_BASE(sih) + CC_SROM_OTP); - - return (volatile uint8*)curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP; -} - -#if defined(WLTEST) || defined (DHD_SPROM) || defined (BCMDBG) -#define WRITE_ENABLE_DELAY 500 /* 500 ms after write enable/disable toggle */ -#define WRITE_WORD_DELAY 20 /* 20 ms between each word write */ -#endif - -srom_info_t *sromh = NULL; - -extern char *_vars; -extern uint _varsz; -#ifdef DONGLEBUILD -char * BCMATTACHDATA(_vars_otp) = NULL; -#define DONGLE_STORE_VARS_OTP_PTR(v) (_vars_otp = (v)) -#else -#define DONGLE_STORE_VARS_OTP_PTR(v) -#endif - -#define SROM_CIS_SINGLE 1 - -#if !defined(BCMDONGLEHOST) -static int initvars_srom_si(si_t *sih, osl_t *osh, volatile void *curmap, char **vars, uint *count); -static void _initvars_srom_pci(uint8 sromrev, uint16 *srom, uint off, varbuf_t *b); -static int initvars_srom_pci(si_t *sih, volatile void *curmap, char **vars, uint *count); -static int initvars_cis_pci(si_t *sih, osl_t *osh, volatile void *curmap, char **vars, uint *count); -#endif /* !defined(BCMDONGLEHOST) */ -#if !defined(BCMUSBDEV_ENABLED) && !defined(BCMSDIODEV_ENABLED) &&\ - !defined(BCMDONGLEHOST) && !defined(BCMPCIEDEV_ENABLED) -static int initvars_flash_si(si_t *sih, char **vars, uint *count); -#endif /* !defined(BCMUSBDEV) && !defined(BCMSDIODEV) && !defined(BCMDONGLEHOST) */ -#ifdef BCMSDIO -#if !defined(BCMDONGLEHOST) -static int initvars_cis_sdio(si_t *sih, osl_t *osh, char **vars, uint *count); -#endif /* !defined(BCMDONGLEHOST) */ -static int sprom_cmd_sdio(osl_t *osh, uint8 cmd); -static int sprom_read_sdio(osl_t *osh, uint16 addr, uint16 *data); -#if defined(WLTEST) || defined (DHD_SPROM) || defined (BCMDBG) -static int sprom_write_sdio(osl_t *osh, uint16 addr, uint16 data); -#endif /* defined(WLTEST) || defined (DHD_SPROM) || defined (BCMDBG) */ -#endif /* BCMSDIO */ -#if !defined(BCMDONGLEHOST) -#ifdef BCMSPI -static int initvars_cis_spi(si_t *sih, osl_t *osh, char **vars, uint *count); -#endif /* BCMSPI */ -#endif /* !defined(BCMDONGLEHOST) */ -static int sprom_read_pci(osl_t *osh, si_t *sih, volatile uint16 *sprom, uint wordoff, uint16 *buf, - uint nwords, bool check_crc); -#if !defined(BCMDONGLEHOST) -#if defined(BCMNVRAMW) || defined(BCMNVRAMR) -static int otp_read_pci(osl_t *osh, si_t *sih, uint16 *buf, uint bufsz); -#endif /* defined(BCMNVRAMW) || defined(BCMNVRAMR) */ -#endif /* !defined(BCMDONGLEHOST) */ -static uint16 srom_cc_cmd(si_t *sih, osl_t *osh, volatile void *ccregs, uint32 cmd, uint wordoff, - uint16 data); - -#if !defined(BCMDONGLEHOST) -static int initvars_flash(si_t *sih, osl_t *osh, char **vp, uint len); -int dbushost_initvars_flash(si_t *sih, osl_t *osh, char **base, uint len); -static uint get_max_cis_size(si_t *sih); -#endif /* !defined(BCMDONGLEHOST) */ - -#if defined (BCMHOSTVARS) -/* Also used by wl_readconfigdata for vars download */ -char BCMATTACHDATA(mfgsromvars)[VARS_MAX]; -int BCMATTACHDATA(defvarslen) = 0; -#endif /* defined(BCMHOSTVARS) */ - -#if !defined(BCMDONGLEHOST) -#if defined (BCMHOSTVARS) -/* FIXME: Fake 4331 SROM to boot 4331 driver on QT w/o SPROM/OTP */ -static char BCMATTACHDATA(defaultsromvars_4331)[] = - "sromrev=9\0" - "boardrev=0x1104\0" - "boardflags=0x200\0" - "boardflags2=0x0\0" - "boardtype=0x524\0" - "boardvendor=0x14e4\0" - "boardnum=0x2064\0" - "macaddr=00:90:4c:1a:20:64\0" - "ccode=0x0\0" - "regrev=0x0\0" - "opo=0x0\0" - "aa2g=0x7\0" - "aa5g=0x7\0" - "ag0=0x2\0" - "ag1=0x2\0" - "ag2=0x2\0" - "ag3=0xff\0" - "pa0b0=0xfe7f\0" - "pa0b1=0x15d9\0" - "pa0b2=0xfac6\0" - "pa0itssit=0x20\0" - "pa0maxpwr=0x48\0" - "pa1b0=0xfe89\0" - "pa1b1=0x14b1\0" - "pa1b2=0xfada\0" - "pa1lob0=0xffff\0" - "pa1lob1=0xffff\0" - "pa1lob2=0xffff\0" - "pa1hib0=0xfe8f\0" - "pa1hib1=0x13df\0" - "pa1hib2=0xfafa\0" - "pa1itssit=0x3e\0" - "pa1maxpwr=0x3c\0" - "pa1lomaxpwr=0x3c\0" - "pa1himaxpwr=0x3c\0" - "bxa2g=0x3\0" - "rssisav2g=0x7\0" - "rssismc2g=0xf\0" - "rssismf2g=0xf\0" - "bxa5g=0x3\0" - "rssisav5g=0x7\0" - "rssismc5g=0xf\0" - "rssismf5g=0xf\0" - "tri2g=0xff\0" - "tri5g=0xff\0" - "tri5gl=0xff\0" - "tri5gh=0xff\0" - "rxpo2g=0xff\0" - "rxpo5g=0xff\0" - "txchain=0x7\0" - "rxchain=0x7\0" - "antswitch=0x0\0" - "tssipos2g=0x1\0" - "extpagain2g=0x2\0" - "pdetrange2g=0x4\0" - "triso2g=0x3\0" - "antswctl2g=0x0\0" - "tssipos5g=0x1\0" - "elna2g=0xff\0" - "extpagain5g=0x2\0" - "pdetrange5g=0x4\0" - "triso5g=0x3\0" - "antswctl5g=0x0\0" - "elna5g=0xff\0" - "cckbw202gpo=0x0\0" - "cckbw20ul2gpo=0x0\0" - "legofdmbw202gpo=0x0\0" - "legofdmbw20ul2gpo=0x0\0" - "legofdmbw205glpo=0x0\0" - "legofdmbw20ul5glpo=0x0\0" - "legofdmbw205gmpo=0x0\0" - "legofdmbw20ul5gmpo=0x0\0" - "legofdmbw205ghpo=0x0\0" - "legofdmbw20ul5ghpo=0x0\0" - "mcsbw202gpo=0x0\0" - "mcsbw20ul2gpo=0x0\0" - "mcsbw402gpo=0x0\0" - "mcsbw205glpo=0x0\0" - "mcsbw20ul5glpo=0x0\0" - "mcsbw405glpo=0x0\0" - "mcsbw205gmpo=0x0\0" - "mcsbw20ul5gmpo=0x0\0" - "mcsbw405gmpo=0x0\0" - "mcsbw205ghpo=0x0\0" - "mcsbw20ul5ghpo=0x0\0" - "mcsbw405ghpo=0x0\0" - "mcs32po=0x0\0" - "legofdm40duppo=0x0\0" - "maxp2ga0=0x48\0" - "itt2ga0=0x20\0" - "itt5ga0=0x3e\0" - "pa2gw0a0=0xfe7f\0" - "pa2gw1a0=0x15d9\0" - "pa2gw2a0=0xfac6\0" - "maxp5ga0=0x3c\0" - "maxp5gha0=0x3c\0" - "maxp5gla0=0x3c\0" - "pa5gw0a0=0xfe89\0" - "pa5gw1a0=0x14b1\0" - "pa5gw2a0=0xfada\0" - "pa5glw0a0=0xffff\0" - "pa5glw1a0=0xffff\0" - "pa5glw2a0=0xffff\0" - "pa5ghw0a0=0xfe8f\0" - "pa5ghw1a0=0x13df\0" - "pa5ghw2a0=0xfafa\0" - "maxp2ga1=0x48\0" - "itt2ga1=0x20\0" - "itt5ga1=0x3e\0" - "pa2gw0a1=0xfe54\0" - "pa2gw1a1=0x1563\0" - "pa2gw2a1=0xfa7f\0" - "maxp5ga1=0x3c\0" - "maxp5gha1=0x3c\0" - "maxp5gla1=0x3c\0" - "pa5gw0a1=0xfe53\0" - "pa5gw1a1=0x14fe\0" - "pa5gw2a1=0xfa94\0" - "pa5glw0a1=0xffff\0" - "pa5glw1a1=0xffff\0" - "pa5glw2a1=0xffff\0" - "pa5ghw0a1=0xfe6e\0" - "pa5ghw1a1=0x1457\0" - "pa5ghw2a1=0xfab9\0" - "END\0"; - -static char BCMATTACHDATA(defaultsromvars_4360)[] = - "sromrev=11\0" - "boardrev=0x1421\0" - "boardflags=0x10401001\0" - "boardflags2=0x0\0" - "boardtype=0x61b\0" - "subvid=0x14e4\0" - "boardflags3=0x1\0" - "boardnum=62526\0" - "macaddr=00:90:4c:0d:f4:3e\0" - "ccode=X0\0" - "regrev=15\0" - "aa2g=7\0" - "aa5g=7\0" - "agbg0=71\0" - "agbg1=71\0" - "agbg2=133\0" - "aga0=71\0" - "aga1=133\0" - "aga2=133\0" - "antswitch=0\0" - "tssiposslope2g=1\0" - "epagain2g=0\0" - "pdgain2g=9\0" - "tworangetssi2g=0\0" - "papdcap2g=0\0" - "femctrl=2\0" - "tssiposslope5g=1\0" - "epagain5g=0\0" - "pdgain5g=9\0" - "tworangetssi5g=0\0" - "papdcap5g=0\0" - "gainctrlsph=0\0" - "tempthresh=255\0" - "tempoffset=255\0" - "rawtempsense=0x1ff\0" - "measpower=0x7f\0" - "tempsense_slope=0xff\0" - "tempcorrx=0x3f\0" - "tempsense_option=0x3\0" - "xtalfreq=65535\0" - "phycal_tempdelta=255\0" - "temps_period=15\0" - "temps_hysteresis=15\0" - "measpower1=0x7f\0" - "measpower2=0x7f\0" - "pdoffset2g40ma0=15\0" - "pdoffset2g40ma1=15\0" - "pdoffset2g40ma2=15\0" - "pdoffset2g40mvalid=1\0" - "pdoffset40ma0=9010\0" - "pdoffset40ma1=12834\0" - "pdoffset40ma2=8994\0" - "pdoffset80ma0=16\0" - "pdoffset80ma1=4096\0" - "pdoffset80ma2=0\0" - "subband5gver=0x4\0" - "cckbw202gpo=0\0" - "cckbw20ul2gpo=0\0" - "mcsbw202gpo=2571386880\0" - "mcsbw402gpo=2571386880\0" - "dot11agofdmhrbw202gpo=17408\0" - "ofdmlrbw202gpo=0\0" - "mcsbw205glpo=4001923072\0" - "mcsbw405glpo=4001923072\0" - "mcsbw805glpo=4001923072\0" - "mcsbw1605glpo=0\0" - "mcsbw205gmpo=3431497728\0" - "mcsbw405gmpo=3431497728\0" - "mcsbw805gmpo=3431497728\0" - "mcsbw1605gmpo=0\0" - "mcsbw205ghpo=3431497728\0" - "mcsbw405ghpo=3431497728\0" - "mcsbw805ghpo=3431497728\0" - "mcsbw1605ghpo=0\0" - "mcslr5glpo=0\0" - "mcslr5gmpo=0\0" - "mcslr5ghpo=0\0" - "sb20in40hrpo=0\0" - "sb20in80and160hr5glpo=0\0" - "sb40and80hr5glpo=0\0" - "sb20in80and160hr5gmpo=0\0" - "sb40and80hr5gmpo=0\0" - "sb20in80and160hr5ghpo=0\0" - "sb40and80hr5ghpo=0\0" - "sb20in40lrpo=0\0" - "sb20in80and160lr5glpo=0\0" - "sb40and80lr5glpo=0\0" - "sb20in80and160lr5gmpo=0\0" - "sb40and80lr5gmpo=0\0" - "sb20in80and160lr5ghpo=0\0" - "sb40and80lr5ghpo=0\0" - "dot11agduphrpo=0\0" - "dot11agduplrpo=0\0" - "pcieingress_war=15\0" - "sar2g=18\0" - "sar5g=15\0" - "noiselvl2ga0=31\0" - "noiselvl2ga1=31\0" - "noiselvl2ga2=31\0" - "noiselvl5ga0=31,31,31,31\0" - "noiselvl5ga1=31,31,31,31\0" - "noiselvl5ga2=31,31,31,31\0" - "rxgainerr2ga0=63\0" - "rxgainerr2ga1=31\0" - "rxgainerr2ga2=31\0" - "rxgainerr5ga0=63,63,63,63\0" - "rxgainerr5ga1=31,31,31,31\0" - "rxgainerr5ga2=31,31,31,31\0" - "maxp2ga0=76\0" - "pa2ga0=0xff3c,0x172c,0xfd20\0" - "rxgains5gmelnagaina0=7\0" - "rxgains5gmtrisoa0=15\0" - "rxgains5gmtrelnabypa0=1\0" - "rxgains5ghelnagaina0=7\0" - "rxgains5ghtrisoa0=15\0" - "rxgains5ghtrelnabypa0=1\0" - "rxgains2gelnagaina0=4\0" - "rxgains2gtrisoa0=7\0" - "rxgains2gtrelnabypa0=1\0" - "rxgains5gelnagaina0=3\0" - "rxgains5gtrisoa0=7\0" - "rxgains5gtrelnabypa0=1\0" - "maxp5ga0=76,76,76,76\0" -"pa5ga0=0xff3a,0x14d4,0xfd5f,0xff36,0x1626,0xfd2e,0xff42,0x15bd,0xfd47,0xff39,0x15a3,0xfd3d\0" - "maxp2ga1=76\0" - "pa2ga1=0xff2a,0x16b2,0xfd28\0" - "rxgains5gmelnagaina1=7\0" - "rxgains5gmtrisoa1=15\0" - "rxgains5gmtrelnabypa1=1\0" - "rxgains5ghelnagaina1=7\0" - "rxgains5ghtrisoa1=15\0" - "rxgains5ghtrelnabypa1=1\0" - "rxgains2gelnagaina1=3\0" - "rxgains2gtrisoa1=6\0" - "rxgains2gtrelnabypa1=1\0" - "rxgains5gelnagaina1=3\0" - "rxgains5gtrisoa1=6\0" - "rxgains5gtrelnabypa1=1\0" - "maxp5ga1=76,76,76,76\0" -"pa5ga1=0xff4e,0x1530,0xfd53,0xff58,0x15b4,0xfd4d,0xff58,0x1671,0xfd2f,0xff55,0x15e2,0xfd46\0" - "maxp2ga2=76\0" - "pa2ga2=0xff3c,0x1736,0xfd1f\0" - "rxgains5gmelnagaina2=7\0" - "rxgains5gmtrisoa2=15\0" - "rxgains5gmtrelnabypa2=1\0" - "rxgains5ghelnagaina2=7\0" - "rxgains5ghtrisoa2=15\0" - "rxgains5ghtrelnabypa2=1\0" - "rxgains2gelnagaina2=4\0" - "rxgains2gtrisoa2=7\0" - "rxgains2gtrelnabypa2=1\0" - "rxgains5gelnagaina2=3\0" - "rxgains5gtrisoa2=7\0" - "rxgains5gtrelnabypa2=1\0" - "maxp5ga2=76,76,76,76\0" -"pa5ga2=0xff2d,0x144a,0xfd63,0xff35,0x15d7,0xfd3b,0xff35,0x1668,0xfd2f,0xff31,0x1664,0xfd27\0" - "END\0"; - -#endif /* defined(BCMHOSTVARS) */ -#endif /* !defined(BCMDONGLEHOST) */ - -#if !defined(BCMDONGLEHOST) -#if defined(BCMHOSTVARS) -static char BCMATTACHDATA(defaultsromvars_wltest)[] = - "macaddr=00:90:4c:f8:00:01\0" - "et0macaddr=00:11:22:33:44:52\0" - "et0phyaddr=30\0" - "et0mdcport=0\0" - "gpio2=robo_reset\0" - "boardvendor=0x14e4\0" - "boardflags=0x210\0" - "boardflags2=0\0" - "boardtype=0x04c3\0" - "boardrev=0x1100\0" - "sromrev=8\0" - "devid=0x432c\0" - "ccode=0\0" - "regrev=0\0" - "aa2g=3\0" - "ag0=2\0" - "ag1=2\0" - "aa5g=3\0" - "aa0=2\0" - "aa1=2\0" - "txchain=3\0" - "rxchain=3\0" - "antswitch=0\0" - "itt2ga0=0x20\0" - "maxp2ga0=0x48\0" - "pa2gw0a0=0xfe9e\0" - "pa2gw1a0=0x15d5\0" - "pa2gw2a0=0xfae9\0" - "itt2ga1=0x20\0" - "maxp2ga1=0x48\0" - "pa2gw0a1=0xfeb3\0" - "pa2gw1a1=0x15c9\0" - "pa2gw2a1=0xfaf7\0" - "tssipos2g=1\0" - "extpagain2g=0\0" - "pdetrange2g=0\0" - "triso2g=3\0" - "antswctl2g=0\0" - "tssipos5g=1\0" - "extpagain5g=0\0" - "pdetrange5g=0\0" - "triso5g=3\0" - "antswctl5g=0\0" - "cck2gpo=0\0" - "ofdm2gpo=0\0" - "mcs2gpo0=0\0" - "mcs2gpo1=0\0" - "mcs2gpo2=0\0" - "mcs2gpo3=0\0" - "mcs2gpo4=0\0" - "mcs2gpo5=0\0" - "mcs2gpo6=0\0" - "mcs2gpo7=0\0" - "cddpo=0\0" - "stbcpo=0\0" - "bw40po=4\0" - "bwduppo=0\0" - "END\0"; - -/** - * The contents of this array is a first attempt, is likely incorrect for 43602, needs to be - * edited in a later stage. - */ -static char BCMATTACHDATA(defaultsromvars_43602)[] = - "sromrev=11\0" - "boardrev=0x1421\0" - "boardflags=0x10401001\0" - "boardflags2=0x00000002\0" - "boardflags3=0x00000003\0" - "boardtype=0x61b\0" - "subvid=0x14e4\0" - "boardnum=62526\0" - "macaddr=00:90:4c:0d:f4:3e\0" - "ccode=X0\0" - "regrev=15\0" - "aa2g=7\0" - "aa5g=7\0" - "agbg0=71\0" - "agbg1=71\0" - "agbg2=133\0" - "aga0=71\0" - "aga1=133\0" - "aga2=133\0" - "antswitch=0\0" - "tssiposslope2g=1\0" - "epagain2g=0\0" - "pdgain2g=9\0" - "tworangetssi2g=0\0" - "papdcap2g=0\0" - "femctrl=2\0" - "tssiposslope5g=1\0" - "epagain5g=0\0" - "pdgain5g=9\0" - "tworangetssi5g=0\0" - "papdcap5g=0\0" - "gainctrlsph=0\0" - "tempthresh=255\0" - "tempoffset=255\0" - "rawtempsense=0x1ff\0" - "measpower=0x7f\0" - "tempsense_slope=0xff\0" - "tempcorrx=0x3f\0" - "tempsense_option=0x3\0" - "xtalfreq=40000\0" - "phycal_tempdelta=255\0" - "temps_period=15\0" - "temps_hysteresis=15\0" - "measpower1=0x7f\0" - "measpower2=0x7f\0" - "pdoffset2g40ma0=15\0" - "pdoffset2g40ma1=15\0" - "pdoffset2g40ma2=15\0" - "pdoffset2g40mvalid=1\0" - "pdoffset40ma0=9010\0" - "pdoffset40ma1=12834\0" - "pdoffset40ma2=8994\0" - "pdoffset80ma0=16\0" - "pdoffset80ma1=4096\0" - "pdoffset80ma2=0\0" - "subband5gver=0x4\0" - "cckbw202gpo=0\0" - "cckbw20ul2gpo=0\0" - "mcsbw202gpo=2571386880\0" - "mcsbw402gpo=2571386880\0" - "dot11agofdmhrbw202gpo=17408\0" - "ofdmlrbw202gpo=0\0" - "mcsbw205glpo=4001923072\0" - "mcsbw405glpo=4001923072\0" - "mcsbw805glpo=4001923072\0" - "mcsbw1605glpo=0\0" - "mcsbw205gmpo=3431497728\0" - "mcsbw405gmpo=3431497728\0" - "mcsbw805gmpo=3431497728\0" - "mcsbw1605gmpo=0\0" - "mcsbw205ghpo=3431497728\0" - "mcsbw405ghpo=3431497728\0" - "mcsbw805ghpo=3431497728\0" - "mcsbw1605ghpo=0\0" - "mcslr5glpo=0\0" - "mcslr5gmpo=0\0" - "mcslr5ghpo=0\0" - "sb20in40hrpo=0\0" - "sb20in80and160hr5glpo=0\0" - "sb40and80hr5glpo=0\0" - "sb20in80and160hr5gmpo=0\0" - "sb40and80hr5gmpo=0\0" - "sb20in80and160hr5ghpo=0\0" - "sb40and80hr5ghpo=0\0" - "sb20in40lrpo=0\0" - "sb20in80and160lr5glpo=0\0" - "sb40and80lr5glpo=0\0" - "sb20in80and160lr5gmpo=0\0" - "sb40and80lr5gmpo=0\0" - "sb20in80and160lr5ghpo=0\0" - "sb40and80lr5ghpo=0\0" - "dot11agduphrpo=0\0" - "dot11agduplrpo=0\0" - "pcieingress_war=15\0" - "sar2g=18\0" - "sar5g=15\0" - "noiselvl2ga0=31\0" - "noiselvl2ga1=31\0" - "noiselvl2ga2=31\0" - "noiselvl5ga0=31,31,31,31\0" - "noiselvl5ga1=31,31,31,31\0" - "noiselvl5ga2=31,31,31,31\0" - "rxgainerr2ga0=63\0" - "rxgainerr2ga1=31\0" - "rxgainerr2ga2=31\0" - "rxgainerr5ga0=63,63,63,63\0" - "rxgainerr5ga1=31,31,31,31\0" - "rxgainerr5ga2=31,31,31,31\0" - "maxp2ga0=76\0" - "pa2ga0=0xff3c,0x172c,0xfd20\0" - "rxgains5gmelnagaina0=7\0" - "rxgains5gmtrisoa0=15\0" - "rxgains5gmtrelnabypa0=1\0" - "rxgains5ghelnagaina0=7\0" - "rxgains5ghtrisoa0=15\0" - "rxgains5ghtrelnabypa0=1\0" - "rxgains2gelnagaina0=4\0" - "rxgains2gtrisoa0=7\0" - "rxgains2gtrelnabypa0=1\0" - "rxgains5gelnagaina0=3\0" - "rxgains5gtrisoa0=7\0" - "rxgains5gtrelnabypa0=1\0" - "maxp5ga0=76,76,76,76\0" -"pa5ga0=0xff3a,0x14d4,0xfd5f,0xff36,0x1626,0xfd2e,0xff42,0x15bd,0xfd47,0xff39,0x15a3,0xfd3d\0" - "maxp2ga1=76\0" - "pa2ga1=0xff2a,0x16b2,0xfd28\0" - "rxgains5gmelnagaina1=7\0" - "rxgains5gmtrisoa1=15\0" - "rxgains5gmtrelnabypa1=1\0" - "rxgains5ghelnagaina1=7\0" - "rxgains5ghtrisoa1=15\0" - "rxgains5ghtrelnabypa1=1\0" - "rxgains2gelnagaina1=3\0" - "rxgains2gtrisoa1=6\0" - "rxgains2gtrelnabypa1=1\0" - "rxgains5gelnagaina1=3\0" - "rxgains5gtrisoa1=6\0" - "rxgains5gtrelnabypa1=1\0" - "maxp5ga1=76,76,76,76\0" -"pa5ga1=0xff4e,0x1530,0xfd53,0xff58,0x15b4,0xfd4d,0xff58,0x1671,0xfd2f,0xff55,0x15e2,0xfd46\0" - "maxp2ga2=76\0" - "pa2ga2=0xff3c,0x1736,0xfd1f\0" - "rxgains5gmelnagaina2=7\0" - "rxgains5gmtrisoa2=15\0" - "rxgains5gmtrelnabypa2=1\0" - "rxgains5ghelnagaina2=7\0" - "rxgains5ghtrisoa2=15\0" - "rxgains5ghtrelnabypa2=1\0" - "rxgains2gelnagaina2=4\0" - "rxgains2gtrisoa2=7\0" - "rxgains2gtrelnabypa2=1\0" - "rxgains5gelnagaina2=3\0" - "rxgains5gtrisoa2=7\0" - "rxgains5gtrelnabypa2=1\0" - "maxp5ga2=76,76,76,76\0" -"pa5ga2=0xff2d,0x144a,0xfd63,0xff35,0x15d7,0xfd3b,0xff35,0x1668,0xfd2f,0xff31,0x1664,0xfd27\0" - "END\0"; - -/** - * The contents of this array is a first attempt, was copied from 4378, needs to be edited in - * a later stage. - */ -static char BCMATTACHDATA(defaultsromvars_4378)[] = - "cckdigfilttype=4\0" - "sromrev=11\0" - "boardrev=0x1102\0" - "boardtype=0x0771\0" - "boardflags=0x10481201\0" - "boardflags2=0x00000000\0" - "boardflags3=0x04000080\0" - "macaddr=00:90:4c:12:43:47\0" - "ccode=0\0" - "regrev=0\0" - "antswitch=0\0" - "pdgain5g=0\0" - "pdgain2g=0\0" - "tworangetssi2g=0\0" - "tworangetssi5g=0\0" - "femctrl=16\0" - "vendid=0x14e4\0" - "devid=0x4425\0" - "manfid=0x2d0\0" - "nocrc=1\0" - "btc_params82=0x1a0\0" - "otpimagesize=502\0" - "xtalfreq=37400\0" - "rxgains2gelnagaina0=3\0" - "rxgains2gtrisoa0=7\0" - "rxgains2gtrelnabypa0=1\0" - "rxgains5gelnagaina0=3\0" - "rxgains5gtrisoa0=6\0" - "rxgains5gtrelnabypa0=1\0" - "rxgains5gmelnagaina0=3\0" - "rxgains5gmtrisoa0=6\0" - "rxgains5gmtrelnabypa0=1\0" - "rxgains5ghelnagaina0=3\0" - "rxgains5ghtrisoa0=6\0" - "rxgains5ghtrelnabypa0=1\0" - "rxgains2gelnagaina1=3\0" - "rxgains2gtrisoa1=7\0" - "rxgains2gtrelnabypa1=1\0" - "rxgains5gelnagaina1=3\0" - "rxgains5gtrisoa1=6\0" - "rxgains5gtrelnabypa1=1\0" - "rxgains5gmelnagaina1=3\0" - "rxgains5gmtrisoa1=6\0" - "rxgains5gmtrelnabypa1=1\0" - "rxgains5ghelnagaina1=3\0" - "rxgains5ghtrisoa1=6\0" - "rxgains5ghtrelnabypa1=1\0" - "rxchain=3\0" - "txchain=3\0" - "aa2g=3\0" - "aa5g=3\0" - "agbg0=2\0" - "agbg1=2\0" - "aga0=2\0" - "aga1=2\0" - "tssipos2g=1\0" - "tssipos5g=1\0" - "tempthresh=255\0" - "tempoffset=255\0" - "rawtempsense=0x1ff\0" - "pa2gccka0=-200,7392,-897\0" - "pa2gccka1=-198,7522,-907\0" - "pa2ga0=-174,7035,-838\0" - "pa2ga1=-185,6772,-811\0" - "pa5ga0=-175,7296,-887,-164,7553,-910,-155,7801,-936,-149,7908,-951\0" - "pa5ga1=-155,7675,-925,-148,7851,-940,-152,7930,-954,-143,8121,-969\0" - "pa5gbw4080a0=-178,7872,-959,-173,8107,-986,-165,8398,-1019,-150,8809,-1063\0" - "pa5gbw4080a1=-166,8179,-993,-161,8378,-1015,-165,8402,-1019,-155,8757,-1057\0" - "maxp2ga0=66\0" - "maxp2ga1=66\0" - "maxp5ga0=66,66,66,66\0" - "maxp5ga1=66,66,66,66\0" - "subband5gver=0x4\0" - "paparambwver=3\0" - "cckpwroffset0=0\0" - "cckpwroffset1=0\0" - "pdoffset40ma0=0x0000\0" - "pdoffset80ma0=0xeeee\0" - "pdoffset40ma1=0x0000\0" - "pdoffset80ma1=0xeeee\0" - "cckbw202gpo=0\0" - "cckbw20ul2gpo=0\0" - "mcsbw202gpo=0xEC888222\0" - "mcsbw402gpo=0xEC888222\0" - "dot11agofdmhrbw202gpo=0x6622\0" - "ofdmlrbw202gpo=0x0000\0" - "mcsbw205glpo=0xCA666000\0" - "mcsbw405glpo=0xCA666000\0" - "mcsbw805glpo=0xEA666000\0" - "mcsbw1605glpo=0\0" - "mcsbw205gmpo=0xCA666000\0" - "mcsbw405gmpo=0xCA666000\0" - "mcsbw805gmpo=0xEA666000\0" - "mcsbw1605gmpo=0\0" - "mcsbw205ghpo=0xCA666000\0" - "mcsbw405ghpo=0xCA666000\0" - "mcsbw805ghpo=0xEA666000\0" - "mcsbw1605ghpo=0\0" - "mcslr5glpo=0x0000\0" - "mcslr5gmpo=0x0000\0" - "mcslr5ghpo=0x0000\0" - "sb20in40hrpo=0x0\0" - "sb20in80and160hr5glpo=0x0\0" - "sb40and80hr5glpo=0x0\0" - "sb20in80and160hr5gmpo=0x0\0" - "sb40and80hr5gmpo=0x0\0" - "sb20in80and160hr5ghpo=0x0\0" - "sb40and80hr5ghpo=0x0\0" - "sb20in40lrpo=0x0\0" - "sb20in80and160lr5glpo=0x0\0" - "sb40and80lr5glpo=0x0\0" - "sb20in80and160lr5gmpo=0x0\0" - "sb40and80lr5gmpo=0x0\0" - "sb20in80and160lr5ghpo=0x0\0" - "sb40and80lr5ghpo=0x0\0" - "dot11agduphrpo=0x0\0" - "dot11agduplrpo=0x0\0" - "phycal_tempdelta=15\0" - "temps_period=15\0" - "temps_hysteresis=15\0" - "swctrlmap_2g=0x00000404,0x0a0a0000,0x02020000,0x010a02,0x1fe\0" - "swctrlmapext_2g=0x00000000,0x00000000,0x00000000,0x000000,0x000\0" - "swctrlmap_5g=0x00001010,0x60600000,0x40400000,0x000000,0x0f0\0" - "swctrlmapext_5g=0x00000000,0x00000000,0x00000000,0x000000,0x000\0" - "powoffs2gtna0=1,3,3,1,0,0,1,2,2,2,1,1,0,0\0" - "powoffs2gtna1=-1,1,1,1,0,0,1,2,3,2,2,0,0,0\0" - "END\0"; - -/** - * The contents of this array is a first attempt, was copied from 4387, needs to be edited in - * a later stage. - */ -static char BCMATTACHDATA(defaultsromvars_4387)[] = - "cckdigfilttype=4\0" - "sromrev=11\0" - "boardrev=0x1102\0" - "boardtype=0x0771\0" - "boardflags=0x10481201\0" - "boardflags2=0x00000000\0" - "boardflags3=0x04000080\0" - "macaddr=00:90:4c:12:43:47\0" - "ccode=0\0" - "regrev=0\0" - "antswitch=0\0" - "pdgain5g=0\0" - "pdgain2g=0\0" - "tworangetssi2g=0\0" - "tworangetssi5g=0\0" - "femctrl=16\0" - "vendid=0x14e4\0" - "devid=0x4425\0" - "manfid=0x2d0\0" - "nocrc=1\0" - "btc_params82=0x1a0\0" - "otpimagesize=502\0" - "xtalfreq=37400\0" - "rxgains2gelnagaina0=3\0" - "rxgains2gtrisoa0=7\0" - "rxgains2gtrelnabypa0=1\0" - "rxgains5gelnagaina0=3\0" - "rxgains5gtrisoa0=6\0" - "rxgains5gtrelnabypa0=1\0" - "rxgains5gmelnagaina0=3\0" - "rxgains5gmtrisoa0=6\0" - "rxgains5gmtrelnabypa0=1\0" - "rxgains5ghelnagaina0=3\0" - "rxgains5ghtrisoa0=6\0" - "rxgains5ghtrelnabypa0=1\0" - "rxgains2gelnagaina1=3\0" - "rxgains2gtrisoa1=7\0" - "rxgains2gtrelnabypa1=1\0" - "rxgains5gelnagaina1=3\0" - "rxgains5gtrisoa1=6\0" - "rxgains5gtrelnabypa1=1\0" - "rxgains5gmelnagaina1=3\0" - "rxgains5gmtrisoa1=6\0" - "rxgains5gmtrelnabypa1=1\0" - "rxgains5ghelnagaina1=3\0" - "rxgains5ghtrisoa1=6\0" - "rxgains5ghtrelnabypa1=1\0" - "rxchain=3\0" - "txchain=3\0" - "aa2g=3\0" - "aa5g=3\0" - "agbg0=2\0" - "agbg1=2\0" - "aga0=2\0" - "aga1=2\0" - "tssipos2g=1\0" - "tssipos5g=1\0" - "tempthresh=255\0" - "tempoffset=255\0" - "rawtempsense=0x1ff\0" - "pa2gccka0=-200,7392,-897\0" - "pa2gccka1=-198,7522,-907\0" - "pa2ga0=-174,7035,-838\0" - "pa2ga1=-185,6772,-811\0" - "pa5ga0=-175,7296,-887,-164,7553,-910,-155,7801,-936,-149,7908,-951\0" - "pa5ga1=-155,7675,-925,-148,7851,-940,-152,7930,-954,-143,8121,-969\0" - "pa5gbw4080a0=-178,7872,-959,-173,8107,-986,-165,8398,-1019,-150,8809,-1063\0" - "pa5gbw4080a1=-166,8179,-993,-161,8378,-1015,-165,8402,-1019,-155,8757,-1057\0" - "maxp2ga0=66\0" - "maxp2ga1=66\0" - "maxp5ga0=66,66,66,66\0" - "maxp5ga1=66,66,66,66\0" - "subband5gver=0x4\0" - "paparambwver=3\0" - "cckpwroffset0=0\0" - "cckpwroffset1=0\0" - "pdoffset40ma0=0x0000\0" - "pdoffset80ma0=0xeeee\0" - "pdoffset40ma1=0x0000\0" - "pdoffset80ma1=0xeeee\0" - "cckbw202gpo=0\0" - "cckbw20ul2gpo=0\0" - "mcsbw202gpo=0xEC888222\0" - "mcsbw402gpo=0xEC888222\0" - "dot11agofdmhrbw202gpo=0x6622\0" - "ofdmlrbw202gpo=0x0000\0" - "mcsbw205glpo=0xCA666000\0" - "mcsbw405glpo=0xCA666000\0" - "mcsbw805glpo=0xEA666000\0" - "mcsbw1605glpo=0\0" - "mcsbw205gmpo=0xCA666000\0" - "mcsbw405gmpo=0xCA666000\0" - "mcsbw805gmpo=0xEA666000\0" - "mcsbw1605gmpo=0\0" - "mcsbw205ghpo=0xCA666000\0" - "mcsbw405ghpo=0xCA666000\0" - "mcsbw805ghpo=0xEA666000\0" - "mcsbw1605ghpo=0\0" - "mcslr5glpo=0x0000\0" - "mcslr5gmpo=0x0000\0" - "mcslr5ghpo=0x0000\0" - "sb20in40hrpo=0x0\0" - "sb20in80and160hr5glpo=0x0\0" - "sb40and80hr5glpo=0x0\0" - "sb20in80and160hr5gmpo=0x0\0" - "sb40and80hr5gmpo=0x0\0" - "sb20in80and160hr5ghpo=0x0\0" - "sb40and80hr5ghpo=0x0\0" - "sb20in40lrpo=0x0\0" - "sb20in80and160lr5glpo=0x0\0" - "sb40and80lr5glpo=0x0\0" - "sb20in80and160lr5gmpo=0x0\0" - "sb40and80lr5gmpo=0x0\0" - "sb20in80and160lr5ghpo=0x0\0" - "sb40and80lr5ghpo=0x0\0" - "dot11agduphrpo=0x0\0" - "dot11agduplrpo=0x0\0" - "phycal_tempdelta=15\0" - "temps_period=15\0" - "temps_hysteresis=15\0" - "swctrlmap_2g=0x00000404,0x0a0a0000,0x02020000,0x010a02,0x1fe\0" - "swctrlmapext_2g=0x00000000,0x00000000,0x00000000,0x000000,0x000\0" - "swctrlmap_5g=0x00001010,0x60600000,0x40400000,0x000000,0x0f0\0" - "swctrlmapext_5g=0x00000000,0x00000000,0x00000000,0x000000,0x000\0" - "powoffs2gtna0=1,3,3,1,0,0,1,2,2,2,1,1,0,0\0" - "powoffs2gtna1=-1,1,1,1,0,0,1,2,3,2,2,0,0,0\0" - "END\0"; - -#endif /* defined(BCMHOSTVARS) */ -#endif /* !defined(BCMDONGLEHOST) */ - -static bool srvars_inited = FALSE; /* Use OTP/SROM as global variables */ - -#if (!defined(BCMDONGLEHOST) && defined(BCMHOSTVARS)) -/* It must end with pattern of "END" */ -static uint -BCMATTACHFN(srom_vars_len)(char *vars) -{ - uint pos = 0; - uint len; - char *s; - char *emark = "END"; - uint emark_len = strlen(emark) + 1; - - for (s = vars; s && *s;) { - - if (strcmp(s, emark) == 0) - break; - - len = strlen(s); - s += strlen(s) + 1; - pos += len + 1; - /* BS_ERROR(("len %d vars[pos] %s\n", pos, s)); */ - if (pos >= (VARS_MAX - emark_len)) { - return 0; - } - } - - return pos + emark_len; /* include the "END\0" */ -} -#endif /* BCMHOSTVARS */ - -#if !defined(BCMDONGLEHOST) -#ifdef BCMNVRAMVARS -static int -BCMATTACHFN(initvars_nvram_vars)(si_t *sih, osl_t *osh, char **vars, uint *vars_sz) -{ - int ret; - - ASSERT(vars != NULL && vars_sz != NULL); - - /* allocate maximum buffer as we don't know big it should be */ - *vars = MALLOC(osh, MAXSZ_NVRAM_VARS); - if (*vars == NULL) { - ret = BCME_NOMEM; - goto fail; - } - *vars_sz = MAXSZ_NVRAM_VARS; - - /* query the name=value pairs */ - if ((ret = nvram_getall(*vars, *vars_sz)) != BCME_OK) { - goto fail; - } - - /* treat empty name=value list as an error so that we can indicate - * the condition up throught error code return... - */ - if (*vars_sz == 0) { - ret = BCME_ERROR; - goto fail; - } - - return BCME_OK; - -fail: - if (*vars != NULL) { - MFREE(osh, *vars, MAXSZ_NVRAM_VARS); - } - *vars = NULL; - *vars_sz = 0; - return ret; -} -#endif /* BCMNVRAMVARS */ - -/** - * Initialize local vars from the right source for this platform. Called from siutils.c. - * - * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this - * function set 'vars' to NULL, in that case this function will prematurely return. - * - * Return 0 on success, nonzero on error. - */ -int -BCMATTACHFN(srom_var_init)(si_t *sih, uint bustype, volatile void *curmap, osl_t *osh, - char **vars, uint *count) -{ - ASSERT(bustype == BUSTYPE(bustype)); - if (vars == NULL || count == NULL) - return (0); - - *vars = NULL; - *count = 0; - - switch (BUSTYPE(bustype)) { - case SI_BUS: -#ifdef BCMPCIEDEV - if (BCMPCIEDEV_ENAB()) { - int ret; - - ret = initvars_cis_pci(sih, osh, curmap, vars, count); - -#ifdef BCMPCIEDEV_SROM_FORMAT - if (ret) - ret = initvars_srom_pci(sih, curmap, vars, count); -#endif - if (ret) - ret = initvars_srom_si(sih, osh, curmap, vars, count); - return ret; - } else -#endif /* BCMPCIEDEV */ - { - return initvars_srom_si(sih, osh, curmap, vars, count); - } - case PCI_BUS: { - int ret; - -#ifdef BCMNVRAMVARS - if ((ret = initvars_nvram_vars(sih, osh, vars, count)) == BCME_OK) { - return ret; - } else -#endif - { - ASSERT(curmap != NULL); - if (curmap == NULL) - return (-1); - - /* First check for CIS format. if not CIS, try SROM format */ - if ((ret = initvars_cis_pci(sih, osh, curmap, vars, count))) - return initvars_srom_pci(sih, curmap, vars, count); - return ret; - } - } - -#ifdef BCMSDIO - case SDIO_BUS: - return initvars_cis_sdio(sih, osh, vars, count); -#endif /* BCMSDIO */ - -#ifdef BCMSPI - case SPI_BUS: - return initvars_cis_spi(sih, osh, vars, count); -#endif /* BCMSPI */ - - default: - ASSERT(0); - } - return (-1); -} -#endif /* !defined(BCMDONGLEHOST) */ - -/** support only 16-bit word read from srom */ -int -srom_read(si_t *sih, uint bustype, volatile void *curmap, osl_t *osh, - uint byteoff, uint nbytes, uint16 *buf, bool check_crc) -{ - uint i, off, nw; - - BCM_REFERENCE(i); - - ASSERT(bustype == BUSTYPE(bustype)); - - /* check input - 16-bit access only */ - if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > SROM_MAX) - return 1; - - off = byteoff / 2; - nw = nbytes / 2; - -#ifdef BCMPCIEDEV - if ((BUSTYPE(bustype) == SI_BUS) && - (BCM43602_CHIP(sih->chip) || - (BCM4369_CHIP(sih->chip)) || - (BCM4378_CHIP(sih->chip)) || - (BCM4387_CHIP(sih->chip)) || - (BCM4388_CHIP(sih->chip)) || - (BCM4362_CHIP(sih->chip)) || - (BCM4385_CHIP(sih->chip)) || - (BCM4389_CHIP(sih->chip)) || - (BCM4397_CHIP(sih->chip)) || - -#ifdef UNRELEASEDCHIP -#endif - - FALSE)) { /* building firmware for chips with a PCIe interface and internal SI bus */ -#else - if (BUSTYPE(bustype) == PCI_BUS) { -#endif /* BCMPCIEDEV */ - if (!curmap) - return 1; - - if (si_is_sprom_available(sih)) { - volatile uint16 *srom; - - srom = (volatile uint16 *)srom_offset(sih, curmap); - if (srom == NULL) - return 1; - - if (sprom_read_pci(osh, sih, srom, off, buf, nw, check_crc)) - return 1; - } -#if !defined(BCMDONGLEHOST) && (defined(BCMNVRAMW) || defined(BCMNVRAMR)) - else if (!((BUSTYPE(bustype) == SI_BUS) && - (BCM43602_CHIP(sih->chip) || - (BCM4369_CHIP(sih->chip)) || - (BCM4362_CHIP(sih->chip)) || - (BCM4378_CHIP(sih->chip)) || - (BCM4385_CHIP(sih->chip)) || - (BCM4389_CHIP(sih->chip)) || - (BCM4387_CHIP(sih->chip)) || - (BCM4388_CHIP(sih->chip)) || - (BCM4397_CHIP(sih->chip)) || - 0))) { - if (otp_read_pci(osh, sih, buf, nbytes)) - return 1; - } -#endif /* !BCMDONGLEHOST && (BCMNVRAMW||BCMNVRAMR) */ -#ifdef BCMSDIO - } else if (BUSTYPE(bustype) == SDIO_BUS) { - off = byteoff / 2; - nw = nbytes / 2; - for (i = 0; i < nw; i++) { - if (sprom_read_sdio(osh, (uint16)(off + i), (uint16 *)(buf + i))) - return 1; - } -#endif /* BCMSDIO */ -#ifdef BCMSPI - } else if (BUSTYPE(bustype) == SPI_BUS) { - if (bcmsdh_cis_read(NULL, SDIO_FUNC_1, (uint8 *)buf, byteoff + nbytes) != 0) - return 1; -#endif /* BCMSPI */ - } else if (BUSTYPE(bustype) == SI_BUS) { - return 1; - } else { - return 1; - } - - return 0; -} - -#if defined(WLTEST) || defined (DHD_SPROM) || defined (BCMDBG) -/** support only 16-bit word write into srom */ -int -srom_write(si_t *sih, uint bustype, volatile void *curmap, osl_t *osh, - uint byteoff, uint nbytes, uint16 *buf) -{ - uint i, nw, crc_range; - uint16 *old, *new; - uint8 crc; - volatile uint32 val32; - int rc = 1; - - ASSERT(bustype == BUSTYPE(bustype)); - - /* freed in same function */ - old = MALLOC_NOPERSIST(osh, SROM_MAXW * sizeof(uint16)); - new = MALLOC_NOPERSIST(osh, SROM_MAXW * sizeof(uint16)); - - if (old == NULL || new == NULL) - goto done; - - /* check input - 16-bit access only. use byteoff 0x55aa to indicate - * srclear - */ - if ((byteoff != 0x55aa) && ((byteoff & 1) || (nbytes & 1))) - goto done; - - if ((byteoff != 0x55aa) && ((byteoff + nbytes) > SROM_MAX)) - goto done; - - if (FALSE) { - } -#ifdef BCMSDIO - else if (BUSTYPE(bustype) == SDIO_BUS) { - crc_range = SROM_MAX; - } -#endif - else { - crc_range = srom_size(sih, osh); - } - - nw = crc_range / 2; - /* read first small number words from srom, then adjust the length, read all */ - if (srom_read(sih, bustype, curmap, osh, 0, crc_range, old, FALSE)) - goto done; - - BS_ERROR(("srom_write: old[SROM4_SIGN] 0x%x, old[SROM8_SIGN] 0x%x\n", - old[SROM4_SIGN], old[SROM8_SIGN])); - /* Deal with blank srom */ - if (old[0] == 0xffff) { - /* Do nothing to blank srom when it's srclear */ - if (byteoff == 0x55aa) { - rc = 0; - goto done; - } - - /* see if the input buffer is valid SROM image or not */ - if (buf[SROM11_SIGN] == SROM11_SIGNATURE) { - BS_ERROR(("srom_write: buf[SROM11_SIGN] 0x%x\n", - buf[SROM11_SIGN])); - - /* block invalid buffer size */ - if (nbytes < SROM11_WORDS * 2) { - rc = BCME_BUFTOOSHORT; - goto done; - } else if (nbytes > SROM11_WORDS * 2) { - rc = BCME_BUFTOOLONG; - goto done; - } - - nw = SROM11_WORDS; - - } else if (buf[SROM12_SIGN] == SROM12_SIGNATURE) { - BS_ERROR(("srom_write: buf[SROM12_SIGN] 0x%x\n", - buf[SROM12_SIGN])); - - /* block invalid buffer size */ - if (nbytes < SROM12_WORDS * 2) { - rc = BCME_BUFTOOSHORT; - goto done; - } else if (nbytes > SROM12_WORDS * 2) { - rc = BCME_BUFTOOLONG; - goto done; - } - - nw = SROM12_WORDS; - - } else if (buf[SROM13_SIGN] == SROM13_SIGNATURE) { - BS_ERROR(("srom_write: buf[SROM13_SIGN] 0x%x\n", - buf[SROM13_SIGN])); - - /* block invalid buffer size */ - if (nbytes < SROM13_WORDS * 2) { - rc = BCME_BUFTOOSHORT; - goto done; - } else if (nbytes > SROM13_WORDS * 2) { - rc = BCME_BUFTOOLONG; - goto done; - } - - nw = SROM13_WORDS; - - } else if (buf[SROM16_SIGN] == SROM16_SIGNATURE) { - BS_ERROR(("srom_write: buf[SROM16_SIGN] 0x%x\n", - buf[SROM16_SIGN])); - - /* block invalid buffer size */ - if (nbytes < SROM16_WORDS * 2) { - rc = BCME_BUFTOOSHORT; - goto done; - } else if (nbytes > SROM16_WORDS * 2) { - rc = BCME_BUFTOOLONG; - goto done; - } - - nw = SROM16_WORDS; - - } else if (buf[SROM17_SIGN] == SROM17_SIGNATURE) { - BS_ERROR(("srom_write: buf[SROM17_SIGN] 0x%x\n", - buf[SROM17_SIGN])); - - /* block invalid buffer size */ - if (nbytes < SROM17_WORDS * 2) { - rc = BCME_BUFTOOSHORT; - goto done; - } else if (nbytes > SROM17_WORDS * 2) { - rc = BCME_BUFTOOLONG; - goto done; - } - - nw = SROM17_WORDS; - } else if (buf[SROM18_SIGN] == SROM18_SIGNATURE) { - BS_ERROR(("srom_write: buf[SROM18_SIGN] 0x%x\n", - buf[SROM18_SIGN])); - - /* block invalid buffer size */ - /* nbytes can be < SROM18 bytes since host limits transfer chunk size - * to 1500 Bytes - */ - if (nbytes > SROM18_WORDS * 2) { - rc = BCME_BUFTOOLONG; - goto done; - } - - nw = SROM18_WORDS; - - } else if (buf[SROM11_SIGN] == SROM15_SIGNATURE) { - BS_ERROR(("srom_write: buf[SROM15_SIGN] 0x%x\n", - buf[SROM11_SIGN])); - /* nbytes can be < SROM15 bytes since host limits trasnfer chunk size - * to 1518 Bytes - */ - if (nbytes > SROM15_WORDS * 2) { - rc = BCME_BUFTOOLONG; - goto done; - } - nw = SROM15_WORDS; - } else if ((buf[SROM4_SIGN] == SROM4_SIGNATURE) || - (buf[SROM8_SIGN] == SROM4_SIGNATURE)) { - BS_ERROR(("srom_write: buf[SROM4_SIGN] 0x%x, buf[SROM8_SIGN] 0x%x\n", - buf[SROM4_SIGN], buf[SROM8_SIGN])); - - /* block invalid buffer size */ - if (nbytes < SROM4_WORDS * 2) { - rc = BCME_BUFTOOSHORT; - goto done; - } else if (nbytes > SROM4_WORDS * 2) { - rc = BCME_BUFTOOLONG; - goto done; - } - - nw = SROM4_WORDS; - } else if (nbytes == SROM_WORDS * 2){ /* the other possible SROM format */ - BS_ERROR(("srom_write: Not SROM4 or SROM8.\n")); - - nw = SROM_WORDS; - } else { - BS_ERROR(("srom_write: Invalid input file signature\n")); - rc = BCME_BADARG; - goto done; - } - crc_range = nw * 2; - if (srom_read(sih, bustype, curmap, osh, 0, crc_range, old, FALSE)) { - goto done; - } - } else if (old[SROM18_SIGN] == SROM18_SIGNATURE) { - nw = SROM18_WORDS; - crc_range = nw * 2; - if (srom_read(sih, bustype, curmap, osh, 0, crc_range, old, FALSE)) { - goto done; - } - } else if (old[SROM17_SIGN] == SROM17_SIGNATURE) { - nw = SROM17_WORDS; - crc_range = nw * 2; - if (srom_read(sih, bustype, curmap, osh, 0, crc_range, old, FALSE)) { - goto done; - } - } else if (old[SROM16_SIGN] == SROM16_SIGNATURE) { - nw = SROM16_WORDS; - crc_range = nw * 2; - if (srom_read(sih, bustype, curmap, osh, 0, crc_range, old, FALSE)) { - goto done; - } - } else if (old[SROM15_SIGN] == SROM15_SIGNATURE) { - nw = SROM15_WORDS; - crc_range = nw * 2; - if (srom_read(sih, bustype, curmap, osh, 0, crc_range, old, FALSE)) { - goto done; - } - } else if (old[SROM13_SIGN] == SROM13_SIGNATURE) { - nw = SROM13_WORDS; - crc_range = nw * 2; - if (srom_read(sih, bustype, curmap, osh, 0, crc_range, old, FALSE)) { - goto done; - } - } else if (old[SROM12_SIGN] == SROM12_SIGNATURE) { - nw = SROM12_WORDS; - crc_range = nw * 2; - if (srom_read(sih, bustype, curmap, osh, 0, crc_range, old, FALSE)) { - goto done; - } - } else if (old[SROM11_SIGN] == SROM11_SIGNATURE) { - nw = SROM11_WORDS; - crc_range = nw * 2; - if (srom_read(sih, bustype, curmap, osh, 0, crc_range, old, FALSE)) { - goto done; - } - } else if ((old[SROM4_SIGN] == SROM4_SIGNATURE) || - (old[SROM8_SIGN] == SROM4_SIGNATURE)) { - nw = SROM4_WORDS; - crc_range = nw * 2; - if (srom_read(sih, bustype, curmap, osh, 0, crc_range, old, FALSE)) { - goto done; - } - } else { - /* Assert that we have already read enough for sromrev 2 */ - ASSERT(crc_range >= SROM_WORDS * 2); - nw = SROM_WORDS; - crc_range = nw * 2; - } - - if (byteoff == 0x55aa) { - /* Erase request */ - crc_range = 0; - memset((void *)new, 0xff, nw * 2); - } else { - /* Copy old contents */ - bcopy((void *)old, (void *)new, nw * 2); - /* make changes */ - bcopy((void *)buf, (void *)&new[byteoff / 2], nbytes); - } - - if (crc_range) { - /* calculate crc */ - htol16_buf(new, crc_range); - crc = ~hndcrc8((uint8 *)new, crc_range - 1, CRC8_INIT_VALUE); - ltoh16_buf(new, crc_range); - new[nw - 1] = (crc << 8) | (new[nw - 1] & 0xff); - } - -#ifdef BCMPCIEDEV - if ((BUSTYPE(bustype) == SI_BUS) && - (BCM43602_CHIP(sih->chip) || - (BCM4369_CHIP(sih->chip)) || - (BCM4362_CHIP(sih->chip)) || - (BCM4378_CHIP(sih->chip)) || - (BCM4387_CHIP(sih->chip)) || - (BCM4388_CHIP(sih->chip)) || - (BCM4385_CHIP(sih->chip)) || - (BCM4389_CHIP(sih->chip)) || - (BCM4397_CHIP(sih->chip)) || - -#ifdef UNRELEASEDCHIP -#endif /* UNRELEASEDCHIP */ - - FALSE)) { -#else - if (BUSTYPE(bustype) == PCI_BUS) { -#endif /* BCMPCIEDEV */ - volatile uint16 *srom = NULL; - volatile void *ccregs = NULL; - uint32 ccval = 0; - - if ((CHIPID(sih->chip) == BCM4360_CHIP_ID) || - (CHIPID(sih->chip) == BCM43460_CHIP_ID) || - (CHIPID(sih->chip) == BCM43526_CHIP_ID) || - (CHIPID(sih->chip) == BCM4352_CHIP_ID) || - BCM43602_CHIP(sih->chip)) { - /* save current control setting */ - ccval = si_chipcontrl_read(sih); - } - - if (BCM43602_CHIP(sih->chip) || - (((CHIPID(sih->chip) == BCM4360_CHIP_ID) || - (CHIPID(sih->chip) == BCM43460_CHIP_ID) || - (CHIPID(sih->chip) == BCM4352_CHIP_ID)) && - (CHIPREV(sih->chiprev) <= 2))) { - si_chipcontrl_srom4360(sih, TRUE); - } - - if (FALSE) { - si_srom_clk_set(sih); /* corrects srom clock frequency */ - } - - /* enable writes to the SPROM */ - if (sih->ccrev > 31) { - if (BUSTYPE(sih->bustype) == SI_BUS) - ccregs = (void *)(uintptr)SI_ENUM_BASE(sih); - else - ccregs = ((volatile uint8 *)curmap + PCI_16KB0_CCREGS_OFFSET); - srom = (volatile uint16 *)((volatile uint8 *)ccregs + CC_SROM_OTP); - (void)srom_cc_cmd(sih, osh, ccregs, SRC_OP_WREN, 0, 0); - } else { - srom = (volatile uint16 *) - ((volatile uint8 *)curmap + PCI_BAR0_SPROM_OFFSET); - val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); - val32 |= SPROM_WRITEEN; - OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32); - } - bcm_mdelay(WRITE_ENABLE_DELAY); - /* write srom */ - for (i = 0; i < nw; i++) { - if (old[i] != new[i]) { - if (sih->ccrev > 31) { - if ((sih->cccaps & CC_CAP_SROM) == 0) { - /* No srom support in this chip */ - BS_ERROR(("srom_write, invalid srom, skip\n")); - } else - (void)srom_cc_cmd(sih, osh, ccregs, SRC_OP_WRITE, - i, new[i]); - } else { - W_REG(osh, &srom[i], new[i]); - } - bcm_mdelay(WRITE_WORD_DELAY); - } - } - /* disable writes to the SPROM */ - if (sih->ccrev > 31) { - (void)srom_cc_cmd(sih, osh, ccregs, SRC_OP_WRDIS, 0, 0); - } else { - OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & - ~SPROM_WRITEEN); - } - - if (BCM43602_CHIP(sih->chip) || - (CHIPID(sih->chip) == BCM4360_CHIP_ID) || - (CHIPID(sih->chip) == BCM43460_CHIP_ID) || - (CHIPID(sih->chip) == BCM4352_CHIP_ID)) { - /* Restore config after reading SROM */ - si_chipcontrl_restore(sih, ccval); - } -#ifdef BCMSDIO - } else if (BUSTYPE(bustype) == SDIO_BUS) { - /* enable writes to the SPROM */ - if (sprom_cmd_sdio(osh, SBSDIO_SPROM_WEN)) - goto done; - bcm_mdelay(WRITE_ENABLE_DELAY); - /* write srom */ - for (i = 0; i < nw; i++) { - if (old[i] != new[i]) { - sprom_write_sdio(osh, (uint16)(i), new[i]); - bcm_mdelay(WRITE_WORD_DELAY); - } - } - /* disable writes to the SPROM */ - if (sprom_cmd_sdio(osh, SBSDIO_SPROM_WDS)) - goto done; -#endif /* BCMSDIO */ - } else if (BUSTYPE(bustype) == SI_BUS) { - goto done; - } else { - goto done; - } - - bcm_mdelay(WRITE_ENABLE_DELAY); - rc = 0; - -done: - if (old != NULL) - MFREE(osh, old, SROM_MAXW * sizeof(uint16)); - if (new != NULL) - MFREE(osh, new, SROM_MAXW * sizeof(uint16)); - - return rc; -} - -/** support only 16-bit word write into srom */ -int -srom_write_short(si_t *sih, uint bustype, volatile void *curmap, osl_t *osh, - uint byteoff, uint16 value) -{ - volatile uint32 val32; - int rc = 1; - - ASSERT(bustype == BUSTYPE(bustype)); - - if (byteoff & 1) - goto done; - -#ifdef BCMPCIEDEV - if ((BUSTYPE(bustype) == SI_BUS) && - (BCM43602_CHIP(sih->chip) || - FALSE)) { -#else - if (BUSTYPE(bustype) == PCI_BUS) { -#endif /* BCMPCIEDEV */ - volatile uint16 *srom = NULL; - volatile void *ccregs = NULL; - uint32 ccval = 0; - - if (BCM43602_CHIP(sih->chip) || - (CHIPID(sih->chip) == BCM4360_CHIP_ID) || - (CHIPID(sih->chip) == BCM43460_CHIP_ID) || - (CHIPID(sih->chip) == BCM43526_CHIP_ID) || - (CHIPID(sih->chip) == BCM4352_CHIP_ID)) { - /* save current control setting */ - ccval = si_chipcontrl_read(sih); - } - - if (BCM43602_CHIP(sih->chip) || - (((CHIPID(sih->chip) == BCM4360_CHIP_ID) || - (CHIPID(sih->chip) == BCM43460_CHIP_ID) || - (CHIPID(sih->chip) == BCM4352_CHIP_ID)) && - (CHIPREV(sih->chiprev) <= 2))) { - si_chipcontrl_srom4360(sih, TRUE); - } - - if (FALSE) { - si_srom_clk_set(sih); /* corrects srom clock frequency */ - } - - /* enable writes to the SPROM */ - if (sih->ccrev > 31) { - if (BUSTYPE(sih->bustype) == SI_BUS) - ccregs = (void *)(uintptr)SI_ENUM_BASE(sih); - else - ccregs = ((volatile uint8 *)curmap + PCI_16KB0_CCREGS_OFFSET); - srom = (volatile uint16 *)((volatile uint8 *)ccregs + CC_SROM_OTP); - (void)srom_cc_cmd(sih, osh, ccregs, SRC_OP_WREN, 0, 0); - } else { - srom = (volatile uint16 *) - ((volatile uint8 *)curmap + PCI_BAR0_SPROM_OFFSET); - val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); - val32 |= SPROM_WRITEEN; - OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32); - } - bcm_mdelay(WRITE_ENABLE_DELAY); - /* write srom */ - if (sih->ccrev > 31) { - if ((sih->cccaps & CC_CAP_SROM) == 0) { - /* No srom support in this chip */ - BS_ERROR(("srom_write, invalid srom, skip\n")); - } else - (void)srom_cc_cmd(sih, osh, ccregs, SRC_OP_WRITE, - byteoff/2, value); - } else { - W_REG(osh, &srom[byteoff/2], value); - } - bcm_mdelay(WRITE_WORD_DELAY); - - /* disable writes to the SPROM */ - if (sih->ccrev > 31) { - (void)srom_cc_cmd(sih, osh, ccregs, SRC_OP_WRDIS, 0, 0); - } else { - OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & - ~SPROM_WRITEEN); - } - - if (BCM43602_CHIP(sih->chip) || - (CHIPID(sih->chip) == BCM4360_CHIP_ID) || - (CHIPID(sih->chip) == BCM43460_CHIP_ID) || - (CHIPID(sih->chip) == BCM43526_CHIP_ID) || - (CHIPID(sih->chip) == BCM4352_CHIP_ID)) { - /* Restore config after reading SROM */ - si_chipcontrl_restore(sih, ccval); - } -#ifdef BCMSDIO - } else if (BUSTYPE(bustype) == SDIO_BUS) { - /* enable writes to the SPROM */ - if (sprom_cmd_sdio(osh, SBSDIO_SPROM_WEN)) - goto done; - bcm_mdelay(WRITE_ENABLE_DELAY); - /* write srom */ - sprom_write_sdio(osh, (uint16)(byteoff/2), value); - bcm_mdelay(WRITE_WORD_DELAY); - - /* disable writes to the SPROM */ - if (sprom_cmd_sdio(osh, SBSDIO_SPROM_WDS)) - goto done; -#endif /* BCMSDIO */ - } else if (BUSTYPE(bustype) == SI_BUS) { - goto done; - } else { - goto done; - } - - bcm_mdelay(WRITE_ENABLE_DELAY); - rc = 0; - -done: - return rc; -} -#endif /* defined(WLTEST) || defined (DHD_SPROM) || defined (BCMDBG) */ - -/** - * These 'vstr_*' definitions are used to convert from CIS format to a 'NVRAM var=val' format, the - * NVRAM format is used throughout the rest of the firmware. - */ -#if !defined(BCMDONGLEHOST) -static const char BCMATTACHDATA(vstr_manf)[] = "manf=%s"; -static const char BCMATTACHDATA(vstr_productname)[] = "productname=%s"; -static const char BCMATTACHDATA(vstr_manfid)[] = "manfid=0x%x"; -static const char BCMATTACHDATA(vstr_prodid)[] = "prodid=0x%x"; -#ifdef BCMSDIO -static const char BCMATTACHDATA(vstr_sdmaxspeed)[] = "sdmaxspeed=%d"; -static const char BCMATTACHDATA(vstr_sdmaxblk)[][13] = - { "sdmaxblk0=%d", "sdmaxblk1=%d", "sdmaxblk2=%d" }; -#endif -static const char BCMATTACHDATA(vstr_regwindowsz)[] = "regwindowsz=%d"; -static const char BCMATTACHDATA(vstr_sromrev)[] = "sromrev=%d"; -static const char BCMATTACHDATA(vstr_chiprev)[] = "chiprev=%d"; -static const char BCMATTACHDATA(vstr_subvendid)[] = "subvendid=0x%x"; -static const char BCMATTACHDATA(vstr_subdevid)[] = "subdevid=0x%x"; -static const char BCMATTACHDATA(vstr_boardrev)[] = "boardrev=0x%x"; -static const char BCMATTACHDATA(vstr_aa2g)[] = "aa2g=0x%x"; -static const char BCMATTACHDATA(vstr_aa5g)[] = "aa5g=0x%x"; -static const char BCMATTACHDATA(vstr_ag)[] = "ag%d=0x%x"; -static const char BCMATTACHDATA(vstr_cc)[] = "cc=%d"; -static const char BCMATTACHDATA(vstr_opo)[] = "opo=%d"; -static const char BCMATTACHDATA(vstr_pa0b)[][9] = { "pa0b0=%d", "pa0b1=%d", "pa0b2=%d" }; -static const char BCMATTACHDATA(vstr_pa0b_lo)[][12] = - { "pa0b0_lo=%d", "pa0b1_lo=%d", "pa0b2_lo=%d" }; -static const char BCMATTACHDATA(vstr_pa0itssit)[] = "pa0itssit=%d"; -static const char BCMATTACHDATA(vstr_pa0maxpwr)[] = "pa0maxpwr=%d"; -static const char BCMATTACHDATA(vstr_pa1b)[][9] = { "pa1b0=%d", "pa1b1=%d", "pa1b2=%d" }; -static const char BCMATTACHDATA(vstr_pa1lob)[][11] = - { "pa1lob0=%d", "pa1lob1=%d", "pa1lob2=%d" }; -static const char BCMATTACHDATA(vstr_pa1hib)[][11] = - { "pa1hib0=%d", "pa1hib1=%d", "pa1hib2=%d" }; -static const char BCMATTACHDATA(vstr_pa1itssit)[] = "pa1itssit=%d"; -static const char BCMATTACHDATA(vstr_pa1maxpwr)[] = "pa1maxpwr=%d"; -static const char BCMATTACHDATA(vstr_pa1lomaxpwr)[] = "pa1lomaxpwr=%d"; -static const char BCMATTACHDATA(vstr_pa1himaxpwr)[] = "pa1himaxpwr=%d"; -static const char BCMATTACHDATA(vstr_oem)[] = "oem=%02x%02x%02x%02x%02x%02x%02x%02x"; -static const char BCMATTACHDATA(vstr_boardflags)[] = "boardflags=0x%x"; -static const char BCMATTACHDATA(vstr_boardflags2)[] = "boardflags2=0x%x"; -static const char BCMATTACHDATA(vstr_boardflags3)[] = "boardflags3=0x%x"; -static const char BCMATTACHDATA(vstr_boardflags4)[] = "boardflags4=0x%x"; -static const char BCMATTACHDATA(vstr_boardflags5)[] = "boardflags5=0x%x"; -static const char BCMATTACHDATA(vstr_noccode)[] = "ccode=0x0"; -static const char BCMATTACHDATA(vstr_ccode)[] = "ccode=%c%c"; -static const char BCMATTACHDATA(vstr_cctl)[] = "cctl=0x%x"; -static const char BCMATTACHDATA(vstr_cckpo)[] = "cckpo=0x%x"; -static const char BCMATTACHDATA(vstr_ofdmpo)[] = "ofdmpo=0x%x"; -static const char BCMATTACHDATA(vstr_rdlid)[] = "rdlid=0x%x"; -#ifdef BCM_BOOTLOADER -static const char BCMATTACHDATA(vstr_rdlrndis)[] = "rdlrndis=%d"; -static const char BCMATTACHDATA(vstr_rdlrwu)[] = "rdlrwu=%d"; -static const char BCMATTACHDATA(vstr_rdlsn)[] = "rdlsn=%d"; -#endif /* BCM_BOOTLOADER */ -static const char BCMATTACHDATA(vstr_usbfs)[] = "usbfs=%d"; -static const char BCMATTACHDATA(vstr_wpsgpio)[] = "wpsgpio=%d"; -static const char BCMATTACHDATA(vstr_wpsled)[] = "wpsled=%d"; -static const char BCMATTACHDATA(vstr_rssismf2g)[] = "rssismf2g=%d"; -static const char BCMATTACHDATA(vstr_rssismc2g)[] = "rssismc2g=%d"; -static const char BCMATTACHDATA(vstr_rssisav2g)[] = "rssisav2g=%d"; -static const char BCMATTACHDATA(vstr_bxa2g)[] = "bxa2g=%d"; -static const char BCMATTACHDATA(vstr_rssismf5g)[] = "rssismf5g=%d"; -static const char BCMATTACHDATA(vstr_rssismc5g)[] = "rssismc5g=%d"; -static const char BCMATTACHDATA(vstr_rssisav5g)[] = "rssisav5g=%d"; -static const char BCMATTACHDATA(vstr_bxa5g)[] = "bxa5g=%d"; -static const char BCMATTACHDATA(vstr_tri2g)[] = "tri2g=%d"; -static const char BCMATTACHDATA(vstr_tri5gl)[] = "tri5gl=%d"; -static const char BCMATTACHDATA(vstr_tri5g)[] = "tri5g=%d"; -static const char BCMATTACHDATA(vstr_tri5gh)[] = "tri5gh=%d"; -static const char BCMATTACHDATA(vstr_rxpo2g)[] = "rxpo2g=%d"; -static const char BCMATTACHDATA(vstr_rxpo5g)[] = "rxpo5g=%d"; -static const char BCMATTACHDATA(vstr_boardtype)[] = "boardtype=0x%x"; -static const char BCMATTACHDATA(vstr_vendid)[] = "vendid=0x%x"; -static const char BCMATTACHDATA(vstr_devid)[] = "devid=0x%x"; -static const char BCMATTACHDATA(vstr_xtalfreq)[] = "xtalfreq=%d"; -static const char BCMATTACHDATA(vstr_txchain)[] = "txchain=0x%x"; -static const char BCMATTACHDATA(vstr_rxchain)[] = "rxchain=0x%x"; -static const char BCMATTACHDATA(vstr_elna2g)[] = "elna2g=0x%x"; -static const char BCMATTACHDATA(vstr_elna5g)[] = "elna5g=0x%x"; -static const char BCMATTACHDATA(vstr_antswitch)[] = "antswitch=0x%x"; -static const char BCMATTACHDATA(vstr_regrev)[] = "regrev=0x%x"; -static const char BCMATTACHDATA(vstr_antswctl2g)[] = "antswctl2g=0x%x"; -static const char BCMATTACHDATA(vstr_triso2g)[] = "triso2g=0x%x"; -static const char BCMATTACHDATA(vstr_pdetrange2g)[] = "pdetrange2g=0x%x"; -static const char BCMATTACHDATA(vstr_extpagain2g)[] = "extpagain2g=0x%x"; -static const char BCMATTACHDATA(vstr_tssipos2g)[] = "tssipos2g=0x%x"; -static const char BCMATTACHDATA(vstr_antswctl5g)[] = "antswctl5g=0x%x"; -static const char BCMATTACHDATA(vstr_triso5g)[] = "triso5g=0x%x"; -static const char BCMATTACHDATA(vstr_pdetrange5g)[] = "pdetrange5g=0x%x"; -static const char BCMATTACHDATA(vstr_extpagain5g)[] = "extpagain5g=0x%x"; -static const char BCMATTACHDATA(vstr_tssipos5g)[] = "tssipos5g=0x%x"; -static const char BCMATTACHDATA(vstr_maxp2ga)[] = "maxp2ga%d=0x%x"; -static const char BCMATTACHDATA(vstr_itt2ga0)[] = "itt2ga0=0x%x"; -static const char BCMATTACHDATA(vstr_pa)[] = "pa%dgw%da%d=0x%x"; -static const char BCMATTACHDATA(vstr_pahl)[] = "pa%dg%cw%da%d=0x%x"; -static const char BCMATTACHDATA(vstr_maxp5ga0)[] = "maxp5ga0=0x%x"; -static const char BCMATTACHDATA(vstr_itt5ga0)[] = "itt5ga0=0x%x"; -static const char BCMATTACHDATA(vstr_maxp5gha0)[] = "maxp5gha0=0x%x"; -static const char BCMATTACHDATA(vstr_maxp5gla0)[] = "maxp5gla0=0x%x"; -static const char BCMATTACHDATA(vstr_itt2ga1)[] = "itt2ga1=0x%x"; -static const char BCMATTACHDATA(vstr_maxp5ga1)[] = "maxp5ga1=0x%x"; -static const char BCMATTACHDATA(vstr_itt5ga1)[] = "itt5ga1=0x%x"; -static const char BCMATTACHDATA(vstr_maxp5gha1)[] = "maxp5gha1=0x%x"; -static const char BCMATTACHDATA(vstr_maxp5gla1)[] = "maxp5gla1=0x%x"; -static const char BCMATTACHDATA(vstr_cck2gpo)[] = "cck2gpo=0x%x"; -static const char BCMATTACHDATA(vstr_ofdm2gpo)[] = "ofdm2gpo=0x%x"; -static const char BCMATTACHDATA(vstr_ofdm5gpo)[] = "ofdm5gpo=0x%x"; -static const char BCMATTACHDATA(vstr_ofdm5glpo)[] = "ofdm5glpo=0x%x"; -static const char BCMATTACHDATA(vstr_ofdm5ghpo)[] = "ofdm5ghpo=0x%x"; -static const char BCMATTACHDATA(vstr_cddpo)[] = "cddpo=0x%x"; -static const char BCMATTACHDATA(vstr_stbcpo)[] = "stbcpo=0x%x"; -static const char BCMATTACHDATA(vstr_bw40po)[] = "bw40po=0x%x"; -static const char BCMATTACHDATA(vstr_bwduppo)[] = "bwduppo=0x%x"; -static const char BCMATTACHDATA(vstr_mcspo)[] = "mcs%dgpo%d=0x%x"; -static const char BCMATTACHDATA(vstr_mcspohl)[] = "mcs%dg%cpo%d=0x%x"; -static const char BCMATTACHDATA(vstr_custom)[] = "customvar%d=0x%x"; -static const char BCMATTACHDATA(vstr_cckdigfilttype)[] = "cckdigfilttype=%d"; -static const char BCMATTACHDATA(vstr_usbflags)[] = "usbflags=0x%x"; -#ifdef BCM_BOOTLOADER -static const char BCMATTACHDATA(vstr_mdio)[] = "mdio%d=0x%%x"; -static const char BCMATTACHDATA(vstr_mdioex)[] = "mdioex%d=0x%%x"; -static const char BCMATTACHDATA(vstr_brmin)[] = "brmin=0x%x"; -static const char BCMATTACHDATA(vstr_brmax)[] = "brmax=0x%x"; -static const char BCMATTACHDATA(vstr_pllreg)[] = "pll%d=0x%x"; -static const char BCMATTACHDATA(vstr_ccreg)[] = "chipc%d=0x%x"; -static const char BCMATTACHDATA(vstr_regctrl)[] = "reg%d=0x%x"; -static const char BCMATTACHDATA(vstr_time)[] = "r%dt=0x%x"; -static const char BCMATTACHDATA(vstr_depreg)[] = "r%dd=0x%x"; -static const char BCMATTACHDATA(vstr_usbpredly)[] = "usbpredly=0x%x"; -static const char BCMATTACHDATA(vstr_usbpostdly)[] = "usbpostdly=0x%x"; -static const char BCMATTACHDATA(vstr_usbrdy)[] = "usbrdy=0x%x"; -static const char BCMATTACHDATA(vstr_hsicphyctrl1)[] = "hsicphyctrl1=0x%x"; -static const char BCMATTACHDATA(vstr_hsicphyctrl2)[] = "hsicphyctrl2=0x%x"; -static const char BCMATTACHDATA(vstr_usbdevctrl)[] = "usbdevctrl=0x%x"; -static const char BCMATTACHDATA(vstr_bldr_reset_timeout)[] = "bldr_to=0x%x"; -static const char BCMATTACHDATA(vstr_muxenab)[] = "muxenab=0x%x"; -static const char BCMATTACHDATA(vstr_pubkey)[] = "pubkey=%s"; -#endif /* BCM_BOOTLOADER */ -static const char BCMATTACHDATA(vstr_boardnum)[] = "boardnum=%d"; -static const char BCMATTACHDATA(vstr_macaddr)[] = "macaddr=%s"; -static const char BCMATTACHDATA(vstr_macaddr2)[] = "macaddr2=%s"; -static const char BCMATTACHDATA(vstr_usbepnum)[] = "usbepnum=0x%x"; -#ifdef BCMUSBDEV_COMPOSITE -static const char BCMATTACHDATA(vstr_usbdesc_composite)[] = "usbdesc_composite=0x%x"; -#endif /* BCMUSBDEV_COMPOSITE */ -static const char BCMATTACHDATA(vstr_usbutmi_ctl)[] = "usbutmi_ctl=0x%x"; -static const char BCMATTACHDATA(vstr_usbssphy_utmi_ctl0)[] = "usbssphy_utmi_ctl0=0x%x"; -static const char BCMATTACHDATA(vstr_usbssphy_utmi_ctl1)[] = "usbssphy_utmi_ctl1=0x%x"; -static const char BCMATTACHDATA(vstr_usbssphy_utmi_ctl2)[] = "usbssphy_utmi_ctl2=0x%x"; -static const char BCMATTACHDATA(vstr_usbssphy_sleep0)[] = "usbssphy_sleep0=0x%x"; -static const char BCMATTACHDATA(vstr_usbssphy_sleep1)[] = "usbssphy_sleep1=0x%x"; -static const char BCMATTACHDATA(vstr_usbssphy_sleep2)[] = "usbssphy_sleep2=0x%x"; -static const char BCMATTACHDATA(vstr_usbssphy_sleep3)[] = "usbssphy_sleep3=0x%x"; -static const char BCMATTACHDATA(vstr_usbssphy_mdio)[] = "usbssmdio%d=0x%x,0x%x,0x%x,0x%x"; -static const char BCMATTACHDATA(vstr_usb30phy_noss)[] = "usbnoss=0x%x"; -static const char BCMATTACHDATA(vstr_usb30phy_u1u2)[] = "usb30u1u2=0x%x"; -static const char BCMATTACHDATA(vstr_usb30phy_regs)[] = "usb30regs%d=0x%x,0x%x,0x%x,0x%x"; - -/* Power per rate for SROM V9 */ -static const char BCMATTACHDATA(vstr_cckbw202gpo)[][21] = - { "cckbw202gpo=0x%x", "cckbw20ul2gpo=0x%x", "cckbw20in802gpo=0x%x" }; -static const char BCMATTACHDATA(vstr_legofdmbw202gpo)[][23] = - { "legofdmbw202gpo=0x%x", "legofdmbw20ul2gpo=0x%x" }; -static const char BCMATTACHDATA(vstr_legofdmbw205gpo)[][24] = - { "legofdmbw205glpo=0x%x", "legofdmbw20ul5glpo=0x%x", - "legofdmbw205gmpo=0x%x", "legofdmbw20ul5gmpo=0x%x", - "legofdmbw205ghpo=0x%x", "legofdmbw20ul5ghpo=0x%x" }; - -static const char BCMATTACHDATA(vstr_mcs2gpo)[][19] = -{ "mcsbw202gpo=0x%x", "mcsbw20ul2gpo=0x%x", "mcsbw402gpo=0x%x", "mcsbw802gpo=0x%x" }; - -static const char BCMATTACHDATA(vstr_mcs5glpo)[][20] = - { "mcsbw205glpo=0x%x", "mcsbw20ul5glpo=0x%x", "mcsbw405glpo=0x%x" }; - -static const char BCMATTACHDATA(vstr_mcs5gmpo)[][20] = - { "mcsbw205gmpo=0x%x", "mcsbw20ul5gmpo=0x%x", "mcsbw405gmpo=0x%x" }; - -static const char BCMATTACHDATA(vstr_mcs5ghpo)[][20] = - { "mcsbw205ghpo=0x%x", "mcsbw20ul5ghpo=0x%x", "mcsbw405ghpo=0x%x" }; - -static const char BCMATTACHDATA(vstr_mcs32po)[] = "mcs32po=0x%x"; -static const char BCMATTACHDATA(vstr_legofdm40duppo)[] = "legofdm40duppo=0x%x"; - -/* SROM V11 */ -static const char BCMATTACHDATA(vstr_tempthresh)[] = "tempthresh=%d"; /* HNBU_TEMPTHRESH */ -static const char BCMATTACHDATA(vstr_temps_period)[] = "temps_period=%d"; -static const char BCMATTACHDATA(vstr_temps_hysteresis)[] = "temps_hysteresis=%d"; -static const char BCMATTACHDATA(vstr_tempoffset)[] = "tempoffset=%d"; -static const char BCMATTACHDATA(vstr_tempsense_slope)[] = "tempsense_slope=%d"; -static const char BCMATTACHDATA(vstr_temp_corrx)[] = "tempcorrx=%d"; -static const char BCMATTACHDATA(vstr_tempsense_option)[] = "tempsense_option=%d"; -static const char BCMATTACHDATA(vstr_phycal_tempdelta)[] = "phycal_tempdelta=%d"; -static const char BCMATTACHDATA(vstr_tssiposslopeg)[] = "tssiposslope%dg=%d"; /* HNBU_FEM_CFG */ -static const char BCMATTACHDATA(vstr_epagaing)[] = "epagain%dg=%d"; -static const char BCMATTACHDATA(vstr_pdgaing)[] = "pdgain%dg=%d"; -static const char BCMATTACHDATA(vstr_tworangetssi)[] = "tworangetssi%dg=%d"; -static const char BCMATTACHDATA(vstr_papdcap)[] = "papdcap%dg=%d"; -static const char BCMATTACHDATA(vstr_femctrl)[] = "femctrl=%d"; -static const char BCMATTACHDATA(vstr_gainctrlsph)[] = "gainctrlsph=%d"; -static const char BCMATTACHDATA(vstr_subband5gver)[] = "subband5gver=%d"; /* HNBU_ACPA_CX */ -static const char BCMATTACHDATA(vstr_pa2ga)[] = "pa2ga%d=0x%x,0x%x,0x%x"; -static const char BCMATTACHDATA(vstr_maxp5ga)[] = "maxp5ga%d=0x%x,0x%x,0x%x,0x%x"; -static const char BCMATTACHDATA(vstr_pa5ga)[] = "pa5ga%d=0x%x,0x%x,0x%x,0x%x,0x%x,0x%x," - "0x%x,0x%x,0x%x,0x%x,0x%x,0x%x"; -static const char BCMATTACHDATA(vstr_subband6gver)[] = "subband6gver=%d"; /* HNBU_ACPA_CX */ -static const char BCMATTACHDATA(vstr_maxp6ga)[] = "maxp6ga%d=0x%x,0x%x,0x%x,0x%x,0x%x,0x%x"; -static const char BCMATTACHDATA(vstr_pa6ga)[] = "pa6ga%d=0x%x,0x%x,0x%x,0x%x,0x%x,0x%x," - "0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x"; -static const char BCMATTACHDATA(vstr_pa2gccka)[] = "pa2gccka%d=0x%x,0x%x,0x%x"; -static const char BCMATTACHDATA(vstr_pa5gbw40a)[] = "pa5gbw40a%d=0x%x,0x%x,0x%x,0x%x,0x%x,0x%x," - "0x%x,0x%x,0x%x,0x%x,0x%x,0x%x"; -static const char BCMATTACHDATA(vstr_pa5gbw80a)[] = "pa5gbw80a%d=0x%x,0x%x,0x%x,0x%x,0x%x,0x%x," - "0x%x,0x%x,0x%x,0x%x,0x%x,0x%x"; -static const char BCMATTACHDATA(vstr_pa5gbw4080a)[] = "pa5gbw4080a%d=0x%x,0x%x,0x%x,0x%x,0x%x,0x%x," - "0x%x,0x%x,0x%x,0x%x,0x%x,0x%x"; -static const char BCMATTACHDATA(vstr_rxgainsgelnagaina)[] = "rxgains%dgelnagaina%d=%d"; -static const char BCMATTACHDATA(vstr_rxgainsgtrisoa)[] = "rxgains%dgtrisoa%d=%d"; -static const char BCMATTACHDATA(vstr_rxgainsgtrelnabypa)[] = "rxgains%dgtrelnabypa%d=%d"; -static const char BCMATTACHDATA(vstr_rxgainsgxelnagaina)[] = "rxgains%dg%celnagaina%d=%d"; -static const char BCMATTACHDATA(vstr_rxgainsgxtrisoa)[] = "rxgains%dg%ctrisoa%d=%d"; -static const char BCMATTACHDATA(vstr_rxgainsgxtrelnabypa)[] = "rxgains%dg%ctrelnabypa%d=%d"; -static const char BCMATTACHDATA(vstr_measpower)[] = "measpower=0x%x"; /* HNBU_MEAS_PWR */ -static const char BCMATTACHDATA(vstr_measpowerX)[] = "measpower%d=0x%x"; -static const char BCMATTACHDATA(vstr_pdoffsetma)[] = "pdoffset%dma%d=0x%x"; /* HNBU_PDOFF */ -static const char BCMATTACHDATA(vstr_pdoffset2gma)[] = "pdoffset2g%dma%d=0x%x"; /* HNBU_PDOFF_2G */ -static const char BCMATTACHDATA(vstr_pdoffset2gmvalid)[] = "pdoffset2g%dmvalid=0x%x"; -static const char BCMATTACHDATA(vstr_rawtempsense)[] = "rawtempsense=0x%x"; -/* HNBU_ACPPR_2GPO */ -static const char BCMATTACHDATA(vstr_dot11agofdmhrbw202gpo)[] = "dot11agofdmhrbw202gpo=0x%x"; -static const char BCMATTACHDATA(vstr_ofdmlrbw202gpo)[] = "ofdmlrbw202gpo=0x%x"; -static const char BCMATTACHDATA(vstr_mcsbw805gpo)[] = "mcsbw805g%cpo=0x%x"; /* HNBU_ACPPR_5GPO */ -static const char BCMATTACHDATA(vstr_mcsbw1605gpo)[] = "mcsbw1605g%cpo=0x%x"; -static const char BCMATTACHDATA(vstr_mcsbw80p805gpo)[] = "mcsbw80p805g%cpo=0x%x"; -static const char BCMATTACHDATA(vstr_mcsbw80p805g1po)[] = "mcsbw80p805g%c1po=0x%x"; -static const char BCMATTACHDATA(vstr_mcsbw1605g1po)[] = "mcsbw1605g%c1po=0x%x"; -static const char BCMATTACHDATA(vstr_mcsbw805g1po)[] = "mcsbw805g%c1po=0x%x"; -static const char BCMATTACHDATA(vstr_mcsbw405g1po)[] = "mcsbw405g%c1po=0x%x"; -static const char BCMATTACHDATA(vstr_mcsbw205g1po)[] = "mcsbw205g%c1po=0x%x"; -static const char BCMATTACHDATA(vstr_mcslr5gpo)[] = "mcslr5g%cpo=0x%x"; -static const char BCMATTACHDATA(vstr_mcslr5g1po)[] = "mcslr5g%c1po=0x%x"; -static const char BCMATTACHDATA(vstr_mcslr5g80p80po)[] = "mcslr5g80p80po=0x%x"; -/* HNBU_ACPPR_SBPO */ -static const char BCMATTACHDATA(vstr_sb20in40rpo)[] = "sb20in40%crpo=0x%x"; -/* HNBU_ACPPR_SBPO */ -static const char BCMATTACHDATA(vstr_sb20in40and80rpo)[] = "sb20in40and80%crpo=0x%x"; -static const char BCMATTACHDATA(vstr_sb20in80and160r5gpo)[] = "sb20in80and160%cr5g%cpo=0x%x"; -static const char BCMATTACHDATA(vstr_sb20in80and160r5g1po)[] = "sb20in80and160%cr5g%c1po=0x%x"; -static const char BCMATTACHDATA(vstr_sb2040and80in80p80r5gpo)[] = - "sb2040and80in80p80%cr5g%cpo=0x%x"; -static const char BCMATTACHDATA(vstr_sb2040and80in80p80r5g1po)[] = - "sb2040and80in80p80%cr5g%c1po=0x%x"; -static const char BCMATTACHDATA(vstr_sb20in40dot11agofdm2gpo)[] = "sb20in40dot11agofdm2gpo=0x%x"; -static const char BCMATTACHDATA(vstr_sb20in80dot11agofdm2gpo)[] = "sb20in80dot11agofdm2gpo=0x%x"; -static const char BCMATTACHDATA(vstr_sb20in40ofdmlrbw202gpo)[] = "sb20in40ofdmlrbw202gpo=0x%x"; -static const char BCMATTACHDATA(vstr_sb20in80ofdmlrbw202gpo)[] = "sb20in80ofdmlrbw202gpo=0x%x"; -static const char BCMATTACHDATA(vstr_sb20in80p80r5gpo)[] = "sb20in80p80%cr5gpo=0x%x"; -static const char BCMATTACHDATA(vstr_sb40and80r5gpo)[] = "sb40and80%cr5g%cpo=0x%x"; -static const char BCMATTACHDATA(vstr_sb40and80r5g1po)[] = "sb40and80%cr5g%c1po=0x%x"; -static const char BCMATTACHDATA(vstr_dot11agduprpo)[] = "dot11agdup%crpo=0x%x"; -static const char BCMATTACHDATA(vstr_dot11agduppo)[] = "dot11agduppo=0x%x"; -static const char BCMATTACHDATA(vstr_noiselvl2ga)[] = "noiselvl2ga%d=%d"; /* HNBU_NOISELVL */ -static const char BCMATTACHDATA(vstr_noiselvl5ga)[] = "noiselvl5ga%d=%d,%d,%d,%d"; -/* HNBU_RXGAIN_ERR */ -static const char BCMATTACHDATA(vstr_rxgainerr2ga)[] = "rxgainerr2ga%d=0x%x"; -static const char BCMATTACHDATA(vstr_rxgainerr5ga)[] = "rxgainerr5ga%d=0x%x,0x%x,0x%x,0x%x"; -static const char BCMATTACHDATA(vstr_agbg)[] = "agbg%d=0x%x"; /* HNBU_AGBGA */ -static const char BCMATTACHDATA(vstr_aga)[] = "aga%d=0x%x"; -static const char BCMATTACHDATA(vstr_txduty_ofdm)[] = "tx_duty_cycle_ofdm_%d_5g=%d"; -static const char BCMATTACHDATA(vstr_txduty_thresh)[] = "tx_duty_cycle_thresh_%d_5g=%d"; -static const char BCMATTACHDATA(vstr_paparambwver)[] = "paparambwver=%d"; - -static const char BCMATTACHDATA(vstr_uuid)[] = "uuid=%s"; - -static const char BCMATTACHDATA(vstr_wowlgpio)[] = "wowl_gpio=%d"; -static const char BCMATTACHDATA(vstr_wowlgpiopol)[] = "wowl_gpiopol=%d"; - -static const char BCMATTACHDATA(rstr_ag0)[] = "ag0"; -static const char BCMATTACHDATA(rstr_sromrev)[] = "sromrev"; - -static const char BCMATTACHDATA(vstr_paparamrpcalvars)[][20] = - {"rpcal2g=0x%x", "rpcal5gb0=0x%x", "rpcal5gb1=0x%x", - "rpcal5gb2=0x%x", "rpcal5gb3=0x%x"}; - -static const char BCMATTACHDATA(vstr_gpdn)[] = "gpdn=0x%x"; - -/* SROM V13 PA */ -static const char BCMATTACHDATA(vstr_sr13pa2ga)[] = "pa2ga%d=0x%x,0x%x,0x%x,0x%x"; -static const char BCMATTACHDATA(vstr_maxp5gba)[] = "maxp5gb%da%d=0x%x"; -static const char BCMATTACHDATA(vstr_sr13pa5ga)[] = "pa5ga%d=%s"; -static const char BCMATTACHDATA(vstr_sr13pa5gbwa)[] = "pa5g%da%d=%s"; -static const char BCMATTACHDATA(vstr_pa2g40a)[] = "pa2g40a%d=0x%x,0x%x,0x%x,0x%x"; - -/* RSSI Cal parameters */ -static const char BCMATTACHDATA(vstr_rssicalfrqg)[] = - "rssi_cal_freq_grp_2g=0x%x0x%x0x%x0x%x0x%x0x%x0x%x"; -static const char BCMATTACHDATA(vstr_rssidelta2g)[] = - "rssi_delta_2gb%d=%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d"; -static const char BCMATTACHDATA(vstr_rssidelta5g)[] = - "rssi_delta_5g%s=%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d"; - -uint8 patch_pair = 0; - -/* For dongle HW, accept partial calibration parameters */ -#if defined(BCMSDIODEV) || defined(BCMUSBDEV) || defined(BCMDONGLEHOST) -#define BCMDONGLECASE(n) case n: -#else -#define BCMDONGLECASE(n) -#endif - -#ifdef BCM_BOOTLOADER -/* The format of the PMUREGS OTP Tuple -> - * 1 byte -> Lower 5 bits has the address of the register - * Higher 3 bits has the mode of the register like - * PLL, ChipCtrl, RegCtrl, UpDwn or Dependency mask - * 4 bytes -> Value of the register to be updated. - */ -#define PMUREGS_MODE_MASK 0xE0 -#define PMUREGS_MODE_SHIFT 5 -#define PMUREGS_ADDR_MASK 0x1F -#define PMUREGS_TPL_SIZE 5 - -enum { - PMU_PLLREG_MODE, - PMU_CCREG_MODE, - PMU_VOLTREG_MODE, - PMU_RES_TIME_MODE, - PMU_RESDEPEND_MODE -}; - -#define USBREGS_TPL_SIZE 5 -enum { - USB_DEV_CTRL_REG, - HSIC_PHY_CTRL1_REG, - HSIC_PHY_CTRL2_REG -}; - -#define USBRDY_DLY_TYPE 0x8000 /* Bit indicating if the byte is pre or post delay value */ -#define USBRDY_DLY_MASK 0x7FFF /* Bits indicating the amount of delay */ -#define USBRDY_MAXOTP_SIZE 5 /* Max size of the OTP parameter */ - -#endif /* BCM_BOOTLOADER */ - -static uint -BCMATTACHFN(get_max_cis_size)(si_t *sih) -{ - uint max_cis_size; - void *oh; - - max_cis_size = (sih && sih->ccrev >= 49) ? CIS_SIZE_12K : CIS_SIZE; - if (sih && (oh = otp_init(sih)) != NULL) { - max_cis_size -= otp_avsbitslen(oh); - } - return max_cis_size; -} - -#ifndef BCM_BOOTLOADER -static uint32 -BCMATTACHFN(srom_data2value)(uint8 *p, uint8 len) -{ - uint8 pos = 0; - uint32 value = 0; - - ASSERT(len <= 4); - - while (pos < len) { - value += (p[pos] << (pos * 8)); - pos++; - } - - return value; -} -#endif /* BCM_BOOTLOADER */ - -/** - * Both SROM and OTP contain variables in 'CIS' format, whereas the rest of the firmware works with - * 'variable/value' string pairs. - */ -int -BCMATTACHFN(srom_parsecis)(si_t *sih, osl_t *osh, uint8 *pcis[], uint ciscnt, char **vars, - uint *count) -{ - char eabuf[32]; - char eabuf2[32]; - char *base; - varbuf_t b; - uint8 *cis, tup, tlen, sromrev = 1; - uint i; - uint16 j; -#ifndef BCM_BOOTLOADER - bool ag_init = FALSE; -#endif - uint32 w32; - uint funcid; - uint cisnum; - int32 boardnum; - int err; - bool standard_cis; - uint max_cis_size; - uint var_cis_size = 0; - - ASSERT(count != NULL); - - if (vars == NULL) { - ASSERT(0); /* crash debug images for investigation */ - return BCME_BADARG; - } - - boardnum = -1; - - /* freed in same function */ - max_cis_size = get_max_cis_size(sih); - var_cis_size = *count + ((max_cis_size + 2u) * ciscnt); - - ASSERT(var_cis_size <= MAXSZ_NVRAM_VARS); - - base = MALLOC_NOPERSIST(osh, var_cis_size); - ASSERT(base != NULL); - if (!base) - return -2; - - varbuf_init(&b, base, var_cis_size); - bzero(base, var_cis_size); - /* Append from vars if there's already something inside */ - if (*vars && **vars && (*count >= 3)) { - /* back off \0 at the end, leaving only one \0 for the last param */ - while (((*vars)[(*count)-1] == '\0') && ((*vars)[(*count)-2] == '\0')) - (*count)--; - - bcopy(*vars, base, *count); - b.buf += *count; - } - eabuf[0] = '\0'; - eabuf2[0] = '\0'; - for (cisnum = 0; cisnum < ciscnt; cisnum++) { - cis = *pcis++; - i = 0; - funcid = 0; - standard_cis = TRUE; - do { - if (standard_cis) { - tup = cis[i++]; - if (tup == CISTPL_NULL || tup == CISTPL_END) - tlen = 0; - else - tlen = cis[i++]; - } else { - if (cis[i] == CISTPL_NULL || cis[i] == CISTPL_END) { - tlen = 0; - tup = cis[i]; - } else { - tlen = cis[i]; - tup = CISTPL_BRCM_HNBU; - } - ++i; - } - if ((i + tlen) >= max_cis_size) - break; - - switch (tup) { - case CISTPL_VERS_1: - /* assume the strings are good if the version field checks out */ - if (((cis[i + 1] << 8) + cis[i]) >= 0x0008) { - varbuf_append(&b, vstr_manf, &cis[i + 2]); - varbuf_append(&b, vstr_productname, - &cis[i + 3 + strlen((char *)&cis[i + 2])]); - break; - } - - case CISTPL_MANFID: - varbuf_append(&b, vstr_manfid, (cis[i + 1] << 8) + cis[i]); - varbuf_append(&b, vstr_prodid, (cis[i + 3] << 8) + cis[i + 2]); - break; - - case CISTPL_FUNCID: - funcid = cis[i]; - break; - - case CISTPL_FUNCE: - switch (funcid) { - case CISTPL_FID_SDIO: -#ifdef BCMSDIO - if (cis[i] == 0) { - uint8 spd = cis[i + 3]; - static int lbase[] = { - -1, 10, 12, 13, 15, 20, 25, 30, - 35, 40, 45, 50, 55, 60, 70, 80 - }; - static int mult[] = { - 10, 100, 1000, 10000, - -1, -1, -1, -1 - }; - ASSERT((mult[spd & 0x7] != -1) && - (lbase[(spd >> 3) & 0x0f])); - varbuf_append(&b, vstr_sdmaxblk[0], - (cis[i + 2] << 8) + cis[i + 1]); - varbuf_append(&b, vstr_sdmaxspeed, - (mult[spd & 0x7] * - lbase[(spd >> 3) & 0x0f])); - } else if (cis[i] == 1) { - varbuf_append(&b, vstr_sdmaxblk[cisnum], - (cis[i + 13] << 8) | cis[i + 12]); - } -#endif /* BCMSDIO */ - funcid = 0; - break; - default: - /* set macaddr if HNBU_MACADDR not seen yet */ - if (eabuf[0] == '\0' && cis[i] == LAN_NID && - !(ETHER_ISNULLADDR(&cis[i + 2])) && - !(ETHER_ISMULTI(&cis[i + 2]))) { - ASSERT(cis[i + 1] == ETHER_ADDR_LEN); - bcm_ether_ntoa((struct ether_addr *)&cis[i + 2], - eabuf); - - /* set boardnum if HNBU_BOARDNUM not seen yet */ - if (boardnum == -1) - boardnum = (cis[i + 6] << 8) + cis[i + 7]; - } - break; - } - break; - - case CISTPL_CFTABLE: - varbuf_append(&b, vstr_regwindowsz, (cis[i + 7] << 8) | cis[i + 6]); - break; - - case CISTPL_BRCM_HNBU: - switch (cis[i]) { - case HNBU_SROMREV: - sromrev = cis[i + 1]; - varbuf_append(&b, vstr_sromrev, sromrev); - break; - - case HNBU_XTALFREQ: - varbuf_append(&b, vstr_xtalfreq, - (cis[i + 4] << 24) | - (cis[i + 3] << 16) | - (cis[i + 2] << 8) | - cis[i + 1]); - break; - - case HNBU_CHIPID: - varbuf_append(&b, vstr_vendid, (cis[i + 2] << 8) + - cis[i + 1]); - varbuf_append(&b, vstr_devid, (cis[i + 4] << 8) + - cis[i + 3]); - if (tlen >= 7) { - varbuf_append(&b, vstr_chiprev, - (cis[i + 6] << 8) + cis[i + 5]); - } - if (tlen >= 9) { - varbuf_append(&b, vstr_subvendid, - (cis[i + 8] << 8) + cis[i + 7]); - } - if (tlen >= 11) { - varbuf_append(&b, vstr_subdevid, - (cis[i + 10] << 8) + cis[i + 9]); - /* subdevid doubles for boardtype */ - varbuf_append(&b, vstr_boardtype, - (cis[i + 10] << 8) + cis[i + 9]); - } - break; - - case HNBU_BOARDNUM: - boardnum = (cis[i + 2] << 8) + cis[i + 1]; - break; - - case HNBU_PATCH: { - char vstr_paddr[16]; - char vstr_pdata[16]; - - /* retrieve the patch pairs - * from tlen/6; where 6 is - * sizeof(patch addr(2)) + - * sizeof(patch data(4)). - */ - patch_pair = tlen/6; - - for (j = 0; j < patch_pair; j++) { - snprintf(vstr_paddr, sizeof(vstr_paddr), - rstr_paddr, j); - snprintf(vstr_pdata, sizeof(vstr_pdata), - rstr_pdata, j); - - varbuf_append(&b, vstr_paddr, - (cis[i + (j*6) + 2] << 8) | - cis[i + (j*6) + 1]); - - varbuf_append(&b, vstr_pdata, - (cis[i + (j*6) + 6] << 24) | - (cis[i + (j*6) + 5] << 16) | - (cis[i + (j*6) + 4] << 8) | - cis[i + (j*6) + 3]); - } - break; - } - - case HNBU_BOARDREV: - if (tlen == 2) - varbuf_append(&b, vstr_boardrev, cis[i + 1]); - else - varbuf_append(&b, vstr_boardrev, - (cis[i + 2] << 8) + cis[i + 1]); - break; - - case HNBU_BOARDFLAGS: - w32 = (cis[i + 2] << 8) + cis[i + 1]; - if (tlen >= 5) - w32 |= ((cis[i + 4] << 24) + (cis[i + 3] << 16)); - varbuf_append(&b, vstr_boardflags, w32); - - if (tlen >= 7) { - w32 = (cis[i + 6] << 8) + cis[i + 5]; - if (tlen >= 9) - w32 |= ((cis[i + 8] << 24) + - (cis[i + 7] << 16)); - varbuf_append(&b, vstr_boardflags2, w32); - } - if (tlen >= 11) { - w32 = (cis[i + 10] << 8) + cis[i + 9]; - if (tlen >= 13) - w32 |= ((cis[i + 12] << 24) + - (cis[i + 11] << 16)); - varbuf_append(&b, vstr_boardflags3, w32); - } - if (tlen >= 15) { - w32 = (cis[i + 14] << 8) + cis[i + 13]; - if (tlen >= 17) - w32 |= ((cis[i + 16] << 24) + - (cis[i + 15] << 16)); - varbuf_append(&b, vstr_boardflags4, w32); - } - if (tlen >= 19) { - w32 = (cis[i + 18] << 8) + cis[i + 17]; - if (tlen >= 21) - w32 |= ((cis[i + 20] << 24) + - (cis[i + 19] << 16)); - varbuf_append(&b, vstr_boardflags5, w32); - } - break; - - case HNBU_USBFS: - varbuf_append(&b, vstr_usbfs, cis[i + 1]); - break; - - case HNBU_BOARDTYPE: - varbuf_append(&b, vstr_boardtype, - (cis[i + 2] << 8) + cis[i + 1]); - break; - - case HNBU_HNBUCIS: - /* - * what follows is a nonstandard HNBU CIS - * that lacks CISTPL_BRCM_HNBU tags - * - * skip 0xff (end of standard CIS) - * after this tuple - */ - tlen++; - standard_cis = FALSE; - break; - - case HNBU_USBEPNUM: - varbuf_append(&b, vstr_usbepnum, - (cis[i + 2] << 8) | cis[i + 1]); - break; - - case HNBU_PATCH_AUTOINC: { - char vstr_paddr[16]; - char vstr_pdata[16]; - uint32 addr_inc; - uint8 pcnt; - - addr_inc = (cis[i + 4] << 24) | - (cis[i + 3] << 16) | - (cis[i + 2] << 8) | - (cis[i + 1]); - - pcnt = (tlen - 5)/4; - for (j = 0; j < pcnt; j++) { - snprintf(vstr_paddr, sizeof(vstr_paddr), - rstr_paddr, j + patch_pair); - snprintf(vstr_pdata, sizeof(vstr_pdata), - rstr_pdata, j + patch_pair); - - varbuf_append(&b, vstr_paddr, addr_inc); - varbuf_append(&b, vstr_pdata, - (cis[i + (j*4) + 8] << 24) | - (cis[i + (j*4) + 7] << 16) | - (cis[i + (j*4) + 6] << 8) | - cis[i + (j*4) + 5]); - addr_inc += 4; - } - patch_pair += pcnt; - break; - } - case HNBU_PATCH2: { - char vstr_paddr[16]; - char vstr_pdata[16]; - - /* retrieve the patch pairs - * from tlen/8; where 8 is - * sizeof(patch addr(4)) + - * sizeof(patch data(4)). - */ - patch_pair = tlen/8; - - for (j = 0; j < patch_pair; j++) { - snprintf(vstr_paddr, sizeof(vstr_paddr), - rstr_paddr, j); - snprintf(vstr_pdata, sizeof(vstr_pdata), - rstr_pdata, j); - - varbuf_append(&b, vstr_paddr, - (cis[i + (j*8) + 4] << 24) | - (cis[i + (j*8) + 3] << 16) | - (cis[i + (j*8) + 2] << 8) | - cis[i + (j*8) + 1]); - - varbuf_append(&b, vstr_pdata, - (cis[i + (j*8) + 8] << 24) | - (cis[i + (j*8) + 7] << 16) | - (cis[i + (j*8) + 6] << 8) | - cis[i + (j*8) + 5]); - } - break; - } - case HNBU_PATCH_AUTOINC8: { - char vstr_paddr[16]; - char vstr_pdatah[16]; - char vstr_pdatal[16]; - uint32 addr_inc; - uint8 pcnt; - - addr_inc = (cis[i + 4] << 24) | - (cis[i + 3] << 16) | - (cis[i + 2] << 8) | - (cis[i + 1]); - - pcnt = (tlen - 5)/8; - for (j = 0; j < pcnt; j++) { - snprintf(vstr_paddr, sizeof(vstr_paddr), - rstr_paddr, j + patch_pair); - snprintf(vstr_pdatah, sizeof(vstr_pdatah), - rstr_pdatah, j + patch_pair); - snprintf(vstr_pdatal, sizeof(vstr_pdatal), - rstr_pdatal, j + patch_pair); - - varbuf_append(&b, vstr_paddr, addr_inc); - varbuf_append(&b, vstr_pdatal, - (cis[i + (j*8) + 8] << 24) | - (cis[i + (j*8) + 7] << 16) | - (cis[i + (j*8) + 6] << 8) | - cis[i + (j*8) + 5]); - varbuf_append(&b, vstr_pdatah, - (cis[i + (j*8) + 12] << 24) | - (cis[i + (j*8) + 11] << 16) | - (cis[i + (j*8) + 10] << 8) | - cis[i + (j*8) + 9]); - addr_inc += 8; - } - patch_pair += pcnt; - break; - } - case HNBU_PATCH8: { - char vstr_paddr[16]; - char vstr_pdatah[16]; - char vstr_pdatal[16]; - - /* retrieve the patch pairs - * from tlen/8; where 8 is - * sizeof(patch addr(4)) + - * sizeof(patch data(4)). - */ - patch_pair = tlen/12; - - for (j = 0; j < patch_pair; j++) { - snprintf(vstr_paddr, sizeof(vstr_paddr), - rstr_paddr, j); - snprintf(vstr_pdatah, sizeof(vstr_pdatah), - rstr_pdatah, j); - snprintf(vstr_pdatal, sizeof(vstr_pdatal), - rstr_pdatal, j); - - varbuf_append(&b, vstr_paddr, - (cis[i + (j*12) + 4] << 24) | - (cis[i + (j*12) + 3] << 16) | - (cis[i + (j*12) + 2] << 8) | - cis[i + (j*12) + 1]); - - varbuf_append(&b, vstr_pdatal, - (cis[i + (j*12) + 8] << 24) | - (cis[i + (j*12) + 7] << 16) | - (cis[i + (j*12) + 6] << 8) | - cis[i + (j*12) + 5]); - - varbuf_append(&b, vstr_pdatah, - (cis[i + (j*12) + 12] << 24) | - (cis[i + (j*12) + 11] << 16) | - (cis[i + (j*12) + 10] << 8) | - cis[i + (j*12) + 9]); - } - break; - } - case HNBU_USBFLAGS: - varbuf_append(&b, vstr_usbflags, - (cis[i + 4] << 24) | - (cis[i + 3] << 16) | - (cis[i + 2] << 8) | - cis[i + 1]); - break; -#ifdef BCM_BOOTLOADER - case HNBU_MDIOEX_REGLIST: - case HNBU_MDIO_REGLIST: { - /* Format: addr (8 bits) | val (16 bits) */ - const uint8 msize = 3; - char mdiostr[24]; - const char *mdiodesc; - uint8 *st; - - mdiodesc = (cis[i] == HNBU_MDIO_REGLIST) ? - vstr_mdio : vstr_mdioex; - - ASSERT(((tlen - 1) % msize) == 0); - - st = &cis[i + 1]; /* start of reg list */ - for (j = 0; j < (tlen - 1); j += msize, st += msize) { - snprintf(mdiostr, sizeof(mdiostr), - mdiodesc, st[0]); - varbuf_append(&b, mdiostr, (st[2] << 8) | st[1]); - } - break; - } - case HNBU_BRMIN: - varbuf_append(&b, vstr_brmin, - (cis[i + 4] << 24) | - (cis[i + 3] << 16) | - (cis[i + 2] << 8) | - cis[i + 1]); - break; - - case HNBU_BRMAX: - varbuf_append(&b, vstr_brmax, - (cis[i + 4] << 24) | - (cis[i + 3] << 16) | - (cis[i + 2] << 8) | - cis[i + 1]); - break; -#endif /* BCM_BOOTLOADER */ - - case HNBU_RDLID: - varbuf_append(&b, vstr_rdlid, - (cis[i + 2] << 8) | cis[i + 1]); - break; - - case HNBU_GCI_CCR: { - /* format: - * |0x80| <== brcm - * |len| <== variable, multiple of 5 - * |tup| <== tupletype - * |ccreg_ix0| <== ix of ccreg [1byte] - * |ccreg_val0| <== corr value [4bytes] - * --- - * Multiple registers are possible. for eg: we - * can specify reg_ix3val3 and reg_ix5val5, etc - */ - char vstr_gci_ccreg_entry[16]; - uint8 num_entries = 0; - - /* retrieve the index-value pairs - * from tlen/5; where 5 is - * sizeof(ccreg_ix(1)) + - * sizeof(ccreg_val(4)). - */ - num_entries = tlen/5; - - for (j = 0; j < num_entries; j++) { - snprintf(vstr_gci_ccreg_entry, - sizeof(vstr_gci_ccreg_entry), - rstr_gci_ccreg_entry, - cis[i + (j*5) + 1]); - - varbuf_append(&b, vstr_gci_ccreg_entry, - (cis[i + (j*5) + 5] << 24) | - (cis[i + (j*5) + 4] << 16) | - (cis[i + (j*5) + 3] << 8) | - cis[i + (j*5) + 2]); - } - break; - } - -#ifdef BCM_BOOTLOADER - case HNBU_RDLRNDIS: - varbuf_append(&b, vstr_rdlrndis, cis[i + 1]); - break; - - case HNBU_RDLRWU: - varbuf_append(&b, vstr_rdlrwu, cis[i + 1]); - break; - - case HNBU_RDLSN: - if (tlen >= 5) - varbuf_append(&b, vstr_rdlsn, - (cis[i + 4] << 24) | - (cis[i + 3] << 16) | - (cis[i + 2] << 8) | - cis[i + 1]); - else - varbuf_append(&b, vstr_rdlsn, - (cis[i + 2] << 8) | - cis[i + 1]); - break; - - case HNBU_PMUREGS: { - uint8 offset = 1, mode_addr, mode, addr; - const char *fmt; - - do { - mode_addr = cis[i+offset]; - - mode = (mode_addr & PMUREGS_MODE_MASK) - >> PMUREGS_MODE_SHIFT; - addr = mode_addr & PMUREGS_ADDR_MASK; - - switch (mode) { - case PMU_PLLREG_MODE: - fmt = vstr_pllreg; - break; - case PMU_CCREG_MODE: - fmt = vstr_ccreg; - break; - case PMU_VOLTREG_MODE: - fmt = vstr_regctrl; - break; - case PMU_RES_TIME_MODE: - fmt = vstr_time; - break; - case PMU_RESDEPEND_MODE: - fmt = vstr_depreg; - break; - default: - fmt = NULL; - break; - } - - if (fmt != NULL) { - varbuf_append(&b, fmt, addr, - (cis[i + offset + 4] << 24) | - (cis[i + offset + 3] << 16) | - (cis[i + offset + 2] << 8) | - cis[i + offset + 1]); - } - - offset += PMUREGS_TPL_SIZE; - } while (offset < tlen); - break; - } - - case HNBU_USBREGS: { - uint8 offset = 1, usb_reg; - const char *fmt; - - do { - usb_reg = cis[i+offset]; - - switch (usb_reg) { - case USB_DEV_CTRL_REG: - fmt = vstr_usbdevctrl; - break; - case HSIC_PHY_CTRL1_REG: - fmt = vstr_hsicphyctrl1; - break; - case HSIC_PHY_CTRL2_REG: - fmt = vstr_hsicphyctrl2; - break; - default: - fmt = NULL; - break; - } - - if (fmt != NULL) { - varbuf_append(&b, fmt, - (cis[i + offset + 4] << 24) | - (cis[i + offset + 3] << 16) | - (cis[i + offset + 2] << 8) | - cis[i + offset + 1]); - } - - offset += USBREGS_TPL_SIZE; - } while (offset < tlen); - break; - } - - case HNBU_USBRDY: - /* The first byte of this tuple indicate if the host - * needs to be informed about the readiness of - * the HSIC/USB for enumeration on which GPIO should - * the device assert this event. - */ - varbuf_append(&b, vstr_usbrdy, cis[i + 1]); - - /* The following fields in this OTP are optional. - * The remaining bytes will indicate the delay required - * before and/or after the ch_init(). The delay is defined - * using 16-bits of this the MSB(bit15 of 15:0) will be - * used indicate if the parameter is for Pre or Post delay. - */ - for (j = 2; j < USBRDY_MAXOTP_SIZE && j < tlen; - j += 2) { - uint16 usb_delay; - - usb_delay = cis[i + j] | (cis[i + j + 1] << 8); - - /* The bit-15 of the delay field will indicate the - * type of delay (pre or post). - */ - if (usb_delay & USBRDY_DLY_TYPE) { - varbuf_append(&b, vstr_usbpostdly, - (usb_delay & USBRDY_DLY_MASK)); - } else { - varbuf_append(&b, vstr_usbpredly, - (usb_delay & USBRDY_DLY_MASK)); - } - } - break; - - case HNBU_BLDR_TIMEOUT: - /* The Delay after USBConnect for timeout till dongle - * receives get_descriptor request. - */ - varbuf_append(&b, vstr_bldr_reset_timeout, - (cis[i + 1] | (cis[i + 2] << 8))); - break; - - case HNBU_MUXENAB: - varbuf_append(&b, vstr_muxenab, cis[i + 1]); - break; - case HNBU_PUBKEY: { - /* The public key is in binary format in OTP, - * convert to string format before appending - * buffer string. - * public key(12 bytes) + crc (1byte) = 129 - */ - unsigned char a[300]; - int k; - - for (k = 1, j = 0; k < 129; k++) - j += snprintf((char *)(a + j), - sizeof(a) - j, - "%02x", cis[i + k]); - - a[256] = 0; - - varbuf_append(&b, vstr_pubkey, a); - break; - } -#else - case HNBU_AA: - varbuf_append(&b, vstr_aa2g, cis[i + 1]); - if (tlen >= 3) - varbuf_append(&b, vstr_aa5g, cis[i + 2]); - break; - - case HNBU_AG: - varbuf_append(&b, vstr_ag, 0, cis[i + 1]); - if (tlen >= 3) - varbuf_append(&b, vstr_ag, 1, cis[i + 2]); - if (tlen >= 4) - varbuf_append(&b, vstr_ag, 2, cis[i + 3]); - if (tlen >= 5) - varbuf_append(&b, vstr_ag, 3, cis[i + 4]); - ag_init = TRUE; - break; - - case HNBU_ANT5G: - varbuf_append(&b, vstr_aa5g, cis[i + 1]); - varbuf_append(&b, vstr_ag, 1, cis[i + 2]); - break; - - case HNBU_CC: - ASSERT(sromrev == 1); - varbuf_append(&b, vstr_cc, cis[i + 1]); - break; - - case HNBU_PAPARMS: { - uint8 pa0_lo_offset = 0; - switch (tlen) { - case 2: - ASSERT(sromrev == 1); - varbuf_append(&b, vstr_pa0maxpwr, cis[i + 1]); - break; - /* case 16: - ASSERT(sromrev >= 11); - for (j = 0; j < 3; j++) { - varbuf_append(&b, vstr_pa0b_lo[j], - (cis[i + (j * 2) + 11] << 8) + - cis[i + (j * 2) + 10]); - } - FALLTHROUGH - */ - case 10: - case 16: - ASSERT(sromrev >= 2); - varbuf_append(&b, vstr_opo, cis[i + 9]); - if (tlen >= 13 && pa0_lo_offset == 0) - pa0_lo_offset = 9; - /* FALLTHROUGH */ - case 9: - case 15: - varbuf_append(&b, vstr_pa0maxpwr, cis[i + 8]); - if (tlen >= 13 && pa0_lo_offset == 0) - pa0_lo_offset = 8; - /* FALLTHROUGH */ - BCMDONGLECASE(8) - BCMDONGLECASE(14) - varbuf_append(&b, vstr_pa0itssit, cis[i + 7]); - varbuf_append(&b, vstr_maxp2ga, 0, cis[i + 7]); - if (tlen >= 13 && pa0_lo_offset == 0) - pa0_lo_offset = 7; - /* FALLTHROUGH */ - BCMDONGLECASE(7) - BCMDONGLECASE(13) - for (j = 0; j < 3; j++) { - varbuf_append(&b, vstr_pa0b[j], - (cis[i + (j * 2) + 2] << 8) + - cis[i + (j * 2) + 1]); - } - if (tlen >= 13 && pa0_lo_offset == 0) - pa0_lo_offset = 6; - - if (tlen >= 13 && pa0_lo_offset != 0) { - for (j = 0; j < 3; j++) { - varbuf_append(&b, vstr_pa0b_lo[j], - (cis[pa0_lo_offset+i+(j*2)+2]<<8)+ - cis[pa0_lo_offset+i+(j*2)+1]); - } - } - break; - default: - ASSERT((tlen == 2) || (tlen == 9) || (tlen == 10) || - (tlen == 15) || (tlen == 16)); - break; - } - break; - } - case HNBU_PAPARMS5G: - ASSERT((sromrev == 2) || (sromrev == 3)); - switch (tlen) { - case 23: - varbuf_append(&b, vstr_pa1himaxpwr, cis[i + 22]); - varbuf_append(&b, vstr_pa1lomaxpwr, cis[i + 21]); - varbuf_append(&b, vstr_pa1maxpwr, cis[i + 20]); - /* FALLTHROUGH */ - case 20: - varbuf_append(&b, vstr_pa1itssit, cis[i + 19]); - /* FALLTHROUGH */ - case 19: - for (j = 0; j < 3; j++) { - varbuf_append(&b, vstr_pa1b[j], - (cis[i + (j * 2) + 2] << 8) + - cis[i + (j * 2) + 1]); - } - for (j = 3; j < 6; j++) { - varbuf_append(&b, vstr_pa1lob[j - 3], - (cis[i + (j * 2) + 2] << 8) + - cis[i + (j * 2) + 1]); - } - for (j = 6; j < 9; j++) { - varbuf_append(&b, vstr_pa1hib[j - 6], - (cis[i + (j * 2) + 2] << 8) + - cis[i + (j * 2) + 1]); - } - break; - default: - ASSERT((tlen == 19) || - (tlen == 20) || (tlen == 23)); - break; - } - break; - - case HNBU_OEM: - ASSERT(sromrev == 1); - varbuf_append(&b, vstr_oem, - cis[i + 1], cis[i + 2], - cis[i + 3], cis[i + 4], - cis[i + 5], cis[i + 6], - cis[i + 7], cis[i + 8]); - break; - - case HNBU_CCODE: - ASSERT(sromrev > 1); - if ((cis[i + 1] == 0) || (cis[i + 2] == 0)) - varbuf_append(&b, vstr_noccode); - else - varbuf_append(&b, vstr_ccode, - cis[i + 1], cis[i + 2]); - varbuf_append(&b, vstr_cctl, cis[i + 3]); - break; - - case HNBU_CCKPO: - ASSERT(sromrev > 2); - varbuf_append(&b, vstr_cckpo, - (cis[i + 2] << 8) | cis[i + 1]); - break; - - case HNBU_OFDMPO: - ASSERT(sromrev > 2); - varbuf_append(&b, vstr_ofdmpo, - (cis[i + 4] << 24) | - (cis[i + 3] << 16) | - (cis[i + 2] << 8) | - cis[i + 1]); - break; - - case HNBU_WPS: - varbuf_append(&b, vstr_wpsgpio, cis[i + 1]); - if (tlen >= 3) - varbuf_append(&b, vstr_wpsled, cis[i + 2]); - break; - - case HNBU_RSSISMBXA2G: - ASSERT(sromrev == 3); - varbuf_append(&b, vstr_rssismf2g, cis[i + 1] & 0xf); - varbuf_append(&b, vstr_rssismc2g, (cis[i + 1] >> 4) & 0xf); - varbuf_append(&b, vstr_rssisav2g, cis[i + 2] & 0x7); - varbuf_append(&b, vstr_bxa2g, (cis[i + 2] >> 3) & 0x3); - break; - - case HNBU_RSSISMBXA5G: - ASSERT(sromrev == 3); - varbuf_append(&b, vstr_rssismf5g, cis[i + 1] & 0xf); - varbuf_append(&b, vstr_rssismc5g, (cis[i + 1] >> 4) & 0xf); - varbuf_append(&b, vstr_rssisav5g, cis[i + 2] & 0x7); - varbuf_append(&b, vstr_bxa5g, (cis[i + 2] >> 3) & 0x3); - break; - - case HNBU_TRI2G: - ASSERT(sromrev == 3); - varbuf_append(&b, vstr_tri2g, cis[i + 1]); - break; - - case HNBU_TRI5G: - ASSERT(sromrev == 3); - varbuf_append(&b, vstr_tri5gl, cis[i + 1]); - varbuf_append(&b, vstr_tri5g, cis[i + 2]); - varbuf_append(&b, vstr_tri5gh, cis[i + 3]); - break; - - case HNBU_RXPO2G: - ASSERT(sromrev == 3); - varbuf_append(&b, vstr_rxpo2g, cis[i + 1]); - break; - - case HNBU_RXPO5G: - ASSERT(sromrev == 3); - varbuf_append(&b, vstr_rxpo5g, cis[i + 1]); - break; - - case HNBU_MACADDR: - if (!(ETHER_ISNULLADDR(&cis[i+1])) && - !(ETHER_ISMULTI(&cis[i+1]))) { - bcm_ether_ntoa((struct ether_addr *)&cis[i + 1], - eabuf); - - /* set boardnum if HNBU_BOARDNUM not seen yet */ - if (boardnum == -1) - boardnum = (cis[i + 5] << 8) + cis[i + 6]; - } - break; - - case HNBU_CHAINSWITCH: - varbuf_append(&b, vstr_txchain, cis[i + 1]); - varbuf_append(&b, vstr_rxchain, cis[i + 2]); - varbuf_append(&b, vstr_antswitch, - (cis[i + 4] << 8) + cis[i + 3]); - break; - - case HNBU_ELNA2G: - varbuf_append(&b, vstr_elna2g, cis[i + 1]); - break; - - case HNBU_ELNA5G: - varbuf_append(&b, vstr_elna5g, cis[i + 1]); - break; - - case HNBU_REGREV: - varbuf_append(&b, vstr_regrev, - srom_data2value(&cis[i + 1], tlen - 1)); - break; - - case HNBU_FEM: { - uint16 fem = (cis[i + 2] << 8) + cis[i + 1]; - varbuf_append(&b, vstr_antswctl2g, (fem & - SROM8_FEM_ANTSWLUT_MASK) >> - SROM8_FEM_ANTSWLUT_SHIFT); - varbuf_append(&b, vstr_triso2g, (fem & - SROM8_FEM_TR_ISO_MASK) >> - SROM8_FEM_TR_ISO_SHIFT); - varbuf_append(&b, vstr_pdetrange2g, (fem & - SROM8_FEM_PDET_RANGE_MASK) >> - SROM8_FEM_PDET_RANGE_SHIFT); - varbuf_append(&b, vstr_extpagain2g, (fem & - SROM8_FEM_EXTPA_GAIN_MASK) >> - SROM8_FEM_EXTPA_GAIN_SHIFT); - varbuf_append(&b, vstr_tssipos2g, (fem & - SROM8_FEM_TSSIPOS_MASK) >> - SROM8_FEM_TSSIPOS_SHIFT); - if (tlen < 5) break; - - fem = (cis[i + 4] << 8) + cis[i + 3]; - varbuf_append(&b, vstr_antswctl5g, (fem & - SROM8_FEM_ANTSWLUT_MASK) >> - SROM8_FEM_ANTSWLUT_SHIFT); - varbuf_append(&b, vstr_triso5g, (fem & - SROM8_FEM_TR_ISO_MASK) >> - SROM8_FEM_TR_ISO_SHIFT); - varbuf_append(&b, vstr_pdetrange5g, (fem & - SROM8_FEM_PDET_RANGE_MASK) >> - SROM8_FEM_PDET_RANGE_SHIFT); - varbuf_append(&b, vstr_extpagain5g, (fem & - SROM8_FEM_EXTPA_GAIN_MASK) >> - SROM8_FEM_EXTPA_GAIN_SHIFT); - varbuf_append(&b, vstr_tssipos5g, (fem & - SROM8_FEM_TSSIPOS_MASK) >> - SROM8_FEM_TSSIPOS_SHIFT); - break; - } - - case HNBU_PAPARMS_C0: - varbuf_append(&b, vstr_maxp2ga, 0, cis[i + 1]); - varbuf_append(&b, vstr_itt2ga0, cis[i + 2]); - varbuf_append(&b, vstr_pa, 2, 0, 0, - (cis[i + 4] << 8) + cis[i + 3]); - varbuf_append(&b, vstr_pa, 2, 1, 0, - (cis[i + 6] << 8) + cis[i + 5]); - varbuf_append(&b, vstr_pa, 2, 2, 0, - (cis[i + 8] << 8) + cis[i + 7]); - if (tlen < 31) break; - - varbuf_append(&b, vstr_maxp5ga0, cis[i + 9]); - varbuf_append(&b, vstr_itt5ga0, cis[i + 10]); - varbuf_append(&b, vstr_maxp5gha0, cis[i + 11]); - varbuf_append(&b, vstr_maxp5gla0, cis[i + 12]); - varbuf_append(&b, vstr_pa, 5, 0, 0, - (cis[i + 14] << 8) + cis[i + 13]); - varbuf_append(&b, vstr_pa, 5, 1, 0, - (cis[i + 16] << 8) + cis[i + 15]); - varbuf_append(&b, vstr_pa, 5, 2, 0, - (cis[i + 18] << 8) + cis[i + 17]); - varbuf_append(&b, vstr_pahl, 5, 'l', 0, 0, - (cis[i + 20] << 8) + cis[i + 19]); - varbuf_append(&b, vstr_pahl, 5, 'l', 1, 0, - (cis[i + 22] << 8) + cis[i + 21]); - varbuf_append(&b, vstr_pahl, 5, 'l', 2, 0, - (cis[i + 24] << 8) + cis[i + 23]); - varbuf_append(&b, vstr_pahl, 5, 'h', 0, 0, - (cis[i + 26] << 8) + cis[i + 25]); - varbuf_append(&b, vstr_pahl, 5, 'h', 1, 0, - (cis[i + 28] << 8) + cis[i + 27]); - varbuf_append(&b, vstr_pahl, 5, 'h', 2, 0, - (cis[i + 30] << 8) + cis[i + 29]); - break; - - case HNBU_PAPARMS_C1: - varbuf_append(&b, vstr_maxp2ga, 1, cis[i + 1]); - varbuf_append(&b, vstr_itt2ga1, cis[i + 2]); - varbuf_append(&b, vstr_pa, 2, 0, 1, - (cis[i + 4] << 8) + cis[i + 3]); - varbuf_append(&b, vstr_pa, 2, 1, 1, - (cis[i + 6] << 8) + cis[i + 5]); - varbuf_append(&b, vstr_pa, 2, 2, 1, - (cis[i + 8] << 8) + cis[i + 7]); - if (tlen < 31) break; - - varbuf_append(&b, vstr_maxp5ga1, cis[i + 9]); - varbuf_append(&b, vstr_itt5ga1, cis[i + 10]); - varbuf_append(&b, vstr_maxp5gha1, cis[i + 11]); - varbuf_append(&b, vstr_maxp5gla1, cis[i + 12]); - varbuf_append(&b, vstr_pa, 5, 0, 1, - (cis[i + 14] << 8) + cis[i + 13]); - varbuf_append(&b, vstr_pa, 5, 1, 1, - (cis[i + 16] << 8) + cis[i + 15]); - varbuf_append(&b, vstr_pa, 5, 2, 1, - (cis[i + 18] << 8) + cis[i + 17]); - varbuf_append(&b, vstr_pahl, 5, 'l', 0, 1, - (cis[i + 20] << 8) + cis[i + 19]); - varbuf_append(&b, vstr_pahl, 5, 'l', 1, 1, - (cis[i + 22] << 8) + cis[i + 21]); - varbuf_append(&b, vstr_pahl, 5, 'l', 2, 1, - (cis[i + 24] << 8) + cis[i + 23]); - varbuf_append(&b, vstr_pahl, 5, 'h', 0, 1, - (cis[i + 26] << 8) + cis[i + 25]); - varbuf_append(&b, vstr_pahl, 5, 'h', 1, 1, - (cis[i + 28] << 8) + cis[i + 27]); - varbuf_append(&b, vstr_pahl, 5, 'h', 2, 1, - (cis[i + 30] << 8) + cis[i + 29]); - break; - - case HNBU_PO_CCKOFDM: - varbuf_append(&b, vstr_cck2gpo, - (cis[i + 2] << 8) + cis[i + 1]); - varbuf_append(&b, vstr_ofdm2gpo, - (cis[i + 6] << 24) + (cis[i + 5] << 16) + - (cis[i + 4] << 8) + cis[i + 3]); - if (tlen < 19) break; - - varbuf_append(&b, vstr_ofdm5gpo, - (cis[i + 10] << 24) + (cis[i + 9] << 16) + - (cis[i + 8] << 8) + cis[i + 7]); - varbuf_append(&b, vstr_ofdm5glpo, - (cis[i + 14] << 24) + (cis[i + 13] << 16) + - (cis[i + 12] << 8) + cis[i + 11]); - varbuf_append(&b, vstr_ofdm5ghpo, - (cis[i + 18] << 24) + (cis[i + 17] << 16) + - (cis[i + 16] << 8) + cis[i + 15]); - break; - - case HNBU_PO_MCS2G: - for (j = 0; j <= (tlen/2); j++) { - varbuf_append(&b, vstr_mcspo, 2, j, - (cis[i + 2 + 2*j] << 8) + cis[i + 1 + 2*j]); - } - break; - - case HNBU_PO_MCS5GM: - for (j = 0; j <= (tlen/2); j++) { - varbuf_append(&b, vstr_mcspo, 5, j, - (cis[i + 2 + 2*j] << 8) + cis[i + 1 + 2*j]); - } - break; - - case HNBU_PO_MCS5GLH: - for (j = 0; j <= (tlen/4); j++) { - varbuf_append(&b, vstr_mcspohl, 5, 'l', j, - (cis[i + 2 + 2*j] << 8) + cis[i + 1 + 2*j]); - } - - for (j = 0; j <= (tlen/4); j++) { - varbuf_append(&b, vstr_mcspohl, 5, 'h', j, - (cis[i + ((tlen/2)+2) + 2*j] << 8) + - cis[i + ((tlen/2)+1) + 2*j]); - } - - break; - - case HNBU_PO_CDD: - varbuf_append(&b, vstr_cddpo, - (cis[i + 2] << 8) + cis[i + 1]); - break; - - case HNBU_PO_STBC: - varbuf_append(&b, vstr_stbcpo, - (cis[i + 2] << 8) + cis[i + 1]); - break; - - case HNBU_PO_40M: - varbuf_append(&b, vstr_bw40po, - (cis[i + 2] << 8) + cis[i + 1]); - break; - - case HNBU_PO_40MDUP: - varbuf_append(&b, vstr_bwduppo, - (cis[i + 2] << 8) + cis[i + 1]); - break; - - case HNBU_OFDMPO5G: - varbuf_append(&b, vstr_ofdm5gpo, - (cis[i + 4] << 24) + (cis[i + 3] << 16) + - (cis[i + 2] << 8) + cis[i + 1]); - varbuf_append(&b, vstr_ofdm5glpo, - (cis[i + 8] << 24) + (cis[i + 7] << 16) + - (cis[i + 6] << 8) + cis[i + 5]); - varbuf_append(&b, vstr_ofdm5ghpo, - (cis[i + 12] << 24) + (cis[i + 11] << 16) + - (cis[i + 10] << 8) + cis[i + 9]); - break; - /* Power per rate for SROM V9 */ - case HNBU_CCKBW202GPO: - varbuf_append(&b, vstr_cckbw202gpo[0], - ((cis[i + 2] << 8) + cis[i + 1])); - if (tlen > 4) - varbuf_append(&b, vstr_cckbw202gpo[1], - ((cis[i + 4] << 8) + cis[i + 3])); - if (tlen > 6) - varbuf_append(&b, vstr_cckbw202gpo[2], - ((cis[i + 6] << 8) + cis[i + 5])); - break; - - case HNBU_LEGOFDMBW202GPO: - varbuf_append(&b, vstr_legofdmbw202gpo[0], - ((cis[i + 4] << 24) + (cis[i + 3] << 16) + - (cis[i + 2] << 8) + cis[i + 1])); - if (tlen > 6) { - varbuf_append(&b, vstr_legofdmbw202gpo[1], - ((cis[i + 8] << 24) + (cis[i + 7] << 16) + - (cis[i + 6] << 8) + cis[i + 5])); - } - break; - - case HNBU_LEGOFDMBW205GPO: - for (j = 0; j < 6; j++) { - if (tlen < (2 + 4 * j)) - break; - varbuf_append(&b, vstr_legofdmbw205gpo[j], - ((cis[4 * j + i + 4] << 24) - + (cis[4 * j + i + 3] << 16) - + (cis[4 * j + i + 2] << 8) - + cis[4 * j + i + 1])); - } - break; - - case HNBU_MCS2GPO: - for (j = 0; j < 4; j++) { - if (tlen < (2 + 4 * j)) - break; - varbuf_append(&b, vstr_mcs2gpo[j], - ((cis[4 * j + i + 4] << 24) - + (cis[4 * j + i + 3] << 16) - + (cis[4 * j + i + 2] << 8) - + cis[4 * j + i + 1])); - } - break; - - case HNBU_MCS5GLPO: - for (j = 0; j < 3; j++) { - if (tlen < (2 + 4 * j)) - break; - varbuf_append(&b, vstr_mcs5glpo[j], - ((cis[4 * j + i + 4] << 24) - + (cis[4 * j + i + 3] << 16) - + (cis[4 * j + i + 2] << 8) - + cis[4 * j + i + 1])); - } - break; - - case HNBU_MCS5GMPO: - for (j = 0; j < 3; j++) { - if (tlen < (2 + 4 * j)) - break; - varbuf_append(&b, vstr_mcs5gmpo[j], - ((cis[4 * j + i + 4] << 24) - + (cis[4 * j + i + 3] << 16) - + (cis[4 * j + i + 2] << 8) - + cis[4 * j + i + 1])); - } - break; - - case HNBU_MCS5GHPO: - for (j = 0; j < 3; j++) { - if (tlen < (2 + 4 * j)) - break; - varbuf_append(&b, vstr_mcs5ghpo[j], - ((cis[4 * j + i + 4] << 24) - + (cis[4 * j + i + 3] << 16) - + (cis[4 * j + i + 2] << 8) - + cis[4 * j + i + 1])); - } - break; - - case HNBU_MCS32PO: - varbuf_append(&b, vstr_mcs32po, - (cis[i + 2] << 8) + cis[i + 1]); - break; - - case HNBU_LEG40DUPPO: - varbuf_append(&b, vstr_legofdm40duppo, - (cis[i + 2] << 8) + cis[i + 1]); - break; - - case HNBU_CUSTOM1: - varbuf_append(&b, vstr_custom, 1, ((cis[i + 4] << 24) + - (cis[i + 3] << 16) + (cis[i + 2] << 8) + - cis[i + 1])); - break; - -#if defined(BCMSDIO) || defined(BCMCCISSR3) - case HNBU_SROM3SWRGN: - if (tlen >= 73) { - uint16 srom[35]; - uint8 srev = cis[i + 1 + 70]; - ASSERT(srev == 3); - /* make tuple value 16-bit aligned and parse it */ - bcopy(&cis[i + 1], srom, sizeof(srom)); - _initvars_srom_pci(srev, srom, SROM3_SWRGN_OFF, &b); - /* 2.4G antenna gain is included in SROM */ - ag_init = TRUE; - /* Ethernet MAC address is included in SROM */ - eabuf[0] = 0; - /* why boardnum is not -1? */ - boardnum = -1; - } - /* create extra variables */ - if (tlen >= 75) - varbuf_append(&b, vstr_vendid, - (cis[i + 1 + 73] << 8) + - cis[i + 1 + 72]); - if (tlen >= 77) - varbuf_append(&b, vstr_devid, - (cis[i + 1 + 75] << 8) + - cis[i + 1 + 74]); - if (tlen >= 79) - varbuf_append(&b, vstr_xtalfreq, - (cis[i + 1 + 77] << 8) + - cis[i + 1 + 76]); - break; -#endif /* BCMSDIO || BCMCCISSR3 */ - - case HNBU_CCKFILTTYPE: - varbuf_append(&b, vstr_cckdigfilttype, - (cis[i + 1])); - break; - - case HNBU_TEMPTHRESH: - varbuf_append(&b, vstr_tempthresh, - (cis[i + 1])); - /* period in msb nibble */ - varbuf_append(&b, vstr_temps_period, - (cis[i + 2] & SROM11_TEMPS_PERIOD_MASK) >> - SROM11_TEMPS_PERIOD_SHIFT); - /* hysterisis in lsb nibble */ - varbuf_append(&b, vstr_temps_hysteresis, - (cis[i + 2] & SROM11_TEMPS_HYSTERESIS_MASK) >> - SROM11_TEMPS_HYSTERESIS_SHIFT); - if (tlen >= 4) { - varbuf_append(&b, vstr_tempoffset, - (cis[i + 3])); - varbuf_append(&b, vstr_tempsense_slope, - (cis[i + 4])); - varbuf_append(&b, vstr_temp_corrx, - (cis[i + 5] & SROM11_TEMPCORRX_MASK) >> - SROM11_TEMPCORRX_SHIFT); - varbuf_append(&b, vstr_tempsense_option, - (cis[i + 5] & SROM11_TEMPSENSE_OPTION_MASK) >> - SROM11_TEMPSENSE_OPTION_SHIFT); - varbuf_append(&b, vstr_phycal_tempdelta, - (cis[i + 6])); - } - break; - - case HNBU_FEM_CFG: { - /* fem_cfg1 */ - uint16 fem_cfg = (cis[i + 2] << 8) + cis[i + 1]; - varbuf_append(&b, vstr_femctrl, - (fem_cfg & SROM11_FEMCTRL_MASK) >> - SROM11_FEMCTRL_SHIFT); - varbuf_append(&b, vstr_papdcap, 2, - (fem_cfg & SROM11_PAPDCAP_MASK) >> - SROM11_PAPDCAP_SHIFT); - varbuf_append(&b, vstr_tworangetssi, 2, - (fem_cfg & SROM11_TWORANGETSSI_MASK) >> - SROM11_TWORANGETSSI_SHIFT); - varbuf_append(&b, vstr_pdgaing, 2, - (fem_cfg & SROM11_PDGAIN_MASK) >> - SROM11_PDGAIN_SHIFT); - varbuf_append(&b, vstr_epagaing, 2, - (fem_cfg & SROM11_EPAGAIN_MASK) >> - SROM11_EPAGAIN_SHIFT); - varbuf_append(&b, vstr_tssiposslopeg, 2, - (fem_cfg & SROM11_TSSIPOSSLOPE_MASK) >> - SROM11_TSSIPOSSLOPE_SHIFT); - /* fem_cfg2 */ - fem_cfg = (cis[i + 4] << 8) + cis[i + 3]; - varbuf_append(&b, vstr_gainctrlsph, - (fem_cfg & SROM11_GAINCTRLSPH_MASK) >> - SROM11_GAINCTRLSPH_SHIFT); - varbuf_append(&b, vstr_papdcap, 5, - (fem_cfg & SROM11_PAPDCAP_MASK) >> - SROM11_PAPDCAP_SHIFT); - varbuf_append(&b, vstr_tworangetssi, 5, - (fem_cfg & SROM11_TWORANGETSSI_MASK) >> - SROM11_TWORANGETSSI_SHIFT); - varbuf_append(&b, vstr_pdgaing, 5, - (fem_cfg & SROM11_PDGAIN_MASK) >> - SROM11_PDGAIN_SHIFT); - varbuf_append(&b, vstr_epagaing, 5, - (fem_cfg & SROM11_EPAGAIN_MASK) >> - SROM11_EPAGAIN_SHIFT); - varbuf_append(&b, vstr_tssiposslopeg, 5, - (fem_cfg & SROM11_TSSIPOSSLOPE_MASK) >> - SROM11_TSSIPOSSLOPE_SHIFT); - break; - } - - case HNBU_ACPA_C0: { - const int a = 0; - -#ifndef OTP_SKIP_MAXP_PAPARAMS - varbuf_append(&b, vstr_subband5gver, - (cis[i + 2] << 8) + cis[i + 1]); - /* maxp2g */ - /* Decoupling this touple to program from NVRAM */ - varbuf_append(&b, vstr_maxp2ga, a, - (cis[i + 4] << 8) + cis[i + 3]); -#endif /* OTP_SKIP_MAXP_PAPARAMS */ - /* pa2g */ - varbuf_append(&b, vstr_pa2ga, a, - (cis[i + 6] << 8) + cis[i + 5], - (cis[i + 8] << 8) + cis[i + 7], - (cis[i + 10] << 8) + cis[i + 9]); -#ifndef OTP_SKIP_MAXP_PAPARAMS - /* maxp5g */ - varbuf_append(&b, vstr_maxp5ga, a, - cis[i + 11], - cis[i + 12], - cis[i + 13], - cis[i + 14]); -#endif /* OTP_SKIP_MAXP_PAPARAMS */ - /* pa5g */ - varbuf_append(&b, vstr_pa5ga, a, - (cis[i + 16] << 8) + cis[i + 15], - (cis[i + 18] << 8) + cis[i + 17], - (cis[i + 20] << 8) + cis[i + 19], - (cis[i + 22] << 8) + cis[i + 21], - (cis[i + 24] << 8) + cis[i + 23], - (cis[i + 26] << 8) + cis[i + 25], - (cis[i + 28] << 8) + cis[i + 27], - (cis[i + 30] << 8) + cis[i + 29], - (cis[i + 32] << 8) + cis[i + 31], - (cis[i + 34] << 8) + cis[i + 33], - (cis[i + 36] << 8) + cis[i + 35], - (cis[i + 38] << 8) + cis[i + 37]); - break; - } - - case HNBU_ACPA_C1: { - const int a = 1; - -#ifndef OTP_SKIP_MAXP_PAPARAMS - /* maxp2g */ - /* Decoupling this touple to program from NVRAM */ - varbuf_append(&b, vstr_maxp2ga, a, - (cis[i + 2] << 8) + cis[i + 1]); -#endif /* OTP_SKIP_MAXP_PAPARAMS */ - /* pa2g */ - varbuf_append(&b, vstr_pa2ga, a, - (cis[i + 4] << 8) + cis[i + 3], - (cis[i + 6] << 8) + cis[i + 5], - (cis[i + 8] << 8) + cis[i + 7]); -#ifndef OTP_SKIP_MAXP_PAPARAMS - /* maxp5g */ - varbuf_append(&b, vstr_maxp5ga, a, - cis[i + 9], - cis[i + 10], - cis[i + 11], - cis[i + 12]); -#endif /* OTP_SKIP_MAXP_PAPARAMS */ - /* pa5g */ - varbuf_append(&b, vstr_pa5ga, a, - (cis[i + 14] << 8) + cis[i + 13], - (cis[i + 16] << 8) + cis[i + 15], - (cis[i + 18] << 8) + cis[i + 17], - (cis[i + 20] << 8) + cis[i + 19], - (cis[i + 22] << 8) + cis[i + 21], - (cis[i + 24] << 8) + cis[i + 23], - (cis[i + 26] << 8) + cis[i + 25], - (cis[i + 28] << 8) + cis[i + 27], - (cis[i + 30] << 8) + cis[i + 29], - (cis[i + 32] << 8) + cis[i + 31], - (cis[i + 34] << 8) + cis[i + 33], - (cis[i + 36] << 8) + cis[i + 35]); - break; - } - - case HNBU_ACPA_C2: { - const int a = 2; - -#ifndef OTP_SKIP_MAXP_PAPARAMS - /* maxp2g */ - /* Decoupling this touple to program from NVRAM */ - varbuf_append(&b, vstr_maxp2ga, a, - (cis[i + 2] << 8) + cis[i + 1]); -#endif /* OTP_SKIP_MAXP_PAPARAMS */ - /* pa2g */ - varbuf_append(&b, vstr_pa2ga, a, - (cis[i + 4] << 8) + cis[i + 3], - (cis[i + 6] << 8) + cis[i + 5], - (cis[i + 8] << 8) + cis[i + 7]); -#ifndef OTP_SKIP_MAXP_PAPARAMS - /* maxp5g */ - varbuf_append(&b, vstr_maxp5ga, a, - cis[i + 9], - cis[i + 10], - cis[i + 11], - cis[i + 12]); -#endif /* OTP_SKIP_MAXP_PAPARAMS */ - /* pa5g */ - varbuf_append(&b, vstr_pa5ga, a, - (cis[i + 14] << 8) + cis[i + 13], - (cis[i + 16] << 8) + cis[i + 15], - (cis[i + 18] << 8) + cis[i + 17], - (cis[i + 20] << 8) + cis[i + 19], - (cis[i + 22] << 8) + cis[i + 21], - (cis[i + 24] << 8) + cis[i + 23], - (cis[i + 26] << 8) + cis[i + 25], - (cis[i + 28] << 8) + cis[i + 27], - (cis[i + 30] << 8) + cis[i + 29], - (cis[i + 32] << 8) + cis[i + 31], - (cis[i + 34] << 8) + cis[i + 33], - (cis[i + 36] << 8) + cis[i + 35]); - break; - } - - case HNBU_MEAS_PWR: - varbuf_append(&b, vstr_measpower, cis[i + 1]); - varbuf_append(&b, vstr_measpowerX, 1, (cis[i + 2])); - varbuf_append(&b, vstr_measpowerX, 2, (cis[i + 3])); - varbuf_append(&b, vstr_rawtempsense, - ((cis[i + 5] & 0x1) << 8) + cis[i + 4]); - break; - - case HNBU_PDOFF: - varbuf_append(&b, vstr_pdoffsetma, 40, 0, - (cis[i + 2] << 8) + cis[i + 1]); - varbuf_append(&b, vstr_pdoffsetma, 40, 1, - (cis[i + 4] << 8) + cis[i + 3]); - varbuf_append(&b, vstr_pdoffsetma, 40, 2, - (cis[i + 6] << 8) + cis[i + 5]); - varbuf_append(&b, vstr_pdoffsetma, 80, 0, - (cis[i + 8] << 8) + cis[i + 7]); - varbuf_append(&b, vstr_pdoffsetma, 80, 1, - (cis[i + 10] << 8) + cis[i + 9]); - varbuf_append(&b, vstr_pdoffsetma, 80, 2, - (cis[i + 12] << 8) + cis[i + 11]); - break; - - case HNBU_ACPPR_2GPO: - varbuf_append(&b, vstr_dot11agofdmhrbw202gpo, - (cis[i + 2] << 8) + cis[i + 1]); - varbuf_append(&b, vstr_ofdmlrbw202gpo, - (cis[i + 4] << 8) + cis[i + 3]); - - if (tlen < 13) break; - varbuf_append(&b, vstr_sb20in40dot11agofdm2gpo, - (cis[i + 6] << 8) + cis[i + 5]); - varbuf_append(&b, vstr_sb20in80dot11agofdm2gpo, - (cis[i + 8] << 8) + cis[i + 7]); - varbuf_append(&b, vstr_sb20in40ofdmlrbw202gpo, - (cis[i + 10] << 8) + cis[i + 9]); - varbuf_append(&b, vstr_sb20in80ofdmlrbw202gpo, - (cis[i + 12] << 8) + cis[i + 11]); - break; - - case HNBU_ACPPR_5GPO: - varbuf_append(&b, vstr_mcsbw805gpo, 'l', - (cis[i + 4] << 24) + (cis[i + 3] << 16) + - (cis[i + 2] << 8) + cis[i + 1]); - varbuf_append(&b, vstr_mcsbw1605gpo, 'l', - (cis[i + 8] << 24) + (cis[i + 7] << 16) + - (cis[i + 6] << 8) + cis[i + 5]); - varbuf_append(&b, vstr_mcsbw805gpo, 'm', - (cis[i + 12] << 24) + (cis[i + 11] << 16) + - (cis[i + 10] << 8) + cis[i + 9]); - varbuf_append(&b, vstr_mcsbw1605gpo, 'm', - (cis[i + 16] << 24) + (cis[i + 15] << 16) + - (cis[i + 14] << 8) + cis[i + 13]); - varbuf_append(&b, vstr_mcsbw805gpo, 'h', - (cis[i + 20] << 24) + (cis[i + 19] << 16) + - (cis[i + 18] << 8) + cis[i + 17]); - varbuf_append(&b, vstr_mcsbw1605gpo, 'h', - (cis[i + 24] << 24) + (cis[i + 23] << 16) + - (cis[i + 22] << 8) + cis[i + 21]); - varbuf_append(&b, vstr_mcslr5gpo, 'l', - (cis[i + 26] << 8) + cis[i + 25]); - varbuf_append(&b, vstr_mcslr5gpo, 'm', - (cis[i + 28] << 8) + cis[i + 27]); - varbuf_append(&b, vstr_mcslr5gpo, 'h', - (cis[i + 30] << 8) + cis[i + 29]); - - if (tlen < 51) break; - varbuf_append(&b, vstr_mcsbw80p805gpo, 'l', - (cis[i + 34] << 24) + (cis[i + 33] << 16) + - (cis[i + 32] << 8) + cis[i + 31]); - varbuf_append(&b, vstr_mcsbw80p805gpo, 'm', - (cis[i + 38] << 24) + (cis[i + 37] << 16) + - (cis[i + 36] << 8) + cis[i + 35]); - varbuf_append(&b, vstr_mcsbw80p805gpo, 'h', - (cis[i + 42] << 24) + (cis[i + 41] << 16) + - (cis[i + 40] << 8) + cis[i + 39]); - varbuf_append(&b, vstr_mcsbw80p805g1po, 'x', - (cis[i + 46] << 24) + (cis[i + 45] << 16) + - (cis[i + 44] << 8) + cis[i + 43]); - varbuf_append(&b, vstr_mcslr5g1po, 'x', - (cis[i + 48] << 8) + cis[i + 47]); - varbuf_append(&b, vstr_mcslr5g80p80po, - (cis[i + 50] << 8) + cis[i + 49]); - varbuf_append(&b, vstr_mcsbw805g1po, 'x', - (cis[i + 54] << 24) + (cis[i + 53] << 16) + - (cis[i + 52] << 8) + cis[i + 51]); - varbuf_append(&b, vstr_mcsbw1605g1po, 'x', - (cis[i + 58] << 24) + (cis[i + 57] << 16) + - (cis[i + 56] << 8) + cis[i + 55]); - - break; - - case HNBU_MCS5Gx1PO: - varbuf_append(&b, vstr_mcsbw205g1po, 'x', - (cis[i + 4] << 24) + (cis[i + 3] << 16) + - (cis[i + 2] << 8) + cis[i + 1]); - varbuf_append(&b, vstr_mcsbw405g1po, 'x', - (cis[i + 8] << 24) + (cis[i + 7] << 16) + - (cis[i + 6] << 8) + cis[i + 5]); - break; - - case HNBU_ACPPR_SBPO: - varbuf_append(&b, vstr_sb20in40rpo, 'h', - (cis[i + 2] << 8) + cis[i + 1]); - varbuf_append(&b, vstr_sb20in80and160r5gpo, 'h', 'l', - (cis[i + 4] << 8) + cis[i + 3]); - varbuf_append(&b, vstr_sb40and80r5gpo, 'h', 'l', - (cis[i + 6] << 8) + cis[i + 5]); - varbuf_append(&b, vstr_sb20in80and160r5gpo, 'h', 'm', - (cis[i + 8] << 8) + cis[i + 7]); - varbuf_append(&b, vstr_sb40and80r5gpo, 'h', 'm', - (cis[i + 10] << 8) + cis[i + 9]); - varbuf_append(&b, vstr_sb20in80and160r5gpo, 'h', 'h', - (cis[i + 12] << 8) + cis[i + 11]); - varbuf_append(&b, vstr_sb40and80r5gpo, 'h', 'h', - (cis[i + 14] << 8) + cis[i + 13]); - varbuf_append(&b, vstr_sb20in40rpo, 'l', - (cis[i + 16] << 8) + cis[i + 15]); - varbuf_append(&b, vstr_sb20in80and160r5gpo, 'l', 'l', - (cis[i + 18] << 8) + cis[i + 17]); - varbuf_append(&b, vstr_sb40and80r5gpo, 'l', 'l', - (cis[i + 20] << 8) + cis[i + 19]); - varbuf_append(&b, vstr_sb20in80and160r5gpo, 'l', 'm', - (cis[i + 22] << 8) + cis[i + 21]); - varbuf_append(&b, vstr_sb40and80r5gpo, 'l', 'm', - (cis[i + 24] << 8) + cis[i + 23]); - varbuf_append(&b, vstr_sb20in80and160r5gpo, 'l', 'h', - (cis[i + 26] << 8) + cis[i + 25]); - varbuf_append(&b, vstr_sb40and80r5gpo, 'l', 'h', - (cis[i + 28] << 8) + cis[i + 27]); - varbuf_append(&b, vstr_dot11agduprpo, 'h', - (cis[i + 32] << 24) + (cis[i + 31] << 16) + - (cis[i + 30] << 8) + cis[i + 29]); - varbuf_append(&b, vstr_dot11agduprpo, 'l', - (cis[i + 36] << 24) + (cis[i + 35] << 16) + - (cis[i + 34] << 8) + cis[i + 33]); - - if (tlen < 49) break; - varbuf_append(&b, vstr_sb20in40and80rpo, 'h', - (cis[i + 38] << 8) + cis[i + 37]); - varbuf_append(&b, vstr_sb20in40and80rpo, 'l', - (cis[i + 40] << 8) + cis[i + 39]); - varbuf_append(&b, vstr_sb20in80and160r5g1po, 'h', 'x', - (cis[i + 42] << 8) + cis[i + 41]); - varbuf_append(&b, vstr_sb20in80and160r5g1po, 'l', 'x', - (cis[i + 44] << 8) + cis[i + 43]); - varbuf_append(&b, vstr_sb40and80r5g1po, 'h', 'x', - (cis[i + 46] << 8) + cis[i + 45]); - varbuf_append(&b, vstr_sb40and80r5g1po, 'l', 'x', - (cis[i + 48] << 8) + cis[i + 47]); - break; - - case HNBU_ACPPR_SB8080_PO: - varbuf_append(&b, vstr_sb2040and80in80p80r5gpo, 'h', 'l', - (cis[i + 2] << 8) + cis[i + 1]); - varbuf_append(&b, vstr_sb2040and80in80p80r5gpo, 'l', 'l', - (cis[i + 4] << 8) + cis[i + 3]); - varbuf_append(&b, vstr_sb2040and80in80p80r5gpo, 'h', 'm', - (cis[i + 6] << 8) + cis[i + 5]); - varbuf_append(&b, vstr_sb2040and80in80p80r5gpo, 'l', 'm', - (cis[i + 8] << 8) + cis[i + 7]); - varbuf_append(&b, vstr_sb2040and80in80p80r5gpo, 'h', 'h', - (cis[i + 10] << 8) + cis[i + 9]); - varbuf_append(&b, vstr_sb2040and80in80p80r5gpo, 'l', 'h', - (cis[i + 12] << 8) + cis[i + 11]); - varbuf_append(&b, vstr_sb2040and80in80p80r5g1po, 'h', 'x', - (cis[i + 14] << 8) + cis[i + 13]); - varbuf_append(&b, vstr_sb2040and80in80p80r5g1po, 'l', 'x', - (cis[i + 16] << 8) + cis[i + 15]); - varbuf_append(&b, vstr_sb20in80p80r5gpo, 'h', - (cis[i + 18] << 8) + cis[i + 17]); - varbuf_append(&b, vstr_sb20in80p80r5gpo, 'l', - (cis[i + 20] << 8) + cis[i + 19]); - varbuf_append(&b, vstr_dot11agduppo, - (cis[i + 22] << 8) + cis[i + 21]); - break; - - case HNBU_NOISELVL: - /* noiselvl2g */ - varbuf_append(&b, vstr_noiselvl2ga, 0, - (cis[i + 1] & 0x1f)); - varbuf_append(&b, vstr_noiselvl2ga, 1, - (cis[i + 2] & 0x1f)); - varbuf_append(&b, vstr_noiselvl2ga, 2, - (cis[i + 3] & 0x1f)); - /* noiselvl5g */ - varbuf_append(&b, vstr_noiselvl5ga, 0, - (cis[i + 4] & 0x1f), - (cis[i + 5] & 0x1f), - (cis[i + 6] & 0x1f), - (cis[i + 7] & 0x1f)); - varbuf_append(&b, vstr_noiselvl5ga, 1, - (cis[i + 8] & 0x1f), - (cis[i + 9] & 0x1f), - (cis[i + 10] & 0x1f), - (cis[i + 11] & 0x1f)); - varbuf_append(&b, vstr_noiselvl5ga, 2, - (cis[i + 12] & 0x1f), - (cis[i + 13] & 0x1f), - (cis[i + 14] & 0x1f), - (cis[i + 15] & 0x1f)); - break; - - case HNBU_RXGAIN_ERR: - varbuf_append(&b, vstr_rxgainerr2ga, 0, - (cis[i + 1] & 0x3f)); - varbuf_append(&b, vstr_rxgainerr2ga, 1, - (cis[i + 2] & 0x1f)); - varbuf_append(&b, vstr_rxgainerr2ga, 2, - (cis[i + 3] & 0x1f)); - varbuf_append(&b, vstr_rxgainerr5ga, 0, - (cis[i + 4] & 0x3f), - (cis[i + 5] & 0x3f), - (cis[i + 6] & 0x3f), - (cis[i + 7] & 0x3f)); - varbuf_append(&b, vstr_rxgainerr5ga, 1, - (cis[i + 8] & 0x1f), - (cis[i + 9] & 0x1f), - (cis[i + 10] & 0x1f), - (cis[i + 11] & 0x1f)); - varbuf_append(&b, vstr_rxgainerr5ga, 2, - (cis[i + 12] & 0x1f), - (cis[i + 13] & 0x1f), - (cis[i + 14] & 0x1f), - (cis[i + 15] & 0x1f)); - break; - - case HNBU_AGBGA: - varbuf_append(&b, vstr_agbg, 0, cis[i + 1]); - varbuf_append(&b, vstr_agbg, 1, cis[i + 2]); - varbuf_append(&b, vstr_agbg, 2, cis[i + 3]); - varbuf_append(&b, vstr_aga, 0, cis[i + 4]); - varbuf_append(&b, vstr_aga, 1, cis[i + 5]); - varbuf_append(&b, vstr_aga, 2, cis[i + 6]); - break; - - case HNBU_ACRXGAINS_C0: { - int a = 0; - - /* rxgains */ - uint16 rxgains = (cis[i + 2] << 8) + cis[i + 1]; - varbuf_append(&b, vstr_rxgainsgtrelnabypa, 5, a, - (rxgains & SROM11_RXGAINS5GTRELNABYPA_MASK) >> - SROM11_RXGAINS5GTRELNABYPA_SHIFT); - varbuf_append(&b, vstr_rxgainsgtrisoa, 5, a, - (rxgains & SROM11_RXGAINS5GTRISOA_MASK) >> - SROM11_RXGAINS5GTRISOA_SHIFT); - varbuf_append(&b, vstr_rxgainsgelnagaina, 5, a, - (rxgains & SROM11_RXGAINS5GELNAGAINA_MASK) >> - SROM11_RXGAINS5GELNAGAINA_SHIFT); - varbuf_append(&b, vstr_rxgainsgtrelnabypa, 2, a, - (rxgains & SROM11_RXGAINS2GTRELNABYPA_MASK) >> - SROM11_RXGAINS2GTRELNABYPA_SHIFT); - varbuf_append(&b, vstr_rxgainsgtrisoa, 2, a, - (rxgains & SROM11_RXGAINS2GTRISOA_MASK) >> - SROM11_RXGAINS2GTRISOA_SHIFT); - varbuf_append(&b, vstr_rxgainsgelnagaina, 2, a, - (rxgains & SROM11_RXGAINS2GELNAGAINA_MASK) >> - SROM11_RXGAINS2GELNAGAINA_SHIFT); - /* rxgains1 */ - rxgains = (cis[i + 4] << 8) + cis[i + 3]; - varbuf_append(&b, vstr_rxgainsgxtrelnabypa, 5, 'h', a, - (rxgains & SROM11_RXGAINS5GTRELNABYPA_MASK) >> - SROM11_RXGAINS5GTRELNABYPA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxtrisoa, 5, 'h', a, - (rxgains & SROM11_RXGAINS5GTRISOA_MASK) >> - SROM11_RXGAINS5GTRISOA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxelnagaina, 5, 'h', a, - (rxgains & SROM11_RXGAINS5GELNAGAINA_MASK) >> - SROM11_RXGAINS5GELNAGAINA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxtrelnabypa, 5, 'm', a, - (rxgains & SROM11_RXGAINS5GTRELNABYPA_MASK) >> - SROM11_RXGAINS5GTRELNABYPA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxtrisoa, 5, 'm', a, - (rxgains & SROM11_RXGAINS5GTRISOA_MASK) >> - SROM11_RXGAINS5GTRISOA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxelnagaina, 5, 'm', a, - (rxgains & SROM11_RXGAINS5GELNAGAINA_MASK) >> - SROM11_RXGAINS5GELNAGAINA_SHIFT); - break; - } - - case HNBU_ACRXGAINS_C1: { - int a = 1; - - /* rxgains */ - uint16 rxgains = (cis[i + 2] << 8) + cis[i + 1]; - varbuf_append(&b, vstr_rxgainsgtrelnabypa, 5, a, - (rxgains & SROM11_RXGAINS5GTRELNABYPA_MASK) >> - SROM11_RXGAINS5GTRELNABYPA_SHIFT); - varbuf_append(&b, vstr_rxgainsgtrisoa, 5, a, - (rxgains & SROM11_RXGAINS5GTRISOA_MASK) >> - SROM11_RXGAINS5GTRISOA_SHIFT); - varbuf_append(&b, vstr_rxgainsgelnagaina, 5, a, - (rxgains & SROM11_RXGAINS5GELNAGAINA_MASK) >> - SROM11_RXGAINS5GELNAGAINA_SHIFT); - varbuf_append(&b, vstr_rxgainsgtrelnabypa, 2, a, - (rxgains & SROM11_RXGAINS2GTRELNABYPA_MASK) >> - SROM11_RXGAINS2GTRELNABYPA_SHIFT); - varbuf_append(&b, vstr_rxgainsgtrisoa, 2, a, - (rxgains & SROM11_RXGAINS2GTRISOA_MASK) >> - SROM11_RXGAINS2GTRISOA_SHIFT); - varbuf_append(&b, vstr_rxgainsgelnagaina, 2, a, - (rxgains & SROM11_RXGAINS2GELNAGAINA_MASK) >> - SROM11_RXGAINS2GELNAGAINA_SHIFT); - /* rxgains1 */ - rxgains = (cis[i + 4] << 8) + cis[i + 3]; - varbuf_append(&b, vstr_rxgainsgxtrelnabypa, 5, 'h', a, - (rxgains & SROM11_RXGAINS5GTRELNABYPA_MASK) >> - SROM11_RXGAINS5GTRELNABYPA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxtrisoa, 5, 'h', a, - (rxgains & SROM11_RXGAINS5GTRISOA_MASK) >> - SROM11_RXGAINS5GTRISOA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxelnagaina, 5, 'h', a, - (rxgains & SROM11_RXGAINS5GELNAGAINA_MASK) >> - SROM11_RXGAINS5GELNAGAINA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxtrelnabypa, 5, 'm', a, - (rxgains & SROM11_RXGAINS5GTRELNABYPA_MASK) >> - SROM11_RXGAINS5GTRELNABYPA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxtrisoa, 5, 'm', a, - (rxgains & SROM11_RXGAINS5GTRISOA_MASK) >> - SROM11_RXGAINS5GTRISOA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxelnagaina, 5, 'm', a, - (rxgains & SROM11_RXGAINS5GELNAGAINA_MASK) >> - SROM11_RXGAINS5GELNAGAINA_SHIFT); - break; - } - - case HNBU_ACRXGAINS_C2: { - int a = 2; - - /* rxgains */ - uint16 rxgains = (cis[i + 2] << 8) + cis[i + 1]; - varbuf_append(&b, vstr_rxgainsgtrelnabypa, 5, a, - (rxgains & SROM11_RXGAINS5GTRELNABYPA_MASK) >> - SROM11_RXGAINS5GTRELNABYPA_SHIFT); - varbuf_append(&b, vstr_rxgainsgtrisoa, 5, a, - (rxgains & SROM11_RXGAINS5GTRISOA_MASK) >> - SROM11_RXGAINS5GTRISOA_SHIFT); - varbuf_append(&b, vstr_rxgainsgelnagaina, 5, a, - (rxgains & SROM11_RXGAINS5GELNAGAINA_MASK) >> - SROM11_RXGAINS5GELNAGAINA_SHIFT); - varbuf_append(&b, vstr_rxgainsgtrelnabypa, 2, a, - (rxgains & SROM11_RXGAINS2GTRELNABYPA_MASK) >> - SROM11_RXGAINS2GTRELNABYPA_SHIFT); - varbuf_append(&b, vstr_rxgainsgtrisoa, 2, a, - (rxgains & SROM11_RXGAINS2GTRISOA_MASK) >> - SROM11_RXGAINS2GTRISOA_SHIFT); - varbuf_append(&b, vstr_rxgainsgelnagaina, 2, a, - (rxgains & SROM11_RXGAINS2GELNAGAINA_MASK) >> - SROM11_RXGAINS2GELNAGAINA_SHIFT); - /* rxgains1 */ - rxgains = (cis[i + 4] << 8) + cis[i + 3]; - varbuf_append(&b, vstr_rxgainsgxtrelnabypa, 5, 'h', a, - (rxgains & SROM11_RXGAINS5GTRELNABYPA_MASK) >> - SROM11_RXGAINS5GTRELNABYPA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxtrisoa, 5, 'h', a, - (rxgains & SROM11_RXGAINS5GTRISOA_MASK) >> - SROM11_RXGAINS5GTRISOA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxelnagaina, 5, 'h', a, - (rxgains & SROM11_RXGAINS5GELNAGAINA_MASK) >> - SROM11_RXGAINS5GELNAGAINA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxtrelnabypa, 5, 'm', a, - (rxgains & SROM11_RXGAINS5GTRELNABYPA_MASK) >> - SROM11_RXGAINS5GTRELNABYPA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxtrisoa, 5, 'm', a, - (rxgains & SROM11_RXGAINS5GTRISOA_MASK) >> - SROM11_RXGAINS5GTRISOA_SHIFT); - varbuf_append(&b, vstr_rxgainsgxelnagaina, 5, 'm', a, - (rxgains & SROM11_RXGAINS5GELNAGAINA_MASK) >> - SROM11_RXGAINS5GELNAGAINA_SHIFT); - break; - } - - case HNBU_TXDUTY: { - varbuf_append(&b, vstr_txduty_ofdm, 40, - (cis[i + 2] << 8) + cis[i + 1]); - varbuf_append(&b, vstr_txduty_thresh, 40, - (cis[i + 4] << 8) + cis[i + 3]); - varbuf_append(&b, vstr_txduty_ofdm, 80, - (cis[i + 6] << 8) + cis[i + 5]); - varbuf_append(&b, vstr_txduty_thresh, 80, - (cis[i + 8] << 8) + cis[i + 7]); - break; - } - - case HNBU_UUID: { - /* uuid format 12345678-1234-5678-1234-567812345678 */ - - char uuidstr[37]; /* 32 ids, 4 '-', 1 Null */ - - snprintf(uuidstr, sizeof(uuidstr), - rstr_uuidstr, - cis[i + 1], cis[i + 2], cis[i + 3], cis[i + 4], - cis[i + 5], cis[i + 6], cis[i + 7], cis[i + 8], - cis[i + 9], cis[i + 10], cis[i + 11], cis[i + 12], - cis[i + 13], cis[i + 14], cis[i + 15], cis[i + 16]); - - varbuf_append(&b, vstr_uuid, uuidstr); - break; - } - - case HNBU_WOWLGPIO: - varbuf_append(&b, vstr_wowlgpio, ((cis[i + 1]) & 0x7F)); - varbuf_append(&b, vstr_wowlgpiopol, - (((cis[i + 1]) >> 7) & 0x1)); - break; - -#endif /* !BCM_BOOTLOADER */ -#ifdef BCMUSBDEV_COMPOSITE - case HNBU_USBDESC_COMPOSITE: - varbuf_append(&b, vstr_usbdesc_composite, - (cis[i + 2] << 8) | cis[i + 1]); - break; -#endif /* BCMUSBDEV_COMPOSITE */ - case HNBU_USBUTMI_CTL: - varbuf_append(&b, vstr_usbutmi_ctl, - (cis[i + 2] << 8) | cis[i + 1]); - break; - - case HNBU_USBSSPHY_UTMI_CTL0: - varbuf_append(&b, vstr_usbssphy_utmi_ctl0, - (cis[i + 4] << 24) | (cis[i + 3] << 16) | - (cis[i + 2] << 8) | cis[i + 1]); - break; - - case HNBU_USBSSPHY_UTMI_CTL1: - varbuf_append(&b, vstr_usbssphy_utmi_ctl1, - (cis[i + 4] << 24) | (cis[i + 3] << 16) | - (cis[i + 2] << 8) | cis[i + 1]); - break; - - case HNBU_USBSSPHY_UTMI_CTL2: - varbuf_append(&b, vstr_usbssphy_utmi_ctl2, - (cis[i + 4] << 24) | (cis[i + 3] << 16) | - (cis[i + 2] << 8) | cis[i + 1]); - break; - - case HNBU_USBSSPHY_SLEEP0: - varbuf_append(&b, vstr_usbssphy_sleep0, - (cis[i + 2] << 8) | cis[i + 1]); - break; - - case HNBU_USBSSPHY_SLEEP1: - varbuf_append(&b, vstr_usbssphy_sleep1, - (cis[i + 2] << 8) | cis[i + 1]); - break; - - case HNBU_USBSSPHY_SLEEP2: - varbuf_append(&b, vstr_usbssphy_sleep2, - (cis[i + 2] << 8) | cis[i + 1]); - break; - - case HNBU_USBSSPHY_SLEEP3: - varbuf_append(&b, vstr_usbssphy_sleep3, - (cis[i + 2] << 8) | cis[i + 1]); - break; - case HNBU_USBSSPHY_MDIO: { - uint8 setnum; - uint16 k; - - setnum = (cis[i + 1])/4; - if (setnum == 0) - break; - for (j = 0; j < setnum; j++) { - k = j*12; - varbuf_append(&b, vstr_usbssphy_mdio, j, - (cis[i+4+k]<<16) | (cis[i+3+k]<<8) | cis[i+2+k], - (cis[i+7+k]<<16) | (cis[i+6+k]<<8) | cis[i+5+k], - (cis[i+10+k]<<16) | (cis[i+9+k]<<8) | cis[i+8+k], - (cis[i+13+k]<<16) | (cis[i+12+k]<<8) | cis[i+11+k]); - } - break; - } - case HNBU_USB30PHY_NOSS: - varbuf_append(&b, vstr_usb30phy_noss, cis[i + 1]); - break; - case HNBU_USB30PHY_U1U2: - varbuf_append(&b, vstr_usb30phy_u1u2, cis[i + 1]); - break; - case HNBU_USB30PHY_REGS: - varbuf_append(&b, vstr_usb30phy_regs, 0, - cis[i+4]|cis[i+3]|cis[i+2]|cis[i+1], - cis[i+8]|cis[i+7]|cis[i+6]|cis[i+5], - cis[i+12]|cis[i+11]|cis[i+10]|cis[i+9], - cis[i+16]|cis[i+15]|cis[i+14]|cis[i+13]); - varbuf_append(&b, vstr_usb30phy_regs, 1, - cis[i+20]|cis[i+19]|cis[i+18]|cis[i+17], - cis[i+24]|cis[i+23]|cis[i+22]|cis[i+21], - cis[i+28]|cis[i+27]|cis[i+26]|cis[i+25], - cis[i+32]|cis[i+31]|cis[i+30]|cis[i+29]); - - break; - - case HNBU_PDOFF_2G: { - uint16 pdoff_2g = (cis[i + 2] << 8) + cis[i + 1]; - varbuf_append(&b, vstr_pdoffset2gma, 40, 0, - (pdoff_2g & SROM11_PDOFF_2G_40M_A0_MASK) >> - SROM11_PDOFF_2G_40M_A0_SHIFT); - varbuf_append(&b, vstr_pdoffset2gma, 40, 1, - (pdoff_2g & SROM11_PDOFF_2G_40M_A1_MASK) >> - SROM11_PDOFF_2G_40M_A1_SHIFT); - varbuf_append(&b, vstr_pdoffset2gma, 40, 2, - (pdoff_2g & SROM11_PDOFF_2G_40M_A2_MASK) >> - SROM11_PDOFF_2G_40M_A2_SHIFT); - varbuf_append(&b, vstr_pdoffset2gmvalid, 40, - (pdoff_2g & SROM11_PDOFF_2G_40M_VALID_MASK) >> - SROM11_PDOFF_2G_40M_VALID_SHIFT); - break; - } - - case HNBU_ACPA_CCK_C0: - varbuf_append(&b, vstr_pa2gccka, 0, - (cis[i + 2] << 8) + cis[i + 1], - (cis[i + 4] << 8) + cis[i + 3], - (cis[i + 6] << 8) + cis[i + 5]); - break; - - case HNBU_ACPA_CCK_C1: - varbuf_append(&b, vstr_pa2gccka, 1, - (cis[i + 2] << 8) + cis[i + 1], - (cis[i + 4] << 8) + cis[i + 3], - (cis[i + 6] << 8) + cis[i + 5]); - break; - - case HNBU_ACPA_40: - varbuf_append(&b, vstr_pa5gbw40a, 0, - (cis[i + 2] << 8) + cis[i + 1], - (cis[i + 4] << 8) + cis[i + 3], - (cis[i + 6] << 8) + cis[i + 5], - (cis[i + 8] << 8) + cis[i + 7], - (cis[i + 10] << 8) + cis[i + 9], - (cis[i + 12] << 8) + cis[i + 11], - (cis[i + 14] << 8) + cis[i + 13], - (cis[i + 16] << 8) + cis[i + 15], - (cis[i + 18] << 8) + cis[i + 17], - (cis[i + 20] << 8) + cis[i + 19], - (cis[i + 22] << 8) + cis[i + 21], - (cis[i + 24] << 8) + cis[i + 23]); - break; - - case HNBU_ACPA_80: - varbuf_append(&b, vstr_pa5gbw80a, 0, - (cis[i + 2] << 8) + cis[i + 1], - (cis[i + 4] << 8) + cis[i + 3], - (cis[i + 6] << 8) + cis[i + 5], - (cis[i + 8] << 8) + cis[i + 7], - (cis[i + 10] << 8) + cis[i + 9], - (cis[i + 12] << 8) + cis[i + 11], - (cis[i + 14] << 8) + cis[i + 13], - (cis[i + 16] << 8) + cis[i + 15], - (cis[i + 18] << 8) + cis[i + 17], - (cis[i + 20] << 8) + cis[i + 19], - (cis[i + 22] << 8) + cis[i + 21], - (cis[i + 24] << 8) + cis[i + 23]); - break; - - case HNBU_ACPA_4080: - varbuf_append(&b, vstr_pa5gbw4080a, 0, - (cis[i + 2] << 8) + cis[i + 1], - (cis[i + 4] << 8) + cis[i + 3], - (cis[i + 6] << 8) + cis[i + 5], - (cis[i + 8] << 8) + cis[i + 7], - (cis[i + 10] << 8) + cis[i + 9], - (cis[i + 12] << 8) + cis[i + 11], - (cis[i + 14] << 8) + cis[i + 13], - (cis[i + 16] << 8) + cis[i + 15], - (cis[i + 18] << 8) + cis[i + 17], - (cis[i + 20] << 8) + cis[i + 19], - (cis[i + 22] << 8) + cis[i + 21], - (cis[i + 24] << 8) + cis[i + 23]); - varbuf_append(&b, vstr_pa5gbw4080a, 1, - (cis[i + 26] << 8) + cis[i + 25], - (cis[i + 28] << 8) + cis[i + 27], - (cis[i + 30] << 8) + cis[i + 29], - (cis[i + 32] << 8) + cis[i + 31], - (cis[i + 34] << 8) + cis[i + 33], - (cis[i + 36] << 8) + cis[i + 35], - (cis[i + 38] << 8) + cis[i + 37], - (cis[i + 40] << 8) + cis[i + 39], - (cis[i + 42] << 8) + cis[i + 41], - (cis[i + 44] << 8) + cis[i + 43], - (cis[i + 46] << 8) + cis[i + 45], - (cis[i + 48] << 8) + cis[i + 47]); - break; - - case HNBU_ACPA_4X4C0: - case HNBU_ACPA_4X4C1: - case HNBU_ACPA_4X4C2: - case HNBU_ACPA_4X4C3: { - int core_num = 0; - uint8 tuple = cis[i]; - - if (tuple == HNBU_ACPA_4X4C1) { - core_num = 1; - } else if (tuple == HNBU_ACPA_4X4C2) { - core_num = 2; - } else if (tuple == HNBU_ACPA_4X4C3) { - core_num = 3; - } - - varbuf_append(&b, vstr_maxp2ga, core_num, cis[i + 1]); - /* pa2g */ - varbuf_append(&b, vstr_sr13pa2ga, core_num, - (cis[i + 3] << 8) + cis[i + 2], - (cis[i + 5] << 8) + cis[i + 4], - (cis[i + 7] << 8) + cis[i + 6], - (cis[i + 9] << 8) + cis[i + 8]); - /* pa2g40 */ - varbuf_append(&b, vstr_pa2g40a, core_num, - (cis[i + 11] << 8) + cis[i + 10], - (cis[i + 13] << 8) + cis[i + 12], - (cis[i + 15] << 8) + cis[i + 14], - (cis[i + 17] << 8) + cis[i + 16]); - for (j = 0; j < 5; j++) { - varbuf_append(&b, vstr_maxp5gba, j, core_num, - cis[i + j + 18]); - } - break; - } - - case HNBU_ACPA_BW20_4X4C0: - case HNBU_ACPA_BW40_4X4C0: - case HNBU_ACPA_BW80_4X4C0: - case HNBU_ACPA_BW20_4X4C1: - case HNBU_ACPA_BW40_4X4C1: - case HNBU_ACPA_BW80_4X4C1: - case HNBU_ACPA_BW20_4X4C2: - case HNBU_ACPA_BW40_4X4C2: - case HNBU_ACPA_BW80_4X4C2: - case HNBU_ACPA_BW20_4X4C3: - case HNBU_ACPA_BW40_4X4C3: - case HNBU_ACPA_BW80_4X4C3: { - int k = 0; - char pabuf[140]; /* max: 20 '0x????'s + 19 ','s + 1 Null */ - int core_num = 0, buflen = 0; - uint8 tuple = cis[i]; - - if (tuple == HNBU_ACPA_BW20_4X4C1 || - tuple == HNBU_ACPA_BW40_4X4C1 || - tuple == HNBU_ACPA_BW80_4X4C1) { - core_num = 1; - } else if (tuple == HNBU_ACPA_BW20_4X4C2 || - tuple == HNBU_ACPA_BW40_4X4C2 || - tuple == HNBU_ACPA_BW80_4X4C2) { - core_num = 2; - } else if (tuple == HNBU_ACPA_BW20_4X4C3 || - tuple == HNBU_ACPA_BW40_4X4C3 || - tuple == HNBU_ACPA_BW80_4X4C3) { - core_num = 3; - } - - buflen = sizeof(pabuf); - for (j = 0; j < 20; j++) { /* cis[i+1] - cis[i+40] */ - k += snprintf(pabuf+k, buflen-k, rstr_hex, - ((cis[i + (2*j) + 2] << 8) + - cis[i + (2*j) + 1])); - if (j < 19) { - k += snprintf(pabuf+k, buflen-k, - ","); - } - } - - if (tuple == HNBU_ACPA_BW20_4X4C0 || - tuple == HNBU_ACPA_BW20_4X4C1 || - tuple == HNBU_ACPA_BW20_4X4C2 || - tuple == HNBU_ACPA_BW20_4X4C3) { - varbuf_append(&b, vstr_sr13pa5ga, core_num, pabuf); - } else { - int bw = 40; - - if (tuple == HNBU_ACPA_BW80_4X4C0 || - tuple == HNBU_ACPA_BW80_4X4C1 || - tuple == HNBU_ACPA_BW80_4X4C2 || - tuple == HNBU_ACPA_BW80_4X4C3) { - bw = 80; - } - varbuf_append(&b, vstr_sr13pa5gbwa, bw, - core_num, pabuf); - } - break; - } - - case HNBU_RSSI_DELTA_2G_B0: - case HNBU_RSSI_DELTA_2G_B1: - case HNBU_RSSI_DELTA_2G_B2: - case HNBU_RSSI_DELTA_2G_B3: - case HNBU_RSSI_DELTA_2G_B4: { - uint8 tuple = cis[i]; - uint8 grp; - if (tuple == HNBU_RSSI_DELTA_2G_B0) { - grp = 0; - } else if (tuple == HNBU_RSSI_DELTA_2G_B1) { - grp = 1; - } else if (tuple == HNBU_RSSI_DELTA_2G_B2) { - grp = 2; - } else if (tuple == HNBU_RSSI_DELTA_2G_B3) { - grp = 3; - } else { - grp = 4; - } - /* 2G Band Gourp = grp */ - varbuf_append(&b, vstr_rssidelta2g, grp, - cis[i + 1], cis[i + 2], - cis[i + 3], cis[i + 4], - cis[i + 5], cis[i + 6], - cis[i + 7], cis[i + 8], - cis[i + 9], cis[i + 10], - cis[i + 11], cis[i + 12], - cis[i + 13], cis[i + 14], - cis[i + 15], cis[i + 16]); - break; - } - - case HNBU_RSSI_CAL_FREQ_GRP_2G: - /* 2G Band Gourp Defintion */ - varbuf_append(&b, vstr_rssicalfrqg, - cis[i + 1], cis[i + 2], - cis[i + 3], cis[i + 4], - cis[i + 5], cis[i + 6], - cis[i + 7]); - break; - - case HNBU_RSSI_DELTA_5GL: - case HNBU_RSSI_DELTA_5GML: - case HNBU_RSSI_DELTA_5GMU: - case HNBU_RSSI_DELTA_5GH: { - uint8 tuple = cis[i]; - char *band[] = {"l", "ml", "mu", "h"}; - char *pband; - if (tuple == HNBU_RSSI_DELTA_5GL) { - pband = band[0]; - } else if (tuple == HNBU_RSSI_DELTA_5GML) { - pband = band[1]; - } else if (tuple == HNBU_RSSI_DELTA_5GMU) { - pband = band[2]; - } else { - pband = band[3]; - } - /* 5G Band = band */ - varbuf_append(&b, vstr_rssidelta5g, pband, - cis[i + 1], cis[i + 2], - cis[i + 3], cis[i + 4], - cis[i + 5], cis[i + 6], - cis[i + 7], cis[i + 8], - cis[i + 9], cis[i + 10], - cis[i + 11], cis[i + 12], - cis[i + 13], cis[i + 14], - cis[i + 15], cis[i + 16], - cis[i + 17], cis[i + 17], - cis[i + 19], cis[i + 20], - cis[i + 21], cis[i + 22], - cis[i + 9], cis[i + 24]); - break; - } - - case HNBU_ACPA_6G_C0: { - const int a = 0; -#ifndef OTP_SKIP_MAXP_PAPARAMS - varbuf_append(&b, vstr_subband6gver, - (cis[i + 2] << 8) + cis[i + 1]); - /* maxp5g */ - varbuf_append(&b, vstr_maxp6ga, a, - cis[i + 3], - cis[i + 4], - cis[i + 5], - cis[i + 6], - cis[i + 7], - cis[i + 8]); -#endif /* OTP_SKIP_MAXP_PAPARAMS */ - /* pa5g */ - varbuf_append(&b, vstr_pa6ga, a, - (cis[i + 10] << 8) + cis[i + 9], - (cis[i + 12] << 8) + cis[i + 11], - (cis[i + 14] << 8) + cis[i + 13], - (cis[i + 16] << 8) + cis[i + 15], - (cis[i + 18] << 8) + cis[i + 17], - (cis[i + 20] << 8) + cis[i + 19], - (cis[i + 22] << 8) + cis[i + 21], - (cis[i + 24] << 8) + cis[i + 23], - (cis[i + 26] << 8) + cis[i + 25], - (cis[i + 28] << 8) + cis[i + 27], - (cis[i + 30] << 8) + cis[i + 29], - (cis[i + 32] << 8) + cis[i + 31], - (cis[i + 34] << 8) + cis[i + 33], - (cis[i + 36] << 8) + cis[i + 35], - (cis[i + 38] << 8) + cis[i + 37], - (cis[i + 40] << 8) + cis[i + 39], - (cis[i + 42] << 8) + cis[i + 41], - (cis[i + 44] << 8) + cis[i + 43]); - break; - } - - case HNBU_ACPA_6G_C1: { - const int a = 1; -#ifndef OTP_SKIP_MAXP_PAPARAMS - /* maxp6g */ - varbuf_append(&b, vstr_maxp6ga, a, - cis[i + 1], - cis[i + 2], - cis[i + 3], - cis[i + 4], - cis[i + 5], - cis[i + 6]); -#endif /* OTP_SKIP_MAXP_PAPARAMS */ - /* pa6g */ - varbuf_append(&b, vstr_pa6ga, a, - (cis[i + 8] << 8) + cis[i + 7], - (cis[i + 10] << 8) + cis[i + 9], - (cis[i + 12] << 8) + cis[i + 11], - (cis[i + 14] << 8) + cis[i + 13], - (cis[i + 16] << 8) + cis[i + 15], - (cis[i + 18] << 8) + cis[i + 17], - (cis[i + 20] << 8) + cis[i + 19], - (cis[i + 22] << 8) + cis[i + 21], - (cis[i + 24] << 8) + cis[i + 23], - (cis[i + 26] << 8) + cis[i + 25], - (cis[i + 28] << 8) + cis[i + 27], - (cis[i + 30] << 8) + cis[i + 29], - (cis[i + 32] << 8) + cis[i + 31], - (cis[i + 34] << 8) + cis[i + 33], - (cis[i + 36] << 8) + cis[i + 35], - (cis[i + 38] << 8) + cis[i + 37], - (cis[i + 40] << 8) + cis[i + 39], - (cis[i + 42] << 8) + cis[i + 41]); - break; - } - - case HNBU_ACPA_6G_C2: { - const int a = 2; -#ifndef OTP_SKIP_MAXP_PAPARAMS - /* maxp6g */ - varbuf_append(&b, vstr_maxp6ga, a, - cis[i + 1], - cis[i + 2], - cis[i + 3], - cis[i + 4], - cis[i + 5], - cis[i + 6]); -#endif /* OTP_SKIP_MAXP_PAPARAMS */ - /* pa6g */ - varbuf_append(&b, vstr_pa6ga, a, - (cis[i + 8] << 8) + cis[i + 7], - (cis[i + 10] << 8) + cis[i + 9], - (cis[i + 12] << 8) + cis[i + 11], - (cis[i + 14] << 8) + cis[i + 13], - (cis[i + 16] << 8) + cis[i + 15], - (cis[i + 18] << 8) + cis[i + 17], - (cis[i + 20] << 8) + cis[i + 19], - (cis[i + 22] << 8) + cis[i + 21], - (cis[i + 24] << 8) + cis[i + 23], - (cis[i + 26] << 8) + cis[i + 25], - (cis[i + 28] << 8) + cis[i + 27], - (cis[i + 30] << 8) + cis[i + 29], - (cis[i + 32] << 8) + cis[i + 31], - (cis[i + 34] << 8) + cis[i + 33], - (cis[i + 36] << 8) + cis[i + 35], - (cis[i + 38] << 8) + cis[i + 37], - (cis[i + 40] << 8) + cis[i + 39], - (cis[i + 42] << 8) + cis[i + 41]); - break; - } - - case HNBU_SUBBAND5GVER: - varbuf_append(&b, vstr_subband5gver, - (cis[i + 2] << 8) + cis[i + 1]); - break; - - case HNBU_PAPARAMBWVER: - varbuf_append(&b, vstr_paparambwver, cis[i + 1]); - break; - - case HNBU_TXBFRPCALS: - /* note: all 5 rpcal parameters are expected to be */ - /* inside one tuple record, i.e written with one */ - /* wl wrvar cmd as follows: */ - /* wl wrvar rpcal2g=0x1211 ... rpcal5gb3=0x0 */ - if (tlen != 11 ) { /* sanity check */ - BS_ERROR(("srom_parsecis:incorrect length:%d for" - " HNBU_TXBFRPCALS tuple\n", - tlen)); - break; - } - - varbuf_append(&b, vstr_paparamrpcalvars[0], - (cis[i + 1] + (cis[i + 2] << 8))); - varbuf_append(&b, vstr_paparamrpcalvars[1], - (cis[i + 3] + (cis[i + 4] << 8))); - varbuf_append(&b, vstr_paparamrpcalvars[2], - (cis[i + 5] + (cis[i + 6] << 8))); - varbuf_append(&b, vstr_paparamrpcalvars[3], - (cis[i + 7] + (cis[i + 8] << 8))); - varbuf_append(&b, vstr_paparamrpcalvars[4], - (cis[i + 9] + (cis[i + 10] << 8))); - break; - - case HNBU_GPIO_PULL_DOWN: - varbuf_append(&b, vstr_gpdn, - (cis[i + 4] << 24) | - (cis[i + 3] << 16) | - (cis[i + 2] << 8) | - cis[i + 1]); - break; - - case HNBU_MACADDR2: - if (!(ETHER_ISNULLADDR(&cis[i+1])) && - !(ETHER_ISMULTI(&cis[i+1]))) { - bcm_ether_ntoa((struct ether_addr *)&cis[i + 1], - eabuf2); - } - break; - } /* CISTPL_BRCM_HNBU */ - break; - } /* switch (tup) */ - - i += tlen; - } while (tup != CISTPL_END); - } - - if (boardnum != -1) { - varbuf_append(&b, vstr_boardnum, boardnum); - } - - if (eabuf[0]) { - varbuf_append(&b, vstr_macaddr, eabuf); - } - - if (eabuf2[0]) { - varbuf_append(&b, vstr_macaddr2, eabuf2); - } - -#ifndef BCM_BOOTLOADER - /* if there is no antenna gain field, set default */ - sromrev = (sromrev == 1u) ? (uint8)getintvar(NULL, rstr_sromrev) : sromrev; - if (sromrev <= 10u && getvar(NULL, rstr_ag0) == NULL && ag_init == FALSE) { - varbuf_append(&b, vstr_ag, 0, 0xff); - } -#endif - - /* final nullbyte terminator */ - ASSERT(b.size >= 1u); - *b.buf++ = '\0'; - - ASSERT((uint)(b.buf - base) <= var_cis_size); - - /* initvars_table() MALLOCs, copies and assigns the MALLOCed buffer to '*vars' */ - err = initvars_table(osh, base /* start */, b.buf /* end */, vars, count); - - MFREE(osh, base, var_cis_size); - return err; -} -#endif /* !defined(BCMDONGLEHOST) */ - -/** - * In chips with chipcommon rev 32 and later, the srom is in chipcommon, - * not in the bus cores. - */ -static uint16 -srom_cc_cmd(si_t *sih, osl_t *osh, volatile void *ccregs, uint32 cmd, uint wordoff, uint16 data) -{ - chipcregs_t *cc = ccregs; - uint wait_cnt = 1000; - uint32 byteoff = 0, sprom_size = 0; - - BCM_REFERENCE(sih); - byteoff = wordoff * 2; - - sprom_size = R_REG(osh, &cc->sromcontrol); - sprom_size = (sprom_size & SROM_SIZE_MASK) >> SROM_SIZE_SHFT_MASK; - if (sprom_size == SROM_SIZE_2K) - sprom_size = 2048; - else if (sprom_size == SROM_SIZE_512) - sprom_size = 512; - else if (sprom_size == SROM_SIZE_128) - sprom_size = 128; - if (byteoff >= sprom_size) - return 0xffff; - - if ((cmd == SRC_OP_READ) || (cmd == SRC_OP_WRITE)) { - if (sih->ccrev >= 59) - W_REG(osh, &cc->chipcontrol, (byteoff & SROM16K_BANK_SEL_MASK) >> - SROM16K_BANK_SHFT_MASK); - W_REG(osh, &cc->sromaddress, (byteoff & SROM16K_ADDR_SEL_MASK)); - if (cmd == SRC_OP_WRITE) - W_REG(osh, &cc->sromdata, data); - } - - W_REG(osh, &cc->sromcontrol, SRC_START | cmd); - - while (wait_cnt--) { - if ((R_REG(osh, &cc->sromcontrol) & SRC_BUSY) == 0) - break; - } - - if (!wait_cnt) { - BS_ERROR(("srom_cc_cmd: Command 0x%x timed out\n", cmd)); - return 0xffff; - } - if (cmd == SRC_OP_READ) - return (uint16)R_REG(osh, &cc->sromdata); - else - return 0xffff; -} - -#define CC_SROM_SHADOW_WSIZE 512 /* 0x800 - 0xC00 */ - -/** - * Read in and validate sprom. - * Return 0 on success, nonzero on error. - * Returns success on an SPROM containing only ones, unclear if this is intended. - */ -static int -sprom_read_pci(osl_t *osh, si_t *sih, volatile uint16 *sprom, uint wordoff, - uint16 *buf, uint nwords, bool check_crc) -{ - int err = 0; - uint i; - volatile void *ccregs = NULL; - chipcregs_t *cc = NULL; - uint32 ccval = 0, sprom_size = 0; - uint32 sprom_num_words; - - if (BCM43602_CHIP(sih->chip) || - (CHIPID(sih->chip) == BCM4360_CHIP_ID) || - (CHIPID(sih->chip) == BCM43460_CHIP_ID) || - (CHIPID(sih->chip) == BCM4352_CHIP_ID)) { - /* save current control setting */ - ccval = si_chipcontrl_read(sih); - } - - if (BCM43602_CHIP(sih->chip) || - (((CHIPID(sih->chip) == BCM4360_CHIP_ID) || - (CHIPID(sih->chip) == BCM43460_CHIP_ID) || - (CHIPID(sih->chip) == BCM4352_CHIP_ID)) && - (CHIPREV(sih->chiprev) <= 2))) { - si_chipcontrl_srom4360(sih, TRUE); - } - - if (FALSE) { - si_srom_clk_set(sih); /* corrects srom clock frequency */ - } - - ccregs = ((volatile uint8 *)sprom - CC_SROM_OTP); - cc = ccregs; - sprom_size = R_REG(osh, &cc->sromcontrol); - sprom_size = (sprom_size & SROM_SIZE_MASK) >> SROM_SIZE_SHFT_MASK; - if (sprom_size == SROM_SIZE_2K) - sprom_size = 2048; - else if (sprom_size == SROM_SIZE_512) - sprom_size = 512; - else if (sprom_size == SROM_SIZE_128) - sprom_size = 128; - sprom_num_words = sprom_size/2; - - /* read the sprom */ - for (i = 0; i < nwords; i++) { - if (sih->ccrev > 31 && ISSIM_ENAB(sih)) { - /* use indirect since direct is too slow on QT */ - if ((sih->cccaps & CC_CAP_SROM) == 0) { - err = 1; - goto error; - } - - /* hack to get ccregs */ - ccregs = (volatile void *)((volatile uint8 *)sprom - CC_SROM_OTP); - buf[i] = srom_cc_cmd(sih, osh, ccregs, SRC_OP_READ, wordoff + i, 0); - - } else { - /* Because of the slow emulation we need to read twice in QT */ - if (ISSIM_ENAB(sih)) { - buf[i] = R_REG(osh, &sprom[wordoff + i]); - } - - if ((wordoff + i) >= sprom_num_words) { - buf[i] = 0xffff; - } else if ((wordoff + i) >= CC_SROM_SHADOW_WSIZE) { - /* Srom shadow region in chipcommon is only 512 words - * use indirect access for Srom beyond 512 words - */ - buf[i] = srom_cc_cmd(sih, osh, ccregs, SRC_OP_READ, wordoff + i, 0); - } else { - buf[i] = R_REG(osh, &sprom[wordoff + i]); - } - } - if (i == SROM13_SIGN) { - if ((buf[SROM13_SIGN] != SROM13_SIGNATURE) && (nwords == SROM13_WORDS)) { - err = 1; - goto error; - } - } - } - - /* bypass crc checking for simulation to allow srom hack */ - if (ISSIM_ENAB(sih)) { - goto error; - } - - if (check_crc) { - - if (buf[0] == 0xffff) { - /* The hardware thinks that an srom that starts with 0xffff - * is blank, regardless of the rest of the content, so declare - * it bad. - */ - BS_ERROR(("sprom_read_pci: buf[0] = 0x%x, returning bad-crc\n", buf[0])); - err = 1; - goto error; - } - - /* fixup the endianness so crc8 will pass */ - htol16_buf(buf, nwords * 2); - if (hndcrc8((uint8 *)buf, nwords * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE) { - /* DBG only pci always read srom4 first, then srom8/9 */ - /* BS_ERROR(("sprom_read_pci: bad crc\n")); */ - err = 1; - } - /* now correct the endianness of the byte array */ - ltoh16_buf(buf, nwords * 2); - } - -error: - if ((CHIPID(sih->chip) == BCM4360_CHIP_ID) || - (CHIPID(sih->chip) == BCM43460_CHIP_ID) || - (CHIPID(sih->chip) == BCM4352_CHIP_ID) || - BCM43602_CHIP(sih->chip)) { - /* Restore config after reading SROM */ - si_chipcontrl_restore(sih, ccval); - } - - return err; -} - -#if !defined(BCMDONGLEHOST) -#if defined(BCMNVRAMW) || defined(BCMNVRAMR) -static int -BCMSROMATTACHFN(otp_read_pci)(osl_t *osh, si_t *sih, uint16 *buf, uint bufsz) -{ - uint8 *otp; - uint sz = OTP_SZ_MAX/2; /* size in words */ - int err = 0; - - if (bufsz > OTP_SZ_MAX) { - return BCME_ERROR; - } - - /* freed in same function */ - if ((otp = MALLOC_NOPERSIST(osh, OTP_SZ_MAX)) == NULL) { - return BCME_ERROR; - } - - bzero(otp, OTP_SZ_MAX); - - err = otp_read_region(sih, OTP_HW_RGN, (uint16 *)otp, &sz); - - if (err) { - MFREE(osh, otp, OTP_SZ_MAX); - return err; - } - - bcopy(otp, buf, bufsz); - - /* Check CRC */ - if (((uint16 *)otp)[0] == 0xffff) { - /* The hardware thinks that an srom that starts with 0xffff - * is blank, regardless of the rest of the content, so declare - * it bad. - */ - BS_ERROR(("otp_read_pci: otp[0] = 0x%x, returning bad-crc\n", - ((uint16 *)otp)[0])); - MFREE(osh, otp, OTP_SZ_MAX); - return 1; - } - - /* fixup the endianness so crc8 will pass */ - htol16_buf(otp, OTP_SZ_MAX); - if (hndcrc8(otp, SROM4_WORDS * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE && - hndcrc8(otp, SROM10_WORDS * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE && - hndcrc8(otp, SROM11_WORDS * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE && - hndcrc8(otp, SROM12_WORDS * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE && - hndcrc8(otp, SROM13_WORDS * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE) { - BS_ERROR(("otp_read_pci: bad crc\n")); - err = 1; - } - - MFREE(osh, otp, OTP_SZ_MAX); - - return err; -} -#endif /* defined(BCMNVRAMW) || defined(BCMNVRAMR) */ -#endif /* !defined(BCMDONGLEHOST) */ - -int -srom_otp_write_region_crc(si_t *sih, uint nbytes, uint16* buf16, bool write) -{ -#if defined(WLTEST) || defined(BCMDBG) - int err = 0, crc = 0; -#if !defined(BCMDONGLEHOST) - uint8 *buf8; - - /* Check nbytes is not odd or too big */ - if ((nbytes & 1) || (nbytes > SROM_MAX)) - return 1; - - /* block invalid buffer size */ - if (nbytes < SROM4_WORDS * 2) - return BCME_BUFTOOSHORT; - else if (nbytes > SROM13_WORDS * 2) - return BCME_BUFTOOLONG; - - /* Verify signatures */ - if (!((buf16[SROM4_SIGN] == SROM4_SIGNATURE) || - (buf16[SROM8_SIGN] == SROM4_SIGNATURE) || - (buf16[SROM10_SIGN] == SROM4_SIGNATURE) || - (buf16[SROM11_SIGN] == SROM11_SIGNATURE)|| - (buf16[SROM12_SIGN] == SROM12_SIGNATURE)|| - (buf16[SROM13_SIGN] == SROM13_SIGNATURE))) { - BS_ERROR(("srom_otp_write_region_crc: wrong signature SROM4_SIGN %x SROM8_SIGN %x" - " SROM10_SIGN %x\n", - buf16[SROM4_SIGN], buf16[SROM8_SIGN], buf16[SROM10_SIGN])); - return BCME_ERROR; - } - - /* Check CRC */ - if (buf16[0] == 0xffff) { - /* The hardware thinks that an srom that starts with 0xffff - * is blank, regardless of the rest of the content, so declare - * it bad. - */ - BS_ERROR(("srom_otp_write_region_crc: invalid buf16[0] = 0x%x\n", buf16[0])); - goto out; - } - - buf8 = (uint8*)buf16; - /* fixup the endianness and then calculate crc */ - htol16_buf(buf8, nbytes); - crc = ~hndcrc8(buf8, nbytes - 1, CRC8_INIT_VALUE); - /* now correct the endianness of the byte array */ - ltoh16_buf(buf8, nbytes); - - if (nbytes == SROM11_WORDS * 2) - buf16[SROM11_CRCREV] = (crc << 8) | (buf16[SROM11_CRCREV] & 0xff); - else if (nbytes == SROM12_WORDS * 2) - buf16[SROM12_CRCREV] = (crc << 8) | (buf16[SROM12_CRCREV] & 0xff); - else if (nbytes == SROM13_WORDS * 2) - buf16[SROM13_CRCREV] = (crc << 8) | (buf16[SROM13_CRCREV] & 0xff); - else if (nbytes == SROM10_WORDS * 2) - buf16[SROM10_CRCREV] = (crc << 8) | (buf16[SROM10_CRCREV] & 0xff); - else - buf16[SROM4_CRCREV] = (crc << 8) | (buf16[SROM4_CRCREV] & 0xff); - -#ifdef BCMNVRAMW - /* Write the CRC back */ - if (write) - err = otp_write_region(sih, OTP_HW_RGN, buf16, nbytes/2, 0); -#endif /* BCMNVRAMW */ - -out: -#endif /* !defined(BCMDONGLEHOST) */ - return write ? err : crc; -#else - BCM_REFERENCE(sih); - BCM_REFERENCE(nbytes); - BCM_REFERENCE(buf16); - BCM_REFERENCE(write); - return 0; -#endif /* WLTEST || BCMDBG */ - -} - -#if !defined(BCMDONGLEHOST) -int -BCMATTACHFN(dbushost_initvars_flash)(si_t *sih, osl_t *osh, char **base, uint len) -{ - return initvars_flash(sih, osh, base, len); -} - -/** - * Find variables with from flash. 'base' points to the beginning - * of the table upon enter and to the end of the table upon exit when success. - * Return 0 on success, nonzero on error. - */ -static int -BCMATTACHFN(initvars_flash)(si_t *sih, osl_t *osh, char **base, uint len) -{ - char *vp = *base; - char *flash; - int err; - char *s; - uint l, dl, copy_len; - char devpath[SI_DEVPATH_BUFSZ], devpath_pcie[SI_DEVPATH_BUFSZ]; - char coded_name[SI_DEVPATH_BUFSZ] = {0}; - int path_len, coded_len, devid_len, pcie_path_len; - - /* allocate memory and read in flash */ - /* freed in same function */ - if (!(flash = MALLOC_NOPERSIST(osh, MAX_NVRAM_SPACE))) - return BCME_NOMEM; - if ((err = nvram_getall(flash, MAX_NVRAM_SPACE))) - goto exit; - - /* create legacy devpath prefix */ - si_devpath(sih, devpath, sizeof(devpath)); - path_len = strlen(devpath); - - if (BUSTYPE(sih->bustype) == PCI_BUS) { - si_devpath_pcie(sih, devpath_pcie, sizeof(devpath_pcie)); - pcie_path_len = strlen(devpath_pcie); - } else - pcie_path_len = 0; - - /* create coded devpath prefix */ - si_coded_devpathvar(sih, coded_name, sizeof(coded_name), "devid"); - - /* coded_name now is 'xx:devid, eat ending 'devid' */ - /* to be 'xx:' */ - devid_len = strlen("devid"); - coded_len = strlen(coded_name); - if (coded_len > devid_len) { - coded_name[coded_len - devid_len] = '\0'; - coded_len -= devid_len; - } - else - coded_len = 0; - - /* grab vars with the prefix or previx in name */ - for (s = flash; s && *s; s += l + 1) { - l = strlen(s); - - /* skip non-matching variable */ - if (strncmp(s, devpath, path_len) == 0) - dl = path_len; - else if (pcie_path_len && strncmp(s, devpath_pcie, pcie_path_len) == 0) - dl = pcie_path_len; - else if (coded_len && strncmp(s, coded_name, coded_len) == 0) - dl = coded_len; - else - continue; - - /* is there enough room to copy? */ - copy_len = l - dl + 1; - if (len < copy_len) { - err = BCME_BUFTOOSHORT; - goto exit; - } - - /* no prefix, just the name=value */ - strlcpy(vp, &s[dl], copy_len); - vp += copy_len; - len -= copy_len; - } - - /* add null string as terminator */ - if (len < 1) { - err = BCME_BUFTOOSHORT; - goto exit; - } - *vp++ = '\0'; - - *base = vp; - -exit: - MFREE(osh, flash, MAX_NVRAM_SPACE); - return err; -} -#endif /* !defined(BCMDONGLEHOST) */ - -#if !defined(BCMUSBDEV_ENABLED) && !defined(BCMSDIODEV_ENABLED) && \ - !defined(BCMPCIEDEV_ENABLED) -#if !defined(BCMDONGLEHOST) -/** - * Initialize nonvolatile variable table from flash. - * Return 0 on success, nonzero on error. - */ -/* no needs to load the nvram variables from the flash for dongles. - * These variables are mainly for supporting SROM-less devices although - * we can use the same machenism to support configuration of multiple - * cores of the same type. - */ -static int -BCMATTACHFN(initvars_flash_si)(si_t *sih, char **vars, uint *count) -{ - osl_t *osh = si_osh(sih); - char *vp, *base; - int err; - - ASSERT(vars != NULL); - ASSERT(count != NULL); - - /* freed in same function */ - base = vp = MALLOC_NOPERSIST(osh, MAXSZ_NVRAM_VARS); - ASSERT(vp != NULL); - if (!vp) - return BCME_NOMEM; - - if ((err = initvars_flash(sih, osh, &vp, MAXSZ_NVRAM_VARS)) == 0) - err = initvars_table(osh, base, vp, vars, count); - - MFREE(osh, base, MAXSZ_NVRAM_VARS); - - return err; -} -#endif /* !defined(BCMDONGLEHOST) */ -#endif /* !BCMUSBDEV && !BCMSDIODEV */ - -#if !defined(BCMDONGLEHOST) - -/** returns position of rightmost bit that was set in caller supplied mask */ -static uint -mask_shift(uint16 mask) -{ - uint i; - for (i = 0; i < (sizeof(mask) << 3); i ++) { - if (mask & (1 << i)) - return i; - } - ASSERT(mask); - return 0; -} - -static uint -mask_width(uint16 mask) -{ - int i; - for (i = (sizeof(mask) << 3) - 1; i >= 0; i --) { - if (mask & (1 << i)) - return (uint)(i - mask_shift(mask) + 1); - } - ASSERT(mask); - return 0; -} - -#ifdef BCMASSERT_SUPPORT -static bool -mask_valid(uint16 mask) -{ - uint shift = mask_shift(mask); - uint width = mask_width(mask); - return mask == ((~0 << shift) & ~(~0 << (shift + width))); -} -#endif -#ifdef NVSRCX -void -srom_set_sromvars(char *vars) -{ - if (sromh) - sromh->_srom_vars = vars; -} -char * -srom_get_sromvars() -{ - if (sromh) - return sromh->_srom_vars; - else - return NULL; -} - -srom_info_t * -srom_info_init(osl_t *osh) -{ - sromh = (srom_info_t *) MALLOC_NOPERSIST(osh, sizeof(srom_info_t)); - if (!sromh) - return NULL; - sromh->_srom_vars = NULL; - sromh->is_caldata_prsnt = FALSE; - return sromh; -} -#endif /* NVSRCX */ -/** - * Parses caller supplied SROM contents into name=value pairs. Global array pci_sromvars[] contains - * the link between a word offset in SROM and the corresponding NVRAM variable name.'srom' points to - * the SROM word array. 'off' specifies the offset of the first word 'srom' points to, which should - * be either 0 or SROM3_SWRG_OFF (full SROM or software region). - */ -static void -BCMATTACHFN(_initvars_srom_pci)(uint8 sromrev, uint16 *srom, uint off, varbuf_t *b) -{ - uint16 w; - uint32 val; - const sromvar_t *srv; - uint width; - uint flags; - uint32 sr = (1 << sromrev); - bool in_array = FALSE; - static char array_temp[256]; - uint array_curr = 0; - const char* array_name = NULL; - - varbuf_append(b, "sromrev=%d", sromrev); -#if !defined(SROM15_MEMOPT) && !defined(SROM17_MEMOPT) - if (sromrev == 15) { - srv = pci_srom15vars; - } else if (sromrev == 16) { - srv = pci_srom16vars; - } else if (sromrev == 17) { - srv = pci_srom17vars; - } else if (sromrev == 18) { - srv = pci_srom18vars; - } else { - srv = pci_sromvars; - } -#else -#if defined(SROM15_MEMOPT) - srv = pci_srom15vars; -#endif /* defined(SROM15_MEMOPT) */ -#if defined(SROM17_MEMOPT) - srv = pci_srom17vars; -#endif /* defined(SROM17_MEMOPT) */ -#endif /* !defined(SROM15_MEMOPT) && !defined(SROM17_MEMOPT) */ - - for (; srv->name != NULL; srv ++) { - const char *name; - static bool in_array2 = FALSE; - static char array_temp2[256]; - static uint array_curr2 = 0; - static const char* array_name2 = NULL; - - if ((srv->revmask & sr) == 0) - continue; - - if (srv->off < off) - continue; - - flags = srv->flags; - name = srv->name; - - /* This entry is for mfgc only. Don't generate param for it, */ - if (flags & SRFL_NOVAR) - continue; - - if (flags & SRFL_ETHADDR) { - char eabuf[ETHER_ADDR_STR_LEN]; - struct ether_addr ea; - - ea.octet[0] = (srom[srv->off - off] >> 8) & 0xff; - ea.octet[1] = srom[srv->off - off] & 0xff; - ea.octet[2] = (srom[srv->off + 1 - off] >> 8) & 0xff; - ea.octet[3] = srom[srv->off + 1 - off] & 0xff; - ea.octet[4] = (srom[srv->off + 2 - off] >> 8) & 0xff; - ea.octet[5] = srom[srv->off + 2 - off] & 0xff; - bcm_ether_ntoa(&ea, eabuf); - - varbuf_append(b, "%s=%s", name, eabuf); - } else { - ASSERT(mask_valid(srv->mask)); - ASSERT(mask_width(srv->mask)); - - /* Start of an array */ - if (sromrev >= 10 && (srv->flags & SRFL_ARRAY) && !in_array2) { - array_curr2 = 0; - array_name2 = (const char*)srv->name; - bzero((void*)array_temp2, sizeof(array_temp2)); - in_array2 = TRUE; - } - - w = srom[srv->off - off]; - val = (w & srv->mask) >> mask_shift(srv->mask); - width = mask_width(srv->mask); - - while (srv->flags & SRFL_MORE) { - srv ++; - ASSERT(srv->name != NULL); - - if (srv->off == 0 || srv->off < off) - continue; - - ASSERT(mask_valid(srv->mask)); - ASSERT(mask_width(srv->mask)); - - w = srom[srv->off - off]; - val += ((w & srv->mask) >> mask_shift(srv->mask)) << width; - width += mask_width(srv->mask); - } - - if ((flags & SRFL_NOFFS) && ((int)val == (1 << width) - 1)) - continue; - - /* Array support starts in sromrev 10. Skip arrays for sromrev <= 9 */ - if (sromrev <= 9 && srv->flags & SRFL_ARRAY) { - while (srv->flags & SRFL_ARRAY) - srv ++; - srv ++; - } - - if (in_array2) { - int ret; - - if (flags & SRFL_PRHEX) { - ret = snprintf(array_temp2 + array_curr2, - sizeof(array_temp2) - array_curr2, "0x%x,", val); - } else if ((flags & SRFL_PRSIGN) && - (val & (1 << (width - 1)))) { - ret = snprintf(array_temp2 + array_curr2, - sizeof(array_temp2) - array_curr2, "%d,", - (int)(val | (~0 << width))); - } else { - ret = snprintf(array_temp2 + array_curr2, - sizeof(array_temp2) - array_curr2, "%u,", val); - } - - if (ret > 0) { - array_curr2 += ret; - } else { - BS_ERROR(("_initvars_srom_pci: array %s parsing error." - " buffer too short.\n", - array_name2)); - ASSERT(0); - - /* buffer too small, skip this param */ - while (srv->flags & SRFL_ARRAY) - srv ++; - srv ++; - in_array2 = FALSE; - continue; - } - - if (!(srv->flags & SRFL_ARRAY)) { /* Array ends */ - /* Remove the last ',' */ - array_temp2[array_curr2-1] = '\0'; - in_array2 = FALSE; - varbuf_append(b, "%s=%s", array_name2, array_temp2); - } - } else if (flags & SRFL_CCODE) { - if (val == 0) - varbuf_append(b, "ccode="); - else - varbuf_append(b, "ccode=%c%c", (val >> 8), (val & 0xff)); - } else if (flags & SRFL_PRHEX) { - varbuf_append(b, "%s=0x%x", name, val); - } else if ((flags & SRFL_PRSIGN) && (val & (1 << (width - 1)))) { - varbuf_append(b, "%s=%d", name, (int)(val | (~0 << width))); - } else { - varbuf_append(b, "%s=%u", name, val); - } - } - } - - if ((sromrev >= 4) && (sromrev != 16) && (sromrev != 18)) { - /* Do per-path variables */ - uint p, pb, psz, path_num; - - if ((sromrev == 17) || (sromrev == 15)) { - pb = psz = 0; - path_num = 0; - if (sromh) - sromh->is_caldata_prsnt = TRUE; - } else if (sromrev >= 13) { - pb = SROM13_PATH0; - psz = SROM13_PATH1 - SROM13_PATH0; - path_num = MAX_PATH_SROM_13; - } else if (sromrev >= 12) { - pb = SROM12_PATH0; - psz = SROM12_PATH1 - SROM12_PATH0; - path_num = MAX_PATH_SROM_12; - } else if (sromrev >= 11) { - pb = SROM11_PATH0; - psz = SROM11_PATH1 - SROM11_PATH0; - path_num = MAX_PATH_SROM_11; - } else if (sromrev >= 8) { - pb = SROM8_PATH0; - psz = SROM8_PATH1 - SROM8_PATH0; - path_num = MAX_PATH_SROM; - } else { - pb = SROM4_PATH0; - psz = SROM4_PATH1 - SROM4_PATH0; - path_num = MAX_PATH_SROM; - } - - for (p = 0; p < path_num; p++) { - for (srv = perpath_pci_sromvars; srv->name != NULL; srv ++) { - - if ((srv->revmask & sr) == 0) - continue; - - if (pb + srv->off < off) - continue; - - /* This entry is for mfgc only. Don't generate param for it, */ - if (srv->flags & SRFL_NOVAR) - continue; - - /* Start of an array */ - if (sromrev >= 10 && (srv->flags & SRFL_ARRAY) && !in_array) { - array_curr = 0; - array_name = (const char*)srv->name; - bzero((void*)array_temp, sizeof(array_temp)); - in_array = TRUE; - } - - w = srom[pb + srv->off - off]; - - ASSERT(mask_valid(srv->mask)); - val = (w & srv->mask) >> mask_shift(srv->mask); - width = mask_width(srv->mask); - - flags = srv->flags; - - /* Cheating: no per-path var is more than 1 word */ - - if ((srv->flags & SRFL_NOFFS) && ((int)val == (1 << width) - 1)) - continue; - - if (in_array) { - int ret; - - if (flags & SRFL_PRHEX) { - ret = snprintf(array_temp + array_curr, - sizeof(array_temp) - array_curr, "0x%x,", val); - } else if ((flags & SRFL_PRSIGN) && - (val & (1 << (width - 1)))) { - ret = snprintf(array_temp + array_curr, - sizeof(array_temp) - array_curr, "%d,", - (int)(val | (~0 << width))); - } else { - ret = snprintf(array_temp + array_curr, - sizeof(array_temp) - array_curr, "%u,", val); - } - - if (ret > 0) { - array_curr += ret; - } else { - BS_ERROR( - ("_initvars_srom_pci: array %s parsing error." - " buffer too short.\n", - array_name)); - ASSERT(0); - - /* buffer too small, skip this param */ - while (srv->flags & SRFL_ARRAY) - srv ++; - srv ++; - in_array = FALSE; - continue; - } - - if (!(srv->flags & SRFL_ARRAY)) { /* Array ends */ - /* Remove the last ',' */ - array_temp[array_curr-1] = '\0'; - in_array = FALSE; - varbuf_append(b, "%s%d=%s", - array_name, p, array_temp); - } - } else if (srv->flags & SRFL_PRHEX) - varbuf_append(b, "%s%d=0x%x", srv->name, p, val); - else - varbuf_append(b, "%s%d=%d", srv->name, p, val); - } - if (sromrev >= 13 && (p == (MAX_PATH_SROM_13 - 2))) { - psz = SROM13_PATH3 - SROM13_PATH2; - } - pb += psz; - } - } /* per path variables */ -} /* _initvars_srom_pci */ - -int -BCMATTACHFN(get_srom_pci_caldata_size)(uint32 sromrev) -{ - uint32 caldata_size; - - switch (sromrev) { - case 15: - caldata_size = (SROM15_CALDATA_WORDS * 2); - break; - case 17: - caldata_size = (SROM17_CALDATA_WORDS * 2); - break; - default: - caldata_size = 0; - break; - } - return caldata_size; -} - -uint32 -BCMATTACHFN(get_srom_size)(uint32 sromrev) -{ - uint32 size; - - switch (sromrev) { - case 15: - size = (SROM15_WORDS * 2); - break; - case 17: - size = (SROM17_WORDS * 2); - break; - default: - size = 0; - break; - } - return size; -} -#if defined(BCMPCIEDEV_SROM_FORMAT) && defined(WLC_TXCAL) - -int -BCMATTACHFN(_initvars_srom_pci_caldata)(si_t *sih, uint16 *srom, uint32 sromrev) -{ - int err = BCME_ERROR; - - if (sromh && (!sromh->is_caldata_prsnt)) { - return err; - } - - if (si_is_sprom_available(sih)) { - uint32 caldata_size; - - caldata_size = get_srom_pci_caldata_size(sromrev); - memcpy(srom, caldata_array, caldata_size); - err = BCME_OK; - } - return err; -} -#endif /* defined(BCMPCIEDEV_SROM_FORMAT) && defined(WLC_TXCAL) */ -/** - * Initialize nonvolatile variable table from sprom, or OTP when SPROM is not available, or - * optionally a set of 'defaultsromvars' (compiled-in) variables when both OTP and SPROM bear no - * contents. - * - * On success, a buffer containing var/val pairs is allocated and returned in params vars and count. - * - * Return 0 on success, nonzero on error. - */ -static int -BCMATTACHFN(initvars_srom_pci)(si_t *sih, volatile void *curmap, char **vars, uint *count) -{ - uint16 *srom; - volatile uint16 *sromwindow; - uint8 sromrev = 0; - uint32 sr; - varbuf_t b; - char *vp, *base = NULL; - osl_t *osh = si_osh(sih); - bool flash = FALSE; - int err = 0; -#if defined(BCMPCIEDEV_SROM_FORMAT) && defined(WLC_TXCAL) - uint16 cal_wordoffset; -#endif - - /* - * Apply CRC over SROM content regardless SROM is present or not, and use variable - * sromrev's existance in flash to decide if we should return an error when CRC - * fails or read SROM variables from flash. - */ - - /* freed in same function */ - srom = MALLOC_NOPERSIST(osh, SROM_MAX); - ASSERT(srom != NULL); - if (!srom) - return -2; - - sromwindow = (volatile uint16 *)srom_offset(sih, curmap); - if (si_is_sprom_available(sih)) { - err = sprom_read_pci(osh, sih, sromwindow, 0, srom, SROM_SIGN_MINWORDS + 1, FALSE); - if (err == 0) { - if (srom[SROM18_SIGN] == SROM18_SIGNATURE) { - err = sprom_read_pci(osh, sih, sromwindow, - 0, srom, SROM18_WORDS, TRUE); - sromrev = srom[SROM18_CRCREV] & 0xff; - } else if (srom[SROM17_SIGN] == SROM17_SIGNATURE) { - err = sprom_read_pci(osh, sih, sromwindow, - 0, srom, SROM17_WORDS, TRUE); - sromrev = srom[SROM17_CRCREV] & 0xff; - } else if (srom[SROM16_SIGN] == SROM16_SIGNATURE) { - err = sprom_read_pci(osh, sih, sromwindow, - 0, srom, SROM16_WORDS, TRUE); - sromrev = srom[SROM16_CRCREV] & 0xff; - } else if (srom[SROM15_SIGN] == SROM15_SIGNATURE) { /* srom 15 */ - err = sprom_read_pci(osh, sih, sromwindow, - 0, srom, SROM15_WORDS, TRUE); - sromrev = srom[SROM15_CRCREV] & 0xff; - } else if (srom[SROM11_SIGN] == SROM13_SIGNATURE) { - err = sprom_read_pci(osh, sih, sromwindow, - 0, srom, SROM13_WORDS, TRUE); - sromrev = srom[SROM13_CRCREV] & 0xff; - } else if (srom[SROM11_SIGN] == SROM12_SIGNATURE) { - err = sprom_read_pci(osh, sih, sromwindow, - 0, srom, SROM12_WORDS, TRUE); - sromrev = srom[SROM12_CRCREV] & 0xff; - } else if (srom[SROM11_SIGN] == SROM11_SIGNATURE) { - err = sprom_read_pci(osh, sih, sromwindow, - 0, srom, SROM11_WORDS, TRUE); - sromrev = srom[SROM11_CRCREV] & 0xff; - } else if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) || /* srom 4 */ - (srom[SROM8_SIGN] == SROM4_SIGNATURE)) { /* srom 8,9 */ - err = sprom_read_pci(osh, sih, sromwindow, - 0, srom, SROM4_WORDS, TRUE); - sromrev = srom[SROM4_CRCREV] & 0xff; - } else { - err = sprom_read_pci(osh, sih, sromwindow, 0, - srom, SROM_WORDS, TRUE); - if (err == 0) { - /* srom is good and is rev < 4 */ - /* top word of sprom contains version and crc8 */ - sromrev = srom[SROM_CRCREV] & 0xff; - /* bcm4401 sroms misprogrammed */ - if (sromrev == 0x10) - sromrev = 1; - } - } - if (err) - BS_ERROR(("srom read failed\n")); - } - else - BS_ERROR(("srom read failed\n")); - } - -#if defined(BCMNVRAMW) || defined(BCMNVRAMR) - /* Use OTP if SPROM not available */ - else if ((err = otp_read_pci(osh, sih, srom, SROM_MAX)) == 0) { - /* OTP only contain SROM rev8/rev9/rev10/Rev11 for now */ - - if (srom[SROM13_SIGN] == SROM13_SIGNATURE) - sromrev = srom[SROM13_CRCREV] & 0xff; - else if (srom[SROM12_SIGN] == SROM12_SIGNATURE) - sromrev = srom[SROM12_CRCREV] & 0xff; - else if (srom[SROM11_SIGN] == SROM11_SIGNATURE) - sromrev = srom[SROM11_CRCREV] & 0xff; - else if (srom[SROM10_SIGN] == SROM10_SIGNATURE) - sromrev = srom[SROM10_CRCREV] & 0xff; - else - sromrev = srom[SROM4_CRCREV] & 0xff; - } -#endif /* defined(BCMNVRAMW) || defined(BCMNVRAMR) */ - else { - err = 1; - BS_ERROR(("Neither SPROM nor OTP has valid image\n")); - } - - BS_ERROR(("srom rev:%d\n", sromrev)); - - /* We want internal/wltest driver to come up with default sromvars so we can - * program a blank SPROM/OTP. - */ - if (err || sromrev == 0) { - char *value; -#if defined(BCMHOSTVARS) - uint32 val; -#endif - - if ((value = si_getdevpathvar(sih, "sromrev"))) { - sromrev = (uint8)bcm_strtoul(value, NULL, 0); - flash = TRUE; - goto varscont; - } - - BS_ERROR(("initvars_srom_pci, SROM CRC Error\n")); - -#if !defined(DONGLEBUILD) || defined(BCMPCIEDEV_SROM_FORMAT) - /* NIC build or PCIe FD using SROM format shouldn't load driver - * default when external nvram exists. - */ - if ((value = getvar(NULL, "sromrev"))) { - BS_ERROR(("initvars_srom_pci, Using external nvram\n")); - err = 0; - goto errout; - } -#endif /* !DONGLEBUILD || BCMPCIEDEV_SROM_FORMAT */ - -#if defined(BCMHOSTVARS) - /* - * CRC failed on srom, so if the device is using OTP - * and if OTP is not programmed use the default variables. - * for 4311 A1 there is no signature to indicate that OTP is - * programmed, so can't really verify the OTP is unprogrammed - * or a bad OTP. - */ - val = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); - if ((si_is_sprom_available(sih) && srom[0] == 0xffff) || -#ifdef BCMQT - (si_is_sprom_available(sih) && sromrev == 0) || -#endif - (val & SPROM_OTPIN_USE)) { - vp = base = mfgsromvars; - - /* For windows internal/wltest driver, a .nvm file with default - * nvram parameters is downloaded from the file system (in src/wl/sys: - * wl_readconfigdata()). - * Only when we cannot download default vars from the file system, use - * defaultsromvars_wltest as default - */ - if (defvarslen == 0) { - BS_ERROR(("No nvm file, use generic default (for programming" - " SPROM/OTP only)\n")); - - if (BCM43602_CHIP(sih->chip)) { - defvarslen = srom_vars_len(defaultsromvars_43602); - bcopy(defaultsromvars_43602, vp, defvarslen); - } else if ((CHIPID(sih->chip) == BCM4360_CHIP_ID) || - (CHIPID(sih->chip) == BCM4352_CHIP_ID)) { - defvarslen = srom_vars_len(defaultsromvars_4360); - bcopy(defaultsromvars_4360, vp, defvarslen); - } else if (BCM4378_CHIP(sih->chip)) { - defvarslen = srom_vars_len(defaultsromvars_4378); - bcopy(defaultsromvars_4378, vp, defvarslen); - } else if (BCM4387_CHIP(sih->chip)) { - defvarslen = srom_vars_len(defaultsromvars_4387); - bcopy(defaultsromvars_4387, vp, defvarslen); - } else { - defvarslen = srom_vars_len(defaultsromvars_wltest); - bcopy(defaultsromvars_wltest, vp, defvarslen); - } - } else { - BS_ERROR(("Use nvm file as default\n")); - } - - vp += defvarslen; - /* add final null terminator */ - *vp++ = '\0'; - - BS_ERROR(("Used %d bytes of defaultsromvars\n", defvarslen)); - goto varsdone; - - } else if ((CHIPID(sih->chip) == BCM4360_CHIP_ID) || - (CHIPID(sih->chip) == BCM43460_CHIP_ID) || - (CHIPID(sih->chip) == BCM4352_CHIP_ID) || - BCM43602_CHIP(sih->chip)) { - - base = vp = mfgsromvars; - - if ((CHIPID(sih->chip) == BCM4360_CHIP_ID) || - (CHIPID(sih->chip) == BCM43460_CHIP_ID) || - (CHIPID(sih->chip) == BCM4352_CHIP_ID) || - BCM43602_CHIP(sih->chip)) - BS_ERROR(("4360 BOOT w/o SPROM or OTP\n")); - else - BS_ERROR(("BOOT w/o SPROM or OTP\n")); - - if (defvarslen == 0) { - if (BCM43602_CHIP(sih->chip)) { - defvarslen = srom_vars_len(defaultsromvars_43602); - bcopy(defaultsromvars_43602, vp, defvarslen); - } else if ((sih->chip == BCM4360_CHIP_ID) || - (sih->chip == BCM4352_CHIP_ID)) { - defvarslen = srom_vars_len(defaultsromvars_4360); - bcopy(defaultsromvars_4360, vp, defvarslen); - } else { - defvarslen = srom_vars_len(defaultsromvars_4331); - bcopy(defaultsromvars_4331, vp, defvarslen); - } - } - vp += defvarslen; - *vp++ = '\0'; - goto varsdone; - } else -#endif /* defined(BCMHOSTVARS) */ - { - err = -1; - goto errout; - } - } -#if defined(BCM_ONE_NVRAM_SRC) - /* Discard hostvars if SROM parsing is successful, so only one nvram source - * will be used. - * Routers use combined srom/host nvram so shouldn't define BCM_ONE_NVRAM_SRC. - */ - else { - nvram_exit((void *)sih); /* free up global vars */ - } -#endif /* BCM_ONE_NVRAM_SRC */ - -varscont: - /* Bitmask for the sromrev */ - sr = 1 << sromrev; - - /* srom version check: Current valid versions are: - * 1-5, 8-11, 12, 13, 15, 16, 17, 18 SROM_MAXREV - * This is a bit mask of all valid SROM versions. - */ - if ((sr & 0x7bf3e) == 0) { - BS_ERROR(("Invalid SROM rev %d\n", sromrev)); - err = -2; - goto errout; - } - - ASSERT(vars != NULL); - ASSERT(count != NULL); - -#if defined(BCMPCIEDEV_SROM_FORMAT) && defined(WLC_TXCAL) - srom_sromrev = sromrev; -#endif /* defined(BCMPCIEDEV_SROM_FORMAT) && defined(WLC_TXCAL) */ - - /* freed in same function */ - base = vp = MALLOC_NOPERSIST(osh, MAXSZ_NVRAM_VARS); - ASSERT(vp != NULL); - if (!vp) { - err = -2; - goto errout; - } - - /* read variables from flash */ - if (flash) { - if ((err = initvars_flash(sih, osh, &vp, MAXSZ_NVRAM_VARS))) - goto errout; - goto varsdone; - } - - varbuf_init(&b, base, MAXSZ_NVRAM_VARS); - - /* parse SROM into name=value pairs. */ - _initvars_srom_pci(sromrev, srom, 0, &b); - - /* final nullbyte terminator */ - ASSERT(b.size >= 1); - vp = b.buf; - *vp++ = '\0'; - - ASSERT((vp - base) <= MAXSZ_NVRAM_VARS); - -varsdone: - err = initvars_table(osh, base, vp, vars, count); /* allocates buffer in 'vars' */ - -#if defined(BCMPCIEDEV_SROM_FORMAT) && defined(WLC_TXCAL) - if (sromrev == 18) { - int caldata_wordoffset = srom[SROM18_CALDATA_OFFSET_LOC] / 2; - - if ((caldata_wordoffset != 0) && - (caldata_wordoffset + SROM_CALDATA_WORDS < SROM18_WORDS)) { - memcpy(caldata_array, srom + caldata_wordoffset, SROM18_CALDATA_WORDS * 2); - is_caldata_prsnt = TRUE; - } - } else if (sromrev == 16) { - int caldata_wordoffset = srom[SROM16_CALDATA_OFFSET_LOC] / 2; - - if ((caldata_wordoffset != 0) && - (caldata_wordoffset + SROM_CALDATA_WORDS < SROM16_WORDS)) { - memcpy(caldata_array, srom + caldata_wordoffset, SROM_CALDATA_WORDS * 2); - is_caldata_prsnt = TRUE; - } - } -#endif /* defined(BCMPCIEDEV_SROM_FORMAT) && defined(WLC_TXCAL) */ - -#ifdef NVSRCX - if (sromrev != 0) - nvram_append((void *)sih, *vars, *count, VARBUF_PRIO_SROM); -#endif -#if defined(BCMPCIEDEV_SROM_FORMAT) && defined(WLC_TXCAL) - if ((sromrev == 15) || (sromrev == 17)) { - uint32 caldata_size = get_srom_pci_caldata_size(sromrev); - - cal_wordoffset = getintvar(NULL, "caldata_offset")/2; - memcpy(caldata_array, srom + cal_wordoffset, caldata_size); - } -#endif -errout: -#if defined(BCMHOSTVARS) - if (base && (base != mfgsromvars)) -#else - if (base) -#endif /* defined(BCMHOSTVARS) */ - MFREE(osh, base, MAXSZ_NVRAM_VARS); - - MFREE(osh, srom, SROM_MAX); - return err; -} - -/** - * initvars_cis_pci() parses OTP CIS. This is specifically for PCIe full dongle that has SROM - * header plus CIS tuples programmed in OTP. - * Return error if the content is not in CIS format or OTP is not present. - */ -static int -BCMATTACHFN(initvars_cis_pci)(si_t *sih, osl_t *osh, volatile void *curmap, - char **vars, uint *count) -{ - uint wsz = 0, sz = 0, base_len = 0; - void *oh = NULL; - int rc = BCME_OK; - uint16 *cisbuf = NULL; - uint8 *cis = NULL; -#if defined (BCMHOSTVARS) - char *vp = NULL; -#endif /* BCMHOSTVARS */ - char *base = NULL; - bool wasup; - uint32 min_res_mask = 0; - BCM_REFERENCE(curmap); - - /* Bail out if we've dealt with OTP/SPROM before! */ - if (srvars_inited) - goto exit; - - /* Turn on OTP if it's not already on */ - if (!(wasup = si_is_otp_powered(sih))) - si_otp_power(sih, TRUE, &min_res_mask); - - if (si_cis_source(sih) != CIS_OTP) - rc = BCME_NOTFOUND; - else if ((oh = otp_init(sih)) == NULL) - rc = BCME_ERROR; - else if (!(((BUSCORETYPE(sih->buscoretype) == PCIE2_CORE_ID) || otp_newcis(oh)) && - (otp_status(oh) & OTPS_GUP_HW))) { - /* OTP bit CIS format (507) not used by pcie core - only needed for sdio core */ - rc = BCME_NOTFOUND; - } else if ((sz = otp_size(oh)) != 0) { - if ((cisbuf = (uint16*)MALLOC_NOPERSIST(osh, sz))) { - /* otp_size() returns bytes, not words. */ - wsz = sz >> 1; - /* for 4389b0 (CCREV-70) sw region is before the hw region */ - if (CCREV(sih->ccrev) == 70) { - rc = otp_read_region(sih, OTP_SW_RGN, cisbuf, &wsz); - cis = (uint8*)cisbuf; - } else { - rc = otp_read_region(sih, OTP_HW_RGN, cisbuf, &wsz); - /* Bypass the HW header and signature */ - cis = (uint8*)(cisbuf + (otp_pcie_hwhdr_sz(sih) / 2)); - } - BS_ERROR(("initvars_cis_pci: Parsing CIS in OTP.\n")); - } else - rc = BCME_NOMEM; - } - - /* Restore original OTP state */ - if (!wasup) - si_otp_power(sih, FALSE, &min_res_mask); - - if (rc != BCME_OK) { - BS_ERROR(("initvars_cis_pci: Not CIS format\n")); - goto exit; - } - -#if defined (BCMHOSTVARS) - if (defvarslen) { - vp = mfgsromvars; - vp += defvarslen; - - /* allocates buffer in 'vars' */ - rc = initvars_table(osh, mfgsromvars, vp, &base, &base_len); - if (rc) - goto exit; - - *vars = base; - *count = base_len; - - BS_ERROR(("initvars_cis_pci external nvram %d bytes\n", defvarslen)); - } - -#endif /* BCMHOSTVARS */ - - /* Parse the CIS and allocate a(nother) buffer in 'vars' */ - rc = srom_parsecis(sih, osh, &cis, SROM_CIS_SINGLE, vars, count); - - srvars_inited = TRUE; -exit: - /* Clean up */ - if (base) - MFREE(osh, base, base_len); - if (cisbuf) - MFREE(osh, cisbuf, sz); - - /* return OK so the driver will load & use defaults if bad srom/otp */ - return rc; -} -#endif /* !defined(BCMDONGLEHOST) */ - -#ifdef BCMSDIO -#if !defined(BCMDONGLEHOST) -/** - * Read the SDIO cis and call parsecis to allocate and initialize the NVRAM vars buffer. - * Return 0 on success, nonzero on error. - */ -static int -BCMATTACHFN(initvars_cis_sdio)(si_t *sih, osl_t *osh, char **vars, uint *count) -{ - uint8 *cis[SBSDIO_NUM_FUNCTION + 1]; - uint fn, numfn; - int rc = 0; - - /* Using MALLOC here causes the Windows driver to crash Needs Investigating */ -#ifdef NDIS - uint8 cisd[SBSDIO_NUM_FUNCTION + 1][SBSDIO_CIS_SIZE_LIMIT]; -#endif - - numfn = bcmsdh_query_iofnum(NULL); - ASSERT(numfn <= SDIOD_MAX_IOFUNCS); - - for (fn = 0; fn <= numfn; fn++) { -#ifdef NDIS - cis[fn] = (uint8*)cisd[fn]; -#else - /* freed in same function */ - if ((cis[fn] = MALLOC_NOPERSIST(osh, SBSDIO_CIS_SIZE_LIMIT)) == NULL) { - rc = -1; - break; - } -#endif /* NDIS */ - - bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT); - - if (bcmsdh_cis_read(NULL, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT) != 0) { -#ifdef NDIS - /* nothing to do */ -#else - MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); -#endif - rc = -2; - break; - } - } - - if (!rc) - rc = srom_parsecis(sih, osh, cis, fn, vars, count); - -#ifdef NDIS - /* nothing to do here */ -#else - while (fn-- > 0) - MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); -#endif - - return (rc); -} -#endif /* !defined(BCMDONGLEHOST) */ - -/** set SDIO sprom command register */ -static int -BCMATTACHFN(sprom_cmd_sdio)(osl_t *osh, uint8 cmd) -{ - uint8 status = 0; - uint wait_cnt = 1000; - - /* write sprom command register */ - bcmsdh_cfg_write(NULL, SDIO_FUNC_1, SBSDIO_SPROM_CS, cmd, NULL); - - /* wait status */ - while (wait_cnt--) { - status = bcmsdh_cfg_read(NULL, SDIO_FUNC_1, SBSDIO_SPROM_CS, NULL); - if (status & SBSDIO_SPROM_DONE) - return 0; - } - - return 1; -} - -/** read a word from the SDIO srom */ -static int -sprom_read_sdio(osl_t *osh, uint16 addr, uint16 *data) -{ - uint8 addr_l, addr_h, data_l, data_h; - - addr_l = (uint8)((addr * 2) & 0xff); - addr_h = (uint8)(((addr * 2) >> 8) & 0xff); - - /* set address */ - bcmsdh_cfg_write(NULL, SDIO_FUNC_1, SBSDIO_SPROM_ADDR_HIGH, addr_h, NULL); - bcmsdh_cfg_write(NULL, SDIO_FUNC_1, SBSDIO_SPROM_ADDR_LOW, addr_l, NULL); - - /* do read */ - if (sprom_cmd_sdio(osh, SBSDIO_SPROM_READ)) - return 1; - - /* read data */ - data_h = bcmsdh_cfg_read(NULL, SDIO_FUNC_1, SBSDIO_SPROM_DATA_HIGH, NULL); - data_l = bcmsdh_cfg_read(NULL, SDIO_FUNC_1, SBSDIO_SPROM_DATA_LOW, NULL); - - *data = (data_h << 8) | data_l; - return 0; -} - -#if defined(WLTEST) || defined (DHD_SPROM) || defined (BCMDBG) -/** write a word to the SDIO srom */ -static int -sprom_write_sdio(osl_t *osh, uint16 addr, uint16 data) -{ - uint8 addr_l, addr_h, data_l, data_h; - - addr_l = (uint8)((addr * 2) & 0xff); - addr_h = (uint8)(((addr * 2) >> 8) & 0xff); - data_l = (uint8)(data & 0xff); - data_h = (uint8)((data >> 8) & 0xff); - - /* set address */ - bcmsdh_cfg_write(NULL, SDIO_FUNC_1, SBSDIO_SPROM_ADDR_HIGH, addr_h, NULL); - bcmsdh_cfg_write(NULL, SDIO_FUNC_1, SBSDIO_SPROM_ADDR_LOW, addr_l, NULL); - - /* write data */ - bcmsdh_cfg_write(NULL, SDIO_FUNC_1, SBSDIO_SPROM_DATA_HIGH, data_h, NULL); - bcmsdh_cfg_write(NULL, SDIO_FUNC_1, SBSDIO_SPROM_DATA_LOW, data_l, NULL); - - /* do write */ - return sprom_cmd_sdio(osh, SBSDIO_SPROM_WRITE); -} -#endif /* defined(WLTEST) || defined (DHD_SPROM) || defined (BCMDBG) */ -#endif /* BCMSDIO */ - -#if !defined(BCMDONGLEHOST) -#ifdef BCMSPI -/** - * Read the SPI cis and call parsecis to allocate and initialize the NVRAM vars buffer. - * Return 0 on success, nonzero on error. - */ -static int -BCMATTACHFN(initvars_cis_spi)(si_t *sih, osl_t *osh, char **vars, uint *count) -{ - uint8 *cis; - int rc; - - /* Using MALLOC here causes the Windows driver to crash Needs Investigating */ -#ifdef NDIS - uint8 cisd[SBSDIO_CIS_SIZE_LIMIT]; - cis = (uint8*)cisd; -#else - /* freed in same function */ - if ((cis = MALLOC_NOPERSIST(osh, SBSDIO_CIS_SIZE_LIMIT)) == NULL) { - return -1; - } -#endif /* NDIS */ - - bzero(cis, SBSDIO_CIS_SIZE_LIMIT); - - if (bcmsdh_cis_read(NULL, SDIO_FUNC_1, cis, SBSDIO_CIS_SIZE_LIMIT) != 0) { -#ifdef NDIS - /* nothing to do */ -#else - MFREE(osh, cis, SBSDIO_CIS_SIZE_LIMIT); -#endif /* NDIS */ - return -2; - } - - rc = srom_parsecis(sih, osh, &cis, SDIO_FUNC_1, vars, count); - -#ifdef NDIS - /* nothing to do here */ -#else - MFREE(osh, cis, SBSDIO_CIS_SIZE_LIMIT); -#endif - - return (rc); -} -#endif /* BCMSPI */ -#endif /* !defined(BCMDONGLEHOST) */ - -/** Return sprom size in 16-bit words */ -uint -srom_size(si_t *sih, osl_t *osh) -{ - uint size = (SROM16_SIGN + 1) * 2; /* must big enough for SROM16 */ - return size; -} - -/** - * initvars are different for BCMUSBDEV and BCMSDIODEV. This is OK when supporting both at - * the same time, but only because all of the code is in attach functions and not in ROM. - */ - -#if defined(BCMUSBDEV_ENABLED) -#ifdef BCM_DONGLEVARS -/*** reads a CIS structure (so not an SROM-MAP structure) from either OTP or SROM */ -static int -BCMATTACHFN(initvars_srom_si_bl)(si_t *sih, osl_t *osh, volatile void *curmap, - char **vars, uint *varsz) -{ - int sel = 0; /* where to read srom/cis: 0 - none, 1 - otp, 2 - sprom */ - uint sz = 0; /* srom size in bytes */ - void *oh = NULL; - int rc = BCME_OK; - uint16 prio = VARBUF_PRIO_INVALID; - - if ((oh = otp_init(sih)) != NULL && (otp_status(oh) & OTPS_GUP_SW)) { - /* Access OTP if it is present, powered on, and programmed */ - sz = otp_size(oh); - sel = 1; - } else if ((sz = srom_size(sih, osh)) != 0) { - /* Access the SPROM if it is present */ - sz <<= 1; - sel = 2; - } - - /* Read CIS in OTP/SPROM */ - if (sel != 0) { - uint16 *srom; - uint8 *body = NULL; - uint otpsz = sz; - - ASSERT(sz); - - /* Allocate memory */ - if ((srom = (uint16 *)MALLOC(osh, sz)) == NULL) - return BCME_NOMEM; - - /* Read CIS */ - switch (sel) { - case 1: - rc = otp_read_region(sih, OTP_SW_RGN, srom, &otpsz); - sz = otpsz; - body = (uint8 *)srom; - prio = VARBUF_PRIO_OTP; - break; - case 2: - rc = srom_read(sih, SI_BUS, curmap, osh, 0, sz, srom, TRUE); - /* sprom has 8 byte h/w header */ - body = (uint8 *)srom + SBSDIO_SPROM_CIS_OFFSET; - prio = VARBUF_PRIO_SROM; - break; - default: - /* impossible to come here */ - ASSERT(0); - break; - } - - /* Parse CIS */ - if (rc == BCME_OK) { - /* each word is in host endian */ - htol16_buf((uint8 *)srom, sz); - ASSERT(body); - rc = srom_parsecis(sih, osh, &body, SROM_CIS_SINGLE, vars, varsz); - } - - MFREE(osh, srom, sz); /* Clean up */ - - /* Make SROM variables global */ - if (rc == BCME_OK) { - nvram_append((void *)sih, *vars, *varsz, prio); - DONGLE_STORE_VARS_OTP_PTR(*vars); - } - } - - return BCME_OK; -} -#endif /* #ifdef BCM_DONGLEVARS */ - -/** - * initvars_srom_si() is defined multiple times in this file. This is the 1st variant for chips with - * an active USB interface. It is called only for bus types SI_BUS, and only for CIS - * format in SPROM and/or OTP. Reads OTP or SPROM (bootloader only) and appends parsed contents to - * caller supplied var/value pairs. - */ -static int -BCMATTACHFN(initvars_srom_si)(si_t *sih, osl_t *osh, volatile void *curmap, - char **vars, uint *varsz) -{ - -#if defined(BCM_DONGLEVARS) - BCM_REFERENCE(osh); - BCM_REFERENCE(sih); - BCM_REFERENCE(curmap); -#endif - - /* Bail out if we've dealt with OTP/SPROM before! */ - if (srvars_inited) - goto exit; - -#ifdef BCM_DONGLEVARS /* this flag should be defined for usb bootloader, to read OTP or SROM */ - if (BCME_OK != initvars_srom_si_bl(sih, osh, curmap, vars, varsz)) /* CIS format only */ - return BCME_ERROR; -#endif - - /* update static local var to skip for next call */ - srvars_inited = TRUE; - -exit: - /* Tell the caller there is no individual SROM variables */ - *vars = NULL; - *varsz = 0; - - /* return OK so the driver will load & use defaults if bad srom/otp */ - return BCME_OK; -} - -#elif defined(BCMSDIODEV_ENABLED) - -#ifdef BCM_DONGLEVARS -static uint8 BCMATTACHDATA(defcis4369)[] = { 0x20, 0x4, 0xd0, 0x2, 0x64, 0x43, 0xff, 0xff }; -static uint8 BCMATTACHDATA(defcis43012)[] = { 0x20, 0x4, 0xd0, 0x2, 0x04, 0xA8, 0xff, 0xff }; -static uint8 BCMATTACHDATA(defcis43013)[] = { 0x20, 0x4, 0xd0, 0x2, 0x05, 0xA8, 0xff, 0xff }; -static uint8 BCMATTACHDATA(defcis43014)[] = { 0x20, 0x4, 0xd0, 0x2, 0x06, 0xA8, 0xff, 0xff }; -static uint8 BCMATTACHDATA(defcis4362)[] = { 0x20, 0x4, 0xd0, 0x2, 0x62, 0x43, 0xff, 0xff }; -static uint8 BCMATTACHDATA(defcis4378)[] = { 0x20, 0x4, 0xd0, 0x2, 0x78, 0x43, 0xff, 0xff }; -static uint8 BCMATTACHDATA(defcis4385)[] = { 0x20, 0x4, 0xd0, 0x2, 0x85, 0x43, 0xff, 0xff }; -static uint8 BCMATTACHDATA(defcis4387)[] = { 0x20, 0x4, 0xd0, 0x2, 0x78, 0x43, 0xff, 0xff }; -static uint8 BCMATTACHDATA(defcis4388)[] = { 0x20, 0x4, 0xd0, 0x2, 0x88, 0x43, 0xff, 0xff }; -static uint8 BCMATTACHDATA(defcis4389)[] = { 0x20, 0x4, 0xd0, 0x2, 0x89, 0x43, 0xff, 0xff }; -static uint8 BCMATTACHDATA(defcis4397)[] = { 0x20, 0x4, 0xd0, 0x2, 0x97, 0x43, 0xff, 0xff }; - -/** - * initvars_srom_si() is defined multiple times in this file. This is the 2nd variant for chips with - * an active SDIOd interface using DONGLEVARS - */ -static int -BCMATTACHFN(initvars_srom_si)(si_t *sih, osl_t *osh, volatile void *curmap, - char **vars, uint *varsz) -{ - int cis_src; - uint msz = 0; - uint sz = 0; - void *oh = NULL; - int rc = BCME_OK; - bool new_cisformat = FALSE; - - uint16 *cisbuf = NULL; - - /* # sdiod fns + common + extra */ - uint8 *cis[SBSDIO_NUM_FUNCTION + 2] = { 0 }; - - uint ciss = 0; - uint8 *defcis; - uint hdrsz; - uint16 prio = VARBUF_PRIO_INVALID; - -#if defined(BCMSDIODEV_ENABLED) && defined(ATE_BUILD) - if (si_chipcap_sdio_ate_only(sih)) { - BS_ERROR(("ATE BUILD: skip cis based var init\n")); - goto exit; - } -#endif /* BCMSDIODEV_ENABLED && ATE_BUILD */ - - /* Bail out if we've dealt with OTP/SPROM before! */ - if (srvars_inited) - goto exit; - - /* Initialize default and cis format count */ - switch (CHIPID(sih->chip)) { - case BCM4369_CHIP_GRPID: ciss = 1; defcis = defcis4369; hdrsz = 4; break; - case BCM4378_CHIP_GRPID: ciss = 1; defcis = defcis4378; hdrsz = 4; break; - case BCM4385_CHIP_GRPID: ciss = 1; defcis = defcis4385; hdrsz = 4; break; - case BCM4387_CHIP_GRPID: ciss = 1; defcis = defcis4387; hdrsz = 4; break; - case BCM4388_CHIP_GRPID: ciss = 1; defcis = defcis4388; hdrsz = 4; break; - case BCM4389_CHIP_GRPID: ciss = 1; defcis = defcis4389; hdrsz = 4; break; - case BCM4397_CHIP_GRPID: ciss = 1; defcis = defcis4397; hdrsz = 4; break; - case BCM43012_CHIP_ID: ciss = 1; defcis = defcis43012; hdrsz = 4; break; - case BCM43013_CHIP_ID: ciss = 1; defcis = defcis43013; hdrsz = 4; break; - case BCM43014_CHIP_ID: ciss = 1; defcis = defcis43014; hdrsz = 4; break; - case BCM4362_CHIP_GRPID: ciss = 1; defcis = defcis4362; hdrsz = 4; break; - default: - BS_ERROR(("initvars_srom_si: Unknown chip 0x%04x\n", CHIPID(sih->chip))); - return BCME_ERROR; - } - if (sih->ccrev >= 36) { - uint32 otplayout; - if (AOB_ENAB(sih)) { - otplayout = si_corereg(sih, si_findcoreidx(sih, GCI_CORE_ID, 0), - OFFSETOF(gciregs_t, otplayout), 0, 0); - } else { - otplayout = si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, otplayout), - 0, 0); - } - if (otplayout & OTP_CISFORMAT_NEW) { - ciss = 1; - hdrsz = 2; - new_cisformat = TRUE; - } - else { - ciss = 3; - hdrsz = 12; - } - } - - cis_src = si_cis_source(sih); - switch (cis_src) { - case CIS_SROM: - sz = srom_size(sih, osh) << 1; - prio = VARBUF_PRIO_SROM; - break; - case CIS_OTP: - /* Note that for *this* type of OTP -- which otp_read_region() - * can operate on -- otp_size() returns bytes, not words. - */ - if (((oh = otp_init(sih)) != NULL) && (otp_status(oh) & OTPS_GUP_HW)) - sz = otp_size(oh); - prio = VARBUF_PRIO_OTP; - break; - } - - if (sz != 0) { - /* freed in same function */ - if ((cisbuf = (uint16*)MALLOC_NOPERSIST(osh, sz)) == NULL) - return BCME_NOMEM; - msz = sz; - - switch (cis_src) { - case CIS_SROM: - rc = srom_read(sih, SI_BUS, curmap, osh, 0, sz, cisbuf, FALSE); - break; - case CIS_OTP: - sz >>= 1; - rc = otp_read_region(sih, OTP_HW_RGN, cisbuf, &sz); - sz <<= 1; - break; - } - - ASSERT(sz > hdrsz); - if (rc == BCME_OK) { - if ((cisbuf[0] == 0xffff) || (cisbuf[0] == 0)) { - MFREE(osh, cisbuf, msz); - } else if (new_cisformat) { - cis[0] = (uint8*)(cisbuf + hdrsz); - } else { - cis[0] = (uint8*)cisbuf + hdrsz; - cis[1] = (uint8*)cisbuf + hdrsz + - (cisbuf[1] >> 8) + ((cisbuf[2] & 0x00ff) << 8) - - SBSDIO_CIS_BASE_COMMON; - cis[2] = (uint8*)cisbuf + hdrsz + - cisbuf[3] - SBSDIO_CIS_BASE_COMMON; - cis[3] = (uint8*)cisbuf + hdrsz + - cisbuf[4] - SBSDIO_CIS_BASE_COMMON; - ASSERT((cis[1] >= cis[0]) && (cis[1] < (uint8*)cisbuf + sz)); - ASSERT((cis[2] >= cis[0]) && (cis[2] < (uint8*)cisbuf + sz)); - ASSERT(((cis[3] >= cis[0]) && (cis[3] < (uint8*)cisbuf + sz)) || - (ciss <= 3)); - } - } - } - - /* Use default if strapped to, or strapped source empty */ - if (cisbuf == NULL) { - ciss = 1; - cis[0] = defcis; - } - - /* Parse the CIS */ - if (rc == BCME_OK) { - if ((rc = srom_parsecis(sih, osh, cis, ciss, vars, varsz)) == BCME_OK) { - nvram_append((void *)sih, *vars, *varsz, prio); - DONGLE_STORE_VARS_OTP_PTR(*vars); - } - } - - /* Clean up */ - if (cisbuf != NULL) - MFREE(osh, cisbuf, msz); - - srvars_inited = TRUE; -exit: - /* Tell the caller there is no individual SROM variables */ - *vars = NULL; - *varsz = 0; - - /* return OK so the driver will load & use defaults if bad srom/otp */ - return BCME_OK; -} /* initvars_srom_si */ -#else /* BCM_DONGLEVARS */ - -/** - * initvars_srom_si() is defined multiple times in this file. This is the variant for chips with an - * active SDIOd interface but without BCM_DONGLEVARS - */ -static int -BCMATTACHFN(initvars_srom_si)(si_t *sih, osl_t *osh, volatile void *curmap, - char **vars, uint *varsz) -{ - *vars = NULL; - *varsz = 0; - return BCME_OK; -} -#endif /* BCM_DONGLEVARS */ - -#elif defined(BCMPCIEDEV_ENABLED) - -/** - * initvars_srom_si() is defined multiple times in this file. This is the variant for chips with an - * active PCIe interface *and* that use OTP for NVRAM storage. - * - * On success, a buffer containing var/val values has been allocated in parameter 'vars'. - * put an ifdef where if the host wants the dongle wants to parse sprom or not - */ -static int -BCMATTACHFN(initvars_srom_si)(si_t *sih, osl_t *osh, volatile void *curmap, - char **vars, uint *varsz) -{ -#ifdef BCM_DONGLEVARS - void *oh = NULL; - uint8 *cis; - uint sz = 0; - int rc; - - if (si_cis_source(sih) != CIS_OTP) - return BCME_OK; - - if (((oh = otp_init(sih)) != NULL) && (otp_status(oh) & OTPS_GUP_HW)) - sz = otp_size(oh); - if (sz == 0) - return BCME_OK; - - if ((cis = MALLOC(osh, sz)) == NULL) - return BCME_NOMEM; - sz >>= 1; - rc = otp_read_region(sih, OTP_HW_RGN, (uint16 *)cis, &sz); - sz <<= 1; - - /* account for the Hardware header */ - if (sz == 128) - return BCME_OK; - - cis += 128; - - /* need to find a better way to identify sprom format content and ignore parse */ - if (*(uint16 *)cis == SROM11_SIGNATURE) { - return BCME_OK; - } - - if ((rc = srom_parsecis(sih, osh, &cis, SROM_CIS_SINGLE, vars, varsz)) == BCME_OK) - nvram_append((void *)sih, *vars, *varsz, VARBUF_PRIO_OTP); - - return rc; -#else /* BCM_DONGLEVARS */ - *vars = NULL; - *varsz = 0; - return BCME_OK; -#endif /* BCM_DONGLEVARS */ -} -#else /* !BCMUSBDEV && !BCMSDIODEV && !BCMPCIEDEV */ - -#ifndef BCMDONGLEHOST - -/** - * initvars_srom_si() is defined multiple times in this file. This is the variant for: - * !BCMDONGLEHOST && !BCMUSBDEV && !BCMSDIODEV && !BCMPCIEDEV - * So this function is defined for PCI (not PCIe) builds that are also non DHD builds. - * On success, a buffer containing var/val values has been allocated in parameter 'vars'. - */ -static int -BCMATTACHFN(initvars_srom_si)(si_t *sih, osl_t *osh, volatile void *curmap, - char **vars, uint *varsz) -{ - /* Search flash nvram section for srom variables */ - BCM_REFERENCE(osh); - BCM_REFERENCE(curmap); - return initvars_flash_si(sih, vars, varsz); -} /* initvars_srom_si */ -#endif /* !BCMDONGLEHOST */ -#endif /* !BCMUSBDEV && !BCMSDIODEV && !BCMPCIEDEV */ - -void -BCMATTACHFN(srom_var_deinit)(si_t *sih) -{ - BCM_REFERENCE(sih); - - srvars_inited = FALSE; -} - -#if defined(BCMPCIEDEV_SROM_FORMAT) && defined(WLC_TXCAL) -bool -BCMATTACHFN(srom_caldata_prsnt)(si_t *sih) -{ - return is_caldata_prsnt; -} - -int -BCMATTACHFN(srom_get_caldata)(si_t *sih, uint16 *srom) -{ - if (!is_caldata_prsnt) { - return BCME_ERROR; - } - if (srom_sromrev == 18) { - memcpy(srom, caldata_array, SROM18_CALDATA_WORDS * 2); - } else { - memcpy(srom, caldata_array, SROM_CALDATA_WORDS * 2); - } - return BCME_OK; -} -#endif /* defined(BCMPCIEDEV_SROM_FORMAT) && defined(WLC_TXCAL) */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmstdlib.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmstdlib.c deleted file mode 100755 index 9e4f3a66121b..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmstdlib.c +++ /dev/null @@ -1,1251 +0,0 @@ -/* - * stdlib support routines for self-contained images. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -/* - * bcmstdlib.c file should be used only to construct an OSL or alone without any OSL - * It should not be used with any orbitarary OSL's as there could be a conflict - * with some of the routines defined here. - */ - -/* - * Define BCMSTDLIB_WIN32_APP if this is a Win32 Application compile - */ -#if defined(_WIN32) && !defined(NDIS) && !defined(EFI) -#define BCMSTDLIB_WIN32_APP 1 -#endif /* _WIN32 && !NDIS */ - -/* - * Define BCMSTDLIB_SNPRINTF_ONLY if we only want snprintf & vsnprintf implementations - */ -#if defined(_WIN32) && !defined(EFI) -#define BCMSTDLIB_SNPRINTF_ONLY 1 -#endif /* _WIN32 || !EFI */ - -#include -#ifdef BCMSTDLIB_WIN32_APP -/* for size_t definition */ -#include -#endif -#include -#ifndef BCMSTDLIB_WIN32_APP -#include -#endif -#include - -/* Don't use compiler builtins for stdlib APIs within the implementation of the stdlib itself. */ -#if defined(BCM_FORTIFY_SOURCE) || defined(BCM_STDLIB_USE_BUILTINS) -#undef memcpy -#undef memmove -#undef memset -#undef strncpy -#undef snprintf -#undef vsnprintf -#endif /* BCM_FORTIFY_SOURCE || BCM_STDLIB_USE_BUILTINS */ - -#ifdef HND_PRINTF_THREAD_SAFE -#include -#include -#include - -/* mutex macros for thread safe */ -#define HND_PRINTF_MUTEX_DECL(mutex) static OSL_EXT_MUTEX_DECL(mutex) -#define HND_PRINTF_MUTEX_CREATE(name, mutex) osl_ext_mutex_create(name, mutex) -#define HND_PRINTF_MUTEX_DELETE(mutex) osl_ext_mutex_delete(mutex) -#define HND_PRINTF_MUTEX_ACQUIRE(mutex, msec) osl_ext_mutex_acquire(mutex, msec) -#define HND_PRINTF_MUTEX_RELEASE(mutex) osl_ext_mutex_release(mutex) - -HND_PRINTF_MUTEX_DECL(printf_mutex); -int in_isr_handler = 0, in_trap_handler = 0, in_fiq_handler = 0; - -bool -printf_lock_init(void) -{ - /* create mutex for critical section locking */ - if (HND_PRINTF_MUTEX_CREATE("printf_mutex", &printf_mutex) != OSL_EXT_SUCCESS) - return FALSE; - return TRUE; -} - -bool -printf_lock_cleanup(void) -{ - /* create mutex for critical section locking */ - if (HND_PRINTF_MUTEX_DELETE(&printf_mutex) != OSL_EXT_SUCCESS) - return FALSE; - return TRUE; -} - -/* returns TRUE if allowed to proceed, FALSE to discard. -* printf from isr hook or fiq hook is not allowed due to IRQ_MODE and FIQ_MODE stack size -* limitation. -*/ -static bool -printf_lock(void) -{ - - /* discard for irq or fiq context, we need to keep irq/fiq stack small. */ - if (in_isr_handler || in_fiq_handler) - return FALSE; - - /* allow printf in trap handler, proceed without mutex. */ - if (in_trap_handler) - return TRUE; - - /* if not in isr or trap, then go thread-protection with mutex. */ - if (HND_PRINTF_MUTEX_ACQUIRE(&printf_mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) - return FALSE; - else - return TRUE; -} - -static void -printf_unlock(void) -{ - if (in_isr_handler || in_fiq_handler) - return; - - if (in_trap_handler) - return; - - if (HND_PRINTF_MUTEX_RELEASE(&printf_mutex) != OSL_EXT_SUCCESS) - return; -} - -#else -#define printf_lock() (TRUE) -#define printf_unlock() -#endif /* HND_PRINTF_THREAD_SAFE */ - -#ifdef BCMSTDLIB_WIN32_APP - -/* for a WIN32 application, use _vsnprintf as basis of vsnprintf/snprintf to - * support full set of format specifications. - */ - -int -BCMPOSTTRAPFN(vsnprintf)(char *buf, size_t bufsize, const char *fmt, va_list ap) -{ - int r; - - r = _vsnprintf(buf, bufsize, fmt, ap); - - /* Microsoft _vsnprintf() will not null terminate on overflow, - * so null terminate at buffer end on error - */ - if (r < 0 && bufsize > 0) - buf[bufsize - 1] = '\0'; - - return r; -} - -int -BCMPOSTTRAPFN(snprintf)(char *buf, size_t bufsize, const char *fmt, ...) -{ - va_list ap; - int r; - - va_start(ap, fmt); - r = vsnprintf(buf, bufsize, fmt, ap); - va_end(ap); - - return r; -} - -#else /* BCMSTDLIB_WIN32_APP */ - -#if !defined(BCMROMOFFLOAD_EXCLUDE_STDLIB_FUNCS) - -static const char hex_upper[17] = "0123456789ABCDEF"; -static const char hex_lower[17] = "0123456789abcdef"; - -static int -BCMPOSTTRAPFN(__atolx)(char *buf, char * end, unsigned long num, unsigned long radix, int width, - const char *digits, int zero_pad) -{ - char buffer[32]; - char *op; - int retval; - - op = &buffer[0]; - retval = 0; - - do { - *op++ = digits[num % radix]; - retval++; - num /= radix; - } while (num != 0); - - if (width && (width > retval) && zero_pad) { - width = width - retval; - while (width) { - *op++ = '0'; - retval++; - width--; - } - } - - while (op != buffer) { - op--; - if (buf <= end) - *buf = *op; - buf++; - } - - return retval; -} - -static int -BCMPOSTTRAPFN(__atox)(char *buf, char * end, unsigned int num, unsigned int radix, int width, - const char *digits, int zero_pad) -{ - char buffer[16]; - char *op; - int retval; - - op = &buffer[0]; - retval = 0; - - do { - *op++ = digits[num % radix]; - retval++; - num /= radix; - } while (num != 0); - - if (width && (width > retval) && zero_pad) { - width = width - retval; - while (width) { - *op++ = '0'; - retval++; - width--; - } - } - - while (op != buffer) { - op--; - if (buf <= end) - *buf = *op; - buf++; - } - - return retval; -} - -int -BCMPOSTTRAPFN(vsnprintf)(char *buf, size_t size, const char *fmt, va_list ap) -{ - char *optr; - char *end; - const char *iptr, *tmpptr; - unsigned int x; - int i; - int islong; - int width; - int width2 = 0; - int hashash = 0; - int zero_pad; - unsigned long ul = 0; - long int li = 0; - - optr = buf; - end = buf + size - 1; - iptr = fmt; - - if (FWSIGN_ENAB()) { - return 0; - } - - if (end < buf - 1) { - end = ((void *) -1); - size = end - buf + 1; - } - - while (*iptr) { - zero_pad = 0; - if (*iptr != '%') { - if (optr <= end) - *optr = *iptr; - ++optr; - ++iptr; - continue; - } - - iptr++; - - if (*iptr == '#') { - hashash = 1; - iptr++; - } - if (*iptr == '-') { - iptr++; - } - - if (*iptr == '0') { - zero_pad = 1; - iptr++; - } - - width = 0; - while (*iptr && bcm_isdigit(*iptr)) { - width += (*iptr - '0'); - iptr++; - if (bcm_isdigit(*iptr)) - width *= 10; - } - if (*iptr == '.') { - iptr++; - width2 = 0; - while (*iptr && bcm_isdigit(*iptr)) { - width2 += (*iptr - '0'); - iptr++; - if (bcm_isdigit(*iptr)) width2 *= 10; - } - } - - islong = 0; - if (*iptr == 'l') { - islong++; - iptr++; - if (*iptr == 'l') { - ++islong; - ++iptr; - } - } - - switch (*iptr) { - case 's': - tmpptr = va_arg(ap, const char *); - if (!tmpptr) - tmpptr = "(null)"; - if ((width == 0) & (width2 == 0)) { - while (*tmpptr) { - if (optr <= end) - *optr = *tmpptr; - ++optr; - ++tmpptr; - } - break; - } - while (width && *tmpptr) { - if (optr <= end) - *optr = *tmpptr; - ++optr; - ++tmpptr; - width--; - } - while (width) { - if (optr <= end) - *optr = ' '; - ++optr; - width--; - } - break; - case 'd': - case 'i': - if (!islong) { - i = va_arg(ap, int); - if (i < 0) { - if (optr <= end) - *optr = '-'; - ++optr; - i = -i; - } - optr += __atox(optr, end, i, 10, width, hex_upper, zero_pad); - } else { - li = va_arg(ap, long int); - if (li < 0) { - if (optr <= end) - *optr = '-'; - ++optr; - li = -li; - } - optr += __atolx(optr, end, li, 10, width, hex_upper, zero_pad); - } - break; - case 'u': - if (!islong) { - x = va_arg(ap, unsigned int); - optr += __atox(optr, end, x, 10, width, hex_upper, zero_pad); - } else { - ul = va_arg(ap, unsigned long); - optr += __atolx(optr, end, ul, 10, width, hex_upper, zero_pad); - } - break; - case 'X': - case 'x': - if (hashash) { - *optr++ = '0'; - *optr++ = *iptr; - } - if (!islong) { - x = va_arg(ap, unsigned int); - optr += __atox(optr, end, x, 16, width, - (*iptr == 'X') ? hex_upper : hex_lower, zero_pad); - } else { - ul = va_arg(ap, unsigned long); - optr += __atolx(optr, end, ul, 16, width, - (*iptr == 'X') ? hex_upper : hex_lower, zero_pad); - } - break; - case 'p': - case 'P': - x = va_arg(ap, unsigned int); - optr += __atox(optr, end, x, 16, 8, - (*iptr == 'P') ? hex_upper : hex_lower, zero_pad); - break; - case 'c': - x = va_arg(ap, int); - if (optr <= end) - *optr = x & 0xff; - optr++; - break; - - default: - if (optr <= end) - *optr = *iptr; - optr++; - break; - } - iptr++; - } - - if (optr <= end) { - *optr = '\0'; - return (int)(optr - buf); - } else { - *end = '\0'; - return (int)(end - buf); - } -} - -int -BCMPOSTTRAPFN(snprintf)(char *buf, size_t bufsize, const char *fmt, ...) -{ - va_list ap; - int r; - - if (FWSIGN_ENAB()) { - return 0; - } - - va_start(ap, fmt); - r = vsnprintf(buf, bufsize, fmt, ap); - va_end(ap); - - return r; -} -#endif /* !BCMROMOFFLOAD_EXCLUDE_STDLIB_FUNCS */ - -#endif /* BCMSTDLIB_WIN32_APP */ - -#ifndef BCMSTDLIB_SNPRINTF_ONLY -int -BCMPOSTTRAPFN(vsprintf)(char *buf, const char *fmt, va_list ap) -{ - if (FWSIGN_ENAB()) { - return 0; - } - return (vsnprintf(buf, INT_MAX, fmt, ap)); -} - -int -BCMPOSTTRAPFN(sprintf)(char *buf, const char *fmt, ...) -{ - va_list ap; - int count; - - if (FWSIGN_ENAB()) { - return 0; - } - - va_start(ap, fmt); - count = vsprintf(buf, fmt, ap); - va_end(ap); - - return count; -} - -#if !defined(EFI) || !defined(COMPILER_INTRINSICS_LIB) -void * -memmove(void *dest, const void *src, size_t n) -{ - /* only use memcpy if there is no overlap. otherwise copy each byte in a safe sequence */ - if (((const char *)src >= (char *)dest + n) || ((const char *)src + n <= (char *)dest)) { - return memcpy(dest, src, n); - } - - /* Overlapping copy forward or backward */ - if (src < dest) { - unsigned char *d = (unsigned char *)dest + (n - 1); - const unsigned char *s = (const unsigned char *)src + (n - 1); - while (n) { - *d-- = *s--; - n--; - } - } else if (src > dest) { - unsigned char *d = (unsigned char *)dest; - const unsigned char *s = (const unsigned char *)src; - while (n) { - *d++ = *s++; - n--; - } - } - - return dest; -} -#endif /* !EFI || !COMPILER_INTRINSICS_LIB */ - -#ifndef EFI -int -memcmp(const void *s1, const void *s2, size_t n) -{ - const unsigned char *ss1; - const unsigned char *ss2; - - ss1 = (const unsigned char *)s1; - ss2 = (const unsigned char *)s2; - - while (n) { - if (*ss1 < *ss2) - return -1; - if (*ss1 > *ss2) - return 1; - ss1++; - ss2++; - n--; - } - - return 0; -} - -/* Skip over functions that are being used from DriverLibrary to save space */ -char * -strncpy(char *dest, const char *src, size_t n) -{ - char *endp; - char *p; - - p = dest; - endp = p + n; - - while (p != endp && (*p++ = *src++) != '\0') - ; - - /* zero fill remainder */ - bzero(p, (endp - p)); - - return dest; -} - -size_t -BCMPOSTTRAPFN(strlen)(const char *s) -{ - size_t n = 0; - - while (*s) { - s++; - n++; - } - - return n; -} - -int -BCMPOSTTRAPFN(strcmp)(const char *s1, const char *s2) -{ - while (*s2 && *s1) { - if (*s1 < *s2) - return -1; - if (*s1 > *s2) - return 1; - s1++; - s2++; - } - - if (*s1 && !*s2) - return 1; - if (!*s1 && *s2) - return -1; - return 0; -} -#endif /* EFI */ - -int -strncmp(const char *s1, const char *s2, size_t n) -{ - while (*s2 && *s1 && n) { - if (*s1 < *s2) - return -1; - if (*s1 > *s2) - return 1; - s1++; - s2++; - n--; - } - - if (!n) - return 0; - if (*s1 && !*s2) - return 1; - if (!*s1 && *s2) - return -1; - return 0; -} - -char * -strchr(const char *str, int c) -{ - const char *x = str; - - while (*x != (char)c) { - if (*x++ == '\0') - return (NULL); - } - - return DISCARD_QUAL(x, char); -} - -char * -strrchr(const char *str, int c) -{ - const char *save = NULL; - - do { - if (*str == (char)c) - save = str; - } while (*str++ != '\0'); - - return DISCARD_QUAL(save, char); -} - -/* Skip over functions that are being used from DriverLibrary to save space */ -#ifndef EFI -char * -strstr(const char *s, const char *substr) -{ - int substr_len = strlen(substr); - - for (; *s; s++) - if (strncmp(s, substr, substr_len) == 0) - return DISCARD_QUAL(s, char); - - return NULL; -} -#endif /* EFI */ - -size_t -strspn(const char *s, const char *accept) -{ - uint count = 0; - - while (s[count] && strchr(accept, s[count])) - count++; - - return count; -} - -size_t -strcspn(const char *s, const char *reject) -{ - uint count = 0; - - while (s[count] && !strchr(reject, s[count])) - count++; - - return count; -} - -void * -memchr(const void *s, int c, size_t n) -{ - if (n != 0) { - const unsigned char *ptr = s; - - do { - if (*ptr == (unsigned char)c) - return DISCARD_QUAL(ptr, void); - ptr++; - n--; - } while (n != 0); - } - return NULL; -} - -unsigned long -strtoul(const char *cp, char **endp, int base) -{ - ulong result, value; - bool minus; - - minus = FALSE; - - while (bcm_isspace(*cp)) - cp++; - - if (cp[0] == '+') - cp++; - else if (cp[0] == '-') { - minus = TRUE; - cp++; - } - - if (base == 0) { - if (cp[0] == '0') { - if ((cp[1] == 'x') || (cp[1] == 'X')) { - base = 16; - cp = &cp[2]; - } else { - base = 8; - cp = &cp[1]; - } - } else - base = 10; - } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { - cp = &cp[2]; - } - - result = 0; - - while (bcm_isxdigit(*cp) && - (value = bcm_isdigit(*cp) ? *cp - '0' : bcm_toupper(*cp) - 'A' + 10) < - (ulong) base) { - result = result * base + value; - cp++; - } - - if (minus) - result = (ulong)(result * -1); - - if (endp) - *endp = DISCARD_QUAL(cp, char); - - return (result); -} - -#ifdef EFI -int -putchar(int c) -{ - return putc(c, stdout); -} - -int -puts(const char *s) -{ - char c; - - while ((c = *s++)) - putchar(c); - - putchar('\n'); - - return 0; -} - -#else /* !EFI */ - -/* memset is not in ROM offload because it is used directly by the compiler in - * structure assignments/character array initialization with "". - */ -void * -BCMPOSTTRAPFN(memset)(void *dest, int c, size_t n) -{ - uint32 w, *dw; - unsigned char *d; - - dw = (uint32 *)dest; - - /* 8 min because we have to create w */ - if ((n >= 8) && (((uintptr)dest & 3) == 0)) { - if (c == 0) - w = 0; - else { - unsigned char ch; - - ch = (unsigned char)(c & 0xff); - w = (ch << 8) | ch; - w |= w << 16; - } - while (n >= 4) { - *dw++ = w; - n -= 4; - } - } - d = (unsigned char *)dw; - - while (n) { - *d++ = (unsigned char)c; - n--; - } - - return dest; -} - -/* memcpy is not in ROM offload because it is used directly by the compiler in - * structure assignments. - */ -#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7A__) -void * -BCMPOSTTRAPFN(memcpy)(void *dest, const void *src, size_t n) -{ - uint32 *dw; - const uint32 *sw; - unsigned char *d; - const unsigned char *s; - - sw = (const uint32 *)src; - dw = (uint32 *)dest; - - if (n >= 4 && ((uintptr)src & 3) == ((uintptr)dest & 3)) { - uint32 t1, t2, t3, t4, t5, t6, t7, t8; - int i = (4 - ((uintptr)src & 3)) % 4; - - n -= i; - - d = (unsigned char *)dw; - s = (const unsigned char *)sw; - while (i--) { - *d++ = *s++; - } - sw = (const uint32 *)s; - dw = (uint32 *)d; - - if (n >= 32) { - const uint32 *sfinal = (const uint32 *)((const uint8 *)sw + (n & ~31)); - - asm volatile("\n1:\t" - "ldmia.w\t%0!, {%3, %4, %5, %6, %7, %8, %9, %10}\n\t" - "stmia.w\t%1!, {%3, %4, %5, %6, %7, %8, %9, %10}\n\t" - "cmp\t%2, %0\n\t" - "bhi.n\t1b\n\t" - : "=r" (sw), "=r" (dw), "=r" (sfinal), "=r" (t1), "=r" (t2), - "=r" (t3), "=r" (t4), "=r" (t5), "=r" (t6), "=r" (t7), - "=r" (t8) - : "0" (sw), "1" (dw), "2" (sfinal)); - - n %= 32; - } - - /* Copy the remaining words */ - switch (n / 4) { - case 0: - break; - case 1: - asm volatile("ldr\t%2, [%0]\n\t" - "str\t%2, [%1]\n\t" - "adds\t%0, #4\n\t" - "adds\t%1, #4\n\t" - : "=r" (sw), "=r" (dw), "=r" (t1) - : "0" (sw), "1" (dw)); - break; - case 2: - asm volatile("ldmia.w\t%0!, {%2, %3}\n\t" - "stmia.w\t%1!, {%2, %3}\n\t" - : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2) - : "0" (sw), "1" (dw)); - break; - case 3: - asm volatile("ldmia.w\t%0!, {%2, %3, %4}\n\t" - "stmia.w\t%1!, {%2, %3, %4}\n\t" - : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2), - "=r" (t3) - : "0" (sw), "1" (dw)); - break; - case 4: - asm volatile("ldmia.w\t%0!, {%2, %3, %4, %5}\n\t" - "stmia.w\t%1!, {%2, %3, %4, %5}\n\t" - : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2), - "=r" (t3), "=r" (t4) - : "0" (sw), "1" (dw)); - break; - case 5: - asm volatile( - "ldmia.w\t%0!, {%2, %3, %4, %5, %6}\n\t" - "stmia.w\t%1!, {%2, %3, %4, %5, %6}\n\t" - : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2), - "=r" (t3), "=r" (t4), "=r" (t5) - : "0" (sw), "1" (dw)); - break; - case 6: - asm volatile( - "ldmia.w\t%0!, {%2, %3, %4, %5, %6, %7}\n\t" - "stmia.w\t%1!, {%2, %3, %4, %5, %6, %7}\n\t" - : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2), - "=r" (t3), "=r" (t4), "=r" (t5), "=r" (t6) - : "0" (sw), "1" (dw)); - break; - case 7: - asm volatile( - "ldmia.w\t%0!, {%2, %3, %4, %5, %6, %8, %7}\n\t" - "stmia.w\t%1!, {%2, %3, %4, %5, %6, %8, %7}\n\t" - : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2), - "=r" (t3), "=r" (t4), "=r" (t5), "=r" (t6), - "=r" (t7) - : "0" (sw), "1" (dw)); - break; - default: - ASSERT(0); - break; - } - n = n % 4; - } - - /* Copy the remaining bytes */ - d = (unsigned char *)dw; - s = (const unsigned char *)sw; - while (n--) { - *d++ = *s++; - } - - return dest; -} - -#ifdef __clang__ -/* TODO: remove once toolchain builtin libraries are available */ -/* simulate compiler builtins */ - -/* not aligned */ -void *__aeabi_memcpy(void *dest, const void *src, size_t n); -void * -__aeabi_memcpy(void *dest, const void *src, size_t n) -{ - return memcpy(dest, src, n); -} - -/* 4 byte aligned */ -void *__aeabi_memcpy4(void *dest, const void *src, size_t n); -void * -__aeabi_memcpy4(void *dest, const void *src, size_t n) -{ - return memcpy(dest, src, n); -} - -/* 8 byte aligned */ -void *__aeabi_memcpy8(void *dest, const void *src, size_t n); -void * -__aeabi_memcpy8(void *dest, const void *src, size_t n) -{ - return memcpy(dest, src, n); -} - -/* 8 byte aligned */ -void *__aeabi_memclr8(void *dest, size_t n); -void * -__aeabi_memclr8(void *dest, size_t n) -{ - return memset(dest, 0, n); -} -#endif /* __clang__ */ -#else -void * -memcpy(void *dest, const void *src, size_t n) -{ - uint32 *dw; - const uint32 *sw; - unsigned char *d; - const unsigned char *s; - - sw = (const uint32 *)src; - dw = (uint32 *)dest; - - if ((n >= 4) && (((uintptr)src & 3) == ((uintptr)dest & 3))) { - int i = (4 - ((uintptr)src & 3)) % 4; - n -= i; - d = (unsigned char *)dw; - s = (const unsigned char *)sw; - while (i--) { - *d++ = *s++; - } - - sw = (const uint32 *)s; - dw = (uint32 *)d; - while (n >= 4) { - *dw++ = *sw++; - n -= 4; - } - } - d = (unsigned char *)dw; - s = (const unsigned char *)sw; - while (n--) { - *d++ = *s++; - } - - return dest; -} -#endif /* defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7A__) */ -#endif /* EFI */ - -/* a hook to send printf output to the host */ -static printf_sendup_output_fn_t g_printf_sendup_output_fn = NULL; -static void *g_printf_sendup_output_ctx = NULL; - -#ifdef DONGLEBUILD -static bool _rodata_overwritten = FALSE; - -/* Ensure this string is not const. */ -CONST char BCMPOST_TRAP_RODATA(warn_str)[] = "RO overwritten %p\n"; -CONST char BCMPOST_TRAP_RODATA(time_str)[] = "%06u.%03u "; -#endif /* DONGLEBUILD */ - -void -printf_set_sendup_output_fn(printf_sendup_output_fn_t fn, void *ctx) -{ - g_printf_sendup_output_fn = fn; - g_printf_sendup_output_ctx = ctx; -} - -#ifdef DONGLEBUILD -void -BCMPOSTTRAPFN(printf_set_rodata_invalid)(void) -{ - _rodata_overwritten = TRUE; -} - -bool -printf_get_rodata_invalid(void) -{ - return (_rodata_overwritten); -} -#endif /* DONGLEBUILD */ - -/* Include printf if it has already not been defined as NULL */ -#ifndef printf -static bool last_nl = FALSE; -int -BCMPOSTTRAPFN(printf)(const char *fmt, ...) -{ - va_list ap; - int count = 0, i; - char buffer[PRINTF_BUFLEN + 1]; - - if (FWSIGN_ENAB()) { - return 0; - } - - if (!printf_lock()) - return 0; - -#ifdef DONGLEBUILD - if (_rodata_overwritten == TRUE) { - /* Regular printf will be garbage if ROdata is overwritten. In that case, - * print the caller address. - */ - _rodata_overwritten = FALSE; - count = printf(warn_str, CALL_SITE); - _rodata_overwritten = TRUE; - return count; - } - - if (last_nl) { - /* add the dongle ref time */ - uint32 dongle_time_ms = hnd_get_reftime_ms(); - count = sprintf(buffer, time_str, dongle_time_ms / 1000, dongle_time_ms % 1000); - } -#endif /* DONGLEBUILD */ - - va_start(ap, fmt); - count += vsnprintf(buffer + count, sizeof(buffer) - count, fmt, ap); - va_end(ap); - - for (i = 0; i < count; i++) { - putchar(buffer[i]); - - /* EFI environment requires CR\LF in a printf, etc. - * so unless the string has \r\n, it will not execute CR - * So force it! - */ -#ifdef EFI - if (buffer[i] == '\n') - putchar('\r'); -#endif - } - - /* send the output up to the host */ - if (g_printf_sendup_output_fn != NULL) { - g_printf_sendup_output_fn(g_printf_sendup_output_ctx, buffer, count); - } - - if (buffer[count - 1] == '\n') - last_nl = TRUE; - else - last_nl = FALSE; - - printf_unlock(); - - return count; -} -#endif /* printf */ - -#if !defined(_WIN32) && !defined(EFI) -int -fputs(const char *s, FILE *stream /* UNUSED */) -{ - char c; - - UNUSED_PARAMETER(stream); - while ((c = *s++)) - putchar(c); - return 0; -} - -int -puts(const char *s) -{ - fputs(s, stdout); - putchar('\n'); - return 0; -} - -int -fputc(int c, FILE *stream) -{ - return putc(c, stream); -} - -unsigned long -rand(void) -{ - static unsigned long seed = 1; - long x, hi, lo, t; - - x = seed; - hi = x / 127773; - lo = x % 127773; - t = 16807 * lo - 2836 * hi; - if (t <= 0) t += 0x7fffffff; - seed = t; - return t; -} -#endif /* !_WIN32 && !EFI */ - -#endif /* BCMSTDLIB_SNPRINTF_ONLY */ - -#if !defined(_WIN32) || defined(EFI) -size_t -strnlen(const char *s, size_t maxlen) -{ - const char *b = s; - const char *e = s + maxlen; - - while (s < e && *s) { - s++; - } - - return s - b; -} -#endif /* !_WIN32 || EFI */ - -/* FORTIFY_SOURCE: Implementation of compiler built-in functions for C standard library functions - * that provide run-time buffer overflow detection. - */ -#if defined(BCM_FORTIFY_SOURCE) - -void* -__memcpy_chk(void *dest, const void *src, size_t n, size_t destsz) -{ - if (memcpy_s(dest, destsz, src, n) != 0) { - OSL_SYS_HALT(); - } - - return (dest); -} - -void * -__memmove_chk(void *dest, const void *src, size_t n, size_t destsz) -{ - if (memmove_s(dest, destsz, src, n) != 0) { - OSL_SYS_HALT(); - } - - return (dest); -} - -void * -__memset_chk(void *dest, int c, size_t n, size_t destsz) -{ - if (memset_s(dest, destsz, c, n) != 0) { - OSL_SYS_HALT(); - } - - return (dest); -} - -int -__snprintf_chk(char *str, size_t n, int flag, size_t destsz, const char *fmt, ...) -{ - va_list arg; - int rc; - - if (n > destsz) { - OSL_SYS_HALT(); - } - - va_start(arg, fmt); - rc = vsnprintf(str, n, fmt, arg); - va_end(arg); - - return (rc); -} - -int -__vsnprintf_chk(char *str, size_t n, int flags, size_t destsz, const char *fmt, va_list ap) -{ - if (n > destsz) { - OSL_SYS_HALT(); - } - - return (vsnprintf(str, n, fmt, ap)); -} - -char * -__strncpy_chk(char *dest, const char *src, size_t n, size_t destsz) -{ - if (n > destsz) { - OSL_SYS_HALT(); - } - - return (strncpy(dest, src, n)); -} -#endif /* BCM_FORTIFY_SOURCE */ - -/* Provide stub implementations for xxx_s() APIs that are remapped to compiler builtins. - * This allows the target to link. - * - * This is only intended as a compile-time test, and should be used by compile-only targets. - */ -#if defined(BCM_STDLIB_S_BUILTINS_TEST) -#undef strcpy -char* strcpy(char *dest, const char *src); -char* -strcpy(char *dest, const char *src) -{ - return (NULL); -} - -#undef strcat -char* strcat(char *dest, const char *src); -char* -strcat(char *dest, const char *src) -{ - return (NULL); -} -#endif /* BCM_STDLIB_S_BUILTINS_TEST */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmstdlib_s.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmstdlib_s.c old mode 100755 new mode 100644 index fd7e83e582cb..c540349ac503 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmstdlib_s.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmstdlib_s.c @@ -1,7 +1,7 @@ /* * Broadcom Secure Standard Library. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -28,6 +28,7 @@ #else /* BCMDRIVER */ #include #include +#include #endif /* else BCMDRIVER */ #include @@ -60,8 +61,8 @@ #endif /* SIZE_MAX */ #define RSIZE_MAX (SIZE_MAX >> 1u) -#if !defined(__STDC_WANT_SECURE_LIB__) && \ - !(defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) +#if !defined(__STDC_WANT_SECURE_LIB__) && !(defined(__STDC_LIB_EXT1__) && \ + defined(__STDC_WANT_LIB_EXT1__)) /* * memmove_s - secure memmove * dest : pointer to the object to copy to @@ -73,7 +74,7 @@ * than RSIZE_MAX, writes destsz zero bytes into the dest object. */ int -memmove_s(void *dest, size_t destsz, const void *src, size_t n) +BCMPOSTTRAPFN(memmove_s)(void *dest, size_t destsz, const void *src, size_t n) { int err = BCME_OK; @@ -88,13 +89,13 @@ memmove_s(void *dest, size_t destsz, const void *src, size_t n) } if (destsz < n) { - memset(dest, 0, destsz); + bzero(dest, destsz); err = BCME_BADLEN; goto exit; } if ((!src) || (((const char *)src + n) < (const char *)src)) { - memset(dest, 0, destsz); + bzero(dest, destsz); err = BCME_BADARG; goto exit; } @@ -132,20 +133,20 @@ BCMPOSTTRAPFN(memcpy_s)(void *dest, size_t destsz, const void *src, size_t n) } if (destsz < n) { - memset(dest, 0, destsz); + bzero(dest, destsz); err = BCME_BADLEN; goto exit; } if ((!s) || ((s + n) < s)) { - memset(dest, 0, destsz); + bzero(dest, destsz); err = BCME_BADARG; goto exit; } /* overlap checking between dest and src */ if (!(((d + destsz) <= s) || (d >= (s + n)))) { - memset(dest, 0, destsz); + bzero(dest, destsz); err = BCME_BADARG; goto exit; } @@ -204,7 +205,7 @@ exit: * of course, the buffer size is zero). It does not pad * out the result like strncpy() does. */ -size_t strlcpy(char *dest, const char *src, size_t size) +size_t BCMPOSTTRAPFN(strlcpy)(char *dest, const char *src, size_t size) { size_t i; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmutils.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmutils.c old mode 100755 new mode 100644 index 6d9e4a80fa63..6231b4b8f1f3 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmutils.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmutils.c @@ -1,7 +1,7 @@ /* * Driver O/S-independent utility routines * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -23,9 +23,7 @@ #include #include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) -#include -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) */ + #ifdef BCMDRIVER #include #include @@ -38,6 +36,7 @@ #include #include #include +#include #if defined(BCMEXTSUP) #include @@ -46,22 +45,13 @@ #ifndef ASSERT #define ASSERT(exp) #endif +#ifndef ASSERT_FP +#define ASSERT_FP(exp) +#endif #endif /* !BCMDRIVER */ -#ifdef WL_UNITTEST -/* - * Definitions and includes needed during software unit test compilation and execution. - */ -#include -#include -#ifdef ASSERT -#undef ASSERT -#endif /* ASSERT */ -#define ASSERT(exp) -#endif /* WL_UNITTEST */ - -#if defined(_WIN32) || defined(NDIS) +#if defined(_WIN32) || defined(NDIS) || defined(DONGLEBUILD) /* Debatable */ #include #endif @@ -81,25 +71,19 @@ #endif #include +#include + #define NUMBER_OF_BITS_BYTE 8u -#ifdef CUSTOM_DSCP_TO_PRIO_MAPPING -#define CUST_IPV4_TOS_PREC_MASK 0x3F -#define DCSP_MAX_VALUE 64 -extern uint dhd_dscpmap_enable; -/* 0:BE,1:BK,2:RESV(BK):,3:EE,:4:CL,5:VI,6:VO,7:NC */ -int dscp2priomap[DCSP_MAX_VALUE]= -{ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, /* BK->BE */ - 2, 0, 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 0, 0, 0, 0, - 5, 0, 0, 0, 0, 0, 0, 0, - 6, 0, 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 0, 0, 0, 0 -}; -#endif /* CUSTOM_DSCP_TO_PRIO_MAPPING */ +/* TX_HISTOGRAM enable/disable state flag + * Updated in histogram.c + */ +#if defined(TX_HISTOGRAM) && !defined(TX_HISTOGRAM_DISABLED) +/* initialized to TRUE in tx_histogram_init() */ +bool _tx_histogram_enabled = FALSE; +#else +bool _tx_histogram_enabled = FALSE; +#endif /* TX_HISTOGRAM && !TX_HISTOGRAM_DISABLED */ #ifdef PRIVACY_MASK struct ether_addr privacy_addrmask; @@ -116,27 +100,37 @@ BCMRAMFN(privacy_addrmask_get)(void) #ifndef BCM_ARM_BACKTRACE /* function pointers for firmware stack backtrace utility */ -void (*const print_btrace_int_fn)(int depth, uint32 pc, uint32 lr, uint32 sp) = NULL; -void (*const print_btrace_fn)(int depth) = NULL; +void (*const BCMPOST_TRAP_RODATA(print_btrace_int_fn))(int depth, uint32 pc, uint32 lr, uint32 sp) = + NULL; +void (*const BCMPOST_TRAP_RODATA(print_btrace_fn))(int depth) = NULL; #else void print_backtrace(int depth); -void (*const print_btrace_fn)(int depth) = print_backtrace; +void (*const BCMPOST_TRAP_RODATA(print_btrace_fn))(int depth) = print_backtrace; void print_backtrace_int(int depth, uint32 pc, uint32 lr, uint32 sp); -void (*const print_btrace_int_fn)(int depth, uint32 pc, uint32 lr, uint32 sp) = print_backtrace_int; +void (*const BCMPOST_TRAP_RODATA(print_btrace_int_fn))(int depth, uint32 pc, uint32 lr, uint32 sp) = + print_backtrace_int; #endif #if !defined(BCMDONGLEHOST) -/* Forward declarations */ -char * getvar_internal(char *vars, const char *name); -int getintvar_internal(char *vars, const char *name); -int getintvararray_internal(char *vars, const char *name, int index); -int getintvararraysize_internal(char *vars, const char *name); -#ifndef WL_FWSIGN +#ifndef BCM_BOOTLOADER +/* Forward declarations */ +static int getintvararray_internal(char *vars, const char *name, int index); +static int getintvararraysize_internal(char *vars, const char *name); +static +#ifndef ATE_BUILD +const +#endif +char * getvar_internal(char *vars, const char *name); +static int getintvar_internal(char *vars, const char *name); + /* * Search the name=value vars for a specific one and return its value. * Returns NULL if not found. */ +#ifndef ATE_BUILD +const +#endif char * getvar(char *vars, const char *name) { @@ -144,6 +138,10 @@ getvar(char *vars, const char *name) return getvar_internal(vars, name); } +static +#ifndef ATE_BUILD +const +#endif char * getvar_internal(char *vars, const char *name) { @@ -182,15 +180,15 @@ getintvar(char *vars, const char *name) return getintvar_internal(vars, name); } -int +static int getintvar_internal(char *vars, const char *name) { - char *val; + const char *val; if ((val = getvar_internal(vars, name)) == NULL) return (0); - return (bcm_strtoul(val, NULL, 0)); + return (int)(bcm_strtoul(val, NULL, 0)); } int @@ -200,10 +198,11 @@ getintvararray(char *vars, const char *name, int index) return getintvararray_internal(vars, name, index); } -int +static int getintvararray_internal(char *vars, const char *name, int index) { - char *buf, *endp; + const char *buf; + char *endp; int i = 0; int val = 0; @@ -213,7 +212,7 @@ getintvararray_internal(char *vars, const char *name, int index) /* table values are always separated by "," or " " */ while (*buf != '\0') { - val = bcm_strtoul(buf, &endp, 0); + val = (int)bcm_strtoul(buf, &endp, 0); if (i == index) { return val; } @@ -233,10 +232,11 @@ getintvararraysize(char *vars, const char *name) return getintvararraysize_internal(vars, name); } -int +static int getintvararraysize_internal(char *vars, const char *name) { - char *buf, *endp; + const char *buf; + char *endp; int count = 0; int val = 0; @@ -246,7 +246,7 @@ getintvararraysize_internal(char *vars, const char *name) /* table values are always separated by "," or " " */ while (*buf != '\0') { - val = bcm_strtoul(buf, &endp, 0); + val = (int)bcm_strtoul(buf, &endp, 0); buf = endp; /* delimiter is ',' */ if (*buf == ',') @@ -262,7 +262,7 @@ getintvararraysize_internal(char *vars, const char *name) * Pass in NULL for the dest_array[12] that is not to be used. */ static int -BCMATTACHFN(getintvararray_slicespecific)(osl_t *osh, char *vars, char *vars_table_accessor, +getintvararray_slicespecific(osl_t *osh, char *vars, char *vars_table_accessor, const char* name, uint8* dest_array1, int16* dest_array2, uint dest_size) { uint i; @@ -302,7 +302,7 @@ BCMATTACHFN(getintvararray_slicespecific)(osl_t *osh, char *vars, char *vars_tab /* load the destination array with the nvram array values */ for (i = 0; i < array_size; i++) { - val = getintvararray(vars, new_name, i); + val = getintvararray(vars, new_name, (int)i); if (dest_array1) { dest_array1[i] = (uint8)val; } else if (dest_array2) { @@ -315,7 +315,7 @@ done: } int -BCMATTACHFN(get_uint8_vararray_slicespecific)(osl_t *osh, char *vars, char *vars_table_accessor, +get_uint8_vararray_slicespecific(osl_t *osh, char *vars, char *vars_table_accessor, const char* name, uint8* dest_array, uint dest_size) { int ret; @@ -326,7 +326,7 @@ BCMATTACHFN(get_uint8_vararray_slicespecific)(osl_t *osh, char *vars, char *vars } int -BCMATTACHFN(get_int16_vararray_slicespecific)(osl_t *osh, char *vars, char *vars_table_accessor, +get_int16_vararray_slicespecific(osl_t *osh, char *vars, char *vars_table_accessor, const char* name, int16* dest_array, uint dest_size) { return getintvararray_slicespecific(osh, vars, vars_table_accessor, @@ -338,7 +338,7 @@ BCMATTACHFN(get_int16_vararray_slicespecific)(osl_t *osh, char *vars, char *vars * Caller is responsible for freeing the resulting name string with MFREE. */ uint -BCMATTACHFN(get_slicespecific_var_name)(osl_t *osh, char *vars_table_accessor, const char *name, +get_slicespecific_var_name(osl_t *osh, char *vars_table_accessor, const char *name, char **name_out) { char *name_with_prefix = NULL; @@ -368,8 +368,9 @@ end: *name_out = name_with_prefix; return sz; } -#endif /* WL_FWSIGN */ +#endif /* BCM_BOOTLOADER */ +#if defined(BCMNVRAMR) || defined(BCMNVRAMW) /* Search for token in comma separated token-string */ static int findmatch(const char *string, const char *name) @@ -403,7 +404,7 @@ uint getgpiopin(char *vars, char *pin_name, uint def_pin) { char name[] = "gpioXXXX"; - char *val; + const char *val; uint pin; /* Go thru all possibilities till a match in pin name */ @@ -423,6 +424,7 @@ getgpiopin(char *vars, char *pin_name, uint def_pin) } return def_pin; } +#endif /* BCMNVRAMR || BCMNVRAMW */ #endif /* !BCMDONGLEHOST */ /* return total length of buffer chain. In case of CSO, submsdu may have extra tsohdr and if @@ -522,8 +524,8 @@ BCMFASTPATH(pktsegcnt)(osl_t *osh, void *p) void BCMFASTPATH(pktfrag_trim_tailbytes)(osl_t * osh, void* p, uint16 trim_len, uint8 type) { - uint16 tcmseg_len = PKTLEN(osh, p); /* TCM segment length */ - uint16 hostseg_len = PKTFRAGUSEDLEN(osh, p); /* HOST segment length */ + uint tcmseg_len = PKTLEN(osh, p); /* TCM segment length */ + uint hostseg_len = PKTFRAGUSEDLEN(osh, p); /* HOST segment length */ /* return if zero trim length- Nothing to do */ if (trim_len == 0) @@ -556,7 +558,7 @@ BCMFASTPATH(pktfrag_trim_tailbytes)(osl_t * osh, void* p, uint16 trim_len, uint8 /* copy a pkt buffer chain into a buffer */ uint -pktcopy(osl_t *osh, void *p, uint offset, uint len, uchar *buf) +BCMPOSTTRAPFN(pktcopy)(osl_t *osh, void *p, uint offset, uint len, uchar *buf) { uint n, ret = 0; @@ -612,29 +614,6 @@ pktfrombuf(osl_t *osh, void *p, uint offset, uint len, uchar *buf) return ret; } -#ifdef NOT_YET -/* copy data from one pkt buffer (chain) to another */ -uint -pkt2pktcopy(osl_t *osh, void *p1, uint offs1, void *p2, uint offs2, uint maxlen) -{ - uint8 *dp1, *dp2; - uint len1, len2, copylen, totallen; - - for (; p1 && offs; p1 = PKTNEXT(osh, p1)) { - if (offs1 < (uint)PKTLEN(osh, p1)) - break; - offs1 -= PKTLEN(osh, p1); - } - for (; p2 && offs; p2 = PKTNEXT(osh, p2)) { - if (offs2 < (uint)PKTLEN(osh, p2)) - break; - offs2 -= PKTLEN(osh, p2); - } - - /* Heck w/it, only need the above for now */ -} -#endif /* NOT_YET */ - uint8 * BCMFASTPATH(pktdataoffset)(osl_t *osh, void *p, uint offset) { @@ -814,9 +793,12 @@ bcmdumplog(char *buf, int size) char *limit; int j = 0; int num; + struct bcmstrbuf strubuf; + struct bcmstrbuf *b = &strubuf; - limit = buf + size - 80; - *buf = '\0'; + bcm_binit(b, buf, size); + + limit = BCMSTRBUF_BUF(b) + BCMSTRBUF_LEN(b) - 80; num = logi - readi; @@ -825,13 +807,12 @@ bcmdumplog(char *buf, int size) /* print in chronological order */ - for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) { + for (j = 0; j < num && (BCMSTRBUF_BUF(b) < limit); readi = (readi + 1) % LOGSIZE, j++) { if (logtab[readi].fmt == NULL) continue; - buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles); - buf += snprintf(buf, (limit - buf), logtab[readi].fmt, logtab[readi].a1, - logtab[readi].a2); - buf += snprintf(buf, (limit - buf), "\n"); + bcm_bprintf(b, "%d\t", logtab[readi].cycles); + bcm_bprintf(b, logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2); + bcm_bprintf(b, "\n"); } } @@ -844,6 +825,8 @@ int bcmdumplogent(char *buf, uint i) { bool hit; + struct bcmstrbuf strubuf; + struct bcmstrbuf *b = &strubuf; /* * If buf is NULL, return the starting index, @@ -861,13 +844,14 @@ bcmdumplogent(char *buf, uint i) if (i == logi) return (-1); + bcm_binit(b, buf, i); hit = FALSE; for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE) { if (logtab[i].fmt == NULL) continue; - buf += snprintf(buf, LOGSIZE, "%d: %d\t", i, logtab[i].cycles); - buf += snprintf(buf, LOGSIZE, logtab[i].fmt, logtab[i].a1, logtab[i].a2); - buf += snprintf(buf, LOGSIZE, "\n"); + bcm_bprintf(b, "%d: %d\t", i, logtab[i].cycles); + bcm_bprintf(b, logtab[i].fmt, logtab[i].a1, logtab[i].a2); + bcm_bprintf(b, "\n"); hit = TRUE; } @@ -1064,8 +1048,8 @@ BCMFASTPATH(pktsetprio)(void *pkt, bool update_vtag) struct ether_header *eh; struct ethervlan_header *evh; uint8 *pktdata; - int priority = 0; - int rc = 0; + uint priority = 0; + uint rc = 0; pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); ASSERT_FP(ISALIGNED((uintptr)pktdata, sizeof(uint16))); @@ -1074,18 +1058,18 @@ BCMFASTPATH(pktsetprio)(void *pkt, bool update_vtag) if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { uint16 vlan_tag; - int vlan_prio, dscp_prio = 0; + uint vlan_prio, dscp_prio = 0; evh = (struct ethervlan_header *)eh; vlan_tag = ntoh16(evh->vlan_tag); - vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; + vlan_prio = (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; if ((evh->ether_type == hton16(ETHER_TYPE_IP)) || (evh->ether_type == hton16(ETHER_TYPE_IPV6))) { uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); uint8 tos_tc = IP_TOS46(ip_body); - dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); + dscp_prio = tos_tc >> IPV4_TOS_PREC_SHIFT; } /* DSCP priority gets precedence over 802.1P (vlan tag) */ @@ -1105,7 +1089,7 @@ BCMFASTPATH(pktsetprio)(void *pkt, bool update_vtag) */ if (update_vtag && (priority != vlan_prio)) { vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); - vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; + vlan_tag |= priority << VLAN_PRI_SHIFT; evh->vlan_tag = hton16(vlan_tag); rc |= PKTPRIO_UPD; } @@ -1114,6 +1098,15 @@ BCMFASTPATH(pktsetprio)(void *pkt, bool update_vtag) priority = PRIO_8021D_NC; rc = PKTPRIO_DSCP; #endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */ +#if defined(PRIORITIZE_ARP) + } else if (eh->ether_type == hton16(ETHER_TYPE_ARP)) { + /* Certain Host stacks attempt disconnection on continous ARP timeouts. In + * congested scenarios with traffic, ARP packets may not get chance + * for transmission leading to disconnection. so prioritize it. + */ + priority = PRIO_8021D_NC; + rc = PKTPRIO_DSCP; +#endif /* PRIORITIZE_ARP */ #if defined(WLTDLS) } else if (eh->ether_type == hton16(ETHER_TYPE_89_0D)) { /* Bump up the priority for TDLS frames */ @@ -1147,29 +1140,21 @@ BCMFASTPATH(pktsetprio)(void *pkt, bool update_vtag) case DSCP_CS2: priority = PRIO_8021D_BE; break; +#ifdef RFC8325_DSCP_CS6_TO_UP7 case DSCP_CS6: +#endif /* RFC8325_DSCP_CS6_TO_UP7 */ case DSCP_CS7: priority = PRIO_8021D_NC; break; default: -#ifndef CUSTOM_DSCP_TO_PRIO_MAPPING - priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); -#else - if (dhd_dscpmap_enable) { - priority = (int)dscp2priomap[((tos_tc >> IPV4_TOS_DSCP_SHIFT) - & CUST_IPV4_TOS_PREC_MASK)]; - } - else { - priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); - } -#endif /* CUSTOM_DSCP_TO_PRIO_MAPPING */ + priority = tos_tc >> IPV4_TOS_PREC_SHIFT; break; } rc |= PKTPRIO_DSCP; } - ASSERT_FP(priority >= 0 && priority <= MAXPRIO); + ASSERT_FP(priority <= MAXPRIO); PKTSETPRIO(pkt, priority); return (rc | priority); } @@ -1185,9 +1170,12 @@ dscp2up(uint8 *up_table, uint8 dscp) user_priority = up_table[dscp]; } - /* 255 is unused value so return up from dscp */ - if (user_priority == 255) { - user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT); + if (user_priority == 255) { /* unknown user priority */ + + /* If the user_priority from the QoS Map table is unknown(i.e., 255), then + * set the default user priority as PRIO_8021D_BE(0); Reference RFC 8325. + */ + user_priority = PRIO_8021D_BE; /* default priority */ } return user_priority; @@ -1211,6 +1199,11 @@ BCMFASTPATH(pktsetprio_qms)(void *pkt, uint8* up_table, bool update_vtag) user_priority = dscp2up(up_table, dscp); PKTSETPRIO(pkt, user_priority); } +#ifdef WL_CUSTOM_MAPPING_OF_DSCP + else { + return pktsetprio(pkt, update_vtag); + } +#endif /* WL_CUSTOM_MAPPING_OF_DSCP */ return (rc | user_priority); } else { @@ -1449,6 +1442,7 @@ _pktlist_trace(pktlist_info_t *pktlist, void *pkt, uint16 bit) pktlist->list[(*idx)].pkt_trace[bit/NBBY] |= (1 << ((bit)%NBBY)); } + void pktlist_trace(pktlist_info_t *pktlist, void *pkt, uint16 bit) { @@ -1698,7 +1692,7 @@ typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */ /* Incarnate a hierarchical multiword bitmap based small index allocator. */ struct bcm_mwbmap * -BCMATTACHFN(bcm_mwbmap_init)(osl_t *osh, uint32 items_max) +bcm_mwbmap_init(osl_t *osh, uint32 items_max) { struct bcm_mwbmap * mwbmap_p; uint32 wordix, size, words, extra; @@ -1718,12 +1712,11 @@ BCMATTACHFN(bcm_mwbmap_init)(osl_t *osh, uint32 items_max) /* Allocate runtime state of multiword bitmap */ /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */ size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words); - mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size); + mwbmap_p = (bcm_mwbmap_t *)MALLOCZ(osh, size); if (mwbmap_p == (bcm_mwbmap_t *)NULL) { ASSERT(0); goto error1; } - memset(mwbmap_p, 0, size); /* Initialize runtime multiword bitmap state */ mwbmap_p->imaps = (uint16)words; @@ -1772,7 +1765,7 @@ error1: /* Release resources used by multiword bitmap based small index allocator. */ void -BCMATTACHFN(bcm_mwbmap_fini)(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl) +bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl) { bcm_mwbmap_t * mwbmap_p; @@ -1827,7 +1820,7 @@ BCMFASTPATH(bcm_mwbmap_alloc)(struct bcm_mwbmap * mwbmap_hdl) MWBMAP_ASSERT(count >= 0); /* clear wd_bitmap bit if id_map count is 0 */ - bitmap = (count == 0) << bitix; + bitmap = (uint32)(count == 0) << bitix; MWBMAP_DBG(( "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d", @@ -1913,7 +1906,7 @@ bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ MWBMAP_ASSERT(count >= 0); - bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix); + bitmap = (uint32)(count == 0) << BCM_MWBMAP_MODOP(bitix); MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d", BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap, @@ -1995,9 +1988,9 @@ bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl) BCM_MWBMAP_AUDIT(mwbmap_hdl); mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - ASSERT(mwbmap_p->ifree >= 0); + ASSERT_FP(mwbmap_p->ifree >= 0); - return mwbmap_p->ifree; + return (uint32)mwbmap_p->ifree; } /* Determine whether an index is inuse or free */ @@ -2065,7 +2058,7 @@ bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl) bitmap_p = &mwbmap_p->wd_bitmap[wordix]; for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) { - if ((*bitmap_p) & (1 << bitix)) { + if ((*bitmap_p) & (1u << bitix)) { idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix; #if defined(BCM_MWBMAP_USE_CNTSETBITS) count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]); @@ -2080,7 +2073,11 @@ bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl) } ASSERT((int)free_cnt == mwbmap_p->ifree); + if (free_cnt != mwbmap_p->ifree) { + printf("Error: free_cnt != mwbmap_p->ifree\n"); + } } + /* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */ /* Simple 16bit Id allocator using a stack implementation. */ @@ -2126,7 +2123,7 @@ id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16) ASSERT((start_val16 == ID16_UNDEFINED) || (start_val16 + total_ids) < ID16_INVALID); - id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids)); + id16_map = (id16_map_t *) MALLOCZ(osh, ID16_MAP_SZ(total_ids)); if (id16_map == NULL) { return NULL; } @@ -2153,7 +2150,7 @@ id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16) #if defined(BCM_DBG) && defined(BCM_DBG_ID16) if (id16_map->start != ID16_UNDEFINED) { - id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids)); + id16_map->dbg = MALLOCZ(osh, ID16_MAP_DBG_SZ(total_ids)); if (id16_map->dbg) { id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; @@ -2363,18 +2360,21 @@ done: /* invoke any other system audits */ return (!!insane); } + /* END: Simple id16 allocator */ void -BCMATTACHFN(dll_pool_detach)(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size) +dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size) { uint32 mem_size; - mem_size = sizeof(dll_pool_t) + (elems_max * elem_size); - if (pool) + mem_size = (uint32)sizeof(dll_pool_t) + ((uint32)elems_max * (uint32)elem_size); + if (pool) { MFREE(osh, pool, mem_size); + } } + dll_pool_t * -BCMATTACHFN(dll_pool_init)(void * osh, uint16 elems_max, uint16 elem_size) +dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size) { uint32 mem_size, i; dll_pool_t * dll_pool_p; @@ -2382,7 +2382,7 @@ BCMATTACHFN(dll_pool_init)(void * osh, uint16 elems_max, uint16 elem_size) ASSERT(elem_size > sizeof(dll_t)); - mem_size = sizeof(dll_pool_t) + (elems_max * elem_size); + mem_size = (uint32)sizeof(dll_pool_t) + ((uint32)elems_max * (uint32)elem_size); if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, mem_size)) == NULL) { ASSERT(0); @@ -2462,13 +2462,27 @@ dll_pool_dump(dll_pool_t * dll_pool_p, dll_elem_dump elem_dump) #if defined(BCMDRIVER) || defined(WL_UNITTEST) +#ifndef DONGLEBUILD /* triggers bcm_bprintf to print to kernel log */ bool bcm_bprintf_bypass = FALSE; +#endif /* !DONGLEBUILD */ + +#if !(defined(_WIN32) || defined(NDIS)) +/* TODO: add vprintf to ndis OSL and remove this conditional */ +#define BCM_BPRINTF_ALLOW_NULL_B +#endif /* Initialization of bcmstrbuf structure */ void BCMPOSTTRAPFN(bcm_binit)(struct bcmstrbuf *b, char *buf, uint size) { +#ifdef BCM_BPRINTF_ALLOW_NULL_B + /* pass NULL to struct bcmstrbuf *b to indicate the output is console */ + if (b == NULL) { + return; + } +#endif /* BCM_BPRINTF_ALLOW_NULL_B */ + b->origsize = b->size = size; b->origbuf = b->buf = buf; if (size > 0) { @@ -2485,11 +2499,22 @@ BCMPOSTTRAPFN(bcm_bprintf)(struct bcmstrbuf *b, const char *fmt, ...) va_start(ap, fmt); +#ifdef BCM_BPRINTF_ALLOW_NULL_B + /* pass NULL to struct bcmstrbuf *b to indicate the output is console */ + if (b == NULL) { + r = vprintf(fmt, ap); + goto exit; + } +#endif /* BCM_BPRINTF_ALLOW_NULL_B */ + r = vsnprintf(b->buf, b->size, fmt, ap); + +#ifndef DONGLEBUILD if (bcm_bprintf_bypass == TRUE) { printf("%s", b->buf); goto exit; } +#endif /* !DONGLEBUILD */ /* Non Ansi C99 compliant returns -1, * Ansi compliant return r >= b->size, @@ -2501,7 +2526,7 @@ BCMPOSTTRAPFN(bcm_bprintf)(struct bcmstrbuf *b, const char *fmt, ...) if ((r == -1) || (r >= (int)b->size)) { b->size = 0; } else { - b->size -= r; + b->size -= (uint)r; b->buf += r; } @@ -2524,6 +2549,24 @@ bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, bcm_bprintf(b, "\n"); } +/* print the buffer in hex string format with the most significant byte first */ +void +bcm_bprhex_msb(struct bcmstrbuf *b, const char *msg, bool newline, + const uint8 *buf, uint len) +{ + int i; + + if (msg != NULL && msg[0] != '\0') { + bcm_bprintf(b, "%s", msg); + } + for (i = (int)len - 1; i >= 0; i --) { + bcm_bprintf(b, "%02X", buf[i]); + } + if (newline) { + bcm_bprintf(b, "\n"); + } +} + void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) { @@ -2631,7 +2674,7 @@ bcm_find_vendor_ie(const void *tlvs, uint tlvs_len, const char *voui, uint8 *ty { /* compare optional type */ if (type_len == 0 || - !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) { + !bcmp(((const char *)ie->data) + DOT11_OUI_LEN, type, type_len)) { COV_TAINTED_DATA_ARG(ie); @@ -2666,7 +2709,7 @@ bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) } else if (bcm_isprint((uchar)c)) { *p++ = (char)c; } else { - p += snprintf(p, (endp - p), "\\x%02X", c); + p += snprintf(p, (size_t)(endp - p), "\\x%02X", c); } } *p = '\0'; @@ -2848,7 +2891,7 @@ bcm_ipv6_ntoa(void *ipv6, char *buf) } #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) -const unsigned char bcm_ctype[256] = { +const unsigned char BCMPOST_TRAP_RODATA(bcm_ctype)[256] = { _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C, @@ -2921,7 +2964,7 @@ bcm_strtoull(const char *cp, char **endp, uint base) result = 0; while (bcm_isxdigit(*cp) && - (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { + (value = (uint64)(bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10)) < base) { result = result*base + value; /* Detected overflow */ if (result < last_result && !minus) { @@ -3058,7 +3101,7 @@ bcmstrtok(char **string, const char *delimiters, char *tokdelim) /* Set bits in delimiter table */ do { - map[*delimiters >> 5] |= (1 << (*delimiters & 31)); + map[*delimiters >> 5] |= (1UL << (*delimiters & 31)); } while (*delimiters++); @@ -3068,7 +3111,7 @@ bcmstrtok(char **string, const char *delimiters, char *tokdelim) * there is no token iff this loop sets str to point to the terminal * null (*str == '\0') */ - while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) { + while (((map[*str >> 5] & (1UL << (*str & 31))) && *str) || (*str == ' ')) { str++; } @@ -3078,7 +3121,7 @@ bcmstrtok(char **string, const char *delimiters, char *tokdelim) * put a null there. */ for (; *str; str++) { - if (map[*str >> 5] & (1 << (*str & 31))) { + if (map[*str >> 5] & (1UL << (*str & 31))) { if (tokdelim != NULL) { *tokdelim = *str; } @@ -3203,7 +3246,7 @@ bcm_atoipv4(const char *p, struct ipv4_addr *ip) #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; -const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; +const struct ether_addr BCMPOST_TRAP_RODATA(ether_null) = {{0, 0, 0, 0, 0, 0}}; const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}}; int @@ -3300,7 +3343,7 @@ bcm_object_trace_init(void) { int i = 0; BCM_OBJDBG_LOCK_INIT(); - memset(&bcm_dbg_objs, 0x00, sizeof(struct bcm_dbgobj) * BCM_OBJDBG_COUNT); + bzero(&bcm_dbg_objs, sizeof(struct bcm_dbgobj) * BCM_OBJDBG_COUNT); dbgobj_freehead = &bcm_dbg_objs[0]; dbgobj_freetail = &bcm_dbg_objs[BCM_OBJDBG_COUNT - 1]; @@ -3545,11 +3588,6 @@ bcm_object_trace_chk(void *obj, uint32 chksn, uint32 sn, while (dbgobj) { if ((dbgobj->obj == obj) && ((!chksn) || (dbgobj->obj_sn == sn))) { -#if 0 - printf("bcm_object_trace_chk: (%s:%d) obj %p was allocated from %s(%d)\n", - caller, line, - dbgobj->obj, dbgobj->caller, dbgobj->line); -#endif /* #if 0 */ if (dbgobj != dbgobj_objtail) { bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail, dbgobj, BCM_OBJDBG_ADDTOTAIL); @@ -3967,7 +4005,7 @@ hndcrc16( return crc; } -static const uint32 crc32_table[256] = { +static const uint32 BCMPOST_TRAP_RODATA(crc32_table)[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, @@ -4039,7 +4077,7 @@ static const uint32 crc32_table[256] = { * accumulating over multiple pieces. */ uint32 -hndcrc32(const uint8 *pdata, uint nbytes, uint32 crc) +BCMPOSTTRAPRAMFN(hndcrc32)(const uint8 *pdata, uint nbytes, uint32 crc) { const uint8 *pend; pend = pdata + nbytes; @@ -4049,42 +4087,6 @@ hndcrc32(const uint8 *pdata, uint nbytes, uint32 crc) return crc; } -#ifdef NOT_YET -#define CLEN 1499 /* CRC Length */ -#define CBUFSIZ (CLEN+4) -#define CNBUFS 5 /* # of bufs */ - -void -testcrc32(void) -{ - uint j, k, l; - uint8 *buf; - uint len[CNBUFS]; - uint32 crcr; - uint32 crc32tv[CNBUFS] = - {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110}; - - ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL); - - /* step through all possible alignments */ - for (l = 0; l <= 4; l++) { - for (j = 0; j < CNBUFS; j++) { - len[j] = CLEN; - for (k = 0; k < len[j]; k++) - *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff; - } - - for (j = 0; j < CNBUFS; j++) { - crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE); - ASSERT(crcr == crc32tv[j]); - } - } - - MFREE(buf, CBUFSIZ*CNBUFS); - return; -} -#endif /* NOT_YET */ - /* * Advance from the current 1-byte tag/1-byte length/variable-length value * triple, to the next, returning a pointer to the next. @@ -4273,7 +4275,9 @@ bcm_parse_tlvs(const void *buf, uint buflen, uint key) break; } /* did we find the ID? */ - if ((elt->id == key)) { + if ((elt->id == key) || + (elt->id == DOT11_MNG_ID_EXT_ID && len > 0 && + elt->data[0] + (uint)DOT11_MNG_ID_EXT_ID == key)) { COV_TAINTED_DATA_ARG(elt); GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); @@ -4455,6 +4459,48 @@ bcm_parse_ordered_tlvs(const void *buf, uint buflen, uint key) } return NULL; } + +/** + * Return a const tlv buffer pointer and length representing the sub-buffer contained + * inside the given 'elt' starting at the given 'body_offset'. + * The function assumes that elt is a valid tlv; the elt pointer and data + * are all in the range of its parent buffer/length. + * + * @param elt pointer to a valid bcm_tlv_t + * @param body_offset offset into the data body of elt + * @param buffer on return, pointer to an offset in elt + * @param buflen on return, length of the buffer to the end of elt + * + * On return, if body_offset is not less than the elt's body length, the *buffer parameter + * will be set to NULL and *buflen parameter will be set to zero. Otherwise, + * *buffer will point to the sub-buffer at the body_offset, and *buflen be the remaining + * bytes in the body. + * E.g. Given a TLV with elt->len == 10, the call + * bcm_tlv_sub_buffer(elt, 4, &buffer, &buflen) + * will result with buffer = elt->data + 4, and buflen = 6. + */ +void +bcm_tlv_sub_buffer(const bcm_tlv_t *elt, uint body_offset, const uint8 **buffer, uint8 *buflen) +{ + if (elt->len > body_offset) { + uint8 body_len = elt->len; + +#if defined(__COVERITY__) + /* The 'body_len' value is tainted in Coverity because it is read from + * the tainted data pointed to by 'elt'. However, bcm_parse_tlvs() verifies + * that the elt pointer is a valid element, so its body length is in the bounds + * of the buffer. + * Clearing the tainted attribute of 'body_len' for Coverity. + */ + __coverity_tainted_data_sanitize__(body_len); +#endif /* __COVERITY__ */ + *buflen = body_len - body_offset; + *buffer = elt->data + body_offset; + } else { + *buflen = 0u; + *buffer = NULL; + } +} #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ uint @@ -4472,7 +4518,7 @@ bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, uint len) for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) { bit = bd->bitfield[i].bit; if ((flags & mask) == bit) { - slen = (int)strlen(name); + slen = strlen(name); if (memcpy_s(buf, len, name, slen + 1) != BCME_OK) { slen = 0; } @@ -4512,7 +4558,7 @@ bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, uint len) flags &= ~bit; /* Print named bit. */ - p += strlcpy(p, name, (end - p)); + p += strlcpy(p, name, (size_t)(end - p)); if (p == end) { /* Truncation error. */ err = TRUE; @@ -4521,7 +4567,7 @@ bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, uint len) /* Add space delimiter if there are more bits. */ if (flags != 0) { - p += strlcpy(p, " ", (end - p)); + p += strlcpy(p, " ", (size_t)(end - p)); if (p == end) { /* Truncation error. */ err = TRUE; @@ -4562,7 +4608,7 @@ bcm_format_octets(const bcm_bit_desc_t *bd, uint bdsz, bit = bd[i].bit; name = bd[i].name; if (isset(addr, bit)) { - nlen = (int)strlen(name); + nlen = strlen(name); slen += nlen; /* need SPACE - for simplicity */ slen += 1; @@ -4664,12 +4710,12 @@ prhex(const char *msg, const uchar *buf, uint nbytes) if (i % 16 == 0) { nchar = snprintf(p, len, " %04x: ", i); /* line prefix */ p += nchar; - len -= nchar; + len -= (uint)nchar; } if (len > 0) { nchar = snprintf(p, len, "%02x ", buf[i]); p += nchar; - len -= nchar; + len -= (uint)nchar; } if (i % 16 == 15) { @@ -4788,8 +4834,9 @@ uint bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array, char *buf, uint32 bufsize) { - uint filled_len; - int len; + int ret; + uint filled_len; + uint len; struct fielddesc *cur_ptr; filled_len = 0; @@ -4798,11 +4845,16 @@ bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc while (bufsize > 1) { if (cur_ptr->nameandfmt == NULL) break; - len = snprintf(buf, bufsize, cur_ptr->nameandfmt, - read_rtn(arg0, arg1, cur_ptr->offset)); /* check for snprintf overflow or error */ - if (len < 0 || (uint32)len >= bufsize) - len = bufsize - 1; + ret = snprintf(buf, bufsize, cur_ptr->nameandfmt, + read_rtn(arg0, arg1, cur_ptr->offset)); + if (ret < 0 || ret >= (int)bufsize) { + /* encoding error from snprintf */ + len = bufsize - 1u; + } else { + len = (uint32)ret; + } + buf += len; bufsize -= len; filled_len += len; @@ -4891,8 +4943,8 @@ bcm_mw_to_qdbm(uint16 mw) { uint8 qdbm; int offset; - uint mw_uint = mw; - uint boundary; + uint16 mw_uint = mw; + uint16 boundary; /* handle boundary case */ if (mw_uint <= 1) @@ -4932,6 +4984,61 @@ BCMPOSTTRAPFN(bcm_bitcount)(const uint8 *bitmap, uint length) return bitcount; } +/* Count 0s or 1s in an octets list from 'from_bit' to 'to_bit' inclusively */ +uint +bcm_count_bits(const uint8 *buf, uint buf_len, uint from_bit, uint to_bit, bool val_1) +{ + uint from; + uint to; + uint len; + uint8 tmp; + uint bits; + + /* sanity check */ + if (to_bit < from_bit) { + return 0u; + } + + /* byte offset */ + from = from_bit >> 3u; + to = to_bit >> 3u; + if (from >= buf_len || to >= buf_len) { + return 0u; + } + + /* count 1s always */ + len = to - from + 1u; + if (len == 1u) { + /* the only octet */ + ASSERT(from == to); + tmp = buf[from]; + tmp &= (0xffu << (from_bit & 7u)); + tmp &= ~(0xffu << ((to_bit & 7u) + 1u)); + bits = bcm_bitcount(&tmp, 1u); + } else { + ASSERT(len >= 2u); + /* the first octet */ + tmp = buf[from]; + tmp &= (0xffu << (from_bit & 7u)); + bits = bcm_bitcount(&tmp, 1u); + /* the middle octet(s) */ + if (len > 2u) { + bits += bcm_bitcount(&buf[from + 1u], len - 2u); + } + /* the last octet */ + tmp = buf[to]; + tmp &= ~(0xffu << ((to_bit & 7u) + 1u)); + bits += bcm_bitcount(&tmp, 1u); + } + + /* calc 0s if requested */ + if (!val_1) { + bits = to_bit - from_bit + 1u - bits; + } + + return bits; +} + static void dump_nvram(char *varbuf, int column, unsigned int n, unsigned int len) { @@ -5210,13 +5317,13 @@ uint16 bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum) { while (len > 1) { - sum += (buf[0] << 8) | buf[1]; + sum += ((uint32)buf[0] << 8) | buf[1]; buf += 2; len -= 2; } if (len > 0) { - sum += (*buf) << 8; + sum += ((uint32)*buf) << 8; } while (sum >> 16) { @@ -5390,7 +5497,7 @@ ipv4_tcp_hdr_cksum(uint8 *ip, uint8 *tcp, uint16 tcp_len) ASSERT(tcp_len >= TCP_MIN_HEADER_LEN); /* pseudo header cksum */ - memset(&tcp_ps, 0, sizeof(tcp_ps)); + bzero(&tcp_ps, sizeof(tcp_ps)); memcpy(&tcp_ps.dst_ip, ip_hdr->dst_ip, IPV4_ADDR_LEN); memcpy(&tcp_ps.src_ip, ip_hdr->src_ip, IPV4_ADDR_LEN); tcp_ps.zero = 0; @@ -5426,7 +5533,7 @@ ipv6_tcp_hdr_cksum(uint8 *ipv6, uint8 *tcp, uint16 tcp_len) ASSERT(tcp_len >= TCP_MIN_HEADER_LEN); /* pseudo header cksum */ - memset((char *)&ipv6_pseudo, 0, sizeof(ipv6_pseudo)); + bzero((char *)&ipv6_pseudo, sizeof(ipv6_pseudo)); memcpy((char *)ipv6_pseudo.saddr, (char *)ipv6_hdr->saddr.addr, sizeof(ipv6_pseudo.saddr)); memcpy((char *)ipv6_pseudo.daddr, (char *)ipv6_hdr->daddr.addr, @@ -5452,9 +5559,9 @@ uint32 sqrt_int(uint32 value) /* Compute integer nearest to square root of input integer value */ for (shift = 0; shift < 32; shift += 2) { - if (((0x40000000 >> shift) + root) <= value) { - value -= ((0x40000000 >> shift) + root); - root = (root >> 1) | (0x40000000 >> shift); + if (((0x40000000u >> shift) + root) <= value) { + value -= ((0x40000000u >> shift) + root); + root = (root >> 1) | (0x40000000u >> shift); } else { root = root >> 1; @@ -5466,6 +5573,7 @@ uint32 sqrt_int(uint32 value) return root; } + /* GROUP 1 --- end */ /* read/write field in a consecutive bits in an octet array. @@ -5530,12 +5638,12 @@ setbits(uint8 *addr, uint size, uint stbit, uint nbits, uint32 val) uint32 getbits(const uint8 *addr, uint size, uint stbit, uint nbits) { - uint fbyte = stbit >> 3; /* first byte */ - uint lbyte = (stbit + nbits - 1) >> 3; /* last byte */ - uint fbit = stbit & 7; /* first bit in the first byte */ - uint rbits = (nbits > 8 - fbit ? - nbits - (8 - fbit) : - 0) & 7; /* remaining bits of the last byte when not 0 */ + uint fbyte = stbit >> 3u; /* first byte */ + uint lbyte = (stbit + nbits - 1u) >> 3u; /* last byte */ + uint fbit = stbit & 7u; /* first bit in the first byte */ + uint rbits = (nbits > 8u - fbit ? + nbits - (8u - fbit) : + 0) & 7u; /* remaining bits of the last byte when not 0 */ uint32 val = 0; uint bits = 0; /* bits in first partial byte */ uint8 mask; @@ -5543,35 +5651,35 @@ getbits(const uint8 *addr, uint size, uint stbit, uint nbits) BCM_REFERENCE(size); - ASSERT(fbyte < size); - ASSERT(lbyte < size); - ASSERT(nbits <= (sizeof(val) << 3)); + ASSERT_FP(fbyte < size); + ASSERT_FP(lbyte < size); + ASSERT_FP(nbits <= (sizeof(val) << 3u)); /* all bits are in the same byte */ if (fbyte == lbyte) { - mask = ((1 << nbits) - 1) << fbit; - val = (addr[fbyte] & mask) >> fbit; + mask = ((1u << nbits) - 1u) << fbit; + val = ((uint32)addr[fbyte] & mask) >> fbit; return val; } /* first partial byte */ if (fbit > 0) { - bits = 8 - fbit; - mask = (0xff << fbit); - val |= (addr[fbyte] & mask) >> fbit; + bits = 8u - fbit; + mask = (0xffu << fbit); + val |= ((uint32)addr[fbyte] & mask) >> fbit; fbyte ++; /* first full byte */ } /* last partial byte */ if (rbits > 0) { - mask = (1 << rbits) - 1; - val |= (addr[lbyte] & mask) << (nbits - rbits); + mask = (1u << rbits) - 1u; + val |= ((uint32)addr[lbyte] & mask) << (nbits - rbits); lbyte --; /* last full byte */ } /* remaining full byte(s) */ for (byte = fbyte; byte <= lbyte; byte ++) { - val |= (addr[byte] << (((byte - fbyte) << 3) + bits)); + val |= ((uint32)addr[byte] << (((byte - fbyte) << 3u) + bits)); } return val; @@ -5734,7 +5842,7 @@ BCMRAMFN(bcm_ether_privacy_mask)(struct ether_addr *addr) /* Count the number of elements not matching a given value in a null terminated array */ int -BCMATTACHFN(array_value_mismatch_count)(uint8 value, uint8 *array, int array_size) +array_value_mismatch_count(uint8 value, uint8 *array, int array_size) { int i; int count = 0; @@ -5753,14 +5861,14 @@ BCMATTACHFN(array_value_mismatch_count)(uint8 value, uint8 *array, int array_siz /* Count the number of non-zero elements in an uint8 array */ int -BCMATTACHFN(array_nonzero_count)(uint8 *array, int array_size) +array_nonzero_count(uint8 *array, int array_size) { return array_value_mismatch_count(0, array, array_size); } /* Count the number of non-zero elements in an int16 array */ int -BCMATTACHFN(array_nonzero_count_int16)(int16 *array, int array_size) +array_nonzero_count_int16(int16 *array, int array_size) { int i; int count = 0; @@ -5775,7 +5883,7 @@ BCMATTACHFN(array_nonzero_count_int16)(int16 *array, int array_size) /* Count the number of zero elements in an uint8 array */ int -BCMATTACHFN(array_zero_count)(uint8 *array, int array_size) +array_zero_count(uint8 *array, int array_size) { int i; int count = 0; @@ -5792,7 +5900,7 @@ BCMATTACHFN(array_zero_count)(uint8 *array, int array_size) * One of array1 or array2 should be non-NULL. The other should be NULL. */ static int -BCMATTACHFN(verify_ordered_array)(uint8 *array1, int16 *array2, int array_size, +verify_ordered_array(uint8 *array1, int16 *array2, int array_size, int range_lo, int range_hi, bool err_if_no_zero_term, bool is_ordered) { int ret; @@ -5840,7 +5948,7 @@ BCMATTACHFN(verify_ordered_array)(uint8 *array1, int16 *array2, int array_size, /* Validate an ordered uint8 configuration array */ int -BCMATTACHFN(verify_ordered_array_uint8)(uint8 *array, int array_size, +verify_ordered_array_uint8(uint8 *array, int array_size, uint8 range_lo, uint8 range_hi) { return verify_ordered_array(array, NULL, array_size, (int)range_lo, (int)range_hi, @@ -5849,7 +5957,7 @@ BCMATTACHFN(verify_ordered_array_uint8)(uint8 *array, int array_size, /* Validate an ordered int16 non-zero-terminated configuration array */ int -BCMATTACHFN(verify_ordered_array_int16)(int16 *array, int array_size, +verify_ordered_array_int16(int16 *array, int array_size, int16 range_lo, int16 range_hi) { return verify_ordered_array(NULL, array, array_size, (int)range_lo, (int)range_hi, @@ -5858,7 +5966,7 @@ BCMATTACHFN(verify_ordered_array_int16)(int16 *array, int array_size, /* Validate all values in an array are in range */ int -BCMATTACHFN(verify_array_values)(uint8 *array, int array_size, +verify_array_values(uint8 *array, int array_size, int range_lo, int range_hi, bool zero_terminated) { int ret = BCME_OK; @@ -5897,20 +6005,21 @@ replace_nvram_variable(char *varbuf, unsigned int buflen, const char *variable, unsigned int *datalen) { char *p; - int variable_heading_len, record_len, variable_record_len = (int)strlen(variable) + 1; + uint variable_heading_len, record_len, variable_record_len = strlen(variable) + 1; char *buf_end = varbuf + buflen; p = strchr(variable, '='); if (!p) { return FALSE; } /* Length of given variable name, followed by '=' */ - variable_heading_len = (int)((const char *)(p + 1) - variable); + variable_heading_len = (uint)((const char *)(p + 1) - variable); /* Scanning NVRAM, record by record up to trailing 0 */ for (p = varbuf; *p; p += strlen(p) + 1) { /* If given variable found - remove it */ if (!strncmp(p, variable, variable_heading_len)) { - record_len = (int)strlen(p) + 1; - memmove_s(p, buf_end - p, p + record_len, buf_end - (p + record_len)); + record_len = strlen(p) + 1; + memmove_s(p, (size_t)(buf_end - p), p + record_len, + (size_t)(buf_end - (p + record_len))); } } /* If buffer does not have space for given variable - return FALSE */ @@ -5918,7 +6027,7 @@ replace_nvram_variable(char *varbuf, unsigned int buflen, const char *variable, return FALSE; } /* Copy given variable to end of buffer */ - memmove_s(p, buf_end - p, variable, variable_record_len); + memmove_s(p, (size_t)(buf_end - p), variable, variable_record_len); /* Adding trailing 0 */ p[variable_record_len] = 0; /* Setting optional output parameter - length of data in buffer */ @@ -5954,7 +6063,7 @@ bcm_get_ceil_pow_2(uint val) #if !defined(BCMDONGLEHOST) /** Initialization of varbuf structure */ void -BCMATTACHFN(varbuf_init)(varbuf_t *b, char *buf, uint size) +varbuf_init(varbuf_t *b, char *buf, uint size) { b->size = size; b->base = b->buf = buf; @@ -5962,7 +6071,7 @@ BCMATTACHFN(varbuf_init)(varbuf_t *b, char *buf, uint size) /** append a null terminated var=value string */ int -BCMATTACHFN(varbuf_append)(varbuf_t *b, const char *fmt, ...) +varbuf_append(varbuf_t *b, const char *fmt, ...) { va_list ap; int r; @@ -5994,7 +6103,7 @@ BCMATTACHFN(varbuf_append)(varbuf_t *b, const char *fmt, ...) for (s = b->base; s < b->buf;) { if ((memcmp(s, b->buf, len) == 0) && s[len] == '=') { len = strlen(s) + 1; - memmove(s, (s + len), ((b->buf + r + 1) - (s + len))); + memmove(s, (s + len), (size_t)((b->buf + r + 1) - (s + len))); b->buf -= len; b->size += (unsigned int)len; break; @@ -6007,7 +6116,7 @@ BCMATTACHFN(varbuf_append)(varbuf_t *b, const char *fmt, ...) /* skip over this string's null termination */ r++; - b->size -= r; + b->size -= (uint)r; b->buf += r; return r; @@ -6019,14 +6128,14 @@ BCMATTACHFN(varbuf_append)(varbuf_t *b, const char *fmt, ...) * Return 0 on success, nonzero on error. */ int -BCMATTACHFN(initvars_table)(osl_t *osh, char *start, char *end, char **vars, +initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count) { - int c = (int)(end - start); + uint c = (uint)(end - start); /* do it only when there is more than just the null string */ if (c > 1) { - char *vp = MALLOC(osh, c); + char *vp = MALLOCZ(osh, c); ASSERT(vp != NULL); if (!vp) return BCME_NOMEM; @@ -6081,6 +6190,307 @@ prhexstr(const char *prefix, const uint8 *buf, uint len, bool newline) } } +/* print the buffer in hex string format with the most significant byte first */ +void +prhexstr_msb(const char *prefix, const uint8 *buf, uint len, bool newline) +{ + if (len > 0) { + int i; + + if (prefix != NULL) { + printf("%s", prefix); + } + for (i = (int)len - 1; i >= 0; i --) { + printf("%02X", buf[i]); + } + if (newline) { + printf("\n"); + } + } +} + +#ifdef DONGLEBUILD +static const char BCMPOST_TRAP_RODATA(bcm_print_string)[] = "%s"; + +int +BCMPOSTTRAPFN(print_string)(const char *str) +{ + return printf(bcm_print_string, str); +} +#endif /* DONGLEBUILD */ + +#ifdef DBG_SEQ_LOG +#define DBG_SEQ_SEQ_LOG_MAX 10000u + +#define DBG_SEQ_SEQ_START (1u << 12u) +#define DBG_SEQ_SEQ_END (1u << 13u) +#define DBG_SEQ_SEQ_MASK 0xFFFu + +#define DBG_SEQ_SEQ_INC_UPDATE(id, seq, flags) \ + do { \ + g_dbg_seq_seq_idx[id]++; \ + g_dbg_seq_seq_idx[id] %= DBG_SEQ_SEQ_LOG_MAX; \ + g_dbg_seq_seq[id][g_dbg_seq_seq_idx[id]] = (seq & DBG_SEQ_SEQ_MASK) | flags; \ + } while (0) + +uint16 g_dbg_seq_last_seq[DBG_SEQ_LOG_ID_MAX] = {0}; +uint16 g_dbg_seq_seq_exp[DBG_SEQ_LOG_ID_MAX] = {0}; +uint16 g_dbg_seq_seq_idx[DBG_SEQ_LOG_ID_MAX] = {0}; +uint16 g_dbg_seq_seq[DBG_SEQ_LOG_ID_MAX][DBG_SEQ_SEQ_LOG_MAX] = {0}; +uint32 g_dbg_seq_pkt[DBG_SEQ_SEQ_LOG_MAX] = {0}; +uint32 g_dbg_seq_pkt_prev_free[DBG_SEQ_SEQ_LOG_MAX] = {0}; + +/** + * @brief Function to log the sequence numbers in a compreesed or uncompressed format. + * + * @param[in] id Debug module ID. Refer to dbg_seq_log_id_t for possible values. + * @param[in] seq Sequence number to log + * @param[in] arg1 User specific argument 1 to log + * @param[in] arg2 User specific argument 2 to log + */ +void dbg_seq_log_seq(dbg_seq_log_id_t id, uint16 seq, void *arg1, void *arg2) +{ +#if DBG_SEQ_LOG_COMPRESSED + /* Storing the sequence numbers in compressed format */ + if ((g_dbg_seq_seq[id][g_dbg_seq_seq_idx[id]] & DBG_SEQ_SEQ_START) && + !(g_dbg_seq_seq[id][g_dbg_seq_seq_idx[id]] & DBG_SEQ_SEQ_END)) { + /* Continuation of the previous contigous logging */ + if ((seq != g_dbg_seq_seq_exp[id]) || (seq == 0)) { + /* If we have received a dicontigous seq number or seq number restart then + * close the logging and start new logging. If the seq numbers are + * contigous, then we don't come here. + */ + if ((g_dbg_seq_seq[id][g_dbg_seq_seq_idx[id]] & DBG_SEQ_SEQ_MASK) == + g_dbg_seq_last_seq[id]) { + /* If the contigous seq number count is just 1, then close the + * current logging in the same index and start a new one. + */ + g_dbg_seq_seq[id][g_dbg_seq_seq_idx[id]] |= DBG_SEQ_SEQ_END; + } else { + /* If the contigous seq number count is > 1, then close the + * current logging in the next index and start a new one. + */ + DBG_SEQ_SEQ_INC_UPDATE(id, g_dbg_seq_last_seq[id], DBG_SEQ_SEQ_END); + } + DBG_SEQ_SEQ_INC_UPDATE(id, seq, DBG_SEQ_SEQ_START); + } + } else { + /* Starting a fresh logging */ + DBG_SEQ_SEQ_INC_UPDATE(id, seq, DBG_SEQ_SEQ_START); + } + + g_dbg_seq_last_seq[id] = seq; + g_dbg_seq_seq_exp[id] = MODINC_POW2(seq, SEQNUM_MAX); +#else + /* Storing the sequence numbers in un-compressed format */ + DBG_SEQ_SEQ_INC_UPDATE(id, seq, (DBG_SEQ_SEQ_START | DBG_SEQ_SEQ_END)); + g_dbg_seq_last_seq[id] = seq; + + if (id == DBG_SEQ_LOG_ID_RX) { + g_dbg_seq_pkt[g_dbg_seq_seq_idx[id]] = (uint32)arg1; + g_dbg_seq_pkt_prev_free[g_dbg_seq_seq_idx[id]] = (uint32)arg2; + } +#endif /* DBG_SEQ_LOG_COMPRESSED */ +} +#endif /* DBG_SEQ_LOG */ + +/* To be used in computing timestamps on log records. Applicable to dumps carrying + * enhanced timestamp records + * inputs: + * The latest Enhanced timestamp versioned message + * Log record time as a 64-bit value + * output: + * FW time of log record in ns + */ + +#define BCMUTILS_EVENT_LOG_TS_CPU_FREQUENCY_MULTIPLE 1000u + +/* Adapted from version 1 timestamp computation in logprint.c:process_event_log_data() */ +static uint64 +bcmutils_event_log_compute_current_time_v1(ets_msg_t *ets_msg, uint32 log_record_time) +{ + uint32 base_cycles; + uint32 cpu_freq; + uint64 base_time; + int64 cycle_count_offset; + + ets_msg_v1_t *ets_msg_v1 = (ets_msg_v1_t *)ets_msg; + + /* ets_msg_v1->cyclecount is the ARM cycle count */ + base_cycles = ets_msg_v1->cyclecount; + cpu_freq = ets_msg_v1->cpu_freq * BCMUTILS_EVENT_LOG_TS_CPU_FREQUENCY_MULTIPLE; + + /* ets_msg_v1->timestamp is in ms and holds sys up time */ + base_time = ets_msg_v1->timestamp; + + cycle_count_offset = log_record_time - base_cycles; + if (cycle_count_offset >= 0) { + base_time += (log_record_time - base_cycles)/cpu_freq; + } else { + /* Negative cycle_count_offset == counter wrapped */ + base_time += (log_record_time + + (0xffffffff - base_cycles))/cpu_freq; + } + + /* basetime is in ms. convert to uint64 and return */ + return base_time; +} + +static uint64 +bcmutils_event_log_compute_current_time_v2(ets_msg_t *ets_msg, uint64 q4_log_record_time) +{ + ets_msg_v2_t *ets_msg_v2 = (ets_msg_v2_t *)ets_msg->data; + uint64 ets_msg_40bit_ptm_time = ets_msg_v2->ets_write_ptm_time & 0xFFFFFFFFFFULL; + uint64 el_40bit_log_record_time = q4_log_record_time << 8; + + uint64 delta_time; + + /* Corner case. The top 40 bits match indicating logging happened in the same time unit + * as recorded RAW PTM time in the ETS message. + */ + if (q4_log_record_time == (ets_msg_40bit_ptm_time >> 8)) { + delta_time = 0; + } else { + delta_time = (el_40bit_log_record_time - ets_msg_40bit_ptm_time) & + 0xFFFFFFFFFFULL; + } + return ets_msg_v2->sysuptime_ns + delta_time; +} + +int +bcmutils_event_log_compute_current_time(void *ets_msg, uint64 log_record_time, uint64 *current_time) +{ + ets_msg_t *ets_msg_ptr = (ets_msg_t *)ets_msg; + + if (ets_msg_ptr == NULL) { + return BCME_ERROR; + } + + if (ets_msg_ptr->version == ENHANCED_TS_MSG_VERSION_1) { + /* log record time is a 32-bit ARM cycle count */ + *current_time = bcmutils_event_log_compute_current_time_v1(ets_msg_ptr, + (uint32) log_record_time); + } else if (ets_msg_ptr->version == ENHANCED_TS_MSG_VERSION_2) { + *current_time = bcmutils_event_log_compute_current_time_v2(ets_msg_ptr, + log_record_time); + } else { + return BCME_VERSION; + } + + return BCME_OK; +} + +#ifdef DBG_PKTID_POOLPKT_PROCESS +uint16 +bcm_mwbmap_total_pktid(struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + return mwbmap_p->total; +} +#endif /* DBG_PKTID_POOLPKT_PROCESS */ + +/** + * @brief Divide the uint64 dividend 'q' by 1,000 + * + * @param[in] dividend + * + * @return quotient + */ +uint64 +BCMPOSTTRAPFASTPATH(div_1K)(uint64 q) +{ + /** 1/1000 fractional bits: 0x004189374BC6A7EF(9DB) + * shift until no leading zeros: 0x83126E97'8D4FDF3B S=9 + */ + + const uint64 d1 = 0x83126E97llu; // first 32 fractional bits + const uint64 d2 = 0x8D4FDF3Bllu; // second 32 fractional bits + const uint64 S = 9llu; + + uint64 a1; + uint64 a; // answer + int carry; + uint32 a_low; + uint32 lo; // low 32 bits of quotient + uint32 hi; // high 32 bits of quotient + + lo = (uint32)q; + hi = (uint32)(q >> 32u); + + // fractional d1/d2 values truncate all lower order bits, so + // add a low order bit to make the fraction slightly higher than the + // exact 1/1000. This allows the final truncation of the answer to + // no come up short. + a1 = lo * (d1 + 1); + a = hi * (d2 + 1) + a1; + + // Detect carry + carry = (a < a1); + + a_low = (uint32)(a >> 32u); + + a = (hi * d1) + a_low; + if (carry) { + a += 0x100000000llu; + } + a = a >> S; + + return a; +} + +/** + * @brief Divide the uint64 dividend 'q' by 1,000,000 + * + * @param[in] dividend + * + * @return quotient + */ +uint64 +BCMPOSTTRAPFASTPATH(div_1M)(uint64 q) +{ + /** 1/1000000 fractional bits: 0x000010C6F7A0B5ED8D36B + * shift until no leading zeros: 0x8637BD05'AF6C69B5 S=19 + */ + + const uint64 d1 = 0x8637BD05llu; // first 32 fractional bits + const uint64 d2 = 0xAF6C69B5llu; // second 32 fractional bits + const uint64 S = 19llu; + + uint64 a1; + uint64 a; // answer + int carry; + uint32 a_low; + uint32 lo; // low 32 bits of quotent + uint32 hi; // high 32 bits of quotent + + lo = (uint32)q; + hi = (uint32)(q >> 32u); + + // fractional d1/d2 values truncate all lower order bits, so + // add a low order bit to make the fraction slightly higher than the + // exact 1/1000. This allows the final truncation of the answer to + // no come up short. + a1 = lo * (d1 + 1); + a = hi * (d2 + 1) + a1; + + // Detect carry + carry = (a < a1); + + a_low = (uint32)(a >> 32u); + + a = (hi * d1) + a_low; + if (carry) { + a += 0x100000000llu; + } + a = a >> S; + + return a; +} + /* Add to adjust the 802.1x priority */ void pktset8021xprio(void *pkt, int prio) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_channels.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_channels.c old mode 100755 new mode 100644 index 938720710a2b..9333915ea703 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_channels.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_channels.c @@ -3,7 +3,7 @@ * Contents are wifi-specific, used by any kernel or app-level * software that might want wifi things as it grows. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -29,7 +29,9 @@ #ifdef BCMDRIVER #include #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) +#ifndef tolower #define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) +#endif #else #include #include @@ -47,6 +49,7 @@ #endif #include <802.11.h> +#include <802.11ac.h> /* Definitions for D11AC capable (80MHz+) Chanspec type */ @@ -184,6 +187,13 @@ static const uint8 wf_5g_160m_chans[] = { #define WFC_BW_EQ(bw, val) (FALSE) #endif +/* compare bandwidth based on WFC_NON_CONT_CHAN */ +#ifdef WFC_NON_CONT_CHAN +#define WFC_NCBW_EQ(bw, val) WFC_2VALS_EQ(bw, val) +#else +#define WFC_NCBW_EQ(bw, val) (FALSE) +#endif + static void wf_chanspec_iter_firstchan(wf_chanspec_iter_t *iter); static chanspec_bw_t wf_iter_next_bw(chanspec_bw_t bw); static bool wf_chanspec_iter_next_2g(wf_chanspec_iter_t *iter); @@ -383,6 +393,88 @@ channel_6g_320mhz_to_id(uint ch) return -1; } +/** + * This function returns the the 5GHz 80MHz center channel for the given chanspec 80MHz ID + * + * @param chan_80MHz_id 80MHz chanspec ID + * + * @return Return the center channel number, or 0 on error. + * + */ +static uint8 +wf_chspec_5G_id80_to_ch(uint8 chan_80MHz_id) +{ + if (chan_80MHz_id < WF_NUM_5G_80M_CHANS) { + return wf_5g_80m_chans[chan_80MHz_id]; + } + + return 0; +} + +/** + * This function returns the the 6GHz 80MHz center channel for the given chanspec 80MHz ID + * + * @param chan_80MHz_id 80MHz chanspec ID + * + * @return Return the center channel number, or 0 on error. + * + */ +static uint8 +wf_chspec_6G_id80_to_ch(uint8 chan_80MHz_id) +{ + uint8 ch = 0; + + if (chan_80MHz_id < WF_NUM_6G_80M_CHANS) { + /* The 6GHz center channels have a spacing of 16 + * starting from the first 80MHz center + */ + ch = CH_MIN_6G_80M_CHANNEL + (chan_80MHz_id * 16); + } + + return ch; +} + +/** + * This function returns the the 5GHz 160MHz center channel for the given chanspec 160MHz ID + * + * @param chan_160MHz_id 160MHz chanspec ID + * + * @return Return the center channel number, or 0 on error. + * + */ +static uint8 +wf_chspec_5G_id160_to_ch(uint8 chan_160MHz_id) +{ + if (chan_160MHz_id < WF_NUM_5G_160M_CHANS) { + return wf_5g_160m_chans[chan_160MHz_id]; + } + + return 0; +} + +/** + * This function returns the the 6GHz 160MHz center channel for the given chanspec 160MHz ID + * + * @param chan_160MHz_id 160MHz chanspec ID + * + * @return Return the center channel number, or 0 on error. + * + */ +static uint8 +wf_chspec_6G_id160_to_ch(uint8 chan_160MHz_id) +{ + uint8 ch = 0; + + if (chan_160MHz_id < WF_NUM_6G_160M_CHANS) { + /* The 6GHz center channels have a spacing of 32 + * starting from the first 160MHz center + */ + ch = CH_MIN_6G_160M_CHANNEL + (chan_160MHz_id * 32); + } + + return ch; +} + /** * This function returns the the 6GHz 240MHz center channel for the given chanspec 240MHz ID * @@ -521,6 +613,24 @@ wf_chspec_ntoa(chanspec_t chspec, char *buf) /* bandwidth and primary20 sideband */ if (CHSPEC_IS20(chspec)) { snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, pri_chan); + } else if (CHSPEC_IS8080(chspec)) { + /* 80+80 */ + uint ch0; + uint ch1; + + /* get the center channels for each frequency segment */ + if (CHSPEC_IS5G(chspec)) { + ch0 = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN0(chspec)); + ch1 = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN1(chspec)); + } else if (CHSPEC_IS6G(chspec)) { + ch0 = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN0(chspec)); + ch1 = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN1(chspec)); + } else { + return NULL; + } + + /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */ + snprintf(buf, CHANSPEC_STR_LEN, "%s%d/80+80/%d-%d", band, pri_chan, ch0, ch1); } else if (CHSPEC_IS240(chspec)) { /* 240 */ const char *bw; @@ -535,6 +645,24 @@ wf_chspec_ntoa(chanspec_t chspec, char *buf) bw = wf_chspec_to_bw_str(chspec); snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, pri_chan, bw); + } else if (CHSPEC_IS160160(chspec)) { + /* 160+160 */ + uint ch0; + uint ch1; + + /* get the center channels for each frequency segment */ + if (CHSPEC_IS5G(chspec)) { + ch0 = wf_chspec_5G_id160_to_ch(CHSPEC_CHAN0(chspec)); + ch1 = wf_chspec_5G_id160_to_ch(CHSPEC_CHAN1(chspec)); + } else if (CHSPEC_IS6G(chspec)) { + ch0 = wf_chspec_6G_id160_to_ch(CHSPEC_CHAN0(chspec)); + ch1 = wf_chspec_6G_id160_to_ch(CHSPEC_CHAN1(chspec)); + } else { + return NULL; + } + + /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */ + snprintf(buf, CHANSPEC_STR_LEN, "%s%d/160+160/%d-%d", band, pri_chan, ch0, ch1); } else { const char *bw; const char *sb = ""; @@ -796,6 +924,40 @@ wf_chspec_malformed(chanspec_t chanspec) } else { return TRUE; } + } else if (WFC_NCBW_EQ(chspec_bw, WL_CHANSPEC_BW_160160)) { + uint ch0_id, ch1_id; + + ch0_id = CHSPEC_CHAN0(chanspec); + ch1_id = CHSPEC_CHAN1(chanspec); + + /* channel IDs in 160+160 must be in range */ + if (CHSPEC_IS5G(chanspec) && + (ch0_id >= WF_NUM_5G_160M_CHANS || ch1_id >= WF_NUM_5G_160M_CHANS)) { + /* bad 160MHz channel ID for the band */ + return TRUE; + } + if (CHSPEC_IS6G(chanspec) && + (ch0_id >= WF_NUM_6G_160M_CHANS || ch1_id >= WF_NUM_6G_160M_CHANS)) { + /* bad 160MHz channel ID for the band */ + return TRUE; + } + } else if (WFC_NCBW_EQ(chspec_bw, WL_CHANSPEC_BW_8080)) { + uint ch0_id, ch1_id; + + ch0_id = CHSPEC_CHAN0(chanspec); + ch1_id = CHSPEC_CHAN1(chanspec); + + /* channel IDs in 80+80 must be in range */ + if (CHSPEC_IS5G(chanspec) && + (ch0_id >= WF_NUM_5G_80M_CHANS || ch1_id >= WF_NUM_5G_80M_CHANS)) { + /* bad 80MHz channel ID for the band */ + return TRUE; + } + if (CHSPEC_IS6G(chanspec) && + (ch0_id >= WF_NUM_6G_80M_CHANS || ch1_id >= WF_NUM_6G_80M_CHANS)) { + /* bad 80MHz channel ID for the band */ + return TRUE; + } } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 || chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) { @@ -827,13 +989,15 @@ wf_chspec_malformed(chanspec_t chanspec) } else if (chspec_bw == WL_CHANSPEC_BW_40) { if (chspec_sb > WL_CHANSPEC_CTL_SB_LLU) return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_80) { + } else if (chspec_bw == WL_CHANSPEC_BW_80 || + WFC_NCBW_EQ(chspec_bw, WL_CHANSPEC_BW_8080)) { /* both 80MHz and 80+80MHz use 80MHz side bands. * 80+80 SB info is relative to the primary 80MHz sub-band. */ if (chspec_sb > WL_CHANSPEC_CTL_SB_LUU) return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_160) { + } else if (chspec_bw == WL_CHANSPEC_BW_160 || + WFC_NCBW_EQ(chspec_bw, WL_CHANSPEC_BW_160160)) { ASSERT(chspec_sb <= WL_CHANSPEC_CTL_SB_UUU); } else if (WFC_BW_EQ(chspec_bw, WL_CHANSPEC_BW_240)) { /* FIXME: define the max sideband index */ @@ -918,6 +1082,45 @@ wf_chspec_valid(chanspec_t chanspec) return wf_valid_320MHz_center_chan(chspec_ch, chspec_band); + } else if (WFC_NCBW_EQ(chspec_bw, WL_CHANSPEC_BW_8080)) { + uint16 ch0 = 0; + uint16 ch1 = 0; + + /* get the center channels for each frequency segment */ + if (CHSPEC_IS5G(chanspec)) { + ch0 = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN0(chanspec)); + ch1 = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN1(chanspec)); + } else if (CHSPEC_IS6G(chanspec)) { + ch0 = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN0(chanspec)); + ch1 = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN1(chanspec)); + } else { + return FALSE; + } + + /* the two channels must be separated by more than 80MHz by VHT req */ + if ((ch1 > ch0 + CH_80MHZ_APART) || + (ch0 > ch1 + CH_80MHZ_APART)) + return TRUE; + } else if (WFC_NCBW_EQ(chspec_bw, WL_CHANSPEC_BW_160160)) { + uint16 ch0 = 0; + uint16 ch1 = 0; + + /* get the center channels for each frequency segment */ + if (CHSPEC_IS5G(chanspec)) { + ch0 = wf_chspec_5G_id160_to_ch(CHSPEC_CHAN0(chanspec)); + ch1 = wf_chspec_5G_id160_to_ch(CHSPEC_CHAN1(chanspec)); + } else if (CHSPEC_IS6G(chanspec)) { + ch0 = wf_chspec_6G_id160_to_ch(CHSPEC_CHAN0(chanspec)); + ch1 = wf_chspec_6G_id160_to_ch(CHSPEC_CHAN1(chanspec)); + } else { + return FALSE; + } + + /* the two channels must be separated by more than 160MHz by EHT req */ + if ((ch1 > ch0 + CH_160MHZ_APART) || + (ch0 > ch1 + CH_160MHZ_APART)) { + return TRUE; + } } return FALSE; @@ -2197,7 +2400,35 @@ wf_chspec_primary20_chan(chanspec_t chspec) sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; } - if (CHSPEC_IS240(chspec)) { + if (CHSPEC_IS8080(chspec)) { + /* For an 80+80 MHz channel, the sideband 'sb' field is an 80 MHz sideband + * (LL, LU, UL, LU) for the 80 MHz frequency segment 0. + */ + + /* use bw 80MHz for the primary channel lookup */ + bw = WL_CHANSPEC_BW_80; + + /* convert from channel index to channel number */ + if (CHSPEC_IS5G(chspec)) { + center_chan = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN0(chspec)); + } else if (CHSPEC_IS6G(chspec)) { + center_chan = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN0(chspec)); + } + } else if (CHSPEC_IS160160(chspec)) { + /* For an 160+160 MHz channel, the sideband 'sb' field is an 160MHz sideband + * for the 160 MHz frequency segment 0. + */ + + /* use bw 160MHz for the primary channel lookup */ + bw = WL_CHANSPEC_BW_160; + + /* convert from channel index to channel number */ + if (CHSPEC_IS5G(chspec)) { + center_chan = wf_chspec_5G_id160_to_ch(CHSPEC_CHAN0(chspec)); + } else if (CHSPEC_IS6G(chspec)) { + center_chan = wf_chspec_6G_id160_to_ch(CHSPEC_CHAN0(chspec)); + } + } else if (CHSPEC_IS240(chspec)) { /* use bw 240MHz for the primary channel lookup */ bw = WL_CHANSPEC_BW_240; @@ -2345,7 +2576,7 @@ wf_chspec_primary40_chspec(chanspec_t chspec) ASSERT(!wf_chspec_malformed(chspec)); /* if the chanspec is > 80MHz, use the helper routine to find the primary 80 MHz channel */ - if (CHSPEC_IS160(chspec)) { + if (CHSPEC_IS8080(chspec) || CHSPEC_IS160(chspec)) { chspec = wf_chspec_primary80_chspec(chspec); } @@ -2373,6 +2604,29 @@ wf_chspec_primary40_chspec(chanspec_t chspec) return chspec40; } +/** + * Return the chanspec band for a given frequency. + * + * @param freq frequency in MHz of the channel center + * + * @return Returns chanspec band of frequency (chanspec_band_t) + */ +chanspec_band_t +wf_mhz2chanspec_band(uint freq) +{ + chanspec_band_t band = INVCHANSPEC; + + if (freq >= 2400u && freq <= 2500u) { + band = WL_CHANSPEC_BAND_2G; + } else if (freq >= 5000u && freq < 5935u) { + band = WL_CHANSPEC_BAND_5G; + } else if (freq >= 5935u && freq <= 7205u) { + band = WL_CHANSPEC_BAND_6G; + } + + return band; +} + /** * Return the channel number for a given frequency and base frequency. * @@ -2674,7 +2928,23 @@ wf_chspec_primary80_chspec(chanspec_t chspec) if (CHSPEC_IS80(chspec)) { chspec80 = chspec; - } else if (CHSPEC_IS160(chspec)) { + } + else if (CHSPEC_IS8080(chspec)) { + sb = CHSPEC_CTL_SB(chspec); + + /* primary sub-band is stored in seg0 */ + if (CHSPEC_IS5G(chspec)) { + center_chan = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN0(chspec)); + } else if (CHSPEC_IS6G(chspec)) { + center_chan = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN0(chspec)); + } else { + center_chan = INVCHANNEL; + } + + /* Create primary 80MHz chanspec */ + chspec80 = (CHSPEC_BAND(chspec) | WL_CHANSPEC_BW_80 | sb | center_chan); + } + else if (CHSPEC_IS160(chspec)) { center_chan = CHSPEC_CHANNEL(chspec); sb = CHSPEC_CTL_SB(chspec); @@ -2709,7 +2979,23 @@ wf_chspec_secondary80_chspec(chanspec_t chspec) ASSERT(!wf_chspec_malformed(chspec)); - if (CHSPEC_IS160(chspec)) { + if (CHSPEC_IS8080(chspec)) { + /* secondary sub-band is stored in seg1 */ + if (CHSPEC_IS5G(chspec)) { + center_chan = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN1(chspec)); + } else if (CHSPEC_IS6G(chspec)) { + center_chan = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN1(chspec)); + } else { + center_chan = INVCHANNEL; + } + + /* Create secondary 80MHz chanspec */ + chspec80 = (CHSPEC_BAND(chspec) | + WL_CHANSPEC_BW_80 | + WL_CHANSPEC_CTL_SB_LL | + center_chan); + } + else if (CHSPEC_IS160(chspec)) { center_chan = CHSPEC_CHANNEL(chspec); if (CHSPEC_CTL_SB(chspec) < WL_CHANSPEC_CTL_SB_ULL) { @@ -2916,6 +3202,8 @@ channel_bw_to_width(chanspec_t chspec) channel_width = VHT_OP_CHAN_WIDTH_80; else if (CHSPEC_IS160(chspec)) channel_width = VHT_OP_CHAN_WIDTH_160; + else if (CHSPEC_IS8080(chspec)) + channel_width = VHT_OP_CHAN_WIDTH_80_80; else channel_width = VHT_OP_CHAN_WIDTH_20_40; @@ -2924,11 +3212,6 @@ channel_bw_to_width(chanspec_t chspec) uint wf_chspec_first_20_sb(chanspec_t chspec) { -#if defined(WL_BW160MHZ) - if (CHSPEC_IS160(chspec)) { - return LLL_20_SB_160(CHSPEC_CHANNEL(chspec)); - } else -#endif if (CHSPEC_IS80(chspec)) { return LL_20_SB(CHSPEC_CHANNEL(chspec)); } else if (CHSPEC_IS40(chspec)) { @@ -2949,6 +3232,56 @@ wf_create_chspec_sb(uint sb, uint center_channel, chanspec_bw_t bw, chanspec_ban return wf_chspec_valid(chspec) ? chspec : INVCHANSPEC; } +chanspec_t +wf_create_8080MHz_chspec_sb(uint sb, uint chan0, uint chan1, chanspec_band_t band) +{ + int chan0_id, chan1_id, seg0, seg1; + chanspec_t chspec; + + if (sb > (WL_CHANSPEC_CTL_SB_UUU >> WL_CHANSPEC_CTL_SB_SHIFT)) { + return INVCHANSPEC; + } + /* From here on sb is not an index, but value for SB field */ + sb <<= WL_CHANSPEC_CTL_SB_SHIFT; + + /* frequency segments need to be non-contiguous, so the channel + * separation needs to be greater than 80MHz + */ + if ((uint)ABS((int)(chan0 - chan1)) <= CH_80MHZ_APART) { + return INVCHANSPEC; + } + + if (band == WL_CHANSPEC_BAND_5G) { + chan0_id = channel_80mhz_to_id(chan0); + chan1_id = channel_80mhz_to_id(chan1); + } else if (band == WL_CHANSPEC_BAND_6G) { + chan0_id = channel_6g_80mhz_to_id(chan0); + chan1_id = channel_6g_80mhz_to_id(chan1); + } else { + return INVCHANSPEC; + } + + /* make sure the channel numbers were valid */ + if ((chan0_id == -1) || (chan1_id == -1)) { + return INVCHANSPEC; + } + /* Optionally swapping channel IDs to make sure that control subchannel + * is in chan0 + */ + if (sb < WL_CHANSPEC_CTL_SB_ULL) { + seg0 = chan0_id; + seg1 = chan1_id; + } else { + seg0 = chan1_id; + seg1 = chan0_id; + sb -= WL_CHANSPEC_CTL_SB_ULL; + } + chspec = ((seg0 << WL_CHANSPEC_CHAN0_SHIFT) | + (seg1 << WL_CHANSPEC_CHAN1_SHIFT) | + sb | WL_CHANSPEC_BW_8080 | band); + return wf_chspec_valid(chspec) ? chspec : INVCHANSPEC; +} + chanspec_t wf_create_160160MHz_chspec_sb(uint sb, uint chan0, uint chan1, chanspec_band_t band) { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_monitor.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_monitor.c deleted file mode 100755 index 1b606eb6eff4..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_monitor.c +++ /dev/null @@ -1,1071 +0,0 @@ -/* - * Monitor Mode routines. - * This header file housing the Monitor Mode routines implementation. - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct monitor_info { - ratespec_t ampdu_rspec; /* spec value for AMPDU sniffing */ - uint16 ampdu_counter; - uint16 amsdu_len; - uint8* amsdu_pkt; - int8 headroom; - d11_info_t *d11_info; - uint8 ampdu_plcp[D11_PHY_HDR_LEN]; -}; - -struct he_ltf_gi_info { - uint8 gi; - uint8 ltf_size; - uint8 num_ltf; -}; - -struct he_mu_ltf_mp_info { - uint8 num_ltf; - uint8 mid_per; -}; - -/* - * su ppdu - mapping of ltf and gi values from plcp to rtap data format - * https://www.radiotap.org/fields/HE.html - */ -static const struct he_ltf_gi_info he_plcp2ltf_gi[4] = { - {3, 0, 7}, /* reserved, reserved, reserved */ - {0, 2, 1}, /* 0.8us, 2x, 2x */ - {1, 2, 1}, /* 1.6us, 2x, 2x */ - {2, 3, 2} /* 3.2us, 4x, 4x */ -}; - -/* - * mu ppdu - mapping of ru type value from phy rxstatus to rtap data format - * https://www.radiotap.org/fields/HE.html - */ -static const uint8 he_mu_phyrxs2ru_type[7] = { - 4, /* 26-tone RU */ - 5, /* 52-tone RU */ - 6, /* 106-tone RU */ - 7, /* 242-tone RU */ - 8, /* 484-tone RU */ - 9, /* 996-tone RU */ - 10 /* 2x996-tone RU */ -}; - -/* - * mu ppdu - doppler:1, mapping of ltf and midamble periodicity values from plcp to rtap data format - * https://www.radiotap.org/fields/HE.html - */ -static const struct he_mu_ltf_mp_info he_mu_plcp2ltf_mp[8] = { - {0, 0}, /* 1x, 10 */ - {1, 0}, /* 2x, 10 */ - {2, 0}, /* 4x, 10 */ - {7, 0}, /* reserved, reserved */ - {0, 1}, /* 1x, 20 */ - {1, 1}, /* 2x, 20 */ - {2, 1}, /* 4x, 20 */ - {7, 0} /* reserved, reserved */ -}; - -/* - * mu ppdu - doppler:0, mapping of ltf value from plcp to rtap data format - * https://www.radiotap.org/fields/HE.html - */ -static const uint8 he_mu_plcp2ltf[8] = { - 0, /* 1x */ - 1, /* 2x */ - 2, /* 4x */ - 3, /* 6x */ - 4, /* 8x */ - 7, /* reserved */ - 7, /* reserved */ - 7 /* reserved */ -}; - -/** Calculate the rate of a received frame and return it as a ratespec (monitor mode) */ -static ratespec_t -BCMFASTPATH(wlc_recv_mon_compute_rspec)(monitor_info_t* info, wlc_d11rxhdr_t *wrxh, uint8 *plcp) -{ - d11rxhdr_t *rxh = &wrxh->rxhdr; - ratespec_t rspec = 0; - uint16 phy_ft; - uint corerev = info->d11_info->major_revid; - uint corerev_minor = info->d11_info->minor_revid; - BCM_REFERENCE(corerev_minor); - - phy_ft = D11PPDU_FT(rxh, corerev); - switch (phy_ft) { - case FT_CCK: - rspec = CCK_RSPEC(CCK_PHY2MAC_RATE(((cck_phy_hdr_t *)plcp)->signal)); - rspec |= WL_RSPEC_BW_20MHZ; - break; - case FT_OFDM: - rspec = OFDM_RSPEC(OFDM_PHY2MAC_RATE(((ofdm_phy_hdr_t *)plcp)->rlpt[0])); - rspec |= WL_RSPEC_BW_20MHZ; - break; - case FT_HT: { - uint ht_sig1, ht_sig2; - uint8 stbc; - - ht_sig1 = plcp[0]; /* only interested in low 8 bits */ - ht_sig2 = plcp[3] | (plcp[4] << 8); /* only interested in low 10 bits */ - - rspec = HT_RSPEC((ht_sig1 & HT_SIG1_MCS_MASK)); - if (ht_sig1 & HT_SIG1_CBW) { - /* indicate rspec is for 40 MHz mode */ - rspec |= WL_RSPEC_BW_40MHZ; - } else { - /* indicate rspec is for 20 MHz mode */ - rspec |= WL_RSPEC_BW_20MHZ; - } - if (ht_sig2 & HT_SIG2_SHORT_GI) - rspec |= WL_RSPEC_SGI; - if (ht_sig2 & HT_SIG2_FEC_CODING) - rspec |= WL_RSPEC_LDPC; - stbc = ((ht_sig2 & HT_SIG2_STBC_MASK) >> HT_SIG2_STBC_SHIFT); - if (stbc != 0) { - rspec |= WL_RSPEC_STBC; - } - break; - } - case FT_VHT: - rspec = wf_vht_plcp_to_rspec(plcp); - break; -#ifdef WL11AX - case FT_HE: - rspec = wf_he_plcp_to_rspec(plcp); - break; -#endif /* WL11AX */ -#ifdef WL11BE - case FT_EHT: - rspec = wf_eht_plcp_to_rspec(plcp); - break; -#endif - default: - /* return a valid rspec if not a debug/assert build */ - rspec = OFDM_RSPEC(6) | WL_RSPEC_BW_20MHZ; - break; - } - - return rspec; -} /* wlc_recv_compute_rspec */ - -static void -wlc_he_su_fill_rtap_data(struct wl_rxsts *sts, uint8 *plcp) -{ - ASSERT(plcp); - - /* he ppdu format */ - sts->data1 |= WL_RXS_HEF_SIGA_PPDU_SU; - - /* bss color */ - sts->data1 |= WL_RXS_HEF_SIGA_BSS_COLOR; - sts->data3 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, BSS_COLOR); - - /* beam change */ - sts->data1 |= WL_RXS_HEF_SIGA_BEAM_CHANGE; - sts->data3 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, BEAM_CHANGE); - - /* ul/dl */ - sts->data1 |= WL_RXS_HEF_SIGA_DL_UL; - sts->data3 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, DL_UL); - - /* data mcs */ - sts->data1 |= WL_RXS_HEF_SIGA_MCS; - sts->data3 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, MCS); - - /* data dcm */ - sts->data1 |= WL_RXS_HEF_SIGA_DCM; - sts->data3 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, DCM); - - /* coding */ - sts->data1 |= WL_RXS_HEF_SIGA_CODING; - sts->data3 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, CODING); - - /* ldpc extra symbol segment */ - sts->data1 |= WL_RXS_HEF_SIGA_LDPC; - sts->data3 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, LDPC); - - /* stbc */ - sts->data1 |= WL_RXS_HEF_SIGA_STBC; - sts->data3 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, STBC); - - /* spatial reuse */ - sts->data1 |= WL_RXS_HEF_SIGA_SPATIAL_REUSE; - sts->data4 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, SR); - - /* data bw */ - sts->data1 |= WL_RXS_HEF_SIGA_BW; - sts->data5 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, BW); - - /* gi */ - sts->data2 |= WL_RXS_HEF_SIGA_GI; - sts->data5 |= HE_PACK_RTAP_GI_LTF_FROM_PLCP(plcp, SU, GI, gi); - - /* ltf symbol size */ - sts->data2 |= WL_RXS_HEF_SIGA_LTF_SIZE; - sts->data5 |= HE_PACK_RTAP_GI_LTF_FROM_PLCP(plcp, SU, LTF_SIZE, ltf_size); - - /* number of ltf symbols */ - sts->data2 |= WL_RXS_HEF_SIGA_NUM_LTF; - sts->data5 |= HE_PACK_RTAP_GI_LTF_FROM_PLCP(plcp, SU, NUM_LTF, num_ltf); - - /* pre-fec padding factor */ - sts->data2 |= WL_RXS_HEF_SIGA_PADDING; - sts->data5 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, PADDING); - - /* txbf */ - sts->data2 |= WL_RXS_HEF_SIGA_TXBF; - sts->data5 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, TXBF); - - /* pe disambiguity */ - sts->data2 |= WL_RXS_HEF_SIGA_PE; - sts->data5 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, PE); - - /* - * if doppler (bit:41) is set in plcp to 1 then, - * - bit:25 indicates 'midamble periodicity' - * - bit:23-24 indicate 'nsts' - * - * if doppler (bit:41) is set to 0 then, - * - bit:23-25 indicate 'nsts' - */ - if (HE_EXTRACT_FROM_PLCP(plcp, SU, DOPPLER)) { - /* doppler */ - sts->data1 |= WL_RXS_HEF_SIGA_DOPPLER; - sts->data6 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, DOPPLER); - - /* midamble periodicity */ - sts->data2 |= WL_RXS_HEF_SIGA_MIDAMBLE; - sts->data6 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, MIDAMBLE); - - /* nsts */ - sts->data6 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, DOPPLER_SET_NSTS); - } else { - /* nsts */ - sts->data6 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, DOPPLER_NOTSET_NSTS); - } - - /* txop */ - sts->data2 |= WL_RXS_HEF_SIGA_TXOP; - sts->data6 |= HE_PACK_RTAP_FROM_PLCP(plcp, SU, TXOP); -} - -static void -wlc_he_dl_ofdma_fill_rtap_data(struct wl_rxsts *sts, d11rxhdr_t *rxh, - uint8 *plcp, uint32 corerev, uint32 corerev_minor) -{ - uint8 doppler, midamble, val; - ASSERT(rxh); - ASSERT(plcp); - - /* he ppdu format */ - sts->data1 |= WL_RXS_HEF_SIGA_PPDU_MU; - - /* bss color */ - sts->data1 |= WL_RXS_HEF_SIGA_BSS_COLOR; - sts->data3 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, BSS_COLOR); - - /* beam change (doesn't apply to mu ppdu) */ - sts->data1 &= ~WL_RXS_HEF_SIGA_BEAM_CHANGE; - - /* ul/dl */ - sts->data1 |= WL_RXS_HEF_SIGA_DL_UL; - sts->data3 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, DL_UL); - - /* data mcs */ - sts->data1 |= WL_RXS_HEF_SIGA_MCS; - sts->data3 |= HE_PACK_RTAP_FROM_PRXS(rxh, corerev, corerev_minor, MCS); - - /* data dcm */ - sts->data1 |= WL_RXS_HEF_SIGA_DCM; - sts->data3 |= HE_PACK_RTAP_FROM_PRXS(rxh, corerev, corerev_minor, DCM); - - /* coding */ - sts->data1 |= WL_RXS_HEF_SIGA_CODING; - sts->data3 |= HE_PACK_RTAP_FROM_PRXS(rxh, corerev, corerev_minor, CODING); - - /* ldpc extra symbol segment */ - sts->data1 |= WL_RXS_HEF_SIGA_LDPC; - sts->data3 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, LDPC); - - /* stbc */ - sts->data1 |= WL_RXS_HEF_SIGA_STBC; - sts->data3 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, STBC); - - /* spatial reuse */ - sts->data1 |= WL_RXS_HEF_SIGA_SPATIAL_REUSE; - sts->data4 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, SR); - - /* sta-id */ - sts->data1 |= WL_RXS_HEF_SIGA_STA_ID; - sts->data4 |= HE_PACK_RTAP_FROM_PRXS(rxh, corerev, corerev_minor, STAID); - - /* ru allocation */ - val = he_mu_phyrxs2ru_type[D11PPDU_RU_TYPE(rxh, corerev, corerev_minor)]; - sts->data1 |= WL_RXS_HEF_SIGA_RU_ALLOC; - sts->data5 |= HE_PACK_RTAP_FROM_VAL(val, RU_ALLOC); - - /* doppler */ - sts->data1 |= WL_RXS_HEF_SIGA_DOPPLER; - sts->data6 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, DOPPLER); - - doppler = HE_EXTRACT_FROM_PLCP(plcp, MU, DOPPLER); - midamble = HE_EXTRACT_FROM_PLCP(plcp, MU, MIDAMBLE); - if (doppler) { - /* number of ltf symbols */ - val = he_mu_plcp2ltf_mp[midamble].num_ltf; - sts->data2 |= WL_RXS_HEF_SIGA_NUM_LTF; - sts->data5 |= HE_PACK_RTAP_FROM_VAL(val, NUM_LTF); - - /* midamble periodicity */ - val = he_mu_plcp2ltf_mp[midamble].mid_per; - sts->data2 |= WL_RXS_HEF_SIGA_MIDAMBLE; - sts->data6 |= HE_PACK_RTAP_FROM_VAL(val, MIDAMBLE); - } else { - /* number of ltf symbols */ - val = he_mu_plcp2ltf[midamble]; - sts->data2 |= WL_RXS_HEF_SIGA_NUM_LTF; - sts->data5 |= HE_PACK_RTAP_FROM_VAL(val, NUM_LTF); - } - - /* nsts */ - sts->data6 |= HE_PACK_RTAP_FROM_PRXS(rxh, corerev, corerev_minor, NSTS); - - /* gi */ - sts->data2 |= WL_RXS_HEF_SIGA_GI; - sts->data5 |= HE_PACK_RTAP_GI_LTF_FROM_PLCP(plcp, MU, GI, gi); - - /* ltf symbol size */ - sts->data2 |= WL_RXS_HEF_SIGA_LTF_SIZE; - sts->data5 |= HE_PACK_RTAP_GI_LTF_FROM_PLCP(plcp, MU, LTF_SIZE, ltf_size); - - /* pre-fec padding factor */ - sts->data2 |= WL_RXS_HEF_SIGA_PADDING; - sts->data5 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, PADDING); - - /* txbf */ - sts->data2 |= WL_RXS_HEF_SIGA_TXBF; - sts->data5 |= HE_PACK_RTAP_FROM_PRXS(rxh, corerev, corerev_minor, TXBF); - - /* pe disambiguity */ - sts->data2 |= WL_RXS_HEF_SIGA_PE; - sts->data5 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, PE); - - /* txop */ - sts->data2 |= WL_RXS_HEF_SIGA_TXOP; - sts->data6 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, TXOP); -} - -static void -wlc_he_dl_ofdma_fill_rtap_flag(struct wl_rxsts *sts, uint8 *plcp, uint32 corerev) -{ - ASSERT(plcp); - - /* sig-b mcs */ - sts->flag1 |= WL_RXS_HEF_SIGB_MCS_KNOWN; - sts->flag1 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, SIGB_MCS); - - /* sig-b dcm */ - sts->flag1 |= WL_RXS_HEF_SIGB_DCM_KNOWN; - sts->flag1 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, SIGB_DCM); - - /* sig-b compression */ - sts->flag1 |= WL_RXS_HEF_SIGB_COMP_KNOWN; - sts->flag2 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, SIGB_COMP); - - /* # of he-sig-b symbols/mu-mimo users */ - sts->flag1 |= WL_RXS_HEF_NUM_SIGB_SYMB_KNOWN; - sts->flag2 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, SIGB_SYM_MU_MIMO_USER); - - /* bandwidth from bandwidth field in he-sig-a */ - sts->flag2 |= WL_RXS_HEF_BW_SIGA_KNOWN; - sts->flag2 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, BW_SIGA); - - /* preamble puncturing from bandwidth field in he-sig-a */ - sts->flag2 |= WL_RXS_HEF_PREPUNCR_SIGA_KNOWN; - sts->flag2 |= HE_PACK_RTAP_FROM_PLCP(plcp, MU, PRE_PUNCR_SIGA); -} - -static void -wlc_he_ul_ofdma_fill_rtap_data(struct wl_rxsts *sts, d11rxhdr_t *rxh, uint8 *plcp, - uint32 corerev) -{ - ASSERT(rxh); - ASSERT(plcp); - - BCM_REFERENCE(rxh); - - /* he ppdu format */ - sts->data1 |= WL_RXS_HEF_SIGA_PPDU_TRIG; - - /* bss color */ - sts->data1 |= WL_RXS_HEF_SIGA_BSS_COLOR; - sts->data3 |= HE_PACK_RTAP_FROM_PLCP(plcp, TRIG, BSS_COLOR); - - /* beam change (doesn't apply to mu ppdu) */ - sts->data1 &= ~WL_RXS_HEF_SIGA_BEAM_CHANGE; - - /* ul/dl */ - sts->data1 |= WL_RXS_HEF_SIGA_DL_UL; - sts->data3 |= HE_PACK_RTAP_FROM_VAL(1, DL_UL); - - /* txop */ - sts->data2 |= WL_RXS_HEF_SIGA_TXOP; - sts->data6 |= HE_PACK_RTAP_FROM_PLCP(plcp, TRIG, TXOP); -} - -/* recover 32bit TSF value from the 16bit TSF value */ -/* assumption is time in rxh is within 65ms of the current tsf */ -/* local TSF inserted in the rxh is at RxStart which is before 802.11 header */ -static uint32 -wlc_recover_tsf32(uint16 rxh_tsf, uint32 ts_tsf) -{ - uint16 rfdly; - - /* adjust rx dly added in RxTSFTime */ - /* comment in d11.h: - * BWL_PRE_PACKED_STRUCT struct d11rxhdr { - * ... - * uint16 RxTSFTime; RxTSFTime time of first MAC symbol + M_PHY_PLCPRX_DLY - * ... - * } - */ - - /* TODO: add PHY type specific value here... */ - rfdly = M_BPHY_PLCPRX_DLY; - - rxh_tsf -= rfdly; - - return (((ts_tsf - rxh_tsf) & 0xFFFF0000) | rxh_tsf); -} - -static uint8 -wlc_vht_get_gid(uint8 *plcp) -{ - uint32 plcp0 = plcp[0] | (plcp[1] << 8); - return (plcp0 & VHT_SIGA1_GID_MASK) >> VHT_SIGA1_GID_SHIFT; -} - -static uint16 -wlc_vht_get_aid(uint8 *plcp) -{ - uint32 plcp0 = plcp[0] | (plcp[1] << 8) | (plcp[2] << 16); - return (plcp0 & VHT_SIGA1_PARTIAL_AID_MASK) >> VHT_SIGA1_PARTIAL_AID_SHIFT; -} - -static bool -wlc_vht_get_txop_ps_not_allowed(uint8 *plcp) -{ - return !!(plcp[2] & (VHT_SIGA1_TXOP_PS_NOT_ALLOWED >> 16)); -} - -static bool -wlc_vht_get_sgi_nsym_da(uint8 *plcp) -{ - return !!(plcp[3] & VHT_SIGA2_GI_W_MOD10); -} - -static bool -wlc_vht_get_ldpc_extra_symbol(uint8 *plcp) -{ - return !!(plcp[3] & VHT_SIGA2_LDPC_EXTRA_OFDM_SYM); -} - -static bool -wlc_vht_get_beamformed(uint8 *plcp) -{ - return !!(plcp[4] & (VHT_SIGA2_BEAMFORM_ENABLE >> 8)); -} -/* Convert htflags and mcs values to -* rate in units of 500kbps -*/ -static uint16 -wlc_ht_phy_get_rate(uint8 htflags, uint8 mcs) -{ - - ratespec_t rspec = HT_RSPEC(mcs); - - if (htflags & WL_RXS_HTF_40) - rspec |= WL_RSPEC_BW_40MHZ; - - if (htflags & WL_RXS_HTF_SGI) - rspec |= WL_RSPEC_SGI; - - return RSPEC2KBPS(rspec)/500; -} - -static void -bcmwifi_update_rxpwr_per_ant(monitor_pkt_rxsts_t *pkt_rxsts, wlc_d11rxhdr_t *wrxh) -{ - int i = 0; - wlc_d11rxhdr_ext_t *wrxh_ext = (wlc_d11rxhdr_ext_t *)((uint8 *)wrxh - WLC_SWRXHDR_EXT_LEN); - - BCM_REFERENCE(wrxh_ext); - - pkt_rxsts->corenum = 0; - - for (i = 0; i < WL_RSSI_ANT_MAX; i++) { -#ifdef BCM_MON_QDBM_RSSI - pkt_rxsts->rxpwr[i].dBm = wrxh_ext->rxpwr[i].dBm; - pkt_rxsts->rxpwr[i].decidBm = wrxh_ext->rxpwr[i].decidBm; -#else - pkt_rxsts->rxpwr[i].dBm = wrxh->rxpwr[i]; - pkt_rxsts->rxpwr[i].decidBm = 0; -#endif - if (pkt_rxsts->rxpwr[i].dBm == 0) { - break; - } - pkt_rxsts->corenum ++; - } -} - -static void -bcmwifi_parse_ampdu(monitor_info_t *info, d11rxhdr_t *rxh, uint16 subtype, ratespec_t rspec, - uint8 *plcp, struct wl_rxsts *sts) -{ - uint32 corerev = info->d11_info->major_revid; - uint32 corerev_minor = info->d11_info->minor_revid; - uint32 ft = D11PPDU_FT(rxh, corerev); - uint8 plcp_len = D11_PHY_RXPLCP_LEN(corerev); - BCM_REFERENCE(corerev_minor); - if ((subtype == FC_SUBTYPE_QOS_DATA) || (subtype == FC_SUBTYPE_QOS_NULL)) { - /* A-MPDU parsing */ - switch (ft) { - case FT_HT: - if (WLC_IS_MIMO_PLCP_AMPDU(plcp)) { - sts->nfrmtype |= WL_RXS_NFRM_AMPDU_FIRST; - /* Save the rspec & plcp for later */ - info->ampdu_rspec = rspec; - /* src & dst len are same */ - (void)memcpy_s(info->ampdu_plcp, plcp_len, plcp, plcp_len); - } else if (!PLCP_VALID(plcp)) { - sts->nfrmtype |= WL_RXS_NFRM_AMPDU_SUB; - /* Use the saved rspec & plcp */ - rspec = info->ampdu_rspec; - /* src & dst len are same */ - (void)memcpy_s(plcp, plcp_len, info->ampdu_plcp, plcp_len); - } - break; - - case FT_VHT: - case FT_HE: - case FT_EHT: - if (PLCP_VALID(plcp) && - !IS_PHYRXHDR_VALID(rxh, corerev, corerev_minor)) { - /* First MPDU: - * PLCP header is valid, Phy RxStatus is not valid - */ - sts->nfrmtype |= WL_RXS_NFRM_AMPDU_FIRST; - /* Save the rspec & plcp for later */ - info->ampdu_rspec = rspec; - /* src & dst len are same */ - (void)memcpy_s(info->ampdu_plcp, plcp_len, plcp, plcp_len); - info->ampdu_counter++; - } else if (!PLCP_VALID(plcp) && - !IS_PHYRXHDR_VALID(rxh, corerev, corerev_minor)) { - /* Sub MPDU: * PLCP header is not valid, - * Phy RxStatus is not valid - */ - sts->nfrmtype |= WL_RXS_NFRM_AMPDU_SUB; - /* Use the saved rspec & plcp */ - rspec = info->ampdu_rspec; - /* src & dst len are same */ - (void)memcpy_s(plcp, plcp_len, info->ampdu_plcp, plcp_len); - } else if (PLCP_VALID(plcp) && - IS_PHYRXHDR_VALID(rxh, corerev, corerev_minor)) { - /* MPDU is not a part of A-MPDU: - * PLCP header is valid and Phy RxStatus is valid - */ - info->ampdu_counter++; - } else { - /* Last MPDU */ - /* done to take care of the last MPDU in A-mpdu - * VHT packets are considered A-mpdu - * Use the saved rspec - */ - rspec = info->ampdu_rspec; - /* src & dst len are same */ - (void)memcpy_s(plcp, plcp_len, info->ampdu_plcp, plcp_len); - } - - sts->ampdu_counter = info->ampdu_counter; - break; - - case FT_OFDM: - break; - default: - printf("invalid frame type: %d\n", ft); - break; - } - } -} - -static void -bcmwifi_update_rate_modulation_info(monitor_info_t *info, d11rxhdr_t *rxh, d11rxhdr_t *rxh_last, - ratespec_t rspec, uint8* plcp, struct wl_rxsts *sts) -{ - uint32 corerev = info->d11_info->major_revid; - uint32 corerev_minor = info->d11_info->minor_revid; - - /* prepare rate/modulation info */ - if (RSPEC_ISVHT(rspec)) { - uint32 bw = RSPEC_BW(rspec); - /* prepare VHT rate/modulation info */ - sts->nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; - sts->mcs = (rspec & WL_RSPEC_VHT_MCS_MASK); - - if (CHSPEC_IS80(sts->chanspec)) { - if (bw == WL_RSPEC_BW_20MHZ) { - switch (CHSPEC_CTL_SB(sts->chanspec)) { - default: - case WL_CHANSPEC_CTL_SB_LL: - sts->bw = WL_RXS_VHT_BW_20LL; - break; - case WL_CHANSPEC_CTL_SB_LU: - sts->bw = WL_RXS_VHT_BW_20LU; - break; - case WL_CHANSPEC_CTL_SB_UL: - sts->bw = WL_RXS_VHT_BW_20UL; - break; - case WL_CHANSPEC_CTL_SB_UU: - sts->bw = WL_RXS_VHT_BW_20UU; - break; - } - } else if (bw == WL_RSPEC_BW_40MHZ) { - switch (CHSPEC_CTL_SB(sts->chanspec)) { - default: - case WL_CHANSPEC_CTL_SB_L: - sts->bw = WL_RXS_VHT_BW_40L; - break; - case WL_CHANSPEC_CTL_SB_U: - sts->bw = WL_RXS_VHT_BW_40U; - break; - } - } else { - sts->bw = WL_RXS_VHT_BW_80; - } - } else if (CHSPEC_IS40(sts->chanspec)) { - if (bw == WL_RSPEC_BW_20MHZ) { - switch (CHSPEC_CTL_SB(sts->chanspec)) { - default: - case WL_CHANSPEC_CTL_SB_L: - sts->bw = WL_RXS_VHT_BW_20L; - break; - case WL_CHANSPEC_CTL_SB_U: - sts->bw = WL_RXS_VHT_BW_20U; - break; - } - } else if (bw == WL_RSPEC_BW_40MHZ) { - sts->bw = WL_RXS_VHT_BW_40; - } - } else { - sts->bw = WL_RXS_VHT_BW_20; - } - - if (RSPEC_ISSTBC(rspec)) - sts->vhtflags |= WL_RXS_VHTF_STBC; - if (wlc_vht_get_txop_ps_not_allowed(plcp)) - sts->vhtflags |= WL_RXS_VHTF_TXOP_PS; - if (RSPEC_ISSGI(rspec)) { - sts->vhtflags |= WL_RXS_VHTF_SGI; - if (wlc_vht_get_sgi_nsym_da(plcp)) - sts->vhtflags |= WL_RXS_VHTF_SGI_NSYM_DA; - } - if (RSPEC_ISLDPC(rspec)) { - sts->coding = WL_RXS_VHTF_CODING_LDCP; - if (wlc_vht_get_ldpc_extra_symbol(plcp)) { - /* need to un-set for MU-MIMO */ - sts->vhtflags |= WL_RXS_VHTF_LDPC_EXTRA; - } - } - if (wlc_vht_get_beamformed(plcp)) - sts->vhtflags |= WL_RXS_VHTF_BF; - - sts->gid = wlc_vht_get_gid(plcp); - sts->aid = wlc_vht_get_aid(plcp); - sts->datarate = RSPEC2KBPS(rspec)/500; - } else if (RSPEC_ISHT(rspec)) { - /* prepare HT rate/modulation info */ - sts->mcs = (rspec & WL_RSPEC_HT_MCS_MASK); - - if (CHSPEC_IS40(sts->chanspec) || CHSPEC_IS80(sts->chanspec)) { - uint32 bw = RSPEC_BW(rspec); - - if (bw == WL_RSPEC_BW_20MHZ) { - if (CHSPEC_CTL_SB(sts->chanspec) == WL_CHANSPEC_CTL_SB_L) { - sts->htflags = WL_RXS_HTF_20L; - } else { - sts->htflags = WL_RXS_HTF_20U; - } - } else if (bw == WL_RSPEC_BW_40MHZ) { - sts->htflags = WL_RXS_HTF_40; - } - } - - if (RSPEC_ISSGI(rspec)) - sts->htflags |= WL_RXS_HTF_SGI; - if (RSPEC_ISLDPC(rspec)) - sts->htflags |= WL_RXS_HTF_LDPC; - if (RSPEC_ISSTBC(rspec)) - sts->htflags |= (1 << WL_RXS_HTF_STBC_SHIFT); - - sts->datarate = wlc_ht_phy_get_rate(sts->htflags, sts->mcs); - } else if (FALSE || -#ifdef WL11BE - RSPEC_ISHEEXT(rspec) || -#else - RSPEC_ISHE(rspec) || -#endif - FALSE) { - sts->nss = (rspec & WL_RSPEC_NSS_MASK) >> WL_RSPEC_NSS_SHIFT; - sts->mcs = (rspec & WL_RSPEC_MCS_MASK); - - if (D11PPDU_ISMU_REV80(rxh_last, corerev, corerev_minor)) { - if (IS_PHYRXHDR_VALID(rxh_last, corerev, corerev_minor)) { - uint16 ff_type = D11PPDU_FF_TYPE(rxh_last, - corerev, corerev_minor); - - switch (ff_type) { - case HE_MU_PPDU: - wlc_he_dl_ofdma_fill_rtap_data(sts, rxh_last, - plcp, corerev, corerev_minor); - wlc_he_dl_ofdma_fill_rtap_flag(sts, plcp, corerev); - break; - case HE_TRIG_PPDU: - wlc_he_ul_ofdma_fill_rtap_data(sts, rxh_last, - plcp, corerev); - break; - default: - /* should not have come here */ - ASSERT(0); - break; - } - } - } else { - /* frame format is either SU or SU_RE (assumption only SU is supported) */ - wlc_he_su_fill_rtap_data(sts, plcp); - } - } else { - /* round non-HT data rate to nearest 500bkps unit */ - sts->datarate = RSPEC2KBPS(rspec)/500; - } -} - -/* Convert RX hardware status to standard format and send to wl_monitor - * assume p points to plcp header - */ -static uint16 -wl_d11rx_to_rxsts(monitor_info_t* info, monitor_pkt_info_t* pkt_info, wlc_d11rxhdr_t *wrxh, - wlc_d11rxhdr_t *wrxh_last, void *pkt, uint16 len, void* pout, uint16 pad_req) -{ - struct wl_rxsts sts; - monitor_pkt_rxsts_t pkt_rxsts; - ratespec_t rspec; - uint16 chan_num; - uint8 *plcp; - uint8 *p = (uint8*)pkt; - uint8 hwrxoff = 0; - uint32 corerev = 0; - uint32 corerev_minor = 0; - struct dot11_header *h; - uint16 subtype; - d11rxhdr_t *rxh = &(wrxh->rxhdr); - d11rxhdr_t *rxh_last = &(wrxh_last->rxhdr); - d11_info_t* d11i = info->d11_info; - uint8 plcp_len = 0; - - BCM_REFERENCE(chan_num); - - ASSERT(p); - ASSERT(info); - pkt_rxsts.rxsts = &sts; - - hwrxoff = (pkt_info->marker >> 16) & 0xff; - corerev = d11i->major_revid; - corerev_minor = d11i->minor_revid; - BCM_REFERENCE(corerev_minor); - - plcp = (uint8*)p + hwrxoff; - plcp_len = D11_PHY_RXPLCP_LEN(corerev); - - /* only non short rxstatus is expected */ - if (IS_D11RXHDRSHORT(rxh, corerev, corerev_minor)) { - printf("short rxstatus is not expected here!\n"); - ASSERT(0); - return 0; - } - - if (RXHDR_GET_PAD_PRES(rxh, corerev, corerev_minor)) { - plcp += 2; - } - - bzero((void *)&sts, sizeof(wl_rxsts_t)); - - sts.mactime = wlc_recover_tsf32(pkt_info->ts.ts_high, pkt_info->ts.ts_low); - - /* update rxpwr per antenna */ - bcmwifi_update_rxpwr_per_ant(&pkt_rxsts, wrxh); - - /* calculate rspec based on ppdu frame type */ - rspec = wlc_recv_mon_compute_rspec(info, wrxh, plcp); - - h = (struct dot11_header *)(plcp + plcp_len); - subtype = (ltoh16(h->fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT; - - /* parse & cache respec for ampdu */ - bcmwifi_parse_ampdu(info, rxh, subtype, rspec, plcp, &sts); - - /* A-MSDU parsing */ - if (RXHDR_GET_AMSDU(rxh, corerev, corerev_minor)) { - /* it's chained buffer, break it if necessary */ - sts.nfrmtype |= WL_RXS_NFRM_AMSDU_FIRST | WL_RXS_NFRM_AMSDU_SUB; - } - - sts.signal = (pkt_info->marker >> 8) & 0xff; - sts.noise = (int8)pkt_info->marker; - sts.chanspec = D11RXHDR_ACCESS_VAL(rxh, corerev, corerev_minor, RxChan); - - if (wf_chspec_malformed(sts.chanspec)) { - printf("Malformed chspec, %x\n", sts.chanspec); - return 0; - } - - /* 4360: is chan_num supposed to be primary or CF channel? */ - chan_num = CHSPEC_CHANNEL(sts.chanspec); - - if (PRXS5_ACPHY_DYNBWINNONHT(rxh)) - sts.vhtflags |= WL_RXS_VHTF_DYN_BW_NONHT; - else - sts.vhtflags &= ~WL_RXS_VHTF_DYN_BW_NONHT; - - switch (PRXS5_ACPHY_CHBWINNONHT(rxh)) { - default: case PRXS5_ACPHY_CHBWINNONHT_20MHZ: - sts.bw_nonht = WLC_20_MHZ; - break; - case PRXS5_ACPHY_CHBWINNONHT_40MHZ: - sts.bw_nonht = WLC_40_MHZ; - break; - case PRXS5_ACPHY_CHBWINNONHT_80MHZ: - sts.bw_nonht = WLC_80_MHZ; - break; - case PRXS5_ACPHY_CHBWINNONHT_160MHZ: - sts.bw_nonht = WLC_160_MHZ; - break; - } - - /* update rate and modulation info */ - bcmwifi_update_rate_modulation_info(info, rxh, rxh_last, rspec, plcp, &sts); - - sts.pktlength = FRAMELEN(corerev, corerev_minor, rxh) - plcp_len; - - sts.phytype = WL_RXS_PHY_N; - - if (RSPEC_ISCCK(rspec)) { - sts.encoding = WL_RXS_ENCODING_DSSS_CCK; - sts.preamble = (PRXS_SHORTH(rxh, corerev, corerev_minor) ? - WL_RXS_PREAMBLE_SHORT : WL_RXS_PREAMBLE_LONG); - } else if (RSPEC_ISOFDM(rspec)) { - sts.encoding = WL_RXS_ENCODING_OFDM; - sts.preamble = WL_RXS_PREAMBLE_SHORT; - } if (RSPEC_ISVHT(rspec)) { - sts.encoding = WL_RXS_ENCODING_VHT; - } else if (RSPEC_ISHE(rspec)) { - sts.encoding = WL_RXS_ENCODING_HE; - } else if (RSPEC_ISEHT(rspec)) { - sts.encoding = WL_RXS_ENCODING_EHT; - } else { /* MCS rate */ - sts.encoding = WL_RXS_ENCODING_HT; - sts.preamble = (uint32)((D11HT_MMPLCPLen(rxh) != 0) ? - WL_RXS_PREAMBLE_HT_MM : WL_RXS_PREAMBLE_HT_GF); - } - - /* translate error code */ - if (D11RXHDR_ACCESS_VAL(rxh, corerev, corerev_minor, RxStatus1) & RXS_DECERR) - sts.pkterror |= WL_RXS_DECRYPT_ERR; - if (D11RXHDR_ACCESS_VAL(rxh, corerev, corerev_minor, RxStatus1) & RXS_FCSERR) - sts.pkterror |= WL_RXS_CRC_ERROR; - - if (RXHDR_GET_PAD_PRES(rxh, corerev, corerev_minor)) { - p += 2; len -= 2; - } - - p += (hwrxoff + D11_PHY_RXPLCP_LEN(corerev)); - len -= (hwrxoff + D11_PHY_RXPLCP_LEN(corerev)); - return (wl_rxsts_to_rtap(&pkt_rxsts, p, len, pout, pad_req)); -} - -#ifndef MONITOR_DNGL_CONV -/* Collect AMSDU subframe packets */ -static uint16 -wl_monitor_amsdu(monitor_info_t* info, monitor_pkt_info_t* pkt_info, wlc_d11rxhdr_t *wrxh, - wlc_d11rxhdr_t *wrxh_last, void *pkt, uint16 len, void* pout, uint16* offset) -{ - uint8 *p = pkt; - uint8 hwrxoff = (pkt_info->marker >> 16) & 0xff; - uint16 frame_len = 0; - uint16 aggtype = (wrxh->rxhdr.lt80.RxStatus2 & RXS_AGGTYPE_MASK) >> RXS_AGGTYPE_SHIFT; - - switch (aggtype) { - case RXS_AMSDU_FIRST: - case RXS_AMSDU_N_ONE: - /* Flush any previously collected */ - if (info->amsdu_len) { - info->amsdu_len = 0; - } - - info->headroom = MAX_RADIOTAP_SIZE - D11_PHY_RXPLCP_LEN(corerev) - hwrxoff; - info->headroom -= (wrxh->rxhdr.lt80.RxStatus1 & RXS_PBPRES) ? 2 : 0; - - /* Save the new starting AMSDU subframe */ - info->amsdu_len = len; - info->amsdu_pkt = (uint8*)pout + (info->headroom > 0 ? - info->headroom : 0); - - memcpy(info->amsdu_pkt, p, len); - - if (aggtype == RXS_AMSDU_N_ONE) { - /* all-in-one AMSDU subframe */ - frame_len = wl_d11rx_to_rxsts(info, pkt_info, wrxh, wrxh, p, - len, info->amsdu_pkt - info->headroom, 0); - - *offset = ABS(info->headroom); - frame_len += *offset; - - info->amsdu_len = 0; - } - break; - - case RXS_AMSDU_INTERMEDIATE: - case RXS_AMSDU_LAST: - default: - /* Check for previously collected */ - if (info->amsdu_len) { - /* Append next AMSDU subframe */ - p += hwrxoff; len -= hwrxoff; - - if (wrxh->rxhdr.lt80.RxStatus1 & RXS_PBPRES) { - p += 2; len -= 2; - } - - memcpy(info->amsdu_pkt + info->amsdu_len, p, len); - info->amsdu_len += len; - - /* complete AMSDU frame */ - if (aggtype == RXS_AMSDU_LAST) { - frame_len = wl_d11rx_to_rxsts(info, pkt_info, wrxh, wrxh, - info->amsdu_pkt, info->amsdu_len, - info->amsdu_pkt - info->headroom, 0); - - *offset = ABS(info->headroom); - frame_len += *offset; - - info->amsdu_len = 0; - } - } - break; - } - - return frame_len; -} -#endif /* MONITOR_DNGL_CONV */ - -uint16 bcmwifi_monitor_create(monitor_info_t** info) -{ - *info = MALLOCZ(NULL, sizeof(struct monitor_info)); - if ((*info) == NULL) { - return FALSE; - } - - (*info)->d11_info = MALLOCZ(NULL, sizeof(struct d11_info)); - if ((*info)->d11_info == NULL) { - goto fail; - } - - return TRUE; - -fail: - bcmwifi_monitor_delete(*info); - - return FALSE; -} - -void -bcmwifi_set_corerev_major(monitor_info_t* info, int8 corerev) -{ - d11_info_t* d11i = info->d11_info; - d11i->major_revid = corerev; -} - -void -bcmwifi_set_corerev_minor(monitor_info_t* info, int8 corerev) -{ - d11_info_t* d11i = info->d11_info; - d11i->minor_revid = corerev; -} - -void -bcmwifi_monitor_delete(monitor_info_t* info) -{ - if (info == NULL) { - return; - } - - if (info->d11_info != NULL) { - MFREE(NULL, info->d11_info, sizeof(struct d11_info)); - } - - MFREE(NULL, info, sizeof(struct monitor_info)); -} - -uint16 -bcmwifi_monitor(monitor_info_t* info, monitor_pkt_info_t* pkt_info, void *pkt, uint16 len, - void* pout, uint16* offset, uint16 pad_req, void *wrxh_in, void *wrxh_last) -{ - wlc_d11rxhdr_t *wrxh; - int hdr_ext_offset = 0; - -#ifdef MONITOR_DNGL_CONV - wrxh = (wlc_d11rxhdr_t *)wrxh_in; - if (info == NULL) { - return 0; - } -#else - -#ifdef BCM_MON_QDBM_RSSI - hdr_ext_offset = WLC_SWRXHDR_EXT_LEN; -#endif - /* move beyond the extension, if any */ - pkt = (void *)((uint8 *)pkt + hdr_ext_offset); - wrxh = (wlc_d11rxhdr_t *)pkt; - - if ((wrxh->rxhdr.lt80.RxStatus2 & htol16(RXS_AMSDU_MASK))) { - /* Need to add support for AMSDU */ - return wl_monitor_amsdu(info, pkt_info, wrxh, wrxh_last, pkt, len, pout, offset); - } else -#endif /* NO MONITOR_DNGL_CONV */ - { - info->amsdu_len = 0; /* reset amsdu */ - *offset = 0; - return wl_d11rx_to_rxsts(info, pkt_info, wrxh, wrxh_last, - pkt, len - hdr_ext_offset, pout, pad_req); - } -} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_radiotap.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_radiotap.c old mode 100755 new mode 100644 index 7832981c0d17..acdb551fc046 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_radiotap.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_radiotap.c @@ -3,7 +3,7 @@ * This file housing the functions use by * wl driver. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_rates.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_rates.c deleted file mode 100755 index c5cebbfab04e..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_rates.c +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Common [OS-independent] rate management - * 802.11 Networking Adapter Device Driver. - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ - -#include -#ifdef BCMDRIVER -#include -#else -#include -#ifndef ASSERT -#define ASSERT(e) assert(e) -#endif -#ifndef ASSERT_FP -#define ASSERT_FP(e) assert(e) -#endif -#endif /* BCMDRIVER */ -#include <802.11.h> -#include <802.11ax.h> -#include - -#include -#include - -/* TODO: Consolidate rate utility functions from wlc_rate.c and bcmwifi_monitor.c - * into here if they're shared by non wl layer as well... - */ - -/* ============================================ */ -/* Moved from wlc_rate.c */ -/* ============================================ */ - -/* HE mcs info */ -struct ieee_80211_mcs_rate_info { - uint8 constellation_bits; - uint8 coding_q; - uint8 coding_d; - uint8 dcm_capable; /* 1 if dcm capable */ -}; - -static const struct ieee_80211_mcs_rate_info wlc_mcs_info[] = { - { 1, 1, 2, 1 }, /* MCS 0: MOD: BPSK, CR 1/2, dcm capable */ - { 2, 1, 2, 1 }, /* MCS 1: MOD: QPSK, CR 1/2, dcm capable */ - { 2, 3, 4, 0 }, /* MCS 2: MOD: QPSK, CR 3/4, NOT dcm capable */ - { 4, 1, 2, 1 }, /* MCS 3: MOD: 16QAM, CR 1/2, dcm capable */ - { 4, 3, 4, 1 }, /* MCS 4: MOD: 16QAM, CR 3/4, dcm capable */ - { 6, 2, 3, 0 }, /* MCS 5: MOD: 64QAM, CR 2/3, NOT dcm capable */ - { 6, 3, 4, 0 }, /* MCS 6: MOD: 64QAM, CR 3/4, NOT dcm capable */ - { 6, 5, 6, 0 }, /* MCS 7: MOD: 64QAM, CR 5/6, NOT dcm capable */ - { 8, 3, 4, 0 }, /* MCS 8: MOD: 256QAM, CR 3/4, NOT dcm capable */ - { 8, 5, 6, 0 }, /* MCS 9: MOD: 256QAM, CR 5/6, NOT dcm capable */ - { 10, 3, 4, 0 }, /* MCS 10: MOD: 1024QAM, CR 3/4, NOT dcm capable */ - { 10, 5, 6, 0 }, /* MCS 11: MOD: 1024QAM, CR 5/6, NOT dcm capable */ -#ifdef WL11BE - /* TODO: for now EHT shares this table with HE, - * create a new table if needed once we know more - * about EHT rate calculation... - */ - { 12, 3, 4, 0 }, /* MCS 12: MOD: 4096QAM, CR 3/4, NOT dcm capable */ - { 12, 5, 6, 0 }, /* MCS 13: MOD: 4096QAM, CR 5/6, NOT dcm capable */ -#endif -}; - -/* Nsd values Draft0.4 Table 26.63 onwards */ -static const uint wlc_he_nsd[] = { - 234, /* BW20 */ - 468, /* BW40 */ - 980, /* BW80 */ - 1960, /* BW160 */ -#ifdef WL11BE - /* TODO: for now EHT shares this table with HE, - * create a new table if needed once we know more - * about EHT rate calculation... - */ - 2940, /* BW240 */ - 3920 /* BW320 */ -#endif -}; - -/* Nsd values Draft3.3 Table 28-15 */ -static const uint wlc_he_ru_nsd[] = { - 24, /* 26T */ - 48, /* 52T */ - 102, /* 106T */ - 234, /* 242T/BW20 */ - 468, /* 484T/BW40 */ - 980, /* 996T/BW80 */ - 1960, /* 2*996T/BW160 */ -#ifdef WL11BE - /* TODO: for now EHT shares this table with HE, - * create a new table if needed once we know more - * about EHT rate calculation... - */ - 2940, /* 3*996T/BW240 */ - 3920 /* 4*996T/BW320 */ -#endif -}; - -#define HE_RU_TO_NSD(ru_idx) \ - (ru_idx < ARRAYSIZE(wlc_he_ru_nsd)) ? \ - wlc_he_ru_nsd[ru_idx] : 0 - -/* sym_len = 12.8 us. For calculation purpose, *10 */ -#define HE_SYM_LEN_FACTOR (128) - -/* GI values = 0.8 , 1.6 or 3.2 us. For calculation purpose, *10 */ -#define HE_GI_800us_FACTOR (8) -#define HE_GI_1600us_FACTOR (16) -#define HE_GI_3200us_FACTOR (32) - -/* To avoid ROM invalidation use the old macro as is... */ -#ifdef WL11BE -#define HE_BW_TO_NSD(bwi) \ - ((bwi) > 0u && (bwi) <= ARRAYSIZE(wlc_he_nsd)) ? \ - wlc_he_nsd[(bwi) - 1u] : 0u -#else -#define HE_BW_TO_NSD(bwi) \ - ((bwi) > 0 && ((bwi) << WL_RSPEC_BW_SHIFT) <= WL_RSPEC_BW_160MHZ) ? \ - wlc_he_nsd[(bwi)-1] : 0 -#endif /* WL11BE */ - -#define ksps 250 /* kilo symbols per sec, 4 us sym */ - -#ifdef WL11BE -/* Table "wlc_nsd" is derived from HT and VHT #defines below, but extended for HE - * for rate calculation purpose at a given NSS and bandwidth combination. - * - * It should and can only be used in where it wants to know the relative rate in kbps - * for a different NSS and bandwidth combination at a given mcs e.g. in fallback rate - * search. It shouldn not and can not be used in where it calculates the absolute rate - * i.e. the result doesn't agree with what the spec says otherwise. - * - * See Std 802.11-2016 "Table 21-61 VHT-MCSs for optional 160 MHz and 80+80 MHz, NSS = 8" - * for VHT, and P802.11ax/D6.0 "Table 27-111 HE-MCSs for 2x996-tone RU, NSS = 8" for HE, - * for 160Mhz bandwidth for resulting rate comparison. - * - * It's again extended for EHT 240/320Mhz bandwidth, for the same purpose. - */ -static const uint16 wlc_nsd[] = { - 52, /* 20MHz */ - 108, /* 40MHz */ - 234, /* 80Mhz */ - 468, /* 160MHz */ - 702, /* 240MHz */ - 936, /* 320MHz */ -}; - -#define BW_TO_NSD(bwi) \ - ((bwi) > 0u && (bwi) <= ARRAYSIZE(wlc_nsd)) ? \ - wlc_nsd[(bwi) - 1u] : 0u - -static uint -wf_nsd2ndbps(uint mcs, uint nss, uint nsd, bool dcm) -{ - uint Ndbps; - - /* multiply number of spatial streams, - * bits per number from the constellation, - * and coding quotient - */ - Ndbps = nsd * nss * - wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits; - - /* adjust for the coding rate divisor */ - Ndbps = Ndbps / wlc_mcs_info[mcs].coding_d; - - /* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */ - if (dcm) { - if (wlc_mcs_info[mcs].dcm_capable) { - Ndbps >>= 1u; - } - } - - return Ndbps; -} -#else -/* for HT and VHT? */ -#define Nsd_20MHz 52 -#define Nsd_40MHz 108 -#define Nsd_80MHz 234 -#define Nsd_160MHz 468 -#endif /* WL11BE */ - -uint -wf_he_mcs_to_Ndbps(uint mcs, uint nss, uint bw, bool dcm) -{ - uint Nsd; - uint Ndbps; - - /* find the number of complex numbers per symbol */ - Nsd = HE_BW_TO_NSD(bw >> WL_RSPEC_BW_SHIFT); - -#ifdef WL11BE - Ndbps = wf_nsd2ndbps(mcs, nss, Nsd, dcm); -#else - /* multiply number of spatial streams, - * bits per number from the constellation, - * and coding quotient - */ - Ndbps = Nsd * nss * - wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits; - - /* adjust for the coding rate divisor */ - Ndbps = Ndbps / wlc_mcs_info[mcs].coding_d; - - /* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */ - if (dcm) { - if (wlc_mcs_info[mcs].dcm_capable) { - Ndbps >>= 1; - } - } -#endif /* WL11BE */ - - return Ndbps; -} - -uint32 -wf_he_mcs_ru_to_ndbps(uint8 mcs, uint8 nss, bool dcm, uint8 ru_index) -{ - uint32 nsd; - uint32 ndbps; - - /* find the number of complex numbers per symbol */ - nsd = HE_RU_TO_NSD(ru_index); - -#ifdef WL11BE - ndbps = wf_nsd2ndbps(mcs, nss, nsd, dcm); -#else - /* multiply number of spatial streams, - * bits per number from the constellation, - * and coding quotient - * Ndbps = Nss x Nsd x (Nbpscs x R) x (DCM/2) - */ - ndbps = nsd * nss * - wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits; - - /* adjust for the coding rate divisor */ - ndbps = ndbps / wlc_mcs_info[mcs].coding_d; - - /* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */ - if (dcm && wlc_mcs_info[mcs].dcm_capable) { - ndbps >>= 1; - } -#endif /* WL11BE */ - return ndbps; -} - -/** - * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi/dcm combination. - * 'mcs' : a *single* spatial stream MCS (11ax) - * formula as per http: - * WLAN&preview=/323036249/344457953/11ax_rate_table.xlsx - * Symbol length = 12.8 usec [given as sym_len/10 below] - * GI value = 0.8 or 1.6 or 3.2 usec [given as GI_value/10 below] - * rate (Kbps) = (Nsd * Nbpscs * nss * (coding_q/coding_d) * 1000) / ((sym_len/10) + (GI_value/10)) - * Note that, for calculation purpose, following is used. [to be careful with overflows] - * rate (Kbps) = (Nsd * Nbpscs * nss * (coding_q/coding_d) * 1000) / ((sym_len + GI_value) / 10) - * rate (Kbps) = (Nsd * Nbpscs * nss * (coding_q/coding_d) * 1000) / (sym_len + GI_value) * 10 - */ -uint -wf_he_mcs_to_rate(uint mcs, uint nss, uint bw, uint gi, bool dcm) -{ - uint rate; - uint rate_deno; - - rate = HE_BW_TO_NSD(bw >> WL_RSPEC_BW_SHIFT); - -#ifdef WL11BE - rate = wf_nsd2ndbps(mcs, nss, rate, dcm); -#else - /* Nbpscs: multiply by bits per number from the constellation in use */ - rate = rate * wlc_mcs_info[mcs].constellation_bits; - - /* Nss: adjust for the number of spatial streams */ - rate = rate * nss; - - /* R: adjust for the coding rate given as a quotient and divisor */ - rate = (rate * wlc_mcs_info[mcs].coding_q) / wlc_mcs_info[mcs].coding_d; - - /* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */ - if (dcm) { - if (wlc_mcs_info[mcs].dcm_capable) { - rate >>= 1; - } - } -#endif /* WL11BE */ - - /* add sym len factor */ - rate_deno = HE_SYM_LEN_FACTOR; - - /* get GI for denominator */ - if (HE_IS_GI_3_2us(gi)) { - rate_deno += HE_GI_3200us_FACTOR; - } else if (HE_IS_GI_1_6us(gi)) { - rate_deno += HE_GI_1600us_FACTOR; - } else { - /* assuming HE_GI_0_8us */ - rate_deno += HE_GI_800us_FACTOR; - } - - /* as per above formula */ - rate *= 1000; /* factor of 10. *100 to accommodate 2 places */ - rate /= rate_deno; - rate *= 10; /* *100 was already done above. Splitting is done to avoid overflow. */ - - return rate; -} - -uint -wf_mcs_to_Ndbps(uint mcs, uint nss, uint bw) -{ - uint Nsd; - uint Ndbps; - - /* This calculation works for 11n HT and 11ac VHT if the HT mcs values - * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8. - * That is, HT MCS 23 is a base MCS = 7, Nss = 3 - */ - - /* find the number of complex numbers per symbol */ -#ifdef WL11BE - Nsd = BW_TO_NSD(bw >> WL_RSPEC_BW_SHIFT); - - Ndbps = wf_nsd2ndbps(mcs, nss, Nsd, FALSE); -#else - if (bw == WL_RSPEC_BW_20MHZ) { - Nsd = Nsd_20MHz; - } else if (bw == WL_RSPEC_BW_40MHZ) { - Nsd = Nsd_40MHz; - } else if (bw == WL_RSPEC_BW_80MHZ) { - Nsd = Nsd_80MHz; - } else if (bw == WL_RSPEC_BW_160MHZ) { - Nsd = Nsd_160MHz; - } else { - Nsd = 0; - } - - /* multiply number of spatial streams, - * bits per number from the constellation, - * and coding quotient - */ - Ndbps = Nsd * nss * - wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits; - - /* adjust for the coding rate divisor */ - Ndbps = Ndbps / wlc_mcs_info[mcs].coding_d; -#endif /* WL11BE */ - - return Ndbps; -} - -/** - * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi combination. - * 'mcs' : a *single* spatial stream MCS (11n or 11ac) - */ -uint -wf_mcs_to_rate(uint mcs, uint nss, uint bw, int sgi) -{ - uint rate; - - if (mcs == 32) { - /* just return fixed values for mcs32 instead of trying to parametrize */ - rate = (sgi == 0) ? 6000 : 6778; - } else { - /* This calculation works for 11n HT, 11ac VHT and 11ax HE if the HT mcs values - * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8. - * That is, HT MCS 23 is a base MCS = 7, Nss = 3 - */ - -#if defined(WLPROPRIETARY_11N_RATES) - switch (mcs) { - case 87: - mcs = 8; /* MCS 8: MOD: 256QAM, CR 3/4 */ - break; - case 88: - mcs = 9; /* MCS 9: MOD: 256QAM, CR 5/6 */ - break; - default: - break; - } -#endif /* WLPROPRIETARY_11N_RATES */ - -#ifdef WL11BE - rate = wf_mcs_to_Ndbps(mcs, nss, bw); -#else - /* find the number of complex numbers per symbol */ - if (RSPEC_IS20MHZ(bw)) { - /* 4360 TODO: eliminate Phy const in rspec bw, then just compare - * as in 80 and 160 case below instead of RSPEC_IS20MHZ(bw) - */ - rate = Nsd_20MHz; - } else if (RSPEC_IS40MHZ(bw)) { - /* 4360 TODO: eliminate Phy const in rspec bw, then just compare - * as in 80 and 160 case below instead of RSPEC_IS40MHZ(bw) - */ - rate = Nsd_40MHz; - } else if (bw == WL_RSPEC_BW_80MHZ) { - rate = Nsd_80MHz; - } else if (bw == WL_RSPEC_BW_160MHZ) { - rate = Nsd_160MHz; - } else { - rate = 0; - } - - /* multiply by bits per number from the constellation in use */ - rate = rate * wlc_mcs_info[mcs].constellation_bits; - - /* adjust for the number of spatial streams */ - rate = rate * nss; - - /* adjust for the coding rate given as a quotient and divisor */ - rate = (rate * wlc_mcs_info[mcs].coding_q) / wlc_mcs_info[mcs].coding_d; -#endif /* WL11BE */ - - /* multiply by Kilo symbols per sec to get Kbps */ - rate = rate * ksps; - - /* adjust the symbols per sec for SGI - * symbol duration is 4 us without SGI, and 3.6 us with SGI, - * so ratio is 10 / 9 - */ - if (sgi) { - /* add 4 for rounding of division by 9 */ - rate = ((rate * 10) + 4) / 9; - } - } - - return rate; -} /* wf_mcs_to_rate */ - -/* This function needs update to handle MU frame PLCP as well (MCS is conveyed via VHT-SIGB - * field in case of MU frames). Currently this support needs to be added in uCode to communicate - * MCS information for an MU frame - * - * For VHT frame: - * bit 0-3 mcs index - * bit 6-4 nsts for VHT - * bit 7: 1 for VHT - * Note: bit 7 is used to indicate to the rate sel the mcs is a non HT mcs! - * - * Essentially it's the NSS:MCS portions of the rspec - */ -uint8 -wf_vht_plcp_to_rate(uint8 *plcp) -{ - uint8 rate, gid; - uint nss; - uint32 plcp0 = plcp[0] + (plcp[1] << 8); /* don't need plcp[2] */ - - gid = (plcp0 & VHT_SIGA1_GID_MASK) >> VHT_SIGA1_GID_SHIFT; - if (gid > VHT_SIGA1_GID_TO_AP && gid < VHT_SIGA1_GID_NOT_TO_AP) { - /* for MU packet we hacked Signal Tail field in VHT-SIG-A2 to save nss and mcs, - * copy from murate in d11 rx header. - * nss = bit 18:19 (for 11ac 2 bits to indicate maximum 4 nss) - * mcs = 20:23 - */ - rate = (plcp[5] & 0xF0) >> 4; - nss = ((plcp[5] & 0x0C) >> 2) + 1; - } else { - rate = (plcp[3] >> VHT_SIGA2_MCS_SHIFT); - nss = ((plcp0 & VHT_SIGA1_NSTS_SHIFT_MASK_USER0) >> - VHT_SIGA1_NSTS_SHIFT) + 1; - if (plcp0 & VHT_SIGA1_STBC) - nss = nss >> 1; - } - rate |= ((nss << WL_RSPEC_VHT_NSS_SHIFT) | WF_NON_HT_MCS); - - return rate; -} - -/** - * Function for computing NSS:MCS from HE SU PLCP or - * MCS:LTF-GI from HE MU PLCP - * - * based on rev3.10 : - * https://docs.google.com/spreadsheets/d/ - * 1eP6ZCRrtnF924ds1R-XmbcH0IdQ0WNJpS1-FHmWeb9g/edit#gid=1492656555 - * - * For HE SU frame: - * bit 0-3 mcs index - * bit 6-4 nsts for HE - * bit 7: 1 for HE - * Note: bit 7 is used to indicate to the rate sel the mcs is a non HT mcs! - * Essentially it's the NSS:MCS portions of the rspec - * - * For HE MU frame: - * bit 0-3 mcs index - * bit 4-5 LTF-GI value - * bit 6 STBC - * Essentially it's the MCS and LTF-GI portion of the rspec - */ -/* Macros to be used for calculating rate from PLCP */ -#define HE_SU_PLCP2RATE_MCS_MASK 0x0F -#define HE_SU_PLCP2RATE_MCS_SHIFT 0 -#define HE_SU_PLCP2RATE_NSS_MASK 0x70 -#define HE_SU_PLCP2RATE_NSS_SHIFT 4 -#define HE_MU_PLCP2RATE_LTF_GI_MASK 0x30 -#define HE_MU_PLCP2RATE_LTF_GI_SHIFT 4 -#define HE_MU_PLCP2RATE_STBC_MASK 0x40 -#define HE_MU_PLCP2RATE_STBC_SHIFT 6 - -uint8 -wf_he_plcp_to_rate(uint8 *plcp, bool is_mu) -{ - uint8 rate = 0; - uint8 nss = 0; - uint32 plcp0 = 0; - uint32 plcp1 = 0; - uint8 he_ltf_gi; - uint8 stbc; - - ASSERT(plcp); - - BCM_REFERENCE(nss); - BCM_REFERENCE(he_ltf_gi); - - plcp0 = ((plcp[3] << 24) | (plcp[2] << 16) | (plcp[1] << 8) | plcp[0]); - plcp1 = ((plcp[5] << 8) | plcp[4]); - - if (!is_mu) { - /* For SU frames return rate in MCS:NSS format */ - rate = ((plcp0 & HE_SU_RE_SIGA_MCS_MASK) >> HE_SU_RE_SIGA_MCS_SHIFT); - nss = ((plcp0 & HE_SU_RE_SIGA_NSTS_MASK) >> HE_SU_RE_SIGA_NSTS_SHIFT) + 1; - rate |= ((nss << HE_SU_PLCP2RATE_NSS_SHIFT) | WF_NON_HT_MCS); - } else { - /* For MU frames return rate in MCS:LTF-GI format */ - rate = (plcp0 & HE_MU_SIGA_SIGB_MCS_MASK) >> HE_MU_SIGA_SIGB_MCS_SHIFT; - he_ltf_gi = (plcp0 & HE_MU_SIGA_GI_LTF_MASK) >> HE_MU_SIGA_GI_LTF_SHIFT; - stbc = (plcp1 & HE_MU_SIGA_STBC_MASK) >> HE_MU_SIGA_STBC_SHIFT; - - /* LTF-GI shall take the same position as NSS */ - rate |= (he_ltf_gi << HE_MU_PLCP2RATE_LTF_GI_SHIFT); - - /* STBC needs to be filled in bit 6 */ - rate |= (stbc << HE_MU_PLCP2RATE_STBC_SHIFT); - } - - return rate; -} - -/** - * Function for computing NSS:MCS from EHT SU PLCP or - * MCS:LTF-GI from EHT MU PLCP - * - * TODO: add link to the HW spec. - * FIXME: do we really need to support mu? - */ -uint8 -wf_eht_plcp_to_rate(uint8 *plcp, bool is_mu) -{ - BCM_REFERENCE(plcp); - BCM_REFERENCE(is_mu); - ASSERT(!"wf_eht_plcp_to_rate: not implemented!"); - return 0; -} - -/* ============================================ */ -/* Moved from wlc_rate_def.c */ -/* ============================================ */ - -/** - * Some functions require a single stream MCS as an input parameter. Given an MCS, this function - * returns the single spatial stream MCS equivalent. - */ -uint8 -wf_get_single_stream_mcs(uint mcs) -{ - if (mcs < 32) { - return mcs % 8; - } - switch (mcs) { - case 32: - return 32; - case 87: - case 99: - case 101: - return 87; /* MCS 87: SS 1, MOD: 256QAM, CR 3/4 */ - default: - return 88; /* MCS 88: SS 1, MOD: 256QAM, CR 5/6 */ - } -} - -/* ============================================ */ -/* Moved from wlc_phy_iovar.c */ -/* ============================================ */ - -const uint8 plcp_ofdm_rate_tbl[] = { - DOT11_RATE_48M, /* 8: 48Mbps */ - DOT11_RATE_24M, /* 9: 24Mbps */ - DOT11_RATE_12M, /* A: 12Mbps */ - DOT11_RATE_6M, /* B: 6Mbps */ - DOT11_RATE_54M, /* C: 54Mbps */ - DOT11_RATE_36M, /* D: 36Mbps */ - DOT11_RATE_18M, /* E: 18Mbps */ - DOT11_RATE_9M /* F: 9Mbps */ -}; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_rspec.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_rspec.c deleted file mode 100755 index e3c5957fdec8..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwifi_rspec.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Common [OS-independent] rate management - * 802.11 Networking Adapter Device Driver. - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ - -#include -#include -#include -#include <802.11ax.h> - -#include -#include - -/* TODO: Consolidate rspec utility functions from wlc_rate.c and bcmwifi_monitor.c - * into here if they're shared by non wl layer as well... - */ - -/* ============================================ */ -/* Moved from wlc_rate.c */ -/* ============================================ */ - -/** - * Returns the rate in [Kbps] units. - */ -static uint -wf_he_rspec_to_rate(ratespec_t rspec, uint max_mcs, uint max_nss) -{ - uint mcs = (rspec & WL_RSPEC_HE_MCS_MASK); - uint nss = (rspec & WL_RSPEC_HE_NSS_MASK) >> WL_RSPEC_HE_NSS_SHIFT; - bool dcm = (rspec & WL_RSPEC_DCM) != 0; - uint bw = RSPEC_BW(rspec); - uint gi = RSPEC_HE_LTF_GI(rspec); - - ASSERT(mcs <= max_mcs); - ASSERT(nss <= max_nss); - - if (mcs > max_mcs) { - return 0; - } - BCM_REFERENCE(max_nss); - - return wf_he_mcs_to_rate(mcs, nss, bw, gi, dcm); -} /* wf_he_rspec_to_rate */ - -/* take a well formed ratespec_t arg and return phy rate in [Kbps] units. - * 'rsel' indicates if the call comes from rate selection. - */ -static uint -_wf_rspec_to_rate(ratespec_t rspec, bool rsel) -{ - uint rate = (uint)(-1); - - if (RSPEC_ISLEGACY(rspec)) { - rate = 500 * RSPEC2RATE(rspec); - } else if (RSPEC_ISHT(rspec)) { - uint mcs = (rspec & WL_RSPEC_HT_MCS_MASK); - - ASSERT_FP(mcs <= 32 || IS_PROPRIETARY_11N_MCS(mcs)); - - if (mcs == 32) { - rate = wf_mcs_to_rate(mcs, 1, WL_RSPEC_BW_40MHZ, RSPEC_ISSGI(rspec)); - } else { -#if defined(WLPROPRIETARY_11N_RATES) - uint nss = GET_11N_MCS_NSS(mcs); - mcs = wf_get_single_stream_mcs(mcs); -#else /* this ifdef prevents ROM abandons */ - uint nss = 1 + (mcs / 8); - mcs = mcs % 8; -#endif /* WLPROPRIETARY_11N_RATES */ - - rate = wf_mcs_to_rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec)); - } - } else if (RSPEC_ISVHT(rspec)) { - uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK); - uint nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; - - if (rsel) { - rate = wf_mcs_to_rate(mcs, nss, RSPEC_BW(rspec), 0); - } else { - ASSERT_FP(mcs <= WLC_MAX_VHT_MCS); - ASSERT_FP(nss <= 8); - - rate = wf_mcs_to_rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec)); - } - } else if (RSPEC_ISHE(rspec)) { - rate = wf_he_rspec_to_rate(rspec, WLC_MAX_HE_MCS, 8); - } else if (RSPEC_ISEHT(rspec)) { - rate = wf_he_rspec_to_rate(rspec, WLC_MAX_EHT_MCS, 16); - } else { - ASSERT(0); - } - - return (rate == 0) ? (uint)(-1) : rate; -} - -/* take a well formed ratespec_t 'rspec' and return phy rate in [Kbps] units */ -uint -wf_rspec_to_rate(ratespec_t rspec) -{ - return _wf_rspec_to_rate(rspec, FALSE); -} - -/* take a well formed ratespec_t 'rspec' and return phy rate in [Kbps] units, - * FOR RATE SELECTION ONLY, WHICH USES LEGACY, HT, AND VHT RATES, AND VHT MCS - * COULD BE BIGGER THAN WLC_MAX_VHT_MCS! - */ -uint -wf_rspec_to_rate_rsel(ratespec_t rspec) -{ - return _wf_rspec_to_rate(rspec, TRUE); -} - -#ifdef BCMDBG -/* Return the rate in 500Kbps units if the rspec is legacy rate, assert otherwise */ -uint -wf_rspec_to_rate_legacy(ratespec_t rspec) -{ - ASSERT(RSPEC_ISLEGACY(rspec)); - - return rspec & WL_RSPEC_LEGACY_RATE_MASK; -} -#endif - -/** - * Function for computing RSPEC from EHT PLCP - * - * TODO: add link to the HW spec. - */ -ratespec_t -wf_eht_plcp_to_rspec(uint8 *plcp) -{ - ASSERT(!"wf_eht_plcp_to_rspec: not implemented!"); - return 0; -} - -/** - * Function for computing RSPEC from HE PLCP - * - * based on rev3.10 : - * https://docs.google.com/spreadsheets/d/ - * 1eP6ZCRrtnF924ds1R-XmbcH0IdQ0WNJpS1-FHmWeb9g/edit#gid=1492656555 - */ -ratespec_t -wf_he_plcp_to_rspec(uint8 *plcp) -{ - uint8 rate; - uint8 nss; - uint8 bw; - uint8 gi; - ratespec_t rspec; - - /* HE plcp - 6 B */ - uint32 plcp0; - uint16 plcp1; - - ASSERT(plcp); - - plcp0 = ((plcp[3] << 24) | (plcp[2] << 16) | (plcp[1] << 8) | plcp[0]); - plcp1 = ((plcp[5] << 8) | plcp[4]); - - /* TBD: only SU supported now */ - rate = (plcp0 & HE_SU_RE_SIGA_MCS_MASK) >> HE_SU_RE_SIGA_MCS_SHIFT; - /* PLCP contains (NSTS - 1) while RSPEC stores NSTS */ - nss = ((plcp0 & HE_SU_RE_SIGA_NSTS_MASK) >> HE_SU_RE_SIGA_NSTS_SHIFT) + 1; - rspec = HE_RSPEC(rate, nss); - - /* GI info comes from CP/LTF */ - gi = (plcp0 & HE_SU_RE_SIGA_GI_LTF_MASK) >> HE_SU_RE_SIGA_GI_LTF_SHIFT; - rspec |= HE_GI_TO_RSPEC(gi); - - /* b19-b20 of plcp indicate bandwidth in the format (2-bit): - * 0 for 20M, 1 for 40M, 2 for 80M, and 3 for 80p80/160M - * SW store this BW in rspec format (3-bit): - * 1 for 20M, 2 for 40M, 3 for 80M, and 4 for 80p80/160M - */ - bw = ((plcp0 & HE_SU_SIGA_BW_MASK) >> HE_SU_SIGA_BW_SHIFT) + 1; - rspec |= (bw << WL_RSPEC_BW_SHIFT); - - if (plcp1 & HE_SU_RE_SIGA_BEAMFORM_MASK) - rspec |= WL_RSPEC_TXBF; - if (plcp1 & HE_SU_RE_SIGA_CODING_MASK) - rspec |= WL_RSPEC_LDPC; - if (plcp1 & HE_SU_RE_SIGA_STBC_MASK) - rspec |= WL_RSPEC_STBC; - if (plcp0 & HE_SU_RE_SIGA_DCM_MASK) - rspec |= WL_RSPEC_DCM; - - return rspec; -} - -ratespec_t -wf_vht_plcp_to_rspec(uint8 *plcp) -{ - uint8 rate; - uint vht_sig_a1, vht_sig_a2; - ratespec_t rspec; - - ASSERT(plcp); - - rate = wf_vht_plcp_to_rate(plcp) & ~WF_NON_HT_MCS; - - vht_sig_a1 = plcp[0] | (plcp[1] << 8); - vht_sig_a2 = plcp[3] | (plcp[4] << 8); - - rspec = VHT_RSPEC((rate & WL_RSPEC_VHT_MCS_MASK), - (rate >> WL_RSPEC_VHT_NSS_SHIFT)); -#if ((((VHT_SIGA1_20MHZ_VAL + 1) << WL_RSPEC_BW_SHIFT) != WL_RSPEC_BW_20MHZ) || \ - (((VHT_SIGA1_40MHZ_VAL + 1) << WL_RSPEC_BW_SHIFT) != WL_RSPEC_BW_40MHZ) || \ - (((VHT_SIGA1_80MHZ_VAL + 1) << WL_RSPEC_BW_SHIFT) != WL_RSPEC_BW_80MHZ) || \ - (((VHT_SIGA1_160MHZ_VAL + 1) << WL_RSPEC_BW_SHIFT) != WL_RSPEC_BW_160MHZ)) -#error "VHT SIGA BW mapping to RSPEC BW needs correction" -#endif - rspec |= ((vht_sig_a1 & VHT_SIGA1_160MHZ_VAL) + 1) << WL_RSPEC_BW_SHIFT; - if (vht_sig_a1 & VHT_SIGA1_STBC) - rspec |= WL_RSPEC_STBC; - if (vht_sig_a2 & VHT_SIGA2_GI_SHORT) - rspec |= WL_RSPEC_SGI; - if (vht_sig_a2 & VHT_SIGA2_CODING_LDPC) - rspec |= WL_RSPEC_LDPC; - - return rspec; -} - -ratespec_t -wf_ht_plcp_to_rspec(uint8 *plcp) -{ - return HT_RSPEC(plcp[0] & MIMO_PLCP_MCS_MASK); -} - -/* ============================================ */ -/* Moved from wlc_rate_def.c */ -/* ============================================ */ - -/** - * Rate info per rate: tells for *pre* 802.11n rates whether a given rate is OFDM or not and its - * phy_rate value. Table index is a rate in [500Kbps] units, from 0 to 54Mbps. - * Contents of a table element: - * d[7] : 1=OFDM rate, 0=DSSS/CCK rate - * d[3:0] if DSSS/CCK rate: - * index into the 'M_RATE_TABLE_B' table maintained by ucode in shm - * d[3:0] if OFDM rate: encode rate per 802.11a-1999 sec 17.3.4.1, with lsb transmitted first. - * index into the 'M_RATE_TABLE_A' table maintained by ucode in shm - */ -/* Note: make this table 128 elements so the result of (rspec & 0x7f) can be safely - * used as the index into this table... - */ -const uint8 rate_info[128] = { - /* 0 1 2 3 4 5 6 7 8 9 */ -/* 0 */ 0x00, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 10 */ 0x00, 0x37, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00, -/* 20 */ 0x00, 0x00, 0x6e, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, -/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, -/* 50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 70 */ 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, -/* 100 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, -/* ------------- guard ------------ */ 0x00, -/* 110 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwpa.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwpa.c deleted file mode 100755 index 62738c119a9b..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmwpa.c +++ /dev/null @@ -1,2648 +0,0 @@ -/* - * bcmwpa.c - shared WPA-related functions - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ - -/* include wl driver config file if this file is compiled for driver */ -#ifdef BCMDRIVER -#include -/* HACK: this case for external supplicant use */ -#else -#include -#if defined(BCMEXTSUP) -#include -#else -#ifndef ASSERT -#define ASSERT(exp) -#endif -#endif /* BCMEXTSUP */ -#endif /* BCMDRIVER */ - -#include -#include -#include <802.11.h> -#include -#include <802.11r.h> - -#include -#include -#include -#include - -#include - -#include - -#include -#include -#ifdef WL_OCV -#include -#endif /* WL_OCV */ - -#if defined(BCMSUP_PSK) || defined(WLFBT) || defined(BCMAUTH_PSK) || \ - defined(WL_OKC) || defined(WLTDLS) || defined(GTKOE) || defined(WLHOSTFBT) -#ifdef WLHOSTFBT -#include -#endif -#endif /* defined(BCMSUP_PSK) || defined(WLFBT) || defined(BCMAUTH_PSK) || - * defined(WL_OKC) || defined(WLTDLS) || defined(GTKOE) || defined(WLHOSTFBT) - */ - -/* prefix strings */ -#define PMK_NAME_PFX "PMK Name" -#define FT_PTK_PFX "FT-PTK" -#define FT_R0_PFX "FT-R0" -#define FT_R0N_PFX "FT-R0N" -#define FT_R1_PFX "FT-R1" -#define FT_R1N_PFX "FT-R1N" -#define WPA_PTK_PFX "Pairwise key expansion" -#define TDLS_PMK_PFX "TDLS PMK" -/* end prefix strings */ - -#ifndef BIT -#define BIT(x) (1 << (x)) -#endif - -#define PRF_PREFIXES_NUM 5u - -typedef struct key_length_entry { - uint8 suite; - uint8 len; -} key_length_entry_t; - -/* EAPOL key(PMK/KCK/KEK/TK) length lookup tables */ -static const key_length_entry_t eapol_pmk_len[] = { - {RSN_AKM_SUITEB_SHA384_1X, EAPOL_WPA_PMK_SHA384_LEN}, - {RSN_AKM_FBT_SHA384_1X, EAPOL_WPA_PMK_SHA384_LEN}, - {RSN_AKM_FBT_SHA384_PSK, EAPOL_WPA_PMK_SHA384_LEN}, - {0u, EAPOL_WPA_PMK_DEFAULT_LEN} /* default */ -}; - -static const key_length_entry_t eapol_kck_mic_len[] = { - {RSN_AKM_SUITEB_SHA384_1X, EAPOL_WPA_KCK_MIC_SHA384_LEN}, - {RSN_AKM_FILS_SHA256, 0u}, - {RSN_AKM_FILS_SHA384, 0u}, - {RSN_AKM_FBT_SHA256_FILS, EAPOL_WPA_KCK_MIC_DEFAULT_LEN}, - {RSN_AKM_FBT_SHA384_FILS, EAPOL_WPA_KCK2_SHA384_LEN}, - {RSN_AKM_OWE, EAPOL_WPA_KCK_MIC_DEFAULT_LEN}, - {RSN_AKM_FBT_SHA384_1X, EAPOL_WPA_KCK_MIC_SHA384_LEN}, - {RSN_AKM_FBT_SHA384_PSK, EAPOL_WPA_KCK_MIC_SHA384_LEN}, - {0u, EAPOL_WPA_KCK_MIC_DEFAULT_LEN} /* default */ -}; - -static const key_length_entry_t eapol_kck_len[] = { - {RSN_AKM_SUITEB_SHA384_1X, EAPOL_WPA_KCK_SHA384_LEN}, - {RSN_AKM_FILS_SHA256, 0u}, - {RSN_AKM_FILS_SHA384, 0u}, - {RSN_AKM_FBT_SHA256_FILS, 0u}, - {RSN_AKM_FBT_SHA384_FILS, 0u}, - {RSN_AKM_OWE, EAPOL_WPA_KCK_DEFAULT_LEN}, - {RSN_AKM_FBT_SHA384_1X, EAPOL_WPA_KCK_SHA384_LEN}, - {RSN_AKM_FBT_SHA384_PSK, EAPOL_WPA_KCK_SHA384_LEN}, - {0u, EAPOL_WPA_KCK_DEFAULT_LEN} /* default */ -}; - -static const key_length_entry_t eapol_kek_len[] = { - {RSN_AKM_FILS_SHA384, EAPOL_WPA_ENCR_KEY_MAX_LEN}, - {RSN_AKM_FBT_SHA384_FILS, EAPOL_WPA_ENCR_KEY_MAX_LEN}, - {RSN_AKM_SUITEB_SHA384_1X, EAPOL_WPA_ENCR_KEY_MAX_LEN / 2}, - {RSN_AKM_FILS_SHA256, EAPOL_WPA_ENCR_KEY_MAX_LEN / 2}, - {RSN_AKM_FBT_SHA256_FILS, EAPOL_WPA_ENCR_KEY_MAX_LEN / 2}, - {RSN_AKM_OWE, EAPOL_WPA_ENCR_KEY_DEFAULT_LEN}, - {RSN_AKM_FBT_SHA384_1X, EAPOL_WPA_ENCR_KEY_MAX_LEN / 2}, - {RSN_AKM_FBT_SHA384_PSK, EAPOL_WPA_ENCR_KEY_MAX_LEN / 2}, - {0u, EAPOL_WPA_ENCR_KEY_DEFAULT_LEN} /* default */ -}; - -static const key_length_entry_t eapol_tk_len[] = { - {WPA_CIPHER_CCMP_256, EAPOL_WPA_TEMP_ENCR_KEY_MAX_LEN}, - {WPA_CIPHER_AES_GCM256, EAPOL_WPA_TEMP_ENCR_KEY_MAX_LEN}, - {WPA_CIPHER_BIP_GMAC_256, EAPOL_WPA_TEMP_ENCR_KEY_MAX_LEN}, - {WPA_CIPHER_BIP_CMAC_256, EAPOL_WPA_TEMP_ENCR_KEY_MAX_LEN}, - {WPA_CIPHER_AES_CCM, EAPOL_WPA_TEMP_ENCR_KEY_MAX_LEN / 2}, - {WPA_CIPHER_AES_GCM, EAPOL_WPA_TEMP_ENCR_KEY_MAX_LEN / 2}, - {WPA_CIPHER_BIP_GMAC_128, EAPOL_WPA_TEMP_ENCR_KEY_MAX_LEN / 2}, - {WPA_CIPHER_TKIP, EAPOL_WPA_TEMP_ENCR_KEY_MAX_LEN}, - {0u, 0u} /* default */ -}; - -#if defined(WL_FILS) && defined(WLFBT) -static const key_length_entry_t eapol_kck2_len[] = { - {RSN_AKM_FBT_SHA256_FILS, EAPOL_WPA_KCK2_SHA256_LEN}, - {RSN_AKM_FBT_SHA384_FILS, EAPOL_WPA_KCK2_SHA384_LEN}, - {0u, 0u} /* default */ -}; - -static const key_length_entry_t eapol_kek2_len[] = { - {RSN_AKM_FBT_SHA256_FILS, EAPOL_WPA_KEK2_SHA256_LEN}, - {RSN_AKM_FBT_SHA384_FILS, EAPOL_WPA_KEK2_SHA384_LEN}, - {0u, 0u} /* default */ -}; -#endif /* WL_FILS && WLFBT */ - -typedef struct key_length_lookup { - const eapol_key_type_t key; - const key_length_entry_t *key_entry; -} key_length_lookup_t; - -static const key_length_lookup_t eapol_key_lookup_tbl[] = { - {EAPOL_KEY_PMK, eapol_pmk_len}, - {EAPOL_KEY_KCK_MIC, eapol_kck_mic_len}, - {EAPOL_KEY_KCK, eapol_kck_len}, - {EAPOL_KEY_KEK, eapol_kek_len}, - {EAPOL_KEY_TK, eapol_tk_len}, -#if defined(WL_FILS) && defined(WLFBT) - {EAPOL_KEY_KCK2, eapol_kck2_len}, - {EAPOL_KEY_KEK2, eapol_kek2_len}, -#endif /* WL_FILS && WLFBT */ -}; - -typedef struct rsn_akm_lookup_entry { - const rsn_akm_t rsn_akm; - const sha2_hash_type_t hash_type; -} rsn_akm_lookup_entry_t; - -static const rsn_akm_lookup_entry_t rsn_akm_lookup_tbl[] = { - {RSN_AKM_NONE, HASH_SHA1}, - {RSN_AKM_UNSPECIFIED, HASH_SHA1}, - {RSN_AKM_PSK, HASH_SHA1}, - {RSN_AKM_FBT_1X, HASH_SHA256}, - {RSN_AKM_FBT_PSK, HASH_SHA256}, - {RSN_AKM_MFP_1X, HASH_SHA256}, - {RSN_AKM_MFP_PSK, HASH_SHA256}, - {RSN_AKM_SHA256_1X, HASH_SHA256}, - {RSN_AKM_SHA256_PSK, HASH_SHA256}, - {RSN_AKM_TPK, HASH_SHA256}, - {RSN_AKM_SAE_PSK, HASH_SHA256}, - {RSN_AKM_SAE_FBT, HASH_SHA256}, - {RSN_AKM_SUITEB_SHA256_1X, HASH_SHA256}, - {RSN_AKM_SUITEB_SHA384_1X, HASH_SHA384}, - {RSN_AKM_FBT_SHA384_1X, HASH_SHA384}, - {RSN_AKM_FILS_SHA256, HASH_SHA256}, - {RSN_AKM_FILS_SHA384, HASH_SHA384}, - {RSN_AKM_FBT_SHA256_FILS, HASH_SHA256}, - {RSN_AKM_FBT_SHA384_FILS, HASH_SHA384}, - {RSN_AKM_OWE, HASH_SHA256}, - {RSN_AKM_FBT_SHA384_PSK, HASH_SHA384}, - {RSN_AKM_PSK_SHA384, HASH_SHA384}, -}; - -typedef struct rsn_akm_cipher_match_entry { - uint16 akm_type; - uint32 u_cast; /* BITMAP */ - uint32 m_cast; /* BITMAP */ - uint32 g_mgmt; /* BITMAP */ -} rsn_akm_cipher_match_entry_t; - -/* list only explicit cipher restriction for given AKM (e.g SuiteB) - * refer to 802.11 spec 9.4.2.24.3 - * If not listed here, it means no restriction in using any ciphers. - */ -static const rsn_akm_cipher_match_entry_t rsn_akm_cipher_match_table[] = { - {RSN_AKM_SUITEB_SHA256_1X, - BCM_BIT(WPA_CIPHER_AES_GCM), - BCM_BIT(WPA_CIPHER_AES_GCM), - BCM_BIT(WPA_CIPHER_BIP_GMAC_128)}, - {RSN_AKM_SUITEB_SHA384_1X, - BCM_BIT(WPA_CIPHER_AES_GCM256) | BCM_BIT(WPA_CIPHER_CCMP_256), - BCM_BIT(WPA_CIPHER_AES_GCM256) | BCM_BIT(WPA_CIPHER_AES_GCM256), - BCM_BIT(WPA_CIPHER_BIP_GMAC_256) | BCM_BIT(WPA_CIPHER_BIP_CMAC_256)}, - {RSN_AKM_FBT_SHA384_1X, - BCM_BIT(WPA_CIPHER_AES_GCM256) | BCM_BIT(WPA_CIPHER_CCMP_256), - BCM_BIT(WPA_CIPHER_AES_GCM256) | BCM_BIT(WPA_CIPHER_AES_GCM256), - BCM_BIT(WPA_CIPHER_BIP_GMAC_256) | BCM_BIT(WPA_CIPHER_BIP_CMAC_256)} -}; - -#if defined(WL_BAND6G) -static const rsn_akm_mask_t rsn_akm_6g_inval_mask = - BCM_BIT(RSN_AKM_PSK) | - BCM_BIT(RSN_AKM_FBT_PSK) | - BCM_BIT(RSN_AKM_SHA256_PSK) | - BCM_BIT(RSN_AKM_FBT_SHA384_PSK) | - BCM_BIT(RSN_AKM_PSK_SHA384); - -static const rsn_ciphers_t cipher_6g_inval_mask = - BCM_BIT(WPA_CIPHER_NONE) | - BCM_BIT(WPA_CIPHER_WEP_40) | - BCM_BIT(WPA_CIPHER_TKIP) | - BCM_BIT(WPA_CIPHER_WEP_104); -#endif /* WL_BAND6G */ - -#if defined(BCMSUP_PSK) || defined(BCMSUPPL) -typedef struct group_cipher_algo_entry { - rsn_cipher_t g_mgmt_cipher; - uint8 bip_algo; -} group_cipher_algo_entry_t; - -static const group_cipher_algo_entry_t group_mgmt_cipher_algo[] = { - {WPA_CIPHER_BIP_GMAC_256, CRYPTO_ALGO_BIP_GMAC256}, - {WPA_CIPHER_BIP_CMAC_256, CRYPTO_ALGO_BIP_CMAC256}, - {WPA_CIPHER_BIP_GMAC_128, CRYPTO_ALGO_BIP_GMAC}, - {WPA_CIPHER_BIP, CRYPTO_ALGO_BIP}, -}; -#endif /* defined(BCMSUP_PSK) || defined(BCMSUPPL) */ - -static uint16 wlc_calc_rsn_desc_version(const rsn_ie_info_t *rsn_info); -static int bcmwpa_is_valid_akm(const rsn_akm_t akm); -#if defined(BCMSUP_PSK) || defined(BCMAUTH_PSK) || defined(WLFBT) || defined(GTKOE) -static sha2_hash_type_t bcmwpa_rsn_akm_to_hash(const rsn_akm_t akm); -#ifdef RSN_IE_INFO_STRUCT_RELOCATED -static int bcmwpa_decode_cipher_suite(rsn_ie_info_t *info, const uint8 **ptr, uint ie_len, uint - *remain_len, uint16 *p_count); -#endif -#endif /* defined(BCMSUP_PSK) || defined(BCMAUTH_PSK) || defined(WLFBT) || defined(GTKOE) */ -#if defined(BCMSUP_PSK) || defined(WLFBT) || defined(WL_OKC) || defined(WLHOSTFBT) -#include - -/* calculate wpa PMKID: HMAC-SHA1-128(PMK, "PMK Name" | AA | SPA) */ -static void -wpa_calc_pmkid_impl(sha2_hash_type_t hash_type, - const struct ether_addr *auth_ea, const struct ether_addr *sta_ea, - const uint8 *pmk, uint pmk_len, uint8 *pmkid) -{ - int err; - hmac_sha2_ctx_t ctx; - - err = hmac_sha2_init(&ctx, hash_type, pmk, pmk_len); - if (err != BCME_OK) - goto done; - hmac_sha2_update(&ctx, (const uint8 *)PMK_NAME_PFX, sizeof(PMK_NAME_PFX) - 1); - hmac_sha2_update(&ctx, (const uint8 *)auth_ea, ETHER_ADDR_LEN); - hmac_sha2_update(&ctx, (const uint8 *)sta_ea, ETHER_ADDR_LEN); - hmac_sha2_final(&ctx, pmkid, WPA2_PMKID_LEN); -done:; -} - -void -wpa_calc_pmkid(const struct ether_addr *auth_ea, const struct ether_addr *sta_ea, - const uint8 *pmk, uint pmk_len, uint8 *pmkid) -{ - wpa_calc_pmkid_impl(HASH_SHA1, auth_ea, sta_ea, pmk, pmk_len, pmkid); -} - -void -kdf_calc_pmkid(const struct ether_addr *auth_ea, const struct ether_addr *sta_ea, - const uint8 *key, uint key_len, uint8 *pmkid, rsn_ie_info_t *rsn_info) -{ - sha2_hash_type_t hash_type; - - if (rsn_info->sta_akm == RSN_AKM_SUITEB_SHA384_1X) { - hash_type = HASH_SHA384; - } else { - hash_type = HASH_SHA256; - } - - wpa_calc_pmkid_impl(hash_type, auth_ea, sta_ea, key, key_len, pmkid); -} - -#if defined(WLFBT) || defined(WLHOSTFBT) -void -wpa_calc_pmkR0(sha2_hash_type_t hash_type, const uint8 *ssid, uint ssid_len, - uint16 mdid, const uint8 *r0kh, uint r0kh_len, const struct ether_addr *sta_ea, - const uint8 *pmk, uint pmk_len, uint8 *pmkr0, uint8 *pmkr0name) -{ - uint8 out[FBT_R0KH_ID_LEN + WPA2_PMKID_LEN - 1]; - int out_len = FBT_R0KH_ID_LEN - 1; - bcm_const_xlvp_t pfx[7]; - bcm_const_xlvp_t pfx2[2]; - int npfx = 0; - int npfx2 = 0; - uint8 mdid_le[2]; - uint8 pfx_ssid_len; - uint8 pfx_r0kh_len; - - if (hash_type == HASH_SHA384) { - out_len += WPA2_PMKID_LEN; - } - - /* create prefixes for pmkr0 */ - pfx[npfx].len = sizeof(FT_R0_PFX) - 1; - pfx[npfx++].data = (uint8 *)FT_R0_PFX; - - /* ssid length and ssid */ - pfx_ssid_len = ssid_len & 0xff; - pfx[npfx].len = (uint16)sizeof(pfx_ssid_len); - pfx[npfx++].data = &pfx_ssid_len; - - pfx[npfx].len = (uint16)(ssid_len & 0xffff); - pfx[npfx++].data = ssid; - - /* mdid */ - htol16_ua_store(mdid, mdid_le); - pfx[npfx].len = sizeof(mdid_le); - pfx[npfx++].data = mdid_le; - - /* r0kh len and r0kh */ - pfx_r0kh_len = r0kh_len & 0xff; - pfx[npfx].len = sizeof(pfx_r0kh_len); - pfx[npfx++].data = &pfx_r0kh_len; - - pfx[npfx].len = (uint16)(r0kh_len & 0xffff); - pfx[npfx++].data = r0kh; - - /* sta addr */ - pfx[npfx].len = ETHER_ADDR_LEN; - pfx[npfx++].data = (const uint8 *)sta_ea; - - hmac_sha2_n(hash_type, pmk, pmk_len, pfx, npfx, NULL, 0, out, out_len); - (void)memcpy_s(pmkr0, pmk_len, out, pmk_len); - - /* coverity checks overflow if pfx size changes */ - - /* create prefixes for pmkr0 name */ - pfx2[npfx2].len = sizeof(FT_R0N_PFX) - 1; - pfx2[npfx2++].data = (uint8 *)FT_R0N_PFX; - pfx2[npfx2].len = WPA2_PMKID_LEN; - pfx2[npfx2++].data = &out[pmk_len]; - - (void)sha2(hash_type, pfx2, npfx2, NULL, 0, pmkr0name, WPA2_PMKID_LEN); -} - -void -wpa_calc_pmkR1(sha2_hash_type_t hash_type, const struct ether_addr *r1kh, - const struct ether_addr *sta_ea, const uint8 *pmk, uint pmk_len, const uint8 *pmkr0name, - uint8 *pmkr1, uint8 *pmkr1name) -{ - bcm_const_xlvp_t pfx[3]; - bcm_const_xlvp_t pfx2[4]; - int npfx = 0; - int npfx2 = 0; - - if (!pmkr1 && !pmkr1name) - goto done; - else if (!pmkr1) - goto calc_r1name; - - /* create prefixes for pmkr1 */ - pfx[npfx].len = sizeof(FT_R1_PFX) - 1; - pfx[npfx++].data = (uint8 *)FT_R1_PFX; - - pfx[npfx].len = ETHER_ADDR_LEN; - pfx[npfx++].data = (const uint8 *)r1kh; - - pfx[npfx].len = ETHER_ADDR_LEN; - pfx[npfx++].data = (const uint8 *)sta_ea; - - hmac_sha2_n(hash_type, pmk, pmk_len, pfx, npfx, NULL, 0, - pmkr1, sha2_digest_len(hash_type)); - -calc_r1name: - /* create prefixes for pmkr1 name */ - pfx2[npfx2].len = sizeof(FT_R1N_PFX) - 1; - pfx2[npfx2++].data = (uint8 *)FT_R1N_PFX; - - pfx2[npfx2].len = WPA2_PMKID_LEN; - pfx2[npfx2++].data = pmkr0name; - - pfx2[npfx2].len = ETHER_ADDR_LEN; - pfx2[npfx2++].data = (const uint8 *)r1kh; - - pfx2[npfx2].len = ETHER_ADDR_LEN; - pfx2[npfx2++].data = (const uint8 *)sta_ea; - - sha2(hash_type, pfx2, npfx2, NULL, 0, pmkr1name, WPA2_PMKID_LEN); -done:; -} - -void -wpa_calc_ft_ptk(sha2_hash_type_t hash_type, - const struct ether_addr *bssid, const struct ether_addr *sta_ea, - const uint8 *anonce, const uint8* snonce, - const uint8 *pmk, uint pmk_len, uint8 *ptk, uint ptk_len) -{ - bcm_const_xlvp_t pfx[5]; - int npfx = 0; - - /* FT-PTK||SNONCE||ANONCE||BSSID||STA Addr */ - - pfx[npfx].len = sizeof(FT_PTK_PFX) - 1; - pfx[npfx++].data = (uint8 *)FT_PTK_PFX; - - pfx[npfx].len = EAPOL_WPA_KEY_NONCE_LEN; - pfx[npfx++].data = snonce; - - pfx[npfx].len = EAPOL_WPA_KEY_NONCE_LEN; - pfx[npfx++].data = anonce; - - pfx[npfx].len = ETHER_ADDR_LEN; - pfx[npfx++].data = (const uint8 *)bssid; - - pfx[npfx].len = ETHER_ADDR_LEN; - pfx[npfx++].data = (const uint8 *)sta_ea; - - hmac_sha2_n(hash_type, pmk, pmk_len, pfx, npfx, NULL, 0, ptk, ptk_len); -} - -void -wpa_derive_pmkR1_name(sha2_hash_type_t hash_type, - struct ether_addr *r1kh, struct ether_addr *sta_ea, - uint8 *pmkr0name, uint8 *pmkr1name) -{ - wpa_calc_pmkR1(hash_type, r1kh, sta_ea, NULL /* pmk */, 0, - pmkr0name, NULL /* pmkr1 */, pmkr1name); -} -#endif /* WLFBT || WLHOSTFBT */ -#endif /* BCMSUP_PSK || WLFBT || WL_OKC */ - -#if defined(BCMSUP_PSK) || defined(GTKOE) || defined(BCMAUTH_PSK) || defined(WLFBT) -/* Decrypt a key data from a WPA key message */ -int -wpa_decr_key_data(eapol_wpa_key_header_t *body, uint16 key_info, uint8 *ekey, - uint8 *encrkey, rc4_ks_t *rc4key, const rsn_ie_info_t *rsn_info, uint16 *dec_len) -{ - uint16 len; - int err = BCME_OK; - uint8 *key_data; - - switch (key_info & (WPA_KEY_DESC_V1 | WPA_KEY_DESC_V2)) { - case WPA_KEY_DESC_V1: - err = memcpy_s(encrkey, EAPOL_WPA_KEY_IV_LEN + EAPOL_WPA_ENCR_KEY_MAX_LEN, - body->iv, EAPOL_WPA_KEY_IV_LEN); - if (err) { - ASSERT(0); - return err; - } - err = memcpy_s(&encrkey[EAPOL_WPA_KEY_IV_LEN], EAPOL_WPA_ENCR_KEY_MAX_LEN, - ekey, rsn_info->kek_len); - if (err) { - ASSERT(0); - return err; - } - /* decrypt the key data */ - prepare_key(encrkey, EAPOL_WPA_KEY_IV_LEN + rsn_info->kek_len, rc4key); - rc4(NULL, WPA_KEY_DATA_LEN_256, rc4key); /* dump 256 bytes */ - len = ntoh16_ua(EAPOL_WPA_KEY_HDR_DATA_LEN_PTR(body, rsn_info->kck_mic_len)); - key_data = EAPOL_WPA_KEY_HDR_DATA_PTR(body, rsn_info->kck_mic_len); - rc4(key_data, len, rc4key); - break; - - case WPA_KEY_DESC_V2: - case WPA_KEY_DESC_V3: - case WPA_KEY_DESC_V0: - /* fallthrough */ - len = ntoh16_ua(EAPOL_WPA_KEY_HDR_DATA_LEN_PTR(body, rsn_info->kck_mic_len)); - if (!len) { - *dec_len = 0; - break; /* ignore zero length */ - } - key_data = EAPOL_WPA_KEY_HDR_DATA_PTR(body, rsn_info->kck_mic_len); - if (aes_unwrap(rsn_info->kek_len, ekey, len, key_data, key_data)) { - *dec_len = 0; - err = BCME_DECERR; - break; - } - *dec_len = (len > AKW_BLOCK_LEN) ? (len - AKW_BLOCK_LEN) : 0; - break; - - default: - *dec_len = 0; - err = BCME_UNSUPPORTED; /* may need revisiting - see 802.11-2016 */ - break; - } - - return err; -} - -/* internal function - assumes enouch space allocated, retuns written number */ -static int -wpa_calc_ptk_prefixes(const uint8 *prefix, uint prefix_len, - const struct ether_addr *auth_ea, const struct ether_addr *sta_ea, - const uint8 *anonce, uint8 anonce_len, const uint8 *snonce, uint8 snonce_len, - bcm_const_xlvp_t *pfx) -{ - int npfx = 0; - const uint8 *nonce; - - /* prefix || min ea || max ea || min nonce || max nonce */ - pfx[npfx].len = (uint16)(prefix_len & 0xffff); - pfx[npfx++].data = prefix; - - pfx[npfx].len = ETHER_ADDR_LEN; - pfx[npfx++].data = (const uint8 *) wpa_array_cmp(MIN_ARRAY, - (const uint8 *)auth_ea, (const uint8 *)sta_ea, ETHER_ADDR_LEN); - - pfx[npfx].len = ETHER_ADDR_LEN; - pfx[npfx++].data = (const uint8 *) wpa_array_cmp(MAX_ARRAY, - (const uint8 *)auth_ea, (const uint8 *)sta_ea, ETHER_ADDR_LEN); - - nonce = (const uint8 *)wpa_array_cmp(MIN_ARRAY, snonce, anonce, snonce_len); - - if (nonce == snonce) { - pfx[npfx].len = snonce_len; - pfx[npfx++].data = snonce; - pfx[npfx].len = anonce_len; - pfx[npfx++].data = anonce; - } else { - pfx[npfx].len = anonce_len; - pfx[npfx++].data = anonce; - pfx[npfx].len = snonce_len; - pfx[npfx++].data = snonce; - } - - return npfx; -} - -void -kdf_calc_ptk(const struct ether_addr *auth_ea, const struct ether_addr *sta_ea, - const uint8 *anonce, const uint8* snonce, - const uint8 *pmk, uint pmk_len, uint8 *ptk, uint ptk_len) -{ - bcm_const_xlvp_t pfx[5]; - int npfx; - - /* note: kdf omits trailing NULL in prefix */ - npfx = wpa_calc_ptk_prefixes((uint8 *)WPA_PTK_PFX, sizeof(WPA_PTK_PFX) - 1, - auth_ea, sta_ea, anonce, EAPOL_WPA_KEY_NONCE_LEN, snonce, - EAPOL_WPA_KEY_NONCE_LEN, pfx); - hmac_sha2_n(HASH_SHA256, pmk, pmk_len, pfx, npfx, NULL, 0, ptk, ptk_len); -} -#endif /* BCMSUP_PSK || GTKOE || BCMAUTH_PSK || WLFBT */ - -#if defined(BCMSUP_PSK) || defined(BCMAUTH_PSK) || defined(WLFBT) || defined(GTKOE) -/* Compute Message Integrity Code (MIC) over EAPOL message */ -int -wpa_make_mic(eapol_header_t *eapol, uint key_desc, uint8 *mic_key, - rsn_ie_info_t *rsn_info, uchar *mic, uint mic_len) -{ - uint data_len; - int err = BCME_OK; - sha2_hash_type_t type = HASH_NONE; - - /* length of eapol pkt from the version field on */ - data_len = 4 + ntoh16_ua((uint8 *)&eapol->length); - - /* Create the MIC for the pkt */ - switch (key_desc) { - case WPA_KEY_DESC_V1: - type = HASH_MD5; - break; - case WPA_KEY_DESC_V2: - /* note: transparent truncation to mic_len */ - type = HASH_SHA1; - break; - case WPA_KEY_DESC_V3: - aes_cmac_calc(NULL, 0, &eapol->version, data_len, mic_key, - mic_len, mic, AES_BLOCK_SZ); - goto exit; - case WPA_KEY_DESC_V0: - ASSERT(rsn_info != NULL); - if (rsn_info == NULL) { - return BCME_BADARG; - } - if (IS_SAE_AKM(rsn_info->sta_akm)) { - aes_cmac_calc(NULL, 0, &eapol->version, data_len, mic_key, - mic_len, mic, AES_BLOCK_SZ); - goto exit; - } - type = bcmwpa_rsn_akm_to_hash(rsn_info->sta_akm); - break; - default: - /* 11mc D8.0 some AKMs use descriptor version 0 */ - err = BCME_UNSUPPORTED; - goto exit; - } - - if (type) { - err = hmac_sha2(type, mic_key, mic_len, NULL, 0, (uint8 *)&eapol->version, data_len, - mic, mic_len); - } -exit: - return err; -} - -int -wpa_calc_ptk(rsn_akm_t akm, const struct ether_addr *auth_ea, const struct ether_addr *sta_ea, - const uint8 *anonce, uint8 anon_len, const uint8 *snonce, uint8 snon_len, const uint8 *pmk, - uint pmk_len, uint8 *ptk, uint ptk_len) -{ - bcm_const_xlvp_t pfx[PRF_PREFIXES_NUM]; - int npfx; - int ret = BCME_OK; - sha2_hash_type_t hash_type; - uint label_len; - - if (RSN_AKM_USE_KDF(akm)) { - label_len = sizeof(WPA_PTK_PFX) - 1u; - } else { //WPA AKMS - label_len = sizeof(WPA_PTK_PFX); /* note: wpa needs trailing NULL in prefix */ - } - - hash_type = bcmwpa_rsn_akm_to_hash(akm); - - npfx = wpa_calc_ptk_prefixes((uint8 *)WPA_PTK_PFX, label_len, - auth_ea, sta_ea, anonce, anon_len, snonce, snon_len, pfx); - ret = hmac_sha2_n(hash_type, pmk, pmk_len, pfx, npfx, NULL, 0, ptk, ptk_len); - return ret; -} - -bool -wpa_encr_key_data(eapol_wpa_key_header_t *body, uint16 key_info, uint8 *ekey, - uint8 *gtk, uint8 *data, uint8 *encrkey, rc4_ks_t *rc4key, const rsn_ie_info_t *rsn_info) -{ - uint16 len; - uint8 *key_data; - - switch (key_info & (WPA_KEY_DESC_V1 | WPA_KEY_DESC_V2)) { - case WPA_KEY_DESC_V1: - if (gtk) { - len = ntoh16_ua((uint8 *)&body->key_len); - } else { - len = ntoh16_ua(EAPOL_WPA_KEY_HDR_DATA_LEN_PTR(body, - rsn_info->kck_mic_len)); - } - - /* create the iv/ptk key */ - if (memcpy_s(encrkey, EAPOL_WPA_KEY_IV_LEN, body->iv, sizeof(body->iv))) { - return FALSE; - } - if (memcpy_s(&encrkey[EAPOL_WPA_KEY_IV_LEN], EAPOL_WPA_ENCR_KEY_DEFAULT_LEN, - ekey, EAPOL_WPA_ENCR_KEY_DEFAULT_LEN)) { - return FALSE; - } - /* encrypt the key data */ - prepare_key(encrkey, EAPOL_WPA_KEY_IV_LEN + EAPOL_WPA_ENCR_KEY_DEFAULT_LEN, - rc4key); - rc4(data, WPA_KEY_DATA_LEN_256, rc4key); /* dump 256 bytes */ - key_data = EAPOL_WPA_KEY_HDR_DATA_PTR(body, rsn_info->kck_mic_len); - rc4(key_data, len, rc4key); - break; - case WPA_KEY_DESC_V2: /* fall through */ - case WPA_KEY_DESC_V3: - case WPA_KEY_DESC_V0: - len = ntoh16_ua(EAPOL_WPA_KEY_HDR_DATA_LEN_PTR(body, - rsn_info->kck_mic_len)); - /* FIXME: data_len is length to encrypt, but need to make sure - * buffer is big enought - * for expansion. how? problem for caller? - */ - key_data = EAPOL_WPA_KEY_HDR_DATA_PTR(body, rsn_info->kck_mic_len); - /* pad if needed - min. 16 bytes, 8 byte aligned */ - /* padding is 0xdd followed by 0's */ - if (len < 2u *AKW_BLOCK_LEN) { - key_data[len] = WPA2_KEY_DATA_PAD; - bzero(&key_data[len + 1u], 2u * AKW_BLOCK_LEN - (len + 1u)); - len = 2u *AKW_BLOCK_LEN; - } else if (len % AKW_BLOCK_LEN) { - key_data[len] = WPA2_KEY_DATA_PAD; - bzero(&key_data[len + 1u], - AKW_BLOCK_LEN - ((len + 1u) % AKW_BLOCK_LEN)); - len += AKW_BLOCK_LEN - (len % AKW_BLOCK_LEN); - } - if (aes_wrap(rsn_info->kek_len, ekey, len, key_data, key_data)) { - return FALSE; - } - len += AKW_BLOCK_LEN; - hton16_ua_store(len, - (uint8 *)EAPOL_WPA_KEY_HDR_DATA_LEN_PTR(body, - rsn_info->kck_mic_len)); - break; - default: - /* 11mc D8.0 key descriptor version 0 used */ - return FALSE; - } - - return TRUE; -} - -/* Check MIC of EAPOL message */ -bool -wpa_check_mic(eapol_header_t *eapol, uint key_desc, uint8 *mic_key, rsn_ie_info_t *rsn_info) -{ - eapol_wpa_key_header_t *body = NULL; - uchar digest[SHA2_MAX_DIGEST_LEN]; - uchar mic[EAPOL_WPA_KEY_MAX_MIC_LEN]; - - if (!mic_key || !rsn_info || !eapol) { - return FALSE; - } - - body = (eapol_wpa_key_header_t *)eapol->body; - -#ifndef EAPOL_KEY_HDR_VER_V2 - if (rsn_info->kck_mic_len != EAPOL_WPA_KCK_DEFAULT_LEN) -#else - if (rsn_info->kck_mic_len > EAPOL_WPA_KEY_MAX_MIC_LEN) -#endif /* EAPOL_KEY_HDR_VER_V2 */ - { - ASSERT(0); - return FALSE; - } - /* save MIC and clear its space in message */ - if (memcpy_s(mic, sizeof(mic), EAPOL_WPA_KEY_HDR_MIC_PTR(body), - rsn_info->kck_mic_len)) { - return FALSE; - } - bzero(EAPOL_WPA_KEY_HDR_MIC_PTR(body), rsn_info->kck_mic_len); - if (wpa_make_mic(eapol, key_desc, mic_key, rsn_info, digest, rsn_info->kck_mic_len) - != BCME_OK) { - return FALSE; - } - return !memcmp(digest, mic, rsn_info->kck_mic_len); -} - -static sha2_hash_type_t bcmwpa_rsn_akm_to_hash(const rsn_akm_t akm) -{ - uint i = 0; - sha2_hash_type_t type = HASH_NONE; - - for (i = 0; i < ARRAYSIZE(rsn_akm_lookup_tbl); i++) { - if (akm == rsn_akm_lookup_tbl[i].rsn_akm) { - type = rsn_akm_lookup_tbl[i].hash_type; - break; - } - } - return type; -} -#endif /* BCMSUP_PSK || BCMAUTH_PSK || WLFBT || GTKOE */ - -#ifdef WLTDLS -void -wpa_calc_tpk(const struct ether_addr *init_ea, const struct ether_addr *resp_ea, - const struct ether_addr *bssid, const uint8 *anonce, const uint8* snonce, - uint8 *tpk, uint tpk_len) -{ - uint8 pmk[SHA2_MAX_DIGEST_LEN]; - uint pmk_len; - bcm_const_xlvp_t ikpfx[2]; - int nikpfx = 0; - bcm_const_xlvp_t tpkpfx[4]; - int ntpkpfx = 0; - - pmk_len = sha2_digest_len(HASH_SHA256); - - /* compute pmk to use - using anonce and snonce - min and then max */ - ikpfx[nikpfx].len = EAPOL_WPA_KEY_NONCE_LEN; - ikpfx[nikpfx++].data = wpa_array_cmp(MIN_ARRAY, snonce, anonce, - EAPOL_WPA_KEY_NONCE_LEN), - - ikpfx[nikpfx].len = EAPOL_WPA_KEY_NONCE_LEN; - ikpfx[nikpfx++].data = wpa_array_cmp(MAX_ARRAY, snonce, anonce, - EAPOL_WPA_KEY_NONCE_LEN), - - (void)sha2(HASH_SHA256, ikpfx, nikpfx, NULL, 0, pmk, SHA2_SHA256_DIGEST_LEN); - - /* compute the tpk - using prefix, min ea, max ea, bssid */ - tpkpfx[ntpkpfx].len = sizeof(TDLS_PMK_PFX) - 1; - tpkpfx[ntpkpfx++].data = (const uint8 *)TDLS_PMK_PFX; - - tpkpfx[ntpkpfx].len = ETHER_ADDR_LEN; - tpkpfx[ntpkpfx++].data = wpa_array_cmp(MIN_ARRAY, (const uint8 *)init_ea, - (const uint8 *)resp_ea, ETHER_ADDR_LEN), - - tpkpfx[ntpkpfx].len = ETHER_ADDR_LEN; - tpkpfx[ntpkpfx++].data = wpa_array_cmp(MAX_ARRAY, (const uint8 *)init_ea, - (const uint8 *)resp_ea, ETHER_ADDR_LEN), - - tpkpfx[ntpkpfx].len = ETHER_ADDR_LEN; - tpkpfx[ntpkpfx++].data = (const uint8 *)bssid; - - (void)hmac_sha2_n(HASH_SHA256, pmk, pmk_len, tpkpfx, ntpkpfx, NULL, 0, tpk, tpk_len); -} -#endif /* WLTDLS */ - -/* Convert WPA/WPA2 IE cipher suite to locally used value */ -static bool -rsn_cipher(wpa_suite_t *suite, ushort *cipher, const uint8 *std_oui, bool wep_ok) -{ - bool ret = TRUE; - - if (!memcmp((const char *)suite->oui, std_oui, DOT11_OUI_LEN)) { - switch (suite->type) { - case WPA_CIPHER_TKIP: - *cipher = CRYPTO_ALGO_TKIP; - break; - case WPA_CIPHER_AES_CCM: - *cipher = CRYPTO_ALGO_AES_CCM; - break; - case WPA_CIPHER_AES_GCM: - *cipher = CRYPTO_ALGO_AES_GCM; - break; - case WPA_CIPHER_AES_GCM256: - *cipher = CRYPTO_ALGO_AES_GCM256; - break; - case WPA_CIPHER_WEP_40: - if (wep_ok) - *cipher = CRYPTO_ALGO_WEP1; - else - ret = FALSE; - break; - case WPA_CIPHER_WEP_104: - if (wep_ok) - *cipher = CRYPTO_ALGO_WEP128; - else - ret = FALSE; - break; - default: - ret = FALSE; - break; - } - return ret; - } - - return FALSE; -} - -bool -wpa_cipher(wpa_suite_t *suite, ushort *cipher, bool wep_ok) -{ - return rsn_cipher(suite, cipher, (const uchar*)WPA_OUI, wep_ok); -} - -bool -wpa2_cipher(wpa_suite_t *suite, ushort *cipher, bool wep_ok) -{ - return rsn_cipher(suite, cipher, (const uchar*)WPA2_OUI, wep_ok); -} - -/* Is any of the tlvs the expected entry? If - * not update the tlvs buffer pointer/length. - */ -bool -bcm_has_ie(uint8 *ie, uint8 **tlvs, uint *tlvs_len, const uint8 *oui, uint oui_len, uint8 type) -{ - /* If the contents match the OUI and the type */ - if (ie[TLV_LEN_OFF] >= oui_len + 1 && - !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) && - type == ie[TLV_BODY_OFF + oui_len]) { - return TRUE; - } - - /* point to the next ie */ - ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; - /* calculate the length of the rest of the buffer */ - *tlvs_len -= (uint)(ie - *tlvs); - /* update the pointer to the start of the buffer */ - *tlvs = ie; - - return FALSE; -} - -wpa_ie_fixed_t * -bcm_find_wpaie(uint8 *parse, uint len) -{ - return (wpa_ie_fixed_t *) bcm_find_ie(parse, len, DOT11_MNG_VS_ID, - WPA_OUI_LEN, (const char*) WPA_OUI, WPA_OUI_TYPE); -} - -int -bcm_find_security_ies(uint8 *buf, uint buflen, void **wpa_ie, - void **rsn_ie) -{ - bcm_tlv_t *tlv = NULL; - uint totlen = 0; - uint8 *end = NULL; - uint len = 0; - uint tlvs_len = 0; - uint8 *tlvs = NULL; - - if ((tlv = (bcm_tlv_t*)buf) == NULL || - !wpa_ie || !rsn_ie || buflen == 0) { - return BCME_BADARG; - } - - totlen = buflen; - *rsn_ie = *wpa_ie = NULL; - end = buf; - end += buflen; - - /* find rsn ie and wpa ie */ - while (totlen >= TLV_HDR_LEN) { - len = tlv->len; - tlvs_len = buflen; - tlvs = buf; - - /* check if tlv overruns buffer */ - if (totlen < (len + TLV_HDR_LEN)) { - return BCME_BUFTOOSHORT; - } - - /* validate remaining totlen */ - if (totlen >= (len + TLV_HDR_LEN)) { - if ((*rsn_ie == NULL) && (tlv->id == DOT11_MNG_RSN_ID)) { - *rsn_ie = tlv; - } else if ((*wpa_ie == NULL) && (tlv->id == DOT11_MNG_VS_ID)) { - /* if vendor ie, check if its wpa ie */ - if (bcm_is_wpa_ie((uint8 *)tlv, &tlvs, &tlvs_len)) - *wpa_ie = tlv; - } - } - - if (*rsn_ie && *wpa_ie) - break; - - tlv = (bcm_tlv_t*)((uint8*)tlv + (len + TLV_HDR_LEN)); - totlen -= (len + TLV_HDR_LEN); - - if (totlen > buflen) { - return BCME_BUFTOOLONG; - } - - if ((uint8 *)tlv > end) { - return BCME_BUFTOOSHORT; - } - - } - - if (*wpa_ie || *rsn_ie) - return BCME_OK; - else - return BCME_NOTFOUND; -} - -bcm_tlv_t * -bcm_find_wmeie(uint8 *parse, uint len, uint8 subtype, uint8 subtype_len) -{ - bcm_tlv_t *ie; - if ((ie = bcm_find_ie(parse, len, DOT11_MNG_VS_ID, WME_OUI_LEN, - (const char*) WME_OUI, WME_OUI_TYPE))) { - uint ie_len = TLV_HDR_LEN + ie->len; - wme_ie_t *ie_data = (wme_ie_t *)ie->data; - /* the subtype_len must include OUI+type+subtype */ - if (subtype_len > WME_OUI_LEN + 1 && - ie_len == (uint)TLV_HDR_LEN + subtype_len && - ie_data->subtype == subtype) { - return ie; - } - /* move to next IE */ - len -= (uint)((uint8 *)ie + ie_len - parse); - parse = (uint8 *)ie + ie_len; - } - return NULL; -} - -wps_ie_fixed_t * -bcm_find_wpsie(const uint8 *parse, uint len) -{ - uint8 type = WPS_OUI_TYPE; - - return (wps_ie_fixed_t *)bcm_find_vendor_ie(parse, len, WPS_OUI, &type, sizeof(type)); -} - -/* locate the Attribute in the WPS IE */ -/* assume the caller has validated the WPS IE tag and length */ -wps_at_fixed_t * -bcm_wps_find_at(wps_at_fixed_t *at, uint len, uint16 id) -{ - while ((int)len >= WPS_AT_FIXED_LEN) { - uint alen = WPS_AT_FIXED_LEN + ntoh16_ua(((wps_at_fixed_t *)at)->len); - if (ntoh16_ua(((wps_at_fixed_t *)at)->at) == id && alen <= len) - return at; - at = (wps_at_fixed_t *)((uint8 *)at + alen); - len -= alen; - } - return NULL; -} - -#ifdef WLP2P -wifi_p2p_ie_t * -bcm_find_p2pie(const uint8 *parse, uint len) -{ - uint8 type = P2P_OUI_TYPE; - - return (wifi_p2p_ie_t *)bcm_find_vendor_ie(parse, len, P2P_OUI, &type, sizeof(type)); -} -#endif - -bcm_tlv_t * -bcm_find_hs20ie(uint8 *parse, uint len) -{ - return bcm_find_ie(parse, len, DOT11_MNG_VS_ID, WFA_OUI_LEN, - (const char *)WFA_OUI, WFA_OUI_TYPE_HS20); -} - -bcm_tlv_t * -bcm_find_osenie(uint8 *parse, uint len) -{ - return bcm_find_ie(parse, len, DOT11_MNG_VS_ID, WFA_OUI_LEN, - (const char *) WFA_OUI, WFA_OUI_TYPE_OSEN); -} - -#if defined(BCMSUP_PSK) || defined(BCMSUPPL) || defined(GTKOE) || defined(WL_FILS) -#define wpa_is_kde(ie, tlvs, len, type) bcm_has_ie(ie, tlvs, len, \ - (const uint8 *)WPA2_OUI, WPA2_OUI_LEN, type) - -eapol_wpa2_encap_data_t * -wpa_find_kde(const uint8 *parse, uint len, uint8 type) -{ - return (eapol_wpa2_encap_data_t *) bcm_find_ie(parse, len, - DOT11_MNG_PROPR_ID, WPA2_OUI_LEN, (const char *) WPA2_OUI, type); -} - -bool -wpa_is_gtk_encap(uint8 *ie, uint8 **tlvs, uint *tlvs_len) -{ - return wpa_is_kde(ie, tlvs, tlvs_len, WPA2_KEY_DATA_SUBTYPE_GTK); -} - -eapol_wpa2_encap_data_t * -wpa_find_gtk_encap(uint8 *parse, uint len) -{ - eapol_wpa2_encap_data_t *data; - - /* minimum length includes kde upto gtk field in eapol_wpa2_key_gtk_encap_t */ - data = wpa_find_kde(parse, len, WPA2_KEY_DATA_SUBTYPE_GTK); - if (data && (data->length < EAPOL_WPA2_GTK_ENCAP_MIN_LEN)) { - data = NULL; - } - - return data; -} - -int -wpa_find_eapol_kde_data(eapol_header_t* eapol, uint8 eapol_mic_len, - uint8 subtype, eapol_wpa2_encap_data_t **out_data) -{ - eapol_wpa_key_header_t *body; - uint8 *parse; - uint16 body_len; - uint16 data_len; - - if (!eapol) { - return BCME_BADARG; - } - - body = (eapol_wpa_key_header_t *)eapol->body; - body_len = ntoh16_ua(&eapol->length); - - data_len = ntoh16_ua(EAPOL_WPA_KEY_HDR_DATA_LEN_PTR(body, - eapol_mic_len)); - - parse = EAPOL_WPA_KEY_HDR_DATA_PTR(body, eapol_mic_len); - - if (((uint8 *)body + body_len) < ((uint8 *)parse + data_len)) { - return BCME_BUFTOOSHORT; - } - - return wpa_find_kde_data(parse, data_len, subtype, out_data); -} - -int -wpa_find_kde_data(const uint8 *kde_buf, uint16 buf_len, - uint8 subtype, eapol_wpa2_encap_data_t **out_data) -{ - eapol_wpa2_encap_data_t *data; - uint8 min_len; - - if (!kde_buf) { - return BCME_BADARG; - } - - /* minimum length includes kde upto gtk field in eapol_wpa2_key_gtk_encap_t */ - data = wpa_find_kde(kde_buf, buf_len, subtype); - if (!data) { - return BCME_IE_NOTFOUND; - } - - switch (subtype) { - case WPA2_KEY_DATA_SUBTYPE_GTK: - min_len = EAPOL_WPA2_GTK_ENCAP_MIN_LEN; - break; - case WPA2_KEY_DATA_SUBTYPE_IGTK: - min_len = EAPOL_WPA2_BIGTK_ENCAP_MIN_LEN; - break; - case WPA2_KEY_DATA_SUBTYPE_BIGTK: - min_len = EAPOL_WPA2_IGTK_ENCAP_MIN_LEN; - break; -#ifdef WL_OCV - case WPA2_KEY_DATA_SUBTYPE_OCI: - min_len = EAPOL_WPA2_OCI_ENCAP_MIN_LEN; - break; -#endif /* WL_OCV */ - default: - return BCME_UNSUPPORTED; - } - - if (data->length < min_len) { - return BCME_BADLEN; - } - - *out_data = data; - - return BCME_OK; -} - -#ifdef WL_OCV -bool -wpa_check_ocv_caps(uint16 local_caps, uint16 peer_caps) -{ - bool ocv_enabled = - ((local_caps & RSN_CAP_OCVC) && - (peer_caps & RSN_CAP_OCVC)); - bool mfp_enabled = - ((peer_caps & RSN_CAP_MFPC) || - (peer_caps & RSN_CAP_MFPR)); - - return (ocv_enabled && mfp_enabled); -} - -int -wpa_add_oci_encap(chanspec_t chspec, uint8* buf, uint buf_len) -{ - int retval = BCME_OK; - eapol_wpa2_encap_data_t* oci_kde; - uint len = buf_len; - - if (buf_len < WPA_OCV_OCI_KDE_SIZE) { - retval = BCME_BUFTOOSHORT; - goto done; - } - - oci_kde = (eapol_wpa2_encap_data_t*)buf; - - oci_kde->type = DOT11_MNG_WPA_ID; - oci_kde->subtype = WPA2_KEY_DATA_SUBTYPE_OCI; - oci_kde->length = (WPA_OCV_OCI_KDE_SIZE - TLV_HDR_LEN); - - oci_kde->oui[0u] = WPA2_OUI[0u]; - oci_kde->oui[1u] = WPA2_OUI[1u]; - oci_kde->oui[2u] = WPA2_OUI[2u]; - - buf += EAPOL_WPA2_ENCAP_DATA_HDR_LEN; - len -= EAPOL_WPA2_ENCAP_DATA_HDR_LEN; - - retval = bcm_ocv_write_oci(chspec, buf, len); - if (retval != BCME_OK) { - goto done; - } - -done: - return retval; -} - -int -wpa_add_oci_ie(chanspec_t chspec, uint8* buf, uint buf_len) -{ - int retval = BCME_OK; - uint8* oci_buf = buf + BCM_TLV_EXT_HDR_SIZE; - - if (buf_len < (bcm_ocv_get_oci_len() + BCM_TLV_EXT_HDR_SIZE)) { - retval = BCME_BUFTOOSHORT; - goto done; - } - - retval = bcm_ocv_write_oci(chspec, oci_buf, bcm_ocv_get_oci_len()); - if (retval != BCME_OK) { - goto done; - } - - (void)bcm_write_tlv_ext(DOT11_MNG_ID_EXT_ID, - OCV_EXTID_MNG_OCI_ID, oci_buf, bcm_ocv_get_oci_len(), buf); - -done: - return retval; -} - -int -wpa_add_oci_ft_subelem(chanspec_t chspec, uint8* buf, uint buf_len) -{ - int retval = BCME_OK; - uint8* oci_buf = buf + BCM_TLV_HDR_SIZE; - - if (buf_len < (bcm_ocv_get_oci_len() + BCM_TLV_HDR_SIZE)) { - retval = BCME_BUFTOOSHORT; - goto done; - } - - retval = bcm_ocv_write_oci(chspec, oci_buf, bcm_ocv_get_oci_len()); - if (retval != BCME_OK) { - goto done; - } - - bcm_write_tlv_safe(DOT11_FBT_SUBELEM_ID_OCI, - oci_buf, bcm_ocv_get_oci_len(), buf, buf_len); - -done: - return retval; -} - -int wpa_validate_oci_encap(chanspec_t chspec, const uint8* buf, uint buf_len) -{ - int retval = BCME_OK; - eapol_wpa2_encap_data_t *encap = NULL; - - retval = wpa_find_kde_data(buf, buf_len, WPA2_KEY_DATA_SUBTYPE_OCI, &encap); - if (retval != BCME_OK) { - retval = BCME_NOTFOUND; - goto done; - } - - retval = bcm_ocv_validate_oci(chspec, - encap->data, encap->length); - if (retval != BCME_OK) { - goto done; - } - -done: - return retval; -} - -int wpa_validate_oci_ie(chanspec_t chspec, const uint8* buf, uint buf_len) -{ - int retval = BCME_OK; - bcm_tlv_ext_t *oci_ie; - - oci_ie = (bcm_tlv_ext_t *)bcm_parse_tlvs_dot11(buf, buf_len, - OCV_EXTID_MNG_OCI_ID, TRUE); - - if (!oci_ie) { - retval = BCME_NOTFOUND; - goto done; - } - - retval = bcm_ocv_validate_oci(chspec, oci_ie->data, oci_ie->len); - if (retval != BCME_OK) { - goto done; - } - -done: - return retval; -} - -int wpa_validate_oci_ft_subelem(chanspec_t chspec, const uint8* buf, uint buf_len) -{ - int retval = BCME_OK; - bcm_tlv_t *oci_ie; - - oci_ie = (bcm_tlv_t *)bcm_parse_tlvs_dot11(buf, buf_len, - DOT11_FBT_SUBELEM_ID_OCI, FALSE); - - if (!oci_ie) { - retval = BCME_NOTFOUND; - goto done; - } - - retval = bcm_ocv_validate_oci(chspec, oci_ie->data, oci_ie->len); - if (retval != BCME_OK) { - goto done; - } - -done: - return retval; -} -#endif /* WL_OCV */ -#endif /* defined(BCMSUP_PSK) || defined(BCMSUPPL) || defined(GTKOE) || defined(WL_FILS) */ - -const uint8 * -wpa_array_cmp(int max_array, const uint8 *x, const uint8 *y, uint len) -{ - uint i; - const uint8 *ret = x; - - for (i = 0; i < len; i++) - if (x[i] != y[i]) - break; - - if (i == len) { - /* returning null will cause crash, return value used for copying */ - /* return first param in this case to close security loophole */ - return x; - } - if (max_array && (y[i] > x[i])) - ret = y; - if (!max_array && (y[i] < x[i])) - ret = y; - - return (ret); -} - -void -wpa_incr_array(uint8 *array, uint len) -{ - int i; - - for (i = (len-1); i >= 0; i--) - if (array[i]++ != 0xff) { - break; - } -} - -bool -bcmwpa_akm2WPAauth(uint8 *akm, uint32 *auth, bool sta_iswpa) -{ - uint i; - oui_akm_wpa_tbl_t wpa_auth_tbl_match[] = { - {WPA2_OUI, RSN_AKM_NONE, WPA_AUTH_NONE}, - {WPA2_OUI, RSN_AKM_UNSPECIFIED, WPA2_AUTH_UNSPECIFIED}, - {WPA2_OUI, RSN_AKM_PSK, WPA2_AUTH_PSK}, - {WPA2_OUI, RSN_AKM_FBT_1X, WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT}, - {WPA2_OUI, RSN_AKM_FBT_PSK, WPA2_AUTH_PSK | WPA2_AUTH_FT}, - {WPA2_OUI, RSN_AKM_SHA256_1X, WPA2_AUTH_1X_SHA256}, - {WPA2_OUI, RSN_AKM_SHA256_PSK, WPA2_AUTH_PSK_SHA256}, - {WPA2_OUI, RSN_AKM_FILS_SHA256, WPA2_AUTH_FILS_SHA256}, - {WPA2_OUI, RSN_AKM_FILS_SHA384, WPA2_AUTH_FILS_SHA384}, - {WPA2_OUI, RSN_AKM_FBT_SHA256_FILS, WPA2_AUTH_FILS_SHA256 | WPA2_AUTH_FT}, - {WPA2_OUI, RSN_AKM_FBT_SHA384_FILS, WPA2_AUTH_FILS_SHA384 | WPA2_AUTH_FT}, - {WPA2_OUI, RSN_AKM_SAE_PSK, WPA3_AUTH_SAE_PSK}, - {WPA2_OUI, RSN_AKM_SAE_FBT, WPA3_AUTH_SAE_PSK | WPA2_AUTH_FT}, - {WPA2_OUI, RSN_AKM_OWE, WPA3_AUTH_OWE}, - {WPA2_OUI, RSN_AKM_SUITEB_SHA256_1X, WPA3_AUTH_1X_SUITE_B_SHA256}, - {WPA2_OUI, RSN_AKM_SUITEB_SHA384_1X, WPA3_AUTH_1X_SUITE_B_SHA384}, - {WFA_OUI, OSEN_AKM_UNSPECIFIED, WPA2_AUTH_UNSPECIFIED}, - {WFA_OUI, RSN_AKM_FBT_SHA256_FILS, WPA2_AUTH_FILS_SHA256 | WPA2_AUTH_FT}, - {WFA_OUI, RSN_AKM_FBT_SHA384_FILS, WPA2_AUTH_FILS_SHA384 | WPA2_AUTH_FT}, - {WFA_OUI, RSN_AKM_DPP, WPA3_AUTH_DPP_AKM}, - -#ifdef BCMWAPI_WAI - {WAPI_OUI, RSN_AKM_NONE, WAPI_AUTH_NONE}, - {WAPI_OUI, RSN_AKM_UNSPECIFIED, WAPI_AUTH_UNSPECIFIED}, - {WAPI_OUI, RSN_AKM_PSK, WAPI_AUTH_PSK}, -#endif /* BCMWAPI_WAI */ - - {WPA_OUI, RSN_AKM_NONE, WPA_AUTH_NONE}, - {WPA_OUI, RSN_AKM_UNSPECIFIED, WPA_AUTH_UNSPECIFIED}, - {WPA_OUI, RSN_AKM_PSK, WPA_AUTH_PSK}, - }; - - BCM_REFERENCE(sta_iswpa); - - for (i = 0; i < ARRAYSIZE(wpa_auth_tbl_match); i++) { - if (!memcmp(akm, wpa_auth_tbl_match[i].oui, DOT11_OUI_LEN)) { - if (wpa_auth_tbl_match[i].rsn_akm == akm[DOT11_OUI_LEN]) { - *auth = wpa_auth_tbl_match[i].wpa_auth; - return TRUE; - } - } - } - return FALSE; -} - -/* map cipher suite to internal WSEC_XXXX */ -/* cs points 4 byte cipher suite, and only the type is used for non CCX ciphers */ -bool -bcmwpa_cipher2wsec(uint8 *cipher, uint32 *wsec) -{ - -#ifdef BCMWAPI_WAI - if (!memcmp(cipher, WAPI_OUI, DOT11_OUI_LEN)) { - switch (WAPI_CSE_WPI_2_CIPHER(cipher[DOT11_OUI_LEN])) { - case WAPI_CIPHER_NONE: - *wsec = 0; - break; - case WAPI_CIPHER_SMS4: - *wsec = SMS4_ENABLED; - break; - default: - return FALSE; - } - return TRUE; - } -#endif /* BCMWAPI_WAI */ - - switch (cipher[DOT11_OUI_LEN]) { - case WPA_CIPHER_NONE: - *wsec = 0; - break; - case WPA_CIPHER_WEP_40: - case WPA_CIPHER_WEP_104: - *wsec = WEP_ENABLED; - break; - case WPA_CIPHER_TKIP: - *wsec = TKIP_ENABLED; - break; - case WPA_CIPHER_AES_CCM: - /* fall through */ - case WPA_CIPHER_AES_GCM: - /* fall through */ - case WPA_CIPHER_AES_GCM256: - *wsec = AES_ENABLED; - break; - -#ifdef BCMWAPI_WAI - case WAPI_CIPHER_SMS4: - *wsec = SMS4_ENABLED; - break; -#endif /* BCMWAPI_WAI */ - - default: - return FALSE; - } - return TRUE; -} - -#ifdef RSN_IE_INFO_STRUCT_RELOCATED -/* map WPA/RSN cipher to internal WSEC */ -uint32 -bcmwpa_wpaciphers2wsec(uint32 wpacipher) -{ - uint32 wsec = 0; - - switch (wpacipher) { - case BCM_BIT(WPA_CIPHER_WEP_40): - case BCM_BIT(WPA_CIPHER_WEP_104): - wsec = WEP_ENABLED; - break; - case BCM_BIT(WPA_CIPHER_TKIP): - wsec = TKIP_ENABLED; - break; - case BCM_BIT(WPA_CIPHER_AES_OCB): - /* fall through */ - case BCM_BIT(WPA_CIPHER_AES_CCM): - wsec = AES_ENABLED; - break; - case BCM_BIT(WPA_CIPHER_AES_GCM): - /* fall through */ - case BCM_BIT(WPA_CIPHER_AES_GCM256): - wsec = AES_ENABLED; - break; - -#ifdef BCMWAPI_WAI - case BCM_BIT(WAPI_CIPHER_SMS4): - wsec = SMS4_ENABLED; - break; -#endif /* BCMWAPI_WAI */ - - default: - break; - } - - return wsec; -} - -uint32 -wlc_convert_rsn_to_wsec_bitmap(uint32 ap_cipher_mask) -{ - - uint32 ap_wsec = 0; - uint32 tmp_mask = ap_cipher_mask; - uint32 c; - - FOREACH_BIT(c, tmp_mask) { - ap_wsec |= bcmwpa_wpaciphers2wsec(c); - } - - return ap_wsec; -} - -#else /* Not RSN_IE_INFO_STRUCT_RELOCATED */ -uint32 -bcmwpa_wpaciphers2wsec(uint8 wpacipher) -{ - uint32 wsec = 0; - - switch (wpacipher) { - case WPA_CIPHER_NONE: - break; - case WPA_CIPHER_WEP_40: - case WPA_CIPHER_WEP_104: - wsec = WEP_ENABLED; - break; - case WPA_CIPHER_TKIP: - wsec = TKIP_ENABLED; - break; - case WPA_CIPHER_AES_OCB: - /* fall through */ - case WPA_CIPHER_AES_CCM: - wsec = AES_ENABLED; - break; - case WPA_CIPHER_AES_GCM: - /* fall through */ - case WPA_CIPHER_AES_GCM256: - wsec = AES_ENABLED; - break; - -#ifdef BCMWAPI_WAI - case WAPI_CIPHER_SMS4: - wsec = SMS4_ENABLED; - break; -#endif /* BCMWAPI_WAI */ - - default: - break; - } - - return wsec; -} -#endif /* RSN_IE_INFO_STRUCT_RELOCATED */ - -bool -bcmwpa_is_wpa_auth(uint32 auth) -{ - if ((auth == WPA_AUTH_NONE) || - (auth == WPA_AUTH_UNSPECIFIED) || - (auth == WPA_AUTH_PSK)) - return TRUE; - else - return FALSE; -} - -bool -bcmwpa_includes_wpa_auth(uint32 auth) -{ - if (auth & (WPA_AUTH_NONE | - WPA_AUTH_UNSPECIFIED | - WPA_AUTH_PSK)) - return TRUE; - else - return FALSE; -} - -bool -bcmwpa_is_rsn_auth(uint32 auth) -{ - auth = auth & ~WPA2_AUTH_FT; - - if ((auth == WPA2_AUTH_UNSPECIFIED) || - (auth == WPA2_AUTH_PSK) || - (auth == BRCM_AUTH_PSK) || - (auth == WPA2_AUTH_1X_SHA256) || - (auth == WPA2_AUTH_PSK_SHA256) || - (auth == WPA3_AUTH_SAE_PSK) || - (auth == WPA3_AUTH_OWE) || - WPA2_AUTH_IS_FILS(auth) || - (auth == WPA3_AUTH_1X_SUITE_B_SHA256) || - (auth == WPA3_AUTH_1X_SUITE_B_SHA384) || - (auth == WPA3_AUTH_PSK_SHA384) || - (auth == WPA3_AUTH_DPP_AKM)) { - return TRUE; - } else { - return FALSE; - } -} - -bool -bcmwpa_includes_rsn_auth(uint32 auth) -{ - if (auth & (WPA2_AUTH_UNSPECIFIED | - WPA2_AUTH_PSK | - BRCM_AUTH_PSK | WPA2_AUTH_1X_SHA256 | WPA2_AUTH_PSK_SHA256 | - WPA2_AUTH_IS_FILS(auth) | WPA3_AUTH_SAE_PSK | WPA3_AUTH_OWE | - WPA3_AUTH_1X_SUITE_B_SHA256 | WPA3_AUTH_1X_SUITE_B_SHA384 | - WPA3_AUTH_PSK_SHA384 | WPA3_AUTH_DPP_AKM)) - return TRUE; - else - return FALSE; -} - -#ifdef RSN_IE_INFO_STRUCT_RELOCATED -/* decode unicast/multicast cipher in RSNIE */ -static int -bcmwpa_decode_cipher_suite(rsn_ie_info_t *info, const uint8 **ptr_inc, uint ie_len, uint - *remain_len, uint16 *p_count) -{ - const wpa_suite_ucast_t *ucast; - const wpa_suite_mcast_t *mcast; - uint i; - - if (!(*remain_len)) { - info->g_cipher = WPA_CIPHER_UNSPECIFIED; - info->p_ciphers = WPA_P_CIPHERS_UNSPECIFIED; - goto done; /* only have upto ver */ - } - *ptr_inc += ie_len - *remain_len; - - if (*remain_len < sizeof(wpa_suite_mcast_t)) { - info->parse_status = BCME_BADLEN; - goto done; - } - mcast = (const wpa_suite_mcast_t *)*ptr_inc; - - if (IS_WPA_CIPHER(mcast->type)) { - info->g_cipher = mcast->type; - } else { - info->parse_status = BCME_BAD_IE_DATA; - goto done; - } - - /* for rsn pairwise cipher suite */ - *ptr_inc += sizeof(wpa_suite_mcast_t); - *remain_len -= sizeof(wpa_suite_mcast_t); - - if (!(*remain_len)) { - info->p_ciphers = WPA_P_CIPHERS_UNSPECIFIED; - info->sta_akm = WPA_CIPHER_UNSPECIFIED; - goto done; - } - - ucast = (const wpa_suite_ucast_t *)*ptr_inc; - - if ((*remain_len) < sizeof(ucast->count)) { - info->parse_status = BCME_BADLEN; - goto done; - } - - if (!ucast->count.low && !ucast->count.high) { - info->parse_status = BCME_BADLEN; - goto done; - } - - *p_count = ltoh16_ua(&ucast->count); - if (info->dev_type == DEV_STA && *p_count != 1u) { - info->parse_status = BCME_BAD_IE_DATA; - goto done; - } - if ((*remain_len) < (*p_count * WPA_SUITE_LEN + sizeof(ucast->count))) { - info->parse_status = BCME_BADLEN; - goto done; - } - - if (info->dev_type == DEV_STA) { - if (IS_WPA_CIPHER(ucast->list[0].type)) { - /* update the pairwise cipher */ - info->sta_cipher = ucast->list[0].type; - } else { - info->parse_status = BCME_BAD_IE_DATA; - goto done; - } - } else { - for (i = 0; i < *p_count; i++) { - if (IS_WPA_CIPHER(ucast->list[i].type)) { - info->p_ciphers |= BIT(ucast->list[i].type); - info->rsn_p_ciphers = info->p_ciphers; - } else { - info->parse_status = BCME_BAD_IE_DATA; - goto done; - } - } - } - - /* update buffer ptr and remaining length */ - *ptr_inc += (*p_count * WPA_SUITE_LEN) + sizeof(ucast->count); - *remain_len -= (*p_count * WPA_SUITE_LEN) + sizeof(ucast->count); - -done: - - if (info->parse_status == BCME_OK) { - if (info->g_cipher == WPA_CIPHER_UNSPECIFIED) { - info->g_cipher = WPA_CIPHER_AES_CCM; - } - if (info->p_ciphers == WPA_P_CIPHERS_UNSPECIFIED) { - info->p_ciphers = BIT(WPA_CIPHER_AES_CCM); - info->rsn_p_ciphers = info->p_ciphers; - } - } - - return info->parse_status; -} -/* sta_akm/sta_cipher must be set before this call */ -int -bcmwpa_rsnie_eapol_key_len(rsn_ie_info_t *info) -{ - info->pmk_len = bcmwpa_eapol_key_length(EAPOL_KEY_PMK, info->sta_akm, 0); - info->kck_mic_len = bcmwpa_eapol_key_length(EAPOL_KEY_KCK_MIC, info->sta_akm, 0); - info->kck_len = bcmwpa_eapol_key_length(EAPOL_KEY_KCK, info->sta_akm, 0); - info->kek_len = bcmwpa_eapol_key_length(EAPOL_KEY_KEK, info->sta_akm, 0); - info->tk_len = bcmwpa_eapol_key_length(EAPOL_KEY_TK, 0, info->sta_cipher); - info->ptk_len = info->kck_len + info->kek_len + info->tk_len; -#if defined(WL_FILS) && defined(WLFBT) - info->kck2_len = bcmwpa_eapol_key_length(EAPOL_KEY_KCK2, info->sta_akm, 0); - info->kek2_len = bcmwpa_eapol_key_length(EAPOL_KEY_KEK2, info->sta_akm, 0); - if (WPA_IS_FILS_FT_AKM(info->sta_akm)) { - info->ptk_len += (info->kck2_len + info->kek2_len); - } -#endif /* WL_FILS && WLFBT */ - return BCME_OK; -} -/* Extract and store information from WPA or RSN IEs - * - * called after either - * -an association request has been built (STA), - * - an association was received (AP) - * - a probe request has been built (AP) - * - a probe response was received (STA) - * - * All available information is extracted to be used for subsequent - * bss pruning, association request validation, key descriptor compuation etc. - * - * To be expanded as needed. - * - * ie: RSN IE input - * rsn_info: parsed information. Placed in either bsscfg for self, or scb for peer. - * dev_type: STA_RSN or AP_RSN - * - * Return : parse status. - * NOTE: the parse status is also saved in the the parse_status field. - * NOTE 2 : the IE itself is copied at the end of the structure. Since there is - * no reference to the osh available here, the allocation has to happen outside - * and so the structure cannot be zeroed in this function. - * For the STA, it should happen everytime. - * For the AP, it should happen right after a new beacon/probe has been acquired. - */ - -int -bcmwpa_parse_rsnie(const bcm_tlv_t *ie, rsn_ie_info_t *info, device_type_t dev_type) -{ - - const uint8 *ptr_inc = NULL; - const wpa_suite_mcast_t *mcast; - const wpa_suite_auth_key_mgmt_t *mgmt; - const wpa_pmkid_list_t *pmkid_list; - uint32 remain_len = 0, i; - uint8 auth_ie_type; - uint16 p_count = 0; - uint16 akm_count; - - ASSERT(info != NULL); - - /* this function might be called from place where there - * is no error detection. - * e.g. fron the iem callback. Store status here. - */ - - info->parse_status = BCME_OK; - - if (!ie) { - info->parse_status = BCME_BADARG; - goto done; - } - - /* For AP, do not zero this structure since there could be multiple - * IEs. In that case, add to the existing - * bits in field (ciphers, akms) as necessary. - */ - if (dev_type == DEV_AP) { - /* if already created, check device type */ - if (info->dev_type != DEV_NONE) { - if (info->dev_type != DEV_AP) { - info->parse_status = BCME_BADARG; - goto done; - } - } - } - info->dev_type = dev_type; - ptr_inc = ie->data; - - /* decode auth IE (WPA vs RSN). Fill in the auth_ie_type and version. - * Modify remain_len to indicate the position of the pointer. - */ - /* NOTE the status field will be updated in this call */ - if (bcmwpa_decode_ie_type(ie, info, &remain_len, &auth_ie_type) != BCME_OK) { - goto done; - } - - /* decode multicast, unicast ciphers */ - if (bcmwpa_decode_cipher_suite(info, &ptr_inc, ie->len, &remain_len, &p_count) != BCME_OK) { - goto done; - } - - if (!(remain_len)) { - info->akms = BIT(RSN_AKM_UNSPECIFIED); - goto done; - } - - mgmt = (const wpa_suite_auth_key_mgmt_t *)ptr_inc; - - if (remain_len < sizeof(mgmt->count)) { - info->parse_status = BCME_BADLEN; - goto done; - } - - akm_count = ltoh16_ua(&mgmt->count); - - if (!akm_count) { - info->parse_status = BCME_BADARG; - goto done; - } - - if (dev_type == DEV_STA && akm_count != 1) { - info->parse_status = BCME_BADARG; - goto done; - } - - if ((remain_len) < (akm_count * WPA_SUITE_LEN + sizeof(mgmt->count))) { - info->parse_status = BCME_BADLEN; - goto done; - } - - if (dev_type == DEV_STA) { - info->sta_akm = mgmt->list[0].type; - } - for (i = 0; i < akm_count; i++) { - if (bcmwpa_is_valid_akm(mgmt->list[i].type) == BCME_OK) { - ASSERT((mgmt->list[i].type) < - (sizeof(info->akms) * NBBY)); - info->akms |= BIT(mgmt->list[i].type); - } - } - - /* save IE dependent values in their respective fields */ - if (dev_type == DEV_AP) { - if (auth_ie_type == RSN_AUTH_IE) { - info->rsn_akms = info->akms; - } else if (auth_ie_type == WPA_AUTH_IE) { - info->wpa_akms = info->akms; - info->wpa_p_ciphers = info->p_ciphers; - } - } - - /* as a STA, at this point, we can compute the key descriptor version */ - if (dev_type == DEV_STA) { - info->key_desc = wlc_calc_rsn_desc_version(info); - /* For STA, we can set the auth ie */ - if (auth_ie_type == RSN_AUTH_IE) { - info->auth_ie = info->rsn_ie; - info->auth_ie_len = info->rsn_ie_len; - } else { - info->auth_ie = info->wpa_ie; - info->auth_ie_len = info->wpa_ie_len; - } - } - - /* RSN AKM/cipher suite related EAPOL key length update */ - bcmwpa_rsnie_eapol_key_len(info); - - /* for rsn capabilities */ - ptr_inc += akm_count * WPA_SUITE_LEN + sizeof(mgmt->count); - remain_len -= akm_count * WPA_SUITE_LEN + sizeof(mgmt->count); - - if (!(remain_len)) { - goto done; - } - if (remain_len < RSN_CAP_LEN) { - info->parse_status = BCME_BADLEN; - goto done; - } - - if (ie->id == DOT11_MNG_RSN_ID) { - info->caps = ltoh16_ua(ptr_inc); - } - - /* check if AKMs require MFP capable to be set */ - if ((info->akms & RSN_MFPC_AKM_MASK) && !(info->caps & RSN_CAP_MFPC)) { - /* NOTE: Acting as WPA3 CTT testbed device, it requires to send assoc request frame - with user provided mfp value as is. So should not return error here. - */ -#ifndef WPA3_CTT - info->parse_status = BCME_EPERM; - goto done; -#endif /* WPA3_CTT */ - } - - /* for rsn PMKID */ - ptr_inc += RSN_CAP_LEN; - remain_len -= RSN_CAP_LEN; - - if (!(remain_len)) { - goto done; - } - - /* here's possible cases after RSN_CAP parsed - * a) pmkid_count 2B(00 00) - * b) pmkid_count 2B(00 00) + BIP 4B - * c) pmkid_count 2B(non zero) + pmkid_count * 16B - * d) pmkid_count 2B(non zero) + pmkid_count * 16B + BIP 4B - */ - - /* pmkids_offset set to - * 1) if pmkid_count field(2B) present, point to first PMKID offset in the RSN ID - * no matter what pmkid_count value is. (true, even if pmkid_count == 00 00) - * 2) if pmkid_count field(2B) not present, it shall be zero. - */ - - pmkid_list = (const wpa_pmkid_list_t*)ptr_inc; - - if ((remain_len) < sizeof(pmkid_list->count)) { - info->parse_status = BCME_BADLEN; - goto done; - } - - info->pmkid_count = (uint8)ltoh16_ua(&pmkid_list->count); - ptr_inc += sizeof(pmkid_list->count); - remain_len -= sizeof(pmkid_list->count); - - if (remain_len < (uint32)(info->pmkid_count * WPA2_PMKID_LEN)) { - info->parse_status = BCME_BADLEN; - goto done; - } - - info->pmkids_offset = ie->len + TLV_HDR_LEN - remain_len; - /* for rsn group management cipher suite */ - ptr_inc += info->pmkid_count * WPA2_PMKID_LEN; - remain_len -= info->pmkid_count * WPA2_PMKID_LEN; - - if (!(remain_len)) { - goto done; - } - /* - * from WPA2_Security_Improvements_Test_Plan_v1.0 - * 4.2.4 APUT RSNE bounds verification using WPA2-PSK - * May content RSNE extensibile element ay this point - */ - if (remain_len < sizeof(wpa_suite_mcast_t)) { - info->parse_status = BCME_BADLEN; - goto done; - } - - mcast = (const wpa_suite_mcast_t *)ptr_inc; - if (IS_VALID_BIP_CIPHER((rsn_cipher_t)mcast->type)) { - info->g_mgmt_cipher = (rsn_cipher_t)mcast->type; - } - -done: - return info->parse_status; -} - -/* Determine if the IE is of WPA or RSN type. Decode - * up to version field. Modify the remaining len parameter to - * indicate where the next field is. - * Store and return error status. - */ - -int -bcmwpa_decode_ie_type(const bcm_tlv_t *ie, rsn_ie_info_t *info, uint32 *remaining, - uint8 *type) -{ - const uint8 * ptr_inc = (const uint8 *)ie->data; - uint32 remain_len = ie->len; - uint8 version, version_len; - - if (ie->id == DOT11_MNG_WPA_ID) { - /* min len check */ - if (remain_len < WPA_IE_FIXED_LEN) { - info->parse_status = BCME_BADLEN; - goto done; - } - /* WPA IE */ - if (memcmp(WPA_OUI, ie->data, WPA_OUI_LEN)) { - /* bad OUI */ - info->parse_status = BCME_BADARG; - goto done; - } - ptr_inc += WPA_OUI_LEN; - if (*ptr_inc == WPA_OUI_TYPE) { - *type = WPA_AUTH_IE; - } else if (*ptr_inc == WFA_OUI_TYPE_OSEN) { - *type = OSEN_AUTH_IE; - } - else { - /* wrong type */ - info->parse_status = BCME_BADARG; - goto done; - } - - ptr_inc ++; - remain_len -= WPA_OUI_LEN + 1u; - version_len = WPA_VERSION_LEN; - } - else if (ie->id == DOT11_MNG_RSN_ID) { - if (remain_len < WPA2_VERSION_LEN) { - info->parse_status = BCME_BADLEN; - goto done; - } - /* RSN IE */ - *type = RSN_AUTH_IE; - version_len = WPA2_VERSION_LEN; - } else { - printf("IE ID %d\n", ie->id); - /* TODO : add support for CCX, WAPI ? */ - info->parse_status = BCME_UNSUPPORTED; - goto done; - } - info->auth_ie_type |= *type; - /* mask down to uint8 for Windows build */ - version = 0xff & ltoh16_ua(ptr_inc); - if (version > MAX_RSNE_SUPPORTED_VERSION) { - info->parse_status = BCME_UNSUPPORTED; - goto done; - } - - info->version = (uint8)version; - *remaining = remain_len - version_len; -done: - return info->parse_status; -} - -/* rsn info allocation management. - * - * In some cases, the rsn ie info structures are embedded in the scan results - * which can be shared by different lists. - * To keep track of their allocation, we use a reference counter. - * The counter is incremented on demand by rsn_ie_info_add_ref() - * at the time the reference is shared. - * It is decremented in rsn_ie_info_rel_ref - * When ref_count gets to 0, bcmwpa_rsn_ie_info_free_mem - * is called to free the whole structure. - */ - -/* free rsn_ie and wpa_ie, if any, and zero the rsn_info */ -void -bcmwpa_rsn_ie_info_reset(rsn_ie_info_t *rsn_info, osl_t *osh) -{ - uint8 ref_count; - if (rsn_info == NULL) { - return; - } - ref_count = rsn_info->ref_count; - MFREE(osh, rsn_info->rsn_ie, rsn_info->rsn_ie_len); - MFREE(osh, rsn_info->wpa_ie, rsn_info->wpa_ie_len); - MFREE(osh, rsn_info->rsnxe, rsn_info->rsnxe_len); - bzero(rsn_info, sizeof(*rsn_info)); - rsn_info->ref_count = ref_count; - -} - -static -void bcmwpa_rsn_ie_info_free_mem(rsn_ie_info_t **rsn_info, osl_t *osh) -{ - bcmwpa_rsn_ie_info_reset(*rsn_info, osh); - MFREE(osh, *rsn_info, sizeof(**rsn_info)); - *rsn_info = NULL; -} - -void bcmwpa_rsn_ie_info_rel_ref(rsn_ie_info_t **rsn_info, osl_t *osh) -{ - - if (rsn_info == NULL || *rsn_info == NULL) { - return; - } - - /* already freed ? */ - if ((*rsn_info)->ref_count == 0) { - ASSERT(0); - return; - } - /* decrement ref count */ - (*rsn_info)->ref_count -= 1; - /* clear reference. */ - if ((*rsn_info)->ref_count > 0) { - *rsn_info = NULL; - return; - } - /* free memory and clear reference */ - bcmwpa_rsn_ie_info_free_mem(rsn_info, osh); -} - -int -bcmwpa_rsn_ie_info_add_ref(rsn_ie_info_t *rsn_info) -{ - int status = BCME_OK; - if (rsn_info == NULL) { - goto done; - } - if (rsn_info->ref_count == 0) { - /* don't increase from 0, which means this structure has been freed earlier. - * That reference should not exist anymore. - */ - ASSERT(0); - status = BCME_BADARG; - goto done; - } - rsn_info->ref_count++; -done: - return status; -} - -#else /* Not RSN_IE_INFO_STRUCT_RELOCATED */ - -int -bcmwpa_parse_rsnie(const bcm_tlv_t *ie, rsn_ie_info_t *info, device_type_t dev_type) -{ - - const uint8 *ptr_inc = NULL; - const wpa_suite_ucast_t *ucast; - const wpa_suite_mcast_t *mcast; - const wpa_suite_auth_key_mgmt_t *mgmt; - const wpa_pmkid_list_t *pmkid_list; - uint32 remain_len = 0, i; - - ASSERT(info != NULL); - - /* this function might be called from place where there - * is no error detection. - * e.g. fron the iem callback. Store status here. - */ - - info->parse_status = BCME_OK; - - if (!ie) { - info->parse_status = BCME_BADARG; - goto done; - } - - /* For AP, do not zero this structure since there could be multiple - * IEs. In that case, add to the existing - * bits in field (ciphers, akms) as necessary. - */ - if (dev_type != DEV_AP) { - bzero(info, sizeof(*info)); - } else { - /* if already created, check device type */ - if (info->dev_type != DEV_NONE) { - if (info->dev_type != DEV_AP) { - info->parse_status = BCME_BADARG; - goto done; - } - } - } - info->dev_type = dev_type; - ptr_inc = ie->data; - - /* decode auth IE (WPA vs RSN). Fill in the auth_ie_type and version. - * Modify remain_len to indicate the position of the pointer. - */ - /* NOTE the status field will be updated in this call */ - if (bcmwpa_decode_ie_type(ie, info, &remain_len) != BCME_OK) { - goto done; - } - - if (!(remain_len)) { - info->g_cipher = WPA_CIPHER_NONE; - goto done; /* only have upto ver */ - } - ptr_inc += ie->len - remain_len; - - if (remain_len < sizeof(wpa_suite_mcast_t)) { - info->parse_status = BCME_BADLEN; - goto done; - } - mcast = (const wpa_suite_mcast_t *)ptr_inc; - - if (IS_WPA_CIPHER(mcast->type)) { - info->g_cipher = mcast->type; - } - - /* for rsn pairwise cipher suite */ - ptr_inc += sizeof(wpa_suite_mcast_t); - remain_len -= sizeof(wpa_suite_mcast_t); - - if (!(remain_len)) { - goto done; - } - - ucast = (const wpa_suite_ucast_t *)ptr_inc; - - if ((remain_len) < sizeof(ucast->count)) { - info->parse_status = BCME_BADLEN; - goto done; - } - - if (!ucast->count.low && !ucast->count.high) { - info->parse_status = BCME_BADLEN; - goto done; - } - - info->p_count = (uint8)ltoh16_ua(&ucast->count); - - if (dev_type == DEV_STA && info->p_count != 1) { - info->parse_status = BCME_BADARG; - goto done; - } - if ((remain_len) < (info->p_count * WPA_SUITE_LEN + sizeof(ucast->count))) { - info->parse_status = BCME_BADLEN; - goto done; - } - - if (IS_WPA_CIPHER(ucast->list[0].type)) { - /* update the pairwise cipher */ - /* set cipher to invald value */ - if (dev_type == DEV_STA) { - info->sta_cipher = ucast->list[0].type; - } else { - for (i = 0; i < info->p_count; i++) { - if (IS_WPA_CIPHER(ucast->list[i].type)) { - info->p_ciphers |= BIT(ucast->list[i].type); - } else { - info->parse_status = BCME_BAD_IE_DATA; - goto done; - } - } - } - } else { - info->parse_status = BCME_BAD_IE_DATA; - goto done; - } - - /* for rsn AKM authentication */ - ptr_inc += info->p_count * WPA_SUITE_LEN + sizeof(ucast->count); - remain_len -= (info->p_count * WPA_SUITE_LEN + sizeof(ucast->count)); - - mgmt = (const wpa_suite_auth_key_mgmt_t *)ptr_inc; - - if (remain_len < sizeof(mgmt->count)) { - info->parse_status = BCME_BADLEN; - goto done; - } - - info->akm_count = (uint8)ltoh16_ua(&mgmt->count); - - if (!info->akm_count) { - info->parse_status = BCME_BADARG; - goto done; - } - - if (dev_type == DEV_STA && info->akm_count != 1) { - info->parse_status = BCME_BADARG; - goto done; - } - - if ((remain_len) < (info->akm_count * WPA_SUITE_LEN + sizeof(mgmt->count))) { - info->parse_status = BCME_BADLEN; - goto done; - } - - if (dev_type == DEV_STA) { - info->sta_akm = mgmt->list[0].type; - } - for (i = 0; i < info->akm_count; i++) { - if (bcmwpa_is_valid_akm(mgmt->list[i].type) == BCME_OK) { - ASSERT((mgmt->list[i].type) < - (sizeof(info->akms) * NBBY)); - info->akms |= BIT(mgmt->list[i].type); - } - } - - /* RSN AKM/cipher suite related EAPOL key length update */ - info->pmk_len = bcmwpa_eapol_key_length(EAPOL_KEY_PMK, info->sta_akm, 0); - info->kck_mic_len = bcmwpa_eapol_key_length(EAPOL_KEY_KCK_MIC, info->sta_akm, 0); - info->kck_len = bcmwpa_eapol_key_length(EAPOL_KEY_KCK, info->sta_akm, 0); - info->kek_len = bcmwpa_eapol_key_length(EAPOL_KEY_KEK, info->sta_akm, 0); - info->tk_len = bcmwpa_eapol_key_length(EAPOL_KEY_TK, 0, info->sta_cipher); - info->ptk_len = info->kck_mic_len + info->kek_len + info->tk_len; -#if defined(WL_FILS) && defined(WLFBT) - info->kck2_len = bcmwpa_eapol_key_length(EAPOL_KEY_KCK2, info->sta_akm, 0); - info->kek2_len = bcmwpa_eapol_key_length(EAPOL_KEY_KEK2, info->sta_akm, 0); -#endif /* WL_FILS && WLFBT */ - - /* for rsn capabilities */ - ptr_inc += info->akm_count * WPA_SUITE_LEN + sizeof(mgmt->count); - remain_len -= info->akm_count * WPA_SUITE_LEN + sizeof(mgmt->count); - - /* as a STA, at this point, we can compute the key descriptor version */ - if (dev_type == DEV_STA) { - info->key_desc = wlc_calc_rsn_desc_version(info); - } - - if (!(remain_len)) { - goto done; - } - if (remain_len < RSN_CAP_LEN) { - info->parse_status = BCME_BADLEN; - goto done; - } - - if (ie->id == DOT11_MNG_RSN_ID) { - info->caps = ltoh16_ua(ptr_inc); - } - - /* for WFA If MFP required, check that we are using a SHA256 AKM - * or higher and nothing else. - * In case MFP Required and MFP Capable do not enforce check of AKM. - */ - if ((info->caps & RSN_CAP_MFPR) && !(info->akms & (1u << RSN_AKM_PSK))) { - if ((info->akms & (AKM_SHA256_MASK | AKM_SHA384_MASK)) == 0 || - (info->akms & ~(AKM_SHA256_MASK | AKM_SHA384_MASK))) { - info->parse_status = BCME_EPERM; - goto done; - } - } - - /* check if AKMs require MFP capable to be set */ - if ((info->akms & RSN_MFPC_AKM_MASK) && !(info->caps & RSN_CAP_MFPC)) { - info->parse_status = BCME_EPERM; - goto done; - } - - /* for rsn PMKID */ - ptr_inc += RSN_CAP_LEN; - remain_len -= RSN_CAP_LEN; - - if (!(remain_len)) { - goto done; - } - - pmkid_list = (const wpa_pmkid_list_t*)ptr_inc; - - if ((remain_len) < sizeof(pmkid_list->count)) { - info->parse_status = BCME_BADLEN; - goto done; - } - - info->pmkid_count = (uint8)ltoh16_ua(&pmkid_list->count); - ptr_inc += sizeof(pmkid_list->count); - remain_len -= sizeof(pmkid_list->count); - - if (info->pmkid_count) { - if (remain_len < (uint32)(info->pmkid_count * WPA2_PMKID_LEN)) { - info->parse_status = BCME_BADLEN; - goto done; - } - info->pmkids_offset = ie->len + TLV_HDR_LEN - remain_len; - /* for rsn group management cipher suite */ - ptr_inc += info->pmkid_count * WPA2_PMKID_LEN; - remain_len -= info->pmkid_count * WPA2_PMKID_LEN; - } - - if (!(remain_len)) { - goto done; - } - /* - * from WPA2_Security_Improvements_Test_Plan_v1.0 - * 4.2.4 APUT RSNE bounds verification using WPA2-PSK - * May content RSNE extensibile element ay this point - */ - if (remain_len < sizeof(wpa_suite_mcast_t)) { - info->parse_status = BCME_BADLEN; - goto done; - } - - mcast = (const wpa_suite_mcast_t *)ptr_inc; - if (IS_VALID_BIP_CIPHER((rsn_cipher_t)mcast->type)) { - info->g_mgmt_cipher = (rsn_cipher_t)mcast->type; - } - -done: - return info->parse_status; -} - -/* Determine if the IE is of WPA or RSN type. Decode - * up to version field. Modify the remaining len parameter to - * indicate where the next field is. - * Store and return error status. - */ - -int -bcmwpa_decode_ie_type(const bcm_tlv_t *ie, rsn_ie_info_t *info, uint32 *remaining) -{ - const uint8 * ptr_inc = (const uint8 *)ie->data; - uint32 remain_len = ie->len; - uint8 version, version_len; - - if (ie->id == DOT11_MNG_WPA_ID) { - /* min len check */ - if (remain_len < WPA_IE_FIXED_LEN) { - info->parse_status = BCME_BADLEN; - goto done; - } - /* WPA IE */ - if (memcmp(WPA_OUI, ie->data, WPA_OUI_LEN)) { - /* bad OUI */ - info->parse_status = BCME_BADARG; - goto done; - } - ptr_inc += WPA_OUI_LEN; - if (*ptr_inc != WPA_OUI_TYPE) { - /* wrong type */ - info->parse_status = BCME_BADARG; - goto done; - } - ptr_inc ++; - remain_len -= WPA_OUI_LEN + 1u; - info->auth_ie_type |= WPA_AUTH_IE; - version_len = WPA_VERSION_LEN; - } - else if (ie->id == DOT11_MNG_RSN_ID) { - if (remain_len < WPA2_VERSION_LEN) { - info->parse_status = BCME_BADLEN; - goto done; - } - /* RSN IE */ - info->auth_ie_type |= RSN_AUTH_IE; - version_len = WPA2_VERSION_LEN; - } else { - /* TODO : add support for CCX, WAPI ? */ - info->parse_status = BCME_UNSUPPORTED; - goto done; - } - - /* mask down to uint8 for Windows build */ - version = 0xff & ltoh16_ua(ptr_inc); - if (version > MAX_RSNE_SUPPORTED_VERSION) { - info->parse_status = BCME_UNSUPPORTED; - goto done; - } - - info->version = (uint8)version; - *remaining = remain_len - version_len; -done: - return info->parse_status; -} - -#endif /* RSN_IE_INFO_STRUCT_RELOCATED */ - -/* return the key descriptor version based on the AKM suite - * applicable only for STA with RSN - */ -static uint16 -wlc_calc_rsn_desc_version(const rsn_ie_info_t *rsn_info) -{ - uint16 key_desc_ver = WPA_KEY_DESC_V0; - uint8 akm; - - ASSERT(rsn_info != NULL); - ASSERT(rsn_info->dev_type == DEV_STA); - akm = rsn_info->sta_akm; - - /* Refer Draft 802.11REVmd_D1.0.pdf Section 12.7.2 */ - if ((akm == RSN_AKM_UNSPECIFIED) || - (akm == RSN_AKM_PSK)) { - if ((rsn_info->sta_cipher == WPA_CIPHER_TKIP) || - (rsn_info->sta_cipher == WPA_CIPHER_NONE)) { - key_desc_ver = WPA_KEY_DESC_V1; - } else if ((rsn_info->sta_cipher != WPA_CIPHER_TKIP) || - (rsn_info->g_cipher != WPA_CIPHER_TKIP)) { - key_desc_ver = WPA_KEY_DESC_V2; - } - } else if ((akm == RSN_AKM_FBT_1X) || - (akm == RSN_AKM_FBT_PSK) || - (akm == RSN_AKM_SHA256_1X) || - (akm == RSN_AKM_SHA256_PSK)) { - key_desc_ver = WPA_KEY_DESC_V3; - } - return key_desc_ver; -} - -/* get EAPOL key length based on RSN IE AKM/Cipher(unicast) suite - * key: EAPOL key type - * akm: RSN AKM suite selector - * cipher: RSN unicast cipher suite selector - * return: key length found in matching key_length_entry table - */ -uint8 -bcmwpa_eapol_key_length(eapol_key_type_t key, rsn_akm_t akm, rsn_cipher_t cipher) -{ - uint i; - uint8 key_length = 0; - uint8 suite; - const key_length_entry_t *key_entry = NULL; - - if (key == EAPOL_KEY_TK) { - suite = cipher; - } else { - suite = akm; - } - for (i = 0; i < ARRAYSIZE(eapol_key_lookup_tbl); i++) { - if (eapol_key_lookup_tbl[i].key == key) { - key_entry = eapol_key_lookup_tbl[i].key_entry; - break; - } - } - - if (key_entry) { - i = 0; - do { - if (key_entry[i].suite == suite || key_entry[i].suite == 0) { - key_length = key_entry[i].len; - break; - } - i++; - } while (i > 0); - } - - return key_length; -} - -/* check if RSM AKM suite is valid */ -static int bcmwpa_is_valid_akm(const rsn_akm_t akm) -{ - uint i = 0; - for (i = 0; i < ARRAYSIZE(rsn_akm_lookup_tbl); i++) { - if (akm == rsn_akm_lookup_tbl[i].rsn_akm) { - return BCME_OK; - } - } - return BCME_ERROR; -} - -/* checking cipher suite selector restriction based on AKM */ -int -bcmwpa_rsn_akm_cipher_match(rsn_ie_info_t *rsn_info) -{ - uint i; - const rsn_akm_cipher_match_entry_t *p_entry = NULL; - - for (i = 0; i < ARRAYSIZE(rsn_akm_cipher_match_table); i++) { - /* akm match */ - if (rsn_info->sta_akm == rsn_akm_cipher_match_table[i].akm_type) { - p_entry = &rsn_akm_cipher_match_table[i]; - break; - } - } - - if (p_entry) { - /* unicast cipher match */ - if (!(rsn_info->p_ciphers & p_entry->u_cast)) { - return BCME_UNSUPPORTED; - } - /* multicast cipher match */ - if (!(BCM_BIT(rsn_info->g_cipher) & p_entry->m_cast)) { - return BCME_UNSUPPORTED; - } - /* group management cipher match */ - if (!(BCM_BIT(rsn_info->g_mgmt_cipher) & p_entry->g_mgmt)) { - return BCME_UNSUPPORTED; - } - } - return BCME_OK; -} - -#if defined(BCMSUP_PSK) || defined(BCMSUPPL) -uint8 bcmwpa_find_group_mgmt_algo(rsn_cipher_t g_mgmt_cipher) -{ - uint8 i; - uint8 algo = CRYPTO_ALGO_BIP; - - for (i = 0; i < ARRAYSIZE(group_mgmt_cipher_algo); i++) { - if ((group_mgmt_cipher_algo[i].g_mgmt_cipher == g_mgmt_cipher)) { - algo = group_mgmt_cipher_algo[i].bip_algo; - break; - } - } - - return algo; -} -#endif /* defined(BCMSUP_PSK) || defined(BCMSUPPL) */ - -#if defined(WL_BAND6G) -bool -bcmwpa_is_invalid_6g_akm(const rsn_akm_mask_t akms_bmp) -{ - if (akms_bmp & rsn_akm_6g_inval_mask) { - return TRUE; - } - return FALSE; -} - -bool -bcmwpa_is_invalid_6g_cipher(const rsn_ciphers_t ciphers_bmp) -{ - if (ciphers_bmp & cipher_6g_inval_mask) { - return TRUE; - } - return FALSE; -} -#endif /* WL_BAND6G */ - -/* - * bcmwpa_get_algo_key_len returns the key_length for the algorithm. - * API : bcm_get_algorithm key length - * input: algo: Get the crypto algorithm. - * km: Keymgmt information. - * output: returns the key length and error status. - * BCME_OK is valid else BCME_UNSUPPORTED if not supported - */ -int -bcmwpa_get_algo_key_len(uint8 algo, uint16 *key_len) -{ - int err = BCME_OK; - - if (key_len == NULL) { - return BCME_BADARG; - } - - switch (algo) { - case CRYPTO_ALGO_WEP1: - *key_len = WEP1_KEY_SIZE; - break; - - case CRYPTO_ALGO_TKIP: - *key_len = TKIP_KEY_SIZE; - break; - - case CRYPTO_ALGO_WEP128: - *key_len = WEP128_KEY_SIZE; - break; - - case CRYPTO_ALGO_AES_CCM: /* fall through */ - case CRYPTO_ALGO_AES_GCM: /* fall through */ - case CRYPTO_ALGO_AES_OCB_MSDU : /* fall through */ - case CRYPTO_ALGO_AES_OCB_MPDU: - *key_len = AES_KEY_SIZE; - break; - -#ifdef BCMWAPI_WPI - /* TODO: Need to double check */ - case CRYPTO_ALGO_SMS4: - *key_len = SMS4_KEY_LEN + SMS4_WPI_CBC_MAC_LEN; - break; -#endif /* BCMWAPI_WPI */ - - case CRYPTO_ALGO_BIP: /* fall through */ - case CRYPTO_ALGO_BIP_GMAC: - *key_len = BIP_KEY_SIZE; - break; - - case CRYPTO_ALGO_AES_CCM256: /* fall through */ - case CRYPTO_ALGO_AES_GCM256: /* fall through */ - case CRYPTO_ALGO_BIP_CMAC256: /* fall through */ - case CRYPTO_ALGO_BIP_GMAC256: - *key_len = AES256_KEY_SIZE; - break; - - case CRYPTO_ALGO_OFF: - *key_len = 0; - break; - -#if !defined(BCMCCX) && !defined(BCMEXTCCX) - case CRYPTO_ALGO_NALG: /* fall through */ -#else - case CRYPTO_ALGO_CKIP: /* fall through */ - case CRYPTO_ALGO_CKIP_MMH: /* fall through */ - case CRYPTO_ALGO_WEP_MMH: /* fall through */ - case CRYPTO_ALGO_PMK: /* fall through default */ -#endif /* !defined(BCMCCX) && !defined(BCMEXTCCX) */ - default: - *key_len = 0; - err = BCME_UNSUPPORTED; - break; - } - return err; -} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmxtlv.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmxtlv.c old mode 100755 new mode 100644 index 70bb74e7c074..33d02ae6a3c8 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmxtlv.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmxtlv.c @@ -1,7 +1,7 @@ /* * Driver O/S-independent utility routines * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -24,10 +24,6 @@ #include #include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) -#include -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) */ - #ifdef BCMDRIVER #include #else /* !BCMDRIVER */ @@ -428,14 +424,14 @@ int bcm_unpack_xtlv_buf(void *ctx, const uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts, bcm_xtlv_unpack_cbfn_t *cbfn) { + int res = BCME_OK; + const bcm_xtlv_t *ptlv; uint16 len; uint16 type; - int res = BCME_OK; - int size; - const bcm_xtlv_t *ptlv; - int sbuflen = buflen; const uint8 *data; - int hdr_size; + uint32 sbuflen = buflen; + uint32 hdr_size; /* size of tlv header */ + uint32 size; /* size of tlv including header + data */ ASSERT(!buflen || tlv_buf); ASSERT(!buflen || cbfn); @@ -447,12 +443,11 @@ bcm_unpack_xtlv_buf(void *ctx, const uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opt bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts); size = bcm_xtlv_size_for_data(len, opts); - sbuflen -= size; - /* check for buffer overrun */ - if (sbuflen < 0) { + if (sbuflen < size) { break; } + sbuflen -= size; if ((res = cbfn(ctx, data, type, len)) != BCME_OK) { break; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c old mode 100755 new mode 100644 index 4ce1ffa90385..9b65c3c04ab8 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c @@ -1,18 +1,17 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /** @file dbus.c * * Hides details of USB / SDIO / SPI interfaces and OS details. It is intended to shield details and * provide the caller with one common bus interface for all dongle devices. In practice, it is only * used for USB interfaces. DBUS is not a protocol, but an abstraction layer. * - * Copyright (C) 1999-2016, Broadcom Corporation - * + * Copyright (C) 2022, Broadcom. + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -20,18 +19,11 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. * * - * <> - * - * $Id: dbus.c 553311 2015-04-29 10:23:08Z $ + * <> */ - #include #include "osl.h" #include "dbus.h" @@ -43,8 +35,22 @@ #include #endif #include +#ifdef WL_CFG80211 +#include +#include +#endif -#if defined(BCM_REQUEST_FW) +#include +#if defined(BCM_DNGL_EMBEDIMAGE) +#include +#include +#include +#include +#include +#include +#include +#include +#elif defined(BCM_REQUEST_FW) #include #include #include @@ -52,15 +58,42 @@ #include #include #include +#endif /* #if defined(BCM_DNGL_EMBEDIMAGE) */ +#if defined(EHCI_FASTPATH_TX) || defined(EHCI_FASTPATH_RX) +#include +#endif /* EHCI_FASTPATH_TX || EHCI_FASTPATH_RX */ + +#if defined(BCM_DNGL_EMBEDIMAGE) +/* zlib file format field ids etc from gzio.c */ +#define Z_DEFLATED 8 +#define ASCII_FLAG 0x01 /**< bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /**< bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /**< bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /**< bit 3 set: original file name present */ +#define COMMENT 0x10 /**< bit 4 set: file comment present */ +#define RESERVED 0xE0 /**< bits 5..7: reserved */ + +/* Rename define */ +#ifdef WL_FW_DECOMP +#define UNZIP_ENAB(info) 1 +#else +#define UNZIP_ENAB(info) 0 + +#ifdef inflateInit2 +#undef inflateInit2 +#define inflateInit2(a, b) Z_ERRNO #endif +#define inflate(a, b) Z_STREAM_ERROR +#define inflateEnd(a) do {} while (0) +#define crc32(a, b, c) -1 +#define free(a) do {} while (0) +#endif /* WL_FW_DECOMP */ - - -#if defined(BCM_REQUEST_FW) +#elif defined(BCM_REQUEST_FW) #ifndef VARS_MAX #define VARS_MAX 8192 #endif -#endif +#endif /* #if defined(BCM_DNGL_EMBEDIMAGE) */ #ifdef DBUS_USB_LOOPBACK extern bool is_loopback_pkt(void *buf); @@ -83,26 +116,33 @@ typedef struct dhd_bus { dhd_pub_t *dhd; void *cbarg; - dbus_callbacks_t *cbs; /* callbacks to higher level, e.g. dhd_linux.c */ + dbus_callbacks_t *cbs; /**< callbacks to higher level, eg dhd_linux.c */ void *bus_info; - dbus_intf_t *drvintf; /* callbacks to lower level, e.g. dbus_usb.c or dbus_usb_linux.c */ + dbus_intf_t *drvintf; /**< callbacks to lower level, eg dbus_usb.c or dbus_usb_linux.c */ uint8 *fw; int fwlen; uint32 errmask; - int rx_low_watermark; /* avoid rx overflow by filling rx with free IRBs */ + int rx_low_watermark; /**< avoid rx overflow by filling rx with free IRBs */ int tx_low_watermark; bool txoff; - bool txoverride; /* flow control related */ + bool txoverride; /**< flow control related */ bool rxoff; bool tx_timer_ticking; - + uint ctl_completed; dbus_irbq_t *rx_q; dbus_irbq_t *tx_q; +#ifdef BCMDBG + int *txpend_q_hist; + int *rxpend_q_hist; +#endif /* BCMDBG */ +#ifdef EHCI_FASTPATH_RX + atomic_t rx_outstanding; +#endif uint8 *nvram; int nvram_len; - uint8 *image; /* buffer for combine fw and nvram */ + uint8 *image; /**< buffer for combine fw and nvram */ int image_len; uint8 *orig_fw; int origfw_len; @@ -115,6 +155,7 @@ typedef struct dhd_bus { #endif char *fw_path; /* module_param: path to firmware image */ char *nv_path; /* module_param: path to nvram vars file */ + uint64 last_suspend_end_time; } dhd_bus_t; struct exec_parms { @@ -153,12 +194,13 @@ static void dbus_if_pktfree(void *handle, void *p, bool send); static struct dbus_irb *dbus_if_getirb(void *cbarg, bool send); static void dbus_if_rxerr_indicate(void *handle, bool on); -void * dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, - uint16 bus_no, uint16 slot, uint32 hdrlen); -void dhd_dbus_disconnect_cb(void *arg); -void dbus_detach(dhd_bus_t *pub); +static int dbus_suspend(void *context); +static int dbus_resume(void *context); +static void * dhd_dbus_probe_cb(uint16 bus_no, uint16 slot, uint32 hdrlen); +static void dhd_dbus_disconnect_cb(void *arg); +static void dbus_detach(dhd_bus_t *pub); -/** functions in this file that are called by lower DBUS levels, e.g. dbus_usb.c */ +/** functions in this file that are called by lower DBUS levels, eg dbus_usb.c */ static dbus_intf_callbacks_t dbus_intf_cbs = { dbus_if_send_irb_timeout, dbus_if_send_irb_complete, @@ -166,9 +208,9 @@ static dbus_intf_callbacks_t dbus_intf_cbs = { dbus_if_errhandler, dbus_if_ctl_complete, dbus_if_state_change, - NULL, /* isr */ - NULL, /* dpc */ - NULL, /* watchdog */ + NULL, /**< isr */ + NULL, /**< dpc */ + NULL, /**< watchdog */ dbus_if_pktget, dbus_if_pktfree, dbus_if_getirb, @@ -181,13 +223,9 @@ static dbus_intf_callbacks_t dbus_intf_cbs = { * can be called inside disconnect() */ static dbus_intf_t *g_busintf = NULL; -static probe_cb_t probe_cb = NULL; -static disconnect_cb_t disconnect_cb = NULL; -static void *probe_arg = NULL; -static void *disc_arg = NULL; #if defined(BCM_REQUEST_FW) -int8 *nonfwnvram = NULL; /* stand-alone multi-nvram given with driver load */ +int8 *nonfwnvram = NULL; /**< stand-alone multi-nvram given with driver load */ int nonfwnvramlen = 0; #endif /* #if defined(BCM_REQUEST_FW) */ @@ -202,24 +240,24 @@ static int dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq, int size static int dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb); static int dbus_rxirbs_fill(dhd_bus_t *dhd_bus); static int dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info); -static void dbus_disconnect(void *handle); -static void *dbus_probe(void *arg, const char *desc, uint32 bustype, - uint16 bus_no, uint16 slot, uint32 hdrlen); +#if (defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW)) #if defined(BCM_REQUEST_FW) extern char * dngl_firmware; extern unsigned int dngl_fwlen; +#endif /* #if defined(BCM_REQUEST_FW) */ #ifndef EXTERNAL_FW_PATH static int dbus_get_nvram(dhd_bus_t *dhd_bus); static int dbus_jumbo_nvram(dhd_bus_t *dhd_bus); -static int dbus_otp(dhd_bus_t *dhd_bus, uint16 *boardtype, uint16 *boardrev); static int dbus_select_nvram(dhd_bus_t *dhd_bus, int8 *jumbonvram, int jumbolen, uint16 boardtype, uint16 boardrev, int8 **nvram, int *nvram_len); #endif /* !EXTERNAL_FW_PATH */ -extern int dbus_zlib_decomp(dhd_bus_t *dhd_bus); +#ifndef BCM_REQUEST_FW +static int dbus_zlib_decomp(dhd_bus_t *dhd_bus); extern void *dbus_zlib_calloc(int num, int size); extern void dbus_zlib_free(void *ptr); #endif +#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */ /* function */ void @@ -375,13 +413,12 @@ dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq, int size_irb) ASSERT(dhd_bus); for (i = 0; i < nq; i++) { - /* MALLOC dbus_irb_tx or dbus_irb_rx, but cast to simple dbus_irb_t linkedlist */ - irb = (dbus_irb_t *) MALLOC(dhd_bus->pub.osh, size_irb); + /* MALLOCZ dbus_irb_tx or dbus_irb_rx, but cast to simple dbus_irb_t linkedlist */ + irb = (dbus_irb_t *) MALLOCZ(dhd_bus->pub.osh, size_irb); if (irb == NULL) { ASSERT(irb); return DBUS_ERR; } - bzero(irb, size_irb); /* q_enq() does not need to go through EXEC_xxLOCK() during init() */ q_enq(q, irb); @@ -417,6 +454,21 @@ dbus_rxirbs_fill(dhd_bus_t *dhd_bus) { int err = DBUS_OK; +#ifdef EHCI_FASTPATH_RX + while (atomic_read(&dhd_bus->rx_outstanding) < 100) /* TODO: Improve constant */ + { +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) + /* NOCOPY force new packet allocation */ + optimize_submit_rx_request(&dhd_bus->pub, 1, NULL, NULL); +#else + /* Copy mode - allocate own buffer to be reused */ + void *buf = MALLOCZ(dhd_bus->pub.osh, 4000); /* usbos_info->rxbuf_len */ + optimize_submit_rx_request(&dhd_bus->pub, 1, NULL, buf); + /* ME: Need to check result and set err = DBUS_ERR_RXDROP */ +#endif /* BCM_RPC_NOCOPY || BCM_RPC_RXNOCOPY */ + atomic_inc(&dhd_bus->rx_outstanding); + } +#else /* EHCI_FASTPATH_RX */ dbus_irb_rx_t *rxirb; struct exec_parms args; @@ -456,6 +508,7 @@ dbus_rxirbs_fill(dhd_bus_t *dhd_bus) } } } +#endif /* EHCI_FASTPATH_RX */ return err; } /* dbus_rxirbs_fill */ @@ -501,9 +554,11 @@ dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info) { dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; int err = DBUS_OK; +#ifndef EHCI_FASTPATH_TX dbus_irb_tx_t *txirb = NULL; int txirb_pending; struct exec_parms args; +#endif /* EHCI_FASTPATH_TX */ if (dhd_bus == NULL) return DBUS_ERR; @@ -512,6 +567,43 @@ dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info) if (dhd_bus->pub.busstate == DBUS_STATE_UP || dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { +#ifdef EHCI_FASTPATH_TX + struct ehci_qtd *qtd; + int token = EHCI_QTD_SET_CERR(3); + int len; + + ASSERT(buf == NULL); /* Not handled */ + ASSERT(pkt != NULL); + + qtd = optimize_ehci_qtd_alloc(GFP_KERNEL); + + if (qtd == NULL) + return DBUS_ERR; + + len = PKTLEN(pub->osh, pkt); + + len = ROUNDUP(len, sizeof(uint32)); + +#ifdef BCMDBG + /* The packet length is already padded to not to be multiple of 512 bytes + * in bcm_rpc_tp_buf_send_internal(), so it should not be 512*N bytes here. + */ + if (len % EHCI_BULK_PACKET_SIZE == 0) { + DBUSERR(("%s: len = %d (multiple of 512 bytes)\n", __FUNCTION__, len)); + return DBUS_ERR_TXDROP; + } +#endif /* BCMDBG */ + + optimize_qtd_fill_with_rpc(pub, 0, qtd, pkt, token, len); + err = optimize_submit_async(qtd, 0); + + if (err) { + optimize_ehci_qtd_free(qtd); + err = DBUS_ERR_TXDROP; + } + + /* ME: Add timeout? */ +#else args.qdeq.q = dhd_bus->tx_q; if (dhd_bus->drvintf) txirb = EXEC_TXLOCK(dhd_bus, q_deq_exec, &args); @@ -549,11 +641,15 @@ dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info) } else { dbus_tx_timer_start(dhd_bus, DBUS_TX_TIMEOUT_INTERVAL); txirb_pending = dhd_bus->pub.ntxq - dhd_bus->tx_q->cnt; +#ifdef BCMDBG + dhd_bus->txpend_q_hist[txirb_pending]++; +#endif /* BCMDBG */ if (txirb_pending > (dhd_bus->tx_low_watermark * 3)) { dbus_flowctrl_tx(dhd_bus, TRUE); } } } +#endif /* EHCI_FASTPATH_TX */ } else { err = DBUS_ERR_TXFAIL; DBUSTRACE(("%s: bus down, send_irb failed\n", __FUNCTION__)); @@ -562,7 +658,7 @@ dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info) return err; } /* dbus_send_irb */ -#if defined(BCM_REQUEST_FW) +#if (defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW)) /** * Before downloading a firmware image into the dongle, the validity of the image must be checked. @@ -603,7 +699,7 @@ check_file(osl_t *osh, unsigned char *headers) #ifdef EXTERNAL_FW_PATH static int -dbus_get_fw_nvram(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path) +dbus_get_fw_nvram(dhd_bus_t *dhd_bus) { int bcmerror = -1, i; uint len, total_len; @@ -618,6 +714,8 @@ dbus_get_fw_nvram(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path) struct trx_header *hdr; uint32 img_offset = 0; int offset = 0; + char *pfw_path = dhd_bus->fw_path; + char *pnv_path = dhd_bus->nv_path; /* For Get nvram */ file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); @@ -750,11 +848,11 @@ err: * the dongle */ static int -dbus_do_download(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path) +dbus_do_download(dhd_bus_t *dhd_bus) { int err = DBUS_OK; - err = dbus_get_fw_nvram(dhd_bus, pfw_path, pnv_path); + err = dbus_get_fw_nvram(dhd_bus); if (err) { DBUSERR(("dbus_do_download: fail to get nvram %d\n", err)); return err; @@ -798,12 +896,6 @@ dbus_jumbo_nvram(dhd_bus_t *dhd_bus) uint16 boardrev = 0xFFFF; uint16 boardtype = 0xFFFF; - /* read the otp for boardrev & boardtype - * if boardtype/rev are present in otp - * select nvram data for that boardtype/rev - */ - dbus_otp(dhd_bus, &boardtype, &boardrev); - ret = dbus_select_nvram(dhd_bus, dhd_bus->extdl.vars, dhd_bus->extdl.varslen, boardtype, boardrev, &nvram, &nvram_len); @@ -862,7 +954,17 @@ dbus_get_nvram(dhd_bus_t *dhd_bus) nvram_words_pad = 4 - dhd_bus->nvram_len % 4; len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad; - dhd_bus->image = MALLOC(dhd_bus->pub.osh, len); +#ifdef USBAP + /* Allocate virtual memory otherwise it might fail on embedded systems */ + dhd_bus->image = VMALLOC(dhd_bus->pub.osh, len); +#else +#if defined(CONFIG_DHD_USE_STATIC_BUF) + dhd_bus->image = (uint8*)DHD_OS_PREALLOC(dhd_bus->dhd, + DHD_PREALLOC_MEMDUMP_RAM, len); +#else + dhd_bus->image = MALLOCZ(dhd_bus->pub.osh, len); +#endif /* CONFIG_DHD_USE_STATIC_BUF */ +#endif /* USBAP */ dhd_bus->image_len = len; if (dhd_bus->image == NULL) { DBUSERR(("%s: malloc failed!\n", __FUNCTION__)); @@ -894,6 +996,7 @@ dbus_get_nvram(dhd_bus_t *dhd_bus) hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] + hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX]); + /* Not needed */ img_offset += hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] + hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX]; } @@ -938,13 +1041,28 @@ dbus_do_download(dhd_bus_t *dhd_bus) int temp_len; #endif -#if defined(BCM_REQUEST_FW) +#if defined(BCM_DNGL_EMBEDIMAGE) + if (dhd_bus->extdl.fw && (dhd_bus->extdl.fwlen > 0)) { + dhd_bus->fw = (uint8 *)dhd_bus->extdl.fw; + dhd_bus->fwlen = dhd_bus->extdl.fwlen; + DBUSERR(("dbus_do_download: using override firmmware %d bytes\n", + dhd_bus->fwlen)); + } else + dbus_bus_fw_get(dhd_bus->bus_info, &dhd_bus->fw, &dhd_bus->fwlen, + &decomp_override); + + if (!dhd_bus->fw) { + DBUSERR(("dbus_do_download: devid 0x%x / %d not supported\n", + dhd_bus->pub.attrib.devid, dhd_bus->pub.attrib.devid)); + return DBUS_ERR; + } +#elif defined(BCM_REQUEST_FW) dhd_bus->firmware = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid, dhd_bus->pub.attrib.chiprev, &dhd_bus->fw, &dhd_bus->fwlen, - DBUS_FIRMWARE, 0, 0); + DBUS_FIRMWARE, 0, 0, dhd_bus->fw_path); if (!dhd_bus->firmware) return DBUS_ERR; -#endif +#endif /* defined(BCM_DNGL_EMBEDIMAGE) */ dhd_bus->image = dhd_bus->fw; dhd_bus->image_len = (uint32)dhd_bus->fwlen; @@ -960,16 +1078,14 @@ dbus_do_download(dhd_bus_t *dhd_bus) #endif #if defined(BCM_REQUEST_FW) - /* check if firmware is appended with nvram file */ - err = dbus_otp(dhd_bus, &boardtype, &boardrev); /* check if nvram is provided as separte file */ nonfwnvram = NULL; nonfwnvramlen = 0; dhd_bus->nvfile = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid, dhd_bus->pub.attrib.chiprev, (void *)&temp_nvram, &temp_len, - DBUS_NVFILE, boardtype, boardrev); + DBUS_NVFILE, boardtype, boardrev, dhd_bus->nv_path); if (dhd_bus->nvfile) { - int8 *tmp = MALLOC(dhd_bus->pub.osh, temp_len); + int8 *tmp = MALLOCZ(dhd_bus->pub.osh, temp_len); if (tmp) { bcopy(temp_nvram, tmp, temp_len); nonfwnvram = tmp; @@ -987,7 +1103,6 @@ dbus_do_download(dhd_bus_t *dhd_bus) return err; } - if (dhd_bus->drvintf->dlstart && dhd_bus->drvintf->dlrun) { err = dhd_bus->drvintf->dlstart(dhd_bus->bus_info, dhd_bus->image, dhd_bus->image_len); @@ -998,7 +1113,15 @@ dbus_do_download(dhd_bus_t *dhd_bus) err = DBUS_ERR; if (dhd_bus->nvram) { +#ifdef USBAP + VMFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len); +#else +#if defined(CONFIG_DHD_USE_STATIC_BUF) + DHD_OS_PREFREE(dhd_bus->dhd, dhd_bus->image, dhd_bus->image_len); +#else MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len); +#endif /* CONFIG_DHD_USE_STATIC_BUF */ +#endif /* USBAP */ dhd_bus->image = dhd_bus->fw; dhd_bus->image_len = (uint32)dhd_bus->fwlen; } @@ -1030,17 +1153,7 @@ fail: return err; } /* dbus_do_download */ #endif /* EXTERNAL_FW_PATH */ -#endif - -/** required for DBUS deregistration */ -static void -dbus_disconnect(void *handle) -{ - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (disconnect_cb) - disconnect_cb(disc_arg); -} +#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */ /** * This function is called when the sent irb times out without a tx response status. @@ -1057,13 +1170,17 @@ dbus_if_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb) DBUSTRACE(("%s\n", __FUNCTION__)); + /* Timeout in DBUS is fatal until we have a reproducible case. If the time out really + * happen, then retry needs to be fixed to maintain the order of IRPs going out + * (cancel in reverse order) + */ return; } /* dbus_if_send_irb_timeout */ /** * When lower DBUS level signals that a send IRB completed, either successful or not, the higher - * level (e.g. dhd_linux.c) has to be notified, and transmit flow control has to be evaluated. + * level (eg dhd_linux.c) has to be notified, and transmit flow control has to be evaluated. */ static void dbus_if_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status) @@ -1168,6 +1285,9 @@ dbus_if_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status) } rxirb_pending = dhd_bus->pub.nrxq - dhd_bus->rx_q->cnt - 1; +#ifdef BCMDBG + dhd_bus->rxpend_q_hist[rxirb_pending]++; +#endif /* BCMDBG */ if ((rxirb_pending <= dhd_bus->rx_low_watermark) && !dhd_bus->rxoff) { DBUSTRACE(("Low watermark so submit more %d <= %d \n", @@ -1216,7 +1336,7 @@ dbus_if_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status) } /* dbus_if_recv_irb_complete */ /** - * Accumulate errors signaled by lower DBUS levels and signal them to higher (e.g. dhd_linux.c) + * Accumulate errors signaled by lower DBUS levels and signal them to higher (eg dhd_linux.c) * level. */ static void @@ -1254,7 +1374,7 @@ dbus_if_errhandler(void *handle, int err) } /** - * When lower DBUS level signals control IRB completed, higher level (e.g. dhd_linux.c) has to be + * When lower DBUS level signals control IRB completed, higher level (eg dhd_linux.c) has to be * notified. */ static void @@ -1278,7 +1398,7 @@ dbus_if_ctl_complete(void *handle, int type, int status) /** * Rx related functionality (flow control, posting of free IRBs to rx queue) is dependent upon the * bus state. When lower DBUS level signals a change in the interface state, take appropriate action - * and forward the signaling to the higher (e.g. dhd_linux.c) level. + * and forward the signaling to the higher (eg dhd_linux.c) level. */ static void dbus_if_state_change(void *handle, int state) @@ -1373,25 +1493,20 @@ dbus_if_getirb(void *cbarg, bool send) return irb; } -/** - * Called as part of DBUS bus registration. Calls back into higher level (e.g. dhd_linux.c) probe - * function. +/* Register/Unregister functions are called by the main DHD entry + * point (e.g. module insertion) to link with the bus driver, in + * order to look for or await the device. */ -static void * -dbus_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no, - uint16 slot, uint32 hdrlen) -{ - DBUSTRACE(("%s\n", __FUNCTION__)); - if (probe_cb) { - disc_arg = probe_cb(probe_arg, desc, bustype, bus_no, slot, hdrlen); - return disc_arg; - } - return (void *)DBUS_ERR; -} +static dbus_driver_t dhd_dbus = { + dhd_dbus_probe_cb, + dhd_dbus_disconnect_cb, + dbus_suspend, + dbus_resume +}; /** - * As part of initialization, higher level (e.g. dhd_linux.c) requests DBUS to prepare for + * As part of initialization, higher level (eg dhd_linux.c) requests DBUS to prepare for * action. */ int @@ -1401,12 +1516,7 @@ dhd_bus_register(void) DBUSTRACE(("%s: Enter\n", __FUNCTION__)); - probe_cb = dhd_dbus_probe_cb; - disconnect_cb = dhd_dbus_disconnect_cb; - probe_arg = NULL; - - err = dbus_bus_register(0xa5c, 0x48f, dbus_probe, /* call lower DBUS level register function */ - dbus_disconnect, NULL, &g_busintf, NULL, NULL); + err = dbus_bus_register(&dhd_dbus, &g_busintf); /* Device not detected */ if (err == DBUS_ERR_NODEVICE) @@ -1416,11 +1526,10 @@ dhd_bus_register(void) } dhd_pub_t *g_pub = NULL; +bool net_attached = FALSE; void dhd_bus_unregister(void) { - int ret; - DBUSTRACE(("%s\n", __FUNCTION__)); DHD_MUTEX_LOCK(); @@ -1430,11 +1539,8 @@ dhd_bus_unregister(void) dhd_dbus_disconnect_cb(g_pub->bus); } } - probe_cb = NULL; DHD_MUTEX_UNLOCK(); - ret = dbus_bus_deregister(); - disconnect_cb = NULL; - probe_arg = NULL; + dbus_bus_deregister(); } /** As part of initialization, data structures have to be allocated and initialized */ @@ -1453,14 +1559,12 @@ dbus_attach(osl_t *osh, int rxsize, int nrxq, int ntxq, dhd_pub_t *pub, if ((nrxq <= 0) || (ntxq <= 0)) return NULL; - dhd_bus = MALLOC(osh, sizeof(dhd_bus_t)); + dhd_bus = MALLOCZ(osh, sizeof(dhd_bus_t)); if (dhd_bus == NULL) { DBUSERR(("%s: malloc failed %zu\n", __FUNCTION__, sizeof(dhd_bus_t))); return NULL; } - bzero(dhd_bus, sizeof(dhd_bus_t)); - /* BUS-specific driver interface (at a lower DBUS level) */ dhd_bus->drvintf = g_busintf; dhd_bus->cbarg = pub; @@ -1470,31 +1574,42 @@ dbus_attach(osl_t *osh, int rxsize, int nrxq, int ntxq, dhd_pub_t *pub, dhd_bus->pub.osh = osh; dhd_bus->pub.rxsize = rxsize; +#ifdef EHCI_FASTPATH_RX + atomic_set(&dhd_bus->rx_outstanding, 0); +#endif + dhd_bus->pub.nrxq = nrxq; dhd_bus->rx_low_watermark = nrxq / 2; /* keep enough posted rx urbs */ dhd_bus->pub.ntxq = ntxq; dhd_bus->tx_low_watermark = ntxq / 4; /* flow control when too many tx urbs posted */ - dhd_bus->tx_q = MALLOC(osh, sizeof(dbus_irbq_t)); + dhd_bus->tx_q = MALLOCZ(osh, sizeof(dbus_irbq_t)); if (dhd_bus->tx_q == NULL) goto error; else { - bzero(dhd_bus->tx_q, sizeof(dbus_irbq_t)); err = dbus_irbq_init(dhd_bus, dhd_bus->tx_q, ntxq, sizeof(dbus_irb_tx_t)); if (err != DBUS_OK) goto error; } - dhd_bus->rx_q = MALLOC(osh, sizeof(dbus_irbq_t)); + dhd_bus->rx_q = MALLOCZ(osh, sizeof(dbus_irbq_t)); if (dhd_bus->rx_q == NULL) goto error; else { - bzero(dhd_bus->rx_q, sizeof(dbus_irbq_t)); err = dbus_irbq_init(dhd_bus, dhd_bus->rx_q, nrxq, sizeof(dbus_irb_rx_t)); if (err != DBUS_OK) goto error; } +#ifdef BCMDBG + dhd_bus->txpend_q_hist = MALLOCZ(osh, dhd_bus->pub.ntxq * sizeof(int)); + if (dhd_bus->txpend_q_hist == NULL) + goto error; + + dhd_bus->rxpend_q_hist = MALLOCZ(osh, dhd_bus->pub.nrxq * sizeof(int)); + if (dhd_bus->rxpend_q_hist == NULL) + goto error; +#endif /* BCMDBG */ dhd_bus->bus_info = (void *)g_busintf->attach(&dhd_bus->pub, dhd_bus, &dbus_intf_cbs); @@ -1503,10 +1618,10 @@ dbus_attach(osl_t *osh, int rxsize, int nrxq, int ntxq, dhd_pub_t *pub, dbus_tx_timer_init(dhd_bus); -#if defined(BCM_REQUEST_FW) +#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) /* Need to copy external image for re-download */ if (extdl && extdl->fw && (extdl->fwlen > 0)) { - dhd_bus->extdl.fw = MALLOC(osh, extdl->fwlen); + dhd_bus->extdl.fw = MALLOCZ(osh, extdl->fwlen); if (dhd_bus->extdl.fw) { bcopy(extdl->fw, dhd_bus->extdl.fw, extdl->fwlen); dhd_bus->extdl.fwlen = extdl->fwlen; @@ -1514,13 +1629,13 @@ dbus_attach(osl_t *osh, int rxsize, int nrxq, int ntxq, dhd_pub_t *pub, } if (extdl && extdl->vars && (extdl->varslen > 0)) { - dhd_bus->extdl.vars = MALLOC(osh, extdl->varslen); + dhd_bus->extdl.vars = MALLOCZ(osh, extdl->varslen); if (dhd_bus->extdl.vars) { bcopy(extdl->vars, dhd_bus->extdl.vars, extdl->varslen); dhd_bus->extdl.varslen = extdl->varslen; } } -#endif +#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */ return (dhd_bus_t *)dhd_bus; @@ -1530,7 +1645,7 @@ error: return NULL; } /* dbus_attach */ -void +static void dbus_detach(dhd_bus_t *pub) { dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; @@ -1560,6 +1675,12 @@ dbus_detach(dhd_bus_t *pub) dhd_bus->rx_q = NULL; } +#ifdef BCMDBG + if (dhd_bus->txpend_q_hist) + MFREE(osh, dhd_bus->txpend_q_hist, dhd_bus->pub.ntxq * sizeof(int)); + if (dhd_bus->rxpend_q_hist) + MFREE(osh, dhd_bus->rxpend_q_hist, dhd_bus->pub.nrxq * sizeof(int)); +#endif /* BCMDBG */ if (dhd_bus->extdl.fw && (dhd_bus->extdl.fwlen > 0)) { MFREE(osh, dhd_bus->extdl.fw, dhd_bus->extdl.fwlen); @@ -1599,8 +1720,8 @@ int dbus_dlneeded(dhd_bus_t *pub) return dlneeded; } -#if defined(BCM_REQUEST_FW) -int dbus_download_firmware(dhd_bus_t *pub, char *pfw_path, char *pnv_path) +#if (defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW)) +int dbus_download_firmware(dhd_bus_t *pub) { dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; int err = DBUS_OK; @@ -1613,11 +1734,7 @@ int dbus_download_firmware(dhd_bus_t *pub, char *pfw_path, char *pnv_path) DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate)); dhd_bus->pub.busstate = DBUS_STATE_DL_PENDING; -#ifdef EXTERNAL_FW_PATH - err = dbus_do_download(dhd_bus, pfw_path, pnv_path); -#else err = dbus_do_download(dhd_bus); -#endif /* EXTERNAL_FW_PATH */ if (err == DBUS_OK) { dhd_bus->pub.busstate = DBUS_STATE_DL_DONE; } else { @@ -1626,7 +1743,7 @@ int dbus_download_firmware(dhd_bus_t *pub, char *pfw_path, char *pnv_path) return err; } -#endif +#endif /* BCM_DNGL_EMBEDIMAGE || BCM_REQUEST_FW */ /** * higher layer requests us to 'up' the interface to the dongle. Prerequisite is that firmware (not @@ -1718,24 +1835,19 @@ dbus_stop(struct dhd_bus *pub) return DBUS_ERR; } -int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf) -{ - return dbus_send_pkt(dbus, pktbuf, pktbuf /* pktinfo */); -} - int dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info) { return dbus_send_irb(pub, buf, len, NULL, info); } -int +static int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info) { return dbus_send_irb(pub, NULL, 0, pkt, info); } -int +static int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len) { dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; @@ -1756,7 +1868,7 @@ dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len) return DBUS_ERR; } -int +static int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len) { dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; @@ -1768,6 +1880,8 @@ dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len) dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { if (dhd_bus->drvintf && dhd_bus->drvintf->recv_ctl) return dhd_bus->drvintf->recv_ctl(dhd_bus->bus_info, buf, len); + } else { + DBUSERR(("%s: bustate=%d\n", __FUNCTION__, dhd_bus->pub.busstate)); } return DBUS_ERR; @@ -1777,6 +1891,10 @@ dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len) int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx) { +#ifdef EHCI_FASTPATH_RX + /* 2nd bulk in not supported for EHCI_FASTPATH_RX */ + ASSERT(0); +#else dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; dbus_irb_rx_t *rxirb; @@ -1802,12 +1920,14 @@ dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx) } } } +#endif /* EHCI_FASTPATH_RX */ - return DBUS_ERR; + return DBUS_ERR; /* ME DVV: This does not seem right :-) */ } +#ifdef INTR_EP_ENABLE /** only called by dhd_cdc.c (Dec 2012) */ -int +static int dbus_poll_intr(dbus_pub_t *pub) { dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; @@ -1825,6 +1945,7 @@ dbus_poll_intr(dbus_pub_t *pub) } return status; } +#endif /* INTR_EP_ENABLE */ /** called by nobody (Dec 2012) */ void * @@ -1962,6 +2083,23 @@ dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload) return DBUS_OK; } +#if defined(BCM_DNGL_EMBEDIMAGE) + if (dhd_bus->drvintf->device_exists && + dhd_bus->drvintf->device_exists(dhd_bus->bus_info)) { + if (dhd_bus->drvintf->dlneeded) { + if (dhd_bus->drvintf->dlneeded(dhd_bus->bus_info)) { + err = dbus_do_download(dhd_bus); + if (err == DBUS_OK) { + fwdl = TRUE; + } + if (dhd_bus->pub.busstate == DBUS_STATE_DL_DONE) + dbus_up(&dhd_bus->pub); + } + } + } else { + return DBUS_ERR; + } +#endif /* BCM_DNGL_EMBEDIMAGE */ if (dhd_bus->drvintf->pnp) { @@ -1976,6 +2114,11 @@ dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload) } } +#if defined(BCM_DNGL_EMBEDIMAGE) + if (fwdl == TRUE) { + dbus_if_state_change(dhd_bus, DBUS_STATE_PNP_FWDL); + } +#endif /* BCM_DNGL_EMBEDIMAGE */ if (fw_reload) *fw_reload = fwdl; @@ -2045,6 +2188,42 @@ dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, return err; } +#ifdef BCMDBG +void +dbus_hist_dump(dbus_pub_t *pub, struct bcmstrbuf *b) +{ + int i = 0, j = 0; + dbus_info_t *dbus_info = (dbus_info_t *) pub; + + bcm_bprintf(b, "\nDBUS histogram\n"); + bcm_bprintf(b, "txq\n"); + for (i = 0; i < dbus_info->pub.ntxq; i++) { + if (dbus_info->txpend_q_hist[i]) { + bcm_bprintf(b, "%d: %d ", i, dbus_info->txpend_q_hist[i]); + j++; + if (j % 10 == 0) { + bcm_bprintf(b, "\n"); + } + } + } + + j = 0; + bcm_bprintf(b, "\nrxq\n"); + for (i = 0; i < dbus_info->pub.nrxq; i++) { + if (dbus_info->rxpend_q_hist[i]) { + bcm_bprintf(b, "%d: %d ", i, dbus_info->rxpend_q_hist[i]); + j++; + if (j % 10 == 0) { + bcm_bprintf(b, "\n"); + } + } + } + bcm_bprintf(b, "\n"); + + if (dbus_info->drvintf && dbus_info->drvintf->dump) + dbus_info->drvintf->dump(dbus_info->bus_info, b); +} +#endif /* BCMDBG */ void * dhd_dbus_txq(const dbus_pub_t *pub) @@ -2064,133 +2243,7 @@ dbus_get_devinfo(dbus_pub_t *pub) return pub->dev_info; } -#if defined(BCM_REQUEST_FW) && !defined(EXTERNAL_FW_PATH) -static int -dbus_otp(dhd_bus_t *dhd_bus, uint16 *boardtype, uint16 *boardrev) -{ - uint32 value = 0; - uint8 *cis; - uint16 *otpinfo; - uint32 i; - bool standard_cis = TRUE; - uint8 tup, tlen; - bool btype_present = FALSE; - bool brev_present = FALSE; - int ret; - int devid; - uint16 btype = 0; - uint16 brev = 0; - uint32 otp_size = 0, otp_addr = 0, otp_sw_rgn = 0; - - if (dhd_bus == NULL || dhd_bus->drvintf == NULL || - dhd_bus->drvintf->readreg == NULL) - return DBUS_ERR; - - devid = dhd_bus->pub.attrib.devid; - - if ((devid == BCM43234_CHIP_ID) || (devid == BCM43235_CHIP_ID) || - (devid == BCM43236_CHIP_ID)) { - - otp_size = BCM_OTP_SIZE_43236; - otp_sw_rgn = BCM_OTP_SW_RGN_43236; - otp_addr = BCM_OTP_ADDR_43236; - - } else { - return DBUS_ERR_NVRAM; - } - - cis = MALLOC(dhd_bus->pub.osh, otp_size * 2); - if (cis == NULL) - return DBUS_ERR; - - otpinfo = (uint16 *) cis; - - for (i = 0; i < otp_size; i++) { - - ret = dhd_bus->drvintf->readreg(dhd_bus->bus_info, - otp_addr + ((otp_sw_rgn + i) << 1), 2, &value); - - if (ret != DBUS_OK) { - MFREE(dhd_bus->pub.osh, cis, otp_size * 2); - return ret; - } - otpinfo[i] = (uint16) value; - } - - for (i = 0; i < (otp_size << 1); ) { - - if (standard_cis) { - tup = cis[i++]; - if (tup == CISTPL_NULL || tup == CISTPL_END) - tlen = 0; - else - tlen = cis[i++]; - } else { - if (cis[i] == CISTPL_NULL || cis[i] == CISTPL_END) { - tlen = 0; - tup = cis[i]; - } else { - tlen = cis[i]; - tup = CISTPL_BRCM_HNBU; - } - ++i; - } - - if (tup == CISTPL_END || (i + tlen) >= (otp_size << 1)) { - break; - } - - switch (tup) { - - case CISTPL_BRCM_HNBU: - - switch (cis[i]) { - - case HNBU_BOARDTYPE: - - btype = (uint16) ((cis[i + 2] << 8) + cis[i + 1]); - btype_present = TRUE; - DBUSTRACE(("%s: HNBU_BOARDTYPE = 0x%2x\n", __FUNCTION__, - (uint32)btype)); - break; - - case HNBU_BOARDREV: - - if (tlen == 2) - brev = (uint16) cis[i + 1]; - else - brev = (uint16) ((cis[i + 2] << 8) + cis[i + 1]); - brev_present = TRUE; - DBUSTRACE(("%s: HNBU_BOARDREV = 0x%2x\n", __FUNCTION__, - (uint32)*boardrev)); - break; - - case HNBU_HNBUCIS: - DBUSTRACE(("%s: HNBU_HNBUCIS\n", __FUNCTION__)); - tlen++; - standard_cis = FALSE; - break; - } - break; - } - - i += tlen; - } - - MFREE(dhd_bus->pub.osh, cis, otp_size * 2); - - if (btype_present == TRUE && brev_present == TRUE) { - *boardtype = btype; - *boardrev = brev; - DBUSERR(("otp boardtype = 0x%2x boardrev = 0x%2x\n", - *boardtype, *boardrev)); - - return DBUS_OK; - } - else - return DBUS_ERR; -} /* dbus_otp */ - +#if (defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW)) && !defined(EXTERNAL_FW_PATH) static int dbus_select_nvram(dhd_bus_t *dhd_bus, int8 *jumbonvram, int jumbolen, uint16 boardtype, uint16 boardrev, int8 **nvram, int *nvram_len) @@ -2328,6 +2381,245 @@ uint16 boardtype, uint16 boardrev, int8 **nvram, int *nvram_len) #endif +#if defined(BCM_DNGL_EMBEDIMAGE) + +/* store the global osh handle */ +static osl_t *osl_handle = NULL; + +/** this function is a combination of trx.c and bcmdl.c plus dbus adaptation */ +static int +dbus_zlib_decomp(dhd_bus_t *dhd_bus) +{ + + int method, flags, len, status; + unsigned int uncmp_len, uncmp_crc, dec_crc, crc_init; + struct trx_header *trx, *newtrx; + unsigned char *file = NULL; + unsigned char gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + z_stream d_stream; + unsigned char unused; + int actual_len = -1; + unsigned char *headers; + unsigned int trxhdrsize, nvramsize, decomp_memsize, i; + + (void)actual_len; + (void)unused; + (void)crc_init; + + osl_handle = dhd_bus->pub.osh; + dhd_bus->orig_fw = NULL; + + headers = dhd_bus->fw; + /* Extract trx header */ + trx = (struct trx_header *)headers; + trxhdrsize = sizeof(struct trx_header); + + if (ltoh32(trx->magic) != TRX_MAGIC) { + DBUSERR(("%s: Error: trx bad hdr %x\n", __FUNCTION__, + ltoh32(trx->magic))); + return -1; + } + + headers += sizeof(struct trx_header); + + if (ltoh32(trx->flag_version) & TRX_UNCOMP_IMAGE) { + actual_len = ltoh32(trx->offsets[TRX_OFFSETS_DLFWLEN_IDX]) + + sizeof(struct trx_header); + DBUSERR(("%s: not a compressed image\n", __FUNCTION__)); + return 0; + } else { + /* Extract the gzip header info */ + if ((*headers++ != gz_magic[0]) || (*headers++ != gz_magic[1])) { + DBUSERR(("%s: Error: gzip bad hdr\n", __FUNCTION__)); + return -1; + } + + method = (int) *headers++; + flags = (int) *headers++; + + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + DBUSERR(("%s: Error: gzip bad hdr not a Z_DEFLATED file\n", __FUNCTION__)); + return -1; + } + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) + unused = *headers++; + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uint32) *headers++; + len += ((uint32)*headers++)<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0) unused = *headers++; + } + + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while (*headers++ && (*headers != 0)); + } + + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while (*headers++ && (*headers != 0)); + } + + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) unused = *headers++; + } + + headers++; /* I need this, why ? */ + + /* create space for the uncompressed file */ + /* the space is for trx header, uncompressed image and nvram file */ + /* with typical compression of 0.6, space double of firmware should be ok */ + + decomp_memsize = dhd_bus->fwlen * 2; + dhd_bus->decomp_memsize = decomp_memsize; + if (!(file = MALLOCZ(osl_handle, decomp_memsize))) { + DBUSERR(("%s: check_file : failed malloc\n", __FUNCTION__)); + goto err; + } + + /* Initialise the decompression struct */ + d_stream.next_in = NULL; + d_stream.avail_in = 0; + d_stream.next_out = NULL; + d_stream.avail_out = decomp_memsize - trxhdrsize; + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + if (inflateInit2(&d_stream, -15) != Z_OK) { + DBUSERR(("%s: Err: inflateInit2\n", __FUNCTION__)); + goto err; + } + + /* Inflate the code */ + d_stream.next_in = headers; + d_stream.avail_in = ltoh32(trx->len); + d_stream.next_out = (unsigned char*)(file + trxhdrsize); + + status = inflate(&d_stream, Z_SYNC_FLUSH); + + if (status != Z_STREAM_END) { + DBUSERR(("%s: Error: decompression failed\n", __FUNCTION__)); + goto err; + } + + uncmp_crc = *d_stream.next_in++; + uncmp_crc |= *d_stream.next_in++<<8; + uncmp_crc |= *d_stream.next_in++<<16; + uncmp_crc |= *d_stream.next_in++<<24; + + uncmp_len = *d_stream.next_in++; + uncmp_len |= *d_stream.next_in++<<8; + uncmp_len |= *d_stream.next_in++<<16; + uncmp_len |= *d_stream.next_in++<<24; + + actual_len = (int) (d_stream.next_in - (unsigned char *)trx); + + inflateEnd(&d_stream); + + /* Do a CRC32 on the uncompressed data */ + crc_init = crc32(0L, Z_NULL, 0); + dec_crc = crc32(crc_init, file + trxhdrsize, uncmp_len); + + if (dec_crc != uncmp_crc) { + DBUSERR(("%s: decompression: bad crc check \n", __FUNCTION__)); + goto err; + } + else { + DBUSTRACE(("%s: decompression: good crc check \n", __FUNCTION__)); + } + + /* rebuild the new trx header and calculate crc */ + newtrx = (struct trx_header *)file; + newtrx->magic = trx->magic; + /* add the uncompressed image flag */ + newtrx->flag_version = trx->flag_version; + newtrx->flag_version |= htol32(TRX_UNCOMP_IMAGE); + newtrx->offsets[TRX_OFFSETS_DLFWLEN_IDX] = htol32(uncmp_len); + newtrx->offsets[TRX_OFFSETS_JUMPTO_IDX] = trx->offsets[TRX_OFFSETS_JUMPTO_IDX]; + newtrx->offsets[TRX_OFFSETS_NVM_LEN_IDX] = trx->offsets[TRX_OFFSETS_NVM_LEN_IDX]; + + nvramsize = ltoh32(trx->offsets[TRX_OFFSETS_NVM_LEN_IDX]); + + /* the original firmware has nvram file appended */ + /* copy the nvram file to uncompressed firmware */ + + if (nvramsize) { + if (nvramsize + uncmp_len > decomp_memsize) { + DBUSERR(("%s: nvram cannot be accomodated\n", __FUNCTION__)); + goto err; + } + bcopy(d_stream.next_in, &file[uncmp_len], nvramsize); + uncmp_len += nvramsize; + } + + /* add trx header size to uncmp_len */ + uncmp_len += trxhdrsize; + /* PR14373 WAR: Pad to multiple of 4096 bytes */ + uncmp_len = ROUNDUP(uncmp_len, 4096); + newtrx->len = htol32(uncmp_len); + + /* Calculate CRC over header */ + newtrx->crc32 = hndcrc32((uint8 *)&newtrx->flag_version, + sizeof(struct trx_header) - OFFSETOF(struct trx_header, flag_version), + CRC32_INIT_VALUE); + + /* Calculate CRC over data */ + for (i = trxhdrsize; i < (uncmp_len); ++i) + newtrx->crc32 = hndcrc32((uint8 *)&file[i], 1, newtrx->crc32); + newtrx->crc32 = htol32(newtrx->crc32); + + dhd_bus->orig_fw = dhd_bus->fw; + dhd_bus->origfw_len = dhd_bus->fwlen; + dhd_bus->image = dhd_bus->fw = file; + dhd_bus->image_len = dhd_bus->fwlen = uncmp_len; + + return 0; + +err: + if (file) + free(file); + return -1; +} /* dbus_zlib_decomp */ + +void * +dbus_zlib_calloc(int num, int size) +{ + uint *ptr; + uint totalsize; + + if (osl_handle == NULL) + return NULL; + + totalsize = (num * (size + 1)); + + ptr = MALLOCZ(osl_handle, totalsize); + + if (ptr == NULL) + return NULL; + + /* store the size in the first integer space */ + + ptr[0] = totalsize; + + return ((void *) &ptr[1]); +} + +void +dbus_zlib_free(void *ptr) +{ + uint totalsize; + uchar *memptr = (uchar *)ptr; + + if (ptr && osl_handle) { + memptr -= sizeof(uint); + totalsize = *(uint *) memptr; + MFREE(osl_handle, memptr, totalsize); + } +} + +#endif /* #if defined(BCM_DNGL_EMBEDIMAGE) */ + #define DBUS_NRXQ 50 #define DBUS_NTXQ 100 @@ -2461,31 +2753,49 @@ dhd_dbus_ctl_complete(void *handle, int type, int status) dhd->tx_ctlerrs++; } - dhd_prot_ctl_complete(dhd); + dhd->bus->ctl_completed = TRUE; + dhd_os_ioctl_resp_wake(dhd); } static void dhd_dbus_state_change(void *handle, int state) { dhd_pub_t *dhd = (dhd_pub_t *)handle; + unsigned long flags; + wifi_adapter_info_t *adapter; + int wowl_dngldown = 0; if (dhd == NULL) { DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); return; } + adapter = (wifi_adapter_info_t *)dhd->adapter; +#ifdef WL_EXT_WOWL + wowl_dngldown = dhd_conf_wowl_dngldown(dhd); +#endif + if ((dhd->busstate == DHD_BUS_SUSPEND && state == DBUS_STATE_DOWN) || + (dhd->hostsleep && wowl_dngldown)) { + DBUSERR(("%s: switch state %d to %d\n", __FUNCTION__, state, DBUS_STATE_SLEEP)); + state = DBUS_STATE_SLEEP; + } switch (state) { - case DBUS_STATE_DL_NEEDED: DBUSERR(("%s: firmware request cannot be handled\n", __FUNCTION__)); break; case DBUS_STATE_DOWN: + DHD_LINUX_GENERAL_LOCK(dhd, flags); + dhd_txflowcontrol(dhd, ALL_INTERFACES, ON); DBUSTRACE(("%s: DBUS is down\n", __FUNCTION__)); dhd->busstate = DHD_BUS_DOWN; + DHD_LINUX_GENERAL_UNLOCK(dhd, flags); break; case DBUS_STATE_UP: DBUSTRACE(("%s: DBUS is up\n", __FUNCTION__)); + DHD_LINUX_GENERAL_LOCK(dhd, flags); + dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); dhd->busstate = DHD_BUS_DATA; + DHD_LINUX_GENERAL_UNLOCK(dhd, flags); break; default: break; @@ -2577,14 +2887,7 @@ dhd_bus_chiprev(struct dhd_bus *bus) struct device * dhd_bus_to_dev(struct dhd_bus *bus) { - struct usb_device *pdev; - - pdev = (struct usb_device *)bus->pub.dev_info; - - if (pdev) - return &pdev->dev; - else - return NULL; + return dbus_get_dev(); } void @@ -2606,7 +2909,95 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pktbuf) DBUSTRACE(("txoff\n")); return BCME_EPERM; } - return dbus_send_txdata(&bus->pub, pktbuf); + return dbus_send_pkt(&bus->pub, pktbuf, pktbuf); +} + +int +dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) +{ + int timeleft = 0; + int ret = -1; + + DBUSTRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd->dongle_reset) + return -EIO; + + bus->ctl_completed = FALSE; + ret = dbus_send_ctl(bus, (void *)msg, msglen); + if (ret) { + DBUSERR(("%s: dbus_send_ctl error %d\n", __FUNCTION__, ret)); + return ret; + } + + timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->ctl_completed); + if ((!timeleft) || (!bus->ctl_completed)) { + DBUSERR(("%s: Txctl timeleft %d ctl_completed %d\n", + __FUNCTION__, timeleft, bus->ctl_completed)); + ret = -1; +#ifdef OEM_ANDROID + bus->dhd->hang_reason = HANG_REASON_IOCTL_RESP_TIMEOUT_SCHED_ERROR; + dhd_os_send_hang_message(bus->dhd); +#endif /* OEM_ANDROID */ + } + +#ifdef INTR_EP_ENABLE + /* If the ctl write is successfully completed, wait for an acknowledgement + * that indicates that it is now ok to do ctl read from the dongle + */ + if (ret != -1) { + bus->ctl_completed = FALSE; + if (dbus_poll_intr(bus->pub)) { + DBUSERR(("%s: dbus_poll_intr not submitted\n", __FUNCTION__)); + } else { + /* interrupt polling is sucessfully submitted. Wait for dongle to send + * interrupt + */ + timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->ctl_completed); + if (!timeleft) { + DBUSERR(("%s: intr poll wait timed out\n", __FUNCTION__)); + } + } + } +#endif /* INTR_EP_ENABLE */ + + return ret; +} + +int +dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) +{ + int timeleft; + int ret = -1; + + DBUSTRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd->dongle_reset) + return -EIO; + + bus->ctl_completed = FALSE; + ret = dbus_recv_ctl(bus, (uchar*)msg, msglen); + if (ret) { + DBUSERR(("%s: dbus_recv_ctl error %d\n", __FUNCTION__, ret)); + goto done; + } + + timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->ctl_completed); + if ((!timeleft) || (!bus->ctl_completed)) { + DBUSERR(("%s: Rxctl timeleft %d ctl_completed %d\n", __FUNCTION__, + timeleft, bus->ctl_completed)); + ret = -ETIMEDOUT; + goto done; + } + + /* XXX FIX: Must return cdc_len, not len, because after query_ioctl() + * it subtracts sizeof(cdc_ioctl_t); The other approach is + * to have dbus_recv_ctl() return actual len. + */ + ret = msglen; + +done: + return ret; } static void @@ -2636,7 +3027,8 @@ dhd_dbus_advertise_bus_remove(dhd_pub_t *dhdp) int timeleft; DHD_LINUX_GENERAL_LOCK(dhdp, flags); - dhdp->busstate = DHD_BUS_REMOVE; + if (dhdp->busstate != DHD_BUS_SUSPEND) + dhdp->busstate = DHD_BUS_REMOVE; DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); @@ -2729,27 +3121,160 @@ dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, } +static int +dhd_dbus_sync_dongle(dhd_pub_t *pub, int dlneeded) +{ + int ret = 0; + + if (dlneeded == 0) { + ret = dbus_up(pub->bus); + if (ret) { + DBUSERR(("%s: dbus_up failed!!\n", __FUNCTION__)); + goto exit; + } + ret = dhd_sync_with_dongle(pub); + if (ret < 0) { + DBUSERR(("%s: failed with code ret=%d\n", __FUNCTION__, ret)); + goto exit; + } + } + +exit: + return ret; +} + +static int +dbus_suspend(void *context) +{ + int ret = 0; + +#if defined(LINUX) + dhd_bus_t *bus = (dhd_bus_t*)context; + unsigned long flags; + + DBUSERR(("%s Enter\n", __FUNCTION__)); + if (bus->dhd == NULL) { + DBUSERR(("bus not inited\n")); + return BCME_ERROR; + } + if (bus->dhd->prot == NULL) { + DBUSERR(("prot is not inited\n")); + return BCME_ERROR; + } + + if (bus->dhd->up == FALSE) { + return BCME_OK; + } + + DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); + if (bus->dhd->busstate != DHD_BUS_DATA && bus->dhd->busstate != DHD_BUS_SUSPEND) { + DBUSERR(("not in a readystate to LPBK is not inited\n")); + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); + return BCME_ERROR; + } + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); + if (bus->dhd->dongle_reset) { + DBUSERR(("Dongle is in reset state.\n")); + return -EIO; + } + + DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); + /* stop all interface network queue. */ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); + bus->dhd->busstate = DHD_BUS_SUSPEND; +#if defined(LINUX) || defined(linux) + if (DHD_BUS_BUSY_CHECK_IN_TX(bus->dhd)) { + DBUSERR(("Tx Request is not ended\n")); + bus->dhd->busstate = DHD_BUS_DATA; + /* resume all interface network queue. */ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); + return -EBUSY; + } +#endif /* LINUX || linux */ + DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd); + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); + + ret = dhd_os_check_wakelock_all(bus->dhd); + + DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); + if (ret) { + bus->dhd->busstate = DHD_BUS_DATA; + /* resume all interface network queue. */ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); + } else { + bus->last_suspend_end_time = OSL_LOCALTIME_NS(); + } + bus->dhd->hostsleep = 2; + DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd); + dhd_os_busbusy_wake(bus->dhd); + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); + +#endif /* LINUX */ + DBUSERR(("%s Exit ret=%d\n", __FUNCTION__, ret)); + return ret; +} + +static int +dbus_resume(void *context) +{ + dhd_bus_t *bus = (dhd_bus_t*)context; + ulong flags; + int dlneeded = 0; + int ret = 0; + + DBUSERR(("%s Enter\n", __FUNCTION__)); + + if (bus->dhd->up == FALSE) { + return BCME_OK; + } + + dlneeded = dbus_dlneeded(bus); + if (dlneeded == 0) { + ret = dbus_up(bus); + if (ret) { + DBUSERR(("%s: dbus_up failed!!\n", __FUNCTION__)); + } + } + + DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); + DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd); + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); + + DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); + DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd); + bus->dhd->hostsleep = 0; + bus->dhd->busstate = DHD_BUS_DATA; + dhd_os_busbusy_wake(bus->dhd); + /* resume all interface network queue. */ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); +// dhd_conf_set_suspend_resume(bus->dhd, 0); + + return 0; +} + /* * hdrlen is space to reserve in pkt headroom for DBUS */ -void * -dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, - uint16 bus_no, uint16 slot, uint32 hdrlen) +static void * +dhd_dbus_probe_cb(uint16 bus_no, uint16 slot, uint32 hdrlen) { osl_t *osh = NULL; dhd_bus_t *bus = NULL; dhd_pub_t *pub = NULL; uint rxsz; - int dlneeded = 0; + int dlneeded = 0, ret = DBUS_OK; wifi_adapter_info_t *adapter = NULL; + bool net_attach_now = TRUE; DBUSTRACE(("%s: Enter\n", __FUNCTION__)); - adapter = dhd_wifi_platform_get_adapter(bustype, bus_no, slot); + adapter = dhd_wifi_platform_get_adapter(USB_BUS, bus_no, slot); if (!g_pub) { /* Ask the OS interface part for an OSL handle */ - if (!(osh = osl_attach(NULL, bustype, TRUE))) { + if (!(osh = osl_attach(NULL, USB_BUS, TRUE))) { DBUSERR(("%s: OSL attach failed\n", __FUNCTION__)); goto fail; } @@ -2776,35 +3301,57 @@ dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, bus->dhd = pub; dlneeded = dbus_dlneeded(bus); - if (dlneeded >= 0) { - if (!g_pub) { - dhd_conf_reset(pub); - dhd_conf_set_chiprev(pub, bus->pub.attrib.devid, bus->pub.attrib.chiprev); - dhd_conf_preinit(pub); - } + if (dlneeded >= 0 && !g_pub) { + dhd_conf_reset(pub); + dhd_conf_set_chiprev(pub, bus->pub.attrib.devid, bus->pub.attrib.chiprev); + dhd_conf_preinit(pub); } - if (g_pub || dhd_download_fw_on_driverload) { - if (dlneeded == 0) { +#if defined(BCMDHD_MODULAR) && defined(INSMOD_FW_LOAD) + if (1) +#else + if (g_pub || dhd_download_fw_on_driverload) +#endif + { + if (dlneeded == 0) wifi_set_adapter_status(adapter, WIFI_STATUS_FW_READY); #ifdef BCM_REQUEST_FW - } else if (dlneeded > 0) { + else if (dlneeded > 0) { + struct dhd_conf *conf = pub->conf; + unsigned long flags; + bool suspended; + wifi_clr_adapter_status(adapter, WIFI_STATUS_FW_READY); + suspended = conf->suspended; dhd_set_path(bus->dhd); - if (dbus_download_firmware(bus, bus->fw_path, bus->nv_path) != DBUS_OK) + conf->suspended = suspended; + if (dbus_download_firmware(bus) != DBUS_OK) goto fail; + DHD_LINUX_GENERAL_LOCK(pub, flags); + if (bus->dhd->busstate != DHD_BUS_SUSPEND) + bus->dhd->busstate = DHD_BUS_LOAD; + DHD_LINUX_GENERAL_UNLOCK(pub, flags); + } #endif - } else { + else { goto fail; } } - } else { + } + else { DBUSERR(("%s: dbus_attach failed\n", __FUNCTION__)); + goto fail; } - if (!g_pub) { - /* Ok, have the per-port tell the stack we're open for business */ - if (dhd_attach_net(bus->dhd, TRUE) != 0) - { +#if defined(BCMDHD_MODULAR) && defined(INSMOD_FW_LOAD) + if (dlneeded > 0) + net_attach_now = FALSE; +#endif + + if (!net_attached && (net_attach_now || (dlneeded == 0))) { + if (dhd_dbus_sync_dongle(pub, dlneeded)) { + goto fail; + } + if (dhd_attach_net(bus->dhd, TRUE) != 0) { DBUSERR(("%s: Net attach failed!!\n", __FUNCTION__)); goto fail; } @@ -2812,14 +3359,32 @@ dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, #if defined(MULTIPLE_SUPPLICANT) wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe #endif + net_attached = TRUE; + } + else if (net_attached && (pub->up == 1) && (dlneeded == 0)) { + // kernel resume case + pub->hostsleep = 0; + ret = dhd_dbus_sync_dongle(pub, dlneeded); +#ifdef WL_CFG80211 + __wl_cfg80211_up_resume(pub); + wl_cfgp2p_start_p2p_device_resume(pub); +#endif + dhd_conf_set_suspend_resume(pub, 0); + if (ret != DBUS_OK) + goto fail; + } + + if (!g_pub) { g_pub = pub; } DBUSTRACE(("%s: Exit\n", __FUNCTION__)); - wifi_clr_adapter_status(adapter, WIFI_STATUS_DETTACH); - wifi_set_adapter_status(adapter, WIFI_STATUS_ATTACH); - wake_up_interruptible(&adapter->status_event); - /* This is passed to dhd_dbus_disconnect_cb */ + wifi_clr_adapter_status(adapter, WIFI_STATUS_BUS_DISCONNECTED); + if (net_attached) { + wifi_set_adapter_status(adapter, WIFI_STATUS_NET_ATTACHED); + wake_up_interruptible(&adapter->status_event); + /* This is passed to dhd_dbus_disconnect_cb */ + } return bus; fail: @@ -2842,7 +3407,7 @@ fail: return NULL; } -void +static void dhd_dbus_disconnect_cb(void *arg) { dhd_bus_t *bus = (dhd_bus_t *)arg; @@ -2868,8 +3433,7 @@ dhd_dbus_disconnect_cb(void *arg) dhd_dbus_advertise_bus_remove(bus->dhd); dbus_detach(pub->bus); pub->bus = NULL; - wifi_clr_adapter_status(adapter, WIFI_STATUS_ATTACH); - wifi_set_adapter_status(adapter, WIFI_STATUS_DETTACH); + wifi_set_adapter_status(adapter, WIFI_STATUS_BUS_DISCONNECTED); wake_up_interruptible(&adapter->status_event); } else { osh = pub->osh; @@ -2880,6 +3444,8 @@ dhd_dbus_disconnect_cb(void *arg) } dhd_free(pub); g_pub = NULL; + net_attached = FALSE; + wifi_clr_adapter_status(adapter, WIFI_STATUS_NET_ATTACHED); if (MALLOCED(osh)) { DBUSERR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh))); } @@ -2889,6 +3455,24 @@ dhd_dbus_disconnect_cb(void *arg) DBUSTRACE(("%s: Exit\n", __FUNCTION__)); } +int +dhd_bus_sleep(dhd_pub_t *dhdp, bool sleep, uint32 *intstatus) +{ + wifi_adapter_info_t *adapter = (wifi_adapter_info_t *)dhdp->adapter; + s32 timeout = -1; + int err = 0; + + timeout = wait_event_interruptible_timeout(adapter->status_event, + wifi_get_adapter_status(adapter, WIFI_STATUS_BUS_DISCONNECTED), + msecs_to_jiffies(12000)); + if (timeout <= 0) { + err = -1; + DBUSERR(("%s: bus disconnected timeout\n", __FUNCTION__)); + } + + return err; +} + #ifdef LINUX_EXTERNAL_MODULE_DBUS static int __init @@ -2906,7 +3490,11 @@ bcm_dbus_module_exit(void) } EXPORT_SYMBOL(dbus_pnp_sleep); +EXPORT_SYMBOL(dhd_bus_register); EXPORT_SYMBOL(dbus_get_devinfo); +#ifdef BCMDBG +EXPORT_SYMBOL(dbus_hist_dump); +#endif EXPORT_SYMBOL(dbus_detach); EXPORT_SYMBOL(dbus_get_attrib); EXPORT_SYMBOL(dbus_down); @@ -2918,6 +3506,7 @@ EXPORT_SYMBOL(dbus_get_device_speed); EXPORT_SYMBOL(dbus_send_pkt); EXPORT_SYMBOL(dbus_recv_ctl); EXPORT_SYMBOL(dbus_attach); +EXPORT_SYMBOL(dhd_bus_unregister); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c old mode 100755 new mode 100644 index edc4109a19ce..28cf3f092f1c --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c @@ -1,15 +1,14 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /* * Dongle BUS interface for USB, OS independent * - * Copyright (C) 1999-2016, Broadcom Corporation - * + * Copyright (C) 2022, Broadcom. + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -17,15 +16,9 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. * * - * <> - * - * $Id: dbus_usb.c 565557 2015-06-22 19:29:44Z $ + * <> */ /** @@ -43,10 +36,21 @@ #include #include +#if defined(BCM_DNGL_EMBEDIMAGE) +#ifdef EMBED_IMAGE_43526a +#include "rtecdc_43526a.h" +#endif /* EMBED_IMAGE_43526a */ +#ifdef EMBED_IMAGE_43526b +#include "rtecdc_43526b.h" +#endif /* EMBED_IMAGE_43526b */ +#ifdef EMBED_IMAGE_GENERIC +#include "rtecdc.h" +#endif +#endif /* BCM_DNGL_EMBEDIMAGE */ + uint dbus_msglevel = DBUS_ERROR_VAL; module_param(dbus_msglevel, int, 0); - #define USB_DLIMAGE_RETRY_TIMEOUT 3000 /* retry Timeout */ #define USB_SFLASH_DLIMAGE_SPINWAIT 150 /* in unit of ms */ #define USB_SFLASH_DLIMAGE_LIMIT 2000 /* spinwait limit (ms) */ @@ -56,6 +60,9 @@ module_param(dbus_msglevel, int, 0); #define USB_DLGO_SPINWAIT 100 /* wait after DL_GO (ms) */ #define TEST_CHIP 0x4328 +/* driver info, initialized when bcmsdh_register is called */ +static dbus_driver_t drvinfo = {NULL, NULL, NULL, NULL}; + typedef struct { dbus_pub_t *pub; @@ -83,11 +90,11 @@ static void dbus_usb_rxerr_indicate(void *handle, bool on); static int dbus_usb_resetcfg(usb_info_t *usbinfo); #endif static int dbus_usb_iovar_op(void *bus, const char *name, - void *params, int plen, void *arg, int len, bool set); + void *params, uint plen, void *arg, uint len, bool set); static int dbus_iovar_process(usb_info_t* usbinfo, const char *name, - void *params, int plen, void *arg, int len, bool set); + void *params, int plen, void *arg, uint len, bool set); static int dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, - const char *name, void *params, int plen, void *arg, int len, int val_size); + const char *name, void *params, int plen, void *arg, uint len, int val_size); static int dhdusb_downloadvars(usb_info_t *bus, void *arg, int len); static int dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen); @@ -96,6 +103,9 @@ static int dbus_usb_dlneeded(void *bus); static int dbus_usb_dlrun(void *bus); static int dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo); +#ifdef BCM_DNGL_EMBEDIMAGE +static bool dbus_usb_device_exists(void *bus); +#endif /* OS specific */ extern bool dbus_usbos_dl_cmd(void *info, uint8 cmd, void *buffer, int buflen); @@ -135,12 +145,12 @@ enum { }; const bcm_iovar_t dhdusb_iovars[] = { - {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, - {"dbus_msglevel", IOV_DBUS_MSGLEVEL, 0, IOVT_UINT32, 0 }, - {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, - {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, - {"usb_lb_txfer", IOV_LOOPBACK_TX, 0, IOVT_BUFFER, 2 * sizeof(int) }, - {NULL, 0, 0, 0, 0 } + {"vars", IOV_VARS, 0, 0, IOVT_BUFFER, 0 }, + {"dbus_msglevel", IOV_DBUS_MSGLEVEL, 0, 0, IOVT_UINT32, 0 }, + {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, 0, IOVT_BOOL, 0 }, + {"membytes", IOV_MEMBYTES, 0, 0, IOVT_BUFFER, 2 * sizeof(int) }, + {"usb_lb_txfer", IOV_LOOPBACK_TX, 0, 0, IOVT_BUFFER, 2 * sizeof(int) }, + {NULL, 0, 0, 0, 0, 0 } }; /* @@ -148,10 +158,6 @@ const bcm_iovar_t dhdusb_iovars[] = { * attach() is not called at probe and detach() * can be called inside disconnect() */ -static probe_cb_t probe_cb = NULL; -static disconnect_cb_t disconnect_cb = NULL; -static void *probe_arg = NULL; -static void *disc_arg = NULL; static dbus_intf_t *g_dbusintf = NULL; static dbus_intf_t dbus_usb_intf; /** functions called by higher layer DBUS into lower layer */ @@ -161,8 +167,10 @@ static dbus_intf_t dbus_usb_intf; /** functions called by higher layer DBUS into */ static void *dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs); static void dbus_usb_detach(dbus_pub_t *pub, void *info); -static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype, - uint16 bus_no, uint16 slot, uint32 hdrlen); +/* : g_usb_info needed for over-ridden functions + * since the bus argument is actually from dbus_usb_.c. + */ +static void * dbus_usb_probe(uint16 bus_no, uint16 slot, uint32 hdrlen); /* functions */ @@ -171,12 +179,10 @@ static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype, * lower level DBUS functions to call (in both dbus_usb.c and dbus_usb_os.c). */ static void * -dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no, - uint16 slot, uint32 hdrlen) +dbus_usb_probe(uint16 bus_no, uint16 slot, uint32 hdrlen) { DBUSTRACE(("%s(): \n", __FUNCTION__)); - if (probe_cb) { - + if (drvinfo.probe) { if (g_dbusintf != NULL) { /* First, initialize all lower-level functions as default * so that dbus.c simply calls directly to dbus_usb_os.c. @@ -190,34 +196,60 @@ dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no, dbus_usb_intf.dlstart = dbus_usb_dlstart; dbus_usb_intf.dlneeded = dbus_usb_dlneeded; dbus_usb_intf.dlrun = dbus_usb_dlrun; +#ifdef BCM_DNGL_EMBEDIMAGE + dbus_usb_intf.device_exists = dbus_usb_device_exists; +#endif } - disc_arg = probe_cb(probe_arg, "DBUS USB", USB_BUS, bus_no, slot, hdrlen); - return disc_arg; + return drvinfo.probe(bus_no, slot, hdrlen); } return NULL; } +static int +dbus_usb_suspend(void *handle) +{ + DBUSTRACE(("%s(): \n", __FUNCTION__)); + + if (drvinfo.suspend) + return drvinfo.suspend(handle); + + return BCME_OK; +} + +static int +dbus_usb_resume(void *handle) +{ + DBUSTRACE(("%s(): \n", __FUNCTION__)); + + if (drvinfo.resume) + drvinfo.resume(handle); + + return 0; +} + +static dbus_driver_t dhd_usb_dbus = { + dbus_usb_probe, + dbus_usb_disconnect, + dbus_usb_suspend, + dbus_usb_resume +}; + /** * On return, *intf contains this or lower-level DBUS functions to be called by higher * level (dbus.c) */ int -dbus_bus_register(int vid, int pid, probe_cb_t prcb, - disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2) +dbus_bus_register(dbus_driver_t *driver, dbus_intf_t **intf) { int err; DBUSTRACE(("%s(): \n", __FUNCTION__)); - probe_cb = prcb; - disconnect_cb = discb; - probe_arg = prarg; - + drvinfo = *driver; *intf = &dbus_usb_intf; - err = dbus_bus_osl_register(vid, pid, dbus_usb_probe, - dbus_usb_disconnect, NULL, &g_dbusintf, param1, param2); + err = dbus_bus_osl_register(&dhd_usb_dbus, &g_dbusintf); ASSERT(g_dbusintf); return err; @@ -293,8 +325,8 @@ void dbus_usb_disconnect(void *handle) { DBUSTRACE(("%s(): \n", __FUNCTION__)); - if (disconnect_cb) - disconnect_cb(disc_arg); + if (drvinfo.remove) + drvinfo.remove(handle); } /** @@ -433,7 +465,7 @@ dbus_usb_state_change(void *handle, int state) /** called by higher DBUS level (dbus.c) */ static int dbus_usb_iovar_op(void *bus, const char *name, - void *params, int plen, void *arg, int len, bool set) + void *params, uint plen, void *arg, uint len, bool set) { int err = DBUS_OK; @@ -444,7 +476,7 @@ dbus_usb_iovar_op(void *bus, const char *name, /** process iovar request from higher DBUS level */ static int dbus_iovar_process(usb_info_t* usbinfo, const char *name, - void *params, int plen, void *arg, int len, bool set) + void *params, int plen, void *arg, uint len, bool set) { const bcm_iovar_t *vi = NULL; int bcmerror = 0; @@ -454,7 +486,6 @@ dbus_iovar_process(usb_info_t* usbinfo, const char *name, DBUSTRACE(("%s: Enter\n", __FUNCTION__)); ASSERT(name); - ASSERT(len >= 0); /* Get MUST have return space */ ASSERT(set || (arg && len)); @@ -500,7 +531,7 @@ exit: static int dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, - void *params, int plen, void *arg, int len, int val_size) + void *params, int plen, void *arg, uint len, int val_size) { int bcmerror = 0; int32 int_val = 0; @@ -558,7 +589,6 @@ dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, const } break; - case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): if (bool_val == TRUE) { @@ -700,6 +730,7 @@ dbus_usb_resetcfg(usb_info_t *usbinfo) dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t)); + /* this wait may not be necessary */ dbus_usbos_wait(osinfo, USB_RESETCFG_SPINWAIT); return DBUS_OK; } else { @@ -750,13 +781,8 @@ dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen) char *bulkchunk = NULL, *dlpos; rdl_state_t state; int err = DBUS_OK; - bootrom_id_t id; - uint16 wait, wait_time; uint32 dl_trunk_size = RDL_CHUNK; - if (BCM4350_CHIP(usbinfo->pub->attrib.devid)) - dl_trunk_size = RDL_CHUNK_MAX; - while (!bulkchunk) { bulkchunk = MALLOC(osh, dl_trunk_size); if (dl_trunk_size == RDL_CHUNK) @@ -777,10 +803,6 @@ dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen) dlpos = fw; dllen = fwlen; - /* Get chip id and rev */ - id.chip = usbinfo->pub->attrib.devid; - id.chiprev = usbinfo->pub->attrib.chiprev; - DBUSTRACE(("enter %s: fwlen=%d\n", __FUNCTION__, fwlen)); dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t)); @@ -789,6 +811,7 @@ dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen) while ((sent < dllen)) { /* Wait until the usb device reports it received all the bytes we sent */ + /* add a timeout so we dont wait indefinetly */ if (sent < dllen) { if ((dllen-sent) < dl_trunk_size) sendlen = dllen-sent; @@ -813,26 +836,11 @@ dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen) DBUSTRACE(("%s: sendlen %d\n", __FUNCTION__, sendlen)); } - wait = 0; - wait_time = USB_SFLASH_DLIMAGE_SPINWAIT; - while (!dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, - sizeof(rdl_state_t))) { - if ((id.chip == 43236) && (id.chiprev == 0)) { - DBUSERR(("%s: 43236a0 SFlash delay, waiting for dongle crc check " - "completion!!!\n", __FUNCTION__)); - dbus_usbos_wait(osinfo, wait_time); - wait += wait_time; - if (wait >= USB_SFLASH_DLIMAGE_LIMIT) { - DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__)); - err = DBUS_ERR; - goto fail; - break; - } - } else { - DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__)); - err = DBUS_ERR; - goto fail; - } + /* Wait for downloaded image crc check to complete in the dongle */ + while (!dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t))) { + DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__)); + err = DBUS_ERR; + goto fail; } state.state = ltoh32(state.state); @@ -888,58 +896,32 @@ dbus_usb_update_chipinfo(usb_info_t *usbinfo, uint32 chip) bool retval = TRUE; /* based on the CHIP Id, store the ram size which is needed for NVRAM download. */ switch (chip) { - - case 0x4319: - usbinfo->rdlram_size = RDL_RAM_SIZE_4319; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_4319; - break; - - case 0x4329: - usbinfo->rdlram_size = RDL_RAM_SIZE_4329; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_4329; - break; - - case 43234: - case 43235: - case 43236: - usbinfo->rdlram_size = RDL_RAM_SIZE_43236; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_43236; - break; - - case 0x4328: - usbinfo->rdlram_size = RDL_RAM_SIZE_4328; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_4328; - break; - - case 0x4322: - usbinfo->rdlram_size = RDL_RAM_SIZE_4322; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_4322; - break; - case 0x4360: case 0xAA06: usbinfo->rdlram_size = RDL_RAM_SIZE_4360; usbinfo->rdlram_base_addr = RDL_RAM_BASE_4360; break; - case 43242: - case 43243: usbinfo->rdlram_size = RDL_RAM_SIZE_43242; usbinfo->rdlram_base_addr = RDL_RAM_BASE_43242; break; - case 43143: usbinfo->rdlram_size = RDL_RAM_SIZE_43143; usbinfo->rdlram_base_addr = RDL_RAM_BASE_43143; break; - - case 0x4350: - case 43556: - case 43558: case 43569: usbinfo->rdlram_size = RDL_RAM_SIZE_4350; usbinfo->rdlram_base_addr = RDL_RAM_BASE_4350; break; + case BCM4381_CHIP_ID: + usbinfo->rdlram_size = RDL_RAM_SIZE_4381; + usbinfo->rdlram_base_addr = RDL_RAM_BASE_4381; + break; + + case BCM4382_CHIP_ID: + usbinfo->rdlram_size = RDL_RAM_SIZE_4382; + usbinfo->rdlram_base_addr = RDL_RAM_BASE_4382; + break; case POSTBOOT_ID: break; @@ -1032,6 +1014,9 @@ dbus_usb_dlrun(void *bus) DBUSTRACE(("%s: Issue DL_GO\n", __FUNCTION__)); dbus_usbos_dl_cmd(osinfo, DL_GO, &state, sizeof(rdl_state_t)); + /* : Need this for 4326 for some reason + * Same issue under both Linux/Windows + */ if (usbinfo->pub->attrib.devid == TEST_CHIP) dbus_usbos_wait(osinfo, USB_DLGO_SPINWAIT); @@ -1059,111 +1044,12 @@ dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp) devid = usbinfo->pub->attrib.devid; crev = usbinfo->pub->attrib.chiprev; + BCM_REFERENCE(crev); *fw = NULL; *fwlen = 0; switch (devid) { - case BCM43236_CHIP_ID: - case BCM43235_CHIP_ID: - case BCM43234_CHIP_ID: - case BCM43238_CHIP_ID: { - if (crev == 3 || crev == 2 || crev == 1) { -#ifdef EMBED_IMAGE_43236b - *fw = (uint8 *)dlarray_43236b; - *fwlen = sizeof(dlarray_43236b); - -#endif - } - } break; - case BCM4360_CHIP_ID: - case BCM4352_CHIP_ID: - case BCM43526_CHIP_ID: -#ifdef EMBED_IMAGE_43526a - if (crev <= 2) { - *fw = (uint8 *)dlarray_43526a; - *fwlen = sizeof(dlarray_43526a); - } -#endif -#ifdef EMBED_IMAGE_43526b - if (crev > 2) { - *fw = (uint8 *)dlarray_43526b; - *fwlen = sizeof(dlarray_43526b); - } -#endif - break; - - case BCM43242_CHIP_ID: -#ifdef EMBED_IMAGE_43242a0 - *fw = (uint8 *)dlarray_43242a0; - *fwlen = sizeof(dlarray_43242a0); -#endif - break; - - case BCM43143_CHIP_ID: -#ifdef EMBED_IMAGE_43143a0 - *fw = (uint8 *)dlarray_43143a0; - *fwlen = sizeof(dlarray_43143a0); -#endif -#ifdef EMBED_IMAGE_43143b0 - *fw = (uint8 *)dlarray_43143b0; - *fwlen = sizeof(dlarray_43143b0); -#endif - break; - - case BCM4350_CHIP_ID: - case BCM4354_CHIP_ID: - case BCM43556_CHIP_ID: - case BCM43558_CHIP_ID: - case BCM43566_CHIP_ID: - case BCM43568_CHIP_ID: - case BCM43570_CHIP_ID: - case BCM4358_CHIP_ID: -#ifdef EMBED_IMAGE_4350a0 - if (crev == 0) { - *fw = (uint8 *)dlarray_4350a0; - *fwlen = sizeof(dlarray_4350a0); - } -#endif -#ifdef EMBED_IMAGE_4350b0 - if (crev == 1) { - *fw = (uint8 *)dlarray_4350b0; - *fwlen = sizeof(dlarray_4350b0); - } -#endif -#ifdef EMBED_IMAGE_4350b1 - if (crev == 2) { - *fw = (uint8 *)dlarray_4350b1; - *fwlen = sizeof(dlarray_4350b1); - } -#endif -#ifdef EMBED_IMAGE_43556b1 - if (crev == 2) { - *fw = (uint8 *)dlarray_43556b1; - *fwlen = sizeof(dlarray_43556b1); - } -#endif -#ifdef EMBED_IMAGE_4350c0 - if (crev == 3) { - *fw = (uint8 *)dlarray_4350c0; - *fwlen = sizeof(dlarray_4350c0); - } -#endif /* EMBED_IMAGE_4350c0 */ -#ifdef EMBED_IMAGE_4350c1 - if (crev == 4) { - *fw = (uint8 *)dlarray_4350c1; - *fwlen = sizeof(dlarray_4350c1); - } -#endif /* EMBED_IMAGE_4350c1 */ - break; - case BCM43569_CHIP_ID: -#ifdef EMBED_IMAGE_43569a0 - if (crev == 0) { - *fw = (uint8 *)dlarray_43569a0; - *fwlen = sizeof(dlarray_43569a0); - } -#endif /* EMBED_IMAGE_43569a0 */ - break; default: #ifdef EMBED_IMAGE_GENERIC *fw = (uint8 *)dlarray; @@ -1172,3 +1058,31 @@ dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp) break; } } /* dbus_bus_fw_get */ + +#ifdef BCM_DNGL_EMBEDIMAGE +static bool +dbus_usb_device_exists(void *bus) +{ + usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); + void *osinfo; + bootrom_id_t id; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (usbinfo == NULL) + return FALSE; + + osinfo = usbinfo->usbosl_info; + ASSERT(osinfo); + + id.chip = 0xDEAD; + /* Query device to see if we get a response */ + dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t)); + + usbinfo->pub->attrib.devid = id.chip; + if (id.chip == 0xDEAD) + return FALSE; + else + return TRUE; +} +#endif /* BCM_DNGL_EMBEDIMAGE */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c old mode 100755 new mode 100644 index ccf018b07cff..f113d5b8d6c5 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c @@ -1,16 +1,15 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /* * Dongle BUS interface * USB Linux Implementation * - * Copyright (C) 1999-2016, Broadcom Corporation - * + * Copyright (C) 2022, Broadcom. + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -18,15 +17,9 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. * * - * <> - * - * $Id: dbus_usb_linux.c 564663 2015-06-18 02:34:42Z $ + * <> */ /** @@ -84,6 +77,9 @@ #include #include #include +#ifdef DBUS_LINUX_RXDPC +#include +#endif #include #include @@ -101,8 +97,6 @@ * To improve system responsiveness and TPUT usb-thread was implemented. The system's threads could * be scheduled to run on any core. One core could be processing data in the usb-layer and the other * core could be processing data in the wl-layer. - * - * For further info see [WlThreadAndUsbThread] Twiki. */ #include @@ -113,7 +107,15 @@ #include #endif /* USBOS_THREAD || USBOS_TX_THREAD */ - +#ifdef DBUS_LINUX_RXDPC +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) +#define RESCHED() _cond_resched() +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define RESCHED() cond_resched() +#else +#define RESCHED() __cond_resched() +#endif /* LINUX_VERSION_CODE */ +#endif /* DBUS_LINUX_RXDPC */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) #define KERNEL26 @@ -124,26 +126,20 @@ * the kernel was built with CONFIG_PM_RUNTIME enabled. The CONFIG_USB_SUSPEND option has * been eliminated. */ -#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)) && defined(CONFIG_USB_SUSPEND)) \ - || ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) && defined(CONFIG_PM_RUNTIME)) \ - || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)) && defined(CONFIG_USB_SUSPEND)) ||\ + ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) && defined(CONFIG_PM_RUNTIME)) ||\ + (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) /* For USB power management support, see Linux kernel: Documentation/usb/power-management.txt */ #define USB_SUSPEND_AVAILABLE #endif -/* Define alternate fw/nvram paths used in Android */ -#ifdef OEM_ANDROID -#define CONFIG_ANDROID_BCMDHD_FW_PATH "broadcom/dhd/firmware/fw.bin.trx" -#define CONFIG_ANDROID_BCMDHD_NVRAM_PATH "broadcom/dhd/nvrams/nvm.txt" -#endif /* OEM_ANDROID */ - static inline int usb_submit_urb_linux(struct urb *urb) { #ifdef BCM_MAX_URB_LEN if (urb && (urb->transfer_buffer_length > BCM_MAX_URB_LEN)) { DBUSERR(("URB transfer length=%d exceeded %d ra=%p\n", urb->transfer_buffer_length, - BCM_MAX_URB_LEN, __builtin_return_address(0))); + BCM_MAX_URB_LEN, CALL_SITE)); return DBUS_ERR; } #endif @@ -204,13 +200,23 @@ static inline int usb_submit_urb_linux(struct urb *urb) #define URB_QUEUE_BULK 0 #endif /* WL_URB_ZPKT */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)) +#define CALLBACK_ARGS struct urb *urb +#define CALLBACK_ARGS_DATA urb +#else #define CALLBACK_ARGS struct urb *urb, struct pt_regs *regs #define CALLBACK_ARGS_DATA urb, regs +#endif /* 5.18 */ + #define CONFIGDESC(usb) (&((usb)->actconfig)->desc) #define IFPTR(usb, idx) ((usb)->actconfig->interface[idx]) #define IFALTS(usb, idx) (IFPTR((usb), (idx))->altsetting[0]) #define IFDESC(usb, idx) IFALTS((usb), (idx)).desc #define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[ep]).desc +#ifdef DBUS_LINUX_RXDPC +#define DAEMONIZE(a) daemonize(a); allow_signal(SIGKILL); allow_signal(SIGTERM); +#define SET_NICE(n) set_user_nice(current, n) +#endif #else /* KERNEL26 */ @@ -244,6 +250,10 @@ static inline int usb_submit_urb_linux(struct urb *urb) #define IFDESC(usb, idx) IFALTS((usb), (idx)) #define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[ep]) +#ifdef DBUS_LINUX_RXDPC +#define DAEMONIZE(a) daemonize(); +#define SET_NICE(n) do {current->nice = (n);} while (0) +#endif /* DBUS_LINUX_RXDPC */ #endif /* KERNEL26 */ @@ -257,13 +267,14 @@ static inline int usb_submit_urb_linux(struct urb *urb) #ifdef BCMUSBDEV_COMPOSITE #define USB_COMPIF_MAX 4 +/* temp defines, should come from the standard usb.h file */ #define USB_CLASS_WIRELESS 0xe0 #define USB_CLASS_MISC 0xef #define USB_SUBCLASS_COMMON 0x02 #define USB_PROTO_IAD 0x01 #define USB_PROTO_VENDOR 0xff -#define USB_QUIRK_NO_SET_INTF 0x04 /* device does not support set_interface */ +#define USB_QUIRK_NO_SET_INTF 0x04 /**< device does not support set_interface */ #endif /* BCMUSBDEV_COMPOSITE */ #define USB_SYNC_WAIT_TIMEOUT 300 /* ms */ @@ -273,26 +284,26 @@ static inline int usb_submit_urb_linux(struct urb *urb) #define SKB_PRIV_URB(skb) (*(struct urb **)SKB_PRIV(skb, 0)) #ifndef DBUS_USB_RXQUEUE_BATCH_ADD -/* items to add each time within limit */ +/** items to add each time within limit */ #define DBUS_USB_RXQUEUE_BATCH_ADD 8 #endif #ifndef DBUS_USB_RXQUEUE_LOWER_WATERMARK -/* add a new batch req to rx queue when waiting item count reduce to this number */ +/** add a new batch req to rx queue when waiting item count reduce to this number */ #define DBUS_USB_RXQUEUE_LOWER_WATERMARK 4 #endif enum usbos_suspend_state { - USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow suspend */ - USBOS_SUSPEND_STATE_SUSPEND_PENDING, /* Device is idle, can be suspended */ + USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /**< Device is busy, won't allow suspend */ + USBOS_SUSPEND_STATE_SUSPEND_PENDING, /**< Device is idle, can be suspended */ /* Wating PM to suspend */ - USBOS_SUSPEND_STATE_SUSPENDED /* Device suspended */ + USBOS_SUSPEND_STATE_SUSPENDED /**< Device suspended */ }; enum usbos_request_state { - USBOS_REQUEST_STATE_UNSCHEDULED = 0, /* USB TX request not scheduled */ - USBOS_REQUEST_STATE_SCHEDULED, /* USB TX request given to TX thread */ - USBOS_REQUEST_STATE_SUBMITTED /* USB TX request submitted */ + USBOS_REQUEST_STATE_UNSCHEDULED = 0, /**< USB TX request not scheduled */ + USBOS_REQUEST_STATE_SCHEDULED, /**< USB TX request given to TX thread */ + USBOS_REQUEST_STATE_SUBMITTED /**< USB TX request submitted */ }; typedef struct { @@ -307,25 +318,28 @@ typedef struct { dbus_intf_callbacks_t *cbs; /* Imported */ - struct usb_device *usb; /* USB device pointer from OS */ - struct urb *intr_urb; /* URB for interrupt endpoint */ + struct usb_device *usb; /**< USB device pointer from OS */ + struct urb *intr_urb; /**< URB for interrupt endpoint */ struct list_head req_rxfreeq; struct list_head req_txfreeq; - struct list_head req_rxpostedq; /* Posted down to USB driver for RX */ - struct list_head req_txpostedq; /* Posted down to USB driver for TX */ - spinlock_t rxfree_lock; /* Lock for rx free list */ - spinlock_t txfree_lock; /* Lock for tx free list */ - spinlock_t rxposted_lock; /* Lock for rx posted list */ - spinlock_t txposted_lock; /* Lock for tx posted list */ - uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2; /* Pipe numbers for USB I/O */ + struct list_head req_rxpostedq; /**< Posted down to USB driver for RX */ + struct list_head req_txpostedq; /**< Posted down to USB driver for TX */ + spinlock_t rxfree_lock; /**< Lock for rx free list */ + spinlock_t txfree_lock; /**< Lock for tx free list */ + spinlock_t rxposted_lock; /**< Lock for rx posted list */ + spinlock_t txposted_lock; /**< Lock for tx posted list */ + uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2; /**< Pipe numbers for USB I/O */ uint rxbuf_len; - struct list_head req_rxpendingq; /* RXDPC: Pending for dpc to send up */ - spinlock_t rxpending_lock; /* RXDPC: Lock for rx pending list */ + struct list_head req_rxpendingq; /**< RXDPC: Pending for dpc to send up */ + spinlock_t rxpending_lock; /**< RXDPC: Lock for rx pending list */ long dpc_pid; struct semaphore dpc_sem; struct completion dpc_exited; int rxpending; +#if defined(BCMDBG) || defined(DBUS_LINUX_HIST) + int dpc_cnt, dpc_pktcnt, dpc_maxpktcnt; +#endif struct urb *ctl_urb; int ctl_in_pipe, ctl_out_pipe; @@ -336,28 +350,31 @@ typedef struct { enum usbos_request_state ctl_state; #endif /* USBOS_TX_THREAD */ - spinlock_t rxlock; /* Lock for rxq management */ - spinlock_t txlock; /* Lock for txq management */ + spinlock_t rxlock; /**< Lock for rxq management */ + spinlock_t txlock; /**< Lock for txq management */ - int intr_size; /* Size of interrupt message */ - int interval; /* Interrupt polling interval */ - intr_t intr; /* Data buffer for interrupt endpoint */ + int intr_size; /**< Size of interrupt message */ + int interval; /**< Interrupt polling interval */ + intr_t intr; /**< Data buffer for interrupt endpoint */ int maxps; atomic_t txposted; atomic_t rxposted; atomic_t txallocated; atomic_t rxallocated; - bool rxctl_deferrespok; /* Get a response for setup from dongle */ + bool rxctl_deferrespok; /**< Get a response for setup from dongle */ wait_queue_head_t wait; bool waitdone; int sync_urb_status; - struct urb *blk_urb; /* Used for downloading embedded image */ + struct urb *blk_urb; /**< Used for downloading embedded image */ +#if defined(BCMDBG) || defined(DBUS_LINUX_HIST) + int *txposted_hist; + int *rxposted_hist; +#endif #ifdef USBOS_THREAD - spinlock_t ctrl_lock; spinlock_t usbos_list_lock; struct list_head usbos_list; struct list_head usbos_free_list; @@ -373,9 +390,12 @@ typedef struct { struct task_struct *usbos_tx_kt; #endif /* USBOS_TX_THREAD */ - struct dma_pool *qtd_pool; /* QTD pool for USB optimization only */ - int tx_ep, rx_ep, rx2_ep; /* EPs for USB optimization */ - struct usb_device *usb_device; /* USB device for optimization */ + struct dma_pool *qtd_pool; /**< QTD pool for USB optimization only */ + int tx_ep, rx_ep, rx2_ep; /**< EPs for USB optimization */ + struct usb_device *usb_device; /**< USB device for optimization */ +#if defined(EHCI_FASTPATH_TX) || defined(EHCI_FASTPATH_RX) /** Linux USB AP related */ + spinlock_t fastpath_lock; +#endif } usbos_info_t; typedef struct urb_req { @@ -415,6 +435,10 @@ int dbus_write_membytes(usbos_info_t *usbinfo, bool set, uint32 address, uint8 * /* Local function prototypes */ static void dbus_usbos_send_complete(CALLBACK_ARGS); +#ifdef DBUS_LINUX_RXDPC +static void dbus_usbos_recv_dpc(usbos_info_t *usbos_info); +static int dbus_usbos_dpc_thread(void *data); +#endif /* DBUS_LINUX_RXDPC */ static void dbus_usbos_recv_complete(CALLBACK_ARGS); static int dbus_usbos_errhandler(void *bus, int err); static int dbus_usbos_state_change(void *bus, int state); @@ -426,7 +450,7 @@ static void dbus_usbos_disconnect(struct usb_interface *intf); #if defined(USB_SUSPEND_AVAILABLE) static int dbus_usbos_resume(struct usb_interface *intf); static int dbus_usbos_suspend(struct usb_interface *intf, pm_message_t message); -/* at the moment, used for full dongle host driver only */ +/** at the moment, used for full dongle host driver only */ static int dbus_usbos_reset_resume(struct usb_interface *intf); #endif /* USB_SUSPEND_AVAILABLE */ #else /* KERNEL26 */ @@ -435,6 +459,19 @@ static void *dbus_usbos_probe(struct usb_device *usb, unsigned int ifnum, static void dbus_usbos_disconnect(struct usb_device *usb, void *ptr); #endif /* KERNEL26 */ +#ifdef USB_TRIGGER_DEBUG +static bool dbus_usbos_ctl_send_debugtrig(usbos_info_t *usbinfo); +#endif /* USB_TRIGGER_DEBUG */ + +#ifdef KEEPIF_ON_DEVICE_RESET +enum usb_dev_status { + USB_DEVICE_INIT = 0, + USB_DEVICE_RESETTED = 1, + USB_DEVICE_DISCONNECTED = 2, + USB_DEVICE_PROBED +}; +static int dbus_usbos_usbreset_func(void *data); +#endif /* KEEPIF_ON_DEVICE_RESET */ /** * have to disable missing-field-initializers warning as last element {} triggers it @@ -450,16 +487,13 @@ static void dbus_usbos_disconnect(struct usb_device *usb, void *ptr); static struct usb_device_id devid_table[] = { { USB_DEVICE(BCM_DNGL_VID, 0x0000) }, /* Configurable via register() */ -#if defined(BCM_REQUEST_FW) +#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4328) }, - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4322) }, - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4319) }, - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43236) }, { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43143) }, { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43242) }, { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4360) }, - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4350) }, { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43569) }, + { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4381) }, #endif #ifdef EXTENDED_VID_PID EXTENDED_VID_PID, @@ -477,7 +511,7 @@ MODULE_DEVICE_TABLE(usb, devid_table); /** functions called by the Linux kernel USB subsystem */ static struct usb_driver dbus_usbdev = { - name: "dbus_usbdev", + name: "dbus_usbdev"BUS_TYPE, probe: dbus_usbos_probe, disconnect: dbus_usbos_disconnect, id_table: devid_table, @@ -485,7 +519,7 @@ static struct usb_driver dbus_usbdev = { suspend: dbus_usbos_suspend, resume: dbus_usbos_resume, reset_resume: dbus_usbos_reset_resume, - /* Linux USB core will allow autosuspend for devices bound to this driver */ + /** Linux USB core will allow autosuspend for devices bound to this driver */ supports_autosuspend: 1 #endif /* USB_SUSPEND_AVAILABLE */ }; @@ -495,13 +529,13 @@ static struct usb_driver dbus_usbdev = { */ typedef struct { void *usbos_info; - struct usb_device *usb; /* USB device pointer from OS */ - uint rx_pipe; /* Pipe numbers for USB I/O */ - uint tx_pipe; /* Pipe numbers for USB I/O */ - uint intr_pipe; /* Pipe numbers for USB I/O */ - uint rx_pipe2; /* Pipe numbers for USB I/O */ - int intr_size; /* Size of interrupt message */ - int interval; /* Interrupt polling interval */ + struct usb_device *usb; /**< USB device pointer from OS */ + uint rx_pipe; /**< Pipe numbers for USB I/O */ + uint tx_pipe; /**< Pipe numbers for USB I/O */ + uint intr_pipe; /**< Pipe numbers for USB I/O */ + uint rx_pipe2; /**< Pipe numbers for USB I/O */ + int intr_size; /**< Size of interrupt message */ + int interval; /**< Interrupt polling interval */ bool dldone; int vid; int pid; @@ -510,11 +544,23 @@ typedef struct { DEVICE_SPEED device_speed; enum usbos_suspend_state suspend_state; struct usb_interface *intf; +#ifdef KEEPIF_ON_DEVICE_RESET + bool keepif_on_devreset; /* if need keep network interface on dev reset */ + bool dev_resetted; /* if dev reset event occured */ + enum dbus_state busstate_bf_devreset; /* busstate before devreset */ + atomic_t usbdev_stat; /* usb device status: resetted? disconnected? re-probed? */ + wait_queue_head_t usbreset_queue_head; /* kernel thread waiting queue */ + struct task_struct *usbreset_kt; /* kernel thread handle dev reset/probe event */ +#endif /* KEEPIF_ON_DEVICE_RESET */ } probe_info_t; +/* driver info, initialized when bcmsdh_register is called */ +static dbus_driver_t drvinfo = {NULL, NULL, NULL, NULL}; + /* * USB Linux dbus_intf_t */ +static void dbus_usbos_init_info(void); static void *dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs); static void dbus_usbos_intf_detach(dbus_pub_t *pub, void *info); static int dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb); @@ -530,6 +576,9 @@ static int dbus_usbos_intf_stop(void *bus); static int dbus_usbos_readreg(void *bus, uint32 regaddr, int datalen, uint32 *value); extern int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size); int dbus_usbos_writereg(void *bus, uint32 regaddr, int datalen, uint32 data); +#if defined(BCMDBG) || defined(DBUS_LINUX_HIST) +static void dbus_usbos_intf_dump(void *bus, struct bcmstrbuf *b); +#endif /* BCMDBG || DBUS_LINUX_HIST */ static int dbus_usbos_intf_set_config(void *bus, dbus_config_t *config); static bool dbus_usbos_intf_recv_needed(void *bus); static void *dbus_usbos_intf_exec_rxlock(void *bus, exec_cb_t cb, struct exec_parms *args); @@ -559,7 +608,11 @@ static dbus_intf_t dbus_usbos_intf = { .pktget = NULL, .pktfree = NULL, .iovar_op = NULL, +#if defined(BCMDBG) || defined(DBUS_LINUX_HIST) + .dump = dbus_usbos_intf_dump, +#else .dump = NULL, +#endif /* BCMDBG || DBUS_LINUX_HIST */ .set_config = dbus_usbos_intf_set_config, .get_config = NULL, .device_exists = NULL, @@ -589,12 +642,78 @@ static dbus_intf_t dbus_usbos_intf = { }; static probe_info_t g_probe_info; -static probe_cb_t probe_cb = NULL; -static disconnect_cb_t disconnect_cb = NULL; -static void *probe_arg = NULL; static void *disc_arg = NULL; +#if defined(EHCI_FASTPATH_TX) || defined(EHCI_FASTPATH_RX) +#define EHCI_PAGE_SIZE 4096 + +/* Copies of structures located elsewhere. */ +/* ME: Unify (move to include file) */ + +typedef struct { + dbus_pub_t *pub; + void *cbarg; + dbus_intf_callbacks_t *cbs; + dbus_intf_t *drvintf; + void *usbosl_info; +} usb_info_t; + +/** General info for all BUS */ +typedef struct dbus_irbq { + dbus_irb_t *head; + dbus_irb_t *tail; + int cnt; +} dbus_irbq_t; + +/** + * This private structure dbus_info_t is also declared in dbus.c. + * All the fields must be consistent in both declarations. + */ +typedef struct dbus_info { + dbus_pub_t pub; /* MUST BE FIRST */ + + void *cbarg; + dbus_callbacks_t *cbs; + void *bus_info; + dbus_intf_t *drvintf; + uint8 *fw; + int fwlen; + uint32 errmask; + int rx_low_watermark; + int tx_low_watermark; + bool txoff; + bool txoverride; + bool rxoff; + bool tx_timer_ticking; + dbus_irbq_t *rx_q; + dbus_irbq_t *tx_q; + +#ifdef BCMDBG + int *txpend_q_hist; + int *rxpend_q_hist; +#endif /* BCMDBG */ +#ifdef EHCI_FASTPATH_RX + atomic_t rx_outstanding; +#endif + uint8 *nvram; + int nvram_len; + uint8 *image; /**< buffer for combine fw and nvram */ + int image_len; + uint8 *orig_fw; + int origfw_len; + int decomp_memsize; + dbus_extdl_t extdl; + int nvram_nontxt; +} dbus_info_t; + +/* ME: Move to device extension */ +static atomic_t s_tx_pending; + +static int optimize_init(usbos_info_t *usbos_info, struct usb_device *usb, int out, + int in, int in2); +static int optimize_deinit(usbos_info_t *usbos_info, struct usb_device *usb); +#endif /* #if defined(EHCI_FASTPATH_TX) || defined(EHCI_FASTPATH_RX) */ static volatile int loopback_rx_cnt, loopback_tx_cnt; int loopback_size; @@ -620,14 +739,9 @@ dbus_usbos_qdeq(struct list_head *urbreq_q, spinlock_t *lock) } else { ASSERT(urbreq_q->next != NULL); ASSERT(urbreq_q->next != urbreq_q); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); req = list_entry(urbreq_q->next, urb_req_t, urb_list); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif + GCC_DIAGNOSTIC_POP(); list_del_init(&req->urb_list); } @@ -665,7 +779,6 @@ dbus_usbos_req_del(urb_req_t *req, spinlock_t *lock) spin_unlock_irqrestore(lock, flags); } - /** * Driver requires a pool of URBs to operate. This function is called during * initialization (attach phase), allocates a number of URBs, and puts them @@ -766,15 +879,14 @@ dbus_usbos_urbreqs_free(usbos_info_t *usbos_info, bool is_rx) req_q = &usbos_info->req_txfreeq; lock = &usbos_info->txfree_lock; } - while ((req = dbus_usbos_qdeq(req_q, lock)) != NULL) { + while ((req = dbus_usbos_qdeq(req_q, lock)) != NULL) { if (is_rx) { if (req->pkt) { /* We do MFREE instead of PKTFREE because the pkt has been * converted to native already */ MFREE(usbos_info->pub->osh, req->pkt, req->buf_len); - req->pkt = NULL; req->buf_len = 0; } } else { @@ -790,6 +902,7 @@ dbus_usbos_urbreqs_free(usbos_info_t *usbos_info, bool is_rx) rtn++; } + return rtn; } /* dbus_usbos_urbreqs_free */ @@ -813,6 +926,11 @@ dbus_usbos_send_complete(CALLBACK_ARGS) dbus_usbos_req_del(req, &usbos_info->txposted_lock); txposted = atomic_dec_return(&usbos_info->txposted); +#if defined(BCMDBG) || defined(DBUS_LINUX_HIST) + if (usbos_info->txposted_hist) { + usbos_info->txposted_hist[txposted]++; + } +#endif /* BCMDBG || DBUS_LINUX_HIST */ if (unlikely (txposted < 0)) { DBUSERR(("%s ERROR: txposted is negative (%d)!!\n", __FUNCTION__, txposted)); } @@ -831,7 +949,6 @@ dbus_usbos_send_complete(CALLBACK_ARGS) if (txirb != NULL) { if (txirb->send_buf != NULL) { MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len); - txirb->send_buf = NULL; req->buf_len = 0; } if (likely (usbos_info->cbarg && usbos_info->cbs)) { @@ -848,7 +965,8 @@ dbus_usbos_send_complete(CALLBACK_ARGS) * URB that is going to contain received data. */ static int -dbus_usbos_recv_urb_submit(usbos_info_t *usbos_info, dbus_irb_rx_t *rxirb, uint32 ep_idx) +dbus_usbos_recv_urb_submit(usbos_info_t *usbos_info, dbus_irb_rx_t *rxirb, + uint32 ep_idx) { urb_req_t *req; int ret = DBUS_OK; @@ -909,7 +1027,11 @@ dbus_usbos_recv_urb_submit(usbos_info_t *usbos_info, dbus_irb_rx_t *rxirb, uint3 usb_fill_bulk_urb(req->urb, usbos_info->usb, rx_pipe, p, rxirb->buf_len, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + (void *)dbus_usbos_recv_complete, req); +#else (usb_complete_t)dbus_usbos_recv_complete, req); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) */ req->urb->transfer_flags |= URB_QUEUE_BULK; if ((ret = USB_SUBMIT_URB(req->urb))) { @@ -919,6 +1041,11 @@ dbus_usbos_recv_urb_submit(usbos_info_t *usbos_info, dbus_irb_rx_t *rxirb, uint3 goto fail; } rxposted = atomic_inc_return(&usbos_info->rxposted); +#if defined(BCMDBG) || defined(DBUS_LINUX_HIST) + if (usbos_info->rxposted_hist) { + usbos_info->rxposted_hist[rxposted]++; + } +#endif /* BCMDBG || DBUS_LINUX_HIST */ dbus_usbos_qenq(&usbos_info->req_rxpostedq, req, &usbos_info->rxposted_lock); fail: @@ -926,6 +1053,113 @@ fail: return ret; } /* dbus_usbos_recv_urb_submit */ +#ifdef DBUS_LINUX_RXDPC + +static void +dbus_usbos_recv_dpc(usbos_info_t *usbos_info) +{ + urb_req_t *req = NULL; + dbus_irb_rx_t *rxirb = NULL; + int dbus_status = DBUS_OK; + bool killed = (g_probe_info.suspend_state == USBOS_SUSPEND_STATE_SUSPEND_PENDING) ? 1 : 0; + +#if defined(BCMDBG) || defined(DBUS_LINUX_HIST) + int cnt = 0; + + usbos_info->dpc_cnt++; +#endif /* BCMDBG || DBUS_LINUX_HIST */ + + /* make it bounded if we think it can take too long */ + while ((req = dbus_usbos_qdeq(&usbos_info->req_rxpendingq, + &usbos_info->rxpending_lock)) != NULL) { + struct urb *urb = req->urb; + rxirb = req->arg; + + /* Handle errors */ + if (urb->status) { + /* + * Linux 2.4 disconnect: -ENOENT or -EILSEQ for CRC error; rmmod: -ENOENT + * Linux 2.6 disconnect: -EPROTO, rmmod: -ESHUTDOWN + */ + if ((urb->status == -ENOENT && (!killed)) || urb->status == -ESHUTDOWN) { + /* NOTE: unlink() can not be called from URB callback(). + * Do not call dbusos_stop() here. + */ + dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN); + } else if (urb->status == -EPROTO) { + } else { + DBUSERR(("%s rx error %d\n", __FUNCTION__, urb->status)); + dbus_usbos_errhandler(usbos_info, DBUS_ERR_RXFAIL); + } + + /* On error, don't submit more URBs yet */ + DBUSERR(("%s %d rx error %d\n", __FUNCTION__, __LINE__, urb->status)); + rxirb->buf = NULL; + rxirb->actual_len = 0; + dbus_status = DBUS_ERR_RXFAIL; + goto fail; + } + +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) + /* detach the packet from the req */ + req->pkt = NULL; +#endif + /* Make the skb represent the received urb */ + rxirb->actual_len = urb->actual_length; + +fail: + /* this is just a stats, we don't protect it with locks for now */ + usbos_info->rxpending--; +#if defined(BCMDBG) || defined(DBUS_LINUX_HIST) + cnt++; +#endif /* BCMDBG || DBUS_LINUX_HIST */ + if (usbos_info->cbarg && usbos_info->cbs && + usbos_info->cbs->recv_irb_complete) { + usbos_info->cbs->recv_irb_complete(usbos_info->cbarg, rxirb, dbus_status); + } + dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); + } + +#if defined(BCMDBG) || defined(DBUS_LINUX_HIST) + usbos_info->dpc_pktcnt += cnt; + usbos_info->dpc_maxpktcnt = MAX(cnt, usbos_info->dpc_maxpktcnt); +#endif /* BCMDBG || DBUS_LINUX_HIST */ +#ifdef DBUS_LINUX_HIST + { + static unsigned long last_dump = 0; + + /* dump every 20 sec */ + if (jiffies > (last_dump + 20*HZ)) { + dbus_usbos_intf_dump(usbos_info, NULL); + last_dump = jiffies; + } + } +#endif /* DBUS_LINUX_HIST */ +} /* dbus_usbos_recv_dpc */ + +static int +dbus_usbos_dpc_thread(void *data) +{ + usbos_info_t *usbos_info = (usbos_info_t*)data; + + DAEMONIZE("dbus_rx_dpc"); + /* High priority for short response time. We will yield by ourselves. */ + /* SET_NICE(-10); */ + + /* Run until signal received */ + while (1) { + if (down_interruptible(&usbos_info->dpc_sem) == 0) { + dbus_usbos_recv_dpc(usbos_info); + RESCHED(); + } else + break; + } + + complete_and_exit(&usbos_info->dpc_exited, 0); + return 0; +} + +#endif /* DBUS_LINUX_RXDPC */ /** * Called by worked thread when a 'receive URB' completed or Linux kernel when it returns a URB to @@ -934,6 +1168,37 @@ fail: static void dbus_usbos_recv_complete_handle(urb_req_t *req, int len, int status) { +#ifdef DBUS_LINUX_RXDPC + usbos_info_t *usbos_info = req->usbinfo; + unsigned long flags; + int rxallocated, rxposted; + + spin_lock_irqsave(&usbos_info->rxlock, flags); + /* detach the packet from the queue */ + dbus_usbos_req_del(req, &usbos_info->rxposted_lock); + rxposted = atomic_dec_return(&usbos_info->rxposted); + rxallocated = atomic_read(&usbos_info->rxallocated); + + /* Enqueue to rxpending queue */ + usbos_info->rxpending++; + dbus_usbos_qenq(&usbos_info->req_rxpendingq, req, &usbos_info->rxpending_lock); + spin_unlock_irqrestore(&usbos_info->rxlock, flags); + +#error "RX req/buf appending-mode not verified for DBUS_LINUX_RXDPC because it was disabled" + if ((rxallocated < usbos_info->pub->nrxq) && (!status) && + (rxposted == DBUS_USB_RXQUEUE_LOWER_WATERMARK)) { + DBUSTRACE(("%s: need more rx buf: rxallocated %d rxposted %d!\n", + __FUNCTION__, rxallocated, rxposted)); + dbus_usbos_urbreqs_alloc(usbos_info, + MIN(DBUS_USB_RXQUEUE_BATCH_ADD, + usbos_info->pub->nrxq - rxallocated), TRUE); + } +#error "Please verify above code works if you happened to enable DBUS_LINUX_RXDPC!!" + + /* Wake up dpc for further processing */ + ASSERT(usbos_info->dpc_pid >= 0); + up(&usbos_info->dpc_sem); +#else dbus_irb_rx_t *rxirb = req->arg; usbos_info_t *usbos_info = req->usbinfo; unsigned long flags; @@ -1005,6 +1270,7 @@ fail: } dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); +#endif /* DBUS_LINUX_RXDPC */ /* Mark the interface as busy to reset USB autosuspend timer */ USB_MARK_LAST_BUSY(usbos_info->usb); @@ -1021,7 +1287,6 @@ dbus_usbos_recv_complete(CALLBACK_ARGS) #endif /* USBOS_THREAD */ } - /** * If Linux notifies our driver that a control read or write URB has completed, we should notify * the DBUS layer above us (dbus_usb.c in this case). @@ -1198,6 +1463,9 @@ dbusos_stop(usbos_info_t *usbos_info) ASSERT(usbos_info); +#ifdef USB_TRIGGER_DEBUG + dbus_usbos_ctl_send_debugtrig(usbos_info); +#endif /* USB_TRIGGER_DEBUG */ dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN); dbus_usbos_cancel_all_urbs(usbos_info); @@ -1219,6 +1487,20 @@ dbusos_stop(usbos_info_t *usbos_info) ASSERT(atomic_read(&usbos_info->txposted) == 0 && rxposted == 0); +#ifdef DBUS_LINUX_RXDPC + /* Stop the dpc thread */ + if (usbos_info->dpc_pid >= 0) { + KILL_PROC(usbos_info->dpc_pid, SIGTERM); + wait_for_completion(&usbos_info->dpc_exited); + } + + /* Move pending reqs to free queue so they can be freed */ + while ((req = dbus_usbos_qdeq(&usbos_info->req_rxpendingq, + &usbos_info->rxpending_lock)) != NULL) { + dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, + &usbos_info->rxfree_lock); + } +#endif /* DBUS_LINUX_RXDPC */ } /* dbusos_stop */ #if defined(USB_SUSPEND_AVAILABLE) @@ -1233,26 +1515,46 @@ static int dbus_usbos_suspend(struct usb_interface *intf, pm_message_t message) { - DBUSERR(("%s suspend state: %d\n", __FUNCTION__, g_probe_info.suspend_state)); + usbos_info_t *usbos_info = (usbos_info_t *) g_probe_info.usbos_info; + int err = 0; + + printf("%s Enter\n", __FUNCTION__); + /* DHD for full dongle model */ g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPEND_PENDING; - dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_SLEEP); + if (drvinfo.suspend && disc_arg) + err = drvinfo.suspend(disc_arg); + if (err) { + printf("%s: err=%d\n", __FUNCTION__, err); +// g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; +// return err; + } + usbos_info->pub->busstate = DBUS_STATE_SLEEP; + dbus_usbos_cancel_all_urbs((usbos_info_t*)g_probe_info.usbos_info); g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPENDED; - return 0; + printf("%s Exit err=%d\n", __FUNCTION__, err); + return err; } /** * The resume method is called to tell the driver that the device has been resumed and the driver * can return to normal operation. URBs may once more be submitted. */ -static int dbus_usbos_resume(struct usb_interface *intf) +static int +dbus_usbos_resume(struct usb_interface *intf) { - DBUSERR(("%s Device resumed\n", __FUNCTION__)); + usbos_info_t *usbos_info = (usbos_info_t *) g_probe_info.usbos_info; + + printf("%s Enter\n", __FUNCTION__); - dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_UP); g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; + if (drvinfo.resume && disc_arg) + drvinfo.resume(disc_arg); + usbos_info->pub->busstate = DBUS_STATE_UP; + + printf("%s Exit\n", __FUNCTION__); return 0; } @@ -1260,13 +1562,24 @@ static int dbus_usbos_resume(struct usb_interface *intf) * This function is directly called by the Linux kernel, when the suspended device has been reset * instead of being resumed */ -static int dbus_usbos_reset_resume(struct usb_interface *intf) +static int +dbus_usbos_reset_resume(struct usb_interface *intf) { - DBUSERR(("%s Device reset resumed\n", __FUNCTION__)); + printf("%s Enter\n", __FUNCTION__); - /* The device may have lost power, so a firmware download may be required */ - dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_DL_NEEDED); - g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; +#ifdef KEEPIF_ON_DEVICE_RESET + if (g_probe_info.keepif_on_devreset) { + atomic_set(&g_probe_info.usbdev_stat, USB_DEVICE_RESETTED); + wake_up_interruptible(&g_probe_info.usbreset_queue_head); + } else +#endif /* KEEPIF_ON_DEVICE_RESET */ + { + g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; + if (drvinfo.resume && disc_arg) + drvinfo.resume(disc_arg); + } + + printf("%s Exit\n", __FUNCTION__); return 0; } @@ -1310,6 +1623,7 @@ DBUS_USBOS_PROBE() usb->portnum, WIFI_STATUS_POWER_ON); if (adapter == NULL) { DBUSERR(("%s: can't find adapter info for this chip\n", __FUNCTION__)); + ret = -ENOMEM; goto fail; } @@ -1555,8 +1869,14 @@ DBUS_USBOS_PROBE() g_probe_info.device_speed = FULL_SPEED; DBUSERR(("full speed device detected\n")); } - if (g_probe_info.dereged == FALSE && probe_cb) { - disc_arg = probe_cb(probe_arg, "", USB_BUS, usb->bus->busnum, usb->portnum, 0); +#ifdef KEEPIF_ON_DEVICE_RESET + if (g_probe_info.keepif_on_devreset && g_probe_info.dev_resetted) { + atomic_set(&g_probe_info.usbdev_stat, USB_DEVICE_PROBED); + wake_up_interruptible(&g_probe_info.usbreset_queue_head); + } else +#endif /* KEEPIF_ON_DEVICE_RESET */ + if (g_probe_info.dereged == FALSE && drvinfo.probe) { + disc_arg = drvinfo.probe(usb->bus->busnum, usb->portnum, 0); } g_probe_info.disc_cb_done = FALSE; @@ -1617,10 +1937,17 @@ DBUS_USBOS_DISCONNECT() if (probe_usb_init_data) { usbos_info = (usbos_info_t *) probe_usb_init_data->usbos_info; if (usbos_info) { - if ((probe_usb_init_data->dereged == FALSE) && disconnect_cb && disc_arg) { - disconnect_cb(disc_arg); - disc_arg = NULL; - probe_usb_init_data->disc_cb_done = TRUE; + if ((probe_usb_init_data->dereged == FALSE) && drvinfo.remove && disc_arg) { + bool remove_if = TRUE; +#ifdef KEEPIF_ON_DEVICE_RESET + if (g_probe_info.keepif_on_devreset) + remove_if = FALSE; +#endif /* KEEPIF_ON_DEVICE_RESET */ + if (remove_if) { + drvinfo.remove(disc_arg); + disc_arg = NULL; + probe_usb_init_data->disc_cb_done = TRUE; + } } } } @@ -1635,6 +1962,14 @@ DBUS_USBOS_DISCONNECT() usb_dec_dev_use(usb); #endif /* !KERNEL26 */ } + +#ifdef KEEPIF_ON_DEVICE_RESET + if (g_probe_info.keepif_on_devreset && (!g_probe_info.dev_resetted)) { + atomic_set(&g_probe_info.usbdev_stat, USB_DEVICE_DISCONNECTED); + wake_up_interruptible(&g_probe_info.usbreset_queue_head); + } +#endif /* KEEPIF_ON_DEVICE_RESET */ + DHD_MUTEX_UNLOCK(); } /* dbus_usbos_disconnect */ @@ -1805,7 +2140,11 @@ dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb) req_zlp->buf_len = 0; usb_fill_bulk_urb(req_zlp->urb, usbos_info->usb, usbos_info->tx_pipe, NULL, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + 0, (void *)dbus_usbos_send_complete, req_zlp); +#else 0, (usb_complete_t)dbus_usbos_send_complete, req_zlp); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) */ req_zlp->urb->transfer_flags |= URB_QUEUE_BULK; } @@ -1860,7 +2199,11 @@ dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb) } usb_fill_bulk_urb(req->urb, usbos_info->usb, usbos_info->tx_pipe, buf, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + buffer_length, (void *)dbus_usbos_send_complete, req); +#else buffer_length, (usb_complete_t)dbus_usbos_send_complete, req); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) */ req->urb->transfer_flags |= URB_QUEUE_BULK; @@ -1908,7 +2251,6 @@ dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb) fail: if (txirb->send_buf != NULL) { MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len); - txirb->send_buf = NULL; req->buf_len = 0; } dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); @@ -1982,6 +2324,7 @@ dbus_usbos_intf_cancel_irb(void *bus, dbus_irb_tx_t *txirb) if (usbos_info == NULL) return DBUS_ERR; + /* : Need to implement */ return DBUS_ERR; } @@ -2025,7 +2368,11 @@ dbus_usbos_intf_send_ctl(void *bus, uint8 *buf, int len) usbos_info->usb, usb_sndctrlpipe(usbos_info->usb, 0), (unsigned char *) &usbos_info->ctl_write, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + buf, size, (void *)dbus_usbos_ctlwrite_complete, usbos_info); +#else buf, size, (usb_complete_t)dbus_usbos_ctlwrite_complete, usbos_info); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) */ #ifdef USBOS_TX_THREAD /* Enqueue CTRL request for transmission by the TX thread. The @@ -2090,7 +2437,11 @@ dbus_usbos_intf_recv_ctl(void *bus, uint8 *buf, int len) usbos_info->usb, usb_rcvctrlpipe(usbos_info->usb, 0), (unsigned char *) &usbos_info->ctl_read, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + buf, size, (void *)dbus_usbos_ctlread_complete, usbos_info); +#else buf, size, (usb_complete_t)dbus_usbos_ctlread_complete, usbos_info); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) */ status = USB_SUBMIT_URB(usbos_info->ctl_urb); if (status < 0) { @@ -2118,6 +2469,10 @@ dbus_usbos_intf_get_attrib(void *bus, dbus_attrib_t *attrib) attrib->pid = g_probe_info.pid; attrib->devid = 0x4322; + /* : Need nchan for both TX and RX?; + * BDC uses one RX pipe and one TX pipe + * RPC may use two RX pipes and one TX pipe? + */ attrib->nchan = 1; /* MaxPacketSize for USB hi-speed bulk out is 512 bytes @@ -2160,7 +2515,7 @@ dbus_usbos_intf_up(void *bus) return DBUS_ERR; } } -#endif +#endif /* INTR_EP_ENABLE */ if (usbos_info->ctl_urb) { usbos_info->ctl_in_pipe = usb_rcvctrlpipe(usbos_info->usb, 0); @@ -2217,6 +2572,90 @@ dbus_usbos_intf_stop(void *bus) return DBUS_OK; } +#if defined(BCMDBG) || defined(DBUS_LINUX_HIST) +static void +dbus_usbos_intf_dump(void *bus, struct bcmstrbuf *b) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + int i = 0, j = 0, rxposted, txposted; + + rxposted = atomic_read(&usbos_info->rxposted); + txposted = atomic_read(&usbos_info->txposted); + if (b) { + bcm_bprintf(b, "\ndbus linux dump\n"); + bcm_bprintf(b, "txposted %d rxposted %d\n", + txposted, rxposted); + + bcm_bprintf(b, "RXDPC: dpc_cnt %d dpc_pktcnt %d dpc_maxpktcnt %d avg_dpc_pktcnt\n", + usbos_info->dpc_cnt, usbos_info->dpc_pktcnt, + usbos_info->dpc_maxpktcnt, usbos_info->dpc_cnt ? + (usbos_info->dpc_pktcnt/usbos_info->dpc_cnt):1); + + /* Histogram */ + bcm_bprintf(b, "txposted\n"); + } else { + printf("\ndbus linux dump\n"); + printf("txposted %d rxposted %d\n", + txposted, rxposted); + printf("RXDPC: dpc_cnt %d dpc_pktcnt %d dpc_maxpktcnt %d avg_dpc_pktcnt %d\n", + usbos_info->dpc_cnt, usbos_info->dpc_pktcnt, + usbos_info->dpc_maxpktcnt, usbos_info->dpc_cnt ? + (usbos_info->dpc_pktcnt/usbos_info->dpc_cnt):1); + + /* Histogram */ + printf("txposted\n"); + } + + for (i = 0; i < usbos_info->pub->ntxq; i++) { + if (usbos_info->txposted_hist == NULL) { + break; + } + if (usbos_info->txposted_hist[i]) { + if (b) + bcm_bprintf(b, "%d: %d ", i, usbos_info->txposted_hist[i]); + else + printf("%d: %d ", i, usbos_info->txposted_hist[i]); + j++; + if (j % 10 == 0) { + if (b) + bcm_bprintf(b, "\n"); + else + printf("\n"); + } + } + } + + j = 0; + if (b) + bcm_bprintf(b, "\nrxposted\n"); + else + printf("\nrxposted\n"); + for (i = 0; i < usbos_info->pub->nrxq; i++) { + if (usbos_info->rxposted_hist == NULL) { + break; + } + if (usbos_info->rxposted_hist[i]) { + if (b) + bcm_bprintf(b, "%d: %d ", i, usbos_info->rxposted_hist[i]); + else + printf("%d: %d ", i, usbos_info->rxposted_hist[i]); + j++; + if (j % 10 == 0) { + if (b) + bcm_bprintf(b, "\n"); + else + printf("\n"); + } + } + } + if (b) + bcm_bprintf(b, "\n"); + else + printf("\n"); + + return; +} +#endif /* BCMDBG || DBUS_LINUX_HIST */ /** Called by higher layer (dbus_usb.c) */ static int @@ -2228,9 +2667,18 @@ dbus_usbos_intf_set_config(void *bus, dbus_config_t *config) if (config->config_id == DBUS_CONFIG_ID_RXCTL_DEFERRES) { usbos_info->rxctl_deferrespok = config->rxctl_deferrespok; err = DBUS_OK; - } else if (config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) { + } +#ifdef KEEPIF_ON_DEVICE_RESET + else if (config->config_id == DBUS_CONFIG_ID_KEEPIF_ON_DEVRESET) { + g_probe_info.keepif_on_devreset = config->general_param ? TRUE : FALSE; + err = DBUS_OK; + } +#endif /* KEEPIF_ON_DEVICE_RESET */ + else if (config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) { +#ifndef BCM_FD_AGGR /* DBUS_CONFIG_ID_AGGR_LIMIT shouldn't be called after probe stage */ ASSERT(disc_arg == NULL); +#endif /* BCM_FD_AGGR */ ASSERT(config->aggr_param.maxrxsf > 0); ASSERT(config->aggr_param.maxrxsize > 0); if (config->aggr_param.maxrxsize > usbos_info->rxbuf_len) { @@ -2250,6 +2698,33 @@ dbus_usbos_intf_set_config(void *bus, dbus_config_t *config) return err; } +#ifdef EHCI_FASTPATH_TX + +/** + * In some cases, the code must submit an URB and wait for its completion. + * Related: dbus_usbos_sync_complete() + */ +static int +dbus_usbos_sync_wait(usbos_info_t *usbinfo, uint16 time) +{ + int ret; + int err = DBUS_OK; + int ms = time; + + ret = wait_event_interruptible_timeout(usbinfo->wait, + usbinfo->waitdone == TRUE, (ms * HZ / 1000)); + + if ((usbinfo->waitdone == FALSE) || (usbinfo->sync_urb_status)) { + DBUSERR(("%s: timeout(%d) or urb err=0x%x\n", + __FUNCTION__, ret, usbinfo->sync_urb_status)); + err = DBUS_ERR; + BCM_REFERENCE(ret); + } + usbinfo->waitdone = FALSE; + return err; +} + +#endif /* EHCI_FASTPATH_TX */ /** Called by dbus_usb.c when it wants to download firmware into the dongle */ bool @@ -2262,6 +2737,9 @@ dbus_usbos_dl_cmd(usbos_info_t *usbinfo, uint8 cmd, void *buffer, int buflen) if ((usbinfo == NULL) || (buffer == NULL) || (buflen == 0)) return FALSE; + /* PR82642: Input buffer on stack is causing failures + * on some platforms (STB boxes) + */ tmpbuf = (char *) MALLOC(usbinfo->pub->osh, buflen); if (!tmpbuf) { DBUSERR(("%s: Unable to allocate memory \n", __FUNCTION__)); @@ -2269,6 +2747,7 @@ dbus_usbos_dl_cmd(usbos_info_t *usbinfo, uint8 cmd, void *buffer, int buflen) } #ifdef BCM_REQUEST_FW + /* Adopted from Windows layer dbus_usb_ndis.c to support USB3.0 core */ if (cmd == DL_GO) { index = 1; } @@ -2294,7 +2773,7 @@ dbus_usbos_dl_cmd(usbos_info_t *usbinfo, uint8 cmd, void *buffer, int buflen) } /** - * Called by dbus_usb.c when it wants to download a buffer into the dongle (e.g. as part of the + * Called by dbus_usb.c when it wants to download a buffer into the dongle (eg as part of the * download process, when writing nvram variables). */ int @@ -2354,7 +2833,7 @@ err: USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); return retval; -} +} /* dbus_write_membytes */ int dbus_usbos_readreg(void *bus, uint32 regaddr, int datalen, uint32 *value) @@ -2392,7 +2871,7 @@ dbus_usbos_readreg(void *bus, uint32 regaddr, int datalen, uint32 *value) USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); return ret; -} +} /* dbus_usbos_readreg */ int dbus_usbos_writereg(void *bus, uint32 regaddr, int datalen, uint32 data) @@ -2432,6 +2911,7 @@ int dbus_usbos_wait(usbos_info_t *usbinfo, uint16 ms) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + /* : Need to test under 2.6 kernel */ if (in_interrupt()) mdelay(ms); else @@ -2446,6 +2926,24 @@ dbus_usbos_wait(usbos_info_t *usbinfo, uint16 ms) bool dbus_usbos_dl_send_bulk(usbos_info_t *usbinfo, void *buffer, int len) { +#ifdef EHCI_FASTPATH_TX + int ret = DBUS_ERR; + + struct ehci_qtd *qtd = optimize_ehci_qtd_alloc(GFP_KERNEL); + int token = EHCI_QTD_SET_CERR(3); + + if (qtd == NULL) + goto fail; + + optimize_qtd_fill_with_data(usbinfo->pub, 0, qtd, buffer, token, len); + optimize_submit_async(qtd, 0); + + ret = dbus_usbos_sync_wait(usbinfo, USB_SYNC_WAIT_TIMEOUT); + + return (ret == DBUS_OK); +fail: + return FALSE; +#else bool ret = TRUE; int status; int transferred = 0; @@ -2467,6 +2965,7 @@ dbus_usbos_dl_send_bulk(usbos_info_t *usbinfo, void *buffer, int len) USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); return ret; +#endif /* EHCI_FASTPATH_TX */ } static bool @@ -2555,22 +3054,24 @@ dbus_usbos_state_change(void *bus, int state) } int -dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, - disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2) +dbus_bus_osl_register(dbus_driver_t *driver, dbus_intf_t **intf) { bzero(&g_probe_info, sizeof(probe_info_t)); - probe_cb = prcb; - disconnect_cb = discb; - probe_arg = prarg; - - devid_table[0].idVendor = vid; - devid_table[0].idProduct = pid; - + drvinfo = *driver; *intf = &dbus_usbos_intf; USB_REGISTER(); +#ifdef KEEPIF_ON_DEVICE_RESET + init_waitqueue_head(&g_probe_info.usbreset_queue_head); + atomic_set(&g_probe_info.usbdev_stat, USB_DEVICE_INIT); + g_probe_info.usbreset_kt = kthread_create(dbus_usbos_usbreset_func, + &g_probe_info, "usbreset-thread"); + ASSERT(!IS_ERR(g_probe_info.usbreset_kt)); + wake_up_process(g_probe_info.usbreset_kt); +#endif /* KEEPIF_ON_DEVICE_RESET */ + return DBUS_ERR_NODEVICE; } @@ -2580,8 +3081,13 @@ dbus_bus_osl_deregister() g_probe_info.dereged = TRUE; DHD_MUTEX_LOCK(); - if (disconnect_cb && disc_arg && (g_probe_info.disc_cb_done == FALSE)) { - disconnect_cb(disc_arg); +#ifdef KEEPIF_ON_DEVICE_RESET + wake_up_interruptible(&g_probe_info.usbreset_queue_head); + kthread_stop(g_probe_info.usbreset_kt); +#endif /* KEEPIF_ON_DEVICE_RESET */ + + if (drvinfo.remove && disc_arg && (g_probe_info.disc_cb_done == FALSE)) { + drvinfo.remove(disc_arg); disc_arg = NULL; } DHD_MUTEX_UNLOCK(); @@ -2591,6 +3097,41 @@ dbus_bus_osl_deregister() return DBUS_OK; } +static void +dbus_usbos_init_info(void) +{ + usbos_info_t *usbos_info = g_probe_info.usbos_info; + + if (!usbos_info) { + return; + } + + /* Update USB Info */ + usbos_info->usb = g_probe_info.usb; + usbos_info->rx_pipe = g_probe_info.rx_pipe; + usbos_info->rx_pipe2 = g_probe_info.rx_pipe2; + usbos_info->tx_pipe = g_probe_info.tx_pipe; + usbos_info->intr_pipe = g_probe_info.intr_pipe; + usbos_info->intr_size = g_probe_info.intr_size; + usbos_info->interval = g_probe_info.interval; + usbos_info->pub->device_speed = g_probe_info.device_speed; + usbos_info->pub->dev_info = g_probe_info.usb; + if (usbos_info->rx_pipe2) { + usbos_info->pub->attrib.has_2nd_bulk_in_ep = 1; + } else { + usbos_info->pub->attrib.has_2nd_bulk_in_ep = 0; + } + + if (usbos_info->tx_pipe) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0)) + usbos_info->maxps = usb_maxpacket(usbos_info->usb, + usbos_info->tx_pipe); +#else + usbos_info->maxps = usb_maxpacket(usbos_info->usb, + usbos_info->tx_pipe, usb_pipeout(usbos_info->tx_pipe)); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0) */ +} + void * dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs) { @@ -2616,25 +3157,7 @@ dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs) /* Needed for disconnect() */ g_probe_info.usbos_info = usbos_info; - - /* Update USB Info */ - usbos_info->usb = g_probe_info.usb; - usbos_info->rx_pipe = g_probe_info.rx_pipe; - usbos_info->rx_pipe2 = g_probe_info.rx_pipe2; - usbos_info->tx_pipe = g_probe_info.tx_pipe; - usbos_info->intr_pipe = g_probe_info.intr_pipe; - usbos_info->intr_size = g_probe_info.intr_size; - usbos_info->interval = g_probe_info.interval; - usbos_info->pub->device_speed = g_probe_info.device_speed; - if (usbos_info->rx_pipe2) { - usbos_info->pub->attrib.has_2nd_bulk_in_ep = 1; - } else { - usbos_info->pub->attrib.has_2nd_bulk_in_ep = 0; - } - - if (usbos_info->tx_pipe) - usbos_info->maxps = usb_maxpacket(usbos_info->usb, - usbos_info->tx_pipe, usb_pipeout(usbos_info->tx_pipe)); + dbus_usbos_init_info(); INIT_LIST_HEAD(&usbos_info->req_rxfreeq); INIT_LIST_HEAD(&usbos_info->req_txfreeq); @@ -2650,8 +3173,23 @@ dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs) atomic_set(&usbos_info->rxposted, 0); atomic_set(&usbos_info->txposted, 0); +#ifdef DBUS_LINUX_RXDPC + INIT_LIST_HEAD(&usbos_info->req_rxpendingq); + spin_lock_init(&usbos_info->rxpending_lock); +#endif /* DBUS_LINUX_RXDPC */ +#if defined(BCMDBG) || defined(DBUS_LINUX_HIST) + usbos_info->txposted_hist = MALLOC(pub->osh, (usbos_info->pub->ntxq+1) * sizeof(int)); + if (usbos_info->txposted_hist) { + bzero(usbos_info->txposted_hist, (usbos_info->pub->ntxq+1) * sizeof(int)); + } + usbos_info->rxposted_hist = MALLOC(pub->osh, (usbos_info->pub->nrxq+1) * sizeof(int)); + if (usbos_info->rxposted_hist) { + bzero(usbos_info->rxposted_hist, (usbos_info->pub->nrxq+1) * sizeof(int)); + } +#endif #ifdef USB_DISABLE_INT_EP + /* PR 82639 Don't use interrupt EP */ usbos_info->intr_urb = NULL; #else if (!(usbos_info->intr_urb = USB_ALLOC_URB())) { @@ -2674,7 +3212,15 @@ dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs) usbos_info->rxbuf_len = (uint)usbos_info->pub->rxsize; - +#ifdef DBUS_LINUX_RXDPC /* Initialize DPC thread */ + sema_init(&usbos_info->dpc_sem, 0); + init_completion(&usbos_info->dpc_exited); + usbos_info->dpc_pid = kernel_thread(dbus_usbos_dpc_thread, usbos_info, 0); + if (usbos_info->dpc_pid < 0) { + DBUSERR(("%s: failed to create dpc thread\n", __FUNCTION__)); + goto fail; + } +#endif /* DBUS_LINUX_RXDPC */ atomic_set(&usbos_info->txallocated, 0); if (DBUS_OK != dbus_usbos_urbreqs_alloc(usbos_info, @@ -2684,7 +3230,11 @@ dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs) atomic_set(&usbos_info->rxallocated, 0); if (DBUS_OK != dbus_usbos_urbreqs_alloc(usbos_info, +#ifdef CTFPOOL + usbos_info->pub->nrxq, +#else MIN(DBUS_USB_RXQUEUE_BATCH_ADD, usbos_info->pub->nrxq), +#endif TRUE)) { goto fail; } @@ -2701,11 +3251,24 @@ dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs) goto fail; #endif /* USBOS_TX_THREAD */ - pub->dev_info = g_probe_info.usb; +#if defined(EHCI_FASTPATH_TX) || defined(EHCI_FASTPATH_RX) + spin_lock_init(&usbos_info->fastpath_lock); + if (optimize_init(usbos_info, usbos_info->usb, usbos_info->tx_pipe, + usbos_info->rx_pipe, usbos_info->rx_pipe2) != 0) { + DBUSERR(("%s: optimize_init failed!\n", __FUNCTION__)); + goto fail; + } +#endif /* EHCI_FASTPATH_TX || EHCI_FASTPATH_RX */ return (void *) usbos_info; fail: +#ifdef DBUS_LINUX_RXDPC + if (usbos_info->dpc_pid >= 0) { + KILL_PROC(usbos_info->dpc_pid, SIGTERM); + wait_for_completion(&usbos_info->dpc_exited); + } +#endif /* DBUS_LINUX_RXDPC */ if (usbos_info->intr_urb) { USB_FREE_URB(usbos_info->intr_urb); usbos_info->intr_urb = NULL; @@ -2716,7 +3279,7 @@ fail: usbos_info->ctl_urb = NULL; } -#if defined(BCM_REQUEST_FW) +#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) if (usbos_info->blk_urb) { USB_FREE_URB(usbos_info->blk_urb); usbos_info->blk_urb = NULL; @@ -2748,6 +3311,9 @@ dbus_usbos_intf_detach(dbus_pub_t *pub, void *info) dbus_usbos_tx_thread_deinit(usbos_info); #endif /* USBOS_TX_THREAD */ +#if defined(EHCI_FASTPATH_TX) || defined(EHCI_FASTPATH_RX) + optimize_deinit(usbos_info, usbos_info->usb); +#endif /* Must unlink all URBs prior to driver unload; * otherwise an URB callback can occur after driver * has been de-allocated and rmmod'd @@ -2774,6 +3340,14 @@ dbus_usbos_intf_detach(dbus_pub_t *pub, void *info) dbus_usbos_urbreqs_free(usbos_info, FALSE); atomic_set(&usbos_info->txallocated, 0); +#if defined(BCMDBG) || defined(DBUS_LINUX_HIST) + if (usbos_info->txposted_hist) { + MFREE(osh, usbos_info->txposted_hist, (usbos_info->pub->ntxq+1) * sizeof(int)); + } + if (usbos_info->rxposted_hist) { + MFREE(osh, usbos_info->rxposted_hist, (usbos_info->pub->nrxq+1) * sizeof(int)); + } +#endif /* BCMDBG || DBUS_LINUX_HIST */ #ifdef USBOS_THREAD dbus_usbos_thread_deinit(usbos_info); #endif /* USBOS_THREAD */ @@ -2782,7 +3356,6 @@ dbus_usbos_intf_detach(dbus_pub_t *pub, void *info) MFREE(osh, usbos_info, sizeof(usbos_info_t)); } /* dbus_usbos_intf_detach */ - #ifdef USBOS_TX_THREAD void* @@ -2907,7 +3480,6 @@ dbus_usbos_tx_thread_func(void *data) txirb = req->arg; if (txirb->send_buf) { MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len); - txirb->send_buf = NULL; req->buf_len = 0; } @@ -2938,13 +3510,11 @@ dbus_usbos_thread_init(usbos_info_t *usbos_info) unsigned long flags, ii; spin_lock_init(&usbos_info->usbos_list_lock); - spin_lock_init(&usbos_info->ctrl_lock); INIT_LIST_HEAD(&usbos_info->usbos_list); INIT_LIST_HEAD(&usbos_info->usbos_free_list); init_waitqueue_head(&usbos_info->usbos_queue_head); atomic_set(&usbos_info->usbos_list_cnt, 0); - for (ii = 0; ii < (usbos_info->pub->nrxq + usbos_info->pub->ntxq); ii++) { entry = MALLOC(usbos_info->pub->osh, sizeof(usbos_list_entry_t)); if (entry) { @@ -2980,10 +3550,7 @@ dbus_usbos_thread_deinit(usbos_info_t *usbos_info) wake_up_interruptible(&usbos_info->usbos_queue_head); kthread_stop(usbos_info->usbos_kt); } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_safe(cur, next, &usbos_info->usbos_list) { entry = list_entry(cur, struct usbos_list_entry, list); @@ -3003,9 +3570,7 @@ dbus_usbos_thread_deinit(usbos_info_t *usbos_info) MFREE(usbos_info->pub->osh, entry, sizeof(usbos_list_entry_t)); spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif + GCC_DIAGNOSTIC_POP(); } /** Process completed URBs in a worker thread */ @@ -3036,10 +3601,7 @@ dbus_usbos_thread_func(void *data) /* For each entry on the list, process it. Remove the entry from * the list when done. */ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_safe(cur, next, &usbos_info->usbos_list) { urb_req_t *req; @@ -3072,9 +3634,7 @@ dbus_usbos_thread_func(void *data) spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif + GCC_DIAGNOSTIC_POP(); return 0; } /* dbus_usbos_thread_func */ @@ -3092,14 +3652,9 @@ dbus_usbos_dispatch_schedule(CALLBACK_ARGS) spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); cur = usbos_info->usbos_free_list.next; -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); entry = list_entry(cur, struct usbos_list_entry, list); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif + GCC_DIAGNOSTIC_POP(); /* detach this entry from the free list and prepare it insert it to use list */ list_del_init(cur); @@ -3123,8 +3678,823 @@ dbus_usbos_dispatch_schedule(CALLBACK_ARGS) #endif /* USBOS_THREAD */ +#ifdef USB_TRIGGER_DEBUG +static bool +dbus_usbos_ctl_send_debugtrig(usbos_info_t* usbinfo) +{ + bootrom_id_t id; + if (usbinfo == NULL) + return FALSE; + id.chip = 0xDEAD; + + dbus_usbos_dl_cmd(usbinfo, DL_DBGTRIG, &id, sizeof(bootrom_id_t)); + + /* ignore the result for now */ + return TRUE; +} +#endif /* USB_TRIGGER_DEBUG */ + +#if defined(EHCI_FASTPATH_TX) || defined(EHCI_FASTPATH_RX) + +/** New optimized code for USB AP. EHCI fastpath specific function. */ +void inline optimize_ehci_qtd_init(struct ehci_qtd *qtd, dma_addr_t dma) +{ + bzero(qtd, sizeof(*qtd)); + wmb(); + qtd->qtd_self = dma; + qtd->qtd_status = cpu_to_le32(EHCI_QTD_HALTED); + qtd->qtd_next = EHCI_NULL; + qtd->qtd_altnext = EHCI_NULL; + qtd->obj_next = NULL; + qtd->rpc = NULL; + /* qtd->buff = NULL; */ + qtd->xacterrs = EHCI_QTD_XACTERR_MAX; + wmb(); +} + +/** EHCI fastpath specific function */ +struct ehci_qtd *optimize_ehci_qtd_alloc(gfp_t flags) +{ + struct ehci_qtd *qtd; + dma_addr_t dma; + + usbos_info_t *usbos_info = g_probe_info.usbos_info; + + struct dma_pool *pool = usbos_info->qtd_pool; + + qtd = dma_pool_alloc(pool, flags, &dma); + if (qtd != NULL) { + /* ME: Only clear the necessary fields: + * - hw + * - chain of QTDs in mapped space + */ + optimize_ehci_qtd_init(qtd, dma); + } + + return qtd; +} + +/** EHCI fastpath specific function */ +void optimize_ehci_qtd_free(struct ehci_qtd *qtd) +{ + usbos_info_t *usbos_info = g_probe_info.usbos_info; + struct dma_pool *pool = usbos_info->qtd_pool; + dma_pool_free(pool, qtd, qtd->qtd_self); +} + +/** + * EHCI fastpath specific function. Loosely follows qtd_copy_status + * Greatly simplified as there are only three options: normal, short read, and disaster + */ +static int +get_qtd_status(struct ehci_qtd *qtd, int token, int *actual_length) +{ + int status = -EINPROGRESS; + + *actual_length += qtd->length - EHCI_QTD_GET_BYTES(token); + + /* Short read is not an error */ + if (unlikely (SHORT_READ_Q (token))) + status = -EREMOTEIO; + + /* Check for serious problems */ + if (token & EHCI_QTD_HALTED) { + status = -EPROTO; + if (token & (EHCI_QTD_BABBLE | EHCI_QTD_MISSEDMICRO | EHCI_QTD_BUFERR | + EHCI_QTD_XACTERR)) + printk("EHCI Fastpath: Serious USB issue qtd %p token %08x --> status %d\n", + qtd, token, status); + } + + return status; +} + +/** This only works in the BCM embedded world (code uses primitive address mapping) */ +static void dump_qtd(struct ehci_qtd *qtd) +{ + printk("qtd_next %08x qtd_altnext %08x qtd_status %08x\n", qtd->qtd_next, + qtd->qtd_altnext, qtd->qtd_status); +} + +static void dump_qh(struct ehci_qh *qh) +{ + struct ehci_qtd *qtd = (struct ehci_qtd *)(qh->qh_curqtd | 0xa0000000); + printk("EHCI Fastpath: QH %p Dump\n", qh); + printk("qtd_next %08x info1 %08x info2 %08x current %08x\n", qh->qh_link, qh->qh_endp, + qh->qh_endphub, qh->qh_curqtd); + printk("overlay\n"); + dump_qtd((struct ehci_qtd *)&qh->ow_next); + while ((((int)qtd)&EHCI_NULL) == 0) + { + printk("QTD %p\n", qtd); + dump_qtd((struct ehci_qtd *)qtd); + qtd = (struct ehci_qtd *)(qtd->qtd_next | 0xa0000000); + } +} + +/** + * EHCI fastpath specific function. + * This code assumes the caller holding a lock + * It is currently called from scan_async that should have the lock + * Lock shall be dropped around the actual completion, then reacquired + * This is a clean implementation of the qh_completions() + */ +static void +ehci_bypass_callback(int pipeindex, struct ehci_qh *qh, spinlock_t *lock) +{ + /* Loop variables */ + struct ehci_qtd *qtd, /* current QTD */ + *end = qh->dummy, /* "afterend" */ + *next; + int stopped; + + /* ME: Obtain the same info in cleaner way */ + usbos_info_t *usbos_info = g_probe_info.usbos_info; + + /* printk("EHCI Fastpath: callback pipe %d QH %p lock %p\n", pipeindex, qh, lock); */ + + /* + * This code should not require any interlocking with QTD additions + * The additions never touch QH, we should never touch 'end' + * Note that QTD additions will keep 'end' in place + */ + for (qtd = qh->first_qtd; qtd != end; qtd = next) + { + u32 status; /* Status bits from QTD */ + + /* Get the status bits from the QTD */ + rmb(); + status = hc32_to_cpu(qtd->qtd_status); + + if ((status & EHCI_QTD_ACTIVE) == 0) { + if (unlikely((status & EHCI_QTD_HALTED) != 0)) { + /* Retry transaction errors until we + * reach the software xacterr limit + */ + if ((status & EHCI_QTD_XACTERR) && + EHCI_QTD_GET_CERR(status) == 0 && + --qtd->xacterrs > 0) { + /* Reset the token in the qtd and the + * qh overlay (which still contains + * the qtd) so that we pick up from + * where we left off + */ + printk("EHCI Fastpath: detected XactErr " + "qtd %p len %d/%d retry %d\n", + qtd, qtd->length - EHCI_QTD_GET_BYTES(status), + qtd->length, + EHCI_QTD_XACTERR_MAX - qtd->xacterrs); + + status &= ~EHCI_QTD_HALTED; + status |= EHCI_QTD_ACTIVE | EHCI_QTD_SET_CERR(3); + qtd->qtd_status = cpu_to_le32(status); + wmb(); + qh->ow_status = cpu_to_le32(status); + + break; + } + + /* QTD processing was aborted - highly unlikely (never seen, so not + * tested). In very new 2.6, we can retry. In 2.4 and older 2.6, + * life sucks (the USB stack does the same) + */ + printk("EHCI Fastpath: QTD halted\n"); + dump_qh(qh); + stopped = 1; + } + } else { + /* Inactive QTD is an afterend, finished the list */ + break; + } + + /* Remove the QTD from software QH. This should be done before dropping the lock + * in for upper layer + */ + next = qtd->obj_next; + qh->first_qtd = next; + + /* Upper layer processing. */ + if (EHCI_QTD_GET_PID(status) == 0) /* OUT (host->dongle) pipe */ + { + if (qtd->rpc == NULL) + { + /* Download, just signal completion + * ME: Use non-global OS handle + * Code from dbus_usbos_sync_complete + */ + usbos_info->waitdone = TRUE; + wake_up_interruptible(&usbos_info->wait); + /* ME: Set to meaningful status */ + usbos_info->sync_urb_status = 0; + } else { + /* RPC packet handling + * First, relevant processing from dbus_if_send_irb_complete: + * ME: Check for bus state here + */ + + /* Now propagate to the RPC layer from dbus_usbos_send_complete: + * usbos_info->cbs->send_irb_complete(usbos_info->cbarg, + * txirb, status); + */ + + /* From dbus_usb_send_irb_complete: */ + + /* usb_info_t *usb_info = (usb_info_t *) handle; */ + usb_info_t *usb_info = (usb_info_t *) usbos_info->cbarg; + /* if(usb_info && usb_info->cbs && usb_info->cbs->send_irb_complete) + * usb_info->cbs->send_irb_complete(usb_info->cbarg, txirb, status); + */ + + /* From dbus_if_send_irb_complete + * dbus_info_t *dbus_info = (dbus_info_t *) handle; + */ + dbus_info_t *dbus_info = (dbus_info_t *)usb_info->cbarg; + /* printk("RPC send completed %p %p %p\n", usbos_info, + * usb_info, dbus_info); + * dbus_tx_timer_stop(dbus_info); + * if (txirb_pending) + * dbus_tx_timer_start(dbus_info, DBUS_TX_TIMEOUT_INTERVAL); + * pktinfo = txirb->info; // This is the same as the pkt :-) + * if (dbus_info->cbs && dbus_info->cbs->send_complete) + * dbus_info->cbs->send_complete(dbus_info->cbarg, pktinfo, + * status); + */ + + /* Free the coalesce buffer, if multi-buffer packet only. Do not + * rely on buff, as it might not even exist + */ + if (PKTNEXT(usbos_info->pub->osh, qtd->rpc)) { + /* ME: dma_unmap_single */ + /* printk("k-Freeing %p\n", qtd->buff); */ + kfree(qtd->buff); + } + + if (dbus_info->cbs && dbus_info->cbs->send_complete) + { + atomic_dec(&s_tx_pending); + spin_unlock(lock); + /* printk("Sending to RPC qtd %p\n", qtd); */ +#if !(defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC)) + #error Configuration not supported; read dbus_if_send_irb_complete for guidelines +#endif + /* ME: Set to meaningful status */ + dbus_info->cbs->send_complete(dbus_info->cbarg, qtd->rpc, + 0); + if ((atomic_read(&s_tx_pending) < 16) && + /* ME: 16 or dbus_info->tx_low_watermark? */ + dbus_info->txoff && !dbus_info->txoverride) { + dbus_flowctrl_tx(dbus_info, OFF); + } + spin_lock(lock); + + /* Things could have happened while the lock was gone, + * resync to the hardware + */ + next = qh->first_qtd; + end = qh->dummy; + } + } + + optimize_ehci_qtd_free(qtd); + } else { /* IN (dongle->host) pipe */ + /* Simulates the upstream travel */ + usb_info_t *usb_info = (usb_info_t *) usbos_info->cbarg; + dbus_info_t *dbus_info = (dbus_info_t *)usb_info->cbarg; + /* unsigned long flags; */ + int actual_length = 0; + + /* All our reads must be short */ + if (!SHORT_READ_Q (status)) ASSERT(0); + + /* Done with hardware, convert status to error codes */ + status = get_qtd_status(qtd, status, &actual_length); + + switch (status) { + /* success */ + case 0: + case -EINPROGRESS: + case -EREMOTEIO: + status = 0; + break; + + case -ECONNRESET: /* canceled */ + case -ENOENT: + case -EPROTO: + DBUSERR(("%s: ehci unlink. status %x\n", __FUNCTION__, status)); + break; + } + + if (g_probe_info.dereged) { + printk("%s: DBUS deregistering, ignoring recv callback\n", + __FUNCTION__); + return; + } + + dma_unmap_single( + usbos_info->usb->bus->controller, + (dma_addr_t)qtd->qtd_buffer_hi[0], + actual_length, + DMA_FROM_DEVICE); + + /* From dbus_usb_recv_irb_complete + * + * if (usb_info->cbs && usb_info->cbs->recv_irb_complete) + * usb_info->cbs->recv_irb_complete(usb_info->cbarg, rxirb, status); + */ + + /* From dbus_if_recv_irb_complete */ + if (dbus_info->pub.busstate != DBUS_STATE_DOWN) { + if (status == 0) { + void *buf = qtd->rpc; + + ASSERT(buf != NULL); + spin_unlock(lock); +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) + /* Note that these ifdefs are indirectly coming from + * dbus_usbos_recv_urb_submit The code itself is from + * dbus_if_recv_irb_complete that makes the decision + * at runtime, yet it is only pkt or buf depending on + * the NOCOPY setup, never both :-) + */ + if (dbus_info->cbs && dbus_info->cbs->recv_pkt) + dbus_info->cbs->recv_pkt(dbus_info->cbarg, buf); +#else + if (actual_length > 0) { + if (dbus_info->cbs && dbus_info->cbs->recv_buf) + dbus_info->cbs->recv_buf(dbus_info->cbarg, + buf, actual_length); + } +#endif + spin_lock(lock); + + /* Things could have happened while the lock was gone, + * resync to the hardware + */ + next = qh->first_qtd; + end = qh->dummy; + + /* Reinitialize this qtd since it will be reused. */ + optimize_ehci_qtd_init(qtd, qtd->qtd_self); + +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) + /* Note that these ifdefs are coming from + * dbus_usbos_recv_urb_submit. In the NOCOPY configuration, + * force an allocation of a new packet + */ + optimize_submit_rx_request(&dbus_info->pub, 1, qtd, NULL); + +#else + /* In the copy mode, simply reuse the buffer; upper level + * had already consumed the data + */ + optimize_submit_rx_request(&dbus_info->pub, 1, qtd, buf); +#endif + /* Not to free this qtd because it will be reused. */ + continue; + } + } else { + printk("%s: DBUS down, ignoring recv callback\n", __FUNCTION__); + } + optimize_ehci_qtd_free(qtd); + } + } +} /* ehci_bypass_callback */ + +/** EHCI fastpath specific function */ +static void optimize_urb_callback(struct urb *urb) +{ + struct usb_ctrlrequest *req = urb->context; + + kfree(req); + USB_FREE_URB(urb); +} + +/** + * EHCI fastpath specific function. Shall be called under an external lock (currently RPC_TP_LOCK) + */ +static int optimize_submit_urb(struct usb_device *usb, void *ptr, int request) +{ + struct usb_ctrlrequest *req; + struct urb *urb; + + if ((urb = USB_ALLOC_URB()) == NULL) { + printk("EHCI Fastpath: Error allocating URB in optimize_EP!"); + return -ENOMEM; + } + + if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) { + printk("EHCI Fastpath: Failed to allocate memory for control request in" + " optimize_EP!"); + USB_FREE_URB(urb); + return -ENOMEM; + } + + req->bRequestType = (USB_TYPE_VENDOR | USB_RECIP_OTHER); + req->bRequest = request; + + /* Use this instead of a buffer */ + req->wValue = ((int)ptr & 0xffff); + req->wIndex = ((((int)ptr)>>16) & 0xffff); + req->wLength = 0; + + printk("EHCI Fastpath: usb_dev %p\n", usb); + printk("EHCI Fastpath: bus %p\n", usb->bus); + printk("EHCI Fastpath: Hub %p\n", usb->bus->root_hub); + + usb_fill_control_urb( + urb, + usb->bus->root_hub, + usb_sndctrlpipe(usb->bus->root_hub, 0), + (void *)req, + NULL, + 0, + optimize_urb_callback, + req); + + USB_SUBMIT_URB(urb); + + if (urb->status != 0) { + printk("EHCI Fastpath: Cannot submit URB in optimize_EP: %d\n", urb->status); + } + + return urb->status; +} /* optimize_submit_urb */ + +/** EHCI fastpath specific function */ +static int epnum(int pipe) +{ + int epn = usb_pipeendpoint(pipe); + if (usb_pipein (pipe)) + epn |= 0x10; + return epn; +} + +/** EHCI fastpath specific function */ +static int optimize_init(usbos_info_t *usbos_info, struct usb_device *usb, int out, int in, int in2) +{ + int retval = -EPIPE; + + atomic_set(&s_tx_pending, 0); + /* atomic_set(&s_rx_pending, 0); */ + + usbos_info->tx_ep = epnum(out); + usbos_info->rx_ep = epnum(in); + usbos_info->rx2_ep = epnum(in2); + usbos_info->usb_device = usb; + + /* printk("EHCI Fastpath: Create pool %p %p %p\n", usb, usb->bus, usb->bus->controller); */ + + /* QTDs for bulk transfers - separate pool */ + /* ME: Destroy pool */ + usbos_info->qtd_pool = dma_pool_create("usbnet_qtd", + usb->bus->controller, + sizeof(struct ehci_qtd), + EHCI_QTD_ALIGN /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */); + if (!usbos_info->qtd_pool) { + printk("EHCI Fastpath: Cannot create the QTD pool\n"); + goto fail; + } + + /* detaching the EP */ + if (optimize_submit_urb(usb, usb, EHCI_SET_BYPASS_DEV) != 0) + goto fail; + optimize_submit_urb(usb, ehci_bypass_callback, EHCI_SET_BYPASS_CB); + optimize_submit_urb(usb, usbos_info->qtd_pool, EHCI_SET_BYPASS_POOL); +#ifdef EHCI_FASTPATH_TX + optimize_submit_urb(usb, (void*)((0<<16)|usbos_info->tx_ep), EHCI_FASTPATH); +#endif +#ifdef EHCI_FASTPATH_RX + optimize_submit_urb(usb, (void*)((1<<16)|usbos_info->rx_ep), EHCI_FASTPATH); +#endif + /* ME: Later optimize_submit_urb(usb, ((2<<16)|s_rx2_ep), EHCI_FASTPATH); */ + + /* getting the QH */ + printk("EHCI Fastpath: EP in %d EP in2 %d EP out %d\n", usbos_info->rx_ep, + usbos_info->rx2_ep, usbos_info->tx_ep); + + return 0; + +fail: + return retval; +} /* optimize_submit_urb */ + +/** EHCI fastpath specific function */ +static int optimize_deinit_qtds(struct ehci_qh *qh, int coalesce_buf) +{ + usbos_info_t *usbos_info = g_probe_info.usbos_info; + struct ehci_qtd *qtd, *end, *next; + unsigned long flags; + + if (qh == NULL) + return 0; + + end = qh->dummy; + + printk("%s %d. qh = %p\n", __func__, __LINE__, qh); + + spin_lock_irqsave(&usbos_info->fastpath_lock, flags); + for (qtd = qh->first_qtd; qtd != end; qtd = next) { + next = qtd->obj_next; + qh->first_qtd = next; + + /* Free the coalesce buffer, if multi-buffer packet only. Do not + * rely on buff, as it might not even exist + */ + if (coalesce_buf && PKTNEXT(usbos_info->pub->osh, qtd->rpc)) { + /* ME: dma_unmap_single */ + printk("k-Freeing %p, ", qtd->buff); + kfree(qtd->buff); + } + printk("freeing qtd %p\n", qtd); + + optimize_ehci_qtd_free(qtd); + } + spin_unlock_irqrestore(&usbos_info->fastpath_lock, flags); + + return 0; +} + +/** EHCI fastpath specific function. This code might deserve a separate file */ +static struct ehci_qh * +get_ep(usbos_info_t *usbos_info, int ep) +{ +#ifdef KERNEL26 + struct usb_host_endpoint *epp = NULL; + switch (ep) + { + case 0: epp = usbos_info->usb_device->ep_out[usbos_info->tx_ep&0xf]; break; + case 1: epp = usbos_info->usb_device->ep_in[usbos_info->rx_ep&0xf]; break; + case 2: epp = usbos_info->usb_device->ep_in[usbos_info->rx2_ep&0xf]; break; + default: ASSERT(0); + } + if (epp != NULL) + return (struct ehci_qh *)epp->hcpriv; + else return NULL; +#else + switch (ep) + { + case 0: return (struct ehci_qh *)(((struct hcd_dev*)(usbos_info-> + usb_device->hcpriv))->ep[usbos_info->tx_ep]); + case 1: return (struct ehci_qh *)(((struct hcd_dev*)(usbos_info-> + usb_device->hcpriv))->ep[usbos_info->rx_ep]); + case 2: return (struct ehci_qh *)(((struct hcd_dev*)(usbos_info-> + usb_device->hcpriv))->ep[usbos_info->rx2_ep]); + default: ASSERT(0); + } + return NULL; +#endif /* KERNEL26 */ +} + +/** EHCI fastpath specific function */ +int optimize_deinit(usbos_info_t *usbos_info, struct usb_device *usb) +{ + optimize_deinit_qtds(get_ep(usbos_info, 0), 1); + optimize_deinit_qtds(get_ep(usbos_info, 1), 0); +#if defined(EHCI_FASTPATH_TX) || defined(EHCI_FASTPATH_RX) + optimize_submit_urb(usb, (void *)0, EHCI_CLR_EP_BYPASS); +#endif + dma_pool_destroy(usbos_info->qtd_pool); + return 0; +} + +/** EHCI fastpath specific function. Reassemble the segmented packet */ +static int +optimize_gather(const dbus_pub_t *pub, void *pkt, void **buf) +{ + int len = 0; + + void *transfer_buf = kmalloc(pkttotlen(pub->osh, pkt), + GFP_ATOMIC); + *buf = transfer_buf; + + if (!transfer_buf) { + printk("fail to alloc to usb buffer\n"); + return 0; + } + + while (pkt) { + int pktlen = PKTLEN(pub->osh, pkt); + bcopy(PKTDATA(pub->osh, pkt), transfer_buf, pktlen); + transfer_buf += pktlen; + len += pktlen; + pkt = PKTNEXT(pub->osh, pkt); + } + + /* printk("Coalesced a %d-byte buffer\n", len); */ + + return len; +} + +/** EHCI fastpath specific function */ +int +optimize_qtd_fill_with_rpc(const dbus_pub_t *pub, int epn, + struct ehci_qtd *qtd, void *rpc, int token, int len) +{ + void *data = NULL; + + if (len == 0) + return optimize_qtd_fill_with_data(pub, epn, qtd, data, token, len); + + ASSERT(rpc != NULL); + data = PKTDATA(pub->osh, rpc); + qtd->rpc = rpc; + + if (PKTNEXT(pub->osh, rpc)) { + len = optimize_gather(pub, rpc, &data); + qtd->buff = data; + } + + return optimize_qtd_fill_with_data(pub, epn, qtd, data, token, len); +} + +/** EHCI fastpath specific function. Fill the QTD from the data buffer */ +int +optimize_qtd_fill_with_data(const dbus_pub_t *pub, int epn, + struct ehci_qtd *qtd, void *data, int token, int len) +{ + int i, bytes_fit, page_offset; + dma_addr_t addr = 0; + + /* struct usb_host_endpoint *ep = get_ep(epn); */ + usbos_info_t *usbos_info = g_probe_info.usbos_info; + + token |= (EHCI_QTD_ACTIVE | EHCI_QTD_IOC); /* Allow execution, force interrupt */ + + if (len > 0) { + addr = dma_map_single( + usbos_info->usb->bus->controller, + data, + len, + EHCI_QTD_GET_PID(token) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + } + + qtd->qtd_buffer[0] = cpu_to_hc32((u32)addr); + /* Here qtd->qtd_buffer_hi[0] is leveraged to store addr value, which + * is needed when invoking dma_unmap_single() in ehci_bypass_callback(). + * This is valid for EHCI 32bit only. + */ + qtd->qtd_buffer_hi[0] = cpu_to_hc32((u32)addr); + page_offset = (addr & (EHCI_PAGE_SIZE-1)); + bytes_fit = EHCI_PAGE_SIZE - page_offset; + addr -= page_offset; + if (len < bytes_fit) + bytes_fit = len; + else { + addr += EHCI_PAGE_SIZE; + + for (i = 1; bytes_fit < len && i < EHCI_QTD_NBUFFERS; i++) { + qtd->qtd_buffer[i] = cpu_to_hc32((u32)addr); + qtd->qtd_buffer_hi[i] = 0; + addr += EHCI_PAGE_SIZE; + if ((bytes_fit + EHCI_PAGE_SIZE) < len) + bytes_fit += EHCI_PAGE_SIZE; + else + bytes_fit = len; + } + + if (bytes_fit != len) + { + /* ME: Handle long packets? Does not happen */ + ASSERT(0); + } + } + qtd->qtd_status = cpu_to_hc32((bytes_fit << 16) | token); + qtd->length = bytes_fit; + + return bytes_fit; +} /* optimize_qtd_fill_with_data */ + +/** + * EHCI fastpath specific function. Reimplementation of qh_append_tds(). Returns nonzero if too many + * requests pending. + */ +int +optimize_submit_async(struct ehci_qtd *qtd, int epn) +{ + /* Clean implementation along the lines of qh_append_tds() */ + + struct ehci_qtd *afterend; /* Element at the end of the QTD chain (after the + * last useful one, "after-end") + */ + dma_addr_t hw_addr; + __hc32 status; + unsigned long flags; + + usbos_info_t *usbos_info = g_probe_info.usbos_info; + struct ehci_qh *qh = get_ep(usbos_info, epn); + usb_info_t *usb_info = (usb_info_t *) usbos_info->cbarg; + dbus_info_t *dbus_info = (dbus_info_t *)usb_info->cbarg; + + /* printk("Submit qtd %p to pipe %d (%p)\n", qtd, epn, qh); */ + if (qh == NULL) + { + printk("EHCI Fastpath: Attempt of optimized submit to a non-optimized pipe\n"); + return -1; + } + + spin_lock_irqsave(&usbos_info->fastpath_lock, flags); + + /* Limit outstanding - for rpc behavior only */ + /* printk("QH qtd_status %08x\n", qh->hw->qtd_status); */ + + if ((qtd->qtd_status & (1<<8)) == 0) + { + atomic_inc(&s_tx_pending); + if (atomic_read(&s_tx_pending) > 16*2) /* (dbus_info->tx_low_watermark * 3)) */ + dbus_flowctrl_tx(dbus_info, TRUE); + } + + ASSERT(qh != NULL); + + /* ME: Check for hardware availability here */ + + /* + * Standard list processing trick: + * * old "afterend" is filled with the incoming data while still HALTed + * * new element is appended and prepared to serve as new afterend + * * now old afterend is activated + * This way, HW never races the SW - no semaphores are necessary, as long as this function + * is not reentered for the same QH + */ + + /* Make new QTD to be HALTed, wait for it to actually happen */ + status = qtd->qtd_status; + qtd->qtd_status = cpu_to_le32(EHCI_QTD_HALTED); + wmb(); + + /* Now copy all information from the new QTD to the old afterend, + * except the own HW address + */ + afterend = qh->dummy; + hw_addr = afterend->qtd_self; + *afterend = *qtd; + afterend->qtd_self = hw_addr; + + /* The new QTD is ready to serve as a new afterend, append it */ + qh->dummy = qtd; + afterend->qtd_next = qtd->qtd_self; + afterend->qtd_altnext = qtd->qtd_self; /* Always assume short read. Harmless in our case */ + afterend->obj_next = qtd; + + /* Wait for writes to happen and enable the old afterend (now containing the QTD data) */ + wmb(); + afterend->qtd_status = status; + wmb(); + + spin_unlock_irqrestore(&usbos_info->fastpath_lock, flags); + + return 0; +} /* optimize_submit_async */ + +/** EHCI fastpath specific function. ME: Error return and handling */ +void +optimize_submit_rx_request(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd_in, + void *buf) +{ + /* ME: Replace with getting usbos_info from pub */ + usbos_info_t *usbos_info = g_probe_info.usbos_info; + int len = usbos_info->rxbuf_len; + void *pkt; + struct ehci_qtd *qtd; + int token = EHCI_QTD_SET_CERR(3) | EHCI_QTD_SET_PID(1); + + if (qtd_in == NULL) { + qtd = optimize_ehci_qtd_alloc(GFP_KERNEL); + if (!qtd) { + printk("EHCI Fastpath: Out of QTDs\n"); + return; + } + } else { + qtd = qtd_in; + } + + if (buf == NULL) + { + /* NOCOPY, allocate own packet */ + /* Follow dbus_usbos_recv_urb_submit */ + pkt = PKTGET(usbos_info->pub->osh, len, FALSE); + if (pkt == NULL) { + printk("%s: PKTGET failed\n", __FUNCTION__); + optimize_ehci_qtd_free(qtd); + return; + } + /* consider the packet "native" so we don't count it as MALLOCED in the osl */ + PKTTONATIVE(usbos_info->pub->osh, pkt); + qtd->rpc = pkt; + buf = PKTDATA(usbos_info->pub->osh, pkt); + + } else { + qtd->rpc = buf; + } + + optimize_qtd_fill_with_data(pub, epn, qtd, buf, token, len); + optimize_submit_async(qtd, epn); +} /* optimize_submit_rx_request */ + +#endif /* EHCI_FASTPATH_TX || EHCI_FASTPATH_RX */ #ifdef BCM_REQUEST_FW @@ -3183,187 +4553,159 @@ dbus_request_firmware(const char *name, const struct firmware **firmware) return *firmware != NULL ? 0 : -ENOENT; } +#ifndef DHD_LINUX_STD_FW_API static void * -dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev) +dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen, + uint16 boardtype, uint16 boardrev, char *path) { const struct firmware *firmware = NULL; -#ifndef OEM_ANDROID s8 *device_id = NULL; s8 *chip_rev = ""; -#endif /* OEM_ANDROID */ - s8 file_name[64]; + s8 file_name[64] = {0, }; int ret; -#ifndef OEM_ANDROID switch (devid) { - case BCM4350_CHIP_ID: - case BCM4354_CHIP_ID: - case BCM43556_CHIP_ID: - case BCM43558_CHIP_ID: - case BCM43566_CHIP_ID: - case BCM43568_CHIP_ID: - case BCM43570_CHIP_ID: - case BCM4358_CHIP_ID: - device_id = "4350"; - break; - case BCM43143_CHIP_ID: - device_id = "43143"; - break; - case BCM43234_CHIP_ID: - case BCM43235_CHIP_ID: - case BCM43236_CHIP_ID: - device_id = "43236"; - break; - case BCM43242_CHIP_ID: - device_id = "43242"; - break; - case BCM43238_CHIP_ID: - device_id = "43238"; - break; - case BCM43526_CHIP_ID: - device_id = "43526"; - break; - case BCM43569_CHIP_ID: - device_id = "43569"; + case BCM4381_CHIP_ID: + device_id = "4381"; switch (chiprev) { - case 0: + case 1: chip_rev = "a0"; break; - case 2: - chip_rev = "a2"; - break; default: break; } break; + case BCM4382_CHIP_ID: + device_id = "4382"; + switch (chiprev) { + case 1: + chip_rev = "a0"; + break; + default: + break; + } + break; + default: DBUSERR(("unsupported device %x\n", devid)); return NULL; } /* Load firmware */ - snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-firmware.bin", device_id, chip_rev); -#else - snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_FW_PATH); -#endif /* OEM_ANDROID */ + snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-usb.bin", device_id, chip_rev); - ret = dbus_request_firmware(file_name, &firmware); + ret = dbus_request_firmware(path, &firmware); if (ret) { - DBUSERR(("fail to request firmware %s\n", file_name)); + DBUSERR(("fail to request firmware %s\n", path)); return NULL; - } - + } else + DBUSERR(("%s: %s (%zu bytes) open success\n", __FUNCTION__, path, firmware->size)); + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); *fwlen = firmware->size; *fw = (uint8 *)firmware->data; return (void *)firmware; - + GCC_DIAGNOSTIC_POP(); } static void * -dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev) +dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, + uint16 boardtype, uint16 boardrev, char *path) { const struct firmware *firmware = NULL; -#ifndef OEM_ANDROID s8 *device_id = NULL; s8 *chip_rev = ""; -#endif /* OEM_ANDROID */ s8 file_name[64]; int ret; -#ifndef OEM_ANDROID switch (devid) { - case BCM4350_CHIP_ID: - case BCM4354_CHIP_ID: - case BCM43556_CHIP_ID: - case BCM43558_CHIP_ID: - case BCM43566_CHIP_ID: - case BCM43568_CHIP_ID: - case BCM43570_CHIP_ID: - case BCM4358_CHIP_ID: - device_id = "4350"; - break; - case BCM43143_CHIP_ID: - device_id = "43143"; - break; - case BCM43234_CHIP_ID: - device_id = "43234"; - break; - case BCM43235_CHIP_ID: - device_id = "43235"; - break; - case BCM43236_CHIP_ID: - device_id = "43236"; - break; - case BCM43238_CHIP_ID: - device_id = "43238"; - break; - case BCM43242_CHIP_ID: - device_id = "43242"; - break; - case BCM43526_CHIP_ID: - device_id = "43526"; - break; - case BCM43569_CHIP_ID: - device_id = "43569"; + case BCM4381_CHIP_ID: + device_id = "4381"; switch (chiprev) { - case 0: + case 1: chip_rev = "a0"; break; - case 2: - chip_rev = "a2"; - break; default: break; } break; + case BCM4382_CHIP_ID: + device_id = "4382"; + switch (chiprev) { + case 1: + chip_rev = "a0"; + break; + default: + break; + } + break; + default: DBUSERR(("unsupported device %x\n", devid)); return NULL; } /* Load board specific nvram file */ - snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-%2x-%2x.nvm", - device_id, chip_rev, boardtype, boardrev); -#else - snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_NVRAM_PATH); -#endif /* OEM_ANDROID */ + snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-usb.nvm", + device_id, chip_rev); - ret = dbus_request_firmware(file_name, &firmware); + ret = dbus_request_firmware(path, &firmware); if (ret) { - DBUSERR(("fail to request nvram %s\n", file_name)); + DBUSERR(("fail to request nvram %s\n", path)); -#ifndef OEM_ANDROID /* Load generic nvram file */ snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s.nvm", device_id, chip_rev); ret = dbus_request_firmware(file_name, &firmware); -#endif /* OEM_ANDROID */ - if (ret) { - DBUSERR(("fail to request nvram %s\n", file_name)); + DBUSERR(("fail to request nvram %s\n", path)); return NULL; } + } else + DBUSERR(("%s: %s (%zu bytes) open success\n", __FUNCTION__, path, firmware->size)); + + *fwlen = firmware->size; + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + *fw = (uint8 *)firmware->data; + return (void *)firmware; + GCC_DIAGNOSTIC_POP(); +} /* dbus_get_fw_nvfile */ + +void * +dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, uint16 boardtype, + uint16 boardrev, char *path) +{ + switch (type) { + case DBUS_FIRMWARE: + return dbus_get_fwfile(devid, chiprev, fw, fwlen, boardtype, boardrev, path); + case DBUS_NVFILE: + return dbus_get_nvfile(devid, chiprev, fw, fwlen, boardtype, boardrev, path); + default: + return NULL; + } +} +#else +void * +dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, uint16 boardtype, + uint16 boardrev, char *path) +{ + const struct firmware *firmware = NULL; + int err = DBUS_OK; + + err = dbus_request_firmware(path, &firmware); + if (err) { + DBUSERR(("fail to request firmware %s\n", path)); + return NULL; + } else { + DBUSERR(("%s: %s (%zu bytes) open success\n", + __FUNCTION__, path, firmware->size)); } *fwlen = firmware->size; *fw = (uint8 *)firmware->data; return (void *)firmware; } - -void * -dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, uint16 boardtype, - uint16 boardrev) -{ - switch (type) { - case DBUS_FIRMWARE: - return dbus_get_fwfile(devid, chiprev, fw, fwlen, boardtype, boardrev); - case DBUS_NVFILE: - return dbus_get_nvfile(devid, chiprev, fw, fwlen, boardtype, boardrev); - default: - return NULL; - } -} +#endif void dbus_release_fw_nvfile(void *firmware) @@ -3404,3 +4746,62 @@ dbus_usbos_intf_wlan(struct usb_device *usb) return intf_wlan; } #endif /* BCMUSBDEV_COMPOSITE */ + +#ifdef KEEPIF_ON_DEVICE_RESET +/* if keepif_on_devreset is set, and reset_resume or disconnect got called, we need de-register or + * register the usb driver to OS again; but this operation can't be called inside the reset_resume + * or disconnect callback, so introduce a kernel thread to do these work + */ +static int +dbus_usbos_usbreset_func(void *data) +{ + enum usb_dev_status flag = USB_DEVICE_INIT; + usbos_info_t *usbos_info; + + while (1) { + wait_event_interruptible_timeout(g_probe_info.usbreset_queue_head, + atomic_read(&g_probe_info.usbdev_stat), 100); /* 100 ms */ + + if (kthread_should_stop()) + break; + if (!(usbos_info = g_probe_info.usbos_info)) + continue; + if (!(flag = atomic_read(&g_probe_info.usbdev_stat))) + continue; + + usbos_info = g_probe_info.usbos_info; + flag = atomic_read(&g_probe_info.usbdev_stat); + atomic_set(&g_probe_info.usbdev_stat, USB_DEVICE_INIT); + + if ((flag == USB_DEVICE_RESETTED) || (flag == USB_DEVICE_DISCONNECTED)) { + DBUSERR(("Device reset, re-register USB driver\n")); + g_probe_info.dev_resetted = TRUE; + g_probe_info.busstate_bf_devreset = usbos_info->pub->busstate; + dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN); + + g_probe_info.dereged = TRUE; + USB_DEREGISTER(); + USB_REGISTER(); + g_probe_info.dereged = FALSE; + } else if (flag == USB_DEVICE_PROBED) { + DBUSERR(("Device probed, but no need to initialize higher layer\n")); + g_probe_info.dev_resetted = FALSE; + dbus_usbos_init_info(); + /* The device may have lost power, so a firmware download may be required */ + dbus_usbos_state_change(usbos_info, + DBUS_STATE_DL_NEEDED); + g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; + dbus_usbos_state_change(usbos_info, + g_probe_info.busstate_bf_devreset); + } + } + return 0; +} +#endif /* KEEPIF_ON_DEVICE_RESET */ + +#ifdef LINUX +struct device * dbus_get_dev(void) +{ + return &g_probe_info.usb->dev; +} +#endif /* LINUX */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h old mode 100755 new mode 100644 index 3b70e18bf5f6..923697417e42 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -47,9 +47,9 @@ #include #include #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) -#include -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) #include #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) */ #ifdef DHD_BUZZZ_LOG_ENABLED @@ -72,6 +72,7 @@ int get_scheduler_policy(struct task_struct *p); #define ENODATA 6 #define EREMOTEIO 7 #define ENODEV 8 +#define ENOCSI 50 /* No CSI structure available */ #define ERESTARTSYS 512 #endif /* LINUX */ #define MAX_EVENT 16 @@ -101,19 +102,6 @@ int get_scheduler_policy(struct task_struct *p); #ifdef WL_CFGVENDOR_SEND_HANG_EVENT #include #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */ - -#ifdef DHD_ERPOM -#include -#ifdef PCIE_OOB -/* - * Both ERPOM and PCIE_OOB depend on ftdi to programme GPIOs. - * Both features operating parallelly make the GPIOs go outof sync. - * So only one feature is expected to be present at a time. - */ -#error "PCIE_OOB enabled" -#endif /* PCIE_OOB */ -#endif /* DHD_ERPOM */ - #include #include @@ -124,7 +112,9 @@ int get_scheduler_policy(struct task_struct *p); #if defined(LINUX) || defined(linux) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) && LINUX_VERSION_CODE < \ KERNEL_VERSION(3, 18, 0) || defined(CONFIG_BCMDHD_VENDOR_EXT)) +#ifndef WL_VENDOR_EXT_SUPPORT #define WL_VENDOR_EXT_SUPPORT +#endif /* WL_VENDOR_EXT_SUPPORT */ #endif /* 3.18 > KERNEL_VER >= 3.14 || defined(CONFIG_BCMDHD_VENDOR_EXT) */ #endif /* defined (LINUX) || defined(linux) */ @@ -193,6 +183,9 @@ enum dhd_bus_devreset_type { #define DHD_BUS_BUSY_IN_HALDUMP 0x8000 #define DHD_BUS_BUSY_IN_NAPI 0x10000 #define DHD_BUS_BUSY_IN_DS_DEASSERT 0x20000 +#define DHD_BUS_BUSY_IN_DUMP_DONGLE_MEM 0x40000 +#define DHD_BUS_BUSY_IN_SYSFS_DUMP 0x80000 +#define DHD_BUS_BUSY_IN_PM_CALLBACK 0x100000 #define DHD_BUS_BUSY_SET_IN_TX(dhdp) \ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_TX @@ -230,6 +223,12 @@ enum dhd_bus_devreset_type { (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_NAPI #define DHD_BUS_BUSY_SET_IN_DS_DEASSERT(dhdp) \ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_DS_DEASSERT +#define DHD_BUS_BUSY_SET_IN_DUMP_DONGLE_MEM(dhdp) \ + (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_DUMP_DONGLE_MEM +#define DHD_BUS_BUSY_SET_IN_SYSFS_DUMP(dhdp) \ + (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_SYSFS_DUMP +#define DHD_BUS_BUSY_SET_IN_PM_CALLBACK(dhdp) \ + (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_PM_CALLBACK #define DHD_BUS_BUSY_CLEAR_IN_TX(dhdp) \ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_TX @@ -267,6 +266,12 @@ enum dhd_bus_devreset_type { (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_NAPI #define DHD_BUS_BUSY_CLEAR_IN_DS_DEASSERT(dhdp) \ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_DS_DEASSERT +#define DHD_BUS_BUSY_CLEAR_IN_DUMP_DONGLE_MEM(dhdp) \ + (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_DUMP_DONGLE_MEM +#define DHD_BUS_BUSY_CLEAR_IN_SYSFS_DUMP(dhdp) \ + (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_SYSFS_DUMP +#define DHD_BUS_BUSY_CLEAR_IN_PM_CALLBACK(dhdp) \ + (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_PM_CALLBACK #define DHD_BUS_BUSY_CHECK_IN_TX(dhdp) \ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_TX) @@ -303,7 +308,11 @@ enum dhd_bus_devreset_type { #define DHD_BUS_BUSY_CHECK_IN_HALDUMP(dhdp) \ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_HALDUMP) #define DHD_BUS_BUSY_CHECK_IN_DS_DEASSERT(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_DS_DEASSERT) + ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_DS_DEASSERT) +#define DHD_BUS_BUSY_CHECK_IN_DUMP_DONGLE_MEM(dhdp) \ + ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_DUMP_DONGLE_MEM) +#define DHD_BUS_BUSY_CHECK_IN_SYSFS_DUMP(dhdp) \ + ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_SYSFS_DUMP) #define DHD_BUS_BUSY_CHECK_IDLE(dhdp) \ ((dhdp)->dhd_bus_busy_state == 0) @@ -339,7 +348,14 @@ enum dhd_bus_devreset_type { #ifndef USEC_PER_SEC #define USEC_PER_SEC (1000 * 1000) #endif -#if (defined (LINUX) || defined(linux)) +#ifndef MSEC_PER_SEC +#define MSEC_PER_SEC 1000u +#endif + +#define TIMESPEC64_TO_US(ts) \ + (((ts).tv_sec * USEC_PER_SEC) + ((ts).tv_nsec / NSEC_PER_USEC)) + +#if (defined(LINUX) || defined(linux)) /* (u64)result = (u64)dividend / (u64)divisor */ #define DIV_U64_BY_U64(dividend, divisor) div64_u64(dividend, divisor) @@ -469,7 +485,11 @@ enum dhd_op_flags { #define DHD_SCAN_UNASSOC_ACTIVE_TIME CUSTOM_SCAN_UNASSOC_ACTIVE_TIME #endif /* CUSTOM_SCAN_UNASSOC_ACTIVE_TIME */ #define DHD_SCAN_HOME_TIME 45 /* ms: Embedded default Home time setting from DHD */ +#ifndef CUSTOM_SCAN_HOME_AWAY_TIME #define DHD_SCAN_HOME_AWAY_TIME 100 /* ms: Embedded default Home Away time setting from DHD */ +#else +#define DHD_SCAN_HOME_AWAY_TIME CUSTOM_SCAN_HOME_AWAY_TIME /* ms: Custom setting from DHD */ +#endif /* CUSTOM_SCAN_HOME_AWAY_TIME */ #ifndef CUSTOM_SCAN_PASSIVE_TIME #define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD */ #else @@ -485,23 +505,40 @@ enum dhd_op_flags { /* * MAX_NVRAMBUF_SIZE determines the size of the Buffer in the DHD that holds * the NVRAM data. That is the size of the buffer pointed by bus->vars - * This also needs to be increased to 24K to support NVRAM size higher than 16K + * This also needs to be increased if NVRAM files size increases */ -#define MAX_NVRAMBUF_SIZE (24 * 1024) /* max nvram buf size */ -#define MAX_CLM_BUF_SIZE (48 * 1024) /* max clm blob size */ +#define MAX_NVRAMBUF_SIZE (32 * 1024) /* max nvram buf size */ +#define MAX_CLM_BUF_SIZE (64 * 1024) /* max clm blob size */ #define MAX_TXCAP_BUF_SIZE (16 * 1024) /* max txcap blob size */ #ifdef DHD_DEBUG #define DHD_JOIN_MAX_TIME_DEFAULT 10000 /* ms: Max time out for joining AP */ #define DHD_SCAN_DEF_TIMEOUT 10000 /* ms: Max time out for scan in progress */ #endif /* DHD_DEBUG */ +/* Enable Flow ring pre-memory allocation by default for Android */ +#ifdef OEM_ANDROID +#define FLOW_RING_PREALLOC +#endif /* OEM_ANDROID */ + +#ifndef CONFIG_BCMDHD_FW_PATH +#ifdef OEM_ANDROID +#define CONFIG_BCMDHD_FW_PATH "/system/vendor/etc/wifi/fw_bcmdhd.bin" +#else +#define CONFIG_BCMDHD_FW_PATH "/var/run/rtecdc.bin" +#endif /* OEM_ANDROID */ +#endif /* CONFIG_BCMDHD_FW_PATH */ + +#ifndef CONFIG_BCMDHD_NVRAM_PATH +#ifdef OEM_ANDROID +#define CONFIG_BCMDHD_NVRAM_PATH "/system/vendor/etc/wifi/bcmdhd.cal" +#else +#define CONFIG_BCMDHD_NVRAM_PATH "/var/run/nvram.txt" +#endif /* OEM_ANDROID */ +#endif /* CONFIG_BCMDHD_NVRAM_PATH */ + #ifndef CONFIG_BCMDHD_CLM_PATH #ifdef OEM_ANDROID -#if defined(CUSTOMER_HW4) && defined(PLATFORM_SLP) -#define CONFIG_BCMDHD_CLM_PATH "/lib/firmware/bcmdhd_clm.blob" -#else #define CONFIG_BCMDHD_CLM_PATH "/etc/wifi/bcmdhd_clm.blob" -#endif /* CUSTOMER_HW4 && PLATFORM_SLP */ #elif defined(LINUX) || defined(linux) #define CONFIG_BCMDHD_CLM_PATH "/var/run/bcmdhd_clm.blob" #else @@ -509,13 +546,35 @@ enum dhd_op_flags { #define CONFIG_BCMDHD_CLM_PATH "" #endif /* OEM_ANDROID */ #endif /* CONFIG_BCMDHD_CLM_PATH */ + +#ifdef DHD_LINUX_STD_FW_API +#ifndef CONFIG_BCMDHD_CONFIG_SAR_PATH +#define CONFIG_BCMDHD_CONFIG_SAR_PATH "sar_config.ini" +#endif /* CONFIG_BCMDHD_CONFIG_SAR_PATH */ +#ifndef CONFIG_BCMDHD_CONFIG_PATH +#define CONFIG_BCMDHD_CONFIG_PATH "wlan_config.ini" +#endif /* CONFIG_BCMDHD_CONFIG_PATH */ +#else +#ifndef CONFIG_BCMDHD_CONFIG_SAR_PATH +#ifdef OEM_ANDROID +#define CONFIG_BCMDHD_CONFIG_SAR_PATH "/system/vendor/etc/wifi/sar_config.ini" +#else /* OEM_ANDROID */ +#define CONFIG_BCMDHD_CONFIG_SAR_PATH "/var/run/sar_config.ini" +#endif /* OEM_ANDROID */ +#endif /* CONFIG_BCMDHD_CONFIG_SAR_PATH */ + +#ifndef CONFIG_BCMDHD_CONFIG_PATH +#ifdef OEM_ANDROID +#define CONFIG_BCMDHD_CONFIG_PATH "/system/vendor/etc/wifi/wlan_config.ini" +#else /* OEM_ANDROID */ +#define CONFIG_BCMDHD_CONFIG_PATH "/var/run/wlan_config.ini" +#endif /* OEM_ANDROID */ +#endif /* CONFIG_BCMDHD_CONFIG_PATH */ +#endif /* DHD_LINUX_STD_FW_API */ + #define WL_CCODE_NULL_COUNTRY "#n" -#ifdef DHD_EFI -#define FW_VER_STR_LEN 256 -#else #define FW_VER_STR_LEN 128 -#endif #define FWID_STR_LEN 256 #define CLM_VER_STR_LEN 128 #define BUS_API_REV_STR_LEN 128 @@ -560,6 +619,12 @@ enum dhd_bus_ds_state { DW_DEVICE_HOST_WAKE_WAIT = 7, DW_DEVICE_DS_D3_INFORM_WAIT = 8 }; +#ifdef PCIE_INB_DSACK_EXT_WAIT +/* DS ack timeout is 3sec, FW retry count is 5. + * 5times * 3sec = 15sec. + */ +#define DW_DS_ACK_RETRY_THRESHOLD 15u +#endif /* PCIE_INB_DSACK_EXT_WAIT */ #endif /* PCIE_INB_DW */ enum dhd_prealloc_index { @@ -576,11 +641,11 @@ enum dhd_prealloc_index { /* 10 */ DHD_PREALLOC_MEMDUMP_RAM = 11, DHD_PREALLOC_DHD_WLFC_HANGER = 12, - DHD_PREALLOC_PKTID_MAP = 13, - DHD_PREALLOC_PKTID_MAP_IOCTL = 14, + DHD_PREALLOC_PKTID_MAP = 13, /* Deprecated */ + DHD_PREALLOC_PKTID_MAP_IOCTL = 14, /* Deprecated */ DHD_PREALLOC_DHD_LOG_DUMP_BUF = 15, DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX = 16, - DHD_PREALLOC_DHD_PKTLOG_DUMP_BUF = 17, + DHD_PREALLOC_DHD_PKTLOG_DUMP_BUF = 17, /* Deprecated */ DHD_PREALLOC_STAT_REPORT_BUF = 18, DHD_PREALLOC_WL_ESCAN = 19, DHD_PREALLOC_FW_VERBOSE_RING = 20, @@ -597,6 +662,15 @@ enum dhd_dongledump_mode { DUMP_MEMFILE_MAX = 4 }; +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) +typedef enum dhd_dongledump_status { + DUMP_READY = 0, + DUMP_IN_PROGRESS = 1, + DUMP_FAILURE = 2, + DUMP_NOT_READY = 3 +} dhd_dongledump_status_t; +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ + enum dhd_dongledump_type { DUMP_TYPE_RESUMED_ON_TIMEOUT = 1, DUMP_TYPE_D3_ACK_TIMEOUT = 2, @@ -630,7 +704,12 @@ enum dhd_dongledump_type { DUMP_TYPE_INBAND_DEVICE_WAKE_FAILURE = 30, DUMP_TYPE_PKTID_POOL_DEPLETED = 31, DUMP_TYPE_ESCAN_SYNCID_MISMATCH = 32, - DUMP_TYPE_INVALID_SHINFO_NRFRAGS = 33 + DUMP_TYPE_INVALID_SHINFO_NRFRAGS = 33, + DUMP_TYPE_P2P_DISC_BUSY = 34, + DUMP_TYPE_CONT_EXCESS_PM_AWAKE = 35, + DUMP_TYPE_DONGLE_TRAP_DURING_WIFI_ONOFF = 36, + DUMP_TYPE_BY_DSACK_HC_DUE_TO_ISR_DELAY = 37, + DUMP_TYPE_BY_DSACK_HC_DUE_TO_DPC_DELAY = 38 }; enum dhd_hang_reason { @@ -653,12 +732,18 @@ enum dhd_hang_reason { HANG_REASON_BSS_DOWN_FAILURE = 0x8011, HANG_REASON_IOCTL_SUSPEND_ERROR = 0x8012, HANG_REASON_ESCAN_SYNCID_MISMATCH = 0x8013, + HANG_REASON_SCAN_TIMEOUT = 0x8014, + HANG_REASON_SCAN_TIMEOUT_SCHED_ERROR = 0x8015, + HANG_REASON_P2P_DISC_BUSY = 0x8016, HANG_REASON_PCIE_LINK_DOWN_RC_DETECT = 0x8805, HANG_REASON_INVALID_EVENT_OR_DATA = 0x8806, HANG_REASON_UNKNOWN = 0x8807, HANG_REASON_PCIE_LINK_DOWN_EP_DETECT = 0x8808, HANG_REASON_PCIE_CTO_DETECT = 0x8809, - HANG_REASON_MAX = 0x880A + HANG_REASON_SLEEP_FAILURE = 0x880A, + HANG_REASON_DS_SKIP_TIMEOUT = 0x880B, + HANG_REASON_BT2WL_REG_RESET = 0x880C, + HANG_REASON_MAX = 0x880D }; #define WLC_E_DEAUTH_MAX_REASON 0x0FFF @@ -694,7 +779,7 @@ enum dhd_rsdb_scan_features { #define HANG_FIELD_MISMATCH_CNT 10 #define HANG_INFO_BIGDATA_KEY_STACK_CNT 4 -#define DEBUG_DUMP_TIME_BUF_LEN (16 + 1) +#define DEBUG_DUMP_TIME_BUF_LEN (22 + 1) /* delimiter between values */ #define HANG_KEY_DEL ' ' #define HANG_RAW_DEL '_' @@ -894,106 +979,14 @@ typedef enum dhd_ring_id { DRIVER_LOG_RING_ID = 0x4, ROAM_STATS_RING_ID = 0x5, BT_LOG_RING_ID = 0x6, - DEBUG_RING_ID_MAX = 0x7 + PACKET_LOG_RING_ID = 0x7, + DEBUG_DUMP_RING1_ID = 0x8, + DEBUG_DUMP_RING2_ID = 0x9, + MEM_DUMP_RING_ID = 0xa, + DEBUG_RING_ID_MAX = 0xb } dhd_ring_id_t; -#ifdef DHD_LOG_DUMP -#define DUMP_SSSR_ATTR_START 2 -#define DUMP_SSSR_ATTR_COUNT 10 - -typedef enum { - SSSR_C0_D11_BEFORE = 0, - SSSR_C0_D11_AFTER = 1, - SSSR_C1_D11_BEFORE = 2, - SSSR_C1_D11_AFTER = 3, - SSSR_C2_D11_BEFORE = 4, - SSSR_C2_D11_AFTER = 5, - SSSR_DIG_BEFORE = 6, - SSSR_DIG_AFTER = 7 -} EWP_SSSR_DUMP; - -typedef enum { - DLD_BUF_TYPE_GENERAL = 0, - DLD_BUF_TYPE_PRESERVE = 1, - DLD_BUF_TYPE_SPECIAL = 2, - DLD_BUF_TYPE_ECNTRS = 3, - DLD_BUF_TYPE_FILTER = 4, - DLD_BUF_TYPE_ALL = 5 -} log_dump_type_t; - -#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING -struct dhd_dbg_ring_buf -{ - void *dhd_pub; -}; -#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ - -#define LOG_DUMP_MAGIC 0xDEB3DEB3 #define HEALTH_CHK_BUF_SIZE 256 -#ifdef EWP_ECNTRS_LOGGING -#define ECNTR_RING_ID 0xECDB -#define ECNTR_RING_NAME "ewp_ecntr_ring" -#endif /* EWP_ECNTRS_LOGGING */ - -#ifdef EWP_RTT_LOGGING -#define RTT_RING_ID 0xADCD -#define RTT_RING_NAME "ewp_rtt_ring" -#endif /* EWP_ECNTRS_LOGGING */ - -#ifdef EWP_BCM_TRACE -#define BCM_TRACE_RING_ID 0xBCBC -#define BCM_TRACE_RING_NAME "ewp_bcm_trace_ring" -#endif /* EWP_BCM_TRACE */ - -/* - * XXX: Always add new enums at the end to compatible with parser, - * also add new section in split_ret of EWP_config.py - */ -typedef enum { - LOG_DUMP_SECTION_GENERAL = 0, - LOG_DUMP_SECTION_ECNTRS, - LOG_DUMP_SECTION_SPECIAL, - LOG_DUMP_SECTION_DHD_DUMP, - LOG_DUMP_SECTION_EXT_TRAP, - LOG_DUMP_SECTION_HEALTH_CHK, - LOG_DUMP_SECTION_PRESERVE, - LOG_DUMP_SECTION_COOKIE, - LOG_DUMP_SECTION_FLOWRING, - LOG_DUMP_SECTION_STATUS, - LOG_DUMP_SECTION_RTT, - LOG_DUMP_SECTION_BCM_TRACE -} log_dump_section_type_t; - -/* Each section in the debug_dump log file shall begin with a header */ -typedef struct { - uint32 magic; /* 0xDEB3DEB3 */ - uint32 type; /* of type log_dump_section_type_t */ - uint64 timestamp; - uint32 length; /* length of the section that follows */ -} log_dump_section_hdr_t; - -/* below structure describe ring buffer. */ -struct dhd_log_dump_buf -{ -#if defined(LINUX) || defined(linux) || defined(ANDROID) || defined(OEM_ANDROID) - spinlock_t lock; -#endif - void *dhd_pub; - unsigned int enable; - unsigned int wraparound; - unsigned long max; - unsigned int remain; - char* present; - char* front; - char* buffer; -}; - -#define DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE 256 -#define DHD_LOG_DUMP_MAX_TAIL_FLUSH_SIZE (80 * 1024) - -extern void dhd_log_dump_write(int type, char *binary_data, - int binary_len, const char *fmt, ...); -#endif /* DHD_LOG_DUMP */ /* DEBUG_DUMP SUB COMMAND */ enum { @@ -1003,10 +996,6 @@ enum { CMD_MAX }; -#define DHD_LOG_DUMP_TS_MULTIPLIER_VALUE 60 -#define DHD_LOG_DUMP_TS_FMT_YYMMDDHHMMSSMSMS "%02d%02d%02d%02d%02d%02d%04d" -#define DHD_LOG_DUMP_TS_FMT_YYMMDDHHMMSS "%02d%02d%02d%02d%02d%02d" -#define DHD_DEBUG_DUMP_TYPE "debug_dump" #define DHD_DUMP_SUBSTR_UNWANTED "_unwanted" #define DHD_DUMP_SUBSTR_DISCONNECTED "_disconnected" @@ -1015,29 +1004,23 @@ enum { #define DHD_DUMP_HAL_FILENAME_SUFFIX "_hal" #endif /* DNGL_AXI_ERROR_LOGGING */ -extern void get_debug_dump_time(char *str); -extern void clear_debug_dump_time(char *str); -#if defined(WL_CFGVENDOR_SEND_HANG_EVENT) || defined(DHD_PKT_LOGGING) -extern void copy_debug_dump_time(char *dest, char *src); -#endif /* WL_CFGVENDOR_SEND_HANG_EVENT || DHD_PKT_LOGGING */ - #define FW_LOGSET_MASK_ALL 0xFFFFu -#if defined(CUSTOMER_HW4) -#ifndef DHD_COMMON_DUMP_PATH -#define DHD_COMMON_DUMP_PATH "/data/log/wifi/" -#endif /* !DHD_COMMON_DUMP_PATH */ -#elif defined(CUSTOMER_HW2_DEBUG) +#if defined(CUSTOMER_HW7_DEBUG) #define DHD_COMMON_DUMP_PATH PLATFORM_PATH +#elif defined(CUSTOM_DHD_COMMON_DUMP_PATH) +#define DHD_COMMON_DUMP_PATH CUSTOM_DHD_COMMON_DUMP_PATH #elif defined(BOARD_HIKEY) +#ifndef DHD_COMMON_DUMP_PATH #define DHD_COMMON_DUMP_PATH "/data/misc/wifi/" +#endif /* !DHD_COMMON_DUMP_PATH */ #elif defined(OEM_ANDROID) && defined(__ARM_ARCH_7A__) #define DHD_COMMON_DUMP_PATH "/data/vendor/wifi/" #elif defined(OEM_ANDROID) /* For Brix Live Image */ #define DHD_COMMON_DUMP_PATH "/installmedia/" #else /* Default */ #define DHD_COMMON_DUMP_PATH "/root/" -#endif /* CUSTOMER_HW4 */ +#endif /* CUSTOMER_HW7_DEBUG */ #define DHD_MEMDUMP_LONGSTR_LEN 180 @@ -1047,14 +1030,11 @@ struct cntry_locales_custom { int32 custom_locale_rev; /* Custom local revisin default -1 */ }; -#ifdef DHD_PKTTS -#if defined(linux) || defined(LINUX) -extern uint dhd_msgbuf_get_ipv6_id(void *pkt); +#ifdef __linux__ +extern uint16 dhd_plat_align_rxbuf_size(uint16 rxbufpost_sz); #else -static INLINE uint dhd_msgbuf_get_ipv6_id(void *pkt) { return 0; } -#endif /* linux || LINUX */ -int dhd_send_msg_to_ts(struct sk_buff *skb, void *data, int size); -#endif /* DHD_PKTTS */ +static INLINE uint16 dhd_plat_align_rxbuf_size(uint16 rxbufpost_sz) { return rxbufpost_sz; } +#endif /* !__linux__ */ #if defined(LINUX) || defined(linux) int dhd_send_msg_to_daemon(struct sk_buff *skb, void *data, int size); @@ -1103,16 +1083,6 @@ typedef struct dmamap_stats { } dma_stats_t; #endif /* DMAMAP_STATS */ -#ifdef BT_OVER_PCIE -enum dhd_bus_quiesce_state { - DHD_QUIESCE_INIT = 0, - REQUEST_BT_QUIESCE = 1, - RESPONSE_BT_QUIESCE = 2, - REQUEST_BT_RESUME = 3, - RESPONSE_BT_RESUME = 4 -}; -#endif /* BT_OVER_PCIE */ - /* see wlfc_proto.h for tx status details */ #define DHD_MAX_TX_STATUS_MSGS 9u @@ -1125,23 +1095,6 @@ typedef struct dhd_if_tx_status_latency { } dhd_if_tx_status_latency_t; #endif /* TX_STATUS_LATENCY_STATS */ -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) -#define AWDL_NUM_SLOTS 16u /* 0 to 15 are the AWDL slots FW operates on */ -#define AWDL_SLOT_MULT 4u /* AWDL slot information sent by FW is in multiples of 4 */ -typedef struct dhd_awdl_statistics { - uint64 slot_start_time; /* AWDL slot start time in us */ - uint64 cum_slot_time; /* Cumulative time for which this AWDL slot was active */ - uint64 num_slots; /* Number of times this AWDL slot was active */ - uint64 cum_tx_status_latency; /* cum tx_status latency while this AWDL slot is active */ - uint64 num_tx_status; /* Num of AWDL(flowring with role as AWDL) tx status received */ - uint64 fw_cum_slot_time; /* Cumulative FW time for which this AWDL slot was active */ - uint32 fw_slot_start_time; /* AWDL slot start time sent by FW in us */ -#if defined(BCMDBG) - uint32 tx_status[DHD_MAX_TX_STATUS_MSGS]; /* Dongle return val wrt TX packet sent out */ -#endif /* BCMDBG */ -} dhd_awdl_stats_t; -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ - /* Bit in dhd_pub_t::gdb_proxy_stop_count set when firmware is stopped by GDB */ #define GDB_PROXY_STOP_MASK 1 @@ -1158,10 +1111,12 @@ typedef enum { #define PCIE_DB7_MAGIC_NUMBER_ISR_TRAP 0xdead0001 #define PCIE_DB7_MAGIC_NUMBER_DPC_TRAP 0xdead0002 +#define PCIE_DB7_MAGIC_NUMBER_DPC_LPM 0xdead0003 typedef struct dhd_db7_info { bool fw_db7w_trap; bool fw_db7w_trap_inprogress; + bool fw_db7w_trap_recieved; uint32 db7_magic_number; uint32 debug_db7_send_cnt; @@ -1174,12 +1129,6 @@ typedef struct dhd_db7_info { uint64 debug_max_db7_trap_time; } dhd_db7_info_t; -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE -typedef struct fwtrace_info fwtrace_info_t; /* forward declaration */ -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ - typedef enum dhd_induce_error_states { DHD_INDUCE_ERROR_CLEAR = 0x0, @@ -1190,37 +1139,82 @@ typedef enum dhd_induce_error_states DHD_INDUCE_DROP_AXI_SIG = 0x5, DHD_INDUCE_TX_BIG_PKT = 0x6, DHD_INDUCE_IOCTL_SUSPEND_ERROR = 0x7, + DHD_INDUCE_SCAN_TIMEOUT = 0x8, + DHD_INDUCE_SCAN_TIMEOUT_SCHED_ERROR = 0x9, + DHD_INDUCE_PKTID_INVALID_SAVE = 0xA, + DHD_INDUCE_PKTID_INVALID_FREE = 0xB, + DHD_INDUCE_PCIE_LINK_DOWN = 0xC, /* Big hammer induction */ DHD_INDUCE_BH_ON_FAIL_ONCE = 0x10, DHD_INDUCE_BH_ON_FAIL_ALWAYS = 0x11, DHD_INDUCE_BH_CBP_HANG = 0x12, + DHD_INDUCE_P2P_DISC_BUSY = 0x13, + DHD_INDUCE_PCIE_LINK_DOWN_IN_ISR = 0x14, DHD_INDUCE_ERROR_MAX } dhd_induce_error_states_t; -#ifdef DHD_HP2P -#define MAX_TX_HIST_BIN 16 -#define MAX_RX_HIST_BIN 10 -#define MAX_HP2P_FLOWS 16 -#define HP2P_PRIO 7 -#define HP2P_PKT_THRESH 48 -#define HP2P_TIME_THRESH 200 -#define HP2P_PKT_EXPIRY 40 -#define HP2P_TIME_SCALE 32 +#define MAX_MDRING_ITEM_DUMP 20 -typedef struct hp2p_info { - void *dhd_pub; - uint16 flowid; - bool hrtimer_init; - void *ring; - struct hrtimer timer; - uint64 num_pkt_limit; - uint64 num_timer_limit; - uint64 num_timer_start; - uint64 tx_t0[MAX_TX_HIST_BIN]; - uint64 tx_t1[MAX_TX_HIST_BIN]; - uint64 rx_t0[MAX_RX_HIST_BIN]; -} hp2p_info_t; -#endif /* DHD_HP2P */ +#define MAX_RX_LAT_PRIO 8 +#define MAX_RX_LAT_HIST_BIN 50 +#define MAX_RXCPL_HISTORY 50 +#define RX_LAT_TIME_SCALE 32 +#define RX_LAT_BIN_SCALE 500 + +typedef struct rx_cpl_history { + uint32 host_time; + uint32 ptm_high; + uint32 ptm_low; + uint32 rx_t0; + uint32 latency; + uint8 slice; + uint8 priority; + int8 rssi; +} rx_cpl_history_t; + +typedef struct rx_cpl_lat_info { + rx_cpl_history_t rx_history[MAX_RXCPL_HISTORY]; + uint32 rxcpl_hist_count; + uint32 rx_dur_2g[MAX_RX_LAT_PRIO][MAX_RX_LAT_HIST_BIN]; + uint32 rx_dur_5g[MAX_RX_LAT_PRIO][MAX_RX_LAT_HIST_BIN]; +} rx_cpl_lat_info_t; + +#define MAX_TXCPL_HISTORY 50u +typedef struct tx_cpl_history { + uint32 host_time; + uint32 ptm_high; + uint32 ptm_low; + uint16 latency; + uint16 flowid; + uint8 tid; +} tx_cpl_history_t; + +typedef struct tx_cpl_info { + tx_cpl_history_t tx_history[MAX_TXCPL_HISTORY]; + uint32 txcpl_hist_count; +} tx_cpl_info_t; + +#define DHD_PTM_CLK_ID 0xEu /* PTM clock ID; IDs 0-3 are used in tsync module */ +#define DHD_PTM_CLK_ID_MASK 0xF0000000u /* Bitmask for clkid */ +#define DHD_PTM_CLK_ID_SHIFT 28u /* Bitshift for clkid */ + +#define DHD_PTM_GET_CLKID(ts) (((ts) & DHD_PTM_CLK_ID_MASK) >> DHD_PTM_CLK_ID_SHIFT) +#define DHD_PTM_CLKID(ts) (DHD_PTM_GET_CLKID(ts) == DHD_PTM_CLK_ID) + +#ifdef DHD_USE_STATIC_CTRLBUF +#define PKTFREE_CTRLBUF(osh, p, flag) PKTFREE_STATIC(osh, p, flag); +#else +#define PKTFREE_CTRLBUF(osh, p, flag) PKTFREE(osh, p, flag); +#endif /* DHD_USE_STATIC_CTRLBUF */ + +#define RX_PKTFREE(osh, pkt_type, p, flag) \ +do { \ + if (ntoh16(pkt_type) == ETHER_TYPE_BRCM) { \ + PKTFREE_CTRLBUF(osh, p, flag); \ + } else { \ + PKTCFREE(osh, p, flag); \ + } \ +} while (0); #if defined(SHOW_LOGTRACE) && defined(DHD_USE_KTHREAD_FOR_LOGTRACE) /* Timestamps to trace dhd_logtrace_thread() */ @@ -1232,7 +1226,16 @@ struct dhd_logtrace_thr_ts { uint64 complete_time; }; #endif /* SHOW_LOGTRACE && DHD_USE_KTHREAD_FOR_LOGTRACE */ - +#ifdef SUPPORT_OTA_UPDATE +#define MAX_EXT_INFO_LEN 10u +typedef struct ota_update_info { + uint32 clm_len; + uint8 *clm_buf; + uint32 nvram_len; + uint8 *nvram_buf; + uint8 nvram_ext[MAX_EXT_INFO_LEN]; +} ota_update_info_t; +#endif /* SUPPORT_OTA_UPDATE */ /** * Common structure for module and instance linkage. * Instantiated once per hardware (dongle) instance that this DHD manages. @@ -1254,7 +1257,7 @@ typedef struct dhd_pub { #ifdef BCMDBUS struct dbus_pub *dbus; -#endif /* BCMDBUS */ +#endif /* Internal dhd items */ bool up; /* Driver up/down (to OS) */ @@ -1290,6 +1293,7 @@ typedef struct dhd_pub { ulong tx_ctlpkts; /* Control packets sent to dongle */ ulong tx_ctlerrs; /* Errors sending control frames to dongle */ ulong rx_packets; /* Packets sent up the network interface */ + ulong rx_forward; /* Packets forwarded at DHD driver level */ ulong rx_multicast; /* Multicast packets sent up the network interface */ ulong rx_errors; /* Errors processing rx data packets */ ulong rx_ctlpkts; /* Control frames processed from dongle */ @@ -1298,11 +1302,14 @@ typedef struct dhd_pub { ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */ ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */ ulong rx_pktgetfail; /* Number of PKTGET failures in DHD on RX */ + ulong rx_pktgetpool_fail; /* Number of PKTGET_POOL failures in DHD on RX */ ulong tx_pktgetfail; /* Number of PKTGET failures in DHD on TX */ ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */ ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */ ulong fc_packets; /* Number of flow control pkts recvd */ ulong tx_big_packets; /* Dropped data packets that are larger than MAX_MTU_SZ */ + ulong tx_bytes; /* total no. of bytes transmitted successfully */ + ulong rx_bytes; /* total no. of bytes received */ #ifdef DMAMAP_STATS /* DMA Mapping statistics */ dma_stats_t dma_stats; @@ -1329,12 +1336,10 @@ typedef struct dhd_pub { /* DTIM skip value, default 0(or 1) means wake each DTIM * 3 means skip 2 DTIMs and wake up 3rd DTIM(9th beacon when AP DTIM is 3) */ - int suspend_bcn_li_dtim; /* bcn_li_dtim value in suspend mode */ - int early_suspended; /* Early suspend status */ -#ifdef PKT_FILTER_SUPPORT - int dhcp_in_progress; /* DHCP period */ -#endif - + int early_suspended; /* Early suspend status */ +#if defined(PKT_FILTER_SUPPORT) + int dhcp_in_progress; /* DHCP period */ +#endif /* PKT_FILTER_SUPPORT */ /* Pkt filter defination */ char * pktfilter[100]; int pktfilter_count; @@ -1419,9 +1424,6 @@ typedef struct dhd_pub { /* Begin - Variables to track Bus Errors */ bool dongle_trap_occured; /* flag for sending HANG event to upper layer */ -#ifdef BT_OVER_PCIE - bool dongle_trap_due_to_bt; /* flag to indicate that dongle has trapped due to BT */ -#endif /* BT_OVER_PCIE */ bool iovar_timeout_occured; /* flag to indicate iovar resumed on timeout */ bool invalid_shinfo_nrfrags; /* flag to indicate invlaid shinfo nrfrags */ bool is_sched_error; /* flag to indicate timeout due to scheduling issue */ @@ -1429,6 +1431,7 @@ typedef struct dhd_pub { bool d3ack_timeout_occured; /* flag to indicate d3ack resumed on timeout */ bool livelock_occured; /* flag to indicate livelock occured */ bool pktid_audit_failed; /* flag to indicate pktid audit failure */ + bool pktid_invalid_occured; /* flag to indicate invalid pktid */ #endif /* PCIE_FULL_DONGLE */ bool iface_op_failed; /* flag to indicate interface operation failed */ bool scan_timeout_occurred; /* flag to indicate scan has timedout */ @@ -1437,6 +1440,10 @@ typedef struct dhd_pub { bool is_bt_recovery_required; #endif bool smmu_fault_occurred; /* flag to indicate SMMU Fault */ + bool p2p_disc_busy_occurred; + bool dongle_trap_during_wifi_onoff; /* flag to indicate trap during wifi on/off */ + bool dsack_hc_due_to_isr_delay; /* flag to indicate DSACK HC by ISR delay */ + bool dsack_hc_due_to_dpc_delay; /* flag to indicate DSACK HC by DPC delay */ /* * Add any new variables to track Bus errors above * this line. Also ensure that the variable is @@ -1484,9 +1491,6 @@ typedef struct dhd_pub { #if defined(BCMSUP_4WAY_HANDSHAKE) bool fw_4way_handshake; /* Whether firmware will to do the 4way handshake. */ #endif -#ifdef BCMINTERNAL - bool loopback; /* 1- enable loopback of tx packets, 0 - disable */ -#endif /* BCMINTERNAL */ #ifdef DEBUG_DPC_THREAD_WATCHDOG bool dhd_bug_on; #endif /* DEBUG_DPC_THREAD_WATCHDOG */ @@ -1501,17 +1505,15 @@ typedef struct dhd_pub { bool flow_rings_inited; /* set this flag after initializing flow rings */ #endif /* PCIE_FULL_DONGLE */ void *flowid_allocator; /* unique flowid allocator */ -#if defined(DHD_HTPUT_TUNABLES) void *htput_flowid_allocator; /* unique htput flowid allocator */ - uint8 htput_client_flow_rings; /* current number of htput client flowrings */ - uint8 htput_flow_ring_start; /* start index of htput flow rings */ -#endif /* DHD_HTPUT_TUNABLES */ + uint16 htput_client_flow_rings; /* current number of htput client flowrings */ + uint16 htput_flow_ring_start; /* start index of htput flow rings */ void *flow_ring_table; /* flow ring table, include prot and bus info */ void *if_flow_lkup; /* per interface flowid lkup hash table */ void *flowid_lock; /* per os lock for flowid info protection */ void *flowring_list_lock; /* per os lock for flowring list protection */ uint8 max_multi_client_flow_rings; - uint8 multi_client_flow_rings; + osl_atomic_t multi_client_flow_rings; uint32 num_h2d_rings; /* Max h2d rings including static and dynamic rings */ uint32 max_tx_flowid; /* used to validate flowid */ cumm_ctr_t cumm_ctr; /* cumm queue length placeholder */ @@ -1552,6 +1554,7 @@ typedef struct dhd_pub { #endif /* DHD_L2_FILTER */ #ifdef DHD_SSSR_DUMP bool sssr_inited; + bool force_sssr_init; bool sssr_dump_collected; /* Flag to indicate sssr dump is collected */ sssr_reg_info_cmn_t *sssr_reg_info; uint8 *sssr_mempool; @@ -1569,6 +1572,7 @@ typedef struct dhd_pub { #ifdef DHD_SDTC_ETB_DUMP etb_addr_info_t etb_addr_info; uint8 *sdtc_etb_mempool; + uint sdtc_etb_dump_len; bool sdtc_etb_inited; bool collect_sdtc; /* Flag to indicate SDTC dump is required */ #endif /* DHD_SDTC_ETB_DUMP */ @@ -1576,12 +1580,10 @@ typedef struct dhd_pub { uint32 soc_ram_length; uint32 memdump_type; #ifdef DHD_COREDUMP + uint8 *coredump_mem; + uint32 coredump_len; char memdump_str[DHD_MEMDUMP_LONGSTR_LEN]; #endif /* DHD_COREDUMP */ -#ifdef DHD_RND_DEBUG - uint8 *rnd_buf; - uint32 rnd_len; -#endif /* DHD_RND_DEBUG */ #ifdef DHD_FW_COREDUMP uint32 memdump_enabled; #ifdef DHD_DEBUG_UART @@ -1617,9 +1619,9 @@ typedef struct dhd_pub { #ifdef GSCAN_SUPPORT bool lazy_roam_enable; #endif -#if defined(PKT_FILTER_SUPPORT) && defined(APF) +#if defined(APF) bool apf_set; -#endif /* PKT_FILTER_SUPPORT && APF */ +#endif /* APF */ void *macdbg_info; #ifdef DHD_WET void *wet_info; @@ -1634,10 +1636,6 @@ typedef struct dhd_pub { uint8 dequeue_prec_map; uint8 prio_8021x; #endif -#ifdef WL_NATOE - struct dhd_nfct_info *nfct; - spinlock_t nfct_lock; -#endif /* WL_NATOE */ /* timesync link */ struct dhd_ts *ts; bool d2h_hostrdy_supported; @@ -1654,9 +1652,6 @@ typedef struct dhd_pub { uint32 ndo_max_host_ip; /* # of host ip addr supported by FW */ #endif /* NDO_CONFIG_SUPPORT */ #if defined(DHD_LOG_DUMP) -#if defined(DHD_EFI) - uint8 log_capture_enable; -#endif /* DHD_EFI */ /* buffer to hold 'dhd dump' data before dumping to file */ uint8 *concise_dbg_buf; uint64 last_file_posn; @@ -1704,11 +1699,6 @@ typedef struct dhd_pub { spinlock_t tdls_lock; #endif /* WLTDLS */ uint pcie_txs_metadata_enable; -#ifdef BTLOG - bool bt_logging; - bool submit_count_WAR; /* submission count WAR */ - bool bt_logging_enabled; -#endif /* BTLOG */ uint wbtext_policy; /* wbtext policy of dongle */ bool wbtext_support; /* for product policy only */ #ifdef PCIE_OOB @@ -1718,10 +1708,6 @@ typedef struct dhd_pub { bool d2h_inband_dw; enum dhd_bus_ds_state ds_state; #endif /* PCIE_INB_DW */ - bool max_dtim_enable; /* use MAX bcn_li_dtim value in suspend mode */ -#ifdef SNAPSHOT_UPLOAD - bool snapshot_upload; -#endif /* SNAPSHOT_UPLOAD */ tput_test_t tput_data; uint64 tput_start_ts; uint64 tput_stop_ts; @@ -1734,28 +1720,14 @@ typedef struct dhd_pub { /* True if deadman_to shall be forced to 0 */ bool gdb_proxy_nodeadman; /* Counter incremented at each firmware stop/go transition. LSB (GDB_PROXY_STOP_MASK) - * is set when firmwar eis stopped, clear when running + * is set when firmware is stopped, clear when running */ uint32 gdb_proxy_stop_count; #endif /* GDB_PROXY */ int debug_dump_subcmd; uint64 debug_dump_time_sec; bool hscb_enable; -#if defined(DHD_AWDL) -#if defined(AWDL_SLOT_STATS) - dhd_awdl_stats_t awdl_stats[AWDL_NUM_SLOTS]; - uint8 awdl_tx_status_slot; /* Slot in which AWDL is active right now */ - void *awdl_stats_lock; /* Lock to protect against parallel AWDL stats updates */ - uint16 awdl_aw_counter; - uint32 pkt_latency; -#endif /* AWDL_SLOT_STATS */ - uint32 awdl_ifidx; - uint16 awdl_seq; - uint8 awdl_minext; - uint8 awdl_presmode; - bool awdl_llc_enabled; -#endif /* DHD_AWDL */ - uint32 logset_prsrv_mask; + uint64 logset_prsrv_mask; #ifdef DHD_PKT_LOGGING struct dhd_pktlog *pktlog; char debug_dump_time_pktlog_str[DEBUG_DUMP_TIME_BUF_LEN]; @@ -1765,7 +1737,7 @@ typedef struct dhd_pub { bool dongle_edl_support; dhd_dma_buf_t edl_ring_mem; #endif /* EWP_EDL */ -#if defined (LINUX) || defined(linux) +#if defined(LINUX) || defined(linux) struct mutex ndev_op_sync; #endif /* defined (LINUX) || defined(linux) */ bool debug_buf_dest_support; @@ -1781,17 +1753,7 @@ typedef struct dhd_pub { #if defined(LINUX) || defined(linux) wait_queue_head_t tx_tput_test_wait; wait_queue_head_t tx_completion_wait; -#ifdef WL_NANHO - void *nanhoi; /* NANHO instance */ -#endif /* WL_NANHO */ #endif /* defined(LINUX) || defined(linux) */ -#ifdef DHD_ERPOM - bool enable_erpom; - pom_func_handler_t pom_wlan_handler; - int (*pom_func_register)(pom_func_handler_t *func); - int (*pom_func_deregister)(pom_func_handler_t *func); - int (*pom_toggle_reg_on)(uchar func_id, uchar reason); -#endif /* DHD_ERPOM */ #if defined(DHD_H2D_LOG_TIME_SYNC) #define DHD_H2D_LOG_TIME_STAMP_MATCH (10000) /* 10 Seconds */ /* @@ -1802,90 +1764,34 @@ typedef struct dhd_pub { #endif /* DHD_H2D_LOG_TIME_SYNC */ uint32 batch_tx_pkts_cmpl; uint32 batch_tx_num_pkts; -#ifdef DHD_EFI - bool insert_random_mac; - /* threshold # of pkts Tx'd/Rx'd after which efi dhd - * will switch intr poll period to 100us - */ - uint64 npkts_thresh; - /* the period of time in which if no pkt is Tx'd/Rx'd - * efi dhd will restore intr poll period to default value - */ - uint64 pkt_intvl_thresh_us; - /* time stamp of last Tx'd pkt */ - uint64 tx_last_pkt_ts; - /* time stamp of last Rx'd pkt */ - uint64 rx_last_pkt_ts; - /* used to temporarily store the current intr poll period - * during efi dhd iovar execution, so as to restore it back - * once iovar completes - */ - uint32 cur_intr_poll_period; - /* the intr poll period set by user through dhd iovar */ - uint32 iovar_intr_poll_period; - bool pcie_readshared_done; -#endif /* DHD_EFI */ #ifdef DHD_DUMP_MNGR struct _dhd_dump_file_manage *dump_file_manage; #endif /* DHD_DUMP_MNGR */ -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE - fwtrace_info_t *fwtrace_info; /* f/w trace information */ -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ bool event_log_max_sets_queried; uint32 event_log_max_sets; #ifdef DHD_STATUS_LOGGING void *statlog; #endif /* DHD_STATUS_LOGGING */ -#ifdef DHD_HP2P - /* whether enabled from host by user iovar */ - bool hp2p_enable; - bool hp2p_infra_enable; - /* whether fw supports it */ - bool hp2p_capable; - bool hp2p_mf_enable; - bool hp2p_ts_capable; - uint16 pkt_thresh; - uint16 time_thresh; - uint16 pkt_expiry; - hp2p_info_t hp2p_info[MAX_HP2P_FLOWS]; - /* Flag to allow more hp2p ring creation */ - bool hp2p_ring_more; -#endif /* D2H_HP2P */ -#ifdef DHD_DB0TS - bool db0ts_capable; -#endif /* DHD_DB0TS */ +#ifdef DHD_MAP_PKTID_LOGGING + bool enable_pktid_log_dump; +#endif /* DHD_MAP_PKTID_LOGGING */ bool extdtxs_in_txcpl; bool hostrdy_after_init; uint16 dhd_induce_error; uint16 dhd_induce_bh_error; int wlc_ver_major; int wlc_ver_minor; -#ifdef DHD_PKTTS - /* stores the packet meta data buffer length queried via iovar */ - uint16 pkt_metadata_version; - uint16 pkt_metadata_buflen; -#endif #ifdef SUPPORT_SET_TID uint8 tid_mode; uint32 target_uid; uint8 target_tid; #endif /* SUPPORT_SET_TID */ -#ifdef CONFIG_SILENT_ROAM - bool sroam_turn_on; /* Silent roam monitor enable flags */ - bool sroamed; /* Silent roam monitor check flags */ -#endif /* CONFIG_SILENT_ROAM */ #ifdef DHD_PKTDUMP_ROAM void *pktcnts; #endif /* DHD_PKTDUMP_ROAM */ dhd_db7_info_t db7_trap; bool fw_preinit; bool ring_attached; -#ifdef DHD_PCIE_RUNTIMEPM - bool rx_pending_due_to_rpm; -#endif /* DHD_PCIE_RUNTIMEPM */ - bool disable_dtim_in_suspend; /* Disable set bcn_li_dtim in suspend */ union { wl_roam_stats_v1_t v1; } roam_evt; @@ -1911,6 +1817,7 @@ typedef struct dhd_pub { uint64 lb_rxp_strt_thr_hitcnt; uint64 lb_rxp_napi_sched_cnt; uint64 lb_rxp_napi_complete_cnt; + uint64 rx_dma_stall_hc_ignore_cnt; #endif /* DHD_LB_STATS */ bool check_trap_rot; /* if FW supports host insertion of SFH LLC */ @@ -1918,6 +1825,55 @@ typedef struct dhd_pub { #ifdef DHD_GRO_ENABLE_HOST_CTRL bool permitted_gro; #endif /* DHD_GRO_ENABLE_HOST_CTRL */ +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT + uint32 alert_reason; /* reason codes for alert event */ +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ +#ifdef DBG_PKT_MON + bool aml_enable; /* aml(assoc mgmt frame logger) enable flags */ +#endif /* DBG_PKT_MON */ + bool fw_mode_changed; + bool do_chip_bighammer; + uint chip_bighammer_count; + bool rx_cpl_lat_capable; /* FW supports latency posting in Rx cpl ring */ + rx_cpl_lat_info_t rxcpl_lat_info; /* Rx Cpl latency information */ + tx_cpl_info_t txcpl_info; /* TX completion timestamp info */ +#ifdef SUPPORT_OTA_UPDATE + ota_update_info_t ota_update_info; +#endif /* SUPPORT_OTA_UPDATE */ +#ifdef CSI_SUPPORT + struct mutex csi_lock; + struct list_head csi_list; + uint csi_count; + uint csi_data_send_manner; +#endif /* CSI_SUPPORT */ + bool stop_in_progress; +#ifdef SYNA_SAR_CUSTOMER_PARAMETER + uint32 dhd_sar_mode; +#endif /* SYNA_SAR_CUSTOMER_PARAMETER */ + + /* Pointer to Platform Layer */ + void *plat_info; + uint32 plat_info_size; + bool htput_support; +#ifdef FLOW_RING_PREALLOC + uint16 non_htput_total_flow_rings; +#endif /* FLOW_RING_PREALLOC */ + bool fw_lpm_support; /* fw supports LPM mode */ + bool igmpo_enable; /* fw supports igmp offload */ +#ifdef DHD_SUPPORT_SPMI_MODE + uint dhd_spmi_mode; +#endif /* DHD_SUPPORT_SPMI_MODE */ + /* Flag to indicate H2D flowring phase nibble value support */ + uint8 fr_phase_nibble; + bool mdring_capable; /* FW supports metadata ring cpl ring */ + uint8 *mdring_info; /* Saved metadta ring work items */ + uint32 md_item_count; /* # of saved metadata work items */ +#if defined(DEVICE_TX_STUCK_DETECT) && defined(ASSOC_CHECK_SR) + /* is infra associated or not before suspend ? */ + bool assoc_at_suspend; +#endif /* DEVICE_TX_STUCK_DETECT && ASSOC_CHECK_SR */ + uint32 p2p_disc_busy_cnt; + bool skip_memdump_map_read; #ifdef CSI_SUPPORT struct list_head csi_list; int csi_count; @@ -1927,6 +1883,9 @@ typedef struct dhd_pub { struct dhd_conf *conf; /* Bus module handle */ void *adapter; /* adapter information, interrupt, fw path etc. */ void *event_params; +#ifdef WL_TIMER + void *timer_params; +#endif /* WL_TIMER */ #ifdef BCMDBUS bool dhd_remove; #endif /* BCMDBUS */ @@ -1957,6 +1916,7 @@ int dhd_wifi_platform_set_power(dhd_pub_t *pub, bool on); static INLINE int dhd_wifi_platform_set_power(dhd_pub_t *pub, bool on) { return 0; } #endif /* __linux__ */ +#define MAX_WAKE_REASON_STATS 32u typedef struct { uint rxwake; uint rcwake; @@ -1965,6 +1925,7 @@ typedef struct { uint rx_arp; uint rx_mcast; uint rx_multi_ipv6; + uint rx_icmp; uint rx_icmpv6; uint rx_icmpv6_ra; uint rx_icmpv6_na; @@ -1974,7 +1935,12 @@ typedef struct { uint rx_ucast; #endif /* DHD_WAKE_RX_STATUS */ #ifdef DHD_WAKE_EVENT_STATUS +#ifdef CUSTOM_WAKE_REASON_STATS + int rc_event[MAX_WAKE_REASON_STATS]; + int rc_event_idx; +#else uint rc_event[WLC_E_LAST]; +#endif /* CUSTOM_WAKE_REASON_STATS */ #endif /* DHD_WAKE_EVENT_STATUS */ } wake_counts_t; @@ -2001,9 +1967,9 @@ typedef struct dhd_pkttag_fd { void *dmah; /* dma mapper handle */ void *secdma; /* secure dma sec_cma_info handle */ #endif /* !DHD_PCIE_PKTID */ -#if defined(TX_STATUS_LATENCY_STATS) || defined(DHD_PKTTS) +#if defined(TX_STATUS_LATENCY_STATS) uint64 q_time_us; /* time when tx pkt queued to flowring */ -#endif /* TX_STATUS_LATENCY_STATS || DHD_PKTTS */ +#endif } dhd_pkttag_fd_t; /* Packet Tag for DHD PCIE Full Dongle */ @@ -2033,11 +1999,11 @@ typedef struct dhd_pkttag_fd { #define DHD_PKT_SET_SECDMA(pkt, pkt_secdma) \ DHD_PKTTAG_FD(pkt)->secdma = (void *)(pkt_secdma) -#if defined(TX_STATUS_LATENCY_STATS) || defined(DHD_PKTTS) +#if defined(TX_STATUS_LATENCY_STATS) #define DHD_PKT_GET_QTIME(pkt) ((DHD_PKTTAG_FD(pkt))->q_time_us) #define DHD_PKT_SET_QTIME(pkt, pkt_q_time_us) \ DHD_PKTTAG_FD(pkt)->q_time_us = (uint64)(pkt_q_time_us) -#endif /* TX_STATUS_LATENCY_STATS || DHD_PKTTS */ +#endif #endif /* PCIE_FULL_DONGLE */ #if defined(BCMWDF) @@ -2198,32 +2164,38 @@ inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) } while (0) #define DHD_PM_WAKE_LOCK_TIMEOUT(pub, val) \ do { \ - printf("call pm_wake_timeout enable\n"); \ - dhd_pm_wake_lock_timeout(pub, val); \ + printf("call pm_wake_timeout enable: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_pm_wake_lock_timeout(pub, val); \ } while (0) #define DHD_PM_WAKE_UNLOCK(pub) \ do { \ - printf("call pm_wake unlock\n"); \ - dhd_pm_wake_unlock(pub); \ + printf("call pm_wake unlock: %s %d\n", \ + __FUNCTION__, __LINE__); \ + dhd_pm_wake_unlock(pub); \ } while (0) #define DHD_TXFL_WAKE_LOCK_TIMEOUT(pub, val) \ do { \ - printf("call pm_wake_timeout enable\n"); \ + printf("call txfl_wake_timeout enable: %s %d\n", \ + __FUNCTION__, __LINE__); \ dhd_txfl_wake_lock_timeout(pub, val); \ } while (0) #define DHD_TXFL_WAKE_UNLOCK(pub) \ do { \ - printf("call pm_wake unlock\n"); \ + printf("call txfl_wake unlock: %s %d\n", \ + __FUNCTION__, __LINE__); \ dhd_txfl_wake_unlock(pub); \ } while (0) #define DHD_NAN_WAKE_LOCK_TIMEOUT(pub, val) \ do { \ - printf("call pm_wake_timeout enable\n"); \ + printf("call nan_wake_timeout enable: %s %d\n", \ + __FUNCTION__, __LINE__); \ dhd_nan_wake_lock_timeout(pub, val); \ } while (0) #define DHD_NAN_WAKE_UNLOCK(pub) \ do { \ - printf("call pm_wake unlock\n"); \ + printf("call nan_wake unlock: %s %d\n", \ + __FUNCTION__, __LINE__); \ dhd_nan_wake_unlock(pub); \ } while (0) #define DHD_OS_WAKE_LOCK_TIMEOUT(pub) \ @@ -2361,10 +2333,20 @@ extern void dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub); #define DHD_OS_OOB_IRQ_WAKE_UNLOCK(pub) dhd_os_oob_irq_wake_unlock(pub) #endif /* BCMPCIE_OOB_HOST_WAKE */ -#define DHD_PACKET_TIMEOUT_MS 500 +/* The DHD_PACKET_TIMEOUT_MS & MAX_TX_TIMEOUT are used for wake_lock timeout + * to prevent the system from entering suspend during TX/RX frame processing. + * It can be adjusted depending on the host platform. + */ +#define DHD_MONITOR_TIMEOUT_MS 1000 +#ifndef DHD_PACKET_TIMEOUT_MS +#define DHD_PACKET_TIMEOUT_MS 100 +#endif +#define DHD_HANDSHAKE_TIMEOUT_MS 1000 #define DHD_EVENT_TIMEOUT_MS 1500 #define SCAN_WAKE_LOCK_TIMEOUT 10000 -#define MAX_TX_TIMEOUT 500 +#ifndef MAX_TX_TIMEOUT +#define MAX_TX_TIMEOUT 100 +#endif /* Enum for IOCTL recieved status */ typedef enum dhd_ioctl_recieved_status @@ -2382,6 +2364,7 @@ typedef enum dhd_ioctl_recieved_status #if defined(LINUX) void dhd_net_if_lock(struct net_device *dev); void dhd_net_if_unlock(struct net_device *dev); +bool dhd_net_if_locked(struct net_device *dev); #endif /* LINUX */ #if defined(LINUX) || defined(linux) @@ -2615,6 +2598,8 @@ extern unsigned int dhd_os_get_ioctl_resp_timeout(void); extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec); extern void dhd_os_ioctl_resp_lock(dhd_pub_t * pub); extern void dhd_os_ioctl_resp_unlock(dhd_pub_t * pub); +extern int dhd_os_read_file(void *file, char *buf, uint32 size); +extern int dhd_os_seek_file(void *file, int64 offset); #ifdef PCIE_FULL_DONGLE extern void dhd_wakeup_ioctl_event(dhd_pub_t *pub, dhd_ioctl_recieved_status_t reason); #else @@ -2627,25 +2612,19 @@ static INLINE void dhd_wakeup_ioctl_event(dhd_pub_t *pub, dhd_ioctl_recieved_sta */ #define DHD_EVENT_LOGTRACE_BOUND 10u #define DHD_EVENT_LOGTRACE_RESCHEDULE_DELAY_MS 10u -extern int dhd_os_read_file(void *file, char *buf, uint32 size); -extern int dhd_os_seek_file(void *file, int64 offset); #endif /* SHOW_LOGTRACE */ int dhd_os_write_file_posn(void *fp, unsigned long *posn, void *buf, unsigned long buflen); int dhd_msix_message_set(dhd_pub_t *dhdp, uint table_entry, uint message_number, bool unmask); -#if defined(DHD_EFI) -void dhd_os_set_intr_poll_period(struct dhd_bus *bus, unsigned int period_us); -unsigned int dhd_os_get_intr_poll_period(void); -int dhd_intr_poll(struct dhd_bus *bus, char *arg, int len, int set); -#define INTR_POLL_PERIOD_CRITICAL 100 /* 100us -- in us */ -#define INTR_POLL_NPKTS_THRESH 1 -#define INTR_POLL_PKT_INTERVAL_THRESH 2000000 /* 2000ms -- in us */ -#if defined(DHD_INTR_POLL_PERIOD_DYNAMIC) -void dhd_intr_poll_pkt_thresholds(dhd_pub_t *dhd); -#endif /* DHD_INTR_POLL_PERIOD_DYNAMIC */ -#endif /* DHD_EFI && DHD_INTR_POLL_PERIOD_DYNAMIC */ +#ifdef DHD_DEBUG +void dhd_convert_memdump_type_to_str(uint32 type, char *buf, size_t buf_len, int substr_type); +#endif /* DHD_DEBUG */ + +#ifdef DHD_COREDUMP +void dhd_convert_hang_reason_to_str(uint32 reason, char *buf, size_t buf_len); +#endif /* DHD_COREDUMP */ extern void dhd_pcie_dump_core_regs(dhd_pub_t * pub, uint32 index, uint32 first_addr, uint32 last_addr); @@ -2675,9 +2654,6 @@ extern void dhdsdio_bus_usr_cnt_dec(dhd_pub_t *pub); extern void *dhd_os_open_image1(dhd_pub_t *pub, char *filename); /* rev1 function signature */ extern void dhd_os_close_image1(dhd_pub_t *pub, void *image); extern void dhd_os_wd_timer(void *bus, uint wdtick); -#ifdef DHD_PCIE_RUNTIMEPM -extern void dhd_os_runtimepm_timer(void *bus, uint tick); -#endif /* DHD_PCIE_RUNTIMEPM */ extern void dhd_os_sdlock(dhd_pub_t * pub); extern void dhd_os_sdunlock(dhd_pub_t * pub); extern void dhd_os_sdlock_txq(dhd_pub_t * pub); @@ -2702,6 +2678,50 @@ extern void get_customized_country_code(void *adapter, char *country_iso_code, #else extern void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec); #endif /* CUSTOM_COUNTRY_CODE */ + +#ifdef SYNA_SAR_CUSTOMER_PARAMETER + +enum sar_para_mode { + SAR_OFF = 0, + HEAD_NORMAL = 1, + HEAD_AIRPLANE = 2, + GRIP_NORMAL = 3, + GRIP_AIRPLANE = 4, + BT_NORMAL = 5, + BT_AIRPLANE = 6, + HOTSPOT_NORMAL = 7, + HOTSPOT_AIRPLANE = 8 +}; + +typedef enum _eCountry_type { + SYNA_COUNTRY_TYPE_DEFAULT, + SYNA_COUNTRY_TYPE_FCC, + SYNA_COUNTRY_TYPE_EU, + SYNA_COUNTRY_TYPE_LATAM, + SYNA_COUNTRY_TYPE_CANADA, + SYNA_COUNTRY_TYPE_JAPAN, + SYNA_COUNTRY_TYPE_QTY, + SYNA_COUNTRY_TYPE_INVALID = SYNA_COUNTRY_TYPE_QTY +} eCountry_flag_type; + +/* SAR parameters from dhd */ +typedef struct _dhd_sar_parameter { + sarctrl_set dynamic; + sarctrl_set grip; + sarctrl_set bt; + sarctrl_set hotspot; +} dhd_sar_parameter; + +extern eCountry_flag_type syna_country_check_type(char *cntry); +extern int syna_country_update_type_list(eCountry_flag_type type, char *list_str); + +extern int dhd_sar_init_parameter(dhd_pub_t *dhd, eCountry_flag_type type, int advance_mode, + char *list_str); +extern int dhd_sar_reset_parameter(void); +extern int dhd_sar_set_parameter(dhd_pub_t *dhd_pub, int advance_mode); + +#endif /* SYNA_SAR_CUSTOMER_PARAMETER */ + extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); @@ -2716,17 +2736,28 @@ extern int dhd_get_instance(dhd_pub_t *pub); extern void dhd_set_cpucore(dhd_pub_t *dhd, int set); #endif /* CUSTOM_SET_CPUCORE */ +#ifdef DHD_DETECT_CONSECUTIVE_MFG_HANG +#define MAX_CONSECUTIVE_MFG_HANG_COUNT 2 +#endif /* DHD_DETECT_CONSECUTIVE_MFG_HANG */ + #if defined(KEEP_ALIVE) extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); #endif /* KEEP_ALIVE */ #if defined(DHD_FW_COREDUMP) +#ifdef LINUX +extern bool dhd_memdump_is_scheduled(dhd_pub_t *dhdp); +#else +static INLINE bool dhd_memdump_is_scheduled(dhd_pub_t *dhdp) { return FALSE; } +#endif /* LINUX */ void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size); #endif /* DHD_FW_COREDUMP */ #if defined(linux) || defined(LINUX) +#ifdef DHD_LINUX_STD_FW_API int dhd_os_get_img_fwreq(const struct firmware **fw, char *file_path); void dhd_os_close_img_fwreq(const struct firmware *fw); +#endif /* DHD_LINUX_STD_FW_API */ #if defined(DHD_SSSR_DUMP) void dhd_write_sssr_dump(dhd_pub_t *dhdp, uint32 dump_mode); #endif /* DHD_SSSR_DUMP */ @@ -2785,7 +2816,6 @@ extern void dhd_enable_packet_filter(int value, dhd_pub_t *dhd); extern int dhd_packet_filter_add_remove(dhd_pub_t *dhdp, int add_remove, int num); extern int net_os_enable_packet_filter(struct net_device *dev, int val); extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); -extern int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val); #define MAX_PKTFLT_BUF_SIZE 2048 #define MAX_PKTFLT_FIXED_PATTERN_SIZE 32 @@ -2794,12 +2824,6 @@ extern int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val); #define MAXPKT_ARG 16 #endif /* PKT_FILTER_SUPPORT */ -#if defined(OEM_ANDROID) && defined(BCMPCIE) -extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd, int *dtim_period, int *bcn_interval); -#else -extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); -#endif /* OEM_ANDROID && BCMPCIE */ - extern bool dhd_support_sta_mode(dhd_pub_t *dhd); extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); @@ -2846,7 +2870,7 @@ typedef struct { } dhd_event_log_t; #endif /* SHOW_LOGTRACE */ -#if defined(PKT_FILTER_SUPPORT) && defined(APF) +#if defined(APF) /* * As per Google's current implementation, there will be only one APF filter. * Therefore, userspace doesn't bother about filter id and because of that @@ -2860,12 +2884,12 @@ extern void dhd_apf_lock(struct net_device *dev); extern void dhd_apf_unlock(struct net_device *dev); extern int dhd_dev_apf_get_version(struct net_device *ndev, uint32 *version); extern int dhd_dev_apf_get_max_len(struct net_device *ndev, uint32 *max_len); -extern int dhd_dev_apf_add_filter(struct net_device *ndev, u8* program, - uint32 program_len); +extern int dhd_dev_apf_add_filter(struct net_device *ndev, u8* program, uint32 program_len); extern int dhd_dev_apf_enable_filter(struct net_device *ndev); extern int dhd_dev_apf_disable_filter(struct net_device *ndev); extern int dhd_dev_apf_delete_filter(struct net_device *ndev); -#endif /* PKT_FILTER_SUPPORT && APF */ +extern int dhd_dev_apf_read_filter_data(struct net_device *ndev, u8* buf, uint32 buf_len); +#endif /* APF */ extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); extern int dhd_timeout_expired(dhd_timeout_t *tmo); @@ -2917,10 +2941,6 @@ extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx); extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); -#ifdef WL_NATOE -extern int dhd_natoe_ct_event(dhd_pub_t *dhd, char *data); -#endif /* WL_NATOE */ - /* Send packet to dongle via data channel */ extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); @@ -2937,6 +2957,9 @@ void dhd_sendup_info_buf(dhd_pub_t *dhdp, uint8 *msg); #if defined(WIFI_TURNON_USE_HALINIT) extern int dhd_open(struct net_device *net); #endif /* WIFI_TURNON_USE_HALINIT */ +#if defined(LINUX) || defined(linux) +extern int dhd_stop(struct net_device *net); +#endif /* LINUX */ extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag); extern uint dhd_bus_status(dhd_pub_t *dhdp); extern int dhd_bus_start(dhd_pub_t *dhdp); @@ -2945,6 +2968,9 @@ extern int dhd_bus_resume(dhd_pub_t *dhdpub, int stage); extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); extern bool dhd_is_associated(dhd_pub_t *dhd, uint8 ifidx, int *retval); +#if defined(LINUX) || defined(linux) +extern bool dhd_scan_associated(dhd_pub_t *dhd, struct net_device *dev); +#endif /* LINUX */ #if defined(BCMSDIO) || defined(BCMPCIE) extern uint dhd_bus_chip_id(dhd_pub_t *dhdp); extern uint dhd_bus_chiprev_id(dhd_pub_t *dhdp); @@ -2966,26 +2992,23 @@ extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); * to use mutexes, other OSes will continue to * use osl_spin_lock */ -#if (defined(LINUX) || defined(linux)) && !defined(DHD_EFI) +#if (defined(LINUX) || defined(linux)) void *dhd_os_dbgring_lock_init(osl_t *osh); void dhd_os_dbgring_lock_deinit(osl_t *osh, void *mtx); unsigned long dhd_os_dbgring_lock(void *lock); void dhd_os_dbgring_unlock(void *lock, unsigned long flags); -#endif /* (LINUX || linux) && !DHD_EFI */ +#endif #ifdef PCIE_INB_DW -#ifdef DHD_EFI -extern int dhd_os_ds_enter_wait(dhd_pub_t * pub, uint * condition); -extern int dhd_os_ds_enter_wake(dhd_pub_t * pub); -#else static INLINE int dhd_os_ds_enter_wait(dhd_pub_t * pub, uint * condition) { return 1; } static INLINE int dhd_os_ds_enter_wake(dhd_pub_t * pub) { return 0; } -#endif /* DHD_EFI */ #endif /* PCIE_INB_DW */ -#if defined(LINUX) || defined(linux) || defined(DHD_EFI) +#define FWBOOT_INTR_TIMEOUT_MS 5000u + +#if defined(LINUX) || defined(linux) extern int dhd_os_busbusy_wait_negation(dhd_pub_t * pub, uint * condition); extern int dhd_os_busbusy_wake(dhd_pub_t * pub); extern void dhd_os_tx_completion_wake(dhd_pub_t *dhd); @@ -3031,7 +3054,7 @@ static INLINE int dhd_os_dmaxfer_wake(dhd_pub_t *pub) static INLINE int dhd_os_busbusy_wait_bitmask(dhd_pub_t *pub, uint *var, uint bitmask, uint condition) { return 0; } -#endif /* LINUX || DHD_EFI */ +#endif /* LINUX || linux */ #if defined(LINUX) || defined(linux) /* @@ -3044,6 +3067,9 @@ extern struct dhd_sta *dhd_find_sta(void *pub, int ifidx, void *ea); extern struct dhd_sta *dhd_findadd_sta(void *pub, int ifidx, void *ea); extern void dhd_del_all_sta(void *pub, int ifidx); extern void dhd_del_sta(void *pub, int ifidx, void *ea); +extern void dhd_update_sta_chanspec_info(void *pub, int ifidx, const uint8 *ea, + chanspec_t chanspec); +extern bool dhd_is_sta_htput(void *pub, int ifidx, void *ea); extern int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx); extern int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val); extern int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx); @@ -3055,11 +3081,19 @@ static INLINE void* dhd_find_sta(void *pub, int ifidx, void *ea) { return NULL;} static INLINE void *dhd_findadd_sta(void *pub, int ifidx, void *ea) { return NULL; } static INLINE void dhd_del_all_sta(void *pub, int ifidx) { } static INLINE void dhd_del_sta(void *pub, int ifidx, void *ea) { } +static INLINE void dhd_update_sta_chanspec_info(void *pub, int ifidx, const uint8 *ea, + chanspec_t chanspec) {} +static INLINE bool dhd_is_sta_htput(void *pub, int ifidx, void *ea) { return FALSE; } static INLINE int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx) { return 0; } static INLINE int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val) { return 0; } static INLINE int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx) { return 0; } #endif /* LINUX */ +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) +dhd_dongledump_status_t dhd_get_dump_status(dhd_pub_t *pub); +void dhd_set_dump_status(dhd_pub_t *pub, dhd_dongledump_status_t status); +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ + extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd); int dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, char *res_buf, uint res_len, bool set); @@ -3098,9 +3132,6 @@ extern void dhd_flush_rx_tx_wq(dhd_pub_t *dhdp); /* Watchdog timer interval */ extern uint dhd_watchdog_ms; extern bool dhd_os_wd_timer_enabled(void *bus); -#ifdef DHD_PCIE_RUNTIMEPM -extern uint dhd_runtimepm_ms; -#endif /* DHD_PCIE_RUNTIMEPM */ /** Default console output poll interval */ extern uint dhd_console_ms; @@ -3148,6 +3179,22 @@ extern uint dhd_radio_up; /* TCM verification control */ extern uint dhd_tcm_test_enable; +/* TCM test status */ +typedef enum tcm_test_status { + TCM_TEST_NOT_RUN = 0, + TCM_TEST_FAILED = 1, + TCM_TEST_PASSED = 2 +} tcm_test_status_t; +extern tcm_test_status_t dhd_tcm_test_status; + +/* TCM test mode */ +typedef enum tcm_test_mode { + TCM_TEST_MODE_DISABLE = 0, + TCM_TEST_MODE_ONCE = 1, + TCM_TEST_MODE_ALWAYS = 2 +} tcm_test_mode_t; +extern tcm_test_mode_t dhd_tcm_test_mode; + /* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ extern int dhd_idletime; #ifdef DHD_USE_IDLECOUNT @@ -3250,6 +3297,18 @@ extern uint dhd_force_tx_queueing; #define CUSTOM_DHD_WATCHDOG_MS DEFAULT_DHD_WATCHDOG_INTERVAL_MS #endif /* DEFAULT_DHD_WATCHDOG_INTERVAL_MS */ +#if defined(DHD_DEBUG) +#ifdef OEM_ANDROID +#define DEFAULT_DHD_CONSOLE_INTERVAL_MS 0 /* android by default disable console msgs */ +#else +#define DEFAULT_DHD_CONSOLE_INTERVAL_MS 250 /* msec */ +#endif /* OEM_ANDROID */ + +#ifndef CUSTOM_DHD_CONSOLE_MS +#define CUSTOM_DHD_CONSOLE_MS DEFAULT_DHD_CONSOLE_INTERVAL_MS +#endif /* DEFAULT_DHD_WATCHDOG_INTERVAL_MS */ +#endif /* DHD_DEBUG */ + #define DHD_INB_DW_DEASSERT_MS 250 #define DEFAULT_ASSOC_RETRY_MAX 3 @@ -3257,7 +3316,7 @@ extern uint dhd_force_tx_queueing; #define CUSTOM_ASSOC_RETRY_MAX DEFAULT_ASSOC_RETRY_MAX #endif /* DEFAULT_ASSOC_RETRY_MAX */ -#if defined(BCMSDIO) || defined(DISABLE_FRAMEBURST) +#if defined(DISABLE_FRAMEBURST) #define DEFAULT_FRAMEBURST_SET 0 #else #define DEFAULT_FRAMEBURST_SET 1 @@ -3289,7 +3348,7 @@ extern uint dhd_force_tx_queueing; #define DEFAULT_BCN_TIMEOUT 6 #else #define DEFAULT_BCN_TIMEOUT 4 -#endif /* CUSTOMER_HW4 && (VSDB || ROAM_ENABLE) */ +#endif #ifndef CUSTOM_BCN_TIMEOUT #define CUSTOM_BCN_TIMEOUT DEFAULT_BCN_TIMEOUT @@ -3354,11 +3413,14 @@ extern int dngl_xtalfreq; extern char fw_path2[MOD_PARAM_PATHLEN]; #endif -#if defined(CUSTOMER_HW4) -#define VENDOR_PATH "/vendor" -#else +#if defined(SUPPORT_MULTIPLE_NVRAM) || defined(SUPPORT_MULTIPLE_CLMBLOB) +#define MAX_HW_INFO_LEN 10u +#define MAX_HW_EXT_LEN (MAX_HW_INFO_LEN * 2) +#define MAX_FILE_COUNT 8u +#define MAX_FILE_LEN 90u +#endif /* SUPPORT_MULTIPLE_NVRAM || SUPPORT_MULTIPLE_CLMBLOB */ + #define VENDOR_PATH "" -#endif /* CUSTOMER_HW4 */ /* Platform path Name - * Used to find out where to find the FW debug support files. @@ -3377,13 +3439,8 @@ extern char fw_path2[MOD_PARAM_PATHLEN]; #define PLATFORM_PATH "/opt/etc/" #else /* End of Overrides, rely on what is dictated by Android */ -#if defined(CUSTOMER_HW4) -#define PLATFORM_PATH "/data/vendor/conn/" -#else #define PLATFORM_PATH "/data/misc/conn/" -#endif /* CUSTOMER_HW4 */ #define DHD_MAC_ADDR_EXPORT -#define DHD_ADPS_BAM_EXPORT #define DHD_EXPORT_CNTL_FILE #define DHD_SOFTAP_DUAL_IF_INFO #define DHD_SEND_HANG_PRIVCMD_ERRORS @@ -3433,6 +3490,7 @@ typedef struct { char nvram_ext[MAX_EXTENSION]; char fw_ext[MAX_EXTENSION]; } naming_info_t; +extern uint32 cur_vid_info; #ifdef DHD_EXPORT_CNTL_FILE extern char cidinfostr[MAX_VNAME_LEN]; #endif /* DHD_EXPORT_CNTL_FILE */ @@ -3476,6 +3534,8 @@ extern naming_info_t * dhd_find_naming_info_by_chip_rev(dhd_pub_t *dhdp, bool *i #define MD_REV_OFF 0 #define A0_REV "_a0" #define B0_REV "_b0" +#define C0_REV "_c0" +#define C1_REV "_c1" extern int dhd_check_stored_module_info(char *vid); extern int concate_nvram_by_vid(dhd_pub_t *dhdp, char *nv_path, char *chipstr); #endif /* USE_DIRECT_VID_TAG */ @@ -3521,6 +3581,7 @@ void dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx); int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx); void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx); #endif /* ARP_OFFLOAD_SUPPORT */ + #ifdef WLTDLS int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac); int dhd_tdls_set_mode(dhd_pub_t *dhd, bool wfd_mode); @@ -3558,10 +3619,11 @@ void dhd_set_bus_state(void *bus, uint32 state); typedef int (*f_droppkt_t)(dhd_pub_t *dhdp, int prec, void* p, bool bPktInQ); extern bool dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn); +extern const uint8 wme_fifo2ac[]; +extern const uint8 prio2fifo[]; #ifdef PROP_TXSTATUS int dhd_os_wlfc_block(dhd_pub_t *pub); int dhd_os_wlfc_unblock(dhd_pub_t *pub); -extern const uint8 prio2fifo[]; #endif /* PROP_TXSTATUS */ int dhd_os_socram_dump(struct net_device *dev, uint32 *dump_size); @@ -3569,6 +3631,7 @@ int dhd_os_get_socram_dump(struct net_device *dev, char **buf, uint32 *size); int dhd_common_socram_dump(dhd_pub_t *dhdp); int dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen); +int dhd_counters(dhd_pub_t *dhdp, char *buf, int buflen); int dhd_os_get_version(struct net_device *dev, bool dhd_ver, char **buf, uint32 size); void dhd_get_memdump_filename(struct net_device *ndev, char *memdump_path, int len, char *fname); @@ -3708,11 +3771,6 @@ extern void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags); #define DHD_PKT_LOG_UNLOCK(lock, flags) osl_spin_unlock(lock, (flags)) #endif /* DHD_PKT_LOGGING */ -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) -#define DHD_AWDL_STATS_LOCK(lock, flags) (flags) = osl_spin_lock(lock) -#define DHD_AWDL_STATS_UNLOCK(lock, flags) osl_spin_unlock(lock, (flags)) -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ - #if defined(linux) || defined(LINUX) #define DHD_LINUX_GENERAL_LOCK(dhdp, flags) DHD_GENERAL_LOCK(dhdp, flags) #define DHD_LINUX_GENERAL_UNLOCK(dhdp, flags) DHD_GENERAL_UNLOCK(dhdp, flags) @@ -3744,8 +3802,9 @@ extern void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags); #define DHD_PKT_WAKE_LOCK(lock, flags) (flags) = osl_spin_lock(lock) #define DHD_PKT_WAKE_UNLOCK(lock, flags) osl_spin_unlock((lock), (flags)) -#define DHD_OOB_IRQ_LOCK(lock, flags) (flags) = osl_spin_lock(lock) -#define DHD_OOB_IRQ_UNLOCK(lock, flags) osl_spin_unlock((lock), (flags)) +/* wlan_oob_irq is called in hard irq context */ +#define DHD_OOB_IRQ_LOCK(lock, flags) (flags) = osl_spin_lock_irq(lock) +#define DHD_OOB_IRQ_UNLOCK(lock, flags) osl_spin_unlock_irq((lock), (flags)) #define DHD_IF_STA_LIST_LOCK(lock, flags) (flags) = osl_spin_lock(lock) #define DHD_IF_STA_LIST_UNLOCK(lock, flags) osl_spin_unlock((lock), (flags)) @@ -3864,8 +3923,13 @@ int dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path); #ifdef SHOW_LOGTRACE int dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size, dhd_event_log_t *event_log); +#ifdef DHD_LINUX_STD_FW_API +int dhd_parse_map_file(osl_t *osh, const void *ptr, uint32 *ramstart, + uint32 *rodata_start, uint32 *rodata_end); +#else int dhd_parse_map_file(osl_t *osh, void *file, uint32 *ramstart, uint32 *rodata_start, uint32 *rodata_end); +#endif /* DHD_LINUX_STD_FW_API */ #ifdef PCIE_FULL_DONGLE int dhd_event_logtrace_infobuf_pkt_process(dhd_pub_t *dhdp, void *pktbuf, dhd_event_log_t *event_data); @@ -3891,10 +3955,6 @@ typedef enum logtrace_ctrl { extern uint8 control_logtrace; -#ifdef BTLOG -int dhd_bt_log_pkt_process(dhd_pub_t *dhdp, void *pktbuf); -#endif /* BTLOG */ - #if defined(NDIS) bool dhd_is_device_removed(dhd_pub_t *dhd); #else @@ -3925,6 +3985,22 @@ static INLINE void dhd_get_assert_info(dhd_pub_t *dhd) { } #if defined(PCIE_FULL_DONGLE) extern void dmaxfer_free_prev_dmaaddr(dhd_pub_t *dhdp, dmaxref_mem_map_t *dmmap); void dhd_schedule_dmaxfer_free(dhd_pub_t *dhdp, dmaxref_mem_map_t *dmmap); + +extern int ring_size_version; + +extern uint h2d_max_txpost; +extern uint h2d_htput_max_txpost; +extern uint d2h_max_txcpl; + +extern uint h2d_max_rxpost; +extern uint d2h_max_rxcpl; + +extern uint h2d_max_ctrlpost; +extern uint d2h_max_ctrlcpl; + +extern uint rx_buf_burst; +extern uint rx_bufpost_threshold; + #endif /* PCIE_FULL_DONGLE */ #define DHD_LB_STATS_NOOP do { /* noop */ } while (0) @@ -3966,9 +4042,9 @@ extern void dhd_lb_stats_rxc_percpu_cnt_incr(dhd_pub_t *dhdp); #define DHD_LB_STATS_UPDATE_NAPI_HISTO(dhd, x) DHD_LB_STATS_NOOP #endif /* !DHD_LB_STATS */ -#ifdef BCMDBG +#if defined(BCMDBG) && defined(DHD_MACDBG) extern void dhd_schedule_macdbg_dump(dhd_pub_t *dhdp); -#endif /* BCMDBG */ +#endif /* BCMDBG && DHD_MACDBG */ #ifdef DHD_SSSR_DUMP #ifdef DHD_SSSR_DUMP_BEFORE_SR @@ -4012,11 +4088,28 @@ extern uint dhd_sssr_mac_xmtdata(dhd_pub_t *dhdp, uint8 core_idx); #define DHD_SSSR_REG_INFO_DEINIT(dhdp) do { /* noop */ } while (0) #endif /* DHD_SSSR_DUMP */ +#ifdef DHD_COREDUMP +#define WLAN_DHD_MEMDUMP_SIZE (3u * 1024u * 1024u) +#ifdef DHD_SSSR_DUMP +#define DHD_MEMDUMP_BUFFER_SIZE (WLAN_DHD_MEMDUMP_SIZE + DHD_SSSR_MEMPOOL_SIZE) +#else +#define DHD_MEMDUMP_BUFFER_SIZE (WLAN_DHD_MEMDUMP_SIZE) +#endif +extern int dhd_coredump_mempool_init(dhd_pub_t *dhd); +extern void dhd_coredump_mempool_deinit(dhd_pub_t *dhd); +#define DHD_COREDUMP_MEMPOOL_INIT(dhdp) dhd_coredump_mempool_init(dhdp) +#define DHD_COREDUMP_MEMPOOL_DEINIT(dhdp) dhd_coredump_mempool_deinit(dhdp) +#else +#define DHD_COREDUMP_MEMPOOL_INIT(dhdp) do { /* noop */ } while (0) +#define DHD_COREDUMP_MEMPOOL_DEINIT(dhdp) do { /* noop */ } while (0) +#endif /* DHD_COREDUMP */ + #ifdef BCMPCIE extern int dhd_prot_debug_info_print(dhd_pub_t *dhd); extern bool dhd_bus_skip_clm(dhd_pub_t *dhdp); extern void dhd_pcie_dump_rc_conf_space_cap(dhd_pub_t *dhd); extern bool dhd_pcie_dump_int_regs(dhd_pub_t *dhd); +void dhd_prot_ctrl_info_print(dhd_pub_t *dhd); #else #define dhd_prot_debug_info_print(x) static INLINE bool dhd_bus_skip_clm(dhd_pub_t *dhd_pub) @@ -4034,7 +4127,7 @@ static INLINE void dhd_show_kirqstats(dhd_pub_t *dhd) #define WLC_SSID_MASK 0x01 #define WLC_WPA_MASK 0x02 -#if defined(LINUX) || defined(linux) || defined(DHD_EFI) +#if defined(LINUX) || defined(linux) fw_download_status_t dhd_fw_download_status(dhd_pub_t *dhd_pub); extern int dhd_start_join_timer(dhd_pub_t *pub); extern int dhd_stop_join_timer(dhd_pub_t *pub); @@ -4099,57 +4192,14 @@ static INLINE void dhd_pktid_logging_dump(dhd_pub_t *dhdp) { } #endif /* LINUX || linux */ #endif /* DHD_MAP_PKTID_LOGGING */ -#ifdef DHD_PCIE_RUNTIMEPM -#define DEFAULT_DHD_RUNTIME_MS 100 -#ifndef CUSTOM_DHD_RUNTIME_MS -#define CUSTOM_DHD_RUNTIME_MS DEFAULT_DHD_RUNTIME_MS -#endif /* CUSTOM_DHD_RUNTIME_MS */ - -#ifndef MAX_IDLE_COUNT -#define MAX_IDLE_COUNT 11 -#endif /* MAX_IDLE_COUNT */ - -extern bool dhd_runtimepm_state(dhd_pub_t *dhd); -extern bool dhd_runtime_bus_wake(struct dhd_bus *bus, bool wait, void *func_addr); -extern bool dhdpcie_runtime_bus_wake(dhd_pub_t *dhdp, bool wait, void *func_addr); -extern void dhdpcie_block_runtime_pm(dhd_pub_t *dhdp); -extern bool dhdpcie_is_resume_done(dhd_pub_t *dhdp); -extern void dhd_runtime_pm_disable(dhd_pub_t *dhdp); -extern void dhd_runtime_pm_enable(dhd_pub_t *dhdp); -/* Disable the Runtime PM thread and wake up if the bus is already in suspend */ -#define DHD_DISABLE_RUNTIME_PM(dhdp) \ -do { \ - dhd_runtime_pm_disable(dhdp); \ -} while (0); - -/* Enable the Runtime PM thread */ -#define DHD_ENABLE_RUNTIME_PM(dhdp) \ -do { \ - dhd_runtime_pm_enable(dhdp); \ -} while (0); - -/* Stop the timer and disable RPM thread */ -#define DHD_STOP_RPM_TIMER(dhdp) \ -do { \ - dhd_os_runtimepm_timer(dhdp, 0); \ - DHD_DISABLE_RUNTIME_PM(dhdp) \ -} while (0); - -/* Start the timer and enable RPM thread */ -#define DHD_START_RPM_TIMER(dhdp) \ -do { \ - dhd_os_runtimepm_timer(dhdp, dhd_runtimepm_ms); \ - DHD_ENABLE_RUNTIME_PM(dhdp) \ -} while (0); -#else #define DHD_DISABLE_RUNTIME_PM(dhdp) #define DHD_ENABLE_RUNTIME_PM(dhdp) #define DHD_STOP_RPM_TIMER(dhdp) #define DHD_START_RPM_TIMER(dhdp) -#endif /* DHD_PCIE_RUNTIMEPM */ -extern bool dhd_prot_is_cmpl_ring_empty(dhd_pub_t *dhd, void *prot_info); +extern bool dhd_prot_is_h2d_ring_empty(dhd_pub_t *dhd, void *prot_info); extern void dhd_prot_dump_ring_ptrs(void *prot_info); +extern bool dhd_prot_check_pending_ctrl_cmpls(dhd_pub_t *dhd); #if defined(LINUX) || defined(linux) #if defined(DHD_TRACE_WAKE_LOCK) @@ -4162,16 +4212,9 @@ void dhd_clear_bus_errors(dhd_pub_t *dhdp); #if (defined(linux) || defined(LINUX)) && defined(CONFIG_64BIT) #define DHD_SUPPORT_64BIT -#elif defined(DHD_EFI) -#define DHD_SUPPORT_64BIT -/* by default disabled for other platforms, can enable appropriate macro to enable 64 bit support */ #endif /* (linux || LINUX) && CONFIG_64BIT */ -#if defined(DHD_EFI) || defined(DHD_ERPOM) -extern void dhd_schedule_reset(dhd_pub_t *dhdp); -#else static INLINE void dhd_schedule_reset(dhd_pub_t *dhdp) {;} -#endif /* DHD_EFI || DHD_ERPOM */ extern void init_dhd_timeouts(dhd_pub_t *pub); extern void deinit_dhd_timeouts(dhd_pub_t *pub); @@ -4190,15 +4233,11 @@ void dhd_send_trap_to_fw_for_timeout(dhd_pub_t * pub, timeout_reasons_t reason); extern int dhd_bus_set_device_wake(struct dhd_bus *bus, bool val); extern void dhd_bus_dw_deassert(dhd_pub_t *dhd); #endif /* defined(PCIE_OOB) || defined(PCIE_INB_DW) */ -extern void dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint8 dbg_level); +extern void dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint32 dbg_level); int dhd_tput_test(dhd_pub_t *dhd, tput_test_t *tput_data); void dhd_tput_test_rx(dhd_pub_t *dhd, void *pkt); -#ifdef DHD_EFI -int dhd_get_max_txbufs(dhd_pub_t *dhdp); -#else static INLINE int dhd_get_max_txbufs(dhd_pub_t *dhdp) { return -1; } -#endif #ifdef FILTER_IE int dhd_read_from_file(dhd_pub_t *dhd); @@ -4223,14 +4262,6 @@ extern void dhd_set_irq_cpucore(dhd_pub_t *dhdp, int affinity_cmd); #if defined(DHD_HANG_SEND_UP_TEST) extern void dhd_make_hang_with_reason(struct net_device *dev, const char *string_num); #endif /* DHD_HANG_SEND_UP_TEST */ -#ifdef BTLOG -extern void dhd_rx_bt_log(dhd_pub_t *dhdp, void *pkt); -#endif /* BTLOG */ - -#ifdef DHD_RND_DEBUG -int dhd_dump_rnd_info(dhd_pub_t *dhd, uint8 *rnd_buf, uint32 rnd_len); -int dhd_get_rnd_info(dhd_pub_t *dhd); -#endif /* DHD_RND_DEBUG */ #ifdef DHD_WAKE_STATUS wake_counts_t* dhd_get_wakecount(dhd_pub_t *dhdp); @@ -4241,97 +4272,11 @@ extern int dhd_get_random_bytes(uint8 *buf, uint len); extern void dhd_set_blob_support(dhd_pub_t *dhdp, char *fw_path); #endif /* DHD_BLOB_EXISTENCE_CHECK */ -int dhd_get_preserve_log_numbers(dhd_pub_t *dhd, uint32 *logset_mask); -#ifdef DHD_LOG_DUMP -void dhd_schedule_log_dump(dhd_pub_t *dhdp, void *type); -void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd); -#endif - -#ifdef DHD_LOG_DUMP -int dhd_log_dump_ring_to_file(dhd_pub_t *dhdp, void *ring_ptr, void *file, - unsigned long *file_posn, log_dump_section_hdr_t *sec_hdr, char *text_hdr, - uint32 sec_type); -int dhd_dump_debug_ring(dhd_pub_t *dhdp, void *ring_ptr, const void *user_buf, - log_dump_section_hdr_t *sec_hdr, char *text_hdr, int buflen, uint32 sec_type); -int dhd_log_dump_cookie_to_file(dhd_pub_t *dhdp, void *fp, - const void *user_buf, unsigned long *f_pos); -int dhd_log_dump_cookie(dhd_pub_t *dhdp, const void *user_buf); -uint32 dhd_log_dump_cookie_len(dhd_pub_t *dhdp); -int dhd_logdump_cookie_init(dhd_pub_t *dhdp, uint8 *buf, uint32 buf_size); -void dhd_logdump_cookie_deinit(dhd_pub_t *dhdp); -void dhd_logdump_cookie_save(dhd_pub_t *dhdp, char *cookie, char *type); -int dhd_logdump_cookie_get(dhd_pub_t *dhdp, char *ret_cookie, uint32 buf_size); -int dhd_logdump_cookie_count(dhd_pub_t *dhdp); -int dhd_get_dld_log_dump(void *dev, dhd_pub_t *dhdp, const void *user_buf, void *fp, - uint32 len, int type, void *pos); -#if defined(BCMPCIE) -int dhd_print_ext_trap_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos); -uint32 dhd_get_ext_trap_len(void *ndev, dhd_pub_t *dhdp); -#endif /* BCMPCIE */ -int dhd_print_dump_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos); -int dhd_print_cookie_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos); -int dhd_print_health_chk_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos); -int dhd_print_time_str(const void *user_buf, void *fp, uint32 len, void *pos); -#ifdef DHD_DUMP_PCIE_RINGS -int dhd_print_flowring_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos); -uint32 dhd_get_flowring_len(void *ndev, dhd_pub_t *dhdp); -#endif /* DHD_DUMP_PCIE_RINGS */ -#ifdef DHD_STATUS_LOGGING -extern int dhd_print_status_log_data(void *dev, dhd_pub_t *dhdp, - const void *user_buf, void *fp, uint32 len, void *pos); -extern uint32 dhd_get_status_log_len(void *ndev, dhd_pub_t *dhdp); -#endif /* DHD_STATUS_LOGGING */ -int dhd_print_ecntrs_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos); -int dhd_print_rtt_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos); -int dhd_get_debug_dump_file_name(void *dev, dhd_pub_t *dhdp, - char *dump_path, int size); -uint32 dhd_get_time_str_len(void); -uint32 dhd_get_health_chk_len(void *ndev, dhd_pub_t *dhdp); -uint32 dhd_get_dhd_dump_len(void *ndev, dhd_pub_t *dhdp); -uint32 dhd_get_cookie_log_len(void *ndev, dhd_pub_t *dhdp); -uint32 dhd_get_ecntrs_len(void *ndev, dhd_pub_t *dhdp); -uint32 dhd_get_rtt_len(void *ndev, dhd_pub_t *dhdp); -uint32 dhd_get_dld_len(int log_type); -void dhd_init_sec_hdr(log_dump_section_hdr_t *sec_hdr); -extern char *dhd_log_dump_get_timestamp(void); -bool dhd_log_dump_ecntr_enabled(void); -bool dhd_log_dump_rtt_enabled(void); -void dhd_nla_put_sssr_dump_len(void *ndev, uint32 *arr_len); -int dhd_get_debug_dump(void *dev, const void *user_buf, uint32 len, int type); -#ifdef DHD_SSSR_DUMP_BEFORE_SR -int -dhd_sssr_dump_d11_buf_before(void *dev, const void *user_buf, uint32 len, int core); -int -dhd_sssr_dump_dig_buf_before(void *dev, const void *user_buf, uint32 len); -#endif /* DHD_SSSR_DUMP_BEFORE_SR */ -int -dhd_sssr_dump_d11_buf_after(void *dev, const void *user_buf, uint32 len, int core); -int -dhd_sssr_dump_dig_buf_after(void *dev, const void *user_buf, uint32 len); -#ifdef DHD_PKT_LOGGING -extern int dhd_os_get_pktlog_dump(void *dev, const void *user_buf, uint32 len); -extern uint32 dhd_os_get_pktlog_dump_size(struct net_device *dev); -extern void dhd_os_get_pktlogdump_filename(struct net_device *dev, char *dump_path, int len); -#endif /* DHD_PKT_LOGGING */ - -#ifdef DNGL_AXI_ERROR_LOGGING -extern int dhd_os_get_axi_error_dump(void *dev, const void *user_buf, uint32 len); -extern int dhd_os_get_axi_error_dump_size(struct net_device *dev); -extern void dhd_os_get_axi_error_filename(struct net_device *dev, char *dump_path, int len); -#endif /* DNGL_AXI_ERROR_LOGGING */ - -#endif /* DHD_LOG_DUMP */ +int dhd_get_preserve_log_numbers(dhd_pub_t *dhd, uint64 *logset_mask); #define DHD_WORD_TO_LEN_SHIFT (2u) /* WORD to BYTES SHIFT */ -#if defined(linux) || defined(LINUX) || defined(DHD_EFI) +#if defined(linux) || defined(LINUX) int dhd_export_debug_data(void *mem_buf, void *fp, const void *user_buf, uint32 buf_len, void *pos); #else static int dhd_export_debug_data(void *mem_buf, void *fp, const void *user_buf, @@ -4341,7 +4286,7 @@ static int dhd_export_debug_data(void *mem_buf, void *fp, const void *user_buf, #if defined(linux) || defined(LINUX) #define DHD_PCIE_CONFIG_SAVE(bus) pci_save_state(bus->dev) #define DHD_PCIE_CONFIG_RESTORE(bus) pci_restore_state(bus->dev) -#elif defined(DHD_EFI) || defined(NDIS) +#elif defined(NDIS) /* For EFI the pcie config space which is saved during init * is the one that should always be restored, so NOP for save */ @@ -4396,6 +4341,8 @@ void dhd_ring_whole_unlock(void *ring); #define DHD_GDB_PROXY_PROBE_BOOTLOADER_MODE 0x00000008 /** Host memory code offload present */ #define DHD_GDB_PROXY_PROBE_HOSTMEM_CODE 0x00000010 +/** Memory dump count field present */ +#define DHD_GDB_PROXY_PROBE_MEMDUMP_COUNT 0x00000020 /* Data structure, returned by "gdb_proxy_probe" iovar */ typedef struct dhd_gdb_proxy_probe_data { @@ -4406,15 +4353,42 @@ typedef struct dhd_gdb_proxy_probe_data { uint32 hostmem_code_win_base; /* Hostmem code window start in ARM physical address space */ uint32 hostmem_code_win_length; /* Hostmem code window length */ + uint32 mem_dump_count; /* Number of memory dumps made so far */ } dhd_gdb_proxy_probe_data_t; -#endif /* GDB_PROXY */ -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) -void dhd_clear_awdl_stats(dhd_pub_t *dhd); -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ -#ifdef DHD_EFI -extern void dhd_insert_random_mac_addr(dhd_pub_t *dhd, char *nvram_mem, uint *len); -#endif /* DHD_EFI */ +/* Timeout loop brackets */ +/* Intended usage is to keep repeating timeoutable operation (operation that expected to + * succeed but may fail because of timeout) while timeout may be explained by firmware + * stop in gdb + * Example: + * dhd_pub_t *dhd; + * ... + * #ifdef GDB_PROXY + * GDB_PROXY_TIMEOUT_DO(dhd) { + * operation_that_may_succeed_or_timeout(); + * } GDB_PROXY_TIMEOUT_WHILE(operation_timed_out()); + * #else + * operation_that_may_succeed_or_timeout(); + * #endif + * ... + * if (operation_timed_out()) { + * bang_memdump_crash_horror(); + * } + */ +/* Argument is pointer to dhd_pub_t structure */ +#define GDB_PROXY_TIMEOUT_DO(dhd) \ +{ \ + uint32 gdb_prev_stop_count; \ + dhd_pub_t *gdb_dhd = dhd; \ + do { \ + gdb_prev_stop_count = gdb_dhd->gdb_proxy_stop_count; + +/* Argument should evaluate to true if operation failed because of timeout */ +#define GDB_PROXY_TIMEOUT_WHILE(timeout_cond) \ + } while ((timeout_cond) && ((gdb_dhd->gdb_proxy_stop_count != gdb_prev_stop_count) || \ + (gdb_dhd->gdb_proxy_stop_count & GDB_PROXY_STOP_MASK))); \ +} +#endif /* GDB_PROXY */ #ifdef PKT_FILTER_SUPPORT extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); @@ -4444,20 +4418,6 @@ void dhd_prot_edl_ring_tcm_rd_update(dhd_pub_t *dhd); #define DHD_EDL_RING_TCM_RD_UPDATE(dhdp) do { /* noop */ } while (0) #endif /* EWP_EDL */ -#ifdef BIGDATA_SOFTAP -void dhd_schedule_gather_ap_stadata(void *bcm_cfg, void *ndev, const wl_event_msg_t *e); -#endif /* BIGDATA_SOFTAP */ - -#ifdef DHD_PKTTS -int dhd_get_pktts_enab(dhd_pub_t *dhdp); -int dhd_set_pktts_enab(dhd_pub_t *dhdp, bool val); - -int dhd_get_pktts_flow(dhd_pub_t *dhdp, void *args, int len); -int dhd_set_pktts_flow(dhd_pub_t *dhdp, void *params, int plen); -pktts_flow_t *dhd_match_pktts_flow(dhd_pub_t *dhdp, uint32 checksum, - uint32 *idx, uint32 *num_config); -#endif /* DHD_PKTTS */ - #if defined(DHD_H2D_LOG_TIME_SYNC) void dhd_h2d_log_time_sync_deferred_wq_schedule(dhd_pub_t *dhdp); void dhd_h2d_log_time_sync(dhd_pub_t *dhdp); @@ -4498,11 +4458,6 @@ extern void dhd_dump_file_manage_enqueue(dhd_pub_t *dhd, char *dump_path, char * #define HD_PREFIX_SIZE 2 /* hexadecimal prefix size */ #define HD_BYTE_SIZE 2 /* hexadecimal byte size */ -#ifdef DHD_HP2P -extern unsigned long dhd_os_hp2plock(dhd_pub_t *pub); -extern void dhd_os_hp2punlock(dhd_pub_t *pub, unsigned long flags); -#endif /* DHD_HP2P */ - #ifdef DNGL_AXI_ERROR_LOGGING extern void dhd_axi_error(dhd_pub_t *dhd); #ifdef DHD_USE_WQ_FOR_DNGL_AXI_ERROR @@ -4532,6 +4487,9 @@ enum dhd_set_tid_mode { /* Change TID for UDP frames based on UID */ SET_TID_BASED_ON_UID }; + +#define DEFAULT_SET_TID_TARGET_UID 0 +#define DEFAULT_SET_TID_TARGET_PRIO 0 #if defined(linux) || defined(LINUX) extern void dhd_set_tid_based_on_uid(dhd_pub_t *dhdp, void *pkt); #else @@ -4550,6 +4508,18 @@ typedef wlc_sroam_info_v1_t wlc_sroam_info_t; #define FILE_NAME_HAL_TAG "_hal" /* The tag name concatenated by HAL */ #endif /* DHD_DUMP_FILE_WRITE_FROM_KERNEL */ +void dhd_bus_counters(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); + +#define DHD_HISTOGRAM_ENTRIES (14u) +#define DHD_HISTOGRAM_SIZE (sizeof(uint64) * DHD_HISTOGRAM_ENTRIES) + +void dhd_histo_update(dhd_pub_t *dhd, uint64 *histo, uint32 value); +void dhd_histo_clear(dhd_pub_t *dhd, uint64 *histo); +void dhd_histo_tag_dump(dhd_pub_t *dhd, struct bcmstrbuf *strbuf, char *tagname); +void dhd_histo_dump(dhd_pub_t *dhd, struct bcmstrbuf *strbuf, uint64 *histo, char *histoname); +uint64 *dhd_histo_init(dhd_pub_t *dhd); +void dhd_histo_deinit(dhd_pub_t *dhd, uint64 *histo); + /* Given a number 'n' returns 'm' that is next larger power of 2 after n */ static inline uint32 next_larger_power2(uint32 num) { @@ -4566,11 +4536,8 @@ static inline uint32 next_larger_power2(uint32 num) extern struct dhd_if * dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx); uint8 dhd_d11_slices_num_get(dhd_pub_t *dhdp); -#ifdef WL_AUTO_QOS -extern void dhd_wl_sock_qos_set_status(dhd_pub_t *dhdp, unsigned long on_off); -#endif /* WL_AUTO_QOS */ -void *dhd_get_roam_evt(dhd_pub_t *dhdp); +extern void *dhd_get_roam_evt(dhd_pub_t *dhdp); #if defined(DISABLE_HE_ENAB) || defined(CUSTOM_CONTROL_HE_ENAB) extern int dhd_control_he_enab(dhd_pub_t * dhd, uint8 he_enab); extern uint8 control_he_enab; @@ -4584,9 +4551,13 @@ extern void dhd_sdtc_etb_mempool_deinit(dhd_pub_t *dhd); extern void dhd_sdtc_etb_init(dhd_pub_t *dhd); extern void dhd_sdtc_etb_deinit(dhd_pub_t *dhd); extern void dhd_sdtc_etb_dump(dhd_pub_t *dhd); +extern int dhd_sdtc_etb_hal_file_dump(void *dev, const void *user_buf, uint32 len); #endif /* DHD_SDTC_ETB_DUMP */ #ifdef DHD_TX_PROFILE +/* whether or not a dhd_tx_profile_protocol_t matches with data in a packet */ +bool dhd_protocol_matches_profile(uint8 *p, int plen, + const dhd_tx_profile_protocol_t *proto, bool is_host_sfhllc); int dhd_tx_profile_attach(dhd_pub_t *dhdp); int dhd_tx_profile_detach(dhd_pub_t *dhdp); #endif /* defined (DHD_TX_PROFILE) */ @@ -4596,15 +4567,23 @@ uint32 dhd_lb_rxp_process_qlen(dhd_pub_t *dhdp); * To avoid OOM, Flow control will be kicked in when packet size in process_queue * crosses LB_RXP_STOP_THR * rcpl ring size * 1500(pkt size) and will stop * when it goes below LB_RXP_STRT_THR * rcpl ring size * 1500(pkt size) + * By default flow control is diabled. i.e tunables set to 0/0. + * to enable flow control, these tunables need to be passed from platform Makefiles. */ -#define LB_RXP_STOP_THR 200 /* 200 * 1024 * 1500 = 300MB */ -#define LB_RXP_STRT_THR 199 /* 199 * 1024 * 1500 = 291MB */ +#ifndef LB_RXP_STOP_THR +#define LB_RXP_STOP_THR 0 +#endif /* LB_RXP_STOP_THR */ +#ifndef LB_RXP_STRT_THR +#define LB_RXP_STRT_THR 0 +#endif /* LB_RXP_STRT_THR */ + #endif /* DHD_LB_RXP */ #ifdef DHD_SUPPORT_HDM extern bool hdm_trigger_init; extern int dhd_module_init_hdm(void); extern void dhd_hdm_wlan_sysfs_init(void); extern void dhd_hdm_wlan_sysfs_deinit(struct work_struct *); +extern int hdm_wifi_support; #define SYSFS_DEINIT_MS 10 #endif /* DHD_SUPPORT_HDM */ @@ -4617,14 +4596,14 @@ void dhd_ctrl_tcp_limit_output_bytes(int level); #if defined(__linux__) extern void dhd_schedule_delayed_dpc_on_dpc_cpu(dhd_pub_t *dhdp, ulong delay); extern void dhd_handle_pktdata(dhd_pub_t *dhdp, int ifidx, void *pkt, uint8 *pktdata, - uint32 pktid, uint32 pktlen, uint16 *pktfate, uint8 *dhd_udr, bool tx, int pkt_wake, - bool pkt_log); + uint32 pktid, uint32 pktlen, uint16 *pktfate, uint8 *dhd_udr, uint8 *dhd_igmp, + bool tx, int pkt_wake, bool pkt_log); #else static INLINE void dhd_schedule_delayed_dpc_on_dpc_cpu(dhd_pub_t *dhdp, ulong delay) { return; } static INLINE void dhd_handle_pktdata(dhd_pub_t *dhdp, int ifidx, void *pkt, uint8 *pktdata, - uint32 pktid, uint32 pktlen, uint16 *pktfate, uint8 *dhd_udr, bool tx, int pkt_wake, - bool pkt_log) { return; } + uint32 pktid, uint32 pktlen, uint16 *pktfate, uint8 *dhd_udr, uint8 *dhd_igmp, + bool tx, int pkt_wake, bool pkt_log) { return; } #endif /* __linux */ #if defined(BCMPCIE) && defined(__linux__) @@ -4634,23 +4613,160 @@ static INLINE int dhd_check_shinfo_nrfrags(dhd_pub_t *dhdp, void *pktbuf, dmaadd uint32 pktid) { return BCME_OK; } #endif /* BCMPCIE && __linux__ */ -#ifdef HOST_SFH_LLC -int dhd_ether_to_8023_hdr(osl_t *osh, struct ether_header *eh, void *p); -int dhd_8023_llc_to_ether_hdr(osl_t *osh, struct ether_header *eh8023, void *p); -#endif int dhd_schedule_socram_dump(dhd_pub_t *dhdp); -#ifdef DHD_AWDL -int dhd_ether_to_awdl_llc_hdr(struct dhd_pub *dhd, struct ether_header *eh, void *p); -int dhd_awdl_llc_to_eth_hdr(struct dhd_pub *dhd, struct ether_header *eh, void *p); -#endif /* DHD_AWDL */ +extern int dhd_dev_set_accel_force_reg_on(struct net_device *dev); -#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING +#if defined(DHD_DEBUGABILITY_LOG_DUMP_RING) || defined(DHD_DEBUGABILITY_EVENT_RING) #ifndef DEBUGABILITY -#error "DHD_DEBUGABILITY_LOG_DUMP_RING without DEBUGABILITY" +#error "DHD_DEBUGABILITY_LOG_DUMP_RING or DHD_DEBUGABILITY_EVENT_RING without DEBUGABILITY" #endif /* DEBUGABILITY */ -#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ +#endif /* defined(DHD_DEBUGABILITY_LOG_DUMP_RING) || defined(DHD_DEBUGABILITY_EVENT_RING) */ +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT +typedef enum dhd_alert_reason_codes { + ALERT_BCN_LOST = 0, + ALERT_TX_STALL = 1, + ALERT_RX_STALL = 2, + ALERT_IOCTL_TIMEOUT = 3, + ALERT_DONGLE_TRAP = 4, + ALERT_SCAN_STALL = 5, + ALERT_SCAN_ERR = 6, + ALERT_SCAN_BUSY = 7, + ALERT_FW_QUEUE_STALL = 8 +} dhd_alert_reason_codes_t; +int dhd_os_send_alert_message(dhd_pub_t *dhdp); +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ + +#ifdef RX_PKT_POOL +#define MAX_RX_PKT_POOL (1024) +void dhd_rx_pktpool_create(struct dhd_info *dhd, uint16 len); +void * BCMFASTPATH(dhd_rxpool_pktget)(osl_t *osh, struct dhd_info *dhd, uint16 len); +#endif /* RX_PKT_POOL */ + +int dhd_rxf_thread(void *data); +void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb); +int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val); + +#if defined(__linux__) +#ifdef DHD_SUPPORT_VFS_CALL +static INLINE struct file *dhd_filp_open(const char *filename, int flags, int mode) +{ + return filp_open(filename, flags, mode); +} + +static INLINE int dhd_filp_close(void *image, void *id) +{ + return filp_close((struct file *)image, id); +} + +static INLINE int dhd_i_size_read(const struct inode *inode) +{ + return i_size_read(inode); +} + +static INLINE int dhd_kernel_read_compat(struct file *fp, loff_t pos, void *buf, size_t count) +{ + return kernel_read_compat(fp, pos, buf, count); +} + +static INLINE int dhd_vfs_read(struct file *filep, char *buf, size_t size, loff_t *pos) +{ + return vfs_read(filep, buf, size, pos); +} + +static INLINE int dhd_vfs_write(struct file *filep, char *buf, size_t size, loff_t *pos) +{ + return vfs_write(filep, buf, size, pos); +} + +static INLINE int dhd_vfs_fsync(struct file *filep, int datasync) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) + return vfs_fsync(filep, datasync); +#else + return vfs_fsync(filep, filep->f_path.dentry, 0); +#endif +} + +static INLINE long dhd_vfs_size_read(struct file *fp) +{ + return dhd_i_size_read(file_inode(fp)); +} + +static INLINE int dhd_kern_path(char *name, int flags, struct path *file_path) +{ + return kern_path(name, flags, file_path); +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)) +#define DHD_VFS_INODE(dir) (dir->d_inode) +#else +#define DHD_VFS_INODE(dir) d_inode(dir) +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) && (RHEL_RELEASE_CODE < \ + RHEL_RELEASE_VERSION(7, 6)) +#define DHD_VFS_UNLINK(dir, file_path, c) vfs_unlink(DHD_VFS_INODE(dir), file_path.dentry) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) +#define DHD_VFS_UNLINK(dir, file_path, c) \ + vfs_unlink(mnt_idmap(file_path.mnt), DHD_VFS_INODE(dir), file_path.dentry, c) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) +#define DHD_VFS_UNLINK(dir, file_path, c) \ + vfs_unlink(mnt_user_ns(file_path.mnt), DHD_VFS_INODE(dir), file_path.dentry, c) +#else +#define DHD_VFS_UNLINK(dir, file_path, c) vfs_unlink(DHD_VFS_INODE(dir), file_path.dentry, c) +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */ +#else +#define DHD_VFS_UNLINK(dir, file_path, c) 0 + +static INLINE struct file *dhd_filp_open(const char *filename, int flags, int mode) + { printf("%s: DHD_SUPPORT_VFS_CALL not defined\n", __FUNCTION__); return NULL; } +static INLINE int dhd_filp_close(void *image, void *id) + { return 0; } +static INLINE int dhd_i_size_read(const struct inode *inode) + { return 0; } +static INLINE int dhd_kernel_read_compat(struct file *fp, loff_t pos, void *buf, size_t count) + { return 0; } +static INLINE int dhd_vfs_read(struct file *filep, char *buf, size_t size, loff_t *pos) + { return 0; } +static INLINE int dhd_vfs_write(struct file *filep, char *buf, size_t size, loff_t *pos) + { return 0; } +static INLINE int dhd_vfs_fsync(struct file *filep, int datasync) + { return 0; } +static INLINE long dhd_vfs_size_read(struct file *fp) + { return 0; } +static INLINE int dhd_kern_path(char *name, int flags, struct path *file_path) + { return 0; } +#endif /* DHD_SUPPORT_VFS_CALL */ +#endif /* __linux__ */ +#ifdef WL_TWT +extern int dhd_config_twt_event_mask_in_suspend(dhd_pub_t *dhdp, bool suspend); +extern int dhd_send_twt_info_suspend(dhd_pub_t *dhdp, bool suspend); +#endif /* WL_TWT */ +#if defined(DHD_WAKE_STATUS_PRINT) && defined(DHD_WAKE_RX_STATUS) && \ + defined(DHD_WAKE_STATUS) +void dhd_dump_wake_status(dhd_pub_t *dhdp, wake_counts_t *wcp, struct ether_header *eh); +#endif /* DHD_WAKE_STATUS_PRINT && DHD_WAKE_RX_STATUS && DHD_WAKE_STATUS */ +#ifdef SUPPORT_OTA_UPDATE +void dhd_ota_buf_clean(dhd_pub_t *dhdp); +#endif /* SUPPORT_OTA_UPDATE */ +#if defined(OEM_ANDROID) && !defined(AP) && defined(WLP2P) +extern uint32 dhd_get_concurrent_capabilites(dhd_pub_t *dhd); +#endif +#ifdef DHD_CUSTOM_CONFIG_RTS_IN_SUSPEND +#ifndef CUSTOM_RETRUN_TO_SLEEP_TIME_SUSPEND +#define CUSTOM_RETRUN_TO_SLEEP_TIME_SUSPEND 20 +#endif +#ifndef CUSTOM_RETRUN_TO_SLEEP_TIME_DEFAULT +#define CUSTOM_RETRUN_TO_SLEEP_TIME_DEFAULT 200 +#endif +int dhd_config_rts_in_suspend(dhd_pub_t *dhdp, bool suspend); +#endif /* DHD_CUSTOM_CONFIG_RTS_IN_SUSPEND */ #ifdef WL_MONITOR void dhd_set_monitor(dhd_pub_t *pub, int ifidx, int val); +#ifdef BCMSDIO +extern void dhd_rx_mon_pkt_sdio(dhd_pub_t *dhdp, void *pkt, int ifidx); +bool dhd_monitor_enabled(dhd_pub_t *dhd, int ifidx); +#endif /* BCMSDIO */ #endif /* WL_MONITOR */ #endif /* _dhd_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bitpack.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bitpack.c deleted file mode 100755 index c3aecaf1e0a4..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bitpack.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Bit packing and Base64 utils for EWP - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - */ - -#include - -#define BIT_PACK_OVERFLOW 0xFFFFFFFFu - -const char* base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -#define BASE64_MAX_VALUE 63u - -#define BASE64_UNIT_LEN 6u - -#define BASE64_OFFSET0 0u -#define BASE64_OFFSET1 6u -#define BASE64_OFFSET2 12u - -#define MASK_UPPER_6BIT 0xfc -#define MASK_LOWER_6BIT 0x3f - -#define MASK_UPPER_4BIT 0xf0 -#define MASK_LOWER_4BIT 0x0f - -#define MASK_UPPER_2BIT 0xc0 -#define MASK_LOWER_2BIT 0x03 - -#define SHIFT_2BIT 2u -#define SHIFT_4BIT 4u -#define SHIFT_6BIT 6u - -#define BASE64_PADDING_MARGIN 4u - -/* - * Function: dhd_bit_pack - * - * Purpose: bit data packing to given buffer - * - * Input Parameters: - * buf buffer to pack bit data - * buf_len total buffer length - * bit_offset offset in buffer (bitwise) - * data data to pack (max 32 bit) - * bit_length bit length to pack - * - * Output: - * Updated bit offset in buf - */ -int32 -dhd_bit_pack(char *buf, int buf_len, int bit_offset, uint32 data, int32 bit_length) -{ - - int32 byte_shift = (bit_offset / 8); - int32 local_bit_offset = bit_offset % 8; - int32 available_bit = 8 - local_bit_offset; - int32 remain_bit = bit_length; - uint32 cropped_data; - int32 idx; - int32 total_byte = BYTE_SIZE(local_bit_offset + bit_length); - - if (bit_length > 32) { - /* exceeded max bit length, do nothing */ - return bit_offset; - } - if (BYTE_SIZE(bit_offset + bit_length) > buf_len) { - /* can't pack more bits if expected offset is - * exceeded then buffer size - */ - return bit_offset; - } - if (bit_length < 32 && data >= 1<> (32 - bit_length); - } else { - cropped_data = data << (32 - bit_length); - cropped_data = cropped_data >> (32 - bit_length); - } - - buf += byte_shift; - - remain_bit = bit_length; - if (total_byte > 10) { - return bit_offset; - } - for (idx = 0; idx < total_byte; idx++) { - char temp_byte = 0x00; - if (idx == 0) { - local_bit_offset = bit_offset % 8; - } else { - local_bit_offset = 0; - } - - available_bit = 8 - local_bit_offset; - remain_bit -= available_bit; - if (remain_bit >= 0) { - temp_byte = cropped_data >> remain_bit; - } else { - temp_byte = cropped_data << (-1*remain_bit); - } - *buf = *buf | temp_byte; - buf ++; - } - bit_offset += bit_length; - - return bit_offset; -} - -static char -dhd_base64_get_code(char input) -{ - if (input > BASE64_MAX_VALUE) { - return '='; - } - return base64_table[(int)input]; -} - -/* - * Function: dhd_base64_encode - * - * Purpose: base64 encoding module which converts from 8 bits to - * 6 bit based, base64 format using base64_table - * eg: input: hex-123456 - * bin-0001|0010|0011|0100|0101|0110 - * encode every 6 bit : - * bin-000100|100011|010001|010110 - * base64 code : - * base64-EjRW - * - * Input Parameters: - * in_buf input buffer - * in_buf_len length of input buffer - * out_buf output buffer - * out_buf_len length_ of output buffer - * - * Output: - * length of encoded base64 string - */ -int32 -dhd_base64_encode(char* in_buf, int32 in_buf_len, char* out_buf, int32 out_buf_len) -{ - char* input_pos; - char* input_end; - char* base64_out; - char* base64_out_pos; - char* base64_output_end; - char current_byte = 0; - char masked_byte = 0; - int32 estimated_out_len = 0; - int32 offset = 0; - - if (!in_buf || !out_buf || in_buf_len == 0 || out_buf_len == 0) { - /* wrong input parameters */ - return 0; - } - - input_pos = in_buf; - input_end = in_buf + in_buf_len; - base64_out = out_buf; - base64_out_pos = base64_out; - base64_output_end = out_buf + out_buf_len - BASE64_PADDING_MARGIN; - estimated_out_len = in_buf_len / 3 * 4; - - if (estimated_out_len > out_buf_len) { - /* estimated output length is - * larger than output buffer size - */ - return 0; - } - - while (input_pos != input_end) { - if (base64_out_pos > base64_output_end) { - /* outbuf buffer size exceeded, finish encoding */ - break; - } - if (offset == BASE64_OFFSET0) { - current_byte = *input_pos++; - masked_byte = (current_byte & MASK_UPPER_6BIT) >> SHIFT_2BIT; - *base64_out_pos++ = dhd_base64_get_code(masked_byte); - masked_byte = (current_byte & MASK_LOWER_2BIT) << SHIFT_4BIT; - offset += BASE64_UNIT_LEN; - } else if (offset == BASE64_OFFSET1) { - current_byte = *input_pos++; - masked_byte |= (current_byte & MASK_UPPER_4BIT) >> SHIFT_4BIT; - *base64_out_pos++ = dhd_base64_get_code(masked_byte); - masked_byte = (current_byte & MASK_LOWER_4BIT) << SHIFT_2BIT; - offset += BASE64_UNIT_LEN; - } else if (offset == BASE64_OFFSET2) { - current_byte = *input_pos++; - masked_byte |= (current_byte & MASK_UPPER_2BIT) >> SHIFT_6BIT; - *base64_out_pos++ = dhd_base64_get_code(masked_byte); - offset += BASE64_UNIT_LEN; - masked_byte = (current_byte & MASK_LOWER_6BIT); - *base64_out_pos++ = dhd_base64_get_code(masked_byte); - offset = BASE64_OFFSET0; - } - } - if (offset == BASE64_OFFSET1) { - *base64_out_pos++ = dhd_base64_get_code(masked_byte); - *base64_out_pos++ = '='; - *base64_out_pos++ = '='; - } else if (offset == BASE64_OFFSET2) { - *base64_out_pos++ = dhd_base64_get_code(masked_byte); - *base64_out_pos++ = '='; - } - - return base64_out_pos - base64_out; -} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bitpack.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bitpack.h old mode 100755 new mode 100644 index 74bebf3f1be7..8332fb790a78 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bitpack.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bitpack.h @@ -1,7 +1,7 @@ /* * Bit packing and Base64 utils for EWP * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h old mode 100755 new mode 100644 index 3614d4869203..e5067ea47a13 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -31,8 +31,6 @@ extern int dbus_up(struct dhd_bus *pub); extern int dbus_stop(struct dhd_bus *pub); -extern int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len); -extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len); /* * Exported from dhd bus module (dhd_usb, dhd_sdio) */ @@ -72,6 +70,7 @@ extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp); #ifdef BCMPCIE extern uint16 dhd_prot_get_rxbufpost_sz(dhd_pub_t *dhd); +extern uint16 dhd_prot_get_rxbufpost_alloc_sz(dhd_pub_t *dhd); extern uint16 dhd_prot_get_h2d_rx_post_active(dhd_pub_t *dhd); extern uint16 dhd_prot_get_d2h_rx_cpln_active(dhd_pub_t *dhd); extern void dhdpcie_cto_recovery_handler(dhd_pub_t *dhd); @@ -111,6 +110,7 @@ extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, /* Add bus dump output to a buffer */ extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); +extern void dhd_bus_dump_flowring(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); /* Clear any bus counters */ extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); @@ -198,6 +198,7 @@ enum { #endif /* D2H_MINIDUMP */ DNGL_TO_HOST_TRAP_ADDR, HOST_SCB_ADDR, /* update host scb base address to dongle */ + HOST_CAP2, /* Host capability 2 flags */ }; typedef void (*dhd_mb_ring_t) (struct dhd_bus *, uint32); @@ -225,7 +226,8 @@ extern void dhd_bus_flow_ring_delete_response(struct dhd_bus *bus, uint16 flowid extern int dhd_bus_flow_ring_flush_request(struct dhd_bus *bus, void *flow_ring_node); extern void dhd_bus_flow_ring_flush_response(struct dhd_bus *bus, uint16 flowid, uint32 status); extern uint32 dhd_bus_max_h2d_queues(struct dhd_bus *bus); -extern int dhd_bus_schedule_queue(struct dhd_bus *bus, uint16 flow_id, bool txs); +extern int dhd_bus_schedule_queue(struct dhd_bus *bus, uint16 flow_id, bool txs, + uint32 bound, bool *is_qempty); #ifdef IDLE_TX_FLOW_MGMT extern void dhd_bus_flow_ring_resume_response(struct dhd_bus *bus, uint16 flowid, int32 status); @@ -252,8 +254,6 @@ extern void dhd_bus_aer_config(struct dhd_bus *bus); static INLINE void dhd_bus_aer_config(struct dhd_bus *bus) { } #endif /* LINUX || linux */ -extern struct device * dhd_bus_to_dev(struct dhd_bus *bus); - extern int dhdpcie_cto_init(struct dhd_bus *bus, bool enable); extern int dhdpcie_cto_cfg_init(struct dhd_bus *bus, bool enable); @@ -273,7 +273,6 @@ extern void dhd_bus_handle_mb_data(struct dhd_bus *bus, uint32 d2h_mb_data); extern void dhd_bus_dump_trap_info(struct dhd_bus *bus, struct bcmstrbuf *b); extern void dhd_bus_copy_trap_sig(struct dhd_bus *bus, trap_t *tr); #ifdef WL_CFGVENDOR_SEND_HANG_EVENT -extern void dhd_dump_pcie_rc_regs_for_linkdown(dhd_pub_t *dhd, int *bytes_written); void copy_hang_info_linkdown(dhd_pub_t *dhd); void copy_ext_trap_sig(dhd_pub_t *dhd, trap_t *tr); void copy_hang_info_trap(dhd_pub_t *dhd); @@ -298,11 +297,12 @@ extern bool dhd_bus_query_dpc_sched_errors(dhd_pub_t *dhdp); extern int dhd_bus_dmaxfer_lpbk(dhd_pub_t *dhdp, uint32 type); extern bool dhd_bus_check_driver_up(void); extern int dhd_bus_get_cto(dhd_pub_t *dhdp); +extern bool dhd_bus_get_read_shm(dhd_pub_t *dhdp); extern void dhd_bus_set_linkdown(dhd_pub_t *dhdp, bool val); extern int dhd_bus_get_linkdown(dhd_pub_t *dhdp); -#ifdef CONFIG_ARCH_MSM +#if defined(CONFIG_ARCH_MSM) && defined(CONFIG_SEC_PCIE_L1SS) extern void dhd_bus_inform_ep_loaded_to_rc(dhd_pub_t *dhdp, bool up); -#endif /* CONFIG_ARCH_MSM */ +#endif /* CONFIG_ARCH_MSM && CONFIG_SEC_PCIE_L1SS */ extern int dhd_bus_checkdied(struct dhd_bus *bus, char *data, uint size); #else #define dhd_bus_dump_console_buffer(x) @@ -313,7 +313,8 @@ static INLINE bool dhd_bus_check_driver_up(void) { return FALSE; } static INLINE void dhd_bus_set_linkdown(dhd_pub_t *dhdp, bool val) { } static INLINE int dhd_bus_get_linkdown(dhd_pub_t *dhdp) { return 0; } static INLINE int dhd_bus_get_cto(dhd_pub_t *dhdp) { return 0; } -extern INLINE int dhd_bus_checkdied(struct dhd_bus *bus, char *data, uint size) { return 0; } +static INLINE bool dhd_bus_get_read_shm(dhd_pub_t *dhdp) { return 0; } +static INLINE int dhd_bus_checkdied(struct dhd_bus *bus, char *data, uint size) { return 0; } #endif /* BCMPCIE */ #if defined(BCMPCIE) && defined(EWP_ETD_PRSRV_LOGS) @@ -322,14 +323,15 @@ void dhdpcie_get_etd_preserve_logs(dhd_pub_t *dhd, uint8 *ext_trap_data, #endif extern uint16 dhd_get_chipid(struct dhd_bus *bus); - -#ifdef BTLOG -extern void dhd_bus_rx_bt_log(struct dhd_bus *bus, void* pkt); -#endif /* BTLOG */ +extern uint16 dhd_get_chiprev(struct dhd_bus *bus); #ifdef DHD_WAKE_STATUS extern wake_counts_t* dhd_bus_get_wakecount(dhd_pub_t *dhd); extern int dhd_bus_get_bus_wake(dhd_pub_t * dhd); +extern int dhd_bus_set_get_bus_wake(dhd_pub_t * dhd, int set); +#if defined(BCMPCIE) +extern int dhd_bus_set_get_bus_wake_pkt_dump(dhd_pub_t *dhd, int wake_pkt_dump); +#endif /* BCMPCIE */ #endif /* DHD_WAKE_STATUS */ #ifdef BT_OVER_SDIO @@ -348,26 +350,18 @@ int dhd_bus_perform_flr(struct dhd_bus *bus, bool force_fail); extern bool dhd_bus_get_flr_force_fail(struct dhd_bus *bus); extern bool dhd_bus_aspm_enable_rc_ep(struct dhd_bus *bus, bool enable); +extern bool dhd_bus_is_aspm_enab_rc_ep(struct dhd_bus *bus); extern void dhd_bus_l1ss_enable_rc_ep(struct dhd_bus *bus, bool enable); +extern bool dhd_bus_is_l1ss_enab_rc_ep(struct dhd_bus *bus); bool dhd_bus_is_multibp_capable(struct dhd_bus *bus); -#ifdef BT_OVER_PCIE -int dhd_bus_pwr_off(dhd_pub_t *dhdp, int reason); -int dhd_bus_pwr_on(dhd_pub_t *dhdp, int reason); -int dhd_bus_pwr_toggle(dhd_pub_t *dhdp, int reason); -bool dhdpcie_is_btop_chip(struct dhd_bus *bus); -bool dhdpcie_is_bt_loaded(struct dhd_bus *bus); -int dhdpcie_redownload_fw(dhd_pub_t *dhdp); -extern void dhd_bus_pcie_pwr_req_reload_war(struct dhd_bus *bus); -int dhd_bus_perform_flr_with_quiesce(dhd_pub_t *dhdp, struct dhd_bus *bus, - bool init_deinit_path); -#endif /* BT_OVER_PCIE */ - #ifdef BCMPCIE extern void dhdpcie_advertise_bus_cleanup(dhd_pub_t *dhdp); extern void dhd_msgbuf_iovar_timeout_dump(dhd_pub_t *dhd); extern void dhdpcie_induce_cbp_hang(dhd_pub_t *dhd); +extern void dhdpcie_busbusy_wait(dhd_pub_t *dhdp); +extern int dhd_dump_flowrings(dhd_pub_t *dhdp, char *buf, int buflen); #endif /* BCMPCIE */ extern bool dhd_bus_force_bt_quiesce_enabled(struct dhd_bus *bus); @@ -414,7 +408,9 @@ extern int dhd_bus_get_sdtc_etb(dhd_pub_t *dhd, uint8 *sdtc_etb_mempool, uint addr, uint read_bytes); #endif /* DHD_SDTC_ETB_DUMP */ +#ifndef BCMDBUS extern int dhd_socram_dump(struct dhd_bus *bus); +#endif /* BCMDBUS */ extern int dhdpcie_get_max_eventbufpost(struct dhd_bus *bus); @@ -422,4 +418,15 @@ extern int dhdpcie_get_max_eventbufpost(struct dhd_bus *bus); extern void dhd_bus_flow_ring_status_isr_trace(dhd_pub_t *dhd); extern void dhd_bus_flow_ring_status_dpc_trace(dhd_pub_t *dhd); #endif /* DHD_FLOW_RING_STATUS_TRACE */ + +extern bool dhd_bus_init_done(struct dhd_bus *bus); + +extern void dhdpcie_db7_trap(struct dhd_bus *bus); + +#if defined(NDIS) +void * dhd_bus_get_socram_buf(struct dhd_bus *bus, struct dhd_pub *dhdp); +#endif + +void dhd_bus_set_signature_path(struct dhd_bus *bus, char *sig_path); + #endif /* _dhd_bus_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_buzzz.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_buzzz.h deleted file mode 100755 index 0e04c75d3120..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_buzzz.h +++ /dev/null @@ -1,224 +0,0 @@ -#ifndef _DHD_BUZZZ_H_INCLUDED_ -#define _DHD_BUZZZ_H_INCLUDED_ - -*/ - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - */ - -#if defined(DHD_BUZZZ_LOG_ENABLED) -/* - * Broadcom proprietary logging system. Deleted performance counters. - */ -void dhd_buzzz_attach(void); -void dhd_buzzz_detach(void); -void dhd_buzzz_panic(uint32 crash); -void dhd_buzzz_dump(void); -void dhd_buzzz_log_disable(void); -void dhd_buzzz_crash(void); - -void dhd_buzzz_log0(uint32 evt_id); -void dhd_buzzz_log1(uint32 evt_id, uint32 arg1); -void dhd_buzzz_log2(uint32 evt_id, uint32 arg1, uintptr arg2); - -void dhd_buzzz_fmt_reg(uint32 id, char * fmt); - -extern void* dhd_os_create_buzzz_thread(void); -extern void dhd_os_destroy_buzzz_thread(void *thr_hdl); -extern void dhd_os_sched_buzzz_thread(void *thr_hdl); - -#undef BUZZZ_EVT -#define BUZZZ_EVT(ID) BUZZZ_EVT__## ID, - -#undef BUZZZ_FMT -#define BUZZZ_FMT(ID, format) \ - dhd_buzzz_fmt_reg(BUZZZ_EVT__## ID, "\t" format); - -typedef enum buzzz_evt_id -{ - BUZZZ_EVT__DHD = 100, /* BUZZZ_EVT(DHD) */ - BUZZZ_EVT(GENERAL_LOCK) - BUZZZ_EVT(GENERAL_UNLOCK) - BUZZZ_EVT(FLOWRING_LOCK) - BUZZZ_EVT(FLOWRING_UNLOCK) - BUZZZ_EVT(FLOWID_LOCK) - BUZZZ_EVT(FLOWID_UNLOCK) - - BUZZZ_EVT(START_XMIT_BGN) - BUZZZ_EVT(START_XMIT_END) - BUZZZ_EVT(PROCESS_CTRL_BGN) - BUZZZ_EVT(PROCESS_CTRL_END) - BUZZZ_EVT(UPDATE_TXFLOWRINGS_BGN) - BUZZZ_EVT(UPDATE_TXFLOWRINGS_END) - BUZZZ_EVT(PROCESS_TXCPL_BGN) - BUZZZ_EVT(PROCESS_TXCPL_END) - BUZZZ_EVT(PROCESS_RXCPL_BGN) - BUZZZ_EVT(PROCESS_RXCPL_END) - - BUZZZ_EVT(GET_SRC_ADDR) - BUZZZ_EVT(WRITE_COMPLETE) - BUZZZ_EVT(ALLOC_RING_SPACE) - BUZZZ_EVT(ALLOC_RING_SPACE_RET) - BUZZZ_EVT(ALLOC_RING_SPACE_FAIL) - - BUZZZ_EVT(PKTID_MAP_CLEAR) - BUZZZ_EVT(PKTID_NOT_AVAILABLE) - BUZZZ_EVT(PKTID_MAP_RSV) - BUZZZ_EVT(PKTID_MAP_SAVE) - BUZZZ_EVT(PKTID_MAP_ALLOC) - BUZZZ_EVT(PKTID_MAP_FREE) - BUZZZ_EVT(LOCKER_INUSE_ABORT) - BUZZZ_EVT(BUFFER_TYPE_ABORT1) - BUZZZ_EVT(BUFFER_TYPE_ABORT2) - - BUZZZ_EVT(UPD_READ_IDX) - BUZZZ_EVT(STORE_RXCPLN_RD) - BUZZZ_EVT(EARLY_UPD_RXCPLN_RD) - - BUZZZ_EVT(POST_TXDATA) - BUZZZ_EVT(RETURN_RXBUF) - BUZZZ_EVT(RXBUF_POST) - BUZZZ_EVT(RXBUF_POST_EVENT) - BUZZZ_EVT(RXBUF_POST_IOCTL) - BUZZZ_EVT(RXBUF_POST_CTRL_PKTGET_FAIL) - BUZZZ_EVT(RXBUF_POST_PKTGET_FAIL) - BUZZZ_EVT(RXBUF_POST_PKTID_FAIL) - - BUZZZ_EVT(DHD_DUPLICATE_ALLOC) - BUZZZ_EVT(DHD_DUPLICATE_FREE) - BUZZZ_EVT(DHD_TEST_IS_ALLOC) - BUZZZ_EVT(DHD_TEST_IS_FREE) - - BUZZZ_EVT(DHD_PROT_IOCT_BGN) - BUZZZ_EVT(DHDMSGBUF_CMPLT_BGN) - BUZZZ_EVT(DHDMSGBUF_CMPLT_END) - BUZZZ_EVT(DHD_PROT_IOCT_END) - BUZZZ_EVT(DHD_FILLUP_IOCT_REQST_BGN) - BUZZZ_EVT(DHD_FILLUP_IOCT_REQST_END) - BUZZZ_EVT(DHD_MSGBUF_RXBUF_POST_IOCTLRESP_BUFS_BGN) - BUZZZ_EVT(DHD_MSGBUF_RXBUF_POST_IOCTLRESP_BUFS_END) - BUZZZ_EVT(DHD_PROT_IOCTCMPLT_PROCESS_ONE) - BUZZZ_EVT(DHD_PROT_IOCTCMPLT_PROCESS_TWO) - BUZZZ_EVT(DHD_PROT_EVENT_PROCESS_BGN) - BUZZZ_EVT(DHD_PROT_EVENT_PROCESS_END) - BUZZZ_EVT(DHD_PROT_D2H_SYNC_LIVELOCK) - BUZZZ_EVT(DHD_IOCTL_BUFPOST) - BUZZZ_EVT(DHD_EVENT_BUFPOST) - BUZZZ_EVT(DHD_PROC_MSG_TYPE) - BUZZZ_EVT(DHD_BUS_RXCTL_ONE) - BUZZZ_EVT(DHD_BUS_RXCTL_TWO) -} buzzz_evt_id_t; - -static inline void dhd_buzzz_fmt_init(void) -{ - BUZZZ_FMT(DHD, "DHD events") - BUZZZ_FMT(GENERAL_LOCK, "+++LOCK GENERAL flags<0x%08x>") - BUZZZ_FMT(GENERAL_UNLOCK, "---UNLK GENERAL flags<0x%08x>") - BUZZZ_FMT(FLOWRING_LOCK, "+++LOCK FLOWRING flags<0x%08x>") - BUZZZ_FMT(FLOWRING_UNLOCK, "---UNLK FLOWRING flags<0x%08x>") - BUZZZ_FMT(FLOWID_LOCK, "+++LOCK FLOWID flags<0x%08x>") - BUZZZ_FMT(FLOWID_UNLOCK, "---UNLK FLOWID flags<0x%08x>") - - BUZZZ_FMT(START_XMIT_BGN, "{ dhd_start_xmit() ifidx<%u> skb<0x%p>") - BUZZZ_FMT(START_XMIT_END, "} dhd_start_xmit()") - BUZZZ_FMT(PROCESS_CTRL_BGN, "{ dhd_prot_process_ctrlbuf()") - BUZZZ_FMT(PROCESS_CTRL_END, "} dhd_prot_process_ctrlbuf()") - BUZZZ_FMT(UPDATE_TXFLOWRINGS_BGN, "{ dhd_update_txflowrings()"); - BUZZZ_FMT(UPDATE_TXFLOWRINGS_END, "} dhd_update_txflowrings()"); - BUZZZ_FMT(PROCESS_TXCPL_BGN, "{ dhd_prot_process_msgbuf_txcpl()") - BUZZZ_FMT(PROCESS_TXCPL_END, "} dhd_prot_process_msgbuf_txcpl()") - BUZZZ_FMT(PROCESS_RXCPL_BGN, "{ dhd_prot_process_msgbuf_rxcpl()") - BUZZZ_FMT(PROCESS_RXCPL_END, "} dhd_prot_process_msgbuf_rxcpl()") - - BUZZZ_FMT(GET_SRC_ADDR, "bytes<%u> @<0x%p> prot_get_src_addr()") - BUZZZ_FMT(WRITE_COMPLETE, "WR<%u> prot_ring_write_complete") - BUZZZ_FMT(ALLOC_RING_SPACE, "{ dhd_alloc_ring_space nitems<%d>") - BUZZZ_FMT(ALLOC_RING_SPACE_RET, "} dhd_alloc_ring_space() alloc<%d> @<0x%p>") - BUZZZ_FMT(ALLOC_RING_SPACE_FAIL, "FAILURE } dhd_alloc_ring_space() alloc<%d>") - - BUZZZ_FMT(PKTID_MAP_CLEAR, "pktid map clear") - BUZZZ_FMT(PKTID_NOT_AVAILABLE, "FAILURE pktid pool depletion failures<%u>") - BUZZZ_FMT(PKTID_MAP_RSV, "pktid<%u> pkt<0x%p> dhd_pktid_map_reserve()") - BUZZZ_FMT(PKTID_MAP_SAVE, "pktid<%u> pkt<0x%p> dhd_pktid_map_save()") - BUZZZ_FMT(PKTID_MAP_ALLOC, "pktid<%u> pkt<0x%p> dhd_pktid_map_alloc()") - BUZZZ_FMT(PKTID_MAP_FREE, "pktid<%u> pkt<0x%p> dhd_pktid_map_free()") - BUZZZ_FMT(LOCKER_INUSE_ABORT, "ASSERT pktid<%u> pkt<0x%p> locker->inuse") - BUZZZ_FMT(BUFFER_TYPE_ABORT1, "ASSERT pktid<%u> pkt<0x%p> locker->dma") - BUZZZ_FMT(BUFFER_TYPE_ABORT2, "ASSERT locker->dma<%u> buf_type<%u>") - - BUZZZ_FMT(UPD_READ_IDX, "RD<%u> prot_upd_read_idx()") - BUZZZ_FMT(STORE_RXCPLN_RD, "RD<%u> prot_store_rxcpln_read_idx()") - BUZZZ_FMT(EARLY_UPD_RXCPLN_RD, "RD<%u> prot_early_upd_rxcpln_read_idx()") - - BUZZZ_FMT(POST_TXDATA, "flr<%u> pkt<0x%p> dhd_prot_txdata()") - BUZZZ_FMT(RETURN_RXBUF, "cnt<%u> dhd_prot_return_rxbuf()"); - BUZZZ_FMT(RXBUF_POST, "cnt<%u> dhd_prot_rxbufpost()"); - BUZZZ_FMT(RXBUF_POST_EVENT, "event dhd_prot_rxbufpost_ctrl()"); - BUZZZ_FMT(RXBUF_POST_IOCTL, "ioctl dhd_prot_rxbufpost_ctrl()"); - BUZZZ_FMT(RXBUF_POST_CTRL_PKTGET_FAIL, "FAILURE pktget dhd_prot_rxbufpost_ctrl()"); - BUZZZ_FMT(RXBUF_POST_PKTGET_FAIL, "FAILURE pktget loop<%u> dhd_prot_rxbufpost()") - BUZZZ_FMT(RXBUF_POST_PKTID_FAIL, "FAILURE pktid loop<%u> dhd_prot_rxbufpost()") - - BUZZZ_FMT(DHD_DUPLICATE_ALLOC, "ASSERT dhd_pktid_audit(%u) DHD_DUPLICATE_ALLOC") - BUZZZ_FMT(DHD_DUPLICATE_FREE, "ASSERT dhd_pktid_audit(%u) DHD_DUPLICATE_FREE") - BUZZZ_FMT(DHD_TEST_IS_ALLOC, "ASSERT dhd_pktid_audit(%u) DHD_TEST_IS_ALLOC") - BUZZZ_FMT(DHD_TEST_IS_FREE, "ASSERT dhd_pktid_audit(%u) DHD_TEST_IS_FREE") - - BUZZZ_FMT(DHD_PROT_IOCT_BGN, "{ dhd_prot_ioct pending<%u> thread<0x%p>") - BUZZZ_FMT(DHDMSGBUF_CMPLT_BGN, "{ dhdmsgbuf_cmplt bus::retlen<%u> bus::pktid<%u>") - BUZZZ_FMT(DHDMSGBUF_CMPLT_END, "} dhdmsgbuf_cmplt resp_len<%d> pktid<%u>") - BUZZZ_FMT(DHD_PROT_IOCT_END, "} dhd_prot_ioct pending<%u> thread<0x%p>") - BUZZZ_FMT(DHD_FILLUP_IOCT_REQST_BGN, "{ dhd_fillup_ioct_reqst_ptrbased cmd<%u> transid<%u>") - BUZZZ_FMT(DHD_FILLUP_IOCT_REQST_END, - "} dhd_fillup_ioct_reqst_ptrbased transid<%u> bus::pktid<%u>") - BUZZZ_FMT(DHD_MSGBUF_RXBUF_POST_IOCTLRESP_BUFS_BGN, - "{ dhd_msgbuf_rxbuf_post_ioctlresp_bufs cur_posted<%u> bus::pktid<%u>") - BUZZZ_FMT(DHD_MSGBUF_RXBUF_POST_IOCTLRESP_BUFS_END, - "} dhd_msgbuf_rxbuf_post_ioctlresp_bufs cur_posted<%u> bus::pktid<%u>") - BUZZZ_FMT(DHD_PROT_IOCTCMPLT_PROCESS_ONE, - "{ dhd_prot_ioctlcmplt_process cmd<%d> transid<%d>") - BUZZZ_FMT(DHD_PROT_IOCTCMPLT_PROCESS_TWO, - "} dhd_prot_ioctlcmplt_process resplen<%u> pktid<%u>") - BUZZZ_FMT(DHD_PROT_EVENT_PROCESS_BGN, "{ dhd_prot_event_process pktid<%u>") - BUZZZ_FMT(DHD_PROT_EVENT_PROCESS_END, "} dhd_prot_event_process buflen<%u> pkt<0x%p>") - BUZZZ_FMT(DHD_PROT_D2H_SYNC_LIVELOCK, " dhd_prot_d2h_sync_livelock seqnum<%u>") - BUZZZ_FMT(DHD_IOCTL_BUFPOST, " dhd_prot_rxbufpost_ctrl ioctl pktid<%u> phyaddr<0x%x>") - BUZZZ_FMT(DHD_EVENT_BUFPOST, " dhd_prot_rxbufpost_ctrl event pktid<%u> phyaddr<0x%x>") - BUZZZ_FMT(DHD_PROC_MSG_TYPE, " dhd_process_msgtype msg<0x%x> epoch<%u>") - BUZZZ_FMT(DHD_BUS_RXCTL_ONE, "dhd_bus_rxctl prev resplen<%u> pktid<%u>") - BUZZZ_FMT(DHD_BUS_RXCTL_TWO, "dhd_bus_rxctl cur resplen<%u> pktid<%u>") -} - -#define BUZZZ_LOG(ID, N, ARG...) dhd_buzzz_log ##N(BUZZZ_EVT__ ##ID, ##ARG) - -#else /* DHD_BUZZZ_LOG_ENABLED */ -/* - * Broadcom logging system - Empty implementaiton - */ - -#define dhd_buzzz_attach() do { /* noop */ } while (0) -#define dhd_buzzz_detach() do { /* noop */ } while (0) -#define dhd_buzzz_panic(x) do { /* noop */ } while (0) -#define BUZZZ_LOG(ID, N, ARG...) do { /* noop */ } while (0) - -#endif /* DHD_BUZZZ_LOG_ENABLED */ - -#endif /* _DHD_BUZZZ_H_INCLUDED_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ccode.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ccode.c old mode 100755 new mode 100644 index c1008f9998a0..90d6deaf9986 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ccode.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ccode.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 + #ifdef CCODE_LIST #ifdef CONFIG_COMPAT #include @@ -16,7 +16,7 @@ #define CCODE_4359C0 #endif #if defined(BCMPCIE) -#define CCODE_4375B4 +//#define CCODE_4375B4 #endif #ifdef BCMDBUS #define CCODE_4358U @@ -232,7 +232,7 @@ const ccode_list_map_t ccode_list_map[] = { {BCM4354_CHIP_ID, 2, ccode_4356a2, "XZ/11"}, {BCM4356_CHIP_ID, 2, ccode_4356a2, "XZ/11"}, {BCM4359_CHIP_ID, 9, ccode_4359c0, "XZ/11"}, - {BCM4375_CHIP_ID, 5, ccode_4375b4, "XZ/11"}, + {BCM4375_CHIP_ID, 5, ccode_4375b4, ""}, #endif #ifdef BCMDBUS {BCM43569_CHIP_ID, 2, ccode_4358u, "XW/0"}, @@ -264,9 +264,11 @@ dhd_ccode_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec) } } - if (bcmerror && ccode_ww && strlen(ccode_ww)>=4) { - memcpy(cspec->ccode, ccode_ww, 2); - cspec->rev = (int)simple_strtol(ccode_ww+3, NULL, 0); + if (dhd->op_mode != DHD_FLAG_MFG_MODE) { + if (bcmerror && ccode_ww && strlen(ccode_ww)>=4) { + memcpy(cspec->ccode, ccode_ww, 2); + cspec->rev = (int)simple_strtol(ccode_ww+3, NULL, 0); + } } return bcmerror; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c old mode 100755 new mode 100644 index 0152c18c9cca..668d11389e56 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c @@ -1,7 +1,7 @@ /* * DHD Protocol Module for CDC and BDC. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -71,9 +71,6 @@ typedef struct dhd_prot { uint16 reqid; uint8 pending; uint32 lastcmd; -#ifdef BCMDBUS - uint ctl_completed; -#endif /* BCMDBUS */ uint8 bus_header[BUS_HEADER_LEN]; cdc_ioctl_t msg; unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN]; @@ -89,9 +86,6 @@ dhd_prot_get_ioctl_trans_id(dhd_pub_t *dhdp) static int dhdcdc_msg(dhd_pub_t *dhd) { -#ifdef BCMDBUS - int timeout = 0; -#endif /* BCMDBUS */ int err = 0; dhd_prot_t *prot = dhd->prot; int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); @@ -108,46 +102,8 @@ dhdcdc_msg(dhd_pub_t *dhd) len = CDC_MAX_MSG_SIZE; /* Send request */ -#ifdef BCMDBUS - prot->ctl_completed = FALSE; - err = dbus_send_ctl(dhd->bus, (void *)&prot->msg, len); - if (err) { - DHD_ERROR(("dbus_send_ctl error=0x%x\n", err)); - DHD_OS_WAKE_UNLOCK(dhd); - return err; - } -#else err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); -#endif /* BCMDBUS */ -#ifdef BCMDBUS - timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed); - if ((!timeout) || (!prot->ctl_completed)) { - DHD_ERROR(("Txctl timeout %d ctl_completed %d\n", - timeout, prot->ctl_completed)); - DHD_ERROR(("Txctl wait timed out\n")); - err = -1; - } -#endif /* BCMDBUS */ -#if defined(BCMDBUS) && defined(INTR_EP_ENABLE) - /* If the ctl write is successfully completed, wait for an acknowledgement - * that indicates that it is now ok to do ctl read from the dongle - */ - if (err != -1) { - prot->ctl_completed = FALSE; - if (dbus_poll_intr(dhd->dbus)) { - DHD_ERROR(("dbus_poll_intr not submitted\n")); - } else { - /* interrupt polling is sucessfully submitted. Wait for dongle to send - * interrupt - */ - timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed); - if (!timeout) { - DHD_ERROR(("intr poll wait timed out\n")); - } - } - } -#endif /* defined(BCMDBUS) && defined(INTR_EP_ENABLE) */ DHD_OS_WAKE_UNLOCK(dhd); return err; } @@ -155,39 +111,34 @@ dhdcdc_msg(dhd_pub_t *dhd) static int dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) { -#ifdef BCMDBUS - int timeout = 0; -#endif /* BCMDBUS */ int ret; int cdc_len = len + sizeof(cdc_ioctl_t); dhd_prot_t *prot = dhd->prot; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + /* + * prot->msg is the buffer used to send the ioctl msg in dhdcdc_msg and the same is + * used for receiving the ioctl response. + * As this buffer is not cleared after sending message and before re-using for receive + * operation, problems are seen when bus errors occur. + * Example:- An error is seen on the bus where a 0 byte pkt is received. + * the bus-controller "layer below cdc" does not update the buffer in this 0 byte pkt case. + * bus-controller layer calls the completion callback without any error and with the + * same buffer.(no change) + * This issue is seen on DBUS/USB + FPGA platforms + * In this function if there is no update to the buffer, the stale id field of sent msg + * matches to expected ID and further processing is done thinking that + * proper response is received. + * This is a generic problem and its a good idea to clear the buffer or atleast + * the buffer's key value (ioctl ID within flags field in this case) before re-using it. + * + * To ensure that a new content is indeed received from the bus making flags = 0. + * Note that ID=0 is invalid value. + */ + prot->msg.flags = 0; do { -#ifdef BCMDBUS - prot->ctl_completed = FALSE; - ret = dbus_recv_ctl(dhd->bus, (uchar*)&prot->msg, cdc_len); - if (ret) { - DHD_ERROR(("dbus_recv_ctl error=0x%x(%d)\n", ret, ret)); - goto done; - } - timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed); - if ((!timeout) || (!prot->ctl_completed)) { - DHD_ERROR(("Rxctl timeout %d ctl_completed %d\n", - timeout, prot->ctl_completed)); - ret = -ETIMEDOUT; - goto done; - } - - /* XXX FIX: Must return cdc_len, not len, because after query_ioctl() - * it subtracts sizeof(cdc_ioctl_t); The other approach is - * to have dbus_recv_ctl() return actual len. - */ - ret = cdc_len; -#else ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); -#endif /* BCMDBUS */ if (ret < 0) break; } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); @@ -197,9 +148,6 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) ret = len; } -#ifdef BCMDBUS -done: -#endif /* BCMDBUS */ return ret; } @@ -230,6 +178,12 @@ dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uin } } + if (ifidx >= DHD_MAX_IFS) { + DHD_ERROR(("%s: IF index %d Invalid for the dongle FW\n", + __FUNCTION__, ifidx)); + return -EIO; + } + memset(msg, 0, sizeof(cdc_ioctl_t)); #ifdef BCMSPI @@ -343,16 +297,15 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 } } #endif /* DHD_PM_OVERRIDE */ -#if defined(WLAIBSS) - if (dhd->op_mode == DHD_FLAG_IBSS_MODE) { - DHD_ERROR(("%s: SET PM ignored for IBSS!(Requested:%d)\n", - __FUNCTION__, buf ? *(char *)buf : 0)); - goto done; - } -#endif /* WLAIBSS */ DHD_TRACE_HW4(("%s: SET PM to %d\n", __FUNCTION__, buf ? *(char *)buf : 0)); } + if (ifidx >= DHD_MAX_IFS) { + DHD_ERROR(("%s: IF index %d Invalid for the dongle FW\n", + __FUNCTION__, ifidx)); + return -EIO; + } + memset(msg, 0, sizeof(cdc_ioctl_t)); msg->cmd = htol32(cmd); @@ -403,24 +356,6 @@ done: return ret; } -#ifdef BCMDBUS -int -dhd_prot_ctl_complete(dhd_pub_t *dhd) -{ - dhd_prot_t *prot; - - if (dhd == NULL) - return BCME_ERROR; - - prot = dhd->prot; - - ASSERT(prot); - prot->ctl_completed = TRUE; - dhd_os_ioctl_resp_wake(dhd); - return 0; -} -#endif /* BCMDBUS */ - /* XXX: due to overlays this should not be called directly; call dhd_wl_ioctl() instead */ int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) @@ -516,6 +451,19 @@ dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) #endif } +void +dhd_prot_counters(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf, + bool print_ringinfo, bool print_pktidinfo) +{ + return; +} + +void +dhd_bus_counters(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + return; +} + /* The FreeBSD PKTPUSH could change the packet buf pinter so we need to make it changable */ @@ -640,6 +588,17 @@ exit: return 0; } +#ifdef DHD_LOSSLESS_ROAMING +int dhd_update_sdio_data_prio_map(dhd_pub_t *dhdp) +{ + const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + + bcopy(prio2tid, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); + + return BCME_OK; +} +#endif // DHD_LOSSLESS_ROAMING + int dhd_prot_attach(dhd_pub_t *dhd) { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c old mode 100755 new mode 100644 index 59258ec0e0b6..370510189ffe --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -57,7 +57,6 @@ static int dhd_dongle_up = FALSE; static s32 wl_dongle_up(struct net_device *ndev); static s32 wl_dongle_down(struct net_device *ndev); #ifndef OEM_ANDROID -#ifndef CUSTOMER_HW6 static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode); #ifdef BCMSDIO /* glomming is a sdio specific feature */ static s32 wl_dongle_glom(struct net_device *ndev, s32 glom, u32 dongle_align); @@ -66,7 +65,6 @@ static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, s32 static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol); static s32 wl_pattern_atoh(s8 *src, s8 *dst); static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode); -#endif /* !CUSTOMER_HW6 */ #endif /* !OEM_ANDROID */ /** @@ -142,20 +140,13 @@ int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev, bool rtnl_lock_reqd) { -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(cfg->pub, CAN_SLEEP(), __builtin_return_address(0)); -#endif /* DHD_PCIE_RUNTIMEPM */ return dhd_remove_if(cfg->pub, ifidx, rtnl_lock_reqd); } void wl_cfg80211_cleanup_if(struct net_device *net) { struct bcm_cfg80211 *cfg = wl_get_cfg(net); -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(cfg->pub, CAN_SLEEP(), __builtin_return_address(0)); -#else BCM_REFERENCE(cfg); -#endif /* DHD_PCIE_RUNTIMEPM */ dhd_cleanup_if(net); } @@ -233,7 +224,6 @@ wl_dongle_down(struct net_device *ndev) } #ifndef OEM_ANDROID -#ifndef CUSTOMER_HW6 static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode) { s32 err = 0; @@ -271,7 +261,6 @@ dongle_glom_out: } #endif /* BCMSDIO */ -#endif /* !CUSTOMER_HW6 */ #endif /* !OEM_ANDROID */ s32 @@ -293,12 +282,12 @@ wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) WL_ERR(("roam_off error (%d)\n", err)); goto dongle_rom_out; } + ROAMOFF_DBG_SAVE(ndev, SET_ROAM_FILS_TOGGLE, roamvar); dongle_rom_out: return err; } #ifndef OEM_ANDROID -#ifndef CUSTOMER_HW6 static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, s32 scan_unassoc_time) @@ -494,7 +483,6 @@ static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode) dongle_filter_out: return err; } -#endif /* !CUSTOMER_HW6 */ #endif /* !OEM_ANDROID */ s32 dhd_config_dongle(struct bcm_cfg80211 *cfg) @@ -527,7 +515,6 @@ s32 dhd_config_dongle(struct bcm_cfg80211 *cfg) } #ifndef OEM_ANDROID -#ifndef CUSTOMER_HW6 err = wl_dongle_power(ndev, PM_FAST); if (unlikely(err)) { WL_ERR(("wl_dongle_power failed\n")); @@ -548,7 +535,6 @@ s32 dhd_config_dongle(struct bcm_cfg80211 *cfg) wl_dongle_scantime(ndev, 40, 80); wl_dongle_offload(ndev, 1, 0xf); wl_dongle_filter(ndev, 1); -#endif /* !CUSTOMER_HW6 */ #endif /* OEM_ANDROID */ default_conf_out: @@ -595,3 +581,35 @@ done: DHD_OS_WAKE_UNLOCK(dhd); return ret; } + +int +dhd_set_wsec_info(dhd_pub_t *dhd, uint32 data, int tag) +{ + struct net_device *ndev; + uint32 wsec_info = data; + int ret = BCME_OK; + + ndev = dhd_linux_get_primary_netdev(dhd); + if (!ndev) { + WL_ERR(("Cannot find primary netdev\n")); + return -ENODEV; + } + BCM_REFERENCE(wsec_info); +#if defined(WL_CFG80211) + ret = wl_cfg80211_set_wsec_info(ndev, &wsec_info, sizeof(wsec_info), tag); + if (unlikely(ret)) { + WL_ERR(("Set wsec_info tag 0x%04x failed \n", tag)); + } +#endif /* WL_CFG80211 */ + + return ret; +} + +#ifdef RPM_FAST_TRIGGER +void +dhd_trigger_rpm_fast(struct bcm_cfg80211 *cfg) +{ + dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub; + dhdpcie_trigger_rpm_fast(dhd); +} +#endif /* RPM_FAST_TRIGGER */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.h old mode 100755 new mode 100644 index 1abf42b7d80e..ae24bce5503c --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -46,4 +46,8 @@ s32 dhd_config_dongle(struct bcm_cfg80211 *cfg); int dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev, const struct bcm_nlmsg_hdr *nlioc, void *data); s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout); +int dhd_set_wsec_info(dhd_pub_t *dhd, uint32 data, int tag); +#ifdef RPM_FAST_TRIGGER +void dhd_trigger_rpm_fast(struct bcm_cfg80211 *cfg); +#endif /* RPM_FAST_TRIGGER */ #endif /* __DHD_CFG80211__ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_common.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_common.c old mode 100755 new mode 100644 index 7272fc323889..ed4c32cd3ef8 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_common.c @@ -1,7 +1,7 @@ /* * Broadcom Dongle Host Driver (DHD), common DHD core. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -39,9 +40,9 @@ #include #endif /* DHD_SDTC_ETB_DUMP */ -#ifdef BCMDBG +#if defined(DHD_MACDBG) && defined(BCMDBG) #include -#endif /* BCMDBG */ +#endif /* defined(DHD_MACDBG) && defined(BCMDBG) */ #ifdef PCIE_FULL_DONGLE #include @@ -61,6 +62,9 @@ #include #include <802.1d.h> #include +#ifdef DHD_LOG_DUMP +#include +#endif #include #include #include @@ -119,9 +123,6 @@ #ifdef DHD_PSTA #include #endif /* DHD_PSTA */ -#ifdef DHD_TIMESYNC -#include -#endif /* DHD_TIMESYNC */ #ifdef DHD_WET #include @@ -137,18 +138,46 @@ #endif #endif /* DHD_LOG_DUMP */ +#ifdef CSI_SUPPORT +#include +#endif /* CSI_SUPPORT */ + #ifdef DHD_LOG_PRINT_RATE_LIMIT int log_print_threshold = 0; #endif /* DHD_LOG_PRINT_RATE_LIMIT */ +/* dhd_msg_level : a default level to print to dmesg buffer + * dhd_log_level : a default level to log to DLD or Ring + * To keep one level operation(dhd_msg_level) in HW4, + * dhd_msg_level and dhd_log_level have the same level + */ #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING -int dbgring_msg_level = DHD_ERROR_VAL | DHD_FWLOG_VAL | DHD_INFO_VAL - | DHD_EVENT_VAL | DHD_PKT_MON_VAL | DHD_IOVAR_MEM_VAL; -int dhd_msg_level = DHD_ERROR_VAL; +int dhd_msg_level = DHD_ERROR_VAL | DHD_EVENT_VAL +#ifdef BOARD_HIKEY + | DHD_FWLOG_VAL +#endif /* BOARD_HIKEY */ +#ifndef DHD_REDUCE_PM_LOG + | DHD_RPM_VAL +#endif /* REDUCE_PM_LOG */ + | DHD_PKT_MON_VAL; +int dhd_log_level = DHD_ERROR_VAL | DHD_EVENT_VAL + | DHD_RPM_VAL + | DHD_PKT_MON_VAL | DHD_FWLOG_VAL | DHD_IOVAR_MEM_VAL; #else -int dbgring_msg_level = 0; /* For CUSTOMER_HW4/Hikey do not enable DHD_ERROR_MEM_VAL by default */ int dhd_msg_level = DHD_ERROR_VAL | DHD_FWLOG_VAL; + +int dhd_log_level = DHD_ERROR_VAL | DHD_FWLOG_VAL | DHD_EVENT_VAL + /* For CUSTOMER_HW4 do not enable DHD_IOVAR_MEM_VAL by default */ +#if !defined(BOARD_HIKEY) + | DHD_IOVAR_MEM_VAL +#endif +#ifndef OEM_ANDROID + | DHD_MSGTRACE_VAL +#endif /* OEM_ANDROID */ + | DHD_RPM_VAL + | DHD_PKT_MON_VAL; + #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ #ifdef NDIS @@ -171,13 +200,9 @@ extern uint wl_msg_level; #include #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ -#ifdef CSI_SUPPORT -#include -#endif /* CSI_SUPPORT */ - -#if defined(BTLOG) && !defined(BCMPCIE) -#error "BT logging supported only with PCIe" -#endif /* defined(BTLOG) && !defined(BCMPCIE) */ +#if defined(DHD_LOGLEVEL) && !defined(DHD_DEBUG) +#error "Log level control is supported only with DHD_DEBUG" +#endif /* defined(DHD_LOGLEVEL) && !defined(DHD_DEBUG) */ #ifdef SOFTAP char fw_path2[MOD_PARAM_PATHLEN]; @@ -188,33 +213,11 @@ extern int disable_proptx; #endif /* PROP_TXSTATUS */ #ifdef REPORT_FATAL_TIMEOUTS -#ifdef BCMINTERNAL -/* - * Internal Builds are used by DVT. - * The timeouts are not required for DVT builds, since they use IOVARs like - * SROM programming etc, that takes long time. So make the timeout values - * as 0. If DVT needs to use this feature they can enable them using IOVAR - * - * SVT any way uses external builds - */ -#define SCAN_TIMEOUT_DEFAULT 0 -#define JOIN_TIMEOUT_DEFAULT 0 -#define BUS_TIMEOUT_DEFAULT 0 -#define CMD_TIMEOUT_DEFAULT 0 -#else /* Default timeout value in ms */ -#ifdef DHD_EFI -#define BUS_TIMEOUT_DEFAULT 800 /* 800ms */ -#define CMD_TIMEOUT_DEFAULT 1500 /* 1.5s */ -#define SCAN_TIMEOUT_DEFAULT 0 -#define JOIN_TIMEOUT_DEFAULT 0 -#else #define BUS_TIMEOUT_DEFAULT 800 #define CMD_TIMEOUT_DEFAULT 1200 #define SCAN_TIMEOUT_DEFAULT 17000 #define JOIN_TIMEOUT_DEFAULT 7500 -#endif /* DHD_EFI */ -#endif /* BCMINTERNAL */ #endif /* REPORT_FATAL_TIMEOUTS */ #ifdef SHOW_LOGTRACE @@ -263,11 +266,11 @@ extern int dhd_iscan_in_progress(void *h); void dhd_iscan_lock(void); void dhd_iscan_unlock(void); extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); -#if defined(OEM_ANDROID) && !defined(AP) && defined(WLP2P) -extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd); -#endif +#ifndef BCMDBUS extern int dhd_socram_dump(struct dhd_bus *bus); +#endif /* BCMDBUS */ + extern void dhd_set_packet_filter(dhd_pub_t *dhd); #ifdef DNGL_EVENT_SUPPORT @@ -306,7 +309,7 @@ extern int dhd_get_1905_almac(dhd_pub_t *dhdp, uint8 ifidx, uint8* ea, bool mcas #define CHIPID_MISMATCH 8 -#define DHD_VERSION "Dongle Host Driver, version " EPI_VERSION_STR "\n" +#define DHD_VERSION "Dongle Host Driver, version " EPI_VERSION_STR EPI_COMMIT_ID "\n" #if defined(DHD_DEBUG) && defined(DHD_COMPILED) const char dhd_version[] = DHD_VERSION DHD_COMPILED " compiled on " @@ -329,6 +332,11 @@ static int traffic_mgmt_add_dwm_filter(dhd_pub_t *dhd, static char* ioctl2str(uint32 ioctl); +#ifdef DHD_LOGLEVEL +void dhd_loglevel_set(dhd_loglevel_data_t *); +void dhd_loglevel_get(dhd_loglevel_data_t *); +#endif /* DHD_LOGLEVEL */ + /* IOVar table */ enum { IOV_VERSION = 1, @@ -338,7 +346,7 @@ enum { IOV_BCMERROR, IOV_WDTICK, IOV_DUMP, - IOV_CLEARCOUNTS, + IOV_RESET_COUNTS, IOV_LOGDUMP, IOV_LOGCAL, IOV_LOGSTAMP, @@ -416,11 +424,11 @@ enum { #ifdef DHD_MCAST_REGEN IOV_MCAST_REGEN_BSS_ENABLE, #endif -#ifdef BCMDBG +#if defined(DHD_MACDBG) && defined(BCMDBG) IOV_MACDBG_PD11REGS, IOV_MACDBG_REGLIST, IOV_MACDBG_PSVMPMEMS, -#endif /* BCMDBG */ +#endif /* defined(DHD_MACDBG) && defined(BCMDBG) */ #ifdef SHOW_LOGTRACE IOV_DUMP_TRACE_LOG, #endif /* SHOW_LOGTRACE */ @@ -435,34 +443,13 @@ enum { IOV_BPADDR, IOV_DUMP_DONGLE, /**< dumps core registers and d11 memories */ #if defined(DHD_LOG_DUMP) -#if defined(DHD_EFI) - IOV_LOG_CAPTURE_ENABLE, -#endif IOV_LOG_DUMP, #endif /* DHD_LOG_DUMP */ -#ifdef BTLOG - IOV_DUMP_BT_LOG, - IOV_BTLOG, -#endif /* BTLOG */ -#ifdef SNAPSHOT_UPLOAD - IOV_BT_MEM_DUMP, - IOV_BT_UPLOAD, -#endif /* SNAPSHOT_UPLOAD */ IOV_TPUT_TEST, -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) - IOV_PKT_LATENCY, -#endif /* defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) */ IOV_DEBUG_BUF_DEST_STAT, -#ifdef DHD_PKTTS - IOV_PKTTS_ENAB, - IOV_PKTTS_FLOW, -#endif /* DHD_PKTTS */ #ifdef DHD_DEBUG IOV_INDUCE_ERROR, #endif /* DHD_DEBUG */ -#if defined(DHD_EFI) - IOV_INTR_POLL, -#endif IOV_FIS_TRIGGER, #ifdef WL_IFACE_MGMT_CONF #ifdef WL_CFG80211 @@ -475,7 +462,7 @@ enum { #endif /* WL_CFG80211 */ #endif /* WL_IFACE_MGMT_CONF */ #ifdef RTT_GEOFENCE_CONT -#if defined (RTT_SUPPORT) && defined (WL_NAN) +#if defined(RTT_SUPPORT) && defined(WL_NAN) IOV_RTT_GEOFENCE_TYPE_OVRD, #endif /* RTT_SUPPORT && WL_NAN */ #endif /* RTT_GEOFENCE_CONT */ @@ -486,9 +473,19 @@ enum { IOV_TX_PROFILE_DUMP, #endif /* defined(DHD_TX_PROFILE) */ IOV_CHECK_TRAP_ROT, -#if defined(DHD_AWDL) - IOV_AWDL_LLC_ENABLE, +#ifdef DHD_LOGLEVEL + IOV_LOGLEVEL, +#endif /* DHD_LOGLEVEL */ + IOV_COUNTERS, +#ifdef BCMPCIE + IOV_DUMP_FLOWRINGS, #endif +#ifdef SYNA_SAR_CUSTOMER_PARAMETER + IOV_SAR_MODE, +#endif /* SYNA_SAR_CUSTOMER_PARAMETER */ +#ifdef CSI_SUPPORT + IOV_CSI_CONFIG, +#endif /* CSI_SUPPORT */ #ifdef WLEASYMESH IOV_1905_AL_UCAST, IOV_1905_AL_MCAST, @@ -516,7 +513,7 @@ const bcm_iovar_t dhd_iovars[] = { {"dump", IOV_DUMP, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN_32K}, {"cons", IOV_CONS, 0, 0, IOVT_BUFFER, 0}, {"dconpoll", IOV_DCONSOLE_POLL, 0, 0, IOVT_UINT32, 0}, - {"clearcounts", IOV_CLEARCOUNTS, 0, 0, IOVT_VOID, 0}, + {"reset_cnts", IOV_RESET_COUNTS, 0, 0, IOVT_VOID, 0}, #ifdef BCMPERFSTATS {"logdump", IOV_LOGDUMP, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN}, {"logcal", IOV_LOGCAL, 0, 0, IOVT_UINT32, 0}, @@ -597,11 +594,11 @@ const bcm_iovar_t dhd_iovars[] = { #ifdef DHD_MCAST_REGEN {"mcast_regen_bss_enable", IOV_MCAST_REGEN_BSS_ENABLE, 0, 0, IOVT_BOOL, 0}, #endif -#ifdef BCMDBG +#if defined(DHD_MACDBG) && defined(BCMDBG) {"pd11regs", IOV_MACDBG_PD11REGS, 0, 0, IOVT_BUFFER, 0}, {"mreglist", IOV_MACDBG_REGLIST, 0, 0, IOVT_BUFFER, 0}, {"psvmpmems", IOV_MACDBG_PSVMPMEMS, 0, 0, IOVT_BUFFER, 0}, -#endif /* BCMDBG */ +#endif /* defined(DHD_MACDBG) && defined(BCMDBG) */ #ifdef SHOW_LOGTRACE {"dump_trace_buf", IOV_DUMP_TRACE_LOG, 0, 0, IOVT_BUFFER, sizeof(trace_buf_info_t) }, #endif /* SHOW_LOGTRACE */ @@ -619,31 +616,10 @@ const bcm_iovar_t dhd_iovars[] = { {"dump_dongle", IOV_DUMP_DONGLE, 0, 0, IOVT_BUFFER, MAX(sizeof(dump_dongle_in_t), sizeof(dump_dongle_out_t)) }, #if defined(DHD_LOG_DUMP) -#if defined(DHD_EFI) - {"log_capture_enable", IOV_LOG_CAPTURE_ENABLE, 0, 0, IOVT_UINT8, 0}, -#endif {"log_dump", IOV_LOG_DUMP, 0, 0, IOVT_UINT8, 0}, #endif /* DHD_LOG_DUMP */ -#ifdef BTLOG - {"dump_bt_log", IOV_DUMP_BT_LOG, 0, 0, IOVT_BUFFER, sizeof(bt_log_buf_info_t) }, - {"btlog", IOV_BTLOG, 0, 0, IOVT_UINT32, 0 }, -#endif /* BTLOG */ -#ifdef SNAPSHOT_UPLOAD - {"bt_mem_dump", IOV_BT_MEM_DUMP, 0, 0, IOVT_UINT32, 0}, - {"bt_upload", IOV_BT_UPLOAD, 0, 0, IOVT_BUFFER, sizeof(bt_log_buf_info_t) }, -#endif /* SNAPSHOT_UPLOAD */ {"tput_test", IOV_TPUT_TEST, 0, 0, IOVT_BUFFER, sizeof(tput_test_t)}, {"debug_buf_dest_stat", IOV_DEBUG_BUF_DEST_STAT, 0, 0, IOVT_UINT32, 0 }, -#ifdef DHD_PKTTS - {"pktts_enab", IOV_PKTTS_ENAB, (0), 0, IOVT_BOOL, 0 }, - {"pktts_flow", IOV_PKTTS_FLOW, (0), 0, IOVT_BUFFER, sizeof(tput_test_t) }, -#endif /* DHD_PKTTS */ -#if defined(DHD_EFI) - {"intr_poll", IOV_INTR_POLL, 0, 0, IOVT_BUFFER, sizeof(intr_poll_t)}, -#endif -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) - {"pkt_latency", IOV_PKT_LATENCY, 0, 0, IOVT_UINT32, 0 }, -#endif /* defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) */ #if defined(DHD_SSSR_DUMP) {"fis_trigger", IOV_FIS_TRIGGER, 0, 0, IOVT_UINT32, 0}, #endif @@ -661,7 +637,7 @@ const bcm_iovar_t dhd_iovars[] = { #endif /* WL_CFG80211 */ #endif /* WL_IFACE_MGMT_CONF */ #ifdef RTT_GEOFENCE_CONT -#if defined (RTT_SUPPORT) && defined (WL_NAN) +#if defined(RTT_SUPPORT) && defined(WL_NAN) {"rtt_geofence_type_ovrd", IOV_RTT_GEOFENCE_TYPE_OVRD, (0), 0, IOVT_BOOL, 0}, #endif /* RTT_SUPPORT && WL_NAN */ #endif /* RTT_GEOFENCE_CONT */ @@ -673,9 +649,19 @@ const bcm_iovar_t dhd_iovars[] = { {"tx_profile_dump", IOV_TX_PROFILE_DUMP, 0, 0, IOVT_UINT32, 0}, #endif /* defined(DHD_TX_PROFILE) */ {"check_trap_rot", IOV_CHECK_TRAP_ROT, (0), 0, IOVT_BOOL, 0}, -#if defined(DHD_AWDL) - {"awdl_llc_enable", IOV_AWDL_LLC_ENABLE, 0, 0, IOVT_BOOL, 0}, +#ifdef DHD_LOGLEVEL + {"loglevel", IOV_LOGLEVEL, (0), 0, IOVT_BUFFER, sizeof(dhd_loglevel_data_t)}, +#endif /* DHD_LOGLEVEL */ + {"counters", IOV_COUNTERS, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN_32K}, +#ifdef BCMPCIE + {"dump_flowrings", IOV_DUMP_FLOWRINGS, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN_32K}, #endif +#ifdef SYNA_SAR_CUSTOMER_PARAMETER + {"sarmode", IOV_SAR_MODE, (0), 0, IOVT_UINT32, 0}, +#endif /* SYNA_SAR_CUSTOMER_PARAMETER */ +#ifdef CSI_SUPPORT + {"csi_config", IOV_CSI_CONFIG, (0), 0, IOVT_BUFFER, sizeof(uint32)}, +#endif /* CSI_SUPPORT */ /* --- add new iovars *ABOVE* this line --- */ #ifdef WLEASYMESH {"1905_al_ucast", IOV_1905_AL_UCAST, 0, 0, IOVT_BUFFER, ETHER_ADDR_LEN}, @@ -686,25 +672,19 @@ const bcm_iovar_t dhd_iovars[] = { #define DHD_IOVAR_BUF_SIZE 128 -#if defined(LINUX) || defined(linux) || defined(DHD_EFI) +#if defined(LINUX) || defined(linux) fw_download_status_t dhd_fw_download_status(dhd_pub_t * dhd_pub) { return dhd_pub->fw_download_status; } -#endif /* defined(LINUX) || defined(linux) || defined(DHD_EFI) */ +#endif bool dhd_query_bus_erros(dhd_pub_t *dhdp) { bool ret = FALSE; - if (dhdp->dongle_reset) { - DHD_ERROR_RLMT(("%s: Dongle Reset occurred, cannot proceed\n", - __FUNCTION__)); - ret = TRUE; - } - if (dhdp->dongle_trap_occured) { DHD_ERROR_RLMT(("%s: FW TRAP has occurred, cannot proceed\n", __FUNCTION__)); @@ -738,6 +718,11 @@ dhd_query_bus_erros(dhd_pub_t *dhdp) __FUNCTION__)); ret = TRUE; } + if (dhdp->pktid_invalid_occured) { + DHD_ERROR_RLMT(("%s: invalid pktid, cannot proceed\n", + __FUNCTION__)); + ret = TRUE; + } #endif /* PCIE_FULL_DONGLE */ if (dhdp->iface_op_failed) { @@ -758,6 +743,12 @@ dhd_query_bus_erros(dhd_pub_t *dhdp) ret = TRUE; } + if (dhdp->p2p_disc_busy_occurred) { + DHD_ERROR_RLMT(("%s: p2p_disc_busy_occurred, cannot proceed\n", + __FUNCTION__)); + ret = TRUE; + } + #ifdef DNGL_AXI_ERROR_LOGGING if (dhdp->axi_error) { DHD_ERROR_RLMT(("%s: AXI error occurred, cannot proceed\n", @@ -766,8 +757,11 @@ dhd_query_bus_erros(dhd_pub_t *dhdp) } #endif /* DNGL_AXI_ERROR_LOGGING */ -#if defined(BCMPCIE) +#ifdef BCMPCIE if (dhd_bus_get_linkdown(dhdp)) { + /* pcie link down, so do chip big hammer */ + DHD_ERROR_RLMT(("%s: set do_chip_bighammer\n", __FUNCTION__)); + dhdp->do_chip_bighammer = TRUE; DHD_ERROR_RLMT(("%s : PCIE Link down occurred, cannot proceed\n", __FUNCTION__)); ret = TRUE; @@ -778,8 +772,13 @@ dhd_query_bus_erros(dhd_pub_t *dhdp) __FUNCTION__)); ret = TRUE; } -#endif + if (dhd_bus_get_read_shm(dhdp)) { + DHD_ERROR_RLMT(("%s : read shm check failed, cannot proceed\n", + __FUNCTION__)); + ret = TRUE; + } +#endif /* BCMPCIE */ return ret; } @@ -791,24 +790,34 @@ dhd_clear_bus_errors(dhd_pub_t *dhdp) dhdp->dongle_reset = FALSE; dhdp->dongle_trap_occured = FALSE; + dhdp->dsack_hc_due_to_isr_delay = FALSE; + dhdp->dsack_hc_due_to_dpc_delay = FALSE; dhdp->iovar_timeout_occured = FALSE; #ifdef PCIE_FULL_DONGLE dhdp->d3ack_timeout_occured = FALSE; dhdp->livelock_occured = FALSE; dhdp->pktid_audit_failed = FALSE; + dhdp->pktid_invalid_occured = FALSE; #endif dhdp->iface_op_failed = FALSE; dhdp->scan_timeout_occurred = FALSE; dhdp->scan_busy_occurred = FALSE; -#ifdef BT_OVER_PCIE - dhdp->dongle_trap_due_to_bt = FALSE; -#endif + dhdp->p2p_disc_busy_occurred = FALSE; } #ifdef DHD_SSSR_DUMP /* This can be overwritten by module parameter defined in dhd_linux.c */ +#ifdef GDB_PROXY +/* GDB Proxy can't connect to crashed firmware after SSSR dump is generated. + * SSSR dump generation disabled for GDB Proxy enabled firmware by default. + * Still it can be explicitly enabled by echo 1 > /sys/wifi/sssr_enab or by + * sssr_enab=1 in insmod command line + */ +uint sssr_enab = FALSE; +#else /* GDB_PROXY */ uint sssr_enab = TRUE; +#endif /* else GDB_PROXY */ #ifdef DHD_FIS_DUMP uint fis_enab = TRUE; @@ -819,7 +828,11 @@ uint fis_enab = FALSE; int dhd_sssr_mempool_init(dhd_pub_t *dhd) { +#ifdef CONFIG_BCMDHD_PCIE + dhd->sssr_mempool = (uint8 *) VMALLOCZ(dhd->osh, DHD_SSSR_MEMPOOL_SIZE); +#else dhd->sssr_mempool = (uint8 *) MALLOCZ(dhd->osh, DHD_SSSR_MEMPOOL_SIZE); +#endif /* CONFIG_BCMDHD_PCIE */ if (dhd->sssr_mempool == NULL) { DHD_ERROR(("%s: MALLOC of sssr_mempool failed\n", __FUNCTION__)); @@ -832,7 +845,11 @@ void dhd_sssr_mempool_deinit(dhd_pub_t *dhd) { if (dhd->sssr_mempool) { +#ifdef CONFIG_BCMDHD_PCIE + VMFREE(dhd->osh, dhd->sssr_mempool, DHD_SSSR_MEMPOOL_SIZE); +#else MFREE(dhd->osh, dhd->sssr_mempool, DHD_SSSR_MEMPOOL_SIZE); +#endif /* CONFIG_BCMDHD_PCIE */ dhd->sssr_mempool = NULL; } } @@ -941,7 +958,7 @@ dhd_dump_sssr_reg_info_v3(dhd_pub_t *dhd) sssr_reg_info->hwa_regs.wrapper_regs.resetctrl)); DHD_ERROR(("HWA regs value seq for reset \n")); for (i = 0; i < SSSR_HWA_RESET_SEQ_STEPS; i++) { - DHD_ERROR(("hwa_resetseq_val[%d] 0x%x", i, + DHD_ERROR(("hwa_resetseq_val[%d] 0x%x\n", i, sssr_reg_info->hwa_regs.hwa_resetseq_val[i])); } } @@ -1034,10 +1051,19 @@ dhd_dump_sssr_reg_info(dhd_pub_t *dhd) #endif /* DHD_PCIE_REG_ACCESS */ } +void dhdpcie_fill_sssr_reg_info(dhd_pub_t *dhd); + int dhd_get_sssr_reg_info(dhd_pub_t *dhd) { int ret; + + if (dhd->force_sssr_init) { + dhdpcie_fill_sssr_reg_info(dhd); + dhd->force_sssr_init = FALSE; + goto done; + } + /* get sssr_reg_info from firmware */ ret = dhd_iovar(dhd, 0, "sssr_reg_info", NULL, 0, (char *)dhd->sssr_reg_info, sizeof(sssr_reg_info_cmn_t), FALSE); @@ -1047,6 +1073,7 @@ dhd_get_sssr_reg_info(dhd_pub_t *dhd) return BCME_ERROR; } +done: dhd_dump_sssr_reg_info(dhd); return BCME_OK; } @@ -1139,7 +1166,7 @@ dhd_sssr_dump_init(dhd_pub_t *dhd) /* Get SSSR reg info */ if (dhd_get_sssr_reg_info(dhd) != BCME_OK) { DHD_ERROR(("%s: dhd_get_sssr_reg_info failed\n", __FUNCTION__)); - printf("DEBUG_SSSr: %s: dhd_get_sssr_reg_info failed\n", __FUNCTION__); + DHD_CONS_ONLY(("DEBUG_SSSr: %s: dhd_get_sssr_reg_info failed\n", __FUNCTION__)); return BCME_ERROR; } @@ -1380,6 +1407,158 @@ dhd_sssr_print_filepath(dhd_pub_t *dhd, char *path) } #endif /* DHD_SSSR_DUMP */ +#ifdef DHD_COREDUMP +int +dhd_coredump_mempool_init(dhd_pub_t *dhd) +{ + dhd->coredump_mem = (uint8*) VMALLOCZ(dhd->osh, DHD_MEMDUMP_BUFFER_SIZE); + if (dhd->coredump_mem == NULL) { + DHD_ERROR(("%s: VMALLOCZ of coredump_mem failed\n", __FUNCTION__)); + return BCME_ERROR; + } + + dhd->coredump_len = DHD_MEMDUMP_BUFFER_SIZE; + return BCME_OK; +} + +void +dhd_coredump_mempool_deinit(dhd_pub_t *dhd) +{ + if (dhd->coredump_mem) { + VMFREE(dhd->osh, dhd->coredump_mem, DHD_MEMDUMP_BUFFER_SIZE); + dhd->coredump_mem = NULL; + dhd->coredump_len = 0; + } +} + +#ifdef DHD_SSSR_DUMP +dhd_coredump_t dhd_coredump_types[] = { + {DHD_COREDUMP_TYPE_SSSRDUMP_CORE0_BEFORE, 0, NULL}, + {DHD_COREDUMP_TYPE_SSSRDUMP_CORE0_AFTER, 0, NULL}, + {DHD_COREDUMP_TYPE_SSSRDUMP_CORE1_BEFORE, 0, NULL}, + {DHD_COREDUMP_TYPE_SSSRDUMP_CORE1_AFTER, 0, NULL}, + {DHD_COREDUMP_TYPE_SSSRDUMP_CORE2_BEFORE, 0, NULL}, + {DHD_COREDUMP_TYPE_SSSRDUMP_CORE2_AFTER, 0, NULL}, + {DHD_COREDUMP_TYPE_SSSRDUMP_DIG_BEFORE, 0, NULL}, + {DHD_COREDUMP_TYPE_SSSRDUMP_DIG_AFTER, 0, NULL}, + {DHD_COREDUMP_TYPE_SOCRAMDUMP, 0, NULL} +}; + +static int dhd_append_sssr_tlv(uint8 *buf_dst, int type_idx, int buf_remain) +{ + uint32 type_val, length_val; + uint32 *type, *length; + void *buf_src; + int total_size = 0, ret = 0; + + /* DHD_COREDUMP_TYPE_SSSRDUMP_[CORE[0|1|2]|DIG]_[BEFORE|AFTER] */ + type_val = dhd_coredump_types[type_idx].type; + length_val = dhd_coredump_types[type_idx].length; + + if (length_val == 0) { + return 0; + } + + type = (uint32*)buf_dst; + *type = type_val; + length = (uint32*)(buf_dst + sizeof(*type)); + *length = length_val; + + buf_dst += TLV_TYPE_LENGTH_SIZE; + total_size += TLV_TYPE_LENGTH_SIZE; + + buf_src = dhd_coredump_types[type_idx].bufptr; + ret = memcpy_s(buf_dst, buf_remain, buf_src, *length); + + if (ret) { + DHD_ERROR(("Failed to memcpy_s() for coredump.\n")); + return BCME_ERROR; + } + + DHD_INFO(("%s: type: %u, length: %u\n", __FUNCTION__, *type, *length)); + + total_size += *length; + return total_size; +} + +/* reconstruct dump memory with socram and sssr dump as TLV format */ +int dhd_collect_coredump(dhd_pub_t *dhdp, dhd_dump_t *dump) +{ + uint8 *buf_ptr = dhdp->coredump_mem; + int buf_len = dhdp->coredump_len; + uint8 *socram_mem = dump->buf; + int socram_len = dump->bufsize; + int ret = 0, i = 0; + int total_size = 0; + uint32 *magic, *type, *length; + uint8 num_d11cores = 0, offset = 0; + + /* SSSR dump */ + if (!sssr_enab || !dhdp->collect_sssr) { + DHD_ERROR(("SSSR is not enabled or not collected yet.\n")); + return BCME_UNSUPPORTED; + } + + /* SOCRAM dump start with magic code */ + magic = (uint32*)buf_ptr; + *magic = DHD_COREDUMP_MAGIC; + + /* DHD_COREDUMP_TYPE_SOCRAMDUMP */ + type = (uint32*)(buf_ptr + sizeof(*magic)); + *type = dhd_coredump_types[DHD_COREDUMP_TYPE_SOCRAMDUMP].type; + length = (uint32*)(buf_ptr + sizeof(*magic) + sizeof(*type)); + *length = socram_len; + + offset = sizeof(*magic) + sizeof(*type) + sizeof(*length); + ret = memcpy_s(buf_ptr + offset, buf_len - offset, + socram_mem, socram_len); + + if (ret) { + DHD_ERROR(("Failed to memmove_s() for coredump.\n")); + return BCME_ERROR; + } + total_size = offset + socram_len; + buf_ptr += total_size; + + DHD_ERROR(("%s: type: %u, length: %u\n", __FUNCTION__, *type, *length)); + + num_d11cores = dhd_d11_slices_num_get(dhdp); + for (i = 0; i < num_d11cores + 1; i++) { + int written_bytes = 0; + int type_idx = i * 2; + if ((i < num_d11cores) && (!dhdp->sssr_d11_outofreset[i])) { + continue; + } + +#ifdef DHD_SSSR_DUMP_BEFORE_SR + /* DHD_COREDUMP_TYPE_SSSRDUMP_[CORE[0|1|2]|DIG]_BEFORE */ + written_bytes = dhd_append_sssr_tlv(buf_ptr, type_idx, + buf_len - total_size); + if (written_bytes == BCME_ERROR) { + return BCME_ERROR; + } + buf_ptr += written_bytes; + total_size += written_bytes; +#endif /* DHD_SSSR_DUMP_BEFORE_SR */ + + /* DHD_COREDUMP_TYPE_SSSRDUMP_[CORE[0|1|2]|DIG]_AFTER */ + written_bytes = dhd_append_sssr_tlv(buf_ptr, type_idx + 1, + buf_len - total_size); + if (written_bytes == BCME_ERROR) { + return BCME_ERROR; + } + buf_ptr += written_bytes; + total_size += written_bytes; + } + + dump->buf = dhdp->coredump_mem; + dump->bufsize = total_size; + + return BCME_OK; +} +#endif /* DHD_SSSR_DUMP */ +#endif /* DHD_COREDUMP */ + #ifdef DHD_SDTC_ETB_DUMP /* * sdtc: system debug trace controller @@ -1463,11 +1642,13 @@ void dhd_sdtc_etb_deinit(dhd_pub_t *dhd) { dhd->sdtc_etb_inited = FALSE; + dhd->sdtc_etb_dump_len = 0; } int dhd_sdtc_etb_mempool_init(dhd_pub_t *dhd) { + dhd->sdtc_etb_dump_len = 0; dhd->sdtc_etb_mempool = (uint8 *) MALLOCZ(dhd->osh, DHD_SDTC_ETB_MEMPOOL_SIZE); if (dhd->sdtc_etb_mempool == NULL) { DHD_ERROR(("%s: MALLOC of sdtc_etb_mempool failed\n", @@ -1526,25 +1707,92 @@ void* dhd_get_fwdump_buf(dhd_pub_t *dhd_pub, uint32 length) int dhd_common_socram_dump(dhd_pub_t *dhdp) { -#ifdef BCMDBUS - return 0; -#else +#ifndef BCMDBUS return dhd_socram_dump(dhdp->bus); +#else + return -1; #endif /* BCMDBUS */ } +static void +dhd_dump_txrx_stats(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + /* TX Stats -- add any Tx counters in this section only */ + bcm_bprintf(strbuf, "\nTX stats:\n=========\n"); + bcm_bprintf(strbuf, "tx_packets %lu tx_bytes %lu tx_dropped %lu" + " tx_multicast %lu tx_errors %lu\n", + dhdp->tx_packets, dhdp->tx_bytes, dhdp->tx_dropped, + dhdp->tx_multicast, dhdp->tx_errors); + bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n", + dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); + bcm_bprintf(strbuf, "tx_realloc %lu tx_pktgetfail %lu tx_big_packets %lu\n", + dhdp->tx_realloc, dhdp->tx_pktgetfail, dhdp->tx_big_packets); + /* ----------------------------------------------------- */ + + /* RX Stats -- add any Rx counters in this section only */ + bcm_bprintf(strbuf, "\nRX stats:\n=========\n"); + bcm_bprintf(strbuf, "rx_packets %lu rx_bytes %lu rx_forward" + " %lu rx_multicast %lu rx_errors %lu \n", + dhdp->rx_packets, dhdp->rx_bytes, dhdp->rx_forward, + dhdp->rx_multicast, dhdp->rx_errors); + bcm_bprintf(strbuf, "rx_ctlpkts %lu rx_ctlerrs %lu rx_dropped %lu\n", + dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); + bcm_bprintf(strbuf, "rx_readahead_cnt %lu rx_pktgetfail %lu rx_pktgetpool_fail %lu\n", + dhdp->rx_readahead_cnt, dhdp->rx_pktgetfail, dhdp->rx_pktgetpool_fail); + bcm_bprintf(strbuf, "\n"); + /* ----------------------------------------------------- */ +} + +#ifdef DHD_MEM_STATS +static void +dhd_dump_memstats(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + uint64 malloc_mem = 0; + uint64 total_txpath_mem = 0; + uint64 txpath_bkpq_len = 0; + uint64 txpath_bkpq_mem = 0; + uint64 total_dhd_mem = 0; + + malloc_mem = MALLOCED(dhdp->osh); + + UNUSED_PARAMETER(malloc_mem); + UNUSED_PARAMETER(total_txpath_mem); + UNUSED_PARAMETER(txpath_bkpq_len); + UNUSED_PARAMETER(txpath_bkpq_mem); + +#ifdef BCMPCIE + txpath_bkpq_len = dhd_active_tx_flowring_bkpq_len(dhdp); + /* + * Instead of traversing the entire queue to find the skbs length, + * considering MAX_MTU_SZ as lenth of each skb. + */ + txpath_bkpq_mem = (txpath_bkpq_len* MAX_MTU_SZ); + total_txpath_mem = dhdp->txpath_mem + txpath_bkpq_mem; + + bcm_bprintf(strbuf, "\nDHD malloc memory_usage: %llubytes %lluKB\n", + malloc_mem, (malloc_mem / 1024)); + + bcm_bprintf(strbuf, "\nDHD tx-bkpq len: %llu memory_usage: %llubytes %lluKB\n", + txpath_bkpq_len, txpath_bkpq_mem, (txpath_bkpq_mem / 1024)); + bcm_bprintf(strbuf, "DHD tx-path memory_usage: %llubytes %lluKB\n", + total_txpath_mem, (total_txpath_mem / 1024)); + + total_dhd_mem = malloc_mem + total_txpath_mem; +#endif /* BCMPCIE */ + +#if defined(DHD_LB_STATS) + total_dhd_mem += dhd_lb_mem_usage(dhdp, strbuf); +#endif /* DHD_LB_STATS */ + bcm_bprintf(strbuf, "\nDHD Total memory_usage: %llubytes %lluKB \n", + total_dhd_mem, (total_dhd_mem / 1024)); +} +#endif /* DHD_MEM_STATS */ + int dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) { struct bcmstrbuf b; struct bcmstrbuf *strbuf = &b; -#ifdef DHD_MEM_STATS - uint64 malloc_mem = 0; - uint64 total_txpath_mem = 0; - uint64 txpath_bkpq_len = 0; - uint64 txpath_bkpq_mem = 0; - uint64 total_dhd_mem = 0; -#endif /* DHD_MEM_STATS */ if (!dhdp || !dhdp->prot || !buf) { return BCME_ERROR; @@ -1557,37 +1805,17 @@ dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) bcm_bprintf(strbuf, "\n"); bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", dhdp->up, dhdp->txoff, dhdp->busstate); +#ifdef WBRC + bcm_bprintf(strbuf, "chip_bighammer_count:%d\n", dhdp->chip_bighammer_count); +#endif /* WBRC */ bcm_bprintf(strbuf, "pub.hdrlen %u pub.maxctl %u pub.rxsz %u\n", dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz); bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac "MACDBG"\n", dhdp->iswl, dhdp->drv_version, MAC2STRDBG(&dhdp->mac)); bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %u\n", dhdp->bcmerror, dhdp->tickcnt); - bcm_bprintf(strbuf, "dongle stats:\n"); - bcm_bprintf(strbuf, "tx_packets %lu tx_bytes %lu tx_errors %lu tx_dropped %lu\n", - dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes, - dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped); - bcm_bprintf(strbuf, "rx_packets %lu rx_bytes %lu rx_errors %lu rx_dropped %lu\n", - dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes, - dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped); - bcm_bprintf(strbuf, "multicast %lu\n", dhdp->dstats.multicast); + dhd_dump_txrx_stats(dhdp, strbuf); - bcm_bprintf(strbuf, "bus stats:\n"); - bcm_bprintf(strbuf, "tx_packets %lu tx_dropped %lu tx_multicast %lu tx_errors %lu\n", - dhdp->tx_packets, dhdp->tx_dropped, dhdp->tx_multicast, dhdp->tx_errors); - bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n", - dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); - bcm_bprintf(strbuf, "rx_packets %lu rx_multicast %lu rx_errors %lu \n", - dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); - bcm_bprintf(strbuf, "rx_ctlpkts %lu rx_ctlerrs %lu rx_dropped %lu\n", - dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); - bcm_bprintf(strbuf, "rx_readahead_cnt %lu tx_realloc %lu\n", - dhdp->rx_readahead_cnt, dhdp->tx_realloc); - bcm_bprintf(strbuf, "tx_pktgetfail %lu rx_pktgetfail %lu\n", - dhdp->tx_pktgetfail, dhdp->rx_pktgetfail); - bcm_bprintf(strbuf, "tx_big_packets %lu\n", - dhdp->tx_big_packets); - bcm_bprintf(strbuf, "\n"); #ifdef DMAMAP_STATS /* Add DMA MAP info */ bcm_bprintf(strbuf, "DMA MAP stats: \n"); @@ -1625,38 +1853,8 @@ dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) #endif /* DHD_LB_STATS */ #ifdef DHD_MEM_STATS - - malloc_mem = MALLOCED(dhdp->osh); - - txpath_bkpq_len = dhd_active_tx_flowring_bkpq_len(dhdp); - /* - * Instead of traversing the entire queue to find the skbs length, - * considering MAX_MTU_SZ as lenth of each skb. - */ - txpath_bkpq_mem = (txpath_bkpq_len* MAX_MTU_SZ); - total_txpath_mem = dhdp->txpath_mem + txpath_bkpq_mem; - - bcm_bprintf(strbuf, "\nDHD malloc memory_usage: %llubytes %lluKB\n", - malloc_mem, (malloc_mem / 1024)); - - bcm_bprintf(strbuf, "\nDHD tx-bkpq len: %llu memory_usage: %llubytes %lluKB\n", - txpath_bkpq_len, txpath_bkpq_mem, (txpath_bkpq_mem / 1024)); - bcm_bprintf(strbuf, "DHD tx-path memory_usage: %llubytes %lluKB\n", - total_txpath_mem, (total_txpath_mem / 1024)); - - total_dhd_mem = malloc_mem + total_txpath_mem; -#if defined(DHD_LB_STATS) - total_dhd_mem += dhd_lb_mem_usage(dhdp, strbuf); -#endif /* DHD_LB_STATS */ - bcm_bprintf(strbuf, "\nDHD Totoal memory_usage: %llubytes %lluKB \n", - total_dhd_mem, (total_dhd_mem / 1024)); + dhd_dump_memstats(dhdp, strbuf); #endif /* DHD_MEM_STATS */ -#if defined(DHD_LB_STATS) - bcm_bprintf(strbuf, "\nlb_rxp_stop_thr_hitcnt: %llu lb_rxp_strt_thr_hitcnt: %llu\n", - dhdp->lb_rxp_stop_thr_hitcnt, dhdp->lb_rxp_strt_thr_hitcnt); - bcm_bprintf(strbuf, "\nlb_rxp_napi_sched_cnt: %llu lb_rxp_napi_complete_cnt: %llu\n", - dhdp->lb_rxp_napi_sched_cnt, dhdp->lb_rxp_napi_complete_cnt); -#endif /* DHD_LB_STATS */ #if defined(DHD_MQ) && defined(DHD_MQ_STATS) dhd_mqstats_dump(dhdp, strbuf); @@ -1674,6 +1872,33 @@ dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) return (!strbuf->size ? BCME_BUFTOOSHORT : strbuf->size); } +int +dhd_counters(dhd_pub_t *dhdp, char *buf, int buflen) +{ + struct bcmstrbuf bcmbuf; + struct bcmstrbuf *strbuf = &bcmbuf; + + if (!dhdp || !dhdp->prot || !buf) { + return BCME_ERROR; + } + + bcm_binit(strbuf, buf, buflen); + + dhd_dump_txrx_stats(dhdp, strbuf); + + dhd_bus_counters(dhdp, strbuf); + +#if defined(DHD_LB_STATS) + dhd_lb_stats_dump(dhdp, strbuf); +#endif /* DHD_LB_STATS */ + +#ifdef DHD_MEM_STATS + dhd_dump_memstats(dhdp, strbuf); +#endif /* DHD_MEM_STATS */ + + return (!strbuf->size ? BCME_BUFTOOSHORT : strbuf->size); +} + void dhd_dump_to_kernelog(dhd_pub_t *dhdp) { @@ -1803,7 +2028,7 @@ dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len) dhd_iov_li_t *iov_li; #endif /* DUMP_IOCTL_IOV_LIST */ #ifdef REPORT_FATAL_TIMEOUTS - wl_escan_params_t *eparams; + wl_escan_params_v1_t *eparams; uint8 *buf_ptr = (uint8 *)buf; uint16 action = 0; #endif /* REPORT_FATAL_TIMEOUTS */ @@ -1824,24 +2049,24 @@ dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len) #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ #ifdef KEEPIF_ON_DEVICE_RESET - if (ioc->cmd == WLC_GET_VAR) { - dbus_config_t config; - config.general_param = 0; - if (buf) { - if (!strcmp(buf, "wowl_activate")) { - /* 1 (TRUE) after decreased by 1 */ - config.general_param = 2; - } else if (!strcmp(buf, "wowl_clear")) { - /* 0 (FALSE) after decreased by 1 */ - config.general_param = 1; - } - } - if (config.general_param) { - config.config_id = DBUS_CONFIG_ID_KEEPIF_ON_DEVRESET; - config.general_param--; - dbus_set_config(dhd_pub->dbus, &config); + if (ioc->cmd == WLC_GET_VAR) { + dbus_config_t config; + config.general_param = 0; + if (buf) { + if (!strcmp(buf, "wowl_activate")) { + /* 1 (TRUE) after decreased by 1 */ + config.general_param = 2; + } else if (!strcmp(buf, "wowl_clear")) { + /* 0 (FALSE) after decreased by 1 */ + config.general_param = 1; } } + if (config.general_param) { + config.config_id = DBUS_CONFIG_ID_KEEPIF_ON_DEVRESET; + config.general_param--; + dbus_set_config(dhd_pub->dbus, &config); + } + } #endif /* KEEPIF_ON_DEVICE_RESET */ if (dhd_os_proto_block(dhd_pub)) @@ -1888,13 +2113,8 @@ dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len) DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd_pub)) { -#ifdef DHD_EFI DHD_INFO(("%s: returning as busstate=%d\n", __FUNCTION__, dhd_pub->busstate)); -#else - DHD_INFO(("%s: returning as busstate=%d\n", - __FUNCTION__, dhd_pub->busstate)); -#endif /* DHD_EFI */ DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); dhd_os_proto_unblock(dhd_pub); return -ENODEV; @@ -1902,9 +2122,27 @@ dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len) DHD_BUS_BUSY_SET_IN_IOVAR(dhd_pub); DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(dhd_pub, TRUE, dhd_wl_ioctl); -#endif /* DHD_PCIE_RUNTIMEPM */ +#ifdef OEM_ANDROID + /* + * If system suspend started before ioctl, after getting d3 ack, + * it will check for wakelock and as ioctl will hold wakelock, + * it will put bus back to d0 and bail out. + * So the current ioctl should wait till it is bailed out. + */ + if (DHD_BUS_BUSY_CHECK_SUSPEND_IN_PROGRESS(dhd_pub)) { + int timeleft = 0; + DHD_PRINT(("%s: wait till system suspend bails out\n", __FUNCTION__)); + /* wait till SUSPEND_IN_PROGRESS bit is cleared */ + timeleft = dhd_os_busbusy_wait_bitmask(dhd_pub, + &dhd_pub->dhd_bus_busy_state, + DHD_BUS_BUSY_SUSPEND_IN_PROGRESS, 0); + if ((dhd_pub->dhd_bus_busy_state & DHD_BUS_BUSY_SUSPEND_IN_PROGRESS) != 0) { + DHD_ERROR(("%s: system suspend wait timed out(%d)" + " dhd_bus_busy_state=0x%x\n", __FUNCTION__, timeleft, + dhd_pub->dhd_bus_busy_state)); + } + } +#endif /* OEM_ANDROID */ DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); if (DHD_BUS_CHECK_SUSPEND_OR_ANY_SUSPEND_IN_PROGRESS(dhd_pub) || @@ -1971,7 +2209,7 @@ dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len) if ((ioc->cmd == WLC_SET_VAR && buf != NULL && strcmp("escan", buf) == 0)) { - eparams = (wl_escan_params_t *) (buf_ptr + strlen("escan") + 1); + eparams = (wl_escan_params_v1_t *) (buf_ptr + strlen("escan") + 1); action = dtoh16(eparams->action); if (action == WL_SCAN_ACTION_START) { ++dhd_pub->esync_id; @@ -2029,8 +2267,8 @@ dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len) lval = 0; } } - DHD_IOVAR_MEM(( - "%s: cmd: %d, msg: %s val: 0x%x," + DHD_IOVAR_LOG(dhd_pub, ioc->cmd, msg, + ("%s: cmd: %d, msg: %s val: 0x%x," " len: %d, set: %d, txn-id: %d\n", ioc->cmd == WLC_GET_VAR ? "WLC_GET_VAR" : "WLC_SET_VAR", @@ -2434,6 +2672,362 @@ dhd_flow_ring_debug(dhd_pub_t *dhd, char *msg, uint msglen) #endif /* BCMPCIE */ #endif /* DHD_DEBUG */ +#ifdef SYNA_SAR_CUSTOMER_PARAMETER + +typedef struct _dhd_sar_parameters { + dhd_sar_parameter other; + dhd_sar_parameter fcc; + dhd_sar_parameter eu; + dhd_sar_parameter latam; + dhd_sar_parameter canada; + dhd_sar_parameter japan; +} dhd_sar_parameters; + +static dhd_sar_parameters gSAR_params; + +/* pick up usable parameters */ +static sarctrl_set *dhd_sar_ctrlset_get( + dhd_sar_parameter *dhd_sar_param, int advance_mode) +{ + sarctrl_set *sarctrl = NULL; + + if (dhd_sar_param == NULL) { + DHD_ERROR(("%s: *invalid argument, sar_param=0x%p\n", + __FUNCTION__, dhd_sar_param)); + } else switch (advance_mode) { + case SAR_HEAD: + sarctrl = &dhd_sar_param->dynamic; + DHD_TRACE(("%s: dynamic=0x%p, sarctrl=0x%p, ver=%d," + " sarctrl_2g=0x%X, sarctrl_2g_2=0x%X\n", + __FUNCTION__, dhd_sar_param, sarctrl, sarctrl->ver, + sarctrl->basic.sarctrl_2g, sarctrl->basic.sarctrl_2g_2)); + break; + case SAR_GRIP: + sarctrl = &dhd_sar_param->grip; + DHD_TRACE(("%s: grip=0x%p, sarctrl=0x%p, ver=%d," + " sarctrl_2g=0x%X, sarctrl_2g_2=0x%X\n", + __FUNCTION__, dhd_sar_param, sarctrl, sarctrl->ver, + sarctrl->basic.sarctrl_2g, sarctrl->basic.sarctrl_2g_2)); + break; + case SAR_BT: + sarctrl = &dhd_sar_param->bt; + DHD_TRACE(("%s: bt=0x%p, sarctrl=0x%p, ver=%d," + " sarctrl_2g=0x%X, sarctrl_2g_2=0x%X\n", + __FUNCTION__, dhd_sar_param, sarctrl, sarctrl->ver, + sarctrl->basic.sarctrl_2g, sarctrl->basic.sarctrl_2g_2)); + break; + case SAR_HOTSPOT: + sarctrl = &dhd_sar_param->hotspot; + DHD_TRACE(("%s: hotspot=0x%p, sarctrl=0x%p, ver=%d," + " sarctrl_2g=0x%X, sarctrl_2g_2=0x%X\n", + __FUNCTION__, dhd_sar_param, sarctrl, sarctrl->ver, + sarctrl->basic.sarctrl_2g, sarctrl->basic.sarctrl_2g_2)); + break; + default: + DHD_ERROR(("%s: *Error, invalid advance_mode=%d\n", + __FUNCTION__, advance_mode)); + } + + return sarctrl; +} + +int dhd_sar_init_parameter(dhd_pub_t *dhd, eCountry_flag_type type, int advance_mode, + char *list_str) +{ + char temp_str[16]; + sarctrl_set *sarctrl = NULL; + uint32 *txpwr_list = NULL; + char *next = NULL; + int len = 0, idx = 0; + + if (list_str == NULL) { + DHD_ERROR(("%s: *Error, invalid parameber\n", __FUNCTION__)); + return BCME_BADARG; + } else { + next = list_str; + } + + switch (type) { + case SYNA_COUNTRY_TYPE_FCC: + sarctrl = dhd_sar_ctrlset_get(&gSAR_params.fcc, advance_mode); + break; + case SYNA_COUNTRY_TYPE_EU: + sarctrl = dhd_sar_ctrlset_get(&gSAR_params.eu, advance_mode); + break; + case SYNA_COUNTRY_TYPE_LATAM: + sarctrl = dhd_sar_ctrlset_get(&gSAR_params.latam, advance_mode); + break; + case SYNA_COUNTRY_TYPE_CANADA: + sarctrl = dhd_sar_ctrlset_get(&gSAR_params.canada, advance_mode); + break; + case SYNA_COUNTRY_TYPE_JAPAN: + sarctrl = dhd_sar_ctrlset_get(&gSAR_params.japan, advance_mode); + break; + case SYNA_COUNTRY_TYPE_DEFAULT: + sarctrl = dhd_sar_ctrlset_get(&gSAR_params.other, advance_mode); + break; + default: + DHD_ERROR(("%s: *Error, invalid type=%d\n", __FUNCTION__, type)); + return BCME_UNSUPPORTED; + break; + } + if (!sarctrl) { + DHD_ERROR(("%s: *Error, invalid advance_mode=%d\n", + __FUNCTION__, advance_mode)); + return BCME_UNSUPPORTED; + } + + /* change dhd_sar_parameter structure to uint32 array. + * use txpwr_list pointer to fill the data + * one by one in following loop code + */ + txpwr_list = (uint32 *)(&sarctrl->basic); + idx = 0; + while ((len = strcspn(next, " ,")) > 0) { + if (len >= sizeof(temp_str)) { + DHD_ERROR(("%s: init '%s' before ','/' ' is too long\n", + __FUNCTION__, next)); + return BCME_ERROR; + } + strlcpy(temp_str, next, sizeof(temp_str)); + temp_str[len] = 0; + txpwr_list[idx] = (uint32)simple_strtoul(temp_str, NULL, 0); + DHD_TRACE(("%s: get txpwr[%d]=0x%x\n", + __FUNCTION__, idx, txpwr_list[idx])); + + if (idx == CONST_SARCTRL_SET_QTY) { + DHD_ERROR(("%s: too many parameters(more than %d): '%s'\n", + __FUNCTION__, idx, list_str)); + break; + } + + idx++; + next += len; + next += strspn(next, " ,"); + } + +#ifdef VSDB + if (FW_SUPPORTED(dhd, 6g)) { + sarctrl->ver = SAR_PARAM_6G_V3_VSDB; + } else { + sarctrl->ver = SAR_PARAM_V1_VSDB; + } + if (CONST_SARCTRL_SINGLE_SET_QTY != idx) { + DHD_ERROR(("%s: *Waring, idx=%d mismatch VSDB expect=%d\n", + __FUNCTION__, idx, (int)CONST_SARCTRL_SINGLE_SET_QTY)); + } +#else /* VSDB */ + if (FW_SUPPORTED(dhd, 6g)) { + sarctrl->ver = SAR_PARAM_6G_V4_RSDB; + } else { + sarctrl->ver = SAR_PARAM_V2_RSDB; + } + if (CONST_SARCTRL_SET_QTY != idx) { + DHD_ERROR(("%s: *Waring, idx=%d mismatch RSDB expect=%d\n", + __FUNCTION__, idx, (int)CONST_SARCTRL_SET_QTY)); + } +#endif /* VSDB */ + + return 0; +} + +int dhd_sar_reset_parameter(void) +{ + bzero(&gSAR_params, sizeof(gSAR_params)); + + return BCME_OK; +} + +int dhd_sar_set_parameter(dhd_pub_t *dhd_pub, int advance_mode) +{ + int err = BCME_OK; + char iovbuf[WLC_IOCTL_SMLEN]; + wl_country_t *cspec = NULL; + sarctrl_set sarctrl_iov = { 0 }, *sarctrl = NULL; + eCountry_flag_type type = SYNA_COUNTRY_TYPE_INVALID; + + if (dhd_pub == NULL) { + DHD_ERROR(("%s: bcm_mkiovar failed.", __FUNCTION__)); + return BCME_BADARG; + } else if (SAR_DISABLE == advance_mode) { + DHD_ERROR(("%s: SKIP since disabled.", __FUNCTION__)); + return BCME_OK; + } + + memset(iovbuf, 0, sizeof(iovbuf)); + if (0 >= bcm_mkiovar("country", NULL, 0, iovbuf, sizeof(iovbuf))) { + err = BCME_BUFTOOSHORT; + DHD_ERROR(("%s: sar country mkiovar failed.", __FUNCTION__)); + return err; + } + err = dhd_wl_ioctl_cmd(dhd_pub, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); + if (err) { + DHD_ERROR(("%s: country code get failed\n", __FUNCTION__)); + return err; + } + cspec = (wl_country_t *)iovbuf; + type = syna_country_check_type(cspec->ccode); + switch (type) { + case SYNA_COUNTRY_TYPE_FCC: + sarctrl = dhd_sar_ctrlset_get(&gSAR_params.fcc, advance_mode); + break; + case SYNA_COUNTRY_TYPE_EU: + sarctrl = dhd_sar_ctrlset_get(&gSAR_params.eu, advance_mode); + break; + case SYNA_COUNTRY_TYPE_LATAM: + sarctrl = dhd_sar_ctrlset_get(&gSAR_params.latam, advance_mode); + break; + case SYNA_COUNTRY_TYPE_CANADA: + sarctrl = dhd_sar_ctrlset_get(&gSAR_params.canada, advance_mode); + break; + case SYNA_COUNTRY_TYPE_JAPAN: + sarctrl = dhd_sar_ctrlset_get(&gSAR_params.japan, advance_mode); + break; + default: + sarctrl = dhd_sar_ctrlset_get(&gSAR_params.other, advance_mode); + break; + } + /* check if parameters valid */ + if ((!sarctrl) || (!sarctrl->ver)) { + DHD_ERROR(("%s: *warning, try default for country='%s'(type=%d)\n", + __FUNCTION__, cspec->ccode, type)); + sarctrl = dhd_sar_ctrlset_get(&gSAR_params.other, advance_mode); + if ((!sarctrl) || (!sarctrl->ver)) { + /* stop/block setting if customer not set parameters */ + DHD_ERROR(("%s: *skip since parameter not set\n", __FUNCTION__)); + return BCME_UNSUPPORTED; + } + } + DHD_TRACE(("%s: country='%s', type=%d, advance_mode=%d\n", + __FUNCTION__, cspec->ccode, type, advance_mode)); + + /* prepare IOVAR */ + sarctrl_iov.ver = sarctrl->ver; + sarctrl_iov.basic = sarctrl->basic; + sarctrl_iov.rsdb = sarctrl->rsdb; + DHD_TRACE(("%s: sarctrl_iov=0x%p, ver=%d, sarctrl_2g=0x%X, sarctrl_2g_2=0x%X\n", + __FUNCTION__, &sarctrl_iov, sarctrl_iov.ver, + sarctrl_iov.basic.sarctrl_2g, + sarctrl_iov.basic.sarctrl_2g_2)); + err = dhd_iovar(dhd_pub, 0, "sar_params", (char *)&sarctrl_iov, + sizeof(sarctrl_iov), NULL, 0, TRUE); + if (unlikely(err)) { + DHD_ERROR(("%s: Failed to set sar_params - error (%d)\n", + __FUNCTION__, err)); + } + + return err; +} + +int dhd_sar_set(dhd_pub_t *dhd_pub, int sar_val) +{ + sar_advance_modes sar_tx_power_val = SAR_DISABLE; + int airplane_mode = 0; + int err = 0; + + /* Map Android TX power modes to power mode */ + switch (sar_val) { + case SAR_OFF: + /* SAR disabled */ + sar_tx_power_val = SAR_DISABLE; + airplane_mode = 0; + break; + case HEAD_NORMAL: + /* HEAD mode, Normal */ + sar_tx_power_val = SAR_HEAD; + airplane_mode = 0; + break; + case HEAD_AIRPLANE: + /* HEAD mode, Airplane */ + sar_tx_power_val = SAR_HEAD; + airplane_mode = 1; + break; + case GRIP_NORMAL: + /* GRIP mode, Normal */ + sar_tx_power_val = SAR_GRIP; + airplane_mode = 0; + break; + case GRIP_AIRPLANE: + /* GRIP mode, Airplane */ + sar_tx_power_val = SAR_GRIP; + airplane_mode = 1; + break; + case BT_NORMAL: + /* BT mode, Normal */ + sar_tx_power_val = SAR_BT; + airplane_mode = 0; + break; + case BT_AIRPLANE: + /* BT mode, Airplane */ + sar_tx_power_val = SAR_BT; + airplane_mode = 1; + break; + case HOTSPOT_NORMAL: + /* HOTSPOT mode, Normal */ + sar_tx_power_val = SAR_HOTSPOT; + airplane_mode = 0; + break; + case HOTSPOT_AIRPLANE: + /* HOTSPOT mode, AIRPLANE */ + sar_tx_power_val = SAR_HOTSPOT; + airplane_mode = 1; + break; + default: + DHD_ERROR(("%s: invalid wifi tx power scenario = %d\n", + __FUNCTION__, sar_tx_power_val)); + err = -EINVAL; + goto exit; + } + + if (sar_tx_power_val) { + err = dhd_sar_set_parameter(dhd_pub, sar_tx_power_val); + if (!err) { + /* If dhd and FW all support this feature, it will return 0 + * DHD already set sar parameter to FW. + * so only need to set sar_enable 1 to enable SAR + */ + sar_tx_power_val = 1; + } else if (err == BCME_UNSUPPORTED) { + /* If dhd or FW not support/set these parameters + * use traditional way + */ + DHD_TRACE(("DHD/FW not support sar_param," + "try to use SAR parameters in nvram")); + } else { + DHD_ERROR(("%s: Failed to set sar_params - error (%d)\n", + __FUNCTION__, err)); + goto exit; + } + } + + DHD_TRACE(("%s: sar_mode %d airplane_mode %d\n", + __FUNCTION__, sar_tx_power_val, airplane_mode)); + err = dhd_iovar(dhd_pub, 0, "fccpwrlimit2g", (char *)&airplane_mode, + sizeof(airplane_mode), NULL, 0, TRUE); + if (unlikely(err)) { + DHD_ERROR(("%s: Failed to set airplane_mode - error (%d)\n", + __FUNCTION__, err)); + goto exit; + } + err = dhd_iovar(dhd_pub, 0, "sar_enable", (char *)&sar_tx_power_val, + sizeof(sar_tx_power_val), NULL, 0, TRUE); + if (unlikely(err)) { + DHD_ERROR(("%s: Failed to set sar_enable - error (%d)\n", + __FUNCTION__, err)); + goto exit; + } + + /* Cache the tx power mode sent by the hal */ + dhd_pub->dhd_sar_mode = sar_val; + DHD_TRACE(("%s: tx_power_mode %d SUCCESS\n", __FUNCTION__, sar_val)); + +exit: + return err; + +} + +#endif /* SYNA_SAR_CUSTOMER_PARAMETER */ + static int dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, void *params, int plen, void *arg, uint len, int val_size) @@ -2516,6 +3110,15 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch dhd_msg_level = int_val; break; +#ifdef DHD_LOGLEVEL + case IOV_GVAL(IOV_LOGLEVEL): + dhd_loglevel_get((dhd_loglevel_data_t *)arg); + break; + + case IOV_SVAL(IOV_LOGLEVEL): + dhd_loglevel_set((dhd_loglevel_data_t *)arg); + break; +#endif /* DHD_LOGLEVEL */ case IOV_GVAL(IOV_BCMERRORSTR): bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); ((char *)arg)[BCME_STRLEN - 1] = 0x00; @@ -2574,8 +3177,10 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch #endif /* DHD_DEBUG */ #endif /* !BCMDBUS */ - case IOV_SVAL(IOV_CLEARCOUNTS): + case IOV_SVAL(IOV_RESET_COUNTS): dhd_pub->tx_packets = dhd_pub->rx_packets = 0; + dhd_pub->tx_multicast = dhd_pub->rx_multicast = 0; + dhd_pub->tx_bytes = dhd_pub->rx_bytes = 0; dhd_pub->tx_errors = dhd_pub->rx_errors = 0; dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; @@ -2664,9 +3269,14 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch disable_proptx = 0; } - if (int_val == TRUE) + if (int_val == TRUE) { + uint32 up; bcmerror = dhd_wlfc_init(dhd_pub); - else + /* set WLC_UP to update wlfc credit */ + if (dhd_wl_ioctl_cmd(dhd_pub, WLC_UP, &up, sizeof(uint32), TRUE, 0) < 0) { + DHD_ERROR(("%s: WLC_UP return err\n", __FUNCTION__)); + } + } else bcmerror = dhd_wlfc_deinit(dhd_pub); break; @@ -3253,7 +3863,7 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch break; } #endif /* !NDIS && !BCM_ROUTER_DHD */ -#ifdef BCMDBG +#if defined(DHD_MACDBG) && defined(BCMDBG) case IOV_GVAL(IOV_MACDBG_PD11REGS): bcmerror = dhd_macdbg_pd11regs(dhd_pub, params, plen, arg, len); break; @@ -3263,7 +3873,7 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch case IOV_GVAL(IOV_MACDBG_PSVMPMEMS): bcmerror = dhd_macdbg_psvmpmems(dhd_pub, params, plen, arg, len); break; -#endif /* BCMDBG */ +#endif /* defined(DHD_MACDBG) && defined(BCMDBG) */ #ifdef SHOW_LOGTRACE case IOV_GVAL(IOV_DUMP_TRACE_LOG): { @@ -3287,78 +3897,6 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch break; } #endif /* SHOW_LOGTRACE */ -#ifdef BTLOG - case IOV_GVAL(IOV_DUMP_BT_LOG): { - bt_log_buf_info_t *bt_log_buf_info = (bt_log_buf_info_t *)arg; - uint32 rlen; - - rlen = dhd_dbg_pull_single_from_ring(dhd_pub, BT_LOG_RING_ID, bt_log_buf_info->buf, - BT_LOG_BUF_MAX_SIZE, TRUE); - bt_log_buf_info->size = rlen; - bt_log_buf_info->availability = BT_LOG_NEXT_BUF_NOT_AVAIL; - if (rlen == 0) { - bt_log_buf_info->availability = BT_LOG_BUF_NOT_AVAILABLE; - } else { - dhd_dbg_ring_status_t ring_status; - dhd_dbg_get_ring_status(dhd_pub, BT_LOG_RING_ID, &ring_status); - if (ring_status.written_bytes != ring_status.read_bytes) { - bt_log_buf_info->availability = BT_LOG_NEXT_BUF_AVAIL; - } - } - break; - } - case IOV_GVAL(IOV_BTLOG): - { - uint32 btlog_val = dhd_pub->bt_logging_enabled ? 1 : 0; - bcopy(&btlog_val, arg, val_size); - } - break; - case IOV_SVAL(IOV_BTLOG): - { - if (dhd_pub->busstate != DHD_BUS_DOWN) { - DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", - __FUNCTION__)); - bcmerror = BCME_NOTDOWN; - break; - } - if (int_val) - dhd_pub->bt_logging_enabled = TRUE; - else - dhd_pub->bt_logging_enabled = FALSE; - } - break; - -#endif /* BTLOG */ -#ifdef SNAPSHOT_UPLOAD - case IOV_SVAL(IOV_BT_MEM_DUMP): { - dhd_prot_send_snapshot_request(dhd_pub, SNAPSHOT_TYPE_BT, int_val); - break; - } - case IOV_GVAL(IOV_BT_UPLOAD): { - int status; - bt_mem_req_t req; - bt_log_buf_info_t *mem_info = (bt_log_buf_info_t *)arg; - uint32 size; - bool is_more; - - memcpy(&req, params, sizeof(req)); - - status = dhd_prot_get_snapshot(dhd_pub, SNAPSHOT_TYPE_BT, req.offset, - req.buf_size, mem_info->buf, &size, &is_more); - if (status == BCME_OK) { - mem_info->size = size; - mem_info->availability = is_more ? - BT_LOG_NEXT_BUF_AVAIL : BT_LOG_NEXT_BUF_NOT_AVAIL; - } else if (status == BCME_NOTREADY) { - mem_info->size = 0; - mem_info->availability = BT_LOG_NOT_READY; - } else { - mem_info->size = 0; - mem_info->availability = BT_LOG_BUF_NOT_AVAILABLE; - } - break; - } -#endif /* SNAPSHOT_UPLOAD */ #ifdef REPORT_FATAL_TIMEOUTS case IOV_GVAL(IOV_SCAN_TO): { dhd_get_scan_to_val(dhd_pub, (uint32 *)&int_val); @@ -3470,20 +4008,6 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch break; #endif /* DHD_DEBUG */ #if defined(DHD_LOG_DUMP) -#if defined(DHD_EFI) - case IOV_GVAL(IOV_LOG_CAPTURE_ENABLE): - { - int_val = dhd_pub->log_capture_enable; - bcopy(&int_val, arg, val_size); - break; - } - - case IOV_SVAL(IOV_LOG_CAPTURE_ENABLE): - { - dhd_pub->log_capture_enable = (uint8)int_val; - break; - } -#endif /* DHD_EFI */ case IOV_GVAL(IOV_LOG_DUMP): { dhd_prot_debug_info_print(dhd_pub); @@ -3504,15 +4028,6 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch } break; } -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) - case IOV_SVAL(IOV_PKT_LATENCY): - dhd_pub->pkt_latency = (uint32)int_val; - break; - case IOV_GVAL(IOV_PKT_LATENCY): - int_val = (int32)dhd_pub->pkt_latency; - bcopy(&int_val, arg, val_size); - break; -#endif /* defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) */ case IOV_GVAL(IOV_DEBUG_BUF_DEST_STAT): { if (dhd_pub->debug_buf_dest_support) { @@ -3526,37 +4041,6 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch break; } -#ifdef DHD_PKTTS - case IOV_GVAL(IOV_PKTTS_ENAB): { - int_val = dhd_get_pktts_enab(dhd_pub); - (void)memcpy_s(arg, val_size, &int_val, sizeof(int_val)); - break; - } - case IOV_SVAL(IOV_PKTTS_ENAB): { - dhd_set_pktts_enab(dhd_pub, !!int_val); - break; - } - - case IOV_GVAL(IOV_PKTTS_FLOW): { - bcmerror = dhd_get_pktts_flow(dhd_pub, arg, len); - break; - } - case IOV_SVAL(IOV_PKTTS_FLOW): { - bcmerror = dhd_set_pktts_flow(dhd_pub, params, plen); - break; - } -#endif /* DHD_PKTTS */ - -#if defined(DHD_EFI) - case IOV_SVAL(IOV_INTR_POLL): - bcmerror = dhd_intr_poll(dhd_pub->bus, arg, len, TRUE); - break; - - case IOV_GVAL(IOV_INTR_POLL): - bcmerror = dhd_intr_poll(dhd_pub->bus, params, plen, FALSE); - break; -#endif /* DHD_EFI */ - #if defined(DHD_SSSR_DUMP) case IOV_GVAL(IOV_FIS_TRIGGER): bcmerror = dhd_bus_fis_trigger(dhd_pub); @@ -3580,6 +4064,13 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch if (dhd_pub->dhd_induce_error == DHD_INDUCE_BH_CBP_HANG) { dhdpcie_induce_cbp_hang(dhd_pub); } + if (dhd_pub->dhd_induce_error == DHD_INDUCE_PCIE_LINK_DOWN) { + dhd_bus_set_linkdown(dhd_pub, TRUE); +#ifdef OEM_ANDROID + dhd_pub->hang_reason = HANG_REASON_PCIE_LINK_DOWN_EP_DETECT; + dhd_os_send_hang_message(dhd_pub); +#endif /* OEM_ANDROID */ + } #endif /* BCMPCIE */ } break; @@ -3617,7 +4108,7 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch #endif /* WL_CFG80211 */ #endif /* WL_IFACE_MGMT_CONF */ #ifdef RTT_GEOFENCE_CONT -#if defined (RTT_SUPPORT) && defined (WL_NAN) +#if defined(RTT_SUPPORT) && defined(WL_NAN) case IOV_GVAL(IOV_RTT_GEOFENCE_TYPE_OVRD): { bool enable = 0; dhd_rtt_get_geofence_cont_ind(dhd_pub, &enable); @@ -3735,7 +4226,6 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch { const dhd_tx_profile_protocol_t *protocol = NULL; uint8 offset; - char *format = "%s:\ttx_profile %s: %d\n"; for (offset = 0; offset < dhd_pub->num_profiles; offset++) { if (dhd_pub->protocol_filters[offset].profile_index == int_val) { @@ -3751,11 +4241,16 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch break; } - printf(format, __FUNCTION__, "profile_index", protocol->profile_index); - printf(format, __FUNCTION__, "layer", protocol->layer); - printf(format, __FUNCTION__, "protocol_number", protocol->protocol_number); - printf(format, __FUNCTION__, "src_port", protocol->src_port); - printf(format, __FUNCTION__, "dest_port", protocol->dest_port); + DHD_CONS_ONLY(("%s:\ttx_profile %s: %d\n", __FUNCTION__, + "profile_index", protocol->profile_index)); + DHD_CONS_ONLY(("%s:\ttx_profile %s: %d\n", __FUNCTION__, + "layer", protocol->layer)); + DHD_CONS_ONLY(("%s:\ttx_profile %s: %d\n", __FUNCTION__, + "protocol_number", protocol->protocol_number)); + DHD_CONS_ONLY(("%s:\ttx_profile %s: %d\n", __FUNCTION__, + "src_port", protocol->src_port)); + DHD_CONS_ONLY(("%s:\ttx_profile %s: %d\n", __FUNCTION__, + "dest_port", protocol->dest_port)); break; } @@ -3771,20 +4266,38 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch break; } -#if defined(DHD_AWDL) - case IOV_SVAL(IOV_AWDL_LLC_ENABLE): { - bool bval = *(bool *)arg; - if (bval != 0 && bval != 1) + case IOV_GVAL(IOV_COUNTERS): + if (dhd_counters(dhd_pub, arg, len) <= 0) bcmerror = BCME_ERROR; else - dhd_pub->awdl_llc_enabled = bval; + bcmerror = BCME_OK; break; - } - case IOV_GVAL(IOV_AWDL_LLC_ENABLE): - int_val = dhd_pub->awdl_llc_enabled; +#ifdef BCMPCIE + case IOV_GVAL(IOV_DUMP_FLOWRINGS): + if (dhd_dump_flowrings(dhd_pub, arg, len) <= 0) + bcmerror = BCME_ERROR; + else + bcmerror = BCME_OK; + break; +#endif /* BCMPCIE */ +#ifdef SYNA_SAR_CUSTOMER_PARAMETER + case IOV_GVAL(IOV_SAR_MODE): + int_val = dhd_pub->dhd_sar_mode; (void)memcpy_s(arg, val_size, &int_val, sizeof(int_val)); break; -#endif + case IOV_SVAL(IOV_SAR_MODE): + dhd_sar_set(dhd_pub, int_val); + break; +#endif /* SYNA_SAR_CUSTOMER_PARAMETER */ + +#ifdef CSI_SUPPORT + case IOV_GVAL(IOV_CSI_CONFIG): + bcmerror = dhd_csi_config(dhd_pub, arg, val_size, FALSE); + break; + case IOV_SVAL(IOV_CSI_CONFIG): + bcmerror = dhd_csi_config(dhd_pub, arg, val_size, TRUE); + break; +#endif /* CSI_SUPPORT */ #ifdef WLEASYMESH case IOV_SVAL(IOV_1905_AL_UCAST): { uint32 bssidx; @@ -4117,10 +4630,6 @@ dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen) DHD_BUS_BUSY_SET_IN_DHD_IOVAR(dhd_pub); DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(dhd_pub, TRUE, dhd_ioctl); -#endif /* DHD_PCIE_RUNTIMEPM */ - DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhd_pub)) { /* If Suspend/Resume is tested via pcie_suspend IOVAR @@ -4128,19 +4637,10 @@ dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen) * other IOVARs, also include pciecfgreg and devreset to go * through. */ -#ifdef DHD_EFI - if (bcmstricmp((char *)buf, "pcie_suspend") && - bcmstricmp((char *)buf, "pciecfgreg") && - bcmstricmp((char *)buf, "devreset") && - bcmstricmp((char *)buf, "sdio_suspend") && - bcmstricmp((char *)buf, "control_signal")) -#else if (bcmstricmp((char *)buf, "pcie_suspend") && bcmstricmp((char *)buf, "pciecfgreg") && bcmstricmp((char *)buf, "devreset") && - bcmstricmp((char *)buf, "sdio_suspend")) -#endif /* DHD_EFI */ - { + bcmstricmp((char *)buf, "sdio_suspend")) { DHD_ERROR(("%s: bus is in suspend(%d)" "or suspending(0x%x) state\n", __FUNCTION__, dhd_pub->busstate, @@ -4164,10 +4664,6 @@ dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen) (dhd_bus_is_multibp_capable(dhd_pub->bus) && !bcmstricmp((char *)buf, "dwnldstate")) || #endif /* BCMPCIE */ -#if defined(DHD_EFI) && defined (BT_OVER_PCIE) - !bcmstricmp((char *)buf, "btop_test") || - !bcmstricmp((char *)buf, "control_signal") || -#endif /* DHD_EFI && BT_OVER_PCIE */ FALSE) { DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhd_pub); @@ -4221,15 +4717,6 @@ dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen) goto unlock_exit; } -#ifdef DHD_TIMESYNC - /* check TS module */ - if (ioc->cmd == DHD_GET_VAR) - bcmerror = dhd_timesync_iovar_op(dhd_pub->ts, buf, arg, - arglen, buf, buflen, IOV_GET); - else - bcmerror = dhd_timesync_iovar_op(dhd_pub->ts, buf, - NULL, 0, arg, arglen, IOV_SET); -#endif /* DHD_TIMESYNC */ } goto unlock_exit; @@ -4250,45 +4737,6 @@ unlock_exit: #ifdef SHOW_EVENTS -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) -static void -dhd_update_awdl_stats(dhd_pub_t *dhd_pub, const awdl_aws_event_data_t *aw) -{ - dhd_awdl_stats_t *awdl_stats; - unsigned long lock_flags; - - /* since AWDL stats are read on clear to protect against clear, - * lock before update - */ - DHD_AWDL_STATS_LOCK(dhd_pub->awdl_stats_lock, lock_flags); - /* Start of AWDL slot */ - if (!(aw->flags & AWDL_AW_LAST_EXT)) { - dhd_pub->awdl_tx_status_slot = - ((aw->aw_counter/AWDL_SLOT_MULT) % AWDL_NUM_SLOTS); - awdl_stats = &dhd_pub->awdl_stats[dhd_pub->awdl_tx_status_slot]; - awdl_stats->slot_start_time = OSL_SYSUPTIME_US(); - awdl_stats->fw_slot_start_time = ntoh32_ua(&aw->fw_time); - awdl_stats->num_slots++; - } else { - /* End of AWDL slot */ - awdl_stats = &dhd_pub->awdl_stats[dhd_pub->awdl_tx_status_slot]; - if (awdl_stats->slot_start_time) { - awdl_stats->cum_slot_time += - OSL_SYSUPTIME_US() - awdl_stats->slot_start_time; - /* FW reports time in us in a 32bit number. - * This 32bit number wrap-arround in ~90 minutes. - * Below logic considers wrap-arround too - */ - awdl_stats->fw_cum_slot_time += - ((ntoh32_ua(&aw->fw_time) - awdl_stats->fw_slot_start_time) & - (UINT_MAX)); - - } - } - DHD_AWDL_STATS_UNLOCK(dhd_pub->awdl_stats_lock, lock_flags); -} -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ - static void wl_show_roam_event(dhd_pub_t *dhd_pub, uint status, uint datalen, const char *event_name, char *eabuf, void *event_data) @@ -4407,6 +4855,10 @@ wl_show_roam_cache_update_event(const char *name, uint status, {WLC_E_STATUS_INVALID, "Invalid status code"} }; + UNUSED_PARAMETER(ntoa_buf); + UNUSED_PARAMETER(reason_name); + UNUSED_PARAMETER(status_name); + switch (reason) { case WLC_ROAM_CACHE_UPDATE_NEW_ROAM_CACHE: DHD_EVENT(("Current roam cache status %d, " @@ -4508,6 +4960,7 @@ wl_show_roam_cache_update_event(const char *name, uint status, { rmc_candidate_info_v1_t *candidate_info = (rmc_candidate_info_v1_t *)(val_xtlv->data); + UNUSED_PARAMETER(candidate_info); if (val_xtlv->id == WL_RMC_RPT_XTLV_CANDIDATE_INFO) { DHD_EVENT(("\t Candidate INFO:\n")); } else { @@ -4592,6 +5045,11 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, break; + case WLC_E_BSSID: + DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d datalen %d\n", event_name, + eabuf, (int)reason, datalen)); + break; + case WLC_E_ASSOC: case WLC_E_REASSOC: if (status == WLC_E_STATUS_SUCCESS) { @@ -4676,6 +5134,7 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, if (datalen >= sizeof(wlc_roam_start_event_t)) { const wlc_roam_start_event_t *roam_start = (wlc_roam_start_event_t *)event_data; + UNUSED_PARAMETER(roam_start); DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d," " reason %d, auth %d, current bss rssi %d\n", event_name, event_type, eabuf, (int)status, (int)reason, @@ -4690,6 +5149,7 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, if (datalen >= sizeof(wlc_roam_prep_event_t)) { const wlc_roam_prep_event_t *roam_prep = (wlc_roam_prep_event_t *)event_data; + UNUSED_PARAMETER(roam_prep); DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d," " reason %d, auth %d, target bss rssi %d\n", event_name, event_type, eabuf, (int)status, (int)reason, @@ -4732,6 +5192,10 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, } break; + case WLC_E_JOIN_START: + DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); + break; + case WLC_E_BEACON_RX: if (status == WLC_E_STATUS_SUCCESS) { DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name)); @@ -4796,6 +5260,9 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, case WLC_E_PFN_SCAN_NONE: case WLC_E_PFN_SCAN_ALLGONE: case WLC_E_PFN_GSCAN_FULL_RESULT: +#ifdef WL_SCHED_SCAN + case WLC_E_PFN_PARTIAL_RESULT: +#endif /* WL_SCHED_SCAN */ case WLC_E_PFN_SSID_EXT: DHD_EVENT(("PNOEVENT: %s\n", event_name)); break; @@ -4837,11 +5304,12 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, } #endif /* SHOW_LOGTRACE */ - case WLC_E_RSSI: - if (datalen >= sizeof(int)) { - DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data)))); - } - break; + case WLC_E_RSSI: { + wl_event_data_rssi_t *e_data = (wl_event_data_rssi_t *)event_data; + UNUSED_PARAMETER(e_data); + DHD_EVENT(("MACEVENT: %s (RSSI=%d SNR=%d NF=%d)\n", event_name, + ntoh32(e_data->rssi), ntoh32(e_data->snr), ntoh32(e_data->noise))); + } break; case WLC_E_SERVICE_FOUND: case WLC_E_P2PO_ADD_DEVICE: @@ -4849,61 +5317,20 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); break; -#ifdef BT_WIFI_HANDOBER - case WLC_E_BT_WIFI_HANDOVER_REQ: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; -#endif -#ifdef DHD_AWDL - case WLC_E_AWDL_AW: - if (datalen >= sizeof(awdl_aws_event_data_t)) { - const awdl_aws_event_data_t *aw = - (awdl_aws_event_data_t *)event_data; - BCM_REFERENCE(aw); - DHD_EVENT(("MACEVENT: %s, MAC %s aw_cnt %u ext_cnt %u flags %u " - "aw_ch %u\n", event_name, eabuf, aw->aw_counter, - aw->aw_ext_count, aw->flags, CHSPEC_CHANNEL(aw->aw_chan))); - host_data = TRUE; - -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) - dhd_update_awdl_stats(dhd_pub, aw); - /* Store last received aw counter */ - dhd_pub->awdl_aw_counter = aw->aw_counter; -#endif /* DHD_AWDL */ - } - break; - case WLC_E_AWDL_ROLE: - DHD_EVENT(("MACEVENT: %s, MAC %s ROLE %d\n", event_name, eabuf, (int)status)); - break; - case WLC_E_AWDL_EVENT: - DHD_EVENT(("MACEVENT: %s, MAC %s status %d reason %d\n", - event_name, eabuf, (int)status, (int)reason)); - if (datalen >= OFFSETOF(awdl_scan_event_data_t, chan_list)) { - const awdl_scan_event_data_t *scan_evt = - (awdl_scan_event_data_t *)event_data; - BCM_REFERENCE(scan_evt); - DHD_EVENT(("scan_usage %d, nscan_chans %d, ncached_chans %d, " - "iscan_flags 0x%x\n", scan_evt->scan_usage, - scan_evt->nscan_chans, scan_evt->ncached_chans, - scan_evt->flags)); - host_data = TRUE; - } - break; -#endif /* DHD_AWDL */ - case WLC_E_CCA_CHAN_QUAL: /* I would like to check here that datalen >= sizeof(cca_chan_qual_event_t) * but since definition of cca_chan_qual_event_t is different * between blazar and legacy firmware, I will * check only that datalen is bigger than 0. */ - if (datalen > 0) { - const cca_chan_qual_event_t *cca_event = + if (datalen >= sizeof(cca_chan_qual_event_t)) { + cca_chan_qual_event_t *cca_event = (cca_chan_qual_event_t *)event_data; if ((cca_event->id == WL_CHAN_QUAL_FULLPM_CCA) || - (cca_event->id == WL_CHAN_QUAL_FULLPM_CCA_OFDM_DESENSE)) { - const cca_only_chan_qual_event_t *cca_only_event = - (const cca_only_chan_qual_event_t *)cca_event; + (cca_event->id == WL_CHAN_QUAL_FULLPM_CCA_OFDM_DESENSE) || + (cca_event->id == WL_CHAN_QUAL_FULLPM_CCA_ALL_DESENSE)) { + cca_only_chan_qual_event_t *cca_only_event = + (cca_only_chan_qual_event_t *)cca_event; BCM_REFERENCE(cca_only_event); DHD_EVENT(( "MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d," @@ -4931,9 +5358,32 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, cca_only_event->cca_busy_pm.congest_obss, cca_only_event->cca_busy_pm.interference)); if (cca_event->id == WL_CHAN_QUAL_FULLPM_CCA_OFDM_DESENSE) { - DHD_EVENT(("\t OFDM desense %d\n", - ((const cca_only_chan_qual_event_v2_t *) - cca_only_event)->ofdm_desense)); + cca_only_chan_qual_event_v2_t *cca_event_v2 = + (cca_only_chan_qual_event_v2_t *) + cca_only_event; + if (cca_event->len >= + (STRUCT_SIZE_THROUGH(cca_event_v2, ofdm_desense) - + STRUCT_SIZE_THROUGH(cca_event_v2, len))) { + DHD_EVENT(("\t OFDM desense %d\n", + cca_event_v2->ofdm_desense)); + } else { + DHD_EVENT(("\t OFDM desense: missing data\n")); + } + } else if (cca_event->id == WL_CHAN_QUAL_FULLPM_CCA_ALL_DESENSE) { + cca_only_chan_qual_event_v3_t *cca_event_v3 = + (cca_only_chan_qual_event_v3_t *) + cca_only_event; + if (cca_event->len >= + (STRUCT_SIZE_THROUGH(cca_event_v3, desense) - + STRUCT_SIZE_THROUGH(cca_event_v3, len))) { + DHD_EVENT(("\t OFDM desense %d BPHY desense %d" + " reason 0x%x)\n", + cca_event_v3->desense.ofdm_desense, + cca_event_v3->desense.bphy_desense, + cca_event_v3->desense.reason)); + } else { + DHD_EVENT(("\t PHY desense: missing data\n")); + } } } else if (cca_event->id == WL_CHAN_QUAL_FULL_CCA) { DHD_EVENT(( @@ -4975,6 +5425,9 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, } break; case WLC_E_ESCAN_RESULT: +#if defined(NDIS) + break; +#endif if (datalen >= sizeof(wl_escan_result_v2_t)) { const wl_escan_result_v2_t *escan_result = (wl_escan_result_v2_t *)event_data; @@ -4989,7 +5442,7 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d sync-id %u\n", event_name, event_type, eabuf, (int)status, dtoh16(escan_result->sync_id))); -#endif /* CUSTOMER_HW4 */ +#endif #ifdef REPORT_FATAL_TIMEOUTS /* a 'partial' status means the escan is still in progress * any other status implies the escan has either finished or aborted @@ -5150,19 +5603,41 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, if (datalen >= sizeof(wlc_bcn_mute_miti_event_data_v1_t)) { const wlc_bcn_mute_miti_event_data_v1_t *bcn_mute_miti_evnt_data = event_data; + UNUSED_PARAMETER(bcn_mute_miti_evnt_data); DHD_EVENT(("MACEVENT: %s, reason :%d uatbtt_count: %d\n", event_name, reason, bcn_mute_miti_evnt_data->uatbtt_count)); } break; - - case WLC_E_TWT_SETUP: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); +#ifdef WL_TWT + case WLC_E_TWT: + DHD_EVENT(("MACEVENT: %s, type:%d\n", event_name, reason)); break; - case WLC_E_TWT_TEARDOWN: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); +#endif /* WL_TWT */ + case WLC_E_COUNTRY_CODE_CHANGED: + DHD_EVENT(("MACEVENT: %s: Country code changed to %s\n", event_name, + (char*)event_data)); break; - case WLC_E_TWT_INFO_FRM: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); +#if defined(CSI_SUPPORT) + case WLC_E_CSI: + /* defferred the process due to extra IOVAR may execute */ + break; +#endif /* CSI_SUPPORT */ + case WLC_E_SCAN: + { + const char *scan_state; + UNUSED_PARAMETER(scan_state); + if (reason == WL_SCAN_START) { + scan_state = "WL_SCAN_START"; + } else if (reason == WL_SCAN_END) { + scan_state = "WL_SCAN_END"; + } else { + scan_state = "Unknown"; + } + DHD_EVENT(("MACEVENT: %s: scan state %s\n", event_name, scan_state)); + break; + } + case WLC_E_OWE_INFO: + DHD_EVENT(("MACEVENT: %s, MAC %s type:%d\n", event_name, eabuf, reason)); break; default: DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n", @@ -5283,6 +5758,35 @@ dhd_parse_hck_common_sw_event(bcm_xtlv_t *wl_hc) } #endif /* PARSE_DONGLE_HOST_EVENT */ +#ifdef HCHK_COMMON_SW_EVENT +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT +static void +dhd_send_error_alert_event(dhd_pub_t *dhdp, bcm_xtlv_t *wl_hc) +{ + uint16 id; + + id = ltoh16(wl_hc->id); + + switch (id) { + case WL_HC_DD_RX_STALL: + dhdp->alert_reason = ALERT_RX_STALL; + break; + case WL_HC_DD_TX_STALL: + dhdp->alert_reason = ALERT_TX_STALL; + break; + case WL_HC_DD_SCAN_STALL: + dhdp->alert_reason = ALERT_SCAN_STALL; + break; + case WL_HC_DD_TXQ_STALL: + dhdp->alert_reason = ALERT_FW_QUEUE_STALL; + break; + default: + return; + } + dhd_os_send_alert_message(dhdp); +} +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ +#endif /* HCHK_COMMON_SW_EVENT */ void dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, @@ -5292,6 +5796,7 @@ dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, uint16 type = ntoh16_ua((void *)&dngl_event->event_type); uint16 datalen = ntoh16_ua((void *)&dngl_event->datalen); uint16 version = ntoh16_ua((void *)&dngl_event->version); + bool ignore_hc = FALSE; DHD_EVENT(("VERSION:%d, EVENT TYPE:%d, DATALEN:%d\n", version, type, datalen)); if (datalen > (pktlen - sizeof(bcm_dngl_event_t) + ETHER_TYPE_LEN)) { @@ -5394,10 +5899,29 @@ dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, BCM_REFERENCE(wl_hc); DHD_EVENT(("WL SW HC type %d len %d\n", ltoh16(wl_hc->id), ltoh16(wl_hc->len))); +#ifdef DHD_LB_STATS + if ((ltoh16(wl_hc->id) == WL_HC_DD_RX_DMA_STALL) && + (dhdp->lb_rxp_stop_thr_hitcnt > + dhdp->lb_rxp_strt_thr_hitcnt)) { + ignore_hc = TRUE; + dhdp->rx_dma_stall_hc_ignore_cnt++; + DHD_ERROR(("%s:lb_rxp_stop_thr_hitcnt(%llu)" + " > lb_rxp_strt_thr_hitcnt(%llu)" + " rx_dma_stall_hc_ignore_cnt(%llu)" + "\n", + __FUNCTION__, + dhdp->lb_rxp_stop_thr_hitcnt, + dhdp->lb_rxp_strt_thr_hitcnt, + dhdp->rx_dma_stall_hc_ignore_cnt)); + } +#endif /* DHD_LB_STATS */ #ifdef PARSE_DONGLE_HOST_EVENT dhd_parse_hck_common_sw_event(wl_hc); #endif /* PARSE_DONGLE_HOST_EVENT */ +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT + dhd_send_error_alert_event(dhdp, wl_hc); +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ break; } @@ -5421,6 +5945,28 @@ dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, } break; } + case DNGL_E_SPMI_RESET_IND: + { + bcm_dngl_spmi_reset_ind_v1_t *spmi_reset_ind_v1_ptr = + (bcm_dngl_spmi_reset_ind_v1_t *)p; + uint16 ver = ltoh32(spmi_reset_ind_v1_ptr->version); + switch (ver) { + case DNGL_E_SPMI_RESET_IND_VERSION_1: + { + uint16 num_resets = ltoh32(spmi_reset_ind_v1_ptr->num_resets); + uint16 slave_idx = ltoh32(spmi_reset_ind_v1_ptr->slave_idx); + UNUSED_PARAMETER(num_resets); + UNUSED_PARAMETER(slave_idx); + DHD_EVENT(("DNGL_E_SPMI_RESET_IND resets=%u SPMI core=%u\n", + num_resets, slave_idx)); + break; + } + default: + DHD_ERROR(("DNGL_E_SPMI_RESET_IND: unknown version\n")); + break; + } + break; + } default: DHD_ERROR(("%s:Unknown DNGL Event Type:%d\n", __FUNCTION__, type)); if (p && DHD_EVENT_ON()) { @@ -5428,22 +5974,27 @@ dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, } break; } + + /* Skip socram collection if ignore_hc is set */ + if (!ignore_hc) { #ifndef BCMDBUS #ifdef DHD_FW_COREDUMP - if (dhdp->memdump_enabled) { - dhdp->memdump_type = DUMP_TYPE_DONGLE_HOST_EVENT; - if ( + if (dhdp->memdump_enabled) { + dhdp->memdump_type = DUMP_TYPE_DONGLE_HOST_EVENT; + if ( #ifdef GDB_PROXY - !dhdp->gdb_proxy_active && + !dhdp->gdb_proxy_active && #endif /* GDB_PROXY */ - dhd_schedule_socram_dump(dhdp)) { - DHD_ERROR(("%s: socram dump failed\n", __FUNCTION__)); + dhd_schedule_socram_dump(dhdp)) { + DHD_ERROR(("%s: socram dump failed\n", __FUNCTION__)); + } } - } #else - dhd_dbg_send_urgent_evt(dhdp, p, datalen); + dhd_dbg_send_urgent_evt(dhdp, p, datalen); #endif /* DHD_FW_COREDUMP */ #endif /* !BCMDBUS */ + } + } #endif /* DNGL_EVENT_SUPPORT */ @@ -5611,6 +6162,9 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen case WLC_E_IF: { struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data; +#if defined(__linux__) + struct net_device *ndev = NULL; +#endif /* __linux__ */ /* Ignore the event if NOIF is set */ if (ifevent->reserved & WLC_E_IF_FLAGS_BSSCFG_NOIF) { @@ -5656,7 +6210,20 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen __FUNCTION__, ifevent->ifidx, event->ifname)); return (BCME_ERROR); } +#if defined(__linux__) + ndev = dhd_idx2net(dhd_pub, ifevent->ifidx); + if (ndev) { + dhd_clear_del_in_progress(dhd_pub, ndev); + } +#endif /* __linux__ */ } else if (ifevent->opcode == WLC_E_IF_DEL) { +#if defined(__linux__) + ndev = dhd_idx2net(dhd_pub, ifevent->ifidx); + if (ndev) { + dhd_set_del_in_progress(dhd_pub, ndev); + netif_tx_disable(ndev); + } +#endif /* __linux__ */ #ifdef PCIE_FULL_DONGLE dhd_flow_rings_delete(dhd_pub, (uint8)dhd_ifname2idx(dhd_pub->info, event->ifname)); @@ -5697,7 +6264,6 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen #if defined(RTT_SUPPORT) case WLC_E_PROXD: #ifndef WL_CFG80211 - dhd_rtt_event_handler(dhd_pub, event, (void *)event_data); #endif /* WL_CFG80211 */ break; #endif /* RTT_SUPPORT */ @@ -5729,16 +6295,12 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen event->ifname), (void*) event_data); break; #endif /* BCM_ROUTER_DHD */ -#ifdef BCMDBG +#if defined(DHD_MACDBG) && defined(BCMDBG) case WLC_E_MACDBG: dhd_macdbg_event_handler(dhd_pub, reason, event_data, datalen); break; -#endif /* BCMDBG */ +#endif /* defined(DHD_MACDBG) && defined(BCMDBG) */ case WLC_E_NATOE_NFCT: -#ifdef WL_NATOE - DHD_EVENT(("%s: WLC_E_NATOE_NFCT event received \n", __FUNCTION__)); - dhd_natoe_ct_event(dhd_pub, event_data); -#endif /* WL_NATOE */ break; case WLC_E_SLOTTED_BSS_PEER_OP: DHD_EVENT(("%s: WLC_E_SLOTTED_BSS_PEER_OP event received for peer: " @@ -5799,8 +6361,9 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen dhd_flow_rings_delete(dhd_pub, (uint8)dhd_ifname2idx(dhd_pub->info, event->ifname)); } - /* fall through */ #endif /* PCIE_FULL_DONGLE */ + /* fall through */ + fallthrough; case WLC_E_DEAUTH: case WLC_E_DEAUTH_IND: case WLC_E_DISASSOC: @@ -5818,8 +6381,10 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen del_sta = FALSE; } #endif /* WL_CFG80211 */ - DHD_EVENT(("%s: Link event %d, flags %x, status %x, role %d, del_sta %d\n", - __FUNCTION__, type, flags, status, role, del_sta)); + DHD_EVENT(("%s: Link event %d, flags %x, status %x, " + "reason=%d, role %d, del_sta %d\n", + __FUNCTION__, type, flags, status, + reason, role, del_sta)); if (del_sta) { DHD_EVENT(("%s: Deleting STA " MACDBG "\n", @@ -5838,7 +6403,6 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen } #endif /* PCIE_FULL_DONGLE */ #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT - /* fall through */ ifp = dhd_get_ifp(dhd_pub, event->ifidx); if (ifp) { ifp->recv_reassoc_evt = FALSE; @@ -5846,6 +6410,7 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen } #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */ /* fall through */ + fallthrough; default: *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); #ifdef DHD_UPDATE_INTF_MAC @@ -6260,7 +6825,7 @@ dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) *endptr = '\0'; rc = wl_pkt_filter_base_parse(argv[i]); if (rc == -1) { - printf("Invalid base %s\n", argv[i]); + DHD_ERROR(("Invalid base %s\n", argv[i])); goto fail; } *endptr = ':'; @@ -6268,7 +6833,7 @@ dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) } if (endptr == NULL) { - printf("Invalid [base:]offset format: %s\n", argv[i]); + DHD_ERROR(("Invalid [base:]offset format: %s\n", argv[i])); goto fail; } @@ -6281,11 +6846,11 @@ dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) } if (*endptr) { - printf("Invalid [base:]offset format: %s\n", argv[i]); + DHD_ERROR(("Invalid [base:]offset format: %s\n", argv[i])); goto fail; } if (rc > 0x0000FFFF) { - printf("Offset too large\n"); + DHD_ERROR(("Offset too large\n")); goto fail; } pf_el->rel_offs = htod16(rc); @@ -6295,18 +6860,18 @@ dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) /* Parse pattern filter mask and pattern directly into ioctl buffer */ if (argv[++i] == NULL) { - printf("Bitmask not provided\n"); + DHD_ERROR(("Bitmask not provided\n")); goto fail; } rc = wl_pattern_atoh(argv[i], (char*)pf_el->mask_and_data); if ((rc == -1) || (rc > MAX_PKTFLT_FIXED_PATTERN_SIZE)) { - printf("Rejecting: %s\n", argv[i]); + DHD_ERROR(("Rejecting: %s\n", argv[i])); goto fail; } mask_size = htod16(rc); if (argv[++i] == NULL) { - printf("Pattern not provided\n"); + DHD_ERROR(("Pattern not provided\n")); goto fail; } @@ -6315,19 +6880,19 @@ dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) pf_el->match_flags = htod16(WL_PKT_FILTER_MFLAG_NEG); if (*(++endptr) == '\0') { - printf("Pattern not provided\n"); + DHD_ERROR(("Pattern not provided\n")); goto fail; } } rc = wl_pattern_atoh(endptr, (char*)&pf_el->mask_and_data[rc]); if ((rc == -1) || (rc > MAX_PKTFLT_FIXED_PATTERN_SIZE)) { - printf("Rejecting: %s\n", argv[i]); + DHD_ERROR(("Rejecting: %s\n", argv[i])); goto fail; } pattern_size = htod16(rc); if (mask_size != pattern_size) { - printf("Mask and pattern not the same size\n"); + DHD_ERROR(("Mask and pattern not the same size\n")); goto fail; } @@ -7020,7 +7585,7 @@ dhd_iscan_get_partial_result(void *dhdp, uint *scan_count) { wl_iscan_results_t *list_buf; wl_iscan_results_t list; - wl_scan_results_t *results; + wl_scan_results_v109_t *results; iscan_buf_t *iscan_cur; int status = -1; dhd_pub_t *dhd = dhd_bus_pub(dhdp); @@ -7216,232 +7781,29 @@ bool dhd_is_associated(dhd_pub_t *dhd, uint8 ifidx, int *retval) return TRUE; } -/* Function to estimate possible DTIM_SKIP value */ -#if defined(OEM_ANDROID) && defined(BCMPCIE) -int -dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd, int *dtim_period, int *bcn_interval) +#if defined(__linux__) +/* + * returns = TRUE if anyone is associated, FALSE if all are disassociated + */ +bool dhd_scan_associated(dhd_pub_t *dhd, struct net_device *ndev) { - int bcn_li_dtim = 1; /* deafult no dtim skip setting */ - int ret = -1; - int allowed_skip_dtim_cnt = 0; + dhd_if_t *ifp = NULL; + u32 idx = 0; - if (dhd->disable_dtim_in_suspend) { - DHD_ERROR(("%s Disable bcn_li_dtim in suspend\n", __FUNCTION__)); - bcn_li_dtim = 0; - return bcn_li_dtim; + for (idx = 0; idx < DHD_MAX_IFS; idx++) { + ifp = dhd_get_ifp(dhd, idx); + if (!ifp) + continue; + if (ifp->net == ndev) + continue; + if (!dhd_is_associated(dhd, idx, NULL)) + continue; + return TRUE; } - /* Check if associated */ - if (dhd_is_associated(dhd, 0, NULL) == FALSE) { - DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); - return bcn_li_dtim; - } - - if (dtim_period == NULL || bcn_interval == NULL) - return bcn_li_dtim; - - /* read associated AP beacon interval */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD, - bcn_interval, sizeof(*bcn_interval), FALSE, 0)) < 0) { - DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret)); - return bcn_li_dtim; - } - - /* read associated AP dtim setup */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, - dtim_period, sizeof(*dtim_period), FALSE, 0)) < 0) { - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); - return bcn_li_dtim; - } - - /* if not assocated just return */ - if (*dtim_period == 0) { - return bcn_li_dtim; - } - - if (dhd->max_dtim_enable) { - bcn_li_dtim = - (int) (MAX_DTIM_ALLOWED_INTERVAL / ((*dtim_period) * (*bcn_interval))); - if (bcn_li_dtim == 0) { - bcn_li_dtim = 1; - } - } else { - /* attemp to use platform defined dtim skip interval */ - bcn_li_dtim = dhd->suspend_bcn_li_dtim; - - /* check if sta listen interval fits into AP dtim */ - if (*dtim_period > CUSTOM_LISTEN_INTERVAL) { - /* AP DTIM to big for our Listen Interval : no dtim skiping */ - bcn_li_dtim = NO_DTIM_SKIP; - DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", - __FUNCTION__, *dtim_period, CUSTOM_LISTEN_INTERVAL)); - return bcn_li_dtim; - } - - if (((*dtim_period) * (*bcn_interval) * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) { - allowed_skip_dtim_cnt = - MAX_DTIM_ALLOWED_INTERVAL / ((*dtim_period) * (*bcn_interval)); - bcn_li_dtim = - (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP; - } - - if ((bcn_li_dtim * (*dtim_period)) > CUSTOM_LISTEN_INTERVAL) { - /* Round up dtim_skip to fit into STAs Listen Interval */ - bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / *dtim_period); - DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); - } - } - - if (dhd->conf->suspend_bcn_li_dtim >= 0) - bcn_li_dtim = dhd->conf->suspend_bcn_li_dtim; - DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", - __FUNCTION__, *bcn_interval, bcn_li_dtim, *dtim_period, CUSTOM_LISTEN_INTERVAL)); - - return bcn_li_dtim; + return FALSE; } -#else /* OEM_ANDROID && BCMPCIE */ -int -dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) -{ - int bcn_li_dtim = 1; /* deafult no dtim skip setting */ - int ret = -1; - int dtim_period = 0; - int ap_beacon = 0; - int allowed_skip_dtim_cnt = 0; - - if (dhd->disable_dtim_in_suspend) { - DHD_ERROR(("%s Disable bcn_li_dtim in suspend\n", __FUNCTION__)); - bcn_li_dtim = 0; - goto exit; - } - - /* Check if associated */ - if (dhd_is_associated(dhd, 0, NULL) == FALSE) { - DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); - goto exit; - } - - /* read associated AP beacon interval */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD, - &ap_beacon, sizeof(ap_beacon), FALSE, 0)) < 0) { - DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret)); - goto exit; - } - - /* read associated ap's dtim setup */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, - &dtim_period, sizeof(dtim_period), FALSE, 0)) < 0) { - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); - goto exit; - } - - /* if not assocated just exit */ - if (dtim_period == 0) { - goto exit; - } - - if (dhd->max_dtim_enable) { - bcn_li_dtim = - (int) (MAX_DTIM_ALLOWED_INTERVAL / (ap_beacon * dtim_period)); - if (bcn_li_dtim == 0) { - bcn_li_dtim = 1; - } - } else { - /* attemp to use platform defined dtim skip interval */ - bcn_li_dtim = dhd->suspend_bcn_li_dtim; - - /* check if sta listen interval fits into AP dtim */ - if (dtim_period > CUSTOM_LISTEN_INTERVAL) { - /* AP DTIM to big for our Listen Interval : no dtim skiping */ - bcn_li_dtim = NO_DTIM_SKIP; - DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", - __FUNCTION__, dtim_period, CUSTOM_LISTEN_INTERVAL)); - goto exit; - } - - if ((dtim_period * ap_beacon * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) { - allowed_skip_dtim_cnt = - MAX_DTIM_ALLOWED_INTERVAL / (dtim_period * ap_beacon); - bcn_li_dtim = - (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP; - } - - if ((bcn_li_dtim * dtim_period) > CUSTOM_LISTEN_INTERVAL) { - /* Round up dtim_skip to fit into STAs Listen Interval */ - bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_period); - DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); - } - } - - if (dhd->conf->suspend_bcn_li_dtim >= 0) - bcn_li_dtim = dhd->conf->suspend_bcn_li_dtim; - DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", - __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL)); - -exit: - return bcn_li_dtim; -} -#endif /* OEM_ANDROID && BCMPCIE */ - -#ifdef CONFIG_SILENT_ROAM -int -dhd_sroam_set_mon(dhd_pub_t *dhd, bool set) -{ - int ret = BCME_OK; - wlc_sroam_t *psroam; - wlc_sroam_info_t *sroam; - uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN; - - /* Check if associated */ - if (dhd_is_associated(dhd, 0, NULL) == FALSE) { - DHD_TRACE(("%s NOT assoc\n", __FUNCTION__)); - return ret; - } - - if (set && (dhd->op_mode & - (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) { - DHD_INFO((" Failed to set sroam %d, op_mode 0x%04x\n", set, dhd->op_mode)); - return ret; - } - - if (!dhd->sroam_turn_on) { - DHD_INFO((" Failed to set sroam %d, sroam turn %d\n", set, dhd->sroam_turn_on)); - return ret; - } - psroam = (wlc_sroam_t *)MALLOCZ(dhd->osh, sroamlen); - if (!psroam) { - DHD_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__)); - return BCME_NOMEM; - } - - ret = dhd_iovar(dhd, 0, "sroam", NULL, 0, (char *)psroam, sroamlen, FALSE); - if (ret < 0) { - DHD_ERROR(("%s Failed to Get sroam %d\n", __FUNCTION__, ret)); - goto done; - } - - if (psroam->ver != WLC_SILENT_ROAM_CUR_VER) { - ret = BCME_VERSION; - goto done; - } - - sroam = (wlc_sroam_info_t *)psroam->data; - sroam->sroam_on = set; - DHD_INFO((" Silent roam monitor mode %s\n", set ? "On" : "Off")); - - ret = dhd_iovar(dhd, 0, "sroam", (char *)psroam, sroamlen, NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Failed to Set sroam %d\n", __FUNCTION__, ret)); - } - -done: - if (psroam) { - MFREE(dhd->osh, psroam, sroamlen); - } - - return ret; -} -#endif /* CONFIG_SILENT_ROAM */ +#endif /* __linux__ */ /* Check if the mode supports STA MODE */ bool dhd_support_sta_mode(dhd_pub_t *dhd) @@ -7460,8 +7822,8 @@ int dhd_keep_alive_onoff(dhd_pub_t *dhd) { char buf[32] = {0}; const char *str; - wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0, 0, 0, 0, 0, {0}}; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; + wl_mkeep_alive_pkt_v1_t mkeep_alive_pkt = {0, 0, 0, 0, 0, {0}}; + wl_mkeep_alive_pkt_v1_t *mkeep_alive_pktp; int buf_len; int str_len; int res = -1; @@ -7474,10 +7836,10 @@ int dhd_keep_alive_onoff(dhd_pub_t *dhd) str = "mkeep_alive"; str_len = strlen(str); strlcpy(buf, str, sizeof(buf)); - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); + mkeep_alive_pktp = (wl_mkeep_alive_pkt_v1_t *) (buf + str_len + 1); mkeep_alive_pkt.period_msec = dhd->conf->keep_alive_period; buf_len = str_len + 1; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION_1); mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); /* Setup keep alive zero for null packet generation */ mkeep_alive_pkt.keep_alive_id = 0; @@ -7853,7 +8215,7 @@ int dhd_get_download_buffer(dhd_pub_t *dhd, char *file_path, download_type_t com *length = fw->size; goto err; } - *buffer = VMALLOCZ(dhd->osh, fw->size); + *buffer = VMALLOCZ(dhd->osh, *length); if (*buffer == NULL) { DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, (int)fw->size)); @@ -7886,7 +8248,6 @@ err: */ int dhd_get_download_buffer(dhd_pub_t *dhd, char *file_path, download_type_t component, char ** buffer, int *length) - { int ret = BCME_ERROR; int len = 0; @@ -7935,33 +8296,20 @@ int dhd_get_download_buffer(dhd_pub_t *dhd, char *file_path, download_type_t com goto err; } } - buf = MALLOCZ(dhd->osh, file_len); if (buf == NULL) { DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, file_len)); + ret = BCME_NOMEM; goto err; } /* Download image */ -#if defined(BCMEMBEDIMAGE) && defined(DHD_EFI) - if (!image) { - memcpy(buf, nvram_arr, sizeof(nvram_arr)); - len = sizeof(nvram_arr); - } else { - len = dhd_os_get_image_block((char *)buf, file_len, image); - if ((len <= 0 || len > file_len)) { - MFREE(dhd->osh, buf, file_len); - goto err; - } - } -#else len = dhd_os_get_image_block((char *)buf, file_len, image); if ((len <= 0 || len > file_len)) { MFREE(dhd->osh, buf, file_len); goto err; } -#endif /* DHD_EFI */ } ret = BCME_OK; @@ -8105,9 +8453,10 @@ dhd_download_blob_cached(dhd_pub_t *dhd, char *file_path, int ret = BCME_ERROR; uint chunk_len, size2alloc, data_offset, file_offset; unsigned char *pay_load, *dnld_buf; - char *memblock; + char *memblock = NULL; uint16 dl_flag = DL_BEGIN; download_type_t dl_type; + uint32 memblock_len = len; data_offset = OFFSETOF(wl_dload_data_t, data); size2alloc = data_offset + MAX_CHUNK_LEN; @@ -8156,6 +8505,9 @@ exit: if (dnld_buf) { MFREE(dhd->osh, dnld_buf, size2alloc); } + if (memblock) { + dhd_free_download_buffer(dhd, memblock, memblock_len); + } return ret; } @@ -8200,6 +8552,7 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) imgbuf = dhd_os_open_image((char *)clm_blob_path); if (imgbuf == NULL) { + DHD_ERROR(("%s: clm from path %s open fail\n", __func__, clm_path)); goto exit; } @@ -8340,6 +8693,9 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) int err = BCME_OK; char iovbuf[WLC_IOCTL_SMLEN]; int status = FALSE; +#ifdef SUPPORT_OTA_UPDATE + ota_update_info_t *ota_info = &dhd->ota_update_info; +#endif /* SUPPORT_OTA_UPDATE */ if (clm_path && clm_path[0] != '\0') { if (strlen(clm_path) > MOD_PARAM_PATHLEN) { @@ -8379,9 +8735,7 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) if (memblock == NULL) { printf("%s: Ignore clm file %s\n", __FUNCTION__, clm_path); #if defined(DHD_BLOB_EXISTENCE_CHECK) - if (dhd->is_blob) { - err = BCME_ERROR; - } else { + if (!dhd->is_blob) { status = dhd_check_current_clm_data(dhd); if (status == TRUE) { err = BCME_OK; @@ -8392,7 +8746,7 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) #endif /* DHD_BLOB_EXISTENCE_CHECK */ goto exit; } -#endif /* !LINUX && !linux */ +#endif /* defined(LINUX) || defined(linux) */ if ((len > 0) && (len < MAX_CLM_BUF_SIZE) && memblock) { status = dhd_check_current_clm_data(dhd); @@ -8440,7 +8794,7 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) err = BCME_ERROR; goto exit; } else { - DHD_INFO(("%s: CLM download succeeded \n", __FUNCTION__)); + DHD_ERROR(("%s: CLM download succeeded \n", __FUNCTION__)); } } else { DHD_INFO(("Skipping the clm download. len:%d memblk:%p \n", len, memblock)); @@ -8457,11 +8811,20 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) exit: if (memblock) { +#ifdef SUPPORT_OTA_UPDATE + if (ota_info->clm_len) { + MFREE(dhd->osh, ota_info->clm_buf, ota_info->clm_len); + ota_info->clm_len = 0; + } + else +#endif /* SUPPORT_OTA_UPDATE */ + { #if (defined(LINUX) || defined(linux)) && !defined(DHD_LINUX_STD_FW_API) - dhd_os_close_image1(dhd, memblock); + dhd_os_close_image1(dhd, memblock); #else - dhd_free_download_buffer(dhd, memblock, memblock_len); + dhd_free_download_buffer(dhd, memblock, memblock_len); #endif /* LINUX || linux */ + } } return err; @@ -8570,7 +8933,6 @@ dhd_cmd_timeout(void *ctx) DHD_ERROR(("%s: dhd_stop_cmd_timer() failed\n", __FUNCTION__)); ASSERT(0); } - dhd_wakeup_ioctl_event(pub, IOCTL_RETURN_ON_ERROR); if (!dhd_query_bus_erros(pub)) dhd_send_trap_to_fw_for_timeout(pub, DHD_REASON_COMMAND_TO); } else { @@ -9156,6 +9518,8 @@ dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size, int32 i = 0; uint8 *pfw_id = NULL; uint32 fwid = 0; + char fwid_str[FWID_STR_LEN]; + uint32 hdr_logstrs_size = 0; #ifdef DHD_LINUX_STD_FW_API int err = 0; const struct firmware *fw = NULL; @@ -9163,13 +9527,10 @@ dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size, void *file = NULL; int file_len = 0; #endif /* DHD_LINUX_STD_FW_API */ - char fwid_str[FWID_STR_LEN]; - uint32 hdr_logstrs_size = 0; /* Read last three words in the logstrs.bin file */ trailer = (logstr_trailer_t *) (raw_fmts + logstrs_size - sizeof(logstr_trailer_t)); - if (trailer->log_magic == LOGSTRS_MAGIC) { /* * logstrs.bin has a header. @@ -9194,7 +9555,6 @@ dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size, /* For ver. 2 of the header, need to match fwid of * both logstrs.bin and fw bin */ - #ifdef DHD_LINUX_STD_FW_API err = dhd_os_get_img_fwreq(&fw, st_str_file_path); if (err < 0) { @@ -9262,7 +9622,6 @@ dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size, __FUNCTION__, hdr->fw_id, fwid)); goto error; } - match_fail = FALSE; num_fmts = hdr->rom_logstrs_offset / sizeof(uint32); ram_index = (hdr->ram_lognums_offset - @@ -9325,7 +9684,6 @@ error: return BCME_ERROR; } event_log->fmts_size = num_fmts * sizeof(char *); - for (i = 0; i < num_fmts; i++) { /* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base * (they are 0-indexed relative to 'rom_logstrs_offset'). @@ -9346,7 +9704,7 @@ error: } /* dhd_parse_logstrs_file */ #ifdef DHD_LINUX_STD_FW_API -int dhd_parse_map_file(osl_t *osh, void *ptr, uint32 *ramstart, uint32 *rodata_start, +int dhd_parse_map_file(osl_t *osh, const void *ptr, uint32 *ramstart, uint32 *rodata_start, uint32 *rodata_end) { char *raw_fmts = NULL, *raw_fmts_loc = NULL; @@ -9360,7 +9718,7 @@ int dhd_parse_map_file(osl_t *osh, void *ptr, uint32 *ramstart, uint32 *rodata_s *ramstart = 0; *rodata_start = 0; *rodata_end = 0; - size = (uint32)(((struct firmware *)ptr)->size); + size = (uint32)(((const struct firmware *)ptr)->size); /* Allocate 1 byte more than read_size to terminate it with NULL */ raw_fmts = MALLOCZ(osh, read_size + 1); @@ -9378,7 +9736,7 @@ int dhd_parse_map_file(osl_t *osh, void *ptr, uint32 *ramstart, uint32 *rodata_s } error = memcpy_s(raw_fmts, read_size, - (((char *)((struct firmware *)ptr)->data) + offset), read_size); + (((const char *)((const struct firmware *)ptr)->data) + offset), read_size); if (error) { DHD_ERROR(("%s: failed to copy raw_fmts, err=%d\n", __FUNCTION__, error)); @@ -9473,7 +9831,6 @@ int dhd_parse_map_file(osl_t *osh, void *file, uint32 *ramstart, uint32 *rodata_ /* End raw_fmts with NULL as strstr expects NULL terminated strings */ raw_fmts[read_size] = '\0'; - /* Get ramstart address */ raw_fmts_loc = raw_fmts; if (!(count & RAMSTART_BIT) && @@ -9519,7 +9876,12 @@ int dhd_parse_map_file(osl_t *osh, void *file, uint32 *ramstart, uint32 *rodata_ * go back to predefined NUM of bytes so that we won't miss * the string and addr even if it comes as splited in next read. */ - dhd_os_seek_file(file, -GO_BACK_FILE_POS_NUM_BYTES); + error = dhd_os_seek_file(file, -GO_BACK_FILE_POS_NUM_BYTES); + if (error < 0) { + DHD_ERROR(("%s: map file seek failed err:%d \n", __FUNCTION__, + error)); + goto fail; + } } fail: @@ -9600,19 +9962,6 @@ exit: #endif /* PCIE_FULL_DONGLE */ #endif /* SHOW_LOGTRACE */ -#ifdef BTLOG -int -dhd_bt_log_pkt_process(dhd_pub_t *dhdp, void *pktbuf) -{ - DHD_TRACE(("%s:Enter\n", __FUNCTION__)); - - dhd_dbg_bt_log_handler(dhdp, - PKTDATA(dhdp->osh, pktbuf), PKTLEN(dhdp->osh, pktbuf)); - - return BCME_OK; -} -#endif /* BTLOG */ - #if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) /* To handle the TDLS event in the dhd_common.c @@ -9653,7 +10002,7 @@ int dhd_free_tdls_peer_list(dhd_pub_t *dhd_pub) * based on the debug level specified */ void -dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint8 dbg_level) +dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint32 dbg_level) { char line[128], *p; int len = sizeof(line); @@ -9661,12 +10010,15 @@ dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint8 dbg_level) uint i; if (msg && (msg[0] != '\0')) { - if (dbg_level == DHD_ERROR_VAL) + if (dbg_level == DHD_ERROR_VAL) { DHD_ERROR(("%s:\n", msg)); - else if (dbg_level == DHD_INFO_VAL) + } else if (dbg_level == DHD_INFO_VAL) { DHD_INFO(("%s:\n", msg)); - else if (dbg_level == DHD_TRACE_VAL) + } else if (dbg_level == DHD_TRACE_VAL) { DHD_TRACE(("%s:\n", msg)); + } else if (dbg_level == DHD_RPM_VAL) { + DHD_RPM(("%s:\n", msg)); + } } p = line; @@ -9684,12 +10036,16 @@ dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint8 dbg_level) if (i % 16 == 15) { /* flush line */ - if (dbg_level == DHD_ERROR_VAL) + if (dbg_level == DHD_ERROR_VAL) { DHD_ERROR(("%s:\n", line)); - else if (dbg_level == DHD_INFO_VAL) + } else if (dbg_level == DHD_INFO_VAL) { DHD_INFO(("%s:\n", line)); - else if (dbg_level == DHD_TRACE_VAL) + } else if (dbg_level == DHD_TRACE_VAL) { DHD_TRACE(("%s:\n", line)); + } else if (dbg_level == DHD_RPM_VAL) { + DHD_RPM(("%s:\n", line)); + } + p = line; len = sizeof(line); } @@ -9697,12 +10053,15 @@ dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint8 dbg_level) /* flush last partial line */ if (p != line) { - if (dbg_level == DHD_ERROR_VAL) + if (dbg_level == DHD_ERROR_VAL) { DHD_ERROR(("%s:\n", line)); - else if (dbg_level == DHD_INFO_VAL) + } else if (dbg_level == DHD_INFO_VAL) { DHD_INFO(("%s:\n", line)); - else if (dbg_level == DHD_TRACE_VAL) + } else if (dbg_level == DHD_TRACE_VAL) { DHD_TRACE(("%s:\n", line)); + } else if (dbg_level == DHD_RPM_VAL) { + DHD_RPM(("%s:\n", line)); + } } } @@ -9728,13 +10087,6 @@ dhd_tput_test(dhd_pub_t *dhd, tput_test_t *tput_data) bool batch_cnt = FALSE; bool tx_stop_pkt = FALSE; -#if defined(DHD_EFI) && defined(DHD_INTR_POLL_PERIOD_DYNAMIC) - uint32 cur_intr_poll_period = 0; - cur_intr_poll_period = dhd_os_get_intr_poll_period(); - /* before running tput_test, set interrupt poll period to a lesser value */ - dhd_os_set_intr_poll_period(dhd->bus, INTR_POLL_PERIOD_CRITICAL); -#endif /* DHD_EFI && DHD_INTR_POLL_PERIOD_DYNAMIC */ - if (tput_data->version != TPUT_TEST_T_VER || tput_data->length != TPUT_TEST_T_LEN) { DHD_ERROR(("%s: wrong structure ver/len! \n", __FUNCTION__)); @@ -9939,10 +10291,6 @@ exit_error: DHD_ERROR(("%s: pkts_good = %u; pkts_bad = %u; pkts_cmpl = %u\n", __FUNCTION__, dhd->tput_data.pkts_good, dhd->tput_data.pkts_bad, dhd->tput_data.pkts_cmpl)); -#if defined(DHD_EFI) && defined(DHD_INTR_POLL_PERIOD_DYNAMIC) - /* restore interrupt poll period to the previous existing value */ - dhd_os_set_intr_poll_period(dhd->bus, cur_intr_poll_period); -#endif /* DHD_EFI && DHD_INTR_POLL_PERIOD_DYNAMIC */ return err_exit; } @@ -10154,77 +10502,7 @@ dhd_event_logtrace_process_edl(dhd_pub_t *dhdp, uint8 *data, } #endif /* EWP_EDL */ -#ifdef DHD_LOG_DUMP -#define DEBUG_DUMP_TRIGGER_INTERVAL_SEC 4 -void -dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd) -{ -#if defined(DHD_DUMP_FILE_WRITE_FROM_KERNEL) - log_dump_type_t *flush_type; -#endif /* DHD_DUMP_FILE_WRITE_FROM_KERNEL */ - uint64 current_time_sec; - - if (!dhdp) { - DHD_ERROR(("dhdp is NULL !\n")); - return; - } - - if (subcmd >= CMD_MAX || subcmd < CMD_DEFAULT) { - DHD_ERROR(("%s : Invalid subcmd \n", __FUNCTION__)); - return; - } - - current_time_sec = DIV_U64_BY_U32(OSL_LOCALTIME_NS(), NSEC_PER_SEC); - - DHD_ERROR(("%s: current_time_sec=%lld debug_dump_time_sec=%lld interval=%d\n", - __FUNCTION__, current_time_sec, dhdp->debug_dump_time_sec, - DEBUG_DUMP_TRIGGER_INTERVAL_SEC)); - - if ((current_time_sec - dhdp->debug_dump_time_sec) < DEBUG_DUMP_TRIGGER_INTERVAL_SEC) { - DHD_ERROR(("%s : Last debug dump triggered(%lld) within %d seconds, so SKIP\n", - __FUNCTION__, dhdp->debug_dump_time_sec, DEBUG_DUMP_TRIGGER_INTERVAL_SEC)); - return; - } - - clear_debug_dump_time(dhdp->debug_dump_time_str); -#ifdef DHD_PCIE_RUNTIMEPM - /* wake up RPM if SYSDUMP is triggered */ - dhdpcie_runtime_bus_wake(dhdp, TRUE, __builtin_return_address(0)); -#endif /* DHD_PCIE_RUNTIMEPM */ - /* */ - - dhdp->debug_dump_subcmd = subcmd; - - dhdp->debug_dump_time_sec = DIV_U64_BY_U32(OSL_LOCALTIME_NS(), NSEC_PER_SEC); - -#if defined(DHD_DUMP_FILE_WRITE_FROM_KERNEL) - /* flush_type is freed at do_dhd_log_dump function */ - flush_type = MALLOCZ(dhdp->osh, sizeof(log_dump_type_t)); - if (flush_type) { - *flush_type = DLD_BUF_TYPE_ALL; - dhd_schedule_log_dump(dhdp, flush_type); - } else { - DHD_ERROR(("%s Fail to malloc flush_type\n", __FUNCTION__)); - return; - } -#endif /* DHD_DUMP_FILE_WRITE_FROM_KERNEL */ - - /* Inside dhd_mem_dump, event notification will be sent to HAL and - * from other context DHD pushes memdump, debug_dump and pktlog dump - * to HAL and HAL will write into file - */ -#if (defined(BCMPCIE) || defined(BCMSDIO)) && defined(DHD_FW_COREDUMP) - dhdp->memdump_type = DUMP_TYPE_BY_SYSDUMP; - dhd_bus_mem_dump(dhdp); -#endif /* BCMPCIE && DHD_FW_COREDUMP */ - -#if defined(DHD_PKT_LOGGING) && defined(DHD_DUMP_FILE_WRITE_FROM_KERNEL) - dhd_schedule_pktlog_dump(dhdp); -#endif /* DHD_PKT_LOGGING && DHD_DUMP_FILE_WRITE_FROM_KERNEL */ -} -#endif /* DHD_LOG_DUMP */ - -#if (defined(LINUX) || defined(DHD_EFI)) && defined(SHOW_LOGTRACE) +#if defined(LINUX) && defined(SHOW_LOGTRACE) int dhd_print_fw_ver_from_file(dhd_pub_t *dhdp, char *fwpath) { @@ -10294,25 +10572,9 @@ exit: return ret; } -#endif /* LINUX || DHD_EFI */ - -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) -void -dhd_clear_awdl_stats(dhd_pub_t *dhd) -{ - unsigned long flags; - /* - * Since event path(ex: WLC_E_AWDL_AW) and bus path(tx status process) update - * the AWDL data acquire lock before clearing the AWDL stats. - */ - DHD_AWDL_STATS_LOCK(dhd->awdl_stats_lock, flags); - memset(dhd->awdl_stats, 0, sizeof(dhd->awdl_stats)); - DHD_AWDL_STATS_UNLOCK(dhd->awdl_stats_lock, flags); -} -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ +#endif /* LINUX && SHOW_LOGTRACE */ #ifdef WL_CFGVENDOR_SEND_HANG_EVENT - static void copy_hang_info_ioctl_timeout(dhd_pub_t *dhd, int ifidx, wl_ioctl_t *ioc) { @@ -10851,193 +11113,6 @@ fail: } return rc; } -#ifdef DHD_LOG_DUMP -int -dhd_dump_debug_ring(dhd_pub_t *dhdp, void *ring_ptr, const void *user_buf, - log_dump_section_hdr_t *sec_hdr, - char *text_hdr, int buflen, uint32 sec_type) -{ - uint32 rlen = 0; - uint32 data_len = 0; - void *data = NULL; - unsigned long flags = 0; - int ret = 0; - dhd_dbg_ring_t *ring = (dhd_dbg_ring_t *)ring_ptr; - int pos = 0; - int fpos_sechdr = 0; - - if (!dhdp || !ring || !user_buf || !sec_hdr || !text_hdr) { - return BCME_BADARG; - } - /* do not allow further writes to the ring - * till we flush it - */ - DHD_DBG_RING_LOCK(ring->lock, flags); - ring->state = RING_SUSPEND; - DHD_DBG_RING_UNLOCK(ring->lock, flags); - - if (dhdp->concise_dbg_buf) { - /* re-use concise debug buffer temporarily - * to pull ring data, to write - * record by record to file - */ - data_len = CONCISE_DUMP_BUFLEN; - data = dhdp->concise_dbg_buf; - ret = dhd_export_debug_data(text_hdr, NULL, user_buf, strlen(text_hdr), &pos); - /* write the section header now with zero length, - * once the correct length is found out, update - * it later - */ - fpos_sechdr = pos; - sec_hdr->type = sec_type; - sec_hdr->length = 0; - ret = dhd_export_debug_data((char *)sec_hdr, NULL, user_buf, - sizeof(*sec_hdr), &pos); - do { - rlen = dhd_dbg_ring_pull_single(ring, data, data_len, TRUE); - if (rlen > 0) { - /* write the log */ - ret = dhd_export_debug_data(data, NULL, user_buf, rlen, &pos); - } - DHD_DBGIF(("%s: rlen : %d\n", __FUNCTION__, rlen)); - } while ((rlen > 0)); - /* now update the section header length in the file */ - /* Complete ring size is dumped by HAL, hence updating length to ring size */ - sec_hdr->length = ring->ring_size; - ret = dhd_export_debug_data((char *)sec_hdr, NULL, user_buf, - sizeof(*sec_hdr), &fpos_sechdr); - } else { - DHD_ERROR(("%s: No concise buffer available !\n", __FUNCTION__)); - } - DHD_DBG_RING_LOCK(ring->lock, flags); - ring->state = RING_ACTIVE; - /* Resetting both read and write pointer, - * since all items are read. - */ - ring->rp = ring->wp = 0; - DHD_DBG_RING_UNLOCK(ring->lock, flags); - - return ret; -} - -int -dhd_log_dump_ring_to_file(dhd_pub_t *dhdp, void *ring_ptr, void *file, - unsigned long *file_posn, log_dump_section_hdr_t *sec_hdr, - char *text_hdr, uint32 sec_type) -{ - uint32 rlen = 0; - uint32 data_len = 0, total_len = 0; - void *data = NULL; - unsigned long fpos_sechdr = 0; - unsigned long flags = 0; - int ret = 0; - dhd_dbg_ring_t *ring = (dhd_dbg_ring_t *)ring_ptr; - - if (!dhdp || !ring || !file || !sec_hdr || - !file_posn || !text_hdr) - return BCME_BADARG; - - /* do not allow further writes to the ring - * till we flush it - */ - DHD_DBG_RING_LOCK(ring->lock, flags); - ring->state = RING_SUSPEND; - DHD_DBG_RING_UNLOCK(ring->lock, flags); - - if (dhdp->concise_dbg_buf) { - /* re-use concise debug buffer temporarily - * to pull ring data, to write - * record by record to file - */ - data_len = CONCISE_DUMP_BUFLEN; - data = dhdp->concise_dbg_buf; - dhd_os_write_file_posn(file, file_posn, text_hdr, - strlen(text_hdr)); - /* write the section header now with zero length, - * once the correct length is found out, update - * it later - */ - dhd_init_sec_hdr(sec_hdr); - fpos_sechdr = *file_posn; - sec_hdr->type = sec_type; - sec_hdr->length = 0; - dhd_os_write_file_posn(file, file_posn, (char *)sec_hdr, - sizeof(*sec_hdr)); - do { - rlen = dhd_dbg_ring_pull_single(ring, data, data_len, TRUE); - if (rlen > 0) { - /* write the log */ - ret = dhd_os_write_file_posn(file, file_posn, data, rlen); - if (ret < 0) { - DHD_ERROR(("%s: write file error !\n", __FUNCTION__)); - DHD_DBG_RING_LOCK(ring->lock, flags); - ring->state = RING_ACTIVE; - DHD_DBG_RING_UNLOCK(ring->lock, flags); - return BCME_ERROR; - } - } - total_len += rlen; - } while (rlen > 0); - /* now update the section header length in the file */ - sec_hdr->length = total_len; - dhd_os_write_file_posn(file, &fpos_sechdr, (char *)sec_hdr, sizeof(*sec_hdr)); - } else { - DHD_ERROR(("%s: No concise buffer available !\n", __FUNCTION__)); - } - - DHD_DBG_RING_LOCK(ring->lock, flags); - ring->state = RING_ACTIVE; - /* Resetting both read and write pointer, - * since all items are read. - */ - ring->rp = ring->wp = 0; - DHD_DBG_RING_UNLOCK(ring->lock, flags); - return BCME_OK; -} - -/* logdump cookie */ -#define MAX_LOGUDMP_COOKIE_CNT 10u -#define LOGDUMP_COOKIE_STR_LEN 50u -int -dhd_logdump_cookie_init(dhd_pub_t *dhdp, uint8 *buf, uint32 buf_size) -{ - uint32 ring_size; - - if (!dhdp || !buf) { - DHD_ERROR(("INVALID PTR: dhdp:%p buf:%p\n", dhdp, buf)); - return BCME_ERROR; - } - - ring_size = dhd_ring_get_hdr_size() + LOGDUMP_COOKIE_STR_LEN * MAX_LOGUDMP_COOKIE_CNT; - if (buf_size < ring_size) { - DHD_ERROR(("BUF SIZE IS TO SHORT: req:%d buf_size:%d\n", - ring_size, buf_size)); - return BCME_ERROR; - } - - dhdp->logdump_cookie = dhd_ring_init(dhdp, buf, buf_size, - LOGDUMP_COOKIE_STR_LEN, MAX_LOGUDMP_COOKIE_CNT, - DHD_RING_TYPE_FIXED); - if (!dhdp->logdump_cookie) { - DHD_ERROR(("FAIL TO INIT COOKIE RING\n")); - return BCME_ERROR; - } - - return BCME_OK; -} - -void -dhd_logdump_cookie_deinit(dhd_pub_t *dhdp) -{ - if (!dhdp) { - return; - } - if (dhdp->logdump_cookie) { - dhd_ring_deinit(dhdp, dhdp->logdump_cookie); - } - - return; -} #ifdef DHD_TX_PROFILE int @@ -11079,235 +11154,6 @@ dhd_tx_profile_attach(dhd_pub_t *dhdp) } #endif /* defined(DHD_TX_PROFILE) */ -void -dhd_logdump_cookie_save(dhd_pub_t *dhdp, char *cookie, char *type) -{ - char *ptr; - - if (!dhdp || !cookie || !type || !dhdp->logdump_cookie) { - DHD_ERROR(("%s: At least one buffer ptr is NULL dhdp=%p cookie=%p" - " type = %p, cookie_cfg:%p\n", __FUNCTION__, - dhdp, cookie, type, dhdp?dhdp->logdump_cookie: NULL)); - return; - } - ptr = (char *)dhd_ring_get_empty(dhdp->logdump_cookie); - if (ptr == NULL) { - DHD_ERROR(("%s : Skip to save due to locking\n", __FUNCTION__)); - return; - } - scnprintf(ptr, LOGDUMP_COOKIE_STR_LEN, "%s: %s\n", type, cookie); - return; -} - -int -dhd_logdump_cookie_get(dhd_pub_t *dhdp, char *ret_cookie, uint32 buf_size) -{ - char *ptr; - - if (!dhdp || !ret_cookie || !dhdp->logdump_cookie) { - DHD_ERROR(("%s: At least one buffer ptr is NULL dhdp=%p" - "cookie=%p cookie_cfg:%p\n", __FUNCTION__, - dhdp, ret_cookie, dhdp?dhdp->logdump_cookie: NULL)); - return BCME_ERROR; - } - ptr = (char *)dhd_ring_get_first(dhdp->logdump_cookie); - if (ptr == NULL) { - DHD_ERROR(("%s : Skip to save due to locking\n", __FUNCTION__)); - return BCME_ERROR; - } - memcpy(ret_cookie, ptr, MIN(buf_size, strlen(ptr))); - dhd_ring_free_first(dhdp->logdump_cookie); - return BCME_OK; -} - -int -dhd_logdump_cookie_count(dhd_pub_t *dhdp) -{ - if (!dhdp || !dhdp->logdump_cookie) { - DHD_ERROR(("%s: At least one buffer ptr is NULL dhdp=%p cookie=%p\n", - __FUNCTION__, dhdp, dhdp?dhdp->logdump_cookie: NULL)); - return 0; - } - return dhd_ring_get_cur_size(dhdp->logdump_cookie); -} - -static inline int -__dhd_log_dump_cookie_to_file( - dhd_pub_t *dhdp, void *fp, const void *user_buf, unsigned long *f_pos, - char *buf, uint32 buf_size) -{ - - uint32 remain = buf_size; - int ret = BCME_ERROR; - char tmp_buf[LOGDUMP_COOKIE_STR_LEN]; - log_dump_section_hdr_t sec_hdr; - uint32 read_idx; - uint32 write_idx; - - read_idx = dhd_ring_get_read_idx(dhdp->logdump_cookie); - write_idx = dhd_ring_get_write_idx(dhdp->logdump_cookie); - while (dhd_logdump_cookie_count(dhdp) > 0) { - memset(tmp_buf, 0, sizeof(tmp_buf)); - ret = dhd_logdump_cookie_get(dhdp, tmp_buf, LOGDUMP_COOKIE_STR_LEN); - if (ret != BCME_OK) { - return ret; - } - remain -= scnprintf(&buf[buf_size - remain], remain, "%s", tmp_buf); - } - dhd_ring_set_read_idx(dhdp->logdump_cookie, read_idx); - dhd_ring_set_write_idx(dhdp->logdump_cookie, write_idx); - - ret = dhd_export_debug_data(COOKIE_LOG_HDR, fp, user_buf, strlen(COOKIE_LOG_HDR), f_pos); - if (ret < 0) { - DHD_ERROR(("%s : Write file Error for cookie hdr\n", __FUNCTION__)); - return ret; - } - sec_hdr.magic = LOG_DUMP_MAGIC; - sec_hdr.timestamp = local_clock(); - sec_hdr.type = LOG_DUMP_SECTION_COOKIE; - sec_hdr.length = buf_size - remain; - - ret = dhd_export_debug_data((char *)&sec_hdr, fp, user_buf, sizeof(sec_hdr), f_pos); - if (ret < 0) { - DHD_ERROR(("%s : Write file Error for section hdr\n", __FUNCTION__)); - return ret; - } - - ret = dhd_export_debug_data(buf, fp, user_buf, sec_hdr.length, f_pos); - if (ret < 0) { - DHD_ERROR(("%s : Write file Error for cookie data\n", __FUNCTION__)); - } - - return ret; -} - -uint32 -dhd_log_dump_cookie_len(dhd_pub_t *dhdp) -{ - int len = 0; - char tmp_buf[LOGDUMP_COOKIE_STR_LEN]; - log_dump_section_hdr_t sec_hdr; - char *buf = NULL; - int ret = BCME_ERROR; - uint32 buf_size = MAX_LOGUDMP_COOKIE_CNT * LOGDUMP_COOKIE_STR_LEN; - uint32 read_idx; - uint32 write_idx; - uint32 remain; - - remain = buf_size; - - if (!dhdp || !dhdp->logdump_cookie) { - DHD_ERROR(("%s At least one ptr is NULL " - "dhdp = %p cookie %p\n", - __FUNCTION__, dhdp, dhdp?dhdp->logdump_cookie:NULL)); - goto exit; - } - - buf = (char *)MALLOCZ(dhdp->osh, buf_size); - if (!buf) { - DHD_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__)); - goto exit; - } - - read_idx = dhd_ring_get_read_idx(dhdp->logdump_cookie); - write_idx = dhd_ring_get_write_idx(dhdp->logdump_cookie); - while (dhd_logdump_cookie_count(dhdp) > 0) { - memset(tmp_buf, 0, sizeof(tmp_buf)); - ret = dhd_logdump_cookie_get(dhdp, tmp_buf, LOGDUMP_COOKIE_STR_LEN); - if (ret != BCME_OK) { - goto exit; - } - remain -= (uint32)strlen(tmp_buf); - } - dhd_ring_set_read_idx(dhdp->logdump_cookie, read_idx); - dhd_ring_set_write_idx(dhdp->logdump_cookie, write_idx); - len += strlen(COOKIE_LOG_HDR); - len += sizeof(sec_hdr); - len += (buf_size - remain); -exit: - if (buf) - MFREE(dhdp->osh, buf, buf_size); - return len; -} - -int -dhd_log_dump_cookie(dhd_pub_t *dhdp, const void *user_buf) -{ - int ret = BCME_ERROR; - char tmp_buf[LOGDUMP_COOKIE_STR_LEN]; - log_dump_section_hdr_t sec_hdr; - char *buf = NULL; - uint32 buf_size = MAX_LOGUDMP_COOKIE_CNT * LOGDUMP_COOKIE_STR_LEN; - int pos = 0; - uint32 read_idx; - uint32 write_idx; - uint32 remain; - - remain = buf_size; - - if (!dhdp || !dhdp->logdump_cookie) { - DHD_ERROR(("%s At least one ptr is NULL " - "dhdp = %p cookie %p\n", - __FUNCTION__, dhdp, dhdp?dhdp->logdump_cookie:NULL)); - goto exit; - } - - buf = (char *)MALLOCZ(dhdp->osh, buf_size); - if (!buf) { - DHD_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__)); - goto exit; - } - - read_idx = dhd_ring_get_read_idx(dhdp->logdump_cookie); - write_idx = dhd_ring_get_write_idx(dhdp->logdump_cookie); - while (dhd_logdump_cookie_count(dhdp) > 0) { - memset(tmp_buf, 0, sizeof(tmp_buf)); - ret = dhd_logdump_cookie_get(dhdp, tmp_buf, LOGDUMP_COOKIE_STR_LEN); - if (ret != BCME_OK) { - goto exit; - } - remain -= scnprintf(&buf[buf_size - remain], remain, "%s", tmp_buf); - } - dhd_ring_set_read_idx(dhdp->logdump_cookie, read_idx); - dhd_ring_set_write_idx(dhdp->logdump_cookie, write_idx); - ret = dhd_export_debug_data(COOKIE_LOG_HDR, NULL, user_buf, strlen(COOKIE_LOG_HDR), &pos); - sec_hdr.magic = LOG_DUMP_MAGIC; - sec_hdr.timestamp = local_clock(); - sec_hdr.type = LOG_DUMP_SECTION_COOKIE; - sec_hdr.length = buf_size - remain; - ret = dhd_export_debug_data((char *)&sec_hdr, NULL, user_buf, sizeof(sec_hdr), &pos); - ret = dhd_export_debug_data(buf, NULL, user_buf, sec_hdr.length, &pos); -exit: - if (buf) - MFREE(dhdp->osh, buf, buf_size); - return ret; -} - -int -dhd_log_dump_cookie_to_file(dhd_pub_t *dhdp, void *fp, const void *user_buf, unsigned long *f_pos) -{ - char *buf; - int ret = BCME_ERROR; - uint32 buf_size = MAX_LOGUDMP_COOKIE_CNT * LOGDUMP_COOKIE_STR_LEN; - - if (!dhdp || !dhdp->logdump_cookie || (!fp && !user_buf) || !f_pos) { - DHD_ERROR(("%s At least one ptr is NULL " - "dhdp = %p cookie %p fp = %p f_pos = %p\n", - __FUNCTION__, dhdp, dhdp?dhdp->logdump_cookie:NULL, fp, f_pos)); - return ret; - } - - buf = (char *)MALLOCZ(dhdp->osh, buf_size); - if (!buf) { - DHD_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__)); - return ret; - } - ret = __dhd_log_dump_cookie_to_file(dhdp, fp, user_buf, f_pos, buf, buf_size); - MFREE(dhdp->osh, buf, buf_size); - - return ret; -} -#endif /* DHD_LOG_DUMP */ #endif /* LINUX || linux */ #if defined(DISABLE_HE_ENAB) || defined(CUSTOM_CONTROL_HE_ENAB) @@ -11500,215 +11346,6 @@ done: } #endif /* CONFIG_ROAM_MIN_DELTA */ -#ifdef HOST_SFH_LLC -#define SSTLOOKUP(proto) (((proto) == 0x80f3) || ((proto) == 0x8137)) -/** Convert Ethernet to 802.3 per 802.1H (use bridge-tunnel if type in SST) - * Note:- This function will overwrite the ethernet header in the pkt - * with a 802.3 ethernet + LLC/SNAP header by utilising the headroom - * in the packet. The pkt data pointer should be pointing to the - * start of the packet (at the ethernet header) when the function is called. - * The pkt data pointer will be pointing to the - * start of the new 802.3 header if the function returns successfully - * - * - * Original Ethernet (header length = 14): - * ---------------------------------------------------------------------------------------- - * | | DA | SA | T | Data... | - * ---------------------------------------------------------------------------------------- - * 6 6 2 - * - * Conversion to 802.3 (header length = 22): - * (LLC includes ether_type in last 2 bytes): - * ---------------------------------------------------------------------------------------- - * | | DA | SA | L | LLC/SNAP | T | Data... | - * ---------------------------------------------------------------------------------------- - * 6 6 2 6 2 - */ -int -BCMFASTPATH(dhd_ether_to_8023_hdr)(osl_t *osh, struct ether_header *eh, void *p) -{ - struct ether_header *neh; - struct dot11_llc_snap_header *lsh; - uint16 plen, ether_type; - - if (PKTHEADROOM(osh, p) < DOT11_LLC_SNAP_HDR_LEN) { - DHD_ERROR(("%s: FATAL! not enough pkt headroom !\n", __FUNCTION__)); - ASSERT(0); - return BCME_BUFTOOSHORT; - } - - ether_type = ntoh16(eh->ether_type); - neh = (struct ether_header *)PKTPUSH(osh, p, DOT11_LLC_SNAP_HDR_LEN); - - /* 802.3 MAC header */ - eacopy((char*)eh->ether_dhost, (char*)neh->ether_dhost); - eacopy((char*)eh->ether_shost, (char*)neh->ether_shost); - plen = (uint16)PKTLEN(osh, p) - ETHER_HDR_LEN; - neh->ether_type = hton16(plen); - - /* 802.2 LLC header */ - lsh = (struct dot11_llc_snap_header *)&neh[1]; - lsh->dsap = 0xaa; - lsh->ssap = 0xaa; - lsh->ctl = 0x03; - - /* 802.2 SNAP header Use RFC1042 or bridge-tunnel if type in SST per 802.1H */ - lsh->oui[0] = 0x00; - lsh->oui[1] = 0x00; - if (SSTLOOKUP(ether_type)) - lsh->oui[2] = 0xf8; - else - lsh->oui[2] = 0x00; - lsh->type = hton16(ether_type); - - return BCME_OK; -} - -/** Convert 802.3+LLC to ethernet - * Note:- This function will overwrite the 802.3+LLC hdr in the pkt - * with an ethernet header. The pkt data pointer should be pointing to the - * start of the packet (at the 802.3 header) when the function is called. - * The pkt data pointer will be pointing to the - * start of the ethernet header if the function returns successfully - */ -int -BCMFASTPATH(dhd_8023_llc_to_ether_hdr)(osl_t *osh, struct ether_header *eh8023, void *p) -{ - struct dot11_llc_snap_header *lsh = NULL; - uint16 ether_type = 0; - uint8 *pdata = NULL; - - if (!p || !eh8023) - return BCME_BADARG; - - pdata = PKTDATA(osh, p); - ether_type = ntoh16(eh8023->ether_type); - /* ether type in 802.3 hdr for sfh llc host insertion case - * contains length, replace it with actual ether type at the - * end of the LLC hdr - */ - if (ether_type < ETHER_TYPE_MIN) { - /* 802.2 LLC header */ - lsh = (struct dot11_llc_snap_header *)(pdata + sizeof(*eh8023)); - eh8023->ether_type = lsh->type; - pdata = PKTPULL(osh, p, DOT11_LLC_SNAP_HDR_LEN); - memcpy_s(pdata, sizeof(*eh8023), eh8023, sizeof(*eh8023)); - } else { - DHD_ERROR_RLMT(("ethertype 0x%x is not a length !\n", ether_type)); - return BCME_BADARG; - } - - return BCME_OK; -} -#endif /* HOST_SFH_LLC */ - -#ifdef DHD_AWDL - -#define AWDL_MIN_EXTENSION_DEFAULT 0x3u -#define AWDL_PRESENCE_MODE_DEFAULT 0x4u -#define AWDL_FLAGS_DEFAULT 0x0000u -#define AWDL_PID 0x0800u -#define AWDL_USERDATA_SIZE 6u -/** Convert Ethernet to 802.3 + AWDL LLC SNAP header - * Note:- This function will overwrite the ethernet header in the pkt 'p' - * with a 802.3 ethernet + AWDL LLC/SNAP header by utilising the headroom - * in the packet. The pkt data pointer should be pointing to the - * start of the packet (at the ethernet header) when the function is called. - * The pkt data pointer will be pointing to the - * start of the new 802.3 header if the function returns successfully - */ -int -BCMFASTPATH(dhd_ether_to_awdl_llc_hdr)(struct dhd_pub *dhd, struct ether_header *eh, void *p) -{ - osl_t *osh = dhd->osh; - struct ether_header *neh; - struct dot11_llc_snap_header *lsh; - uint16 plen, ether_type; - uint8 *awdl_data = NULL; - uint16 *seq = NULL; - uint16 *flags = NULL; - uint16 *type = NULL; - - if (PKTHEADROOM(osh, p) < (2 * DOT11_LLC_SNAP_HDR_LEN)) { - DHD_ERROR(("%s: FATAL! not enough pkt headroom !\n", __FUNCTION__)); - ASSERT(0); - return BCME_BUFTOOSHORT; - } - - ether_type = ntoh16(eh->ether_type); - neh = (struct ether_header *)PKTPUSH(osh, p, 2 * DOT11_LLC_SNAP_HDR_LEN); - - /* 802.3 MAC header */ - eacopy((char*)eh->ether_dhost, (char*)neh->ether_dhost); - eacopy((char*)eh->ether_shost, (char*)neh->ether_shost); - plen = (uint16)PKTLEN(osh, p) - ETHER_HDR_LEN; - neh->ether_type = hton16(plen); - - /* 802.2 LLC header */ - lsh = (struct dot11_llc_snap_header *)&neh[1]; - lsh->dsap = 0xaa; - lsh->ssap = 0xaa; - lsh->ctl = 0x03; - - /* 802.2 SNAP header */ - lsh->oui[0] = 0x00; - lsh->oui[1] = 0x17; - lsh->oui[2] = 0xf2; - lsh->type = hton16(AWDL_PID); - - /* AWDL upper layer data */ - awdl_data = (uint8 *)&lsh[1]; - - awdl_data[0] = dhd->awdl_minext; - awdl_data[1] = dhd->awdl_presmode; - - seq = (uint16 *)&awdl_data[2]; - *seq = dhd->awdl_seq++; - - flags = (uint16 *)&awdl_data[4]; - *flags = hton16(AWDL_FLAGS_DEFAULT); - - type = (uint16 *)&awdl_data[6]; - *type = hton16(ether_type); - - return BCME_OK; -} - -/** Convert 802.3 + AWDL LLC SNAP header to ethernet header - * Note:- This function will overwrite the existing - * 802.3 ethernet + AWDL LLC/SNAP header in the packet 'p' - * with a 14 byte ethernet header - * The pkt data pointer should be pointing to the - * start of the packet (at the 802.3 header) when the function is called. - * The pkt data pointer will be pointing to the - * start of the new ethernet header if the function returns successfully - */ -int -dhd_awdl_llc_to_eth_hdr(struct dhd_pub *dhd, struct ether_header *eh, void *p) -{ - uint16 *ethertype = NULL; - uint8 *ptr = NULL; - - if (!eh || !p || !dhd) - return BCME_BADARG; - - ptr = PKTDATA(dhd->osh, p); - - /* copy ether type instead of length from the - * end of the awdl llc header to the ethernet header - */ - ptr += sizeof(*eh) + DOT11_LLC_SNAP_HDR_LEN + AWDL_USERDATA_SIZE; - ethertype = (uint16 *)ptr; - eh->ether_type = *ethertype; - - /* overwrite awdl llc header with ethernet header */ - PKTPULL(dhd->osh, p, 2 * DOT11_LLC_SNAP_HDR_LEN); - ptr = PKTDATA(dhd->osh, p); - memcpy_s(ptr, sizeof(*eh), eh, sizeof(*eh)); - return BCME_OK; -} -#endif /* DHD_AWDL */ - int dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, char *res_buf, uint res_len, bool set) @@ -11728,7 +11365,7 @@ dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len * to avoid the length check error in fw */ if (!set && !param_len) { - input_len += sizeof(int); + input_len += (uint) sizeof(int); } if (input_len > WLC_IOCTL_MAXLEN) return BCME_BADARG; @@ -11812,3 +11449,566 @@ exit: } return ret; } + +#ifdef DHD_DEBUG +void +dhd_convert_memdump_type_to_str(uint32 type, char *buf, size_t buf_len, int substr_type) +{ + char *type_str = NULL; + + switch (type) { + case DUMP_TYPE_RESUMED_ON_TIMEOUT: + type_str = "resumed_on_timeout"; + break; + case DUMP_TYPE_D3_ACK_TIMEOUT: + type_str = "D3_ACK_timeout"; + break; + case DUMP_TYPE_DONGLE_TRAP: + type_str = "Dongle_Trap"; + break; + case DUMP_TYPE_DONGLE_TRAP_DURING_WIFI_ONOFF: + type_str = "Dongle_Trap_During_Wifi_OnOff"; + break; + case DUMP_TYPE_BY_DSACK_HC_DUE_TO_ISR_DELAY: + type_str = "Dongle_Trap_DSACK_HC_due_to_ISR_delay"; + break; + case DUMP_TYPE_BY_DSACK_HC_DUE_TO_DPC_DELAY: + type_str = "Dongle_Trap_DSACK_HC_due_to_DPC_delay"; + break; + case DUMP_TYPE_MEMORY_CORRUPTION: + type_str = "Memory_Corruption"; + break; + case DUMP_TYPE_PKTID_AUDIT_FAILURE: + type_str = "PKTID_AUDIT_Fail"; + break; + case DUMP_TYPE_PKTID_INVALID: + type_str = "PKTID_INVALID"; + break; + case DUMP_TYPE_SCAN_TIMEOUT: + type_str = "SCAN_timeout"; + break; + case DUMP_TYPE_SCAN_BUSY: + type_str = "SCAN_Busy"; + break; + case DUMP_TYPE_BY_SYSDUMP: + if (substr_type == CMD_UNWANTED) { + type_str = "BY_SYSDUMP_FORUSER_unwanted"; + } else if (substr_type == CMD_DISCONNECTED) { + type_str = "BY_SYSDUMP_FORUSER_disconnected"; + } else { + type_str = "BY_SYSDUMP_FORUSER"; + } + break; + case DUMP_TYPE_BY_LIVELOCK: + type_str = "BY_LIVELOCK"; + break; + case DUMP_TYPE_AP_LINKUP_FAILURE: + type_str = "BY_AP_LINK_FAILURE"; + break; + case DUMP_TYPE_AP_ABNORMAL_ACCESS: + type_str = "INVALID_ACCESS"; + break; + case DUMP_TYPE_RESUMED_ON_TIMEOUT_RX: + type_str = "ERROR_RX_TIMED_OUT"; + break; + case DUMP_TYPE_RESUMED_ON_TIMEOUT_TX: + type_str = "ERROR_TX_TIMED_OUT"; + break; + case DUMP_TYPE_CFG_VENDOR_TRIGGERED: + type_str = "CFG_VENDOR_TRIGGERED"; + break; + case DUMP_TYPE_RESUMED_ON_INVALID_RING_RDWR: + type_str = "BY_INVALID_RING_RDWR"; + break; + case DUMP_TYPE_IFACE_OP_FAILURE: + type_str = "BY_IFACE_OP_FAILURE"; + break; + case DUMP_TYPE_TRANS_ID_MISMATCH: + type_str = "BY_TRANS_ID_MISMATCH"; + break; +#ifdef DEBUG_DNGL_INIT_FAIL + case DUMP_TYPE_DONGLE_INIT_FAILURE: + type_str = "DONGLE_INIT_FAIL"; + break; +#endif /* DEBUG_DNGL_INIT_FAIL */ + case DUMP_TYPE_DONGLE_HOST_EVENT: + type_str = "BY_DONGLE_HOST_EVENT"; + break; + case DUMP_TYPE_SMMU_FAULT: + type_str = "SMMU_FAULT"; + break; + case DUMP_TYPE_BY_USER: + type_str = "BY_USER"; + break; + case DUMP_TYPE_LOGSET_BEYOND_RANGE: + type_str = "LOGSET_BEYOND_RANGE"; + break; + case DUMP_TYPE_CTO_RECOVERY: + type_str = "CTO_RECOVERY"; + break; + case DUMP_TYPE_SEQUENTIAL_PRIVCMD_ERROR: + type_str = "SEQUENTIAL_PRIVCMD_ERROR"; + break; + case DUMP_TYPE_PROXD_TIMEOUT: + type_str = "PROXD_TIMEOUT"; + break; + case DUMP_TYPE_INBAND_DEVICE_WAKE_FAILURE: + type_str = "INBAND_DEVICE_WAKE_FAILURE"; + break; + case DUMP_TYPE_PKTID_POOL_DEPLETED: + type_str = "PKTID_POOL_DEPLETED"; + break; + case DUMP_TYPE_ESCAN_SYNCID_MISMATCH: + type_str = "ESCAN_SYNCID_MISMATCH"; + break; + case DUMP_TYPE_INVALID_SHINFO_NRFRAGS: + type_str = "INVALID_SHINFO_NRFRAGS"; + break; + case DUMP_TYPE_P2P_DISC_BUSY: + type_str = "P2P_DISC_BUSY"; + break; + case DUMP_TYPE_CONT_EXCESS_PM_AWAKE: + type_str = "CONT_EXCESS_PM_AWAKE"; + break; + default: + type_str = "Unknown_type"; + break; + } + + strlcpy(buf, type_str, buf_len); +} +#endif /* DHD_DEBUG */ + +#ifdef DHD_LOGLEVEL +void dhd_loglevel_get(dhd_loglevel_data_t *level_data) +{ + level_data->dhd_print_lv = dhd_msg_level; + level_data->dhd_log_lv = dhd_log_level; + level_data->wl_print_lv = wl_cfg80211_get_print_level(); + level_data->wl_log_lv = wl_cfg80211_get_log_level(); +} + +void dhd_loglevel_set(dhd_loglevel_data_t *level_data) +{ + if (level_data->type == DHD_LOGLEVEL_TYPE_ALL) { +#ifdef WL_CFG80211 + if (level_data->component == DHD_LOGLEVEL_COMP_WL) { + wl_cfg80211_enable_trace(level_data->wl_print_lv); + wl_cfg80211_enable_log_trace(TRUE, level_data->wl_log_lv); + } else +#endif /* WL_CFG80211 */ + { + dhd_msg_level = level_data->dhd_print_lv; + dhd_log_level = level_data->dhd_log_lv; + } + } else if (level_data->type == DHD_LOGLEVEL_TYPE_PRINT) { +#ifdef WL_CFG80211 + if (level_data->component == DHD_LOGLEVEL_COMP_WL) { + wl_cfg80211_enable_trace(level_data->wl_print_lv); + } else +#endif /* WL_CFG80211 */ + { + dhd_msg_level = level_data->dhd_print_lv; + } + } else if (level_data->type == DHD_LOGLEVEL_TYPE_LOG) { +#ifdef WL_CFG80211 + if (level_data->component == DHD_LOGLEVEL_COMP_WL) { + wl_cfg80211_enable_log_trace(TRUE, level_data->wl_log_lv); + } else +#endif /* WL_CFG80211 */ + { + dhd_log_level = level_data->dhd_log_lv; + } + } + DHD_ERROR(("%s: type:%u dhd_msg_level:0x%x dhd_log_level:0x%x\n", + __func__, level_data->type, dhd_msg_level, dhd_log_level)); + DHD_ERROR(("%s: type:%u wl_dbg_level:0x%x wl_log_level:0x%x\n", + __func__, level_data->type, wl_dbg_level, wl_log_level)); +} +#endif /* DHD_LOGLEVEL */ + +#if defined(DHD_WAKE_STATUS_PRINT) && defined(DHD_WAKE_RX_STATUS) && \ + defined(DHD_WAKE_STATUS) +#ifdef BCMPCIE +extern int bcmpcie_get_total_wake(struct dhd_bus *bus); +#endif /* BCMPCIE */ +void +dhd_dump_wake_status(dhd_pub_t *dhdp, wake_counts_t *wcp, struct ether_header *eh) +{ + uint wake = 0; + + BCM_REFERENCE(wake); +#ifdef BCMPCIE + wake = bcmpcie_get_total_wake(dhdp->bus); +#endif /* BCMPCIE */ + + DHD_ERROR(("wake %u rxwake %u readctrlwake %u\n", + wake, wcp->rxwake, wcp->rcwake)); + DHD_ERROR(("unicast %u muticast %u broadcast %u icmp %u\n", + wcp->rx_ucast, wcp->rx_mcast, wcp->rx_bcast, wcp->rx_icmp)); + DHD_ERROR(("multi4 %u multi6 %u icmp6 %u multiother %u\n", + wcp->rx_multi_ipv4, wcp->rx_multi_ipv6, wcp->rx_icmpv6, wcp->rx_multi_other)); + DHD_ERROR(("icmp6_ra %u, icmp6_na %u, icmp6_ns %u\n", + wcp->rx_icmpv6_ra, wcp->rx_icmpv6_na, wcp->rx_icmpv6_ns)); + DHD_ERROR(("Src_mac: "MACDBG", Dst_mac: "MACDBG"\n", + MAC2STRDBG(eh->ether_shost), MAC2STRDBG(eh->ether_dhost))); + return; +} +#endif /* DHD_WAKE_STATUS_PRINT && DHD_WAKE_RX_STATUS && DHD_WAKE_STATUS */ +#ifdef SUPPORT_OTA_UPDATE +void +dhd_ota_buf_clean(dhd_pub_t *dhdp) +{ + ota_update_info_t *ota_info = &dhdp->ota_update_info; + + if (ota_info->clm_buf) { + MFREE(dhdp->osh, ota_info->clm_buf, ota_info->clm_len); + } + if (ota_info->nvram_buf) { + MFREE(dhdp->osh, ota_info->nvram_buf, ota_info->nvram_len); + } + ota_info->nvram_len = 0; + ota_info->clm_len = 0; + return; +} +#endif /* SUPPORT_OTA_UPDATE */ + +#if defined(OEM_ANDROID) && !defined(AP) && defined(WLP2P) +/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware + * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA + * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware + * would still be named as fw_bcmdhd_apsta. + */ +uint32 +dhd_get_concurrent_capabilites(dhd_pub_t *dhd) +{ + int32 ret = 0; + char buf[WLC_IOCTL_SMLEN]; + bool mchan_supported = FALSE; + /* if dhd->op_mode is already set for HOSTAP and Manufacturing + * test mode, that means we only will use the mode as it is + */ + if (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE)) + return 0; + if (FW_SUPPORTED(dhd, vsdb)) { + mchan_supported = TRUE; + } + if (!FW_SUPPORTED(dhd, p2p)) { + DHD_TRACE(("Chip does not support p2p\n")); + return 0; + } else { + /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */ + memset(buf, 0, sizeof(buf)); + ret = dhd_iovar(dhd, 0, "p2p", NULL, 0, (char *)&buf, + sizeof(buf), FALSE); + if (ret < 0) { + DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); + return 0; + } else { + if (buf[0] == 1) { + /* By default, chip supports single chan concurrency, + * now lets check for mchan + */ + ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; + if (mchan_supported) + ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; + if (FW_SUPPORTED(dhd, rsdb)) { + ret |= DHD_FLAG_RSDB_MODE; + } +#ifdef WL_SUPPORT_MULTIP2P + if (FW_SUPPORTED(dhd, mp2p)) { + ret |= DHD_FLAG_MP2P_MODE; + } +#endif /* WL_SUPPORT_MULTIP2P */ +#if defined(WL_CFG80211_P2P_DEV_IF) + return ret; +#else + return 0; +#endif + } + } + } + return 0; +} +#endif /* defined(OEM_ANDROID) && !defined(AP) && defined(WLP2P) */ + +#ifdef SUPPORT_AP_POWERSAVE +int dhd_set_ap_powersave(dhd_pub_t *dhdp, int ifidx, int enable) +{ + int32 pps = RXCHAIN_PWRSAVE_PPS; + int32 quiet_time = RXCHAIN_PWRSAVE_QUIET_TIME; + int32 stas_assoc_check = RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK; + int ret; + + if (enable) { + ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_enable", (char *)&enable, sizeof(enable), + NULL, 0, TRUE); + if (ret != BCME_OK) { + DHD_ERROR(("Failed to enable AP power save")); + } + ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_pps", (char *)&pps, sizeof(pps), NULL, 0, + TRUE); + if (ret != BCME_OK) { + DHD_ERROR(("Failed to set pps")); + } + ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_quiet_time", (char *)&quiet_time, + sizeof(quiet_time), NULL, 0, TRUE); + if (ret != BCME_OK) { + DHD_ERROR(("Failed to set quiet time")); + } + ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_stas_assoc_check", + (char *)&stas_assoc_check, sizeof(stas_assoc_check), NULL, 0, TRUE); + if (ret != BCME_OK) { + DHD_ERROR(("Failed to set stas assoc check")); + } + } else { + ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_enable", (char *)&enable, sizeof(enable), + NULL, 0, TRUE); + if (ret != BCME_OK) { + DHD_ERROR(("Failed to disable AP power save")); + } + } + + return 0; +} +#endif /* SUPPORT_AP_POWERSAVE */ +#ifdef DHD_COREDUMP +void +dhd_convert_hang_reason_to_str(uint32 reason, char *buf, size_t buf_len) +{ + char *type_str = NULL; + + switch (reason) { + case HANG_REASON_BUS_DOWN: + type_str = "BUS_DOWN"; + break; + case HANG_REASON_PCIE_RC_LINK_UP_FAIL: + type_str = "PCIE_RC_LINK_UP_FAIL"; + break; + case HANG_REASON_IOCTL_SUSPEND_ERROR: + type_str = "IOCTL_SUSPEND_ERROR"; + break; + case HANG_REASON_PCIE_LINK_DOWN_RC_DETECT: + type_str = "PCIE_LINK_DOWN_RC_DETECT"; + break; + case HANG_REASON_PCIE_LINK_DOWN_EP_DETECT: + type_str = "PCIE_LINK_DOWN_EP_DETECT"; + break; + case HANG_REASON_MSGBUF_LIVELOCK: + type_str = "BY_LIVELOCK"; + break; + case HANG_REASON_IOCTL_RESP_TIMEOUT: + case HANG_REASON_IOCTL_RESP_TIMEOUT_SCHED_ERROR: + type_str = "resumed_on_timeout"; + break; + case HANG_REASON_D3_ACK_TIMEOUT: + case HANG_REASON_D3_ACK_TIMEOUT_SCHED_ERROR: + type_str = "D3_ACK_timeout"; + break; + case HANG_REASON_DONGLE_TRAP: + type_str = "Dongle_Trap"; + break; + case HANG_REASON_PCIE_PKTID_ERROR: + type_str = "PKTID_INVALID"; + break; + case HANG_REASON_SCAN_TIMEOUT: + case HANG_REASON_SCAN_TIMEOUT_SCHED_ERROR: + type_str = "SCAN_timeout"; + break; + case HANG_REASON_SCAN_BUSY: + type_str = "SCAN_Busy"; + break; + case HANG_REASON_IFACE_DEL_FAILURE: + case HANG_REASON_IFACE_ADD_FAILURE: + case HANG_REASON_BSS_UP_FAILURE: + case HANG_REASON_BSS_DOWN_FAILURE: + type_str = "BY_IFACE_OP_FAILURE"; + break; + case HANG_REASON_PCIE_CTO_DETECT: + type_str = "CTO_RECOVERY"; + break; + case HANG_REASON_SEQUENTIAL_PRIVCMD_ERROR: + type_str = "SEQUENTIAL_PRIVCMD_ERROR"; + break; + case HANG_REASON_ESCAN_SYNCID_MISMATCH: + type_str = "ESCAN_SYNCID_MISMATCH"; + break; + case HANG_REASON_P2P_DISC_BUSY: + type_str = "P2P_DISC_BUSY"; + break; + case HANG_REASON_DS_SKIP_TIMEOUT: + type_str = "DS_SKIP_TIMEOUT"; + break; + case HANG_REASON_BT2WL_REG_RESET: + type_str = "BT2WL_REG_RESET"; + break; + default: + type_str = "Unknown_type"; + break; + } + + strlcpy(buf, type_str, buf_len); +} +#endif /* DHD_COREDUMP */ +#ifdef DHD_CUSTOM_CONFIG_RTS_IN_SUSPEND +int dhd_config_rts_in_suspend(dhd_pub_t *dhdp, bool suspend) +{ + int ret = BCME_OK; + uint return_to_sleep_time = 0; + + int buf_len; + bcm_iov_buf_t *iov_buf = NULL; + wl_adps_suspend_v1_t *data = NULL; + + if (!dhdp || dhdp->up == 0) { + return ret; + } + + /* if it's not associated, skip to set */ + if (!dhd_is_associated(dhdp, 0, NULL)) { + return ret; + } + + if (suspend) { + return_to_sleep_time = CUSTOM_RETRUN_TO_SLEEP_TIME_SUSPEND; + } + else { + return_to_sleep_time = CUSTOM_RETRUN_TO_SLEEP_TIME_DEFAULT; + } + + ret = dhd_iovar(dhdp, 0, "pm2_sleep_ret", (char *)&return_to_sleep_time, + sizeof(return_to_sleep_time), NULL, 0, TRUE); + + if (ret < 0) { + DHD_ERROR(("%s set pm2_sleep_ret failed %d\n", __FUNCTION__, ret)); + goto exit; + } + + buf_len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(*data); + iov_buf = MALLOCZ(dhdp->osh, buf_len); + if (iov_buf == NULL) { + DHD_ERROR(("%s - failed to alloc %d bytes for iov_buf\n", + __FUNCTION__, buf_len)); + ret = BCME_NOMEM; + goto exit; + } + + iov_buf->version = WL_ADPS_IOV_VER; + iov_buf->len = sizeof(*data); + iov_buf->id = WL_ADPS_IOV_SUSPEND; + + data = (wl_adps_suspend_v1_t *)iov_buf->data; + data->version = ADPS_SUB_IOV_VERSION_1; + data->length = sizeof(*data); + data->suspend = suspend; + + ret = dhd_iovar(dhdp, 0, "adps", (char *)iov_buf, buf_len, + NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s - fail to set adps suspend %d (%d)\n", + __FUNCTION__, suspend, ret)); + goto exit; + } + +exit: + if (ret == BCME_OK) { + DHD_ERROR(("%s - Success to set RTS [%d] and ADPS suspend [%d].\n", + __FUNCTION__, return_to_sleep_time, suspend)); + } + if (iov_buf) { + MFREE(dhdp->osh, iov_buf, buf_len); + } + return ret; +} +#endif /* DHD_CUSTOM_CONFIG_RTS_IN_SUSPEND */ + +void +dhd_histo_update(dhd_pub_t *dhd, uint64 *histo, uint32 value) +{ + uint64 *p; + uint64 *bin = histo; + uint32 bin_power = next_larger_power2(value); + if (histo == NULL) { + DHD_ERROR(("%s: histo is NULL\n", __FUNCTION__)); + return; + } + + switch (bin_power) { + case 1: p = bin + 0; break; + case 2: p = bin + 1; break; + case 4: p = bin + 2; break; + case 8: p = bin + 3; break; + case 16: p = bin + 4; break; + case 32: p = bin + 5; break; + case 64: p = bin + 6; break; + case 128: p = bin + 7; break; + case 256: p = bin + 8; break; + case 512: p = bin + 9; break; + case 1024: p = bin + 10; break; + case 2048: p = bin + 11; break; + case 4096: p = bin + 12; break; + case 8192: p = bin + 13; break; + default : p = bin + 13; break; + } + ASSERT((p - bin) < DHD_HISTOGRAM_ENTRIES); + *p = *p + 1; + return; +} + +void +dhd_histo_clear(dhd_pub_t *dhd, uint64 *histo) +{ + + if (histo == NULL) { + return; + } + + bzero(histo, DHD_HISTOGRAM_SIZE); +} + +void +dhd_histo_tag_dump(dhd_pub_t *dhd, struct bcmstrbuf *strbuf, char *tagname) +{ + uint32 i; + + bcm_bprintf(strbuf, "%20s: ", tagname); + for (i = 0; i < DHD_HISTOGRAM_ENTRIES; i++) { + bcm_bprintf(strbuf, "%10llu ", 1ULL<osh, DHD_HISTOGRAM_SIZE); + if (histo == NULL) { + DHD_ERROR(("%s: unable to alloc histo\n", __FUNCTION__)); + } + return histo; +} + +void +dhd_histo_deinit(dhd_pub_t *dhd, uint64 *histo) +{ + if (histo) { + MFREE(dhd->osh, histo, DHD_HISTOGRAM_SIZE); + } +} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c old mode 100755 new mode 100644 index dac725e0e305..c1b93fac5f8e --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ + #include #include @@ -67,6 +67,10 @@ uint dump_msg_level = 0; #define MAXSZ_BUF 4096 #define MAXSZ_CONFIG 8192 +extern uint wl_reassoc_support; +#ifdef BTC_WAR +extern int btc_war; +#endif /* BTC_WAR */ #if defined(BCMSDIO) && defined(DYNAMIC_MAX_HDR_READ) extern uint firstread; #endif @@ -136,16 +140,63 @@ const chip_name_map_t chip_name_map[] = { {BCM43751_CHIP_ID, 1, DONT_CARE, "bcm43751a1_pcie_ag", ""}, {BCM43751_CHIP_ID, 2, DONT_CARE, "bcm43751a2_pcie_ag", ""}, {BCM43752_CHIP_ID, 1, DONT_CARE, "bcm43752a1_pcie_ag", ""}, - {BCM43752_CHIP_ID, 2, DONT_CARE, "bcm43752a2_pcie_ag", "AP6275P"}, + {BCM43752_CHIP_ID, 2, DONT_CARE, "bcm43752a2_pcie_ag", "ap6275p"}, {BCM4375_CHIP_ID, 5, DONT_CARE, "bcm4375b4_pcie_ag", ""}, #endif #ifdef BCMDBUS - {BCM43143_CHIP_ID, 2, DONT_CARE, "bcm43143b0", ""}, - {BCM43242_CHIP_ID, 1, DONT_CARE, "bcm43242a1_ag", ""}, - {BCM43569_CHIP_ID, 2, DONT_CARE, "bcm4358u_ag", ""}, + {BCM43143_CHIP_ID, 2, DONT_CARE, "bcm43143b0", ""}, + {BCM43242_CHIP_ID, 1, DONT_CARE, "bcm43242a1_ag", ""}, + {BCM43569_CHIP_ID, 2, DONT_CARE, "bcm4358u_ag", ""}, #endif }; +typedef struct module_name_map_v2_t { + uint chip; + uint chiprev; + char *module_name; +} module_name_map_v2_t; + +const module_name_map_v2_t module_name_map_v2[] = { +#ifdef BCMSDIO + {BCM4381_CHIP_ID, 0, ""}, + {BCM4381_CHIP_ID, 1, ""}, + {BCM43752_CHIP_ID, 4, "ap6276s"}, + {BCM43756_CHIP_ID, 4, "ap6276s"}, + {BCM43756_CHIP_ID, 6, ""}, + {BCM43711_CHIP_ID, 0, "ap6611s"}, + {BCM4382_CHIP_ID, 3, ""}, +#endif +#ifdef BCMPCIE + {BCM4381_CHIP_ID, 0, ""}, + {BCM4381_CHIP_ID, 1, ""}, + {BCM43752_CHIP_ID, 4, ""}, + {BCM43756_CHIP_ID, 4, ""}, + {BCM43756_CHIP_ID, 6, ""}, + {BCM4382_CHIP_ID, 3, ""}, +#endif +#ifdef BCMDBUS + {BCM4381_CHIP_ID, 0, ""}, + {BCM4381_CHIP_ID, 1, ""}, + {BCM4382_CHIP_ID, 3, ""}, +#endif +}; + +typedef struct chip_name_map_v2_t { + uint chip; + uint chiprev; + char *chip_name; +} chip_name_map_v2_t; + +const chip_name_map_v2_t chip_name_map_v2[] = { + {BCM4381_CHIP_ID, 0, "syn4381a0"}, + {BCM4381_CHIP_ID, 1, "syn4381a0"}, + {BCM43752_CHIP_ID, 4, "syn43756b0"}, + {BCM43756_CHIP_ID, 4, "syn43756b0"}, + {BCM43756_CHIP_ID, 6, "syn43756c0"}, + {BCM43711_CHIP_ID, 0, "syn43711a0"}, + {BCM4382_CHIP_ID, 3, "syn4382a0"}, +}; + #ifdef UPDATE_MODULE_NAME typedef void (compat_func_t)(dhd_pub_t *dhd); typedef struct module_name_map_t { @@ -213,6 +264,89 @@ const chip_cisaddr_map_t chip_cisaddr_map[] = { extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); #endif +#ifdef WL_CFG80211 +bool +dhd_conf_legacy_chip_check(dhd_pub_t *dhd) +{ + uint chip = dhd->conf->chip; + + if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || + chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || + chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || + chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || + chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || + chip == BCM4371_CHIP_ID || + chip == BCM43430_CHIP_ID || + chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID || + chip == BCM4359_CHIP_ID || + chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID || + chip == BCM43569_CHIP_ID) { + return true; + } + + return false; +} + +bool +dhd_conf_new_chip_check(dhd_pub_t *dhd) +{ + uint chip = dhd->conf->chip; + + if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || + chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || + chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || + chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || + chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || + chip == BCM4371_CHIP_ID || + chip == BCM43430_CHIP_ID || + chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID || + chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID || + chip == BCM43569_CHIP_ID) { + return false; + } + + return true; +} + +bool +dhd_conf_extsae_chip(dhd_pub_t *dhd) +{ + uint chip = dhd->conf->chip; + + if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || + chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || + chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || + chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || + chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID || + chip == BCM43569_CHIP_ID) { + return false; + } + + return true; +} +#endif + +#ifdef BCMSDIO +static void +dhd_conf_disable_slpauto(dhd_pub_t *dhd) +{ + uint chip = dhd->conf->chip; + + if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || + chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || + chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || + chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || + chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || + chip == BCM4371_CHIP_ID || + chip == BCM43430_CHIP_ID || + chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID || + chip == BCM4359_CHIP_ID) { + dhd_slpauto = FALSE; + } + CONFIG_MSG("dhd_slpauto = %d\n", dhd_slpauto); +} +#endif + void dhd_conf_free_chip_nv_path_list(wl_chip_nv_path_list_ctrl_t *chip_nv_list) { @@ -477,6 +611,30 @@ dhd_conf_set_nv_name_by_mac(dhd_pub_t *dhd, char *nv_path) } } #endif + +bool +dhd_conf_legacy_otp_chip(dhd_pub_t *dhd) +{ + uint chip; + + chip = dhd->conf->chip; + + if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || + chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || + chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || + chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || + chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || + chip == BCM4371_CHIP_ID || + chip == BCM43430_CHIP_ID || + chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID || + chip == BCM4359_CHIP_ID || chip == BCM43012_CHIP_ID || + chip == BCM43751_CHIP_ID || chip == BCM43752_CHIP_ID || + chip == BCM43756_CHIP_ID || chip == BCM43711_CHIP_ID) { + return true; + } + + return false; +} #endif #ifdef BCMPCIE @@ -690,7 +848,7 @@ dhd_conf_match_chip(dhd_pub_t *dhd, uint ag_type) chiprev = dhd->conf->chiprev; for (i=0; ichip == chip && row->chiprev == chiprev && (row->ag_type == ag_type || ag_type == DONT_CARE || row->ag_type == DONT_CARE)) { @@ -701,6 +859,44 @@ dhd_conf_match_chip(dhd_pub_t *dhd, uint ag_type) return NULL; } +const chip_name_map_v2_t* +dhd_conf_match_chip_v2(dhd_pub_t *dhd) +{ + uint chip, chiprev; + int i; + + chip = dhd->conf->chip; + chiprev = dhd->conf->chiprev; + + for (i=0; ichip == chip && row->chiprev == chiprev) { + return row; + } + } + + return NULL; +} + +const module_name_map_v2_t* +dhd_conf_match_module_v2(dhd_pub_t *dhd) +{ + uint chip, chiprev; + int i; + + chip = dhd->conf->chip; + chiprev = dhd->conf->chiprev; + + for (i=0; ichip == chip && row->chiprev == chiprev) { + return row; + } + } + + return NULL; +} + #ifdef UPDATE_MODULE_NAME const module_name_map_t* dhd_conf_match_module(dhd_pub_t *dhd) @@ -723,7 +919,7 @@ dhd_conf_match_module(dhd_pub_t *dhd) #ifdef BCMSDIO for (i=0; idevid == devid && row->chip == chip && row->chiprev == chiprev && !strcmp(row->module_name, dhd->conf->module_name)) { return row; @@ -733,7 +929,7 @@ dhd_conf_match_module(dhd_pub_t *dhd) #ifdef BCMPCIE for (i=0; idevid == devid && row->chip == chip && row->chiprev == chiprev && row->svid == svid && row->ssid == ssid) { return row; @@ -745,21 +941,80 @@ dhd_conf_match_module(dhd_pub_t *dhd) } #endif +char * +dhd_conf_get_chip_name(dhd_pub_t *dhd, int ag_type, bool *chip_map_v2) +{ +#ifdef UPDATE_MODULE_NAME + const module_name_map_t *row_module = NULL; +#endif + const chip_name_map_t *row_chip = NULL; + const chip_name_map_v2_t *row_chip_v2 = NULL; + char *name = NULL; + + *chip_map_v2 = FALSE; +#ifdef UPDATE_MODULE_NAME + row_module = dhd_conf_match_module(dhd); + if (row_module && strlen(row_module->chip_name)) { + name = row_module->chip_name; + } else +#endif + { + row_chip = dhd_conf_match_chip(dhd, ag_type); + if (row_chip && strlen(row_chip->chip_name)) { + name = row_chip->chip_name; + } + else { + row_chip_v2 = dhd_conf_match_chip_v2(dhd); + if (row_chip_v2 && strlen(row_chip_v2->chip_name)) { + name = row_chip_v2->chip_name; + *chip_map_v2 = TRUE; + } + } + } + + return name; +} + +char * +dhd_conf_get_module_name(dhd_pub_t *dhd, int ag_type) +{ +#if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME) + const module_name_map_t *row_module = NULL; +#endif + const chip_name_map_t *row_chip = NULL; + const module_name_map_v2_t *row_module_v2 = NULL; + char *name = NULL; + +#if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME) + row_module = dhd_conf_match_module(dhd); + if (row_module && strlen(row_module->module_name)) { + name = row_module->module_name; + } else +#endif + { + row_chip = dhd_conf_match_chip(dhd, ag_type); + if (row_chip && strlen(row_chip->module_name)) { + name = row_chip->module_name; + } + else { + row_module_v2 = dhd_conf_match_module_v2(dhd); + if (row_module_v2 && strlen(row_module_v2->module_name)) { + name = row_module_v2->module_name; + } + } + } + + return name; +} + int dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path) { -#ifdef UPDATE_MODULE_NAME - const module_name_map_t* row_module = NULL; -#endif - const chip_name_map_t* row_chip = NULL; int fw_type, ag_type; - uint chip, chiprev; - char *name_ptr; + char *name_ptr, *chip_name = NULL; + bool chip_map_v2; int i; - chip = dhd->conf->chip; - chiprev = dhd->conf->chiprev; - if (fw_path[0] == '\0') { #ifdef CONFIG_BCMDHD_FW_PATH bcm_strncpy_s(fw_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_FW_PATH, MOD_PARAM_PATHLEN-1); @@ -810,10 +1065,21 @@ dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path) fw_type = FW_TYPE_EZMESH; #endif /* WLEASYMESH */ - row_chip = dhd_conf_match_chip(dhd, ag_type); - if (row_chip && strlen(row_chip->chip_name)) { + chip_name = dhd_conf_get_chip_name(dhd, ag_type, &chip_map_v2); + if (chip_name) { strcpy(name_ptr, "fw_"); - strcat(name_ptr, row_chip->chip_name); + strcat(name_ptr, chip_name); + if (chip_map_v2) { +#ifdef BCMSDIO + strcat(name_ptr, "_sdio"); +#endif +#ifdef BCMPCIE + strcat(name_ptr, "_pcie"); +#endif +#if defined(BCMDBUS) && !defined(BCMUSBDEV_COMPOSITE) + strcat(name_ptr, "_usb"); +#endif + } #ifdef BCMUSBDEV_COMPOSITE strcat(name_ptr, "_cusb"); #endif @@ -835,33 +1101,6 @@ dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path) strcat(name_ptr, ".bin"); } -#ifdef UPDATE_MODULE_NAME - row_module = dhd_conf_match_module(dhd); - if (row_module && strlen(row_module->chip_name)) { - strcpy(name_ptr, "fw_"); - strcat(name_ptr, row_module->chip_name); -#ifdef BCMUSBDEV_COMPOSITE - strcat(name_ptr, "_cusb"); -#endif - if (fw_type == FW_TYPE_APSTA) - strcat(name_ptr, "_apsta.bin"); - else if (fw_type == FW_TYPE_P2P) - strcat(name_ptr, "_p2p.bin"); - else if (fw_type == FW_TYPE_MESH) - strcat(name_ptr, "_mesh.bin"); - else if (fw_type == FW_TYPE_EZMESH) - strcat(name_ptr, "_ezmesh.bin"); - else if (fw_type == FW_TYPE_ES) - strcat(name_ptr, "_es.bin"); - else if (fw_type == FW_TYPE_MFG) - strcat(name_ptr, "_mfg.bin"); - else if (fw_type == FW_TYPE_MINIME) - strcat(name_ptr, "_minime.bin"); - else - strcat(name_ptr, ".bin"); - } -#endif - dhd->conf->fw_type = fw_type; #ifndef MINIME @@ -876,17 +1115,10 @@ dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path) void dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path, int ag_type) { -#ifdef UPDATE_MODULE_NAME - const module_name_map_t* row_module = NULL; -#endif - const chip_name_map_t* row_chip = NULL; - uint chip, chiprev; - char *name_ptr; + char *name_ptr, *chip_name = NULL; + bool chip_map_v2; int i; - chip = dhd->conf->chip; - chiprev = dhd->conf->chiprev; - if (clm_path[0] == '\0') { CONFIG_MSG("clm path is null\n"); return; @@ -903,34 +1135,21 @@ dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path, int ag_type) } name_ptr = &clm_path[i]; - row_chip = dhd_conf_match_chip(dhd, ag_type); - if (row_chip && strlen(row_chip->chip_name)) { + chip_name = dhd_conf_get_chip_name(dhd, ag_type, &chip_map_v2); + if (chip_name) { strcpy(name_ptr, "clm_"); - strcat(name_ptr, row_chip->chip_name); + strcat(name_ptr, chip_name); strcat(name_ptr, ".blob"); } -#ifdef UPDATE_MODULE_NAME - row_module = dhd_conf_match_module(dhd); - if (row_module && strlen(row_module->chip_name)) { - strcpy(name_ptr, "clm_"); - strcat(name_ptr, row_module->chip_name); - strcat(name_ptr, ".blob"); - } -#endif - CONFIG_TRACE("clm_path=%s\n", clm_path); } void dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path, int ag_type) { -#if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME) - const module_name_map_t* row_module = NULL; -#endif - const chip_name_map_t* row_chip = NULL; uint chip, chiprev; - char *name_ptr, nv_name[32]; + char *name_ptr, *module_name = NULL, nv_name[32]; int i; chip = dhd->conf->chip; @@ -958,10 +1177,10 @@ dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path, int ag_type) } name_ptr = &nv_path[i]; - row_chip = dhd_conf_match_chip(dhd, ag_type); - if (row_chip && strlen(row_chip->module_name)) { + module_name = dhd_conf_get_module_name(dhd, ag_type); + if (module_name) { strcpy(name_ptr, "nvram_"); - strcat(name_ptr, row_chip->module_name); + strcat(name_ptr, module_name); #ifdef BCMUSBDEV_COMPOSITE strcat(name_ptr, "_cusb"); #endif @@ -976,28 +1195,31 @@ dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path, int ag_type) strcat(name_ptr, ".txt"); #ifdef COMPAT_OLD_MODULE if (dhd->conf->chip == BCM4359_CHIP_ID) { - struct file *fp; // compatible for AP6398S and AP6398SA - fp = filp_open(nv_path, O_RDONLY, 0); - if (IS_ERR(fp)) { +#ifdef DHD_LINUX_STD_FW_API + const struct firmware *nv = NULL; + int ret = BCME_ERROR; + ret = dhd_os_get_img_fwreq(&nv, nv_path); + if (ret < 0) { + strcpy(name_ptr, nv_name); + } + if (nv) { + dhd_os_close_img_fwreq(nv); + } +#else + struct file *fp; + fp = dhd_filp_open(nv_path, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { strcpy(name_ptr, nv_name); } else { - filp_close((struct file *)fp, NULL); + dhd_filp_close((struct file *)fp, NULL); } +#endif } #endif } #endif -#if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME) - row_module = dhd_conf_match_module(dhd); - if (row_module && strlen(row_module->module_name)) { - strcpy(name_ptr, "nvram_"); - strcat(name_ptr, row_module->module_name); - strcat(name_ptr, ".txt"); - } -#endif - for (i=0; iconf->nv_by_chip.count; i++) { if (chip==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chip && chiprev==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chiprev) { @@ -1038,17 +1260,10 @@ dhd_conf_copy_path(dhd_pub_t *dhd, char *dst_name, char *dst_path, char *src_pat void dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path) { -#ifdef UPDATE_MODULE_NAME - const module_name_map_t* row_module = NULL; -#endif - const chip_name_map_t* row_chip = NULL; - uint chip, chiprev; - char *name_ptr; + char *name_ptr, *chip_name = NULL; + bool chip_map_v2; int i; - chip = dhd->conf->chip; - chiprev = dhd->conf->chiprev; - if (conf_path[0] == '\0') { CONFIG_MSG("config path is null\n"); return; @@ -1065,22 +1280,13 @@ dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path) } name_ptr = &conf_path[i]; - row_chip = dhd_conf_match_chip(dhd, DONT_CARE); - if (row_chip && strlen(row_chip->chip_name)) { + chip_name = dhd_conf_get_chip_name(dhd, DONT_CARE, &chip_map_v2); + if (chip_name) { strcpy(name_ptr, "config_"); - strcat(name_ptr, row_chip->chip_name); + strcat(name_ptr, chip_name); strcat(name_ptr, ".txt"); } -#ifdef UPDATE_MODULE_NAME - row_module = dhd_conf_match_module(dhd); - if (row_module && strlen(row_module->chip_name)) { - strcpy(name_ptr, "config_"); - strcat(name_ptr, row_module->chip_name); - strcat(name_ptr, ".txt"); - } -#endif - CONFIG_TRACE("config_path=%s\n", conf_path); } #endif @@ -1254,28 +1460,8 @@ dhd_conf_dump_tput_patch(dhd_pub_t *dhd) } #endif /* DHD_TPUT_PATCH */ -#ifdef DHD_LINUX_STD_FW_API +#ifdef DHD_REQUEST_FW_PATH #define FIRMWARE_CLASS_PATH "/sys/module/firmware_class/parameters/path" -static int -dhd_conf_get_fw_path(char *path, int len) -{ - char *pch; - int err, path_len = 0; - - err = dhd_read_file(FIRMWARE_CLASS_PATH, path, len); - if(err < 0){ - CONFIG_ERROR("firmware path can not read %d\n", err); - } else { - pch = strchr(path, '\n'); - if (pch) - *pch = '\0'; - CONFIG_TRACE("path = %s\n", path); - path_len = strlen(path); - } - - return path_len; -} - static void dhd_conf_get_filename(char *pFilename) { @@ -1297,23 +1483,48 @@ dhd_conf_get_filename(char *pFilename) if (pName) strcpy(pFilename, pName); + return; } -#endif /* DHD_LINUX_STD_FW_API */ + +static void +dhd_conf_add_filepath(dhd_pub_t *dhd, char *pFilename) +{ + char path[WLC_IOCTL_SMLEN]; + char *name_ptr, *module_name = NULL; + + if (strlen(pFilename)) { + name_ptr = path; + strcpy(name_ptr, ""); +#ifdef FW_AMPAK_PATH + strcat(name_ptr, "/"); + strcat(name_ptr, FW_AMPAK_PATH); +#endif +#ifdef MODULE_PATH + module_name = dhd_conf_get_module_name(dhd, DONT_CARE); +#endif + if (module_name) { + strcat(name_ptr, "/"); + strcat(name_ptr, module_name); + } + strcat(name_ptr, "/"); + strcat(name_ptr, pFilename); + strcpy(pFilename, path); + } + + return; +} +#endif /* DHD_REQUEST_FW_PATH */ void dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path) { int ag_type; -#ifdef DHD_LINUX_STD_FW_API - char path[WLC_IOCTL_SMLEN]; - int path_len; -#endif /* External conf takes precedence if specified */ dhd_conf_preinit(dhd); -#ifdef DHD_LINUX_STD_FW_API +#ifdef DHD_REQUEST_FW_PATH // preprocess the filename to only left 'name' dhd_conf_get_filename(fw_path); dhd_conf_get_filename(nv_path); @@ -1339,23 +1550,17 @@ dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path) dhd_conf_set_nv_name_by_mac(dhd, nv_path); #endif -#ifdef DHD_LINUX_STD_FW_API - memset(path, 0, sizeof(path)); - path_len = dhd_conf_get_fw_path(path, sizeof(path)); - snprintf(path+path_len, WLC_IOCTL_SMLEN, "%s", fw_path); - CONFIG_MSG("Final fw_path=%s\n", path); - snprintf(path+path_len, WLC_IOCTL_SMLEN, "%s", nv_path); - CONFIG_MSG("Final nv_path=%s\n", path); - snprintf(path+path_len, WLC_IOCTL_SMLEN, "%s", dhd->clm_path); - CONFIG_MSG("Final clm_path=%s\n", path); - snprintf(path+path_len, WLC_IOCTL_SMLEN, "%s", dhd->conf_path); - CONFIG_MSG("Final conf_path=%s\n", path); -#else +#ifdef DHD_REQUEST_FW_PATH + dhd_conf_add_filepath(dhd, fw_path); + dhd_conf_add_filepath(dhd, nv_path); + dhd_conf_add_filepath(dhd, dhd->clm_path); + dhd_conf_add_filepath(dhd, dhd->conf_path); +#endif + CONFIG_MSG("Final fw_path=%s\n", fw_path); CONFIG_MSG("Final nv_path=%s\n", nv_path); CONFIG_MSG("Final clm_path=%s\n", dhd->clm_path); CONFIG_MSG("Final conf_path=%s\n", dhd->conf_path); -#endif dhd_conf_read_config(dhd, dhd->conf_path); #ifdef DHD_TPUT_PATCH @@ -1372,17 +1577,17 @@ dhd_conf_set_intiovar(dhd_pub_t *dhd, int ifidx, uint cmd, char *name, int val, if (val >= def) { if (down) { - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0) + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, ifidx)) < 0) CONFIG_ERROR("WLC_DOWN setting failed %d\n", ret); } if (cmd == WLC_SET_VAR) { CONFIG_TRACE("set %s %d\n", name, val); bcm_mkiovar(name, (char *)&val, sizeof(val), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, ifidx)) < 0) CONFIG_ERROR("%s setting failed %d\n", name, ret); } else { CONFIG_TRACE("set %s %d %d\n", name, cmd, val); - if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, 0)) < 0) + if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, ifidx)) < 0) CONFIG_ERROR("%s setting failed %d\n", name, ret); } } @@ -1487,6 +1692,150 @@ dhd_conf_get_iovar(dhd_pub_t *dhd, int ifidx, int cmd, char *name, return ret; } +static int +dhd_conf_get_ioctl_ver(dhd_pub_t *dhd) +{ + int ret = 0; + s32 val = 0; + + dhd->conf->ioctl_ver = WLC_IOCTL_VERSION; + ret = dhd_conf_get_iovar(dhd, 0, WLC_GET_VERSION, "WLC_GET_VERSION", + (char *)&val, sizeof(val)); + if (ret) { + return ret; + } + val = dtoh32(val); + if (val != WLC_IOCTL_VERSION && val != 1) { + CONFIG_ERROR("Version mismatch, please upgrade. Got %d, expected %d or 1\n", + val, WLC_IOCTL_VERSION); + return BCME_VERSION; + } + dhd->conf->ioctl_ver = val; + CONFIG_TRACE("ioctl_ver=%d\n", dhd->conf->ioctl_ver); + + return ret; +} + +int +dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec) +{ + int bcmerror = -1; + + memset(cspec, 0, sizeof(wl_country_t)); + bcm_mkiovar("country", NULL, 0, (char*)cspec, sizeof(wl_country_t)); + if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cspec, sizeof(wl_country_t), + FALSE, 0)) < 0) + CONFIG_ERROR("country code getting failed %d\n", bcmerror); + + return bcmerror; +} + +int +dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec) +{ + int bcmerror = -1; + struct dhd_conf *conf = dhd->conf; + country_list_t *country = conf->country_head; + +#ifdef CCODE_LIST + bcmerror = dhd_ccode_map_country_list(dhd, cspec); +#endif + // **:XZ/11 => return XZ/11 if not found + // **:**/0 => return user specified ccode if not found, but set regrev 0 + while (country != NULL) { + if (!strncmp("**", country->cspec.country_abbrev, 2)) { + if (!strncmp("**", country->cspec.ccode, 2)) { + cspec->rev = 0; + bcmerror = 0; + break; + } + memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ); + cspec->rev = country->cspec.rev; + bcmerror = 0; + break; + } else if (!strncmp(cspec->country_abbrev, + country->cspec.country_abbrev, 2)) { + memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ); + cspec->rev = country->cspec.rev; + bcmerror = 0; + break; + } + country = country->next; + } + + if (!bcmerror) + CONFIG_MSG("%s/%d\n", cspec->ccode, cspec->rev); + + return bcmerror; +} + +static int +dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec) +{ + int bcmerror = -1; + struct net_device *net; + int bytes_written = 0; + char event_msg[32]; + + memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t)); + + net = dhd_idx2net(dhd, 0); + snprintf(event_msg, sizeof(event_msg), "wl event_msg %d 0", WLC_E_COUNTRY_CODE_CHANGED); + wl_android_ext_priv_cmd(net, event_msg, 0, &bytes_written); + + CONFIG_MSG("set country %s, revision %d\n", cspec->ccode, cspec->rev); + bcmerror = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "country", (char *)cspec, + sizeof(wl_country_t), FALSE); + dhd_conf_get_country(dhd, cspec); + CONFIG_MSG("Country code: %s (%s/%d)\n", + cspec->country_abbrev, cspec->ccode, cspec->rev); + + snprintf(event_msg, sizeof(event_msg), "wl event_msg %d 1", WLC_E_COUNTRY_CODE_CHANGED); + wl_android_ext_priv_cmd(net, event_msg, 0, &bytes_written); + + return bcmerror; +} + +int +dhd_conf_fix_country(dhd_pub_t *dhd) +{ + int bcmerror = -1; + int band; + wl_uint32_list_t *list; + u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; + wl_country_t cspec; + + if (!(dhd && dhd->conf)) { + return bcmerror; + } + + memset(valid_chan_list, 0, sizeof(valid_chan_list)); + list = (wl_uint32_list_t *)(void *) valid_chan_list; + list->count = htod32(WL_NUMCHANNELS); + if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, valid_chan_list, + sizeof(valid_chan_list), FALSE, 0)) < 0) { + CONFIG_ERROR("get channels failed with %d\n", bcmerror); + } + + band = dhd_conf_get_band(dhd); + + if (bcmerror || ((band==WLC_BAND_AUTO || band==WLC_BAND_2G || band==-1) && + dtoh32(list->count)<11)) { + CONFIG_ERROR("bcmerror=%d, # of channels %d\n", + bcmerror, dtoh32(list->count)); + dhd_conf_map_country_list(dhd, &dhd->conf->cspec); + if ((bcmerror = dhd_conf_set_country(dhd, &dhd->conf->cspec)) < 0) { + strcpy(cspec.country_abbrev, "US"); + cspec.rev = 0; + strcpy(cspec.ccode, "US"); + dhd_conf_map_country_list(dhd, &cspec); + dhd_conf_set_country(dhd, &cspec); + } + } + + return bcmerror; +} + static int dhd_conf_rsdb_mode(dhd_pub_t *dhd, char *cmd, char *buf) { @@ -1694,6 +2043,76 @@ dhd_conf_scan_mac(dhd_pub_t * dhd, char *cmd, char *buf) } #endif +bool +dhd_conf_same_country(dhd_pub_t *dhd, char *buf) +{ + wl_country_t cspec = {{0}, 0, {0}}; + wl_country_t cur_cspec = {{0}, 0, {0}}; + + strlcpy(cspec.country_abbrev, buf, WL_CCODE_LEN + 1); + strlcpy(cspec.ccode, buf, WL_CCODE_LEN + 1); + dhd_conf_map_country_list(dhd, &cspec); + dhd_conf_get_country(dhd, &cur_cspec); + if (!memcmp(&cspec.ccode, &cur_cspec.ccode, WL_CCODE_LEN) && + (cspec.rev == cur_cspec.rev)) { + CONFIG_MSG("country code = %s/%d is already configured\n", + cspec.ccode, cspec.rev); + return TRUE; + } + + return FALSE; +} + +int +dhd_conf_country(dhd_pub_t *dhd, char *cmd, char *buf) +{ + wl_country_t cspec = {{0}, 0, {0}}; + int err = 0; + + if (buf) { + if (dhd_conf_same_country(dhd, buf)) { + return 0; + } + strlcpy(cspec.country_abbrev, buf, WL_CCODE_LEN + 1); + strlcpy(cspec.ccode, buf, WL_CCODE_LEN + 1); + dhd_conf_map_country_list(dhd, &cspec); + err = dhd_conf_set_country(dhd, &cspec); + if (!err) { + dhd_conf_fix_country(dhd); + } + dhd_conf_get_country(dhd, &dhd->dhd_cspec); + } + + return err; +} + +int +dhd_conf_autocountry(dhd_pub_t *dhd, char *cmd, char *buf) +{ + struct net_device *net; + int bytes_written = 0; + char event_msg[32]; + int enable = 0; + + if (buf) { + sscanf(buf, "%d", &enable); + } + + net = dhd_idx2net(dhd, 0); + snprintf(event_msg, sizeof(event_msg), "wl event_msg %d 0", WLC_E_COUNTRY_CODE_CHANGED); + wl_android_ext_priv_cmd(net, event_msg, 0, &bytes_written); + + CONFIG_MSG("autocountry %d\n", enable); + dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "autocountry", enable, 0, FALSE); + + snprintf(event_msg, sizeof(event_msg), "wl event_msg %d 1", WLC_E_COUNTRY_CODE_CHANGED); + wl_android_ext_priv_cmd(net, event_msg, 0, &bytes_written); + + dhd_conf_country(dhd, "country", dhd->conf->cspec.country_abbrev); + + return 0; +} + typedef int (tpl_parse_t)(dhd_pub_t *dhd, char *name, char *buf); typedef struct iovar_tpl_t { @@ -1709,6 +2128,8 @@ const iovar_tpl_t iovar_tpl_list[] = { #ifndef SUPPORT_RANDOM_MAC_SCAN {WLC_SET_VAR, "scanmac", dhd_conf_scan_mac}, #endif + {WLC_SET_VAR, "country", dhd_conf_country}, + {WLC_SET_VAR, "autocountry", dhd_conf_autocountry}, }; static int iovar_tpl_parse(const iovar_tpl_t *tpl, int tpl_count, @@ -1800,170 +2221,39 @@ dhd_conf_get_band(dhd_pub_t *dhd) } int -dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec) -{ - int bcmerror = -1; - - memset(cspec, 0, sizeof(wl_country_t)); - bcm_mkiovar("country", NULL, 0, (char*)cspec, sizeof(wl_country_t)); - if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cspec, sizeof(wl_country_t), - FALSE, 0)) < 0) - CONFIG_ERROR("country code getting failed %d\n", bcmerror); - - return bcmerror; -} - -int -dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec) -{ - int bcmerror = -1; - struct dhd_conf *conf = dhd->conf; - country_list_t *country = conf->country_head; - -#ifdef CCODE_LIST - bcmerror = dhd_ccode_map_country_list(dhd, cspec); -#endif - // **:XZ/11 => return XZ/11 if not found - // **:**/0 => return user specified ccode if not found, but set regrev 0 - while (country != NULL) { - if (!strncmp("**", country->cspec.country_abbrev, 2)) { - if (!strncmp("**", country->cspec.ccode, 2)) { - cspec->rev = 0; - bcmerror = 0; - break; - } - memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ); - cspec->rev = country->cspec.rev; - bcmerror = 0; - break; - } else if (!strncmp(cspec->country_abbrev, - country->cspec.country_abbrev, 2)) { - memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ); - cspec->rev = country->cspec.rev; - bcmerror = 0; - break; - } - country = country->next; - } - - if (!bcmerror) - CONFIG_MSG("%s/%d\n", cspec->ccode, cspec->rev); - - return bcmerror; -} - -int -dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec) -{ - int bcmerror = -1; - - memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t)); - - CONFIG_MSG("set country %s, revision %d\n", cspec->ccode, cspec->rev); - bcmerror = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "country", (char *)cspec, - sizeof(wl_country_t), FALSE); - dhd_conf_get_country(dhd, cspec); - CONFIG_MSG("Country code: %s (%s/%d)\n", - cspec->country_abbrev, cspec->ccode, cspec->rev); - - return bcmerror; -} - -int -dhd_conf_fix_country(dhd_pub_t *dhd) -{ - int bcmerror = -1; - int band; - wl_uint32_list_t *list; - u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; - wl_country_t cspec; - - if (!(dhd && dhd->conf)) { - return bcmerror; - } - - memset(valid_chan_list, 0, sizeof(valid_chan_list)); - list = (wl_uint32_list_t *)(void *) valid_chan_list; - list->count = htod32(WL_NUMCHANNELS); - if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, valid_chan_list, - sizeof(valid_chan_list), FALSE, 0)) < 0) { - CONFIG_ERROR("get channels failed with %d\n", bcmerror); - } - - band = dhd_conf_get_band(dhd); - - if (bcmerror || ((band==WLC_BAND_AUTO || band==WLC_BAND_2G || band==-1) && - dtoh32(list->count)<11)) { - CONFIG_ERROR("bcmerror=%d, # of channels %d\n", - bcmerror, dtoh32(list->count)); - dhd_conf_map_country_list(dhd, &dhd->conf->cspec); - if ((bcmerror = dhd_conf_set_country(dhd, &dhd->conf->cspec)) < 0) { - strcpy(cspec.country_abbrev, "US"); - cspec.rev = 0; - strcpy(cspec.ccode, "US"); - dhd_conf_map_country_list(dhd, &cspec); - dhd_conf_set_country(dhd, &cspec); - } - } - - return bcmerror; -} - -bool -dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel) -{ - int i; - bool match = false; - - if (dhd && dhd->conf) { - if (dhd->conf->channels.count == 0) - return true; - for (i=0; iconf->channels.count; i++) { - if (channel == dhd->conf->channels.channel[i]) - match = true; - } - } else { - match = true; - CONFIG_ERROR("dhd or conf is NULL\n"); - } - - return match; -} - -int -dhd_conf_set_roam(dhd_pub_t *dhd) +dhd_conf_set_roam(dhd_pub_t *dhd, int ifidx) { int bcmerror = -1; struct dhd_conf *conf = dhd->conf; uint wnm_bsstrans_resp = 0; if (dhd->conf->chip == BCM4359_CHIP_ID) { - dhd_conf_get_iovar(dhd, 0, WLC_GET_VAR, "wnm_bsstrans_resp", + dhd_conf_get_iovar(dhd, ifidx, WLC_GET_VAR, "wnm_bsstrans_resp", (char *)&wnm_bsstrans_resp, sizeof(wnm_bsstrans_resp)); if (wnm_bsstrans_resp == WL_BSSTRANS_POLICY_PRODUCT) { dhd->wbtext_policy = WL_BSSTRANS_POLICY_ROAM_ALWAYS; - dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "wnm_bsstrans_resp", + dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "wnm_bsstrans_resp", WL_BSSTRANS_POLICY_ROAM_ALWAYS, 0, FALSE); } } dhd_roam_disable = conf->roam_off; - dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "roam_off", dhd->conf->roam_off, 0, FALSE); + dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "roam_off", dhd->conf->roam_off, 0, FALSE); if (!conf->roam_off || !conf->roam_off_suspend) { CONFIG_MSG("set roam_trigger %d\n", conf->roam_trigger[0]); - dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_TRIGGER, "WLC_SET_ROAM_TRIGGER", + dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_ROAM_TRIGGER, "WLC_SET_ROAM_TRIGGER", (char *)conf->roam_trigger, sizeof(conf->roam_trigger), FALSE); CONFIG_MSG("set roam_scan_period %d\n", conf->roam_scan_period[0]); - dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_SCAN_PERIOD, "WLC_SET_ROAM_SCAN_PERIOD", + dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_ROAM_SCAN_PERIOD, "WLC_SET_ROAM_SCAN_PERIOD", (char *)conf->roam_scan_period, sizeof(conf->roam_scan_period), FALSE); CONFIG_MSG("set roam_delta %d\n", conf->roam_delta[0]); - dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_DELTA, "WLC_SET_ROAM_DELTA", + dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_ROAM_DELTA, "WLC_SET_ROAM_DELTA", (char *)conf->roam_delta, sizeof(conf->roam_delta), FALSE); - dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "fullroamperiod", + dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "fullroamperiod", dhd->conf->fullroamperiod, 1, FALSE); } @@ -2258,9 +2548,8 @@ dhd_conf_add_pkt_filter(dhd_pub_t *dhd) * Case 3: magic pkt and event wake up * 1) dhd_master_mode=1 * 2) pkt_filter_delete=100, 102, 103, 104, 105, 106, 107 - * 3) pkt_filter_add=141 0 0 0 0xFFFFFFFFFFFF 0x000000000000 - * 4) magic_pkt_filter_add=141 0 1 12 - * 5) rekey_offload=1 + * 3) magic_pkt_filter_add=141 0 1 12 + * 4) rekey_offload=1 */ for(i=0; iconf->pkt_filter_add.count; i++) { dhd->pktfilter[i+dhd->pktfilter_count] = dhd->conf->pkt_filter_add.filter[i]; @@ -2342,12 +2631,24 @@ dhd_conf_check_hostsleep(dhd_pub_t *dhd, int cmd, void *buf, int len, int *hostsleep_set, int *hostsleep_val, int *ret) { if (dhd->conf->insuspend & (NO_TXCTL_IN_SUSPEND | WOWL_IN_SUSPEND)) { + int wowl_dngldown = 0; +#ifdef WL_EXT_WOWL + wowl_dngldown = dhd_conf_wowl_dngldown(dhd); +#endif if (cmd == WLC_SET_VAR) { char *psleep = NULL; - psleep = strstr(buf, "hostsleep"); - if (psleep) { - *hostsleep_set = 1; - memcpy(hostsleep_val, psleep+strlen("hostsleep")+1, sizeof(int)); + if (wowl_dngldown) { + psleep = strstr(buf, "wowl_activate"); + if (psleep) { + *hostsleep_set = 1; + memcpy(hostsleep_val, psleep+strlen("wowl_activate")+1, sizeof(int)); + } + } else { + psleep = strstr(buf, "hostsleep"); + if (psleep) { + *hostsleep_set = 1; + memcpy(hostsleep_val, psleep+strlen("hostsleep")+1, sizeof(int)); + } } } if (dhd->hostsleep && (!*hostsleep_set || *hostsleep_val)) { @@ -2589,13 +2890,28 @@ dhd_conf_wowl_wakeind(dhd_pub_t *dhd, int ifidx, bool clear) return ret; } + +int +dhd_conf_wowl_dngldown(dhd_pub_t *dhd) +{ + int wowl_dngldown = 0; +#ifdef BCMDBUS + uint insuspend = 0; + insuspend = dhd_conf_get_insuspend(dhd, ALL_IN_SUSPEND); + if ((insuspend & WOWL_IN_SUSPEND) && dhd_master_mode) { + wowl_dngldown = dhd->conf->wowl_dngldown; + } +#endif + + return wowl_dngldown; +} #endif int dhd_conf_mkeep_alive(dhd_pub_t *dhd, int ifidx, int id, int period, char *packet, bool bcast) { - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; + wl_mkeep_alive_pkt_v1_t *mkeep_alive_pktp; int ret = 0, len_bytes=0, buf_len=0; char *buf = NULL, *iovar_buf = NULL; uint8 *pdata; @@ -2612,8 +2928,8 @@ dhd_conf_mkeep_alive(dhd_pub_t *dhd, int ifidx, int id, int period, CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN); goto exit; } - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *)buf; - mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pktp = (wl_mkeep_alive_pkt_v1_t *)buf; + mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION_1); mkeep_alive_pktp->length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); mkeep_alive_pktp->keep_alive_id = id; buf_len += WL_MKEEP_ALIVE_FIXED_LEN; @@ -2849,14 +3165,18 @@ dhd_conf_suspend_resume_sta(dhd_pub_t *dhd, int ifidx, int suspend) for(i=0; ipkt_filter_add.count; i++) { dhd_conf_wowl_pattern(dhd, ifidx, TRUE, conf->pkt_filter_add.filter[i]); } + CONFIG_MSG("wowl = 0x%x\n", conf->wowl); dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "wowl", conf->wowl, 0, FALSE); - dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "wowl_activate", 1, 0, FALSE); +#ifdef BCMDBUS + CONFIG_MSG("wowl_dngldown = %d\n", conf->wowl_dngldown); + dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "wowl_dngldown", conf->wowl_dngldown, 1, FALSE); +#endif dhd_conf_wowl_wakeind(dhd, ifidx, TRUE); } #endif } else { - dhd_conf_get_iovar(dhd, 0, WLC_GET_PM, "WLC_GET_PM", (char *)&pm, sizeof(pm)); + dhd_conf_get_iovar(dhd, ifidx, WLC_GET_PM, "WLC_GET_PM", (char *)&pm, sizeof(pm)); CONFIG_TRACE("PM in suspend = %d\n", pm); if (conf->pm >= 0) pm = conf->pm; @@ -2866,7 +3186,7 @@ dhd_conf_suspend_resume_sta(dhd_pub_t *dhd, int ifidx, int suspend) #ifdef WL_EXT_WOWL if (insuspend & WOWL_IN_SUSPEND) { dhd_conf_wowl_wakeind(dhd, ifidx, FALSE); - dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "wowl_activate", 0, 0, FALSE); +// dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "wowl_activate", 0, 0, FALSE); dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "wowl", 0, 0, FALSE); dhd_conf_wowl_pattern(dhd, ifidx, FALSE, "clr"); } @@ -2884,7 +3204,6 @@ dhd_conf_suspend_resume_sta(dhd_pub_t *dhd, int ifidx, int suspend) static int dhd_conf_suspend_resume_ap(dhd_pub_t *dhd, int ifidx, int suspend) { - struct dhd_conf *conf = dhd->conf; uint insuspend = 0; insuspend = dhd_conf_get_insuspend(dhd, ALL_IN_SUSPEND); @@ -2916,19 +3235,32 @@ dhd_conf_suspend_resume_bus(dhd_pub_t *dhd, int suspend) if (suspend) { if (insuspend & (WOWL_IN_SUSPEND | NO_TXCTL_IN_SUSPEND)) { -#ifdef BCMSDIO uint32 intstatus = 0; - int ret = 0; -#endif - int hostsleep = 2; + int ret = 0, hostsleep = 2, wowl_dngldown = 0; #ifdef WL_EXT_WOWL hostsleep = 1; + if ((insuspend & WOWL_IN_SUSPEND) && dhd_master_mode) { + dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "wowl_activate", 1, 0, FALSE); +#ifdef BCMDBUS + wowl_dngldown = dhd->conf->wowl_dngldown; #endif - dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "hostsleep", hostsleep, 0, FALSE); + } +#endif + if (!wowl_dngldown) { + dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "hostsleep", hostsleep, 0, FALSE); + } #ifdef BCMSDIO ret = dhd_bus_sleep(dhd, TRUE, &intstatus); - CONFIG_TRACE("ret = %d, intstatus = 0x%x\n", ret, intstatus); #endif +#ifdef BCMPCIE + ret = dhd_bus_sleep(dhd, TRUE, NULL); +#endif +#ifdef BCMDBUS + if (wowl_dngldown) { + ret = dhd_bus_sleep(dhd, TRUE, NULL); + } +#endif + CONFIG_MSG("ret = %d, intstatus = 0x%x\n", ret, intstatus); } } else { if (insuspend & (WOWL_IN_SUSPEND | NO_TXCTL_IN_SUSPEND)) { @@ -3506,7 +3838,15 @@ dhd_conf_read_roam_params(dhd_pub_t *dhd, char *full_param, uint len_param) else if (!strncmp("fullroamperiod=", full_param, len_param)) { conf->fullroamperiod = (int)simple_strtol(data, NULL, 10); CONFIG_MSG("fullroamperiod = %d\n", conf->fullroamperiod); - } else + } + else if (!strncmp("wl_reassoc_support=", full_param, len_param)) { + if (!strncmp(data, "0", 1)) + wl_reassoc_support = FALSE; + else + wl_reassoc_support = TRUE; + CONFIG_MSG("wl_reassoc_support = %d\n", wl_reassoc_support); + } + else return false; return true; @@ -3845,11 +4185,10 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param) dhd_doflow = TRUE; CONFIG_MSG("dhd_doflow = %d\n", dhd_doflow); } - else if (!strncmp("dhd_slpauto=", full_param, len_param) || - !strncmp("kso_enable=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - dhd_slpauto = FALSE; - else + else if (!strncmp("dhd_slpauto=", full_param, len_param)) { + if (!strncmp(data, "0", 1)) { + dhd_conf_disable_slpauto(dhd); + } else dhd_slpauto = TRUE; CONFIG_MSG("dhd_slpauto = %d\n", dhd_slpauto); } @@ -4021,6 +4360,14 @@ dhd_conf_read_pcie_params(dhd_pub_t *dhd, char *full_param, uint len_param) conf->enq_hdr_pkt = (int)simple_strtol(data, NULL, 0); CONFIG_MSG("enq_hdr_pkt = 0x%x\n", conf->enq_hdr_pkt); } + else if (!strncmp("aspm=", full_param, len_param)) { + conf->aspm = (int)simple_strtol(data, NULL, 0); + CONFIG_MSG("aspm = %d\n", conf->aspm); + } + else if (!strncmp("l1ss=", full_param, len_param)) { + conf->l1ss = (int)simple_strtol(data, NULL, 0); + CONFIG_MSG("l1ss = %d\n", conf->l1ss); + } else return false; @@ -4079,6 +4426,12 @@ dhd_conf_read_pm_params(dhd_pub_t *dhd, char *full_param, uint len_param) conf->wowl = (int)simple_strtol(data, NULL, 0); CONFIG_MSG("wowl = 0x%x\n", conf->wowl); } +#ifdef BCMDBUS + else if (!strncmp("wowl_dngldown=", full_param, len_param)) { + conf->wowl_dngldown = (int)simple_strtol(data, NULL, 0); + CONFIG_MSG("wowl_dngldown = 0x%x\n", conf->wowl_dngldown); + } +#endif #endif else if (!strncmp("rekey_offload=", full_param, len_param)) { if (!strncmp(data, "1", 1)) @@ -4117,7 +4470,6 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param) struct dhd_conf *conf = dhd->conf; char *data = full_param+len_param; char *pch, *pick_tmp; - int i; #ifdef GET_CUSTOM_MAC_FROM_CONFIG struct ether_addr ea_addr; char macpad[56]; @@ -4167,21 +4519,6 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param) CONFIG_MSG("bw_cap 5g = %d\n", conf->bw_cap[1]); } } - else if (!strncmp("channels=", full_param, len_param)) { - pick_tmp = data; - pch = bcmstrtok(&pick_tmp, " ,.-", 0); - i=0; - while (pch != NULL && ichannels.channel[i] = (uint32)simple_strtol(pch, NULL, 10); - pch = bcmstrtok(&pick_tmp, " ,.-", 0); - i++; - } - conf->channels.count = i; - CONFIG_MSG("channels = "); - for (i=0; ichannels.count; i++) - printk(KERN_CONT "%d ", conf->channels.channel[i]); - printk(KERN_CONT "\n"); - } else if (!strncmp("keep_alive_period=", full_param, len_param)) { conf->keep_alive_period = (uint)simple_strtol(data, NULL, 10); CONFIG_MSG("keep_alive_period = %d\n", conf->keep_alive_period); @@ -4233,7 +4570,7 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param) conf->pktprio8021x = (int)simple_strtol(data, NULL, 10); CONFIG_MSG("pktprio8021x = %d\n", conf->pktprio8021x); } -#if defined(BCMSDIO) || defined(BCMPCIE) +#if defined(BCMSDIO) else if (!strncmp("dhd_txbound=", full_param, len_param)) { dhd_txbound = (uint)simple_strtol(data, NULL, 10); CONFIG_MSG("dhd_txbound = %d\n", dhd_txbound); @@ -4263,6 +4600,12 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param) conf->in4way = (int)simple_strtol(data, NULL, 0); CONFIG_MSG("in4way = 0x%x\n", conf->in4way); } +#ifdef BTC_WAR + else if (!strncmp("btc_war=", full_param, len_param)) { + btc_war = (int)simple_strtol(data, NULL, 0); + CONFIG_MSG("btc_war = 0x%x\n", btc_war); + } +#endif /* BTC_WAR */ else if (!strncmp("war=", full_param, len_param)) { conf->war = (int)simple_strtol(data, NULL, 0); CONFIG_MSG("war = 0x%x\n", conf->war); @@ -4475,11 +4818,7 @@ dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path) goto err; } -#ifdef DHD_LINUX_STD_FW_API - memblock_len = len; -#else memblock_len = MAXSZ_CONFIG; -#endif /* DHD_LINUX_STD_FW_API */ pick = MALLOC(dhd->osh, MAXSZ_BUF); if (!pick) { @@ -4684,8 +5023,115 @@ dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable) } } + +static void +dhd_conf_set_ampdu_mpdu(dhd_pub_t *dhd) +{ + uint chip = dhd->conf->chip; + char ampdu_mpdu[32] = "ampdu_mpdu="; + int val = -1; + + if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || + chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || + chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || + chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || + chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || + chip == BCM4371_CHIP_ID || + chip == BCM43430_CHIP_ID || + chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID || + chip == BCM4359_CHIP_ID || chip == BCM43012_CHIP_ID) { + val = 16; + } else if (chip == BCM43751_CHIP_ID || chip == BCM43752_CHIP_ID || + chip == BCM43756_CHIP_ID) { + val = 32; + } + + if (val > 0) { + snprintf(ampdu_mpdu+strlen(ampdu_mpdu), sizeof(ampdu_mpdu), "%d", val); + dhd_conf_set_wl_cmd(dhd, ampdu_mpdu, TRUE); + } +} + +#if defined(SDIO_ISR_THREAD) +static void +dhd_conf_set_intr_extn(dhd_pub_t *dhd) +{ + uint chip = dhd->conf->chip; + + if (chip == BCM43012_CHIP_ID || + chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || + chip == BCM43454_CHIP_ID || chip == BCM4345_CHIP_ID || + chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || + chip == BCM4345_CHIP_ID || chip == BCM4371_CHIP_ID || + chip == BCM4359_CHIP_ID || + chip == BCM43751_CHIP_ID || chip == BCM43752_CHIP_ID || + chip == BCM4375_CHIP_ID || chip == BCM43756_CHIP_ID || + chip == BCM43711_CHIP_ID || + chip == BCM4381_CHIP_ID || chip == BCM4382_CHIP_ID) { + CONFIG_TRACE("enable intr_extn\n"); + dhd->conf->intr_extn = TRUE; + } +} +#endif /* SDIO_ISR_THREAD */ #endif +static void +dhd_conf_set_txbf(dhd_pub_t *dhd) +{ + uint chip = dhd->conf->chip; + + if (chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || + chip == BCM4371_CHIP_ID || chip == BCM4359_CHIP_ID || + chip == BCM43569_CHIP_ID || + chip == BCM43751_CHIP_ID || chip == BCM43752_CHIP_ID || + chip == BCM4375_CHIP_ID || chip == BCM43756_CHIP_ID || + chip == BCM4382_CHIP_ID) { + CONFIG_TRACE("enable txbf\n"); + dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "txbf", 1, 0, FALSE); + } +} + +static void +dhd_conf_tput_improve(dhd_pub_t *dhd) +{ + struct dhd_conf *conf = dhd->conf; + uint chip = conf->chip; + uint chiprev = conf->chiprev; + + if ((chip == BCM43430_CHIP_ID && chiprev == 2) || + chip == BCM43012_CHIP_ID || + chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || + chip == BCM43454_CHIP_ID || chip == BCM4345_CHIP_ID || + chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || + chip == BCM4345_CHIP_ID || chip == BCM4371_CHIP_ID || + chip == BCM43569_CHIP_ID || chip == BCM4359_CHIP_ID || + chip == BCM43751_CHIP_ID || chip == BCM43752_CHIP_ID || + chip == BCM4375_CHIP_ID || chip == BCM43756_CHIP_ID || + chip == BCM43711_CHIP_ID || + chip == BCM4381_CHIP_ID || chip == BCM4382_CHIP_ID) { + CONFIG_TRACE("enable tput parameters\n"); +#ifdef DHDTCPACK_SUPPRESS +#ifdef BCMSDIO + conf->tcpack_sup_mode = TCPACK_SUP_REPLACE; +#endif +#endif +#if defined(BCMSDIO) + dhd_rxbound = 128; + dhd_txbound = 64; +#endif + conf->frameburst = 1; +#ifdef BCMSDIO + conf->dhd_txminmax = -1; + conf->txinrx_thres = 128; +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) + conf->orphan_move = 1; +#else + conf->orphan_move = 0; +#endif + } +} + #ifdef UPDATE_MODULE_NAME #if defined(BCMSDIO) || defined(BCMPCIE) static void @@ -4702,7 +5148,7 @@ dhd_conf_compat_vht(dhd_pub_t *dhd) int dhd_conf_compat_func(dhd_pub_t *dhd) { - const module_name_map_t* row = NULL; + const module_name_map_t *row = NULL; row = dhd_conf_match_module(dhd); if (row && row->compat_func) { @@ -4713,29 +5159,44 @@ dhd_conf_compat_func(dhd_pub_t *dhd) } #endif +void +dhd_conf_preinit_ioctls_sta(dhd_pub_t *dhd, int ifidx) +{ + struct dhd_conf *conf = dhd->conf; + int pm; + + dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "bcn_timeout", conf->bcn_timeout, 0, FALSE); +#ifdef NO_POWER_SAVE + pm = PM_OFF; +#else + if (conf->pm >= 0) + pm = conf->pm; + else + pm = PM_FAST; +#endif + dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_PM, "WLC_SET_PM", pm, 0, FALSE); + dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "assoc_retry_max", 10, 0, FALSE); + dhd_conf_set_roam(dhd, ifidx); +} + void dhd_conf_postinit_ioctls(dhd_pub_t *dhd) { struct dhd_conf *conf = dhd->conf; - char wl_preinit[] = "assoc_retry_max=10"; + char wl_preinit[] = ""; #ifdef NO_POWER_SAVE char wl_no_power_save[] = "mpc=0, 86=0"; dhd_conf_set_wl_cmd(dhd, wl_no_power_save, FALSE); #endif + dhd_conf_get_ioctl_ver(dhd); dhd_conf_set_intiovar(dhd, 0, WLC_UP, "WLC_UP", 0, 0, FALSE); - dhd_conf_map_country_list(dhd, &conf->cspec); - dhd_conf_set_country(dhd, &conf->cspec); - dhd_conf_fix_country(dhd); - dhd_conf_get_country(dhd, &dhd->dhd_cspec); + dhd_conf_country(dhd, "country", conf->cspec.country_abbrev); dhd_conf_set_intiovar(dhd, 0, WLC_SET_BAND, "WLC_SET_BAND", conf->band, 0, FALSE); - dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "bcn_timeout", conf->bcn_timeout, 0, FALSE); - dhd_conf_set_intiovar(dhd, 0, WLC_SET_PM, "WLC_SET_PM", conf->pm, 0, FALSE); dhd_conf_set_intiovar(dhd, 0, WLC_SET_SRL, "WLC_SET_SRL", conf->srl, 0, FALSE); dhd_conf_set_intiovar(dhd, 0, WLC_SET_LRL, "WLC_SET_LRL", conf->lrl, 0, FALSE); dhd_conf_set_bw_cap(dhd); - dhd_conf_set_roam(dhd); #if defined(BCMPCIE) dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "bus:deepsleep_disable", @@ -4761,28 +5222,17 @@ dhd_conf_postinit_ioctls(dhd_pub_t *dhd) dhd_conf_set_intiovar(dhd, 0, WLC_SET_FAKEFRAG, "WLC_SET_FAKEFRAG", conf->frameburst, 0, FALSE); + dhd_conf_preinit_ioctls_sta(dhd, 0); dhd_conf_set_wl_cmd(dhd, wl_preinit, TRUE); #if defined(BCMSDIO) - if (conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID) { - char ampdu_mpdu[] = "ampdu_mpdu=32"; - dhd_conf_set_wl_cmd(dhd, ampdu_mpdu, TRUE); - } else { - char ampdu_mpdu[] = "ampdu_mpdu=16"; - dhd_conf_set_wl_cmd(dhd, ampdu_mpdu, TRUE); - } + dhd_conf_set_ampdu_mpdu(dhd); #endif #ifdef DHD_TPUT_PATCH if (dhd->conf->mtu) dhd_change_mtu(dhd, dhd->conf->mtu, 0); #endif - if (conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID || - conf->chip == BCM4371_CHIP_ID || conf->chip == BCM4359_CHIP_ID || - conf->chip == BCM43569_CHIP_ID || - conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID || - conf->chip == BCM4375_CHIP_ID) { - dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "txbf", 1, 0, FALSE); - } + dhd_conf_set_txbf(dhd); if (conf->chip == BCM4375_CHIP_ID) { char he_cmd[] = "110=1, nmode=1, vhtmode=1, he=enab 1"; dhd_conf_set_wl_cmd(dhd, he_cmd, TRUE); @@ -4808,6 +5258,7 @@ dhd_conf_postinit_ioctls(dhd_pub_t *dhd) } } #endif /* WLEASYMESH */ +#if defined(BCMSDIO) || defined(BCMPCIE) #if defined(BCMSDIO) if (conf->devid == BCM43751_CHIP_ID) #elif defined(BCMPCIE) @@ -4819,6 +5270,7 @@ dhd_conf_postinit_ioctls(dhd_pub_t *dhd) dhd_conf_set_wl_cmd(dhd, he_features, TRUE); } } +#endif #ifdef UPDATE_MODULE_NAME dhd_conf_compat_func(dhd); #endif @@ -4828,6 +5280,10 @@ dhd_conf_postinit_ioctls(dhd_pub_t *dhd) dhd_conf_set_wl_cmd(dhd, scanmac, TRUE); } #endif + if (conf->chip == BCM4381_CHIP_ID) { + char ampdu_hostreorder[] = "ampdu_hostreorder=1"; + dhd_conf_set_wl_cmd(dhd, ampdu_hostreorder, TRUE); + } dhd_conf_set_wl_cmd(dhd, conf->wl_preinit, TRUE); #ifndef WL_CFG80211 @@ -4836,13 +5292,11 @@ dhd_conf_postinit_ioctls(dhd_pub_t *dhd) } -int -dhd_conf_preinit(dhd_pub_t *dhd) +void +dhd_conf_free_preinit(dhd_pub_t *dhd) { struct dhd_conf *conf = dhd->conf; - CONFIG_TRACE("Enter\n"); - #ifdef SET_FWNV_BY_MAC dhd_conf_free_mac_list(&conf->fw_by_mac); dhd_conf_free_mac_list(&conf->nv_by_mac); @@ -4872,6 +5326,16 @@ dhd_conf_preinit(dhd_pub_t *dhd) kfree(conf->vndr_ie_assocreq); conf->vndr_ie_assocreq = NULL; } +} + +int +dhd_conf_preinit(dhd_pub_t *dhd) +{ + struct dhd_conf *conf = dhd->conf; + + CONFIG_TRACE("Enter\n"); + + dhd_conf_free_preinit(dhd); conf->band = -1; memset(&conf->bw_cap, -1, sizeof(conf->bw_cap)); if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) { @@ -4888,12 +5352,19 @@ dhd_conf_preinit(dhd_pub_t *dhd) strcpy(conf->cspec.ccode, "CN"); conf->cspec.rev = 38; } + else if ((conf->chip == BCM43752_CHIP_ID && conf->chiprev == 4) || + conf->chip == BCM43756_CHIP_ID || conf->chip == BCM43711_CHIP_ID || + conf->chip == BCM4381_CHIP_ID || conf->chip == BCM4382_CHIP_ID) { + strcpy(conf->cspec.country_abbrev, "US"); + strcpy(conf->cspec.ccode, "US"); + conf->cspec.rev = 0; + } else { strcpy(conf->cspec.country_abbrev, "CN"); strcpy(conf->cspec.ccode, "CN"); conf->cspec.rev = 0; } - memset(&conf->channels, 0, sizeof(wl_channel_list_t)); + conf->ioctl_ver = WLC_IOCTL_VERSION; conf->roam_off = 1; conf->roam_off_suspend = 1; conf->roam_trigger[0] = -65; @@ -4954,10 +5425,12 @@ dhd_conf_preinit(dhd_pub_t *dhd) #endif #endif #ifdef BCMPCIE - conf->bus_deepsleep_disable = 1; + conf->bus_deepsleep_disable = -1; conf->flow_ring_queue_threshold = FLOW_RING_QUEUE_THRESHOLD; conf->d2h_intr_method = -1; conf->d2h_intr_control = -1; + conf->aspm = -1; + conf->l1ss = -1; conf->enq_hdr_pkt = 0; #endif conf->dpc_cpucore = -1; @@ -4969,11 +5442,18 @@ dhd_conf_preinit(dhd_pub_t *dhd) conf->pm_in_suspend = -1; conf->insuspend = 0; conf->suspend_mode = PM_NOTIFIER; +#ifndef WL_CFG80211 + conf->suspend_bcn_li_dtim = 3; +#else conf->suspend_bcn_li_dtim = -1; +#endif conf->rekey_offload = FALSE; #ifdef WL_EXT_WOWL dhd_master_mode = TRUE; conf->wowl = WL_WOWL_NET|WL_WOWL_DIS|WL_WOWL_BCN; +#ifdef BCMDBUS + conf->wowl_dngldown = 0; +#endif conf->insuspend |= (WOWL_IN_SUSPEND | NO_TXDATA_IN_SUSPEND); #endif if (conf->suspend_mode == PM_NOTIFIER || conf->suspend_mode == SUSPEND_MODE_2) @@ -5011,10 +5491,17 @@ dhd_conf_preinit(dhd_pub_t *dhd) conf->rxcnt_timeout = 3; conf->in4way = STA_NO_SCAN_IN4WAY | STA_WAIT_DISCONNECTED | AP_WAIT_STA_RECONNECT; +#ifdef WL_EXT_RECONNECT + conf->in4way |= STA_REASSOC_RETRY; +#endif if (conf->chip == BCM43752_CHIP_ID) - conf->war = SET_CHAN_INCONN | FW_REINIT_INCSA | FW_REINIT_EMPTY_SCAN; + conf->war = SET_CHAN_INCONN | FW_REINIT_INCSA | FW_REINIT_EMPTY_SCAN | + FW_REINIT_RXF0OVFL; else conf->war = 0; +#ifdef EAPOL_RESEND + conf->war |= RESEND_EAPOL_PKT; +#endif #ifdef P2P_AP_CONCURRENT conf->war |= P2P_AP_MAC_CONFLICT; #endif @@ -5026,7 +5513,9 @@ dhd_conf_preinit(dhd_pub_t *dhd) conf->data_drop_mode = NO_DATA_DROP; conf->tput_monitor_ms = 0; #ifdef BCMSDIO - if (conf->chip == BCM43752_CHIP_ID || conf->chip == BCM4375_CHIP_ID) + if (conf->chip == BCM43752_CHIP_ID || conf->chip == BCM43756_CHIP_ID || + conf->chip == BCM43711_CHIP_ID || + conf->chip == BCM4381_CHIP_ID || conf->chip == BCM4382_CHIP_ID) conf->doflow_tput_thresh = 200; else conf->doflow_tput_thresh = 9999; @@ -5038,7 +5527,9 @@ dhd_conf_preinit(dhd_pub_t *dhd) conf->scan_intput = SCAN_CURCHAN_INTPUT; conf->scan_busy_thresh = 10; conf->scan_busy_tmo = 120; - if (conf->chip == BCM43752_CHIP_ID || conf->chip == BCM4375_CHIP_ID) + if (conf->chip == BCM43752_CHIP_ID || conf->chip == BCM4375_CHIP_ID || + conf->chip == BCM43756_CHIP_ID || conf->chip == BCM43711_CHIP_ID || + conf->chip == BCM4381_CHIP_ID || conf->chip == BCM4382_CHIP_ID) conf->scan_tput_thresh = 100; else conf->scan_tput_thresh = 9999; @@ -5065,49 +5556,14 @@ dhd_conf_preinit(dhd_pub_t *dhd) memset(conf->isam_enable, 0, sizeof(conf->isam_enable)); #endif #if defined(SDIO_ISR_THREAD) - if (conf->chip == BCM43012_CHIP_ID || - conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID || - conf->chip == BCM43454_CHIP_ID || conf->chip == BCM4345_CHIP_ID || - conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID || - conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID || - conf->chip == BCM4359_CHIP_ID || - conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID || - conf->chip == BCM4375_CHIP_ID) { - conf->intr_extn = TRUE; - } + dhd_conf_set_intr_extn(dhd); #endif - if ((conf->chip == BCM43430_CHIP_ID && conf->chiprev == 2) || - conf->chip == BCM43012_CHIP_ID || - conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID || - conf->chip == BCM43454_CHIP_ID || conf->chip == BCM4345_CHIP_ID || - conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID || - conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID || - conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID || - conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID || - conf->chip == BCM4375_CHIP_ID) { -#ifdef DHDTCPACK_SUPPRESS -#ifdef BCMSDIO - conf->tcpack_sup_mode = TCPACK_SUP_REPLACE; -#endif -#endif -#if defined(BCMSDIO) || defined(BCMPCIE) - dhd_rxbound = 128; - dhd_txbound = 64; -#endif - conf->frameburst = 1; -#ifdef BCMSDIO - conf->dhd_txminmax = -1; - conf->txinrx_thres = 128; -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) - conf->orphan_move = 1; -#else - conf->orphan_move = 0; -#endif - } + dhd_conf_tput_improve(dhd); #ifdef DHD_TPUT_PATCH if (conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID || - conf->chip == BCM4375_CHIP_ID) { + conf->chip == BCM4375_CHIP_ID || conf->chip == BCM43756_CHIP_ID || + conf->chip == BCM43711_CHIP_ID || + conf->chip == BCM4381_CHIP_ID || conf->chip == BCM4382_CHIP_ID) { conf->tput_patch = TRUE; dhd_conf_set_tput_patch(dhd); } @@ -5150,35 +5606,7 @@ dhd_conf_reset(dhd_pub_t *dhd) { struct dhd_conf *conf = dhd->conf; -#ifdef SET_FWNV_BY_MAC - dhd_conf_free_mac_list(&conf->fw_by_mac); - dhd_conf_free_mac_list(&conf->nv_by_mac); -#endif - dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip); - dhd_conf_free_country_list(conf); - dhd_conf_free_mchan_list(conf); -#ifdef PKT_FILTER_SUPPORT - if (conf->magic_pkt_filter_add) { - kfree(conf->magic_pkt_filter_add); - conf->magic_pkt_filter_add = NULL; - } -#endif - if (conf->wl_preinit) { - kfree(conf->wl_preinit); - conf->wl_preinit = NULL; - } - if (conf->wl_suspend) { - kfree(conf->wl_suspend); - conf->wl_suspend = NULL; - } - if (conf->wl_resume) { - kfree(conf->wl_resume); - conf->wl_resume = NULL; - } - if (conf->vndr_ie_assocreq) { - kfree(conf->vndr_ie_assocreq); - conf->vndr_ie_assocreq = NULL; - } + dhd_conf_free_preinit(dhd); memset(conf, 0, sizeof(dhd_conf_t)); return 0; } @@ -5218,35 +5646,7 @@ dhd_conf_detach(dhd_pub_t *dhd) CONFIG_TRACE("Enter\n"); if (dhd->conf) { -#ifdef SET_FWNV_BY_MAC - dhd_conf_free_mac_list(&conf->fw_by_mac); - dhd_conf_free_mac_list(&conf->nv_by_mac); -#endif - dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip); - dhd_conf_free_country_list(conf); - dhd_conf_free_mchan_list(conf); -#ifdef PKT_FILTER_SUPPORT - if (conf->magic_pkt_filter_add) { - kfree(conf->magic_pkt_filter_add); - conf->magic_pkt_filter_add = NULL; - } -#endif - if (conf->wl_preinit) { - kfree(conf->wl_preinit); - conf->wl_preinit = NULL; - } - if (conf->wl_suspend) { - kfree(conf->wl_suspend); - conf->wl_suspend = NULL; - } - if (conf->wl_resume) { - kfree(conf->wl_resume); - conf->wl_resume = NULL; - } - if (conf->vndr_ie_assocreq) { - kfree(conf->vndr_ie_assocreq); - conf->vndr_ie_assocreq = NULL; - } + dhd_conf_free_preinit(dhd); MFREE(dhd->osh, conf, sizeof(dhd_conf_t)); } dhd->conf = NULL; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.h old mode 100755 new mode 100644 index 815e9c458b93..4e2595b7c9f5 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _dhd_config_ #define _dhd_config_ @@ -28,7 +27,7 @@ //#define CONFIG_PATH_AUTO_SELECT #endif extern char firmware_path[MOD_PARAM_PATHLEN]; -#if defined(BCMSDIO) || defined(BCMPCIE) +#if defined(BCMSDIO) extern uint dhd_rxbound; extern uint dhd_txbound; #endif @@ -68,12 +67,6 @@ typedef struct wl_chip_nv_path_list_ctrl { struct wl_chip_nv_path *m_chip_nv_path_head; } wl_chip_nv_path_list_ctrl_t; -#define MAX_CTRL_CHANSPECS 256 -typedef struct wl_channel_list { - uint32 count; - uint32 channel[MAX_CTRL_CHANSPECS]; -} wl_channel_list_t; - typedef struct wmes_param { int aifsn[AC_COUNT]; int ecwmin[AC_COUNT]; @@ -126,7 +119,8 @@ enum war_flags { FW_REINIT_INCSA = (1 << (1)), FW_REINIT_EMPTY_SCAN = (1 << (2)), P2P_AP_MAC_CONFLICT = (1 << (3)), - RESEND_EAPOL_PKT = (1 << (4)) + RESEND_EAPOL_PKT = (1 << (4)), + FW_REINIT_RXF0OVFL = (1 << (5)) }; enum in4way_flags { @@ -171,25 +165,27 @@ enum conn_state { CONN_STATE_AUTH_SAE_M2 = 3, CONN_STATE_AUTH_SAE_M3 = 4, CONN_STATE_AUTH_SAE_M4 = 5, - CONN_STATE_REQID = 6, - CONN_STATE_RSPID = 7, - CONN_STATE_WSC_START = 8, - CONN_STATE_WPS_M1 = 9, - CONN_STATE_WPS_M2 = 10, - CONN_STATE_WPS_M3 = 11, - CONN_STATE_WPS_M4 = 12, - CONN_STATE_WPS_M5 = 13, - CONN_STATE_WPS_M6 = 14, - CONN_STATE_WPS_M7 = 15, - CONN_STATE_WPS_M8 = 16, - CONN_STATE_WSC_DONE = 17, - CONN_STATE_4WAY_M1 = 18, - CONN_STATE_4WAY_M2 = 19, - CONN_STATE_4WAY_M3 = 20, - CONN_STATE_4WAY_M4 = 21, - CONN_STATE_CONNECTED = 22, - CONN_STATE_GROUPKEY_M1 = 23, - CONN_STATE_GROUPKEY_M2 = 24, + CONN_STATE_ASSOCIATED = 6, + CONN_STATE_REQID = 7, + CONN_STATE_RSPID = 8, + CONN_STATE_WSC_START = 9, + CONN_STATE_WPS_M1 = 10, + CONN_STATE_WPS_M2 = 11, + CONN_STATE_WPS_M3 = 12, + CONN_STATE_WPS_M4 = 13, + CONN_STATE_WPS_M5 = 14, + CONN_STATE_WPS_M6 = 15, + CONN_STATE_WPS_M7 = 16, + CONN_STATE_WPS_M8 = 17, + CONN_STATE_WSC_DONE = 18, + CONN_STATE_4WAY_M1 = 19, + CONN_STATE_4WAY_M2 = 20, + CONN_STATE_4WAY_M3 = 21, + CONN_STATE_4WAY_M4 = 22, + CONN_STATE_ADD_KEY = 23, + CONN_STATE_CONNECTED = 24, + CONN_STATE_GROUPKEY_M1 = 25, + CONN_STATE_GROUPKEY_M2 = 26, }; enum enq_pkt_type { @@ -218,10 +214,10 @@ typedef struct dhd_conf { #endif wl_chip_nv_path_list_ctrl_t nv_by_chip; country_list_t *country_head; + int ioctl_ver; int band; int bw_cap[2]; wl_country_t cspec; - wl_channel_list_t channels; uint roam_off; uint roam_off_suspend; int roam_trigger[2]; @@ -297,6 +293,8 @@ typedef struct dhd_conf { int d2h_intr_method; int d2h_intr_control; int enq_hdr_pkt; + int aspm; + int l1ss; #endif int dpc_cpucore; int rxf_cpucore; @@ -345,6 +343,9 @@ typedef struct dhd_conf { uint war; #ifdef WL_EXT_WOWL uint wowl; +#ifdef BCMDBUS + uint wowl_dngldown; +#endif #endif #ifdef GET_CUSTOM_MAC_FROM_CONFIG char hw_ether[62]; @@ -395,23 +396,27 @@ void dhd_conf_get_otp(dhd_pub_t *dhd, bcmsdh_info_t *sdh, si_t *sih); void dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, struct si_pub *sih); #endif void dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable); +bool dhd_conf_legacy_otp_chip(dhd_pub_t *dhd); #endif #ifdef BCMPCIE int dhd_conf_get_otp(dhd_pub_t *dhd, si_t *sih); bool dhd_conf_legacy_msi_chip(dhd_pub_t *dhd); #endif +#ifdef WL_CFG80211 +bool dhd_conf_legacy_chip_check(dhd_pub_t *dhd); +bool dhd_conf_new_chip_check(dhd_pub_t *dhd); +bool dhd_conf_extsae_chip(dhd_pub_t *dhd); +#endif void dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path); int dhd_conf_set_intiovar(dhd_pub_t *dhd, int ifidx, uint cmd, char *name, int val, int def, bool down); int dhd_conf_get_band(dhd_pub_t *dhd); -int dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec); +bool dhd_conf_same_country(dhd_pub_t *dhd, char *buf); +int dhd_conf_country(dhd_pub_t *dhd, char *cmd, char *buf); int dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec); -int dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec); #ifdef CCODE_LIST int dhd_ccode_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec); #endif -int dhd_conf_fix_country(dhd_pub_t *dhd); -bool dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel); void dhd_conf_set_wme(dhd_pub_t *dhd, int ifidx, int mode); void dhd_conf_set_mchan_bw(dhd_pub_t *dhd, int go, int source); void dhd_conf_add_pkt_filter(dhd_pub_t *dhd); @@ -422,6 +427,7 @@ int dhd_conf_set_chiprev(dhd_pub_t *dhd, uint chip, uint chiprev); uint dhd_conf_get_chip(void *context); uint dhd_conf_get_chiprev(void *context); int dhd_conf_get_pm(dhd_pub_t *dhd); +int dhd_conf_reg2args(dhd_pub_t *dhd, char *cmd, bool set, uint32 index, uint32 *val); int dhd_conf_check_hostsleep(dhd_pub_t *dhd, int cmd, void *buf, int len, int *hostsleep_set, int *hostsleep_val, int *ret); void dhd_conf_get_hostsleep(dhd_pub_t *dhd, @@ -440,6 +446,7 @@ void dhd_conf_tput_monitor(dhd_pub_t *dhd); uint dhd_conf_get_insuspend(dhd_pub_t *dhd, uint mask); int dhd_conf_set_suspend_resume(dhd_pub_t *dhd, int suspend); void dhd_conf_postinit_ioctls(dhd_pub_t *dhd); +void dhd_conf_preinit_ioctls_sta(dhd_pub_t *dhd, int ifidx); int dhd_conf_preinit(dhd_pub_t *dhd); int dhd_conf_reset(dhd_pub_t *dhd); int dhd_conf_attach(dhd_pub_t *dhd); @@ -449,7 +456,10 @@ int wl_pattern_atoh(char *src, char *dst); int dhd_conf_suspend_resume_sta(dhd_pub_t *dhd, int ifidx, int suspend); /* Add to adjust 802.1x priority */ extern void pktset8021xprio(void *pkt, int prio); -#ifdef BCMSDIO +#if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS) extern int dhd_bus_sleep(dhd_pub_t *dhdp, bool sleep, uint32 *intstatus); #endif +#ifdef WL_EXT_WOWL +int dhd_conf_wowl_dngldown(dhd_pub_t *dhd); +#endif #endif /* _dhd_config_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_csi.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_csi.c old mode 100755 new mode 100644 index 5cacb9c80365..aa243a3c2aa5 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_csi.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_csi.c @@ -1,7 +1,7 @@ /* - * Broadcom Dongle Host Driver (DHD) + * Broadcom Dongle Host Driver (DHD), Channel State information Module * - * Copyright (C) 1999-2018, Broadcom. + * Copyright (C) 2023, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -17,12 +17,13 @@ * derived from this software. The special exception does not apply to any * modifications of the software. * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_csi.c 606280 2015-12-15 05:28:25Z $ + * <> + * + * $Id$ */ + +#ifdef CSI_SUPPORT #include #include @@ -38,182 +39,789 @@ #include #include #include +#include +#include -#define NULL_CHECK(p, s, err) \ - do { \ - if (!(p)) { \ - printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ - err = BCME_ERROR; \ - return err; \ - } \ - } while (0) +#define SYNA_ALIGN_BYTES (sizeof(uint32)) +#define SYNA_ALIGN_PADDING (SYNA_ALIGN_BYTES -1LL) +#define SYNA_ALIGN_MASK (~SYNA_ALIGN_PADDING) +#define SYNA_ALIGN(value) \ +(\ + (SYNA_ALIGN_PADDING + ((long long int)(value))) \ + & SYNA_ALIGN_MASK \ +) -#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \ - (ts).tv_nsec / NSEC_PER_USEC) +static const uint8 _gpMAC_zero[6] = {0, 0, 0, 0, 0, 0}; -#define NULL_ADDR "\x00\x00\x00\x00\x00\x00" - -int -dhd_csi_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) +static int dhd_csi_data_append(uint32 remain_length, uint32 data_length, + const uint8 *pData, struct csi_cfr_node *ptr) { - int ret = BCME_OK; - bool is_new = TRUE; - cfr_dump_data_t *p_event; - cfr_dump_list_t *ptr, *next, *new; + struct syna_csi_header *pEntry = NULL; + int error_status = 0; + int ret = BCME_OK; + int append_len = 0; - NULL_CHECK(dhd, "dhd is NULL", ret); + if ((!pData) || (!ptr) || (ptr->pNode != ptr)) { + DHD_ERROR(("%s-%d: *Error, invalid parameter, " + "pData=0x%px, ptr=0x%px, pNode=0x%px\n", + __func__, __LINE__, + pData, ptr, ptr?(ptr->pNode):(NULL))); + ret = BCME_BADARG; + goto done; + } else { + pEntry = (struct syna_csi_header *)&(ptr->entry); + error_status = SYNA_CSI_FLAG_ERROR_MASK & pEntry->flags; + } + /* find the append length */ + if (remain_length) { + append_len = data_length + - pEntry->data_length + - remain_length; + } else if (pEntry->remain_length) { + append_len = pEntry->remain_length; + } else if (SYNA_CSI_CFR_NODE_FREE_LEN(ptr) >= data_length) { + append_len = data_length; + } - DHD_TRACE(("Enter %s\n", __FUNCTION__)); + DHD_TRACE(("%s-%d: data_length=%d, remain=%d, append=%d " + "pNode: pEntry=0x%px, global_id=%d, flags=0x%x, " + "data_len=%d, remain_len=%d, copied_len=%d\n", + __func__, __LINE__, + data_length, remain_length, append_len, + pEntry, pEntry->global_id, pEntry->flags, + pEntry->data_length, + pEntry->remain_length, pEntry->copied_length)); + + /* copy and update */ + if (append_len) { + memcpy((pEntry->data_length + ((uint8 *)pEntry->data)), + pData, append_len); + pEntry->data_length += append_len; + + if ((!error_status) + && (!remain_length) + && (pEntry->checksum)) { + uint16 checksum = 0; + uint i; + pData = (uint8 *)pEntry->data; + for (i = 0; i < data_length; i++) { + checksum += pData[i]; + } + if (checksum != pEntry->checksum) { + DHD_ERROR(("%s-%d: *Error, global_id=%d, " + "checksum=0x%X mismatch to FW=0x%X, " + "data_length=%d, remain_length=%d, " + "pData=0x%px\n", + __func__, __LINE__, + pEntry->global_id, + checksum, pEntry->checksum, + data_length, remain_length, pData)); + pEntry->flags |= SYNA_CSI_FLAG_ERROR_CHECKSUM; + } + } + } else if (!error_status) { + DHD_ERROR(("%s-%d: *Error, no data append, " + "total_size=%d, free_len=%d, " + "in_data_length=%d, in_remain_length=%d, " + " Node: global_id=%d, flags=0x%X, " + "data_length=%d, remain_length=%d\n", + __func__, __LINE__, + ptr->total_size, + (int)SYNA_CSI_CFR_NODE_FREE_LEN(ptr), + data_length, remain_length, + pEntry->global_id, pEntry->flags, + pEntry->data_length, pEntry->remain_length)); + } else { + DHD_ERROR(("%s-%d: *Warning, error report frame, " + "size=%d, free=%d, " + "in_data_length=%d, in_remain_length=%d, " + " Node: global_id=%d, flags=0x%X%s, " + "data_length=%d, remain_length=%d\n", + __func__, __LINE__, + ptr->total_size, + (int)SYNA_CSI_CFR_NODE_FREE_LEN(ptr), + data_length, remain_length, + pEntry->global_id, pEntry->flags, + (SYNA_CSI_FLAG_ERROR_CHECKSUM & pEntry->flags) + ? "(error_checksum)" + : (SYNA_CSI_FLAG_ERROR_NO_ACK & pEntry->flags) + ? "(error_no_ack)" + : (SYNA_CSI_FLAG_ERROR_READ & pEntry->flags) + ? "(error_read)" + : (SYNA_CSI_FLAG_ERROR_PS & pEntry->flags) + ? "(error_ps)" + : (SYNA_CSI_FLAG_ERROR_GENERIC & pEntry->flags) + ? "(error_generic)" + : "", + pEntry->data_length, pEntry->remain_length)); + } + + /* make this as final step to avoid packet early retrieved */ + pEntry->copied_length = 0; + pEntry->remain_length = remain_length; + + ret = append_len; + +done: + return ret; +} + +static int dhd_csi_data_new_v0(dhd_pub_t *dhdp, const wl_event_msg_t *event, + struct dhd_cfr_header_v0 *pEvent) +{ + struct csi_cfr_node *ptr = NULL; + struct syna_csi_header *pEntry = NULL; + struct timespec64 ts; + dhd_if_t *ifp = NULL; + int ret = BCME_ERROR; + uint total_size = 0; + u32 chanspec = 0; + uint32 remain_length = 0; + uint32 data_length = 0; + uint8 *pData = NULL; + + ktime_get_real_ts64(&ts); + total_size = SYNA_CSI_CFR_NODE_LEN + ltoh32_ua(&(pEvent->cfr_dump_length)); + + ptr = (struct csi_cfr_node *)MALLOCZ(dhdp->osh, total_size); + if (!ptr) { + DHD_ERROR(("%s-%d: *Error, malloc %d for cfr dump list error\n", + __func__, __LINE__, total_size)); + return BCME_NOMEM; + } + ptr->pNode = ptr; /* Not useful */ + ptr->total_size = total_size; + pEntry = &(ptr->entry); + + DHD_TRACE(("%s-%d: ptr=0x%p, ptr=0x%px, pEntry=0x%px, " + "delta=%d, header_size=%d\n", + __func__, __LINE__, ptr, ptr, pEntry, + (int)((uintptr)pEntry - (uintptr)ptr), + (int)SYNA_CSI_CFR_NODE_LEN)); + + /* process one by one for alignment consideration */ + pEntry->magic_flag = CONST_SYNA_CSI_MAGIC_FLAG; + pEntry->version = CONST_SYNA_CSI_COMMON_HEADER_VERSION; + pEntry->format_type = SYNA_CSI_FORMAT_Q8; + pEntry->fc = 0; + if (pEvent->status) { + pEntry->flags |= SYNA_CSI_FLAG_ERROR_GENERIC; + } + memcpy(pEntry->client_ea, pEvent->peer_macaddr, ETHER_ADDR_LEN); + + ifp = dhd_get_ifp(dhdp, event->ifidx); + if (!ifp) { + DHD_ERROR(("%s-%d: *Error, get ifp error\n", + __func__, __LINE__)); + } else { + memcpy(pEntry->bsscfg_ea, ifp->mac_addr, ETHER_ADDR_LEN); + } + + if ((ret = dhd_iovar(dhdp, event->ifidx, "chanspec", + NULL, 0, (char*)&chanspec, + sizeof(chanspec), FALSE) != BCME_OK)) { + pEntry->band = SYNA_CSI_BAND_UNKNOWN; + pEntry->bandwidth = SYNA_CSI_BW_UNKNOWN; + pEntry->channel = 0; + } else { + switch (CHSPEC_BAND(chanspec)) { + case WL_CHANSPEC_BAND_2G: + pEntry->band = SYNA_CSI_BAND_2G; + break; + case WL_CHANSPEC_BAND_5G: + pEntry->band = SYNA_CSI_BAND_5G; + break; + case WL_CHANSPEC_BAND_6G: + pEntry->band = SYNA_CSI_BAND_6G; + break; + default: + pEntry->band = SYNA_CSI_BAND_UNKNOWN; + break; + } + + switch (CHSPEC_BW(chanspec)) { + case WL_CHANSPEC_BW_20: + pEntry->bandwidth = SYNA_CSI_BW_20MHz; + break; + case WL_CHANSPEC_BW_40: + pEntry->bandwidth = SYNA_CSI_BW_40MHz; + break; + case WL_CHANSPEC_BW_80: + pEntry->bandwidth = SYNA_CSI_BW_80MHz; + break; + case WL_CHANSPEC_BW_160: + pEntry->bandwidth = SYNA_CSI_BW_160MHz; + break; + case WL_CHANSPEC_BW_320: + pEntry->bandwidth = SYNA_CSI_BW_320MHz; + break; + default: + pEntry->bandwidth = SYNA_CSI_BAND_UNKNOWN; + break; + } + + pEntry->channel = CHSPEC_CHANNEL(chanspec); + } + + pEntry->num_txstream = pEvent->sts; + pEntry->num_rxchain = pEvent->num_rx; + pEntry->num_subcarrier = ltoh16_ua(&(pEvent->num_carrier)); + pEntry->report_tsf = (uint64)TIMESPEC64_TO_US(ts); + pEntry->rssi = pEvent->rssi; + pEntry->data_length = 0; + pEntry->remain_length = 0; + pEntry->copied_length = 0; + + DHD_TRACE(("%s-%d: Entry data_size=%d, remain_size=%d, @%llu\n", + __func__, __LINE__, + ltoh32_ua(&(pEvent->cfr_dump_length)), + ltoh32_ua(&(pEvent->remain_length)), + ltoh64_ua(&(pEntry->report_tsf)))); + + remain_length = ltoh32_ua(&(pEvent->remain_length)); + data_length = ltoh32_ua(&(pEvent->cfr_dump_length)); + pData = (uint8 *)pEvent->data; + ret = dhd_csi_data_append(remain_length, data_length, pData, ptr); + if (0 <= ret) { + INIT_LIST_HEAD(&(ptr->list)); + mutex_lock(&dhdp->csi_lock); + list_add_tail(&(ptr->list), &dhdp->csi_list); + dhdp->csi_count++; + mutex_unlock(&dhdp->csi_lock); + } else { + MFREE(dhdp->osh, ptr, total_size); + } + + return ret; +} + +static int dhd_csi_data_new_v1(dhd_pub_t *dhdp, const wl_event_msg_t *event, + struct dhd_cfr_header_v1 *pEvent) +{ + struct csi_cfr_node *ptr = NULL; + struct syna_csi_header *pEntry = NULL; + dhd_if_t *ifp = NULL; + int ret = BCME_ERROR; + uint total_size = 0; + u32 chanspec = 0; + uint32 remain_length = 0; + uint32 data_length = 0; + uint8 *pData = NULL; + + total_size = SYNA_CSI_CFR_NODE_LEN + ltoh32_ua(&(pEvent->cfr_dump_length)); + + ptr = (struct csi_cfr_node *)MALLOCZ(dhdp->osh, total_size); + if (!ptr) { + DHD_ERROR(("%s-%d: *Error, malloc %d for cfr dump list error\n", + __func__, __LINE__, total_size)); + return BCME_NOMEM; + } + ptr->pNode = ptr; /* Not useful */ + ptr->total_size = total_size; + pEntry = &(ptr->entry); + + DHD_TRACE(("%s-%d: ptr=0x%p, ptr=0x%px, pEntry=0x%px, " + "delta=%d, header_size=%d\n", + __func__, __LINE__, ptr, ptr, pEntry, + (int)((uintptr)pEntry - (uintptr)ptr), + (int)SYNA_CSI_CFR_NODE_LEN)); + + /* process one by one for alignment consideration */ + pEntry->magic_flag = CONST_SYNA_CSI_MAGIC_FLAG; + pEntry->version = CONST_SYNA_CSI_COMMON_HEADER_VERSION; + pEntry->format_type = SYNA_CSI_FORMAT_Q8; + pEntry->fc = pEvent->fc; + if (pEvent->status) { + pEntry->flags |= SYNA_CSI_FLAG_ERROR_GENERIC; + } + + memcpy(pEntry->client_ea, pEvent->peer_macaddr, ETHER_ADDR_LEN); + + ifp = dhd_get_ifp(dhdp, event->ifidx); + + if (!ifp) { + DHD_ERROR(("%s-%d: *Error, get ifp error\n", + __func__, __LINE__)); + } else { + memcpy(pEntry->bsscfg_ea, ifp->mac_addr, ETHER_ADDR_LEN); + } + + if ((ret = dhd_iovar(dhdp, event->ifidx, "chanspec", + NULL, 0, (char*)&chanspec, sizeof(chanspec), FALSE) != BCME_OK)) { + pEntry->band = SYNA_CSI_BAND_UNKNOWN; + pEntry->bandwidth = SYNA_CSI_BW_UNKNOWN; + pEntry->channel = 0; + } else { + switch (CHSPEC_BAND(chanspec)) { + case WL_CHANSPEC_BAND_2G: + pEntry->band = SYNA_CSI_BAND_2G; + break; + case WL_CHANSPEC_BAND_5G: + pEntry->band = SYNA_CSI_BAND_5G; + break; + case WL_CHANSPEC_BAND_6G: + pEntry->band = SYNA_CSI_BAND_6G; + break; + default: + pEntry->band = SYNA_CSI_BAND_UNKNOWN; + break; + } + + switch (CHSPEC_BW(chanspec)) { + case WL_CHANSPEC_BW_20: + pEntry->bandwidth = SYNA_CSI_BW_20MHz; + break; + case WL_CHANSPEC_BW_40: + pEntry->bandwidth = SYNA_CSI_BW_40MHz; + break; + case WL_CHANSPEC_BW_80: + pEntry->bandwidth = SYNA_CSI_BW_80MHz; + break; + case WL_CHANSPEC_BW_160: + pEntry->bandwidth = SYNA_CSI_BW_160MHz; + break; + case WL_CHANSPEC_BW_320: + pEntry->bandwidth = SYNA_CSI_BW_320MHz; + break; + default: + pEntry->bandwidth = SYNA_CSI_BAND_UNKNOWN; + break; + } + + pEntry->channel = CHSPEC_CHANNEL(chanspec); + } + + pEntry->num_txstream = pEvent->sts; + pEntry->num_rxchain = pEvent->num_rx; + pEntry->num_subcarrier = ltoh16_ua(&(pEvent->num_carrier)); + pEntry->report_tsf = ltoh64_ua(&(pEvent->cfr_timestamp)); + pEntry->rssi = pEvent->rssi; + pEntry->data_length = 0; + pEntry->remain_length = 0; + pEntry->copied_length = 0; + + DHD_TRACE(("%s-%d: Entry data_size=%d, remain_size=%d, @%llu\n", + __func__, __LINE__, + ltoh32_ua(&(pEvent->cfr_dump_length)), + ltoh32_ua(&(pEvent->remain_length)), + ltoh64_ua(&(pEntry->report_tsf)))); + + remain_length = ltoh32_ua(&(pEvent->remain_length)); + data_length = ltoh32_ua(&(pEvent->cfr_dump_length)); + pData = (uint8 *)pEvent->data; + ret = dhd_csi_data_append(remain_length, data_length, pData, ptr); + if (0 <= ret) { + INIT_LIST_HEAD(&(ptr->list)); + mutex_lock(&dhdp->csi_lock); + list_add_tail(&(ptr->list), &dhdp->csi_list); + dhdp->csi_count++; + mutex_unlock(&dhdp->csi_lock); + } else { + MFREE(dhdp->osh, ptr, total_size); + } + + return ret; +} + +static int dhd_csi_data_new_v2(dhd_pub_t *dhdp, const wl_event_msg_t *event, + struct dhd_cfr_header_v2 *pEvent) +{ + struct csi_cfr_node *ptr = NULL; + struct syna_csi_header *pEntry = NULL; + int ret = BCME_ERROR; + uint total_size = 0; + uint32 remain_length = 0; + uint32 data_length = 0; + uint8 *pData = NULL; + + if (SYNA_ALIGN_PADDING & (uintptr)pEvent) { + DHD_ERROR(("%s-%d: *Error, pEvent=0x%px is not aligned!", + __func__, __LINE__, pEvent)); + } + + total_size = SYNA_CSI_CFR_NODE_LEN + pEvent->data_length; + + ptr = (struct csi_cfr_node *)MALLOCZ(dhdp->osh, total_size); + if (!ptr) { + DHD_ERROR(("%s-%d: *Error, malloc %d for cfr dump list error\n", + __func__, __LINE__, total_size)); + return BCME_NOMEM; + } + ptr->pNode = ptr; /* Not useful */ + ptr->total_size = total_size; + pEntry = &(ptr->entry); + + DHD_TRACE(("%s-%d: ptr=0x%p, ptr=0x%px, pEntry=0x%px, " + "delta=%d, header_size=%d\n", + __func__, __LINE__, ptr, ptr, pEntry, + (int)((uintptr)pEntry - (uintptr)ptr), + (int)SYNA_CSI_CFR_NODE_LEN)); + + /* process one by one for alignment consideration */ + memcpy(pEntry, pEvent, sizeof(struct syna_csi_header)); + pEntry->magic_flag = CONST_SYNA_CSI_MAGIC_FLAG; + pEntry->version = CONST_SYNA_CSI_COMMON_HEADER_VERSION; + + if ((pEvent->status_compat) + && (!(SYNA_CSI_FLAG_ERROR_MASK & pEntry->flags))) { + pEntry->flags |= SYNA_CSI_FLAG_ERROR_GENERIC; + DHD_ERROR(("%s-%d: *Warning, status=0x%X, " + " global_id=%d!\n", + __func__, __LINE__, + pEvent->status_compat, + pEvent->global_id)); + } + if (!pEntry->format_type) { + pEntry->format_type = SYNA_CSI_FORMAT_Q8; + } + if (!memcmp(_gpMAC_zero, pEntry->bsscfg_ea, ETHER_ADDR_LEN)) { + dhd_if_t *ifp = dhd_get_ifp(dhdp, event->ifidx); + if (!ifp) { + DHD_ERROR(("%s-%d: *Error, get ifp error\n", + __func__, __LINE__)); + } else { + memcpy(pEntry->bsscfg_ea, ifp->mac_addr, ETHER_ADDR_LEN); + } + } + + if (!pEntry->report_tsf) { + struct timespec64 ts; + ktime_get_real_ts64(&ts); + pEntry->report_tsf = (uint64)TIMESPEC64_TO_US(ts); + } + + pEntry->data_length = 0; + pEntry->remain_length = 0; + pEntry->copied_length = 0; + pEntry->checksum = pEvent->checksum; + + DHD_TRACE(("%s-%d: Entry data_size=%d, remain_size=%d, @%llu\n", + __func__, __LINE__, + pEvent->data_length, + pEvent->remain_length, + pEntry->report_tsf)); + + remain_length = pEvent->remain_length; + data_length = pEvent->data_length; + pData = (uint8 *)pEvent->data; + ret = dhd_csi_data_append(remain_length, data_length, pData, ptr); + if (0 <= ret) { + INIT_LIST_HEAD(&(ptr->list)); + mutex_lock(&dhdp->csi_lock); + list_add_tail(&(ptr->list), &dhdp->csi_list); + dhdp->csi_count++; + mutex_unlock(&dhdp->csi_lock); + } else { + MFREE(dhdp->osh, ptr, total_size); + } + + return ret; +} + +int dhd_csi_event_handler(dhd_pub_t *dhdp, const wl_event_msg_t *event, void *event_data) +{ + union dhd_cfr_header *pEvent = NULL; + struct csi_cfr_node *ptr = NULL, *next = NULL, *save_ptr = NULL; + const uint8 *pMAC = NULL, *pData = NULL; + uint8 version = 0xff; + uint32 data_length = 0, remain_length = 0, header_length = 0; + int ret = BCME_OK; + + NULL_CHECK(dhdp, "dhdp is NULL", ret); + + DHD_TRACE(("%s-%d: Enter\n", __func__, __LINE__)); if (!event_data) { - DHD_ERROR(("%s: event_data is NULL\n", __FUNCTION__)); - return -EINVAL; + DHD_ERROR(("%s-%d: event_data is NULL\n", + __func__, __LINE__)); + ret = BCME_BADARG; + goto done; } - p_event = (cfr_dump_data_t *)event_data; + pEvent = (union dhd_cfr_header *)event_data; + if (pEvent->header_v0.status) { + DHD_ERROR(("%s-%d: *Warning, status=0x%X " + " may indicate error!\n", + __func__, __LINE__, + pEvent->header_v0.status)); + /* TODO: do need to abandon this scenario? */ + } + + version = pEvent->header_v0.version; + switch (version) { + case CSI_VERSION_V0: + pMAC = pEvent->header_v0.peer_macaddr; + header_length = sizeof(struct dhd_cfr_header_v0); + remain_length = ltoh32_ua(&(pEvent->header_v0.remain_length)); + data_length = ltoh32_ua(&(pEvent->header_v0.cfr_dump_length)); + pData = (uint8 *)pEvent->header_v0.data; + break; + case CSI_VERSION_V1: + pMAC = pEvent->header_v1.peer_macaddr; + header_length = sizeof(struct dhd_cfr_header_v1); + remain_length = ltoh32_ua(&(pEvent->header_v1.remain_length)); + data_length = ltoh32_ua(&(pEvent->header_v1.cfr_dump_length)); + pData = (uint8 *)pEvent->header_v1.data; + break; + case CSI_VERSION_V2: + pMAC = pEvent->header_v2.client_ea; + header_length = sizeof(struct dhd_cfr_header_v2); + remain_length = pEvent->header_v2.remain_length; + data_length = pEvent->header_v2.data_length; + pData = (uint8 *)pEvent->header_v2.data; + break; + default: + DHD_ERROR(("%s-%d: CSI version=%d error\n", + __func__, __LINE__, version)); + ret = BCME_BADOPTION; + goto done; + break; + } + + if (header_length <= remain_length) { + remain_length -= header_length; + } + if (CONST_CSI_MAXIMUM_DATA_BYTES < remain_length) { + DHD_ERROR(("%s-%d: *Error, drop too big length, " + "global_id=%d, version=%d, status=%d, " + "data_length=%d(0x%X), remain_length=%d(0x%X) > %d\n", + __func__, __LINE__, + pEvent->header_v2.global_id, + version, pEvent->header_v2.status_compat, + data_length, data_length, + remain_length, remain_length, + (int)CONST_CSI_MAXIMUM_DATA_BYTES)); + prhex("TOO_BIG_LENGTH", (uchar *)pEvent, 128); + ret = BCME_BADLEN; + goto done; + } + + mutex_lock(&dhdp->csi_lock); /* check if this addr exist */ - if (!list_empty(&dhd->csi_list)) { - list_for_each_entry_safe(ptr, next, &dhd->csi_list, list) { - if (bcmp(&ptr->entry.header.peer_macaddr, &p_event->header.peer_macaddr, - ETHER_ADDR_LEN) == 0) { - int pos = 0, dump_len = 0, remain = 0; - is_new = FALSE; - DHD_INFO(("CSI data exist\n")); - if (p_event->header.status == 0) { - bcopy(&p_event->header, &ptr->entry.header, sizeof(cfr_dump_header_t)); - dump_len = p_event->header.cfr_dump_length; - if (dump_len < MAX_EVENT_SIZE) { - bcopy(&p_event->data, &ptr->entry.data, dump_len); - } else { - /* for big csi data */ - uint8 *p = (uint8 *)&ptr->entry.data; - remain = p_event->header.remain_length; - if (remain) { - pos = dump_len - remain - MAX_EVENT_SIZE; - p += pos; - bcopy(&p_event->data, p, MAX_EVENT_SIZE); - } - /* copy rest of csi data */ - else { - pos = dump_len - (dump_len % MAX_EVENT_SIZE); - p += pos; - bcopy(&p_event->data, p, (dump_len % MAX_EVENT_SIZE)); - } - } - return BCME_OK; + if (!list_empty(&dhdp->csi_list)) { + list_for_each_entry_safe(ptr, next, &dhdp->csi_list, list) { + struct syna_csi_header *pEntry = &(ptr->entry); + /* check if is new */ + if (bcmp(&pEntry->client_ea, pMAC, ETHER_ADDR_LEN) == 0) { + if (pEntry->remain_length > 0) { + save_ptr = ptr; + break; } } } } - if (is_new) { - if (dhd->csi_count < MAX_CSI_NUM) { - new = (cfr_dump_list_t *)MALLOCZ(dhd->osh, sizeof(cfr_dump_list_t)); - if (!new){ - DHD_ERROR(("Malloc cfr dump list error\n")); - return BCME_NOMEM; - } - bcopy(&p_event->header, &new->entry.header, sizeof(cfr_dump_header_t)); - DHD_INFO(("New entry data size %d\n", p_event->header.cfr_dump_length)); - /* for big csi data */ - if (p_event->header.remain_length) { - DHD_TRACE(("remain %d\n", p_event->header.remain_length)); - bcopy(&p_event->data, &new->entry.data, MAX_EVENT_SIZE); - } - else - bcopy(&p_event->data, &new->entry.data, p_event->header.cfr_dump_length); - INIT_LIST_HEAD(&(new->list)); - list_add_tail(&(new->list), &dhd->csi_list); - dhd->csi_count++; - } - else { - DHD_TRACE(("Over maximum CSI Number 8. SKIP it.\n")); - } + /* check if need to drop head packet */ + if ((!save_ptr) && (dhdp->csi_count >= MAX_CSI_BUF_NUM)) { + DHD_ERROR(("%s-%d: CSI data is full, drop pkt \n", + __func__, __LINE__)); + ptr = list_first_entry(&dhdp->csi_list, struct csi_cfr_node, list); + list_del_init(&ptr->list); + MFREE(dhdp->osh, ptr, ptr->total_size); + dhdp->csi_count--; } + mutex_unlock(&dhdp->csi_lock); + + /* try to append new node if needs */ + DHD_TRACE(("%s-%d: save_ptr=0x%px, version=%d\n", + __func__, __LINE__, save_ptr, version)); + if (!save_ptr) { + switch (version) { + case CSI_VERSION_V0: + ret = dhd_csi_data_new_v0(dhdp, event, &(pEvent->header_v0)); + break; + case CSI_VERSION_V1: + ret = dhd_csi_data_new_v1(dhdp, event, &(pEvent->header_v1)); + break; + case CSI_VERSION_V2: + ret = dhd_csi_data_new_v2(dhdp, event, &(pEvent->header_v2)); + break; + default: + DHD_ERROR(("%s-%d: CSI version=%d error\n", + __func__, __LINE__, version)); + ret = BCME_BADOPTION; + goto done; + break; + } + } else { + ret = dhd_csi_data_append(remain_length, data_length, pData, save_ptr); + } + +done: return ret; } -int -dhd_csi_init(dhd_pub_t *dhd) +static void +dhd_csi_clean_list(dhd_pub_t *dhdp) { - int err = BCME_OK; - - NULL_CHECK(dhd, "dhd is NULL", err); - INIT_LIST_HEAD(&dhd->csi_list); - dhd->csi_count = 0; - - return err; -} - -int -dhd_csi_deinit(dhd_pub_t *dhd) -{ - int err = BCME_OK; - cfr_dump_list_t *ptr, *next; - - NULL_CHECK(dhd, "dhd is NULL", err); - - if (!list_empty(&dhd->csi_list)) { - list_for_each_entry_safe(ptr, next, &dhd->csi_list, list) { - list_del(&ptr->list); - MFREE(dhd->osh, ptr, sizeof(cfr_dump_list_t)); - } - } - return err; -} - -void -dhd_csi_clean_list(dhd_pub_t *dhd) -{ - cfr_dump_list_t *ptr, *next; + struct csi_cfr_node *ptr, *next; int num = 0; - if (!dhd) { - DHD_ERROR(("NULL POINTER: %s\n", __FUNCTION__)); + if (!dhdp) { + DHD_ERROR(("%s-%d: *Error, NULL POINTER\n", + __func__, __LINE__)); return; } - if (!list_empty(&dhd->csi_list)) { - list_for_each_entry_safe(ptr, next, &dhd->csi_list, list) { - if (0 == ptr->entry.header.remain_length) { - list_del(&ptr->list); - num++; - MFREE(dhd->osh, ptr, sizeof(cfr_dump_list_t)); - } + mutex_lock(&dhdp->csi_lock); + if (!list_empty(&dhdp->csi_list)) { + list_for_each_entry_safe(ptr, next, &dhdp->csi_list, list) { + list_del(&ptr->list); + num++; + MFREE(dhdp->osh, ptr, ptr->total_size); } } - dhd->csi_count = 0; - DHD_TRACE(("Clean up %d record\n", num)); + dhdp->csi_count = 0; + mutex_unlock(&dhdp->csi_lock); + + DHD_TRACE(("%s-%d: Clean up %d record\n", + __func__, __LINE__, num)); +} + +int dhd_csi_config(dhd_pub_t *dhdp, char *pBuf, uint length, bool is_set) +{ + int ret = BCME_OK; + + if ((!dhdp) || (!pBuf) || (sizeof(uint32) > length)) { + DHD_ERROR(("%s-%d: *Error, Bad argument\n", + __func__, __LINE__)); + ret = BCME_BADARG; + goto done; + } + + if (is_set) { + uint value = *((uint *)pBuf); + if (SYNA_CSI_DATA_MODE_LAST <= value) { + ret = BCME_BADOPTION; + goto done; + } else if (SYNA_CSI_DATA_MODE_NONE != value) { + dhdp->csi_data_send_manner = value; + dhd_csi_clean_list(dhdp); + } + } else { + memcpy(pBuf, &dhdp->csi_data_send_manner, sizeof(uint32)); + } + +done: + return ret; +} + +int dhd_csi_init(dhd_pub_t *dhdp) +{ + int err = BCME_OK; + + mutex_init(&dhdp->csi_lock); + mutex_lock(&dhdp->csi_lock); + NULL_CHECK(dhdp, "dhdp is NULL", err); + INIT_LIST_HEAD(&dhdp->csi_list); + dhdp->csi_count = 0; + mutex_unlock(&dhdp->csi_lock); + + return err; } int -dhd_csi_dump_list(dhd_pub_t *dhd, char *buf) +dhd_csi_deinit(dhd_pub_t *dhdp) { - int ret = BCME_OK; - cfr_dump_list_t *ptr, *next; - uint8 * pbuf = buf; - int num = 0; - int length = 0; + int err = BCME_OK; - NULL_CHECK(dhd, "dhd is NULL", ret); + NULL_CHECK(dhdp, "dhdp is NULL", err); - /* check if this addr exist */ - if (!list_empty(&dhd->csi_list)) { - list_for_each_entry_safe(ptr, next, &dhd->csi_list, list) { - if (ptr->entry.header.remain_length) { - DHD_ERROR(("data not ready %d\n", ptr->entry.header.remain_length)); + dhd_csi_clean_list(dhdp); + + mutex_destroy(&dhdp->csi_lock); + + return err; +} + +int dhd_csi_retrieve_queue_data(dhd_pub_t *dhdp, char *buf, uint count) +{ + struct csi_cfr_node *ptr = NULL, *next = NULL; + int ret = BCME_OK; + char *pbuf = buf; + int num = 0; + int copy_len = 0; + int left_data = 0; + int total_copy_len = 0; + + NULL_CHECK(dhdp, "dhdp is NULL", ret); + + mutex_lock(&dhdp->csi_lock); + if (!list_empty(&dhdp->csi_list)) { + list_for_each_entry_safe(ptr, next, &dhdp->csi_list, list) { + struct syna_csi_header *pEntry = &(ptr->entry); + if (pEntry->remain_length) { + DHD_ERROR(("%s-%d: *Warning, data not ready " + "for %02X:%02X:%02X:%02X:%02X:%02X," + "global_id=%d, data_length=%d, " + "remain_length=%d\n", + __func__, __LINE__, + pEntry->client_ea[0], + pEntry->client_ea[1], + pEntry->client_ea[2], + pEntry->client_ea[3], + pEntry->client_ea[4], + pEntry->client_ea[5], + pEntry->global_id, + pEntry->data_length, + pEntry->remain_length)); continue; } - bcopy(&ptr->entry.header, pbuf, sizeof(cfr_dump_header_t)); - length += sizeof(cfr_dump_header_t); - pbuf += sizeof(cfr_dump_header_t); - DHD_TRACE(("Copy data size %d\n", ptr->entry.header.cfr_dump_length)); - bcopy(&ptr->entry.data, pbuf, ptr->entry.header.cfr_dump_length); - length += ptr->entry.header.cfr_dump_length; - pbuf += ptr->entry.header.cfr_dump_length; - num++; + + left_data = SYNA_CSI_PKT_TOTAL_LEN(pEntry) + - pEntry->copied_length; + copy_len = count; + + if (0 > left_data) { + DHD_ERROR(("%s-%d: *Error, invalid case, " + "total_len=%d, data_len=%d, " + "remain_len=%d, copied_len=%d\n", + __func__, __LINE__, + (int)SYNA_CSI_PKT_TOTAL_LEN(pEntry), + pEntry->data_length, + pEntry->remain_length, + pEntry->copied_length)); + copy_len = 0; + } else if (copy_len > left_data) { + copy_len = left_data; + } + + DHD_TRACE(("%s-%d: Packet[%d]: " + "left_room=%d, copy_len=%d, " + "pNode_data_len=%d, pNode_reamin_len=%d, " + "pNode_copied_len=%d, csi_count=%d\n", + __func__, __LINE__, + num, count, copy_len, + pEntry->data_length, + pEntry->remain_length, + pEntry->copied_length, + dhdp->csi_count)); + + if (0 < copy_len) { + memcpy(pbuf, + pEntry->copied_length + (uint8 *)pEntry, + copy_len); + pEntry->copied_length += copy_len; + count -= copy_len; + pbuf += copy_len; + num++; + } + + if (pEntry->copied_length >= SYNA_CSI_PKT_TOTAL_LEN(pEntry)) { + list_del(&ptr->list); + MFREE(dhdp->osh, ptr, ptr->total_size); + dhdp->csi_count--; + } + + if (0 >= copy_len) { + break; + } } } - DHD_TRACE(("dump %d record %d bytes\n", num, length)); + mutex_unlock(&dhdp->csi_lock); + total_copy_len = pbuf - buf; + DHD_TRACE(("%s-%d: dump %d record %d bytes\n", + __func__, __LINE__, num, total_copy_len)); - return length; + return total_copy_len; } +#endif /* CSI_SUPPORT */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_csi.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_csi.h old mode 100755 new mode 100644 index e1c0aaaac6dc..02ee564f6572 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_csi.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_csi.h @@ -1,7 +1,8 @@ /* - * Broadcom Dongle Host Driver (DHD), CSI + * Broadcom Dongle Host Driver (DHD), Linux-specific network interface. + * Basically selected code segments from usb-cdc.c and usb-rndis.c * - * Copyright (C) 1999-2018, Broadcom. + * Copyright (C) 2023, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -17,27 +18,252 @@ * derived from this software. The special exception does not apply to any * modifications of the software. * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_csi.h 558438 2015-05-22 06:05:11Z $ + * <> + * + * $Id$ */ + #ifndef __DHD_CSI_H__ #define __DHD_CSI_H__ +/* definition for structure and API between APPP and driver */ + +/* **** SYNA CSI header interface with driver **** */ + +enum syna_csi_data_mode_type { + SYNA_CSI_DATA_MODE_NONE = 0, + /* upper layer will fetch data by sysfs */ + SYNA_CSI_DATA_MODE_SYSFS, + /* upper layer will fetch data by UDP socket */ + SYNA_CSI_DATA_MODE_UDP_SOCKET, + SYNA_CSI_DATA_MODE_LAST +}; + +enum syna_csi_format_type { + SYNA_CSI_FORMAT_UNKNOWN = 0, + SYNA_CSI_FORMAT_Q8, /* (9,9,5) Q8 floating point + * BCM4358/4359 + */ + SYNA_CSI_FORMAT_Q13, /* (14,14) Q13 fixed point + * BCM4339/43455/43456/43458 + */ + SYNA_CSI_FORMAT_Q11, /* (12,12,6) Q11 floating point + * BCM4360/4366 + */ + SYNA_CSI_FORMAT_LAST +}; +/* (9,9,5) Q8 floating point data format */ +#define _Q8_REAL_MA(t) (0x000ff &((t)>>14)) +#define _Q8_REAL_SI(t) (0x00001 &((t)>>22)) +#define _Q8_IMAGE_MA(t) (0x000ff &((t)>> 5)) +#define _Q8_IMAGE_SI(t) (0x00001 &((t)>>13)) +#define SYNA_CSI_DATA_Q8_REAL(t) \ +(((0 < _Q8_REAL_SI(t)) \ + ? (-1) \ + : (1)) \ + * ((int32)_Q8_REAL_MA(t)) \ +) +#define SYNA_CSI_DATA_Q8_IMAGE(t) \ +(((0 < _Q8_IMAGE_SI(t)) \ + ? (-1) \ + : (1)) \ + * ((int32)_Q8_IMAGE_MA(t)) \ +) +#define SYNA_CSI_DATA_Q8_EXP(t) \ +(((int8)(0xf8 \ + & ((t) << 3))) \ + >> 3 \ +) +/* (14,14) Q13 fixed point data format */ +#define SYNA_CSI_DATA_Q13_REAL(t) \ +(((int32)(0xfff30000 \ + & ((t) << 4))) \ + >> (14 + 4) \ +) +#define SYNA_CSI_DATA_Q13_IMAGE(t) \ +(((int32)(0xfff30000 \ + & ((t) << 18))) \ + >> (0 + 18) \ +) +/* (12,12,6) Q11 floating point */ +#define _Q11_REAL_MA(t) (0x007ff &((t)>>18)) +#define _Q11_REAL_SI(t) (0x00001 &((t)>>29)) +#define _Q11_IMAGE_MA(t) (0x007ff &((t)>> 6)) +#define _Q11_IMAGE_SI(t) (0x00001 &((t)>>17)) +#define SYNA_CSI_DATA_Q11_REAL(t) \ +(((0 < _Q11_REAL_SI(t)) \ + ? (-1) \ + : (1)) \ + * ((int32)_Q11_REAL_MA(t)) \ +) +#define SYNA_CSI_DATA_Q11_IMAGE(t) \ +(((0 < _Q11_IMAGE_SI(t)) \ + ? (-1) \ + : (1)) \ + * ((int32)_Q11_IMAGE_MA(t)) \ +) +#define SYNA_CSI_DATA_Q11_EXP(t) \ +(((int8)(0xfc \ + & ((t) << 2))) \ + >> 2 \ +) + +enum syna_csi_error_status { + SYNA_CSI_ERROR_NONE, + SYNA_CSI_ERROR_GENERIC, /* generic error */ + SYNA_CSI_ERROR_NO_ACK, /* peer doesn't ACK */ + SYNA_CSI_ERROR_READ, /* read data error */ + SYNA_CSI_ERROR_PS, /* peer device under powersaving */ + SYNA_CSI_ERROR_LAST +}; + +enum syna_csi_flag { + /* bit 0 ~ bit 15 are for error information */ + SYNA_CSI_FLAG_ERROR_MASK = 0x0FFFF, + SYNA_CSI_FLAG_ERROR_CHECKSUM = (1 << 0), + SYNA_CSI_FLAG_ERROR_GENERIC = (1 << SYNA_CSI_ERROR_GENERIC), + SYNA_CSI_FLAG_ERROR_NO_ACK = (1 << SYNA_CSI_ERROR_NO_ACK), + SYNA_CSI_FLAG_ERROR_READ = (1 << SYNA_CSI_ERROR_READ), + SYNA_CSI_FLAG_ERROR_PS = (1 << SYNA_CSI_ERROR_PS), + + /* subcarrier real position along FFT index: (total N=2*M subcarries) + * -M, -(M-1), -(M-2), -(M-3),...,-1, 0, 1, 2,...M-1, M + * + * Data Output order with positive part first(*default*): + * 0, 1, 2,...M-1, M, -M, -(M-1), -(M-2), -(M-3),...,-1, + * + * Data Output order with negative part first: + * -M, -(M-1), -(M-2), -(M-3),...,-1, 0, 1, 2,...M-1, M + */ + SYNA_CSI_FLAG_FFT_NEGATIVE_FIRST = (1 << 16), + SYNA_CSI_FLAG_LAST +}; + +enum syna_csi_band_type { + SYNA_CSI_BAND_UNKNOWN = 0, + SYNA_CSI_BAND_2G, + SYNA_CSI_BAND_5G, + SYNA_CSI_BAND_6G, + SYNA_CSI_BAND_LAST +}; + +enum syna_csi_bandwidth_type { + SYNA_CSI_BW_UNKNOWN = 0x000, + SYNA_CSI_BW_5MHz = 0x001, + SYNA_CSI_BW_10MHz = 0x002, + SYNA_CSI_BW_20MHz = 0x004, + SYNA_CSI_BW_40MHz = 0x008, + SYNA_CSI_BW_80MHz = 0x010, + SYNA_CSI_BW_160MHz = 0x020, + SYNA_CSI_BW_320MHz = 0x040, + SYNA_CSI_BW_LAST +}; + +/* 'SYNA' -> 'A'53, 'N'59, 'Y'4e, 'S'41 */ +#define CONST_SYNA_CSI_MAGIC_FLAG 0x414E5953 + +/* CSI API common header structure (8 bytes alignment for 64bit system) */ +/* below is version 1 'syna_csi_header' */ +#define CONST_SYNA_CSI_COMMON_HEADER_VERSION 0x01 +struct syna_csi_header { + /* byte 0 ~ 3 */ + uint32 magic_flag; /* flag for protecting and detecting header */ + + /* byte 4 ~ 7 */ + uint8 version; /* header version of this structure */ + uint8 format_type; /* data format type of current CSI packet, + * enumerated in 'syna_csi_format_type' + */ + uint8 fc; /* packet frame control type of current + * CSI data for further checking if it + * is correct expected result + */ + uint8 flags; /* flag may use for extra emendation + * which enumerated as 'syna_csi_flag' + */ + + /* byte 8 ~ 19 */ + uint8 client_ea[6]; /* client MAC address */ + uint8 bsscfg_ea[6]; /* BSSCFG address of current interface */ + + /* byte 20 ~ 23 */ + uint8 band; /* enumerated in 'syna_csi_band_type' */ + uint8 bandwidth; /* enumerated in 'syna_csi_bandwidth_type' */ + uint16 channel; /* channel number of corresponding band */ + + /* byte 24 ~ 31 */ + uint64 report_tsf; /* current CSI DATA RX timestamp */ + + /* byte 32 ~ 35 */ + uint8 num_txstream; /* peer side TX spatial steams */ + uint8 num_rxchain; /* number of RX side chain/antenna */ + uint16 num_subcarrier; /* Number of subcarrier */ + + /* byte 36 ~ 39 */ + int8 rssi; /* average RSSI, and goto check the + * 'rssi_ant' if this 'rssi' is zero + */ + int8 noise; /* average noise */ + int16 global_id; /* CSI frame global ID */ + + /* byte 40 ~ 47 */ + int8 rssi_ant[8]; /* RSSI of each RX chain/antenna + * (Depends on solution, and some + * chipsets may only provide 'rssi' + * rather than 'rssi_ant') + */ + + /* byte 48 ~ 55 */ + uint64 padding_future; /* reserved */ + + /* byte 56 ~ 63 */ + uint16 data_length; /* the bytes of 'data[]' */ + uint16 remain_length; /* remain length of not received data */ + uint16 copied_length; /* the length has been copied to user */ + uint16 checksum; /* 'data[]' checksum, 0 - not used */ + + /* byte 64 ~ End */ + uint32 data[0]; /* variable length according to the + * 'data_length', but the minimal + * valid data length will be + * decided by the 'num_txchains' + * 'num_rxchain' 'num_subcarrier'. + * For example, the index quantity + * of 'uint32' in the 11N 80MHz can + * be got via: + * 256 SubCarriers * 2 TXStream * 2 RXChain + * Note: 'data_length' is bytes quantity, + * and the 'data[]' array index range should + * be 0 ~ (data_length/4 - 1) + */ +}; + +#define SYNA_CSI_PKT_TOTAL_LEN(ptr) \ +(sizeof(struct syna_csi_header) \ + + ((struct syna_csi_header *)(ptr))->data_length \ +) + +/* definition for structure and functions between driver and FW */ + /* Maxinum csi file dump size */ #define MAX_CSI_FILESZ (32 * 1024) /* Maxinum subcarrier number */ -#define MAXINUM_CFR_DATA 256 * 4 +#define MAXIMUM_CFR_DATA 2048 #define CSI_DUMP_PATH "/sys/bcm-dhd/csi" #define MAX_EVENT_SIZE 1400 /* maximun csi number stored at dhd */ -#define MAX_CSI_NUM 8 +#define MAX_CSI_NUM 16 +#define MAX_CSI_BUF_NUM 1024 -typedef struct cfr_dump_header { - /* 0 - successful; 1 - Failed */ - uint8 status; +/* CSI VERSION */ +#define CSI_VERSION_V0 0 /* V0 */ +#define CSI_VERSION_V1 1 /* V1 */ +#define CSI_VERSION_V2 2 /* V2 */ + +struct dhd_cfr_header_v0 { + uint8 status:4; /* bit3-0 */ + uint8 version:4; /* bit7-4 */ /* Peer MAC address */ uint8 peer_macaddr[6]; /* Number of Space Time Streams */ @@ -52,25 +278,189 @@ typedef struct cfr_dump_header { uint32 remain_length; /* RSSI */ int8 rssi; -} __attribute__((packed)) cfr_dump_header_t; + uint32 data[0]; +} __attribute__ ((packed)); -typedef struct cfr_dump_data { - cfr_dump_header_t header; - uint32 data[MAXINUM_CFR_DATA]; -} cfr_dump_data_t; +struct dhd_cfr_header_v1 { + uint8 status:4; /* bit3-0 */ + uint8 version:4; /* bit7-4 */ + /* Peer MAC address */ + uint8 peer_macaddr[6]; + /* Number of Space Time Streams */ + uint8 sts; + /* Number of RX chain */ + uint8 num_rx; + /* Number of subcarrier */ + uint16 num_carrier; + /* Length of the CSI dump */ + uint32 cfr_dump_length; + /* remain unsend CSI data length */ + uint32 remain_length; + /* RSSI */ + int8 rssi; -typedef struct { - struct list_head list; - cfr_dump_data_t entry; -} cfr_dump_list_t; + /* Chip id. 1 for BCM43456/8 */ + uint8 chip_id; + /* Frame control field */ + uint8 fc; + /* Time stamp when CFR capture is taken, + * in microseconds since the epoch + */ + uint64 cfr_timestamp; -int dhd_csi_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); + uint32 data[0]; +} __attribute__ ((packed)); -int dhd_csi_init(dhd_pub_t *dhd); +struct dhd_cfr_header_v2 { /* 8 bytes aligment for x64 */ + /* byte 0 ~ 7 */ + uint8 status_compat:4; /* bit3-0, current CSI data status: 0->good */ + uint8 version_compat:4; /* bit7-4, duplicate but compatible part */ + uint8 padding_magic; + uint16 magic_flag; /* flag for protecting and detecting header */ -int dhd_csi_deinit(dhd_pub_t *dhd); + uint8 version; /* header version of this structure */ + uint8 format_type; /* data format type of current CSI packet, + * enumerated in 'syna_csi_format_type' + */ + uint8 fc; /* packet frame control type of current + * CSI data for further checking if it + * is correct expected result + */ + uint8 flags; /* flag may use for extra emendation + * which enumerated as 'syna_csi_flag' + */ -void dhd_csi_clean_list(dhd_pub_t *dhd); + /* byte 8 ~ 19 */ + uint8 client_ea[6]; /* client MAC address */ + uint8 bsscfg_ea[6]; /* BSSCFG address of current interface */ + + /* byte 20 ~ 23 */ + uint8 band; /* enumerated in 'syna_csi_band_type' */ + uint8 bandwidth; /* enumerated in 'syna_csi_bandwidth_type' */ + uint16 channel; /* channel number of corresponding band */ + + /* byte 24 ~ 31 */ + uint64 report_tsf; /* current CSI DATA RX timestamp */ + + /* byte 32 ~ 35 */ + uint8 num_txstream; /* peer side TX spatial steams */ + uint8 num_rxchain; /* number of RX side chain/antenna */ + uint16 num_subcarrier; /* Number of subcarrier */ + + /* byte 36 ~ 39 */ + int8 rssi; /* average RSSI, and goto check the + * 'rssi_ant' if this 'rssi' is zero + */ + int8 noise; /* average noise */ + int16 global_id; /* CSI frame global ID */ + + /* byte 40 ~ 47 */ + int8 rssi_ant[8]; /* RSSI of each RX chain/antenna + * (Depends on solution, and some + * chipsets may only provide 'rssi' + * rather than 'rssi_ant') + */ + + /* byte 48 ~ 55 */ + uint64 padding_future; /* reserved */ + + /* byte 56 ~ 63 */ + uint16 data_length; /* the data length of 'data[]' */ + uint16 remain_length; /* the remain unsent length of 'data[]' */ + uint16 padding_length; /* reserved */ + uint16 checksum; /* 'data[]' checksum, 0 - not used */ + + /* byte 64 ~ End */ + uint32 data[0]; /* variable according to 'data_length', but + * the minial valid data length will be + * decided by 'num_txchains', 'num_rxchain' + * 'num_subcarrier'. For example, the + * quantity of uint32(4 bytes) in the + * 11N 80MHz can be got via: + * 256 SubCarriers * 2 TXStream * 2 RXChain + */ +}; + +union dhd_cfr_header { + struct dhd_cfr_header_v0 header_v0; + struct dhd_cfr_header_v1 header_v1; + struct dhd_cfr_header_v2 header_v2; +}; +#define CSI_CFR_TOTAL_LENGTH(data_len) \ + (sizeof(union dhd_cfr_header) + data_len) + +/* BW80 2x2 => 4bytes*256subcarries*2txstream*2rxchain */ +#define CONST_CSI_MAXIMUM_DATA_BYTES (CSI_CFR_TOTAL_LENGTH(256 *2 *2 *4)) + +struct csi_cfr_node { + struct list_head list; + void *pNode; /* recording current node pointer + * especially for UDP data manner + */ + uint32 total_size; + + struct syna_csi_header entry; +}; + +#define SYNA_CSI_CFR_NODE_LEN sizeof(struct csi_cfr_node) + +#define SYNA_CSI_CFR_NODE_TOTAL_LEN(ptr, data_length) \ +(\ + SYNA_CSI_CFR_NODE_LEN + data_length \ +) + +#define SYNA_CSI_CFR_NODE_FREE_LEN(ptr) \ +(\ + ((struct csi_cfr_node *)(ptr))->total_size \ + - SYNA_CSI_CFR_NODE_LEN \ +) + +extern int dhd_csi_config(dhd_pub_t *dhdp, char *buf, uint length, bool is_set); + +/* Function: change the upper layer fetching data manner + * Input: uint is_set indicate it's set or get action + * uint type the expected fetch type(ignore when get) + * uint param extra param when set(UDP socket port) + * Output: < 0 error encounter + * == 0 successful + * > 0 corresponding 'fetch type' when get + */ +extern int dhd_csi_data_fetch_type_access(uint is_set, uint type, uint param); + +/* Function: parse the CSI event and convert to 'dhd_csi_header' format, + * and queue the item into the common 'csi_cfr_queue' + * Input: dhd_pub_t *dhdp context for operation + * char *buf buffer for storing csi data + * uint count total bytes available in 'buf' + * Output: < 0 error encounter + * == 0 successful but no csi data in queue + * > 0 bytes write into 'buf' + */ +extern int dhd_csi_retrieve_queue_data(dhd_pub_t *dhdp, char *buf, uint count); + +/* Function: parse the CSI event and convert to 'dhd_csi_header' format, + * and queue the item into the common 'csi_cfr_queue' + * Input: dhd_pub_t *dhdp context for operation + * wl_event_msg_t *event wl event message header + * void *event_data extra event data + * Output: < 0 error encounter + * == 0 successful + */ +extern int dhd_csi_event_handler(dhd_pub_t *dhdp, + const wl_event_msg_t *event, void *event_data); + +/* Function: Initialize the CSI module + * Input: dhd_pub_t *dhdp context for operation + * Output: < 0 error encounter + * == 0 successful + */ +extern int dhd_csi_init(dhd_pub_t *dhdp); + +/* Function: Deinitialize the CSI module + * Input: dhd_pub_t *dhdp context for operation + * Output: < 0 error encounter + * == 0 successful + */ +extern int dhd_csi_deinit(dhd_pub_t *dhdp); -int dhd_csi_dump_list(dhd_pub_t *dhd, char *buf); #endif /* __DHD_CSI_H__ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_cis.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_cis.c deleted file mode 100755 index 7105a9ee516e..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_cis.c +++ /dev/null @@ -1,2010 +0,0 @@ -/* - * Process CIS information from OTP for customer platform - * (Handle the MAC address and module information) - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef DHD_USE_CISINFO_FROM_OTP -#include /* need to still support chips no longer in trunk firmware */ -#include -#include -#include -#endif /* DHD_USE_CISINFO_FROM_OTP */ - -#ifdef DHD_USE_CISINFO_FROM_OTP -#define CIS_TUPLE_HDR_LEN 2 -#if defined(BCM4375_CHIP) -#define CIS_TUPLE_START_ADDRESS 0x18011120 -#define CIS_TUPLE_END_ADDRESS 0x18011177 -#elif defined(BCM4389_CHIP_DEF) -#define CIS_TUPLE_START_ADDRESS 0x18011058 -#define CIS_TUPLE_END_ADDRESS 0x180110AF -#else -#define CIS_TUPLE_START_ADDRESS 0x18011110 -#define CIS_TUPLE_END_ADDRESS 0x18011167 -#endif /* defined(BCM4375_CHIP) */ -#define CIS_TUPLE_MAX_COUNT (uint32)((CIS_TUPLE_END_ADDRESS - CIS_TUPLE_START_ADDRESS\ - + 1) / sizeof(uint32)) -#define CIS_TUPLE_TAG_START 0x80 -#define CIS_TUPLE_TAG_VENDOR 0x81 -#define CIS_TUPLE_TAG_BOARDTYPE 0x1b -#define CIS_TUPLE_TAG_LENGTH 1 - -typedef struct cis_tuple_format { - uint8 id; - uint8 len; /* total length of tag and data */ - uint8 tag; - uint8 data[1]; -} cis_tuple_format_t; - -static int -read_otp_from_bp(dhd_bus_t *bus, uint32 *data_buf) -{ - int int_val = 0, i = 0, bp_idx = 0; - int boardtype_backplane_addr[] = { - 0x18010324, /* OTP Control 1 */ - 0x18012618, /* PMU min resource mask */ - }; - int boardtype_backplane_data[] = { - 0x00fa0000, - 0x0e4fffff /* Keep on ARMHTAVAIL */ - }; - - uint32 cis_start_addr = CIS_TUPLE_START_ADDRESS; - uint32 org_boardtype_backplane_data[] = { - 0, - 0 - }; - - for (bp_idx = 0; bp_idx < ARRAYSIZE(boardtype_backplane_addr); bp_idx++) { - /* Read OTP Control 1 and PMU min_rsrc_mask before writing */ - if (si_backplane_access(bus->sih, boardtype_backplane_addr[bp_idx], sizeof(int), - &org_boardtype_backplane_data[bp_idx], TRUE) != BCME_OK) { - DHD_ERROR(("invalid size/addr combination\n")); - return BCME_ERROR; - } - - /* Write new OTP and PMU configuration */ - if (si_backplane_access(bus->sih, boardtype_backplane_addr[bp_idx], sizeof(int), - &boardtype_backplane_data[bp_idx], FALSE) != BCME_OK) { - DHD_ERROR(("invalid size/addr combination\n")); - return BCME_ERROR; - } - - if (si_backplane_access(bus->sih, boardtype_backplane_addr[bp_idx], sizeof(int), - &int_val, TRUE) != BCME_OK) { - DHD_ERROR(("invalid size/addr combination\n")); - return BCME_ERROR; - } - - DHD_INFO(("%s: boardtype_backplane_addr 0x%08x rdata 0x%04x\n", - __FUNCTION__, boardtype_backplane_addr[bp_idx], int_val)); - } - - /* read tuple raw data */ - for (i = 0; i < CIS_TUPLE_MAX_COUNT; i++) { - if (si_backplane_access(bus->sih, cis_start_addr + i * sizeof(uint32), - sizeof(uint32), &data_buf[i], TRUE) != BCME_OK) { - break; - } - DHD_INFO(("%s: tuple index %d, raw data 0x%08x\n", __FUNCTION__, i, data_buf[i])); - } - - for (bp_idx = 0; bp_idx < ARRAYSIZE(boardtype_backplane_addr); bp_idx++) { - /* Write original OTP and PMU configuration */ - if (si_backplane_access(bus->sih, boardtype_backplane_addr[bp_idx], sizeof(int), - &org_boardtype_backplane_data[bp_idx], FALSE) != BCME_OK) { - DHD_ERROR(("invalid size/addr combination\n")); - return BCME_ERROR; - } - - if (si_backplane_access(bus->sih, boardtype_backplane_addr[bp_idx], sizeof(int), - &int_val, TRUE) != BCME_OK) { - DHD_ERROR(("invalid size/addr combination\n")); - return BCME_ERROR; - } - - DHD_INFO(("%s: boardtype_backplane_addr 0x%08x rdata 0x%04x\n", - __FUNCTION__, boardtype_backplane_addr[bp_idx], int_val)); - } - - return i * sizeof(uint32); -} - -static int -dhd_parse_board_information_bcm(dhd_bus_t *bus, int *boardtype, - unsigned char *vid, int *vid_length) -{ - int totlen, len; - uint32 raw_data[CIS_TUPLE_MAX_COUNT]; - cis_tuple_format_t *tuple; - - totlen = read_otp_from_bp(bus, raw_data); - if (totlen == BCME_ERROR || totlen == 0) { - DHD_ERROR(("%s : Can't read the OTP\n", __FUNCTION__)); - return BCME_ERROR; - } - - tuple = (cis_tuple_format_t *)raw_data; - - /* check the first tuple has tag 'start' */ - if (tuple->id != CIS_TUPLE_TAG_START) { - DHD_ERROR(("%s: Can not find the TAG\n", __FUNCTION__)); - return BCME_ERROR; - } - - *vid_length = *boardtype = 0; - - /* find tagged parameter */ - while ((totlen >= (tuple->len + CIS_TUPLE_HDR_LEN)) && - (*vid_length == 0 || *boardtype == 0)) { - len = tuple->len; - - if ((tuple->tag == CIS_TUPLE_TAG_VENDOR) && - (totlen >= (int)(len + CIS_TUPLE_HDR_LEN))) { - /* found VID */ - memcpy(vid, tuple->data, tuple->len - CIS_TUPLE_TAG_LENGTH); - *vid_length = tuple->len - CIS_TUPLE_TAG_LENGTH; - prhex("OTP VID", tuple->data, tuple->len - CIS_TUPLE_TAG_LENGTH); - } - else if ((tuple->tag == CIS_TUPLE_TAG_BOARDTYPE) && - (totlen >= (int)(len + CIS_TUPLE_HDR_LEN))) { - /* found boardtype */ - *boardtype = (int)tuple->data[0]; - prhex("OTP boardtype", tuple->data, tuple->len - CIS_TUPLE_TAG_LENGTH); - } - - tuple = (cis_tuple_format_t*)((uint8*)tuple + (len + CIS_TUPLE_HDR_LEN)); - totlen -= (len + CIS_TUPLE_HDR_LEN); - } - - if (*vid_length <= 0 || *boardtype <= 0) { - DHD_ERROR(("failed to parse information (vid=%d, boardtype=%d)\n", - *vid_length, *boardtype)); - return BCME_ERROR; - } - - return BCME_OK; -} - -#ifdef USE_CID_CHECK -#define CHIP_REV_A0 1 -#define CHIP_REV_A1 2 -#define CHIP_REV_B0 3 -#define CHIP_REV_B1 4 -#define CHIP_REV_B2 5 -#define CHIP_REV_C0 6 -#define BOARD_TYPE_EPA 0x080f -#define BOARD_TYPE_IPA 0x0827 -#define BOARD_TYPE_IPA_OLD 0x081a -#define DEFAULT_CIDINFO_FOR_EPA "r00a_e000_a0_ePA" -#define DEFAULT_CIDINFO_FOR_IPA "r00a_e000_a0_iPA" -#define DEFAULT_CIDINFO_FOR_A1 "r01a_e30a_a1" -#define DEFAULT_CIDINFO_FOR_B0 "r01i_e32_b0" - -naming_info_t bcm4361_naming_table[] = { - { {""}, {""}, {""} }, - { {"r00a_e000_a0_ePA"}, {"_a0_ePA"}, {"_a0_ePA"} }, - { {"r00a_e000_a0_iPA"}, {"_a0"}, {"_a1"} }, - { {"r01a_e30a_a1"}, {"_r01a_a1"}, {"_a1"} }, - { {"r02a_e30a_a1"}, {"_r02a_a1"}, {"_a1"} }, - { {"r02c_e30a_a1"}, {"_r02c_a1"}, {"_a1"} }, - { {"r01d_e31_b0"}, {"_r01d_b0"}, {"_b0"} }, - { {"r01f_e31_b0"}, {"_r01f_b0"}, {"_b0"} }, - { {"r02g_e31_b0"}, {"_r02g_b0"}, {"_b0"} }, - { {"r01h_e32_b0"}, {"_r01h_b0"}, {"_b0"} }, - { {"r01i_e32_b0"}, {"_r01i_b0"}, {"_b0"} }, - { {"r02j_e32_b0"}, {"_r02j_b0"}, {"_b0"} }, - { {"r012_1kl_a1"}, {"_r012_a1"}, {"_a1"} }, - { {"r013_1kl_b0"}, {"_r013_b0"}, {"_b0"} }, - { {"r013_1kl_b0"}, {"_r013_b0"}, {"_b0"} }, - { {"r014_1kl_b0"}, {"_r014_b0"}, {"_b0"} }, - { {"r015_1kl_b0"}, {"_r015_b0"}, {"_b0"} }, - { {"r020_1kl_b0"}, {"_r020_b0"}, {"_b0"} }, - { {"r021_1kl_b0"}, {"_r021_b0"}, {"_b0"} }, - { {"r022_1kl_b0"}, {"_r022_b0"}, {"_b0"} }, - { {"r023_1kl_b0"}, {"_r023_b0"}, {"_b0"} }, - { {"r024_1kl_b0"}, {"_r024_b0"}, {"_b0"} }, - { {"r030_1kl_b0"}, {"_r030_b0"}, {"_b0"} }, - { {"r031_1kl_b0"}, {"_r030_b0"}, {"_b0"} }, /* exceptional case : r31 -> r30 */ - { {"r032_1kl_b0"}, {"_r032_b0"}, {"_b0"} }, - { {"r033_1kl_b0"}, {"_r033_b0"}, {"_b0"} }, - { {"r034_1kl_b0"}, {"_r034_b0"}, {"_b0"} }, - { {"r02a_e32a_b2"}, {"_r02a_b2"}, {"_b2"} }, - { {"r02b_e32a_b2"}, {"_r02b_b2"}, {"_b2"} }, - { {"r020_1qw_b2"}, {"_r020_b2"}, {"_b2"} }, - { {"r021_1qw_b2"}, {"_r021_b2"}, {"_b2"} }, - { {"r022_1qw_b2"}, {"_r022_b2"}, {"_b2"} }, - { {"r031_1qw_b2"}, {"_r031_b2"}, {"_b2"} } -}; - -naming_info_t bcm4375_naming_table[] = { - { {""}, {""}, {""} }, - { {"e41_es11"}, {"_ES00_semco_b0"}, {"_b0"} }, - { {"e43_es33"}, {"_ES01_semco_b0"}, {"_b0"} }, - { {"e43_es34"}, {"_ES02_semco_b0"}, {"_b0"} }, - { {"e43_es35"}, {"_ES02_semco_b0"}, {"_b0"} }, - { {"e43_es36"}, {"_ES03_semco_b0"}, {"_b0"} }, - { {"e43_cs41"}, {"_CS00_semco_b1"}, {"_b1"} }, - { {"e43_cs51"}, {"_CS01_semco_b1"}, {"_b1"} }, - { {"e43_cs53"}, {"_CS01_semco_b1"}, {"_b1"} }, - { {"e43_cs61"}, {"_CS00_skyworks_b1"}, {"_b1"} }, - { {"1rh_es10"}, {"_1rh_es10_b0"}, {"_b0"} }, - { {"1rh_es11"}, {"_1rh_es11_b0"}, {"_b0"} }, - { {"1rh_es12"}, {"_1rh_es12_b0"}, {"_b0"} }, - { {"1rh_es13"}, {"_1rh_es13_b0"}, {"_b0"} }, - { {"1rh_es20"}, {"_1rh_es20_b0"}, {"_b0"} }, - { {"1rh_es32"}, {"_1rh_es32_b0"}, {"_b0"} }, - { {"1rh_es41"}, {"_1rh_es41_b1"}, {"_b1"} }, - { {"1rh_es42"}, {"_1rh_es42_b1"}, {"_b1"} }, - { {"1rh_es43"}, {"_1rh_es43_b1"}, {"_b1"} }, - { {"1rh_es44"}, {"_1rh_es44_b1"}, {"_b1"} } -}; - -naming_info_t bcm4389_naming_table[] = { - { {""}, {""}, {""} }, - { {"e53_es23"}, {"_ES10_semco_b0"}, {"_b0"} }, - { {"e53_es24"}, {"_ES20_semco_b0"}, {"_b0"} }, - { {"e53_es25"}, {"_ES21_semco_b0"}, {"_b0"} }, - { {"e53_es31"}, {"_ES30_semco_c0"}, {"_c0"} }, - { {"e53_es32"}, {"_ES32_semco_c0"}, {"_c0"} }, - { {"e53_es40"}, {"_ES40_semco_c1"}, {"_c1"} }, - { {"1wk_es21"}, {"_1wk_es21_b0"}, {"_b0"} }, - { {"1wk_es30"}, {"_1wk_es30_b0"}, {"_b0"} }, - { {"1wk_es31"}, {"_1wk_es31_b0"}, {"_b0"} }, - { {"1wk_es32"}, {"_1wk_es32_b0"}, {"_b0"} }, - { {"1wk_es40"}, {"_1wk_es40_c0"}, {"_c0"} }, - { {"1wk_es41"}, {"_1wk_es41_c0"}, {"_c0"} }, - { {"1wk_es42"}, {"_1wk_es42_c0"}, {"_c0"} }, - { {"1wk_es43"}, {"_1wk_es43_c0"}, {"_c0"} }, - { {"1wk_es50"}, {"_1wk_es50_c1"}, {"_c1"} } -}; - -/* select the NVRAM/FW tag naming table */ -naming_info_t * -select_naming_table(dhd_pub_t *dhdp, int *table_size) -{ - naming_info_t * info = NULL; - - if (!dhdp || !dhdp->bus || !dhdp->bus->sih) - { - DHD_ERROR(("%s : Invalid pointer \n", __FUNCTION__)); - return info; - } - - switch (si_chipid(dhdp->bus->sih)) { - case BCM4361_CHIP_ID: - case BCM4347_CHIP_ID: - info = &bcm4361_naming_table[0]; - *table_size = ARRAYSIZE(bcm4361_naming_table); - DHD_INFO(("%s: info %p, ret %d\n", __FUNCTION__, info, *table_size)); - break; - case BCM4375_CHIP_ID: - info = &bcm4375_naming_table[0]; - *table_size = ARRAYSIZE(bcm4375_naming_table); - DHD_INFO(("%s: info %p, ret %d\n", __FUNCTION__, info, *table_size)); - break; - case BCM4389_CHIP_ID: - info = &bcm4389_naming_table[0]; - *table_size = ARRAYSIZE(bcm4389_naming_table); - DHD_INFO(("%s: info %p, ret %d\n", __FUNCTION__, info, *table_size)); - break; - default: - DHD_ERROR(("%s: No MODULE NAMING TABLE found\n", __FUNCTION__)); - break; - } - - return info; -} - -#define CID_FEM_MURATA "_mur_" -naming_info_t * -dhd_find_naming_info(dhd_pub_t *dhdp, char *module_type) -{ - int i = 0; - naming_info_t *info = NULL; - int table_size = 0; - - info = select_naming_table(dhdp, &table_size); - if (!info || !table_size) { - DHD_ERROR(("%s : Can't select the naming table\n", __FUNCTION__)); - return NULL; - } - - if (module_type && strlen(module_type) > 0) { - for (i = 1, info++; i < table_size; info++, i++) { - DHD_INFO(("%s : info %p, %d, info->cid_ext : %s\n", - __FUNCTION__, info, i, info->cid_ext)); - if (!strncmp(info->cid_ext, module_type, strlen(info->cid_ext))) { - break; - } - } - } - - return info; -} - -static naming_info_t * -dhd_find_naming_info_by_cid(dhd_pub_t *dhdp, char *cid_info) -{ - int i = 0; - char *ptr; - naming_info_t *info = NULL; - int table_size = 0; - - info = select_naming_table(dhdp, &table_size); - if (!info || !table_size) { - DHD_ERROR(("%s : Can't select the naming table\n", __FUNCTION__)); - return NULL; - } - - /* truncate extension */ - for (i = 1, ptr = cid_info; i < MODULE_NAME_INDEX_MAX && ptr; i++) { - ptr = bcmstrstr(ptr, "_"); - if (ptr) { - ptr++; - } - } - - for (i = 1, info++; i < table_size && ptr; info++, i++) { - DHD_INFO(("%s : info %p, %d, info->cid_ext : %s\n", - __FUNCTION__, info, i, info->cid_ext)); - if (!strncmp(info->cid_ext, ptr, strlen(info->cid_ext))) { - break; - } - } - - return info; -} - -naming_info_t * -dhd_find_naming_info_by_chip_rev(dhd_pub_t *dhdp, bool *is_murata_fem) -{ - int board_type = 0, chip_rev = 0, vid_length = 0; - unsigned char vid[MAX_VID_LEN]; - naming_info_t *info = NULL; - char *cid_info = NULL; - dhd_bus_t *bus = NULL; - - if (!dhdp) { - DHD_ERROR(("%s: dhdp is NULL \n", __FUNCTION__)); - return NULL; - } - - bus = dhdp->bus; - - if (!bus || !bus->sih) { - DHD_ERROR(("%s:bus(%p) or bus->sih is NULL\n", __FUNCTION__, bus)); - return NULL; - } - - chip_rev = bus->sih->chiprev; - - if (dhd_parse_board_information_bcm(bus, &board_type, vid, &vid_length) - != BCME_OK) { - DHD_ERROR(("%s:failed to parse board information\n", __FUNCTION__)); - return NULL; - } - - DHD_INFO(("%s:chip version %d\n", __FUNCTION__, chip_rev)); - -#ifdef BCM4361_CHIP - /* A0 chipset has exception only */ - if (chip_rev == CHIP_REV_A0) { - if (board_type == BOARD_TYPE_EPA) { - info = dhd_find_naming_info(dhdp, DEFAULT_CIDINFO_FOR_EPA); - } else if ((board_type == BOARD_TYPE_IPA) || - (board_type == BOARD_TYPE_IPA_OLD)) { - info = dhd_find_naming_info(dhdp, DEFAULT_CIDINFO_FOR_IPA); - } - } else -#endif /* BCM4361_CHIP */ - { - cid_info = dhd_get_cid_info(vid, vid_length); - if (cid_info) { - info = dhd_find_naming_info_by_cid(dhdp, cid_info); - if (strstr(cid_info, CID_FEM_MURATA)) { - *is_murata_fem = TRUE; - } - } - } - - return info; -} -#endif /* USE_CID_CHECK */ -#ifdef USE_DIRECT_VID_TAG -static int -concate_nvram_by_vid(dhd_pub_t *dhdp, char *nv_path, char *chipstr) -{ - unsigned char vid[MAX_VID_LEN]; - unsigned char vid2str[MAX_VID_LEN]; - - memset(vid, 0, sizeof(vid)); - memset(vid2str, 0, sizeof(vid2str)); - - if (dhd_check_stored_module_info(vid) == BCME_OK) { - /* concate chip string tag */ - strncat(nv_path, chipstr, strlen(nv_path)); - /* concate nvram tag */ - snprintf(vid2str, sizeof(vid2str), "_%x%x", vid[VENDOR_OFF], vid[MD_REV_OFF]); - strncat(nv_path, vid2str, strlen(nv_path)); - DHD_ERROR(("%s: nvram_path : %s\n", __FUNCTION__, nv_path)); - } else { - int board_type = 0, vid_length = 0; - dhd_bus_t *bus = NULL; - if (!dhdp) { - - DHD_ERROR(("%s : dhdp is NULL \n", __FUNCTION__)); - return BCME_ERROR; - } - bus = dhdp->bus; - if (dhd_parse_board_information_bcm(bus, &board_type, vid, &vid_length) - != BCME_OK) { - DHD_ERROR(("%s:failed to parse board information\n", __FUNCTION__)); - return BCME_ERROR; - } else { - /* concate chip string tag */ - strncat(nv_path, chipstr, strlen(nv_path)); - /* vid from CIS - vid[1] = vendor, vid[0] - module rev. */ - snprintf(vid2str, sizeof(vid2str), "_%x%x", - vid[VENDOR_OFF], vid[MD_REV_OFF]); - /* concate nvram tag */ - strncat(nv_path, vid2str, strlen(nv_path)); - DHD_ERROR(("%s: nvram_path : %s\n", __FUNCTION__, nv_path)); - } - } - return BCME_OK; -} -#endif /* USE_DIRECT_VID_TAG */ -#endif /* DHD_USE_CISINFO_FROM_OTP */ - -#ifdef DHD_USE_CISINFO - -/* File Location to keep each information */ -#ifdef OEM_ANDROID -#define MACINFO PLATFORM_PATH".mac.info" -#define CIDINFO PLATFORM_PATH".cid.info" -#ifdef PLATFORM_SLP -#define MACINFO_EFS "/csa/.mac.info" -#else -#define MACINFO_EFS "/efs/wifi/.mac.info" -#define CIDINFO_DATA "/data/.cid.info" -#endif /* PLATFORM_SLP */ -#else -#define MACINFO "/opt/.mac.info" -#define MACINFO_EFS "/opt/.efs.mac.info" -#define CIDINFO "/opt/.cid.info" -#endif /* OEM_ANDROID */ - -/* Definitions for MAC address */ -#define MAC_BUF_SIZE 20 -#define MAC_CUSTOM_FORMAT "%02X:%02X:%02X:%02X:%02X:%02X" - -/* Definitions for CIS information */ -#if defined(BCM4359_CHIP) || defined(BCM4361_CHIP) || defined(BCM4375_CHIP) || \ - defined(BCM4389_CHIP_DEF) -#define CIS_BUF_SIZE 1280 -#else -#define CIS_BUF_SIZE 512 -#endif /* BCM4359_CHIP */ - -#define DUMP_CIS_SIZE 48 - -#define CIS_TUPLE_TAG_START 0x80 -#define CIS_TUPLE_TAG_VENDOR 0x81 -#define CIS_TUPLE_TAG_MACADDR 0x19 -#define CIS_TUPLE_TAG_BOARDTYPE 0x1b -#define CIS_TUPLE_LEN_MACADDR 7 -#define CIS_DUMP_END 0xff -#define CIS_TUPLE_NULL 0X00 - -#ifdef CONFIG_BCMDHD_PCIE -#if defined(BCM4361_CHIP) || defined(BCM4375_CHIP) -#define OTP_OFFSET 208 -#elif defined(BCM4389_CHIP_DEF) -#define OTP_OFFSET 0 -#else -#define OTP_OFFSET 128 -#endif /* BCM4361 | BCM4375 = 208, BCM4389 = 0, Others = 128 */ -#else /* CONFIG_BCMDHD_PCIE */ -#define OTP_OFFSET 12 /* SDIO */ -#endif /* CONFIG_BCMDHD_PCIE */ - -unsigned char *g_cis_buf = NULL; - -/* Definitions for common interface */ -typedef struct tuple_entry { - struct list_head list; /* head of the list */ - uint32 cis_idx; /* index of each tuples */ -} tuple_entry_t; - -extern int _dhd_set_mac_address(struct dhd_info *dhd, int ifidx, struct ether_addr *addr); -#if defined(GET_MAC_FROM_OTP) || defined(USE_CID_CHECK) -static tuple_entry_t *dhd_alloc_tuple_entry(dhd_pub_t *dhdp, const int idx); -static void dhd_free_tuple_entry(dhd_pub_t *dhdp, struct list_head *head); -static int dhd_find_tuple_list_from_otp(dhd_pub_t *dhdp, int req_tup, - unsigned char* req_tup_len, struct list_head *head); -#endif /* GET_MAC_FROM_OTP || USE_CID_CHECK */ - -/* otp region read/write information */ -typedef struct otp_rgn_rw_info { - uint8 rgnid; - uint8 preview; - uint8 integrity_chk; - uint16 rgnsize; - uint16 datasize; - uint8 *data; -} otp_rgn_rw_info_t; - -/* otp region status information */ -typedef struct otp_rgn_stat_info { - uint8 rgnid; - uint16 rgnstart; - uint16 rgnsize; -} otp_rgn_stat_info_t; - -typedef int (pack_handler_t)(void *ctx, uint8 *buf, uint16 *buflen); - -/* Common Interface Functions */ -int -dhd_alloc_cis(dhd_pub_t *dhdp) -{ - if (g_cis_buf == NULL) { - g_cis_buf = MALLOCZ(dhdp->osh, CIS_BUF_SIZE); - if (g_cis_buf == NULL) { - DHD_ERROR(("%s: Failed to alloc buffer for CIS\n", __FUNCTION__)); - return BCME_NOMEM; - } else { - DHD_ERROR(("%s: Local CIS buffer is alloced\n", __FUNCTION__)); - memset(g_cis_buf, 0, CIS_BUF_SIZE); - } - } - return BCME_OK; -} - -void -dhd_clear_cis(dhd_pub_t *dhdp) -{ - if (g_cis_buf) { - MFREE(dhdp->osh, g_cis_buf, CIS_BUF_SIZE); - g_cis_buf = NULL; - DHD_ERROR(("%s: Local CIS buffer is freed\n", __FUNCTION__)); - } -} - -#ifdef DHD_READ_CIS_FROM_BP -int -dhd_read_cis(dhd_pub_t *dhdp) -{ - int ret = 0, totlen = 0; - uint32 raw_data[CIS_TUPLE_MAX_COUNT]; - - int cis_offset = OTP_OFFSET + sizeof(cis_rw_t); -#if defined(BCM4389_CHIP_DEF) - /* override OTP_OFFSET for 4389 */ - cis_offset = OTP_OFFSET; -#endif /* BCM4389_CHIP_DEF */ - - totlen = read_otp_from_bp(dhdp->bus, raw_data); - if (totlen == BCME_ERROR || totlen == 0) { - DHD_ERROR(("%s : Can't read the OTP\n", __FUNCTION__)); - return BCME_ERROR; - } - - (void)memcpy_s(g_cis_buf + cis_offset, CIS_BUF_SIZE, raw_data, totlen); - return ret; -} -#else -int -dhd_read_cis(dhd_pub_t *dhdp) -{ - int ret = 0; - cis_rw_t *cish; - int buf_size = CIS_BUF_SIZE; - int length = strlen("cisdump"); - - if (length >= buf_size) { - DHD_ERROR(("%s: check CIS_BUF_SIZE\n", __FUNCTION__)); - return BCME_BADLEN; - } - - /* Try reading out from CIS */ - cish = (cis_rw_t *)(g_cis_buf + 8); - cish->source = 0; - cish->byteoff = 0; - cish->nbytes = buf_size; - strlcpy(g_cis_buf, "cisdump", buf_size); - - ret = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, g_cis_buf, buf_size, 0, 0); - if (ret < 0) { - if (ret == BCME_UNSUPPORTED) { - DHD_ERROR(("%s: get cisdump, UNSUPPORTED\n", __FUNCTION__)); - } else { - DHD_ERROR(("%s : get cisdump err(%d)\n", - __FUNCTION__, ret)); - } - /* free local buf */ - dhd_clear_cis(dhdp); - } - - return ret; -} -#endif /* DHD_READ_CIS_FROM_BP */ - -static int -dhd_otp_process_iov_resp_buf(void *ctx, void *iov_resp, uint16 cmd_id, - bcm_xtlv_unpack_cbfn_t cbfn) -{ - bcm_iov_buf_t *p_resp = NULL; - int ret = BCME_OK; - uint16 version; - - /* check for version */ - version = dtoh16(*(uint16 *)iov_resp); - if (version != WL_OTP_IOV_VERSION) { - return BCME_VERSION; - } - - p_resp = (bcm_iov_buf_t *)iov_resp; - if ((p_resp->id == cmd_id) && (cbfn != NULL)) { - ret = bcm_unpack_xtlv_buf(ctx, (uint8 *)p_resp->data, p_resp->len, - BCM_XTLV_OPTION_ALIGN32, cbfn); - } - - return ret; -} - -static int -dhd_otp_get_iov_resp(dhd_pub_t *dhdp, const uint16 cmd_id, void *ctx, - pack_handler_t packfn, bcm_xtlv_unpack_cbfn_t cbfn) -{ - bcm_iov_buf_t *iov_buf = NULL; - uint8 *iov_resp = NULL; - int ret = BCME_OK; - int buf_size = CIS_BUF_SIZE; - uint16 iovlen = 0, buflen = 0, buflen_start = 0; - - /* allocate input buffer */ - iov_buf = MALLOCZ(dhdp->osh, WLC_IOCTL_SMLEN); - if (iov_buf == NULL) { - DHD_ERROR(("%s: Failed to alloc buffer for iovar input\n", __FUNCTION__)); - ret = BCME_NOMEM; - goto fail; - } - - iov_resp = MALLOCZ(dhdp->osh, WLC_IOCTL_MAXLEN); - if (iov_resp == NULL) { - DHD_ERROR(("%s: Failed to alloc buffer for iovar response\n", __FUNCTION__)); - ret = BCME_NOMEM; - goto fail; - } - - /* parse and pack config parameters */ - buflen = buflen_start = (WLC_IOCTL_SMLEN - sizeof(*iov_buf)); - ret = packfn(ctx, (uint8 *)&iov_buf->data[0], &buflen); - if (ret != BCME_OK) { - goto fail; - } - - /* fill header portion */ - iov_buf->version = WL_OTP_IOV_VERSION; - iov_buf->len = (buflen_start - buflen); - iov_buf->id = cmd_id; - - /* issue get iovar and process response */ - iovlen = sizeof(*iov_buf) + iov_buf->len; - ret = dhd_iovar(dhdp, 0, "otp", (char *)iov_buf, iovlen, - iov_resp, WLC_IOCTL_MAXLEN, FALSE); - if (ret == BCME_OK) { - ret = dhd_otp_process_iov_resp_buf(ctx, iov_resp, cmd_id, cbfn); - } else { - DHD_ERROR(("%s: Failed to get otp iovar\n", __FUNCTION__)); - } - -fail: - if (iov_buf) { - MFREE(dhdp->osh, iov_buf, WLC_IOCTL_SMLEN); - } - if (iov_resp) { - MFREE(dhdp->osh, iov_resp, buf_size); - } - if (ret < 0) { - /* free local buf */ - dhd_clear_cis(dhdp); - } - return ret; -} - -static int -dhd_otp_cbfn_rgnstatus(void *ctx, const uint8 *data, uint16 type, uint16 len) -{ - otp_rgn_stat_info_t *stat_info = (otp_rgn_stat_info_t *)ctx; - - BCM_REFERENCE(len); - - if (data == NULL) { - DHD_ERROR(("%s: bad argument !!!\n", __FUNCTION__)); - return BCME_BADARG; - } - - switch (type) { - case WL_OTP_XTLV_RGN: - stat_info->rgnid = *data; - break; - case WL_OTP_XTLV_ADDR: - stat_info->rgnstart = dtoh16((uint16)*data); - break; - case WL_OTP_XTLV_SIZE: - stat_info->rgnsize = dtoh16((uint16)*data); - break; - default: - DHD_ERROR(("%s: unknown tlv %u\n", __FUNCTION__, type)); - break; - } - - return BCME_OK; -} - -static int -dhd_otp_packfn_rgnstatus(void *ctx, uint8 *buf, uint16 *buflen) -{ - uint8 *pxtlv = buf; - int ret = BCME_OK; - uint16 len = *buflen; - uint8 rgnid = OTP_RGN_SW; - - BCM_REFERENCE(ctx); - - /* pack option <-r region> */ - ret = bcm_pack_xtlv_entry(&pxtlv, &len, WL_OTP_XTLV_RGN, sizeof(rgnid), - &rgnid, BCM_XTLV_OPTION_ALIGN32); - if (ret != BCME_OK) { - DHD_ERROR(("%s: Failed pack xtlv entry of region: %d\n", __FUNCTION__, ret)); - return ret; - } - - *buflen = len; - return ret; -} - -static int -dhd_otp_packfn_rgndump(void *ctx, uint8 *buf, uint16 *buflen) -{ - uint8 *pxtlv = buf; - int ret = BCME_OK; - uint16 len = *buflen, size = WLC_IOCTL_MAXLEN; - uint8 rgnid = OTP_RGN_SW; - - /* pack option <-r region> */ - ret = bcm_pack_xtlv_entry(&pxtlv, &len, WL_OTP_XTLV_RGN, - sizeof(rgnid), &rgnid, BCM_XTLV_OPTION_ALIGN32); - if (ret != BCME_OK) { - DHD_ERROR(("%s: Failed pack xtlv entry of region: %d\n", __FUNCTION__, ret)); - goto fail; - } - - /* pack option [-s size] */ - ret = bcm_pack_xtlv_entry(&pxtlv, &len, WL_OTP_XTLV_SIZE, - sizeof(size), (uint8 *)&size, BCM_XTLV_OPTION_ALIGN32); - if (ret != BCME_OK) { - DHD_ERROR(("%s: Failed pack xtlv entry of size: %d\n", __FUNCTION__, ret)); - goto fail; - } - *buflen = len; -fail: - return ret; -} - -static int -dhd_otp_cbfn_rgndump(void *ctx, const uint8 *data, uint16 type, uint16 len) -{ - otp_rgn_rw_info_t *rw_info = (otp_rgn_rw_info_t *)ctx; - - BCM_REFERENCE(len); - - if (data == NULL) { - DHD_ERROR(("%s: bad argument !!!\n", __FUNCTION__)); - return BCME_BADARG; - } - - switch (type) { - case WL_OTP_XTLV_RGN: - rw_info->rgnid = *data; - break; - case WL_OTP_XTLV_DATA: - /* - * intentionally ignoring the return value of memcpy_s as it is just - * a variable copy and because of this size is within the bounds - */ - (void)memcpy_s(&rw_info->data, sizeof(rw_info->data), - &data, sizeof(rw_info->data)); - rw_info->datasize = len; - break; - default: - DHD_ERROR(("%s: unknown tlv %u\n", __FUNCTION__, type)); - break; - } - return BCME_OK; -} - -int -dhd_read_otp_sw_rgn(dhd_pub_t *dhdp) -{ - int ret = BCME_OK; - otp_rgn_rw_info_t rw_info; - otp_rgn_stat_info_t stat_info; - - memset(&rw_info, 0, sizeof(rw_info)); - memset(&stat_info, 0, sizeof(stat_info)); - - ret = dhd_otp_get_iov_resp(dhdp, WL_OTP_CMD_RGNSTATUS, &stat_info, - dhd_otp_packfn_rgnstatus, dhd_otp_cbfn_rgnstatus); - if (ret != BCME_OK) { - DHD_ERROR(("%s: otp region status failed, ret=%d\n", __FUNCTION__, ret)); - goto fail; - } - - rw_info.rgnsize = stat_info.rgnsize; - ret = dhd_otp_get_iov_resp(dhdp, WL_OTP_CMD_RGNDUMP, &rw_info, - dhd_otp_packfn_rgndump, dhd_otp_cbfn_rgndump); - if (ret != BCME_OK) { - DHD_ERROR(("%s: otp region dump failed, ret=%d\n", __FUNCTION__, ret)); - goto fail; - } - - ret = memcpy_s(g_cis_buf, CIS_BUF_SIZE, rw_info.data, rw_info.datasize); - if (ret != BCME_OK) { - DHD_ERROR(("%s: Failed to copy otp dump, ret=%d\n", __FUNCTION__, ret)); - } -fail: - return ret; - -} - -#if defined(GET_MAC_FROM_OTP) || defined(USE_CID_CHECK) -static tuple_entry_t* -dhd_alloc_tuple_entry(dhd_pub_t *dhdp, const int idx) -{ - tuple_entry_t *entry; - - entry = MALLOCZ(dhdp->osh, sizeof(tuple_entry_t)); - if (!entry) { - DHD_ERROR(("%s: failed to alloc entry\n", __FUNCTION__)); - return NULL; - } - - entry->cis_idx = idx; - - return entry; -} - -static void -dhd_free_tuple_entry(dhd_pub_t *dhdp, struct list_head *head) -{ - tuple_entry_t *entry; - - while (!list_empty(head)) { - entry = list_entry(head->next, tuple_entry_t, list); - list_del(&entry->list); - - MFREE(dhdp->osh, entry, sizeof(tuple_entry_t)); - } -} - -static int -dhd_find_tuple_list_from_otp(dhd_pub_t *dhdp, int req_tup, - unsigned char* req_tup_len, struct list_head *head) -{ - int idx = OTP_OFFSET + sizeof(cis_rw_t); - int tup, tup_len = 0; - int buf_len = CIS_BUF_SIZE; - int found = 0; - -#if defined(BCM4389_CHIP_DEF) - /* override OTP_OFFEST for 4389 */ - idx = OTP_OFFSET; -#endif /* BCM4389_CHIP_DEF */ - - if (!g_cis_buf) { - DHD_ERROR(("%s: Couldn't find cis info from" - " local buffer\n", __FUNCTION__)); - return BCME_ERROR; - } - - do { - tup = g_cis_buf[idx++]; - if (tup == CIS_TUPLE_NULL || tup == CIS_DUMP_END) { - tup_len = 0; - } else { - tup_len = g_cis_buf[idx++]; - if ((idx + tup_len) > buf_len) { - return BCME_ERROR; - } - - if (tup == CIS_TUPLE_TAG_START && - tup_len != CIS_TUPLE_NULL && - g_cis_buf[idx] == req_tup) { - idx++; - if (head) { - tuple_entry_t *entry; - entry = dhd_alloc_tuple_entry(dhdp, idx); - if (entry) { - list_add_tail(&entry->list, head); - found++; - } - } - if (found == 1 && req_tup_len) { - *req_tup_len = tup_len; - } - tup_len--; - } - } - idx += tup_len; - } while (tup != CIS_DUMP_END && (idx < buf_len)); - - return (found > 0) ? found : BCME_ERROR; -} -#endif /* GET_MAC_FROM_OTP || USE_CID_CHECK */ - -#ifdef DUMP_CIS -static void -dhd_dump_cis_buf(dhd_pub_t *dhdp, int size) -{ - int i; - int cis_offset = 0; - - cis_offset = OTP_OFFSET + sizeof(cis_rw_t); -#if defined(BCM4389_CHIP_DEF) - /* override OTP_OFFEST for 4389 */ - cis_offset = OTP_OFFSET; -#endif /* BCM4389_CHIP_DEF */ - - if (size <= 0) { - return; - } - - if (size > CIS_BUF_SIZE) { - size = CIS_BUF_SIZE; - } - - DHD_ERROR(("========== START CIS DUMP ==========\n")); - for (i = 0; i < size; i++) { - DHD_ERROR(("%02X ", g_cis_buf[i + cis_offset])); - if ((i % 16) == 15) { - DHD_ERROR(("\n")); - } - } - if ((i % 16) != 15) { - DHD_ERROR(("\n")); - } - DHD_ERROR(("========== END CIS DUMP ==========\n")); -} -#endif /* DUMP_CIS */ - -/* MAC address mangement functions */ -#ifdef READ_MACADDR -static void -dhd_create_random_mac(char *buf, unsigned int buf_len) -{ - char random_mac[3]; - - memset(random_mac, 0, sizeof(random_mac)); - get_random_bytes(random_mac, 3); - - snprintf(buf, buf_len, MAC_CUSTOM_FORMAT, 0x00, 0x12, 0x34, - (uint32)random_mac[0], (uint32)random_mac[1], (uint32)random_mac[2]); - - DHD_ERROR(("%s: The Random Generated MAC ID: %s\n", - __FUNCTION__, random_mac)); -} - -#ifndef DHD_MAC_ADDR_EXPORT -int -dhd_set_macaddr_from_file(dhd_pub_t *dhdp) -{ - char mac_buf[MAC_BUF_SIZE]; - char *filepath_efs = MACINFO_EFS; -#ifdef PLATFORM_SLP - char *filepath_mac = MACINFO; -#endif /* PLATFORM_SLP */ - int ret; - struct dhd_info *dhd; - struct ether_addr *mac; - char *invalid_mac = "00:00:00:00:00:00"; - - if (dhdp) { - dhd = dhdp->info; - mac = &dhdp->mac; - } else { - DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); - return BCME_ERROR; - } - - memset(mac_buf, 0, sizeof(mac_buf)); - - /* Read MAC address from the specified file */ - ret = dhd_read_file(filepath_efs, mac_buf, sizeof(mac_buf) - 1); - - /* Check if the file does not exist or contains invalid data */ - if (ret || (!ret && strstr(mac_buf, invalid_mac))) { - /* Generate a new random MAC address */ - dhd_create_random_mac(mac_buf, sizeof(mac_buf)); - - /* Write random MAC address to the file */ - if (dhd_write_file(filepath_efs, mac_buf, strlen(mac_buf)) < 0) { - DHD_ERROR(("%s: MAC address [%s] Failed to write into File:" - " %s\n", __FUNCTION__, mac_buf, filepath_efs)); - return BCME_ERROR; - } else { - DHD_ERROR(("%s: MAC address [%s] written into File: %s\n", - __FUNCTION__, mac_buf, filepath_efs)); - } - } -#ifdef PLATFORM_SLP - /* Write random MAC address for framework */ - if (dhd_write_file(filepath_mac, mac_buf, strlen(mac_buf)) < 0) { - DHD_ERROR(("%s: MAC address [%c%c:xx:xx:xx:x%c:%c%c] Failed to write into File:" - " %s\n", __FUNCTION__, mac_buf[0], mac_buf[1], - mac_buf[13], mac_buf[15], mac_buf[16], filepath_mac)); - } else { - DHD_ERROR(("%s: MAC address [%c%c:xx:xx:xx:x%c:%c%c] written into File: %s\n", - __FUNCTION__, mac_buf[0], mac_buf[1], mac_buf[13], - mac_buf[15], mac_buf[16], filepath_mac)); - } -#endif /* PLATFORM_SLP */ - - mac_buf[sizeof(mac_buf) - 1] = '\0'; - - /* Write the MAC address to the Dongle */ - sscanf(mac_buf, MAC_CUSTOM_FORMAT, - (uint32 *)&(mac->octet[0]), (uint32 *)&(mac->octet[1]), - (uint32 *)&(mac->octet[2]), (uint32 *)&(mac->octet[3]), - (uint32 *)&(mac->octet[4]), (uint32 *)&(mac->octet[5])); - - if (_dhd_set_mac_address(dhd, 0, mac) == 0) { - DHD_INFO(("%s: MAC Address is overwritten\n", __FUNCTION__)); - } else { - DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__)); - } - - return 0; -} -#else -int -dhd_set_macaddr_from_file(dhd_pub_t *dhdp) -{ - char mac_buf[MAC_BUF_SIZE]; - - struct dhd_info *dhd; - struct ether_addr *mac; - - if (dhdp) { - dhd = dhdp->info; - mac = &dhdp->mac; - } else { - DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); - return BCME_ERROR; - } - - memset(mac_buf, 0, sizeof(mac_buf)); - if (ETHER_ISNULLADDR(&sysfs_mac_addr)) { - /* Generate a new random MAC address */ - dhd_create_random_mac(mac_buf, sizeof(mac_buf)); - if (!bcm_ether_atoe(mac_buf, &sysfs_mac_addr)) { - DHD_ERROR(("%s : mac parsing err\n", __FUNCTION__)); - return BCME_ERROR; - } - } - - /* Write the MAC address to the Dongle */ - memcpy(mac, &sysfs_mac_addr, sizeof(sysfs_mac_addr)); - - if (_dhd_set_mac_address(dhd, 0, mac) == 0) { - DHD_INFO(("%s: MAC Address is overwritten\n", __FUNCTION__)); - } else { - DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__)); - } - - return 0; -} -#endif /* !DHD_MAC_ADDR_EXPORT */ -#endif /* READ_MACADDR */ - -#ifdef GET_MAC_FROM_OTP -static int -dhd_set_default_macaddr(dhd_pub_t *dhdp) -{ - char iovbuf[WLC_IOCTL_SMLEN]; - struct ether_addr *mac; - int ret; - - if (!dhdp) { - DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); - return BCME_BADARG; - } - - mac = &dhdp->mac; - - /* Read the default MAC address */ - ret = dhd_iovar(dhdp, 0, "cur_etheraddr", NULL, 0, iovbuf, sizeof(iovbuf), - FALSE); - if (ret < 0) { - DHD_ERROR(("%s: Can't get the default MAC address\n", __FUNCTION__)); - return BCME_NOTUP; - } - - /* Update the default MAC address */ - memcpy(mac, iovbuf, ETHER_ADDR_LEN); -#ifdef DHD_MAC_ADDR_EXPORT - memcpy(&sysfs_mac_addr, mac, sizeof(sysfs_mac_addr)); -#endif /* DHD_MAC_ADDR_EXPORT */ - - return 0; -} - -static int -dhd_verify_macaddr(dhd_pub_t *dhdp, struct list_head *head) -{ - tuple_entry_t *cur, *next; - int idx = -1; /* Invalid index */ - - list_for_each_entry(cur, head, list) { - list_for_each_entry(next, &cur->list, list) { - if ((unsigned long)next == (unsigned long)head) { - DHD_INFO(("%s: next ptr %p is same as head ptr %p\n", - __FUNCTION__, next, head)); - break; - } - if (!memcmp(&g_cis_buf[cur->cis_idx], - &g_cis_buf[next->cis_idx], ETHER_ADDR_LEN)) { - idx = cur->cis_idx; - break; - } - } - } - - return idx; -} - -int -dhd_check_module_mac(dhd_pub_t *dhdp) -{ -#ifndef DHD_MAC_ADDR_EXPORT - char *filepath_efs = MACINFO_EFS; -#endif /* !DHD_MAC_ADDR_EXPORT */ - unsigned char otp_mac_buf[MAC_BUF_SIZE]; - struct ether_addr *mac; - struct dhd_info *dhd; - - if (!dhdp) { - DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); - return BCME_BADARG; - } - - dhd = dhdp->info; - if (!dhd) { - DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); - return BCME_BADARG; - } - -#if defined(DHD_READ_CIS_FROM_BP) && defined(READ_MACADDR) - /* - * For KOR Module, CID update is required only - * so, clearing and making g_cis_buf = NULL before processing it when read_cis from STA FW - * It will get MAC from sysfs && won't update sysfs mac - */ - if (dhd_bus_get_fw_mode(dhdp) == DHD_FLAG_STA_MODE) { - dhd_clear_cis(dhdp); - } -#endif /* DHD_READ_CIS_FROM_BP && READ_MACADDR */ - - mac = &dhdp->mac; - memset(otp_mac_buf, 0, sizeof(otp_mac_buf)); - - if (!g_cis_buf) { -#ifndef DHD_MAC_ADDR_EXPORT - char eabuf[ETHER_ADDR_STR_LEN]; - DHD_INFO(("%s: Couldn't read CIS information\n", __FUNCTION__)); - - /* Read the MAC address from the specified file */ - if (dhd_read_file(filepath_efs, otp_mac_buf, sizeof(otp_mac_buf) - 1) < 0) { - DHD_ERROR(("%s: Couldn't read the file, " - "use the default MAC Address\n", __FUNCTION__)); - if (dhd_set_default_macaddr(dhdp) < 0) { - return BCME_BADARG; - } - } else { - bzero((char *)eabuf, sizeof(eabuf)); - strlcpy(eabuf, otp_mac_buf, sizeof(eabuf)); - if (!bcm_ether_atoe(eabuf, mac)) { - DHD_ERROR(("%s : mac parsing err\n", __FUNCTION__)); - if (dhd_set_default_macaddr(dhdp) < 0) { - return BCME_BADARG; - } - } - } -#else - DHD_INFO(("%s: Couldn't read CIS information\n", __FUNCTION__)); - - /* Read the MAC address from the specified file */ - if (ETHER_ISNULLADDR(&sysfs_mac_addr)) { - DHD_ERROR(("%s: Couldn't read the file, " - "use the default MAC Address\n", __FUNCTION__)); - if (dhd_set_default_macaddr(dhdp) < 0) { - return BCME_BADARG; - } - } else { - /* sysfs mac addr is confirmed with valid format in set_mac_addr */ - memcpy(mac, &sysfs_mac_addr, sizeof(sysfs_mac_addr)); - } -#endif /* !DHD_MAC_ADDR_EXPORT */ - } else { - struct list_head mac_list; - unsigned char tuple_len = 0; - int found = 0; - int idx = -1; /* Invalid index */ - -#ifdef DUMP_CIS - dhd_dump_cis_buf(dhdp, DUMP_CIS_SIZE); -#endif /* DUMP_CIS */ - - /* Find a new tuple tag */ - INIT_LIST_HEAD(&mac_list); - found = dhd_find_tuple_list_from_otp(dhdp, CIS_TUPLE_TAG_MACADDR, - &tuple_len, &mac_list); - if ((found > 0) && tuple_len == CIS_TUPLE_LEN_MACADDR) { - if (found == 1) { - tuple_entry_t *cur = list_entry((&mac_list)->next, - tuple_entry_t, list); - idx = cur->cis_idx; - } else { - /* Find the start index of MAC address */ - idx = dhd_verify_macaddr(dhdp, &mac_list); - } - } - - /* Find the MAC address */ - if (idx > 0) { -#ifdef DHD_EXPORT_CNTL_FILE - /* - * WAR for incorrect otp mac address (including multicast bit) - * for SEMCo e53_es31 module - */ - if (strcmp(cidinfostr, "semco_sem_e53_es31") == 0) { - g_cis_buf[idx] &= 0xFE; - } -#endif /* DHD_EXPORT_CNTL_FILE */ - /* update MAC address */ - snprintf(otp_mac_buf, sizeof(otp_mac_buf), MAC_CUSTOM_FORMAT, - (uint32)g_cis_buf[idx], (uint32)g_cis_buf[idx + 1], - (uint32)g_cis_buf[idx + 2], (uint32)g_cis_buf[idx + 3], - (uint32)g_cis_buf[idx + 4], (uint32)g_cis_buf[idx + 5]); - DHD_ERROR(("%s: MAC address is taken from OTP: " MACDBG "\n", - __FUNCTION__, MAC2STRDBG(&g_cis_buf[idx]))); - } else { - /* Not found MAC address info from the OTP, use the default value */ - if (dhd_set_default_macaddr(dhdp) < 0) { - dhd_free_tuple_entry(dhdp, &mac_list); - return BCME_BADARG; - } - snprintf(otp_mac_buf, sizeof(otp_mac_buf), MAC_CUSTOM_FORMAT, - (uint32)mac->octet[0], (uint32)mac->octet[1], - (uint32)mac->octet[2], (uint32)mac->octet[3], - (uint32)mac->octet[4], (uint32)mac->octet[5]); - DHD_ERROR(("%s: Cannot find MAC address info from OTP," - " Check module mac by initial value: " MACDBG "\n", - __FUNCTION__, MAC2STRDBG(mac->octet))); - } - - dhd_free_tuple_entry(dhdp, &mac_list); -#ifndef DHD_MAC_ADDR_EXPORT - dhd_write_file(filepath_efs, otp_mac_buf, strlen(otp_mac_buf)); -#else - /* Export otp_mac_buf to the sys/mac_addr */ - if (!bcm_ether_atoe(otp_mac_buf, &sysfs_mac_addr)) { - DHD_ERROR(("%s : mac parsing err\n", __FUNCTION__)); - if (dhd_set_default_macaddr(dhdp) < 0) { - return BCME_BADARG; - } - } else { - DHD_INFO(("%s : set mac address properly\n", __FUNCTION__)); - /* set otp mac to sysfs */ - memcpy(mac, &sysfs_mac_addr, sizeof(sysfs_mac_addr)); - } -#endif /* !DHD_MAC_ADDR_EXPORT */ - } - - if (_dhd_set_mac_address(dhd, 0, mac) == 0) { - DHD_INFO(("%s: MAC Address is set\n", __FUNCTION__)); - } else { - DHD_ERROR(("%s: Failed to set MAC address\n", __FUNCTION__)); - } - - return 0; -} -#endif /* GET_MAC_FROM_OTP */ - -/* - * XXX:SWWLAN-210178 SysFS MAC ADDR export - * framework controls mac addr with sysfs mac_addr kernel object without file system - * For this reason, DHD doesn't need to write mac address to file system directly - */ -#ifndef DHD_MAC_ADDR_EXPORT -#ifdef WRITE_MACADDR -int -dhd_write_macaddr(struct ether_addr *mac) -{ - char *filepath_data = MACINFO; - char *filepath_efs = MACINFO_EFS; - char mac_buf[MAC_BUF_SIZE]; - int ret = 0; - int retry_cnt = 0; - - memset(mac_buf, 0, sizeof(mac_buf)); - snprintf(mac_buf, sizeof(mac_buf), MAC_CUSTOM_FORMAT, - (uint32)mac->octet[0], (uint32)mac->octet[1], - (uint32)mac->octet[2], (uint32)mac->octet[3], - (uint32)mac->octet[4], (uint32)mac->octet[5]); - - if (filepath_data) { - for (retry_cnt = 0; retry_cnt < 3; retry_cnt++) { - /* Write MAC information into /data/.mac.info */ - ret = dhd_write_file_and_check(filepath_data, mac_buf, strlen(mac_buf)); - if (!ret) { - break; - } - } - - if (ret < 0) { - DHD_ERROR(("%s: MAC address [%s] Failed to write into" - " File: %s\n", __FUNCTION__, mac_buf, filepath_data)); - return BCME_ERROR; - } - } else { - DHD_ERROR(("%s: filepath_data doesn't exist\n", __FUNCTION__)); - } - - if (filepath_efs) { - for (retry_cnt = 0; retry_cnt < 3; retry_cnt++) { - /* Write MAC information into /efs/wifi/.mac.info */ - ret = dhd_write_file_and_check(filepath_efs, mac_buf, strlen(mac_buf)); - if (!ret) { - break; - } - } - - if (ret < 0) { - DHD_ERROR(("%s: MAC address [%s] Failed to write into" - " File: %s\n", __FUNCTION__, mac_buf, filepath_efs)); - return BCME_ERROR; - } - } else { - DHD_ERROR(("%s: filepath_efs doesn't exist\n", __FUNCTION__)); - } - - return ret; -} -#endif /* WRITE_MACADDR */ -#endif /* !DHD_MAC_ADDR_EXPORT */ - -#if defined(USE_CID_CHECK) || defined(USE_DIRECT_VID_TAG) -static int -dhd_find_tuple_idx_from_otp(dhd_pub_t *dhdp, int req_tup, unsigned char *req_tup_len) -{ - struct list_head head; - int start_idx; - int entry_num; - - if (!g_cis_buf) { - DHD_ERROR(("%s: Couldn't find cis info from" - " local buffer\n", __FUNCTION__)); - return BCME_ERROR; - } - - INIT_LIST_HEAD(&head); - entry_num = dhd_find_tuple_list_from_otp(dhdp, req_tup, req_tup_len, &head); - /* find the first cis index from the tuple list */ - if (entry_num > 0) { - tuple_entry_t *cur = list_entry((&head)->next, tuple_entry_t, list); - start_idx = cur->cis_idx; - } else { - start_idx = -1; /* Invalid index */ - } - - dhd_free_tuple_entry(dhdp, &head); - - return start_idx; -} -#endif /* USE_CID_CHECK || USE_DIRECT_VID_TAG */ - -#ifdef USE_CID_CHECK -/* Definitions for module information */ -#define MAX_VID_LEN 8 - -#ifdef SUPPORT_MULTIPLE_BOARDTYPE -#define MAX_BNAME_LEN 6 - -typedef struct { - uint8 b_len; - unsigned char btype[MAX_VID_LEN]; - char bname[MAX_BNAME_LEN]; -} board_info_t; - -#if defined(BCM4361_CHIP) -board_info_t semco_PA_info[] = { - { 3, { 0x0f, 0x08, }, { "_ePA" } }, /* semco All ePA */ - { 3, { 0x27, 0x08, }, { "_iPA" } }, /* semco 2g iPA, 5g ePA */ - { 3, { 0x1a, 0x08, }, { "_iPA" } }, /* semco 2g iPA, 5g ePA old */ - { 0, { 0x00, }, { "" } } /* Default: Not specified yet */ -}; -#else -board_info_t semco_board_info[] = { - { 3, { 0x51, 0x07, }, { "_b90b" } }, /* semco three antenna */ - { 3, { 0x61, 0x07, }, { "_b90b" } }, /* semco two antenna */ - { 0, { 0x00, }, { "" } } /* Default: Not specified yet */ -}; -board_info_t murata_board_info[] = { - { 3, { 0xa5, 0x07, }, { "_b90" } }, /* murata three antenna */ - { 3, { 0xb0, 0x07, }, { "_b90b" } }, /* murata two antenna */ - { 3, { 0xb1, 0x07, }, { "_es5" } }, /* murata two antenna */ - { 0, { 0x00, }, { "" } } /* Default: Not specified yet */ -}; -#endif /* BCM4361_CHIP */ -#endif /* SUPPORT_MULTIPLE_BOARDTYPE */ - -typedef struct { - uint8 vid_length; - unsigned char vid[MAX_VID_LEN]; - char cid_info[MAX_VNAME_LEN]; -} vid_info_t; - -#if defined(BCM4335_CHIP) -vid_info_t vid_info[] = { - { 3, { 0x33, 0x66, }, { "semcosh" } }, /* B0 Sharp 5G-FEM */ - { 3, { 0x33, 0x33, }, { "semco" } }, /* B0 Skyworks 5G-FEM and A0 chip */ - { 3, { 0x33, 0x88, }, { "semco3rd" } }, /* B0 Syri 5G-FEM */ - { 3, { 0x00, 0x11, }, { "muratafem1" } }, /* B0 ANADIGICS 5G-FEM */ - { 3, { 0x00, 0x22, }, { "muratafem2" } }, /* B0 TriQuint 5G-FEM */ - { 3, { 0x00, 0x33, }, { "muratafem3" } }, /* 3rd FEM: Reserved */ - { 0, { 0x00, }, { "murata" } } /* Default: for Murata A0 module */ -}; -#elif defined(BCM4339_CHIP) || defined(BCM4354_CHIP) || \ - defined(BCM4356_CHIP) -vid_info_t vid_info[] = { /* 4339:2G FEM+5G FEM ,4354: 2G FEM+5G FEM */ - { 3, { 0x33, 0x33, }, { "semco" } }, /* 4339:Skyworks+sharp,4354:Panasonic+Panasonic */ - { 3, { 0x33, 0x66, }, { "semco" } }, /* 4339: , 4354:Panasonic+SEMCO */ - { 3, { 0x33, 0x88, }, { "semco3rd" } }, /* 4339: , 4354:SEMCO+SEMCO */ - { 3, { 0x90, 0x01, }, { "wisol" } }, /* 4339: , 4354:Microsemi+Panasonic */ - { 3, { 0x90, 0x02, }, { "wisolfem1" } }, /* 4339: , 4354:Panasonic+Panasonic */ - { 3, { 0x90, 0x03, }, { "wisolfem2" } }, /* 4354:Murata+Panasonic */ - { 3, { 0x00, 0x11, }, { "muratafem1" } }, /* 4339: , 4354:Murata+Anadigics */ - { 3, { 0x00, 0x22, }, { "muratafem2"} }, /* 4339: , 4354:Murata+Triquint */ - { 0, { 0x00, }, { "samsung" } } /* Default: Not specified yet */ -}; -#elif defined(BCM4358_CHIP) -vid_info_t vid_info[] = { - { 3, { 0x33, 0x33, }, { "semco_b85" } }, - { 3, { 0x33, 0x66, }, { "semco_b85" } }, - { 3, { 0x33, 0x88, }, { "semco3rd_b85" } }, - { 3, { 0x90, 0x01, }, { "wisol_b85" } }, - { 3, { 0x90, 0x02, }, { "wisolfem1_b85" } }, - { 3, { 0x90, 0x03, }, { "wisolfem2_b85" } }, - { 3, { 0x31, 0x90, }, { "wisol_b85b" } }, - { 3, { 0x00, 0x11, }, { "murata_b85" } }, - { 3, { 0x00, 0x22, }, { "murata_b85"} }, - { 6, { 0x00, 0xFF, 0xFF, 0x00, 0x00, }, { "murata_b85"} }, - { 3, { 0x10, 0x33, }, { "semco_b85a" } }, - { 3, { 0x30, 0x33, }, { "semco_b85b" } }, - { 3, { 0x31, 0x33, }, { "semco_b85b" } }, - { 3, { 0x10, 0x22, }, { "murata_b85a" } }, - { 3, { 0x20, 0x22, }, { "murata_b85a" } }, - { 3, { 0x21, 0x22, }, { "murata_b85a" } }, - { 3, { 0x23, 0x22, }, { "murata_b85a" } }, - { 3, { 0x31, 0x22, }, { "murata_b85b" } }, - { 0, { 0x00, }, { "samsung" } } /* Default: Not specified yet */ -}; -#elif defined(BCM4359_CHIP) -vid_info_t vid_info[] = { -#if defined(SUPPORT_BCM4359_MIXED_MODULES) - { 3, { 0x34, 0x33, }, { "semco_b90b" } }, - { 3, { 0x40, 0x33, }, { "semco_b90b" } }, - { 3, { 0x41, 0x33, }, { "semco_b90b" } }, - { 3, { 0x11, 0x33, }, { "semco_b90b" } }, - { 3, { 0x33, 0x66, }, { "semco_b90b" } }, - { 3, { 0x23, 0x22, }, { "murata_b90b" } }, - { 3, { 0x40, 0x22, }, { "murata_b90b" } }, - { 3, { 0x10, 0x90, }, { "wisol_b90b" } }, - { 3, { 0x33, 0x33, }, { "semco_b90s_b1" } }, - { 3, { 0x66, 0x33, }, { "semco_b90s_c0" } }, - { 3, { 0x60, 0x22, }, { "murata_b90s_b1" } }, - { 3, { 0x61, 0x22, }, { "murata_b90s_b1" } }, - { 3, { 0x62, 0x22, }, { "murata_b90s_b1" } }, - { 3, { 0x63, 0x22, }, { "murata_b90s_b1" } }, - { 3, { 0x70, 0x22, }, { "murata_b90s_c0" } }, - { 3, { 0x71, 0x22, }, { "murata_b90s_c0" } }, - { 3, { 0x72, 0x22, }, { "murata_b90s_c0" } }, - { 3, { 0x73, 0x22, }, { "murata_b90s_c0" } }, - { 0, { 0x00, }, { "samsung" } } /* Default: Not specified yet */ -#else /* SUPPORT_BCM4359_MIXED_MODULES */ - { 3, { 0x34, 0x33, }, { "semco" } }, - { 3, { 0x40, 0x33, }, { "semco" } }, - { 3, { 0x41, 0x33, }, { "semco" } }, - { 3, { 0x11, 0x33, }, { "semco" } }, - { 3, { 0x33, 0x66, }, { "semco" } }, - { 3, { 0x23, 0x22, }, { "murata" } }, - { 3, { 0x40, 0x22, }, { "murata" } }, - { 3, { 0x51, 0x22, }, { "murata" } }, - { 3, { 0x52, 0x22, }, { "murata" } }, - { 3, { 0x10, 0x90, }, { "wisol" } }, - { 0, { 0x00, }, { "samsung" } } /* Default: Not specified yet */ -#endif /* SUPPORT_BCM4359_MIXED_MODULES */ -}; -#elif defined(BCM4361_CHIP) -vid_info_t vid_info[] = { -#if defined(SUPPORT_MIXED_MODULES) - { 3, { 0x66, 0x33, }, { "semco_sky_r00a_e000_a0" } }, - { 3, { 0x30, 0x33, }, { "semco_sky_r01a_e30a_a1" } }, - { 3, { 0x31, 0x33, }, { "semco_sky_r02a_e30a_a1" } }, - { 3, { 0x32, 0x33, }, { "semco_sky_r02a_e30a_a1" } }, - { 3, { 0x51, 0x33, }, { "semco_sky_r01d_e31_b0" } }, - { 3, { 0x61, 0x33, }, { "semco_sem_r01f_e31_b0" } }, - { 3, { 0x62, 0x33, }, { "semco_sem_r02g_e31_b0" } }, - { 3, { 0x71, 0x33, }, { "semco_sky_r01h_e32_b0" } }, - { 3, { 0x81, 0x33, }, { "semco_sem_r01i_e32_b0" } }, - { 3, { 0x82, 0x33, }, { "semco_sem_r02j_e32_b0" } }, - { 3, { 0x91, 0x33, }, { "semco_sem_r02a_e32a_b2" } }, - { 3, { 0xa1, 0x33, }, { "semco_sem_r02b_e32a_b2" } }, - { 3, { 0x12, 0x22, }, { "murata_nxp_r012_1kl_a1" } }, - { 3, { 0x13, 0x22, }, { "murata_mur_r013_1kl_b0" } }, - { 3, { 0x14, 0x22, }, { "murata_mur_r014_1kl_b0" } }, - { 3, { 0x15, 0x22, }, { "murata_mur_r015_1kl_b0" } }, - { 3, { 0x20, 0x22, }, { "murata_mur_r020_1kl_b0" } }, - { 3, { 0x21, 0x22, }, { "murata_mur_r021_1kl_b0" } }, - { 3, { 0x22, 0x22, }, { "murata_mur_r022_1kl_b0" } }, - { 3, { 0x23, 0x22, }, { "murata_mur_r023_1kl_b0" } }, - { 3, { 0x24, 0x22, }, { "murata_mur_r024_1kl_b0" } }, - { 3, { 0x30, 0x22, }, { "murata_mur_r030_1kl_b0" } }, - { 3, { 0x31, 0x22, }, { "murata_mur_r031_1kl_b0" } }, - { 3, { 0x32, 0x22, }, { "murata_mur_r032_1kl_b0" } }, - { 3, { 0x33, 0x22, }, { "murata_mur_r033_1kl_b0" } }, - { 3, { 0x34, 0x22, }, { "murata_mur_r034_1kl_b0" } }, - { 3, { 0x50, 0x22, }, { "murata_mur_r020_1qw_b2" } }, - { 3, { 0x51, 0x22, }, { "murata_mur_r021_1qw_b2" } }, - { 3, { 0x52, 0x22, }, { "murata_mur_r022_1qw_b2" } }, - { 3, { 0x61, 0x22, }, { "murata_mur_r031_1qw_b2" } }, - { 0, { 0x00, }, { "samsung" } } /* Default: Not specified yet */ -#endif /* SUPPORT_MIXED_MODULES */ -}; -#elif defined(BCM4375_CHIP) -vid_info_t vid_info[] = { -#if defined(SUPPORT_MIXED_MODULES) - { 3, { 0x11, 0x33, }, { "semco_sky_e41_es11" } }, - { 3, { 0x33, 0x33, }, { "semco_sem_e43_es33" } }, - { 3, { 0x34, 0x33, }, { "semco_sem_e43_es34" } }, - { 3, { 0x35, 0x33, }, { "semco_sem_e43_es35" } }, - { 3, { 0x36, 0x33, }, { "semco_sem_e43_es36" } }, - { 3, { 0x41, 0x33, }, { "semco_sem_e43_cs41" } }, - { 3, { 0x51, 0x33, }, { "semco_sem_e43_cs51" } }, - { 3, { 0x53, 0x33, }, { "semco_sem_e43_cs53" } }, - { 3, { 0x61, 0x33, }, { "semco_sky_e43_cs61" } }, - { 3, { 0x10, 0x22, }, { "murata_mur_1rh_es10" } }, - { 3, { 0x11, 0x22, }, { "murata_mur_1rh_es11" } }, - { 3, { 0x12, 0x22, }, { "murata_mur_1rh_es12" } }, - { 3, { 0x13, 0x22, }, { "murata_mur_1rh_es13" } }, - { 3, { 0x20, 0x22, }, { "murata_mur_1rh_es20" } }, - { 3, { 0x32, 0x22, }, { "murata_mur_1rh_es32" } }, - { 3, { 0x41, 0x22, }, { "murata_mur_1rh_es41" } }, - { 3, { 0x42, 0x22, }, { "murata_mur_1rh_es42" } }, - { 3, { 0x43, 0x22, }, { "murata_mur_1rh_es43" } }, - { 3, { 0x44, 0x22, }, { "murata_mur_1rh_es44" } } -#endif /* SUPPORT_MIXED_MODULES */ -}; -#elif defined(BCM4389_CHIP_DEF) -vid_info_t vid_info[] = { -#if defined(SUPPORT_MIXED_MODULES) - { 3, { 0x21, 0x33, }, { "semco_sem_e53_es23" } }, - { 3, { 0x23, 0x33, }, { "semco_sem_e53_es23" } }, - { 3, { 0x24, 0x33, }, { "semco_sem_e53_es24" } }, - { 3, { 0x25, 0x33, }, { "semco_sem_e53_es25" } }, - { 3, { 0x31, 0x33, }, { "semco_sem_e53_es31" } }, - { 3, { 0x32, 0x33, }, { "semco_sem_e53_es32" } }, - { 3, { 0x40, 0x33, }, { "semco_sem_e53_es40" } }, - { 3, { 0x21, 0x22, }, { "murata_mur_1wk_es21" } }, - { 3, { 0x30, 0x22, }, { "murata_mur_1wk_es30" } }, - { 3, { 0x31, 0x22, }, { "murata_mur_1wk_es31" } }, - { 3, { 0x32, 0x22, }, { "murata_mur_1wk_es32" } }, - { 3, { 0x40, 0x22, }, { "murata_mur_1wk_es40" } }, - { 3, { 0x41, 0x22, }, { "murata_mur_1wk_es41" } }, - { 3, { 0x42, 0x22, }, { "murata_mur_1wk_es42" } }, - { 3, { 0x43, 0x22, }, { "murata_mur_1wk_es43" } }, - { 3, { 0x50, 0x22, }, { "murata_mur_1wk_es50" } } -#endif /* SUPPORT_MIXED_MODULES */ -}; -#else -vid_info_t vid_info[] = { - { 0, { 0x00, }, { "samsung" } } /* Default: Not specified yet */ -}; -#endif /* BCM_CHIP_ID */ - -/* CID managment functions */ - -char * -dhd_get_cid_info(unsigned char *vid, int vid_length) -{ - int i; - - for (i = 0; i < ARRAYSIZE(vid_info); i++) { - if (vid_info[i].vid_length-1 == vid_length && - !memcmp(vid_info[i].vid, vid, vid_length)) { - return vid_info[i].cid_info; - } - } - - DHD_ERROR(("%s : Can't find the cid info\n", __FUNCTION__)); - return NULL; -} - -int -dhd_check_module_cid(dhd_pub_t *dhdp) -{ - int ret = -1; -#ifndef DHD_EXPORT_CNTL_FILE - const char *cidfilepath = CIDINFO; -#endif /* DHD_EXPORT_CNTL_FILE */ - int idx, max; - vid_info_t *cur_info; - unsigned char *tuple_start = NULL; - unsigned char tuple_length = 0; - unsigned char cid_info[MAX_VNAME_LEN]; - int found = FALSE; -#ifdef SUPPORT_MULTIPLE_BOARDTYPE - board_info_t *cur_b_info = NULL; - board_info_t *vendor_b_info = NULL; - unsigned char *btype_start; - unsigned char boardtype_len = 0; -#endif /* SUPPORT_MULTIPLE_BOARDTYPE */ - - /* Try reading out from CIS */ - if (!g_cis_buf) { - DHD_INFO(("%s: Couldn't read CIS info\n", __FUNCTION__)); - return BCME_ERROR; - } - - DHD_INFO(("%s: Reading CIS from local buffer\n", __FUNCTION__)); -#ifdef DUMP_CIS - dhd_dump_cis_buf(dhdp, DUMP_CIS_SIZE); -#endif /* DUMP_CIS */ - - idx = dhd_find_tuple_idx_from_otp(dhdp, CIS_TUPLE_TAG_VENDOR, &tuple_length); - if (idx > 0) { - found = TRUE; - tuple_start = &g_cis_buf[idx]; - } - - if (found) { - max = sizeof(vid_info) / sizeof(vid_info_t); - for (idx = 0; idx < max; idx++) { - cur_info = &vid_info[idx]; -#ifdef BCM4358_CHIP - if (cur_info->vid_length == 6 && tuple_length == 6) { - if (cur_info->vid[0] == tuple_start[0] && - cur_info->vid[3] == tuple_start[3] && - cur_info->vid[4] == tuple_start[4]) { - goto check_board_type; - } - } -#endif /* BCM4358_CHIP */ - if ((cur_info->vid_length == tuple_length) && - (cur_info->vid_length != 0) && - (memcmp(cur_info->vid, tuple_start, - cur_info->vid_length - 1) == 0)) { - goto check_board_type; - } - } - } - - /* find default nvram, if exist */ - DHD_ERROR(("%s: cannot find CIS TUPLE set as default\n", __FUNCTION__)); - max = sizeof(vid_info) / sizeof(vid_info_t); - for (idx = 0; idx < max; idx++) { - cur_info = &vid_info[idx]; - if (cur_info->vid_length == 0) { - goto write_cid; - } - } - DHD_ERROR(("%s: cannot find default CID\n", __FUNCTION__)); - return BCME_ERROR; - -check_board_type: -#ifdef SUPPORT_MULTIPLE_BOARDTYPE - idx = dhd_find_tuple_idx_from_otp(dhdp, CIS_TUPLE_TAG_BOARDTYPE, &tuple_length); - if (idx > 0) { - btype_start = &g_cis_buf[idx]; - boardtype_len = tuple_length; - DHD_INFO(("%s: board type found.\n", __FUNCTION__)); - } else { - boardtype_len = 0; - } -#if defined(BCM4361_CHIP) - vendor_b_info = semco_PA_info; - max = sizeof(semco_PA_info) / sizeof(board_info_t); -#else - if (strcmp(cur_info->cid_info, "semco") == 0) { - vendor_b_info = semco_board_info; - max = sizeof(semco_board_info) / sizeof(board_info_t); - } else if (strcmp(cur_info->cid_info, "murata") == 0) { - vendor_b_info = murata_board_info; - max = sizeof(murata_board_info) / sizeof(board_info_t); - } else { - max = 0; - } -#endif /* BCM4361_CHIP */ - if (boardtype_len) { - for (idx = 0; idx < max; idx++) { - cur_b_info = vendor_b_info; - if ((cur_b_info->b_len == boardtype_len) && - (cur_b_info->b_len != 0) && - (memcmp(cur_b_info->btype, btype_start, - cur_b_info->b_len - 1) == 0)) { - DHD_INFO(("%s : board type name : %s\n", - __FUNCTION__, cur_b_info->bname)); - break; - } - cur_b_info = NULL; - vendor_b_info++; - } - } -#endif /* SUPPORT_MULTIPLE_BOARDTYPE */ - -write_cid: -#ifdef SUPPORT_MULTIPLE_BOARDTYPE - if (cur_b_info && cur_b_info->b_len > 0) { - strcpy(cid_info, cur_info->cid_info); - strcpy(cid_info + strlen(cur_info->cid_info), cur_b_info->bname); - } else -#endif /* SUPPORT_MULTIPLE_BOARDTYPE */ - strcpy(cid_info, cur_info->cid_info); - - DHD_INFO(("%s: CIS MATCH FOUND : %s\n", __FUNCTION__, cid_info)); -#ifndef DHD_EXPORT_CNTL_FILE - dhd_write_file(cidfilepath, cid_info, strlen(cid_info) + 1); -#else - strlcpy(cidinfostr, cid_info, MAX_VNAME_LEN); -#endif /* DHD_EXPORT_CNTL_FILE */ - - return ret; -} - -#ifdef SUPPORT_MULTIPLE_MODULE_CIS -#ifndef DHD_EXPORT_CNTL_FILE -static bool -dhd_check_module(char *module_name) -{ - char vname[MAX_VNAME_LEN]; - const char *cidfilepath = CIDINFO; - int ret; - - memset(vname, 0, sizeof(vname)); - ret = dhd_read_file(cidfilepath, vname, sizeof(vname) - 1); - if (ret < 0) { - return FALSE; - } - DHD_INFO(("%s: This module is %s \n", __FUNCTION__, vname)); - return strstr(vname, module_name) ? TRUE : FALSE; -} -#else -bool -dhd_check_module(char *module_name) -{ - return strstr(cidinfostr, module_name) ? TRUE : FALSE; -} -#endif /* !DHD_EXPORT_CNTL_FILE */ - -int -dhd_check_module_b85a(void) -{ - int ret; - char *vname_b85a = "_b85a"; - - if (dhd_check_module(vname_b85a)) { - DHD_INFO(("%s: It's a b85a module\n", __FUNCTION__)); - ret = 1; - } else { - DHD_INFO(("%s: It is not a b85a module\n", __FUNCTION__)); - ret = -1; - } - - return ret; -} - -int -dhd_check_module_b90(void) -{ - int ret = 0; - char *vname_b90b = "_b90b"; - char *vname_b90s = "_b90s"; - - if (dhd_check_module(vname_b90b)) { - DHD_INFO(("%s: It's a b90b module \n", __FUNCTION__)); - ret = BCM4359_MODULE_TYPE_B90B; - } else if (dhd_check_module(vname_b90s)) { - DHD_INFO(("%s: It's a b90s module\n", __FUNCTION__)); - ret = BCM4359_MODULE_TYPE_B90S; - } else { - DHD_ERROR(("%s: It's neither b90b nor b90s\n", __FUNCTION__)); - ret = BCME_ERROR; - } - - return ret; -} -#endif /* SUPPORT_MULTIPLE_MODULE_CIS */ - -#define CID_FEM_MURATA "_mur_" -/* extract module type from cid information */ -/* XXX: extract string by delimiter '_' at specific counting position. - * it would be used for module type information. - * for example, cid information is 'semco_sky_r02a_e30a_a1', - * then output (module type) is 'r02a_e30a_a1' when index is 3. - */ -int -dhd_check_module_bcm(char *module_type, int index, bool *is_murata_fem) -{ - int ret = 0, i; - char vname[MAX_VNAME_LEN]; - char *ptr = NULL; -#ifndef DHD_EXPORT_CNTL_FILE - const char *cidfilepath = CIDINFO; -#endif /* DHD_EXPORT_CNTL_FILE */ - - memset(vname, 0, sizeof(vname)); - -#ifndef DHD_EXPORT_CNTL_FILE - ret = dhd_read_file(cidfilepath, vname, sizeof(vname) - 1); - if (ret < 0) { - DHD_ERROR(("%s: failed to get module infomaion from .cid.info\n", - __FUNCTION__)); - return ret; - } -#else - strlcpy(vname, cidinfostr, MAX_VNAME_LEN); -#endif /* DHD_EXPORT_CNTL_FILE */ - - for (i = 1, ptr = vname; i < index && ptr; i++) { - ptr = bcmstrstr(ptr, "_"); - if (ptr) { - ptr++; - } - } - - if (bcmstrnstr(vname, MAX_VNAME_LEN, CID_FEM_MURATA, 5)) { - *is_murata_fem = TRUE; - } - - if (ptr) { - memcpy(module_type, ptr, strlen(ptr)); - } else { - DHD_ERROR(("%s: failed to get module infomaion\n", __FUNCTION__)); - return BCME_ERROR; - } - - DHD_INFO(("%s: module type = %s \n", __FUNCTION__, module_type)); - - return ret; -} -#endif /* USE_CID_CHECK */ - -#ifdef USE_DIRECT_VID_TAG -int -dhd_check_module_cid(dhd_pub_t *dhdp) -{ - int ret = BCME_ERROR; - int idx; - unsigned char tuple_length = 0; - unsigned char *vid = NULL; - unsigned char cid_info[MAX_VNAME_LEN]; -#ifndef DHD_EXPORT_CNTL_FILE - const char *cidfilepath = CIDINFO; -#endif /* DHD_EXPORT_CNTL_FILE */ - - /* Try reading out from CIS */ - if (!g_cis_buf) { - DHD_INFO(("%s: Couldn't read CIS info\n", __FUNCTION__)); - return BCME_ERROR; - } - - DHD_INFO(("%s: Reading CIS from local buffer\n", __FUNCTION__)); -#ifdef DUMP_CIS - dhd_dump_cis_buf(dhdp, DUMP_CIS_SIZE); -#endif /* DUMP_CIS */ - idx = dhd_find_tuple_idx_from_otp(dhdp, CIS_TUPLE_TAG_VENDOR, &tuple_length); - if (idx > 0) { - vid = &g_cis_buf[idx]; - DHD_INFO(("%s: VID FOUND : 0x%x%x\n", __FUNCTION__, - vid[VENDOR_OFF], vid[MD_REV_OFF])); - } else { - DHD_ERROR(("%s: use nvram default\n", __FUNCTION__)); - return BCME_ERROR; - } - - memset(cid_info, 0, sizeof(MAX_VNAME_LEN)); - cid_info[MD_REV_OFF] = vid[MD_REV_OFF]; - cid_info[VENDOR_OFF] = vid[VENDOR_OFF]; -#ifndef DHD_EXPORT_CNTL_FILE - dhd_write_file(cidfilepath, cid_info, strlen(cid_info) + 1); -#else - strlcpy(cidinfostr, cid_info, MAX_VNAME_LEN); -#endif /* DHD_EXPORT_CNTL_FILE */ - - DHD_INFO(("%s: cidinfostr %x%x\n", __FUNCTION__, - cidinfostr[VENDOR_OFF], cidinfostr[MD_REV_OFF])); - return ret; -} - -int -dhd_check_stored_module_info(char *vid) -{ - int ret = BCME_OK; -#ifndef DHD_EXPORT_CNTL_FILE - const char *cidfilepath = CIDINFO; -#endif /* DHD_EXPORT_CNTL_FILE */ - - memset(vid, 0, MAX_VID_LEN); - -#ifndef DHD_EXPORT_CNTL_FILE - ret = dhd_read_file(cidfilepath, vid, MAX_VID_LEN - 1); - if (ret != BCME_OK) { - DHD_ERROR(("%s: failed to get module infomaion from .cid.info\n", - __FUNCTION__)); - return ret; - } -#else - strlcpy(vid, cidinfostr, MAX_VID_LEN); -#endif /* DHD_EXPORT_CNTL_FILE */ - - if (vid[0] == (char)0) { - DHD_ERROR(("%s : Failed to get module information \n", __FUNCTION__)); - return BCME_ERROR; - } - - DHD_INFO(("%s: stored VID= 0x%x%x\n", __FUNCTION__, vid[VENDOR_OFF], vid[MD_REV_OFF])); - return ret; -} -#endif /* USE_DIRECT_VID_TAG */ -#endif /* DHD_USE_CISINFO */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_exynos.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_exynos.c deleted file mode 100755 index 01e1f5482f90..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_exynos.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Platform Dependent file for Samsung Exynos - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_SOC_EXYNOS8895) || defined(CONFIG_SOC_EXYNOS9810) || \ - defined(CONFIG_SOC_EXYNOS9820) || defined(CONFIG_SOC_EXYNOS9830) || \ - defined(CONFIG_SOC_EXYNOS2100) || defined(CONFIG_SOC_EXYNOS1000) -#include -#endif /* CONFIG_SOC_EXYNOS8895 || CONFIG_SOC_EXYNOS9810 || - * CONFIG_SOC_EXYNOS9820 || CONFIG_SOC_EXYNOS9830 || - * CONFIG_SOC_EXYNOS2100 || CONFIG_SOC_EXYNOS1000 - */ - -#if defined(CONFIG_64BIT) -#include -#endif /* CONFIG_64BIT */ - -#ifdef BCMDHD_MODULAR -#if IS_ENABLED(CONFIG_SEC_SYSFS) -#include -#endif /* CONFIG_SEC_SYSFS */ -#if IS_ENABLED(CONFIG_DRV_SAMSUNG) -#include -#endif /* CONFIG_SEC_SYSFS */ -#else -#if defined(CONFIG_SEC_SYSFS) -#include -#elif defined(CONFIG_DRV_SAMSUNG) -#include -#endif /* CONFIG_SEC_SYSFS */ -#endif /* BCMDHD_MODULAR */ -#include - -#if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE) -#define PINCTL_DELAY 150 -#endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */ - -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM -extern void dhd_exit_wlan_mem(void); -extern int dhd_init_wlan_mem(void); -extern void *dhd_wlan_mem_prealloc(int section, unsigned long size); -#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ - -#define WIFI_TURNON_DELAY 200 -static int wlan_pwr_on = -1; - -#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE -static int wlan_host_wake_irq = 0; -static unsigned int wlan_host_wake_up = -1; -#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ - -#if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE) -extern struct device *mmc_dev_for_wlan; -#endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */ - -#ifdef CONFIG_BCMDHD_PCIE -extern int pcie_ch_num; -extern void exynos_pcie_pm_resume(int); -extern void exynos_pcie_pm_suspend(int); -#endif /* CONFIG_BCMDHD_PCIE */ - -#if defined(CONFIG_SOC_EXYNOS7870) || defined(CONFIG_SOC_EXYNOS9110) -extern struct mmc_host *wlan_mmc; -extern void mmc_ctrl_power(struct mmc_host *host, bool onoff); -#endif /* SOC_EXYNOS7870 || CONFIG_SOC_EXYNOS9110 */ - -static int -dhd_wlan_power(int onoff) -{ -#if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE) - struct pinctrl *pinctrl = NULL; -#endif /* CONFIG_MACH_A7LTE || ONFIG_NOBLESSE */ - - printk(KERN_INFO"%s Enter: power %s\n", __FUNCTION__, onoff ? "on" : "off"); - -#if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE) - if (onoff) { - pinctrl = devm_pinctrl_get_select(mmc_dev_for_wlan, "sdio_wifi_on"); - if (IS_ERR(pinctrl)) - printk(KERN_INFO "%s WLAN SDIO GPIO control error\n", __FUNCTION__); - msleep(PINCTL_DELAY); - } -#endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */ - - if (gpio_direction_output(wlan_pwr_on, onoff)) { - printk(KERN_ERR "%s failed to control WLAN_REG_ON to %s\n", - __FUNCTION__, onoff ? "HIGH" : "LOW"); - return -EIO; - } - -#if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE) - if (!onoff) { - pinctrl = devm_pinctrl_get_select(mmc_dev_for_wlan, "sdio_wifi_off"); - if (IS_ERR(pinctrl)) - printk(KERN_INFO "%s WLAN SDIO GPIO control error\n", __FUNCTION__); - } -#endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */ - -#if defined(CONFIG_SOC_EXYNOS7870) || defined(CONFIG_SOC_EXYNOS9110) - if (wlan_mmc) - mmc_ctrl_power(wlan_mmc, onoff); -#endif /* SOC_EXYNOS7870 || CONFIG_SOC_EXYNOS9110 */ - return 0; -} - -static int -dhd_wlan_reset(int onoff) -{ - return 0; -} - -#ifndef CONFIG_BCMDHD_PCIE -extern void (*notify_func_callback)(void *dev_id, int state); -extern void *mmc_host_dev; -#endif /* !CONFIG_BCMDHD_PCIE */ - -static int -dhd_wlan_set_carddetect(int val) -{ -#ifndef CONFIG_BCMDHD_PCIE - pr_err("%s: notify_func=%p, mmc_host_dev=%p, val=%d\n", - __FUNCTION__, notify_func_callback, mmc_host_dev, val); - - if (notify_func_callback) { - notify_func_callback(mmc_host_dev, val); - } else { - pr_warning("%s: Nobody to notify\n", __FUNCTION__); - } -#else - if (val) { - exynos_pcie_pm_resume(pcie_ch_num); - } else { - exynos_pcie_pm_suspend(pcie_ch_num); - } -#endif /* CONFIG_BCMDHD_PCIE */ - - return 0; -} - -int __init -dhd_wlan_init_gpio(void) -{ - const char *wlan_node = "samsung,brcm-wlan"; - struct device_node *root_node = NULL; - struct device *wlan_dev; - - wlan_dev = sec_device_create(NULL, "wlan"); - - root_node = of_find_compatible_node(NULL, NULL, wlan_node); - if (!root_node) { - WARN(1, "failed to get device node of bcm4354\n"); - return -ENODEV; - } - - /* ========== WLAN_PWR_EN ============ */ - wlan_pwr_on = of_get_gpio(root_node, 0); - if (!gpio_is_valid(wlan_pwr_on)) { - WARN(1, "Invalied gpio pin : %d\n", wlan_pwr_on); - return -ENODEV; - } - - if (gpio_request(wlan_pwr_on, "WLAN_REG_ON")) { - WARN(1, "fail to request gpio(WLAN_REG_ON)\n"); - return -ENODEV; - } -#ifdef CONFIG_BCMDHD_PCIE - gpio_direction_output(wlan_pwr_on, 1); - msleep(WIFI_TURNON_DELAY); -#else - gpio_direction_output(wlan_pwr_on, 0); -#endif /* CONFIG_BCMDHD_PCIE */ - gpio_export(wlan_pwr_on, 1); - if (wlan_dev) - gpio_export_link(wlan_dev, "WLAN_REG_ON", wlan_pwr_on); - -#ifdef CONFIG_BCMDHD_PCIE - exynos_pcie_pm_resume(pcie_ch_num); -#endif /* CONFIG_BCMDHD_PCIE */ - -#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE - /* ========== WLAN_HOST_WAKE ============ */ - wlan_host_wake_up = of_get_gpio(root_node, 1); - if (!gpio_is_valid(wlan_host_wake_up)) { - WARN(1, "Invalied gpio pin : %d\n", wlan_host_wake_up); - return -ENODEV; - } - - if (gpio_request(wlan_host_wake_up, "WLAN_HOST_WAKE")) { - WARN(1, "fail to request gpio(WLAN_HOST_WAKE)\n"); - return -ENODEV; - } - gpio_direction_input(wlan_host_wake_up); - gpio_export(wlan_host_wake_up, 1); - if (wlan_dev) - gpio_export_link(wlan_dev, "WLAN_HOST_WAKE", wlan_host_wake_up); - - wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up); -#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ - - return 0; -} - -#if defined(CONFIG_BCMDHD_OOB_HOST_WAKE) && defined(CONFIG_BCMDHD_GET_OOB_STATE) -int -dhd_get_wlan_oob_gpio(void) -{ - return gpio_is_valid(wlan_host_wake_up) ? - gpio_get_value(wlan_host_wake_up) : -1; -} -EXPORT_SYMBOL(dhd_get_wlan_oob_gpio); -#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE && CONFIG_BCMDHD_GET_OOB_STATE */ - -struct resource dhd_wlan_resources = { - .name = "bcmdhd_wlan_irq", - .start = 0, - .end = 0, - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE | -#ifdef CONFIG_BCMDHD_PCIE - IORESOURCE_IRQ_HIGHEDGE, -#else - IORESOURCE_IRQ_HIGHLEVEL, -#endif /* CONFIG_BCMDHD_PCIE */ -}; -EXPORT_SYMBOL(dhd_wlan_resources); - -struct wifi_platform_data dhd_wlan_control = { - .set_power = dhd_wlan_power, - .set_reset = dhd_wlan_reset, - .set_carddetect = dhd_wlan_set_carddetect, -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM - .mem_prealloc = dhd_wlan_mem_prealloc, -#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ -}; -EXPORT_SYMBOL(dhd_wlan_control); - -int __init -dhd_wlan_init(void) -{ - int ret; - - printk(KERN_INFO "%s: START.......\n", __FUNCTION__); - ret = dhd_wlan_init_gpio(); - if (ret < 0) { - printk(KERN_ERR "%s: failed to initiate GPIO, ret=%d\n", - __FUNCTION__, ret); - goto fail; - } - -#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE - dhd_wlan_resources.start = wlan_host_wake_irq; - dhd_wlan_resources.end = wlan_host_wake_irq; -#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ - -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM - ret = dhd_init_wlan_mem(); - if (ret < 0) { - printk(KERN_ERR "%s: failed to alloc reserved memory," - " ret=%d\n", __FUNCTION__, ret); - } -#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ - -fail: - return ret; -} - -int -dhd_wlan_deinit(void) -{ -#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE - gpio_free(wlan_host_wake_up); -#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ - gpio_free(wlan_pwr_on); - -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM - dhd_exit_wlan_mem(); -#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ - return 0; -} - -#ifndef BCMDHD_MODULAR -#if defined(CONFIG_MACH_UNIVERSAL7420) || defined(CONFIG_SOC_EXYNOS8890) || \ - defined(CONFIG_SOC_EXYNOS8895) || defined(CONFIG_SOC_EXYNOS9810) || \ - defined(CONFIG_SOC_EXYNOS9820) || defined(CONFIG_SOC_EXYNOS9830) -#if defined(CONFIG_DEFERRED_INITCALLS) -deferred_module_init(dhd_wlan_init); -#else -late_initcall(dhd_wlan_init); -#endif /* CONFIG_DEFERRED_INITCALLS */ -#else -device_initcall(dhd_wlan_init); -#endif /* CONFIG Exynos PCIE Platforms */ -#endif /* !BCMDHD_MODULAR */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_gpio.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_gpio.c old mode 100755 new mode 100644 index baf4740559b9..21edfc12a9cb --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_gpio.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_gpio.c @@ -1,7 +1,7 @@ /* * Customer code to add GPIO control during WLAN start/stop * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -33,6 +33,8 @@ #include +#include + #ifndef BCMDONGLEHOST #include #include @@ -68,7 +70,7 @@ int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr) { int host_oob_irq = 0; -#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW4) || defined(BOARD_HIKEY) +#if defined(BOARD_HIKEY) host_oob_irq = wifi_platform_get_irq_number(adapter, irq_flags_ptr); #else @@ -87,7 +89,7 @@ int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr) WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", __FUNCTION__, dhd_oob_gpio_num)); -#endif /* CUSTOMER_HW2 || CUSTOMER_HW4 || BOARD_HIKEY */ +#endif /* BOARD_HIKER */ return (host_oob_irq); } @@ -114,8 +116,7 @@ dhd_custom_get_mac_address(void *adapter, unsigned char *buf) return -EINVAL; /* Customer access to MAC address stored outside of DHD driver */ -#if (defined(CUSTOMER_HW2) || defined(CUSTOMER_HW10) || defined(BOARD_HIKEY)) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) +#if defined(BOARD_HIKEY) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) ret = wifi_platform_get_mac_addr(adapter, buf); #endif @@ -131,7 +132,195 @@ dhd_custom_get_mac_address(void *adapter, unsigned char *buf) } #endif /* GET_CUSTOM_MAC_ENABLE */ -#ifndef CUSTOMER_HW4 +#ifdef SYNA_SAR_CUSTOMER_PARAMETER +struct customer_cntry_list { + eCountry_flag_type type; + char ccode[WLC_CNTRY_BUF_SZ]; /* Country code */ +}; + +/* maximum: (A~Z+0~9) * (A~Z+0~9) = (26+10)*(26+10) = 1296 */ +#define MAX_COUNTRY_LIST 500 +struct customer_cntry_list syna_cntry_flag[MAX_COUNTRY_LIST] = { + /* FCC TYPE */ + {SYNA_COUNTRY_TYPE_FCC, "AG"}, + {SYNA_COUNTRY_TYPE_FCC, "AI"}, + {SYNA_COUNTRY_TYPE_FCC, "AR"}, + {SYNA_COUNTRY_TYPE_FCC, "AW"}, + {SYNA_COUNTRY_TYPE_FCC, "BB"}, + {SYNA_COUNTRY_TYPE_FCC, "BL"}, + {SYNA_COUNTRY_TYPE_FCC, "BM"}, + {SYNA_COUNTRY_TYPE_FCC, "BO"}, + {SYNA_COUNTRY_TYPE_FCC, "BS"}, + {SYNA_COUNTRY_TYPE_FCC, "BZ"}, + {SYNA_COUNTRY_TYPE_FCC, "CA"}, + {SYNA_COUNTRY_TYPE_FCC, "CL"}, + {SYNA_COUNTRY_TYPE_FCC, "CO"}, + {SYNA_COUNTRY_TYPE_FCC, "CR"}, + {SYNA_COUNTRY_TYPE_FCC, "CW"}, + {SYNA_COUNTRY_TYPE_FCC, "DO"}, + {SYNA_COUNTRY_TYPE_FCC, "EC"}, + {SYNA_COUNTRY_TYPE_FCC, "FM"}, + {SYNA_COUNTRY_TYPE_FCC, "GT"}, + {SYNA_COUNTRY_TYPE_FCC, "GU"}, + {SYNA_COUNTRY_TYPE_FCC, "GY"}, + {SYNA_COUNTRY_TYPE_FCC, "HN"}, + {SYNA_COUNTRY_TYPE_FCC, "HT"}, + {SYNA_COUNTRY_TYPE_FCC, "IN"}, + {SYNA_COUNTRY_TYPE_FCC, "IR"}, + {SYNA_COUNTRY_TYPE_FCC, "JM"}, + {SYNA_COUNTRY_TYPE_FCC, "KH"}, + {SYNA_COUNTRY_TYPE_FCC, "KN"}, + {SYNA_COUNTRY_TYPE_FCC, "KR"}, + {SYNA_COUNTRY_TYPE_FCC, "KY"}, + {SYNA_COUNTRY_TYPE_FCC, "LC"}, + {SYNA_COUNTRY_TYPE_FCC, "MF"}, + {SYNA_COUNTRY_TYPE_FCC, "MP"}, + {SYNA_COUNTRY_TYPE_FCC, "NI"}, + {SYNA_COUNTRY_TYPE_FCC, "PA"}, + {SYNA_COUNTRY_TYPE_FCC, "PE"}, + {SYNA_COUNTRY_TYPE_FCC, "PG"}, + {SYNA_COUNTRY_TYPE_FCC, "PM"}, + {SYNA_COUNTRY_TYPE_FCC, "PW"}, + {SYNA_COUNTRY_TYPE_FCC, "PR"}, + {SYNA_COUNTRY_TYPE_FCC, "PY"}, + {SYNA_COUNTRY_TYPE_FCC, "SR"}, + {SYNA_COUNTRY_TYPE_FCC, "SV"}, + {SYNA_COUNTRY_TYPE_FCC, "SX"}, + {SYNA_COUNTRY_TYPE_FCC, "TC"}, + {SYNA_COUNTRY_TYPE_FCC, "TT"}, + {SYNA_COUNTRY_TYPE_FCC, "US"}, + {SYNA_COUNTRY_TYPE_FCC, "UY"}, + {SYNA_COUNTRY_TYPE_FCC, "VC"}, + {SYNA_COUNTRY_TYPE_FCC, "VE"}, + {SYNA_COUNTRY_TYPE_FCC, "VG"}, + {SYNA_COUNTRY_TYPE_FCC, "VI"}, + {SYNA_COUNTRY_TYPE_FCC, "VU"}, + {SYNA_COUNTRY_TYPE_FCC, "WF"}, + {SYNA_COUNTRY_TYPE_FCC, "WS"}, + {SYNA_COUNTRY_TYPE_INVALID, ""} +}; + +static int gSyna_country_flag_qty = 55; + +static int syna_country_flag_find(char *cntry) +{ + char country[WLC_CNTRY_BUF_SZ]; + int ret = BCME_NOTFOUND; + int n; + + if (!cntry) { + DHD_ERROR(("%s: invalid cntry!\n", __FUNCTION__)); + return BCME_BADARG; + } else { + n = strcspn(cntry, " ,"); + if ((n != 2) && (n != 3)) { + DHD_ERROR(("%s: invalid n=%d!\n", __FUNCTION__, n)); + return BCME_BUFTOOLONG; + } else { + strlcpy(country, cntry, WLC_CNTRY_BUF_SZ); + country[n] = '\0'; + DHD_TRACE(("%s: here n=%d, country='%s'!\n", + __FUNCTION__, n, country)); + } + } + + n = 0; + while ((MAX_COUNTRY_LIST > n) && + (SYNA_COUNTRY_TYPE_INVALID != syna_cntry_flag[n].type) && + (0 < strlen(syna_cntry_flag[n].ccode))) { + if (!strncmp(country, syna_cntry_flag[n].ccode, WLC_CNTRY_BUF_SZ)) { + ret = n; + break; + } else { + n++; + } + } + + /* sync up the quantity for appending new item */ + if ((MAX_COUNTRY_LIST > n) && + (SYNA_COUNTRY_TYPE_INVALID == syna_cntry_flag[n].type)) { + gSyna_country_flag_qty = n; + DHD_TRACE(("%s: update qty=%d!\n", __FUNCTION__, n)); + } + + return ret; +} + +eCountry_flag_type syna_country_check_type(char *cntry) +{ + int ret = SYNA_COUNTRY_TYPE_INVALID; + int i; + + i = syna_country_flag_find(cntry); + if (0 <= i) { + ret = syna_cntry_flag[i].type; + } + + return ret; +} + +int syna_country_update_type_list(eCountry_flag_type type, char *list_str) +{ + char *next = NULL; + int n = 0; + size_t len; + + if (SYNA_COUNTRY_TYPE_QTY <= type) { + return BCME_BADARG; + } else if ((next = list_str) == NULL) { + return BCME_BADARG; + } + + while ((len = strcspn(next, " ,")) > 0) { + if (len >= WLC_CNTRY_BUF_SZ) { + DHD_ERROR(("%s: string '%s' before ',' or ' ' is too long\n", + __FUNCTION__, next)); + return BCME_ERROR; + } + + n = syna_country_flag_find(next); + if (0 > n) { + if (BCME_NOTFOUND == n) { + if (MAX_COUNTRY_LIST <= (1 + gSyna_country_flag_qty)) { + DHD_ERROR(("%s: too many ccode(max=%d) list: '%s'\n", + __FUNCTION__, MAX_COUNTRY_LIST, list_str)); + break; + } else { + /* adopt this new item */ + n = gSyna_country_flag_qty; + gSyna_country_flag_qty++; + } + } else { + DHD_ERROR(("%s: skip this invalid item '%s', err=%d\n", + __FUNCTION__, next, n)); + } + } + + if (0 <= n) { + /* update or add a new item */ + syna_cntry_flag[n].type = type; + strlcpy(syna_cntry_flag[n].ccode, next, WLC_CNTRY_BUF_SZ); + syna_cntry_flag[n].ccode[len] = '\0'; + DHD_TRACE(("%s: cntry list [%d] type=%d ccode=%s\n", + __FUNCTION__, n, + syna_cntry_flag[n].type, syna_cntry_flag[n].ccode)); + + /* fill with a new blank item as terminate */ + if ((gSyna_country_flag_qty == (n + 1)) && + (MAX_COUNTRY_LIST > gSyna_country_flag_qty)) { + syna_cntry_flag[n+1].type = SYNA_COUNTRY_TYPE_INVALID; + syna_cntry_flag[n+1].ccode[0] = '\0'; + } + } + + next += len; + next += strspn(next, " ,"); + } + + return BCME_OK; +} +#endif /* SYNA_SAR_CUSTOMER_PARAMETER */ + /* Customized Locale table : OPTIONAL feature */ const struct cntry_locales_custom translate_custom_table[] = { /* Table should be filled out based on custom platform regulatory requirement */ @@ -179,7 +368,7 @@ const struct cntry_locales_custom translate_custom_table[] = { {"TR", "TR", 0}, {"NO", "NO", 0}, #endif /* EXMAPLE_TABLE */ -#if (defined(CUSTOMER_HW2) || defined(BOARD_HIKEY)) && !defined(CUSTOMER_HW5) +#if defined(BOARD_HIKEY) #if defined(BCM4335_CHIP) {"", "XZ", 11}, /* Universal if Country code is unknown or empty */ #endif @@ -236,142 +425,7 @@ const struct cntry_locales_custom translate_custom_table[] = { {"PS", "XZ", 11}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ {"TL", "XZ", 11}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ {"MH", "XZ", 11}, /* Universal if Country code is MARSHALL ISLANDS */ -#elif defined(CUSTOMER_HW5) - {"", "XZ", 11}, - {"AE", "AE", 212}, - {"AG", "AG", 2}, - {"AI", "AI", 2}, - {"AL", "AL", 2}, - {"AN", "AN", 3}, - {"AR", "AR", 212}, - {"AS", "AS", 15}, - {"AT", "AT", 4}, - {"AU", "AU", 212}, - {"AW", "AW", 2}, - {"AZ", "AZ", 2}, - {"BA", "BA", 2}, - {"BD", "BD", 2}, - {"BE", "BE", 4}, - {"BG", "BG", 4}, - {"BH", "BH", 4}, - {"BM", "BM", 15}, - {"BN", "BN", 4}, - {"BR", "BR", 212}, - {"BS", "BS", 2}, - {"BY", "BY", 3}, - {"BW", "BW", 1}, - {"CA", "CA", 212}, - {"CH", "CH", 212}, - {"CL", "CL", 212}, - {"CN", "CN", 212}, - {"CO", "CO", 212}, - {"CR", "CR", 21}, - {"CY", "CY", 212}, - {"CZ", "CZ", 212}, - {"DE", "DE", 212}, - {"DK", "DK", 4}, - {"DZ", "DZ", 1}, - {"EC", "EC", 23}, - {"EE", "EE", 4}, - {"EG", "EG", 212}, - {"ES", "ES", 212}, - {"ET", "ET", 2}, - {"FI", "FI", 4}, - {"FR", "FR", 212}, - {"GB", "GB", 212}, - {"GD", "GD", 2}, - {"GF", "GF", 2}, - {"GP", "GP", 2}, - {"GR", "GR", 212}, - {"GT", "GT", 0}, - {"GU", "GU", 17}, - {"HK", "HK", 212}, - {"HR", "HR", 4}, - {"HU", "HU", 4}, - {"IN", "IN", 212}, - {"ID", "ID", 212}, - {"IE", "IE", 5}, - {"IL", "IL", 7}, - {"IN", "IN", 212}, - {"IS", "IS", 4}, - {"IT", "IT", 212}, - {"JO", "JO", 3}, - {"JP", "JP", 212}, - {"KH", "KH", 4}, - {"KI", "KI", 1}, - {"KR", "KR", 212}, - {"KW", "KW", 5}, - {"KY", "KY", 4}, - {"KZ", "KZ", 212}, - {"LA", "LA", 4}, - {"LB", "LB", 6}, - {"LI", "LI", 4}, - {"LK", "LK", 3}, - {"LS", "LS", 2}, - {"LT", "LT", 4}, - {"LR", "LR", 2}, - {"LU", "LU", 3}, - {"LV", "LV", 4}, - {"MA", "MA", 2}, - {"MC", "MC", 1}, - {"MD", "MD", 2}, - {"ME", "ME", 2}, - {"MK", "MK", 2}, - {"MN", "MN", 0}, - {"MO", "MO", 2}, - {"MR", "MR", 2}, - {"MT", "MT", 4}, - {"MQ", "MQ", 2}, - {"MU", "MU", 2}, - {"MV", "MV", 3}, - {"MX", "MX", 212}, - {"MY", "MY", 212}, - {"NI", "NI", 0}, - {"NL", "NL", 212}, - {"NO", "NO", 4}, - {"NP", "NP", 3}, - {"NZ", "NZ", 9}, - {"OM", "OM", 4}, - {"PA", "PA", 17}, - {"PE", "PE", 212}, - {"PG", "PG", 2}, - {"PH", "PH", 212}, - {"PL", "PL", 212}, - {"PR", "PR", 25}, - {"PT", "PT", 212}, - {"PY", "PY", 4}, - {"RE", "RE", 2}, - {"RO", "RO", 212}, - {"RS", "RS", 2}, - {"RU", "RU", 212}, - {"SA", "SA", 212}, - {"SE", "SE", 212}, - {"SG", "SG", 212}, - {"SI", "SI", 4}, - {"SK", "SK", 212}, - {"SN", "SN", 2}, - {"SV", "SV", 25}, - {"TH", "TH", 212}, - {"TR", "TR", 212}, - {"TT", "TT", 5}, - {"TW", "TW", 212}, - {"UA", "UA", 212}, - {"UG", "UG", 2}, - {"US", "US", 212}, - {"UY", "UY", 5}, - {"VA", "VA", 2}, - {"VE", "VE", 3}, - {"VG", "VG", 2}, - {"VI", "VI", 18}, - {"VN", "VN", 4}, - {"YT", "YT", 2}, - {"ZA", "ZA", 212}, - {"ZM", "ZM", 2}, - {"XT", "XT", 212}, - {"XZ", "XZ", 11}, - {"XV", "XV", 17}, - {"Q1", "Q1", 77}, -#endif /* (CUSTOMER_HW2 || BOARD_HIKEY) && CUSTOMER_HW5 */ +#endif /* BOARD_HIKEY */ }; /* Customized Locale convertor @@ -434,4 +488,3 @@ get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t */ #endif /* OEM_ANDROID */ } -#endif /* !CUSTOMER_HW4 */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_hikey.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_hikey.c old mode 100755 new mode 100644 index cb5b71563a90..070fc5695932 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_hikey.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_hikey.c @@ -1,7 +1,7 @@ /* * Platform Dependent file for Hikey * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -47,6 +47,9 @@ extern int dhd_init_wlan_mem(void); extern void *dhd_wlan_mem_prealloc(int section, unsigned long size); #endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ +#define HIKEY_PCIE_VENDOR_ID 0x19e5 +#define HIKEY_PCIE_DEVICE_ID 0x3660 + #define WLAN_REG_ON_GPIO 491 #define WLAN_HOST_WAKE_GPIO 493 @@ -58,6 +61,30 @@ static int wlan_host_wake_up = -1; static int wlan_host_wake_irq = 0; #define WIFI_WLAN_HOST_WAKE_PROPNAME "wl_host_wake" +extern void kirin_pcie_power_on_atu_fixup(void) __attribute__ ((weak)); +extern int kirin_pcie_lp_ctrl(u32 enable) __attribute__ ((weak)); + +void +dhd_wifi_deinit_gpio(void) +{ + /* Disable ASPM before powering off */ + if (kirin_pcie_lp_ctrl) { + kirin_pcie_lp_ctrl(0); + } else { + DHD_ERROR(("[%s] kirin_pcie_lp_ctrl is NULL. " + "ASPM may not work\n", __func__)); + } + if (gpio_direction_output(wlan_reg_on, 0)) { + DHD_ERROR(("%s: WL_REG_ON is failed to pull up\n", __FUNCTION__)); + } + if (gpio_get_value(wlan_reg_on)) { + DHD_INFO(("WL_REG_ON on-step-2 : [%d]\n", + gpio_get_value(wlan_reg_on))); + } + gpio_free(wlan_host_wake_up); + gpio_free(wlan_reg_on); +} + int dhd_wifi_init_gpio(void) { @@ -83,7 +110,7 @@ dhd_wifi_init_gpio(void) * For reg_on, gpio_request will fail if the gpio is configured to output-high * in the dts using gpio-hog, so do not return error for failure. */ - if (gpio_request_one(wlan_reg_on, GPIOF_OUT_INIT_HIGH, "WL_REG_ON")) { + if (gpio_request_one(wlan_reg_on, GPIOF_DIR_OUT, "WL_REG_ON")) { DHD_ERROR(("%s: Failed to request gpio %d for WL_REG_ON, " "might have configured in the dts\n", __FUNCTION__, wlan_reg_on)); @@ -93,7 +120,7 @@ dhd_wifi_init_gpio(void) } gpio_reg_on_val = gpio_get_value(wlan_reg_on); - DHD_INFO(("%s: Initial WL_REG_ON: [%d]\n", + DHD_ERROR(("%s: Initial WL_REG_ON: [%d]\n", __FUNCTION__, gpio_get_value(wlan_reg_on))); if (gpio_reg_on_val == 0) { @@ -102,10 +129,27 @@ dhd_wifi_init_gpio(void) DHD_ERROR(("%s: WL_REG_ON is failed to pull up\n", __FUNCTION__)); return -EIO; } - } + /* Wait for WIFI_TURNON_DELAY due to power stability */ + msleep(WIFI_TURNON_DELAY); - /* Wait for WIFI_TURNON_DELAY due to power stability */ - msleep(WIFI_TURNON_DELAY); + /* + * Call Kiric RC ATU fixup else si_attach will fail due to + * improper BAR0/1 address translations + */ + if (kirin_pcie_power_on_atu_fixup) { + kirin_pcie_power_on_atu_fixup(); + } else { + DHD_ERROR(("[%s] kirin_pcie_power_on_atu_fixup is NULL. " + "REG_ON may not work\n", __func__)); + } + /* Enable ASPM after powering ON */ + if (kirin_pcie_lp_ctrl) { + kirin_pcie_lp_ctrl(1); + } else { + DHD_ERROR(("[%s] kirin_pcie_lp_ctrl is NULL. " + "ASPM may not work\n", __func__)); + } + } /* ========== WLAN_HOST_WAKE ============ */ DHD_INFO(("%s: gpio_wlan_host_wake : %d\n", __FUNCTION__, wlan_host_wake_up)); @@ -130,9 +174,6 @@ dhd_wifi_init_gpio(void) return 0; } -extern void kirin_pcie_power_on_atu_fixup(void) __attribute__ ((weak)); -extern int kirin_pcie_lp_ctrl(u32 enable) __attribute__ ((weak)); - int dhd_wlan_power(int onoff) { @@ -254,6 +295,15 @@ dhd_wlan_init(void) int ret; DHD_INFO(("%s: START.......\n", __FUNCTION__)); +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM + ret = dhd_init_wlan_mem(); + if (ret < 0) { + DHD_ERROR(("%s: failed to alloc reserved memory," + " ret=%d\n", __FUNCTION__, ret)); + goto fail; + } +#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ + ret = dhd_wifi_init_gpio(); if (ret < 0) { DHD_ERROR(("%s: failed to initiate GPIO, ret=%d\n", @@ -264,14 +314,6 @@ dhd_wlan_init(void) dhd_wlan_resources.start = wlan_host_wake_irq; dhd_wlan_resources.end = wlan_host_wake_irq; -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM - ret = dhd_init_wlan_mem(); - if (ret < 0) { - DHD_ERROR(("%s: failed to alloc reserved memory," - " ret=%d\n", __FUNCTION__, ret)); - } -#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ - fail: DHD_INFO(("%s: FINISH.......\n", __FUNCTION__)); return ret; @@ -280,10 +322,20 @@ fail: int dhd_wlan_deinit(void) { - gpio_free(wlan_host_wake_up); - gpio_free(wlan_reg_on); + dhd_wifi_deinit_gpio(); return 0; } + +uint32 dhd_plat_get_rc_vendor_id(void) +{ + return HIKEY_PCIE_VENDOR_ID; +} + +uint32 dhd_plat_get_rc_device_id(void) +{ + return HIKEY_PCIE_DEVICE_ID; +} + #ifndef BCMDHD_MODULAR /* Required only for Built-in DHD */ device_initcall(dhd_wlan_init); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_memprealloc.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_memprealloc.c old mode 100755 new mode 100644 index f43d7e336b21..fac72fe11be3 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_memprealloc.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_memprealloc.c @@ -1,7 +1,7 @@ /* * Platform Dependent file for usage of Preallocted Memory * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -38,7 +38,7 @@ #include #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM - +/* Please refer to 'enum dhd_prealloc_index' in dhd.h */ #define WLAN_STATIC_SCAN_BUF0 5 #define WLAN_STATIC_SCAN_BUF1 6 #define WLAN_STATIC_DHD_INFO_BUF 7 @@ -46,11 +46,11 @@ #define WLAN_STATIC_DHD_IF_FLOW_LKUP 9 #define WLAN_STATIC_DHD_MEMDUMP_RAM 11 #define WLAN_STATIC_DHD_WLFC_HANGER 12 -#define WLAN_STATIC_DHD_PKTID_MAP 13 -#define WLAN_STATIC_DHD_PKTID_IOCTL_MAP 14 +#define WLAN_STATIC_DHD_PKTID_MAP 13 /* Deprecated */ +#define WLAN_STATIC_DHD_PKTID_IOCTL_MAP 14 /* Deprecated */ #define WLAN_STATIC_DHD_LOG_DUMP_BUF 15 #define WLAN_STATIC_DHD_LOG_DUMP_BUF_EX 16 -#define WLAN_STATIC_DHD_PKTLOG_DUMP_BUF 17 +#define WLAN_STATIC_DHD_PKTLOG_DUMP_BUF 17 /* Deprecated */ #define WLAN_SCAN_BUF_SIZE (64 * 1024) @@ -112,7 +112,7 @@ ((WLAN_MAX_PKTID_IOCTL_ITEMS+1) * WLAN_DHD_PKTID_IOCTL_MAP_ITEM_SIZE)) #define DHD_LOG_DUMP_BUF_SIZE (1024 * 1024 * 4) -#define DHD_LOG_DUMP_BUF_EX_SIZE (1024 * 1024 * 2) +#define DHD_LOG_DUMP_BUF_EX_SIZE (1024 * 8) #define DHD_PKTLOG_DUMP_BUF_SIZE (64 * 1024) @@ -138,15 +138,17 @@ static struct wlan_mem_prealloc wlan_mem_array[PREALLOC_WLAN_SEC_NUM] = { static void *wlan_static_scan_buf0 = NULL; static void *wlan_static_scan_buf1 = NULL; static void *wlan_static_dhd_info_buf = NULL; -static void *wlan_static_dhd_wlfc_buf = NULL; +#ifdef CONFIG_BCMDHD_PCIE static void *wlan_static_if_flow_lkup = NULL; -static void *wlan_static_dhd_memdump_ram = NULL; +#else +static void *wlan_static_dhd_wlfc_buf = NULL; static void *wlan_static_dhd_wlfc_hanger = NULL; -static void *wlan_static_dhd_pktid_map = NULL; -static void *wlan_static_dhd_pktid_ioctl_map = NULL; +#endif /* CONFIG_BCMDHD_PCIE */ +#ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP +static void *wlan_static_dhd_memdump_ram = NULL; +#endif /* #ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP */ static void *wlan_static_dhd_log_dump_buf = NULL; static void *wlan_static_dhd_log_dump_buf_ex = NULL; -static void *wlan_static_dhd_pktlog_dump_buf = NULL; void dhd_exit_wlan_mem(void); @@ -174,7 +176,17 @@ void } return wlan_static_dhd_info_buf; } - +#ifdef CONFIG_BCMDHD_PCIE + if (section == WLAN_STATIC_DHD_IF_FLOW_LKUP) { + if (size > WLAN_DHD_IF_FLOW_LKUP_SIZE) { + pr_err("request DHD_WLFC size(%lu) is bigger than" + " static size(%d).\n", + size, WLAN_DHD_WLFC_BUF_SIZE); + return NULL; + } + return wlan_static_if_flow_lkup; + } +#else if (section == WLAN_STATIC_DHD_WLFC_BUF) { if (size > WLAN_DHD_WLFC_BUF_SIZE) { pr_err("request DHD_WLFC size(%lu) is bigger than" @@ -194,17 +206,8 @@ void } return wlan_static_dhd_wlfc_hanger; } - - if (section == WLAN_STATIC_DHD_IF_FLOW_LKUP) { - if (size > WLAN_DHD_IF_FLOW_LKUP_SIZE) { - pr_err("request DHD_WLFC size(%lu) is bigger than" - " static size(%d).\n", - size, WLAN_DHD_WLFC_BUF_SIZE); - return NULL; - } - return wlan_static_if_flow_lkup; - } - +#endif /* CONFIG_BCMDHD_PCIE */ +#ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP if (section == WLAN_STATIC_DHD_MEMDUMP_RAM) { if (size > WLAN_DHD_MEMDUMP_SIZE) { pr_err("request DHD_MEMDUMP_RAM size(%lu) is bigger" @@ -214,27 +217,7 @@ void } return wlan_static_dhd_memdump_ram; } - - if (section == WLAN_STATIC_DHD_PKTID_MAP) { - if (size > WLAN_DHD_PKTID_MAP_SIZE) { - pr_err("request DHD_PKTID_MAP size(%lu) is bigger than" - " static size(%d).\n", - size, WLAN_DHD_PKTID_MAP_SIZE); - return NULL; - } - return wlan_static_dhd_pktid_map; - } - - if (section == WLAN_STATIC_DHD_PKTID_IOCTL_MAP) { - if (size > WLAN_DHD_PKTID_IOCTL_MAP_SIZE) { - pr_err("request DHD_PKTID_IOCTL_MAP size(%lu) is bigger than" - " static size(%d).\n", - size, WLAN_DHD_PKTID_IOCTL_MAP_SIZE); - return NULL; - } - return wlan_static_dhd_pktid_ioctl_map; - } - +#endif /* CONFIG_BCMDHD_PREALLOC_MEMDUMP */ if (section == WLAN_STATIC_DHD_LOG_DUMP_BUF) { if (size > DHD_LOG_DUMP_BUF_SIZE) { pr_err("request DHD_LOG_DUMP_BUF size(%lu) is bigger then" @@ -255,16 +238,6 @@ void return wlan_static_dhd_log_dump_buf_ex; } - if (section == WLAN_STATIC_DHD_PKTLOG_DUMP_BUF) { - if (size > DHD_PKTLOG_DUMP_BUF_SIZE) { - pr_err("request DHD_PKTLOG_DUMP_BUF size(%lu) is bigger then" - " static size(%d).\n", - size, DHD_PKTLOG_DUMP_BUF_SIZE); - return NULL; - } - return wlan_static_dhd_pktlog_dump_buf; - } - if ((section < 0) || (section >= PREALLOC_WLAN_SEC_NUM)) { return NULL; } @@ -277,6 +250,13 @@ void } EXPORT_SYMBOL(dhd_wlan_mem_prealloc); +#ifdef DHD_DUMP_BUF_KVMALLOC +#define DUMP_BUF_MALLOC(size) kvmalloc(size, GFP_KERNEL) +#define DUMP_BUF_MFREE(addr) kvfree(addr) +#else +#define DUMP_BUF_MALLOC(size) kmalloc(size, GFP_KERNEL) +#define DUMP_BUF_MFREE(addr) kfree(addr) +#endif /* DHD_DUMP_BUF_KVMALLOC */ int dhd_init_wlan_mem(void) { @@ -311,8 +291,13 @@ dhd_init_wlan_mem(void) for (i = 0; i < PREALLOC_WLAN_SEC_NUM; i++) { if (wlan_mem_array[i].size > 0) { +#ifdef CONFIG_BCMDHD_PCIE + wlan_mem_array[i].mem_ptr = + kvmalloc(wlan_mem_array[i].size, GFP_KERNEL); +#else wlan_mem_array[i].mem_ptr = kmalloc(wlan_mem_array[i].size, GFP_KERNEL); +#endif /* CONFIG_BCMDHD_PCIE */ if (!wlan_mem_array[i].mem_ptr) { pr_err("Failed to mem_alloc for WLAN\n"); @@ -321,59 +306,55 @@ dhd_init_wlan_mem(void) } } +#ifdef CONFIG_BCMDHD_PCIE + wlan_static_scan_buf0 = kvmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL); +#else wlan_static_scan_buf0 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL); +#endif /* CONFIG_BCMDHD_PCIE */ if (!wlan_static_scan_buf0) { pr_err("Failed to alloc wlan_static_scan_buf0\n"); goto err_mem_alloc; } +#ifdef CONFIG_BCMDHD_PCIE + wlan_static_scan_buf1 = kvmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL); +#else wlan_static_scan_buf1 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL); +#endif /* CONFIG_BCMDHD_PCIE */ if (!wlan_static_scan_buf1) { pr_err("Failed to alloc wlan_static_scan_buf1\n"); goto err_mem_alloc; } - wlan_static_dhd_log_dump_buf = kmalloc(DHD_LOG_DUMP_BUF_SIZE, GFP_KERNEL); + wlan_static_dhd_log_dump_buf = DUMP_BUF_MALLOC(DHD_LOG_DUMP_BUF_SIZE); if (!wlan_static_dhd_log_dump_buf) { pr_err("Failed to alloc wlan_static_dhd_log_dump_buf\n"); goto err_mem_alloc; } - wlan_static_dhd_log_dump_buf_ex = kmalloc(DHD_LOG_DUMP_BUF_EX_SIZE, GFP_KERNEL); + wlan_static_dhd_log_dump_buf_ex = DUMP_BUF_MALLOC(DHD_LOG_DUMP_BUF_EX_SIZE); if (!wlan_static_dhd_log_dump_buf_ex) { pr_err("Failed to alloc wlan_static_dhd_log_dump_buf_ex\n"); goto err_mem_alloc; } +#ifdef CONFIG_BCMDHD_PCIE + wlan_static_dhd_info_buf = kvmalloc(WLAN_DHD_INFO_BUF_SIZE, GFP_KERNEL); +#else wlan_static_dhd_info_buf = kmalloc(WLAN_DHD_INFO_BUF_SIZE, GFP_KERNEL); +#endif /* CONFIG_BCMDHD_PCIE */ if (!wlan_static_dhd_info_buf) { pr_err("Failed to alloc wlan_static_dhd_info_buf\n"); goto err_mem_alloc; } #ifdef CONFIG_BCMDHD_PCIE - wlan_static_if_flow_lkup = kmalloc(WLAN_DHD_IF_FLOW_LKUP_SIZE, + wlan_static_if_flow_lkup = kvmalloc(WLAN_DHD_IF_FLOW_LKUP_SIZE, GFP_KERNEL); if (!wlan_static_if_flow_lkup) { pr_err("Failed to alloc wlan_static_if_flow_lkup\n"); goto err_mem_alloc; } - -#ifdef CONFIG_BCMDHD_PREALLOC_PKTIDMAP - wlan_static_dhd_pktid_map = kmalloc(WLAN_DHD_PKTID_MAP_SIZE, - GFP_KERNEL); - if (!wlan_static_dhd_pktid_map) { - pr_err("Failed to alloc wlan_static_dhd_pktid_map\n"); - goto err_mem_alloc; - } - - wlan_static_dhd_pktid_ioctl_map = kmalloc(WLAN_DHD_PKTID_IOCTL_MAP_SIZE, - GFP_KERNEL); - if (!wlan_static_dhd_pktid_ioctl_map) { - pr_err("Failed to alloc wlan_static_dhd_pktid_ioctl_map\n"); - goto err_mem_alloc; - } -#endif /* CONFIG_BCMDHD_PREALLOC_PKTIDMAP */ #else wlan_static_dhd_wlfc_buf = kmalloc(WLAN_DHD_WLFC_BUF_SIZE, GFP_KERNEL); @@ -391,19 +372,13 @@ dhd_init_wlan_mem(void) #endif /* CONFIG_BCMDHD_PCIE */ #ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP - wlan_static_dhd_memdump_ram = kmalloc(WLAN_DHD_MEMDUMP_SIZE, GFP_KERNEL); + wlan_static_dhd_memdump_ram = DUMP_BUF_MALLOC(WLAN_DHD_MEMDUMP_SIZE); if (!wlan_static_dhd_memdump_ram) { pr_err("Failed to alloc wlan_static_dhd_memdump_ram\n"); goto err_mem_alloc; } #endif /* CONFIG_BCMDHD_PREALLOC_MEMDUMP */ - wlan_static_dhd_pktlog_dump_buf = kmalloc(DHD_PKTLOG_DUMP_BUF_SIZE, GFP_KERNEL); - if (!wlan_static_dhd_pktlog_dump_buf) { - pr_err("Failed to alloc wlan_static_dhd_pktlog_dump_buf\n"); - goto err_mem_alloc; - } - pr_err("%s: WIFI MEM Allocated\n", __FUNCTION__); return 0; @@ -432,25 +407,14 @@ dhd_exit_wlan_mem(void) #ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP if (wlan_static_dhd_memdump_ram) { - kfree(wlan_static_dhd_memdump_ram); + DUMP_BUF_MFREE(wlan_static_dhd_memdump_ram); } - #endif /* CONFIG_BCMDHD_PREALLOC_MEMDUMP */ #ifdef CONFIG_BCMDHD_PCIE if (wlan_static_if_flow_lkup) { - kfree(wlan_static_if_flow_lkup); + kvfree(wlan_static_if_flow_lkup); } - -#ifdef CONFIG_BCMDHD_PREALLOC_PKTIDMAP - if (wlan_static_dhd_pktid_map) { - kfree(wlan_static_dhd_pktid_map); - } - - if (wlan_static_dhd_pktid_ioctl_map) { - kfree(wlan_static_dhd_pktid_ioctl_map); - } -#endif /* CONFIG_BCMDHD_PREALLOC_PKTIDMAP */ #else if (wlan_static_dhd_wlfc_buf) { kfree(wlan_static_dhd_wlfc_buf); @@ -461,32 +425,44 @@ dhd_exit_wlan_mem(void) } #endif /* CONFIG_BCMDHD_PCIE */ if (wlan_static_dhd_info_buf) { +#ifdef CONFIG_BCMDHD_PCIE + kvfree(wlan_static_dhd_info_buf); +#else kfree(wlan_static_dhd_info_buf); +#endif /* CONFIG_BCMDHD_PCIE */ } if (wlan_static_dhd_log_dump_buf) { - kfree(wlan_static_dhd_log_dump_buf); + DUMP_BUF_MFREE(wlan_static_dhd_log_dump_buf); } if (wlan_static_dhd_log_dump_buf_ex) { - kfree(wlan_static_dhd_log_dump_buf_ex); + DUMP_BUF_MFREE(wlan_static_dhd_log_dump_buf_ex); } if (wlan_static_scan_buf1) { +#ifdef CONFIG_BCMDHD_PCIE + kvfree(wlan_static_scan_buf1); +#else kfree(wlan_static_scan_buf1); +#endif /* CONFIG_BCMDHD_PCIE */ } if (wlan_static_scan_buf0) { +#ifdef CONFIG_BCMDHD_PCIE + kvfree(wlan_static_scan_buf0); +#else kfree(wlan_static_scan_buf0); - } - - if (wlan_static_dhd_pktlog_dump_buf) { - kfree(wlan_static_dhd_pktlog_dump_buf); +#endif /* CONFIG_BCMDHD_PCIE */ } for (i = 0; i < PREALLOC_WLAN_SEC_NUM; i++) { if (wlan_mem_array[i].mem_ptr) { +#ifdef CONFIG_BCMDHD_PCIE + kvfree(wlan_mem_array[i].mem_ptr); +#else kfree(wlan_mem_array[i].mem_ptr); +#endif /* CONFIG_BCMDHD_PCIE */ } } diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_msm.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_msm.c deleted file mode 100755 index eb16b69f1401..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_msm.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Platform Dependent file for Qualcomm MSM/APQ - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_BCMDHD_PCIE -#include -#endif /* CONFIG_BCMDHD_PCIE */ -#include -#include -#include -#include - -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM -extern void dhd_exit_wlan_mem(void); -extern int dhd_init_wlan_mem(void); -extern void *dhd_wlan_mem_prealloc(int section, unsigned long size); -#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ - -#define WIFI_TURNON_DELAY 200 -static int wlan_reg_on = -1; -#define DHD_DT_COMPAT_ENTRY "android,bcmdhd_wlan" -#ifdef CUSTOMER_HW2 -#define WIFI_WL_REG_ON_PROPNAME "wl_reg_on" -#else -#define WIFI_WL_REG_ON_PROPNAME "wlan-en-gpio" -#endif /* CUSTOMER_HW2 */ - -#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_ARCH_MSM8998) || \ - defined(CONFIG_ARCH_SDM845) || defined(CONFIG_ARCH_SM8150) || \ - defined(CONFIG_ARCH_KONA) || defined(CONFIG_ARCH_LAHAINA) -#define MSM_PCIE_CH_NUM 0 -#else -#define MSM_PCIE_CH_NUM 1 -#endif /* MSM PCIE Platforms */ - -#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE -static int wlan_host_wake_up = -1; -static int wlan_host_wake_irq = 0; -#ifdef CUSTOMER_HW2 -#define WIFI_WLAN_HOST_WAKE_PROPNAME "wl_host_wake" -#else -#define WIFI_WLAN_HOST_WAKE_PROPNAME "wlan-host-wake-gpio" -#endif /* CUSTOMER_HW2 */ -#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ - -int __init -dhd_wifi_init_gpio(void) -{ - char *wlan_node = DHD_DT_COMPAT_ENTRY; - struct device_node *root_node = NULL; - - root_node = of_find_compatible_node(NULL, NULL, wlan_node); - if (!root_node) { - WARN(1, "failed to get device node of BRCM WLAN\n"); - return -ENODEV; - } - - /* ========== WLAN_PWR_EN ============ */ - wlan_reg_on = of_get_named_gpio(root_node, WIFI_WL_REG_ON_PROPNAME, 0); - printk(KERN_INFO "%s: gpio_wlan_power : %d\n", __FUNCTION__, wlan_reg_on); - - if (gpio_request_one(wlan_reg_on, GPIOF_OUT_INIT_LOW, "WL_REG_ON")) { - printk(KERN_ERR "%s: Faiiled to request gpio %d for WL_REG_ON\n", - __FUNCTION__, wlan_reg_on); - } else { - printk(KERN_ERR "%s: gpio_request WL_REG_ON done - WLAN_EN: GPIO %d\n", - __FUNCTION__, wlan_reg_on); - } - - if (gpio_direction_output(wlan_reg_on, 1)) { - printk(KERN_ERR "%s: WL_REG_ON failed to pull up\n", __FUNCTION__); - } else { - printk(KERN_ERR "%s: WL_REG_ON is pulled up\n", __FUNCTION__); - } - - if (gpio_get_value(wlan_reg_on)) { - printk(KERN_INFO "%s: Initial WL_REG_ON: [%d]\n", - __FUNCTION__, gpio_get_value(wlan_reg_on)); - } - - /* Wait for WIFI_TURNON_DELAY due to power stability */ - msleep(WIFI_TURNON_DELAY); - -#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE - /* ========== WLAN_HOST_WAKE ============ */ - wlan_host_wake_up = of_get_named_gpio(root_node, WIFI_WLAN_HOST_WAKE_PROPNAME, 0); - printk(KERN_INFO "%s: gpio_wlan_host_wake : %d\n", __FUNCTION__, wlan_host_wake_up); - -#ifndef CUSTOMER_HW2 - if (gpio_request_one(wlan_host_wake_up, GPIOF_IN, "WLAN_HOST_WAKE")) { - printk(KERN_ERR "%s: Faiiled to request gpio %d for WLAN_HOST_WAKE\n", - __FUNCTION__, wlan_host_wake_up); - return -ENODEV; - } else { - printk(KERN_ERR "%s: gpio_request WLAN_HOST_WAKE done" - " - WLAN_HOST_WAKE: GPIO %d\n", - __FUNCTION__, wlan_host_wake_up); - } -#endif /* !CUSTOMER_HW2 */ - - gpio_direction_input(wlan_host_wake_up); - wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up); -#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ - -#ifdef CONFIG_BCMDHD_PCIE - printk(KERN_INFO "%s: Call msm_pcie_enumerate\n", __FUNCTION__); - msm_pcie_enumerate(MSM_PCIE_CH_NUM); -#endif /* CONFIG_BCMDHD_PCIE */ - - return 0; -} - -int -dhd_wlan_power(int onoff) -{ - printk(KERN_INFO"%s Enter: power %s\n", __func__, onoff ? "on" : "off"); - - if (onoff) { - if (gpio_direction_output(wlan_reg_on, 1)) { - printk(KERN_ERR "%s: WL_REG_ON is failed to pull up\n", __FUNCTION__); - return -EIO; - } - if (gpio_get_value(wlan_reg_on)) { - printk(KERN_INFO"WL_REG_ON on-step-2 : [%d]\n", - gpio_get_value(wlan_reg_on)); - } else { - printk("[%s] gpio value is 0. We need reinit.\n", __func__); - if (gpio_direction_output(wlan_reg_on, 1)) { - printk(KERN_ERR "%s: WL_REG_ON is " - "failed to pull up\n", __func__); - } - } - } else { - if (gpio_direction_output(wlan_reg_on, 0)) { - printk(KERN_ERR "%s: WL_REG_ON is failed to pull up\n", __FUNCTION__); - return -EIO; - } - if (gpio_get_value(wlan_reg_on)) { - printk(KERN_INFO"WL_REG_ON on-step-2 : [%d]\n", - gpio_get_value(wlan_reg_on)); - } - } - return 0; -} -EXPORT_SYMBOL(dhd_wlan_power); - -static int -dhd_wlan_reset(int onoff) -{ - return 0; -} - -static int -dhd_wlan_set_carddetect(int val) -{ -#ifdef CONFIG_BCMDHD_PCIE - printk(KERN_INFO "%s: Call msm_pcie_enumerate\n", __FUNCTION__); - msm_pcie_enumerate(MSM_PCIE_CH_NUM); -#endif /* CONFIG_BCMDHD_PCIE */ - return 0; -} - -#if defined(CONFIG_BCMDHD_OOB_HOST_WAKE) && defined(CONFIG_BCMDHD_GET_OOB_STATE) -int -dhd_get_wlan_oob_gpio(void) -{ - return gpio_is_valid(wlan_host_wake_up) ? - gpio_get_value(wlan_host_wake_up) : -1; -} -EXPORT_SYMBOL(dhd_get_wlan_oob_gpio); -#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE && CONFIG_BCMDHD_GET_OOB_STATE */ - -struct resource dhd_wlan_resources = { - .name = "bcmdhd_wlan_irq", - .start = 0, /* Dummy */ - .end = 0, /* Dummy */ - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE | -#ifdef CONFIG_BCMDHD_PCIE - IORESOURCE_IRQ_HIGHEDGE, -#else - IORESOURCE_IRQ_HIGHLEVEL, -#endif /* CONFIG_BCMDHD_PCIE */ -}; -EXPORT_SYMBOL(dhd_wlan_resources); - -struct wifi_platform_data dhd_wlan_control = { - .set_power = dhd_wlan_power, - .set_reset = dhd_wlan_reset, - .set_carddetect = dhd_wlan_set_carddetect, -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM - .mem_prealloc = dhd_wlan_mem_prealloc, -#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ -}; -EXPORT_SYMBOL(dhd_wlan_control); - -int __init -dhd_wlan_init(void) -{ - int ret; - - printk(KERN_INFO"%s: START.......\n", __FUNCTION__); - ret = dhd_wifi_init_gpio(); - if (ret < 0) { - printk(KERN_ERR "%s: failed to initiate GPIO, ret=%d\n", - __FUNCTION__, ret); - goto fail; - } - -#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE - dhd_wlan_resources.start = wlan_host_wake_irq; - dhd_wlan_resources.end = wlan_host_wake_irq; -#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ - -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM - ret = dhd_init_wlan_mem(); - if (ret < 0) { - printk(KERN_ERR "%s: failed to alloc reserved memory," - " ret=%d\n", __FUNCTION__, ret); - } -#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ - -fail: - printk(KERN_INFO"%s: FINISH.......\n", __FUNCTION__); - return ret; -} - -int -dhd_wlan_deinit(void) -{ -#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE - gpio_free(wlan_host_wake_up); -#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ - gpio_free(wlan_reg_on); - -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM - dhd_exit_wlan_mem(); -#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ - return 0; -} - -#ifndef BCMDHD_MODULAR -#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_ARCH_MSM8998) || \ - defined(CONFIG_ARCH_SDM845) || defined(CONFIG_ARCH_SM8150) || \ - defined(CONFIG_ARCH_KONA) || defined(CONFIG_ARCH_LAHAINA) -#if defined(CONFIG_DEFERRED_INITCALLS) -deferred_module_init(dhd_wlan_init); -#else -late_initcall(dhd_wlan_init); -#endif /* CONFIG_DEFERRED_INITCALLS */ -#else -device_initcall(dhd_wlan_init); -#endif /* MSM PCIE Platforms */ -#endif /* !BCMDHD_MODULAR */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_sec.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_sec.c deleted file mode 100755 index fd5607bcb113..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_custom_sec.c +++ /dev/null @@ -1,1040 +0,0 @@ -/* - * Customer HW 4 dependant file - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id: dhd_custom_sec.c 334946 2012-05-24 20:38:00Z chanyun $ - */ -#if defined(CUSTOMER_HW4) || defined(CUSTOMER_HW40) -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include /* need to still support chips no longer in trunk firmware */ - -#include -#include - -const struct cntry_locales_custom translate_custom_table[] = { - /* default ccode/regrev */ - {"", "XZ", 11}, /* Universal if Country code is unknown or empty */ - {"IR", "XZ", 11}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */ - {"SD", "XZ", 11}, /* Universal if Country code is SUDAN */ - {"PS", "XZ", 11}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ - {"TL", "XZ", 11}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ - {"MH", "XZ", 11}, /* Universal if Country code is MARSHALL ISLANDS */ - {"GL", "GP", 2}, - {"AL", "AL", 2}, -#ifdef DHD_SUPPORT_GB_999 - {"DZ", "GB", 999}, -#else - {"DZ", "GB", 6}, -#endif /* DHD_SUPPORT_GB_999 */ - {"AS", "AS", 12}, - {"AI", "AI", 1}, - {"AF", "AD", 0}, - {"AG", "AG", 2}, - {"AR", "AU", 6}, - {"AW", "AW", 2}, - {"AU", "AU", 6}, - {"AT", "AT", 4}, - {"AZ", "AZ", 2}, - {"BS", "BS", 2}, - {"BH", "BH", 4}, - {"BD", "BD", 1}, - {"BY", "BY", 3}, - {"BE", "BE", 4}, - {"BM", "BM", 12}, - {"BA", "BA", 2}, - {"BR", "BR", 2}, - {"VG", "VG", 2}, - {"BN", "BN", 4}, - {"BG", "BG", 4}, - {"KH", "KH", 2}, - {"KY", "KY", 3}, - {"CN", "CN", 38}, - {"CO", "CO", 17}, - {"CR", "CR", 17}, - {"HR", "HR", 4}, - {"CY", "CY", 4}, - {"CZ", "CZ", 4}, - {"DK", "DK", 4}, - {"EE", "EE", 4}, - {"ET", "ET", 2}, - {"FI", "FI", 4}, - {"FR", "FR", 5}, - {"GF", "GF", 2}, - {"DE", "DE", 7}, - {"GR", "GR", 4}, - {"GD", "GD", 2}, - {"GP", "GP", 2}, - {"GU", "GU", 30}, - {"HK", "HK", 2}, - {"HU", "HU", 4}, - {"IS", "IS", 4}, - {"IN", "IN", 3}, - {"ID", "ID", 1}, - {"IE", "IE", 5}, - {"IL", "IL", 14}, - {"IT", "IT", 4}, - {"JP", "JP", 45}, - {"JO", "JO", 3}, - {"KE", "SA", 0}, - {"KW", "KW", 5}, - {"LA", "LA", 2}, - {"LV", "LV", 4}, - {"LB", "LB", 5}, - {"LS", "LS", 2}, - {"LI", "LI", 4}, - {"LT", "LT", 4}, - {"LU", "LU", 3}, - {"MO", "SG", 0}, - {"MK", "MK", 2}, - {"MW", "MW", 1}, - {"MY", "MY", 3}, - {"MV", "MV", 3}, - {"MT", "MT", 4}, - {"MQ", "MQ", 2}, - {"MR", "MR", 2}, - {"MU", "MU", 2}, - {"YT", "YT", 2}, - {"MX", "MX", 44}, - {"MD", "MD", 2}, - {"MC", "MC", 1}, - {"ME", "ME", 2}, - {"MA", "MA", 2}, - {"NL", "NL", 4}, - {"AN", "GD", 2}, - {"NZ", "NZ", 4}, - {"NO", "NO", 4}, - {"OM", "OM", 4}, - {"PA", "PA", 17}, - {"PG", "AU", 6}, - {"PY", "PY", 2}, - {"PE", "PE", 20}, - {"PH", "PH", 5}, - {"PL", "PL", 4}, - {"PT", "PT", 4}, - {"PR", "PR", 38}, - {"RE", "RE", 2}, - {"RO", "RO", 4}, - {"SN", "MA", 2}, - {"RS", "RS", 2}, - {"SK", "SK", 4}, - {"SI", "SI", 4}, - {"ES", "ES", 4}, - {"LK", "LK", 1}, - {"SE", "SE", 4}, - {"CH", "CH", 4}, - {"TW", "TW", 1}, - {"TH", "TH", 5}, - {"TT", "TT", 3}, - {"TR", "TR", 7}, - {"AE", "AE", 6}, -#ifdef DHD_SUPPORT_GB_999 - {"GB", "GB", 999}, -#else - {"GB", "GB", 6}, -#endif /* DHD_SUPPORT_GB_999 */ - {"UY", "VE", 3}, - {"VI", "PR", 38}, - {"VA", "VA", 2}, - {"VE", "VE", 3}, - {"VN", "VN", 4}, - {"ZM", "LA", 2}, - {"EC", "EC", 21}, - {"SV", "SV", 25}, -#if defined(BCM4358_CHIP) || defined(BCM4359_CHIP) - {"KR", "KR", 70}, -#else - {"KR", "KR", 48}, -#endif - {"RU", "RU", 13}, - {"UA", "UA", 8}, - {"GT", "GT", 1}, - {"MN", "MN", 1}, - {"NI", "NI", 2}, - {"UZ", "MA", 2}, - {"ZA", "ZA", 6}, - {"EG", "EG", 13}, - {"TN", "TN", 1}, - {"AO", "AD", 0}, - {"BT", "BJ", 0}, - {"BW", "BJ", 0}, - {"LY", "LI", 4}, - {"BO", "NG", 0}, - {"UM", "PR", 38}, - /* Support FCC 15.407 (Part 15E) Changes, effective June 2 2014 */ - /* US/988, Q2/993 country codes with higher power on UNII-1 5G band */ - {"US", "US", 988}, - {"CU", "US", 988}, - {"CA", "Q2", 993}, -}; - -/* Customized Locale convertor -* input : ISO 3166-1 country abbreviation -* output: customized cspec -*/ -void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec) -{ - int size, i; - - size = ARRAYSIZE(translate_custom_table); - - if (cspec == 0) - return; - - if (size == 0) - return; - - for (i = 0; i < size; i++) { - if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { - memcpy(cspec->ccode, - translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = translate_custom_table[i].custom_locale_rev; - return; - } - } - return; -} - -#define PSMINFO PLATFORM_PATH".psm.info" -#define ANTINFO PLATFORM_PATH".ant.info" -#define WIFIVERINFO PLATFORM_PATH".wifiver.info" -#define LOGTRACEINFO PLATFORM_PATH".logtrace.info" -#define SOFTAPINFO PLATFORM_PATH".softap.info" - -#ifdef DHD_PM_CONTROL_FROM_FILE -/* XXX This function used for setup PM related value control by read from file. - * Normally, PM related value Turn Offed for MFG process - */ -extern bool g_pm_control; -#ifdef DHD_EXPORT_CNTL_FILE -extern uint32 pmmode_val; -#endif /* !DHD_EXPORT_CNTL_FILE */ -void sec_control_pm(dhd_pub_t *dhd, uint *power_mode) -{ -#ifndef DHD_EXPORT_CNTL_FILE - struct file *fp = NULL; - char *filepath = PSMINFO; -#endif /* DHD_EXPORT_CNTL_FILE */ - char power_val = 0; - int ret = 0; -#ifdef DHD_ENABLE_LPC - uint32 lpc = 0; -#endif /* DHD_ENABLE_LPC */ - -#ifndef DHD_EXPORT_CNTL_FILE - g_pm_control = FALSE; - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp) || (fp == NULL)) { - /* Enable PowerSave Mode */ - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)power_mode, - sizeof(uint), TRUE, 0); - DHD_ERROR(("[WIFI_SEC] %s: %s doesn't exist" - " so set PM to %d\n", - __FUNCTION__, filepath, *power_mode)); - return; - } else { - kernel_read_compat(fp, fp->f_pos, &power_val, 1); - DHD_ERROR(("[WIFI_SEC] %s: POWER_VAL = %c \r\n", __FUNCTION__, power_val)); - filp_close(fp, NULL); - } -#else - g_pm_control = FALSE; - /* Not set from the framework side */ - if (pmmode_val == 0xFFu) { - /* Enable PowerSave Mode */ - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)power_mode, - sizeof(uint), TRUE, 0); - DHD_ERROR(("[WIFI_SEC] %s: doesn't set from sysfs" - " so set PM to %d\n", - __FUNCTION__, *power_mode)); - return; - - } else { - power_val = (char)pmmode_val; - } -#endif /* !DHD_EXPORT_CNTL_FILE */ - -#ifdef DHD_EXPORT_CNTL_FILE - if (power_val == 0) { -#else - /* XXX: power_val is compared with character type read from .psm.info file */ - if (power_val == '0') { -#endif /* DHD_EXPORT_CNTL_FILE */ -#ifdef ROAM_ENABLE - uint roamvar = 1; -#endif - uint32 wl_updown = 1; - - *power_mode = PM_OFF; - /* Disable PowerSave Mode */ - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)power_mode, - sizeof(uint), TRUE, 0); -#ifndef CUSTOM_SET_ANTNPM - /* Turn off MPC in AP mode */ - ret = dhd_iovar(dhd, 0, "mpc", (char *)power_mode, sizeof(*power_mode), - NULL, 0, TRUE); -#endif /* !CUSTOM_SET_ANTNPM */ - g_pm_control = TRUE; -#ifdef ROAM_ENABLE - /* Roaming off of dongle */ - ret = dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), NULL, - 0, TRUE); -#endif -#ifdef DHD_ENABLE_LPC - /* Set lpc 0 */ - ret = dhd_iovar(dhd, 0, "lpc", (char *)&lpc, sizeof(lpc), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("[WIFI_SEC] %s: Set lpc failed %d\n", - __FUNCTION__, ret)); - } -#endif /* DHD_ENABLE_LPC */ -#ifdef DHD_PCIE_RUNTIMEPM - DHD_ERROR(("[WIFI_SEC] %s : Turn Runtime PM off \n", __FUNCTION__)); - /* Turn Runtime PM off */ - dhdpcie_block_runtime_pm(dhd); -#endif /* DHD_PCIE_RUNTIMEPM */ - /* Disable ocl */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&wl_updown, - sizeof(wl_updown), TRUE, 0)) < 0) { - DHD_ERROR(("[WIFI_SEC] %s: WLC_UP faield %d\n", __FUNCTION__, ret)); - } -#ifndef CUSTOM_SET_OCLOFF - { - uint32 ocl_enable = 0; - ret = dhd_iovar(dhd, 0, "ocl_enable", (char *)&ocl_enable, - sizeof(ocl_enable), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("[WIFI_SEC] %s: Set ocl_enable %d failed %d\n", - __FUNCTION__, ocl_enable, ret)); - } else { - DHD_ERROR(("[WIFI_SEC] %s: Set ocl_enable %d OK %d\n", - __FUNCTION__, ocl_enable, ret)); - } - } -#else - dhd->ocl_off = TRUE; -#endif /* CUSTOM_SET_OCLOFF */ -#ifdef WLADPS - if ((ret = dhd_enable_adps(dhd, ADPS_DISABLE)) < 0) { - DHD_ERROR(("[WIFI_SEC] %s: dhd_enable_adps failed %d\n", - __FUNCTION__, ret)); - } -#endif /* WLADPS */ - - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, (char *)&wl_updown, - sizeof(wl_updown), TRUE, 0)) < 0) { - DHD_ERROR(("[WIFI_SEC] %s: WLC_DOWN faield %d\n", - __FUNCTION__, ret)); - } - } else { - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)power_mode, - sizeof(uint), TRUE, 0); - } -} -#endif /* DHD_PM_CONTROL_FROM_FILE */ - -#ifdef MIMO_ANT_SETTING -int get_ant_val_from_file(uint32 *read_val) -{ - int ret = -1; - struct file *fp = NULL; - char *filepath = ANTINFO; - char *p_ant_val = NULL; - uint32 ant_val = 0; - - /* Read antenna settings from the file */ - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { - DHD_ERROR(("[WIFI_SEC] %s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); - ret = -ENOENT; - return ret; - } else { - ret = kernel_read_compat(fp, 0, (char *)&ant_val, sizeof(uint32)); - if (ret < 0) { - DHD_ERROR(("[WIFI_SEC] %s: File read error, ret=%d\n", __FUNCTION__, ret)); - filp_close(fp, NULL); - return ret; - } - - p_ant_val = (char *)&ant_val; - p_ant_val[sizeof(uint32) - 1] = '\0'; - ant_val = bcm_atoi(p_ant_val); - - DHD_ERROR(("[WIFI_SEC]%s: ANT val = %d\n", __FUNCTION__, ant_val)); - filp_close(fp, NULL); - - /* Check value from the file */ - if (ant_val < 1 || ant_val > 3) { - DHD_ERROR(("[WIFI_SEC] %s: Invalid value %d read from the file %s\n", - __FUNCTION__, ant_val, filepath)); - return -1; - } - } - *read_val = ant_val; - return ret; -} - -int dhd_sel_ant_from_file(dhd_pub_t *dhd) -{ - int ret = -1; - uint32 ant_val = 0; - uint32 btc_mode = 0; - uint chip_id = dhd_bus_chip_id(dhd); -#ifndef CUSTOM_SET_ANTNPM - wl_config_t rsdb_mode; - - memset(&rsdb_mode, 0, sizeof(rsdb_mode)); -#endif /* !CUSTOM_SET_ANTNPM */ - - /* Check if this chip can support MIMO */ - if (chip_id != BCM4350_CHIP_ID && - chip_id != BCM4354_CHIP_ID && - chip_id != BCM43569_CHIP_ID && - chip_id != BCM4358_CHIP_ID && - chip_id != BCM4359_CHIP_ID && - chip_id != BCM4355_CHIP_ID && - chip_id != BCM4347_CHIP_ID && - chip_id != BCM4361_CHIP_ID && - chip_id != BCM4375_CHIP_ID && - chip_id != BCM4389_CHIP_ID) { - DHD_ERROR(("[WIFI_SEC] %s: This chipset does not support MIMO\n", - __FUNCTION__)); - return ret; - } - -#ifndef DHD_EXPORT_CNTL_FILE - ret = get_ant_val_from_file(&ant_val); -#else - ant_val = (uint32)antsel; -#endif /* !DHD_EXPORT_CNTL_FILE */ - if (ant_val == 0) { -#ifdef CUSTOM_SET_ANTNPM - dhd->mimo_ant_set = 0; -#endif /* CUSTOM_SET_ANTNPM */ - return ret; - } - DHD_ERROR(("[WIFI_SEC]%s: ANT val = %d\n", __FUNCTION__, ant_val)); - - /* bt coex mode off */ - if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) { - ret = dhd_iovar(dhd, 0, "btc_mode", (char *)&btc_mode, sizeof(btc_mode), NULL, 0, - TRUE); - if (ret) { - DHD_ERROR(("[WIFI_SEC] %s: Fail to execute dhd_wl_ioctl_cmd(): " - "btc_mode, ret=%d\n", - __FUNCTION__, ret)); - return ret; - } - } - -#ifndef CUSTOM_SET_ANTNPM - /* rsdb mode off */ - DHD_ERROR(("[WIFI_SEC] %s: %s the RSDB mode!\n", - __FUNCTION__, rsdb_mode.config ? "Enable" : "Disable")); - ret = dhd_iovar(dhd, 0, "rsdb_mode", (char *)&rsdb_mode, sizeof(rsdb_mode), NULL, 0, TRUE); - if (ret) { - DHD_ERROR(("[WIFI_SEC] %s: Fail to execute dhd_wl_ioctl_cmd(): " - "rsdb_mode, ret=%d\n", __FUNCTION__, ret)); - return ret; - } - - /* Select Antenna */ - ret = dhd_iovar(dhd, 0, "txchain", (char *)&ant_val, sizeof(ant_val), NULL, 0, TRUE); - if (ret) { - DHD_ERROR(("[WIFI_SEC] %s: Fail to execute dhd_wl_ioctl_cmd(): txchain, ret=%d\n", - __FUNCTION__, ret)); - return ret; - } - - ret = dhd_iovar(dhd, 0, "rxchain", (char *)&ant_val, sizeof(ant_val), NULL, 0, TRUE); - if (ret) { - DHD_ERROR(("[WIFI_SEC] %s: Fail to execute dhd_wl_ioctl_cmd(): rxchain, ret=%d\n", - __FUNCTION__, ret)); - return ret; - } -#else - dhd->mimo_ant_set = ant_val; - DHD_ERROR(("[WIFI_SEC] %s: mimo_ant_set = %d\n", __FUNCTION__, dhd->mimo_ant_set)); -#endif /* CUSTOM_SET_ANTNPM */ - - return 0; -} -#endif /* MIMO_ANTENNA_SETTING */ - -#ifdef LOGTRACE_FROM_FILE -/* - * LOGTRACEINFO = .logtrace.info - * - logtrace = 1 => Enable LOGTRACE Event - * - logtrace = 0 => Disable LOGTRACE Event - * - file not exist => Disable LOGTRACE Event - */ -int dhd_logtrace_from_file(dhd_pub_t *dhd) -{ -#ifndef DHD_EXPORT_CNTL_FILE - struct file *fp = NULL; - int ret = -1; - uint32 logtrace = 0; - char *filepath = LOGTRACEINFO; - char *p_logtrace = NULL; - - /* Read LOGTRACE Event on/off request from the file */ - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { - DHD_ERROR(("[WIFI_SEC] %s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); - return 0; - } else { - ret = kernel_read_compat(fp, 0, (char *)&logtrace, sizeof(uint32)); - if (ret < 0) { - DHD_ERROR(("[WIFI_SEC] %s: File read error, ret=%d\n", __FUNCTION__, ret)); - filp_close(fp, NULL); - return 0; - } - - p_logtrace = (char *)&logtrace; - p_logtrace[sizeof(uint32) - 1] = '\0'; - logtrace = bcm_atoi(p_logtrace); - - DHD_ERROR(("[WIFI_SEC] %s: LOGTRACE On/Off from file = %d\n", - __FUNCTION__, logtrace)); - filp_close(fp, NULL); - - /* Check value from the file */ - if (logtrace > 2) { - DHD_ERROR(("[WIFI_SEC] %s: Invalid value %d read from the file %s\n", - __FUNCTION__, logtrace, filepath)); - return 0; - } - } - - return (int)logtrace; -#else - DHD_ERROR(("[WIFI_SEC] %s : LOGTRACE On/Off from sysfs = %d\n", - __FUNCTION__, (int)logtrace_val)); - return (int)logtrace_val; -#endif /* !DHD_EXPORT_CNTL_FILE */ -} -#endif /* LOGTRACE_FROM_FILE */ - -#ifdef USE_WFA_CERT_CONF -#ifndef DHD_EXPORT_CNTL_FILE -int sec_get_param_wfa_cert(dhd_pub_t *dhd, int mode, uint* read_val) -{ - struct file *fp = NULL; - char *filepath = NULL; - int val = 0; - char *p_val = NULL; - - if (!dhd || (mode < SET_PARAM_BUS_TXGLOM_MODE) || - (mode >= PARAM_LAST_VALUE)) { - DHD_ERROR(("[WIFI_SEC] %s: invalid argument\n", __FUNCTION__)); - return BCME_ERROR; - } - - switch (mode) { -#ifdef BCMSDIO - case SET_PARAM_BUS_TXGLOM_MODE: - filepath = PLATFORM_PATH".bustxglom.info"; - break; -#endif /* BCMSDIO */ -#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) - case SET_PARAM_ROAMOFF: - filepath = PLATFORM_PATH".roamoff.info"; - break; -#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ -#ifdef USE_WL_FRAMEBURST - case SET_PARAM_FRAMEBURST: - filepath = PLATFORM_PATH".frameburst.info"; - break; -#endif /* USE_WL_FRAMEBURST */ -#ifdef USE_WL_TXBF - case SET_PARAM_TXBF: - filepath = PLATFORM_PATH".txbf.info"; - break; -#endif /* USE_WL_TXBF */ -#ifdef PROP_TXSTATUS - case SET_PARAM_PROPTX: - filepath = PLATFORM_PATH".proptx.info"; - break; -#endif /* PROP_TXSTATUS */ - default: - DHD_ERROR(("[WIFI_SEC] %s: File to find file name for index=%d\n", - __FUNCTION__, mode)); - return BCME_ERROR; - } - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp) || (fp == NULL)) { - DHD_ERROR(("[WIFI_SEC] %s: File open failed, file path=%s\n", - __FUNCTION__, filepath)); - return BCME_ERROR; - } else { - if (kernel_read_compat(fp, fp->f_pos, (char *)&val, sizeof(uint32)) < 0) { - filp_close(fp, NULL); - /* File operation is failed so we will return error code */ - DHD_ERROR(("[WIFI_SEC] %s: read failed, file path=%s\n", - __FUNCTION__, filepath)); - return BCME_ERROR; - } - filp_close(fp, NULL); - } - - p_val = (char *)&val; - p_val[sizeof(uint32) - 1] = '\0'; - val = bcm_atoi(p_val); - - switch (mode) { -#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) - case SET_PARAM_ROAMOFF: -#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ -#ifdef USE_WL_FRAMEBURST - case SET_PARAM_FRAMEBURST: -#endif /* USE_WL_FRAMEBURST */ -#ifdef USE_WL_TXBF - case SET_PARAM_TXBF: -#endif /* USE_WL_TXBF */ -#ifdef PROP_TXSTATUS - case SET_PARAM_PROPTX: -#endif /* PROP_TXSTATUS */ - if (val < 0 || val > 1) { - DHD_ERROR(("[WIFI_SEC] %s: value[%d] is out of range\n", - __FUNCTION__, *read_val)); - return BCME_ERROR; - } - break; - default: - return BCME_ERROR; - } - *read_val = (uint)val; - return BCME_OK; -} -#else -int sec_get_param_wfa_cert(dhd_pub_t *dhd, int mode, uint* read_val) -{ - uint val = 0; - - if (!dhd || (mode < SET_PARAM_BUS_TXGLOM_MODE) || - (mode >= PARAM_LAST_VALUE)) { - DHD_ERROR(("[WIFI_SEC] %s: invalid argument\n", __FUNCTION__)); - return BCME_ERROR; - } - - switch (mode) { -#ifdef BCMSDIO - case SET_PARAM_BUS_TXGLOM_MODE: - if (bus_txglom == VALUENOTSET) - return BCME_ERROR; - else - val = (uint)bus_txglom; - break; -#endif /* BCMSDIO */ -#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) - case SET_PARAM_ROAMOFF: - if (roam_off == VALUENOTSET) - return BCME_ERROR; - else - val = (uint)roam_off; - break; -#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ -#ifdef USE_WL_FRAMEBURST - case SET_PARAM_FRAMEBURST: - if (frameburst == VALUENOTSET) - return BCME_ERROR; - else - val = (uint)frameburst; - break; -#endif /* USE_WL_FRAMEBURST */ -#ifdef USE_WL_TXBF - case SET_PARAM_TXBF: - if (txbf == VALUENOTSET) - return BCME_ERROR; - else - val = (uint)txbf; - break; -#endif /* USE_WL_TXBF */ -#ifdef PROP_TXSTATUS - case SET_PARAM_PROPTX: - if (proptx == VALUENOTSET) - return BCME_ERROR; - else - val = (uint)proptx; - break; -#endif /* PROP_TXSTATUS */ - default: - return BCME_ERROR; - } - *read_val = val; - return BCME_OK; -} -#endif /* !DHD_EXPORT_CNTL_FILE */ -#endif /* USE_WFA_CERT_CONF */ - -#ifdef WRITE_WLANINFO -#define FIRM_PREFIX "Firm_ver:" -#define DHD_PREFIX "DHD_ver:" -#define NV_PREFIX "Nv_info:" -#define CLM_PREFIX "CLM_ver:" -#define max_len(a, b) ((sizeof(a)/(2)) - (strlen(b)) - (3)) -#define tstr_len(a, b) ((strlen(a)) + (strlen(b)) + (3)) - -char version_info[MAX_VERSION_LEN]; -char version_old_info[MAX_VERSION_LEN]; - -int write_filesystem(struct file *file, unsigned long long offset, - unsigned char* data, unsigned int size) -{ - mm_segment_t oldfs; - int ret; - - oldfs = get_fs(); - set_fs(KERNEL_DS); - - ret = vfs_write(file, data, size, &offset); - - set_fs(oldfs); - return ret; -} - -uint32 sec_save_wlinfo(char *firm_ver, char *dhd_ver, char *nvram_p, char *clm_ver) -{ -#ifndef DHD_EXPORT_CNTL_FILE - struct file *fp = NULL; - char *filepath = WIFIVERINFO; -#endif /* DHD_EXPORT_CNTL_FILE */ - struct file *nvfp = NULL; - int min_len, str_len = 0; - int ret = 0; - char* nvram_buf; - char temp_buf[256]; - - DHD_TRACE(("[WIFI_SEC] %s: Entered.\n", __FUNCTION__)); - - DHD_INFO(("[WIFI_SEC] firmware version : %s\n", firm_ver)); - DHD_INFO(("[WIFI_SEC] dhd driver version : %s\n", dhd_ver)); - DHD_INFO(("[WIFI_SEC] nvram path : %s\n", nvram_p)); - DHD_INFO(("[WIFI_SEC] clm version : %s\n", clm_ver)); - - memset(version_info, 0, sizeof(version_info)); - - if (strlen(dhd_ver)) { - min_len = min(strlen(dhd_ver), max_len(temp_buf, DHD_PREFIX)); - min_len += strlen(DHD_PREFIX) + 3; - DHD_INFO(("[WIFI_SEC] DHD ver length : %d\n", min_len)); - snprintf(version_info+str_len, min_len, DHD_PREFIX " %s\n", dhd_ver); - str_len = strlen(version_info); - - DHD_INFO(("[WIFI_SEC] Driver version_info len : %d\n", str_len)); - DHD_INFO(("[WIFI_SEC] Driver version_info : %s\n", version_info)); - } else { - DHD_ERROR(("[WIFI_SEC] Driver version is missing.\n")); - } - - if (strlen(firm_ver)) { - min_len = min(strlen(firm_ver), max_len(temp_buf, FIRM_PREFIX)); - min_len += strlen(FIRM_PREFIX) + 3; - DHD_INFO(("[WIFI_SEC] firmware ver length : %d\n", min_len)); - snprintf(version_info+str_len, min_len, FIRM_PREFIX " %s\n", firm_ver); - str_len = strlen(version_info); - - DHD_INFO(("[WIFI_SEC] Firmware version_info len : %d\n", str_len)); - DHD_INFO(("[WIFI_SEC] Firmware version_info : %s\n", version_info)); - } else { - DHD_ERROR(("[WIFI_SEC] Firmware version is missing.\n")); - } - - if (nvram_p) { - memset(temp_buf, 0, sizeof(temp_buf)); - nvfp = filp_open(nvram_p, O_RDONLY, 0); - if (IS_ERR(nvfp) || (nvfp == NULL)) { - DHD_ERROR(("[WIFI_SEC] %s: Nvarm File open failed.\n", __FUNCTION__)); - return -1; - } else { - ret = kernel_read_compat(nvfp, nvfp->f_pos, temp_buf, sizeof(temp_buf)); - filp_close(nvfp, NULL); - } - - if (strlen(temp_buf)) { - nvram_buf = temp_buf; - bcmstrtok(&nvram_buf, "\n", 0); - DHD_INFO(("[WIFI_SEC] nvram tolkening : %s(%zu) \n", - temp_buf, strlen(temp_buf))); - snprintf(version_info+str_len, tstr_len(temp_buf, NV_PREFIX), - NV_PREFIX " %s\n", temp_buf); - str_len = strlen(version_info); - DHD_INFO(("[WIFI_SEC] NVRAM version_info : %s\n", version_info)); - DHD_INFO(("[WIFI_SEC] NVRAM version_info len : %d, nvram len : %zu\n", - str_len, strlen(temp_buf))); - } else { - DHD_ERROR(("[WIFI_SEC] NVRAM info is missing.\n")); - } - } else { - DHD_ERROR(("[WIFI_SEC] Not exist nvram path\n")); - } - - if (strlen(clm_ver)) { - min_len = min(strlen(clm_ver), max_len(temp_buf, CLM_PREFIX)); - min_len += strlen(CLM_PREFIX) + 3; - DHD_INFO(("[WIFI_SEC] clm ver length : %d\n", min_len)); - snprintf(version_info+str_len, min_len, CLM_PREFIX " %s\n", clm_ver); - str_len = strlen(version_info); - - DHD_INFO(("[WIFI_SEC] CLM version_info len : %d\n", str_len)); - DHD_INFO(("[WIFI_SEC] CLM version_info : %s\n", version_info)); - } else { - DHD_ERROR(("[WIFI_SEC] CLM version is missing.\n")); - } - - DHD_INFO(("[WIFI_SEC] version_info : %s, strlen : %zu\n", - version_info, strlen(version_info))); - -#ifndef DHD_EXPORT_CNTL_FILE - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp) || (fp == NULL)) { - DHD_ERROR(("[WIFI_SEC] %s: .wifiver.info File open failed.\n", __FUNCTION__)); - } else { - memset(version_old_info, 0, sizeof(version_old_info)); - ret = kernel_read_compat(fp, fp->f_pos, version_old_info, sizeof(version_info)); - filp_close(fp, NULL); - DHD_INFO(("[WIFI_SEC] kernel_read ret : %d.\n", ret)); - if (strcmp(version_info, version_old_info) == 0) { - DHD_ERROR(("[WIFI_SEC] .wifiver.info already saved.\n")); - return 0; - } - } - - fp = filp_open(filepath, O_RDWR | O_CREAT, 0664); - if (IS_ERR(fp) || (fp == NULL)) { - DHD_ERROR(("[WIFI_SEC] %s: .wifiver.info File open failed.\n", - __FUNCTION__)); - } else { - ret = write_filesystem(fp, fp->f_pos, version_info, sizeof(version_info)); - DHD_INFO(("[WIFI_SEC] sec_save_wlinfo done. ret : %d\n", ret)); - DHD_ERROR(("[WIFI_SEC] save .wifiver.info file.\n")); - filp_close(fp, NULL); - } -#endif /* DHD_EXPORT_CNTL_FILE */ - return ret; -} -#endif /* WRITE_WLANINFO */ - -#ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_HW -unsigned int system_hw_rev; -static int -__init get_hw_rev(char *arg) -{ - get_option(&arg, &system_hw_rev); - printk("dhd : hw_rev : %d\n", system_hw_rev); - return 0; -} - -early_param("androidboot.hw_rev", get_hw_rev); -#endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_HW */ - -#ifdef GEN_SOFTAP_INFO_FILE -#define SOFTAP_INFO_FILE_FIRST_LINE "#.softap.info" -/* - * # Does RSDB Wifi sharing support? - * DualBandConcurrency - * # Both wifi and hotspot can be turned on at the same time? - * DualInterface - * # 5Ghz band support? - * 5G - * # How many clients can be connected? - * maxClient - * # Does hotspot support PowerSave mode? - * PowerSave - * # Does android_net_wifi_set_Country_Code_Hal feature supported? - * HalFn_setCountryCodeHal - * # Does android_net_wifi_getValidChannels supported? - * HalFn_getValidChannels - */ -const char *softap_info_items[] = { - "DualBandConcurrency", -#ifdef DHD_SOFTAP_DUAL_IF_INFO - "DualInterface", -#endif /* DHD_SOFTAP_DUAL_IF_INFO */ - "5G", "maxClient", "PowerSave", - "HalFn_setCountryCodeHal", "HalFn_getValidChannels", NULL -}; -#if defined(BCM4361_CHIP) || defined(BCM4375_CHIP) || defined(BCM4389_CHIP_DEF) -const char *softap_info_values[] = { - "yes", -#ifdef DHD_SOFTAP_DUAL_IF_INFO - "yes", -#endif /* DHD_SOFTAP_DUAL_IF_INFO */ - "yes", "10", "yes", "yes", "yes", NULL -}; -#elif defined(BCM43455_CHIP) -const char *softap_info_values[] = { - "no", -#ifdef DHD_SOFTAP_DUAL_IF_INFO - "no", -#endif /* DHD_SOFTAP_DUAL_IF_INFO */ - "yes", "10", "no", "yes", "yes", NULL -}; -#elif defined(BCM43430_CHIP) -const char *softap_info_values[] = { - "no", -#ifdef DHD_SOFTAP_DUAL_IF_INFO - "no", -#endif /* DHD_SOFTAP_DUAL_IF_INFO */ - "no", "10", "no", "yes", "yes", NULL -}; -#else -const char *softap_info_values[] = { - "UNDEF", -#ifdef DHD_SOFTAP_DUAL_IF_INFO - "UNDEF", -#endif /* DHD_SOFTAP_DUAL_IF_INFO */ - "UNDEF", "UNDEF", "UNDEF", "UNDEF", "UNDEF", NULL -}; -#endif /* defined(BCM4361_CHIP) || defined(BCM4375_CHIP) || defined(BCM4389_CHIP_DEF) */ -#endif /* GEN_SOFTAP_INFO_FILE */ - -#ifdef GEN_SOFTAP_INFO_FILE -uint32 sec_save_softap_info(void) -{ -#ifndef DHD_EXPORT_CNTL_FILE - struct file *fp = NULL; - char *filepath = SOFTAPINFO; -#endif /* DHD_EXPORT_CNTL_FILE */ - char temp_buf[SOFTAP_INFO_BUF_SZ]; - int ret = -1, idx = 0, rem = 0, written = 0; - char *pos = NULL; - - DHD_TRACE(("[WIFI_SEC] %s: Entered.\n", __FUNCTION__)); - memset(temp_buf, 0, sizeof(temp_buf)); - - pos = temp_buf; - rem = sizeof(temp_buf); - written = snprintf(pos, sizeof(temp_buf), "%s\n", - SOFTAP_INFO_FILE_FIRST_LINE); - do { - int len = strlen(softap_info_items[idx]) + - strlen(softap_info_values[idx]) + 2; - pos += written; - rem -= written; - if (len > rem) { - break; - } - written = snprintf(pos, rem, "%s=%s\n", - softap_info_items[idx], softap_info_values[idx]); - } while (softap_info_items[++idx] != NULL); - -#ifndef DHD_EXPORT_CNTL_FILE - fp = filp_open(filepath, O_RDWR | O_CREAT, 0664); - if (IS_ERR(fp) || (fp == NULL)) { - DHD_ERROR(("[WIFI_SEC] %s: %s File open failed.\n", - SOFTAPINFO, __FUNCTION__)); - } else { - ret = write_filesystem(fp, fp->f_pos, temp_buf, strlen(temp_buf)); - DHD_INFO(("[WIFI_SEC] %s done. ret : %d\n", __FUNCTION__, ret)); - DHD_ERROR(("[WIFI_SEC] save %s file.\n", SOFTAPINFO)); - filp_close(fp, NULL); - } -#else - strlcpy(softapinfostr, temp_buf, SOFTAP_INFO_BUF_SZ); - - ret = BCME_OK; -#endif /* !DHD_EXPORT_CNTL_FILE */ - return ret; -} -#endif /* GEN_SOFTAP_INFO_FILE */ -#endif /* CUSTOMER_HW4 || CUSTOMER_HW40 */ - -/* XXX WAR: disable pm_bcnrx , scan_ps for BCM4354 WISOL module. - * WISOL module have ANT_1 Rx sensitivity issue. -*/ -#if defined(FORCE_DISABLE_SINGLECORE_SCAN) -void -dhd_force_disable_singlcore_scan(dhd_pub_t *dhd) -{ - int ret = 0; - struct file *fp = NULL; - char *filepath = PLATFORM_PATH".cid.info"; - char vender[10] = {0, }; - uint32 pm_bcnrx = 0; - uint32 scan_ps = 0; - - if (BCM4354_CHIP_ID != dhd_bus_chip_id(dhd)) - return; - - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { - DHD_ERROR(("%s file open error\n", filepath)); - } else { - ret = kernel_read_compat(fp, 0, (char *)vender, 5); - - if (ret > 0 && NULL != strstr(vender, "wisol")) { - DHD_ERROR(("wisol module : set pm_bcnrx=0, set scan_ps=0\n")); - - ret = dhd_iovar(dhd, 0, "pm_bcnrx", (char *)&pm_bcnrx, sizeof(pm_bcnrx), - NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("Set pm_bcnrx error (%d)\n", ret)); - - ret = dhd_iovar(dhd, 0, "scan_ps", (char *)&scan_ps, sizeof(scan_ps), NULL, - 0, TRUE); - if (ret < 0) - DHD_ERROR(("Set scan_ps error (%d)\n", ret)); - } - filp_close(fp, NULL); - } -} -#endif /* FORCE_DISABLE_SINGLECORE_SCAN */ - -#ifdef BCM4335_XTAL_WAR -bool -check_bcm4335_rev(void) -{ - int ret = -1; - struct file *fp = NULL; - char *filepath = "/data/.rev"; - char chip_rev[10] = {0, }; - bool is_revb0 = TRUE; - - DHD_ERROR(("check BCM4335, check_bcm4335_rev \n")); - fp = filp_open(filepath, O_RDONLY, 0); - - if (IS_ERR(fp)) { - DHD_ERROR(("/data/.rev file open error\n")); - is_revb0 = TRUE; - } else { - DHD_ERROR(("/data/.rev file Found\n")); - ret = kernel_read_compat(fp, 0, (char *)chip_rev, 9); - if (ret != -1 && NULL != strstr(chip_rev, "BCM4335B0")) { - DHD_ERROR(("Found BCM4335B0\n")); - is_revb0 = TRUE; - } else { - is_revb0 = FALSE; - } - filp_close(fp, NULL); - } - return is_revb0; -} -#endif /* BCM4335_XTAL_WAR */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg.h old mode 100755 new mode 100644 index c955e38fcc46..cac6787a0066 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg.h @@ -1,7 +1,7 @@ /* * Debug/trace/assert driver definitions for Dongle Host Driver. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -29,102 +29,38 @@ #if defined(NDIS) #include "wl_nddbg.h" #endif /* defined(NDIS) */ - #ifdef DHD_LOG_DUMP -extern char *dhd_log_dump_get_timestamp(void); -#ifdef DHD_EFI -/* FW verbose/console output to FW ring buffer */ -extern void dhd_log_dump_print(const char *fmt, ...); -/* DHD verbose/console output to DHD ring buffer */ -extern void dhd_log_dump_print_drv(const char *fmt, ...); -#define DHD_LOG_DUMP_WRITE(fmt, ...) dhd_log_dump_print_drv(fmt, ##__VA_ARGS__) -#define DHD_LOG_DUMP_WRITE_FW(fmt, ...) dhd_log_dump_print(fmt, ##__VA_ARGS__) -#else -#ifndef _DHD_LOG_DUMP_DEFINITIONS_ -#define _DHD_LOG_DUMP_DEFINITIONS_ -#define GENERAL_LOG_HDR "\n-------------------- General log ---------------------------\n" -#define PRESERVE_LOG_HDR "\n-------------------- Preserve log ---------------------------\n" -#define SPECIAL_LOG_HDR "\n-------------------- Special log ---------------------------\n" -#define DHD_DUMP_LOG_HDR "\n-------------------- 'dhd dump' log -----------------------\n" -#define EXT_TRAP_LOG_HDR "\n-------------------- Extended trap data -------------------\n" -#define HEALTH_CHK_LOG_HDR "\n-------------------- Health check data --------------------\n" -#ifdef DHD_DUMP_PCIE_RINGS -#define FLOWRING_DUMP_HDR "\n-------------------- Flowring dump --------------------\n" -#endif /* DHD_DUMP_PCIE_RINGS */ -#define DHD_LOG_DUMP_DLD(fmt, ...) \ - dhd_log_dump_write(DLD_BUF_TYPE_GENERAL, NULL, 0, fmt, ##__VA_ARGS__) -#define DHD_LOG_DUMP_DLD_EX(fmt, ...) \ - dhd_log_dump_write(DLD_BUF_TYPE_SPECIAL, NULL, 0, fmt, ##__VA_ARGS__) -#define DHD_LOG_DUMP_DLD_PRSRV(fmt, ...) \ - dhd_log_dump_write(DLD_BUF_TYPE_PRESERVE, NULL, 0, fmt, ##__VA_ARGS__) -#endif /* !_DHD_LOG_DUMP_DEFINITIONS_ */ - -#ifndef DHD_LOG_DUMP_RING_DEFINITIONS -#define DHD_LOG_DUMP_RING_DEFINITIONS -#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING -/* Enabled DHD_DEBUGABILITY_LOG_DUMP_RING */ -extern void dhd_dbg_ring_write(int type, char *binary_data, - int binary_len, const char *fmt, ...); -extern char* dhd_dbg_get_system_timestamp(void); -#define DHD_DBG_RING(fmt, ...) \ - dhd_dbg_ring_write(DRIVER_LOG_RING_ID, NULL, 0, fmt, ##__VA_ARGS__) -#define DHD_DBG_RING_EX(fmt, ...) \ - dhd_dbg_ring_write(FW_VERBOSE_RING_ID, NULL, 0, fmt, ##__VA_ARGS__) -#define DHD_DBG_RING_ROAM(fmt, ...) \ - dhd_dbg_ring_write(ROAM_STATS_RING_ID, NULL, 0, fmt, ##__VA_ARGS__) - -#define DHD_LOG_DUMP_WRITE DHD_DBG_RING -#define DHD_LOG_DUMP_WRITE_EX DHD_DBG_RING_EX -#define DHD_LOG_DUMP_WRITE_PRSRV DHD_DBG_RING -#define DHD_LOG_DUMP_WRITE_ROAM DHD_DBG_RING_ROAM - -#define DHD_PREFIX_TS "[%s][%s]: ", dhd_dbg_get_system_timestamp(), dhd_log_dump_get_timestamp() -#define DHD_PREFIX_TS_FN DHD_PREFIX_TS -#define DHD_LOG_DUMP_WRITE_TS DHD_DBG_RING(DHD_PREFIX_TS) -#define DHD_LOG_DUMP_WRITE_TS_FN DHD_DBG_RING(DHD_PREFIX_TS_FN) -#define DHD_LOG_DUMP_WRITE_EX_TS DHD_DBG_RING_EX(DHD_PREFIX_TS) -#define DHD_LOG_DUMP_WRITE_EX_TS_FN DHD_DBG_RING_EX(DHD_PREFIX_TS_FN) -#define DHD_LOG_DUMP_WRITE_PRSRV_TS DHD_DBG_RING(DHD_PREFIX_TS) -#define DHD_LOG_DUMP_WRITE_PRSRV_TS_FN DHD_DBG_RING(DHD_PREFIX_TS_FN) -#define DHD_LOG_DUMP_WRITE_ROAM_TS DHD_DBG_RING_ROAM(DHD_PREFIX_TS) -#define DHD_LOG_DUMP_WRITE_ROAM_TS_FN DHD_DBG_RING_ROAM(DHD_PREFIX_TS_FN) -#else -/* Not enabled DHD_DEBUGABILITY_LOG_DUMP_RING */ -#define DHD_LOG_DUMP_WRITE DHD_LOG_DUMP_DLD -#define DHD_LOG_DUMP_WRITE_EX DHD_LOG_DUMP_DLD_EX -#define DHD_LOG_DUMP_WRITE_PRSRV DHD_LOG_DUMP_DLD_PRSRV -#define DHD_LOG_DUMP_WRITE_ROAM DHD_LOG_DUMP_DLD - -#define DHD_PREFIX_TS "[%s]: ", dhd_log_dump_get_timestamp() -#define DHD_PREFIX_TS_FN "[%s] %s: ", dhd_log_dump_get_timestamp(), __func__ -#define DHD_LOG_DUMP_WRITE_TS DHD_LOG_DUMP_DLD(DHD_PREFIX_TS) -#define DHD_LOG_DUMP_WRITE_TS_FN DHD_LOG_DUMP_DLD(DHD_PREFIX_TS_FN) -#define DHD_LOG_DUMP_WRITE_EX_TS DHD_LOG_DUMP_DLD_EX(DHD_PREFIX_TS) -#define DHD_LOG_DUMP_WRITE_EX_TS_FN DHD_LOG_DUMP_DLD_EX(DHD_PREFIX_TS_FN) -#define DHD_LOG_DUMP_WRITE_PRSRV_TS DHD_LOG_DUMP_DLD_PRSRV(DHD_PREFIX_TS) -#define DHD_LOG_DUMP_WRITE_PRSRV_TS_FN DHD_LOG_DUMP_DLD_PRSRV(DHD_PREFIX_TS_FN) -#define DHD_LOG_DUMP_WRITE_ROAM_TS DHD_LOG_DUMP_DLD(DHD_PREFIX_TS) -#define DHD_LOG_DUMP_WRITE_ROAM_TS_FN DHD_LOG_DUMP_DLD(DHD_PREFIX_TS_FN) -#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ -#endif /* DHD_LOG_DUMP_RING_DEFINITIONS */ - -#endif /* DHD_EFI */ -#define CONCISE_DUMP_BUFLEN 32 * 1024 -#define ECNTRS_LOG_HDR "\n-------------------- Ecounters log --------------------------\n" -#ifdef DHD_STATUS_LOGGING -#define STATUS_LOG_HDR "\n-------------------- Status log -----------------------\n" -#endif /* DHD_STATUS_LOGGING */ -#define RTT_LOG_HDR "\n-------------------- RTT log --------------------------\n" -#define BCM_TRACE_LOG_HDR "\n-------------------- BCM Trace log --------------------------\n" -#define COOKIE_LOG_HDR "\n-------------------- Cookie List ----------------------------\n" -#endif /* DHD_LOG_DUMP */ - -#if defined(CUSTOMER_DBG_SYSTEM_TIME) && defined(DHD_DEBUGABILITY_LOG_DUMP_RING) -#define DBG_PRINT_PREFIX "[%s][dhd][wlan]", dhd_dbg_get_system_timestamp() -#else -#define DBG_PRINT_PREFIX +#include #endif + +#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING +/* Only for writing to ring */ +#define DHD_INFO_RING(args) DHD_ERROR(args) +/* FW_VERBOSE RING */ +#define DHD_LOG_DUMP_FWLOG DHD_LOG_DUMP_WRITE_EX +#define DHD_LOG_DUMP_FWLOG_TS DHD_LOG_DUMP_WRITE_EX_TS +#else +#define DHD_INFO_RING(args) +/* DLD_BUF_TYPE_GENERAL */ +#define DHD_LOG_DUMP_FWLOG DHD_LOG_DUMP_WRITE +#define DHD_LOG_DUMP_FWLOG_TS DHD_LOG_DUMP_WRITE_TS +#endif + +#ifdef CUSTOM_PREFIX +#define DBG_PRINT_PREFIX "[%s]"CUSTOM_PREFIX, OSL_GET_RTCTIME() +#elif defined(CUSTOM_PREFIX_NORTCTIME) +#define DBG_PRINT_PREFIX CUSTOM_PREFIX_NORTCTIME + #define DBG_PRINT_SYSTEM_TIME pr_cont(DBG_PRINT_PREFIX) +#define DHD_CONS_ONLY(args) \ +do { \ + DBG_PRINT_SYSTEM_TIME; \ + pr_cont args; \ +} while (0) +#else +#define DBG_PRINT_SYSTEM_TIME +#define DHD_CONS_ONLY(args) do { printf args;} while (0) +#endif /* CUSTOM_PREFIX */ #if defined(BCMDBG) || defined(DHD_DEBUG) @@ -139,38 +75,32 @@ extern char* dhd_dbg_get_system_timestamp(void); #else /* NON-NDIS cases */ #ifdef DHD_LOG_DUMP -#ifdef DHD_EFI -/* defined(DHD_EFI) && defined(DHD_LOG_DUMP) */ -#define DHD_ERROR(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - printf args; \ - DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) - -#define DHD_INFO(args) \ -do { \ - if (dhd_msg_level & DHD_INFO_VAL) { \ - printf args; \ - DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) -#else /* DHD_EFI */ /* !defined(DHD_EFI) and defined(DHD_LOG_DUMP) */ #define DHD_ERROR(args) \ do { \ if (dhd_msg_level & DHD_ERROR_VAL) { \ printf args; \ + } \ + if (dhd_log_level & DHD_ERROR_VAL) { \ DHD_LOG_DUMP_WRITE_TS; \ DHD_LOG_DUMP_WRITE args; \ } \ } while (0) +#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING +#define DHD_INFO(args) \ +do { \ + if (dhd_msg_level & DHD_INFO_VAL) { \ + printf args; \ + } \ + if (dhd_log_level & DHD_INFO_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ + DHD_LOG_DUMP_WRITE args; \ + } \ +} while (0) +#else #define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0) -#endif /* DHD_EFI */ +#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ #else /* DHD_LOG_DUMP */ /* !defined(DHD_LOG_DUMP cases) */ #define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_VAL) printf args;} while (0) @@ -183,55 +113,6 @@ do { \ #ifdef DHD_LOG_DUMP /* LOG_DUMP defines common to EFI and NON-EFI */ -#ifdef DHD_EFI -/* EFI builds with LOG DUMP enabled */ -#define DHD_ERROR_MEM(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - if (dhd_msg_level & DHD_ERROR_MEM_VAL) { \ - printf args; \ - } \ - DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) -#define DHD_IOVAR_MEM(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - if (dhd_msg_level & DHD_IOVAR_MEM_VAL) { \ - printf args; \ - } \ - DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) -#define DHD_LOG_MEM(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) - -#define DHD_EVENT(args) \ -do { \ - if (dhd_msg_level & DHD_EVENT_VAL) { \ - DHD_LOG_DUMP_WRITE_FW("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE_FW args; \ - } \ -} while (0) -#define DHD_ECNTR_LOG(args) DHD_EVENT(args) -#define DHD_ERROR_EX(args) DHD_ERROR(args) -#define DHD_ERROR_ROAM(args) DHD_ERROR(args) -#define DHD_MSGTRACE_LOG(args) \ -do { \ - if (dhd_msg_level & DHD_MSGTRACE_VAL) { \ - DHD_LOG_DUMP_WRITE_FW("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE_FW args; \ - } \ -} while (0) -#define DHD_PRSRV_MEM(args) DHD_EVENT(args) -#else /* NON-EFI builds with LOG DUMP enabled */ #define DHD_ERROR_MEM(args) \ do { \ @@ -239,6 +120,9 @@ do { \ if (dhd_msg_level & DHD_ERROR_MEM_VAL) { \ printf args; \ } \ + } \ + if (dhd_log_level & DHD_ERROR_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ DHD_LOG_DUMP_WRITE args; \ } \ } while (0) @@ -248,12 +132,16 @@ do { \ if (dhd_msg_level & DHD_IOVAR_MEM_VAL) { \ printf args; \ } \ + } \ + if (dhd_log_level & DHD_ERROR_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ DHD_LOG_DUMP_WRITE args; \ } \ } while (0) #define DHD_LOG_MEM(args) \ do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ + if (dhd_log_level & DHD_ERROR_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ DHD_LOG_DUMP_WRITE args; \ } \ } while (0) @@ -262,6 +150,8 @@ do { \ do { \ if (dhd_msg_level & DHD_EVENT_VAL) { \ printf args; \ + } \ + if (dhd_log_level & DHD_EVENT_VAL) { \ DHD_LOG_DUMP_WRITE_PRSRV_TS; \ DHD_LOG_DUMP_WRITE_PRSRV args; \ } \ @@ -272,8 +162,10 @@ do { \ if (dhd_msg_level & DHD_PRSRV_MEM_VAL) { \ printf args; \ } \ - DHD_LOG_DUMP_WRITE_TS; \ - DHD_LOG_DUMP_WRITE args; \ + } \ + if (dhd_log_level & DHD_EVENT_VAL) { \ + DHD_LOG_DUMP_WRITE_PRSRV_TS; \ + DHD_LOG_DUMP_WRITE_PRSRV args; \ } \ } while (0) /* Re-using 'DHD_MSGTRACE_VAL' for controlling printing of ecounter binary event @@ -286,6 +178,10 @@ do { \ if (dhd_msg_level & DHD_EVENT_VAL) { \ if (dhd_msg_level & DHD_MSGTRACE_VAL) { \ printf args; \ + } \ + } \ + if (dhd_log_level & DHD_EVENT_VAL) { \ + if (dhd_log_level & DHD_MSGTRACE_VAL) { \ DHD_LOG_DUMP_WRITE_TS; \ DHD_LOG_DUMP_WRITE args; \ } \ @@ -295,6 +191,8 @@ do { \ do { \ if (dhd_msg_level & DHD_ERROR_VAL) { \ printf args; \ + } \ + if (dhd_log_level & DHD_ERROR_VAL) { \ DHD_LOG_DUMP_WRITE_EX_TS; \ DHD_LOG_DUMP_WRITE_EX args; \ } \ @@ -312,11 +210,122 @@ do { \ do { \ if (dhd_msg_level & DHD_ERROR_VAL) { \ printf args; \ + } \ + if (dhd_log_level & DHD_ERROR_VAL) { \ DHD_LOG_DUMP_WRITE_ROAM_TS; \ DHD_LOG_DUMP_WRITE_ROAM args; \ } \ } while (0) -#endif /* DHD_EFI */ + +#define DHD_PKT_MON(args) \ +do { \ + if (dhd_msg_level & DHD_PKT_MON_VAL) { \ + printf args; \ + } \ + if (dhd_log_level & DHD_PKT_MON_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ + DHD_LOG_DUMP_WRITE args; \ + } \ +} while (0) + +#define DHD_CTL(args) \ +do { \ + if (dhd_msg_level & DHD_CTL_VAL) { \ + printf args; \ + } \ + if (dhd_log_level & DHD_CTL_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ + DHD_LOG_DUMP_WRITE args; \ + } \ +} while (0) + +#define DHD_TIMER(args) \ +do { \ + if (dhd_msg_level & DHD_TIMER_VAL) { \ + printf args; \ + } \ + if (dhd_log_level & DHD_TIMER_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ + DHD_LOG_DUMP_WRITE args; \ + } \ +} while (0) + +#define DHD_INTR(args) \ +do { \ + if (dhd_msg_level & DHD_INTR_VAL) { \ + printf args; \ + } \ + if (dhd_log_level & DHD_INTR_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ + DHD_LOG_DUMP_WRITE args; \ + } \ +} while (0) + +#define DHD_ISCAN(args) \ +do { \ + if (dhd_msg_level & DHD_ISCAN_VAL) { \ + printf args; \ + } \ + if (dhd_log_level & DHD_ISCAN_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ + DHD_LOG_DUMP_WRITE args; \ + } \ +} while (0) + +#define DHD_ARPOE(args) \ +do { \ + if (dhd_msg_level & DHD_ARPOE_VAL) { \ + printf args; \ + } \ + if (dhd_log_level & DHD_ARPOE_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ + DHD_LOG_DUMP_WRITE args; \ + } \ +} while (0) + +#define DHD_REORDER(args) \ +do { \ + if (dhd_msg_level & DHD_REORDER_VAL) { \ + printf args; \ + } \ + if (dhd_log_level & DHD_REORDER_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ + DHD_LOG_DUMP_WRITE args; \ + } \ +} while (0) + +#define DHD_PNO(args) \ +do { \ + if (dhd_msg_level & DHD_PNO_VAL) { \ + printf args; \ + } \ + if (dhd_log_level & DHD_PNO_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ + DHD_LOG_DUMP_WRITE args; \ + } \ +} while (0) + +#define DHD_RTT(args) \ +do { \ + if (dhd_msg_level & DHD_RTT_VAL) { \ + printf args; \ + } \ + if (dhd_log_level & DHD_RTT_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ + DHD_LOG_DUMP_WRITE args; \ + } \ +} while (0) + +#define DHD_RPM(args) \ +do { \ + if (dhd_msg_level & DHD_RPM_VAL) { \ + printf args; \ + } \ + if (dhd_log_level & DHD_RPM_VAL) { \ + DHD_LOG_DUMP_WRITE_TS; \ + DHD_LOG_DUMP_WRITE args; \ + } \ +} while (0) #else /* DHD_LOG_DUMP */ /* !DHD_LOG_DUMP */ #define DHD_MSGTRACE_LOG(args) do {if (dhd_msg_level & DHD_MSGTRACE_VAL) printf args;} while (0) @@ -328,50 +337,43 @@ do { \ #define DHD_PRSRV_MEM(args) DHD_EVENT(args) #define DHD_ERROR_EX(args) DHD_ERROR(args) #define DHD_ERROR_ROAM(args) DHD_ERROR(args) +#define DHD_PKT_MON(args) DHD_ERROR(args) #endif /* DHD_LOG_DUMP */ -#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0) +#if !defined(DHD_LOG_DUMP) #define DHD_CTL(args) do {if (dhd_msg_level & DHD_CTL_VAL) printf args;} while (0) #define DHD_TIMER(args) do {if (dhd_msg_level & DHD_TIMER_VAL) printf args;} while (0) -#define DHD_HDRS(args) do {if (dhd_msg_level & DHD_HDRS_VAL) printf args;} while (0) -#define DHD_BYTES(args) do {if (dhd_msg_level & DHD_BYTES_VAL) printf args;} while (0) #define DHD_INTR(args) do {if (dhd_msg_level & DHD_INTR_VAL) printf args;} while (0) -#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0) -#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0) #define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0) #define DHD_ARPOE(args) do {if (dhd_msg_level & DHD_ARPOE_VAL) printf args;} while (0) #define DHD_REORDER(args) do {if (dhd_msg_level & DHD_REORDER_VAL) printf args;} while (0) #define DHD_PNO(args) do {if (dhd_msg_level & DHD_PNO_VAL) printf args;} while (0) #define DHD_RTT(args) do {if (dhd_msg_level & DHD_RTT_VAL) printf args;} while (0) #define DHD_RPM(args) do {if (dhd_msg_level & DHD_RPM_VAL) printf args;} while (0) -#define DHD_PKT_MON(args) do {if (dhd_msg_level & DHD_PKT_MON_VAL) printf args;} while (0) +#endif + +#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0) +#define DHD_HDRS(args) do {if (dhd_msg_level & DHD_HDRS_VAL) printf args;} while (0) +#define DHD_BYTES(args) do {if (dhd_msg_level & DHD_BYTES_VAL) printf args;} while (0) +#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0) +#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0) #if defined(DHD_LOG_DUMP) -#if defined(DHD_EFI) -#define DHD_FWLOG(args) DHD_MSGTRACE_LOG(args) -#elif defined(DHD_LOG_PRINT_RATE_LIMIT) -#define DHD_FW_VERBOSE(args) \ -do { \ - if (dbgring_msg_level & DHD_FWLOG_VAL) { \ - DHD_LOG_DUMP_WRITE_EX args; \ - } \ -} while (0) +#if defined(DHD_LOG_PRINT_RATE_LIMIT) + #define DHD_FWLOG(args) \ - do { \ - if (dhd_msg_level & DHD_FWLOG_VAL) { \ - if (control_logtrace && !log_print_threshold) \ - printf args; \ - DHD_LOG_DUMP_WRITE args; \ - } \ - } while (0) -#else -#define DHD_FW_VERBOSE(args) \ -do { \ - if (dbgring_msg_level & DHD_FWLOG_VAL) { \ - DHD_LOG_DUMP_WRITE_EX args; \ - } \ +do { \ + if (dhd_msg_level & DHD_FWLOG_VAL) { \ + if (control_logtrace && !log_print_threshold) \ + printf args; \ + } \ + if (dhd_log_level & DHD_FWLOG_VAL) { \ + DHD_LOG_DUMP_FWLOG_TS; \ + DHD_LOG_DUMP_FWLOG args; \ + } \ } while (0) +#else #define DHD_FWLOG(args) \ do { \ if (dhd_msg_level & DHD_FWLOG_VAL) { \ @@ -380,7 +382,7 @@ do { \ DHD_LOG_DUMP_WRITE args; \ } \ } while (0) -#endif /* DHD_EFI */ +#endif #else /* DHD_LOG_DUMP */ #if defined(NDIS) && (NDISVER >= 0x0630) #define DHD_FWLOG(args) do {if (dhd_msg_level & DHD_FWLOG_VAL) \ @@ -391,20 +393,11 @@ do { \ #endif /* DHD_LOG_DUMP */ #define DHD_DBGIF(args) do {if (dhd_msg_level & DHD_DBGIF_VAL) printf args;} while (0) +#define DHD_TXFLOWCTL(args) DHD_RPM(args) -#ifdef DHD_PCIE_NATIVE_RUNTIMEPM -#define DHD_RPM(args) do {if (dhd_msg_level & DHD_RPM_VAL) printf args;} while (0) -#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ - -#ifdef CUSTOMER_HW4_DEBUG -#define DHD_TRACE_HW4 DHD_ERROR -#define DHD_INFO_HW4 DHD_ERROR -#define DHD_ERROR_NO_HW4 DHD_INFO -#else #define DHD_TRACE_HW4 DHD_TRACE #define DHD_INFO_HW4 DHD_INFO #define DHD_ERROR_NO_HW4 DHD_ERROR -#endif /* CUSTOMER_HW4_DEBUG */ #define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL) #define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL) @@ -442,25 +435,6 @@ do { \ {DHD_NDDBG_OUTPUT args;}} while (0) #define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) \ {DHD_NDDBG_OUTPUT args;}} while (0) -#elif defined(DHD_EFI) && defined(DHD_LOG_DUMP) -#define DHD_ERROR(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - printf args; \ - DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) -#define DHD_INFO(args) \ -do { \ - if (dhd_msg_level & DHD_INFO_VAL) { \ - printf args; \ - DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) -#define DHD_TRACE(args) -#define DHD_ERROR_ROAM(args) DHD_ERROR(args) #else /* DHD_EFI && DHD_LOG_DUMP */ #define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_VAL) \ @@ -478,19 +452,8 @@ do { \ #define DHD_INTR(args) #define DHD_GLOM(args) -#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) -#define DHD_EVENT(args) \ -do { \ - if (dhd_msg_level & DHD_EVENT_VAL) { \ - DHD_LOG_DUMP_WRITE_FW("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE_FW args; \ - } \ -} while (0) -#define DHD_ECNTR_LOG(args) DHD_EVENT(args) -#else #define DHD_EVENT(args) #define DHD_ECNTR_LOG(args) DHD_EVENT(args) -#endif /* DHD_EFI && DHD_LOG_DUMP */ #define DHD_PRSRV_MEM(args) DHD_EVENT(args) @@ -502,61 +465,21 @@ do { \ #define DHD_RTT(args) #define DHD_PKT_MON(args) -#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) -#define DHD_MSGTRACE_LOG(args) \ -do { \ - if (dhd_msg_level & DHD_MSGTRACE_VAL) { \ - DHD_LOG_DUMP_WRITE_FW("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE_FW args; \ - } \ -} while (0) -#define DHD_FWLOG(args) DHD_MSGTRACE_LOG(args) -#else #define DHD_MSGTRACE_LOG(args) #define DHD_FWLOG(args) -#endif /* DHD_EFI && DHD_LOG_DUMP */ #define DHD_DBGIF(args) -#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) -#define DHD_ERROR_MEM(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) -#define DHD_IOVAR_MEM(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) -#define DHD_LOG_MEM(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) -#define DHD_ERROR_EX(args) DHD_ERROR(args) -#else #define DHD_ERROR_MEM(args) DHD_ERROR(args) #define DHD_IOVAR_MEM(args) DHD_ERROR(args) #define DHD_LOG_MEM(args) DHD_ERROR(args) #define DHD_ERROR_EX(args) DHD_ERROR(args) -#endif /* DHD_EFI */ #define DHD_ERROR_ROAM(args) DHD_ERROR(args) -#ifdef CUSTOMER_HW4_DEBUG -#define DHD_TRACE_HW4 DHD_ERROR -#define DHD_INFO_HW4 DHD_ERROR -#define DHD_ERROR_NO_HW4 DHD_INFO -#else +#define DHD_RPM(args) DHD_ERROR(args) +#define DHD_TXFLOWCTL(args) DHD_ERROR(args) #define DHD_TRACE_HW4 DHD_TRACE #define DHD_INFO_HW4 DHD_INFO #define DHD_ERROR_NO_HW4 DHD_ERROR -#endif /* CUSTOMER_HW4_DEBUG */ #define DHD_ERROR_ON() 0 #define DHD_TRACE_ON() 0 @@ -616,21 +539,34 @@ do { \ #define DHD_LOG(args) #endif -#if defined(BCMINTERNAL) && defined(LINUX) && defined(BCMSDIO) && (defined(BCMDBG) || \ - defined(DHD_DEBUG)) -extern void dhd_blog(char *cp, int size); -#define DHD_BLOG(cp, size) do { dhd_blog(cp, size);} while (0) -#else #define DHD_BLOG(cp, size) -#endif #define DHD_NONE(args) extern int dhd_msg_level; -extern int dbgring_msg_level; +extern int dhd_log_level; #ifdef DHD_LOG_PRINT_RATE_LIMIT extern int log_print_threshold; #endif /* DHD_LOG_PRINT_RATE_LIMIT */ +#ifdef DHD_IOVAR_LOG_FILTER_DUMP +#define DHD_IOVAR_LOG_CHECK(dhd_pub, ioc_cmd, ioc_msg) \ + dhd_iovar_log_dump_check(dhd_pub, ioc_cmd, ioc_msg) +#else +#define DHD_IOVAR_LOG_CHECK(dhd_pub, ioc_cmd, ioc_msg) TRUE +#endif /* DHD_IOVAR_LOG_FILTER_DUMP */ + +#define DHD_IOVAR_LOG(dhd_pub, ioc_cmd, ioc_msg, fmt) \ + do { \ + if (DHD_IOVAR_LOG_CHECK(dhd_pub, ioc_cmd, ioc_msg)) { \ + DHD_IOVAR_MEM(fmt); \ + } else { \ + DHD_TRACE(fmt); \ + } \ + } while (0) + +/* DHD_PRINT - informational non-error messages which need to be always printed */ +#define DHD_PRINT DHD_ERROR + /* Defines msg bits */ #include diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg_ring.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg_ring.c old mode 100755 new mode 100644 index d78d21ef3e79..b1c3d85c89fe --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg_ring.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg_ring.c @@ -1,7 +1,7 @@ /* * DHD debug ring API and structures - implementation * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -30,6 +30,7 @@ #include #include #include +#include dhd_dbg_ring_t * dhd_dbg_ring_alloc_init(dhd_pub_t *dhd, uint16 ring_id, @@ -97,7 +98,14 @@ dhd_dbg_ring_init(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, uint16 id, uint8 *name, unsigned long flags = 0; if (allocd_buf == NULL) { - return BCME_NOMEM; + /* for DEBUG_DUMP and MEM_DUMP, buffer can be NULL + * since act as delayed allocation or fake rings + */ + if (id != DEBUG_DUMP_RING1_ID && id != DEBUG_DUMP_RING2_ID && + id != MEM_DUMP_RING_ID) { + return BCME_NOMEM; + } + buf = NULL; } else { buf = allocd_buf; } @@ -120,6 +128,17 @@ dhd_dbg_ring_init(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, uint16 id, uint8 *name, return BCME_OK; } +int +dhd_dbg_ring_set_buf(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, void *buf) +{ + unsigned long flags = 0; + + DHD_DBG_RING_LOCK(ring->lock, flags); + ring->ring_buf = buf; + DHD_DBG_RING_UNLOCK(ring->lock, flags); + + return BCME_OK; +} void dhd_dbg_ring_deinit(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring) { @@ -182,6 +201,38 @@ dhd_dbg_ring_get_pending_len(dhd_dbg_ring_t *ring) return pending_len; } +#ifdef DHD_PKT_LOGGING_DBGRING +int +dhd_dbg_ring_update(void *dbg_ring, uint32 w_len) +{ + unsigned long flags; + dhd_dbg_ring_t *ring = (dhd_dbg_ring_t *)dbg_ring; + + if (ring->id != PACKET_LOG_RING_ID) { + return BCME_UNSUPPORTED; + } + + DHD_DBG_RING_LOCK(ring->lock, flags); + + if (ring->state != RING_ACTIVE) { + DHD_DBG_RING_UNLOCK(ring->lock, flags); + return BCME_OK; + } + + /* update statistics */ + ring->stat.written_records++; + ring->stat.written_bytes += w_len; + DHD_DBGIF(("%s : RING%d[%s] written_records %d, written_bytes %d, read_bytes=%d," + " ring->threshold=%d, wp=%d, rp=%d\n", __FUNCTION__, ring->id, ring->name, + ring->stat.written_records, ring->stat.written_bytes, ring->stat.read_bytes, + ring->threshold, ring->wp, ring->rp)); + + DHD_DBG_RING_UNLOCK(ring->lock, flags); + + return BCME_OK; +} +#endif /* DHD_PKT_LOGGING_DBGRING */ + int dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data) { @@ -189,11 +240,22 @@ dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data) uint32 w_len; uint32 avail_size; dhd_dbg_ring_entry_t *w_entry, *r_entry; + int ret; if (!ring || !hdr || !data) { return BCME_BADARG; } +#if defined(__linux__) + /* Prevents the case of accessing the ring buffer in the HardIRQ context. + * If an interrupt arise after holding ring lock, It could try the same lock. + * This is to use the ring lock as spin_lock_bh instead of spin_lock_irqsave. + */ + if (in_irq()) { + return BCME_BUSY; + } +#endif /* defined(__linux__) */ + DHD_DBG_RING_LOCK(ring->lock, flags); if (ring->state != RING_ACTIVE) { @@ -254,7 +316,7 @@ dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data) ring->rp); /* check bounds before incrementing read ptr */ if (ring->rp + ENTRY_LENGTH(r_entry) >= ring->ring_size) { - DHD_ERROR(("%s: RING%d[%s] rp points out of boundary," + DHD_DBGIF(("%s: RING%d[%s] rp points out of boundary," "ring->wp=%u, ring->rp=%u, ring->ring_size=%d\n", __FUNCTION__, ring->id, ring->name, ring->wp, ring->rp, ring->ring_size)); @@ -286,7 +348,7 @@ dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data) /* check before writing to the ring */ if (ring->wp + w_len >= ring->ring_size) { - DHD_ERROR(("%s: RING%d[%s] wp pointed out of ring boundary, " + DHD_DBGIF(("%s: RING%d[%s] wp pointed out of ring boundary, " "wp=%d, ring_size=%d, w_len=%u\n", __FUNCTION__, ring->id, ring->name, ring->wp, ring->ring_size, w_len)); ASSERT(0); @@ -296,10 +358,22 @@ dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data) w_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + ring->wp); /* header */ - memcpy(w_entry, hdr, DBG_RING_ENTRY_SIZE); + ret = memcpy_s(w_entry, avail_size, hdr, DBG_RING_ENTRY_SIZE); + if (ret) { + DHD_ERROR((" memcpy_s() error : %d, destsz: %d, n: %d\n", + ret, avail_size, (int)DBG_RING_ENTRY_SIZE)); + return BCME_ERROR; + } w_entry->len = hdr->len; /* payload */ - memcpy((char *)w_entry + DBG_RING_ENTRY_SIZE, data, w_entry->len); + avail_size -= DBG_RING_ENTRY_SIZE; + ret = memcpy_s((char *)w_entry + DBG_RING_ENTRY_SIZE, + avail_size, data, w_entry->len); + if (ret) { + DHD_ERROR((" memcpy_s() error : %d, destsz: %d, n: %d\n", + ret, avail_size, w_entry->len)); + return BCME_ERROR; + } /* update write pointer */ ring->wp += w_len; @@ -325,11 +399,13 @@ dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool dhd_dbg_ring_entry_t *r_entry = NULL; uint32 rlen = 0; char *buf = NULL; + unsigned long flags; if (!ring || !data || buf_len <= 0) { return 0; } + DHD_DBG_RING_LOCK(ring->lock, flags); /* pull from ring is allowed for inactive (suspended) ring * in case of ecounters only, this is because, for ecounters * when a trap occurs the ring is suspended and data is then @@ -353,7 +429,7 @@ dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool /* Boundary Check */ rlen = ENTRY_LENGTH(r_entry); if ((ring->rp + rlen) > ring->ring_size) { - DHD_ERROR(("%s: entry len %d is out of boundary of ring size %d," + DHD_DBGIF(("%s: entry len %d is out of boundary of ring size %d," " current ring %d[%s] - rp=%d\n", __FUNCTION__, rlen, ring->ring_size, ring->id, ring->name, ring->rp)); rlen = 0; @@ -368,12 +444,17 @@ dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool buf = (char *)r_entry; } if (rlen > buf_len) { - DHD_ERROR(("%s: buf len %d is too small for entry len %d\n", + DHD_DBGIF(("%s: buf len %d is too small for entry len %d\n", __FUNCTION__, buf_len, rlen)); - DHD_ERROR(("%s: ring %d[%s] - ring size=%d, wp=%d, rp=%d\n", + DHD_DBGIF(("%s: ring %d[%s] - ring size=%d, wp=%d, rp=%d\n", __FUNCTION__, ring->id, ring->name, ring->ring_size, ring->wp, ring->rp)); - ASSERT(0); + /* The state of ringbuffer is different between calculating buf_len + * and current. ring->rp have chance to be update by pushing data + * to ring buffer when unlocking after calculating buf_len. + * But, It doesn't need to ASSERT because we only send up the + * entries stored so far. + */ rlen = 0; goto exit; } @@ -391,7 +472,7 @@ dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool ring->rem_len = 0; } if (ring->rp >= ring->ring_size) { - DHD_ERROR(("%s: RING%d[%s] rp pointed out of ring boundary," + DHD_DBGIF(("%s: RING%d[%s] rp pointed out of ring boundary," " rp=%d, ring_size=%d\n", __FUNCTION__, ring->id, ring->name, ring->rp, ring->ring_size)); ASSERT(0); @@ -403,21 +484,27 @@ dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool ring->id, ring->name, ring->stat.read_bytes, ring->wp, ring->rp)); exit: + DHD_DBG_RING_UNLOCK(ring->lock, flags); return rlen; } int -dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_hdr) +dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, + bool strip_hdr, int *num_entries) { int32 r_len, total_r_len = 0; + unsigned long flags; if (!ring || !data) return 0; + DHD_DBG_RING_LOCK(ring->lock, flags); if (!ring->pull_inactive && (ring->state != RING_ACTIVE)) { + DHD_DBG_RING_UNLOCK(ring->lock, flags); return 0; } + DHD_DBG_RING_UNLOCK(ring->lock, flags); while (buf_len > 0) { r_len = dhd_dbg_ring_pull_single(ring, data, buf_len, strip_hdr); @@ -426,6 +513,7 @@ dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_h data = (uint8 *)data + r_len; buf_len -= r_len; total_r_len += r_len; + (*num_entries)++; } return total_r_len; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg_ring.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg_ring.h old mode 100755 new mode 100644 index bab864699254..cce8f15c64fc --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg_ring.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_dbg_ring.h @@ -1,7 +1,7 @@ /* * DHD debug ring header file - interface * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -52,6 +52,11 @@ typedef struct dhd_dbg_ring_entry { uint64 timestamp; /* present if has_timestamp bit is set. */ } PACKED_STRUCT dhd_dbg_ring_entry_t; +typedef struct dhd_dbg_ring_entry_pack { + uint32 magic; + int num_entries; +} PACKED_STRUCT dhd_dbg_ring_entry_pack_t; + struct ring_statistics { /* number of bytes that was written to the buffer by driver */ uint32 written_bytes; @@ -95,7 +100,9 @@ typedef struct dhd_dbg_ring { bool pull_inactive; /* pull contents from ring even if it is inactive */ } dhd_dbg_ring_t; -#define DBGRING_FLUSH_THRESHOLD(ring) (ring->ring_size / 3) +#define DBGRING_FLUSH_THRESHOLD(ring) \ + (ring->id != PACKET_LOG_RING_ID) ? \ + (ring->ring_size / 3u) : (ring->ring_size / 4u) #define RING_STAT_TO_STATUS(ring, status) \ do { \ /* status.name/ring->name are the same length so no need to check return value */ \ @@ -108,10 +115,11 @@ typedef struct dhd_dbg_ring { status.verbose_level = ring->log_level; \ } while (0) +#define DBG_RING_PACK_MAGIC 0xDBAADBAA +#define DBG_RING_ENTRY_PACK_SIZE (sizeof(dhd_dbg_ring_entry_pack_t)) #define DBG_RING_ENTRY_SIZE (sizeof(dhd_dbg_ring_entry_t)) #define ENTRY_LENGTH(hdr) ((hdr)->len + DBG_RING_ENTRY_SIZE) #define PAYLOAD_MAX_LEN 65535 -#define PAYLOAD_ECNTR_MAX_LEN 1648u #define PAYLOAD_RTT_MAX_LEN 1648u #define PAYLOAD_BCM_TRACE_MAX_LEN 1648u #define PENDING_LEN_MAX 0xFFFFFFFF @@ -133,9 +141,13 @@ void dhd_dbg_ring_dealloc_deinit(void **dbgring, dhd_pub_t *dhd); int dhd_dbg_ring_init(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, uint16 id, uint8 *name, uint32 ring_sz, void *allocd_buf, bool pull_inactive); void dhd_dbg_ring_deinit(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring); +int dhd_dbg_ring_set_buf(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, void *buf); +#ifdef DHD_PKT_LOGGING_DBGRING +int dhd_dbg_ring_update(void *dbg_ring, uint32 w_len); +#endif /* DHD_PKT_LOGGING_DBGRING */ int dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data); int dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, - bool strip_hdr); + bool strip_hdr, int* num_entries); int dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_header); uint32 dhd_dbg_ring_get_pending_len(dhd_dbg_ring_t *ring); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug.c old mode 100755 new mode 100644 index ac77b2062355..b99a6c5bf60f --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug.c @@ -1,7 +1,7 @@ /* * DHD debugability support * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -38,25 +38,32 @@ #include #include #include +#if defined(DBG_PKT_MON) +#include +#include +#endif /* DBG_PKT_MON */ +#if defined(DHD_PKT_LOGGING) && defined(DHD_PKT_LOGGING_DBGRING) +#include +#endif /* DHD_PKT_LOGGING && DHD_PKT_LOGGING_DBGRING */ #if defined(DHD_EVENT_LOG_FILTER) #include #endif /* DHD_EVENT_LOG_FILTER */ -#if defined(DHD_EFI) || defined(NDIS) +#ifdef WL_CFGVENDOR_CUST_ADVLOG +void wl_cfgvendor_custom_advlog_roam_log(void *plog, uint32 armcycle); +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ + +#if defined(NDIS) #if !defined(offsetof) #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif /* !defined(offsetof) */ #define container_of(ptr, type, member) \ (type *)((char *)(ptr) - offsetof(type, member)) -#endif /* defined(DHD_EFI ) || defined(NDIS) */ +#endif /* NDIS */ -#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING -uint8 control_logtrace = LOGTRACE_RAW_FMT; -#else uint8 control_logtrace = CUSTOM_CONTROL_LOGTRACE; -#endif struct map_table { uint16 fw_id; @@ -117,53 +124,31 @@ struct map_table event_tag_map[] = { {TRACE_TAG_RATE_MBPS, WIFI_TAG_RATE_MBPS, "RATE"}, }; +struct event_log_table { + int log_level; + uint16 tag; + uint8 set; + char *desc; +}; + /* define log level per ring type */ -struct log_level_table fw_verbose_level_map[] = { - {1, EVENT_LOG_TAG_PCI_ERROR, "PCI_ERROR"}, -#ifndef DISABLE_PCI_LOGGING - {1, EVENT_LOG_TAG_PCI_WARN, "PCI_WARN"}, - {2, EVENT_LOG_TAG_PCI_INFO, "PCI_INFO"}, - {3, EVENT_LOG_TAG_PCI_DBG, "PCI_DEBUG"}, -#endif -#ifndef DISABLE_BEACON_LOGGING - {3, EVENT_LOG_TAG_BEACON_LOG, "BEACON_LOG"}, -#endif - {2, EVENT_LOG_TAG_WL_ASSOC_LOG, "ASSOC_LOG"}, - {2, EVENT_LOG_TAG_WL_ROAM_LOG, "ROAM_LOG"}, - {1, EVENT_LOG_TAG_TRACE_WL_INFO, "WL INFO"}, - {1, EVENT_LOG_TAG_TRACE_BTCOEX_INFO, "BTCOEX INFO"}, +struct event_log_table fw_verbose_level_map[] = { + {1, EVENT_LOG_TAG_PCI_ERROR, EVENT_LOG_SET_BUS, "PCI_ERROR"}, + {1, EVENT_LOG_TAG_PCI_WARN, EVENT_LOG_SET_PRSRV_BUS, "PCI_WARN"}, + {1, EVENT_LOG_TAG_PCI_INFO, EVENT_LOG_SET_BUS, "PCI_INFO"}, + {3, EVENT_LOG_TAG_PCI_DBG, EVENT_LOG_SET_BUS, "PCI_DEBUG"}, + {2, EVENT_LOG_TAG_BEACON_LOG, EVENT_LOG_SET_PRSRV_CHATTY, "BEACON_LOG"}, + {1, EVENT_LOG_TAG_WL_ASSOC_LOG, EVENT_LOG_SET_PRSRV, "ASSOC_LOG"}, + {1, EVENT_LOG_TAG_WL_ROAM_LOG, EVENT_LOG_SET_PRSRV, "ROAM_LOG"}, + {1, EVENT_LOG_TAG_TRACE_WL_INFO, EVENT_LOG_SET_WL, "WL INFO"}, + {1, EVENT_LOG_TAG_TRACE_BTCOEX_INFO, EVENT_LOG_SET_WL, "BTCOEX INFO"}, #ifdef DHD_RANDMAC_LOGGING - {1, EVENT_LOG_TAG_RANDMAC_ERR, "RANDMAC_ERR"}, + {1, EVENT_LOG_TAG_RANDMAC_ERR, EVENT_LOG_SET_PRSRV, "RANDMAC_ERR"}, #endif /* DHD_RANDMAC_LOGGING */ -#ifdef CUSTOMER_HW4_DEBUG - {3, EVENT_LOG_TAG_SCAN_WARN, "SCAN_WARN"}, -#else - {1, EVENT_LOG_TAG_SCAN_WARN, "SCAN_WARN"}, -#endif /* CUSTOMER_HW4_DEBUG */ - {1, EVENT_LOG_TAG_SCAN_ERROR, "SCAN_ERROR"}, - {2, EVENT_LOG_TAG_SCAN_TRACE_LOW, "SCAN_TRACE_LOW"}, - {2, EVENT_LOG_TAG_SCAN_TRACE_HIGH, "SCAN_TRACE_HIGH"}, -#ifdef DHD_WL_ERROR_LOGGING - {3, EVENT_LOG_TAG_WL_ERROR, "WL_ERROR"}, -#endif -#ifdef DHD_IE_ERROR_LOGGING - {3, EVENT_LOG_TAG_IE_ERROR, "IE_ERROR"}, -#endif -#ifdef DHD_ASSOC_ERROR_LOGGING - {3, EVENT_LOG_TAG_ASSOC_ERROR, "ASSOC_ERROR"}, -#endif -#ifdef DHD_PMU_ERROR_LOGGING - {3, EVENT_LOG_TAG_PMU_ERROR, "PMU_ERROR"}, -#endif -#ifdef DHD_8021X_ERROR_LOGGING - {3, EVENT_LOG_TAG_4WAYHANDSHAKE, "8021X_ERROR"}, -#endif -#ifdef DHD_AMPDU_ERROR_LOGGING - {3, EVENT_LOG_TAG_AMSDU_ERROR, "AMPDU_ERROR"}, -#endif -#ifdef DHD_SAE_ERROR_LOGGING - {3, EVENT_LOG_TAG_SAE_ERROR, "SAE_ERROR"}, -#endif + {1, EVENT_LOG_TAG_SCAN_WARN, EVENT_LOG_SET_PRSRV_CHATTY, "SCAN_WARN"}, + {2, EVENT_LOG_TAG_SCAN_ERROR, EVENT_LOG_SET_ERROR, "SCAN_ERROR"}, + {1, EVENT_LOG_TAG_SCAN_TRACE_LOW, EVENT_LOG_SET_PRSRV, "SCAN_TRACE_LOW"}, + {1, EVENT_LOG_TAG_SCAN_TRACE_HIGH, EVENT_LOG_SET_WL, "SCAN_TRACE_HIGH"}, }; /* reference tab table */ @@ -188,6 +173,81 @@ struct tracelog_header { }; #define TRACE_LOG_MAGIC_NUMBER 0xEAE47C06 +#ifdef DHD_PKT_LOGGING_DBGRING +int +dhd_dbg_update_to_ring(dhd_pub_t *dhdp, void *ring, uint32 w_len) +{ + return dhd_dbg_push_to_ring(dhdp, ((dhd_dbg_ring_t *)ring)->id, NULL, (void*)&w_len); +} + +static uint32 +dhd_dbg_urgent_pull(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring) +{ + uint32 pending_len = 0; + struct dhd_pktlog_ring *pktlog_ring; + + if (ring->id != PACKET_LOG_RING_ID) { + return pending_len; + } + + if (ring->stat.written_bytes > ring->stat.read_bytes) { + pending_len = ring->stat.written_bytes - ring->stat.read_bytes; + } else { + pending_len = 0; + } + + pktlog_ring = dhdp->pktlog->pktlog_ring; + if (pktlog_ring->pktcount >= DHD_PACKET_LOG_RING_SUSPEND_THRESHOLD) { + dhd_pktlog_suspend(dhdp); + } + + if (pending_len > ring->threshold) { + DHD_INFO(("%s: pending_len(%d) is exceeded threshold(%d), pktcount(%d)\n", + __FUNCTION__, pending_len, ring->threshold, pktlog_ring->pktcount)); + } + + return pending_len; +} +#endif /* DHD_PKT_LOGGING_DBGRING */ + +#ifdef DHD_DEBUGABILITY_DEBUG_DUMP +int +dhd_debug_dump_ring_push(dhd_pub_t *dhdp, int ring_id, uint32 len, void *data) +{ + dhd_dbg_ring_t *ring; + int ret = 0; + uint32 remain_len = 0; + char *cur_buf; + dhd_dbg_ring_entry_t msg_hdr; + + if (!dhdp || !dhdp->dbg) { + return BCME_BADADDR; + } + + if (!VALID_RING(ring_id)) { + DHD_ERROR(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id)); + return BCME_RANGE; + } + + ring = &dhdp->dbg->dbg_rings[ring_id]; + + remain_len = len; + cur_buf = data; + + memset(&msg_hdr, 0, sizeof(msg_hdr)); + while (remain_len > 0) { + msg_hdr.type = DBG_RING_ENTRY_DATA_TYPE; + msg_hdr.len = MIN(remain_len, DHD_DEBUG_DUMP_NETLINK_MAX); + ret = dhd_dbg_ring_push(ring, &msg_hdr, cur_buf); + if (ret == BCME_OK) { + cur_buf += msg_hdr.len; + remain_len -= msg_hdr.len; + } + } + return ret; +} +#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */ + int dhd_dbg_push_to_ring(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_entry_t *hdr, void *data) { @@ -206,13 +266,25 @@ dhd_dbg_push_to_ring(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_entry_t *hdr, vo ring = &dhdp->dbg->dbg_rings[ring_id]; - ret = dhd_dbg_ring_push(ring, hdr, data); +#ifdef DHD_PKT_LOGGING_DBGRING + if (ring_id == PACKET_LOG_RING_ID) { + ret = dhd_dbg_ring_update(ring, *(uint32*)data); + } else +#endif /* DHD_PKT_LOGGING_DBGRING */ + { + ret = dhd_dbg_ring_push(ring, hdr, data); + } if (ret != BCME_OK) return ret; - pending_len = dhd_dbg_ring_get_pending_len(ring); +#ifdef DHD_PKT_LOGGING_DBGRING + pending_len = dhd_dbg_urgent_pull(dhdp, ring); +#endif /* DHD_PKT_LOGGING_DBGRING */ + if (pending_len == 0) { + pending_len = dhd_dbg_ring_get_pending_len(ring); + } dhd_dbg_ring_sched_pull(ring, pending_len, dhdp->dbg->pullreq, - dhdp->dbg->private, ring->id); + dhdp->dbg->private, ring->id); return ret; } @@ -252,19 +324,71 @@ dhd_dbg_pull_single_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 b return dhd_dbg_ring_pull_single(ring, data, buf_len, strip_header); } +#ifdef DHD_PKT_LOGGING_DBGRING +extern int dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, + const void *user_buf, uint32 *written_bytes); + int -dhd_dbg_pull_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len) +dhd_dbg_pull_from_pktlog(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len) +{ + dhd_dbg_ring_entry_t *r_entry = NULL; + char *buf = NULL; + int ret = BCME_OK; + uint32 written_bytes = 0; + + if (!dhdp || !dhdp->dbg) { + return 0; + } + if (!VALID_RING(ring_id)) { + DHD_DBGIF(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id)); + return BCME_RANGE; + } + if (ring_id != PACKET_LOG_RING_ID) { + return BCME_UNSUPPORTED; + } + + r_entry = (dhd_dbg_ring_entry_t *)data; + r_entry->len = buf_len - DBG_RING_ENTRY_SIZE; + written_bytes = (uint32)r_entry->len; + if (!written_bytes) { + return 0; + } + + r_entry->type = DBG_RING_ENTRY_DATA_TYPE; + r_entry->flags = (DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP | + DBG_RING_ENTRY_FLAGS_HAS_BINARY); + r_entry->timestamp = local_clock(); + r_entry->timestamp = DIV_U64_BY_U32(r_entry->timestamp, NSEC_PER_MSEC); + buf = (char*)data; + + ret = dhd_pktlog_dump_write(dhdp, NULL, buf + DBG_RING_ENTRY_SIZE, &written_bytes); + + if (ret != BCME_OK) { + DHD_DBGIF(("%s : pktlog_dump error\n", __FUNCTION__)); + buf_len = 0; + } else { + r_entry->len = (uint16)written_bytes; + buf_len = r_entry->len + DBG_RING_ENTRY_SIZE; + } + + return buf_len; +} +#endif /* DHD_PKT_LOGGING_DBGRING */ + +int +dhd_dbg_pull_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len, + int *num_entries) { dhd_dbg_ring_t *ring; if (!dhdp || !dhdp->dbg) return 0; if (!VALID_RING(ring_id)) { - DHD_ERROR(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id)); + DHD_DBGIF(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id)); return BCME_RANGE; } ring = &dhdp->dbg->dbg_rings[ring_id]; - return dhd_dbg_ring_pull(ring, data, buf_len, FALSE); + return dhd_dbg_ring_pull(ring, data, buf_len, FALSE, num_entries); } static int @@ -321,11 +445,11 @@ dhd_dbg_msgtrace_msg_parser(void *event_data) */ while (*data != '\0' && (s = strstr(data, "\n")) != NULL) { *s = '\0'; - DHD_FWLOG(("[FWLOG] %s\n", data)); + printf("[FWLOG] %s\n", data); data = s+1; } if (*data) - DHD_FWLOG(("[FWLOG] %s", data)); + printf("[FWLOG] %s", data); } #ifdef SHOW_LOGTRACE #define DATA_UNIT_FOR_LOG_CNT 4 @@ -471,6 +595,7 @@ dhd_dbg_process_event_log_hdr(event_log_hdr_t *log_hdr, prcd_event_log_hdr_t *pr event_log_extended_hdr_t *ext_log_hdr; uint16 event_log_fmt_num; uint8 event_log_hdr_type; + uint8 extended_fmtnum = 0; /* Identify the type of event tag, payload type etc.. */ event_log_hdr_type = log_hdr->fmt_num & DHD_EVENT_LOG_HDR_MASK; @@ -510,14 +635,25 @@ dhd_dbg_process_event_log_hdr(event_log_hdr_t *log_hdr, prcd_event_log_hdr_t *pr if (prcd_log_hdr->ext_event_log_hdr) { ext_log_hdr = (event_log_extended_hdr_t *) ((uint8 *)log_hdr - sizeof(event_log_hdr_t)); + extended_fmtnum = (ext_log_hdr->extended_fmtnum & DHD_EXT_FMTNUM_MASK); + } + /* Parse extended event log tag */ + if (prcd_log_hdr->ext_event_log_hdr) { prcd_log_hdr->tag = ((ext_log_hdr->extended_tag & DHD_TW_VALID_TAG_BITS_MASK) << DHD_TW_EVENT_LOG_TAG_OFFSET) | log_hdr->tag; } else { prcd_log_hdr->tag = log_hdr->tag; } + /* Parse extended format number */ + if ((event_log_hdr_type == DHD_TW_NB_EVENT_LOG_HDR) && (extended_fmtnum != 0)) { + prcd_log_hdr->fmt_num_raw = (extended_fmtnum << 16) | log_hdr->fmt_num; + prcd_log_hdr->fmt_num = (extended_fmtnum << 14) | event_log_fmt_num; + + } else { + prcd_log_hdr->fmt_num_raw = log_hdr->fmt_num; + prcd_log_hdr->fmt_num = event_log_fmt_num; + } prcd_log_hdr->count = log_hdr->count; - prcd_log_hdr->fmt_num_raw = log_hdr->fmt_num; - prcd_log_hdr->fmt_num = event_log_fmt_num; /* update arm cycle */ /* @@ -595,6 +731,11 @@ dhd_dbg_verboselog_handler(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr, DHD_MSGTRACE_LOG(("EVENT_LOG_ROM[0x%08x]: %s", log_ptr[plog_hdr->count - 1], fmtstr_loc_buf)); + if (!strlen(fmtstr_loc_buf)) { + DHD_ERROR(("%s fmt_str_loc_buf len can not be zero\n", __FUNCTION__)); + return; + } + /* Add newline if missing */ if (fmtstr_loc_buf[strlen(fmtstr_loc_buf) - 1] != '\n') DHD_MSGTRACE_LOG(("\n")); @@ -659,7 +800,7 @@ dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr, #endif /* DHD_LOG_PRINT_RATE_LIMIT */ /* print the message out in a logprint */ if ((control_logtrace == LOGTRACE_RAW_FMT) || !(raw_event->fmts)) { - if (dhdp->dbg) { + if (dhdp->dbg && dhdp->dbg->dbg_rings[FW_VERBOSE_RING_ID].state != RING_STOP) { log_level = dhdp->dbg->dbg_rings[FW_VERBOSE_RING_ID].log_level; for (id = 0; id < ARRAYSIZE(fw_verbose_level_map); id++) { if ((fw_verbose_level_map[id].tag == plog_hdr->tag) && @@ -709,14 +850,10 @@ dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr, /* ensure preserve fw logs go to debug_dump only in case of customer4 */ if (logset < dhdp->event_log_max_sets && - ((0x01u << logset) & dhdp->logset_prsrv_mask)) { + ((0x01ULL << logset) & dhdp->logset_prsrv_mask)) { DHD_PRSRV_MEM(("%s\n", b.origbuf)); } else { -#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING - DHD_FW_VERBOSE(("%s\n", b.origbuf)); -#else DHD_FWLOG(("%s\n", b.origbuf)); -#endif #ifdef DHD_LOG_PRINT_RATE_LIMIT log_print_count++; #endif /* DHD_LOG_PRINT_RATE_LIMIT */ @@ -731,7 +868,7 @@ dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr, return; } - if ((plog_hdr->fmt_num) < raw_event->num_fmts) { + if ((plog_hdr->fmt_num < raw_event->num_fmts) && (plog_hdr->binary_payload == FALSE)) { if (plog_hdr->tag == EVENT_LOG_TAG_MSCHPROFILE) { snprintf(fmtstr_loc_buf, FMTSTR_SIZE, "%s", raw_event->fmts[plog_hdr->fmt_num]); @@ -758,8 +895,8 @@ dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr, goto exit; } - if (plog_hdr->count > MAX_NO_OF_ARG) { - DHD_ERROR(("%s: plog_hdr->count(%d) out of range\n", + if (plog_hdr->binary_payload == FALSE && plog_hdr->count > MAX_NO_OF_ARG) { + DHD_INFO(("%s: plog_hdr->count(%d) out of range\n", __FUNCTION__, plog_hdr->count)); goto exit; } @@ -831,7 +968,7 @@ dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr, /* ensure preserve fw logs go to debug_dump only in case of customer4 */ if (logset < dhdp->event_log_max_sets && - ((0x01u << logset) & dhdp->logset_prsrv_mask)) { + ((0x01ULL << logset) & dhdp->logset_prsrv_mask)) { if (dhd_msg_level & DHD_EVENT_VAL) { if (dhd_msg_level & DHD_PRSRV_MEM_VAL) printk(fmtstr_loc_buf, arg[0], arg[1], arg[2], arg[3], @@ -853,8 +990,7 @@ exit: MFREE(dhdp->osh, str_buf, (MAX_NO_OF_ARG * SIZE_LOC_STR)); } -#if defined(EWP_BCM_TRACE) || defined(EWP_RTT_LOGGING) || \ - defined(EWP_ECNTRS_LOGGING) +#if defined(EWP_BCM_TRACE) || defined(EWP_RTT_LOGGING) || defined(EWP_ECNTRS_LOGGING) static int dhd_dbg_send_evtlog_to_ring(prcd_event_log_hdr_t *plog_hdr, dhd_dbg_ring_entry_t *msg_hdr, dhd_dbg_ring_t *ring, @@ -918,6 +1054,8 @@ dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, uint32 event_log_max_sets; uint min_expected_len = 0; uint16 len_chk = 0; + uint32 datalen_bak = datalen; + uint16 block_hdr_len; BCM_REFERENCE(ecntr_pushed); BCM_REFERENCE(rtt_pushed); @@ -997,9 +1135,7 @@ dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, msg_hdr.len = sizeof(*logentry_header) + datalen; memcpy(logbuf + sizeof(*logentry_header), data, datalen); DHD_DBGIF(("%s: datalen %d %d\n", __FUNCTION__, msg_hdr.len, datalen)); -#ifndef DHD_DEBUGABILITY_LOG_DUMP_RING - dhd_dbg_push_to_ring(dhdp, FW_VERBOSE_RING_ID, &msg_hdr, logbuf); -#endif + /* Print sequence number, originating set and length of received * event log buffer. Refer to event log buffer structure in * event_log.h @@ -1009,12 +1145,13 @@ dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, ltoh16(*((uint16 *)(data))))); logset = ltoh32(*((uint32 *)(data + 4))); + block_hdr_len = ltoh16(*((uint16 *)(data))); if (logset >= event_log_max_sets) { DHD_ERROR(("%s logset: %d max: %d out of range queried: %d\n", __FUNCTION__, logset, event_log_max_sets, event_log_max_sets_queried)); #ifdef DHD_FW_COREDUMP - if (event_log_max_sets_queried) { + if (event_log_max_sets_queried && !dhd_memdump_is_scheduled(dhdp)) { DHD_ERROR(("%s: collect socram for DUMP_TYPE_LOGSET_BEYOND_RANGE\n", __FUNCTION__)); dhdp->memdump_type = DUMP_TYPE_LOGSET_BEYOND_RANGE; @@ -1046,8 +1183,14 @@ dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, log_hdr = (event_log_hdr_t *)(data + datalen - log_hdr_len); memset(&prcd_log_hdr, 0, sizeof(prcd_log_hdr)); if (!dhd_dbg_process_event_log_hdr(log_hdr, &prcd_log_hdr)) { - DHD_ERROR(("%s: Error while parsing event log header\n", - __FUNCTION__)); + DHD_ERROR(("%s: Error while parsing event log header " + "set:%u block:%u block_hdr_len:%d " + "datalen:%u cur_datalen:%u msgtrace_hdr_present:%d\n", + __FUNCTION__, logset, block, block_hdr_len, + datalen_bak, datalen, msgtrace_hdr_present)); + dhd_prhex("[event_data]", (char*)event_data, datalen_bak, + DHD_ERROR_VAL); + break; } /* skip zero padding at end of frame */ @@ -1084,10 +1227,16 @@ dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, /* skip 4 bytes time stamp packet */ if (prcd_log_hdr.tag == EVENT_LOG_TAG_TS || prcd_log_hdr.tag == EVENT_LOG_TAG_ENHANCED_TS) { - datalen -= (log_pyld_len + log_hdr_len); + if (datalen >= (log_pyld_len + log_hdr_len)) { + datalen -= (log_pyld_len + log_hdr_len); + } else { + DHD_ERROR(("%s: invalid length : %d < %d + %d\n", + __FUNCTION__, datalen, log_pyld_len, log_hdr_len)); + datalen = 0; + } continue; } - if (!(log_item = MALLOC(dhdp->osh, sizeof(*log_item)))) { + if (!(log_item = VMALLOC(dhdp->osh, sizeof(*log_item)))) { DHD_ERROR(("%s allocating log list item failed\n", __FUNCTION__)); break; @@ -1104,7 +1253,13 @@ dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, log_item->prcd_log_hdr.binary_payload = prcd_log_hdr.binary_payload; dll_insert(&log_item->list, &list_head); - datalen -= (log_pyld_len + log_hdr_len); + if (datalen >= (log_pyld_len + log_hdr_len)) { + datalen -= (log_pyld_len + log_hdr_len); + } else { + DHD_ERROR(("%s: invalid length : %d < %d + %d\n", + __FUNCTION__, datalen, log_pyld_len, log_hdr_len)); + datalen = 0; + } } while (!dll_empty(&list_head)) { @@ -1124,7 +1279,7 @@ dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, if (!ecntr_pushed && dhd_log_dump_ecntr_enabled()) { if (dhd_dbg_send_evtlog_to_ring(plog_hdr, &msg_hdr, dhdp->ecntr_dbg_ring, - PAYLOAD_ECNTR_MAX_LEN, logbuf) != BCME_OK) { + EVENT_LOG_MAX_BLOCK_SIZE, logbuf) != BCME_OK) { goto exit; } ecntr_pushed = TRUE; @@ -1162,7 +1317,7 @@ dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, } #endif /* EWP_BCM_TRACE */ -#if defined (DHD_EVENT_LOG_FILTER) +#if defined(DHD_EVENT_LOG_FILTER) if (plog_hdr->tag == EVENT_LOG_TAG_STATS) { dhd_event_log_filter_event_handler(dhdp, plog_hdr, plog_hdr->log_ptr); } @@ -1172,7 +1327,7 @@ dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, logset, block, (uint32 *)data); } dll_delete(cur); - MFREE(dhdp->osh, log_item, sizeof(*log_item)); + VMFREE(dhdp->osh, log_item, sizeof(*log_item)); } BCM_REFERENCE(log_hdr); @@ -1185,7 +1340,7 @@ exit: GCC_DIAGNOSTIC_POP(); dll_delete(cur); - MFREE(dhdp->osh, log_item, sizeof(*log_item)); + VMFREE(dhdp->osh, log_item, sizeof(*log_item)); } VMFREE(dhdp->osh, logbuf, ring_data_len); @@ -1218,29 +1373,11 @@ dhd_dbg_trace_evnt_handler(dhd_pub_t *dhdp, void *event_data, dhd_dbg_msgtrace_log_parser(dhdp, event_data, raw_event_ptr, datalen, TRUE, 0); } -#ifdef BTLOG -void -dhd_dbg_bt_log_handler(dhd_pub_t *dhdp, void *data, uint datalen) -{ - dhd_dbg_ring_entry_t msg_hdr; - int ret; - - /* push to ring */ - memset(&msg_hdr, 0, sizeof(msg_hdr)); - msg_hdr.type = DBG_RING_ENTRY_DATA_TYPE; - msg_hdr.len = datalen; - ret = dhd_dbg_push_to_ring(dhdp, BT_LOG_RING_ID, &msg_hdr, data); - if (ret != BCME_OK) { - DHD_ERROR(("%s ring push failed %d\n", __FUNCTION__, ret)); - } -} -#endif /* BTLOG */ - /* * dhd_dbg_set_event_log_tag : modify the state of an event log tag */ void -dhd_dbg_set_event_log_tag(dhd_pub_t *dhdp, uint16 tag, uint8 set) +dhd_dbg_set_event_log_tag(dhd_pub_t *dhdp, uint16 tag, uint8 set_num, uint8 is_set) { wl_el_tag_params_t pars; char *cmd = "event_log_tag_control"; @@ -1249,8 +1386,8 @@ dhd_dbg_set_event_log_tag(dhd_pub_t *dhdp, uint16 tag, uint8 set) memset(&pars, 0, sizeof(pars)); pars.tag = tag; - pars.set = set; - pars.flags = EVENT_LOG_TAG_FLAG_LOG; + pars.set = set_num; + pars.flags = (is_set) ? EVENT_LOG_TAG_FLAG_LOG : EVENT_LOG_TAG_FLAG_NONE; if (!bcm_mkiovar(cmd, (char *)&pars, sizeof(pars), iovbuf, sizeof(iovbuf))) { DHD_ERROR(("%s mkiovar failed\n", __FUNCTION__)); @@ -1259,7 +1396,7 @@ dhd_dbg_set_event_log_tag(dhd_pub_t *dhdp, uint16 tag, uint8 set) ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); if (ret) { - /* DHD_ERROR(("%s set log tag iovar failed %d\n", __FUNCTION__, ret)); */ +// DHD_ERROR(("%s set log tag iovar failed %d\n", __FUNCTION__, ret)); } } @@ -1269,7 +1406,7 @@ dhd_dbg_set_configuration(dhd_pub_t *dhdp, int ring_id, int log_level, int flags dhd_dbg_ring_t *ring; uint8 set = 1; int i, array_len = 0; - struct log_level_table *log_level_tbl = NULL; + struct event_log_table *log_level_tbl = NULL; if (!dhdp || !dhdp->dbg) return BCME_BADADDR; @@ -1300,7 +1437,8 @@ dhd_dbg_set_configuration(dhd_pub_t *dhdp, int ring_id, int log_level, int flags set = (ref_tag_tbl[log_level_tbl[i].tag])? 1 : 0; DHD_DBGIF(("%s TAG(%s) is %s for the ring(%s)\n", __FUNCTION__, log_level_tbl[i].desc, (set)? "SET" : "CLEAR", ring->name)); - dhd_dbg_set_event_log_tag(dhdp, log_level_tbl[i].tag, set); + dhd_dbg_set_event_log_tag(dhdp, log_level_tbl[i].tag, + log_level_tbl[i].set, set); } return BCME_OK; } @@ -1346,7 +1484,7 @@ dhd_dbg_get_ring_status(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_status_t *dbg } } if (!VALID_RING(id)) { - DHD_ERROR(("%s : cannot find the ring_id : %d\n", __FUNCTION__, ring_id)); + DHD_DBGIF(("%s : cannot find the ring_id : %d\n", __FUNCTION__, ring_id)); ret = BCME_NOTFOUND; } return ret; @@ -1473,8 +1611,8 @@ __dhd_dbg_pkt_hash(uintptr_t pkt, uint32 pktid) (__pkt + __pktid * __pktid)); } -#define __TIMESPEC_TO_US(ts) \ - (((uint32)(ts).tv_sec * USEC_PER_SEC) + ((ts).tv_nsec / NSEC_PER_USEC)) +#define __TIMESPEC64_TO_US(ts) \ + (((ts).tv_sec * USEC_PER_SEC) + ((ts).tv_nsec / NSEC_PER_USEC)) uint32 __dhd_dbg_driver_ts_usec(void) @@ -1482,7 +1620,7 @@ __dhd_dbg_driver_ts_usec(void) struct osl_timespec ts; osl_get_monotonic_boottime(&ts); - return ((uint32)(__TIMESPEC_TO_US(ts))); + return ((uint32)(__TIMESPEC64_TO_US(ts))); } wifi_tx_packet_fate @@ -1508,11 +1646,18 @@ __dhd_dbg_map_tx_status_to_pkt_fate(uint16 status) case WLFC_CTL_PKTFLAG_EXPIRED: pkt_fate = TX_PKT_FATE_FW_DROP_EXPTIME; break; -#ifndef OEM_ANDROID + case WLFC_CTL_PKTFLAG_DROPPED: + pkt_fate = TX_PKT_FATE_DRV_DROP_OTHER; + break; case WLFC_CTL_PKTFLAG_MKTFREE: pkt_fate = TX_PKT_FATE_FW_PKT_FREE; break; -#endif /* !OEM_ANDROID */ + case WLFC_CTL_PKTFLAG_MAX_SUP_RETR: + pkt_fate = TX_PKT_FATE_FW_MAX_SUP_RETR; + break; + case WLFC_CTL_PKTFLAG_FORCED_EXPIRED: + pkt_fate = TX_PKT_FATE_FW_FORCED_EXPIRED; + break; default: pkt_fate = TX_PKT_FATE_FW_DROP_OTHER; break; @@ -1523,6 +1668,83 @@ __dhd_dbg_map_tx_status_to_pkt_fate(uint16 status) #endif /* DBG_PKT_MON || DHD_PKT_LOGGING */ #ifdef DBG_PKT_MON +static int do_iovar_aml_enable(dhd_pub_t *dhdp, uint val); +static void dhd_do_aml_disable(void *handle, void *event_info, u8 event); +void dhd_schedule_aml_disable(dhd_pub_t *dhdp); + +static int +do_iovar_aml_enable(dhd_pub_t *dhdp, uint val) +{ + wl_aml_iovar_t *iov_in; + wl_aml_iov_uint_data_t *subcmd; + int buf_size, alloc_len, ret = BCME_OK; + + buf_size = OFFSETOF(wl_aml_iovar_t, data); + alloc_len = buf_size + sizeof(wl_aml_iov_uint_data_t); + + iov_in = MALLOCZ(dhdp->osh, alloc_len); + if (!iov_in) { + DHD_ERROR(("%s: Error allocating %u bytes for aml enable\n", + __FUNCTION__, alloc_len)); + return BCME_NOMEM; + } + + iov_in->hdr.ver = htod16(WL_AML_IOV_VERSION_1_0); + iov_in->hdr.len = htod16(alloc_len); + iov_in->hdr.subcmd = htod16(WL_AML_SUBCMD_ENABLE); + + if (val & ~(1u << WL_AML_ASSOC_ENABLE | 1u << WL_AML_ROAM_ENABLE)) { + ret = BCME_BADARG; + goto fail; + } + + subcmd = (wl_aml_iov_uint_data_t *)iov_in->data; + subcmd->val = htod32(val); + + ret = dhd_iovar(dhdp, 0, "aml", (char *)iov_in, alloc_len, NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s aml failed %d\n", __FUNCTION__, ret)); + ret = BCME_ERROR; + goto fail; + } + +fail: + if (iov_in) { + MFREE(dhdp->osh, iov_in, alloc_len); + } + + return ret; +} + +static void dhd_do_aml_disable(void *handle, void *event_info, u8 event) +{ + dhd_info_t *dhd = (dhd_info_t *)handle; + dhd_pub_t *dhdp = NULL; + uint val = 0; /* Disabled */ + + dhdp = &dhd->pub; + if (!dhdp) { + DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); + return; + } + + if (do_iovar_aml_enable(dhdp, val) == BCME_OK) { + dhdp->aml_enable = FALSE; + } + + return; +} + +void dhd_schedule_aml_disable(dhd_pub_t *dhdp) +{ + if (dhdp->dbg->pkt_mon.tx_pkt_state == PKT_MON_STOPPED && + dhdp->dbg->pkt_mon.rx_pkt_state == PKT_MON_STOPPED) { + DHD_ERROR(("%s: scheduling aml iovar..\n", __FUNCTION__)); + dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, NULL, + DHD_WQ_WORK_AML_IOVAR, dhd_do_aml_disable, DHD_WQ_WORK_PRIORITY_HIGH); + } +} + static int __dhd_dbg_free_tx_pkts(dhd_pub_t *dhdp, dhd_dbg_tx_info_t *tx_pkts, uint16 pkt_count) @@ -1533,6 +1755,8 @@ __dhd_dbg_free_tx_pkts(dhd_pub_t *dhdp, dhd_dbg_tx_info_t *tx_pkts, while ((count < pkt_count) && tx_pkts) { if (tx_pkts->info.pkt) { PKTFREE(dhdp->osh, tx_pkts->info.pkt, TRUE); + /* Set NULL pointer after freeing for preventing dangling pointer problem */ + tx_pkts->info.pkt = NULL; } tx_pkts++; count++; @@ -1551,6 +1775,8 @@ __dhd_dbg_free_rx_pkts(dhd_pub_t *dhdp, dhd_dbg_rx_info_t *rx_pkts, while ((count < pkt_count) && rx_pkts) { if (rx_pkts->info.pkt) { PKTFREE(dhdp->osh, rx_pkts->info.pkt, TRUE); + /* Set NULL pointer after freeing for preventing dangling pointer problem */ + rx_pkts->info.pkt = NULL; } rx_pkts++; count++; @@ -1734,6 +1960,13 @@ dhd_dbg_start_pkt_monitor(dhd_pub_t *dhdp) dhd_dbg_pkt_mon_state_t tx_status_state; dhd_dbg_pkt_mon_state_t rx_pkt_state; unsigned long flags; +#ifdef DBG_PKT_MON_ROAM + /* assoc mgmt logging for assoc/roam is allowed by default */ + uint32 enable = (1u << WL_AML_ROAM_ENABLE | 1u << WL_AML_ASSOC_ENABLE); +#else + /* assoc mgmt logging for assoc is allowed by default */ + uint32 enable = (1u << WL_AML_ASSOC_ENABLE); +#endif if (!dhdp || !dhdp->dbg) { DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, @@ -1741,6 +1974,10 @@ dhd_dbg_start_pkt_monitor(dhd_pub_t *dhdp) return -EINVAL; } + if (do_iovar_aml_enable(dhdp, enable) == BCME_OK) { + dhdp->aml_enable = TRUE; + } + DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; @@ -1792,7 +2029,7 @@ dhd_dbg_start_pkt_monitor(dhd_pub_t *dhdp) } int -dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid) +dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid, frame_type type, uint8 mgmt_acked) { dhd_dbg_tx_report_t *tx_report; dhd_dbg_tx_info_t *tx_pkts; @@ -1800,6 +2037,9 @@ dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid) uint32 pkt_hash, driver_ts; uint16 pkt_pos; unsigned long flags; +#if !defined(PCIE_FULL_DONGLE) + void *clone_pkt = NULL; +#endif if (!dhdp || !dhdp->dbg) { DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, @@ -1818,19 +2058,49 @@ dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid) pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid); driver_ts = __dhd_dbg_driver_ts_usec(); - tx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt); - tx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt); + if (type == FRAME_TYPE_80211_MGMT) { + tx_pkts[pkt_pos].info.pkt = pkt; + if (mgmt_acked) { + tx_pkts[pkt_pos].fate = TX_PKT_FATE_ACKED; + } else { + tx_pkts[pkt_pos].fate = TX_PKT_FATE_SENT; + } + tx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt); + } else { +#if !defined(PCIE_FULL_DONGLE) + clone_pkt = PKTDUP(dhdp->osh, pkt); + skb_pull((struct sk_buff*)clone_pkt, SDIO_HLEN); + tx_pkts[pkt_pos].info.pkt = clone_pkt; + tx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, clone_pkt) - SDIO_HLEN; +#else + tx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt); + tx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt); +#endif + tx_pkts[pkt_pos].fate = TX_PKT_FATE_DRV_QUEUED; + } + tx_pkts[pkt_pos].info.pkt_hash = pkt_hash; tx_pkts[pkt_pos].info.driver_ts = driver_ts; tx_pkts[pkt_pos].info.firmware_ts = 0U; - tx_pkts[pkt_pos].info.payload_type = FRAME_TYPE_ETHERNET_II; - tx_pkts[pkt_pos].fate = TX_PKT_FATE_DRV_QUEUED; + tx_pkts[pkt_pos].info.payload_type = type; tx_report->pkt_pos++; + /* TX mgmt packet is updated with the final fate reason, + * so status_pos should be also increased. + */ + if (type == FRAME_TYPE_80211_MGMT) { + tx_report->status_pos++; + } } else { + if (type == FRAME_TYPE_80211_MGMT) { + PKTFREE(dhdp->osh, pkt, TRUE); + } dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STOPPED; DHD_PKT_MON(("%s(): tx pkt logging stopped, reached " "max limit\n", __FUNCTION__)); + if (dhdp->aml_enable) { + dhd_schedule_aml_disable(dhdp); + } } } @@ -1919,7 +2189,7 @@ dhd_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid, } int -dhd_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt) +dhd_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt, frame_type type) { dhd_dbg_rx_report_t *rx_report; dhd_dbg_rx_info_t *rx_pkts; @@ -1944,19 +2214,29 @@ dhd_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt) rx_pkts = rx_report->rx_pkts; driver_ts = __dhd_dbg_driver_ts_usec(); - rx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt); + if (type == FRAME_TYPE_80211_MGMT) { + rx_pkts[pkt_pos].info.pkt = pkt; + } else { + rx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt); + } rx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt); rx_pkts[pkt_pos].info.pkt_hash = 0U; rx_pkts[pkt_pos].info.driver_ts = driver_ts; rx_pkts[pkt_pos].info.firmware_ts = 0U; - rx_pkts[pkt_pos].info.payload_type = FRAME_TYPE_ETHERNET_II; + rx_pkts[pkt_pos].info.payload_type = type; rx_pkts[pkt_pos].fate = RX_PKT_FATE_SUCCESS; rx_report->pkt_pos++; } else { + if (type == FRAME_TYPE_80211_MGMT) { + PKTFREE(dhdp->osh, pkt, TRUE); + } dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STOPPED; DHD_PKT_MON(("%s(): rx pkt logging stopped, reached " "max limit\n", __FUNCTION__)); + if (dhdp->aml_enable) { + dhd_schedule_aml_disable(dhdp); + } } } @@ -2012,18 +2292,33 @@ dhd_dbg_stop_pkt_monitor(dhd_pub_t *dhdp) } \ } while (0); +static wifi_tx_packet_fate +__dhd_dbg_convert_fate(wifi_tx_packet_fate fate) +{ + wifi_tx_packet_fate new_fate = fate; + + /* To prevent SIG-ABORT, packet_fate > TX_PKT_FATE_DRV_DROP_OTHER */ + if (fate > TX_PKT_FATE_DRV_DROP_OTHER) { + new_fate = TX_PKT_FATE_FW_DROP_OTHER; + } + + return new_fate; +} + int dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, uint16 req_count, uint16 *resp_count) { dhd_dbg_tx_report_t *tx_report; - dhd_dbg_tx_info_t *tx_pkt; + dhd_dbg_tx_info_t *tx_pkt, *ori_tx_pkt; wifi_tx_report_t *ptr; compat_wifi_tx_report_t *cptr; dhd_dbg_pkt_mon_state_t tx_pkt_state; dhd_dbg_pkt_mon_state_t tx_status_state; uint16 pkt_count, count; unsigned long flags; + dhd_dbg_tx_info_t *tmp_tx_pkt = NULL; + uint32 alloc_len, i, ret; BCM_REFERENCE(ptr); BCM_REFERENCE(cptr); @@ -2037,7 +2332,8 @@ dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; - if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state)) { + if (!PKT_MON_ATTACHED(tx_pkt_state) || + !PKT_MON_ATTACHED(tx_status_state)) { DHD_PKT_MON(("%s(): packet monitor is not yet enabled, " "tx_pkt_state=%d, tx_status_state=%d\n", __FUNCTION__, tx_pkt_state, tx_status_state)); @@ -2047,22 +2343,51 @@ dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, count = 0; tx_report = dhdp->dbg->pkt_mon.tx_report; - tx_pkt = tx_report->tx_pkts; + ori_tx_pkt = tx_report->tx_pkts; pkt_count = MIN(req_count, tx_report->status_pos); + alloc_len = (sizeof(*tmp_tx_pkt) * pkt_count); + tmp_tx_pkt = (dhd_dbg_tx_info_t *)MALLOCZ(dhdp->osh, alloc_len); + if (unlikely(!tmp_tx_pkt)) { + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + DHD_ERROR(("%s: failed to allocate tmp_tx_pkt", __FUNCTION__)); + return -ENOMEM; + } + if ((ret = memcpy_s(tmp_tx_pkt, alloc_len, ori_tx_pkt, alloc_len))) { + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + DHD_ERROR(("%s: failed to copy tmp_tx_pkt ret:%d", __FUNCTION__, ret)); + return -EINVAL; + } + for (i = 0; i < pkt_count; i++) { + tmp_tx_pkt[i].info.pkt = skb_copy((struct sk_buff*)ori_tx_pkt[i].info.pkt, + GFP_ATOMIC); + if (!tmp_tx_pkt[i].info.pkt) { + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + DHD_ERROR(("%s: failed to copy skb", __FUNCTION__)); + return -ENOMEM; + } + } + tx_pkt = tmp_tx_pkt; + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + #ifdef CONFIG_COMPAT #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) if (in_compat_syscall()) #else if (is_compat_task()) -#endif +#endif /* LINUX_VER >= 4.6 */ { cptr = (compat_wifi_tx_report_t *)user_buf; while ((count < pkt_count) && tx_pkt && cptr) { compat_wifi_tx_report_t *comp_ptr = compat_ptr((uintptr_t) cptr); compat_dhd_dbg_pkt_info_t compat_tx_pkt; __dhd_dbg_dump_tx_pkt_info(dhdp, tx_pkt, count); - __COPY_TO_USER(&comp_ptr->fate, &tx_pkt->fate, sizeof(tx_pkt->fate)); + /* fate convert asscording to wifi_logger.h */ + { + wifi_tx_packet_fate new_fate = tx_pkt->fate; + new_fate = __dhd_dbg_convert_fate(new_fate); + __COPY_TO_USER(&comp_ptr->fate, &new_fate, sizeof(new_fate)); + } compat_tx_pkt.payload_type = tx_pkt->info.payload_type; compat_tx_pkt.pkt_len = tx_pkt->info.pkt_len; @@ -2085,7 +2410,12 @@ dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, ptr = (wifi_tx_report_t *)user_buf; while ((count < pkt_count) && tx_pkt && ptr) { __dhd_dbg_dump_tx_pkt_info(dhdp, tx_pkt, count); - __COPY_TO_USER(&ptr->fate, &tx_pkt->fate, sizeof(tx_pkt->fate)); + /* fate convert asscording to wifi_logger.h */ + { + wifi_tx_packet_fate new_fate = tx_pkt->fate; + new_fate = __dhd_dbg_convert_fate(new_fate); + __COPY_TO_USER(&ptr->fate, &new_fate, sizeof(new_fate)); + } __COPY_TO_USER(&ptr->frame_inf.payload_type, &tx_pkt->info.payload_type, OFFSETOF(dhd_dbg_pkt_info_t, pkt_hash)); @@ -2099,13 +2429,17 @@ dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, } *resp_count = pkt_count; - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); if (!pkt_count) { DHD_ERROR(("%s(): no tx_status in tx completion messages, " "make sure that 'd11status' is enabled in firmware, " "status_pos=%u\n", __FUNCTION__, pkt_count)); } + for (i = 0; i < pkt_count; i++) { + PKTFREE(dhdp->osh, tmp_tx_pkt[i].info.pkt, TRUE); + } + MFREE(dhdp->osh, tmp_tx_pkt, alloc_len); + return BCME_OK; } @@ -2114,12 +2448,14 @@ dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf, uint16 req_count, uint16 *resp_count) { dhd_dbg_rx_report_t *rx_report; - dhd_dbg_rx_info_t *rx_pkt; + dhd_dbg_rx_info_t *rx_pkt, *ori_rx_pkt; wifi_rx_report_t *ptr; compat_wifi_rx_report_t *cptr; dhd_dbg_pkt_mon_state_t rx_pkt_state; uint16 pkt_count, count; unsigned long flags; + dhd_dbg_rx_info_t *tmp_rx_pkt = NULL; + uint32 alloc_len, i, ret = BCME_OK; BCM_REFERENCE(ptr); BCM_REFERENCE(cptr); @@ -2132,7 +2468,7 @@ dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf, DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; - if (PKT_MON_DETACHED(rx_pkt_state)) { + if (!PKT_MON_ATTACHED(rx_pkt_state)) { DHD_PKT_MON(("%s(): packet fetch is not allowed , " "rx_pkt_state=%d\n", __FUNCTION__, rx_pkt_state)); DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); @@ -2141,15 +2477,39 @@ dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf, count = 0; rx_report = dhdp->dbg->pkt_mon.rx_report; - rx_pkt = rx_report->rx_pkts; + ori_rx_pkt = rx_report->rx_pkts; pkt_count = MIN(req_count, rx_report->pkt_pos); + alloc_len = (sizeof(*tmp_rx_pkt) * pkt_count); + tmp_rx_pkt = (dhd_dbg_rx_info_t *)MALLOCZ(dhdp->osh, alloc_len); + if (unlikely(!tmp_rx_pkt)) { + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + DHD_ERROR(("%s: failed to allocate tmp_rx_pkt", __FUNCTION__)); + return -ENOMEM; + } + if ((ret = memcpy_s(tmp_rx_pkt, alloc_len, ori_rx_pkt, alloc_len))) { + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + DHD_ERROR(("%s: failed to copy tmp_rx_pkt ret:%d", __FUNCTION__, ret)); + goto exit; + } + for (i = 0; i < pkt_count; i++) { + tmp_rx_pkt[i].info.pkt = skb_copy((struct sk_buff*)ori_rx_pkt[i].info.pkt, + GFP_ATOMIC); + if (!tmp_rx_pkt[i].info.pkt) { + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + DHD_ERROR(("%s: failed to copy skb", __FUNCTION__)); + goto exit; + } + } + rx_pkt = tmp_rx_pkt; + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + #ifdef CONFIG_COMPAT #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) if (in_compat_syscall()) #else if (is_compat_task()) -#endif +#endif /* LINUX_VER >= 4.6 */ { cptr = (compat_wifi_rx_report_t *)user_buf; while ((count < pkt_count) && rx_pkt && cptr) { @@ -2179,7 +2539,6 @@ dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf, ptr = (wifi_rx_report_t *)user_buf; while ((count < pkt_count) && rx_pkt && ptr) { __dhd_dbg_dump_rx_pkt_info(dhdp, rx_pkt, count); - __COPY_TO_USER(&ptr->fate, &rx_pkt->fate, sizeof(rx_pkt->fate)); __COPY_TO_USER(&ptr->frame_inf.payload_type, &rx_pkt->info.payload_type, @@ -2194,9 +2553,14 @@ dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf, } *resp_count = pkt_count; - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - return BCME_OK; +exit: + for (i = 0; i < pkt_count; i++) { + PKTFREE(dhdp->osh, tmp_rx_pkt[i].info.pkt, TRUE); + } + MFREE(dhdp->osh, tmp_rx_pkt, alloc_len); + + return ret; } int @@ -2380,37 +2744,54 @@ void pr_roam_btm_rep_v2(prcd_event_log_hdr_t *plog_hdr); void pr_roam_bcn_req_v3(prcd_event_log_hdr_t *plog_hdr); void pr_roam_bcn_rep_v3(prcd_event_log_hdr_t *plog_hdr); void pr_roam_btm_rep_v3(prcd_event_log_hdr_t *plog_hdr); +void pr_roam_6g_novlp_rep_v3(prcd_event_log_hdr_t *plog_hdr); +void pr_roam_wtc_btm_rep_v3(prcd_event_log_hdr_t *plog_hdr); +void pr_roam_btm_query_v3(prcd_event_log_hdr_t *plog_hdr); + +void pr_roam_btm_resp_v4(prcd_event_log_hdr_t *plog_hdr); +void pr_roam_btm_req_v4(prcd_event_log_hdr_t *plog_hdr); + +/* Will find an entity which has highest version of that ROAM_LOG id. + * ALL structure should support backward compatibility. + * { ROAM_LOG_VER, ROAM_LOG_ID, print ROAM_LOG function() }, + */ static const pr_roam_tbl_t roam_log_print_tbl[] = { - {ROAM_LOG_VER_1, ROAM_LOG_SCANSTART, pr_roam_scan_start_v1}, - {ROAM_LOG_VER_1, ROAM_LOG_SCAN_CMPLT, pr_roam_scan_cmpl_v1}, - {ROAM_LOG_VER_1, ROAM_LOG_ROAM_CMPLT, pr_roam_cmpl_v1}, - {ROAM_LOG_VER_1, ROAM_LOG_NBR_REQ, pr_roam_nbr_req_v1}, - {ROAM_LOG_VER_1, ROAM_LOG_NBR_REP, pr_roam_nbr_rep_v1}, - {ROAM_LOG_VER_1, ROAM_LOG_BCN_REQ, pr_roam_bcn_req_v1}, - {ROAM_LOG_VER_1, ROAM_LOG_BCN_REP, pr_roam_bcn_rep_v1}, - + /* ROAM Scan Start */ {ROAM_LOG_VER_2, ROAM_LOG_SCANSTART, pr_roam_scan_start_v2}, + {ROAM_LOG_VER_1, ROAM_LOG_SCANSTART, pr_roam_scan_start_v1}, + /* ROAM Scan Completed */ {ROAM_LOG_VER_2, ROAM_LOG_SCAN_CMPLT, pr_roam_scan_cmpl_v2}, - {ROAM_LOG_VER_2, ROAM_LOG_ROAM_CMPLT, pr_roam_cmpl_v1}, - {ROAM_LOG_VER_2, ROAM_LOG_NBR_REQ, pr_roam_nbr_req_v1}, + {ROAM_LOG_VER_1, ROAM_LOG_SCAN_CMPLT, pr_roam_scan_cmpl_v1}, + /* ROAM Completed */ + {ROAM_LOG_VER_1, ROAM_LOG_ROAM_CMPLT, pr_roam_cmpl_v1}, + /* Neighbor Request */ + {ROAM_LOG_VER_1, ROAM_LOG_NBR_REQ, pr_roam_nbr_req_v1}, + /* Neighbor Report */ {ROAM_LOG_VER_2, ROAM_LOG_NBR_REP, pr_roam_nbr_rep_v2}, - {ROAM_LOG_VER_2, ROAM_LOG_BCN_REQ, pr_roam_bcn_req_v1}, - {ROAM_LOG_VER_2, ROAM_LOG_BCN_REP, pr_roam_bcn_rep_v2}, - {ROAM_LOG_VER_2, ROAM_LOG_BTM_REP, pr_roam_btm_rep_v2}, - - {ROAM_LOG_VER_3, ROAM_LOG_SCANSTART, pr_roam_scan_start_v2}, - {ROAM_LOG_VER_3, ROAM_LOG_SCAN_CMPLT, pr_roam_scan_cmpl_v2}, - {ROAM_LOG_VER_3, ROAM_LOG_ROAM_CMPLT, pr_roam_cmpl_v1}, - {ROAM_LOG_VER_3, ROAM_LOG_NBR_REQ, pr_roam_nbr_req_v1}, - {ROAM_LOG_VER_3, ROAM_LOG_NBR_REP, pr_roam_nbr_rep_v2}, + {ROAM_LOG_VER_1, ROAM_LOG_NBR_REP, pr_roam_nbr_rep_v1}, + /* Beacon Request */ {ROAM_LOG_VER_3, ROAM_LOG_BCN_REQ, pr_roam_bcn_req_v3}, + {ROAM_LOG_VER_1, ROAM_LOG_BCN_REQ, pr_roam_bcn_req_v1}, + /* Beacon Report */ {ROAM_LOG_VER_3, ROAM_LOG_BCN_REP, pr_roam_bcn_rep_v3}, + {ROAM_LOG_VER_2, ROAM_LOG_BCN_REP, pr_roam_bcn_rep_v2}, + {ROAM_LOG_VER_1, ROAM_LOG_BCN_REP, pr_roam_bcn_rep_v1}, + /* BTM Response */ + {ROAM_LOG_VER_4, ROAM_LOG_BTM_REP, pr_roam_btm_resp_v4}, {ROAM_LOG_VER_3, ROAM_LOG_BTM_REP, pr_roam_btm_rep_v3}, + {ROAM_LOG_VER_2, ROAM_LOG_BTM_REP, pr_roam_btm_rep_v2}, + /* SCAN 6G no VLP channels */ + {ROAM_LOG_VER_3, ROAM_LOG_6G_NOVLP_REP, pr_roam_6g_novlp_rep_v3}, + /* BTM WTC Request/Response */ + {ROAM_LOG_VER_3, ROAM_LOG_WTC_BTM_REP, pr_roam_wtc_btm_rep_v3}, + /* BTM Query */ + {ROAM_LOG_VER_3, ROAM_LOG_BTM_QUERY, pr_roam_btm_query_v3}, + /* BTM Request */ + {ROAM_LOG_VER_4, ROAM_LOG_BTM_REQ, pr_roam_btm_req_v4}, {0, PRSV_PERIODIC_ID_MAX, NULL} - }; void pr_roam_scan_start_v1(prcd_event_log_hdr_t *plog_hdr) @@ -2441,7 +2822,7 @@ void pr_roam_scan_cmpl_v1(prcd_event_log_hdr_t *plog_hdr) int i; DHD_ERROR_ROAM(("ROAM_LOG_SCAN_CMPL: time:%d version:%d" - "is_full:%d scan_count:%d score_delta:%d", + "is_full:%d scan_count:%d score_delta:%d\n", plog_hdr->armcycle, log->hdr.version, log->full_scan, log->scan_count, log->score_delta)); DHD_ERROR_ROAM((" ROAM_LOG_CUR_AP: " MACDBG "rssi:%d score:%d channel:%s\n", @@ -2522,12 +2903,6 @@ void pr_roam_scan_start_v2(prcd_event_log_hdr_t *plog_hdr) log->reason == WLC_E_REASON_DISASSOC) { DHD_ERROR_ROAM((" ROAM_LOG_PRT_ROAM: RCVD reason:%d\n", log->prt_roam.rcvd_reason)); - } else if (log->reason == WLC_E_REASON_BSSTRANS_REQ) { - DHD_ERROR_ROAM((" ROAM_LOG_BSS_REQ: mode:%d candidate:%d token:%d " - "duration disassoc:%d valid:%d term:%d\n", - log->bss_trans.req_mode, log->bss_trans.nbrlist_size, - log->bss_trans.token, log->bss_trans.disassoc_dur, - log->bss_trans.validity_dur, log->bss_trans.bss_term_dur)); } else if (log->reason == WLC_E_REASON_LOW_RSSI) { DHD_ERROR_ROAM((" ROAM_LOG_LOW_RSSI: threshold:%d\n", log->low_rssi.rssi_threshold)); @@ -2541,7 +2916,7 @@ void pr_roam_scan_cmpl_v2(prcd_event_log_hdr_t *plog_hdr) char chanspec_buf[CHANSPEC_STR_LEN]; DHD_ERROR_ROAM(("ROAM_LOG_SCAN_CMPL: time:%d version:%d" - "scan_count:%d score_delta:%d", + "scan_count:%d score_delta:%d\n", plog_hdr->armcycle, log->hdr.version, log->scan_count, log->score_delta)); DHD_ERROR_ROAM((" ROAM_LOG_CUR_AP: " MACDBG "rssi:%d score:%d channel:%s\n", @@ -2554,7 +2929,8 @@ void pr_roam_scan_cmpl_v2(prcd_event_log_hdr_t *plog_hdr) "rssi:%d score:%d cu :%d channel:%s TPUT:%dkbps\n", i, MAC2STRDBG((uint8 *)&log->scan_list[i].addr), log->scan_list[i].rssi, log->scan_list[i].score, - log->scan_list[i].cu * 100 / WL_MAX_CHANNEL_USAGE, + log->scan_list[i].cu_avail ? + (log->scan_list[i].cu * 100 / WL_MAX_CHANNEL_USAGE) : WL_CU_NOT_AVAIL, wf_chspec_ntoa_ex(log->scan_list[i].chanspec, chanspec_buf), log->scan_list[i].estm_tput != ROAM_LOG_INVALID_TPUT? @@ -2659,6 +3035,93 @@ void pr_roam_btm_rep_v3(prcd_event_log_hdr_t *plog_hdr) MAC2STRDBG((uint8 *)&log->target_addr))); } +void +pr_roam_btm_query_v3(prcd_event_log_hdr_t *plog_hdr) +{ + roam_log_btm_query_v3_t *log = (roam_log_btm_query_v3_t *)plog_hdr->log_ptr; + DHD_ERROR_ROAM(("ROAM_LOG_BTM_QUERY: time:%d version:%d token:%d reason:%d\n", + plog_hdr->armcycle, log->hdr.version, log->token, log->reason)); +} + +void +pr_roam_6g_novlp_rep_v3(prcd_event_log_hdr_t *plog_hdr) +{ + roam_log_6g_novlp_v3_t *log = (roam_log_6g_novlp_v3_t *)plog_hdr->log_ptr; + char chanspec_buf[CHANSPEC_STR_LEN]; + + DHD_ERROR_ROAM(("ROAM_LOG_6G_NoVPL_Filtered: time:%d version:%d " + "CH:%s(0x%04x) BSSID:" MACDBG "\n", + plog_hdr->armcycle, log->hdr.version, + wf_chspec_ntoa_ex(log->chanspec, chanspec_buf), + log->chanspec, MAC2STRDBG((uint8 *)&log->bssid))); +} + +void +pr_roam_wtc_btm_rep_v3(prcd_event_log_hdr_t *plog_hdr) +{ + roam_log_wtc_btmrep_v3_t *log = (roam_log_wtc_btmrep_v3_t *)plog_hdr->log_ptr; + + DHD_ERROR_ROAM(("ROAM_LOG_WTC: time:%d version:%d WTC BTM %s\n", + plog_hdr->armcycle, log->hdr.version, + (log->wtc_type == WTC_BTMREQ) ? "Request" : "Response")); + + if (log->wtc_type == WTC_BTMREQ) { + DHD_ERROR_ROAM(("ROAM_LOG_WTC_CFG: mode:%d Scan mode:%d RSSI TH:%d " + "Candidate RSSI TH:%d %d %d\n", + log->wtcreq.mode, log->wtcreq.scantype, + log->wtcreq.rssithresh[WTC_BAND_2G], + log->wtcreq.ap_rssithresh[WTC_BAND_2G], + log->wtcreq.ap_rssithresh[WTC_BAND_5G], + log->wtcreq.ap_rssithresh[WTC_BAND_6G])); + if (log->wtcreq.status) { + DHD_ERROR_ROAM((" Recvd invalid WTC Req len:%d ver:%d\n", + log->ie_length, log->wtc_ver)); + } else { + DHD_ERROR_ROAM(("ROAM_LOG_WTC_REQ len:%d WTC ver:%d " + "Reason code:%d Subcode:%d duration:%d\n", + log->ie_length, log->wtc_ver, + log->wtcreq.rsn_code, log->wtcreq.subcode, + log->wtcreq.duration)); + } + } else if (log->wtc_type == WTC_BTMRESP) { + DHD_ERROR_ROAM(("ROAM_LOG_WTC_RESP len:%d WTC ver:%d " + "Reason code:%d Resp status:%d\n", + log->ie_length, log->wtc_ver, + log->wtcresp.rsn_code, log->wtcresp.status)); + } +} +/* ROAM logging BTM Request */ +void +pr_roam_btm_req_v4(prcd_event_log_hdr_t *plog_hdr) +{ + roam_log_btm_req_v4_t *log = (roam_log_btm_req_v4_t *)plog_hdr->log_ptr; + int i; + DHD_ERROR_ROAM(("ROAM_LOG_BTM_REQ: time:%d version:%d req_mode:%d " + "token:%d candi:%d duration disassoc:%d valid:%d term:%d\n", + plog_hdr->armcycle, log->hdr.version, + log->req_mode, log->token, log->nbrlist_size, + log->disassoc_dur, log->validity_dur, log->bss_term_dur)); + if (log->nbrlist_size) { + int max_idx = MIN(log->nbrlist_size, ROAM_NBR_RPT_LIST_SIZE); + for (i = 0; i < max_idx; i++) { + DHD_ERROR_ROAM((" ROAM_LOG_NBR: [%d]" MACDBG " pref:0x%x\n", + i, MAC2STRDBG((uint8 *)&log->nbr_list[i].bssid), + log->nbr_list[i].preference)); + } + } +} +/* ROAM logging BTM Response */ +void +pr_roam_btm_resp_v4(prcd_event_log_hdr_t *plog_hdr) +{ + roam_log_btm_resp_v4_t *log = (roam_log_btm_resp_v4_t *)plog_hdr->log_ptr; + DHD_ERROR_ROAM(("ROAM_LOG_BTM_REP: time:%d version:%d req_mode:%d " + "status:%d token:%d term_delay:%d ret:%d target:" MACDBG "\n", + plog_hdr->armcycle, log->hdr.version, + log->req_mode, log->status, log->token, log->term_delay, log->result, + MAC2STRDBG((uint8 *)&log->target_addr))); +} + void print_roam_enhanced_log(prcd_event_log_hdr_t *plog_hdr) { @@ -2670,8 +3133,12 @@ print_roam_enhanced_log(prcd_event_log_hdr_t *plog_hdr) char pr_buf[EL_LOG_STR_LEN] = { 0 }; const pr_roam_tbl_t *cur_elem = &roam_log_print_tbl[0]; +#ifdef WL_CFGVENDOR_CUST_ADVLOG + wl_cfgvendor_custom_advlog_roam_log(plog_hdr->log_ptr, plog_hdr->armcycle); +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ + while (cur_elem && cur_elem->pr_func) { - if (hdr->version == cur_elem->version && + if (hdr->version >= cur_elem->version && hdr->id == cur_elem->id) { cur_elem->pr_func(plog_hdr); return; @@ -2702,68 +3169,158 @@ dhd_dbg_attach(dhd_pub_t *dhdp, dbg_pullreq_t os_pullreq, dbg_urgent_noti_t os_urgent_notifier, void *os_priv) { dhd_dbg_t *dbg = NULL; +#if defined(DHD_DEBUGABILITY_LOG_DUMP_RING) || defined(DHD_DEBUGABILITY_EVENT_RING) || \ + defined(DHD_PKT_LOGGING_DBGRING) dhd_dbg_ring_t *ring = NULL; - int ret = BCME_ERROR, ring_id = 0; + int ring_id = 0; void *buf = NULL; + int ret = BCME_ERROR; +#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING || BTLOG || + * DHD_DEBUGABILITY_EVENT_RING || DHD_PKT_LOGGING_DBGRING || + * (DEBUGABILITY && CUSTOMER_HW6) + */ #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING struct dhd_dbg_ring_buf *ring_buf; #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ +#ifdef DHD_PKT_LOGGING_DBGRING + dhd_pktlog_ring_t *pktlog_ring = NULL; +#endif /* DHD_PKT_LOGGING_DBGRING */ - dbg = MALLOCZ(dhdp->osh, sizeof(dhd_dbg_t)); - if (!dbg) + dbg = VMALLOCZ(dhdp->osh, sizeof(dhd_dbg_t)); + if (!dbg) { + DHD_ERROR(("%s:%d: VMALLOC failed for dbg, size %d\n", + __FUNCTION__, __LINE__, (uint32)sizeof(dhd_dbg_t))); return BCME_NOMEM; + } -#ifdef CONFIG_DHD_USE_STATIC_BUF - buf = DHD_OS_PREALLOC(dhdp, DHD_PREALLOC_FW_VERBOSE_RING, FW_VERBOSE_RING_SIZE); -#else - buf = MALLOCZ(dhdp->osh, FW_VERBOSE_RING_SIZE); -#endif - if (!buf) - goto error; - ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[FW_VERBOSE_RING_ID], FW_VERBOSE_RING_ID, - (uint8 *)FW_VERBOSE_RING_NAME, FW_VERBOSE_RING_SIZE, buf, FALSE); - if (ret) - goto error; - +#ifdef DHD_DEBUGABILITY_EVENT_RING #ifdef CONFIG_DHD_USE_STATIC_BUF buf = DHD_OS_PREALLOC(dhdp, DHD_PREALLOC_DHD_EVENT_RING, DHD_EVENT_RING_SIZE); #else - buf = MALLOCZ(dhdp->osh, DHD_EVENT_RING_SIZE); + buf = VMALLOCZ(dhdp->osh, DHD_EVENT_RING_SIZE); #endif - if (!buf) + if (!buf) { + DHD_ERROR(("%s:%d: VMALLOC failed for event_ring, size %d\n", + __FUNCTION__, __LINE__, DHD_EVENT_RING_SIZE)); + ret = BCME_NOMEM; goto error; - ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[DHD_EVENT_RING_ID], DHD_EVENT_RING_ID, - (uint8 *)DHD_EVENT_RING_NAME, DHD_EVENT_RING_SIZE, buf, FALSE); - if (ret) + } + ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[DHD_EVENT_RING_ID], + DHD_EVENT_RING_ID, (uint8 *)DHD_EVENT_RING_NAME, + DHD_EVENT_RING_SIZE, buf, FALSE); + if (ret) { goto error; + } +#endif /* DHD_DEBUGABILITY_EVENT_RING */ + +#if defined(DHD_DEBUGABILITY_LOG_DUMP_RING) +#ifdef CONFIG_DHD_USE_STATIC_BUF + buf = DHD_OS_PREALLOC(dhdp, DHD_PREALLOC_FW_VERBOSE_RING, FW_VERBOSE_RING_SIZE); +#else + buf = VMALLOCZ(dhdp->osh, FW_VERBOSE_RING_SIZE); +#endif + if (!buf) { + DHD_ERROR(("%s:%d: VMALLOC failed for fw_verbose_ring, size %d\n", + __FUNCTION__, __LINE__, FW_VERBOSE_RING_SIZE)); + ret = BCME_NOMEM; + goto error; + } + ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[FW_VERBOSE_RING_ID], + FW_VERBOSE_RING_ID, (uint8 *)FW_VERBOSE_RING_NAME, + FW_VERBOSE_RING_SIZE, buf, FALSE); + if (ret) { + goto error; + } +#endif #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING - buf = MALLOCZ(dhdp->osh, DRIVER_LOG_RING_SIZE); - if (!buf) + buf = VMALLOCZ(dhdp->osh, DRIVER_LOG_RING_SIZE); + if (!buf) { + DHD_ERROR(("%s:%d: VMALLOC failed for driver_log_ring, size %d\n", + __FUNCTION__, __LINE__, DRIVER_LOG_RING_SIZE)); + ret = BCME_NOMEM; goto error; - ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[DRIVER_LOG_RING_ID], DRIVER_LOG_RING_ID, - (uint8 *)DRIVER_LOG_RING_NAME, DRIVER_LOG_RING_SIZE, buf, FALSE); - if (ret) + } + ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[DRIVER_LOG_RING_ID], + DRIVER_LOG_RING_ID, (uint8 *)DRIVER_LOG_RING_NAME, + DRIVER_LOG_RING_SIZE, buf, FALSE); + if (ret) { goto error; + } - buf = MALLOCZ(dhdp->osh, ROAM_STATS_RING_SIZE); - if (!buf) + buf = VMALLOCZ(dhdp->osh, ROAM_STATS_RING_SIZE); + if (!buf) { + DHD_ERROR(("%s:%d: VMALLOC failed for roam_stats_ring, size %d\n", + __FUNCTION__, __LINE__, ROAM_STATS_RING_SIZE)); + ret = BCME_NOMEM; goto error; - ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[ROAM_STATS_RING_ID], ROAM_STATS_RING_ID, - (uint8 *)ROAM_STATS_RING_NAME, ROAM_STATS_RING_SIZE, buf, FALSE); - if (ret) + } + ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[ROAM_STATS_RING_ID], + ROAM_STATS_RING_ID, (uint8 *)ROAM_STATS_RING_NAME, + ROAM_STATS_RING_SIZE, buf, FALSE); + if (ret) { goto error; + } #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ -#ifdef BTLOG - buf = MALLOCZ(dhdp->osh, BT_LOG_RING_SIZE); - if (!buf) - goto error; - ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[BT_LOG_RING_ID], BT_LOG_RING_ID, - BT_LOG_RING_NAME, BT_LOG_RING_SIZE, buf, FALSE); - if (ret) - goto error; -#endif /* BTLOG */ +#if defined(DHD_DEBUGABILITY_DEBUG_DUMP) || defined(DHD_HAL_RING_DUMP) + /* + * delayed memory allocation. memory will be allocated when debug_dump is invoked + * To prepare the ringbuffer in legacy HAL, we should initialize ring at this time + */ + ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[DEBUG_DUMP_RING1_ID], + DEBUG_DUMP_RING1_ID, (uint8 *)DEBUG_DUMP_RING1_NAME, + DEBUG_DUMP_RING1_SIZE, NULL, FALSE); + if (ret) { + DHD_ERROR(("%s: Failed to init debug ring1\n", __func__)); + goto error; + } + + ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[DEBUG_DUMP_RING2_ID], + DEBUG_DUMP_RING2_ID, (uint8 *)DEBUG_DUMP_RING2_NAME, + DEBUG_DUMP_RING2_SIZE, NULL, FALSE); + if (ret) { + DHD_ERROR(("%s: Failed to init debug ring2\n", __func__)); + goto error; + } +#endif /* defined(DHD_DEBUGABILITY_DEBUG_DUMP) || defined(DHD_HAL_RING_DUMP) */ + +#if defined(DHD_HAL_RING_DUMP_MEMDUMP) + ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[MEM_DUMP_RING_ID], MEM_DUMP_RING_ID, + (uint8 *)MEM_DUMP_RING_NAME, MEM_DUMP_RING_SIZE, NULL, FALSE); + if (ret) { + DHD_ERROR(("%s: Failed to init mem dump ring\n", __func__)); + goto error; + } +#endif /* DHD_HAL_RING_DUMP_MEMDUMP */ + +#ifdef DHD_PKT_LOGGING_DBGRING + if (dhdp && dhdp->pktlog && dhdp->pktlog->pktlog_ring) { + pktlog_ring = dhdp->pktlog->pktlog_ring; + } + + if (!pktlog_ring) { + DHD_ERROR(("%s: pktlog_ring is NULL. return.\n", __FUNCTION__)); + ret = BCME_NOMEM; + goto error; + } + + buf = pktlog_ring->ring_info_mem; + if (!buf) { + DHD_ERROR(("%s: ring_info_mem is NULL. return.\n", __FUNCTION__)); + ret = BCME_NOMEM; + goto error; + } + + ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[PACKET_LOG_RING_ID], + PACKET_LOG_RING_ID, (uint8 *)DHD_PACKET_LOG_RING_NAME, + DHD_PACKET_LOG_RING_SIZE, buf, FALSE); + if (ret) { + goto error; + } + + pktlog_ring->dbg_ring = &dbg->dbg_rings[PACKET_LOG_RING_ID]; +#endif /* DHD_PKT_LOGGING_DBGRING */ dbg->private = os_priv; dbg->pullreq = os_pullreq; dbg->urgent_notifier = os_urgent_notifier; @@ -2772,29 +3329,42 @@ dhd_dbg_attach(dhd_pub_t *dhdp, dbg_pullreq_t os_pullreq, ring_buf = &g_ring_buf; ring_buf->dhd_pub = dhdp; #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ + return BCME_OK; +#if defined(DHD_DEBUGABILITY_LOG_DUMP_RING) || defined(DHD_DEBUGABILITY_EVENT_RING) || \ + defined(DHD_PKT_LOGGING_DBGRING) error: for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) { if (VALID_RING(dbg->dbg_rings[ring_id].id)) { ring = &dbg->dbg_rings[ring_id]; dhd_dbg_ring_deinit(dhdp, ring); if (ring->ring_buf) { +#ifdef DHD_PKT_LOGGING_DBGRING + if (ring_id != PACKET_LOG_RING_ID) +#endif /* DHD_PKT_LOGGING_DBGRING */ + { #ifndef CONFIG_DHD_USE_STATIC_BUF - MFREE(dhdp->osh, ring->ring_buf, ring->ring_size); + VMFREE(dhdp->osh, ring->ring_buf, ring->ring_size); #endif + } ring->ring_buf = NULL; } ring->ring_size = 0; } } - MFREE(dhdp->osh, dbg, sizeof(dhd_dbg_t)); + + VMFREE(dhdp->osh, dbg, sizeof(dhd_dbg_t)); #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING ring_buf = &g_ring_buf; ring_buf->dhd_pub = NULL; #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ return ret; +#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING || BTLOG || + * DHD_DEBUGABILITY_EVENT_RING || DHD_PKT_LOGGING_DBGRING || + * (DEBUGABILITY && CUSTOMER_HW6) + */ } /* @@ -2803,34 +3373,49 @@ error: void dhd_dbg_detach(dhd_pub_t *dhdp) { - int ring_id; dhd_dbg_t *dbg; +#if defined(DHD_DEBUGABILITY_LOG_DUMP_RING) || defined(DHD_DEBUGABILITY_EVENT_RING) || \ + defined(DHD_PKT_LOGGING_DBGRING) + int ring_id; dhd_dbg_ring_t *ring = NULL; -#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING - struct dhd_dbg_ring_buf *ring_buf; -#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ - - if (!dhdp->dbg) - return; +#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING || BTLOG || + * DHD_DEBUGABILITY_EVENT_RING || DHD_PKT_LOGGING_DBGRING || + * (DEBUGABILITY && CUSTOMER_HW6) + */ dbg = dhdp->dbg; + if (!dbg) { + return; + } + +#if defined(DHD_DEBUGABILITY_LOG_DUMP_RING) || defined(DHD_DEBUGABILITY_EVENT_RING) || \ + defined(DHD_PKT_LOGGING_DBGRING) for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) { if (VALID_RING(dbg->dbg_rings[ring_id].id)) { ring = &dbg->dbg_rings[ring_id]; dhd_dbg_ring_deinit(dhdp, ring); if (ring->ring_buf) { +#ifdef DHD_PKT_LOGGING_DBGRING + if (ring_id != PACKET_LOG_RING_ID) +#endif /* DHD_PKT_LOGGING_DBGRING */ + { #ifndef CONFIG_DHD_USE_STATIC_BUF - MFREE(dhdp->osh, ring->ring_buf, ring->ring_size); + VMFREE(dhdp->osh, ring->ring_buf, ring->ring_size); #endif + } ring->ring_buf = NULL; } ring->ring_size = 0; } } - MFREE(dhdp->osh, dhdp->dbg, sizeof(dhd_dbg_t)); + + VMFREE(dhdp->osh, dbg, sizeof(dhd_dbg_t)); +#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING || BTLOG || + * DHD_DEBUGABILITY_EVENT_RING || DHD_PKT_LOGGING_DBGRING || + * (DEBUGABILITY && CUSTOMER_HW6) + */ #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING - ring_buf = &g_ring_buf; - ring_buf->dhd_pub = NULL; + g_ring_buf.dhd_pub = NULL; #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ } @@ -2851,3 +3436,231 @@ dhd_dbg_set_fwverbose(dhd_pub_t *dhdp, uint32 new_val) dhdp->dbg->dbg_rings[FW_VERBOSE_RING_ID].log_level = new_val; } } + +#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING +void +dhd_dbg_ring_write(int type, char *binary_data, + int binary_len, const char *fmt, ...) +{ + int len = 0; + va_list args; + struct dhd_dbg_ring_buf *ring_buf = NULL; + char tmp_buf[DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE] = {0, }; + + ring_buf = &g_ring_buf; + + va_start(args, fmt); + len = vsnprintf(tmp_buf, DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE, fmt, args); + /* Non ANSI C99 compliant returns -1, + * ANSI compliant return len >= DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE + */ + va_end(args); + if (len < 0) { + return; + } + + if (len >= DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE) { + len = DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE - 1; + tmp_buf[len] = '\0'; + } + + if (ring_buf->dhd_pub) { + dhd_pub_t *dhdp = (dhd_pub_t *)ring_buf->dhd_pub; + if (type == DRIVER_LOG_RING_ID || type == FW_VERBOSE_RING_ID || + type == ROAM_STATS_RING_ID) { + if (DBG_RING_ACTIVE(dhdp, type)) { + dhd_os_push_push_ring_data(dhdp, type, + tmp_buf, strlen(tmp_buf)); + return; + } + } + } + return; +} + +#ifdef DHD_DEBUGABILITY_DEBUG_DUMP +void dhd_debug_dump_get_section_len(dhd_pub_t *dhdp, uint32 sec_len[]) +{ + sec_len[LOG_DUMP_SECTION_TIMESTAMP] = dhd_get_time_str_len(); +#ifdef EWP_ECNTRS_LOGGING + sec_len[LOG_DUMP_SECTION_ECNTRS] = dhd_get_ecntrs_len(NULL, dhdp); +#endif /* EWP_ECNTRS_LOGGING */ + sec_len[LOG_DUMP_SECTION_DHD_DUMP] = dhd_get_dhd_dump_len(NULL, dhdp); +#if defined(BCMPCIE) + sec_len[LOG_DUMP_SECTION_EXT_TRAP] = dhd_get_ext_trap_len(NULL, dhdp); +#endif /* BCMPCIE */ + +#if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT) + sec_len[LOG_DUMP_SECTION_HEALTH_CHK] = dhd_get_health_chk_len(NULL, dhdp); +#endif + sec_len[LOG_DUMP_SECTION_COOKIE] = dhd_get_cookie_log_len(NULL, dhdp); +#ifdef DHD_DUMP_PCIE_RINGS + sec_len[LOG_DUMP_SECTION_RING] = dhd_get_flowring_len(NULL, dhdp); +#endif +#ifdef DHD_STATUS_LOGGING + sec_len[LOG_DUMP_SECTION_STATUS] = dhd_get_status_log_len(NULL, dhdp); +#endif /* DHD_STATUS_LOGGING */ +#ifdef EWP_RTT_LOGGING + sec_len[LOG_DUMP_SECTION_RTT] = dhd_get_rtt_len(NULL, dhdp); +#endif /* EWP_RTT_LOGGING */ +#ifdef DHD_MAP_PKTID_LOGGING + sec_len[LOG_DUMP_SECTION_PKTID_MAP_LOG] = + dhd_get_pktid_map_logging_len(NULL, dhdp, TRUE); + sec_len[LOG_DUMP_SECTION_PKTID_UNMAP_LOG] = + dhd_get_pktid_map_logging_len(NULL, dhdp, FALSE); +#endif /* DHD_MAP_PKTID_LOGGING */ + + DHD_ERROR(("%s: TS:%d ECNTRS:%d DHD_DUMP:%d ETRAP:%d" + " HCK:%d CKI:%d FLOW:%d STATUS:%d RTT:%d PKTID_MAP:%d PKTID_UNMAP:%d\n", + __func__, sec_len[LOG_DUMP_SECTION_TIMESTAMP], sec_len[LOG_DUMP_SECTION_ECNTRS], + sec_len[LOG_DUMP_SECTION_DHD_DUMP], sec_len[LOG_DUMP_SECTION_EXT_TRAP], + sec_len[LOG_DUMP_SECTION_HEALTH_CHK], sec_len[LOG_DUMP_SECTION_COOKIE], + sec_len[LOG_DUMP_SECTION_RING], sec_len[LOG_DUMP_SECTION_STATUS], + sec_len[LOG_DUMP_SECTION_RTT], sec_len[LOG_DUMP_SECTION_PKTID_MAP_LOG], + sec_len[LOG_DUMP_SECTION_PKTID_UNMAP_LOG])); + return; +} + +int dhd_debug_dump_buf_alloc(dhd_pub_t *dhdp, int id, char* name, int size) +{ + dhd_dbg_t *dbg = dhdp->dbg; + dhd_dbg_ring_t *ring = &dbg->dbg_rings[id]; + char *buf = NULL; + + if (!ring->ring_buf) { + buf = VMALLOCZ(dhdp->osh, size); + if (!buf) { + DHD_ERROR(("%s: Failed to alloc id:%d, size:%d\n", __func__, id, size)); + return BCME_NOMEM; + } + dhd_dbg_ring_set_buf(dhdp, &dbg->dbg_rings[id], buf); + DHD_ERROR(("%s: success to allocate ring id:%d name:%s\n", __func__, id, name)); + } else { + DHD_ERROR(("%s: already allocated id:%d name:%s\n", __func__, id, name)); + } + + return BCME_OK; +} + +int dhd_debug_dump_to_ring(dhd_pub_t *dhdp) +{ + dhd_dbg_t *dbg = dhdp->dbg; + dhd_dbg_ring_t *dbg_ring; + int ret = BCME_OK; + int ring_num, id; + uint32 sec_len[LOG_DUMP_SECTION_MAX] = {0}; + dhd_dbg_ring_status_t ring_status; + uint32 sync_retry; + unsigned long flags = 0; + + ret = dhd_debug_dump_buf_alloc(dhdp, DEBUG_DUMP_RING1_ID, + DEBUG_DUMP_RING1_NAME, DEBUG_DUMP_RING1_SIZE); + if (ret) { + return ret; + } + + ret = dhd_debug_dump_buf_alloc(dhdp, DEBUG_DUMP_RING2_ID, + DEBUG_DUMP_RING2_NAME, DEBUG_DUMP_RING2_SIZE); + if (ret) { + return ret; + } + +#ifdef DHD_MAP_PKTID_LOGGING + dhd_pktid_logging_dump(dhdp); +#endif /* DHD_MAP_PKTID_LOGGING */ + dhd_debug_dump_get_section_len(dhdp, sec_len); + + ring_num = dhd_debug_dump_get_ring_num(LOG_DUMP_SECTION_TIMESTAMP); + if (dhd_print_time_str(NULL, NULL, sec_len[LOG_DUMP_SECTION_TIMESTAMP], &ring_num)) { + DHD_ERROR(("Error section: dhd_print_time_str\n")); + } +#ifdef EWP_ECNTRS_LOGGING + if (dhd_print_ecntrs_data(NULL, dhdp, NULL, NULL, + sec_len[LOG_DUMP_SECTION_ECNTRS], NULL)) { + DHD_ERROR(("Error section: ECNTRS\n")); + } +#endif /* EWP_ECNTRS_LOGGING */ + +#ifdef DHD_STATUS_LOGGING + ring_num = dhd_debug_dump_get_ring_num(LOG_DUMP_SECTION_STATUS); + if (dhd_print_status_log_data(NULL, dhdp, NULL, NULL, + sec_len[LOG_DUMP_SECTION_STATUS], &ring_num)) { + DHD_ERROR(("Error section: STATUS_LOG\n")); + } +#endif /* DHD_STATUS_LOGGING */ +#ifdef EWP_RTT_LOGGING + if (dhd_print_rtt_data(NULL, dhdp, NULL, NULL, + sec_len[LOG_DUMP_SECTION_RTT], NULL)) { + DHD_ERROR(("Error section: RTT_LOG\n")); + } +#endif /* EWP_RTT_LOGGING */ +#ifdef DHD_MAP_PKTID_LOGGING + ring_num = dhd_debug_dump_get_ring_num(LOG_DUMP_SECTION_PKTID_MAP_LOG); + if (dhd_print_pktid_map_log_data(NULL, dhdp, NULL, NULL, + sec_len[LOG_DUMP_SECTION_PKTID_MAP_LOG], &ring_num, TRUE)) { + DHD_ERROR(("Error section: PKTID_MAP_LOG\n")); + } + ring_num = dhd_debug_dump_get_ring_num(LOG_DUMP_SECTION_PKTID_UNMAP_LOG); + if (dhd_print_pktid_map_log_data(NULL, dhdp, NULL, NULL, + sec_len[LOG_DUMP_SECTION_PKTID_UNMAP_LOG], &ring_num, FALSE)) { + DHD_ERROR(("Error section: PKTID_UNMAP_LOG\n")); + } +#endif /* DHD_MAP_PKTID_LOGGING */ + ring_num = dhd_debug_dump_get_ring_num(LOG_DUMP_SECTION_DHD_DUMP); + if (dhd_print_dump_data(NULL, dhdp, NULL, NULL, + sec_len[LOG_DUMP_SECTION_DHD_DUMP], &ring_num)) { + DHD_ERROR(("Error section: DHD_DUMP\n")); + } +#if defined(BCMPCIE) + ring_num = dhd_debug_dump_get_ring_num(LOG_DUMP_SECTION_EXT_TRAP); + if (dhd_print_ext_trap_data(NULL, dhdp, NULL, NULL, + sec_len[LOG_DUMP_SECTION_EXT_TRAP], &ring_num)) { + DHD_ERROR(("Error section: EXT TRAP\n")); + } +#endif /* BCMPCIE */ +#if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT) + ring_num = dhd_debug_dump_get_ring_num(LOG_DUMP_SECTION_HEALTH_CHK); + if (dhd_print_health_chk_data(NULL, dhdp, NULL, NULL, + sec_len[LOG_DUMP_SECTION_HEALTH_CHK], &ring_num)) { + DHD_ERROR(("Error section: HEALTH CHECK\n")); + } +#endif + ring_num = dhd_debug_dump_get_ring_num(LOG_DUMP_SECTION_COOKIE); + if (dhd_print_cookie_data(NULL, dhdp, NULL, NULL, + sec_len[LOG_DUMP_SECTION_COOKIE], &ring_num)) { + DHD_ERROR(("Error section: COOKIE DATA\n")); + } +#ifdef DHD_DUMP_PCIE_RINGS + ring_num = dhd_debug_dump_get_ring_num(LOG_DUMP_SECTION_RING); + if (dhd_print_flowring_data(NULL, dhdp, NULL, NULL, + sec_len[LOG_DUMP_SECTION_RING], &ring_num)) { + DHD_ERROR(("Error section: FLOWRING_DUMP\n")); + } +#endif + for (id = DEBUG_RING_ID_INVALID + 1; id < DEBUG_RING_ID_MAX; id++) { + dbg_ring = &dbg->dbg_rings[id]; + if (VALID_RING(dbg_ring->id)) { + /* To sync up with the ringbuffer in legacy HAL */ + dhd_os_trigger_get_ring_data(dhdp, dbg_ring->name); + + sync_retry = 0; + while (sync_retry < DHD_DEBUG_DUMP_MAX_SYNC_CNT) { + DHD_DBG_RING_LOCK(dbg_ring->lock, flags); + __dhd_dbg_get_ring_status(dbg_ring, &ring_status); + DHD_DBG_RING_UNLOCK(dbg_ring->lock, flags); + if (ring_status.written_bytes == ring_status.read_bytes) { + break; + } else { + OSL_SLEEP(50); + } + sync_retry++; + } + DHD_ERROR(("%s: ring sync up name:%s w/r bytes(%u/%u) retry:%d\n", + __func__, dbg_ring->name, ring_status.written_bytes, + ring_status.read_bytes, sync_retry)); + } + } + return ret; +} +#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */ +#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug.h old mode 100755 new mode 100644 index 08ba4a5aaa5c..6631c9830950 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug.h @@ -1,7 +1,7 @@ /* * DHD debugability header file * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -41,6 +41,7 @@ enum { DBG_DRIVER_DUMP_SUPPORTED = (1 << (7)), /* dumps driver state */ DBG_PACKET_FATE_SUPPORTED = (1 << (8)), /* tracks connection packets' fate */ DBG_NAN_EVENT_SUPPORTED = (1 << (9)), /* NAN Events */ + DBG_PACKET_LOG_SUPPORTED = (1 << (10)), /* Packet log with dbgring */ }; enum { @@ -50,6 +51,14 @@ enum { DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP = (1 << (1)) }; +enum { + /* Verbose logging level to set for each debug ring buffer */ + RING_LOG_LEVEL_NONE = 0, + RING_LOG_LEVEL_DEFAULT = 1, + RING_LOG_LEVEL_VERBOSE = 2, + RING_LOG_LEVEL_EXCESSIVE = 3 +}; + /* firmware verbose ring, ring id 1 */ #define FW_VERBOSE_RING_NAME "fw_verbose" #define FW_VERBOSE_RING_SIZE (256 * 1024) @@ -70,13 +79,31 @@ enum { /* ROAM stats log ring */ #define ROAM_STATS_RING_NAME "roam_stats" #define ROAM_STATS_RING_SIZE (64 * 1024) + +#define DEBUG_DUMP_RING1_NAME "debug_dump1_" +#define DEBUG_DUMP_RING1_SIZE (2 * 1024 * 1024) + +#define DEBUG_DUMP_RING2_NAME "debug_dump2_" +#define DEBUG_DUMP_RING2_SIZE (2 * 1024 * 1024) + +#define MEM_DUMP_RING_NAME "mem_dump" +#define MEM_DUMP_RING_SIZE (3 * 1024 * 1024) + +#define DHD_DEBUG_DUMP_NETLINK_MAX (1024 * 8) +#define DHD_DEBUG_DUMP_MAX_SYNC_CNT 5u #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ -#ifdef BTLOG -/* BT log ring, ring id 5 */ -#define BT_LOG_RING_NAME "bt_log" -#define BT_LOG_RING_SIZE (64 * 1024) -#endif /* BTLOG */ +/* Packet log ring, ring id 7 */ +#ifdef DHD_PKT_LOGGING_DBGRING +#define DHD_PACKET_LOG_RING_NAME "packet_log" +#define DHD_PACKET_LOG_RING_PKTS MIN_PKTLOG_LEN +#define DHD_PACKET_LOG_RING_SUSPEND_THRESHOLD \ + (DHD_PACKET_LOG_RING_PKTS * 8u / 10u) +#define DHD_PACKET_LOG_RING_RESUME_THRESHOLD \ + (DHD_PACKET_LOG_RING_PKTS * 2u / 10u) +#define DHD_PACKET_LOG_RING_SIZE \ + (DHD_PACKET_LOG_RING_PKTS * sizeof(dhd_pktlog_ring_info_t)) +#endif /* DHD_PKT_LOGGING_DBGRING */ #define TLV_LOG_SIZE(tlv) ((tlv) ? (sizeof(tlv_log) + (tlv)->len) : 0) @@ -90,7 +117,7 @@ enum { #ifdef DEBUGABILITY #define DBG_RING_ACTIVE(dhdp, ring_id) \ - ((dhdp)->dbg->dbg_rings[(ring_id)].state == RING_ACTIVE) + ((dhdp)->dbg && (dhdp)->dbg->dbg_rings[(ring_id)].state == RING_ACTIVE) #else #define DBG_RING_ACTIVE(dhdp, ring_id) 0 #endif /* DEBUGABILITY */ @@ -424,6 +451,16 @@ typedef enum { /* Packet free by firmware. */ TX_PKT_FATE_FW_PKT_FREE, + /* Firmware dropped the frame after suppress retries reached max */ + TX_PKT_FATE_FW_MAX_SUP_RETR, + + /* Firmware forced packet lifetime expiry */ + TX_PKT_FATE_FW_FORCED_EXPIRED, + +#ifdef DHD_PKT_LOGGING_DBGRING + /* Indicate to wait for updating txfate. */ + TX_PKT_FATE_DRV_WAIT_UPDATE = 0x80000000, +#endif /* DHD_PKT_LOGGING_DBGRING */ } wifi_tx_packet_fate; typedef enum { @@ -627,22 +664,26 @@ typedef struct dhd_dbg_rx_info typedef struct dhd_dbg_tx_report { dhd_dbg_tx_info_t *tx_pkts; + /* Indicates how many packets queued to send over the air */ uint16 pkt_pos; + /* Indicates how many packets sent over the air and received txstatus */ uint16 status_pos; } dhd_dbg_tx_report_t; typedef struct dhd_dbg_rx_report { dhd_dbg_rx_info_t *rx_pkts; + /* Indicates how many packets sent over the air and received txstatus */ uint16 pkt_pos; } dhd_dbg_rx_report_t; typedef void (*dbg_pullreq_t)(void *os_priv, const int ring_id); typedef void (*dbg_urgent_noti_t) (dhd_pub_t *dhdp, const void *data, const uint32 len); -typedef int (*dbg_mon_tx_pkts_t) (dhd_pub_t *dhdp, void *pkt, uint32 pktid); +typedef int (*dbg_mon_tx_pkts_t) (dhd_pub_t *dhdp, void *pkt, uint32 pktid, + frame_type type, uint8 mgmt_acked); typedef int (*dbg_mon_tx_status_t) (dhd_pub_t *dhdp, void *pkt, uint32 pktid, uint16 status); -typedef int (*dbg_mon_rx_pkts_t) (dhd_pub_t *dhdp, void *pkt); +typedef int (*dbg_mon_rx_pkts_t) (dhd_pub_t *dhdp, void *pkt, frame_type type); typedef struct dhd_dbg_pkt_mon { @@ -682,10 +723,11 @@ typedef struct dhd_dbg { (((status_count) >= (pkt_count)) || ((status_count) >= MAX_FATE_LOG_LEN)) #ifdef DBG_PKT_MON -#define DHD_DBG_PKT_MON_TX(dhdp, pkt, pktid) \ +#define DHD_DBG_PKT_MON_TX(dhdp, pkt, pktid, type, mgmt_acked) \ do { \ if ((dhdp) && (dhdp)->dbg && (dhdp)->dbg->pkt_mon.tx_pkt_mon && (pkt)) { \ - (dhdp)->dbg->pkt_mon.tx_pkt_mon((dhdp), (pkt), (pktid)); \ + (dhdp)->dbg->pkt_mon.tx_pkt_mon((dhdp), (pkt), \ + (pktid), (type), (mgmt_acked)); \ } \ } while (0); #define DHD_DBG_PKT_MON_TX_STATUS(dhdp, pkt, pktid, status) \ @@ -694,11 +736,11 @@ typedef struct dhd_dbg { (dhdp)->dbg->pkt_mon.tx_status_mon((dhdp), (pkt), (pktid), (status)); \ } \ } while (0); -#define DHD_DBG_PKT_MON_RX(dhdp, pkt) \ +#define DHD_DBG_PKT_MON_RX(dhdp, pkt, type) \ do { \ if ((dhdp) && (dhdp)->dbg && (dhdp)->dbg->pkt_mon.rx_pkt_mon && (pkt)) { \ if (ntoh16((pkt)->protocol) != ETHER_TYPE_BRCM) { \ - (dhdp)->dbg->pkt_mon.rx_pkt_mon((dhdp), (pkt)); \ + (dhdp)->dbg->pkt_mon.rx_pkt_mon((dhdp), (pkt), (type)); \ } \ } \ } while (0); @@ -708,9 +750,9 @@ typedef struct dhd_dbg { #define DHD_DBG_PKT_MON_STOP(dhdp) \ dhd_os_dbg_stop_pkt_monitor((dhdp)); #else -#define DHD_DBG_PKT_MON_TX(dhdp, pkt, pktid) +#define DHD_DBG_PKT_MON_TX(dhdp, pkt, pktid, type, mgmt_acked) #define DHD_DBG_PKT_MON_TX_STATUS(dhdp, pkt, pktid, status) -#define DHD_DBG_PKT_MON_RX(dhdp, pkt) +#define DHD_DBG_PKT_MON_RX(dhdp, pkt, type) #define DHD_DBG_PKT_MON_START(dhdp) #define DHD_DBG_PKT_MON_STOP(dhdp) #endif /* DBG_PKT_MON */ @@ -741,6 +783,8 @@ typedef struct { #define DHD_EVENT_LOG_FMT_NUM_OFFSET 2 #define DHD_EVENT_LOG_FMT_NUM_MASK 0x3FFF + +#define DHD_EXT_FMTNUM_MASK 0xF /* bits[3..0] used */ /** * OW:- one word * TW:- two word @@ -783,9 +827,6 @@ void dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, void *raw_event_ptr, uint datalen, bool msgtrace_hdr_present, uint32 msgtrace_seqnum); -#ifdef BTLOG -extern void dhd_dbg_bt_log_handler(dhd_pub_t *dhdp, void *data, uint datalen); -#endif /* BTLOG */ extern int dhd_dbg_attach(dhd_pub_t *dhdp, dbg_pullreq_t os_pullreq, dbg_urgent_noti_t os_urgent_notifier, void *os_priv); extern void dhd_dbg_detach(dhd_pub_t *dhdp); @@ -798,9 +839,18 @@ extern void *dhd_dbg_get_priv(dhd_pub_t *dhdp); extern int dhd_dbg_send_urgent_evt(dhd_pub_t *dhdp, const void *data, const uint32 len); extern void dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr, void *raw_event_ptr, uint32 *log_ptr, uint32 logset, uint16 block); -int dhd_dbg_pull_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len); +int dhd_dbg_pull_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len, + int *num_entries); int dhd_dbg_pull_single_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len, bool strip_header); +#ifdef DHD_PKT_LOGGING_DBGRING +int dhd_dbg_update_to_ring(dhd_pub_t *dhdp, void *ring, uint32 w_len); +int dhd_dbg_pull_from_pktlog(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len); +void dhd_os_dbg_urgent_pullreq(void *os_priv, int ring_id); +#endif /* DHD_PKT_LOGGING_DBGRING */ +#ifdef DHD_DEBUGABILITY_DEBUG_DUMP +int dhd_debug_dump_ring_push(dhd_pub_t *dhdp, int ring_id, uint32 len, void *data); +#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */ int dhd_dbg_push_to_ring(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_entry_t *hdr, void *data); int __dhd_dbg_get_ring_status(dhd_dbg_ring_t *ring, dhd_dbg_ring_status_t *ring_status); @@ -816,10 +866,11 @@ extern int dhd_dbg_attach_pkt_monitor(dhd_pub_t *dhdp, dbg_mon_tx_status_t tx_status_mon, dbg_mon_rx_pkts_t rx_pkt_mon); extern int dhd_dbg_start_pkt_monitor(dhd_pub_t *dhdp); -extern int dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid); +extern int dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, + uint32 pktid, frame_type type, uint8 mgmt_acked); extern int dhd_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid, uint16 status); -extern int dhd_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt); +extern int dhd_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt, frame_type type); extern int dhd_dbg_stop_pkt_monitor(dhd_pub_t *dhdp); extern int dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, uint16 req_count, uint16 *resp_count); @@ -855,10 +906,11 @@ extern int dhd_os_dbg_get_feature(dhd_pub_t *dhdp, int32 *features); extern int dhd_os_dbg_attach_pkt_monitor(dhd_pub_t *dhdp); extern int dhd_os_dbg_start_pkt_monitor(dhd_pub_t *dhdp); extern int dhd_os_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, - uint32 pktid); + uint32 pktid, frame_type type, uint8 mgmt_acked); extern int dhd_os_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid, uint16 status); -extern int dhd_os_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt); +extern int dhd_os_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt, + frame_type type); extern int dhd_os_dbg_stop_pkt_monitor(dhd_pub_t *dhdp); extern int dhd_os_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, uint16 req_count, uint16 *resp_count); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug_linux.c old mode 100755 new mode 100644 index 81aa730f238b..8f2f21a26815 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug_linux.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_debug_linux.c @@ -1,7 +1,7 @@ /* * DHD debugability Linux os layer * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -34,6 +34,9 @@ #include #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) +#include +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) */ #include typedef void (*dbg_ring_send_sub_t)(void *ctx, const int ring_id, const void *data, @@ -73,6 +76,7 @@ debug_data_send(dhd_pub_t *dhdp, int ring_id, const void *data, const uint32 len struct net_device *ndev; dbg_ring_send_sub_t ring_sub_send; ndev = dhd_linux_get_primary_netdev(dhdp); + if (!ndev) return; if (!VALID_RING(ring_id)) @@ -105,11 +109,21 @@ dbg_ring_poll_worker(struct work_struct *work) dhd_pub_t *dhdp; int ringid; dhd_dbg_ring_status_t ring_status; - void *buf; + void *buf, *buf_entries; + dhd_dbg_ring_entry_pack_t *pack_hdr; dhd_dbg_ring_entry_t *hdr; - uint32 buflen, rlen; + int32 buflen, rlen, remain_buflen; + int32 alloc_len; unsigned long flags; + BCM_REFERENCE(hdr); + + if (!CAN_SLEEP()) { + DHD_CONS_ONLY(("this context should be sleepable\n")); + sched = FALSE; + goto exit; + } + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); ring_info = container_of(d_work, linux_dbgring_info_t, work); GCC_DIAGNOSTIC_POP(); @@ -120,55 +134,126 @@ dbg_ring_poll_worker(struct work_struct *work) ring = &dhdp->dbg->dbg_rings[ringid]; DHD_DBG_RING_LOCK(ring->lock, flags); dhd_dbg_get_ring_status(dhdp, ringid, &ring_status); + DHD_DBG_RING_UNLOCK(ring->lock, flags); - if (ring->wp > ring->rp) { - buflen = ring->wp - ring->rp; - } else if (ring->wp < ring->rp) { - buflen = ring->ring_size - ring->rp + ring->wp; - } else { - goto exit; +#ifdef DHD_PKT_LOGGING_DBGRING + if (ringid == PACKET_LOG_RING_ID) { + struct net_device *ndev; + ndev = dhd_linux_get_primary_netdev(dhdp); + buflen = DBG_RING_ENTRY_SIZE; + buflen += dhd_os_get_pktlog_dump_size(ndev); + DHD_DBGIF(("%s: buflen: %d\n", __FUNCTION__, buflen)); + alloc_len = buflen + DBG_RING_ENTRY_PACK_SIZE; + } else +#endif /* DHD_PKT_LOGGING_DBGRING */ + { + DHD_DBG_RING_LOCK(ring->lock, flags); + if (ring->wp > ring->rp) { + buflen = ring->wp - ring->rp; + } else if (ring->wp < ring->rp) { + buflen = ring->ring_size - ring->rp + ring->wp; + } else { + DHD_DBG_RING_UNLOCK(ring->lock, flags); + goto exit; + } + + if (buflen > ring->ring_size) { + DHD_DBG_RING_UNLOCK(ring->lock, flags); + goto exit; + } + DHD_DBG_RING_UNLOCK(ring->lock, flags); + + alloc_len = NLMSG_DEFAULT_SIZE; } + buf = VMALLOCZ(dhdp->osh, alloc_len); - if (buflen > ring->ring_size) { - goto exit; - } - - buf = MALLOCZ(dhdp->osh, buflen); if (!buf) { - DHD_ERROR(("%s failed to allocate read buf\n", __FUNCTION__)); + DHD_CONS_ONLY(("%s failed to allocate read buf\n", __FUNCTION__)); sched = FALSE; goto exit; } - DHD_DBG_RING_UNLOCK(ring->lock, flags); - rlen = dhd_dbg_pull_from_ring(dhdp, ringid, buf, buflen); - DHD_DBG_RING_LOCK(ring->lock, flags); + pack_hdr = (dhd_dbg_ring_entry_pack_t *)buf; + pack_hdr->magic = DBG_RING_PACK_MAGIC; + buf_entries = (char *)buf + sizeof(dhd_dbg_ring_entry_pack_t); + +#ifdef DHD_PKT_LOGGING_DBGRING + if (ringid == PACKET_LOG_RING_ID) { + pack_hdr->num_entries = 1u; + rlen = dhd_dbg_pull_from_pktlog(dhdp, ringid, buf_entries, buflen); + DHD_DBGIF(("%s: rlen: %d\n", __FUNCTION__, rlen)); + hdr = (dhd_dbg_ring_entry_t *)buf_entries; + while (rlen > 0) { + DHD_DBG_RING_LOCK(ring->lock, flags); + ring_status.read_bytes += (rlen - DBG_RING_ENTRY_SIZE); + ring->stat.read_bytes += (rlen - DBG_RING_ENTRY_SIZE); + if (ring->stat.read_bytes > ring->stat.written_bytes) { + DHD_DBGIF(("%s READ/WRITE counter mismatched!\n", __FUNCTION__)); + ring->stat.read_bytes = ring->stat.written_bytes; + } + DHD_DBGIF(("%s RING%d[%s]read_bytes %d, written_bytes %d, " + "writen_records %d\n", __FUNCTION__, ring->id, ring->name, + ring->stat.read_bytes, ring->stat.written_bytes, + ring->stat.written_records)); + DHD_DBG_RING_UNLOCK(ring->lock, flags); + /* offset fw ts to host ts */ + hdr->timestamp += ring_info->tsoffset; + debug_data_send(dhdp, ringid, pack_hdr, + ENTRY_LENGTH(hdr) + DBG_RING_ENTRY_PACK_SIZE, ring_status); + rlen -= ENTRY_LENGTH(hdr); + hdr = (dhd_dbg_ring_entry_t *)((char *)hdr + ENTRY_LENGTH(hdr)); + } + } else +#endif /* DHD_PKT_LOGGING_DBGRING */ + { + remain_buflen = buflen; + while (remain_buflen > 0) { + pack_hdr->num_entries = 0; + memset_s(buf_entries, NLMSG_DEFAULT_SIZE - DBG_RING_ENTRY_PACK_SIZE, + 0, NLMSG_DEFAULT_SIZE - DBG_RING_ENTRY_PACK_SIZE); + /* Returns as much as possible with the size of the passed buffer + * rlen means the total length of multiple entries including entry hdr + */ + rlen = dhd_dbg_pull_from_ring(dhdp, ringid, buf_entries, + NLMSG_DEFAULT_SIZE - DBG_RING_ENTRY_PACK_SIZE, + &pack_hdr->num_entries); + if (rlen <= 0) { + break; + } + + DHD_DBG_RING_LOCK(ring->lock, flags); + ring_status.read_bytes += rlen; + DHD_DBG_RING_UNLOCK(ring->lock, flags); + + /* payload length includes pack_hdr size */ + debug_data_send(dhdp, ringid, pack_hdr, + rlen + DBG_RING_ENTRY_PACK_SIZE, ring_status); + remain_buflen -= rlen; + } + } + + VMFREE(dhdp->osh, buf, alloc_len); + + DHD_DBG_RING_LOCK(ring->lock, flags); if (!ring->sched_pull) { ring->sched_pull = TRUE; } - - hdr = (dhd_dbg_ring_entry_t *)buf; - while (rlen > 0) { - ring_status.read_bytes += ENTRY_LENGTH(hdr); - /* offset fw ts to host ts */ - hdr->timestamp += ring_info->tsoffset; - debug_data_send(dhdp, ringid, hdr, ENTRY_LENGTH(hdr), - ring_status); - rlen -= ENTRY_LENGTH(hdr); - hdr = (dhd_dbg_ring_entry_t *)((char *)hdr + ENTRY_LENGTH(hdr)); - } - MFREE(dhdp->osh, buf, buflen); - + DHD_DBG_RING_UNLOCK(ring->lock, flags); exit: if (sched) { /* retrigger the work at same interval */ - if ((ring_status.written_bytes == ring_status.read_bytes) && - (ring_info->interval)) { - schedule_delayed_work(d_work, ring_info->interval); + if ((ring_info->interval)) { + if ((ring_status.written_bytes == ring_status.read_bytes) || +#ifdef DHD_PKT_LOGGING_DBGRING + (ringid == PACKET_LOG_RING_ID)) { +#else + FALSE) { +#endif /* DHD_PKT_LOGGING_DBGRING */ + schedule_delayed_work(d_work, ring_info->interval); + } } } - DHD_DBG_RING_UNLOCK(ring->lock, flags); return; } @@ -205,8 +290,9 @@ dhd_os_start_logging(dhd_pub_t *dhdp, char *ring_name, int log_level, if (!VALID_RING(ring_id)) return BCME_UNSUPPORTED; - DHD_INFO(("%s , log_level : %d, time_intval : %d, threshod %d Bytes\n", - __FUNCTION__, log_level, time_intval, threshold)); + DHD_ERROR(("%s , ring_id : %d log_level : %d, " + "time_intval : %d, threshod %d Bytes\n", + __FUNCTION__, ring_id, log_level, time_intval, threshold)); /* change the configuration */ ret = dhd_dbg_set_configuration(dhdp, ring_id, log_level, flags, threshold); @@ -248,8 +334,6 @@ dhd_os_reset_logging(dhd_pub_t *dhdp) DHD_INFO(("%s: Stop ring buffer %d\n", __FUNCTION__, ring_id)); ring_info = &os_priv[ring_id]; - /* cancel any pending work */ - cancel_delayed_work_sync(&ring_info->work); /* log level zero makes stop logging on that ring */ ring_info->log_level = 0; ring_info->interval = 0; @@ -259,6 +343,8 @@ dhd_os_reset_logging(dhd_pub_t *dhdp) DHD_ERROR(("dhd_set_configuration is failed : %d\n", ret)); return ret; } + /* cancel any pending work */ + cancel_delayed_work_sync(&ring_info->work); } return ret; } @@ -365,7 +451,7 @@ dhd_os_push_push_ring_data(dhd_pub_t *dhdp, int ring_id, void *data, int32 data_ } #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ ret = dhd_dbg_push_to_ring(dhdp, ring_id, &msg_hdr, event_data); - if (ret) { + if (ret && ret != BCME_BUSY) { DHD_ERROR(("%s : failed to push data into the ring (%d) with ret(%d)\n", __FUNCTION__, ring_id, ret)); } @@ -388,9 +474,10 @@ dhd_os_dbg_start_pkt_monitor(dhd_pub_t *dhdp) } int -dhd_os_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid) +dhd_os_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid, + frame_type type, uint8 mgmt_acked) { - return dhd_dbg_monitor_tx_pkts(dhdp, pkt, pktid); + return dhd_dbg_monitor_tx_pkts(dhdp, pkt, pktid, type, mgmt_acked); } int @@ -401,9 +488,9 @@ dhd_os_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid, } int -dhd_os_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt) +dhd_os_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt, frame_type type) { - return dhd_dbg_monitor_rx_pkts(dhdp, pkt); + return dhd_dbg_monitor_rx_pkts(dhdp, pkt, type); } int @@ -465,6 +552,9 @@ dhd_os_dbg_get_feature(dhd_pub_t *dhdp, int32 *features) } #endif /* DBG_PKT_MON */ #endif /* DEBUGABILITY */ +#ifdef DHD_PKT_LOGGING_DBGRING + *features |= DBG_PACKET_LOG_SUPPORTED; +#endif /* DHD_PKT_LOGGING_DBGRING */ return ret; } @@ -478,6 +568,14 @@ dhd_os_dbg_pullreq(void *os_priv, int ring_id) schedule_delayed_work(&ring_info->work, 0); } +#ifdef DHD_PKT_LOGGING_DBGRING +void +dhd_os_dbg_urgent_pullreq(void *os_priv, int ring_id) +{ + dhd_os_dbg_pullreq(os_priv, ring_id); +} +#endif /* DHD_PKT_LOGGING_DBGRING */ + int dhd_os_dbg_attach(dhd_pub_t *dhdp) { @@ -486,9 +584,12 @@ dhd_os_dbg_attach(dhd_pub_t *dhdp) int ring_id; /* os_dbg data */ - os_priv = MALLOCZ(dhdp->osh, sizeof(*os_priv) * DEBUG_RING_ID_MAX); - if (!os_priv) + os_priv = VMALLOCZ(dhdp->osh, sizeof(*os_priv) * DEBUG_RING_ID_MAX); + if (!os_priv) { + DHD_ERROR(("%s:%d: VMALLOC failed for os_priv, size %d\n", __FUNCTION__, + __LINE__, (uint32)sizeof(*os_priv) * DEBUG_RING_ID_MAX)); return BCME_NOMEM; + } for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) { @@ -499,8 +600,9 @@ dhd_os_dbg_attach(dhd_pub_t *dhdp) } ret = dhd_dbg_attach(dhdp, dhd_os_dbg_pullreq, dhd_os_dbg_urgent_notifier, os_priv); - if (ret) - MFREE(dhdp->osh, os_priv, sizeof(*os_priv) * DEBUG_RING_ID_MAX); + if (ret) { + VMFREE(dhdp->osh, os_priv, sizeof(*os_priv) * DEBUG_RING_ID_MAX); + } return ret; } @@ -522,7 +624,7 @@ dhd_os_dbg_detach(dhd_pub_t *dhdp) cancel_delayed_work_sync(&ring_info->work); } } - MFREE(dhdp->osh, os_priv, sizeof(*os_priv) * DEBUG_RING_ID_MAX); + VMFREE(dhdp->osh, os_priv, sizeof(*os_priv) * DEBUG_RING_ID_MAX); return dhd_dbg_detach(dhdp); } diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_event_log_filter.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_event_log_filter.c old mode 100755 new mode 100644 index 7964c7b6b13b..b5417aece43d --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_event_log_filter.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_event_log_filter.c @@ -1,7 +1,7 @@ /* * Wifi dongle status Filter and Report * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -63,11 +63,7 @@ #endif /* IL_BIGENDINAN */ #define DHD_FILTER_ERR_INTERNAL(fmt, ...) DHD_ERROR(("EWPF-" fmt, ##__VA_ARGS__)) -#ifdef DHD_REPLACE_LOG_INFO_TO_TRACE -#define DHD_FILTER_TRACE_INTERNAL(fmt, ...) DHD_TRACE(("EWPF-" fmt, ##__VA_ARGS__)) -#else #define DHD_FILTER_TRACE_INTERNAL(fmt, ...) DHD_INFO(("EWPF-" fmt, ##__VA_ARGS__)) -#endif /* DHD_REPLACE_LOG_INFO_TO_TRACE */ #define DHD_FILTER_ERR(x) DHD_FILTER_ERR_INTERNAL x #define DHD_FILTER_TRACE(x) DHD_FILTER_TRACE_INTERNAL x @@ -92,7 +88,7 @@ #define EWPF_SLICE_MAIN 0 /* SLICE ID for 5GHZ */ #define EWPF_SLICE_AUX 1 /* SLICE ID for 2GHZ */ -#define EWPF_MAX_IFACE 2 /* MAX IFACE supported, 0: STA */ +#define EWPF_MAX_IFACE 3 /* MAX IFACE supported */ #define EWPF_MAX_EVENT 1 /* MAX EVENT counter supported */ #define EWPF_MAX_KEY_INFO 1 /* MAX KEY INFO counter supported */ @@ -131,6 +127,7 @@ typedef struct { wl_periodic_compact_cntrs_v1_t compact_cntr_v1; wl_periodic_compact_cntrs_v2_t compact_cntr_v2; wl_periodic_compact_cntrs_v3_t compact_cntr_v3; + wl_periodic_compact_cntrs_v4_t compact_cntr_v4; }; evt_hist_compact_toss_stats_v1_t hist_tx_toss_stat; evt_hist_compact_toss_stats_v1_t hist_rx_toss_stat; @@ -230,7 +227,7 @@ static EWPF_tbl_t EWPF_periodic[] = { WL_STATE_COMPACT_COUNTERS, evt_xtlv_copy_cb, - SLICE_INFO(compact_cntr_v3), + SLICE_INFO(compact_cntr_v4), NULL }, { @@ -835,7 +832,7 @@ static int evt_get_last_toss_hist(uint8 *ptr, const uint8 *data, uint16 len) { bcm_xtlv_t *bcm_xtlv_desc = (bcm_xtlv_t *)data; - wl_hist_compact_toss_stats_v2_t *ewp_stats; + wl_hist_compact_toss_stats_v3_t *ewp_stats; evt_hist_compact_toss_stats_v1_t bidata_stats; int16 max_rcidx = EWPF_INVALID, secnd_rcidx = EWPF_INVALID; uint16 cur_rnidx = 0, prev_rnidx = 0; @@ -846,21 +843,21 @@ evt_get_last_toss_hist(uint8 *ptr, const uint8 *data, uint16 len) return BCME_ERROR; } - if (bcm_xtlv_desc->len != sizeof(wl_hist_compact_toss_stats_v2_t)) { + if (bcm_xtlv_desc->len != sizeof(wl_hist_compact_toss_stats_v3_t)) { DHD_FILTER_ERR(("%s : size is not matched %d\n", __FUNCTION__, bcm_xtlv_desc->len)); return BCME_ERROR; } - ewp_stats = (wl_hist_compact_toss_stats_v2_t *)(&bcm_xtlv_desc->data[0]); + ewp_stats = (wl_hist_compact_toss_stats_v3_t *)(&bcm_xtlv_desc->data[0]); if (ewp_stats->htr_type == WL_STATE_HIST_TX_TOSS_REASONS) { - if (ewp_stats->version != WL_HIST_COMPACT_TOSS_STATS_TX_VER_2) { + if (ewp_stats->version != WL_HIST_COMPACT_TOSS_STATS_TX_VER_3) { DHD_FILTER_ERR(("%s : unsupported version %d (type: %d)\n", __FUNCTION__, ewp_stats->version, ewp_stats->htr_type)); return BCME_ERROR; } } else if (ewp_stats->htr_type == WL_STATE_HIST_RX_TOSS_REASONS) { - if (ewp_stats->version != WL_HIST_COMPACT_TOSS_STATS_RX_VER_2) { + if (ewp_stats->version != WL_HIST_COMPACT_TOSS_STATS_RX_VER_3) { DHD_FILTER_ERR(("%s : unsupported version %d (type: %d)\n", __FUNCTION__, ewp_stats->version, ewp_stats->htr_type)); return BCME_ERROR; @@ -888,10 +885,9 @@ evt_get_last_toss_hist(uint8 *ptr, const uint8 *data, uint16 len) * Need to get largest count of toss reasons */ for (idx = 0; idx < WLC_HIST_TOSS_LEN; idx ++) { - cur_rccnt = (uint16)((ewp_stats->htr_rc[idx] & - HIST_TOSS_RC_COUNT_MASK)>>HIST_TOSS_RC_COUNT_POS); + cur_rccnt = (uint16)(ewp_stats->htr_rc[idx].toss_cnt); DHD_FILTER_TRACE(("%s: idx %d htr_rc %04x cur_rccnt %d\n", - __FUNCTION__, idx, ewp_stats->htr_rc[idx], cur_rccnt)); + __FUNCTION__, idx, ewp_stats->htr_rc[idx].toss_reason, cur_rccnt)); if (ewp_stats->htr_rc_ts[idx] && max_rccnt < cur_rccnt) { max_rccnt = cur_rccnt; secnd_rcidx = max_rcidx; @@ -906,16 +902,16 @@ evt_get_last_toss_hist(uint8 *ptr, const uint8 *data, uint16 len) bidata_stats.version = ewp_stats->version; bidata_stats.htr_type = ewp_stats->htr_type; bidata_stats.htr_num = ewp_stats->htr_num; - bidata_stats.htr_rn_last = ewp_stats->htr_running[cur_rnidx]; + bidata_stats.htr_rn_last = *(uint32*)(&ewp_stats->htr_running[cur_rnidx]); bidata_stats.htr_rn_ts_last = ewp_stats->htr_rn_ts[cur_rnidx]; - bidata_stats.htr_rn_prev = ewp_stats->htr_running[prev_rnidx]; + bidata_stats.htr_rn_prev = *(uint32*)(&ewp_stats->htr_running[prev_rnidx]); bidata_stats.htr_rn_ts_prev = ewp_stats->htr_rn_ts[prev_rnidx]; if (max_rcidx != EWPF_INVALID) { - bidata_stats.htr_rc_max = ewp_stats->htr_rc[max_rcidx]; + bidata_stats.htr_rc_max = *(uint32*)(&ewp_stats->htr_rc[max_rcidx]); bidata_stats.htr_rc_ts_max = ewp_stats->htr_rc_ts[max_rcidx]; } if (secnd_rcidx != EWPF_INVALID) { - bidata_stats.htr_rc_secnd = ewp_stats->htr_rc[secnd_rcidx]; + bidata_stats.htr_rc_secnd = *(uint32*)(&ewp_stats->htr_rc[secnd_rcidx]); bidata_stats.htr_rc_ts_secnd = ewp_stats->htr_rc_ts[secnd_rcidx]; } DHD_FILTER_TRACE(("%s: ver %d type %d num %d " @@ -1279,7 +1275,7 @@ dhd_event_log_filter_event_handler(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_h #define EWP_REPORT_NAME_MAX 64 #ifdef DHD_EWPR_VER2 -#define EWP_REPORT_VERSION 0x20190514 +#define EWP_REPORT_VERSION 0x20200722 #define EWP_REPORT_SET_DEFAULT 0x01 #define EWPR_CSDCLIENT_DIFF 10 #define EWPR_INTERVAL 3 @@ -1349,7 +1345,7 @@ typedef struct { uint32 *delta_list; /* IN delta values to find */ } ewpr_lock_param_t; -#define MAX_MULTI_VER 3 +#define MAX_MULTI_VER 4 typedef struct { uint32 version; /* VERSION for multiple version struct */ uint32 offset; /* offset of the member at the version */ @@ -1386,7 +1382,7 @@ typedef struct { /* offset defines */ #define EWPR_CNT_VERSION_OFFSET \ - OFFSETOF(EWPF_slc_elem_t, compact_cntr_v3) + OFFSETOF(EWPF_slc_elem_t, compact_cntr_v4) #define EWPR_CNT_V1_OFFSET(a) \ WL_PERIODIC_COMPACT_CNTRS_VER_1, \ @@ -1397,6 +1393,9 @@ typedef struct { #define EWPR_CNT_V3_OFFSET(a) \ WL_PERIODIC_COMPACT_CNTRS_VER_3, \ (OFFSETOF(EWPF_slc_elem_t, compact_cntr_v3) + OFFSETOF(wl_periodic_compact_cntrs_v3_t, a)) +#define EWPR_CNT_V4_OFFSET(a) \ + WL_PERIODIC_COMPACT_CNTRS_VER_4, \ + (OFFSETOF(EWPF_slc_elem_t, compact_cntr_v4) + OFFSETOF(wl_periodic_compact_cntrs_v4_t, a)) #define EWPR_STAT_OFFSET(a) \ (OFFSETOF(EWPF_ifc_elem_t, if_stat) + OFFSETOF(wl_if_stats_t, a)) #define EWPR_INFRA_OFFSET(a) \ @@ -1434,14 +1433,16 @@ typedef struct { .v_info = { EWPR_CNT_VERSION_OFFSET, \ {{EWPR_CNT_V1_OFFSET(a)}, \ {EWPR_CNT_V2_OFFSET(a)}, \ - {EWPR_CNT_V3_OFFSET(a)}}}, \ + {EWPR_CNT_V3_OFFSET(a)}, \ + {EWPR_CNT_V4_OFFSET(a)}}}, \ EWP_UINT32, EWP_HEX, EWP_UINT32} #define EWPR_SERIAL_CNT_16(a) {\ #a, EWPF_IDX_TYPE_SLICE, TRUE, \ .v_info = { EWPR_CNT_VERSION_OFFSET, \ {{EWPR_CNT_V1_OFFSET(a)}, \ {EWPR_CNT_V2_OFFSET(a)}, \ - {EWPR_CNT_V3_OFFSET(a)}}}, \ + {EWPR_CNT_V3_OFFSET(a)}, \ + {EWPR_CNT_V4_OFFSET(a)}}}, \ EWP_UINT32, EWP_HEX, EWP_UINT16} #define EWPR_SERIAL_STAT(a) {\ #a, EWPF_IDX_TYPE_IFACE, FALSE, .offset = EWPR_STAT_OFFSET(a), \ @@ -1528,10 +1529,10 @@ typedef struct { #define EWPR_SINGLE_USEC_TO_SEC EWPR_DISPLAY_METHOD_SINGLE, EWPF_USEC_TO_SEC /* serail info type define */ -#define EWPR_SERIAL_CNT_V3_BIT(a, b, c, d) {\ +#define EWPR_SERIAL_CNT_V4_BIT(a, b, c, d) {\ #a, EWPF_IDX_TYPE_SLICE, TRUE, \ .v_info = { EWPR_CNT_VERSION_OFFSET, \ - {{EWPR_CNT_V3_OFFSET(a)}}}, \ + {{EWPR_CNT_V4_OFFSET(a)}}}, \ EWP_UINT32, EWP_BIN, EWP_BIT, EWPF_INFO_ECNT, b, c, d} #define EWPR_SERIAL_STAT_BIT(a, b, c, d) {\ #a, EWPF_IDX_TYPE_IFACE, FALSE, .offset = EWPR_STAT_OFFSET(a), \ @@ -1717,21 +1718,28 @@ ewpr_serial_bit_unwanted_network_default_tbl[] = { EWPR_SERIAL_MGMT_BIT(rxdeauth, 4, 6, EWPR_DIFF_DEFAULT), EWPR_SERIAL_MGMT_BIT(txaction, 7, 6, EWPR_DIFF_DEFAULT), EWPR_SERIAL_MGMT_BIT(rxaction, 7, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(txallfrm, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxrsptmout, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxbadplcp, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxcrsglitch, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxbadfcs, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxbeaconmbss, 5, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxbeaconobss, 12, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(lqcm_report, 19, 6, EWPR_SINGLE_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(tx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxretry, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxdup, 15, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(chswitch_cnt, 8, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(pm_dur, 12, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxholes, 15, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(txallfrm, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxrsptmout, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxbadplcp, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxcrsglitch, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxbadfcs, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxbeaconmbss, 5, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxbeaconobss, 12, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(lqcm_report, 19, 6, EWPR_SINGLE_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(tx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxretry, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxdup, 15, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(chswitch_cnt, 8, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(pm_dur, 12, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxholes, 15, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxundec, 16, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxundec_mcst, 16, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(replay, 12, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(replay_mcst, 12, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(pktfilter_discard, 16, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(pktfilter_forward, 16, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(mac_rxfilter, 16, 6, EWPR_DIFF_DEFAULT), EWPR_SERIAL_BTC_STAT_16_BIT(bt_dcsn_map, 16, 3, EWPR_SINGLE_DEFAULT), EWPR_SERIAL_BTC_STAT_16_BIT(bt_dcsn_cnt, 12, 3, EWPR_SINGLE_DEFAULT), EWPR_SERIAL_BTC_STAT_16_BIT(bt_a2dp_hiwat_cnt, 12, 3, EWPR_SINGLE_DEFAULT), @@ -1783,7 +1791,7 @@ ewpr_serial_bit_unwanted_network_default_tbl[] = { EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_max, 32, 1, EWPR_SINGLE_DEFAULT), EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_ts_secnd, 32, 1, EWPR_SINGLE_DEFAULT), EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_secnd, 32, 1, EWPR_SINGLE_DEFAULT), - EWPR_SERIAL_CPLOG_BIT(packtlog, 22, 70), + EWPR_SERIAL_CPLOG_BIT(packtlog, 22, 50), EWPR_SERIAL_NONE }; @@ -1817,21 +1825,28 @@ ewpr_serial_bit_assoc_fail_default_tbl[] = { EWPR_SERIAL_MGMT_BIT(rxdeauth, 4, 6, EWPR_DIFF_DEFAULT), EWPR_SERIAL_MGMT_BIT(txaction, 7, 6, EWPR_DIFF_DEFAULT), EWPR_SERIAL_MGMT_BIT(rxaction, 7, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(txallfrm, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxrsptmout, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxbadplcp, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxcrsglitch, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxbadfcs, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxbeaconmbss, 5, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxbeaconobss, 12, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(lqcm_report, 19, 6, EWPR_SINGLE_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(tx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxretry, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxdup, 15, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(chswitch_cnt, 8, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(pm_dur, 12, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxholes, 15, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(txallfrm, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxrsptmout, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxbadplcp, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxcrsglitch, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxbadfcs, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxbeaconmbss, 5, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxbeaconobss, 12, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(lqcm_report, 19, 6, EWPR_SINGLE_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(tx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxretry, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxdup, 15, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(chswitch_cnt, 8, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(pm_dur, 12, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxholes, 15, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxundec, 16, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxundec_mcst, 16, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(replay, 12, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(replay_mcst, 12, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(pktfilter_discard, 16, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(pktfilter_forward, 16, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(mac_rxfilter, 16, 6, EWPR_DIFF_DEFAULT), EWPR_SERIAL_BTC_STAT_16_BIT(bt_dcsn_map, 16, 3, EWPR_SINGLE_DEFAULT), EWPR_SERIAL_BTC_STAT_16_BIT(bt_dcsn_cnt, 12, 3, EWPR_SINGLE_DEFAULT), EWPR_SERIAL_BTC_STAT_16_BIT(bt_a2dp_hiwat_cnt, 12, 3, EWPR_SINGLE_DEFAULT), @@ -1869,7 +1884,7 @@ ewpr_serial_bit_assoc_fail_default_tbl[] = { EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_max, 32, 1, EWPR_SINGLE_DEFAULT), EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_ts_secnd, 32, 1, EWPR_SINGLE_DEFAULT), EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_secnd, 32, 1, EWPR_SINGLE_DEFAULT), - EWPR_SERIAL_CPLOG_BIT(packtlog, 22, 70), + EWPR_SERIAL_CPLOG_BIT(packtlog, 22, 50), EWPR_SERIAL_NONE }; @@ -1903,21 +1918,28 @@ ewpr_serial_bit_abnormal_disconnect_default_tbl[] = { EWPR_SERIAL_MGMT_BIT(rxdeauth, 4, 6, EWPR_DIFF_DEFAULT), EWPR_SERIAL_MGMT_BIT(txaction, 7, 6, EWPR_DIFF_DEFAULT), EWPR_SERIAL_MGMT_BIT(rxaction, 7, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(txallfrm, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxrsptmout, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxbadplcp, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxcrsglitch, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxbadfcs, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxbeaconmbss, 5, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxbeaconobss, 12, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(lqcm_report, 19, 6, EWPR_SINGLE_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(tx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxretry, 17, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxdup, 15, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(chswitch_cnt, 8, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(pm_dur, 12, 6, EWPR_DIFF_DEFAULT), - EWPR_SERIAL_CNT_V3_BIT(rxholes, 15, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(txallfrm, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxrsptmout, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxbadplcp, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxcrsglitch, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxbadfcs, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxbeaconmbss, 5, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxbeaconobss, 12, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(lqcm_report, 19, 6, EWPR_SINGLE_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(tx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxretry, 17, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxdup, 15, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(chswitch_cnt, 8, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(pm_dur, 12, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxholes, 15, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxundec, 16, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(rxundec_mcst, 16, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(replay, 12, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(replay_mcst, 12, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(pktfilter_discard, 16, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(pktfilter_forward, 16, 6, EWPR_DIFF_DEFAULT), + EWPR_SERIAL_CNT_V4_BIT(mac_rxfilter, 16, 6, EWPR_DIFF_DEFAULT), EWPR_SERIAL_BTC_STAT_16_BIT(bt_dcsn_map, 16, 3, EWPR_SINGLE_DEFAULT), EWPR_SERIAL_BTC_STAT_16_BIT(bt_dcsn_cnt, 12, 3, EWPR_SINGLE_DEFAULT), EWPR_SERIAL_BTC_STAT_16_BIT(bt_a2dp_hiwat_cnt, 12, 3, EWPR_SINGLE_DEFAULT), @@ -1969,7 +1991,7 @@ ewpr_serial_bit_abnormal_disconnect_default_tbl[] = { EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_max, 32, 1, EWPR_SINGLE_DEFAULT), EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_ts_secnd, 32, 1, EWPR_SINGLE_DEFAULT), EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_secnd, 32, 1, EWPR_SINGLE_DEFAULT), - EWPR_SERIAL_CPLOG_BIT(packtlog, 22, 70), + EWPR_SERIAL_CPLOG_BIT(packtlog, 22, 50), EWPR_SERIAL_NONE }; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_event_log_filter.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_event_log_filter.h old mode 100755 new mode 100644 index a39da3bd7edd..37612db18fe2 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_event_log_filter.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_event_log_filter.h @@ -1,7 +1,7 @@ /* * Wifi dongle status Filter and Report * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_flowring.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_flowring.c old mode 100755 new mode 100644 index 12218c260ce7..1b3b20c34f57 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_flowring.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_flowring.c @@ -4,7 +4,7 @@ * Flow rings are transmit traffic (=propagating towards antenna) related entities * * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -64,12 +64,6 @@ int dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt); #define FLOW_QUEUE_PKT_NEXT(p) PKTLINK(p) #define FLOW_QUEUE_PKT_SETNEXT(p, x) PKTSETLINK((p), (x)) -#ifdef DHD_REPLACE_LOG_INFO_TO_TRACE -#define DHD_FLOWRING_INFO DHD_TRACE -#else -#define DHD_FLOWRING_INFO DHD_INFO -#endif /* DHD_REPLACE_LOG_INFO_TO_TRACE */ - const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 3 }; const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; @@ -254,7 +248,6 @@ BCMFASTPATH(dhd_flow_queue_dequeue)(dhd_pub_t *dhdp, flow_queue_t *queue) pkt = queue->head; /* from head */ if (pkt == NULL) { - ASSERT((queue->len == 0) && (queue->tail == NULL)); goto done; } @@ -361,11 +354,11 @@ dhd_get_max_multi_client_flow_rings(dhd_pub_t *dhdp) int dhd_flowid_map_init(dhd_pub_t *dhdp, uint16 max_tx_flow_rings) { -#if defined(DHD_HTPUT_TUNABLES) - uint16 max_normal_tx_flow_rings = max_tx_flow_rings - HTPUT_TOTAL_FLOW_RINGS; -#else uint16 max_normal_tx_flow_rings = max_tx_flow_rings; -#endif /* DHD_HTPUT_TUNABLES */ + + if (dhdp->htput_support) { + max_normal_tx_flow_rings = max_tx_flow_rings - HTPUT_TOTAL_FLOW_RINGS; + } /* Construct a normal flowid allocator from FLOWID_RESERVED to * (max_normal_tx_flow_rings - 1) @@ -377,21 +370,24 @@ dhd_flowid_map_init(dhd_pub_t *dhdp, uint16 max_tx_flow_rings) return BCME_NOMEM; } -#if defined(DHD_HTPUT_TUNABLES) - if (HTPUT_TOTAL_FLOW_RINGS > 0) { - dhdp->htput_flow_ring_start = max_normal_tx_flow_rings + FLOWID_RESERVED; - /* Construct a htput flowid allocator from htput_flow_ring_start to - * (htput_flow_ring_start + HTPUT_TOTAL_FLOW_RINGS - 1) - */ - dhdp->htput_flowid_allocator = id16_map_init(dhdp->osh, HTPUT_TOTAL_FLOW_RINGS, - dhdp->htput_flow_ring_start); - if (dhdp->htput_flowid_allocator == NULL) { - DHD_ERROR(("%s: htput flowid allocator init failure\n", __FUNCTION__)); - return BCME_NOMEM; + dhdp->htput_flowid_allocator = NULL; + + if (dhdp->htput_support) { + if (HTPUT_TOTAL_FLOW_RINGS > 0) { + dhdp->htput_flow_ring_start = max_normal_tx_flow_rings + FLOWID_RESERVED; + /* Construct a htput flowid allocator from htput_flow_ring_start to + * (htput_flow_ring_start + HTPUT_TOTAL_FLOW_RINGS - 1) + */ + dhdp->htput_flowid_allocator = id16_map_init(dhdp->osh, + HTPUT_TOTAL_FLOW_RINGS, dhdp->htput_flow_ring_start); + if (dhdp->htput_flowid_allocator == NULL) { + DHD_ERROR(("%s: htput flowid allocator init failure\n", + __FUNCTION__)); + return BCME_NOMEM; + } + dhdp->htput_client_flow_rings = 0u; } - dhdp->htput_client_flow_rings = 0u; } -#endif /* !DHD_HTPUT_TUNABLES */ return BCME_OK; } @@ -404,14 +400,13 @@ dhd_flowid_map_deinit(dhd_pub_t *dhdp) } ASSERT(dhdp->flowid_allocator == NULL); -#if defined(DHD_HTPUT_TUNABLES) if (dhdp->htput_flowid_allocator) { dhdp->htput_flowid_allocator = id16_map_fini(dhdp->osh, dhdp->htput_flowid_allocator); ASSERT(dhdp->htput_flowid_allocator == NULL); } dhdp->htput_client_flow_rings = 0u; -#endif /* !DHD_HTPUT_TUNABLES */ + return; } @@ -508,7 +503,8 @@ dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_h2d_rings) bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); dhdp->max_multi_client_flow_rings = dhd_get_max_multi_client_flow_rings(dhdp); - dhdp->multi_client_flow_rings = 0U; + + OSL_ATOMIC_INIT(dhdp->osh, &dhdp->multi_client_flow_rings); #ifdef DHD_LOSSLESS_ROAMING dhdp->dequeue_prec_map = ALLPRIO; @@ -608,7 +604,8 @@ void dhd_flow_rings_deinit(dhd_pub_t *dhdp) bzero(dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); dhdp->max_multi_client_flow_rings = 0U; - dhdp->multi_client_flow_rings = 0U; + + OSL_ATOMIC_INIT(dhdp->osh, &dhdp->multi_client_flow_rings); lock = dhdp->flowid_lock; dhdp->flowid_lock = NULL; @@ -702,7 +699,8 @@ dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) } } else { - if (ETHER_ISMULTI(da)) { + if (ETHER_ISMULTI(da) && + TRUE) { ismcast = TRUE; hash = 0; } else { @@ -723,11 +721,7 @@ dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) } DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); -#ifdef DHD_EFI - DHD_TRACE(("%s: cannot find flowid\n", __FUNCTION__)); -#else - DHD_FLOWRING_INFO(("%s: cannot find flowid\n", __FUNCTION__)); -#endif + DHD_INFO(("%s: cannot find flowid\n", __FUNCTION__)); return FLOWID_INVALID; } /* dhd_flowid_find */ @@ -737,7 +731,13 @@ dhd_flowid_map_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *da) uint16 flowid = FLOWID_INVALID; ASSERT(dhdp->flowid_allocator != NULL); -#if defined(DHD_HTPUT_TUNABLES) + /* P2P Connections are always 80Mhz */ + if (DHD_IF_ROLE_P2PGC(dhdp, ifindex) || + DHD_IF_ROLE_P2PGO(dhdp, ifindex)) { + flowid = id16_map_alloc(dhdp->flowid_allocator); + return flowid; + } + if (dhdp->htput_flowid_allocator) { if (prio == HTPUT_FLOW_RING_PRIO) { if (DHD_IF_ROLE_GENERIC_STA(dhdp, ifindex)) { @@ -748,7 +748,8 @@ dhd_flowid_map_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *da) * will take care assigning same for those HTPUT_PRIO packets. */ flowid = id16_map_alloc(dhdp->htput_flowid_allocator); - } else if (DHD_IF_ROLE_MULTI_CLIENT(dhdp, ifindex) && !ETHER_ISMULTI(da)) { + } else if (DHD_IF_ROLE_MULTI_CLIENT(dhdp, ifindex) && !ETHER_ISMULTI(da) && + dhd_is_sta_htput(dhdp, ifindex, (uint8 *)da)) { /* Use HTPUT flowrings for only HTPUT_NUM_CLIENT_FLOW_RINGS */ if (dhdp->htput_client_flow_rings < HTPUT_NUM_CLIENT_FLOW_RINGS) { flowid = id16_map_alloc(dhdp->htput_flowid_allocator); @@ -760,7 +761,6 @@ dhd_flowid_map_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *da) } } } -#endif /* !DHD_HTPUT_TUNABLES */ BCM_REFERENCE(flowid); @@ -830,7 +830,9 @@ dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) } else { /* For bcast/mcast assign first slot in in interface */ - hash = ETHER_ISMULTI(da) ? 0 : DHD_FLOWRING_HASHINDEX(da, prio); + hash = (ETHER_ISMULTI(da) && + TRUE) ? 0 : DHD_FLOWRING_HASHINDEX(da, prio); + cur = if_flow_lkup[ifindex].fl_hash[hash]; if (cur) { while (cur->next) { @@ -842,7 +844,7 @@ dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) } DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - DHD_FLOWRING_INFO(("%s: allocated flowid %d\n", __FUNCTION__, fl_hash_node->flowid)); + DHD_INFO(("%s: allocated flowid %d\n", __FUNCTION__, fl_hash_node->flowid)); if (fl_hash_node->flowid > dhdp->max_tx_flowid) { DHD_ERROR(("%s: flowid=%d max_tx_flowid=%d ifindex=%d prio=%d role=%d\n", @@ -881,7 +883,7 @@ dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex, id = dhd_flowid_find(dhdp, ifindex, prio, sa, da); - if (id == FLOWID_INVALID) { + if (id == FLOWID_INVALID || (id > dhdp->max_tx_flowid)) { bool if_role_multi_client; if_flow_lkup_t *if_flow_lkup; if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; @@ -895,9 +897,11 @@ dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex, /* Abort Flowring creation if multi client flowrings crossed the threshold */ #ifdef DHD_LIMIT_MULTI_CLIENT_FLOWRINGS if (if_role_multi_client && - (dhdp->multi_client_flow_rings >= dhdp->max_multi_client_flow_rings)) { + (OSL_ATOMIC_READ(dhdp->osh, &dhdp->multi_client_flow_rings) >= + dhdp->max_multi_client_flow_rings)) { DHD_ERROR_RLMT(("%s: Max multi client flow rings reached: %d:%d\n", - __FUNCTION__, dhdp->multi_client_flow_rings, + __FUNCTION__, + OSL_ATOMIC_READ(dhdp->osh, &dhdp->multi_client_flow_rings), dhdp->max_multi_client_flow_rings)); return BCME_ERROR; } @@ -923,7 +927,7 @@ dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex, /* Only after flowid alloc, increment multi_client_flow_rings */ if (if_role_multi_client) { - dhdp->multi_client_flow_rings++; + OSL_ATOMIC_INC(dhdp->osh, &dhdp->multi_client_flow_rings); } /* register this flowid in dhd_pub */ @@ -1095,7 +1099,7 @@ BCMFASTPATH(dhd_flowid_update)(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, void return BCME_ERROR; } - DHD_FLOWRING_INFO(("%s: prio %d flowid %d\n", __FUNCTION__, prio, flowid)); + DHD_INFO(("%s: prio %d flowid %d\n", __FUNCTION__, prio, flowid)); /* Tag the packet with flowid */ DHD_PKT_SET_FLOWID(pktbuf, flowid); @@ -1105,7 +1109,6 @@ BCMFASTPATH(dhd_flowid_update)(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, void static void dhd_flowid_map_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid) { -#if defined(DHD_HTPUT_TUNABLES) if (dhdp->htput_flowid_allocator) { if (DHD_IS_FLOWID_HTPUT(dhdp, flowid)) { id16_map_free(dhdp->htput_flowid_allocator, flowid); @@ -1116,7 +1119,6 @@ dhd_flowid_map_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid) return; } } -#endif /* !DHD_HTPUT_TUNABLES */ id16_map_free(dhdp->flowid_allocator, flowid); @@ -1169,15 +1171,19 @@ dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid) /* Decrement multi_client_flow_rings */ if (if_role_multi_client) { - dhdp->multi_client_flow_rings--; + if (OSL_ATOMIC_READ(dhdp->osh, + &dhdp->multi_client_flow_rings)) { + OSL_ATOMIC_DEC(dhdp->osh, + &dhdp->multi_client_flow_rings); + } } /* deregister flowid from dhd_pub. */ dhd_del_flowid(dhdp, ifindex, flowid); dhd_flowid_map_free(dhdp, ifindex, flowid); - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); MFREE(dhdp->osh, cur, sizeof(flow_hash_info_t)); + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); return; } @@ -1219,6 +1225,50 @@ dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex) } } +void +dhd_update_multicilent_flow_rings(dhd_pub_t *dhdp, uint8 ifindex, bool increment) +{ + uint32 id; + flow_ring_table_t *flow_ring_table; + + DHD_ERROR(("%s: ifindex %u\n", __FUNCTION__, ifindex)); + + ASSERT(ifindex < DHD_MAX_IFS); + if (ifindex >= DHD_MAX_IFS) + return; + + if (!dhdp->flow_ring_table) + return; + + flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; + for (id = 0; id < dhdp->num_h2d_rings; id++) { + if (flow_ring_table[id].active && + (flow_ring_table[id].flow_info.ifindex == ifindex) && + (flow_ring_table[id].status == FLOW_RING_STATUS_OPEN)) { + if (increment) { + if (OSL_ATOMIC_READ(dhdp->osh, &dhdp->multi_client_flow_rings) < + dhdp->max_multi_client_flow_rings) { + OSL_ATOMIC_INC(dhdp->osh, &dhdp->multi_client_flow_rings); + } else { + DHD_ERROR(("%s: multi_client_flow_rings:%u" + " reached max:%d\n", __FUNCTION__, + OSL_ATOMIC_READ(dhdp->osh, + &dhdp->multi_client_flow_rings), + dhdp->max_multi_client_flow_rings)); + } + } else { + if (OSL_ATOMIC_READ(dhdp->osh, &dhdp->multi_client_flow_rings)) { + OSL_ATOMIC_DEC(dhdp->osh, &dhdp->multi_client_flow_rings); + } else { + DHD_ERROR(("%s: multi_client_flow_rings:%u" + " reached ZERO\n", __FUNCTION__, + OSL_ATOMIC_READ(dhdp->osh, + &dhdp->multi_client_flow_rings))); + } + } + } + } +} void dhd_flow_rings_flush(dhd_pub_t *dhdp, uint8 ifindex) { @@ -1252,7 +1302,7 @@ dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, char *addr) uint32 id; flow_ring_table_t *flow_ring_table; - DHD_ERROR(("%s: ifindex %u\n", __FUNCTION__, ifindex)); + DHD_INFO(("%s: ifindex %u\n", __FUNCTION__, ifindex)); ASSERT(ifindex < DHD_MAX_IFS); if (ifindex >= DHD_MAX_IFS) @@ -1277,7 +1327,7 @@ dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, char *addr) (!memcmp(flow_ring_table[id].flow_info.da, addr, ETHER_ADDR_LEN)) && ((flow_ring_table[id].status == FLOW_RING_STATUS_OPEN) || (flow_ring_table[id].status == FLOW_RING_STATUS_CREATE_PENDING))) { - DHD_ERROR(("%s: deleting flowid %d\n", + DHD_INFO(("%s: deleting flowid %d\n", __FUNCTION__, flow_ring_table[id].flowid)); dhd_bus_flow_ring_delete_request(dhdp->bus, (void *) &flow_ring_table[id]); @@ -1308,8 +1358,15 @@ dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex, if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; if (op == WLC_E_IF_ADD || op == WLC_E_IF_CHANGE) { - + DHD_ERROR(("%s: ifindex:%d previous role:%d new role:%d\n", + __FUNCTION__, ifindex, if_flow_lkup[ifindex].role, role)); if_flow_lkup[ifindex].role = role; +#ifdef PCIE_FULL_DONGLE + if (op == WLC_E_IF_CHANGE) { + bool increment = DHD_IF_ROLE_MULTI_CLIENT(dhdp, ifindex); + dhd_update_multicilent_flow_rings(dhdp, ifindex, increment); + } +#endif /* PCIE_FULL_DONGLE */ if (role == WLC_E_IF_ROLE_WDS) { /** @@ -1452,48 +1509,3 @@ dhd_active_tx_flowring_bkpq_len(dhd_pub_t *dhd) DHD_FLOWRING_LIST_UNLOCK(bus->dhd->flowring_list_lock, list_lock_flags); return active_tx_flowring_qlen; } - -#ifdef DHD_AWDL -/** - * Handle/Intercept awdl peer op IOVAR fired by user - * buf = NULL means delete all peers in awdl interface - */ -void -dhd_awdl_peer_op(dhd_pub_t *dhdp, uint8 ifindex, void *buf, uint32 buflen) -{ - awdl_peer_op_t *peer = (awdl_peer_op_t *)buf; - DHD_TRACE(("%s\n", __FUNCTION__)); - - ASSERT(ifindex < DHD_MAX_IFS); - if (ifindex >= DHD_MAX_IFS) - return; - if (!buf) { - /* Delete all peers in awdl interface */ - if_flow_lkup_t *if_flow_lkup; - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - if (if_flow_lkup[ifindex].role != WLC_E_IF_ROLE_AWDL) { - DHD_ERROR(("%s: Iinterface %d is not a awdl peer \n", - __FUNCTION__, ifindex)); - return; - } - dhd_flow_rings_delete(dhdp, ifindex); - return; - } - /* Parse awdl_peer_op info now */ - if (buflen < sizeof(awdl_peer_op_t)) { - DHD_ERROR(("%s: cannot handle awdl_peer_op add/del\n", __FUNCTION__)); - return; - } - /** - * Only flowring deletion is handled here - * Flowring addition is taken care in dhd_flowid_lookup - */ - if (peer->opcode == AWDL_PEER_OP_DEL) { - dhd_del_sta(dhdp, ifindex, &peer->addr.octet[0]); - dhd_flow_rings_delete_for_peer(dhdp, ifindex, (char *)&peer->addr.octet[0]); - } else if (peer->opcode == AWDL_PEER_OP_ADD) { - dhd_findadd_sta(dhdp, ifindex, &peer->addr.octet[0]); - } - return; -} -#endif /* DHD_AWDL */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_flowring.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_flowring.h old mode 100755 new mode 100644 index 404ea4c0e370..1b1d1d0d20b9 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_flowring.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_flowring.h @@ -6,7 +6,7 @@ * Provides type definitions and function prototypes used to create, delete and manage flow rings at * high level. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -58,47 +58,19 @@ #endif /* IDLE_TX_FLOW_MGMT */ #define FLOW_RING_STATUS_STA_FREEING 7 -#if defined(DHD_HTPUT_TUNABLES) #define HTPUT_FLOW_RING_PRIO PRIO_8021D_BE #define HTPUT_NUM_STA_FLOW_RINGS 1u #define HTPUT_NUM_CLIENT_FLOW_RINGS 3u #define HTPUT_TOTAL_FLOW_RINGS (HTPUT_NUM_STA_FLOW_RINGS + HTPUT_NUM_CLIENT_FLOW_RINGS) #define DHD_IS_FLOWID_HTPUT(pub, flowid) \ - ((flowid >= (pub)->htput_flow_ring_start) && \ - (flowid < ((pub)->htput_flow_ring_start + HTPUT_TOTAL_FLOW_RINGS))) -#endif /* DHD_HTPUT_TUNABLES */ + ((pub)->htput_support && (flowid >= (pub)->htput_flow_ring_start) && \ + ((uint16)flowid < ((pub)->htput_flow_ring_start + HTPUT_TOTAL_FLOW_RINGS))) + +#if defined(FLOW_RING_PREALLOC) +#define MAX_FLOW_RINGS 64 +#endif /* FLOW_RING_PREALLOC */ -#ifdef DHD_EFI -/* - * Each lbuf is of size 2048 bytes. But the last 112 bytes is occupied for lbuf header. - * Since lbuf is crucial data structure we want to avoid operations very close to lbuf. - * so providing a pad of 136 bytes. so lbuf and pad together is 248 bytes. - * - * So the maximum usable lbuf size is 1800 bytes. - * - * These 1800 bytes is utilized for below purposes. - * - * 1. FW operating in mode2 requires 98 bytes for extra headers - * like SNAP, PLCP etc. Whereas FW operating in mode4 requires 70 bytes. - * So in EFI DHD we will consider 98 bytes which fits for chips operating in both mode2 and mode4. - * - * 2. For TPUT tests in EFI user can request a maximum payload of 1500 bytes. - * To add ethernet header and TPUT header etc we are reserving 100bytes. So 1600 bytes are utilized - * for headers and payload. - * - * so 1698(98 + 1600) bytes by are consumed by 1 and 2. - * So we still have 112 bytes which can be utilized - * if FW needs buffer for more headers in future. - * - * --Update-- 13Jul2018 (above comments preserved for history) - * 3. In case of 11ax chips more headroom is required, FW requires a min. of 1920 bytes for Rx - * buffers, or it will trap. Therefore bumping up the size to 1920 bytes. Which leaves - * only 16 bytes pad between data and lbuf header ! Further size increase may not be possible !! - */ -#define DHD_FLOWRING_RX_BUFPOST_PKTSZ 1920 -#else #define DHD_FLOWRING_RX_BUFPOST_PKTSZ 2048 -#endif /* DHD_EFI */ #define DHD_FLOWRING_RX_BUFPOST_PKTSZ_MAX 4096 @@ -127,16 +99,9 @@ #define DHD_IF_ROLE_GENERIC_STA(pub, idx) \ (DHD_IF_ROLE_STA(pub, idx) || DHD_IF_ROLE_P2PGC(pub, idx) || DHD_IF_ROLE_WDS(pub, idx)) -#ifdef DHD_AWDL -#define DHD_IF_ROLE_AWDL(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_AWDL) -#define DHD_IF_ROLE_MULTI_CLIENT(pub, idx) \ - (DHD_IF_ROLE_AP(pub, idx) || DHD_IF_ROLE_P2PGO(pub, idx) || DHD_IF_ROLE_AWDL(pub, idx) ||\ - DHD_IF_ROLE_NAN(pub, idx)) -#else #define DHD_IF_ROLE_MULTI_CLIENT(pub, idx) \ (DHD_IF_ROLE_AP(pub, idx) || DHD_IF_ROLE_P2PGO(pub, idx) ||\ DHD_IF_ROLE_NAN(pub, idx)) -#endif /* DHD_AWDL */ #define DHD_FLOW_RING(dhdp, flowid) \ (flow_ring_node_t *)&(((flow_ring_node_t *)((dhdp)->flow_ring_table))[flowid]) @@ -272,9 +237,6 @@ typedef struct flow_ring_node { /* counter to decide if this particlur flow is stuck or not */ uint32 stuck_count; #endif /* DEVICE_TX_STUCK_DETECT */ -#ifdef DHD_HP2P - bool hp2p_ring; -#endif /* DHD_HP2P */ } flow_ring_node_t; typedef flow_ring_node_t flow_ring_table_t; @@ -327,6 +289,8 @@ extern int dhd_flowid_find_by_ifidx(dhd_pub_t *dhdp, uint8 ifidex, uint16 flowid extern void dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid); extern void dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex); +extern void dhd_update_multicilent_flow_rings(dhd_pub_t *dhdp, uint8 ifindex, + bool increment); extern void dhd_flow_rings_flush(dhd_pub_t *dhdp, uint8 ifindex); extern void dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, @@ -342,10 +306,5 @@ extern int dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex, extern int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set); extern int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map); extern uint32 dhd_active_tx_flowring_bkpq_len(dhd_pub_t *dhdp); -#ifdef DHD_AWDL -/* DHD handler for awdl peer op IOVAR */ -extern void dhd_awdl_peer_op(dhd_pub_t *dhdp, uint8 ifindex, - void *buf, uint32 buflen); -#endif /* DHD_AWDL */ extern uint8 dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex); #endif /* _dhd_flowrings_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_fwtrace.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_fwtrace.c deleted file mode 100755 index 4737b43bfa00..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_fwtrace.c +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Firmware trace handling on the DHD side. Kernel thread reads the trace data and writes - * to the file and implements various utility functions. - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - * - * $Id$ - */ - -#ifdef BCMINTERNAL - -#ifdef DHD_FWTRACE - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include - -static int fwtrace_write_to_file(uint8 *buf, uint16 buf_len, dhd_pub_t *dhdp); -static int fwtrace_close_file(dhd_pub_t *dhdp); -static int fwtrace_open_file(uint32 fw_trace_enabled, dhd_pub_t *dhdp); -static fwtrace_buf_t *fwtrace_get_trace_data_ptr(dhd_pub_t *dhdp); -static void fwtrace_free_trace_buf(dhd_pub_t *dhdp); - -typedef struct fwtrace_info { - struct file *fw_trace_fp; - int file_index; - int part_index; - int trace_buf_index; - int trace_buf_count; - uint16 overflow_counter; - - char trace_file[TRACE_FILE_NAME_LEN]; - - fwtrace_buf_t *trace_data_ptr; - - uint16 prev_seq; - - uint32 fwtrace_enable; /* Enable firmware tracing and the - * trace file management. - */ - struct mutex fwtrace_lock; /* Synchronization between the - * ioctl and the kernel thread. - */ - dhd_dma_buf_t fwtrace_buf; /* firmware trace buffer */ -} fwtrace_info_t; - -int -dhd_fwtrace_attach(dhd_pub_t *dhdp) -{ - fwtrace_info_t *fwtrace_info; - - /* Allocate prot structure */ - if (!(fwtrace_info = (fwtrace_info_t *)VMALLOCZ(dhdp->osh, sizeof(*fwtrace_info)))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - return (BCME_NOMEM); - } - - bzero(fwtrace_info, sizeof(*fwtrace_info)); - dhdp->fwtrace_info = fwtrace_info; - - mutex_init(&dhdp->fwtrace_info->fwtrace_lock); - - DHD_INFO(("allocated DHD fwtrace\n")); - - return BCME_OK; -} - -int -dhd_fwtrace_detach(dhd_pub_t *dhdp) -{ - fwtrace_info_t *fwtrace_info; - - DHD_TRACE(("%s: %d\n", __FUNCTION__, __LINE__)); - - if (!dhdp) { - return BCME_OK; - } - - if (!dhdp->fwtrace_info) { - return BCME_OK; - } - - fwtrace_info = dhdp->fwtrace_info; - - dhd_dma_buf_free(dhdp, &dhdp->fwtrace_info->fwtrace_buf); - - /* close the file if valid */ - if (!(IS_ERR_OR_NULL(dhdp->fwtrace_info->fw_trace_fp))) { - (void) filp_close(dhdp->fwtrace_info->fw_trace_fp, 0); - } - - mutex_destroy(&dhdp->fwtrace_info->fwtrace_lock); - - VMFREE(dhdp->osh, fwtrace_info, sizeof(*fwtrace_info)); - - dhdp->fwtrace_info = NULL; - - DHD_INFO(("Deallocated DHD fwtrace_info\n")); - - return (BCME_OK); -} - -uint16 -get_fw_trace_overflow_counter(dhd_pub_t *dhdp) -{ - return (dhdp->fwtrace_info->overflow_counter); -} - -void -process_fw_trace_data(dhd_pub_t *dhdp) -{ - fwtrace_info_t *fwtrace_info = dhdp->fwtrace_info; - uint16 length; - uint16 incoming_seq; - uint32 trace_buf_index = fwtrace_info->trace_buf_index; - fwtrace_buf_t * trace_buf; - fwtrace_buf_t * curr_buf; - - mutex_lock(&fwtrace_info->fwtrace_lock); - - if (fwtrace_info->fw_trace_fp == NULL) { - goto done; - } - - if ((trace_buf = fwtrace_get_trace_data_ptr(dhdp)) == NULL) { - goto done; - } - - do { - curr_buf = trace_buf + trace_buf_index; - - length = curr_buf->info.length; - /* If the incoming length is 0, means nothing is updated by the firmware */ - if (length == 0) { - break; - } - - incoming_seq = curr_buf->info.seq_num; - - if (((uint16)(fwtrace_info->prev_seq + 1) != incoming_seq) && - length != sizeof(*curr_buf)) { - DHD_ERROR(("*** invalid trace len idx = %u, length = %u, " - "cur seq = %u, in-seq = %u \n", - trace_buf_index, length, - fwtrace_info->prev_seq, incoming_seq)); - break; - } - - DHD_TRACE(("*** TRACE BUS: IDX:%d, in-seq:%d(prev-%d), ptr:%p(%llu), len:%d\n", - trace_buf_index, incoming_seq, fwtrace_info->prev_seq, - curr_buf, (uint64)curr_buf, length)); - - /* Write trace data to a file */ - if (fwtrace_write_to_file((uint8 *) curr_buf, length, dhdp) != BCME_OK) { - DHD_ERROR(("*** fwtrace_write_to_file has failed \n")); - break; - } - - /* Reset length after consuming the fwtrace data */ - curr_buf->info.length = 0; - - if ((fwtrace_info->prev_seq + 1) != incoming_seq) { - DHD_ERROR(("*** seq mismatch, index = %u, length = %u, " - "cur seq = %u, in-seq = %u \n", - trace_buf_index, length, - fwtrace_info->prev_seq, incoming_seq)); - } - fwtrace_info->prev_seq = incoming_seq; - - trace_buf_index++; - trace_buf_index &= (fwtrace_info->trace_buf_count - 1u); - fwtrace_info->trace_buf_index = trace_buf_index; - } while (true); - -done: - mutex_unlock(&fwtrace_info->fwtrace_lock); - return; -} - -/* - * Write the incoming trace data to a file. The maximum file size is 1MB. After that - * the trace data is saved into a new file. - */ -static int -fwtrace_write_to_file(uint8 *buf, uint16 buf_len, dhd_pub_t *dhdp) -{ - fwtrace_info_t *fwtrace_info = dhdp->fwtrace_info; - int ret_val = BCME_OK; - int ret_val_1 = 0; - mm_segment_t old_fs; - loff_t pos = 0; - struct kstat stat; - int error; - - /* Change to KERNEL_DS address limit */ - old_fs = get_fs(); - set_fs(KERNEL_DS); - - if (buf == NULL) { - ret_val = BCME_ERROR; - goto done; - } - - if (IS_ERR_OR_NULL(fwtrace_info->fw_trace_fp)) { - ret_val = BCME_ERROR; - goto done; - } - - // - // Get the file size - // if the size + buf_len > TRACE_FILE_SIZE, then write to a different file. - // - error = vfs_stat(fwtrace_info->trace_file, &stat); - if (error) { - DHD_ERROR(("vfs_stat has failed with error code = %d\n", error)); - goto done; - } - - if ((int) stat.size + buf_len > TRACE_FILE_SIZE) { - fwtrace_close_file(dhdp); - (fwtrace_info->part_index)++; - fwtrace_open_file(TRUE, dhdp); - } - - pos = fwtrace_info->fw_trace_fp->f_pos; - /* Write buf to file */ - ret_val_1 = vfs_write(fwtrace_info->fw_trace_fp, - (char *) buf, (uint32) buf_len, &pos); - if (ret_val_1 < 0) { - DHD_ERROR(("write file error, err = %d\n", ret_val_1)); - ret_val = BCME_ERROR; - goto done; - } - fwtrace_info->fw_trace_fp->f_pos = pos; - - /* Sync file from filesystem to physical media */ - ret_val_1 = vfs_fsync(fwtrace_info->fw_trace_fp, 0); - if (ret_val_1 < 0) { - DHD_ERROR(("sync file error, error = %d\n", ret_val_1)); - ret_val = BCME_ERROR; - goto done; - } - -done: - /* restore previous address limit */ - set_fs(old_fs); - return (ret_val); -} - -/* - * Start the trace, gets called from the ioctl handler. - */ -int -fw_trace_start(dhd_pub_t *dhdp, uint32 fw_trace_enabled) -{ - int ret_val = BCME_OK; - - (dhdp->fwtrace_info->file_index)++; - dhdp->fwtrace_info->part_index = 1; - - dhdp->fwtrace_info->trace_buf_index = 0; - - mutex_lock(&dhdp->fwtrace_info->fwtrace_lock); - ret_val = fwtrace_open_file(fw_trace_enabled, dhdp); - if (ret_val == BCME_OK) { - dhdp->fwtrace_info->fwtrace_enable = fw_trace_enabled; - } - mutex_unlock(&dhdp->fwtrace_info->fwtrace_lock); - - return (ret_val); -} - -/* - * Stop the trace collection and close the file descriptor. - */ -int -fw_trace_stop(dhd_pub_t *dhdp) -{ - int ret_val = BCME_OK; - - /* Check to see if there is any trace data */ - process_fw_trace_data(dhdp); - - mutex_lock(&dhdp->fwtrace_info->fwtrace_lock); /* acquire lock */ - /* flush the trace buffer */ - ret_val = fwtrace_close_file(dhdp); - - /* free the trace buffer */ - fwtrace_free_trace_buf(dhdp); - mutex_unlock(&dhdp->fwtrace_info->fwtrace_lock); /* release the lock */ - - return (ret_val); -} - -/* - * The trace file format is: fw_trace_w_part_x_y_z - * where w is the file index, x is the part index, - * y is in seconds and z is in milliseconds - * - * fw_trace_1_part_1_1539298163209110 - * fw_trace_1_part_2_1539298194739003 etc. - * - */ -static int -fwtrace_open_file(uint32 fw_trace_enabled, dhd_pub_t *dhdp) -{ - fwtrace_info_t *fwtrace_info = dhdp->fwtrace_info; - int ret_val = BCME_OK; - uint32 file_mode; - char ts_str[DEBUG_DUMP_TIME_BUF_LEN]; - - if (fw_trace_enabled) { - if (!(IS_ERR_OR_NULL(fwtrace_info->fw_trace_fp))) { - (void) filp_close(fwtrace_info->fw_trace_fp, 0); - } - - DHD_INFO((" *** Creating the trace file \n")); - - file_mode = O_CREAT | O_WRONLY | O_SYNC; - clear_debug_dump_time(ts_str); - get_debug_dump_time(ts_str); - - snprintf(fwtrace_info->trace_file, - sizeof(fwtrace_info->trace_file), - "%sfw_trace_%d_part_%d_%x_%s", - DHD_COMMON_DUMP_PATH, fwtrace_info->file_index, - fwtrace_info->part_index, - dhd_bus_get_bp_base(dhdp), - ts_str); - - fwtrace_info->fw_trace_fp = - filp_open(fwtrace_info->trace_file, file_mode, 0664); - - if (IS_ERR(fwtrace_info->fw_trace_fp)) { - DHD_ERROR(("Unable to create the fw trace file file: %s\n", - fwtrace_info->trace_file)); - ret_val = BCME_ERROR; - goto done; - } - } - -done: - return (ret_val); -} - -static int -fwtrace_close_file(dhd_pub_t *dhdp) -{ - int ret_val = BCME_OK; - - if (!(IS_ERR_OR_NULL(dhdp->fwtrace_info->fw_trace_fp))) { - (void) filp_close(dhdp->fwtrace_info->fw_trace_fp, 0); - } - - dhdp->fwtrace_info->fw_trace_fp = NULL; - - return (ret_val); -} - -#define FWTRACE_HADDR_PARAMS_SIZE 256u -#define FW_TRACE_FLUSH 0x8u /* bit 3 */ - -static int send_fw_trace_val(dhd_pub_t *dhdp, int val); - -/* - * Initialize FWTRACE. - * Allocate trace buffer and open trace file. - */ -int -fwtrace_init(dhd_pub_t *dhdp) -{ - int ret_val = BCME_OK; - fwtrace_hostaddr_info_t host_buf_info; - - if (dhdp->fwtrace_info->fwtrace_buf.va != NULL) { - /* Already initialized */ - goto done; - } - - ret_val = fwtrace_get_haddr(dhdp, &host_buf_info); - - if (ret_val != BCME_OK) { - goto done; - } - - DHD_INFO(("dhd_get_trace_haddr: addr = %llx, len = %u\n", - host_buf_info.haddr.u64, host_buf_info.num_bufs)); - - /* Initialize and setup the file */ - ret_val = fw_trace_start(dhdp, TRUE); - -done: - return ret_val; -} - -/* - * Process the fwtrace set command to enable/disable firmware tracing. - * Always, enable preceeds with disable. - */ -int -handle_set_fwtrace(dhd_pub_t *dhdp, uint32 val) -{ - int ret, ret_val = BCME_OK; - - /* On set, consider only lower two bytes for now */ - dhdp->fwtrace_info->fwtrace_enable = (val & 0xFFFF); - - if (val & FW_TRACE_FLUSH) { /* only flush the trace buffer */ - if ((ret_val = send_fw_trace_val(dhdp, val)) != BCME_OK) { - goto done; - } - } else if (val == 0) { /* disable the tracing */ - /* Disable the trace in the firmware */ - if ((ret_val = send_fw_trace_val(dhdp, val)) != BCME_OK) { - goto done; - } - - /* cleanup in the driver */ - fw_trace_stop(dhdp); - } else { /* enable the tracing */ - fwtrace_hostaddr_info_t haddr_info; - - ret_val = fwtrace_init(dhdp); - if (ret_val != BCME_OK) { - goto done; - } - - if ((ret_val = fwtrace_get_haddr(dhdp, &haddr_info)) != BCME_OK) { - DHD_ERROR(("%s: set dhd_iovar has failed for " - "fw_trace_haddr, " - "ret=%d\n", __FUNCTION__, ret_val)); - goto done; - } - - ret = dhd_iovar(dhdp, 0, "dngl:fwtrace_haddr", - (char *) &haddr_info, sizeof(haddr_info), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: set dhd_iovar has failed for " - "fwtrace_haddr, " - "ret=%d\n", __FUNCTION__, ret)); - ret_val = BCME_NOMEM; - goto done; - } - - /* Finaly, enable the trace in the firmware */ - if ((ret_val = send_fw_trace_val(dhdp, val)) != BCME_OK) { - goto done; - } - } -done: - return (ret_val); -} - -/* - * Send dngl:fwtrace IOVAR to the firmware. - */ - -static int -send_fw_trace_val(dhd_pub_t *dhdp, int val) -{ - int ret_val = BCME_OK; - - if ((ret_val = dhd_iovar(dhdp, 0, "dngl:fwtrace", (char *)&val, sizeof(val), - NULL, 0, TRUE)) < 0) { - DHD_ERROR(("%s: set dhd_iovar has failed fwtrace, " - "ret=%d\n", __FUNCTION__, ret_val)); - } - - return (ret_val); -} - -/* - * Returns the virual address for the firmware trace buffer. - * DHD monitors this buffer for an update from the firmware. - */ -static fwtrace_buf_t * -fwtrace_get_trace_data_ptr(dhd_pub_t *dhdp) -{ - return ((fwtrace_buf_t *) dhdp->fwtrace_info->fwtrace_buf.va); -} - -int -fwtrace_get_haddr(dhd_pub_t *dhdp, fwtrace_hostaddr_info_t *haddr_info) -{ - int ret_val = BCME_NOMEM; - int num_host_buffers = FWTRACE_NUM_HOST_BUFFERS; - - if (haddr_info == NULL) { - ret_val = BCME_BADARG; - goto done; - } - - if (dhdp->fwtrace_info->fwtrace_buf.va != NULL) { - /* Use the existing buffer and send to the firmware */ - haddr_info->haddr.u64 = HTOL64(*(uint64 *) - &dhdp->fwtrace_info->fwtrace_buf.pa); - haddr_info->num_bufs = dhdp->fwtrace_info->trace_buf_count; - haddr_info->buf_len = sizeof(fwtrace_buf_t); - ret_val = BCME_OK; - goto done; - } - - do { - /* Initialize firmware trace buffer */ - if (dhd_dma_buf_alloc(dhdp, &dhdp->fwtrace_info->fwtrace_buf, - sizeof(fwtrace_buf_t) * num_host_buffers) == BCME_OK) { - dhdp->fwtrace_info->trace_buf_count = num_host_buffers; - ret_val = BCME_OK; - break; - } - - DHD_ERROR(("%s: Allocing %d buffers of size %lu bytes failed\n", - __FUNCTION__, num_host_buffers, - sizeof(fwtrace_buf_t) * num_host_buffers)); - - /* Retry with smaller numbers */ - num_host_buffers >>= 1; - } while (num_host_buffers > 0); - - haddr_info->haddr.u64 = HTOL64(*(uint64 *)&dhdp->fwtrace_info->fwtrace_buf.pa); - haddr_info->num_bufs = num_host_buffers; - haddr_info->buf_len = sizeof(fwtrace_buf_t); - - DHD_INFO(("Firmware trace buffer, host address = %llx, count = %u \n", - haddr_info->haddr.u64, - haddr_info->num_bufs)); -done: - return (ret_val); -} - -/* - * Frees the host buffer. - */ -static void -fwtrace_free_trace_buf(dhd_pub_t *dhdp) -{ - dhd_dma_buf_free(dhdp, &dhdp->fwtrace_info->fwtrace_buf); - return; -} - -#endif /* DHD_FWTRACE */ - -#endif /* BCMINTERNAL */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_fwtrace.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_fwtrace.h deleted file mode 100755 index 4e977bfb0467..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_fwtrace.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Data structures required for the firmware tracing support on Linux. - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - * - * $Id$ - */ - -#ifndef _DHD_FWTRACE_H -#define _DHD_FWTRACE_H - -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE /* firmware tracing */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#define TRACE_FILE_NAME_LEN 128u /* bytes */ -#define TRACE_FILE_SIZE (1024u * 1024u) /* Trace file size is 1 MB */ - -/* Prototypes */ -void dhd_event_logtrace_enqueue_fwtrace(dhd_pub_t *dhdp); -int dhd_fwtrace_attach(dhd_pub_t *dhdinfo); -int dhd_fwtrace_detach(dhd_pub_t *dhdinfo); - -void process_fw_trace_data(dhd_pub_t *dhdp); -uint32 dhd_bus_get_bp_base(dhd_pub_t *dhdp); -int fwtrace_init(dhd_pub_t *dhdp); -int fw_trace_start(dhd_pub_t *dhdp, uint32 fw_trace_enabled); -int fw_trace_stop(dhd_pub_t *dhdp); -int handle_set_fwtrace(dhd_pub_t *dhdp, uint32 val); -uint16 get_fw_trace_overflow_counter(dhd_pub_t *dhdp); -int fwtrace_get_haddr(dhd_pub_t *dhdp, fwtrace_hostaddr_info_t *haddr_info); - -#endif /* DHD_FWTRACE */ - -#endif /* BCMINTERNAL */ - -#endif /* _DHD_FWTRACE_H */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c old mode 100755 new mode 100644 index 05b735fcdf3e..05984a978a69 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c @@ -1,24 +1,19 @@ -/* SPDX-License-Identifier: GPL-2.0 */ + #include #include #include +#ifdef BCMDHD_DTS +#include +#endif +#ifdef BCMDHD_PLATDEV +#include +#endif #ifdef CUSTOMER_HW_ROCKCHIP #include #endif -#if defined(BUS_POWER_RESTORE) && defined(BCMSDIO) -#include -#include -#include -#include -#endif /* defined(BUS_POWER_RESTORE) && defined(BCMSDIO) */ - #ifdef CONFIG_DHD_USE_STATIC_BUF -#ifdef DHD_STATIC_IN_DRIVER -extern int dhd_static_buf_init(void); -extern void dhd_static_buf_exit(void); -#endif /* DHD_STATIC_IN_DRIVER */ -#ifdef BCMDHD_MDRIVER +#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER) extern void *dhd_wlan_mem_prealloc(uint bus_type, int index, int section, unsigned long size); #else @@ -33,7 +28,7 @@ extern void *dhd_wlan_mem_prealloc(int section, unsigned long size); #ifdef BCMDHD_DTS /* This is sample code in dts file. -bcmdhd { +bcmdhd_wlan { compatible = "android,bcmdhd_wlan"; gpio_wl_reg_on = <&gpio GPIOH_4 GPIO_ACTIVE_HIGH>; gpio_wl_host_wake = <&gpio GPIOZ_15 GPIO_ACTIVE_HIGH>; @@ -62,19 +57,11 @@ dhd_wlan_set_power(int on, wifi_adapter_info_t *adapter) #ifdef CUSTOMER_HW_ROCKCHIP rockchip_wifi_power(1); #ifdef BCMPCIE - //rk_pcie_power_on_atu_fixup(); +// rk_pcie_power_on_atu_fixup(); #endif #endif #ifdef BUS_POWER_RESTORE -#ifdef BCMSDIO -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) - if (adapter->sdio_func && adapter->sdio_func->card && adapter->sdio_func->card->host) { - mdelay(100); - printf("======== mmc_power_restore_host! ========\n"); - mmc_power_restore_host(adapter->sdio_func->card->host); - } -#endif -#elif defined(BCMPCIE) +#ifdef BCMPCIE if (adapter->pci_dev) { mdelay(100); printf("======== pci_set_power_state PCI_D0! ========\n"); @@ -90,17 +77,9 @@ dhd_wlan_set_power(int on, wifi_adapter_info_t *adapter) #endif /* BCMPCIE */ #endif /* BUS_POWER_RESTORE */ /* Lets customer power to get stable */ - mdelay(100); } else { #ifdef BUS_POWER_RESTORE -#ifdef BCMSDIO -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) - if (adapter->sdio_func && adapter->sdio_func->card && adapter->sdio_func->card->host) { - printf("======== mmc_power_save_host! ========\n"); - mmc_power_save_host(adapter->sdio_func->card->host); - } -#endif -#elif defined(BCMPCIE) +#ifdef BCMPCIE if (adapter->pci_dev) { printf("======== pci_set_power_state PCI_D3hot! ========\n"); pci_save_state(adapter->pci_dev); @@ -127,16 +106,17 @@ dhd_wlan_set_power(int on, wifi_adapter_info_t *adapter) return err; } -static int dhd_wlan_set_reset(int onoff) +static int +dhd_wlan_set_reset(int onoff) { return 0; } -static int dhd_wlan_set_carddetect(int present) +static int +dhd_wlan_set_carddetect(int present) { int err = 0; -#if !defined(BUS_POWER_RESTORE) if (present) { #if defined(BCMSDIO) printf("======== Card detection to detect SDIO card! ========\n"); @@ -156,20 +136,20 @@ static int dhd_wlan_set_carddetect(int present) err = sdhci_force_presence_change(&sdmmc_channel, 0); #endif /* CUSTOMER_HW_PLATFORM */ #ifdef CUSTOMER_HW_ROCKCHIP - rockchip_wifi_set_carddetect(0); + rockchip_wifi_set_carddetect(0); #endif #elif defined(BCMPCIE) printf("======== Card detection to remove PCIE card! ========\n"); #endif } -#endif /* BUS_POWER_RESTORE */ return err; } -static int dhd_wlan_get_mac_addr(unsigned char *buf, int ifidx) +static int +dhd_wlan_get_mac_addr(unsigned char *buf, int ifidx) { - int err = 0; + int err = -1; if (ifidx == 1) { #ifdef EXAMPLE_GET_MAC @@ -265,16 +245,17 @@ struct wifi_platform_data dhd_wlan_control = { .get_country_code = dhd_wlan_get_country_code, }; -int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter) +static int +dhd_wlan_init_gpio(wifi_adapter_info_t *adapter) { #ifdef BCMDHD_DTS char wlan_node[32]; struct device_node *root_node = NULL; #endif int err = 0; - int gpio_wl_reg_on; + int gpio_wl_reg_on = -1; #ifdef CUSTOMER_OOB - int gpio_wl_host_wake; + int gpio_wl_host_wake = -1; int host_oob_irq = -1; uint host_oob_irq_flags = 0; #ifdef CUSTOMER_HW_ROCKCHIP @@ -288,9 +269,19 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter) * WL_REG_ON and WL_HOST_WAKE. */ #ifdef BCMDHD_DTS +#ifdef BCMDHD_PLATDEV + if (adapter->pdev) { + root_node = adapter->pdev->dev.of_node; + strcpy(wlan_node, root_node->name); + } else { + printf("%s: adapter->pdev is NULL\n", __FUNCTION__); + return -1; + } +#else strcpy(wlan_node, DHD_DT_COMPAT_ENTRY); - printf("======== Get GPIO from DTS(%s) ========\n", wlan_node); root_node = of_find_compatible_node(NULL, NULL, wlan_node); +#endif + printf("======== Get GPIO from DTS(%s) ========\n", wlan_node); if (root_node) { gpio_wl_reg_on = of_get_named_gpio(root_node, GPIO_WL_REG_ON_PROPNAME, 0); #ifdef CUSTOMER_OOB @@ -308,8 +299,8 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter) if (gpio_wl_reg_on >= 0) { err = gpio_request(gpio_wl_reg_on, "WL_REG_ON"); if (err < 0) { - printf("%s: gpio_request(%d) for WL_REG_ON failed\n", - __FUNCTION__, gpio_wl_reg_on); + printf("%s: gpio_request(%d) for WL_REG_ON failed %d\n", + __FUNCTION__, gpio_wl_reg_on, err); gpio_wl_reg_on = -1; } } @@ -319,22 +310,22 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter) if (gpio_wl_host_wake >= 0) { err = gpio_request(gpio_wl_host_wake, "bcmdhd"); if (err < 0) { - printf("%s: gpio_request(%d) for WL_HOST_WAKE failed\n", - __FUNCTION__, gpio_wl_host_wake); + printf("%s: gpio_request(%d) for WL_HOST_WAKE failed %d\n", + __FUNCTION__, gpio_wl_host_wake, err); return -1; } adapter->gpio_wl_host_wake = gpio_wl_host_wake; err = gpio_direction_input(gpio_wl_host_wake); if (err < 0) { - printf("%s: gpio_direction_input(%d) for WL_HOST_WAKE failed\n", - __FUNCTION__, gpio_wl_host_wake); + printf("%s: gpio_direction_input(%d) for WL_HOST_WAKE failed %d\n", + __FUNCTION__, gpio_wl_host_wake, err); gpio_free(gpio_wl_host_wake); return -1; } host_oob_irq = gpio_to_irq(gpio_wl_host_wake); if (host_oob_irq < 0) { - printf("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed\n", - __FUNCTION__, gpio_wl_host_wake); + printf("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed %d\n", + __FUNCTION__, gpio_wl_host_wake, host_oob_irq); gpio_free(gpio_wl_host_wake); return -1; } @@ -374,7 +365,8 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter) return 0; } -static void dhd_wlan_deinit_gpio(wifi_adapter_info_t *adapter) +static void +dhd_wlan_deinit_gpio(wifi_adapter_info_t *adapter) { int gpio_wl_reg_on = adapter->gpio_wl_reg_on; #ifdef CUSTOMER_OOB @@ -384,42 +376,74 @@ static void dhd_wlan_deinit_gpio(wifi_adapter_info_t *adapter) if (gpio_wl_reg_on >= 0) { printf("%s: gpio_free(WL_REG_ON %d)\n", __FUNCTION__, gpio_wl_reg_on); gpio_free(gpio_wl_reg_on); - gpio_wl_reg_on = -1; + adapter->gpio_wl_reg_on = -1; } #ifdef CUSTOMER_OOB if (gpio_wl_host_wake >= 0) { printf("%s: gpio_free(WL_HOST_WAKE %d)\n", __FUNCTION__, gpio_wl_host_wake); gpio_free(gpio_wl_host_wake); - gpio_wl_host_wake = -1; + adapter->gpio_wl_host_wake = -1; } #endif /* CUSTOMER_OOB */ } -int dhd_wlan_init_plat_data(wifi_adapter_info_t *adapter) +#if defined(BCMDHD_MDRIVER) +static void +dhd_wlan_init_adapter(wifi_adapter_info_t *adapter) +{ +#ifdef ADAPTER_IDX + if (ADAPTER_IDX == 0) { + adapter->bus_num = 1; + adapter->slot_num = 1; + } else if (ADAPTER_IDX == 1) { + adapter->bus_num = 2; + adapter->slot_num = 1; + } + adapter->index = ADAPTER_IDX; +#ifdef BCMSDIO + adapter->bus_type = SDIO_BUS; +#elif defined(BCMPCIE) + adapter->bus_type = PCI_BUS; +#elif defined(BCMDBUS) + adapter->bus_type = USB_BUS; +#endif + printf("bus_type=%d, bus_num=%d, slot_num=%d\n", + adapter->bus_type, adapter->bus_num, adapter->slot_num); +#endif /* ADAPTER_IDX */ + +#ifdef DHD_STATIC_IN_DRIVER + adapter->index = 0; +#elif !defined(ADAPTER_IDX) +#ifdef BCMSDIO + adapter->index = 0; +#elif defined(BCMPCIE) + adapter->index = 1; +#elif defined(BCMDBUS) + adapter->index = 2; +#endif +#endif /* DHD_STATIC_IN_DRIVER */ +} +#endif /* BCMDHD_MDRIVER */ + +int +dhd_wlan_init_plat_data(wifi_adapter_info_t *adapter) { int err = 0; - printf("======== %s ========\n", __FUNCTION__); - if (adapter->index == -1) { - adapter->index = 0; - } +#ifdef BCMDHD_MDRIVER + dhd_wlan_init_adapter(adapter); +#endif /* BCMDHD_MDRIVER */ + err = dhd_wlan_init_gpio(adapter); if (err) goto exit; -#ifdef DHD_STATIC_IN_DRIVER - err = dhd_static_buf_init(); -#endif - exit: return err; } -void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter) +void +dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter) { - printf("======== %s ========\n", __FUNCTION__); -#ifdef DHD_STATIC_IN_DRIVER - dhd_static_buf_exit(); -#endif dhd_wlan_deinit_gpio(adapter); } diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c old mode 100755 new mode 100644 index 3f9b625d0935..751a5c7b7220 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c @@ -1,7 +1,7 @@ /* * IP Packet Parser Module. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -976,6 +977,11 @@ dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt) cur_framelen -= ETHER_HDR_LEN; ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); + if (cur_framelen < IPV4_MIN_HEADER_LEN) { + DHD_TRACE(("%s %d: cur_framelen(%d) < IPV4_MIN_HEADER_LEN\n", __FUNCTION__, + __LINE__, cur_framelen)); + goto exit; + } ip_hdr_len = IPV4_HLEN(ip_hdr); if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) { @@ -988,6 +994,11 @@ dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt) cur_framelen -= ip_hdr_len; ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); + if (cur_framelen < TCP_MIN_HEADER_LEN) { + DHD_TRACE(("%s %d: cur_framelen is less than TCP_MIN_HEADER_LEN\n", + __FUNCTION__, __LINE__)); + goto exit; + } DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.h old mode 100755 new mode 100644 index a478c890439a..efbf2d3f62a6 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.h @@ -3,7 +3,7 @@ * * Provides type definitions and function prototypes used to parse ip packet. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -62,10 +62,10 @@ extern tcp_hdr_flag_t dhd_tcpdata_get_flag(dhd_pub_t *dhdp, void *pkt); /* Max number of TCP streams that have own src/dst IP addrs and TCP ports */ #ifndef TCPACK_INFO_MAXNUM -#define TCPACK_INFO_MAXNUM 4 +#define TCPACK_INFO_MAXNUM 40 #endif #ifndef TCPDATA_INFO_MAXNUM -#define TCPDATA_INFO_MAXNUM 4 +#define TCPDATA_INFO_MAXNUM 40 #endif #define TCPDATA_PSH_INFO_MAXNUM (8 * TCPDATA_INFO_MAXNUM) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c old mode 100755 new mode 100644 index 6377495297a5..11e16779fb32 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Linux-specific network interface. * Basically selected code segments from usb-cdc.c and usb-rndis.c * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -24,6 +24,7 @@ * $Id$ */ +#include #include #include #include @@ -48,7 +49,6 @@ #include #include #include -#include #include #include #include @@ -61,13 +61,14 @@ #include #endif /* ENABLE_ADAPTIVE_SCHED */ #include -#include #include #include #include -#if defined(CUSTOMER_HW_ROCKCHIP) && defined(BCMPCIE) +#ifdef BCMPCIE +#if defined(CUSTOMER_HW_ROCKCHIP) && defined(CUSTOMER_HW_ROCKCHIP_RK3588) #include -#endif /* CUSTOMER_HW_ROCKCHIP && BCMPCIE */ +#endif /* CUSTOMER_HW_ROCKCHIP && CUSTOMER_HW_ROCKCHIP_RK3588 */ +#endif /* BCMPCIE */ #include #include @@ -82,11 +83,9 @@ #include #include <802.3.h> -#ifdef WL_NANHO -#include -#endif /* WL_NANHO */ #include #include +#include #include #include #ifdef DHD_WET @@ -104,8 +103,12 @@ #include #include #include +#ifdef DHD_LOG_DUMP +#include +#endif #if defined(WL_CFG80211) #include +#include #ifdef WL_BAM #include #endif /* WL_BAM */ @@ -116,28 +119,13 @@ #ifdef RTT_SUPPORT #include #endif -#ifdef DHD_TIMESYNC -#include -#include -#include -#endif /* DHD_TIMESYNC */ #include -#ifdef CSI_SUPPORT -#include -#endif /* CSI_SUPPORT */ - #ifdef CONFIG_COMPAT #include #endif -#ifdef CONFIG_ARCH_EXYNOS -#ifndef SUPPORT_EXYNOS7420 -#include -#endif /* SUPPORT_EXYNOS7420 */ -#endif /* CONFIG_ARCH_EXYNOS */ - #ifdef DHD_WMF #include #endif /* DHD_WMF */ @@ -173,11 +161,6 @@ void dhd_page_corrupt_cb(void *handle, void *addr_corrupt, size_t len); extern void register_page_corrupt_cb(page_corrupt_cb_t cb, void* handle); #endif /* DHD_DEBUG_PAGEALLOC */ -#if defined(DHD_TCP_WINSIZE_ADJUST) -#include -#include -#endif /* DHD_TCP_WINSIZE_ADJUST */ - #ifdef ENABLE_DHD_GRO #include #endif /* ENABLE_DHD_GRO */ @@ -192,12 +175,6 @@ module_param(enable_mq, int, 0644); int mq_select_disable = FALSE; #endif -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE -#include -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ - #if defined(DHD_LB) #if !defined(PCIE_FULL_DONGLE) #error "DHD Loadbalancing only supported on PCIE_FULL_DONGLE" @@ -214,24 +191,14 @@ int mq_select_disable = FALSE; static void dhd_m4_state_handler(struct work_struct * work); #endif /* DHD_4WAYM4_FAIL_DISCONNECT */ -#if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) static int dhd_wait_for_file_dump(dhd_pub_t *dhdp); -#endif /* WL_CFG80211 && DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ #ifdef FIX_CPU_MIN_CLOCK #include #endif /* FIX_CPU_MIN_CLOCK */ -#ifdef ENABLE_ADAPTIVE_SCHED -#define DEFAULT_CPUFREQ_THRESH 1000000 /* threshold frequency : 1000000 = 1GHz */ -#ifndef CUSTOM_CPUFREQ_THRESH -#define CUSTOM_CPUFREQ_THRESH DEFAULT_CPUFREQ_THRESH -#endif /* CUSTOM_CPUFREQ_THRESH */ -#endif /* ENABLE_ADAPTIVE_SCHED */ - -/* enable HOSTIP cache update from the host side when an eth0:N is up */ -#define AOE_IP_ALIAS_SUPPORT 1 - #ifdef PROP_TXSTATUS #include #include @@ -248,6 +215,12 @@ static int dhd_wait_for_file_dump(dhd_pub_t *dhdp); #define DHD_MAX_STA 32 #endif /* BCM_ROUTER_DHD */ +#if defined(IFACE_HANG_FORCE_DEV_CLOSE) && defined(HANG_DELAY_BEFORE_DEV_CLOSE) +#ifndef WAIT_FOR_DEV_CLOSE_MAX +#define WAIT_FOR_DEV_CLOSE_MAX 50 +#endif /* WAIT_FOR_DEV_CLOSE_MAX */ +#endif /* IFACE_HANG_FORCE_DEV_CLOSE && HANG_DELAY_BEFORE_DEV_CLOSE */ + #if (defined(BCM_ROUTER_DHD) && defined(HNDCTF)) #include @@ -257,9 +230,9 @@ static int dhd_wait_for_file_dump(dhd_pub_t *dhdp); #endif /* CTFPOOL */ #endif /* BCM_ROUTER_DHD && HNDCTF */ -#ifdef BCMDBG +#if defined(BCMDBG) && defined(DHD_MACDBG) #include -#endif /* BCMDBG */ +#endif /* BCMDBG && DHD_MACDBG */ #ifdef DHD_EVENT_LOG_FILTER #include @@ -269,10 +242,6 @@ static int dhd_wait_for_file_dump(dhd_pub_t *dhdp); static void dhd_blk_tsfl_handler(struct work_struct * work); #endif /* DHDTCPSYNC_FLOOD_BLK */ -#ifdef WL_NATOE -#include -#endif /* WL_NATOE */ - #ifdef DHD_TX_PROFILE #include #include @@ -280,11 +249,11 @@ static void dhd_blk_tsfl_handler(struct work_struct * work); #include #endif /* defined(DHD_TX_PROFILE) */ -#if defined(DHD_TCP_WINSIZE_ADJUST) -static uint target_ports[MAX_TARGET_PORTS] = {20, 0, 0, 0, 0}; -static uint dhd_use_tcp_window_size_adjust = FALSE; -static void dhd_adjust_tcp_winsize(int op_mode, struct sk_buff *skb); -#endif /* DHD_TCP_WINSIZE_ADJUST */ +#ifdef CSI_SUPPORT +#include +#endif /* CSI_SUPPORT */ + +#include #ifdef SET_RANDOM_MAC_SOFTAP #ifndef CONFIG_DHD_SET_RANDOM_MAC_VAL @@ -326,7 +295,6 @@ module_param(dhd_if_threshold, int, 0); /* XXX: this needs to reviewed for host OS. */ const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 }; const uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; -#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]] #ifdef ARP_OFFLOAD_SUPPORT void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx); @@ -353,7 +321,7 @@ static struct notifier_block dhd_inet6addr_notifier = { static bool dhd_inet6addr_notifier_registered = FALSE; #endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ -#if defined (CONFIG_PM_SLEEP) +#if defined(CONFIG_PM_SLEEP) #include volatile bool dhd_mmc_suspend = FALSE; DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); @@ -370,7 +338,6 @@ extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); static void dhd_hang_process(struct work_struct *work_data); #endif /* OEM_ANDROID */ MODULE_LICENSE("GPL and additional rights"); -MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); #if defined(MULTIPLE_SUPPLICANT) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) @@ -403,7 +370,7 @@ extern int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_si #include #endif /* defined(WL_WIRELESS_EXT) */ -#ifdef CONFIG_PARTIALSUSPEND_SLP +#if defined(CONFIG_PARTIALSUSPEND_SLP) && !defined(DHD_USE_PM_SLEEP) /* XXX SLP use defferent earlysuspend header file and some functions * But most of meaning is same as Android */ @@ -418,57 +385,22 @@ extern int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_si #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) #include #endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ -#endif /* CONFIG_PARTIALSUSPEND_SLP */ +#endif /* CONFIG_PARTIALSUSPEND_SLP && !DHD_USE_PM_SLEEP */ -#ifdef CONFIG_IRQ_HISTORY -#include -#endif /* CONFIG_IRQ_HISTORY */ - -#if defined(OEM_ANDROID) -#include -#endif /* OEM_ANDROID */ - -#if defined(PKT_FILTER_SUPPORT) && defined(APF) -static int __dhd_apf_add_filter(struct net_device *ndev, uint32 filter_id, - u8* program, uint32 program_len); -static int __dhd_apf_config_filter(struct net_device *ndev, uint32 filter_id, - uint32 mode, uint32 enable); -static int __dhd_apf_delete_filter(struct net_device *ndev, uint32 filter_id); -#endif /* PKT_FILTER_SUPPORT && APF */ +#if defined(APF) +static int _dhd_apf_add_filter(struct net_device *ndev, uint32 filter_id, u8* program, + uint32 program_len); +static int _dhd_apf_config_filter(struct net_device *ndev, uint32 filter_id, uint32 mode, + uint32 enable); +static int _dhd_apf_delete_filter(struct net_device *ndev, uint32 filter_id); +static int _dhd_apf_read_filter_data(struct net_device *ndev, uint32 filter_id, u8* buf, + uint32 buf_len); +#endif /* APF */ #ifdef DHD_FW_COREDUMP static void dhd_mem_dump(void *dhd_info, void *event_info, u8 event); #endif /* DHD_FW_COREDUMP */ -#ifdef DHD_LOG_DUMP - -struct dhd_log_dump_buf g_dld_buf[DLD_BUFFER_NUM]; - -/* Only header for log dump buffers is stored in array - * header for sections like 'dhd dump', 'ext trap' - * etc, is not in the array, because they are not log - * ring buffers - */ -dld_hdr_t dld_hdrs[DLD_BUFFER_NUM] = { - {GENERAL_LOG_HDR, LOG_DUMP_SECTION_GENERAL}, - {PRESERVE_LOG_HDR, LOG_DUMP_SECTION_PRESERVE}, - {SPECIAL_LOG_HDR, LOG_DUMP_SECTION_SPECIAL} -}; -static int dld_buf_size[DLD_BUFFER_NUM] = { - LOG_DUMP_GENERAL_MAX_BUFSIZE, /* DLD_BUF_TYPE_GENERAL */ - LOG_DUMP_PRESERVE_MAX_BUFSIZE, /* DLD_BUF_TYPE_PRESERVE */ - LOG_DUMP_SPECIAL_MAX_BUFSIZE, /* DLD_BUF_TYPE_SPECIAL */ -}; - -static void dhd_log_dump_init(dhd_pub_t *dhd); -static void dhd_log_dump_deinit(dhd_pub_t *dhd); -static void dhd_log_dump(void *handle, void *event_info, u8 event); -static int do_dhd_log_dump(dhd_pub_t *dhdp, log_dump_type_t *type); -static void dhd_print_buf_addr(dhd_pub_t *dhdp, char *name, void *buf, unsigned int size); -static void dhd_log_dump_buf_addr(dhd_pub_t *dhdp, log_dump_type_t *type); -char *dhd_dbg_get_system_timestamp(void); -#endif /* DHD_LOG_DUMP */ - #ifdef DHD_PCIE_NATIVE_RUNTIMEPM #include #include @@ -487,29 +419,22 @@ static struct notifier_block dhd_reboot_notifier = { .priority = 1, }; -#ifdef OEM_ANDROID -#ifdef BCMPCIE -static int is_reboot = 0; -#endif /* BCMPCIE */ -#endif /* OEM_ANDROID */ - dhd_pub_t *g_dhd_pub = NULL; #if defined(BT_OVER_SDIO) #include "dhd_bt_interface.h" #endif /* defined (BT_OVER_SDIO) */ -#ifdef WL_NANHO -static int dhd_nho_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_buf); -static int dhd_nho_ioctl_cb(void *drv_ctx, int ifidx, wl_ioctl_t *ioc, bool drv_lock); -static int dhd_nho_evt_cb(void *drv_ctx, int ifidx, bcm_event_t *evt, uint16 evt_len); -#endif /* WL_NANHO */ +#if defined(DHD_ENABLE_S2MPU) +#include +#endif /* DHD_ENABLE_S2MPU */ #ifdef WL_STATIC_IF bool dhd_is_static_ndev(dhd_pub_t *dhdp, struct net_device *ndev); #endif /* WL_STATIC_IF */ atomic_t exit_in_progress = ATOMIC_INIT(0); +atomic_t reboot_in_progress = ATOMIC_INIT(-1); static void dhd_process_daemon_msg(struct sk_buff *skb); static void dhd_destroy_to_notifier_skt(void); @@ -524,26 +449,6 @@ struct netlink_kernel_cfg dhd_netlink_cfg = { }; #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) */ -#ifdef DHD_PKTTS -static int dhd_create_to_notifier_ts(void); -static void dhd_destroy_to_notifier_ts(void); - -static struct sock *nl_to_ts = NULL; -int sender_pid_ts = 0; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) -static void dhd_recv_msg_from_ts(struct sk_buff *skb); - -struct netlink_kernel_cfg dhd_netlink_ts = { - .groups = 1, - .input = dhd_recv_msg_from_ts, -}; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) */ - -#define GET_METADATA_VER(val) ((uint16)((val & 0xffff0000) >> 16)) -#define GET_METADATA_BUFLEN(val) ((uint16)(val & 0x0000ffff)) -#endif /* DHD_PKTTS */ - #if defined(BT_OVER_SDIO) /* Flag to indicate if driver is initialized */ uint dhd_driver_init_done = TRUE; @@ -557,10 +462,18 @@ uint dhd_download_fw_on_driverload = TRUE; /* Definitions to provide path to the firmware and nvram * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" */ -char firmware_path[MOD_PARAM_PATHLEN]; -char nvram_path[MOD_PARAM_PATHLEN]; +#ifdef DHD_LINUX_STD_FW_API +char firmware_path[MOD_PARAM_PATHLEN] = DHD_FW_NAME; +char nvram_path[MOD_PARAM_PATHLEN] = DHD_NVRAM_NAME; char clm_path[MOD_PARAM_PATHLEN]; char config_path[MOD_PARAM_PATHLEN]; +#else +char firmware_path[MOD_PARAM_PATHLEN] = CONFIG_BCMDHD_FW_PATH; +char nvram_path[MOD_PARAM_PATHLEN] = CONFIG_BCMDHD_NVRAM_PATH; +char clm_path[MOD_PARAM_PATHLEN]; +char config_path[MOD_PARAM_PATHLEN]; +#endif /* DHD_LINUX_STD_FW_API */ +char signature_path[MOD_PARAM_PATHLEN]; #ifdef DHD_UCODE_DOWNLOAD char ucode_path[MOD_PARAM_PATHLEN]; #endif /* DHD_UCODE_DOWNLOAD */ @@ -574,6 +487,11 @@ char nv_bak_path[MOD_PARAM_PATHLEN]; /* information string to keep firmware, chio, cheip version info visiable from log */ char info_string[MOD_PARAM_INFOLEN]; module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444); + +#ifdef SYNA_SAR_CUSTOMER_PARAMETER +char config_sar_path[MOD_PARAM_PATHLEN] = CONFIG_BCMDHD_CONFIG_SAR_PATH; +module_param_string(config_sar_path, config_sar_path, MOD_PARAM_PATHLEN, 0660); +#endif /* SYNA_SAR_CUSTOMER_PARAMETER */ int op_mode = 0; int disable_proptx = 0; module_param(op_mode, int, 0644); @@ -585,27 +503,6 @@ struct semaphore dhd_registration_sem; #endif /* defined(OEM_ANDROID) */ void dhd_generate_rand_mac_addr(struct ether_addr *ea_addr); -#ifdef DHD_LOG_DUMP -int logdump_max_filesize = LOG_DUMP_MAX_FILESIZE; -module_param(logdump_max_filesize, int, 0644); -int logdump_max_bufsize = LOG_DUMP_GENERAL_MAX_BUFSIZE; -module_param(logdump_max_bufsize, int, 0644); -int logdump_periodic_flush = FALSE; -module_param(logdump_periodic_flush, int, 0644); -#ifdef EWP_ECNTRS_LOGGING -int logdump_ecntr_enable = TRUE; -#else -int logdump_ecntr_enable = FALSE; -#endif /* EWP_ECNTRS_LOGGING */ -module_param(logdump_ecntr_enable, int, 0644); -#ifdef EWP_RTT_LOGGING -int logdump_rtt_enable = TRUE; -#else -int logdump_rtt_enable = FALSE; -#endif /* EWP_RTT_LOGGING */ -int logdump_prsrv_tailsize = DHD_LOG_DUMP_MAX_TAIL_FLUSH_SIZE; -#endif /* DHD_LOG_DUMP */ - #ifdef EWP_EDL int host_edl_support = TRUE; module_param(host_edl_support, int, 0644); @@ -616,14 +513,15 @@ static void dhd_ifadd_event_handler(void *handle, void *event_info, u8 event); static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event); static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event); static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event); +static void dhd_ndev_upd_features_handler(void *handle, void *event_info, u8 event); #ifdef BCM_ROUTER_DHD static void dhd_inform_dhd_monitor_handler(void *handle, void *event_info, u8 event); #endif -#ifdef WL_NATOE -static void dhd_natoe_ct_event_hanlder(void *handle, void *event_info, u8 event); -static void dhd_natoe_ct_ioctl_handler(void *handle, void *event_info, uint8 event); -#endif /* WL_NATOE */ +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_STATIC_IN_DRIVER) +extern int dhd_static_buf_init(void); +extern void dhd_static_buf_exit(void); +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_STATIC_IN_DRIVER */ #ifdef DHD_UPDATE_INTF_MAC static void dhd_ifupdate_event_handler(void *handle, void *event_info, u8 event); #endif /* DHD_UPDATE_INTF_MAC */ @@ -676,6 +574,7 @@ module_param(disable_proptx, int, 0644); module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660); module_param_string(config_path, config_path, MOD_PARAM_PATHLEN, 0); +module_param_string(signature_path, signature_path, MOD_PARAM_PATHLEN, 0660); #ifdef DHD_UCODE_DOWNLOAD module_param_string(ucode_path, ucode_path, MOD_PARAM_PATHLEN, 0660); #endif /* DHD_UCODE_DOWNLOAD */ @@ -703,16 +602,9 @@ module_param(logtrace_pkt_sendup, uint, 0660); uint dhd_watchdog_ms = CUSTOM_DHD_WATCHDOG_MS; module_param(dhd_watchdog_ms, uint, 0); -#ifdef DHD_PCIE_RUNTIMEPM -uint dhd_runtimepm_ms = CUSTOM_DHD_RUNTIME_MS; -#endif /* DHD_PCIE_RUNTIMEPMT */ #if defined(DHD_DEBUG) /* Console poll interval */ -#if defined(OEM_ANDROID) -uint dhd_console_ms = 0; /* XXX andrey by default no fw msg prints */ -#else -uint dhd_console_ms = 250; -#endif /* OEM_ANDROID */ +uint dhd_console_ms = CUSTOM_DHD_CONSOLE_MS; module_param(dhd_console_ms, uint, 0644); #else uint dhd_console_ms = 0; @@ -746,10 +638,6 @@ module_param(dhd_watchdog_prio, int, 0); int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; module_param(dhd_dpc_prio, int, 0); -/* RX frame thread priority */ -int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING; -module_param(dhd_rxf_prio, int, 0); - #if !defined(BCMDBUS) extern int dhd_dongle_ramsize; module_param(dhd_dongle_ramsize, int, 0); @@ -799,13 +687,30 @@ module_param(dhd_napi_weight, int, 0644); #endif /* DHD_LB_RXP && PCIE_FULL_DONGLE */ #ifdef PCIE_FULL_DONGLE -extern int h2d_max_txpost; -module_param(h2d_max_txpost, int, 0644); +extern uint h2d_max_txpost; +module_param(h2d_max_txpost, uint, 0644); -#if defined(DHD_HTPUT_TUNABLES) -extern int h2d_htput_max_txpost; -module_param(h2d_htput_max_txpost, int, 0644); -#endif /* DHD_HTPUT_TUNABLES */ +extern uint h2d_htput_max_txpost; +module_param(h2d_htput_max_txpost, uint, 0644); + +extern uint d2h_max_txcpl; +module_param(d2h_max_txcpl, uint, 0644); + +extern uint h2d_max_ctrlpost; +module_param(h2d_max_ctrlpost, uint, 0644); +extern uint d2h_max_ctrlcpl; +module_param(d2h_max_ctrlcpl, uint, 0644); + +extern uint h2d_max_rxpost; +module_param(h2d_max_rxpost, uint, 0644); +extern uint d2h_max_rxcpl; +module_param(d2h_max_rxcpl, uint, 0644); + +extern uint rx_buf_burst; +module_param(rx_buf_burst, uint, 0644); + +extern uint rx_bufpost_threshold; +module_param(rx_bufpost_threshold, uint, 0644); #ifdef AGG_H2D_DB extern bool agg_h2d_db_enab; @@ -870,18 +775,10 @@ static int dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *s char *map_file); #endif /* SHOW_LOGTRACE */ -#if defined(GDB_PROXY) && defined(PCIE_FULL_DONGLE) && defined(BCMINTERNAL) -static void gdb_proxy_fs_try_create(dhd_info_t *dhd, const char *dev_name); -static void gdb_proxy_fs_remove(dhd_info_t *dhd); -#endif /* defined(GDB_PROXY) && defined(PCIE_FULL_DONGLE) && defined(BCMINTERNAL) */ - #ifdef D2H_MINIDUMP void dhd_d2h_minidump(dhd_pub_t *dhdp); #endif /* D2H_MINIDUMP */ -#define DHD_MEMDUMP_TYPE_STR_LEN 32 -#define DHD_MEMDUMP_PATH_STR_LEN 128 - #ifdef DHD_TX_PROFILE /* process layer 3 headers, to ultimately determine if a * dhd_tx_profile_protocol_t matches @@ -902,25 +799,9 @@ bool dhd_protocol_matches_profile(uint8 *p, int plen, const static void dhd_set_bandlock(dhd_pub_t * dhd); -static void -dhd_tx_stop_queues(struct net_device *net) -{ -#ifdef DHD_MQ - netif_tx_stop_all_queues(net); -#else - netif_stop_queue(net); -#endif -} - -static void -dhd_tx_start_queues(struct net_device *net) -{ -#ifdef DHD_MQ - netif_tx_wake_all_queues(net); -#else - netif_wake_queue(net); -#endif -} +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT +void dhd_alert_process(struct work_struct *work_data); +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ #ifdef USE_WFA_CERT_CONF int g_frameburst = 1; @@ -940,6 +821,9 @@ static void dhd_sta_list_snapshot_free(dhd_info_t *dhd, struct list_head *snapsh #endif /* DHD_IGMP_UCQUERY || DHD_UCAST_UPNP */ #endif /* PCIE_FULL_DONGLE */ +/* hostwake delay after d3 enter in ms */ +#define D3_HOSTWAKE_DELAY 200 + /* Control fw roaming */ #ifdef BCMCCX uint dhd_roam_disable = 0; @@ -956,6 +840,19 @@ extern void dhd_dbgfs_init(dhd_pub_t *dhdp); extern void dhd_dbgfs_remove(void); #endif +#ifdef BCMPCIE +/* Tx/Rx/Ctrl cpl/post bounds */ +extern uint dhd_tx_cpl_bound; +extern uint dhd_rx_cpl_post_bound; +extern uint dhd_tx_post_bound; +extern uint dhd_ctrl_cpl_post_bound; + +module_param(dhd_tx_cpl_bound, uint, 0); +module_param(dhd_rx_cpl_post_bound, uint, 0); +module_param(dhd_tx_post_bound, uint, 0); +module_param(dhd_ctrl_cpl_post_bound, uint, 0); +#endif /* BCMPCIE */ + /* Enable TX status metadta report: 0=disable 1=enable 2=debug */ static uint pcie_txs_metadata_enable = 0; module_param(pcie_txs_metadata_enable, int, 0); @@ -1002,10 +899,6 @@ module_param(dhd_rxbound, uint, 0); extern uint dhd_deferred_tx; module_param(dhd_deferred_tx, uint, 0); -#ifdef BCMINTERNAL -extern uint dhd_anychip; -module_param(dhd_anychip, uint, 0); -#endif /* BCMINTERNAL */ #endif /* BCMSDIO */ #ifdef BCMSLTGT @@ -1031,11 +924,6 @@ uint dhd_pktgen_len = 0; module_param(dhd_pktgen_len, uint, 0); #endif /* SDTEST */ -#ifdef CUSTOM_DSCP_TO_PRIO_MAPPING -uint dhd_dscpmap_enable = 1; -module_param(dhd_dscpmap_enable, uint, 0644); -#endif /* CUSTOM_DSCP_TO_PRIO_MAPPING */ - #if defined(BCMSUP_4WAY_HANDSHAKE) /* Use in dongle supplicant for 4-way handshake */ #if defined(WLFBT) || defined(WL_ENABLE_IDSUP) @@ -1081,10 +969,18 @@ int qt_dngl_timeout = 0; // dongle attach timeout in ms module_param(qt_dngl_timeout, int, 0); #endif /* BCMQT_HW */ +#ifdef DHD_SUPPORT_SPMI_MODE +uint spmi_mode = 0; +module_param(spmi_mode, uint, 0644); +#endif /* DHD_SUPPORT_SPMI_MODE */ + /* TCM verification flag */ uint dhd_tcm_test_enable = FALSE; module_param(dhd_tcm_test_enable, uint, 0644); +tcm_test_status_t dhd_tcm_test_status = TCM_TEST_NOT_RUN; +tcm_test_mode_t dhd_tcm_test_mode = TCM_TEST_MODE_ALWAYS; + extern char dhd_version[]; extern char fw_version[]; extern char clm_version[]; @@ -1104,11 +1000,7 @@ bool g_pm_control; #ifdef DHD_EXPORT_CNTL_FILE uint32 pmmode_val = 0xFF; #endif /* DHD_EXPORT_CNTL_FILE */ -#ifdef CUSTOMER_HW10 -void dhd_control_pm(dhd_pub_t *dhd, uint *); -#else void sec_control_pm(dhd_pub_t *dhd, uint *); -#endif /* CUSTOMER_HW10 */ #endif /* DHD_PM_CONTROL_FROM_FILE */ #if defined(WL_WIRELESS_EXT) @@ -1134,22 +1026,243 @@ static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); #endif /* TOE */ -static int dhd_wl_host_event(dhd_info_t *dhd, int ifidx, void *pktdata, uint16 pktlen, - wl_event_msg_t *event_ptr, void **data_ptr); +#ifdef DHD_MAP_LOGGING +void dhd_smmu_fault_handler(uint32 axid, ulong fault_addr); +#endif /* DHD_MAP_LOGGING */ + +#if defined(DHD_ENABLE_S2MPU) +int s2mpufd_notifier_callback(struct s2mpufd_notifier_block *block, + struct s2mpufd_notifier_info *info); +static void dhd_module_s2mpu_register(struct device *dev); +#endif /* DHD_ENABLE_S2MPU */ +#ifdef DHD_REGISTER_SMMU_FAULT_HANDLER +extern int pcie_sysmmu_add_fault_handler(struct notifier_block *pcie_sysmmu_nb); +static int sysmmu_notifier_callback(struct notifier_block *nb, unsigned long addr, + void *flag); +static struct notifier_block dhd_pcie_sysmmu_nb = { + .notifier_call = sysmmu_notifier_callback +}; +#endif /* DHD_REGISTER_SMMU_FAULT_HANDLER */ + +static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force); +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) +static void dhd_dump_proc(struct work_struct *work_data); +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ + +#ifdef CUSTOM_EVENT_PM_WAKE +void +dhd_set_excess_pm_awake(dhd_pub_t *dhd, bool suspend) +{ + int ret = 0; + uint32 iovar_val = 0; /* Disable the excess PM notify */ + char *iovar_name; + +#ifdef CUSTOM_EVENT_PM_PERCENT + iovar_name = "excess_pm_period"; +#else + iovar_name = "const_awake_thresh"; + iovar_val = CUSTOM_EVENT_PM_WAKE; +#endif /* CUSTOM_EVENT_PM_PERCENT */ + + if (suspend) { + iovar_val = CUSTOM_EVENT_PM_WAKE * 4; + } + + ret = dhd_iovar(dhd, 0, iovar_name, (char *)&iovar_val, + sizeof(iovar_val), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s set %s failed %d\n", __FUNCTION__, iovar_name, ret)); + } + return; +} +void +dhd_init_excess_pm_awake(dhd_pub_t *dhd) +{ + int ret = 0; + uint32 pm_awake_thresh = CUSTOM_EVENT_PM_WAKE; +#ifdef CUSTOM_EVENT_PM_PERCENT + uint32 pm_awake_percent = CUSTOM_EVENT_PM_PERCENT; + + ret = dhd_iovar(dhd, 0, "excess_pm_percent", (char *)&pm_awake_percent, + sizeof(pm_awake_percent), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s set excess_pm_percent failed %d\n", __FUNCTION__, ret)); + } + pm_awake_thresh = 0; /* Disable the excess PM notify */ +#endif /* CUSTOM_EVENT_PM_PERCENT */ + ret = dhd_iovar(dhd, 0, "const_awake_thresh", (char *)&pm_awake_thresh, + sizeof(pm_awake_thresh), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s set const_awake_thresh failed %d\n", __FUNCTION__, ret)); + } + + return; +} +#endif /* CUSTOM_EVENT_PM_WAKE */ #if defined(CONFIG_PM_SLEEP) +#ifdef WL_TWT +#define TWT_NOMINAL_RESUME (5U * 1024U) /* 5ms */ + +int dhd_send_twt_info_suspend(dhd_pub_t *dhdp, bool suspend) +{ + int ret = BCME_OK; + wl_twt_info_t ti; + u8 buf[WLC_IOCTL_SMLEN] = {0}; + + uint8 *pbuf = buf; + uint16 param_len = sizeof(buf); + + bzero(&ti, sizeof(ti)); + ti.version = WL_TWT_INFO_VER; + ti.length = sizeof(ti.version) + sizeof(ti.length); + + if (!dhdp || dhdp->up == 0) { + return ret; + } + + /* if it's not associated, skip send info */ + if (!dhd_is_associated(dhdp, 0, NULL)) { + return ret; + } + + /* Default values, Overide Below */ + ti.infodesc.flow_id = 0xFF; + ti.desc.next_twt_h = 0xFFFFFFFF; + ti.desc.next_twt_l = 0xFFFFFFFF; + + /* Set allTWT info suspend, ConfigID = 0 */ + ti.configID = 0; + + /* resume TWT session in resume */ + if (suspend == FALSE) { + /* Resume TWT session */ + ti.infodesc.next_twt_h = htod32((u32)((u64)TWT_NOMINAL_RESUME >> 32)); + ti.infodesc.next_twt_l = htod32((u32)TWT_NOMINAL_RESUME); + ti.infodesc.flow_flags |= WL_TWT_INFO_FLAG_RESUME; + } + + /* Packing parameters */ + ret = bcm_pack_xtlv_entry(&pbuf, ¶m_len, WL_TWT_CMD_INFO, + sizeof(ti), (uint8 *)&ti, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + DHD_ERROR(("%s : parameter packing error \n", __FUNCTION__)); + return ret; + } + + ret = dhd_iovar(dhdp, 0, "twt", buf, sizeof(buf) - param_len, NULL, 0, TRUE); + if (ret) { + DHD_ERROR(("%s : TWT info failed ret : %d\n", __FUNCTION__, ret)); + } + return ret; + +} +int dhd_config_twt_event_mask_in_suspend(dhd_pub_t *dhdp, bool suspend) +{ + int ret = BCME_OK; + u8 buf[WLC_IOCTL_SMLEN] = {0}; + eventmsgs_ext_t *eventmask_msg = NULL; + + int msglen = WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE; + + if (!dhdp || dhdp->up == 0) { + return ret; + } + + /* if it's not associated in suspend, skip teardown */ + if (suspend && !dhd_is_associated(dhdp, 0, NULL)) { + return ret; + } + + /* TWT_E_TWT event mask configuration */ + eventmask_msg = (eventmsgs_ext_t *)MALLOC(dhdp->osh, msglen); + if (eventmask_msg == NULL) { + DHD_ERROR(("%s : failed to allocate for event_msg_ext\n", __FUNCTION__)); + return ret; + } + + bzero(eventmask_msg, msglen); + eventmask_msg->ver = EVENTMSGS_VER; + eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; + + /* Read event_msgs_ext mask */ + ret = dhd_iovar(dhdp, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, buf, + WLC_IOCTL_SMLEN, FALSE); + /* event_msgs_ext must be supported */ + if (ret != BCME_OK) { + DHD_ERROR(("%s read event mask ext failed %d\n", __FUNCTION__, ret)); + goto fail; + } + + bcopy(buf, eventmask_msg, msglen); + + /* suspend */ + if (suspend) { + /* Clear TWT EVENT bit mask */ + clrbit(eventmask_msg->mask, WLC_E_TWT); + } else { + /* resume */ + /* Set TWT EVENT bit mask */ + setbit(eventmask_msg->mask, WLC_E_TWT); + } + + /* Write updated Event mask */ + eventmask_msg->ver = EVENTMSGS_VER; + eventmask_msg->command = EVENTMSGS_SET_MASK; + eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN; + + ret = dhd_iovar(dhdp, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, + NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret)); + goto fail; + } + +fail: + if (eventmask_msg) { + MFREE(dhdp->osh, eventmask_msg, msglen); + } + + return ret; + +} +#endif /* WL_TWT */ + static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) { int ret = NOTIFY_DONE; bool suspend = FALSE; - dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, const dhd_info_t, pm_notifier); - dhd_pub_t *dhd = &dhdinfo->pub; - struct dhd_conf *conf = dhd->conf; - int suspend_mode = conf->suspend_mode; + dhd_info_t *dhdinfo; + unsigned long flags = 0; + dhd_pub_t *dhd; + struct dhd_conf *conf; + int suspend_mode; +#if defined(BCMDBUS) && defined(WL_EXT_WOWL) + int wowl_dngldown = 0; +#endif BCM_REFERENCE(dhdinfo); BCM_REFERENCE(suspend); + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + dhdinfo = container_of(nfb, struct dhd_info, pm_notifier); + GCC_DIAGNOSTIC_POP(); + + if (!dhdinfo->pub.up) { + return ret; + } + dhd = &dhdinfo->pub; + conf = dhd->conf; + suspend_mode = conf->suspend_mode; + + DHD_GENERAL_LOCK(&dhdinfo->pub, flags); +#if defined(BCMDBUS) && defined(WL_EXT_WOWL) + wowl_dngldown = dhd_conf_wowl_dngldown(dhd); + if (!wowl_dngldown) +#endif + DHD_BUS_BUSY_SET_IN_PM_CALLBACK(&dhdinfo->pub); + DHD_GENERAL_UNLOCK(&dhdinfo->pub, flags); + switch (action) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: @@ -1171,9 +1284,19 @@ static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, voi printf("%s: action=%ld, suspend=%d, suspend_mode=%d\n", __FUNCTION__, action, suspend, suspend_mode); if (suspend) { +#ifdef WL_TWT + dhd_config_twt_event_mask_in_suspend(&dhdinfo->pub, TRUE); + dhd_send_twt_info_suspend(&dhdinfo->pub, TRUE); +#endif /* WL_TWT */ DHD_OS_WAKE_LOCK_WAIVE(dhd); if (suspend_mode == PM_NOTIFIER) dhd_suspend_resume_helper(dhdinfo, suspend, 0); +#ifdef DHD_CUSTOM_CONFIG_RTS_IN_SUSPEND + dhd_config_rts_in_suspend(&dhdinfo->pub, suspend); +#endif /* DHD_CUSTOM_CONFIG_RTS_IN_SUSPEND */ +#ifdef CUSTOM_EVENT_PM_WAKE + dhd_set_excess_pm_awake(&dhdinfo->pub, suspend); +#endif /* CUSTOM_EVENT_PM_WAKE */ #if defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) dhd_wlfc_suspend(dhd); #endif /* defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) */ @@ -1181,21 +1304,47 @@ static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, voi dhd_conf_set_suspend_resume(dhd, suspend); DHD_OS_WAKE_LOCK_RESTORE(dhd); } else { +#ifdef BCMDBUS + if (dhd->busstate == DHD_BUS_DATA) { +#endif if (suspend_mode == PM_NOTIFIER || suspend_mode == SUSPEND_MODE_2) dhd_conf_set_suspend_resume(dhd, suspend); #if defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) dhd_wlfc_resume(dhd); #endif /* defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) */ +#ifdef CUSTOM_EVENT_PM_WAKE + dhd_set_excess_pm_awake(&dhdinfo->pub, suspend); +#endif /* CUSTOM_EVENT_PM_WAKE */ +#ifdef DHD_CUSTOM_CONFIG_RTS_IN_SUSPEND + dhd_config_rts_in_suspend(&dhdinfo->pub, suspend); +#endif /* DHD_CUSTOM_CONFIG_RTS_IN_SUSPEND */ if (suspend_mode == PM_NOTIFIER) dhd_suspend_resume_helper(dhdinfo, suspend, 0); +#ifdef BCMDBUS + } else { +#if defined(BCMDBUS) && defined(WL_EXT_WOWL) + if (wowl_dngldown) { + printf("%s: reset power\n", __FUNCTION__); + dhd_wifi_platform_set_power(dhd, FALSE); + dhd_wifi_platform_set_power(dhd, TRUE); + } else +#endif + { + printf("%s: skip resume since bus suspeneded\n", __FUNCTION__); + } + } +#endif } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ - KERNEL_VERSION(2, 6, 39)) + KERNEL_VERSION(2, 6, 39)) dhd_mmc_suspend = suspend; smp_mb(); #endif + DHD_GENERAL_LOCK(&dhdinfo->pub, flags); + DHD_BUS_BUSY_CLEAR_IN_PM_CALLBACK(&dhdinfo->pub); + DHD_GENERAL_UNLOCK(&dhdinfo->pub, flags); return ret; } @@ -1208,31 +1357,11 @@ extern int register_pm_notifier(struct notifier_block *nb); extern int unregister_pm_notifier(struct notifier_block *nb); #endif /* CONFIG_PM_SLEEP */ -/* Request scheduling of the bus rx frame */ -static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb); -static void dhd_os_rxflock(dhd_pub_t *pub); -static void dhd_os_rxfunlock(dhd_pub_t *pub); - #if defined(DHD_H2D_LOG_TIME_SYNC) static void dhd_deferred_work_rte_log_time_sync(void *handle, void *event_info, u8 event); #endif /* DHD_H2D_LOG_TIME_SYNC */ -/** priv_link is the link between netdev and the dhdif and dhd_info structs. */ -typedef struct dhd_dev_priv { - dhd_info_t * dhd; /* cached pointer to dhd_info in netdevice priv */ - dhd_if_t * ifp; /* cached pointer to dhd_if in netdevice priv */ - int ifidx; /* interface index */ - void * lkup; -} dhd_dev_priv_t; - -#define DHD_DEV_PRIV_SIZE (sizeof(dhd_dev_priv_t)) -#define DHD_DEV_PRIV(dev) ((dhd_dev_priv_t *)DEV_PRIV(dev)) -#define DHD_DEV_INFO(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->dhd) -#define DHD_DEV_IFP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifp) -#define DHD_DEV_IFIDX(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifidx) -#define DHD_DEV_LKUP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->lkup) - /** Clear the dhd net_device's private structure. */ static inline void dhd_dev_priv_clear(struct net_device * dev) @@ -1423,6 +1552,7 @@ dhd_sta_free(dhd_pub_t * dhdp, dhd_sta_t * sta) DHD_CUMM_CTR_INIT(&sta->cumm_ctr); sta->ifp = DHD_IF_NULL; /* dummy dhd_if object */ sta->ifidx = DHD_BAD_IF; + sta->chanspec = 0; bzero(sta->ea.octet, ETHER_ADDR_LEN); INIT_LIST_HEAD(&sta->list); sta->idx = ID16_INVALID; /* implying free */ @@ -1600,6 +1730,28 @@ dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta) } } +/* + * Lockless variant of dhd_find_sta() + * Find STA with MAC address ea in an interface's STA list. + */ +dhd_sta_t * +__dhd_find_sta(dhd_if_t *ifp, void *pub, int ifidx, void *ea) +{ + dhd_sta_t *sta; + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + list_for_each_entry(sta, &ifp->sta_list, list) { + GCC_DIAGNOSTIC_POP(); + if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) { + DHD_INFO(("%s: Found STA " MACDBG "\n", + __FUNCTION__, MAC2STRDBG((char *)ea))); + return sta; + } + } + + return DHD_STA_NULL; +} + /** Find STA with MAC address ea in an interface's STA list. */ dhd_sta_t * dhd_find_sta(void *pub, int ifidx, void *ea) @@ -1608,40 +1760,27 @@ dhd_find_sta(void *pub, int ifidx, void *ea) dhd_if_t *ifp; unsigned long flags; - ASSERT(ea != NULL); ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); if (ifp == NULL) return DHD_STA_NULL; DHD_IF_STA_LIST_LOCK(&ifp->sta_list_lock, flags); - GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); - list_for_each_entry(sta, &ifp->sta_list, list) { - GCC_DIAGNOSTIC_POP(); - if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) { - DHD_INFO(("%s: Found STA " MACDBG "\n", - __FUNCTION__, MAC2STRDBG((char *)ea))); - DHD_IF_STA_LIST_UNLOCK(&ifp->sta_list_lock, flags); - return sta; - } - } + + sta = __dhd_find_sta(ifp, pub, ifidx, ea); DHD_IF_STA_LIST_UNLOCK(&ifp->sta_list_lock, flags); - return DHD_STA_NULL; + return sta; } -/** Add STA into the interface's STA list. */ +/* + * Lockless variant of dhd_add_sta() + * Add STA into the interface's STA list. + */ dhd_sta_t * -dhd_add_sta(void *pub, int ifidx, void *ea) +__dhd_add_sta(dhd_if_t *ifp, void *pub, int ifidx, void *ea) { dhd_sta_t *sta; - dhd_if_t *ifp; - unsigned long flags; - - ASSERT(ea != NULL); - ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); - if (ifp == NULL) - return DHD_STA_NULL; if (!memcmp(ifp->net->dev_addr, ea, ETHER_ADDR_LEN)) { DHD_ERROR(("%s: Serious FAILURE, receive own MAC %pM !!\n", __FUNCTION__, ea)); @@ -1664,13 +1803,30 @@ dhd_add_sta(void *pub, int ifidx, void *ea) #endif INIT_LIST_HEAD(&sta->list); - DHD_IF_STA_LIST_LOCK(&ifp->sta_list_lock, flags); - list_add_tail(&sta->list, &ifp->sta_list); DHD_ERROR(("%s: Adding STA " MACDBG "\n", __FUNCTION__, MAC2STRDBG((char *)ea))); + return sta; +} + +/** Add STA into the interface's STA list. */ +dhd_sta_t * +dhd_add_sta(void *pub, int ifidx, void *ea) +{ + dhd_sta_t *sta; + dhd_if_t *ifp; + unsigned long flags; + + ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); + if (ifp == NULL) + return DHD_STA_NULL; + + DHD_IF_STA_LIST_LOCK(&ifp->sta_list_lock, flags); + + sta = __dhd_add_sta(ifp, pub, ifidx, ea); + DHD_IF_STA_LIST_UNLOCK(&ifp->sta_list_lock, flags); return sta; @@ -1750,17 +1906,105 @@ dhd_sta_t* dhd_findadd_sta(void *pub, int ifidx, void *ea) { dhd_sta_t *sta; + dhd_if_t *ifp; + unsigned long flags; - sta = dhd_find_sta(pub, ifidx, ea); + ASSERT(ea != NULL); + ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); + if (ifp == NULL) + return DHD_STA_NULL; + + DHD_IF_STA_LIST_LOCK(&ifp->sta_list_lock, flags); + sta = __dhd_find_sta(ifp, pub, ifidx, ea); if (!sta) { /* Add entry */ - sta = dhd_add_sta(pub, ifidx, ea); + sta = __dhd_add_sta(ifp, pub, ifidx, ea); } + DHD_IF_STA_LIST_UNLOCK(&ifp->sta_list_lock, flags); return sta; } +void +dhd_update_sta_chanspec_info(void *pub, int ifidx, const uint8 *ea, chanspec_t chanspec) +{ + dhd_sta_t *sta; + dhd_if_t *ifp; + unsigned long flags; + + ASSERT(ea != NULL); + ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); + if (ifp == NULL) { + DHD_ERROR(("%s: NULL ifp for ifidx:%d\n", __FUNCTION__, ifidx)); + return; + } + + DHD_IF_STA_LIST_LOCK(&ifp->sta_list_lock, flags); + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + sta = __dhd_find_sta(ifp, pub, ifidx, (void *)ea); + GCC_DIAGNOSTIC_POP(); + + if (sta) { + sta->chanspec = chanspec; + DHD_ERROR(("%s: updated chanspec:0x%x for STA:" MACDBG "\n", + __FUNCTION__, sta->chanspec, MAC2STRDBG(sta->ea.octet))); + } else { + DHD_ERROR(("%s: found no STA:" MACDBG "\n", + __FUNCTION__, MAC2STRDBG(ea))); + } + DHD_IF_STA_LIST_UNLOCK(&ifp->sta_list_lock, flags); + +} + +bool +dhd_is_sta_htput(void *pub, int ifidx, void *ea) +{ +#ifdef WL_CFG80211 + dhd_sta_t *sta; + dhd_if_t *ifp; + unsigned long flags; + bool htput = FALSE; + + /* For non-AP role, chanspec will not be updated and always use htput */ + if (!DHD_IF_ROLE_AP((dhd_pub_t *)pub, ifidx)) { + DHD_ERROR(("%s: non-AP role, set htput\n", __FUNCTION__)); + htput = TRUE; + return htput; + } + + ASSERT(ea != NULL); + ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); + if (ifp == NULL) { + DHD_ERROR(("%s: NULL ifp for ifidx:%d\n", __FUNCTION__, ifidx)); + return htput; + } + + DHD_IF_STA_LIST_LOCK(&ifp->sta_list_lock, flags); + sta = __dhd_find_sta(ifp, pub, ifidx, ea); + /* Set htput for 160 Mhz */ + if (sta) { + if (CHSPEC_IS160(sta->chanspec)) { + htput = TRUE; + } + DHD_ERROR(("%s: ifidx:%d htput:%d chanspec:0x%x of STA:" MACDBG "\n", + __FUNCTION__, ifidx, htput, sta->chanspec, MAC2STRDBG(sta->ea.octet))); + } else { + DHD_ERROR(("%s: found no STA " MACDBG "\n", + __FUNCTION__, MAC2STRDBG(ea))); + } + DHD_IF_STA_LIST_UNLOCK(&ifp->sta_list_lock, flags); + + return htput; +#else + /* For Non-CFG builds, always create HTPUT flowrings , + * as dhd_update_sta_chanspec_info will not be called. + */ + return TRUE; +#endif /* WL_CFG80211 */ +} + #if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) static struct list_head * dhd_sta_list_snapshot(dhd_info_t *dhd, dhd_if_t *ifp, struct list_head *snapshot_list) @@ -1811,6 +2055,9 @@ static inline void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta) {} dhd_sta_t *dhd_findadd_sta(void *pub, int ifidx, void *ea) { return NULL; } dhd_sta_t *dhd_find_sta(void *pub, int ifidx, void *ea) { return NULL; } void dhd_del_sta(void *pub, int ifidx, void *ea) {} +void dhd_update_sta_chanspec_info(void *pub, int ifidx, const uint8 *ea, + chanspec_t chanspec) {} +bool dhd_is_sta_htput(void *pub, int ifidx, void *ea) { return FALSE; } #endif /* PCIE_FULL_DONGLE */ #ifdef BCM_ROUTER_DHD @@ -1947,82 +2194,13 @@ int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx) return i; } -static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb) -{ - uint32 store_idx; - uint32 sent_idx; - - if (!skb) { - DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n")); - return BCME_ERROR; - } - - dhd_os_rxflock(dhdp); - store_idx = dhdp->store_idx; - sent_idx = dhdp->sent_idx; - if (dhdp->skbbuf[store_idx] != NULL) { - /* Make sure the previous packets are processed */ - dhd_os_rxfunlock(dhdp); -#ifdef RXF_DEQUEUE_ON_BUSY - DHD_TRACE(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", - skb, store_idx, sent_idx)); - return BCME_BUSY; -#else /* RXF_DEQUEUE_ON_BUSY */ - DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", - skb, store_idx, sent_idx)); - /* removed msleep here, should use wait_event_timeout if we - * want to give rx frame thread a chance to run - */ -#if defined(WAIT_DEQUEUE) - OSL_SLEEP(1); -#endif - return BCME_ERROR; -#endif /* RXF_DEQUEUE_ON_BUSY */ - } - DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n", - skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1))); - dhdp->skbbuf[store_idx] = skb; - dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1); - dhd_os_rxfunlock(dhdp); - - return BCME_OK; -} - -static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp) -{ - uint32 store_idx; - uint32 sent_idx; - void *skb; - - dhd_os_rxflock(dhdp); - - store_idx = dhdp->store_idx; - sent_idx = dhdp->sent_idx; - skb = dhdp->skbbuf[sent_idx]; - - if (skb == NULL) { - dhd_os_rxfunlock(dhdp); - DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n", - store_idx, sent_idx)); - return NULL; - } - - dhdp->skbbuf[sent_idx] = NULL; - dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1); - - DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n", - skb, sent_idx)); - - dhd_os_rxfunlock(dhdp); - - return skb; -} - int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost) { -#if defined(BCMSDIO) || defined(BCMPCIE) - uint chipid = dhd_bus_chip_id(dhdp); + uint chipid = 0; int ret = BCME_OK; +#ifndef BCMDBUS + chipid = dhd_bus_chip_id(dhdp); +#endif /* BCMDBUS */ if (prepost) { /* pre process */ ret = dhd_alloc_cis(dhdp); if (ret != BCME_OK) { @@ -2046,7 +2224,6 @@ int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost) dhd_write_macaddr(&dhdp->mac); dhd_clear_cis(dhdp); } -#endif return BCME_OK; } @@ -2093,9 +2270,9 @@ dhd_enable_packet_filter(int value, dhd_pub_t *dhd) int i; DHD_ERROR(("%s: enter, value = %d\n", __FUNCTION__, value)); - if ((dhd->op_mode & DHD_FLAG_HOSTAP_MODE) && value && + if ((dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_P2P_GO_MODE)) && value && !dhd_conf_get_insuspend(dhd, AP_FILTER_IN_SUSPEND)) { - DHD_ERROR(("%s: DHD_FLAG_HOSTAP_MODE\n", __FUNCTION__)); + DHD_ERROR(("%s: DHD_FLAG_HOSTAP_MODE or DHD_FLAG_P2P_GO_MODE\n", __FUNCTION__)); return; } /* 1 - Enable packet filter, only allow unicast packet to send up */ @@ -2209,30 +2386,11 @@ dhd_packet_filter_add_remove(dhd_pub_t *dhdp, int add_remove, int num) static int dhd_set_suspend(int value, dhd_pub_t *dhd) { -#ifndef SUPPORT_PM2_ONLY - int power_mode = PM_MAX; -#endif /* SUPPORT_PM2_ONLY */ /* wl_pkt_filter_enable_t enable_parm; */ - int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */ int ret = 0; -#ifdef DHD_USE_EARLYSUSPEND -#ifdef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND - int roam_time_thresh = 0; /* (ms) */ -#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */ -#ifndef ENABLE_FW_ROAM_SUSPEND - uint roamvar = 1; -#endif /* ENABLE_FW_ROAM_SUSPEND */ -#ifdef ENABLE_BCN_LI_BCN_WAKEUP - int bcn_li_bcn = 1; -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ +#if defined(DHD_USE_EARLYSUSPEND) || defined(DHD_USE_PM_SLEEP) uint nd_ra_filter = 0; -#ifdef ENABLE_IPMCAST_FILTER - int ipmcast_l2filter; -#endif /* ENABLE_IPMCAST_FILTER */ -#ifdef CUSTOM_EVENT_PM_WAKE - uint32 pm_awake_thresh = CUSTOM_EVENT_PM_WAKE; -#endif /* CUSTOM_EVENT_PM_WAKE */ -#endif /* DHD_USE_EARLYSUSPEND */ +#endif /* DHD_USE_EARLYSUSPEND || DHD_USE_PM_SLEEP */ #ifdef PASS_ALL_MCAST_PKTS struct dhd_info *dhdinfo; uint32 allmulti; @@ -2244,18 +2402,16 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) int intr_width = 0; #endif /* CUSTOM_INTR_WIDTH */ #endif /* DYNAMIC_SWOOB_DURATION */ - -#if defined(DHD_BCN_TIMEOUT_IN_SUSPEND) && defined(DHD_USE_EARLYSUSPEND) +#ifdef WL_CFG80211 + struct net_device *dev = dhd_linux_get_primary_netdev(dhd); +#endif /* WL_CFG80211 */ +#if defined(DHD_BCN_TIMEOUT_IN_SUSPEND) && (defined(DHD_USE_EARLYSUSPEND) || \ + defined(DHD_USE_PM_SLEEP)) /* CUSTOM_BCN_TIMEOUT_IN_SUSPEND in suspend, otherwise CUSTOM_BCN_TIMEOUT */ int bcn_timeout = CUSTOM_BCN_TIMEOUT; -#endif /* DHD_BCN_TIMEOUT_IN_SUSPEND && DHD_USE_EARLYSUSPEND */ -#if defined(OEM_ANDROID) && defined(BCMPCIE) - int lpas = 0; - int dtim_period = 0; - int bcn_interval = 0; - int bcn_to_dly = 0; -#endif /* OEM_ANDROID && BCMPCIE */ +#endif /* DHD_BCN_TIMEOUT_IN_SUSPEND && (DHD_USE_EARLYSUSPEND || DHD_USE_PM_SLEEP) */ + BCM_REFERENCE(ret); if (!dhd) return -ENODEV; @@ -2279,152 +2435,52 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) /* Kernel suspended */ DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); -#ifndef SUPPORT_PM2_ONLY - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); -#endif /* SUPPORT_PM2_ONLY */ - #ifdef PKT_FILTER_SUPPORT /* Enable packet filter, * only allow unicast packet to send up */ dhd_enable_packet_filter(1, dhd); +#endif /* PKT_FILTER_SUPPORT */ #ifdef APF dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd)); #endif /* APF */ -#endif /* PKT_FILTER_SUPPORT */ #ifdef ARP_OFFLOAD_SUPPORT if (dhd->arpoe_enable) { dhd_arp_offload_enable(dhd, TRUE); } #endif /* ARP_OFFLOAD_SUPPORT */ - #ifdef PASS_ALL_MCAST_PKTS - allmulti = 0; for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) { - ret = dhd_iovar(dhd, i, "allmulti", - (char *)&allmulti, - sizeof(allmulti), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s allmulti failed %d\n", - __FUNCTION__, ret)); - } + struct net_device *ndev = NULL; + if (!dhdinfo->iflist[i] || !dhdinfo->iflist[i]->net) { + continue; + } + + ndev = dhdinfo->iflist[i]->net; +#ifdef WL_CFG80211 + if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO || + ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) { + allmulti = 1; + DHD_LOG_MEM(("%s: IF[%s] is AP/GO, set allmulti.\n", + __FUNCTION__, ndev->name)); + } else +#endif /* WL_CFG80211 */ + { + allmulti = 0; + } + + ret = dhd_iovar(dhd, i, "allmulti", + (char *)&allmulti, + sizeof(allmulti), + NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s allmulti failed %d\n", + __FUNCTION__, ret)); } } #endif /* PASS_ALL_MCAST_PKTS */ - /* If DTIM skip is set up as default, force it to wake - * each third DTIM for better power savings. Note that - * one side effect is a chance to miss BC/MC packet. - */ -#ifdef WLTDLS - /* Do not set bcn_li_ditm on WFD mode */ - if (dhd->tdls_mode) { - bcn_li_dtim = 0; - } else -#endif /* WLTDLS */ -#if defined(OEM_ANDROID) && defined(BCMPCIE) - bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd, &dtim_period, - &bcn_interval); - ret = dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, - sizeof(bcn_li_dtim), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s bcn_li_dtim failed %d\n", - __FUNCTION__, ret)); - } - if ((bcn_li_dtim * dtim_period * bcn_interval) >= - MIN_DTIM_FOR_ROAM_THRES_EXTEND) { - /* - * Increase max roaming threshold from 2 secs to 8 secs - * the real roam threshold is MIN(max_roam_threshold, - * bcn_timeout/2) - */ - lpas = 1; - ret = dhd_iovar(dhd, 0, "lpas", (char *)&lpas, sizeof(lpas), - NULL, 0, TRUE); - if (ret < 0) { - if (ret == BCME_UNSUPPORTED) { - DHD_ERROR(("%s lpas, UNSUPPORTED\n", - __FUNCTION__)); - } else { - DHD_ERROR(("%s set lpas failed %d\n", - __FUNCTION__, ret)); - } - } - bcn_to_dly = 1; - /* - * if bcn_to_dly is 1, the real roam threshold is - * MIN(max_roam_threshold, bcn_timeout -1); - * notify link down event after roaming procedure complete - * if we hit bcn_timeout while we are in roaming progress. - */ - ret = dhd_iovar(dhd, 0, "bcn_to_dly", (char *)&bcn_to_dly, - sizeof(bcn_to_dly), NULL, 0, TRUE); - if (ret < 0) { - if (ret == BCME_UNSUPPORTED) { - DHD_ERROR(("%s bcn_to_dly, UNSUPPORTED\n", - __FUNCTION__)); - } else { - DHD_ERROR(("%s set bcn_to_dly failed %d\n", - __FUNCTION__, ret)); - } - } - } -#else - bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd); - if (dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, - sizeof(bcn_li_dtim), NULL, 0, TRUE) < 0) - DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__)); -#endif /* OEM_ANDROID && BCMPCIE */ - -#ifdef DHD_USE_EARLYSUSPEND -#ifdef DHD_BCN_TIMEOUT_IN_SUSPEND - bcn_timeout = CUSTOM_BCN_TIMEOUT_IN_SUSPEND; - ret = dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, - sizeof(bcn_timeout), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s bcn_timeout failed %d\n", __FUNCTION__, - ret)); - } -#endif /* DHD_BCN_TIMEOUT_IN_SUSPEND */ -#ifdef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND - roam_time_thresh = CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND; - ret = dhd_iovar(dhd, 0, "roam_time_thresh", - (char *)&roam_time_thresh, - sizeof(roam_time_thresh), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s roam_time_thresh failed %d\n", - __FUNCTION__, ret)); - } -#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */ -#ifndef ENABLE_FW_ROAM_SUSPEND - /* Disable firmware roaming during suspend */ - ret = dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, - sizeof(roamvar), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s roam_off failed %d\n", - __FUNCTION__, ret)); - } -#endif /* ENABLE_FW_ROAM_SUSPEND */ -#ifdef ENABLE_BCN_LI_BCN_WAKEUP - if (bcn_li_dtim) { - bcn_li_bcn = 0; - } - ret = dhd_iovar(dhd, 0, "bcn_li_bcn", (char *)&bcn_li_bcn, - sizeof(bcn_li_bcn), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s bcn_li_bcn failed %d\n", __FUNCTION__, ret)); - } -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ -#if defined(WL_CFG80211) && defined(WL_BCNRECV) - ret = wl_android_bcnrecv_suspend(dhd_linux_get_primary_netdev(dhd)); - if (ret != BCME_OK) { - DHD_ERROR(("failed to stop beacon recv event on" - " suspend state (%d)\n", ret)); - } -#endif /* WL_CFG80211 && WL_BCNRECV */ +#if defined(DHD_USE_EARLYSUSPEND) || defined(DHD_USE_PM_SLEEP) #ifdef NDO_CONFIG_SUPPORT if (dhd->ndo_enable) { if (!dhd->ndo_host_ip_overflow) { @@ -2456,15 +2512,6 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) ret)); } dhd_os_suppress_logging(dhd, TRUE); -#ifdef ENABLE_IPMCAST_FILTER - ipmcast_l2filter = 1; - ret = dhd_iovar(dhd, 0, "ipmcast_l2filter", - (char *)&ipmcast_l2filter, sizeof(ipmcast_l2filter), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("failed to set ipmcast_l2filter (%d)\n", ret)); - } -#endif /* ENABLE_IPMCAST_FILTER */ #ifdef DYNAMIC_SWOOB_DURATION intr_width = CUSTOM_INTR_WIDTH; ret = dhd_iovar(dhd, 0, "bus:intr_width", (char *)&intr_width, @@ -2473,27 +2520,10 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) DHD_ERROR(("failed to set intr_width (%d)\n", ret)); } #endif /* DYNAMIC_SWOOB_DURATION */ -#ifdef CUSTOM_EVENT_PM_WAKE - pm_awake_thresh = CUSTOM_EVENT_PM_WAKE * 4; - ret = dhd_iovar(dhd, 0, "const_awake_thresh", - (char *)&pm_awake_thresh, - sizeof(pm_awake_thresh), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s set const_awake_thresh failed %d\n", - __FUNCTION__, ret)); - } -#endif /* CUSTOM_EVENT_PM_WAKE */ -#ifdef CONFIG_SILENT_ROAM - if (!dhd->sroamed) { - ret = dhd_sroam_set_mon(dhd, TRUE); - if (ret < 0) { - DHD_ERROR(("%s set sroam failed %d\n", - __FUNCTION__, ret)); - } - } - dhd->sroamed = FALSE; -#endif /* CONFIG_SILENT_ROAM */ -#endif /* DHD_USE_EARLYSUSPEND */ +#endif /* DHD_USE_EARLYSUSPEND || DHD_USE_PM_SLEEP */ +#ifdef WL_CFG80211 + wl_cfg80211_soft_suspend(dev, TRUE); +#endif /* WL_CFG80211 */ } else { dhd->early_suspended = 0; /* Kernel resumed */ @@ -2506,18 +2536,6 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) DHD_ERROR(("failed to set intr_width (%d)\n", ret)); } #endif /* DYNAMIC_SWOOB_DURATION */ -#ifndef SUPPORT_PM2_ONLY - power_mode = PM_FAST; - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); -#endif /* SUPPORT_PM2_ONLY */ -#if defined(WL_CFG80211) && defined(WL_BCNRECV) - ret = wl_android_bcnrecv_resume(dhd_linux_get_primary_netdev(dhd)); - if (ret != BCME_OK) { - DHD_ERROR(("failed to resume beacon recv state (%d)\n", - ret)); - } -#endif /* WL_CF80211 && WL_BCNRECV */ #ifdef ARP_OFFLOAD_SUPPORT if (dhd->arpoe_enable) { dhd_arp_offload_enable(dhd, FALSE); @@ -2526,10 +2544,10 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) #ifdef PKT_FILTER_SUPPORT /* disable pkt filter */ dhd_enable_packet_filter(0, dhd); +#endif /* PKT_FILTER_SUPPORT */ #ifdef APF dhd_dev_apf_disable_filter(dhd_linux_get_primary_netdev(dhd)); #endif /* APF */ -#endif /* PKT_FILTER_SUPPORT */ #ifdef PASS_ALL_MCAST_PKTS allmulti = 1; for (i = 0; i < DHD_MAX_IFS; i++) { @@ -2544,80 +2562,7 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) } } #endif /* PASS_ALL_MCAST_PKTS */ -#if defined(OEM_ANDROID) && defined(BCMPCIE) - /* restore pre-suspend setting */ - ret = dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, - sizeof(bcn_li_dtim), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s:bcn_li_ditm failed:%d\n", - __FUNCTION__, ret)); - } - ret = dhd_iovar(dhd, 0, "lpas", (char *)&lpas, sizeof(lpas), NULL, - 0, TRUE); - if (ret < 0) { - if (ret == BCME_UNSUPPORTED) { - DHD_ERROR(("%s lpas, UNSUPPORTED\n", __FUNCTION__)); - } else { - DHD_ERROR(("%s set lpas failed %d\n", - __FUNCTION__, ret)); - } - } - ret = dhd_iovar(dhd, 0, "bcn_to_dly", (char *)&bcn_to_dly, - sizeof(bcn_to_dly), NULL, 0, TRUE); - if (ret < 0) { - if (ret == BCME_UNSUPPORTED) { - DHD_ERROR(("%s bcn_to_dly UNSUPPORTED\n", - __FUNCTION__)); - } else { - DHD_ERROR(("%s set bcn_to_dly failed %d\n", - __FUNCTION__, ret)); - } - } -#else - /* restore pre-suspend setting for dtim_skip */ - ret = dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, - sizeof(bcn_li_dtim), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s:bcn_li_ditm fail:%d\n", __FUNCTION__, ret)); - } -#endif /* OEM_ANDROID && BCMPCIE */ -#ifdef DHD_USE_EARLYSUSPEND -#ifdef DHD_BCN_TIMEOUT_IN_SUSPEND - bcn_timeout = CUSTOM_BCN_TIMEOUT; - ret = dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, - sizeof(bcn_timeout), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s:bcn_timeout failed:%d\n", - __FUNCTION__, ret)); - } -#endif /* DHD_BCN_TIMEOUT_IN_SUSPEND */ -#ifdef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND - roam_time_thresh = 2000; - ret = dhd_iovar(dhd, 0, "roam_time_thresh", - (char *)&roam_time_thresh, - sizeof(roam_time_thresh), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s:roam_time_thresh failed:%d\n", - __FUNCTION__, ret)); - } - -#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */ -#ifndef ENABLE_FW_ROAM_SUSPEND - roamvar = dhd_roam_disable; - ret = dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, - sizeof(roamvar), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: roam_off fail:%d\n", __FUNCTION__, ret)); - } -#endif /* ENABLE_FW_ROAM_SUSPEND */ -#ifdef ENABLE_BCN_LI_BCN_WAKEUP - ret = dhd_iovar(dhd, 0, "bcn_li_bcn", (char *)&bcn_li_bcn, - sizeof(bcn_li_bcn), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: bcn_li_bcn failed:%d\n", - __FUNCTION__, ret)); - } -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ +#if defined(DHD_USE_EARLYSUSPEND) || defined(DHD_USE_PM_SLEEP) #ifdef NDO_CONFIG_SUPPORT if (dhd->ndo_enable) { /* Disable ND offload on resume */ @@ -2645,31 +2590,10 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) } } dhd_os_suppress_logging(dhd, FALSE); -#ifdef ENABLE_IPMCAST_FILTER - ipmcast_l2filter = 0; - ret = dhd_iovar(dhd, 0, "ipmcast_l2filter", - (char *)&ipmcast_l2filter, sizeof(ipmcast_l2filter), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("failed to clear ipmcast_l2filter ret:%d", ret)); - } -#endif /* ENABLE_IPMCAST_FILTER */ -#ifdef CUSTOM_EVENT_PM_WAKE - ret = dhd_iovar(dhd, 0, "const_awake_thresh", - (char *)&pm_awake_thresh, - sizeof(pm_awake_thresh), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s set const_awake_thresh failed %d\n", - __FUNCTION__, ret)); - } -#endif /* CUSTOM_EVENT_PM_WAKE */ -#ifdef CONFIG_SILENT_ROAM - ret = dhd_sroam_set_mon(dhd, FALSE); - if (ret < 0) { - DHD_ERROR(("%s set sroam failed %d\n", __FUNCTION__, ret)); - } -#endif /* CONFIG_SILENT_ROAM */ -#endif /* DHD_USE_EARLYSUSPEND */ +#endif /* DHD_USE_EARLYSUSPEND || DHD_USE_PM_SLEEP */ +#ifdef WL_CFG80211 + wl_cfg80211_soft_suspend(dev, FALSE); +#endif /* WL_CFG80211 */ } } dhd_suspend_unlock(dhd); @@ -2682,7 +2606,9 @@ static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) dhd_pub_t *dhdp = &dhd->pub; int ret = 0; +#if !defined(DHD_USE_PM_SLEEP) DHD_OS_WAKE_LOCK(dhdp); +#endif /* !defined(DHD_USE_PM_SLEEP) */ /* Set flag when early suspend was called */ dhdp->in_suspend = val; @@ -2692,7 +2618,10 @@ static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) ret = dhd_set_suspend(val, dhdp); } +#if !defined(DHD_USE_PM_SLEEP) DHD_OS_WAKE_UNLOCK(dhdp); +#endif /* !defined(DHD_USE_PM_SLEEP) */ + return ret; } @@ -2927,10 +2856,9 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) #endif /* MCAST_LIST_ACCUMULATION */ #ifdef PASS_ALL_MCAST_PKTS -#ifdef PKT_FILTER_SUPPORT - if (!dhd->pub.early_suspended) -#endif /* PKT_FILTER_SUPPORT */ + if (!dhd->pub.early_suspended) { allmulti = TRUE; + } #endif /* PASS_ALL_MCAST_PKTS */ /* Send down the multicast list first. */ @@ -3074,7 +3002,7 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr, bool skip_stop) dhd_ifname(&dhd->pub, ifidx), addr, ret)); goto exit; } else { - dev_addr_set(dhd->iflist[ifidx]->net, addr); + DEV_ADDR_SET((dhd->iflist[ifidx]->net), addr); if (ifidx == 0) memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); WL_MSG(dhd_ifname(&dhd->pub, ifidx), "MACID %pM is overwritten\n", addr); @@ -3268,9 +3196,6 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event) #else struct net_device *ndev; #endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ -#ifdef DHD_AWDL - bool is_awdl_iface = FALSE; -#endif /* DHD_AWDL */ BCM_REFERENCE(ret); if (event != DHD_WQ_WORK_IF_ADD) { @@ -3289,20 +3214,11 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event) } dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); ifidx = if_event->event.ifidx; bssidx = if_event->event.bssidx; DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx)); -#ifdef DHD_AWDL - if (if_event->event.opcode == WLC_E_IF_ADD && - if_event->event.role == WLC_E_IF_ROLE_AWDL) { - dhd->pub.awdl_ifidx = ifidx; - is_awdl_iface = TRUE; - } -#endif /* DHD_AWDL */ - #if defined(WL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) if (if_event->event.ifidx > 0) { u8 *mac_addr; @@ -3370,15 +3286,9 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event) #endif /* WLDWDS && FOURADDR_AUTO_BRG */ done: -#ifdef DHD_AWDL - if (ret != BCME_OK && is_awdl_iface) { - dhd->pub.awdl_ifidx = 0; - } -#endif /* DHD_AWDL */ MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); - DHD_OS_WAKE_UNLOCK(&dhd->pub); dhd_net_if_unlock_local(dhd); } @@ -3405,7 +3315,6 @@ dhd_ifdel_event_handler(void *handle, void *event_info, u8 event) } dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); ifidx = if_event->event.ifidx; DHD_TRACE(("Removing interface with idx %d\n", ifidx)); @@ -3430,18 +3339,11 @@ dhd_ifdel_event_handler(void *handle, void *event_info, u8 event) #else /* For non-cfg80211 drivers */ dhd_remove_if(&dhd->pub, ifidx, TRUE); -#ifdef DHD_AWDL - if (if_event->event.opcode == WLC_E_IF_DEL && - if_event->event.role == WLC_E_IF_ROLE_AWDL) { - dhd->pub.awdl_ifidx = 0; - } -#endif /* DHD_AWDL */ #endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ done: MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); - DHD_OS_WAKE_UNLOCK(&dhd->pub); dhd_net_if_unlock_local(dhd); } @@ -3530,7 +3432,8 @@ static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event) { dhd_info_t *dhd = handle; - dhd_if_t *ifp = event_info; + int ifidx = (int)((long int)event_info); + dhd_if_t *ifp = NULL; if (event != DHD_WQ_WORK_SET_MAC) { DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); @@ -3541,9 +3444,14 @@ dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event) return; } +#ifdef DHD_NOTIFY_MAC_CHANGED + rtnl_lock(); +#endif /* DHD_NOTIFY_MAC_CHANGED */ dhd_net_if_lock_local(dhd); DHD_OS_WAKE_LOCK(&dhd->pub); + ifp = dhd->iflist[ifidx]; + // terence 20160907: fix for not able to set mac when wlan0 is down if (ifp == NULL || !ifp->set_macaddress) { goto done; @@ -3555,22 +3463,43 @@ dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event) ifp->set_macaddress = FALSE; -#ifdef DHD_NOTIFY_MAC_CHANGED - rtnl_lock(); -#endif /* DHD_NOTIFY_MAC_CHANGED */ - if (_dhd_set_mac_address(dhd, ifp->idx, ifp->mac_addr, TRUE) == 0) DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__)); else DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__)); -#ifdef DHD_NOTIFY_MAC_CHANGED - rtnl_unlock(); -#endif /* DHD_NOTIFY_MAC_CHANGED */ - done: DHD_OS_WAKE_UNLOCK(&dhd->pub); dhd_net_if_unlock_local(dhd); +#ifdef DHD_NOTIFY_MAC_CHANGED + rtnl_unlock(); +#endif /* DHD_NOTIFY_MAC_CHANGED */ +} + +static void +dhd_ndev_upd_features_handler(void *handle, void *event_info, u8 event) +{ + struct net_device *net = event_info; + + if (event != DHD_WQ_WORK_NDEV_UPD_FEATURES) { + DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); + return; + } + if (!net) { + DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); + return; + } + rtnl_lock(); + netdev_update_features(net); + rtnl_unlock(); +} + +static void +dhd_ndev_upd_features(dhd_info_t *dhd, struct net_device *net) +{ + dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)net, + DHD_WQ_WORK_NDEV_UPD_FEATURES, dhd_ndev_upd_features_handler, + DHD_WQ_WORK_PRIORITY_HIGH); } static void @@ -3600,11 +3529,6 @@ dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event) goto done; } - if (ifp == NULL || !dhd->pub.up) { - DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); - goto done; - } - ifidx = ifp->idx; #ifdef MCAST_LIST_ACCUMULATION @@ -3632,8 +3556,10 @@ dhd_set_mac_address(struct net_device *dev, void *addr) struct bcm_cfg80211 *cfg = wl_get_cfg(dev); #endif /* WL_STATIC_IF */ dhd_pub_t *dhdp = &dhd->pub; + bool addr_chngd = TRUE; BCM_REFERENCE(ifidx); + BCM_REFERENCE(addr_chngd); DHD_TRACE(("%s \n", __func__)); @@ -3643,6 +3569,9 @@ dhd_set_mac_address(struct net_device *dev, void *addr) } ifidx = dhdif->idx; dhd_net_if_lock_local(dhd); + if (memcmp(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN) == 0) { + addr_chngd = FALSE; + } memcpy(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN); dhdif->set_macaddress = TRUE; dhd_net_if_unlock_local(dhd); @@ -3661,7 +3590,7 @@ dhd_set_mac_address(struct net_device *dev, void *addr) * available). Store the address and return. macaddr will be applied * from interface create context. */ - dev_addr_set(dev, dhdif->mac_addr); + DEV_ADDR_SET(dev, dhdif->mac_addr); #ifdef DHD_NOTIFY_MAC_CHANGED #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)) dev_open(dev, NULL); @@ -3673,12 +3602,17 @@ dhd_set_mac_address(struct net_device *dev, void *addr) } #endif /* WL_STATIC_IF */ wl_cfg80211_handle_macaddr_change(dev, dhdif->mac_addr); - return _dhd_set_mac_address(dhd, ifidx, dhdif->mac_addr, TRUE); + ret = _dhd_set_mac_address(dhd, ifidx, dhdif->mac_addr, TRUE); + if ((ret == BCME_OK) && (addr_chngd == TRUE)) { + /* Notify Dev/Address change to upperlayer */ + netdev_state_change(dev); + } + return ret; } #endif /* WL_CFG80211 */ - dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhdif, DHD_WQ_WORK_SET_MAC, - dhd_set_mac_addr_handler, DHD_WQ_WORK_PRIORITY_LOW); + dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)((long int)ifidx), + DHD_WQ_WORK_SET_MAC, dhd_set_mac_addr_handler, DHD_WQ_WORK_PRIORITY_LOW); return ret; } @@ -3697,7 +3631,7 @@ dhd_set_multicast_list(struct net_device *dev) DHD_WQ_WORK_SET_MCAST_LIST, dhd_set_mcast_list_handler, DHD_WQ_WORK_PRIORITY_LOW); // terence 20160907: fix for not able to set mac when wlan0 is down - dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhd->iflist[ifidx], + dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)((long int)ifidx), DHD_WQ_WORK_SET_MAC, dhd_set_mac_addr_handler, DHD_WQ_WORK_PRIORITY_LOW); } @@ -3747,12 +3681,21 @@ dhd_os_wlfc_unblock(dhd_pub_t *pub) #endif /* PROP_TXSTATUS */ -#if defined(WL_MONITOR) && defined(BCMSDIO) -static void -dhd_rx_mon_pkt_sdio(dhd_pub_t *dhdp, void *pkt, int ifidx); -bool -dhd_monitor_enabled(dhd_pub_t *dhd, int ifidx); -#endif /* WL_MONITOR && BCMSDIO */ +void +dhd_netif_rx_ni(struct sk_buff * skb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) + /* Do not call netif_recieve_skb as this workqueue scheduler is + * not from NAPI Also as we are not in INTR context, do not call + * netif_rx, instead call netif_rx_ni (for kerenl >= 2.6) which + * does netif_rx, disables irq, raise NET_IF_RX softirq and + * enables interrupts back + */ + netif_rx_ni(skb); +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) */ + netif_rx(skb); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) */ +} /* This routine do not support Packet chain feature, Currently tested for * proxy arp feature @@ -3796,7 +3739,7 @@ int dhd_sendup(dhd_pub_t *dhdp, int ifidx, void *p) dhd_rx_mon_pkt_sdio(dhdp, skb, ifidx); else #endif /* WL_MONITOR && BCMSDIO */ - netif_rx_ni(skb); + dhd_netif_rx_ni(skb); } } @@ -3806,867 +3749,7 @@ int dhd_sendup(dhd_pub_t *dhdp, int ifidx, void *p) return BCME_OK; } -void -dhd_handle_pktdata(dhd_pub_t *dhdp, int ifidx, void *pkt, uint8 *pktdata, uint32 pktid, - uint32 pktlen, uint16 *pktfate, uint8 *dhd_udr, bool tx, int pkt_wake, bool pkt_log) -{ - struct ether_header *eh; - uint16 ether_type; - uint32 pkthash; - uint8 pkt_type = PKT_TYPE_DATA; - - if (!pktdata || pktlen < ETHER_HDR_LEN) { - return; - } - - eh = (struct ether_header *)pktdata; - ether_type = ntoh16(eh->ether_type); - - /* Check packet type */ - if (dhd_check_ip_prot(pktdata, ether_type)) { - if (dhd_check_dhcp(pktdata)) { - pkt_type = PKT_TYPE_DHCP; - } else if (dhd_check_icmp(pktdata)) { - pkt_type = PKT_TYPE_ICMP; - } else if (dhd_check_dns(pktdata)) { - pkt_type = PKT_TYPE_DNS; - } - } - else if (dhd_check_arp(pktdata, ether_type)) { - pkt_type = PKT_TYPE_ARP; - } - else if (ether_type == ETHER_TYPE_802_1X) { - pkt_type = PKT_TYPE_EAP; - } - -#ifdef DHD_SBN - /* Set UDR based on packet type */ - if (dhd_udr && (pkt_type == PKT_TYPE_DHCP || - pkt_type == PKT_TYPE_DNS || - pkt_type == PKT_TYPE_ARP)) { - *dhd_udr = TRUE; - } -#endif /* DHD_SBN */ - -#ifdef DHD_PKT_LOGGING -#ifdef DHD_SKIP_PKTLOGGING_FOR_DATA_PKTS - if (pkt_type != PKT_TYPE_DATA) -#endif - { - if (pkt_log) { - if (tx) { - if (pktfate) { - /* Tx status */ - DHD_PKTLOG_TXS(dhdp, pkt, pktdata, pktid, *pktfate); - } else { - /* Tx packet */ - DHD_PKTLOG_TX(dhdp, pkt, pktdata, pktid); - } - pkthash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid); - } else { - struct sk_buff *skb = (struct sk_buff *)pkt; - if (pkt_wake) { - DHD_PKTLOG_WAKERX(dhdp, skb, pktdata); - } else { - DHD_PKTLOG_RX(dhdp, skb, pktdata); - } - } - } - } -#endif /* DHD_PKT_LOGGING */ - - /* Dump packet data */ - if (!tx) { - switch (pkt_type) { - case PKT_TYPE_DHCP: - dhd_dhcp_dump(dhdp, ifidx, pktdata, tx, &pkthash, pktfate); - break; - case PKT_TYPE_ICMP: - dhd_icmp_dump(dhdp, ifidx, pktdata, tx, &pkthash, pktfate); - break; - case PKT_TYPE_DNS: - dhd_dns_dump(dhdp, ifidx, pktdata, tx, &pkthash, pktfate); - break; - case PKT_TYPE_ARP: - dhd_arp_dump(dhdp, ifidx, pktdata, tx, &pkthash, pktfate); - break; - case PKT_TYPE_EAP: - dhd_dump_eapol_message(dhdp, ifidx, pktdata, pktlen, tx, &pkthash, pktfate); - break; - default: - break; - } - } -} - -int -BCMFASTPATH(__dhd_sendpkt)(dhd_pub_t *dhdp, int ifidx, void *pktbuf) -{ - int ret = BCME_OK; - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct ether_header *eh = NULL; - uint8 pkt_flow_prio; - -#if (defined(DHD_L2_FILTER) || (defined(BCM_ROUTER_DHD) && defined(QOS_MAP_SET))) - dhd_if_t *ifp = dhd_get_ifp(dhdp, ifidx); -#endif /* DHD_L2_FILTER || (BCM_ROUTER_DHD && QOS_MAP_SET) */ - - /* Reject if down */ - if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { - /* free the packet here since the caller won't */ - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return -ENODEV; - } - -#ifdef PCIE_FULL_DONGLE - if (dhdp->busstate == DHD_BUS_SUSPEND) { - DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return NETDEV_TX_BUSY; - } -#endif /* PCIE_FULL_DONGLE */ - - /* Reject if pktlen > MAX_MTU_SZ */ - if (PKTLEN(dhdp->osh, pktbuf) > MAX_MTU_SZ) { - /* free the packet here since the caller won't */ - dhdp->tx_big_packets++; - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return BCME_ERROR; - } - -#ifdef DHD_L2_FILTER - /* if dhcp_unicast is enabled, we need to convert the */ - /* broadcast DHCP ACK/REPLY packets to Unicast. */ - if (ifp->dhcp_unicast) { - uint8* mac_addr; - uint8* ehptr = NULL; - int ret; - ret = bcm_l2_filter_get_mac_addr_dhcp_pkt(dhdp->osh, pktbuf, ifidx, &mac_addr); - if (ret == BCME_OK) { - /* if given mac address having valid entry in sta list - * copy the given mac address, and return with BCME_OK - */ - if (dhd_find_sta(dhdp, ifidx, mac_addr)) { - ehptr = PKTDATA(dhdp->osh, pktbuf); - bcopy(mac_addr, ehptr + ETHER_DEST_OFFSET, ETHER_ADDR_LEN); - } - } - } - - if (ifp->grat_arp && DHD_IF_ROLE_AP(dhdp, ifidx)) { - if (bcm_l2_filter_gratuitous_arp(dhdp->osh, pktbuf) == BCME_OK) { - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return BCME_ERROR; - } - } - - if (ifp->parp_enable && DHD_IF_ROLE_AP(dhdp, ifidx)) { - ret = dhd_l2_filter_pkt_handle(dhdp, ifidx, pktbuf, TRUE); - - /* Drop the packets if l2 filter has processed it already - * otherwise continue with the normal path - */ - if (ret == BCME_OK) { - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return BCME_ERROR; - } - } -#endif /* DHD_L2_FILTER */ - /* Update multicast statistic */ - if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { - uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); - eh = (struct ether_header *)pktdata; - - if (ETHER_ISMULTI(eh->ether_dhost)) - dhdp->tx_multicast++; - if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) { -#ifdef DHD_LOSSLESS_ROAMING - uint8 prio = (uint8)PKTPRIO(pktbuf); - - /* back up 802.1x's priority */ - dhdp->prio_8021x = prio; -#endif /* DHD_LOSSLESS_ROAMING */ - DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED); - atomic_inc(&dhd->pend_8021x_cnt); -#if defined(WL_CFG80211) && defined (WL_WPS_SYNC) - wl_handle_wps_states(dhd_idx2net(dhdp, ifidx), - pktdata, PKTLEN(dhdp->osh, pktbuf), TRUE); -#endif /* WL_CFG80211 && WL_WPS_SYNC */ -#ifdef EAPOL_RESEND - wl_ext_backup_eapol_txpkt(dhdp, ifidx, pktbuf); -#endif /* EAPOL_RESEND */ - } - dhd_dump_pkt(dhdp, ifidx, pktdata, - (uint32)PKTLEN(dhdp->osh, pktbuf), TRUE, NULL, NULL); - } else { - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return BCME_ERROR; - } - -#if (defined(BCM_ROUTER_DHD) && defined(QOS_MAP_SET)) - if (ifp->qosmap_up_table_enable) { - pktsetprio_qms(pktbuf, ifp->qosmap_up_table, FALSE); - } - else -#endif - { - /* Look into the packet and update the packet priority */ -#ifndef PKTPRIO_OVERRIDE - /* XXX RB:6270 Ignore skb->priority from TCP/IP stack */ - if (PKTPRIO(pktbuf) == 0) -#endif /* !PKTPRIO_OVERRIDE */ - { -#if (!defined(BCM_ROUTER_DHD) && defined(QOS_MAP_SET)) - pktsetprio_qms(pktbuf, wl_get_up_table(dhdp, ifidx), FALSE); -#else - /* For LLR, pkt prio will be changed to 7(NC) here */ - pktsetprio(pktbuf, FALSE); -#endif /* QOS_MAP_SET */ - } -#ifndef PKTPRIO_OVERRIDE - else { - /* Some protocols like OZMO use priority values from 256..263. - * these are magic values to indicate a specific 802.1d priority. - * make sure that priority field is in range of 0..7 - */ - PKTSETPRIO(pktbuf, PKTPRIO(pktbuf) & 0x7); - } -#endif /* !PKTPRIO_OVERRIDE */ - } - -#if defined(BCM_ROUTER_DHD) - traffic_mgmt_pkt_set_prio(dhdp, pktbuf); - -#endif /* BCM_ROUTER_DHD */ - - BCM_REFERENCE(pkt_flow_prio); - /* Intercept and create Socket level statistics */ - /* - * TODO: Some how moving this code block above the pktsetprio code - * is resetting the priority back to 0, but this does not happen for - * packets generated from iperf uisng -S option. Can't understand why. - */ - dhd_update_sock_flows(dhd, pktbuf); - -#ifdef SUPPORT_SET_TID - dhd_set_tid_based_on_uid(dhdp, pktbuf); -#endif /* SUPPORT_SET_TID */ - -#ifdef PCIE_FULL_DONGLE - /* - * Lkup the per interface hash table, for a matching flowring. If one is not - * available, allocate a unique flowid and add a flowring entry. - * The found or newly created flowid is placed into the pktbuf's tag. - */ - -#ifdef DHD_TX_PROFILE - if (dhdp->tx_profile_enab && dhdp->num_profiles > 0 && - dhd_protocol_matches_profile(PKTDATA(dhdp->osh, pktbuf), - PKTLEN(dhdp->osh, pktbuf), dhdp->protocol_filters, - dhdp->host_sfhllc_supported)) { - /* we only have support for one tx_profile at the moment */ - - /* tagged packets must be put into TID 6 */ - pkt_flow_prio = PRIO_8021D_VO; - } else -#endif /* defined(DHD_TX_PROFILE) */ - { - pkt_flow_prio = dhdp->flow_prio_map[(PKTPRIO(pktbuf))]; - } - - ret = dhd_flowid_update(dhdp, ifidx, pkt_flow_prio, pktbuf); - if (ret != BCME_OK) { - PKTCFREE(dhd->pub.osh, pktbuf, TRUE); - return ret; - } -#endif /* PCIE_FULL_DONGLE */ - /* terence 20150901: Micky add to ajust the 802.1X priority */ - /* Set the 802.1X packet with the highest priority 7 */ - if (dhdp->conf->pktprio8021x >= 0) - pktset8021xprio(pktbuf, dhdp->conf->pktprio8021x); - -#ifdef PROP_TXSTATUS - if (dhd_wlfc_is_supported(dhdp)) { - /* store the interface ID */ - DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx); - - /* store destination MAC in the tag as well */ - DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost); - - /* decide which FIFO this packet belongs to */ - if (ETHER_ISMULTI(eh->ether_dhost)) - /* one additional queue index (highest AC + 1) is used for bc/mc queue */ - DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT); - else - DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf))); - } else -#endif /* PROP_TXSTATUS */ - { - /* If the protocol uses a data header, apply it */ - dhd_prot_hdrpush(dhdp, ifidx, pktbuf); - } - - /* Use bus module to send data frame */ -#ifdef PROP_TXSTATUS - { - if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata, - dhdp->bus, pktbuf, TRUE) == WLFC_UNSUPPORTED) { - /* non-proptxstatus way */ -#ifdef BCMPCIE - ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); -#else - ret = dhd_bus_txdata(dhdp->bus, pktbuf); -#endif /* BCMPCIE */ - } - } -#else -#ifdef BCMPCIE - ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); -#else - ret = dhd_bus_txdata(dhdp->bus, pktbuf); -#endif /* BCMPCIE */ -#endif /* PROP_TXSTATUS */ -#ifdef BCMDBUS - if (ret) - PKTCFREE(dhdp->osh, pktbuf, TRUE); -#endif /* BCMDBUS */ - - return ret; -} - -int -BCMFASTPATH(dhd_sendpkt)(dhd_pub_t *dhdp, int ifidx, void *pktbuf) -{ - int ret = 0; - unsigned long flags; - dhd_if_t *ifp; - - DHD_GENERAL_LOCK(dhdp, flags); - ifp = dhd_get_ifp(dhdp, ifidx); - if (!ifp || ifp->del_in_progress) { - DHD_ERROR(("%s: ifp:%p del_in_progress:%d\n", - __FUNCTION__, ifp, ifp ? ifp->del_in_progress : 0)); - DHD_GENERAL_UNLOCK(dhdp, flags); - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return -ENODEV; - } - if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp)) { - DHD_ERROR(("%s: returning as busstate=%d\n", - __FUNCTION__, dhdp->busstate)); - DHD_GENERAL_UNLOCK(dhdp, flags); - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return -ENODEV; - } - DHD_IF_SET_TX_ACTIVE(ifp, DHD_TX_SEND_PKT); - DHD_BUS_BUSY_SET_IN_SEND_PKT(dhdp); - DHD_GENERAL_UNLOCK(dhdp, flags); - -#ifdef DHD_PCIE_RUNTIMEPM - if (dhdpcie_runtime_bus_wake(dhdp, FALSE, __builtin_return_address(0))) { - DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); - PKTCFREE(dhdp->osh, pktbuf, TRUE); - ret = -EBUSY; - goto exit; - } -#endif /* DHD_PCIE_RUNTIMEPM */ - - DHD_GENERAL_LOCK(dhdp, flags); - if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp)) { - DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", - __FUNCTION__, dhdp->busstate, dhdp->dhd_bus_busy_state)); - DHD_BUS_BUSY_CLEAR_IN_SEND_PKT(dhdp); - DHD_IF_CLR_TX_ACTIVE(ifp, DHD_TX_SEND_PKT); - dhd_os_tx_completion_wake(dhdp); - dhd_os_busbusy_wake(dhdp); - DHD_GENERAL_UNLOCK(dhdp, flags); - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return -ENODEV; - } - DHD_GENERAL_UNLOCK(dhdp, flags); - - ret = __dhd_sendpkt(dhdp, ifidx, pktbuf); - -#ifdef DHD_PCIE_RUNTIMEPM -exit: -#endif - DHD_GENERAL_LOCK(dhdp, flags); - DHD_BUS_BUSY_CLEAR_IN_SEND_PKT(dhdp); - DHD_IF_CLR_TX_ACTIVE(ifp, DHD_TX_SEND_PKT); - dhd_os_tx_completion_wake(dhdp); - dhd_os_busbusy_wake(dhdp); - DHD_GENERAL_UNLOCK(dhdp, flags); - return ret; -} - -#ifdef DHD_MQ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) -static uint16 -BCMFASTPATH(dhd_select_queue)(struct net_device *net, struct sk_buff *skb, - void *accel_priv, select_queue_fallback_t fallback) -#else -static uint16 -BCMFASTPATH(dhd_select_queue)(struct net_device *net, struct sk_buff *skb) -#endif /* LINUX_VERSION_CODE */ -{ - dhd_info_t *dhd_info = DHD_DEV_INFO(net); - dhd_pub_t *dhdp = &dhd_info->pub; - uint16 prio = 0; - - BCM_REFERENCE(dhd_info); - BCM_REFERENCE(dhdp); - BCM_REFERENCE(prio); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) - if (mq_select_disable) { - /* if driver side queue selection is disabled via sysfs, call the kernel - * supplied fallback function to select the queue, which is usually - * '__netdev_pick_tx()' in net/core/dev.c - */ - return fallback(net, skb); - } -#endif /* LINUX_VERSION */ - - prio = dhdp->flow_prio_map[skb->priority]; - if (prio < AC_COUNT) - return prio; - else - return AC_BK; -} -#endif /* DHD_MQ */ - -netdev_tx_t -BCMFASTPATH(dhd_start_xmit)(struct sk_buff *skb, struct net_device *net) -{ - int ret; - uint datalen; - void *pktbuf; - dhd_info_t *dhd = DHD_DEV_INFO(net); - dhd_if_t *ifp = NULL; - int ifidx; - unsigned long flags; -#if !defined(BCM_ROUTER_DHD) - uint8 htsfdlystat_sz = 0; -#endif /* ! BCM_ROUTER_DHD */ -#ifdef DHD_WMF - struct ether_header *eh; - uint8 *iph; -#endif /* DHD_WMF */ -#if defined(DHD_MQ) && defined(DHD_MQ_STATS) - int qidx = 0; - int cpuid = 0; - int prio = 0; -#endif /* DHD_MQ && DHD_MQ_STATS */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#if defined(DHD_MQ) && defined(DHD_MQ_STATS) - qidx = skb_get_queue_mapping(skb); - /* if in a non pre-emptable context, smp_processor_id can be used - * else get_cpu and put_cpu should be used - */ - if (!CAN_SLEEP()) { - cpuid = smp_processor_id(); - } - else { - cpuid = get_cpu(); - put_cpu(); - } - prio = dhd->pub.flow_prio_map[skb->priority]; - DHD_TRACE(("%s: Q idx = %d, CPU = %d, prio = %d \n", __FUNCTION__, - qidx, cpuid, prio)); - dhd->pktcnt_qac_histo[qidx][prio]++; - dhd->pktcnt_per_ac[prio]++; - dhd->cpu_qstats[qidx][cpuid]++; -#endif /* DHD_MQ && DHD_MQ_STATS */ - - if (dhd_query_bus_erros(&dhd->pub)) { - return -ENODEV; - } - - DHD_GENERAL_LOCK(&dhd->pub, flags); - DHD_BUS_BUSY_SET_IN_TX(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - -#ifdef DHD_PCIE_RUNTIMEPM - if (dhdpcie_runtime_bus_wake(&dhd->pub, FALSE, dhd_start_xmit)) { - /* In order to avoid pkt loss. Return NETDEV_TX_BUSY until run-time resumed. */ - /* stop the network queue temporarily until resume done */ - DHD_GENERAL_LOCK(&dhd->pub, flags); - if (!dhdpcie_is_resume_done(&dhd->pub)) { - dhd_bus_stop_queue(dhd->pub.bus); - } - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - return NETDEV_TX_BUSY; - } -#endif /* DHD_PCIE_RUNTIMEPM */ - - DHD_GENERAL_LOCK(&dhd->pub, flags); -#ifdef BCMPCIE - if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(&dhd->pub)) { - DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", - __FUNCTION__, dhd->pub.busstate, dhd->pub.dhd_bus_busy_state)); - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); -#ifdef PCIE_FULL_DONGLE - /* Stop tx queues if suspend is in progress */ - if (DHD_BUS_CHECK_ANY_SUSPEND_IN_PROGRESS(&dhd->pub)) { - dhd_bus_stop_queue(dhd->pub.bus); - } -#endif /* PCIE_FULL_DONGLE */ - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - return NETDEV_TX_BUSY; - } -#else - if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(&dhd->pub)) { - DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", - __FUNCTION__, dhd->pub.busstate, dhd->pub.dhd_bus_busy_state)); - } -#endif - - DHD_OS_WAKE_LOCK(&dhd->pub); - -#if defined(DHD_HANG_SEND_UP_TEST) - if (dhd->pub.req_hang_type == HANG_REASON_BUS_DOWN) { - DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__)); - dhd->pub.busstate = DHD_BUS_DOWN; - } -#endif /* DHD_HANG_SEND_UP_TEST */ - - /* Reject if down */ - /* XXX kernel panic issue when first bootup time, - * rmmod without interface down make unnecessary hang event. - */ - if (dhd->pub.hang_was_sent || DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(&dhd->pub)) { - DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", - __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); - dhd_tx_stop_queues(net); -#if defined(OEM_ANDROID) - /* Send Event when bus down detected during data session */ - if (dhd->pub.up && !dhd->pub.hang_was_sent && !DHD_BUS_CHECK_REMOVE(&dhd->pub)) { - DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); - dhd->pub.hang_reason = HANG_REASON_BUS_DOWN; - net_os_send_hang_message(net); - } -#endif /* OEM_ANDROID */ - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return NETDEV_TX_BUSY; - } - - ifp = DHD_DEV_IFP(net); - ifidx = DHD_DEV_IFIDX(net); -#ifdef DHD_BUZZZ_LOG_ENABLED - BUZZZ_LOG(START_XMIT_BGN, 2, (uint32)ifidx, (uintptr)skb); -#endif /* DHD_BUZZZ_LOG_ENABLED */ - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx)); - dhd_tx_stop_queues(net); - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return NETDEV_TX_BUSY; - } - - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - - /* If tput test is in progress */ - if (dhd->pub.tput_data.tput_test_running) { - return NETDEV_TX_BUSY; - } - - ASSERT(ifidx == dhd_net2idx(dhd, net)); - ASSERT((ifp != NULL) && ((ifidx < DHD_MAX_IFS) && (ifp == dhd->iflist[ifidx]))); - - bcm_object_trace_opr(skb, BCM_OBJDBG_ADD_PKT, __FUNCTION__, __LINE__); - - /* re-align socket buffer if "skb->data" is odd address */ - if (((unsigned long)(skb->data)) & 0x1) { - unsigned char *data = skb->data; - uint32 length = skb->len; - PKTPUSH(dhd->pub.osh, skb, 1); - memmove(skb->data, data, length); - PKTSETLEN(dhd->pub.osh, skb, length); - } - - datalen = PKTLEN(dhd->pub.osh, skb); - -#ifdef TPUT_MONITOR - if (dhd->pub.conf->tput_monitor_ms) { - dhd_os_sdlock_txq(&dhd->pub); - dhd->pub.conf->net_len += datalen; - dhd_os_sdunlock_txq(&dhd->pub); - if ((dhd->pub.conf->data_drop_mode == XMIT_DROP) && - (PKTLEN(dhd->pub.osh, skb) > 500)) { - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - } -#endif - /* Make sure there's enough room for any header */ -#if !defined(BCM_ROUTER_DHD) - if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) { - struct sk_buff *skb2; - - DHD_INFO(("%s: insufficient headroom\n", - dhd_ifname(&dhd->pub, ifidx))); - dhd->pub.tx_realloc++; - - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, __FUNCTION__, __LINE__); - skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz); - - dev_kfree_skb(skb); - if ((skb = skb2) == NULL) { - DHD_ERROR(("%s: skb_realloc_headroom failed\n", - dhd_ifname(&dhd->pub, ifidx))); - ret = -ENOMEM; - goto done; - } - bcm_object_trace_opr(skb, BCM_OBJDBG_ADD_PKT, __FUNCTION__, __LINE__); - } -#endif /* !BCM_ROUTER_DHD */ - - /* move from dhdsdio_sendfromq(), try to orphan skb early */ - if (dhd->pub.conf->orphan_move == 2) - PKTORPHAN(skb, dhd->pub.conf->tsq); - else if (dhd->pub.conf->orphan_move == 3) - skb_orphan(skb); - - /* Convert to packet */ - if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) { - DHD_ERROR(("%s: PKTFRMNATIVE failed\n", - dhd_ifname(&dhd->pub, ifidx))); - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, __FUNCTION__, __LINE__); - dev_kfree_skb_any(skb); - ret = -ENOMEM; - goto done; - } - -#ifdef DHD_WET - /* wet related packet proto manipulation should be done in DHD - since dongle doesn't have complete payload - */ - if (WET_ENABLED(&dhd->pub) && - (dhd_wet_send_proc(dhd->pub.wet_info, pktbuf, &pktbuf) < 0)) { - DHD_INFO(("%s:%s: wet send proc failed\n", - __FUNCTION__, dhd_ifname(&dhd->pub, ifidx))); - PKTFREE(dhd->pub.osh, pktbuf, FALSE); - ret = -EFAULT; - goto done; - } -#endif /* DHD_WET */ - -#ifdef DHD_WMF - eh = (struct ether_header *)PKTDATA(dhd->pub.osh, pktbuf); - iph = (uint8 *)eh + ETHER_HDR_LEN; - - /* WMF processing for multicast packets - * Only IPv4 packets are handled - */ - if (ifp->wmf.wmf_enable && (ntoh16(eh->ether_type) == ETHER_TYPE_IP) && - (IP_VER(iph) == IP_VER_4) && (ETHER_ISMULTI(eh->ether_dhost) || - ((IPV4_PROT(iph) == IP_PROT_IGMP) && dhd->pub.wmf_ucast_igmp))) { -#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) - void *sdu_clone; - bool ucast_convert = FALSE; -#ifdef DHD_UCAST_UPNP - uint32 dest_ip; - - dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET))); - ucast_convert = dhd->pub.wmf_ucast_upnp && MCAST_ADDR_UPNP_SSDP(dest_ip); -#endif /* DHD_UCAST_UPNP */ -#ifdef DHD_IGMP_UCQUERY - ucast_convert |= dhd->pub.wmf_ucast_igmp_query && - (IPV4_PROT(iph) == IP_PROT_IGMP) && - (*(iph + IPV4_HLEN(iph)) == IGMPV2_HOST_MEMBERSHIP_QUERY); -#endif /* DHD_IGMP_UCQUERY */ - if (ucast_convert) { - dhd_sta_t *sta; - unsigned long flags; - struct list_head snapshot_list; - struct list_head *wmf_ucforward_list; - - ret = NETDEV_TX_OK; - - /* For non BCM_GMAC3 platform we need a snapshot sta_list to - * resolve double DHD_IF_STA_LIST_LOCK call deadlock issue. - */ - wmf_ucforward_list = DHD_IF_WMF_UCFORWARD_LOCK(dhd, ifp, &snapshot_list); - - GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); - /* Convert upnp/igmp query to unicast for each assoc STA */ - list_for_each_entry(sta, wmf_ucforward_list, list) { - GCC_DIAGNOSTIC_POP(); - /* Skip sending to proxy interfaces of proxySTA */ - if (sta->psta_prim != NULL && !ifp->wmf_psta_disable) { - continue; - } - if ((sdu_clone = PKTDUP(dhd->pub.osh, pktbuf)) == NULL) { - ret = WMF_NOP; - break; - } - dhd_wmf_forward(ifp->wmf.wmfh, sdu_clone, 0, sta, 1); - } - DHD_IF_WMF_UCFORWARD_UNLOCK(dhd, wmf_ucforward_list); - - DHD_GENERAL_LOCK(&dhd->pub, flags); - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - if (ret == NETDEV_TX_OK) - PKTFREE(dhd->pub.osh, pktbuf, TRUE); - - return ret; - } else -#endif /* defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) */ - { - /* There will be no STA info if the packet is coming from LAN host - * Pass as NULL - */ - ret = dhd_wmf_packets_handle(&dhd->pub, pktbuf, NULL, ifidx, 0); - switch (ret) { - case WMF_TAKEN: - case WMF_DROP: - /* Either taken by WMF or we should drop it. - * Exiting send path - */ - - DHD_GENERAL_LOCK(&dhd->pub, flags); - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return NETDEV_TX_OK; - default: - /* Continue the transmit path */ - break; - } - } - } -#endif /* DHD_WMF */ -#ifdef DHD_PSTA - /* PSR related packet proto manipulation should be done in DHD - * since dongle doesn't have complete payload - */ - if (PSR_ENABLED(&dhd->pub) && -#ifdef BCM_ROUTER_DHD - !(ifp->primsta_dwds) && -#endif /* BCM_ROUTER_DHD */ - (dhd_psta_proc(&dhd->pub, ifidx, &pktbuf, TRUE) < 0)) { - - DHD_ERROR(("%s:%s: psta send proc failed\n", __FUNCTION__, - dhd_ifname(&dhd->pub, ifidx))); - } -#endif /* DHD_PSTA */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) && defined(DHD_TCP_PACING_SHIFT) -#ifndef DHD_DEFAULT_TCP_PACING_SHIFT -#define DHD_DEFAULT_TCP_PACING_SHIFT 7 -#endif /* DHD_DEFAULT_TCP_PACING_SHIFT */ - if (skb->sk) { - sk_pacing_shift_update(skb->sk, DHD_DEFAULT_TCP_PACING_SHIFT); - } -#endif /* LINUX_VERSION_CODE >= 4.19.0 && DHD_TCP_PACING_SHIFT */ - -#ifdef DHDTCPSYNC_FLOOD_BLK - if (dhd_tcpdata_get_flag(&dhd->pub, pktbuf) == FLAG_SYNCACK) { - ifp->tsyncack_txed ++; - } -#endif /* DHDTCPSYNC_FLOOD_BLK */ - -#ifdef DHDTCPACK_SUPPRESS - if (dhd->pub.tcpack_sup_mode == TCPACK_SUP_HOLD) { - /* If this packet has been hold or got freed, just return */ - if (dhd_tcpack_hold(&dhd->pub, pktbuf, ifidx)) { - ret = 0; - goto done; - } - } else { - /* If this packet has replaced another packet and got freed, just return */ - if (dhd_tcpack_suppress(&dhd->pub, pktbuf)) { - ret = 0; - goto done; - } - } -#endif /* DHDTCPACK_SUPPRESS */ - - /* - * If Load Balance is enabled queue the packet - * else send directly from here. - */ -#if defined(DHD_LB_TXP) - ret = dhd_lb_sendpkt(dhd, net, ifidx, pktbuf); -#else - ret = __dhd_sendpkt(&dhd->pub, ifidx, pktbuf); -#endif - -done: - /* XXX Bus modules may have different "native" error spaces? */ - /* XXX USB is native linux and it'd be nice to retain errno */ - /* XXX meaning, but SDIO is not so we'd need an OSL_ERROR. */ - if (ret) { - ifp->stats.tx_dropped++; - dhd->pub.tx_dropped++; - } else { -#ifdef PROP_TXSTATUS - /* tx_packets counter can counted only when wlfc is disabled */ - if (!dhd_wlfc_is_supported(&dhd->pub)) -#endif - { - dhd->pub.tx_packets++; - ifp->stats.tx_packets++; - ifp->stats.tx_bytes += datalen; - } - dhd->pub.actual_tx_pkts++; - } - - DHD_GENERAL_LOCK(&dhd->pub, flags); - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); - DHD_IF_CLR_TX_ACTIVE(ifp, DHD_TX_START_XMIT); - dhd_os_tx_completion_wake(&dhd->pub); - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_OS_WAKE_UNLOCK(&dhd->pub); -#ifdef DHD_BUZZZ_LOG_ENABLED - BUZZZ_LOG(START_XMIT_END, 0); -#endif /* DHD_BUZZZ_LOG_ENABLED */ - /* Return ok: we always eat the packet */ - return NETDEV_TX_OK; -} - #ifdef DHD_PCIE_NATIVE_RUNTIMEPM -void dhd_rx_wq_wakeup(struct work_struct *ptr) -{ - struct dhd_rx_tx_work *work; - struct dhd_pub * pub; - - work = container_of(ptr, struct dhd_rx_tx_work, work); - - pub = work->pub; - - DHD_RPM(("%s: ENTER. \n", __FUNCTION__)); - - if (atomic_read(&pub->block_bus) || pub->busstate == DHD_BUS_DOWN) { - return; - } - - DHD_OS_WAKE_LOCK(pub); - if (pm_runtime_get_sync(dhd_bus_to_dev(pub->bus)) >= 0) { - - // do nothing but wakeup the bus. - pm_runtime_mark_last_busy(dhd_bus_to_dev(pub->bus)); - pm_runtime_put_autosuspend(dhd_bus_to_dev(pub->bus)); - } - DHD_OS_WAKE_UNLOCK(pub); - kfree(work); -} - void dhd_start_xmit_wq_adapter(struct work_struct *ptr) { struct dhd_rx_tx_work *work; @@ -4757,68 +3840,6 @@ dhd_bus_wakeup_work(dhd_pub_t *dhdp) } #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ -static void -__dhd_txflowcontrol(dhd_pub_t *dhdp, struct net_device *net, bool state) -{ - if (state == ON) { - if (!netif_queue_stopped(net)) { - DHD_INFO(("%s: Stop Netif Queue\n", __FUNCTION__)); - netif_stop_queue(net); - } else { - DHD_INFO(("%s: Netif Queue already stopped\n", __FUNCTION__)); - } - } - - if (state == OFF) { - if (netif_queue_stopped(net)) { - DHD_INFO(("%s: Start Netif Queue\n", __FUNCTION__)); - netif_wake_queue(net); - } else { - DHD_INFO(("%s: Netif Queue already started\n", __FUNCTION__)); - } - } -} - -void -dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) -{ - struct net_device *net; - dhd_info_t *dhd = dhdp->info; - unsigned long flags; - int i; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(dhd); - -#ifdef DHD_LOSSLESS_ROAMING - /* block flowcontrol during roaming */ - if ((dhdp->dequeue_prec_map == (1 << dhdp->flow_prio_map[PRIO_8021D_NC])) && (state == ON)) - { - DHD_ERROR_RLMT(("%s: Roaming in progress, cannot stop network queue (0x%x:%d)\n", - __FUNCTION__, dhdp->dequeue_prec_map, dhdp->flow_prio_map[PRIO_8021D_NC])); - return; - } -#endif - - flags = dhd_os_sdlock_txoff(&dhd->pub); - if (ifidx == ALL_INTERFACES) { - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - net = dhd->iflist[i]->net; - __dhd_txflowcontrol(dhdp, net, state); - } - } - } else { - if (dhd->iflist[ifidx]) { - net = dhd->iflist[ifidx]->net; - __dhd_txflowcontrol(dhdp, net, state); - } - } - dhdp->txoff = state; - dhd_os_sdunlock_txoff(&dhd->pub, flags); -} - #if (defined(BCM_ROUTER_DHD) && defined(HNDCTF)) /* Dump CTF stats */ @@ -4937,16 +3958,6 @@ BCMFASTPATH(dhd_ctf_forward)(dhd_info_t *dhd, struct sk_buff *skb, void **pnext) } #endif /* BCM_ROUTER_DHD && HNDCTF */ -#ifdef DHD_WMF -bool -dhd_is_rxthread_enabled(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = dhdp->info; - - return dhd->rxthread_enabled; -} -#endif /* DHD_WMF */ - #ifdef DHD_MCAST_REGEN /* * Description: This function is called to do the reverse translation @@ -5012,18 +4023,6 @@ dhd_schedule_delayed_dpc_on_dpc_cpu(dhd_pub_t *dhdp, ulong delay) } #ifdef SHOW_LOGTRACE -static void -dhd_netif_rx_ni(struct sk_buff * skb) -{ - /* Do not call netif_recieve_skb as this workqueue scheduler is - * not from NAPI Also as we are not in INTR context, do not call - * netif_rx, instead call netif_rx_ni (for kerenl >= 2.6) which - * does netif_rx, disables irq, raise NET_IF_RX softirq and - * enables interrupts back - */ - netif_rx_ni(skb); -} - static int dhd_event_logtrace_pkt_process(dhd_pub_t *dhdp, struct sk_buff * skb) { @@ -5090,12 +4089,6 @@ dhd_event_logtrace_process_items(dhd_info_t *dhd) return 0; } -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE - /* Check if there is any update in the firmware trace buffer */ - process_fw_trace_data(dhdp); -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ qlen = skb_queue_len(&dhd->evt_trace_queue); process_len = MIN(qlen, DHD_EVENT_LOGTRACE_BOUND); @@ -5157,11 +4150,7 @@ dhd_event_logtrace_process_items(dhd_info_t *dhd) dhd_netif_rx_ni(skb); } else { /* Don't send up. Free up the packet. */ -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, skb, FALSE); -#else - PKTFREE(dhdp->osh, skb, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ + PKTFREE_CTRLBUF(dhdp->osh, skb, FALSE); } } @@ -5219,6 +4208,11 @@ dhd_logtrace_thread(void *data) } } while (ret > 0); } + /* Check terminated in case of dongle_reset */ + if (tsk->terminated) { + DHD_ERROR(("%s: task terminated\n", __FUNCTION__)); + goto exit; + } if (tsk->flush_ind) { DHD_ERROR(("%s: flushed\n", __FUNCTION__)); dhdp->logtrace_thr_ts.flush_time = OSL_LOCALTIME_NS(); @@ -5287,11 +4281,13 @@ void dhd_cancel_logtrace_process_sync(dhd_info_t *dhd) { #ifdef DHD_USE_KTHREAD_FOR_LOGTRACE - if (dhd->thr_logtrace_ctl.thr_pid >= 0) { - PROC_STOP_USING_BINARY_SEMA(&dhd->thr_logtrace_ctl); + tsk_ctl_t *tsk = &dhd->thr_logtrace_ctl; + + if (tsk->parent && tsk->thr_pid >= 0) { + PROC_STOP_USING_BINARY_SEMA(tsk); } else { - DHD_ERROR(("%s: thr_logtrace_ctl(%ld) not inited\n", __FUNCTION__, - dhd->thr_logtrace_ctl.thr_pid)); + DHD_ERROR(("%s: thr_logtrace_ctl(%ld) not inited\n", + __FUNCTION__, tsk->thr_pid)); } #else cancel_delayed_work_sync(&dhd->event_log_dispatcher_work); @@ -5362,7 +4358,8 @@ void dhd_event_logtrace_enqueue(dhd_pub_t *dhdp, int ifidx, void *pktbuf) { dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - + BCM_REFERENCE(dhd); +#if 1 #ifdef PCIE_FULL_DONGLE /* Add ifidx in the PKTTAG */ DHD_PKTTAG_SET_IFID((dhd_pkttag_fr_t *)PKTTAG(pktbuf), ifidx); @@ -5370,23 +4367,15 @@ dhd_event_logtrace_enqueue(dhd_pub_t *dhdp, int ifidx, void *pktbuf) skb_queue_tail(&dhd->evt_trace_queue, pktbuf); dhd_schedule_logtrace(dhd); +#else /* !BCMDBUS */ +#ifdef DHD_USE_STATIC_CTRLBUF + PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); +#else + PKTFREE(dhdp->osh, pktbuf, FALSE); +#endif /* DHD_USE_STATIC_CTRLBUF */ +#endif /* BCMDBUS */ } -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE -void -dhd_event_logtrace_enqueue_fwtrace(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = (dhd_info_t *) dhdp->info; - - /* Schedule a kernel thread */ - dhd_schedule_logtrace(dhd); - - return; -} -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ - void dhd_event_logtrace_flush_queue(dhd_pub_t *dhdp) { @@ -5394,11 +4383,7 @@ dhd_event_logtrace_flush_queue(dhd_pub_t *dhdp) struct sk_buff *skb; while ((skb = skb_dequeue(&dhd->evt_trace_queue)) != NULL) { -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, skb, FALSE); -#else - PKTFREE(dhdp->osh, skb, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ + PKTFREE_CTRLBUF(dhdp->osh, skb, FALSE); } } @@ -5439,56 +4424,6 @@ dhd_sendup_info_buf(dhd_pub_t *dhdp, uint8 *msg) #endif /* EWP_EDL */ #endif /* SHOW_LOGTRACE */ -#ifdef BTLOG -static void -dhd_bt_log_process(struct work_struct *work) -{ - struct dhd_info *dhd; - dhd_pub_t *dhdp; - struct sk_buff *skb; - - /* Ignore compiler warnings due to -Werror=cast-qual */ - GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); - dhd = container_of(work, struct dhd_info, bt_log_dispatcher_work); - GCC_DIAGNOSTIC_POP(); - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - dhdp = &dhd->pub; - - if (!dhdp) { - DHD_ERROR(("%s: dhd pub is null \n", __FUNCTION__)); - return; - } - - DHD_TRACE(("%s:Enter\n", __FUNCTION__)); - - /* Run while(1) loop till all skbs are dequeued */ - while ((skb = skb_dequeue(&dhd->bt_log_queue)) != NULL) { - dhd_bt_log_pkt_process(dhdp, skb); -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, skb, FALSE); -#else - PKTFREE(dhdp->osh, skb, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ - } -} - -void -dhd_rx_bt_log(dhd_pub_t *dhdp, void *pkt) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - - skb_queue_tail(&dhd->bt_log_queue, pkt); - - /* schedule workqueue to process bt logs */ - schedule_work(&dhd->bt_log_dispatcher_work); -} -#endif /* BTLOG */ - #ifdef EWP_EDL static void dhd_edl_process_work(struct work_struct *work) @@ -5512,63 +4447,6 @@ dhd_schedule_edl_work(dhd_pub_t *dhdp, uint delay_ms) } #endif /* EWP_EDL */ -#ifdef WL_NANHO -/* forward NAN event to NANHO host module. API returns TRUE if event is consumed by NANHO */ -static bool -dhd_nho_evt_process(dhd_pub_t *pub, int ifidx, wl_event_msg_t *evt_msg, - void *pktdata, uint16 pktlen) -{ - uint32 evt_type = ntoh32_ua(&evt_msg->event_type); - bool consumed = FALSE; - - if ((evt_type == WLC_E_NAN_CRITICAL) || (evt_type == WLC_E_NAN_NON_CRITICAL)) { - bcm_event_t *pvt_data = (bcm_event_t *)pktdata; - uint32 event_len = sizeof(wl_event_msg_t) + ntoh32_ua(&evt_msg->datalen); - - bcm_nanho_evt(pub->nanhoi, &pvt_data->event, event_len, &consumed); - } - return consumed; -} - -static int -dhd_nho_evt_cb(void *drv_ctx, int ifidx, bcm_event_t *evt, uint16 evt_len) -{ - struct sk_buff *p, *skb; - dhd_if_t *ifp; - dhd_pub_t *dhdp = (dhd_pub_t *)drv_ctx; - - if ((p = PKTGET(dhdp->osh, evt_len, FALSE))) { - memcpy(PKTDATA(dhdp->osh, p), (uint8 *)evt, evt_len); - skb = PKTTONATIVE(dhdp->osh, p); - - ifp = dhdp->info->iflist[ifidx]; - if (ifp == NULL) { - /* default to main interface */ - ifp = dhdp->info->iflist[0]; - } - ASSERT(ifp); - - skb->dev = ifp->net; - skb->protocol = eth_type_trans(skb, skb->dev); - - /* strip header, count, deliver upward */ - skb_pull(skb, ETH_HLEN); - - /* send the packet */ - if (in_interrupt()) { - netif_rx(skb); - } else { - netif_rx_ni(skb); - } - } else { - DHD_ERROR(("NHO: dhd_nho_evt_cb: unable to alloc sk_buf")); - return BCME_NOMEM; - } - - return BCME_OK; -} -#endif /* WL_NANHO */ - #ifdef ENABLE_WAKEUP_PKT_DUMP static void update_wake_pkt_info(struct sk_buff *skb) @@ -5680,7 +4558,7 @@ dhd_check_shinfo_nrfrags(dhd_pub_t *dhdp, void *pktbuf, shinfo->nr_frags, (uint)skb, (uint)(skb->data), (uint)(skb->head), (uint)(skb->tail), (uint)(skb->end), skb->len, (uint)shinfo, pktid)); -#endif +#endif /* BCMDMA64OSL */ prhex("shinfo", (char*)shinfo, sizeof(struct skb_shared_info)); if (!dhd_query_bus_erros(dhdp)) { #ifdef DHD_FW_COREDUMP @@ -5706,871 +4584,6 @@ dhd_check_shinfo_nrfrags(dhd_pub_t *dhdp, void *pktbuf, } #endif /* BCMPCIE */ -/** Called when a frame is received by the dongle on interface 'ifidx' */ -void -dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - struct sk_buff *skb; - uchar *eth; - uint len; - void *data, *pnext = NULL; - int i; - dhd_if_t *ifp; - wl_event_msg_t event; -#if defined(OEM_ANDROID) - int tout_rx = 0; - int tout_ctrl = 0; -#endif /* OEM_ANDROID */ - void *skbhead = NULL; - void *skbprev = NULL; - uint16 protocol; - unsigned char *dump_data; -#ifdef DHD_MCAST_REGEN - uint8 interface_role; - if_flow_lkup_t *if_flow_lkup; - unsigned long flags; -#endif -#ifdef DHD_WAKE_STATUS - wake_counts_t *wcp = NULL; -#endif /* DHD_WAKE_STATUS */ - int pkt_wake = 0; -#ifdef ENABLE_DHD_GRO - bool dhd_gro_enable = TRUE; - struct Qdisc *qdisc = NULL; -#endif /* ENABLE_DHD_GRO */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - BCM_REFERENCE(dump_data); - BCM_REFERENCE(pkt_wake); - -#ifdef DHD_TPUT_PATCH - if (dhdp->conf->pktsetsum) - PKTSETSUMGOOD(pktbuf, TRUE); -#endif - -#ifdef ENABLE_DHD_GRO - if (ifidx < DHD_MAX_IFS) { - ifp = dhd->iflist[ifidx]; - if (ifp && ifp->net->qdisc) { - if (ifp->net->qdisc->ops->cl_ops) { - dhd_gro_enable = FALSE; - DHD_TRACE(("%s: disable sw gro becasue of" - " qdisc tx traffic control\n", __FUNCTION__)); - } - - if (dev_ingress_queue(ifp->net)) { - qdisc = dev_ingress_queue(ifp->net)->qdisc_sleeping; - if (qdisc != NULL && (qdisc->flags & TCQ_F_INGRESS)) { - dhd_gro_enable = FALSE; - DHD_TRACE(("%s: disable sw gro because of" - " qdisc rx traffic control\n", __FUNCTION__)); - } - } - } - } -#ifdef DHD_GRO_ENABLE_HOST_CTRL - if (!dhdp->permitted_gro && dhd_gro_enable) { - dhd_gro_enable = FALSE; - } -#endif /* DHD_GRO_ENABLE_HOST_CTRL */ -#endif /* ENABLE_DHD_GRO */ - - for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { - struct ether_header *eh; - - pnext = PKTNEXT(dhdp->osh, pktbuf); - PKTSETNEXT(dhdp->osh, pktbuf, NULL); - - /* info ring "debug" data, which is not a 802.3 frame, is sent/hacked with a - * special ifidx of DHD_DUMMY_INFO_IF. This is just internal to dhd to get the data - * from dhd_msgbuf.c:dhd_prot_infobuf_cmplt_process() to here (dhd_rx_frame). - */ - if (ifidx == DHD_DUMMY_INFO_IF) { - /* Event msg printing is called from dhd_rx_frame which is in Tasklet - * context in case of PCIe FD, in case of other bus this will be from - * DPC context. If we get bunch of events from Dongle then printing all - * of them from Tasklet/DPC context that too in data path is costly. - * Also in the new Dongle SW(4359, 4355 onwards) console prints too come as - * events with type WLC_E_TRACE. - * We'll print this console logs from the WorkQueue context by enqueing SKB - * here and Dequeuing will be done in WorkQueue and will be freed only if - * logtrace_pkt_sendup is TRUE - */ -#ifdef SHOW_LOGTRACE - dhd_event_logtrace_enqueue(dhdp, ifidx, pktbuf); -#else /* !SHOW_LOGTRACE */ - /* If SHOW_LOGTRACE not defined and ifidx is DHD_DUMMY_INFO_IF, - * free the PKT here itself - */ -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ -#endif /* SHOW_LOGTRACE */ - continue; - } -#ifdef DHD_WAKE_STATUS -#ifdef BCMDBUS - wcp = NULL; -#else - pkt_wake = dhd_bus_get_bus_wake(dhdp); - wcp = dhd_bus_get_wakecount(dhdp); -#endif /* BCMDBUS */ - if (wcp == NULL) { - /* If wakeinfo count buffer is null do not update wake count values */ - pkt_wake = 0; - } -#endif /* DHD_WAKE_STATUS */ - - eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); -#ifdef DHD_AWDL - if (dhdp->awdl_llc_enabled && - dhdp->awdl_ifidx && ifidx == dhdp->awdl_ifidx) { - if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) { - dhd_awdl_llc_to_eth_hdr(dhdp, eh, pktbuf); - } - } -#endif /* DHD_AWDL */ - - if (dhd->pub.tput_data.tput_test_running && - dhd->pub.tput_data.direction == TPUT_DIR_RX && - ntoh16(eh->ether_type) == ETHER_TYPE_IP) { - dhd_tput_test_rx(dhdp, pktbuf); - PKTFREE(dhd->pub.osh, pktbuf, FALSE); - continue; - } - - if (ifidx >= DHD_MAX_IFS) { - DHD_ERROR(("%s: ifidx(%d) Out of bound. drop packet\n", - __FUNCTION__, ifidx)); - if (ntoh16(eh->ether_type) == ETHER_TYPE_BRCM) { -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ - } else { - PKTCFREE(dhdp->osh, pktbuf, FALSE); - } - continue; - } - - ifp = dhd->iflist[ifidx]; - if (ifp == NULL) { - DHD_ERROR_RLMT(("%s: ifp is NULL. drop packet\n", - __FUNCTION__)); - if (ntoh16(eh->ether_type) == ETHER_TYPE_BRCM) { -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ - } else { - PKTCFREE(dhdp->osh, pktbuf, FALSE); - } - continue; - } - - /* Dropping only data packets before registering net device to avoid kernel panic */ -#ifndef PROP_TXSTATUS_VSDB - if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) && - (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) -#else - if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) && - (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) -#endif /* PROP_TXSTATUS_VSDB */ - { - DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n", - __FUNCTION__)); - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - -#ifdef PROP_TXSTATUS - if (dhd_wlfc_is_header_only_pkt(dhdp, pktbuf)) { - /* WLFC may send header only packet when - there is an urgent message but no packet to - piggy-back on - */ - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } -#endif -#ifdef DHD_L2_FILTER - /* If block_ping is enabled drop the ping packet */ - if (ifp->block_ping) { - if (bcm_l2_filter_block_ping(dhdp->osh, pktbuf) == BCME_OK) { - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - } - if (ifp->grat_arp && DHD_IF_ROLE_STA(dhdp, ifidx)) { - if (bcm_l2_filter_gratuitous_arp(dhdp->osh, pktbuf) == BCME_OK) { - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - } - if (ifp->parp_enable && DHD_IF_ROLE_AP(dhdp, ifidx)) { - int ret = dhd_l2_filter_pkt_handle(dhdp, ifidx, pktbuf, FALSE); - - /* Drop the packets if l2 filter has processed it already - * otherwise continue with the normal path - */ - if (ret == BCME_OK) { - PKTCFREE(dhdp->osh, pktbuf, TRUE); - continue; - } - } - if (ifp->block_tdls) { - if (bcm_l2_filter_block_tdls(dhdp->osh, pktbuf) == BCME_OK) { - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - } -#endif /* DHD_L2_FILTER */ - -#ifdef DHD_MCAST_REGEN - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - ASSERT(if_flow_lkup); - - interface_role = if_flow_lkup[ifidx].role; - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - - if (ifp->mcast_regen_bss_enable && (interface_role != WLC_E_IF_ROLE_WDS) && - !DHD_IF_ROLE_AP(dhdp, ifidx) && - ETHER_ISUCAST(eh->ether_dhost)) { - if (dhd_mcast_reverse_translation(eh) == BCME_OK) { -#ifdef DHD_PSTA - /* Change bsscfg to primary bsscfg for unicast-multicast packets */ - if ((dhd_get_psta_mode(dhdp) == DHD_MODE_PSTA) || - (dhd_get_psta_mode(dhdp) == DHD_MODE_PSR)) { - if (ifidx != 0) { - /* Let the primary in PSTA interface handle this - * frame after unicast to Multicast conversion - */ - ifp = dhd_get_ifp(dhdp, 0); - ASSERT(ifp); - } - } - } -#endif /* PSTA */ - } -#endif /* MCAST_REGEN */ - -#ifdef DHD_WMF - /* WMF processing for multicast packets */ - if (ifp->wmf.wmf_enable && (ETHER_ISMULTI(eh->ether_dhost))) { - dhd_sta_t *sta; - int ret; - - sta = dhd_find_sta(dhdp, ifidx, (void *)eh->ether_shost); - ret = dhd_wmf_packets_handle(dhdp, pktbuf, sta, ifidx, 1); - switch (ret) { - case WMF_TAKEN: - /* The packet is taken by WMF. Continue to next iteration */ - continue; - case WMF_DROP: - /* Packet DROP decision by WMF. Toss it */ - DHD_ERROR(("%s: WMF decides to drop packet\n", - __FUNCTION__)); - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - default: - /* Continue the transmit path */ - break; - } - } -#endif /* DHD_WMF */ - -#ifdef DHDTCPSYNC_FLOOD_BLK - if (dhd_tcpdata_get_flag(dhdp, pktbuf) == FLAG_SYNC) { - int delta_sec; - int delta_sync; - int sync_per_sec; - u64 curr_time = DIV_U64_BY_U32(OSL_LOCALTIME_NS(), NSEC_PER_SEC); - ifp->tsync_rcvd ++; - delta_sync = ifp->tsync_rcvd - ifp->tsyncack_txed; - delta_sec = curr_time - ifp->last_sync; - if (delta_sec > 1) { - sync_per_sec = delta_sync/delta_sec; - if (sync_per_sec > TCP_SYNC_FLOOD_LIMIT) { - schedule_work(&ifp->blk_tsfl_work); - DHD_ERROR(("ifx %d TCP SYNC Flood attack suspected! " - "sync recvied %d pkt/sec \n", - ifidx, sync_per_sec)); - ifp->tsync_per_sec = sync_per_sec; - } - dhd_reset_tcpsync_info_by_ifp(ifp); - } - - } -#endif /* DHDTCPSYNC_FLOOD_BLK */ - -#ifdef DHDTCPACK_SUPPRESS - dhd_tcpdata_info_get(dhdp, pktbuf); -#endif - skb = PKTTONATIVE(dhdp->osh, pktbuf); - - ASSERT(ifp); - skb->dev = ifp->net; -#ifdef DHD_WET - /* wet related packet proto manipulation should be done in DHD - * since dongle doesn't have complete payload - */ - if (WET_ENABLED(&dhd->pub) && (dhd_wet_recv_proc(dhd->pub.wet_info, - pktbuf) < 0)) { - DHD_INFO(("%s:%s: wet recv proc failed\n", - __FUNCTION__, dhd_ifname(dhdp, ifidx))); - } -#endif /* DHD_WET */ - -#ifdef DHD_PSTA - if (PSR_ENABLED(dhdp) && -#ifdef BCM_ROUTER_DHD - !(ifp->primsta_dwds) && -#endif /* BCM_ROUTER_DHD */ - (dhd_psta_proc(dhdp, ifidx, &pktbuf, FALSE) < 0)) { - DHD_ERROR(("%s:%s: psta recv proc failed\n", __FUNCTION__, - dhd_ifname(dhdp, ifidx))); - } -#endif /* DHD_PSTA */ - -#if defined(BCM_ROUTER_DHD) - /* XXX Use WOFA for both dhdap and dhdap-atlas router. */ - /* XXX dhd_sendpkt verify pkt accounting (TO/FRM NATIVE) and PKTCFREE */ - - if (DHD_IF_ROLE_AP(dhdp, ifidx) && (!ifp->ap_isolate)) { - eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); - if (ETHER_ISUCAST(eh->ether_dhost)) { - if (dhd_find_sta(dhdp, ifidx, (void *)eh->ether_dhost)) { - dhd_sendpkt(dhdp, ifidx, pktbuf); - continue; - } - } else { - void *npkt; -#if defined(HNDCTF) - if (PKTISCHAINED(pktbuf)) { /* XXX WAR */ - DHD_ERROR(("Error: %s():%d Chained non unicast pkt<%p>\n", - __FUNCTION__, __LINE__, pktbuf)); - PKTFRMNATIVE(dhdp->osh, pktbuf); - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } -#endif /* HNDCTF */ - if ((ntoh16(eh->ether_type) != ETHER_TYPE_IAPP_L2_UPDATE) && - ((npkt = PKTDUP(dhdp->osh, pktbuf)) != NULL)) - dhd_sendpkt(dhdp, ifidx, npkt); - } - } - -#if defined(HNDCTF) - /* try cut thru' before sending up */ - if (dhd_ctf_forward(dhd, skb, &pnext) == BCME_OK) { - continue; - } -#endif /* HNDCTF */ - -#else /* !BCM_ROUTER_DHD */ -#ifdef PCIE_FULL_DONGLE - if ((DHD_IF_ROLE_AP(dhdp, ifidx) || DHD_IF_ROLE_P2PGO(dhdp, ifidx)) && - (!ifp->ap_isolate)) { - eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); - if (ETHER_ISUCAST(eh->ether_dhost)) { - if (dhd_find_sta(dhdp, ifidx, (void *)eh->ether_dhost)) { - dhd_sendpkt(dhdp, ifidx, pktbuf); - continue; - } - } else { - if ((ntoh16(eh->ether_type) != ETHER_TYPE_IAPP_L2_UPDATE)) { - void *npktbuf = NULL; - /* - * If host_sfhllc_supported enabled, do skb_copy as SFHLLC - * header will be inserted during Tx, due to which network - * stack will not decode the Rx packet. - * Else PKTDUP(skb_clone) is enough. - */ - if (dhdp->host_sfhllc_supported) { - npktbuf = skb_copy(skb, GFP_ATOMIC); - } else { - npktbuf = PKTDUP(dhdp->osh, pktbuf); - } - if (npktbuf != NULL) { - dhd_sendpkt(dhdp, ifidx, npktbuf); - } - } - } - } -#endif /* PCIE_FULL_DONGLE */ -#endif /* BCM_ROUTER_DHD */ -#ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT - if (IS_STA_IFACE(ndev_to_wdev(ifp->net)) && - (ifp->recv_reassoc_evt == TRUE) && (ifp->post_roam_evt == FALSE) && - (dhd_is_4way_msg((char *)(skb->data)) == EAPOL_4WAY_M1)) { - DHD_ERROR(("%s: Reassoc is in progress. " - "Drop EAPOL M1 frame\n", __FUNCTION__)); - PKTFREE(dhdp->osh, pktbuf, FALSE); - continue; - } -#endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */ -#ifdef WLEASYMESH - if ((dhdp->conf->fw_type == FW_TYPE_EZMESH) && - (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) { - uint16 * da = (uint16 *)(eh->ether_dhost); - ASSERT(ISALIGNED(da, 2)); - - /* XXX: Special handling for 1905 messages - * if DA matches with configured 1905 AL MAC addresses - * bypass fwder and foward it to linux stack - */ - if (ntoh16(eh->ether_type) == ETHER_TYPE_1905_1) { - if (!eacmp(da, ifp->_1905_al_ucast) || !eacmp(da, ifp->_1905_al_mcast)) { - //skb->fwr_flood = 0; - } else { - //skb->fwr_flood = 1; - } - } - } -#endif /* WLEASYMESH */ - /* Get the protocol, maintain skb around eth_type_trans() - * The main reason for this hack is for the limitation of - * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len' - * to perform skb_pull inside vs ETH_HLEN. Since to avoid - * coping of the packet coming from the network stack to add - * BDC, Hardware header etc, during network interface registration - * we set the 'net->hard_header_len' to ETH_HLEN + extra space required - * for BDC, Hardware header etc. and not just the ETH_HLEN - */ - eth = skb->data; - len = skb->len; - dump_data = skb->data; - protocol = (skb->data[12] << 8) | skb->data[13]; - - if (protocol == ETHER_TYPE_802_1X) { - DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED); -#if defined(WL_CFG80211) && defined(WL_WPS_SYNC) - wl_handle_wps_states(ifp->net, dump_data, len, FALSE); -#endif /* WL_CFG80211 && WL_WPS_SYNC */ -#ifdef DHD_4WAYM4_FAIL_DISCONNECT - if (dhd_is_4way_msg((uint8 *)(skb->data)) == EAPOL_4WAY_M3) { - OSL_ATOMIC_SET(dhdp->osh, &ifp->m4state, M3_RXED); - } -#endif /* DHD_4WAYM4_FAIL_DISCONNECT */ -#ifdef EAPOL_RESEND - wl_ext_release_eapol_txpkt(dhdp, ifidx, TRUE); -#endif /* EAPOL_RESEND */ - } - dhd_dump_pkt(dhdp, ifidx, dump_data, len, FALSE, NULL, NULL); - -#if defined(DHD_WAKE_STATUS) && defined(DHD_WAKEPKT_DUMP) - if (pkt_wake) { - dhd_prhex("[wakepkt_dump]", (char*)dump_data, MIN(len, 64), DHD_ERROR_VAL); - DHD_ERROR(("config check in_suspend: %d ", dhdp->in_suspend)); -#ifdef ARP_OFFLOAD_SUPPORT - DHD_ERROR(("arp hmac_update:%d \n", dhdp->hmac_updated)); -#endif /* ARP_OFFLOAD_SUPPORT */ - } -#endif /* DHD_WAKE_STATUS && DHD_WAKEPKT_DUMP */ - -#ifdef BCMINTERNAL - if (dhd->pub.loopback) { - struct ether_header *local_eh = (struct ether_header *)eth; - if (ntoh16(local_eh->ether_type) == ETHER_TYPE_IP) { - uint8 *myp = (uint8 *)local_eh; - struct ipv4_hdr *iph = (struct ipv4_hdr *)(myp + ETHER_HDR_LEN); - uint16 iplen = (iph->version_ihl & 0xf) * sizeof(uint32); - if (iph->prot == 1) { - uint8 *icmph = (uint8 *)iph + iplen; - if (icmph[0] == 8) { - uint8 temp_addr[ETHER_ADDR_LEN]; - uint8 temp_ip[IPV4_ADDR_LEN]; - /* Ether header flip */ - memcpy(temp_addr, local_eh->ether_dhost, - ETHER_ADDR_LEN); - memcpy(local_eh->ether_dhost, - local_eh->ether_shost, ETHER_ADDR_LEN); - memcpy(local_eh->ether_shost, temp_addr, - ETHER_ADDR_LEN); - - /* IP header flip */ - memcpy(temp_ip, iph->src_ip, IPV4_ADDR_LEN); - memcpy(iph->src_ip, iph->dst_ip, IPV4_ADDR_LEN); - memcpy(iph->dst_ip, temp_ip, IPV4_ADDR_LEN); - - /* ICMP header flip */ - icmph[0] = 0; - } - } else if (iph->prot == 17) { - uint8 *udph = (uint8 *)iph + iplen; - uint16 destport = ntoh16(*((uint16 *)udph + 1)); - if (destport == 8888) { - uint8 temp_addr[ETHER_ADDR_LEN]; - uint8 temp_ip[IPV4_ADDR_LEN]; - /* Ether header flip */ - memcpy(temp_addr, local_eh->ether_dhost, - ETHER_ADDR_LEN); - memcpy(local_eh->ether_dhost, - local_eh->ether_shost, ETHER_ADDR_LEN); - memcpy(local_eh->ether_shost, temp_addr, - ETHER_ADDR_LEN); - - /* IP header flip */ - memcpy(temp_ip, iph->src_ip, IPV4_ADDR_LEN); - memcpy(iph->src_ip, iph->dst_ip, IPV4_ADDR_LEN); - memcpy(iph->dst_ip, temp_ip, IPV4_ADDR_LEN); - - /* Reset UDP checksum to */ - *((uint16 *)udph + 3) = 0; - } - } - } - } -#endif /* BCMINTERNAL */ - skb->protocol = eth_type_trans(skb, skb->dev); - - if (skb->pkt_type == PACKET_MULTICAST) { - dhd->pub.rx_multicast++; - ifp->stats.multicast++; - } - - skb->data = eth; - skb->len = len; - - /* TODO: XXX: re-look into dropped packets. */ - DHD_DBG_PKT_MON_RX(dhdp, skb); - /* Strip header, count, deliver upward */ - skb_pull(skb, ETH_HLEN); - -#ifdef ENABLE_WAKEUP_PKT_DUMP - if (dhd_mmc_wake) { - DHD_INFO(("wake_pkt %s(%d)\n", __FUNCTION__, __LINE__)); - if (DHD_INFO_ON()) { - prhex("wake_pkt", (char*) eth, MIN(len, 48)); - } - update_wake_pkt_info(skb); -#ifdef CONFIG_IRQ_HISTORY - add_irq_history(0, "WIFI"); -#endif - dhd_mmc_wake = FALSE; - } -#endif /* ENABLE_WAKEUP_PKT_DUMP */ - - /* Process special event packets and then discard them */ - /* XXX Decide on a better way to fit this in */ - memset(&event, 0, sizeof(event)); - - if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) { - bcm_event_msg_u_t evu; - int ret_event, event_type; - void *pkt_data = skb_mac_header(skb); - - ret_event = wl_host_event_get_data(pkt_data, len, &evu); - - if (ret_event != BCME_OK) { - DHD_ERROR(("%s: wl_host_event_get_data err = %d\n", - __FUNCTION__, ret_event)); -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif - continue; - } - - memcpy(&event, &evu.event, sizeof(wl_event_msg_t)); - event_type = ntoh32_ua((void *)&event.event_type); -#ifdef SHOW_LOGTRACE - /* Event msg printing is called from dhd_rx_frame which is in Tasklet - * context in case of PCIe FD, in case of other bus this will be from - * DPC context. If we get bunch of events from Dongle then printing all - * of them from Tasklet/DPC context that too in data path is costly. - * Also in the new Dongle SW(4359, 4355 onwards) console prints too come as - * events with type WLC_E_TRACE. - * We'll print this console logs from the WorkQueue context by enqueing SKB - * here and Dequeuing will be done in WorkQueue and will be freed only if - * logtrace_pkt_sendup is true - */ - if (event_type == WLC_E_TRACE) { - DHD_TRACE(("%s: WLC_E_TRACE\n", __FUNCTION__)); - dhd_event_logtrace_enqueue(dhdp, ifidx, pktbuf); - continue; - } -#endif /* SHOW_LOGTRACE */ - -#ifdef WL_NANHO - /* Process firmware NAN event by NANHO host module */ - if (dhd_nho_evt_process(dhdp, ifidx, &event, pkt_data, len)) { - /* NANHO host module consumed NAN event. free pkt here. */ -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif - continue; - } -#endif /* WL_NANHO */ - - ret_event = dhd_wl_host_event(dhd, ifidx, pkt_data, len, &event, &data); - - wl_event_to_host_order(&event); -#if defined(OEM_ANDROID) - if (!tout_ctrl) - tout_ctrl = DHD_PACKET_TIMEOUT_MS; -#endif /* OEM_ANDROID */ - -#if (defined(OEM_ANDROID) && defined(PNO_SUPPORT)) - if (event_type == WLC_E_PFN_NET_FOUND) { - /* enforce custom wake lock to garantee that Kernel not suspended */ - tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS; - } -#endif /* PNO_SUPPORT */ - if (numpkt != 1) { - DHD_TRACE(("%s: Got BRCM event packet in a chained packet.\n", - __FUNCTION__)); - } - -#ifdef DHD_WAKE_STATUS - if (unlikely(pkt_wake)) { -#ifdef DHD_WAKE_EVENT_STATUS - if (event.event_type < WLC_E_LAST) { - wcp->rc_event[event.event_type]++; - wcp->rcwake++; - pkt_wake = 0; - } -#endif /* DHD_WAKE_EVENT_STATUS */ - } -#endif /* DHD_WAKE_STATUS */ - - /* For delete virtual interface event, wl_host_event returns positive - * i/f index, do not proceed. just free the pkt. - */ - if ((event_type == WLC_E_IF) && (ret_event > 0)) { - DHD_ERROR(("%s: interface is deleted. Free event packet\n", - __FUNCTION__)); -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif - continue; - } - - /* - * For the event packets, there is a possibility - * of ifidx getting modifed.Thus update the ifp - * once again. - */ - ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); - ifp = dhd->iflist[ifidx]; -#ifndef PROP_TXSTATUS_VSDB - if (!(ifp && ifp->net && (ifp->net->reg_state == NETREG_REGISTERED))) -#else - if (!(ifp && ifp->net && (ifp->net->reg_state == NETREG_REGISTERED) && - dhd->pub.up)) -#endif /* PROP_TXSTATUS_VSDB */ - { - DHD_ERROR(("%s: net device is NOT registered. drop event packet\n", - __FUNCTION__)); -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif - continue; - } - -#ifdef SENDPROB - if (dhdp->wl_event_enabled || - (dhdp->recv_probereq && (event.event_type == WLC_E_PROBREQ_MSG))) -#else - if (dhdp->wl_event_enabled) -#endif - { -#ifdef DHD_USE_STATIC_CTRLBUF - /* If event bufs are allocated via static buf pool - * and wl events are enabled, make a copy, free the - * local one and send the copy up. - */ - struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); - /* Copy event and send it up */ - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); - if (nskb) { - skb = nskb; - } else { - DHD_ERROR(("skb clone failed. dropping event.\n")); - continue; - } -#endif /* DHD_USE_STATIC_CTRLBUF */ - } else { - /* If event enabled not explictly set, drop events */ -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ - continue; - } - } else { -#if defined(OEM_ANDROID) - tout_rx = DHD_PACKET_TIMEOUT_MS; -#endif /* OEM_ANDROID */ - -#ifdef PROP_TXSTATUS - dhd_wlfc_save_rxpath_ac_time(dhdp, (uint8)PKTPRIO(skb)); -#endif /* PROP_TXSTATUS */ - -#ifdef DHD_WAKE_STATUS - if (unlikely(pkt_wake)) { - wcp->rxwake++; -#ifdef DHD_WAKE_RX_STATUS -#define ETHER_ICMP6_HEADER 20 -#define ETHER_IPV6_SADDR (ETHER_ICMP6_HEADER + 2) -#define ETHER_IPV6_DAADR (ETHER_IPV6_SADDR + IPV6_ADDR_LEN) -#define ETHER_ICMPV6_TYPE (ETHER_IPV6_DAADR + IPV6_ADDR_LEN) - - if (ntoh16(skb->protocol) == ETHER_TYPE_ARP) /* ARP */ - wcp->rx_arp++; - if (dump_data[0] == 0xFF) { /* Broadcast */ - wcp->rx_bcast++; - } else if (dump_data[0] & 0x01) { /* Multicast */ - wcp->rx_mcast++; - if (ntoh16(skb->protocol) == ETHER_TYPE_IPV6) { - wcp->rx_multi_ipv6++; - if ((skb->len > ETHER_ICMP6_HEADER) && - (dump_data[ETHER_ICMP6_HEADER] == IPPROTO_ICMPV6)) { - wcp->rx_icmpv6++; - if (skb->len > ETHER_ICMPV6_TYPE) { - switch (dump_data[ETHER_ICMPV6_TYPE]) { - case NDISC_ROUTER_ADVERTISEMENT: - wcp->rx_icmpv6_ra++; - break; - case NDISC_NEIGHBOUR_ADVERTISEMENT: - wcp->rx_icmpv6_na++; - break; - case NDISC_NEIGHBOUR_SOLICITATION: - wcp->rx_icmpv6_ns++; - break; - } - } - } - } else if (dump_data[2] == 0x5E) { - wcp->rx_multi_ipv4++; - } else { - wcp->rx_multi_other++; - } - } else { /* Unicast */ - wcp->rx_ucast++; - } -#undef ETHER_ICMP6_HEADER -#undef ETHER_IPV6_SADDR -#undef ETHER_IPV6_DAADR -#undef ETHER_ICMPV6_TYPE -#endif /* DHD_WAKE_RX_STATUS */ - pkt_wake = 0; - } -#endif /* DHD_WAKE_STATUS */ - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) - ifp->net->last_rx = jiffies; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) */ - - if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { - dhdp->dstats.rx_bytes += skb->len; - dhdp->rx_packets++; /* Local count */ - ifp->stats.rx_bytes += skb->len; - ifp->stats.rx_packets++; - } -#if defined(DHD_TCP_WINSIZE_ADJUST) - if (dhd_use_tcp_window_size_adjust) { - if (ifidx == 0 && ntoh16(skb->protocol) == ETHER_TYPE_IP) { - dhd_adjust_tcp_winsize(dhdp->op_mode, skb); - } - } -#endif /* DHD_TCP_WINSIZE_ADJUST */ - - /* XXX WL here makes sure data is 4-byte aligned? */ - if (in_interrupt()) { - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); -#if defined(DHD_LB_RXP) -#ifdef ENABLE_DHD_GRO - /* The pktlog module clones a skb using skb_clone and - * stores the skb point to the ring buffer of the pktlog module. - * Once the buffer is full, - * the PKTFREE is called for removing the oldest skb. - * The kernel panic occurred when the pktlog module free - * the rx frame handled by napi_gro_receive(). - * It is a fix code that DHD don't use napi_gro_receive() for - * the packet used in pktlog module. - */ - if (dhd_gro_enable && !skb_cloned(skb) && - ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { - napi_gro_receive(&dhd->rx_napi_struct, skb); - } else { - netif_receive_skb(skb); - } -#else -#if defined(WL_MONITOR) && defined(BCMSDIO) - if (dhd_monitor_enabled(dhdp, ifidx)) - dhd_rx_mon_pkt_sdio(dhdp, skb, ifidx); - else -#endif /* WL_MONITOR && BCMSDIO */ - netif_receive_skb(skb); -#endif /* ENABLE_DHD_GRO */ -#else /* !defined(DHD_LB_RXP) */ - netif_rx(skb); -#endif /* !defined(DHD_LB_RXP) */ - } else { - if (dhd->rxthread_enabled) { - if (!skbhead) - skbhead = skb; - else - PKTSETNEXT(dhdp->osh, skbprev, skb); - skbprev = skb; - } else { - - /* If the receive is not processed inside an ISR, - * the softirqd must be woken explicitly to service - * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled - * by netif_rx_ni(), but in earlier kernels, we need - * to do it manually. - */ - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); - -#if defined(BCMPCIE) && defined(DHDTCPACK_SUPPRESS) - dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF); -#endif /* BCMPCIE && DHDTCPACK_SUPPRESS */ -#if defined(DHD_LB_RXP) -#ifdef ENABLE_DHD_GRO - if (dhd_gro_enable && !skb_cloned(skb) && - ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { - napi_gro_receive(&dhd->rx_napi_struct, skb); - } else { - netif_receive_skb(skb); - } -#else - netif_receive_skb(skb); -#endif /* ENABLE_DHD_GRO */ -#else /* !defined(DHD_LB_RXP) */ - netif_rx_ni(skb); -#endif /* !defined(DHD_LB_RXP) */ - } - } - } - - if (dhd->rxthread_enabled && skbhead) - dhd_sched_rxf(dhdp, skbhead); - -#if defined(OEM_ANDROID) - DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); -#endif /* OEM_ANDROID */ -} - void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) { @@ -6578,64 +4591,6 @@ dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) return; } -void -dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) -{ - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct ether_header *eh; - uint16 type; - - if (dhdp->tput_data.tput_test_running) { - - dhdp->batch_tx_pkts_cmpl++; - - /* don't count the stop pkt */ - if (success && - dhdp->batch_tx_pkts_cmpl <= dhdp->batch_tx_num_pkts) - dhdp->tput_data.pkts_good++; - else if (!success) - dhdp->tput_data.pkts_bad++; - - /* we dont care for the stop packet in tput test */ - if (dhdp->batch_tx_pkts_cmpl == dhdp->batch_tx_num_pkts) { - dhdp->tput_stop_ts = OSL_SYSUPTIME_US(); - dhdp->tput_data.pkts_cmpl += dhdp->batch_tx_pkts_cmpl; - dhdp->tput_data.num_pkts += dhdp->batch_tx_num_pkts; - dhd_os_tput_test_wake(dhdp); - } - } - /* XXX where does this stuff belong to? */ - dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); - - /* XXX Use packet tag when it is available to identify its type */ - - eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); - type = ntoh16(eh->ether_type); - - if (type == ETHER_TYPE_802_1X) { - atomic_dec(&dhd->pend_8021x_cnt); - } - -#ifdef PROP_TXSTATUS - if (dhdp->wlfc_state && (dhdp->proptxstatus_mode != WLFC_FCMODE_NONE)) { - dhd_if_t *ifp = dhd->iflist[DHD_PKTTAG_IF(PKTTAG(txp))]; - uint datalen = PKTLEN(dhd->pub.osh, txp); - if (ifp != NULL) { - if (success) { - dhd->pub.tx_packets++; - ifp->stats.tx_packets++; - ifp->stats.tx_bytes += datalen; - } else { - ifp->stats.tx_dropped++; - } - } - } -#endif - if (success) { - dhd->pub.tot_txcpl++; - } -} - int dhd_os_tput_test_wait(dhd_pub_t *pub, uint *condition, uint timeout_ms) { @@ -6729,10 +4684,6 @@ dhd_watchdog_thread(void *data) dhd_analyze_sock_flows(dhd, dhd_watchdog_ms); dhd_bus_watchdog(&dhd->pub); -#ifdef DHD_TIMESYNC - /* Call the timesync module watchdog */ - dhd_timesync_watchdog(&dhd->pub); -#endif /* DHD_TIMESYNC */ #if defined(BCM_ROUTER_DHD) && defined(CTFPOOL) /* allocate and add a new skb to the pkt pool */ if (CTF_ENAB(dhd->cih)) @@ -6787,11 +4738,6 @@ static void dhd_watchdog(ulong data) /* Call the bus module watchdog */ dhd_bus_watchdog(&dhd->pub); -#ifdef DHD_TIMESYNC - /* Call the timesync module watchdog */ - dhd_timesync_watchdog(&dhd->pub); -#endif /* DHD_TIMESYNC */ - DHD_GENERAL_LOCK(&dhd->pub, flags); /* Count the tick for reference */ dhd->pub.tickcnt++; @@ -6813,87 +4759,6 @@ static void dhd_watchdog(ulong data) #endif /* BCM_ROUTER_DHD && CTFPOOL */ } -#ifdef DHD_PCIE_RUNTIMEPM -static int -dhd_rpm_state_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - - while (1) { - if (down_interruptible (&tsk->sema) == 0) { - unsigned long flags; - unsigned long jiffies_at_start = jiffies; - unsigned long time_lapse; - - SMP_RD_BARRIER_DEPENDS(); - if (tsk->terminated) { - break; - } - - if (dhd->pub.dongle_reset == FALSE) { - DHD_TIMER(("%s:\n", __FUNCTION__)); - if (dhd->pub.up) { -#if defined(PCIE_OOB) || defined(PCIE_INB_DW) - dhd_bus_dw_deassert(&dhd->pub); -#endif /* PCIE_OOB || PCIE_INB_DW */ - if (dhd_get_rpm_state(&dhd->pub)) { - dhd_runtimepm_state(&dhd->pub); - } - } - DHD_GENERAL_LOCK(&dhd->pub, flags); - time_lapse = jiffies - jiffies_at_start; - - /* Reschedule the watchdog */ - if (dhd->rpm_timer_valid) { - mod_timer(&dhd->rpm_timer, - jiffies + - msecs_to_jiffies(dhd_runtimepm_ms) - - min(msecs_to_jiffies(dhd_runtimepm_ms), - time_lapse)); - } - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - } - } else { - break; - } - } - - complete_and_exit(&tsk->completed, 0); -} - -static void dhd_runtimepm(ulong data) -{ - dhd_info_t *dhd = (dhd_info_t *)data; - - if (dhd->pub.dongle_reset) { - return; - } - - if (dhd->thr_rpm_ctl.thr_pid >= 0) { - up(&dhd->thr_rpm_ctl.sema); - return; - } -} - -void dhd_runtime_pm_disable(dhd_pub_t *dhdp) -{ - dhd_set_rpm_state(dhdp, FALSE); - dhdpcie_runtime_bus_wake(dhdp, CAN_SLEEP(), __builtin_return_address(0)); -} - -void dhd_runtime_pm_enable(dhd_pub_t *dhdp) -{ - /* Enable Runtime PM except for MFG Mode */ - if (!(dhdp->op_mode & DHD_FLAG_MFG_MODE)) { - if (dhd_get_idletime(dhdp)) { - dhd_set_rpm_state(dhdp, TRUE); - } - } -} - -#endif /* DHD_PCIE_RUNTIMEPM */ - #ifdef ENABLE_ADAPTIVE_SCHED static void dhd_sched_policy(int prio) @@ -7010,82 +4875,6 @@ dhd_dpc_thread(void *data) complete_and_exit(&tsk->completed, 0); } -static int -dhd_rxf_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; -#if defined(WAIT_DEQUEUE) -#define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) / */ - ulong watchdogTime = OSL_SYSUPTIME(); /* msec */ -#endif - dhd_pub_t *pub = &dhd->pub; - - /* This thread doesn't need any user-level access, - * so get rid of all our resources - */ - if (dhd_rxf_prio > 0) - { - struct sched_param param; - param.sched_priority = (dhd_rxf_prio < MAX_RT_PRIO)?dhd_rxf_prio:(MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - -#ifdef CUSTOM_SET_CPUCORE - dhd->pub.current_rxf = current; -#endif /* CUSTOM_SET_CPUCORE */ - /* Run until signal received */ - while (1) { - if (dhd->pub.conf->rxf_cpucore >= 0) { - printf("%s: set rxf_cpucore %d\n", __FUNCTION__, dhd->pub.conf->rxf_cpucore); - set_cpus_allowed_ptr(current, cpumask_of(dhd->pub.conf->rxf_cpucore)); - dhd->pub.conf->rxf_cpucore = -1; - } - if (down_interruptible(&tsk->sema) == 0) { - void *skb; -#ifdef ENABLE_ADAPTIVE_SCHED - dhd_sched_policy(dhd_rxf_prio); -#endif /* ENABLE_ADAPTIVE_SCHED */ - - SMP_RD_BARRIER_DEPENDS(); - - if (tsk->terminated) { - DHD_OS_WAKE_UNLOCK(pub); - break; - } - skb = dhd_rxf_dequeue(pub); - - if (skb == NULL) { - continue; - } - while (skb) { - void *skbnext = PKTNEXT(pub->osh, skb); - PKTSETNEXT(pub->osh, skb, NULL); - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); -#if defined(WL_MONITOR) && defined(BCMSDIO) - if (dhd_monitor_enabled(pub, 0)) - dhd_rx_mon_pkt_sdio(pub, skb, 0); - else -#endif /* WL_MONITOR && BCMSDIO */ - netif_rx_ni(skb); - skb = skbnext; - } -#if defined(WAIT_DEQUEUE) - if (OSL_SYSUPTIME() - watchdogTime > RXF_WATCHDOG_TIME) { - OSL_SLEEP(1); - watchdogTime = OSL_SYSUPTIME(); - } -#endif - - DHD_OS_WAKE_UNLOCK(pub); - } else { - break; - } - } - complete_and_exit(&tsk->completed, 0); -} - #ifdef BCMPCIE void dhd_dpc_enable(dhd_pub_t *dhdp) { @@ -7099,6 +4888,7 @@ void dhd_dpc_enable(dhd_pub_t *dhdp) #ifdef DHD_LB_RXP __skb_queue_head_init(&dhd->rx_pend_queue); + skb_queue_head_init(&dhd->rx_emerge_queue); #endif /* DHD_LB_RXP */ #ifdef DHD_LB_TXP @@ -7133,6 +4923,7 @@ dhd_dpc_kill(dhd_pub_t *dhdp) #ifdef DHD_LB_RXP cancel_work_sync(&dhd->rx_napi_dispatcher_work); __skb_queue_purge(&dhd->rx_pend_queue); + skb_queue_purge(&dhd->rx_emerge_queue); #endif /* DHD_LB_RXP */ #ifdef DHD_LB_TXP cancel_work_sync(&dhd->tx_dispatcher_work); @@ -7167,8 +4958,8 @@ static void dhd_dpc(ulong data) { dhd_info_t *dhd = (dhd_info_t *)data; - int curr_cpu = get_cpu(); + put_cpu(); /* Store current cpu as dpc_cpu */ @@ -7185,6 +4976,9 @@ dhd_dpc(ulong data) #endif /* DHD_LB_STATS && PCIE_FULL_DONGLE */ if (dhd_bus_dpc(dhd->pub.bus)) { tasklet_schedule(&dhd->tasklet); + dhd_plat_report_bh_sched(dhd->pub.plat_info, 1); + } else { + dhd_plat_report_bh_sched(dhd->pub.plat_info, 0); } } else { dhd_bus_stop(dhd->pub.bus, TRUE); @@ -7215,61 +5009,6 @@ dhd_sched_dpc(dhd_pub_t *dhdp) } #endif /* BCMDBUS */ -static void -dhd_sched_rxf(dhd_pub_t *dhdp, void *skb) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; -#ifdef RXF_DEQUEUE_ON_BUSY - int ret = BCME_OK; - int retry = 2; -#endif /* RXF_DEQUEUE_ON_BUSY */ - - DHD_OS_WAKE_LOCK(dhdp); - - DHD_TRACE(("dhd_sched_rxf: Enter\n")); -#ifdef RXF_DEQUEUE_ON_BUSY - do { - ret = dhd_rxf_enqueue(dhdp, skb); - if (ret == BCME_OK || ret == BCME_ERROR) - break; - else - OSL_SLEEP(50); /* waiting for dequeueing */ - } while (retry-- > 0); - - if (retry <= 0 && ret == BCME_BUSY) { - void *skbp = skb; - - while (skbp) { - void *skbnext = PKTNEXT(dhdp->osh, skbp); - PKTSETNEXT(dhdp->osh, skbp, NULL); - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); - netif_rx_ni(skbp); - skbp = skbnext; - } - DHD_ERROR(("send skb to kernel backlog without rxf_thread\n")); - } else { - if (dhd->thr_rxf_ctl.thr_pid >= 0) { - up(&dhd->thr_rxf_ctl.sema); - } - } -#else /* RXF_DEQUEUE_ON_BUSY */ - do { - if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK) - break; - } while (1); - if (dhd->thr_rxf_ctl.thr_pid >= 0) { - up(&dhd->thr_rxf_ctl.sema); - } else { - DHD_OS_WAKE_UNLOCK(dhdp); - } - return; -#endif /* RXF_DEQUEUE_ON_BUSY */ -} - -#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) -#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */ - #ifdef TOE /* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ static int @@ -7530,6 +5269,49 @@ static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) return FALSE; } +#if defined(DBG_PKT_MON) +#ifdef PCIE_FULL_DONGLE +void +dhd_80211_mon_pkt(dhd_pub_t *dhdp, host_rxbuf_cmpl_t* msg, void *pkt, int ifidx) +{ + /* Distinguish rx/tx frame */ + wl_aml_header_v1_t hdr; + + hdr = *(wl_aml_header_v1_t *)PKTDATA(dhdp->osh, pkt); + PKTPULL(dhdp->osh, pkt, sizeof(hdr)); + if (hdr.flags & WL_AML_F_DIRECTION) { + bool ack = !!(hdr.flags & WL_AML_F_ACKED); + DHD_DBG_PKT_MON_TX(dhdp, pkt, 0, FRAME_TYPE_80211_MGMT, (uint8)ack); + } else { + DHD_DBG_PKT_MON_RX(dhdp, (struct sk_buff *)pkt, FRAME_TYPE_80211_MGMT); + } +} +#else +bool +dhd_80211_mon_pkt(dhd_pub_t *dhdp, void *pkt, int ifidx) +{ + /* Distinguish rx/tx frame */ + wl_aml_header_v1_t hdr; + + hdr = *(wl_aml_header_v1_t *)PKTDATA(dhdp->osh, pkt); + if (hdr.version == WL_AML_HEADER_VERSION) { + if (hdr.flags & WL_AML_F_MGMT) { + PKTPULL(dhdp->osh, pkt, sizeof(hdr)); + if (hdr.flags & WL_AML_F_DIRECTION) { + bool ack = !!(hdr.flags & WL_AML_F_ACKED); + DHD_DBG_PKT_MON_TX(dhdp, pkt, 0, FRAME_TYPE_80211_MGMT, (uint8)ack); + } else { + DHD_DBG_PKT_MON_RX(dhdp, (struct sk_buff *)pkt, + FRAME_TYPE_80211_MGMT); + } + return TRUE; + } + } + return FALSE; +} +#endif /* PCIE_FULL_DONGLE */ +#endif /* DBG_PKT_MON */ + #ifdef WL_MONITOR bool dhd_monitor_enabled(dhd_pub_t *dhd, int ifidx) @@ -7537,194 +5319,121 @@ dhd_monitor_enabled(dhd_pub_t *dhd, int ifidx) return (dhd->info->monitor_type != 0); } -#ifdef BCMSDIO -static void -dhd_rx_mon_pkt_sdio(dhd_pub_t *dhdp, void *pkt, int ifidx) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - - if (!dhd->monitor_skb) { - if ((dhd->monitor_skb = PKTTONATIVE(dhdp->osh, pkt)) == NULL) - return; - } - - if (dhd->monitor_type && dhd->monitor_dev) - dhd->monitor_skb->dev = dhd->monitor_dev; - else { - PKTFREE(dhdp->osh, pkt, FALSE); - dhd->monitor_skb = NULL; - return; - } - - dhd->monitor_skb->protocol = - eth_type_trans(dhd->monitor_skb, dhd->monitor_skb->dev); - dhd->monitor_len = 0; - - netif_rx_ni(dhd->monitor_skb); - - dhd->monitor_skb = NULL; -} -#elif defined(BCMPCIE) - -void -dhd_rx_mon_pkt(dhd_pub_t *dhdp, host_rxbuf_cmpl_t* msg, void *pkt, int ifidx) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; -#ifdef HOST_RADIOTAP_CONV - if (dhd->host_radiotap_conv) { - uint16 len = 0, offset = 0; - monitor_pkt_info_t pkt_info; - - memcpy(&pkt_info.marker, &msg->marker, sizeof(msg->marker)); - memcpy(&pkt_info.ts, &msg->ts, sizeof(monitor_pkt_ts_t)); - - if (!dhd->monitor_skb) { - if ((dhd->monitor_skb = dev_alloc_skb(MAX_MON_PKT_SIZE)) == NULL) - return; - } - - len = bcmwifi_monitor(dhd->monitor_info, &pkt_info, PKTDATA(dhdp->osh, pkt), - PKTLEN(dhdp->osh, pkt), PKTDATA(dhdp->osh, dhd->monitor_skb), &offset); - - if (dhd->monitor_type && dhd->monitor_dev) - dhd->monitor_skb->dev = dhd->monitor_dev; - else { - PKTFREE(dhdp->osh, pkt, FALSE); - dev_kfree_skb(dhd->monitor_skb); - return; - } - - PKTFREE(dhdp->osh, pkt, FALSE); - - if (!len) { - return; - } - - skb_put(dhd->monitor_skb, len); - skb_pull(dhd->monitor_skb, offset); - - dhd->monitor_skb->protocol = eth_type_trans(dhd->monitor_skb, - dhd->monitor_skb->dev); - } - else -#endif /* HOST_RADIOTAP_CONV */ - { - uint8 amsdu_flag = (msg->flags & BCMPCIE_PKT_FLAGS_MONITOR_MASK) >> - BCMPCIE_PKT_FLAGS_MONITOR_SHIFT; - switch (amsdu_flag) { - case BCMPCIE_PKT_FLAGS_MONITOR_NO_AMSDU: - default: - if (!dhd->monitor_skb) { - if ((dhd->monitor_skb = PKTTONATIVE(dhdp->osh, pkt)) - == NULL) - return; - } - if (dhd->monitor_type && dhd->monitor_dev) - dhd->monitor_skb->dev = dhd->monitor_dev; - else { - PKTFREE(dhdp->osh, pkt, FALSE); - dhd->monitor_skb = NULL; - return; - } - dhd->monitor_skb->protocol = - eth_type_trans(dhd->monitor_skb, dhd->monitor_skb->dev); - dhd->monitor_len = 0; - break; - - case BCMPCIE_PKT_FLAGS_MONITOR_FIRST_PKT: - if (!dhd->monitor_skb) { - if ((dhd->monitor_skb = dev_alloc_skb(MAX_MON_PKT_SIZE)) - == NULL) - return; - dhd->monitor_len = 0; - } - if (dhd->monitor_type && dhd->monitor_dev) - dhd->monitor_skb->dev = dhd->monitor_dev; - else { - PKTFREE(dhdp->osh, pkt, FALSE); - dev_kfree_skb(dhd->monitor_skb); - return; - } - memcpy(PKTDATA(dhdp->osh, dhd->monitor_skb), - PKTDATA(dhdp->osh, pkt), PKTLEN(dhdp->osh, pkt)); - dhd->monitor_len = PKTLEN(dhdp->osh, pkt); - PKTFREE(dhdp->osh, pkt, FALSE); - return; - - case BCMPCIE_PKT_FLAGS_MONITOR_INTER_PKT: - memcpy(PKTDATA(dhdp->osh, dhd->monitor_skb) + dhd->monitor_len, - PKTDATA(dhdp->osh, pkt), PKTLEN(dhdp->osh, pkt)); - dhd->monitor_len += PKTLEN(dhdp->osh, pkt); - PKTFREE(dhdp->osh, pkt, FALSE); - return; - - case BCMPCIE_PKT_FLAGS_MONITOR_LAST_PKT: - memcpy(PKTDATA(dhdp->osh, dhd->monitor_skb) + dhd->monitor_len, - PKTDATA(dhdp->osh, pkt), PKTLEN(dhdp->osh, pkt)); - dhd->monitor_len += PKTLEN(dhdp->osh, pkt); - PKTFREE(dhdp->osh, pkt, FALSE); - skb_put(dhd->monitor_skb, dhd->monitor_len); - dhd->monitor_skb->protocol = - eth_type_trans(dhd->monitor_skb, dhd->monitor_skb->dev); - dhd->monitor_len = 0; - break; - } - } - - if (skb_headroom(dhd->monitor_skb) < ETHER_HDR_LEN) { - struct sk_buff *skb2; - - DHD_INFO(("%s: insufficient headroom\n", - dhd_ifname(&dhd->pub, ifidx))); - - skb2 = skb_realloc_headroom(dhd->monitor_skb, ETHER_HDR_LEN); - - dev_kfree_skb(dhd->monitor_skb); - if ((dhd->monitor_skb = skb2) == NULL) { - DHD_ERROR(("%s: skb_realloc_headroom failed\n", - dhd_ifname(&dhd->pub, ifidx))); - return; - } - } - PKTPUSH(dhd->pub.osh, dhd->monitor_skb, ETHER_HDR_LEN); - - /* XXX WL here makes sure data is 4-byte aligned? */ - if (in_interrupt()) { - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); - netif_rx(dhd->monitor_skb); - } else { - /* If the receive is not processed inside an ISR, - * the softirqd must be woken explicitly to service - * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled - * by netif_rx_ni(), but in earlier kernels, we need - * to do it manually. - */ - bcm_object_trace_opr(dhd->monitor_skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); - - netif_rx_ni(dhd->monitor_skb); - } - - dhd->monitor_skb = NULL; -} -#endif - typedef struct dhd_mon_dev_priv { + dhd_info_t *dhd; struct net_device_stats stats; } dhd_mon_dev_priv_t; #define DHD_MON_DEV_PRIV_SIZE (sizeof(dhd_mon_dev_priv_t)) #define DHD_MON_DEV_PRIV(dev) ((dhd_mon_dev_priv_t *)DEV_PRIV(dev)) +#define DHD_MON_DEV_INFO(dev) (((dhd_mon_dev_priv_t *)DEV_PRIV(dev))->dhd) #define DHD_MON_DEV_STATS(dev) (((dhd_mon_dev_priv_t *)DEV_PRIV(dev))->stats) -static int +static netdev_tx_t dhd_monitor_start(struct sk_buff *skb, struct net_device *dev) { PKTFREE(NULL, skb, FALSE); - return 0; + return NETDEV_TX_OK; } +#ifdef WL_CFG80211_MONITOR +static int +dhd_set_monitor_ioctl(dhd_pub_t *dhdp, bool val) +{ + dhd_info_t *dhd = dhdp->info; + int ret = 0; + uint monitor = (uint)val; + + DHD_TRACE(("%s: val %d\n", __FUNCTION__, val)); + + if ((ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_MONITOR, &monitor, + sizeof(monitor), TRUE, 0)) != 0) { + DHD_ERROR(("%s Failed to set monitor mode, err %d\n", + __FUNCTION__, ret)); + } else { + dhd_net_if_lock_local(dhd); + dhd->monitor_type = monitor; + dhd_net_if_unlock_local(dhd); + } + + return ret; +} + +static int +dhd_monitor_open(struct net_device *net) +{ + int ret = 0; + dhd_info_t *dhd = DHD_MON_DEV_INFO(net); + uint32 scan_suppress = FALSE; + + if (!dhd) { + DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); + return BCME_ERROR; + } + + if (!dhd->pub.monitor_enable) { + DHD_ERROR(("%s: Monitor mode is not enabled in FW cap\n", + __FUNCTION__)); + return BCME_ERROR; + } + + ret = dhd_set_monitor_ioctl(&dhd->pub, TRUE); + if (ret) { + DHD_ERROR(("%s: Set monitor mode IOCTL failed.\n", __FUNCTION__)); + return ret; + } + + if (FW_SUPPORTED((&dhd->pub), monitor)) { + scan_suppress = TRUE; + /* Set the SCAN SUPPRESS Flag in the firmware to disable scan in Monitor mode */ + ret = dhd_iovar(&dhd->pub, 0, "scansuppress", (char *)&scan_suppress, + sizeof(scan_suppress), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: scansuppress set failed, ret=%d\n", __FUNCTION__, ret)); + } + } + + return ret; +} + +static int +dhd_monitor_stop(struct net_device *net) +{ + int ret = 0; + dhd_info_t *dhd = DHD_MON_DEV_INFO(net); + uint32 scan_suppress = FALSE; + + if (!dhd) { + DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); + return BCME_ERROR; + } + + if (!dhd->pub.monitor_enable) { + DHD_ERROR(("%s: Monitor mode is not enabled in FW cap\n", + __FUNCTION__)); + return BCME_ERROR; + } + + if (FW_SUPPORTED((&dhd->pub), monitor)) { + scan_suppress = FALSE; + /* Unset the SCAN SUPPRESS Flag in the firmware to enable scan */ + ret = dhd_iovar(&dhd->pub, 0, "scansuppress", (char *)&scan_suppress, + sizeof(scan_suppress), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: scansuppress set failed, ret=%d\n", __FUNCTION__, ret)); + } + } + + ret = dhd_set_monitor_ioctl(&dhd->pub, FALSE); + if (ret) { + DHD_ERROR(("%s: Set monitor mode IOCTL failed.\n", __FUNCTION__)); + return ret; + } + + return ret; +} +#endif /* WL_CFG80211_MONITOR */ + #if defined(BT_OVER_SDIO) void @@ -7969,6 +5678,10 @@ static const struct net_device_ops netdev_monitor_ops = { .ndo_start_xmit = dhd_monitor_start, .ndo_get_stats = dhd_monitor_get_stats, +#ifdef WL_CFG80211_MONITOR + .ndo_open = dhd_monitor_open, + .ndo_stop = dhd_monitor_stop, +#endif /* WL_CFG80211_MONITOR */ .ndo_do_ioctl = dhd_monitor_ioctl }; @@ -7980,9 +5693,9 @@ dhd_add_monitor_if(dhd_info_t *dhd) #ifdef HOST_RADIOTAP_CONV dhd_pub_t *dhdp = (dhd_pub_t *)&dhd->pub; #endif /* HOST_RADIOTAP_CONV */ - uint32 scan_suppress = FALSE; - int ret = BCME_OK; + dhd_mon_dev_priv_t *dev_priv; + BCM_REFERENCE(dev_priv); if (!dhd) { DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); return; @@ -8015,6 +5728,14 @@ dhd_add_monitor_if(dhd_info_t *dhd) dev->netdev_ops = &netdev_monitor_ops; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 9)) + /* as priv_destructor calls free_netdev, no need to set need_free_netdev */ + dev->needs_free_netdev = 0; + dev->priv_destructor = free_netdev; +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 9) */ + dev->destructor = free_netdev; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 9) */ + /* XXX: This is called from IOCTL path, in this case, rtnl_lock is already taken. * So, register_netdev() shouldn't be called. It leads to deadlock. * To avoid deadlock due to rtnl_lock(), register_netdevice() should be used. @@ -8026,35 +5747,25 @@ dhd_add_monitor_if(dhd_info_t *dhd) return; } - if (FW_SUPPORTED((&dhd->pub), monitor)) { -#ifdef DHD_PCIE_RUNTIMEPM - /* Disable RuntimePM in monitor mode */ - DHD_DISABLE_RUNTIME_PM(&dhd->pub); - DHD_ERROR(("%s : disable runtime PM in monitor mode\n", __FUNCTION__)); -#endif /* DHD_PCIE_RUNTIME_PM */ - scan_suppress = TRUE; - /* Set the SCAN SUPPRESS Flag in the firmware to disable scan in Monitor mode */ - ret = dhd_iovar(&dhd->pub, 0, "scansuppress", (char *)&scan_suppress, - sizeof(scan_suppress), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: scansuppress set failed, ret=%d\n", __FUNCTION__, ret)); - } - } - #ifdef HOST_RADIOTAP_CONV bcmwifi_monitor_create(&dhd->monitor_info); bcmwifi_set_corerev_major(dhd->monitor_info, dhdpcie_get_corerev_major(dhdp)); bcmwifi_set_corerev_minor(dhd->monitor_info, dhdpcie_get_corerev_minor(dhdp)); #endif /* HOST_RADIOTAP_CONV */ dhd->monitor_dev = dev; +#ifdef WL_CFG80211_MONITOR + dev_priv = DHD_MON_DEV_PRIV(dev); + dev_priv->dhd = dhd; + bzero(&dev_priv->stats, sizeof(dev_priv->stats)); +#endif /* WL_CFG80211_MONITOR */ } static void dhd_del_monitor_if(dhd_info_t *dhd) { - int ret = BCME_OK; - uint32 scan_suppress = FALSE; + dhd_mon_dev_priv_t *dev_priv; + BCM_REFERENCE(dev_priv); if (!dhd) { DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); return; @@ -8064,21 +5775,12 @@ dhd_del_monitor_if(dhd_info_t *dhd) DHD_ERROR(("%s: monitor i/f doesn't exist\n", __FUNCTION__)); return; } - - if (FW_SUPPORTED((&dhd->pub), monitor)) { -#ifdef DHD_PCIE_RUNTIMEPM - /* Enable RuntimePM */ - DHD_ENABLE_RUNTIME_PM(&dhd->pub); - DHD_ERROR(("%s : enabled runtime PM\n", __FUNCTION__)); -#endif /* DHD_PCIE_RUNTIME_PM */ - scan_suppress = FALSE; - /* Unset the SCAN SUPPRESS Flag in the firmware to enable scan */ - ret = dhd_iovar(&dhd->pub, 0, "scansuppress", (char *)&scan_suppress, - sizeof(scan_suppress), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: scansuppress set failed, ret=%d\n", __FUNCTION__, ret)); - } - } +#ifdef WL_CFG80211_MONITOR + dhd->monitor_type = FALSE; + dev_priv = DHD_MON_DEV_PRIV(dhd->monitor_dev); + dev_priv->dhd = (dhd_info_t *)NULL; + bzero(&dev_priv->stats, sizeof(dev_priv->stats)); +#endif /* WL_CFG80211_MONITOR */ if (dhd->monitor_dev) { if (dhd->monitor_dev->reg_state == NETREG_UNINITIALIZED) { @@ -8195,7 +5897,9 @@ int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_bu goto done; } buflen = ioc->len; - } else if (!bcmstricmp((char *)data_buf, "dump")) { + } else if (!bcmstricmp((char *)data_buf, "dump") || + !bcmstricmp((char *)data_buf, "counters") || + !bcmstricmp((char *)data_buf, "dump_flowrings")) { buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN_32K); } else { /* This is a DHD IOVAR, truncate buflen to DHD_IOCTL_MAXLEN */ @@ -8327,58 +6031,6 @@ done: return bcmerror; } -#ifdef WL_NANHO -static bool -dhd_nho_iovar_filter(dhd_ioctl_t *ioc) -{ - bool forward_to_nanho = FALSE; - - if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) { - if ((ioc->len >= sizeof("nan")) && !strcmp(ioc->buf, "nan")) { - /* forward nan iovar to nanho module */ - forward_to_nanho = TRUE; - } else if ((ioc->len >= sizeof("slot_bss")) && !strcmp(ioc->buf, "slot_bss")) { - /* forward slot_bss iovar to nanho module */ - forward_to_nanho = TRUE; - } - } - return forward_to_nanho; -} - -static int -dhd_nho_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_buf) -{ - int err; - - if (dhd_nho_iovar_filter(ioc)) { - /* forward iovar to nanho module */ - err = bcm_nanho_iov(pub->nanhoi, ifidx, (wl_ioctl_t *)ioc); - } else { - /* all other iovars bypass nanho and issued through normal path */ - err = dhd_ioctl_process(pub, ifidx, ioc, data_buf); - } - return err; -} - -static int -dhd_nho_ioctl_cb(void *drv_ctx, int ifidx, wl_ioctl_t *ioc, bool drv_lock) -{ - int err; - - if (drv_lock) { - DHD_OS_WAKE_LOCK((dhd_pub_t *)drv_ctx); - } - - err = dhd_ioctl_process((dhd_pub_t *)drv_ctx, ifidx, (dhd_ioctl_t *)ioc, ioc->buf); - - if (drv_lock) { - DHD_OS_WAKE_UNLOCK((dhd_pub_t *)drv_ctx); - } - - return err; -} -#endif /* WL_NANHO */ - /* XXX For the moment, local ioctls will return BCM errors */ /* XXX Others return linux codes, need to be changed... */ /** @@ -8496,35 +6148,17 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, goto done; } ioc.cmd = compat_ioc.cmd; - if (ioc.cmd & WLC_SPEC_FLAG) { - memset(&ioc, 0, sizeof(ioc)); - /* Copy the ioc control structure part of ioctl request */ - if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { - bcmerror = BCME_BADADDR; - goto done; - } - ioc.cmd &= ~WLC_SPEC_FLAG; /* Clear the FLAG */ - - /* To differentiate between wl and dhd read 4 more byes */ - if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), - sizeof(uint)) != 0)) { - bcmerror = BCME_BADADDR; - goto done; - } - - } else { /* ioc.cmd & WLC_SPEC_FLAG */ - ioc.buf = compat_ptr(compat_ioc.buf); - ioc.len = compat_ioc.len; - ioc.set = compat_ioc.set; - ioc.used = compat_ioc.used; - ioc.needed = compat_ioc.needed; - /* To differentiate between wl and dhd read 4 more byes */ - if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t), - sizeof(uint)) != 0)) { - bcmerror = BCME_BADADDR; - goto done; - } - } /* ioc.cmd & WLC_SPEC_FLAG */ + ioc.buf = compat_ptr(compat_ioc.buf); + ioc.len = compat_ioc.len; + ioc.set = compat_ioc.set; + ioc.used = compat_ioc.used; + ioc.needed = compat_ioc.needed; + /* To differentiate between wl and dhd read 4 more byes */ + if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t), + sizeof(uint)) != 0)) { + bcmerror = BCME_BADADDR; + goto done; + } } else #endif /* CONFIG_COMPAT */ { @@ -8533,9 +6167,6 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, bcmerror = BCME_BADADDR; goto done; } -#ifdef CONFIG_COMPAT - ioc.cmd &= ~WLC_SPEC_FLAG; /* make sure it was clear when it isn't a compat task*/ -#endif /* To differentiate between wl and dhd read 4 more byes */ if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), @@ -8593,11 +6224,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, } #endif /* OEM_ANDROID */ -#ifdef WL_NANHO - bcmerror = dhd_nho_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf); -#else bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf); -#endif /* WL_NANHO */ /* Restore back userspace pointer to ioc.buf */ ioc.buf = ioc_buf_user; @@ -8670,7 +6297,7 @@ static void dhd_rollback_cpu_freq(dhd_info_t *dhd) static int dhd_ioctl_entry_wrapper(struct net_device *net, struct ifreq *ifr, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) - void __user *data, + void __user *data, #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(5, 15, 0) */ int cmd) { @@ -8696,21 +6323,7 @@ dhd_ioctl_entry_wrapper(struct net_device *net, struct ifreq *ifr, } #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ -#ifdef CONFIG_HAS_WAKELOCK -#define dhd_wake_lock_unlock_destroy(wlock) \ -{ \ - if (dhd_wake_lock_active(wlock)) { \ - dhd_wake_unlock(wlock); \ - } \ - dhd_wake_lock_destroy(wlock); \ -} -#endif /* CONFIG_HAS_WAKELOCK */ - #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) && defined(DHD_TCP_LIMIT_OUTPUT) -#define DHD_TCP_LIMIT_OUTPUT_BYTES (4 * 1024 * 1024) -#ifndef TCP_DEFAULT_LIMIT_OUTPUT -#define TCP_DEFAULT_LIMIT_OUTPUT (256 * 1024) -#endif /* TSQ_DEFAULT_LIMIT_OUTPUT */ void dhd_ctrl_tcp_limit_output_bytes(int level) { @@ -8722,7 +6335,23 @@ dhd_ctrl_tcp_limit_output_bytes(int level) } #endif /* LINUX_VERSION_CODE > 4.19.0 && DHD_TCP_LIMIT_OUTPUT */ -static int +void +dhd_force_collect_socram_during_wifi_onoff(dhd_pub_t *dhdp) +{ +#ifdef OEM_ANDROID +#ifdef DHD_FW_COREDUMP + if (dhdp->memdump_enabled && (dhdp->busstate != DHD_BUS_DOWN)) { +#ifdef DHD_SSSR_DUMP + dhdp->collect_sssr = TRUE; +#endif /* DHD_SSSR_DUMP */ + dhdp->memdump_type = DUMP_TYPE_DONGLE_TRAP_DURING_WIFI_ONOFF; + dhd_bus_mem_dump(dhdp); + } +#endif /* DHD_FW_COREDUMP */ +#endif /* OEM_ANDROID */ +} + +int dhd_stop(struct net_device *net) { int ifidx = 0; @@ -8734,6 +6363,8 @@ dhd_stop(struct net_device *net) #endif /* WL_STATIC_IF */ #endif /* WL_CFG80211 */ dhd_info_t *dhd = DHD_DEV_INFO(net); + int timeleft = 0; + uint32 bitmask = (uint32)-1; DHD_OS_WAKE_LOCK(&dhd->pub); WL_MSG(net->name, "Enter\n"); @@ -8744,6 +6375,25 @@ dhd_stop(struct net_device *net) dhd->pub.d3ackcnt_timeout = 0; #endif /* BCMPCIE */ + /* Synchronize between the stop and rx path */ + dhd->pub.stop_in_progress = true; + OSL_SMP_WMB(); + +#ifdef DHD_COREDUMP + if (DHD_BUS_BUSY_CHECK_IN_HALDUMP(&dhd->pub)) { + DHD_ERROR(("%s: Cancel the triggerd HAL dump.\n", __FUNCTION__)); + DHD_BUS_BUSY_CLEAR_IN_HALDUMP(&dhd->pub); + } + bitmask = ~(DHD_BUS_BUSY_IN_HALDUMP); +#endif /* DHD_COREDUMP */ + timeleft = dhd_os_busbusy_wait_bitmask(&dhd->pub, + &dhd->pub.dhd_bus_busy_state, + bitmask, 0); + if (dhd->pub.dhd_bus_busy_state & bitmask) { + DHD_ERROR(("%s: Timed out(%d) dhd_bus_busy_state=0x%x\n", + __FUNCTION__, timeleft, dhd->pub.dhd_bus_busy_state)); + } + mutex_lock(&dhd->pub.ndev_op_sync); if (dhd->pub.up == 0) { goto exit; @@ -8775,7 +6425,8 @@ dhd_stop(struct net_device *net) #if defined(WL_STATIC_IF) && defined(WL_CFG80211) /* If static if is operational, don't reset the chip */ - if (wl_cfg80211_static_if_active(cfg)) { + if ((!dhd->pub.hang_was_sent) && (wl_cfg80211_static_if_active(cfg) || + (wl_cfgvif_get_iftype_count(cfg, WL_IF_TYPE_AP)) > 0)) { WL_MSG(net->name, "static if operational. skip chip reset.\n"); skip_reset = true; wl_cfg80211_sta_ifdown(net); @@ -8783,7 +6434,7 @@ dhd_stop(struct net_device *net) } #endif /* WL_STATIC_IF && WL_CFG80211 */ #ifdef DHD_NOTIFY_MAC_CHANGED - if (dhd->pub.skip_dhd_stop) { + if (!dhd->pub.hang_was_sent && dhd->pub.skip_dhd_stop) { WL_MSG(net->name, "skip chip reset.\n"); skip_reset = true; #if defined(WL_CFG80211) @@ -8809,9 +6460,9 @@ dhd_stop(struct net_device *net) #else dhd->pub.up = 0; #endif /* WL_CFG80211 */ -#if defined(BCMPCIE) && defined(CONFIG_ARCH_MSM) +#if defined(BCMPCIE) && defined(CONFIG_ARCH_MSM) && defined(CONFIG_SEC_PCIE_L1SS) dhd_bus_inform_ep_loaded_to_rc(&dhd->pub, dhd->pub.up); -#endif /* BCMPCIE && CONFIG_ARCH_MSM */ +#endif /* BCMPCIE && CONFIG_ARCH_MSM && CONFIG_SEC_PCIE_L1SS */ ifp = dhd->iflist[0]; /* @@ -8861,17 +6512,13 @@ dhd_stop(struct net_device *net) dhd_cancel_logtrace_process_sync(dhd); #endif /* SHOW_LOGTRACE */ -#ifdef BTLOG - /* Wait till bt_log_dispatcher_work finishes */ - cancel_work_sync(&dhd->bt_log_dispatcher_work); -#endif /* BTLOG */ - #ifdef EWP_EDL cancel_delayed_work_sync(&dhd->edl_dispatcher_work); #endif #if defined(DHD_LB_RXP) __skb_queue_purge(&dhd->rx_pend_queue); + skb_queue_purge(&dhd->rx_emerge_queue); #endif /* DHD_LB_RXP */ #if defined(DHD_LB_TXP) @@ -8926,9 +6573,18 @@ dhd_stop(struct net_device *net) /* Stop all ring buffer */ dhd_os_reset_logging(&dhd->pub); #endif +#ifdef DHD_PKT_LOGGING_DBGRING + if (dhd_pktlog_ring_reinit(&dhd->pub) != BCME_OK) { + DHD_ERROR(("%s: dhd_pktlog_ring_reinit() error.\n", __FUNCTION__)); + } +#endif /* DHD_PKT_LOGGING_DBGRING */ #ifdef APF dhd_dev_apf_delete_filter(net); #endif /* APF */ +#ifdef CUSTOM_EVENT_PM_WAKE + /* Clear EXCESS_PM_PERIOD explicitly when Wi-Fi turn off */ + dhd_set_excess_pm_awake(&dhd->pub, FALSE); +#endif /* CUSTOM_EVENT_PM_WAKE */ /* Stop the protocol module */ dhd_prot_stop(&dhd->pub); @@ -8943,9 +6599,16 @@ exit: #endif /* WL_ESCAN */ if (ifidx == 0 && !dhd_download_fw_on_driverload) { #if defined(WLAN_ACCEL_BOOT) + if (dhd->pub.dongle_trap_during_wifi_onoff) { + DHD_ERROR(("%s: force collect socram due to trap " + "during wifi on/off.\n", __FUNCTION__)); + dhd_force_collect_socram_during_wifi_onoff(&dhd->pub); + dhd->pub.dongle_trap_during_wifi_onoff = 0; + } + wl_android_wifi_accel_off(net, dhd->wl_accel_force_reg_on); #else -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) dhd_bus_put(&dhd->pub, WLAN_MODULE); wl_android_set_wifi_on_flag(FALSE); #else @@ -9005,6 +6668,8 @@ exit: WL_MSG(net->name, "Exit\n"); mutex_unlock(&dhd->pub.ndev_op_sync); + /* Clear stop in progress flag */ + dhd->pub.stop_in_progress = false; return 0; } @@ -9034,6 +6699,9 @@ dhd_verify_firmware_mode_change(dhd_info_t *dhd) { int current_mode = 0; + dhd->pub.fw_mode_changed = FALSE; + + DHD_ERROR(("%s: do_chip_bighammer:%d\n", __FUNCTION__, dhd->pub.do_chip_bighammer)); /* * check for the FW change * previous FW mode - dhd->pub.op_mode remember the previous mode @@ -9044,116 +6712,69 @@ dhd_verify_firmware_mode_change(dhd_info_t *dhd) DHD_INFO(("%s : check monitor mode with fw_path : %s\n", __FUNCTION__, dhd->fw_path)); if (strstr(dhd->fw_path, "_mon") != NULL) { - DHD_ERROR(("%s : monitor mode is enabled, set force reg on", __FUNCTION__)); + DHD_ERROR(("%s : monitor mode is enabled, set force reg on\n", __FUNCTION__)); dhd->wl_accel_force_reg_on = TRUE; + dhd->pub.fw_mode_changed = TRUE; return; } else if (dhd->pub.monitor_enable == TRUE) { - DHD_ERROR(("%s : monitor was enabled, changed to other fw_mode", __FUNCTION__)); + DHD_ERROR(("%s : monitor was enabled, changed to other fw_mode\n", __FUNCTION__)); dhd->wl_accel_force_reg_on = TRUE; + dhd->pub.fw_mode_changed = TRUE; return; } #endif /* WL_MONITOR */ current_mode = dhd_get_fw_mode(dhd); - DHD_ERROR(("%s: current_mode 0x%x, prev_opmode 0x%x", __FUNCTION__, + DHD_ERROR(("%s: current_mode 0x%x, prev_opmode 0x%x\n", __FUNCTION__, current_mode, dhd->pub.op_mode)); if (!(dhd->pub.op_mode & current_mode)) { - DHD_ERROR(("%s: firmware path has changed, set force reg on", __FUNCTION__)); + DHD_ERROR(("%s: firmware path has changed, set force reg on\n", __FUNCTION__)); dhd->wl_accel_force_reg_on = TRUE; + dhd->pub.fw_mode_changed = TRUE; } } - -#ifndef DHD_FS_CHECK_RETRY_DELAY_MS -#define DHD_FS_CHECK_RETRY_DELAY_MS 3000 -#endif - -#ifndef DHD_FS_CHECK_RETRIES -#define DHD_FS_CHECK_RETRIES 3 -#endif - -static bool -dhd_check_filesystem_is_up(void) -{ - struct file *fp; - const char *clm = VENDOR_PATH CONFIG_BCMDHD_CLM_PATH; - fp = filp_open(clm, O_RDONLY, 0); - - if (IS_ERR(fp)) { - DHD_ERROR(("%s: filp_open(%s) failed(%d) schedule wl_accel_work\n", - __FUNCTION__, clm, (int)IS_ERR(fp))); - return FALSE; - } - filp_close(fp, NULL); - - return TRUE; -} - -static void -dhd_wifi_accel_on_work_cb(struct work_struct *work) -{ - int ret = 0; - struct delayed_work *dw = to_delayed_work(work); - struct dhd_info *dhd; - struct net_device *net; - - /* Ignore compiler warnings due to -Werror=cast-qual */ - GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); - dhd = container_of(dw, struct dhd_info, wl_accel_work); - GCC_DIAGNOSTIC_POP(); - - DHD_ERROR(("%s\n", __FUNCTION__)); - - /* Initialise force regon to TRUE and it will be made FALSE at the end */ - dhd->wl_accel_force_reg_on = TRUE; - - if (!dhd_check_filesystem_is_up()) { - if (!dhd->fs_check_retry--) { - DHD_ERROR(("%s: max retry reached, BACKOFF\n", __FUNCTION__)); - return; - } - schedule_delayed_work(&dhd->wl_accel_work, - msecs_to_jiffies(DHD_FS_CHECK_RETRY_DELAY_MS)); - return; - } - - net = dhd->iflist[0]->net; - - /* - * Keep wlan turn on and download firmware during bootup - * by making g_wifi_on = FALSE - */ - ret = wl_android_wifi_on(net); - if (ret) { - DHD_ERROR(("%s: wl_android_wifi_on failed(%d)\n", __FUNCTION__, ret)); - goto fail; - } - - /* Disable host access from dongle */ - ret = dhd_wl_ioctl_set_intiovar(&dhd->pub, "bus:host_access", 0, WLC_SET_VAR, TRUE, 0); - if (ret) { - /* Proceed even if iovar fails for backward compatibilty */ - DHD_ERROR(("%s: bus:host_access(0) failed(%d)\n", __FUNCTION__, ret)); - } - - /* After bootup keep in suspend state */ - ret = dhd_net_bus_suspend(net); - if (ret) { - DHD_ERROR(("%s: dhd_net_bus_suspend failed(%d)\n", __FUNCTION__, ret)); - goto fail; - } - - /* Set force regon to FALSE and it will be set for Big Hammer case */ - dhd->wl_accel_force_reg_on = FALSE; - -fail: - /* mark wl_accel_boot_on_done for dhd_open to proceed */ - dhd->wl_accel_boot_on_done = TRUE; - return; - -} #endif /* WLAN_ACCEL_BOOT */ +void +dhd_force_collect_init_fail_dumps(dhd_pub_t *dhdp) +{ +#ifndef SKIP_FORCE_INIT_DUMP +#ifdef OEM_ANDROID + +#if defined(CUSTOMER_HW7_DEBUG) +#ifdef DEBUG_DNGL_INIT_FAIL + /* As HAL is not inited, do force crash and collect from host dram */ + dhdp->memdump_enabled = DUMP_MEMONLY; +#else + DHD_ERROR(("%s: As DEBUG_DNGL_INIT_FAIL is not enabled, and HAL not inited," + " cannot collect dumps\n", __FUNCTION__)); + return; +#endif /* DEBUG_DNGL_INIT_FAIL */ +#endif /* CUSTOMER_HW7_DEBUG */ + +#ifdef DHD_FW_COREDUMP + /* save core dump or write to a file */ + if (dhdp->memdump_enabled && (dhdp->busstate != DHD_BUS_DOWN)) { +#ifdef DHD_SSSR_DUMP + if (!dhdp->sssr_inited) { + DHD_ERROR(("%s: #### force init SSSR ###\n", __FUNCTION__)); + dhdp->force_sssr_init = TRUE; + /* Hard code sssr_reg_info for 4389 */ + DHD_SSSR_DUMP_INIT(dhdp); + /* force collect FIS */ + fis_enab = TRUE; + } + dhdp->collect_sssr = TRUE; +#endif /* DHD_SSSR_DUMP */ + dhdp->memdump_type = DUMP_TYPE_DONGLE_INIT_FAILURE; + dhd_bus_mem_dump(dhdp); + } +#endif /* DHD_FW_COREDUMP */ +#endif /* OEM_ANDROID */ +#endif /* SKIP_FORCE_INIT_DUMP */ +} + int dhd_open(struct net_device *net) { @@ -9189,6 +6810,11 @@ dhd_open(struct net_device *net) } #endif /* PREVENT_REOPEN_DURING_HANG */ + /* clear to run TCM test once per dhd_open() */ + if (dhd_tcm_test_mode != TCM_TEST_MODE_ONCE) { + dhd_tcm_test_status = TCM_TEST_NOT_RUN; + } + mutex_lock(&dhd->pub.ndev_op_sync); #ifdef SCAN_SUPPRESS @@ -9204,19 +6830,16 @@ dhd_open(struct net_device *net) if (!dhd_download_fw_on_driverload) { #if defined(WLAN_ACCEL_BOOT) - if (dhd->wl_accel_boot_on_done == FALSE) { -#if defined(WLAN_ACCEL_SKIP_WQ_IN_ATTACH) - dhd_wifi_accel_on_work_cb(&dhd->wl_accel_work.work); -#else - DHD_ERROR(("%s: WLAN accel boot not done yet\n", __FUNCTION__)); - mutex_unlock(&dhd->pub.ndev_op_sync); - return -1; -#endif /* WLAN_ACCEL_SKIP_WQ_IN_ATTACH */ - } if (!dhd->wl_accel_force_reg_on && dhd_query_bus_erros(&dhd->pub)) { DHD_ERROR(("%s: set force reg on\n", __FUNCTION__)); dhd->wl_accel_force_reg_on = TRUE; } + if (!dhd->wl_accel_force_reg_on && !DHD_BUS_BUSY_CHECK_IDLE(&dhd->pub)) { + DHD_ERROR(("%s: clear dhd_bus_busy_state: 0x%x\n", + __FUNCTION__, dhd->pub.dhd_bus_busy_state)); + dhd->pub.dhd_bus_busy_state = 0; + dhd->wl_accel_force_reg_on = TRUE; + } #endif /* WLAN_ACCEL_BOOT */ if (!dhd_driver_init_done) { DHD_ERROR(("%s: WLAN driver is not initialized\n", __FUNCTION__)); @@ -9252,9 +6875,9 @@ dhd_open(struct net_device *net) DHD_OS_WAKE_LOCK(&dhd->pub); dhd->pub.dongle_trap_occured = 0; -#ifdef BT_OVER_PCIE - dhd->pub.dongle_trap_due_to_bt = 0; -#endif /* BT_OVER_PCIE */ + dhd->pub.dsack_hc_due_to_isr_delay = 0; + dhd->pub.dsack_hc_due_to_dpc_delay = 0; + dhd->pub.dongle_trap_during_wifi_onoff = 0; dhd->pub.hang_was_sent = 0; dhd->pub.hang_was_pending = 0; dhd->pub.hang_reason = 0; @@ -9263,17 +6886,29 @@ dhd_open(struct net_device *net) dhd->pub.d3ack_timeout_occured = 0; dhd->pub.livelock_occured = 0; dhd->pub.pktid_audit_failed = 0; + dhd->pub.pktid_invalid_occured = 0; #endif /* PCIE_FULL_DONGLE */ dhd->pub.iface_op_failed = 0; dhd->pub.scan_timeout_occurred = 0; dhd->pub.scan_busy_occurred = 0; + dhd->pub.p2p_disc_busy_occurred = 0; dhd->pub.smmu_fault_occurred = 0; #ifdef DHD_LOSSLESS_ROAMING dhd->pub.dequeue_prec_map = ALLPRIO; #endif +#ifdef DHD_SSSR_DUMP + dhd->pub.collect_sssr = FALSE; +#endif /* DHD_SSSR_DUMP */ +#ifdef DHD_SDTC_ETB_DUMP + dhd->pub.collect_sdtc = FALSE; +#endif /* DHD_SDTC_ETB_DUMP */ #ifdef DHD_GRO_ENABLE_HOST_CTRL dhd->pub.permitted_gro = TRUE; #endif /* DHD_GRO_ENABLE_HOST_CTRL */ +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) + dhd_set_dump_status(&dhd->pub, DUMP_NOT_READY); +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ + #if 0 /* * Force start if ifconfig_up gets called before START command @@ -9306,6 +6941,7 @@ dhd_open(struct net_device *net) DHD_ERROR(("%s: ######### called for ifidx=%d #########\n", __FUNCTION__, ifidx)); + dhd->pub.p2p_disc_busy_cnt = 0; #if defined(WLAN_ACCEL_BOOT) dhd_verify_firmware_mode_change(dhd); #endif /* WLAN_ACCEL_BOOT */ @@ -9356,6 +6992,8 @@ dhd_open(struct net_device *net) if (ret != 0) { DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n", __FUNCTION__, ret)); + /* Set chip big hammer */ + dhd->pub.do_chip_bighammer = TRUE; ret = -1; goto exit; } @@ -9444,7 +7082,9 @@ dhd_open(struct net_device *net) #endif /* dhd_sync_with_dongle has been called in dhd_bus_start or wl_android_wifi_on */ - dev_addr_set(net, dhd->pub.mac.octet); + DEV_ADDR_SET(net, dhd->pub.mac.octet); + (void)memcpy_s(dhd_linux_get_primary_netdev(&dhd->pub)->perm_addr, ETHER_ADDR_LEN, + dhd->pub.mac.octet, ETHER_ADDR_LEN); #ifdef TOE /* Get current TOE mode from dongle */ @@ -9460,17 +7100,19 @@ dhd_open(struct net_device *net) dhd->iflist[ifidx]->net->features |= NETIF_F_GRO; #endif /* ENABLE_DHD_GRO */ -#ifdef HOST_SFH_LLC - dhd->iflist[ifidx]->net->needed_headroom = DOT11_LLC_SNAP_HDR_LEN; -#endif - #if defined(DHD_LB_RXP) __skb_queue_head_init(&dhd->rx_pend_queue); + skb_queue_head_init(&dhd->rx_emerge_queue); if (dhd->rx_napi_netdev == NULL) { dhd->rx_napi_netdev = dhd->iflist[ifidx]->net; memset(&dhd->rx_napi_struct, 0, sizeof(struct napi_struct)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0) + netif_napi_add_weight(dhd->rx_napi_netdev, &dhd->rx_napi_struct, + dhd_napi_poll, dhd_napi_weight); +#else netif_napi_add(dhd->rx_napi_netdev, &dhd->rx_napi_struct, dhd_napi_poll, dhd_napi_weight); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0) */ DHD_INFO(("%s napi<%p> enabled ifp->net<%p,%s> dhd_napi_weight: %d\n", __FUNCTION__, &dhd->rx_napi_struct, net, net->name, dhd_napi_weight)); @@ -9487,7 +7129,7 @@ dhd_open(struct net_device *net) #endif /* DHD_LB_TXP */ dhd->dhd_lb_candidacy_override = FALSE; #endif /* DHD_LB */ - netdev_update_features(net); + dhd_ndev_upd_features(dhd, net); #ifdef DHD_PM_OVERRIDE g_pm_override = FALSE; #endif /* DHD_PM_OVERRIDE */ @@ -9541,10 +7183,14 @@ dhd_open(struct net_device *net) #endif } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) && defined(DHD_TCP_LIMIT_OUTPUT) + dhd_ctrl_tcp_limit_output_bytes(1); +#endif /* LINUX_VERSION_CODE > 4.19.0 && DHD_TCP_LIMIT_OUTPUT */ + dhd->pub.up = 1; -#if defined(BCMPCIE) && defined(CONFIG_ARCH_MSM) +#if defined(BCMPCIE) && defined(CONFIG_ARCH_MSM) && defined(CONFIG_SEC_PCIE_L1SS) dhd_bus_inform_ep_loaded_to_rc(&dhd->pub, dhd->pub.up); -#endif /* BCMPCIE && CONFIG_ARCH_MSM */ +#endif /* BCMPCIE && CONFIG_ARCH_MSM && CONFIG_SEC_PCIE_L1SS */ DHD_START_RPM_TIMER(&dhd->pub); if (wl_event_enable) { @@ -9569,7 +7215,19 @@ dhd_open(struct net_device *net) exit: mutex_unlock(&dhd->pub.ndev_op_sync); + + if (dhd_query_bus_erros(&dhd->pub)) { + ret = BCME_ERROR; + } + if (ret) { + if (ret != BCME_NOMEM) { + dhd_force_collect_init_fail_dumps(&dhd->pub); + } else { + DHD_ERROR(("%s: skip collect dump in case of BCME_NOMEM\n", + __FUNCTION__)); + ret = BCME_ERROR; + } dhd_stop(net); } else { #if defined(ENABLE_INSMOD_NO_FW_LOAD) && defined(NO_POWER_OFF_AFTER_OPEN) @@ -9583,6 +7241,11 @@ exit: DHD_OS_WAKE_UNLOCK(&dhd->pub); +#if defined(SUPPORT_OTA_UPDATE) && defined(WLAN_ACCEL_BOOT) + if (ret == BCME_OK) { + (void)dhd_ota_buf_clean(&dhd->pub); + } +#endif /* SUPPORT_OTA_UPDATE && WLAN_ACCEL_BOOT */ WL_MSG(net->name, "Exit ret=%d\n", ret); return ret; } @@ -9594,9 +7257,11 @@ static int dhd_pri_open(struct net_device *net) { s32 ret; + dhd_info_t *dhd = DHD_DEV_INFO(net); DHD_MUTEX_IS_LOCK_RETURN(); DHD_MUTEX_LOCK(); + BCM_REFERENCE(dhd); ret = dhd_open(net); if (unlikely(ret)) { DHD_ERROR(("Failed to open primary dev ret %d\n", ret)); @@ -9604,6 +7269,13 @@ dhd_pri_open(struct net_device *net) return ret; } +#ifdef WL_CFG80211_MONITOR + dhd_net_if_lock_local(dhd); + /* Add monitor */ + dhd_add_monitor_if(dhd); + dhd_net_if_unlock_local(dhd); +#endif /* WL_CFG80211_MONITOR */ + /* Allow transmit calls */ dhd_tx_start_queues(net); WL_MSG(net->name, "tx queue started\n"); @@ -9627,11 +7299,20 @@ static int dhd_pri_stop(struct net_device *net) { s32 ret; + dhd_info_t *dhd = DHD_DEV_INFO(net); + BCM_REFERENCE(dhd); /* Set state and stop OS transmissions */ dhd_tx_stop_queues(net); WL_MSG(net->name, "tx queue stopped\n"); +#ifdef WL_CFG80211_MONITOR + dhd_net_if_lock_local(dhd); + /* Del monitor */ + dhd_del_monitor_if(dhd); + dhd_net_if_unlock_local(dhd); +#endif /* WL_CFG80211_MONITOR */ + ret = dhd_stop(net); if (unlikely(ret)) { DHD_ERROR(("dhd_stop failed: %d\n", ret)); @@ -9702,6 +7383,7 @@ dhd_static_if_open(struct net_device *net) /* Allow transmit calls */ netif_start_queue(net); } + dhd_clear_del_in_progress(cfg->pub, net); done: WL_MSG(net->name, "Exit ret=%d\n", ret); DHD_MUTEX_UNLOCK(); @@ -9730,6 +7412,7 @@ dhd_static_if_stop(struct net_device *net) } #endif /* DHD_NOTIFY_MAC_CHANGED */ + dhd_set_del_in_progress(cfg->pub, net); /* Ensure queue is disabled */ netif_tx_disable(net); @@ -9895,101 +7578,6 @@ dhd_event_ifchange(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, return BCME_OK; } -#ifdef WL_NATOE -/* Handler to update natoe info and bind with new subscriptions if there is change in config */ -static void -dhd_natoe_ct_event_hanlder(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - wl_event_data_natoe_t *natoe = event_info; - dhd_nfct_info_t *nfct = dhd->pub.nfct; - - if (event != DHD_WQ_WORK_NATOE_EVENT) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - if (natoe->natoe_active && natoe->sta_ip && natoe->start_port && natoe->end_port && - (natoe->start_port < natoe->end_port)) { - /* Rebind subscriptions to start receiving notifications from groups */ - if (dhd_ct_nl_bind(nfct, nfct->subscriptions) < 0) { - dhd_ct_close(nfct); - } - dhd_ct_send_dump_req(nfct); - } else if (!natoe->natoe_active) { - /* Rebind subscriptions to stop receiving notifications from groups */ - if (dhd_ct_nl_bind(nfct, CT_NULL_SUBSCRIPTION) < 0) { - dhd_ct_close(nfct); - } - } -} - -/* As NATOE enable/disbale event is received, we have to bind with new NL subscriptions. - * Scheduling workq to switch from tasklet context as bind call may sleep in handler - */ -int -dhd_natoe_ct_event(dhd_pub_t *dhd, char *data) -{ - wl_event_data_natoe_t *event_data = (wl_event_data_natoe_t *)data; - - if (dhd->nfct) { - wl_event_data_natoe_t *natoe = dhd->nfct->natoe_info; - uint8 prev_enable = natoe->natoe_active; - - spin_lock_bh(&dhd->nfct_lock); - memcpy(natoe, event_data, sizeof(*event_data)); - spin_unlock_bh(&dhd->nfct_lock); - - if (prev_enable != event_data->natoe_active) { - dhd_deferred_schedule_work(dhd->info->dhd_deferred_wq, - (void *)natoe, DHD_WQ_WORK_NATOE_EVENT, - dhd_natoe_ct_event_hanlder, DHD_WQ_WORK_PRIORITY_LOW); - } - return BCME_OK; - } - DHD_ERROR(("%s ERROR NFCT is not enabled \n", __FUNCTION__)); - return BCME_ERROR; -} - -/* Handler to send natoe ioctl to dongle */ -static void -dhd_natoe_ct_ioctl_handler(void *handle, void *event_info, uint8 event) -{ - dhd_info_t *dhd = handle; - dhd_ct_ioc_t *ct_ioc = event_info; - - if (event != DHD_WQ_WORK_NATOE_IOCTL) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - if (dhd_natoe_prep_send_exception_port_ioctl(&dhd->pub, ct_ioc) < 0) { - DHD_ERROR(("%s: Error in sending NATOE IOCTL \n", __FUNCTION__)); - } -} - -/* When Netlink message contains port collision info, the info must be sent to dongle FW - * For that we have to switch context from softirq/tasklet by scheduling workq for natoe_ct ioctl - */ -void -dhd_natoe_ct_ioctl_schedule_work(dhd_pub_t *dhd, dhd_ct_ioc_t *ioc) -{ - - dhd_deferred_schedule_work(dhd->info->dhd_deferred_wq, (void *)ioc, - DHD_WQ_WORK_NATOE_IOCTL, dhd_natoe_ct_ioctl_handler, - DHD_WQ_WORK_PRIORITY_HIGH); -} -#endif /* WL_NATOE */ - /* This API maps ndev to ifp inclusive of static IFs */ static dhd_if_t * dhd_get_ifp_by_ndev(dhd_pub_t *dhdp, struct net_device *ndev) @@ -10048,6 +7636,9 @@ dhd_update_iflist_info(dhd_pub_t *dhdp, struct net_device *ndev, int ifidx, if_state, ifidx)); ASSERT(dhdinfo && (ifidx < (DHD_MAX_IFS + DHD_MAX_STATIC_IFS))); + if (ifidx < 0 || ifidx >= (DHD_MAX_IFS + DHD_MAX_STATIC_IFS)) { + return -EINVAL; + } if ((ifp = dhd_get_ifp_by_ndev(dhdp, ndev)) == NULL) { return -ENODEV; @@ -10066,7 +7657,9 @@ dhd_update_iflist_info(dhd_pub_t *dhdp, struct net_device *ndev, int ifidx, DHD_ERROR(("ifp ptr already present for ifidx:%d\n", ifidx)); ASSERT(0); dhdp->hang_reason = HANG_REASON_IFACE_ADD_FAILURE; +#ifdef OEM_ANDROID net_os_send_hang_message(ifp->net); +#endif /* OEM_ANDROID */ return -EINVAL; } @@ -10190,6 +7783,7 @@ dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, const char *name, ifp->info = dhdinfo; ifp->idx = ifidx; ifp->bssidx = bssidx; + ifp->del_in_progress = FALSE; #ifdef DHD_MCAST_REGEN ifp->mcast_regen_bss_enable = FALSE; #endif @@ -10400,7 +7994,7 @@ dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock) DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx)); DHD_GENERAL_LOCK(dhdpub, flags); - ifp->del_in_progress = true; + ifp->del_in_progress = TRUE; DHD_GENERAL_UNLOCK(dhdpub, flags); /* If TX is in progress, hold the if del */ @@ -10439,8 +8033,13 @@ dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock) #endif /* DHDTCPACK_SUPPRESS && BCMPCIE */ if (need_rtnl_lock) unregister_netdev(ifp->net); - else + else { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) && defined(WL_CFG80211) + cfg80211_unregister_netdevice(ifp->net); +#else unregister_netdevice(ifp->net); +#endif + } #if defined(WLDWDS) && defined(WL_EXT_IAPSTA) if (ifp->dwds) { wl_ext_iapsta_dettach_dwds_netdev(ifp->net, ifidx, ifp->bssidx); @@ -10459,9 +8058,6 @@ dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock) } } ifp->net = NULL; - DHD_GENERAL_LOCK(dhdpub, flags); - ifp->del_in_progress = false; - DHD_GENERAL_UNLOCK(dhdpub, flags); } #ifdef DHD_WMF dhd_wmf_cleanup(dhdpub, ifidx); @@ -10579,14 +8175,13 @@ dhd_os_write_file_posn(void *fp, unsigned long *posn, void *buf, if (!fp || !buf || buflen == 0) return -1; - if (vfs_write((struct file *)fp, buf, buflen, &wr_posn) < 0) + if (dhd_vfs_write((struct file *)fp, buf, buflen, &wr_posn) < 0) return -1; *posn = wr_posn; return 0; } -#ifdef SHOW_LOGTRACE int dhd_os_read_file(void *file, char *buf, uint32 size) { @@ -10595,7 +8190,7 @@ dhd_os_read_file(void *file, char *buf, uint32 size) if (!file || !buf) return -1; - return vfs_read(filep, buf, size, &filep->f_pos); + return dhd_vfs_read(filep, buf, size, &filep->f_pos); } int @@ -10611,141 +8206,8 @@ dhd_os_seek_file(void *file, int64 offset) return 0; } -static int -dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp) -{ - struct file *filep = NULL; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - struct kstat stat; - mm_segment_t fs; - int error = 0; -#endif - char *raw_fmts = NULL; - int logstrs_size = 0; - - if (control_logtrace != LOGTRACE_PARSED_FMT) { - DHD_ERROR_NO_HW4(("%s : turned off logstr parsing\n", __FUNCTION__)); - return BCME_ERROR; - } - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - fs = get_fs(); - set_fs(KERNEL_DS); -#endif - - filep = filp_open(logstrs_path, O_RDONLY, 0); - - if (IS_ERR(filep)) { - DHD_ERROR_NO_HW4(("%s: Failed to open the file %s \n", __FUNCTION__, logstrs_path)); - goto fail; - } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - error = vfs_stat(logstrs_path, &stat); - if (error) { - DHD_ERROR_NO_HW4(("%s: Failed to stat file %s \n", __FUNCTION__, logstrs_path)); - goto fail; - } - logstrs_size = (int) stat.size; -#else - logstrs_size = dhd_os_get_image_size(filep); -#endif - - if (logstrs_size == 0) { - DHD_ERROR(("%s: return as logstrs_size is 0\n", __FUNCTION__)); - goto fail1; - } - - if (temp->raw_fmts != NULL) { - raw_fmts = temp->raw_fmts; /* reuse already malloced raw_fmts */ - } else { - raw_fmts = MALLOC(osh, logstrs_size); - if (raw_fmts == NULL) { - DHD_ERROR(("%s: Failed to allocate memory \n", __FUNCTION__)); - goto fail; - } - } - - if (vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) != logstrs_size) { - DHD_ERROR_NO_HW4(("%s: Failed to read file %s\n", __FUNCTION__, logstrs_path)); - goto fail; - } - - if (dhd_parse_logstrs_file(osh, raw_fmts, logstrs_size, temp) - == BCME_OK) { - filp_close(filep, NULL); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - set_fs(fs); -#endif - return BCME_OK; - } - -fail: - if (raw_fmts) { - MFREE(osh, raw_fmts, logstrs_size); - } - if (temp->fmts != NULL) { - MFREE(osh, temp->fmts, temp->num_fmts * sizeof(char *)); - } - -fail1: - if (!IS_ERR(filep)) - filp_close(filep, NULL); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - set_fs(fs); -#endif - temp->fmts = NULL; - temp->raw_fmts = NULL; - - return BCME_ERROR; -} - -static int -dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start, - uint32 *rodata_end) -{ - struct file *filep = NULL; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - mm_segment_t fs; -#endif - int err = BCME_ERROR; - - if (fname == NULL) { - DHD_ERROR(("%s: ERROR fname is NULL \n", __FUNCTION__)); - return BCME_ERROR; - } - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - fs = get_fs(); - set_fs(KERNEL_DS); -#endif - - filep = filp_open(fname, O_RDONLY, 0); - if (IS_ERR(filep)) { - DHD_ERROR_NO_HW4(("%s: Failed to open %s \n", __FUNCTION__, fname)); - goto fail; - } - - if ((err = dhd_parse_map_file(osh, filep, ramstart, - rodata_start, rodata_end)) < 0) - goto fail; - -fail: - if (!IS_ERR(filep)) - filp_close(filep, NULL); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - set_fs(fs); -#endif - - return err; -} +#ifdef SHOW_LOGTRACE #ifdef DHD_COREDUMP -#define PC_FOUND_BIT 0x01 -#define LR_FOUND_BIT 0x02 -#define ALL_ADDR_VAL (PC_FOUND_BIT | LR_FOUND_BIT) -#define READ_NUM_BYTES 1000 -#define DHD_FUNC_STR_LEN 80 static int dhd_lookup_map(osl_t *osh, char *fname, uint32 pc, char *pc_fn, uint32 lr, char *lr_fn) @@ -10755,9 +8217,9 @@ dhd_lookup_map(osl_t *osh, char *fname, uint32 pc, char *pc_fn, uint32 size = 0, mem_offset = 0; #else struct file *filep = NULL; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs mm_segment_t fs; -#endif +#endif /* get_fs */ #endif /* DHD_LINUX_STD_FW_API */ char *raw_fmts = NULL, *raw_fmts_loc = NULL, *cptr = NULL; uint32 read_size = READ_NUM_BYTES; @@ -10770,6 +8232,7 @@ dhd_lookup_map(osl_t *osh, char *fname, uint32 pc, char *pc_fn, uint8 count = 0; int num, len = 0, offset; + BCM_REFERENCE(type1); DHD_TRACE(("%s: fname %s pc 0x%x lr 0x%x \n", __FUNCTION__, fname, pc, lr)); if (fname == NULL) { @@ -10794,13 +8257,12 @@ dhd_lookup_map(osl_t *osh, char *fname, uint32 pc, char *pc_fn, } size = fw->size; #else -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs fs = get_fs(); set_fs(KERNEL_DS); -#endif - - filep = filp_open(fname, O_RDONLY, 0); - if (IS_ERR(filep)) { +#endif /* get_fs */ + filep = dhd_filp_open(fname, O_RDONLY, 0); + if (IS_ERR(filep) || (filep == NULL)) { DHD_ERROR(("%s: Failed to open %s \n", __FUNCTION__, fname)); goto fail; } @@ -10962,12 +8424,11 @@ fail: } #else if (!IS_ERR(filep)) - filp_close(filep, NULL); + dhd_filp_close(filep, NULL); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs set_fs(fs); -#endif - +#endif /* get_fs */ #endif /* DHD_LINUX_STD_FW_API */ if (!(count & PC_FOUND_BIT)) { sprintf(pc_fn, "0x%08x", pc); @@ -11015,7 +8476,7 @@ dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp) goto fail; } } - error = memcpy_s(raw_fmts, logstrs_size, (char *)(fw->data), logstrs_size); + error = memcpy_s(raw_fmts, logstrs_size, (const char *)(fw->data), logstrs_size); if (error) { DHD_ERROR(("%s: failed to copy raw_fmts, err=%d\n", __FUNCTION__, error)); @@ -11063,7 +8524,7 @@ dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start, goto fail; } - if ((err = dhd_parse_map_file(osh, (struct firmware *)fw, ramstart, + if ((err = dhd_parse_map_file(osh, fw, ramstart, rodata_start, rodata_end)) < 0) { goto fail; } @@ -11131,7 +8592,7 @@ dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, ch goto fail; } - error = memcpy_s(raw_fmts, logstrs_size, (char *)((fw->data) + logfilebase), + error = memcpy_s(raw_fmts, logstrs_size, (const char *)((fw->data) + logfilebase), logstrs_size); if (error) { DHD_ERROR(("%s: failed to copy raw_fmts, err=%d\n", @@ -11180,23 +8641,21 @@ static int dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp) { struct file *filep = NULL; - struct kstat stat; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs mm_segment_t fs; -#endif +#endif /* get_fs */ char *raw_fmts = NULL; int logstrs_size = 0; - int error = 0; if (control_logtrace != LOGTRACE_PARSED_FMT) { DHD_ERROR_NO_HW4(("%s : turned off logstr parsing\n", __FUNCTION__)); return BCME_ERROR; } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs fs = get_fs(); set_fs(KERNEL_DS); -#endif +#endif /* get_fs */ filep = dhd_filp_open(logstrs_path, O_RDONLY, 0); @@ -11205,12 +8664,8 @@ dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp) __FUNCTION__, logstrs_path)); goto fail; } - error = dhd_vfs_stat(logstrs_path, &stat); - if (error) { - DHD_ERROR_NO_HW4(("%s: Failed to stat file %s \n", __FUNCTION__, logstrs_path)); - goto fail; - } - logstrs_size = (int) stat.size; + + logstrs_size = dhd_vfs_size_read(filep); if (logstrs_size == 0) { DHD_ERROR(("%s: return as logstrs_size is 0\n", __FUNCTION__)); @@ -11235,9 +8690,9 @@ dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp) if (dhd_parse_logstrs_file(osh, raw_fmts, logstrs_size, temp) == BCME_OK) { dhd_filp_close(filep, NULL); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs set_fs(fs); -#endif +#endif /* get_fs */ return BCME_OK; } @@ -11253,9 +8708,9 @@ dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp) if (!IS_ERR(filep)) dhd_filp_close(filep, NULL); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs set_fs(fs); -#endif +#endif /* get_fs */ temp->fmts = NULL; temp->raw_fmts = NULL; @@ -11267,9 +8722,9 @@ dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start, uint32 *rodata_end) { struct file *filep = NULL; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs mm_segment_t fs; -#endif +#endif /* get_fs */ int err = BCME_ERROR; if (fname == NULL) { @@ -11277,10 +8732,10 @@ dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start, return BCME_ERROR; } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs fs = get_fs(); set_fs(KERNEL_DS); -#endif +#endif /* get_fs */ filep = dhd_filp_open(fname, O_RDONLY, 0); if (IS_ERR(filep) || (filep == NULL)) { @@ -11296,9 +8751,9 @@ fail: if (!IS_ERR(filep)) dhd_filp_close(filep, NULL); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs set_fs(fs); -#endif +#endif /* get_fs */ return err; } @@ -11307,9 +8762,9 @@ static int dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, char *map_file) { struct file *filep = NULL; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs mm_segment_t fs; -#endif +#endif /* get_fs */ char *raw_fmts = NULL; uint32 logstrs_size = 0; int error = 0; @@ -11332,13 +8787,13 @@ dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, ch DHD_ERROR(("ramstart: 0x%x, rodata_start: 0x%x, rodata_end:0x%x\n", ramstart, rodata_start, rodata_end)); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs fs = get_fs(); set_fs(KERNEL_DS); -#endif +#endif /* get_fs */ - filep = filp_open(str_file, O_RDONLY, 0); - if (IS_ERR(filep)) { + filep = dhd_filp_open(str_file, O_RDONLY, 0); + if (IS_ERR(filep) || (filep == NULL)) { DHD_ERROR(("%s: Failed to open the file %s \n", __FUNCTION__, str_file)); goto fail; } @@ -11375,7 +8830,7 @@ dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, ch } } - error = vfs_read(filep, raw_fmts, logstrs_size, (&filep->f_pos)); + error = dhd_vfs_read(filep, raw_fmts, logstrs_size, (&filep->f_pos)); if (error != logstrs_size) { DHD_ERROR(("%s: %s read failed %d \n", __FUNCTION__, str_file, error)); goto fail; @@ -11393,10 +8848,10 @@ dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, ch temp->rom_rodata_end = rodata_end; } - filp_close(filep, NULL); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) + dhd_filp_close(filep, NULL); +#ifdef get_fs set_fs(fs); -#endif +#endif /* get_fs */ return BCME_OK; @@ -11407,11 +8862,11 @@ fail: fail1: if (!IS_ERR(filep)) - filp_close(filep, NULL); + dhd_filp_close(filep, NULL); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs set_fs(fs); -#endif +#endif /* get_fs */ if (strstr(str_file, ram_file_str) != NULL) { temp->raw_sstr = NULL; @@ -11424,85 +8879,6 @@ fail1: #endif /* DHD_LINUX_STD_FW_API */ #endif /* SHOW_LOGTRACE */ -#ifdef BT_OVER_PCIE -void request_bt_quiesce(bool quiesce) __attribute__ ((weak)); -void response_bt_quiesce(bool quiesce); - -static void (*request_bt_quiesce_ptr)(bool); -typedef void (*response_bt_quiesce_ptr)(bool); - -response_bt_quiesce_ptr -register_request_bt_quiesce(void (*fnc)(bool)) -{ - request_bt_quiesce_ptr = fnc; - return response_bt_quiesce; -} -EXPORT_SYMBOL(register_request_bt_quiesce); - -void -unregister_request_bt_quiesce(void) -{ - request_bt_quiesce_ptr = NULL; - return; -} -EXPORT_SYMBOL(unregister_request_bt_quiesce); -#endif /* BT_OVER_PCIE */ - -#ifdef DHD_ERPOM -uint enable_erpom = 0; -module_param(enable_erpom, int, 0); - -int -dhd_wlan_power_off_handler(void *handler, unsigned char reason) -{ - dhd_pub_t *dhdp = (dhd_pub_t *)handler; - bool dongle_isolation = dhdp->dongle_isolation; - - DHD_ERROR(("%s: WLAN DHD cleanup reason: %d\n", __FUNCTION__, reason)); - - if ((reason == BY_BT_DUE_TO_BT) || (reason == BY_BT_DUE_TO_WLAN)) { -#if defined(DHD_FW_COREDUMP) - /* save core dump to a file */ - if (dhdp->memdump_enabled) { -#ifdef DHD_SSSR_DUMP - DHD_ERROR(("%s : Set collect_sssr as TRUE\n", __FUNCTION__)); - dhdp->collect_sssr = TRUE; -#endif /* DHD_SSSR_DUMP */ - dhdp->memdump_type = DUMP_TYPE_DUE_TO_BT; - dhd_bus_mem_dump(dhdp); - } -#endif /* DHD_FW_COREDUMP */ - } - - /* pause data on all the interfaces */ - dhd_bus_stop_queue(dhdp->bus); - - /* Devreset function will perform FLR again, to avoid it set dongle_isolation */ - dhdp->dongle_isolation = TRUE; - dhd_bus_devreset(dhdp, 1); /* DHD structure cleanup */ - dhdp->dongle_isolation = dongle_isolation; /* Restore the old value */ - return 0; -} - -int -dhd_wlan_power_on_handler(void *handler, unsigned char reason) -{ - dhd_pub_t *dhdp = (dhd_pub_t *)handler; - bool dongle_isolation = dhdp->dongle_isolation; - - DHD_ERROR(("%s: WLAN DHD re-init reason: %d\n", __FUNCTION__, reason)); - /* Devreset function will perform FLR again, to avoid it set dongle_isolation */ - dhdp->dongle_isolation = TRUE; - dhd_bus_devreset(dhdp, 0); /* DHD structure re-init */ - dhdp->dongle_isolation = dongle_isolation; /* Restore the old value */ - /* resume data on all the interfaces */ - dhd_bus_start_queue(dhdp->bus); - return 0; - -} - -#endif /* DHD_ERPOM */ - #ifdef BCMDBUS uint dhd_get_rxsz(dhd_pub_t *pub) @@ -11548,16 +8924,13 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen dhd_info_t *dhd = NULL; struct net_device *net = NULL; char if_name[IFNAMSIZ] = {'\0'}; -#ifdef SHOW_LOGTRACE - int ret; -#endif /* SHOW_LOGTRACE */ -#ifdef DHD_ERPOM - pom_func_handler_t *pom_handler; -#endif /* DHD_ERPOM */ #if defined(BCMSDIO) || defined(BCMPCIE) uint32 bus_type = -1; uint32 bus_num = -1; uint32 slot_num = -1; +#if defined(SHOW_LOGTRACE) && !defined(OEM_ANDROID) + int ret; +#endif /* SHOW_LOGTRACE && !OEM_ANDROID */ wifi_adapter_info_t *adapter = NULL; #elif defined(BCMDBUS) wifi_adapter_info_t *adapter = data; @@ -11611,11 +8984,22 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen dll_init(&(dhd->pub.mw_list_head)); #endif /* DHD_DEBUG */ + /* + * Attach DHD Core Layer to Platform Layer. For non + * Embedded environment, where there is no dependency on platform + * layer, dhd_get_plat_info_size can return 0, if the platform + * layer does not exist or chooses not to implement it. + */ + dhd->pub.plat_info_size = dhd_plat_get_info_size(); + if (dhd->pub.plat_info_size) { + dhd->pub.plat_info = MALLOCZ(osh, dhd->pub.plat_info_size); + } + +#ifdef CUSTOM_COUNTRY_CODE #ifdef CUSTOM_FORCE_NODFS_FLAG dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; dhd->pub.force_country_change = TRUE; #endif /* CUSTOM_FORCE_NODFS_FLAG */ -#ifdef CUSTOM_COUNTRY_CODE get_customized_country_code(dhd->adapter, dhd->pub.dhd_cspec.country_abbrev, &dhd->pub.dhd_cspec, dhd->pub.dhd_cflags); @@ -11626,13 +9010,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen #ifdef DHD_WET dhd->pub.wet_info = dhd_get_wet_info(&dhd->pub); #endif /* DHD_WET */ -#ifdef WL_NANHO - /* initialize NANHO host module */ - if (bcm_nanho_init(&dhd->pub.nanhoi, &dhd->pub, - dhd_nho_ioctl_cb, dhd_nho_evt_cb, NULL) != BCME_OK) { - goto fail; - } -#endif /* WL_NANHO */ /* Initialize thread based operation and lock */ sema_init(&dhd->sdsem, 1); #endif /* BCMDBUS */ @@ -11654,6 +9031,10 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen dhd->pub.check_trap_rot = FALSE; #endif /* CHECK_TRAP_ROT */ +#ifdef WBRC + dhd->pub.chip_bighammer_count = 0; +#endif /* WBRC */ + /* dhd_conf must be attached after linking dhd to dhd->pub.info, * because dhd_detech will check .info is NULL or not. */ @@ -11737,9 +9118,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen init_waitqueue_head(&dhd->ctrl_wait); init_waitqueue_head(&dhd->dhd_bus_busy_state_wait); init_waitqueue_head(&dhd->dmaxfer_wait); -#ifdef BT_OVER_PCIE - init_waitqueue_head(&dhd->quiesce_wait); -#endif /* BT_OVER_PCIE */ init_waitqueue_head(&dhd->pub.tx_completion_wait); dhd->pub.dhd_bus_busy_state = 0; /* Initialize the spinlocks */ @@ -11759,9 +9137,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen spin_lock_init(&dhd->tcpack_lock); #endif /* DHDTCPACK_SUPPRESS */ -#ifdef DHD_HP2P - spin_lock_init(&dhd->hp2p_lock); -#endif /* Initialize Wakelock stuff */ spin_lock_init(&dhd->wakelock_spinlock); spin_lock_init(&dhd->wakelock_evt_spinlock); @@ -11769,17 +9144,15 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen dhd->wakelock_counter = 0; /* wakelocks prevent a system from going into a low power state */ #ifdef CONFIG_HAS_WAKELOCK - // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry - dhd_wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); - dhd_wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake"); + dhd_wake_lock_init(dhd->wl_wdwake, dhd_bus_to_dev(bus), "wlan_wd_wake"); #endif /* CONFIG_HAS_WAKELOCK */ #if defined(OEM_ANDROID) mutex_init(&dhd->dhd_net_if_mutex); mutex_init(&dhd->dhd_suspend_mutex); -#if defined(PKT_FILTER_SUPPORT) && defined(APF) +#if defined(APF) mutex_init(&dhd->dhd_apf_mutex); -#endif /* PKT_FILTER_SUPPORT && APF */ +#endif /* APF */ #endif /* defined(OEM_ANDROID) */ dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; @@ -11790,15 +9163,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen } dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH; -#ifdef DHD_TIMESYNC - /* attach the timesync module */ - if (dhd_timesync_attach(&dhd->pub) != 0) { - DHD_ERROR(("dhd_timesync_attach failed\n")); - goto fail; - } - dhd_state |= DHD_ATTACH_TIMESYNC_ATTACH_DONE; -#endif /* DHD_TIMESYNC */ - #ifdef WL_CFG80211 spin_lock_init(&dhd->pub.up_lock); /* Attach and link in the cfg80211 */ @@ -11811,12 +9175,28 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen dhd_state |= DHD_ATTACH_STATE_CFG80211; #endif +#if defined(SHOW_LOGTRACE) && !defined(OEM_ANDROID) + ret = dhd_init_logstrs_array(osh, &dhd->event_data); + if (ret == BCME_OK) { + dhd_init_static_strs_array(osh, &dhd->event_data, st_str_file_path, map_file_path); + dhd_init_static_strs_array(osh, &dhd->event_data, rom_st_str_file_path, + rom_map_file_path); + dhd_state |= DHD_ATTACH_LOGTRACE_INIT; + } +#endif /* SHOW_LOGTRACE && !OEM_ANDROID */ + #ifdef WL_EVENT if (wl_ext_event_attach(net) != 0) { DHD_ERROR(("wl_ext_event_attach failed\n")); goto fail; } #endif /* WL_EVENT */ +#ifdef WL_TIMER + if (wl_timer_attach(net) != 0) { + DHD_ERROR(("wl_ext_timer_attach failed\n")); + goto fail; + } +#endif /* WL_TIMER */ #ifdef WL_ESCAN /* Attach and link in the escan */ if (wl_escan_attach(net) != 0) { @@ -11845,15 +9225,15 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; #endif /* defined(WL_WIRELESS_EXT) */ -#ifdef SHOW_LOGTRACE - ret = dhd_init_logstrs_array(osh, &dhd->event_data); - if (ret == BCME_OK) { - dhd_init_static_strs_array(osh, &dhd->event_data, st_str_file_path, map_file_path); - dhd_init_static_strs_array(osh, &dhd->event_data, rom_st_str_file_path, - rom_map_file_path); - dhd_state |= DHD_ATTACH_LOGTRACE_INIT; - } -#endif /* SHOW_LOGTRACE */ +#ifdef DHD_LOG_DUMP + dhd_log_dump_init(&dhd->pub); +#endif /* DHD_LOG_DUMP */ +#ifdef DHD_PKTDUMP_ROAM + dhd_dump_pkt_init(&dhd->pub); +#endif /* DHD_PKTDUMP_ROAM */ +#ifdef DHD_PKT_LOGGING + dhd_os_attach_pktlog(&dhd->pub); +#endif /* DHD_PKT_LOGGING */ /* attach debug if support */ if (dhd_os_dbg_attach(&dhd->pub)) { @@ -11866,10 +9246,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen dhd_os_start_logging(&dhd->pub, FW_VERBOSE_RING_NAME, 3, 0, 0, 0); #endif /* !OEM_ANDROID && SHOW_LOGTRACE */ -#if !defined(OEM_ANDROID) && defined(BTLOG) - /* enable bt log ring to support dump_bt_log */ - dhd_os_start_logging(&dhd->pub, BT_LOG_RING_NAME, 3, 0, 0, 0); -#endif /* !OEM_ANDROID && BTLOG */ #ifdef DBG_PKT_MON dhd->pub.dbg->pkt_mon_lock = osl_spin_lock_init(dhd->pub.osh); #ifdef DBG_PKT_MON_INIT_DEFAULT @@ -11885,10 +9261,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen dhd->pub.rxpath_mem = 0; #endif /* DHD_MEM_STATS */ -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) - dhd->pub.awdl_stats_lock = osl_spin_lock_init(dhd->pub.osh); -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ - #ifdef DHD_STATUS_LOGGING dhd->pub.statlog = dhd_attach_statlog(&dhd->pub, MAX_STATLOG_ITEM, MAX_STATLOG_REQ_ITEM, STATLOG_LOGBUF_LEN); @@ -11897,22 +9269,17 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen } #endif /* DHD_STATUS_LOGGING */ -#ifdef DHD_LOG_DUMP - dhd_log_dump_init(&dhd->pub); -#endif /* DHD_LOG_DUMP */ -#ifdef DHD_PKTDUMP_ROAM - dhd_dump_pkt_init(&dhd->pub); -#endif /* DHD_PKTDUMP_ROAM */ -#ifdef DHD_PKT_LOGGING - dhd_os_attach_pktlog(&dhd->pub); -#endif /* DHD_PKT_LOGGING */ - +#ifdef RX_PKT_POOL + dhd_rx_pktpool_init(dhd); +#endif /* RX_PKT_POOL */ #ifdef WL_CFGVENDOR_SEND_HANG_EVENT dhd->pub.hang_info = MALLOCZ(osh, VENDOR_SEND_HANG_EXT_INFO_LEN); if (dhd->pub.hang_info == NULL) { DHD_ERROR(("%s: alloc hang_info failed\n", __FUNCTION__)); + goto fail; } #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */ + if (dhd_sta_pool_init(&dhd->pub, DHD_MAX_STA) != BCME_OK) { DHD_ERROR(("%s: Initializing %u sta\n", __FUNCTION__, DHD_MAX_STA)); goto fail; @@ -11967,34 +9334,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen dhd->thr_wdt_ctl.thr_pid = -1; } -#ifdef DHD_PCIE_RUNTIMEPM - /* Setup up the runtime PM Idlecount timer */ - init_timer_compat(&dhd->rpm_timer, dhd_runtimepm, dhd); - dhd->rpm_timer_valid = FALSE; - - dhd->thr_rpm_ctl.thr_pid = DHD_PID_KT_INVALID; - PROC_START(dhd_rpm_state_thread, dhd, &dhd->thr_rpm_ctl, 0, "dhd_rpm_state_thread"); - if (dhd->thr_rpm_ctl.thr_pid < 0) { - goto fail; - } -#endif /* DHD_PCIE_RUNTIMEPM */ - -#ifdef SHOW_LOGTRACE - skb_queue_head_init(&dhd->evt_trace_queue); - - /* Create ring proc entries */ - dhd_dbg_ring_proc_create(&dhd->pub); -#endif /* SHOW_LOGTRACE */ - -#ifdef BTLOG - skb_queue_head_init(&dhd->bt_log_queue); -#endif /* BTLOG */ - -#ifdef BT_OVER_PCIE - mutex_init(&dhd->quiesce_flr_lock); - mutex_init(&dhd->quiesce_lock); -#endif - /* Set up the bottom half handler */ if (dhd_dpc_prio >= 0) { /* Initialize DPC thread */ @@ -12018,6 +9357,13 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen } #endif /* !BCMDBUS */ +#ifdef SHOW_LOGTRACE + skb_queue_head_init(&dhd->evt_trace_queue); + + /* Create ring proc entries */ + dhd_dbg_ring_proc_create(&dhd->pub); +#endif /* SHOW_LOGTRACE */ + dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; #if defined(CONFIG_PM_SLEEP) @@ -12053,7 +9399,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen } #endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ dhd->dhd_deferred_wq = dhd_deferred_work_init((void *)dhd); -#if defined (OEM_ANDROID) +#if defined(OEM_ANDROID) INIT_WORK(&dhd->dhd_hang_process_work, dhd_hang_process); #endif /* OEM_ANDROID */ #ifdef DEBUG_CPU_FREQ @@ -12127,6 +9473,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen /* Initialize the Load Balancing Tasklets and Napi object */ #if defined(DHD_LB_RXP) __skb_queue_head_init(&dhd->rx_pend_queue); + skb_queue_head_init(&dhd->rx_emerge_queue); skb_queue_head_init(&dhd->rx_napi_queue); __skb_queue_head_init(&dhd->rx_process_queue); /* Initialize the work that dispatches NAPI job to a given core */ @@ -12147,16 +9494,20 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen dhd_state |= DHD_ATTACH_STATE_LB_ATTACH_DONE; #endif /* DHD_LB */ +#ifdef CSI_SUPPORT + dhd_csi_init(&dhd->pub); +#endif /* CSI_SUPPORT */ + #if defined(DNGL_AXI_ERROR_LOGGING) && defined(DHD_USE_WQ_FOR_DNGL_AXI_ERROR) INIT_WORK(&dhd->axi_error_dispatcher_work, dhd_axi_error_dispatcher_fn); #endif /* DNGL_AXI_ERROR_LOGGING && DHD_USE_WQ_FOR_DNGL_AXI_ERROR */ -#ifdef BCMDBG +#if defined(BCMDBG) && defined(DHD_MACDBG) if (dhd_macdbg_attach(&dhd->pub) != BCME_OK) { DHD_ERROR(("%s: dhd_macdbg_attach fail\n", __FUNCTION__)); goto fail; } -#endif /* BCMDBG */ +#endif /* BCMDBG && DHD_MACDBG */ #ifdef REPORT_FATAL_TIMEOUTS init_dhd_timeouts(&dhd->pub); @@ -12180,14 +9531,11 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen } #endif /* SHOW_LOGTRACE */ -#ifdef BTLOG - INIT_WORK(&dhd->bt_log_dispatcher_work, dhd_bt_log_process); -#endif /* BTLOG */ - #ifdef EWP_EDL INIT_DELAYED_WORK(&dhd->edl_dispatcher_work, dhd_edl_process_work); #endif + DHD_COREDUMP_MEMPOOL_INIT(&dhd->pub); DHD_SSSR_MEMPOOL_INIT(&dhd->pub); DHD_SSSR_REG_INFO_INIT(&dhd->pub); @@ -12207,11 +9555,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen (void)dhd_sysfs_init(dhd); -#ifdef WL_NATOE - /* Open Netlink socket for NF_CONNTRACK notifications */ - dhd->pub.nfct = dhd_ct_open(&dhd->pub, NFNL_SUBSYS_CTNETLINK | NFNL_SUBSYS_CTNETLINK_EXP, - CT_ALL); -#endif /* WL_NATOE */ #ifdef GDB_PROXY dhd->pub.gdb_proxy_nodeadman = nodeadman != 0; #endif /* GDB_PROXY */ @@ -12220,15 +9563,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen dhd_found++; -#ifdef CSI_SUPPORT - dhd_csi_init(&dhd->pub); -#endif /* CSI_SUPPORT */ - #ifdef DHD_FW_COREDUMP /* Set memdump default values */ -#ifdef CUSTOMER_HW4_DEBUG - dhd->pub.memdump_enabled = DUMP_DISABLED; -#elif defined(OEM_ANDROID) +#if defined(OEM_ANDROID) #ifdef DHD_COREDUMP dhd->pub.memdump_enabled = DUMP_MEMFILE; #else @@ -12236,45 +9573,11 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen #endif /* DHD_COREDUMP */ #else dhd->pub.memdump_enabled = DUMP_MEMFILE; -#endif /* CUSTOMER_HW4_DEBUG */ +#endif /* OEM_ANDROID */ /* Check the memdump capability */ dhd_get_memdump_info(&dhd->pub); #endif /* DHD_FW_COREDUMP */ -#ifdef DHD_ERPOM - if (enable_erpom) { - pom_handler = &dhd->pub.pom_wlan_handler; - pom_handler->func_id = WLAN_FUNC_ID; - pom_handler->handler = (void *)g_dhd_pub; - pom_handler->power_off = dhd_wlan_power_off_handler; - pom_handler->power_on = dhd_wlan_power_on_handler; - - dhd->pub.pom_func_register = NULL; - dhd->pub.pom_func_deregister = NULL; - dhd->pub.pom_toggle_reg_on = NULL; - - dhd->pub.pom_func_register = symbol_get(pom_func_register); - dhd->pub.pom_func_deregister = symbol_get(pom_func_deregister); - dhd->pub.pom_toggle_reg_on = symbol_get(pom_toggle_reg_on); - - symbol_put(pom_func_register); - symbol_put(pom_func_deregister); - symbol_put(pom_toggle_reg_on); - - if (!dhd->pub.pom_func_register || - !dhd->pub.pom_func_deregister || - !dhd->pub.pom_toggle_reg_on) { - DHD_ERROR(("%s, enable_erpom enabled through module parameter but " - "POM is not loaded\n", __FUNCTION__)); - ASSERT(0); - goto fail; - } - dhd->pub.pom_func_register(pom_handler); - dhd->pub.enable_erpom = TRUE; - - } -#endif /* DHD_ERPOM */ - #ifdef DHD_DUMP_MNGR dhd->pub.dump_file_manage = (dhd_dump_file_manage_t *)MALLOCZ(dhd->pub.osh, sizeof(dhd_dump_file_manage_t)); @@ -12284,16 +9587,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen } #endif /* DHD_DUMP_MNGR */ -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE - /* Attach the fwtrace */ - if (dhd_fwtrace_attach(&dhd->pub) != 0) { - DHD_ERROR(("dhd_fwtrace_attach has failed\n")); - goto fail; - } -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ - #ifdef RTT_SUPPORT if (dhd_rtt_attach(&dhd->pub)) { DHD_ERROR(("dhd_rtt_attach has failed\n")); @@ -12308,6 +9601,20 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen } #endif /* defined(DHD_TX_PROFILE) */ +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT + INIT_WORK(&dhd->dhd_alert_process_work, dhd_alert_process); +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ +#if defined(DHD_ENABLE_S2MPU) + dhd_module_s2mpu_register(dhd_bus_to_dev(bus)); +#endif /* DHD_ENABLE_S2MPU */ +#ifdef DHD_REGISTER_SMMU_FAULT_HANDLER + pcie_sysmmu_add_fault_handler(&dhd_pcie_sysmmu_nb); +#endif /* DHD_REGISTER_SMMU_FAULT_HANDLER */ +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) + OSL_ATOMIC_SET(dhd->pub.osh, &dhd->dump_status, DUMP_NOT_READY); + INIT_WORK(&dhd->dhd_dump_proc_work, dhd_dump_proc); +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ + return &dhd->pub; fail: @@ -12349,6 +9656,7 @@ bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) int nv_len; int clm_len; int conf_len; + int sig_len; const char *fw = NULL; const char *nv = NULL; const char *clm = NULL; @@ -12360,6 +9668,8 @@ bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) wifi_adapter_info_t *adapter = dhdinfo->adapter; int fw_path_len = sizeof(dhdinfo->fw_path); int nv_path_len = sizeof(dhdinfo->nv_path); + int clm_path_len = sizeof(dhdinfo->clm_path); + int sig_path_len = sizeof(dhdinfo->sig_path); /* Update firmware and nvram path. The path may be from adapter info or module parameter * The path from adapter info is used for initialization only (as it won't change). @@ -12388,10 +9698,11 @@ bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) /* check if we need to initialize the path */ if (dhdinfo->fw_path[0] == '\0') { - if (adapter && adapter->fw_path && adapter->fw_path[0] != '\0') + if (adapter && adapter->fw_path && adapter->fw_path[0] != '\0') { fw = adapter->fw_path; - + } } + if (dhdinfo->nv_path[0] == '\0') { if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0') nv = adapter->nv_path; @@ -12409,15 +9720,43 @@ bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) * * TODO: need a solution for multi-chip, can't use the same firmware for all chips */ - if (firmware_path[0] != '\0') + if (firmware_path[0] != '\0') { + /* Newline is getting added sometimes when firmware_path module parameter + * is updated via command line using echo command, due to which + * file not found error is seen, hence replacing '\n' with '\0'. + */ + if (firmware_path[strlen(firmware_path)-1] == '\n') { + firmware_path[strlen(firmware_path)-1] = '\0'; + } fw = firmware_path; + } - if (nvram_path[0] != '\0') + if (nvram_path[0] != '\0') { + if (nvram_path[strlen(nvram_path)-1] == '\n') { + nvram_path[strlen(nvram_path)-1] = '\0'; + } nv = nvram_path; - if (clm_path[0] != '\0') + } + + if (clm_path[0] != '\0') { + if (clm_path[strlen(clm_path)-1] == '\n') { + clm_path[strlen(clm_path)-1] = '\0'; + } clm = clm_path; - if (config_path[0] != '\0') + } + + if (config_path[0] != '\0') { + if (config_path[strlen(config_path)-1] == '\n') { + config_path[strlen(config_path)-1] = '\0'; + } conf = config_path; + } + + if (signature_path[0] != '\0') { + if (signature_path[strlen(signature_path) - 1] == '\n') { + signature_path[strlen(signature_path) - 1] = '\0'; + } + } #ifdef DHD_UCODE_DOWNLOAD if (ucode_path[0] != '\0') @@ -12484,16 +9823,16 @@ bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) } #endif /* DHD_USE_SINGLE_NVRAM_FILE */ } + /* CLM blob */ if (clm && clm[0] != '\0') { clm_len = strlen(clm); - if (clm_len >= sizeof(dhdinfo->clm_path)) { + if (clm_len >= clm_path_len) { DHD_ERROR(("clm path len exceeds max len of dhdinfo->clm_path\n")); return FALSE; } - strncpy(dhdinfo->clm_path, clm, sizeof(dhdinfo->clm_path)); - if (dhdinfo->clm_path[clm_len-1] == '\n') - dhdinfo->clm_path[clm_len-1] = '\0'; + strlcpy(dhdinfo->clm_path, clm, clm_path_len); } + if (conf && conf[0] != '\0') { conf_len = strlen(conf); if (conf_len >= sizeof(dhdinfo->conf_path)) { @@ -12504,6 +9843,15 @@ bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) if (dhdinfo->conf_path[conf_len-1] == '\n') dhdinfo->conf_path[conf_len-1] = '\0'; } + if (signature_path[0] != '\0') { + sig_len = strlen(signature_path); + if (sig_len >= sig_path_len) { + DHD_ERROR(("signature path len exceeds max len of dhdinfo->sig_path\n")); + return FALSE; + } + strlcpy(dhdinfo->sig_path, signature_path, sig_path_len); + } + #ifdef DHD_UCODE_DOWNLOAD if (uc && uc[0] != '\0') { uc_len = strlen(uc); @@ -12520,8 +9868,7 @@ bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) if (dhd_download_fw_on_driverload) { firmware_path[0] = '\0'; nvram_path[0] = '\0'; - clm_path[0] = '\0'; - config_path[0] = '\0'; + signature_path[0] = '\0'; } #endif #ifdef DHD_UCODE_DOWNLOAD @@ -12600,75 +9947,6 @@ extern bool dhd_update_btfw_path(dhd_info_t *dhdinfo, char* btfw_path) } #endif /* defined (BT_OVER_SDIO) */ -#ifdef CUSTOMER_HW4_DEBUG -bool dhd_validate_chipid(dhd_pub_t *dhdp) -{ - uint chipid = dhd_bus_chip_id(dhdp); - uint config_chipid; - -#ifdef BCM4389_CHIP_DEF - config_chipid = BCM4389_CHIP_ID; -#elif defined(BCM4375_CHIP) - config_chipid = BCM4375_CHIP_ID; -#elif defined(BCM4361_CHIP) - config_chipid = BCM4361_CHIP_ID; -#elif defined(BCM4359_CHIP) - config_chipid = BCM4359_CHIP_ID; -#elif defined(BCM4358_CHIP) - config_chipid = BCM4358_CHIP_ID; -#elif defined(BCM4354_CHIP) - config_chipid = BCM4354_CHIP_ID; -#elif defined(BCM4339_CHIP) - config_chipid = BCM4339_CHIP_ID; -#elif defined(BCM4335_CHIP) - config_chipid = BCM4335_CHIP_ID; -#elif defined(BCM43430_CHIP) - config_chipid = BCM43430_CHIP_ID; -#elif defined(BCM43018_CHIP) - config_chipid = BCM43018_CHIP_ID; -#elif defined(BCM43455_CHIP) - config_chipid = BCM4345_CHIP_ID; -#elif defined(BCM43454_CHIP) - config_chipid = BCM43454_CHIP_ID; -#elif defined(BCM43012_CHIP_) - config_chipid = BCM43012_CHIP_ID; -#elif defined(BCM43013_CHIP) - config_chipid = BCM43012_CHIP_ID; -#else - DHD_ERROR(("%s: Unknown chip id, if you use new chipset," - " please add CONFIG_BCMXXXX into the Kernel and" - " BCMXXXX_CHIP definition into the DHD driver\n", - __FUNCTION__)); - config_chipid = 0; - - return FALSE; -#endif /* BCM4354_CHIP */ - -#if defined(BCM4354_CHIP) && defined(SUPPORT_MULTIPLE_REVISION) - if (chipid == BCM4350_CHIP_ID && config_chipid == BCM4354_CHIP_ID) { - return TRUE; - } -#endif /* BCM4354_CHIP && SUPPORT_MULTIPLE_REVISION */ -#if defined(BCM4358_CHIP) && defined(SUPPORT_MULTIPLE_REVISION) - if (chipid == BCM43569_CHIP_ID && config_chipid == BCM4358_CHIP_ID) { - return TRUE; - } -#endif /* BCM4358_CHIP && SUPPORT_MULTIPLE_REVISION */ -#if defined(BCM4359_CHIP) - if (chipid == BCM4355_CHIP_ID && config_chipid == BCM4359_CHIP_ID) { - return TRUE; - } -#endif /* BCM4359_CHIP */ -#if defined(BCM4361_CHIP) - if (chipid == BCM4347_CHIP_ID && config_chipid == BCM4361_CHIP_ID) { - return TRUE; - } -#endif /* BCM4361_CHIP */ - - return config_chipid == chipid; -} -#endif /* CUSTOMER_HW4_DEBUG */ - #if defined(BT_OVER_SDIO) wlan_bt_handle_t dhd_bt_get_pub_hndl(void) { @@ -12713,6 +9991,15 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_TRACE(("Enter %s:\n", __FUNCTION__)); dhdp->memdump_type = 0; dhdp->dongle_trap_occured = 0; + dhd->pub.dsack_hc_due_to_isr_delay = 0; + dhd->pub.dsack_hc_due_to_dpc_delay = 0; + dhdp->dongle_trap_during_wifi_onoff = 0; +#ifdef DHD_SSSR_DUMP + dhdp->collect_sssr = FALSE; +#endif /* DHD_SSSR_DUMP */ +#ifdef DHD_SDTC_ETB_DUMP + dhdp->collect_sdtc = FALSE; +#endif /* DHD_SDTC_ETB_DUMP */ #if defined(BCMPCIE) if (dhdp->extended_trap_data) { memset(dhdp->extended_trap_data, 0, BCMPCIE_EXT_TRAP_DATA_MAXLEN); @@ -12722,41 +10009,31 @@ dhd_bus_start(dhd_pub_t *dhdp) /* Flag to indicate sssr dump is collected */ dhdp->sssr_dump_collected = 0; #endif /* DHD_SSSR_DUMP */ -#ifdef BT_OVER_PCIE - dhd->pub.dongle_trap_due_to_bt = 0; -#endif /* BT_OVER_PCIE */ dhdp->iovar_timeout_occured = 0; #ifdef PCIE_FULL_DONGLE dhdp->d3ack_timeout_occured = 0; dhdp->livelock_occured = 0; dhdp->pktid_audit_failed = 0; + dhdp->pktid_invalid_occured = 0; #endif /* PCIE_FULL_DONGLE */ dhd->pub.iface_op_failed = 0; dhd->pub.scan_timeout_occurred = 0; dhd->pub.scan_busy_occurred = 0; + dhd->pub.p2p_disc_busy_occurred = 0; /* Retain BH induced errors and clear induced error during initialize */ if (dhd->pub.dhd_induce_error) { dhd->pub.dhd_induce_bh_error = dhd->pub.dhd_induce_error; } dhd->pub.dhd_induce_error = DHD_INDUCE_ERROR_CLEAR; -#ifdef DHD_PKTTS - dhd->latency = 0; -#endif +#ifdef DHD_MAP_PKTID_LOGGING + dhd->pub.enable_pktid_log_dump = FALSE; +#endif /* DHD_MAP_PKTID_LOGGING */ +#ifdef DHD_SUPPORT_SPMI_MODE + dhd->pub.dhd_spmi_mode = spmi_mode; +#endif /* DHD_SUPPORT_SPMI_MODE */ dhd->pub.tput_test_done = FALSE; -#if defined(BCMINTERNAL) && defined(BCMPCIE) - { - /* JIRA:SW4349-436 JIRA:HW4349-302 Work around for 4349a0 PCIE-D11 DMA bug */ - uint chipid = dhd_bus_chip_id(&dhd->pub); - uint revid = dhd_bus_chiprev_id(&dhd->pub); - - if ((chipid == BCM4349_CHIP_ID) && (revid == 1)) { - DHD_INFO(("%s:Detected 4349 A0 enable 16MB Mem restriction Flag", - __FUNCTION__)); - osl_flag_set(dhd->pub.osh, OSL_PHYS_MEM_LESS_THAN_16MB); - } - } -#endif /* BCMINTERNAL && BCMINTERNAL */ + dhd->pub.p2p_disc_busy_cnt = 0; /* try to download image and nvram to the dongle */ if (dhd->pub.busstate == DHD_BUS_DOWN && dhd_update_fw_nv_path(dhd)) { /* Indicate FW Download has not yet done */ @@ -12766,6 +10043,7 @@ dhd_bus_start(dhd_pub_t *dhdp) #if defined(DHD_DEBUG) && defined(BCMSDIO) fw_download_start = OSL_SYSUPTIME(); #endif /* DHD_DEBUG && BCMSDIO */ + dhd_bus_set_signature_path(dhd->pub.bus, dhd->sig_path); ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, dhd->fw_path, dhd->nv_path, dhd->clm_path, dhd->conf_path); #if defined(DHD_DEBUG) && defined(BCMSDIO) @@ -12833,7 +10111,7 @@ dhd_bus_start(dhd_pub_t *dhdp) /* max_h2d_rings includes H2D common rings */ uint32 max_h2d_rings = dhd_bus_max_h2d_queues(dhd->pub.bus); - DHD_ERROR(("%s: Initializing %u h2drings\n", __FUNCTION__, + DHD_INFO(("%s: Initializing %u h2drings\n", __FUNCTION__, max_h2d_rings)); if ((ret = dhd_flow_rings_init(&dhd->pub, max_h2d_rings)) != BCME_OK) { #ifdef BCMSDIO @@ -12896,30 +10174,22 @@ dhd_bus_start(dhd_pub_t *dhdp) return ret; } -#ifdef BT_OVER_PCIE - /* Enable L1SS of RC and EP */ - dhd_bus_l1ss_enable_rc_ep(dhdp->bus, TRUE); -#endif /* BT_OVER_PCIE */ - -#if defined(CUSTOMER_HW_ROCKCHIP) && defined(BCMPCIE) +#ifdef BCMPCIE +#if defined(CUSTOMER_HW_ROCKCHIP) && defined(CUSTOMER_HW_ROCKCHIP_RK3588) if (IS_ENABLED(CONFIG_PCIEASPM_ROCKCHIP_WIFI_EXTENSION)) rk_dhd_bus_l1ss_enable_rc_ep(dhdp->bus, TRUE); #endif /* CUSTOMER_HW_ROCKCHIP && BCMPCIE */ +#endif /* BCMPCIE */ -#if defined(CONFIG_ARCH_EXYNOS) && defined(BCMPCIE) -#if !defined(CONFIG_SOC_EXYNOS8890) && !defined(SUPPORT_EXYNOS7420) +#if defined(BCMPCIE) /* XXX: JIRA SWWLAN-139454: Added L1ss enable * after firmware download completion due to link down issue * JIRA SWWLAN-142236: Amendment - Changed L1ss enable point */ - DHD_ERROR(("%s: Enable L1ss EP side\n", __FUNCTION__)); -#if defined(CONFIG_SOC_GS101) - exynos_pcie_rc_l1ss_ctrl(1, PCIE_L1SS_CTRL_WIFI, 1); -#else - exynos_pcie_l1ss_ctrl(1, PCIE_L1SS_CTRL_WIFI); -#endif /* CONFIG_SOC_GS101 */ -#endif /* !CONFIG_SOC_EXYNOS8890 && !SUPPORT_EXYNOS7420 */ -#endif /* CONFIG_ARCH_EXYNOS && BCMPCIE */ + DHD_RPM(("%s: Enable L1ss EP side\n", __FUNCTION__)); + dhd_plat_l1ss_ctrl(1); +#endif /* BCMPCIE */ + #if defined(DHD_DEBUG) && defined(BCMSDIO) f2_sync_end = OSL_SYSUPTIME(); DHD_ERROR(("Time taken for FW download and F2 ready is: %d msec\n", @@ -13155,444 +10425,8 @@ bool dhd_is_concurrent_mode(dhd_pub_t *dhd) else return FALSE; } -#if defined(OEM_ANDROID) && !defined(AP) && defined(WLP2P) -/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware - * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA - * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware - * would still be named as fw_bcmdhd_apsta. - */ -uint32 -dhd_get_concurrent_capabilites(dhd_pub_t *dhd) -{ - int32 ret = 0; - char buf[WLC_IOCTL_SMLEN]; - bool mchan_supported = FALSE; - /* if dhd->op_mode is already set for HOSTAP and Manufacturing - * test mode, that means we only will use the mode as it is - */ - if (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE)) - return 0; - if (FW_SUPPORTED(dhd, vsdb)) { - mchan_supported = TRUE; - } - if (!FW_SUPPORTED(dhd, p2p)) { - DHD_TRACE(("Chip does not support p2p\n")); - return 0; - } else { - /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */ - memset(buf, 0, sizeof(buf)); - ret = dhd_iovar(dhd, 0, "p2p", NULL, 0, (char *)&buf, - sizeof(buf), FALSE); - if (ret < 0) { - DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); - return 0; - } else { - if (buf[0] == 1) { - /* By default, chip supports single chan concurrency, - * now lets check for mchan - */ - ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; - if (mchan_supported) - ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; - if (FW_SUPPORTED(dhd, rsdb)) { - ret |= DHD_FLAG_RSDB_MODE; - } -#ifdef WL_SUPPORT_MULTIP2P - if (FW_SUPPORTED(dhd, mp2p)) { - ret |= DHD_FLAG_MP2P_MODE; - } -#endif /* WL_SUPPORT_MULTIP2P */ -#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) - return ret; -#else - return 0; -#endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */ - } - } - } - return 0; -} -#endif /* defined(OEM_ANDROID) && !defined(AP) && defined(WLP2P) */ -#ifdef SUPPORT_AP_POWERSAVE -#define RXCHAIN_PWRSAVE_PPS 10 -#define RXCHAIN_PWRSAVE_QUIET_TIME 10 -#define RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK 0 -int dhd_set_ap_powersave(dhd_pub_t *dhdp, int ifidx, int enable) -{ - int32 pps = RXCHAIN_PWRSAVE_PPS; - int32 quiet_time = RXCHAIN_PWRSAVE_QUIET_TIME; - int32 stas_assoc_check = RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK; - int ret; - - if (enable) { - ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_enable", (char *)&enable, sizeof(enable), - NULL, 0, TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("Failed to enable AP power save")); - } - ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_pps", (char *)&pps, sizeof(pps), NULL, 0, - TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("Failed to set pps")); - } - ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_quiet_time", (char *)&quiet_time, - sizeof(quiet_time), NULL, 0, TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("Failed to set quiet time")); - } - ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_stas_assoc_check", - (char *)&stas_assoc_check, sizeof(stas_assoc_check), NULL, 0, TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("Failed to set stas assoc check")); - } - } else { - ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_enable", (char *)&enable, sizeof(enable), - NULL, 0, TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("Failed to disable AP power save")); - } - } - - return 0; -} -#endif /* SUPPORT_AP_POWERSAVE */ - -#if defined(READ_CONFIG_FROM_FILE) -#include -#include - -#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) -bool PM_control = TRUE; - -static int dhd_preinit_proc(dhd_pub_t *dhd, int ifidx, char *name, char *value) -{ - int var_int; - wl_country_t cspec = {{0}, -1, {0}}; - char *revstr; - char *endptr = NULL; -#ifdef ROAM_AP_ENV_DETECTION - int roam_env_mode = AP_ENV_INDETERMINATE; -#endif /* ROAM_AP_ENV_DETECTION */ - - if (!strcmp(name, "country")) { - revstr = strchr(value, '/'); -#if defined(DHD_BLOB_EXISTENCE_CHECK) - if (dhd->is_blob) { - cspec.rev = 0; - memcpy(cspec.country_abbrev, value, WLC_CNTRY_BUF_SZ); - memcpy(cspec.ccode, value, WLC_CNTRY_BUF_SZ); - } else -#endif /* DHD_BLOB_EXISTENCE_CHECK */ - { - if (revstr) { - cspec.rev = strtoul(revstr + 1, &endptr, 10); - memcpy(cspec.country_abbrev, value, WLC_CNTRY_BUF_SZ); - cspec.country_abbrev[2] = '\0'; - memcpy(cspec.ccode, cspec.country_abbrev, WLC_CNTRY_BUF_SZ); - } else { - cspec.rev = -1; - memcpy(cspec.country_abbrev, value, WLC_CNTRY_BUF_SZ); - memcpy(cspec.ccode, value, WLC_CNTRY_BUF_SZ); - get_customized_country_code(dhd->info->adapter, - (char *)&cspec.country_abbrev, &cspec); - } - - } - DHD_ERROR(("config country code is country : %s, rev : %d !!\n", - cspec.country_abbrev, cspec.rev)); - return dhd_iovar(dhd, 0, "country", (char*)&cspec, sizeof(cspec), NULL, 0, TRUE); - } else if (!strcmp(name, "roam_scan_period")) { - var_int = (int)simple_strtol(value, NULL, 0); - return dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, - &var_int, sizeof(var_int), TRUE, 0); - } else if (!strcmp(name, "roam_delta")) { - struct { - int val; - int band; - } x; - x.val = (int)simple_strtol(value, NULL, 0); - /* x.band = WLC_BAND_AUTO; */ - x.band = WLC_BAND_ALL; - return dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, &x, sizeof(x), TRUE, 0); - } else if (!strcmp(name, "roam_trigger")) { - int ret = 0; - int roam_trigger[2]; - - roam_trigger[0] = (int)simple_strtol(value, NULL, 0); - roam_trigger[1] = WLC_BAND_ALL; - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, &roam_trigger, - sizeof(roam_trigger), TRUE, 0); - -#ifdef ROAM_AP_ENV_DETECTION - if (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER) { - if (dhd_iovar(dhd, 0, "roam_env_detection", - (char *)&roam_env_mode, sizeof(roam_env_mode), NULL, - 0, TRUE) == BCME_OK) { - dhd->roam_env_detection = TRUE; - } else { - dhd->roam_env_detection = FALSE; - } - } -#endif /* ROAM_AP_ENV_DETECTION */ - return ret; - } else if (!strcmp(name, "PM")) { - int ret = 0; - var_int = (int)simple_strtol(value, NULL, 0); - - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, - &var_int, sizeof(var_int), TRUE, 0); - -#if defined(DHD_PM_CONTROL_FROM_FILE) || defined(CONFIG_PM_LOCK) - if (var_int == 0) { - g_pm_control = TRUE; - printk("%s var_int=%d don't control PM\n", __func__, var_int); - } else { - g_pm_control = FALSE; - printk("%s var_int=%d do control PM\n", __func__, var_int); - } -#endif - - return ret; - } - else if (!strcmp(name, "band")) { - int ret; - if (!strcmp(value, "auto")) - var_int = WLC_BAND_AUTO; - else if (!strcmp(value, "a")) - var_int = WLC_BAND_5G; - else if (!strcmp(value, "b")) - var_int = WLC_BAND_2G; - else if (!strcmp(value, "all")) - var_int = WLC_BAND_ALL; - else { - printk(" set band value should be one of the a or b or all\n"); - var_int = WLC_BAND_AUTO; - } - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_BAND, &var_int, - sizeof(var_int), TRUE, 0)) < 0) - printk(" set band err=%d\n", ret); - return ret; - } else if (!strcmp(name, "cur_etheraddr")) { - struct ether_addr ea; - int ret; - - bcm_ether_atoe(value, &ea); - - ret = memcmp(&ea.octet, dhd->mac.octet, ETHER_ADDR_LEN); - if (ret == 0) { - DHD_ERROR(("%s: Same Macaddr\n", __FUNCTION__)); - return 0; - } - - DHD_ERROR(("%s: Change Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", __FUNCTION__, - ea.octet[0], ea.octet[1], ea.octet[2], - ea.octet[3], ea.octet[4], ea.octet[5])); - - ret = dhd_iovar(dhd, 0, "cur_etheraddr", (char*)&ea, ETHER_ADDR_LEN, NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); - return ret; - } else { - memcpy(dhd->mac.octet, (void *)&ea, ETHER_ADDR_LEN); - return ret; - } - } else if (!strcmp(name, "lpc")) { - int ret = 0; - var_int = (int)simple_strtol(value, NULL, 0); - if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { - DHD_ERROR(("%s: wl down failed\n", __FUNCTION__)); - } - ret = dhd_iovar(dhd, 0, "lpc", (char *)&var_int, sizeof(var_int), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret)); - } - if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { - DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); - } - return ret; - } else if (!strcmp(name, "vht_features")) { - int ret = 0; - var_int = (int)simple_strtol(value, NULL, 0); - - if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { - DHD_ERROR(("%s: wl down failed\n", __FUNCTION__)); - } - ret = dhd_iovar(dhd, 0, "vht_features", (char *)&var_int, sizeof(var_int), NULL, 0, - TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set vht_features failed %d\n", __FUNCTION__, ret)); - } - if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { - DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); - } - return ret; - } else { - /* wlu_iovar_setint */ - var_int = (int)simple_strtol(value, NULL, 0); - - /* Setup timeout bcm_timeout from dhd driver 4.217.48 */ - - DHD_INFO(("%s:[%s]=[%d]\n", __FUNCTION__, name, var_int)); - - return dhd_iovar(dhd, 0, name, (char *)&var_int, - sizeof(var_int), NULL, 0, TRUE); - } - - return 0; -} - -static int dhd_preinit_config(dhd_pub_t *dhd, int ifidx) -{ - mm_segment_t old_fs; - struct kstat stat; - struct file *fp = NULL; - unsigned int len; - char *buf = NULL, *p, *name, *value; - int ret = 0; - char *config_path; - - config_path = CONFIG_BCMDHD_CONFIG_PATH; - - if (!config_path) - { - printk(KERN_ERR "config_path can't read. \n"); - return 0; - } - - old_fs = get_fs(); - set_fs(get_ds()); - if ((ret = vfs_stat(config_path, &stat))) { - set_fs(old_fs); - printk(KERN_ERR "%s: Failed to get information (%d)\n", - config_path, ret); - return ret; - } - set_fs(old_fs); - - if (!(buf = MALLOC(dhd->osh, stat.size + 1))) { - printk(KERN_ERR "Failed to allocate memory %llu bytes\n", stat.size); - return -ENOMEM; - } - memset(buf, 0x0, stat.size + 1); - printk("dhd_preinit_config : config path : %s \n", config_path); - - if (!(fp = dhd_os_open_image1(dhd, config_path)) || - (len = dhd_os_get_image_block(buf, stat.size, fp)) < 0) - goto err; - - if (len != stat.size) { - printk("dhd_preinit_config : Error - read length mismatched len = %d\n", len); - goto err; - } - - buf[stat.size] = '\0'; - for (p = buf; *p; p++) { - if (isspace(*p)) - continue; - for (name = p++; *p && !isspace(*p); p++) { - if (*p == '=') { - *p = '\0'; - p++; - for (value = p; *p && !isspace(*p); p++); - *p = '\0'; - if ((ret = dhd_preinit_proc(dhd, ifidx, name, value)) < 0) { - printk(KERN_ERR "%s: %s=%s\n", - bcmerrorstr(ret), name, value); - } - break; - } - } - } - ret = 0; - -out: - if (fp) - dhd_os_close_image1(dhd, fp); - if (buf) - MFREE(dhd->osh, buf, stat.size+1); - return ret; - -err: - ret = -1; - goto out; -} -#endif /* READ_CONFIG_FROM_FILE */ - -#ifdef WLAIBSS -int -dhd_preinit_aibss_ioctls(dhd_pub_t *dhd, char *iov_buf_smlen) -{ - int ret = BCME_OK; - aibss_bcn_force_config_t bcn_config; - uint32 aibss; -#ifdef WLAIBSS_PS - uint32 aibss_ps; - s32 atim; -#endif /* WLAIBSS_PS */ - int ibss_coalesce; - - aibss = 1; - ret = dhd_iovar(dhd, 0, "aibss", (char *)&aibss, sizeof(aibss), NULL, 0, TRUE); - if (ret < 0) { - if (ret == BCME_UNSUPPORTED) { - DHD_ERROR(("%s aibss , UNSUPPORTED\n", __FUNCTION__)); - return BCME_OK; - } else { - DHD_ERROR(("%s Set aibss to %d err(%d)\n", __FUNCTION__, aibss, ret)); - return ret; - } - } - -#ifdef WLAIBSS_PS - aibss_ps = 1; - ret = dhd_iovar(dhd, 0, "aibss_ps", (char *)&aibss_ps, sizeof(aibss_ps), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set aibss PS to %d failed %d\n", - __FUNCTION__, aibss, ret)); - return ret; - } - - atim = 10; - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ATIM, - (char *)&atim, sizeof(atim), TRUE, 0)) < 0) { - DHD_ERROR(("%s Enable custom IBSS ATIM mode failed %d\n", - __FUNCTION__, ret)); - return ret; - } -#endif /* WLAIBSS_PS */ - - memset(&bcn_config, 0, sizeof(bcn_config)); - bcn_config.initial_min_bcn_dur = AIBSS_INITIAL_MIN_BCN_DUR; - bcn_config.min_bcn_dur = AIBSS_MIN_BCN_DUR; - bcn_config.bcn_flood_dur = AIBSS_BCN_FLOOD_DUR; - bcn_config.version = AIBSS_BCN_FORCE_CONFIG_VER_0; - bcn_config.len = sizeof(bcn_config); - - ret = dhd_iovar(dhd, 0, "aibss_bcn_force_config", (char *)&bcn_config, - sizeof(aibss_bcn_force_config_t), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set aibss_bcn_force_config to %d, %d, %d failed %d\n", - __FUNCTION__, AIBSS_INITIAL_MIN_BCN_DUR, AIBSS_MIN_BCN_DUR, - AIBSS_BCN_FLOOD_DUR, ret)); - return ret; - } - - ibss_coalesce = IBSS_COALESCE_DEFAULT; - ret = dhd_iovar(dhd, 0, "ibss_coalesce_allowed", (char *)&ibss_coalesce, - sizeof(ibss_coalesce), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set ibss_coalesce_allowed failed %d\n", - __FUNCTION__, ret)); - return ret; - } - - dhd->op_mode |= DHD_FLAG_IBSS_MODE; - return BCME_OK; -} -#endif /* WLAIBSS */ - -#if defined(WLADPS) || defined(WLADPS_PRIVATE_CMD) +#if defined(WLADPS) #ifdef WL_BAM static int dhd_check_adps_bad_ap(dhd_pub_t *dhd) @@ -13620,6 +10454,11 @@ dhd_check_adps_bad_ap(dhd_pub_t *dhd) } profile = wl_get_profile_by_netdev(cfg, ndev); + if (!profile) { + DHD_ERROR(("%s : Cannot get profile\n", __FUNCTION__)); + return -EINVAL; + } + memcpy(bssid.octet, profile->bssid, ETHER_ADDR_LEN); if (wl_adps_bad_ap_check(cfg, &bssid)) { if (wl_adps_enabled(cfg, ndev)) { @@ -13687,10 +10526,10 @@ exit: } return ret; } -#endif /* WLADPS || WLADPS_PRIVATE_CMD */ +#endif /* WLADPS */ int -dhd_get_preserve_log_numbers(dhd_pub_t *dhd, uint32 *logset_mask) +dhd_get_preserve_log_numbers(dhd_pub_t *dhd, uint64 *logset_mask) { wl_el_set_type_t logset_type, logset_op; wl_el_set_all_type_v1_t *logset_all_type_op = NULL; @@ -13716,7 +10555,11 @@ dhd_get_preserve_log_numbers(dhd_pub_t *dhd, uint32 *logset_mask) *logset_mask = 0; memset(&logset_type, 0, sizeof(logset_type)); memset(&logset_op, 0, sizeof(logset_op)); +#if defined(EVENT_LOG_SET_TYPE_VERSION_0) + logset_type.version = htod16(EVENT_LOG_SET_TYPE_VERSION_0); +#else logset_type.version = htod16(EVENT_LOG_SET_TYPE_CURRENT_VERSION); +#endif logset_type.len = htod16(sizeof(wl_el_set_type_t)); /* Try with set = event_log_max_sets, if fails, use legacy event_log_set_type */ @@ -13741,9 +10584,9 @@ dhd_get_preserve_log_numbers(dhd_pub_t *dhd, uint32 *logset_mask) */ if (err == BCME_OK && logset_op.type == EVENT_LOG_SET_TYPE_PRSRV) { - *logset_mask |= 0x01u << i; + *logset_mask |= 0x01ULL << i; ret = BCME_OK; - DHD_ERROR(("[INIT] logset:%d is preserve/chatty\n", i)); + DHD_INFO(("[INIT] logset:%d is preserve/chatty\n", i)); } } @@ -13820,9 +10663,6 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) int ret = 0; /* Room for "event_msgs_ext" + '\0' + bitvec */ char iovbuf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE + 16]; -#ifdef DHD_PKTTS - uint32 val = 0; -#endif uint32 event_log_max_sets = 0; char* iov_buf = NULL; /* XXX: Use ret2 for return check of IOVARS that might return BCME_UNSUPPORTED, @@ -13865,24 +10705,27 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) uint32 hostwake_oob = 0; #endif /* BCMPCIE_OOB_HOST_WAKE */ wl_wlc_version_t wlc_ver; +#ifdef CUSTOM_OCL_RSSI_VAL + int ocl_rssi_threshold = CUSTOM_OCL_RSSI_VAL; +#endif /* CUSTOM_OCL_RSSI_VAL */ #if defined(WBTEXT) && defined(RRM_BCNREQ_MAX_CHAN_TIME) uint32 rrm_bcn_req_thrtl_win = RRM_BCNREQ_MAX_CHAN_TIME * 2; uint32 rrm_bcn_req_max_off_chan_time = RRM_BCNREQ_MAX_CHAN_TIME; #endif /* WBTEXT && RRM_BCNREQ_MAX_CHAN_TIME */ + + uint32 d3_hostwake_delay = D3_HOSTWAKE_DELAY; +#ifdef SUPPORT_MULTIPLE_CLMBLOB + char customer_clm_file_name[MAX_FILE_LEN] = {0, }; +#endif /* SUPPORT_MULTIPLE_CLMBLOB */ + char* apply_clm; + #ifdef PKT_FILTER_SUPPORT dhd_pkt_filter_enable = TRUE; +#endif /* PKT_FILTER_SUPPORT */ #ifdef APF dhd->apf_set = FALSE; #endif /* APF */ -#endif /* PKT_FILTER_SUPPORT */ - dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; -#ifdef ENABLE_MAX_DTIM_IN_SUSPEND - dhd->max_dtim_enable = TRUE; -#else - dhd->max_dtim_enable = FALSE; -#endif /* ENABLE_MAX_DTIM_IN_SUSPEND */ - dhd->disable_dtim_in_suspend = FALSE; #ifdef CUSTOM_SET_OCLOFF dhd->ocl_off = FALSE; #endif /* CUSTOM_SET_OCLOFF */ @@ -13905,17 +10748,6 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) dhd->dhd_cflags &= ~WLAN_PLAT_AP_FLAG; #endif /* CUSTOM_COUNTRY_CODE */ -#ifdef CUSTOMER_HW4_DEBUG - if (!dhd_validate_chipid(dhd)) { - DHD_ERROR(("%s: CONFIG_BCMXXX and CHIP ID(%x) is mismatched\n", - __FUNCTION__, dhd_bus_chip_id(dhd))); -#ifndef SUPPORT_MULTIPLE_CHIPS - ret = BCME_BADARG; - goto done; -#endif /* !SUPPORT_MULTIPLE_CHIPS */ - } -#endif /* CUSTOMER_HW4_DEBUG */ - /* query for 'ver' to get version info from firmware */ memset(buf, 0, sizeof(buf)); ptr = buf; @@ -13925,12 +10757,8 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) else { bcmstrtok(&ptr, "\n", 0); /* Print fw version info */ - DHD_ERROR(("Firmware version = %s\n", buf)); strncpy(fw_version, buf, FW_VER_STR_LEN); fw_version[FW_VER_STR_LEN-1] = '\0'; -#if defined(BCMSDIO) || defined(BCMPCIE) - dhd_set_version_info(dhd, buf); -#endif /* BCMSDIO || BCMPCIE */ } /* query for 'wlc_ver' to get version info from firmware */ @@ -13945,14 +10773,13 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) dhd->wlc_ver_major = wlc_ver.wlc_ver_major; dhd->wlc_ver_minor = wlc_ver.wlc_ver_minor; } -#ifdef BOARD_HIKEY +// mark flag for later blob checking /* Set op_mode as MFG_MODE if WLTEST is present in "wl ver" */ if (strstr(fw_version, "WLTEST") != NULL) { DHD_ERROR(("%s: wl ver has WLTEST, setting op_mode as DHD_FLAG_MFG_MODE\n", __FUNCTION__)); op_mode = DHD_FLAG_MFG_MODE; } -#endif /* BOARD_HIKEY */ /* get a capabilities from firmware */ ret = dhd_get_fw_capabilities(dhd); @@ -13969,11 +10796,6 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) /* disable runtimePM by default in MFG mode. */ pm_runtime_disable(dhd_bus_to_dev(dhd->bus)); #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ -#ifdef DHD_PCIE_RUNTIMEPM - /* Disable RuntimePM in mfg mode */ - DHD_DISABLE_RUNTIME_PM(dhd); - DHD_ERROR(("%s : Disable RuntimePM in Manufactring Firmware\n", __FUNCTION__)); -#endif /* DHD_PCIE_RUNTIME_PM */ /* Check and adjust IOCTL response timeout for Manufactring firmware */ dhd_os_set_ioctl_resp_timeout(MFG_IOCTL_RESP_TIMEOUT); DHD_ERROR(("%s : Set IOCTL response time for Manufactring Firmware\n", @@ -14102,13 +10924,25 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) dhd->mac.octet, ETHER_ADDR_LEN); } - if ((ret = dhd_apply_default_clm(dhd, dhd->clm_path)) < 0) { - DHD_ERROR(("%s: CLM set failed. Abort initialization.\n", __FUNCTION__)); - goto done; +#ifdef SUPPORT_MULTIPLE_CLMBLOB + if (dhd_get_platform_naming_for_nvram_clmblob_file(CLM_BLOB, + customer_clm_file_name) == BCME_OK) { + apply_clm = customer_clm_file_name; + } + else +#endif /* SUPPORT_MULTIPLE_CLMBLOB */ + { + apply_clm = dhd->info->clm_path; + } + + if ((ret = dhd_apply_default_clm(dhd, apply_clm)) < 0) { + DHD_ERROR(("%s: CLM set failed. Ignore and continue initialization.\n", + __FUNCTION__)); } DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n", dhd->op_mode, MAC2STRDBG(dhd->mac.octet))); + dhd_set_version_info(dhd, fw_version); #if defined(DHD_BLOB_EXISTENCE_CHECK) if (!dhd->is_blob) #endif /* DHD_BLOB_EXISTENCE_CHECK */ @@ -14129,6 +10963,13 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) else dhd->info->rxthread_enabled = TRUE; #endif + +#if defined(CUSTOM_COUNTRY_CODE_XZ) + /* Set initial country code to XZ */ + strlcpy(dhd->dhd_cspec.country_abbrev, "XZ", WLC_CNTRY_BUF_SZ); + strlcpy(dhd->dhd_cspec.ccode, "XZ", WLC_CNTRY_BUF_SZ); + DHD_ERROR(("%s: Set initial country code to XZ(World Wide Safe)\n", __FUNCTION__)); +#endif /* CUSTOM_COUNTRY_CODE_XZ */ /* Set Country code */ if (dhd->dhd_cspec.ccode[0] != 0) { ret = dhd_iovar(dhd, 0, "country", (char *)&dhd->dhd_cspec, sizeof(wl_country_t), @@ -14138,22 +10979,19 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) } #if defined(ROAM_ENABLE) - BCM_REFERENCE(roamvar); #ifdef USE_WFA_CERT_CONF if (sec_get_param_wfa_cert(dhd, SET_PARAM_ROAMOFF, &roamvar) == BCME_OK) { DHD_ERROR(("%s: read roam_off param =%d\n", __FUNCTION__, roamvar)); } - /* roamvar is set to 0 by preinit fw, change only if roamvar is non-zero */ - if (roamvar != 0) { - /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ - ret = dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), NULL, 0, - TRUE); - if (ret < 0) { - DHD_ERROR(("%s roam_off failed %d\n", __FUNCTION__, ret)); - } - } #endif /* USE_WFA_CERT_CONF */ - + /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ + ret = dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s roam_off failed %d\n", __FUNCTION__, ret)); + } +#ifdef WL_CFG80211 + ROAMOFF_DBG_SAVE(dhd_linux_get_primary_netdev(dhd), SET_ROAM_PREINIT, roamvar); +#endif /* WL_CFG80211 */ #ifdef ROAM_AP_ENV_DETECTION /* Changed to GET iovar to read roam_env_mode */ dhd->roam_env_detection = FALSE; @@ -14180,6 +11018,9 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) } #endif /* CONFIG_ROAM_MIN_DELTA */ #endif /* ROAM_ENABLE */ +#ifdef CUSTOM_EVENT_PM_WAKE + dhd_init_excess_pm_awake(dhd); +#endif /* CUSTOM_EVENT_PM_WAKE */ #ifdef WLTDLS dhd->tdls_enable = FALSE; @@ -14190,11 +11031,7 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) #endif /* WLTDLS */ #ifdef DHD_PM_CONTROL_FROM_FILE -#ifdef CUSTOMER_HW10 - dhd_control_pm(dhd, &power_mode); -#else sec_control_pm(dhd, &power_mode); -#endif /* CUSTOMER_HW10 */ #endif /* DHD_PM_CONTROL_FROM_FILE */ #ifdef MIMO_ANT_SETTING @@ -14301,6 +11138,10 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) dhd_update_flow_prio_map(dhd, DHD_FLOW_PRIO_LLR_MAP); #endif /* defined(BCMPCIE) && defined(EAPOL_PKT_PRIO) */ +#if defined(BCMSDIO) && defined(DHD_LOSSLESS_ROAMING) + dhd_update_sdio_data_prio_map(dhd); +#endif /* BCMSDIO && DHD_LOSSLESS_ROAMING */ + #ifdef ARP_OFFLOAD_SUPPORT DHD_ERROR(("arp_enable:%d arp_ol:%d\n", dhd->arpoe_enable, dhd->arpol_configured)); @@ -14312,60 +11153,64 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) */ #ifdef PKT_FILTER_SUPPORT /* Setup default defintions for pktfilter , enable in suspend */ - dhd->pktfilter_count = 6; - dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL; - if (!FW_SUPPORTED(dhd, pf6)) { - dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL; - dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; - } else { - /* Immediately pkt filter TYPE 6 Discard IPv4/IPv6 Multicast Packet */ - dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = DISCARD_IPV4_MCAST; - dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = DISCARD_IPV6_MCAST; - } - /* apply APP pktfilter */ - dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806"; + if (dhd_master_mode) { + dhd->pktfilter_count = 6; + dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL; + if (!FW_SUPPORTED(dhd, pf6)) { + dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL; + dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; + } else { + /* Immediately pkt filter TYPE 6 Discard IPv4/IPv6 Multicast Packet */ + dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = DISCARD_IPV4_MCAST; + dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = DISCARD_IPV6_MCAST; + } + /* apply APP pktfilter */ + dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806"; #ifdef BLOCK_IPV6_PACKET - /* Setup filter to allow only IPv4 unicast frames */ - dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 " - HEX_PREF_STR UNI_FILTER_STR ZERO_ADDR_STR ETHER_TYPE_STR IPV6_FILTER_STR - " " - HEX_PREF_STR ZERO_ADDR_STR ZERO_ADDR_STR ETHER_TYPE_STR ZERO_TYPE_STR; + /* Setup filter to allow only IPv4 unicast frames */ + dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 " + HEX_PREF_STR UNI_FILTER_STR ZERO_ADDR_STR ETHER_TYPE_STR IPV6_FILTER_STR + " " + HEX_PREF_STR ZERO_ADDR_STR ZERO_ADDR_STR ETHER_TYPE_STR ZERO_TYPE_STR; #else - /* Setup filter to allow only unicast */ - dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00"; + /* Setup filter to allow only unicast */ + dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00"; #endif /* BLOCK_IPV6_PACKET */ #ifdef PASS_IPV4_SUSPEND - /* XXX customer want to get IPv4 multicast packets */ - dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFF 0x01005E"; + /* XXX customer want to get IPv4 multicast packets */ + dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFF 0x01005E"; #else - /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ - dhd->pktfilter[DHD_MDNS_FILTER_NUM] = NULL; + /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ + dhd->pktfilter[DHD_MDNS_FILTER_NUM] = NULL; #endif /* PASS_IPV4_SUSPEND */ - if (FW_SUPPORTED(dhd, pf6)) { - /* Immediately pkt filter TYPE 6 Dicard Broadcast IP packet */ - dhd->pktfilter[DHD_IP4BCAST_DROP_FILTER_NUM] = DISCARD_IPV4_BCAST; - /* Immediately pkt filter TYPE 6 Dicard Cisco STP packet */ - dhd->pktfilter[DHD_LLC_STP_DROP_FILTER_NUM] = DISCARD_LLC_STP; - /* Immediately pkt filter TYPE 6 Dicard Cisco XID protocol */ - dhd->pktfilter[DHD_LLC_XID_DROP_FILTER_NUM] = DISCARD_LLC_XID; - /* Immediately pkt filter TYPE 6 Dicard NETBIOS packet(port 137) */ - dhd->pktfilter[DHD_UDPNETBIOS_DROP_FILTER_NUM] = DISCARD_UDPNETBIOS; - dhd->pktfilter_count = 11; - } + if (FW_SUPPORTED(dhd, pf6)) { + /* Immediately pkt filter TYPE 6 Dicard Broadcast IP packet */ + dhd->pktfilter[DHD_IP4BCAST_DROP_FILTER_NUM] = DISCARD_IPV4_BCAST; + /* Immediately pkt filter TYPE 6 Dicard Cisco STP packet */ + dhd->pktfilter[DHD_LLC_STP_DROP_FILTER_NUM] = DISCARD_LLC_STP; + /* Immediately pkt filter TYPE 6 Dicard Cisco XID protocol */ + dhd->pktfilter[DHD_LLC_XID_DROP_FILTER_NUM] = DISCARD_LLC_XID; + /* Immediately pkt filter TYPE 6 Dicard NETBIOS packet(port 137) */ + dhd->pktfilter[DHD_UDPNETBIOS_DROP_FILTER_NUM] = DISCARD_UDPNETBIOS; + dhd->pktfilter_count = 11; + } #ifdef GAN_LITE_NAT_KEEPALIVE_FILTER - dhd->pktfilter_count = 4; - /* Setup filter to block broadcast and NAT Keepalive packets */ - /* discard all broadcast packets */ - dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0xffffff 0xffffff"; - /* discard NAT Keepalive packets */ - dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = "102 0 0 36 0xffffffff 0x11940009"; - /* discard NAT Keepalive packets */ - dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = "104 0 0 38 0xffffffff 0x11940009"; - dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; + dhd->pktfilter_count = 4; + /* Setup filter to block broadcast and NAT Keepalive packets */ + /* discard all broadcast packets */ + dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0xffffff 0xffffff"; + /* discard NAT Keepalive packets */ + dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = "102 0 0 36 0xffffffff 0x11940009"; + /* discard NAT Keepalive packets */ + dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = "104 0 0 38 0xffffffff 0x11940009"; + dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; #endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */ + } else + dhd_conf_discard_pkt_filter(dhd); + dhd_conf_add_pkt_filter(dhd); #if defined(SOFTAP) if (ap_fw_loaded) { @@ -14398,41 +11243,6 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) } } -#if defined(CUSTOMER_HW4_DEBUG) - if ((ver_temp_buf = bcmstrstr(ptr, "Customization:")) == NULL) { - DHD_ERROR(("Couldn't find \"Customization:\"\n")); - } else { - char tokenlim; - ptr = (ver_temp_buf + strlen("Customization:")); - if ((ver_temp_buf = bcmstrtok(&ptr, "(\n", &tokenlim)) == NULL) { - DHD_ERROR(("Couldn't find project blob version" - "or New line character\n")); - } else if (tokenlim == '(') { - snprintf(clm_version, - CLM_VER_STR_LEN - 1, "%s, Blob ver = Major : %s minor : ", - clm_version, ver_temp_buf); - DHD_INFO(("[INFO]CLM/Blob version = %s\n", clm_version)); - if ((ver_temp_buf = bcmstrtok(&ptr, "\n", &tokenlim)) == NULL) { - DHD_ERROR(("Couldn't find New line character\n")); - } else { - snprintf(clm_version, - strlen(clm_version) + strlen(ver_temp_buf), - "%s%s", clm_version, ver_temp_buf); - DHD_INFO(("[INFO]CLM/Blob/project version = %s\n", - clm_version)); - - } - } else if (tokenlim == '\n') { - snprintf(clm_version, - strlen(clm_version) + strlen(", Blob ver = Major : ") + 1, - "%s, Blob ver = Major : ", clm_version); - snprintf(clm_version, - strlen(clm_version) + strlen(ver_temp_buf) + 1, - "%s%s", clm_version, ver_temp_buf); - DHD_INFO(("[INFO]CLM/Blob/project version = %s\n", clm_version)); - } - } -#endif /* CUSTOMER_HW4_DEBUG */ if (strlen(clm_version)) { DHD_ERROR(("CLM version = %s\n", clm_version)); } else { @@ -14442,7 +11252,21 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) } #ifdef WRITE_WLANINFO - sec_save_wlinfo(fw_version, EPI_VERSION_STR, dhd->info->nv_path, clm_version); + do { + uint len = MAX_NVRAMBUF_SIZE; + char *memblock = NULL; + + dhd_get_download_buffer(dhd, dhd->info->nv_path, NVRAM, &memblock, (int *)&len); + if ((len <= 0 || len > MAX_NVRAMBUF_SIZE)) { + DHD_ERROR(("Can't open nvram info, skip save wifiver info\n")); + break; + } + + sec_save_wlinfo(fw_version, EPI_VERSION_STR, memblock, clm_version); + if (memblock) { + dhd_free_download_buffer(dhd, memblock, len); + } + } while (0); #endif /* WRITE_WLANINFO */ #ifdef GEN_SOFTAP_INFO_FILE @@ -14455,33 +11279,6 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) } #endif -#ifdef DHD_PKTTS - /* get the pkt metadata buffer length supported by FW */ - if (dhd_wl_ioctl_get_intiovar(dhd, "bus:metadata_info", &val, - WLC_GET_VAR, FALSE, 0) != BCME_OK) { - DHD_ERROR(("%s: failed to get pkt metadata buflen, use IPC pkt TS.\n", - __FUNCTION__)); - /* - * if iovar fails, IPC method of collecting - * TS should be used, hence set metadata_buflen as - * 0 here. This will be checked later on Tx completion - * to decide if IPC or metadata method of reading TS - * should be used - */ - dhd->pkt_metadata_version = 0; - dhd->pkt_metadata_buflen = 0; - } else { - dhd->pkt_metadata_version = GET_METADATA_VER(val); - dhd->pkt_metadata_buflen = GET_METADATA_BUFLEN(val); - } - - /* Check FW supports pktlat, if supports enable pktts_enab iovar */ - ret = dhd_set_pktts_enab(dhd, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: Enabling pktts_enab failed, ret=%d\n", __FUNCTION__, ret)); - } -#endif /* DHD_PKTTS */ - #ifdef RTT_SUPPORT if (dhd->rtt_state) { ret = dhd_rtt_init(dhd); @@ -14595,10 +11392,31 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) DHD_ERROR(("%s: Failed to get preserve log # !\n", __FUNCTION__)); } -#ifdef CONFIG_SILENT_ROAM - dhd->sroam_turn_on = TRUE; - dhd->sroamed = FALSE; -#endif /* CONFIG_SILENT_ROAM */ +#ifdef CUSTOM_OCL_RSSI_VAL + if (ocl_rssi_threshold != FW_OCL_RSSI_THRESH_INITVAL) { + ret = dhd_iovar(dhd, 0, "ocl_rssi_threshold", (char *)&ocl_rssi_threshold, + sizeof(ocl_rssi_threshold), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("failed to set ocl_rssi_threshold ret %d\n", ret)); + } + } +#endif /* CUSTOM_OCL_RSSI_VAL */ + + if (dhd_iovar(dhd, 0, "bus:d3_hostwake_delay", (char *)&d3_hostwake_delay, + sizeof(d3_hostwake_delay), NULL, 0, TRUE) < 0) { + DHD_ERROR(("%s: d3_hostwake_delay IOVAR not present, proceed\n", __FUNCTION__)); + } else { + DHD_ERROR(("%s: d3_hostwake_delay enabled\n", __FUNCTION__)); + } + + dhd->fr_phase_nibble = TRUE; + if (dhd_iovar(dhd, 0, "bus:fr_phase_nibble", (char *)&dhd->fr_phase_nibble, + sizeof(dhd->fr_phase_nibble), NULL, 0, TRUE) < 0) { + dhd->fr_phase_nibble = FALSE; + DHD_ERROR(("%s: fr_phase_nibble IOVAR not present, proceed\n", __FUNCTION__)); + } else { + DHD_ERROR(("%s: fr_phase_nibble enabled\n", __FUNCTION__)); + } #ifndef OEM_ANDROID /* For non-android FC modular builds, override firmware preinited values */ @@ -14606,7 +11424,33 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) #endif /* !OEM_ANDROID */ dhd_set_bandlock(dhd); +#ifdef DHD_WAKE_EVENT_STATUS +#ifdef CUSTOM_WAKE_REASON_STATS + /* Initialization */ + if (dhd_bus_get_wakecount(dhd)) { + int i = 0; + wake_counts_t *wcp = dhd_bus_get_wakecount(dhd); + + wcp->rc_event_idx = 0; + for (i = 0; i < MAX_WAKE_REASON_STATS; i++) { + wcp->rc_event[i] = -1; + } + } +#endif /* CUSTOM_WAKE_REASON_STATS */ +#endif /* DHD_WAKE_EVENT_STATUS */ + +#ifdef WL_UWB_COEX +#ifdef WL_UWB_COEX_DEF_ENABLE + ret = wl_cfg_uwb_coex_enable(dhd_linux_get_primary_netdev(dhd), + TRUE, UWB_COEX_CH_MIN, UWB_COEX_CH_MAX); + if (ret != BCME_OK) { + DHD_ERROR(("Failed to set UWB Coex (%d)\n", ret)); + } +#endif /* WL_UWB_COEX_DEF_ENABLE */ +#endif /* WL_UWB_COEX */ + done: + dhd_conf_postinit_ioctls(dhd); if (iov_buf) { MFREE(dhd->osh, iov_buf, WLC_IOCTL_SMLEN); } @@ -14621,9 +11465,6 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) char iovbuf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE + 16]; char *mask; uint32 buf_key_b4_m4 = 1; -#ifdef DHD_PKTTS - uint32 val = 0; -#endif uint8 msglen; eventmsgs_ext_t *eventmask_msg = NULL; uint32 event_log_max_sets = 0; @@ -14640,10 +11481,9 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) #if defined(BCMSUP_4WAY_HANDSHAKE) uint32 sup_wpa = 1; #endif /* BCMSUP_4WAY_HANDSHAKE */ -#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \ - defined(CUSTOM_IBSS_AMPDU_BA_WSIZE)) +#if defined(CUSTOM_AMPDU_BA_WSIZE) uint32 ampdu_ba_wsize = 0; -#endif /* CUSTOM_AMPDU_BA_WSIZE ||(WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */ +#endif #if defined(CUSTOM_AMPDU_MPDU) int32 ampdu_mpdu = 0; #endif @@ -14684,6 +11524,9 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) uint32 lpc = 1; #endif /* DHD_ENABLE_LPC */ uint power_mode = PM_FAST; +#ifdef ASSOC_PREFER_RSSI_THRESH + int assoc_pref_rssi_thresh = ASSOC_PREFER_RSSI_THRESH; +#endif /* ASSOC_PREFER_RSSI_THRESH */ #if defined(BCMSDIO) uint32 dongle_align = DHD_SDALIGN; uint32 glom = CUSTOM_GLOM_SETTING; @@ -14700,9 +11543,6 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) char buf[WLC_IOCTL_SMLEN]; char *ptr; uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ -#if defined(DHD_8021X_DUMP) && defined(SHOW_LOGTRACE) - wl_el_tag_params_t *el_tag = NULL; -#endif /* DHD_8021X_DUMP */ #ifdef DHD_RANDMAC_LOGGING uint privacy_mask = 0; #endif /* DHD_RANDMAC_LOGGING */ @@ -14747,10 +11587,10 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) uint32 apsta = 0; int ap_mode = 1; #endif /* (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) */ -#ifdef GET_CUSTOM_MAC_ENABLE struct ether_addr ea_addr; char hw_ether[62]; -#endif /* GET_CUSTOM_MAC_ENABLE */ + dhd_if_t *ifp = dhd->info->iflist[0]; + bool set_mac = FALSE; #ifdef OKC_SUPPORT uint32 okc = 1; #endif @@ -14784,12 +11624,6 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) #ifdef DISABLE_11N_PROPRIETARY_RATES uint32 ht_features = 0; #endif /* DISABLE_11N_PROPRIETARY_RATES */ -#ifdef CUSTOM_PSPRETEND_THR - uint32 pspretend_thr = CUSTOM_PSPRETEND_THR; -#endif -#ifdef CUSTOM_EVENT_PM_WAKE - uint32 pm_awake_thresh = CUSTOM_EVENT_PM_WAKE; -#endif /* CUSTOM_EVENT_PM_WAKE */ #ifdef DISABLE_PRUNED_SCAN uint32 scan_features = 0; #endif /* DISABLE_PRUNED_SCAN */ @@ -14801,6 +11635,7 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) #define EVENT_LOG_RATE_HC_THRESHOLD 1000 uint32 event_log_rate_hc = EVENT_LOG_RATE_HC_THRESHOLD; #endif /* EVENT_LOG_RATE_HC */ +#endif /* OEM_ANDROID */ #if defined(WBTEXT) && defined(WBTEXT_BTMDELTA) uint32 btmdelta = WBTEXT_BTMDELTA; #endif /* WBTEXT && WBTEXT_BTMDELTA */ @@ -14808,7 +11643,14 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) uint32 rrm_bcn_req_thrtl_win = RRM_BCNREQ_MAX_CHAN_TIME * 2; uint32 rrm_bcn_req_max_off_chan_time = RRM_BCNREQ_MAX_CHAN_TIME; #endif /* WBTEXT && RRM_BCNREQ_MAX_CHAN_TIME */ -#endif /* OEM_ANDROID */ +#ifdef CUSTOM_PSPRETEND_THR + uint32 pspretend_thr = CUSTOM_PSPRETEND_THR; +#endif +#if (defined(DHD_8021X_DUMP) && defined(SHOW_LOGTRACE)) || defined(DEBUGABILITY) + wl_el_tag_params_t *el_tag = NULL; +#endif /* DHD_8021X_DUMP */ + + uint32 d3_hostwake_delay = D3_HOSTWAKE_DELAY; BCM_REFERENCE(iovbuf); DHD_TRACE(("Enter %s\n", __FUNCTION__)); @@ -14822,17 +11664,10 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) #ifdef OEM_ANDROID #ifdef PKT_FILTER_SUPPORT dhd_pkt_filter_enable = TRUE; +#endif /* PKT_FILTER_SUPPORT */ #ifdef APF dhd->apf_set = FALSE; #endif /* APF */ -#endif /* PKT_FILTER_SUPPORT */ - dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; -#ifdef ENABLE_MAX_DTIM_IN_SUSPEND - dhd->max_dtim_enable = TRUE; -#else - dhd->max_dtim_enable = FALSE; -#endif /* ENABLE_MAX_DTIM_IN_SUSPEND */ - dhd->disable_dtim_in_suspend = FALSE; #ifdef CUSTOM_SET_OCLOFF dhd->ocl_off = FALSE; #endif /* CUSTOM_SET_OCLOFF */ @@ -14851,17 +11686,6 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) dhd->dhd_cflags &= ~WLAN_PLAT_AP_FLAG; #endif /* CUSTOM_COUNTRY_CODE */ -#ifdef CUSTOMER_HW4_DEBUG - if (!dhd_validate_chipid(dhd)) { - DHD_ERROR(("%s: CONFIG_BCMXXX and CHIP ID(%x) is mismatched\n", - __FUNCTION__, dhd_bus_chip_id(dhd))); -#ifndef SUPPORT_MULTIPLE_CHIPS - ret = BCME_BADARG; - goto done; -#endif /* !SUPPORT_MULTIPLE_CHIPS */ - } -#endif /* CUSTOMER_HW4_DEBUG */ - /* query for 'ver' to get version info from firmware */ memset(buf, 0, sizeof(buf)); ptr = buf; @@ -14875,14 +11699,13 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) fw_version[FW_VER_STR_LEN-1] = '\0'; } -#ifdef BOARD_HIKEY +// mark flag for later blob checking /* Set op_mode as MFG_MODE if WLTEST is present in "wl ver" */ if (strstr(fw_version, "WLTEST") != NULL) { DHD_ERROR(("%s: wl ver has WLTEST, setting op_mode as DHD_FLAG_MFG_MODE\n", __FUNCTION__)); op_mode = DHD_FLAG_MFG_MODE; } -#endif /* BOARD_HIKEY */ if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || (op_mode == DHD_FLAG_MFG_MODE)) { @@ -14891,11 +11714,6 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) /* disable runtimePM by default in MFG mode. */ pm_runtime_disable(dhd_bus_to_dev(dhd->bus)); #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ -#ifdef DHD_PCIE_RUNTIMEPM - /* Disable RuntimePM in mfg mode */ - DHD_DISABLE_RUNTIME_PM(dhd); - DHD_ERROR(("%s : Disable RuntimePM in Manufactring Firmware\n", __FUNCTION__)); -#endif /* DHD_PCIE_RUNTIME_PM */ /* Check and adjust IOCTL response timeout for Manufactring firmware */ dhd_os_set_ioctl_resp_timeout(MFG_IOCTL_RESP_TIMEOUT); DHD_ERROR(("%s : Set IOCTL response time for Manufactring Firmware\n", @@ -14928,7 +11746,7 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) DHD_ERROR(("%s: axierror_logbuf_addr IOVAR not present, proceed\n", __FUNCTION__)); dhd->axierror_logbuf_addr = 0; } else { - DHD_ERROR(("%s: axierror_logbuf_addr : 0x%x\n", + DHD_INFO(("%s: axierror_logbuf_addr : 0x%x\n", __FUNCTION__, dhd->axierror_logbuf_addr)); } #endif /* DNGL_AXI_ERROR_LOGGING */ @@ -14944,19 +11762,26 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) } #endif /* EVENT_LOG_RATE_HC */ -#ifdef GET_CUSTOM_MAC_ENABLE memset(hw_ether, 0, sizeof(hw_ether)); - ret = wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, 0); -#ifdef GET_CUSTOM_MAC_FROM_CONFIG - if (!memcmp(ðer_null, &dhd->conf->hw_ether, ETHER_ADDR_LEN)) { - ret = 0; - } else -#endif - if (!ret) { - memset(buf, 0, sizeof(buf)); + if (ifp->set_macaddress) { + memcpy(hw_ether, ifp->mac_addr, ETHER_ADDR_LEN); + set_mac = TRUE; + } +#ifdef GET_CUSTOM_MAC_ENABLE #ifdef GET_CUSTOM_MAC_FROM_CONFIG + else if (memcmp(ðer_null, &dhd->conf->hw_ether, ETHER_ADDR_LEN)) { + set_mac = TRUE; memcpy(hw_ether, &dhd->conf->hw_ether, sizeof(dhd->conf->hw_ether)); + } #endif + else { + ret = wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, 0); + if (!ret) + set_mac = TRUE; + } +#endif /* GET_CUSTOM_MAC_ENABLE */ + if (set_mac) { + memset(buf, 0, sizeof(buf)); bcopy(hw_ether, ea_addr.octet, sizeof(struct ether_addr)); bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf)); ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); @@ -14972,7 +11797,9 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) goto done; } } - } else { + } +#ifdef GET_CUSTOM_MAC_ENABLE + else { DHD_ERROR(("%s: can't get custom MAC address, ret=%d\n", __FUNCTION__, ret)); ret = BCME_NOTUP; goto done; @@ -15020,10 +11847,21 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) } } #endif /* WL_STA_ASSOC_RAND && WL_STA_INIT_RAND */ +#ifdef BCMDBUS + if (dhd->info->clm_path[0] == '\0') { + if ((strlen(clm_path) > MOD_PARAM_PATHLEN) || + (strlen(clm_path) >= sizeof(dhd->info->clm_path))) { + DHD_ERROR(("%s clm path exceeds max len\n", __FUNCTION__)); + ret = BCME_BADLEN; + goto done; + } + strlcpy(dhd->info->clm_path, clm_path, sizeof(dhd->info->clm_path)); + } +#endif /* BCMDBUS */ - if ((ret = dhd_apply_default_clm(dhd, dhd->clm_path)) < 0) { - DHD_ERROR(("%s: CLM set failed. Abort initialization.\n", __FUNCTION__)); - goto done; + if ((ret = dhd_apply_default_clm(dhd, dhd->info->clm_path)) < 0) { + DHD_ERROR(("%s: CLM set failed. Ignore and continue initialization.\n", + __FUNCTION__)); } /* get a capabilities from firmware */ @@ -15057,7 +11895,6 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) dhd_pkt_filter_enable = FALSE; #endif #ifdef SET_RANDOM_MAC_SOFTAP - SRANDOM32((uint)jiffies); rand_mac = RANDOM32(); iovbuf[0] = (unsigned char)(vendor_oui >> 16) | 0x02; /* local admin bit */ iovbuf[1] = (unsigned char)(vendor_oui >> 8); @@ -15218,6 +12055,13 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) else dhd->info->rxthread_enabled = TRUE; #endif + +#if defined(CUSTOM_COUNTRY_CODE_XZ) + /* Set initial country code to XZ */ + strlcpy(dhd->dhd_cspec.country_abbrev, "XZ", WLC_CNTRY_BUF_SZ); + strlcpy(dhd->dhd_cspec.ccode, "XZ", WLC_CNTRY_BUF_SZ); + DHD_ERROR(("%s: Set initial country code to XZ(World Wide Safe)\n", __FUNCTION__)); +#endif /* CUSTOM_COUNTRY_CODE_XZ */ /* Set Country code */ if (dhd->dhd_cspec.ccode[0] != 0) { ret = dhd_iovar(dhd, 0, "country", (char *)&dhd->dhd_cspec, sizeof(wl_country_t), @@ -15249,6 +12093,7 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) if (ret < 0) { DHD_ERROR(("%s roam_off failed %d\n", __FUNCTION__, ret)); } + ROAMOFF_DBG_SAVE(dhd_linux_get_primary_netdev(dhd), SET_ROAM_PREINIT, roamvar); #endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ #if defined(ROAM_ENABLE) #ifdef DISABLE_BCNLOSS_ROAM @@ -15295,12 +12140,7 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) #endif /* ROAM_ENABLE */ #ifdef CUSTOM_EVENT_PM_WAKE - /* XXX need to check time value */ - ret = dhd_iovar(dhd, 0, "const_awake_thresh", (char *)&pm_awake_thresh, - sizeof(pm_awake_thresh), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s set const_awake_thresh failed %d\n", __FUNCTION__, ret)); - } + dhd_init_excess_pm_awake(dhd); #endif /* CUSTOM_EVENT_PM_WAKE */ #ifdef OKC_SUPPORT dhd_iovar(dhd, 0, "okc_enable", (char *)&okc, sizeof(okc), NULL, 0, TRUE); @@ -15334,7 +12174,7 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) #ifdef WLADPS if (dhd->op_mode & DHD_FLAG_STA_MODE) { - if ((ret = dhd_enable_adps(dhd, ADPS_ENABLE)) != BCME_OK && + if ((ret = dhd_enable_adps(dhd, ADPS_MODE_PM2_ONLY)) != BCME_OK && (ret != BCME_UNSUPPORTED)) { DHD_ERROR(("%s dhd_enable_adps failed %d\n", __FUNCTION__, ret)); @@ -15343,16 +12183,18 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) #endif /* WLADPS */ #ifdef DHD_PM_CONTROL_FROM_FILE -#ifdef CUSTOMER_HW10 - dhd_control_pm(dhd, &power_mode); -#else sec_control_pm(dhd, &power_mode); -#endif /* CUSTOMER_HW10 */ #else /* Set PowerSave mode */ (void) dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); #endif /* DHD_PM_CONTROL_FROM_FILE */ - +#ifdef ASSOC_PREFER_RSSI_THRESH + ret = dhd_iovar(dhd, 0, "assoc_pref_rssi_thresh", (char *)&assoc_pref_rssi_thresh, + sizeof(assoc_pref_rssi_thresh), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s set assoc_pref_rssi_thresh failed %d\n", __FUNCTION__, ret)); + } +#endif /* ASSOC_PREFER_RSSI_THRESH */ #if defined(BCMSDIO) /* Match Host and Dongle rx alignment */ ret = dhd_iovar(dhd, 0, "bus:txglomalign", (char *)&dongle_align, sizeof(dongle_align), @@ -15438,9 +12280,19 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) } #else /* OEM_ANDROID */ - if ((ret = dhd_apply_default_clm(dhd, clm_path)) < 0) { - DHD_ERROR(("%s: CLM set failed. Abort initialization.\n", __FUNCTION__)); - goto done; +#ifdef BCMDBUS + if (dhd->info->clm_path[0] == '\0') { + if (strlen(clm_path) > MOD_PARAM_PATHLEN) { + DHD_ERROR(("%s clm path exceeds max len\n", __FUNCTION__)); + ret = BCME_BADLEN; + goto done; + } + strlcpy(dhd->info->clm_path, clm_path, strlen(clm_path)+1); + } +#endif /* BCMDBUS */ + if ((ret = dhd_apply_default_clm(dhd, dhd->info->clm_path)) < 0) { + DHD_ERROR(("%s: CLM set failed. Ignore and continue initialization.\n", + __FUNCTION__)); } #if defined(KEEP_ALIVE) @@ -15540,25 +12392,11 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) BCM_REFERENCE(ret2); -#ifdef WLAIBSS - /* Apply AIBSS configurations */ - if ((ret = dhd_preinit_aibss_ioctls(dhd, iov_buf)) != BCME_OK) { - DHD_ERROR(("%s dhd_preinit_aibss_ioctls failed %d\n", - __FUNCTION__, ret)); - goto done; - } -#endif /* WLAIBSS */ - -#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \ - defined(CUSTOM_IBSS_AMPDU_BA_WSIZE)) +#if defined(CUSTOM_AMPDU_BA_WSIZE) /* Set ampdu ba wsize to 64 or 16 */ #ifdef CUSTOM_AMPDU_BA_WSIZE ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE; #endif -#if defined(WLAIBSS) && defined(CUSTOM_IBSS_AMPDU_BA_WSIZE) - if (dhd->op_mode == DHD_FLAG_IBSS_MODE) - ampdu_ba_wsize = CUSTOM_IBSS_AMPDU_BA_WSIZE; -#endif /* WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE */ if (ampdu_ba_wsize != 0) { ret = dhd_iovar(dhd, 0, "ampdu_ba_wsize", (char *)&du_ba_wsize, sizeof(ampdu_ba_wsize), NULL, 0, TRUE); @@ -15567,7 +12405,7 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) __FUNCTION__, ampdu_ba_wsize, ret)); } } -#endif /* CUSTOM_AMPDU_BA_WSIZE || (WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */ +#endif /* CUSTOM_AMPDU_BA_WSIZE */ #if defined(CUSTOM_AMPDU_MPDU) ampdu_mpdu = CUSTOM_AMPDU_MPDU; @@ -15750,6 +12588,7 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) // setbit(mask, WLC_E_TXFAIL); // terence 20181106: remove unnecessary event #endif setbit(mask, WLC_E_JOIN_START); + setbit(mask, WLC_E_OWE_INFO); // setbit(mask, WLC_E_SCAN_COMPLETE); // terence 20150628: remove redundant event #ifdef DHD_DEBUG setbit(mask, WLC_E_SCAN_CONFIRM_IND); @@ -15774,15 +12613,12 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) #ifdef WLTDLS setbit(mask, WLC_E_TDLS_PEER_EVENT); #endif /* WLTDLS */ -#ifdef WL_ESCAN - setbit(mask, WLC_E_ESCAN_RESULT); -#endif /* WL_ESCAN */ -#ifdef CSI_SUPPORT - setbit(mask, WLC_E_CSI); -#endif /* CSI_SUPPORT */ #ifdef RTT_SUPPORT setbit(mask, WLC_E_PROXD); #endif /* RTT_SUPPORT */ +#ifdef WL_ESCAN + setbit(mask, WLC_E_ESCAN_RESULT); +#endif /* WL_ESCAN */ #if !defined(WL_CFG80211) && !defined(OEM_ANDROID) setbit(mask, WLC_E_ESCAN_RESULT); #endif @@ -15794,9 +12630,6 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) setbit(mask, WLC_E_P2P_DISC_LISTEN_COMPLETE); } #endif /* WL_CFG80211 */ -#ifdef WLAIBSS - setbit(mask, WLC_E_AIBSS_TXFAIL); -#endif /* WLAIBSS */ #if defined(SHOW_LOGTRACE) && defined(LOGTRACE_FROM_FILE) if (dhd_logtrace_from_file(dhd)) { @@ -15830,6 +12663,10 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) dhd_update_flow_prio_map(dhd, DHD_FLOW_PRIO_LLR_MAP); #endif /* defined(BCMPCIE) && defined(EAPOL_PKT_PRIO) */ +#if defined(BCMSDIO) && defined(DHD_LOSSLESS_ROAMING) + dhd_update_sdio_data_prio_map(dhd); +#endif /* BCMSDIO && DHD_LOSSLESS_ROAMING */ + #ifdef RSSI_MONITOR_SUPPORT setbit(mask, WLC_E_RSSI_LQM); #endif /* RSSI_MONITOR_SUPPORT */ @@ -15840,15 +12677,9 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) setbit(mask, WLC_E_ROAM_EXP_EVENT); #endif /* GSCAN_SUPPORT */ setbit(mask, WLC_E_RSSI_LQM); -#ifdef BT_WIFI_HANDOVER - setbit(mask, WLC_E_BT_WIFI_HANDOVER_REQ); -#endif /* BT_WIFI_HANDOVER */ #ifdef DBG_PKT_MON setbit(mask, WLC_E_ROAM_PREP); #endif /* DBG_PKT_MON */ -#ifdef WL_NATOE - setbit(mask, WLC_E_NATOE_NFCT); -#endif /* WL_NATOE */ #ifdef BCM_ROUTER_DHD setbit(mask, WLC_E_DPSTA_INTF_IND); #endif /* BCM_ROUTER_DHD */ @@ -15859,14 +12690,14 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) #ifdef WL_MBO setbit(mask, WLC_E_MBO); #endif /* WL_MBO */ -#ifdef WL_CLIENT_SAE - setbit(mask, WLC_E_JOIN_START); -#endif /* WL_CLIENT_SAE */ #ifdef WL_CAC_TS setbit(mask, WLC_E_ADDTS_IND); setbit(mask, WLC_E_DELTS_IND); #endif /* WL_BCNRECV */ setbit(mask, WLC_E_COUNTRY_CODE_CHANGED); +#ifdef CSI_SUPPORT + setbit(mask, WLC_E_CSI); +#endif /* CSI_SUPPORT */ /* Write updated Event mask */ eventmask_msg->ver = EVENTMSGS_VER; @@ -15897,6 +12728,26 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) DHD_ERROR(("%s set event_log_tag_control fail %d\n", __FUNCTION__, ret)); } #endif /* DHD_8021X_DUMP */ + +#ifdef DEBUGABILITY + /* Enabling event log trace for roam stats events */ + el_tag = (wl_el_tag_params_t *)MALLOC(dhd->osh, sizeof(wl_el_tag_params_t)); + if (el_tag == NULL) { + DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", + (int)sizeof(wl_el_tag_params_t))); + ret = BCME_NOMEM; + goto done; + } + el_tag->tag = EVENT_LOG_TAG_ROAM_ENHANCED_LOG; + el_tag->set = 1; + el_tag->flags = EVENT_LOG_TAG_FLAG_LOG; + ret = dhd_iovar(dhd, 0, "event_log_tag_control", (char *)el_tag, sizeof(*el_tag), NULL, + 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s set event_log_tag_control fail %d\n", __FUNCTION__, ret)); + } +#endif /* DEBUGABILITY */ + #ifdef DHD_RANDMAC_LOGGING if (FW_SUPPORTED((dhd), event_log)) { if (dhd_iovar(dhd, 0, "privacy_mask", (char *)&privacy_mask, sizeof(privacy_mask), @@ -16022,9 +12873,6 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) #ifdef DHDTCPACK_SUPPRESS dhd_tcpack_suppress_set(dhd, TCPACK_SUP_OFF); #endif -#if defined(DHD_TCP_WINSIZE_ADJUST) - dhd_use_tcp_window_size_adjust = TRUE; -#endif #if defined(BCMSDIO) memset(buf, 0, sizeof(buf)); @@ -16081,41 +12929,6 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) } } -#if defined(CUSTOMER_HW4_DEBUG) - if ((ver_temp_buf = bcmstrstr(ptr, "Customization:")) == NULL) { - DHD_ERROR(("Couldn't find \"Customization:\"\n")); - } else { - char tokenlim; - ptr = (ver_temp_buf + strlen("Customization:")); - if ((ver_temp_buf = bcmstrtok(&ptr, "(\n", &tokenlim)) == NULL) { - DHD_ERROR(("Couldn't find project blob version" - "or New line character\n")); - } else if (tokenlim == '(') { - snprintf(clm_version, - CLM_VER_STR_LEN - 1, "%s, Blob ver = Major : %s minor : ", - clm_version, ver_temp_buf); - DHD_INFO(("[INFO]CLM/Blob version = %s\n", clm_version)); - if ((ver_temp_buf = bcmstrtok(&ptr, "\n", &tokenlim)) == NULL) { - DHD_ERROR(("Couldn't find New line character\n")); - } else { - snprintf(clm_version, - strlen(clm_version) + strlen(ver_temp_buf), - "%s%s", clm_version, ver_temp_buf); - DHD_INFO(("[INFO]CLM/Blob/project version = %s\n", - clm_version)); - - } - } else if (tokenlim == '\n') { - snprintf(clm_version, - strlen(clm_version) + strlen(", Blob ver = Major : ") + 1, - "%s, Blob ver = Major : ", clm_version); - snprintf(clm_version, - strlen(clm_version) + strlen(ver_temp_buf) + 1, - "%s%s", clm_version, ver_temp_buf); - DHD_INFO(("[INFO]CLM/Blob/project version = %s\n", clm_version)); - } - } -#endif /* CUSTOMER_HW4_DEBUG */ if (strlen(clm_version)) { DHD_INFO(("CLM version = %s\n", clm_version)); } else { @@ -16125,7 +12938,21 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) dhd_set_version_info(dhd, fw_version); #ifdef WRITE_WLANINFO - sec_save_wlinfo(fw_version, EPI_VERSION_STR, dhd->info->nv_path, clm_version); + do { + uint len = MAX_NVRAMBUF_SIZE; + char *memblock = NULL; + + dhd_get_download_buffer(dhd, dhd->info->nv_path, NVRAM, &memblock, (int *)&len); + if ((len <= 0 || len > MAX_NVRAMBUF_SIZE)) { + DHD_ERROR(("Can't open nvram info, skip save wifiver info\n")); + break; + } + + sec_save_wlinfo(fw_version, EPI_VERSION_STR, memblock, clm_version); + if (memblock) { + dhd_free_download_buffer(dhd, memblock, len); + } + } while (0); #endif /* WRITE_WLANINFO */ #endif /* defined(OEM_ANDROID) */ @@ -16196,7 +13023,7 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) #endif /* DISABLE_11N */ #ifdef READ_CONFIG_FROM_FILE - dhd_preinit_config(dhd, 0); + dhd_preinit_config(dhd, 0, CONFIG_BCMDHD_CONFIG_PATH); #endif /* READ_CONFIG_FROM_FILE */ if (wlfc_enable) { @@ -16214,6 +13041,12 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "ampdu_hostreorder", 0, 0, TRUE); #endif /* PROP_TXSTATUS */ #endif /* BCMSDIO || BCMDBUS */ + +#if defined(SYNA_SAR_CUSTOMER_PARAMETER) && defined(READ_CONFIG_FROM_FILE) + dhd_sar_reset_parameter(); + dhd_preinit_config(dhd, 0, config_sar_path); +#endif /* SYNA_SAR_CUSTOMER_PARAMETER && READ_CONFIG_FROM_FILE */ + #ifndef PCIE_FULL_DONGLE /* For FD we need all the packets at DHD to handle intra-BSS forwarding */ if (FW_SUPPORTED(dhd, ap)) { @@ -16230,33 +13063,6 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) } #endif -#ifdef DHD_PKTTS - /* get the pkt metadata buffer length supported by FW */ - if (dhd_wl_ioctl_get_intiovar(dhd, "bus:metadata_info", &val, - WLC_GET_VAR, FALSE, 0) != BCME_OK) { - DHD_ERROR(("%s: failed to get pkt metadata buflen, use IPC pkt TS.\n", - __FUNCTION__)); - /* - * if iovar fails, IPC method of collecting - * TS should be used, hence set metadata_buflen as - * 0 here. This will be checked later on Tx completion - * to decide if IPC or metadata method of reading TS - * should be used - */ - dhd->pkt_metadata_version = 0; - dhd->pkt_metadata_buflen = 0; - } else { - dhd->pkt_metadata_version = GET_METADATA_VER(val); - dhd->pkt_metadata_buflen = GET_METADATA_BUFLEN(val); - } - - /* Check FW supports pktlat, if supports enable pktts_enab iovar */ - ret = dhd_set_pktts_enab(dhd, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: Enabling pktts_enab failed, ret=%d\n", __FUNCTION__, ret)); - } -#endif /* DHD_PKTTS */ - #ifdef RTT_SUPPORT if (dhd->rtt_state) { ret = dhd_rtt_init(dhd); @@ -16411,12 +13217,25 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) dhd_ecounter_configure(dhd, TRUE); } -#ifdef CONFIG_SILENT_ROAM - dhd->sroam_turn_on = TRUE; - dhd->sroamed = FALSE; -#endif /* CONFIG_SILENT_ROAM */ dhd_set_bandlock(dhd); +#ifdef WL_UWB_COEX +#ifdef WL_UWB_COEX_DEF_ENABLE + ret = wl_cfg_uwb_coex_enable(dhd_linux_get_primary_netdev(dhd), + TRUE, UWB_COEX_CH_MIN, UWB_COEX_CH_MAX); + if (ret != BCME_OK) { + DHD_ERROR(("Failed to set UWB Coex (%d)\n", ret)); + } +#endif /* WL_UWB_COEX_DEF_ENABLE */ +#endif /* WL_UWB_COEX */ + + if (dhd_iovar(dhd, 0, "bus:d3_hostwake_delay", (char *)&d3_hostwake_delay, + sizeof(d3_hostwake_delay), NULL, 0, TRUE) < 0) { + DHD_ERROR(("%s: d3_hostwake_delay IOVAR not present, proceed\n", __FUNCTION__)); + } else { + DHD_ERROR(("%s: d3_hostwake_delay enabled\n", __FUNCTION__)); + } + dhd_conf_postinit_ioctls(dhd); done: @@ -16426,7 +13245,7 @@ done: if (iov_buf) { MFREE(dhd->osh, iov_buf, WLC_IOCTL_SMLEN); } -#if defined(DHD_8021X_DUMP) && defined(SHOW_LOGTRACE) +#if (defined(DHD_8021X_DUMP) && defined(SHOW_LOGTRACE)) || defined(DEBUGABILITY) if (el_tag) { MFREE(dhd->osh, el_tag, sizeof(wl_el_tag_params_t)); } @@ -16434,14 +13253,21 @@ done: return ret; } +#if defined(BCMPCIE) /* Deafult enable preinit optimisation */ #define DHD_PREINIT_OPTIMISATION +#endif /* BCMPCIE */ int dhd_preinit_ioctls(dhd_pub_t *dhd) { int ret = 0; +#if defined(BCMSDIO) + extern void dhd_bus_check_srmemsize(dhd_pub_t *dhdp); + /* check if srmemsize consitant at fw and dhd side */ + dhd_bus_check_srmemsize(dhd); +#endif /* BCMSDIO */ #ifdef DHD_PREINIT_OPTIMISATION int preinit_status = 0; ret = dhd_iovar(dhd, 0, "preinit_status", NULL, 0, (char *)&preinit_status, @@ -16465,6 +13291,12 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd->fw_preinit = FALSE; ret = dhd_legacy_preinit_ioctls(dhd); #endif /* DHD_PREINIT_OPTIMISATION */ + + if (!ret && dhd_query_bus_erros(dhd)) { + DHD_ERROR(("%s: retrun error due to query errors\n", __FUNCTION__)); + ret = BCME_ERROR; + } + return ret; } @@ -16526,12 +13358,14 @@ int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) return 0; } -#if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) static int dhd_wait_for_file_dump(dhd_pub_t *dhdp) { int ret = BCME_OK; struct net_device *primary_ndev; +#ifdef WL_CFG80211 struct bcm_cfg80211 *cfg; +#endif /* WL_CFG80211 */ unsigned long flags = 0; primary_ndev = dhd_linux_get_primary_netdev(dhdp); @@ -16539,12 +13373,19 @@ static int dhd_wait_for_file_dump(dhd_pub_t *dhdp) DHD_ERROR(("%s: Cannot find primary netdev\n", __FUNCTION__)); return BCME_ERROR; } +#ifdef WL_CFG80211 cfg = wl_get_cfg(primary_ndev); if (!cfg) { DHD_ERROR(("%s: Cannot find cfg\n", __FUNCTION__)); return BCME_ERROR; } +#endif /* WL_CFG80211 */ + + if (dhdp->stop_in_progress) { + DHD_ERROR(("%s: dhd_stop in progress\n", __FUNCTION__)); + return BCME_ERROR; + } DHD_GENERAL_LOCK(dhdp, flags); if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp)) { @@ -16557,12 +13398,16 @@ static int dhd_wait_for_file_dump(dhd_pub_t *dhdp) DHD_BUS_BUSY_SET_IN_HALDUMP(dhdp); DHD_GENERAL_UNLOCK(dhdp, flags); +#ifdef WL_CFG80211 DHD_OS_WAKE_LOCK(dhdp); /* check for hal started and only then send event if not clear dump state here */ if (wl_cfg80211_is_hal_started(cfg)) { int timeleft = 0; DHD_ERROR(("[DUMP] %s: HAL started. send urgent event\n", __FUNCTION__)); +#ifdef DHD_MAP_PKTID_LOGGING + dhd_pktid_logging_dump(dhdp); +#endif /* DHD_MAP_PKTID_LOGGING */ dhd_dbg_send_urgent_evt(dhdp, NULL, 0); DHD_ERROR(("%s: wait to clear dhd_bus_busy_state: 0x%x\n", @@ -16572,14 +13417,16 @@ static int dhd_wait_for_file_dump(dhd_pub_t *dhdp) if ((dhdp->dhd_bus_busy_state & DHD_BUS_BUSY_IN_HALDUMP) != 0) { DHD_ERROR(("%s: Timed out(%d) dhd_bus_busy_state=0x%x\n", __FUNCTION__, timeleft, dhdp->dhd_bus_busy_state)); + dhd_set_dump_status(dhdp, DUMP_FAILURE); ret = BCME_ERROR; } } else { DHD_ERROR(("[DUMP] %s: HAL Not started. skip urgent event\n", __FUNCTION__)); ret = BCME_ERROR; } - DHD_OS_WAKE_UNLOCK(dhdp); +#endif /* WL_CFG80211 */ + /* In case of dhd_os_busbusy_wait_bitmask() timeout, * hal dump bit will not be cleared. Hence clearing it here. */ @@ -16590,7 +13437,7 @@ static int dhd_wait_for_file_dump(dhd_pub_t *dhdp) return ret; } -#endif /* WL_CFG80211 && DHD_FILE_DUMP_EVENT && DHD_FW_CORE_DUMP */ +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_CORE_DUMP */ #ifdef ARP_OFFLOAD_SUPPORT /* add or remove AOE host ip(s) (up to 8 IPs on the interface) */ @@ -16868,7 +13715,7 @@ int dhd_inet6addr_notifier_call(struct notifier_block *this, unsigned long event dhd_pub_t *dhdp; struct inet6_ifaddr *inet6_ifa = ptr; struct ipv6_work_info_t *ndo_info; - int idx; + int idx = 0; /* Filter notifications meant for non Broadcom devices */ if (inet6_ifa->idev->dev->netdev_ops != &dhd_ops_pri) { @@ -16881,9 +13728,15 @@ int dhd_inet6addr_notifier_call(struct notifier_block *this, unsigned long event } dhdp = &dhd->pub; - /* Supports only primary interface */ idx = dhd_net2idx(dhd, inet6_ifa->idev->dev); - if (idx != 0) { + if ((idx >= 0 && idx < DHD_MAX_IFS) +#if defined(WL_CFG80211) + && IS_STA_IFACE(ndev_to_wdev(inet6_ifa->idev->dev)) +#endif /* WL_CFG80211 */ + && 1) { + DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net, + dhd->iflist[idx]->name, dhd->iflist[idx]->idx)); + } else { return NOTIFY_DONE; } @@ -16959,6 +13812,7 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) struct net_device *net = NULL; int err = 0; uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; + unsigned long flags; DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); @@ -17004,32 +13858,6 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) } net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; -#ifdef HOST_SFH_LLC - net->needed_headroom += DOT11_LLC_SNAP_HDR_LEN; -#endif - -#ifdef DHD_AWDL - if (dhdp->awdl_ifidx && - ifidx == dhdp->awdl_ifidx) { - /* A total of 30 bytes are required for the - * ethernet + AWDL LLC header. Out of this 14 - * bytes in the form of ethernet header is already - * present in the skb handed over by the stack. - * So we need to reserve an additonal 16 bytes as - * headroom. Out of these 16 bytes, if the host - * sfh llc feature is being used, then additonal - * 8 bytes are already being reserved - * during dhd_register_if (below), hence reserving - * only an additional 8 bytes is enough. If the host - * sfh llc feature is not used, then all of the 16 - * bytes need to be reserved from here - */ - net->needed_headroom += DOT11_LLC_SNAP_HDR_LEN; -#ifndef HOST_SFH_LLC - net->needed_headroom += DOT11_LLC_SNAP_HDR_LEN; -#endif /* HOST_SFH_LLC */ - } -#endif /* DHD_AWDL */ net->ethtool_ops = &dhd_ethtool_ops; @@ -17056,7 +13884,7 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) * XXX Linux 2.6.25 does not like a blank MAC address, so use a * dummy address until the interface is brought up. */ - dev_addr_set(net, temp_addr); + DEV_ADDR_SET(net, temp_addr); if (ifidx == 0) printf("%s\n", dhd_version); @@ -17065,7 +13893,8 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) wl_ext_iapsta_update_net_device(net, ifidx); #endif /* WL_EXT_IAPSTA */ if (dhd->pub.up == 1) { - if (_dhd_set_mac_address(dhd, ifidx, net->dev_addr, FALSE) == 0) + memcpy(temp_addr, net->dev_addr, ETHER_ADDR_LEN); + if (_dhd_set_mac_address(dhd, ifidx, temp_addr, FALSE) == 0) DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__)); else DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__)); @@ -17118,12 +13947,8 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) net_stat_tizen_register(net); #endif /* CONFIG_TIZEN */ - printf("Register interface [%s] MAC: "MACDBG"\n\n", net->name, -#if defined(CUSTOMER_HW4_DEBUG) - MAC2STRDBG(dhd->pub.mac.octet)); -#else - MAC2STRDBG(net->dev_addr)); -#endif /* CUSTOMER_HW4_DEBUG */ + DHD_CONS_ONLY(("Register interface [%s] MAC: "MACDBG"\n\n", net->name, + MAC2STRDBG(net->dev_addr))); #if defined(OEM_ANDROID) && (defined(BCMPCIE) || defined(BCMLXSDMMC) || defined(BCMDBUS)) if (ifidx == 0) { @@ -17136,6 +13961,7 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) #endif /* WL_CFG80211 */ #if defined(DHD_LB_RXP) __skb_queue_purge(&dhd->rx_pend_queue); + skb_queue_purge(&dhd->rx_emerge_queue); #endif /* DHD_LB_RXP */ #if defined(DHD_LB_TXP) @@ -17152,20 +13978,17 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) #endif /* BCMPCIE && DHDTCPACK_SUPPRESS */ #if defined(WLAN_ACCEL_BOOT) - dhd->fs_check_retry = DHD_FS_CHECK_RETRIES; - dhd->wl_accel_boot_on_done = FALSE; - INIT_DELAYED_WORK(&dhd->wl_accel_work, dhd_wifi_accel_on_work_cb); -#if !defined(WLAN_ACCEL_SKIP_WQ_IN_ATTACH) - /* If the WLAN_ACCEL_SKIP_WQ_IN_ATTACH feature is enabled, - * the dhd_wifi_accel_on_work_cb() is called in dhd_open() - * to skip dongle firmware downloading during insmod and dhd_attach. - */ - schedule_delayed_work(&dhd->wl_accel_work, - msecs_to_jiffies(DHD_FS_CHECK_RETRY_DELAY_MS)); -#endif /* !defined(WLAN_ACCEL_SKIP_WQ_IN_ATTACH) */ + /* + * Make Wifi suspended after boot up with forge_reg_on true + * This will download fw when ifconfig wlan0 up sequence + */ + wl_android_wifi_off(net, TRUE); + dhd->wl_accel_force_reg_on = TRUE; + /* Module init time clear do_chip_bighammer */ + dhd->pub.do_chip_bighammer = FALSE; #else /* Turn off Wifi after boot up */ -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) dhd_bus_put(&dhd->pub, WLAN_MODULE); wl_android_set_wifi_on_flag(FALSE); #else @@ -17176,9 +13999,11 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) } } #endif /* OEM_ANDROID && (BCMPCIE || (BCMLXSDMMC) */ -#if defined(GDB_PROXY) && defined(PCIE_FULL_DONGLE) && defined(BCMINTERNAL) - gdb_proxy_fs_try_create(ifp->info, net->name); -#endif /* defined(GDB_PROXY) && defined(PCIE_FULL_DONGLE) && defined(BCMINTERNAL) */ + + DHD_GENERAL_LOCK(dhdp, flags); + ifp->del_in_progress = FALSE; + DHD_GENERAL_UNLOCK(dhdp, flags); + return 0; fail: @@ -17243,10 +14068,6 @@ void dhd_detach(dhd_pub_t *dhdp) if (!dhd) return; -#if defined(GDB_PROXY) && defined(PCIE_FULL_DONGLE) && defined(BCMINTERNAL) - gdb_proxy_fs_remove(dhd); -#endif /* defined(GDB_PROXY) && defined(PCIE_FULL_DONGLE) && defined(BCMINTERNAL) */ - /* primary interface 0 */ ifp = dhd->iflist[0]; if (ifp && ifp->net) { @@ -17288,12 +14109,6 @@ void dhd_detach(dhd_pub_t *dhdp) #ifdef DHD_WET dhd_free_wet_info(&dhd->pub, dhd->pub.wet_info); #endif /* DHD_WET */ -#ifdef WL_NANHO - /* deinit NANHO host module */ - bcm_nanho_deinit(dhd->pub.nanhoi); -#endif /* WL_NANHO */ -#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) -#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */ #ifdef PROP_TXSTATUS #ifdef DHD_WLFC_THREAD @@ -17306,29 +14121,11 @@ void dhd_detach(dhd_pub_t *dhdp) #endif /* DHD_WLFC_THREAD */ #endif /* PROP_TXSTATUS */ -#ifdef DHD_TIMESYNC - if (dhd->dhd_state & DHD_ATTACH_TIMESYNC_ATTACH_DONE) { - dhd_timesync_detach(dhdp); - } -#endif /* DHD_TIMESYNC */ - if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { #if defined(OEM_ANDROID) || !defined(BCMSDIO) dhd_bus_detach(dhdp); #endif /* OEM_ANDROID || !BCMSDIO */ -#ifdef OEM_ANDROID -#ifdef BCMPCIE - if (is_reboot == SYS_RESTART) { - extern bcmdhd_wifi_platdata_t *dhd_wifi_platdata; - if (dhd_wifi_platdata && !dhdp->dongle_reset) { - dhdpcie_bus_stop_host_dev(dhdp->bus); - wifi_platform_set_power(dhd_wifi_platdata->adapters, - FALSE, WIFI_TURNOFF_DELAY); - } - } -#endif /* BCMPCIE */ -#endif /* OEM_ANDROID */ #ifndef PCIE_FULL_DONGLE #if defined(OEM_ANDROID) || !defined(BCMSDIO) if (dhdp->prot) @@ -17371,6 +14168,9 @@ void dhd_detach(dhd_pub_t *dhdp) #ifdef WL_ESCAN wl_escan_detach(dev); #endif /* WL_ESCAN */ +#ifdef WL_TIMER + wl_timer_dettach(dhdp); +#endif /* WL_TIMER */ #ifdef WL_EVENT wl_ext_event_dettach(dhdp); #endif /* WL_EVENT */ @@ -17461,11 +14261,6 @@ void dhd_detach(dhd_pub_t *dhdp) tasklet_kill(&dhd->tasklet); #else if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { -#ifdef DHD_PCIE_RUNTIMEPM - if (dhd->thr_rpm_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_rpm_ctl); - } -#endif /* DHD_PCIE_RUNTIMEPM */ if (dhd->thr_wdt_ctl.thr_pid >= 0) { PROC_STOP(&dhd->thr_wdt_ctl); } @@ -17483,12 +14278,6 @@ void dhd_detach(dhd_pub_t *dhdp) } #endif /* BCMDBUS */ -#ifdef WL_NATOE - if (dhd->pub.nfct) { - dhd_ct_close(dhd->pub.nfct); - } -#endif /* WL_NATOE */ - cancel_delayed_work_sync(&dhd->dhd_dpc_dispatcher_work); #ifdef DHD_LB if (dhd->dhd_state & DHD_ATTACH_STATE_LB_ATTACH_DONE) { @@ -17499,6 +14288,7 @@ void dhd_detach(dhd_pub_t *dhdp) #ifdef DHD_LB_RXP cancel_work_sync(&dhd->rx_napi_dispatcher_work); __skb_queue_purge(&dhd->rx_pend_queue); + skb_queue_purge(&dhd->rx_emerge_queue); #endif /* DHD_LB_RXP */ #ifdef DHD_LB_TXP cancel_work_sync(&dhd->tx_dispatcher_work); @@ -17514,27 +14304,21 @@ void dhd_detach(dhd_pub_t *dhdp) } #endif /* DHD_LB */ -#ifdef CSI_SUPPORT - dhd_csi_deinit(dhdp); -#endif /* CSI_SUPPORT */ - #if defined(DNGL_AXI_ERROR_LOGGING) && defined(DHD_USE_WQ_FOR_DNGL_AXI_ERROR) cancel_work_sync(&dhd->axi_error_dispatcher_work); #endif /* DNGL_AXI_ERROR_LOGGING && DHD_USE_WQ_FOR_DNGL_AXI_ERROR */ DHD_SSSR_REG_INFO_DEINIT(&dhd->pub); DHD_SSSR_MEMPOOL_DEINIT(&dhd->pub); + DHD_COREDUMP_MEMPOOL_DEINIT(&dhd->pub); #ifdef DHD_SDTC_ETB_DUMP dhd_sdtc_etb_mempool_deinit(&dhd->pub); #endif /* DHD_SDTC_ETB_DUMP */ -#ifdef EWP_EDL - if (host_edl_support) { - DHD_EDL_MEM_DEINIT(dhdp); - host_edl_support = FALSE; - } -#endif /* EWP_EDL */ +#ifdef RX_PKT_POOL + dhd_rx_pktpool_deinit(dhd); +#endif #ifdef WL_CFG80211 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { @@ -17569,9 +14353,6 @@ void dhd_detach(dhd_pub_t *dhdp) osl_spin_lock_deinit(dhd->pub.osh, dhd->pub.mem_stats_lock); #endif /* DHD_MEM_STATS */ -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) - osl_spin_lock_deinit(dhd->pub.osh, dhd->pub.awdl_stats_lock); -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ #ifdef DHD_PKT_LOGGING dhd_os_detach_pktlog(dhdp); #endif /* DHD_PKT_LOGGING */ @@ -17616,9 +14397,6 @@ void dhd_detach(dhd_pub_t *dhdp) dhd->dhd_state &= ~DHD_ATTACH_LOGTRACE_INIT; } #endif /* SHOW_LOGTRACE */ -#ifdef BTLOG - skb_queue_purge(&dhd->bt_log_queue); -#endif /* BTLOG */ #ifdef PNO_SUPPORT if (dhdp->pno_state) dhd_pno_deinit(dhdp); @@ -17641,14 +14419,12 @@ void dhd_detach(dhd_pub_t *dhdp) dhd->new_freq = NULL; cpufreq_unregister_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); #endif - DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter)); #ifdef CONFIG_HAS_WAKELOCK dhd->wakelock_wd_counter = 0; - dhd_wake_lock_unlock_destroy(&dhd->wl_wdwake); - // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry - dhd_wake_lock_unlock_destroy(&dhd->wl_wifi); + dhd_wake_lock_destroy(dhd->wl_wdwake); #endif /* CONFIG_HAS_WAKELOCK */ if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { + DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter)); DHD_OS_WAKE_LOCK_DESTROY(dhd); } @@ -17663,6 +14439,13 @@ void dhd_detach(dhd_pub_t *dhdp) dhd_prot_detach(dhdp); #endif +#ifdef EWP_EDL + if (host_edl_support) { + DHD_EDL_MEM_DEINIT(dhdp); + host_edl_support = FALSE; + } +#endif /* EWP_EDL */ + #if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) dhd_free_tdls_peer_list(dhdp); #endif @@ -17680,9 +14463,9 @@ void dhd_detach(dhd_pub_t *dhdp) if (dhd->cih) ctf_detach(dhd->cih); #endif /* BCM_ROUTER_DHD && HNDCTF */ -#ifdef BCMDBG +#if defined(BCMDBG) && defined(DHD_MACDBG) dhd_macdbg_detach(dhdp); -#endif /* BCMDBG */ +#endif /* BCMDBG && DHD_MACDBG */ #ifdef DUMP_IOCTL_IOV_LIST dhd_iov_li_delete(dhdp, &(dhdp->dump_iovlist_head)); @@ -17695,12 +14478,6 @@ void dhd_detach(dhd_pub_t *dhdp) dhd_del_monitor_if(dhd); #endif /* WL_MONITOR */ -#ifdef DHD_ERPOM - if (dhdp->enable_erpom) { - dhdp->pom_func_deregister(&dhdp->pom_wlan_handler); - } -#endif /* DHD_ERPOM */ - cancel_work_sync(&dhd->dhd_hang_process_work); /* Prefer adding de-init code above this comment unless necessary. @@ -17728,17 +14505,16 @@ void dhd_detach(dhd_pub_t *dhdp) #endif /* DNGL_AXI_ERROR_LOGGING */ #endif /* BCMPCIE */ -#ifdef BTLOG - /* Wait till bt_log_dispatcher_work finishes */ - cancel_work_sync(&dhd->bt_log_dispatcher_work); -#endif /* BTLOG */ - #ifdef EWP_EDL cancel_delayed_work_sync(&dhd->edl_dispatcher_work); #endif (void)dhd_deinit_sock_flows_buf(dhd); +#ifdef CSI_SUPPORT + dhd_csi_deinit(dhdp); +#endif /* CSI_SUPPORT */ + #ifdef DHD_DUMP_MNGR if (dhd->pub.dump_file_manage) { MFREE(dhd->pub.osh, dhd->pub.dump_file_manage, @@ -17753,17 +14529,16 @@ void dhd_detach(dhd_pub_t *dhdp) mutex_destroy(&dhd->bus_user_lock); #endif /* BT_OVER_SDIO */ -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE - (void) dhd_fwtrace_detach(dhdp); -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ - #ifdef DHD_TX_PROFILE (void)dhd_tx_profile_detach(dhdp); #endif /* defined(DHD_TX_PROFILE) */ +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT + cancel_work_sync(&dhd->dhd_alert_process_work); +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) + cancel_work_sync(&dhd->dhd_dump_proc_work); +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ dhd_conf_detach(dhdp); - } /* dhd_detach */ void @@ -17814,11 +14589,19 @@ dhd_free(dhd_pub_t *dhdp) MFREE(dhdp->osh, dhdp->cached_nvram, MAX_NVRAMBUF_SIZE); } #endif +#ifdef SUPPORT_OTA_UPDATE + (void)dhd_ota_buf_clean(dhdp); +#endif /* SUPPORT_OTA_UPDATE */ if (dhd != NULL) { #ifdef REPORT_FATAL_TIMEOUTS deinit_dhd_timeouts(&dhd->pub); #endif /* REPORT_FATAL_TIMEOUTS */ + /* Free Platform Layer allocations */ + if (dhd->pub.plat_info) { + MFREE(dhdp->osh, dhdp->plat_info, dhdp->plat_info_size); + } + /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */ if (dhd != (dhd_info_t *)dhd_os_prealloc(dhdp, DHD_PREALLOC_DHD_INFO, 0, FALSE)) @@ -17875,8 +14658,23 @@ dhd_clear(dhd_pub_t *dhdp) static void dhd_module_cleanup(void) { +#ifdef DHD_SR_FIX + uint wl_down = 1; + int ret = 0; +#endif /* DHD_SR_FIX */ + +#if defined(ENABLE_NOT_LOAD_DHD_MODULE) + DHD_ERROR(("%s ##### Do not clean-up due to secondary build\n", __FUNCTION__)); + return; +#endif /* ENABLE_NOT_LOAD_DHD_MODULE */ printf("%s: Enter\n", __FUNCTION__); +#ifdef DHD_SR_FIX + ret = dhd_wl_ioctl_cmd(g_dhd_pub, WLC_DOWN, + (char *)&wl_down, sizeof(wl_down), TRUE, 0); + DHD_ERROR(("%s WL_DOWN : %d\n", __FUNCTION__, ret)); +#endif /* DHD_SR_FIX */ + dhd_bus_unregister(); #if defined(OEM_ANDROID) @@ -17884,12 +14682,19 @@ dhd_module_cleanup(void) #endif /* OEM_ANDROID */ dhd_wifi_platform_unregister_drv(); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_STATIC_IN_DRIVER) + dhd_static_buf_exit(); +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_STATIC_IN_DRIVER */ printf("%s: Exit\n", __FUNCTION__); } static void dhd_module_exit(void) { +#if defined(ENABLE_NOT_LOAD_DHD_MODULE) + DHD_ERROR(("%s ##### Do not unload driver due to secondary build\n", __FUNCTION__)); + return; +#endif /* ENABLE_NOT_LOAD_DHD_MODULE */ atomic_set(&exit_in_progress, 1); #ifdef DHD_BUZZZ_LOG_ENABLED dhd_buzzz_detach(); @@ -17897,11 +14702,12 @@ dhd_module_exit(void) dhd_module_cleanup(); unregister_reboot_notifier(&dhd_reboot_notifier); dhd_destroy_to_notifier_skt(); -#ifdef DHD_PKTTS - dhd_destroy_to_notifier_ts(); -#endif /* DHD_PKTTS */ } +#if defined(CONFIG_ARCH_WAIPIO) || defined(CONFIG_SOC_S5E9925) +extern bool devid_mismatch; +#endif /* CONFIG_ARCH_WAIPIO || CONFIG_SOC_S5E9925 */ + static int _dhd_module_init(void) { @@ -17912,6 +14718,12 @@ _dhd_module_init(void) PRINTF_SYSTEM_TIME, __FUNCTION__, dhd_version); if (ANDROID_VERSION > 0) printf("ANDROID_VERSION = %d\n", ANDROID_VERSION); +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_STATIC_IN_DRIVER) + err = dhd_static_buf_init(); + if (err) { + goto exit; + } +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_STATIC_IN_DRIVER */ #ifdef DHD_BUZZZ_LOG_ENABLED dhd_buzzz_attach(); @@ -17949,8 +14761,20 @@ _dhd_module_init(void) err = dhd_wifi_platform_register_drv(); if (!err) { register_reboot_notifier(&dhd_reboot_notifier); + dhd_create_to_notifier_skt(); break; } else { + if (err == -ENXIO) { + DHD_ERROR(("%s: driver is disabled\n", __FUNCTION__)); + break; + } +#if defined(CONFIG_ARCH_WAIPIO) || defined(CONFIG_SOC_S5E9925) + if (devid_mismatch == TRUE) { + DHD_ERROR(("%s: Devid is mismatch, don't retry\n", + __FUNCTION__)); + break; + } +#endif /* CONFIG_ARCH_WAIPIO || CONFIG_SOC_S5E9925 */ DHD_ERROR(("%s: Failed to load the driver, try cnt %d\n", __FUNCTION__, retry)); strlcpy(firmware_path, fw_bak_path, sizeof(firmware_path)); @@ -17958,11 +14782,12 @@ _dhd_module_init(void) } } while (retry--); - dhd_create_to_notifier_skt(); - -#ifdef DHD_PKTTS - dhd_create_to_notifier_ts(); -#endif /* DHD_PKTTS */ +#if defined(CONFIG_ARCH_WAIPIO) || defined(CONFIG_SOC_S5E9925) + if (devid_mismatch == TRUE) { + DHD_ERROR(("%s: Return true if devid is mismatch \n", __FUNCTION__)); + return 0; + } +#endif /* CONFIG_ARCH_WAIPIO || CONFIG_SOC_S5E9925 */ if (err) { DHD_ERROR(("%s: Failed to load driver max retry reached**\n", __FUNCTION__)); @@ -17972,6 +14797,11 @@ _dhd_module_init(void) } } +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_STATIC_IN_DRIVER) +exit: + if (err) + dhd_static_buf_exit(); +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_STATIC_IN_DRIVER */ printf("%s: Exit err=%d\n", __FUNCTION__, err); return err; } @@ -17981,12 +14811,20 @@ dhd_module_init(void) { int err; +#if defined(ENABLE_NOT_LOAD_DHD_MODULE) + DHD_ERROR(("%s ##### Do not load driver due to secondary build\n", __FUNCTION__)); + return 0; +#endif /* ENABLE_NOT_LOAD_DHD_MODULE */ err = _dhd_module_init(); #ifdef DHD_SUPPORT_HDM - if (err && !dhd_download_fw_on_driverload) { + if (hdm_wifi_support && err && !dhd_download_fw_on_driverload) { dhd_hdm_wlan_sysfs_init(); + err = 0; } #endif /* DHD_SUPPORT_HDM */ +#if defined(BCMDHD_MODULAR) && defined(DHD_MODULE_INIT_FORCE_SUCCESS) + err = 0; +#endif /* BCMDHD_MODULAR && DHD_MODULE_INIT_FORCE_SUCCESS */ return err; } @@ -18023,16 +14861,22 @@ dhd_module_init_hdm(void) static int dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused) { - DHD_TRACE(("%s: code = %ld\n", __FUNCTION__, code)); - if (code == SYS_RESTART) { + dhd_pub_t *dhdp = g_dhd_pub; + + BCM_REFERENCE(dhdp); + DHD_ERROR(("%s: code = %ld\n", __FUNCTION__, code)); #ifdef OEM_ANDROID -#ifdef BCMPCIE - is_reboot = code; -#endif /* BCMPCIE */ -#else - dhd_module_cleanup(); -#endif /* OEM_ANDROID */ + if (!OSL_ATOMIC_INC_AND_TEST(dhdp->osh, &reboot_in_progress)) { + DHD_ERROR(("%s: Skip duplicated reboot callback!\n", __FUNCTION__)); + return NOTIFY_DONE; } + + dhd_module_cleanup(); +#else + if (code == SYS_RESTART) { + dhd_module_cleanup(); + } +#endif /* OEM_ANDROID */ return NOTIFY_DONE; } @@ -18098,6 +14942,15 @@ late_initcall(dhd_module_init); module_exit(dhd_module_exit); #endif +/* For the Exynos platform, the WLAN_REG_ON pin is connected to an expander GPIO such as PMIC. + * The WLAN_REG_ON pin initialization failed + * if the Wi-Fi module is loaded before the PMIC module is loaded. + * Add the MODULE_SOFTDEP macro to load the Wi-Fi module after the PMIC module is loaded. + */ +#if defined(CONFIG_SOC_S5E9925) +MODULE_SOFTDEP("pre: acpm-mfd-bus"); +#endif /* CONFIG_SOC_S5E9925 */ + /* * OS specific functions required to implement DHD driver in OS independent way */ @@ -18178,28 +15031,6 @@ dhd_os_logdump_unlock(dhd_pub_t *pub) } } -unsigned long -dhd_os_dbgring_lock(void *lock) -{ - if (!lock) - return 0; - - mutex_lock((struct mutex *)lock); - - return 0; -} - -void -dhd_os_dbgring_unlock(void *lock, unsigned long flags) -{ - BCM_REFERENCE(flags); - - if (!lock) - return; - - mutex_unlock((struct mutex *)lock); -} - unsigned int dhd_os_get_ioctl_resp_timeout(void) { @@ -18377,14 +15208,6 @@ dhd_os_dmaxfer_wake(dhd_pub_t *pub) return 0; } -void -dhd_os_tx_completion_wake(dhd_pub_t *dhd) -{ - /* Call wmb() to make sure before waking up the other event value gets updated */ - OSL_SMP_WMB(); - wake_up(&dhd->tx_completion_wait); -} - /* Fix compilation error for FC11 */ INLINE int dhd_os_busbusy_wake(dhd_pub_t *pub) @@ -18462,58 +15285,6 @@ dhd_os_wd_timer(void *bus, uint wdtick) #endif /* BCMDBUS */ } -#ifdef DHD_PCIE_RUNTIMEPM -void -dhd_os_runtimepm_timer(void *bus, uint tick) -{ - dhd_pub_t *pub = bus; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - unsigned long flags; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!dhd) { - DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); - return; - } - - DHD_GENERAL_LOCK(pub, flags); - - /* don't start the RPM until fw is loaded */ - if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(pub)) { - DHD_GENERAL_UNLOCK(pub, flags); - return; - } - - /* If tick is non-zero, the request is to start the timer */ - if (tick) { - /* Start the timer only if its not already running */ - if (dhd->rpm_timer_valid == FALSE) { - mod_timer(&dhd->rpm_timer, jiffies + msecs_to_jiffies(dhd_runtimepm_ms)); - dhd->rpm_timer_valid = TRUE; - DHD_ERROR(("DHD Runtime PM Timer ON\n")); - } - } else { - /* tick is zero, we have to stop the timer */ - /* Stop the timer only if its running, otherwise we don't have to do anything */ - if (dhd->rpm_timer_valid == TRUE) { - dhd->rpm_timer_valid = FALSE; - DHD_GENERAL_UNLOCK(pub, flags); - del_timer_sync(&dhd->rpm_timer); - DHD_ERROR(("DHD Runtime PM Timer OFF \n")); - /* we have already released the lock, so just go to exit */ - goto exit; - } - } - - DHD_GENERAL_UNLOCK(pub, flags); -exit: - return; - -} - -#endif /* DHD_PCIE_RUNTIMEPM */ - #ifdef DHD_LINUX_STD_FW_API int dhd_os_get_img_fwreq(const struct firmware **fw, char *file_path) @@ -18526,7 +15297,7 @@ dhd_os_get_img_fwreq(const struct firmware **fw, char *file_path) /* convert to BCME_NOTFOUND error for error handling */ ret = BCME_NOTFOUND; } else - DHD_ERROR(("%s: %s (%zu bytes) open success\n", __FUNCTION__, file_path, (*fw)->size)); + DHD_ERROR(("%s: %s (%zu bytes) open success\n", __FUNCTION__, file_path, (*fw)->size)); return ret; } @@ -18544,14 +15315,15 @@ dhd_os_open_image1(dhd_pub_t *pub, char *filename) struct file *fp; int size; - fp = filp_open(filename, O_RDONLY, 0); + fp = dhd_filp_open(filename, O_RDONLY, 0); + /* - * 2.6.11 (FC4) supports filp_open() but later revs don't? + * 2.6.11 (FC4) supports dhd_filp_open() but later revs don't? * Alternative: * fp = open_namei(AT_FDCWD, filename, O_RD, 0); * ??? */ - if (IS_ERR(fp)) { + if (IS_ERR(fp) || (fp == NULL)) { fp = NULL; goto err; } @@ -18562,7 +15334,7 @@ dhd_os_open_image1(dhd_pub_t *pub, char *filename) goto err; } - size = i_size_read(file_inode(fp)); + size = dhd_i_size_read(file_inode(fp)); if (size <= 0) { DHD_ERROR(("%s: %s file size invalid %d\n", __FUNCTION__, filename, size)); fp = NULL; @@ -18586,8 +15358,8 @@ dhd_os_get_image_block(char *buf, int len, void *image) return 0; } - size = i_size_read(file_inode(fp)); - rdlen = kernel_read_compat(fp, fp->f_pos, buf, MIN(len, size)); + size = dhd_i_size_read(file_inode(fp)); + rdlen = dhd_kernel_read_compat(fp, fp->f_pos, buf, MIN(len, size)); if (len >= size && size != rdlen) { return -EIO; @@ -18612,7 +15384,7 @@ dhd_os_gets_image(dhd_pub_t *pub, char *str, int len, void *image) if (!image) return 0; - rd_len = kernel_read_compat(fp, fp->f_pos, str, len); + rd_len = dhd_kernel_read_compat(fp, fp->f_pos, str, len); str_end = strnchr(str, len, '\n'); if (str_end == NULL) { goto err; @@ -18637,7 +15409,7 @@ dhd_os_get_image_size(void *image) return 0; } - size = i_size_read(file_inode(fp)); + size = dhd_i_size_read(file_inode(fp)); return size; } @@ -18646,7 +15418,7 @@ void dhd_os_close_image1(dhd_pub_t *pub, void *image) { if (image) { - filp_close((struct file *)image, NULL); + dhd_filp_close((struct file *)image, NULL); } } @@ -18684,82 +15456,6 @@ dhd_os_sdunlock(dhd_pub_t *pub) #endif /* !BCMDBUS */ } -void -dhd_os_sdlock_txq(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); -#ifdef BCMDBUS - spin_lock_irqsave(&dhd->txqlock, dhd->txqlock_flags); -#else - spin_lock_bh(&dhd->txqlock); -#endif /* BCMDBUS */ -} - -void -dhd_os_sdunlock_txq(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); -#ifdef BCMDBUS - spin_unlock_irqrestore(&dhd->txqlock, dhd->txqlock_flags); -#else - spin_unlock_bh(&dhd->txqlock); -#endif /* BCMDBUS */ -} - -unsigned long -dhd_os_sdlock_txoff(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - unsigned long flags = 0; - - dhd = (dhd_info_t *)(pub->info); - spin_lock_irqsave(&dhd->txoff_lock, flags); - - return flags; -} - -void -dhd_os_sdunlock_txoff(dhd_pub_t *pub, unsigned long flags) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_unlock_irqrestore(&dhd->txoff_lock, flags); -} - -void -dhd_os_sdlock_rxq(dhd_pub_t *pub) -{ -} - -void -dhd_os_sdunlock_rxq(dhd_pub_t *pub) -{ -} - -static void -dhd_os_rxflock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_lock_bh(&dhd->rxf_lock); - -} - -static void -dhd_os_rxfunlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_unlock_bh(&dhd->rxf_lock); -} - #ifdef DHDTCPACK_SUPPRESS unsigned long dhd_os_tcpacklock(dhd_pub_t *pub) @@ -18841,52 +15537,6 @@ dhd_get_wireless_stats(struct net_device *dev) } #endif /* defined(WL_WIRELESS_EXT) */ -static int -dhd_wl_host_event(dhd_info_t *dhd, int ifidx, void *pktdata, uint16 pktlen, - wl_event_msg_t *event, void **data) -{ - int bcmerror = 0; -#ifdef WL_CFG80211 - unsigned long flags = 0; -#endif /* WL_CFG80211 */ - ASSERT(dhd != NULL); - -#ifdef SHOW_LOGTRACE - bcmerror = wl_process_host_event(&dhd->pub, &ifidx, pktdata, pktlen, event, data, - &dhd->event_data); -#else - bcmerror = wl_process_host_event(&dhd->pub, &ifidx, pktdata, pktlen, event, data, - NULL); -#endif /* SHOW_LOGTRACE */ - if (unlikely(bcmerror != BCME_OK)) { - return bcmerror; - } - - if (ntoh32(event->event_type) == WLC_E_IF) { - /* WLC_E_IF event types are consumed by wl_process_host_event. - * For ifadd/del ops, the netdev ptr may not be valid at this - * point. so return before invoking cfg80211/wext handlers. - */ - return BCME_OK; - } - -#ifdef WL_EVENT - wl_ext_event_send(dhd->pub.event_params, event, *data); -#endif - -#ifdef WL_CFG80211 - if (dhd->iflist[ifidx]->net) { - DHD_UP_LOCK(&dhd->pub.up_lock, flags); - if (dhd->pub.up) { - wl_cfg80211_event(dhd->iflist[ifidx]->net, event, *data); - } - DHD_UP_UNLOCK(&dhd->pub.up_lock, flags); - } -#endif /* defined(WL_CFG80211) */ - - return (bcmerror); -} - /* send up locally generated event */ void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) @@ -18948,7 +15598,7 @@ dhd_sendup_log(dhd_pub_t *dhdp, void *data, int data_len) if (in_interrupt()) { netif_rx(skb); } else { - netif_rx_ni(skb); + dhd_netif_rx_ni(skb); } } else { /* Could not allocate a sk_buf */ @@ -18969,7 +15619,7 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) dhd_os_sdlock(dhd); #endif /* defined(BCMSDIO) */ return; -} /* dhd_init_static_strs_array */ +} void dhd_wait_event_wakeup(dhd_pub_t *dhd) { @@ -19045,25 +15695,24 @@ dhd_net_bus_devreset(struct net_device *dev, uint8 flag) dhd->fw_path, dhd->nv_path, dhd->clm_path, dhd->conf_path); } #endif /* BCMSDIO */ -#if defined(CONFIG_ARCH_EXYNOS) && defined(BCMPCIE) -#if !defined(CONFIG_SOC_EXYNOS8890) && !defined(SUPPORT_EXYNOS7420) +#if defined(BCMPCIE) /* XXX: JIRA SWWLAN-139454: Added L1ss enable * after firmware download completion due to link down issue * JIRA SWWLAN-142236: Amendment - Changed L1ss enable point */ - DHD_ERROR(("%s Disable L1ss EP side\n", __FUNCTION__)); if (flag == FALSE && dhd->pub.busstate == DHD_BUS_DOWN) { -#if defined(CONFIG_SOC_GS101) - exynos_pcie_rc_l1ss_ctrl(0, PCIE_L1SS_CTRL_WIFI, 1); -#else - exynos_pcie_l1ss_ctrl(0, PCIE_L1SS_CTRL_WIFI); -#endif /* CONFIG_SOC_GS101 */ + DHD_RPM(("%s Disable L1ss EP side\n", __FUNCTION__)); + dhd_plat_l1ss_ctrl(0); } -#endif /* !CONFIG_SOC_EXYNOS8890 && !defined(SUPPORT_EXYNOS7420) */ -#endif /* CONFIG_ARCH_EXYNOS && BCMPCIE */ +#endif /* BCMPCIE */ ret = dhd_bus_devreset(&dhd->pub, flag); + if (!ret && dhd_query_bus_erros(&dhd->pub)) { + DHD_ERROR(("%s: retrun error due to query errors\n", __FUNCTION__)); + ret = BCME_ERROR; + } + #ifdef DHD_PCIE_NATIVE_RUNTIMEPM pm_runtime_mark_last_busy(dhd_bus_to_dev(dhd->pub.bus)); pm_runtime_put_autosuspend(dhd_bus_to_dev(dhd->pub.bus)); @@ -19072,23 +15721,39 @@ dhd_net_bus_devreset(struct net_device *dev, uint8 flag) if (flag) { /* Clear some flags for recovery logic */ dhd->pub.dongle_trap_occured = 0; -#ifdef BT_OVER_PCIE - dhd->pub.dongle_trap_due_to_bt = 0; -#endif /* BT_OVER_PCIE */ + dhd->pub.dsack_hc_due_to_isr_delay = 0; + dhd->pub.dsack_hc_due_to_dpc_delay = 0; dhd->pub.iovar_timeout_occured = 0; #ifdef PCIE_FULL_DONGLE dhd->pub.d3ack_timeout_occured = 0; dhd->pub.livelock_occured = 0; dhd->pub.pktid_audit_failed = 0; + dhd->pub.pktid_invalid_occured = 0; #endif /* PCIE_FULL_DONGLE */ dhd->pub.smmu_fault_occurred = 0; dhd->pub.iface_op_failed = 0; dhd->pub.scan_timeout_occurred = 0; dhd->pub.scan_busy_occurred = 0; + dhd->pub.p2p_disc_busy_occurred = 0; + } + + dhd->pub.p2p_disc_busy_cnt = 0; + + if (ret == BCME_NOMEM) { + DHD_ERROR(("%s: skip collect dump in case of BCME_NOMEM\n", + __FUNCTION__)); + return BCME_ERROR; + } + + if ((ret == BCME_NOMEM) || (ret == BCME_NOTFOUND)) { + DHD_ERROR(("%s: skip collect dump in case of BCME_NOMEM or BCME_NOTFOUND\n", + __FUNCTION__)); + return BCME_ERROR; } if (ret) { DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); + dhd_force_collect_init_fail_dumps(&dhd->pub); } return ret; @@ -19099,14 +15764,59 @@ int dhd_net_bus_suspend(struct net_device *dev) { dhd_info_t *dhd = DHD_DEV_INFO(dev); - return dhd_bus_suspend(&dhd->pub); + uint bitmask = 0xFFFFFFFF; + int timeleft = 0; + unsigned long flags = 0; + int ret = 0; + + DHD_GENERAL_LOCK(&dhd->pub, flags); + if (!DHD_BUS_BUSY_CHECK_IDLE(&dhd->pub)) { + DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(&dhd->pub); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + DHD_ERROR(("%s: wait to clear dhd_bus_busy_state: 0x%x\n", + __FUNCTION__, dhd->pub.dhd_bus_busy_state)); + timeleft = dhd_os_busbusy_wait_bitmask(&dhd->pub, + &dhd->pub.dhd_bus_busy_state, bitmask, + DHD_BUS_BUSY_SUSPEND_IN_PROGRESS); + if ((timeleft == 0) || (timeleft == 1)) { + DHD_ERROR(("%s: Timed out dhd_bus_busy_state=0x%x\n", + __FUNCTION__, dhd->pub.dhd_bus_busy_state)); + ASSERT(0); + } + } else { + DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(&dhd->pub); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + } + + ret = dhd_bus_suspend(&dhd->pub); + + DHD_GENERAL_LOCK(&dhd->pub, flags); + DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(&dhd->pub); + dhd_os_busbusy_wake(&dhd->pub); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + + return ret; } int dhd_net_bus_resume(struct net_device *dev, uint8 stage) { dhd_info_t *dhd = DHD_DEV_INFO(dev); - return dhd_bus_resume(&dhd->pub, stage); + unsigned long flags = 0; + int ret = 0; + + DHD_GENERAL_LOCK(&dhd->pub, flags); + DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(&dhd->pub); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + + ret = dhd_bus_resume(&dhd->pub, stage); + + DHD_GENERAL_LOCK(&dhd->pub, flags); + DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(&dhd->pub); + dhd_os_busbusy_wake(&dhd->pub); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + + return ret; } #endif /* BCMSDIO || BCMPCIE */ @@ -19147,91 +15857,7 @@ int net_os_set_suspend(struct net_device *dev, int val, int force) return ret; } -int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (dhd) { - DHD_ERROR(("%s: Set bcn_li_dtim in suspend %d\n", - __FUNCTION__, val)); - dhd->pub.suspend_bcn_li_dtim = val; - } - - return 0; -} - -int net_os_set_max_dtim_enable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (dhd) { - DHD_ERROR(("%s: use MAX bcn_li_dtim in suspend %s\n", - __FUNCTION__, (val ? "Enable" : "Disable"))); - if (val) { - dhd->pub.max_dtim_enable = TRUE; - } else { - dhd->pub.max_dtim_enable = FALSE; - } - } else { - return -1; - } - - return 0; -} - -#ifdef DISABLE_DTIM_IN_SUSPEND -int net_os_set_disable_dtim_in_suspend(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (dhd) { - DHD_ERROR(("%s: Disable bcn_li_dtim in suspend %s\n", - __FUNCTION__, (val ? "Enable" : "Disable"))); - if (val) { - dhd->pub.disable_dtim_in_suspend = TRUE; - } else { - dhd->pub.disable_dtim_in_suspend = FALSE; - } - } else { - return BCME_ERROR; - } - - return BCME_OK; -} -#endif /* DISABLE_DTIM_IN_SUSPEND */ - #ifdef PKT_FILTER_SUPPORT -int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) -{ - int ret = 0; - -#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (!dhd_master_mode) - add_remove = !add_remove; - DHD_ERROR(("%s: add_remove = %d, num = %d\n", __FUNCTION__, add_remove, num)); - if (!dhd || (num == DHD_UNICAST_FILTER_NUM)) { - return 0; - } - -#ifdef BLOCK_IPV6_PACKET - /* customer want to use NO IPV6 packets only */ - if (num == DHD_MULTICAST6_FILTER_NUM) { - return 0; - } -#endif /* BLOCK_IPV6_PACKET */ - - if (num >= dhd->pub.pktfilter_count) { - return -EINVAL; - } - - ret = dhd_packet_filter_add_remove(&dhd->pub, add_remove, num); -#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */ - - return ret; -} - /* XXX RB:4238 Change net_os_set_packet_filter() function name to net_os_enable_packet_filter() * previous code do 'set' & 'enable' in one fucntion. * but from now on, we are going to separate 'set' and 'enable' feature. @@ -19263,7 +15889,7 @@ int net_os_enable_packet_filter(struct net_device *dev, int val) { dhd_info_t *dhd = DHD_DEV_INFO(dev); - DHD_ERROR(("%s: val = %d\n", __FUNCTION__, val)); + DHD_INFO(("%s: val = %d\n", __FUNCTION__, val)); return dhd_os_enable_packet_filter(&dhd->pub, val); } #endif /* PKT_FILTER_SUPPORT */ @@ -19332,7 +15958,9 @@ dhd_dev_get_feature_set(struct net_device *dev) /* terence 20171115: remove to get GTS PASS * com.google.android.gts.wifi.WifiHostTest#testWifiScannerBatchTimestamp */ +#ifndef DISABLE_ANDROID_GSCAN // feature_set |= WIFI_FEATURE_GSCAN; +#endif /* DISABLE_ANDROID_GSCAN */ // feature_set |= WIFI_FEATURE_HAL_EPNO; #endif /* GSCAN_SUPPORT */ } @@ -19362,9 +15990,6 @@ dhd_dev_get_feature_set(struct net_device *dev) #ifdef ROAMEXP_SUPPORT feature_set |= WIFI_FEATURE_CONTROL_ROAMING; #endif /* ROAMEXP_SUPPORT */ -#ifdef WL_LATENCY_MODE - feature_set |= WIFI_FEATURE_SET_LATENCY_MODE; -#endif /* WL_LATENCY_MODE */ #ifdef WL_P2P_RAND feature_set |= WIFI_FEATURE_P2P_RAND_MAC; #endif /* WL_P2P_RAND */ @@ -19430,20 +16055,34 @@ dhd_dev_get_feature_set_matrix(struct net_device *dev, int num) return ret; } -#ifdef CUSTOM_FORCE_NODFS_FLAG +#if defined(CUSTOM_FORCE_NODFS_FLAG) && defined(CUSTOM_COUNTRY_CODE) int dhd_dev_set_nodfs(struct net_device *dev, u32 nodfs) { dhd_info_t *dhd = DHD_DEV_INFO(dev); + bool force_ccode_change = FALSE; + UNUSED_PARAMETER(force_ccode_change); - if (nodfs) + if (nodfs && !(dhd->pub.dhd_cflags & WLAN_PLAT_NODFS_FLAG)) { dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; - else + force_ccode_change = TRUE; + } else if (!nodfs && (dhd->pub.dhd_cflags & WLAN_PLAT_NODFS_FLAG)) { dhd->pub.dhd_cflags &= ~WLAN_PLAT_NODFS_FLAG; + force_ccode_change = TRUE; + } + +#ifdef SKIP_CCODE_FOR_SAME_DFS_FLAG + if (force_ccode_change == FALSE) { + DHD_ERROR(("No change in dfs flags. dfs:%d\n", !!nodfs)); + return 0; + } +#endif /* SKIP_CCODE_FOR_SAME_DFS_FLAG */ + + DHD_ERROR(("Force country change. dfs:%d \n", !!nodfs)); dhd->pub.force_country_change = TRUE; return 0; } -#endif /* CUSTOM_FORCE_NODFS_FLAG */ +#endif /* CUSTOM_FORCE_NODFS_FLAG && CUSTOM_COUNTRY_CODE */ #ifdef NDO_CONFIG_SUPPORT int @@ -19742,7 +16381,7 @@ dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize) } #endif /* PNO_SUPPORT */ -#if defined(OEM_ANDROID) && defined(PNO_SUPPORT) +#if defined(PNO_SUPPORT) #ifdef GSCAN_SUPPORT bool dhd_dev_is_legacy_pno_enabled(struct net_device *dev) @@ -19912,7 +16551,7 @@ dhd_dev_set_lazy_roam_cfg(struct net_device *dev, roam_param->alert_roam_trigger_threshold, roam_param->a_band_max_boost)); memcpy(&roam_exp_cfg.params, roam_param, sizeof(*roam_param)); - roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; + roam_exp_cfg.version = ROAM_EXP_CFG_VERSION_1; roam_exp_cfg.flags = ROAM_EXP_CFG_PRESENT; if (dhd->pub.lazy_roam_enable) { roam_exp_cfg.flags |= ROAM_EXP_ENABLE_FLAG; @@ -19934,7 +16573,7 @@ dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable) wl_roam_exp_cfg_t roam_exp_cfg; memset(&roam_exp_cfg, 0, sizeof(roam_exp_cfg)); - roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; + roam_exp_cfg.version = ROAM_EXP_CFG_VERSION_1; if (enable) { roam_exp_cfg.flags = ROAM_EXP_ENABLE_FLAG; } @@ -19958,7 +16597,7 @@ dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, uint len; dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - bssid_pref->version = BSSID_PREF_LIST_VERSION; + bssid_pref->version = BSSID_PREF_LIST_VERSION_1; /* By default programming bssid pref flushes out old values */ bssid_pref->flags = (flush && !bssid_pref->count) ? ROAM_EXP_CLEAR_BSSID_PREF: 0; len = sizeof(wl_bssid_pref_cfg_t); @@ -20018,7 +16657,7 @@ dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *ssid_whi return BCME_BADARG; } } - ssid_whitelist->version = SSID_WHITELIST_VERSION; + ssid_whitelist->version = SSID_WHITELIST_VERSION_1; ssid_whitelist->flags = flush ? ROAM_EXP_CLEAR_SSID_WHITELIST : 0; err = dhd_iovar(&dhd->pub, 0, "roam_exp_ssid_whitelist", (char *)ssid_whitelist, len, NULL, 0, TRUE); @@ -20044,7 +16683,7 @@ dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, wl_rssi_monitor_cfg_t rssi_monitor; dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - rssi_monitor.version = RSSI_MONITOR_VERSION; + rssi_monitor.version = RSSI_MONITOR_VERSION_1; rssi_monitor.max_rssi = max_rssi; rssi_monitor.min_rssi = min_rssi; rssi_monitor.flags = start ? 0: RSSI_MONITOR_STOP; @@ -20184,7 +16823,8 @@ int dhd_dev_rtt_cancel_responder(struct net_device *dev) } #endif /* RTT_SUPPORT */ -#if defined(PKT_FILTER_SUPPORT) && defined(APF) + +#if defined(APF) static void _dhd_apf_lock_local(dhd_info_t *dhd) { if (dhd) { @@ -20200,44 +16840,54 @@ static void _dhd_apf_unlock_local(dhd_info_t *dhd) } static int -__dhd_apf_add_filter(struct net_device *ndev, uint32 filter_id, - u8* program, uint32 program_len) +_dhd_apf_add_filter(struct net_device *ndev, uint32 filter_id, u8* program, uint32 program_len) { dhd_info_t *dhd = DHD_DEV_INFO(ndev); dhd_pub_t *dhdp = &dhd->pub; wl_pkt_filter_t * pkt_filterp; wl_apf_program_t *apf_program; - char *buf; - u32 cmd_len, buf_len; - int ifidx, ret; + char *buf = NULL; + u32 cmd_len, buf_len, max_len; + int ifidx, ret = BCME_OK; char cmd[] = "pkt_filter_add"; ifidx = dhd_net2idx(dhd, ndev); if (ifidx == DHD_BAD_IF) { DHD_ERROR(("%s: bad ifidx\n", __FUNCTION__)); - return -ENODEV; + ret = -ENODEV; + goto exit; } cmd_len = sizeof(cmd); - /* Check if the program_len is more than the expected len - * and if the program is NULL return from here. + /* Check if the program_len is more than the expected len or if the program is NULL, + * then return from here. */ - if ((program_len > WL_APF_PROGRAM_MAX_SIZE) || (program == NULL)) { - DHD_ERROR(("%s Invalid program_len: %d, program: %pK\n", - __FUNCTION__, program_len, program)); - return -EINVAL; + ret = dhd_wl_ioctl_get_intiovar(dhdp, "apf_size_limit", &max_len, WLC_GET_VAR, + FALSE, ifidx); + if (unlikely(ret)) { + DHD_ERROR(("%s: failed to get APF size limit, ret=%d\n", __FUNCTION__, ret)); + goto exit; + } + if ((program_len > max_len) || (program == NULL)) { + DHD_ERROR(("%s Invalid program_len: %d, program: %pK\n", __FUNCTION__, + program_len, program)); + ret = -EINVAL; + goto exit; } - buf_len = cmd_len + WL_PKT_FILTER_FIXED_LEN + - WL_APF_PROGRAM_FIXED_LEN + program_len; + buf_len = cmd_len + WL_PKT_FILTER_FIXED_LEN + WL_APF_PROGRAM_FIXED_LEN + program_len; buf = MALLOCZ(dhdp->osh, buf_len); if (unlikely(!buf)) { DHD_ERROR(("%s: MALLOC failure, %d bytes\n", __FUNCTION__, buf_len)); - return -ENOMEM; + ret = -ENOMEM; + goto exit; } - memcpy(buf, cmd, cmd_len); + ret = memcpy_s(buf, buf_len, cmd, cmd_len); + if (unlikely(ret)) { + goto exit; + } pkt_filterp = (wl_pkt_filter_t *) (buf + cmd_len); pkt_filterp->id = htod32(filter_id); @@ -20247,65 +16897,16 @@ __dhd_apf_add_filter(struct net_device *ndev, uint32 filter_id, apf_program = &pkt_filterp->u.apf_program; apf_program->version = htod16(WL_APF_INTERNAL_VERSION); apf_program->instr_len = htod16(program_len); - memcpy(apf_program->instrs, program, program_len); - - ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, buf_len, TRUE, ifidx); + ret = memcpy_s(apf_program->instrs, program_len, program, program_len); if (unlikely(ret)) { - DHD_ERROR(("%s: failed to add APF filter, id=%d, ret=%d\n", - __FUNCTION__, filter_id, ret)); - } - - if (buf) { - MFREE(dhdp->osh, buf, buf_len); - } - return ret; -} - -static int -__dhd_apf_config_filter(struct net_device *ndev, uint32 filter_id, - uint32 mode, uint32 enable) -{ - dhd_info_t *dhd = DHD_DEV_INFO(ndev); - dhd_pub_t *dhdp = &dhd->pub; - wl_pkt_filter_enable_t * pkt_filterp; - char *buf; - u32 cmd_len, buf_len; - int ifidx, ret; - char cmd[] = "pkt_filter_enable"; - - ifidx = dhd_net2idx(dhd, ndev); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: bad ifidx\n", __FUNCTION__)); - return -ENODEV; - } - - cmd_len = sizeof(cmd); - buf_len = cmd_len + sizeof(*pkt_filterp); - - buf = MALLOCZ(dhdp->osh, buf_len); - if (unlikely(!buf)) { - DHD_ERROR(("%s: MALLOC failure, %d bytes\n", __FUNCTION__, buf_len)); - return -ENOMEM; - } - - memcpy(buf, cmd, cmd_len); - - pkt_filterp = (wl_pkt_filter_enable_t *) (buf + cmd_len); - pkt_filterp->id = htod32(filter_id); - pkt_filterp->enable = htod32(enable); - - ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, buf_len, TRUE, ifidx); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to enable APF filter, id=%d, ret=%d\n", - __FUNCTION__, filter_id, ret)); goto exit; } - ret = dhd_wl_ioctl_set_intiovar(dhdp, "pkt_filter_mode", dhd_master_mode, - WLC_SET_VAR, TRUE, ifidx); + ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, buf_len, TRUE, ifidx); if (unlikely(ret)) { - DHD_ERROR(("%s: failed to set APF filter mode, id=%d, ret=%d\n", - __FUNCTION__, filter_id, ret)); + DHD_ERROR(("%s: failed to add APF filter, id=%d, ret=%d\n", __FUNCTION__, + filter_id, ret)); + goto exit; } exit: @@ -20316,7 +16917,66 @@ exit: } static int -__dhd_apf_delete_filter(struct net_device *ndev, uint32 filter_id) +_dhd_apf_config_filter(struct net_device *ndev, uint32 filter_id, uint32 mode, uint32 enable) +{ + dhd_info_t *dhd = DHD_DEV_INFO(ndev); + dhd_pub_t *dhdp = &dhd->pub; + wl_pkt_filter_enable_t * pkt_filterp; + char *buf = NULL; + u32 cmd_len, buf_len; + int ifidx, ret; + char cmd[] = "pkt_filter_enable"; + + ifidx = dhd_net2idx(dhd, ndev); + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s: bad ifidx\n", __FUNCTION__)); + ret = -ENODEV; + goto exit; + } + + cmd_len = sizeof(cmd); + buf_len = cmd_len + (u32)sizeof(*pkt_filterp); + + buf = MALLOCZ(dhdp->osh, buf_len); + if (unlikely(!buf)) { + DHD_ERROR(("%s: MALLOC failure, %d bytes\n", __FUNCTION__, buf_len)); + ret = -ENOMEM; + goto exit; + } + + ret = memcpy_s(buf, buf_len, cmd, cmd_len); + if (unlikely(ret)) { + goto exit; + } + + pkt_filterp = (wl_pkt_filter_enable_t *) (buf + cmd_len); + pkt_filterp->id = htod32(filter_id); + pkt_filterp->enable = htod32(enable); + + ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, buf_len, TRUE, ifidx); + if (unlikely(ret)) { + DHD_ERROR(("%s: failed to enable APF filter, id=%d, ret=%d\n", __FUNCTION__, + filter_id, ret)); + goto exit; + } + + ret = dhd_wl_ioctl_set_intiovar(dhdp, "pkt_filter_mode", dhd_master_mode, WLC_SET_VAR, + TRUE, ifidx); + if (unlikely(ret)) { + DHD_ERROR(("%s: failed to set APF filter mode, id=%d, ret=%d\n", __FUNCTION__, + filter_id, ret)); + goto exit; + } + +exit: + if (buf) { + MFREE(dhdp->osh, buf, buf_len); + } + return ret; +} + +static int +_dhd_apf_delete_filter(struct net_device *ndev, uint32 filter_id) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(ndev); dhd_pub_t *dhdp = &dhd->pub; @@ -20328,11 +16988,68 @@ __dhd_apf_delete_filter(struct net_device *ndev, uint32 filter_id) return -ENODEV; } - ret = dhd_wl_ioctl_set_intiovar(dhdp, "pkt_filter_delete", - htod32(filter_id), WLC_SET_VAR, TRUE, ifidx); + ret = dhd_wl_ioctl_set_intiovar(dhdp, "pkt_filter_delete", htod32(filter_id), + WLC_SET_VAR, TRUE, ifidx); if (unlikely(ret)) { - DHD_ERROR(("%s: failed to delete APF filter, id=%d, ret=%d\n", - __FUNCTION__, filter_id, ret)); + DHD_ERROR(("%s: failed to delete APF filter, id=%d, ret=%d\n", __FUNCTION__, + filter_id, ret)); + return ret; + } + + return ret; +} + +static int +_dhd_apf_read_filter_data(struct net_device *ndev, uint32 filter_id, u8* buf, uint32 buf_len) +{ + dhd_info_t *dhd = DHD_DEV_INFO(ndev); + dhd_pub_t *dhdp = &dhd->pub; + wl_apf_program_t *apf_program; + u32 cmd_len, max_len; + int ifidx, ret; + char cmd[] = "apf_buf_get"; + + ifidx = dhd_net2idx(dhd, ndev); + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s: bad ifidx\n", __FUNCTION__)); + return -ENODEV; + } + + /* Check if the provided buffer is large enough to store the filter data or + * if the buffer is NULL, then return from here. + */ + ret = dhd_wl_ioctl_get_intiovar(dhdp, "apf_size_limit", &max_len, + WLC_GET_VAR, FALSE, ifidx); + if (unlikely(ret)) { + DHD_ERROR(("%s: failed to get APF size limit, ret=%d\n", + __FUNCTION__, ret)); + return ret; + } + if ((buf_len < (WL_APF_PROGRAM_FIXED_LEN + max_len)) || (buf == NULL)) { + DHD_ERROR(("%s: Invalid buf_len=%d or buf=%pK\n", __FUNCTION__, buf_len, buf)); + return -EINVAL; + } + + /* Get APF filter data from the dongle */ + cmd_len = sizeof(cmd); + ret = memcpy_s(buf, buf_len, cmd, cmd_len); + if (unlikely(ret)) { + return ret; + } + *(buf + cmd_len) = htod32(filter_id); + ret = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, buf, buf_len, FALSE, ifidx); + if (unlikely(ret)) { + DHD_ERROR(("%s: failed to read APF filter data, id=%d, ret=%d\n", __FUNCTION__, + filter_id, ret)); + return ret; + } + + /* Validate structure version */ + apf_program = (wl_apf_program_t *)buf; + if (apf_program->version != WL_APF_INTERNAL_VERSION) { + DHD_ERROR(("%s: incorrect version, version=%d, expected version=%d\n", + __FUNCTION__, apf_program->version, WL_APF_INTERNAL_VERSION)); + return BCME_VERSION; } return ret; @@ -20359,11 +17076,7 @@ dhd_dev_apf_get_version(struct net_device *ndev, uint32 *version) if (!FW_SUPPORTED(dhdp, apf)) { DHD_ERROR(("%s: firmware doesn't support APF\n", __FUNCTION__)); - - /* - * Notify Android framework that APF is not supported by setting - * version as zero. - */ + /* Notify Android framework that APF is not supported by setting version as zero. */ *version = 0; return BCME_OK; } @@ -20374,11 +17087,10 @@ dhd_dev_apf_get_version(struct net_device *ndev, uint32 *version) return -ENODEV; } - ret = dhd_wl_ioctl_get_intiovar(dhdp, "apf_ver", version, - WLC_GET_VAR, FALSE, ifidx); + ret = dhd_wl_ioctl_get_intiovar(dhdp, "apf_ver", version, WLC_GET_VAR, FALSE, ifidx); if (unlikely(ret)) { - DHD_ERROR(("%s: failed to get APF version, ret=%d\n", - __FUNCTION__, ret)); + DHD_ERROR(("%s: failed to get APF version, ret=%d\n", __FUNCTION__, ret)); + return ret; } return ret; @@ -20403,11 +17115,10 @@ dhd_dev_apf_get_max_len(struct net_device *ndev, uint32 *max_len) return -ENODEV; } - ret = dhd_wl_ioctl_get_intiovar(dhdp, "apf_size_limit", max_len, - WLC_GET_VAR, FALSE, ifidx); + ret = dhd_wl_ioctl_get_intiovar(dhdp, "apf_size_limit", max_len, WLC_GET_VAR, FALSE, ifidx); if (unlikely(ret)) { - DHD_ERROR(("%s: failed to get APF size limit, ret=%d\n", - __FUNCTION__, ret)); + DHD_ERROR(("%s: failed to get APF size limit, ret=%d\n", __FUNCTION__, ret)); + return ret; } return ret; @@ -20425,23 +17136,30 @@ dhd_dev_apf_add_filter(struct net_device *ndev, u8* program, /* delete, if filter already exists */ if (dhdp->apf_set) { - ret = __dhd_apf_delete_filter(ndev, PKT_FILTER_APF_ID); + ret = _dhd_apf_delete_filter(ndev, PKT_FILTER_APF_ID); if (unlikely(ret)) { goto exit; } dhdp->apf_set = FALSE; } - ret = __dhd_apf_add_filter(ndev, PKT_FILTER_APF_ID, program, program_len); + ret = _dhd_apf_add_filter(ndev, PKT_FILTER_APF_ID, program, program_len); if (ret) { goto exit; } dhdp->apf_set = TRUE; if (dhdp->in_suspend && dhdp->apf_set && !(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) { - /* Driver is still in (early) suspend state, enable APF filter back */ - ret = __dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, + /* Driver is still in (early) suspend state and during this time Android + * framework updated the filter program. As there will not be another + * early suspend notification, enable back the APF filter with the new + * filter program to avoid unnecessary host wake-ups. + */ + ret = _dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, PKT_FILTER_MODE_FORWARD_ON_MATCH, TRUE); + if (ret) { + goto exit; + } } exit: DHD_APF_UNLOCK(ndev); @@ -20458,12 +17176,13 @@ dhd_dev_apf_enable_filter(struct net_device *ndev) bool nan_dp_active = false; DHD_APF_LOCK(ndev); + #ifdef WL_NAN nan_dp_active = wl_cfgnan_is_dp_active(ndev); #endif /* WL_NAN */ - if (dhdp->apf_set && (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) && - !nan_dp_active)) { - ret = __dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, + + if (dhdp->apf_set && (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) && !nan_dp_active)) { + ret = _dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, PKT_FILTER_MODE_FORWARD_ON_MATCH, TRUE); } @@ -20482,7 +17201,7 @@ dhd_dev_apf_disable_filter(struct net_device *ndev) DHD_APF_LOCK(ndev); if (dhdp->apf_set) { - ret = __dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, + ret = _dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, PKT_FILTER_MODE_FORWARD_ON_MATCH, FALSE); } @@ -20501,7 +17220,7 @@ dhd_dev_apf_delete_filter(struct net_device *ndev) DHD_APF_LOCK(ndev); if (dhdp->apf_set) { - ret = __dhd_apf_delete_filter(ndev, PKT_FILTER_APF_ID); + ret = _dhd_apf_delete_filter(ndev, PKT_FILTER_APF_ID); if (!ret) { dhdp->apf_set = FALSE; } @@ -20511,7 +17230,54 @@ dhd_dev_apf_delete_filter(struct net_device *ndev) return ret; } -#endif /* PKT_FILTER_SUPPORT && APF */ + +int +dhd_dev_apf_read_filter_data(struct net_device *ndev, u8* buf, uint32 buf_len) +{ + dhd_info_t *dhd = DHD_DEV_INFO(ndev); + dhd_pub_t *dhdp = &dhd->pub; + int ret = 0; + bool apf_disabled = FALSE; + + DHD_APF_LOCK(ndev); + + if (!dhdp->apf_set) { + DHD_ERROR(("%s: APF filter is not programmed\n", __FUNCTION__)); + goto exit; + } + + /* As per the requirement, APF filter needs to be stopped while reading the filter data. + * Otherwise the APF counters could be wrong. Therefore disable the APF filter, if driver + * is in (early) suspend state. + */ + if (dhdp->in_suspend) { + ret = _dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, + PKT_FILTER_MODE_FORWARD_ON_MATCH, FALSE); + if (unlikely(ret)) { + DHD_ERROR(("%s: failed to disable APF filter, ret=%d\n", + __FUNCTION__, ret)); + goto exit; + } + apf_disabled = TRUE; + } + + ret = _dhd_apf_read_filter_data(ndev, PKT_FILTER_APF_ID, buf, buf_len); + if (unlikely(ret)) { + goto exit; + } + +exit: + /* Re-enable the filter if got disabled above */ + if (apf_disabled && _dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, + PKT_FILTER_MODE_FORWARD_ON_MATCH, TRUE)) { + DHD_ERROR(("%s: failed to enable APF filter, ret=%d\n", __FUNCTION__, ret)); + } + + DHD_APF_UNLOCK(ndev); + + return ret; +} +#endif /* APF */ #if defined(OEM_ANDROID) static void dhd_hang_process(struct work_struct *work_data) @@ -20522,34 +17288,64 @@ static void dhd_hang_process(struct work_struct *work_data) uint8 i = 0; #endif /* IFACE_HANG_FORCE_DEV_CLOSE */ struct dhd_info *dhd; + dhd_pub_t *dhdp; +#ifdef WL_CFG80211 + struct bcm_cfg80211 *cfg; +#endif /* WL_CFG80211 */ + /* Ignore compiler warnings due to -Werror=cast-qual */ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); dhd = container_of(work_data, dhd_info_t, dhd_hang_process_work); GCC_DIAGNOSTIC_POP(); + dhdp = &dhd->pub; - if (!dhd || !dhd->iflist[0]) + dev = dhd_linux_get_primary_netdev(dhdp); + + if (!dev) { + DHD_ERROR(("%s: Cannot find primary netdev\n", __FUNCTION__)); + dhdp->hang_was_sent = 0; return; - dev = dhd->iflist[0]->net; - - if (dev) { + } +#ifdef WL_CFG80211 + cfg = wl_get_cfg(dev); + if (!cfg) { + DHD_ERROR(("%s: Cannot find cfg\n", __FUNCTION__)); + dhdp->hang_was_sent = 0; + return; + } + /* Skip sending HANG event to framework if driver is not ready */ + if (!wl_get_drv_status(cfg, READY, dev)) { + DHD_ERROR(("%s: device is not ready\n", __FUNCTION__)); + dhdp->hang_was_sent = 0; + return; + } +#endif /* WL_CFG80211 */ #if defined(WL_WIRELESS_EXT) - wl_iw_send_priv_event(dev, "HANG"); + wl_iw_send_priv_event(dev, "HANG"); #endif #if defined(WL_CFG80211) - wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); + wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); #endif - } + #ifdef IFACE_HANG_FORCE_DEV_CLOSE /* - * For HW2, dev_close need to be done to recover - * from upper layer after hang. For Interposer skip - * dev_close so that dhd iovars can be used to take - * socramdump after crash, also skip for HW4 as - * handling of hang event is different + * In case of wif scan only mode, upper layer doesn't handle hang + * So dev_close need to be called explicitly */ +#ifdef HANG_DELAY_BEFORE_DEV_CLOSE + { + int wait_cnt = WAIT_FOR_DEV_CLOSE_MAX; + while (dev && (dev->flags & IFF_UP) && (wait_cnt > 0)) { + wait_cnt--; + OSL_SLEEP(10); + } + DHD_ERROR(("dev->name : %s wait for interface down done, wait_cnt:%d\n", + ((dev == NULL) ? "null" : dev->name), wait_cnt)); + } +#endif /* HANG_DELAY_BEFORE_DEV_CLOSE */ rtnl_lock(); - for (i = 0; i < DHD_MAX_IFS; i++) { + for (i = 0; i < DHD_MAX_IFS && dhd; i++) { ndev = dhd->iflist[i] ? dhd->iflist[i]->net : NULL; if (ndev && (ndev->flags & IFF_UP)) { DHD_ERROR(("ndev->name : %s dev close\n", @@ -20576,17 +17372,14 @@ void dhd_host_recover_link(void) EXPORT_SYMBOL(dhd_host_recover_link); #endif /* CONFIG_ARCH_EXYNOS && BCMPCIE */ -#ifdef DHD_DETECT_CONSECUTIVE_MFG_HANG -#define MAX_CONSECUTIVE_MFG_HANG_COUNT 2 -#endif /* DHD_DETECT_CONSECUTIVE_MFG_HANG */ +/* + * Note that this function should be called in both interrupt and process context + * Therefore, Keep it simple, and use workqueue for complex/time-consuming work + */ int dhd_os_send_hang_message(dhd_pub_t *dhdp) { int ret = 0; dhd_info_t *dhd_info = NULL; -#ifdef WL_CFG80211 - struct net_device *primary_ndev; - struct bcm_cfg80211 *cfg; -#endif /* WL_CFG80211 */ if (!dhdp) { DHD_ERROR(("%s: dhdp is null\n", __FUNCTION__)); @@ -20595,7 +17388,15 @@ int dhd_os_send_hang_message(dhd_pub_t *dhdp) dhd_info = (dhd_info_t *)dhdp->info; BCM_REFERENCE(dhd_info); - +#ifdef DHD_FW_COREDUMP + if (dhdp->memdump_enabled == DUMP_MEMFILE_BUGON && + (dhdp->hang_reason == HANG_REASON_PCIE_LINK_DOWN_RC_DETECT || + dhdp->hang_reason == HANG_REASON_PCIE_LINK_DOWN_EP_DETECT)) { + DHD_ERROR(("%s: BUG_ON for pcie link down memdump_enabled:%d\n", + __FUNCTION__, dhdp->memdump_enabled)); + BUG_ON(1); + } +#endif /* DHD_FW_COREDUMP */ #if defined(WLAN_ACCEL_BOOT) if (!dhd_info->wl_accel_force_reg_on) { DHD_ERROR(("%s: set force reg on\n", __FUNCTION__)); @@ -20608,32 +17409,18 @@ int dhd_os_send_hang_message(dhd_pub_t *dhdp) return BCME_ERROR; } -#if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT) + if (dhdp->stop_in_progress) { + DHD_ERROR(("%s: dhd_stop in progress\n", __FUNCTION__)); + return BCME_OK; + } + +#if defined(WL_CFG80211) && (defined(DHD_FILE_DUMP_EVENT) || defined(DHD_COREDUMP)) if (dhd_info->scheduled_memdump) { DHD_ERROR_RLMT(("[DUMP]:%s, memdump in progress. return\n", __FUNCTION__)); dhdp->hang_was_pending = 1; return BCME_OK; } -#endif /* WL_CFG80211 && DHD_FILE_DUMP_EVENT */ - -#ifdef WL_CFG80211 - primary_ndev = dhd_linux_get_primary_netdev(dhdp); - if (!primary_ndev) { - DHD_ERROR(("%s: Cannot find primary netdev\n", __FUNCTION__)); - return -ENODEV; - } - cfg = wl_get_cfg(primary_ndev); - if (!cfg) { - DHD_ERROR(("%s: Cannot find cfg\n", __FUNCTION__)); - return -EINVAL; - } - - /* Skip sending HANG event to framework if driver is not ready */ - if (!wl_get_drv_status(cfg, READY, primary_ndev)) { - DHD_ERROR(("%s: device is not ready\n", __FUNCTION__)); - return -ENODEV; - } -#endif /* WL_CFG80211 */ +#endif /* WL_CFG80211 && (DHD_FILE_DUMP_EVENT || DHD_COREDUMP) */ #if defined(DHD_HANG_SEND_UP_TEST) if (dhdp->req_hang_type) { @@ -20686,11 +17473,12 @@ int net_os_send_hang_message(struct net_device *dev) /* Report FW problem when enabled */ if (dhd->pub.hang_report) { #ifdef BT_OVER_SDIO - if (netif_running(dev)) { + if (netif_running(dev)) #endif /* BT_OVER_SDIO */ + { ret = dhd_os_send_hang_message(&dhd->pub); -#ifdef BT_OVER_SDIO } +#ifdef BT_OVER_SDIO DHD_ERROR(("%s: HANG -> Reset BT\n", __FUNCTION__)); bcmsdh_btsdio_process_dhd_hang_notification(!netif_running(dev)); #endif /* BT_OVER_SDIO */ @@ -20745,10 +17533,15 @@ int dhd_wifi_platform_set_power(dhd_pub_t *pub, bool on) bool dhd_force_country_change(struct net_device *dev) { +#if defined(CUSTOM_FORCE_NODFS_FLAG) && defined(CUSTOM_COUNTRY_CODE) dhd_info_t *dhd = DHD_DEV_INFO(dev); - if (dhd && dhd->pub.up) - return dhd->pub.force_country_change; + if (dhd && dhd->pub.up && dhd->pub.force_country_change) { + DHD_ERROR(("force country change\n")); + return TRUE; + } +#endif /* CUSTOM_FORCE_NODFS_FLAG && CUSTOM_COUNTRY_CODE */ + DHD_ERROR(("skip force country change\n")); return FALSE; } @@ -20769,8 +17562,11 @@ void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_c } #if defined(DHD_BLOB_EXISTENCE_CHECK) && !defined(CUSTOM_COUNTRY_CODE) else { - /* Replace the ccode to XZ if ccode is undefined country */ - if (strncmp(country_iso_code, "", WLC_CNTRY_BUF_SZ) == 0) { + /* Replace the ccode to XZ if ccode is undefined country or world + * domain + */ + if ((strncmp(country_iso_code, "", WLC_CNTRY_BUF_SZ) == 0) || + (strncmp(country_iso_code, "00", WLC_CNTRY_BUF_SZ) == 0)) { strlcpy(country_iso_code, "XZ", WLC_CNTRY_BUF_SZ); strlcpy(cspec->country_abbrev, country_iso_code, WLC_CNTRY_BUF_SZ); strlcpy(cspec->ccode, country_iso_code, WLC_CNTRY_BUF_SZ); @@ -20809,6 +17605,7 @@ void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notif if (dhd && dhd->pub.up) { memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); + dhd->pub.force_country_change = FALSE; #ifdef WL_CFG80211 wl_update_wiphybands(cfg, notify); #endif @@ -20861,6 +17658,18 @@ void dhd_net_if_unlock(struct net_device *dev) dhd_net_if_unlock_local(dhd); } +bool dhd_net_if_locked(struct net_device *dev) +{ + bool locked = FALSE; + + dhd_info_t *dhd = DHD_DEV_INFO(dev); + if (dhd) { + if (mutex_is_locked(&dhd->dhd_net_if_mutex)) + locked = TRUE; + } + return locked; +} + static void dhd_net_if_lock_local(dhd_info_t *dhd) { #if defined(OEM_ANDROID) @@ -20916,29 +17725,6 @@ void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags) } } -void * -dhd_os_dbgring_lock_init(osl_t *osh) -{ - struct mutex *mtx = NULL; - - mtx = MALLOCZ(osh, sizeof(*mtx)); - if (mtx) - mutex_init(mtx); - - return mtx; -} - -void -dhd_os_dbgring_lock_deinit(osl_t *osh, void *mutex) -{ - struct mutex *mtx = mutex; - - if (mtx) { - mutex_destroy(mtx); - MFREE(osh, mtx, sizeof(struct mutex)); - } -} - static int dhd_get_pend_8021x_cnt(dhd_info_t *dhd) { @@ -20977,37 +17763,33 @@ int write_file(const char * file_name, uint32 flags, uint8 *buf, int size) { int ret = 0; struct file *fp = NULL; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs mm_segment_t old_fs; -#endif +#endif /* get_fs */ loff_t pos = 0; +#ifdef get_fs /* change to KERNEL_DS address limit */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) old_fs = get_fs(); set_fs(KERNEL_DS); -#endif +#endif /* get_fs */ /* open file to write */ - fp = filp_open(file_name, flags, 0664); - if (IS_ERR(fp)) { + fp = dhd_filp_open(file_name, flags, 0664); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("open file error, err = %ld\n", PTR_ERR(fp))); goto exit; } /* Write buf to file */ - ret = vfs_write(fp, buf, size, &pos); + ret = dhd_vfs_write(fp, buf, size, &pos); if (ret < 0) { DHD_ERROR(("write file error, err = %d\n", ret)); goto exit; } /* Sync file from filesystem to physical media */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) - ret = vfs_fsync(fp, 0); -#else - ret = vfs_fsync(fp, fp->f_path.dentry, 0); -#endif + ret = dhd_vfs_fsync(fp, 0); if (ret < 0) { DHD_ERROR(("sync file error, error = %d\n", ret)); goto exit; @@ -21017,140 +17799,18 @@ int write_file(const char * file_name, uint32 flags, uint8 *buf, int size) exit: /* close file before return */ if (!IS_ERR(fp)) - filp_close(fp, current->files); + dhd_filp_close(fp, current->files); +#ifdef get_fs /* restore previous address limit */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) set_fs(old_fs); -#endif +#endif /* get_fs */ return ret; } #endif /* BCM_ROUTER_DHD || DHD_DEBUG */ #ifdef DHD_DEBUG -static void -dhd_convert_memdump_type_to_str(uint32 type, char *buf, size_t buf_len, int substr_type) -{ - char *type_str = NULL; - - switch (type) { - case DUMP_TYPE_RESUMED_ON_TIMEOUT: - type_str = "resumed_on_timeout"; - break; - case DUMP_TYPE_D3_ACK_TIMEOUT: - type_str = "D3_ACK_timeout"; - break; - case DUMP_TYPE_DONGLE_TRAP: - type_str = "Dongle_Trap"; - break; - case DUMP_TYPE_MEMORY_CORRUPTION: - type_str = "Memory_Corruption"; - break; - case DUMP_TYPE_PKTID_AUDIT_FAILURE: - type_str = "PKTID_AUDIT_Fail"; - break; - case DUMP_TYPE_PKTID_INVALID: - type_str = "PKTID_INVALID"; - break; - case DUMP_TYPE_SCAN_TIMEOUT: - type_str = "SCAN_timeout"; - break; - case DUMP_TYPE_SCAN_BUSY: - type_str = "SCAN_Busy"; - break; - case DUMP_TYPE_BY_SYSDUMP: - if (substr_type == CMD_UNWANTED) { - type_str = "BY_SYSDUMP_FORUSER_unwanted"; - } else if (substr_type == CMD_DISCONNECTED) { - type_str = "BY_SYSDUMP_FORUSER_disconnected"; - } else { - type_str = "BY_SYSDUMP_FORUSER"; - } - break; - case DUMP_TYPE_BY_LIVELOCK: - type_str = "BY_LIVELOCK"; - break; - case DUMP_TYPE_AP_LINKUP_FAILURE: - type_str = "BY_AP_LINK_FAILURE"; - break; - case DUMP_TYPE_AP_ABNORMAL_ACCESS: - type_str = "INVALID_ACCESS"; - break; - case DUMP_TYPE_RESUMED_ON_TIMEOUT_RX: - type_str = "ERROR_RX_TIMED_OUT"; - break; - case DUMP_TYPE_RESUMED_ON_TIMEOUT_TX: - type_str = "ERROR_TX_TIMED_OUT"; - break; - case DUMP_TYPE_CFG_VENDOR_TRIGGERED: - type_str = "CFG_VENDOR_TRIGGERED"; - break; - case DUMP_TYPE_RESUMED_ON_INVALID_RING_RDWR: - type_str = "BY_INVALID_RING_RDWR"; - break; - case DUMP_TYPE_IFACE_OP_FAILURE: - type_str = "BY_IFACE_OP_FAILURE"; - break; - case DUMP_TYPE_TRANS_ID_MISMATCH: - type_str = "BY_TRANS_ID_MISMATCH"; - break; -#ifdef DEBUG_DNGL_INIT_FAIL - case DUMP_TYPE_DONGLE_INIT_FAILURE: - type_str = "DONGLE_INIT_FAIL"; - break; -#endif /* DEBUG_DNGL_INIT_FAIL */ -#ifdef SUPPORT_LINKDOWN_RECOVERY - case DUMP_TYPE_READ_SHM_FAIL: - type_str = "READ_SHM_FAIL"; - break; -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - case DUMP_TYPE_DONGLE_HOST_EVENT: - type_str = "BY_DONGLE_HOST_EVENT"; - break; - case DUMP_TYPE_SMMU_FAULT: - type_str = "SMMU_FAULT"; - break; -#ifdef DHD_ERPOM - case DUMP_TYPE_DUE_TO_BT: - type_str = "DUE_TO_BT"; - break; -#endif /* DHD_ERPOM */ - case DUMP_TYPE_BY_USER: - type_str = "BY_USER"; - break; - case DUMP_TYPE_LOGSET_BEYOND_RANGE: - type_str = "LOGSET_BEYOND_RANGE"; - break; - case DUMP_TYPE_CTO_RECOVERY: - type_str = "CTO_RECOVERY"; - break; - case DUMP_TYPE_SEQUENTIAL_PRIVCMD_ERROR: - type_str = "SEQUENTIAL_PRIVCMD_ERROR"; - break; - case DUMP_TYPE_PROXD_TIMEOUT: - type_str = "PROXD_TIMEOUT"; - break; - case DUMP_TYPE_INBAND_DEVICE_WAKE_FAILURE: - type_str = "INBAND_DEVICE_WAKE_FAILURE"; - break; - case DUMP_TYPE_PKTID_POOL_DEPLETED: - type_str = "PKTID_POOL_DEPLETED"; - break; - case DUMP_TYPE_ESCAN_SYNCID_MISMATCH: - type_str = "ESCAN_SYNCID_MISMATCH"; - break; - case DUMP_TYPE_INVALID_SHINFO_NRFRAGS: - type_str = "INVALID_SHINFO_NRFRAGS"; - break; - default: - type_str = "Unknown_type"; - break; - } - - strlcpy(buf, type_str, buf_len); -} - void dhd_get_memdump_filename(struct net_device *ndev, char *memdump_path, int len, char *fname) { @@ -21161,10 +17821,12 @@ dhd_get_memdump_filename(struct net_device *ndev, char *memdump_path, int len, c /* Init file name */ memset(memdump_path, 0, len); memset(memdump_type, 0, DHD_MEMDUMP_TYPE_STR_LEN); +#ifdef DHD_LOG_DUMP dhd_convert_memdump_type_to_str(dhdp->memdump_type, memdump_type, DHD_MEMDUMP_TYPE_STR_LEN, dhdp->debug_dump_subcmd); clear_debug_dump_time(dhdp->debug_dump_time_str); get_debug_dump_time(dhdp->debug_dump_time_str); +#endif /* DHD_LOG_DUMP */ snprintf(memdump_path, len, "%s%s_%s_" "%s", DHD_COMMON_DUMP_PATH, fname, memdump_type, dhdp->debug_dump_time_str); @@ -21187,16 +17849,16 @@ write_dump_to_file(dhd_pub_t *dhd, uint8 *buf, int size, char *fname) /* Init file name */ memset(memdump_path, 0, DHD_MEMDUMP_PATH_STR_LEN); memset(memdump_type, 0, DHD_MEMDUMP_TYPE_STR_LEN); +#ifdef DHD_LOG_DUMP dhd_convert_memdump_type_to_str(dhd->memdump_type, memdump_type, DHD_MEMDUMP_TYPE_STR_LEN, dhd->debug_dump_subcmd); clear_debug_dump_time(dhd->debug_dump_time_str); get_debug_dump_time(dhd->debug_dump_time_str); +#endif /* DHD_LOG_DUMP */ snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_" "%s", DHD_COMMON_DUMP_PATH, fname, memdump_type, dhd->debug_dump_time_str); -#ifdef CUSTOMER_HW4_DEBUG - file_mode = O_CREAT | O_WRONLY | O_SYNC; -#elif defined(CUSTOMER_HW2) || defined(BOARD_HIKEY) +#if defined(BOARD_HIKEY) file_mode = O_CREAT | O_WRONLY | O_SYNC; #elif defined(OEM_ANDROID) && defined(__ARM_ARCH_7A__) file_mode = O_CREAT | O_WRONLY; @@ -21209,19 +17871,19 @@ write_dump_to_file(dhd_pub_t *dhd, uint8 *buf, int size, char *fname) */ file_mode = O_CREAT | O_WRONLY | O_SYNC; { - struct file *fp = filp_open(memdump_path, file_mode, 0664); + struct file *fp = dhd_filp_open(memdump_path, file_mode, 0664); /* Check if it is live Brix image having /installmedia, else use /data */ - if (IS_ERR(fp)) { + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("open file %s, try /data/\n", memdump_path)); snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_" "%s", "/data/", fname, memdump_type, dhd->debug_dump_time_str); } else { - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); } } #else file_mode = O_CREAT | O_WRONLY; -#endif /* CUSTOMER_HW4_DEBUG */ +#endif /* BOARD_HIKEY */ /* print SOCRAM dump file path */ DHD_ERROR(("%s: file_path = %s\n", __FUNCTION__, memdump_path)); @@ -21254,11 +17916,15 @@ int dhd_os_wake_lock_timeout(dhd_pub_t *pub) ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ? dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable; #ifdef CONFIG_HAS_WAKELOCK +#ifdef DHD_DEBUG_WAKE_LOCK + printf("%s: rx_timeout=%dms, ctrl_timeout=%dms\n", __FUNCTION__, + dhd->wakelock_rx_timeout_enable, dhd->wakelock_ctrl_timeout_enable); +#endif if (dhd->wakelock_rx_timeout_enable) - dhd_wake_lock_timeout(&dhd->wl_rxwake, + dhd_wake_lock_timeout(dhd->wl_rxwake, msecs_to_jiffies(dhd->wakelock_rx_timeout_enable)); if (dhd->wakelock_ctrl_timeout_enable) - dhd_wake_lock_timeout(&dhd->wl_ctrlwake, + dhd_wake_lock_timeout(dhd->wl_ctrlwake, msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable)); #endif dhd->wakelock_rx_timeout_enable = 0; @@ -21278,20 +17944,6 @@ int net_os_wake_lock_timeout(struct net_device *dev) return ret; } -int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - - if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { - DHD_WAKE_SPIN_LOCK(&dhd->wakelock_spinlock, flags); - if (val > dhd->wakelock_rx_timeout_enable) - dhd->wakelock_rx_timeout_enable = val; - DHD_WAKE_SPIN_UNLOCK(&dhd->wakelock_spinlock, flags); - } - return 0; -} - int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val) { dhd_info_t *dhd = (dhd_info_t *)(pub->info); @@ -21315,24 +17967,14 @@ int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub) DHD_WAKE_SPIN_LOCK(&dhd->wakelock_spinlock, flags); dhd->wakelock_ctrl_timeout_enable = 0; #ifdef CONFIG_HAS_WAKELOCK - if (dhd_wake_lock_active(&dhd->wl_ctrlwake)) - dhd_wake_unlock(&dhd->wl_ctrlwake); + if (dhd_wake_lock_active(dhd->wl_ctrlwake)) + dhd_wake_unlock(dhd->wl_ctrlwake); #endif DHD_WAKE_SPIN_UNLOCK(&dhd->wakelock_spinlock, flags); } return 0; } -int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val); - return ret; -} - int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val) { dhd_info_t *dhd = DHD_DEV_INFO(dev); @@ -21346,33 +17988,15 @@ int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val) #if defined(DHD_TRACE_WAKE_LOCK) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) #include -#else -#include -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) /* Define 2^5 = 32 bucket size hash table */ DEFINE_HASHTABLE(wklock_history, 5); #else +#include /* Define 2^5 = 32 bucket size hash table */ struct hlist_head wklock_history[32] = { [0 ... 31] = HLIST_HEAD_INIT }; #endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ atomic_t trace_wklock_onoff; -typedef enum dhd_wklock_type { - DHD_WAKE_LOCK, - DHD_WAKE_UNLOCK, - DHD_WAIVE_LOCK, - DHD_RESTORE_LOCK -} dhd_wklock_t; - -struct wk_trace_record { - unsigned long addr; /* Address of the instruction */ - dhd_wklock_t lock_type; /* lock_type */ - unsigned long long counter; /* counter information */ - struct hlist_node wklock_node; /* hash node */ -}; - static struct wk_trace_record *find_wklock_entry(unsigned long addr) { struct wk_trace_record *wklock_info; @@ -21394,48 +18018,6 @@ static struct wk_trace_record *find_wklock_entry(unsigned long addr) return NULL; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) -#define HASH_ADD(hashtable, node, key) \ - do { \ - hash_add(hashtable, node, key); \ - } while (0); -#else -#define HASH_ADD(hashtable, node, key) \ - do { \ - int index = hash_long(key, ilog2(ARRAY_SIZE(hashtable))); \ - hlist_add_head(node, &hashtable[index]); \ - } while (0); -#endif /* KERNEL_VER < KERNEL_VERSION(3, 7, 0) */ - -#define STORE_WKLOCK_RECORD(wklock_type) \ - do { \ - struct wk_trace_record *wklock_info = NULL; \ - unsigned long func_addr = (unsigned long)__builtin_return_address(0); \ - wklock_info = find_wklock_entry(func_addr); \ - if (wklock_info) { \ - if (wklock_type == DHD_WAIVE_LOCK || wklock_type == DHD_RESTORE_LOCK) { \ - wklock_info->counter = dhd->wakelock_counter; \ - } else { \ - wklock_info->counter++; \ - } \ - } else { \ - wklock_info = kzalloc(sizeof(*wklock_info), GFP_ATOMIC); \ - if (!wklock_info) {\ - printk("Can't allocate wk_trace_record \n"); \ - } else { \ - wklock_info->addr = func_addr; \ - wklock_info->lock_type = wklock_type; \ - if (wklock_type == DHD_WAIVE_LOCK || \ - wklock_type == DHD_RESTORE_LOCK) { \ - wklock_info->counter = dhd->wakelock_counter; \ - } else { \ - wklock_info->counter++; \ - } \ - HASH_ADD(wklock_history, &wklock_info->wklock_node, func_addr); \ - } \ - } \ - } while (0); - static inline void dhd_wk_lock_rec_dump(void) { int bkt; @@ -21536,8 +18118,6 @@ void dhd_wk_lock_stats_dump(dhd_pub_t *dhdp) DHD_WAKE_SPIN_UNLOCK(&dhd->wakelock_spinlock, flags); } -#else -#define STORE_WKLOCK_RECORD(wklock_type) #endif /* ! DHD_TRACE_WAKE_LOCK */ int dhd_os_wake_lock(dhd_pub_t *pub) @@ -21550,7 +18130,7 @@ int dhd_os_wake_lock(dhd_pub_t *pub) DHD_WAKE_SPIN_LOCK(&dhd->wakelock_spinlock, flags); if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { #ifdef CONFIG_HAS_WAKELOCK - dhd_wake_lock(&dhd->wl_wifi); + dhd_wake_lock(dhd->wl_wifi); #elif defined(BCMSDIO) dhd_bus_dev_pm_stay_awake(pub); #endif @@ -21574,7 +18154,7 @@ void dhd_event_wake_lock(dhd_pub_t *pub) if (dhd) { #ifdef CONFIG_HAS_WAKELOCK - dhd_wake_lock(&dhd->wl_evtwake); + dhd_wake_lock(dhd->wl_evtwake); #elif defined(BCMSDIO) dhd_bus_dev_pm_stay_awake(pub); #endif @@ -21588,19 +18168,7 @@ dhd_pm_wake_lock_timeout(dhd_pub_t *pub, int val) dhd_info_t *dhd = (dhd_info_t *)(pub->info); if (dhd) { - dhd_wake_lock_timeout(&dhd->wl_pmwake, msecs_to_jiffies(val)); - } -#endif /* CONFIG_HAS_WAKE_LOCK */ -} - -void -dhd_txfl_wake_lock_timeout(dhd_pub_t *pub, int val) -{ -#ifdef CONFIG_HAS_WAKELOCK - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - dhd_wake_lock_timeout(&dhd->wl_txflwake, msecs_to_jiffies(val)); + dhd_wake_lock_timeout(dhd->wl_pmwake, msecs_to_jiffies(val)); } #endif /* CONFIG_HAS_WAKE_LOCK */ } @@ -21612,7 +18180,7 @@ dhd_nan_wake_lock_timeout(dhd_pub_t *pub, int val) dhd_info_t *dhd = (dhd_info_t *)(pub->info); if (dhd) { - dhd_wake_lock_timeout(&dhd->wl_nanwake, msecs_to_jiffies(val)); + dhd_wake_lock_timeout(dhd->wl_nanwake, msecs_to_jiffies(val)); } #endif /* CONFIG_HAS_WAKE_LOCK */ } @@ -21646,7 +18214,7 @@ int dhd_os_wake_unlock(dhd_pub_t *pub) #endif /* DHD_TRACE_WAKE_LOCK */ if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { #ifdef CONFIG_HAS_WAKELOCK - dhd_wake_unlock(&dhd->wl_wifi); + dhd_wake_unlock(dhd->wl_wifi); #elif defined(BCMSDIO) dhd_bus_dev_pm_relax(pub); #endif @@ -21664,7 +18232,7 @@ void dhd_event_wake_unlock(dhd_pub_t *pub) if (dhd) { #ifdef CONFIG_HAS_WAKELOCK - dhd_wake_unlock(&dhd->wl_evtwake); + dhd_wake_unlock(dhd->wl_evtwake); #elif defined(BCMSDIO) dhd_bus_dev_pm_relax(pub); #endif @@ -21678,8 +18246,8 @@ void dhd_pm_wake_unlock(dhd_pub_t *pub) if (dhd) { /* if wl_pmwake is active, unlock it */ - if (dhd_wake_lock_active(&dhd->wl_pmwake)) { - dhd_wake_unlock(&dhd->wl_pmwake); + if (dhd_wake_lock_active(dhd->wl_pmwake)) { + dhd_wake_unlock(dhd->wl_pmwake); } } #endif /* CONFIG_HAS_WAKELOCK */ @@ -21692,8 +18260,8 @@ void dhd_txfl_wake_unlock(dhd_pub_t *pub) if (dhd) { /* if wl_txflwake is active, unlock it */ - if (dhd_wake_lock_active(&dhd->wl_txflwake)) { - dhd_wake_unlock(&dhd->wl_txflwake); + if (dhd_wake_lock_active(dhd->wl_txflwake)) { + dhd_wake_unlock(dhd->wl_txflwake); } } #endif /* CONFIG_HAS_WAKELOCK */ @@ -21706,8 +18274,8 @@ void dhd_nan_wake_unlock(dhd_pub_t *pub) if (dhd) { /* if wl_nanwake is active, unlock it */ - if (dhd_wake_lock_active(&dhd->wl_nanwake)) { - dhd_wake_unlock(&dhd->wl_nanwake); + if (dhd_wake_lock_active(dhd->wl_nanwake)) { + dhd_wake_unlock(dhd->wl_nanwake); } } #endif /* CONFIG_HAS_WAKELOCK */ @@ -21732,8 +18300,8 @@ int dhd_os_check_wakelock(dhd_pub_t *pub) #ifdef CONFIG_HAS_WAKELOCK c = dhd->wakelock_counter; - l1 = dhd_wake_lock_active(&dhd->wl_wifi); - l2 = dhd_wake_lock_active(&dhd->wl_wdwake); + l1 = dhd_wake_lock_active(dhd->wl_wifi); + l2 = dhd_wake_lock_active(dhd->wl_wdwake); lock_active = (l1 || l2); /* Indicate to the SD Host to avoid going to suspend if internal locks are up */ if (lock_active) { @@ -21776,27 +18344,34 @@ dhd_os_check_wakelock_all(dhd_pub_t *pub) #ifdef CONFIG_HAS_WAKELOCK c = dhd->wakelock_counter; - l1 = dhd_wake_lock_active(&dhd->wl_wifi); - l2 = dhd_wake_lock_active(&dhd->wl_wdwake); - l3 = dhd_wake_lock_active(&dhd->wl_rxwake); - l4 = dhd_wake_lock_active(&dhd->wl_ctrlwake); - l7 = dhd_wake_lock_active(&dhd->wl_evtwake); + l1 = dhd_wake_lock_active(dhd->wl_wifi); + l2 = dhd_wake_lock_active(dhd->wl_wdwake); + l3 = dhd_wake_lock_active(dhd->wl_rxwake); + l4 = dhd_wake_lock_active(dhd->wl_ctrlwake); + l7 = dhd_wake_lock_active(dhd->wl_evtwake); #ifdef BCMPCIE_OOB_HOST_WAKE - l5 = dhd_wake_lock_active(&dhd->wl_intrwake); + l5 = dhd_wake_lock_active(dhd->wl_intrwake); #endif /* BCMPCIE_OOB_HOST_WAKE */ #ifdef DHD_USE_SCAN_WAKELOCK - l6 = dhd_wake_lock_active(&dhd->wl_scanwake); + l6 = dhd_wake_lock_active(dhd->wl_scanwake); #endif /* DHD_USE_SCAN_WAKELOCK */ - l8 = dhd_wake_lock_active(&dhd->wl_pmwake); - l9 = dhd_wake_lock_active(&dhd->wl_txflwake); - l10 = dhd_wake_lock_active(&dhd->wl_nanwake); + l8 = dhd_wake_lock_active(dhd->wl_pmwake); + l9 = dhd_wake_lock_active(dhd->wl_txflwake); + l10 = dhd_wake_lock_active(dhd->wl_nanwake); lock_active = (l1 || l2 || l3 || l4 || l5 || l6 || l7 || l8 || l9 || l10); /* Indicate to the Host to avoid going to suspend if internal locks are up */ + DHD_ERROR(("%s wakelock c-%d wl-%d wd-%d rx-%d " + "ctl-%d intr-%d scan-%d evt-%d, pm-%d, txfl-%d nan-%d\n", + __FUNCTION__, c, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10)); if (lock_active) { - DHD_ERROR(("%s wakelock c-%d wl-%d wd-%d rx-%d " - "ctl-%d intr-%d scan-%d evt-%d, pm-%d, txfl-%d nan-%d\n", - __FUNCTION__, c, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10)); +#ifdef RPM_FAST_TRIGGER + if (pub->rpm_fast_trigger && l4) { + DHD_ERROR(("%s : reset rpm_fast_trigger becasue of wl_ctrlwake activated\n", + __FUNCTION__)); + pub->rpm_fast_trigger = FALSE; + } +#endif /* RPM_FAST_TRIGGER */ return 1; } #elif defined(BCMSDIO) @@ -21829,7 +18404,7 @@ int dhd_os_wd_wake_lock(dhd_pub_t *pub) if (dhd->wakelock_wd_counter == 0 && !dhd->waive_wakelock) { #ifdef CONFIG_HAS_WAKELOCK /* if wakelock_wd_counter was never used : lock it at once */ - dhd_wake_lock(&dhd->wl_wdwake); + dhd_wake_lock(dhd->wl_wdwake); #endif } dhd->wakelock_wd_counter++; @@ -21851,7 +18426,7 @@ int dhd_os_wd_wake_unlock(dhd_pub_t *pub) dhd->wakelock_wd_counter = 0; if (!dhd->waive_wakelock) { #ifdef CONFIG_HAS_WAKELOCK - dhd_wake_unlock(&dhd->wl_wdwake); + dhd_wake_unlock(dhd->wl_wdwake); #endif } } @@ -21864,16 +18439,13 @@ int dhd_os_wd_wake_unlock(dhd_pub_t *pub) void dhd_os_oob_irq_wake_lock_timeout(dhd_pub_t *pub, int val) { +#ifdef CONFIG_HAS_WAKELOCK dhd_info_t *dhd = (dhd_info_t *)(pub->info); if (dhd) { -#ifdef CONFIG_HAS_WAKELOCK - dhd_wake_lock_timeout(&dhd->wl_intrwake, msecs_to_jiffies(val)); -#else - printk("%s: =========\n",__FUNCTION__); - wake_lock_timeout(&dhd->rx_wakelock, 5*HZ); -#endif /* CONFIG_HAS_WAKELOCK */ + dhd_wake_lock_timeout(dhd->wl_intrwake, msecs_to_jiffies(val)); } +#endif /* CONFIG_HAS_WAKELOCK */ } void @@ -21884,8 +18456,8 @@ dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub) if (dhd) { /* if wl_intrwake is active, unlock it */ - if (dhd_wake_lock_active(&dhd->wl_intrwake)) { - dhd_wake_unlock(&dhd->wl_intrwake); + if (dhd_wake_lock_active(dhd->wl_intrwake)) { + dhd_wake_unlock(dhd->wl_intrwake); } } #endif /* CONFIG_HAS_WAKELOCK */ @@ -21900,7 +18472,7 @@ dhd_os_scan_wake_lock_timeout(dhd_pub_t *pub, int val) dhd_info_t *dhd = (dhd_info_t *)(pub->info); if (dhd) { - dhd_wake_lock_timeout(&dhd->wl_scanwake, msecs_to_jiffies(val)); + dhd_wake_lock_timeout(dhd->wl_scanwake, msecs_to_jiffies(val)); } #endif /* CONFIG_HAS_WAKELOCK */ } @@ -21913,8 +18485,8 @@ dhd_os_scan_wake_unlock(dhd_pub_t *pub) if (dhd) { /* if wl_scanwake is active, unlock it */ - if (dhd_wake_lock_active(&dhd->wl_scanwake)) { - dhd_wake_unlock(&dhd->wl_scanwake); + if (dhd_wake_lock_active(dhd->wl_scanwake)) { + dhd_wake_unlock(dhd->wl_scanwake); } } #endif /* CONFIG_HAS_WAKELOCK */ @@ -21980,13 +18552,13 @@ int dhd_os_wake_lock_restore(dhd_pub_t *pub) if (dhd->wakelock_before_waive == 0 && dhd->wakelock_counter > 0) { #ifdef CONFIG_HAS_WAKELOCK - dhd_wake_lock(&dhd->wl_wifi); + dhd_wake_lock(dhd->wl_wifi); #elif defined(BCMSDIO) dhd_bus_dev_pm_stay_awake(&dhd->pub); #endif } else if (dhd->wakelock_before_waive > 0 && dhd->wakelock_counter == 0) { #ifdef CONFIG_HAS_WAKELOCK - dhd_wake_unlock(&dhd->wl_wifi); + dhd_wake_unlock(dhd->wl_wifi); #elif defined(BCMSDIO) dhd_bus_dev_pm_relax(&dhd->pub); #endif @@ -22006,24 +18578,23 @@ void dhd_os_wake_lock_init(struct dhd_info *dhd) dhd->wakelock_ctrl_timeout_enable = 0; /* wakelocks prevent a system from going into a low power state */ #ifdef CONFIG_HAS_WAKELOCK - // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry - dhd_wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); - dhd_wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake"); - dhd_wake_lock_init(&dhd->wl_evtwake, WAKE_LOCK_SUSPEND, "wlan_evt_wake"); - dhd_wake_lock_init(&dhd->wl_pmwake, WAKE_LOCK_SUSPEND, "wlan_pm_wake"); - dhd_wake_lock_init(&dhd->wl_txflwake, WAKE_LOCK_SUSPEND, "wlan_txfl_wake"); + dhd_wake_lock_init(dhd->wl_wifi, dhd_bus_to_dev(dhd->pub.bus), "wlan_wake"); + dhd_wake_lock_init(dhd->wl_rxwake, dhd_bus_to_dev(dhd->pub.bus), "wlan_rx_wake"); + dhd_wake_lock_init(dhd->wl_ctrlwake, dhd_bus_to_dev(dhd->pub.bus), "wlan_ctrl_wake"); + dhd_wake_lock_init(dhd->wl_evtwake, dhd_bus_to_dev(dhd->pub.bus), "wlan_evt_wake"); + dhd_wake_lock_init(dhd->wl_pmwake, dhd_bus_to_dev(dhd->pub.bus), "wlan_pm_wake"); + dhd_wake_lock_init(dhd->wl_txflwake, dhd_bus_to_dev(dhd->pub.bus), "wlan_txfl_wake"); #ifdef BCMPCIE_OOB_HOST_WAKE - dhd_wake_lock_init(&dhd->wl_intrwake, WAKE_LOCK_SUSPEND, "wlan_oob_irq_wake"); + dhd_wake_lock_init(dhd->wl_intrwake, dhd_bus_to_dev(dhd->pub.bus), "wlan_oob_irq_wake"); #endif /* BCMPCIE_OOB_HOST_WAKE */ #ifdef DHD_USE_SCAN_WAKELOCK - dhd_wake_lock_init(&dhd->wl_scanwake, WAKE_LOCK_SUSPEND, "wlan_scan_wake"); + dhd_wake_lock_init(dhd->wl_scanwake, dhd_bus_to_dev(dhd->pub.bus), "wlan_scan_wake"); #endif /* DHD_USE_SCAN_WAKELOCK */ - dhd_wake_lock_init(&dhd->wl_nanwake, WAKE_LOCK_SUSPEND, "wlan_nan_wake"); + dhd_wake_lock_init(dhd->wl_nanwake, dhd_bus_to_dev(dhd->pub.bus), "wlan_nan_wake"); #endif /* CONFIG_HAS_WAKELOCK */ #ifdef DHD_TRACE_WAKE_LOCK dhd_wk_lock_trace_init(dhd); #endif /* DHD_TRACE_WAKE_LOCK */ - wake_lock_init(&dhd->rx_wakelock, WAKE_LOCK_SUSPEND, "wlan_rx_wakelock"); } void dhd_os_wake_lock_destroy(struct dhd_info *dhd) @@ -22033,19 +18604,19 @@ void dhd_os_wake_lock_destroy(struct dhd_info *dhd) dhd->wakelock_counter = 0; dhd->wakelock_rx_timeout_enable = 0; dhd->wakelock_ctrl_timeout_enable = 0; - // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry - dhd_wake_lock_unlock_destroy(&dhd->wl_rxwake); - dhd_wake_lock_unlock_destroy(&dhd->wl_ctrlwake); - dhd_wake_lock_unlock_destroy(&dhd->wl_evtwake); - dhd_wake_lock_unlock_destroy(&dhd->wl_pmwake); - dhd_wake_lock_unlock_destroy(&dhd->wl_txflwake); + dhd_wake_lock_destroy(dhd->wl_wifi); + dhd_wake_lock_destroy(dhd->wl_rxwake); + dhd_wake_lock_destroy(dhd->wl_ctrlwake); + dhd_wake_lock_destroy(dhd->wl_evtwake); + dhd_wake_lock_destroy(dhd->wl_pmwake); + dhd_wake_lock_destroy(dhd->wl_txflwake); #ifdef BCMPCIE_OOB_HOST_WAKE - dhd_wake_lock_unlock_destroy(&dhd->wl_intrwake); + dhd_wake_lock_destroy(dhd->wl_intrwake); #endif /* BCMPCIE_OOB_HOST_WAKE */ #ifdef DHD_USE_SCAN_WAKELOCK - dhd_wake_lock_unlock_destroy(&dhd->wl_scanwake); + dhd_wake_lock_destroy(dhd->wl_scanwake); #endif /* DHD_USE_SCAN_WAKELOCK */ - dhd_wake_lock_unlock_destroy(&dhd->wl_nanwake); + dhd_wake_lock_destroy(dhd->wl_nanwake); #ifdef DHD_TRACE_WAKE_LOCK dhd_wk_lock_trace_deinit(dhd); #endif /* DHD_TRACE_WAKE_LOCK */ @@ -22056,7 +18627,6 @@ void dhd_os_wake_lock_destroy(struct dhd_info *dhd) while (dhd_os_wake_unlock(&dhd->pub)); } #endif /* CONFIG_HAS_WAKELOCK */ - wake_lock_destroy(&dhd->rx_wakelock); } bool dhd_os_check_if_up(dhd_pub_t *pub) @@ -22081,9 +18651,13 @@ void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) if (!dhdp) return; - i = snprintf(&info_string[i], sizeof(info_string) - i, + i += snprintf(&info_string[i], sizeof(info_string) - i, "\n%s Chip: %x Rev %x", DHD_LOG_PREFIXS, dhd_conf_get_chip(dhdp), dhd_conf_get_chiprev(dhdp)); +#if defined(USE_CID_CHECK) + i += snprintf(&info_string[i], sizeof(info_string) - i, + " VID %x", cur_vid_info); +#endif /* USE_CID_CHECK */ } int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) @@ -22400,7 +18974,7 @@ void dhd_set_cpucore(dhd_pub_t *dhd, int set) return; } - if (DPC_CPUCORE) { + if (DPC_CPUCORE && dhd->current_dpc) { do { if (set == TRUE) { e_dpc = set_cpus_allowed_ptr(dhd->current_dpc, @@ -22417,7 +18991,7 @@ void dhd_set_cpucore(dhd_pub_t *dhd, int set) OSL_SLEEP(1); } while (e_dpc < 0); } - if (RXF_CPUCORE) { + if (RXF_CPUCORE && dhd->current_rxf) { do { if (set == TRUE) { e_rxf = set_cpus_allowed_ptr(dhd->current_rxf, @@ -22439,48 +19013,6 @@ void dhd_set_cpucore(dhd_pub_t *dhd, int set) return; } #endif /* CUSTOM_SET_CPUCORE */ -#if defined(DHD_TCP_WINSIZE_ADJUST) -static int dhd_port_list_match(int port) -{ - int i; - for (i = 0; i < MAX_TARGET_PORTS; i++) { - if (target_ports[i] == port) - return 1; - } - return 0; -} -static void dhd_adjust_tcp_winsize(int op_mode, struct sk_buff *skb) -{ - struct iphdr *ipheader; - struct tcphdr *tcpheader; - uint16 win_size; - int32 incremental_checksum; - - if (!(op_mode & DHD_FLAG_HOSTAP_MODE)) - return; - if (skb == NULL || skb->data == NULL) - return; - - ipheader = (struct iphdr*)(skb->data); - - if (ipheader->protocol == IPPROTO_TCP) { - tcpheader = (struct tcphdr*) skb_pull(skb, (ipheader->ihl)<<2); - if (tcpheader) { - win_size = ntoh16(tcpheader->window); - if (win_size < MIN_TCP_WIN_SIZE && - dhd_port_list_match(ntoh16(tcpheader->dest))) { - incremental_checksum = ntoh16(tcpheader->check); - incremental_checksum += win_size - win_size*WIN_SIZE_SCALE_FACTOR; - if (incremental_checksum < 0) - --incremental_checksum; - tcpheader->window = hton16(win_size*WIN_SIZE_SCALE_FACTOR); - tcpheader->check = hton16((unsigned short)incremental_checksum); - } - } - skb_push(skb, (ipheader->ihl)<<2); - } -} -#endif /* DHD_TCP_WINSIZE_ADJUST */ #ifdef DHD_MCAST_REGEN /* Get interface specific ap_isolate configuration */ @@ -22545,164 +19077,12 @@ int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val) return 0; } -#ifdef DHD_RND_DEBUG -/* - * XXX The filename to store .rnd.(in/out) is defined for each platform. - * - The default path of CUSTOMER_HW4 device is "PLATFORM_PATH/.memdump.info" - * - Brix platform will take default path "/installmedia/.memdump.info" - * New platforms can add their ifdefs accordingly below. - */ - -#ifdef CUSTOMER_HW4_DEBUG -#define RNDINFO PLATFORM_PATH".rnd" -#elif defined(CUSTOMER_HW2) || defined(BOARD_HIKEY) -#define RNDINFO "/data/misc/wifi/.rnd" -#elif defined(OEM_ANDROID) && defined(__ARM_ARCH_7A__) -#define RNDINFO "/data/misc/wifi/.rnd" -#elif defined(OEM_ANDROID) -#define RNDINFO_LIVE "/installmedia/.rnd" -#define RNDINFO_INST "/data/.rnd" -#define RNDINFO RNDINFO_LIVE -#else /* FC19 and Others */ -#define RNDINFO "/root/.rnd" -#endif /* CUSTOMER_HW4_DEBUG */ - -#define RND_IN RNDINFO".in" -#define RND_OUT RNDINFO".out" - -int -dhd_get_rnd_info(dhd_pub_t *dhd) -{ - struct file *fp = NULL; - int ret = BCME_ERROR; - char *filepath = RND_IN; - uint32 file_mode = O_RDONLY; - mm_segment_t old_fs; - loff_t pos = 0; - - /* Read memdump info from the file */ - fp = filp_open(filepath, file_mode, 0); - if (IS_ERR(fp)) { - DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); -#if defined(CONFIG_X86) && defined(OEM_ANDROID) - /* Check if it is Live Brix Image */ - if (bcmstrstr(filepath, RNDINFO_LIVE)) { - goto err1; - } - /* Try if it is Installed Brix Image */ - filepath = RNDINFO_INST".in"; - DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath)); - fp = filp_open(filepath, file_mode, 0); - if (IS_ERR(fp)) { - DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); - goto err1; - } -#else /* Non Brix Android platform */ - goto err1; -#endif /* CONFIG_X86 && OEM_ANDROID */ - } - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - /* Handle success case */ - ret = vfs_read(fp, (char *)&dhd->rnd_len, sizeof(dhd->rnd_len), &pos); - if (ret < 0) { - DHD_ERROR(("%s: rnd_len read error, ret=%d\n", __FUNCTION__, ret)); - goto err2; - } - - dhd->rnd_buf = MALLOCZ(dhd->osh, dhd->rnd_len); - if (!dhd->rnd_buf) { - DHD_ERROR(("%s: MALLOC failed\n", __FUNCTION__)); - goto err2; - } - - ret = vfs_read(fp, (char *)dhd->rnd_buf, dhd->rnd_len, &pos); - if (ret < 0) { - DHD_ERROR(("%s: rnd_buf read error, ret=%d\n", __FUNCTION__, ret)); - goto err3; - } - - set_fs(old_fs); - filp_close(fp, NULL); - - DHD_ERROR(("%s: RND read from %s\n", __FUNCTION__, filepath)); - return BCME_OK; - -err3: - MFREE(dhd->osh, dhd->rnd_buf, dhd->rnd_len); - dhd->rnd_buf = NULL; -err2: - set_fs(old_fs); - filp_close(fp, NULL); -err1: - return BCME_ERROR; -} - -int -dhd_dump_rnd_info(dhd_pub_t *dhd, uint8 *rnd_buf, uint32 rnd_len) -{ - struct file *fp = NULL; - int ret = BCME_OK; - char *filepath = RND_OUT; - uint32 file_mode = O_CREAT | O_WRONLY | O_SYNC; - mm_segment_t old_fs; - loff_t pos = 0; - - /* Read memdump info from the file */ - fp = filp_open(filepath, file_mode, 0664); - if (IS_ERR(fp)) { - DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); -#if defined(CONFIG_X86) && defined(OEM_ANDROID) - /* Check if it is Live Brix Image */ - if (bcmstrstr(filepath, RNDINFO_LIVE)) { - goto err1; - } - /* Try if it is Installed Brix Image */ - filepath = RNDINFO_INST".out"; - DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath)); - fp = filp_open(filepath, file_mode, 0664); - if (IS_ERR(fp)) { - DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); - goto err1; - } -#else /* Non Brix Android platform */ - goto err1; -#endif /* CONFIG_X86 && OEM_ANDROID */ - } - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - /* Handle success case */ - ret = vfs_write(fp, (char *)&rnd_len, sizeof(rnd_len), &pos); - if (ret < 0) { - DHD_ERROR(("%s: rnd_len write error, ret=%d\n", __FUNCTION__, ret)); - goto err2; - } - - ret = vfs_write(fp, (char *)rnd_buf, rnd_len, &pos); - if (ret < 0) { - DHD_ERROR(("%s: rnd_buf write error, ret=%d\n", __FUNCTION__, ret)); - goto err2; - } - - set_fs(old_fs); - filp_close(fp, NULL); - DHD_ERROR(("%s: RND written to %s\n", __FUNCTION__, filepath)); - return BCME_OK; - -err2: - set_fs(old_fs); - filp_close(fp, NULL); -err1: - return BCME_ERROR; - -} -#endif /* DHD_RND_DEBUG */ - #ifdef DHD_FW_COREDUMP +bool dhd_memdump_is_scheduled(dhd_pub_t *dhdp) +{ + return dhdp->info->scheduled_memdump; +} + void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size) { dhd_dump_t *dump = NULL; @@ -22735,18 +19115,16 @@ void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size) #endif /* !DHD_DUMP_FILE_WRITE_FROM_KERNEL */ #endif /* DHD_LOG_DUMP */ - if (dhdp->memdump_enabled == DUMP_MEMONLY) { - BUG_ON(1); - } - if ((dhdp->memdump_type == DUMP_TYPE_DONGLE_INIT_FAILURE) || (dhdp->memdump_type == DUMP_TYPE_DUE_TO_BT) || - (dhdp->memdump_type == DUMP_TYPE_SMMU_FAULT)) + (dhdp->memdump_type == DUMP_TYPE_SMMU_FAULT) || + (dhdp->memdump_type == DUMP_TYPE_DONGLE_TRAP_DURING_WIFI_ONOFF)) { dhd_info->scheduled_memdump = FALSE; dhd_mem_dump((void *)dhdp->info, (void *)dump, 0); /* No need to collect debug dump for init failure */ - if (dhdp->memdump_type == DUMP_TYPE_DONGLE_INIT_FAILURE) { + if (dhdp->memdump_type == DUMP_TYPE_DONGLE_INIT_FAILURE || + dhdp->memdump_type == DUMP_TYPE_DONGLE_TRAP_DURING_WIFI_ONOFF) { return; } #ifdef DHD_LOG_DUMP @@ -22779,6 +19157,21 @@ void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size) dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dump, DHD_WQ_WORK_SOC_RAM_DUMP, dhd_mem_dump, DHD_WQ_WORK_PRIORITY_HIGH); } +#ifdef DHD_SSSR_DUMP +#define DUMP_SSSR_DUMP_MAX_COUNT 8 +#endif +#ifdef DHD_COREDUMP +#ifdef DHD_LINUX_STD_FW_API +char map_path[PATH_MAX] = DHD_MAP_NAME; +#else +#ifndef CONFIG_BCMDHD_MAP_PATH +char map_path[PATH_MAX] = PLATFORM_PATH"rtecdc.map"; +#else +char map_path[PATH_MAX] = VENDOR_PATH CONFIG_BCMDHD_MAP_PATH; +#endif /* CONFIG_BCMDHD_MAP_PATH */ +#endif /* DHD_LINUX_STD_FW_API */ +extern int dhd_collect_coredump(dhd_pub_t *dhdp, dhd_dump_t *dump); +#endif /* DHD_COREDUMP */ static void dhd_mem_dump(void *handle, void *event_info, u8 event) @@ -22786,17 +19179,23 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) dhd_info_t *dhd = handle; dhd_pub_t *dhdp = NULL; unsigned long flags = 0; +#if defined(DHD_LOG_DUMP) +#if defined(DHD_FILE_DUMP_EVENT) || defined(DHD_DEBUGABILITY_DEBUG_DUMP) + log_dump_type_t type = DLD_BUF_TYPE_ALL; +#endif /* DHD_FILE_DUMP_EVENT || DHD_DEBUGABILITY_DEBUG_DUMP */ +#endif /* DHD_LOG_DUMP */ -#if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT) +#if defined(DHD_FILE_DUMP_EVENT) || (defined(DHD_SSSR_COREDUMP) && \ + defined(DHD_COREDUMP)) int ret = 0; -#endif /* WL_CFG80211 && DHD_FILE_DUMP_EVENT */ +#endif /* DHD_FILE_DUMP_EVENT || DHD_SSSR_COREDUMP && DHD_COREDUMP */ dhd_dump_t *dump = NULL; #ifdef DHD_COREDUMP char pc_fn[DHD_FUNC_STR_LEN] = "\0"; char lr_fn[DHD_FUNC_STR_LEN] = "\0"; - char *map_path = VENDOR_PATH CONFIG_BCMDHD_MAP_PATH; trap_t *tr; #endif /* DHD_COREDUMP */ + uint32 memdump_type; DHD_ERROR(("%s: ENTER \n", __FUNCTION__)); @@ -22810,6 +19209,8 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); return; } + /* to keep it in case other memdump overwrites it */ + memdump_type = dhdp->memdump_type; DHD_GENERAL_LOCK(dhdp, flags); if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp)) { @@ -22825,17 +19226,12 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) goto exit; } -#ifdef DHD_SDTC_ETB_DUMP - if (dhdp->collect_sdtc) { - dhd_sdtc_etb_dump(dhdp); - dhdp->collect_sdtc = FALSE; - } -#endif /* DHD_SDTC_ETB_DUMP */ - #ifdef DHD_SSSR_DUMP DHD_ERROR(("%s: sssr_enab=%d dhdp->sssr_inited=%d dhdp->collect_sssr=%d\n", __FUNCTION__, sssr_enab, dhdp->sssr_inited, dhdp->collect_sssr)); if (sssr_enab && dhdp->sssr_inited && dhdp->collect_sssr) { + uint32 arr_len[DUMP_SSSR_DUMP_MAX_COUNT]; + if (fis_enab && dhdp->sssr_reg_info->rev3.fis_enab) { int bcmerror = dhd_bus_fis_trigger(dhdp); @@ -22850,40 +19246,104 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) __FUNCTION__, fis_enab, dhdp->sssr_reg_info->rev3.fis_enab)); dhdpcie_sssr_dump(dhdp); } +#ifndef DHD_FIS_DUMP + /* Reset fis_enab flag after fis collection which was set for init failure debug */ + fis_enab = FALSE; +#endif /* DHD_FIS_DUMP */ + /* Print sssr buffer address for debugging */ + if (dhdp->sssr_dump_collected) { + dhdpcie_sssr_dump_get_before_after_len(dhdp, arr_len); + } } - dhdp->collect_sssr = FALSE; #endif /* DHD_SSSR_DUMP */ -#if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT) +#ifdef DHD_SDTC_ETB_DUMP + if (dhdp->collect_sdtc) { + dhd_sdtc_etb_dump(dhdp); + dhdp->collect_sdtc = FALSE; + } +#endif /* DHD_SDTC_ETB_DUMP */ + +#if (defined(DHD_FILE_DUMP_EVENT) || defined(DHD_DEBUGABILITY_DEBUG_DUMP)) + if (dhdp->memdump_enabled == DUMP_MEMONLY) { + DHD_ERROR(("%s: Force BUG_ON for memdump_enabled:%d\n", + __FUNCTION__, dhdp->memdump_enabled)); + BUG_ON(1); + } + +#ifdef DHD_LOG_DUMP + if (dhd_log_flush(dhdp, &type) < 0) { + DHD_ERROR(("%s: Failed to flush Preserve/FW logs\n", + __FUNCTION__)); + } +#endif /* DHD_LOG_DUMP */ + +#if defined(DHD_FILE_DUMP_EVENT) ret = dhd_wait_for_file_dump(dhdp); -#ifdef BOARD_HIKEY - /* For Hikey do force kernel write of socram if HAL dump fails */ if (ret) { + DHD_ERROR(("%s: file_dump failed.\n", __FUNCTION__)); +#ifdef BOARD_HIKEY + /* For Hikey do force kernel write of socram if HAL dump fails */ if (write_dump_to_file(&dhd->pub, dump->buf, dump->bufsize, "mem_dump")) { DHD_ERROR(("%s: writing SoC_RAM dump to the file failed\n", __FUNCTION__)); } - } #endif /* BOARD_HIKEY */ -#endif /* WL_CFG80211 && DHD_FILE_DUMP_EVENT */ + } + dhdp->skip_memdump_map_read = FALSE; +#elif defined(DHD_DEBUGABILITY_DEBUG_DUMP) + dhd_debug_dump_to_ring(dhdp); +#endif /* DHD_FILE_DUMP_EVENT */ +#endif /* (DHD_FILE_DUMP_EVENT || DHD_DEBUGABILITY_DEBUG_DUMP) */ #ifdef DHD_COREDUMP memset_s(dhdp->memdump_str, DHD_MEMDUMP_LONGSTR_LEN, 0, DHD_MEMDUMP_LONGSTR_LEN); - dhd_convert_memdump_type_to_str(dhdp->memdump_type, dhdp->memdump_str, + + if (dhdp->dsack_hc_due_to_isr_delay) { + memdump_type = DUMP_TYPE_BY_DSACK_HC_DUE_TO_ISR_DELAY; + } else if (dhdp->dsack_hc_due_to_dpc_delay) { + memdump_type = DUMP_TYPE_BY_DSACK_HC_DUE_TO_DPC_DELAY; + } + +#ifdef DHD_LOG_DUMP + dhd_convert_memdump_type_to_str(memdump_type, dhdp->memdump_str, DHD_MEMDUMP_LONGSTR_LEN, dhdp->debug_dump_subcmd); - if (dhdp->memdump_type == DUMP_TYPE_DONGLE_TRAP && +#endif /* DHD_LOG_DUMP */ + + if (memdump_type == DUMP_TYPE_DONGLE_TRAP && dhdp->dongle_trap_occured == TRUE) { - tr = &dhdp->last_trap_info; - dhd_lookup_map(dhdp->osh, map_path, - ltoh32(tr->epc), pc_fn, ltoh32(tr->r14), lr_fn); - sprintf(&dhdp->memdump_str[strlen(dhdp->memdump_str)], "_%.79s_%.79s", - pc_fn, lr_fn); + if (!dhdp->dsack_hc_due_to_isr_delay && + !dhdp->dsack_hc_due_to_dpc_delay) { + tr = &dhdp->last_trap_info; + dhd_lookup_map(dhdp->osh, map_path, + ltoh32(tr->epc), pc_fn, ltoh32(tr->r14), lr_fn); + sprintf(&dhdp->memdump_str[strlen(dhdp->memdump_str)], + "_%.79s_%.79s", pc_fn, lr_fn); + } } DHD_ERROR(("%s: dump reason: %s\n", __FUNCTION__, dhdp->memdump_str)); - if (wifi_platform_set_coredump(dhd->adapter, dump->buf, dump->bufsize, dhdp->memdump_str)) { - DHD_ERROR(("%s: writing SoC_RAM dump failed\n", __FUNCTION__)); + +#ifdef DHD_SSSR_COREDUMP + ret = dhd_collect_coredump(dhdp, dump); + if (ret == BCME_ERROR) { + DHD_ERROR(("%s: dhd_collect_coredump() failed.\n", __FUNCTION__)); + goto exit; + } else if (ret == BCME_UNSUPPORTED) { + DHD_LOG_MEM(("%s: Unable to collect SSSR dumps. Skip it.\n", + __FUNCTION__)); + } +#endif /* DHD_SSSR_COREDUMP */ + if (memdump_type == DUMP_TYPE_BY_SYSDUMP) { + DHD_LOG_MEM(("%s: coredump is not supported for BY_SYSDUMP/non trap cases\n", + __FUNCTION__)); + } else { + DHD_ERROR(("%s: writing SoC_RAM dump\n", __FUNCTION__)); + if (wifi_platform_set_coredump(dhd->adapter, dump->buf, + dump->bufsize, dhdp->memdump_str)) { + DHD_ERROR(("%s: writing SoC_RAM dump failed\n", __FUNCTION__)); #ifdef DHD_DEBUG_UART - dhd->pub.memdump_success = FALSE; + dhd->pub.memdump_success = FALSE; #endif /* DHD_DEBUG_UART */ + } } #endif /* DHD_COREDUMP */ @@ -22921,9 +19381,9 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) } } -#ifndef DHD_PKT_LOGGING +#if !defined(DHD_PKT_LOGGING) && defined(DHD_LOG_DUMP) clear_debug_dump_time(dhdp->debug_dump_time_str); -#endif /* !DHD_PKT_LOGGING */ +#endif /* !DHD_PKT_LOGGING && DHD_LOG_DUMP */ /* directly call dhd_log_dump for debug_dump collection from the mem_dump work queue * context, no need to schedule another work queue for log dump. In case of @@ -22934,7 +19394,7 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) */ #ifdef DHD_LOG_DUMP if (dhd->scheduled_memdump && - dhdp->memdump_type != DUMP_TYPE_BY_SYSDUMP) { + memdump_type != DUMP_TYPE_BY_SYSDUMP) { log_dump_type_t *flush_type = MALLOCZ(dhdp->osh, sizeof(log_dump_type_t)); if (flush_type) { @@ -22969,31 +19429,22 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) #endif /* DHD_DUMP_FILE_WRITE_FROM_KERNEL */ if (dhd->pub.memdump_enabled == DUMP_MEMFILE_BUGON && -#ifdef WLAN_ACCEL_BOOT - /* BUG_ON only if wlan accel boot up is done */ - dhd->wl_accel_boot_on_done == TRUE && -#endif /* WLAN_ACCEL_BOOT */ #ifdef DHD_LOG_DUMP - dhd->pub.memdump_type != DUMP_TYPE_BY_SYSDUMP && + memdump_type != DUMP_TYPE_BY_SYSDUMP && #endif /* DHD_LOG_DUMP */ - dhd->pub.memdump_type != DUMP_TYPE_BY_USER && + memdump_type != DUMP_TYPE_BY_USER && #ifdef DHD_DEBUG_UART dhd->pub.memdump_success == TRUE && #endif /* DHD_DEBUG_UART */ #ifdef DNGL_EVENT_SUPPORT - dhd->pub.memdump_type != DUMP_TYPE_DONGLE_HOST_EVENT && + memdump_type != DUMP_TYPE_DONGLE_HOST_EVENT && #endif /* DNGL_EVENT_SUPPORT */ - dhd->pub.memdump_type != DUMP_TYPE_CFG_VENDOR_TRIGGERED) { + memdump_type != DUMP_TYPE_CFG_VENDOR_TRIGGERED) { #ifdef SHOW_LOGTRACE /* Wait till logtrace context is flushed */ dhd_flush_logtrace_process(dhd); #endif /* SHOW_LOGTRACE */ -#ifdef BTLOG - /* Wait till bt_log_dispatcher_work finishes */ - cancel_work_sync(&dhd->bt_log_dispatcher_work); -#endif /* BTLOG */ - #ifdef EWP_EDL cancel_delayed_work_sync(&dhd->edl_dispatcher_work); #endif @@ -23001,7 +19452,11 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) printf("%s\n", info_string); printf("MAC %pM\n", &dhdp->mac); DHD_ERROR(("%s: call BUG_ON \n", __FUNCTION__)); +#ifdef DHD_USE_WARN_RATHER_THAN_BUG_ON + WARN_ON(1); +#else // DHD_USE_WARN_RATHER_THAN_BUG_ON // BUG_ON(1); +#endif // DHD_USE_WARN_RATHER_THAN_BUG_ON } exit: @@ -23428,7 +19883,6 @@ dhd_sdtc_etb_dump(dhd_pub_t *dhd) etb_info_t etb_info; uint8 *sdtc_etb_dump; uint8 *sdtc_etb_mempool; - uint etb_dump_len; int ret = 0; if (!dhd->sdtc_etb_inited) { @@ -23443,6 +19897,12 @@ dhd_sdtc_etb_dump(dhd_pub_t *dhd) return; } + if (etb_info.addr == (uint32)-1) { + DHD_ERROR(("%s: invalid etbinfo.addr 0x%x Hence donot collect SDTC ETB\n", + __FUNCTION__, etb_info.addr)); + return; + } + if (etb_info.read_bytes == 0) { DHD_ERROR(("%s ETB is of zero size. Hence donot collect SDTC ETB\n", __FUNCTION__)); return; @@ -23456,10 +19916,10 @@ dhd_sdtc_etb_dump(dhd_pub_t *dhd) /* * etb mempool format = etb_info + etb */ - etb_dump_len = etb_info.read_bytes + sizeof(etb_info); - if (etb_dump_len > DHD_SDTC_ETB_MEMPOOL_SIZE) { + dhd->sdtc_etb_dump_len = etb_info.read_bytes + sizeof(etb_info); + if (dhd->sdtc_etb_dump_len > DHD_SDTC_ETB_MEMPOOL_SIZE) { DHD_ERROR(("%s etb_dump_len: %d is more than the alloced %d.Hence cannot collect\n", - __FUNCTION__, etb_dump_len, DHD_SDTC_ETB_MEMPOOL_SIZE)); + __FUNCTION__, dhd->sdtc_etb_dump_len, DHD_SDTC_ETB_MEMPOOL_SIZE)); return; } sdtc_etb_mempool = dhd->sdtc_etb_mempool; @@ -23470,1371 +19930,40 @@ dhd_sdtc_etb_dump(dhd_pub_t *dhd) return; } + dhd_print_buf_addr(dhd, "sdtc_etb_dump", (uint8 *)sdtc_etb_mempool, dhd->sdtc_etb_dump_len); + /* + * If kernel does not have file write access enabled + * then skip writing dumps to files. + * The dumps will be pushed to HAL layer which will + * write into files + */ +#ifdef DHD_DUMP_FILE_WRITE_FROM_KERNEL if (write_dump_to_file(dhd, (uint8 *)sdtc_etb_mempool, - etb_dump_len, "sdtc_etb_dump")) { + dhd->sdtc_etb_dump_len, "sdtc_etb_dump")) { DHD_ERROR(("%s: failed to dump sdtc_etb to file\n", __FUNCTION__)); } +#endif /* DHD_DUMP_FILE_WRITE_FROM_KERNEL */ +} + +int +dhd_sdtc_etb_hal_file_dump(void *dev, const void *user_buf, uint32 len) +{ + dhd_info_t *dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); + dhd_pub_t *dhdp = &dhd_info->pub; + int pos = 0, ret = BCME_ERROR; + + if (dhdp->sdtc_etb_dump_len) { + ret = dhd_export_debug_data((char *)dhdp->sdtc_etb_mempool, + NULL, user_buf, dhdp->sdtc_etb_dump_len, &pos); + } else { + DHD_ERROR(("%s ETB is of zero size. Hence donot collect SDTC ETB\n", __FUNCTION__)); + } + DHD_ERROR(("%s, done ret: %d\n", __FUNCTION__, ret)); + return ret; } #endif /* DHD_SDTC_ETB_DUMP */ -#ifdef DHD_LOG_DUMP -static void -dhd_log_dump(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - log_dump_type_t *type = (log_dump_type_t *)event_info; - - if (!dhd || !type) { - DHD_ERROR(("%s: dhd/type is NULL\n", __FUNCTION__)); - return; - } - -#ifdef WL_CFG80211 - /* flush the fw preserve logs */ - wl_flush_fw_log_buffer(dhd_linux_get_primary_netdev(&dhd->pub), - FW_LOGSET_MASK_ALL); -#endif - - /* there are currently 3 possible contexts from which - * log dump can be scheduled - - * 1.TRAP 2.supplicant DEBUG_DUMP pvt driver command - * 3.HEALTH CHECK event - * The concise debug info buffer is a shared resource - * and in case a trap is one of the contexts then both the - * scheduled work queues need to run because trap data is - * essential for debugging. Hence a mutex lock is acquired - * before calling do_dhd_log_dump(). - */ - DHD_ERROR(("%s: calling log dump.. \n", __FUNCTION__)); - dhd_os_logdump_lock(&dhd->pub); - DHD_OS_WAKE_LOCK(&dhd->pub); - if (do_dhd_log_dump(&dhd->pub, type) != BCME_OK) { - DHD_ERROR(("%s: writing debug dump to the file failed\n", __FUNCTION__)); - } - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_os_logdump_unlock(&dhd->pub); -} - -void dhd_schedule_log_dump(dhd_pub_t *dhdp, void *type) -{ - DHD_ERROR(("%s: scheduling log dump.. \n", __FUNCTION__)); - - dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, - type, DHD_WQ_WORK_DHD_LOG_DUMP, - dhd_log_dump, DHD_WQ_WORK_PRIORITY_HIGH); -} - -static void -dhd_print_buf_addr(dhd_pub_t *dhdp, char *name, void *buf, unsigned int size) -{ -#ifdef DHD_FW_COREDUMP - if ((dhdp->memdump_enabled == DUMP_MEMONLY) || - (dhdp->memdump_enabled == DUMP_MEMFILE_BUGON) || - (dhdp->memdump_type == DUMP_TYPE_SMMU_FAULT) || -#ifdef DHD_DETECT_CONSECUTIVE_MFG_HANG - (dhdp->op_mode & DHD_FLAG_MFG_MODE && - (dhdp->hang_count >= MAX_CONSECUTIVE_MFG_HANG_COUNT-1)) || -#endif /* DHD_DETECT_CONSECUTIVE_MFG_HANG */ - FALSE) -#else - if (dhdp->memdump_type == DUMP_TYPE_SMMU_FAULT) -#endif - { -#if defined(CONFIG_ARM64) - DHD_ERROR(("-------- %s: buf(va)=%llx, buf(pa)=%llx, bufsize=%d\n", - name, (uint64)buf, (uint64)__virt_to_phys((ulong)buf), size)); -#elif defined(__ARM_ARCH_7A__) - DHD_ERROR(("-------- %s: buf(va)=%x, buf(pa)=%x, bufsize=%d\n", - name, (uint32)buf, (uint32)__virt_to_phys((ulong)buf), size)); -#endif /* __ARM_ARCH_7A__ */ - } -} - -static void -dhd_log_dump_buf_addr(dhd_pub_t *dhdp, log_dump_type_t *type) -{ - int i; - unsigned long wr_size = 0; - struct dhd_log_dump_buf *dld_buf = &g_dld_buf[0]; - size_t log_size = 0; - char buf_name[DHD_PRINT_BUF_NAME_LEN]; - dhd_dbg_ring_t *ring = NULL; - - BCM_REFERENCE(ring); - - for (i = 0; i < DLD_BUFFER_NUM; i++) { - dld_buf = &g_dld_buf[i]; - log_size = (unsigned long)dld_buf->max - - (unsigned long)dld_buf->buffer; - if (dld_buf->wraparound) { - wr_size = log_size; - } else { - wr_size = (unsigned long)dld_buf->present - - (unsigned long)dld_buf->front; - } - scnprintf(buf_name, sizeof(buf_name), "dlb_buf[%d]", i); - dhd_print_buf_addr(dhdp, buf_name, dld_buf, dld_buf_size[i]); - scnprintf(buf_name, sizeof(buf_name), "dlb_buf[%d] buffer", i); - dhd_print_buf_addr(dhdp, buf_name, dld_buf->buffer, wr_size); - scnprintf(buf_name, sizeof(buf_name), "dlb_buf[%d] present", i); - dhd_print_buf_addr(dhdp, buf_name, dld_buf->present, wr_size); - scnprintf(buf_name, sizeof(buf_name), "dlb_buf[%d] front", i); - dhd_print_buf_addr(dhdp, buf_name, dld_buf->front, wr_size); - } - -#ifdef DEBUGABILITY_ECNTRS_LOGGING - /* periodic flushing of ecounters is NOT supported */ - if (*type == DLD_BUF_TYPE_ALL && - logdump_ecntr_enable && - dhdp->ecntr_dbg_ring) { - - ring = (dhd_dbg_ring_t *)dhdp->ecntr_dbg_ring; - dhd_print_buf_addr(dhdp, "ecntr_dbg_ring", ring, LOG_DUMP_ECNTRS_MAX_BUFSIZE); - dhd_print_buf_addr(dhdp, "ecntr_dbg_ring ring_buf", ring->ring_buf, - LOG_DUMP_ECNTRS_MAX_BUFSIZE); - } -#endif /* DEBUGABILITY_ECNTRS_LOGGING */ - -#if defined(BCMPCIE) - if (dhdp->dongle_trap_occured && dhdp->extended_trap_data) { - dhd_print_buf_addr(dhdp, "extended_trap_data", dhdp->extended_trap_data, - BCMPCIE_EXT_TRAP_DATA_MAXLEN); - } -#endif /* BCMPCIE */ - -#if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT) - /* if health check event was received */ - if (dhdp->memdump_type == DUMP_TYPE_DONGLE_HOST_EVENT) { - dhd_print_buf_addr(dhdp, "health_chk_event_data", dhdp->health_chk_event_data, - HEALTH_CHK_BUF_SIZE); - } -#endif /* DHD_FW_COREDUMP && DNGL_EVENT_SUPPORT */ - - /* append the concise debug information */ - if (dhdp->concise_dbg_buf) { - dhd_print_buf_addr(dhdp, "concise_dbg_buf", dhdp->concise_dbg_buf, - CONCISE_DUMP_BUFLEN); - } -} - -#ifdef CUSTOMER_HW4_DEBUG -static void -dhd_log_dump_print_to_kmsg(char *bufptr, unsigned long len) -{ - char tmp_buf[DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE + 1]; - char *end = NULL; - unsigned long plen = 0; - - if (!bufptr || !len) - return; - - memset(tmp_buf, 0, DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE); - end = bufptr + len; - while (bufptr < end) { - if ((bufptr + DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE) < end) { - memcpy(tmp_buf, bufptr, DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE); - tmp_buf[DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE] = '\0'; - printf("%s", tmp_buf); - bufptr += DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE; - } else { - plen = (unsigned long)end - (unsigned long)bufptr; - memcpy(tmp_buf, bufptr, plen); - tmp_buf[plen] = '\0'; - printf("%s", tmp_buf); - bufptr += plen; - } - } -} - -static void -dhd_log_dump_print_tail(dhd_pub_t *dhdp, - struct dhd_log_dump_buf *dld_buf, - uint tail_len) -{ - char *flush_ptr1 = NULL, *flush_ptr2 = NULL; - unsigned long len_flush1 = 0, len_flush2 = 0; - unsigned long flags = 0; - - /* need to hold the lock before accessing 'present' and 'remain' ptrs */ - DHD_LOG_DUMP_BUF_LOCK(&dld_buf->lock, flags); - flush_ptr1 = dld_buf->present - tail_len; - if (flush_ptr1 >= dld_buf->front) { - /* tail content is within the buffer */ - flush_ptr2 = NULL; - len_flush1 = tail_len; - } else if (dld_buf->wraparound) { - /* tail content spans the buffer length i.e, wrap around */ - flush_ptr1 = dld_buf->front; - len_flush1 = (unsigned long)dld_buf->present - (unsigned long)flush_ptr1; - len_flush2 = (unsigned long)tail_len - len_flush1; - flush_ptr2 = (char *)((unsigned long)dld_buf->max - - (unsigned long)len_flush2); - } else { - /* amt of logs in buffer is less than tail size */ - flush_ptr1 = dld_buf->front; - flush_ptr2 = NULL; - len_flush1 = (unsigned long)dld_buf->present - (unsigned long)dld_buf->front; - } - DHD_LOG_DUMP_BUF_UNLOCK(&dld_buf->lock, flags); - - printf("\n================= LOG_DUMP tail =================\n"); - if (flush_ptr2) { - dhd_log_dump_print_to_kmsg(flush_ptr2, len_flush2); - } - dhd_log_dump_print_to_kmsg(flush_ptr1, len_flush1); - printf("\n===================================================\n"); -} -#endif /* CUSTOMER_HW4_DEBUG */ - -#ifdef DHD_SSSR_DUMP -int -dhdpcie_sssr_dump_get_before_after_len(dhd_pub_t *dhd, uint32 *arr_len) -{ - int i = 0; - uint dig_buf_size = 0; - - DHD_ERROR(("%s\n", __FUNCTION__)); - - /* core 0 */ - i = 0; -#ifdef DHD_SSSR_DUMP_BEFORE_SR - if (dhd->sssr_d11_before[i] && dhd->sssr_d11_outofreset[i] && - (dhd->sssr_dump_mode == SSSR_DUMP_MODE_SSSR)) { - - arr_len[SSSR_C0_D11_BEFORE] = dhd_sssr_mac_buf_size(dhd, i); - DHD_ERROR(("%s: arr_len[SSSR_C0_D11_BEFORE] : %d\n", __FUNCTION__, - arr_len[SSSR_C0_D11_BEFORE])); -#ifdef DHD_LOG_DUMP - dhd_print_buf_addr(dhd, "SSSR_C0_D11_BEFORE", - dhd->sssr_d11_before[i], arr_len[SSSR_C0_D11_BEFORE]); -#endif /* DHD_LOG_DUMP */ - } -#endif /* DHD_SSSR_DUMP_BEFORE_SR */ - if (dhd->sssr_d11_after[i] && dhd->sssr_d11_outofreset[i]) { - arr_len[SSSR_C0_D11_AFTER] = dhd_sssr_mac_buf_size(dhd, i); - DHD_ERROR(("%s: arr_len[SSSR_C0_D11_AFTER] : %d\n", __FUNCTION__, - arr_len[SSSR_C0_D11_AFTER])); -#ifdef DHD_LOG_DUMP - dhd_print_buf_addr(dhd, "SSSR_C0_D11_AFTER", - dhd->sssr_d11_after[i], arr_len[SSSR_C0_D11_AFTER]); -#endif /* DHD_LOG_DUMP */ - } - - /* core 1 */ - i = 1; -#ifdef DHD_SSSR_DUMP_BEFORE_SR - if (dhd->sssr_d11_before[i] && dhd->sssr_d11_outofreset[i] && - (dhd->sssr_dump_mode == SSSR_DUMP_MODE_SSSR)) { - arr_len[SSSR_C1_D11_BEFORE] = dhd_sssr_mac_buf_size(dhd, i); - DHD_ERROR(("%s: arr_len[SSSR_C1_D11_BEFORE] : %d\n", __FUNCTION__, - arr_len[SSSR_C1_D11_BEFORE])); -#ifdef DHD_LOG_DUMP - dhd_print_buf_addr(dhd, "SSSR_C1_D11_BEFORE", - dhd->sssr_d11_before[i], arr_len[SSSR_C1_D11_BEFORE]); -#endif /* DHD_LOG_DUMP */ - } -#endif /* DHD_SSSR_DUMP_BEFORE_SR */ - if (dhd->sssr_d11_after[i] && dhd->sssr_d11_outofreset[i]) { - arr_len[SSSR_C1_D11_AFTER] = dhd_sssr_mac_buf_size(dhd, i); - DHD_ERROR(("%s: arr_len[SSSR_C1_D11_AFTER] : %d\n", __FUNCTION__, - arr_len[SSSR_C1_D11_AFTER])); -#ifdef DHD_LOG_DUMP - dhd_print_buf_addr(dhd, "SSSR_C1_D11_AFTER", - dhd->sssr_d11_after[i], arr_len[SSSR_C1_D11_AFTER]); -#endif /* DHD_LOG_DUMP */ - } - - /* core 2 scan core */ - if (dhd->sssr_reg_info->rev2.version >= SSSR_REG_INFO_VER_2) { - i = 2; -#ifdef DHD_SSSR_DUMP_BEFORE_SR - if (dhd->sssr_d11_before[i] && dhd->sssr_d11_outofreset[i] && - (dhd->sssr_dump_mode == SSSR_DUMP_MODE_SSSR)) { - arr_len[SSSR_C2_D11_BEFORE] = dhd_sssr_mac_buf_size(dhd, i); - DHD_ERROR(("%s: arr_len[SSSR_C2_D11_BEFORE] : %d\n", __FUNCTION__, - arr_len[SSSR_C2_D11_BEFORE])); -#ifdef DHD_LOG_DUMP - dhd_print_buf_addr(dhd, "SSSR_C2_D11_BEFORE", - dhd->sssr_d11_before[i], arr_len[SSSR_C2_D11_BEFORE]); -#endif /* DHD_LOG_DUMP */ - } -#endif /* DHD_SSSR_DUMP_BEFORE_SR */ - if (dhd->sssr_d11_after[i] && dhd->sssr_d11_outofreset[i]) { - arr_len[SSSR_C2_D11_AFTER] = dhd_sssr_mac_buf_size(dhd, i); - DHD_ERROR(("%s: arr_len[SSSR_C2_D11_AFTER] : %d\n", __FUNCTION__, - arr_len[SSSR_C2_D11_AFTER])); -#ifdef DHD_LOG_DUMP - dhd_print_buf_addr(dhd, "SSSR_C2_D11_AFTER", - dhd->sssr_d11_after[i], arr_len[SSSR_C2_D11_AFTER]); -#endif /* DHD_LOG_DUMP */ - } - } - - /* DIG core or VASIP */ - dig_buf_size = dhd_sssr_dig_buf_size(dhd); -#ifdef DHD_SSSR_DUMP_BEFORE_SR - arr_len[SSSR_DIG_BEFORE] = (dhd->sssr_dig_buf_before) ? dig_buf_size : 0; - DHD_ERROR(("%s: arr_len[SSSR_DIG_BEFORE] : %d\n", __FUNCTION__, - arr_len[SSSR_DIG_BEFORE])); -#ifdef DHD_LOG_DUMP - if (dhd->sssr_dig_buf_before) { - dhd_print_buf_addr(dhd, "SSSR_DIG_BEFORE", - dhd->sssr_dig_buf_before, arr_len[SSSR_DIG_BEFORE]); - } -#endif /* DHD_LOG_DUMP */ -#endif /* DHD_SSSR_DUMP_BEFORE_SR */ - - arr_len[SSSR_DIG_AFTER] = (dhd->sssr_dig_buf_after) ? dig_buf_size : 0; - DHD_ERROR(("%s: arr_len[SSSR_DIG_AFTER] : %d\n", __FUNCTION__, - arr_len[SSSR_DIG_AFTER])); -#ifdef DHD_LOG_DUMP - if (dhd->sssr_dig_buf_after) { - dhd_print_buf_addr(dhd, "SSSR_DIG_AFTER", - dhd->sssr_dig_buf_after, arr_len[SSSR_DIG_AFTER]); - } -#endif /* DHD_LOG_DUMP */ - - return BCME_OK; -} - -void -dhd_nla_put_sssr_dump_len(void *ndev, uint32 *arr_len) -{ - dhd_info_t *dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); - dhd_pub_t *dhdp = &dhd_info->pub; - - if (dhdp->sssr_dump_collected) { - dhdpcie_sssr_dump_get_before_after_len(dhdp, arr_len); - } -} -#endif /* DHD_SSSR_DUMP */ - -uint32 -dhd_get_time_str_len() -{ - char *ts = NULL, time_str[128]; - - ts = dhd_log_dump_get_timestamp(); - snprintf(time_str, sizeof(time_str), - "\n\n ========== LOG DUMP TAKEN AT : %s =========\n", ts); - return strlen(time_str); -} - -#if defined(BCMPCIE) -uint32 -dhd_get_ext_trap_len(void *ndev, dhd_pub_t *dhdp) -{ - int length = 0; - log_dump_section_hdr_t sec_hdr; - dhd_info_t *dhd_info; - - if (ndev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return length; - - if (dhdp->extended_trap_data) { - length = (strlen(EXT_TRAP_LOG_HDR) - + sizeof(sec_hdr) + BCMPCIE_EXT_TRAP_DATA_MAXLEN); - } - return length; -} -#endif /* BCMPCIE */ - -#if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT) -uint32 -dhd_get_health_chk_len(void *ndev, dhd_pub_t *dhdp) -{ - int length = 0; - log_dump_section_hdr_t sec_hdr; - dhd_info_t *dhd_info; - - if (ndev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return length; - - if (dhdp->memdump_type == DUMP_TYPE_DONGLE_HOST_EVENT) { - length = (strlen(HEALTH_CHK_LOG_HDR) - + sizeof(sec_hdr) + HEALTH_CHK_BUF_SIZE); - } - return length; -} -#endif /* DHD_FW_COREDUMP && DNGL_EVENT_SUPPORT */ - -uint32 -dhd_get_dhd_dump_len(void *ndev, dhd_pub_t *dhdp) -{ - uint32 length = 0; - log_dump_section_hdr_t sec_hdr; - dhd_info_t *dhd_info; - int remain_len = 0; - - if (ndev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return length; - - if (dhdp->concise_dbg_buf) { - remain_len = dhd_dump(dhdp, (char *)dhdp->concise_dbg_buf, CONCISE_DUMP_BUFLEN); - if (remain_len <= 0 || remain_len >= CONCISE_DUMP_BUFLEN) { - DHD_ERROR(("%s: error getting concise debug info ! remain_len: %d\n", - __FUNCTION__, remain_len)); - return length; - } - - length += (uint32)(CONCISE_DUMP_BUFLEN - remain_len); - } - - length += (uint32)(strlen(DHD_DUMP_LOG_HDR) + sizeof(sec_hdr)); - return length; -} - -uint32 -dhd_get_cookie_log_len(void *ndev, dhd_pub_t *dhdp) -{ - int length = 0; - dhd_info_t *dhd_info; - - if (ndev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return length; - - if (dhdp->logdump_cookie && dhd_logdump_cookie_count(dhdp) > 0) { - length = dhd_log_dump_cookie_len(dhdp); - } - return length; - -} - -#ifdef DHD_DUMP_PCIE_RINGS -uint32 -dhd_get_flowring_len(void *ndev, dhd_pub_t *dhdp) -{ - uint32 length = 0; - log_dump_section_hdr_t sec_hdr; - dhd_info_t *dhd_info; - uint16 h2d_flowrings_total; - int remain_len = 0; - - if (ndev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return length; - - if (dhdp->concise_dbg_buf) { - remain_len = dhd_dump(dhdp, (char *)dhdp->concise_dbg_buf, CONCISE_DUMP_BUFLEN); - if (remain_len <= 0 || remain_len >= CONCISE_DUMP_BUFLEN) { - DHD_ERROR(("%s: error getting concise debug info ! remain_len: %d\n", - __FUNCTION__, remain_len)); - return length; - } - - length += (uint32)(CONCISE_DUMP_BUFLEN - remain_len); - } - - length += (uint32) strlen(FLOWRING_DUMP_HDR); - length += (uint32) sizeof(sec_hdr); - h2d_flowrings_total = dhd_get_max_flow_rings(dhdp); - length += ((D2HRING_TXCMPLT_ITEMSIZE * D2HRING_TXCMPLT_MAX_ITEM) - + (H2DRING_RXPOST_ITEMSIZE * H2DRING_RXPOST_MAX_ITEM) - + (D2HRING_RXCMPLT_ITEMSIZE * D2HRING_RXCMPLT_MAX_ITEM) - + (H2DRING_CTRL_SUB_ITEMSIZE * H2DRING_CTRL_SUB_MAX_ITEM) - + (D2HRING_CTRL_CMPLT_ITEMSIZE * D2HRING_CTRL_CMPLT_MAX_ITEM) -#ifdef EWP_EDL - + (D2HRING_EDL_HDR_SIZE * D2HRING_EDL_MAX_ITEM)); -#else - + (H2DRING_INFO_BUFPOST_ITEMSIZE * H2DRING_DYNAMIC_INFO_MAX_ITEM) - + (D2HRING_INFO_BUFCMPLT_ITEMSIZE * D2HRING_DYNAMIC_INFO_MAX_ITEM)); -#endif /* EWP_EDL */ - -#if defined(DHD_HTPUT_TUNABLES) - /* flowring lengths are different for HTPUT rings, handle accordingly */ - length += ((H2DRING_TXPOST_ITEMSIZE * dhd_prot_get_h2d_htput_max_txpost(dhdp) * - HTPUT_TOTAL_FLOW_RINGS) + - (H2DRING_TXPOST_ITEMSIZE * dhd_prot_get_h2d_max_txpost(dhdp) * - (h2d_flowrings_total - HTPUT_TOTAL_FLOW_RINGS))); -#else - length += (H2DRING_TXPOST_ITEMSIZE * dhd_prot_get_h2d_max_txpost(dhdp) * - h2d_flowrings_total); -#endif /* DHD_HTPUT_TUNABLES */ - - return length; -} -#endif /* DHD_DUMP_PCIE_RINGS */ - -#ifdef EWP_ECNTRS_LOGGING -uint32 -dhd_get_ecntrs_len(void *ndev, dhd_pub_t *dhdp) -{ - dhd_info_t *dhd_info; - log_dump_section_hdr_t sec_hdr; - int length = 0; - dhd_dbg_ring_t *ring; - - if (ndev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return length; - - if (logdump_ecntr_enable && dhdp->ecntr_dbg_ring) { - ring = (dhd_dbg_ring_t *)dhdp->ecntr_dbg_ring; - length = ring->ring_size + strlen(ECNTRS_LOG_HDR) + sizeof(sec_hdr); - } - return length; -} -#endif /* EWP_ECNTRS_LOGGING */ - -int -dhd_get_dld_log_dump(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, int type, void *pos) -{ - int ret = BCME_OK; - struct dhd_log_dump_buf *dld_buf; - log_dump_section_hdr_t sec_hdr; - dhd_info_t *dhd_info; - - dld_buf = &g_dld_buf[type]; - - if (dev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); - dhdp = &dhd_info->pub; - } else if (!dhdp) { - return BCME_ERROR; - } - - DHD_ERROR(("%s: ENTER \n", __FUNCTION__)); - - dhd_init_sec_hdr(&sec_hdr); - - /* write the section header first */ - ret = dhd_export_debug_data(dld_hdrs[type].hdr_str, fp, user_buf, - strlen(dld_hdrs[type].hdr_str), pos); - if (ret < 0) - goto exit; - len -= (uint32)strlen(dld_hdrs[type].hdr_str); - len -= (uint32)sizeof(sec_hdr); - sec_hdr.type = dld_hdrs[type].sec_type; - sec_hdr.length = len; - ret = dhd_export_debug_data((char *)&sec_hdr, fp, user_buf, sizeof(sec_hdr), pos); - if (ret < 0) - goto exit; - ret = dhd_export_debug_data(dld_buf->buffer, fp, user_buf, len, pos); - if (ret < 0) - goto exit; - -exit: - return ret; -} - -static int -dhd_log_flush(dhd_pub_t *dhdp, log_dump_type_t *type) -{ - unsigned long flags = 0; -#ifdef EWP_EDL - int i = 0; -#endif /* EWP_EDL */ - dhd_info_t *dhd_info = NULL; - - BCM_REFERENCE(dhd_info); - - /* if dhdp is null, its extremely unlikely that log dump will be scheduled - * so not freeing 'type' here is ok, even if we want to free 'type' - * we cannot do so, since 'dhdp->osh' is unavailable - * as dhdp is null - */ - if (!dhdp || !type) { - if (dhdp) { - DHD_GENERAL_LOCK(dhdp, flags); - DHD_BUS_BUSY_CLEAR_IN_LOGDUMP(dhdp); - dhd_os_busbusy_wake(dhdp); - DHD_GENERAL_UNLOCK(dhdp, flags); - } - return BCME_ERROR; - } - -#if defined(BCMPCIE) - if (dhd_bus_get_linkdown(dhdp)) { - /* As link is down donot collect any data over PCIe. - * Also return BCME_OK to caller, so that caller can - * dump all the outstanding data to file - */ - return BCME_OK; - } -#endif /* BCMPCIE */ - - dhd_info = (dhd_info_t *)dhdp->info; - /* in case of trap get preserve logs from ETD */ -#if defined(BCMPCIE) && defined(EWP_ETD_PRSRV_LOGS) - if (dhdp->dongle_trap_occured && - dhdp->extended_trap_data) { - dhdpcie_get_etd_preserve_logs(dhdp, (uint8 *)dhdp->extended_trap_data, - &dhd_info->event_data); - } -#endif /* BCMPCIE */ - - /* flush the event work items to get any fw events/logs - * flush_work is a blocking call - */ -#ifdef SHOW_LOGTRACE -#ifdef EWP_EDL - if (dhd_info->pub.dongle_edl_support) { - /* wait till existing edl items are processed */ - dhd_flush_logtrace_process(dhd_info); - /* dhd_flush_logtrace_process will ensure the work items in the ring - * (EDL ring) from rd to wr are processed. But if wr had - * wrapped around, only the work items from rd to ring-end are processed. - * So to ensure that the work items at the - * beginning of ring are also processed in the wrap around case, call - * it twice - */ - for (i = 0; i < 2; i++) { - /* blocks till the edl items are processed */ - dhd_flush_logtrace_process(dhd_info); - } - } else { - dhd_flush_logtrace_process(dhd_info); - } -#else - dhd_flush_logtrace_process(dhd_info); -#endif /* EWP_EDL */ -#endif /* SHOW_LOGTRACE */ - -#ifdef CUSTOMER_HW4_DEBUG - /* print last 'x' KB of preserve buffer data to kmsg console - * this is to address cases where debug_dump is not - * available for debugging - */ - dhd_log_dump_print_tail(dhdp, - &g_dld_buf[DLD_BUF_TYPE_PRESERVE], logdump_prsrv_tailsize); -#endif /* CUSTOMER_HW4_DEBUG */ - return BCME_OK; -} - -int -dhd_get_debug_dump_file_name(void *dev, dhd_pub_t *dhdp, char *dump_path, int size) -{ - int ret; - int len = 0; - dhd_info_t *dhd_info; - - if (dev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return BCME_ERROR; - - memset(dump_path, 0, size); - - ret = snprintf(dump_path, size, "%s", - DHD_COMMON_DUMP_PATH DHD_DEBUG_DUMP_TYPE); - len += ret; - - /* Keep the same timestamp across different dump logs */ - if (!dhdp->logdump_periodic_flush) { - struct rtc_time tm; - clear_debug_dump_time(dhdp->debug_dump_time_str); - get_debug_dump_time(dhdp->debug_dump_time_str); - sscanf(dhdp->debug_dump_time_str, DHD_LOG_DUMP_TS_FMT_YYMMDDHHMMSS, - &tm.tm_year, &tm.tm_mon, &tm.tm_mday, - &tm.tm_hour, &tm.tm_min, &tm.tm_sec); - ret = snprintf(dump_path + len, size - len, "_" DHD_LOG_DUMP_TS_FMT_YYMMDDHHMMSS, - tm.tm_year, tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - len += ret; - } - - ret = 0; - switch (dhdp->debug_dump_subcmd) { - case CMD_UNWANTED: - ret = snprintf(dump_path + len, size - len, "%s", DHD_DUMP_SUBSTR_UNWANTED); - break; - case CMD_DISCONNECTED: - ret = snprintf(dump_path + len, size - len, "%s", DHD_DUMP_SUBSTR_DISCONNECTED); - break; - default: - break; - } - len += ret; - - return BCME_OK; -} - -uint32 -dhd_get_dld_len(int log_type) -{ - unsigned long wr_size = 0; - unsigned long buf_size = 0; - unsigned long flags = 0; - struct dhd_log_dump_buf *dld_buf; - log_dump_section_hdr_t sec_hdr; - - /* calculate the length of the log */ - dld_buf = &g_dld_buf[log_type]; - buf_size = (unsigned long)dld_buf->max - - (unsigned long)dld_buf->buffer; - - if (dld_buf->wraparound) { - wr_size = buf_size; - } else { - /* need to hold the lock before accessing 'present' and 'remain' ptrs */ - DHD_LOG_DUMP_BUF_LOCK(&dld_buf->lock, flags); - wr_size = (unsigned long)dld_buf->present - - (unsigned long)dld_buf->front; - DHD_LOG_DUMP_BUF_UNLOCK(&dld_buf->lock, flags); - } - return (wr_size + sizeof(sec_hdr) + strlen(dld_hdrs[log_type].hdr_str)); -} - -static void -dhd_get_time_str(dhd_pub_t *dhdp, char *time_str, int size) -{ - char *ts = NULL; - memset(time_str, 0, size); - ts = dhd_log_dump_get_timestamp(); - snprintf(time_str, size, - "\n\n ========== LOG DUMP TAKEN AT : %s =========\n", ts); -} - -int -dhd_print_time_str(const void *user_buf, void *fp, uint32 len, void *pos) -{ - char *ts = NULL; - int ret = 0; - char time_str[128]; - - memset_s(time_str, sizeof(time_str), 0, sizeof(time_str)); - ts = dhd_log_dump_get_timestamp(); - snprintf(time_str, sizeof(time_str), - "\n\n ========== LOG DUMP TAKEN AT : %s =========\n", ts); - - /* write the timestamp hdr to the file first */ - ret = dhd_export_debug_data(time_str, fp, user_buf, strlen(time_str), pos); - if (ret < 0) { - DHD_ERROR(("write file error, err = %d\n", ret)); - } - return ret; -} - -#if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT) -int -dhd_print_health_chk_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos) -{ - int ret = BCME_OK; - log_dump_section_hdr_t sec_hdr; - dhd_info_t *dhd_info; - - if (dev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return BCME_ERROR; - - dhd_init_sec_hdr(&sec_hdr); - - if (dhdp->memdump_type == DUMP_TYPE_DONGLE_HOST_EVENT) { - /* write the section header first */ - ret = dhd_export_debug_data(HEALTH_CHK_LOG_HDR, fp, user_buf, - strlen(HEALTH_CHK_LOG_HDR), pos); - if (ret < 0) - goto exit; - - len -= (uint32)strlen(HEALTH_CHK_LOG_HDR); - sec_hdr.type = LOG_DUMP_SECTION_HEALTH_CHK; - sec_hdr.length = HEALTH_CHK_BUF_SIZE; - ret = dhd_export_debug_data((char *)&sec_hdr, fp, user_buf, sizeof(sec_hdr), pos); - if (ret < 0) - goto exit; - - len -= (uint32)sizeof(sec_hdr); - /* write the log */ - ret = dhd_export_debug_data((char *)dhdp->health_chk_event_data, fp, - user_buf, len, pos); - if (ret < 0) - goto exit; - } -exit: - return ret; -} -#endif /* DHD_FW_COREDUMP && DNGL_EVENT_SUPPORT */ - -#if defined(BCMPCIE) -int -dhd_print_ext_trap_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos) -{ - int ret = BCME_OK; - log_dump_section_hdr_t sec_hdr; - dhd_info_t *dhd_info; - - if (dev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return BCME_ERROR; - - dhd_init_sec_hdr(&sec_hdr); - - /* append extended trap data to the file in case of traps */ - if (dhdp->dongle_trap_occured && - dhdp->extended_trap_data) { - /* write the section header first */ - ret = dhd_export_debug_data(EXT_TRAP_LOG_HDR, fp, user_buf, - strlen(EXT_TRAP_LOG_HDR), pos); - if (ret < 0) - goto exit; - - len -= (uint32)strlen(EXT_TRAP_LOG_HDR); - sec_hdr.type = LOG_DUMP_SECTION_EXT_TRAP; - sec_hdr.length = BCMPCIE_EXT_TRAP_DATA_MAXLEN; - ret = dhd_export_debug_data((uint8 *)&sec_hdr, fp, user_buf, sizeof(sec_hdr), pos); - if (ret < 0) - goto exit; - - len -= (uint32)sizeof(sec_hdr); - /* write the log */ - ret = dhd_export_debug_data((uint8 *)dhdp->extended_trap_data, fp, - user_buf, len, pos); - if (ret < 0) - goto exit; - } -exit: - return ret; -} -#endif /* BCMPCIE */ - -int -dhd_print_dump_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos) -{ - int ret = BCME_OK; - log_dump_section_hdr_t sec_hdr; - dhd_info_t *dhd_info; - - if (dev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return BCME_ERROR; - - dhd_init_sec_hdr(&sec_hdr); - - ret = dhd_export_debug_data(DHD_DUMP_LOG_HDR, fp, user_buf, strlen(DHD_DUMP_LOG_HDR), pos); - if (ret < 0) - goto exit; - - len -= (uint32)strlen(DHD_DUMP_LOG_HDR); - sec_hdr.type = LOG_DUMP_SECTION_DHD_DUMP; - sec_hdr.length = len; - ret = dhd_export_debug_data((char *)&sec_hdr, fp, user_buf, sizeof(sec_hdr), pos); - if (ret < 0) - goto exit; - - len -= (uint32)sizeof(sec_hdr); - - if (dhdp->concise_dbg_buf) { - dhd_dump(dhdp, (char *)dhdp->concise_dbg_buf, CONCISE_DUMP_BUFLEN); - ret = dhd_export_debug_data(dhdp->concise_dbg_buf, fp, user_buf, len, pos); - if (ret < 0) - goto exit; - } - -exit: - return ret; -} - -int -dhd_print_cookie_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos) -{ - int ret = BCME_OK; - dhd_info_t *dhd_info; - - if (dev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return BCME_ERROR; - - if (dhdp->logdump_cookie && dhd_logdump_cookie_count(dhdp) > 0) { - ret = dhd_log_dump_cookie_to_file(dhdp, fp, user_buf, (unsigned long *)pos); - } - return ret; -} - -#ifdef DHD_DUMP_PCIE_RINGS -int -dhd_print_flowring_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos) -{ - log_dump_section_hdr_t sec_hdr; - int ret = BCME_OK; - int remain_len = 0; - dhd_info_t *dhd_info; - - if (dev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return BCME_ERROR; - - dhd_init_sec_hdr(&sec_hdr); - - remain_len = dhd_dump(dhdp, (char *)dhdp->concise_dbg_buf, CONCISE_DUMP_BUFLEN); - if (remain_len <= 0 || remain_len >= CONCISE_DUMP_BUFLEN) { - DHD_ERROR(("%s: error getting concise debug info !\n", - __FUNCTION__)); - return BCME_ERROR; - } - memset(dhdp->concise_dbg_buf, 0, CONCISE_DUMP_BUFLEN); - - /* write the section header first */ - ret = dhd_export_debug_data(FLOWRING_DUMP_HDR, fp, user_buf, - strlen(FLOWRING_DUMP_HDR), pos); - if (ret < 0) - goto exit; - - /* Write the ring summary */ - ret = dhd_export_debug_data(dhdp->concise_dbg_buf, fp, user_buf, - (CONCISE_DUMP_BUFLEN - remain_len), pos); - if (ret < 0) - goto exit; - - sec_hdr.type = LOG_DUMP_SECTION_FLOWRING; - sec_hdr.length = len; - ret = dhd_export_debug_data((char *)&sec_hdr, fp, user_buf, sizeof(sec_hdr), pos); - if (ret < 0) - goto exit; - - /* write the log */ - ret = dhd_d2h_h2d_ring_dump(dhdp, fp, user_buf, (unsigned long *)pos, TRUE); - if (ret < 0) - goto exit; - -exit: - return ret; -} -#endif /* DHD_DUMP_PCIE_RINGS */ - -#ifdef EWP_ECNTRS_LOGGING -int -dhd_print_ecntrs_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos) -{ - log_dump_section_hdr_t sec_hdr; - int ret = BCME_OK; - dhd_info_t *dhd_info; - - if (dev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return BCME_ERROR; - - dhd_init_sec_hdr(&sec_hdr); - - if (logdump_ecntr_enable && - dhdp->ecntr_dbg_ring) { - sec_hdr.type = LOG_DUMP_SECTION_ECNTRS; - ret = dhd_dump_debug_ring(dhdp, dhdp->ecntr_dbg_ring, - user_buf, &sec_hdr, ECNTRS_LOG_HDR, len, LOG_DUMP_SECTION_ECNTRS); - } - return ret; - -} -#endif /* EWP_ECNTRS_LOGGING */ - -#ifdef EWP_RTT_LOGGING -int -dhd_print_rtt_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos) -{ - log_dump_section_hdr_t sec_hdr; - int ret = BCME_OK; - dhd_info_t *dhd_info; - - if (dev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) - return BCME_ERROR; - - dhd_init_sec_hdr(&sec_hdr); - - if (logdump_rtt_enable && dhdp->rtt_dbg_ring) { - ret = dhd_dump_debug_ring(dhdp, dhdp->rtt_dbg_ring, - user_buf, &sec_hdr, RTT_LOG_HDR, len, LOG_DUMP_SECTION_RTT); - } - return ret; - -} -#endif /* EWP_RTT_LOGGING */ - -#ifdef DHD_STATUS_LOGGING -int -dhd_print_status_log_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, - void *fp, uint32 len, void *pos) -{ - dhd_info_t *dhd_info; - - if (dev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); - dhdp = &dhd_info->pub; - } - - if (!dhdp) { - return BCME_ERROR; - } - - return dhd_statlog_write_logdump(dhdp, user_buf, fp, len, pos); -} - -uint32 -dhd_get_status_log_len(void *ndev, dhd_pub_t *dhdp) -{ - dhd_info_t *dhd_info; - uint32 length = 0; - - if (ndev) { - dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); - dhdp = &dhd_info->pub; - } - - if (dhdp) { - length = dhd_statlog_get_logbuf_len(dhdp); - } - - return length; -} -#endif /* DHD_STATUS_LOGGING */ - -void -dhd_init_sec_hdr(log_dump_section_hdr_t *sec_hdr) -{ - /* prep the section header */ - memset(sec_hdr, 0, sizeof(*sec_hdr)); - sec_hdr->magic = LOG_DUMP_MAGIC; - sec_hdr->timestamp = local_clock(); -} - -/* Must hold 'dhd_os_logdump_lock' before calling this function ! */ -static int -do_dhd_log_dump(dhd_pub_t *dhdp, log_dump_type_t *type) -{ - int ret = 0, i = 0; - struct file *fp = NULL; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - mm_segment_t old_fs; - struct kstat stat; -#endif - loff_t pos = 0; - char dump_path[128]; - uint32 file_mode; - unsigned long flags = 0; - size_t log_size = 0; - size_t fspace_remain = 0; - char time_str[128]; - unsigned int len = 0; - log_dump_section_hdr_t sec_hdr; - uint32 file_size = 0; - - DHD_ERROR(("%s: ENTER \n", __FUNCTION__)); - - DHD_GENERAL_LOCK(dhdp, flags); - if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp)) { - DHD_GENERAL_UNLOCK(dhdp, flags); - DHD_ERROR(("%s: bus is down! can't collect log dump. \n", __FUNCTION__)); - goto exit1; - } - DHD_BUS_BUSY_SET_IN_LOGDUMP(dhdp); - DHD_GENERAL_UNLOCK(dhdp, flags); - - if ((ret = dhd_log_flush(dhdp, type)) < 0) { - goto exit1; - } - /* change to KERNEL_DS address limit */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - old_fs = get_fs(); - set_fs(KERNEL_DS); -#endif - - dhd_get_debug_dump_file_name(NULL, dhdp, dump_path, sizeof(dump_path)); - - DHD_ERROR(("debug_dump_path = %s\n", dump_path)); - DHD_ERROR(("DHD version: %s\n", dhd_version)); - DHD_ERROR(("F/W version: %s\n", fw_version)); - - dhd_log_dump_buf_addr(dhdp, type); - - dhd_get_time_str(dhdp, time_str, 128); - - /* if this is the first time after dhd is loaded, - * or, if periodic flush is disabled, clear the log file - */ - if (!dhdp->logdump_periodic_flush || dhdp->last_file_posn == 0) - file_mode = O_CREAT | O_WRONLY | O_SYNC | O_TRUNC; - else - file_mode = O_CREAT | O_RDWR | O_SYNC; - - fp = filp_open(dump_path, file_mode, 0664); - if (IS_ERR(fp)) { - /* If android installed image, try '/data' directory */ -#if defined(CONFIG_X86) && defined(OEM_ANDROID) - DHD_ERROR(("%s: File open error on Installed android image, trying /data...\n", - __FUNCTION__)); - snprintf(dump_path, sizeof(dump_path), "/data/" DHD_DEBUG_DUMP_TYPE); - if (!dhdp->logdump_periodic_flush) { - snprintf(dump_path + strlen(dump_path), - sizeof(dump_path) - strlen(dump_path), - "_%s", dhdp->debug_dump_time_str); - } - fp = filp_open(dump_path, file_mode, 0664); - if (IS_ERR(fp)) { - ret = PTR_ERR(fp); - DHD_ERROR(("open file error, err = %d\n", ret)); - goto exit2; - } - DHD_ERROR(("debug_dump_path = %s\n", dump_path)); -#else - ret = PTR_ERR(fp); - DHD_ERROR(("open file error, err = %d\n", ret)); - goto exit2; -#endif /* CONFIG_X86 && OEM_ANDROID */ - } - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - ret = vfs_stat(dump_path, &stat); - if (ret < 0) { - DHD_ERROR(("file stat error, err = %d\n", ret)); - goto exit2; - } - file_size = stat.size; -#else - file_size = dhd_os_get_image_size(fp); - if (file_size <= 0) { - DHD_ERROR(("%s: get file size fails ! %d\n", __FUNCTION__, file_size)); - goto exit2; - } -#endif - - /* if some one else has changed the file */ - if (dhdp->last_file_posn != 0 && - file_size < dhdp->last_file_posn) { - dhdp->last_file_posn = 0; - } - - /* XXX: periodic flush is disabled by default, if enabled - * only periodic flushing of 'GENERAL' log dump buffer - * is supported, its not recommended to turn on periodic - * flushing, except for developer unit test. - */ - if (dhdp->logdump_periodic_flush) { - log_size = strlen(time_str) + strlen(DHD_DUMP_LOG_HDR) + sizeof(sec_hdr); - /* calculate the amount of space required to dump all logs */ - for (i = 0; i < DLD_BUFFER_NUM; ++i) { - if (*type != DLD_BUF_TYPE_ALL && i != *type) - continue; - - if (g_dld_buf[i].wraparound) { - log_size += (unsigned long)g_dld_buf[i].max - - (unsigned long)g_dld_buf[i].buffer; - } else { - DHD_LOG_DUMP_BUF_LOCK(&g_dld_buf[i].lock, flags); - log_size += (unsigned long)g_dld_buf[i].present - - (unsigned long)g_dld_buf[i].front; - DHD_LOG_DUMP_BUF_UNLOCK(&g_dld_buf[i].lock, flags); - } - log_size += strlen(dld_hdrs[i].hdr_str) + sizeof(sec_hdr); - - if (*type != DLD_BUF_TYPE_ALL && i == *type) - break; - } - - ret = generic_file_llseek(fp, dhdp->last_file_posn, SEEK_CUR); - if (ret < 0) { - DHD_ERROR(("file seek last posn error ! err = %d \n", ret)); - goto exit2; - } - pos = fp->f_pos; - - /* if the max file size is reached, wrap around to beginning of the file - * we're treating the file as a large ring buffer - */ - fspace_remain = logdump_max_filesize - pos; - if (log_size > fspace_remain) { - fp->f_pos -= pos; - pos = fp->f_pos; - } - } - - dhd_print_time_str(0, fp, len, &pos); - - for (i = 0; i < DLD_BUFFER_NUM; ++i) { - - if (*type != DLD_BUF_TYPE_ALL && i != *type) - continue; - - len = dhd_get_dld_len(i); - dhd_get_dld_log_dump(NULL, dhdp, 0, fp, len, i, &pos); - if (*type != DLD_BUF_TYPE_ALL) - break; - } - -#ifdef EWP_ECNTRS_LOGGING - if (*type == DLD_BUF_TYPE_ALL && - logdump_ecntr_enable && - dhdp->ecntr_dbg_ring) { - dhd_log_dump_ring_to_file(dhdp, dhdp->ecntr_dbg_ring, - fp, (unsigned long *)&pos, - &sec_hdr, ECNTRS_LOG_HDR, LOG_DUMP_SECTION_ECNTRS); - } -#endif /* EWP_ECNTRS_LOGGING */ - -#ifdef DHD_STATUS_LOGGING - if (dhdp->statlog) { - /* write the statlog */ - len = dhd_get_status_log_len(NULL, dhdp); - if (len) { - if (dhd_print_status_log_data(NULL, dhdp, 0, fp, - len, &pos) < 0) { - goto exit2; - } - } - } -#endif /* DHD_STATUS_LOGGING */ - -#ifdef DHD_STATUS_LOGGING - if (dhdp->statlog) { - dhd_print_buf_addr(dhdp, "statlog_logbuf", dhd_statlog_get_logbuf(dhdp), - dhd_statlog_get_logbuf_len(dhdp)); - } -#endif /* DHD_STATUS_LOGGING */ - -#ifdef EWP_RTT_LOGGING - if (*type == DLD_BUF_TYPE_ALL && - logdump_rtt_enable && - dhdp->rtt_dbg_ring) { - dhd_log_dump_ring_to_file(dhdp, dhdp->rtt_dbg_ring, - fp, (unsigned long *)&pos, - &sec_hdr, RTT_LOG_HDR, LOG_DUMP_SECTION_RTT); - } -#endif /* EWP_RTT_LOGGING */ - -#ifdef EWP_BCM_TRACE - if (*type == DLD_BUF_TYPE_ALL && - dhdp->bcm_trace_dbg_ring) { - dhd_log_dump_ring_to_file(dhdp, dhdp->bcm_trace_dbg_ring, - fp, (unsigned long *)&pos, - &sec_hdr, BCM_TRACE_LOG_HDR, LOG_DUMP_SECTION_BCM_TRACE); - } -#endif /* EWP_BCM_TRACE */ - -#ifdef BCMPCIE - len = dhd_get_ext_trap_len(NULL, dhdp); - if (len) { - if (dhd_print_ext_trap_data(NULL, dhdp, 0, fp, len, &pos) < 0) - goto exit2; - } -#endif /* BCMPCIE */ - -#if defined(DHD_FW_COREDUMP) && defined (DNGL_EVENT_SUPPORT) - len = dhd_get_health_chk_len(NULL, dhdp); - if (len) { - if (dhd_print_health_chk_data(NULL, dhdp, 0, fp, len, &pos) < 0) - goto exit2; - } -#endif /* DHD_FW_COREDUMP && DNGL_EVENT_SUPPORT */ - - len = dhd_get_dhd_dump_len(NULL, dhdp); - if (len) { - if (dhd_print_dump_data(NULL, dhdp, 0, fp, len, &pos) < 0) - goto exit2; - } - - len = dhd_get_cookie_log_len(NULL, dhdp); - if (len) { - if (dhd_print_cookie_data(NULL, dhdp, 0, fp, len, &pos) < 0) - goto exit2; - } - -#ifdef DHD_DUMP_PCIE_RINGS - len = dhd_get_flowring_len(NULL, dhdp); - if (len) { - if (dhd_print_flowring_data(NULL, dhdp, 0, fp, len, &pos) < 0) - goto exit2; - } -#endif - - if (dhdp->logdump_periodic_flush) { - /* store the last position written to in the file for future use */ - dhdp->last_file_posn = pos; - } - -exit2: - if (!IS_ERR(fp) && fp != NULL) { - filp_close(fp, NULL); - DHD_ERROR(("%s: Finished writing log dump to file - '%s' \n", - __FUNCTION__, dump_path)); - } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - set_fs(old_fs); -#endif -exit1: - if (type) { - MFREE(dhdp->osh, type, sizeof(*type)); - } - DHD_GENERAL_LOCK(dhdp, flags); - DHD_BUS_BUSY_CLEAR_IN_LOGDUMP(dhdp); - dhd_os_busbusy_wake(dhdp); - DHD_GENERAL_UNLOCK(dhdp, flags); - -#ifdef DHD_DUMP_MNGR - if (ret >= 0) { - dhd_dump_file_manage_enqueue(dhdp, dump_path, DHD_DEBUG_DUMP_TYPE); - } -#endif /* DHD_DUMP_MNGR */ - - return (ret < 0) ? BCME_ERROR : BCME_OK; -} -#endif /* DHD_LOG_DUMP */ - /* This function writes data to the file pointed by fp, OR * copies data to the user buffer sent by upper layer(HAL). */ @@ -24842,14 +19971,17 @@ int dhd_export_debug_data(void *mem_buf, void *fp, const void *user_buf, uint32 buf_len, void *pos) { int ret = BCME_OK; +#ifdef DHD_DEBUGABILITY_DEBUG_DUMP + struct dhd_dbg_ring_buf *ring_buf; +#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */ if (fp) { - ret = vfs_write(fp, mem_buf, buf_len, (loff_t *)pos); + ret = dhd_vfs_write(fp, mem_buf, buf_len, (loff_t *)pos); if (ret < 0) { DHD_ERROR(("write file error, err = %d\n", ret)); goto exit; } - } else { + } else if (user_buf) { #ifdef CONFIG_COMPAT #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) if (in_compat_syscall()) @@ -24877,6 +20009,18 @@ dhd_export_debug_data(void *mem_buf, void *fp, const void *user_buf, uint32 buf_ } (*(int *)pos) += buf_len; } +#ifdef DHD_DEBUGABILITY_DEBUG_DUMP + else { + ring_buf = &g_ring_buf; + if (ring_buf->dhd_pub) { + ret = dhd_debug_dump_ring_push(ring_buf->dhd_pub, (*(int *)pos), + buf_len, mem_buf); + if (ret != BCME_OK) { + DHD_ERROR(("%s: ring push failed ret:%d\n", __func__, ret)); + } + } + } +#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */ exit: return ret; } @@ -24974,7 +20118,7 @@ exit: } #endif /* BCM_ROUTER_DHD */ -#ifdef BCMDBG +#if defined(BCMDBG) && defined(DHD_MACDBG) #define DUMPMAC_BUF_SZ (128 * 1024) #define DUMPMAC_FILENAME_SZ 32 @@ -25087,7 +20231,7 @@ dhd_schedule_macdbg_dump(dhd_pub_t *dhdp) dhd_deferred_work_set_skip(dhdp->info->dhd_deferred_wq, DHD_WQ_WORK_MACDBG, TRUE); } -#endif /* BCMDBG */ +#endif /* BCMDBG && DHD_MACDBG */ /* * This call is to get the memdump size so that, @@ -25110,9 +20254,6 @@ dhd_os_socram_dump(struct net_device *dev, uint32 *dump_size) __FUNCTION__, dhdp->busstate, dhdp->dhd_bus_busy_state)); return BCME_ERROR; } -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(dhdp, TRUE, __builtin_return_address(0)); -#endif /* DHD_PCIE_RUNTIMEPM */ ret = dhd_common_socram_dump(dhdp); if (ret == BCME_OK) { *dump_size = dhdp->soc_ram_length; @@ -25149,30 +20290,44 @@ dhd_os_get_socram_dump(struct net_device *dev, char **buf, uint32 *size) return ret; } -#ifdef EWP_RTT_LOGGING +#ifdef DHD_MAP_PKTID_LOGGING uint32 -dhd_get_rtt_len(void *ndev, dhd_pub_t *dhdp) +dhd_get_pktid_map_logging_len(void *ndev, dhd_pub_t *dhdp, bool is_map) { dhd_info_t *dhd_info; log_dump_section_hdr_t sec_hdr; - int length = 0; - dhd_dbg_ring_t *ring; + uint32 length = 0; if (ndev) { dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); dhdp = &dhd_info->pub; } - if (!dhdp) + if (!dhdp || !dhdp->enable_pktid_log_dump) return length; - if (logdump_rtt_enable && dhdp->rtt_dbg_ring) { - ring = (dhd_dbg_ring_t *)dhdp->rtt_dbg_ring; - length = ring->ring_size + strlen(RTT_LOG_HDR) + sizeof(sec_hdr); - } + length = dhd_pktid_buf_len(dhdp, is_map) + sizeof(sec_hdr); return length; } -#endif /* EWP_RTT_LOGGING */ + +int +dhd_print_pktid_map_log_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos, bool is_map) +{ + dhd_info_t *dhd_info; + + if (dev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) { + return BCME_ERROR; + } + + return dhd_write_pktid_log_dump(dhdp, user_buf, fp, len, pos, is_map); +} +#endif /* DHD_MAP_PKTID_LOGGING */ int dhd_os_get_version(struct net_device *dev, bool dhd_ver, char **buf, uint32 size) @@ -25200,6 +20355,10 @@ dhd_os_get_version(struct net_device *dev, bool dhd_ver, char **buf, uint32 size int dhd_os_get_pktlog_dump(void *dev, const void *user_buf, uint32 len) { +#ifdef DHD_PKT_LOGGING_DBGRING + /* With DHD_PKT_LOGGING_DBGRING, this path is not allowed. */ + return BCME_UNSUPPORTED; +#else int ret = BCME_OK; dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); dhd_pub_t *dhdp = &dhd->pub; @@ -25214,20 +20373,29 @@ dhd_os_get_pktlog_dump(void *dev, const void *user_buf, uint32 len) return ret; } return ret; +#endif /* DHD_PKT_LOGGING_DBGRING */ +} + +spinlock_t * +dhd_os_get_pktlog_lock(dhd_pub_t *dhdp) +{ + return dhdp->pktlog->pktlog_ring->pktlog_ring_lock; } uint32 dhd_os_get_pktlog_dump_size(struct net_device *dev) { - uint32 size = 0; + int ret = 0; dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); dhd_pub_t *dhdp = &dhd->pub; - size = dhd_pktlog_get_dump_length(dhdp); - if (size == 0) { - DHD_ERROR(("%s(): fail to get pktlog size, err = %d\n", __FUNCTION__, size)); + ret = dhd_pktlog_get_dump_length(dhdp); + if (ret < 0) { + DHD_ERROR(("%s(): fail to get pktlog size, err = %d\n", + __FUNCTION__, ret)); + return 0; } - return size; + return ret; } void @@ -25620,7 +20788,9 @@ void custom_xps_map_clear(struct net_device *net) DHD_INFO(("%s : Entered.\n", __FUNCTION__)); rcu_read_lock(); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + dev_maps = rcu_dereference(net->xps_maps[XPS_CPUS]); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) dev_maps = rcu_dereference(net->xps_cpus_map); #else dev_maps = rcu_dereference(net->xps_maps); @@ -25628,7 +20798,9 @@ void custom_xps_map_clear(struct net_device *net) rcu_read_unlock(); if (dev_maps) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + RCU_INIT_POINTER(net->xps_maps[XPS_CPUS], NULL); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) RCU_INIT_POINTER(net->xps_cpus_map, NULL); #else RCU_INIT_POINTER(net->xps_maps, NULL); @@ -25774,73 +20946,6 @@ void custom_rps_map_clear(struct netdev_rx_queue *queue) } #endif // endif -#ifdef DHD_BUZZZ_LOG_ENABLED - -static int -dhd_buzzz_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - - DAEMONIZE("dhd_buzzz"); - - /* signal: thread has started */ - complete(&tsk->completed); - - /* Run until signal received */ - while (1) { - if (down_interruptible(&tsk->sema) == 0) { - if (tsk->terminated) { - break; - } - printk("%s: start to dump...\n", __FUNCTION__); - dhd_buzzz_dump(); - } else { - break; - } - } - complete_and_exit(&tsk->completed, 0); -} - -void* dhd_os_create_buzzz_thread(void) -{ - tsk_ctl_t *thr_buzzz_ctl = NULL; - - thr_buzzz_ctl = kmalloc(sizeof(tsk_ctl_t), GFP_KERNEL); - if (!thr_buzzz_ctl) { - return NULL; - } - - PROC_START(dhd_buzzz_thread, NULL, thr_buzzz_ctl, 0, "dhd_buzzz"); - - return (void *)thr_buzzz_ctl; -} - -void dhd_os_destroy_buzzz_thread(void *thr_hdl) -{ - tsk_ctl_t *thr_buzzz_ctl = (tsk_ctl_t *)thr_hdl; - - if (!thr_buzzz_ctl) { - return; - } - - PROC_STOP(thr_buzzz_ctl); - kfree(thr_buzzz_ctl); -} - -void dhd_os_sched_buzzz_thread(void *thr_hdl) -{ - tsk_ctl_t *thr_buzzz_ctl = (tsk_ctl_t *)thr_hdl; - - if (!thr_buzzz_ctl) { - return; - } - - if (thr_buzzz_ctl->thr_pid >= 0) { - up(&thr_buzzz_ctl->sema); - } -} -#endif /* DHD_BUZZZ_LOG_ENABLED */ - #ifdef DHD_DEBUG_PAGEALLOC /* XXX Additional Kernel implemenation is needed to use this function at * the top of the check_poison_mem() function in mm/debug-pagealloc.c file. @@ -25941,136 +21046,6 @@ dhd_linux_get_primary_netdev(dhd_pub_t *dhdp) return NULL; } -#ifdef DHD_PKTTS -/** - * dhd_msgbuf_get_ipv6_id - return ipv6 identification number - * return 0 in case of error - * - * @pkt: packet pointer - */ -uint -dhd_msgbuf_get_ipv6_id(void *pkt) -{ - struct frag_hdr _frag; - const struct sk_buff *skb; - const struct frag_hdr *fh; - unsigned int offset = 0; - int err; - - skb = (struct sk_buff *)pkt; - err = ipv6_find_hdr(skb, &offset, NEXTHDR_FRAGMENT, NULL, NULL); - if (err < 0) { - return 0; - } - - fh = skb_header_pointer(skb, offset, sizeof(_frag), &_frag); - if (fh == NULL) { - return 0; - } - - return ntohl(fh->identification); -} - -/** - * dhd_create_to_notifier_ts - create BCM_NL_TS netlink socket - * - * @void: - */ -int -dhd_create_to_notifier_ts(void) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) - /* Kernel 3.6 onwards this API accepts only 3 arguments. */ - nl_to_ts = netlink_kernel_create(&init_net, BCM_NL_TS, &dhd_netlink_ts); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) */ - if (!nl_to_ts) { - DHD_ERROR(("Error creating ts socket.\n")); - return -1; - } - DHD_INFO(("nl_to socket created successfully...\n")); - return 0; -} - -/** - * dhd_destroy_to_notifier_ts - destroy BCM_NL_TS netlink socket - * - * @void: - */ -void -dhd_destroy_to_notifier_ts(void) -{ - DHD_INFO(("Destroying nl_to_ts socket\n")); - if (nl_to_ts) { - netlink_kernel_release(nl_to_ts); - nl_to_ts = NULL; - } -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) -/** - * dhd_recv_msg_from_ts - this is called on BCM_NL_TS netlink recv message - * this api updates app pid of app which is currenty using this netlink socket - * - * @skb: rx packet socket buffer - */ -static void -dhd_recv_msg_from_ts(struct sk_buff *skb) -{ - sender_pid_ts = ((struct nlmsghdr *)(skb->data))->nlmsg_pid; - DHD_INFO(("DHD Daemon Started, PID:%d\n", sender_pid_ts)); -} -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) */ - -/** - * dhd_send_msg_to_ts - send data to BCM_NL_TS netlink socket - * - * @skb: socket buffer (unused) - * @data: output data - * @size: size of output data - */ -int -dhd_send_msg_to_ts(struct sk_buff *skb, void *data, int size) -{ - struct nlmsghdr *nlh; - struct sk_buff *skb_out = NULL; - int ret = BCME_ERROR; - - BCM_REFERENCE(skb); - if (sender_pid_ts == 0) { - goto err; - } - - if ((skb_out = nlmsg_new(size, GFP_ATOMIC)) == NULL) { - DHD_ERROR(("%s: skb alloc failed\n", __FUNCTION__)); - goto err; - } - - nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, size, 0); - if (nlh == NULL) { - DHD_ERROR(("%s: nlmsg_put failed\n", __FUNCTION__)); - goto err; - } - - NETLINK_CB(skb_out).dst_group = 0; /* Unicast */ - (void)memcpy_s(nlmsg_data(nlh), size, (char *)data, size); - - if ((ret = nlmsg_unicast(nl_to_ts, skb_out, sender_pid_ts)) < 0) { - DHD_ERROR(("Error sending message, ret:%d\n", ret)); - /* skb is already freed inside nlmsg_unicast() on error case */ - /* explicitly making skb_out to NULL to avoid double free */ - skb_out = NULL; - goto err; - } - return BCME_OK; - -err: - if (skb_out) { - nlmsg_free(skb_out); - } - return ret; -} -#endif /* DHD_PKTTS */ - static int dhd_create_to_notifier_skt(void) { @@ -26088,7 +21063,7 @@ dhd_create_to_notifier_skt(void) #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) */ if (!nl_to_event_sk) { - printf("Error creating socket.\n"); + DHD_CONS_ONLY(("Error creating socket.\n")); return -1; } DHD_INFO(("nl_to socket created successfully...\n")); @@ -26226,9 +21201,10 @@ dhd_dbg_get_system_timestamp(void) osl_do_gettimeofday(&tv); local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60)); rtc_time_to_tm(local_time, &tm); - scnprintf(timebuf, DEBUG_DUMP_TIME_BUF_LEN, - "%02d:%02d:%02d.%06lu", - tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec); + snprintf(timebuf, DEBUG_DUMP_TIME_BUF_LEN, + "%02d-%02d-%02d/%02d:%02d:%02d.%04lu", + tm.tm_year - 100, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, + tm.tm_sec, tv.tv_usec); return timebuf; } @@ -26247,422 +21223,6 @@ dhd_log_dump_get_timestamp(void) return buf; } -#ifdef DHD_LOG_DUMP -bool -dhd_log_dump_ecntr_enabled(void) -{ - return (bool)logdump_ecntr_enable; -} - -bool -dhd_log_dump_rtt_enabled(void) -{ - return (bool)logdump_rtt_enable; -} - -void -dhd_log_dump_init(dhd_pub_t *dhd) -{ - struct dhd_log_dump_buf *dld_buf, *dld_buf_special; - int i = 0; - uint8 *prealloc_buf = NULL, *bufptr = NULL; -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) - int prealloc_idx = DHD_PREALLOC_DHD_LOG_DUMP_BUF; -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ - int ret; - dhd_dbg_ring_t *ring = NULL; - unsigned long flags = 0; - dhd_info_t *dhd_info = dhd->info; -#if defined(EWP_ECNTRS_LOGGING) - void *cookie_buf = NULL; -#endif - - BCM_REFERENCE(ret); - BCM_REFERENCE(ring); - BCM_REFERENCE(flags); - - /* sanity check */ - if (logdump_prsrv_tailsize <= 0 || - logdump_prsrv_tailsize > DHD_LOG_DUMP_MAX_TAIL_FLUSH_SIZE) { - logdump_prsrv_tailsize = DHD_LOG_DUMP_MAX_TAIL_FLUSH_SIZE; - } - /* now adjust the preserve log flush size based on the - * kernel printk log buffer size - */ -#ifdef CONFIG_LOG_BUF_SHIFT - DHD_ERROR(("%s: kernel log buf size = %uKB; logdump_prsrv_tailsize = %uKB;" - " limit prsrv tail size to = %uKB\n", - __FUNCTION__, (1 << CONFIG_LOG_BUF_SHIFT)/1024, - logdump_prsrv_tailsize/1024, LOG_DUMP_KERNEL_TAIL_FLUSH_SIZE/1024)); - - if (logdump_prsrv_tailsize > LOG_DUMP_KERNEL_TAIL_FLUSH_SIZE) { - logdump_prsrv_tailsize = LOG_DUMP_KERNEL_TAIL_FLUSH_SIZE; - } -#else - DHD_ERROR(("%s: logdump_prsrv_tailsize = %uKB \n", - __FUNCTION__, logdump_prsrv_tailsize/1024); -#endif /* CONFIG_LOG_BUF_SHIFT */ - - mutex_init(&dhd_info->logdump_lock); - /* initialize log dump buf structures */ - memset(g_dld_buf, 0, sizeof(struct dhd_log_dump_buf) * DLD_BUFFER_NUM); - - /* set the log dump buffer size based on the module_param */ - if (logdump_max_bufsize > LOG_DUMP_GENERAL_MAX_BUFSIZE || - logdump_max_bufsize <= 0) - dld_buf_size[DLD_BUF_TYPE_GENERAL] = LOG_DUMP_GENERAL_MAX_BUFSIZE; - else - dld_buf_size[DLD_BUF_TYPE_GENERAL] = logdump_max_bufsize; - - /* pre-alloc the memory for the log buffers & 'special' buffer */ - dld_buf_special = &g_dld_buf[DLD_BUF_TYPE_SPECIAL]; -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) - prealloc_buf = DHD_OS_PREALLOC(dhd, prealloc_idx++, LOG_DUMP_TOTAL_BUFSIZE); - dld_buf_special->buffer = DHD_OS_PREALLOC(dhd, prealloc_idx++, - dld_buf_size[DLD_BUF_TYPE_SPECIAL]); -#else - prealloc_buf = MALLOCZ(dhd->osh, LOG_DUMP_TOTAL_BUFSIZE); - dld_buf_special->buffer = MALLOCZ(dhd->osh, dld_buf_size[DLD_BUF_TYPE_SPECIAL]); -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ - - if (!prealloc_buf) { - DHD_ERROR(("Failed to allocate memory for log buffers\n")); - goto fail; - } - if (!dld_buf_special->buffer) { - DHD_ERROR(("Failed to allocate memory for special buffer\n")); - goto fail; - } -#ifdef BCMINTERNAL - DHD_ERROR(("prealloc_buf:%p dld_buf_special->buffer:%p\n", - prealloc_buf, dld_buf_special->buffer)); -#endif /* BCMINTERNAL */ - - bufptr = prealloc_buf; - for (i = 0; i < DLD_BUFFER_NUM; i++) { - dld_buf = &g_dld_buf[i]; - dld_buf->dhd_pub = dhd; - spin_lock_init(&dld_buf->lock); - dld_buf->wraparound = 0; - if (i != DLD_BUF_TYPE_SPECIAL) { - dld_buf->buffer = bufptr; - dld_buf->max = (unsigned long)dld_buf->buffer + dld_buf_size[i]; - bufptr = (uint8 *)dld_buf->max; - } else { - dld_buf->max = (unsigned long)dld_buf->buffer + dld_buf_size[i]; - } - dld_buf->present = dld_buf->front = dld_buf->buffer; - dld_buf->remain = dld_buf_size[i]; - dld_buf->enable = 1; - } - - /* now use the rest of the pre-alloc'd memory for other rings */ -#ifdef EWP_ECNTRS_LOGGING - dhd->ecntr_dbg_ring = dhd_dbg_ring_alloc_init(dhd, - ECNTR_RING_ID, ECNTR_RING_NAME, - LOG_DUMP_ECNTRS_MAX_BUFSIZE, - bufptr, TRUE); - if (!dhd->ecntr_dbg_ring) { - DHD_ERROR(("%s: unable to init ecounters dbg ring !\n", - __FUNCTION__)); - goto fail; - } - bufptr += LOG_DUMP_ECNTRS_MAX_BUFSIZE; -#endif /* EWP_ECNTRS_LOGGING */ - -#ifdef EWP_RTT_LOGGING - dhd->rtt_dbg_ring = dhd_dbg_ring_alloc_init(dhd, - RTT_RING_ID, RTT_RING_NAME, - LOG_DUMP_RTT_MAX_BUFSIZE, - bufptr, TRUE); - if (!dhd->rtt_dbg_ring) { - DHD_ERROR(("%s: unable to init rtt dbg ring !\n", - __FUNCTION__)); - goto fail; - } - bufptr += LOG_DUMP_RTT_MAX_BUFSIZE; -#endif /* EWP_RTT_LOGGING */ - -#ifdef EWP_BCM_TRACE - dhd->bcm_trace_dbg_ring = dhd_dbg_ring_alloc_init(dhd, - BCM_TRACE_RING_ID, BCM_TRACE_RING_NAME, - LOG_DUMP_BCM_TRACE_MAX_BUFSIZE, - bufptr, TRUE); - if (!dhd->bcm_trace_dbg_ring) { - DHD_ERROR(("%s: unable to init bcm trace dbg ring !\n", - __FUNCTION__)); - goto fail; - } - bufptr += LOG_DUMP_BCM_TRACE_MAX_BUFSIZE; -#endif /* EWP_BCM_TRACE */ - - /* Concise buffer is used as intermediate buffer for following purposes - * a) pull ecounters records temporarily before - * writing it to file - * b) to store dhd dump data before putting it to file - * It should have a size equal to - * MAX(largest possible ecntr record, 'dhd dump' data size) - */ - dhd->concise_dbg_buf = MALLOC(dhd->osh, CONCISE_DUMP_BUFLEN); - if (!dhd->concise_dbg_buf) { - DHD_ERROR(("%s: unable to alloc mem for concise debug info !\n", - __FUNCTION__)); - goto fail; - } - -#if defined(DHD_EVENT_LOG_FILTER) - /* XXX init filter last, because filter use buffer which alloced by log dump */ - ret = dhd_event_log_filter_init(dhd, - bufptr, - LOG_DUMP_FILTER_MAX_BUFSIZE); - if (ret != BCME_OK) { - goto fail; - } -#endif /* DHD_EVENT_LOG_FILTER */ - -#if defined(EWP_ECNTRS_LOGGING) - cookie_buf = MALLOC(dhd->osh, LOG_DUMP_COOKIE_BUFSIZE); - if (!cookie_buf) { - DHD_ERROR(("%s: unable to alloc mem for logdump cookie buffer\n", - __FUNCTION__)); - goto fail; - } - - ret = dhd_logdump_cookie_init(dhd, cookie_buf, LOG_DUMP_COOKIE_BUFSIZE); - if (ret != BCME_OK) { - MFREE(dhd->osh, cookie_buf, LOG_DUMP_COOKIE_BUFSIZE); - goto fail; - } -#endif /* EWP_ECNTRS_LOGGING */ - return; - -fail: - -#if defined(DHD_EVENT_LOG_FILTER) - /* XXX deinit filter first, because filter use buffer which alloced by log dump */ - if (dhd->event_log_filter) { - dhd_event_log_filter_deinit(dhd); - } -#endif /* DHD_EVENT_LOG_FILTER */ - - if (dhd->concise_dbg_buf) { - MFREE(dhd->osh, dhd->concise_dbg_buf, CONCISE_DUMP_BUFLEN); - } - -#ifdef EWP_ECNTRS_LOGGING - if (dhd->logdump_cookie) { - dhd_logdump_cookie_deinit(dhd); - MFREE(dhd->osh, dhd->logdump_cookie, LOG_DUMP_COOKIE_BUFSIZE); - dhd->logdump_cookie = NULL; - } -#endif /* EWP_ECNTRS_LOGGING */ - -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) - if (prealloc_buf) { - DHD_OS_PREFREE(dhd, prealloc_buf, LOG_DUMP_TOTAL_BUFSIZE); - } - if (dld_buf_special->buffer) { - DHD_OS_PREFREE(dhd, dld_buf_special->buffer, - dld_buf_size[DLD_BUF_TYPE_SPECIAL]); - } -#else - if (prealloc_buf) { - MFREE(dhd->osh, prealloc_buf, LOG_DUMP_TOTAL_BUFSIZE); - } - if (dld_buf_special->buffer) { - MFREE(dhd->osh, dld_buf_special->buffer, - dld_buf_size[DLD_BUF_TYPE_SPECIAL]); - } -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - for (i = 0; i < DLD_BUFFER_NUM; i++) { - dld_buf = &g_dld_buf[i]; - dld_buf->enable = 0; - dld_buf->buffer = NULL; - } - mutex_destroy(&dhd_info->logdump_lock); -} - -void -dhd_log_dump_deinit(dhd_pub_t *dhd) -{ - struct dhd_log_dump_buf *dld_buf = NULL, *dld_buf_special = NULL; - int i = 0; - dhd_info_t *dhd_info = dhd->info; - dhd_dbg_ring_t *ring = NULL; - - BCM_REFERENCE(ring); - - if (dhd->concise_dbg_buf) { - MFREE(dhd->osh, dhd->concise_dbg_buf, CONCISE_DUMP_BUFLEN); - dhd->concise_dbg_buf = NULL; - } - -#ifdef EWP_ECNTRS_LOGGING - if (dhd->logdump_cookie) { - dhd_logdump_cookie_deinit(dhd); - MFREE(dhd->osh, dhd->logdump_cookie, LOG_DUMP_COOKIE_BUFSIZE); - dhd->logdump_cookie = NULL; - } - - if (dhd->ecntr_dbg_ring) { - dhd_dbg_ring_dealloc_deinit(&dhd->ecntr_dbg_ring, dhd); - } -#endif /* EWP_ECNTRS_LOGGING */ - -#ifdef EWP_RTT_LOGGING - if (dhd->rtt_dbg_ring) { - dhd_dbg_ring_dealloc_deinit(&dhd->rtt_dbg_ring, dhd); - } -#endif /* EWP_RTT_LOGGING */ - -#ifdef EWP_BCM_TRACE - if (dhd->bcm_trace_dbg_ring) { - dhd_dbg_ring_dealloc_deinit(&dhd->bcm_trace_dbg_ring, dhd); - } -#endif /* EWP_BCM_TRACE */ - - /* 'general' buffer points to start of the pre-alloc'd memory */ - dld_buf = &g_dld_buf[DLD_BUF_TYPE_GENERAL]; - dld_buf_special = &g_dld_buf[DLD_BUF_TYPE_SPECIAL]; -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) - if (dld_buf->buffer) { - DHD_OS_PREFREE(dhd, dld_buf->buffer, LOG_DUMP_TOTAL_BUFSIZE); - } - if (dld_buf_special->buffer) { - DHD_OS_PREFREE(dhd, dld_buf_special->buffer, - dld_buf_size[DLD_BUF_TYPE_SPECIAL]); - } -#else - if (dld_buf->buffer) { - MFREE(dhd->osh, dld_buf->buffer, LOG_DUMP_TOTAL_BUFSIZE); - } - if (dld_buf_special->buffer) { - MFREE(dhd->osh, dld_buf_special->buffer, - dld_buf_size[DLD_BUF_TYPE_SPECIAL]); - } -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - for (i = 0; i < DLD_BUFFER_NUM; i++) { - dld_buf = &g_dld_buf[i]; - dld_buf->enable = 0; - dld_buf->buffer = NULL; - } - mutex_destroy(&dhd_info->logdump_lock); -} - -void -dhd_log_dump_write(int type, char *binary_data, - int binary_len, const char *fmt, ...) -{ - int len = 0; - char tmp_buf[DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE] = {0, }; - va_list args; - unsigned long flags = 0; - struct dhd_log_dump_buf *dld_buf = NULL; - bool flush_log = FALSE; - - if (type < 0 || type >= DLD_BUFFER_NUM) { - DHD_INFO(("%s: Unsupported DHD_LOG_DUMP_BUF_TYPE(%d).\n", - __FUNCTION__, type)); - return; - } - - dld_buf = &g_dld_buf[type]; - if (dld_buf->enable != 1) { - return; - } - - va_start(args, fmt); - len = vsnprintf(tmp_buf, DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE, fmt, args); - /* Non ANSI C99 compliant returns -1, - * ANSI compliant return len >= DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE - */ - va_end(args); - if (len < 0) { - return; - } - - if (len >= DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE) { - len = DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE - 1; - tmp_buf[len] = '\0'; - } - - /* make a critical section to eliminate race conditions */ - DHD_LOG_DUMP_BUF_LOCK(&dld_buf->lock, flags); - if (dld_buf->remain < len) { - dld_buf->wraparound = 1; - dld_buf->present = dld_buf->front; - dld_buf->remain = dld_buf_size[type]; - /* if wrap around happens, flush the ring buffer to the file */ - flush_log = TRUE; - } - - memcpy(dld_buf->present, tmp_buf, len); - dld_buf->remain -= len; - dld_buf->present += len; - DHD_LOG_DUMP_BUF_UNLOCK(&dld_buf->lock, flags); - - /* double check invalid memory operation */ - ASSERT((unsigned long)dld_buf->present <= dld_buf->max); - - if (dld_buf->dhd_pub) { - dhd_pub_t *dhdp = (dhd_pub_t *)dld_buf->dhd_pub; - dhdp->logdump_periodic_flush = - logdump_periodic_flush; - if (logdump_periodic_flush && flush_log) { - log_dump_type_t *flush_type = MALLOCZ(dhdp->osh, - sizeof(log_dump_type_t)); - if (flush_type) { - *flush_type = type; - dhd_schedule_log_dump(dld_buf->dhd_pub, flush_type); - } - } - } -} - -#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING -extern struct dhd_dbg_ring_buf g_ring_buf; -void -dhd_dbg_ring_write(int type, char *binary_data, - int binary_len, const char *fmt, ...) -{ - int len = 0; - va_list args; - struct dhd_dbg_ring_buf *ring_buf = NULL; - char tmp_buf[DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE] = {0, }; - - ring_buf = &g_ring_buf; - - va_start(args, fmt); - len = vsnprintf(tmp_buf, DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE, fmt, args); - /* Non ANSI C99 compliant returns -1, - * ANSI compliant return len >= DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE - */ - va_end(args); - if (len < 0) { - return; - } - - if (len >= DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE) { - len = DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE - 1; - tmp_buf[len] = '\0'; - } - - if (ring_buf->dhd_pub) { - dhd_pub_t *dhdp = (dhd_pub_t *)ring_buf->dhd_pub; - if (type == DRIVER_LOG_RING_ID || type == FW_VERBOSE_RING_ID || - type == ROAM_STATS_RING_ID) { - if (DBG_RING_ACTIVE(dhdp, type)) { - dhd_os_push_push_ring_data(dhdp, type, - tmp_buf, strlen(tmp_buf)); - return; - } - } - } - return; -} -#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ -#endif /* DHD_LOG_DUMP */ - #ifdef DHD_PCIE_NATIVE_RUNTIMEPM void dhd_flush_rx_tx_wq(dhd_pub_t *dhdp) @@ -26739,14 +21299,16 @@ dhd_debug_uart_exec(dhd_pub_t *dhdp, char *cmd) #endif /* DHD_DEBUG_UART */ #if defined(DHD_BLOB_EXISTENCE_CHECK) +#ifdef DHD_LINUX_STD_FW_API void dhd_set_blob_support(dhd_pub_t *dhdp, char *fw_path) { - struct file *fp; - char *filepath = VENDOR_PATH CONFIG_BCMDHD_CLM_PATH; + char *filepath = DHD_CLM_NAME; + const struct firmware *fw = NULL; + int ret = 0; - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { + ret = dhd_os_get_img_fwreq(&fw, filepath); + if (ret < 0) { DHD_ERROR(("%s: ----- blob file doesn't exist (%s) -----\n", __FUNCTION__, filepath)); dhdp->is_blob = FALSE; @@ -26758,9 +21320,33 @@ dhd_set_blob_support(dhd_pub_t *dhdp, char *fw_path) #else BCM_REFERENCE(fw_path); #endif /* SKIP_CONCATE_BLOB */ - filp_close(fp, NULL); + dhd_os_close_img_fwreq(fw); } } +#else +void +dhd_set_blob_support(dhd_pub_t *dhdp, char *fw_path) +{ + struct file *fp; + char *filepath = dhdp->info->clm_path; + + fp = dhd_filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { + DHD_ERROR(("%s: ----- blob file doesn't exist (%s) -----\n", __FUNCTION__, + filepath)); + dhdp->is_blob = FALSE; + } else { + DHD_ERROR(("%s: ----- blob file exists (%s) -----\n", __FUNCTION__, filepath)); + dhdp->is_blob = TRUE; +#if defined(CONCATE_BLOB) + strncat(fw_path, "_blob", strlen("_blob")); +#else + BCM_REFERENCE(fw_path); +#endif /* SKIP_CONCATE_BLOB */ + dhd_filp_close(fp, NULL); + } +} +#endif /* DHD_LINUX_STD_FW_API */ #endif /* DHD_BLOB_EXISTENCE_CHECK */ #if defined(PCIE_FULL_DONGLE) @@ -26796,133 +21382,31 @@ dhd_schedule_dmaxfer_free(dhd_pub_t *dhdp, dmaxref_mem_map_t *dmmap) } #endif /* PCIE_FULL_DONGLE */ /* ---------------------------- End of sysfs implementation ------------------------------------- */ -#ifdef SET_PCIE_IRQ_CPU_CORE -void -dhd_set_irq_cpucore(dhd_pub_t *dhdp, int affinity_cmd) -{ - unsigned int pcie_irq = 0; -#if defined(DHD_LB) && defined(DHD_LB_HOST_CTRL) - struct dhd_info *dhd = NULL; -#endif /* DHD_LB && DHD_LB_HOST_CTRL */ - - if (!dhdp) { - DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); - return; - } - - if (!dhdp->bus) { - DHD_ERROR(("%s : dhd->bus is NULL\n", __FUNCTION__)); - return; - } - - if (affinity_cmd < DHD_AFFINITY_OFF || affinity_cmd > DHD_AFFINITY_LAST) { - DHD_ERROR(("Wrong Affinity cmds:%d, %s\n", affinity_cmd, __FUNCTION__)); - return; - } - - DHD_ERROR(("Enter %s, PCIe affinity cmd=0x%x\n", __FUNCTION__, affinity_cmd)); - - if (dhdpcie_get_pcieirq(dhdp->bus, &pcie_irq)) { - DHD_ERROR(("%s : Can't get interrupt number\n", __FUNCTION__)); - return; - } - -#if defined(DHD_LB) && defined(DHD_LB_HOST_CTRL) - dhd = dhdp->info; - - if (affinity_cmd == DHD_AFFINITY_OFF) { - dhd->permitted_primary_cpu = FALSE; - } else if (affinity_cmd == DHD_AFFINITY_TPUT_150MBPS || - affinity_cmd == DHD_AFFINITY_TPUT_300MBPS) { - dhd->permitted_primary_cpu = TRUE; - } - dhd_select_cpu_candidacy(dhd); - /* - * It needs to NAPI disable -> enable to raise NET_RX napi CPU core - * during Rx traffic - * NET_RX does not move to NAPI CPU core if continusly calling napi polling - * function - */ - napi_disable(&dhd->rx_napi_struct); - napi_enable(&dhd->rx_napi_struct); -#endif /* DHD_LB && DHD_LB_HOST_CTRL */ - - /* - irq_set_affinity() assign dedicated CPU core PCIe interrupt - If dedicated CPU core is not on-line, - PCIe interrupt scheduled on CPU core 0 - */ -#if defined(CONFIG_ARCH_SM8150) || defined(CONFIG_ARCH_KONA) - /* For SDM platform */ - switch (affinity_cmd) { - case DHD_AFFINITY_OFF: -#if defined(DHD_LB) && defined(DHD_LB_HOST_CTRL) - irq_set_affinity_hint(pcie_irq, dhdp->info->cpumask_secondary); - irq_set_affinity(pcie_irq, dhdp->info->cpumask_secondary); -#endif /* DHD_LB && DHD_LB_HOST_CTRL */ - break; - case DHD_AFFINITY_TPUT_150MBPS: - case DHD_AFFINITY_TPUT_300MBPS: - irq_set_affinity_hint(pcie_irq, dhdp->info->cpumask_primary); - irq_set_affinity(pcie_irq, dhdp->info->cpumask_primary); - break; - default: - DHD_ERROR(("%s, Unknown PCIe affinity cmd=0x%x\n", - __FUNCTION__, affinity_cmd)); - } -#elif defined(CONFIG_SOC_EXYNOS9810) || defined(CONFIG_SOC_EXYNOS9820) || \ - defined(CONFIG_SOC_EXYNOS9830) - /* For Exynos platform */ - switch (affinity_cmd) { - case DHD_AFFINITY_OFF: -#if defined(DHD_LB) && defined(DHD_LB_HOST_CTRL) - irq_set_affinity(pcie_irq, dhdp->info->cpumask_secondary); -#endif /* DHD_LB && DHD_LB_HOST_CTRL */ - break; - case DHD_AFFINITY_TPUT_150MBPS: - irq_set_affinity(pcie_irq, dhdp->info->cpumask_primary); - break; - case DHD_AFFINITY_TPUT_300MBPS: - DHD_ERROR(("%s, PCIe IRQ:%u set Core %d\n", - __FUNCTION__, pcie_irq, PCIE_IRQ_CPU_CORE)); - irq_set_affinity(pcie_irq, cpumask_of(PCIE_IRQ_CPU_CORE)); - break; - default: - DHD_ERROR(("%s, Unknown PCIe affinity cmd=0x%x\n", - __FUNCTION__, affinity_cmd)); - } -#else /* For Undefined platform */ - DHD_ERROR(("%s, Unknown PCIe affinity cmd=0x%x\n", - __FUNCTION__, affinity_cmd)); -#endif /* End of Platfrom define */ - -} -#endif /* SET_PCIE_IRQ_CPU_CORE */ int dhd_write_file(const char *filepath, char *buf, int buf_len) { struct file *fp = NULL; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs mm_segment_t old_fs; -#endif +#endif /* get_fs */ int ret = 0; +#ifdef get_fs /* change to KERNEL_DS address limit */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) old_fs = get_fs(); set_fs(KERNEL_DS); -#endif +#endif /* get_fs */ /* File is always created. */ - fp = filp_open(filepath, O_RDWR | O_CREAT, 0664); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, O_RDWR | O_CREAT, 0664); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: Couldn't open file '%s' err %ld\n", __FUNCTION__, filepath, PTR_ERR(fp))); ret = BCME_ERROR; } else { if (fp->f_mode & FMODE_WRITE) { - ret = vfs_write(fp, buf, buf_len, &fp->f_pos); + ret = dhd_vfs_write(fp, buf, buf_len, &fp->f_pos); if (ret < 0) { DHD_ERROR(("%s: Couldn't write file '%s'\n", __FUNCTION__, filepath)); @@ -26931,13 +21415,13 @@ dhd_write_file(const char *filepath, char *buf, int buf_len) ret = BCME_OK; } } - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); } +#ifdef get_fs /* restore previous address limit */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) set_fs(old_fs); -#endif +#endif /* get_fs */ return ret; } @@ -26946,33 +21430,33 @@ int dhd_read_file(const char *filepath, char *buf, int buf_len) { struct file *fp = NULL; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#ifdef get_fs mm_segment_t old_fs; -#endif +#endif /* get_fs */ int ret; +#ifdef get_fs /* change to KERNEL_DS address limit */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) old_fs = get_fs(); set_fs(KERNEL_DS); -#endif +#endif /* get_fs */ - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) + fp = dhd_filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { +#ifdef get_fs set_fs(old_fs); -#endif +#endif /* get_fs */ DHD_ERROR(("%s: File %s doesn't exist\n", __FUNCTION__, filepath)); return BCME_ERROR; } - ret = kernel_read_compat(fp, 0, buf, buf_len); - filp_close(fp, NULL); + ret = dhd_kernel_read_compat(fp, 0, buf, buf_len); + dhd_filp_close(fp, NULL); +#ifdef get_fs /* restore previous address limit */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) set_fs(old_fs); -#endif +#endif /* get_fs */ /* Return the number of bytes read */ if (ret > 0) { @@ -27007,8 +21491,15 @@ dhd_write_file_and_check(const char *filepath, char *buf, int buf_len) #ifdef FILTER_IE int dhd_read_from_file(dhd_pub_t *dhd) { - int ret = 0, nread = 0; + int ret = 0; +#ifdef DHD_LINUX_STD_FW_API + const struct firmware *fw = NULL; + char *filepath = FILTER_IE_PATH; + int filelen = 0; +#else + int nread = 0; void *fd; +#endif /* DHD_LINUX_STD_FW_API */ uint8 *buf; NULL_CHECK(dhd, "dhd is NULL", ret); @@ -27019,6 +21510,32 @@ int dhd_read_from_file(dhd_pub_t *dhd) } /* open file to read */ +#ifdef DHD_LINUX_STD_FW_API + ret = dhd_os_get_img_fwreq(&fw, filepath); + if (ret < 0) { + DHD_ERROR(("dhd_os_get_img_fwreq(%s) error : %d\n", + filepath, ret)); + goto exit; + } + + filelen = fw->size; + if (filelen == 0) { + DHD_ERROR(("error: zero length file.failed to read\n")); + ret = BCME_ERROR; + goto exit; + } + + ret = memcpy_s(buf, FILE_BLOCK_READ_SIZE, fw->data, fw->size); + if (ret < 0) { + DHD_ERROR((" memcpy_s() error : %d\n", ret)); + goto exit; + } + + ret = dhd_parse_filter_ie(dhd, buf); + if (ret < 0) { + DHD_ERROR(("error: failed to parse filter ie\n")); + } +#else fd = dhd_os_open_image1(dhd, FILTER_IE_PATH); if (!fd) { DHD_ERROR(("No filter file(not an error), filter path%s\n", FILTER_IE_PATH)); @@ -27035,8 +21552,15 @@ int dhd_read_from_file(dhd_pub_t *dhd) DHD_ERROR(("error: zero length file.failed to read\n")); ret = BCME_ERROR; } - dhd_os_close_image1(dhd, fd); +#endif /* DHD_LINUX_STD_FW_API */ exit: +#ifdef DHD_LINUX_STD_FW_API + if (fw) { + dhd_os_close_img_fwreq(fw); + } +#else + dhd_os_close_image1(dhd, fd); +#endif /* DHD_LINUX_STD_FW_API */ if (buf) { MFREE(dhd->osh, buf, FILE_BLOCK_READ_SIZE); } @@ -27111,10 +21635,6 @@ int dhd_check_valid_ie(dhd_pub_t *dhdp, uint8* buf, int len) } i++; } - if (bcm_atoi((char*)buf) > 255) { - DHD_ERROR(("error: element id cannot be greater than 255 \n")); - return BCME_ERROR; - } return BCME_OK; } @@ -27141,7 +21661,7 @@ int dhd_parse_filter_ie(dhd_pub_t *dhd, uint8 *buf) } /* setup filter iovar header */ - p_filter_iov->version = WL_FILTER_IE_VERSION; + p_filter_iov->version = WL_FILTER_IE_VERSION_1; p_filter_iov->len = filter_iovsize; p_filter_iov->fixed_length = p_filter_iov->len - FILTER_IE_BUFSZ; p_filter_iov->pktflag = FC_PROBE_REQ; @@ -27274,15 +21794,7 @@ int dhd_get_random_bytes(uint8 *buf, uint len) { #ifdef BCMPCIE -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) - int rndlen = get_random_bytes_arch(buf, len); - if (rndlen != len) { - bzero(buf, len); - get_random_bytes(buf, len); - } -#else - get_random_bytes_arch(buf, len); -#endif + get_random_bytes(buf, len); #endif /* BCMPCIE */ return BCME_OK; } @@ -27377,188 +21889,6 @@ dhd_make_hang_with_reason(struct net_device *dev, const char *string_num) } #endif /* DHD_HANG_SEND_UP_TEST */ -#ifdef BT_OVER_PCIE -#define BT_QUIESCE TRUE -#define BT_RESUME FALSE -#define BT_QUIESCE_RESPONSE_TIMEOUT 4000 - -int -dhd_request_bt_quiesce(dhd_pub_t *dhdp) -{ - dhd_info_t * dhd = (dhd_info_t *)(dhdp->info); - long timeout = BT_QUIESCE_RESPONSE_TIMEOUT; - - if (request_bt_quiesce_ptr == NULL) { - DHD_ERROR(("%s: BT not loaded\n", __FUNCTION__)); - return BCME_OK; - } - - mutex_lock(&dhd->quiesce_lock); - DHD_ERROR(("%s: start quiesce_state = %d\n", __FUNCTION__, dhd->dhd_quiesce_state)); - if (dhd->dhd_quiesce_state != DHD_QUIESCE_INIT) { - DHD_ERROR(("%s: start quiesce_state = %d\n", __FUNCTION__, dhd->dhd_quiesce_state)); - mutex_unlock(&dhd->quiesce_lock); - return BCME_ERROR; - } - dhd->dhd_quiesce_state = REQUEST_BT_QUIESCE; - request_bt_quiesce_ptr(BT_QUIESCE); - - timeout = wait_event_timeout(dhd->quiesce_wait, - (dhd->dhd_quiesce_state == RESPONSE_BT_QUIESCE), timeout); - - DHD_ERROR(("%s: after wait quiesce_state = %d\n", __FUNCTION__, dhd->dhd_quiesce_state)); - - mutex_unlock(&dhd->quiesce_lock); - if (!timeout) { - DHD_ERROR(("%s: timeout quiesce_state = %d\n", - __FUNCTION__, dhd->dhd_quiesce_state)); - return BCME_BUSY; - } - return BCME_OK; -} - -int -dhd_request_bt_resume(dhd_pub_t *dhdp) -{ - dhd_info_t * dhd = (dhd_info_t *)(dhdp->info); - long timeout = BT_QUIESCE_RESPONSE_TIMEOUT; - - if (request_bt_quiesce_ptr == NULL) { - DHD_ERROR(("%s: BT not loaded\n", __FUNCTION__)); - return BCME_OK; - } - - DHD_ERROR(("%s: start quiesce_state = %d\n", __FUNCTION__, dhd->dhd_quiesce_state)); - mutex_lock(&dhd->quiesce_lock); - if (dhd->dhd_quiesce_state != RESPONSE_BT_QUIESCE) { - mutex_unlock(&dhd->quiesce_lock); - return BCME_ERROR; - } - dhd->dhd_quiesce_state = REQUEST_BT_RESUME; - request_bt_quiesce_ptr(BT_RESUME); - - timeout = wait_event_timeout(dhd->quiesce_wait, - (dhd->dhd_quiesce_state == RESPONSE_BT_RESUME), timeout); - - DHD_ERROR(("%s: after wait quiesce_state = %d\n", __FUNCTION__, dhd->dhd_quiesce_state)); - - dhd->dhd_quiesce_state = DHD_QUIESCE_INIT; - mutex_unlock(&dhd->quiesce_lock); - if (!timeout) { - DHD_ERROR(("%s: timeout quiesce_state = %d\n", - __FUNCTION__, dhd->dhd_quiesce_state)); - return BCME_BUSY; - } - return BCME_OK; -} - -void -response_bt_quiesce(bool quiesce) -{ - dhd_pub_t *dhdp = g_dhd_pub; - dhd_info_t * dhd = (dhd_info_t *)(dhdp->info); - if (quiesce == BT_QUIESCE) { - if (dhd->dhd_quiesce_state == REQUEST_BT_QUIESCE) { - dhd->dhd_quiesce_state = RESPONSE_BT_QUIESCE; - wake_up(&dhd->quiesce_wait); - return; - } - } else if (quiesce == BT_RESUME) { - if (dhd->dhd_quiesce_state == REQUEST_BT_RESUME) { - dhd->dhd_quiesce_state = RESPONSE_BT_RESUME; - wake_up(&dhd->quiesce_wait); - return; - } - } - DHD_ERROR(("%s: Wrong Queisce Response=%d in State=%d\n", - __FUNCTION__, quiesce, dhd->dhd_quiesce_state)); - return; -} - -int -dhd_bus_perform_flr_with_quiesce(dhd_pub_t *dhdp, struct dhd_bus *bus, - bool init_deinit_path) -{ - int ret; - dhd_info_t * dhd = (dhd_info_t *)(dhdp->info); - bool dongle_isolation = dhdp->dongle_isolation; - mutex_lock(&dhd->quiesce_flr_lock); - dhd->dhd_quiesce_state = DHD_QUIESCE_INIT; - - /* pause data on all the interfaces */ - dhd_bus_stop_queue(dhdp->bus); - - /* Since we are about to do FLR advertise that bus down is in progress - * to other bus user contexts like Tx, Rx, IOVAR, WD etc - */ - dhdpcie_advertise_bus_cleanup(dhdp); - -#ifdef BT_OVER_PCIE - /* Disable L1SS of RC and EP - * L1SS is enabled again in dhd_bus_start if dhd_sync_with_dongle succeed - */ - dhd_bus_l1ss_enable_rc_ep(dhdp->bus, FALSE); -#endif /* BT_OVER_PCIE */ - - if (dhd_bus_force_bt_quiesce_enabled(dhdp->bus)) { - DHD_ERROR(("%s: Request Quiesce\n", __FUNCTION__)); - /* Request BT quiesce right before F0 FLR to minimise latency */ - ret = dhd_request_bt_quiesce(dhdp); /* Handle return value */ - if (ret != BCME_OK) { - DHD_ERROR(("%s: Error(%d) in Request Quiesce\n", __FUNCTION__, ret)); - /* TODO: plugin API for Toggle REGON Here */ - mutex_unlock(&dhd->quiesce_flr_lock); - return ret; - } - } - - dhd_bus_pcie_pwr_req_reload_war(dhdp->bus); - - DHD_ERROR(("%s: Perform FLR\n", __FUNCTION__)); - - ret = dhd_bus_perform_flr(dhdp->bus, dhd_bus_get_flr_force_fail(dhdp->bus)); - if (ret != BCME_OK) { - DHD_ERROR(("%s: Error(%d) in Performing FLR\n", __FUNCTION__, ret)); - /* TODO: Ensure that BT Host Driver is out of Quiesce state before REGON - * Either by sending an unquiesce message Here OR as a part of ON/OFF API. - */ - /* TODO: plugin API for Toggle REGON Here */ - mutex_unlock(&dhd->quiesce_flr_lock); - return ret; - } - - if (dhd_bus_force_bt_quiesce_enabled(dhdp->bus)) { - DHD_ERROR(("%s: Request Resume\n", __FUNCTION__)); - /* Resume BT right after F0 FLR to minimise latency */ - ret = dhd_request_bt_resume(dhdp); /* Handle return value */ - if (ret != BCME_OK) { - DHD_ERROR(("%s: Error(%d) in Request Resume\n", __FUNCTION__, ret)); - /* TODO: plugin API for Toggle REGON Here */ - mutex_unlock(&dhd->quiesce_flr_lock); - return ret; - } - } - - /* Devreset function will perform FLR again, to avoid it set dongle_isolation */ - dhdp->dongle_isolation = TRUE; - - DHD_ERROR(("%s: Devreset ON\n", __FUNCTION__)); - dhd_bus_devreset(dhdp, 1); /* DHD structure cleanup */ - - DHD_ERROR(("%s: Devreset OFF\n", __FUNCTION__)); - dhd_bus_devreset(dhdp, 0); /* DHD structure re-init */ - - dhdp->dongle_isolation = dongle_isolation; /* Restore the old value */ - - /* resume data on all the interfaces */ - dhd_bus_start_queue(dhdp->bus); - mutex_unlock(&dhd->quiesce_flr_lock); - - DHD_ERROR(("%s: done\n", __FUNCTION__)); - return BCME_DNGL_DEVRESET; -} -#endif /* BT_OVER_PCIE */ - #ifdef DHD_TX_PROFILE static int process_layer2_headers(uint8 **p, int *plen, uint16 *type, bool is_host_sfhllc) @@ -27721,52 +22051,6 @@ dhd_protocol_matches_profile(uint8 *p, int plen, const dhd_tx_profile_protocol_t } #endif /* defined(DHD_TX_PROFILE) */ -#ifdef DHD_TIMESYNC -void -BCMFASTPATH(dhd_parse_proto)(uint8 *pktdata, dhd_pkt_parse_t *parse) -{ - uint8 *pkt = NULL; - struct iphdr *iph = NULL; - struct ether_header *eh = (struct ether_header *)pktdata; - - if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) { - pkt = (uint8 *)&pktdata[ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN]; - } else { - pkt = (uint8 *)&pktdata[ETHER_HDR_LEN]; - } - - iph = (struct iphdr *)pkt; - - parse->proto = IP_PROT_RESERVED; - parse->t1 = 0; - parse->t2 = 0; - - /* check IP header */ - if ((IPV4_HLEN(iph) != IPV4_HLEN_MIN) || (IP_VER(iph) != IP_VER_4)) { - return; - } - - if (iph->protocol == IP_PROT_ICMP) { - struct icmphdr *icmph; - - parse->proto = iph->protocol; - icmph = (struct icmphdr *)((uint8 *)pkt + sizeof(struct iphdr)); - - if ((icmph->type == ICMP_ECHO) || (icmph->type == ICMP_ECHOREPLY)) { - parse->t1 = icmph->type; - parse->t2 = ntoh16(icmph->un.echo.sequence); - } else { - parse->t1 = icmph->type; - parse->t2 = icmph->code; - } - } else { - parse->proto = iph->protocol; - } - - return; -} -#endif /* DHD_TIMESYNC */ - #ifdef BCMPCIE #define KIRQ_PRINT_BUF_LEN 256 @@ -27780,10 +22064,10 @@ dhd_print_kirqstats(dhd_pub_t *dhd, unsigned int irq_num) char tmp_buf[KIRQ_PRINT_BUF_LEN]; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) - desc = irq_data_to_desc(irq_get_irq_data(irq_num)); -#else +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)) desc = irq_to_desc(irq_num); +#else // (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)) + desc = irq_data_to_desc(irq_get_irq_data(irq_num)); #endif // (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)) if (!desc) { DHD_ERROR(("%s : irqdesc is not found \n", __FUNCTION__)); @@ -27866,6 +22150,9 @@ dhd_print_tasklet_status(dhd_pub_t *dhd) } DHD_ERROR(("DHD Tasklet status : 0x%lx\n", dhdinfo->tasklet.state)); +#ifndef BCMDBUS + DHD_ERROR(("DPC thread thr_pid: %ld\n", dhdinfo->thr_dpc_ctl.thr_pid)); +#endif /* BCMDBUS */ } #if defined(DHD_MQ) && defined(DHD_MQ_STATS) @@ -27909,358 +22196,6 @@ dhd_mqstats_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) } #endif /* DHD_MQ && DHD_MQ_STATS */ -#if defined(GDB_PROXY) && defined(PCIE_FULL_DONGLE) && defined(BCMINTERNAL) -/* Procfs that provides to GDB Proxy asynchronous access to "sbreg", "membytes", - * "gdb_proxy_probe", "gdb_proxy_stop_count" iovars. - * Procfs is comprised of the root directory, - * /proc/dhd_gdb_proxy_ (here is like 'eth0', - * etc.) that contains files: "sbreg", "membytes", "gdb_proxy_probe", - * "gdb_proxy_stop_count". These files are to be used to access respective - * iovars. Difference from iovar is that access to these files is not blocked - * by current iovar processing (i.e. file might be accessed while wl iovar is - * stuck on breakpoint inside firmware) - * Setting address for "membytes" and "sbreg" files is performed by means of - * seek position - * For now "membytes" and "sbreg" may only be used to read/write 1, 2 or 4 - * bytes - this may be expanded later. - * For now "gdb_proxy_probe" only returns current Proxy ID, but does not set - * a new one (unlike iovar that may do both things) - */ - -/* Size of firmware address space */ -#define GDB_PROXY_FS_MEM_SIZE ((loff_t)1 << 32) - -/* Common part of 'llseek' routine for all files */ -static loff_t -gdb_proxy_fs_llseek(struct file *fp, loff_t off, int whence, loff_t file_len) -{ - loff_t pos = -1; - - switch (whence) { - case SEEK_SET: - pos = off; - break; - case SEEK_CUR: - pos = fp->f_pos + off; - break; - case SEEK_END: - pos = file_len - off; - break; - } - if ((pos < 0) || (pos > file_len)) { - return -EINVAL; - } - fp->f_pos = pos; - return pos; -} - -/* Common read/write procedure for "gdb_proxy_probe" and "gdb_proxy_stop_count" - * procfs files - * fp: file descriptor - * user_buffer_in: userspace buffer address for write operation, NULL for read - * operation - * user_buffer_out: userspace buffer address for read operation, NULL for write - * operation - * count: maximum number of bytes to read/write - * position: seek position incremented by length of data read/written - * iovar: name of iovar being accessed - * iovar_data_buf: intermediate buffer to store iovar data - * iovar_data_len: length of data, corresponded to iovar - * read_params: NULL or address of input parameter for iovar read - * read_plen: 0 or length of input parameter for iovar read - * Returns number of bytes read/written or error code - */ -static ssize_t -gdb_proxy_fs_iovar_data_op(struct file *fp, const char __user *user_buffer_in, - char __user *user_buffer_out, size_t count, loff_t *position, - const char *iovar, void *iovar_data_buf, size_t iovar_data_len, - void *read_params, size_t read_plen) -{ - dhd_info_t *dhd = (dhd_info_t *)PDE_DATA(file_inode(fp)); - int err; - if (count == 0) { - return 0; - } - /* If position out of data length - read nothing */ - if ((*position < 0) || (*position >= (loff_t)iovar_data_len)) { - return 0; - } - /* If buffer end is past structure lenght - truncate it */ - if ((*position + count) > (loff_t)iovar_data_len) { - count = (size_t)((loff_t)iovar_data_len - *position); - } - if (user_buffer_in) { - /* SET operation */ - /* Read/modify/write if not whole-buffer-operation */ - if ((*position != 0) || (count < iovar_data_len)) { - err = dhd_bus_iovar_op(&(dhd->pub), iovar, - (char *)read_params, (uint)read_plen, - (char *)iovar_data_buf, (uint)iovar_data_len, IOV_GET); - if (err) { - return -EPERM; - } - } - if (copy_from_user((char *)iovar_data_buf + (uint)*position, user_buffer_in, count)) - { - return -EPERM; - } - /* This params/plen of NULL/0 is a 'legal fiction', imposed by - * strange assert in dhd_bus_iovar_op(). After this strange - * assert, arg/arglen is copied to params/plen - and even used - * inside iovar handler! - */ - err = dhd_bus_iovar_op(&(dhd->pub), iovar, NULL, 0, - (char *)iovar_data_buf, (uint)iovar_data_len, IOV_SET); - } else { - /* GET operation */ - err = dhd_bus_iovar_op(&(dhd->pub), iovar, (char *)read_params, (uint)read_plen, - (char *)iovar_data_buf, (uint)iovar_data_len, IOV_GET); - } - if (err) { - return -EPERM; - } - if (user_buffer_out) { - if (copy_to_user(user_buffer_out, (char *)iovar_data_buf + (uint)*position, count)) - { - return -EPERM; - } - } - *position += count; - return count; -} - -/* Read for "gdb_proxy_probe" procfs file */ -static ssize_t -gdb_proxy_fs_probe_read(struct file *fp, char __user *user_buffer, size_t count, - loff_t *position) -{ - uint32 proxy_id = 0; - dhd_gdb_proxy_probe_data_t probe_data; - return gdb_proxy_fs_iovar_data_op(fp, NULL, user_buffer, count, position, "gdb_proxy_probe", - &probe_data, sizeof(probe_data), &proxy_id, sizeof(proxy_id)); -} - -/* Seek for "gdb_proxy_probe" file */ -static loff_t -gdb_proxy_fs_probe_llseek(struct file *fp, loff_t off, int whence) -{ - return gdb_proxy_fs_llseek(fp, off, whence, sizeof(dhd_gdb_proxy_probe_data_t)); -} - -/* File operations for "gdb_proxy_probe" procfs file */ -static const struct file_operations -gdb_proxy_fs_probe_file_ops = { - .read = gdb_proxy_fs_probe_read, - .llseek = gdb_proxy_fs_probe_llseek, -}; - -/* Read for "gdb_proxy_stop_count" procfs file */ -static ssize_t -gdb_proxy_fs_stop_count_read(struct file *fp, char __user *user_buffer, size_t count, - loff_t *position) -{ - uint32 stop_count; - return gdb_proxy_fs_iovar_data_op(fp, NULL, user_buffer, count, position, - "gdb_proxy_stop_count", &stop_count, sizeof(stop_count), NULL, 0); -} - -/* Write for "gdb_proxy_stop_count" procfs file */ -static ssize_t -gdb_proxy_fs_stop_count_write(struct file *fp, const char __user *user_buffer, size_t count, - loff_t *position) -{ - uint32 stop_count; - return gdb_proxy_fs_iovar_data_op(fp, user_buffer, NULL, count, position, - "gdb_proxy_stop_count", &stop_count, sizeof(stop_count), NULL, 0); -} - -/* Seek for "gdb_proxy_stop_count" file */ -static loff_t -gdb_proxy_fs_stop_count_llseek(struct file *fp, loff_t off, int whence) -{ - return gdb_proxy_fs_llseek(fp, off, whence, sizeof(uint32)); -} - -/* File operations for "gdb_proxy_stop_count" procfs file */ -static const struct file_operations -gdb_proxy_fs_stop_count_file_ops = { - .read = gdb_proxy_fs_stop_count_read, - .write = gdb_proxy_fs_stop_count_write, - .llseek = gdb_proxy_fs_stop_count_llseek, -}; - -/* Common read/write procedure for "membytes" and "sbreg" procfs files - * fp: file descriptor - * buffer_in: userspace buffer address for write operation, NULL for read - * operation - * buffer_out: userspace buffer address for read operation, NULL for write - * operation - * count: maximum number of bytes to read/write - * position: seek position (interpreted as memory address in firmware address - * space), - * incremented by length of data read/written - * iovar: name of iovar being accessed - * address_first: TRUE if address shall be packed first, FALSE if width - * Returns number of bytes read/written or error code - */ -static ssize_t -gdb_proxy_fs_iovar_mem_op(struct file *fp, const char __user *user_buffer_in, - char __user *user_buffer_out, size_t count, loff_t *position, - const char *iovar, bool address_first) -{ - dhd_info_t *dhd = (dhd_info_t *)PDE_DATA(file_inode(fp)); - uint32 buf[3]; - int err; - if (count == 0) { - return 0; - } - if ((count > sizeof(uint32)) || (count & (count - 1))) { - return -EINVAL; - } - buf[address_first ? 0 : 1] = (uint32)(*position); - buf[address_first ? 1 : 0] = (uint32)count; - if (user_buffer_in) { - /* SET operation */ - if (copy_from_user(&buf[2], user_buffer_in, count)) { - return -EPERM; - } - /* This params/plen of NULL/0 is a 'legal fiction', imposed by - * strange assert in dhd_bus_iovar_op(). After this strange - * assert, arg/arglen is copied to params/plen - and even used - * inside iovar handler! - */ - err = dhd_bus_iovar_op(&(dhd->pub), iovar, NULL, 0, (char *)buf, sizeof(*buf) * 3, - IOV_SET); - } else { - /* GET operation */ - /* This arglen of 8 bytes (where 4 would suffice) is due to - * strange requirement of minimum arglen to be 8, hardcoded into - * "membytes" iovar definition - */ - err = dhd_bus_iovar_op(&(dhd->pub), iovar, (char *)buf, sizeof(*buf) * 2, - (char *)buf, sizeof(*buf) * 2, IOV_GET); - } - if (err) { - return -EPERM; - } - *position += count; - if (user_buffer_out) { - if (copy_to_user(user_buffer_out, &buf[0], count)) { - return -EPERM; - } - } - return count; -} - -/* Common seek procedure for "membytes" and "sbreg" procfs files */ -static loff_t -gdb_proxy_fs_memory_llseek(struct file *fp, loff_t off, int whence) -{ - return gdb_proxy_fs_llseek(fp, off, whence, GDB_PROXY_FS_MEM_SIZE); -} - -/* Read for "membytes" procfs file */ -static ssize_t -gdb_proxy_fs_membytes_read(struct file *fp, char __user *user_buffer, size_t count, - loff_t *position) -{ - return gdb_proxy_fs_iovar_mem_op(fp, NULL, user_buffer, count, position, "membytes", TRUE); -} - -/* Write for "membytes" procfs file */ -static ssize_t -gdb_proxy_fs_membytes_write(struct file *fp, const char __user *user_buffer, size_t count, - loff_t *position) -{ - return gdb_proxy_fs_iovar_mem_op(fp, user_buffer, NULL, count, position, "membytes", TRUE); -} - -/* File operations for "membytes" procfs file */ -static const struct file_operations -gdb_proxy_fs_membytes_file_ops = { - .read = gdb_proxy_fs_membytes_read, - .write = gdb_proxy_fs_membytes_write, - .llseek = gdb_proxy_fs_memory_llseek, -}; - -/* Read for "sbreg" procfs file */ -static ssize_t -gdb_proxy_fs_sbreg_read(struct file *fp, char __user *user_buffer, size_t count, loff_t *position) -{ - return gdb_proxy_fs_iovar_mem_op(fp, NULL, user_buffer, count, position, "sbreg", FALSE); -} - -/* Write for "sbreg" procfs file */ -static ssize_t -gdb_proxy_fs_sbreg_write(struct file *fp, const char __user *user_buffer, size_t count, - loff_t *position) -{ - return gdb_proxy_fs_iovar_mem_op(fp, user_buffer, NULL, count, position, "sbreg", FALSE); -} - -/* File operations for "sbreg" procfs file */ -static const struct file_operations -gdb_proxy_fs_sbreg_file_ops = { - .read = gdb_proxy_fs_sbreg_read, - .write = gdb_proxy_fs_sbreg_write, - .llseek = gdb_proxy_fs_memory_llseek, -}; - -/* If GDB Proxy procfs files set not yet created for given dhd instance - creates it */ -static void -gdb_proxy_fs_try_create(dhd_info_t *dhd, const char *dev_name) -{ - char dir_name[sizeof(dhd->gdb_proxy_fs_root_name)] = "dhd_gdb_proxy_"; - struct proc_dir_entry *root_dentry; - int i; - static const struct { - const char *file_name; - const struct file_operations *fops; - } fileinfos[] = { - {"gdb_proxy_probe", &gdb_proxy_fs_probe_file_ops}, - {"gdb_proxy_stop_count", &gdb_proxy_fs_stop_count_file_ops}, - {"membytes", &gdb_proxy_fs_membytes_file_ops}, - {"sbreg", &gdb_proxy_fs_sbreg_file_ops}, - }; - if (!dev_name || !*dev_name || dhd->gdb_proxy_fs_root) { - return; - } - strlcat_s(dir_name, dev_name, sizeof(dir_name)); - dir_name[sizeof(dir_name) - 1] = 0; - root_dentry = proc_mkdir(dir_name, NULL); - if ((root_dentry == NULL) || IS_ERR(root_dentry)) { - return; - } - for (i = 0; i < ARRAYSIZE(fileinfos); ++i) { - struct proc_dir_entry *file_dentry = proc_create_data(fileinfos[i].file_name, - S_IRUGO | (fileinfos[i].fops->write ? S_IWUGO : 0), root_dentry, - fileinfos[i].fops, dhd); - if ((file_dentry == NULL) || IS_ERR(file_dentry)) { - goto fail; - } - } - dhd->gdb_proxy_fs_root = root_dentry; - memcpy_s(dhd->gdb_proxy_fs_root_name, sizeof(dhd->gdb_proxy_fs_root_name), - dir_name, sizeof(dhd->gdb_proxy_fs_root_name)); - return; -fail: - if (root_dentry) { - remove_proc_subtree(dir_name, NULL); - } -} - -/* If GDB Proxy procfs files set created for given dhd instance - removes it */ -static void -gdb_proxy_fs_remove(dhd_info_t *dhd) -{ - if (dhd->gdb_proxy_fs_root) { - remove_proc_subtree(dhd->gdb_proxy_fs_root_name, NULL); - dhd->gdb_proxy_fs_root = NULL; - bzero(dhd->gdb_proxy_fs_root_name, sizeof(dhd->gdb_proxy_fs_root_name)); - } -} -#endif /* defined(GDB_PROXY) && defined(PCIE_FULL_DONGLE) && defined(BCMINTERNAL) */ - #ifdef DHD_MAP_LOGGING /* Will be called from SMMU fault handler */ void @@ -28301,230 +22236,6 @@ dhd_smmu_fault_handler(uint32 axid, ulong fault_addr) EXPORT_SYMBOL(dhd_smmu_fault_handler); #endif /* DHD_MAP_LOGGING */ -#ifdef DHD_PKTTS -/* Get pktts flow configuration */ -int -dhd_get_pktts_flow(dhd_pub_t *dhdp, void *arg, int len) -{ - dhd_info_t *dhd = dhdp->info; - - if (!arg || len <= (sizeof(pktts_flow_t) * PKTTS_CONFIG_MAX)) { - return BCME_BADARG; - } - - return memcpy_s(arg, len, &dhd->config[0], sizeof(dhd->config)); -} - -/* Set pktts flow configuration */ -int -dhd_set_pktts_flow(dhd_pub_t *dhdp, void *params, int plen) -{ - dhd_info_t *dhd = dhdp->info; - pktts_flow_t *config; - uint32 checksum = 0; - int ret = BCME_OK; - uint32 temp; - uint32 idx = PKTTS_CONFIG_MAX; - uint32 num_config = 0; - - if (plen < sizeof(*config)) { - DHD_ERROR(("dhd_set_pktts_flow: invalid buffer length (%d)\n", plen)); - return BCME_BADLEN; - } - - config = (pktts_flow_t *)params; - - temp = htonl(config->src_ip); - checksum ^= bcm_compute_xor32((volatile uint32 *)&temp, - sizeof(temp) / sizeof(uint32)); - temp = htonl(config->dst_ip); - checksum ^= bcm_compute_xor32((volatile uint32 *)&temp, - sizeof(temp) / sizeof(uint32)); - - temp = (hton16(config->dst_port) << 16) | hton16(config->src_port); - checksum ^= bcm_compute_xor32((volatile uint32 *)&temp, - sizeof(temp) / sizeof(uint32)); - temp = config->proto; - checksum ^= bcm_compute_xor32((volatile uint32 *)&temp, - sizeof(temp) / sizeof(uint32)); - - /* Look for checksum match: for delete or update */ - dhd_match_pktts_flow(dhdp, checksum, &idx, &num_config); - - /* no matching config */ - if (idx == PKTTS_CONFIG_MAX) { - if (config->pkt_offset == PKTTS_OFFSET_INVALID) { - /* no matching config found for deletion */ - return BCME_NOTFOUND; - } - - /* look for free config space */ - for (idx = 0; idx < PKTTS_CONFIG_MAX; idx++) { - if (dhd->config[idx].chksum == 0) { - break; - } - } - - if (idx == PKTTS_CONFIG_MAX) { - /* no config space left */ - return BCME_NORESOURCE; - } - } - - if (config->pkt_offset == PKTTS_OFFSET_INVALID) { - /* reset if pkt_offset is zero */ - memset(&dhd->config[idx], 0, sizeof(dhd->config[idx])); - } else { - ret = memcpy_s(&dhd->config[idx], sizeof(dhd->config[idx]), - config, sizeof(*config)); - if (ret == BCME_OK) { - dhd->config[idx].chksum = checksum; - } - } - - return ret; -} - -/** - * dhd_match_pktts_flow - this api returns matching pktts config against checksum - * - * @dhdp: pointer to dhd_pub object - * @checksum: five tuple checksum - * @idx: returns index of matching pktts config - * @num_config: returns number of valid pktts config - */ -pktts_flow_t * -dhd_match_pktts_flow(dhd_pub_t *dhdp, uint32 checksum, uint32 *idx, uint32 *num_config) -{ - dhd_info_t *dhd = dhdp->info; - pktts_flow_t *flow = NULL; - uint8 i; - - for (i = 0; i < PKTTS_CONFIG_MAX; i++) { - if (dhd->config[i].chksum) { - (*num_config)++; - } - - if (checksum && (dhd->config[i].chksum == checksum)) { - flow = &dhd->config[i]; - break; - } - } - - /* update matching config index */ - if (idx) { - *idx = i; - } - - /* countinue with valid config count */ - for (; i < PKTTS_CONFIG_MAX; i++) { - if (dhd->config[i].chksum) { - (*num_config)++; - } - } - - return flow; -} - -/* Get pktts enab configuration */ -int dhd_get_pktts_enab(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = dhdp->info; - - return dhd->latency; -} - -/* Set pktts enable configuration */ -int dhd_set_pktts_enab(dhd_pub_t *dhdp, bool val) -{ - dhd_info_t *dhd = dhdp->info; - uint32 var_int = val; - int ret = BCME_OK; - uint power_val; - - /* check FW supports pktlat_ipc or pktlat_meta */ - if (!FW_SUPPORTED(dhdp, pktlat_ipc) && !FW_SUPPORTED(dhdp, pktlat_meta)) { - BCM_REFERENCE(power_val); - DHD_INFO(("Chip does not support pktlat\n")); - return ret; - } - power_val = 0; - /* Disabling mpc and PM mode for pktlat */ - ret = dhd_iovar(dhdp, 0, "mpc", (char *)&power_val, sizeof(power_val), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: Unable to set mpc 0, ret=%d\n", __FUNCTION__, ret)); - return ret; - } - power_val = PM_OFF; - ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_PM, (char *)&power_val, sizeof(power_val), - TRUE, 0); - if (ret < 0) { - DHD_ERROR(("%s: Unable to set PM 0, ret=%d\n", __FUNCTION__, ret)); - return ret; - } - - ret = dhd_iovar(dhdp, 0, "pktts_enab", (char *)&var_int, sizeof(var_int), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: enabling pktts_enab failed, ret=%d\n", __FUNCTION__, ret)); - return ret; - } - - dhd->latency = val; - - return 0; -} -#endif /* DHD_PKTTS */ - -#ifdef DHD_ERPOM -static void -dhd_error_recovery(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - dhd_pub_t *dhdp; - int ret = 0; - - if (!dhd) { - DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); - return; - } - - dhdp = &dhd->pub; - - if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) { - DHD_ERROR(("%s: init not completed, cannot initiate recovery\n", - __FUNCTION__)); - return; - } - -#ifdef BT_OVER_PCIE - if (dhdp->dongle_trap_due_to_bt) { - DHD_ERROR(("WLAN trapped due to BT, toggle REG_ON\n")); - /* toggle REG_ON */ - dhdp->pom_toggle_reg_on(WLAN_FUNC_ID, BY_WLAN_DUE_TO_BT); - return; - } -#endif /* BT_OVER_PCIE */ - - ret = dhd_bus_perform_flr_with_quiesce(dhdp, dhdp->bus, FALSE); - if (ret != BCME_DNGL_DEVRESET) { - DHD_ERROR(("%s: dhd_bus_perform_flr_with_quiesce failed with ret: %d," - "toggle REG_ON\n", __FUNCTION__, ret)); - /* toggle REG_ON */ - dhdp->pom_toggle_reg_on(WLAN_FUNC_ID, BY_WLAN_DUE_TO_WLAN); - return; - } -} - -void -dhd_schedule_reset(dhd_pub_t *dhdp) -{ - if (dhdp->enable_erpom) { - dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, NULL, - DHD_WQ_WORK_ERROR_RECOVERY, dhd_error_recovery, DHD_WQ_WORK_PRIORITY_HIGH); - } -} -#endif /* DHD_ERPOM */ - #ifdef DHD_PKT_LOGGING int dhd_pktlog_debug_dump(dhd_pub_t *dhdp) @@ -28665,39 +22376,6 @@ static void dhd_m4_state_handler(struct work_struct *work) } } -void -dhd_eap_txcomplete(dhd_pub_t *dhdp, void *txp, bool success, int ifidx) -{ - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct ether_header *eh; - uint16 type; - - if (!success) { - /* XXX where does this stuff belong to? */ - dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); - - /* XXX Use packet tag when it is available to identify its type */ - eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); - type = ntoh16(eh->ether_type); - if (type == ETHER_TYPE_802_1X) { - if (dhd_is_4way_msg((uint8 *)eh) == EAPOL_4WAY_M4) { - dhd_if_t *ifp = NULL; - ifp = dhd->iflist[ifidx]; - if (!ifp || !ifp->net) { - return; - } - - DHD_INFO(("%s: M4 TX failed on %d.\n", - __FUNCTION__, ifidx)); - - OSL_ATOMIC_SET(dhdp->osh, &ifp->m4state, M4_TXFAILED); - schedule_delayed_work(&ifp->m4state_work, - msecs_to_jiffies(MAX_4WAY_TIMEOUT_MS)); - } - } - } -} - void dhd_cleanup_m4_state_work(dhd_pub_t *dhdp, int ifidx) { @@ -28722,80 +22400,6 @@ dhd_cleanup_m4_state_work(dhd_pub_t *dhdp, int ifidx) } #endif /* DHD_4WAYM4_FAIL_DISCONNECT */ -#ifdef BIGDATA_SOFTAP -void dhd_schedule_gather_ap_stadata(void *bcm_cfg, void *ndev, const wl_event_msg_t *e) -{ - struct bcm_cfg80211 *cfg; - dhd_pub_t *dhdp; - ap_sta_wq_data_t *p_wq_data; - - if (!bcm_cfg || !ndev || !e) { - WL_ERR(("bcm_cfg=%p ndev=%p e=%p\n", bcm_cfg, ndev, e)); - return; - } - - cfg = (struct bcm_cfg80211 *)bcm_cfg; - dhdp = (dhd_pub_t *)cfg->pub; - - if (!dhdp || !cfg->ap_sta_info) { - WL_ERR(("dhdp=%p ap_sta_info=%p\n", dhdp, cfg->ap_sta_info)); - return; - } - - p_wq_data = (ap_sta_wq_data_t *)MALLOCZ(dhdp->osh, sizeof(ap_sta_wq_data_t)); - if (unlikely(!p_wq_data)) { - DHD_ERROR(("%s(): could not allocate memory for - " - "ap_sta_wq_data_t\n", __FUNCTION__)); - return; - } - - mutex_lock(&cfg->ap_sta_info->wq_data_sync); - - memcpy(&p_wq_data->e, e, sizeof(wl_event_msg_t)); - p_wq_data->dhdp = dhdp; - p_wq_data->bcm_cfg = cfg; - p_wq_data->ndev = (struct net_device *)ndev; - - mutex_unlock(&cfg->ap_sta_info->wq_data_sync); - - dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, - p_wq_data, DHD_WQ_WORK_GET_BIGDATA_AP, - wl_gather_ap_stadata, DHD_WQ_WORK_PRIORITY_HIGH); - -} -#endif /* BIGDATA_SOFTAP */ - -void -get_debug_dump_time(char *str) -{ - struct osl_timespec curtime; - unsigned long local_time; - struct rtc_time tm; - - if (!strlen(str)) { - osl_do_gettimeofday(&curtime); - local_time = (u32)(curtime.tv_sec - - (sys_tz.tz_minuteswest * DHD_LOG_DUMP_TS_MULTIPLIER_VALUE)); - rtc_time_to_tm(local_time, &tm); - snprintf(str, DEBUG_DUMP_TIME_BUF_LEN, DHD_LOG_DUMP_TS_FMT_YYMMDDHHMMSSMSMS, - tm.tm_year - 100, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, - tm.tm_sec, (int)(curtime.tv_usec/NSEC_PER_USEC)); - } -} - -void -clear_debug_dump_time(char *str) -{ - memset(str, 0, DEBUG_DUMP_TIME_BUF_LEN); -} -#if defined(WL_CFGVENDOR_SEND_HANG_EVENT) || defined(DHD_PKT_LOGGING) -void -copy_debug_dump_time(char *dest, char *src) -{ - memcpy(dest, src, DEBUG_DUMP_TIME_BUF_LEN); -} -#endif /* WL_CFGVENDOR_SEND_HANG_EVENT || DHD_PKT_LOGGING */ - /* * DHD RING */ @@ -29773,21 +23377,15 @@ dhd_ring_whole_unlock(void *_ring) #define DHD_VFS_INODE(dir) d_inode(dir) #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) -#define DHD_VFS_UNLINK(dir, b, c) vfs_unlink(DHD_VFS_INODE(dir), b) -#else -#define DHD_VFS_UNLINK(dir, b, c) vfs_unlink(DHD_VFS_INODE(dir), b, c) -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */ - #if ((defined DHD_DUMP_MNGR) || (defined DNGL_AXI_ERROR_LOGGING)) int dhd_file_delete(char *path) { - struct path file_path; + struct path file_path = {.dentry = 0}; int err; struct dentry *dir; - err = kern_path(path, 0, &file_path); + err = dhd_kern_path(path, 0, &file_path); if (err < 0) { DHD_ERROR(("Failed to get kern-path delete file: %s error: %d\n", path, err)); @@ -29807,7 +23405,7 @@ dhd_file_delete(char *path) dir = dget_parent(file_path.dentry); if (!IS_ERR(dir)) { - err = DHD_VFS_UNLINK(dir, file_path.dentry, NULL); + err = DHD_VFS_UNLINK(dir, file_path, NULL); dput(dir); } else { err = PTR_ERR(dir); @@ -29911,34 +23509,6 @@ dhd_dump_file_manage_enqueue(dhd_pub_t *dhd, char *dump_path, char *fname) } #endif /* DHD_DUMP_MNGR */ -#ifdef DHD_HP2P -unsigned long -dhd_os_hp2plock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - unsigned long flags = 0; - - dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - flags = osl_spin_lock(&dhd->hp2p_lock); - } - - return flags; -} - -void -dhd_os_hp2punlock(dhd_pub_t *pub, unsigned long flags) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - osl_spin_unlock(&dhd->hp2p_lock, flags); - } -} -#endif /* DHD_HP2P */ #ifdef DNGL_AXI_ERROR_LOGGING static void dhd_axi_error_dump(void *handle, void *event_info, u8 event) @@ -30068,6 +23638,17 @@ dhd_cto_recovery_handler(void *handle, void *event_info, u8 event) void dhd_schedule_cto_recovery(dhd_pub_t *dhdp) { + if (dhdp->up == FALSE) { + DHD_ERROR(("%s : skip scheduling cto because dhd is not up\n", + __FUNCTION__)); + return; + } + + if (dhdp->info->scheduled_memdump) { + DHD_ERROR(("%s, memdump in progress\n", __FUNCTION__)); + return; + } + DHD_ERROR(("%s: scheduling cto recovery.. \n", __FUNCTION__)); dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, NULL, DHD_WQ_WORK_CTO_RECOVERY, @@ -30096,13 +23677,6 @@ void wifi_plat_dev_drv_shutdown(struct platform_device *pdev) } } #endif /* DHD_WIFI_SHUTDOWN */ -#ifdef WL_AUTO_QOS -void -dhd_wl_sock_qos_set_status(dhd_pub_t *dhdp, unsigned long on_off) -{ - dhd_sock_qos_set_status(dhdp->info, on_off); -} -#endif /* WL_AUTO_QOS */ #ifdef DHD_CFG80211_SUSPEND_RESUME void @@ -30164,6 +23738,42 @@ static void dhd_set_bandlock(dhd_pub_t * dhd) #endif /* BANDLOCK */ } +void +dhd_set_del_in_progress(dhd_pub_t *dhdp, struct net_device *ndev) +{ + dhd_if_t *ifp = NULL; + unsigned long flags; + + DHD_ERROR(("%s\n", __FUNCTION__)); + ifp = dhd_get_ifp_by_ndev(dhdp, ndev); + if (ifp == NULL) { + DHD_ERROR(("DHD Iface Info corresponding to %s not found\n", ndev->name)); + return; + } + + DHD_GENERAL_LOCK(dhdp, flags); + ifp->del_in_progress = TRUE; + DHD_GENERAL_UNLOCK(dhdp, flags); +} + +void +dhd_clear_del_in_progress(dhd_pub_t *dhdp, struct net_device *ndev) +{ + dhd_if_t *ifp = NULL; + unsigned long flags; + + DHD_ERROR(("%s\n", __FUNCTION__)); + ifp = dhd_get_ifp_by_ndev(dhdp, ndev); + if (ifp == NULL) { + DHD_ERROR(("DHD Iface Info corresponding to %s not found\n", ndev->name)); + return; + } + + DHD_GENERAL_LOCK(dhdp, flags); + ifp->del_in_progress = FALSE; + DHD_GENERAL_UNLOCK(dhdp, flags); +} + #ifdef PCIE_FULL_DONGLE /* API to delete flowings and Stations * corresponding to the interface(ndev) @@ -30186,17 +23796,40 @@ dhd_net_del_flowrings_sta(dhd_pub_t *dhd, struct net_device *ndev) __FUNCTION__, ifp->idx)); dhd_del_all_sta(dhd, ifp->idx); + /* Try to resume if already suspended or suspend in progress */ dhd_flow_rings_delete(dhd, ifp->idx); } +#if defined(WBRC) && defined(WBRC_BT2WL_RESET) +void +dhd_wbrc_wl_trap(void) +{ + dhd_pub_t *dhdp = g_dhd_pub; + + dhdpcie_db7_trap(dhdp->bus); + /* set that dongle trap has occured to stop other contests from firing IOVARS */ + dhdp->dongle_trap_occured = TRUE; +#ifdef OEM_ANDROID + /* Set chip big hammer */ + dhdp->do_chip_bighammer = TRUE; + dhdp->hang_reason = HANG_REASON_BT2WL_REG_RESET; + dhd_os_send_hang_message(dhdp); +#endif /* OEM_ANDROID */ +} +#endif /* WBRC && WBRC_BT2WL_RESET */ #endif /* PCIE_FULL_DONGLE */ #ifndef BCMDBUS static void dhd_deferred_socram_dump(void *handle, void *event_info, u8 event) { +#ifndef BCMDBUS dhd_pub_t *dhdp = (dhd_pub_t *)event_info; DHD_ERROR(("%s ... scheduled to collect memdump over bus\n", __FUNCTION__)); dhd_socram_dump(dhdp->bus); +#else + DHD_ERROR(("%s Not collecting socram dump for BCMDBUS\n", __FUNCTION__)); + return; +#endif /* BCMDBUS */ } int @@ -30209,6 +23842,205 @@ dhd_schedule_socram_dump(dhd_pub_t *dhdp) } #endif +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT +void dhd_alert_process(struct work_struct *work_data) +{ + struct net_device *dev; + dhd_info_t *dhd_info = NULL; + dhd_pub_t *dhdp = NULL; + + /* Ignore compiler warnings due to -Werror=cast-qual */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + dhd_info = container_of(work_data, dhd_info_t, dhd_alert_process_work); + GCC_DIAGNOSTIC_POP(); + dhdp = &dhd_info->pub; + + if (!dhdp) { + DHD_ERROR(("dhd is NULL\n")); + return; + } + dev = dhd_linux_get_primary_netdev(dhdp); + + if (dev) { + wl_cfg80211_alert(dev); + } +} + +int dhd_os_send_alert_message(dhd_pub_t *dhdp) +{ + int ret = 0; + dhd_info_t *dhd_info = NULL; +#ifdef WL_CFG80211 + struct net_device *primary_ndev; + struct bcm_cfg80211 *cfg; +#endif /* WL_CFG80211 */ + + if (!dhdp) { + DHD_ERROR(("dhdp is null\n")); + return -EINVAL; + } + + dhd_info = (dhd_info_t *)dhdp->info; + BCM_REFERENCE(dhd_info); + +#ifdef WL_CFG80211 + primary_ndev = dhd_linux_get_primary_netdev(dhdp); + if (!primary_ndev) { + DHD_ERROR(("Cannot find primary netdev\n")); + return -ENODEV; + } + cfg = wl_get_cfg(primary_ndev); + if (!cfg) { + DHD_ERROR(("Cannot find cfg\n")); + return -EINVAL; + } + + /* Skip sending ALERT event to framework if driver is not ready */ + if (!wl_get_drv_status(cfg, READY, primary_ndev)) { + DHD_ERROR(("device is not ready\n")); + return -ENODEV; + } + + schedule_work(&dhdp->info->dhd_alert_process_work); +#endif /* WL_CFG80211 */ + + return ret; +} +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ +int +dhd_dev_set_accel_force_reg_on(struct net_device *dev) +{ +#if defined(WLAN_ACCEL_BOOT) + dhd_info_t *dhd_info = *(dhd_info_t **)netdev_priv(dev); + + if (dhd_info && !dhd_info->wl_accel_force_reg_on) { + DHD_ERROR(("%s: set force reg on\n", __FUNCTION__)); + dhd_info->wl_accel_force_reg_on = TRUE; + } +#endif /* WLAN_ACCEL_BOOT */ + + return BCME_OK; +} +#ifdef TPUT_DEBUG_DUMP +bool dhd_get_napi_sched_cnt(dhd_pub_t * dhdp, + uint32 **napi_cnts, uint32 **txp_cnts, uint32 **tx_start_cnts) +{ + struct dhd_info *dhd = NULL; + if (!dhdp) { + WL_ERR(("Invaslid dhd_pub\n")); + return FALSE; + } + + dhd = dhdp->info; + + if (!dhd) { + WL_ERR(("Invaslid dhd_info\n")); + return FALSE; + } + + *napi_cnts = dhd->napi_percpu_run_cnt; + *txp_cnts = dhd->txp_percpu_run_cnt; + *tx_start_cnts = dhd->tx_start_percpu_run_cnt; + + return TRUE; +} +#endif /* TPUT_DEBUG_DUMP */ + +#if defined(DHD_ENABLE_S2MPU) +/* + * return + * S2MPUFD_NOTIFY_BAD : watchdog reset + * S2MPUFD_NOTIFY_OK : No watchdog reset + */ +int s2mpufd_notifier_callback(struct s2mpufd_notifier_block *block, + struct s2mpufd_notifier_info *info) +{ + int ret = S2MPUFD_NOTIFY_OK; + + DHD_ERROR(("%s: fault_addr:0x%lx, rw:%d, len:%d, type:%d \n", + __FUNCTION__, info->fault_addr, info->fault_rw, + info->fault_len, info->fault_type)); + dhd_smmu_fault_handler(0, info->fault_addr); + + DHD_ERROR(("%s: return : %d\n", __FUNCTION__, ret)); + + return ret; +} + +static void dhd_module_s2mpu_register(struct device *dev) +{ + struct s2mpufd_notifier_block *s2mpu_nb = NULL; + + DHD_ERROR(("%s: Enter\n", __FUNCTION__)); + + s2mpu_nb = devm_kzalloc(dev, sizeof(struct s2mpufd_notifier_block), GFP_KERNEL); + if (!s2mpu_nb) { + DHD_ERROR(("%s: devm_kzalloc fail\n", __FUNCTION__)); + return; + } + + s2mpu_nb->subsystem = "PCIE_GEN2"; + s2mpu_nb->notifier_call = s2mpufd_notifier_callback; + s2mpufd_notifier_call_register(s2mpu_nb); +} +#endif /* DHD_ENABLE_S2MPU */ + +#ifdef DHD_REGISTER_SMMU_FAULT_HANDLER +#define SYSMMU_NOTIFY_SKIP_PANIC 3 +static int sysmmu_notifier_callback(struct notifier_block *nb, unsigned long addr, + void *flag) +{ + int fault_info = *(int *)flag; + DHD_ERROR(("%s: Fault ADDR 0x%lx - %s\n", __FUNCTION__, addr, + (fault_info & 0x1) ? "WRITE" : "READ")); + dhd_smmu_fault_handler(0, addr); + return SYSMMU_NOTIFY_SKIP_PANIC; +} +#endif /* DHD_REGISTER_SMMU_FAULT_HANDLER */ + +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) +dhd_dongledump_status_t dhd_get_dump_status(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + return OSL_ATOMIC_READ(pub->osh, &dhd->dump_status); +} + +void dhd_set_dump_status(dhd_pub_t *pub, dhd_dongledump_status_t dump_status) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + OSL_ATOMIC_SET(pub->osh, &dhd->dump_status, dump_status); +} + +static void dhd_dump_proc(struct work_struct *work_data) +{ + dhd_info_t *dhd_info = NULL; + dhd_pub_t *dhdp = NULL; + unsigned long flags = 0; + + /* Ignore compiler warnings due to -Werror=cast-qual */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + dhd_info = container_of(work_data, dhd_info_t, dhd_dump_proc_work); + GCC_DIAGNOSTIC_POP(); + + if (!dhd_info || ((dhdp = &dhd_info->pub) == NULL)) { + DHD_ERROR(("dhd is NULL\n")); + return; + } + + DHD_GENERAL_LOCK(dhdp, flags); + DHD_BUS_BUSY_SET_IN_SYSFS_DUMP(dhdp); +#ifdef DHD_LOG_DUMP + DHD_GENERAL_UNLOCK(dhdp, flags); + dhd_log_dump_trigger(dhdp, CMD_DEFAULT); + DHD_GENERAL_LOCK(dhdp, flags); +#endif /* DHD_LOG_DUMP */ + DHD_BUS_BUSY_CLEAR_IN_SYSFS_DUMP(dhdp); + DHD_GENERAL_UNLOCK(dhdp, flags); +} +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ + void *dhd_get_pub(struct net_device *dev) { dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h old mode 100755 new mode 100644 index 2f2c409dfd67..364aa8216201 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h @@ -1,7 +1,7 @@ /* * DHD Linux header file (dhd_linux exports for cfg80211 and other components) * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -35,6 +35,9 @@ #include #include #include +#ifdef DHD_LOG_DUMP +#include +#endif #include #ifdef DHD_WMF #include @@ -55,6 +58,14 @@ #include #endif /* PCIE_FULL_DONGLE */ +#ifdef CONFIG_IRQ_HISTORY +#include +#endif /* CONFIG_IRQ_HISTORY */ + +#if defined(OEM_ANDROID) +#include +#endif /* OEM_ANDROID */ + #ifdef WL_MONITOR #ifdef HOST_RADIOTAP_CONV #include @@ -67,9 +78,9 @@ /* dongle status */ enum wifi_adapter_status { WIFI_STATUS_POWER_ON = 0, - WIFI_STATUS_ATTACH, WIFI_STATUS_FW_READY, - WIFI_STATUS_DETTACH + WIFI_STATUS_NET_ATTACHED, + WIFI_STATUS_BUS_DISCONNECTED }; #define wifi_chk_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status)) #define wifi_get_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status)) @@ -77,9 +88,149 @@ enum wifi_adapter_status { #define wifi_clr_adapter_status(adapter, stat) (clear_bit(stat, &(adapter)->status)) #define wifi_chg_adapter_status(adapter, stat) (change_bit(stat, &(adapter)->status)) +#ifdef DHD_COREDUMP +#define PC_FOUND_BIT 0x01 +#define LR_FOUND_BIT 0x02 +#define ALL_ADDR_VAL (PC_FOUND_BIT | LR_FOUND_BIT) +#define READ_NUM_BYTES 1000 +#define DHD_FUNC_STR_LEN 80 + +#define DHD_COREDUMP_MAGIC 0xDDCEDACF +#define TLV_TYPE_LENGTH_SIZE (8u) +/* coredump is composed as following TLV format. + * Type(32bit) | Length(32bit) | Value(x bit) + * e.g) socram type | length | socram dump + * sssr core1 type | length | sssr core1 dump + * ... + */ +enum coredump_types { + DHD_COREDUMP_TYPE_SSSRDUMP_CORE0_BEFORE = 0, + DHD_COREDUMP_TYPE_SSSRDUMP_CORE0_AFTER, + DHD_COREDUMP_TYPE_SSSRDUMP_CORE1_BEFORE, + DHD_COREDUMP_TYPE_SSSRDUMP_CORE1_AFTER, + DHD_COREDUMP_TYPE_SSSRDUMP_CORE2_BEFORE, + DHD_COREDUMP_TYPE_SSSRDUMP_CORE2_AFTER, + DHD_COREDUMP_TYPE_SSSRDUMP_DIG_BEFORE, + DHD_COREDUMP_TYPE_SSSRDUMP_DIG_AFTER, + DHD_COREDUMP_TYPE_SOCRAMDUMP +}; + +#ifdef DHD_SSSR_DUMP +typedef struct dhd_coredump { + uint32 type; + uint32 length; + void *bufptr; +} dhd_coredump_t; +#endif /* DHD_SSSR_DUMP */ +#endif /* DHD_COREDUMP */ + +#ifdef BCMDBUS +#define DBUS_NRXQ 50 +#define DBUS_NTXQ 100 +#endif /* BCMDBUS */ + +#ifdef DHD_WAKE_RX_STATUS +#define ETHER_ICMP6_HEADER 20 +#define ETHER_IPV6_SADDR (ETHER_ICMP6_HEADER + 2) +#define ETHER_IPV6_DAADR (ETHER_IPV6_SADDR + IPV6_ADDR_LEN) +#define ETHER_ICMPV6_TYPE (ETHER_IPV6_DAADR + IPV6_ADDR_LEN) +#endif /* DHD_WAKE_RX_STATUS */ + +#ifdef SUPPORT_AP_POWERSAVE +#define RXCHAIN_PWRSAVE_PPS 10 +#define RXCHAIN_PWRSAVE_QUIET_TIME 10 +#define RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK 0 +#endif /* SUPPORT_AP_POWERSAVE */ + #define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ #define DHD_FW_READY_TIMEOUT 5000 /* msec : allowed time to finished fw download */ +/* FW initialised value for ocl_rssi_threshold */ +#define FW_OCL_RSSI_THRESH_INITVAL -75 + +#if defined(DHD_TRACE_WAKE_LOCK) +typedef enum dhd_wklock_type { + DHD_WAKE_LOCK, + DHD_WAKE_UNLOCK, + DHD_WAIVE_LOCK, + DHD_RESTORE_LOCK +} dhd_wklock_t; + +struct wk_trace_record { + unsigned long addr; /* Address of the instruction */ + dhd_wklock_t lock_type; /* lock_type */ + unsigned long long counter; /* counter information */ + struct hlist_node wklock_node; /* hash node */ +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) +#define HASH_ADD(hashtable, node, key) \ + do { \ + hash_add(hashtable, node, key); \ + } while (0); +#else +#define HASH_ADD(hashtable, node, key) \ + do { \ + int index = hash_long(key, ilog2(ARRAY_SIZE(hashtable))); \ + hlist_add_head(node, &hashtable[index]); \ + } while (0); +#endif /* KERNEL_VER < KERNEL_VERSION(3, 7, 0) */ + +#define STORE_WKLOCK_RECORD(wklock_type) \ + do { \ + struct wk_trace_record *wklock_info = NULL; \ + unsigned long func_addr = (unsigned long)__builtin_return_address(0); \ + wklock_info = find_wklock_entry(func_addr); \ + if (wklock_info) { \ + if (wklock_type == DHD_WAIVE_LOCK || wklock_type == DHD_RESTORE_LOCK) { \ + wklock_info->counter = dhd->wakelock_counter; \ + } else { \ + wklock_info->counter++; \ + } \ + } else { \ + wklock_info = kzalloc(sizeof(*wklock_info), GFP_ATOMIC); \ + if (!wklock_info) {\ + DHD_ERROR(("Can't allocate wk_trace_record \n")); \ + } else { \ + wklock_info->addr = func_addr; \ + wklock_info->lock_type = wklock_type; \ + if (wklock_type == DHD_WAIVE_LOCK || \ + wklock_type == DHD_RESTORE_LOCK) { \ + wklock_info->counter = dhd->wakelock_counter; \ + } else { \ + wklock_info->counter++; \ + } \ + HASH_ADD(wklock_history, &wklock_info->wklock_node, func_addr); \ + } \ + } \ + } while (0); + +#else +#define STORE_WKLOCK_RECORD(wklock_type) +#endif /* DHD_TRACE_WAKE_LOCK */ + +#ifdef ENABLE_ADAPTIVE_SCHED +#define DEFAULT_CPUFREQ_THRESH 1000000 /* threshold frequency : 1000000 = 1GHz */ +#ifndef CUSTOM_CPUFREQ_THRESH +#define CUSTOM_CPUFREQ_THRESH DEFAULT_CPUFREQ_THRESH +#endif /* CUSTOM_CPUFREQ_THRESH */ +#endif /* ENABLE_ADAPTIVE_SCHED */ + +/* enable HOSTIP cache update from the host side when an eth0:N is up */ +#define AOE_IP_ALIAS_SUPPORT 1 + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) && defined(DHD_TCP_LIMIT_OUTPUT) +#ifndef DHD_TCP_LIMIT_OUTPUT_BYTES +#define DHD_TCP_LIMIT_OUTPUT_BYTES (4 * 1024 * 1024) +#endif /* DHD_TCP_LIMIT_OUTPUT_BYTES */ +#ifndef TCP_DEFAULT_LIMIT_OUTPUT +#define TCP_DEFAULT_LIMIT_OUTPUT (256 * 1024) +#endif /* TSQ_DEFAULT_LIMIT_OUTPUT */ +#endif /* LINUX_VERSION_CODE > 4.19.0 && DHD_TCP_LIMIT_OUTPUT */ + +#define DHD_MEMDUMP_TYPE_STR_LEN 32 +#define DHD_MEMDUMP_PATH_STR_LEN 128 + typedef struct wifi_adapter_info { const char *name; uint irq_num; @@ -99,7 +250,7 @@ typedef struct wifi_adapter_info { #endif wait_queue_head_t status_event; unsigned long status; -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) const char *btfw_path; #endif /* defined (BT_OVER_SDIO) */ #if defined(BCMSDIO) @@ -109,9 +260,12 @@ typedef struct wifi_adapter_info { struct pci_dev *pci_dev; struct pci_saved_state *pci_saved_state; #endif /* BCMPCIE */ +#ifdef BCMDHD_PLATDEV + struct platform_device *pdev; +#endif /* BCMDHD_PLATDEV */ } wifi_adapter_info_t; -#if defined(CONFIG_WIFI_CONTROL_FUNC) || defined(CUSTOMER_HW4) +#if defined(CONFIG_WIFI_CONTROL_FUNC) #include #else #include @@ -134,6 +288,7 @@ typedef struct dhd_sta { #ifdef DHD_WMF struct dhd_sta *psta_prim; /* primary index of psta interface */ #endif /* DHD_WMF */ + chanspec_t chanspec; /* sta chanspec info */ } dhd_sta_t; typedef dhd_sta_t dhd_sta_pool_t; @@ -204,12 +359,6 @@ typedef struct dhd_tx_lb_pkttag_fr { #define dtohchanspec(i) (i) #endif /* IL_BIGENDINA */ -#if defined(DHD_TCP_WINSIZE_ADJUST) -#define MIN_TCP_WIN_SIZE 18000 -#define WIN_SIZE_SCALE_FACTOR 2 -#define MAX_TARGET_PORTS 5 -#endif /* DHD_TCP_WINSIZE_ADJUST */ - #ifdef BLOCK_IPV6_PACKET #define HEX_PREF_STR "0x" #define UNI_FILTER_STR "010000000000" @@ -230,35 +379,6 @@ extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd, int *dtim_period, int *bc extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); #endif /* OEM_ANDROID && BCMPCIE */ -#ifdef CUSTOMER_HW4 -#ifdef MIMO_ANT_SETTING -#ifdef DHD_EXPORT_CNTL_FILE -extern unsigned long antsel; -#endif /* DHD_EXPORT_CNTL_FILE */ -extern int dhd_sel_ant_from_file(dhd_pub_t *dhd); -#endif /* MIMO_ANT_SETTING */ -#ifdef WRITE_WLANINFO -#define MAX_VERSION_LEN 512 -#ifdef DHD_EXPORT_CNTL_FILE -extern char version_info[MAX_VERSION_LEN]; -#endif /* DHD_EXPORT_CNTL_FILE */ -extern uint32 sec_save_wlinfo(char *firm_ver, char *dhd_ver, char *nvram_p, char *clm_ver); -#endif /* WRITE_WLANINFO */ -#ifdef LOGTRACE_FROM_FILE -extern int dhd_logtrace_from_file(dhd_pub_t *dhd); -#ifdef DHD_EXPORT_CNTL_FILE -extern unsigned long logtrace_val; -#endif /* DHD_EXPORT_CNTL_FILE */ -#endif /* LOGTRACE_FROM_FILE */ -#ifdef GEN_SOFTAP_INFO_FILE -#define SOFTAP_INFO_BUF_SZ 512 -#ifdef DHD_EXPORT_CNTL_FILE -extern char softapinfostr[SOFTAP_INFO_BUF_SZ]; -#endif /* DHD_EXPORT_CNTL_FILE */ -extern uint32 sec_save_softap_info(void); -#endif /* GEN_SOFTAP_INFO_FILE */ -#endif /* CUSTOMER_HW4 */ - #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS extern uint32 report_hang_privcmd_err; #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */ @@ -272,65 +392,6 @@ extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int* idle_time); void traffic_mgmt_pkt_set_prio(dhd_pub_t *dhdp, void * pktbuf); #endif /* BCM_ROUTER_DHD */ -#ifdef DHD_LOG_DUMP -/* 0: DLD_BUF_TYPE_GENERAL, 1: DLD_BUF_TYPE_PRESERVE -* 2: DLD_BUF_TYPE_SPECIAL -*/ -#define DLD_BUFFER_NUM 3 - -#ifndef CUSTOM_LOG_DUMP_BUFSIZE_MB -#define CUSTOM_LOG_DUMP_BUFSIZE_MB 4 /* DHD_LOG_DUMP_BUF_SIZE 4 MB static memory in kernel */ -#endif /* CUSTOM_LOG_DUMP_BUFSIZE_MB */ - -#define LOG_DUMP_TOTAL_BUFSIZE (1024 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) - -/* - * Below are different sections that use the prealloced buffer - * and sum of the sizes of these should not cross LOG_DUMP_TOTAL_BUFSIZE - */ -#ifdef EWP_BCM_TRACE -#define LOG_DUMP_GENERAL_MAX_BUFSIZE (192 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) -#define LOG_DUMP_BCM_TRACE_MAX_BUFSIZE (64 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) -#else -#define LOG_DUMP_GENERAL_MAX_BUFSIZE (256 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) -#define LOG_DUMP_BCM_TRACE_MAX_BUFSIZE 0 -#endif /* EWP_BCM_TRACE */ -#define LOG_DUMP_PRESERVE_MAX_BUFSIZE (128 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) -#define LOG_DUMP_ECNTRS_MAX_BUFSIZE (256 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) -#define LOG_DUMP_RTT_MAX_BUFSIZE (256 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) -#define LOG_DUMP_FILTER_MAX_BUFSIZE (128 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) - -#if LOG_DUMP_TOTAL_BUFSIZE < \ - (LOG_DUMP_GENERAL_MAX_BUFSIZE + LOG_DUMP_PRESERVE_MAX_BUFSIZE + \ - LOG_DUMP_ECNTRS_MAX_BUFSIZE + LOG_DUMP_RTT_MAX_BUFSIZE + \ - LOG_DUMP_BCM_TRACE_MAX_BUFSIZE + LOG_DUMP_FILTER_MAX_BUFSIZE) -#error "LOG_DUMP_TOTAL_BUFSIZE is lesser than sum of all rings" -#endif - -/* Special buffer is allocated as separately in prealloc */ -#define LOG_DUMP_SPECIAL_MAX_BUFSIZE (8 * 1024) - -#define LOG_DUMP_MAX_FILESIZE (8 *1024 * 1024) /* 8 MB default */ - -#ifdef CONFIG_LOG_BUF_SHIFT -/* 15% of kernel log buf size, if for example klog buf size is 512KB -* 15% of 512KB ~= 80KB -*/ -#define LOG_DUMP_KERNEL_TAIL_FLUSH_SIZE \ - (15 * ((1 << CONFIG_LOG_BUF_SHIFT)/100)) -#endif /* CONFIG_LOG_BUF_SHIFT */ - -#define LOG_DUMP_COOKIE_BUFSIZE 1024u -typedef struct { - char *hdr_str; - log_dump_section_type_t sec_type; -} dld_hdr_t; - -#define DHD_PRINT_BUF_NAME_LEN 30 -void dhd_get_debug_dump_len(void *handle, struct sk_buff *skb, void *event_info, u8 event); -void cfgvendor_log_dump_len(dhd_pub_t *dhdp, log_dump_type_t *type, struct sk_buff *skb); -#endif /* DHD_LOG_DUMP */ - typedef struct dhd_if_event { struct list_head list; wl_event_data_if_t event; @@ -454,20 +515,24 @@ struct dhd_rx_tx_work { #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ #ifdef FILTER_IE +#ifdef DHD_LINUX_STD_FW_API +#define FILTER_IE_PATH "filter_ie" +#else #define FILTER_IE_PATH "/vendor/etc/wifi/filter_ie" +#endif /* DHD_LINUX_STD_FW_API */ #define FILTER_IE_BUFSZ 1024 /* ioc buffsize for FILTER_IE */ #define FILE_BLOCK_READ_SIZE 256 #define WL_FILTER_IE_IOV_HDR_SIZE OFFSETOF(wl_filter_ie_iov_v1_t, tlvs) #endif /* FILTER_IE */ #define NULL_CHECK(p, s, err) \ - do { \ - if (!(p)) { \ - printk("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ - err = BCME_ERROR; \ - return err; \ - } \ - } while (0) +do { \ + if (!(p)) { \ + DHD_ERROR(("NULL POINTER (%s) : %s\n", __FUNCTION__, (s))); \ + err = BCME_ERROR; \ + return err; \ + } \ +} while (0) int dhd_wifi_platform_register_drv(void); void dhd_wifi_platform_unregister_drv(void); @@ -505,22 +570,40 @@ void dhd_update_psta_interface_for_sta(dhd_pub_t *dhdp, char* ifname, void* mac_addr, void* event_data); #endif /* DHD_WMF */ -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) int dhd_net_bus_get(struct net_device *dev); int dhd_net_bus_put(struct net_device *dev); #endif /* BT_OVER_SDIO */ -#if defined(WLADPS) || defined(WLADPS_PRIVATE_CMD) +#if defined(WLADPS) #define ADPS_ENABLE 1 #define ADPS_DISABLE 0 +#define ADPS_MODE_PM2_ONLY 3 int dhd_enable_adps(dhd_pub_t *dhd, uint8 on); -#endif /* WLADPS || WLADPS_PRIVATE_CMD */ +#endif #ifdef DHDTCPSYNC_FLOOD_BLK extern void dhd_reset_tcpsync_info_by_ifp(dhd_if_t *ifp); extern void dhd_reset_tcpsync_info_by_dev(struct net_device *dev); #endif /* DHDTCPSYNC_FLOOD_BLK */ +extern void dhd_set_del_in_progress(dhd_pub_t *dhdp, struct net_device * ndev); +extern void dhd_clear_del_in_progress(dhd_pub_t *dhdp, struct net_device * ndev); #ifdef PCIE_FULL_DONGLE extern void dhd_net_del_flowrings_sta(dhd_pub_t * dhd, struct net_device * ndev); #endif /* PCIE_FULL_DONGLE */ int dhd_get_fw_capabilities(dhd_pub_t * dhd); +#ifdef BCMDBUS +int dhd_dbus_txdata(dhd_pub_t *dhdp, void *pktbuf); +#endif +void dhd_event_logtrace_enqueue(dhd_pub_t *dhdp, int ifidx, void *pktbuf); +#if defined(SUPPORT_MULTIPLE_NVRAM) || defined(SUPPORT_MULTIPLE_CLMBLOB) +int dhd_get_platform_naming_for_nvram_clmblob_file(download_type_t component, char* file_name); +#ifdef USE_CID_CHECK +void dhd_set_platform_ext_name_for_chip_version(char* chip_version); +#endif /* USE_CID_CHECK */ +#endif /* SUPPORT_MULTIPLE_NVRAM || SUPPORT_MULTIPLE_CLMBLOB */ +void dhd_netif_rx_ni(struct sk_buff * skb); +#if defined(DBG_PKT_MON) && !defined(PCIE_FULL_DONGLE) +extern bool dhd_80211_mon_pkt(dhd_pub_t *dhdp, void *pkt, int ifidx); +#endif /* DBG_PKT_MON */ + #endif /* __DHD_LINUX_H__ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_exportfs.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_exportfs.c old mode 100755 new mode 100644 index 702553175924..adc0efd6c2c2 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_exportfs.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_exportfs.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Linux-specific network interface * Basically selected code segments from usb-cdc.c and usb-rndis.c * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -30,9 +30,10 @@ #include #include #include -#if defined(DHD_ADPS_BAM_EXPORT) && defined(WL_BAM) +#include +#if defined(WL_BAM) #include -#endif /* DHD_ADPS_BAM_EXPORT && WL_BAM */ +#endif /* WL_BAM */ #ifdef PWRSTATS_SYSFS #include #endif /* PWRSTATS_SYSFS */ @@ -48,18 +49,28 @@ extern dhd_pub_t* g_dhd_pub; static int dhd_ring_proc_open(struct inode *inode, struct file *file); ssize_t dhd_ring_proc_read(struct file *file, char *buffer, size_t tt, loff_t *loff); -static const struct file_operations dhd_ring_proc_fops = { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)) +static const struct file_operations dhd_ring_proc_ops = { .open = dhd_ring_proc_open, .read = dhd_ring_proc_read, .release = single_release, }; +#else +static const struct proc_ops dhd_ring_proc_ops = { + .proc_open = dhd_ring_proc_open, + .proc_read = dhd_ring_proc_read, + .proc_release = single_release, +}; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0) */ static int dhd_ring_proc_open(struct inode *inode, struct file *file) { int ret = BCME_ERROR; if (inode) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)) + ret = single_open(file, 0, pde_data(inode)); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) ret = single_open(file, 0, PDE_DATA(inode)); #else /* This feature is not supported for lower kernel versions */ @@ -88,8 +99,14 @@ dhd_ring_proc_read(struct file *file, char __user *buffer, size_t tt, loff_t *lo trace_buf_info = (trace_buf_info_t *)MALLOCZ(g_dhd_pub->osh, sizeof(trace_buf_info_t)); if (trace_buf_info) { dhd_dbg_read_ring_into_trace_buf(ring, trace_buf_info); - if (copy_to_user(buffer, (void*)trace_buf_info->buf, MIN(trace_buf_info->size, tt))) - { + if (!buffer || (MIN(trace_buf_info->size, tt) > TRACE_LOG_BUF_MAX_SIZE)) { + DHD_ERROR(("%s: size %zu tt %zu trace_buf_sz %d\n", __FUNCTION__, + MIN(trace_buf_info->size, tt), tt, trace_buf_info->size)); + ret = -ENOMEM; + goto exit; + } + if (copy_to_user(buffer, (void*)trace_buf_info->buf, + MIN(trace_buf_info->size, tt))) { ret = -EFAULT; goto exit; } @@ -98,7 +115,7 @@ dhd_ring_proc_read(struct file *file, char __user *buffer, size_t tt, loff_t *lo else ret = trace_buf_info->size; } else - DHD_ERROR(("Memory allocation Failed\n")); + DHD_ERROR(("%s: Memory allocation Failed\n", __FUNCTION__)); exit: if (trace_buf_info) { @@ -115,11 +132,11 @@ dhd_dbg_ring_proc_create(dhd_pub_t *dhdp) dbg_verbose_ring = dhd_dbg_get_ring_from_ring_id(dhdp, FW_VERBOSE_RING_ID); if (dbg_verbose_ring) { - if (!proc_create_data("dhd_trace", S_IRUSR, NULL, &dhd_ring_proc_fops, + if (!proc_create_data("dhd_trace", S_IRUSR, NULL, &dhd_ring_proc_ops, dbg_verbose_ring)) { DHD_ERROR(("Failed to create /proc/dhd_trace procfs interface\n")); } else { - DHD_ERROR(("Created /proc/dhd_trace procfs interface\n")); + DHD_INFO(("Created /proc/dhd_trace procfs interface\n")); } } else { DHD_ERROR(("dbg_verbose_ring is NULL, /proc/dhd_trace not created\n")); @@ -127,20 +144,20 @@ dhd_dbg_ring_proc_create(dhd_pub_t *dhdp) #endif /* DEBUGABILITY */ #ifdef EWP_ECNTRS_LOGGING - if (!proc_create_data("dhd_ecounters", S_IRUSR, NULL, &dhd_ring_proc_fops, + if (!proc_create_data("dhd_ecounters", S_IRUSR, NULL, &dhd_ring_proc_ops, dhdp->ecntr_dbg_ring)) { DHD_ERROR(("Failed to create /proc/dhd_ecounters procfs interface\n")); } else { - DHD_ERROR(("Created /proc/dhd_ecounters procfs interface\n")); + DHD_INFO(("Created /proc/dhd_ecounters procfs interface\n")); } #endif /* EWP_ECNTRS_LOGGING */ #ifdef EWP_RTT_LOGGING - if (!proc_create_data("dhd_rtt", S_IRUSR, NULL, &dhd_ring_proc_fops, + if (!proc_create_data("dhd_rtt", S_IRUSR, NULL, &dhd_ring_proc_ops, dhdp->rtt_dbg_ring)) { DHD_ERROR(("Failed to create /proc/dhd_rtt procfs interface\n")); } else { - DHD_ERROR(("Created /proc/dhd_rtt procfs interface\n")); + DHD_INFO(("Created /proc/dhd_rtt procfs interface\n")); } #endif /* EWP_RTT_LOGGING */ } @@ -177,7 +194,6 @@ dhd_dbg_ring_proc_destroy(dhd_pub_t *dhdp) * ----------------------------------------------------------------------------- */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #if defined(DHD_TRACE_WAKE_LOCK) extern atomic_t trace_wklock_onoff; @@ -324,308 +340,6 @@ ecounter_onoff(struct dhd_info *dev, const char *buf, size_t count) return count; } -#if defined(DHD_QOS_ON_SOCK_FLOW) -#include - -static ssize_t -show_sock_qos_onoff(struct dhd_info *dev, char *buf) -{ - ssize_t ret = 0; - unsigned long onoff; - dhd_info_t *dhd = (dhd_info_t *)dev; - - onoff = dhd_sock_qos_get_status(dhd); - ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n", - onoff); - return ret; -} - -static ssize_t -update_sock_qos_onoff(struct dhd_info *dev, const char *buf, size_t count) -{ - unsigned long onoff; - dhd_info_t *dhd = (dhd_info_t *)dev; - - onoff = bcm_strtoul(buf, NULL, 10); - - sscanf(buf, "%lu", &onoff); - if (onoff != 0 && onoff != 1) { - return -EINVAL; - } - - dhd_sock_qos_set_status(dhd, onoff); - - return count; -} - -static ssize_t -show_sock_qos_upgrade(struct dhd_info *dev, char *buf) -{ - ssize_t ret = 0; - unsigned long onoff; - dhd_info_t *dhd = (dhd_info_t *)dev; - - onoff = dhd_sock_qos_get_force_upgrade(dhd); - ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n", - onoff); - return ret; -} - -static ssize_t -update_sock_qos_upgrade(struct dhd_info *dev, const char *buf, size_t count) -{ - unsigned long onoff; - dhd_info_t *dhd = (dhd_info_t *)dev; - - onoff = bcm_strtoul(buf, NULL, 10); - - sscanf(buf, "%lu", &onoff); - if (onoff != 0 && onoff != 1) { - return -EINVAL; - } - - dhd_sock_qos_set_force_upgrade(dhd, onoff); - - return count; -} - -static ssize_t -show_sock_qos_numfl_upgrd_thresh(struct dhd_info *dev, char *buf) -{ - ssize_t ret = 0; - int upgrade_thresh; - dhd_info_t *dhd = (dhd_info_t *)dev; - - upgrade_thresh = dhd_sock_qos_get_numfl_upgrd_thresh(dhd); - ret = scnprintf(buf, PAGE_SIZE - 1, "%d \n", - upgrade_thresh); - return ret; -} - -static ssize_t -update_sock_qos_numfl_upgrd_thresh(struct dhd_info *dev, const char *buf, size_t count) -{ - int upgrade_thresh; - dhd_info_t *dhd = (dhd_info_t *)dev; - - sscanf(buf, "%d", &upgrade_thresh); - if (upgrade_thresh < 0) { - return -EINVAL; - } - - dhd_sock_qos_set_numfl_upgrd_thresh(dhd, upgrade_thresh); - - return count; -} - -static ssize_t -show_sock_qos_avgpktsize_thresh(struct dhd_info *dev, char *buf) -{ - ssize_t ret = 0; - unsigned long avgpktsize_low, avgpktsize_high; - dhd_info_t *dhd = (dhd_info_t *)dev; - - dhd_sock_qos_get_avgpktsize_thresh(dhd, &avgpktsize_low, &avgpktsize_high); - ret = scnprintf(buf, PAGE_SIZE - 1, "%lu %lu\n", - avgpktsize_low, avgpktsize_high); - - return ret; -} - -static ssize_t -update_sock_qos_avgpktsize_thresh(struct dhd_info *dev, const char *buf, size_t count) -{ - unsigned long avgpktsize_low, avgpktsize_high; - dhd_info_t *dhd = (dhd_info_t *)dev; - - sscanf(buf, "%lu %lu", &avgpktsize_low, &avgpktsize_high); - - dhd_sock_qos_set_avgpktsize_thresh(dhd, avgpktsize_low, avgpktsize_high); - - return count; -} - -static ssize_t -show_sock_qos_numpkts_thresh(struct dhd_info *dev, char *buf) -{ - ssize_t ret = 0; - unsigned long numpkts_low, numpkts_high; - dhd_info_t *dhd = (dhd_info_t *)dev; - - dhd_sock_qos_get_numpkts_thresh(dhd, &numpkts_low, &numpkts_high); - ret = scnprintf(buf, PAGE_SIZE - 1, "%lu %lu\n", - numpkts_low, numpkts_high); - - return ret; -} - -static ssize_t -update_sock_qos_numpkts_thresh(struct dhd_info *dev, const char *buf, size_t count) -{ - unsigned long numpkts_low, numpkts_high; - dhd_info_t *dhd = (dhd_info_t *)dev; - - sscanf(buf, "%lu %lu", &numpkts_low, &numpkts_high); - - dhd_sock_qos_set_numpkts_thresh(dhd, numpkts_low, numpkts_high); - - return count; -} - -static ssize_t -show_sock_qos_detectcnt_thresh(struct dhd_info *dev, char *buf) -{ - ssize_t ret = 0; - unsigned char detectcnt_inc, detectcnt_dec; - dhd_info_t *dhd = (dhd_info_t *)dev; - - dhd_sock_qos_get_detectcnt_thresh(dhd, &detectcnt_inc, &detectcnt_dec); - ret = scnprintf(buf, PAGE_SIZE - 1, "%d %d\n", - detectcnt_inc, detectcnt_dec); - - return ret; -} - -static ssize_t -update_sock_qos_detectcnt_thresh(struct dhd_info *dev, const char *buf, size_t count) -{ - unsigned int detectcnt_inc, detectcnt_dec; - dhd_info_t *dhd = (dhd_info_t *)dev; - - sscanf(buf, "%u %u", &detectcnt_inc, &detectcnt_dec); - - dhd_sock_qos_set_detectcnt_thresh(dhd, detectcnt_inc, detectcnt_dec); - - return count; -} - -static ssize_t -show_sock_qos_detectcnt_upgrd_thresh(struct dhd_info *dev, char *buf) -{ - ssize_t ret = 0; - unsigned int detectcnt_upgrd_thresh; - dhd_info_t *dhd = (dhd_info_t *)dev; - - detectcnt_upgrd_thresh = dhd_sock_qos_get_detectcnt_upgrd_thresh(dhd); - ret = scnprintf(buf, PAGE_SIZE - 1, "%d \n", detectcnt_upgrd_thresh); - - return ret; -} - -static ssize_t -update_sock_qos_detectcnt_upgrd_thresh(struct dhd_info *dev, const char *buf, size_t count) -{ - unsigned int detectcnt_upgrd_thresh; - dhd_info_t *dhd = (dhd_info_t *)dev; - - sscanf(buf, "%u", &detectcnt_upgrd_thresh); - - dhd_sock_qos_set_detectcnt_upgrd_thresh(dhd, detectcnt_upgrd_thresh); - - return count; -} - -static ssize_t -show_sock_qos_maxfl(struct dhd_info *dev, char *buf) -{ - ssize_t ret = 0; - unsigned int maxfl; - dhd_info_t *dhd = (dhd_info_t *)dev; - - maxfl = dhd_sock_qos_get_maxfl(dhd); - ret = scnprintf(buf, PAGE_SIZE - 1, "%u \n", maxfl); - - return ret; -} - -static ssize_t -update_sock_qos_maxfl(struct dhd_info *dev, const char *buf, size_t count) -{ - unsigned int maxfl; - dhd_info_t *dhd = (dhd_info_t *)dev; - - sscanf(buf, "%u", &maxfl); - - dhd_sock_qos_set_maxfl(dhd, maxfl); - - return count; -} - -static ssize_t -show_sock_qos_stats(struct dhd_info *dev, char *buf) -{ - dhd_info_t *dhd = (dhd_info_t *)dev; - - dhd_sock_qos_show_stats(dhd, buf, PAGE_SIZE); - - return PAGE_SIZE - 1; -} - -static ssize_t -clear_sock_qos_stats(struct dhd_info *dev, const char *buf, size_t count) -{ - unsigned long clear; - dhd_info_t *dhd = (dhd_info_t *)dev; - - clear = bcm_strtoul(buf, NULL, 10); - - sscanf(buf, "%lu", &clear); - if (clear != 0) { - return -EINVAL; - } - - dhd_sock_qos_clear_stats(dhd); - - return count; -} - -#ifdef DHD_QOS_ON_SOCK_FLOW_UT - -/* - * test_id sub_id Description - * ------ ------ ----------- - * 1 0 psk_qos->sk_fl - * The number of free sk_fl entries in the Table is exhausted - * and more sockets are still getting created - * - * 1 1 psk_qos->sk_fl - * is Full for more than x seconds, there are lot of periodic - * flows, but none of them are detected for upgrade for more - * than 'x' seconds - * - * 2 Force upgrade the socket flows to reach skfl_upgrade_thresh - * check the behaviour - * - * Downgrade one of the sk_fls and check if the 'next' pending - * sk_fl is getting upgraded. The sk_fl getting upgraded - * should follow FIFO scheme. - * - * 3 Upgrade a socket flow ... after some time downgrade the - * same and check if the sk_fl is actually getting downgraded - * Keep switching the behavior every 'x' seconds and observe - * the switches - */ -static ssize_t -do_sock_qos_unit_test(struct dhd_info *dev, const char *buf, size_t count) -{ - unsigned int test_id = 0; - unsigned int sub_id = 0; - dhd_info_t *dhd = (dhd_info_t *)dev; - int ret; - - BCM_REFERENCE(dhd); - - ret = sscanf(buf, "%d %d", &test_id, &sub_id); - if (ret < 1) { - return -EINVAL; - } - - return count; -} - -#endif /* DHD_QOS_ON_SOCK_FLOW_UT */ -#endif /* DHD_QOS_ON_SOCK_FLOW */ - #ifdef DHD_SSSR_DUMP static ssize_t show_sssr_enab(struct dhd_info *dev, char *buf) @@ -739,6 +453,32 @@ store_nvram_path(struct dhd_info *dev, const char *buf, size_t count) return count; } +extern char signature_path[]; + +static ssize_t +show_signature_path(struct dhd_info *dev, char *buf) +{ + ssize_t ret = 0; + ret = scnprintf(buf, PAGE_SIZE - 1, "%s\n", signature_path); + + return ret; +} + +static ssize_t +store_signature_path(struct dhd_info *dev, const char *buf, size_t count) +{ + char fmt_spec[FMT_BUFSZ] = ""; + + if ((int)strlen(buf) >= MOD_PARAM_PATHLEN) { + return -EINVAL; + } + + snprintf(fmt_spec, FMT_BUFSZ, "%%%ds", MOD_PARAM_PATHLEN - 1); + sscanf(buf, fmt_spec, signature_path); + + return count; +} + #ifdef PWRSTATS_SYSFS typedef struct wl_pwrstats_sysfs { uint64 current_ts; @@ -767,12 +507,62 @@ static const char pwrstr_cnt[] = "count:"; static const char pwrstr_dur[] = "duration_usec:"; static const char pwrstr_ts[] = "last_entry_timestamp_usec:"; +ssize_t print_pwrstats_cum(char *buf) +{ + ssize_t ret = 0; + + ret += scnprintf(buf, PAGE_SIZE, "WIFI\n"); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "AWAKE:\n"); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_cnt, + accumstats.awake_cnt); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_dur, + accumstats.awake_dur); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_ts, + laststats.awake_last_entry_us); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "ASLEEP:\n"); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_cnt, + accumstats.pm_cnt); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_dur, + accumstats.pm_dur); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_ts, + laststats.pm_last_entry_us); + + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\nWIFI-PCIE\n"); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "L0:\n"); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_cnt, + accumstats.l0_cnt); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_dur, + accumstats.l0_dur_us); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "L1:\n"); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_cnt, + accumstats.l1_cnt); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_dur, + accumstats.l1_dur_us); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "L1_1:\n"); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_cnt, + accumstats.l1_1_cnt); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_dur, + accumstats.l1_1_dur_us); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "L1_2:\n"); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_cnt, + accumstats.l1_2_cnt); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_dur, + accumstats.l1_2_dur_us); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "L2:\n"); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_cnt, + accumstats.l2_cnt); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s 0x%0llx\n", pwrstr_dur, + accumstats.l2_dur_us); + + return ret; +} + void update_pwrstats_cum(uint64 *accum, uint64 *last, uint64 *now, bool force) { if (accum) { /* accumulation case, ex; counts, duration */ if (*now < *last) { - if (force || ((*last - *now) > USEC_PER_MSEC)) { - /* not to update accum for pm_dur/awake_dur case */ + if (force) { + /* force update for pm_cnt/awake_cnt and PCIE stats */ *accum += *now; *last = *now; } @@ -796,6 +586,26 @@ static const uint16 pwrstats_req_type[] = { + sizeof(wl_pwr_pm_accum_stats_v1_t) \ + (uint)strlen("pwrstats") + 1 +#ifdef BCMPCIE +extern uint64 dhdpcie_get_last_suspend_time(dhd_pub_t *dhdp); +#endif /* BCMPCIE */ + +#ifdef BCMSDIO +extern uint64 dhdsdio_get_last_suspend_time(dhd_pub_t *dhdp); +#endif /* BCMSDIO */ + +uint64 +dhd_get_last_suspend_time(dhd_pub_t *dhdp) +{ +#if defined(BCMPCIE) + return dhdpcie_get_last_suspend_time(dhdp); +#elif defined(BCMSDIO) + return dhdsdio_get_last_suspend_time(dhdp); +#else + return 0; +#endif +} + static ssize_t show_pwrstats_path(struct dhd_info *dev, char *buf) { @@ -814,6 +624,34 @@ show_pwrstats_path(struct dhd_info *dev, char *buf) ASSERT(g_dhd_pub); + /* Even if dongle is in D3 state, + * ASLEEP duration should be updated with estimated value. + */ + if (!dhd_os_check_if_up(&dhd->pub)) { + if (dhd->pub.busstate == DHD_BUS_SUSPEND) { + static uint64 last_suspend_end_time = 0; + uint64 curr_time = 0, estimated_pm_dur = 0; + + if (last_suspend_end_time < + dhd_get_last_suspend_time(&dhd->pub)) { + last_suspend_end_time = dhd_get_last_suspend_time(&dhd->pub); + } + + curr_time = OSL_LOCALTIME_NS(); + if (curr_time >= last_suspend_end_time) { + estimated_pm_dur = DIV_U64_BY_U32( + (curr_time - last_suspend_end_time), NSEC_PER_USEC); + estimated_pm_dur += laststats.pm_dur; + + update_pwrstats_cum(&accumstats.pm_dur, &laststats.pm_dur, + &estimated_pm_dur, FALSE); + last_suspend_end_time = curr_time; + } + } + ret = print_pwrstats_cum(buf); + goto done; /* Not ready yet */ + } + len = PWRSTATS_IOV_BUF_LEN; iovar_buf = (char *)MALLOCZ(g_dhd_pub->osh, len); if (iovar_buf == NULL) { @@ -841,6 +679,7 @@ show_pwrstats_path(struct dhd_info *dev, char *buf) iovar_buf, PWRSTATS_IOV_BUF_LEN, NULL); if (err != BCME_OK) { DHD_ERROR(("error (%d) - size = %zu\n", err, sizeof(wl_pwrstats_t))); + ret = print_pwrstats_cum(buf); goto done; } @@ -938,6 +777,11 @@ show_pwrstats_path(struct dhd_info *dev, char *buf) *(uint8**)&p_data += taglen; } while (len >= BCM_XTLV_HDR_SIZE); + /* [awake|pm]_last_entry_us are provided based on host timestamp. + * These are calculated by dongle timestamp + (delta time of host & dongle) + * If the newly calculated delta time is more than 1 second gap from + * the existing delta time, it is updated to compensate more accurately. + */ OSL_GET_LOCALTIME(&ts_sec, &ts_usec); time_delta = ts_sec * USEC_PER_SEC + ts_usec - pwrstats_sysfs.current_ts; if ((time_delta > last_delta) && @@ -954,24 +798,9 @@ show_pwrstats_path(struct dhd_info *dev, char *buf) update_pwrstats_cum(&accumstats.pm_dur, &laststats.pm_dur, &pwrstats_sysfs.pm_dur, FALSE); update_pwrstats_cum(NULL, &laststats.awake_last_entry_us, - &pwrstats_sysfs.awake_last_entry_us, TRUE); + &pwrstats_sysfs.awake_last_entry_us, FALSE); update_pwrstats_cum(NULL, &laststats.pm_last_entry_us, - &pwrstats_sysfs.pm_last_entry_us, TRUE); - - ret += scnprintf(buf, PAGE_SIZE - 1, "AWAKE:\n"); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt, - accumstats.awake_cnt); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur, - accumstats.awake_dur); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_ts, - laststats.awake_last_entry_us); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "ASLEEP:\n"); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt, - accumstats.pm_cnt); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur, - accumstats.pm_dur); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_ts, - laststats.pm_last_entry_us); + &pwrstats_sysfs.pm_last_entry_us, FALSE); update_pwrstats_cum(&accumstats.l0_cnt, &laststats.l0_cnt, &pwrstats_sysfs.l0_cnt, TRUE); @@ -994,32 +823,7 @@ show_pwrstats_path(struct dhd_info *dev, char *buf) update_pwrstats_cum(&accumstats.l2_dur_us, &laststats.l2_dur_us, &pwrstats_sysfs.l2_dur_us, TRUE); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "L0:\n"); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt, - accumstats.l0_cnt); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur, - accumstats.l0_dur_us); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "L1:\n"); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt, - accumstats.l1_cnt); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur, - accumstats.l1_dur_us); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "L1_1:\n"); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt, - accumstats.l1_1_cnt); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur, - accumstats.l1_1_dur_us); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "L1_2:\n"); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt, - accumstats.l1_2_cnt); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur, - accumstats.l1_2_dur_us); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "L2:\n"); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt, - accumstats.l2_cnt); - ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur, - accumstats.l2_dur_us); - + ret = print_pwrstats_cum(buf); done: if (p_query) { MFREE(g_dhd_pub->osh, p_query, len); @@ -1031,7 +835,40 @@ done: return ret; } #endif /* PWRSTATS_SYSFS */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ + +static ssize_t +show_tcm_test_mode(struct dhd_info *dev, char *buf) +{ + ssize_t ret = 0; + unsigned long mode; + + mode = dhd_tcm_test_mode; + ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n", + mode); + return ret; +} + +static ssize_t +set_tcm_test_mode(struct dhd_info *dev, const char *buf, size_t count) +{ + unsigned long mode; + + mode = bcm_strtoul(buf, NULL, 10); + + sscanf(buf, "%lu", &mode); + if (mode > TCM_TEST_MODE_ALWAYS) { + return -EINVAL; + } + + /* reset with the mode change */ + if (dhd_tcm_test_mode != mode) { + dhd_tcm_test_status = TCM_TEST_NOT_RUN; + } + + dhd_tcm_test_mode = (uint)mode; + + return count; +} /* * Generic Attribute Structure for DHD. @@ -1048,7 +885,6 @@ struct dhd_attr { ssize_t(*store)(struct dhd_info *, const char *, size_t count); }; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #if defined(DHD_TRACE_WAKE_LOCK) static struct dhd_attr dhd_attr_wklock = __ATTR(wklock_trace, 0660, show_wklock_trace, wklock_trace_onoff); @@ -1066,45 +902,6 @@ static struct dhd_attr dhd_attr_logdump_ecntr = static struct dhd_attr dhd_attr_ecounters = __ATTR(ecounters, 0660, show_enable_ecounter, ecounter_onoff); -#if defined(DHD_QOS_ON_SOCK_FLOW) -static struct dhd_attr dhd_attr_sock_qos_onoff = - __ATTR(sock_qos_onoff, 0660, show_sock_qos_onoff, update_sock_qos_onoff); - -static struct dhd_attr dhd_attr_sock_qos_stats = - __ATTR(sock_qos_stats, 0660, show_sock_qos_stats, clear_sock_qos_stats); - -static struct dhd_attr dhd_attr_sock_qos_upgrade = - __ATTR(sock_qos_upgrade, 0660, show_sock_qos_upgrade, update_sock_qos_upgrade); - -static struct dhd_attr dhd_attr_sock_qos_numfl_upgrd_thresh = - __ATTR(sock_qos_numfl_upgrd_thresh, 0660, show_sock_qos_numfl_upgrd_thresh, - update_sock_qos_numfl_upgrd_thresh); - -static struct dhd_attr dhd_attr_sock_qos_avgpktsize_thresh = - __ATTR(sock_qos_avgpktsize_thresh, 0660, show_sock_qos_avgpktsize_thresh, - update_sock_qos_avgpktsize_thresh); - -static struct dhd_attr dhd_attr_sock_qos_numpkts_thresh = - __ATTR(sock_qos_numpkts_thresh, 0660, show_sock_qos_numpkts_thresh, - update_sock_qos_numpkts_thresh); - -static struct dhd_attr dhd_attr_sock_qos_detectcnt_thresh = - __ATTR(sock_qos_detectcnt_thresh, 0660, show_sock_qos_detectcnt_thresh, - update_sock_qos_detectcnt_thresh); - -static struct dhd_attr dhd_attr_sock_qos_detectcnt_upgrd_thresh = - __ATTR(sock_qos_detectcnt_upgrd_thresh, 0660, show_sock_qos_detectcnt_upgrd_thresh, - update_sock_qos_detectcnt_upgrd_thresh); - -static struct dhd_attr dhd_attr_sock_qos_maxfl = - __ATTR(sock_qos_maxfl, 0660, show_sock_qos_maxfl, - update_sock_qos_maxfl); -#if defined(DHD_QOS_ON_SOCK_FLOW_UT) -static struct dhd_attr dhd_attr_sock_qos_unit_test = - __ATTR(sock_qos_unit_test, 0660, NULL, do_sock_qos_unit_test); -#endif -#endif /* DHD_QOS_ON_SOCK_FLOW */ - #ifdef DHD_SSSR_DUMP static struct dhd_attr dhd_attr_sssr_enab = __ATTR(sssr_enab, 0660, show_sssr_enab, set_sssr_enab); @@ -1118,16 +915,20 @@ static struct dhd_attr dhd_attr_firmware_path = static struct dhd_attr dhd_attr_nvram_path = __ATTR(nvram_path, 0660, show_nvram_path, store_nvram_path); +static struct dhd_attr dhd_attr_sig_path = + __ATTR(signature_path, 0660, show_signature_path, store_signature_path); + #ifdef PWRSTATS_SYSFS static struct dhd_attr dhd_attr_pwrstats_path = - __ATTR(power_stats, 0660, show_pwrstats_path, NULL); + __ATTR(power_stats, 0664, show_pwrstats_path, NULL); #endif /* PWRSTATS_SYSFS */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ + +static struct dhd_attr dhd_attr_tcm_test_mode = + __ATTR(tcm_test_mode, 0660, show_tcm_test_mode, set_tcm_test_mode); #define to_dhd(k) container_of(k, struct dhd_info, dhd_kobj) #define to_attr(a) container_of(a, struct dhd_attr, attr) -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #ifdef DHD_MAC_ADDR_EXPORT struct ether_addr sysfs_mac_addr; static ssize_t @@ -1159,7 +960,6 @@ set_mac_addr(struct dhd_info *dev, const char *buf, size_t count) static struct dhd_attr dhd_attr_macaddr = __ATTR(mac_addr, 0660, show_mac_addr, set_mac_addr); #endif /* DHD_MAC_ADDR_EXPORT */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ #ifdef DHD_FW_COREDUMP /* @@ -1191,8 +991,8 @@ get_mem_val_from_file(void) int ret = 0; /* Read memdump info from the file */ - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); #if defined(CONFIG_X86) && defined(OEM_ANDROID) /* Check if it is Live Brix Image */ @@ -1202,8 +1002,8 @@ get_mem_val_from_file(void) /* Try if it is Installed Brix Image */ filepath = MEMDUMPINFO_INST; DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath)); - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); goto done; } @@ -1213,10 +1013,10 @@ get_mem_val_from_file(void) } /* Handle success case */ - ret = kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32)); + ret = dhd_kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32)); if (ret < 0) { DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret)); - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); goto done; } @@ -1224,7 +1024,7 @@ get_mem_val_from_file(void) p_mem_val[sizeof(uint32) - 1] = '\0'; mem_val = bcm_atoi(p_mem_val); - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); done: return mem_val; @@ -1268,7 +1068,6 @@ void dhd_get_memdump_info(dhd_pub_t *dhd) DHD_ERROR(("%s: MEMDUMP ENABLED = %u\n", __FUNCTION__, dhd->memdump_enabled)); } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #ifdef DHD_EXPORT_CNTL_FILE static ssize_t show_memdump_info(struct dhd_info *dev, char *buf) @@ -1310,7 +1109,6 @@ set_memdump_info(struct dhd_info *dev, const char *buf, size_t count) static struct dhd_attr dhd_attr_memdump = __ATTR(memdump, 0660, show_memdump_info, set_memdump_info); #endif /* DHD_EXPORT_CNTL_FILE */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ #endif /* DHD_FW_COREDUMP */ #ifdef BCMASSERT_LOG @@ -1335,11 +1133,11 @@ get_assert_val_from_file(void) * 2: Trigger Kernel crash by BUG() * File doesn't exist: Keep default value (1). */ - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); } else { - int ret = kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32)); + int ret = dhd_kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32)); if (ret < 0) { DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret)); } else { @@ -1348,14 +1146,10 @@ get_assert_val_from_file(void) mem_val = bcm_atoi(p_mem_val); DHD_ERROR(("%s: ASSERT ENABLED = %d\n", __FUNCTION__, mem_val)); } - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); } -#ifdef CUSTOMER_HW4_DEBUG - mem_val = (mem_val >= 0) ? mem_val : 1; -#else mem_val = (mem_val >= 0) ? mem_val : 0; -#endif /* CUSTOMER_HW4_DEBUG */ return mem_val; } @@ -1370,7 +1164,6 @@ void dhd_get_assert_info(dhd_pub_t *dhd) #endif /* !DHD_EXPORT_CNTL_FILE */ } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #ifdef DHD_EXPORT_CNTL_FILE static ssize_t show_assert_info(struct dhd_info *dev, char *buf) @@ -1405,10 +1198,8 @@ set_assert_info(struct dhd_info *dev, const char *buf, size_t count) static struct dhd_attr dhd_attr_assert = __ATTR(assert, 0660, show_assert_info, set_assert_info); #endif /* DHD_EXPORT_CNTL_FILE */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ #endif /* BCMASSERT_LOG */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #ifdef DHD_EXPORT_CNTL_FILE #if defined(WRITE_WLANINFO) static ssize_t @@ -1821,8 +1612,9 @@ static struct dhd_attr dhd_attr_proptx = #endif /* USE_WFA_CERT_CONF */ #endif /* DHD_EXPORT_CNTL_FILE */ -#if defined(DHD_ADPS_BAM_EXPORT) && defined(WL_BAM) +#if defined(WL_BAM) #define BAD_AP_MAC_ADDR_ELEMENT_NUM 6 +#define MACF_READ "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx" wl_bad_ap_mngr_t *g_bad_ap_mngr = NULL; static ssize_t @@ -1868,10 +1660,10 @@ store_adps_bam_list(struct dhd_info *dev, const char *buf, size_t count) len = count; offset = 0; do { - ret = sscanf(buf + offset, MACF"\n", - (uint32 *)&bad_ap.bssid.octet[0], (uint32 *)&bad_ap.bssid.octet[1], - (uint32 *)&bad_ap.bssid.octet[2], (uint32 *)&bad_ap.bssid.octet[3], - (uint32 *)&bad_ap.bssid.octet[4], (uint32 *)&bad_ap.bssid.octet[5]); + ret = sscanf(buf + offset, MACF_READ"\n", + &bad_ap.bssid.octet[0], &bad_ap.bssid.octet[1], + &bad_ap.bssid.octet[2], &bad_ap.bssid.octet[3], + &bad_ap.bssid.octet[4], &bad_ap.bssid.octet[5]); if (ret != BAD_AP_MAC_ADDR_ELEMENT_NUM) { DHD_ERROR(("%s - fail to parse bad ap data\n", __FUNCTION__)); return -EINVAL; @@ -1899,12 +1691,10 @@ store_adps_bam_list(struct dhd_info *dev, const char *buf, size_t count) static struct dhd_attr dhd_attr_adps_bam = __ATTR(bad_ap_list, 0660, show_adps_bam_list, store_adps_bam_list); -#endif /* DHD_ADPS_BAM_EXPORT && WL_BAM */ -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ +#endif /* WL_BAM */ uint32 report_hang_privcmd_err = 1; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS static ssize_t show_hang_privcmd_err(struct dhd_info *dev, char *buf) @@ -1963,6 +1753,148 @@ __ATTR(control_logtrace, 0660, show_control_logtrace, set_control_logtrace); uint8 control_he_enab = 1; #endif /* DISABLE_HE_ENAB || CUSTOM_CONTROL_HE_ENAB */ +#ifdef RX_PKT_POOL +static ssize_t +show_max_rx_pkt_pool(struct dhd_info *dhd, char *buf) +{ + ssize_t ret = 0; + if (!dhd) { + DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); + return ret; + } + + ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", dhd->rx_pkt_pool.max_size); + return ret; +} + +static ssize_t +set_max_rx_pkt_pool(struct dhd_info *dhd, const char *buf, size_t count) +{ + uint32 val; + + if (!dhd) { + DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); + return count; + } + + val = bcm_atoi(buf); + + dhd->rx_pkt_pool.max_size = ((val > MAX_RX_PKT_POOL) && + (val <= (MAX_RX_PKT_POOL * 8))) ? val : MAX_RX_PKT_POOL; + DHD_ERROR(("%s: MAX_RX_PKT_POOL: %d\n", __FUNCTION__, dhd->rx_pkt_pool.max_size)); + return count; +} + +static struct dhd_attr dhd_attr_max_rx_pkt_pool= +__ATTR(dhd_max_rx_pkt_pool, 0660, show_max_rx_pkt_pool, set_max_rx_pkt_pool); +#endif /* RX_PKT_POOL */ + +#ifdef PCIE_FULL_DONGLE +static ssize_t +dhd_set_aspm_enab(struct dhd_info *dhd, const char *buf, size_t count) +{ + unsigned long aspm_enab; + dhd_pub_t *dhdp = &dhd->pub; + + aspm_enab = bcm_strtoul(buf, NULL, 10); + + sscanf(buf, "%lu", &aspm_enab); + if (aspm_enab != 0 && aspm_enab != 1) { + return -EINVAL; + } + dhd_bus_aspm_enable_rc_ep(dhdp->bus, aspm_enab); + + return count; +} + +static ssize_t +show_aspm_enab(struct dhd_info *dhd, char *buf) +{ + ssize_t ret = 0; + bool aspm_enab; + dhd_pub_t *dhdp = &dhd->pub; + if (!dhd) { + DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); + return ret; + } + + aspm_enab = dhd_bus_is_aspm_enab_rc_ep(dhdp->bus); + ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", aspm_enab); + + return ret; +} + +static struct dhd_attr dhd_attr_aspm_enab = +__ATTR(aspm_enab, 0660, show_aspm_enab, dhd_set_aspm_enab); + +static ssize_t +dhd_set_l1ss_enab(struct dhd_info *dhd, const char *buf, size_t count) +{ + unsigned long l1ss_enab; + dhd_pub_t *dhdp = &dhd->pub; + + l1ss_enab = bcm_strtoul(buf, NULL, 10); + + sscanf(buf, "%lu", &l1ss_enab); + if (l1ss_enab != 0 && l1ss_enab != 1) { + return -EINVAL; + } + dhd_bus_l1ss_enable_rc_ep(dhdp->bus, l1ss_enab); + return count; +} + +static ssize_t +show_l1ss_enab(struct dhd_info *dhd, char *buf) +{ + ssize_t ret = 0; + bool l1ss_enab; + dhd_pub_t *dhdp = &dhd->pub; + if (!dhd) { + DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); + return ret; + } + + l1ss_enab = dhd_bus_is_l1ss_enab_rc_ep(dhdp->bus); + ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", l1ss_enab); + + return ret; +} + +static struct dhd_attr dhd_attr_l1ss_enab = +__ATTR(l1ss_enab, 0660, show_l1ss_enab, dhd_set_l1ss_enab); +#endif /* PCIE_FULL_DONGLE */ + +#ifdef RPM_FAST_TRIGGER +static ssize_t +dhd_show_fast_rpm_thresh(struct dhd_info *dev, char *buf) +{ + ssize_t ret = 0; + unsigned long val; + + val = dhd_fast_runtimepm_ms; + ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n", val); + return ret; +} + +static ssize_t +dhd_set_fast_rpm_thresh(struct dhd_info *dev, const char *buf, size_t count) +{ + unsigned long val; + + val = bcm_strtoul(buf, NULL, 10); + + sscanf(buf, "%lu", &val); + /* Ensure fast RPM threashold is lesser than regular RPM threshold */ + if (val == 0 || val >= dhd_runtimepm_ms) { + return -EINVAL; + } + dhd_fast_runtimepm_ms = val; + return count; +} +static struct dhd_attr dhd_attr_fast_rpm_thresh = +__ATTR(fast_rpm_thresh, 0660, dhd_show_fast_rpm_thresh, dhd_set_fast_rpm_thresh); +#endif /* RPM_FAST_TRIGGER */ + #if defined(CUSTOM_CONTROL_HE_ENAB) static ssize_t show_control_he_enab(struct dhd_info *dev, char *buf) @@ -2159,10 +2091,9 @@ static struct dhd_attr dhd_attr_dhd_debug_data = __ATTR(dump_stateinfo, 0660, dhd_debug_dump_stateinfo, NULL); #ifdef WL_CFG80211 -#define _S(x) #x -#define S(x) _S(x) #define SUBLOGLEVEL 20 #define SUBLOGLEVELZ ((SUBLOGLEVEL) + (1)) + static const struct { u32 log_level; char *sublogname; @@ -2172,7 +2103,8 @@ static const struct { {WL_DBG_DBG, "DBG"}, {WL_DBG_SCAN, "SCAN"}, {WL_DBG_TRACE, "TRACE"}, - {WL_DBG_P2P_ACTION, "P2PACTION"} + {WL_DBG_P2P_ACTION, "P2PACTION"}, + {WL_DBG_PNO, "PNO"} }; /** @@ -2230,7 +2162,7 @@ set_wl_debug_level(struct dhd_info *dhd, const char *buf, size_t count) if (colon != NULL) { *colon = ' '; } - tokens = sscanf(token, "%"S(SUBLOGLEVEL)"s %u", sublog, &log_on); + tokens = sscanf(token, "%"SIZE_CONST_STRING(SUBLOGLEVEL)"s %u", sublog, &log_on); if (colon != NULL) *colon = ':'; @@ -2238,12 +2170,17 @@ set_wl_debug_level(struct dhd_info *dhd, const char *buf, size_t count) for (i = 0; i < ARRAYSIZE(sublogname_map); i++) { if (!strncmp(sublog, sublogname_map[i].sublogname, strlen(sublogname_map[i].sublogname))) { - if (log_on) + if (log_on) { wl_dbg_level |= (sublogname_map[i].log_level); - else + wl_log_level |= + (sublogname_map[i].log_level); + } else { wl_dbg_level &= ~(sublogname_map[i].log_level); + wl_log_level &= + ~(sublogname_map[i].log_level); + } } } } else @@ -2260,6 +2197,75 @@ static struct dhd_attr dhd_attr_wl_dbg_level = __ATTR(wl_dbg_level, 0660, show_wl_debug_level, set_wl_debug_level); #endif /* WL_CFG80211 */ +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) +#define DUMP_TRIGGER 1 + +static ssize_t +show_dhd_dump_in_progress(struct dhd_info *dhd, char *buf) +{ + size_t ret = 0; + dhd_dongledump_status_t dump_status; + + if (!dhd) { + DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); + return BCME_ERROR; + } + + dump_status = dhd_get_dump_status(&dhd->pub); + ret = scnprintf(buf, PAGE_SIZE - 1, "%d \n", dump_status); + + return ret; +} + +static ssize_t +set_dhd_dump_in_progress(struct dhd_info *dhd, const char *buf, size_t count) +{ + uint32 input; + dhd_dongledump_status_t dump_status; + + if (!dhd) { + DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); + return count; + } + + dump_status = dhd_get_dump_status(&dhd->pub); + if (dump_status == DUMP_NOT_READY || dump_status == DUMP_IN_PROGRESS) { + DHD_ERROR(("%s: Could not start dongle dump: %d\n", + __FUNCTION__, dump_status)); + goto exit; + } + + input = bcm_atoi(buf); + if (input == DUMP_TRIGGER) { + DHD_INFO(("%s: Trigger dongle dump\n", __FUNCTION__)); + dhd_set_dump_status(&dhd->pub, DUMP_IN_PROGRESS); + schedule_work(&dhd->dhd_dump_proc_work); + } + else { + DHD_ERROR(("%s: Invalid value %d\n", __FUNCTION__, input)); + } + +exit: + return count; +} + +static struct dhd_attr dhd_attr_dump_in_progress = +__ATTR(dump_in_progress, 0660, show_dhd_dump_in_progress, set_dhd_dump_in_progress); +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ + +#ifdef DHD_DUMP_START_COMMAND +static ssize_t +trigger_dhd_dump_start_command(struct dhd_info *dhd, char *buf) +{ + ssize_t ret = 0; + DHD_ERROR(("%s: dump_start command delivered.\n", __FUNCTION__)); + return ret; +} + +static struct dhd_attr dhd_attr_dump_start_command = + __ATTR(dump_start, 0664, trigger_dhd_dump_start_command, NULL); +#endif /* DHD_DUMP_START_COMMAND */ + /* Attribute object that gets registered with "wifi" kobject tree */ static struct attribute *default_file_attrs[] = { #ifdef DHD_MAC_ADDR_EXPORT @@ -2306,9 +2312,9 @@ static struct attribute *default_file_attrs[] = { #endif /* PROP_TXSTATUS */ #endif /* USE_WFA_CERT_CONF */ #endif /* DHD_EXPORT_CNTL_FILE */ -#if defined(DHD_ADPS_BAM_EXPORT) && defined(WL_BAM) +#if defined(WL_BAM) &dhd_attr_adps_bam.attr, -#endif /* DHD_ADPS_BAM_EXPORT && WL_BAM */ +#endif /* WL_BAM */ #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS &dhd_attr_hang_privcmd_err.attr, #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */ @@ -2323,20 +2329,6 @@ static struct attribute *default_file_attrs[] = { &dhd_attr_logdump_ecntr.attr, #endif &dhd_attr_ecounters.attr, -#ifdef DHD_QOS_ON_SOCK_FLOW - &dhd_attr_sock_qos_onoff.attr, - &dhd_attr_sock_qos_stats.attr, - &dhd_attr_sock_qos_upgrade.attr, - &dhd_attr_sock_qos_numfl_upgrd_thresh.attr, - &dhd_attr_sock_qos_avgpktsize_thresh.attr, - &dhd_attr_sock_qos_numpkts_thresh.attr, - &dhd_attr_sock_qos_detectcnt_thresh.attr, - &dhd_attr_sock_qos_detectcnt_upgrd_thresh.attr, - &dhd_attr_sock_qos_maxfl.attr, -#ifdef DHD_QOS_ON_SOCK_FLOW_UT - &dhd_attr_sock_qos_unit_test.attr, -#endif /* DHD_QOS_ON_SOCK_FLOW_UT */ -#endif /* DHD_QOS_ON_SOCK_FLOW */ #ifdef DHD_SSSR_DUMP &dhd_attr_sssr_enab.attr, &dhd_attr_fis_enab.attr, @@ -2355,16 +2347,42 @@ static struct attribute *default_file_attrs[] = { #if defined(WL_CFG80211) &dhd_attr_wl_dbg_level.attr, #endif /* WL_CFG80211 */ +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) + &dhd_attr_dump_in_progress.attr, +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ +#ifdef DHD_DUMP_START_COMMAND + &dhd_attr_dump_start_command.attr, +#endif /* DHD_DUMP_START_COMMAND */ &dhd_attr_dhd_debug_data.attr, #if defined(AGG_H2D_DB) &dhd_attr_agg_h2d_db_enab.attr, &dhd_attr_agg_h2d_db_inflight_thresh.attr, &dhd_attr_agg_h2d_db_timeout.attr, #endif /* AGG_H2D_DB */ +#if defined(RX_PKT_POOL) + &dhd_attr_max_rx_pkt_pool.attr, +#endif /* RX_PKT_POOL */ +#ifdef PCIE_FULL_DONGLE + &dhd_attr_aspm_enab.attr, + &dhd_attr_l1ss_enab.attr, +#endif /* PCIE_FULL_DONGLE */ +#ifdef RPM_FAST_TRIGGER + &dhd_attr_fast_rpm_thresh.attr, +#endif /* RPM_FAST_TRIGGER */ + &dhd_attr_sig_path.attr, + &dhd_attr_tcm_test_mode.attr, NULL }; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) +static const struct attribute_group default_group = { + .attrs = default_file_attrs +}; +static const struct attribute_group *default_groups[] = { + &default_group, + NULL +}; +#endif /* LINUX_VER >= 5.18 */ /* * wifi kobject show function, the "attr" attribute specifices to which * node under "sys/wifi" the show function is called. @@ -2413,46 +2431,24 @@ static ssize_t dhd_store(struct kobject *kobj, struct attribute *attr, } -static struct sysfs_ops dhd_sysfs_ops = { +static const struct sysfs_ops dhd_sysfs_ops = { .show = dhd_show, .store = dhd_store, }; static struct kobj_type dhd_ktype = { .sysfs_ops = &dhd_sysfs_ops, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) + .default_groups = default_groups, +#else .default_attrs = default_file_attrs, -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ +#endif /* LINUX_VER >= 5.18 */ }; -#ifdef CSI_SUPPORT -/* Function to show current ccode */ -static ssize_t read_csi_data(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) -{ - dhd_info_t *dhd = to_dhd(kobj); - int n = 0; - - n = dhd_csi_dump_list(&dhd->pub, buf); - DHD_INFO(("Dump data to file, size %d\n", n)); - dhd_csi_clean_list(&dhd->pub); - - return n; -} - -static struct bin_attribute dhd_attr_csi = { - .attr = { .name = "csi" BUS_TYPE, - .mode = 0660, }, - .size = MAX_CSI_FILESZ, - .read = read_csi_data, -}; -#endif /* CSI_SUPPORT */ - /* * sysfs for dhd_lb */ #ifdef DHD_LB -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #if defined(DHD_LB_TXP) static ssize_t show_lbtxp(struct dhd_info *dev, char *buf) @@ -2561,7 +2557,7 @@ set_lb_rxp_stop_thr(struct dhd_info *dev, const char *buf, size_t count) } dhdp = &dhd->pub; - lb_rxp_stop_thr = bcm_strtoul(buf, NULL, 10); + lb_rxp_stop_thr = (uint32)bcm_strtoul(buf, NULL, 10); sscanf(buf, "%u", &lb_rxp_stop_thr); /* disable lb_rxp flow ctrl */ @@ -2620,7 +2616,7 @@ set_lb_rxp_strt_thr(struct dhd_info *dev, const char *buf, size_t count) } dhdp = &dhd->pub; - lb_rxp_strt_thr = bcm_strtoul(buf, NULL, 10); + lb_rxp_strt_thr = (uint32)bcm_strtoul(buf, NULL, 10); sscanf(buf, "%u", &lb_rxp_strt_thr); /* disable lb_rxp flow ctrl */ @@ -2847,8 +2843,16 @@ static struct attribute *debug_lb_attrs[] = { &dhd_tx_cpu.attr, NULL }; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) +static const struct attribute_group debug_lb_group = { + .attrs = debug_lb_attrs +}; +static const struct attribute_group *debug_lb_groups[] = { + &debug_lb_group, + NULL +}; +#endif /* LINUX_VER >= 5.18 */ #define to_dhd_lb(k) container_of(k, struct dhd_info, dhd_lb_kobj) /* @@ -2899,24 +2903,267 @@ static ssize_t dhd_lb_store(struct kobject *kobj, struct attribute *attr, } -static struct sysfs_ops dhd_sysfs_lb_ops = { +static const struct sysfs_ops dhd_sysfs_lb_ops = { .show = dhd_lb_show, .store = dhd_lb_store, }; static struct kobj_type dhd_lb_ktype = { .sysfs_ops = &dhd_sysfs_lb_ops, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) + .default_groups = debug_lb_groups, +#else .default_attrs = debug_lb_attrs, -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ +#endif /* LINUX_VER >= 5.18 */ }; #endif /* DHD_LB */ +#ifdef BCMPCIE +#define CONST_SYNA_DHD_KOBJ_NAME "wifi_pcie" +#define CONST_SYNA_DHD_CSI_OBJ_NAME "csi" +#define CONST_SYNA_DHD_LB_OBJ_NAME "lb_pcie" +#else /* BCMSDIO */ +#define CONST_SYNA_DHD_KOBJ_NAME "wifi_sdio" +#define CONST_SYNA_DHD_CSI_OBJ_NAME "csi" +#define CONST_SYNA_DHD_LB_OBJ_NAME "lb_sdio" +#endif /* BCMPCIE */ + +/* + * ************ DPC BOUNDS ************* + */ + +static ssize_t +show_ctrl_cpl_post_bound(struct dhd_info *dev, char *buf) +{ + ssize_t ret = 0; + + ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", + dhd_prot_get_ctrl_cpl_post_bound(&dev->pub)); + return ret; +} + +static ssize_t +set_ctrl_cpl_post_bound(struct dhd_info *dev, const char *buf, size_t count) +{ + int val; + + val = (uint32)bcm_atoi(buf); + if (val <= 0) + { + DHD_ERROR(("%s : invalid ctrl_cpl_post_bound %u\n", + __FUNCTION__, val)); + return count; + } + + dhd_prot_set_ctrl_cpl_post_bound(&dev->pub, val); + return count; +} + +static ssize_t +show_tx_post_bound(struct dhd_info *dev, char *buf) +{ + ssize_t ret = 0; + + ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", dhd_prot_get_tx_post_bound(&dev->pub)); + return ret; +} + +static ssize_t +set_tx_post_bound(struct dhd_info *dev, const char *buf, size_t count) +{ + int val; + + val = (uint32)bcm_atoi(buf); + if (val <= 0) + { + DHD_ERROR(("%s : invalid tx_post_bound %u\n", + __FUNCTION__, val)); + return count; + } + + dhd_prot_set_tx_post_bound(&dev->pub, val); + return count; +} + +static ssize_t +show_rx_cpl_post_bound(struct dhd_info *dev, char *buf) +{ + ssize_t ret = 0; + + ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", + dhd_prot_get_rx_cpl_post_bound(&dev->pub)); + return ret; +} + +static ssize_t +set_rx_cpl_post_bound(struct dhd_info *dev, const char *buf, size_t count) +{ + int val; + + val = (uint32)bcm_atoi(buf); + if (val <= 0) + { + DHD_ERROR(("%s : invalid rx_cpl_post_bound %u\n", + __FUNCTION__, val)); + return count; + } + + dhd_prot_set_rx_cpl_post_bound(&dev->pub, val); + return count; +} + +static ssize_t +show_tx_cpl_bound(struct dhd_info *dev, char *buf) +{ + ssize_t ret = 0; + + ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", dhd_prot_get_tx_cpl_bound(&dev->pub)); + return ret; +} + +static ssize_t +set_tx_cpl_bound(struct dhd_info *dev, const char *buf, size_t count) +{ + int val; + + val = (uint32)bcm_atoi(buf); + if (val <= 0) + { + DHD_ERROR(("%s : invalid tx_cpl_bound %u\n", + __FUNCTION__, val)); + return count; + } + + dhd_prot_set_tx_cpl_bound(&dev->pub, val); + return count; +} + +static struct dhd_attr dhd_attr_ctrl_cpl_post_bound = +__ATTR(ctrl_cpl_post_bound, 0660, show_ctrl_cpl_post_bound, set_ctrl_cpl_post_bound); +static struct dhd_attr dhd_attr_tx_post_bound = +__ATTR(tx_post_bound, 0660, show_tx_post_bound, set_tx_post_bound); +static struct dhd_attr dhd_attr_rx_cpl_post_bound = +__ATTR(rx_cpl_post_bound, 0660, show_rx_cpl_post_bound, set_rx_cpl_post_bound); +static struct dhd_attr dhd_attr_tx_cpl_bound = +__ATTR(tx_cpl_bound, 0660, show_tx_cpl_bound, set_tx_cpl_bound); + +static struct attribute *debug_dpc_bounds_attrs[] = { + &dhd_attr_tx_cpl_bound.attr, + &dhd_attr_rx_cpl_post_bound.attr, + &dhd_attr_tx_post_bound.attr, + &dhd_attr_ctrl_cpl_post_bound.attr, + NULL +}; + +#define to_dhd_dpc_bounds(k) container_of(k, struct dhd_info, dhd_dpc_bounds_kobj) + +/* + * wifi/dpc_bounds kobject show function, the "attr" attribute specifices to which + * node under "sys/wifi/dpc_bounds" the show function is called. + */ +static ssize_t dhd_dpc_bounds_show(struct kobject *kobj, struct attribute *attr, char *buf) +{ + dhd_info_t *dhd; + struct dhd_attr *d_attr; + int ret; + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + dhd = to_dhd_dpc_bounds(kobj); + d_attr = to_attr(attr); + GCC_DIAGNOSTIC_POP(); + + if (d_attr->show) + ret = d_attr->show(dhd, buf); + else + ret = -EIO; + + return ret; +} + +/* + * wifi/dpc_bounds kobject store function, the "attr" attribute specifices to which + * node under "sys/wifi/dpc_bounds" the store function is called. + */ +static ssize_t dhd_dpc_bounds_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + dhd_info_t *dhd; + struct dhd_attr *d_attr; + int ret; + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + dhd = to_dhd_dpc_bounds(kobj); + d_attr = to_attr(attr); + GCC_DIAGNOSTIC_POP(); + + if (d_attr->store) + ret = d_attr->store(dhd, buf, count); + else + ret = -EIO; + + return ret; + +} + +static struct sysfs_ops dhd_sysfs_dpc_bounds_ops = { + .show = dhd_dpc_bounds_show, + .store = dhd_dpc_bounds_store, +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) +static const struct attribute_group debug_dpc_bounds_group = { + .attrs = debug_dpc_bounds_attrs +}; +static const struct attribute_group *debug_dpc_bounds_groups[] = { + &debug_dpc_bounds_group, + NULL +}; +#endif /* LINUX_VER >= 5.18 */ + +static struct kobj_type dhd_dpc_bounds_ktype = { + .sysfs_ops = &dhd_sysfs_dpc_bounds_ops, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) + .default_groups = debug_dpc_bounds_groups, +#else + .default_attrs = debug_dpc_bounds_attrs, +#endif /* LINUX_VER >= 5.18 */ +}; + +/* + * ************************************* + */ + +#ifdef CSI_SUPPORT +/* Function to show current ccode */ +static ssize_t read_csi_data(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) +{ + dhd_info_t *dhd = to_dhd(kobj); + int n = 0; + + n = dhd_csi_retrieve_queue_data(&dhd->pub, buf, (uint)count); + DHD_TRACE(("Dump data to file, size %d\n", n)); + + return n; +} + +static struct bin_attribute dhd_attr_csi = { + .attr = { + .name = CONST_SYNA_DHD_CSI_OBJ_NAME, + .mode = 0660 + }, + .size = MAX_CSI_FILESZ, + .read = read_csi_data, +}; +#endif /* CSI_SUPPORT */ + /* Create a kobject and attach to sysfs interface */ int dhd_sysfs_init(dhd_info_t *dhd) { int ret = -1; + dhd->flag_kobj = 0x0; + if (dhd == NULL) { DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__)); return ret; @@ -2928,17 +3175,10 @@ int dhd_sysfs_init(dhd_info_t *dhd) kobject_put(&dhd->dhd_kobj); DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__)); return ret; + } else { + dhd->flag_kobj |= 0x01; } -#ifdef CSI_SUPPORT - ret = sysfs_create_bin_file(&dhd->dhd_kobj, &dhd_attr_csi); - if (ret) { - DHD_ERROR(("%s: can't create %s\n", __FUNCTION__, dhd_attr_csi.attr.name)); - kobject_put(&dhd->dhd_kobj); - return ret; - } -#endif /* CSI_SUPPORT */ - /* * We are always responsible for sending the uevent that the kobject * was added to the system. @@ -2950,13 +3190,35 @@ int dhd_sysfs_init(dhd_info_t *dhd) &dhd_lb_ktype, &dhd->dhd_kobj, "lb"); if (ret) { kobject_put(&dhd->dhd_lb_kobj); - DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__)); + DHD_ERROR(("%s(): Unable to allocate kobject for 'lb'\r\n", __FUNCTION__)); return ret; + } else { + dhd->flag_kobj |= 0x02; } kobject_uevent(&dhd->dhd_lb_kobj, KOBJ_ADD); #endif /* DHD_LB */ + /* DPC bounds */ + ret = kobject_init_and_add(&dhd->dhd_dpc_bounds_kobj, + &dhd_dpc_bounds_ktype, &dhd->dhd_kobj, "dpc_bounds"); + if (ret) { + kobject_put(&dhd->dhd_dpc_bounds_kobj); + DHD_ERROR(("%s(): Unable to allocate kobject for 'dpc_bounds'\r\n", __FUNCTION__)); + return ret; + } + kobject_uevent(&dhd->dhd_dpc_bounds_kobj, KOBJ_ADD); + +#ifdef CSI_SUPPORT + ret = sysfs_create_bin_file(&dhd->dhd_kobj, &dhd_attr_csi); + if (ret) { + DHD_ERROR(("%s: can't create %s\n", __func__, dhd_attr_csi.attr.name)); + return ret; + } else { + dhd->flag_kobj |= 0x04; + } +#endif /* CSI_SUPPORT */ + return ret; } @@ -2968,13 +3230,27 @@ void dhd_sysfs_exit(dhd_info_t *dhd) return; } +#ifdef CSI_SUPPORT + if (0x04 & dhd->flag_kobj) { + sysfs_remove_bin_file(&dhd->dhd_kobj, &dhd_attr_csi); + } +#endif /* CSI_SUPPORT */ + #ifdef DHD_LB - kobject_put(&dhd->dhd_lb_kobj); + if (0X02 & dhd->flag_kobj) { + kobject_put(&dhd->dhd_lb_kobj); + } #endif /* DHD_LB */ - /* Releae the kobject */ - if (dhd->dhd_kobj.state_initialized) + /* DPC bounds */ + kobject_put(&dhd->dhd_dpc_bounds_kobj); + + /* Release the kobject */ + if (0X01 & dhd->flag_kobj) { kobject_put(&dhd->dhd_kobj); + } + + dhd->flag_kobj = 0X0; } #ifdef DHD_SUPPORT_HDM diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_lb.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_lb.c old mode 100755 new mode 100644 index 69b3081d1d5a..dfb5ab6edb89 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_lb.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_lb.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Linux-specific network interface * Basically selected code segments from usb-cdc.c and usb-rndis.c * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -35,12 +35,6 @@ extern dhd_pub_t* g_dhd_pub; #define DHD_NAPI_LATENCY_SIZE (sizeof(uint64) * DHD_NUM_NAPI_LATENCY_ROWS) #endif /* DHD_LB_STATS */ -#ifdef DHD_REPLACE_LOG_INFO_TO_TRACE -#define DHD_LB_INFO DHD_TRACE -#else -#define DHD_LB_INFO DHD_INFO -#endif /* DHD_REPLACE_LOG_INFO_TO_TRACE */ - void dhd_lb_set_default_cpus(dhd_info_t *dhd) { @@ -173,8 +167,22 @@ void dhd_select_cpu_candidacy(dhd_info_t *dhd) * cpumask_next returns >= nr_cpu_ids */ tx_cpu = cpumask_next(napi_cpu, dhd->cpumask_primary_new); - if (tx_cpu >= nr_cpu_ids) - tx_cpu = 0; + if (tx_cpu >= nr_cpu_ids) { + /* If no CPU is available for tx processing in primary CPUs, + * choose the same CPU with net_tx_cpu + * in case net_tx_cpu is in primary CPUs. + */ + cpumask_and(dhd->cpumask_primary_new, dhd->cpumask_primary, + dhd->cpumask_curr_avail); + + if (cpumask_test_cpu(net_tx_cpu, dhd->cpumask_primary_new)) { + tx_cpu = net_tx_cpu; + DHD_INFO(("%s If no CPU is for tx cpu, use net_tx_cpu %d\n", + __FUNCTION__, net_tx_cpu)); + } else { + tx_cpu = 0; + } + } } DHD_INFO(("%s After primary CPU check napi_cpu %d tx_cpu %d\n", @@ -200,24 +208,31 @@ void dhd_select_cpu_candidacy(dhd_info_t *dhd) } else if (tx_cpu == 0) { tx_cpu = cpumask_first(dhd->cpumask_secondary_new); } - - /* If no CPU was available for tx processing, choose CPU 0 */ - if (tx_cpu >= nr_cpu_ids) - tx_cpu = 0; } if ((primary_available_cpus == 0) && (secondary_available_cpus == 0)) { /* No CPUs available from primary or secondary mask */ - napi_cpu = 1; - tx_cpu = 2; + tx_cpu = napi_cpu = nr_cpu_ids - 1; } - DHD_INFO(("%s After secondary CPU check napi_cpu %d tx_cpu %d\n", - __FUNCTION__, napi_cpu, tx_cpu)); + /* If no CPU was available for napi processing, choose CPU 0 */ + if (napi_cpu >= nr_cpu_ids) + napi_cpu = 0; - ASSERT(napi_cpu < nr_cpu_ids); - ASSERT(tx_cpu < nr_cpu_ids); + /* If no CPU was available for tx processing, choose CPU 0 */ + if (tx_cpu >= nr_cpu_ids) + tx_cpu = 0; + + DHD_INFO(("%s After secondary CPU check napi_cpu %d tx_cpu %d nr cpu ids %d\n", + __FUNCTION__, napi_cpu, tx_cpu, nr_cpu_ids)); + + if (!cpu_online(napi_cpu)) { + napi_cpu = 0; + } + if (!cpu_online(tx_cpu)) { + tx_cpu = 0; + } atomic_set(&dhd->rx_napi_cpu, napi_cpu); atomic_set(&dhd->tx_cpu, tx_cpu); @@ -237,6 +252,12 @@ int dhd_cpu_startup_callback(unsigned int cpu) { dhd_info_t *dhd = g_dhd_pub->info; + if (!dhd || !(dhd->dhd_state & DHD_ATTACH_STATE_LB_ATTACH_DONE)) { + DHD_ERROR(("%s(): LB data is not initialized yet.\n", + __FUNCTION__)); + return 0; + } + DHD_INFO(("%s(): \r\n cpu:%d", __FUNCTION__, cpu)); DHD_LB_STATS_INCR(dhd->cpu_online_cnt[cpu]); cpumask_set_cpu(cpu, dhd->cpumask_curr_avail); @@ -249,6 +270,12 @@ int dhd_cpu_teardown_callback(unsigned int cpu) { dhd_info_t *dhd = g_dhd_pub->info; + if (!dhd || !(dhd->dhd_state & DHD_ATTACH_STATE_LB_ATTACH_DONE)) { + DHD_ERROR(("%s(): LB data is not initialized yet.\n", + __FUNCTION__)); + return 0; + } + DHD_INFO(("%s(): \r\n cpu:%d", __FUNCTION__, cpu)); DHD_LB_STATS_INCR(dhd->cpu_offline_cnt[cpu]); cpumask_clear_cpu(cpu, dhd->cpumask_curr_avail); @@ -299,14 +326,13 @@ dhd_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) int dhd_register_cpuhp_callback(dhd_info_t *dhd) { - int cpuhp_ret = 0; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)) - cpuhp_ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "dhd", + dhd->dhd_cpuhp_state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "dhd", dhd_cpu_startup_callback, dhd_cpu_teardown_callback); - if (cpuhp_ret < 0) { + if (dhd->dhd_cpuhp_state < 0) { DHD_ERROR(("%s(): cpuhp_setup_state failed %d RX LB won't happen \r\n", - __FUNCTION__, cpuhp_ret)); + __FUNCTION__, dhd->dhd_cpuhp_state)); } #else /* @@ -317,7 +343,7 @@ int dhd_register_cpuhp_callback(dhd_info_t *dhd) dhd->cpu_notifier.notifier_call = dhd_cpu_callback; register_hotcpu_notifier(&dhd->cpu_notifier); /* Register a callback */ #endif /* LINUX_VERSION_CODE < 4.10.0 */ - return cpuhp_ret; + return dhd->dhd_cpuhp_state; } int dhd_unregister_cpuhp_callback(dhd_info_t *dhd) @@ -325,12 +351,14 @@ int dhd_unregister_cpuhp_callback(dhd_info_t *dhd) int ret = 0; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)) /* Don't want to call tear down while unregistering */ - cpuhp_remove_state_nocalls(CPUHP_AP_ONLINE_DYN); + if (dhd->dhd_cpuhp_state >= 0) { + cpuhp_remove_state_nocalls(dhd->dhd_cpuhp_state); + } #else if (dhd->cpu_notifier.notifier_call != NULL) { unregister_cpu_notifier(&dhd->cpu_notifier); } -#endif +#endif /* LINUX_VERSION_CODE < 4.10.0 */ return ret; } @@ -647,7 +675,7 @@ void dhd_lb_stats_dump_cpu_array(struct bcmstrbuf *strbuf, uint32 *p) uint64 dhd_lb_mem_usage(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) { dhd_info_t *dhd; - uint16 rxbufpost_sz; + uint16 rxbufpost_alloc_sz; uint16 rx_post_active = 0; uint16 rx_cmpl_active = 0; uint64 rx_path_memory_usage = 0; @@ -663,28 +691,30 @@ uint64 dhd_lb_mem_usage(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) DHD_ERROR(("%s(): DHD pointer is NULL \n", __FUNCTION__)); return 0; } - rxbufpost_sz = dhd_prot_get_rxbufpost_sz(dhdp); - if (rxbufpost_sz == 0) { - rxbufpost_sz = DHD_FLOWRING_RX_BUFPOST_PKTSZ; + rxbufpost_alloc_sz = dhd_prot_get_rxbufpost_alloc_sz(dhdp); + if (rxbufpost_alloc_sz == 0) { + rxbufpost_alloc_sz = DHD_FLOWRING_RX_BUFPOST_PKTSZ; } - rx_path_memory_usage = rxbufpost_sz * (skb_queue_len(&dhd->rx_pend_queue) + + rx_path_memory_usage = rxbufpost_alloc_sz * (skb_queue_len(&dhd->rx_emerge_queue) + + skb_queue_len(&dhd->rx_pend_queue) + skb_queue_len(&dhd->rx_napi_queue) + skb_queue_len(&dhd->rx_process_queue)); rx_post_active = dhd_prot_get_h2d_rx_post_active(dhdp); if (rx_post_active != 0) { - rx_path_memory_usage += (rxbufpost_sz * rx_post_active); + rx_path_memory_usage += (rxbufpost_alloc_sz * rx_post_active); } rx_cmpl_active = dhd_prot_get_d2h_rx_cpln_active(dhdp); if (rx_cmpl_active != 0) { - rx_path_memory_usage += (rxbufpost_sz * rx_cmpl_active); + rx_path_memory_usage += (rxbufpost_alloc_sz * rx_cmpl_active); } dhdp->rxpath_mem = rx_path_memory_usage; - bcm_bprintf(strbuf, "\nrxbufpost_sz: %d rx_post_active: %d rx_cmpl_active: %d " - "pend_queue_len: %d napi_queue_len: %d process_queue_len: %d\n", - rxbufpost_sz, rx_post_active, rx_cmpl_active, - skb_queue_len(&dhd->rx_pend_queue), + bcm_bprintf(strbuf, "\nrxbufpost_alloc_sz: %d rx_post_active: %d rx_cmpl_active: %d " + "emerge_queue_len: %d pend_queue_len: %d napi_queue_len: %d" + " process_queue_len: %d\n", + rxbufpost_alloc_sz, rx_post_active, rx_cmpl_active, + skb_queue_len(&dhd->rx_emerge_queue), skb_queue_len(&dhd->rx_pend_queue), skb_queue_len(&dhd->rx_napi_queue), skb_queue_len(&dhd->rx_process_queue)); bcm_bprintf(strbuf, "DHD rx-path memory_usage: %llubytes %lluKB \n", rx_path_memory_usage, (rx_path_memory_usage/ 1024)); @@ -708,6 +738,7 @@ void dhd_lb_stats_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) return; } + bcm_bprintf(strbuf, "\nLoad Balancing/NAPI stats:\n==========================\n"); bcm_bprintf(strbuf, "\ncpu_online_cnt:\n"); dhd_lb_stats_dump_cpu_array(strbuf, dhd->cpu_online_cnt); @@ -731,6 +762,13 @@ void dhd_lb_stats_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) dhd_lb_stats_dump_histo(dhdp, strbuf, dhd->napi_rx_hist); bcm_bprintf(strbuf, "\nNAPI poll latency stats ie from napi schedule to napi execution\n"); dhd_lb_stats_dump_napi_latency(dhdp, strbuf, dhd->napi_latency); + + bcm_bprintf(strbuf, "\nlb_rxp_stop_thr_hitcnt: %llu lb_rxp_strt_thr_hitcnt: %llu" + " rx_dma_stall_hc_ignore_cnt: %llu\n", + dhdp->lb_rxp_stop_thr_hitcnt, dhdp->lb_rxp_strt_thr_hitcnt, + dhdp->rx_dma_stall_hc_ignore_cnt); + bcm_bprintf(strbuf, "\nlb_rxp_napi_sched_cnt: %llu lb_rxp_napi_omplete_cnt: %llu\n", + dhdp->lb_rxp_napi_sched_cnt, dhdp->lb_rxp_napi_complete_cnt); #endif /* DHD_LB_RXP */ #ifdef DHD_LB_TXP @@ -740,6 +778,7 @@ void dhd_lb_stats_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) bcm_bprintf(strbuf, "\ntx_start_percpu_run_cnt:\n"); dhd_lb_stats_dump_cpu_array(strbuf, dhd->tx_start_percpu_run_cnt); #endif /* DHD_LB_TXP */ + bcm_bprintf(strbuf, "\n"); } void dhd_lb_stats_update_napi_latency(uint64 *bin, uint32 latency) @@ -986,7 +1025,7 @@ dhd_napi_poll(struct napi_struct *napi, int budget) napi_latency = (uint32)(OSL_SYSUPTIME_US() - dhd->napi_schedule_time); dhd_lb_stats_update_napi_latency(dhd->napi_latency, napi_latency); #endif /* DHD_LB_STATS */ - DHD_LB_INFO(("%s napi_queue<%d> budget<%d>\n", + DHD_INFO(("%s napi_queue<%d> budget<%d>\n", __FUNCTION__, skb_queue_len(&dhd->rx_napi_queue), budget)); /* @@ -1008,7 +1047,7 @@ dhd_napi_poll(struct napi_struct *napi, int budget) ifid = DHD_PKTTAG_IFID((dhd_pkttag_fr_t *)PKTTAG(skb)); - DHD_LB_INFO(("%s dhd_rx_frame pkt<%p> ifid<%d>\n", + DHD_INFO(("%s dhd_rx_frame pkt<%p> ifid<%d>\n", __FUNCTION__, skb, ifid)); dhd_rx_frame(&dhd->pub, ifid, skb, pkt_count, chan); @@ -1032,7 +1071,7 @@ dhd_napi_poll(struct napi_struct *napi, int budget) } DHD_LB_STATS_UPDATE_NAPI_HISTO(&dhd->pub, processed); - DHD_LB_INFO(("%s processed %d\n", __FUNCTION__, processed)); + DHD_INFO(("%s processed %d\n", __FUNCTION__, processed)); /* * Signal napi complete only when no more packets are processed and @@ -1076,6 +1115,21 @@ dhd_napi_schedule(void *info) DHD_INFO(("%s rx_napi_struct<%p> on cpu<%d>\n", __FUNCTION__, &dhd->rx_napi_struct, atomic_read(&dhd->rx_napi_cpu))); + /* On Android platform, napi prevention during suspend in progress causes + * rx performance drop of ~5Mbs(SWWLAN-349763). + * So, excludes this prevention for Android platform. + */ +#ifndef OEM_ANDROID + DHD_GENERAL_LOCK(&dhd->pub, flags); + + if (DHD_BUS_BUSY_CHECK_SUSPEND_IN_PROGRESS(&dhd->pub)) { + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + return; + } + + DHD_GENERAL_UNLOCK(&dhd->pub, flags); +#endif /* OEM_ANDROID */ + /* add napi_struct to softnet data poll list and raise NET_RX_SOFTIRQ */ if (napi_schedule_prep(&dhd->rx_napi_struct)) { @@ -1104,31 +1158,6 @@ dhd_napi_schedule(void *info) */ } -/** - * dhd_napi_schedule_on - API to schedule on a desired CPU core a NET_RX_SOFTIRQ - * action after placing the dhd's rx_process napi object in the the remote CPU's - * softnet data's poll_list. - * - * @dhd: dhd_info which has the rx_process napi object - * @on_cpu: desired remote CPU id - */ -static INLINE int -dhd_napi_schedule_on(dhd_info_t *dhd, int on_cpu) -{ - int wait = 0; /* asynchronous IPI */ - DHD_INFO(("%s dhd<%p> napi<%p> on_cpu<%d>\n", - __FUNCTION__, dhd, &dhd->rx_napi_struct, on_cpu)); - - if (smp_call_function_single(on_cpu, dhd_napi_schedule, dhd, wait)) { - DHD_ERROR(("%s smp_call_function_single on_cpu<%d> failed\n", - __FUNCTION__, on_cpu)); - } - - DHD_LB_STATS_INCR(dhd->napi_sched_cnt); - - return 0; -} - /* * Call get_online_cpus/put_online_cpus around dhd_napi_schedule_on * Why should we do this? @@ -1186,7 +1215,7 @@ dhd_lb_rx_napi_dispatch(dhd_pub_t *dhdp) return; } - DHD_LB_INFO(("%s append napi_queue<%d> pend_queue<%d>\n", __FUNCTION__, + DHD_INFO(("%s append napi_queue<%d> pend_queue<%d>\n", __FUNCTION__, skb_queue_len(&dhd->rx_napi_queue), skb_queue_len(&dhd->rx_pend_queue))); /* append the producer's queue of packets to the napi's rx process queue */ @@ -1236,7 +1265,7 @@ dhd_lb_rx_napi_dispatch(dhd_pub_t *dhdp) } - DHD_LB_INFO(("%s : schedule to curr_cpu : %d, rx_napi_cpu : %d\n", + DHD_INFO(("%s : schedule to curr_cpu : %d, rx_napi_cpu : %d\n", __FUNCTION__, curr_cpu, rx_napi_cpu)); dhd_work_schedule_on(&dhd->rx_napi_dispatcher_work, rx_napi_cpu); DHD_LB_STATS_INCR(dhd->napi_sched_cnt); @@ -1244,6 +1273,26 @@ dhd_lb_rx_napi_dispatch(dhd_pub_t *dhdp) put_cpu(); } +/** + * dhd_rx_emerge_enqueue - Enqueue the packet into the ememrgency queue for repost + */ +void +dhd_rx_emerge_enqueue(dhd_pub_t *dhdp, void *pkt) +{ + dhd_info_t *dhd = dhdp->info; + skb_queue_tail(&dhd->rx_emerge_queue, pkt); +} + +/** + * dhd_rx_emerge_dequeue - Deueue the packet from the emergency queue for repost + */ +void * +dhd_rx_emerge_dequeue(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd = dhdp->info; + return skb_dequeue(&dhd->rx_emerge_queue); +} + /** * dhd_lb_rx_pkt_enqueue - Enqueue the packet into the producer's queue */ @@ -1252,7 +1301,7 @@ dhd_lb_rx_pkt_enqueue(dhd_pub_t *dhdp, void *pkt, int ifidx) { dhd_info_t *dhd = dhdp->info; - DHD_LB_INFO(("%s enqueue pkt<%p> ifidx<%d> pend_queue<%d>\n", __FUNCTION__, + DHD_INFO(("%s enqueue pkt<%p> ifidx<%d> pend_queue<%d>\n", __FUNCTION__, pkt, ifidx, skb_queue_len(&dhd->rx_pend_queue))); DHD_PKTTAG_SET_IFID((dhd_pkttag_fr_t *)PKTTAG(pkt), ifidx); __skb_queue_tail(&dhd->rx_pend_queue, pkt); @@ -1304,7 +1353,9 @@ BCMFASTPATH(dhd_lb_sendpkt)(dhd_info_t *dhd, struct net_device *net, #endif /* DHD_LB_TXP */ #ifdef DHD_LB_TXP +#ifndef DHD_LB_TXBOUND #define DHD_LB_TXBOUND 64 +#endif /* * Function that performs the TX processing on a given CPU */ @@ -1351,7 +1402,7 @@ dhd_lb_tx_process(dhd_info_t *dhd) } while (1); - DHD_LB_INFO(("%s(): Processed %d packets \r\n", __FUNCTION__, cnt)); + DHD_INFO(("%s(): Processed %d packets \r\n", __FUNCTION__, cnt)); return resched; } @@ -1369,7 +1420,7 @@ dhd_lb_tx_handler(unsigned long data) #endif /* DHD_LB_TXP */ #endif /* DHD_LB */ -#if defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON) +#if defined(SET_PCIE_IRQ_CPU_CORE) || defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON) void dhd_irq_set_affinity(dhd_pub_t *dhdp, const struct cpumask *cpumask) { @@ -1399,4 +1450,77 @@ dhd_irq_set_affinity(dhd_pub_t *dhdp, const struct cpumask *cpumask) DHD_ERROR(("%s : irq set affinity is failed cpu:0x%lx\n", __FUNCTION__, *cpumask_bits(cpumask))); } -#endif /* DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */ +#endif /* SET_PCIE_IRQ_CPU_CORE || DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */ + +#ifdef SET_PCIE_IRQ_CPU_CORE +void +dhd_set_irq_cpucore(dhd_pub_t *dhdp, int affinity_cmd) +{ +#if defined(DHD_LB) && defined(DHD_LB_HOST_CTRL) + struct dhd_info *dhd = NULL; +#endif /* DHD_LB && DHD_LB_HOST_CTRL */ + + if (!dhdp) { + DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); + return; + } + + if (!dhdp->bus) { + DHD_ERROR(("%s : dhd->bus is NULL\n", __FUNCTION__)); + return; + } + + if (affinity_cmd < DHD_AFFINITY_OFF || affinity_cmd > DHD_AFFINITY_LAST) { + DHD_ERROR(("Wrong Affinity cmds:%d, %s\n", affinity_cmd, __FUNCTION__)); + return; + } + + DHD_ERROR(("Enter %s, PCIe affinity cmd=0x%x\n", __FUNCTION__, affinity_cmd)); + +#if defined(DHD_LB) && defined(DHD_LB_HOST_CTRL) + dhd = dhdp->info; + + if (affinity_cmd == DHD_AFFINITY_OFF) { + dhd->permitted_primary_cpu = FALSE; + } else if (affinity_cmd == DHD_AFFINITY_TPUT_150MBPS || + affinity_cmd == DHD_AFFINITY_TPUT_300MBPS) { + dhd->permitted_primary_cpu = TRUE; + } + dhd_select_cpu_candidacy(dhd); + /* + * It needs to NAPI disable -> enable to raise NET_RX napi CPU core + * during Rx traffic + * NET_RX does not move to NAPI CPU core if continusly calling napi polling + * function + */ + napi_disable(&dhd->rx_napi_struct); + napi_enable(&dhd->rx_napi_struct); +#endif /* DHD_LB && DHD_LB_HOST_CTRL */ + + /* + irq_set_affinity() assign dedicated CPU core PCIe interrupt + If dedicated CPU core is not on-line, + PCIe interrupt scheduled on CPU core 0 + */ + switch (affinity_cmd) { + case DHD_AFFINITY_OFF: +#if defined(DHD_LB) && defined(DHD_LB_HOST_CTRL) + dhd_irq_set_affinity(dhdp, dhdp->info->cpumask_secondary); +#endif /* DHD_LB && DHD_LB_HOST_CTRL */ + break; + case DHD_AFFINITY_TPUT_150MBPS: + dhd_irq_set_affinity(dhdp, dhdp->info->cpumask_primary); + break; + case DHD_AFFINITY_TPUT_300MBPS: +#ifdef CONFIG_ARCH_EXYNOS + dhd_irq_set_affinity(dhdp, cpumask_of(PCIE_IRQ_CPU_CORE)); +#else + dhd_irq_set_affinity(dhdp, dhdp->info->cpumask_primary); +#endif /* CONFIG_ARCH_EXYNOS */ + break; + default: + DHD_ERROR(("%s, Unknown PCIe affinity cmd=0x%x\n", + __FUNCTION__, affinity_cmd)); + } +} +#endif /* SET_PCIE_IRQ_CPU_CORE */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_pktdump.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_pktdump.c old mode 100755 new mode 100644 index 028bc762a526..6a521cab9f94 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_pktdump.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_pktdump.c @@ -1,7 +1,7 @@ /* * Packet dump helper functions * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -37,7 +37,13 @@ #include #include #include +#include #include +#ifdef WL_CFGVENDOR_CUST_ADVLOG +#include +#include +#include +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ #include #include @@ -168,16 +174,27 @@ static const char pkt_cnt_msg[][20] = { }; #endif -static const char tx_pktfate[][30] = { - "TX_PKT_FATE_ACKED", /* 0: WLFC_CTL_PKTFLAG_DISCARD */ - "TX_PKT_FATE_FW_QUEUED", /* 1: WLFC_CTL_PKTFLAG_D11SUPPRESS */ - "TX_PKT_FATE_FW_QUEUED", /* 2: WLFC_CTL_PKTFLAG_WLSUPPRESS */ - "TX_PKT_FATE_FW_DROP_INVALID", /* 3: WLFC_CTL_PKTFLAG_TOSSED_BYWLC */ - "TX_PKT_FATE_SENT", /* 4: WLFC_CTL_PKTFLAG_DISCARD_NOACK */ - "TX_PKT_FATE_FW_DROP_OTHER", /* 5: WLFC_CTL_PKTFLAG_SUPPRESS_ACKED */ - "TX_PKT_FATE_FW_DROP_EXPTIME", /* 6: WLFC_CTL_PKTFLAG_EXPIRED */ - "TX_PKT_FATE_FW_DROP_OTHER", /* 7: WLFC_CTL_PKTFLAG_DROPPED */ - "TX_PKT_FATE_FW_PKT_FREE", /* 8: WLFC_CTL_PKTFLAG_MKTFREE */ +#if defined(DHD_DNS_DUMP) || defined(DHD_ARP_DUMP) || defined(DHD_ICMP_DUMP) || \ + defined(DHD_DHCP_DUMP) || defined(DHD_8021X_DUMP) || defined(DHD_PKTDUMP_ROAM) +#define DHD_PKTFATE_STR_MAX 30 +#define DHD_PKTFATE_EX_STR_MAX 10 +typedef struct dhd_tx_pktfate_entry { + const char reason[DHD_PKTFATE_STR_MAX]; + const char ex[DHD_PKTFATE_EX_STR_MAX]; +} dhd_tx_pktfate_entry_t; + +static dhd_tx_pktfate_entry_t tx_pktfate[] = { + {"TX_PKT_FATE_ACKED", "ACK"}, /* 0: WLFC_CTL_PKTFLAG_DISCARD */ + {"TX_PKT_FATE_FW_D11SUPPRESS", "TX_FAIL"}, /* 1: WLFC_CTL_PKTFLAG_D11SUPPRESS */ + {"TX_PKT_FATE_FW_WLSUPPRESS", "TX_FAIL"}, /* 2: WLFC_CTL_PKTFLAG_WLSUPPRESS */ + {"TX_PKT_FATE_FW_TOSSED_BYWLC", "TX_FAIL"}, /* 3: WLFC_CTL_PKTFLAG_TOSSED_BYWLC */ + {"TX_PKT_FATE_SENT_NOACK", "NO_ACK"}, /* 4: WLFC_CTL_PKTFLAG_DISCARD_NOACK */ + {"TX_PKT_FATE_FW_SUPPRESS_ACKED", "TX_FAIL"}, /* 5: WLFC_CTL_PKTFLAG_SUPPRESS_ACKED */ + {"TX_PKT_FATE_FW_DROP_EXPTIME", "TX_FAIL"}, /* 6: WLFC_CTL_PKTFLAG_EXPIRED */ + {"TX_PKT_FATE_FW_DROP_OTHER", "TX_FAIL"}, /* 7: WLFC_CTL_PKTFLAG_DROPPED */ + {"TX_PKT_FATE_FW_PKT_FREE", "TX_FAIL"}, /* 8: WLFC_CTL_PKTFLAG_MKTFREE */ + {"TX_PKT_FATE_FW_MAX_SUP_RETR", "TX_FAIL"}, /* 9: WLFC_CTL_PKTFLAG_MAX_SUP_RETR */ + {"TX_PKT_FATE_FW_FORCED_EXPIRED", "TX_FAIL"}, /* 10: WLFC_CTL_PKTFLAG_FORCED_EXPIRED */ }; #define DBGREPLAY " Replay Counter: %02x%02x%02x%02x%02x%02x%02x%02x" @@ -191,10 +208,17 @@ static const char tx_pktfate[][30] = { ((const eapol_key_hdr_t *)(key))->replay[7] #define TXFATE_FMT " TX_PKTHASH:0x%X TX_PKT_FATE:%s" #define TX_PKTHASH(pkthash) ((pkthash) ? (*pkthash) : (0)) -#define TX_FATE_STR(fate) (((*fate) <= (WLFC_CTL_PKTFLAG_MKTFREE)) ? \ - (tx_pktfate[(*fate)]) : "TX_PKT_FATE_FW_DROP_OTHER") +#define TX_FATE_STR(fate) (((*fate) <= (WLFC_CTL_PKTFLAG_FORCED_EXPIRED)) ? \ + (tx_pktfate[(*fate)].reason) : "TX_PKT_FATE_UNKNOWN") +#define TX_FATE_STR_EX(fate) (((*fate) <= (WLFC_CTL_PKTFLAG_FORCED_EXPIRED)) ? \ + (tx_pktfate[(*fate)].ex) : NULL) #define TX_FATE(fate) ((fate) ? (TX_FATE_STR(fate)) : "N/A") +#define TX_FATE_EX(fate) ((fate) ? (TX_FATE_STR_EX(fate)) : NULL) #define TX_FATE_ACKED(fate) ((fate) ? ((*fate) == (WLFC_CTL_PKTFLAG_DISCARD)) : (0)) +#endif /* + * DHD_DNS_DUMP || DHD_ARP_DUMP || DHD_ICMP_DUMP || + * DHD_DHCP_DUMP || DHD_8021X_DUMP || DHD_PKTDUMP_ROAM + */ #define EAP_PRINT(x, args...) \ do { \ @@ -1075,6 +1099,7 @@ typedef struct bootp_fmt { static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 }; #ifdef DHD_DHCP_DUMP +#if defined(DHD_DHCP_DUMP) || defined(WL_CFGVENDOR_CUST_ADVLOG) #define DHCP_MSGTYPE_DISCOVER 1 #define DHCP_MSGTYPE_OFFER 2 #define DHCP_MSGTYPE_REQUEST 3 @@ -1083,6 +1108,7 @@ static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 }; #define DHCP_MSGTYPE_NAK 6 #define DHCP_MSGTYPE_RELEASE 7 #define DHCP_MSGTYPE_INFORM 8 +#endif /* DHD_DHCP_DUMP || WL_CFGVENDOR_CUST_ADVLOG */ #define DHCP_PRINT(str) \ do { \ @@ -1098,15 +1124,26 @@ static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 }; } \ } while (0) -static char dhcp_ops[][10] = { +#define MAX_DHCP_OPS_STR 3 +#define MAX_DHCP_TYPES_STR 9 + +static char dhcp_ops[MAX_DHCP_OPS_STR][10] = { "NA", "REQUEST", "REPLY" }; -static char dhcp_types[][10] = { +static char dhcp_types[MAX_DHCP_TYPES_STR][10] = { "NA", "DISCOVER", "OFFER", "REQUEST", "DECLINE", "ACK", "NAK", "RELEASE", "INFORM" }; +#define DHCP_OPS_STR(ops) ((ops < MAX_DHCP_OPS_STR) ? \ + (dhcp_ops[ops]) : "UNKNOWN_DHCP_OPS") +#define DHCP_TYPES_STR(type) ((type < MAX_DHCP_TYPES_STR) ? \ + (dhcp_types[type]) : "UNKNOWN_DHCP_TYPE") + #ifdef DHD_STATUS_LOGGING -static const int dhcp_types_stat[9] = { +#define MAX_DHCP_TYPES_STAT 9 +#define DHCP_TYPES_STAT(type) ((type < MAX_DHCP_TYPES_STAT) ? \ + (dhcp_types_stat[type]) : ST(INVALID)) +static const int dhcp_types_stat[MAX_DHCP_TYPES_STAT] = { ST(INVALID), ST(DHCP_DISCOVER), ST(DHCP_OFFER), ST(DHCP_REQUEST), ST(DHCP_DECLINE), ST(DHCP_ACK), ST(DHCP_NAK), ST(DHCP_RELEASE), ST(DHCP_INFORM) @@ -1120,7 +1157,8 @@ dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx, bootp_fmt_t *b = (bootp_fmt_t *)&pktdata[ETHER_HDR_LEN]; struct ipv4_hdr *iph = &b->iph; uint8 *ptr, *opt, *end = (uint8 *) b + ntohs(b->iph.tot_len); - int dhcp_type = 0, len, opt_len; + uint8 dhcp_type = 0; + int len, opt_len; char *ifname = NULL, *typestr = NULL, *opstr = NULL; bool cond; char sabuf[20]="", dabuf[20]=""; @@ -1156,9 +1194,9 @@ dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx, if (*opt == DHCP_OPT_MSGTYPE) { if (opt[1]) { dhcp_type = opt[2]; - typestr = dhcp_types[dhcp_type]; - opstr = dhcp_ops[b->op]; - DHD_STATLOG_DATA(dhdp, dhcp_types_stat[dhcp_type], + typestr = DHCP_TYPES_STR(dhcp_type); + opstr = DHCP_OPS_STR(b->op); + DHD_STATLOG_DATA(dhdp, DHCP_TYPES_STAT(dhcp_type), ifidx, tx, cond); DHCP_PRINT("DHCP"); break; @@ -1186,6 +1224,23 @@ dhd_check_icmp(uint8 *pktdata) return TRUE; } +bool +dhd_check_icmpv6(uint8 *pktdata, uint32 plen) +{ + uint8 *pkt = (uint8 *)&pktdata[ETHER_HDR_LEN]; + struct ipv6_hdr *ip6h = (struct ipv6_hdr *)pkt; + + if (IPV6_PROT(ip6h) != IP_PROT_ICMP6) { + return FALSE; + } + + /* check header length */ + if (plen <= IPV6_MIN_HLEN) { + return FALSE; + } + return TRUE; +} + #ifdef DHD_ICMP_DUMP #define ICMP_TYPE_DEST_UNREACH 3 #define ICMP_ECHO_SEQ_OFFSET 6 @@ -1577,6 +1632,222 @@ dhd_trx_pkt_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, uint32 pktlen, bool } #endif /* DHD_RX_DUMP */ +#ifdef WL_CFGVENDOR_CUST_ADVLOG +typedef struct dhd_advlog_arr_map_entry { + uint32 avglog_type; + dhd_advlog_map_entry_t *arr; + uint32 arr_len; +} dhd_advlog_arr_map_entry_t; + +typedef enum dhd_advlog_type { + DHD_ADVLOG_DHCP_TX = 0, + DHD_ADVLOG_DHCP_RX = 1, + DHD_ADVLOG_EAP = 2, + DHD_ADVLOG_EAPOL = 3, + DHD_ADVLOG_LAST = 4 +} dhd_advlog_type_t; + +static dhd_advlog_map_entry_t eap_type_map[] = { + {EAP_TYPE_IDENT, "Identity"}, + {EAP_TYPE_TLS, "TLS"}, + {EAP_TYPE_LEAP, "LEAP"}, + {EAP_TYPE_TTLS, "TTLS"}, + {EAP_TYPE_AKA, "AKA"}, + {EAP_TYPE_PEAP, "PEAP"}, + {EAP_TYPE_FAST, "FAST"}, + {EAP_TYPE_PSK, "PSK"}, + {EAP_TYPE_AKAP, "AKAP"}, +}; + +static dhd_advlog_map_entry_t eap_advlog_map[] = { + {EAP_CODE_REQUEST, "[EAP] REQ type=%s len=%d"}, + {EAP_CODE_RESPONSE, "[EAP] RESP type=%s len=%d tx_status=%s"}, + {EAP_CODE_SUCCESS, "[EAP] SUCC"}, + {EAP_CODE_FAILURE, "[EAP] FAIL"}, +}; + +static dhd_advlog_map_entry_t dhcp_tx_advlog_map[] = { + {DHCP_MSGTYPE_DISCOVER, "[DHCP] DISCOVER tx_status=%s"}, + {DHCP_MSGTYPE_REQUEST, "[DHCP] REQUEST tx_status=%s"}, +}; + +static dhd_advlog_map_entry_t dhcp_rx_advlog_map[] = { + {DHCP_MSGTYPE_OFFER, "[DHCP] OFFER"}, + {DHCP_MSGTYPE_ACK, "[DHCP] ACK"}, + {DHCP_MSGTYPE_NAK, "[DHCP] NAK"}, +}; + +static dhd_advlog_map_entry_t eapol_advlog_map[] = { + {EAPOL_4WAY_M1, "[EAPOL] 4WAY M1"}, + {EAPOL_4WAY_M2, "[EAPOL] 4WAY M2 tx_status=%s"}, + {EAPOL_4WAY_M3, "[EAPOL] 4WAY M3"}, + {EAPOL_4WAY_M4, "[EAPOL] 4WAY M4 tx_status=%s"}, + {EAPOL_GROUPKEY_M1, "[EAPOL] GTK M1"}, + {EAPOL_GROUPKEY_M2, "[EAPOL] GTK M2 tx_status=%s"}, +}; + +static dhd_advlog_arr_map_entry_t advlog_map_arr[] = { + {DHD_ADVLOG_DHCP_TX, dhcp_tx_advlog_map, ARRAY_SIZE(dhcp_tx_advlog_map)}, + {DHD_ADVLOG_DHCP_RX, dhcp_rx_advlog_map, ARRAY_SIZE(dhcp_rx_advlog_map)}, + {DHD_ADVLOG_EAP, eap_advlog_map, ARRAY_SIZE(eap_advlog_map)}, + {DHD_ADVLOG_EAPOL, eapol_advlog_map, ARRAY_SIZE(eapol_advlog_map)}, +}; + +const char* get_advlog_val(dhd_advlog_map_entry_t *arr, uint32 arr_len, int tag) +{ + int i; + for (i = 0; i < arr_len; i++) { + if (tag == arr[i].key) { + return arr[i].val; + } + } + return NULL; +} + +static int get_dhcp_type(uint8 *pktdata) +{ + bootp_fmt_t *b = (bootp_fmt_t *)&pktdata[ETHER_HDR_LEN]; + uint8 *ptr, *opt, *end = (uint8 *) b + ntohs(b->iph.tot_len); + int dhcp_type = 0, len, opt_len; + + len = ntohs(b->udph.len) - sizeof(struct bcmudp_hdr); + opt_len = len - (sizeof(*b) - sizeof(struct ipv4_hdr) - + sizeof(struct bcmudp_hdr) - sizeof(b->options)); + + /* parse bootp options */ + if (opt_len >= BOOTP_MAGIC_COOKIE_LEN && + !memcmp(b->options, bootp_magic_cookie, BOOTP_MAGIC_COOKIE_LEN)) { + ptr = &b->options[BOOTP_MAGIC_COOKIE_LEN]; + while (ptr < end && *ptr != 0xff) { + opt = ptr++; + if (*opt == 0) { + continue; + } + ptr += *ptr + 1; + if (ptr >= end) { + break; + } + if (*opt == DHCP_OPT_MSGTYPE) { + if (opt[1]) { + dhcp_type = opt[2]; + return dhcp_type; + } + } + } + } + return BCME_ERROR; +} + +static int dhd_send_supp(uint32 avglog_type, int arg_tag, int arg_type, uint32 pktlen, + bool tx, uint16 *pktfate) +{ + const char *type_str = NULL; + const char *fmt_str = NULL; + dhd_advlog_map_entry_t *fmt_arr; + uint32 fmt_arr_len; + + if (avglog_type >= DHD_ADVLOG_LAST) { + DHD_ERROR(("%s incorrect array index type:%d tag:%d\n", + __func__, avglog_type, arg_tag)); + return BCME_ERROR; + } + if ((arg_type && !pktlen) || (!arg_type && pktlen)) { + DHD_ERROR(("%s Not expected value pair type:%d tag:%d pktlen:%u\n", + __func__, avglog_type, arg_tag, pktlen)); + return BCME_ERROR; + } + if (arg_tag <= 0) { + DHD_ERROR(("%s Invalid tag number type:%d tag:%d\n", + __func__, avglog_type, arg_tag)); + return BCME_ERROR; + } + + /* Get the format string corresponding to the type */ + fmt_arr = advlog_map_arr[avglog_type].arr; + fmt_arr_len = advlog_map_arr[avglog_type].arr_len; + fmt_str = get_advlog_val(fmt_arr, fmt_arr_len, arg_tag); + if (!fmt_str) { + DHD_ERROR(("%s map arr not found type:%d tag:%d\n", + __func__, avglog_type, arg_tag)); + return BCME_ERROR; + } + + /* EAP REQ/RESP */ + if (arg_type && pktlen) { + /* Get Identity/PEAP/FAST/etc string */ + type_str = get_advlog_val(eap_type_map, ARRAY_SIZE(eap_type_map), arg_type); + if (!type_str) { + DHD_ERROR(("%s type string not found type:%d tag:%d\n", + __func__, avglog_type, arg_tag)); + return BCME_ERROR; + } + if (tx && pktfate) { + /* EAP RESP */ + SUPP_ADVLOG((fmt_str, type_str, pktlen, TX_FATE_EX(pktfate))); + } else if (!tx) { + /* EAP REQ */ + SUPP_ADVLOG((fmt_str, type_str, pktlen)); + } + } else { + if (tx && pktfate) { + /* EAPOL M2/M4, GTK M2, DHCP DISC/REQ */ + SUPP_ADVLOG((fmt_str, TX_FATE_EX(pktfate))); + } else if (!tx) { + /* EAPOL M1/M3, GTK M1, DHCP OFFER/ACK/NAK, EAP SUCC/FAIL */ + SUPP_ADVLOG((fmt_str)); + } + } + return BCME_OK; +} + +void dhd_send_supp_dhcp(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx, uint16 *pktfate) +{ + uint32 advlog_type; + + /* Advanced Logging supports only STA mode */ + if (!DHD_IF_ROLE_STA(dhdp, ifidx)) { + return; + } + + if (tx) { + advlog_type = DHD_ADVLOG_DHCP_TX; + } else { + advlog_type = DHD_ADVLOG_DHCP_RX; + } + dhd_send_supp(advlog_type, get_dhcp_type(pktdata), 0, 0, tx, pktfate); +} + +void dhd_send_supp_eap(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, uint32 pktlen, + bool tx, uint16 *pktfate) +{ + eapol_header_t *eapol_hdr; + eap_header_fmt_t *eap_hdr; + uint16 len = 0; + uint8 type = 0; + + /* Advanced Logging supports only STA mode */ + if (!DHD_IF_ROLE_STA(dhdp, ifidx)) { + return; + } + + eapol_hdr = (eapol_header_t *)pktdata; + eap_hdr = (eap_header_fmt_t *)(eapol_hdr->body); + + if (eapol_hdr->type == EAP_PACKET) { + /* EAP SUCC/FAIL has no arg to print */ + if (eap_hdr->code != EAP_CODE_SUCCESS && + eap_hdr->code != EAP_CODE_FAILURE) { + type = eap_hdr->type; + len = ntoh16(eap_hdr->len); + } + dhd_send_supp(DHD_ADVLOG_EAP, eap_hdr->code, type, len, tx, pktfate); + } else if (eapol_hdr->type == EAPOL_KEY) { + dhd_send_supp(DHD_ADVLOG_EAPOL, dhd_is_4way_msg(pktdata), + 0, 0, tx, pktfate); + } +} +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ + #ifdef BCMPCIE static bool dhd_is_eapol_pkt(dhd_pub_t *dhd, uint8 *pktdata, uint32 pktlen) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_pktdump.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_pktdump.h old mode 100755 new mode 100644 index 96a160ae33fa..53a856f04f4c --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_pktdump.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_pktdump.h @@ -1,7 +1,7 @@ /* * Header file for the Packet dump helper functions * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -51,11 +51,31 @@ enum pkt_type { PKT_TYPE_DATA = 0, PKT_TYPE_DHCP = 1, PKT_TYPE_ICMP = 2, - PKT_TYPE_DNS = 3, - PKT_TYPE_ARP = 4, - PKT_TYPE_EAP = 5 + PKT_TYPE_ICMPV6 = 3, + PKT_TYPE_DNS = 4, + PKT_TYPE_ARP = 5, + PKT_TYPE_EAP = 6, + PKT_TYPE_IGMP = 7 }; +#ifdef WL_CFGVENDOR_CUST_ADVLOG +#define DHD_ADVLOG_FMT_MAX 256u +typedef struct dhd_advlog_map_entry { + uint32 key; + const char val[DHD_ADVLOG_FMT_MAX]; +} dhd_advlog_map_entry_t; + +extern void dhd_send_supp_dhcp(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, + bool tx, uint16 *pktfate); +extern void dhd_send_supp_eap(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, uint32 pktlen, + bool tx, uint16 *pktfate); +#else +static INLINE void dhd_send_supp_dhcp(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, + bool tx, uint16 *pktfate) {} +static INLINE void dhd_send_supp_eap(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, + uint32 pktlen, bool tx, uint16 *pktfate) {} +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ + extern msg_eapol_t dhd_is_4way_msg(uint8 *pktdata); extern void dhd_dump_pkt(dhd_pub_t *dhd, int ifidx, uint8 *pktdata, uint32 pktlen, bool tx, uint32 *pkthash, uint16 *pktfate); @@ -131,5 +151,6 @@ extern bool dhd_check_ip_prot(uint8 *pktdata, uint16 ether_type); extern bool dhd_check_arp(uint8 *pktdata, uint16 ether_type); extern bool dhd_check_dhcp(uint8 *pktdata); extern bool dhd_check_icmp(uint8 *pktdata); +extern bool dhd_check_icmpv6(uint8 *pktdata, uint32 plen); extern bool dhd_check_dns(uint8 *pktdata); #endif /* __DHD_LINUX_PKTDUMP_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c old mode 100755 new mode 100644 index ab678122d81d..72a4f66877e2 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c @@ -1,7 +1,7 @@ /* * Linux platform device for DHD WLAN adapter * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -37,20 +37,16 @@ #if defined(OEM_ANDROID) #include #endif -#if defined(CONFIG_WIFI_CONTROL_FUNC) || defined(CUSTOMER_HW4) -#include -#else #include +#if defined(CONFIG_WIFI_CONTROL_FUNC) +#include #endif /* CONFIG_WIFI_CONTROL_FUNC */ -#ifdef BCMDBUS -#include -#endif #ifdef CONFIG_DTS #include #include #endif /* CONFIG_DTS */ -#if defined(CUSTOMER_HW) +#if defined(CUSTOMER_HW) || defined(BCMDHD_PLATDEV) extern int dhd_wlan_init_plat_data(wifi_adapter_info_t *adapter); extern void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter); #endif /* CUSTOMER_HW */ @@ -59,6 +55,11 @@ extern void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter); #define WIFI_PLAT_NAME2 "bcm4329_wlan" #define WIFI_PLAT_EXT "bcmdhd_wifi_platform" +#if defined(SUPPORT_MULTIPLE_BOARD_REVISION) +#include +extern char* dhd_get_device_dt_name(void); +#endif /* SUPPORT_MULTIPLE_BOARD_REVISION */ + #ifdef DHD_WIFI_SHUTDOWN extern void wifi_plat_dev_drv_shutdown(struct platform_device *pdev); #endif @@ -88,7 +89,7 @@ static bool dts_enabled = FALSE; #pragma GCC diagnostic ignored "-Wmissing-field-initializers" #endif struct resource dhd_wlan_resources = {0}; -struct wifi_platform_data dhd_wlan_control = {0}; +extern struct wifi_platform_data dhd_wlan_control; #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) #pragma GCC diagnostic pop #endif @@ -99,14 +100,15 @@ static int dhd_wifi_platform_load(void); extern void* wl_cfg80211_get_dhdp(struct net_device *dev); -#ifdef BCMDHD_MODULAR +// modify for compatibility +#if defined(BCMDHD_MODULAR) && defined(BOARD_MODULAR_INIT) //extern int dhd_wlan_init(void); //extern int dhd_wlan_deinit(void); #ifdef WBRC extern int wbrc_init(void); extern void wbrc_exit(void); #endif /* WBRC */ -#endif /* BCMDHD_MODULAR */ +#endif /* defined(BCMDHD_MODULAR) && defined(BOARD_MODULAR_INIT) */ #ifdef ENABLE_4335BT_WAR extern int bcm_bt_lock(int cookie); @@ -118,6 +120,18 @@ static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "Wi extern bool check_bcm4335_rev(void); #endif /* BCM4335_XTAL_WAR */ +#if defined(CONFIG_X86) +#define PCIE_RC_VENDOR_ID 0x8086 +#define PCIE_RC_DEVICE_ID 0x9c1a +#elif defined(CONFIG_ARCH_TEGRA) +#define PCIE_RC_VENDOR_ID 0x14e4 +#define PCIE_RC_DEVICE_ID 0x4347 +#else /* CONFIG_ARCH_TEGRA */ +/* Dummy defn */ +#define PCIE_RC_VENDOR_ID 0xffff +#define PCIE_RC_DEVICE_ID 0xffff +#endif /* CONFIG_X86 */ + wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type, uint32 bus_num, uint32 slot_num, unsigned long status) { @@ -131,7 +145,7 @@ wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type, if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) && (adapter->bus_num == -1 || adapter->bus_num == bus_num) && (adapter->slot_num == -1 || adapter->slot_num == slot_num) -#if defined(ENABLE_INSMOD_NO_FW_LOAD) +#if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(ENABLE_INSMOD_NO_POWER_OFF) && (wifi_chk_adapter_status(adapter, status)) #endif ) { @@ -161,6 +175,10 @@ wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_n return NULL; } +#if defined(CONFIG_WIFI_CONTROL_FUNC) && defined(CONFIG_DHD_USE_STATIC_BUF) +extern void *dhd_wlan_mem_prealloc(int section, unsigned long size); +#endif /* CONFIG_WIFI_CONTROL_FUNC && CONFIG_DHD_USE_STATIC_BUF */ + void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size) { void *alloc_ptr = NULL; @@ -170,10 +188,14 @@ void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned return NULL; plat_data = adapter->wifi_plat_data; if (plat_data->mem_prealloc) { -#ifdef BCMDHD_MDRIVER +#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER) alloc_ptr = plat_data->mem_prealloc(adapter->bus_type, adapter->index, section, size); +#else +#if defined(CONFIG_WIFI_CONTROL_FUNC) && defined(CONFIG_DHD_USE_STATIC_BUF) + alloc_ptr = dhd_wlan_mem_prealloc(section, size); #else alloc_ptr = plat_data->mem_prealloc(section, size); +#endif #endif if (alloc_ptr) { DHD_INFO(("success alloc section %d\n", section)); @@ -260,11 +282,17 @@ int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long } #endif /* ENABLE_4335BT_WAR */ +#ifdef CONFIG_WIFI_CONTROL_FUNC + err = plat_data->set_power(on); +#else err = plat_data->set_power(on, adapter); +#endif } - if (msec && !err) + if (msec && !err) { OSL_SLEEP(msec); + DHD_ERROR(("%s = %d, sleep done: %lu msec\n", __FUNCTION__, on, msec)); + } if (on && !err) is_power_on = TRUE; @@ -310,7 +338,11 @@ int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf, return -EINVAL; plat_data = adapter->wifi_plat_data; if (plat_data->get_mac_addr) { +#ifdef CONFIG_WIFI_CONTROL_FUNC + return plat_data->get_mac_addr(buf); +#else return plat_data->get_mac_addr(buf, ifidx); +#endif } return -EOPNOTSUPP; } @@ -381,6 +413,14 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev) adapter->wifi_plat_data = (void *)&dhd_wlan_control; #endif +#ifdef BCMDHD_PLATDEV + adapter->pdev = pdev; + wifi_plat_dev_probe_ret = dhd_wlan_init_plat_data(adapter); + if (!wifi_plat_dev_probe_ret) + wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); + return wifi_plat_dev_probe_ret; +#endif + resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); if (resource == NULL) resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); @@ -452,6 +492,9 @@ static int wifi_plat_dev_drv_remove(struct platform_device *pdev) #ifdef CONFIG_DTS regulator_put(wifi_regulator); #endif /* CONFIG_DTS */ +#ifdef BCMDHD_PLATDEV + dhd_wlan_deinit_plat_data(adapter); +#endif return 0; } @@ -518,9 +561,10 @@ static int wifi_platdev_match(struct device *dev, const void *data) static int wifi_platdev_match(struct device *dev, void *data) #endif /* LINUX_VER >= 5.3.0 */ { - char *name = (char*)data; + char *name = NULL; const struct platform_device *pdev; GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + name = (char*)data; pdev = to_platform_device(dev); GCC_DIAGNOSTIC_POP(); @@ -544,12 +588,16 @@ static int wifi_ctrlfunc_register_drv(void) dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); #endif -#ifdef BCMDHD_MODULAR -// dhd_wlan_init(); +// modify for compaibility +#if defined(BCMDHD_MODULAR) && defined(BOARD_MODULAR_INIT) +// if ((err = dhd_wlan_init())) { +// DHD_ERROR(("%s: dhd_wlan_init() failed(%d)\n", __FUNCTION__, err)); +// return err; +// } #ifdef WBRC wbrc_init(); #endif /* WBRC */ -#endif /* BCMDHD_MODULAR */ +#endif /* defined(BCMDHD_MODULAR) && defined(BOARD_MODULAR_INIT) */ #if !defined(CONFIG_DTS) && !defined(CUSTOMER_HW) if (!dts_enabled) { @@ -569,16 +617,7 @@ static int wifi_ctrlfunc_register_drv(void) return -ENOMEM; } adapter->name = "DHD generic adapter"; - adapter->index = -1; -#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER) -#ifdef BCMSDIO adapter->index = 0; -#elif defined(BCMPCIE) - adapter->index = 1; -#elif defined(BCMDBUS) - adapter->index = 2; -#endif -#endif adapter->bus_type = -1; adapter->bus_num = -1; adapter->slot_num = -1; @@ -586,6 +625,11 @@ static int wifi_ctrlfunc_register_drv(void) is_power_on = FALSE; wifi_plat_dev_probe_ret = 0; dhd_wifi_platdata = kzalloc(sizeof(bcmdhd_wifi_platdata_t), GFP_KERNEL); + if (dhd_wifi_platdata == NULL) { + DHD_ERROR(("%s:dhd_wifi_platdata alloc failed", __FUNCTION__)); + kfree(adapter); + return -ENOMEM; + } dhd_wifi_platdata->num_adapters = 1; dhd_wifi_platdata->adapters = adapter; init_waitqueue_head(&adapter->status_event); @@ -657,6 +701,11 @@ void wifi_ctrlfunc_unregister_drv(void) if (dev2) platform_driver_unregister(&wifi_platform_dev_driver_legacy); #endif + + if (!dhd_wifi_platdata) { + goto done; + } + if (dts_enabled) { adapter = &dhd_wifi_platdata->adapters[0]; if (is_power_on) { @@ -664,24 +713,30 @@ void wifi_ctrlfunc_unregister_drv(void) } wifi_platform_bus_enumerate(adapter, FALSE); } -#ifdef BCMDHD_MODULAR +// modify for compaibility +#if defined(BCMDHD_MODULAR) && defined(BOARD_MODULAR_INIT) // dhd_wlan_deinit(); + osl_static_mem_deinit(NULL, NULL); #ifdef WBRC wbrc_exit(); #endif /* WBRC */ -#endif /* BCMDHD_MODULAR */ - +#endif /* defined(BCMDHD_MODULAR) && defined(BOARD_MODULAR_INIT) */ #endif /* !defined(CONFIG_DTS) */ #if defined(CUSTOMER_HW) dhd_wlan_deinit_plat_data(adapter); #endif - kfree(dhd_wifi_platdata->adapters); - dhd_wifi_platdata->adapters = NULL; - dhd_wifi_platdata->num_adapters = 0; - kfree(dhd_wifi_platdata); - dhd_wifi_platdata = NULL; +done: + if (dhd_wifi_platdata && dhd_wifi_platdata->adapters) { + kfree(dhd_wifi_platdata->adapters); + dhd_wifi_platdata->adapters = NULL; + dhd_wifi_platdata->num_adapters = 0; + } + if (dhd_wifi_platdata) { + kfree(dhd_wifi_platdata); + dhd_wifi_platdata = NULL; + } } #ifndef CUSTOMER_HW @@ -759,25 +814,31 @@ int dhd_wifi_platform_register_drv(void) #ifdef BCMPCIE static int dhd_wifi_platform_load_pcie(void) { - int err = 0; int i; + int err; + int retry; wifi_adapter_info_t *adapter; - BCM_REFERENCE(i); - BCM_REFERENCE(adapter); - - if (dhd_wifi_platdata == NULL) { - /* XXX For x86 Bringup PC or BRIX */ - err = dhd_bus_register(); - } else { + if (dhd_wifi_platdata) { + /* enumerate PCIe RC */ + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + adapter = &dhd_wifi_platdata->adapters[i]; + err = wifi_platform_bus_enumerate(adapter, TRUE); + if (err) { + DHD_ERROR(("failed to enumerate bus %s err=%d", + adapter->name, err)); + return err; + } + } #ifdef DHD_SUPPORT_HDM - if (dhd_download_fw_on_driverload || hdm_trigger_init) { + if (dhd_download_fw_on_driverload || hdm_trigger_init) #else - if (dhd_download_fw_on_driverload) { + if (dhd_download_fw_on_driverload) #endif /* DHD_SUPPORT_HDM */ + { /* power up all adapters */ for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - int retry = POWERUP_MAX_RETRY; + retry = POWERUP_MAX_RETRY; adapter = &dhd_wifi_platdata->adapters[i]; DHD_ERROR(("Power-up adapter '%s'\n", adapter->name)); @@ -798,17 +859,17 @@ static int dhd_wifi_platform_load_pcie(void) wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); continue; + } + + err = wifi_platform_bus_enumerate(adapter, TRUE); + if (err) { + DHD_ERROR(("failed to enumerate bus %s, " + "%d retry left\n", + adapter->name, retry)); + wifi_platform_set_power(adapter, FALSE, + WIFI_TURNOFF_DELAY); } else { - err = wifi_platform_bus_enumerate(adapter, TRUE); - if (err) { - DHD_ERROR(("failed to enumerate bus %s, " - "%d retry left\n", - adapter->name, retry)); - wifi_platform_set_power(adapter, FALSE, - WIFI_TURNOFF_DELAY); - } else { - break; - } + break; } } while (retry--); @@ -819,19 +880,18 @@ static int dhd_wifi_platform_load_pcie(void) } } } + } - err = dhd_bus_register(); - - if (err) { - DHD_ERROR(("%s: pcie_register_driver failed\n", __FUNCTION__)); - if (dhd_download_fw_on_driverload) { - /* power down all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - adapter = &dhd_wifi_platdata->adapters[i]; - wifi_platform_bus_enumerate(adapter, FALSE); - wifi_platform_set_power(adapter, - FALSE, WIFI_TURNOFF_DELAY); - } + err = dhd_bus_register(); + if (err) { + DHD_ERROR(("%s: dhd_bus_register failed err=%d\n", __FUNCTION__, err)); + if (dhd_wifi_platdata && dhd_download_fw_on_driverload) { + /* power down all adapters */ + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + adapter = &dhd_wifi_platdata->adapters[i]; + wifi_platform_bus_enumerate(adapter, FALSE); + wifi_platform_set_power(adapter, + FALSE, WIFI_TURNOFF_DELAY); } } } @@ -896,7 +956,9 @@ static int dhd_wifi_platform_load_sdio(void) for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { bool chip_up = FALSE; int retry = POWERUP_MAX_RETRY; +#ifndef DHD_INSMOD_NOWAIT struct semaphore dhd_chipup_sem; +#endif adapter = &dhd_wifi_platdata->adapters[i]; @@ -907,6 +969,18 @@ static int dhd_wifi_platform_load_sdio(void) adapter->bus_type, adapter->bus_num, adapter->slot_num)); do { +#ifdef DHD_INSMOD_NOWAIT + err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY); + if (err) { + DHD_ERROR(("%s: wifi pwr on error ! \n", __FUNCTION__)); + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + continue; + } else { + wifi_platform_bus_enumerate(adapter, TRUE); + chip_up = TRUE; + break; + } +#else sema_init(&dhd_chipup_sem, 0); err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem); if (err) { @@ -935,6 +1009,7 @@ static int dhd_wifi_platform_load_sdio(void) dhd_bus_unreg_sdio_notify(); wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); wifi_platform_bus_enumerate(adapter, FALSE); +#endif } while (retry--); if (!chip_up) { @@ -951,6 +1026,7 @@ static int dhd_wifi_platform_load_sdio(void) goto fail; } +#ifndef DHD_INSMOD_NOWAIT /* * Wait till MMC sdio_register_driver callback called and made driver attach. * It's needed to make sync up exit from dhd insmod and @@ -962,6 +1038,7 @@ static int dhd_wifi_platform_load_sdio(void) dhd_bus_unregister(); goto fail; } +#endif return err; @@ -994,16 +1071,15 @@ static int dhd_wifi_platform_load_usb(void) wifi_adapter_info_t *adapter; s32 timeout = -1; int i; - enum wifi_adapter_status wait_status; #endif -#if !defined(DHD_PRELOAD) +#if !defined(DHD_PRELOAD) && !defined(ENABLE_INSMOD_NO_POWER_OFF) /* power down all adapters */ for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { adapter = &dhd_wifi_platdata->adapters[i]; wifi_platform_set_power(adapter, FALSE, 0); if (err) { - DHD_ERROR(("failed to wifi_platform_set_power on %s\n", adapter->name)); + DHD_ERROR(("failed to wifi_platform_set_power off %s\n", adapter->name)); goto exit; } } @@ -1030,12 +1106,8 @@ static int dhd_wifi_platform_load_usb(void) DHD_ERROR(("failed to wifi_platform_set_power on %s\n", adapter->name)); goto fail; } - if (dhd_download_fw_on_driverload) - wait_status = WIFI_STATUS_ATTACH; - else - wait_status = WIFI_STATUS_DETTACH; timeout = wait_event_interruptible_timeout(adapter->status_event, - wifi_get_adapter_status(adapter, wait_status), + wifi_get_adapter_status(adapter, WIFI_STATUS_NET_ATTACHED), msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)); if (timeout <= 0) { err = -1; @@ -1095,3 +1167,127 @@ end: return err; } + +#if defined(SUPPORT_MULTIPLE_BOARD_REVISION) +void +concate_custom_board_revision(char *nv_path) +{ + uint32 board_revision = 0; + struct device_node *root_node = NULL; + char* wlan_node = NULL; + + if (!nv_path) { + DHD_ERROR(("nv_path is null\n")); + return; + } + + wlan_node = dhd_get_device_dt_name(); + if (!wlan_node) { + DHD_ERROR(("Failed to dt name\n")); + return; + } + + root_node = of_find_compatible_node(NULL, NULL, wlan_node); + if (!root_node) { + DHD_ERROR(("Failed to get device node\n")); + return; + } + + if (of_property_read_u32(root_node, "nvram-ES", &board_revision)) { + DHD_ERROR(("No board revision property in dtsi\n")); + return; + } + + DHD_INFO(("Board revision:%d\n", board_revision)); + + if (board_revision == 1) { + strcat(nv_path, "_ES10"); + DHD_INFO(("Mached Board revision ES10: nvram name:%s\n", nv_path)); + } + +} +#endif /* SUPPORT_MULTIPLE_BOARD_REVISION */ + +/* Weak functions that can be overridden in Platform specific implementation */ +char* __attribute__ ((weak)) dhd_get_device_dt_name(void) +{ + return NULL; +} + +uint32 __attribute__ ((weak)) dhd_plat_get_info_size(void) +{ + return 0; +} + +int __attribute__ ((weak)) dhd_plat_pcie_register_event(void *plat_info, + struct pci_dev *pdev, dhd_pcie_event_cb_t pfn) +{ + return 0; +} + +void __attribute__ ((weak)) dhd_plat_pcie_deregister_event(void *plat_info) +{ + return; +} + +void __attribute__ ((weak)) dhd_plat_l1ss_ctrl(bool ctrl) +{ + return; +} + +void __attribute__ ((weak)) dhd_plat_l1_exit_io(void) +{ + return; +} + +void __attribute__ ((weak)) dhd_plat_l1_exit(void) +{ + return; +} + +void __attribute__ ((weak)) dhd_plat_report_bh_sched(void *plat_info, int resched) +{ + return; +} + +int __attribute__ ((weak)) dhd_plat_pcie_suspend(void *plat_info) +{ + return 0; +} + +int __attribute__ ((weak)) dhd_plat_pcie_resume(void *plat_info) +{ + return 0; +} + +void __attribute__ ((weak)) dhd_plat_pcie_register_dump(void *plat_info) +{ + return; +} + +void __attribute__ ((weak)) dhd_plat_pin_dbg_show(void *plat_info) +{ + return; +} + +uint32 __attribute__ ((weak)) dhd_plat_get_rc_vendor_id(void) +{ + return PCIE_RC_VENDOR_ID; +} + +uint32 __attribute__ ((weak)) dhd_plat_get_rc_device_id(void) +{ + return PCIE_RC_DEVICE_ID; +} + +uint16 __attribute__ ((weak)) dhd_plat_align_rxbuf_size(uint16 rxbufpost_sz) +{ + return rxbufpost_sz; +} + +int +__attribute__ ((weak)) dhd_get_platform_naming_for_nvram_clmblob_file(download_type_t component, + char *file_name) +{ + return BCME_ERROR; +} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_priv.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_priv.h old mode 100755 new mode 100644 index 88a3abb7b696..029217a885f4 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_priv.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_priv.h @@ -1,7 +1,7 @@ /* * DHD Linux header file - contains private structure definition of the Linux specific layer * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -41,7 +41,6 @@ #ifdef CONFIG_HAS_WAKELOCK #include #endif /* CONFIG_HAS_WAKELOCK */ -#include #include #include #include @@ -54,9 +53,15 @@ #include #endif /* PCIE_FULL_DONGLE */ -#ifdef DHD_QOS_ON_SOCK_FLOW -struct dhd_sock_qos_info; -#endif /* DHD_QOS_ON_SOCK_FLOW */ +#ifdef RX_PKT_POOL +#define RX_PKTPOOL_RESCHED_DELAY_MS 500u +#define RX_PKTPOOL_FETCH_MAX_ATTEMPTS 10u +typedef struct pkt_pool { + struct sk_buff_head skb_q ____cacheline_aligned; + uint32 max_size; + uint16 rxbuf_sz; +} pkt_pool_t; +#endif /* RX_PKT_POOL */ /* * Do not include this header except for the dhd_linux.c dhd_linux_sysfs.c @@ -74,8 +79,9 @@ typedef struct dhd_info { wifi_adapter_info_t *adapter; /* adapter information, interrupt, fw path etc. */ char fw_path[PATH_MAX]; /* path to firmware image */ char nv_path[PATH_MAX]; /* path to nvram vars file */ - char clm_path[PATH_MAX]; /* path to clm vars file */ + char clm_path[PATH_MAX]; /* path to CLM data */ char conf_path[PATH_MAX]; /* path to config vars file */ + char sig_path[PATH_MAX]; /* path to rtecdc.sig file */ #ifdef DHD_UCODE_DOWNLOAD char uc_path[PATH_MAX]; /* path to ucode image */ #endif /* DHD_UCODE_DOWNLOAD */ @@ -96,18 +102,10 @@ typedef struct dhd_info { wait_queue_head_t d3ack_wait; wait_queue_head_t dhd_bus_busy_state_wait; wait_queue_head_t dmaxfer_wait; -#ifdef BT_OVER_PCIE - wait_queue_head_t quiesce_wait; -#endif /* BT_OVER_PCIE */ uint32 default_wd_interval; timer_list_compat_t timer; bool wd_timer_valid; -#ifdef DHD_PCIE_RUNTIMEPM - timer_list_compat_t rpm_timer; - bool rpm_timer_valid; - tsk_ctl_t thr_rpm_ctl; -#endif /* DHD_PCIE_RUNTIMEPM */ struct tasklet_struct tasklet; spinlock_t sdlock; spinlock_t txqlock; @@ -129,32 +127,35 @@ typedef struct dhd_info { /* Wakelocks */ #if defined(CONFIG_HAS_WAKELOCK) - struct wakeup_source wl_wifi; /* Wifi wakelock */ - struct wakeup_source wl_rxwake; /* Wifi rx wakelock */ - struct wakeup_source wl_ctrlwake; /* Wifi ctrl wakelock */ - struct wakeup_source wl_wdwake; /* Wifi wd wakelock */ - struct wakeup_source wl_evtwake; /* Wifi event wakelock */ - struct wakeup_source wl_pmwake; /* Wifi pm handler wakelock */ - struct wakeup_source wl_txflwake; /* Wifi tx flow wakelock */ + struct wakeup_source *wl_wifi; /* Wifi wakelock */ + struct wakeup_source *wl_rxwake; /* Wifi rx wakelock */ + struct wakeup_source *wl_ctrlwake; /* Wifi ctrl wakelock */ + struct wakeup_source *wl_wdwake; /* Wifi wd wakelock */ + struct wakeup_source *wl_evtwake; /* Wifi event wakelock */ + struct wakeup_source *wl_pmwake; /* Wifi pm handler wakelock */ + struct wakeup_source *wl_txflwake; /* Wifi tx flow wakelock */ #ifdef BCMPCIE_OOB_HOST_WAKE - struct wakeup_source wl_intrwake; /* Host wakeup wakelock */ + struct wakeup_source *wl_intrwake; /* Host wakeup wakelock */ #endif /* BCMPCIE_OOB_HOST_WAKE */ #ifdef DHD_USE_SCAN_WAKELOCK - struct wakeup_source wl_scanwake; /* Wifi scan wakelock */ + struct wakeup_source *wl_scanwake; /* Wifi scan wakelock */ #endif /* DHD_USE_SCAN_WAKELOCK */ - struct wakeup_source wl_nanwake; /* NAN wakelock */ + struct wakeup_source *wl_nanwake; /* NAN wakelock */ #endif /* CONFIG_HAS_WAKELOCK */ - struct wake_lock rx_wakelock; #if defined(OEM_ANDROID) /* net_device interface lock, prevent race conditions among net_dev interface * calls and wifi_on or wifi_off */ struct mutex dhd_net_if_mutex; struct mutex dhd_suspend_mutex; -#if defined(PKT_FILTER_SUPPORT) && defined(APF) +#if defined(APF) struct mutex dhd_apf_mutex; -#endif /* PKT_FILTER_SUPPORT && APF */ +#endif /* APF */ +#else +#if defined(APF) + struct mutex dhd_apf_mutex; +#endif /* APF */ #endif /* OEM_ANDROID */ spinlock_t wakelock_spinlock; spinlock_t wakelock_evt_spinlock; @@ -254,6 +255,11 @@ typedef struct dhd_info { struct work_struct tx_dispatcher_work; struct work_struct rx_compl_dispatcher_work; + /* Emergency queue to hold pkts when flow control is enabled and + * same pkts will be posted back to the dongle till flow control is disabled. + */ + struct sk_buff_head rx_emerge_queue ____cacheline_aligned; + /* Number of times DPC Tasklet ran */ uint32 dhd_dpc_cnt; /* Number of times NAPI processing got scheduled */ @@ -352,7 +358,12 @@ typedef struct dhd_info { uint32 *rxc_hist[HIST_BIN_SIZE]; struct kobject dhd_lb_kobj; bool dhd_lb_candidacy_override; + enum cpuhp_state dhd_cpuhp_state; #endif /* DHD_LB */ + + /* DPC bounds sysfs */ + struct kobject dhd_dpc_bounds_kobj; + #if defined(DNGL_AXI_ERROR_LOGGING) && defined(DHD_USE_WQ_FOR_DNGL_AXI_ERROR) struct work_struct axi_error_dispatcher_work; #endif /* DNGL_AXI_ERROR_LOGGING && DHD_USE_WQ_FOR_DNGL_AXI_ERROR */ @@ -364,24 +375,20 @@ typedef struct dhd_info { #endif /* DHD_USE_KTHREAD_FOR_LOGTRACE */ #endif /* SHOW_LOGTRACE */ -#ifdef BTLOG - struct work_struct bt_log_dispatcher_work; -#endif /* SHOW_LOGTRACE */ #ifdef EWP_EDL struct delayed_work edl_dispatcher_work; #endif #if defined(WLAN_ACCEL_BOOT) - int fs_check_retry; - struct delayed_work wl_accel_work; bool wl_accel_force_reg_on; - bool wl_accel_boot_on_done; #endif #if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) #if defined(BCMDBUS) struct task_struct *fw_download_task; struct semaphore fw_download_lock; + bool fw_download_thread_exit; #endif /* BCMDBUS */ #endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */ + uint32 flag_kobj; /* Add for duplicate kobj processing */ struct kobject dhd_kobj; timer_list_compat_t timesync_timer; #if defined(BT_OVER_SDIO) @@ -397,7 +404,7 @@ typedef struct dhd_info { uint host_radiotap_conv; #endif /* HOST_RADIOTAP_CONV */ #endif /* WL_MONITOR */ -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) struct mutex bus_user_lock; /* lock for sdio bus apis shared between WLAN & BT */ int bus_user_count; /* User counts of sdio bus shared between WLAN & BT */ #endif /* BT_OVER_SDIO */ @@ -408,27 +415,13 @@ typedef struct dhd_info { struct workqueue_struct *tx_wq; struct workqueue_struct *rx_wq; #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ -#ifdef BTLOG - struct sk_buff_head bt_log_queue ____cacheline_aligned; -#endif /* BTLOG */ #ifdef PCIE_INB_DW wait_queue_head_t ds_exit_wait; #endif /* PCIE_INB_DW */ #ifdef DHD_DEBUG_UART bool duart_execute; #endif /* DHD_DEBUG_UART */ -#ifdef BT_OVER_PCIE - struct mutex quiesce_flr_lock; - struct mutex quiesce_lock; - enum dhd_bus_quiesce_state dhd_quiesce_state; -#endif /* BT_OVER_PCIE */ struct mutex logdump_lock; -#if defined(GDB_PROXY) && defined(PCIE_FULL_DONGLE) && defined(BCMINTERNAL) - /* Root directory for GDB Proxy's (proc)fs files, used by first (default) interface */ - struct proc_dir_entry *gdb_proxy_fs_root; - /* Name of procfs root directory */ - char gdb_proxy_fs_root_name[100]; -#endif /* defined(GDB_PROXY) && defined(PCIE_FULL_DONGLE) && defined(BCMINTERNAL) */ #if defined(DHD_MQ) && defined(DHD_MQ_STATS) uint64 pktcnt_qac_histo[MQ_MAX_QUEUES][AC_COUNT]; uint64 pktcnt_per_ac[AC_COUNT]; @@ -436,19 +429,35 @@ typedef struct dhd_info { #endif /* DHD_MQ && DHD_MQ_STATS */ /* indicates mem_dump was scheduled as work queue or called directly */ bool scheduled_memdump; -#ifdef DHD_PKTTS - bool latency; /* pktts enab flag */ - pktts_flow_t config[PKTTS_CONFIG_MAX]; /* pktts user config */ -#endif /* DHD_PKTTS */ struct work_struct dhd_hang_process_work; -#ifdef DHD_HP2P - spinlock_t hp2p_lock; -#endif /* DHD_HP2P */ -#ifdef DHD_QOS_ON_SOCK_FLOW - struct dhd_sock_qos_info *psk_qos; +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT + struct work_struct dhd_alert_process_work; +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ +#ifdef RX_PKT_POOL + pkt_pool_t rx_pkt_pool; + tsk_ctl_t rx_pktpool_thread; #endif +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) + osl_atomic_t dump_status; + struct work_struct dhd_dump_proc_work; +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ } dhd_info_t; +/** priv_link is the link between netdev and the dhdif and dhd_info structs. */ +typedef struct dhd_dev_priv { + dhd_info_t * dhd; /* cached pointer to dhd_info in netdevice priv */ + dhd_if_t * ifp; /* cached pointer to dhd_if in netdevice priv */ + int ifidx; /* interface index */ + void * lkup; +} dhd_dev_priv_t; + +#define DHD_DEV_PRIV_SIZE (sizeof(dhd_dev_priv_t)) +#define DHD_DEV_PRIV(dev) ((dhd_dev_priv_t *)DEV_PRIV(dev)) +#define DHD_DEV_INFO(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->dhd) +#define DHD_DEV_IFP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifp) +#define DHD_DEV_IFIDX(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifidx) +#define DHD_DEV_LKUP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->lkup) + #ifdef WL_MONITOR #define MONPKT_EXTRA_LEN 48u #endif /* WL_MONITOR */ @@ -495,21 +504,42 @@ int dhd_register_cpuhp_callback(dhd_info_t *dhd); int dhd_unregister_cpuhp_callback(dhd_info_t *dhd); #endif /* DHD_LB */ -#if defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON) +#ifdef RX_PKT_POOL +void dhd_rx_pktpool_init(dhd_info_t *dhd); +void dhd_rx_pktpool_deinit(dhd_info_t *dhd); +#endif /* RX_PKT_POOL */ + +#if defined(SET_PCIE_IRQ_CPU_CORE) || defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON) void dhd_irq_set_affinity(dhd_pub_t *dhdp, const struct cpumask *cpumask); -#endif /* DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */ +#endif /* SET_PCIE_IRQ_CPU_CORE || DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */ + +void dhd_flush_logtrace_process(dhd_info_t *dhd); + #ifdef DHD_SSSR_DUMP extern uint sssr_enab; extern uint fis_enab; #endif /* DHD_SSSR_DUMP */ +#if defined(ANDROID_VERSION) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) +#define WAKELOCK_BACKPORT +#endif + #ifdef CONFIG_HAS_WAKELOCK -enum { - WAKE_LOCK_SUSPEND, /* Prevent suspend */ - WAKE_LOCK_TYPE_COUNT -}; -#define dhd_wake_lock_init(wakeup_source, type, name) wakeup_source_add(wakeup_source) -#define dhd_wake_lock_destroy(wakeup_source) wakeup_source_remove(wakeup_source) +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) || defined(WAKELOCK_BACKPORT)) +#define dhd_wake_lock_init(wakeup_source, dev, name) \ +do { \ + wakeup_source = wakeup_source_register(dev, name); \ +} while (0); +#else +#define dhd_wake_lock_init(wakeup_source, dev, name) \ +do { \ + wakeup_source = wakeup_source_register(name); \ +} while (0); +#endif /* LINUX_VERSION >= 5.4.0 */ +#define dhd_wake_lock_destroy(wakeup_source) \ +do { \ + wakeup_source_unregister(wakeup_source); \ +} while (0); #define dhd_wake_lock(wakeup_source) __pm_stay_awake(wakeup_source) #define dhd_wake_unlock(wakeup_source) __pm_relax(wakeup_source) #define dhd_wake_lock_active(wakeup_source) ((wakeup_source)->active) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_rx.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_rx.c new file mode 100644 index 000000000000..7b5fda9e8d4c --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_rx.c @@ -0,0 +1,1691 @@ +/* + * Broadcom Dongle Host Driver (DHD), + * Linux-specific network interface for receive(rx) path + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + * + * $Id$ + */ + +#include +#include +#include +#ifdef SHOW_LOGTRACE +#include +#include +#endif /* SHOW_LOGTRACE */ + +#ifdef PCIE_FULL_DONGLE +#include +#endif /* PCIE_FULL_DONGLE */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_TIZEN) +#include +#endif /* CONFIG_TIZEN */ +#include +#include +#ifdef ENABLE_ADAPTIVE_SCHED +#include +#endif /* ENABLE_ADAPTIVE_SCHED */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include /* need to still support chips no longer in trunk firmware */ +#include +#include + +#include +#include +#include +#include <802.3.h> + +#include +#include +#include +#include +#ifdef DHD_WET +#include +#endif /* DHD_WET */ +#ifdef PCIE_FULL_DONGLE +#include +#endif +#include +#include +#include +#include +#include +#if defined(WL_CFG80211) +#include +#ifdef WL_BAM +#include +#endif /* WL_BAM */ +#endif /* WL_CFG80211 */ +#ifdef PNO_SUPPORT +#include +#endif +#ifdef RTT_SUPPORT +#include +#endif + +#include + +#ifdef CONFIG_COMPAT +#include +#endif + +#ifdef DHD_WMF +#include +#endif /* DHD_WMF */ + +#ifdef DHD_L2_FILTER +#include +#include +#include +#endif /* DHD_L2_FILTER */ + +#ifdef DHD_PSTA +#include +#endif /* DHD_PSTA */ + +#ifdef AMPDU_VO_ENABLE +/* XXX: Enabling VO AMPDU to reduce FER */ +#include <802.1d.h> +#endif /* AMPDU_VO_ENABLE */ + +#if defined(DHDTCPACK_SUPPRESS) || defined(DHDTCPSYNC_FLOOD_BLK) +#include +#endif /* DHDTCPACK_SUPPRESS || DHDTCPSYNC_FLOOD_BLK */ +#include +#ifdef DHD_PKT_LOGGING +#include +#endif /* DHD_PKT_LOGGING */ +#ifdef DHD_4WAYM4_FAIL_DISCONNECT +#include +#endif /* DHD_4WAYM4_FAIL_DISCONNECT */ + +#ifdef ENABLE_DHD_GRO +#include +#endif /* ENABLE_DHD_GRO */ + +#ifdef FIX_CPU_MIN_CLOCK +#include +#endif /* FIX_CPU_MIN_CLOCK */ + +#ifdef PROP_TXSTATUS +#include +#include +#endif + +#if defined(OEM_ANDROID) +#include +#endif +#include + +/* RX frame thread priority */ +int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING; +module_param(dhd_rxf_prio, int, 0); + +/* Request scheduling of the bus rx frame */ +static void dhd_os_rxflock(dhd_pub_t *pub); +static void dhd_os_rxfunlock(dhd_pub_t *pub); + +static int dhd_wl_host_event(dhd_info_t *dhd, int ifidx, void *pktdata, uint16 pktlen, + wl_event_msg_t *event_ptr, void **data_ptr); + +static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb) +{ + uint32 store_idx; + uint32 sent_idx; + + if (!skb) { + DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n")); + return BCME_ERROR; + } + + dhd_os_rxflock(dhdp); + store_idx = dhdp->store_idx; + sent_idx = dhdp->sent_idx; + if (dhdp->skbbuf[store_idx] != NULL) { + /* Make sure the previous packets are processed */ + dhd_os_rxfunlock(dhdp); +#ifdef RXF_DEQUEUE_ON_BUSY + DHD_TRACE(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", + skb, store_idx, sent_idx)); + return BCME_BUSY; +#else /* RXF_DEQUEUE_ON_BUSY */ + DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", + skb, store_idx, sent_idx)); + /* removed msleep here, should use wait_event_timeout if we + * want to give rx frame thread a chance to run + */ +#if defined(WAIT_DEQUEUE) + OSL_SLEEP(1); +#endif + return BCME_ERROR; +#endif /* RXF_DEQUEUE_ON_BUSY */ + } + DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n", + skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1))); + dhdp->skbbuf[store_idx] = skb; + dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1); + dhd_os_rxfunlock(dhdp); + + return BCME_OK; +} + +static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp) +{ + uint32 store_idx; + uint32 sent_idx; + void *skb; + + dhd_os_rxflock(dhdp); + + store_idx = dhdp->store_idx; + sent_idx = dhdp->sent_idx; + skb = dhdp->skbbuf[sent_idx]; + + if (skb == NULL) { + dhd_os_rxfunlock(dhdp); + DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n", + store_idx, sent_idx)); + return NULL; + } + + dhdp->skbbuf[sent_idx] = NULL; + dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1); + + DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n", + skb, sent_idx)); + + dhd_os_rxfunlock(dhdp); + + return skb; +} + +#ifdef DHD_PCIE_NATIVE_RUNTIMEPM +void dhd_rx_wq_wakeup(struct work_struct *ptr) +{ + struct dhd_rx_tx_work *work; + struct dhd_pub * pub; + + work = container_of(ptr, struct dhd_rx_tx_work, work); + + pub = work->pub; + + DHD_RPM(("%s: ENTER. \n", __FUNCTION__)); + + if (atomic_read(&pub->block_bus) || pub->busstate == DHD_BUS_DOWN) { + return; + } + + DHD_OS_WAKE_LOCK(pub); + if (pm_runtime_get_sync(dhd_bus_to_dev(pub->bus)) >= 0) { + + // do nothing but wakeup the bus. + pm_runtime_mark_last_busy(dhd_bus_to_dev(pub->bus)); + pm_runtime_put_autosuspend(dhd_bus_to_dev(pub->bus)); + } + DHD_OS_WAKE_UNLOCK(pub); + kfree(work); +} +#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ + +#ifdef DHD_WMF +bool +dhd_is_rxthread_enabled(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd = dhdp->info; + + return dhd->rxthread_enabled; +} +#endif /* DHD_WMF */ + +/** Called when a frame is received by the dongle on interface 'ifidx' */ +void +dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + struct sk_buff *skb; + uchar *eth; + uint len; + void *data, *pnext = NULL; + int i; + dhd_if_t *ifp; + wl_event_msg_t event; +#if defined(OEM_ANDROID) + int tout_rx = 0; + int tout_ctrl = 0; +#endif /* OEM_ANDROID */ + void *skbhead = NULL; + void *skbprev = NULL; + uint16 protocol; + unsigned char *dump_data; +#ifdef DHD_MCAST_REGEN + uint8 interface_role; + if_flow_lkup_t *if_flow_lkup; + unsigned long flags; +#endif +#ifdef DHD_WAKE_STATUS + wake_counts_t *wcp = NULL; +#endif /* DHD_WAKE_STATUS */ + int pkt_wake = 0; +#ifdef ENABLE_DHD_GRO + bool dhd_gro_enable = TRUE; + struct Qdisc *qdisc = NULL; +#endif /* ENABLE_DHD_GRO */ + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + BCM_REFERENCE(dump_data); + BCM_REFERENCE(pkt_wake); + +#ifdef DHD_TPUT_PATCH + if (dhdp->conf->pktsetsum) + PKTSETSUMGOOD(pktbuf, TRUE); +#endif + +#ifdef ENABLE_DHD_GRO + if (ifidx < DHD_MAX_IFS) { + ifp = dhd->iflist[ifidx]; + if (ifp && ifp->net->qdisc) { + if (ifp->net->qdisc->ops->cl_ops) { + dhd_gro_enable = FALSE; + DHD_TRACE(("%s: disable sw gro becasue of" + " qdisc tx traffic control\n", __FUNCTION__)); + } + + if (dev_ingress_queue(ifp->net)) { + qdisc = dev_ingress_queue(ifp->net)->qdisc_sleeping; + if (qdisc != NULL && (qdisc->flags & TCQ_F_INGRESS)) { +#ifdef CONFIG_NET_CLS_ACT +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) + if (ifp->net->miniq_ingress != NULL) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) + if (ifp->net->ingress_cl_list != NULL) +#endif /* LINUX_VERSION >= 4.2.0 */ + { + dhd_gro_enable = FALSE; + DHD_TRACE(("%s: disable sw gro because of" + " qdisc rx traffic control\n", __FUNCTION__)); + } +#endif /* CONFIG_NET_CLS_ACT */ + } + } + } + } +#ifdef DHD_GRO_ENABLE_HOST_CTRL + if (!dhdp->permitted_gro && dhd_gro_enable) { + dhd_gro_enable = FALSE; + } +#endif /* DHD_GRO_ENABLE_HOST_CTRL */ +#endif /* ENABLE_DHD_GRO */ + + for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { + struct ether_header *eh; + + pnext = PKTNEXT(dhdp->osh, pktbuf); + PKTSETNEXT(dhdp->osh, pktbuf, NULL); + + /* info ring "debug" data, which is not a 802.3 frame, is sent/hacked with a + * special ifidx of DHD_DUMMY_INFO_IF. This is just internal to dhd to get the data + * from dhd_msgbuf.c:dhd_prot_infobuf_cmplt_process() to here (dhd_rx_frame). + */ + if (ifidx == DHD_DUMMY_INFO_IF) { + /* Event msg printing is called from dhd_rx_frame which is in Tasklet + * context in case of PCIe FD, in case of other bus this will be from + * DPC context. If we get bunch of events from Dongle then printing all + * of them from Tasklet/DPC context that too in data path is costly. + * Also in the new Dongle SW(4359, 4355 onwards) console prints too come as + * events with type WLC_E_TRACE. + * We'll print this console logs from the WorkQueue context by enqueing SKB + * here and Dequeuing will be done in WorkQueue and will be freed only if + * logtrace_pkt_sendup is TRUE + */ +#ifdef SHOW_LOGTRACE + dhd_event_logtrace_enqueue(dhdp, ifidx, pktbuf); +#else /* !SHOW_LOGTRACE */ + /* If SHOW_LOGTRACE not defined and ifidx is DHD_DUMMY_INFO_IF, + * free the PKT here itself + */ + PKTFREE_CTRLBUF(dhdp->osh, pktbuf, FALSE); +#endif /* SHOW_LOGTRACE */ + continue; + } + + eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); + + /* Check if dhd_stop is in progress */ + if (dhdp->stop_in_progress) { + DHD_ERROR_RLMT(("%s: dhd_stop in progress ignore received packet\n", + __FUNCTION__)); + RX_PKTFREE(dhdp->osh, eh->ether_type, pktbuf, FALSE); + continue; + } + +#ifdef DHD_WAKE_STATUS + /* Get pkt_wake and clear it */ +#if defined(BCMPCIE) + pkt_wake = dhd_bus_set_get_bus_wake_pkt_dump(dhdp, 0); +#elif defined(BCMSDIO) + pkt_wake = dhd_bus_set_get_bus_wake(dhdp, 0); +#endif /* BCMPCIE */ +#ifdef BCMDBUS + wcp = NULL; +#else + wcp = dhd_bus_get_wakecount(dhdp); +#endif /* BCMDBUS */ + if (wcp == NULL) { + /* If wakeinfo count buffer is null do not update wake count values */ + pkt_wake = 0; + } +#endif /* DHD_WAKE_STATUS */ + + if (dhd->pub.tput_data.tput_test_running && + dhd->pub.tput_data.direction == TPUT_DIR_RX && + ntoh16(eh->ether_type) == ETHER_TYPE_IP) { + dhd_tput_test_rx(dhdp, pktbuf); + PKTFREE(dhd->pub.osh, pktbuf, FALSE); + continue; + } + + if (ifidx >= DHD_MAX_IFS) { + DHD_ERROR(("%s: ifidx(%d) Out of bound. drop packet\n", + __FUNCTION__, ifidx)); + RX_PKTFREE(dhdp->osh, eh->ether_type, pktbuf, FALSE); + continue; + } + + ifp = dhd->iflist[ifidx]; + if (ifp == NULL) { + DHD_ERROR_RLMT(("%s: ifp is NULL. drop packet\n", + __FUNCTION__)); + RX_PKTFREE(dhdp->osh, eh->ether_type, pktbuf, FALSE); + continue; + } + + /* Dropping only data packets before registering net device to avoid kernel panic */ +#ifndef PROP_TXSTATUS_VSDB + if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) && + (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) +#else + if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) && + (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) +#endif /* PROP_TXSTATUS_VSDB */ + { + DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n", + __FUNCTION__)); + PKTCFREE(dhdp->osh, pktbuf, FALSE); + continue; + } + +#ifdef PROP_TXSTATUS + if (dhd_wlfc_is_header_only_pkt(dhdp, pktbuf)) { + /* WLFC may send header only packet when + there is an urgent message but no packet to + piggy-back on + */ + PKTCFREE(dhdp->osh, pktbuf, FALSE); + continue; + } +#endif +#ifdef DHD_L2_FILTER + /* If block_ping is enabled drop the ping packet */ + if (ifp->block_ping) { + if (bcm_l2_filter_block_ping(dhdp->osh, pktbuf) == BCME_OK) { + PKTCFREE(dhdp->osh, pktbuf, FALSE); + continue; + } + } + if (ifp->grat_arp && DHD_IF_ROLE_STA(dhdp, ifidx)) { + if (bcm_l2_filter_gratuitous_arp(dhdp->osh, pktbuf) == BCME_OK) { + PKTCFREE(dhdp->osh, pktbuf, FALSE); + continue; + } + } + if (ifp->parp_enable && DHD_IF_ROLE_AP(dhdp, ifidx)) { + int ret = dhd_l2_filter_pkt_handle(dhdp, ifidx, pktbuf, FALSE); + + /* Drop the packets if l2 filter has processed it already + * otherwise continue with the normal path + */ + if (ret == BCME_OK) { + PKTCFREE(dhdp->osh, pktbuf, TRUE); + continue; + } + } + if (ifp->block_tdls) { + if (bcm_l2_filter_block_tdls(dhdp->osh, pktbuf) == BCME_OK) { + PKTCFREE(dhdp->osh, pktbuf, FALSE); + continue; + } + } +#endif /* DHD_L2_FILTER */ + +#ifdef DHD_MCAST_REGEN + DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); + if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; + ASSERT(if_flow_lkup); + + interface_role = if_flow_lkup[ifidx].role; + DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); + + if (ifp->mcast_regen_bss_enable && (interface_role != WLC_E_IF_ROLE_WDS) && + !DHD_IF_ROLE_AP(dhdp, ifidx) && + ETHER_ISUCAST(eh->ether_dhost)) { + if (dhd_mcast_reverse_translation(eh) == BCME_OK) { +#ifdef DHD_PSTA + /* Change bsscfg to primary bsscfg for unicast-multicast packets */ + if ((dhd_get_psta_mode(dhdp) == DHD_MODE_PSTA) || + (dhd_get_psta_mode(dhdp) == DHD_MODE_PSR)) { + if (ifidx != 0) { + /* Let the primary in PSTA interface handle this + * frame after unicast to Multicast conversion + */ + ifp = dhd_get_ifp(dhdp, 0); + ASSERT(ifp); + } + } + } +#endif /* PSTA */ + } +#endif /* MCAST_REGEN */ + +#ifdef DHD_WMF + /* WMF processing for multicast packets */ + if (ifp->wmf.wmf_enable && (ETHER_ISMULTI(eh->ether_dhost))) { + dhd_sta_t *sta; + int ret; + + sta = dhd_find_sta(dhdp, ifidx, (void *)eh->ether_shost); + ret = dhd_wmf_packets_handle(dhdp, pktbuf, sta, ifidx, 1); + switch (ret) { + case WMF_TAKEN: + /* The packet is taken by WMF. Continue to next iteration */ + continue; + case WMF_DROP: + /* Packet DROP decision by WMF. Toss it */ + DHD_ERROR(("%s: WMF decides to drop packet\n", + __FUNCTION__)); + PKTCFREE(dhdp->osh, pktbuf, FALSE); + continue; + default: + /* Continue the transmit path */ + break; + } + } +#endif /* DHD_WMF */ + +#ifdef DHDTCPSYNC_FLOOD_BLK + if (dhd_tcpdata_get_flag(dhdp, pktbuf) == FLAG_SYNC) { + int delta_sec; + int delta_sync; + int sync_per_sec; + u64 curr_time = DIV_U64_BY_U32(OSL_LOCALTIME_NS(), NSEC_PER_SEC); + ifp->tsync_rcvd ++; + delta_sync = ifp->tsync_rcvd - ifp->tsyncack_txed; + delta_sec = curr_time - ifp->last_sync; + if (delta_sec > 1) { + sync_per_sec = delta_sync/delta_sec; + if (sync_per_sec > TCP_SYNC_FLOOD_LIMIT) { + schedule_work(&ifp->blk_tsfl_work); + DHD_ERROR(("ifx %d TCP SYNC Flood attack suspected! " + "sync recvied %d pkt/sec \n", + ifidx, sync_per_sec)); + ifp->tsync_per_sec = sync_per_sec; + } + dhd_reset_tcpsync_info_by_ifp(ifp); + } + + } +#endif /* DHDTCPSYNC_FLOOD_BLK */ + +#ifdef DHDTCPACK_SUPPRESS + dhd_tcpdata_info_get(dhdp, pktbuf); +#endif + skb = PKTTONATIVE(dhdp->osh, pktbuf); + + ASSERT(ifp); + skb->dev = ifp->net; +#ifdef DHD_WET + /* wet related packet proto manipulation should be done in DHD + * since dongle doesn't have complete payload + */ + if (WET_ENABLED(&dhd->pub) && (dhd_wet_recv_proc(dhd->pub.wet_info, + pktbuf) < 0)) { + DHD_INFO(("%s:%s: wet recv proc failed\n", + __FUNCTION__, dhd_ifname(dhdp, ifidx))); + } +#endif /* DHD_WET */ + +#ifdef DHD_PSTA + if (PSR_ENABLED(dhdp) && +#ifdef BCM_ROUTER_DHD + !(ifp->primsta_dwds) && +#endif /* BCM_ROUTER_DHD */ + (dhd_psta_proc(dhdp, ifidx, &pktbuf, FALSE) < 0)) { + DHD_ERROR(("%s:%s: psta recv proc failed\n", __FUNCTION__, + dhd_ifname(dhdp, ifidx))); + } +#endif /* DHD_PSTA */ + +#if defined(BCM_ROUTER_DHD) + /* XXX Use WOFA for both dhdap and dhdap-atlas router. */ + /* XXX dhd_sendpkt verify pkt accounting (TO/FRM NATIVE) and PKTCFREE */ + + if (DHD_IF_ROLE_AP(dhdp, ifidx) && (!ifp->ap_isolate)) { + eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); + if (ETHER_ISUCAST(eh->ether_dhost)) { + if (dhd_find_sta(dhdp, ifidx, (void *)eh->ether_dhost)) { + dhd_sendpkt(dhdp, ifidx, pktbuf); + continue; + } + } else { + void *npkt; +#if defined(HNDCTF) + if (PKTISCHAINED(pktbuf)) { /* XXX WAR */ + DHD_ERROR(("Error: %s():%d Chained non unicast pkt<%p>\n", + __FUNCTION__, __LINE__, pktbuf)); + PKTFRMNATIVE(dhdp->osh, pktbuf); + PKTCFREE(dhdp->osh, pktbuf, FALSE); + continue; + } +#endif /* HNDCTF */ + if ((ntoh16(eh->ether_type) != ETHER_TYPE_IAPP_L2_UPDATE) && + ((npkt = PKTDUP(dhdp->osh, pktbuf)) != NULL)) + dhd_sendpkt(dhdp, ifidx, npkt); + } + } + +#if defined(HNDCTF) + /* try cut thru' before sending up */ + if (dhd_ctf_forward(dhd, skb, &pnext) == BCME_OK) { + continue; + } +#endif /* HNDCTF */ + +#else /* !BCM_ROUTER_DHD */ + +#if defined(DBG_PKT_MON) && !defined(PCIE_FULL_DONGLE) + if (dhd_80211_mon_pkt(dhdp, pktbuf, ifidx)) { + continue; + } +#endif + +#ifdef PCIE_FULL_DONGLE + if ((DHD_IF_ROLE_AP(dhdp, ifidx) || DHD_IF_ROLE_P2PGO(dhdp, ifidx)) && + (!ifp->ap_isolate)) { + eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); + if (ETHER_ISUCAST(eh->ether_dhost)) { + if (dhd_find_sta(dhdp, ifidx, (void *)eh->ether_dhost)) { + dhdp->rx_forward++; /* Local count */ + dhd_sendpkt(dhdp, ifidx, pktbuf); + continue; + } + } else { + if ((ntoh16(eh->ether_type) != ETHER_TYPE_IAPP_L2_UPDATE)) { + void *npktbuf = NULL; + /* + * If host_sfhllc_supported enabled, do skb_copy as SFHLLC + * header will be inserted during Tx, due to which network + * stack will not decode the Rx packet. + * Else PKTDUP(skb_clone) is enough. + */ + if (dhdp->host_sfhllc_supported) { + npktbuf = skb_copy(skb, GFP_ATOMIC); + } else { + npktbuf = PKTDUP(dhdp->osh, pktbuf); + } + if (npktbuf != NULL) { + dhdp->rx_forward++; /* Local count */ + dhd_sendpkt(dhdp, ifidx, npktbuf); + } + } + } + } +#endif /* PCIE_FULL_DONGLE */ +#endif /* BCM_ROUTER_DHD */ +#ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT + if (IS_STA_IFACE(ndev_to_wdev(ifp->net)) && + (ifp->recv_reassoc_evt == TRUE) && (ifp->post_roam_evt == FALSE) && + (dhd_is_4way_msg((char *)(skb->data)) == EAPOL_4WAY_M1)) { + DHD_ERROR(("%s: Reassoc is in progress. " + "Drop EAPOL M1 frame\n", __FUNCTION__)); + PKTFREE(dhdp->osh, pktbuf, FALSE); + continue; + } +#endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */ +#ifdef WLEASYMESH + if ((dhdp->conf->fw_type == FW_TYPE_EZMESH) && + (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) { + uint16 * da = (uint16 *)(eh->ether_dhost); + ASSERT(ISALIGNED(da, 2)); + + /* XXX: Special handling for 1905 messages + * if DA matches with configured 1905 AL MAC addresses + * bypass fwder and foward it to linux stack + */ + if (ntoh16(eh->ether_type) == ETHER_TYPE_1905_1) { + if (!eacmp(da, ifp->_1905_al_ucast) || !eacmp(da, ifp->_1905_al_mcast)) { + //skb->fwr_flood = 0; + } else { + //skb->fwr_flood = 1; + } + } + } +#endif /* WLEASYMESH */ + /* Get the protocol, maintain skb around eth_type_trans() + * The main reason for this hack is for the limitation of + * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len' + * to perform skb_pull inside vs ETH_HLEN. Since to avoid + * coping of the packet coming from the network stack to add + * BDC, Hardware header etc, during network interface registration + * we set the 'net->hard_header_len' to ETH_HLEN + extra space required + * for BDC, Hardware header etc. and not just the ETH_HLEN + */ + eth = skb->data; + len = skb->len; + dump_data = skb->data; + protocol = (skb->data[12] << 8) | skb->data[13]; + + if (protocol == ETHER_TYPE_802_1X) { + DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED); +#if defined(WL_CFG80211) && defined(WL_WPS_SYNC) + wl_handle_wps_states(ifp->net, dump_data, len, FALSE); +#endif /* WL_CFG80211 && WL_WPS_SYNC */ +#ifdef DHD_4WAYM4_FAIL_DISCONNECT + if (dhd_is_4way_msg((uint8 *)(skb->data)) == EAPOL_4WAY_M3) { + OSL_ATOMIC_SET(dhdp->osh, &ifp->m4state, M3_RXED); + } +#endif /* DHD_4WAYM4_FAIL_DISCONNECT */ +#ifdef EAPOL_RESEND + wl_ext_release_eapol_txpkt(dhdp, ifidx, TRUE); +#endif /* EAPOL_RESEND */ + } + dhd_handle_pktdata(dhdp, ifidx, skb, dump_data, FALSE, + len, NULL, NULL, NULL, FALSE, pkt_wake, TRUE); +#if defined(DHD_WAKE_STATUS) && defined(DHD_WAKEPKT_DUMP) + if (pkt_wake) { + DHD_ERROR(("##### dhdpcie_host_wake caused by packets\n")); + dhd_prhex("[wakepkt_dump]", (char*)dump_data, MIN(len, 64), DHD_RPM_VAL); + DHD_ERROR(("config check in_suspend: %d\n", dhdp->in_suspend)); +#ifdef ARP_OFFLOAD_SUPPORT + DHD_ERROR(("arp hmac_update:%d \n", dhdp->hmac_updated)); +#endif /* ARP_OFFLOAD_SUPPORT */ +#if defined(DHD_WAKEPKT_SET_MARK) && defined(CONFIG_NF_CONNTRACK_MARK) + PKTMARK(skb) |= 0x80000000; +#endif /* DHD_WAKEPKT_SET_MARK && CONFIG_NF_CONNTRACK_MARK */ + } +#endif /* DHD_WAKE_STATUS && DHD_WAKEPKT_DUMP */ + + skb->protocol = eth_type_trans(skb, skb->dev); + + if (skb->pkt_type == PACKET_MULTICAST) { + dhd->pub.rx_multicast++; + ifp->stats.multicast++; + } + + skb->data = eth; + skb->len = len; + + /* TODO: XXX: re-look into dropped packets. */ + DHD_DBG_PKT_MON_RX(dhdp, skb, FRAME_TYPE_ETHERNET_II); + /* Strip header, count, deliver upward */ + skb_pull(skb, ETH_HLEN); + +#ifdef ENABLE_WAKEUP_PKT_DUMP + if (dhd_mmc_wake) { + DHD_INFO(("wake_pkt %s(%d)\n", __FUNCTION__, __LINE__)); + prhex("wake_pkt", (char*) eth, MIN(len, 64)); + + update_wake_pkt_info(skb); + DHD_ERROR(("wake_pkt %s(%d), raw_info=0x%016llx\n", + __FUNCTION__, __LINE__, temp_raw)) +#ifdef CONFIG_IRQ_HISTORY + add_irq_history(0, "WIFI"); +#endif + dhd_mmc_wake = FALSE; + } +#endif /* ENABLE_WAKEUP_PKT_DUMP */ + + /* Process special event packets and then discard them */ + /* XXX Decide on a better way to fit this in */ + memset(&event, 0, sizeof(event)); + + if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) { + bcm_event_msg_u_t evu; + int ret_event, event_type; + void *pkt_data = skb_mac_header(skb); + + ret_event = wl_host_event_get_data(pkt_data, len, &evu); + + if (ret_event != BCME_OK) { + DHD_ERROR(("%s: wl_host_event_get_data err = %d\n", + __FUNCTION__, ret_event)); + PKTFREE_CTRLBUF(dhdp->osh, pktbuf, FALSE); + continue; + } + + memcpy(&event, &evu.event, sizeof(wl_event_msg_t)); + event_type = ntoh32_ua((void *)&event.event_type); +#ifdef SHOW_LOGTRACE + /* Event msg printing is called from dhd_rx_frame which is in Tasklet + * context in case of PCIe FD, in case of other bus this will be from + * DPC context. If we get bunch of events from Dongle then printing all + * of them from Tasklet/DPC context that too in data path is costly. + * Also in the new Dongle SW(4359, 4355 onwards) console prints too come as + * events with type WLC_E_TRACE. + * We'll print this console logs from the WorkQueue context by enqueing SKB + * here and Dequeuing will be done in WorkQueue and will be freed only if + * logtrace_pkt_sendup is true + */ + if (event_type == WLC_E_TRACE) { + DHD_TRACE(("%s: WLC_E_TRACE\n", __FUNCTION__)); + dhd_event_logtrace_enqueue(dhdp, ifidx, pktbuf); + continue; + } +#endif /* SHOW_LOGTRACE */ + + ret_event = dhd_wl_host_event(dhd, ifidx, pkt_data, len, &event, &data); + + wl_event_to_host_order(&event); +#if defined(OEM_ANDROID) + if (!tout_ctrl) + tout_ctrl = DHD_PACKET_TIMEOUT_MS; +#endif /* OEM_ANDROID */ + +#if (defined(OEM_ANDROID) && defined(PNO_SUPPORT)) + if (event_type == WLC_E_PFN_NET_FOUND) { + /* enforce custom wake lock to garantee that Kernel not suspended */ + tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS; + } +#endif /* PNO_SUPPORT */ + if (numpkt != 1) { + DHD_TRACE(("%s: Got BRCM event packet in a chained packet.\n", + __FUNCTION__)); + } + +#ifdef DHD_WAKE_STATUS + if (unlikely(pkt_wake)) { +#ifdef DHD_WAKE_EVENT_STATUS + if (event.event_type < WLC_E_LAST) { +#ifdef CUSTOM_WAKE_REASON_STATS + if (wcp->rc_event_idx == MAX_WAKE_REASON_STATS) { + wcp->rc_event_idx = 0; + } + DHD_ERROR(("[pkt_wake] event id %u = %s\n", + event.event_type, + bcmevent_get_name(event.event_type))); + wcp->rc_event[wcp->rc_event_idx] = event.event_type; + wcp->rc_event_idx++; +#else + wcp->rc_event[event.event_type]++; +#endif /* CUSTOM_WAKE_REASON_STATS */ + wcp->rcwake++; + pkt_wake = 0; + } +#endif /* DHD_WAKE_EVENT_STATUS */ + } +#endif /* DHD_WAKE_STATUS */ + + /* For delete virtual interface event, wl_host_event returns positive + * i/f index, do not proceed. just free the pkt. + */ + if ((event_type == WLC_E_IF) && (ret_event > 0)) { + DHD_ERROR(("%s: interface is deleted. Free event packet\n", + __FUNCTION__)); + PKTFREE_CTRLBUF(dhdp->osh, pktbuf, FALSE); + continue; + } + + /* + * For the event packets, there is a possibility + * of ifidx getting modifed.Thus update the ifp + * once again. + */ + ASSERT(ifidx < DHD_MAX_IFS); + ifp = dhd->iflist[ifidx]; +#ifndef PROP_TXSTATUS_VSDB + if (!(ifp && ifp->net && (ifp->net->reg_state == NETREG_REGISTERED))) +#else + if (!(ifp && ifp->net && (ifp->net->reg_state == NETREG_REGISTERED) && + dhd->pub.up)) +#endif /* PROP_TXSTATUS_VSDB */ + { + DHD_ERROR(("%s: net device is NOT registered. drop event packet\n", + __FUNCTION__)); + PKTFREE_CTRLBUF(dhdp->osh, pktbuf, FALSE); + continue; + } + +#ifdef SENDPROB + if (dhdp->wl_event_enabled || + (dhdp->recv_probereq && (event.event_type == WLC_E_PROBREQ_MSG))) +#else + if (dhdp->wl_event_enabled) +#endif + { +#ifdef DHD_USE_STATIC_CTRLBUF + /* If event bufs are allocated via static buf pool + * and wl events are enabled, make a copy, free the + * local one and send the copy up. + */ + struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); + /* Copy event and send it up */ + PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); + if (nskb) { + skb = nskb; + } else { + DHD_ERROR(("skb clone failed. dropping event.\n")); + continue; + } +#endif /* DHD_USE_STATIC_CTRLBUF */ + } else { + /* If event enabled not explictly set, drop events */ + PKTFREE_CTRLBUF(dhdp->osh, pktbuf, FALSE); + continue; + } + } else { +#if defined(OEM_ANDROID) + tout_rx = DHD_PACKET_TIMEOUT_MS; + + /* Override rx wakelock timeout to give hostapd enough time + * to process retry or error handling for handshake + */ + if (IS_AP_IFACE(ndev_to_wdev(ifp->net)) && + ntoh16(skb->protocol) == ETHER_TYPE_802_1X) { + if (dhd_is_4way_msg(dump_data) == EAPOL_4WAY_M2) { + tout_rx = DHD_HANDSHAKE_TIMEOUT_MS; + } + } +#endif /* OEM_ANDROID */ + +#ifdef PROP_TXSTATUS + dhd_wlfc_save_rxpath_ac_time(dhdp, (uint8)PKTPRIO(skb)); +#endif /* PROP_TXSTATUS */ + +#ifdef DHD_WAKE_STATUS + if (unlikely(pkt_wake)) { + wcp->rxwake++; +#ifdef DHD_WAKE_RX_STATUS + + if (ntoh16(skb->protocol) == ETHER_TYPE_ARP) /* ARP */ + wcp->rx_arp++; + if (ntoh16(skb->protocol) == ETHER_TYPE_IP) { + struct iphdr *ipheader = NULL; + ipheader = (struct iphdr*)(skb->data); + if (ipheader && ipheader->protocol == IPPROTO_ICMP) { + wcp->rx_icmp++; + } + } + if (dump_data[0] == 0xFF) { /* Broadcast */ + wcp->rx_bcast++; + } else if (dump_data[0] & 0x01) { /* Multicast */ + wcp->rx_mcast++; + if (ntoh16(skb->protocol) == ETHER_TYPE_IPV6) { + wcp->rx_multi_ipv6++; + if ((skb->len > ETHER_ICMP6_HEADER) && + (dump_data[ETHER_ICMP6_HEADER] == IPPROTO_ICMPV6)) { + wcp->rx_icmpv6++; + if (skb->len > ETHER_ICMPV6_TYPE) { + switch (dump_data[ETHER_ICMPV6_TYPE]) { + case NDISC_ROUTER_ADVERTISEMENT: + wcp->rx_icmpv6_ra++; + break; + case NDISC_NEIGHBOUR_ADVERTISEMENT: + wcp->rx_icmpv6_na++; + break; + case NDISC_NEIGHBOUR_SOLICITATION: + wcp->rx_icmpv6_ns++; + break; + } + } + } + } else if (dump_data[2] == 0x5E) { + wcp->rx_multi_ipv4++; + } else { + wcp->rx_multi_other++; + } + } else { /* Unicast */ + wcp->rx_ucast++; + } +#undef ETHER_ICMP6_HEADER +#undef ETHER_IPV6_SADDR +#undef ETHER_IPV6_DAADR +#undef ETHER_ICMPV6_TYPE +#ifdef DHD_WAKE_STATUS_PRINT + dhd_dump_wake_status(dhdp, wcp, (struct ether_header *)eth); +#endif /* DHD_WAKE_STATUS_PRINT */ +#endif /* DHD_WAKE_RX_STATUS */ + pkt_wake = 0; + } +#endif /* DHD_WAKE_STATUS */ + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) + ifp->net->last_rx = jiffies; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) */ + + if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { + dhdp->dstats.rx_bytes += skb->len; + dhdp->rx_bytes += skb->len; + dhdp->rx_packets++; /* Local count */ + ifp->stats.rx_bytes += skb->len; + ifp->stats.rx_packets++; + } + + /* XXX WL here makes sure data is 4-byte aligned? */ + if (in_interrupt()) { + bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, + __FUNCTION__, __LINE__); +#if defined(DHD_LB_RXP) +#ifdef ENABLE_DHD_GRO + /* The pktlog module clones a skb using skb_clone and + * stores the skb point to the ring buffer of the pktlog module. + * Once the buffer is full, + * the PKTFREE is called for removing the oldest skb. + * The kernel panic occurred when the pktlog module free + * the rx frame handled by napi_gro_receive(). + * It is a fix code that DHD don't use napi_gro_receive() for + * the packet used in pktlog module. + */ + if (dhd_gro_enable && !skb_cloned(skb) && + ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { + napi_gro_receive(&dhd->rx_napi_struct, skb); + } else { +#if defined(WL_MONITOR) && defined(BCMSDIO) + if (dhd_monitor_enabled(dhdp, ifidx)) + dhd_rx_mon_pkt_sdio(dhdp, skb, ifidx); + else +#endif /* WL_MONITOR && BCMSDIO */ + netif_receive_skb(skb); + } +#else +#if defined(WL_MONITOR) && defined(BCMSDIO) + if (dhd_monitor_enabled(dhdp, ifidx)) + dhd_rx_mon_pkt_sdio(dhdp, skb, ifidx); + else +#endif /* WL_MONITOR && BCMSDIO */ + netif_receive_skb(skb); +#endif /* ENABLE_DHD_GRO */ +#else /* !defined(DHD_LB_RXP) */ + netif_rx(skb); +#endif /* !defined(DHD_LB_RXP) */ + } else { + if (dhd->rxthread_enabled) { + if (!skbhead) + skbhead = skb; + else + PKTSETNEXT(dhdp->osh, skbprev, skb); + skbprev = skb; + } else { + + /* If the receive is not processed inside an ISR, + * the softirqd must be woken explicitly to service + * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled + * by netif_rx_ni(), but in earlier kernels, we need + * to do it manually. + */ + bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, + __FUNCTION__, __LINE__); + +#if defined(BCMPCIE) && defined(DHDTCPACK_SUPPRESS) + dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF); +#endif /* BCMPCIE && DHDTCPACK_SUPPRESS */ +#if defined(DHD_LB_RXP) +#ifdef ENABLE_DHD_GRO + if (dhd_gro_enable && !skb_cloned(skb) && + ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { + napi_gro_receive(&dhd->rx_napi_struct, skb); + } else { + netif_receive_skb(skb); + } +#else + netif_receive_skb(skb); +#endif /* ENABLE_DHD_GRO */ +#else /* !defined(DHD_LB_RXP) */ + dhd_netif_rx_ni(skb); +#endif /* !defined(DHD_LB_RXP) */ + } + } + } + + if (dhd->rxthread_enabled && skbhead) + dhd_sched_rxf(dhdp, skbhead); + +#if defined(OEM_ANDROID) + DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); + + /* To immediately notify the host that timeout is enabled */ + DHD_OS_WAKE_LOCK_TIMEOUT(dhdp); +#endif /* OEM_ANDROID */ +} + +int +dhd_rxf_thread(void *data) +{ + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + dhd_info_t *dhd = (dhd_info_t *)tsk->parent; +#if defined(WAIT_DEQUEUE) +#define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) / */ + ulong watchdogTime = OSL_SYSUPTIME(); /* msec */ +#endif + dhd_pub_t *pub = &dhd->pub; + + /* This thread doesn't need any user-level access, + * so get rid of all our resources + */ + if (dhd_rxf_prio > 0) + { + struct sched_param param; + param.sched_priority = (dhd_rxf_prio < MAX_RT_PRIO)?dhd_rxf_prio:(MAX_RT_PRIO-1); + setScheduler(current, SCHED_FIFO, ¶m); + } + +#ifdef CUSTOM_SET_CPUCORE + dhd->pub.current_rxf = current; +#endif /* CUSTOM_SET_CPUCORE */ + /* Run until signal received */ + while (1) { + if (dhd->pub.conf->rxf_cpucore >= 0) { + printf("%s: set rxf_cpucore %d\n", __FUNCTION__, dhd->pub.conf->rxf_cpucore); + set_cpus_allowed_ptr(current, cpumask_of(dhd->pub.conf->rxf_cpucore)); + dhd->pub.conf->rxf_cpucore = -1; + } + if (down_interruptible(&tsk->sema) == 0) { + void *skb; +#ifdef ENABLE_ADAPTIVE_SCHED + dhd_sched_policy(dhd_rxf_prio); +#endif /* ENABLE_ADAPTIVE_SCHED */ + + SMP_RD_BARRIER_DEPENDS(); + + if (tsk->terminated) { + DHD_OS_WAKE_UNLOCK(pub); + break; + } + skb = dhd_rxf_dequeue(pub); + + if (skb == NULL) { + continue; + } + while (skb) { + void *skbnext = PKTNEXT(pub->osh, skb); + PKTSETNEXT(pub->osh, skb, NULL); + bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, + __FUNCTION__, __LINE__); +#if defined(WL_MONITOR) && defined(BCMSDIO) + if (dhd_monitor_enabled(pub, 0)) + dhd_rx_mon_pkt_sdio(pub, skb, 0); + else +#endif /* WL_MONITOR && BCMSDIO */ + dhd_netif_rx_ni(skb); + skb = skbnext; + } +#if defined(WAIT_DEQUEUE) + if (OSL_SYSUPTIME() - watchdogTime > RXF_WATCHDOG_TIME) { + OSL_SLEEP(1); + watchdogTime = OSL_SYSUPTIME(); + } +#endif + + DHD_OS_WAKE_UNLOCK(pub); + } else { + break; + } + } + complete_and_exit(&tsk->completed, 0); +} + +void +dhd_sched_rxf(dhd_pub_t *dhdp, void *skb) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; +#ifdef RXF_DEQUEUE_ON_BUSY + int ret = BCME_OK; + int retry = 2; +#endif /* RXF_DEQUEUE_ON_BUSY */ + + DHD_OS_WAKE_LOCK(dhdp); + + DHD_TRACE(("dhd_sched_rxf: Enter\n")); +#ifdef RXF_DEQUEUE_ON_BUSY + do { + ret = dhd_rxf_enqueue(dhdp, skb); + if (ret == BCME_OK || ret == BCME_ERROR) + break; + else + OSL_SLEEP(50); /* waiting for dequeueing */ + } while (retry-- > 0); + + if (retry <= 0 && ret == BCME_BUSY) { + void *skbp = skb; + + while (skbp) { + void *skbnext = PKTNEXT(dhdp->osh, skbp); + PKTSETNEXT(dhdp->osh, skbp, NULL); + bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, + __FUNCTION__, __LINE__); + dhd_netif_rx_ni(skbp); + skbp = skbnext; + } + DHD_ERROR(("send skb to kernel backlog without rxf_thread\n")); + } else { + if (dhd->thr_rxf_ctl.thr_pid >= 0) { + up(&dhd->thr_rxf_ctl.sema); + } + } +#else /* RXF_DEQUEUE_ON_BUSY */ + do { + if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK) + break; + } while (1); + if (dhd->thr_rxf_ctl.thr_pid >= 0) { + up(&dhd->thr_rxf_ctl.sema); + } else { + DHD_OS_WAKE_UNLOCK(dhdp); + } + return; +#endif /* RXF_DEQUEUE_ON_BUSY */ +} + +#ifdef WL_MONITOR +#ifdef BCMSDIO +void +dhd_rx_mon_pkt_sdio(dhd_pub_t *dhdp, void *pkt, int ifidx) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + + if (!dhd->monitor_skb) { + if ((dhd->monitor_skb = PKTTONATIVE(dhdp->osh, pkt)) == NULL) + return; + } + + if (dhd->monitor_type && dhd->monitor_dev) + dhd->monitor_skb->dev = dhd->monitor_dev; + else { + PKTFREE(dhdp->osh, pkt, FALSE); + dhd->monitor_skb = NULL; + return; + } + + dhd->monitor_skb->protocol = + eth_type_trans(dhd->monitor_skb, dhd->monitor_skb->dev); + dhd->monitor_len = 0; + + netif_rx_ni(dhd->monitor_skb); + + dhd->monitor_skb = NULL; +} +#elif defined(BCMPCIE) +void +dhd_rx_mon_pkt(dhd_pub_t *dhdp, host_rxbuf_cmpl_t* msg, void *pkt, int ifidx) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; +#ifdef HOST_RADIOTAP_CONV + if (dhd->host_radiotap_conv) { + uint16 len = 0, offset = 0; + monitor_pkt_info_t pkt_info; + + memcpy(&pkt_info.marker, &msg->marker, sizeof(msg->marker)); + memcpy(&pkt_info.ts, &msg->ts, sizeof(monitor_pkt_ts_t)); + + if (!dhd->monitor_skb) { + if ((dhd->monitor_skb = dev_alloc_skb(MAX_MON_PKT_SIZE)) == NULL) + return; + } + + len = bcmwifi_monitor(dhd->monitor_info, &pkt_info, PKTDATA(dhdp->osh, pkt), + PKTLEN(dhdp->osh, pkt), PKTDATA(dhdp->osh, dhd->monitor_skb), &offset); + + if (dhd->monitor_type && dhd->monitor_dev) + dhd->monitor_skb->dev = dhd->monitor_dev; + else { + PKTFREE(dhdp->osh, pkt, FALSE); + dev_kfree_skb(dhd->monitor_skb); + return; + } + + PKTFREE(dhdp->osh, pkt, FALSE); + + if (!len) { + return; + } + + skb_put(dhd->monitor_skb, len); + skb_pull(dhd->monitor_skb, offset); + + dhd->monitor_skb->protocol = eth_type_trans(dhd->monitor_skb, + dhd->monitor_skb->dev); + } + else +#endif /* HOST_RADIOTAP_CONV */ + { + uint8 amsdu_flag = (msg->flags & BCMPCIE_PKT_FLAGS_MONITOR_MASK) >> + BCMPCIE_PKT_FLAGS_MONITOR_SHIFT; + switch (amsdu_flag) { + case BCMPCIE_PKT_FLAGS_MONITOR_NO_AMSDU: + default: + if (!dhd->monitor_skb) { + if ((dhd->monitor_skb = PKTTONATIVE(dhdp->osh, pkt)) + == NULL) + return; + } + if (dhd->monitor_type && dhd->monitor_dev) + dhd->monitor_skb->dev = dhd->monitor_dev; + else { + PKTFREE(dhdp->osh, pkt, FALSE); + dhd->monitor_skb = NULL; + return; + } + dhd->monitor_skb->protocol = + eth_type_trans(dhd->monitor_skb, dhd->monitor_skb->dev); + dhd->monitor_len = 0; + break; + + case BCMPCIE_PKT_FLAGS_MONITOR_FIRST_PKT: + if (!dhd->monitor_skb) { + if ((dhd->monitor_skb = dev_alloc_skb(MAX_MON_PKT_SIZE)) + == NULL) + return; + dhd->monitor_len = 0; + } + if (dhd->monitor_type && dhd->monitor_dev) + dhd->monitor_skb->dev = dhd->monitor_dev; + else { + PKTFREE(dhdp->osh, pkt, FALSE); + dev_kfree_skb(dhd->monitor_skb); + return; + } + memcpy(PKTDATA(dhdp->osh, dhd->monitor_skb), + PKTDATA(dhdp->osh, pkt), PKTLEN(dhdp->osh, pkt)); + dhd->monitor_len = PKTLEN(dhdp->osh, pkt); + PKTFREE(dhdp->osh, pkt, FALSE); + return; + + case BCMPCIE_PKT_FLAGS_MONITOR_INTER_PKT: + memcpy(PKTDATA(dhdp->osh, dhd->monitor_skb) + dhd->monitor_len, + PKTDATA(dhdp->osh, pkt), PKTLEN(dhdp->osh, pkt)); + dhd->monitor_len += PKTLEN(dhdp->osh, pkt); + PKTFREE(dhdp->osh, pkt, FALSE); + return; + + case BCMPCIE_PKT_FLAGS_MONITOR_LAST_PKT: + memcpy(PKTDATA(dhdp->osh, dhd->monitor_skb) + dhd->monitor_len, + PKTDATA(dhdp->osh, pkt), PKTLEN(dhdp->osh, pkt)); + dhd->monitor_len += PKTLEN(dhdp->osh, pkt); + PKTFREE(dhdp->osh, pkt, FALSE); + skb_put(dhd->monitor_skb, dhd->monitor_len); + dhd->monitor_skb->protocol = + eth_type_trans(dhd->monitor_skb, dhd->monitor_skb->dev); + dhd->monitor_len = 0; + break; + } + } + + if (skb_headroom(dhd->monitor_skb) < ETHER_HDR_LEN) { + struct sk_buff *skb2; + + DHD_INFO(("%s: insufficient headroom\n", + dhd_ifname(&dhd->pub, ifidx))); + + skb2 = skb_realloc_headroom(dhd->monitor_skb, ETHER_HDR_LEN); + + dev_kfree_skb(dhd->monitor_skb); + if ((dhd->monitor_skb = skb2) == NULL) { + DHD_ERROR(("%s: skb_realloc_headroom failed\n", + dhd_ifname(&dhd->pub, ifidx))); + return; + } + } + PKTPUSH(dhd->pub.osh, dhd->monitor_skb, ETHER_HDR_LEN); + + /* XXX WL here makes sure data is 4-byte aligned? */ + if (in_interrupt()) { + bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, + __FUNCTION__, __LINE__); + netif_rx(dhd->monitor_skb); + } else { + /* If the receive is not processed inside an ISR, + * the softirqd must be woken explicitly to service + * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled + * by netif_rx_ni(), but in earlier kernels, we need + * to do it manually. + */ + bcm_object_trace_opr(dhd->monitor_skb, BCM_OBJDBG_REMOVE, + __FUNCTION__, __LINE__); + + dhd_netif_rx_ni(dhd->monitor_skb); + } + + dhd->monitor_skb = NULL; + +#if defined(OEM_ANDROID) + DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, DHD_MONITOR_TIMEOUT_MS); + DHD_OS_WAKE_LOCK_TIMEOUT(dhdp); +#endif /* OEM_ANDROID */ +} +#endif /* PCIE_FULL_DONGLE */ +#endif /* WL_MONITOR */ + +static int +dhd_wl_host_event(dhd_info_t *dhd, int ifidx, void *pktdata, uint16 pktlen, + wl_event_msg_t *event, void **data) +{ + int bcmerror = 0; +#ifdef WL_CFG80211 + unsigned long flags = 0; +#endif /* WL_CFG80211 */ + ASSERT(dhd != NULL); + +#ifdef SHOW_LOGTRACE + bcmerror = wl_process_host_event(&dhd->pub, &ifidx, pktdata, pktlen, event, data, + &dhd->event_data); +#else + bcmerror = wl_process_host_event(&dhd->pub, &ifidx, pktdata, pktlen, event, data, + NULL); +#endif /* SHOW_LOGTRACE */ + if (unlikely(bcmerror != BCME_OK)) { + return bcmerror; + } + + if (ntoh32(event->event_type) == WLC_E_IF) { + /* WLC_E_IF event types are consumed by wl_process_host_event. + * For ifadd/del ops, the netdev ptr may not be valid at this + * point. so return before invoking cfg80211/wext handlers. + */ + return BCME_OK; + } + +#ifdef WL_EVENT + wl_ext_event_send(dhd->pub.event_params, event, *data); +#endif + +#ifdef WL_CFG80211 + if (dhd->iflist[ifidx]->net) { + DHD_UP_LOCK(&dhd->pub.up_lock, flags); + if (dhd->pub.up) { + wl_cfg80211_event(dhd->iflist[ifidx]->net, event, *data); + } + DHD_UP_UNLOCK(&dhd->pub.up_lock, flags); + } +#endif /* defined(WL_CFG80211) */ + + return (bcmerror); +} + +void +dhd_os_sdlock_rxq(dhd_pub_t *pub) +{ +} + +void +dhd_os_sdunlock_rxq(dhd_pub_t *pub) +{ +} + +static void +dhd_os_rxflock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_lock_bh(&dhd->rxf_lock); + +} + +static void +dhd_os_rxfunlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_unlock_bh(&dhd->rxf_lock); +} + +#ifdef PKT_FILTER_SUPPORT +int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) +{ + int ret = 0; + +#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER + dhd_info_t *dhd = DHD_DEV_INFO(dev); + + if (!dhd_master_mode) + add_remove = !add_remove; + DHD_INFO(("%s: add_remove = %d, num = %d\n", __FUNCTION__, add_remove, num)); + if (!dhd || (num == DHD_UNICAST_FILTER_NUM)) { + return 0; + } + +#ifdef BLOCK_IPV6_PACKET + /* customer want to use NO IPV6 packets only */ + if (num == DHD_MULTICAST6_FILTER_NUM) { + return 0; + } +#endif /* BLOCK_IPV6_PACKET */ + + if (num >= dhd->pub.pktfilter_count) { + return -EINVAL; + } + + ret = dhd_packet_filter_add_remove(&dhd->pub, add_remove, num); +#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */ + + return ret; +} +#endif /* PKT_FILTER_SUPPORT */ + +int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + + if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { + DHD_WAKE_SPIN_LOCK(&dhd->wakelock_spinlock, flags); + if (val > dhd->wakelock_rx_timeout_enable) + dhd->wakelock_rx_timeout_enable = val; + DHD_WAKE_SPIN_UNLOCK(&dhd->wakelock_spinlock, flags); + } + return 0; +} + +int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) +{ + dhd_info_t *dhd = DHD_DEV_INFO(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val); + return ret; +} + +#ifdef DHD_PCIE_NATIVE_RUNTIMEPM +void +dhd_flush_rx_tx_wq(dhd_pub_t *dhdp) +{ + dhd_info_t * dhd; + + if (dhdp) { + dhd = dhdp->info; + if (dhd) { + flush_workqueue(dhd->tx_wq); + flush_workqueue(dhd->rx_wq); + } + } + + return; +} +#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ + +#ifdef RX_PKT_POOL +void * +BCMFASTPATH(dhd_rxpool_pktget)(osl_t *osh, dhd_info_t *dhd, uint16 len) +{ + void *p = NULL; + pkt_pool_t *rx_pool = &dhd->rx_pkt_pool; + + if (dhd->rx_pktpool_thread.thr_pid >= 0) { + if (rx_pool->rxbuf_sz == len) { + p = skb_dequeue(&rx_pool->skb_q); + /* kick rx buffer mgmt thread to alloc more rx + * buffers into the pool + */ + binary_sema_up(&dhd->rx_pktpool_thread); + } else { + DHD_ERROR_RLMT(("%s: PKTGET_RX_POOL is called with length %u, " + "but pkt pool created with length : %u\n", __FUNCTION__, + len, rx_pool->rxbuf_sz)); + } + } else { + DHD_ERROR_RLMT(("%s: rx_pktpool_thread(%ld) not inited\n", __FUNCTION__, + dhd->rx_pktpool_thread.thr_pid)); + } + + return p; +} + +static int +dhd_rx_pktpool_thread(void *data) +{ + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + dhd_info_t *dhd = (dhd_info_t *)tsk->parent; + dhd_pub_t *dhdp = (dhd_pub_t *)&dhd->pub; + pkt_pool_t *rx_pool = &dhd->rx_pkt_pool; + void *p = NULL; + int qlen = 0; + int num_attempts = 0; + + DHD_TRACE(("%s: STARTED...\n", __FUNCTION__)); + while (1) { + if (!binary_sema_down(tsk)) { + SMP_RD_BARRIER_DEPENDS(); + /* Check terminated before processing the items */ + if (tsk->terminated) { + DHD_ERROR(("%s: task terminated\n", __FUNCTION__)); + goto exit; + } + /* Allocate rx buffer only after dongle + * handshake the actual rxbuf size. + */ + if (rx_pool->rxbuf_sz) { + qlen = skb_queue_len(&rx_pool->skb_q); + DHD_TRACE(("%s: before alloc - skb_q len=%u, max_size=%u " + "rxbuf_sz : %u\n", __FUNCTION__, qlen, rx_pool->max_size, + rx_pool->rxbuf_sz)); + num_attempts = 0; + while (qlen < rx_pool->max_size) { + p = PKTGET(dhdp->osh, rx_pool->rxbuf_sz, FALSE); + if (!p) { + DHD_ERROR_RLMT(("%s: pktget fails, resched...\n", + __FUNCTION__)); + /* retry after some time to fetch packets + * if maximum attempts hit, stop + */ + num_attempts++; + if (num_attempts >= RX_PKTPOOL_FETCH_MAX_ATTEMPTS) { + DHD_ERROR_RLMT(("%s: max attempts to fetch" + " exceeded.\n", __FUNCTION__)); + break; + } + OSL_SLEEP(RX_PKTPOOL_RESCHED_DELAY_MS); + } else { + skb_queue_tail(&rx_pool->skb_q, p); + } + qlen = skb_queue_len(&rx_pool->skb_q); + } + DHD_TRACE(("%s: after alloc - skb_q len=%u, max_size=%u \n", + __FUNCTION__, qlen, rx_pool->max_size)); + } + } else { + DHD_ERROR_RLMT(("%s: unexpected break\n", __FUNCTION__)); + break; + } + } +exit: + DHD_TRACE(("%s: EXITED...\n", __FUNCTION__)); + complete_and_exit(&tsk->completed, 0); +} + +void +dhd_rx_pktpool_create(dhd_info_t *dhd, uint16 rxbuf_sz) +{ + pkt_pool_t *rx_pool = &dhd->rx_pkt_pool; + rx_pool->rxbuf_sz = rxbuf_sz; + binary_sema_up(&dhd->rx_pktpool_thread); +} + +void +dhd_rx_pktpool_init(dhd_info_t *dhd) +{ + pkt_pool_t *rx_pool = &dhd->rx_pkt_pool; + + skb_queue_head_init(&rx_pool->skb_q); + rx_pool->max_size = MAX_RX_PKT_POOL; + rx_pool->rxbuf_sz = 0; + + PROC_START(dhd_rx_pktpool_thread, dhd, &dhd->rx_pktpool_thread, 0, "dhd_rx_pktpool_thread"); +} + +void +dhd_rx_pktpool_deinit(dhd_info_t *dhd) +{ + pkt_pool_t *rx_pool = &dhd->rx_pkt_pool; + tsk_ctl_t *tsk = &dhd->rx_pktpool_thread; + + if (tsk->parent && tsk->thr_pid >= 0) { + PROC_STOP_USING_BINARY_SEMA(tsk); + } else { + DHD_ERROR(("%s: rx_pktpool_thread(%ld) not inited\n", + __FUNCTION__, tsk->thr_pid)); + } + /* skb list manipulation functions use internal + * spin lock, so no need to take separate lock + */ + skb_queue_purge(&rx_pool->skb_q); + rx_pool->max_size = 0; + DHD_ERROR(("%s: de-alloc'd rx buffers in pool \n", + __FUNCTION__)); +} +#endif /* RX_PKT_POOL */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sched.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sched.c old mode 100755 new mode 100644 index 3d6786a85300..4735c4bda897 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sched.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sched.c @@ -1,7 +1,7 @@ /* * Expose some of the kernel scheduler routines * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -31,11 +31,24 @@ int setScheduler(struct task_struct *p, int policy, struct sched_param *param) { int rc = 0; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)) - sched_set_fifo_low(p); -#else + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)) rc = sched_setscheduler(p, policy, param); -#endif +#else + switch (policy) { + case SCHED_FIFO: + sched_set_fifo(p); + break; + case SCHED_RR: + sched_set_fifo_low(p); + break; + case SCHED_NORMAL: + default: + sched_set_normal(p, PRIO_TO_NICE(param->sched_priority)); + break; + } +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)) */ + return rc; } diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sock_qos.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sock_qos.c deleted file mode 100755 index 3348d892df88..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sock_qos.c +++ /dev/null @@ -1,1034 +0,0 @@ -/* - * Source file for DHD QOS on Socket Flow. - * - * Defines a socket flow and maintains a table of socket flows - * for further analysis in order to upgrade the QOS of the flow. - - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Maximum number of Socket Flows supported */ -#define MAX_SOCK_FLOW (1024UL) - -#define SOCK_FLOW_UPGRADE_THRESHOLD (3) -/* - * Mark a Socket Flow as inactive and free the resources - * if there is no packet receied for SOCK_IDLE_THREASHOLD_MS - * of time. Note that this parameter is in milli seconds. - */ -#define SOCK_IDLE_THRESHOLD_MS (2000UL) - -#define DSCP_TOS_CS7 0XE0u - -extern uint dhd_watchdog_ms; - -/* Defines Socket Flow */ -struct dhd_sock_flow_info -{ - /* Unique identifiers */ - struct sock *sk; - unsigned long ino; - - /* statistics */ - qos_stat_t stats; - u64 last_pkt_ns; - kuid_t uid; - - /* Elements related to upgrade management */ - - /* 0 - No upgrade - * 1 - Upgrade - */ - unsigned int cur_up_state; - unsigned int rcm_up_state; - unsigned int bus_flow_id; - - /* TODO: - * Handling Out Of Order during upgrade - * Once an upgrade is decided we cannot handover the skb to - * FW in the upgraded Flow Ring ... it will create Out of Order Packets. - * Instead we can have a output_q per socket flow. Once the upgrade is - * decided, we can start adding skbs to the output_q. The last 'skb' given - * to the actual Flow ring should be remembered in 'last_skb_orig_fl'. - * Once we get a Tx completion for last_skb_orig_fl we can flush the - * contents of output_q to the 'upgraded flowring'. In this solution, - * we should also handle the case where output_q hits the watermark - * before the completion for 'last_skb_orig_fl' is received. If this condition - * happens, not to worry about OOO and flush the contents of output_q. - * Probably the last_skb_orig_fl is not sent out due latency in the - * existing flow ... the actual problem we are trying to solve. - */ - - /* Management elements */ - struct list_head list; - unsigned int in_use; -}; - -typedef enum _frameburst_state -{ - FRMBRST_DISABLED = 0, - FRMBRST_ENABLED = 1 -} frameburst_state_t; - -/* Sock QOS Module Structure */ -typedef struct dhd_sock_qos_info -{ - /* Table of Socket Flows */ - struct dhd_sock_flow_info *sk_fl; - /* maximum number for socket flows supported */ - uint32 max_sock_fl; - - /* TODO: need to make it per flow later on */ - /* global qos algo parameters */ - qos_algo_params_t qos_params; - /* List in which active Socket Flows live */ - struct list_head sk_fl_list_head; - void *list_lock; - - /* Time interval a socket flow resource is moved out of the active list */ - uint32 sock_idle_thresh; - /* - * Keep track of number of flows upgraded. - * If it reaches a threshold we should stop ugrading - * This is to avoid the problem where we overwhelm - * the Dongle with upgraded traffic. - */ - int num_skfl_upgraded; - int skfl_upgrade_thresh; - - /* flag that is set to true when the first flow is upgraded - * so that FW frameburst is disabled, and set to false - * when no more flows are in upgraded state, so that - * FW frameburst is re-enabled - */ - bool upgrade_active; - /* fw frameburst state */ - frameburst_state_t frmbrst_state; - - atomic_t on_off; - atomic_t force_upgrade; - - /* required for enabling/disabling watchdog timer at runtime */ - uint watchdog_ms; -} dhd_sock_qos_info_t; - -#define SK_FL_LIST_LOCK(lock, flags) (flags) = osl_spin_lock(lock) -#define SK_FL_LIST_UNLOCK(lock, flags) osl_spin_unlock((lock), (flags)) - -int -dhd_init_sock_flows_buf(dhd_info_t *dhd, uint watchdog_ms) -{ - unsigned long sz; - unsigned int i; - struct dhd_sock_flow_info *sk_fl = NULL; - int val = 0, ret = 0; - - if (dhd == NULL) - return BCME_BADARG; - - dhd->psk_qos = MALLOCZ(dhd->pub.osh, sizeof(dhd_sock_qos_info_t)); - if (dhd->psk_qos == NULL) { - DHD_ERROR(("%s(): Failed to alloc psk_qos ! \n", __FUNCTION__)); - return BCME_NOMEM; - } - dhd->psk_qos->max_sock_fl = MAX_SOCK_FLOW; - sz = sizeof(struct dhd_sock_flow_info) * MAX_SOCK_FLOW; - dhd->psk_qos->sk_fl = MALLOCZ(dhd->pub.osh, sz); - if (dhd->psk_qos->sk_fl == NULL) { - DHD_ERROR(("%s(): Failed to allocated sk_fl \r\n", __FUNCTION__)); - return BCME_NOMEM; - } - - sk_fl = dhd->psk_qos->sk_fl; - for (i = 0; i < MAX_SOCK_FLOW; i++, sk_fl++) { - sk_fl->in_use = 0; - } - - dhd->psk_qos->sock_idle_thresh = SOCK_IDLE_THRESHOLD_MS; - - dhd->psk_qos->skfl_upgrade_thresh = SOCK_FLOW_UPGRADE_THRESHOLD; - - INIT_LIST_HEAD(&dhd->psk_qos->sk_fl_list_head); - dhd->psk_qos->list_lock = osl_spin_lock_init(dhd->pub.osh); - - dhd->psk_qos->watchdog_ms = watchdog_ms; - /* feature is DISABLED by default */ - dhd_sock_qos_set_status(dhd, 0); - - qos_algo_params_init(&dhd->psk_qos->qos_params); - - dhd->psk_qos->frmbrst_state = FRMBRST_ENABLED; - /* read the initial state of frameburst from FW, cannot - * assume that it will always be in enabled state by default. - * We will cache the FW frameburst state in host and change - * it everytime we change it from host during QoS upgrade. - * This decision is taken, because firing an iovar everytime - * to query FW frameburst state before deciding whether to - * changing the frameburst state or not from host, is sub-optimal, - * especially in the Tx path. - */ - ret = dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_FAKEFRAG, (char *)&val, - sizeof(val), FALSE, 0); - if (ret != BCME_OK) { - DHD_ERROR(("%s: get fw frameburst failed," - " err=%d\n", __FUNCTION__, ret)); - } else { - DHD_INFO(("%s:fw frameburst = %d", __FUNCTION__, val)); - dhd->psk_qos->frmbrst_state = - (val == 1) ? FRMBRST_ENABLED : FRMBRST_DISABLED; - } - return BCME_OK; -} - -int -dhd_deinit_sock_flows_buf(dhd_info_t *dhd) -{ - if (dhd == NULL) - return BCME_BADARG; - - if (dhd->psk_qos->sk_fl) { - MFREE(dhd->pub.osh, dhd->psk_qos->sk_fl, - sizeof(struct dhd_sock_flow_info) * MAX_SOCK_FLOW); - dhd->psk_qos->sk_fl = NULL; - } - - osl_spin_lock_deinit(dhd->pub.osh, dhd->psk_qos->list_lock); - MFREE(dhd->pub.osh, dhd->psk_qos, sizeof(dhd_sock_qos_info_t)); - dhd->psk_qos = NULL; - - return BCME_OK; -} - -/* Caller should hold list_lock */ -static inline struct dhd_sock_flow_info * -__dhd_find_sock_stream_info(dhd_sock_qos_info_t *psk_qos, unsigned long ino) -{ - struct dhd_sock_flow_info *sk_fl = NULL; -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - list_for_each_entry(sk_fl, &psk_qos->sk_fl_list_head, - list) { - if (sk_fl && (sk_fl->ino == ino)) { - return sk_fl; - } - } /* end of list iteration */ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - /* If control comes here, the ino is not found */ - DHD_INFO(("%s(): ino:%lu not found \r\n", __FUNCTION__, ino)); - - return NULL; -} - -static struct dhd_sock_flow_info * -dhd_alloc_sock_stream_info(dhd_sock_qos_info_t *psk_qos) -{ - struct dhd_sock_flow_info *sk_fl = psk_qos->sk_fl; - int i; - - for (i = 0; i < psk_qos->max_sock_fl; i++, sk_fl++) { - if (sk_fl->in_use == 0) { - DHD_ERROR(("%s: Use sk_fl %p \r\n", __FUNCTION__, sk_fl)); - return sk_fl; - } - } - DHD_INFO(("No Free Socket Stream info \r\n")); - return NULL; -} - -/* Caller should hold list_lock */ -static inline void -__dhd_free_sock_stream_info(dhd_sock_qos_info_t *psk_qos, - struct dhd_sock_flow_info *sk_fl) -{ - /* - * If the socket flow getting freed is an upgraded socket flow, - * we can upgrade one more flow. - */ - if (sk_fl->cur_up_state == 1) { - --psk_qos->num_skfl_upgraded; - ASSERT(psk_qos->num_skfl_upgraded >= 0); - } - - /* Remove the flow from active list */ - list_del(&sk_fl->list); - - DHD_ERROR(("%s(): Cleaning Socket Flow ino:%lu psk_qos->num_skfl_upgraded=%d\r\n", - __FUNCTION__, sk_fl->ino, psk_qos->num_skfl_upgraded)); - - /* Clear its content */ - memset_s(sk_fl, sizeof(*sk_fl), 0, sizeof(*sk_fl)); - - return; -} - -static void -dhd_clean_idle_sock_streams(dhd_sock_qos_info_t *psk_qos) -{ - struct dhd_sock_flow_info *sk_fl = NULL, *next = NULL; - u64 now; - u64 diff; - unsigned long flags = 0; - now = local_clock(); - - SK_FL_LIST_LOCK(psk_qos->list_lock, flags); - -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - list_for_each_entry_safe(sk_fl, next, &psk_qos->sk_fl_list_head, list) { - if (sk_fl) { - - if (sk_fl->in_use == 0) { - DHD_ERROR_RLMT(("%s:Something wrong," - " a free sk_fl living in active stream\n", - __FUNCTION__)); - DHD_ERROR_RLMT(("sk_fl:%p sk:%p ino:%lu \r\n", - sk_fl, sk_fl->sk, sk_fl->ino)); - continue; - } - - /* XXX: TODO: need to investigate properly in future. - * it is observed that in some hosts (FC25), the - * current timestamp is lesser than previous timestamp - * leading to false cleanups - */ - if (now <= sk_fl->last_pkt_ns) - continue; - - diff = now - sk_fl->last_pkt_ns; - - /* Convert diff which is in ns to ms */ - diff = div64_u64(diff, 1000000UL); - if (diff >= psk_qos->sock_idle_thresh) { - DHD_ERROR(("sk_fl->sk:%p sk_fl->i_no:%lu \r\n", - sk_fl->sk, sk_fl->ino)); - if (sk_fl->cur_up_state == 1 && - psk_qos->num_skfl_upgraded == 1) { - psk_qos->upgrade_active = FALSE; - } - __dhd_free_sock_stream_info(psk_qos, sk_fl); - } - } - } /* end of list iteration */ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - SK_FL_LIST_UNLOCK(psk_qos->list_lock, flags); - -} - -static inline int -__dhd_upgrade_sock_flow(dhd_info_t *dhd, - struct dhd_sock_flow_info *sk_fl, - struct sk_buff *skb) -{ - dhd_sock_qos_info_t *psk_qos = dhd->psk_qos; -#ifdef DHD_HP2P - dhd_pub_t *dhdp = &dhd->pub; -#endif - uint8 *pktdat = NULL; - struct ether_header *eh = NULL; - struct iphdr *iph = NULL; - - /* Before upgrading a flow, - * Check the bound to control the number of flows getting upgraded - */ - if ((sk_fl->rcm_up_state == 1) && (sk_fl->cur_up_state == 0)) { - if (psk_qos->num_skfl_upgraded >= psk_qos->skfl_upgrade_thresh) { - DHD_ERROR_RLMT(("%s(): Thresh hit num_skfl_upgraded:%d" - "skfl_upgrade_thresh:%d \r\n", - __FUNCTION__, psk_qos->num_skfl_upgraded, - psk_qos->skfl_upgrade_thresh)); - return BCME_ERROR; - } else { - if (psk_qos->num_skfl_upgraded == 0) { - /* if no flows upgraded till now, and this is the - * first flow to be upgraded, - * then disable frameburst in FW. - * The actual iovar to disable frameburst cannot - * be fired here because Tx can happen in atomic context - * and dhd_iovar can sleep due to proto_block lock being - * held. Instead the flag is checked from - * 'dhd_analyze_sock_flows' which execs in non-atomic context - * and the iovar is fired from there - */ - DHD_TRACE(("%s: disable frameburst ..", __FUNCTION__)); - psk_qos->upgrade_active = TRUE; - } - ++psk_qos->num_skfl_upgraded; - DHD_ERROR_RLMT(("%s(): upgrade flow sk_fl %p," - "num_skfl_upgraded:%d skfl_upgrade_thresh:%d \r\n", - __FUNCTION__, sk_fl, psk_qos->num_skfl_upgraded, - psk_qos->skfl_upgrade_thresh)); - } - } - - /* Upgrade the skb */ -#ifdef DHD_HP2P - if (dhdp->hp2p_capable) - skb->priority = TC_PRIO_CONTROL; - else - skb->priority = TC_PRIO_INTERACTIVE; -#else - skb->priority = TC_PRIO_INTERACTIVE; -#endif /* DHD_HP2P */ - - pktdat = PKTDATA(dhd->pub.osh, skb); - eh = (struct ether_header *) pktdat; - if (pktdat && (eh->ether_type == hton16(ETHER_TYPE_IP))) { - /* 'upgrade' DSCP also, else it is observed that on - * AP side if DSCP value is not in sync with L2 prio - * then out of order packets are observed - */ - iph = (struct iphdr *)(pktdat + sizeof(struct ether_header)); - iph->tos = DSCP_TOS_CS7; - /* re-compute ip hdr checksum - * NOTE: this takes around 1us, need to profile more - * accurately to get the number of cpu cycles it takes - * in order to get a better idea of the impact of - * re computing ip hdr chksum in data path - */ - ip_send_check(iph); - } - - /* Mark the Flow as 'upgraded' */ - if (sk_fl->cur_up_state == 0) - sk_fl->cur_up_state = 1; - - return BCME_OK; -} - -static inline int -__dhd_downgrade_sock_flow(dhd_info_t *dhd, - struct dhd_sock_flow_info *sk_fl, - struct sk_buff *skb) -{ - dhd_sock_qos_info_t *psk_qos = dhd->psk_qos; - - if ((sk_fl->rcm_up_state == 0) && (sk_fl->cur_up_state == 1)) { - /* sanity check */ - ASSERT(psk_qos->num_skfl_upgraded > 0); - if (psk_qos->num_skfl_upgraded <= 0) { - DHD_ERROR_RLMT(("%s(): FATAL ! no upgraded flows !\n", - __FUNCTION__)); - return BCME_ERROR; - } - - if (psk_qos->num_skfl_upgraded == 1) { - /* if this is the - * last flow to be downgraded, - * then re-enable frameburst in FW. - * The actual iovar to enable frameburst cannot - * be fired here because Tx can happen in atomic context - * and dhd_iovar can sleep due to proto_block lock being - * held. Instead the flag is checked from - * 'dhd_analyze_sock_flows' which execs in non-atomic context - * and the iovar is fired from there - */ - DHD_TRACE(("%s: enable frameburst ..", __FUNCTION__)); - psk_qos->upgrade_active = FALSE; - } - --psk_qos->num_skfl_upgraded; - DHD_ERROR_RLMT(("%s(): downgrade flow sk_fl %p," - "num_skfl_upgraded:%d \r\n", - __FUNCTION__, sk_fl, psk_qos->num_skfl_upgraded)); - } - - /* Mark the Flow as 'downgraded' */ - if (sk_fl->cur_up_state == 1) - sk_fl->cur_up_state = 0; - - return BCME_OK; -} - -/* - * Update the stats of a Socket flow. - * Create a new flow if need be. - * If a socket flow has been recommended for upgrade, do so. - */ -void -dhd_update_sock_flows(dhd_info_t *dhd, struct sk_buff *skb) -{ - struct sock *sk = NULL; - unsigned long ino = 0; - struct dhd_sock_flow_info *sk_fl = NULL; - dhd_sock_qos_info_t *psk_qos = NULL; - unsigned long flags = 0; - uint8 prio; - - BCM_REFERENCE(prio); - - if ((dhd == NULL) || (skb == NULL)) { - DHD_ERROR_RLMT(("%s: Invalid args \n", __FUNCTION__)); - return; - } - - /* If the Feature is disabled, return */ - if (dhd_sock_qos_get_status(dhd) == 0) - return; - - psk_qos = dhd->psk_qos; - sk = (struct sock *)PKTSOCK(dhd->pub.osh, skb); - - /* TODO: - * Some times sk is NULL, what does that mean ... - * is it a broadcast packet generated by Network Stack ???? - */ - if (sk == NULL) { - return; - } - ino = sock_i_ino(sk); - - /* TODO: - * List Lock need not be held for allocating sock stream .. optimize - */ - SK_FL_LIST_LOCK(psk_qos->list_lock, flags); - - sk_fl = __dhd_find_sock_stream_info(psk_qos, ino); - if (sk_fl == NULL) { - /* Allocate new sock stream */ - sk_fl = dhd_alloc_sock_stream_info(psk_qos); - if (sk_fl == NULL) { - SK_FL_LIST_UNLOCK(psk_qos->list_lock, flags); - goto done; - } - else { - /* SK Flow elements updated first time */ - sk_fl->in_use = 1; - sk_fl->sk = sk; - sk_fl->ino = ino; - /* TODO: Seeing a Kernel Warning ... check */ - /* sk_fl->uid = sock_i_uid(sk); */ - sk_fl->cur_up_state = 0; - list_add_tail(&sk_fl->list, &psk_qos->sk_fl_list_head); - DHD_ERROR(("%s(): skb %p sk %p sk_fl %p ino %lu" - " prio 0x%x \r\n", __FUNCTION__, skb, - sk, sk_fl, ino, skb->priority)); - } /* end of new sk flow allocation */ - } /* end of case when sk flow is found */ - - sk_fl->stats.tx_pkts++; - sk_fl->stats.tx_bytes += skb->len; - sk_fl->last_pkt_ns = local_clock(); - - SK_FL_LIST_UNLOCK(psk_qos->list_lock, flags); - - if (sk_fl->rcm_up_state == 1) { - __dhd_upgrade_sock_flow(dhd, sk_fl, skb); - } else { - __dhd_downgrade_sock_flow(dhd, sk_fl, skb); - } - - prio = PKTPRIO(skb); - DHD_INFO(("%s(): skb:%p skb->priority 0x%x prio %d sk_fl %p\r\n", __FUNCTION__, skb, - skb->priority, prio, sk_fl)); -done: - return; -} - -static int -dhd_change_frameburst_state(frameburst_state_t newstate, dhd_info_t *dhd) -{ - int ret = 0, val = 0; - dhd_sock_qos_info_t *psk_qos = NULL; - - if (!dhd) - return BCME_BADARG; - if (!dhd->psk_qos) - return BCME_BADARG; - - psk_qos = dhd->psk_qos; - - /* Check with the cached frameburst state on host - * instead of querying FW frameburst state. - * This decision is taken, because firing an iovar everytime - * to query FW frameburst state before deciding whether to - * changing the frameburst state or not is sub-optimal, - * especially in the Tx path. - */ - if (psk_qos->frmbrst_state == newstate) - return BCME_BADOPTION; - - val = (newstate == FRMBRST_ENABLED) ? 1 : 0; - ret = dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_FAKEFRAG, (char *)&val, - sizeof(val), TRUE, 0); - if (ret != BCME_OK) { - DHD_ERROR_RLMT(("%s: set frameburst=%d failed," - " err=%d\n", __FUNCTION__, val, ret)); - } else { - /* change the state */ - DHD_INFO(("%s: set frameburst=%d\n", __FUNCTION__, val)); - psk_qos->frmbrst_state = newstate; - } - - return ret; -} - -void dhd_analyze_sock_flows(dhd_info_t *dhd, uint32 watchdog_ms) -{ - struct dhd_sock_flow_info *sk_fl = NULL; - dhd_sock_qos_info_t *psk_qos = NULL; - unsigned long flags = 0; - - if (dhd == NULL) { - DHD_ERROR_RLMT(("%s: Bad argument \r\n", __FUNCTION__)); - return; - } - - /* Check whether the feature is disabled */ - if (dhd_sock_qos_get_status(dhd) == 0) - return; - - psk_qos = dhd->psk_qos; - - dhd_clean_idle_sock_streams(dhd->psk_qos); - - /* TODO: Plug in the QoS Algorithm here */ - SK_FL_LIST_LOCK(psk_qos->list_lock, flags); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - list_for_each_entry(sk_fl, &psk_qos->sk_fl_list_head, list) { - - sk_fl->rcm_up_state = dhd_qos_algo(dhd, &sk_fl->stats, &psk_qos->qos_params); - - /* TODO: Handle downgrades */ - - /* update sk_flow previous elements on every sampling interval */ - sk_fl->stats.tx_pkts_prev = sk_fl->stats.tx_pkts; - sk_fl->stats.tx_bytes_prev = sk_fl->stats.tx_bytes; - - /* TODO: Handle the condition where num_skfl_upgraded reaches the threshold */ - - /* TODO: Handle the condition where we upgrade all the socket flows - * of the uid on which one flow is detected to be upgraded. - */ - - } /* end of list iteration */ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - SK_FL_LIST_UNLOCK(psk_qos->list_lock, flags); - - /* disable frameburst in FW on the first flow upgraded */ - if (psk_qos->upgrade_active) { - dhd_change_frameburst_state(FRMBRST_DISABLED, dhd); - } else { - /* if no upgraded flows remain, either after cleanup, - * or after a downgrade, - * then re-enable frameburst in FW - */ - dhd_change_frameburst_state(FRMBRST_ENABLED, dhd); - } - - return; -} - -void dhd_sock_qos_update_bus_flowid(dhd_info_t *dhd, void *pktbuf, - uint32 bus_flow_id) -{ - BCM_REFERENCE(dhd); - BCM_REFERENCE(pktbuf); - BCM_REFERENCE(bus_flow_id); - return; -} - -/* ================= Sysfs interfce support functions ======================== */ - -unsigned long dhd_sock_qos_get_status(dhd_info_t *dhd) -{ - if (dhd == NULL) - return 0; - - return (atomic_read(&dhd->psk_qos->on_off)); -} - -void dhd_sock_qos_set_status(dhd_info_t *dhd, unsigned long on_off) -{ - if (dhd == NULL) - return; - - atomic_set(&dhd->psk_qos->on_off, on_off); - if (on_off) { - dhd_watchdog_ms = QOS_SAMPLING_INTVL_MS; - /* enable watchdog to monitor the socket flows */ - dhd_os_wd_timer(&dhd->pub, QOS_SAMPLING_INTVL_MS); - } else { - dhd_watchdog_ms = dhd->psk_qos->watchdog_ms; - /* disable watchdog or set it back to the original value */ - dhd_os_wd_timer(&dhd->pub, dhd->psk_qos->watchdog_ms); - } - return; -} - -ssize_t dhd_sock_qos_show_stats(dhd_info_t *dhd, char *buf, - ssize_t sz) -{ - dhd_sock_qos_info_t *psk_qos = NULL; - struct dhd_sock_flow_info *sk_fl = NULL; - unsigned long flags = 0; - ssize_t ret = 0; - char *p = buf; - - /* TODO: Should be actual record length */ - unsigned long rec_len = 100; - - if (dhd == NULL) - return -1; - - psk_qos = dhd->psk_qos; - - ret += scnprintf(p, sz-ret-1, "\nino\t sk\t\t\t tx_pkts\t tx_bytes\t" - "last_pkt_ns\r\n"); - p += ret; - - SK_FL_LIST_LOCK(psk_qos->list_lock, flags); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - list_for_each_entry(sk_fl, &psk_qos->sk_fl_list_head, list) { - /* Protect the buffer from over run */ - if (ret + rec_len >= sz) - break; - - ret += scnprintf(p, sz-ret-1, "%lu\t %p\t %lu\t %lu\t %llu\t \r\n", - sk_fl->ino, sk_fl->sk, sk_fl->stats.tx_pkts, sk_fl->stats.tx_bytes, - sk_fl->last_pkt_ns); - - p += ret; - - } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - SK_FL_LIST_UNLOCK(psk_qos->list_lock, flags); - - return ret + 1; -} - -void dhd_sock_qos_clear_stats(dhd_info_t *dhd) -{ - dhd_sock_qos_info_t *psk_qos = NULL; - struct dhd_sock_flow_info *sk_fl = NULL; - unsigned long flags = 0; - - if (dhd == NULL) - return; - - psk_qos = dhd->psk_qos; - - SK_FL_LIST_LOCK(psk_qos->list_lock, flags); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - list_for_each_entry(sk_fl, &psk_qos->sk_fl_list_head, list) { - sk_fl->stats.tx_pkts = 0; - sk_fl->stats.tx_bytes = 0; - sk_fl->stats.tx_pkts_prev = 0; - sk_fl->stats.tx_bytes_prev = 0; - sk_fl->last_pkt_ns = 0; - } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - SK_FL_LIST_UNLOCK(psk_qos->list_lock, flags); - - return; -} - -unsigned long dhd_sock_qos_get_force_upgrade(dhd_info_t *dhd) -{ - if (dhd == NULL) - return 0; - - return (atomic_read(&dhd->psk_qos->force_upgrade)); -} - -void dhd_sock_qos_set_force_upgrade(dhd_info_t *dhd, unsigned long force_upgrade) -{ - if (dhd == NULL) - return; - - atomic_set(&dhd->psk_qos->force_upgrade, force_upgrade); - return; -} - -int dhd_sock_qos_get_numfl_upgrd_thresh(dhd_info_t *dhd) -{ - if (dhd == NULL) - return 0; - - return dhd->psk_qos->skfl_upgrade_thresh; -} - -void dhd_sock_qos_set_numfl_upgrd_thresh(dhd_info_t *dhd, - int upgrade_thresh) -{ - if (dhd == NULL) - return; - - dhd->psk_qos->skfl_upgrade_thresh = upgrade_thresh; - return; -} - -void dhd_sock_qos_get_avgpktsize_thresh(dhd_info_t *dhd, - unsigned long *avgpktsize_low, - unsigned long *avgpktsize_high) -{ - qos_algo_params_t *pqos_params = NULL; - - if (dhd == NULL || avgpktsize_low == NULL || - avgpktsize_high == NULL) { - return; - } - - pqos_params = QOS_PARAMS(dhd); - *avgpktsize_low = pqos_params->avg_pkt_size_low_thresh; - *avgpktsize_high = pqos_params->avg_pkt_size_high_thresh; - return; -} - -void dhd_sock_qos_set_avgpktsize_thresh(dhd_info_t *dhd, - unsigned long avgpktsize_low, - unsigned long avgpktsize_high) -{ - qos_algo_params_t *pqos_params = NULL; - - if (dhd == NULL) - return; - - pqos_params = QOS_PARAMS(dhd); - pqos_params->avg_pkt_size_low_thresh = avgpktsize_low; - pqos_params->avg_pkt_size_high_thresh = avgpktsize_high; - return; -} - -void dhd_sock_qos_get_numpkts_thresh(dhd_info_t *dhd, - unsigned long *numpkts_low, - unsigned long *numpkts_high) -{ - qos_algo_params_t *pqos_params = NULL; - - if (dhd == NULL || numpkts_low == NULL || - numpkts_high == NULL) { - return; - } - - pqos_params = QOS_PARAMS(dhd); - *numpkts_low = pqos_params->num_pkts_low_thresh; - *numpkts_high = pqos_params->num_pkts_high_thresh; -} - -void dhd_sock_qos_set_numpkts_thresh(dhd_info_t *dhd, - unsigned long numpkts_low, - unsigned long numpkts_high) -{ - qos_algo_params_t *pqos_params = NULL; - - if (dhd == NULL) - return; - pqos_params = QOS_PARAMS(dhd); - pqos_params->num_pkts_low_thresh = numpkts_low; - pqos_params->num_pkts_high_thresh = numpkts_high; - return; -} - -void dhd_sock_qos_get_detectcnt_thresh(dhd_info_t *dhd, - unsigned char *detectcnt_inc, - unsigned char *detectcnt_dec) -{ - qos_algo_params_t *pqos_params = NULL; - - if (dhd == NULL || detectcnt_inc == NULL || - detectcnt_dec == NULL) { - return; - } - - pqos_params = QOS_PARAMS(dhd); - *detectcnt_inc = pqos_params->detect_cnt_inc_thresh; - *detectcnt_dec = pqos_params->detect_cnt_dec_thresh; -} - -void dhd_sock_qos_set_detectcnt_thresh(dhd_info_t *dhd, - unsigned char detectcnt_inc, - unsigned char detectcnt_dec) -{ - qos_algo_params_t *pqos_params = NULL; - - if (dhd == NULL) - return; - - pqos_params = QOS_PARAMS(dhd); - pqos_params->detect_cnt_inc_thresh = detectcnt_inc; - pqos_params->detect_cnt_dec_thresh = detectcnt_dec; - return; -} - -int dhd_sock_qos_get_detectcnt_upgrd_thresh(dhd_info_t *dhd) -{ - qos_algo_params_t *pqos_params = NULL; - - if (dhd == NULL) - return 0; - - pqos_params = QOS_PARAMS(dhd); - return pqos_params->detect_cnt_upgrade_thresh; -} - -void dhd_sock_qos_set_detectcnt_upgrd_thresh(dhd_info_t *dhd, - unsigned char detect_upgrd_thresh) -{ - qos_algo_params_t *pqos_params = NULL; - - if (dhd == NULL) - return; - - pqos_params = QOS_PARAMS(dhd); - pqos_params->detect_cnt_upgrade_thresh = detect_upgrd_thresh; -} - -int dhd_sock_qos_get_maxfl(dhd_info_t *dhd) -{ - if (dhd == NULL) - return 0; - - return dhd->psk_qos->max_sock_fl; -} - -void dhd_sock_qos_set_maxfl(dhd_info_t *dhd, - unsigned int maxfl) -{ - if (dhd == NULL) - return; - - dhd->psk_qos->max_sock_fl = maxfl; -} -/* ================= End of Sysfs interfce support functions ======================== */ - -/* ================= QOS Algorithm ======================== */ - -/* - * Operates on a flow and returns 1 for upgrade and 0 for - * no up-grade - Has the potential of moving into a separate file - * Takes the dhd pointer too in case if it has to access any platform - * functions like MALLOC that takes dhd->pub.osh as argument. - */ -int dhd_qos_algo(dhd_info_t *dhd, qos_stat_t *qos, qos_algo_params_t *pqos_params) -{ - unsigned long tx_bytes, tx_pkts, tx_avg_pkt_size; - - if (!dhd || !qos || !pqos_params) { - return 0; - } - - /* if the user has set the sysfs variable to force upgrade */ - if (atomic_read(&dhd->psk_qos->force_upgrade) == 1) { - return 1; - } - - DHD_TRACE(("%s(): avgpktsize_thrsh %lu:%lu; " - "numpkts_thrs %lu:%lu; detectcnt_thrs %d:%d;" - " detectcnt_upgrd_thrs %d\n", __FUNCTION__, - pqos_params->avg_pkt_size_low_thresh, - pqos_params->avg_pkt_size_high_thresh, - pqos_params->num_pkts_low_thresh, - pqos_params->num_pkts_high_thresh, - pqos_params->detect_cnt_inc_thresh, - pqos_params->detect_cnt_dec_thresh, - pqos_params->detect_cnt_upgrade_thresh)); - - tx_bytes = qos->tx_bytes - qos->tx_bytes_prev; - tx_pkts = qos->tx_pkts - qos->tx_pkts_prev; - if ((tx_bytes == 0) || (tx_pkts == 0)) { - return 0; - } - - tx_avg_pkt_size = tx_bytes / tx_pkts; - - if ((tx_avg_pkt_size > pqos_params->avg_pkt_size_low_thresh) && - (tx_avg_pkt_size < pqos_params->avg_pkt_size_high_thresh) && - (tx_pkts > pqos_params->num_pkts_low_thresh) && - (tx_pkts < pqos_params->num_pkts_high_thresh)) { - if (qos->lowlat_detect_count < pqos_params->detect_cnt_inc_thresh) { - qos->lowlat_detect_count++; - } - } else if (qos->lowlat_detect_count > pqos_params->detect_cnt_dec_thresh) { - qos->lowlat_detect_count--; - } - - if (qos->lowlat_detect_count > pqos_params->detect_cnt_upgrade_thresh) { - qos->lowlat_flow = TRUE; - } else if (qos->lowlat_detect_count == 0) { - qos->lowlat_flow = FALSE; - } - - DHD_TRACE(("%s(): TX:%lu:%lu:%lu, PUBG:%d::%d\n", - __FUNCTION__, tx_avg_pkt_size, tx_bytes, tx_pkts, - qos->lowlat_detect_count, qos->lowlat_flow)); - - return (qos->lowlat_flow == TRUE) ? 1 : 0; -} - -int qos_algo_params_init(qos_algo_params_t *pqos_params) -{ - if (!pqos_params) - return BCME_BADARG; - - memset(pqos_params, 0, sizeof(*pqos_params)); - pqos_params->avg_pkt_size_low_thresh = LOWLAT_AVG_PKT_SIZE_LOW; - pqos_params->avg_pkt_size_high_thresh = LOWLAT_AVG_PKT_SIZE_HIGH; - pqos_params->num_pkts_low_thresh = LOWLAT_NUM_PKTS_LOW; - pqos_params->num_pkts_high_thresh = LOWLAT_NUM_PKTS_HIGH; - pqos_params->detect_cnt_inc_thresh = LOWLAT_DETECT_CNT_INC_THRESH; - pqos_params->detect_cnt_dec_thresh = LOWLAT_DETECT_CNT_DEC_THRESH; - pqos_params->detect_cnt_upgrade_thresh = LOWLAT_DETECT_CNT_UPGRADE_THRESH; - - return BCME_OK; -} -/* ================= End of QOS Algorithm ======================== */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sock_qos.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sock_qos.h old mode 100755 new mode 100644 index 641469df623e..f6745d80c1c1 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sock_qos.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_sock_qos.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes to call into * DHD's QOS on Socket Flow module. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -32,87 +32,45 @@ struct dhd_sock_flow_info; -#if defined(DHD_QOS_ON_SOCK_FLOW) -#define QOS_SAMPLING_INTVL_MS 100 -/* Feature Enabed original implementation */ -int dhd_init_sock_flows_buf(dhd_info_t *dhd, uint watchdog_ms); -int dhd_deinit_sock_flows_buf(dhd_info_t *dhd); -void dhd_update_sock_flows(dhd_info_t *dhd, struct sk_buff *skb); -void dhd_analyze_sock_flows(dhd_info_t *dhd, uint32 watchdog_ms); - -/* sysfs call backs */ -unsigned long dhd_sock_qos_get_status(dhd_info_t *dhd); -void dhd_sock_qos_set_status(dhd_info_t *dhd, unsigned long on_off); -ssize_t dhd_sock_qos_show_stats(dhd_info_t *dhd, char *buf, ssize_t sz); -void dhd_sock_qos_clear_stats(dhd_info_t *dhd); -unsigned long dhd_sock_qos_get_force_upgrade(dhd_info_t *dhd); -void dhd_sock_qos_set_force_upgrade(dhd_info_t *dhd, unsigned long force_upgrade); -int dhd_sock_qos_get_numfl_upgrd_thresh(dhd_info_t *dhd); -void dhd_sock_qos_set_numfl_upgrd_thresh(dhd_info_t *dhd, int upgrade_thresh); -void dhd_sock_qos_get_avgpktsize_thresh(dhd_info_t *dhd, - unsigned long *avgpktsize_low, - unsigned long *avgpktsize_high); -void dhd_sock_qos_set_avgpktsize_thresh(dhd_info_t *dhd, - unsigned long avgpktsize_low, - unsigned long avgpktsize_high); -void dhd_sock_qos_get_numpkts_thresh(dhd_info_t *dhd, - unsigned long *numpkts_low, - unsigned long *numpkts_high); -void dhd_sock_qos_set_numpkts_thresh(dhd_info_t *dhd, - unsigned long numpkts_low, - unsigned long numpkts_high); -void dhd_sock_qos_get_detectcnt_thresh(dhd_info_t *dhd, - unsigned char *detectcnt_inc, - unsigned char *detectcnt_dec); -void dhd_sock_qos_set_detectcnt_thresh(dhd_info_t *dhd, - unsigned char detectcnt_inc, - unsigned char detectcnt_dec); -int dhd_sock_qos_get_detectcnt_upgrd_thresh(dhd_info_t *dhd); -void dhd_sock_qos_set_detectcnt_upgrd_thresh(dhd_info_t *dhd, - unsigned char detect_upgrd_thresh); -int dhd_sock_qos_get_maxfl(dhd_info_t *dhd); -void dhd_sock_qos_set_maxfl(dhd_info_t *dhd, unsigned int maxfl); - -/* Update from Bus Layer */ -void dhd_sock_qos_update_bus_flowid(dhd_info_t *dhd, void *pktbuf, - uint32 bus_flow_id); - -#else /* Feature Disabled dummy implementations */ -inline int dhd_init_sock_flows_buf(dhd_info_t *dhd, uint watchdog_ms) +static inline int +dhd_init_sock_flows_buf(dhd_info_t *dhd, uint watchdog_ms) { BCM_REFERENCE(dhd); return BCME_UNSUPPORTED; } -inline int dhd_deinit_sock_flows_buf(dhd_info_t *dhd) +static inline int +dhd_deinit_sock_flows_buf(dhd_info_t *dhd) { BCM_REFERENCE(dhd); return BCME_UNSUPPORTED; } -inline void dhd_update_sock_flows(dhd_info_t *dhd, struct sk_buff *skb) +static inline void +dhd_update_sock_flows(dhd_info_t *dhd, struct sk_buff *skb) { BCM_REFERENCE(dhd); BCM_REFERENCE(skb); return; } -inline void dhd_analyze_sock_flows(dhd_info_t *dhd, uint32 watchdog_ms) +static inline void +dhd_analyze_sock_flows(dhd_info_t *dhd, uint32 watchdog_ms) { BCM_REFERENCE(dhd); BCM_REFERENCE(dhd_watchdog_ms); return; } -inline void dhd_sock_qos_update_bus_flowid(dhd_info_t *dhd, void *pktbuf, +static inline void +dhd_sock_qos_update_bus_flowid(dhd_info_t *dhd, void *pktbuf, uint32 bus_flow_id) { BCM_REFERENCE(dhd); BCM_REFERENCE(pktbuf); BCM_REFERENCE(bus_flow_id); } -#endif /* End of !DHD_QOS_ON_SOCK_FLOW */ #endif /* _DHD_LINUX_TPA_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_tx.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_tx.c new file mode 100644 index 000000000000..fc3b2e64bb07 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_tx.c @@ -0,0 +1,1290 @@ +/* + * Broadcom Dongle Host Driver (DHD), + * Linux-specific network interface for transmit(tx) path + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + * + * $Id$ + */ + +#include +#include +#include +#ifdef SHOW_LOGTRACE +#include +#include +#endif /* SHOW_LOGTRACE */ + +#ifdef PCIE_FULL_DONGLE +#include +#endif /* PCIE_FULL_DONGLE */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_TIZEN) +#include +#endif /* CONFIG_TIZEN */ +#include +#ifdef ENABLE_ADAPTIVE_SCHED +#include +#endif /* ENABLE_ADAPTIVE_SCHED */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include /* need to still support chips no longer in trunk firmware */ +#include +#include + +#include +#include +#include +#include <802.3.h> + +#include +#include +#include +#include +#ifdef DHD_WET +#include +#endif /* DHD_WET */ +#ifdef PCIE_FULL_DONGLE +#include +#endif +#include +#include +#include +#include +#include +#if defined(WL_CFG80211) +#include +#ifdef WL_BAM +#include +#endif /* WL_BAM */ +#endif /* WL_CFG80211 */ +#ifdef PNO_SUPPORT +#include +#endif +#ifdef RTT_SUPPORT +#include +#endif + +#include + +#ifdef CONFIG_COMPAT +#include +#endif + +#ifdef DHD_WMF +#include +#endif /* DHD_WMF */ + +#ifdef DHD_L2_FILTER +#include +#include +#include +#endif /* DHD_L2_FILTER */ + +#ifdef DHD_PSTA +#include +#endif /* DHD_PSTA */ + +#ifdef AMPDU_VO_ENABLE +/* XXX: Enabling VO AMPDU to reduce FER */ +#include <802.1d.h> +#endif /* AMPDU_VO_ENABLE */ + +#if defined(DHDTCPACK_SUPPRESS) || defined(DHDTCPSYNC_FLOOD_BLK) +#include +#endif /* DHDTCPACK_SUPPRESS || DHDTCPSYNC_FLOOD_BLK */ +#include +#ifdef DHD_PKT_LOGGING +#include +#endif /* DHD_PKT_LOGGING */ +#ifdef DHD_4WAYM4_FAIL_DISCONNECT +#include +#endif /* DHD_4WAYM4_FAIL_DISCONNECT */ + +#ifdef ENABLE_DHD_GRO +#include +#endif /* ENABLE_DHD_GRO */ + +#ifdef FIX_CPU_MIN_CLOCK +#include +#endif /* FIX_CPU_MIN_CLOCK */ + +#ifdef PROP_TXSTATUS +#include +#include +#endif + +#if defined(OEM_ANDROID) +#include +#endif +#include + +#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]] + +void +dhd_tx_stop_queues(struct net_device *net) +{ +#ifdef DHD_MQ + netif_tx_stop_all_queues(net); +#else + netif_stop_queue(net); +#endif +} + +void +dhd_tx_start_queues(struct net_device *net) +{ +#ifdef DHD_MQ + netif_tx_wake_all_queues(net); +#else + netif_wake_queue(net); +#endif +} + +int +BCMFASTPATH(__dhd_sendpkt)(dhd_pub_t *dhdp, int ifidx, void *pktbuf) +{ + int ret = BCME_OK; + dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + struct ether_header *eh = NULL; + uint8 pkt_flow_prio; + dhd_if_t *ifp; + unsigned long flags; + uint datalen; + + DHD_GENERAL_LOCK(dhdp, flags); + ifp = dhd_get_ifp(dhdp, ifidx); + if (!ifp || ifp->del_in_progress) { + DHD_ERROR(("%s: ifp:%p del_in_progress:%d\n", + __FUNCTION__, ifp, ifp ? ifp->del_in_progress : 0)); + DHD_GENERAL_UNLOCK(dhdp, flags); + PKTCFREE(dhdp->osh, pktbuf, TRUE); + return -ENODEV; + } + DHD_GENERAL_UNLOCK(dhdp, flags); + + /* Reject if down */ + if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { + /* free the packet here since the caller won't */ + PKTCFREE(dhdp->osh, pktbuf, TRUE); + return -ENODEV; + } + +#ifdef PCIE_FULL_DONGLE + if (dhdp->busstate == DHD_BUS_SUSPEND) { + DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); + PKTCFREE(dhdp->osh, pktbuf, TRUE); + return NETDEV_TX_BUSY; + } +#endif /* PCIE_FULL_DONGLE */ + + /* Reject if pktlen > MAX_MTU_SZ */ + if (PKTLEN(dhdp->osh, pktbuf) > MAX_MTU_SZ) { + /* free the packet here since the caller won't */ + dhdp->tx_big_packets++; + PKTCFREE(dhdp->osh, pktbuf, TRUE); + return BCME_ERROR; + } + + datalen = PKTLEN(dhdp->osh, pktbuf); + +#ifdef DHD_L2_FILTER + /* if dhcp_unicast is enabled, we need to convert the */ + /* broadcast DHCP ACK/REPLY packets to Unicast. */ + if (ifp->dhcp_unicast) { + uint8* mac_addr; + uint8* ehptr = NULL; + int ret; + ret = bcm_l2_filter_get_mac_addr_dhcp_pkt(dhdp->osh, pktbuf, ifidx, &mac_addr); + if (ret == BCME_OK) { + /* if given mac address having valid entry in sta list + * copy the given mac address, and return with BCME_OK + */ + if (dhd_find_sta(dhdp, ifidx, mac_addr)) { + ehptr = PKTDATA(dhdp->osh, pktbuf); + bcopy(mac_addr, ehptr + ETHER_DEST_OFFSET, ETHER_ADDR_LEN); + } + } + } + + if (ifp->grat_arp && DHD_IF_ROLE_AP(dhdp, ifidx)) { + if (bcm_l2_filter_gratuitous_arp(dhdp->osh, pktbuf) == BCME_OK) { + PKTCFREE(dhdp->osh, pktbuf, TRUE); + return BCME_ERROR; + } + } + + if (ifp->parp_enable && DHD_IF_ROLE_AP(dhdp, ifidx)) { + ret = dhd_l2_filter_pkt_handle(dhdp, ifidx, pktbuf, TRUE); + + /* Drop the packets if l2 filter has processed it already + * otherwise continue with the normal path + */ + if (ret == BCME_OK) { + PKTCFREE(dhdp->osh, pktbuf, TRUE); + return BCME_ERROR; + } + } +#endif /* DHD_L2_FILTER */ + /* Update multicast statistic */ + if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { + uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); + eh = (struct ether_header *)pktdata; + + if (ETHER_ISMULTI(eh->ether_dhost)) + dhdp->tx_multicast++; + if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) { +#ifdef DHD_LOSSLESS_ROAMING + uint8 prio = (uint8)PKTPRIO(pktbuf); + + /* back up 802.1x's priority */ + dhdp->prio_8021x = prio; +#endif /* DHD_LOSSLESS_ROAMING */ + DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED); + atomic_inc(&dhd->pend_8021x_cnt); +#if defined(WL_CFG80211) && defined(WL_WPS_SYNC) + wl_handle_wps_states(dhd_idx2net(dhdp, ifidx), + pktdata, PKTLEN(dhdp->osh, pktbuf), TRUE); +#endif /* WL_CFG80211 && WL_WPS_SYNC */ +#ifdef EAPOL_RESEND + wl_ext_backup_eapol_txpkt(dhdp, ifidx, pktbuf); +#endif /* EAPOL_RESEND */ + } + dhd_dump_pkt(dhdp, ifidx, pktdata, + (uint32)PKTLEN(dhdp->osh, pktbuf), TRUE, NULL, NULL); + } else { + PKTCFREE(dhdp->osh, pktbuf, TRUE); + return BCME_ERROR; + } + +#if (defined(BCM_ROUTER_DHD) && defined(QOS_MAP_SET)) + if (ifp->qosmap_up_table_enable) { + pktsetprio_qms(pktbuf, ifp->qosmap_up_table, FALSE); + } + else +#endif + { + /* Look into the packet and update the packet priority */ +#ifndef PKTPRIO_OVERRIDE + /* XXX RB:6270 Ignore skb->priority from TCP/IP stack */ + if (PKTPRIO(pktbuf) == 0) +#endif /* !PKTPRIO_OVERRIDE */ + { +#if (!defined(BCM_ROUTER_DHD) && (defined(QOS_MAP_SET) || \ + defined(WL_CUSTOM_MAPPING_OF_DSCP))) + u8 *up_table = wl_get_up_table(dhdp, ifidx); + pktsetprio_qms(pktbuf, up_table, FALSE); + if (PKTPRIO(pktbuf) > MAXPRIO) { + DHD_ERROR_RLMT(("wrong user prio:%d from qosmap ifidx:%d\n", + PKTPRIO(pktbuf), ifidx)); + if (up_table) { + prhex("up_table", up_table, UP_TABLE_MAX); + } + } +#else + /* For LLR, pkt prio will be changed to 7(NC) here */ + pktsetprio(pktbuf, FALSE); +#endif /* QOS_MAP_SET || WL_CUSTOM_MAPPING_OF_DSCP */ + } +#ifndef PKTPRIO_OVERRIDE + else { + /* Some protocols like OZMO use priority values from 256..263. + * these are magic values to indicate a specific 802.1d priority. + * make sure that priority field is in range of 0..7 + */ + PKTSETPRIO(pktbuf, PKTPRIO(pktbuf) & 0x7); + } +#endif /* !PKTPRIO_OVERRIDE */ + } + +#if defined(BCM_ROUTER_DHD) + traffic_mgmt_pkt_set_prio(dhdp, pktbuf); + +#endif /* BCM_ROUTER_DHD */ + + BCM_REFERENCE(pkt_flow_prio); + /* Intercept and create Socket level statistics */ + /* + * TODO: Some how moving this code block above the pktsetprio code + * is resetting the priority back to 0, but this does not happen for + * packets generated from iperf uisng -S option. Can't understand why. + */ + dhd_update_sock_flows(dhd, pktbuf); + +#ifdef SUPPORT_SET_TID + dhd_set_tid_based_on_uid(dhdp, pktbuf); +#endif /* SUPPORT_SET_TID */ + +#ifdef PCIE_FULL_DONGLE + /* + * Lkup the per interface hash table, for a matching flowring. If one is not + * available, allocate a unique flowid and add a flowring entry. + * The found or newly created flowid is placed into the pktbuf's tag. + */ + +#ifdef DHD_TX_PROFILE + if (dhdp->tx_profile_enab && dhdp->num_profiles > 0 && + dhd_protocol_matches_profile(PKTDATA(dhdp->osh, pktbuf), + PKTLEN(dhdp->osh, pktbuf), dhdp->protocol_filters, + dhdp->host_sfhllc_supported)) { + /* we only have support for one tx_profile at the moment */ + + /* tagged packets must be put into TID 6 */ + PKTSETPRIO(pktbuf, PRIO_8021D_VO); + } +#endif /* defined(DHD_TX_PROFILE) */ + + if (PKTPRIO(pktbuf) > MAXPRIO) { + DHD_ERROR_RLMT(("Wrong user prio:%d ifidx:%d\n", PKTPRIO(pktbuf), ifidx)); + /* non-assert build, print ratelimit error, free packet and exit */ + ASSERT(0); + PKTCFREE(dhd->pub.osh, pktbuf, TRUE); + return BCME_ERROR; + } + + pkt_flow_prio = dhdp->flow_prio_map[(PKTPRIO(pktbuf))]; + + ret = dhd_flowid_update(dhdp, ifidx, pkt_flow_prio, pktbuf); + if (ret != BCME_OK) { + PKTCFREE(dhd->pub.osh, pktbuf, TRUE); + return ret; + } +#endif /* PCIE_FULL_DONGLE */ + /* terence 20150901: Micky add to ajust the 802.1X priority */ + /* Set the 802.1X packet with the highest priority 7 */ + if (dhdp->conf->pktprio8021x >= 0) + pktset8021xprio(pktbuf, dhdp->conf->pktprio8021x); + +#ifdef PROP_TXSTATUS + if (dhd_wlfc_is_supported(dhdp)) { + /* store the interface ID */ + DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx); + + /* store destination MAC in the tag as well */ + DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost); + + /* decide which FIFO this packet belongs to */ + if (ETHER_ISMULTI(eh->ether_dhost)) + /* one additional queue index (highest AC + 1) is used for bc/mc queue */ + DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT); + else + DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf))); + } else +#endif /* PROP_TXSTATUS */ + { + /* If the protocol uses a data header, apply it */ + dhd_prot_hdrpush(dhdp, ifidx, pktbuf); + } + + /* Use bus module to send data frame */ +#ifdef PROP_TXSTATUS + { + if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata, + dhdp->bus, pktbuf, TRUE) == WLFC_UNSUPPORTED) { + /* non-proptxstatus way */ +#ifdef BCMPCIE + ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); +#else + ret = dhd_bus_txdata(dhdp->bus, pktbuf); +#endif /* BCMPCIE */ + } + } +#else +#ifdef BCMPCIE + ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); +#else + ret = dhd_bus_txdata(dhdp->bus, pktbuf); +#endif /* BCMPCIE */ +#endif /* PROP_TXSTATUS */ + + /* Update the packet counters here, as it is called for LB Tx and non-LB Tx too */ + if (ret) { +#ifdef BCMDBUS + PKTCFREE(dhdp->osh, pktbuf, TRUE); +#endif /* BCMDBUS */ + ifp->stats.tx_dropped++; + dhdp->tx_dropped++; + } else { +#ifdef PROP_TXSTATUS + /* tx_packets counter can counted only when wlfc is disabled */ + if (!dhd_wlfc_is_supported(dhdp)) +#endif + { + dhdp->tx_packets++; + dhdp->tx_bytes += datalen; + ifp->stats.tx_packets++; + ifp->stats.tx_bytes += datalen; + } + dhdp->actual_tx_pkts++; + } + + return ret; +} + +int +BCMFASTPATH(dhd_sendpkt)(dhd_pub_t *dhdp, int ifidx, void *pktbuf) +{ + int ret = 0; + unsigned long flags; + dhd_if_t *ifp; + + DHD_GENERAL_LOCK(dhdp, flags); + ifp = dhd_get_ifp(dhdp, ifidx); + if (!ifp || ifp->del_in_progress) { + DHD_ERROR(("%s: ifp:%p del_in_progress:%d\n", + __FUNCTION__, ifp, ifp ? ifp->del_in_progress : 0)); + DHD_GENERAL_UNLOCK(dhdp, flags); + PKTCFREE(dhdp->osh, pktbuf, TRUE); + return -ENODEV; + } + if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp)) { + DHD_ERROR(("%s: returning as busstate=%d\n", + __FUNCTION__, dhdp->busstate)); + DHD_GENERAL_UNLOCK(dhdp, flags); + PKTCFREE(dhdp->osh, pktbuf, TRUE); + return -ENODEV; + } + DHD_IF_SET_TX_ACTIVE(ifp, DHD_TX_SEND_PKT); + DHD_BUS_BUSY_SET_IN_SEND_PKT(dhdp); + DHD_GENERAL_UNLOCK(dhdp, flags); + + DHD_GENERAL_LOCK(dhdp, flags); + if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp)) { + DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", + __FUNCTION__, dhdp->busstate, dhdp->dhd_bus_busy_state)); + DHD_BUS_BUSY_CLEAR_IN_SEND_PKT(dhdp); + DHD_IF_CLR_TX_ACTIVE(ifp, DHD_TX_SEND_PKT); + dhd_os_tx_completion_wake(dhdp); + dhd_os_busbusy_wake(dhdp); + DHD_GENERAL_UNLOCK(dhdp, flags); + PKTCFREE(dhdp->osh, pktbuf, TRUE); + return -ENODEV; + } + DHD_GENERAL_UNLOCK(dhdp, flags); + + ret = __dhd_sendpkt(dhdp, ifidx, pktbuf); + + DHD_GENERAL_LOCK(dhdp, flags); + DHD_BUS_BUSY_CLEAR_IN_SEND_PKT(dhdp); + DHD_IF_CLR_TX_ACTIVE(ifp, DHD_TX_SEND_PKT); + dhd_os_tx_completion_wake(dhdp); + dhd_os_busbusy_wake(dhdp); + DHD_GENERAL_UNLOCK(dhdp, flags); + return ret; +} + +#ifdef DHD_MQ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +static uint16 +BCMFASTPATH(dhd_select_queue)(struct net_device *net, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback) +#else +static uint16 +BCMFASTPATH(dhd_select_queue)(struct net_device *net, struct sk_buff *skb) +#endif /* LINUX_VERSION_CODE */ +{ + dhd_info_t *dhd_info = DHD_DEV_INFO(net); + dhd_pub_t *dhdp = &dhd_info->pub; + uint16 prio = 0; + + BCM_REFERENCE(dhd_info); + BCM_REFERENCE(dhdp); + BCM_REFERENCE(prio); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + if (mq_select_disable) { + /* if driver side queue selection is disabled via sysfs, call the kernel + * supplied fallback function to select the queue, which is usually + * '__netdev_pick_tx()' in net/core/dev.c + */ + return fallback(net, skb); + } +#endif /* LINUX_VERSION */ + + prio = dhdp->flow_prio_map[skb->priority]; + if (prio < AC_COUNT) + return prio; + else + return AC_BK; +} +#endif /* DHD_MQ */ + +netdev_tx_t +BCMFASTPATH(dhd_start_xmit)(struct sk_buff *skb, struct net_device *net) +{ + int ret; + void *pktbuf; + dhd_info_t *dhd = DHD_DEV_INFO(net); + dhd_if_t *ifp = NULL; + int ifidx; + unsigned long flags; +#if !defined(BCM_ROUTER_DHD) + uint8 htsfdlystat_sz = 0; +#endif /* ! BCM_ROUTER_DHD */ +#ifdef DHD_WMF + struct ether_header *eh; + uint8 *iph; +#endif /* DHD_WMF */ +#if defined(DHD_MQ) && defined(DHD_MQ_STATS) + int qidx = 0; + int cpuid = 0; + int prio = 0; +#endif /* DHD_MQ && DHD_MQ_STATS */ +#ifndef DHD_TCP_PACING_SHIFT +#if defined(BCMPCIE) && defined(DHD_VSDB_SKIP_ORPHAN) + struct bcm_cfg80211 *cfg = wl_get_cfg(net); +#endif /* (BCMPCIE) && (DHD_VSDB_SKIP_ORPHAN) */ +#endif /* DHD_TCP_PACING_SHIFT */ + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + +#if defined(DHD_MQ) && defined(DHD_MQ_STATS) + qidx = skb_get_queue_mapping(skb); + /* if in a non pre-emptable context, smp_processor_id can be used + * else get_cpu and put_cpu should be used + */ + if (!CAN_SLEEP()) { + cpuid = smp_processor_id(); + } + else { + cpuid = get_cpu(); + put_cpu(); + } + prio = dhd->pub.flow_prio_map[skb->priority]; + DHD_TRACE(("%s: Q idx = %d, CPU = %d, prio = %d \n", __FUNCTION__, + qidx, cpuid, prio)); + dhd->pktcnt_qac_histo[qidx][prio]++; + dhd->pktcnt_per_ac[prio]++; + dhd->cpu_qstats[qidx][cpuid]++; +#endif /* DHD_MQ && DHD_MQ_STATS */ + + if (dhd_query_bus_erros(&dhd->pub)) { + return -ENODEV; + } + + DHD_GENERAL_LOCK(&dhd->pub, flags); + DHD_BUS_BUSY_SET_IN_TX(&dhd->pub); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + + DHD_GENERAL_LOCK(&dhd->pub, flags); +#ifdef BCMPCIE + if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(&dhd->pub)) { + DHD_ERROR_RLMT(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", + __FUNCTION__, dhd->pub.busstate, dhd->pub.dhd_bus_busy_state)); + DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); +#ifdef PCIE_FULL_DONGLE + /* Stop tx queues if suspend is in progress or suspended */ + if (DHD_BUS_CHECK_ANY_SUSPEND_IN_PROGRESS(&dhd->pub) || + (dhd->pub.busstate == DHD_BUS_SUSPEND && + !DHD_BUS_BUSY_CHECK_RESUME_IN_PROGRESS(&dhd->pub))) { + dhd_bus_stop_queue(dhd->pub.bus); + } +#endif /* PCIE_FULL_DONGLE */ + dhd_os_busbusy_wake(&dhd->pub); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + return NETDEV_TX_BUSY; + } +#else + if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(&dhd->pub)) { + DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", + __FUNCTION__, dhd->pub.busstate, dhd->pub.dhd_bus_busy_state)); + } +#endif + + DHD_OS_WAKE_LOCK(&dhd->pub); + +#if defined(DHD_HANG_SEND_UP_TEST) + if (dhd->pub.req_hang_type == HANG_REASON_BUS_DOWN) { + DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__)); + dhd->pub.busstate = DHD_BUS_DOWN; + } +#endif /* DHD_HANG_SEND_UP_TEST */ + + /* Reject if down */ + /* XXX kernel panic issue when first bootup time, + * rmmod without interface down make unnecessary hang event. + */ + if (dhd->pub.hang_was_sent || DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(&dhd->pub)) { + DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", + __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); + dhd_tx_stop_queues(net); +#if defined(OEM_ANDROID) + /* Send Event when bus down detected during data session */ + if (dhd->pub.up && !dhd->pub.hang_was_sent && !DHD_BUS_CHECK_REMOVE(&dhd->pub)) { + DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); + dhd->pub.hang_reason = HANG_REASON_BUS_DOWN; + net_os_send_hang_message(net); + } +#endif /* OEM_ANDROID */ + DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); + dhd_os_busbusy_wake(&dhd->pub); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return NETDEV_TX_BUSY; + } + + ifp = DHD_DEV_IFP(net); + ifidx = DHD_DEV_IFIDX(net); +#ifdef DHD_BUZZZ_LOG_ENABLED + BUZZZ_LOG(START_XMIT_BGN, 2, (uint32)ifidx, (uintptr)skb); +#endif /* DHD_BUZZZ_LOG_ENABLED */ + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx)); + dhd_tx_stop_queues(net); + DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); + dhd_os_busbusy_wake(&dhd->pub); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return NETDEV_TX_BUSY; + } +#ifdef RPM_FAST_TRIGGER + /* Xmit is running reset RPM fast trigger */ + if (dhd->pub.rpm_fast_trigger) { + DHD_ERROR(("%s: Reset RPM fast trigger\n", __FUNCTION__)); + dhd->pub.rpm_fast_trigger = FALSE; + } +#endif /* RPM_FAST_TRIGGER */ + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + + /* If tput test is in progress */ + if (dhd->pub.tput_data.tput_test_running) { + return NETDEV_TX_BUSY; + } + + ASSERT(ifidx == dhd_net2idx(dhd, net)); + ASSERT((ifp != NULL) && ((ifidx < DHD_MAX_IFS) && (ifp == dhd->iflist[ifidx]))); + + bcm_object_trace_opr(skb, BCM_OBJDBG_ADD_PKT, __FUNCTION__, __LINE__); + + /* re-align socket buffer if "skb->data" is odd address */ + if (((unsigned long)(skb->data)) & 0x1) { + unsigned char *data = skb->data; + uint32 length = skb->len; + PKTPUSH(dhd->pub.osh, skb, 1); + memmove(skb->data, data, length); + PKTSETLEN(dhd->pub.osh, skb, length); + } + +#ifdef TPUT_MONITOR + if (dhd->pub.conf->tput_monitor_ms) { + dhd_os_sdlock_txq(&dhd->pub); + dhd->pub.conf->net_len += PKTLEN(dhd->pub.osh, skb); + dhd_os_sdunlock_txq(&dhd->pub); + if ((dhd->pub.conf->data_drop_mode == XMIT_DROP) && + (PKTLEN(dhd->pub.osh, skb) > 500)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + } +#endif + /* Make sure there's enough room for any header */ +#if !defined(BCM_ROUTER_DHD) + if (skb_cow(skb, (dhd->pub.hdrlen + htsfdlystat_sz))) { + DHD_ERROR(("%s: skb_cow failed\n", + dhd_ifname(&dhd->pub, ifidx))); + bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, __FUNCTION__, __LINE__); + dev_kfree_skb_any(skb); + ret = -ENOMEM; + goto done; + } +#endif /* !BCM_ROUTER_DHD */ + + /* Convert to packet */ + if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) { + DHD_ERROR(("%s: PKTFRMNATIVE failed\n", + dhd_ifname(&dhd->pub, ifidx))); + bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, __FUNCTION__, __LINE__); + dev_kfree_skb_any(skb); + ret = -ENOMEM; + goto done; + } + +#ifdef DHD_WET + /* wet related packet proto manipulation should be done in DHD + since dongle doesn't have complete payload + */ + if (WET_ENABLED(&dhd->pub) && + (dhd_wet_send_proc(dhd->pub.wet_info, pktbuf, &pktbuf) < 0)) { + DHD_INFO(("%s:%s: wet send proc failed\n", + __FUNCTION__, dhd_ifname(&dhd->pub, ifidx))); + PKTFREE(dhd->pub.osh, pktbuf, FALSE); + ret = -EFAULT; + goto done; + } +#endif /* DHD_WET */ + +#ifdef DHD_WMF + eh = (struct ether_header *)PKTDATA(dhd->pub.osh, pktbuf); + iph = (uint8 *)eh + ETHER_HDR_LEN; + + /* WMF processing for multicast packets + * Only IPv4 packets are handled + */ + if (ifp->wmf.wmf_enable && (ntoh16(eh->ether_type) == ETHER_TYPE_IP) && + (IP_VER(iph) == IP_VER_4) && (ETHER_ISMULTI(eh->ether_dhost) || + ((IPV4_PROT(iph) == IP_PROT_IGMP) && dhd->pub.wmf_ucast_igmp))) { +#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) + void *sdu_clone; + bool ucast_convert = FALSE; +#ifdef DHD_UCAST_UPNP + uint32 dest_ip; + + dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET))); + ucast_convert = dhd->pub.wmf_ucast_upnp && MCAST_ADDR_UPNP_SSDP(dest_ip); +#endif /* DHD_UCAST_UPNP */ +#ifdef DHD_IGMP_UCQUERY + ucast_convert |= dhd->pub.wmf_ucast_igmp_query && + (IPV4_PROT(iph) == IP_PROT_IGMP) && + (*(iph + IPV4_HLEN(iph)) == IGMPV2_HOST_MEMBERSHIP_QUERY); +#endif /* DHD_IGMP_UCQUERY */ + if (ucast_convert) { + dhd_sta_t *sta; + unsigned long flags; + struct list_head snapshot_list; + struct list_head *wmf_ucforward_list; + + ret = NETDEV_TX_OK; + + /* For non BCM_GMAC3 platform we need a snapshot sta_list to + * resolve double DHD_IF_STA_LIST_LOCK call deadlock issue. + */ + wmf_ucforward_list = DHD_IF_WMF_UCFORWARD_LOCK(dhd, ifp, &snapshot_list); + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + /* Convert upnp/igmp query to unicast for each assoc STA */ + list_for_each_entry(sta, wmf_ucforward_list, list) { + GCC_DIAGNOSTIC_POP(); + /* Skip sending to proxy interfaces of proxySTA */ + if (sta->psta_prim != NULL && !ifp->wmf_psta_disable) { + continue; + } + if ((sdu_clone = PKTDUP(dhd->pub.osh, pktbuf)) == NULL) { + ret = WMF_NOP; + break; + } + dhd_wmf_forward(ifp->wmf.wmfh, sdu_clone, 0, sta, 1); + } + DHD_IF_WMF_UCFORWARD_UNLOCK(dhd, wmf_ucforward_list); + + DHD_GENERAL_LOCK(&dhd->pub, flags); + DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); + dhd_os_busbusy_wake(&dhd->pub); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + + if (ret == NETDEV_TX_OK) + PKTFREE(dhd->pub.osh, pktbuf, TRUE); + + return ret; + } else +#endif /* defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) */ + { + /* There will be no STA info if the packet is coming from LAN host + * Pass as NULL + */ + ret = dhd_wmf_packets_handle(&dhd->pub, pktbuf, NULL, ifidx, 0); + switch (ret) { + case WMF_TAKEN: + case WMF_DROP: + /* Either taken by WMF or we should drop it. + * Exiting send path + */ + + DHD_GENERAL_LOCK(&dhd->pub, flags); + DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); + dhd_os_busbusy_wake(&dhd->pub); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return NETDEV_TX_OK; + default: + /* Continue the transmit path */ + break; + } + } + } +#endif /* DHD_WMF */ +#ifdef DHD_PSTA + /* PSR related packet proto manipulation should be done in DHD + * since dongle doesn't have complete payload + */ + if (PSR_ENABLED(&dhd->pub) && +#ifdef BCM_ROUTER_DHD + !(ifp->primsta_dwds) && +#endif /* BCM_ROUTER_DHD */ + (dhd_psta_proc(&dhd->pub, ifidx, &pktbuf, TRUE) < 0)) { + + DHD_ERROR(("%s:%s: psta send proc failed\n", __FUNCTION__, + dhd_ifname(&dhd->pub, ifidx))); + } +#endif /* DHD_PSTA */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) && defined(DHD_TCP_PACING_SHIFT) +#ifndef DHD_DEFAULT_TCP_PACING_SHIFT +#define DHD_DEFAULT_TCP_PACING_SHIFT 7 +#endif /* DHD_DEFAULT_TCP_PACING_SHIFT */ + if (skb->sk) { + sk_pacing_shift_update(skb->sk, DHD_DEFAULT_TCP_PACING_SHIFT); + } +#else +#if defined(BCMPCIE) && defined(DHD_VSDB_SKIP_ORPHAN) + if (!cfg->vsdb_mode) +#endif /* (BCMPCIE) && (DHD_VSDB_SKIP_ORPHAN) */ + skb_orphan(skb); +#endif /* LINUX_VERSION_CODE >= 4.19.0 && DHD_TCP_PACING_SHIFT */ + + /* move from dhdsdio_sendfromq(), try to orphan skb early */ + if (dhd->pub.conf->orphan_move == 2) + PKTORPHAN(skb, dhd->pub.conf->tsq); + else if (dhd->pub.conf->orphan_move == 3) + skb_orphan(skb); + +#ifdef DHDTCPSYNC_FLOOD_BLK + if (dhd_tcpdata_get_flag(&dhd->pub, pktbuf) == FLAG_SYNCACK) { + ifp->tsyncack_txed ++; + } +#endif /* DHDTCPSYNC_FLOOD_BLK */ + +#ifdef DHDTCPACK_SUPPRESS + if (dhd->pub.tcpack_sup_mode == TCPACK_SUP_HOLD) { + /* If this packet has been hold or got freed, just return */ + if (dhd_tcpack_hold(&dhd->pub, pktbuf, ifidx)) { + ret = 0; + goto done; + } + } else { + /* If this packet has replaced another packet and got freed, just return */ + if (dhd_tcpack_suppress(&dhd->pub, pktbuf)) { + ret = 0; + goto done; + } + } +#endif /* DHDTCPACK_SUPPRESS */ + + /* + * If Load Balance is enabled queue the packet + * else send directly from here. + */ +#if defined(DHD_LB_TXP) + ret = dhd_lb_sendpkt(dhd, net, ifidx, pktbuf); +#else + ret = __dhd_sendpkt(&dhd->pub, ifidx, pktbuf); +#endif + BCM_REFERENCE(ret); + +done: + DHD_GENERAL_LOCK(&dhd->pub, flags); + DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); + DHD_IF_CLR_TX_ACTIVE(ifp, DHD_TX_START_XMIT); + dhd_os_tx_completion_wake(&dhd->pub); + dhd_os_busbusy_wake(&dhd->pub); + DHD_GENERAL_UNLOCK(&dhd->pub, flags); + DHD_OS_WAKE_UNLOCK(&dhd->pub); +#ifdef DHD_BUZZZ_LOG_ENABLED + BUZZZ_LOG(START_XMIT_END, 0); +#endif /* DHD_BUZZZ_LOG_ENABLED */ + /* Return ok: we always eat the packet */ + return NETDEV_TX_OK; +} + +static void +__dhd_txflowcontrol(dhd_pub_t *dhdp, struct net_device *net, bool state) +{ + + if (net->reg_state != NETREG_REGISTERED) { + return; + } + + if (state == ON) { + if (!netif_queue_stopped(net)) { + DHD_TXFLOWCTL(("%s: Stop Netif Queue\n", __FUNCTION__)); + netif_stop_queue(net); + } else { + DHD_INFO(("%s: Netif Queue already stopped\n", __FUNCTION__)); + } + } + + if (state == OFF) { + if (netif_queue_stopped(net)) { + DHD_TXFLOWCTL(("%s: Start Netif Queue\n", __FUNCTION__)); + netif_wake_queue(net); + } else { + DHD_INFO(("%s: Netif Queue already started\n", __FUNCTION__)); + } + } +} + +void +dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) +{ + struct net_device *net; + dhd_info_t *dhd = dhdp->info; + unsigned long flags; + int i; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(dhd); + +#ifdef DHD_LOSSLESS_ROAMING + /* block flowcontrol during roaming */ + if ((dhdp->dequeue_prec_map == (1 << dhdp->flow_prio_map[PRIO_8021D_NC])) && (state == ON)) + { + DHD_ERROR_RLMT(("%s: Roaming in progress, cannot stop network queue (0x%x:%d)\n", + __FUNCTION__, dhdp->dequeue_prec_map, dhdp->flow_prio_map[PRIO_8021D_NC])); + return; + } +#endif + + flags = dhd_os_sdlock_txoff(&dhd->pub); + if (ifidx == ALL_INTERFACES) { + for (i = 0; i < DHD_MAX_IFS; i++) { + if (dhd->iflist[i]) { + net = dhd->iflist[i]->net; + __dhd_txflowcontrol(dhdp, net, state); + } + } + } else { + if (dhd->iflist[ifidx]) { + net = dhd->iflist[ifidx]->net; + __dhd_txflowcontrol(dhdp, net, state); + } + } + dhdp->txoff = state; + dhd_os_sdunlock_txoff(&dhd->pub, flags); +} + +void +dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) +{ + dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + struct ether_header *eh; + uint16 type; + + if (dhdp->tput_data.tput_test_running) { + + dhdp->batch_tx_pkts_cmpl++; + + /* don't count the stop pkt */ + if (success && + dhdp->batch_tx_pkts_cmpl <= dhdp->batch_tx_num_pkts) + dhdp->tput_data.pkts_good++; + else if (!success) + dhdp->tput_data.pkts_bad++; + + /* we dont care for the stop packet in tput test */ + if (dhdp->batch_tx_pkts_cmpl == dhdp->batch_tx_num_pkts) { + dhdp->tput_stop_ts = OSL_SYSUPTIME_US(); + dhdp->tput_data.pkts_cmpl += dhdp->batch_tx_pkts_cmpl; + dhdp->tput_data.num_pkts += dhdp->batch_tx_num_pkts; + dhd_os_tput_test_wake(dhdp); + } + } + /* XXX where does this stuff belong to? */ + dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); + + /* XXX Use packet tag when it is available to identify its type */ + + eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); + type = ntoh16(eh->ether_type); + + if (type == ETHER_TYPE_802_1X) { + atomic_dec(&dhd->pend_8021x_cnt); + } + +#ifdef PROP_TXSTATUS + if (dhdp->wlfc_state && (dhdp->proptxstatus_mode != WLFC_FCMODE_NONE)) { + dhd_if_t *ifp = dhd->iflist[DHD_PKTTAG_IF(PKTTAG(txp))]; + uint datalen = PKTLEN(dhd->pub.osh, txp); + if (ifp != NULL) { + if (success) { + dhd->pub.tx_packets++; + dhd->pub.tx_bytes += datalen; + ifp->stats.tx_packets++; + ifp->stats.tx_bytes += datalen; + } else { + ifp->stats.tx_dropped++; + } + } + } +#endif + if (success) { + dhd->pub.tot_txcpl++; + } +} + +void +dhd_os_tx_completion_wake(dhd_pub_t *dhd) +{ + /* Call wmb() to make sure before waking up the other event value gets updated */ + OSL_SMP_WMB(); + wake_up(&dhd->tx_completion_wait); +} + +void +dhd_os_sdlock_txq(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); +#ifdef BCMDBUS + spin_lock_irqsave(&dhd->txqlock, dhd->txqlock_flags); +#else + spin_lock_bh(&dhd->txqlock); +#endif +} + +void +dhd_os_sdunlock_txq(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); +#ifdef BCMDBUS + spin_unlock_irqrestore(&dhd->txqlock, dhd->txqlock_flags); +#else + spin_unlock_bh(&dhd->txqlock); +#endif +} + +unsigned long +dhd_os_sdlock_txoff(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + unsigned long flags = 0; + + dhd = (dhd_info_t *)(pub->info); + spin_lock_irqsave(&dhd->txoff_lock, flags); + + return flags; +} + +void +dhd_os_sdunlock_txoff(dhd_pub_t *pub, unsigned long flags) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_unlock_irqrestore(&dhd->txoff_lock, flags); +} + +void +dhd_txfl_wake_lock_timeout(dhd_pub_t *pub, int val) +{ +#ifdef CONFIG_HAS_WAKELOCK + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + if (dhd) { + dhd_wake_lock_timeout(dhd->wl_txflwake, msecs_to_jiffies(val)); + } +#endif /* CONFIG_HAS_WAKE_LOCK */ +} + +#ifdef DHD_4WAYM4_FAIL_DISCONNECT +void +dhd_eap_txcomplete(dhd_pub_t *dhdp, void *txp, bool success, int ifidx) +{ + dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + struct ether_header *eh; + uint16 type; + + /* XXX where does this stuff belong to? */ + dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); + + /* XXX Use packet tag when it is available to identify its type */ + eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); + type = ntoh16(eh->ether_type); + if (type == ETHER_TYPE_802_1X) { + if (dhd_is_4way_msg((uint8 *)eh) == EAPOL_4WAY_M4) { + dhd_if_t *ifp = NULL; + ifp = dhd->iflist[ifidx]; + if (!ifp || !ifp->net) { + return; + } + if (!success) { + DHD_INFO(("%s: M4 TX failed on %d.\n", + __FUNCTION__, ifidx)); + + OSL_ATOMIC_SET(dhdp->osh, &ifp->m4state, M4_TXFAILED); + schedule_delayed_work(&ifp->m4state_work, + msecs_to_jiffies(MAX_4WAY_TIMEOUT_MS)); + } else { + cancel_delayed_work(&ifp->m4state_work); + } + } + } +} +#endif /* DHD_4WAYM4_FAIL_DISCONNECT */ + +void +dhd_handle_pktdata(dhd_pub_t *dhdp, int ifidx, void *pkt, uint8 *pktdata, uint32 pktid, + uint32 pktlen, uint16 *pktfate, uint8 *dhd_udr, uint8 *dhd_igmp, + bool tx, int pkt_wake, bool pkt_log) +{ + struct ether_header *eh; + uint16 ether_type; + uint32 pkthash; + uint8 pkt_type = PKT_TYPE_DATA; +#ifdef DHD_PKT_LOGGING_DBGRING + bool verbose_logging = FALSE; + dhd_dbg_ring_t *ring; + ring = &dhdp->dbg->dbg_rings[PACKET_LOG_RING_ID]; + UNUSED_PARAMETER(verbose_logging); +#endif /* DHD_PKT_LOGGING_DBGRING */ + + if (!pktdata || pktlen < ETHER_HDR_LEN) { + return; + } + + eh = (struct ether_header *)pktdata; + ether_type = ntoh16(eh->ether_type); + + /* Check packet type */ + if (dhd_check_ip_prot(pktdata, ether_type)) { + if (dhd_check_dhcp(pktdata)) { + pkt_type = PKT_TYPE_DHCP; + } else if (dhd_check_icmp(pktdata)) { + pkt_type = PKT_TYPE_ICMP; + } else if (dhd_check_dns(pktdata)) { + pkt_type = PKT_TYPE_DNS; + } + } + else if (ether_type == ETHER_TYPE_IPV6) { + if (dhd_check_icmpv6(pktdata, pktlen)) { + pkt_type = PKT_TYPE_ICMPV6; + } + } + else if (dhd_check_arp(pktdata, ether_type)) { + pkt_type = PKT_TYPE_ARP; + } + else if (ether_type == ETHER_TYPE_802_1X) { + pkt_type = PKT_TYPE_EAP; + } +#ifdef DHD_PKT_LOGGING_DBGRING + do { + if (!OSL_ATOMIC_READ(dhdp->osh, &dhdp->pktlog->enable)) { + struct dhd_pktlog_ring *pktlog_ring; + + pktlog_ring = dhdp->pktlog->pktlog_ring; + if (pktlog_ring->pktcount <= DHD_PACKET_LOG_RING_RESUME_THRESHOLD) { + dhd_pktlog_resume(dhdp); + } else { + /* If pktlog disabled(suspeneded), only allowed TXS update */ + if (tx && pktfate) { + DHD_PKTLOG_TXS(dhdp, pkt, pktdata, pktid, *pktfate); + pkthash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid); + } + dhd_os_dbg_urgent_pullreq(dhdp->dbg->private, + PACKET_LOG_RING_ID); + break; + } + } + + /* Allow logging for all packets without pktlog filter */ + if (ring->log_level == RING_LOG_LEVEL_EXCESSIVE) { + verbose_logging = TRUE; + pkt_log = TRUE; + /* Not allow logging for any packets */ + } else if (ring->log_level == RING_LOG_LEVEL_NONE) { + verbose_logging = FALSE; + pkt_log = FALSE; + } +#endif /* DHD_PKT_LOGGING_DBGRING */ +#ifdef DHD_SBN + /* Set UDR based on packet type */ + if (dhd_udr && (pkt_type == PKT_TYPE_DHCP || + pkt_type == PKT_TYPE_DNS || + pkt_type == PKT_TYPE_ARP)) { + *dhd_udr = TRUE; + } +#endif /* DHD_SBN */ + +#ifdef DHD_PKT_LOGGING +#ifdef DHD_SKIP_PKTLOGGING_FOR_DATA_PKTS + if (pkt_type != PKT_TYPE_DATA) +#else +#ifdef DHD_PKT_LOGGING_DBGRING + if ((verbose_logging == TRUE) || (pkt_type != PKT_TYPE_DATA)) +#endif /* DHD_PKT_LOGGING_DBGRING */ +#endif /* DHD_PKT_LOGGING */ + { + if (pkt_log) { + if (tx) { + if (pktfate) { + /* Tx status */ + DHD_PKTLOG_TXS(dhdp, pkt, pktdata, pktid, *pktfate); + } else { + /* Tx packet */ + DHD_PKTLOG_TX(dhdp, pkt, pktdata, pktid); + } + pkthash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid); + } else { + struct sk_buff *skb = (struct sk_buff *)pkt; + if (pkt_wake) { + DHD_PKTLOG_WAKERX(dhdp, skb, pktdata); + } else { + DHD_PKTLOG_RX(dhdp, skb, pktdata); + } + } + } + } +#endif /* DHD_PKT_LOGGING */ +#ifdef DHD_PKT_LOGGING_DBGRING + } while (FALSE); +#endif /* DHD_PKT_LOGGING_DBGRING */ + + /* Dump packet data */ + if (!tx) + dhd_dump_pkt(dhdp, ifidx, pktdata, pktlen, FALSE, &pkthash, NULL); + switch (pkt_type) { + case PKT_TYPE_DHCP: + dhd_send_supp_dhcp(dhdp, ifidx, pktdata, tx, pktfate); + break; + case PKT_TYPE_EAP: + dhd_send_supp_eap(dhdp, ifidx, pktdata, pktlen, tx, pktfate); + break; + default: + break; + } +} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_tx.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_tx.h new file mode 100644 index 000000000000..1484f7b5c31b --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_tx.h @@ -0,0 +1,49 @@ +/* + * Broadcom Dongle Host Driver (DHD), + * Linux-specific network interface for transmit(tx) path + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + * + * $Id$ + */ + +#ifndef _dhd_linux_tx_h_ +#define _dhd_linux_tx_h_ +void dhd_tx_stop_queues(struct net_device *net); +void dhd_tx_start_queues(struct net_device *net); +int BCMFASTPATH(__dhd_sendpkt)(dhd_pub_t *dhdp, int ifidx, void *pktbuf); +int BCMFASTPATH(dhd_sendpkt)(dhd_pub_t *dhdp, int ifidx, void *pktbuf); +#ifdef DHD_MQ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +uint16 +BCMFASTPATH(dhd_select_queue)(struct net_device *net, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback); +#else +uint16 +BCMFASTPATH(dhd_select_queue)(struct net_device *net, struct sk_buff *skb); +#endif /* LINUX_VERSION_CODE */ +#endif /* DHD_MQ */ +netdev_tx_t BCMFASTPATH(dhd_start_xmit)(struct sk_buff *skb, struct net_device *net); +void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state); +void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); +void dhd_os_tx_completion_wake(dhd_pub_t *dhd); +void dhd_os_sdlock_txq(dhd_pub_t *pub); +void dhd_os_sdunlock_txq(dhd_pub_t *pub); +#endif /* _dhd_linux_tx_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.c old mode 100755 new mode 100644 index 4bfe72b0c6b9..c642853ff081 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Generic work queue framework * Generic interface to handle dhd deferred work events * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h old mode 100755 new mode 100644 index 42c5a88d4df7..2c097e6c5753 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Generic work queue framework * Generic interface to handle dhd deferred work events * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -47,15 +47,14 @@ enum _wq_event { DHD_WQ_WORK_GET_BIGDATA_AP, DHD_WQ_WORK_SOC_RAM_DUMP, DHD_WQ_WORK_SOC_RAM_COLLECT, -#ifdef DHD_ERPOM - DHD_WQ_WORK_ERROR_RECOVERY, -#endif /* DHD_ERPOM */ DHD_WQ_WORK_H2D_CONSOLE_TIME_STAMP_MATCH, DHD_WQ_WORK_AXI_ERROR_DUMP, DHD_WQ_WORK_CTO_RECOVERY, #ifdef DHD_UPDATE_INTF_MAC DHD_WQ_WORK_IF_UPDATE, #endif /* DHD_UPDATE_INTF_MAC */ + DHD_WQ_WORK_AML_IOVAR, + DHD_WQ_WORK_NDEV_UPD_FEATURES, DHD_MAX_WQ_EVENTS }; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_log_dump.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_log_dump.c new file mode 100644 index 000000000000..cb8fd58838df --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_log_dump.c @@ -0,0 +1,2480 @@ +/* + * log_dump - debugability support for dumping logs to file + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + * + * $Id$ + */ +#ifdef DHD_LOG_DUMP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DHD_EVENT_LOG_FILTER +#include +#endif /* DHD_EVENT_LOG_FILTER */ +#ifdef DHD_PKT_LOGGING +#include +#endif /* DHD_PKT_LOGGING */ +#if defined(WL_CFG80211) +#include +#endif + +extern char dhd_version[]; +extern char fw_version[]; +struct dhd_log_dump_buf g_dld_buf[DLD_BUFFER_NUM]; + +/* Only header for log dump buffers is stored in array + * header for sections like 'dhd dump', 'ext trap' + * etc, is not in the array, because they are not log + * ring buffers + */ +dld_hdr_t dld_hdrs[DLD_BUFFER_NUM] = { + {GENERAL_LOG_HDR, LOG_DUMP_SECTION_GENERAL}, + {PRESERVE_LOG_HDR, LOG_DUMP_SECTION_PRESERVE}, + {SPECIAL_LOG_HDR, LOG_DUMP_SECTION_SPECIAL} +}; +static int dld_buf_size[DLD_BUFFER_NUM] = { + LOG_DUMP_GENERAL_MAX_BUFSIZE, /* DLD_BUF_TYPE_GENERAL */ + LOG_DUMP_PRESERVE_MAX_BUFSIZE, /* DLD_BUF_TYPE_PRESERVE */ + LOG_DUMP_SPECIAL_MAX_BUFSIZE, /* DLD_BUF_TYPE_SPECIAL */ +}; + +int logdump_max_filesize = LOG_DUMP_MAX_FILESIZE; +module_param(logdump_max_filesize, int, 0644); +int logdump_max_bufsize = LOG_DUMP_GENERAL_MAX_BUFSIZE; +module_param(logdump_max_bufsize, int, 0644); +int logdump_periodic_flush = FALSE; +module_param(logdump_periodic_flush, int, 0644); +#ifdef EWP_ECNTRS_LOGGING +int logdump_ecntr_enable = TRUE; +#else +int logdump_ecntr_enable = FALSE; +#endif /* EWP_ECNTRS_LOGGING */ +module_param(logdump_ecntr_enable, int, 0644); +#ifdef EWP_RTT_LOGGING +int logdump_rtt_enable = TRUE; +#else +int logdump_rtt_enable = FALSE; +#endif /* EWP_RTT_LOGGING */ + +int logdump_prsrv_tailsize = DHD_LOG_DUMP_MAX_TAIL_FLUSH_SIZE; + +#ifdef DHD_DEBUGABILITY_DEBUG_DUMP +static dhd_debug_dump_ring_entry_t dhd_debug_dump_ring_map[] = { + {LOG_DUMP_SECTION_TIMESTAMP, DEBUG_DUMP_RING1_ID}, + {LOG_DUMP_SECTION_ECNTRS, DEBUG_DUMP_RING2_ID}, + {LOG_DUMP_SECTION_STATUS, DEBUG_DUMP_RING1_ID}, + {LOG_DUMP_SECTION_RTT, DEBUG_DUMP_RING2_ID}, + {LOG_DUMP_SECTION_PKTID_MAP_LOG, DEBUG_DUMP_RING2_ID}, + {LOG_DUMP_SECTION_PKTID_UNMAP_LOG, DEBUG_DUMP_RING2_ID}, + {LOG_DUMP_SECTION_DHD_DUMP, DEBUG_DUMP_RING1_ID}, + {LOG_DUMP_SECTION_EXT_TRAP, DEBUG_DUMP_RING1_ID}, + {LOG_DUMP_SECTION_HEALTH_CHK, DEBUG_DUMP_RING1_ID}, + {LOG_DUMP_SECTION_COOKIE, DEBUG_DUMP_RING1_ID}, + {LOG_DUMP_SECTION_RING, DEBUG_DUMP_RING1_ID}, +}; +#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */ + +int +dhd_log_flush(dhd_pub_t *dhdp, log_dump_type_t *type) +{ + unsigned long flags = 0; +#ifdef EWP_EDL + int i = 0; +#endif /* EWP_EDL */ + dhd_info_t *dhd_info = NULL; + + BCM_REFERENCE(dhd_info); + + /* if dhdp is null, its extremely unlikely that log dump will be scheduled + * so not freeing 'type' here is ok, even if we want to free 'type' + * we cannot do so, since 'dhdp->osh' is unavailable + * as dhdp is null + */ + if (!dhdp || !type) { + if (dhdp) { + DHD_GENERAL_LOCK(dhdp, flags); + DHD_BUS_BUSY_CLEAR_IN_LOGDUMP(dhdp); + dhd_os_busbusy_wake(dhdp); + DHD_GENERAL_UNLOCK(dhdp, flags); + } + return BCME_ERROR; + } + +#if defined(BCMPCIE) + if (dhd_bus_get_linkdown(dhdp)) { + /* As link is down donot collect any data over PCIe. + * Also return BCME_OK to caller, so that caller can + * dump all the outstanding data to file + */ + return BCME_OK; + } +#endif /* BCMPCIE */ + + dhd_info = (dhd_info_t *)dhdp->info; + /* in case of trap get preserve logs from ETD */ +#if defined(BCMPCIE) && defined(EWP_ETD_PRSRV_LOGS) + if (dhdp->dongle_trap_occured && + dhdp->extended_trap_data) { + dhdpcie_get_etd_preserve_logs(dhdp, (uint8 *)dhdp->extended_trap_data, + &dhd_info->event_data); + } +#endif /* BCMPCIE */ + + /* flush the event work items to get any fw events/logs + * flush_work is a blocking call + */ +#ifdef SHOW_LOGTRACE +#ifdef EWP_EDL + if (dhd_info->pub.dongle_edl_support) { + /* wait till existing edl items are processed */ + dhd_flush_logtrace_process(dhd_info); + /* dhd_flush_logtrace_process will ensure the work items in the ring + * (EDL ring) from rd to wr are processed. But if wr had + * wrapped around, only the work items from rd to ring-end are processed. + * So to ensure that the work items at the + * beginning of ring are also processed in the wrap around case, call + * it twice + */ + for (i = 0; i < 2; i++) { + /* blocks till the edl items are processed */ + dhd_flush_logtrace_process(dhd_info); + } + } else { + dhd_flush_logtrace_process(dhd_info); + } +#else + dhd_flush_logtrace_process(dhd_info); +#endif /* EWP_EDL */ +#endif /* SHOW_LOGTRACE */ + + return BCME_OK; +} + +void +dhd_log_dump(void *handle, void *event_info, u8 event) +{ + dhd_info_t *dhd = handle; + log_dump_type_t *type = (log_dump_type_t *)event_info; + + if (!dhd || !type) { + DHD_ERROR(("%s: dhd/type is NULL\n", __FUNCTION__)); + return; + } + +#ifdef WL_CFG80211 + /* flush the fw preserve logs */ + wl_flush_fw_log_buffer(dhd_linux_get_primary_netdev(&dhd->pub), + FW_LOGSET_MASK_ALL); +#endif + + /* there are currently 3 possible contexts from which + * log dump can be scheduled - + * 1.TRAP 2.supplicant DEBUG_DUMP pvt driver command + * 3.HEALTH CHECK event + * The concise debug info buffer is a shared resource + * and in case a trap is one of the contexts then both the + * scheduled work queues need to run because trap data is + * essential for debugging. Hence a mutex lock is acquired + * before calling do_dhd_log_dump(). + */ + DHD_ERROR(("%s: calling log dump.. \n", __FUNCTION__)); + dhd_os_logdump_lock(&dhd->pub); + DHD_OS_WAKE_LOCK(&dhd->pub); + if (do_dhd_log_dump(&dhd->pub, type) != BCME_OK) { + DHD_ERROR(("%s: writing debug dump to the file failed\n", __FUNCTION__)); + } + DHD_OS_WAKE_UNLOCK(&dhd->pub); + dhd_os_logdump_unlock(&dhd->pub); +} + +void dhd_schedule_log_dump(dhd_pub_t *dhdp, void *type) +{ + DHD_ERROR(("%s: scheduling log dump.. \n", __FUNCTION__)); + + dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, + type, DHD_WQ_WORK_DHD_LOG_DUMP, + dhd_log_dump, DHD_WQ_WORK_PRIORITY_HIGH); +} + +void +dhd_print_buf_addr(dhd_pub_t *dhdp, char *name, void *buf, unsigned int size) +{ +#ifdef DHD_FW_COREDUMP + if ((dhdp->memdump_enabled == DUMP_MEMONLY) || + (dhdp->memdump_enabled == DUMP_MEMFILE_BUGON) || + (dhdp->memdump_type == DUMP_TYPE_SMMU_FAULT) || +#ifdef DHD_DETECT_CONSECUTIVE_MFG_HANG + (dhdp->op_mode & DHD_FLAG_MFG_MODE && + (dhdp->hang_count >= MAX_CONSECUTIVE_MFG_HANG_COUNT-1)) || +#endif /* DHD_DETECT_CONSECUTIVE_MFG_HANG */ + FALSE) +#else + if (dhdp->memdump_type == DUMP_TYPE_SMMU_FAULT) +#endif + { +#if defined(CONFIG_ARM64) + DHD_ERROR(("-------- %s: buf(va)=%llx, buf(pa)=%llx, bufsize=%d\n", + name, (uint64)buf, (uint64)__virt_to_phys((ulong)buf), size)); +#elif defined(__ARM_ARCH_7A__) + DHD_ERROR(("-------- %s: buf(va)=%x, buf(pa)=%x, bufsize=%d\n", + name, (uint32)buf, (uint32)__virt_to_phys((ulong)buf), size)); +#endif /* __ARM_ARCH_7A__ */ + } +} + +void +dhd_log_dump_buf_addr(dhd_pub_t *dhdp, log_dump_type_t *type) +{ + int i; + unsigned long wr_size = 0; + struct dhd_log_dump_buf *dld_buf = &g_dld_buf[0]; + size_t log_size = 0; + char buf_name[DHD_PRINT_BUF_NAME_LEN]; + dhd_dbg_ring_t *ring = NULL; + + BCM_REFERENCE(ring); + + for (i = 0; i < DLD_BUFFER_NUM; i++) { + dld_buf = &g_dld_buf[i]; + log_size = (unsigned long)dld_buf->max - + (unsigned long)dld_buf->buffer; + if (dld_buf->wraparound) { + wr_size = log_size; + } else { + wr_size = (unsigned long)dld_buf->present - + (unsigned long)dld_buf->front; + } + scnprintf(buf_name, sizeof(buf_name), "dlb_buf[%d]", i); + dhd_print_buf_addr(dhdp, buf_name, dld_buf, dld_buf_size[i]); + scnprintf(buf_name, sizeof(buf_name), "dlb_buf[%d] buffer", i); + dhd_print_buf_addr(dhdp, buf_name, dld_buf->buffer, wr_size); + scnprintf(buf_name, sizeof(buf_name), "dlb_buf[%d] present", i); + dhd_print_buf_addr(dhdp, buf_name, dld_buf->present, wr_size); + scnprintf(buf_name, sizeof(buf_name), "dlb_buf[%d] front", i); + dhd_print_buf_addr(dhdp, buf_name, dld_buf->front, wr_size); + } + +#ifdef DEBUGABILITY_ECNTRS_LOGGING + /* periodic flushing of ecounters is NOT supported */ + if (*type == DLD_BUF_TYPE_ALL && + logdump_ecntr_enable && + dhdp->ecntr_dbg_ring) { + + ring = (dhd_dbg_ring_t *)dhdp->ecntr_dbg_ring; + dhd_print_buf_addr(dhdp, "ecntr_dbg_ring", ring, LOG_DUMP_ECNTRS_MAX_BUFSIZE); + dhd_print_buf_addr(dhdp, "ecntr_dbg_ring ring_buf", ring->ring_buf, + LOG_DUMP_ECNTRS_MAX_BUFSIZE); + } +#endif /* DEBUGABILITY_ECNTRS_LOGGING */ + +#if defined(BCMPCIE) + if (dhdp->dongle_trap_occured && dhdp->extended_trap_data) { + dhd_print_buf_addr(dhdp, "extended_trap_data", dhdp->extended_trap_data, + BCMPCIE_EXT_TRAP_DATA_MAXLEN); + } +#endif /* BCMPCIE */ + +#if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT) + /* if health check event was received */ + if (dhdp->memdump_type == DUMP_TYPE_DONGLE_HOST_EVENT) { + dhd_print_buf_addr(dhdp, "health_chk_event_data", dhdp->health_chk_event_data, + HEALTH_CHK_BUF_SIZE); + } +#endif /* DHD_FW_COREDUMP && DNGL_EVENT_SUPPORT */ + + /* append the concise debug information */ + if (dhdp->concise_dbg_buf) { + dhd_print_buf_addr(dhdp, "concise_dbg_buf", dhdp->concise_dbg_buf, + CONCISE_DUMP_BUFLEN); + } +} + +#ifdef DHD_SSSR_DUMP +#ifdef DHD_COREDUMP +extern dhd_coredump_t dhd_coredump_types[]; +#endif /* DHD_COREDUMP */ +int +dhdpcie_sssr_dump_get_before_after_len(dhd_pub_t *dhd, uint32 *arr_len) +{ + int i = 0; + uint dig_buf_size = 0; + + DHD_ERROR(("%s\n", __FUNCTION__)); + + /* core 0 */ + i = 0; +#ifdef DHD_SSSR_DUMP_BEFORE_SR + if (dhd->sssr_d11_before[i] && dhd->sssr_d11_outofreset[i] && + (dhd->sssr_dump_mode == SSSR_DUMP_MODE_SSSR)) { +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_CORE0_BEFORE].length = +#endif /* DHD_COREDUMP */ + arr_len[SSSR_C0_D11_BEFORE] = dhd_sssr_mac_buf_size(dhd, i); + DHD_ERROR(("%s: arr_len[SSSR_C0_D11_BEFORE] : %d\n", __FUNCTION__, + arr_len[SSSR_C0_D11_BEFORE])); +#ifdef DHD_LOG_DUMP + dhd_print_buf_addr(dhd, "SSSR_C0_D11_BEFORE", + dhd->sssr_d11_before[i], arr_len[SSSR_C0_D11_BEFORE]); +#endif /* DHD_LOG_DUMP */ +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_CORE0_BEFORE].bufptr = + dhd->sssr_d11_before[i]; +#endif /* DHD_COREDUMP */ + } +#endif /* DHD_SSSR_DUMP_BEFORE_SR */ + if (dhd->sssr_d11_after[i] && dhd->sssr_d11_outofreset[i]) { +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_CORE0_AFTER].length = +#endif /* DHD_COREDUMP */ + arr_len[SSSR_C0_D11_AFTER] = dhd_sssr_mac_buf_size(dhd, i); + DHD_ERROR(("%s: arr_len[SSSR_C0_D11_AFTER] : %d\n", __FUNCTION__, + arr_len[SSSR_C0_D11_AFTER])); +#ifdef DHD_LOG_DUMP + dhd_print_buf_addr(dhd, "SSSR_C0_D11_AFTER", + dhd->sssr_d11_after[i], arr_len[SSSR_C0_D11_AFTER]); +#endif /* DHD_LOG_DUMP */ +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_CORE0_AFTER].bufptr = + dhd->sssr_d11_after[i]; +#endif /* DHD_COREDUMP */ + } + + /* core 1 */ + i = 1; +#ifdef DHD_SSSR_DUMP_BEFORE_SR + if (dhd->sssr_d11_before[i] && dhd->sssr_d11_outofreset[i] && + (dhd->sssr_dump_mode == SSSR_DUMP_MODE_SSSR)) { +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_CORE1_BEFORE].length = +#endif /* DHD_COREDUMP */ + arr_len[SSSR_C1_D11_BEFORE] = dhd_sssr_mac_buf_size(dhd, i); + DHD_ERROR(("%s: arr_len[SSSR_C1_D11_BEFORE] : %d\n", __FUNCTION__, + arr_len[SSSR_C1_D11_BEFORE])); +#ifdef DHD_LOG_DUMP + dhd_print_buf_addr(dhd, "SSSR_C1_D11_BEFORE", + dhd->sssr_d11_before[i], arr_len[SSSR_C1_D11_BEFORE]); +#endif /* DHD_LOG_DUMP */ +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_CORE1_BEFORE].bufptr = + dhd->sssr_d11_before[i]; +#endif /* DHD_COREDUMP */ + } +#endif /* DHD_SSSR_DUMP_BEFORE_SR */ + if (dhd->sssr_d11_after[i] && dhd->sssr_d11_outofreset[i]) { +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_CORE1_AFTER].length = +#endif /* DHD_COREDUMP */ + arr_len[SSSR_C1_D11_AFTER] = dhd_sssr_mac_buf_size(dhd, i); + DHD_ERROR(("%s: arr_len[SSSR_C1_D11_AFTER] : %d\n", __FUNCTION__, + arr_len[SSSR_C1_D11_AFTER])); +#ifdef DHD_LOG_DUMP + dhd_print_buf_addr(dhd, "SSSR_C1_D11_AFTER", + dhd->sssr_d11_after[i], arr_len[SSSR_C1_D11_AFTER]); +#endif /* DHD_LOG_DUMP */ +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_CORE1_AFTER].bufptr = + dhd->sssr_d11_after[i]; +#endif /* DHD_COREDUMP */ + } + + /* core 2 scan core */ + if (dhd->sssr_reg_info->rev2.version >= SSSR_REG_INFO_VER_2) { + i = 2; +#ifdef DHD_SSSR_DUMP_BEFORE_SR + if (dhd->sssr_d11_before[i] && dhd->sssr_d11_outofreset[i] && + (dhd->sssr_dump_mode == SSSR_DUMP_MODE_SSSR)) { +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_CORE2_BEFORE].length = +#endif /* DHD_COREDUMP */ + arr_len[SSSR_C2_D11_BEFORE] = dhd_sssr_mac_buf_size(dhd, i); + DHD_ERROR(("%s: arr_len[SSSR_C2_D11_BEFORE] : %d\n", __FUNCTION__, + arr_len[SSSR_C2_D11_BEFORE])); +#ifdef DHD_LOG_DUMP + dhd_print_buf_addr(dhd, "SSSR_C2_D11_BEFORE", + dhd->sssr_d11_before[i], arr_len[SSSR_C2_D11_BEFORE]); +#endif /* DHD_LOG_DUMP */ +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_CORE2_BEFORE].bufptr = + dhd->sssr_d11_before[i]; +#endif /* DHD_COREDUMP */ + } +#endif /* DHD_SSSR_DUMP_BEFORE_SR */ + if (dhd->sssr_d11_after[i] && dhd->sssr_d11_outofreset[i]) { +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_CORE2_AFTER].length = +#endif /* DHD_COREDUMP */ + arr_len[SSSR_C2_D11_AFTER] = dhd_sssr_mac_buf_size(dhd, i); + DHD_ERROR(("%s: arr_len[SSSR_C2_D11_AFTER] : %d\n", __FUNCTION__, + arr_len[SSSR_C2_D11_AFTER])); +#ifdef DHD_LOG_DUMP + dhd_print_buf_addr(dhd, "SSSR_C2_D11_AFTER", + dhd->sssr_d11_after[i], arr_len[SSSR_C2_D11_AFTER]); +#endif /* DHD_LOG_DUMP */ +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_CORE2_AFTER].bufptr = + dhd->sssr_d11_after[i]; +#endif /* DHD_COREDUMP */ + } + } + + /* DIG core or VASIP */ + dig_buf_size = dhd_sssr_dig_buf_size(dhd); +#ifdef DHD_SSSR_DUMP_BEFORE_SR +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_DIG_BEFORE].length = +#endif /* DHD_COREDUMP */ + arr_len[SSSR_DIG_BEFORE] = (dhd->sssr_dig_buf_before) ? dig_buf_size : 0; + DHD_ERROR(("%s: arr_len[SSSR_DIG_BEFORE] : %d\n", __FUNCTION__, + arr_len[SSSR_DIG_BEFORE])); +#ifdef DHD_LOG_DUMP + if (dhd->sssr_dig_buf_before) { + dhd_print_buf_addr(dhd, "SSSR_DIG_BEFORE", + dhd->sssr_dig_buf_before, arr_len[SSSR_DIG_BEFORE]); + } +#endif /* DHD_LOG_DUMP */ +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_DIG_BEFORE].bufptr = + dhd->sssr_dig_buf_before; +#endif /* DHD_COREDUMP */ +#endif /* DHD_SSSR_DUMP_BEFORE_SR */ + +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_DIG_AFTER].length = +#endif /* DHD_COREDUMP */ + arr_len[SSSR_DIG_AFTER] = (dhd->sssr_dig_buf_after) ? dig_buf_size : 0; + DHD_ERROR(("%s: arr_len[SSSR_DIG_AFTER] : %d\n", __FUNCTION__, + arr_len[SSSR_DIG_AFTER])); +#ifdef DHD_LOG_DUMP + if (dhd->sssr_dig_buf_after) { + dhd_print_buf_addr(dhd, "SSSR_DIG_AFTER", + dhd->sssr_dig_buf_after, arr_len[SSSR_DIG_AFTER]); + } +#endif /* DHD_LOG_DUMP */ +#ifdef DHD_COREDUMP + dhd_coredump_types[DHD_COREDUMP_TYPE_SSSRDUMP_DIG_AFTER].bufptr = + dhd->sssr_dig_buf_after; +#endif /* DHD_COREDUMP */ + + return BCME_OK; +} + +void +dhd_nla_put_sssr_dump_len(void *ndev, uint32 *arr_len) +{ + dhd_info_t *dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); + dhd_pub_t *dhdp = &dhd_info->pub; + + if (dhdp->sssr_dump_collected) { + dhdpcie_sssr_dump_get_before_after_len(dhdp, arr_len); + } +} +#endif /* DHD_SSSR_DUMP */ + +uint32 +dhd_get_time_str_len(void) +{ + char *ts = NULL, time_str[128]; + + ts = dhd_log_dump_get_timestamp(); + snprintf(time_str, sizeof(time_str), + "\n\n ========== LOG DUMP TAKEN AT : %s =========\n", ts); + return strlen(time_str); +} + +#if defined(BCMPCIE) +uint32 +dhd_get_ext_trap_len(void *ndev, dhd_pub_t *dhdp) +{ + int length = 0; + log_dump_section_hdr_t sec_hdr; + dhd_info_t *dhd_info; + + if (ndev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return length; + + if (dhdp->extended_trap_data) { + length = (strlen(EXT_TRAP_LOG_HDR) + + sizeof(sec_hdr) + BCMPCIE_EXT_TRAP_DATA_MAXLEN); + } + return length; +} +#endif /* BCMPCIE */ + +#if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT) +uint32 +dhd_get_health_chk_len(void *ndev, dhd_pub_t *dhdp) +{ + int length = 0; + log_dump_section_hdr_t sec_hdr; + dhd_info_t *dhd_info; + + if (ndev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return length; + + if (dhdp->memdump_type == DUMP_TYPE_DONGLE_HOST_EVENT) { + length = (strlen(HEALTH_CHK_LOG_HDR) + + sizeof(sec_hdr) + HEALTH_CHK_BUF_SIZE); + } + return length; +} +#endif /* DHD_FW_COREDUMP && DNGL_EVENT_SUPPORT */ + +uint32 +dhd_get_dhd_dump_len(void *ndev, dhd_pub_t *dhdp) +{ + uint32 length = 0; + log_dump_section_hdr_t sec_hdr; + dhd_info_t *dhd_info; + int remain_len = 0; + + if (ndev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return length; + + if (dhdp->concise_dbg_buf) { + remain_len = dhd_dump(dhdp, (char *)dhdp->concise_dbg_buf, CONCISE_DUMP_BUFLEN); + if (remain_len <= 0 || remain_len >= CONCISE_DUMP_BUFLEN) { + DHD_ERROR(("%s: error getting concise debug info ! remain_len: %d\n", + __FUNCTION__, remain_len)); + return length; + } + + length += (uint32)(CONCISE_DUMP_BUFLEN - remain_len); + } + + length += (uint32)(strlen(DHD_DUMP_LOG_HDR) + sizeof(sec_hdr)); + return length; +} + +#ifdef EWP_RTT_LOGGING +uint32 +dhd_get_rtt_len(void *ndev, dhd_pub_t *dhdp) +{ + dhd_info_t *dhd_info; + log_dump_section_hdr_t sec_hdr; + int length = 0; + dhd_dbg_ring_t *ring; + + if (ndev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return length; + + if (logdump_rtt_enable && dhdp->rtt_dbg_ring) { + ring = (dhd_dbg_ring_t *)dhdp->rtt_dbg_ring; + length = ring->ring_size + strlen(RTT_LOG_HDR) + sizeof(sec_hdr); + } + return length; +} +#endif /* EWP_RTT_LOGGING */ + +uint32 +dhd_get_cookie_log_len(void *ndev, dhd_pub_t *dhdp) +{ + int length = 0; + dhd_info_t *dhd_info; + + if (ndev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return length; + + if (dhdp->logdump_cookie && dhd_logdump_cookie_count(dhdp) > 0) { + length = dhd_log_dump_cookie_len(dhdp); + } + return length; + +} + +#ifdef DHD_DUMP_PCIE_RINGS +uint32 +dhd_get_flowring_len(void *ndev, dhd_pub_t *dhdp) +{ + uint32 length = 0; + log_dump_section_hdr_t sec_hdr; + dhd_info_t *dhd_info; + uint16 max_tx_flowrings; + + if (ndev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return length; + + length += (uint32) strlen(RING_DUMP_HDR); + length += (uint32) sizeof(sec_hdr); + length += (uint32) sizeof(max_tx_flowrings); + max_tx_flowrings = dhd_get_max_flow_rings(dhdp); + /* max_item and item_size value which is of 4bytes is dumped at + * start of each ring dump, so adding 4bytes to total length. + */ + length += (uint32) ((D2HRING_TXCMPLT_ITEMSIZE * d2h_max_txcpl) + + (sizeof(uint16) * 2) + + (H2DRING_RXPOST_ITEMSIZE * h2d_max_rxpost) + + (sizeof(uint16) * 2) + + (D2HRING_RXCMPLT_ITEMSIZE * d2h_max_rxcpl) + + (sizeof(uint16) * 2) + + (H2DRING_CTRL_SUB_ITEMSIZE * h2d_max_ctrlpost) + + (sizeof(uint16) * 2) + + (D2HRING_CTRL_CMPLT_ITEMSIZE * d2h_max_ctrlcpl) + + (sizeof(uint16) * 2) +#ifdef EWP_EDL + /* EDL ring doesn't have max_item and item_size */ + + (D2HRING_EDL_HDR_SIZE * D2HRING_EDL_MAX_ITEM)); +#else + + (H2DRING_INFO_BUFPOST_ITEMSIZE * H2DRING_DYNAMIC_INFO_MAX_ITEM) + + (sizeof(uint16) * 2) + + (D2HRING_INFO_BUFCMPLT_ITEMSIZE * D2HRING_DYNAMIC_INFO_MAX_ITEM) + + (sizeof(uint16) * 2)); +#endif /* EWP_EDL */ + + if (dhdp->htput_support) { + /* flowring lengths are different for HTPUT rings, handle accordingly */ + length += ((H2DRING_TXPOST_ITEMSIZE * h2d_htput_max_txpost * + HTPUT_TOTAL_FLOW_RINGS) + + (H2DRING_TXPOST_ITEMSIZE * h2d_max_txpost * + (max_tx_flowrings - HTPUT_TOTAL_FLOW_RINGS))); + } else { + length += (H2DRING_TXPOST_ITEMSIZE * h2d_max_txpost * + max_tx_flowrings); + } + length += max_tx_flowrings * (sizeof(uint16) * 2); + + return length; +} +#endif /* DHD_DUMP_PCIE_RINGS */ + +#ifdef EWP_ECNTRS_LOGGING +uint32 +dhd_get_ecntrs_len(void *ndev, dhd_pub_t *dhdp) +{ + dhd_info_t *dhd_info; + log_dump_section_hdr_t sec_hdr; + int length = 0; + dhd_dbg_ring_t *ring; + + if (ndev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return length; + + if (logdump_ecntr_enable && dhdp->ecntr_dbg_ring) { + ring = (dhd_dbg_ring_t *)dhdp->ecntr_dbg_ring; + length = ring->ring_size + strlen(ECNTRS_LOG_HDR) + sizeof(sec_hdr); + } + return length; +} +#endif /* EWP_ECNTRS_LOGGING */ + +int +dhd_get_dld_log_dump(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, int type, void *pos) +{ + int ret = BCME_OK; + struct dhd_log_dump_buf *dld_buf; + log_dump_section_hdr_t sec_hdr; + dhd_info_t *dhd_info; + + dld_buf = &g_dld_buf[type]; + + if (dev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); + dhdp = &dhd_info->pub; + } else if (!dhdp) { + return BCME_ERROR; + } + + DHD_ERROR(("%s: ENTER \n", __FUNCTION__)); + + dhd_init_sec_hdr(&sec_hdr); + + /* write the section header first */ + ret = dhd_export_debug_data(dld_hdrs[type].hdr_str, fp, user_buf, + strlen(dld_hdrs[type].hdr_str), pos); + if (ret < 0) + goto exit; + len -= (uint32)strlen(dld_hdrs[type].hdr_str); + len -= (uint32)sizeof(sec_hdr); + sec_hdr.type = dld_hdrs[type].sec_type; + sec_hdr.length = len; + ret = dhd_export_debug_data((char *)&sec_hdr, fp, user_buf, sizeof(sec_hdr), pos); + if (ret < 0) + goto exit; + ret = dhd_export_debug_data(dld_buf->buffer, fp, user_buf, len, pos); + if (ret < 0) + goto exit; + +exit: + return ret; +} + +int +dhd_get_debug_dump_file_name(void *dev, dhd_pub_t *dhdp, char *dump_path, int size) +{ + int ret; + int len = 0; + dhd_info_t *dhd_info; + + if (dev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return BCME_ERROR; + + memset(dump_path, 0, size); + + ret = snprintf(dump_path, size, "%s", + DHD_COMMON_DUMP_PATH DHD_DEBUG_DUMP_TYPE); + len += ret; + + /* Keep the same timestamp across different dump logs */ + if (!dhdp->logdump_periodic_flush) { + struct rtc_time tm; +#ifdef DHD_LOG_DUMP + clear_debug_dump_time(dhdp->debug_dump_time_str); + get_debug_dump_time(dhdp->debug_dump_time_str); +#endif /* DHD_LOG_DUMP */ + sscanf(dhdp->debug_dump_time_str, DHD_LOG_DUMP_TS_FMT_YYMMDDHHMMSS, + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec); + ret = snprintf(dump_path + len, size - len, "_" DHD_LOG_DUMP_TS_FMT_YYMMDDHHMMSS, + tm.tm_year, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + len += ret; + } + + ret = 0; + switch (dhdp->debug_dump_subcmd) { + case CMD_UNWANTED: + ret = snprintf(dump_path + len, size - len, "%s", DHD_DUMP_SUBSTR_UNWANTED); + break; + case CMD_DISCONNECTED: + ret = snprintf(dump_path + len, size - len, "%s", DHD_DUMP_SUBSTR_DISCONNECTED); + break; + default: + break; + } + len += ret; + + return BCME_OK; +} + +uint32 +dhd_get_dld_len(int log_type) +{ + unsigned long wr_size = 0; + unsigned long buf_size = 0; + unsigned long flags = 0; + struct dhd_log_dump_buf *dld_buf; + log_dump_section_hdr_t sec_hdr; + + /* calculate the length of the log */ + dld_buf = &g_dld_buf[log_type]; + buf_size = (unsigned long)dld_buf->max - + (unsigned long)dld_buf->buffer; + + if (dld_buf->wraparound) { + wr_size = buf_size; + } else { + /* need to hold the lock before accessing 'present' and 'remain' ptrs */ + DHD_LOG_DUMP_BUF_LOCK(&dld_buf->lock, flags); + wr_size = (unsigned long)dld_buf->present - + (unsigned long)dld_buf->front; + DHD_LOG_DUMP_BUF_UNLOCK(&dld_buf->lock, flags); + } + return (wr_size + sizeof(sec_hdr) + strlen(dld_hdrs[log_type].hdr_str)); +} + +static void +dhd_get_time_str(dhd_pub_t *dhdp, char *time_str, int size) +{ + char *ts = NULL; + memset(time_str, 0, size); + ts = dhd_log_dump_get_timestamp(); + snprintf(time_str, size, + "\n\n ========== LOG DUMP TAKEN AT : %s =========\n", ts); +} + +int +dhd_print_time_str(const void *user_buf, void *fp, uint32 len, void *pos) +{ + char *ts = NULL; + int ret = 0; + char time_str[128]; + + memset_s(time_str, sizeof(time_str), 0, sizeof(time_str)); + ts = dhd_log_dump_get_timestamp(); + snprintf(time_str, sizeof(time_str), + "\n\n ========== LOG DUMP TAKEN AT : %s =========\n", ts); + + /* write the timestamp hdr to the file first */ + ret = dhd_export_debug_data(time_str, fp, user_buf, strlen(time_str), pos); + if (ret < 0) { + DHD_ERROR(("write file error, err = %d\n", ret)); + } + return ret; +} + +#if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT) +int +dhd_print_health_chk_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos) +{ + int ret = BCME_OK; + log_dump_section_hdr_t sec_hdr; + dhd_info_t *dhd_info; + + if (dev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return BCME_ERROR; + + dhd_init_sec_hdr(&sec_hdr); + + if (dhdp->memdump_type == DUMP_TYPE_DONGLE_HOST_EVENT) { + /* write the section header first */ + ret = dhd_export_debug_data(HEALTH_CHK_LOG_HDR, fp, user_buf, + strlen(HEALTH_CHK_LOG_HDR), pos); + if (ret < 0) + goto exit; + + len -= (uint32)strlen(HEALTH_CHK_LOG_HDR); + sec_hdr.type = LOG_DUMP_SECTION_HEALTH_CHK; + sec_hdr.length = HEALTH_CHK_BUF_SIZE; + ret = dhd_export_debug_data((char *)&sec_hdr, fp, user_buf, sizeof(sec_hdr), pos); + if (ret < 0) + goto exit; + + len -= (uint32)sizeof(sec_hdr); + /* write the log */ + ret = dhd_export_debug_data((char *)dhdp->health_chk_event_data, fp, + user_buf, len, pos); + if (ret < 0) + goto exit; + } +exit: + return ret; +} +#endif /* DHD_FW_COREDUMP && DNGL_EVENT_SUPPORT */ + +#if defined(BCMPCIE) +int +dhd_print_ext_trap_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos) +{ + int ret = BCME_OK; + log_dump_section_hdr_t sec_hdr; + dhd_info_t *dhd_info; + + if (dev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return BCME_ERROR; + + dhd_init_sec_hdr(&sec_hdr); + + /* append extended trap data to the file in case of traps */ + if (dhdp->dongle_trap_occured && + dhdp->extended_trap_data) { + /* write the section header first */ + ret = dhd_export_debug_data(EXT_TRAP_LOG_HDR, fp, user_buf, + strlen(EXT_TRAP_LOG_HDR), pos); + if (ret < 0) + goto exit; + + len -= (uint32)strlen(EXT_TRAP_LOG_HDR); + sec_hdr.type = LOG_DUMP_SECTION_EXT_TRAP; + sec_hdr.length = BCMPCIE_EXT_TRAP_DATA_MAXLEN; + ret = dhd_export_debug_data((uint8 *)&sec_hdr, fp, user_buf, sizeof(sec_hdr), pos); + if (ret < 0) + goto exit; + + len -= (uint32)sizeof(sec_hdr); + /* write the log */ + ret = dhd_export_debug_data((uint8 *)dhdp->extended_trap_data, fp, + user_buf, len, pos); + if (ret < 0) + goto exit; + } +exit: + return ret; +} +#endif /* BCMPCIE */ + +int +dhd_print_dump_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos) +{ + int ret = BCME_OK; + log_dump_section_hdr_t sec_hdr; + dhd_info_t *dhd_info; + + if (dev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return BCME_ERROR; + + dhd_init_sec_hdr(&sec_hdr); + + ret = dhd_export_debug_data(DHD_DUMP_LOG_HDR, fp, user_buf, strlen(DHD_DUMP_LOG_HDR), pos); + if (ret < 0) + goto exit; + + len -= (uint32)strlen(DHD_DUMP_LOG_HDR); + sec_hdr.type = LOG_DUMP_SECTION_DHD_DUMP; + sec_hdr.length = len; + ret = dhd_export_debug_data((char *)&sec_hdr, fp, user_buf, sizeof(sec_hdr), pos); + if (ret < 0) + goto exit; + + len -= (uint32)sizeof(sec_hdr); + + if (dhdp->concise_dbg_buf) { + dhd_dump(dhdp, (char *)dhdp->concise_dbg_buf, CONCISE_DUMP_BUFLEN); + ret = dhd_export_debug_data(dhdp->concise_dbg_buf, fp, user_buf, len, pos); + if (ret < 0) + goto exit; + } + +exit: + return ret; +} + +int +dhd_print_cookie_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos) +{ + int ret = BCME_OK; + dhd_info_t *dhd_info; + + if (dev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return BCME_ERROR; + + if (dhdp->logdump_cookie && dhd_logdump_cookie_count(dhdp) > 0) { + ret = dhd_log_dump_cookie_to_file(dhdp, fp, user_buf, (unsigned long *)pos); + } + return ret; +} + +#ifdef DHD_DUMP_PCIE_RINGS +int +dhd_print_flowring_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos) +{ + log_dump_section_hdr_t sec_hdr; + int ret = BCME_OK; + uint16 max_tx_flowrings; + dhd_info_t *dhd_info; + + if (dev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return BCME_ERROR; + + dhd_init_sec_hdr(&sec_hdr); + + /* write the section header first */ + ret = dhd_export_debug_data(RING_DUMP_HDR, fp, user_buf, + strlen(RING_DUMP_HDR), pos); + if (ret < 0) + goto exit; + len -= strlen(RING_DUMP_HDR); + + sec_hdr.type = LOG_DUMP_SECTION_RING; + sec_hdr.length = len - sizeof(sec_hdr); + ret = dhd_export_debug_data((char *)&sec_hdr, fp, user_buf, sizeof(sec_hdr), pos); + if (ret < 0) + goto exit; + + max_tx_flowrings = dhd_get_max_flow_rings(dhdp); + /* write the number of max_tx_flowrings after section header */ + ret = dhd_export_debug_data((char *)&max_tx_flowrings, fp, user_buf, + sizeof(max_tx_flowrings), pos); + if (ret < 0) + goto exit; + + /* write the log */ + ret = dhd_d2h_h2d_ring_dump(dhdp, fp, user_buf, (unsigned long *)pos, TRUE); + if (ret < 0) + goto exit; +exit: + return ret; +} +#endif /* DHD_DUMP_PCIE_RINGS */ + +#ifdef EWP_ECNTRS_LOGGING +int +dhd_print_ecntrs_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos) +{ + log_dump_section_hdr_t sec_hdr; + int ret = BCME_OK; + dhd_info_t *dhd_info; + + if (dev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return BCME_ERROR; + + dhd_init_sec_hdr(&sec_hdr); + + if (logdump_ecntr_enable && + dhdp->ecntr_dbg_ring) { + sec_hdr.type = LOG_DUMP_SECTION_ECNTRS; + ret = dhd_dump_debug_ring(dhdp, dhdp->ecntr_dbg_ring, + user_buf, &sec_hdr, ECNTRS_LOG_HDR, len, LOG_DUMP_SECTION_ECNTRS); + } + return ret; + +} +#endif /* EWP_ECNTRS_LOGGING */ + +#ifdef EWP_RTT_LOGGING +int +dhd_print_rtt_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos) +{ + log_dump_section_hdr_t sec_hdr; + int ret = BCME_OK; + dhd_info_t *dhd_info; + + if (dev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) + return BCME_ERROR; + + dhd_init_sec_hdr(&sec_hdr); + + if (logdump_rtt_enable && dhdp->rtt_dbg_ring) { + ret = dhd_dump_debug_ring(dhdp, dhdp->rtt_dbg_ring, + user_buf, &sec_hdr, RTT_LOG_HDR, len, LOG_DUMP_SECTION_RTT); + } + return ret; + +} +#endif /* EWP_RTT_LOGGING */ + +#ifdef DHD_STATUS_LOGGING +int +dhd_print_status_log_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos) +{ + dhd_info_t *dhd_info; + + if (dev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)dev); + dhdp = &dhd_info->pub; + } + + if (!dhdp) { + return BCME_ERROR; + } + + return dhd_statlog_write_logdump(dhdp, user_buf, fp, len, pos); +} + +uint32 +dhd_get_status_log_len(void *ndev, dhd_pub_t *dhdp) +{ + dhd_info_t *dhd_info; + uint32 length = 0; + + if (ndev) { + dhd_info = *(dhd_info_t **)netdev_priv((struct net_device *)ndev); + dhdp = &dhd_info->pub; + } + + if (dhdp) { + length = dhd_statlog_get_logbuf_len(dhdp); + } + + return length; +} +#endif /* DHD_STATUS_LOGGING */ + +void +dhd_init_sec_hdr(log_dump_section_hdr_t *sec_hdr) +{ + /* prep the section header */ + memset(sec_hdr, 0, sizeof(*sec_hdr)); + sec_hdr->magic = LOG_DUMP_MAGIC; + sec_hdr->timestamp = local_clock(); +} + +/* Must hold 'dhd_os_logdump_lock' before calling this function ! */ +int +do_dhd_log_dump(dhd_pub_t *dhdp, log_dump_type_t *type) +{ + int ret = 0, i = 0; + struct file *fp = NULL; +#ifdef get_fs + mm_segment_t old_fs; +#endif /* get_fs */ + loff_t pos = 0; + char dump_path[128]; + uint32 file_mode; + unsigned long flags = 0; + size_t log_size = 0; + size_t fspace_remain = 0; + struct file *filep = NULL; + int logstrs_size = 0; + char time_str[128]; + unsigned int len = 0; + log_dump_section_hdr_t sec_hdr; + + DHD_ERROR(("%s: ENTER \n", __FUNCTION__)); + + DHD_GENERAL_LOCK(dhdp, flags); + if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp)) { + DHD_GENERAL_UNLOCK(dhdp, flags); + DHD_ERROR(("%s: bus is down! can't collect log dump. \n", __FUNCTION__)); + goto exit1; + } + DHD_BUS_BUSY_SET_IN_LOGDUMP(dhdp); + DHD_GENERAL_UNLOCK(dhdp, flags); + + if ((ret = dhd_log_flush(dhdp, type)) < 0) { + goto exit1; + } +#ifdef get_fs + /* change to KERNEL_DS address limit */ + old_fs = get_fs(); + set_fs(KERNEL_DS); +#endif /* get_fs */ + + dhd_get_debug_dump_file_name(NULL, dhdp, dump_path, sizeof(dump_path)); + + DHD_ERROR(("debug_dump_path = %s\n", dump_path)); + DHD_ERROR(("DHD version: %s\n", dhd_version)); + DHD_ERROR(("F/W version: %s\n", fw_version)); + + dhd_log_dump_buf_addr(dhdp, type); + + dhd_get_time_str(dhdp, time_str, 128); + + /* if this is the first time after dhd is loaded, + * or, if periodic flush is disabled, clear the log file + */ + if (!dhdp->logdump_periodic_flush || dhdp->last_file_posn == 0) + file_mode = O_CREAT | O_WRONLY | O_SYNC | O_TRUNC; + else + file_mode = O_CREAT | O_RDWR | O_SYNC; + + fp = dhd_filp_open(dump_path, file_mode, 0664); + if (IS_ERR(fp) || (fp == NULL)) { + /* If android installed image, try '/data' directory */ +#if defined(CONFIG_X86) && defined(OEM_ANDROID) + DHD_ERROR(("%s: File open error on Installed android image, trying /data...\n", + __FUNCTION__)); + snprintf(dump_path, sizeof(dump_path), "/data/" DHD_DEBUG_DUMP_TYPE); + if (!dhdp->logdump_periodic_flush) { + snprintf(dump_path + strlen(dump_path), + sizeof(dump_path) - strlen(dump_path), + "_%s", dhdp->debug_dump_time_str); + } + fp = dhd_filp_open(dump_path, file_mode, 0664); + if (IS_ERR(fp) || (fp == NULL)) { + ret = PTR_ERR(fp); + DHD_ERROR(("open file error, err = %d\n", ret)); + goto exit2; + } + DHD_ERROR(("debug_dump_path = %s\n", dump_path)); +#else + ret = PTR_ERR(fp); + DHD_ERROR(("open file error, err = %d\n", ret)); + goto exit2; +#endif /* CONFIG_X86 && OEM_ANDROID */ + } + + filep = dhd_filp_open(dump_path, O_RDONLY, 0); + + if (IS_ERR(filep) || (filep == NULL)) { + DHD_ERROR(("file stat error, err = %d\n", ret)); + goto exit2; + } + logstrs_size = dhd_vfs_size_read(filep); + /* if some one else has changed the file */ + if (dhdp->last_file_posn != 0 && + logstrs_size < dhdp->last_file_posn) { + dhdp->last_file_posn = 0; + } + + /* XXX: periodic flush is disabled by default, if enabled + * only periodic flushing of 'GENERAL' log dump buffer + * is supported, its not recommended to turn on periodic + * flushing, except for developer unit test. + */ + if (dhdp->logdump_periodic_flush) { + log_size = strlen(time_str) + strlen(DHD_DUMP_LOG_HDR) + sizeof(sec_hdr); + /* calculate the amount of space required to dump all logs */ + for (i = 0; i < DLD_BUFFER_NUM; ++i) { + if (*type != DLD_BUF_TYPE_ALL && i != *type) + continue; + + if (g_dld_buf[i].wraparound) { + log_size += (unsigned long)g_dld_buf[i].max + - (unsigned long)g_dld_buf[i].buffer; + } else { + DHD_LOG_DUMP_BUF_LOCK(&g_dld_buf[i].lock, flags); + log_size += (unsigned long)g_dld_buf[i].present - + (unsigned long)g_dld_buf[i].front; + DHD_LOG_DUMP_BUF_UNLOCK(&g_dld_buf[i].lock, flags); + } + log_size += strlen(dld_hdrs[i].hdr_str) + sizeof(sec_hdr); + + if (*type != DLD_BUF_TYPE_ALL && i == *type) + break; + } + + ret = generic_file_llseek(fp, dhdp->last_file_posn, SEEK_CUR); + if (ret < 0) { + DHD_ERROR(("file seek last posn error ! err = %d \n", ret)); + goto exit2; + } + pos = fp->f_pos; + + /* if the max file size is reached, wrap around to beginning of the file + * we're treating the file as a large ring buffer + */ + fspace_remain = logdump_max_filesize - pos; + if (log_size > fspace_remain) { + fp->f_pos -= pos; + pos = fp->f_pos; + } + } + + dhd_print_time_str(0, fp, len, &pos); + + for (i = 0; i < DLD_BUFFER_NUM; ++i) { + + if (*type != DLD_BUF_TYPE_ALL && i != *type) + continue; + + len = dhd_get_dld_len(i); + dhd_get_dld_log_dump(NULL, dhdp, 0, fp, len, i, &pos); + if (*type != DLD_BUF_TYPE_ALL) + break; + } + +#ifdef EWP_ECNTRS_LOGGING + if (*type == DLD_BUF_TYPE_ALL && + logdump_ecntr_enable && + dhdp->ecntr_dbg_ring) { + dhd_log_dump_ring_to_file(dhdp, dhdp->ecntr_dbg_ring, + fp, (unsigned long *)&pos, + &sec_hdr, ECNTRS_LOG_HDR, LOG_DUMP_SECTION_ECNTRS); + } +#endif /* EWP_ECNTRS_LOGGING */ + +#ifdef DHD_STATUS_LOGGING + if (dhdp->statlog) { + /* write the statlog */ + len = dhd_get_status_log_len(NULL, dhdp); + if (len) { + if (dhd_print_status_log_data(NULL, dhdp, 0, fp, + len, &pos) < 0) { + goto exit2; + } + } + } +#endif /* DHD_STATUS_LOGGING */ + +#ifdef DHD_STATUS_LOGGING + if (dhdp->statlog) { + dhd_print_buf_addr(dhdp, "statlog_logbuf", dhd_statlog_get_logbuf(dhdp), + dhd_statlog_get_logbuf_len(dhdp)); + } +#endif /* DHD_STATUS_LOGGING */ + +#ifdef EWP_RTT_LOGGING + if (*type == DLD_BUF_TYPE_ALL && + logdump_rtt_enable && + dhdp->rtt_dbg_ring) { + dhd_log_dump_ring_to_file(dhdp, dhdp->rtt_dbg_ring, + fp, (unsigned long *)&pos, + &sec_hdr, RTT_LOG_HDR, LOG_DUMP_SECTION_RTT); + } +#endif /* EWP_RTT_LOGGING */ + +#ifdef EWP_BCM_TRACE + if (*type == DLD_BUF_TYPE_ALL && + dhdp->bcm_trace_dbg_ring) { + dhd_log_dump_ring_to_file(dhdp, dhdp->bcm_trace_dbg_ring, + fp, (unsigned long *)&pos, + &sec_hdr, BCM_TRACE_LOG_HDR, LOG_DUMP_SECTION_BCM_TRACE); + } +#endif /* EWP_BCM_TRACE */ + +#ifdef BCMPCIE + len = dhd_get_ext_trap_len(NULL, dhdp); + if (len) { + if (dhd_print_ext_trap_data(NULL, dhdp, 0, fp, len, &pos) < 0) + goto exit2; + } +#endif /* BCMPCIE */ + +#if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT) + len = dhd_get_health_chk_len(NULL, dhdp); + if (len) { + if (dhd_print_health_chk_data(NULL, dhdp, 0, fp, len, &pos) < 0) + goto exit2; + } +#endif /* DHD_FW_COREDUMP && DNGL_EVENT_SUPPORT */ + + len = dhd_get_dhd_dump_len(NULL, dhdp); + if (len) { + if (dhd_print_dump_data(NULL, dhdp, 0, fp, len, &pos) < 0) + goto exit2; + } + + len = dhd_get_cookie_log_len(NULL, dhdp); + if (len) { + if (dhd_print_cookie_data(NULL, dhdp, 0, fp, len, &pos) < 0) + goto exit2; + } + +#ifdef DHD_DUMP_PCIE_RINGS + len = dhd_get_flowring_len(NULL, dhdp); + if (len) { + if (dhd_print_flowring_data(NULL, dhdp, 0, fp, len, &pos) < 0) + goto exit2; + } +#endif + + if (dhdp->logdump_periodic_flush) { + /* store the last position written to in the file for future use */ + dhdp->last_file_posn = pos; + } + +exit2: + if (!IS_ERR(fp) && fp != NULL) { + dhd_filp_close(fp, NULL); + DHD_ERROR(("%s: Finished writing log dump to file - '%s' \n", + __FUNCTION__, dump_path)); + } +#ifdef get_fs + set_fs(old_fs); +#endif /* get_fs */ +exit1: + if (type) { + MFREE(dhdp->osh, type, sizeof(*type)); + } + DHD_GENERAL_LOCK(dhdp, flags); + DHD_BUS_BUSY_CLEAR_IN_LOGDUMP(dhdp); + dhd_os_busbusy_wake(dhdp); + DHD_GENERAL_UNLOCK(dhdp, flags); + +#ifdef DHD_DUMP_MNGR + if (ret >= 0) { + dhd_dump_file_manage_enqueue(dhdp, dump_path, DHD_DEBUG_DUMP_TYPE); + } +#endif /* DHD_DUMP_MNGR */ + + return (ret < 0) ? BCME_ERROR : BCME_OK; +} + +bool +dhd_log_dump_ecntr_enabled(void) +{ + return (bool)logdump_ecntr_enable; +} + +bool +dhd_log_dump_rtt_enabled(void) +{ + return (bool)logdump_rtt_enable; +} + +void +dhd_log_dump_init(dhd_pub_t *dhd) +{ + struct dhd_log_dump_buf *dld_buf, *dld_buf_special; + int i = 0; + uint8 *prealloc_buf = NULL, *bufptr = NULL; +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) + int prealloc_idx = DHD_PREALLOC_DHD_LOG_DUMP_BUF; +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ + int ret; + dhd_dbg_ring_t *ring = NULL; + unsigned long flags = 0; + dhd_info_t *dhd_info = dhd->info; +#if defined(EWP_ECNTRS_LOGGING) + void *cookie_buf = NULL; +#endif + + BCM_REFERENCE(ret); + BCM_REFERENCE(ring); + BCM_REFERENCE(flags); + + /* sanity check */ + if (logdump_prsrv_tailsize <= 0 || + logdump_prsrv_tailsize > DHD_LOG_DUMP_MAX_TAIL_FLUSH_SIZE) { + logdump_prsrv_tailsize = DHD_LOG_DUMP_MAX_TAIL_FLUSH_SIZE; + } + /* now adjust the preserve log flush size based on the + * kernel printk log buffer size + */ +#ifdef CONFIG_LOG_BUF_SHIFT + DHD_ERROR(("%s: kernel log buf size = %uKB; logdump_prsrv_tailsize = %uKB;" + " limit prsrv tail size to = %uKB\n", + __FUNCTION__, (1 << CONFIG_LOG_BUF_SHIFT)/1024, + logdump_prsrv_tailsize/1024, LOG_DUMP_KERNEL_TAIL_FLUSH_SIZE/1024)); + + if (logdump_prsrv_tailsize > LOG_DUMP_KERNEL_TAIL_FLUSH_SIZE) { + logdump_prsrv_tailsize = LOG_DUMP_KERNEL_TAIL_FLUSH_SIZE; + } +#else + DHD_ERROR(("%s: logdump_prsrv_tailsize = %uKB \n", + __FUNCTION__, logdump_prsrv_tailsize/1024)); +#endif /* CONFIG_LOG_BUF_SHIFT */ + + mutex_init(&dhd_info->logdump_lock); + /* initialize log dump buf structures */ + memset(g_dld_buf, 0, sizeof(struct dhd_log_dump_buf) * DLD_BUFFER_NUM); + + /* set the log dump buffer size based on the module_param */ + if (logdump_max_bufsize > LOG_DUMP_GENERAL_MAX_BUFSIZE || + logdump_max_bufsize <= 0) + dld_buf_size[DLD_BUF_TYPE_GENERAL] = LOG_DUMP_GENERAL_MAX_BUFSIZE; + else + dld_buf_size[DLD_BUF_TYPE_GENERAL] = logdump_max_bufsize; + + /* pre-alloc the memory for the log buffers & 'special' buffer */ + dld_buf_special = &g_dld_buf[DLD_BUF_TYPE_SPECIAL]; +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) + prealloc_buf = DHD_OS_PREALLOC(dhd, prealloc_idx++, LOG_DUMP_TOTAL_BUFSIZE); + dld_buf_special->buffer = DHD_OS_PREALLOC(dhd, prealloc_idx++, + dld_buf_size[DLD_BUF_TYPE_SPECIAL]); +#else + prealloc_buf = MALLOCZ(dhd->osh, LOG_DUMP_TOTAL_BUFSIZE); + dld_buf_special->buffer = MALLOCZ(dhd->osh, dld_buf_size[DLD_BUF_TYPE_SPECIAL]); +#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ + + if (!prealloc_buf) { + DHD_ERROR(("Failed to allocate memory for log buffers\n")); + goto fail; + } + if (!dld_buf_special->buffer) { + DHD_ERROR(("Failed to allocate memory for special buffer\n")); + goto fail; + } + + bufptr = prealloc_buf; + for (i = 0; i < DLD_BUFFER_NUM; i++) { + dld_buf = &g_dld_buf[i]; + dld_buf->dhd_pub = dhd; + spin_lock_init(&dld_buf->lock); + dld_buf->wraparound = 0; + if (i != DLD_BUF_TYPE_SPECIAL) { + dld_buf->buffer = bufptr; + dld_buf->max = (unsigned long)dld_buf->buffer + dld_buf_size[i]; + bufptr = (uint8 *)dld_buf->max; + } else { + dld_buf->max = (unsigned long)dld_buf->buffer + dld_buf_size[i]; + } + dld_buf->present = dld_buf->front = dld_buf->buffer; + dld_buf->remain = dld_buf_size[i]; + dld_buf->enable = 1; + } + + /* now use the rest of the pre-alloc'd memory for other rings */ +#ifdef EWP_ECNTRS_LOGGING + dhd->ecntr_dbg_ring = dhd_dbg_ring_alloc_init(dhd, + ECNTR_RING_ID, ECNTR_RING_NAME, + LOG_DUMP_ECNTRS_MAX_BUFSIZE, + bufptr, TRUE); + if (!dhd->ecntr_dbg_ring) { + DHD_ERROR(("%s: unable to init ecounters dbg ring !\n", + __FUNCTION__)); + goto fail; + } + bufptr += LOG_DUMP_ECNTRS_MAX_BUFSIZE; +#endif /* EWP_ECNTRS_LOGGING */ + +#ifdef EWP_RTT_LOGGING + dhd->rtt_dbg_ring = dhd_dbg_ring_alloc_init(dhd, + RTT_RING_ID, RTT_RING_NAME, + LOG_DUMP_RTT_MAX_BUFSIZE, + bufptr, TRUE); + if (!dhd->rtt_dbg_ring) { + DHD_ERROR(("%s: unable to init rtt dbg ring !\n", + __FUNCTION__)); + goto fail; + } + bufptr += LOG_DUMP_RTT_MAX_BUFSIZE; +#endif /* EWP_RTT_LOGGING */ + +#ifdef EWP_BCM_TRACE + dhd->bcm_trace_dbg_ring = dhd_dbg_ring_alloc_init(dhd, + BCM_TRACE_RING_ID, BCM_TRACE_RING_NAME, + LOG_DUMP_BCM_TRACE_MAX_BUFSIZE, + bufptr, TRUE); + if (!dhd->bcm_trace_dbg_ring) { + DHD_ERROR(("%s: unable to init bcm trace dbg ring !\n", + __FUNCTION__)); + goto fail; + } + bufptr += LOG_DUMP_BCM_TRACE_MAX_BUFSIZE; +#endif /* EWP_BCM_TRACE */ + + /* Concise buffer is used as intermediate buffer for following purposes + * a) pull ecounters records temporarily before + * writing it to file + * b) to store dhd dump data before putting it to file + * It should have a size equal to + * MAX(largest possible ecntr record, 'dhd dump' data size) + */ + dhd->concise_dbg_buf = MALLOC(dhd->osh, CONCISE_DUMP_BUFLEN); + if (!dhd->concise_dbg_buf) { + DHD_ERROR(("%s: unable to alloc mem for concise debug info !\n", + __FUNCTION__)); + goto fail; + } + +#if defined(DHD_EVENT_LOG_FILTER) + /* XXX init filter last, because filter use buffer which alloced by log dump */ + ret = dhd_event_log_filter_init(dhd, + bufptr, + LOG_DUMP_FILTER_MAX_BUFSIZE); + if (ret != BCME_OK) { + goto fail; + } +#endif /* DHD_EVENT_LOG_FILTER */ + +#if defined(EWP_ECNTRS_LOGGING) + cookie_buf = MALLOC(dhd->osh, LOG_DUMP_COOKIE_BUFSIZE); + if (!cookie_buf) { + DHD_ERROR(("%s: unable to alloc mem for logdump cookie buffer\n", + __FUNCTION__)); + goto fail; + } + + ret = dhd_logdump_cookie_init(dhd, cookie_buf, LOG_DUMP_COOKIE_BUFSIZE); + if (ret != BCME_OK) { + MFREE(dhd->osh, cookie_buf, LOG_DUMP_COOKIE_BUFSIZE); + goto fail; + } +#endif /* EWP_ECNTRS_LOGGING */ + return; + +fail: + +#if defined(DHD_EVENT_LOG_FILTER) + /* XXX deinit filter first, because filter use buffer which alloced by log dump */ + if (dhd->event_log_filter) { + dhd_event_log_filter_deinit(dhd); + } +#endif /* DHD_EVENT_LOG_FILTER */ + + if (dhd->concise_dbg_buf) { + MFREE(dhd->osh, dhd->concise_dbg_buf, CONCISE_DUMP_BUFLEN); + } + +#ifdef EWP_ECNTRS_LOGGING + if (dhd->logdump_cookie) { + dhd_logdump_cookie_deinit(dhd); + MFREE(dhd->osh, dhd->logdump_cookie, LOG_DUMP_COOKIE_BUFSIZE); + dhd->logdump_cookie = NULL; + } +#endif /* EWP_ECNTRS_LOGGING */ + +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) + if (prealloc_buf) { + DHD_OS_PREFREE(dhd, prealloc_buf, LOG_DUMP_TOTAL_BUFSIZE); + } + if (dld_buf_special->buffer) { + DHD_OS_PREFREE(dhd, dld_buf_special->buffer, + dld_buf_size[DLD_BUF_TYPE_SPECIAL]); + } +#else + if (prealloc_buf) { + MFREE(dhd->osh, prealloc_buf, LOG_DUMP_TOTAL_BUFSIZE); + } + if (dld_buf_special->buffer) { + MFREE(dhd->osh, dld_buf_special->buffer, + dld_buf_size[DLD_BUF_TYPE_SPECIAL]); + } +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + for (i = 0; i < DLD_BUFFER_NUM; i++) { + dld_buf = &g_dld_buf[i]; + dld_buf->enable = 0; + dld_buf->buffer = NULL; + } + mutex_destroy(&dhd_info->logdump_lock); +} + +void +dhd_log_dump_deinit(dhd_pub_t *dhd) +{ + struct dhd_log_dump_buf *dld_buf = NULL, *dld_buf_special = NULL; + int i = 0; + dhd_info_t *dhd_info = dhd->info; + dhd_dbg_ring_t *ring = NULL; + + BCM_REFERENCE(ring); + + if (dhd->concise_dbg_buf) { + MFREE(dhd->osh, dhd->concise_dbg_buf, CONCISE_DUMP_BUFLEN); + dhd->concise_dbg_buf = NULL; + } + +#ifdef EWP_ECNTRS_LOGGING + if (dhd->logdump_cookie) { + dhd_logdump_cookie_deinit(dhd); + MFREE(dhd->osh, dhd->logdump_cookie, LOG_DUMP_COOKIE_BUFSIZE); + dhd->logdump_cookie = NULL; + } + + if (dhd->ecntr_dbg_ring) { + dhd_dbg_ring_dealloc_deinit(&dhd->ecntr_dbg_ring, dhd); + } +#endif /* EWP_ECNTRS_LOGGING */ + +#ifdef EWP_RTT_LOGGING + if (dhd->rtt_dbg_ring) { + dhd_dbg_ring_dealloc_deinit(&dhd->rtt_dbg_ring, dhd); + } +#endif /* EWP_RTT_LOGGING */ + +#ifdef EWP_BCM_TRACE + if (dhd->bcm_trace_dbg_ring) { + dhd_dbg_ring_dealloc_deinit(&dhd->bcm_trace_dbg_ring, dhd); + } +#endif /* EWP_BCM_TRACE */ + + /* 'general' buffer points to start of the pre-alloc'd memory */ + dld_buf = &g_dld_buf[DLD_BUF_TYPE_GENERAL]; + dld_buf_special = &g_dld_buf[DLD_BUF_TYPE_SPECIAL]; +#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) + if (dld_buf->buffer) { + DHD_OS_PREFREE(dhd, dld_buf->buffer, LOG_DUMP_TOTAL_BUFSIZE); + } + if (dld_buf_special->buffer) { + DHD_OS_PREFREE(dhd, dld_buf_special->buffer, + dld_buf_size[DLD_BUF_TYPE_SPECIAL]); + } +#else + if (dld_buf->buffer) { + MFREE(dhd->osh, dld_buf->buffer, LOG_DUMP_TOTAL_BUFSIZE); + } + if (dld_buf_special->buffer) { + MFREE(dhd->osh, dld_buf_special->buffer, + dld_buf_size[DLD_BUF_TYPE_SPECIAL]); + } +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + for (i = 0; i < DLD_BUFFER_NUM; i++) { + dld_buf = &g_dld_buf[i]; + dld_buf->enable = 0; + dld_buf->buffer = NULL; + } + mutex_destroy(&dhd_info->logdump_lock); +} + +void +dhd_log_dump_write(int type, char *binary_data, + int binary_len, const char *fmt, ...) +{ + int len = 0; + char tmp_buf[DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE] = {0, }; + va_list args; + unsigned long flags = 0; + struct dhd_log_dump_buf *dld_buf = NULL; + bool flush_log = FALSE; + + if (type < 0 || type >= DLD_BUFFER_NUM) { + DHD_INFO(("%s: Unsupported DHD_LOG_DUMP_BUF_TYPE(%d).\n", + __FUNCTION__, type)); + return; + } + + dld_buf = &g_dld_buf[type]; + if (dld_buf->enable != 1) { + return; + } + + va_start(args, fmt); + len = vsnprintf(tmp_buf, DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE, fmt, args); + /* Non ANSI C99 compliant returns -1, + * ANSI compliant return len >= DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE + */ + va_end(args); + if (len < 0) { + return; + } + + if (len >= DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE) { + len = DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE - 1; + tmp_buf[len] = '\0'; + } + + /* make a critical section to eliminate race conditions */ + DHD_LOG_DUMP_BUF_LOCK(&dld_buf->lock, flags); + if (dld_buf->remain < len) { + dld_buf->wraparound = 1; + dld_buf->present = dld_buf->front; + dld_buf->remain = dld_buf_size[type]; + /* if wrap around happens, flush the ring buffer to the file */ + flush_log = TRUE; + } + + memcpy(dld_buf->present, tmp_buf, len); + dld_buf->remain -= len; + dld_buf->present += len; + DHD_LOG_DUMP_BUF_UNLOCK(&dld_buf->lock, flags); + + /* double check invalid memory operation */ + ASSERT((unsigned long)dld_buf->present <= dld_buf->max); + + if (dld_buf->dhd_pub) { + dhd_pub_t *dhdp = (dhd_pub_t *)dld_buf->dhd_pub; + dhdp->logdump_periodic_flush = + logdump_periodic_flush; + if (logdump_periodic_flush && flush_log) { + log_dump_type_t *flush_type = MALLOCZ(dhdp->osh, + sizeof(log_dump_type_t)); + if (flush_type) { + *flush_type = type; + dhd_schedule_log_dump(dld_buf->dhd_pub, flush_type); + } + } + } +} + +void +dhd_log_dump_vendor_trigger(dhd_pub_t *dhd_pub) +{ + unsigned long flags = 0; + DHD_GENERAL_LOCK(dhd_pub, flags); + DHD_BUS_BUSY_SET_IN_DUMP_DONGLE_MEM(dhd_pub); + DHD_GENERAL_UNLOCK(dhd_pub, flags); + + dhd_log_dump_trigger(dhd_pub, CMD_DEFAULT); + + DHD_GENERAL_LOCK(dhd_pub, flags); + DHD_BUS_BUSY_CLEAR_IN_DUMP_DONGLE_MEM(dhd_pub); + dhd_os_busbusy_wake(dhd_pub); + DHD_GENERAL_UNLOCK(dhd_pub, flags); + + return; +} + +void +dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd) +{ +#if defined(DHD_DUMP_FILE_WRITE_FROM_KERNEL) + log_dump_type_t *flush_type; +#endif /* DHD_DUMP_FILE_WRITE_FROM_KERNEL */ + uint64 current_time_sec; + + if (!dhdp) { + DHD_ERROR(("dhdp is NULL !\n")); + return; + } + + if (subcmd >= CMD_MAX || subcmd < CMD_DEFAULT) { + DHD_ERROR(("%s : Invalid subcmd \n", __FUNCTION__)); + return; + } + + current_time_sec = DIV_U64_BY_U32(OSL_LOCALTIME_NS(), NSEC_PER_SEC); + + DHD_ERROR(("%s: current_time_sec=%lld debug_dump_time_sec=%lld interval=%d\n", + __FUNCTION__, current_time_sec, dhdp->debug_dump_time_sec, + DEBUG_DUMP_TRIGGER_INTERVAL_SEC)); + + if ((current_time_sec - dhdp->debug_dump_time_sec) < DEBUG_DUMP_TRIGGER_INTERVAL_SEC) { + DHD_ERROR(("%s : Last debug dump triggered(%lld) within %d seconds, so SKIP\n", + __FUNCTION__, dhdp->debug_dump_time_sec, DEBUG_DUMP_TRIGGER_INTERVAL_SEC)); + return; + } + + clear_debug_dump_time(dhdp->debug_dump_time_str); + /* */ + + dhdp->debug_dump_subcmd = subcmd; + + dhdp->debug_dump_time_sec = DIV_U64_BY_U32(OSL_LOCALTIME_NS(), NSEC_PER_SEC); + +#if defined(DHD_DUMP_FILE_WRITE_FROM_KERNEL) + /* flush_type is freed at do_dhd_log_dump function */ + flush_type = MALLOCZ(dhdp->osh, sizeof(log_dump_type_t)); + if (flush_type) { + *flush_type = DLD_BUF_TYPE_ALL; + dhd_schedule_log_dump(dhdp, flush_type); + } else { + DHD_ERROR(("%s Fail to malloc flush_type\n", __FUNCTION__)); + return; + } +#endif /* DHD_DUMP_FILE_WRITE_FROM_KERNEL */ + +#if defined(DHD_SDTC_ETB_DUMP) && defined(BCMQT_HW) + /* For QT/zebu memdump collection is disabled, + * but set collect_sdtc true here, so that + * developers can issue 'log_dump' dhd iovar + * to get etb/sdtc dumps + */ + DHD_ERROR(("%s : QT/FPGA set collect_sdtc as TRUE\n", __FUNCTION__)); + dhdp->collect_sdtc = TRUE; +#endif /* DHD_SDTC_ETB_DUMP && BCMQT_HW */ + + /* Inside dhd_mem_dump, event notification will be sent to HAL and + * from other context DHD pushes memdump, debug_dump and pktlog dump + * to HAL and HAL will write into file + */ +#if (defined(BCMPCIE) || defined(BCMSDIO)) && defined(DHD_FW_COREDUMP) + dhdp->memdump_type = DUMP_TYPE_BY_SYSDUMP; + dhd_bus_mem_dump(dhdp); +#endif /* BCMPCIE && DHD_FW_COREDUMP */ + +#if defined(DHD_PKT_LOGGING) && defined(DHD_DUMP_FILE_WRITE_FROM_KERNEL) + dhd_schedule_pktlog_dump(dhdp); +#endif /* DHD_PKT_LOGGING && DHD_DUMP_FILE_WRITE_FROM_KERNEL */ +} + +#ifdef DHD_DEBUGABILITY_DEBUG_DUMP +int dhd_debug_dump_get_ring_num(int sec_type) +{ + int idx = 0; + for (idx = 0; idx < ARRAYSIZE(dhd_debug_dump_ring_map); idx++) { + if (dhd_debug_dump_ring_map[idx].type == sec_type) { + idx = dhd_debug_dump_ring_map[idx].debug_dump_ring; + return idx; + } + } + return idx; +} +#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */ + +int +dhd_dump_debug_ring(dhd_pub_t *dhdp, void *ring_ptr, const void *user_buf, + log_dump_section_hdr_t *sec_hdr, + char *text_hdr, int buflen, uint32 sec_type) +{ + uint32 rlen = 0; + uint32 data_len = 0; + void *data = NULL; + unsigned long flags = 0; + int ret = 0; + dhd_dbg_ring_t *ring = (dhd_dbg_ring_t *)ring_ptr; +#ifndef DHD_DEBUGABILITY_DEBUG_DUMP + int pos = 0; +#endif /* !DHD_DEBUGABILITY_DEBUG_DUMP */ + int fpos_sechdr = 0; + int tot_len = 0; + char *tmp_buf = NULL; + int idx; + int ring_num = 0; + + BCM_REFERENCE(idx); + BCM_REFERENCE(tot_len); + BCM_REFERENCE(fpos_sechdr); + BCM_REFERENCE(data_len); + BCM_REFERENCE(tmp_buf); + BCM_REFERENCE(ring_num); + +#ifdef DHD_DEBUGABILITY_DEBUG_DUMP + if (!dhdp || !ring || !sec_hdr || !text_hdr) { + return BCME_BADARG; + } + + tmp_buf = (char *)VMALLOCZ(dhdp->osh, ring->ring_size); + if (!tmp_buf) { + DHD_ERROR(("%s: VMALLOC Fail id:%d size:%u\n", + __func__, ring->id, ring->ring_size)); + return BCME_NOMEM; + } +#else + if (!dhdp || !ring || !user_buf || !sec_hdr || !text_hdr) { + return BCME_BADARG; + } +#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */ + /* do not allow further writes to the ring + * till we flush it + */ + DHD_DBG_RING_LOCK(ring->lock, flags); + ring->state = RING_SUSPEND; + DHD_DBG_RING_UNLOCK(ring->lock, flags); + +#ifdef DHD_DEBUGABILITY_DEBUG_DUMP + ring_num = dhd_debug_dump_get_ring_num(sec_type); + dhd_export_debug_data(text_hdr, NULL, NULL, strlen(text_hdr), &ring_num); + + data = tmp_buf; + do { + rlen = dhd_dbg_ring_pull_single(ring, data, ring->ring_size, TRUE); + if (rlen > 0) { + tot_len += rlen; + data += rlen; + } + } while ((rlen > 0)); + + sec_hdr->type = sec_type; + sec_hdr->length = tot_len; + DHD_ERROR(("%s: DUMP id:%d type:%u tot_len:%d\n", __func__, ring->id, sec_type, tot_len)); + + dhd_export_debug_data((char *)sec_hdr, NULL, NULL, sizeof(*sec_hdr), &ring_num); + dhd_export_debug_data(tmp_buf, NULL, NULL, tot_len, &ring_num); + + VMFREE(dhdp->osh, tmp_buf, ring->ring_size); +#else + if (dhdp->concise_dbg_buf) { + /* re-use concise debug buffer temporarily + * to pull ring data, to write + * record by record to file + */ + data_len = CONCISE_DUMP_BUFLEN; + data = dhdp->concise_dbg_buf; + ret = dhd_export_debug_data(text_hdr, NULL, user_buf, strlen(text_hdr), &pos); + /* write the section header now with zero length, + * once the correct length is found out, update + * it later + */ + fpos_sechdr = pos; + sec_hdr->type = sec_type; + sec_hdr->length = 0; + ret = dhd_export_debug_data((char *)sec_hdr, NULL, user_buf, + sizeof(*sec_hdr), &pos); + do { + rlen = dhd_dbg_ring_pull_single(ring, data, data_len, TRUE); + if (rlen > 0) { + /* write the log */ + ret = dhd_export_debug_data(data, NULL, user_buf, rlen, &pos); + } + DHD_DBGIF(("%s: rlen : %d\n", __FUNCTION__, rlen)); + } while ((rlen > 0)); + /* now update the section header length in the file */ + /* Complete ring size is dumped by HAL, hence updating length to ring size */ + sec_hdr->length = ring->ring_size; + ret = dhd_export_debug_data((char *)sec_hdr, NULL, user_buf, + sizeof(*sec_hdr), &fpos_sechdr); + } else { + DHD_ERROR(("%s: No concise buffer available !\n", __FUNCTION__)); + } +#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */ + + DHD_DBG_RING_LOCK(ring->lock, flags); + ring->state = RING_ACTIVE; + /* Resetting both read and write pointer, + * since all items are read. + */ + ring->rp = ring->wp = 0; + DHD_DBG_RING_UNLOCK(ring->lock, flags); + + return ret; +} + +int +dhd_log_dump_ring_to_file(dhd_pub_t *dhdp, void *ring_ptr, void *file, + unsigned long *file_posn, log_dump_section_hdr_t *sec_hdr, + char *text_hdr, uint32 sec_type) +{ + uint32 rlen = 0; + uint32 data_len = 0, total_len = 0; + void *data = NULL; + unsigned long fpos_sechdr = 0; + unsigned long flags = 0; + int ret = 0; + dhd_dbg_ring_t *ring = (dhd_dbg_ring_t *)ring_ptr; + + if (!dhdp || !ring || !file || !sec_hdr || + !file_posn || !text_hdr) + return BCME_BADARG; + + /* do not allow further writes to the ring + * till we flush it + */ + DHD_DBG_RING_LOCK(ring->lock, flags); + ring->state = RING_SUSPEND; + DHD_DBG_RING_UNLOCK(ring->lock, flags); + + if (dhdp->concise_dbg_buf) { + /* re-use concise debug buffer temporarily + * to pull ring data, to write + * record by record to file + */ + data_len = CONCISE_DUMP_BUFLEN; + data = dhdp->concise_dbg_buf; + dhd_os_write_file_posn(file, file_posn, text_hdr, + strlen(text_hdr)); + /* write the section header now with zero length, + * once the correct length is found out, update + * it later + */ + dhd_init_sec_hdr(sec_hdr); + fpos_sechdr = *file_posn; + sec_hdr->type = sec_type; + sec_hdr->length = 0; + dhd_os_write_file_posn(file, file_posn, (char *)sec_hdr, + sizeof(*sec_hdr)); + do { + rlen = dhd_dbg_ring_pull_single(ring, data, data_len, TRUE); + if (rlen > 0) { + /* write the log */ + ret = dhd_os_write_file_posn(file, file_posn, data, rlen); + if (ret < 0) { + DHD_ERROR(("%s: write file error !\n", __FUNCTION__)); + DHD_DBG_RING_LOCK(ring->lock, flags); + ring->state = RING_ACTIVE; + DHD_DBG_RING_UNLOCK(ring->lock, flags); + return BCME_ERROR; + } + } + total_len += rlen; + } while (rlen > 0); + /* now update the section header length in the file */ + sec_hdr->length = total_len; + dhd_os_write_file_posn(file, &fpos_sechdr, (char *)sec_hdr, sizeof(*sec_hdr)); + } else { + DHD_ERROR(("%s: No concise buffer available !\n", __FUNCTION__)); + } + + DHD_DBG_RING_LOCK(ring->lock, flags); + ring->state = RING_ACTIVE; + /* Resetting both read and write pointer, + * since all items are read. + */ + ring->rp = ring->wp = 0; + DHD_DBG_RING_UNLOCK(ring->lock, flags); + return BCME_OK; +} + +/* logdump cookie */ +#define MAX_LOGUDMP_COOKIE_CNT 10u +#define LOGDUMP_COOKIE_STR_LEN 50u +int +dhd_logdump_cookie_init(dhd_pub_t *dhdp, uint8 *buf, uint32 buf_size) +{ + uint32 ring_size; + + if (!dhdp || !buf) { + DHD_ERROR(("INVALID PTR: dhdp:%p buf:%p\n", dhdp, buf)); + return BCME_ERROR; + } + + ring_size = dhd_ring_get_hdr_size() + LOGDUMP_COOKIE_STR_LEN * MAX_LOGUDMP_COOKIE_CNT; + if (buf_size < ring_size) { + DHD_ERROR(("BUF SIZE IS TO SHORT: req:%d buf_size:%d\n", + ring_size, buf_size)); + return BCME_ERROR; + } + + dhdp->logdump_cookie = dhd_ring_init(dhdp, buf, buf_size, + LOGDUMP_COOKIE_STR_LEN, MAX_LOGUDMP_COOKIE_CNT, + DHD_RING_TYPE_FIXED); + if (!dhdp->logdump_cookie) { + DHD_ERROR(("FAIL TO INIT COOKIE RING\n")); + return BCME_ERROR; + } + + return BCME_OK; +} + +void +dhd_logdump_cookie_deinit(dhd_pub_t *dhdp) +{ + if (!dhdp) { + return; + } + if (dhdp->logdump_cookie) { + dhd_ring_deinit(dhdp, dhdp->logdump_cookie); + } + + return; +} + +void +dhd_logdump_cookie_save(dhd_pub_t *dhdp, char *cookie, char *type) +{ + char *ptr; + + if (!dhdp || !cookie || !type || !dhdp->logdump_cookie) { + DHD_ERROR(("%s: At least one buffer ptr is NULL dhdp=%p cookie=%p" + " type = %p, cookie_cfg:%p\n", __FUNCTION__, + dhdp, cookie, type, dhdp?dhdp->logdump_cookie: NULL)); + return; + } + ptr = (char *)dhd_ring_get_empty(dhdp->logdump_cookie); + if (ptr == NULL) { + DHD_ERROR(("%s : Skip to save due to locking\n", __FUNCTION__)); + return; + } + scnprintf(ptr, LOGDUMP_COOKIE_STR_LEN, "%s: %s\n", type, cookie); + return; +} + +int +dhd_logdump_cookie_get(dhd_pub_t *dhdp, char *ret_cookie, uint32 buf_size) +{ + char *ptr; + + if (!dhdp || !ret_cookie || !dhdp->logdump_cookie) { + DHD_ERROR(("%s: At least one buffer ptr is NULL dhdp=%p" + "cookie=%p cookie_cfg:%p\n", __FUNCTION__, + dhdp, ret_cookie, dhdp?dhdp->logdump_cookie: NULL)); + return BCME_ERROR; + } + ptr = (char *)dhd_ring_get_first(dhdp->logdump_cookie); + if (ptr == NULL) { + DHD_ERROR(("%s : Skip to save due to locking\n", __FUNCTION__)); + return BCME_ERROR; + } + memcpy(ret_cookie, ptr, MIN(buf_size, strlen(ptr))); + dhd_ring_free_first(dhdp->logdump_cookie); + return BCME_OK; +} + +int +dhd_logdump_cookie_count(dhd_pub_t *dhdp) +{ + if (!dhdp || !dhdp->logdump_cookie) { + DHD_ERROR(("%s: At least one buffer ptr is NULL dhdp=%p cookie=%p\n", + __FUNCTION__, dhdp, dhdp?dhdp->logdump_cookie: NULL)); + return 0; + } + return dhd_ring_get_cur_size(dhdp->logdump_cookie); +} + +static inline int +__dhd_log_dump_cookie_to_file( + dhd_pub_t *dhdp, void *fp, const void *user_buf, unsigned long *f_pos, + char *buf, uint32 buf_size) +{ + + uint32 remain = buf_size; + int ret = BCME_ERROR; + char tmp_buf[LOGDUMP_COOKIE_STR_LEN]; + log_dump_section_hdr_t sec_hdr; + uint32 read_idx; + uint32 write_idx; + + read_idx = dhd_ring_get_read_idx(dhdp->logdump_cookie); + write_idx = dhd_ring_get_write_idx(dhdp->logdump_cookie); + while (dhd_logdump_cookie_count(dhdp) > 0) { + memset(tmp_buf, 0, sizeof(tmp_buf)); + ret = dhd_logdump_cookie_get(dhdp, tmp_buf, LOGDUMP_COOKIE_STR_LEN); + if (ret != BCME_OK) { + return ret; + } + remain -= scnprintf(&buf[buf_size - remain], remain, "%s", tmp_buf); + } + dhd_ring_set_read_idx(dhdp->logdump_cookie, read_idx); + dhd_ring_set_write_idx(dhdp->logdump_cookie, write_idx); + + ret = dhd_export_debug_data(COOKIE_LOG_HDR, fp, user_buf, strlen(COOKIE_LOG_HDR), f_pos); + if (ret < 0) { + DHD_ERROR(("%s : Write file Error for cookie hdr\n", __FUNCTION__)); + return ret; + } + sec_hdr.magic = LOG_DUMP_MAGIC; + sec_hdr.timestamp = local_clock(); + sec_hdr.type = LOG_DUMP_SECTION_COOKIE; + sec_hdr.length = buf_size - remain; + + ret = dhd_export_debug_data((char *)&sec_hdr, fp, user_buf, sizeof(sec_hdr), f_pos); + if (ret < 0) { + DHD_ERROR(("%s : Write file Error for section hdr\n", __FUNCTION__)); + return ret; + } + + ret = dhd_export_debug_data(buf, fp, user_buf, sec_hdr.length, f_pos); + if (ret < 0) { + DHD_ERROR(("%s : Write file Error for cookie data\n", __FUNCTION__)); + } + + return ret; +} + +uint32 +dhd_log_dump_cookie_len(dhd_pub_t *dhdp) +{ + int len = 0; + char tmp_buf[LOGDUMP_COOKIE_STR_LEN]; + log_dump_section_hdr_t sec_hdr; + char *buf = NULL; + int ret = BCME_ERROR; + uint32 buf_size = MAX_LOGUDMP_COOKIE_CNT * LOGDUMP_COOKIE_STR_LEN; + uint32 read_idx; + uint32 write_idx; + uint32 remain; + + remain = buf_size; + + if (!dhdp || !dhdp->logdump_cookie) { + DHD_ERROR(("%s At least one ptr is NULL " + "dhdp = %p cookie %p\n", + __FUNCTION__, dhdp, dhdp?dhdp->logdump_cookie:NULL)); + goto exit; + } + + buf = (char *)MALLOCZ(dhdp->osh, buf_size); + if (!buf) { + DHD_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__)); + goto exit; + } + + read_idx = dhd_ring_get_read_idx(dhdp->logdump_cookie); + write_idx = dhd_ring_get_write_idx(dhdp->logdump_cookie); + while (dhd_logdump_cookie_count(dhdp) > 0) { + memset(tmp_buf, 0, sizeof(tmp_buf)); + ret = dhd_logdump_cookie_get(dhdp, tmp_buf, LOGDUMP_COOKIE_STR_LEN); + if (ret != BCME_OK) { + goto exit; + } + remain -= (uint32)strlen(tmp_buf); + } + dhd_ring_set_read_idx(dhdp->logdump_cookie, read_idx); + dhd_ring_set_write_idx(dhdp->logdump_cookie, write_idx); + len += strlen(COOKIE_LOG_HDR); + len += sizeof(sec_hdr); + len += (buf_size - remain); +exit: + if (buf) + MFREE(dhdp->osh, buf, buf_size); + return len; +} + +int +dhd_log_dump_cookie(dhd_pub_t *dhdp, const void *user_buf) +{ + int ret = BCME_ERROR; + char tmp_buf[LOGDUMP_COOKIE_STR_LEN]; + log_dump_section_hdr_t sec_hdr; + char *buf = NULL; + uint32 buf_size = MAX_LOGUDMP_COOKIE_CNT * LOGDUMP_COOKIE_STR_LEN; + int pos = 0; + uint32 read_idx; + uint32 write_idx; + uint32 remain; + + remain = buf_size; + + if (!dhdp || !dhdp->logdump_cookie) { + DHD_ERROR(("%s At least one ptr is NULL " + "dhdp = %p cookie %p\n", + __FUNCTION__, dhdp, dhdp?dhdp->logdump_cookie:NULL)); + goto exit; + } + + buf = (char *)MALLOCZ(dhdp->osh, buf_size); + if (!buf) { + DHD_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__)); + goto exit; + } + + read_idx = dhd_ring_get_read_idx(dhdp->logdump_cookie); + write_idx = dhd_ring_get_write_idx(dhdp->logdump_cookie); + while (dhd_logdump_cookie_count(dhdp) > 0) { + memset(tmp_buf, 0, sizeof(tmp_buf)); + ret = dhd_logdump_cookie_get(dhdp, tmp_buf, LOGDUMP_COOKIE_STR_LEN); + if (ret != BCME_OK) { + goto exit; + } + remain -= scnprintf(&buf[buf_size - remain], remain, "%s", tmp_buf); + } + dhd_ring_set_read_idx(dhdp->logdump_cookie, read_idx); + dhd_ring_set_write_idx(dhdp->logdump_cookie, write_idx); + ret = dhd_export_debug_data(COOKIE_LOG_HDR, NULL, user_buf, strlen(COOKIE_LOG_HDR), &pos); + sec_hdr.magic = LOG_DUMP_MAGIC; + sec_hdr.timestamp = local_clock(); + sec_hdr.type = LOG_DUMP_SECTION_COOKIE; + sec_hdr.length = buf_size - remain; + ret = dhd_export_debug_data((char *)&sec_hdr, NULL, user_buf, sizeof(sec_hdr), &pos); + ret = dhd_export_debug_data(buf, NULL, user_buf, sec_hdr.length, &pos); +exit: + if (buf) + MFREE(dhdp->osh, buf, buf_size); + return ret; +} + +int +dhd_log_dump_cookie_to_file(dhd_pub_t *dhdp, void *fp, const void *user_buf, unsigned long *f_pos) +{ + char *buf; + int ret = BCME_ERROR; + uint32 buf_size = MAX_LOGUDMP_COOKIE_CNT * LOGDUMP_COOKIE_STR_LEN; + +#ifdef DHD_DEBUGABILITY_DEBUG_DUMP + if (!dhdp || !dhdp->logdump_cookie) +#else + if (!dhdp || !dhdp->logdump_cookie || (!fp && !user_buf) || !f_pos) +#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */ + { + DHD_ERROR(("%s At least one ptr is NULL " + "dhdp = %p cookie %p fp = %p f_pos = %p\n", + __FUNCTION__, dhdp, dhdp?dhdp->logdump_cookie:NULL, fp, f_pos)); + return ret; + } + + buf = (char *)MALLOCZ(dhdp->osh, buf_size); + if (!buf) { + DHD_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__)); + return ret; + } + ret = __dhd_log_dump_cookie_to_file(dhdp, fp, user_buf, f_pos, buf, buf_size); + MFREE(dhdp->osh, buf, buf_size); + + return ret; +} + +void +get_debug_dump_time(char *str) +{ + struct osl_timespec curtime; + unsigned long long local_time; + struct rtc_time tm; + + if (!strlen(str)) { + osl_do_gettimeofday(&curtime); + local_time = (u64)(curtime.tv_sec - + (sys_tz.tz_minuteswest * DHD_LOG_DUMP_TS_MULTIPLIER_VALUE)); + rtc_time_to_tm(local_time, &tm); + snprintf(str, DEBUG_DUMP_TIME_BUF_LEN, DHD_LOG_DUMP_TS_FMT_YYMMDDHHMMSSMSMS, + tm.tm_year - 100, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, + tm.tm_sec, curtime.tv_nsec/NSEC_PER_MSEC); + } +} + +void +clear_debug_dump_time(char *str) +{ + memset(str, 0, DEBUG_DUMP_TIME_BUF_LEN); +} +#if defined(WL_CFGVENDOR_SEND_HANG_EVENT) || defined(DHD_PKT_LOGGING) +void +copy_debug_dump_time(char *dest, char *src) +{ + memcpy(dest, src, DEBUG_DUMP_TIME_BUF_LEN); +} +#endif + +#ifdef DHD_IOVAR_LOG_FILTER_DUMP +typedef struct iovar_log_filter_table { + char command[64]; + int enable; +} iovar_log_filter_table_t; + +/* WLC_GET_VAR is not being logged by default. Add for logging in debug_dump. */ +static const iovar_log_filter_table_t iovar_get_filter_params[] = { + {"cur_etheraddr", TRUE}, + {"\0", TRUE} +}; + +/* WLC_SET_VAR is being logged by default. Add for not logging in debug_dump. */ +static const iovar_log_filter_table_t iovar_set_filter_params[] = { + {"pkt_filter_enable", FALSE}, + {"pkt_filter_mode", FALSE}, + {"\0", FALSE} +}; + +bool +dhd_iovar_log_dump_check(dhd_pub_t *dhd_pub, uint32 cmd, char *msg) +{ + int cnt = 0; + const iovar_log_filter_table_t *table; + bool ret_val = TRUE; + + /* Logging all IOVARs with DHD_IOVAR_MEM() in debug_dump file + * during during Wifi ON. + */ + if (dhd_pub->up == FALSE) { + return TRUE; + } + + if (cmd == WLC_GET_VAR) { + ret_val = FALSE; + table = iovar_get_filter_params; + } else if (cmd == WLC_SET_VAR) { + ret_val = TRUE; + table = iovar_set_filter_params; + } else { + return TRUE; + } + while (strlen(table[cnt].command) > 0) { + if (!strncmp(msg, table[cnt].command, + strlen(table[cnt].command))) { + return table[cnt].enable; + } + + cnt++; + } + + return ret_val; +} +#endif /* DHD_IOVAR_LOG_FILTER_DUMP */ +#endif /* DHD_LOG_DUMP */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_log_dump.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_log_dump.h new file mode 100644 index 000000000000..8c42d3f4e010 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_log_dump.h @@ -0,0 +1,402 @@ +/* + * log_dump - debugability support for dumping logs to file - header file + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + * + * $Id$ + */ + +#ifndef __DHD_LOG_DUMP_H__ +#define __DHD_LOG_DUMP_H__ + +#ifdef DHD_LOG_DUMP + +#include + +#define LOG_DUMP_MAGIC 0xDEB3DEB3 +#ifdef EWP_ECNTRS_LOGGING +#define ECNTR_RING_ID 0xECDB +#define ECNTR_RING_NAME "ewp_ecntr_ring" +#endif /* EWP_ECNTRS_LOGGING */ + +#ifdef EWP_RTT_LOGGING +#define RTT_RING_ID 0xADCD +#define RTT_RING_NAME "ewp_rtt_ring" +#endif /* EWP_ECNTRS_LOGGING */ + +#ifdef EWP_BCM_TRACE +#define BCM_TRACE_RING_ID 0xBCBC +#define BCM_TRACE_RING_NAME "ewp_bcm_trace_ring" +#endif /* EWP_BCM_TRACE */ + +#define DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE 512 +#define DHD_LOG_DUMP_MAX_TAIL_FLUSH_SIZE (80 * 1024) +#define DHD_LOG_DUMP_TS_MULTIPLIER_VALUE 60 +#define DHD_LOG_DUMP_TS_FMT_YYMMDDHHMMSSMSMS "%02d-%02d-%02d/%02d:%02d:%02d.%04lu" +#define DHD_LOG_DUMP_TS_FMT_YYMMDDHHMMSS "%02d%02d%02d%02d%02d%02d" +#define DHD_DEBUG_DUMP_TYPE "debug_dump" +#define DEBUG_DUMP_TRIGGER_INTERVAL_SEC 4 + +#ifndef _DHD_LOG_DUMP_DEFINITIONS_ +#define _DHD_LOG_DUMP_DEFINITIONS_ +#define GENERAL_LOG_HDR "\n-------------------- General log ---------------------------\n" +#define PRESERVE_LOG_HDR "\n-------------------- Preserve log ---------------------------\n" +#define SPECIAL_LOG_HDR "\n-------------------- Special log ---------------------------\n" +#define DHD_DUMP_LOG_HDR "\n-------------------- 'dhd dump' log -----------------------\n" +#define EXT_TRAP_LOG_HDR "\n-------------------- Extended trap data -------------------\n" +#define HEALTH_CHK_LOG_HDR "\n-------------------- Health check data --------------------\n" +#ifdef DHD_DUMP_PCIE_RINGS +#define RING_DUMP_HDR "\n-------------------- Ring dump --------------------\n" +#endif /* DHD_DUMP_PCIE_RINGS */ +#define DHD_LOG_DUMP_DLD(fmt, ...) \ + dhd_log_dump_write(DLD_BUF_TYPE_GENERAL, NULL, 0, fmt, ##__VA_ARGS__) +#define DHD_LOG_DUMP_DLD_EX(fmt, ...) \ + dhd_log_dump_write(DLD_BUF_TYPE_SPECIAL, NULL, 0, fmt, ##__VA_ARGS__) +#define DHD_LOG_DUMP_DLD_PRSRV(fmt, ...) \ + dhd_log_dump_write(DLD_BUF_TYPE_PRESERVE, NULL, 0, fmt, ##__VA_ARGS__) +#endif /* !_DHD_LOG_DUMP_DEFINITIONS_ */ + +#ifndef DHD_LOG_DUMP_RING_DEFINITIONS +#define DHD_LOG_DUMP_RING_DEFINITIONS +#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING +/* Enabled DHD_DEBUGABILITY_LOG_DUMP_RING */ +#define DHD_DBG_RING(fmt, ...) \ + dhd_dbg_ring_write(DRIVER_LOG_RING_ID, NULL, 0, fmt, ##__VA_ARGS__) +#define DHD_DBG_RING_EX(fmt, ...) \ + dhd_dbg_ring_write(FW_VERBOSE_RING_ID, NULL, 0, fmt, ##__VA_ARGS__) +#define DHD_DBG_RING_ROAM(fmt, ...) \ + dhd_dbg_ring_write(ROAM_STATS_RING_ID, NULL, 0, fmt, ##__VA_ARGS__) + +#define DHD_LOG_DUMP_WRITE DHD_DBG_RING +#define DHD_LOG_DUMP_WRITE_EX DHD_DBG_RING_EX +#define DHD_LOG_DUMP_WRITE_PRSRV DHD_DBG_RING_EX +#define DHD_LOG_DUMP_WRITE_ROAM DHD_DBG_RING_ROAM + +#define DHD_PREFIX_TS "[%s][%s] ", \ + OSL_GET_RTCTIME(), dhd_log_dump_get_timestamp() +#define DHD_PREFIX_TS_FN "[%s][%s] %s: ", \ + OSL_GET_RTCTIME(), dhd_log_dump_get_timestamp(), __func__ +#define DHD_LOG_DUMP_WRITE_TS DHD_DBG_RING(DHD_PREFIX_TS) +#define DHD_LOG_DUMP_WRITE_TS_FN DHD_DBG_RING(DHD_PREFIX_TS_FN) +#define DHD_LOG_DUMP_WRITE_EX_TS DHD_DBG_RING_EX(DHD_PREFIX_TS) +#define DHD_LOG_DUMP_WRITE_EX_TS_FN DHD_DBG_RING_EX(DHD_PREFIX_TS_FN) +#define DHD_LOG_DUMP_WRITE_PRSRV_TS DHD_DBG_RING_EX(DHD_PREFIX_TS) +#define DHD_LOG_DUMP_WRITE_PRSRV_TS_FN DHD_DBG_RING_EX(DHD_PREFIX_TS_FN) +#define DHD_LOG_DUMP_WRITE_ROAM_TS DHD_DBG_RING_ROAM(DHD_PREFIX_TS) +#define DHD_LOG_DUMP_WRITE_ROAM_TS_FN DHD_DBG_RING_ROAM(DHD_PREFIX_TS_FN) +#else +/* Not enabled DHD_DEBUGABILITY_LOG_DUMP_RING */ +#define DHD_LOG_DUMP_WRITE DHD_LOG_DUMP_DLD +#define DHD_LOG_DUMP_WRITE_EX DHD_LOG_DUMP_DLD_EX +#define DHD_LOG_DUMP_WRITE_PRSRV DHD_LOG_DUMP_DLD_PRSRV +#define DHD_LOG_DUMP_WRITE_ROAM DHD_LOG_DUMP_DLD + +#define DHD_PREFIX_TS "[%s]: ", dhd_log_dump_get_timestamp() +#define DHD_PREFIX_TS_FN "[%s] %s: ", dhd_log_dump_get_timestamp(), __func__ +#define DHD_LOG_DUMP_WRITE_TS DHD_LOG_DUMP_DLD(DHD_PREFIX_TS) +#define DHD_LOG_DUMP_WRITE_TS_FN DHD_LOG_DUMP_DLD(DHD_PREFIX_TS_FN) +#define DHD_LOG_DUMP_WRITE_EX_TS DHD_LOG_DUMP_DLD_EX(DHD_PREFIX_TS) +#define DHD_LOG_DUMP_WRITE_EX_TS_FN DHD_LOG_DUMP_DLD_EX(DHD_PREFIX_TS_FN) +#define DHD_LOG_DUMP_WRITE_PRSRV_TS DHD_LOG_DUMP_DLD_PRSRV(DHD_PREFIX_TS) +#define DHD_LOG_DUMP_WRITE_PRSRV_TS_FN DHD_LOG_DUMP_DLD_PRSRV(DHD_PREFIX_TS_FN) +#define DHD_LOG_DUMP_WRITE_ROAM_TS DHD_LOG_DUMP_DLD(DHD_PREFIX_TS) +#define DHD_LOG_DUMP_WRITE_ROAM_TS_FN DHD_LOG_DUMP_DLD(DHD_PREFIX_TS_FN) +#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ +#endif /* DHD_LOG_DUMP_RING_DEFINITIONS */ + +#define CONCISE_DUMP_BUFLEN 32 * 1024 +#define ECNTRS_LOG_HDR "\n-------------------- Ecounters log --------------------------\n" +#ifdef DHD_STATUS_LOGGING +#define STATUS_LOG_HDR "\n-------------------- Status log -----------------------\n" +#endif /* DHD_STATUS_LOGGING */ +#define RTT_LOG_HDR "\n-------------------- RTT log --------------------------\n" +#define BCM_TRACE_LOG_HDR "\n-------------------- BCM Trace log --------------------------\n" +#define COOKIE_LOG_HDR "\n-------------------- Cookie List ----------------------------\n" +#define DHD_PKTID_MAP_LOG_HDR "\n---------------- PKTID MAP log -----------------------\n" +#define DHD_PKTID_UNMAP_LOG_HDR "\n------------------ PKTID UNMAP log -----------------------\n" +#define PKTID_LOG_DUMP_FMT \ + "\nIndex \t\tTimestamp \tPktaddr(PA) \tPktid \tSize \tPkttype\n(Current=%d)\n" + +/* 0: DLD_BUF_TYPE_GENERAL, 1: DLD_BUF_TYPE_PRESERVE +* 2: DLD_BUF_TYPE_SPECIAL +*/ +#define DLD_BUFFER_NUM 3 + +#ifndef CUSTOM_LOG_DUMP_BUFSIZE_MB +#define CUSTOM_LOG_DUMP_BUFSIZE_MB 4 /* DHD_LOG_DUMP_BUF_SIZE 4 MB static memory in kernel */ +#endif /* CUSTOM_LOG_DUMP_BUFSIZE_MB */ + +#define LOG_DUMP_TOTAL_BUFSIZE (1024 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) + +/* + * Below are different sections that use the prealloced buffer + * and sum of the sizes of these should not cross LOG_DUMP_TOTAL_BUFSIZE + */ +#ifdef EWP_BCM_TRACE +#define LOG_DUMP_GENERAL_MAX_BUFSIZE (192 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) +#define LOG_DUMP_BCM_TRACE_MAX_BUFSIZE (64 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) +#else +#define LOG_DUMP_GENERAL_MAX_BUFSIZE (256 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) +#define LOG_DUMP_BCM_TRACE_MAX_BUFSIZE 0 +#endif /* EWP_BCM_TRACE */ +#define LOG_DUMP_PRESERVE_MAX_BUFSIZE (128 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) +#define LOG_DUMP_ECNTRS_MAX_BUFSIZE (256 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) +#define LOG_DUMP_RTT_MAX_BUFSIZE (256 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) +#define LOG_DUMP_FILTER_MAX_BUFSIZE (128 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) + +#if LOG_DUMP_TOTAL_BUFSIZE < (LOG_DUMP_GENERAL_MAX_BUFSIZE + \ + LOG_DUMP_PRESERVE_MAX_BUFSIZE + LOG_DUMP_ECNTRS_MAX_BUFSIZE + LOG_DUMP_RTT_MAX_BUFSIZE \ + + LOG_DUMP_BCM_TRACE_MAX_BUFSIZE + LOG_DUMP_FILTER_MAX_BUFSIZE) +#error "LOG_DUMP_TOTAL_BUFSIZE is lesser than sum of all rings" +#endif + +/* Special buffer is allocated as separately in prealloc */ +#define LOG_DUMP_SPECIAL_MAX_BUFSIZE (8 * 1024) + +#define LOG_DUMP_MAX_FILESIZE (8 *1024 * 1024) /* 8 MB default */ + +#ifdef CONFIG_LOG_BUF_SHIFT +/* 15% of kernel log buf size, if for example klog buf size is 512KB +* 15% of 512KB ~= 80KB +*/ +#define LOG_DUMP_KERNEL_TAIL_FLUSH_SIZE \ + (15 * ((1 << CONFIG_LOG_BUF_SHIFT)/100)) +#endif /* CONFIG_LOG_BUF_SHIFT */ + +#define LOG_DUMP_COOKIE_BUFSIZE 1024u +#define DHD_PRINT_BUF_NAME_LEN 30 + +#ifdef DHD_SSSR_DUMP +#define DUMP_SSSR_ATTR_START 2 +#define DUMP_SSSR_ATTR_COUNT 10 + +typedef enum { + SSSR_C0_D11_BEFORE = 0, + SSSR_C0_D11_AFTER = 1, + SSSR_C1_D11_BEFORE = 2, + SSSR_C1_D11_AFTER = 3, + SSSR_C2_D11_BEFORE = 4, + SSSR_C2_D11_AFTER = 5, + SSSR_DIG_BEFORE = 6, + SSSR_DIG_AFTER = 7 +} EWP_SSSR_DUMP; +#endif /* DHD_SSSR_DUMP */ + +typedef enum { + DLD_BUF_TYPE_GENERAL = 0, + DLD_BUF_TYPE_PRESERVE = 1, + DLD_BUF_TYPE_SPECIAL = 2, + DLD_BUF_TYPE_ECNTRS = 3, + DLD_BUF_TYPE_FILTER = 4, + DLD_BUF_TYPE_ALL = 5 +} log_dump_type_t; + +/* + * XXX: Always add new enums at the end to compatible with parser, + * also add new section in split_ret of EWP_config.py + */ +typedef enum { + LOG_DUMP_SECTION_GENERAL = 0, + LOG_DUMP_SECTION_ECNTRS, + LOG_DUMP_SECTION_SPECIAL, + LOG_DUMP_SECTION_DHD_DUMP, + LOG_DUMP_SECTION_EXT_TRAP, + LOG_DUMP_SECTION_HEALTH_CHK, + LOG_DUMP_SECTION_PRESERVE, + LOG_DUMP_SECTION_COOKIE, + LOG_DUMP_SECTION_RING, + LOG_DUMP_SECTION_STATUS, + LOG_DUMP_SECTION_RTT, + LOG_DUMP_SECTION_BCM_TRACE, + LOG_DUMP_SECTION_PKTID_MAP_LOG, + LOG_DUMP_SECTION_PKTID_UNMAP_LOG, + LOG_DUMP_SECTION_TIMESTAMP, + LOG_DUMP_SECTION_MAX +} log_dump_section_type_t; + +/* Each section in the debug_dump log file shall begin with a header */ +typedef struct { + uint32 magic; /* 0xDEB3DEB3 */ + uint32 type; /* of type log_dump_section_type_t */ + uint64 timestamp; + uint32 length; /* length of the section that follows */ +} log_dump_section_hdr_t; + +#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING +struct dhd_dbg_ring_buf +{ + void *dhd_pub; +}; +extern struct dhd_dbg_ring_buf g_ring_buf; +#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ + +typedef struct dhd_debug_dump_ring_entry { + log_dump_section_type_t type; + uint32 debug_dump_ring; +} dhd_debug_dump_ring_entry_t; + +/* below structure describe ring buffer. */ +struct dhd_log_dump_buf +{ +#if defined(LINUX) || defined(linux) || defined(ANDROID) || defined(OEM_ANDROID) + spinlock_t lock; +#endif + void *dhd_pub; + unsigned int enable; + unsigned int wraparound; + unsigned long max; + unsigned int remain; + char* present; + char* front; + char* buffer; +}; + +typedef struct { + char *hdr_str; + log_dump_section_type_t sec_type; +} dld_hdr_t; + +extern void dhd_log_dump_write(int type, char *binary_data, + int binary_len, const char *fmt, ...); +void dhd_schedule_log_dump(dhd_pub_t *dhdp, void *type); +void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd); +void dhd_log_dump_vendor_trigger(dhd_pub_t *dhd_pub); + +#ifdef DHD_DEBUGABILITY_DEBUG_DUMP +int dhd_debug_dump_get_ring_num(int sec_type); +#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */ +int dhd_log_dump_ring_to_file(dhd_pub_t *dhdp, void *ring_ptr, void *file, + unsigned long *file_posn, log_dump_section_hdr_t *sec_hdr, char *text_hdr, + uint32 sec_type); +int dhd_dump_debug_ring(dhd_pub_t *dhdp, void *ring_ptr, const void *user_buf, + log_dump_section_hdr_t *sec_hdr, char *text_hdr, int buflen, uint32 sec_type); +int dhd_log_dump_cookie_to_file(dhd_pub_t *dhdp, void *fp, + const void *user_buf, unsigned long *f_pos); +int dhd_log_dump_cookie(dhd_pub_t *dhdp, const void *user_buf); +uint32 dhd_log_dump_cookie_len(dhd_pub_t *dhdp); +int dhd_logdump_cookie_init(dhd_pub_t *dhdp, uint8 *buf, uint32 buf_size); +void dhd_logdump_cookie_deinit(dhd_pub_t *dhdp); +void dhd_logdump_cookie_save(dhd_pub_t *dhdp, char *cookie, char *type); +int dhd_logdump_cookie_get(dhd_pub_t *dhdp, char *ret_cookie, uint32 buf_size); +int dhd_logdump_cookie_count(dhd_pub_t *dhdp); +int dhd_get_dld_log_dump(void *dev, dhd_pub_t *dhdp, const void *user_buf, void *fp, + uint32 len, int type, void *pos); +#if defined(BCMPCIE) +int dhd_print_ext_trap_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos); +uint32 dhd_get_ext_trap_len(void *ndev, dhd_pub_t *dhdp); +#endif /* BCMPCIE */ +int dhd_print_dump_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos); +int dhd_print_cookie_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos); +int dhd_print_health_chk_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos); +int dhd_print_time_str(const void *user_buf, void *fp, uint32 len, void *pos); +#ifdef DHD_DUMP_PCIE_RINGS +int dhd_print_flowring_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos); +uint32 dhd_get_flowring_len(void *ndev, dhd_pub_t *dhdp); +#endif /* DHD_DUMP_PCIE_RINGS */ +#ifdef DHD_STATUS_LOGGING +extern int dhd_print_status_log_data(void *dev, dhd_pub_t *dhdp, + const void *user_buf, void *fp, uint32 len, void *pos); +extern uint32 dhd_get_status_log_len(void *ndev, dhd_pub_t *dhdp); +#endif /* DHD_STATUS_LOGGING */ +#ifdef DHD_MAP_PKTID_LOGGING +extern uint32 dhd_pktid_buf_len(dhd_pub_t *dhd, bool is_map); +extern int dhd_print_pktid_map_log_data(void *dev, dhd_pub_t *dhdp, + const void *user_buf, void *fp, uint32 len, void *pos, bool is_map); +extern int dhd_write_pktid_log_dump(dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, unsigned long *pos, bool is_map); +extern uint32 dhd_get_pktid_map_logging_len(void *ndev, dhd_pub_t *dhdp, bool is_map); +#endif /* DHD_MAP_PKTID_LOGGING */ +int dhd_print_ecntrs_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos); +int dhd_print_rtt_data(void *dev, dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, void *pos); +int dhd_get_debug_dump_file_name(void *dev, dhd_pub_t *dhdp, + char *dump_path, int size); +uint32 dhd_get_time_str_len(void); +uint32 dhd_get_health_chk_len(void *ndev, dhd_pub_t *dhdp); +uint32 dhd_get_dhd_dump_len(void *ndev, dhd_pub_t *dhdp); +uint32 dhd_get_cookie_log_len(void *ndev, dhd_pub_t *dhdp); +uint32 dhd_get_ecntrs_len(void *ndev, dhd_pub_t *dhdp); +uint32 dhd_get_rtt_len(void *ndev, dhd_pub_t *dhdp); +uint32 dhd_get_dld_len(int log_type); +void dhd_init_sec_hdr(log_dump_section_hdr_t *sec_hdr); +extern char *dhd_log_dump_get_timestamp(void); +bool dhd_log_dump_ecntr_enabled(void); +bool dhd_log_dump_rtt_enabled(void); +void dhd_nla_put_sssr_dump_len(void *ndev, uint32 *arr_len); +int dhd_get_debug_dump(void *dev, const void *user_buf, uint32 len, int type); +#ifdef DHD_SSSR_DUMP_BEFORE_SR +int +dhd_sssr_dump_d11_buf_before(void *dev, const void *user_buf, uint32 len, int core); +int +dhd_sssr_dump_dig_buf_before(void *dev, const void *user_buf, uint32 len); +#endif /* DHD_SSSR_DUMP_BEFORE_SR */ +int +dhd_sssr_dump_d11_buf_after(void *dev, const void *user_buf, uint32 len, int core); +int +dhd_sssr_dump_dig_buf_after(void *dev, const void *user_buf, uint32 len); +#ifdef DHD_PKT_LOGGING +extern int dhd_os_get_pktlog_dump(void *dev, const void *user_buf, uint32 len); +extern spinlock_t* dhd_os_get_pktlog_lock(dhd_pub_t *dhdp); +extern uint32 dhd_os_get_pktlog_dump_size(struct net_device *dev); +extern void dhd_os_get_pktlogdump_filename(struct net_device *dev, char *dump_path, int len); +#endif /* DHD_PKT_LOGGING */ + +#ifdef DNGL_AXI_ERROR_LOGGING +extern int dhd_os_get_axi_error_dump(void *dev, const void *user_buf, uint32 len); +extern int dhd_os_get_axi_error_dump_size(struct net_device *dev); +extern void dhd_os_get_axi_error_filename(struct net_device *dev, char *dump_path, int len); +#endif /* DNGL_AXI_ERROR_LOGGING */ + +#ifdef DHD_DEBUGABILITY_DEBUG_DUMP +extern int dhd_debug_dump_to_ring(dhd_pub_t *dhdp); +#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */ + +extern char *dhd_log_dump_get_timestamp(void); +extern void dhd_dbg_ring_write(int type, char *binary_data, + int binary_len, const char *fmt, ...); + +void dhd_log_dump_init(dhd_pub_t *dhd); +void dhd_log_dump_deinit(dhd_pub_t *dhd); +void dhd_log_dump(void *handle, void *event_info, uint8 event); +int do_dhd_log_dump(dhd_pub_t *dhdp, log_dump_type_t *type); +void dhd_print_buf_addr(dhd_pub_t *dhdp, char *name, void *buf, unsigned int size); +void dhd_log_dump_buf_addr(dhd_pub_t *dhdp, log_dump_type_t *type); +int dhd_log_flush(dhd_pub_t *dhdp, log_dump_type_t *type); + +extern void get_debug_dump_time(char *str); +extern void clear_debug_dump_time(char *str); +#if defined(WL_CFGVENDOR_SEND_HANG_EVENT) || defined(DHD_PKT_LOGGING) +extern void copy_debug_dump_time(char *dest, char *src); +#endif + +void dhd_get_debug_dump_len(void *handle, struct sk_buff *skb, void *event_info, uint8 event); +void cfgvendor_log_dump_len(dhd_pub_t *dhdp, log_dump_type_t *type, struct sk_buff *skb); +#ifdef DHD_IOVAR_LOG_FILTER_DUMP +bool dhd_iovar_log_dump_check(dhd_pub_t *dhd_pub, uint32 cmd, char *msg); +#endif /* DHD_IOVAR_LOG_FILTER_DUMP */ +#endif /* DHD_LOG_DUMP */ + +#endif /* !__DHD_LOG_DUMP_H__ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_macdbg.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_macdbg.c deleted file mode 100755 index dd145dffbf15..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_macdbg.c +++ /dev/null @@ -1,746 +0,0 @@ -/* D11 macdbg functions for Broadcom 802.11abgn - * Networking Adapter Device Drivers. - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - * - * $Id: dhd_macdbg.c 670412 2016-11-15 20:01:18Z shinuk $ - */ - -#ifdef BCMDBG -#include -#include - -#include -#include -#include -#include "d11reglist_proto.h" -#include "dhdioctl.h" -#include - -#ifdef BCMDBUS -#include -#define BUS_IOVAR_OP(a, b, c, d, e, f, g) dbus_iovar_op(a->dbus, b, c, d, e, f, g) -#else -#include -#define BUS_IOVAR_OP dhd_bus_iovar_op -#endif - -typedef struct _macdbg_info_t { - dhd_pub_t *dhdp; - d11regs_list_t *pd11regs; - uint16 d11regs_sz; - d11regs_list_t *pd11regs_x; - uint16 d11regsx_sz; - svmp_list_t *psvmpmems; - uint16 svmpmems_sz; -} macdbg_info_t; - -#define SVMPLIST_HARDCODE - -int -dhd_macdbg_attach(dhd_pub_t *dhdp) -{ - macdbg_info_t *macdbg_info = MALLOCZ(dhdp->osh, sizeof(*macdbg_info)); -#ifdef SVMPLIST_HARDCODE - svmp_list_t svmpmems[] = { - {0x20000, 256}, - {0x21e10, 16}, - {0x20300, 16}, - {0x20700, 16}, - {0x20b00, 16}, - {0x20be0, 16}, - {0x20bff, 16}, - {0xc000, 32}, - {0xe000, 32}, - {0x10000, 0x8000}, - {0x18000, 0x8000} - }; -#endif /* SVMPLIST_HARDCODE */ - - if (macdbg_info == NULL) { - return BCME_NOMEM; - } - dhdp->macdbg_info = macdbg_info; - macdbg_info->dhdp = dhdp; - -#ifdef SVMPLIST_HARDCODE - macdbg_info->psvmpmems = MALLOCZ(dhdp->osh, sizeof(svmpmems)); - if (macdbg_info->psvmpmems == NULL) { - return BCME_NOMEM; - } - - macdbg_info->svmpmems_sz = ARRAYSIZE(svmpmems); - memcpy(macdbg_info->psvmpmems, svmpmems, sizeof(svmpmems)); - - DHD_ERROR(("%s: psvmpmems %p svmpmems_sz %d\n", - __FUNCTION__, macdbg_info->psvmpmems, macdbg_info->svmpmems_sz)); -#endif - return BCME_OK; -} - -void -dhd_macdbg_detach(dhd_pub_t *dhdp) -{ - macdbg_info_t *macdbg_info = dhdp->macdbg_info; - ASSERT(macdbg_info); - - if (macdbg_info->pd11regs) { - ASSERT(macdbg_info->d11regs_sz > 0); - MFREE(dhdp->osh, macdbg_info->pd11regs, - (macdbg_info->d11regs_sz * sizeof(macdbg_info->pd11regs[0]))); - macdbg_info->d11regs_sz = 0; - } - if (macdbg_info->pd11regs_x) { - ASSERT(macdbg_info->d11regsx_sz > 0); - MFREE(dhdp->osh, macdbg_info->pd11regs_x, - (macdbg_info->d11regsx_sz * sizeof(macdbg_info->pd11regs_x[0]))); - macdbg_info->d11regsx_sz = 0; - } - if (macdbg_info->psvmpmems) { - ASSERT(macdbg_info->svmpmems_sz > 0); - MFREE(dhdp->osh, macdbg_info->psvmpmems, - (macdbg_info->svmpmems_sz * sizeof(macdbg_info->psvmpmems[0]))); - macdbg_info->svmpmems_sz = 0; - } - MFREE(dhdp->osh, macdbg_info, sizeof(*macdbg_info)); -} - -void -dhd_macdbg_event_handler(dhd_pub_t *dhdp, uint32 reason, - uint8 *event_data, uint32 datalen) -{ - d11regs_list_t *pd11regs; - macdbg_info_t *macdbg_info = dhdp->macdbg_info; - uint d11regs_sz; - - DHD_TRACE(("%s: reason %d datalen %d\n", __FUNCTION__, reason, datalen)); - switch (reason) { - case WLC_E_MACDBG_LIST_PSMX: - /* Fall through */ - case WLC_E_MACDBG_LIST_PSM: - pd11regs = MALLOCZ(dhdp->osh, datalen); - if (pd11regs == NULL) { - DHD_ERROR(("%s: NOMEM for len %d\n", __FUNCTION__, datalen)); - return; - } - memcpy(pd11regs, event_data, datalen); - d11regs_sz = datalen / sizeof(pd11regs[0]); - DHD_ERROR(("%s: d11regs %p d11regs_sz %d\n", - __FUNCTION__, pd11regs, d11regs_sz)); - if (reason == WLC_E_MACDBG_LIST_PSM) { - macdbg_info->pd11regs = pd11regs; - macdbg_info->d11regs_sz = (uint16)d11regs_sz; - } else { - macdbg_info->pd11regs_x = pd11regs; - macdbg_info->d11regsx_sz = (uint16)d11regs_sz; - } - break; - case WLC_E_MACDBG_REGALL: -#ifdef LINUX - /* Schedule to work queue as this context could be ISR */ - dhd_schedule_macdbg_dump(dhdp); -#else - /* Dump PSMr */ - (void) dhd_macdbg_dumpmac(dhdp, NULL, 0, NULL, FALSE); - /* Dump PSMx */ - (void) dhd_macdbg_dumpmac(dhdp, NULL, 0, NULL, TRUE); - /* Dump SVMP mems */ - (void) dhd_macdbg_dumpsvmp(dhdp, NULL, 0, NULL); -#endif - break; - default: - DHD_ERROR(("%s: Unknown reason %d\n", - __FUNCTION__, reason)); - } - return; -} - -static uint16 -_dhd_get_ihr16(macdbg_info_t *macdbg_info, uint16 addr, struct bcmstrbuf *b, bool verbose) -{ - sdreg_t sdreg; - uint16 val; - - sdreg.func = 2; - sdreg.offset = (0x1000 | addr); - BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg", - &sdreg, sizeof(sdreg), &val, sizeof(val), IOV_GET); - if (verbose) { - if (b) { - bcm_bprintf(b, "DEBUG: IHR16: read 0x%08x, size 2, value 0x%04x\n", - (addr + 0x18001000), val); - } else { - printf("DEBUG: IHR16: read 0x%08x, size 2, value 0x%04x\n", - (addr + 0x18001000), val); - } - } - return val; -} - -static uint32 -_dhd_get_ihr32(macdbg_info_t *macdbg_info, uint16 addr, struct bcmstrbuf *b, bool verbose) -{ - sdreg_t sdreg; - uint32 val; - - sdreg.func = 4; - sdreg.offset = (0x1000 | addr); - BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg", - &sdreg, sizeof(sdreg), &val, sizeof(val), IOV_GET); - if (verbose) { - if (b) { - bcm_bprintf(b, "DEBUG: IHR32: read 0x%08x, size 4, value 0x%08x\n", - (addr + 0x18001000), val); - } else { - printf("DEBUG: IHR32: read 0x%08x, size 4, value 0x%08x\n", - (addr + 0x18001000), val); - } - } - return val; -} - -static void -_dhd_set_ihr16(macdbg_info_t *macdbg_info, uint16 addr, uint16 val, - struct bcmstrbuf *b, bool verbose) -{ - sdreg_t sdreg; - - sdreg.func = 2; - sdreg.offset = (0x1000 | addr); - sdreg.value = val; - - if (verbose) { - if (b) { - bcm_bprintf(b, "DEBUG: IHR16: write 0x%08x, size 2, value 0x%04x\n", - (addr + 0x18001000), val); - } else { - printf("DEBUG: IHR16: write 0x%08x, size 2, value 0x%04x\n", - (addr + 0x18001000), val); - } - } - BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg", - NULL, 0, &sdreg, sizeof(sdreg), IOV_SET); -} - -static void -_dhd_set_ihr32(macdbg_info_t *macdbg_info, uint16 addr, uint32 val, - struct bcmstrbuf *b, bool verbose) -{ - sdreg_t sdreg; - - sdreg.func = 4; - sdreg.offset = (0x1000 | addr); - sdreg.value = val; - - if (verbose) { - if (b) { - bcm_bprintf(b, "DEBUG: IHR32: write 0x%08x, size 4, value 0x%08x\n", - (addr + 0x18001000), val); - } else { - printf("DEBUG: IHR32: write 0x%08x, size 4, value 0x%08x\n", - (addr + 0x18001000), val); - } - } - BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg", - NULL, 0, &sdreg, sizeof(sdreg), IOV_SET); -} - -static uint32 -_dhd_get_d11obj32(macdbg_info_t *macdbg_info, uint16 objaddr, uint32 sel, - struct bcmstrbuf *b, bool verbose) -{ - uint32 val; - sdreg_t sdreg; - sdreg.func = 4; // 4bytes by default. - sdreg.offset = 0x1160; - - if (objaddr == 0xffff) { - if (verbose) { - goto objaddr_read; - } else { - goto objdata_read; - } - } - - if (objaddr & 0x3) { - printf("%s: ERROR! Invalid addr 0x%x\n", __FUNCTION__, objaddr); - } - - sdreg.value = (sel | (objaddr >> 2)); - - if (verbose) { - if (b) { - bcm_bprintf(b, "DEBUG: %s: Indirect: write 0x%08x, size %d, value 0x%08x\n", - (sel & 0x00020000) ? "SCR":"SHM", - (sdreg.offset + 0x18000000), sdreg.func, sdreg.value); - } else { - printf("DEBUG: %s: Indirect: write 0x%08x, size %d, value 0x%08x\n", - (sel & 0x00020000) ? "SCR":"SHM", - (sdreg.offset + 0x18000000), sdreg.func, sdreg.value); - } - } - BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg", - NULL, 0, &sdreg, sizeof(sdreg), IOV_SET); - -objaddr_read: - /* Give some time to obj addr register */ - BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg", - &sdreg, sizeof(sdreg), &val, sizeof(val), IOV_GET); - if (verbose) { - if (b) { - bcm_bprintf(b, "DEBUG: %s: Indirect: Read 0x%08x, size %d, value 0x%08x\n", - (sel & 0x00020000) ? "SCR":"SHM", - (sdreg.offset + 0x18000000), sdreg.func, val); - } else { - printf("DEBUG: %s: Indirect: Read 0x%08x, size %d, value 0x%08x\n", - (sel & 0x00020000) ? "SCR":"SHM", - (sdreg.offset + 0x18000000), sdreg.func, val); - } - } - -objdata_read: - sdreg.offset = 0x1164; - BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg", - &sdreg, sizeof(sdreg), &val, sizeof(val), IOV_GET); - if (verbose) { - if (b) { - bcm_bprintf(b, "DEBUG: %s: Indirect: Read 0x%08x, size %d, value 0x%04x\n", - (sel & 0x00020000) ? "SCR":"SHM", - (sdreg.offset + 0x18000000), sdreg.func, val); - } else { - printf("DEBUG: %s: Indirect: Read 0x%08x, size %d, value 0x%04x\n", - (sel & 0x00020000) ? "SCR":"SHM", - (sdreg.offset + 0x18000000), sdreg.func, val); - } - } - return val; -} - -static uint16 -_dhd_get_d11obj16(macdbg_info_t *macdbg_info, uint16 objaddr, - uint32 sel, d11obj_cache_t *obj_cache, struct bcmstrbuf *b, bool verbose) -{ - uint32 val; - if (obj_cache && obj_cache->cache_valid && ((obj_cache->sel ^ sel) & (0xffffff)) == 0) { - if (obj_cache->addr32 == (objaddr & ~0x3)) { - /* XXX: Same objaddr read as the previous one */ - if (verbose) { - if (b) { - bcm_bprintf(b, "DEBUG: %s: Read cache value: " - "addr32 0x%04x, sel 0x%08x, value 0x%08x\n", - (sel & 0x00020000) ? "SCR":"SHM", - obj_cache->addr32, obj_cache->sel, obj_cache->val); - } else { - printf("DEBUG: %s: Read cache value: " - "addr32 0x%04x, sel 0x%08x, value 0x%08x\n", - (sel & 0x00020000) ? "SCR":"SHM", - obj_cache->addr32, obj_cache->sel, obj_cache->val); - } - } - val = obj_cache->val; - goto exit; - } else if ((obj_cache->sel & 0x02000000) && - (obj_cache->addr32 + 4 == (objaddr & ~0x3))) { - /* XXX: objaddr is auto incrementing, so just read objdata */ - if (verbose) { - if (b) { - bcm_bprintf(b, "DEBUG: %s: Read objdata only: " - "addr32 0x%04x, sel 0x%08x, value 0x%08x\n", - (sel & 0x00020000) ? "SCR":"SHM", - obj_cache->addr32, obj_cache->sel, obj_cache->val); - } else { - printf("DEBUG: %s: Read objdata only: " - "addr32 0x%04x, sel 0x%08x, value 0x%08x\n", - (sel & 0x00020000) ? "SCR":"SHM", - obj_cache->addr32, obj_cache->sel, obj_cache->val); - } - } - val = _dhd_get_d11obj32(macdbg_info, 0xffff, sel, b, verbose); - goto exit; - } - } - val = _dhd_get_d11obj32(macdbg_info, (objaddr & ~0x2), sel, b, verbose); -exit: - if (obj_cache) { - obj_cache->addr32 = (objaddr & ~0x3); - obj_cache->sel = sel; - obj_cache->val = val; - obj_cache->cache_valid = TRUE; - } - return (uint16)((objaddr & 0x2) ? (val >> 16) : val); -} - -static int -_dhd_print_d11reg(macdbg_info_t *macdbg_info, int idx, int type, uint16 addr, struct bcmstrbuf *b, - d11obj_cache_t *obj_cache, bool verbose) -{ - const char *regname[D11REG_TYPE_MAX] = D11REGTYPENAME; - uint32 val; - - if (type == D11REG_TYPE_IHR32) { - if ((addr & 0x3)) { - printf("%s: ERROR! Invalid addr 0x%x\n", __FUNCTION__, addr); - addr &= ~0x3; - } - val = _dhd_get_ihr32(macdbg_info, addr, b, verbose); - if (b) { - bcm_bprintf(b, "%-3d %s 0x%-4x = 0x%-8x\n", - idx, regname[type], addr, val); - } else { - printf("%-3d %s 0x%-4x = 0x%-8x\n", - idx, regname[type], addr, val); - } - } else { - switch (type) { - case D11REG_TYPE_IHR16: { - if ((addr & 0x1)) { - printf("%s: ERROR! Invalid addr 0x%x\n", __FUNCTION__, addr); - addr &= ~0x1; - } - val = _dhd_get_ihr16(macdbg_info, addr, b, verbose); - break; - } - case D11REG_TYPE_IHRX16: - val = _dhd_get_d11obj16(macdbg_info, (addr - 0x400) << 1, 0x020b0000, - obj_cache, b, verbose); - break; - case D11REG_TYPE_SCR: - val = _dhd_get_d11obj16(macdbg_info, addr << 2, 0x02020000, - obj_cache, b, verbose); - break; - case D11REG_TYPE_SCRX: - val = _dhd_get_d11obj16(macdbg_info, addr << 2, 0x020a0000, - obj_cache, b, verbose); - break; - case D11REG_TYPE_SHM: - val = _dhd_get_d11obj16(macdbg_info, addr, 0x02010000, - obj_cache, b, verbose); - break; - case D11REG_TYPE_SHMX: - val = _dhd_get_d11obj16(macdbg_info, addr, 0x02090000, - obj_cache, b, verbose); - break; - default: - printf("Unrecognized type %d!\n", type); - return 0; - } - if (b) { - bcm_bprintf(b, "%-3d %s 0x%-4x = 0x%-4x\n", - idx, regname[type], addr, val); - } else { - printf("%-3d %s 0x%-4x = 0x%-4x\n", - idx, regname[type], addr, val); - } - } - return 1; -} - -static int -_dhd_print_d11regs(macdbg_info_t *macdbg_info, d11regs_list_t *pregs, - int start_idx, struct bcmstrbuf *b, bool verbose) -{ - uint16 addr; - int idx = 0; - d11obj_cache_t obj_cache = {0, 0, 0, FALSE}; - - addr = pregs->addr; - if (pregs->type >= D11REG_TYPE_MAX) { - printf("%s: wrong type %d\n", __FUNCTION__, pregs->type); - return 0; - } - if (pregs->bitmap) { - while (pregs->bitmap) { - if (pregs->bitmap && (pregs->bitmap & 0x1)) { - _dhd_print_d11reg(macdbg_info, (idx + start_idx), pregs->type, - addr, b, &obj_cache, verbose); - idx++; - } - pregs->bitmap = pregs->bitmap >> 1; - addr += pregs->step; - } - } else { - for (; idx < pregs->cnt; idx++) { - _dhd_print_d11reg(macdbg_info, (idx + start_idx), pregs->type, - addr, b, &obj_cache, verbose); - addr += pregs->step; - } - } - return idx; -} - -static int -_dhd_pd11regs_bylist(macdbg_info_t *macdbg_info, d11regs_list_t *reglist, - uint16 reglist_sz, struct bcmstrbuf *b) -{ - uint i, idx = 0; - - if (reglist != NULL && reglist_sz > 0) { - for (i = 0; i < reglist_sz; i++) { - DHD_TRACE(("%s %d %p %d\n", __FUNCTION__, __LINE__, - ®list[i], reglist_sz)); - idx += _dhd_print_d11regs(macdbg_info, ®list[i], idx, b, FALSE); - } - } - return idx; -} - -int -dhd_macdbg_dumpmac(dhd_pub_t *dhdp, char *buf, int buflen, - int *outbuflen, bool dump_x) -{ - macdbg_info_t *macdbg_info = dhdp->macdbg_info; - struct bcmstrbuf *b = NULL; - struct bcmstrbuf bcmstrbuf; - uint cnt = 0; - - DHD_TRACE(("%s %d %p %d %p %d %p %d\n", __FUNCTION__, __LINE__, - buf, buflen, macdbg_info->pd11regs, macdbg_info->d11regs_sz, - macdbg_info->pd11regs_x, macdbg_info->d11regsx_sz)); - - if (buf && buflen > 0) { - bcm_binit(&bcmstrbuf, buf, buflen); - b = &bcmstrbuf; - } - if (!dump_x) { - /* Dump PSMr */ - cnt += _dhd_pd11regs_bylist(macdbg_info, macdbg_info->pd11regs, - macdbg_info->d11regs_sz, b); - } else { - /* Dump PSMx */ - cnt += _dhd_pd11regs_bylist(macdbg_info, macdbg_info->pd11regs_x, - macdbg_info->d11regsx_sz, b); - } - - if (b && outbuflen) { - if ((uint)buflen > BCMSTRBUF_LEN(b)) { - *outbuflen = buflen - BCMSTRBUF_LEN(b); - } else { - DHD_ERROR(("%s: buflen insufficient!\n", __FUNCTION__)); - *outbuflen = buflen; - /* Do not return buftooshort to allow printing macregs we have got */ - } - } - - return ((cnt > 0) ? BCME_OK : BCME_UNSUPPORTED); -} - -int -dhd_macdbg_pd11regs(dhd_pub_t *dhdp, char *params, int plen, char *buf, int buflen) -{ - macdbg_info_t *macdbg_info = dhdp->macdbg_info; - dhd_pd11regs_param *pd11regs = (void *)params; - dhd_pd11regs_buf *pd11regs_buf = (void *)buf; - uint16 start_idx; - bool verbose; - d11regs_list_t reglist; - struct bcmstrbuf *b = NULL; - struct bcmstrbuf bcmstrbuf; - - start_idx = pd11regs->start_idx; - verbose = pd11regs->verbose; - memcpy(®list, pd11regs->plist, sizeof(reglist)); - memset(buf, '\0', buflen); - bcm_binit(&bcmstrbuf, (char *)(pd11regs_buf->pbuf), - (buflen - OFFSETOF(dhd_pd11regs_buf, pbuf))); - b = &bcmstrbuf; - pd11regs_buf->idx = (uint16)_dhd_print_d11regs(macdbg_info, ®list, - start_idx, b, verbose); - - return ((pd11regs_buf->idx > 0) ? BCME_OK : BCME_ERROR); -} - -int -dhd_macdbg_reglist(dhd_pub_t *dhdp, char *buf, int buflen) -{ - int err, desc_idx = 0; - dhd_maclist_t *maclist = (dhd_maclist_t *)buf; - macdbg_info_t *macdbg_info = dhdp->macdbg_info; - void *xtlvbuf_p = maclist->plist; - uint16 xtlvbuflen = (uint16)buflen; - xtlv_desc_t xtlv_desc[] = { - {0, 0, NULL}, - {0, 0, NULL}, - {0, 0, NULL}, - {0, 0, NULL} - }; - - if (!macdbg_info->pd11regs) { - err = BCME_NOTFOUND; - goto exit; - } - ASSERT(macdbg_info->d11regs_sz > 0); - xtlv_desc[desc_idx].type = DHD_MACLIST_XTLV_R; - xtlv_desc[desc_idx].len = - macdbg_info->d11regs_sz * (uint16)sizeof(*(macdbg_info->pd11regs)); - xtlv_desc[desc_idx].ptr = macdbg_info->pd11regs; - desc_idx++; - - if (macdbg_info->pd11regs_x) { - ASSERT(macdbg_info->d11regsx_sz); - xtlv_desc[desc_idx].type = DHD_MACLIST_XTLV_X; - xtlv_desc[desc_idx].len = macdbg_info->d11regsx_sz * - (uint16)sizeof(*(macdbg_info->pd11regs_x)); - xtlv_desc[desc_idx].ptr = macdbg_info->pd11regs_x; - desc_idx++; - } - - if (macdbg_info->psvmpmems) { - ASSERT(macdbg_info->svmpmems_sz); - xtlv_desc[desc_idx].type = DHD_SVMPLIST_XTLV; - xtlv_desc[desc_idx].len = macdbg_info->svmpmems_sz * - (uint16)sizeof(*(macdbg_info->psvmpmems)); - xtlv_desc[desc_idx].ptr = macdbg_info->psvmpmems; - desc_idx++; - } - - err = bcm_pack_xtlv_buf_from_mem((uint8 **)&xtlvbuf_p, &xtlvbuflen, - xtlv_desc, BCM_XTLV_OPTION_ALIGN32); - - maclist->version = 0; /* No version control for now anyway */ - maclist->bytes_len = (buflen - xtlvbuflen); - -exit: - return err; -} - -static int -_dhd_print_svmps(macdbg_info_t *macdbg_info, svmp_list_t *psvmp, - int start_idx, struct bcmstrbuf *b, bool verbose) -{ - int idx; - uint32 addr, mem_id, offset, prev_mem_id, prev_offset; - uint16 cnt, val; - - BCM_REFERENCE(start_idx); - - /* Set tbl ID and tbl offset. */ - _dhd_set_ihr32(macdbg_info, 0x3fc, 0x30000d, b, verbose); - _dhd_set_ihr32(macdbg_info, 0x3fc, 0x8000000e, b, verbose); - - addr = psvmp->addr; - cnt = psvmp->cnt; - - /* In validate previous mem_id and offset */ - prev_mem_id = (uint32)(-1); - prev_offset = (uint32)(-1); - - for (idx = 0; idx < cnt; idx++, addr++) { - mem_id = (addr >> 15); - offset = (addr & 0x7fff) >> 1; - - if (mem_id != prev_mem_id) { - /* Set mem_id */ - _dhd_set_ihr32(macdbg_info, 0x3fc, ((mem_id & 0xffff0000) | 0x10), - b, verbose); - _dhd_set_ihr32(macdbg_info, 0x3fc, ((mem_id << 16) | 0xf), - b, verbose); - } - - if (offset != prev_offset) { - /* XXX: Is this needed? - * _dhd_set_ihr32(macdbg_info, 0x3fc, 0x30000d, b, verbose); - */ - /* svmp offset */ - _dhd_set_ihr32(macdbg_info, 0x3fc, ((offset << 16) | 0xe), - b, verbose); - } - /* Read hi or lo */ - _dhd_set_ihr16(macdbg_info, 0x3fc, ((addr & 0x1) ? 0x10 : 0xf), b, verbose); - val = _dhd_get_ihr16(macdbg_info, 0x3fe, b, verbose); - if (b) { - bcm_bprintf(b, "0x%-4x 0x%-4x\n", - addr, val); - - } else { - printf("0x%-4x 0x%-4x\n", - addr, val); - } - prev_mem_id = mem_id; - prev_offset = offset; - } - return idx; -} - -static int -_dhd_psvmps_bylist(macdbg_info_t *macdbg_info, svmp_list_t *svmplist, - uint16 svmplist_sz, struct bcmstrbuf *b) -{ - uint i, idx = 0; - - if (svmplist != NULL && svmplist_sz > 0) { - for (i = 0; i < svmplist_sz; i++) { - DHD_TRACE(("%s %d %p %d\n", __FUNCTION__, __LINE__, - &svmplist[i], svmplist_sz)); - idx += _dhd_print_svmps(macdbg_info, &svmplist[i], idx, b, FALSE); - } - } - return idx; -} - -int -dhd_macdbg_dumpsvmp(dhd_pub_t *dhdp, char *buf, int buflen, - int *outbuflen) -{ - macdbg_info_t *macdbg_info = dhdp->macdbg_info; - struct bcmstrbuf *b = NULL; - struct bcmstrbuf bcmstrbuf; - uint cnt = 0; - - DHD_TRACE(("%s %d %p %d %p %d\n", __FUNCTION__, __LINE__, - buf, buflen, macdbg_info->psvmpmems, macdbg_info->svmpmems_sz)); - - if (buf && buflen > 0) { - bcm_binit(&bcmstrbuf, buf, buflen); - b = &bcmstrbuf; - } - cnt = _dhd_psvmps_bylist(macdbg_info, macdbg_info->psvmpmems, - macdbg_info->svmpmems_sz, b); - - if (b && outbuflen) { - if ((uint)buflen > BCMSTRBUF_LEN(b)) { - *outbuflen = buflen - BCMSTRBUF_LEN(b); - } else { - DHD_ERROR(("%s: buflen insufficient!\n", __FUNCTION__)); - *outbuflen = buflen; - /* Do not return buftooshort to allow printing macregs we have got */ - } - } - - return ((cnt > 0) ? BCME_OK : BCME_UNSUPPORTED); -} - -int -dhd_macdbg_psvmpmems(dhd_pub_t *dhdp, char *params, int plen, char *buf, int buflen) -{ - macdbg_info_t *macdbg_info = dhdp->macdbg_info; - dhd_pd11regs_param *pd11regs = (void *)params; - dhd_pd11regs_buf *pd11regs_buf = (void *)buf; - uint16 start_idx; - bool verbose; - svmp_list_t reglist; - struct bcmstrbuf *b = NULL; - struct bcmstrbuf bcmstrbuf; - - start_idx = pd11regs->start_idx; - verbose = pd11regs->verbose; - memcpy(®list, pd11regs->plist, sizeof(reglist)); - memset(buf, '\0', buflen); - bcm_binit(&bcmstrbuf, (char *)(pd11regs_buf->pbuf), - (buflen - OFFSETOF(dhd_pd11regs_buf, pbuf))); - b = &bcmstrbuf; - pd11regs_buf->idx = (uint16)_dhd_print_svmps(macdbg_info, ®list, - start_idx, b, verbose); - - return ((pd11regs_buf->idx > 0) ? BCME_OK : BCME_ERROR); -} - -#endif /* BCMDBG */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_macdbg.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_macdbg.h deleted file mode 100755 index 2175137cee6d..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_macdbg.h +++ /dev/null @@ -1,34 +0,0 @@ -/* D11 macdbg function prototypes for Broadcom 802.11abgn - * Networking Adapter Device Drivers. - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - * - * $Id: dhd_macdbg.h 649388 2016-07-15 22:54:42Z shinuk $ - */ - -#ifndef _dhd_macdbg_h_ -#define _dhd_macdbg_h_ -#ifdef BCMDBG -#include -#include - -extern int dhd_macdbg_attach(dhd_pub_t *dhdp); -extern void dhd_macdbg_detach(dhd_pub_t *dhdp); -extern void dhd_macdbg_event_handler(dhd_pub_t *dhdp, uint32 reason, - uint8 *event_data, uint32 datalen); -extern int dhd_macdbg_dumpmac(dhd_pub_t *dhdp, char *buf, int buflen, int *outbuflen, bool dump_x); -extern int dhd_macdbg_pd11regs(dhd_pub_t *dhdp, char *params, int plen, char *buf, int buflen); -extern int dhd_macdbg_reglist(dhd_pub_t *dhdp, char *buf, int buflen); -extern int dhd_macdbg_dumpsvmp(dhd_pub_t *dhdp, char *buf, int buflen, int *outbuflen); -extern int dhd_macdbg_psvmpmems(dhd_pub_t *dhdp, char *params, int plen, char *buf, int buflen); -#endif /* BCMDBG */ -#endif /* _dhd_macdbg_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_mschdbg.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_mschdbg.c old mode 100755 new mode 100644 index 5865b6dd2525..167fa19e08fc --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_mschdbg.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_mschdbg.c @@ -1,7 +1,7 @@ /* * DHD debugability support * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -20,7 +20,7 @@ * * <> * - * $Id: dhd_mschdbg.c 639872 2016-05-25 05:39:30Z sjadhav $ + * $Id: dhd_mschdbg.c 639872 2016-05-25 05:39:30Z $ */ #ifdef SHOW_LOGTRACE #include @@ -47,17 +47,17 @@ static const char *head_log = ""; } \ } while (0) -#ifdef DHD_EFI +#if defined(CUSTOM_PREFIX) #define MSCH_EVENT(args) \ do { \ if (dhd_msg_level & DHD_EVENT_VAL) { \ - DHD_LOG_DUMP_WRITE_FW("[%s]: ", dhd_log_dump_get_timestamp()); \ - DHD_LOG_DUMP_WRITE_FW args; \ + DBG_PRINT_SYSTEM_TIME; \ + pr_cont args; \ } \ } while (0) #else #define MSCH_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0) -#endif /* DHD_EFI */ +#endif static uint64 solt_start_time[4], req_start_time[4], profiler_start_time[4]; static uint32 solt_chanspec[4] = {0, }, req_start[4] = {0, }; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_mschdbg.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_mschdbg.h old mode 100755 new mode 100644 index 12ba3ab00c7d..533b4ebd5119 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_mschdbg.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_mschdbg.h @@ -1,7 +1,7 @@ /* * DHD debugability header file * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -20,7 +20,7 @@ * * <> * - * $Id: dhd_mschdbg.h 571265 2015-07-14 20:50:18Z eccopark $ + * $Id: dhd_mschdbg.h 571265 2015-07-14 20:50:18Z $ */ #ifndef _dhd_mschdbg_h_ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c old mode 100755 new mode 100644 index 2262533f53a5..55773b2c9e13 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c @@ -3,7 +3,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -39,11 +39,7 @@ #include #include -#ifdef BCMDBUS -#include -#else #include -#endif /* BCMDBUS */ #include #include @@ -59,15 +55,7 @@ #include #include #include -#ifdef DHD_TIMESYNC -#include -#endif /* DHD_TIMESYNC */ -#ifdef DHD_PKTTS -#include -#include -#endif /* DHD_PKTTS */ #include - #if defined(DHD_LB) #if !defined(LINUX) && !defined(linux) && !defined(OEM_ANDROID) #error "DHD Loadbalancing only supported on LINUX | OEM_ANDROID" @@ -115,15 +103,8 @@ extern char fw_version[]; #define RETRIES 2 /* # of retries to retrieve matching ioctl response */ -#if defined(DHD_HTPUT_TUNABLES) -#define DEFAULT_RX_BUFFERS_TO_POST 1024 -#define RX_BUF_BURST 64 /* Rx buffers for MSDU Data */ -#define RXBUFPOST_THRESHOLD 64 /* Rxbuf post threshold */ -#else -#define DEFAULT_RX_BUFFERS_TO_POST 256 -#define RX_BUF_BURST 32 /* Rx buffers for MSDU Data */ -#define RXBUFPOST_THRESHOLD 32 /* Rxbuf post threshold */ -#endif /* DHD_HTPUT_TUNABLES */ +/* For legacy firmware where pcie shared structure does not have max_host_rxbufs, use this */ +#define LEGACY_MAX_RXBUFPOST 256u /* Read index update Magic sequence */ #define DHD_DMA_INDX_SEQ_H2D_DB_MAGIC 0xDDDDDDDDAu @@ -168,9 +149,6 @@ extern char fw_version[]; #define DHD_FLOWRING_MAX_EVENTBUF_POST 32 #define DHD_FLOWRING_MAX_IOCTLRESPBUF_POST 8 #define DHD_H2D_INFORING_MAX_BUF_POST 32 -#ifdef BTLOG -#define DHD_H2D_BTLOGRING_MAX_BUF_POST 32 -#endif /* BTLOG */ #define DHD_MAX_TSBUF_POST 8 #define DHD_PROT_FUNCS 43 @@ -237,15 +215,15 @@ struct msgbuf_ring; /* ring context for common and flow rings */ * Dongle advertizes host side sync mechanism requirements. */ +#ifdef PCIE_D2H_SYNC_RETRY_CNT_ONE +#define PCIE_D2H_SYNC_WAIT_TRIES (1U) +#define PCIE_D2H_SYNC_NUM_OF_STEPS (1U) +#define PCIE_D2H_SYNC_DELAY (1UL) /* in terms of usecs */ +#else #define PCIE_D2H_SYNC_WAIT_TRIES (512U) #define PCIE_D2H_SYNC_NUM_OF_STEPS (5U) #define PCIE_D2H_SYNC_DELAY (100UL) /* in terms of usecs */ - -#ifdef DHD_REPLACE_LOG_INFO_TO_TRACE -#define DHD_MSGBUF_INFO DHD_TRACE -#else -#define DHD_MSGBUF_INFO DHD_INFO -#endif /* DHD_REPLACE_LOG_INFO_TO_TRACE */ +#endif /* PCIE_D2H_SYNC_RETRY_CNT_ONE */ /** * Custom callback attached based upon D2H DMA Sync mode advertized by dongle. @@ -256,6 +234,8 @@ struct msgbuf_ring; /* ring context for common and flow rings */ typedef uint8 (* d2h_sync_cb_t)(dhd_pub_t *dhd, struct msgbuf_ring *ring, volatile cmn_msg_hdr_t *msg, int msglen); +void dhd_prot_debug_ring_info(dhd_pub_t *dhd); + /** * Custom callback attached based upon D2H DMA Sync mode advertized by dongle. * For EDL messages. @@ -501,15 +481,16 @@ typedef struct msgbuf_ring { #endif /* AGG_H2D_DB */ #endif /* TXP_FLUSH_NITEMS */ - uint8 ring_type; - uint8 n_completion_ids; - bool create_pending; - uint16 create_req_id; - uint8 current_phase; - uint16 compeltion_ring_ids[MAX_COMPLETION_RING_IDS_ASSOCIATED]; + uint8 ring_type; + uint8 n_completion_ids; + bool create_pending; + uint16 create_req_id; + uint8 current_phase; + uint16 compeltion_ring_ids[MAX_COMPLETION_RING_IDS_ASSOCIATED]; uchar name[RING_NAME_MAX_LENGTH]; uint32 ring_mem_allocated; - void *ring_lock; + void *ring_lock; + struct msgbuf_ring *linked_ring; /* Ring Associated to metadata ring */ } msgbuf_ring_t; #define DHD_RING_BGN_VA(ring) ((ring)->dma_buf.va) @@ -517,34 +498,6 @@ typedef struct msgbuf_ring { ((uint8 *)(DHD_RING_BGN_VA((ring))) + \ (((ring)->max_items - 1) * (ring)->item_len)) -#if defined(BCMINTERNAL) && defined(DHD_DBG_DUMP) -#define MAX_IOCTL_TRACE_SIZE 50 -#define MAX_IOCTL_BUF_SIZE 64 -typedef struct _dhd_ioctl_trace_t { - uint32 cmd; - uint16 transid; - char ioctl_buf[MAX_IOCTL_BUF_SIZE]; - uint64 timestamp; -} dhd_ioctl_trace_t; -#endif /* defined(BCMINTERNAL) && defined(DHD_DBG_DUMP) */ - -#ifdef DHD_PKTTS -struct pktts_fwtx_v1 { - uint32 ts[PKTTS_MAX_FWTX]; -}; - -struct pktts_fwtx_v2 { - uint32 ts[PKTTS_MAX_FWTX]; - uint32 ut[PKTTS_MAX_UCTX]; - uint32 uc[PKTTS_MAX_UCCNT]; -}; - -static void dhd_msgbuf_send_msg_tx_ts(dhd_pub_t *dhd, void *pkt, - void *fw_ts, uint16 version); -static void dhd_msgbuf_send_msg_rx_ts(dhd_pub_t *dhd, void *pkt, - uint fwr1, uint fwr2); -#endif /* DHD_PKTTS */ - #if (defined(BCM_ROUTER_DHD) && defined(HNDCTF)) /** D2H WLAN Rx Packet Chaining context */ typedef struct rxchain_info { @@ -558,13 +511,67 @@ typedef struct rxchain_info { } rxchain_info_t; #endif /* BCM_ROUTER_DHD && HNDCTF */ -/* This can be overwritten by module parameter defined in dhd_linux.c - * or by dhd iovar h2d_max_txpost. - */ -int h2d_max_txpost = H2DRING_TXPOST_MAX_ITEM; -#if defined(DHD_HTPUT_TUNABLES) -int h2d_htput_max_txpost = H2DRING_HTPUT_TXPOST_MAX_ITEM; -#endif /* DHD_HTPUT_TUNABLES */ +/* Legacy ring sizes for 1Gbps and lesser */ +#define H2DRING_TXPOST_SIZE_V1 512u +#define H2DRING_HTPUT_TXPOST_SIZE_V1 512u /* Keep it same as H2DRING_TXPOST_SIZE_V1 */ +#define D2HRING_TXCPL_SIZE_V1 1024u + +#define H2DRING_RXPOST_SIZE_V1 512u +#define D2HRING_RXCPL_SIZE_V1 512u + +#define H2DRING_CTRLPOST_SIZE_V1 64u +#define D2HRING_CTRLCPL_SIZE_V1 64u + +#define RX_BUF_BURST_V1 32u /* Rx buffers for MSDU Data */ +#define RX_BUFPOST_THRESHOLD_V1 32u /* Rxbuf post threshold */ + +/* Ring sizes version 2 for 2Gbps */ +#define H2DRING_TXPOST_SIZE_V2 512u +#define H2DRING_HTPUT_TXPOST_SIZE_V2 2048u /* ONLY for 4 160 MHz BE flowrings */ +#define D2HRING_TXCPL_SIZE_V2 2048u + +#define H2DRING_RXPOST_SIZE_V2 2048u +#define D2HRING_RXCPL_SIZE_V2 1024u + +#define H2DRING_CTRLPOST_SIZE_V2 128u +#define D2HRING_CTRLCPL_SIZE_V2 64u + +#define RX_BUF_BURST_V2 64u /* Rx buffers for MSDU Data */ +#define RX_BUFPOST_THRESHOLD_V2 64u /* Rxbuf post threshold */ + +int ring_size_version; +int ring_size_alloc_version; + +uint h2d_max_txpost; +uint h2d_htput_max_txpost; +uint d2h_max_txcpl; + +uint h2d_max_rxpost; +uint d2h_max_rxcpl; + +uint h2d_max_ctrlpost; +uint d2h_max_ctrlcpl; + +uint rx_buf_burst; +uint rx_bufpost_threshold; + +#ifndef DHD_RX_CPL_POST_BOUND +#define DHD_RX_CPL_POST_BOUND 1024 +#endif +#ifndef DHD_TX_POST_BOUND +#define DHD_TX_POST_BOUND 256 +#endif +#ifndef DHD_CTRL_CPL_POST_BOUND +#define DHD_CTRL_CPL_POST_BOUND 64 +#endif +#ifndef DHD_TX_CPL_BOUND +#define DHD_TX_CPL_BOUND 2048 +#endif + +uint dhd_rx_cpl_post_bound = DHD_RX_CPL_POST_BOUND; +uint dhd_tx_post_bound = DHD_TX_POST_BOUND; +uint dhd_tx_cpl_bound = DHD_TX_CPL_BOUND; +uint dhd_ctrl_cpl_post_bound = DHD_CTRL_CPL_POST_BOUND; #ifdef AGG_H2D_DB bool agg_h2d_db_enab = TRUE; @@ -592,11 +599,16 @@ typedef struct _agg_h2d_db_info { } agg_h2d_db_info_t; #endif /* AGG_H2D_DB */ +#define DHD_DEBUG_INVALID_PKTID + /** DHD protocol handle. Is an opaque type to other DHD software layers. */ typedef struct dhd_prot { osl_t *osh; /* OSL handle */ - uint16 rxbufpost_sz; + uint16 rxbufpost_sz; /* Size of rx buffer posted to dongle */ + uint16 rxbufpost_alloc_sz; /* Actual rx buffer packet allocated in the host */ uint16 rxbufpost; + uint16 rx_buf_burst; + uint16 rx_bufpost_threshold; uint16 max_rxbufpost; uint32 tot_rxbufpost; uint32 tot_rxcpl; @@ -612,9 +624,7 @@ typedef struct dhd_prot { /* Flow control mechanism based on active transmits pending */ osl_atomic_t active_tx_count; /* increments/decrements on every packet tx/tx_status */ uint16 h2d_max_txpost; -#if defined(DHD_HTPUT_TUNABLES) uint16 h2d_htput_max_txpost; -#endif /* DHD_HTPUT_TUNABLES */ uint16 txp_threshold; /* optimization to write "n" tx items at a time to ring */ /* MsgBuf Ring info: has a dhd_dma_buf that is dynamically allocated */ @@ -714,24 +724,19 @@ typedef struct dhd_prot { * when the WRITE index must be synced to consumer's workq */ dhd_dma_buf_t fw_trap_buf; /* firmware trap buffer */ - +#ifdef FLOW_RING_PREALLOC + /* pre-allocation htput ring buffer */ + dhd_dma_buf_t htput_ring_buf[HTPUT_TOTAL_FLOW_RINGS]; + /* pre-allocation folw ring(non htput rings) */ + dhd_dma_buf_t flow_ring_buf[MAX_FLOW_RINGS]; +#endif /* FLOW_RING_PREALLOC */ uint32 host_ipc_version; /* Host sypported IPC rev */ uint32 device_ipc_version; /* FW supported IPC rev */ uint32 active_ipc_version; /* Host advertised IPC rev */ -#if defined(BCMINTERNAL) && defined(DHD_DBG_DUMP) - dhd_ioctl_trace_t ioctl_trace[MAX_IOCTL_TRACE_SIZE]; - uint32 ioctl_trace_count; -#endif /* defined(BCMINTERNAL) && defined(DHD_DBG_DUMP) */ dhd_dma_buf_t hostts_req_buf; /* For holding host timestamp request buf */ bool hostts_req_buf_inuse; bool rx_ts_log_enabled; bool tx_ts_log_enabled; -#ifdef BTLOG - msgbuf_ring_t *h2dring_btlog_subn; /* H2D btlog submission ring */ - msgbuf_ring_t *d2hring_btlog_cpln; /* D2H btlog completion ring */ - uint16 btlogbufpost; - uint16 max_btlogbufpost; -#endif /* BTLOG */ #ifdef DHD_HMAPTEST uint32 hmaptest_rx_active; uint32 hmaptest_rx_pktid; @@ -747,26 +752,35 @@ typedef struct dhd_prot { dhd_hmaptest_t hmaptest; /* for hmaptest */ bool hmap_enabled; /* TRUE = hmap is enabled */ #endif /* DHD_HMAPTEST */ -#ifdef SNAPSHOT_UPLOAD - dhd_dma_buf_t snapshot_upload_buf; /* snapshot upload buffer */ - uint32 snapshot_upload_len; /* snapshot uploaded len */ - uint8 snapshot_type; /* snaphot uploaded type */ - bool snapshot_cmpl_pending; /* snapshot completion pending */ -#endif /* SNAPSHOT_UPLOAD */ bool no_retry; bool no_aggr; bool fixed_rate; dhd_dma_buf_t host_scb_buf; /* scb host offload buffer */ -#ifdef DHD_HP2P - msgbuf_ring_t *d2hring_hp2p_txcpl; /* D2H HPP Tx completion ring */ - msgbuf_ring_t *d2hring_hp2p_rxcpl; /* D2H HPP Rx completion ring */ -#endif /* DHD_HP2P */ bool no_tx_resource; uint32 txcpl_db_cnt; #ifdef AGG_H2D_DB agg_h2d_db_info_t agg_h2d_db_info; #endif /* AGG_H2D_DB */ uint64 tx_h2d_db_cnt; +#ifdef DHD_DEBUG_INVALID_PKTID + uint8 ctrl_cpl_snapshot[D2HRING_CTRL_CMPLT_ITEMSIZE]; +#endif /* DHD_DEBUG_INVALID_PKTID */ + uint32 event_wakeup_pkt; /* Number of event wakeup packet rcvd */ + uint32 rx_wakeup_pkt; /* Number of Rx wakeup packet rcvd */ + uint32 info_wakeup_pkt; /* Number of info cpl wakeup packet rcvd */ + msgbuf_ring_t *d2hring_md_cpl; /* D2H metadata completion ring */ + /* no. which controls how many rx cpl/post items are processed per dpc */ + uint32 rx_cpl_post_bound; + /* + * no. which controls how many tx post items are processed per dpc, + * i.e, how many tx pkts are posted to flowring from the bkp queue + * from dpc context + */ + uint32 tx_post_bound; + /* no. which controls how many tx cpl items are processed per dpc */ + uint32 tx_cpl_bound; + /* no. which controls how many ctrl cpl/post items are processed per dpc */ + uint32 ctrl_cpl_post_bound; } dhd_prot_t; #ifdef DHD_EWPR_VER2 @@ -819,7 +833,7 @@ static void* dhd_prot_get_ring_space(msgbuf_ring_t *ring, uint16 nitems, /* Consumer: Determine the location where the next message may be consumed */ static uint8* dhd_prot_get_read_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, - uint32 *available_len); + uint32 *available_len, uint32 bound); /* Producer (WR index update) or Consumer (RD index update) indication */ static void dhd_prot_ring_write_complete(dhd_pub_t *dhd, msgbuf_ring_t *ring, @@ -856,6 +870,7 @@ static int dhd_msgbuf_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, static int dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf); static int dhd_fillup_ioct_reqst(dhd_pub_t *dhd, uint16 len, uint cmd, void *buf, int ifidx); +static void dhd_msgbuf_dump_iovar_name(dhd_pub_t *dhd); /* Post buffers for Rx, control ioctl response and events */ static uint16 dhd_msgbuf_rxbuf_post_ctrlpath(dhd_pub_t *dhd, uint8 msgid, uint32 max_to_post); @@ -867,11 +882,6 @@ static int dhd_msgbuf_rxbuf_post_ts_bufs(dhd_pub_t *pub); static void dhd_prot_return_rxbuf(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint32 pktid, uint32 rxcnt); -#if defined(BCMINTERNAL) && defined(DHD_DBG_DUMP) -static void dhd_prot_ioctl_trace(dhd_pub_t *dhd, ioctl_req_msg_t *ioct_rqst, uchar *buf, int len); -static void dhd_prot_ioctl_dump(dhd_prot_t *prot, struct bcmstrbuf *strbuf); -#endif /* defined(BCMINTERNAL) && defined(DHD_DBG_DUMP) */ - /* D2H Message handling */ static int dhd_prot_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8 *buf, uint32 len); @@ -898,9 +908,12 @@ static void dhd_prot_process_flow_ring_resume_response(dhd_pub_t *dhd, void* msg static void dhd_prot_process_flow_ring_suspend_response(dhd_pub_t *dhd, void* msg); /* Monitor Mode */ -#ifdef WL_MONITOR +#if defined(WL_MONITOR) extern bool dhd_monitor_enabled(dhd_pub_t *dhd, int ifidx); extern void dhd_rx_mon_pkt(dhd_pub_t *dhdp, host_rxbuf_cmpl_t* msg, void *pkt, int ifidx); +#if defined(DBG_PKT_MON) +extern void dhd_80211_mon_pkt(dhd_pub_t *dhdp, host_rxbuf_cmpl_t* msg, void *pkt, int ifidx); +#endif /* DBG_PKT_MON */ #endif /* WL_MONITOR */ /* Configure a soft doorbell per D2H ring */ @@ -913,23 +926,13 @@ static void dhd_prot_process_infobuf_complete(dhd_pub_t *dhd, void* buf); #endif /* !BCM_ROUTER_DHD */ static void dhd_prot_process_d2h_mb_data(dhd_pub_t *dhd, void* buf); static void dhd_prot_detach_info_rings(dhd_pub_t *dhd); -#ifdef BTLOG -static void dhd_prot_process_btlog_complete(dhd_pub_t *dhd, void* buf); -static void dhd_prot_detach_btlog_rings(dhd_pub_t *dhd); -#endif /* BTLOG */ -#ifdef DHD_HP2P -static void dhd_prot_detach_hp2p_rings(dhd_pub_t *dhd); -#endif /* DHD_HP2P */ #ifdef EWP_EDL static void dhd_prot_detach_edl_rings(dhd_pub_t *dhd); #endif +static void dhd_prot_detach_md_rings(dhd_pub_t *dhd); static void dhd_prot_process_d2h_host_ts_complete(dhd_pub_t *dhd, void* buf); static void dhd_prot_process_snapshot_complete(dhd_pub_t *dhd, void *buf); -#ifdef DHD_TIMESYNC -extern void dhd_parse_proto(uint8 *pktdata, dhd_pkt_parse_t *parse); -#endif - #ifdef DHD_FLOW_RING_STATUS_TRACE void dhd_dump_bus_flow_ring_status_isr_trace(dhd_bus_t *bus, struct bcmstrbuf *strbuf); void dhd_dump_bus_flow_ring_status_dpc_trace(dhd_bus_t *bus, struct bcmstrbuf *strbuf); @@ -940,12 +943,7 @@ extern bool dhd_protocol_matches_profile(uint8 *p, int plen, const dhd_tx_profile_protocol_t *proto, bool is_host_sfhllc); #endif /* defined(DHD_TX_PROFILE) */ -#ifdef DHD_HP2P -static void dhd_update_hp2p_rxstats(dhd_pub_t *dhd, host_rxbuf_cmpl_t *rxstatus); -static void dhd_update_hp2p_txstats(dhd_pub_t *dhd, host_txbuf_cmpl_t *txstatus); -static void dhd_calc_hp2p_burst(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint16 flowid); -static void dhd_update_hp2p_txdesc(dhd_pub_t *dhd, host_txbuf_post_t *txdesc); -#endif +static void dhd_update_rxstats(dhd_pub_t *dhd, host_rxbuf_cmpl_t *rxstatus); typedef void (*dhd_msgbuf_func_t)(dhd_pub_t *dhd, void *msg); /** callback functions for messages generated by the dongle */ @@ -1031,14 +1029,148 @@ static void dhd_rxchain_commit(dhd_pub_t *dhd); #endif /* DHD_RX_CHAINING */ -#ifdef DHD_EFI -#define DHD_LPBKDTDUMP_ON() (1) -#else #define DHD_LPBKDTDUMP_ON() (dhd_msg_level & DHD_LPBKDTDUMP_VAL) -#endif static void dhd_prot_h2d_sync_init(dhd_pub_t *dhd); +uint32 +dhd_prot_get_tx_post_bound(dhd_pub_t *dhd) +{ + dhd_prot_t *prot = dhd->prot; + return prot->tx_post_bound; +} + +uint32 +dhd_prot_get_ctrl_cpl_post_bound(dhd_pub_t *dhd) +{ + dhd_prot_t *prot = dhd->prot; + return prot->ctrl_cpl_post_bound; +} + +uint32 +dhd_prot_get_tx_cpl_bound(dhd_pub_t *dhd) +{ + dhd_prot_t *prot = dhd->prot; + return prot->tx_cpl_bound; +} + +uint32 +dhd_prot_get_rx_cpl_post_bound(dhd_pub_t *dhd) +{ + dhd_prot_t *prot = dhd->prot; + return prot->rx_cpl_post_bound; +} + +void +dhd_prot_set_tx_post_bound(dhd_pub_t *dhd, uint32 val) +{ + dhd_prot_t *prot = dhd->prot; + prot->tx_post_bound = val; +} + +void +dhd_prot_set_ctrl_cpl_post_bound(dhd_pub_t *dhd, uint32 val) +{ + dhd_prot_t *prot = dhd->prot; + prot->ctrl_cpl_post_bound = val; +} + +void +dhd_prot_set_tx_cpl_bound(dhd_pub_t *dhd, uint32 val) +{ + dhd_prot_t *prot = dhd->prot; + prot->tx_cpl_bound = val; +} + +void dhd_prot_set_rx_cpl_post_bound(dhd_pub_t *dhd, uint32 val) +{ + dhd_prot_t *prot = dhd->prot; + prot->rx_cpl_post_bound = val; +} + +void +dhd_prot_set_ring_size_ver(dhd_pub_t *dhd, int version) +{ + if (ring_size_alloc_version < version) { + DHD_ERROR(("%s: Ring alloced version(%d) is lesser than requested(%d), ABORT\n", + __FUNCTION__, ring_size_alloc_version, version)); + return; + } + ring_size_version = version; + + /* Change each parameters only if they are 0s, non-zero means, + * it is overridden via module parameter. + */ + switch (version) { + case 1: + if (!h2d_max_txpost) { + h2d_max_txpost = H2DRING_TXPOST_SIZE_V1; + } + if (!h2d_htput_max_txpost) { + h2d_htput_max_txpost = H2DRING_HTPUT_TXPOST_SIZE_V1; + } + if (!d2h_max_txcpl) { + d2h_max_txcpl = D2HRING_TXCPL_SIZE_V1; + } + + if (!h2d_max_rxpost) { + h2d_max_rxpost = H2DRING_RXPOST_SIZE_V1; + } + if (!d2h_max_rxcpl) { + d2h_max_rxcpl = D2HRING_RXCPL_SIZE_V1; + } + + if (!h2d_max_ctrlpost) { + h2d_max_ctrlpost = H2DRING_CTRLPOST_SIZE_V1; + } + if (!d2h_max_ctrlcpl) { + d2h_max_ctrlcpl = D2HRING_CTRLCPL_SIZE_V1; + } + + if (!rx_buf_burst) { + rx_buf_burst = RX_BUF_BURST_V1; + } + if (!rx_bufpost_threshold) { + rx_bufpost_threshold = RX_BUFPOST_THRESHOLD_V1; + } + break; + case 2: + if (!h2d_max_txpost) { + h2d_max_txpost = H2DRING_TXPOST_SIZE_V2; + } + if (!h2d_htput_max_txpost) { + h2d_htput_max_txpost = H2DRING_HTPUT_TXPOST_SIZE_V2; + } + if (!d2h_max_txcpl) { + d2h_max_txcpl = D2HRING_TXCPL_SIZE_V2; + } + + if (!h2d_max_rxpost) { + h2d_max_rxpost = H2DRING_RXPOST_SIZE_V2; + } + if (!d2h_max_rxcpl) { + d2h_max_rxcpl = D2HRING_RXCPL_SIZE_V2; + } + + if (!h2d_max_ctrlpost) { + h2d_max_ctrlpost = H2DRING_CTRLPOST_SIZE_V2; + } + if (!d2h_max_ctrlcpl) { + d2h_max_ctrlcpl = D2HRING_CTRLCPL_SIZE_V2; + } + + if (!rx_buf_burst) { + rx_buf_burst = RX_BUF_BURST_V2; + } + if (!rx_bufpost_threshold) { + rx_bufpost_threshold = RX_BUFPOST_THRESHOLD_V2; + } + break; + default: + DHD_ERROR(("%s: invalid override version:%d", __FUNCTION__, version)); + } +} + #ifdef D2H_MINIDUMP dhd_dma_buf_t * dhd_prot_get_minidump_buf(dhd_pub_t *dhd) @@ -1053,6 +1185,11 @@ dhd_prot_get_rxbufpost_sz(dhd_pub_t *dhd) return dhd->prot->rxbufpost_sz; } +uint16 +dhd_prot_get_rxbufpost_alloc_sz(dhd_pub_t *dhd) +{ + return dhd->prot->rxbufpost_alloc_sz; +} uint16 dhd_prot_get_h2d_rx_post_active(dhd_pub_t *dhd) { @@ -1064,7 +1201,7 @@ dhd_prot_get_h2d_rx_post_active(dhd_pub_t *dhd) wr = flow_ring->wr; if (dhd->dma_d2h_ring_upd_support) { - rd = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_RD_UPD, flow_ring->idx); + rd = dhd_prot_dma_indx_get(dhd, H2D_DMA_INDX_RD_UPD, flow_ring->idx); } else { dhd_bus_cmn_readshared(dhd->bus, &rd, RING_RD_UPD, flow_ring->idx); } @@ -1091,26 +1228,51 @@ dhd_prot_get_d2h_rx_cpln_active(dhd_pub_t *dhd) } bool -dhd_prot_is_cmpl_ring_empty(dhd_pub_t *dhd, void *prot_info) +dhd_prot_is_h2d_ring_empty(dhd_pub_t *dhd, void *prot_info) { - msgbuf_ring_t *flow_ring = (msgbuf_ring_t *)prot_info; + msgbuf_ring_t *ring = (msgbuf_ring_t *)prot_info; uint16 rd, wr; bool ret; - if (dhd->dma_d2h_ring_upd_support) { - wr = flow_ring->wr; - } else { - dhd_bus_cmn_readshared(dhd->bus, &wr, RING_WR_UPD, flow_ring->idx); - } + /* For h2d ring, WR is owned by host, RD is owned by dongle */ + wr = ring->wr; if (dhd->dma_h2d_ring_upd_support) { - rd = flow_ring->rd; + rd = dhd_prot_dma_indx_get(dhd, H2D_DMA_INDX_RD_UPD, ring->idx); } else { - dhd_bus_cmn_readshared(dhd->bus, &rd, RING_RD_UPD, flow_ring->idx); + dhd_bus_cmn_readshared(dhd->bus, &rd, RING_RD_UPD, ring->idx); } ret = (wr == rd) ? TRUE : FALSE; return ret; } +/* returns TRUE if there are pending ctrl completions to be processed at host */ +bool +dhd_prot_check_pending_ctrl_cmpls(dhd_pub_t *dhd) +{ + msgbuf_ring_t *ring = &dhd->prot->d2hring_ctrl_cpln; + uint16 wr, host_rd; + bool ret; + + /* For Completion ring, WR is owned by dongle, RD is owned by Host */ + if (dhd->dma_d2h_ring_upd_support) { + wr = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_WR_UPD, ring->idx); + } else { + dhd_bus_cmn_readshared(dhd->bus, &wr, RING_WR_UPD, ring->idx); + } + + if (wr > ring->max_items) { + DHD_ERROR(("%s(): ring %p, ring->name %s, wr %d ring->max_items %d\n", + __FUNCTION__, ring, ring->name, wr, ring->max_items)); + return FALSE; + } + + host_rd = ring->rd; + + /* Consider the ring as processed if host rd and dongle wr are same */ + ret = (host_rd != wr) ? TRUE : FALSE; + return ret; +} + void dhd_prot_dump_ring_ptrs(void *prot_info) { @@ -1119,29 +1281,6 @@ dhd_prot_dump_ring_ptrs(void *prot_info) ring->curr_rd, ring->rd, ring->wr)); } -uint16 -dhd_prot_get_h2d_max_txpost(dhd_pub_t *dhd) -{ - return (uint16)h2d_max_txpost; -} -void -dhd_prot_set_h2d_max_txpost(dhd_pub_t *dhd, uint16 max_txpost) -{ - h2d_max_txpost = max_txpost; -} -#if defined(DHD_HTPUT_TUNABLES) -uint16 -dhd_prot_get_h2d_htput_max_txpost(dhd_pub_t *dhd) -{ - return (uint16)h2d_htput_max_txpost; -} -void -dhd_prot_set_h2d_htput_max_txpost(dhd_pub_t *dhd, uint16 htput_max_txpost) -{ - h2d_htput_max_txpost = htput_max_txpost; -} - -#endif /* DHD_HTPUT_TUNABLES */ /** * D2H DMA to completion callback handlers. Based on the mode advertised by the * dongle through the PCIE shared region, the appropriate callback will be @@ -1193,9 +1332,6 @@ dhd_prot_d2h_sync_livelock(dhd_pub_t *dhd, uint32 msg_seqnum, msgbuf_ring_t *rin dhd_prhex("D2H MsgBuf Failure", msg, msglen, DHD_ERROR_VAL); /* Try to resume if already suspended or suspend in progress */ -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(dhd, CAN_SLEEP(), __builtin_return_address(0)); -#endif /* DHD_PCIE_RUNTIMEPM */ /* Skip if still in suspended or suspend in progress */ if (DHD_BUS_CHECK_SUSPEND_OR_ANY_SUSPEND_IN_PROGRESS(dhd)) { @@ -1219,14 +1355,6 @@ exit: dhd_schedule_reset(dhd); #ifdef OEM_ANDROID -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - dhd->bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ - /* XXX Trigger HANG event for recovery */ - dhd->hang_reason = HANG_REASON_MSGBUF_LIVELOCK; - dhd_os_send_hang_message(dhd); -#endif /* SUPPORT_LINKDOWN_RECOVERY */ #endif /* OEM_ANDROID */ dhd->livelock_occured = TRUE; } @@ -1838,7 +1966,16 @@ typedef struct dhd_pktid_log { typedef void * dhd_pktid_log_handle_t; /* opaque handle to pktid log */ -#define MAX_PKTID_LOG (2048) +#define MAX_PKTID_LOG (2048u) +/* + * index timestamp pktaddr(pa) pktid size + * index(5) + timestamp (<= 20) + dummy(4) + pa (<=11) + pktid (10) + size(7) + + * pkttype(7) + space(6) + null/lf(2) + * ex) 1367 78348654722 0xabbe69040 3317 1920 1 + */ +#define PKTID_LOG_STR_SZ 72u +#define MAX_PKTID_LOG_BUF_SZ MAX_PKTID_LOG * PKTID_LOG_STR_SZ + \ + strlen(PKTID_LOG_DUMP_FMT) #define DHD_PKTID_LOG_ITEM_SZ (sizeof(dhd_pktid_log_item_t)) #define DHD_PKTID_LOG_SZ(items) (uint32)((sizeof(dhd_pktid_log_t)) + \ ((DHD_PKTID_LOG_ITEM_SZ) * (items))) @@ -1847,7 +1984,11 @@ typedef void * dhd_pktid_log_handle_t; /* opaque handle to pktid log */ #define DHD_PKTID_LOG_FINI(dhd, hdl) dhd_pktid_logging_fini((dhd), (hdl)) #define DHD_PKTID_LOG(dhd, hdl, pa, pktid, len, pkttype) \ dhd_pktid_logging((dhd), (hdl), (pa), (pktid), (len), (pkttype)) +#ifndef DHD_IGNORE_PKTID_AUDIT_ERROR #define DHD_PKTID_LOG_DUMP(dhd) dhd_pktid_logging_dump((dhd)) +#else +#define DHD_PKTID_LOG_DUMP(dhd) +#endif /* DHD_IGNORE_PKTID_AUDIT_ERROR */ static dhd_pktid_log_handle_t * dhd_pktid_logging_init(dhd_pub_t *dhd, uint32 num_items) @@ -1856,9 +1997,9 @@ dhd_pktid_logging_init(dhd_pub_t *dhd, uint32 num_items) uint32 log_size; log_size = DHD_PKTID_LOG_SZ(num_items); - log = (dhd_pktid_log_t *)MALLOCZ(dhd->osh, log_size); + log = (dhd_pktid_log_t *)KVMALLOCZ(dhd->osh, log_size); if (log == NULL) { - DHD_ERROR(("%s: MALLOC failed for size %d\n", + DHD_ERROR(("%s: KVMALLOC failed for size %d\n", __FUNCTION__, log_size)); return (dhd_pktid_log_handle_t *)NULL; } @@ -1882,7 +2023,7 @@ dhd_pktid_logging_fini(dhd_pub_t *dhd, dhd_pktid_log_handle_t *handle) log = (dhd_pktid_log_t *)handle; log_size = DHD_PKTID_LOG_SZ(log->items); - MFREE(dhd->osh, handle, log_size); + KVMFREE(dhd->osh, handle, log_size); } static void @@ -1919,10 +2060,15 @@ dhd_pktid_logging_dump(dhd_pub_t *dhd) return; } + dhd->enable_pktid_log_dump = TRUE; + map_log = (dhd_pktid_log_t *)(prot->pktid_dma_map); unmap_log = (dhd_pktid_log_t *)(prot->pktid_dma_unmap); OSL_GET_LOCALTIME(&ts_sec, &ts_usec); if (map_log && unmap_log) { + DHD_ERROR(("%s: map_log(%s), unmap_log(%s)\n", __FUNCTION__, + is_vmalloc_addr(map_log) ? "vmalloc" : "kmalloc", + is_vmalloc_addr(unmap_log) ? "vmalloc" : "kmalloc")); DHD_ERROR(("%s: map_idx=%d unmap_idx=%d " "current time=[%5lu.%06lu]\n", __FUNCTION__, map_log->index, unmap_log->index, @@ -1935,6 +2081,113 @@ dhd_pktid_logging_dump(dhd_pub_t *dhd) (uint32)(DHD_PKTID_LOG_ITEM_SZ * unmap_log->items))); } } + +uint32 +dhd_pktid_buf_len(dhd_pub_t *dhd, bool is_map) +{ + dhd_prot_t *prot = dhd->prot; + dhd_pktid_log_t *pktlog_buf; + uint32 len = 0; + + if (is_map == TRUE) { + pktlog_buf = (dhd_pktid_log_t *)(prot->pktid_dma_map); + len += strlen(DHD_PKTID_MAP_LOG_HDR); + } else { + pktlog_buf = (dhd_pktid_log_t *)(prot->pktid_dma_unmap); + len += strlen(DHD_PKTID_UNMAP_LOG_HDR); + } + + if (!pktlog_buf) { + return 0; /* len should be 0. */ + } + + /* Adding Format string + LineFeed */ + len += strlen(PKTID_LOG_DUMP_FMT) + 2; + len += (uint32)PKTID_LOG_STR_SZ * pktlog_buf->items; + + return len; +} + +int +dhd_write_pktid_log_dump(dhd_pub_t *dhdp, const void *user_buf, + void *fp, uint32 len, unsigned long *pos, bool is_map) +{ + dhd_prot_t *prot = dhdp->prot; + dhd_pktid_log_t *log_buf; + log_dump_section_hdr_t sec_hdr; + char *buf; + uint32 buflen = 0, remain_len = 0; + unsigned long long addr = 0; + int i = 0; + int ret = BCME_OK; + + if (prot == NULL) { + DHD_ERROR(("%s: prot is NULL\n", __FUNCTION__)); + return BCME_ERROR; + } + + buf = (char *)VMALLOCZ(dhdp->osh, MAX_PKTID_LOG_BUF_SZ); + if (!buf) { + DHD_ERROR(("%s: buf alloc fails!\n", __FUNCTION__)); + return BCME_NOMEM; + } + remain_len = buflen = MAX_PKTID_LOG_BUF_SZ; + + dhd_init_sec_hdr(&sec_hdr); + sec_hdr.magic = LOG_DUMP_MAGIC; + + if (is_map) { + log_buf = prot->pktid_dma_map; + ret = dhd_export_debug_data(DHD_PKTID_MAP_LOG_HDR, fp, user_buf, + strlen(DHD_PKTID_MAP_LOG_HDR), pos); + if (ret < 0) { + DHD_ERROR(("%s : PKTID_MAP_LOG_HDR write error\n", + __FUNCTION__)); + goto exit; + } + sec_hdr.type = LOG_DUMP_SECTION_PKTID_MAP_LOG; + } else { + log_buf = prot->pktid_dma_unmap; + ret = dhd_export_debug_data(DHD_PKTID_UNMAP_LOG_HDR, fp, user_buf, + strlen(DHD_PKTID_UNMAP_LOG_HDR), pos); + if (ret < 0) { + DHD_ERROR(("%s : PKTID_UNMAP_LOG_HDR write error\n", + __FUNCTION__)); + goto exit; + } + sec_hdr.type = LOG_DUMP_SECTION_PKTID_UNMAP_LOG; + } + + remain_len -= scnprintf(&buf[buflen - remain_len], remain_len, + PKTID_LOG_DUMP_FMT, log_buf->index); + + for (i = 0; i < log_buf->items; i++) { +#ifdef BCMDMA64OSL + PHYSADDRTOULONG(log_buf->map[i].pa, addr); +#else + addr = PHYSADDRLO(log_buf->map[i].pa); +#endif /* BCMDMA64OSL */ + remain_len -= scnprintf(&buf[buflen - remain_len], remain_len, + "%5u %20llu %4s 0x%llx %10u %7u %7u\n", + i, log_buf->map[i].ts_nsec, " ", addr, + log_buf->map[i].pktid, log_buf->map[i].size, + log_buf->map[i].pkttype); + } + remain_len -= scnprintf(&buf[buflen - remain_len], remain_len, "\n"); + + sec_hdr.timestamp = local_clock(); + sec_hdr.length = buflen - remain_len; + + ret = dhd_export_debug_data((char *)&sec_hdr, NULL, user_buf, sizeof(sec_hdr), pos); + ret = dhd_export_debug_data(buf, NULL, user_buf, sec_hdr.length, pos); + +exit: + if (buf) { + VMFREE(dhdp->osh, buf, buflen); + } + + return ret; +} #endif /* DHD_MAP_PKTID_LOGGING */ /* +----------------- End of DHD_MAP_PKTID_LOGGING -----------------------+ */ @@ -1992,10 +2245,7 @@ typedef enum dhd_pkttype { #define DHD_H2D_BTLOGRING_REQ_PKTID 0xFFFA #define DHD_D2H_BTLOGRING_REQ_PKTID 0xFFF9 #define DHD_H2D_SNAPSHOT_UPLOAD_REQ_PKTID 0xFFF8 -#ifdef DHD_HP2P -#define DHD_D2H_HPPRING_TXREQ_PKTID 0xFFF7 -#define DHD_D2H_HPPRING_RXREQ_PKTID 0xFFF6 -#endif /* DHD_HP2P */ +#define DHD_D2H_MDRING_REQ_PKTID 0xFFF8 #define IS_FLOWRING(ring) \ ((strncmp(ring->name, "h2dflr", sizeof("h2dflr"))) == (0)) @@ -2014,14 +2264,14 @@ static void dhd_pktid_map_fini(dhd_pub_t *dhd, dhd_pktid_map_handle_t *map); #define DHD_NATIVE_TO_PKTID_FINI_IOCTL(osh, map) dhd_pktid_map_fini_ioctl((osh), (map)) #if defined(DHD_PCIE_PKTID) -#if defined(NDIS) || defined(DHD_EFI) +#if defined(NDIS) /* XXX: for NDIS, using consistent memory instead of buffer from PKTGET for * up to 8K ioctl response */ #define IOCTLRESP_USE_CONSTMEM static void free_ioctl_return_buffer(dhd_pub_t *dhd, dhd_dma_buf_t *retbuf); static int alloc_ioctl_return_buffer(dhd_pub_t *dhd, dhd_dma_buf_t *retbuf); -#endif /* NDIS || DHD_EFI */ +#endif /* Determine number of pktids that are available */ static INLINE uint32 dhd_pktid_map_avail_cnt(dhd_pktid_map_handle_t *handle); @@ -2041,19 +2291,14 @@ static void *dhd_pktid_map_free(dhd_pub_t *dhd, dhd_pktid_map_handle_t *map, uint32 id, dmaaddr_t *pa, uint32 *len, void **dmah, void **secdma, dhd_pkttype_t pkttype, bool rsv_locker); -#ifdef DHD_PKTTS -/* Store the Metadata buffer to the locker */ -static INLINE void -dhd_pktid_map_save_metadata(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, void *mpkt, - dmaaddr_t mpkt_pa, - uint16 mpkt_len, - void *dmah, - uint32 nkey); - -/* Return the Metadata buffer from the locker */ -static void * dhd_pktid_map_retreive_metadata(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, - dmaaddr_t *pmpkt_pa, uint32 *pmpkt_len, void **pdmah, uint32 nkey); -#endif /* DHD_PKTTS */ +/* Metadata d2h completion ring linking/unlink ring types */ +typedef enum dhd_mdata_linked_ring_idx { + DHD_METADATA_NO_RING = 0, + DHD_METADATA_D2H_TXCPL, + DHD_METADATA_D2H_RXCPL, + DHD_METADATA_D2H_HP2PTX, + DHD_METADATA_D2H_HP2PRX +} dhd_mdata_linked_ring_idx_t; /* * DHD_PKTID_AUDIT_ENABLED: Audit of PktIds in DHD for duplicate alloc and frees @@ -2141,11 +2386,6 @@ typedef struct dhd_pktid_item { dmaaddr_t pa; /* physical address of mapped packet's buffer */ void *dmah; /* handle to OS specific DMA map */ void *secdma; -#ifdef DHD_PKTTS - void *mpkt; /* VA of Metadata */ - dmaaddr_t mpkt_pa; /* PA of Metadata */ - uint16 mpkt_len; /* Length of Metadata */ -#endif /* DHD_PKTTS */ } dhd_pktid_item_t; typedef uint32 dhd_pktid_key_t; @@ -2211,19 +2451,16 @@ typedef struct dhd_pktid_map { (dmaaddr_t *)&(pa), (uint32 *)&(len), (void **)&(dmah), \ (void **)&(secdma), (dhd_pkttype_t)(pkttype), DHD_PKTID_RSV_LOCKER) -#ifdef DHD_PKTTS -#define DHD_PKTID_SAVE_METADATA(dhd, map, mpkt, mpkt_pa, mpkt_len, dmah, nkey) \ - dhd_pktid_map_save_metadata(dhd, map, mpkt, mpkt_pa, mpkt_len, dmah, nkey) - -#define DHD_PKTID_RETREIVE_METADATA(dhd, map, mpkt_pa, mpkt_len, dmah, nkey) \ - dhd_pktid_map_retreive_metadata(dhd, map, (dmaaddr_t *)&mpkt_pa, (uint32 *)&mpkt_len, \ - (void **) &dmah, nkey) -#endif /* DHD_PKTTS */ - #define DHD_PKTID_AVAIL(map) dhd_pktid_map_avail_cnt(map) #if defined(DHD_PKTID_AUDIT_ENABLED) +#ifndef DHD_IGNORE_PKTID_AUDIT_ERROR +#define DHD_PKTID_ERROR_HANDLER(dhdp) dhd_pktid_error_handler((dhdp)) +#else +#define DHD_PKTID_ERROR_HANDLER(dhdp) +#endif /* DHD_IGNORE_PKTID_AUDIT_ERROR */ + static int dhd_get_pktid_map_type(dhd_pub_t *dhd, dhd_pktid_map_t *pktid_map) { @@ -2329,24 +2566,26 @@ out: DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); if (error != BCME_OK) { +#ifndef DHD_IGNORE_PKTID_AUDIT_ERROR dhd->pktid_audit_failed = TRUE; +#endif /* !DHD_IGNORE_PKTID_AUDIT_ERROR */ } return error; } static int -dhd_pktid_audit(dhd_pub_t *dhd, dhd_pktid_map_t *pktid_map, uint32 pktid, +dhd_pktid_audit(dhd_pub_t *dhdp, dhd_pktid_map_t *pktid_map, uint32 pktid, const int test_for, const char *errmsg) { int ret = BCME_OK; - ret = __dhd_pktid_audit(dhd, pktid_map, pktid, test_for, errmsg); + ret = __dhd_pktid_audit(dhdp, pktid_map, pktid, test_for, errmsg); if (ret == BCME_ERROR) { DHD_ERROR(("%s: Got Pkt Id Audit failure: PKTID<%d> PKTID MAP TYPE<%d>\n", - __FUNCTION__, pktid, dhd_get_pktid_map_type(dhd, pktid_map))); - dhd_pktid_error_handler(dhd); + __FUNCTION__, pktid, dhd_get_pktid_map_type(dhdp, pktid_map))); + DHD_PKTID_ERROR_HANDLER(dhdp); #ifdef DHD_MAP_PKTID_LOGGING - DHD_PKTID_LOG_DUMP(dhd); + DHD_PKTID_LOG_DUMP(dhdp); #endif /* DHD_MAP_PKTID_LOGGING */ } @@ -2371,7 +2610,17 @@ dhd_pktid_audit_ring_debug(dhd_pub_t *dhdp, dhd_pktid_map_t *map, uint32 pktid, DHD_ERROR(("%s: Got Pkt Id Audit failure: PKTID<%d> PKTID MAP TYPE<%d>\n", __FUNCTION__, pktid, dhd_get_pktid_map_type(dhdp, map))); prhex(func, (uchar *)msg, msg_len); - dhd_pktid_error_handler(dhdp); + if (map == dhdp->prot->pktid_ctrl_map) { +#ifdef DHD_DEBUG_INVALID_PKTID + prhex("ctrl_cpl_snapshot", dhdp->prot->ctrl_cpl_snapshot, + D2HRING_CTRL_CMPLT_ITEMSIZE); +#endif /* DHD_DEBUG_INVALID_PKTID */ + } + DHD_ERROR(("%s: ### For pktid audit failures, read curr_rd as curr_rd - 1," + " as it is updated early before item processing ###\n", + __FUNCTION__)); + dhd_prot_debug_ring_info(dhdp); + DHD_PKTID_ERROR_HANDLER(dhdp); #ifdef DHD_MAP_PKTID_LOGGING DHD_PKTID_LOG_DUMP(dhdp); #endif /* DHD_MAP_PKTID_LOGGING */ @@ -2421,7 +2670,7 @@ dhd_pktid_map_init(dhd_pub_t *dhd, uint32 num_items) map = (dhd_pktid_map_t *)VMALLOC(osh, dhd_pktid_map_sz); if (map == NULL) { - DHD_ERROR(("%s:%d: MALLOC failed for size %d\n", + DHD_ERROR(("%s:%d: VMALLOC failed for size %d\n", __FUNCTION__, __LINE__, dhd_pktid_map_sz)); return (dhd_pktid_map_handle_t *)NULL; } @@ -2440,9 +2689,9 @@ dhd_pktid_map_init(dhd_pub_t *dhd, uint32 num_items) goto error; } - map->keys = (dhd_pktid_key_t *)MALLOC(osh, map_keys_sz); + map->keys = (dhd_pktid_key_t *)VMALLOC(osh, map_keys_sz); if (map->keys == NULL) { - DHD_ERROR(("%s:%d: MALLOC failed for map->keys size %d\n", + DHD_ERROR(("%s:%d: VMALLOC failed for map->keys size %d\n", __FUNCTION__, __LINE__, map_keys_sz)); goto error; } @@ -2491,7 +2740,7 @@ error: #endif /* DHD_PKTID_AUDIT_ENABLED */ if (map->keys) { - MFREE(osh, map->keys, map_keys_sz); + VMFREE(osh, map->keys, map_keys_sz); } if (map->pktid_lock) { @@ -2519,6 +2768,10 @@ dhd_pktid_map_reset(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle) unsigned long flags; bool data_tx = FALSE; + if (handle == NULL) { + return; + } + map = (dhd_pktid_map_t *)handle; DHD_PKTID_LOCK(map->pktid_lock, flags); osh = dhd->osh; @@ -2639,7 +2892,7 @@ dhd_pktid_map_fini(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle) } } #endif /* DHD_PKTID_AUDIT_ENABLED */ - MFREE(dhd->osh, map->keys, map_keys_sz); + VMFREE(dhd->osh, map->keys, map_keys_sz); VMFREE(dhd->osh, handle, dhd_pktid_map_sz); } @@ -2673,7 +2926,7 @@ dhd_pktid_map_fini_ioctl(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle) } #endif /* DHD_PKTID_AUDIT_ENABLED */ - MFREE(dhd->osh, map->keys, map_keys_sz); + VMFREE(dhd->osh, map->keys, map_keys_sz); VMFREE(dhd->osh, handle, dhd_pktid_map_sz); } #endif /* IOCTLRESP_USE_CONSTMEM */ @@ -2750,60 +3003,6 @@ dhd_pktid_map_reserve(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, return nkey; /* return locker's numbered key */ } -#ifdef DHD_PKTTS -/* - * dhd_pktid_map_save_metadata - Save metadata information in a locker - * that has a reserved unique numbered key. - */ -static INLINE void -dhd_pktid_map_save_metadata(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, void *mpkt, - dmaaddr_t mpkt_pa, - uint16 mpkt_len, - void *dmah, - uint32 nkey) -{ - dhd_pktid_map_t *map; - dhd_pktid_item_t *locker; - unsigned long flags; - - ASSERT(handle != NULL); - map = (dhd_pktid_map_t *)handle; - - DHD_PKTID_LOCK(map->pktid_lock, flags); - - if ((nkey == DHD_PKTID_INVALID) || (nkey > DHD_PKIDMAP_ITEMS(map->items))) { - DHD_ERROR(("%s:%d: Error! saving invalid pktid<%u>", - __FUNCTION__, __LINE__, nkey)); - DHD_PKTID_UNLOCK(map->pktid_lock, flags); -#ifdef DHD_FW_COREDUMP - if (dhd->memdump_enabled) { - /* collect core dump */ - dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; - dhd_bus_mem_dump(dhd); - } -#else - ASSERT(0); -#endif /* DHD_FW_COREDUMP */ - return; - } - - locker = &map->lockers[nkey]; - - /* - * TODO: checking the locker state for BUSY will prevent - * us from storing meta data on an already allocated - * Locker. But not checking may lead to overwriting - * existing data. - */ - locker->mpkt = mpkt; - locker->mpkt_pa = mpkt_pa; - locker->mpkt_len = mpkt_len; - locker->dmah = dmah; - - DHD_PKTID_UNLOCK(map->pktid_lock, flags); -} -#endif /* DHD_PKTTS */ - /* * dhd_pktid_map_save - Save a packet's parameters into a locker * corresponding to a previously reserved unique numbered key. @@ -2822,15 +3021,22 @@ dhd_pktid_map_save(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, void *pkt, DHD_PKTID_LOCK(map->pktid_lock, flags); - if ((nkey == DHD_PKTID_INVALID) || (nkey > DHD_PKIDMAP_ITEMS(map->items))) { + if ((nkey == DHD_PKTID_INVALID) || (nkey > DHD_PKIDMAP_ITEMS(map->items)) || + (dhd->dhd_induce_error == DHD_INDUCE_PKTID_INVALID_SAVE)) { DHD_ERROR(("%s:%d: Error! saving invalid pktid<%u> pkttype<%u>\n", __FUNCTION__, __LINE__, nkey, pkttype)); DHD_PKTID_UNLOCK(map->pktid_lock, flags); #ifdef DHD_FW_COREDUMP if (dhd->memdump_enabled) { + dhd->pktid_invalid_occured = TRUE; /* collect core dump */ dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; dhd_bus_mem_dump(dhd); +#ifdef OEM_ANDROID + dhd->hang_reason = HANG_REASON_PCIE_PKTID_ERROR; + dhd_os_send_hang_message(dhd); +#endif /* OEM_ANDROID */ + } #else ASSERT(0); @@ -2878,57 +3084,6 @@ BCMFASTPATH(dhd_pktid_map_alloc)(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, return nkey; } -#ifdef DHD_PKTTS -static void * -BCMFASTPATH(dhd_pktid_map_retreive_metadata)(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, - dmaaddr_t *pmpkt_pa, - uint32 *pmpkt_len, - void **pdmah, - uint32 nkey) -{ - dhd_pktid_map_t *map; - dhd_pktid_item_t *locker; - void *mpkt; - unsigned long flags; - - ASSERT(handle != NULL); - - map = (dhd_pktid_map_t *)handle; - - DHD_PKTID_LOCK(map->pktid_lock, flags); - - /* XXX PLEASE DO NOT remove this ASSERT, fix the bug in caller. */ - if ((nkey == DHD_PKTID_INVALID) || (nkey > DHD_PKIDMAP_ITEMS(map->items))) { - DHD_ERROR(("%s:%d: Error! Try to free invalid pktid<%u>\n", - __FUNCTION__, __LINE__, nkey)); - DHD_PKTID_UNLOCK(map->pktid_lock, flags); -#ifdef DHD_FW_COREDUMP - if (dhd->memdump_enabled) { - /* collect core dump */ - dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; - dhd_bus_mem_dump(dhd); - } -#else - ASSERT(0); -#endif /* DHD_FW_COREDUMP */ - return NULL; - } - - locker = &map->lockers[nkey]; - mpkt = locker->mpkt; - *pmpkt_pa = locker->mpkt_pa; - *pmpkt_len = locker->mpkt_len; - if (pdmah) - *pdmah = locker->dmah; - locker->mpkt = NULL; - locker->mpkt_len = 0; - locker->dmah = NULL; - - DHD_PKTID_UNLOCK(map->pktid_lock, flags); - return mpkt; -} -#endif /* DHD_PKTTS */ - /** * dhd_pktid_map_free - Given a numbered key, return the locker contents. * dhd_pktid_map_free() is not reentrant, and is the caller's responsibility. @@ -2953,15 +3108,21 @@ BCMFASTPATH(dhd_pktid_map_free)(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, DHD_PKTID_LOCK(map->pktid_lock, flags); /* XXX PLEASE DO NOT remove this ASSERT, fix the bug in caller. */ - if ((nkey == DHD_PKTID_INVALID) || (nkey > DHD_PKIDMAP_ITEMS(map->items))) { + if ((nkey == DHD_PKTID_INVALID) || (nkey > DHD_PKIDMAP_ITEMS(map->items)) || + (dhd->dhd_induce_error == DHD_INDUCE_PKTID_INVALID_FREE)) { DHD_ERROR(("%s:%d: Error! Try to free invalid pktid<%u>, pkttype<%d>\n", __FUNCTION__, __LINE__, nkey, pkttype)); DHD_PKTID_UNLOCK(map->pktid_lock, flags); #ifdef DHD_FW_COREDUMP if (dhd->memdump_enabled) { + dhd->pktid_invalid_occured = TRUE; /* collect core dump */ dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; dhd_bus_mem_dump(dhd); +#ifdef OEM_ANDROID + dhd->hang_reason = HANG_REASON_PCIE_PKTID_ERROR; + dhd_os_send_hang_message(dhd); +#endif /* OEM_ANDROID */ } #else ASSERT(0); @@ -2983,9 +3144,14 @@ BCMFASTPATH(dhd_pktid_map_free)(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, /* XXX PLEASE DO NOT remove this ASSERT, fix the bug in caller. */ #ifdef DHD_FW_COREDUMP if (dhd->memdump_enabled) { + dhd->pktid_invalid_occured = TRUE; /* collect core dump */ dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; dhd_bus_mem_dump(dhd); +#ifdef OEM_ANDROID + dhd->hang_reason = HANG_REASON_PCIE_PKTID_ERROR; + dhd_os_send_hang_message(dhd); +#endif /* OEM_ANDROID */ } #else ASSERT(0); @@ -3013,9 +3179,14 @@ BCMFASTPATH(dhd_pktid_map_free)(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, DHD_PKTID_UNLOCK(map->pktid_lock, flags); #ifdef DHD_FW_COREDUMP if (dhd->memdump_enabled) { + dhd->pktid_invalid_occured = TRUE; /* collect core dump */ dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; dhd_bus_mem_dump(dhd); +#ifdef OEM_ANDROID + dhd->hang_reason = HANG_REASON_PCIE_PKTID_ERROR; + dhd_os_send_hang_message(dhd); +#endif /* OEM_ANDROID */ } #else ASSERT(0); @@ -3269,12 +3440,11 @@ dhd_pktid_to_native(dhd_pktid_map_handle_t *map, uint32 pktid32, static int dhd_prot_allocate_bufs(dhd_pub_t *dhd, dhd_prot_t *prot) { - /* Common Ring Allocations */ /* Ring 0: H2D Control Submission */ if (dhd_prot_ring_attach(dhd, &prot->h2dring_ctrl_subn, "h2dctrl", - H2DRING_CTRL_SUB_MAX_ITEM, H2DRING_CTRL_SUB_ITEMSIZE, + (uint16)h2d_max_ctrlpost, H2DRING_CTRL_SUB_ITEMSIZE, BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT) != BCME_OK) { DHD_ERROR(("%s: dhd_prot_ring_attach H2D Ctrl Submission failed\n", __FUNCTION__)); @@ -3283,7 +3453,7 @@ dhd_prot_allocate_bufs(dhd_pub_t *dhd, dhd_prot_t *prot) /* Ring 1: H2D Receive Buffer Post */ if (dhd_prot_ring_attach(dhd, &prot->h2dring_rxp_subn, "h2drxp", - H2DRING_RXPOST_MAX_ITEM, H2DRING_RXPOST_ITEMSIZE, + (uint16)h2d_max_rxpost, H2DRING_RXPOST_ITEMSIZE, BCMPCIE_H2D_MSGRING_RXPOST_SUBMIT) != BCME_OK) { DHD_ERROR(("%s: dhd_prot_ring_attach H2D RxPost failed\n", __FUNCTION__)); @@ -3292,7 +3462,7 @@ dhd_prot_allocate_bufs(dhd_pub_t *dhd, dhd_prot_t *prot) /* Ring 2: D2H Control Completion */ if (dhd_prot_ring_attach(dhd, &prot->d2hring_ctrl_cpln, "d2hctrl", - D2HRING_CTRL_CMPLT_MAX_ITEM, D2HRING_CTRL_CMPLT_ITEMSIZE, + (uint16)d2h_max_ctrlcpl, D2HRING_CTRL_CMPLT_ITEMSIZE, BCMPCIE_D2H_MSGRING_CONTROL_COMPLETE) != BCME_OK) { DHD_ERROR(("%s: dhd_prot_ring_attach D2H Ctrl Completion failed\n", __FUNCTION__)); @@ -3301,7 +3471,7 @@ dhd_prot_allocate_bufs(dhd_pub_t *dhd, dhd_prot_t *prot) /* Ring 3: D2H Transmit Complete */ if (dhd_prot_ring_attach(dhd, &prot->d2hring_tx_cpln, "d2htxcpl", - D2HRING_TXCMPLT_MAX_ITEM, D2HRING_TXCMPLT_ITEMSIZE, + (uint16)d2h_max_txcpl, D2HRING_TXCMPLT_ITEMSIZE, BCMPCIE_D2H_MSGRING_TX_COMPLETE) != BCME_OK) { DHD_ERROR(("%s: dhd_prot_ring_attach D2H Tx Completion failed\n", __FUNCTION__)); @@ -3311,7 +3481,7 @@ dhd_prot_allocate_bufs(dhd_pub_t *dhd, dhd_prot_t *prot) /* Ring 4: D2H Receive Complete */ if (dhd_prot_ring_attach(dhd, &prot->d2hring_rx_cpln, "d2hrxcpl", - D2HRING_RXCMPLT_MAX_ITEM, D2HRING_RXCMPLT_ITEMSIZE, + (uint16)d2h_max_rxcpl, D2HRING_RXCMPLT_ITEMSIZE, BCMPCIE_D2H_MSGRING_RX_COMPLETE) != BCME_OK) { DHD_ERROR(("%s: dhd_prot_ring_attach D2H Rx Completion failed\n", __FUNCTION__)); @@ -3349,6 +3519,7 @@ dhd_prot_allocate_bufs(dhd_pub_t *dhd, dhd_prot_t *prot) #endif /* BCM_HOST_BUF */ { + goto fail; } @@ -3378,13 +3549,6 @@ dhd_prot_allocate_bufs(dhd_pub_t *dhd, dhd_prot_t *prot) goto fail; } -#ifdef SNAPSHOT_UPLOAD - /* snapshot upload buffer */ - if (dhd_dma_buf_alloc(dhd, &prot->snapshot_upload_buf, SNAPSHOT_UPLOAD_BUF_SIZE)) { - goto fail; - } -#endif /* SNAPSHOT_UPLOAD */ - return BCME_OK; fail: @@ -3418,6 +3582,16 @@ dhd_prot_attach(dhd_pub_t *dhd) osl_t *osh = dhd->osh; dhd_prot_t *prot; uint32 trap_buf_len; +#ifdef FLOW_RING_PREALLOC + int i = 0; +#endif /* FLOW_RING_PREALLOC */ + /* bus is required in chipid checks and flowring checks, abort, if it is NULL */ + if (dhd->bus == NULL) { + DHD_ERROR(("%s: Abort as dhd->bus is NULL\n", __FUNCTION__)); + return BCME_ERROR; + } + + dhd->htput_support = dhd_check_htput_chip(dhd->bus); /* Allocate prot structure */ if (!(prot = (dhd_prot_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PROT, @@ -3430,6 +3604,14 @@ dhd_prot_attach(dhd_pub_t *dhd) prot->osh = osh; dhd->prot = prot; + if (dhd->htput_support) { + ring_size_alloc_version = 2; + } else { + ring_size_alloc_version = 1; + } + + dhd_prot_set_ring_size_ver(dhd, ring_size_alloc_version); + /* DMAing ring completes supported? FALSE by default */ dhd->dma_d2h_ring_upd_support = FALSE; dhd->dma_h2d_ring_upd_support = FALSE; @@ -3496,6 +3678,36 @@ dhd_prot_attach(dhd_pub_t *dhd) trap_buf_len = BCMPCIE_EXT_TRAP_DATA_MAXLEN; #endif /* D2H_MINIDUMP */ +#ifdef FLOW_RING_PREALLOC + if (dhd->htput_support) { + /* pre-allocation htput ring */ + for (i = 0; i < HTPUT_TOTAL_FLOW_RINGS; i++) { + if (dhd_dma_buf_alloc(dhd, &dhd->prot->htput_ring_buf[i], + (uint32)(h2d_htput_max_txpost * H2DRING_TXPOST_ITEMSIZE))) + { + DHD_ERROR(("%s : dhd_prealloc_htput_ring_buffer failed\n", + __FUNCTION__)); + goto fail; + } + } + } + + if (dhd->htput_support) { + dhd->non_htput_total_flow_rings = MAX_FLOW_RINGS - HTPUT_TOTAL_FLOW_RINGS; + } else { + dhd->non_htput_total_flow_rings = MAX_FLOW_RINGS; + } + + /* pre-allocation flow ring */ + for (i = 0; i < dhd->non_htput_total_flow_rings; i++) { + if (dhd_dma_buf_alloc(dhd, &dhd->prot->flow_ring_buf[i], + (uint32)(H2DRING_TXPOST_MAX_ITEM * H2DRING_TXPOST_ITEMSIZE))) { + DHD_ERROR(("%s : dhd_prealloc_flowring_buffer failed\n", __FUNCTION__)); + goto fail; + } + } +#endif /* FLOW_RING_PREALLOC */ + /* Initialize trap buffer */ if (dhd_dma_buf_alloc(dhd, &dhd->prot->fw_trap_buf, trap_buf_len)) { DHD_ERROR(("%s: dhd_init_trap_buffer falied\n", __FUNCTION__)); @@ -3559,6 +3771,24 @@ dhd_alloc_host_scbs(dhd_pub_t *dhd) return ret; } +#ifdef DHD_PCIE_PTM +/* + * Currently used to set PCIE PTM capability only. + */ +void +dhd_set_host_cap2(dhd_pub_t *dhd) +{ + uint32 data = 0; + + if (dhd->bus->api.fw_rev >= PCIE_SHARED_VERSION_7) { + /* Advertise PTM capability */ + data |= HOSTCAP2_PCIE_PTM; + dhd_bus_cmn_writeshared(dhd->bus, &data, sizeof(uint32), HOST_CAP2, 0); + DHD_INFO(("Set host_cap2 0x%x\n", data)); + } +} +#endif /* DHD_PCIE_PTM */ + void dhd_set_host_cap(dhd_pub_t *dhd) { @@ -3615,44 +3845,28 @@ dhd_set_host_cap(dhd_pub_t *dhd) if (dhd->pcie_txs_metadata_enable != 0) data |= HOSTCAP_TXSTATUS_METADATA; -#ifdef BTLOG - /* Indicate support for BT logging */ - if (dhd->bt_logging) { - if (dhd->bt_logging_enabled) { - data |= HOSTCAP_BT_LOGGING; - DHD_ERROR(("BT LOGGING enabled\n")); - } - else { - DHD_ERROR(("BT logging upported in FW, BT LOGGING disabled\n")); - } - } - else { - DHD_ERROR(("BT LOGGING not enabled in FW !!\n")); - } -#endif /* BTLOG */ - /* Enable fast delete ring in firmware if supported */ if (dhd->fast_delete_ring_support) { data |= HOSTCAP_FAST_DELETE_RING; } if (dhdpcie_bus_get_pcie_idma_supported(dhd->bus)) { - DHD_ERROR(("IDMA inited\n")); + DHD_ERROR_MEM(("IDMA inited\n")); data |= HOSTCAP_H2D_IDMA; dhd->idma_inited = TRUE; } else { - DHD_ERROR(("IDMA not enabled in FW !!\n")); + DHD_ERROR_MEM(("IDMA not enabled in FW !!\n")); dhd->idma_inited = FALSE; } if (dhdpcie_bus_get_pcie_ifrm_supported(dhd->bus)) { - DHD_ERROR(("IFRM Inited\n")); + DHD_ERROR_MEM(("IFRM Inited\n")); data |= HOSTCAP_H2D_IFRM; dhd->ifrm_inited = TRUE; dhd->dma_h2d_ring_upd_support = FALSE; dhd_prot_dma_indx_free(dhd); } else { - DHD_ERROR(("IFRM not enabled in FW !!\n")); + DHD_ERROR_MEM(("IFRM not enabled in FW !!\n")); dhd->ifrm_inited = FALSE; } @@ -3661,7 +3875,7 @@ dhd_set_host_cap(dhd_pub_t *dhd) data |= HOSTCAP_H2D_DAR; dhd->dar_inited = TRUE; } else { - DHD_ERROR(("DAR not enabled in FW !!\n")); + DHD_ERROR_MEM(("DAR not enabled in FW !!\n")); dhd->dar_inited = FALSE; } @@ -3670,14 +3884,6 @@ dhd_set_host_cap(dhd_pub_t *dhd) */ data |= HOSTCAP_UR_FW_NO_TRAP; -#ifdef SNAPSHOT_UPLOAD - /* Indicate support for snapshot upload */ - if (dhd->snapshot_upload) { - data |= HOSTCAP_SNAPSHOT_UPLOAD; - DHD_ERROR(("ALLOW SNAPSHOT UPLOAD!!\n")); - } -#endif /* SNAPSHOT_UPLOAD */ - if (dhd->hscb_enable) { data |= HOSTCAP_HSCB; } @@ -3697,30 +3903,13 @@ dhd_set_host_cap(dhd_pub_t *dhd) DHD_ERROR(("ALLOW D2H MINIDUMP!!\n")); } #endif /* D2H_MINIDUMP */ -#ifdef DHD_HP2P - if (dhdpcie_bus_get_hp2p_supported(dhd->bus)) { - data |= HOSTCAP_PKT_TIMESTAMP; - data |= HOSTCAP_PKT_HP2P; - DHD_ERROR(("Enable HP2P in host cap\n")); - } else { - DHD_ERROR(("HP2P not enabled in host cap\n")); - } -#endif /* DHD_HP2P */ -#ifdef DHD_DB0TS - if (dhd->db0ts_capable) { - data |= HOSTCAP_DB0_TIMESTAMP; - DHD_ERROR(("Enable DB0 TS in host cap\n")); - } else { - DHD_ERROR(("DB0 TS not enabled in host cap\n")); - } -#endif /* DHD_DB0TS */ if (dhd->extdtxs_in_txcpl) { - DHD_ERROR(("Enable hostcap: EXTD TXS in txcpl\n")); + DHD_ERROR_MEM(("Enable hostcap: EXTD TXS in txcpl\n")); data |= HOSTCAP_PKT_TXSTATUS; } else { - DHD_ERROR(("Enable hostcap: EXTD TXS in txcpl\n")); + DHD_ERROR_MEM(("Enable hostcap: EXTD TXS in txcpl\n")); } DHD_INFO(("%s:Active Ver:%d, Host Ver:%d, FW Ver:%d\n", @@ -3741,9 +3930,6 @@ dhd_set_host_cap(dhd_pub_t *dhd) #endif /* D2H_MINIDUMP */ } -#ifdef DHD_TIMESYNC - dhd_timesync_notify_ipc_rev(dhd->ts, prot->active_ipc_version); -#endif /* DHD_TIMESYNC */ } #ifdef AGG_H2D_DB @@ -3753,6 +3939,10 @@ void dhd_agg_inflight_stats_dump(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) uint32 i; uint64 total_inflight_histo = 0; + if (inflight_histo == NULL) { + return; + } + bcm_bprintf(strbuf, "inflight: \t count\n"); for (i = 0; i < DHD_NUM_INFLIGHT_HISTO_ROWS; i++) { bcm_bprintf(strbuf, "%16u: \t %llu\n", 1U<tx_h2d_db_cnt = 0; } +void +dhd_prot_update_rings_size(dhd_prot_t *prot) +{ + uint16 max_items; + + /* Update ring max_items to MIN of allocated vs iovar overridden */ + max_items = MIN(d2h_max_txcpl, prot->d2hring_tx_cpln.max_items); + d2h_max_txcpl = prot->d2hring_tx_cpln.max_items = max_items; + + max_items = MIN(h2d_max_rxpost, prot->h2dring_rxp_subn.max_items); + h2d_max_rxpost = prot->h2dring_rxp_subn.max_items = max_items; + + max_items = MIN(d2h_max_rxcpl, prot->d2hring_rx_cpln.max_items); + d2h_max_rxcpl = prot->d2hring_rx_cpln.max_items = max_items; + + max_items = MIN(h2d_max_ctrlpost, prot->h2dring_ctrl_subn.max_items); + h2d_max_ctrlpost = prot->h2dring_ctrl_subn.max_items = max_items; + + max_items = MIN(d2h_max_ctrlcpl, prot->d2hring_ctrl_cpln.max_items); + d2h_max_ctrlcpl = prot->d2hring_ctrl_cpln.max_items = max_items; + +} + /** * dhd_prot_init - second stage of dhd_prot_attach. Now that the dongle has * completed it's initialization of the pcie_shared structure, we may now fetch @@ -3922,22 +4135,29 @@ dhd_prot_init(dhd_pub_t *dhd) * if user has not defined any buffers by one of the above methods. */ prot->h2d_max_txpost = (uint16)h2d_max_txpost; - DHD_ERROR(("%s:%d: h2d_max_txpost = %d\n", __FUNCTION__, __LINE__, prot->h2d_max_txpost)); + DHD_ERROR(("%s:%d: h2d_max_txpost = %d\n", __FUNCTION__, __LINE__, + prot->h2d_max_txpost)); -#if defined(DHD_HTPUT_TUNABLES) - prot->h2d_htput_max_txpost = (uint16)h2d_htput_max_txpost; - DHD_ERROR(("%s:%d: h2d_htput_max_txpost = %d\n", - __FUNCTION__, __LINE__, prot->h2d_htput_max_txpost)); -#endif /* DHD_HTPUT_TUNABLES */ + if (dhd->htput_support) { + prot->h2d_htput_max_txpost = (uint16)h2d_htput_max_txpost; + DHD_ERROR(("%s:%d: h2d_htput_max_txpost = %d\n", + __FUNCTION__, __LINE__, prot->h2d_htput_max_txpost)); + } /* Read max rx packets supported by dongle */ dhd_bus_cmn_readshared(dhd->bus, &prot->max_rxbufpost, MAX_HOST_RXBUFS, 0); if (prot->max_rxbufpost == 0) { /* This would happen if the dongle firmware is not */ /* using the latest shared structure template */ - prot->max_rxbufpost = DEFAULT_RX_BUFFERS_TO_POST; + prot->max_rxbufpost = LEGACY_MAX_RXBUFPOST; } - DHD_ERROR(("%s:%d: MAX_RXBUFPOST = %d\n", __FUNCTION__, __LINE__, prot->max_rxbufpost)); + prot->rx_buf_burst = (uint16)rx_buf_burst; + prot->rx_bufpost_threshold = (uint16)rx_bufpost_threshold; + DHD_ERROR(("%s: max_rxbufpost:%d rx_buf_burst:%d rx_bufpost_threshold:%d\n", + __FUNCTION__, prot->max_rxbufpost, prot->rx_buf_burst, prot->rx_bufpost_threshold)); + + /* Update static rings sizes if overridden by iovar */ + dhd_prot_update_rings_size(prot); /* Initialize. bzero() would blow away the dma pointers. */ max_eventbufpost = (uint16)dhdpcie_get_max_eventbufpost(dhd->bus); @@ -3945,9 +4165,6 @@ dhd_prot_init(dhd_pub_t *dhd) H2DRING_CTRL_SUB_MAX_ITEM) ? DHD_FLOWRING_MAX_EVENTBUF_POST : max_eventbufpost; prot->max_ioctlrespbufpost = DHD_FLOWRING_MAX_IOCTLRESPBUF_POST; prot->max_infobufpost = DHD_H2D_INFORING_MAX_BUF_POST; -#ifdef BTLOG - prot->max_btlogbufpost = DHD_H2D_BTLOGRING_MAX_BUF_POST; -#endif /* BTLOG */ prot->max_tsbufpost = DHD_MAX_TSBUF_POST; prot->cur_ioctlresp_bufs_posted = 0; @@ -3962,9 +4179,6 @@ dhd_prot_init(dhd_pub_t *dhd) prot->curr_ioctl_cmd = 0; prot->cur_ts_bufs_posted = 0; prot->infobufpost = 0; -#ifdef BTLOG - prot->btlogbufpost = 0; -#endif /* BTLOG */ prot->dmaxfer.srcmem.va = NULL; prot->dmaxfer.dstmem.va = NULL; @@ -3984,6 +4198,9 @@ dhd_prot_init(dhd_pub_t *dhd) prot->ioctl_status = 0; prot->ioctl_resplen = 0; prot->ioctl_received = IOCTL_WAIT; + prot->rx_wakeup_pkt = 0; + prot->event_wakeup_pkt = 0; + prot->info_wakeup_pkt = 0; /* Initialize Common MsgBuf Rings */ @@ -3991,9 +4208,23 @@ dhd_prot_init(dhd_pub_t *dhd) prot->host_ipc_version = PCIE_SHARED_VERSION; prot->no_tx_resource = FALSE; + prot->rx_cpl_post_bound = + (dhd_rx_cpl_post_bound) ? dhd_rx_cpl_post_bound : DHD_RX_CPL_POST_BOUND; + prot->tx_post_bound = + (dhd_tx_post_bound) ? dhd_tx_post_bound : DHD_TX_POST_BOUND; + prot->tx_cpl_bound = + (dhd_tx_cpl_bound) ? dhd_tx_cpl_bound : DHD_TX_CPL_BOUND; + prot->ctrl_cpl_post_bound = + (dhd_ctrl_cpl_post_bound) ? dhd_ctrl_cpl_post_bound : DHD_CTRL_CPL_POST_BOUND; + /* Init the host API version */ dhd_set_host_cap(dhd); +#ifdef DHD_PCIE_PTM + /* Set host capability 2 flags; for PCIE PTM */ + dhd_set_host_cap2(dhd); +#endif /* DHD_PCIE_PTM */ + /* alloc and configure scb host address for dongle */ if ((ret = dhd_alloc_host_scbs(dhd))) { return ret; @@ -4080,8 +4311,8 @@ dhd_prot_init(dhd_pub_t *dhd) */ /* Pre-allocate pool of msgbuf_ring for flowrings */ - if (dhd_prot_flowrings_pool_attach(dhd) != BCME_OK) { - return BCME_ERROR; + if ((ret = dhd_prot_flowrings_pool_attach(dhd))) { + return ret; } dhd->ring_attached = TRUE; @@ -4110,7 +4341,8 @@ dhd_prot_init(dhd_pub_t *dhd) while (!(idmacontrol & PCIE_IDMA_MODE_EN(buscorerev)) && (waitcount++ < IDMA_ENABLE_WAIT)) { - DHD_ERROR(("iDMA not enabled yet,waiting 1 ms c=%d IDMAControl = %08x\n", + DHD_ERROR(("iDMA not enabled yet,waiting 1 ms " + "c=%d IDMAControl = %08x\n", waitcount, idmacontrol)); OSL_DELAY(1000); /* 1ms as its onetime only */ idmacontrol = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, @@ -4180,31 +4412,16 @@ dhd_prot_init(dhd_pub_t *dhd) } #endif /* EWP_EDL */ -#ifdef BTLOG - /* create BT log rings */ - if (dhd->bus->api.fw_rev >= PCIE_SHARED_VERSION_7 && dhd->bt_logging) { - if ((ret = dhd_prot_init_btlog_rings(dhd)) != BCME_OK) { + /* create MD cpl rings */ + if (dhd->bus->api.fw_rev >= PCIE_SHARED_VERSION_7 && dhd->mdring_capable) { + if ((ret = dhd_prot_init_md_rings(dhd)) != BCME_OK) { /* For now log and proceed, further clean up action maybe necessary * when we have more clarity. */ - DHD_ERROR(("%s Info rings couldn't be created: Err Code%d", + DHD_ERROR(("%s MD rings couldn't be created: Err Code%d", __FUNCTION__, ret)); } } -#endif /* BTLOG */ - -#ifdef DHD_HP2P - /* create HPP txcmpl/rxcmpl rings */ - if (dhd->bus->api.fw_rev >= PCIE_SHARED_VERSION_7 && dhd->hp2p_capable) { - if ((ret = dhd_prot_init_hp2p_rings(dhd)) != BCME_OK) { - /* For now log and proceed, further clean up action maybe necessary - * when we have more clarity. - */ - DHD_ERROR(("%s HP2P rings couldn't be created: Err Code%d", - __FUNCTION__, ret)); - } - } -#endif /* DHD_HP2P */ #ifdef DHD_LB_RXP /* defualt rx flow ctrl thresholds. Can be changed at run time through sysfs */ @@ -4221,6 +4438,9 @@ dhd_prot_init(dhd_pub_t *dhd) */ void dhd_prot_detach(dhd_pub_t *dhd) { +#ifdef FLOW_RING_PREALLOC + int i = 0; +#endif /* FLOW_RING_PREALLOC */ dhd_prot_t *prot = dhd->prot; /* Stop the protocol module */ @@ -4242,9 +4462,6 @@ void dhd_prot_detach(dhd_pub_t *dhd) dhd_dma_buf_free(dhd, &prot->hostts_req_buf); dhd_dma_buf_free(dhd, &prot->fw_trap_buf); dhd_dma_buf_free(dhd, &prot->host_scb_buf); -#ifdef SNAPSHOT_UPLOAD - dhd_dma_buf_free(dhd, &prot->snapshot_upload_buf); -#endif /* SNAPSHOT_UPLOAD */ /* DMA-able buffers for DMAing H2D/D2H WR/RD indices */ dhd_dma_buf_free(dhd, &prot->h2d_dma_indx_wr_buf); @@ -4264,21 +4481,25 @@ void dhd_prot_detach(dhd_pub_t *dhd) /* Detach each DMA-able buffer and free the pool of msgbuf_ring_t */ dhd_prot_flowrings_pool_detach(dhd); +#ifdef FLOW_RING_PREALLOC + if (dhd->htput_support) { + for (i = 0; i < HTPUT_TOTAL_FLOW_RINGS; i++) { + dhd_dma_buf_free(dhd, &prot->htput_ring_buf[i]); + } + } + + for (i = 0; i < dhd->non_htput_total_flow_rings; i++) { + dhd_dma_buf_free(dhd, &prot->flow_ring_buf[i]); + } +#endif /* FLOW_RING_PREALLOC */ + /* detach info rings */ dhd_prot_detach_info_rings(dhd); -#ifdef BTLOG - /* detach BT log rings */ - dhd_prot_detach_btlog_rings(dhd); -#endif /* BTLOG */ - #ifdef EWP_EDL dhd_prot_detach_edl_rings(dhd); #endif -#ifdef DHD_HP2P - /* detach HPP rings */ - dhd_prot_detach_hp2p_rings(dhd); -#endif /* DHD_HP2P */ + dhd_prot_detach_md_rings(dhd); /* if IOCTLRESP_USE_CONSTMEM is defined IOCTL PKTs use pktid_map_handle_ioctl * handler and PKT memory is allocated using alloc_ioctl_return_buffer(), Otherwise @@ -4326,6 +4547,9 @@ void dhd_prot_detach(dhd_pub_t *dhd) void dhd_prot_reset(dhd_pub_t *dhd) { +#ifdef FLOW_RING_PREALLOC + int i = 0; +#endif /* FLOW_RING_PREALLOC */ struct dhd_prot *prot = dhd->prot; DHD_TRACE(("%s\n", __FUNCTION__)); @@ -4371,9 +4595,6 @@ dhd_prot_reset(dhd_pub_t *dhd) dhd_dma_buf_reset(dhd, &prot->hostts_req_buf); dhd_dma_buf_reset(dhd, &prot->fw_trap_buf); dhd_dma_buf_reset(dhd, &prot->host_scb_buf); -#ifdef SNAPSHOT_UPLOAD - dhd_dma_buf_reset(dhd, &prot->snapshot_upload_buf); -#endif /* SNAPSHOT_UPLOAD */ dhd_dma_buf_reset(dhd, &prot->h2d_ifrm_indx_wr_buf); @@ -4383,6 +4604,18 @@ dhd_prot_reset(dhd_pub_t *dhd) dhd_dma_buf_reset(dhd, &prot->d2h_dma_indx_rd_buf); dhd_dma_buf_reset(dhd, &prot->d2h_dma_indx_wr_buf); +#ifdef FLOW_RING_PREALLOC + if (dhd->htput_support) { + for (i = 0; i < HTPUT_TOTAL_FLOW_RINGS; i++) { + dhd_dma_buf_reset(dhd, &prot->htput_ring_buf[i]); + } + } + + for (i = 0; i < dhd->non_htput_total_flow_rings; i++) { + dhd_dma_buf_reset(dhd, &prot->flow_ring_buf[i]); + } +#endif /* FLOW_RING_PREALLOC */ + #ifdef DHD_DMA_INDICES_SEQNUM if (prot->d2h_dma_indx_wr_copy_buf) { dhd_local_buf_reset(prot->h2d_dma_indx_rd_copy_buf, @@ -4418,25 +4651,10 @@ dhd_prot_reset(dhd_pub_t *dhd) dhd_flow_rings_deinit(dhd); } -#ifdef BTLOG - /* Reset BTlog rings */ - if (prot->h2dring_btlog_subn) { - dhd_prot_ring_reset(dhd, prot->h2dring_btlog_subn); + if (prot->d2hring_md_cpl) { + dhd_prot_ring_reset(dhd, prot->d2hring_md_cpl); } - if (prot->d2hring_btlog_cpln) { - dhd_prot_ring_reset(dhd, prot->d2hring_btlog_cpln); - } -#endif /* BTLOG */ -#ifdef DHD_HP2P - if (prot->d2hring_hp2p_txcpl) { - dhd_prot_ring_reset(dhd, prot->d2hring_hp2p_txcpl); - } - if (prot->d2hring_hp2p_rxcpl) { - dhd_prot_ring_reset(dhd, prot->d2hring_hp2p_rxcpl); - } -#endif /* DHD_HP2P */ - /* Reset PKTID map */ DHD_NATIVE_TO_PKTID_RESET(dhd, prot->pktid_ctrl_map); DHD_NATIVE_TO_PKTID_RESET(dhd, prot->pktid_rx_map); @@ -4473,6 +4691,8 @@ dhd_prot_reset(dhd_pub_t *dhd) extern void dhd_lb_rx_napi_dispatch(dhd_pub_t *dhdp); extern void dhd_lb_rx_pkt_enqueue(dhd_pub_t *dhdp, void *pkt, int ifidx); extern unsigned long dhd_read_lb_rxp(dhd_pub_t *dhdp); +extern void dhd_rx_emerge_enqueue(dhd_pub_t *dhdp, void *pkt); +extern void * dhd_rx_emerge_dequeue(dhd_pub_t *dhdp); #if defined(DHD_LB_RXP) /** @@ -4485,6 +4705,12 @@ dhd_lb_dispatch_rx_process(dhd_pub_t *dhdp) dhd_lb_rx_napi_dispatch(dhdp); /* dispatch rx_process_napi */ } #endif /* DHD_LB_RXP */ +#else +static INLINE void * +dhd_rx_emerge_dequeue(dhd_pub_t *dhdp) +{ + return NULL; +} #endif /* DHD_LB */ void @@ -4501,11 +4727,6 @@ dhd_check_create_info_rings(dhd_pub_t *dhd) int ret = BCME_ERROR; uint16 ringid; -#ifdef BTLOG - if (dhd->submit_count_WAR) { - ringid = dhd->bus->max_tx_flowrings + BCMPCIE_COMMON_MSGRINGS; - } else -#endif /* BTLOG */ { /* dongle may increase max_submission_rings so keep * ringid at end of dynamic rings @@ -4597,7 +4818,8 @@ dhd_prot_init_info_rings(dhd_pub_t *dhd) return ret; } - DHD_TRACE(("trying to send create d2h info ring: id %d\n", prot->d2hring_info_cpln->idx)); + DHD_ERROR(("trying to send create d2h info ring: id %d\n", + prot->d2hring_info_cpln->idx)); ret = dhd_send_d2h_ringcreate(dhd, prot->d2hring_info_cpln, BCMPCIE_D2H_RING_TYPE_DBGBUF_CPL, DHD_D2H_DBGRING_REQ_PKTID); if (ret != BCME_OK) @@ -4608,7 +4830,8 @@ dhd_prot_init_info_rings(dhd_pub_t *dhd) prot->d2hring_info_cpln->seqnum = D2H_EPOCH_INIT_VAL; prot->d2hring_info_cpln->current_phase = BCMPCIE_CMNHDR_PHASE_BIT_INIT; - DHD_TRACE(("trying to send create h2d info ring id %d\n", prot->h2dring_info_subn->idx)); + DHD_ERROR_MEM(("trying to send create h2d info ring id %d\n", + prot->h2dring_info_subn->idx)); prot->h2dring_info_subn->n_completion_ids = 1; prot->h2dring_info_subn->compeltion_ring_ids[0] = prot->d2hring_info_cpln->idx; @@ -4634,290 +4857,95 @@ dhd_prot_detach_info_rings(dhd_pub_t *dhd) } } -#ifdef DHD_HP2P static int -dhd_check_create_hp2p_rings(dhd_pub_t *dhd) +dhd_check_create_md_rings(dhd_pub_t *dhd) { dhd_prot_t *prot = dhd->prot; int ret = BCME_ERROR; uint16 ringid; - /* Last 2 dynamic ring indices are used by hp2p rings */ - ringid = dhd->bus->max_submission_rings + dhd->bus->max_completion_rings - 2; + /* Last dynamic ring indices are used by metadata rings */ + ringid = dhd->bus->max_submission_rings + dhd->bus->max_completion_rings - 1; - if (prot->d2hring_hp2p_txcpl == NULL) { - prot->d2hring_hp2p_txcpl = MALLOCZ(prot->osh, sizeof(msgbuf_ring_t)); + if (prot->d2hring_md_cpl == NULL) { + prot->d2hring_md_cpl = MALLOCZ(prot->osh, sizeof(msgbuf_ring_t)); - if (prot->d2hring_hp2p_txcpl == NULL) { - DHD_ERROR(("%s: couldn't alloc memory for d2hring_hp2p_txcpl\n", + if (prot->d2hring_md_cpl == NULL) { + DHD_ERROR(("%s: couldn't alloc memory for d2hring_md_cpl\n", __FUNCTION__)); return BCME_NOMEM; } - DHD_INFO(("%s: about to create hp2p txcpl ring\n", __FUNCTION__)); - ret = dhd_prot_ring_attach(dhd, prot->d2hring_hp2p_txcpl, "d2hhp2p_txcpl", - dhd_bus_get_hp2p_ring_max_size(dhd->bus, TRUE), D2HRING_TXCMPLT_ITEMSIZE, + DHD_INFO(("%s: about to create md cpl ring\n", __FUNCTION__)); + ret = dhd_prot_ring_attach(dhd, prot->d2hring_md_cpl, "d2hmd_cpl", + D2HRING_MDRING_MAX_ITEM, D2HRING_MDCMPLT_ITEMSIZE, ringid); if (ret != BCME_OK) { - DHD_ERROR(("%s: couldn't alloc resources for hp2p txcpl ring\n", + DHD_ERROR(("%s: couldn't alloc resources for md txcpl ring\n", + __FUNCTION__)); + goto err; + } + dhd->md_item_count = 0; + if ((dhd->mdring_info = MALLOCZ(prot->osh, + MAX_MDRING_ITEM_DUMP * D2HRING_MDCMPLT_ITEMSIZE)) == NULL) { + DHD_ERROR(("%s: couldn't alloc resources for md ring dump\n", __FUNCTION__)); - goto err2; } - } else { - /* for re-entry case, clear inited flag */ - prot->d2hring_hp2p_txcpl->inited = FALSE; } - if (prot->d2hring_hp2p_rxcpl == NULL) { - prot->d2hring_hp2p_rxcpl = MALLOCZ(prot->osh, sizeof(msgbuf_ring_t)); - - if (prot->d2hring_hp2p_rxcpl == NULL) { - DHD_ERROR(("%s: couldn't alloc memory for d2hring_hp2p_rxcpl\n", - __FUNCTION__)); - return BCME_NOMEM; - } - - /* create the hp2p rx completion ring next to hp2p tx compl ring - * ringid = id next to hp2p tx compl ring - */ - ringid = ringid + 1; - - DHD_INFO(("%s: about to create hp2p rxcpl ring\n", __FUNCTION__)); - ret = dhd_prot_ring_attach(dhd, prot->d2hring_hp2p_rxcpl, "d2hhp2p_rxcpl", - dhd_bus_get_hp2p_ring_max_size(dhd->bus, FALSE), D2HRING_RXCMPLT_ITEMSIZE, - ringid); - if (ret != BCME_OK) { - DHD_ERROR(("%s: couldn't alloc resources for hp2p rxcpl ring\n", - __FUNCTION__)); - goto err1; - } - } else { - /* for re-entry case, clear inited flag */ - prot->d2hring_hp2p_rxcpl->inited = FALSE; - } - - if (prot->d2hring_hp2p_rxcpl != NULL && - prot->d2hring_hp2p_txcpl != NULL) { + if (prot->d2hring_md_cpl != NULL) { /* dhd_prot_init rentry after a dhd_prot_reset */ ret = BCME_OK; } return ret; -err1: - MFREE(prot->osh, prot->d2hring_hp2p_rxcpl, sizeof(msgbuf_ring_t)); - prot->d2hring_hp2p_rxcpl = NULL; - -err2: - MFREE(prot->osh, prot->d2hring_hp2p_txcpl, sizeof(msgbuf_ring_t)); - prot->d2hring_hp2p_txcpl = NULL; +err: + MFREE(prot->osh, prot->d2hring_md_cpl, sizeof(msgbuf_ring_t)); + prot->d2hring_md_cpl = NULL; return ret; -} /* dhd_check_create_hp2p_rings */ +} /* dhd_check_create_md_rings */ int -dhd_prot_init_hp2p_rings(dhd_pub_t *dhd) +dhd_prot_init_md_rings(dhd_pub_t *dhd) { dhd_prot_t *prot = dhd->prot; int ret = BCME_OK; - dhd->hp2p_ring_more = TRUE; - /* default multiflow not allowed */ - dhd->hp2p_mf_enable = FALSE; - - if ((ret = dhd_check_create_hp2p_rings(dhd)) != BCME_OK) { - DHD_ERROR(("%s: hp2p rings aren't created! \n", + if ((ret = dhd_check_create_md_rings(dhd)) != BCME_OK) { + DHD_ERROR(("%s: md rings aren't created! \n", __FUNCTION__)); return ret; } - if ((prot->d2hring_hp2p_txcpl->inited) || (prot->d2hring_hp2p_txcpl->create_pending)) { - DHD_INFO(("hp2p tx completion ring was created!\n")); + if ((prot->d2hring_md_cpl->inited) || (prot->d2hring_md_cpl->create_pending)) { + DHD_INFO(("md completion ring was created!\n")); return ret; } - DHD_TRACE(("trying to send create d2h hp2p txcpl ring: id %d\n", - prot->d2hring_hp2p_txcpl->idx)); - ret = dhd_send_d2h_ringcreate(dhd, prot->d2hring_hp2p_txcpl, - BCMPCIE_D2H_RING_TYPE_HPP_TX_CPL, DHD_D2H_HPPRING_TXREQ_PKTID); + DHD_ERROR(("trying to send create d2h md cpl ring: id %d\n", + prot->d2hring_md_cpl->idx)); + ret = dhd_send_d2h_ringcreate(dhd, prot->d2hring_md_cpl, + BCMPCIE_D2H_RING_TYPE_MDATA_CPL, DHD_D2H_MDRING_REQ_PKTID); if (ret != BCME_OK) return ret; - prot->d2hring_hp2p_txcpl->seqnum = D2H_EPOCH_INIT_VAL; - prot->d2hring_hp2p_txcpl->current_phase = BCMPCIE_CMNHDR_PHASE_BIT_INIT; - - if ((prot->d2hring_hp2p_rxcpl->inited) || (prot->d2hring_hp2p_rxcpl->create_pending)) { - DHD_INFO(("hp2p rx completion ring was created!\n")); - return ret; - } - - DHD_TRACE(("trying to send create d2h hp2p rxcpl ring: id %d\n", - prot->d2hring_hp2p_rxcpl->idx)); - ret = dhd_send_d2h_ringcreate(dhd, prot->d2hring_hp2p_rxcpl, - BCMPCIE_D2H_RING_TYPE_HPP_RX_CPL, DHD_D2H_HPPRING_RXREQ_PKTID); - if (ret != BCME_OK) - return ret; - - prot->d2hring_hp2p_rxcpl->seqnum = D2H_EPOCH_INIT_VAL; - prot->d2hring_hp2p_rxcpl->current_phase = BCMPCIE_CMNHDR_PHASE_BIT_INIT; + prot->d2hring_md_cpl->seqnum = D2H_EPOCH_INIT_VAL; + prot->d2hring_md_cpl->current_phase = BCMPCIE_CMNHDR_PHASE_BIT_INIT; /* Note that there is no way to delete d2h or h2d ring deletion incase either fails, * so can not cleanup if one ring was created while the other failed */ return BCME_OK; -} /* dhd_prot_init_hp2p_rings */ +} /* dhd_prot_init_md_rings */ static void -dhd_prot_detach_hp2p_rings(dhd_pub_t *dhd) +dhd_prot_detach_md_rings(dhd_pub_t *dhd) { - if (dhd->prot->d2hring_hp2p_txcpl) { - dhd_prot_ring_detach(dhd, dhd->prot->d2hring_hp2p_txcpl); - MFREE(dhd->prot->osh, dhd->prot->d2hring_hp2p_txcpl, sizeof(msgbuf_ring_t)); - dhd->prot->d2hring_hp2p_txcpl = NULL; - } - if (dhd->prot->d2hring_hp2p_rxcpl) { - dhd_prot_ring_detach(dhd, dhd->prot->d2hring_hp2p_rxcpl); - MFREE(dhd->prot->osh, dhd->prot->d2hring_hp2p_rxcpl, sizeof(msgbuf_ring_t)); - dhd->prot->d2hring_hp2p_rxcpl = NULL; + if (dhd->prot->d2hring_md_cpl) { + dhd_prot_ring_detach(dhd, dhd->prot->d2hring_md_cpl); + MFREE(dhd->prot->osh, dhd->prot->d2hring_md_cpl, sizeof(msgbuf_ring_t)); + dhd->prot->d2hring_md_cpl = NULL; } } -#endif /* DHD_HP2P */ - -#ifdef BTLOG -static int -dhd_check_create_btlog_rings(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - int ret = BCME_ERROR; - uint16 ringid; - - if (dhd->submit_count_WAR) { - ringid = dhd->bus->max_tx_flowrings + BCMPCIE_COMMON_MSGRINGS + 2; - } else { - /* ringid is one less than ringids assign by dhd_check_create_info_rings */ - ringid = dhd->bus->max_tx_flowrings + - (dhd->bus->max_submission_rings - dhd->bus->max_tx_flowrings) + - BCMPCIE_H2D_COMMON_MSGRINGS - 1; - } - - if (prot->d2hring_btlog_cpln) { - /* for re-entry case, clear inited flag */ - prot->d2hring_btlog_cpln->inited = FALSE; - } - - if (prot->h2dring_btlog_subn && prot->d2hring_btlog_cpln) { - return BCME_OK; /* dhd_prot_init rentry after a dhd_prot_reset */ - } - - if (prot->h2dring_btlog_subn == NULL) { - prot->h2dring_btlog_subn = MALLOCZ(prot->osh, sizeof(msgbuf_ring_t)); - - if (prot->h2dring_btlog_subn == NULL) { - DHD_ERROR(("%s: couldn't alloc memory for h2dring_btlog_subn\n", - __FUNCTION__)); - return BCME_NOMEM; - } - - DHD_INFO(("%s: about to create debug submit ring\n", __FUNCTION__)); - ret = dhd_prot_ring_attach(dhd, prot->h2dring_btlog_subn, "h2dbtlog", - H2DRING_DYNAMIC_INFO_MAX_ITEM, H2DRING_INFO_BUFPOST_ITEMSIZE, - ringid); - if (ret != BCME_OK) { - DHD_ERROR(("%s: couldn't alloc resources for dbg submit ring\n", - __FUNCTION__)); - goto err; - } - } - - if (prot->d2hring_btlog_cpln == NULL) { - prot->d2hring_btlog_cpln = MALLOCZ(prot->osh, sizeof(msgbuf_ring_t)); - - if (prot->d2hring_btlog_cpln == NULL) { - DHD_ERROR(("%s: couldn't alloc memory for h2dring_btlog_subn\n", - __FUNCTION__)); - return BCME_NOMEM; - } - - if (dhd->submit_count_WAR) { - ringid = ringid + 1; - } else { - /* advance ringid past BTLOG submit ring and INFO submit and cmplt rings */ - ringid = ringid + 3; - } - - DHD_INFO(("%s: about to create debug cpl ring\n", __FUNCTION__)); - ret = dhd_prot_ring_attach(dhd, prot->d2hring_btlog_cpln, "d2hbtlog", - D2HRING_DYNAMIC_INFO_MAX_ITEM, D2HRING_INFO_BUFCMPLT_ITEMSIZE, - ringid); - if (ret != BCME_OK) { - DHD_ERROR(("%s: couldn't alloc resources for dbg cpl ring\n", - __FUNCTION__)); - dhd_prot_ring_detach(dhd, prot->h2dring_btlog_subn); - goto err; - } - } - - return ret; -err: - MFREE(prot->osh, prot->h2dring_btlog_subn, sizeof(msgbuf_ring_t)); - - if (prot->d2hring_btlog_cpln) { - MFREE(prot->osh, prot->d2hring_btlog_cpln, sizeof(msgbuf_ring_t)); - } - return ret; -} /* dhd_check_create_btlog_rings */ - -int -dhd_prot_init_btlog_rings(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - int ret = BCME_OK; - - if ((ret = dhd_check_create_btlog_rings(dhd)) != BCME_OK) { - DHD_ERROR(("%s: btlog rings aren't created! \n", - __FUNCTION__)); - return ret; - } - - if ((prot->d2hring_btlog_cpln->inited) || (prot->d2hring_btlog_cpln->create_pending)) { - DHD_INFO(("Info completion ring was created!\n")); - return ret; - } - - DHD_ERROR(("trying to send create d2h btlog ring: id %d\n", prot->d2hring_btlog_cpln->idx)); - ret = dhd_send_d2h_ringcreate(dhd, prot->d2hring_btlog_cpln, - BCMPCIE_D2H_RING_TYPE_BTLOG_CPL, DHD_D2H_BTLOGRING_REQ_PKTID); - if (ret != BCME_OK) - return ret; - - prot->h2dring_btlog_subn->seqnum = H2D_EPOCH_INIT_VAL; - prot->h2dring_btlog_subn->current_phase = 0; - prot->d2hring_btlog_cpln->seqnum = D2H_EPOCH_INIT_VAL; - prot->d2hring_btlog_cpln->current_phase = BCMPCIE_CMNHDR_PHASE_BIT_INIT; - - DHD_ERROR(("trying to send create h2d btlog ring id %d\n", prot->h2dring_btlog_subn->idx)); - prot->h2dring_btlog_subn->n_completion_ids = 1; - prot->h2dring_btlog_subn->compeltion_ring_ids[0] = prot->d2hring_btlog_cpln->idx; - - ret = dhd_send_h2d_ringcreate(dhd, prot->h2dring_btlog_subn, - BCMPCIE_H2D_RING_TYPE_BTLOG_SUBMIT, DHD_H2D_BTLOGRING_REQ_PKTID); - - /* Note that there is no way to delete d2h or h2d ring deletion incase either fails, - * so can not cleanup if one ring was created while the other failed - */ - return ret; -} /* dhd_prot_init_btlog_rings */ - -static void -dhd_prot_detach_btlog_rings(dhd_pub_t *dhd) -{ - if (dhd->prot->h2dring_btlog_subn) { - dhd_prot_ring_detach(dhd, dhd->prot->h2dring_btlog_subn); - MFREE(dhd->prot->osh, dhd->prot->h2dring_btlog_subn, sizeof(msgbuf_ring_t)); - } - if (dhd->prot->d2hring_btlog_cpln) { - dhd_prot_ring_detach(dhd, dhd->prot->d2hring_btlog_cpln); - MFREE(dhd->prot->osh, dhd->prot->d2hring_btlog_cpln, sizeof(msgbuf_ring_t)); - } -} -#endif /* BTLOG */ #ifdef EWP_EDL static int @@ -4927,11 +4955,6 @@ dhd_check_create_edl_rings(dhd_pub_t *dhd) int ret = BCME_ERROR; uint16 ringid; -#ifdef BTLOG - if (dhd->submit_count_WAR) { - ringid = dhd->bus->max_tx_flowrings + BCMPCIE_COMMON_MSGRINGS; - } else -#endif /* BTLOG */ { /* dongle may increase max_submission_rings so keep * ringid at end of dynamic rings (re-use info ring cpl ring id) @@ -4992,7 +5015,7 @@ dhd_prot_init_edl_rings(dhd_pub_t *dhd) return ret; } - DHD_ERROR(("trying to send create d2h edl ring: idx %d\n", prot->d2hring_edl->idx)); + DHD_ERROR_MEM(("trying to send create d2h edl ring: idx %d\n", prot->d2hring_edl->idx)); ret = dhd_send_d2h_ringcreate(dhd, prot->d2hring_edl, BCMPCIE_D2H_RING_TYPE_EDL, DHD_D2H_DBGRING_REQ_PKTID); if (ret != BCME_OK) @@ -5051,7 +5074,8 @@ int dhd_sync_with_dongle(dhd_pub_t *dhd) dhd->wlc_ver_minor = ((wl_wlc_version_t*)buf)->wlc_ver_minor; } - DHD_ERROR(("wlc_ver_major %d, wlc_ver_minor %d\n", dhd->wlc_ver_major, dhd->wlc_ver_minor)); + DHD_ERROR(("wlc_ver_major %d, wlc_ver_minor %d\n", + dhd->wlc_ver_major, dhd->wlc_ver_minor)); #ifndef OEM_ANDROID /* Get the device MAC address */ bzero(buf, sizeof(buf)); @@ -5061,7 +5085,7 @@ int dhd_sync_with_dongle(dhd_pub_t *dhd) DHD_ERROR(("%s: GET iovar cur_etheraddr FAILED\n", __FUNCTION__)); goto done; } - memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); + eacopy(&buf, &dhd->mac.octet); if (dhd_msg_level & DHD_INFO_VAL) { bcm_print_bytes("CUR_ETHERADDR ", (uchar *)buf, ETHER_ADDR_LEN); } @@ -5115,6 +5139,14 @@ int dhd_sync_with_dongle(dhd_pub_t *dhd) } } + prot->rxbufpost_alloc_sz = dhd_plat_align_rxbuf_size(prot->rxbufpost_sz); + DHD_ERROR(("%s: RxBuf Post Alloc : %d\n", __FUNCTION__, prot->rxbufpost_alloc_sz)); + +#ifdef RX_PKT_POOL + /* Rx pkt pool creation after rxbuf size is shared by dongle */ + dhd_rx_pktpool_create(dhd->info, prot->rxbufpost_alloc_sz); +#endif /* RX_PKT_POOL */ + /* Post buffers for packet reception */ dhd_msgbuf_rxbuf_post(dhd, FALSE); /* alloc pkt ids */ @@ -5127,21 +5159,8 @@ int dhd_sync_with_dongle(dhd_pub_t *dhd) dhd_sdtc_etb_init(dhd); #endif /* DHD_SDTC_ETB_DUMP */ #if defined(DHD_H2D_LOG_TIME_SYNC) -#ifdef DHD_HP2P - if (FW_SUPPORTED(dhd, h2dlogts) || dhd->hp2p_capable) -#else - if (FW_SUPPORTED(dhd, h2dlogts)) -#endif // endif - { -#ifdef DHD_HP2P - if (dhd->hp2p_enable) { - dhd->dhd_rte_time_sync_ms = DHD_H2D_LOG_TIME_STAMP_MATCH / 40; - } else { - dhd->dhd_rte_time_sync_ms = DHD_H2D_LOG_TIME_STAMP_MATCH; - } -#else + if (FW_SUPPORTED(dhd, h2dlogts)) { dhd->dhd_rte_time_sync_ms = DHD_H2D_LOG_TIME_STAMP_MATCH; -#endif /* DHD_HP2P */ dhd->bus->dhd_rte_time_sync_count = OSL_SYSUPTIME_US(); /* This is during initialization. */ dhd_h2d_log_time_sync(dhd); @@ -5150,14 +5169,6 @@ int dhd_sync_with_dongle(dhd_pub_t *dhd) } #endif /* DHD_H2D_LOG_TIME_SYNC */ -#ifdef HOST_SFH_LLC - if (FW_SUPPORTED(dhd, host_sfhllc)) { - dhd->host_sfhllc_supported = TRUE; - } else { - dhd->host_sfhllc_supported = FALSE; - } -#endif /* HOST_SFH_LLC */ - /* Always assumes wl for now */ dhd->iswl = TRUE; done: @@ -5173,6 +5184,7 @@ BCMFASTPATH(dhd_prot_print_metadata)(dhd_pub_t *dhd, void *ptr, int len) uint8 tlv_t; uint8 tlv_l; uint8 *tlv_v = (uint8 *)ptr; + int ret = 0; if (len <= BCMPCIE_D2H_METADATA_HDRLEN) return; @@ -5194,29 +5206,35 @@ BCMFASTPATH(dhd_prot_print_metadata)(dhd_pub_t *dhd, void *ptr, int len) switch (tlv_t) { case WLFC_CTL_TYPE_TXSTATUS: { uint32 txs; - memcpy(&txs, tlv_v, sizeof(uint32)); + (void)memcpy_s(&txs, sizeof(txs), tlv_v, sizeof(uint32)); if (tlv_l < (sizeof(wl_txstatus_additional_info_t) + sizeof(uint32))) { - printf("METADATA TX_STATUS: %08x\n", txs); + DHD_CONS_ONLY(("METADATA TX_STATUS: %08x\n", txs)); } else { wl_txstatus_additional_info_t tx_add_info; - memcpy(&tx_add_info, tlv_v + sizeof(uint32), - sizeof(wl_txstatus_additional_info_t)); - printf("METADATA TX_STATUS: %08x WLFCTS[%04x | %08x - %08x - %08x]" + ret = memcpy_s(&tx_add_info, sizeof(wl_txstatus_additional_info_t), + tlv_v + sizeof(uint32), tlv_l); + if (ret) { + DHD_ERROR(("tx status memcpy failed:%d, destsz:%lu, n:%d\n", + ret, sizeof(wl_txstatus_additional_info_t), tlv_l)); + break; + } + DHD_CONS_ONLY(("METADATA TX_STATUS: %08x" + " WLFCTS[%04x | %08x - %08x - %08x]" " rate = %08x tries = %d - %d\n", txs, tx_add_info.seq, tx_add_info.entry_ts, tx_add_info.enq_ts, tx_add_info.last_ts, tx_add_info.rspec, tx_add_info.rts_cnt, - tx_add_info.tx_cnt); + tx_add_info.tx_cnt)); } } break; case WLFC_CTL_TYPE_RSSI: { if (tlv_l == 1) - printf("METADATA RX_RSSI: rssi = %d\n", *tlv_v); + DHD_CONS_ONLY(("METADATA RX_RSSI: rssi = %d\n", *tlv_v)); else - printf("METADATA RX_RSSI[%04x]: rssi = %d snr = %d\n", + DHD_CONS_ONLY(("METADATA RX_RSSI[%04x]: rssi = %d snr = %d\n", (*(tlv_v + 3) << 8) | *(tlv_v + 2), - (int8)(*tlv_v), *(tlv_v + 1)); + (int8)(*tlv_v), *(tlv_v + 1))_; } break; case WLFC_CTL_TYPE_FIFO_CREDITBACK: @@ -5233,10 +5251,16 @@ BCMFASTPATH(dhd_prot_print_metadata)(dhd_pub_t *dhd, void *ptr, int len) uint32 bus_time; uint32 wlan_time; } rx_tmstamp; - memcpy(&rx_tmstamp, tlv_v, sizeof(rx_tmstamp)); - printf("METADATA RX TIMESTMAP: WLFCTS[%08x - %08x] rate = %08x\n", - rx_tmstamp.wlan_time, rx_tmstamp.bus_time, rx_tmstamp.rspec); - } break; + ret = memcpy_s(&rx_tmstamp, sizeof(rx_tmstamp), tlv_v, tlv_l); + if (ret) { + DHD_ERROR(("rx tmstamp memcpy failed:%d, destsz:%lu, n:%d\n", + ret, sizeof(rx_tmstamp), tlv_l)); + break; + } + DHD_CONS_ONLY(("METADATA RX TIMESTMAP: WLFCTS[%08x - %08x] rate = %08x\n", + rx_tmstamp.wlan_time, rx_tmstamp.bus_time, rx_tmstamp.rspec)); + } + break; case WLFC_CTL_TYPE_TRANS_ID: bcm_print_bytes("METADATA TRANS_ID", tlv_v, tlv_l); @@ -5265,11 +5289,7 @@ BCMFASTPATH(dhd_prot_packet_free)(dhd_pub_t *dhd, void *pkt, uint8 pkttype, bool pkttype == PKTTYPE_EVENT_RX || pkttype == PKTTYPE_INFO_RX || pkttype == PKTTYPE_TSBUF_RX) { -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhd->osh, pkt, send); -#else - PKTFREE(dhd->osh, pkt, send); -#endif /* DHD_USE_STATIC_CTRLBUF */ + PKTFREE_CTRLBUF(dhd->osh, pkt, send); } else { PKTFREE(dhd->osh, pkt, send); } @@ -5386,9 +5406,9 @@ BCMFASTPATH(dhd_msgbuf_rxbuf_post)(dhd_pub_t *dhd, bool use_rsv_pktid) int retcount = 0; fillbufs = prot->max_rxbufpost - prot->rxbufpost; - while (fillbufs >= RX_BUF_BURST) { + while (fillbufs >= prot->rx_buf_burst) { /* Post in a burst of 32 buffers at a time */ - fillbufs = MIN(fillbufs, RX_BUF_BURST); + fillbufs = MIN(fillbufs, prot->rx_buf_burst); /* Post buffers */ retcount = dhd_prot_rxbuf_post(dhd, fillbufs, use_rsv_pktid); @@ -5421,10 +5441,10 @@ BCMFASTPATH(dhd_prot_rxbuf_post)(dhd_pub_t *dhd, uint16 count, bool use_rsv_pkti msgbuf_ring_t *ring = &prot->h2dring_rxp_subn; void *lcl_buf; uint16 lcl_buf_size; + #ifdef BCM_ROUTER_DHD - uint16 pktsz = DHD_FLOWRING_RX_BUFPOST_PKTSZ + BCMEXTRAHDROOM; -#else - uint16 pktsz = prot->rxbufpost_sz; + prot->rxbufpost_sz = DHD_FLOWRING_RX_BUFPOST_PKTSZ + BCMEXTRAHDROOM; + prot->rxbufpost_alloc_sz = prot->rxbufpost_sz; #endif /* BCM_ROUTER_DHD */ #ifdef PCIE_INB_DW @@ -5433,7 +5453,7 @@ BCMFASTPATH(dhd_prot_rxbuf_post)(dhd_pub_t *dhd, uint16 count, bool use_rsv_pkti #endif /* PCIE_INB_DW */ /* allocate a local buffer to store pkt buffer va, pa and length */ lcl_buf_size = (sizeof(void *) + sizeof(dmaaddr_t) + sizeof(uint32)) * - RX_BUF_BURST; + prot->rx_buf_burst; lcl_buf = MALLOC(dhd->osh, lcl_buf_size); if (!lcl_buf) { DHD_ERROR(("%s: local scratch buffer allocation failed\n", __FUNCTION__)); @@ -5443,14 +5463,46 @@ BCMFASTPATH(dhd_prot_rxbuf_post)(dhd_pub_t *dhd, uint16 count, bool use_rsv_pkti return 0; } pktbuf = lcl_buf; - pktbuf_pa = (dmaaddr_t *)((uint8 *)pktbuf + sizeof(void *) * RX_BUF_BURST); - pktlen = (uint32 *)((uint8 *)pktbuf_pa + sizeof(dmaaddr_t) * RX_BUF_BURST); + pktbuf_pa = (dmaaddr_t *)((uint8 *)pktbuf + sizeof(void *) * prot->rx_buf_burst); + pktlen = (uint32 *)((uint8 *)pktbuf_pa + sizeof(dmaaddr_t) * prot->rx_buf_burst); for (i = 0; i < count; i++) { - if ((p = PKTGET(dhd->osh, pktsz, FALSE)) == NULL) { - DHD_ERROR(("%s:%d: PKTGET for rxbuf failed\n", __FUNCTION__, __LINE__)); + /* First try to dequeue from emergency queue which will be filled + * during rx flow control. + */ + p = dhd_rx_emerge_dequeue(dhd); + if ((p == NULL) && + ((p = PKTGET(dhd->osh, prot->rxbufpost_alloc_sz, FALSE)) == NULL)) { dhd->rx_pktgetfail++; - break; + DHD_ERROR_RLMT(("%s:%d: PKTGET for rxbuf failed, rx_pktget_fail :%lu\n", + __FUNCTION__, __LINE__, dhd->rx_pktgetfail)); + /* Try to get pkt from Rx reserve pool if monitor mode is not enabled as + * the buffer size for monitor mode is larger(4k) than normal rx pkt(1920) + */ +#if defined(WL_MONITOR) + if (dhd_monitor_enabled(dhd, 0)) { + break; + } else +#endif /* WL_MONITOR */ + { +#ifdef RX_PKT_POOL + if ((p = PKTGET_RX_POOL(dhd->osh, dhd->info, + prot->rxbufpost_alloc_sz, FALSE)) == NULL) { + dhd->rx_pktgetpool_fail++; + DHD_ERROR_RLMT(("%s:%d: PKTGET_RX_POOL for rxbuf failed, " + "rx_pktgetpool_fail : %lu\n", + __FUNCTION__, __LINE__, dhd->rx_pktgetpool_fail)); + break; + } +#endif /* RX_PKT_POOL */ + } + } + + /* Set pktlen to the actual bufferpost size */ + if (prot->rxbufpost_sz != prot->rxbufpost_alloc_sz) { + DHD_TRACE(("%s: pktlen before: %d\n", __FUNCTION__, PKTLEN(dhd->osh, p))); + PKTSETLEN(dhd->osh, p, prot->rxbufpost_sz); + DHD_TRACE(("%s: pktlen after: %d\n", __FUNCTION__, PKTLEN(dhd->osh, p))); } #ifdef BCM_ROUTER_DHD @@ -5641,15 +5693,6 @@ dhd_prot_infobufpost(dhd_pub_t *dhd, msgbuf_ring_t *ring) count = prot->max_infobufpost - prot->infobufpost; } -#ifdef BTLOG - else if (ring == dhd->prot->h2dring_btlog_subn) { - if (prot->max_btlogbufpost == 0) - return 0; - - pktsz = DHD_BTLOG_RX_BUFPOST_PKTSZ; - count = prot->max_btlogbufpost - prot->btlogbufpost; - } -#endif /* BTLOG */ else { DHD_ERROR(("Unknown ring\n")); return 0; @@ -5704,11 +5747,7 @@ dhd_prot_infobufpost(dhd_pub_t *dhd, msgbuf_ring_t *ring) pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0); if (PHYSADDRISZERO(pa)) { DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL); -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhd->osh, p, FALSE); -#else - PKTFREE(dhd->osh, p, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ + PKTFREE_CTRLBUF(dhd->osh, p, FALSE); DHD_ERROR(("Invalid phyaddr 0\n")); ASSERT(0); break; @@ -5732,12 +5771,7 @@ dhd_prot_infobufpost(dhd_pub_t *dhd, msgbuf_ring_t *ring) #if defined(DHD_PCIE_PKTID) if (pktid == DHD_PKTID_INVALID) { DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, 0); - -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhd->osh, p, FALSE); -#else - PKTFREE(dhd->osh, p, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ + PKTFREE_CTRLBUF(dhd->osh, p, FALSE); DHD_ERROR_RLMT(("%s: Pktid pool depleted.\n", __FUNCTION__)); break; } @@ -5751,7 +5785,7 @@ dhd_prot_infobufpost(dhd_pub_t *dhd, msgbuf_ring_t *ring) DHD_PKTID_AUDIT(dhd, prot->pktid_ctrl_map, pktid, DHD_DUPLICATE_ALLOC); #endif /* DHD_PKTID_AUDIT_RING */ - DHD_MSGBUF_INFO(("ID %d, low_addr 0x%08x, high_addr 0x%08x\n", + DHD_INFO(("ID %d, low_addr 0x%08x, high_addr 0x%08x\n", infobuf_post->cmn_hdr.request_id, infobuf_post->host_buf_addr.low_addr, infobuf_post->host_buf_addr.high_addr)); @@ -5782,11 +5816,6 @@ dhd_prot_infobufpost(dhd_pub_t *dhd, msgbuf_ring_t *ring) if (ring == dhd->prot->h2dring_info_subn) { prot->infobufpost += alloced; } -#ifdef BTLOG - if (ring == dhd->prot->h2dring_btlog_subn) { - prot->btlogbufpost += alloced; - } -#endif /* BTLOG */ dhd_prot_ring_write_complete(dhd, ring, msg_start, alloced); } @@ -6074,7 +6103,7 @@ dhd_msgbuf_rxbuf_post_ctrlpath(dhd_pub_t *dhd, uint8 msg_type, uint32 max_to_pos uint32 i = 0; int32 ret_val; - DHD_MSGBUF_INFO(("max to post %d, event %d \n", max_to_post, msg_type)); + DHD_INFO(("max to post %d, event %d \n", max_to_post, msg_type)); if (dhd->busstate == DHD_BUS_DOWN) { DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); @@ -6087,7 +6116,7 @@ dhd_msgbuf_rxbuf_post_ctrlpath(dhd_pub_t *dhd, uint8 msg_type, uint32 max_to_pos break; i++; } - DHD_MSGBUF_INFO(("posted %d buffers of type %d\n", i, msg_type)); + DHD_INFO(("posted %d buffers of type %d\n", i, msg_type)); return (uint16)i; } @@ -6097,7 +6126,7 @@ dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd_pub_t *dhd) dhd_prot_t *prot = dhd->prot; int max_to_post; - DHD_MSGBUF_INFO(("ioctl resp buf post\n")); + DHD_INFO(("ioctl resp buf post\n")); max_to_post = prot->max_ioctlrespbufpost - prot->cur_ioctlresp_bufs_posted; if (max_to_post <= 0) { DHD_INFO(("%s: Cannot post more than max IOCTL resp buffers\n", @@ -6127,31 +6156,12 @@ dhd_msgbuf_rxbuf_post_event_bufs(dhd_pub_t *dhd) static int dhd_msgbuf_rxbuf_post_ts_bufs(dhd_pub_t *dhd) { -#ifdef DHD_TIMESYNC - dhd_prot_t *prot = dhd->prot; - int max_to_post; - - if (prot->active_ipc_version < 7) { - DHD_ERROR(("no ts buffers to device ipc rev is %d, needs to be atleast 7\n", - prot->active_ipc_version)); - return 0; - } - - max_to_post = prot->max_tsbufpost - prot->cur_ts_bufs_posted; - if (max_to_post <= 0) { - DHD_INFO(("%s: Cannot post more than max ts buffers\n", - __FUNCTION__)); - return 0; - } - - prot->cur_ts_bufs_posted += dhd_msgbuf_rxbuf_post_ctrlpath(dhd, - MSG_TYPE_TIMSTAMP_BUFPOST, max_to_post); -#endif /* DHD_TIMESYNC */ return 0; } bool -BCMFASTPATH(dhd_prot_process_msgbuf_infocpl)(dhd_pub_t *dhd, uint bound) +BCMFASTPATH(dhd_prot_process_msgbuf_infocpl)(dhd_pub_t *dhd, uint bound, + uint32 *info_items) { dhd_prot_t *prot = dhd->prot; bool more = TRUE; @@ -6181,74 +6191,22 @@ BCMFASTPATH(dhd_prot_process_msgbuf_infocpl)(dhd_pub_t *dhd, uint bound) DHD_RING_LOCK(ring->ring_lock, flags); /* Get the message from ring */ - msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len); + /* must pass 'bound - n' rather than just 'bound', because + * within this loop, dhd_prot_get_read_addr is called multiple + * times, so if just 'bound' is passed we may end up reading + * more than 'bound' items, ex:- for a bound of 2048, + * during the first iteration let us say n = 2000, so the loop + * continues and for the second iteration n = 1000 items may be read, + * so the total items read will be 3000 which is > 2048 + */ + msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len, bound - n); DHD_RING_UNLOCK(ring->ring_lock, flags); if (msg_addr == NULL) { more = FALSE; break; } - /* Prefetch data to populate the cache */ - OSL_PREFETCH(msg_addr); - - if (dhd_prot_process_msgtype(dhd, ring, msg_addr, msg_len) != BCME_OK) { - DHD_ERROR(("%s: Error at process rxpl msgbuf of len %d\n", - __FUNCTION__, msg_len)); - } - - /* Update read pointer */ - dhd_prot_upd_read_idx(dhd, ring); - - /* After batch processing, check RX bound */ - n += msg_len / ring->item_len; - if (n >= bound) { - break; - } - } - - return more; -} - -#ifdef BTLOG -bool -BCMFASTPATH(dhd_prot_process_msgbuf_btlogcpl)(dhd_pub_t *dhd, uint bound) -{ - dhd_prot_t *prot = dhd->prot; - bool more = TRUE; - uint n = 0; - msgbuf_ring_t *ring = prot->d2hring_btlog_cpln; - - if (ring == NULL) - return FALSE; - if (ring->inited != TRUE) - return FALSE; - - /* Process all the messages - DTOH direction */ - while (!dhd_is_device_removed(dhd)) { - uint8 *msg_addr; - uint32 msg_len; - - if (dhd_query_bus_erros(dhd)) { - more = FALSE; - break; - } - - if (dhd->hang_was_sent) { - more = FALSE; - break; - } - - if (dhd->smmu_fault_occurred) { - more = FALSE; - break; - } - - /* Get the message from ring */ - msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len); - if (msg_addr == NULL) { - more = FALSE; - break; - } + *info_items = msg_len / ring->item_len; /* Prefetch data to populate the cache */ OSL_PREFETCH(msg_addr); @@ -6270,11 +6228,10 @@ BCMFASTPATH(dhd_prot_process_msgbuf_btlogcpl)(dhd_pub_t *dhd, uint bound) return more; } -#endif /* BTLOG */ #ifdef EWP_EDL bool -dhd_prot_process_msgbuf_edl(dhd_pub_t *dhd) +dhd_prot_process_msgbuf_edl(dhd_pub_t *dhd, uint32 *evtlog_items) { dhd_prot_t *prot = dhd->prot; msgbuf_ring_t *ring = prot->d2hring_edl; @@ -6320,6 +6277,7 @@ dhd_prot_process_msgbuf_edl(dhd_pub_t *dhd) depth = ring->max_items; /* check for avail space, in number of ring items */ items = READ_AVAIL_SPACE(ring->wr, rd, depth); + *evtlog_items = items; if (items == 0) { /* no work items in edl ring */ return FALSE; @@ -6333,11 +6291,6 @@ dhd_prot_process_msgbuf_edl(dhd_pub_t *dhd) DHD_ERROR(("dhd->busstate %d bus->wait_for_d3_ack %d \r\n", dhd->busstate, dhd->bus->wait_for_d3_ack)); DHD_ERROR(("\r\n======================= \r\n")); -#ifdef SUPPORT_LINKDOWN_RECOVERY - if (ring->wr >= ring->max_items) { - dhd->bus->read_shm_fail = TRUE; - } -#else #ifdef DHD_FW_COREDUMP if (dhd->memdump_enabled) { /* collect core dump */ @@ -6346,7 +6299,6 @@ dhd_prot_process_msgbuf_edl(dhd_pub_t *dhd) } #endif /* DHD_FW_COREDUMP */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ dhd_schedule_reset(dhd); return FALSE; @@ -6545,10 +6497,6 @@ dhd_prot_edl_ring_tcm_rd_update(dhd_pub_t *dhd) DHD_RING_LOCK(ring->ring_lock, flags); dhd_prot_upd_read_idx(dhd, ring); DHD_RING_UNLOCK(ring->ring_lock, flags); - if (dhd->dma_h2d_ring_upd_support && - !IDMA_ACTIVE(dhd)) { - dhd_prot_ring_doorbell(dhd, DHD_RDPTR_UPDATE_H2D_DB_MAGIC(ring)); - } } #endif /* EWP_EDL */ @@ -6570,6 +6518,7 @@ static int dhd_prot_lb_rxp_flow_ctrl(dhd_pub_t *dhd) { if ((dhd->lb_rxp_stop_thr == 0) || (dhd->lb_rxp_strt_thr == 0)) { /* when either of stop and start thresholds are zero flow ctrl is not enabled */ + atomic_set(&dhd->lb_rxp_flow_ctrl, FALSE); return FALSE; } @@ -6597,7 +6546,7 @@ static int dhd_prot_lb_rxp_flow_ctrl(dhd_pub_t *dhd) /** called when DHD needs to check for 'receive complete' messages from the dongle */ bool -BCMFASTPATH(dhd_prot_process_msgbuf_rxcpl)(dhd_pub_t *dhd, uint bound, int ringtype) +BCMFASTPATH(dhd_prot_process_msgbuf_rxcpl)(dhd_pub_t *dhd, int ringtype, uint32 *rxcpl_items) { bool more = FALSE; uint n = 0; @@ -6618,30 +6567,13 @@ BCMFASTPATH(dhd_prot_process_msgbuf_rxcpl)(dhd_pub_t *dhd, uint bound, int ringt uint32 pktid; int i; uint8 sync; + unsigned long rx_lock_flags = 0; #ifdef DHD_LB_RXP /* must be the first check in this function */ - if (dhd_prot_lb_rxp_flow_ctrl(dhd)) { - /* DHD is holding a lot of RX packets. - * Just give chance for netwrok stack to consumes RX packets. - */ - return FALSE; - } + (void)dhd_prot_lb_rxp_flow_ctrl(dhd); #endif /* DHD_LB_RXP */ -#ifdef DHD_PCIE_RUNTIMEPM - /* Set rx_pending_due_to_rpm if device is not in resume state */ - if (dhdpcie_runtime_bus_wake(dhd, FALSE, dhd_prot_process_msgbuf_rxcpl)) { - dhd->rx_pending_due_to_rpm = TRUE; - return more; - } - dhd->rx_pending_due_to_rpm = FALSE; -#endif /* DHD_PCIE_RUNTIMEPM */ -#ifdef DHD_HP2P - if (ringtype == DHD_HP2P_RING && prot->d2hring_hp2p_rxcpl) - ring = prot->d2hring_hp2p_rxcpl; - else -#endif /* DHD_HP2P */ ring = &prot->d2hring_rx_cpln; item_len = ring->item_len; while (1) { @@ -6665,12 +6597,23 @@ BCMFASTPATH(dhd_prot_process_msgbuf_rxcpl)(dhd_pub_t *dhd, uint bound, int ringt DHD_RING_LOCK(ring->ring_lock, flags); /* Get the address of the next message to be read from ring */ - msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len); + /* must pass 'bound - n' rather than just 'bound', because + * within this loop, dhd_prot_get_read_addr is called multiple + * times, so if just 'bound' is passed we may end up reading + * more than 'bound' items, ex:- for a bound of 2048, + * during the first iteration let us say n = 2000, so the loop + * continues and for the second iteration n = 1000 items may be read, + * so the total items read will be 3000 which is > 2048 + */ + msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len, + prot->rx_cpl_post_bound - n); if (msg_addr == NULL) { DHD_RING_UNLOCK(ring->ring_lock, flags); break; } + *rxcpl_items = msg_len / ring->item_len; + while (msg_len > 0) { msg = (host_rxbuf_cmpl_t *)msg_addr; @@ -6695,10 +6638,18 @@ BCMFASTPATH(dhd_prot_process_msgbuf_rxcpl)(dhd_pub_t *dhd, uint bound, int ringt } pktid = ltoh32(msg->cmn_hdr.request_id); + if (msg->cmn_hdr.flags & BCMPCIE_CMNHDR_FLAGS_WAKE_PACKET) { + DHD_ERROR(("%s:Rx: Wakeup Packet received\n", __FUNCTION__)); + prot->rx_wakeup_pkt ++; + } #ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_rx_map, pktid, - DHD_DUPLICATE_FREE, msg, D2HRING_RXCMPLT_ITEMSIZE); + if (DHD_PKTID_AUDIT_RING_DEBUG(dhd, prot->pktid_rx_map, pktid, + DHD_DUPLICATE_FREE, msg, D2HRING_RXCMPLT_ITEMSIZE) != BCME_OK) { + msg_len -= item_len; + msg_addr += item_len; + continue; + } #endif /* DHD_PKTID_AUDIT_RING */ pkt = DHD_PKTID_TO_NATIVE(dhd, prot->pktid_rx_map, pktid, pa, @@ -6709,7 +6660,7 @@ BCMFASTPATH(dhd_prot_process_msgbuf_rxcpl)(dhd_pub_t *dhd, uint bound, int ringt msg_addr += item_len; continue; } - dhd->prot->tot_rxcpl++; + prot->tot_rxcpl++; DMA_UNMAP(dhd->osh, pa, (uint) len, DMA_RX, 0, dmah); @@ -6718,32 +6669,32 @@ BCMFASTPATH(dhd_prot_process_msgbuf_rxcpl)(dhd_pub_t *dhd, uint bound, int ringt dhd->dma_stats.rxdata_sz -= len; #endif /* DMAMAP_STATS */ #ifdef DHD_HMAPTEST - if ((dhd->prot->hmaptest_rx_active == HMAPTEST_D11_RX_POSTED) && - (pktid == dhd->prot->hmaptest_rx_pktid)) { + if ((prot->hmaptest_rx_active == HMAPTEST_D11_RX_POSTED) && + (pktid == prot->hmaptest_rx_pktid)) { uchar *ptr; ptr = PKTDATA(dhd->osh, pkt) - (prot->rx_metadata_offset); - DMA_UNMAP(dhd->osh, dhd->prot->hmap_rx_buf_pa, - (uint)dhd->prot->hmap_rx_buf_len, DMA_RX, 0, dmah); + DMA_UNMAP(dhd->osh, prot->hmap_rx_buf_pa, + (uint)prot->hmap_rx_buf_len, DMA_RX, 0, dmah); DHD_ERROR(("hmaptest: d11write rxcpl rcvd sc rxbuf pktid=0x%08x\n", pktid)); DHD_ERROR(("hmaptest: d11write rxcpl r0_st=0x%08x r1_stat=0x%08x\n", msg->rx_status_0, msg->rx_status_1)); DHD_ERROR(("hmaptest: d11write rxcpl rxbuf va=0x%p pa=0x%08x\n", - dhd->prot->hmap_rx_buf_va, - (uint32)PHYSADDRLO(dhd->prot->hmap_rx_buf_pa))); + prot->hmap_rx_buf_va, + (uint32)PHYSADDRLO(prot->hmap_rx_buf_pa))); DHD_ERROR(("hmaptest: d11write rxcpl pktdata va=0x%p pa=0x%08x\n", PKTDATA(dhd->osh, pkt), (uint32)PHYSADDRLO(pa))); - memcpy(ptr, dhd->prot->hmap_rx_buf_va, dhd->prot->hmap_rx_buf_len); - dhd->prot->hmaptest_rx_active = HMAPTEST_D11_RX_INACTIVE; - dhd->prot->hmap_rx_buf_va = NULL; - dhd->prot->hmap_rx_buf_len = 0; - PHYSADDRHISET(dhd->prot->hmap_rx_buf_pa, 0); - PHYSADDRLOSET(dhd->prot->hmap_rx_buf_pa, 0); + memcpy(ptr, prot->hmap_rx_buf_va, prot->hmap_rx_buf_len); + prot->hmaptest_rx_active = HMAPTEST_D11_RX_INACTIVE; + prot->hmap_rx_buf_va = NULL; + prot->hmap_rx_buf_len = 0; + PHYSADDRHISET(prot->hmap_rx_buf_pa, 0); + PHYSADDRLOSET(prot->hmap_rx_buf_pa, 0); prot->hmaptest.in_progress = FALSE; } #endif /* DHD_HMAPTEST */ - DHD_MSGBUF_INFO(("id 0x%04x, offset %d, len %d, idx %d, phase 0x%02x, " + DHD_INFO(("id 0x%04x, offset %d, len %d, idx %d, phase 0x%02x, " "pktdata %p, metalen %d\n", ltoh32(msg->cmn_hdr.request_id), ltoh16(msg->data_offset), @@ -6768,6 +6719,19 @@ BCMFASTPATH(dhd_prot_process_msgbuf_rxcpl)(dhd_pub_t *dhd, uint bound, int ringt #endif /* DHD_DBG_SHOW_METADATA */ #endif /* !BCM_ROUTER_DHD */ +#ifdef DHD_LB_RXP + /* If flow control is hit, do not enqueue the pkt into napi queue, + * rather enque it in emergency queue and same will be dequeued first + * during PKTGET. This rxcpl packet will be dropped and will not be sent + * to network stack. + */ + if (atomic_read(&dhd->lb_rxp_flow_ctrl)) { + /* Put back rx_metadata_offset which was pulled during rxpost */ + PKTPUSH(dhd->osh, pkt, prot->rx_metadata_offset); + dhd_rx_emerge_enqueue(dhd, pkt); + continue; + } +#endif /* DHD_LB_RXP */ /* data_offset from buf start */ if (ltoh16(msg->data_offset)) { /* data offset given from dongle after split rx */ @@ -6779,24 +6743,6 @@ BCMFASTPATH(dhd_prot_process_msgbuf_rxcpl)(dhd_pub_t *dhd, uint bound, int ringt } /* Actual length of the packet */ PKTSETLEN(dhd->osh, pkt, ltoh16(msg->data_len)); -#ifdef DHD_PKTTS - if (dhd_get_pktts_enab(dhd) == TRUE) { - uint fwr1 = 0, fwr2 = 0; - - /* firmware mark rx_pktts.tref with 0xFFFFFFFF for errors */ - if (ltoh32(msg->rx_pktts.tref) != 0xFFFFFFFF) { - fwr1 = (uint)htonl(ltoh32(msg->rx_pktts.tref)); - fwr2 = (uint)htonl(ltoh32(msg->rx_pktts.tref) + - ltoh16(msg->rx_pktts.d_t2)); - - /* check for overflow */ - if (ntohl(fwr2) > ntohl(fwr1)) { - /* send rx timestamp to netlnik socket */ - dhd_msgbuf_send_msg_rx_ts(dhd, pkt, fwr1, fwr2); - } - } - } -#endif /* DHD_PKTTS */ #if defined(WL_MONITOR) if (dhd_monitor_enabled(dhd, ifidx)) { @@ -6807,6 +6753,14 @@ BCMFASTPATH(dhd_prot_process_msgbuf_rxcpl)(dhd_pub_t *dhd, uint bound, int ringt DHD_ERROR(("Received non 802.11 packet, " "when monitor mode is enabled\n")); } +#ifdef DBG_PKT_MON + } else { + if (msg->flags & BCMPCIE_PKT_FLAGS_FRAME_802_11) { + DHD_TRACE(("Received 802.11 packet for PKT MON\n")); + dhd_80211_mon_pkt(dhd, msg, pkt, ifidx); + continue; + } +#endif /* DBG_PKT_MON */ } #endif /* WL_MONITOR */ @@ -6826,28 +6780,11 @@ BCMFASTPATH(dhd_prot_process_msgbuf_rxcpl)(dhd_pub_t *dhd, uint bound, int ringt } } -#ifdef DHD_HP2P - if (dhd->hp2p_capable && ring == prot->d2hring_hp2p_rxcpl) { -#ifdef DHD_HP2P_DEBUG - bcm_print_bytes("Rxcpl", (uchar *)msg, sizeof(host_rxbuf_cmpl_t)); -#endif /* DHD_HP2P_DEBUG */ - dhd_update_hp2p_rxstats(dhd, msg); + if (dhd->rx_cpl_lat_capable) { + DHD_GENERAL_LOCK(dhd, rx_lock_flags); + dhd_update_rxstats(dhd, msg); + DHD_GENERAL_UNLOCK(dhd, rx_lock_flags); } -#endif /* DHD_HP2P */ - -#ifdef DHD_TIMESYNC - if (dhd->prot->rx_ts_log_enabled) { - dhd_pkt_parse_t parse; - ts_timestamp_t *ts = (ts_timestamp_t *)&msg->ts; - - memset(&parse, 0, sizeof(dhd_pkt_parse_t)); - dhd_parse_proto(PKTDATA(dhd->osh, pkt), &parse); - - if (parse.proto == IP_PROT_ICMP) - dhd_timesync_log_rx_timestamp(dhd->ts, ifidx, - ts->low, ts->high, &parse); - } -#endif /* DHD_TIMESYNC */ #ifdef DHD_LBUF_AUDIT PKTAUDIT(dhd->osh, pkt); @@ -6897,7 +6834,7 @@ BCMFASTPATH(dhd_prot_process_msgbuf_rxcpl)(dhd_pub_t *dhd, uint bound, int ringt /* After batch processing, check RX bound */ n += pkt_cnt; - if (n >= bound) { + if (n >= prot->rx_cpl_post_bound) { more = TRUE; break; } @@ -6919,42 +6856,43 @@ BCMFASTPATH(dhd_prot_process_msgbuf_rxcpl)(dhd_pub_t *dhd, uint bound, int ringt /** * Hands transmit packets (with a caller provided flow_id) over to dongle territory (the flow ring) */ -void +bool dhd_prot_update_txflowring(dhd_pub_t *dhd, uint16 flowid, void *msgring) { msgbuf_ring_t *ring = (msgbuf_ring_t *)msgring; + dhd_prot_t *prot = dhd->prot; + bool is_qempty = FALSE; + int ret = 0; if (ring == NULL) { DHD_ERROR(("%s: NULL txflowring. exiting...\n", __FUNCTION__)); - return; - } - /* Update read pointer */ - if (dhd->dma_d2h_ring_upd_support) { - ring->rd = dhd_prot_dma_indx_get(dhd, H2D_DMA_INDX_RD_UPD, ring->idx); + return FALSE; } DHD_TRACE(("ringid %d flowid %d write %d read %d \n\n", ring->idx, flowid, ring->wr, ring->rd)); /* Need more logic here, but for now use it directly */ - dhd_bus_schedule_queue(dhd->bus, flowid, TRUE); /* from queue to flowring */ + ret = dhd_bus_schedule_queue(dhd->bus, flowid, TRUE, + prot->tx_post_bound, &is_qempty); /* from queue to flowring */ + if (ret == BCME_OK) { + return !is_qempty; + } else { + return FALSE; + } } /** called when DHD needs to check for 'transmit complete' messages from the dongle */ bool -BCMFASTPATH(dhd_prot_process_msgbuf_txcpl)(dhd_pub_t *dhd, uint bound, int ringtype) +BCMFASTPATH(dhd_prot_process_msgbuf_txcpl)(dhd_pub_t *dhd, int ringtype, uint32 *txcpl_items) { bool more = TRUE; uint n = 0; msgbuf_ring_t *ring; unsigned long flags; + dhd_prot_t *prot = dhd->prot; -#ifdef DHD_HP2P - if (ringtype == DHD_HP2P_RING && dhd->prot->d2hring_hp2p_txcpl) - ring = dhd->prot->d2hring_hp2p_txcpl; - else -#endif /* DHD_HP2P */ - ring = &dhd->prot->d2hring_tx_cpln; + ring = &prot->d2hring_tx_cpln; /* Process all the messages - DTOH direction */ while (!dhd_is_device_removed(dhd)) { @@ -6977,8 +6915,17 @@ BCMFASTPATH(dhd_prot_process_msgbuf_txcpl)(dhd_pub_t *dhd, uint bound, int ringt } DHD_RING_LOCK(ring->ring_lock, flags); + /* Get the address of the next message to be read from ring */ - msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len); + /* must pass 'bound - n' rather than just 'bound', because + * within this loop, dhd_prot_get_read_addr is called multiple + * times, so if just 'bound' is passed we may end up reading + * more than 'bound' items, ex:- for a bound of 2048, + * during the first iteration let us say n = 2000, so the loop + * continues and for the second iteration n = 1000 items may be read, + * so the total items read will be 3000 which is > 2048 + */ + msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len, prot->tx_cpl_bound - n); DHD_RING_UNLOCK(ring->ring_lock, flags); if (msg_addr == NULL) { @@ -6986,6 +6933,8 @@ BCMFASTPATH(dhd_prot_process_msgbuf_txcpl)(dhd_pub_t *dhd, uint bound, int ringt break; } + *txcpl_items = msg_len / ring->item_len; + /* Prefetch data to populate the cache */ OSL_PREFETCH(msg_addr); @@ -6999,28 +6948,21 @@ BCMFASTPATH(dhd_prot_process_msgbuf_txcpl)(dhd_pub_t *dhd, uint bound, int ringt /* After batch processing, check bound */ n += msg_len / ring->item_len; - if (n >= bound) { + + if (n >= prot->tx_cpl_bound) { break; } } - if (n) { - /* For IDMA and HWA case, doorbell is sent along with read index update. - * For DMA indices case ring doorbell once n items are read to sync with dongle. - */ - if (dhd->dma_h2d_ring_upd_support && !IDMA_ACTIVE(dhd)) { - dhd_prot_ring_doorbell(dhd, DHD_RDPTR_UPDATE_H2D_DB_MAGIC(ring)); - dhd->prot->txcpl_db_cnt++; - } - } return more; } int BCMFASTPATH(dhd_prot_process_trapbuf)(dhd_pub_t *dhd) { - uint32 data; + uint32 data, copylen; dhd_dma_buf_t *trap_addr = &dhd->prot->fw_trap_buf; + int ret = 0; /* Interrupts can come in before this struct * has been initialized. @@ -7036,40 +6978,53 @@ BCMFASTPATH(dhd_prot_process_trapbuf)(dhd_pub_t *dhd) if (data & D2H_DEV_FWHALT) { if (dhd->db7_trap.fw_db7w_trap_inprogress) { DHD_ERROR(("DB7 FW responded 0x%04x\n", data)); + dhd->db7_trap.fw_db7w_trap_recieved = TRUE; } else { DHD_ERROR(("Firmware trapped and trap_data is 0x%04x\n", data)); } +#if defined(PCIE_INB_DW) && defined(PCIE_INB_DSACK_EXT_WAIT) + if (INBAND_DW_ENAB(dhd->bus)) { + if (data & D2H_DEV_TRAP_DS_ACK_TIMEOUT) { + dhd_bus_ds_ack_debug_dump(dhd->bus); + } + } +#endif /* PCIE_INB_DW && PCIE_INB_DSACK_EXT_WAIT */ + if (data & D2H_DEV_EXT_TRAP_DATA) { if (dhd->extended_trap_data) { OSL_CACHE_INV((void *)trap_addr->va, BCMPCIE_EXT_TRAP_DATA_MAXLEN); - memcpy(dhd->extended_trap_data, (uint32 *)trap_addr->va, - BCMPCIE_EXT_TRAP_DATA_MAXLEN); + copylen = MIN(trap_addr->len, BCMPCIE_EXT_TRAP_DATA_MAXLEN); + ret = memcpy_s(dhd->extended_trap_data, + BCMPCIE_EXT_TRAP_DATA_MAXLEN, + (uint32 *)trap_addr->va, copylen); + if (ret) { + DHD_ERROR(("trap data memcpy failed:%d, destsz:%d, n:%u\n", + ret, BCMPCIE_EXT_TRAP_DATA_MAXLEN, + copylen)); + return 0; + } } if (dhd->db7_trap.fw_db7w_trap_inprogress == FALSE) { DHD_ERROR(("Extended trap data available\n")); } } -#ifdef BT_OVER_PCIE - if (data & D2H_DEV_TRAP_DUE_TO_BT) { - DHD_ERROR(("WLAN Firmware trapped due to BT\n")); - dhd->dongle_trap_due_to_bt = TRUE; - } -#endif /* BT_OVER_PCIE */ return data; } return 0; } /** called when DHD needs to check for 'ioctl complete' messages from the dongle */ -int -BCMFASTPATH(dhd_prot_process_ctrlbuf)(dhd_pub_t *dhd) +bool +BCMFASTPATH(dhd_prot_process_ctrlbuf)(dhd_pub_t *dhd, uint32 *ctrlcpl_items) { dhd_prot_t *prot = dhd->prot; msgbuf_ring_t *ring = &prot->d2hring_ctrl_cpln; unsigned long flags; + uint32 n = 0; + bool more = TRUE; /* Process all the messages - DTOH direction */ while (!dhd_is_device_removed(dhd)) { @@ -7077,26 +7032,41 @@ BCMFASTPATH(dhd_prot_process_ctrlbuf)(dhd_pub_t *dhd) uint32 msg_len; if (dhd_query_bus_erros(dhd)) { + more = FALSE; break; } if (dhd->hang_was_sent) { + more = FALSE; break; } if (dhd->smmu_fault_occurred) { + more = FALSE; break; } DHD_RING_LOCK(ring->ring_lock, flags); /* Get the address of the next message to be read from ring */ - msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len); + /* must pass 'bound - n' rather than just 'bound', because + * within this loop, dhd_prot_get_read_addr is called multiple + * times, so if just 'bound' is passed we may end up reading + * more than 'bound' items, ex:- for a bound of 2048, + * during the first iteration let us say n = 2000, so the loop + * continues and for the second iteration n = 1000 items may be read, + * so the total items read will be 3000 which is > 2048 + */ + msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len, + prot->ctrl_cpl_post_bound - n); DHD_RING_UNLOCK(ring->ring_lock, flags); if (msg_addr == NULL) { + more = FALSE; break; } + *ctrlcpl_items = msg_len / ring->item_len; + /* Prefetch data to populate the cache */ OSL_PREFETCH(msg_addr); if (dhd_prot_process_msgtype(dhd, ring, msg_addr, msg_len) != BCME_OK) { @@ -7106,9 +7076,14 @@ BCMFASTPATH(dhd_prot_process_ctrlbuf)(dhd_pub_t *dhd) /* Write to dngl rd ptr */ dhd_prot_upd_read_idx(dhd, ring); + + n += msg_len / ring->item_len; + if (n >= prot->ctrl_cpl_post_bound) { + break; + } } - return 0; + return more; } /** @@ -7144,6 +7119,13 @@ BCMFASTPATH(dhd_prot_process_msgtype)(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8 goto done; } +#ifdef DHD_DEBUG_INVALID_PKTID + if (ring == &dhd->prot->d2hring_ctrl_cpln) { + (void)memcpy_s(dhd->prot->ctrl_cpl_snapshot, D2HRING_CTRL_CMPLT_ITEMSIZE, + buf, D2HRING_CTRL_CMPLT_ITEMSIZE); + } +#endif /* DHD_DEBUG_INVALID_PKTID */ + msg = (cmn_msg_hdr_t *)buf; /* Wait until DMA completes, then fetch msg_type */ @@ -7164,7 +7146,7 @@ BCMFASTPATH(dhd_prot_process_msgtype)(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8 /* Prefetch data to populate the cache */ OSL_PREFETCH(buf + item_len); - DHD_MSGBUF_INFO(("msg_type %d item_len %d buf_len %d\n", + DHD_INFO(("msg_type %d item_len %d buf_len %d\n", msg_type, item_len, buf_len)); if (msg_type == MSG_TYPE_LOOPBACK) { @@ -7192,23 +7174,6 @@ BCMFASTPATH(dhd_prot_process_msgtype)(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8 dhd_prot_infobufpost(dhd, dhd->prot->h2dring_info_subn); dhd_prot_process_infobuf_complete(dhd, buf); } -#ifdef BTLOG - else if (ring == dhd->prot->d2hring_btlog_cpln) { - info_buf_resp_t *resp = (info_buf_resp_t *)buf; - - if (!dhd->prot->btlogbufpost) { - DHD_ERROR(("btlogbuf posted are zero," - "but there is a completion\n")); - goto done; - } - - dhd->prot->btlogbufpost--; - if (resp->compl_hdr.status != BCMPCIE_PKT_FLUSH) { - dhd_prot_infobufpost(dhd, dhd->prot->h2dring_btlog_subn); - } - dhd_prot_process_btlog_complete(dhd, buf); - } -#endif /* BTLOG */ } else #endif /* !defined(BCM_ROUTER_DHD) */ if (table_lookup[msg_type]) { @@ -7281,67 +7246,12 @@ dhd_prot_ringstatus_process(dhd_pub_t *dhd, void *msg) dhd->prot->d2hring_info_cpln->create_pending = FALSE; } else - DHD_ERROR(("ring create ID for info ring, create not pending\n")); + DHD_ERROR_MEM(("ring create ID for info ring, " + "create not pending\n")); } else { DHD_ERROR(("%s info cpl ring doesn't exist\n", __FUNCTION__)); } } -#ifdef BTLOG - else if (request_id == DHD_H2D_BTLOGRING_REQ_PKTID) { - /* XXX: see if the debug ring create is pending */ - if (dhd->prot->h2dring_btlog_subn != NULL) { - if (dhd->prot->h2dring_btlog_subn->create_pending == TRUE) { - DHD_ERROR(("H2D ring create failed for btlog ring\n")); - dhd->prot->h2dring_btlog_subn->create_pending = FALSE; - } - else - DHD_ERROR(("ring create ID for a ring, create not pending\n")); - } else { - DHD_ERROR(("%s btlog submit ring doesn't exist\n", __FUNCTION__)); - } - } - else if (request_id == DHD_D2H_BTLOGRING_REQ_PKTID) { - /* XXX: see if the debug ring create is pending */ - if (dhd->prot->d2hring_btlog_cpln != NULL) { - if (dhd->prot->d2hring_btlog_cpln->create_pending == TRUE) { - DHD_ERROR(("D2H ring create failed for btlog ring\n")); - dhd->prot->d2hring_btlog_cpln->create_pending = FALSE; - } - else - DHD_ERROR(("ring create ID for btlog ring, create not pending\n")); - } else { - DHD_ERROR(("%s btlog cpl ring doesn't exist\n", __FUNCTION__)); - } - } -#endif /* BTLOG */ -#ifdef DHD_HP2P - else if (request_id == DHD_D2H_HPPRING_TXREQ_PKTID) { - /* XXX: see if the HPP txcmpl ring create is pending */ - if (dhd->prot->d2hring_hp2p_txcpl != NULL) { - if (dhd->prot->d2hring_hp2p_txcpl->create_pending == TRUE) { - DHD_ERROR(("H2D ring create failed for hp2p ring\n")); - dhd->prot->d2hring_hp2p_txcpl->create_pending = FALSE; - } - else - DHD_ERROR(("ring create ID for a ring, create not pending\n")); - } else { - DHD_ERROR(("%s hp2p txcmpl ring doesn't exist\n", __FUNCTION__)); - } - } - else if (request_id == DHD_D2H_HPPRING_RXREQ_PKTID) { - /* XXX: see if the hp2p rxcmpl ring create is pending */ - if (dhd->prot->d2hring_hp2p_rxcpl != NULL) { - if (dhd->prot->d2hring_hp2p_rxcpl->create_pending == TRUE) { - DHD_ERROR(("D2H ring create failed for hp2p rxcmpl ring\n")); - dhd->prot->d2hring_hp2p_rxcpl->create_pending = FALSE; - } - else - DHD_ERROR(("ring create ID for hp2p rxcmpl ring, not pending\n")); - } else { - DHD_ERROR(("%s hp2p rxcpl ring doesn't exist\n", __FUNCTION__)); - } - } -#endif /* DHD_HP2P */ else { DHD_ERROR(("don;t know how to pair with original request\n")); } @@ -7379,12 +7289,15 @@ dhd_prot_ioctack_process(dhd_pub_t *dhd, void *msg) /* Skip audit for ADHD_IOCTL_REQ_PKTID = 0xFFFE */ if (pktid != DHD_IOCTL_REQ_PKTID) { #ifndef IOCTLRESP_USE_CONSTMEM - DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_ctrl_map, pktid, - DHD_TEST_IS_ALLOC, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); + if (DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_ctrl_map, pktid, + DHD_TEST_IS_ALLOC, msg, D2HRING_CTRL_CMPLT_ITEMSIZE) != BCME_OK) #else - DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_map_handle_ioctl, pktid, - DHD_TEST_IS_ALLOC, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); + if (DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_map_handle_ioctl, pktid, + DHD_TEST_IS_ALLOC, msg, D2HRING_CTRL_CMPLT_ITEMSIZE) != BCME_OK) #endif /* !IOCTLRESP_USE_CONSTMEM */ + { + return; + } } #endif /* DHD_PKTID_AUDIT_RING && !BCM_ROUTER_DHD */ @@ -7429,6 +7342,7 @@ dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void *msg) #ifdef REPORT_FATAL_TIMEOUTS uint16 dhd_xt_id; #endif + int ret = 0; /* Check for ioctl timeout induce flag, which is set by firing * dhd iovar to induce IOCTL timeout. If flag is set, @@ -7445,12 +7359,15 @@ dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void *msg) #if defined(DHD_PKTID_AUDIT_RING) && !defined(BCM_ROUTER_DHD) #ifndef IOCTLRESP_USE_CONSTMEM - DHD_PKTID_AUDIT_RING_DEBUG(dhd, prot->pktid_ctrl_map, pkt_id, - DHD_DUPLICATE_FREE, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); + if (DHD_PKTID_AUDIT_RING_DEBUG(dhd, prot->pktid_ctrl_map, pkt_id, + DHD_DUPLICATE_FREE, msg, D2HRING_CTRL_CMPLT_ITEMSIZE) != BCME_OK) #else - DHD_PKTID_AUDIT_RING_DEBUG(dhd, prot->pktid_map_handle_ioctl, pkt_id, - DHD_DUPLICATE_FREE, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); + if (DHD_PKTID_AUDIT_RING_DEBUG(dhd, prot->pktid_map_handle_ioctl, pkt_id, + DHD_DUPLICATE_FREE, msg, D2HRING_CTRL_CMPLT_ITEMSIZE) != BCME_OK) #endif /* !IOCTLRESP_USE_CONSTMEM */ + { + return; + } #endif /* DHD_PKTID_AUDIT_RING && !BCM_ROUTER_DHD */ DHD_GENERAL_LOCK(dhd, flags); @@ -7521,11 +7438,18 @@ dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void *msg) pkt_id, xt_id, prot->ioctl_status, prot->ioctl_resplen)); if (prot->ioctl_resplen > 0) { + uint16 copy_len = MIN(prot->ioctl_resplen, prot->retbuf.len); #ifndef IOCTLRESP_USE_CONSTMEM - bcopy(PKTDATA(dhd->osh, pkt), prot->retbuf.va, prot->ioctl_resplen); + ret = memcpy_s(prot->retbuf.va, prot->retbuf.len, PKTDATA(dhd->osh, pkt), copy_len); #else - bcopy(pkt, prot->retbuf.va, prot->ioctl_resplen); + ret = memcpy_s(prot->retbuf.va, prot->retbuf.len, pkt, copy_len); #endif /* !IOCTLRESP_USE_CONSTMEM */ + if (ret) { + DHD_ERROR(("memcpy failed:%d, destsz:%d, n:%u\n", + ret, prot->retbuf.len, copy_len)); + dhd_wakeup_ioctl_event(dhd, IOCTL_RETURN_ON_ERROR); + goto exit; + } } /* wake up any dhd_os_ioctl_resp_wait() */ @@ -7553,302 +7477,6 @@ dhd_prot_check_tx_resource(dhd_pub_t *dhd) return dhd->prot->no_tx_resource; } -#ifdef DHD_PKTTS -/** - * dhd_msgbuf_get_ip_info - this api finds following (ipv4 and ipv6 are supported) - * 1. pointer to data portion of pkt - * 2. five tuple checksum of pkt - * = {scr_ip, dst_ip, src_port, dst_port, proto} - * 3. ip_prec - * - * @dhdp: pointer to dhd_pub object - * @pkt: packet pointer - * @ptr: retuns pointer to data portion of pkt - * @chksum: returns five tuple checksum of pkt - * @prec: returns ip precedence - * @tcp_seqno: returns tcp sequnce number - * - * returns packet length remaining after tcp/udp header or BCME_ERROR. - */ -static int -dhd_msgbuf_get_ip_info(dhd_pub_t *dhdp, void *pkt, void **ptr, uint32 *chksum, - uint32 *prec, uint32 *tcp_seqno, uint32 *tcp_ackno) -{ - char *pdata; - uint plen; - uint32 type, len; - uint32 checksum = 0; - uint8 dscp_prio = 0; - struct bcmtcp_hdr *tcp = NULL; - - pdata = PKTDATA(dhdp->osh, pkt); - plen = PKTLEN(dhdp->osh, pkt); - - /* Ethernet header */ - if (plen < ETHER_HDR_LEN) { - return BCME_ERROR; - } - type = ntoh16(((struct ether_header *)pdata)->ether_type); - pdata += ETHER_HDR_LEN; - plen -= ETHER_HDR_LEN; - - if ((type == ETHER_TYPE_IP) || - (type == ETHER_TYPE_IPV6)) { - dscp_prio = (IP_TOS46(pdata) >> IPV4_TOS_PREC_SHIFT); - } - - /* IP header (v4 or v6) */ - if (type == ETHER_TYPE_IP) { - struct ipv4_hdr *iph = (struct ipv4_hdr *)pdata; - if (plen <= sizeof(*iph)) { - return BCME_ERROR; - } - - len = IPV4_HLEN(iph); - if (plen <= len || IP_VER(iph) != IP_VER_4 || len < IPV4_MIN_HEADER_LEN) { - return BCME_ERROR; - } - - type = IPV4_PROT(iph); - pdata += len; - plen -= len; - - checksum ^= bcm_compute_xor32((volatile uint32 *)iph->src_ip, - sizeof(iph->src_ip) / sizeof(uint32)); - checksum ^= bcm_compute_xor32((volatile uint32 *)iph->dst_ip, - sizeof(iph->dst_ip) / sizeof(uint32)); - } else if (type == ETHER_TYPE_IPV6) { - struct ipv6_hdr *ip6h = (struct ipv6_hdr *)pdata; - - if (plen <= IPV6_MIN_HLEN || IP_VER(ip6h) != IP_VER_6) { - return BCME_ERROR; - } - - type = IPV6_PROT(ip6h); - pdata += IPV6_MIN_HLEN; - plen -= IPV6_MIN_HLEN; - if (IPV6_EXTHDR(type)) { - uint8 proto = 0; - int32 exth_len = ipv6_exthdr_len(pdata, &proto); - if (exth_len < 0 || ((plen -= exth_len) <= 0)) { - return BCME_ERROR; - } - type = proto; - pdata += exth_len; - plen -= exth_len; - } - - checksum ^= bcm_compute_xor32((volatile uint32 *)&ip6h->saddr, - sizeof(ip6h->saddr) / sizeof(uint32)); - checksum ^= bcm_compute_xor32((volatile uint32 *)&ip6h->daddr, - sizeof(ip6h->saddr) / sizeof(uint32)); - } - - /* return error if not TCP or UDP */ - if ((type != IP_PROT_UDP) && (type != IP_PROT_TCP)) { - return BCME_ERROR; - } - - /* src_port and dst_port (together 32bit) */ - checksum ^= bcm_compute_xor32((volatile uint32 *)pdata, 1); - checksum ^= bcm_compute_xor32((volatile uint32 *)&type, 1); - - if (type == IP_PROT_TCP) { - tcp = (struct bcmtcp_hdr *)pdata; - len = TCP_HDRLEN(pdata[TCP_HLEN_OFFSET]) << 2; - } else { /* IP_PROT_UDP */ - len = sizeof(struct bcmudp_hdr); - } - - /* length check */ - if (plen < len) { - return BCME_ERROR; - } - - pdata += len; - plen -= len; - - /* update data[0] */ - *ptr = (void *)pdata; - - /* update fivetuple checksum */ - *chksum = checksum; - - /* update ip prec */ - *prec = dscp_prio; - - /* update tcp sequence number */ - if (tcp != NULL) { - *tcp_seqno = tcp->seq_num; - *tcp_ackno = tcp->ack_num; - } - - return plen; -} - -/** - * dhd_msgbuf_send_msg_tx_ts - send pktts tx timestamp to netlnik socket - * - * @dhdp: pointer to dhd_pub object - * @pkt: packet pointer - * @fwts: firmware timestamp {fwt1..fwt4} - * @version: pktlat version supported in firmware - */ -static void -dhd_msgbuf_send_msg_tx_ts(dhd_pub_t *dhdp, void *pkt, void *fw_ts, uint16 version) -{ - bcm_to_info_tx_ts_t to_tx_info; - void *ptr = NULL; - int dlen = 0; - uint32 checksum = 0; - uint32 prec = 0; - pktts_flow_t *flow = NULL; - uint32 flow_pkt_offset = 0; - uint32 num_config = 0; - uint32 tcp_seqno = 0; - uint32 tcp_ackno = 0; - - dlen = dhd_msgbuf_get_ip_info(dhdp, pkt, &ptr, &checksum, &prec, &tcp_seqno, &tcp_ackno); - - flow = dhd_match_pktts_flow(dhdp, checksum, NULL, &num_config); - if (flow) { - /* there is valid config for this chksum */ - flow_pkt_offset = flow->pkt_offset; - } else if (num_config) { - /* there is valid config + no matching config for this chksum */ - return; - } else { - /* there is no valid config. pass all to netlink */ - } - - memset(&to_tx_info, 0, sizeof(to_tx_info)); - to_tx_info.hdr.type = BCM_TS_TX; - to_tx_info.hdr.flowid = checksum; - to_tx_info.hdr.prec = prec; - - /* special case: if flow is not configured, copy tcp seqno and ackno in xbytes */ - if (!flow && tcp_seqno) { - uint32 *xbytes = (uint32 *)to_tx_info.hdr.xbytes; - - (void)memcpy_s(&xbytes[0], sizeof(xbytes[0]), - ((uint8 *)&tcp_seqno), sizeof(tcp_seqno)); - (void)memcpy_s(&xbytes[1], sizeof(xbytes[1]), - ((uint8 *)&tcp_ackno), sizeof(tcp_ackno)); - } else if ((dlen > flow_pkt_offset) && - ((dlen - flow_pkt_offset) >= sizeof(to_tx_info.hdr.xbytes))) { - (void)memcpy_s(to_tx_info.hdr.xbytes, sizeof(to_tx_info.hdr.xbytes), - ((uint8 *)ptr + flow_pkt_offset), sizeof(to_tx_info.hdr.xbytes)); - } - - to_tx_info.dhdt0 = DHD_PKT_GET_QTIME(pkt); - to_tx_info.dhdt5 = OSL_SYSUPTIME_US(); - - if (version == METADATA_VER_1) { - struct pktts_fwtx_v1 *fwts = (struct pktts_fwtx_v1 *)fw_ts; - - to_tx_info.hdr.magic = BCM_TS_MAGIC; - - to_tx_info.fwts[0] = ntohl(fwts->ts[0]); - to_tx_info.fwts[1] = ntohl(fwts->ts[1]); - to_tx_info.fwts[2] = ntohl(fwts->ts[2]); - to_tx_info.fwts[3] = ntohl(fwts->ts[3]); - - dhd_send_msg_to_ts(NULL, (void *)&to_tx_info, OFFSETOF(bcm_to_info_tx_ts_t, ucts)); - } else if (version == METADATA_VER_2) { - struct pktts_fwtx_v2 *fwts = (struct pktts_fwtx_v2 *)fw_ts; - - to_tx_info.hdr.magic = BCM_TS_MAGIC_V2; - - to_tx_info.fwts[0] = ntohl(fwts->ts[0]); - to_tx_info.fwts[1] = ntohl(fwts->ts[1]); - to_tx_info.fwts[2] = ntohl(fwts->ts[2]); - to_tx_info.fwts[3] = ntohl(fwts->ts[3]); - - to_tx_info.ucts[0] = ntohl(fwts->ut[0]); - to_tx_info.ucts[1] = ntohl(fwts->ut[1]); - to_tx_info.ucts[2] = ntohl(fwts->ut[2]); - to_tx_info.ucts[3] = ntohl(fwts->ut[3]); - to_tx_info.ucts[4] = ntohl(fwts->ut[4]); - - to_tx_info.uccnt[0] = ntohl(fwts->uc[0]); - to_tx_info.uccnt[1] = ntohl(fwts->uc[1]); - to_tx_info.uccnt[2] = ntohl(fwts->uc[2]); - to_tx_info.uccnt[3] = ntohl(fwts->uc[3]); - to_tx_info.uccnt[4] = ntohl(fwts->uc[4]); - to_tx_info.uccnt[5] = ntohl(fwts->uc[5]); - to_tx_info.uccnt[6] = ntohl(fwts->uc[6]); - to_tx_info.uccnt[7] = ntohl(fwts->uc[7]); - - dhd_send_msg_to_ts(NULL, (void *)&to_tx_info, sizeof(to_tx_info)); - } - return; -} - -/** - * dhd_msgbuf_send_msg_dx_ts - send pktts rx timestamp to netlnik socket - * - * @dhdp: pointer to dhd_pub object - * @pkt: packet pointer - * @fwr1: firmware timestamp at probe point 1 - * @fwr2: firmware timestamp at probe point 2 - */ -static void -dhd_msgbuf_send_msg_rx_ts(dhd_pub_t *dhdp, void *pkt, uint fwr1, uint fwr2) -{ - bcm_to_info_rx_ts_t to_rx_info; - void *ptr = NULL; - int dlen = 0; - uint32 checksum = 0; - uint32 prec = 0; - pktts_flow_t *flow = NULL; - uint32 flow_pkt_offset = 0; - uint32 num_config = 0; - uint32 tcp_seqno = 0; - uint32 tcp_ackno = 0; - - dlen = dhd_msgbuf_get_ip_info(dhdp, pkt, &ptr, &checksum, &prec, &tcp_seqno, &tcp_ackno); - - flow = dhd_match_pktts_flow(dhdp, checksum, NULL, &num_config); - if (flow) { - /* there is valid config for this chksum */ - flow_pkt_offset = flow->pkt_offset; - } else if (num_config) { - /* there is valid config + no matching config for this chksum */ - return; - } else { - /* there is no valid config. pass all to netlink */ - } - - memset(&to_rx_info, 0, sizeof(to_rx_info)); - to_rx_info.hdr.magic = BCM_TS_MAGIC; - to_rx_info.hdr.type = BCM_TS_RX; - to_rx_info.hdr.flowid = checksum; - to_rx_info.hdr.prec = prec; - - /* special case: if flow is not configured, copy tcp seqno and ackno in xbytes */ - if (!flow && tcp_seqno) { - uint32 *xbytes = (uint32 *)to_rx_info.hdr.xbytes; - - (void)memcpy_s(&xbytes[0], sizeof(xbytes[0]), - ((uint8 *)&tcp_seqno), sizeof(tcp_seqno)); - (void)memcpy_s(&xbytes[1], sizeof(xbytes[1]), - ((uint8 *)&tcp_ackno), sizeof(tcp_ackno)); - } else if ((dlen > flow_pkt_offset) && - ((dlen - flow_pkt_offset) >= sizeof(to_rx_info.hdr.xbytes))) { - (void)memcpy_s(to_rx_info.hdr.xbytes, sizeof(to_rx_info.hdr.xbytes), - ((uint8 *)ptr + flow_pkt_offset), sizeof(to_rx_info.hdr.xbytes)); - } - - to_rx_info.dhdr3 = OSL_SYSUPTIME_US(); - - to_rx_info.fwts[0] = ntohl(fwr1); - to_rx_info.fwts[1] = ntohl(fwr2); - - dhd_send_msg_to_ts(NULL, (void *)&to_rx_info, sizeof(to_rx_info)); - return; -} -#endif /* DHD_PKTTS */ - /** called on MSG_TYPE_TX_STATUS message received from dongle */ static void BCMFASTPATH(dhd_prot_txstatus_process)(dhd_pub_t *dhd, void *msg) @@ -7871,36 +7499,10 @@ BCMFASTPATH(dhd_prot_txstatus_process)(dhd_pub_t *dhd, void *msg) #ifdef AGG_H2D_DB msgbuf_ring_t *flow_ring; #endif /* AGG_H2D_DB */ -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) - dhd_awdl_stats_t *awdl_stats; - if_flow_lkup_t *if_flow_lkup; - unsigned long awdl_stats_lock_flags; - uint8 ifindex; - uint8 role; -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ flow_ring_node_t *flow_ring_node; uint16 flowid; -#ifdef DHD_PKTTS - struct metadata_txcmpl_v1 meta_ts_v1; - struct metadata_txcmpl_v2 meta_ts_v2; - dhd_dma_buf_t meta_data_buf; - uint64 addr = 0; - - BCM_REFERENCE(meta_ts_v1); - BCM_REFERENCE(meta_ts_v2); - BCM_REFERENCE(meta_data_buf); - BCM_REFERENCE(addr); - - if ((dhd->memdump_type == DUMP_TYPE_PKTID_AUDIT_FAILURE) || - (dhd->memdump_type == DUMP_TYPE_PKTID_INVALID)) { - DHD_ERROR_RLMT(("%s: return as invalid pktid detected\n", __FUNCTION__)); - return; - } - - memset(&meta_ts_v1, 0, sizeof(meta_ts_v1)); - memset(&meta_ts_v2, 0, sizeof(meta_ts_v2)); - memset(&meta_data_buf, 0, sizeof(meta_data_buf)); -#endif /* DHD_PKTTS */ + tx_cpl_info_t *txcpl_info = &dhd->txcpl_info; + ts_timestamp_t *ts; txstatus = (host_txbuf_cmpl_t *)msg; flowid = txstatus->compl_hdr.flow_ring_id; @@ -7919,12 +7521,6 @@ BCMFASTPATH(dhd_prot_txstatus_process)(dhd_pub_t *dhd, void *msg) */ flow_ring_node->tx_cmpl = OSL_SYSUPTIME(); /* update host copy of rd pointer */ -#ifdef DHD_HP2P - if (dhd->prot->d2hring_hp2p_txcpl && - flow_ring_node->flow_info.tid == HP2P_PRIO) { - ring = dhd->prot->d2hring_hp2p_txcpl; - } -#endif /* DHD_HP2P */ ring->curr_rd++; if (ring->curr_rd >= ring->max_items) { ring->curr_rd = 0; @@ -7945,22 +7541,26 @@ BCMFASTPATH(dhd_prot_txstatus_process)(dhd_pub_t *dhd, void *msg) * | |> delay time first fetch to the last fetch (4-bit 1 = 32ms) * |> fetch count (4-bit) */ - printf("TX status[%d] = %04x-%04x -> status = %d (%d/%dms + %d/%dms)\n", pktid, + DHD_CONS_ONLY(("TX status[%d] = %04x-%04x -> status = %d (%d/%dms + %d/%dms)\n", + pktid, ltoh16(txstatus->tx_status_ext), ltoh16(txstatus->tx_status), (txstatus->tx_status & WLFC_CTL_PKTFLAG_MASK), ((txstatus->tx_status >> 12) & 0xf), ((txstatus->tx_status >> 8) & 0xf) * 32, ((txstatus->tx_status_ext & 0xff) * 4), - ((txstatus->tx_status_ext >> 8) & 0xff) * 4); + ((txstatus->tx_status_ext >> 8) & 0xff) * 4)); } pkt_fate = TRUE; #if defined(DHD_PKTID_AUDIT_RING) && !defined(BCM_ROUTER_DHD) - DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_tx_map, pktid, - DHD_DUPLICATE_FREE, msg, D2HRING_TXCMPLT_ITEMSIZE); + if (DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_tx_map, pktid, + DHD_DUPLICATE_FREE, msg, D2HRING_TXCMPLT_ITEMSIZE) != BCME_OK) { + DHD_RING_UNLOCK(ring->ring_lock, flags); + return; + } #endif /* DHD_PKTID_AUDIT_RING && !BCM_ROUTER_DHD */ - DHD_MSGBUF_INFO(("txstatus for pktid 0x%04x\n", pktid)); + DHD_INFO(("txstatus for pktid 0x%04x\n", pktid)); if (OSL_ATOMIC_DEC_RETURN(dhd->osh, &prot->active_tx_count) < 0) { DHD_ERROR(("Extra packets are freed\n")); } @@ -7984,49 +7584,22 @@ BCMFASTPATH(dhd_prot_txstatus_process)(dhd_pub_t *dhd, void *msg) /* original skb is kept as it is because its going to be freed later in this path */ #endif /* DHD_HMAPTEST */ -#ifdef DHD_PKTTS - if (dhd_get_pktts_enab(dhd) && - dhd->pkt_metadata_buflen) { - /* Handle the Metadata first */ - meta_data_buf.va = DHD_PKTID_RETREIVE_METADATA(dhd, dhd->prot->pktid_tx_map, - meta_data_buf.pa, meta_data_buf._alloced, meta_data_buf.dmah, pktid); - if (meta_data_buf.va) { - if (dhd->pkt_metadata_version == METADATA_VER_1) { - memcpy(&meta_ts_v1, meta_data_buf.va, sizeof(meta_ts_v1)); - } else if (dhd->pkt_metadata_version == METADATA_VER_2) { - memcpy(&meta_ts_v2, meta_data_buf.va, sizeof(meta_ts_v2)); - } - memcpy(&addr, &meta_data_buf.pa, sizeof(meta_data_buf.pa)); - DHD_TRACE(("%s(): pktid %d retrieved mdata buffer %p " - "pa: %llx dmah: %p\r\n", __FUNCTION__, - pktid, meta_data_buf.va, addr, - meta_data_buf.dmah)); - } - } -#endif /* DHD_PKTTS */ - pkt = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_tx_map, pktid, pa, len, dmah, secdma, PKTTYPE_DATA_TX); if (!pkt) { DHD_RING_UNLOCK(ring->ring_lock, flags); -#ifdef DHD_PKTTS - /* - * Call the free function after the Ring Lock is released. - * This is becuase pcie_free_consistent is not supposed to be - * called with Interrupts Disabled - */ - if (meta_data_buf.va) { - DMA_FREE_CONSISTENT(dhd->osh, meta_data_buf.va, meta_data_buf._alloced, - meta_data_buf.pa, meta_data_buf.dmah); - } -#endif /* DHD_PKTTS */ DHD_ERROR(("%s: received txstatus with NULL pkt\n", __FUNCTION__)); prhex("dhd_prot_txstatus_process:", (uchar *)msg, D2HRING_TXCMPLT_ITEMSIZE); #ifdef DHD_FW_COREDUMP if (dhd->memdump_enabled) { + dhd->pktid_invalid_occured = TRUE; /* collect core dump */ dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; dhd_bus_mem_dump(dhd); +#ifdef OEM_ANDROID + dhd->hang_reason = HANG_REASON_PCIE_PKTID_ERROR; + dhd_os_send_hang_message(dhd); +#endif /* OEM_ANDROID */ } #else ASSERT(0); @@ -8042,51 +7615,15 @@ BCMFASTPATH(dhd_prot_txstatus_process)(dhd_pub_t *dhd, void *msg) dhd_bus_start_queue(dhd->bus); } - DMA_UNMAP(dhd->osh, pa, (uint) len, DMA_RX, 0, dmah); + DMA_UNMAP(dhd->osh, pa, (uint) len, DMA_TX, 0, dmah); #ifdef TX_STATUS_LATENCY_STATS /* update the tx status latency for flowid */ flow_info = &flow_ring_node->flow_info; tx_status_latency = OSL_SYSUPTIME_US() - DHD_PKT_GET_QTIME(pkt); -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) - if (dhd->pkt_latency > 0 && - tx_status_latency > (dhd->pkt_latency)) { - DHD_ERROR(("Latency: %llu > %u aw_cnt: %u \n", - tx_status_latency, dhd->pkt_latency, - dhd->awdl_aw_counter)); - } -#endif /* defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) */ flow_info->cum_tx_status_latency += tx_status_latency; flow_info->num_tx_status++; #endif /* TX_STATUS_LATENCY_STATS */ -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) - /* update the tx status latency when this AWDL slot is active */ - if_flow_lkup = (if_flow_lkup_t *)dhd->if_flow_lkup; - ifindex = flow_ring_node->flow_info.ifindex; - role = if_flow_lkup[ifindex].role; - if (role == WLC_E_IF_ROLE_AWDL) { - awdl_stats = &dhd->awdl_stats[dhd->awdl_tx_status_slot]; - DHD_AWDL_STATS_LOCK(dhd->awdl_stats_lock, awdl_stats_lock_flags); - awdl_stats->cum_tx_status_latency += tx_status_latency; - awdl_stats->num_tx_status++; - DHD_AWDL_STATS_UNLOCK(dhd->awdl_stats_lock, awdl_stats_lock_flags); - } -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ - -#ifdef HOST_SFH_LLC - if (dhd->host_sfhllc_supported) { - struct ether_header eth; - if (!memcpy_s(ð, sizeof(eth), - PKTDATA(dhd->osh, pkt), sizeof(eth))) { - if (dhd_8023_llc_to_ether_hdr(dhd->osh, - ð, pkt) != BCME_OK) { - DHD_ERROR_RLMT(("%s: host sfh llc" - " converstion to ether failed\n", - __FUNCTION__)); - } - } - } -#endif /* HOST_SFH_LLC */ #ifdef DMAMAP_STATS dhd->dma_stats.txdata--; @@ -8100,102 +7637,16 @@ BCMFASTPATH(dhd_prot_txstatus_process)(dhd_pub_t *dhd, void *msg) WLFC_CTL_PKTFLAG_MASK; dhd_handle_pktdata(dhd, ltoh32(txstatus->cmn_hdr.if_id), pkt, (uint8 *)PKTDATA(dhd->osh, pkt), pktid, len, - &status, NULL, TRUE, FALSE, TRUE); + &status, NULL, NULL, TRUE, FALSE, TRUE); } #endif /* DHD_PKT_LOGGING */ -#if defined(BCMPCIE) && (defined(LINUX) || defined(OEM_ANDROID) || defined(DHD_EFI)) +#if defined(BCMPCIE) && (defined(LINUX) || defined(OEM_ANDROID)) dhd_txcomplete(dhd, pkt, pkt_fate); #ifdef DHD_4WAYM4_FAIL_DISCONNECT dhd_eap_txcomplete(dhd, pkt, pkt_fate, txstatus->cmn_hdr.if_id); #endif /* DHD_4WAYM4_FAIL_DISCONNECT */ #endif /* BCMPCIE && (defined(LINUX) || defined(OEM_ANDROID)) */ -#ifdef DHD_PKTTS - if (dhd_get_pktts_enab(dhd) == TRUE) { - if (dhd->pkt_metadata_buflen) { - /* firmware mark tx_pktts.tref with 0xFFFFFFFF for errors */ - if ((dhd->pkt_metadata_version == METADATA_VER_1) && - (ltoh32(meta_ts_v1.tref) != 0xFFFFFFFF)) { - struct pktts_fwtx_v1 fwts; - fwts.ts[0] = (uint32)htonl(ltoh32(meta_ts_v1.tref)); - fwts.ts[1] = (uint32)htonl(ltoh32(meta_ts_v1.tref) + - ltoh16(meta_ts_v1.d_t2)); - fwts.ts[2] = (uint32)htonl(ltoh32(meta_ts_v1.tref) + - ltoh16(meta_ts_v1.d_t3)); - fwts.ts[3] = (uint32)htonl(ltoh32(meta_ts_v1.tref) + - ltoh16(meta_ts_v1.d_t4)); - /* check for overflow */ - if (ntohl(fwts.ts[3]) > ntohl(fwts.ts[0])) { - /* send tx timestamp to netlink socket */ - dhd_msgbuf_send_msg_tx_ts(dhd, pkt, &fwts, - dhd->pkt_metadata_version); - } - } else if ((dhd->pkt_metadata_version == METADATA_VER_2) && - (ltoh32(meta_ts_v2.tref) != 0xFFFFFFFF)) { - struct pktts_fwtx_v2 fwts; - fwts.ts[0] = (uint32)htonl(ltoh32(meta_ts_v2.tref)); - fwts.ts[1] = (uint32)htonl(ltoh32(meta_ts_v2.tref) + - ltoh16(meta_ts_v2.d_t2)); - fwts.ts[2] = (uint32)htonl(ltoh32(meta_ts_v2.tref) + - ltoh16(meta_ts_v2.d_t3)); - fwts.ts[3] = (uint32)htonl(ltoh32(meta_ts_v2.tref) + - ltoh16(meta_ts_v2.d_t4)); - - fwts.ut[0] = (uint32)htonl(ltoh32(meta_ts_v2.tref) + - ltoh16(meta_ts_v2.u_t1)); - fwts.ut[1] = (uint32)htonl(ltoh16(meta_ts_v2.u_t2)); - fwts.ut[2] = (uint32)htonl(ltoh16(meta_ts_v2.u_t3)); - fwts.ut[3] = (uint32)htonl(ltoh16(meta_ts_v2.u_t4)); - fwts.ut[4] = (uint32)htonl(ltoh32(meta_ts_v2.tref) + - ltoh16(meta_ts_v2.u_t5)); - - fwts.uc[0] = (uint32)htonl(ltoh32(meta_ts_v2.u_c1)); - fwts.uc[1] = (uint32)htonl(ltoh32(meta_ts_v2.u_c2)); - fwts.uc[2] = (uint32)htonl(ltoh32(meta_ts_v2.u_c3)); - fwts.uc[3] = (uint32)htonl(ltoh32(meta_ts_v2.u_c4)); - fwts.uc[4] = (uint32)htonl(ltoh32(meta_ts_v2.u_c5)); - fwts.uc[5] = (uint32)htonl(ltoh32(meta_ts_v2.u_c6)); - fwts.uc[6] = (uint32)htonl(ltoh32(meta_ts_v2.u_c7)); - fwts.uc[7] = (uint32)htonl(ltoh32(meta_ts_v2.u_c8)); - - DHD_INFO(("uct1:%x uct2:%x uct3:%x uct4:%x uct5:%x\n", - ntohl(fwts.ut[0]), ntohl(fwts.ut[1]), ntohl(fwts.ut[2]), - ntohl(fwts.ut[3]), ntohl(fwts.ut[4]))); - DHD_INFO(("ucc1:%x ucc2:%x ucc3:%x ucc4:%x" - " ucc5:%x ucc6:%x ucc7:%x ucc8:%x\n", - ntohl(fwts.uc[0]), ntohl(fwts.uc[1]), ntohl(fwts.uc[2]), - ntohl(fwts.uc[3]), ntohl(fwts.uc[4]), ntohl(fwts.uc[5]), - ntohl(fwts.uc[6]), ntohl(fwts.uc[7]))); - /* check for overflow */ - if (ntohl(fwts.ts[3]) > ntohl(fwts.ts[0])) { - /* send tx timestamp to netlink socket */ - dhd_msgbuf_send_msg_tx_ts(dhd, pkt, &fwts, - dhd->pkt_metadata_version); - } - } - } else { - /* firmware mark tx_pktts.tref with 0xFFFFFFFF for errors */ - if (ltoh32(txstatus->tx_pktts.tref) != 0xFFFFFFFF) { - struct pktts_fwtx_v1 fwts; - - fwts.ts[0] = (uint32)htonl(ltoh32(txstatus->tx_pktts.tref)); - fwts.ts[1] = (uint32)htonl(ltoh32(txstatus->tx_pktts.tref) + - ltoh16(txstatus->tx_pktts.d_t2)); - fwts.ts[2] = (uint32)htonl(ltoh32(txstatus->tx_pktts.tref) + - ltoh16(txstatus->tx_pktts.d_t3)); - fwts.ts[3] = (uint32)htonl(ltoh32(txstatus->tx_pktts.tref) + - ltoh16(txstatus->compl_hdr.tx_pktts.d_t4)); - - /* check for overflow */ - if (ntohl(fwts.ts[3]) > ntohl(fwts.ts[0])) { - /* send tx timestamp to netlnik socket */ - dhd_msgbuf_send_msg_tx_ts(dhd, pkt, &fwts, METADATA_VER_1); - } - } - } - } -#endif /* DHD_PKTTS */ - #if DHD_DBG_SHOW_METADATA if (dhd->prot->metadata_dbg && dhd->prot->tx_metadata_offset && txstatus->metadata_len) { @@ -8210,30 +7661,27 @@ BCMFASTPATH(dhd_prot_txstatus_process)(dhd_pub_t *dhd, void *msg) } #endif /* DHD_DBG_SHOW_METADATA */ -#ifdef DHD_HP2P - if (dhd->hp2p_capable && flow_ring_node->flow_info.tid == HP2P_PRIO) { -#ifdef DHD_HP2P_DEBUG - bcm_print_bytes("txcpl", (uint8 *)txstatus, sizeof(host_txbuf_cmpl_t)); -#endif /* DHD_HP2P_DEBUG */ - dhd_update_hp2p_txstats(dhd, txstatus); + /* Store PTM timestamps */ + ts = (ts_timestamp_t *)&txstatus->ts; + bzero(&txcpl_info->tx_history[txcpl_info->txcpl_hist_count], + sizeof(tx_cpl_history_t)); + if (DHD_PTM_CLKID(ts->high)) { + txcpl_info->tx_history[txcpl_info->txcpl_hist_count].ptm_high = ts->high; + txcpl_info->tx_history[txcpl_info->txcpl_hist_count].ptm_low = ts->low; } -#endif /* DHD_HP2P */ - -#ifdef DHD_TIMESYNC - if (dhd->prot->tx_ts_log_enabled) { - dhd_pkt_parse_t parse; - ts_timestamp_t *ts = (ts_timestamp_t *)&(txstatus->ts); - - memset(&parse, 0, sizeof(parse)); - dhd_parse_proto(PKTDATA(dhd->osh, pkt), &parse); - - if (parse.proto == IP_PROT_ICMP) - dhd_timesync_log_tx_timestamp(dhd->ts, - txstatus->compl_hdr.flow_ring_id, - txstatus->cmn_hdr.if_id, - ts->low, ts->high, &parse); + /* Tx Latency for successful xmission of non HPP packet */ + if ((txstatus->tx_status == 0) && + (ring == &dhd->prot->d2hring_tx_cpln)) { + txcpl_info->tx_history[txcpl_info->txcpl_hist_count].latency = + txstatus->metadata_len & BCMPCIE_TX_PKT_LATENCY_MASK; } -#endif /* DHD_TIMESYNC */ + txcpl_info->tx_history[txcpl_info->txcpl_hist_count].host_time = + (uint32)OSL_SYSUPTIME_US(); + txcpl_info->tx_history[txcpl_info->txcpl_hist_count].tid = + flow_ring_node->flow_info.tid; + txcpl_info->tx_history[txcpl_info->txcpl_hist_count].flowid = flowid; + txcpl_info->txcpl_hist_count = + (txcpl_info->txcpl_hist_count +1) % MAX_TXCPL_HISTORY; #ifdef DHD_LBUF_AUDIT PKTAUDIT(dhd->osh, pkt); @@ -8241,15 +7689,9 @@ BCMFASTPATH(dhd_prot_txstatus_process)(dhd_pub_t *dhd, void *msg) DHD_FLOWRING_TXSTATUS_CNT_UPDATE(dhd->bus, txstatus->compl_hdr.flow_ring_id, txstatus->tx_status); DHD_RING_UNLOCK(ring->ring_lock, flags); -#ifdef DHD_PKTTS - if (meta_data_buf.va) { - DMA_FREE_CONSISTENT(dhd->osh, meta_data_buf.va, meta_data_buf._alloced, - meta_data_buf.pa, meta_data_buf.dmah); - } -#endif /* DHD_PKTTS */ #ifdef DHD_MEM_STATS DHD_MEM_STATS_LOCK(dhd->mem_stats_lock, flags); - DHD_MSGBUF_INFO(("%s txpath_mem: %llu PKTLEN: %d\n", + DHD_INFO(("%s txpath_mem: %llu PKTLEN: %d\n", __FUNCTION__, dhd->txpath_mem, PKTLEN(dhd->osh, pkt))); dhd->txpath_mem -= PKTLEN(dhd->osh, pkt); DHD_MEM_STATS_UNLOCK(dhd->mem_stats_lock, flags); @@ -8276,13 +7718,19 @@ dhd_prot_event_process(dhd_pub_t *dhd, void *msg) bufid = ltoh32(evnt->cmn_hdr.request_id); #if defined(DHD_PKTID_AUDIT_RING) && !defined(BCM_ROUTER_DHD) - DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_ctrl_map, bufid, - DHD_DUPLICATE_FREE, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); + if (DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_ctrl_map, bufid, + DHD_DUPLICATE_FREE, msg, D2HRING_CTRL_CMPLT_ITEMSIZE) != BCME_OK) { + return; + } #endif /* DHD_PKTID_AUDIT_RING && !BCM_ROUTER_DHD */ buflen = ltoh16(evnt->event_data_len); ifidx = BCMMSGBUF_API_IFIDX(&evnt->cmn_hdr); + if (evnt->cmn_hdr.flags & BCMPCIE_CMNHDR_FLAGS_WAKE_PACKET) { + DHD_ERROR(("%s:Event: Wakeup Packet received\n", __FUNCTION__)); + prot->event_wakeup_pkt ++; + } /* FIXME: check the event status */ /* Post another rxbuf to the device */ @@ -8326,11 +7774,13 @@ BCMFASTPATH(dhd_prot_process_infobuf_complete)(dhd_pub_t *dhd, void* buf) buflen = ltoh16(resp->info_data_len); #ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_ctrl_map, pktid, - DHD_DUPLICATE_FREE, buf, D2HRING_INFO_BUFCMPLT_ITEMSIZE); + if (DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_ctrl_map, pktid, + DHD_DUPLICATE_FREE, buf, D2HRING_INFO_BUFCMPLT_ITEMSIZE) != BCME_OK) { + return; + } #endif /* DHD_PKTID_AUDIT_RING */ - DHD_MSGBUF_INFO(("id 0x%04x, len %d, phase 0x%02x, seqnum %d, rx_dataoffset %d\n", + DHD_INFO(("id 0x%04x, len %d, phase 0x%02x, seqnum %d, rx_dataoffset %d\n", pktid, buflen, resp->cmn_hdr.flags, ltoh16(resp->seqnum), dhd->prot->rx_dataoffset)); @@ -8339,6 +7789,10 @@ BCMFASTPATH(dhd_prot_process_infobuf_complete)(dhd_pub_t *dhd, void* buf) dhd->debug_buf_dest_stat[resp->dest]++; } } + if (resp->cmn_hdr.flags & BCMPCIE_CMNHDR_FLAGS_WAKE_PACKET) { + DHD_ERROR(("%s:Infobuf: Wakeup Packet received\n", __FUNCTION__)); + dhd->prot->info_wakeup_pkt ++; + } pkt = dhd_prot_packet_get(dhd, pktid, PKTTYPE_INFO_RX, TRUE); if (!pkt) @@ -8367,90 +7821,8 @@ BCMFASTPATH(dhd_prot_process_infobuf_complete)(dhd_pub_t *dhd, void* buf) static void BCMFASTPATH(dhd_prot_process_snapshot_complete)(dhd_pub_t *dhd, void *buf) { -#ifdef SNAPSHOT_UPLOAD - dhd_prot_t *prot = dhd->prot; - snapshot_resp_t *resp; - uint16 status; - - resp = (snapshot_resp_t *)buf; - - /* check completion status */ - status = resp->compl_hdr.status; - if (status != BCMPCIE_SUCCESS) { - DHD_ERROR(("%s: failed: %s (%d)\n", - __FUNCTION__, - status == BCMPCIE_BT_DMA_ERR ? "DMA_ERR" : - status == BCMPCIE_BT_DMA_DESCR_FETCH_ERR ? - "DMA_DESCR_ERR" : - status == BCMPCIE_SNAPSHOT_ERR ? "SNAPSHOT_ERR" : - status == BCMPCIE_NOT_READY ? "NOT_READY" : - status == BCMPCIE_INVALID_DATA ? "INVALID_DATA" : - status == BCMPCIE_NO_RESPONSE ? "NO_RESPONSE" : - status == BCMPCIE_NO_CLOCK ? "NO_CLOCK" : - "", status)); - } - - /* length may be truncated if error occurred */ - prot->snapshot_upload_len = ltoh32(resp->resp_len); - prot->snapshot_type = resp->type; - prot->snapshot_cmpl_pending = FALSE; - - DHD_INFO(("%s id 0x%04x, phase 0x%02x, resp_len %d, type %d\n", - __FUNCTION__, ltoh32(resp->cmn_hdr.request_id), - resp->cmn_hdr.flags, - prot->snapshot_upload_len, prot->snapshot_type)); -#endif /* SNAPSHOT_UPLOAD */ } -#ifdef BTLOG -/** called on MSG_TYPE_BT_LOG_CMPLT message received from dongle */ -static void -BCMFASTPATH(dhd_prot_process_btlog_complete)(dhd_pub_t *dhd, void* buf) -{ - info_buf_resp_t *resp; - uint32 pktid; - uint16 buflen; - void * pkt; - - resp = (info_buf_resp_t *)buf; - pktid = ltoh32(resp->cmn_hdr.request_id); - buflen = ltoh16(resp->info_data_len); - - /* check completion status */ - if (resp->compl_hdr.status != BCMPCIE_SUCCESS) { - DHD_ERROR(("%s: failed completion status %d\n", - __FUNCTION__, resp->compl_hdr.status)); - return; - } - -#ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_ctrl_map, pktid, - DHD_DUPLICATE_FREE, buf, D2HRING_INFO_BUFCMPLT_ITEMSIZE); -#endif /* DHD_PKTID_AUDIT_RING */ - - DHD_INFO(("id 0x%04x, len %d, phase 0x%02x, seqnum %d, rx_dataoffset %d\n", - pktid, buflen, resp->cmn_hdr.flags, ltoh16(resp->seqnum), - dhd->prot->rx_dataoffset)); - - pkt = dhd_prot_packet_get(dhd, pktid, PKTTYPE_INFO_RX, TRUE); - - if (!pkt) - return; - -#if !defined(BCM_ROUTER_DHD) - /* FIXME: make sure the length is more than dataoffset */ - /* DMA RX offset updated through shared area */ - if (dhd->prot->rx_dataoffset) - PKTPULL(dhd->osh, pkt, dhd->prot->rx_dataoffset); -#endif /* !BCM_ROUTER_DHD */ - - PKTSETLEN(dhd->osh, pkt, buflen); - PKTSETNEXT(dhd->osh, pkt, NULL); - - dhd_bus_rx_bt_log(dhd->bus, pkt); -} -#endif /* BTLOG */ - /** Stop protocol: sync w/dongle state. */ void dhd_prot_stop(dhd_pub_t *dhd) { @@ -8507,16 +7879,9 @@ BCMFASTPATH(dhd_prot_txdata)(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx) msgbuf_ring_t *ring; flow_ring_table_t *flow_ring_table; flow_ring_node_t *flow_ring_node; -#if defined(BCMINTERNAL) && defined(LINUX) - void *pkt_to_free = NULL; -#endif /* BCMINTERNAL && LINUX */ -#ifdef DHD_PKTTS - dhd_dma_buf_t meta_data_buf; - uint16 meta_data_buf_len = dhd->pkt_metadata_buflen; - uint64 addr = 0; -#endif /* DHD_PKTTS */ void *big_pktbuf = NULL; uint8 dhd_udr = FALSE; + uint8 dhd_igmp = FALSE; bool host_sfh_llc_reqd = dhd->host_sfhllc_supported; bool llc_inserted = FALSE; @@ -8584,35 +7949,6 @@ BCMFASTPATH(dhd_prot_txdata)(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx) * hold the pointers from Network Stack, just before putting * the PHY ADDR in the flow rings, we'll do the copy. */ -#if defined(BCMINTERNAL) && defined(LINUX) - if (osl_is_flag_set(dhd->osh, OSL_PHYS_MEM_LESS_THAN_16MB)) { - struct sk_buff *skb; - /* - * We are about to add the Ethernet header and send out, - * copy the skb here. - */ - skb = skb_copy(PKTBUF, GFP_DMA); - if (skb == NULL) { - /* - * Memory allocation failed, the old packet can - * live in the queue, return BCME_NORESOURCE so - * the caller re-queues this packet - */ - DHD_ERROR(("%s: skb_copy(DMA) failed\n", __FUNCTION__)); - goto fail; - } - - /* - * Now we have copied the SKB to GFP_DMA memory, make the - * rest of the code operate on this new SKB. Hold on to - * the original SKB. If we don't get the pkt id or flow ring - * space we'll free the Zone memory and return "no resource" - * so the caller would re-queue the original SKB. - */ - pkt_to_free = PKTBUF; - PKTBUF = skb; - } -#endif /* BCMINTERNAL && LINUX */ if (dhd->dhd_induce_error == DHD_INDUCE_TX_BIG_PKT && big_pktbuf) { PKTFREE(dhd->osh, PKTBUF, TRUE); @@ -8652,75 +7988,16 @@ BCMFASTPATH(dhd_prot_txdata)(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx) pktlen = PKTLEN(dhd->osh, PKTBUF); /* TODO: XXX: re-look into dropped packets */ - DHD_DBG_PKT_MON_TX(dhd, PKTBUF, pktid); + DHD_DBG_PKT_MON_TX(dhd, PKTBUF, pktid, FRAME_TYPE_ETHERNET_II, 0); dhd_handle_pktdata(dhd, ifidx, PKTBUF, pktdata, pktid, - pktlen, NULL, &dhd_udr, TRUE, FALSE, TRUE); - -#if defined(BCMINTERNAL) && defined(LINUX) - /* - * We have got all the resources, pktid and ring space - * so we can safely free the original SKB here. - */ - if (osl_is_flag_set(dhd->osh, OSL_PHYS_MEM_LESS_THAN_16MB)) - PKTCFREE(dhd->osh, pkt_to_free, FALSE); -#endif /* BCMINTERNAL && LINUX */ + pktlen, NULL, &dhd_udr, &dhd_igmp, TRUE, FALSE, TRUE); /* Ethernet header - contains ethertype field * Copy before we cache flush packet using DMA_MAP */ bcopy(pktdata, txdesc->txhdr, ETHER_HDR_LEN); -#ifdef DHD_AWDL - /* the awdl ifidx will always have a non-zero value - * if the awdl iface is created. This is because the - * primary iface (usually eth1) will always have ifidx of 0. - * Hence we can check for non-zero value of awdl ifidx to - * see if awdl iface is created or not - */ - if (dhd->awdl_llc_enabled && - dhd->awdl_ifidx && ifidx == dhd->awdl_ifidx) { - if (host_sfh_llc_reqd) { - /* if FW supports host sfh llc insertion - * then BOTH sfh and llc needs to be inserted - * in which case the host LLC only path - * in FW will not be exercised - which is the - * objective of this feature. Hence in such a - * case disable awdl llc insertion - */ - DHD_ERROR_RLMT(("%s: FW supports host sfh + llc, this is" - "is incompatible with awdl llc insertion" - " disable host sfh llc support in FW and try\n", - __FUNCTION__)); - } else { - if (dhd_ether_to_awdl_llc_hdr(dhd, (struct ether_header *)pktdata, - PKTBUF) == BCME_OK) { - llc_inserted = TRUE; - /* in work item change ether type to len by - * re-copying the ether header - */ - memcpy_s(txdesc->txhdr, ETHER_HDR_LEN, PKTDATA(dhd->osh, PKTBUF), - ETHER_HDR_LEN); - } else { - goto err_rollback_idx; - } - } - } -#endif /* DHD_AWDL */ - -#ifdef HOST_SFH_LLC - if (host_sfh_llc_reqd) { - if (dhd_ether_to_8023_hdr(dhd->osh, (struct ether_header *)pktdata, - PKTBUF) == BCME_OK) { - /* adjust the data pointer and length information */ - pktdata = PKTDATA(dhd->osh, PKTBUF); - pktlen = PKTLEN(dhd->osh, PKTBUF); - txdesc->flags |= BCMPCIE_TXPOST_FLAGS_HOST_SFH_LLC; - } else { - goto err_rollback_idx; - } - } else -#endif /* HOST_SFH_LLC */ { /* Extract the ethernet header and adjust the data pointer and length */ pktlen = PKTLEN(dhd->osh, PKTBUF) - ETHER_HDR_LEN; @@ -8767,8 +8044,16 @@ BCMFASTPATH(dhd_prot_txdata)(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx) dhd->prot->hmaptest_tx_active = HMAPTEST_D11_TX_INACTIVE; dhd->prot->hmaptest.in_progress = FALSE; } else { + int ret = 0; /* copy pktdata to our va */ - memcpy(dhd->prot->hmap_tx_buf_va, PKTDATA(dhd->osh, PKTBUF), pktlen); + ret = memcpy_s(dhd->prot->hmap_tx_buf_va, dhd->prot->hmap_tx_buf_len, + PKTDATA(dhd->osh, PKTBUF), pktlen); + if (ret) { + DHD_ERROR(("memcpy hmap_tx_buf_va failed:%d, destsz:%d, n:%d\n", + ret, dhd->prot->hmap_tx_buf_len, pktlen)); + ASSERT(0); + goto err_rollback_idx; + } pa = DMA_MAP(dhd->osh, dhd->prot->hmap_tx_buf_va, dhd->prot->hmap_tx_buf_len, DMA_TX, PKTBUF, 0); @@ -8783,36 +8068,6 @@ BCMFASTPATH(dhd_prot_txdata)(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx) } #endif /* DHD_HMAPTEST */ -#ifdef DHD_PKTTS - memset(&meta_data_buf, 0, sizeof(meta_data_buf)); - if (dhd_get_pktts_enab(dhd) && - dhd->pkt_metadata_buflen) { - /* Allocate memory for Meta data */ - meta_data_buf.va = DMA_ALLOC_CONSISTENT(dhd->osh, meta_data_buf_len, - DMA_ALIGN_LEN, &meta_data_buf._alloced, - &meta_data_buf.pa, &meta_data_buf.dmah); - - if (meta_data_buf.va == NULL) { - DHD_ERROR_RLMT(("%s: dhd_dma_buf_alloc failed \r\n", __FUNCTION__)); - DHD_ERROR_RLMT((" ... Proceeding without metadata buffer \r\n")); - } else { - DHD_PKTID_SAVE_METADATA(dhd, dhd->prot->pktid_tx_map, - (void *)meta_data_buf.va, - meta_data_buf.pa, - (uint16)meta_data_buf._alloced, - meta_data_buf.dmah, - pktid); - } - memcpy(&addr, &meta_data_buf.pa, sizeof(meta_data_buf.pa)); - DHD_TRACE(("Meta data Buffer VA: %p PA: %llx dmah: %p\r\n", - meta_data_buf.va, addr, meta_data_buf.dmah)); - - txdesc->metadata_buf_addr.low = addr & (0xFFFFFFFF); - txdesc->metadata_buf_addr.high = (addr >> 32) & (0xFFFFFFFF); - txdesc->metadata_buf_len = meta_data_buf_len; - } -#endif /* DHD_PKTTS */ - /* Form the Tx descriptor message buffer */ /* Common message hdr */ @@ -8846,31 +8101,16 @@ BCMFASTPATH(dhd_prot_txdata)(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx) txdesc->ext_flags = 0; -#ifdef DHD_TIMESYNC - txdesc->rate = 0; - - if (!llc_inserted && dhd->prot->tx_ts_log_enabled) { - dhd_pkt_parse_t parse; - - dhd_parse_proto(PKTDATA(dhd->osh, PKTBUF), &parse); - - if (parse.proto == IP_PROT_ICMP) { - if (dhd->prot->no_retry) - txdesc->ext_flags = BCMPCIE_PKT_FLAGS_FRAME_NORETRY; - if (dhd->prot->no_aggr) - txdesc->ext_flags |= BCMPCIE_PKT_FLAGS_FRAME_NOAGGR; - if (dhd->prot->fixed_rate) - txdesc->ext_flags |= BCMPCIE_PKT_FLAGS_FRAME_UDR; - } - } -#endif /* DHD_TIMESYNC */ - #ifdef DHD_SBN if (dhd_udr) { txdesc->ext_flags |= BCMPCIE_PKT_FLAGS_FRAME_UDR; } #endif /* DHD_SBN */ + if (dhd_igmp) { + txdesc->ext_flags |= BCMPCIE_PKT_FLAGS_IGMP; + } + #ifdef DHD_TX_PROFILE if (!llc_inserted && dhd->tx_profile_enab && dhd->num_profiles > 0) @@ -8934,16 +8174,7 @@ BCMFASTPATH(dhd_prot_txdata)(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx) txdesc->metadata_buf_addr.high_addr = htol32(PHYSADDRHI(meta_pa)); txdesc->metadata_buf_addr.low_addr = htol32(PHYSADDRLO(meta_pa)); } else { -#ifdef DHD_HP2P - if (dhd->hp2p_capable && flow_ring_node->flow_info.tid == HP2P_PRIO) { - dhd_update_hp2p_txdesc(dhd, txdesc); - } else -#endif /* DHD_HP2P */ -#ifdef DHD_PKTTS - if (!dhd_get_pktts_enab(dhd) || !dhd->pkt_metadata_buflen) { -#else if (1) { -#endif /* DHD_PKTTS */ txdesc->metadata_buf_len = htol16(0); txdesc->metadata_buf_addr.high_addr = 0; txdesc->metadata_buf_addr.low_addr = 0; @@ -8969,11 +8200,6 @@ BCMFASTPATH(dhd_prot_txdata)(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx) /* Update the write pointer in TCM & ring bell */ #if defined(TXP_FLUSH_NITEMS) -#if defined(DHD_HP2P) - if (dhd->hp2p_capable && flow_ring_node->flow_info.tid == HP2P_PRIO) { - dhd_calc_hp2p_burst(dhd, ring, flowid); - } else -#endif /* HP2P */ { if ((ring->pend_items_count == prot->txp_threshold) || ((uint8 *) txdesc == (uint8 *) DHD_RING_END_VA(ring))) { @@ -8999,11 +8225,6 @@ BCMFASTPATH(dhd_prot_txdata)(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx) #ifdef TX_STATUS_LATENCY_STATS /* set the time when pkt is queued to flowring */ DHD_PKT_SET_QTIME(PKTBUF, OSL_SYSUPTIME_US()); -#elif defined(DHD_PKTTS) - if (dhd_get_pktts_enab(dhd) == TRUE) { - /* set the time when pkt is queued to flowring */ - DHD_PKT_SET_QTIME(PKTBUF, OSL_SYSUPTIME_US()); - } #endif /* TX_STATUS_LATENCY_STATS */ DHD_RING_UNLOCK(ring->ring_lock, flags); @@ -9050,11 +8271,6 @@ err_free_pktid: err_no_res_pktfree: #endif /* DHD_PCIE_PKTID */ -#if defined(BCMINTERNAL) && defined(LINUX) - if (osl_is_flag_set(dhd->osh, OSL_PHYS_MEM_LESS_THAN_16MB)) - PKTCFREE(dhd->osh, PKTBUF, FALSE); -#endif /* BCMINTERNAL && LINUX */ - DHD_RING_UNLOCK(ring->ring_lock, flags); fail: @@ -9145,7 +8361,7 @@ BCMFASTPATH(dhd_prot_return_rxbuf)(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint32 p prot->rxbufpost = 0; } - if (prot->rxbufpost <= (prot->max_rxbufpost - RXBUFPOST_THRESHOLD)) { + if (prot->rxbufpost <= (prot->max_rxbufpost - prot->rx_bufpost_threshold)) { dhd_msgbuf_rxbuf_post(dhd, FALSE); /* alloc pkt ids */ } else if (dhd->dma_h2d_ring_upd_support && !IDMA_ACTIVE(dhd)) { /* Ring DoorBell after processing the rx packets, @@ -9568,65 +8784,6 @@ dhd_prot_wl_ioctl_ret_intercept(dhd_pub_t *dhd, wl_ioctl_t * ioc, void * buf, dhd->wme_dp = (uint8) ltoh32(val); } -#ifdef DHD_AWDL - /* Intercept the awdl_peer_op ioctl here */ - if (!strcmp(buf, "awdl_peer_op")) { - slen = strlen("awdl_peer_op") + 1; - dhd_awdl_peer_op(dhd, (uint8)ifidx, ((char *)buf + slen), len - slen); - } - /* Intercept the awdl ioctl here, delete flow rings if awdl is - * disabled - */ - if (!strcmp(buf, "awdl")) { - int val = 0; - slen = strlen("awdl") + 1; - if (len >= (int)(slen + sizeof(int))) { - bcopy(((char *)buf + slen), &val, sizeof(int)); - val = ltoh32(val); - if (val == TRUE) { - /** - * Though we are updating the link status when we recieve - * WLC_E_LINK from dongle, it is not gaurenteed always. - * So intercepting the awdl command fired from app to - * update the status. - */ - dhd_update_interface_link_status(dhd, (uint8)ifidx, TRUE); -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) - /* reset AWDL stats data structures when AWDL is enabled */ - dhd_clear_awdl_stats(dhd); -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ - } else if (val == FALSE) { - dhd_update_interface_link_status(dhd, (uint8)ifidx, FALSE); - dhd_del_all_sta(dhd, (uint8)ifidx); - dhd_awdl_peer_op(dhd, (uint8)ifidx, NULL, 0); - - } - } - - } - - /* store the awdl min extension count and presence mode values - * set by the user, same will be inserted in the LLC header for - * each tx packet on the awdl iface - */ - slen = strlen("awdl_extcounts"); - if (!strncmp(buf, "awdl_extcounts", slen)) { - awdl_extcount_t *extcnt = NULL; - slen = slen + 1; - if ((len - slen) >= sizeof(*extcnt)) { - extcnt = (awdl_extcount_t *)((char *)buf + slen); - dhd->awdl_minext = extcnt->minExt; - } - } - - slen = strlen("awdl_presencemode"); - if (!strncmp(buf, "awdl_presencemode", slen)) { - slen = slen + 1; - if ((len - slen) >= sizeof(uint8)) { - dhd->awdl_presmode = *((uint8 *)((char *)buf + slen)); - } - } -#endif /* DHD_AWDL */ } } @@ -9883,6 +9040,7 @@ int dmaxfer_prepare_dmaaddr(dhd_pub_t *dhd, uint len, } dmaxfer->len = len; + DHD_ERROR(("using pattern %d, for loopback test\n", dhd->bus->lpbk_xfer_data_pattern_type)); /* Populate source with a pattern like below * 0x00000000 @@ -9895,10 +9053,28 @@ int dmaxfer_prepare_dmaaddr(dhd_pub_t *dhd, uint len, * 0xFFFFFFFF */ while (i < dmaxfer->len) { - ((uint8*)dmaxfer->srcmem.va)[i] = j % 256; - i++; - if (i % 4 == 0) { - j++; + if (dhd->bus->lpbk_xfer_data_pattern_type == LPBK_DMA_XFER_DTPTRN_0x00) { + ((uint8*)dmaxfer->srcmem.va)[i] = 0x00; + i++; + } + else if (dhd->bus->lpbk_xfer_data_pattern_type == LPBK_DMA_XFER_DTPTRN_0xFF) { + ((uint8*)dmaxfer->srcmem.va)[i] = 0xFF; + i++; + } + else if (dhd->bus->lpbk_xfer_data_pattern_type == LPBK_DMA_XFER_DTPTRN_0x55) { + ((uint8*)dmaxfer->srcmem.va)[i] = 0x55; + i++; + } + else if (dhd->bus->lpbk_xfer_data_pattern_type == LPBK_DMA_XFER_DTPTRN_0xAA) { + ((uint8*)dmaxfer->srcmem.va)[i] = 0xAA; + i++; + } + else { + ((uint8*)dmaxfer->srcmem.va)[i] = j % 256; + i++; + if (i % 4 == 0) { + j++; + } } } @@ -9922,11 +9098,6 @@ dhd_msgbuf_dmaxfer_process(dhd_pub_t *dhd, void *msg) BCM_REFERENCE(cmplt); end_usec = OSL_SYSUPTIME_US(); -#if defined(DHD_EFI) && defined(DHD_INTR_POLL_PERIOD_DYNAMIC) - /* restore interrupt poll period to the previous existing value */ - dhd_os_set_intr_poll_period(dhd->bus, dhd->cur_intr_poll_period); -#endif /* DHD_EFI && DHD_INTR_POLL_PERIOD_DYNAMIC */ - DHD_ERROR(("DMA loopback status: %d\n", cmplt->compl_hdr.status)); prot->dmaxfer.status = cmplt->compl_hdr.status; OSL_CACHE_INV(prot->dmaxfer.dstmem.va, prot->dmaxfer.len); @@ -10244,18 +9415,41 @@ done: return ret; } +static void +dhd_msgbuf_dump_iovar_name(dhd_pub_t *dhd) +{ + dhd_prot_t *prot = dhd->prot; + dhd->rxcnt_timeout++; + dhd->rx_ctlerrs++; + DHD_ERROR(("%s: resumed on timeout rxcnt_timeout %d ioctl_cmd %d " + "trans_id %d state %d busstate=%d ioctl_received=%d\n", __FUNCTION__, + dhd->rxcnt_timeout, prot->curr_ioctl_cmd, prot->ioctl_trans_id, + prot->ioctl_state, dhd->busstate, prot->ioctl_received)); + + if (prot->curr_ioctl_cmd == WLC_SET_VAR || + prot->curr_ioctl_cmd == WLC_GET_VAR) { + char iovbuf[32]; + int dump_size = 128; + uint8 *ioctl_buf = (uint8 *)prot->ioctbuf.va; + memset(iovbuf, 0, sizeof(iovbuf)); + strncpy(iovbuf, ioctl_buf, sizeof(iovbuf) - 1); + iovbuf[sizeof(iovbuf) - 1] = '\0'; + DHD_ERROR(("Current IOVAR (%s): %s\n", + prot->curr_ioctl_cmd == WLC_SET_VAR ? + "WLC_SET_VAR" : "WLC_GET_VAR", iovbuf)); + DHD_ERROR(("========== START IOCTL REQBUF DUMP ==========\n")); + dhd_prhex(NULL, ioctl_buf, dump_size, DHD_ERROR_VAL); + DHD_ERROR(("========== END IOCTL REQBUF DUMP ==========\n")); + } +} + void dhd_msgbuf_iovar_timeout_dump(dhd_pub_t *dhd) { uint32 intstatus; - dhd_prot_t *prot = dhd->prot; - dhd->rxcnt_timeout++; - dhd->rx_ctlerrs++; - DHD_ERROR(("%s: resumed on timeout rxcnt_timeout%s %d ioctl_cmd %d " - "trans_id %d state %d busstate=%d ioctl_received=%d\n", __FUNCTION__, - dhd->is_sched_error ? " due to scheduling problem" : "", - dhd->rxcnt_timeout, prot->curr_ioctl_cmd, prot->ioctl_trans_id, - prot->ioctl_state, dhd->busstate, prot->ioctl_received)); + if (dhd->is_sched_error) { + DHD_ERROR(("%s: ROT due to scheduling problem\n", __FUNCTION__)); + } #if defined(DHD_KERNEL_SCHED_DEBUG) && defined(DHD_FW_COREDUMP) /* XXX DHD triggers Kernel panic if the resumed on timeout occurrs * due to tasklet or workqueue scheduling problems in the Linux Kernel. @@ -10274,22 +9468,6 @@ dhd_msgbuf_iovar_timeout_dump(dhd_pub_t *dhd) } #endif /* DHD_KERNEL_SCHED_DEBUG && DHD_FW_COREDUMP */ - if (prot->curr_ioctl_cmd == WLC_SET_VAR || - prot->curr_ioctl_cmd == WLC_GET_VAR) { - char iovbuf[32]; - int dump_size = 128; - uint8 *ioctl_buf = (uint8 *)prot->ioctbuf.va; - memset(iovbuf, 0, sizeof(iovbuf)); - strncpy(iovbuf, ioctl_buf, sizeof(iovbuf) - 1); - iovbuf[sizeof(iovbuf) - 1] = '\0'; - DHD_ERROR(("Current IOVAR (%s): %s\n", - prot->curr_ioctl_cmd == WLC_SET_VAR ? - "WLC_SET_VAR" : "WLC_GET_VAR", iovbuf)); - DHD_ERROR(("========== START IOCTL REQBUF DUMP ==========\n")); - prhex("ioctl_buf", (const u8 *) ioctl_buf, dump_size); - DHD_ERROR(("\n========== END IOCTL REQBUF DUMP ==========\n")); - } - /* Check the PCIe link status by reading intstatus register */ intstatus = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, dhd->bus->pcie_mailbox_int, 0, 0); @@ -10302,6 +9480,7 @@ dhd_msgbuf_iovar_timeout_dump(dhd_pub_t *dhd) dhd_prot_debug_info_print(dhd); } +extern void dhd_validate_pcie_link_cbp_wlbp(dhd_bus_t *bus); /** * Waits for IOCTL completion message from the dongle, copies this into caller * provided parameter 'buf'. @@ -10323,17 +9502,12 @@ dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf) } #ifdef GDB_PROXY /* Loop while timeout is caused by firmware stop in GDB */ - { - uint32 prev_stop_count; - do { - prev_stop_count = dhd->gdb_proxy_stop_count; + GDB_PROXY_TIMEOUT_DO(dhd) { timeleft = dhd_os_ioctl_resp_wait(dhd, (uint *)&prot->ioctl_received); - } while ((timeleft == 0) && ((dhd->gdb_proxy_stop_count != prev_stop_count) || - (dhd->gdb_proxy_stop_count & GDB_PROXY_STOP_MASK))); - } -#else + } GDB_PROXY_TIMEOUT_WHILE(timeleft == 0); +#else /* GDB_PROXY */ timeleft = dhd_os_ioctl_resp_wait(dhd, (uint *)&prot->ioctl_received); -#endif /* GDB_PROXY */ +#endif /* else GDB_PROXY */ #ifdef DHD_RECOVER_TIMEOUT if (prot->ioctl_received == 0) { @@ -10342,15 +9516,21 @@ dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf) int host_irq_disbled = dhdpcie_irq_disabled(dhd->bus); if ((intstatus) && (intstatus != (uint32)-1) && (timeleft == 0) && (!dhd_query_bus_erros(dhd))) { - DHD_ERROR(("%s: iovar timeout trying again intstatus=%x" + DHD_ERROR(("%s: resumed on timeout for IOVAR happened. intstatus=%x" " host_irq_disabled=%d\n", __FUNCTION__, intstatus, host_irq_disbled)); dhd_pcie_intr_count_dump(dhd); dhd_print_tasklet_status(dhd); - dhd_prot_process_ctrlbuf(dhd); - timeleft = dhd_os_ioctl_resp_wait(dhd, (uint *)&prot->ioctl_received); + dhd_prot_ctrl_info_print(dhd); /* Clear Interrupts */ dhdpcie_bus_clear_intstatus(dhd->bus); + if (dhd_prot_check_pending_ctrl_cmpls(dhd)) { + DHD_ERROR(("##### %s: iovar timeout trying again #####\n", + __FUNCTION__)); + dhd_schedule_delayed_dpc_on_dpc_cpu(dhd, 0); + timeleft = dhd_os_ioctl_resp_wait(dhd, + (uint *)&prot->ioctl_received); + } } } #endif /* DHD_RECOVER_TIMEOUT */ @@ -10376,18 +9556,23 @@ dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf) cnt = 0; } - if (timeleft == 0 && (!dhd_query_bus_erros(dhd))) { + if (timeleft == 0 && (!dhd->dongle_trap_data) && (!dhd_query_bus_erros(dhd))) { + /* Dump iovar name */ + dhd_msgbuf_dump_iovar_name(dhd); + dhd_validate_pcie_link_cbp_wlbp(dhd->bus); + if (dhd->bus->link_state != DHD_PCIE_ALL_GOOD) { + DHD_ERROR(("%s: bus->link_state:%d\n", + __FUNCTION__, dhd->bus->link_state)); + ret = -EREMOTEIO; + goto out; + } + if (dhd->check_trap_rot) { /* check dongle trap first */ DHD_ERROR(("Check dongle trap in the case of iovar timeout\n")); dhd_bus_checkdied(dhd->bus, NULL, 0); if (dhd->dongle_trap_occured) { -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - dhd->bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ ret = -EREMOTEIO; goto out; } @@ -10407,27 +9592,18 @@ dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf) } #endif /* DHD_FW_COREDUMP */ -#ifdef DHD_EFI - /* - * for ioctl timeout, recovery is triggered only for EFI case, because - * in linux, dhd daemon will itself trap the FW, - * so if recovery is triggered - * then there is a race between FLR and daemon initiated trap - */ - dhd_schedule_reset(dhd); -#endif /* DHD_EFI */ - -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - dhd->bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT + dhd->alert_reason = ALERT_IOCTL_TIMEOUT; + dhd_os_send_alert_message(dhd); +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ ret = -ETIMEDOUT; goto out; } else { if (prot->ioctl_received != IOCTL_RETURN_ON_SUCCESS) { DHD_ERROR(("%s: IOCTL failure due to ioctl_received = %d\n", __FUNCTION__, prot->ioctl_received)); + DHD_ERROR(("%s: setting iovar_timeout_occured\n", __FUNCTION__)); + dhd->iovar_timeout_occured = TRUE; ret = -EINVAL; goto out; } @@ -10612,24 +9788,52 @@ static int dhd_ring_write(dhd_pub_t *dhd, msgbuf_ring_t *ring, void *file, const void *user_buf, unsigned long *file_posn) { - int ret = 0; + int ret = BCME_ERROR; if (ring == NULL) { DHD_ERROR(("%s: Ring not initialised, failed to dump ring contents\n", __FUNCTION__)); - return BCME_ERROR; + goto exit; } if (file) { + ret = dhd_os_write_file_posn(file, file_posn, &ring->max_items, + sizeof(ring->max_items)); + if (ret < 0) { + DHD_ERROR(("%s: Error writing ring max_items to file !\n", + __FUNCTION__)); + goto exit; + } + ret = dhd_os_write_file_posn(file, file_posn, &ring->item_len, + sizeof(ring->item_len)); + if (ret < 0) { + DHD_ERROR(("%s: Error writing ring length to file !\n", + __FUNCTION__)); + goto exit; + } ret = dhd_os_write_file_posn(file, file_posn, (char *)(ring->dma_buf.va), ((unsigned long)(ring->max_items) * (ring->item_len))); if (ret < 0) { DHD_ERROR(("%s: write file error !\n", __FUNCTION__)); - ret = BCME_ERROR; + goto exit; + } + } else { + ret = dhd_export_debug_data(&ring->max_items, NULL, user_buf, + sizeof(ring->max_items), (int *)file_posn); + if (ret < 0) { + goto exit; + } + ret = dhd_export_debug_data(&ring->item_len, NULL, user_buf, + sizeof(ring->item_len), (int *)file_posn); + if (ret < 0) { + goto exit; } - } else if (user_buf) { ret = dhd_export_debug_data((char *)(ring->dma_buf.va), NULL, user_buf, ((unsigned long)(ring->max_items) * (ring->item_len)), (int *)file_posn); + if (ret < 0) { + goto exit; + } } +exit: return ret; } @@ -10661,7 +9865,11 @@ int dhd_edl_ring_hdr_write(dhd_pub_t *dhd, msgbuf_ring_t *ring, void *file, cons for (; nitems < D2HRING_EDL_MAX_ITEM; nitems++, rd++) { msg_addr = (uint8 *)ring->dma_buf.va + (rd * ring->item_len); - memcpy(ptr, (char *)msg_addr, D2HRING_EDL_HDR_SIZE); + ret = memcpy_s(ptr, D2HRING_EDL_HDR_SIZE, (char *)msg_addr, ring->item_len); + if (ret) { + DHD_ERROR(("D2HRING_EDL_HDR(%d) memcpy failed:%d, destsz:%d, n:%d\n", + rd, ret, D2HRING_EDL_HDR_SIZE, ring->item_len)); + } ptr += D2HRING_EDL_HDR_SIZE; } if (file) { @@ -10686,6 +9894,55 @@ done: #endif /* EWP_EDL */ #endif /* DHD_DUMP_PCIE_RINGS */ +static void +dhd_prot_print_ring_info(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) +{ + dhd_prot_t *prot = dhd->prot; + + bcm_bprintf(strbuf, "max RX bufs to post: %d, \t posted %d \n", + dhd->prot->max_rxbufpost, dhd->prot->rxbufpost); + + bcm_bprintf(strbuf, "Total RX bufs posted: %d, \t RX cpl got %d \n", + dhd->prot->tot_rxbufpost, dhd->prot->tot_rxcpl); + + bcm_bprintf(strbuf, "Total TX packets: %lu, \t TX cpl got %lu \n", + dhd->actual_tx_pkts, dhd->tot_txcpl); + + bcm_bprintf(strbuf, + "%14s %18s %18s %17s %17s %14s %14s %10s\n", + "Type", "TRD: HLRD: HDRD", "TWR: HLWR: HDWR", "BASE(VA)", "BASE(PA)", + "WORK_ITEM_SIZE", "MAX_WORK_ITEMS", "TOTAL_SIZE"); + bcm_bprintf(strbuf, "%14s", "H2DCtrlPost"); + dhd_prot_print_flow_ring(dhd, &prot->h2dring_ctrl_subn, TRUE, strbuf, + " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); + bcm_bprintf(strbuf, "%14s", "D2HCtrlCpl"); + dhd_prot_print_flow_ring(dhd, &prot->d2hring_ctrl_cpln, FALSE, strbuf, + " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); + bcm_bprintf(strbuf, "%14s", "H2DRxPost"); + dhd_prot_print_flow_ring(dhd, &prot->h2dring_rxp_subn, TRUE, strbuf, + " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); + bcm_bprintf(strbuf, "%14s", "D2HRxCpl"); + dhd_prot_print_flow_ring(dhd, &prot->d2hring_rx_cpln, FALSE, strbuf, + " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); + bcm_bprintf(strbuf, "%14s", "D2HTxCpl"); + dhd_prot_print_flow_ring(dhd, &prot->d2hring_tx_cpln, FALSE, strbuf, + " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); + if (dhd->prot->h2dring_info_subn != NULL && dhd->prot->d2hring_info_cpln != NULL) { + bcm_bprintf(strbuf, "%14s", "H2DRingInfoSub"); + dhd_prot_print_flow_ring(dhd, prot->h2dring_info_subn, TRUE, strbuf, + " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); + bcm_bprintf(strbuf, "%14s", "D2HRingInfoCpl"); + dhd_prot_print_flow_ring(dhd, prot->d2hring_info_cpln, FALSE, strbuf, + " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); + } + if (dhd->prot->d2hring_edl != NULL) { + bcm_bprintf(strbuf, "%14s", "D2HRingEDL"); + dhd_prot_print_flow_ring(dhd, prot->d2hring_edl, FALSE, strbuf, + " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); + } + bcm_bprintf(strbuf, "\n"); +} + /** Add prot dump output to a buffer */ void dhd_prot_dump(dhd_pub_t *dhd, struct bcmstrbuf *b) { @@ -10706,28 +9963,59 @@ void dhd_prot_dump(dhd_pub_t *dhd, struct bcmstrbuf *b) dhd->dma_h2d_ring_upd_support, dhd->dma_d2h_ring_upd_support, dhd->prot->rw_index_sz); - bcm_bprintf(b, "h2d_max_txpost: %d, prot->h2d_max_txpost: %d\n", - h2d_max_txpost, dhd->prot->h2d_max_txpost); -#if defined(DHD_HTPUT_TUNABLES) - bcm_bprintf(b, "h2d_htput_max_txpost: %d, prot->h2d_htput_max_txpost: %d\n", - h2d_htput_max_txpost, dhd->prot->h2d_htput_max_txpost); -#endif /* DHD_HTPUT_TUNABLES */ - bcm_bprintf(b, "pktid_txq_start_cnt: %d\n", dhd->prot->pktid_txq_start_cnt); - bcm_bprintf(b, "pktid_txq_stop_cnt: %d\n", dhd->prot->pktid_txq_stop_cnt); - bcm_bprintf(b, "pktid_depleted_cnt: %d\n", dhd->prot->pktid_depleted_cnt); - bcm_bprintf(b, "txcpl_db_cnt: %d\n", dhd->prot->txcpl_db_cnt); #ifdef DHD_DMA_INDICES_SEQNUM bcm_bprintf(b, "host_seqnum %u dngl_seqnum %u\n", dhd_prot_read_seqnum(dhd, TRUE), dhd_prot_read_seqnum(dhd, FALSE)); #endif /* DHD_DMA_INDICES_SEQNUM */ + + dhd_prot_counters(dhd, b, FALSE, FALSE); +} + +void dhd_prot_counters(dhd_pub_t *dhd, struct bcmstrbuf *b, + bool print_ringinfo, bool print_pktidinfo) +{ + bcm_bprintf(b, "\nTX Post, doorbell(DB) stats:\n======================\n"); + + bcm_bprintf(b, "h2d_max_txpost: %d, prot->h2d_max_txpost: %d\n", + h2d_max_txpost, dhd->prot->h2d_max_txpost); + if (dhd->htput_support) { + bcm_bprintf(b, "h2d_htput_max_txpost: %d, prot->h2d_htput_max_txpost: %d\n", + h2d_htput_max_txpost, dhd->prot->h2d_htput_max_txpost); + } + bcm_bprintf(b, "pktid_txq_start_cnt: %d\n", dhd->prot->pktid_txq_start_cnt); + bcm_bprintf(b, "pktid_txq_stop_cnt: %d\n", dhd->prot->pktid_txq_stop_cnt); + bcm_bprintf(b, "pktid_depleted_cnt: %d\n", dhd->prot->pktid_depleted_cnt); + bcm_bprintf(b, "txcpl_db_cnt: %d\n", dhd->prot->txcpl_db_cnt); bcm_bprintf(b, "tx_h2d_db_cnt:%llu\n", dhd->prot->tx_h2d_db_cnt); + bcm_bprintf(b, "\n"); + #ifdef AGG_H2D_DB + bcm_bprintf(b, "Aggregated DB, workitem stats:\n======================\n"); bcm_bprintf(b, "agg_h2d_db_enab:%d agg_h2d_db_timeout:%d agg_h2d_db_inflight_thresh:%d\n", agg_h2d_db_enab, agg_h2d_db_timeout, agg_h2d_db_inflight_thresh); bcm_bprintf(b, "agg_h2d_db: timer_db_cnt:%d direct_db_cnt:%d\n", dhd->prot->agg_h2d_db_info.timer_db_cnt, dhd->prot->agg_h2d_db_info.direct_db_cnt); dhd_agg_inflight_stats_dump(dhd, b); #endif /* AGG_H2D_DB */ + bcm_bprintf(b, "\nrx_buf_burst: %d\n", dhd->prot->rx_buf_burst); + bcm_bprintf(b, "\n"); + + if (print_ringinfo) { + bcm_bprintf(b, "\nRing Info:\n=========\n"); + bcm_bprintf(b, "[RD=read ptr; WR=write ptr; T=TCM; H=Host;" + " L=Local; D=DMA index'd]\n"); + dhd_prot_print_ring_info(dhd, b); + } + + if (print_pktidinfo) { + bcm_bprintf(b, "active_tx_count %d pktidmap_avail(ctrl/rx/tx) %d %d %d\n", + OSL_ATOMIC_READ(dhd->osh, &dhd->prot->active_tx_count), + DHD_PKTID_AVAIL(dhd->prot->pktid_ctrl_map), + DHD_PKTID_AVAIL(dhd->prot->pktid_rx_map), + DHD_PKTID_AVAIL(dhd->prot->pktid_tx_map)); + } + + bcm_bprintf(b, "\n"); } /* Update local copy of dongle statistics */ @@ -10819,14 +10107,6 @@ BCMFASTPATH(dhd_prot_alloc_ring_space)(dhd_pub_t *dhd, msgbuf_ring_t *ring, ring->rd = dhd_prot_dma_indx_get(dhd, H2D_DMA_INDX_RD_UPD, ring->idx); } else { dhd_bus_cmn_readshared(dhd->bus, &(ring->rd), RING_RD_UPD, ring->idx); -#ifdef SUPPORT_LINKDOWN_RECOVERY - /* Check if ring->rd is valid */ - if (ring->rd >= ring->max_items) { - DHD_ERROR(("%s: Invalid rd idx=%d\n", ring->name, ring->rd)); - dhd->bus->read_shm_fail = TRUE; - return NULL; - } -#endif /* SUPPORT_LINKDOWN_RECOVERY */ } /* Try allocating once more */ @@ -10839,8 +10119,17 @@ BCMFASTPATH(dhd_prot_alloc_ring_space)(dhd_pub_t *dhd, msgbuf_ring_t *ring, } if (ret_buf == HOST_RING_BASE(ring)) { - DHD_MSGBUF_INFO(("%s: setting the phase now\n", ring->name)); - ring->current_phase = ring->current_phase ? 0 : BCMPCIE_CMNHDR_PHASE_BIT_INIT; + DHD_INFO(("%s: setting the phase now\n", ring->name)); + if (DHD_IS_FLOWRING(ring->idx, dhd->bus->max_tx_flowrings) && + dhd->fr_phase_nibble) { + ring->current_phase = + ((ring->current_phase == BCMPCIE_FLOWRING_PHASE_NIBBLE_INIT) + ? BCMPCIE_FLOWRING_PHASE_NIBBLE_WRAP : + BCMPCIE_FLOWRING_PHASE_NIBBLE_INIT); + } else { + ring->current_phase = ring->current_phase ? + 0 : BCMPCIE_CMNHDR_PHASE_BIT_INIT; + } } /* Return alloced space */ @@ -10859,12 +10148,13 @@ dhd_fillup_ioct_reqst(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf, int ifidx dhd_prot_t *prot = dhd->prot; ioctl_req_msg_t *ioct_rqst; void * ioct_buf; /* For ioctl payload */ + uint32 ioct_buf_len; uint16 rqstlen, resplen; unsigned long flags; uint16 alloced = 0; msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; #ifdef DBG_DW_CHK_PCIE_READ_LATENCY - ulong addr = dhd->bus->ring_sh[ring->idx].ring_state_r; + uint16 data; ktime_t begin_time, end_time; s64 diff_ns; #endif /* DBG_DW_CHK_PCIE_READ_LATENCY */ @@ -10889,7 +10179,7 @@ dhd_fillup_ioct_reqst(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf, int ifidx #ifdef DBG_DW_CHK_PCIE_READ_LATENCY preempt_disable(); begin_time = ktime_get(); - R_REG(dhd->osh, (volatile uint16 *)(dhd->bus->tcm + addr)); + dhd_bus_cmn_readshared(dhd->bus, &data, RING_RD_UPD, ring->idx); end_time = ktime_get(); preempt_enable(); diff_ns = ktime_to_ns(ktime_sub(end_time, begin_time)); @@ -10949,11 +10239,19 @@ dhd_fillup_ioct_reqst(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf, int ifidx ioct_rqst->host_input_buf_addr.low = htol32(PHYSADDRLO(prot->ioctbuf.pa)); /* copy ioct payload */ ioct_buf = (void *) prot->ioctbuf.va; + ioct_buf_len = prot->ioctbuf.len; prot->ioctl_fillup_time = OSL_LOCALTIME_NS(); - if (buf) - memcpy(ioct_buf, buf, len); + if (buf) { + int ret = 0; + ret = memcpy_s(ioct_buf, ioct_buf_len, buf, len); + if (ret) { + DHD_ERROR(("ioct_buf memcopy failed:%d, destsz:%d, n:%d\n", + ret, ioct_buf_len, len)); + return BCME_ERROR; + } + } OSL_CACHE_FLUSH((void *) prot->ioctbuf.va, len); @@ -10964,10 +10262,6 @@ dhd_fillup_ioct_reqst(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf, int ifidx ioct_rqst->cmn_hdr.request_id, cmd, ioct_rqst->output_buf_len, ioct_rqst->trans_id)); -#if defined(BCMINTERNAL) && defined(DHD_DBG_DUMP) - dhd_prot_ioctl_trace(dhd, ioct_rqst, buf, len); -#endif /* defined(BCMINTERNAL) && defined(DHD_DBG_DUMP) */ - /* update ring's WR index and ring doorbell to dongle */ dhd_prot_ring_write_complete(dhd, ring, ioct_rqst, 1); @@ -11000,6 +10294,9 @@ dhd_prot_ring_attach(dhd_pub_t *dhd, msgbuf_ring_t *ring, const char *name, dhd_prot_t *prot = dhd->prot; uint16 max_flowrings = dhd->bus->max_tx_flowrings; dhd_dma_buf_t *dma_buf = NULL; +#if defined(EWP_EDL) || defined(FLOW_RING_PREALLOC) + int ret; +#endif /* EWP_EDL || FLOW_RING_PREALLOC */ ASSERT(ring); ASSERT(name); @@ -11010,13 +10307,11 @@ dhd_prot_ring_attach(dhd_pub_t *dhd, msgbuf_ring_t *ring, const char *name, ring->idx = ringid; -#if defined(DHD_HTPUT_TUNABLES) /* Use HTPUT max items */ - if (DHD_IS_FLOWRING(ringid, max_flowrings) && + if (dhd->htput_support && DHD_IS_FLOWRING(ringid, max_flowrings) && DHD_IS_FLOWID_HTPUT(dhd, DHD_RINGID_TO_FLOWID(ringid))) { max_items = prot->h2d_htput_max_txpost; } -#endif /* DHD_HTPUT_TUNABLES */ dma_buf_len = max_items * item_len; @@ -11055,15 +10350,57 @@ dhd_prot_ring_attach(dhd_pub_t *dhd, msgbuf_ring_t *ring, const char *name, /* For EDL ring, memory is alloced during attach, * so just need to copy the dma_buf to the ring's dma_buf */ - memcpy(&ring->dma_buf, &dhd->edl_ring_mem, sizeof(ring->dma_buf)); + ret = memcpy_s(&ring->dma_buf, sizeof(ring->dma_buf), + &dhd->edl_ring_mem, sizeof(dhd->edl_ring_mem)); + if (ret != BCME_OK) { + DHD_ERROR(("%s: memcpy_s edl_ring_mem failed\n", __FUNCTION__)); + ASSERT(0); + return BCME_ERROR; + } dma_buf = &ring->dma_buf; if (dma_buf->va == NULL) { return BCME_NOMEM; } } else #endif /* EWP_EDL */ + +#ifdef FLOW_RING_PREALLOC + if (dhd->htput_support && DHD_IS_FLOWRING(ringid, max_flowrings) && + DHD_IS_FLOWID_HTPUT(dhd, DHD_RINGID_TO_FLOWID(ringid))) { + int htput_ringid = ringid % HTPUT_TOTAL_FLOW_RINGS; + /* copy pre-allocated mem with ringid */ + ret = memcpy_s(&ring->dma_buf, sizeof(ring->dma_buf), + &dhd->prot->htput_ring_buf[htput_ringid], + sizeof(dhd->prot->htput_ring_buf[htput_ringid])); + if (ret != BCME_OK) { + DHD_ERROR(("%s: memcpy_s htput_ring_buf failed\n", __FUNCTION__)); + ASSERT(0); + return BCME_ERROR; + } + dma_buf = &ring->dma_buf; + if (dma_buf->va == NULL) { + return BCME_NOMEM; + } + } else if (DHD_IS_FLOWRING(ringid, max_flowrings)) { + int non_htput_ringid = ringid % dhd->non_htput_total_flow_rings; + /* copy pre-allocated mem with ringid : Non-HTPUT ring */ + ret = memcpy_s(&ring->dma_buf, sizeof(ring->dma_buf), + &dhd->prot->flow_ring_buf[non_htput_ringid], + sizeof(dhd->prot->flow_ring_buf[non_htput_ringid])); + if (ret != BCME_OK) { + DHD_ERROR(("%s: memcpy_s non_htput_ring_buf failed\n", + __FUNCTION__)); + ASSERT(0); + return BCME_ERROR; + } + dma_buf = &ring->dma_buf; + if (dma_buf->va == NULL) { + return BCME_NOMEM; + } + } else +#endif /* FLOW_RING_PREALLOC */ { - /* Allocate a dhd_dma_buf */ + /* Allocate a dhd_dma_buf for non-htput flowrings and static rings */ dma_buf_alloced = dhd_dma_buf_alloc(dhd, &ring->dma_buf, dma_buf_len); if (dma_buf_alloced != BCME_OK) { return BCME_NOMEM; @@ -11165,7 +10502,20 @@ dhd_prot_ring_detach(dhd_pub_t *dhd, msgbuf_ring_t *ring) memset(&ring->dma_buf, 0, sizeof(ring->dma_buf)); } else #endif /* EWP_EDL */ +#ifdef FLOW_RING_PREALLOC + if (dhd->htput_support && + DHD_IS_FLOWID_HTPUT(dhd, DHD_RINGID_TO_FLOWID(ring->idx)) && + (ring->dma_buf.va)) { + /* htput ring is freed in dhd_detach */ + memset(&ring->dma_buf, 0, sizeof(ring->dma_buf)); + } else if (DHD_IS_FLOWRING(ring->idx, max_flowrings) && + (ring->dma_buf.va)) { + /* flow ring is freed in dhd_detach */ + memset(&ring->dma_buf, 0, sizeof(ring->dma_buf)); + } else +#endif /* FLOW_RING_PREALLOC */ { + /* Free non-htput flowrings and static rings */ dhd_dma_buf_free(dhd, &ring->dma_buf); } } @@ -11239,6 +10589,14 @@ dhd_prot_flowrings_pool_attach(dhd_pub_t *dhd) goto fail; } +#ifdef FLOW_RING_PREALLOC + if (h2d_flowrings_total > MAX_FLOW_RINGS) { + DHD_ERROR(("%s: requested size %d is bigger than pre-alloc flowrings %d,\n", + __FUNCTION__, h2d_flowrings_total, MAX_FLOW_RINGS)); + goto attach_fail; + } +#endif /* FLOW_RING_PREALLOC */ + /* Setup & Attach a DMA-able buffer to each flowring in the flowring pool */ FOREACH_RING_IN_FLOWRINGS_POOL(prot, ring, flowid, h2d_flowrings_total) { snprintf(ring_name, sizeof(ring_name), "h2dflr_%03u", flowid); @@ -11440,7 +10798,7 @@ BCMFASTPATH(dhd_prot_get_ring_space)(msgbuf_ring_t *ring, uint16 nitems, uint16 if ((ring_avail_cnt == 0) || (exactly_nitems && (ring_avail_cnt < nitems) && ((ring->max_items - ring->wr) >= nitems))) { - DHD_MSGBUF_INFO(("Space not available: ring %s items %d write %d read %d\n", + DHD_INFO(("Space not available: ring %s items %d write %d read %d\n", ring->name, nitems, ring->wr, ring->rd)); return NULL; } @@ -11598,12 +10956,18 @@ BCMFASTPATH(dhd_prot_ring_write_complete)(dhd_pub_t *dhd, msgbuf_ring_t * ring, DHD_BUS_LP_STATE_UNLOCK(dhd->bus->bus_lp_state_lock, flags_bus); } +static void +BCMFASTPATH(__dhd_prot_ring_doorbell)(dhd_pub_t *dhd, uint32 value) +{ + dhd->prot->mb_ring_fn(dhd->bus, value); +} + static void BCMFASTPATH(dhd_prot_ring_doorbell)(dhd_pub_t *dhd, uint32 value) { unsigned long flags_bus; DHD_BUS_LP_STATE_LOCK(dhd->bus->bus_lp_state_lock, flags_bus); - dhd->prot->mb_ring_fn(dhd->bus, value); + __dhd_prot_ring_doorbell(dhd, value); DHD_BUS_LP_STATE_UNLOCK(dhd->bus->bus_lp_state_lock, flags_bus); } @@ -11641,6 +11005,12 @@ dhd_prot_upd_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring) dhd_prot_t *prot = dhd->prot; uint32 db_index; uint corerev; + unsigned long flags_bus; + + /* Hold lp state lock before ringing DB for synchronization + * purpose, to avoid rininging after D3. + */ + DHD_BUS_LP_STATE_LOCK(dhd->bus->bus_lp_state_lock, flags_bus); /* update read index */ /* If dma'ing h2d indices supported @@ -11662,10 +11032,16 @@ dhd_prot_upd_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring) } else if (dhd->dma_h2d_ring_upd_support) { dhd_prot_dma_indx_set(dhd, ring->rd, D2H_DMA_INDX_RD_UPD, ring->idx); + /* For IDMA and HWA case, doorbell is sent along with read index update. + * For DMA indices case ring doorbell once n items are read to sync with dongle. + */ + __dhd_prot_ring_doorbell(dhd, DHD_RDPTR_UPDATE_H2D_DB_MAGIC(ring)); } else { dhd_bus_cmn_writeshared(dhd->bus, &(ring->rd), sizeof(uint16), RING_RD_UPD, ring->idx); } + + DHD_BUS_LP_STATE_UNLOCK(dhd->bus->bus_lp_state_lock, flags_bus); } static int @@ -11851,6 +11227,12 @@ dhd_prot_dma_indx_set(dhd_pub_t *dhd, uint16 new_index, uint8 type, uint16 ringi dhd_prot_t *prot = dhd->prot; uint16 max_h2d_rings = dhd->bus->max_submission_rings; + /* Ensure that instruction operates on workitem are + * completed before dma indices are updated. + * For non-dma indices case, this is handled + * using W_REG() which inturn has wmb(). + */ + OSL_MB(); switch (type) { case H2D_DMA_INDX_WR_UPD: ptr = (uint8 *)(prot->h2d_dma_indx_wr_buf.va); @@ -11881,6 +11263,11 @@ dhd_prot_dma_indx_set(dhd_pub_t *dhd, uint16 new_index, uint8 type, uint16 ringi OSL_CACHE_FLUSH((void *)ptr, prot->rw_index_sz); + /* Ensure that instruction operates on workitem are + * performed after dma indices are updated. + */ + OSL_MB(); + DHD_TRACE(("%s: data %d type %d ringid %d ptr 0x%p offset %d\n", __FUNCTION__, new_index, type, ringid, ptr, offset)); @@ -11901,6 +11288,11 @@ dhd_prot_dma_indx_get(dhd_pub_t *dhd, uint8 type, uint16 ringid) dhd_prot_t *prot = dhd->prot; uint16 max_h2d_rings = dhd->bus->max_submission_rings; + /* Ensure that instruction operates on workitem are + * completed before dma indices are read. + */ + OSL_MB(); + switch (type) { case H2D_DMA_INDX_WR_UPD: ptr = (uint8 *)(prot->h2d_dma_indx_wr_buf.va); @@ -11953,6 +11345,10 @@ dhd_prot_dma_indx_get(dhd_pub_t *dhd, uint8 type, uint16 ringid) DHD_TRACE(("%s: data %d type %d ringid %d ptr 0x%p offset %d\n", __FUNCTION__, data, type, ringid, ptr, offset)); + /* Ensure that instruction operates on workitem are + * performed after dma indices are read. + */ + OSL_MB(); return (data); } /* dhd_prot_dma_indx_get */ @@ -12155,10 +11551,11 @@ ret_no_mem: /** * Called on checking for 'completion' messages from the dongle. Returns next host buffer to read - * from, or NULL if there are no more messages to read. + * from, or NULL if there are no more messages to read. If 'bound' is non-zero, limits + * the no. of items read to bound */ static uint8* -dhd_prot_get_read_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint32 *available_len) +dhd_prot_get_read_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint32 *available_len, uint32 bound) { uint16 wr; uint16 rd; @@ -12166,6 +11563,11 @@ dhd_prot_get_read_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint32 *available_le uint16 items; void *read_addr = NULL; /* address of next msg to be read in ring */ uint16 d2h_wr = 0; + void *md_read_addr = NULL; /* address of next msg to be read in ring */ + int i; + uint8 *ptr = NULL; + uint32 total_md_len = 0; + UNUSED_PARAMETER(total_md_len); DHD_TRACE(("%s: d2h_dma_indx_rd_buf %p, d2h_dma_indx_wr_buf %p\n", __FUNCTION__, (uint32 *)(dhd->prot->d2h_dma_indx_rd_buf.va), @@ -12210,11 +11612,6 @@ dhd_prot_get_read_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint32 *available_le DHD_ERROR(("dhd->busstate %d bus->wait_for_d3_ack %d \r\n", dhd->busstate, dhd->bus->wait_for_d3_ack)); DHD_ERROR(("\r\n======================= \r\n")); -#ifdef SUPPORT_LINKDOWN_RECOVERY - if (wr >= ring->max_items) { - dhd->bus->read_shm_fail = TRUE; - } -#else #ifdef DHD_FW_COREDUMP if (dhd->memdump_enabled) { /* collect core dump */ @@ -12223,7 +11620,6 @@ dhd_prot_get_read_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint32 *available_le } #endif /* DHD_FW_COREDUMP */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ *available_len = 0; dhd_schedule_reset(dhd); @@ -12234,6 +11630,11 @@ dhd_prot_get_read_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint32 *available_le /* if space is available, calculate address to be read */ read_addr = (char*)ring->dma_buf.va + (rd * ring->item_len); + /* limit no. of items to bound */ + if (bound) { + items = MIN(items, bound); + } + /* update read pointer */ if ((ring->rd + items) >= ring->max_items) ring->rd = 0; @@ -12248,6 +11649,36 @@ dhd_prot_get_read_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint32 *available_le /* XXX Double cache invalidate for ARM with L2 cache/prefetch */ OSL_CACHE_INV(read_addr, *available_len); + if (ring->linked_ring) { + md_read_addr = (char*)ring->linked_ring->dma_buf.va + + (rd * ring->linked_ring->item_len); + total_md_len = (uint32)(items * ring->linked_ring->item_len); + OSL_CACHE_INV(md_read_addr, total_md_len); + /* Prefetch data to populate the cache */ + DHD_INFO(("ring address:0x%p, mdring address:0x%p, item:%d:%d\n", + read_addr, md_read_addr, items, total_md_len)); + if (dhd->mdring_info) { + ptr = (uint8 *)md_read_addr; + for (i = 0; i < items; i ++) { + ptr += ring->linked_ring->item_len; + DHD_INFO(("md:0x%x:0x%x:0x%x:0x%x 0x%x:0x%x:0x%x:0x%x\n", + ptr[0], ptr[1], ptr[2], ptr[3], + ptr[4], ptr[5], ptr[6], ptr[7])); + if (memcpy_s(&dhd->mdring_info[dhd->md_item_count * + ring->linked_ring->item_len], + ring->linked_ring->item_len, ptr, + ring->linked_ring->item_len) != BCME_OK) { + DHD_ERROR(("%s:Couldn't copy md item:%d,len:%d\n", + __FUNCTION__, + i, ring->linked_ring->item_len)); + break; + } + dhd->md_item_count = + (dhd->md_item_count + 1) % MAX_MDRING_ITEM_DUMP; + } + } + } + /* return read address */ return read_addr; @@ -12266,7 +11697,7 @@ int dhd_prot_h2d_mbdata_send_ctrlmsg(dhd_pub_t *dhd, uint32 mb_data) int num_post = 1; int i; - DHD_MSGBUF_INFO(("%s Sending H2D MB data Req data 0x%04x\n", + DHD_INFO(("%s Sending H2D MB data Req data 0x%04x\n", __FUNCTION__, mb_data)); if (!ctrl_ring->inited) { DHD_ERROR(("%s: Ctrl Submit Ring: not inited\n", __FUNCTION__)); @@ -12277,8 +11708,10 @@ int dhd_prot_h2d_mbdata_send_ctrlmsg(dhd_pub_t *dhd, uint32 mb_data) if ((INBAND_DW_ENAB(dhd->bus)) && (dhdpcie_bus_get_pcie_inband_dw_state(dhd->bus) == DW_DEVICE_DS_DEV_SLEEP)) { - if (mb_data == H2D_HOST_CONS_INT) { + if (mb_data == H2D_HOST_CONS_INT || mb_data == H2D_HOST_PTM_ENABLE || + mb_data == H2D_HOST_PTM_DISABLE) { /* One additional device_wake post needed */ + DHD_INFO(("%s One additional device_wake post needed\n", __FUNCTION__)); num_post = 2; } } @@ -12319,7 +11752,8 @@ int dhd_prot_h2d_mbdata_send_ctrlmsg(dhd_pub_t *dhd, uint32 mb_data) h2d_mb_data->mail_box_data = htol32(mb_data); } - DHD_MSGBUF_INFO(("%s Send H2D MB data Req data 0x%04x\n", __FUNCTION__, mb_data)); + DHD_INFO(("%s Send H2D MB data Req data 0x%04x\n", __FUNCTION__, + h2d_mb_data->mail_box_data)); /* upd wrt ptr and raise interrupt */ dhd_prot_ring_write_complete_mbdata(dhd, ctrl_ring, h2d_mb_data, @@ -12348,6 +11782,7 @@ dhd_prot_flow_ring_create(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) uint16 alloced = 0; msgbuf_ring_t *ctrl_ring = &prot->h2dring_ctrl_subn; uint16 max_flowrings = dhd->bus->max_tx_flowrings; + int ret = 0; /* Fetch a pre-initialized msgbuf_ring from the flowring pool */ flow_ring = dhd_prot_flowrings_pool_fetch(dhd, flow_ring_node->flowid); @@ -12392,8 +11827,20 @@ dhd_prot_flow_ring_create(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) /* Update flow create message */ flow_create_rqst->tid = flow_ring_node->flow_info.tid; flow_create_rqst->flow_ring_id = htol16((uint16)flow_ring_node->flowid); - memcpy(flow_create_rqst->sa, flow_ring_node->flow_info.sa, sizeof(flow_create_rqst->sa)); - memcpy(flow_create_rqst->da, flow_ring_node->flow_info.da, sizeof(flow_create_rqst->da)); + ret = memcpy_s(flow_create_rqst->sa, sizeof(flow_create_rqst->sa), + flow_ring_node->flow_info.sa, sizeof(flow_ring_node->flow_info.sa)); + if (ret) { + DHD_ERROR(("flow message sa memcpy failed:%d, destsz:%zu, n:%zu\n", + ret, sizeof(flow_create_rqst->sa), sizeof(flow_ring_node->flow_info.sa))); + return BCME_ERROR; + } + ret = memcpy_s(flow_create_rqst->da, sizeof(flow_create_rqst->da), + flow_ring_node->flow_info.da, sizeof(flow_ring_node->flow_info.da)); + if (ret) { + DHD_ERROR(("flow message da memcpy failed:%d, destsz:%zu, n:%zu\n", + ret, sizeof(flow_create_rqst->da), sizeof(flow_ring_node->flow_info.da))); + return BCME_ERROR; + } /* CAUTION: ring::base_addr already in Little Endian */ flow_create_rqst->flow_ring_ptr.low_addr = flow_ring->base_addr.low_addr; flow_create_rqst->flow_ring_ptr.high_addr = flow_ring->base_addr.high_addr; @@ -12401,27 +11848,6 @@ dhd_prot_flow_ring_create(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) flow_create_rqst->len_item = htol16(H2DRING_TXPOST_ITEMSIZE); flow_create_rqst->if_flags = 0; -#ifdef DHD_HP2P - /* Create HPP flow ring if HP2P is enabled and TID=7 and AWDL interface */ - /* and traffic is not multicast */ - /* Allow infra interface only if user enabled hp2p_infra_enable thru iovar */ - if (dhd->hp2p_capable && dhd->hp2p_ring_more && - flow_ring_node->flow_info.tid == HP2P_PRIO && - (dhd->hp2p_infra_enable || flow_create_rqst->msg.if_id) && - !ETHER_ISMULTI(flow_create_rqst->da)) { - flow_create_rqst->if_flags |= BCMPCIE_FLOW_RING_INTF_HP2P; - flow_ring_node->hp2p_ring = TRUE; - /* Allow multiple HP2P Flow if mf override is enabled */ - if (!dhd->hp2p_mf_enable) { - dhd->hp2p_ring_more = FALSE; - } - - DHD_ERROR(("%s: flow ring for HP2P tid = %d flowid = %d\n", - __FUNCTION__, flow_ring_node->flow_info.tid, - flow_ring_node->flowid)); - } -#endif /* DHD_HP2P */ - /* definition for ifrm mask : bit0:d11ac core, bit1:d11ad core * currently it is not used for priority. so uses solely for ifrm mask */ @@ -12489,13 +11915,6 @@ dhd_prot_process_h2d_ring_create_complete(dhd_pub_t *dhd, void *buf) !dhd->prot->h2dring_info_subn->create_pending) { DHD_ERROR(("info ring create status for not pending submit ring\n")); } -#ifdef BTLOG - if (dhd->prot->h2dring_btlog_subn && - dhd->prot->h2dring_btlog_subn->create_req_id == ltoh32(resp->cmn_hdr.request_id) && - !dhd->prot->h2dring_btlog_subn->create_pending) { - DHD_ERROR(("btlog ring create status for not pending submit ring\n")); - } -#endif /* BTLOG */ if (ltoh16(resp->cmplt.status) != BCMPCIE_SUCCESS) { DHD_ERROR(("info/btlog ring create failed with status %d\n", @@ -12508,15 +11927,6 @@ dhd_prot_process_h2d_ring_create_complete(dhd_pub_t *dhd, void *buf) DHD_ERROR(("info buffer post after ring create\n")); dhd_prot_infobufpost(dhd, dhd->prot->h2dring_info_subn); } -#ifdef BTLOG - if (dhd->prot->h2dring_btlog_subn && - dhd->prot->h2dring_btlog_subn->create_req_id == ltoh32(resp->cmn_hdr.request_id)) { - dhd->prot->h2dring_btlog_subn->create_pending = FALSE; - dhd->prot->h2dring_btlog_subn->inited = TRUE; - DHD_ERROR(("btlog buffer post after ring create\n")); - dhd_prot_infobufpost(dhd, dhd->prot->h2dring_btlog_subn); - } -#endif /* BTLOG */ } #endif /* !BCM_ROUTER_DHD */ @@ -12530,10 +11940,7 @@ dhd_prot_process_d2h_ring_create_complete(dhd_pub_t *dhd, void *buf) ltoh32(resp->cmn_hdr.request_id))); if ((ltoh32(resp->cmn_hdr.request_id) != DHD_D2H_DBGRING_REQ_PKTID) && (ltoh32(resp->cmn_hdr.request_id) != DHD_D2H_BTLOGRING_REQ_PKTID) && -#ifdef DHD_HP2P - (ltoh32(resp->cmn_hdr.request_id) != DHD_D2H_HPPRING_TXREQ_PKTID) && - (ltoh32(resp->cmn_hdr.request_id) != DHD_D2H_HPPRING_RXREQ_PKTID) && -#endif /* DHD_HP2P */ + (ltoh32(resp->cmn_hdr.request_id) != DHD_D2H_MDRING_REQ_PKTID) && TRUE) { DHD_ERROR(("invalid request ID with d2h ring create complete\n")); return; @@ -12575,54 +11982,21 @@ dhd_prot_process_d2h_ring_create_complete(dhd_pub_t *dhd, void *buf) #endif /* EWP_EDL */ } -#ifdef BTLOG - if (ltoh32(resp->cmn_hdr.request_id) == DHD_D2H_BTLOGRING_REQ_PKTID) { - if (!dhd->prot->d2hring_btlog_cpln->create_pending) { - DHD_ERROR(("btlog ring create status for not pending cpl ring\n")); + if (dhd->prot->d2hring_md_cpl && + ltoh32(resp->cmn_hdr.request_id) == DHD_D2H_MDRING_REQ_PKTID) { + if (!dhd->prot->d2hring_md_cpl->create_pending) { + DHD_ERROR(("metadata ring create status for not pending cpl ring\n")); return; } if (ltoh16(resp->cmplt.status) != BCMPCIE_SUCCESS) { - DHD_ERROR(("btlog cpl ring create failed with status %d\n", + DHD_ERROR(("metadata cpl ring create failed with status %d\n", ltoh16(resp->cmplt.status))); return; } - dhd->prot->d2hring_btlog_cpln->create_pending = FALSE; - dhd->prot->d2hring_btlog_cpln->inited = TRUE; + dhd->prot->d2hring_md_cpl->create_pending = FALSE; + dhd->prot->d2hring_md_cpl->inited = TRUE; } -#endif /* BTLOG */ -#ifdef DHD_HP2P - if (dhd->prot->d2hring_hp2p_txcpl && - ltoh32(resp->cmn_hdr.request_id) == DHD_D2H_HPPRING_TXREQ_PKTID) { - if (!dhd->prot->d2hring_hp2p_txcpl->create_pending) { - DHD_ERROR(("HPP tx ring create status for not pending cpl ring\n")); - return; - } - - if (ltoh16(resp->cmplt.status) != BCMPCIE_SUCCESS) { - DHD_ERROR(("HPP tx cpl ring create failed with status %d\n", - ltoh16(resp->cmplt.status))); - return; - } - dhd->prot->d2hring_hp2p_txcpl->create_pending = FALSE; - dhd->prot->d2hring_hp2p_txcpl->inited = TRUE; - } - if (dhd->prot->d2hring_hp2p_rxcpl && - ltoh32(resp->cmn_hdr.request_id) == DHD_D2H_HPPRING_RXREQ_PKTID) { - if (!dhd->prot->d2hring_hp2p_rxcpl->create_pending) { - DHD_ERROR(("HPP rx ring create status for not pending cpl ring\n")); - return; - } - - if (ltoh16(resp->cmplt.status) != BCMPCIE_SUCCESS) { - DHD_ERROR(("HPP rx cpl ring create failed with status %d\n", - ltoh16(resp->cmplt.status))); - return; - } - dhd->prot->d2hring_hp2p_rxcpl->create_pending = FALSE; - dhd->prot->d2hring_hp2p_rxcpl->inited = TRUE; - } -#endif /* DHD_HP2P */ } static void @@ -12631,7 +12005,7 @@ dhd_prot_process_d2h_mb_data(dhd_pub_t *dhd, void* buf) d2h_mailbox_data_t *d2h_data; d2h_data = (d2h_mailbox_data_t *)buf; - DHD_MSGBUF_INFO(("%s dhd_prot_process_d2h_mb_data, 0x%04x\n", __FUNCTION__, + DHD_INFO(("%s dhd_prot_process_d2h_mb_data, 0x%04x\n", __FUNCTION__, d2h_data->d2h_mailbox_data)); dhd_bus_handle_mb_data(dhd->bus, d2h_data->d2h_mailbox_data); } @@ -12639,31 +12013,7 @@ dhd_prot_process_d2h_mb_data(dhd_pub_t *dhd, void* buf) static void dhd_prot_process_d2h_host_ts_complete(dhd_pub_t *dhd, void* buf) { -#ifdef DHD_TIMESYNC - host_timestamp_msg_cpl_t *host_ts_cpl; - uint32 pktid; - dhd_prot_t *prot = dhd->prot; - - host_ts_cpl = (host_timestamp_msg_cpl_t *)buf; - DHD_INFO(("%s host TS cpl: status %d, req_ID: 0x%04x, xt_id %d \n", __FUNCTION__, - host_ts_cpl->cmplt.status, host_ts_cpl->msg.request_id, host_ts_cpl->xt_id)); - - pktid = ltoh32(host_ts_cpl->msg.request_id); - if (prot->hostts_req_buf_inuse == FALSE) { - DHD_ERROR(("No Pending Host TS req, but completion\n")); - return; - } - prot->hostts_req_buf_inuse = FALSE; - if (pktid != DHD_H2D_HOSTTS_REQ_PKTID) { - DHD_ERROR(("Host TS req CPL, but req ID different 0x%04x, exp 0x%04x\n", - pktid, DHD_H2D_HOSTTS_REQ_PKTID)); - return; - } - dhd_timesync_handle_host_ts_complete(dhd->ts, host_ts_cpl->xt_id, - host_ts_cpl->cmplt.status); -#else /* DHD_TIMESYNC */ DHD_ERROR(("Timesunc feature not compiled in but GOT HOST_TS_COMPLETE\n")); -#endif /* DHD_TIMESYNC */ } @@ -12717,73 +12067,31 @@ void dhd_prot_print_info(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) { dhd_prot_t *prot = dhd->prot; bcm_bprintf(strbuf, "IPCrevs: Dev %d, \t Host %d, \tactive %d\n", - dhd->prot->device_ipc_version, - dhd->prot->host_ipc_version, - dhd->prot->active_ipc_version); + prot->device_ipc_version, + prot->host_ipc_version, + prot->active_ipc_version); bcm_bprintf(strbuf, "max Host TS bufs to post: %d, \t posted %d \n", - dhd->prot->max_tsbufpost, dhd->prot->cur_ts_bufs_posted); + prot->max_tsbufpost, prot->cur_ts_bufs_posted); bcm_bprintf(strbuf, "max INFO bufs to post: %d, \t posted %d \n", - dhd->prot->max_infobufpost, dhd->prot->infobufpost); -#ifdef BTLOG - bcm_bprintf(strbuf, "max BTLOG bufs to post: %d, \t posted %d \n", - dhd->prot->max_btlogbufpost, dhd->prot->btlogbufpost); -#endif /* BTLOG */ + prot->max_infobufpost, prot->infobufpost); bcm_bprintf(strbuf, "max event bufs to post: %d, \t posted %d \n", - dhd->prot->max_eventbufpost, dhd->prot->cur_event_bufs_posted); + prot->max_eventbufpost, prot->cur_event_bufs_posted); bcm_bprintf(strbuf, "max ioctlresp bufs to post: %d, \t posted %d \n", - dhd->prot->max_ioctlrespbufpost, dhd->prot->cur_ioctlresp_bufs_posted); - bcm_bprintf(strbuf, "max RX bufs to post: %d, \t posted %d \n", - dhd->prot->max_rxbufpost, dhd->prot->rxbufpost); + prot->max_ioctlrespbufpost, prot->cur_ioctlresp_bufs_posted); - bcm_bprintf(strbuf, "Total RX bufs posted: %d, \t RX cpl got %d \n", - dhd->prot->tot_rxbufpost, dhd->prot->tot_rxcpl); - - bcm_bprintf(strbuf, "Total TX packets: %lu, \t TX cpl got %lu \n", - dhd->actual_tx_pkts, dhd->tot_txcpl); - - bcm_bprintf(strbuf, - "%14s %18s %18s %17s %17s %14s %14s %10s\n", - "Type", "TRD: HLRD: HDRD", "TWR: HLWR: HDWR", "BASE(VA)", "BASE(PA)", - "WORK_ITEM_SIZE", "MAX_WORK_ITEMS", "TOTAL_SIZE"); - bcm_bprintf(strbuf, "%14s", "H2DCtrlPost"); - dhd_prot_print_flow_ring(dhd, &prot->h2dring_ctrl_subn, TRUE, strbuf, - " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); - bcm_bprintf(strbuf, "%14s", "D2HCtrlCpl"); - dhd_prot_print_flow_ring(dhd, &prot->d2hring_ctrl_cpln, FALSE, strbuf, - " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); - bcm_bprintf(strbuf, "%14s", "H2DRxPost"); - dhd_prot_print_flow_ring(dhd, &prot->h2dring_rxp_subn, TRUE, strbuf, - " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); - bcm_bprintf(strbuf, "%14s", "D2HRxCpl"); - dhd_prot_print_flow_ring(dhd, &prot->d2hring_rx_cpln, FALSE, strbuf, - " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); - bcm_bprintf(strbuf, "%14s", "D2HTxCpl"); - dhd_prot_print_flow_ring(dhd, &prot->d2hring_tx_cpln, FALSE, strbuf, - " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); - if (dhd->prot->h2dring_info_subn != NULL && dhd->prot->d2hring_info_cpln != NULL) { - bcm_bprintf(strbuf, "%14s", "H2DRingInfoSub"); - dhd_prot_print_flow_ring(dhd, prot->h2dring_info_subn, TRUE, strbuf, - " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); - bcm_bprintf(strbuf, "%14s", "D2HRingInfoCpl"); - dhd_prot_print_flow_ring(dhd, prot->d2hring_info_cpln, FALSE, strbuf, - " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); - } - if (dhd->prot->d2hring_edl != NULL) { - bcm_bprintf(strbuf, "%14s", "D2HRingEDL"); - dhd_prot_print_flow_ring(dhd, prot->d2hring_edl, FALSE, strbuf, - " %5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d\n"); - } + dhd_prot_print_ring_info(dhd, strbuf); bcm_bprintf(strbuf, "active_tx_count %d pktidmap_avail(ctrl/rx/tx) %d %d %d\n", - OSL_ATOMIC_READ(dhd->osh, &dhd->prot->active_tx_count), - DHD_PKTID_AVAIL(dhd->prot->pktid_ctrl_map), - DHD_PKTID_AVAIL(dhd->prot->pktid_rx_map), - DHD_PKTID_AVAIL(dhd->prot->pktid_tx_map)); + OSL_ATOMIC_READ(dhd->osh, &prot->active_tx_count), + DHD_PKTID_AVAIL(prot->pktid_ctrl_map), + DHD_PKTID_AVAIL(prot->pktid_rx_map), + DHD_PKTID_AVAIL(prot->pktid_tx_map)); + + bcm_bprintf(strbuf, "Total wakeup packet rcvd: Event:%d,\t RX:%d,\t Info:%d\n", + prot->event_wakeup_pkt, prot->rx_wakeup_pkt, + prot->info_wakeup_pkt); -#if defined(BCMINTERNAL) && defined(DHD_DBG_DUMP) - dhd_prot_ioctl_dump(dhd->prot, strbuf); -#endif /* defined(BCMINTERNAL) && defined(DHD_DBG_DUMP) */ #ifdef DHD_MMIO_TRACE dhd_dump_bus_mmio_trace(dhd->bus, strbuf); #endif /* DHD_MMIO_TRACE */ @@ -12836,9 +12144,9 @@ dhd_prot_flow_ring_delete(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) flow_delete_rqst->flow_ring_id = htol16((uint16)flow_ring_node->flowid); flow_delete_rqst->reason = htol16(BCME_OK); - DHD_ERROR(("%s: Send Flow Delete Req RING ID %d for peer %pM" + DHD_ERROR(("%s: Send Flow Delete Req RING ID %d for peer " MACDBG " prio %d ifindex %d\n", __FUNCTION__, flow_ring_node->flowid, - flow_ring_node->flow_info.da, flow_ring_node->flow_info.tid, + MAC2STRDBG(flow_ring_node->flow_info.da), flow_ring_node->flow_info.tid, flow_ring_node->flow_info.ifindex)); /* update ring's WR index and ring doorbell to dongle */ @@ -13090,9 +12398,36 @@ dhd_msgbuf_ring_config_d2h_soft_doorbell(dhd_pub_t *dhd) static void dhd_prot_process_d2h_ring_config_complete(dhd_pub_t *dhd, void *msg) { - DHD_INFO(("%s: Ring Config Response - status %d ringid %d\n", + ring_config_resp_t *ring_config_resp = (ring_config_resp_t *)msg; + dhd_prot_t *prot = dhd->prot; + msgbuf_ring_t *cpl_ring = NULL; + + DHD_INFO(("%s: Ring Config Response - status %d ringid %d subtype:%d\n", __FUNCTION__, ltoh16(((ring_config_resp_t *)msg)->compl_hdr.status), - ltoh16(((ring_config_resp_t *)msg)->compl_hdr.flow_ring_id))); + ltoh16(((ring_config_resp_t *)msg)->compl_hdr.flow_ring_id), + ltoh16(((ring_config_resp_t *)msg)->subtype))); + + if (ltoh16(ring_config_resp->compl_hdr.status) == 0) { + if (ring_config_resp->subtype == + htol16(D2H_RING_CONFIG_SUBTYPE_MDATA_LINK)) { + cpl_ring = prot->d2hring_md_cpl->linked_ring; + cpl_ring->linked_ring = prot->d2hring_md_cpl; + } + else if (ring_config_resp->subtype == + htol16(D2H_RING_CONFIG_SUBTYPE_MDATA_UNLINK)) { + cpl_ring = prot->d2hring_md_cpl->linked_ring; + cpl_ring->linked_ring = NULL; + prot->d2hring_md_cpl->linked_ring = NULL; + bzero(dhd->mdring_info, + (MAX_MDRING_ITEM_DUMP * D2HRING_MDCMPLT_ITEMSIZE)); + } + } else { + DHD_ERROR(("%s: Ring Config Failed - status %d ringid %d subtype:%d\n", + __FUNCTION__, ltoh16(((ring_config_resp_t *)msg)->compl_hdr.status), + ltoh16(((ring_config_resp_t *)msg)->compl_hdr.flow_ring_id), + ltoh16(((ring_config_resp_t *)msg)->subtype))); + prot->d2hring_md_cpl->linked_ring = NULL; + } } #ifdef WL_CFGVENDOR_SEND_HANG_EVENT @@ -13591,6 +12926,7 @@ copy_hang_info_linkdown(dhd_pub_t *dhd) get_debug_dump_time(dhd->debug_dump_time_hang_str); copy_debug_dump_time(dhd->debug_dump_time_str, dhd->debug_dump_time_hang_str); +#ifdef BCMPCIE /* hang reason code (0x8808) */ if (dhd->hang_info_cnt < HANG_FIELD_CNT_MAX) { remain_len = VENDOR_SEND_HANG_EXT_INFO_LEN - bytes_written; @@ -13598,6 +12934,7 @@ copy_hang_info_linkdown(dhd_pub_t *dhd) HANG_REASON_PCIE_LINK_DOWN_EP_DETECT, HANG_KEY_DEL); dhd->hang_info_cnt++; } +#endif /* EWP version */ if (dhd->hang_info_cnt < HANG_FIELD_CNT_MAX) { @@ -13617,77 +12954,22 @@ copy_hang_info_linkdown(dhd_pub_t *dhd) clear_debug_dump_time(dhd->debug_dump_time_hang_str); - /* dump PCIE RC registers */ - dhd_dump_pcie_rc_regs_for_linkdown(dhd, &bytes_written); - DHD_INFO(("hang info haed cnt: %d len: %d data: %s\n", dhd->hang_info_cnt, (int)strlen(dhd->hang_info), dhd->hang_info)); } #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */ -int -dhd_prot_debug_info_print(dhd_pub_t *dhd) +void +dhd_prot_ctrl_info_print(dhd_pub_t *dhd) { dhd_prot_t *prot = dhd->prot; msgbuf_ring_t *ring; uint16 rd, wr, drd, dwr; uint32 dma_buf_len; - uint64 current_time; ulong ring_tcm_rd_addr; /* dongle address */ ulong ring_tcm_wr_addr; /* dongle address */ - DHD_ERROR(("\n ------- DUMPING VERSION INFORMATION ------- \r\n")); - DHD_ERROR(("DHD: %s\n", dhd_version)); - DHD_ERROR(("Firmware: %s\n", fw_version)); - -#ifdef DHD_FW_COREDUMP - DHD_ERROR(("\n ------- DUMPING CONFIGURATION INFORMATION ------ \r\n")); - DHD_ERROR(("memdump mode: %d\n", dhd->memdump_enabled)); -#endif /* DHD_FW_COREDUMP */ - - DHD_ERROR(("\n ------- DUMPING PROTOCOL INFORMATION ------- \r\n")); - DHD_ERROR(("ICPrevs: Dev %d, Host %d, active %d\n", - prot->device_ipc_version, - prot->host_ipc_version, - prot->active_ipc_version)); - DHD_ERROR(("d2h_intr_method -> %s d2h_intr_control -> %s\n", - dhd->bus->d2h_intr_method ? "PCIE_MSI" : "PCIE_INTX", - dhd->bus->d2h_intr_control ? "HOST_IRQ" : "D2H_INTMASK")); - DHD_ERROR(("max Host TS bufs to post: %d, posted %d\n", - prot->max_tsbufpost, prot->cur_ts_bufs_posted)); - DHD_ERROR(("max INFO bufs to post: %d, posted %d\n", - prot->max_infobufpost, prot->infobufpost)); - DHD_ERROR(("max event bufs to post: %d, posted %d\n", - prot->max_eventbufpost, prot->cur_event_bufs_posted)); - DHD_ERROR(("max ioctlresp bufs to post: %d, posted %d\n", - prot->max_ioctlrespbufpost, prot->cur_ioctlresp_bufs_posted)); - DHD_ERROR(("max RX bufs to post: %d, posted %d\n", - prot->max_rxbufpost, prot->rxbufpost)); - DHD_ERROR(("h2d_max_txpost: %d, prot->h2d_max_txpost: %d\n", - h2d_max_txpost, prot->h2d_max_txpost)); -#if defined(DHD_HTPUT_TUNABLES) - DHD_ERROR(("h2d_max_txpost: %d, prot->h2d_max_txpost: %d\n", - h2d_htput_max_txpost, prot->h2d_htput_max_txpost)); -#endif /* DHD_HTPUT_TUNABLES */ - - current_time = OSL_LOCALTIME_NS(); - DHD_ERROR(("current_time="SEC_USEC_FMT"\n", GET_SEC_USEC(current_time))); - DHD_ERROR(("ioctl_fillup_time="SEC_USEC_FMT - " ioctl_ack_time="SEC_USEC_FMT - " ioctl_cmplt_time="SEC_USEC_FMT"\n", - GET_SEC_USEC(prot->ioctl_fillup_time), - GET_SEC_USEC(prot->ioctl_ack_time), - GET_SEC_USEC(prot->ioctl_cmplt_time))); - - /* Check PCIe INT registers */ - if (!dhd_pcie_dump_int_regs(dhd)) { - DHD_ERROR(("%s : PCIe link might be down\n", __FUNCTION__)); - dhd->bus->is_linkdown = TRUE; - } - - DHD_ERROR(("\n ------- DUMPING IOCTL RING RD WR Pointers ------- \r\n")); - ring = &prot->h2dring_ctrl_subn; dma_buf_len = ring->max_items * ring->item_len; ring_tcm_rd_addr = dhd->bus->ring_sh[ring->idx].ring_state_r; @@ -13721,6 +13003,7 @@ dhd_prot_debug_info_print(dhd_pub_t *dhd) ring->dma_buf.va, ltoh32(ring->base_addr.high_addr), ltoh32(ring->base_addr.low_addr), ring_tcm_rd_addr, ring_tcm_wr_addr, dma_buf_len)); DHD_ERROR(("CtrlCpl: From Host mem: RD: %d WR %d \r\n", ring->rd, ring->wr)); + DHD_ERROR(("CtrlCpl: From Host mem: CURR_RD: %d\r\n", ring->curr_rd)); if (dhd->dma_d2h_ring_upd_support) { drd = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_RD_UPD, ring->idx); dwr = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_WR_UPD, ring->idx); @@ -13736,6 +13019,22 @@ dhd_prot_debug_info_print(dhd_pub_t *dhd) } DHD_ERROR(("CtrlCpl: Expected seq num: %d \r\n", ring->seqnum % H2D_EPOCH_MODULO)); +} + +void +dhd_prot_debug_ring_info(dhd_pub_t *dhd) +{ + dhd_prot_t *prot = dhd->prot; + msgbuf_ring_t *ring; + uint16 rd, wr, drd, dwr; + uint32 dma_buf_len; + ulong ring_tcm_rd_addr; /* dongle address */ + ulong ring_tcm_wr_addr; /* dongle address */ + + DHD_ERROR(("\n ------- DUMPING IOCTL RING RD WR Pointers ------- \r\n")); + + dhd_prot_ctrl_info_print(dhd); + ring = prot->h2dring_info_subn; if (ring) { dma_buf_len = ring->max_items * ring->item_len; @@ -13773,6 +13072,7 @@ dhd_prot_debug_info_print(dhd_pub_t *dhd) ltoh32(ring->base_addr.low_addr), ring_tcm_rd_addr, ring_tcm_wr_addr, dma_buf_len)); DHD_ERROR(("InfoCpl: From Host mem: RD: %d WR %d \r\n", ring->rd, ring->wr)); + DHD_ERROR(("InfoCpl: From Host mem: CURR_RD: %d\r\n", ring->curr_rd)); if (dhd->dma_d2h_ring_upd_support) { drd = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_RD_UPD, ring->idx); dwr = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_WR_UPD, ring->idx); @@ -13800,6 +13100,7 @@ dhd_prot_debug_info_print(dhd_pub_t *dhd) ltoh32(ring->base_addr.low_addr), ring_tcm_rd_addr, ring_tcm_wr_addr, dma_buf_len)); DHD_ERROR(("EdlRing: From Host mem: RD: %d WR %d \r\n", ring->rd, ring->wr)); + DHD_ERROR(("EdlRing: From Host mem: CURR_RD: %d\r\n", ring->curr_rd)); if (dhd->dma_d2h_ring_upd_support) { drd = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_RD_UPD, ring->idx); dwr = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_WR_UPD, ring->idx); @@ -13829,6 +13130,7 @@ dhd_prot_debug_info_print(dhd_pub_t *dhd) ltoh32(ring->base_addr.low_addr), ring_tcm_rd_addr, ring_tcm_wr_addr, dma_buf_len)); DHD_ERROR(("TxCpl: From Host mem: RD: %d WR %d \r\n", ring->rd, ring->wr)); + DHD_ERROR(("TxCpl: From Host mem: CURR_RD: %d\r\n", ring->curr_rd)); if (dhd->dma_d2h_ring_upd_support) { drd = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_RD_UPD, ring->idx); dwr = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_WR_UPD, ring->idx); @@ -13856,6 +13158,7 @@ dhd_prot_debug_info_print(dhd_pub_t *dhd) ltoh32(ring->base_addr.low_addr), ring_tcm_rd_addr, ring_tcm_wr_addr, dma_buf_len)); DHD_ERROR(("RxCpl: From Host mem: RD: %d WR %d \r\n", ring->rd, ring->wr)); + DHD_ERROR(("RxCpl: From Host mem: CURR_RD: %d\r\n", ring->curr_rd)); if (dhd->dma_d2h_ring_upd_support) { drd = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_RD_UPD, ring->idx); dwr = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_WR_UPD, ring->idx); @@ -13899,11 +13202,71 @@ dhd_prot_debug_info_print(dhd_pub_t *dhd) DHD_ERROR(("RxSub: Expected seq num: %d \r\n", ring->seqnum % D2H_EPOCH_MODULO)); } +} + +int +dhd_prot_debug_info_print(dhd_pub_t *dhd) +{ + dhd_prot_t *prot = dhd->prot; + uint64 current_time; + + DHD_ERROR(("\n ------- DUMPING VERSION INFORMATION ------- \r\n")); + DHD_ERROR(("DHD: %s\n", dhd_version)); + DHD_ERROR(("Firmware: %s\n", fw_version)); + +#ifdef DHD_FW_COREDUMP + DHD_ERROR(("\n ------- DUMPING CONFIGURATION INFORMATION ------ \r\n")); + DHD_ERROR(("memdump mode: %d\n", dhd->memdump_enabled)); +#endif /* DHD_FW_COREDUMP */ + + DHD_ERROR(("\n ------- DUMPING PROTOCOL INFORMATION ------- \r\n")); + DHD_ERROR(("ICPrevs: Dev %d, Host %d, active %d\n", + prot->device_ipc_version, + prot->host_ipc_version, + prot->active_ipc_version)); + DHD_ERROR(("d2h_intr_method -> %s d2h_intr_control -> %s\n", + dhd->bus->d2h_intr_method ? "PCIE_MSI" : "PCIE_INTX", + dhd->bus->d2h_intr_control ? "HOST_IRQ" : "D2H_INTMASK")); + DHD_ERROR(("max Host TS bufs to post: %d, posted %d\n", + prot->max_tsbufpost, prot->cur_ts_bufs_posted)); + DHD_ERROR(("max INFO bufs to post: %d, posted %d\n", + prot->max_infobufpost, prot->infobufpost)); + DHD_ERROR(("max event bufs to post: %d, posted %d\n", + prot->max_eventbufpost, prot->cur_event_bufs_posted)); + DHD_ERROR(("max ioctlresp bufs to post: %d, posted %d\n", + prot->max_ioctlrespbufpost, prot->cur_ioctlresp_bufs_posted)); + DHD_ERROR(("max RX bufs to post: %d, posted %d\n", + prot->max_rxbufpost, prot->rxbufpost)); + DHD_ERROR(("h2d_max_txpost: %d, prot->h2d_max_txpost: %d\n", + h2d_max_txpost, prot->h2d_max_txpost)); + if (dhd->htput_support) { + DHD_ERROR(("h2d_max_txpost: %d, prot->h2d_max_txpost: %d\n", + h2d_htput_max_txpost, prot->h2d_htput_max_txpost)); + } + + current_time = OSL_LOCALTIME_NS(); + DHD_ERROR(("current_time="SEC_USEC_FMT"\n", GET_SEC_USEC(current_time))); + DHD_ERROR(("ioctl_fillup_time="SEC_USEC_FMT + " ioctl_ack_time="SEC_USEC_FMT + " ioctl_cmplt_time="SEC_USEC_FMT"\n", + GET_SEC_USEC(prot->ioctl_fillup_time), + GET_SEC_USEC(prot->ioctl_ack_time), + GET_SEC_USEC(prot->ioctl_cmplt_time))); + + /* Check PCIe INT registers */ + if (!dhd_pcie_dump_int_regs(dhd)) { + DHD_ERROR(("%s : PCIe link might be down\n", __FUNCTION__)); + dhd->bus->is_linkdown = TRUE; + } + + dhd_prot_debug_ring_info(dhd); + DHD_ERROR(("%s: cur_ioctlresp_bufs_posted %d cur_event_bufs_posted %d\n", __FUNCTION__, prot->cur_ioctlresp_bufs_posted, prot->cur_event_bufs_posted)); #ifdef DHD_LIMIT_MULTI_CLIENT_FLOWRINGS - DHD_ERROR(("%s: multi_client_flow_rings:%d max_multi_client_flow_rings:%d\n", - __FUNCTION__, dhd->multi_client_flow_rings, dhd->max_multi_client_flow_rings)); + DHD_ERROR(("%s: multi_client_flow_rings:%u max_multi_client_flow_rings:%d\n", + __FUNCTION__, OSL_ATOMIC_READ(dhd->osh, &dhd->multi_client_flow_rings), + dhd->max_multi_client_flow_rings)); #endif /* DHD_LIMIT_MULTI_CLIENT_FLOWRINGS */ DHD_ERROR(("pktid_txq_start_cnt: %d\n", prot->pktid_txq_start_cnt)); @@ -13916,9 +13279,6 @@ dhd_prot_debug_info_print(dhd_pub_t *dhd) DHD_ERROR(("\nlb_rxp_napi_sched_cnt: %llu lb_rxp_napi_complete_cnt: %llu\n", dhd->lb_rxp_napi_sched_cnt, dhd->lb_rxp_napi_complete_cnt)); #endif /* DHD_LB_STATS */ -#ifdef DHD_TIMESYNC - dhd_timesync_debug_info_print(dhd); -#endif /* DHD_TIMESYNC */ return 0; } @@ -13995,7 +13355,7 @@ dhd_prot_metadata_dbg_get(dhd_pub_t *dhd) uint32 dhd_prot_metadatalen_set(dhd_pub_t *dhd, uint32 val, bool rx) { -#if !(defined(BCM_ROUTER_DHD)) +#if !defined(BCM_ROUTER_DHD) dhd_prot_t *prot = dhd->prot; if (rx) prot->rx_metadata_offset = (uint16)val; @@ -14248,53 +13608,11 @@ dhd_prot_flow_ring_batch_suspend_request(dhd_pub_t *dhd, uint16 *ringid, uint16 } #endif /* IDLE_TX_FLOW_MGMT */ -#if defined(BCMINTERNAL) && defined(DHD_DBG_DUMP) -static void -dhd_prot_ioctl_trace(dhd_pub_t *dhd, ioctl_req_msg_t *ioct_rqst, uchar *buf, int len) -{ - struct dhd_prot *prot = dhd->prot; - uint32 cnt = prot->ioctl_trace_count % MAX_IOCTL_TRACE_SIZE; - - prot->ioctl_trace[cnt].cmd = ioct_rqst->cmd; - prot->ioctl_trace[cnt].transid = ioct_rqst->trans_id; - if ((ioct_rqst->cmd == 262 || ioct_rqst->cmd == 263) && buf) - memcpy(prot->ioctl_trace[cnt].ioctl_buf, buf, - len > MAX_IOCTL_BUF_SIZE ? MAX_IOCTL_BUF_SIZE : len); - else - memset(prot->ioctl_trace[cnt].ioctl_buf, 0, MAX_IOCTL_BUF_SIZE); - prot->ioctl_trace[cnt].timestamp = OSL_SYSUPTIME_US(); - prot->ioctl_trace_count ++; -} - -static void -dhd_prot_ioctl_dump(dhd_prot_t *prot, struct bcmstrbuf *strbuf) -{ - int dumpsz; - int i; - - dumpsz = prot->ioctl_trace_count < MAX_IOCTL_TRACE_SIZE ? - prot->ioctl_trace_count : MAX_IOCTL_TRACE_SIZE; - if (dumpsz == 0) { - bcm_bprintf(strbuf, "\nEmpty IOCTL TRACE\n"); - return; - } - bcm_bprintf(strbuf, "----------- IOCTL TRACE --------------\n"); - bcm_bprintf(strbuf, "Timestamp us\t\tCMD\tTransID\tIOVAR\n"); - for (i = 0; i < dumpsz; i ++) { - bcm_bprintf(strbuf, "%llu\t%d\t%d\t%s\n", - prot->ioctl_trace[i].timestamp, - prot->ioctl_trace[i].cmd, - prot->ioctl_trace[i].transid, - prot->ioctl_trace[i].ioctl_buf); - } -} -#endif /* defined(BCMINTERNAL) && defined(DHD_DBG_DUMP) */ - static void dump_psmwd_v1(const bcm_tlv_t *tlv, struct bcmstrbuf *b) { - const hnd_ext_trap_psmwd_v1_t* psmwd = NULL; + const hnd_ext_trap_psmwd_v1_t* psmwd = (const hnd_ext_trap_psmwd_v1_t *)tlv->data; uint32 i; - psmwd = (const hnd_ext_trap_psmwd_v1_t *)tlv; + for (i = 0; i < PSMDBG_REG_READ_CNT_FOR_PSMWDTRAP_V1; i++) { bcm_bprintf(b, " psmdebug[%d]: 0x%x\n", i, psmwd->i32_psmdebug[i]); } @@ -14326,9 +13644,9 @@ static void dump_psmwd_v1(const bcm_tlv_t *tlv, struct bcmstrbuf *b) static void dump_psmwd_v2(const bcm_tlv_t *tlv, struct bcmstrbuf *b) { - const hnd_ext_trap_psmwd_t* psmwd = NULL; + const hnd_ext_trap_psmwd_v2_t* psmwd = (const hnd_ext_trap_psmwd_v2_t *)tlv->data; uint32 i; - psmwd = (const hnd_ext_trap_psmwd_t *)tlv; + for (i = 0; i < PSMDBG_REG_READ_CNT_FOR_PSMWDTRAP_V2; i++) { bcm_bprintf(b, " psmdebug[%d]: 0x%x\n", i, psmwd->i32_psmdebug[i]); } @@ -14363,6 +13681,130 @@ static void dump_psmwd_v2(const bcm_tlv_t *tlv, struct bcmstrbuf *b) bcm_bprintf(b, " shm_txphyerr_cnt: 0x%x\n", psmwd->shm_txphyerr_cnt); } +static void dump_psmwd_v3(const bcm_tlv_t *tlv, struct bcmstrbuf *b) +{ + const hnd_ext_trap_psmwd_v3_t* psmwd = (const hnd_ext_trap_psmwd_v3_t *)tlv->data; + uint32 i; + + for (i = 0; i < PSMDBG_REG_READ_CNT_FOR_PSMWDTRAP_V1; i++) { + bcm_bprintf(b, " psmdebug[%d]: 0x%x\n", i, psmwd->i32_psmdebug[i]); + } + + bcm_bprintf(b, " i32_gated_clock_en: 0x%x\n", psmwd->i32_gated_clock_en); + bcm_bprintf(b, " Rcv Fifo Ctrl: 0x%x\n", psmwd->rcv_fifo_ctrl); + bcm_bprintf(b, " Rx ctrl 1: 0x%x\n", psmwd->rx_ctrl1); + bcm_bprintf(b, " Rxe Status 1: 0x%x\n", psmwd->rxe_status1); + bcm_bprintf(b, " Rxe Status 2: 0x%x\n", psmwd->rxe_status2); + + bcm_bprintf(b, " rcv wrd count 0: 0x%x\n", psmwd->rcv_wrd_count0); + bcm_bprintf(b, " rcv wrd count 1: 0x%x\n", psmwd->rcv_wrd_count1); + bcm_bprintf(b, " RCV_LFIFO_STS: 0x%x\n", psmwd->rcv_lfifo_sts); + bcm_bprintf(b, " PSM_SLP_TMR: 0x%x\n", psmwd->psm_slp_tmr); + bcm_bprintf(b, " PSM BRC: 0x%x\n", psmwd->psm_brc); + + bcm_bprintf(b, " TXE CTRL: 0x%x\n", psmwd->txe_ctrl); + bcm_bprintf(b, " TXE Status: 0x%x\n", psmwd->txe_status); + bcm_bprintf(b, " TXE_xmtdmabusy: 0x%x\n", psmwd->txe_xmtdmabusy); + bcm_bprintf(b, " TXE_XMTfifosuspflush: 0x%x\n", psmwd->txe_xmt_fifo_susp_flush); + bcm_bprintf(b, " IFS Stat: 0x%x\n", psmwd->ifs_stat); + + bcm_bprintf(b, " IFS_MEDBUSY_CTR: 0x%x\n", psmwd->ifs_medbusy_ctr); + bcm_bprintf(b, " IFS_TX_DUR: 0x%x\n", psmwd->ifs_tx_dur); + bcm_bprintf(b, " SLow_CTL: 0x%x\n", psmwd->slow_ctl); + bcm_bprintf(b, " TXE_AQM fifo Ready: 0x%x\n", psmwd->txe_aqm_fifo_ready); + bcm_bprintf(b, " Dagg ctrl: 0x%x\n", psmwd->dagg_ctrl); + + bcm_bprintf(b, " shm_prewds_cnt: 0x%x\n", psmwd->shm_prewds_cnt); + bcm_bprintf(b, " shm_txtplufl_cnt: 0x%x\n", psmwd->shm_txtplufl_cnt); + bcm_bprintf(b, " shm_txphyerr_cnt: 0x%x\n", psmwd->shm_txphyerr_cnt); +} + +static void dump_psmwd(const bcm_tlv_t *tlv, struct bcmstrbuf *b) +{ + const hnd_ext_trap_psmwd_v1_t * psmwd = (const hnd_ext_trap_psmwd_v1_t*)tlv->data; + + if (psmwd->version == 0 || psmwd->version > HND_EXT_TRAP_PSMWD_INFO_VER_3) { + bcm_bprintf(b, " Bad version: 0x%x\n", psmwd->version); + return; + } + bcm_bprintf(b, " version: 0x%x\n", psmwd->version); + bcm_bprintf(b, " maccontrol: 0x%x\n", psmwd->i32_maccontrol); + bcm_bprintf(b, " maccommand: 0x%x\n", psmwd->i32_maccommand); + bcm_bprintf(b, " macintstatus: 0x%x\n", psmwd->i32_macintstatus); + bcm_bprintf(b, " phydebug: 0x%x\n", psmwd->i32_phydebug); + bcm_bprintf(b, " clk_ctl_st: 0x%x\n", psmwd->i32_clk_ctl_st); + if (psmwd->version == HND_EXT_TRAP_PSMWD_INFO_VER_1) { + dump_psmwd_v1(tlv, b); + } else if (psmwd->version == HND_EXT_TRAP_PSMWD_INFO_VER_2) { + dump_psmwd_v2(tlv, b); + } else if (psmwd->version == HND_EXT_TRAP_PSMWD_INFO_VER_3) { + dump_psmwd_v3(tlv, b); + } + return; +} + +static void dump_macwake_v1(const bcm_tlv_t *tlv, struct bcmstrbuf *b) +{ + const hnd_ext_trap_macenab_v1_t* macwake = (const hnd_ext_trap_macenab_v1_t *)tlv->data; + + bcm_bprintf(b, " gated clock en: 0x%x\n", macwake->i16_0x1a8); + bcm_bprintf(b, " PSM_SLP_TMR: 0x%x\n", macwake->i16_0x480); + bcm_bprintf(b, " PSM BRC: 0x%x\n", macwake->i16_0x490); + bcm_bprintf(b, " TSF CTL: 0x%x\n", macwake->i16_0x600); + bcm_bprintf(b, " IFS Stat: 0x%x\n", macwake->i16_0x690); + bcm_bprintf(b, " IFS_MEDBUSY_CTR: 0x%x\n", macwake->i16_0x692); + bcm_bprintf(b, " Slow_CTL: 0x%x\n", macwake->i16_0x6a0); + bcm_bprintf(b, " Slow_FRAC: 0x%x\n", macwake->i16_0x6a6); + bcm_bprintf(b, " fast power up delay: 0x%x\n", macwake->i16_0x6a8); + bcm_bprintf(b, " Slow_PER: 0x%x\n", macwake->i16_0x6aa); + bcm_bprintf(b, " shm_ucode_dbgst: 0x%x\n", macwake->shm_ucode_dbgst); +} + +static void dump_macwake_v2(const bcm_tlv_t *tlv, struct bcmstrbuf *b) +{ + const hnd_ext_trap_macenab_v2_t* macwake = (const hnd_ext_trap_macenab_v2_t *)tlv->data; + + bcm_bprintf(b, " gated clock en: 0x%x\n", macwake->i32_gated_clock_en); + bcm_bprintf(b, " PSM_SLP_TMR: 0x%x\n", macwake->psm_slp_tmr); + bcm_bprintf(b, " PSM BRC: 0x%x\n", macwake->psm_brc); + bcm_bprintf(b, " TSF CTL: 0x%x\n", macwake->tsf_ctl); + bcm_bprintf(b, " IFS Stat: 0x%x\n", macwake->ifs_stat); + bcm_bprintf(b, " IFS_MEDBUSY_CTR: 0x%x\n", macwake->ifs_medbusy_ctr); + bcm_bprintf(b, " Slow_CTL: 0x%x\n", macwake->slow_ctl); + bcm_bprintf(b, " Slow_FRAC: 0x%x\n", macwake->slow_frac); + bcm_bprintf(b, " fast power up delay: 0x%x\n", macwake->fast_powerup_delay); + bcm_bprintf(b, " Slow_PER: 0x%x\n", macwake->slow_per); + bcm_bprintf(b, " shm_ucode_dbgst: 0x%x\n", macwake->shm_ucode_dbgst); +} + +static void dump_macwake(const bcm_tlv_t *tlv, struct bcmstrbuf *b) +{ + const hnd_ext_trap_macenab_v1_t* macwake = (const hnd_ext_trap_macenab_v1_t *)tlv->data; + uint32 i; + + if (macwake->version == 0 || macwake->version > HND_EXT_TRAP_MACENAB_INFO_VER_2) { + bcm_bprintf(b, " Bad version: 0x%x\n", macwake->version); + return; + } + + bcm_bprintf(b, " version: 0x%x\n", macwake->version); + bcm_bprintf(b, " trap_reason: 0x%x\n", macwake->trap_reason); + bcm_bprintf(b, " maccontrol: 0x%x\n", macwake->i32_maccontrol); + bcm_bprintf(b, " maccommand: 0x%x\n", macwake->i32_maccommand); + bcm_bprintf(b, " macintstatus: 0x%x\n", macwake->i32_macintstatus); + for (i = 0; i < 8; i++) + bcm_bprintf(b, " psmdebug[%d]: 0x%x\n", i, macwake->i32_psmdebug[i]); + bcm_bprintf(b, " clk_ctl_st: 0x%x\n", macwake->i32_clk_ctl_st); + bcm_bprintf(b, " powerctl: 0x%x\n", macwake->i32_powerctl); + + if (macwake->version == HND_EXT_TRAP_MACENAB_INFO_VER_1) { + dump_macwake_v1(tlv, b); + } else if (macwake->version == HND_EXT_TRAP_MACENAB_INFO_VER_2) { + dump_macwake_v2(tlv, b); + } + return; +} + static const char* etd_trap_name(hnd_ext_tag_trap_t tag) { switch (tag) { @@ -14598,22 +14040,8 @@ int dhd_prot_dump_extended_trap(dhd_pub_t *dhdp, struct bcmstrbuf *b, bool raw) tlv = bcm_parse_tlvs(hdr->data, hdr->len, TAG_TRAP_PSM_WD); if (tlv) { - const hnd_ext_trap_psmwd_t* psmwd; - bcm_bprintf(b, "\n%s len: %d\n", etd_trap_name(TAG_TRAP_PSM_WD), tlv->len); - psmwd = (const hnd_ext_trap_psmwd_t *)tlv->data; - bcm_bprintf(b, " version: 0x%x\n", psmwd->version); - bcm_bprintf(b, " maccontrol: 0x%x\n", psmwd->i32_maccontrol); - bcm_bprintf(b, " maccommand: 0x%x\n", psmwd->i32_maccommand); - bcm_bprintf(b, " macintstatus: 0x%x\n", psmwd->i32_macintstatus); - bcm_bprintf(b, " phydebug: 0x%x\n", psmwd->i32_phydebug); - bcm_bprintf(b, " clk_ctl_st: 0x%x\n", psmwd->i32_clk_ctl_st); - if (psmwd->version == 1) { - dump_psmwd_v1(tlv, b); - } - if (psmwd->version == 2) { - dump_psmwd_v2(tlv, b); - } + dump_psmwd(tlv, b); } /* PHY TxErr MacDump */ tlv = bcm_parse_tlvs(hdr->data, hdr->len, TAG_TRAP_PHYTXERR_THRESH); @@ -14687,29 +14115,8 @@ int dhd_prot_dump_extended_trap(dhd_pub_t *dhdp, struct bcmstrbuf *b, bool raw) tlv = bcm_parse_tlvs(hdr->data, hdr->len, TAG_TRAP_MAC_WAKE); if (tlv) { - const hnd_ext_trap_macenab_t* macwake; bcm_bprintf(b, "\n%s len: %d\n", etd_trap_name(TAG_TRAP_MAC_WAKE), tlv->len); - macwake = (const hnd_ext_trap_macenab_t *)tlv->data; - bcm_bprintf(b, " version: 0x%x\n", macwake->version); - bcm_bprintf(b, " trap_reason: 0x%x\n", macwake->trap_reason); - bcm_bprintf(b, " maccontrol: 0x%x\n", macwake->i32_maccontrol); - bcm_bprintf(b, " maccommand: 0x%x\n", macwake->i32_maccommand); - bcm_bprintf(b, " macintstatus: 0x%x\n", macwake->i32_macintstatus); - for (i = 0; i < 8; i++) - bcm_bprintf(b, " psmdebug[%d]: 0x%x\n", i, macwake->i32_psmdebug[i]); - bcm_bprintf(b, " clk_ctl_st: 0x%x\n", macwake->i32_clk_ctl_st); - bcm_bprintf(b, " powerctl: 0x%x\n", macwake->i32_powerctl); - bcm_bprintf(b, " gated clock en: 0x%x\n", macwake->i16_0x1a8); - bcm_bprintf(b, " PSM_SLP_TMR: 0x%x\n", macwake->i16_0x480); - bcm_bprintf(b, " PSM BRC: 0x%x\n", macwake->i16_0x490); - bcm_bprintf(b, " TSF CTL: 0x%x\n", macwake->i16_0x600); - bcm_bprintf(b, " IFS Stat: 0x%x\n", macwake->i16_0x690); - bcm_bprintf(b, " IFS_MEDBUSY_CTR: 0x%x\n", macwake->i16_0x692); - bcm_bprintf(b, " Slow_CTL: 0x%x\n", macwake->i16_0x6a0); - bcm_bprintf(b, " Slow_FRAC: 0x%x\n", macwake->i16_0x6a6); - bcm_bprintf(b, " fast power up delay: 0x%x\n", macwake->i16_0x6a8); - bcm_bprintf(b, " Slow_PER: 0x%x\n", macwake->i16_0x6aa); - bcm_bprintf(b, " shm_ucode_dbgst: 0x%x\n", macwake->shm_ucode_dbgst); + dump_macwake(tlv, b); } tlv = bcm_parse_tlvs(hdr->data, hdr->len, TAG_TRAP_BUS); @@ -14759,6 +14166,7 @@ dhd_prot_send_host_timestamp(dhd_pub_t *dhdp, uchar *tlvs, uint16 tlv_len, uint16 alloced = 0; uchar *ts_tlv_buf; msgbuf_ring_t *ctrl_ring = &prot->h2dring_ctrl_subn; + int ret; if ((tlvs == NULL) || (tlv_len == 0)) { DHD_ERROR(("%s: argument error tlv: %p, tlv_len %d\n", @@ -14813,7 +14221,12 @@ dhd_prot_send_host_timestamp(dhd_pub_t *dhdp, uchar *tlvs, uint16 tlv_len, /* copy ioct payload */ ts_tlv_buf = (void *) prot->hostts_req_buf.va; prot->hostts_req_buf_inuse = TRUE; - memcpy(ts_tlv_buf, tlvs, tlv_len); + ret = memcpy_s(ts_tlv_buf, prot->hostts_req_buf.len, tlvs, tlv_len); + if (ret) { + DHD_ERROR(("copy ioct payload failed:%d, destsz:%d, n:%d\n", + ret, prot->hostts_req_buf.len, tlv_len)); + return BCME_ERROR; + } OSL_CACHE_FLUSH((void *) prot->hostts_req_buf.va, tlv_len); @@ -14902,55 +14315,7 @@ dhd_msgbuf_delay_post_ts_bufs(dhd_pub_t *dhd) static void BCMFASTPATH(dhd_prot_process_fw_timestamp)(dhd_pub_t *dhd, void* buf) { -#ifdef DHD_TIMESYNC - fw_timestamp_event_msg_t *resp; - uint32 pktid; - uint16 buflen, seqnum; - void * pkt; - - resp = (fw_timestamp_event_msg_t *)buf; - pktid = ltoh32(resp->msg.request_id); - buflen = ltoh16(resp->buf_len); - seqnum = ltoh16(resp->seqnum); - -#if defined(DHD_PKTID_AUDIT_RING) - DHD_PKTID_AUDIT(dhd, dhd->prot->pktid_ctrl_map, pktid, - DHD_DUPLICATE_FREE); -#endif /* DHD_PKTID_AUDIT_RING */ - - DHD_INFO(("id 0x%04x, len %d, phase 0x%02x, seqnum %d\n", - pktid, buflen, resp->msg.flags, ltoh16(resp->seqnum))); - - if (!dhd->prot->cur_ts_bufs_posted) { - DHD_ERROR(("tsbuf posted are zero, but there is a completion\n")); - return; - } - - dhd->prot->cur_ts_bufs_posted--; - - if (!dhd_timesync_delay_post_bufs(dhd)) { - if (dhd->prot->max_tsbufpost > 0) { - dhd_msgbuf_rxbuf_post_ts_bufs(dhd); - } - } - - pkt = dhd_prot_packet_get(dhd, pktid, PKTTYPE_TSBUF_RX, TRUE); - - if (!pkt) { - DHD_ERROR(("no ts buffer associated with pktid 0x%04x\n", pktid)); - return; - } - - PKTSETLEN(dhd->osh, pkt, buflen); - dhd_timesync_handle_fw_timestamp(dhd->ts, PKTDATA(dhd->osh, pkt), buflen, seqnum); -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhd->osh, pkt, TRUE); -#else - PKTFREE(dhd->osh, pkt, TRUE); -#endif /* DHD_USE_STATIC_CTRLBUF */ -#else /* DHD_TIMESYNC */ DHD_ERROR(("Timesunc feature not compiled in but GOT FW TS message\n")); -#endif /* DHD_TIMESYNC */ } @@ -14960,118 +14325,6 @@ dhd_prot_get_ioctl_trans_id(dhd_pub_t *dhdp) return dhdp->prot->ioctl_trans_id; } -#ifdef SNAPSHOT_UPLOAD -/* send request to take snapshot */ -int -dhd_prot_send_snapshot_request(dhd_pub_t *dhdp, uint8 snapshot_type, uint8 snapshot_param) -{ - dhd_prot_t *prot = dhdp->prot; - dhd_dma_buf_t *dma_buf = &prot->snapshot_upload_buf; - snapshot_upload_request_msg_t *snap_req; - unsigned long flags; - uint16 alloced = 0; - msgbuf_ring_t *ctrl_ring = &prot->h2dring_ctrl_subn; - -#ifdef PCIE_INB_DW - if (dhd_prot_inc_hostactive_devwake_assert(dhdp->bus) != BCME_OK) - return BCME_ERROR; -#endif /* PCIE_INB_DW */ - - DHD_RING_LOCK(ctrl_ring->ring_lock, flags); - - /* Request for cbuf space */ - snap_req = (snapshot_upload_request_msg_t *)dhd_prot_alloc_ring_space(dhdp, - ctrl_ring, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, - &alloced, FALSE); - if (snap_req == NULL) { - DHD_ERROR(("couldn't allocate space on msgring to send snapshot request\n")); - DHD_RING_UNLOCK(ctrl_ring->ring_lock, flags); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhdp->bus); -#endif - return BCME_ERROR; - } - - /* Common msg buf hdr */ - snap_req->cmn_hdr.msg_type = MSG_TYPE_SNAPSHOT_UPLOAD; - snap_req->cmn_hdr.if_id = 0; - snap_req->cmn_hdr.flags = ctrl_ring->current_phase; - snap_req->cmn_hdr.request_id = DHD_H2D_SNAPSHOT_UPLOAD_REQ_PKTID; - snap_req->cmn_hdr.epoch = ctrl_ring->seqnum % H2D_EPOCH_MODULO; - ctrl_ring->seqnum++; - - /* snapshot request msg */ - snap_req->snapshot_buf_len = htol32(dma_buf->len); - snap_req->snapshot_type = snapshot_type; - snap_req->snapshot_param = snapshot_param; - snap_req->host_buf_addr.high = htol32(PHYSADDRHI(dma_buf->pa)); - snap_req->host_buf_addr.low = htol32(PHYSADDRLO(dma_buf->pa)); - - if (ISALIGNED(dma_buf->va, DMA_ALIGN_LEN) == FALSE) { - DHD_ERROR(("snapshot req buffer address unaligned !!!!! \n")); - } - - /* clear previous snapshot upload */ - memset(dma_buf->va, 0, dma_buf->len); - prot->snapshot_upload_len = 0; - prot->snapshot_type = snapshot_type; - prot->snapshot_cmpl_pending = TRUE; - - DHD_CTL(("submitted snapshot request request_id %d, buf_len %d, type %d, param %d\n", - snap_req->cmn_hdr.request_id, snap_req->snapshot_buf_len, - snap_req->snapshot_type, snap_req->snapshot_param)); - - /* upd wrt ptr and raise interrupt */ - dhd_prot_ring_write_complete(dhdp, ctrl_ring, snap_req, - DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); - - DHD_RING_UNLOCK(ctrl_ring->ring_lock, flags); - -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhdp->bus); -#endif - - return BCME_OK; -} /* dhd_prot_send_snapshot_request */ - -/* get uploaded snapshot */ -int -dhd_prot_get_snapshot(dhd_pub_t *dhdp, uint8 snapshot_type, uint32 offset, - uint32 dst_buf_size, uint8 *dst_buf, uint32 *dst_size, bool *is_more) -{ - dhd_prot_t *prot = dhdp->prot; - uint8 *buf = prot->snapshot_upload_buf.va; - uint8 *buf_end = buf + prot->snapshot_upload_len; - uint32 copy_size; - - /* snapshot type must match */ - if (prot->snapshot_type != snapshot_type) { - return BCME_DATA_NOTFOUND; - } - - /* snapshot not completed */ - if (prot->snapshot_cmpl_pending) { - return BCME_NOTREADY; - } - - /* offset within the buffer */ - if (buf + offset >= buf_end) { - return BCME_BADARG; - } - - /* copy dst buf size or remaining size */ - copy_size = MIN(dst_buf_size, buf_end - (buf + offset)); - memcpy(dst_buf, buf + offset, copy_size); - - /* return size and is_more */ - *dst_size = copy_size; - *is_more = (offset + copy_size < prot->snapshot_upload_len) ? - TRUE : FALSE; - return BCME_OK; -} /* dhd_prot_get_snapshot */ - -#endif /* SNAPSHOT_UPLOAD */ - int dhd_get_hscb_info(dhd_pub_t *dhd, void ** va, uint32 *len) { if (!dhd->hscb_enable) { @@ -15111,201 +14364,223 @@ int dhd_get_hscb_buff(dhd_pub_t *dhd, uint32 offset, uint32 length, void * buff) } #endif /* DHD_BUS_MEM_ACCESS */ -#ifdef DHD_HP2P -uint32 -dhd_prot_pkt_threshold(dhd_pub_t *dhd, bool set, uint32 val) +static uint16 +dhd_d2h_cpl_ring_id(dhd_pub_t *dhd, msgbuf_ring_t *ring) { - if (set) - dhd->pkt_thresh = (uint16)val; + uint16 max_h2d_rings = dhd->bus->max_submission_rings; + dhd_prot_t *prot = dhd->prot; - val = dhd->pkt_thresh; + if (ring == &prot->d2hring_tx_cpln) + return prot->d2hring_tx_cpln.idx; + if (ring == &prot->d2hring_rx_cpln) + return prot->d2hring_rx_cpln.idx; - return val; + return (DHD_D2H_RING_OFFSET(ring->idx, max_h2d_rings) + + BCMPCIE_D2H_COMMON_MSGRINGS); } -uint32 -dhd_prot_time_threshold(dhd_pub_t *dhd, bool set, uint32 val) +static int +dhd_d2h_id_from_cpl_ring_idx(dhd_pub_t *dhd, uint16 idx) { - if (set) - dhd->time_thresh = (uint16)val; + dhd_prot_t *prot = dhd->prot; - val = dhd->time_thresh; - - return val; + if (prot->d2hring_tx_cpln.idx == idx) { + return DHD_METADATA_D2H_TXCPL; + } + if (prot->d2hring_rx_cpln.idx == idx) { + return DHD_METADATA_D2H_RXCPL; + } + return DHD_METADATA_NO_RING; } -uint32 -dhd_prot_pkt_expiry(dhd_pub_t *dhd, bool set, uint32 val) +static msgbuf_ring_t * +dhd_d2h_cpl_ring_from_id(dhd_pub_t *dhd, int idx) { - if (set) - dhd->pkt_expiry = (uint16)val; + dhd_prot_t *prot = dhd->prot; - val = dhd->pkt_expiry; - - return val; -} - -uint8 -dhd_prot_hp2p_enable(dhd_pub_t *dhd, bool set, int enable) -{ - uint8 ret = 0; - if (set) { - dhd->hp2p_enable = (enable & 0xf) ? TRUE : FALSE; - dhd->hp2p_infra_enable = ((enable >> 4) & 0xf) ? TRUE : FALSE; - - if (enable) { - dhd_update_flow_prio_map(dhd, DHD_FLOW_PRIO_TID_MAP); - } else { - dhd_update_flow_prio_map(dhd, DHD_FLOW_PRIO_AC_MAP); + switch (idx) { + case DHD_METADATA_D2H_TXCPL: /* D2H Tx Completion Ring */ + if (prot->d2hring_tx_cpln.inited) { + return &prot->d2hring_tx_cpln; } + break; + case DHD_METADATA_D2H_RXCPL: /* D2H Rx Completion Ring */ + if (prot->d2hring_rx_cpln.inited) { + return &prot->d2hring_rx_cpln; + } + break; + default: + return NULL; } - ret = dhd->hp2p_infra_enable ? 0x1:0x0; - ret <<= 4; - ret |= dhd->hp2p_enable ? 0x1:0x0; - - return ret; + return NULL; } -static void -dhd_update_hp2p_rxstats(dhd_pub_t *dhd, host_rxbuf_cmpl_t *rxstatus) +int +dhd_prot_mdring_link_unlink(dhd_pub_t *dhd, int idx, bool link) { - ts_timestamp_t *ts = (ts_timestamp_t *)&rxstatus->ts; - hp2p_info_t *hp2p_info; - uint32 dur1; - - hp2p_info = &dhd->hp2p_info[0]; - dur1 = ((ts->high & 0x3FF) * HP2P_TIME_SCALE) / 100; - - if (dur1 > (MAX_RX_HIST_BIN - 1)) { - dur1 = MAX_RX_HIST_BIN - 1; - DHD_INFO(("%s: 0x%x 0x%x\n", - __FUNCTION__, ts->low, ts->high)); - } - - hp2p_info->rx_t0[dur1 % MAX_RX_HIST_BIN]++; - return; -} - -static void -dhd_update_hp2p_txstats(dhd_pub_t *dhd, host_txbuf_cmpl_t *txstatus) -{ - ts_timestamp_t *ts = (ts_timestamp_t *)&txstatus->ts; - uint16 flowid = txstatus->compl_hdr.flow_ring_id; - uint32 hp2p_flowid, dur1, dur2; - hp2p_info_t *hp2p_info; - - hp2p_flowid = dhd->bus->max_submission_rings - - dhd->bus->max_cmn_rings - flowid + 1; - hp2p_info = &dhd->hp2p_info[hp2p_flowid]; - ts = (ts_timestamp_t *)&(txstatus->ts); - - dur1 = ((ts->high & 0x3FF) * HP2P_TIME_SCALE) / 1000; - if (dur1 > (MAX_TX_HIST_BIN - 1)) { - dur1 = MAX_TX_HIST_BIN - 1; - DHD_INFO(("%s: 0x%x 0x%x\n", __FUNCTION__, ts->low, ts->high)); - } - hp2p_info->tx_t0[dur1 % MAX_TX_HIST_BIN]++; - - dur2 = (((ts->high >> 10) & 0x3FF) * HP2P_TIME_SCALE) / 1000; - if (dur2 > (MAX_TX_HIST_BIN - 1)) { - dur2 = MAX_TX_HIST_BIN - 1; - DHD_INFO(("%s: 0x%x 0x%x\n", __FUNCTION__, ts->low, ts->high)); - } - - hp2p_info->tx_t1[dur2 % MAX_TX_HIST_BIN]++; - return; -} - -enum hrtimer_restart dhd_hp2p_write(struct hrtimer *timer) -{ - hp2p_info_t *hp2p_info; + void *msg_start; + uint16 alloced = 0; unsigned long flags; - dhd_pub_t *dhdp; + dhd_prot_t *prot = dhd->prot; + ring_config_req_t *ring_config_req; + msgbuf_ring_t *ctrl_ring = &prot->h2dring_ctrl_subn; + msgbuf_ring_t *linked_ring = NULL; - GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); - hp2p_info = container_of(timer, hp2p_info_t, timer); - GCC_DIAGNOSTIC_POP(); + if (!prot->d2hring_md_cpl) { + DHD_ERROR(("%s No metadata ring exists\n", __FUNCTION__)); + return BCME_ERROR; + } + if (link && prot->d2hring_md_cpl->linked_ring) { + DHD_ERROR(("%s Link:metadata ring already linked\n", __FUNCTION__)); + return BCME_ERROR; + } + linked_ring = dhd_d2h_cpl_ring_from_id(dhd, idx); + if (!link && linked_ring != prot->d2hring_md_cpl->linked_ring) { + DHD_ERROR(("%s Unlink:metadata ring not linked\n", __FUNCTION__)); + return BCME_ERROR; + } + prot->d2hring_md_cpl->linked_ring = linked_ring; +#ifdef PCIE_INB_DW + if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) + return BCME_ERROR; +#endif /* PCIE_INB_DW */ + /* Claim space for 1 d2h_ring_config_req_t messages */ + DHD_RING_LOCK(ctrl_ring->ring_lock, flags); + msg_start = dhd_prot_alloc_ring_space(dhd, ctrl_ring, 1, &alloced, TRUE); - dhdp = hp2p_info->dhd_pub; - if (!dhdp) { - goto done; + if (msg_start == NULL) { + DHD_ERROR(("%s Msgbuf no space for D2H ring config metadta ring link/unlink\n", + __FUNCTION__)); + DHD_RING_UNLOCK(ctrl_ring->ring_lock, flags); +#ifdef PCIE_INB_DW + dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); +#endif + return BCME_ERROR; } - DHD_INFO(("%s: pend_item = %d flowid = %d\n", - __FUNCTION__, ((msgbuf_ring_t *)hp2p_info->ring)->pend_items_count, - hp2p_info->flowid)); + /* position the ring_config_req into the ctrl subm ring */ + ring_config_req = (ring_config_req_t *)msg_start; - flags = dhd_os_hp2plock(dhdp); + /* Common msg header */ + ring_config_req->msg.msg_type = MSG_TYPE_D2H_RING_CONFIG; + ring_config_req->msg.if_id = 0; + ring_config_req->msg.request_id = htol32(0); /* TBD */ + ring_config_req->msg.flags = ctrl_ring->current_phase; - dhd_prot_txdata_write_flush(dhdp, hp2p_info->flowid); - hp2p_info->hrtimer_init = FALSE; - hp2p_info->num_timer_limit++; + ring_config_req->msg.epoch = ctrl_ring->seqnum % H2D_EPOCH_MODULO; + ctrl_ring->seqnum++; - dhd_os_hp2punlock(dhdp, flags); -done: - return HRTIMER_NORESTART; -} + ring_config_req->msg.request_id = htol32(DHD_FAKE_PKTID); /* unused */ -static void -dhd_calc_hp2p_burst(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint16 flowid) -{ - hp2p_info_t *hp2p_info; - uint16 hp2p_flowid; - - hp2p_flowid = dhd->bus->max_submission_rings - - dhd->bus->max_cmn_rings - flowid + 1; - hp2p_info = &dhd->hp2p_info[hp2p_flowid]; - - if (ring->pend_items_count == dhd->pkt_thresh) { - dhd_prot_txdata_write_flush(dhd, flowid); - - hp2p_info->hrtimer_init = FALSE; - hp2p_info->ring = NULL; - hp2p_info->num_pkt_limit++; - hrtimer_cancel(&hp2p_info->timer); - - DHD_INFO(("%s: cancel hrtimer for flowid = %d \n" - "hp2p_flowid = %d pkt_thresh = %d\n", - __FUNCTION__, flowid, hp2p_flowid, dhd->pkt_thresh)); + /* Ring Config subtype and d2h ring_id */ + if (link) { + ring_config_req->subtype = htol16(D2H_RING_CONFIG_SUBTYPE_MDATA_LINK); } else { - if (hp2p_info->hrtimer_init == FALSE) { - hp2p_info->hrtimer_init = TRUE; - hp2p_info->flowid = flowid; - hp2p_info->dhd_pub = dhd; - hp2p_info->ring = ring; - hp2p_info->num_timer_start++; - - hrtimer_start(&hp2p_info->timer, - ktime_set(0, dhd->time_thresh * 1000), HRTIMER_MODE_REL); - - DHD_INFO(("%s: start hrtimer for flowid = %d hp2_flowid = %d\n", - __FUNCTION__, flowid, hp2p_flowid)); - } + ring_config_req->subtype = htol16(D2H_RING_CONFIG_SUBTYPE_MDATA_UNLINK); } - return; + ring_config_req->ring_id = + htol16(dhd_d2h_cpl_ring_id(dhd, prot->d2hring_md_cpl)); + + ring_config_req->mdata_assoc.ringid = + htol16(dhd_d2h_cpl_ring_id(dhd, prot->d2hring_md_cpl->linked_ring)); + + DHD_ERROR(("%s: metadata:%d link to ring:%d\n", + __FUNCTION__, ring_config_req->ring_id, + ring_config_req->mdata_assoc.ringid)); + + /* update control subn ring's WR index and ring doorbell to dongle */ + dhd_prot_ring_write_complete(dhd, ctrl_ring, msg_start, 1); + + DHD_RING_UNLOCK(ctrl_ring->ring_lock, flags); + +#ifdef PCIE_INB_DW + dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); +#endif + return BCME_OK; } +int +dhd_prot_mdring_linked_ring(dhd_pub_t *dhd) +{ + dhd_prot_t *prot = dhd->prot; + if (prot->d2hring_md_cpl && prot->d2hring_md_cpl->linked_ring) { + return dhd_d2h_id_from_cpl_ring_idx + (dhd, prot->d2hring_md_cpl->linked_ring->idx); + } + return 0; +} + +/* +* rx_status1: +* Bit [31:0] - Packet reception time +* +* rx_status_ext (marker): +* Bit[7:0] - RSSI for the received packet +* Bit[23:8] - Set to the duration of the packet inside the dongle - +* measured in units of 32 microseconds +* Bit[24] - Packet received on 2G (0) or 5G (1) +* +* flags: +* Bit [7:5] Packet priority +*/ + static void -dhd_update_hp2p_txdesc(dhd_pub_t *dhd, host_txbuf_post_t *txdesc) +dhd_update_rxstats(dhd_pub_t *dhd, host_rxbuf_cmpl_t *rxstatus) { - uint64 ts; + uint32 marker = rxstatus->marker; + uint16 flags = rxstatus->flags; + rx_cpl_lat_info_t *rxcpl_info; + uint32 dur; + uint8 slice; + uint8 prio; + int8 rssi; + uint32 rx_t0; - ts = local_clock(); - do_div(ts, 1000); + ts_timestamp_t *ts = (ts_timestamp_t *)&rxstatus->ts; - txdesc->metadata_buf_len = 0; - txdesc->metadata_buf_addr.high_addr = htol32((ts >> 32) & 0xFFFFFFFF); - txdesc->metadata_buf_addr.low_addr = htol32(ts & 0xFFFFFFFF); - txdesc->exp_time = dhd->pkt_expiry; + rxcpl_info = &dhd->rxcpl_lat_info; + rssi = (marker & BCMPCIE_RX_PKT_RSSI_MASK); + rxcpl_info->rx_history[rxcpl_info->rxcpl_hist_count].rssi = rssi; + dur = (((marker & BCMPCIE_RX_PKT_DUR0_MASK) >> + BCMPCIE_RX_PKT_DUR0_SHIFT) * RX_LAT_TIME_SCALE); + rxcpl_info->rx_history[rxcpl_info->rxcpl_hist_count].latency = dur; + slice = (marker & BCMPCIE_RX_PKT_BAND_MASK) >> BCMPCIE_RX_PKT_BAND_SHIFT; + rxcpl_info->rx_history[rxcpl_info->rxcpl_hist_count].slice = slice; - DHD_INFO(("%s: metadata_high = 0x%x metadata_low = 0x%x exp_time = %x\n", - __FUNCTION__, txdesc->metadata_buf_addr.high_addr, - txdesc->metadata_buf_addr.low_addr, - txdesc->exp_time)); + prio = ((flags & BCMPCIE_PKT_FLAGS_PRIO_MASK) >> BCMPCIE_PKT_FLAGS_PRIO_SHIFT); + if (prio >= MAX_RX_LAT_PRIO) { + DHD_ERROR(("dhd_update_rxstats:Prio exceeded Max:%d\n", prio)); + return; + } + rxcpl_info->rx_history[rxcpl_info->rxcpl_hist_count].priority = prio; - return; + rx_t0 = rxstatus->rx_status_1; + rxcpl_info->rx_history[rxcpl_info->rxcpl_hist_count].rx_t0 = rx_t0; + + /* store PTM timestamps */ + if (DHD_PTM_CLKID(ts->high)) { + rxcpl_info->rx_history[rxcpl_info->rxcpl_hist_count].ptm_high = ts->high; + rxcpl_info->rx_history[rxcpl_info->rxcpl_hist_count].ptm_low = ts->low; + rxcpl_info->rx_history[rxcpl_info->rxcpl_hist_count].host_time = + (uint32)OSL_SYSUPTIME_US(); + } + + DHD_INFO(("%s:0x%x ptm_high:0x%x, ptm_low:0x%x, t0:0x%x band:%s, prio:%d, rssi:%d, " + "dur:%d useconds\n", __FUNCTION__, marker, ts->high, ts->low, rx_t0, + slice ? "5G":"2G", prio, rssi, dur)); + rxcpl_info->rxcpl_hist_count = + (rxcpl_info->rxcpl_hist_count +1) % MAX_RXCPL_HISTORY; + + dur /= RX_LAT_BIN_SCALE; /* scaled down for each bin */ + if (dur >= MAX_RX_LAT_HIST_BIN) { + dur = MAX_RX_LAT_HIST_BIN -1; + } + if (slice) { + rxcpl_info->rx_dur_5g[prio][dur]++; + } else { + rxcpl_info->rx_dur_2g[prio][dur]++; + } } -#endif /* DHD_HP2P */ #ifdef DHD_MAP_LOGGING void @@ -15447,25 +14722,30 @@ dhd_bus_flow_ring_status_trace(dhd_pub_t *dhd, dhd_frs_trace_t *frs_trace) frs_trace->d2h_tx_cpln_dwr = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_WR_UPD, ring->idx); - if (dhd->prot->h2dring_info_subn != NULL && dhd->prot->d2hring_info_cpln != NULL) { + if ((dhd->prot->h2dring_info_subn != NULL) && (dhd->prot->d2hring_info_cpln != NULL)) { ring = prot->h2dring_info_subn; - frs_trace->h2d_info_post_drd = - dhd_prot_dma_indx_get(dhd, H2D_DMA_INDX_RD_UPD, ring->idx); - frs_trace->h2d_info_post_dwr = - dhd_prot_dma_indx_get(dhd, H2D_DMA_INDX_WR_UPD, ring->idx); - + if (ring->inited) { + frs_trace->h2d_info_post_drd = + dhd_prot_dma_indx_get(dhd, H2D_DMA_INDX_RD_UPD, ring->idx); + frs_trace->h2d_info_post_dwr = + dhd_prot_dma_indx_get(dhd, H2D_DMA_INDX_WR_UPD, ring->idx); + } ring = prot->d2hring_info_cpln; - frs_trace->d2h_info_cpln_drd = - dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_RD_UPD, ring->idx); - frs_trace->d2h_info_cpln_dwr = - dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_WR_UPD, ring->idx); + if (ring->inited) { + frs_trace->d2h_info_cpln_drd = + dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_RD_UPD, ring->idx); + frs_trace->d2h_info_cpln_dwr = + dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_WR_UPD, ring->idx); + } } if (prot->d2hring_edl != NULL) { ring = prot->d2hring_edl; - frs_trace->d2h_ring_edl_drd = - dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_RD_UPD, ring->idx); - frs_trace->d2h_ring_edl_dwr = - dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_WR_UPD, ring->idx); + if (ring->inited) { + frs_trace->d2h_ring_edl_drd = + dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_RD_UPD, ring->idx); + frs_trace->d2h_ring_edl_dwr = + dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_WR_UPD, ring->idx); + } } } @@ -15475,7 +14755,7 @@ dhd_bus_flow_ring_status_isr_trace(dhd_pub_t *dhd) { uint32 cnt = dhd->bus->frs_isr_count % FRS_TRACE_SIZE; dhd_frs_trace_t *frs_isr_trace = &dhd->bus->frs_isr_trace[cnt]; - uint64 time_ns_prev = frs_isr_trace[cnt].timestamp; + uint64 time_ns_prev = frs_isr_trace->timestamp; uint64 time_ns_now = OSL_LOCALTIME_NS(); if ((time_ns_now - time_ns_prev) < 250000) { /* delta less than 250us */ @@ -15493,7 +14773,7 @@ dhd_bus_flow_ring_status_dpc_trace(dhd_pub_t *dhd) { uint32 cnt = dhd->bus->frs_dpc_count % FRS_TRACE_SIZE; dhd_frs_trace_t *frs_dpc_trace = &dhd->bus->frs_dpc_trace[cnt]; - uint64 time_ns_prev = frs_dpc_trace[cnt].timestamp; + uint64 time_ns_prev = frs_dpc_trace->timestamp; uint64 time_ns_now = OSL_LOCALTIME_NS(); if ((time_ns_now - time_ns_prev) < 250000) { /* delta less than 250us */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c old mode 100755 new mode 100644 index 035f51bb50d5..b6dbf528d27d --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c @@ -1,7 +1,7 @@ /* * DHD Bus Module for PCIE * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -39,6 +39,7 @@ #include #include #include +#include #include #if defined(DHD_DEBUG) #include @@ -51,15 +52,18 @@ #include #include #include -#if defined(LINUX) || defined(linux) +#if defined(__linux__) #include -#endif /* LINUX || linux */ +#include +#include +#endif /* __linux__ */ #include #include #include #include #include #include +#include #include #include #ifdef DHDTCPACK_SUPPRESS @@ -68,10 +72,6 @@ #include #include -#ifdef DHD_TIMESYNC -#include -#endif /* DHD_TIMESYNC */ - #ifdef BCM_ROUTER_DHD #include #define STR_END "END\0\0" @@ -85,13 +85,14 @@ #include #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ -#if defined(DEBUGGER) || defined (DHD_DSCOPE) +#if defined(DEBUGGER) || defined(DHD_DSCOPE) #include #endif /* DEBUGGER || DHD_DSCOPE */ -#if defined(FW_SIGNATURE) #include -#include +#if defined(FW_SIGNATURE) +#include +#include #endif /* FW_SIGNATURE */ #ifdef DNGL_AXI_ERROR_LOGGING @@ -164,14 +165,15 @@ extern int qt_flr_reset; #define DHD_RING_MEM_MEMBER_ADDR(bus, ringid, member) \ (bus)->ring_sh[ringid].ring_mem_addr + OFFSETOF(ring_mem_t, member) -#ifdef DHD_REPLACE_LOG_INFO_TO_TRACE -#define DHD_PCIE_INFO DHD_TRACE -#else -#define DHD_PCIE_INFO DHD_INFO -#endif /* DHD_REPLACE_LOG_INFO_TO_TRACE */ +/* Mpu conntrol */ +#define MPU_REG(regs, reg) (&((sysmemregs_t *)regs)->reg) +#define BUS_MPU_ENABLE_MASK 0x1u +#define BUS_MPU_ROM_PR_MASK 0x2u +#define BUS_MPU_VEC_PR_MASK 0x4u +#define BUS_MPU_LOCK_MASK 0x8u #if defined(SUPPORT_MULTIPLE_BOARD_REV) - extern unsigned int system_rev; +extern unsigned int system_rev; #endif /* SUPPORT_MULTIPLE_BOARD_REV */ #ifdef EWP_EDL @@ -213,12 +215,6 @@ static int dhdpcie_bus_dmaxfer_req(struct dhd_bus *bus, uint32 len, uint32 srcdelay, uint32 destdelay, uint32 d11_lpbk, uint32 core_num, uint32 wait, uint32 mem_addr); -#ifdef BCMINTERNAL -static int dhdpcie_bus_set_tx_lpback(struct dhd_bus *bus, bool enable); -static int dhdpcie_bus_get_tx_lpback(struct dhd_bus *bus); -static uint64 serialized_backplane_access_64(dhd_bus_t* bus, uint addr, uint size, uint64* val, - bool read); -#endif /* BCMINTERNAL */ static uint serialized_backplane_access(dhd_bus_t* bus, uint addr, uint size, uint* val, bool read); static int dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter); static int _dhdpcie_download_firmware(struct dhd_bus *bus); @@ -226,6 +222,7 @@ static int dhdpcie_download_firmware(dhd_bus_t *bus, osl_t *osh); #if defined(FW_SIGNATURE) static int dhdpcie_bus_download_fw_signature(dhd_bus_t *bus, bool *do_write); +static int dhdpcie_bus_write_fw_signature(dhd_bus_t *bus); static int dhdpcie_bus_download_ram_bootloader(dhd_bus_t *bus); static int dhdpcie_bus_write_fws_status(dhd_bus_t *bus); static int dhdpcie_bus_write_fws_mem_info(dhd_bus_t *bus); @@ -234,6 +231,7 @@ static int dhdpcie_download_rtlv_end(dhd_bus_t *bus); static int dhdpcie_bus_save_download_info(dhd_bus_t *bus, uint32 download_addr, uint32 download_size, const char *signature_fname, const char *bloader_fname, uint32 bloader_download_addr); +static int dhdpcie_read_fwstatus(dhd_bus_t *bus, bl_verif_status_t *status); #endif /* FW_SIGNATURE */ static int dhdpcie_bus_write_vars(dhd_bus_t *bus); @@ -248,7 +246,6 @@ static void dhdpcie_bus_release_dongle(dhd_bus_t *bus, osl_t *osh, static void dhdpcie_bus_release_malloc(dhd_bus_t *bus, osl_t *osh); static int dhdpcie_downloadvars(dhd_bus_t *bus, void *arg, int len); static void dhdpcie_setbar1win(dhd_bus_t *bus, uint32 addr); -static void dhd_init_bar1_switch_lock(dhd_bus_t *bus); static void dhd_deinit_bar1_switch_lock(dhd_bus_t *bus); static void dhd_init_pwr_req_lock(dhd_bus_t *bus); static void dhd_deinit_pwr_req_lock(dhd_bus_t *bus); @@ -269,6 +266,14 @@ static uint64 dhdpcie_bus_rtcm64(dhd_bus_t *bus, ulong offset) __attribute__ ((u static void dhdpcie_bus_cfg_set_bar0_win(dhd_bus_t *bus, uint32 data); static void dhdpcie_bus_reg_unmap(osl_t *osh, volatile char *addr, int size); static int dhdpcie_cc_nvmshadow(dhd_bus_t *bus, struct bcmstrbuf *b); +static void dhd_bus_dump_rxlat_info(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); +static void dhd_bus_dump_rxlat_histo(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); +static void dhd_bus_dump_txcpl_info(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); +static void dhd_bus_dump_mdring_info(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); +static bool dhd_bus_support_dar_sec_status(dhd_bus_t *bus); +static int dhd_bus_security_info(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); +static int dhd_bus_sboot_disable(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); +static int dhd_bus_get_security_status(dhd_bus_t *bus, uint32 *status); static void dhdpcie_fw_trap(dhd_bus_t *bus); static void dhd_fillup_ring_sharedptr_info(dhd_bus_t *bus, ring_info_t *ring_info); static void dhdpcie_handle_mb_data(dhd_bus_t *bus); @@ -282,9 +287,6 @@ static void dhd_bus_ds_trace(dhd_bus_t *bus, uint32 dsval, bool d2h); #ifdef DHD_MMIO_TRACE static void dhd_bus_mmio_trace(dhd_bus_t *bus, uint32 addr, uint32 value, bool set); #endif /* defined(DHD_MMIO_TRACE) */ -#if defined(LINUX) || defined(linux) -extern void dhd_dpc_kill(dhd_pub_t *dhdp); -#endif /* LINUX || linux */ #ifdef IDLE_TX_FLOW_MGMT static void dhd_bus_check_idle_scan(dhd_bus_t *bus); @@ -297,7 +299,7 @@ static int dhdpcie_download_code_array(dhd_bus_t *bus); #ifdef BCM_ROUTER_DHD extern char * nvram_get(const char *name); #endif -#if defined(BCMEMBEDIMAGE) && defined (BCM_ROUTER_DHD) +#if defined(BCMEMBEDIMAGE) && defined(BCM_ROUTER_DHD) static void select_fd_image( struct dhd_bus *bus, unsigned char **p_dlarray, char **p_dlimagename, char **p_dlimagever, @@ -308,10 +310,6 @@ static void select_fd_image( int dbushost_initvars_flash(si_t *sih, osl_t *osh, char **base, uint len); #endif -#ifdef EXYNOS_PCIE_DEBUG -extern void exynos_pcie_register_dump(int ch_num); -#endif /* EXYNOS_PCIE_DEBUG */ - #if defined(DHD_H2D_LOG_TIME_SYNC) static void dhdpci_bus_rte_log_time_sync_poll(dhd_bus_t *bus); #endif /* DHD_H2D_LOG_TIME_SYNC */ @@ -338,22 +336,12 @@ static int dhdpcie_init_d11status(struct dhd_bus *bus); static int dhdpcie_wrt_rnd(struct dhd_bus *bus); -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE -#include -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ - -#ifdef DHD_HP2P -extern enum hrtimer_restart dhd_hp2p_write(struct hrtimer *timer); -static uint16 dhd_bus_set_hp2p_ring_max_size(struct dhd_bus *bus, bool tx, uint16 val); -#endif #if defined(linux) || defined(LINUX) -#ifdef DHD_FW_MEM_CORRUPTION -#define NUM_PATTERNS 2 -#else +#if !defined(DHD_FW_MEM_CORRUPTION) && defined(BCM4375_CHIP) #define NUM_PATTERNS 6 -#endif /* DHD_FW_MEM_CORRUPTION */ +#else +#define NUM_PATTERNS 2 +#endif /* !DHD_FW_MEM_CORRUPTION && BCM4375_CHIP */ static bool dhd_bus_tcm_test(struct dhd_bus *bus); #endif /* LINUX || linux */ @@ -362,6 +350,12 @@ static int dhd_bus_dump_fws(dhd_bus_t *bus, struct bcmstrbuf *strbuf); #endif static void dhdpcie_pme_stat_clear(dhd_bus_t *bus); +static int dhdpcie_download_rtlv(dhd_bus_t *bus, dngl_rtlv_type_t type, dngl_rtlv_len_t len, + uint8 *value); +#if defined(SUPPORT_MULTIPLE_BOARD_REVISION) +extern void concate_custom_board_revision(char *nv_path); +#endif /* SUPPORT_MULTIPLE_BOARD_REVISION */ + /* IOVar table */ enum { IOV_INTR = 1, @@ -379,9 +373,6 @@ enum { IOV_RAMSIZE, IOV_RAMSTART, IOV_SLEEP_ALLOWED, -#ifdef BCMINTERNAL - IOV_PCIE_TX_LPBK, -#endif /* BCMINTERNAL */ IOV_PCIE_DMAXFER, IOV_PCIE_SUSPEND, #ifdef DHD_PCIE_REG_ACCESS @@ -405,20 +396,25 @@ enum { IOV_FORCE_FW_TRAP, IOV_DB1_FOR_MB, IOV_FLOW_PRIO_MAP, -#ifdef DHD_PCIE_RUNTIMEPM - IOV_IDLETIME, -#endif /* DHD_PCIE_RUNTIMEPM */ - IOV_RXBOUND, - IOV_TXBOUND, + IOV_RX_CPL_POST_BOUND, + IOV_TX_CPL_BOUND, + IOV_CTRL_CPL_POST_BOUND, + IOV_TX_POST_BOUND, IOV_HANGREPORT, IOV_H2D_MAILBOXDATA, IOV_INFORINGS, IOV_H2D_PHASE, IOV_H2D_ENABLE_TRAP_BADPHASE, + IOV_RING_SIZE_VER, IOV_H2D_TXPOST_MAX_ITEM, -#if defined(DHD_HTPUT_TUNABLES) IOV_H2D_HTPUT_TXPOST_MAX_ITEM, -#endif /* DHD_HTPUT_TUNABLES */ + IOV_D2H_TXCPL_MAX_ITEM, + IOV_H2D_RXPOST_MAX_ITEM, + IOV_D2H_RXCPL_MAX_ITEM, + IOV_H2D_CTRLPOST_MAX_ITEM, + IOV_D2H_CTRLCPL_MAX_ITEM, + IOV_RX_BUF_BURST, + IOV_RX_BUFPOST_THRESHOLD, IOV_TRAPDATA, IOV_TRAPDATA_RAW, IOV_CTO_PREVENTION, @@ -431,14 +427,6 @@ enum { #endif /* DEVICE_TX_STUCK_DETECT */ IOV_PCIE_WD_RESET, IOV_DUMP_DONGLE, -#ifdef DHD_EFI - IOV_WIFI_PROPERTIES, - IOV_CONTROL_SIGNAL, - IOV_OTP_DUMP, -#ifdef BT_OVER_PCIE - IOV_BTOP_TEST, -#endif -#endif /* DHD_EFI */ IOV_IDMA_ENABLE, IOV_IFRM_ENABLE, IOV_CLEAR_RING, @@ -459,19 +447,10 @@ enum { #ifdef D2H_MINIDUMP IOV_MINIDUMP_OVERRIDE, #endif /* D2H_MINIDUMP */ -#ifdef BCMINTERNAL - IOV_DMA_CHAN, - IOV_HYBRIDFW, -#endif /* BCMINTERNAL */ IOV_HSCBSIZE, /* get HSCB buffer size */ #ifdef DHD_BUS_MEM_ACCESS IOV_HSCBBYTES, /* copy HSCB buffer */ #endif -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE - IOV_FWTRACE, /* Enable/disable firmware tracing */ -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ IOV_HP2P_ENABLE, IOV_HP2P_PKT_THRESHOLD, IOV_HP2P_TIME_THRESHOLD, @@ -480,10 +459,20 @@ enum { IOV_HP2P_RXCPL_MAXITEMS, IOV_EXTDTXS_IN_TXCPL, IOV_HOSTRDY_AFTER_INIT, -#ifdef BCMINTERNAL - IOV_SBREG_64, -#endif /* BCMINTERNAL */ IOV_HP2P_MF_ENABLE, + + IOV_DONGLE_RXLAT_INFO, + IOV_DONGLE_RXLAT_HISTO, + IOV_DONGLE_TXCPL_INFO, + IOV_DONGLE_SEC_INFO, + IOV_DONGLE_SBOOT_DIS, + IOV_LPM_MODE, + IOV_MDRING_LINK, + IOV_MDRING_UNLINK, + IOV_MDRING_DUMP, + IOV_PTM_ENABLE, + IOV_PCIE_DMAXFER_PTRN, + IOV_PCIE_LAST /**< unused IOVAR */ }; @@ -500,9 +489,6 @@ const bcm_iovar_t dhdpcie_iovars[] = { {"devreset", IOV_DEVRESET, 0, 0, IOVT_UINT8, 0 }, {"pcie_device_trap", IOV_FORCE_FW_TRAP, 0, 0, 0, 0 }, {"pcie_lpbk", IOV_PCIE_LPBK, 0, 0, IOVT_UINT32, 0 }, -#ifdef BCMINTERNAL - {"msi_sim", IOV_MSI_SIM, 0, 0, IOVT_BOOL, 0 }, -#endif /* BCMINTERNAL */ {"cc_nvmshadow", IOV_CC_NVMSHADOW, 0, 0, IOVT_BUFFER, 0 }, {"ramsize", IOV_RAMSIZE, 0, 0, IOVT_UINT32, 0 }, {"ramstart", IOV_RAMSTART, 0, 0, IOVT_UINT32, 0 }, @@ -514,10 +500,8 @@ const bcm_iovar_t dhdpcie_iovars[] = { {"bar0secwinreg", IOV_BAR0_SECWIN_REG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) }, {"sbreg", IOV_SBREG, 0, 0, IOVT_BUFFER, sizeof(uint8) }, #endif /* DHD_PCIE_REG_ACCESS */ -#ifdef BCMINTERNAL - {"pcie_tx_lpbk", IOV_PCIE_TX_LPBK, 0, 0, IOVT_UINT32, 0 }, -#endif /* BCMINTERNAL */ {"pcie_dmaxfer", IOV_PCIE_DMAXFER, 0, 0, IOVT_BUFFER, sizeof(dma_xfer_info_t)}, + {"lpbk_dmaxfer_data_pattern", IOV_PCIE_DMAXFER_PTRN, 0, 0, IOVT_UINT32, 0}, {"pcie_suspend", IOV_PCIE_SUSPEND, DHD_IOVF_PWRREQ_BYPASS, 0, IOVT_UINT32, 0 }, #ifdef PCIE_OOB {"oob_bt_reg_on", IOV_OOB_BT_REG_ON, 0, 0, IOVT_UINT32, 0 }, @@ -535,11 +519,10 @@ const bcm_iovar_t dhdpcie_iovars[] = { {"txp_thresh", IOV_TXP_THRESHOLD, 0, 0, IOVT_UINT32, 0 }, {"buzzz_dump", IOV_BUZZZ_DUMP, 0, 0, IOVT_UINT32, 0 }, {"flow_prio_map", IOV_FLOW_PRIO_MAP, 0, 0, IOVT_UINT32, 0 }, -#ifdef DHD_PCIE_RUNTIMEPM - {"idletime", IOV_IDLETIME, 0, 0, IOVT_INT32, 0 }, -#endif /* DHD_PCIE_RUNTIMEPM */ - {"rxbound", IOV_RXBOUND, 0, 0, IOVT_UINT32, 0 }, - {"txbound", IOV_TXBOUND, 0, 0, IOVT_UINT32, 0 }, + {"rx_cpl_post_bound", IOV_RX_CPL_POST_BOUND, 0, 0, IOVT_UINT32, 0 }, + {"tx_cpl_bound", IOV_TX_CPL_BOUND, 0, 0, IOVT_UINT32, 0 }, + {"ctrl_cpl_post_bound", IOV_CTRL_CPL_POST_BOUND, 0, 0, IOVT_UINT32, 0 }, + {"tx_post_bound", IOV_TX_POST_BOUND, 0, 0, IOVT_UINT32, 0 }, #ifdef DHD_PCIE_REG_ACCESS {"aspm", IOV_PCIEASPM, 0, 0, IOVT_INT32, 0 }, #endif /* DHD_PCIE_REG_ACCESS */ @@ -549,10 +532,16 @@ const bcm_iovar_t dhdpcie_iovars[] = { {"h2d_phase", IOV_H2D_PHASE, 0, 0, IOVT_UINT32, 0 }, {"force_trap_bad_h2d_phase", IOV_H2D_ENABLE_TRAP_BADPHASE, 0, 0, IOVT_UINT32, 0 }, + {"ring_size_ver", IOV_RING_SIZE_VER, 0, 0, IOVT_UINT32, 0 }, {"h2d_max_txpost", IOV_H2D_TXPOST_MAX_ITEM, 0, 0, IOVT_UINT32, 0 }, -#if defined(DHD_HTPUT_TUNABLES) {"h2d_htput_max_txpost", IOV_H2D_HTPUT_TXPOST_MAX_ITEM, 0, 0, IOVT_UINT32, 0 }, -#endif /* DHD_HTPUT_TUNABLES */ + {"d2h_max_txcpl", IOV_D2H_TXCPL_MAX_ITEM, 0, 0, IOVT_UINT32, 0 }, + {"h2d_max_rxpost", IOV_H2D_RXPOST_MAX_ITEM, 0, 0, IOVT_UINT32, 0 }, + {"d2h_max_rxcpl", IOV_D2H_RXCPL_MAX_ITEM, 0, 0, IOVT_UINT32, 0 }, + {"h2d_max_ctrlpost", IOV_H2D_CTRLPOST_MAX_ITEM, 0, 0, IOVT_UINT32, 0 }, + {"d2h_max_ctrlcpl", IOV_D2H_CTRLCPL_MAX_ITEM, 0, 0, IOVT_UINT32, 0 }, + {"rx_buf_burst", IOV_RX_BUF_BURST, 0, 0, IOVT_UINT32, 0 }, + {"rx_bufpost_threshold", IOV_RX_BUFPOST_THRESHOLD, 0, 0, IOVT_UINT32, 0 }, {"trap_data", IOV_TRAPDATA, 0, 0, IOVT_BUFFER, 0 }, {"trap_data_raw", IOV_TRAPDATA_RAW, 0, 0, IOVT_BUFFER, 0 }, {"cto_prevention", IOV_CTO_PREVENTION, 0, 0, IOVT_UINT32, 0 }, @@ -563,14 +552,6 @@ const bcm_iovar_t dhdpcie_iovars[] = { {"dump_dongle", IOV_DUMP_DONGLE, 0, 0, IOVT_BUFFER, MAX(sizeof(dump_dongle_in_t), sizeof(dump_dongle_out_t))}, {"clear_ring", IOV_CLEAR_RING, 0, 0, IOVT_UINT32, 0 }, -#ifdef DHD_EFI - {"properties", IOV_WIFI_PROPERTIES, 0, 0, IOVT_BUFFER, 0}, - {"otp_dump", IOV_OTP_DUMP, 0, 0, IOVT_BUFFER, 0}, - {"control_signal", IOV_CONTROL_SIGNAL, 0, 0, IOVT_UINT32, 0}, -#ifdef BT_OVER_PCIE - {"btop_test", IOV_BTOP_TEST, 0, 0, IOVT_UINT32, 0}, -#endif -#endif /* DHD_EFI */ {"idma_enable", IOV_IDMA_ENABLE, 0, 0, IOVT_UINT32, 0 }, {"ifrm_enable", IOV_IFRM_ENABLE, 0, 0, IOVT_UINT32, 0 }, {"dar_enable", IOV_DAR_ENABLE, 0, 0, IOVT_UINT32, 0 }, @@ -590,48 +571,39 @@ const bcm_iovar_t dhdpcie_iovars[] = { #ifdef D2H_MINIDUMP {"minidump_override", IOV_MINIDUMP_OVERRIDE, 0, 0, IOVT_UINT32, 0 }, #endif /* D2H_MINIDUMP */ -#ifdef BCMINTERNAL - {"dma_chan_db0", IOV_DMA_CHAN, 0, 0, IOVT_UINT32, 0 }, - {"hybridfw", IOV_HYBRIDFW, 0, 0, IOVT_BUFFER, 0 }, -#endif /* BCMINTERNAL */ {"hscbsize", IOV_HSCBSIZE, 0, 0, IOVT_UINT32, 0 }, #ifdef DHD_BUS_MEM_ACCESS {"hscbbytes", IOV_HSCBBYTES, 0, 0, IOVT_BUFFER, 2 * sizeof(int32) }, #endif -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE - {"fwtrace", IOV_FWTRACE, 0, 0, IOVT_UINT32, 0 }, -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ - -#ifdef DHD_HP2P - {"hp2p_enable", IOV_HP2P_ENABLE, 0, 0, IOVT_UINT32, 0 }, - {"hp2p_pkt_thresh", IOV_HP2P_PKT_THRESHOLD, 0, 0, IOVT_UINT32, 0 }, - {"hp2p_time_thresh", IOV_HP2P_TIME_THRESHOLD, 0, 0, IOVT_UINT32, 0 }, - {"hp2p_pkt_expiry", IOV_HP2P_PKT_EXPIRY, 0, 0, IOVT_UINT32, 0 }, - {"hp2p_txcpl_maxitems", IOV_HP2P_TXCPL_MAXITEMS, 0, 0, IOVT_UINT32, 0 }, - {"hp2p_rxcpl_maxitems", IOV_HP2P_RXCPL_MAXITEMS, 0, 0, IOVT_UINT32, 0 }, -#endif /* DHD_HP2P */ {"extdtxs_in_txcpl", IOV_EXTDTXS_IN_TXCPL, 0, 0, IOVT_UINT32, 0 }, {"hostrdy_after_init", IOV_HOSTRDY_AFTER_INIT, 0, 0, IOVT_UINT32, 0 }, -#ifdef BCMINTERNAL - {"sbreg_64", IOV_SBREG_64, 0, 0, IOVT_BUFFER, sizeof(uint8) }, -#endif /* BCMINTERNAL */ {"hp2p_mf_enable", IOV_HP2P_MF_ENABLE, 0, 0, IOVT_UINT32, 0 }, + + {"dump_rxlat", IOV_DONGLE_RXLAT_INFO, 0, 0, IOVT_BUFFER, + sizeof(rx_cpl_history_t) * MAX_RXCPL_HISTORY + 128 }, + {"dump_rxlat_hist", IOV_DONGLE_RXLAT_HISTO, 0, 0, IOVT_BUFFER, + (MAX_RX_LAT_PRIO * MAX_RX_LAT_HIST_BIN * 2) + 128 }, + {"lpm_mode", IOV_LPM_MODE, 0, 0, IOVT_UINT32, 0 }, + + {"dump_txcpl", IOV_DONGLE_TXCPL_INFO, 0, 0, IOVT_BUFFER, + sizeof(tx_cpl_history_t) * MAX_TXCPL_HISTORY + 128 }, + + {"security_status", IOV_DONGLE_SEC_INFO, 0, 0, IOVT_BUFFER, + sizeof(tx_cpl_history_t) * MAX_TXCPL_HISTORY + 128 }, + + {"sboot_disable", IOV_DONGLE_SBOOT_DIS, 0, 0, IOVT_BUFFER, + sizeof(tx_cpl_history_t) * MAX_TXCPL_HISTORY + 128 }, + + {"mdring_link", IOV_MDRING_LINK, 0, 0, IOVT_UINT32, 0 }, + {"mdring_unlink", IOV_MDRING_UNLINK, 0, 0, IOVT_UINT32, 0 }, + {"dump_mdring", IOV_MDRING_DUMP, 0, 0, IOVT_BUFFER, + MAX_MDRING_ITEM_DUMP * D2HRING_MDCMPLT_ITEMSIZE }, + {"ptm_enable", IOV_PTM_ENABLE, 0, 0, IOVT_UINT32, 0 }, + {NULL, 0, 0, 0, 0, 0 } }; -#ifdef BCMINTERNAL -#define MSI_SIM_BUFSIZE 64 -#define PCIE_CFG_MSICAP_OFFSET 0x58 -#define PCIE_CFG_MSIADDR_LOW_OFFSET 0x5C -#define PCIE_CFG_MSIDATA_OFFSET 0x64 -#define PCIE_CFG_MSI_GENDATA 0x5678 -#define PCIE_CFG_MSICAP_ENABLE_MSI 0x816805 -#define PCIE_CFG_MSICAP_DISABLE_MSI 0x806805 -#endif - #ifdef BCMQT_HW #define MAX_READ_TIMEOUT 100 * 1000 /* 100 ms in dongle time */ #elif defined(NDIS) @@ -640,19 +612,9 @@ const bcm_iovar_t dhdpcie_iovars[] = { #define MAX_READ_TIMEOUT 2 * 1000 * 1000 #endif -#ifndef DHD_RXBOUND -#define DHD_RXBOUND 64 -#endif -#ifndef DHD_TXBOUND -#define DHD_TXBOUND 64 -#endif - #define DHD_INFORING_BOUND 32 #define DHD_BTLOGRING_BOUND 32 -uint dhd_rxbound = DHD_RXBOUND; -uint dhd_txbound = DHD_TXBOUND; - #if defined(DEBUGGER) || defined(DHD_DSCOPE) /** the GDB debugger layer will call back into this (bus) layer to read/write dongle memory */ static struct dhd_gdb_bus_ops_s bus_ops = { @@ -713,35 +675,29 @@ dhd_bus_db0_addr_get(struct dhd_bus *bus) uint addr = PCIH2D_MailBox; uint dar_addr = DAR_PCIH2D_DB0_0(bus->sih->buscorerev); -#ifdef BCMINTERNAL - if (bus->dma_chan == 1) { - addr = PCIH2D_MailBox_1; - dar_addr = DAR_PCIH2D_DB1_0(bus->sih->buscorerev); - } else if (bus->dma_chan == 2) { - addr = PCIH2D_MailBox_2; - dar_addr = DAR_PCIH2D_DB2_0(bus->sih->buscorerev); - } -#endif /* BCMINTERNAL */ - + /* Note: For DAR doorbell registers, the values is invalid. */ return ((DAR_ACTIVE(bus->dhd)) ? dar_addr : addr); } static INLINE uint dhd_bus_db0_addr_2_get(struct dhd_bus *bus) { + /* Note: For DAR doorbell registers, the values is invalid. */ return ((DAR_ACTIVE(bus->dhd)) ? DAR_PCIH2D_DB2_0(bus->sih->buscorerev) : PCIH2D_MailBox_2); } static INLINE uint dhd_bus_db1_addr_get(struct dhd_bus *bus) { - return ((DAR_ACTIVE(bus->dhd)) ? DAR_PCIH2D_DB0_1(bus->sih->buscorerev) : PCIH2D_DB1); + /* Note: For DB1, don't use DAR register */ + return PCIH2D_DB1; } static INLINE uint dhd_bus_db1_addr_3_get(struct dhd_bus *bus) { - return ((DAR_ACTIVE(bus->dhd)) ? DAR_PCIH2D_DB3_1(bus->sih->buscorerev) : PCIH2D_DB1_3); + /* Note: For DB7, don't use DAR register */ + return PCIH2D_DB1_3; } static void @@ -958,13 +914,15 @@ dhdpcie_chip_support_msi(dhd_bus_t *bus) DHD_INFO(("%s: buscorerev=%d chipid=0x%x\n", __FUNCTION__, bus->sih->buscorerev, si_chipid(bus->sih))); if (bus->sih->buscorerev <= 14 || - si_chipid(bus->sih) == BCM4389_CHIP_ID || + si_chipid(bus->sih) == BCM4381_CHIP_ID || + si_chipid(bus->sih) == BCM4382_CHIP_ID || si_chipid(bus->sih) == BCM4385_CHIP_ID || si_chipid(bus->sih) == BCM4375_CHIP_ID || si_chipid(bus->sih) == BCM4376_CHIP_ID || si_chipid(bus->sih) == BCM4362_CHIP_ID || si_chipid(bus->sih) == BCM43751_CHIP_ID || si_chipid(bus->sih) == BCM43752_CHIP_ID || + si_chipid(bus->sih) == BCM43756_CHIP_ID || si_chipid(bus->sih) == BCM4361_CHIP_ID || si_chipid(bus->sih) == BCM4359_CHIP_ID) { return FALSE; @@ -1007,9 +965,6 @@ int dhdpcie_bus_attach(osl_t *osh, dhd_bus_t **bus_ptr, /* Save pci_dev into dhd_bus, as it may be needed in dhd_attach */ bus->dev = (struct pci_dev *)pci_dev; #endif -#ifdef DHD_EFI - bus->pcie_dev = pci_dev; -#endif dll_init(&bus->flowring_active_list); #ifdef IDLE_TX_FLOW_MGMT @@ -1064,9 +1019,6 @@ int dhdpcie_bus_attach(osl_t *osh, dhd_bus_t **bus_ptr, /* update force trap on bad phase if set through module parameter */ bus->dhd->force_dongletrap_on_bad_h2d_phase = force_trap_bad_h2d_phase ? TRUE : FALSE; -#ifdef BTLOG - bus->dhd->bt_logging_enabled = TRUE; -#endif #ifdef IDLE_TX_FLOW_MGMT bus->enable_idle_flowring_mgmt = FALSE; #endif /* IDLE_TX_FLOW_MGMT */ @@ -1081,17 +1033,17 @@ int dhdpcie_bus_attach(osl_t *osh, dhd_bus_t **bus_ptr, bus->d2h_intr_method = PCIE_INTX; #endif /* DHD_MSI_SUPPORT */ +#ifdef NDIS + /* For NDIS use D2H INTMASK based control */ + bus->d2h_intr_control = PCIE_D2H_INTMASK_CTRL; +#else /* For MSI, use host irq based control and for INTX use D2H INTMASK based control */ if (bus->d2h_intr_method == PCIE_MSI) { bus->d2h_intr_control = PCIE_HOST_IRQ_CTRL; } else { bus->d2h_intr_control = PCIE_D2H_INTMASK_CTRL; } - -#ifdef DHD_HP2P - bus->hp2p_txcpl_max_items = DHD_MAX_ITEMS_HPP_TXCPL_RING; - bus->hp2p_rxcpl_max_items = DHD_MAX_ITEMS_HPP_RXCPL_RING; -#endif /* DHD_HP2P */ +#endif /* NDIS */ DHD_TRACE(("%s: EXIT SUCCESS\n", __FUNCTION__)); @@ -1101,14 +1053,6 @@ int dhdpcie_bus_attach(osl_t *osh, dhd_bus_t **bus_ptr, } while (0); DHD_TRACE(("%s: EXIT FAILURE\n", __FUNCTION__)); -#ifdef DHD_EFI - /* for EFI even if there is an error, load still succeeds - * so 'bus' should not be freed here, it is freed during unload - */ - if (bus) { - *bus_ptr = bus; - } -#else if (bus && bus->pcie_sh) { MFREE(osh, bus->pcie_sh, sizeof(pciedev_shared_t)); } @@ -1116,7 +1060,6 @@ int dhdpcie_bus_attach(osl_t *osh, dhd_bus_t **bus_ptr, if (bus) { MFREE(osh, bus, sizeof(dhd_bus_t)); } -#endif /* DHD_EFI */ return ret; } @@ -1238,7 +1181,7 @@ dhd_bus_query_dpc_sched_errors(dhd_pub_t *dhdp) dhd_bus_t *bus = dhdp->bus; bool sched_err; - if (bus->dpc_entry_time < bus->isr_exit_time) { + if ((bus->dpc_entry_time < bus->isr_exit_time) && bus->dpc_sched) { /* Kernel doesn't schedule the DPC after processing PCIe IRQ */ sched_err = TRUE; } else if (bus->dpc_entry_time < bus->resched_dpc_time) { @@ -1253,17 +1196,21 @@ dhd_bus_query_dpc_sched_errors(dhd_pub_t *dhdp) if (sched_err) { /* print out minimum timestamp info */ DHD_ERROR(("isr_entry_time="SEC_USEC_FMT + " prev_isr_entry_time="SEC_USEC_FMT " isr_exit_time="SEC_USEC_FMT " dpc_entry_time="SEC_USEC_FMT "\ndpc_exit_time="SEC_USEC_FMT " isr_sched_dpc_time="SEC_USEC_FMT - " resched_dpc_time="SEC_USEC_FMT"\n", + " resched_dpc_time="SEC_USEC_FMT + " dpc_sched=%u\n", GET_SEC_USEC(bus->isr_entry_time), + GET_SEC_USEC(bus->prev_isr_entry_time), GET_SEC_USEC(bus->isr_exit_time), GET_SEC_USEC(bus->dpc_entry_time), GET_SEC_USEC(bus->dpc_exit_time), GET_SEC_USEC(bus->isr_sched_dpc_time), - GET_SEC_USEC(bus->resched_dpc_time))); + GET_SEC_USEC(bus->resched_dpc_time), + bus->dpc_sched)); } return sched_err; @@ -1277,11 +1224,7 @@ dhdpcie_bus_intstatus(dhd_bus_t *bus) uint32 intmask = 0; if (__DHD_CHK_BUS_LPS_D3_ACKED(bus)) { -#ifdef DHD_EFI - DHD_INFO(("%s: trying to clear intstatus after D3 Ack\n", __FUNCTION__)); -#else DHD_ERROR(("%s: trying to clear intstatus after D3 Ack\n", __FUNCTION__)); -#endif /* !DHD_EFI */ return intstatus; } /* XXX: check for PCIE Gen2 also */ @@ -1307,20 +1250,6 @@ dhdpcie_bus_intstatus(dhd_bus_t *bus) __FUNCTION__, intstatus, intmask)); bus->is_linkdown = TRUE; dhd_pcie_debug_info_dump(bus->dhd); -#ifdef CUSTOMER_HW4_DEBUG -#if defined(OEM_ANDROID) -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - bus->dhd->hang_reason = HANG_REASON_PCIE_LINK_DOWN_EP_DETECT; -#ifdef WL_CFGVENDOR_SEND_HANG_EVENT - copy_hang_info_linkdown(bus->dhd); -#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */ - dhd_os_send_hang_message(bus->dhd); -#endif /* OEM_ANDROID */ -#endif /* CUSTOMER_HW4_DEBUG */ return intstatus; } @@ -1357,6 +1286,21 @@ dhdpcie_cto_recovery_handler(dhd_pub_t *dhd) dhd_bus_t *bus = dhd->bus; int ret; + if (dhd->up == FALSE) { + DHD_ERROR(("%s : dhd is not up\n", __FUNCTION__)); + return; + } + + if (bus->is_linkdown) { + DHD_ERROR(("%s: link is down\n", __FUNCTION__)); + return; + } + + if (bus->sih == NULL) { + DHD_ERROR(("%s: The address of sih is invalid\n", __FUNCTION__)); + return; + } + /* Disable PCIe Runtime PM to avoid D3_ACK timeout. */ DHD_DISABLE_RUNTIME_PM(dhd); @@ -1390,11 +1334,6 @@ dhdpcie_cto_recovery_handler(dhd_pub_t *dhd) #endif /* DHD_FW_COREDUMP */ } #ifdef OEM_ANDROID -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ bus->is_linkdown = TRUE; bus->dhd->hang_reason = HANG_REASON_PCIE_CTO_DETECT; /* Send HANG event */ @@ -1470,16 +1409,28 @@ dhdpcie_bus_isr(dhd_bus_t *bus) break; } + /* Do not process any ISR after receiving D3_ACK */ + if (__DHD_CHK_BUS_LPS_D3_ACKED(bus)) { + DHD_LOG_MEM(("%s: D3 Ack Received, skip\n", __FUNCTION__)); + break; + } + if (PCIECTO_ENAB(bus)) { /* read pci_intstatus */ intstatus = dhdpcie_bus_cfg_read_dword(bus, PCI_INT_STATUS, 4); - if (intstatus == (uint32)-1) { - DHD_ERROR(("%s : Invalid intstatus for cto recovery\n", - __FUNCTION__)); + if (intstatus == (uint32)-1 || + bus->dhd->dhd_induce_error == DHD_INDUCE_PCIE_LINK_DOWN_IN_ISR) { + DHD_ERROR(("%s: Invalid cfg intstatus(0x%x):0x%x, pcie link down," + "induce %u\n", __FUNCTION__, PCI_INT_STATUS, intstatus, + bus->dhd->dhd_induce_error)); bus->is_linkdown = 1; dhdpcie_disable_irq_nosync(bus); - dhd_prot_debug_info_print(bus->dhd); + dhd_pcie_debug_info_dump(bus->dhd); +#ifdef OEM_ANDROID + bus->dhd->hang_reason = HANG_REASON_PCIE_LINK_DOWN_EP_DETECT; + dhd_os_send_hang_message(bus->dhd); +#endif /* OEM_ANDROID */ break; } @@ -1488,6 +1439,7 @@ dhdpcie_bus_isr(dhd_bus_t *bus) "intstat=0x%x enab=%d\n", __FUNCTION__, intstatus, bus->cto_enable)); bus->cto_triggered = 1; + bus->dhd->do_chip_bighammer = TRUE; dhd_bus_dump_imp_cfg_registers(bus); /* * DAR still accessible @@ -1508,13 +1460,13 @@ dhdpcie_bus_isr(dhd_bus_t *bus) } } +#ifndef DHD_READ_INTSTATUS_IN_DPC if (bus->d2h_intr_method == PCIE_MSI && !dhd_conf_legacy_msi_chip(bus->dhd)) { /* For MSI, as intstatus is cleared by firmware, no need to read */ goto skip_intstatus_read; } -#ifndef DHD_READ_INTSTATUS_IN_DPC intstatus = dhdpcie_bus_intstatus(bus); /* Check if the interrupt is ours or not */ @@ -1551,17 +1503,17 @@ skip_intstatus_read: bus->ipend = TRUE; - bus->isr_intr_disable_count++; - - if (bus->d2h_intr_control == PCIE_D2H_INTMASK_CTRL) { - dhdpcie_bus_intr_disable(bus); /* Disable interrupt using IntMask!! */ + /* Due to irq mismatch WARNING in linux, currently keeping it disabled and + * using dongle intmask to control INTR enable/disable + */ + if (bus->d2h_intr_control == PCIE_HOST_IRQ_CTRL) { + if (!dhdpcie_irq_disabled(bus)) { + bus->host_irq_disable_count++; + dhdpcie_disable_irq_nosync(bus); /* Disable interrupt!! */ + } } else { - /* For Linux, Macos etc (otherthan NDIS) instead of disabling - * dongle interrupt by clearing the IntMask, disable directly - * interrupt from the host side, so that host will not recieve - * any interrupts at all, even though dongle raises interrupts - */ - dhdpcie_disable_irq_nosync(bus); /* Disable interrupt!! */ + dhdpcie_bus_intr_disable(bus); /* Disable interrupt using IntMask!! */ + bus->dngl_intmask_disable_count++; } bus->intdis = TRUE; @@ -1831,6 +1783,27 @@ dhdpcie_dongle_reset(dhd_bus_t *bus) } #ifdef BCMQT_HW +/* Xtal to ALP clock ratio can change from chip to chip and this functions returns the + * Xtal to ALP clock ratio by extracting the value for the current chip. + */ +static uint32 +dhdpcie_get_xtal_to_alp_ratio(dhd_bus_t *bus) +{ + uint16 chipid = si_chipid(bus->sih); + uint32 xtal_to_alp_ratio; + + switch (chipid) { + case BCM4397_CHIP_ID: + xtal_to_alp_ratio = 2; + break; + default: + xtal_to_alp_ratio = 1; + break; + } + + return xtal_to_alp_ratio; +} + /* Calculate dongle/host clock ratio for QT so the waiting period in host driver can be scaled * properly. The dongle uses ALP clock by default which can't be read directly. But ILP and * ALP clocks are scaled disproportionally in QT. So DHD must know the preset crystal frequency @@ -1846,9 +1819,11 @@ dhdpcie_dongle_reset(dhd_bus_t *bus) #define XTAL_FREQ_37M4 37400000u void dhdpcie_htclkratio_cal(dhd_bus_t *bus) { - uint cur_coreidx, pmu_idx; - uint32 ilp_start, ilp_tick, xtal_ratio; + uint cur_coreidx, pmu_idx, ilp_on_fast_lpo = 0; + uint32 ilp_start, ilp_tick = 0, alp_to_ilp_ratio = 0; int xtalfreq = 0; + uint32 alp_freq = 0; + uint32 xtal_to_alp_ratio = dhdpcie_get_xtal_to_alp_ratio(bus); /* If a larger than 1 htclkratio is set through module parameter, use it directly */ if (htclkratio > 1) { @@ -1871,9 +1846,23 @@ void dhdpcie_htclkratio_cal(dhd_bus_t *bus) /* -1 to compensate the incomplete cycle at the beginning */ ilp_tick -= ilp_start - 1; + ilp_on_fast_lpo = si_corereg(bus->sih, pmu_idx, offsetof(pmuregs_t, pmustatus), 0, 0) & + PST_ILPFASTLPO; + + if (PMUREV(bus->sih->pmurev) <= 45) { + /* If ILP is running on Fast LPO is enabled, XtalFreqRatio uses 1 Mhz ILP + * instead of 32 KHz. But PMUTimer runs at 32 KHz only irrespective of Fast + * LPO is enabled or not. Thereby scale up ilp_tick when Fast LPO is enabled. + * In case of Zebu/QT, Fast LPO is exactly 32 times of ILP clock. + * [Reference: CRWLPMU-284] + */ + if (ilp_on_fast_lpo) { + ilp_tick *= 32; + } + } /* Get xtal vs ILP ratio from XtalFreqRatio(0x66c) */ - xtal_ratio = si_corereg(bus->sih, pmu_idx, offsetof(pmuregs_t, pmu_xtalfreq), 0, 0); - xtal_ratio = (xtal_ratio & PMU_XTALFREQ_REG_ILPCTR_MASK) / 4; + alp_to_ilp_ratio = si_corereg(bus->sih, pmu_idx, offsetof(pmuregs_t, pmu_xtalfreq), 0, 0); + alp_to_ilp_ratio = (alp_to_ilp_ratio & PMU_XTALFREQ_REG_ILPCTR_MASK) / 4; /* Go back to original core */ si_setcoreidx(bus->sih, cur_coreidx); @@ -1885,16 +1874,21 @@ void dhdpcie_htclkratio_cal(dhd_bus_t *bus) xtalfreq = XTAL_FREQ_37M4; } - /* htclkratio = xtalfreq / QT_XTAL_FREQ - * = xtalfreq / (ilp_tick * xtal_ratio) + alp_freq = xtalfreq / xtal_to_alp_ratio; + + /* htclkratio = Expected ALP Freq / Real ALP Freq + * = Expected ALP Freq / (Real ILP Tick * Real alp_to_ilp_ratio) */ - htclkratio = xtalfreq / (ilp_tick * xtal_ratio); + htclkratio = alp_freq / (ilp_tick * alp_to_ilp_ratio); bus->xtalfreq = xtalfreq; bus->ilp_tick = ilp_tick; - bus->xtal_ratio = xtal_ratio; + bus->alp_to_ilp_ratio = alp_to_ilp_ratio; + bus->xtal_to_alp_ratio = xtal_to_alp_ratio; exit: - DHD_ERROR(("Dongle/Host clock ratio %u with %dHz xtal frequency\n", htclkratio, xtalfreq)); + DHD_ERROR(("Dongle/Host clock ratio %u with %dHz xtal frequency, ilp_tick: %d, " + "alp_to_ilp_ratio: %d, ilp_on_fast_lpo: %d\n", + htclkratio, xtalfreq, ilp_tick, alp_to_ilp_ratio, !!ilp_on_fast_lpo)); } /* Re-calculate htclkratio if nvram provides a different xtalfreq */ @@ -1903,6 +1897,9 @@ void dhdpcie_htclkratio_recal(dhd_bus_t *bus, char *nvram, uint nvram_sz) char *freq_c = NULL; uint len, p; int xtalfreq = 0; + uint cur_coreidx, pmu_idx; + uint32 alp_to_ilp_ratio = 0; + uint32 alp_freq = 0; /* Do not re-calculate if xtalfreq is overridden by module parameter */ if (dngl_xtalfreq) @@ -1944,11 +1941,26 @@ void dhdpcie_htclkratio_recal(dhd_bus_t *bus, char *nvram, uint nvram_sz) DHD_ERROR(("Re-calculating htclkratio because nvram xtalfreq %dHz is different from %dHz\n", xtalfreq, bus->xtalfreq)); - htclkratio = xtalfreq / (bus->ilp_tick * bus->xtal_ratio); + alp_freq = xtalfreq / bus->xtal_to_alp_ratio; + htclkratio = alp_freq / (bus->ilp_tick * bus->alp_to_ilp_ratio); bus->xtalfreq = xtalfreq; - DHD_ERROR(("Corrected dongle/Host clock ratio %u with %dHz xtal frequency\n", - htclkratio, xtalfreq)); + /* Recalculate alp_to_ilp_ratio just to aid in debuggability. Mainly to compare with the + * previously calculated alp_to_ilp_ratio. + */ + + cur_coreidx = si_coreidx(bus->sih); + si_setcore(bus->sih, PMU_CORE_ID, 0); + pmu_idx = si_coreidx(bus->sih); + + alp_to_ilp_ratio = si_corereg(bus->sih, pmu_idx, offsetof(pmuregs_t, pmu_xtalfreq), 0, 0); + alp_to_ilp_ratio = (alp_to_ilp_ratio & PMU_XTALFREQ_REG_ILPCTR_MASK) / 4; + + si_setcoreidx(bus->sih, cur_coreidx); + + DHD_ERROR(("Corrected Host/Dongle clock ratio %u with %dHz xtal frequency, ilp_tick: %d, " + "alp_to_ilp_ratio: %d, alp_to_ilp_ratio (recalculated): %d\n", htclkratio, + xtalfreq, bus->ilp_tick, bus->alp_to_ilp_ratio, alp_to_ilp_ratio)); } #endif /* BCMQT_HW */ @@ -1993,6 +2005,92 @@ dhdpcie_bus_mpu_disable(dhd_bus_t *bus) } } +uint32 pcie_slave_wrapper_offsets[] = { + AI_ERRLOGCTRL, + AI_ERRLOGDONE, + AI_ERRLOGSTATUS, + AI_ERRLOGADDRLO, + AI_ERRLOGADDRHI, + AI_ERRLOGID, + AI_ERRLOGUSER, + AI_ERRLOGFLAGS +}; + +#define PCIE_SLAVER_WRAPPER_BASE 0x18102000u + +static INLINE void dhd_sbreg_op(dhd_pub_t *dhd, uint addr, uint *val, bool read); + +static uint32 +dhd_get_pcie_slave_wrapper(si_t *sih) +{ + uint32 pcie_slave_wrapper = 0; + uint16 chipid = si_chipid(sih); + + switch (chipid) { + case BCM4389_CHIP_ID: + case BCM4387_CHIP_ID: + pcie_slave_wrapper = PCIE_SLAVER_WRAPPER_BASE; + break; + default: + pcie_slave_wrapper = 0; + break; + } + + return pcie_slave_wrapper; +} + +static void +dhd_dump_pcie_slave_wrapper_regs(dhd_bus_t *bus) +{ + uint32 i, val; + uint32 pcie_slave_wrapper_base = 0; + uint32 total_wrapper_regs; + + if (bus->dhd == NULL) { + return; + } + + pcie_slave_wrapper_base = dhd_get_pcie_slave_wrapper(bus->sih); + if (!pcie_slave_wrapper_base) { + DHD_ERROR(("%s pcie slave wrapper base not populated\n", __FUNCTION__)); + return; + } + + DHD_ERROR(("%s: ##### Dumping PCIe slave wrapper regs #####\n", __FUNCTION__)); + + total_wrapper_regs = + sizeof(pcie_slave_wrapper_offsets) / sizeof(pcie_slave_wrapper_offsets[0]); + + for (i = 0; i < total_wrapper_regs; i++) { + dhd_sbreg_op(bus->dhd, (pcie_slave_wrapper_base + pcie_slave_wrapper_offsets[i]), + &val, TRUE); + } + + DHD_ERROR(("%s: ##### ##### #####\n", __FUNCTION__)); +} + +bool +dhd_check_htput_chip(dhd_bus_t *bus) +{ + bool htput_support = FALSE; + uint16 chipid = si_chipid(bus->sih); + + switch (chipid) { + /* Enable htput support for all 160Mhz chips */ + case BCM4388_CHIP_ID: + case BCM4389_CHIP_ID: + case BCM4397_CHIP_ID: + htput_support = TRUE; + break; + default: + htput_support = TRUE; + } + + DHD_ERROR(("%s: htput_support:%d\n", __FUNCTION__, htput_support)); + + return htput_support; +} + static bool dhdpcie_dongle_attach(dhd_bus_t *bus) { @@ -2008,13 +2106,17 @@ dhdpcie_dongle_attach(dhd_bus_t *bus) DHD_TRACE(("%s: ENTER\n", __FUNCTION__)); + chipid = dhd_get_chipid(bus); + + if (chipid == (uint16)-1) + goto fail; + /* Configure CTO Prevention functionality */ #if defined(BCMFPGA_HW) || defined(BCMQT_HW) DHD_ERROR(("Disable CTO\n")); bus->cto_enable = FALSE; #else #if defined(BCMPCIE_CTO_PREVENTION) - chipid = dhd_get_chipid(bus); if (BCM4349_CHIP(chipid) || BCM4350_CHIP(chipid) || BCM4345_CHIP(chipid)) { DHD_ERROR(("Disable CTO\n")); @@ -2030,7 +2132,10 @@ dhdpcie_dongle_attach(dhd_bus_t *bus) #endif /* BCMFPGA_HW || BCMQT_HW */ if (PCIECTO_ENAB(bus)) { - dhdpcie_cto_init(bus, TRUE); + /* WAR - Delay the CTO init in 4397A0. */ + if (!(BCM4397_CHIP(chipid) && dhd_get_chiprev(bus) == 0)) { + dhdpcie_cto_init(bus, TRUE); + } } #ifdef CONFIG_ARCH_EXYNOS @@ -2066,13 +2171,13 @@ dhdpcie_dongle_attach(dhd_bus_t *bus) goto fail; } -#if defined(DHD_EFI) || defined(NDIS) +#if defined(NDIS) /* Save good copy of PCIe config space */ if (BCME_OK != dhdpcie_config_save(bus)) { DHD_ERROR(("%s : failed to save PCI configuration space!\n", __FUNCTION__)); goto fail; } -#endif /* DHD_EFI */ +#endif /* si_attach() will provide an SI handle and scan the backplane */ if (!(bus->sih = si_attach((uint)devid, osh, regsva, PCI_BUS, bus, @@ -2102,6 +2207,9 @@ dhdpcie_dongle_attach(dhd_bus_t *bus) dhd_bus_pcie_pwr_req_nolock(bus); } + /* Calling after requesting dm1 (Wl) power as there are mac wrapper regs */ + dhd_dump_pcie_slave_wrapper_regs(bus); + /* Get info on the ARM and SOCRAM cores... */ /* Should really be qualified by device id */ if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || @@ -2168,9 +2276,10 @@ dhdpcie_dongle_attach(dhd_bus_t *bus) dongle_reset_needed = !(bus->dhd->dongle_isolation); } - /* Fix for FLR reset specific to 4397a0. Write a value 0x1E in PMU CC reg18 */ - if (BCM4397_CHIP(dhd_get_chipid(bus)) && (bus->sih->chiprev == 0)) { + /* Fix for FLR reset & CTO init specific to 4397a0. Write a value 0x1E in PMU CC reg18 */ + if (BCM4397_CHIP(bus->sih->chip) && (bus->sih->chiprev == 0)) { uint origidx = 0; + chipcregs_t *cc; origidx = si_coreidx(bus->sih); pmu_corereg(bus->sih, SI_CC_IDX, chipcontrol_addr, ~0, PMU_CHIPCTL18); @@ -2179,16 +2288,22 @@ dhdpcie_dongle_attach(dhd_bus_t *bus) (PMU_CC18_WL_BOOKER_FORCEPWRDWN_EN | ((PMU_CC18_WL_P_CHAN_TIMER_SEL_8ms << PMU_CC18_WL_P_CHAN_TIMER_SEL_OFF) & PMU_CC18_WL_P_CHAN_TIMER_SEL_MASK))); - si_setcore(bus->sih, origidx, 0); - } - /* - * Issue dongle to reset all the cores on the chip - similar to rmmod dhd - * This is required to avoid spurious interrupts to the Host and bring back - * dongle to a sane state (on host soft-reboot / watchdog-reboot). - */ - if (dongle_reset_needed) { - dhdpcie_dongle_reset(bus); + /* 4397A0 WAR. Set max rsrc mask to 0x7fffffff and force HT before CTO init */ + pmu_corereg(bus->sih, SI_CC_IDX, max_res_mask, ~0, 0x7fffffff); + + cc = (chipcregs_t*)si_setcore(bus->sih, CC_CORE_ID, 0); + if (cc) { + OR_REG(osh, &cc->clk_ctl_st, CCS_FORCEHT); + SPINWAIT(((R_REG(osh, &cc->clk_ctl_st) & CCS_HTAVAIL) == 0), + PMU_MAX_TRANSITION_DLY); + } else { + DHD_ERROR(("CC is NULL\n")); + } + si_setcore(bus->sih, origidx, 0); + if (PCIECTO_ENAB(bus)) { + dhdpcie_cto_init(bus, TRUE); + } } /* need to set the force_bt_quiesce flag here @@ -2203,6 +2318,15 @@ dhdpcie_dongle_attach(dhd_bus_t *bus) bus->force_bt_quiesce = FALSE; } + /* + * Issue dongle to reset all the cores on the chip - similar to rmmod dhd + * This is required to avoid spurious interrupts to the Host and bring back + * dongle to a sane state (on host soft-reboot / watchdog-reboot). + */ + if (dongle_reset_needed) { + dhdpcie_dongle_reset(bus); + } + dhdpcie_dongle_flr_or_pwr_toggle(bus); dhdpcie_bus_mpu_disable(bus); @@ -2230,11 +2354,6 @@ dhdpcie_dongle_attach(dhd_bus_t *bus) case BCM4389_CHIP_ID: bus->dongle_ram_base = CA7_4389_RAM_BASE; break; -#ifdef UNRELEASEDCHIP - case BCM4397_CHIP_ID: - bus->dongle_ram_base = CA7_4389_RAM_BASE; - break; -#endif default: /* also populate base address */ bus->dongle_ram_base = 0x200000; @@ -2298,6 +2417,12 @@ dhdpcie_dongle_attach(dhd_bus_t *bus) case BCM43752_CHIP_ID: bus->dongle_ram_base = CR4_43752_RAM_BASE; break; + case BCM43756_CHIP_ID: + bus->dongle_ram_base = CR4_43756_RAM_BASE; + break; + case BCM43711_CHIP_ID: + bus->dongle_ram_base = CR4_43711_RAM_BASE; + break; case BCM4376_CHIP_GRPID: bus->dongle_ram_base = CR4_4376_RAM_BASE; break; @@ -2314,6 +2439,12 @@ dhdpcie_dongle_attach(dhd_bus_t *bus) case BCM4377_CHIP_ID: bus->dongle_ram_base = CR4_4377_RAM_BASE; break; + case BCM4381_CHIP_ID: + bus->dongle_ram_base = CR4_4381_RAM_BASE; + break; + case BCM4382_CHIP_ID: + bus->dongle_ram_base = CR4_4382_RAM_BASE; + break; case BCM4387_CHIP_GRPID: bus->dongle_ram_base = CR4_4387_RAM_BASE; break; @@ -2367,15 +2498,15 @@ dhdpcie_dongle_attach(dhd_bus_t *bus) bus->deep_sleep = TRUE; #endif -#ifdef CUSTOMER_HW_ROCKCHIP - bus->idma_enabled = FALSE; -#else - bus->idma_enabled = TRUE; -#endif - bus->ifrm_enabled = TRUE; -#ifdef BCMINTERNAL - bus->dma_chan = 0; -#endif /* BCMINTERNAL */ + /* + * This check is to prevent to go back to enable during fw download + * after forced to disable by dhd commend(eg. "dhd dar_enable 0") after insmod + */ + if ((bus->dhd == NULL) || (bus->dhd->dongle_reset == FALSE)) { + bus->dar_enabled = TRUE; + bus->idma_enabled = TRUE; + bus->ifrm_enabled = TRUE; + } dhdpcie_pme_stat_clear(bus); @@ -2408,7 +2539,6 @@ fail: /* for EFI even if there is an error, load still succeeds * so si_detach should not be called here, it is called during unload */ -#ifndef DHD_EFI /* * As request irq is done later, till then CTO will not be detected, * so unconditionally dump cfg and DAR registers. @@ -2427,6 +2557,7 @@ fail: "intstat=0x%x enab=%d\n", __FUNCTION__, pci_intstatus, bus->cto_enable)); } + dhd_bus_dump_dar_registers(bus); } dhd_deinit_pwr_req_lock(bus); dhd_deinit_bus_lp_state_lock(bus); @@ -2442,8 +2573,6 @@ fail: si_detach(bus->sih); bus->sih = NULL; } - -#endif /* DHD_EFI */ DHD_TRACE(("%s: EXIT: FAILURE\n", __FUNCTION__)); return -1; } @@ -2468,8 +2597,8 @@ dhdpcie_bus_intr_enable(dhd_bus_t *bus) DHD_TRACE(("%s Enter\n", __FUNCTION__)); if (bus) { if (bus->sih && !bus->is_linkdown) { - /* Skip after recieving D3 ACK */ - if (bus->bus_low_power_state == DHD_BUS_D3_ACK_RECIEVED) { + /* Skip after receiving D3 ACK */ + if (__DHD_CHK_BUS_LPS_D3_ACKED(bus)) { return; } if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || @@ -2499,8 +2628,8 @@ dhdpcie_bus_intr_disable(dhd_bus_t *bus) { DHD_TRACE(("%s Enter\n", __FUNCTION__)); if (bus && bus->sih && !bus->is_linkdown) { - /* Skip after recieving D3 ACK */ - if (DHD_CHK_BUS_LPS_D3_ACKED(bus)) { + /* Skip after receiving D3 ACK */ + if (__DHD_CHK_BUS_LPS_D3_ACKED(bus)) { return; } @@ -2543,10 +2672,6 @@ dhdpcie_advertise_bus_cleanup(dhd_pub_t *dhdp) unsigned long flags; int timeleft; -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(dhdp, TRUE, dhdpcie_advertise_bus_cleanup); -#endif /* DHD_PCIE_RUNTIMEPM */ - dhdp->dhd_watchdog_ms_backup = dhd_watchdog_ms; if (dhdp->dhd_watchdog_ms_backup) { DHD_ERROR(("%s: Disabling wdtick before dhd deinit\n", @@ -2565,6 +2690,15 @@ dhdpcie_advertise_bus_cleanup(dhd_pub_t *dhdp) dhdp->db7_trap.fw_db7w_trap_inprogress = TRUE; dhdpcie_fw_trap(dhdp->bus); OSL_DELAY(100 * 1000); // wait 100 msec + if (!dhdp->db7_trap.fw_db7w_trap_recieved) { + DHD_ERROR(("%s : Did not receive DB7 Ack\n", __FUNCTION__)); +#ifdef WBRC + if (dhdp->fw_mode_changed == FALSE) { + DHD_ERROR(("%s : Set do_chip_bighammer\n", __FUNCTION__)); + dhdp->do_chip_bighammer = TRUE; + } +#endif /* WBRC */ + } dhdp->db7_trap.fw_db7w_trap_inprogress = FALSE; } else { DHD_ERROR(("%s: DB7 Not sent!!!\n", @@ -2615,6 +2749,41 @@ dhdpcie_advertise_bus_remove(dhd_pub_t *dhdp) return; } +/* + * dhdpcie_busbusy_wait mark busstate as DHD_BUS_DOWN_IN_PROGRESS and waits + * for all the contexts to garacefully exit. All the bus usage contexts before + * marking busstate as busy, will check for whether the busstate is DHD_BUS_DOWN + * or DHD_BUS_DOWN_IN_PROGRESS, if so they will exit from there itself without + * marking dhd_bus_busy_state as BUSY. + */ +void +dhdpcie_busbusy_wait(dhd_pub_t *dhdp) +{ + unsigned long flags; + int timeleft; + + dhdp->dhd_watchdog_ms_backup = dhd_watchdog_ms; + if (dhdp->dhd_watchdog_ms_backup) { + DHD_ERROR(("%s: Disabling wdtick\n", __FUNCTION__)); + dhd_os_wd_timer(dhdp, 0); + } + + DHD_GENERAL_LOCK(dhdp, flags); + dhdp->busstate = DHD_BUS_DOWN_IN_PROGRESS; + DHD_GENERAL_UNLOCK(dhdp, flags); + + timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); + if ((timeleft == 0) || (timeleft == 1)) { + DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", + __FUNCTION__, dhdp->dhd_bus_busy_state)); + } + + DHD_GENERAL_LOCK(dhdp, flags); + dhdp->busstate = DHD_BUS_DOWN; + DHD_GENERAL_UNLOCK(dhdp, flags); + return; +} + static void dhdpcie_bus_remove_prep(dhd_bus_t *bus) { @@ -2648,8 +2817,8 @@ dhdpcie_bus_remove_prep(dhd_bus_t *bus) } /* disable fast lpo from 4347/4377 */ - /* For 4378/4387/4389, do not disable fast lpo because we always enable fast lpo. - * it causes insmod/rmmod reload failure. + /* Do not disable fast lpo for 4378/4387/4389/4381/4382. + * Because we always enable fast lpo. it causes insmod/rmmod reload failure. */ if ((PMUREV(bus->sih->pmurev) > 31) && !(PCIE_FASTLPO_ENABLED(bus->sih->buscorerev))) { @@ -2663,7 +2832,6 @@ dhdpcie_bus_remove_prep(dhd_bus_t *bus) if (!bus->is_linkdown) { /* For Non-EFI modular builds, do dongle reset during rmmod */ -#ifndef DHD_EFI /* For EFI-DHD this compile flag will be defined. * In EFI, depending on bt over pcie mode * we either power toggle or do F0 FLR @@ -2671,7 +2839,6 @@ dhdpcie_bus_remove_prep(dhd_bus_t *bus) * do dongle reset from here */ dhdpcie_dongle_reset(bus); -#endif /* !DHD_EFI */ } bus->dhd->is_pcie_watchdog_reset = TRUE; @@ -2716,6 +2883,72 @@ dhd_deinit_backplane_access_lock(dhd_bus_t *bus) } } +void +dhd_init_dpc_histos(dhd_pub_t *dhd) +{ + dhd_bus_t *bus = dhd->bus; + if (!bus->dpc_time_histo) { + bus->dpc_time_histo = dhd_histo_init(dhd); + } + if (!bus->ctrl_cpl_post_time_histo) { + bus->ctrl_cpl_post_time_histo = dhd_histo_init(dhd); + } + if (!bus->tx_post_time_histo) { + bus->tx_post_time_histo = dhd_histo_init(dhd); + } + if (!bus->tx_cpl_time_histo) { + bus->tx_cpl_time_histo = dhd_histo_init(dhd); + } + if (!bus->rx_cpl_post_time_histo) { + bus->rx_cpl_post_time_histo = dhd_histo_init(dhd); + } +} + +void +dhd_deinit_dpc_histos(dhd_pub_t *dhd) +{ + dhd_bus_t *bus = dhd->bus; + if (bus->dpc_time_histo) { + dhd_histo_deinit(dhd, bus->dpc_time_histo); + } + if (bus->ctrl_cpl_post_time_histo) { + dhd_histo_deinit(dhd, bus->ctrl_cpl_post_time_histo); + } + if (bus->tx_post_time_histo) { + dhd_histo_deinit(dhd, bus->tx_post_time_histo); + } + if (bus->tx_cpl_time_histo) { + dhd_histo_deinit(dhd, bus->tx_cpl_time_histo); + } + if (bus->rx_cpl_post_time_histo) { + dhd_histo_deinit(dhd, bus->rx_cpl_post_time_histo); + } +} + +void +dhd_dump_dpc_histos(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) +{ + dhd_bus_t *bus = dhd->bus; + bcm_bprintf(strbuf, "==== DPC Histograms in Usec ====\n"); + dhd_histo_tag_dump(dhd, strbuf, "usec/histo"); + dhd_histo_dump(dhd, strbuf, bus->dpc_time_histo, "dpc"); + dhd_histo_dump(dhd, strbuf, bus->ctrl_cpl_post_time_histo, "ctrl_cpl_post"); + dhd_histo_dump(dhd, strbuf, bus->tx_post_time_histo, "tx_post"); + dhd_histo_dump(dhd, strbuf, bus->tx_cpl_time_histo, "tx_cpl"); + dhd_histo_dump(dhd, strbuf, bus->rx_cpl_post_time_histo, "rx_cpl_post"); + bcm_bprintf(strbuf, "================================\n"); +} + +void +dhd_clear_dpc_histos(dhd_pub_t *dhd) +{ + dhd_bus_t *bus = dhd->bus; + dhd_histo_clear(dhd, bus->dpc_time_histo); + dhd_histo_clear(dhd, bus->ctrl_cpl_post_time_histo); + dhd_histo_clear(dhd, bus->tx_post_time_histo); + dhd_histo_clear(dhd, bus->tx_cpl_time_histo); + dhd_histo_clear(dhd, bus->rx_cpl_post_time_histo); +} /** Detach and free everything */ void dhdpcie_bus_release(dhd_bus_t *bus) @@ -2725,6 +2958,9 @@ dhdpcie_bus_release(dhd_bus_t *bus) uint buscorerev = 0; #endif /* BCMQT */ osl_t *osh = NULL; +#if defined(__linux__) + int bcmerror = 0; +#endif /* __linux__ */ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -2734,7 +2970,7 @@ dhdpcie_bus_release(dhd_bus_t *bus) ASSERT(osh); if (bus->dhd) { -#if defined(DEBUGGER) || defined (DHD_DSCOPE) +#if defined(DEBUGGER) || defined(DHD_DSCOPE) debugger_close(); #endif /* DEBUGGER || DHD_DSCOPE */ dhdpcie_advertise_bus_remove(bus->dhd); @@ -2746,6 +2982,8 @@ dhdpcie_bus_release(dhd_bus_t *bus) dhdpcie_bus_intr_disable(bus); dhdpcie_free_irq(bus); } + dhd_deinit_dpc_histos(bus->dhd); + dhd_deinit_bus_lp_state_lock(bus); dhd_deinit_bar1_switch_lock(bus); dhd_deinit_backplane_access_lock(bus); @@ -2773,18 +3011,23 @@ dhdpcie_bus_release(dhd_bus_t *bus) */ dhd_detach(bus->dhd); dhdpcie_bus_release_dongle(bus, osh, dongle_isolation, TRUE); +#if defined(__linux__) + DHD_ERROR(("%s: disable pcie dev\n", __FUNCTION__)); + bcmerror = dhdpcie_bus_disable_device(bus); + if (bcmerror) { + DHD_ERROR(("%s: dhdpcie_bus_disable_device: %d\n", + __FUNCTION__, bcmerror)); + } + DHD_ERROR(("%s: stop host dev dev\n", __FUNCTION__)); + bcmerror = dhdpcie_bus_stop_host_dev(bus); + if (bcmerror) { + DHD_ERROR(("%s: dhdpcie_bus_stop_host_dev failed: %d\n", + __FUNCTION__, bcmerror)); + } +#endif /* __linux__ */ dhd_free(bus->dhd); bus->dhd = NULL; } -#ifdef DHD_EFI - else { - if (bus->intr) { - dhdpcie_bus_intr_disable(bus); - dhdpcie_free_irq(bus); - } - dhdpcie_bus_release_dongle(bus, osh, dongle_isolation, TRUE); - } -#endif /* DHD_EFI */ /* unmap the regs and tcm here!! */ if (bus->regs) { dhdpcie_bus_reg_unmap(osh, bus->regs, DONGLE_REG_MAP_SIZE); @@ -2805,20 +3048,6 @@ dhdpcie_bus_release(dhd_bus_t *bus) MFREE(osh, bus->console.buf, bus->console.bufsize); } -#ifdef BCMINTERNAL - if (bus->msi_sim) { - DMA_UNMAP(osh, bus->msi_sim_phys, MSI_SIM_BUFSIZE, DMA_RX, 0, 0); - MFREE(osh, bus->msi_sim_addr, MSI_SIM_BUFSIZE); - } - - /* free host fw buffer if there is any */ - if (bus->hostfw_buf.va) { - DMA_FREE_CONSISTENT(osh, bus->hostfw_buf.va, bus->hostfw_buf._alloced, - bus->hostfw_buf.pa, bus->hostfw_buf.dmah); - memset(&bus->hostfw_buf, 0, sizeof(bus->hostfw_buf)); - } -#endif /* BCMINTERNAL */ - /* Finally free bus info */ MFREE(osh, bus, sizeof(dhd_bus_t)); @@ -2844,16 +3073,6 @@ dhdpcie_bus_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bo } if (bus->sih) { -#ifdef BCMINTERNAL - if (bus->msi_sim) { - /* disable MSI */ - si_corereg(bus->sih, bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, configaddr), ~0, PCIE_CFG_MSICAP_OFFSET); - si_corereg(bus->sih, bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, configdata), ~0, - PCIE_CFG_MSICAP_DISABLE_MSI); - } -#endif /* BCMINTERNAL */ /* * Perform dongle reset only if dongle isolation is not enabled. @@ -3073,7 +3292,7 @@ dhd_bus_device_tx_stuck_scan(dhd_bus_t *bus) tx_cmpl = flow_ring_node->tx_cmpl; active = flow_ring_node->active; status = flow_ring_node->status; - ring_empty = dhd_prot_is_cmpl_ring_empty(bus->dhd, flow_ring_node->prot_info); + ring_empty = dhd_prot_is_h2d_ring_empty(bus->dhd, flow_ring_node->prot_info); DHD_FLOWRING_UNLOCK(flow_ring_node->lock, ring_lock_flags); /* * Need not monitor the flow ring if, @@ -3162,6 +3381,28 @@ dhd_bus_device_stuck_scan(dhd_bus_t *bus) } return; } +#if defined(ASSOC_CHECK_SR) +void +dhd_assoc_check_sr(dhd_pub_t *dhd, bool state) +{ + int ret = -1; + /* if stuck monitor is disabled */ + if (!dhd->bus->dev_tx_stuck_monitor) { + return; + } + + if (state) { /* suspend */ + dhd->assoc_at_suspend = dhd_is_associated(dhd, 0, NULL); + DHD_ERROR(("%s assoc_at_suspend: %d\n", __FUNCTION__, dhd->assoc_at_suspend)); + } else if ((dhd->assoc_at_suspend) && (!dhd_is_associated(dhd, 0, NULL))) { /* resume */ + DHD_ERROR(("%s - assoc lost in D3. Issue disassoc\n", __FUNCTION__)); + ret = dhd_wl_ioctl_cmd(dhd, WLC_DISASSOC, NULL, 0, IOV_SET, 0); + if (ret != BCME_OK) { + DHD_ERROR(("%s error issuing disassoc, %d\n", __FUNCTION__, ret)); + } + } +} +#endif /* ASSOC_CHECK_SR */ #endif /* DEVICE_TX_STUCK_DETECT */ /** @@ -3186,27 +3427,6 @@ bool dhd_bus_watchdog(dhd_pub_t *dhd) DHD_BUS_BUSY_SET_IN_WD(dhd); DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(dhd, TRUE, __builtin_return_address(0)); -#endif /* DHD_PCIE_RUNTIMEPM */ - -#ifdef BCMINTERNAL - if ((bus->msi_sim) && (++bus->polltick >= bus->pollrate)) { - uint32 val; - bus->polltick = 0; - val = *(uint32 *)bus->msi_sim_addr; - *(uint32 *)bus->msi_sim_addr = 0; - if (val) { - DHD_INFO(("calling dhdpcie_bus_isr 0x%04x\n", val)); - dhdpcie_bus_isr(bus); - } - } -#endif /* BCMINTERNAL */ - -#if defined(DHD_EFI) && defined(DHD_INTR_POLL_PERIOD_DYNAMIC) - dhd_intr_poll_pkt_thresholds(dhd); -#endif /* DHD_EFI && DHD_INTR_POLL_PERIOD_DYNAMIC */ - /* Poll for console output periodically */ if (dhd->busstate == DHD_BUS_DATA && dhd->dhd_console_ms != 0 && @@ -3251,7 +3471,7 @@ bool dhd_bus_watchdog(dhd_pub_t *dhd) DHD_BUS_BUSY_CLEAR_IN_WD(dhd); dhd_os_busbusy_wake(dhd); DHD_GENERAL_UNLOCK(dhd, flags); -#if !defined(DHD_PCIE_RUNTIMEPM) && (defined(PCIE_OOB) || defined(PCIE_INB_DW)) +#if (defined(PCIE_OOB) || defined(PCIE_INB_DW)) dhd->bus->inb_dw_deassert_cnt += dhd_watchdog_ms; if (dhd->bus->inb_dw_deassert_cnt >= DHD_INB_DW_DEASSERT_MS) { @@ -3263,7 +3483,7 @@ bool dhd_bus_watchdog(dhd_pub_t *dhd) */ dhd_bus_dw_deassert(dhd); } -#endif /* !DHD_PCIE_RUNTIMEPM && PCIE_OOB || PCIE_INB_DW */ +#endif return TRUE; } /* dhd_bus_watchdog */ @@ -3375,6 +3595,10 @@ static int concate_revision_bcm4359(dhd_bus_t *bus, char *fw_path, char *nv_path } #define NVRAM_FEM_MURATA "_murata" +#if defined(DHD_FW_COREDUMP) && defined(DHD_COREDUMP) +extern char map_path[PATH_MAX]; +#endif /* DHD_FW_COREDUMP && DHD_COREDUMP */ + static int concate_revision_from_cisinfo(dhd_bus_t *bus, char *fw_path, char *nv_path) { @@ -3408,7 +3632,14 @@ concate_revision_from_cisinfo(dhd_bus_t *bus, char *fw_path, char *nv_path) } #endif /* BCM4361_CHIP */ strncat(nv_path, info->nvram_ext, strlen(info->nvram_ext)); +#if defined(SUPPORT_MULTIPLE_NVRAM) || defined(SUPPORT_MULTIPLE_CLMBLOB) + dhd_set_platform_ext_name_for_chip_version(info->nvram_ext); +#endif /* SUPPORT_MULTIPLE_NVRAM || SUPPORT_MULTIPLE_CLMBLOB */ strncat(fw_path, info->fw_ext, strlen(info->fw_ext)); +#if defined(DHD_COREDUMP) && defined(SUPPORT_MULTIPLE_REVISION_MAP) + if (!bcmstrnstr(map_path, PATH_MAX, info->fw_ext, strlen(info->fw_ext))) + strncat(map_path, info->fw_ext, strlen(info->fw_ext)); +#endif /* DHD_COREDUMP && SUPPORT_MULTIPLE_REVISION_MAP */ } else { DHD_ERROR(("%s:failed to find extension for nvram and firmware\n", __FUNCTION__)); ret = BCME_ERROR; @@ -3422,15 +3653,19 @@ concate_revision_from_cisinfo(dhd_bus_t *bus, char *fw_path, char *nv_path) snprintf(chipstr, sizeof(chipstr), "_4389"); /* write chipstr/vid into nvram tag */ - ret = concate_nvram_by_vid(bus, nv_path, chipstr); + ret = concate_nvram_by_vid(bus->dhd, nv_path, chipstr); /* write chiprev into FW tag */ if (ret == BCME_OK) { - if (revid == 3) { - strncat(fw_path, A0_REV, strlen(fw_path)); - DHD_ERROR(("%s: fw_path : %s\n", __FUNCTION__, fw_path)); - } else if (revid == 1) { + if (revid == 1) { strncat(fw_path, B0_REV, strlen(fw_path)); DHD_ERROR(("%s: fw_path : %s\n", __FUNCTION__, fw_path)); + } else if (revid == 2) { + strncat(fw_path, C0_REV, strlen(fw_path)); + DHD_ERROR(("%s: fw_path : %s\n", __FUNCTION__, fw_path)); + } else if (revid == 3) { + strncat(fw_path, C1_REV, strlen(fw_path)); + DHD_ERROR(("%s: fw_path : %s\n", __FUNCTION__, fw_path)); + } else { DHD_ERROR(("%s: INVALID CHIPREV %d\n", __FUNCTION__, revid)); } @@ -3446,6 +3681,27 @@ concate_revision_from_cisinfo(dhd_bus_t *bus, char *fw_path, char *nv_path) return ret; } +#ifdef CONCAT_DEF_REV_FOR_NOMATCH_VID +#define DEF_REVISION "_c0" +static int +vendor_concat_revision(dhd_bus_t *bus, char *fw_path, char *nv_path) +{ + int ret = BCME_OK; + char *tag = DEF_REVISION; + + DHD_ERROR(("%s:failed to find extension, use %s as default\n", __FUNCTION__, DEF_REVISION)); + /* Failed to find info, use _c0 as default */ + strlcat(nv_path, tag, PATH_MAX); + strlcat(fw_path, tag, PATH_MAX); +#if defined(DHD_COREDUMP) && defined(SUPPORT_MULTIPLE_REVISION_MAP) + if (!bcmstrnstr(map_path, PATH_MAX, tag, strlen(tag))) { + strlcat(map_path, tag, PATH_MAX); + } +#endif /* DHD_COREDUMP && SUPPORT_MULTIPLE_REVISION_MAP */ + return ret; +} +#endif /* CONCAT_DEF_REV_FOR_NOMATCH_VID */ + int concate_revision(dhd_bus_t *bus, char *fw_path, char *nv_path) { @@ -3482,6 +3738,11 @@ concate_revision(dhd_bus_t *bus, char *fw_path, char *nv_path) return res; } +#ifdef CONCAT_DEF_REV_FOR_NOMATCH_VID + if (res != BCME_OK) { + res = vendor_concat_revision(bus, fw_path, nv_path); + } +#endif /* CONCAT_DEF_REV_FOR_NOMATCH_VID */ return res; } #endif /* SUPPORT_MULTIPLE_REVISION */ @@ -3507,6 +3768,27 @@ dhd_get_chipid(struct dhd_bus *bus) } } +uint16 +dhd_get_chiprev(struct dhd_bus *bus) +{ + if (bus && bus->sih) { + return bus->sih->chiprev; + } else if (bus && bus->regs) { + chipcregs_t *cc = (chipcregs_t *)bus->regs; + uint w, chiprev; + + /* Set bar0 window to si_enum_base */ + dhdpcie_bus_cfg_set_bar0_win(bus, si_enum_base(0)); + + w = R_REG(bus->osh, &cc->chipid); + chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; + + return (uint16)chiprev; + } else { + return 0xffff; + } +} + /** * Loads firmware given by caller supplied path and nvram image into PCIe dongle. * @@ -3543,6 +3825,17 @@ dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, } #endif /* SUPPORT_MULTIPLE_REVISION */ +#if defined(SUPPORT_MULTIPLE_NVRAM) + if (dhd_get_platform_naming_for_nvram_clmblob_file(NVRAM, bus->nv_path) != BCME_OK) { + DHD_ERROR(("%s: Platform's NVRAMs file don't exist." + " Download default NVRAM file.\n", __FUNCTION__)); + } +#endif /* SUPPORT_MULTIPLE_NVRAM */ + +#if defined(SUPPORT_MULTIPLE_BOARD_REVISION) + concate_custom_board_revision(bus->nv_path); +#endif /* SUPPORT_MULTIPLE_BOARD_REVISION */ + #if defined(DHD_BLOB_EXISTENCE_CHECK) dhd_set_blob_support(bus->dhd, bus->fw_path); #endif /* DHD_BLOB_EXISTENCE_CHECK */ @@ -3561,17 +3854,28 @@ dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, void dhd_set_bus_params(struct dhd_bus *bus) { - if (bus->dhd->conf->dhd_poll >= 0) { - bus->poll = bus->dhd->conf->dhd_poll; + struct dhd_conf *conf = bus->dhd->conf; + + if (conf->dhd_poll >= 0) { + bus->poll = conf->dhd_poll; if (!bus->pollrate) bus->pollrate = 1; - printf("%s: set polling mode %d\n", __FUNCTION__, bus->dhd->conf->dhd_poll); + printf("%s: set polling mode %d\n", __FUNCTION__, conf->dhd_poll); } - if (bus->dhd->conf->d2h_intr_control >= 0) - bus->d2h_intr_control = bus->dhd->conf->d2h_intr_control; + if (conf->d2h_intr_control >= 0) + bus->d2h_intr_control = conf->d2h_intr_control; printf("d2h_intr_method -> %s(%d); d2h_intr_control -> %s(%d)\n", bus->d2h_intr_method ? "PCIE_MSI" : "PCIE_INTX", bus->d2h_intr_method, bus->d2h_intr_control ? "HOST_IRQ" : "D2H_INTMASK", bus->d2h_intr_control); + + if (conf->aspm != -1) { + bool aspm = conf->aspm ? TRUE : FALSE; + dhd_bus_aspm_enable_rc_ep(bus, aspm); + } + if (conf->l1ss != -1) { + bool l1ss = conf->l1ss ? TRUE : FALSE; + dhd_bus_l1ss_enable_rc_ep(bus, l1ss); + } } /** @@ -3587,6 +3891,9 @@ dhd_set_bus_params(struct dhd_bus *bus) * * @return BCME_OK on success */ +#if defined(BCM_REQUEST_FW) +extern char clm_path[MOD_PARAM_PATHLEN]; +#endif /* BCM_REQUEST_FW */ static int dhdpcie_download_firmware(struct dhd_bus *bus, osl_t *osh) { @@ -3594,8 +3901,13 @@ dhdpcie_download_firmware(struct dhd_bus *bus, osl_t *osh) #if defined(BCM_REQUEST_FW) uint chipid = bus->sih->chip; uint revid = bus->sih->chiprev; +#if defined(DHD_LINUX_STD_FW_API) + char fw_path[64] = "brcm/bcm"; /* path to firmware image */ +#else char fw_path[64] = "/lib/firmware/brcm/bcm"; /* path to firmware image */ +#endif /* DHD_LINUX_STD_FW_API */ char nv_path[64]; /* path to nvram vars file */ + bus->fw_path = fw_path; bus->nv_path = nv_path; switch (chipid) { @@ -3614,6 +3926,16 @@ dhdpcie_download_firmware(struct dhd_bus *bus, osl_t *osh) break; } break; + case BCM4381_CHIP_ID: + bcmstrncat(fw_path, "4381", 4); + switch (revid) { + case 1: + bcmstrncat(fw_path, "a0-pcie", 7); + break; + default: + break; + } + break; default: DHD_ERROR(("%s: unsupported device %x\n", __FUNCTION__, chipid)); @@ -3621,8 +3943,12 @@ dhdpcie_download_firmware(struct dhd_bus *bus, osl_t *osh) } /* load board specific nvram file */ snprintf(bus->nv_path, sizeof(nv_path), "%s.nvm", fw_path); + /* load signature */ + snprintf(bus->fwsig_filename, sizeof(bus->fwsig_filename), "%s.sig", fw_path); + /* load clm_blob */ + snprintf(clm_path, sizeof(clm_path), "%s.clm_blob", fw_path); /* load firmware */ - snprintf(bus->fw_path, sizeof(fw_path), "%s-firmware.bin", fw_path); + snprintf(bus->fw_path, sizeof(fw_path), "%s.bin", fw_path); #endif /* BCM_REQUEST_FW */ DHD_OS_WAKE_LOCK(bus->dhd); @@ -3636,366 +3962,6 @@ dhdpcie_download_firmware(struct dhd_bus *bus, osl_t *osh) return ret; } /* dhdpcie_download_firmware */ -#ifdef BCMINTERNAL -#define PCIE_HYBRIDFW_MAGICNUM 0x434F464Cu -#define PCIE_HYBRIDFW_HOSTOFFSET_MASK 0xFFC00000u -#define PCIE_HYBRIDFW_TYPE_DNGL 0u -#define PCIE_HYBRIDFW_TYPE_HOST 1u -#define PCIE_HYBRIDFW_TYPE_DNGLTBL 2u -#define PCIE_HYBRIDFW_TYPE_HOSTTBL 3u -#define SBtoPCIETranslation2 0xF0 -#define SBtoPCIETranslation2Upper 0xF4 -#define SBtoPCIETranslation3 0xF8 -#define SBtoPCIETranslation3Upper 0xFC -#define SBtoPCIETranslation0 0x100 -#define SBtoPCIETranslation1 0x104 -#define SBtoPCIETranslation0Upper 0x10C -#define SBtoPCIETranslation1Upper 0x110 - -/* Get length of each portion of hybrid fw binary from the header */ -static int -dhdpcie_hybridfw_get_next_block(char * fptr, int *fsize, uint32 *type, uint32 *len) -{ - struct portion_hdr { - uint32 type; - uint32 len; - } hdr; - int ret; - - /* read and verify header */ - if (*fsize <= sizeof(hdr)) { - return BCME_BADLEN; - } - - ret = dhd_os_get_image_block((char *)&hdr, sizeof(hdr), fptr); - if (ret <= 0) { - return BCME_ERROR; - } - - *fsize -= sizeof(hdr); - *type = ltoh32(hdr.type); - *len = ltoh32(hdr.len); - - if ((*len > (uint32)*fsize) || ((int)*len < 0)) { - return BCME_BADLEN; - } - - DHD_INFO(("%s Found section %d with length %d\n", __FUNCTION__, hdr.type, hdr.len)); - - return BCME_OK; -} - -/* Replace host offload functions' pointers */ -static int -dhdpcie_hybridfw_ptrrpl(char *fw, uint fw_sz, uint32 *jmptbl, uint jmptbl_sz, - dmaaddr_t hbuf_pa, uint32 hbuf_len) -{ - uint32 *p_ptr; - uint32 host_addr; - int ret = BCME_OK; - - if (jmptbl_sz % 4) { - DHD_ERROR(("%s table size %u not 4 bytes aligned\n", __FUNCTION__, jmptbl_sz)); - return BCME_ERROR; - } - - host_addr = PCIEDEV_ARM_ADDR(PHYSADDRLO(hbuf_pa), PCIEDEV_TRANS_WIN_HOSTMEM); - for (; jmptbl_sz > 0; jmptbl_sz -= 4, jmptbl++) { - if (*jmptbl >= fw_sz) { - DHD_ERROR(("%s offset %u >= fw size %u\n", __FUNCTION__, *jmptbl, fw_sz)); - ret = BCME_ERROR; - break; - } - p_ptr = (uint32 *)(fw + *jmptbl); - *p_ptr &= ~(uint32)PCIE_HYBRIDFW_HOSTOFFSET_MASK; - if (*p_ptr > hbuf_len) { - DHD_ERROR(("%s function offset %x >= host buffer len %x\n", - __FUNCTION__, *p_ptr, hbuf_len)); - ret = BCME_ERROR; - break; - } - *p_ptr += host_addr; - } - - return ret; -} - -/* configure back plane to pcie translation window */ -static void -dhdpcie_sbtopcie_translation_config(struct dhd_bus *bus, int bp_window, dmaaddr_t addr) -{ - uint32 trans_reg_offset, trans_u_reg_offset; - - switch (bp_window) { - case PCIEDEV_TRANS_WIN_0: - trans_reg_offset = SBtoPCIETranslation0; - trans_u_reg_offset = SBtoPCIETranslation0Upper; - break; - - case PCIEDEV_TRANS_WIN_1: - trans_reg_offset = SBtoPCIETranslation1; - trans_u_reg_offset = SBtoPCIETranslation1Upper; - break; - - case PCIEDEV_TRANS_WIN_2: - trans_reg_offset = SBtoPCIETranslation2; - trans_u_reg_offset = SBtoPCIETranslation2Upper; - break; - - case PCIEDEV_TRANS_WIN_3: - trans_reg_offset = SBtoPCIETranslation3; - trans_u_reg_offset = SBtoPCIETranslation3Upper; - break; - - default: - DHD_ERROR(("%s Invalid bp translation window %d\n", - __FUNCTION__, bp_window)); - return; - } - - si_corereg(bus->sih, bus->sih->buscoreidx, trans_reg_offset, ~0, - ((PHYSADDRLO(addr) & PCIEDEV_HOSTADDR_MAP_WIN_MASK) | 0xC)); - si_corereg(bus->sih, bus->sih->buscoreidx, trans_u_reg_offset, ~0, PHYSADDRHI(addr)); -} - -/** - * hybrid firmware download handler - * - * Parse, prepare and download a hybrid firmware - * - Identify a hybrid firmware - * - Place the host offload portion in an allocated DMA consistent buffer - * - Modifying the host portion function pointers according to info table - */ -static int -dhdpcie_hybridfw_download(struct dhd_bus *bus, char *fp) -{ - uint32 magic_num; - int ret = BCME_OK; - dhd_dma_buf_t *hstfw = &bus->hostfw_buf; - char *dnglfw = NULL, *dngltbl = NULL, *hsttbl = NULL; - int dnglfw_sz = 0, dngltbl_sz = 0, hsttbl_sz = 0; - int fsize; - int offset = 0; - uint32 type = 0, len = 0; - void * ptr = NULL; - - fsize = dhd_os_get_image_size(fp); - - /* Verify magic number */ - if (fsize < sizeof(magic_num)) { - return BCME_UNSUPPORTED; - } - ret = dhd_os_get_image_block((char *)&magic_num, sizeof(magic_num), fp); - if (ret <= 0) { - return BCME_ERROR; - } - magic_num = ltoh32(magic_num); - if (magic_num != PCIE_HYBRIDFW_MAGICNUM) { - return BCME_UNSUPPORTED; - } - fsize -= sizeof(magic_num); - - do { - ret = dhdpcie_hybridfw_get_next_block(fp, &fsize, &type, &len); - if (ret != BCME_OK) { - break; - } - - if (len == 0) { - continue; - } - - if ((ptr = MALLOC(bus->dhd->osh, len)) == NULL) { - ret = BCME_NOMEM; - break; - } - - len = dhd_os_get_image_block(ptr, len, fp); - if (len <= 0) { - MFREE(bus->dhd->osh, ptr, len); - ret = BCME_ERROR; - break; - } - fsize -= len; - - switch (type) { - case PCIE_HYBRIDFW_TYPE_DNGL: - /* cannot have more than one RAM image blocks */ - if (dnglfw_sz) { - MFREE(bus->dhd->osh, ptr, len); - ret = BCME_ERROR; - break; - } - - /* RAM portion of the FW image */ - dnglfw = ptr; - dnglfw_sz = len; - - if ((uint32)len > bus->ramsize) { - ret = BCME_BADLEN; - break; - } - break; - - case PCIE_HYBRIDFW_TYPE_HOST: - /* Host portion of FW image - * Check if a -hostmem- fw has already been loaded, if yes and - * the buffer can accommodate the new firmware host portion, - * reuse the allocated buffer - * For Insufficient size buffer or freshly loaded dhd, allocate - * a coherent buffer - */ - if (hstfw->va) { - if (hstfw->len >= len) { - hstfw->len = len; - } else { - DMA_FREE_CONSISTENT(bus->dhd->osh, hstfw->va, - hstfw->_alloced, hstfw->pa, hstfw->dmah); - memset(hstfw, 0, sizeof(*hstfw)); - } - } - - if (hstfw->va == NULL) { - hstfw->len = len; - hstfw->va = DMA_ALLOC_CONSISTENT(bus->dhd->osh, hstfw->len, - 4, &hstfw->_alloced, &hstfw->pa, &hstfw->dmah); - if (hstfw->va == NULL) { - MFREE(bus->dhd->osh, ptr, len); - ret = BCME_NOMEM; - break; - } - } - - ret = memcpy_s(hstfw->va, hstfw->len, ptr, len); - MFREE(bus->dhd->osh, ptr, len); - break; - - case PCIE_HYBRIDFW_TYPE_DNGLTBL: - /* cannot have more than one ram image relocation information */ - if (dngltbl) { - MFREE(bus->dhd->osh, ptr, len); - ret = BCME_ERROR; - break; - } - - /* RAM image relocation information */ - dngltbl = ptr; - dngltbl_sz = len; - - /* RAM image should be included before RAM reloc info */ - if ((dnglfw == NULL) || (hstfw->va == NULL)) { - ret = BCME_ERROR; - break; - } - /* Store the fw assumed host memory base */ - bus->hostfw_base = *(uint32 *)(dnglfw + *(uint32 *)dngltbl); - bus->hostfw_base &= PCIE_HYBRIDFW_HOSTOFFSET_MASK; - - DHD_INFO(("%s FW assumed host base address is %08x\n", - __FUNCTION__, bus->hostfw_base)); - - ret = dhdpcie_hybridfw_ptrrpl(dnglfw, dnglfw_sz, - (uint32 *)dngltbl, dngltbl_sz, hstfw->pa, hstfw->len); - break; - - case PCIE_HYBRIDFW_TYPE_HOSTTBL: - /* cannot have more than one host image relocation info */ - if (hsttbl) { - MFREE(bus->dhd->osh, ptr, len); - ret = BCME_ERROR; - break; - } - /* Host image relocation information */ - hsttbl = ptr; - hsttbl_sz = len; - - /* Host image should be included before host reloc info */ - if (hstfw->va == NULL) { - ret = BCME_ERROR; - break; - } - ret = dhdpcie_hybridfw_ptrrpl(hstfw->va, hstfw->len, - (uint32 *)hsttbl, hsttbl_sz, hstfw->pa, hstfw->len); - break; - - default: - ret = BCME_ERROR; - break; - } - - } while (!ret && (fsize > 0)); - - if (ret != BCME_OK) { - DHD_ERROR(("%s: err:%d, fsize:%d, t:%d, l:%d\n", - __FUNCTION__, ret, fsize, type, len)); - goto exit; - } - - if ((uint32*)dnglfw == NULL) { - DHD_ERROR(("%s: Dongle image should be present in combo file\n", - __FUNCTION__)); - ret = BCME_ERROR; - goto exit; - } - - if (hstfw->va) { - OSL_CACHE_FLUSH((void *)hstfw->va, hstfw->len); - } - - /* for CR4/CA7 store the reset instruction to be written in 0 */ - if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0) || si_setcore(bus->sih, ARMCA7_CORE_ID, 0)) { - bus->resetinstr = *(((uint32*)dnglfw)); - /* Add start of RAM address to the address given by user */ - offset += bus->dongle_ram_base; - } - - ret = dhdpcie_bus_membytes(bus, TRUE, offset, (uint8 *)dnglfw, dnglfw_sz); - if (ret) { - DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", - __FUNCTION__, ret, dnglfw_sz, offset)); - goto exit; - } - - /* Configrue bptopcie register to allow ARM access the host offload area */ - bus->bp_base = PCIEDEV_ARM_ADDR(PHYSADDRLO(hstfw->pa), PCIEDEV_TRANS_WIN_HOSTMEM); - dhdpcie_sbtopcie_translation_config(bus, PCIEDEV_TRANS_WIN_HOSTMEM, hstfw->pa); - - /* Check if the buffer is crossing 32MB Window */ - if (((bus->bp_base + hstfw->len) & PCIEDEV_ARM_ADDR_SPACE) < - (bus->bp_base & PCIEDEV_ARM_ADDR_SPACE)) { - DHD_ERROR(("Host memomery crissing 32MB window." - " Entire hostmem block should be within continuous 32MB block")); - ret = BCME_ERROR; - goto exit; - } - - DHD_ERROR(("%s %d bytes host offload firmware placed at pa %08x %08x\n", - __FUNCTION__, hstfw->len, - (uint)PHYSADDRHI(hstfw->pa), (uint)PHYSADDRLO(hstfw->pa))); - -exit: - if (dnglfw) { - MFREE(bus->dhd->osh, dnglfw, dnglfw_sz); - } - - if (dngltbl) { - MFREE(bus->dhd->osh, dngltbl, dngltbl_sz); - } - - if (hsttbl) { - MFREE(bus->dhd->osh, hsttbl, hsttbl_sz); - } - - if (ret && hstfw->va) { - DMA_FREE_CONSISTENT(bus->dhd->osh, hstfw->va, hstfw->_alloced, - hstfw->pa, hstfw->dmah); - memset(hstfw, 0, sizeof(*hstfw)); - } - - return ret; -} -#endif /* BCMINTERNAL */ - #ifdef DHD_LINUX_STD_FW_API static int dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path) @@ -4018,12 +3984,24 @@ dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path) dhd_tcm_test_enable = FALSE; } #endif /* DHD_FW_MEM_CORRUPTION */ - DHD_ERROR(("%s: dhd_tcm_test_enable %u\n", __FUNCTION__, dhd_tcm_test_enable)); - /* TCM check */ - if (dhd_tcm_test_enable && !dhd_bus_tcm_test(bus)) { - DHD_ERROR(("dhd_bus_tcm_test failed\n")); - bcmerror = BCME_ERROR; - goto err; + DHD_ERROR(("%s: dhd_tcm_test_enable %u, dhd_tcm_test_status %u, dhd_tcm_test_mode %u\n", + __FUNCTION__, dhd_tcm_test_enable, dhd_tcm_test_status, dhd_tcm_test_mode)); + + if (dhd_tcm_test_enable && dhd_tcm_test_mode != TCM_TEST_MODE_DISABLE) { + if (((dhd_tcm_test_mode == TCM_TEST_MODE_ONCE) && + (dhd_tcm_test_status == TCM_TEST_NOT_RUN)) || + (dhd_tcm_test_mode == TCM_TEST_MODE_ALWAYS)) { + if (dhd_tcm_test_status != TCM_TEST_PASSED) { + if (dhd_bus_tcm_test(bus) == FALSE) { + DHD_ERROR(("dhd_bus_tcm_test failed\n")); + dhd_tcm_test_status = TCM_TEST_FAILED; + bcmerror = BCME_ERROR; + goto err; + } else { + dhd_tcm_test_status = TCM_TEST_PASSED; + } + } + } } DHD_ERROR(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); @@ -4047,6 +4025,9 @@ dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path) } } #endif + + bus->fw_download_len = fw->size; + bus->fw_download_addr = bus->dongle_ram_base; residual_len = fw->size; while (residual_len) { len = MIN(residual_len, MEMBLOCK); @@ -4054,15 +4035,19 @@ dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path) /* if address is 0, store the reset instruction to be written in 0 */ if (store_reset) { ASSERT(offset == 0); - bus->resetinstr = *(((uint32*)fw->data + buf_offset)); + bus->resetinstr = *(((const uint32*)fw->data + buf_offset)); /* Add start of RAM address to the address given by user */ offset += bus->dongle_ram_base; offset_end += offset; store_reset = FALSE; } + /* Ignore compiler warnings due to -Werror=cast-qual */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); bcmerror = dhdpcie_bus_membytes(bus, TRUE, offset, (uint8 *)fw->data + buf_offset, len); + GCC_DIAGNOSTIC_POP(); + if (bcmerror) { DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", __FUNCTION__, bcmerror, MEMBLOCK, offset)); @@ -4121,18 +4106,19 @@ dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path) int offset = 0; int len = 0; bool store_reset; - char *imgbuf = NULL; /**< XXX a file pointer, contradicting its name and type */ + void *filep = NULL; uint8 *memblock = NULL, *memptr = NULL; #ifdef CHECK_DOWNLOAD_FW uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct #endif int offset_end = bus->ramsize; uint32 file_size = 0, read_len = 0; + fwpkg_info_t *fwpkg; #if defined(CACHE_FW_IMAGES) int buf_offset, total_len, residual_len; - char * dnld_buf; -#endif /* CACHE_FW_IMAGE */ + char * dnld_buf = NULL; +#endif /* CACHE_FW_IMAGES */ #if defined(linux) || defined(LINUX) #if defined(DHD_FW_MEM_CORRUPTION) @@ -4142,53 +4128,49 @@ dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path) dhd_tcm_test_enable = FALSE; } #endif /* DHD_FW_MEM_CORRUPTION */ - DHD_ERROR(("%s: dhd_tcm_test_enable %u\n", __FUNCTION__, dhd_tcm_test_enable)); - /* TCM check */ - if (dhd_tcm_test_enable && !dhd_bus_tcm_test(bus)) { - DHD_ERROR(("dhd_bus_tcm_test failed\n")); - bcmerror = BCME_ERROR; - goto err; + DHD_ERROR(("%s: dhd_tcm_test_enable %u, dhd_tcm_test_status %u\n", __FUNCTION__, + dhd_tcm_test_enable, dhd_tcm_test_status)); + /* run TCM test if not passed yet */ + if (dhd_tcm_test_enable && dhd_tcm_test_status != TCM_TEST_PASSED) { + if (dhd_bus_tcm_test(bus) == FALSE) { + DHD_ERROR(("dhd_bus_tcm_test failed\n")); + dhd_tcm_test_status = TCM_TEST_FAILED; + bcmerror = BCME_ERROR; + goto err; + } else { + dhd_tcm_test_status = TCM_TEST_PASSED; + } } #endif /* LINUX || linux */ -#ifndef DHD_EFI - DHD_ERROR(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); -#endif /* DHD_EFI */ + DHD_ERROR_MEM(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); + bcmerror = fwpkg_init(&bus->fwpkg, pfw_path); + if (bcmerror == BCME_ERROR) { + printf("%s: fwpkg_init failed %s\n", __FUNCTION__, pfw_path); + goto err; + } + fwpkg = &bus->fwpkg; /* Should succeed in opening image if it is actually given through registry * entry or in module param. */ - imgbuf = dhd_os_open_image1(bus->dhd, pfw_path); - if (imgbuf == NULL) { + bcmerror = fwpkg_open_firmware_img(fwpkg, pfw_path, &filep); + if (bcmerror == BCME_ERROR) { printf("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path); goto err; } - file_size = dhd_os_get_image_size(imgbuf); - if (!file_size) { - DHD_ERROR(("%s: get file size fails ! \n", __FUNCTION__)); - goto err; + if (bcmerror == BCME_UNSUPPORTED) { + file_size = fwpkg->file_size; + DHD_ERROR(("%s Using SINGLE image (size %d)\n", + __FUNCTION__, file_size)); + } else { + file_size = fwpkg_get_firmware_img_size(fwpkg); + strlcpy(bus->fwsig_filename, pfw_path, sizeof(bus->fwsig_filename)); + DHD_ERROR(("%s Using COMBINED image (size %d)\n", + __FUNCTION__, file_size)); } - -#ifdef BCMINTERNAL - /* dhdpcie_hybridfw_download return BCME_UNSUPPORTED if the binary - * doesn't have a recognizable format. Continue to previous routine - * in such case. Return and propagate the result for BCME_OK or - * other errors - */ - bcmerror = dhdpcie_hybridfw_download(bus, imgbuf); - if (bcmerror != BCME_UNSUPPORTED) { - goto err; - } - - /* Close and re-open the image file to reset the file pointer. - * Needed because dhdpcie_hybridfw_download() already read 4 bytes from the file. - */ - dhd_os_close_image1(bus->dhd, imgbuf); - imgbuf = dhd_os_open_image1(bus->dhd, pfw_path); - if (imgbuf == NULL) { - goto err; - } -#endif /* BCMINTERNAL */ + bus->fw_download_len = file_size; + bus->fw_download_addr = bus->dongle_ram_base; memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); if (memblock == NULL) { @@ -4214,8 +4196,8 @@ dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path) si_setcore(bus->sih, ARMCA7_CORE_ID, 0)); #if defined(CACHE_FW_IMAGES) total_len = bus->ramsize; - dhd_os_close_image(imgbuf); - imgbuf = NULL; + dhd_os_close_image(filep); + filep = NULL; buf_offset = 0; bcmerror = dhd_get_download_buffer(bus->dhd, pfw_path, FW, &dnld_buf, &total_len); if (bcmerror != BCME_OK) { @@ -4223,14 +4205,12 @@ dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path) goto err; } residual_len = total_len; -#endif /* CACHE_FW_IMAGE */ /* Download image with MEMBLOCK size */ -#if defined(CACHE_FW_IMAGES) while (residual_len) #else /* Download image with MEMBLOCK size */ - while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, imgbuf))) -#endif /* CACHE_FW_IMAGE */ + while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, filep))) +#endif /* CACHE_FW_IMAGES */ { #if defined(CACHE_FW_IMAGES) len = MIN(residual_len, MEMBLOCK); @@ -4243,7 +4223,7 @@ dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path) bcmerror = BCME_ERROR; goto err; } -#endif /* CACHE_FW_IMAGE */ +#endif /* CACHE_FW_IMAGES */ read_len += len; if (read_len > file_size) { @@ -4307,19 +4287,20 @@ err: MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN); #endif } +#if defined(CACHE_FW_IMAGES) + if (dnld_buf) { + dhd_free_download_buffer(bus->dhd, dnld_buf, total_len); + } +#endif /* CACHE_FW_IMAGES */ - if (imgbuf) { - dhd_os_close_image1(bus->dhd, imgbuf); + if (filep) { + dhd_os_close_image1(bus->dhd, filep); } return bcmerror; } /* dhdpcie_download_code_file */ #endif /* DHD_LINUX_STD_FW_API */ -#ifdef CUSTOMER_HW4_DEBUG -#define MIN_NVRAMVARS_SIZE 128 -#endif /* CUSTOMER_HW4_DEBUG */ - static int dhdpcie_download_nvram(struct dhd_bus *bus) { @@ -4331,20 +4312,24 @@ dhdpcie_download_nvram(struct dhd_bus *bus) bool nvram_file_exists; bool nvram_uefi_exists = FALSE; bool local_alloc = FALSE; +#ifdef SUPPORT_OTA_UPDATE + ota_update_info_t *ota_info = &bus->dhd->ota_update_info; +#endif /* SUPPORT_OTA_UPDATE */ pnv_path = bus->nv_path; nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); /* First try UEFI */ len = MAX_NVRAMBUF_SIZE; - dhd_get_download_buffer(bus->dhd, NULL, NVRAM, &memblock, (int *)&len); + bcmerror = dhd_get_download_buffer(bus->dhd, NULL, NVRAM, &memblock, (int *)&len); /* If UEFI empty, then read from file system */ if ((len <= 0) || (memblock == NULL)) { if (nvram_file_exists) { len = MAX_NVRAMBUF_SIZE; - dhd_get_download_buffer(bus->dhd, pnv_path, NVRAM, &memblock, (int *)&len); + bcmerror = dhd_get_download_buffer(bus->dhd, pnv_path, NVRAM, &memblock, + (int *)&len); if ((len <= 0 || len > MAX_NVRAMBUF_SIZE)) { goto err; } @@ -4371,29 +4356,20 @@ dhdpcie_download_nvram(struct dhd_bus *bus) } else { nvram_uefi_exists = TRUE; } -#ifdef DHD_LINUX_STD_FW_API - memblock_len = len; -#else memblock_len = MAX_NVRAMBUF_SIZE; -#endif /* DHD_LINUX_STD_FW_API */ - DHD_ERROR(("%s: dhd_get_download_buffer len %d\n", __FUNCTION__, len)); + DHD_ERROR_MEM(("%s: dhd_get_download_buffer len %d\n", __FUNCTION__, len)); - if (len > 0 && len <= MAX_NVRAMBUF_SIZE && memblock != NULL) { + if (len > 0 && len < MAX_NVRAMBUF_SIZE && memblock != NULL) { bufp = (char *) memblock; -#ifdef DHD_EFI - dhd_insert_random_mac_addr(bus->dhd, bufp, &len); - -#endif /* DHD_EFI */ - #ifdef CACHE_FW_IMAGES if (bus->processed_nvram_params_len) { len = bus->processed_nvram_params_len; } if (!bus->processed_nvram_params_len) { - bufp[len] = 0; + bufp[len-1] = 0; if (nvram_uefi_exists || nvram_file_exists) { len = process_nvram_vars(bufp, len); bus->processed_nvram_params_len = len; @@ -4401,22 +4377,14 @@ dhdpcie_download_nvram(struct dhd_bus *bus) } else #else { - bufp[len] = 0; + bufp[len-1] = 0; if (nvram_uefi_exists || nvram_file_exists) { len = process_nvram_vars(bufp, len); } } #endif /* CACHE_FW_IMAGES */ - DHD_ERROR(("%s: process_nvram_vars len %d\n", __FUNCTION__, len)); -#ifdef CUSTOMER_HW4_DEBUG - if (len < MIN_NVRAMVARS_SIZE) { - DHD_ERROR(("%s: invalid nvram size in process_nvram_vars \n", - __FUNCTION__)); - bcmerror = BCME_ERROR; - goto err; - } -#endif /* CUSTOMER_HW4_DEBUG */ + DHD_ERROR_MEM(("%s: process_nvram_vars len %d\n", __FUNCTION__, len)); if (len % 4) { len += 4 - (len % 4); @@ -4433,17 +4401,26 @@ dhdpcie_download_nvram(struct dhd_bus *bus) err: if (memblock) { - if (local_alloc) { - MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); - } else { - dhd_free_download_buffer(bus->dhd, memblock, memblock_len); +#ifdef SUPPORT_OTA_UPDATE + if (ota_info->nvram_len) { + MFREE(bus->dhd->osh, ota_info->nvram_buf, ota_info->nvram_len); + ota_info->nvram_len = 0; + } + else +#endif /* SUPPORT_OTA_UPDATE */ + { + if (local_alloc) { + MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); + } else { + dhd_free_download_buffer(bus->dhd, memblock, memblock_len); + } } } return bcmerror; } -#if defined(BCMEMBEDIMAGE) && defined (BCM_ROUTER_DHD) +#if defined(BCMEMBEDIMAGE) && defined(BCM_ROUTER_DHD) #ifdef DLIMAGE_43602a1 #define CHIPID_43602 BCM43602_CHIP_ID @@ -4555,10 +4532,6 @@ dhdpcie_download_code_array(struct dhd_bus *bus) remaining_len = 0; len = 0; -#ifdef DHD_EFI - p_dlarray = rtecdc_fw_arr; - dlarray_size = sizeof(rtecdc_fw_arr); -#else #ifndef BCM_ROUTER_DHD p_dlarray = dlarray; dlarray_size = sizeof(dlarray); @@ -4569,13 +4542,10 @@ dhdpcie_download_code_array(struct dhd_bus *bus) select_fd_image(bus, &p_dlarray, &p_dlimagename, &p_dlimagever, &p_dlimagedate, &dlarray_size); #endif /* endif for BCM_ROUTER_DHD */ -#endif /* DHD_EFI */ -#ifndef DHD_EFI if ((p_dlarray == 0) || (dlarray_size == 0) ||(dlarray_size > bus->ramsize) || (p_dlimagename == 0) || (p_dlimagever == 0) || (p_dlimagedate == 0)) goto err; -#endif /* DHD_EFI */ memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); if (memblock == NULL) { @@ -4643,13 +4613,6 @@ dhdpcie_download_code_array(struct dhd_bus *bus) uploded_len += len; offset += MEMBLOCK; } -#ifdef DHD_EFI - if (memcmp(p_dlarray, ularray, dlarray_size)) { - DHD_ERROR(("%s: Downloaded image is corrupted ! \n", __FUNCTION__)); - goto upload_err; - } else - DHD_ERROR(("%s: Download, Upload and compare succeeded .\n", __FUNCTION__)); -#else if (memcmp(p_dlarray, ularray, dlarray_size)) { DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n", __FUNCTION__, p_dlimagename, p_dlimagever, p_dlimagedate)); @@ -4658,7 +4621,6 @@ dhdpcie_download_code_array(struct dhd_bus *bus) } else DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", __FUNCTION__, p_dlimagename, p_dlimagever, p_dlimagedate)); -#endif /* DHD_EFI */ upload_err: if (ularray) @@ -4808,7 +4770,7 @@ _dhdpcie_download_firmware(struct dhd_bus *bus) /* External image takes precedence if specified */ if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { - if (dhdpcie_download_code_file(bus, bus->fw_path)) { + if ((bcmerror = dhdpcie_download_code_file(bus, bus->fw_path))) { DHD_ERROR(("%s:%d dongle image file download failed\n", __FUNCTION__, __LINE__)); #ifdef BCMEMBEDIMAGE @@ -4844,11 +4806,15 @@ _dhdpcie_download_firmware(struct dhd_bus *bus) /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */ /* External nvram takes precedence if specified */ - if (dhdpcie_download_nvram(bus)) { + if ((bcmerror = dhdpcie_download_nvram(bus))) { DHD_ERROR(("%s:%d dongle nvram file download failed\n", __FUNCTION__, __LINE__)); goto err; } + if (CHIPID(bus->sih->chip) == BCM43711_CHIP_ID) { + si_pmu_43711a0_pll_war(bus->sih); + } + /* Take arm out of reset */ if (dhdpcie_bus_download_state(bus, FALSE)) { DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__)); @@ -4889,7 +4855,7 @@ dhdpcie_bus_readconsole(dhd_bus_t *bus) c->bufsize = ltoh32(c->log.buf_size); if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) return BCME_NOMEM; - DHD_PCIE_INFO(("conlog: bufsize=0x%x\n", c->bufsize)); + DHD_INFO(("conlog: bufsize=0x%x\n", c->bufsize)); } idx = ltoh32(c->log.idx); @@ -4901,7 +4867,7 @@ dhdpcie_bus_readconsole(dhd_bus_t *bus) if (idx == c->last) return BCME_OK; - DHD_PCIE_INFO(("conlog: addr=0x%x, idx=0x%x, last=0x%x \n", c->log.buf, + DHD_INFO(("conlog: addr=0x%x, idx=0x%x, last=0x%x \n", c->log.buf, idx, c->last)); /* Read the console buffer data to a local buffer @@ -5055,6 +5021,101 @@ dhdpcie_schedule_log_dump(dhd_bus_t *bus) #endif /* DHD_DUMP_FILE_WRITE_FROM_KERNEL && DHD_LOG_DUMP */ } +#ifdef DHD_SSSR_DUMP +extern uint fis_enab; +#endif /* DHD_SSSR_DUMP */ + +dhd_pcie_link_state_type_t +dhdpcie_get_link_state(dhd_bus_t *bus) +{ + uint32 intstatus; + uint origidx; + dhd_pcie_link_state_type_t link_state = DHD_PCIE_ALL_GOOD; + uint32 status_cmd = dhd_pcie_config_read(bus, PCIECFGREG_STATUS_CMD, sizeof(uint32)); + if (status_cmd == (uint32) -1) { + DHD_ERROR(("%s: pcie link down: status_cmd:0x%x\n", __FUNCTION__, status_cmd)); + link_state = DHD_PCIE_LINK_DOWN; + bus->is_linkdown = 1; + goto exit; + } + + /* Check the common backplane status */ + intstatus = si_corereg(bus->sih, bus->sih->buscoreidx, bus->pcie_mailbox_int, 0, 0); + if (intstatus == (uint32) -1) { + DHD_ERROR(("%s: common backplane is down, intstatus:0x%x\n", + __FUNCTION__, intstatus)); + link_state = DHD_PCIE_COMMON_BP_DOWN; + goto exit; + } + + if (MULTIBP_ENAB(bus->sih)) { + dhd_bus_pcie_pwr_req(bus); + } + + origidx = si_coreidx(bus->sih); + + /* Switch to SYSMEM core and check for wlan backplane status */ + if (si_setcore(bus->sih, SYSMEM_CORE_ID, 0)) { + uint32 ioctrl = si_wrapperreg(bus->sih, AI_IOCTRL, 0, 0); + uint32 resetctrl = si_wrapperreg(bus->sih, AI_RESETCTRL, 0, 0); + DHD_ERROR(("%s: sysmem ioctrl:0x%x resetctrl:0x%x\n", + __FUNCTION__, ioctrl, resetctrl)); + if (ioctrl == (uint32) -1) { + DHD_ERROR(("%s: wlan backplane is down ioctrl:0x%x\n", + __FUNCTION__, ioctrl)); + link_state = DHD_PCIE_WLAN_BP_DOWN; + } + } else { + DHD_ERROR(("%s: Failed to find SYSMEM core!\n", __FUNCTION__)); + } + + /* Restore back to original core */ + si_setcoreidx(bus->sih, origidx); + + if (MULTIBP_ENAB(bus->sih)) { + dhd_bus_pcie_pwr_req_clear(bus); + } + +exit: + return link_state; +} + +void +dhd_validate_pcie_link_cbp_wlbp(dhd_bus_t *bus) +{ + bus->link_state = dhdpcie_get_link_state(bus); + + if (bus->link_state == DHD_PCIE_ALL_GOOD) { + dhd_bus_dump_imp_cfg_registers(bus); + dhd_bus_dump_dar_registers(bus); + } else if (bus->link_state == DHD_PCIE_LINK_DOWN) { + DHD_ERROR(("%s: pcie link down\n", __FUNCTION__)); + bus->is_linkdown = 1; + } else if (bus->link_state == DHD_PCIE_COMMON_BP_DOWN) { + dhd_bus_dump_imp_cfg_registers(bus); + dhd_bus_dump_dar_registers(bus); + bus->is_linkdown = 1; + } else if (bus->link_state == DHD_PCIE_WLAN_BP_DOWN) { + dhd_bus_dump_imp_cfg_registers(bus); + dhd_bus_dump_dar_registers(bus); +#if defined(DHD_FW_COREDUMP) +#ifdef DHD_SSSR_DUMP +#ifdef OEM_ANDROID + DHD_ERROR(("%s : Set collect_sssr and fis_enab as TRUE\n", __FUNCTION__)); + bus->dhd->collect_sssr = TRUE; + fis_enab = TRUE; +#endif /* OEM_ANDROID */ +#endif /* DHD_SSSR_DUMP */ + /* save core dump or write to a file */ + if (bus->dhd->memdump_enabled) { + bus->dhd->memdump_type = DUMP_TYPE_READ_SHM_FAIL; + dhdpcie_mem_dump(bus); + } +#endif /* DHD_FW_COREDUMP */ + } + return; +} + /** * Opens the file given by bus->fw_path, reads part of the file into a buffer and closes the file. * @@ -5075,7 +5136,7 @@ dhdpcie_checkdied(dhd_bus_t *bus, char *data, uint size) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - if (DHD_NOCHECKDIED_ON()) { + if (DHD_NOCHECKDIED_ON() || dhd_query_bus_erros(bus->dhd)) { return 0; } @@ -5173,7 +5234,7 @@ dhdpcie_checkdied(dhd_bus_t *bus, char *data, uint size) } if (bus->pcie_sh->flags & (PCIE_SHARED_ASSERT | PCIE_SHARED_TRAP)) { - printf("%s: %s\n", __FUNCTION__, strbuf.origbuf); + DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); #ifdef REPORT_FATAL_TIMEOUTS /** * stop the timers as FW trapped @@ -5202,19 +5263,28 @@ dhdpcie_checkdied(dhd_bus_t *bus, char *data, uint size) dhd_bus_dump_console_buffer(bus); dhd_prot_debug_info_print(bus->dhd); -#if defined(DHD_FW_COREDUMP) - /* save core dump or write to a file */ - if (bus->dhd->memdump_enabled) { +#ifdef DHD_FW_COREDUMP +#ifdef OEM_ANDROID + if (bus->dhd->up == 0) { + DHD_ERROR(("%s: socram will be collected in dhd_net_bus_devreset failure\n", + __FUNCTION__)); + bus->dhd->dongle_trap_during_wifi_onoff = 1; + } else +#endif /* OEM_ANDROID */ + { + /* save core dump or write to a file */ + if (bus->dhd->memdump_enabled) { #ifdef DHD_SSSR_DUMP - DHD_ERROR(("%s : Set collect_sssr as TRUE\n", __FUNCTION__)); - bus->dhd->collect_sssr = TRUE; + DHD_ERROR(("%s : Set collect_sssr as TRUE\n", __FUNCTION__)); + bus->dhd->collect_sssr = TRUE; #endif /* DHD_SSSR_DUMP */ #ifdef DHD_SDTC_ETB_DUMP - DHD_ERROR(("%s : Set collect_sdtc as TRUE\n", __FUNCTION__)); - bus->dhd->collect_sdtc = TRUE; + DHD_ERROR(("%s : Set collect_sdtc as TRUE\n", __FUNCTION__)); + bus->dhd->collect_sdtc = TRUE; #endif /* DHD_SDTC_ETB_DUMP */ - bus->dhd->memdump_type = DUMP_TYPE_DONGLE_TRAP; - dhdpcie_mem_dump(bus); + bus->dhd->memdump_type = DUMP_TYPE_DONGLE_TRAP; + dhdpcie_mem_dump(bus); + } } #endif /* DHD_FW_COREDUMP */ @@ -5247,10 +5317,10 @@ dhdpcie_checkdied(dhd_bus_t *bus, char *data, uint size) } -#ifdef WL_CFGVENDOR_SEND_HANG_EVENT - copy_hang_info_trap(bus->dhd); -#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */ - +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT + bus->dhd->alert_reason = ALERT_DONGLE_TRAP; + dhd_os_send_alert_message(bus->dhd); +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ dhd_schedule_reset(bus->dhd); #ifdef NDIS @@ -5260,6 +5330,33 @@ dhdpcie_checkdied(dhd_bus_t *bus, char *data, uint size) dhd_bus_check_died(bus); #endif + } else if (bus->dhd->dongle_trap_data) { + DHD_ERROR(("%s: TRAP/ASSERT flag not set in shared flags:0x%x\n", + __FUNCTION__, bus->pcie_sh->flags)); + bus->dhd->dongle_trap_occured = TRUE; +#ifdef DHD_FW_COREDUMP +#ifdef OEM_ANDROID + if (bus->dhd->up == 0) { + DHD_ERROR(("%s: socram will be collected in dhd_net_bus_devreset failure\n", + __FUNCTION__)); + } else +#endif /* OEM_ANDROID */ + { + /* save core dump or write to a file */ + if (bus->dhd->memdump_enabled) { +#ifdef DHD_SSSR_DUMP + DHD_ERROR(("%s : Set collect_sssr as TRUE\n", __FUNCTION__)); + bus->dhd->collect_sssr = TRUE; +#endif /* DHD_SSSR_DUMP */ +#ifdef DHD_SDTC_ETB_DUMP + DHD_ERROR(("%s : Set collect_sdtc as TRUE\n", __FUNCTION__)); + bus->dhd->collect_sdtc = TRUE; +#endif /* DHD_SDTC_ETB_DUMP */ + bus->dhd->memdump_type = DUMP_TYPE_DONGLE_TRAP; + dhdpcie_mem_dump(bus); + } + } +#endif /* DHD_FW_COREDUMP */ } done1: @@ -5345,15 +5442,27 @@ dhdpcie_get_mem_dump(dhd_bus_t *bus) #ifdef BOARD_HIKEY unsigned long flags_bus; #endif /* BOARD_HIKEY */ +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) + dhd_dongledump_status_t dump_status; +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ if (!bus) { DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); - return BCME_ERROR; + ret = BCME_ERROR; + goto exit; } if (!bus->dhd) { DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); - return BCME_ERROR; + ret = BCME_ERROR; + goto exit; + } + + if (bus->link_state == DHD_PCIE_WLAN_BP_DOWN) { + DHD_ERROR(("%s: DHD_PCIE_WLAN_BP_DOWN return success and collect only FIS if set\n", + __FUNCTION__)); + ret = BCME_OK; + goto exit; } size = bus->ramsize; /* Full mem size */ @@ -5364,9 +5473,17 @@ dhdpcie_get_mem_dump(dhd_bus_t *bus) if (!p_buf) { DHD_ERROR(("%s: Out of memory (%d bytes)\n", __FUNCTION__, size)); - return BCME_ERROR; + ret = BCME_ERROR; + goto exit; } +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) + dump_status = dhd_get_dump_status(bus->dhd); + if (dump_status != DUMP_IN_PROGRESS) { + dhd_set_dump_status(bus->dhd, DUMP_IN_PROGRESS); + } +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ + /* Read mem content */ DHD_TRACE_HW4(("Dump dongle memory\n")); databuf = p_buf; @@ -5395,6 +5512,13 @@ dhdpcie_get_mem_dump(dhd_bus_t *bus) start += read_size; databuf += read_size; } +exit: +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) + if (ret != BCME_OK) { + dhd_set_dump_status(bus->dhd, DUMP_FAILURE); + } +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ + return ret; } @@ -5402,9 +5526,12 @@ static int dhdpcie_mem_dump(dhd_bus_t *bus) { dhd_pub_t *dhdp; - int ret; + int ret = BCME_OK; uint32 dhd_console_ms_prev = 0; +#ifdef GDB_PROXY + bus->gdb_proxy_mem_dump_count++; +#endif /* GDB_PROXY */ dhdp = bus->dhd; if (!dhdp) { DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); @@ -5417,19 +5544,10 @@ dhdpcie_mem_dump(dhd_bus_t *bus) __FUNCTION__, dhd_console_ms_prev)); dhdp->dhd_console_ms = 0; } -#ifdef EXYNOS_PCIE_DEBUG - exynos_pcie_register_dump(1); -#endif /* EXYNOS_PCIE_DEBUG */ -#ifdef SUPPORT_LINKDOWN_RECOVERY - if (bus->is_linkdown) { - DHD_ERROR(("%s: PCIe link is down so skip\n", __FUNCTION__)); - /* panic only for DUMP_MEMFILE_BUGON */ - ASSERT(bus->dhd->memdump_enabled != DUMP_MEMFILE_BUGON); - ret = BCME_ERROR; - goto exit; - } -#endif /* SUPPORT_LINKDOWN_RECOVERY */ +#if defined(__linux__) + dhd_plat_pcie_register_dump(dhdp->plat_info); +#endif /* __linux__ */ if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp)) { DHD_ERROR(("%s: bus is down! can't collect mem dump. \n", __FUNCTION__)); @@ -5453,18 +5571,63 @@ dhdpcie_mem_dump(dhd_bus_t *bus) /* intentional fall through */ case DUMP_TYPE_BY_LIVELOCK: /* intentional fall through */ + case DUMP_TYPE_TRANS_ID_MISMATCH: + /* intentional fall through */ case DUMP_TYPE_IFACE_OP_FAILURE: /* intentional fall through */ case DUMP_TYPE_PKTID_POOL_DEPLETED: /* intentional fall through */ case DUMP_TYPE_ESCAN_SYNCID_MISMATCH: /* intentional fall through */ + case DUMP_TYPE_PROXD_TIMEOUT: + /* intentional fall through */ + case DUMP_TYPE_INBAND_DEVICE_WAKE_FAILURE: + /* intentional fall through */ case DUMP_TYPE_INVALID_SHINFO_NRFRAGS: + /* intentional fall through */ + case DUMP_TYPE_P2P_DISC_BUSY: + /* intentional fall through */ if (dhdp->db7_trap.fw_db7w_trap) { /* Set fw_db7w_trap_inprogress here and clear from DPC */ dhdp->db7_trap.fw_db7w_trap_inprogress = TRUE; dhdpcie_fw_trap(dhdp->bus); OSL_DELAY(100 * 1000); // wait 100 msec + /* + * Since dpc may have triggered db7, it will not pre-empt itself + * so if trap_data is 0, re-read trap_data before giving up + */ + if (dhdp->dongle_trap_data == 0) { + dhdp->dongle_trap_data = dhd_prot_process_trapbuf(dhdp); + } + if (dhdp->db7_trap.fw_db7w_trap_recieved) { + /* Collect SSSR dump for all non trap cases + * only after DB7 ack + */ +#ifdef DHD_SSSR_DUMP + DHD_ERROR(("%s : Set collect_sssr as TRUE after DB7\n", + __FUNCTION__)); + dhdp->collect_sssr = TRUE; +#endif /* DHD_SSSR_DUMP */ +#ifdef DHD_SDTC_ETB_DUMP + DHD_ERROR(("%s : Set collect_sdtc as TRUE after DB7\n", + __FUNCTION__)); + dhdp->collect_sdtc = TRUE; +#endif /* DHD_SDTC_ETB_DUMP */ + } else { + DHD_ERROR(("%s : Did not receive DB7 Ack\n", __FUNCTION__)); +#ifdef WBRC + DHD_ERROR(("%s : Set do_chip_bighammer\n", __FUNCTION__)); + bus->dhd->do_chip_bighammer = TRUE; +#endif /* WBRC */ + } + DHD_ERROR(("Function_Intstatus(0x%x)=0x%x " + "Function_Intmask(0x%x)=0x%x\n", + PCIFunctionIntstatus(bus->sih->buscorerev), + si_corereg(bus->sih, bus->sih->buscoreidx, + PCIFunctionIntstatus(bus->sih->buscorerev), 0, 0), + PCIFunctionIntmask(bus->sih->buscorerev), + si_corereg(bus->sih, bus->sih->buscoreidx, + PCIFunctionIntmask(bus->sih->buscorerev), 0, 0))); } else { DHD_ERROR(("%s: DB7 Not supported!!!\n", __FUNCTION__)); @@ -5479,22 +5642,20 @@ dhdpcie_mem_dump(dhd_bus_t *bus) return BCME_ERROR; #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ - ret = dhdpcie_get_mem_dump(bus); - if (ret) { - DHD_ERROR(("%s: failed to get mem dump, err=%d\n", - __FUNCTION__, ret)); - goto exit; + if (dhdp->skip_memdump_map_read == FALSE) { + ret = dhdpcie_get_mem_dump(bus); + if (ret) { + DHD_ERROR(("%s: failed to get mem dump, err=%d\n", __FUNCTION__, ret)); + goto exit; + } + } else { + DHD_ERROR(("%s: Skipped to get mem dump, err=%d\n", __FUNCTION__, ret)); + dhdp->skip_memdump_map_read = FALSE; } #ifdef DHD_DEBUG_UART bus->dhd->memdump_success = TRUE; #endif /* DHD_DEBUG_UART */ -#ifdef BCMINTERNAL - /* TODO: for host offload firmware, need to modify the stack and pc/lr to point it back to - * the original offset so gdb can match with symbol files - */ -#endif - dhd_schedule_memdump(dhdp, dhdp->soc_ram, dhdp->soc_ram_length); /* buf, actually soc_ram free handled in dhd_{free,clear} */ @@ -5509,6 +5670,7 @@ exit: __FUNCTION__, dhd_console_ms_prev)); dhdp->dhd_console_ms = dhd_console_ms_prev; } + return ret; } @@ -5535,9 +5697,6 @@ dhd_bus_mem_dump(dhd_pub_t *dhdp) } /* Try to resume if already suspended or suspend in progress */ -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(dhdp, CAN_SLEEP(), __builtin_return_address(0)); -#endif /* DHD_PCIE_RUNTIMEPM */ /* Skip if still in suspended or suspend in progress */ if (DHD_BUS_CHECK_SUSPEND_OR_ANY_SUSPEND_IN_PROGRESS(dhdp)) { @@ -5577,7 +5736,7 @@ dhdpcie_bus_membytes(dhd_bus_t *bus, bool write, ulong address, uint8 *data, uin int detect_endian_flag = 0x01; bool little_endian; - if (write && bus->is_linkdown) { + if (bus->is_linkdown) { DHD_ERROR(("%s: PCIe link was down\n", __FUNCTION__)); return BCME_ERROR; } @@ -5662,16 +5821,18 @@ extern bool agg_h2d_db_enab; * to the (non flow controlled) flow ring. */ int -BCMFASTPATH(dhd_bus_schedule_queue)(struct dhd_bus *bus, uint16 flow_id, bool txs) +BCMFASTPATH(dhd_bus_schedule_queue)(struct dhd_bus *bus, uint16 flow_id, bool txs, + uint32 bound, bool *is_qempty) /** XXX function name could be more descriptive, eg use 'tx' and 'flow ring' in name */ { flow_ring_node_t *flow_ring_node; int ret = BCME_OK; #ifdef DHD_LOSSLESS_ROAMING dhd_pub_t *dhdp = bus->dhd; -#endif +#endif /* DHD_LOSSLESS_ROAMING */ + uint32 cnt = 0; - DHD_PCIE_INFO(("%s: flow_id is %d\n", __FUNCTION__, flow_id)); + DHD_INFO(("%s: flow_id is %d\n", __FUNCTION__, flow_id)); /* ASSERT on flow_id */ if (flow_id >= bus->max_submission_rings) { @@ -5713,6 +5874,11 @@ BCMFASTPATH(dhd_bus_schedule_queue)(struct dhd_bus *bus, uint16 flow_id, bool t return BCME_NOTREADY; } + if (queue->len == 0) { + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + return BCME_NOTREADY; + } + while ((txp = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) { if (bus->dhd->conf->orphan_move <= 1) PKTORPHAN(txp, bus->dhd->conf->tsq); @@ -5741,6 +5907,7 @@ BCMFASTPATH(dhd_bus_schedule_queue)(struct dhd_bus *bus, uint16 flow_id, bool t #endif /* DHDTCPACK_SUPPRESS */ /* Attempt to transfer packet over flow ring */ /* XXX: ifidx is wrong */ + ++cnt; #ifdef TPUT_MONITOR pktlen = PKTLEN(OSH_NULL, txp); if ((bus->dhd->conf->data_drop_mode == TXPKT_DROP) && (pktlen > 500)) @@ -5762,6 +5929,9 @@ BCMFASTPATH(dhd_bus_schedule_queue)(struct dhd_bus *bus, uint16 flow_id, bool t dhd_flow_queue_reinsert(bus->dhd, queue, txp); DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + if (is_qempty) { + *is_qempty = FALSE; + } /* If we are able to requeue back, return success */ return BCME_OK; } @@ -5769,15 +5939,17 @@ BCMFASTPATH(dhd_bus_schedule_queue)(struct dhd_bus *bus, uint16 flow_id, bool t #ifdef DHD_MEM_STATS DHD_MEM_STATS_LOCK(bus->dhd->mem_stats_lock, flags); bus->dhd->txpath_mem += PKTLEN(bus->dhd->osh, txp); - DHD_PCIE_INFO(("%s txpath_mem: %llu PKTLEN: %d\n", + DHD_INFO(("%s txpath_mem: %llu PKTLEN: %d\n", __FUNCTION__, bus->dhd->txpath_mem, PKTLEN(bus->dhd->osh, txp))); DHD_MEM_STATS_UNLOCK(bus->dhd->mem_stats_lock, flags); #endif /* DHD_MEM_STATS */ + + /* check bound and break if exceeded */ + if (bound && cnt >= bound) { + break; + } } -#ifdef DHD_HP2P - if (!flow_ring_node->hp2p_ring) -#endif /* DHD_HP2P */ { #ifdef AGG_H2D_DB if (agg_h2d_db_enab) { @@ -5790,6 +5962,10 @@ BCMFASTPATH(dhd_bus_schedule_queue)(struct dhd_bus *bus, uint16 flow_id, bool t } DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + + if (is_qempty) { + *is_qempty = queue->len > 0 ? FALSE : TRUE; + } } return ret; @@ -5912,7 +6088,7 @@ BCMFASTPATH(dhd_bus_txdata)(struct dhd_bus *bus, void *txp, uint8 ifidx) DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); if (flow_ring_node->status) { - DHD_PCIE_INFO(("%s: Enq pkt flowid %d, status %d active %d\n", + DHD_INFO(("%s: Enq pkt flowid %d, status %d active %d\n", __FUNCTION__, flowid, flow_ring_node->status, flow_ring_node->active)); if (txp_pend) { @@ -5921,7 +6097,7 @@ BCMFASTPATH(dhd_bus_txdata)(struct dhd_bus *bus, void *txp, uint8 ifidx) } return BCME_OK; } - ret = dhd_bus_schedule_queue(bus, flowid, FALSE); /* from queue to flowring */ + ret = dhd_bus_schedule_queue(bus, flowid, FALSE, 0, NULL); /* from queue to flowring */ /* If we have anything pending, try to push into q */ if (txp_pend) { @@ -5962,15 +6138,8 @@ BCMFASTPATH(dhd_bus_txdata)(struct dhd_bus *bus, void *txp, uint8 ifidx) return ret; toss: - DHD_PCIE_INFO(("%s: Toss %d\n", __FUNCTION__, ret)); -#ifdef DHD_EFI - /* for EFI, pass the 'send' flag as false, to avoid enqueuing the failed tx pkt - * into the Tx done queue - */ - PKTCFREE(bus->dhd->osh, txp, FALSE); -#else + DHD_INFO(("%s: Toss %d\n", __FUNCTION__, ret)); PKTCFREE(bus->dhd->osh, txp, TRUE); -#endif /* DHD_EFI */ return ret; } /* dhd_bus_txdata */ @@ -6080,7 +6249,7 @@ BCMFASTPATH(dhd_bus_rx_frame)(struct dhd_bus *bus, void* pkt, int ifidx, uint pk BCM_REFERENCE(flags) /* Init/Deinit bar1_switch_lock only if the chip supports bar1 switching */ -static void +void dhd_init_bar1_switch_lock(dhd_bus_t *bus) { if (bus->bar1_switch_enab && !bus->bar1_switch_lock) { @@ -6134,7 +6303,7 @@ dhdpcie_bar1_window_switch_enab(dhd_bus_t *bus) bus->bar1_switch_enab = TRUE; } - DHD_ERROR(("%s: bar1_switch_enab=%d ramstart=0x%x ramend=0x%x bar1_size=0x%x\n", + DHD_ERROR_MEM(("%s: bar1_switch_enab=%d ramstart=0x%x ramend=0x%x bar1_size=0x%x\n", __FUNCTION__, bus->bar1_switch_enab, ramstart, ramend, bus->bar1_size)); } @@ -6170,22 +6339,13 @@ dhdpcie_bus_chkandshift_bpoffset(dhd_bus_t *bus, ulong offset) { uint32 bpwin; -#ifdef DHD_EFI - /* TODO: bar1_size is hardcoded for EFI. Below logic should be - * revisited. Also EFI platform should find bar1_size from - * EFI Kernel APIs - */ - if (!bus->bar1_switch_enab) { - return offset; - } -#endif /* DHD_EFI */ /* Determine BAR1 backplane window using window size * Window address mask should be ~(size - 1) */ bpwin = DHD_BUS_BAR1_BPWIN(offset, bus->bar1_size); if (bpwin != bus->curr_bar1_win) { - DHD_PCIE_INFO(("%s: move BAR1 window curr_bar1_win=0x%x bpwin=0x%x offset=0x%lx\n", + DHD_INFO(("%s: move BAR1 window curr_bar1_win=0x%x bpwin=0x%x offset=0x%lx\n", __FUNCTION__, bus->curr_bar1_win, bpwin, offset)); /* Move BAR1 window */ dhdpcie_setbar1win(bus, bpwin); @@ -6331,7 +6491,7 @@ dhdpcie_bus_rtcm16(dhd_bus_t *bus, ulong offset) offset = dhdpcie_bus_chkandshift_bpoffset(bus, offset); -#if (defined(linux) || defined (LINUX)) +#if (defined(linux) || defined(LINUX)) data = R_REG(bus->dhd->osh, (volatile uint16 *)(bus->tcm + offset)); #else data = *(volatile uint16 *)(bus->tcm + offset); @@ -6357,7 +6517,7 @@ dhdpcie_bus_rtcm32(dhd_bus_t *bus, ulong offset) offset = dhdpcie_bus_chkandshift_bpoffset(bus, offset); -#if (defined(linux) || defined (LINUX)) +#if (defined(linux) || defined(LINUX)) data = R_REG(bus->dhd->osh, (volatile uint32 *)(bus->tcm + offset)); #else data = *(volatile uint32 *)(bus->tcm + offset); @@ -6384,7 +6544,7 @@ dhdpcie_bus_rtcm64(dhd_bus_t *bus, ulong offset) offset = dhdpcie_bus_chkandshift_bpoffset(bus, offset); -#if (defined(linux) || defined (LINUX)) +#if (defined(linux) || defined(LINUX)) data = R_REG(bus->dhd->osh, (volatile uint64 *)(bus->tcm + offset)); #else data = *(volatile uint64 *)(bus->tcm + offset); @@ -6453,7 +6613,7 @@ dhd_bus_cmn_writeshared(dhd_bus_t *bus, void *data, uint32 len, uint8 type, uint uint64 long_data; ulong addr; /* dongle address */ - DHD_PCIE_INFO(("%s: writing to dongle type %d len %d\n", __FUNCTION__, type, len)); + DHD_INFO(("%s: writing to dongle type %d len %d\n", __FUNCTION__, type, len)); if (bus->is_linkdown) { DHD_ERROR(("%s: PCIe link was down\n", __FUNCTION__)); @@ -6585,7 +6745,7 @@ dhd_bus_cmn_writeshared(dhd_bus_t *bus, void *data, uint32 len, uint8 type, uint long_data = HTOL64(*(uint64 *)data); addr = DHD_PCIE_SHARED_MEMBER_ADDR(bus, host_trap_addr); dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *) &long_data, len); - DHD_PCIE_INFO(("Wrote trap addr:0x%x\n", (uint32) HTOL32(*(uint32 *)data))); + DHD_INFO(("Wrote trap addr:0x%x\n", (uint32) HTOL32(*(uint32 *)data))); break; #ifdef D2H_MINIDUMP @@ -6602,10 +6762,18 @@ dhd_bus_cmn_writeshared(dhd_bus_t *bus, void *data, uint32 len, uint8 type, uint #else /* !DHD_SUPPORT_64BIT */ dhdpcie_bus_wtcm32(bus, addr, *((uint32*)data)); #endif /* DHD_SUPPORT_64BIT */ - DHD_PCIE_INFO(("Wrote host_scb_addr:0x%x\n", + DHD_INFO(("Wrote host_scb_addr:0x%x\n", (uint32) HTOL32(*(uint32 *)data))); break; +#ifdef DHD_PCIE_PTM + case HOST_CAP2: + addr = DHD_PCIE_SHARED_MEMBER_ADDR(bus, host_cap2); + dhdpcie_bus_wtcm32(bus, addr, (uint32) HTOL32(*(uint32 *)data)); + DHD_INFO(("Wrote host_cap2 0x%x\n", (uint32) HTOL32(*(uint32 *)data))); + break; +#endif /* DHD_PCIE_PTM */ + default: break; } @@ -6689,6 +6857,9 @@ void dhd_bus_clearcounts(dhd_pub_t *dhdp) { dhd_prot_clearcounts(dhdp); + dhdp->rx_pktgetpool_fail = 0; + + dhd_clear_dpc_histos(dhdp); } /** @@ -6722,7 +6893,7 @@ dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, if (!(!set || (!params && !plen))) return BCME_BADARG; - DHD_PCIE_INFO(("%s: %s %s, len %d plen %d\n", __FUNCTION__, + DHD_INFO(("%s: %s %s, len %d plen %d\n", __FUNCTION__, name, (set ? "set" : "get"), len, plen)); /* Look up var locally; if not found pass to host driver */ @@ -6927,7 +7098,7 @@ dhd_buzzz_dump_log(char *p, uint32 *core, uint32 *log, bcm_buzzz_t *buzzz) break; } default: - printf("%s: Maximum one argument supported\n", __FUNCTION__); + DHD_CONS_ONLY(("%s: Maximum one argument supported\n", __FUNCTION__)); break; } @@ -6959,11 +7130,11 @@ void dhd_buzzz_dump(bcm_buzzz_t *buzzz_p, void *buffer_p, char *p) } if (total == 0U) { - printf("%s: bcm_buzzz_dump total<%u> done\n", __FUNCTION__, total); + DHD_CONS_ONLY(("%s: bcm_buzzz_dump total<%u> done\n", __FUNCTION__, total)); return; } else { - printf("%s: bcm_buzzz_dump total<%u> : part2<%u> + part1<%u>\n", __FUNCTION__, - total, part2, part1); + DHD_CONS_ONLY(("%s: bcm_buzzz_dump total<%u> : part2<%u> + part1<%u>\n", + __FUNCTION__, total, part2, part1)); } if (part2) { /* with wrap */ @@ -6984,7 +7155,7 @@ void dhd_buzzz_dump(bcm_buzzz_t *buzzz_p, void *buffer_p, char *p) log = (void*)((size_t)log + buzzz_p->log_sz); } - printf("%s: bcm_buzzz_dump done.\n", __FUNCTION__); + DHD_CONS_ONLY(("%s: bcm_buzzz_dump done.\n", __FUNCTION__)); } int dhd_buzzz_dump_dngl(dhd_bus_t *bus) @@ -6999,11 +7170,11 @@ int dhd_buzzz_dump_dngl(dhd_bus_t *bus) return BCME_UNSUPPORTED; } if ((page_p = (char *)MALLOC(bus->dhd->osh, 4096)) == NULL) { - printf("%s: Page memory allocation failure\n", __FUNCTION__); + DHD_CONS_ONLY(("%s: Page memory allocation failure\n", __FUNCTION__)); goto done; } if ((buzzz_p = MALLOC(bus->dhd->osh, sizeof(bcm_buzzz_t))) == NULL) { - printf("%s: BCM BUZZZ memory allocation failure\n", __FUNCTION__); + DHD_CONS_ONLY(("%s: BCM BUZZZ memory allocation failure\n", __FUNCTION__)); goto done; } @@ -7022,24 +7193,24 @@ int dhd_buzzz_dump_dngl(dhd_bus_t *bus) dhdpcie_bus_membytes(bus, FALSE, (ulong)sh->buzz_dbg_ptr, (uint8 *)buzzz_p, sizeof(bcm_buzzz_t)); - printf("BUZZZ[0x%08x]: log<0x%08x> cur<0x%08x> end<0x%08x> " + DHD_CONS_ONLY(("BUZZZ[0x%08x]: log<0x%08x> cur<0x%08x> end<0x%08x> " "count<%u> status<%u> wrap<%u>\n" "cpu<0x%02X> counters<%u> group<%u> buffer_sz<%u> log_sz<%u>\n", (int)sh->buzz_dbg_ptr, (int)buzzz_p->log, (int)buzzz_p->cur, (int)buzzz_p->end, buzzz_p->count, buzzz_p->status, buzzz_p->wrap, buzzz_p->cpu_idcode, buzzz_p->counters, buzzz_p->group, - buzzz_p->buffer_sz, buzzz_p->log_sz); + buzzz_p->buffer_sz, buzzz_p->log_sz)); if (buzzz_p->count == 0) { - printf("%s: Empty dongle BUZZZ trace\n\n", __FUNCTION__); + DHD_CONS_ONLY(("%s: Empty dongle BUZZZ trace\n\n", __FUNCTION__)); goto done; } /* Allocate memory for trace buffer and format strings */ buffer_p = MALLOC(bus->dhd->osh, buzzz_p->buffer_sz); if (buffer_p == NULL) { - printf("%s: Buffer memory allocation failure\n", __FUNCTION__); + DHD_CONS_ONLY(("%s: Buffer memory allocation failure\n", __FUNCTION__)); goto done; } @@ -7054,12 +7225,12 @@ int dhd_buzzz_dump_dngl(dhd_bus_t *bus) for (ctr = 0; ctr < buzzz_p->counters; ctr++) { printf(" ", buzzz_p->eventid[ctr]); } - printf("\n"); + DHD_CONS_ONLY(("\n")); } dhd_buzzz_dump(buzzz_p, buffer_p, page_p); - printf("%s: ----- End of dongle BCM BUZZZ Trace -----\n\n", __FUNCTION__); + DHD_CONS_ONLY(("%s: ----- End of dongle BCM BUZZZ Trace -----\n\n", __FUNCTION__)); MFREE(bus->dhd->osh, buffer_p, buzzz_p->buffer_sz); buffer_p = NULL; } @@ -7164,6 +7335,7 @@ dhd_bus_perform_flr(dhd_bus_t *bus, bool force_fail) uint flr_capab; uint val; int retry = 0; + bool in_flr_already = FALSE; DHD_ERROR(("******** Perform FLR ********\n")); @@ -7191,48 +7363,74 @@ dhd_bus_perform_flr(dhd_bus_t *bus, bool force_fail) DHD_ERROR(("Chip does not support FLR\n")); return BCME_UNSUPPORTED; } + /* Check if we are already in FLR, if we are then just go to restore part of it */ + val = OSL_PCI_READ_CONFIG(bus->osh, PCIE_CFG_SUBSYSTEM_CONTROL, sizeof(val)); + DHD_ERROR(("config space 0x88 is 0x%x\n", val)); + if (val & (1 << PCIE_SSRESET_STATUS_BIT)) { + DHD_ERROR(("******** device already in FLR, so clear only ********\n")); + in_flr_already = TRUE; + } + else { + DHD_ERROR(("******** device not in FLR ********\n")); + } + if (!in_flr_already) { -#if defined(NDIS) && defined(BT_OVER_PCIE) - dhd_bwm_bt_quiesce(bus); -#endif + bus->ptm_ctrl_reg = dhdpcie_bus_cfg_read_dword(bus, PCI_CFG_PTM_CTRL, 4); - /* Save pcie config space */ - DHD_INFO(("Save Pcie Config Space\n")); - DHD_PCIE_CONFIG_SAVE(bus); + /* Save pcie config space */ + DHD_INFO(("Save Pcie Config Space\n")); + DHD_PCIE_CONFIG_SAVE(bus); - /* Set bit 15 of PCIE_CFG_DEVICE_CONTROL */ - DHD_INFO(("Set PCIE_FUNCTION_LEVEL_RESET_BIT(%d) of PCIE_CFG_DEVICE_CONTROL(0x%x)\n", - PCIE_FUNCTION_LEVEL_RESET_BIT, PCIE_CFG_DEVICE_CONTROL)); - val = OSL_PCI_READ_CONFIG(bus->osh, PCIE_CFG_DEVICE_CONTROL, sizeof(val)); - DHD_INFO(("read_config: reg=0x%x read val=0x%x\n", PCIE_CFG_DEVICE_CONTROL, val)); - val = val | (1 << PCIE_FUNCTION_LEVEL_RESET_BIT); - DHD_INFO(("write_config: reg=0x%x write val=0x%x\n", PCIE_CFG_DEVICE_CONTROL, val)); - OSL_PCI_WRITE_CONFIG(bus->osh, PCIE_CFG_DEVICE_CONTROL, sizeof(val), val); + /* Set bit 15 of PCIE_CFG_DEVICE_CONTROL */ + DHD_INFO(("Set PCIE_FUNCTION_LEVEL_RESET_BIT(%d) of" + " PCIE_CFG_DEVICE_CONTROL(0x%x)\n", + PCIE_FUNCTION_LEVEL_RESET_BIT, PCIE_CFG_DEVICE_CONTROL)); + val = OSL_PCI_READ_CONFIG(bus->osh, PCIE_CFG_DEVICE_CONTROL, sizeof(val)); + DHD_INFO(("read_config: reg=0x%x read val=0x%x\n", PCIE_CFG_DEVICE_CONTROL, val)); + val = val | (1 << PCIE_FUNCTION_LEVEL_RESET_BIT); + DHD_INFO(("write_config: reg=0x%x write val=0x%x\n", PCIE_CFG_DEVICE_CONTROL, val)); + OSL_PCI_WRITE_CONFIG(bus->osh, PCIE_CFG_DEVICE_CONTROL, sizeof(val), val); + if (bus->lpm_keep_in_reset) { + /* Keep the device in FLR */ + DHD_ERROR(("******** device force FLR only ********\n")); + return BCME_OK; + } + else { + DHD_ERROR(("******** device force FLR only not set ********\n")); + } - /* wait for DHD_FUNCTION_LEVEL_RESET_DELAY msec */ + /* wait for DHD_FUNCTION_LEVEL_RESET_DELAY msec */ #ifdef BCMSLTGT - DHD_ERROR(("Delay of %d msec\n", DHD_FUNCTION_LEVEL_RESET_DELAY * htclkratio)); + DHD_ERROR_MEM(("Delay of %d msec\n", DHD_FUNCTION_LEVEL_RESET_DELAY * htclkratio)); #else - DHD_INFO(("Delay of %d msec\n", DHD_FUNCTION_LEVEL_RESET_DELAY)); + DHD_ERROR_MEM(("Delay of %d msec\n", DHD_FUNCTION_LEVEL_RESET_DELAY)); #endif /* BCMSLTGT */ - CAN_SLEEP() ? OSL_SLEEP(DHD_FUNCTION_LEVEL_RESET_DELAY) : - OSL_DELAY(DHD_FUNCTION_LEVEL_RESET_DELAY * USEC_PER_MSEC); + CAN_SLEEP() ? OSL_SLEEP(DHD_FUNCTION_LEVEL_RESET_DELAY) : + OSL_DELAY(DHD_FUNCTION_LEVEL_RESET_DELAY * USEC_PER_MSEC); +#ifdef USE_ISB_IN_FLR + OSL_ISB(); +#endif /* USE_ISB_IN_FLR */ - if (force_fail) { - DHD_ERROR(("Set PCIE_SSRESET_DISABLE_BIT(%d) of PCIE_CFG_SUBSYSTEM_CONTROL(0x%x)\n", - PCIE_SSRESET_DISABLE_BIT, PCIE_CFG_SUBSYSTEM_CONTROL)); - val = OSL_PCI_READ_CONFIG(bus->osh, PCIE_CFG_SUBSYSTEM_CONTROL, sizeof(val)); - DHD_ERROR(("read_config: reg=0x%x read val=0x%x\n", PCIE_CFG_SUBSYSTEM_CONTROL, - val)); - val = val | (1 << PCIE_SSRESET_DISABLE_BIT); - DHD_ERROR(("write_config: reg=0x%x write val=0x%x\n", PCIE_CFG_SUBSYSTEM_CONTROL, - val)); - OSL_PCI_WRITE_CONFIG(bus->osh, PCIE_CFG_SUBSYSTEM_CONTROL, sizeof(val), val); + if (force_fail) { + DHD_ERROR(("Set PCIE_SSRESET_DISABLE_BIT(%d) of" + " PCIE_CFG_SUBSYSTEM_CONTROL(0x%x)\n", + PCIE_SSRESET_DISABLE_BIT, PCIE_CFG_SUBSYSTEM_CONTROL)); + val = OSL_PCI_READ_CONFIG(bus->osh, PCIE_CFG_SUBSYSTEM_CONTROL, + sizeof(val)); + DHD_ERROR(("read_config: reg=0x%x read val=0x%x\n", + PCIE_CFG_SUBSYSTEM_CONTROL, val)); + val = val | (1 << PCIE_SSRESET_DISABLE_BIT); + DHD_ERROR(("write_config: reg=0x%x write val=0x%x\n", + PCIE_CFG_SUBSYSTEM_CONTROL, val)); + OSL_PCI_WRITE_CONFIG(bus->osh, PCIE_CFG_SUBSYSTEM_CONTROL, + sizeof(val), val); - val = OSL_PCI_READ_CONFIG(bus->osh, PCIE_CFG_SUBSYSTEM_CONTROL, sizeof(val)); - DHD_ERROR(("read_config: reg=0x%x read val=0x%x\n", PCIE_CFG_SUBSYSTEM_CONTROL, - val)); + val = OSL_PCI_READ_CONFIG(bus->osh, PCIE_CFG_SUBSYSTEM_CONTROL, + sizeof(val)); + DHD_ERROR(("read_config: reg=0x%x read val=0x%x\n", + PCIE_CFG_SUBSYSTEM_CONTROL, val)); + } } /* Clear bit 15 of PCIE_CFG_DEVICE_CONTROL */ @@ -7256,7 +7454,7 @@ dhd_bus_perform_flr(dhd_bus_t *bus, bool force_fail) } while (val && (retry++ < DHD_SSRESET_STATUS_RETRIES)); if (val) { - DHD_ERROR(("ERROR: reg=0x%x bit %d is not cleared\n", + DHD_ERROR_MEM(("ERROR: reg=0x%x bit %d is not cleared\n", PCIE_CFG_SUBSYSTEM_CONTROL, PCIE_SSRESET_STATUS_BIT)); /* User has to fire the IOVAR again, if force_fail is needed */ if (force_fail) { @@ -7266,14 +7464,12 @@ dhd_bus_perform_flr(dhd_bus_t *bus, bool force_fail) return BCME_DONGLE_DOWN; } + dhdpcie_bus_cfg_write_dword(bus, PCI_CFG_PTM_CTRL, 4, bus->ptm_ctrl_reg); + /* Restore pcie config space */ DHD_INFO(("Restore Pcie Config Space\n")); DHD_PCIE_CONFIG_RESTORE(bus); -#if defined(NDIS) && defined(BT_OVER_PCIE) - dhd_bwm_bt_resume(bus); -#endif - DHD_ERROR(("******** FLR Succedeed ********\n")); return BCME_OK; @@ -7626,7 +7822,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) do { bcmerror = dhdpcie_bus_start_host_dev(bus); if (!bcmerror) { - DHD_ERROR(("%s: dhdpcie_bus_start_host_dev OK\n", + DHD_ERROR_MEM(("%s: dhdpcie_bus_start_host_dev OK\n", __FUNCTION__)); break; } else { @@ -7644,9 +7840,6 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) #endif /* DHD_CONTROL_PCIE_ASPM_WIFI_TURNON */ bus->is_linkdown = 0; bus->cto_triggered = 0; -#ifdef SUPPORT_LINKDOWN_RECOVERY - bus->read_shm_fail = FALSE; -#endif /* SUPPORT_LINKDOWN_RECOVERY */ bcmerror = dhdpcie_bus_enable_device(bus); if (bcmerror) { DHD_ERROR(("%s: host configuration restore failed: %d\n", @@ -7660,9 +7853,6 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) __FUNCTION__, bcmerror)); goto done; } -#if defined(DHD_HP2P) && defined(OEM_ANDROID) - bus->dhd->hp2p_enable = TRUE; -#endif #ifdef FORCE_DONGLE_RESET_IN_DEVRESET_ON /* @@ -7842,20 +8032,6 @@ pcie2_mdioop(dhd_bus_t *bus, uint physmedia, uint regaddr, bool write, uint *val } #endif /* DHD_PCIE_REG_ACCESS */ -#ifdef BCMINTERNAL -static uint64 -serialized_backplane_access_64(dhd_bus_t *bus, uint addr, uint size, uint64 *val, bool read) -{ - uint64 ret; - unsigned long flags; - - DHD_BACKPLANE_ACCESS_LOCK(bus->backplane_access_lock, flags); - ret = si_backplane_access_64(bus->sih, addr, size, val, read); - DHD_BACKPLANE_ACCESS_UNLOCK(bus->backplane_access_lock, flags); - return ret; -} -#endif /* BCMINTERNAL */ - static int dhdpcie_get_dma_ring_indices(dhd_pub_t *dhd) { @@ -7962,9 +8138,9 @@ BCMRAMFN(dhd_cap_bcmstrbuf)(dhd_pub_t *dhd, struct bcmstrbuf *b) bcm_bprintf(b, "lbtxp "); #endif /* DHD_LB_TXP_DEFAULT_ENAB */ #endif /* DHD_LB_TXP */ -#ifdef DHD_HTPUT_TUNABLES - bcm_bprintf(b, "htput "); -#endif /* DHD_HTPUT_TUNABLES */ + if (dhd->htput_support) { + bcm_bprintf(b, "htput "); + } } /** Return dhd capability string */ @@ -7998,9 +8174,6 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons void *params, uint plen, void *arg, uint len, int val_size) { int bcmerror = 0; -#ifdef BCMINTERNAL - uint64 uint64_val = 0; -#endif /* BCMINTERNAL */ int32 int_val = 0; int32 int_val2 = 0; int32 int_val3 = 0; @@ -8032,74 +8205,6 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons switch (actionid) { -#ifdef BCMINTERNAL - case IOV_SVAL(IOV_MSI_SIM): - /* allocate memory for MSI (Message Signaled Interrupt) window */ - int_val = !!int_val; - DHD_INFO(("int_val is %d\n", int_val)); - if (bus->msi_sim != int_val) { - if (int_val) { - /* bus->msi_addr */ - bus->msi_sim_addr = - MALLOC(bus->dhd->osh, MSI_SIM_BUFSIZE); - if (bus->msi_sim_addr) { - *bus->msi_sim_addr = 0; - bus->msi_sim_phys = DMA_MAP(bus->dhd->osh, - bus->msi_sim_addr, MSI_SIM_BUFSIZE, DMA_RX, 0, 0); - /* program the MSI addr */ - si_corereg(bus->sih, bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, - configaddr), ~0, PCIE_CFG_MSIDATA_OFFSET); - si_corereg(bus->sih, bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, - configdata), ~0, PCIE_CFG_MSI_GENDATA); - si_corereg(bus->sih, bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, - configaddr), ~0, PCIE_CFG_MSIADDR_LOW_OFFSET); - ASSERT(PHYSADDRHI(bus->msi_sim_phys) == 0); - si_corereg(bus->sih, bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, - configdata), ~0, (uint32)PHYSADDRLO(bus->msi_sim_phys)); - si_corereg(bus->sih, bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, - configaddr), ~0, PCIE_CFG_MSICAP_OFFSET); - si_corereg(bus->sih, bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, - configdata), ~0, PCIE_CFG_MSICAP_ENABLE_MSI); - /* poll the MSI addr window */ - bus->pollrate = 10; - } - DHD_INFO(("msi_sim_addr is %p\n", bus->msi_sim_addr)); - } else { - /* bus->msi_addr */ - si_corereg(bus->sih, bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, - configaddr), ~0, - PCIE_CFG_MSICAP_OFFSET); - si_corereg(bus->sih, bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, - configdata), ~0, - PCIE_CFG_MSICAP_DISABLE_MSI); - si_corereg(bus->sih, bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, - configaddr), ~0, - PCIE_CFG_MSIADDR_LOW_OFFSET); - si_corereg(bus->sih, bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, configdata), ~0, 0); - - DMA_UNMAP(bus->dhd->osh, bus->msi_sim_phys, - MSI_SIM_BUFSIZE, DMA_RX, 0, 0); - MFREE(bus->dhd->osh, - bus->msi_sim_addr, MSI_SIM_BUFSIZE); - } - bus->msi_sim = (bool)int_val; - } - break; - case IOV_GVAL(IOV_MSI_SIM): - bcopy(&bus->msi_sim, arg, val_size); - break; -#endif /* BCMINTERNAL */ - case IOV_SVAL(IOV_VARS): bcmerror = dhdpcie_downloadvars(bus, arg, len); break; @@ -8286,16 +8391,15 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons bcmerror = dhdmsgbuf_dmaxfer_status(bus->dhd, dmaxfer); break; } - -#ifdef BCMINTERNAL - case IOV_GVAL(IOV_PCIE_TX_LPBK): - int_val = dhdpcie_bus_get_tx_lpback(bus); + case IOV_GVAL(IOV_PCIE_DMAXFER_PTRN): { + int_val = bus->lpbk_xfer_data_pattern_type; bcopy(&int_val, arg, val_size); break; - case IOV_SVAL(IOV_PCIE_TX_LPBK): - bcmerror = dhdpcie_bus_set_tx_lpback(bus, bool_val); + } + case IOV_SVAL(IOV_PCIE_DMAXFER_PTRN): { + bus->lpbk_xfer_data_pattern_type = int_val; break; -#endif /* BCMINTERNAL */ + } #ifdef PCIE_OOB case IOV_GVAL(IOV_OOB_BT_REG_ON): @@ -8359,13 +8463,6 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons else if (int_val == 0) { bus->deep_sleep = FALSE; if (bus->ds_enabled) { -#if defined(DHD_EFI) && defined(DHD_INTR_POLL_PERIOD_DYNAMIC) - bus->dhd->cur_intr_poll_period = dhd_os_get_intr_poll_period(); - /* for accurately measuring ds-exit latency - * set interrupt poll period to a lesser value - */ - dhd_os_set_intr_poll_period(bus, INTR_POLL_PERIOD_CRITICAL); -#endif /* DHD_EFI && DHD_INTR_POLL_PERIOD_DYNAMIC */ bus->calc_ds_exit_latency = TRUE; /* Assert */ if (dhd_bus_set_device_wake(bus, TRUE) == BCME_OK) { @@ -8385,10 +8482,6 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons __FUNCTION__)); } bus->calc_ds_exit_latency = FALSE; -#if defined(DHD_EFI) && defined(DHD_INTR_POLL_PERIOD_DYNAMIC) - /* restore interrupt poll period to the previous existing value */ - dhd_os_set_intr_poll_period(bus, bus->dhd->cur_intr_poll_period); -#endif /* DHD_EFI && DHD_INTR_POLL_PERIOD_DYNAMIC */ } else { DHD_ERROR(("%s: Deep Sleep already disabled !\n", __FUNCTION__)); } @@ -8596,6 +8689,8 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons PCIEDEV_TRANS_WIN_HOSTMEM); ret.hostmem_code_win_length = bus->hostfw_buf.len; } + ret.flags |= DHD_GDB_PROXY_PROBE_MEMDUMP_COUNT; + ret.mem_dump_count = bus->gdb_proxy_mem_dump_count; if (plen && int_val) { bus->gdb_proxy_last_id = (uint32)int_val; } @@ -8724,7 +8819,7 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons break; case IOV_SVAL(IOV_RX_METADATALEN): -#if !(defined(BCM_ROUTER_DHD)) +#if !defined(BCM_ROUTER_DHD) if (int_val > 64) { bcmerror = BCME_BUFTOOLONG; break; @@ -8765,7 +8860,7 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons break; case IOV_SVAL(IOV_TX_METADATALEN): -#if !(defined(BCM_ROUTER_DHD)) +#if !defined(BCM_ROUTER_DHD) if (int_val > 64) { bcmerror = BCME_BUFTOOLONG; break; @@ -8805,39 +8900,6 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons case DHD_BUS_DEVRESET_FLR_FORCE_FAIL: bus->flr_force_fail = TRUE; break; -#ifdef BT_OVER_PCIE - case DHD_BUS_DEVRESET_QUIESCE: - if (bus->dhd->busstate == DHD_BUS_DATA) { - if (bus->dhd->db7_trap.fw_db7w_trap) { - unsigned long flags = 0; - - DHD_GENERAL_LOCK(bus->dhd, flags); - bus->dhd->db7_trap.fw_db7w_trap_inprogress = TRUE; - DHD_GENERAL_UNLOCK(bus->dhd, flags); - dhdpcie_fw_trap(bus); - OSL_DELAY(100 * 1000); // wait 100 msec - DHD_GENERAL_LOCK(bus->dhd, flags); - bus->dhd->db7_trap.fw_db7w_trap_inprogress = FALSE; - DHD_GENERAL_UNLOCK(bus->dhd, flags); - } else { - DHD_TRACE(("%s: DB7 Not supported!!!\n", - __FUNCTION__)); - } - - devreset->status = - dhd_bus_perform_flr_with_quiesce(bus->dhd, bus, - FALSE); - - if (devreset->status == BCME_DNGL_DEVRESET) { - devreset->status = BCME_OK; - } - bcmerror = BCME_DNGL_DEVRESET; - } else { - DHD_ERROR(("%s: Bus is NOT up\n", __FUNCTION__)); - bcmerror = BCME_NOTUP; - } - break; -#endif /* BT_OVER_PCIE */ #endif /* !defined(NDIS) */ default: DHD_ERROR(("%s: invalid argument for devreset\n", __FUNCTION__)); @@ -8863,39 +8925,6 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons bcopy(&int_val, arg, val_size); break; -#ifdef DHD_PCIE_RUNTIMEPM - case IOV_GVAL(IOV_IDLETIME): - if (!(bus->dhd->op_mode & DHD_FLAG_MFG_MODE)) { - int_val = bus->idletime; - } else { - int_val = 0; - } - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_IDLETIME): - if (int_val < 0) { - bcmerror = BCME_BADARG; - } else { - bus->idletime = int_val; - if (bus->idletime) { - DHD_ENABLE_RUNTIME_PM(bus->dhd); - } else { - DHD_DISABLE_RUNTIME_PM(bus->dhd); - } - } - break; -#endif /* DHD_PCIE_RUNTIMEPM */ - - case IOV_GVAL(IOV_TXBOUND): - int_val = (int32)dhd_txbound; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_TXBOUND): - dhd_txbound = (uint)int_val; - break; - case IOV_SVAL(IOV_H2D_MAILBOXDATA): dhdpcie_send_mb_data(bus, (uint)int_val); break; @@ -8940,6 +8969,21 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons bcopy(&int_val, arg, val_size); break; + case IOV_SVAL(IOV_RING_SIZE_VER): + if (bus->dhd->busstate != DHD_BUS_DOWN) { + DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", + __FUNCTION__)); + bcmerror = BCME_NOTDOWN; + break; + } + dhd_prot_set_ring_size_ver(bus->dhd, int_val); + break; + + case IOV_GVAL(IOV_RING_SIZE_VER): + int_val = ring_size_version; + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_H2D_TXPOST_MAX_ITEM): if (bus->dhd->busstate != DHD_BUS_DOWN) { DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", @@ -8947,15 +8991,14 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons bcmerror = BCME_NOTDOWN; break; } - dhd_prot_set_h2d_max_txpost(bus->dhd, (uint16)int_val); + h2d_max_txpost = (uint16)int_val; break; case IOV_GVAL(IOV_H2D_TXPOST_MAX_ITEM): - int_val = dhd_prot_get_h2d_max_txpost(bus->dhd); + int_val = h2d_max_txpost; bcopy(&int_val, arg, val_size); break; -#if defined(DHD_HTPUT_TUNABLES) case IOV_SVAL(IOV_H2D_HTPUT_TXPOST_MAX_ITEM): if (bus->dhd->busstate != DHD_BUS_DOWN) { DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", @@ -8963,22 +9006,170 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons bcmerror = BCME_NOTDOWN; break; } - dhd_prot_set_h2d_htput_max_txpost(bus->dhd, (uint16)int_val); + h2d_htput_max_txpost = (uint16)int_val; break; case IOV_GVAL(IOV_H2D_HTPUT_TXPOST_MAX_ITEM): - int_val = dhd_prot_get_h2d_htput_max_txpost(bus->dhd); - bcopy(&int_val, arg, val_size); - break; -#endif /* DHD_HTPUT_TUNABLES */ - - case IOV_GVAL(IOV_RXBOUND): - int_val = (int32)dhd_rxbound; + int_val = h2d_htput_max_txpost; bcopy(&int_val, arg, val_size); break; - case IOV_SVAL(IOV_RXBOUND): - dhd_rxbound = (uint)int_val; + case IOV_SVAL(IOV_D2H_TXCPL_MAX_ITEM): + if (bus->dhd->busstate != DHD_BUS_DOWN) { + DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", + __FUNCTION__)); + bcmerror = BCME_NOTDOWN; + break; + } + d2h_max_txcpl = (uint16)int_val; + break; + + case IOV_GVAL(IOV_D2H_TXCPL_MAX_ITEM): + int_val = d2h_max_txcpl; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_H2D_RXPOST_MAX_ITEM): + if (bus->dhd->busstate != DHD_BUS_DOWN) { + DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", + __FUNCTION__)); + bcmerror = BCME_NOTDOWN; + break; + } + h2d_max_rxpost = (uint16)int_val; + break; + + case IOV_GVAL(IOV_H2D_RXPOST_MAX_ITEM): + int_val = h2d_max_rxpost; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_D2H_RXCPL_MAX_ITEM): + if (bus->dhd->busstate != DHD_BUS_DOWN) { + DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", + __FUNCTION__)); + bcmerror = BCME_NOTDOWN; + break; + } + d2h_max_rxcpl = (uint16)int_val; + break; + + case IOV_GVAL(IOV_D2H_RXCPL_MAX_ITEM): + int_val = d2h_max_rxcpl; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_H2D_CTRLPOST_MAX_ITEM): + if (bus->dhd->busstate != DHD_BUS_DOWN) { + DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", + __FUNCTION__)); + bcmerror = BCME_NOTDOWN; + break; + } + h2d_max_ctrlpost = (uint16)int_val; + break; + + case IOV_GVAL(IOV_H2D_CTRLPOST_MAX_ITEM): + int_val = h2d_max_ctrlpost; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_D2H_CTRLCPL_MAX_ITEM): + if (bus->dhd->busstate != DHD_BUS_DOWN) { + DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", + __FUNCTION__)); + bcmerror = BCME_NOTDOWN; + break; + } + d2h_max_ctrlcpl = (uint16)int_val; + break; + + case IOV_GVAL(IOV_D2H_CTRLCPL_MAX_ITEM): + int_val = d2h_max_ctrlcpl; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_RX_BUF_BURST): + if (bus->dhd->busstate != DHD_BUS_DOWN) { + DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", + __FUNCTION__)); + bcmerror = BCME_NOTDOWN; + break; + } + rx_buf_burst = (uint16)int_val; + break; + + case IOV_GVAL(IOV_RX_BUF_BURST): + int_val = rx_buf_burst; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_RX_BUFPOST_THRESHOLD): + if (bus->dhd->busstate != DHD_BUS_DOWN) { + DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", + __FUNCTION__)); + bcmerror = BCME_NOTDOWN; + break; + } + rx_bufpost_threshold = (uint16)int_val; + break; + + case IOV_GVAL(IOV_RX_BUFPOST_THRESHOLD): + int_val = rx_bufpost_threshold; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_TX_CPL_BOUND): + int_val = (int32)dhd_prot_get_tx_cpl_bound(bus->dhd); + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_TX_CPL_BOUND): + if (int_val <= 0) { + bcmerror = BCME_BADARG; + DHD_ERROR(("%s: invalid tx_cpl_bound value %d !\n", + __FUNCTION__, int_val)); + } else { + dhd_prot_set_tx_cpl_bound(bus->dhd, (uint)int_val); + } + break; + case IOV_GVAL(IOV_RX_CPL_POST_BOUND): + int_val = (int32)dhd_prot_get_rx_cpl_post_bound(bus->dhd); + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_RX_CPL_POST_BOUND): + if (int_val <= 0) { + bcmerror = BCME_BADARG; + DHD_ERROR(("%s: invalid rx_cpl_post_bound value %d !\n", + __FUNCTION__, int_val)); + } else { + dhd_prot_set_rx_cpl_post_bound(bus->dhd, (uint)int_val); + } + break; + case IOV_GVAL(IOV_CTRL_CPL_POST_BOUND): + int_val = (int32)dhd_prot_get_ctrl_cpl_post_bound(bus->dhd); + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_CTRL_CPL_POST_BOUND): + if (int_val <= 0) { + bcmerror = BCME_BADARG; + DHD_ERROR(("%s: invalid ctrl_cpl_post_bound value %d !\n", + __FUNCTION__, int_val)); + } else { + dhd_prot_set_ctrl_cpl_post_bound(bus->dhd, (uint)int_val); + } + break; + case IOV_GVAL(IOV_TX_POST_BOUND): + int_val = (int32)dhd_prot_get_tx_post_bound(bus->dhd); + bcopy(&int_val, arg, val_size); + break; + case IOV_SVAL(IOV_TX_POST_BOUND): + if (int_val <= 0) { + bcmerror = BCME_BADARG; + DHD_ERROR(("%s: invalid tx_post_bound value %d !\n", + __FUNCTION__, int_val)); + } else { + dhd_prot_set_tx_post_bound(bus->dhd, (uint)int_val); + } break; case IOV_GVAL(IOV_TRAPDATA): @@ -9082,30 +9273,6 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons } break; -#ifdef DHD_EFI - case IOV_SVAL(IOV_CONTROL_SIGNAL): - { - bcmerror = dhd_control_signal(bus, arg, len, TRUE); - break; - } - - case IOV_GVAL(IOV_CONTROL_SIGNAL): - { - bcmerror = dhd_control_signal(bus, params, plen, FALSE); - break; - } - case IOV_GVAL(IOV_WIFI_PROPERTIES): - bcmerror = dhd_wifi_properties(bus, params, plen); - break; - case IOV_GVAL(IOV_OTP_DUMP): - bcmerror = dhd_otp_dump(bus, params, plen); - break; -#if defined(BT_OVER_PCIE) && defined(BTOP_TEST) - case IOV_SVAL(IOV_BTOP_TEST): - bcmerror = dhd_btop_test(bus, arg, len); - break; -#endif /* BT_OVER_PCIE && BTOP_TEST */ -#endif /* DHD_EFI */ case IOV_GVAL(IOV_IDMA_ENABLE): int_val = bus->idma_enabled; bcopy(&int_val, arg, val_size); @@ -9120,31 +9287,6 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons case IOV_SVAL(IOV_IFRM_ENABLE): bus->ifrm_enabled = (bool)int_val; break; -#ifdef BCMINTERNAL - case IOV_GVAL(IOV_DMA_CHAN): - int_val = bus->dma_chan; - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_DMA_CHAN): - { - bus->dma_chan = (bool)int_val; - bus->pcie_mb_intr_addr = si_corereg_addr(bus->sih, bus->sih->buscoreidx, - dhd_bus_db0_addr_get(bus)); - break; - } - case IOV_SVAL(IOV_HYBRIDFW): - { - char *fp; - fp = dhd_os_open_image1(bus->dhd, params); - if (fp == NULL) { - bcmerror = BCME_ERROR; - break; - } - bcmerror = dhdpcie_hybridfw_download(bus, fp); - dhd_os_close_image1(bus->dhd, fp); - break; - } -#endif /* BCMINTERNAL */ case IOV_GVAL(IOV_CLEAR_RING): bcopy(&int_val, arg, val_size); dhd_flow_rings_flush(bus->dhd, 0); @@ -9181,109 +9323,6 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons break; #endif /* D2H_MINIDUMP */ -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE - case IOV_SVAL(IOV_FWTRACE): - { - DHD_INFO(("%s: set firware tracing enable/disable %d\n", - __FUNCTION__, int_val)); - - bcmerror = handle_set_fwtrace(bus->dhd, (uint32) int_val); - break; - } - break; - - case IOV_GVAL(IOV_FWTRACE): - { - uint32 val = 0, temp_val = 0; - uint16 of_counter, trace_val = 0; - int ret; - - ret = dhd_iovar(bus->dhd, 0, "dngl:fwtrace", - NULL, 0, (char *) &val, sizeof(val), FALSE); - if (ret < 0) { - DHD_ERROR(("%s: get dhd_iovar has failed fwtrace, " - "ret=%d\n", __FUNCTION__, ret)); - bcmerror = BCME_ERROR; - } else { - of_counter = get_fw_trace_overflow_counter(bus->dhd); - DHD_INFO(("overflow counter = %d \n", of_counter)); - trace_val = val & 0xFFFF; - temp_val = (((uint32) temp_val | (uint32) of_counter) << 16u) | trace_val; - bcopy(&temp_val, arg, sizeof(temp_val)); - } - break; - } -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ - -#ifdef DHD_HP2P - case IOV_SVAL(IOV_HP2P_ENABLE): - dhd_prot_hp2p_enable(bus->dhd, TRUE, int_val); - break; - - case IOV_GVAL(IOV_HP2P_ENABLE): - int_val = dhd_prot_hp2p_enable(bus->dhd, FALSE, int_val); - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_HP2P_PKT_THRESHOLD): - dhd_prot_pkt_threshold(bus->dhd, TRUE, int_val); - break; - - case IOV_GVAL(IOV_HP2P_PKT_THRESHOLD): - int_val = dhd_prot_pkt_threshold(bus->dhd, FALSE, int_val); - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_HP2P_TIME_THRESHOLD): - dhd_prot_time_threshold(bus->dhd, TRUE, int_val); - break; - - case IOV_GVAL(IOV_HP2P_TIME_THRESHOLD): - int_val = dhd_prot_time_threshold(bus->dhd, FALSE, int_val); - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_HP2P_PKT_EXPIRY): - dhd_prot_pkt_expiry(bus->dhd, TRUE, int_val); - break; - - case IOV_GVAL(IOV_HP2P_PKT_EXPIRY): - int_val = dhd_prot_pkt_expiry(bus->dhd, FALSE, int_val); - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_HP2P_TXCPL_MAXITEMS): - if (bus->dhd->busstate != DHD_BUS_DOWN) { - return BCME_NOTDOWN; - } - dhd_bus_set_hp2p_ring_max_size(bus, TRUE, int_val); - break; - - case IOV_GVAL(IOV_HP2P_TXCPL_MAXITEMS): - int_val = dhd_bus_get_hp2p_ring_max_size(bus, TRUE); - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_HP2P_RXCPL_MAXITEMS): - if (bus->dhd->busstate != DHD_BUS_DOWN) { - return BCME_NOTDOWN; - } - dhd_bus_set_hp2p_ring_max_size(bus, FALSE, int_val); - break; - - case IOV_GVAL(IOV_HP2P_RXCPL_MAXITEMS): - int_val = dhd_bus_get_hp2p_ring_max_size(bus, FALSE); - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_HP2P_MF_ENABLE): - bus->dhd->hp2p_mf_enable = int_val ? TRUE : FALSE; - break; - - case IOV_GVAL(IOV_HP2P_MF_ENABLE): - int_val = bus->dhd->hp2p_mf_enable ? 1 : 0; - bcopy(&int_val, arg, val_size); - break; -#endif /* DHD_HP2P */ case IOV_SVAL(IOV_EXTDTXS_IN_TXCPL): if (bus->dhd->busstate != DHD_BUS_DOWN) { return BCME_NOTDOWN; @@ -9314,47 +9353,138 @@ dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, cons bcopy(&int_val, arg, val_size); break; -#ifdef BCMINTERNAL - case IOV_GVAL(IOV_SBREG_64): + case IOV_GVAL(IOV_DONGLE_RXLAT_INFO): { - sdreg_64_t sdreg; - uint32 addr, size; + unsigned long flags = 0; + struct bcmstrbuf strbuf; - bcopy(params, &sdreg, sizeof(sdreg)); - - addr = sdreg.offset | SI_ENUM_BASE(bus->sih); - size = sdreg.func; - - if (serialized_backplane_access_64(bus, addr, size, - &uint64_val, TRUE) != BCME_OK) - { - DHD_ERROR(("Invalid size/addr combination \n")); - bcmerror = BCME_ERROR; - break; - } - bcopy(&uint64_val, arg, size); + bcm_binit(&strbuf, arg, len); + DHD_GENERAL_LOCK(bus->dhd, flags); + dhd_bus_dump_rxlat_info(bus->dhd, &strbuf); + DHD_GENERAL_UNLOCK(bus->dhd, flags); break; } - case IOV_SVAL(IOV_SBREG_64): + case IOV_GVAL(IOV_DONGLE_RXLAT_HISTO): { - sdreg_64_t sdreg; - uint32 addr, size; + unsigned long flags = 0; + struct bcmstrbuf strbuf; - bcopy(params, &sdreg, sizeof(sdreg)); + bcm_binit(&strbuf, arg, len); + DHD_GENERAL_LOCK(bus->dhd, flags); + dhd_bus_dump_rxlat_histo(bus->dhd, &strbuf); + DHD_GENERAL_UNLOCK(bus->dhd, flags); + break; + } - addr = sdreg.offset | SI_ENUM_BASE(bus->sih); - size = sdreg.func; + case IOV_GVAL(IOV_DONGLE_TXCPL_INFO): + { + unsigned long flags = 0; + struct bcmstrbuf strbuf; - if (serialized_backplane_access_64(bus, addr, size, - (uint64 *)(&sdreg.value), FALSE) != BCME_OK) { - DHD_ERROR(("Invalid size/addr combination \n")); - bcmerror = BCME_ERROR; + bcm_binit(&strbuf, arg, len); + DHD_GENERAL_LOCK(bus->dhd, flags); + dhd_bus_dump_txcpl_info(bus->dhd, &strbuf); + DHD_GENERAL_UNLOCK(bus->dhd, flags); + break; + } + + case IOV_GVAL(IOV_DONGLE_SEC_INFO): + { + unsigned long flags = 0; + struct bcmstrbuf strbuf; + + bcm_binit(&strbuf, arg, len); + DHD_GENERAL_LOCK(bus->dhd, flags); + bcmerror = dhd_bus_security_info(bus->dhd, &strbuf); + DHD_GENERAL_UNLOCK(bus->dhd, flags); + break; + } + + case IOV_GVAL(IOV_DONGLE_SBOOT_DIS): + { + unsigned long flags = 0; + struct bcmstrbuf strbuf; + + bcm_binit(&strbuf, arg, len); + DHD_GENERAL_LOCK(bus->dhd, flags); + bcmerror = dhd_bus_sboot_disable(bus->dhd, &strbuf); + DHD_GENERAL_UNLOCK(bus->dhd, flags); + break; + } + case IOV_GVAL(IOV_LPM_MODE): + int_val = bus->lpm_mode; + if (bus->lpm_mode) { + if (!bus->lpm_mem_kill) { + int_val |= LPM_MODE_NO_MEMKILL; + } + if (!bus->lpm_force_flr) { + int_val |= LPM_MODE_NO_FLR; + } + } + (void)memcpy_s(arg, val_size, &int_val, sizeof(int_val)); + break; + case IOV_SVAL(IOV_LPM_MODE): + if (int_val) { + bus->lpm_mode = TRUE; + if (int_val & LPM_MODE_NO_MEMKILL) { + bus->lpm_mem_kill = FALSE; + } + else { + bus->lpm_mem_kill = TRUE; + } + if (int_val & LPM_MODE_NO_FLR) { + bus->lpm_force_flr = FALSE; + } + else { + bus->lpm_force_flr = TRUE; + } + } + else { + bus->lpm_mode = FALSE; + bus->lpm_mem_kill = FALSE; + bus->lpm_force_flr = FALSE; + } + break; + case IOV_GVAL(IOV_MDRING_DUMP): + { + struct bcmstrbuf strbuf; + + if (bus->dhd->mdring_capable) { + bcm_binit(&strbuf, arg, len); + dhd_bus_dump_mdring_info(bus->dhd, &strbuf); } break; } -#endif /* BCMINTERNAL */ - + case IOV_SVAL(IOV_MDRING_LINK): + if (bus->dhd->mdring_capable && int_val) { + dhd_prot_mdring_link_unlink(bus->dhd, int_val, TRUE); + } + break; + case IOV_GVAL(IOV_MDRING_LINK): + if (bus->dhd->mdring_capable) { + int_val = dhd_prot_mdring_linked_ring(bus->dhd); + bcopy(&int_val, arg, val_size); + } + break; + case IOV_SVAL(IOV_MDRING_UNLINK): + if (bus->dhd->mdring_capable) { + dhd_prot_mdring_link_unlink(bus->dhd, int_val, FALSE); + } + break; + case IOV_GVAL(IOV_MDRING_UNLINK): + if (bus->dhd->mdring_capable) { + int_val = dhd_prot_mdring_linked_ring(bus->dhd); + bcopy(&int_val, arg, val_size); + } + break; + case IOV_SVAL(IOV_PTM_ENABLE): + if (int_val) { + dhdpcie_send_mb_data(bus, H2D_HOST_PTM_ENABLE); + } else { + dhdpcie_send_mb_data(bus, H2D_HOST_PTM_DISABLE); + } + break; default: bcmerror = BCME_UNSUPPORTED; break; @@ -9403,6 +9533,8 @@ dhd_bus_dump_dar_registers(struct dhd_bus *bus) return; } + bus->dar_err_set = FALSE; + if (DAR_PWRREQ(bus)) { dhd_bus_pcie_pwr_req(bus); } @@ -9436,6 +9568,11 @@ dhd_bus_dump_dar_registers(struct dhd_bus *bus) "dar_pcie_mbint(0x%x:0x%x)\n", __FUNCTION__, dar_errlog_reg, dar_errlog_val, dar_erraddr_reg, dar_erraddr_val, dar_pcie_mbint_reg, dar_pcie_mbint_val)); + + if (dar_errlog_val || dar_erraddr_val) { + bus->dar_err_set = TRUE; + } + } /* Ring DoorBell1 to indicate Hostready i.e. D3 Exit */ @@ -9451,17 +9588,22 @@ dhd_bus_hostready(struct dhd_bus *bus) return; } - DHD_ERROR_MEM(("%s : Read PCICMD Reg: 0x%08X\n", __FUNCTION__, + DHD_ERROR(("%s : Read PCICMD Reg: 0x%08X\n", __FUNCTION__, dhd_pcie_config_read(bus, PCI_CFG_CMD, sizeof(uint32)))); dhd_bus_dump_dar_registers(bus); + if (bus->is_linkdown) { + DHD_ERROR(("%s: PCIe link was down before DB1\n", __FUNCTION__)); + return; + } + #ifdef DHD_MMIO_TRACE dhd_bus_mmio_trace(bus, dhd_bus_db1_addr_get(bus), 0x1, TRUE); #endif /* defined(DHD_MMIO_TRACE) */ si_corereg(bus->sih, bus->sih->buscoreidx, dhd_bus_db1_addr_get(bus), ~0, 0x12345678); bus->hostready_count ++; - DHD_ERROR_MEM(("%s: Ring Hostready:%d\n", __FUNCTION__, bus->hostready_count)); + DHD_ERROR(("%s: Ring Hostready:%d\n", __FUNCTION__, bus->hostready_count)); } /* Clear INTSTATUS */ @@ -9469,7 +9611,7 @@ void dhdpcie_bus_clear_intstatus(struct dhd_bus *bus) { uint32 intstatus = 0; - /* Skip after recieving D3 ACK */ + /* Skip after receiving D3 ACK */ if (DHD_CHK_BUS_LPS_D3_ACKED(bus)) { return; } @@ -9486,6 +9628,45 @@ dhdpcie_bus_clear_intstatus(struct dhd_bus *bus) } } +#ifdef PWRSTATS_SYSFS +uint64 +dhdpcie_get_last_suspend_time(dhd_pub_t *dhdp) +{ + return dhdp->bus->last_suspend_end_time; +} +#endif /* PWRSTATS_SYSFS */ + +#define BCM4387_WLAN_SYS_MEMDOWN_FORCE_PMU 0x444 +#define BCM4378_WLAN_SYS_MEMDOWN_FORCE_PMU 0x133 + +static void +dhd_pcie_handle_lpm_memkill(struct dhd_bus *bus) +{ + uint16 chipid = si_chipid(bus->sih); + + if (bus->lpm_mem_kill == FALSE) { + DHD_ERROR(("LPM MODE: MEM Kill not enabled\n")); + return; + } + if (chipid == BCM4378_CHIP_ID) { + pmu_corereg(bus->sih, SI_CC_IDX, chipcontrol_addr, ~0, PMU_CHIPCTL13); + pmu_corereg(bus->sih, SI_CC_IDX, chipcontrol_data, + BCM4378_WLAN_SYS_MEMDOWN_FORCE_PMU, BCM4378_WLAN_SYS_MEMDOWN_FORCE_PMU); + } + else if (chipid == BCM4387_CHIP_ID) { + pmu_corereg(bus->sih, SI_CC_IDX, chipcontrol_addr, ~0, PMU_CHIPCTL13); + pmu_corereg(bus->sih, SI_CC_IDX, chipcontrol_data, + BCM4387_WLAN_SYS_MEMDOWN_FORCE_PMU, BCM4387_WLAN_SYS_MEMDOWN_FORCE_PMU); + } + else { + DHD_ERROR(("LPM MODE: Mem kill support not added for chip %d\n", chipid)); + return; + } + DHD_ERROR(("PMU chipcontrol addr %d value is 0x%04x\n", + pmu_corereg(bus->sih, SI_CC_IDX, chipcontrol_addr, 0, 0), + pmu_corereg(bus->sih, SI_CC_IDX, chipcontrol_data, 0, 0))); +} + int #ifdef DHD_PCIE_NATIVE_RUNTIMEPM dhdpcie_bus_suspend(struct dhd_bus *bus, bool state, bool byint) @@ -9502,6 +9683,7 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) uint32 zero = 0; #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ + printf("%s: state=%d\n", __FUNCTION__, state); if (bus->dhd == NULL) { DHD_ERROR(("%s: bus not inited\n", __FUNCTION__)); return BCME_ERROR; @@ -9567,11 +9749,7 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) DHD_ERROR(("Tx Request is not ended\n")); bus->dhd->busstate = DHD_BUS_DATA; DHD_GENERAL_UNLOCK(bus->dhd, flags); -#ifndef DHD_EFI return -EBUSY; -#else - return BCME_ERROR; -#endif } #endif /* LINUX || linux */ @@ -9580,7 +9758,6 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) /* stop all interface network queue. */ dhd_bus_stop_queue(bus); DHD_GENERAL_UNLOCK(bus->dhd, flags); - #ifdef DHD_PCIE_NATIVE_RUNTIMEPM if (byint) { DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); @@ -9602,16 +9779,14 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) } #else DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); -#ifdef DHD_TIMESYNC - /* disable time sync mechanism, if configed */ - dhd_timesync_control(bus->dhd, TRUE); -#endif /* DHD_TIMESYNC */ #ifdef PCIE_INB_DW /* As D3_INFORM will be sent after De-assert, * skip sending DS-ACK for DS-REQ. */ - bus->skip_ds_ack = TRUE; + DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); + bus->skip_ds_ack = TRUE; + DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); #endif /* PCIE_INB_DW */ #if defined(PCIE_OOB) || defined(PCIE_INB_DW) @@ -9623,16 +9798,7 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) #ifdef PCIE_INB_DW /* De-assert at this point for In-band device_wake */ if (INBAND_DW_ENAB(bus)) { -#ifdef DHD_EFI - /* during pcie suspend, irrespective of 'deep_sleep' enabled - * or disabled, always de-assert DW. If 'deep_sleep' was disabled - * by user iovar, then upon resuming, DW is again asserted in the - * 'dhd_bus_handle_mb_data' path. - */ - dhd_bus_inb_set_device_wake(bus, FALSE); -#else dhd_bus_set_device_wake(bus, FALSE); -#endif /* DHD_EFI */ DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); dhdpcie_bus_set_pcie_inband_dw_state(bus, DW_DEVICE_HOST_SLEEP_WAIT); DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); @@ -9660,7 +9826,6 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) /* Wait for D3 ACK for D3_ACK_RESP_TIMEOUT seconds */ timeleft = dhd_os_d3ack_wait(bus->dhd, &bus->wait_for_d3_ack); - #ifdef DHD_RECOVER_TIMEOUT /* XXX: WAR for missing D3 ACK MB interrupt */ if (bus->wait_for_d3_ack == 0) { @@ -9670,20 +9835,21 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) int host_irq_disabled = dhdpcie_irq_disabled(bus); if ((intstatus) && (intstatus != (uint32)-1) && (timeleft == 0) && (!dhd_query_bus_erros(bus->dhd))) { - DHD_ERROR(("%s: D3 ACK trying again intstatus=%x" + DHD_ERROR(("%s: resumed on timeout for D3 ack. intstatus=%x" " host_irq_disabled=%d\n", __FUNCTION__, intstatus, host_irq_disabled)); dhd_pcie_intr_count_dump(bus->dhd); dhd_print_tasklet_status(bus->dhd); - if (bus->api.fw_rev >= PCIE_SHARED_VERSION_6 && - !bus->use_mailbox) { - dhd_prot_process_ctrlbuf(bus->dhd); - } else { - dhdpcie_handle_mb_data(bus); - } - timeleft = dhd_os_d3ack_wait(bus->dhd, &bus->wait_for_d3_ack); + dhd_prot_ctrl_info_print(bus->dhd); /* Clear Interrupts */ dhdpcie_bus_clear_intstatus(bus); + if (dhd_prot_check_pending_ctrl_cmpls(bus->dhd)) { + DHD_ERROR(("##### %s: D3 ack timeout trying again #####\n", + __FUNCTION__)); + dhd_schedule_delayed_dpc_on_dpc_cpu(bus->dhd, 0); + timeleft = dhd_os_d3ack_wait(bus->dhd, + &bus->wait_for_d3_ack); + } } } /* bus->wait_for_d3_ack was 0 */ #endif /* DHD_RECOVER_TIMEOUT */ @@ -9706,7 +9872,7 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) /* Got D3 Ack. Suspend the bus */ #ifdef OEM_ANDROID if (active) { - DHD_ERROR(("%s():Suspend failed because of wakelock" + DHD_ERROR(("%s():Suspend failed because of wakelock " "restoring Dongle to D0\n", __FUNCTION__)); if (bus->dhd->dhd_watchdog_ms_backup) { @@ -9744,33 +9910,16 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) DW_DEVICE_HOST_WAKE_WAIT); dhd_bus_ds_trace(bus, 0, TRUE, dhdpcie_bus_get_pcie_inband_dw_state(bus)); + bus->skip_ds_ack = FALSE; DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); } - bus->skip_ds_ack = FALSE; #endif /* PCIE_INB_DW */ - /* For Linux, Macos etc (otherthan NDIS) enable back the dongle - * interrupts using intmask and host interrupts - * which were disabled in the dhdpcie_bus_isr()-> - * dhd_bus_handle_d3_ack(). - */ - /* Enable back interrupt using Intmask!! */ - dhdpcie_bus_intr_enable(bus); -#ifndef NDIS /* !NDIS */ - /* Defer enabling host irq after RPM suspend failure */ - if (!DHD_BUS_BUSY_CHECK_RPM_SUSPEND_IN_PROGRESS(bus->dhd)) { - /* Enable back interrupt from Host side!! */ - if (dhdpcie_irq_disabled(bus)) { - dhdpcie_enable_irq(bus); - bus->resume_intr_enable_count++; - } - } -#else /* Enable back the intmask which was cleared in DPC * after getting D3_ACK. */ - bus->resume_intr_enable_count++; + dhdpcie_bus_intr_enable(bus); + bus->dngl_intmask_enable_count++; -#endif /* !NDIS */ if (bus->use_d0_inform) { DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); dhdpcie_send_mb_data(bus, @@ -9790,7 +9939,7 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) /* Actual Suspend after no wakelock */ #endif /* OEM_ANDROID */ /* At this time bus->bus_low_power_state will be - * made to DHD_BUS_D3_ACK_RECIEVED after recieving D3_ACK + * made to DHD_BUS_D3_ACK_RECIEVED after receiving D3_ACK * in dhd_bus_handle_d3_ack() */ #ifdef PCIE_OOB @@ -9853,10 +10002,44 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) #if defined(LINUX) || defined(linux) dhdpcie_dump_resource(bus); #endif /* LINUX || linux */ + DHD_INFO(("lpm_mode %d, fw_lpm_support %d\n", bus->lpm_mode, + bus->dhd->fw_lpm_support)); + /* Once LPM mode is entered, recovery is only through WL_REG_ON */ + if (bus->lpm_mode && bus->dhd->fw_lpm_support) { + /* send DB7 with PCIE_DB7_MAGIC_NUMBER_DPC_LPM */ + int trap_data = 0; + uint32 addr = dhd_bus_db1_addr_3_get(bus); + + DHD_ERROR(("forcing LPM mode\n")); + si_corereg(bus->sih, bus->sih->buscoreidx, addr, ~0, + PCIE_DB7_MAGIC_NUMBER_DPC_LPM); + /* wait 500ms */ + OSL_DELAY(500000); + /* read trap data to confirm */ + trap_data = dhd_prot_process_trapbuf(bus->dhd); + DHD_ERROR(("trap data in response to LPM mode entry" + " is 0x%x\n", trap_data)); + /* force memory bits down */ + if (trap_data) { + dhd_pcie_handle_lpm_memkill(bus); + } + } + DHD_INFO(("Doing the D3\n")); rc = dhdpcie_pci_suspend_resume(bus, state); if (!rc) { bus->last_suspend_end_time = OSL_LOCALTIME_NS(); } + DHD_INFO(("Doing the FLR, lpm_mode %d, lpm_force_flr %d," + " fwsupport %d\n", + bus->lpm_mode, bus->lpm_force_flr, + bus->dhd->fw_lpm_support)); + if (bus->lpm_mode && bus->dhd->fw_lpm_support && + bus->lpm_force_flr) { + bus->lpm_keep_in_reset = TRUE; + dhd_bus_perform_flr(bus, FALSE); + bus->lpm_keep_in_reset = FALSE; + DHD_ERROR(("FLR done\n")); + } #ifdef OEM_ANDROID } #endif /* OEM_ANDROID */ @@ -9868,9 +10051,6 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) /* check if the D3 ACK timeout due to scheduling issue */ bus->dhd->is_sched_error = !dhd_query_bus_erros(bus->dhd) && dhd_bus_query_dpc_sched_errors(bus->dhd); - bus->dhd->d3ack_timeout_occured = TRUE; - /* If the D3 Ack has timeout */ - bus->dhd->d3ackcnt_timeout++; DHD_ERROR(("%s: resumed on timeout for D3 ACK%s d3_inform_cnt %d\n", __FUNCTION__, bus->dhd->is_sched_error ? " due to scheduling problem" : "", bus->dhd->d3ackcnt_timeout)); @@ -9898,6 +10078,8 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) /* resume all interface network queue. */ dhd_bus_start_queue(bus); DHD_GENERAL_UNLOCK(bus->dhd, flags); + /* Dump important config space registers */ + dhd_bus_dump_imp_cfg_registers(bus); /* XXX : avoid multiple socram dump from dongle trap and * invalid PCIe bus assceess due to PCIe link down */ @@ -9905,17 +10087,28 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) DHD_ERROR(("Check dongle trap in the case of d3 ack timeout\n")); dhdpcie_checkdied(bus, NULL, 0); } + /* Set d3_ack_timeout_occurred after checkdied, + * as checkdied returns for any bus error + */ + bus->dhd->d3ack_timeout_occured = TRUE; + /* If the D3 Ack has timeout */ + bus->dhd->d3ackcnt_timeout++; + + dhd_validate_pcie_link_cbp_wlbp(bus); + if (bus->link_state != DHD_PCIE_ALL_GOOD) { + DHD_ERROR(("%s: bus->link_state:%d\n", + __FUNCTION__, bus->link_state)); +#ifdef OEM_ANDROID + dhd_os_check_hang(bus->dhd, 0, -ETIMEDOUT); +#endif /* OEM_ANDROID */ + } + if (bus->dhd->dongle_trap_occured) { #ifdef OEM_ANDROID -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ dhd_os_check_hang(bus->dhd, 0, -EREMOTEIO); #endif /* OEM_ANDROID */ } else if (!bus->is_linkdown && - !bus->cto_triggered) { + !bus->cto_triggered && (bus->link_state == DHD_PCIE_ALL_GOOD)) { uint32 intstatus = 0; /* Check if PCIe bus status is valid */ @@ -9946,17 +10139,9 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) #ifdef OEM_ANDROID DHD_ERROR(("%s: Event HANG send up due to D3_ACK timeout\n", __FUNCTION__)); -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ dhd_os_check_hang(bus->dhd, 0, -ETIMEDOUT); #endif /* OEM_ANDROID */ } -#if defined(DHD_ERPOM) || (defined(DHD_EFI) && defined(BT_OVER_PCIE)) - dhd_schedule_reset(bus->dhd); -#endif /* DHD_ERPOM || DHD_EFI */ rc = -ETIMEDOUT; } #ifdef PCIE_OOB @@ -9995,9 +10180,9 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) dhd_bus_ds_trace(bus, 0, TRUE); #endif /* PCIE_INB_DW */ } + bus->skip_ds_ack = FALSE; DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); } - bus->skip_ds_ack = FALSE; #endif /* PCIE_INB_DW */ rc = dhdpcie_pci_suspend_resume(bus, state); #if defined(LINUX) || defined(linux) @@ -10018,13 +10203,6 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) } DHD_GENERAL_LOCK(bus->dhd, flags); bus->dhd->busstate = DHD_BUS_DATA; -#ifdef DHD_PCIE_RUNTIMEPM - if (DHD_BUS_BUSY_CHECK_RPM_SUSPEND_DONE(bus->dhd)) { - bus->bus_wake = 1; - OSL_SMP_WMB(); - wake_up(&bus->rpm_queue); - } -#endif /* DHD_PCIE_RUNTIMEPM */ #ifdef PCIE_OOB /* * Assert & Deassert the Device Wake. The following is the explanation for doing so. @@ -10056,33 +10234,14 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) /* resume all interface network queue. */ dhd_bus_start_queue(bus); - /* For Linux, Macos etc (otherthan NDIS) enable back the dongle interrupts - * using intmask and host interrupts - * which were disabled in the dhdpcie_bus_isr()->dhd_bus_handle_d3_ack(). + /* Enable back the intmask which was cleared in DPC + * after getting D3_ACK. */ - dhdpcie_bus_intr_enable(bus); /* Enable back interrupt using Intmask!! */ -#ifndef NDIS /* !NDIS */ - /* Defer enabling host interrupt until RPM resume done */ - if (!DHD_BUS_BUSY_CHECK_RPM_RESUME_IN_PROGRESS(bus->dhd)) { - if (dhdpcie_irq_disabled(bus)) { - dhdpcie_enable_irq(bus); - bus->resume_intr_enable_count++; - } - } -#else - /* TODO: for NDIS also we need to use enable_irq in future */ - bus->resume_intr_enable_count++; -#endif /* !NDIS */ + dhdpcie_bus_intr_enable(bus); + bus->dngl_intmask_enable_count++; DHD_GENERAL_UNLOCK(bus->dhd, flags); -#ifdef DHD_TIMESYNC - /* enable time sync mechanism, if configed */ - DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); - dhd_timesync_control(bus->dhd, FALSE); - DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); -#endif /* DHD_TIMESYNC */ - if (bus->dhd->dhd_watchdog_ms_backup) { DHD_ERROR(("%s: Enabling wdtick after resume\n", __FUNCTION__)); @@ -10172,7 +10331,9 @@ dhd_apply_d11_war_length(struct dhd_bus *bus, uint32 len, uint32 d11_lpbk) chipid == BCM4362_CHIP_ID || chipid == BCM4377_CHIP_ID || chipid == BCM43751_CHIP_ID || - chipid == BCM43752_CHIP_ID) && + chipid == BCM43752_CHIP_ID || + chipid == BCM43756_CHIP_ID || + chipid == BCM43711_CHIP_ID) && (d11_lpbk != M2M_DMA_LPBK && d11_lpbk != M2M_NON_DMA_LPBK)) { len += 8; } @@ -10207,12 +10368,6 @@ dhdpcie_bus_dmaxfer_req(struct dhd_bus *bus, return BCME_ERROR; } -#if defined(DHD_EFI) && defined(DHD_INTR_POLL_PERIOD_DYNAMIC) - bus->dhd->cur_intr_poll_period = dhd_os_get_intr_poll_period(); - /* before running loopback test, set interrupt poll period to a lesser value */ - dhd_os_set_intr_poll_period(bus, INTR_POLL_PERIOD_CRITICAL); -#endif /* DHD_EFI && DHD_INTR_POLL_PERIOD_DYNAMIC */ - len = dhd_apply_d11_war_length(bus, len, d11_lpbk); bus->dmaxfer_complete = FALSE; @@ -10225,48 +10380,12 @@ dhdpcie_bus_dmaxfer_req(struct dhd_bus *bus, ret = dhd_os_dmaxfer_wait(bus->dhd, &bus->dmaxfer_complete); if (ret < 0) ret = BCME_NOTREADY; -#if defined(DHD_EFI) && defined(DHD_INTR_POLL_PERIOD_DYNAMIC) - /* restore interrupt poll period to the previous existing value */ - dhd_os_set_intr_poll_period(bus, bus->dhd->cur_intr_poll_period); -#endif /* DHD_EFI && DHD_INTR_POLL_PERIOD_DYNAMIC */ } return ret; } -#ifdef BCMINTERNAL -static int -dhdpcie_bus_set_tx_lpback(struct dhd_bus *bus, bool enable) -{ - if (bus->dhd == NULL) { - DHD_ERROR(("bus not inited\n")); - return BCME_ERROR; - } - if (bus->dhd->prot == NULL) { - DHD_ERROR(("prot is not inited\n")); - return BCME_ERROR; - } - if (bus->dhd->busstate != DHD_BUS_DATA) { - DHD_ERROR(("not in a readystate to LPBK is not inited\n")); - return BCME_ERROR; - } - bus->dhd->loopback = enable; - return BCME_OK; -} - -static int -dhdpcie_bus_get_tx_lpback(struct dhd_bus *bus) -{ - if (bus->dhd == NULL) { - DHD_ERROR(("bus not inited\n")); - return BCME_ERROR; - } - return bus->dhd->loopback ? 1 : 0; - return BCME_OK; -} -#endif /* BCMINTERNAL */ - bool dhd_bus_is_multibp_capable(struct dhd_bus *bus) { @@ -10308,28 +10427,6 @@ dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter) */ if (enter) { #ifndef BCMQT /* for performance reasons, skip the FLR for QT */ -#ifdef BT_OVER_PCIE - if (dhd_bus_is_multibp_capable(bus) && do_flr && - dhd_fw_download_status(bus->dhd) != FW_DOWNLOAD_IN_PROGRESS) { - /* for multi-backplane architecture, issue an FLR to reset the WLAN cores */ - const int pwr_req_ref = bus->pwr_req_ref; - if (pwr_req_ref > 0) { - (void)dhd_bus_perform_flr_with_quiesce(bus->dhd, bus, FALSE); - - /* - * If power has been requested prior to calling FLR, but - * the FLR code cleared the power request, we need to - * request again to get back to the status of where we were - * prior, otherwise there'll be a mismatch in reqs/clears - */ - if (bus->pwr_req_ref < pwr_req_ref) { - dhd_bus_pcie_pwr_req(bus); - } - } else { - (void)dhd_bus_perform_flr_with_quiesce(bus->dhd, bus, FALSE); - } - } -#endif /* BT_OVER_PCIE */ #endif /* !BCMQT */ /* Make sure BAR1 maps to backplane address 0 */ @@ -10418,53 +10515,6 @@ dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter) __FUNCTION__)); goto fail; } -#ifdef BCMINTERNAL - if (bus->hostfw_buf.va) { - /* Share the location of the host memory - * location where pageable FW binary is located. - */ - host_page_location_info_t host_location; - host_location.tlv_signature = - htol32(BCM_HOST_PAGE_LOCATION_SIGNATURE); - host_location.tlv_size = htol32(sizeof(host_location)) - - sizeof(host_location.tlv_size) - - sizeof(host_location.tlv_signature); - host_location.binary_size = htol32(bus->hostfw_buf.len); - host_location.addr_hi = PHYSADDRHI(bus->hostfw_buf.pa); - host_location.addr_lo = PHYSADDRLO(bus->hostfw_buf.pa); - bus->next_tlv -= sizeof(host_location); - dhdpcie_bus_membytes(bus, TRUE, bus->next_tlv, - (uint8*)&host_location, sizeof(host_location)); - DHD_INFO(("%s:Host page location info:" - " %08x-%08x Len:%x!\n", - __FUNCTION__, host_location.addr_hi, - host_location.addr_lo, host_location.binary_size)); - } -#ifdef DHD_FWTRACE - { - /* - * Send host trace buffer at time of firmware download - * to enable collecting full init time firmware trace - */ - host_fwtrace_buf_location_info_t host_info; - - if (fwtrace_init(bus->dhd) == BCME_OK) { - fwtrace_get_haddr(bus->dhd, &host_info.host_buf_info); - - host_info.tlv_size = sizeof(host_info.host_buf_info); - host_info.tlv_signature = - htol32(BCM_HOST_FWTRACE_BUF_LOCATION_SIGNATURE); - - bus->ramtop_addr -= sizeof(host_info); - - dhdpcie_bus_membytes(bus, TRUE, bus->ramtop_addr, - (uint8*)&host_info, sizeof(host_info)); - - bus->next_tlv = sizeof(host_info); - } - } -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ #if defined(FW_SIGNATURE) if ((bcmerror = dhdpcie_bus_download_fw_signature(bus, &do_wr_flops)) @@ -10474,7 +10524,7 @@ dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter) #endif /* FW_SIGNATURE */ if (do_wr_flops) { - uint32 resetinstr_data; + uint32 resetinstr_data = 0; /* switch back to arm core again */ if (!(si_setcore(bus->sih, ARMCA7_CORE_ID, 0))) { @@ -10484,20 +10534,22 @@ dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter) goto fail; } - /* - * read address 0 with reset instruction, - * to validate that is not secured - */ - bcmerror = dhdpcie_bus_membytes(bus, FALSE, 0, - (uint8 *)&resetinstr_data, sizeof(resetinstr_data)); - - if (resetinstr_data == 0xFFFFFFFF) { + bcmerror = dhd_bus_get_security_status(bus, &resetinstr_data); + if (bcmerror == BCME_UNSUPPORTED) { + /* + * read address 0 with reset instruction, + * to validate that is not secured + */ + bcmerror = dhdpcie_bus_membytes(bus, FALSE, 0, + (uint8 *)&resetinstr_data, sizeof(resetinstr_data)); + } + if ((resetinstr_data == 0xFFFFFFFF) || + (resetinstr_data & DAR_SEC_SBOOT_MASK)) { DHD_ERROR(("%s: **** FLOPS Vector is secured, " "Signature file is missing! ***\n", __FUNCTION__)); bcmerror = BCME_NO_SIG_FILE; goto fail; } - /* write address 0 with reset instruction */ bcmerror = dhdpcie_bus_membytes(bus, TRUE, 0, (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); @@ -10619,23 +10671,12 @@ dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter) bus->arm_oor_time = OSL_LOCALTIME_NS(); si_core_reset(bus->sih, 0, 0); + DHD_ERROR(("%s: Took ARM out of Reset\n", __FUNCTION__)); + /* Allow HT Clock now that the ARM is running. */ bus->alp_only = FALSE; bus->dhd->busstate = DHD_BUS_LOAD; -#ifdef DHD_EFI - /* - * dhdpcie_init_phase2() sets the fw_download_status as FW_DOWNLOAD_IN_PROGRESS - * during the first default attempt to load FW either from OTP or WIRELESS folder. - * - * After the first successful download of the FW(either from OTP or WIRELESS folder - * or by dhd download command) set the fw_download_status as FW_DOWNLOAD_DONE. - * - * We need to maintain these states to perform FLR in dhdpcie_bus_download_state() - * only after first successful download. - */ - bus->dhd->fw_download_status = FW_DOWNLOAD_DONE; -#endif /* DHD_EFI */ } fail: @@ -10678,6 +10719,35 @@ dhdpcie_bus_download_fw_signature(dhd_bus_t *bus, bool *do_write) goto exit; } + /* Write FW signature to memory */ + if ((bcmerror = dhdpcie_bus_write_fw_signature(bus))) { + DHD_ERROR(("%s: could not write FWsig , err %d\n", + __FUNCTION__, bcmerror)); + goto exit; + } + + /* In case of BL RAM, do write flops */ + if (bus->bootloader_filename[0] != 0) { + *do_write = TRUE; + } else { + *do_write = FALSE; + } + +exit: + return bcmerror; +} + +/* Complete RAM structure, write the followings + * signature image + * signature verification status + * FW memory map + * end-of-TLVs marker + */ +static int +dhdpcie_bus_write_fw_signature(dhd_bus_t *bus) +{ + int bcmerror = BCME_OK; + /* Write FW signature rTLV to TCM */ if ((bcmerror = dhdpcie_bus_write_fwsig(bus, bus->fwsig_filename, NULL))) { @@ -10707,16 +10777,10 @@ dhdpcie_bus_download_fw_signature(dhd_bus_t *bus, bool *do_write) goto exit; } - /* In case of BL RAM, do write flops */ - if (bus->bootloader_filename[0] != 0) { - *do_write = TRUE; - } else { - *do_write = FALSE; - } - exit: return bcmerror; } +#endif /* defined(FW_SIGNATURE) */ /* Download a reversed-TLV to the top of dongle RAM without overlapping any existing rTLVs */ static int @@ -10745,8 +10809,15 @@ dhdpcie_download_rtlv(dhd_bus_t *bus, dngl_rtlv_type_t type, dngl_rtlv_len_t len * +-------------+-------------+ * High 16 bits Low 16 bits */ - dest_raw_size = (~dest_size << 16) | (dest_size & 0x0000FFFF); - + if (type == DNGL_RTLV_TYPE_RNG_SIGNATURE) { + /* Random number seed TLV (DNGL_RTLV_TYPE_RNG_SIGNATURE) was the very + * first TLV, its length does not have checksum, firmware crashes if + * checksum is present + */ + dest_raw_size = dest_size & 0x0000FFFF; + } else { + dest_raw_size = (~dest_size << 16) | (dest_size & 0x0000FFFF); + } /* Write the value block */ if (dest_size > 0) { bcmerror = dhdpcie_bus_membytes(bus, TRUE, dest_addr, value, dest_size); @@ -10831,6 +10902,7 @@ exit: return bcmerror; } /* dhdpcie_download_rtlv */ +#if defined(FW_SIGNATURE) /* Download a reversed-TLV END marker to the top of dongle RAM */ static int dhdpcie_download_rtlv_end(dhd_bus_t *bus) @@ -10842,7 +10914,7 @@ dhdpcie_download_rtlv_end(dhd_bus_t *bus) static int dhdpcie_bus_write_fws_status(dhd_bus_t *bus) { - bcm_fwsign_verif_status_t vstatus; + bl_verif_status_t vstatus; int ret; bzero(&vstatus, sizeof(vstatus)); @@ -10859,7 +10931,7 @@ dhdpcie_bus_write_fws_status(dhd_bus_t *bus) static int dhdpcie_bus_write_fws_mem_info(dhd_bus_t *bus) { - bcm_fwsign_mem_info_t memmap; + bl_mem_info_t memmap; int ret; bzero(&memmap, sizeof(memmap)); @@ -10921,7 +10993,10 @@ dhdpcie_bus_save_download_info(dhd_bus_t *bus, uint32 download_addr, uint32 download_size, const char *signature_fname, const char *bloader_fname, uint32 bloader_download_addr) { - bus->fw_download_len = download_size; + /* DHD EXE may not have size of the downloaded FW image in case of swpaging binary */ + if (download_size) { + bus->fw_download_len = download_size; + } bus->fw_download_addr = download_addr; strlcpy(bus->fwsig_filename, signature_fname, sizeof(bus->fwsig_filename)); strlcpy(bus->bootloader_filename, bloader_fname, sizeof(bus->bootloader_filename)); @@ -10934,13 +11009,64 @@ dhdpcie_bus_save_download_info(dhd_bus_t *bus, uint32 download_addr, * of chips, in which debug cell can't be initialized before ARM CPU * start */ - bus->gdb_proxy_bootloader_mode = - (bus->fwsig_filename[0] != 0) && (bus->bootloader_filename[0] == 0); + bus->gdb_proxy_bootloader_mode = bus->fwsig_filename[0] != 0; #endif /* GDB_PROXY */ return BCME_OK; } /* dhdpcie_bus_save_download_info */ -/* Read a small binary file and write it to the specified socram dest address */ +/* Read a binary file and write it to the specified socram dest address */ +#ifdef DHD_LINUX_STD_FW_API +static int +dhdpcie_download_sig_file(dhd_bus_t *bus, char *path, uint32 type) +{ + int bcmerror = BCME_ERROR; + int srcsize = 0; + uint32 dest_size = 0; /* dongle RAM dest size */ + const struct firmware *sig = NULL; + + if (path == NULL || path[0] == '\0') { + DHD_ERROR(("%s: no file\n", __FUNCTION__)); + bcmerror = BCME_NOTFOUND; + goto exit; + } + + bcmerror = dhd_os_get_img_fwreq(&sig, bus->fwsig_filename); + if (bcmerror < 0) { + DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n", + bcmerror)); + goto exit; + } + DHD_ERROR(("%s: dhd_os_get_img(Request Firmware API) success. size %d.\n", + __func__, sig->size)); + + srcsize = sig->size; + if (srcsize <= 0 || srcsize > MEMBLOCK) { + DHD_ERROR(("%s: invalid fwsig size %u\n", __FUNCTION__, srcsize)); + bcmerror = BCME_BUFTOOSHORT; + goto exit; + } + + dest_size = ROUNDUP(srcsize, 4); + /* Write the src buffer as a rTLV to the dongle */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + bcmerror = dhdpcie_download_rtlv(bus, type, dest_size, (uint8 *)sig->data); + GCC_DIAGNOSTIC_POP(); + if (bcmerror) { + DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, srcsize, bus->ramtop_addr)); + goto exit; + } + + bus->fwsig_download_addr = bus->ramtop_addr; + bus->fwsig_download_len = dest_size; +exit: + if (sig) { + dhd_os_close_img_fwreq(sig); + } + + return bcmerror; +} +#else static int dhdpcie_download_sig_file(dhd_bus_t *bus, char *path, uint32 type) { @@ -10950,6 +11076,7 @@ dhdpcie_download_sig_file(dhd_bus_t *bus, char *path, uint32 type) int srcsize = 0; int len; uint32 dest_size = 0; /* dongle RAM dest size */ + fwpkg_info_t *fwpkg = NULL; if (path == NULL || path[0] == '\0') { DHD_ERROR(("%s: no file\n", __FUNCTION__)); @@ -10957,14 +11084,21 @@ dhdpcie_download_sig_file(dhd_bus_t *bus, char *path, uint32 type) goto exit; } - /* Open file, get size */ - filep = dhd_os_open_image1(bus->dhd, path); - if (filep == NULL) { - DHD_ERROR(("%s: error opening file %s\n", __FUNCTION__, path)); - bcmerror = BCME_NOTFOUND; + bcmerror = fwpkg_init(&bus->fwpkg, path); + if (bcmerror == BCME_ERROR) { goto exit; } - srcsize = dhd_os_get_image_size(filep); + fwpkg = &bus->fwpkg; + + /* Open file, get size */ + bcmerror = fwpkg_open_signature_img(fwpkg, path, &filep); + if (bcmerror == BCME_ERROR) { + DHD_ERROR(("%s: error opening file %s\n", __FUNCTION__, path)); + goto exit; + } + + srcsize = fwpkg_get_signature_img_size(fwpkg); + if (srcsize <= 0 || srcsize > MEMBLOCK) { DHD_ERROR(("%s: invalid fwsig size %u\n", __FUNCTION__, srcsize)); bcmerror = BCME_BUFTOOSHORT; @@ -11001,6 +11135,7 @@ exit: return bcmerror; } /* dhdpcie_download_sig_file */ +#endif /* DHD_LINUX_STD_FW_API */ static int dhdpcie_bus_write_fwsig(dhd_bus_t *bus, char *fwsig_path, char *nvsig_path) @@ -11020,23 +11155,35 @@ exit: return bcmerror; } /* dhdpcie_bus_write_fwsig */ +static int +dhdpcie_read_fwstatus(dhd_bus_t *bus, bl_verif_status_t *status) +{ + int ret = BCME_OK; + + bzero(status, sizeof(*status)); + if (bus->fwstat_download_addr != 0) { + ret = dhdpcie_bus_membytes(bus, FALSE, bus->fwstat_download_addr, + (uint8 *)status, sizeof(*status)); + if (ret != BCME_OK) { + DHD_ERROR(("%s: error %d on reading %zu membytes at 0x%08x\n", + __FUNCTION__, ret, sizeof(*status), bus->fwstat_download_addr)); + } + } + + return ret; +} + /* Dump secure firmware status. */ static int dhd_bus_dump_fws(dhd_bus_t *bus, struct bcmstrbuf *strbuf) { - bcm_fwsign_verif_status_t status; - bcm_fwsign_mem_info_t meminfo; - int err = BCME_OK; + bl_verif_status_t status; + bl_mem_info_t meminfo; + int err = BCME_OK; - bzero(&status, sizeof(status)); - if (bus->fwstat_download_addr != 0) { - err = dhdpcie_bus_membytes(bus, FALSE, bus->fwstat_download_addr, - (uint8 *)&status, sizeof(status)); - if (err != BCME_OK) { - DHD_ERROR(("%s: error %d on reading %zu membytes at 0x%08x\n", - __FUNCTION__, err, sizeof(status), bus->fwstat_download_addr)); - return (err); - } + err = dhdpcie_read_fwstatus(bus, &status); + if (err != BCME_OK) { + return (err); } bzero(&meminfo, sizeof(meminfo)); @@ -11099,6 +11246,7 @@ dhdpcie_bus_write_vars(dhd_bus_t *bus) uint32 varaddr; uint8 *vbuffer; uint32 varsizew; + uint32 rd_varsizew; #ifdef DHD_DEBUG uint8 *nvram_ularray; #endif /* DHD_DEBUG */ @@ -11185,12 +11333,20 @@ dhdpcie_bus_write_vars(dhd_bus_t *bus) varsizew = htol32(varsizew); } - DHD_INFO(("%s: New varsize is %d, length token=0x%08x\n", __FUNCTION__, varsize, varsizew)); + DHD_ERROR(("%s: New varsize is %d, length token(nvram_csm)=0x%08x\n", __FUNCTION__, varsize, varsizew)); /* Write the length token to the last word */ bcmerror = dhdpcie_bus_membytes(bus, TRUE, (phys_size - 4), (uint8*)&varsizew, 4); + /* Read back the last word */ + bcmerror = dhdpcie_bus_membytes(bus, FALSE, (phys_size - 4), + (uint8*)&rd_varsizew, 4); + if (rd_varsizew != varsizew) { + DHD_ERROR(("%s: readback nvram_csm(0x%08x:0x%08x) is wrong at 0x%x\n", + __FUNCTION__, rd_varsizew, varsizew, (phys_size - 4))); + } + return bcmerror; } /* dhdpcie_bus_write_vars */ @@ -11206,6 +11362,9 @@ dhdpcie_downloadvars(dhd_bus_t *bus, void *arg, int len) #ifdef GDB_PROXY const char nodeadman_record[] = "deadman_to=0"; #endif /* GDB_PROXY */ +#ifdef DHD_SUPPORT_SPMI_MODE + char tag_spmi_mode[16] = {0}; +#endif /* DHD_SUPPORT_SPMI_MODE */ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -11222,6 +11381,13 @@ dhdpcie_downloadvars(dhd_bus_t *bus, void *arg, int len) len += sizeof(nodeadman_record); } #endif /* GDB_PROXY */ +#ifdef DHD_SUPPORT_SPMI_MODE + if (bus->dhd->dhd_spmi_mode) { + snprintf(tag_spmi_mode, sizeof(tag_spmi_mode), "spmi_mode=%d\n", + bus->dhd->dhd_spmi_mode); + len += sizeof(tag_spmi_mode); + } +#endif /* DHD_SUPPORT_SPMI_MODE */ bus->vars = MALLOC(bus->dhd->osh, len); bus->varsz = bus->vars ? len : 0; @@ -11240,6 +11406,27 @@ dhdpcie_downloadvars(dhd_bus_t *bus, void *arg, int len) goto err; } #endif /* GDB_PROXY */ +#ifdef DHD_SUPPORT_SPMI_MODE + if (bus->dhd->dhd_spmi_mode) { + char *pos = NULL; + char tag_spmi[] = "spmi="; + uint spmi = 0; + + /* check if the spmi feature is enabled */ + pos = bcmstrnstr(bus->vars, bus->varsz, tag_spmi, strlen(tag_spmi)); + if (pos) { + sscanf(pos, "spmi=%u\n", &spmi); + DHD_INFO(("%s: spmi feature is %s\n", __FUNCTION__, + spmi ? "enabled" : "disabled")); + } + + if (spmi && !replace_nvram_variable(bus->vars, + bus->varsz, tag_spmi_mode, NULL)) { + bcmerror = BCME_NOMEM; + goto err; + } + } +#endif /* DHD_SUPPORT_SPMI_MODE */ /* Re-Calculate htclkratio only for QT, for FPGA it is fixed at 30 */ #ifdef BCMQT_HW @@ -11375,7 +11562,7 @@ dhdpcie_pme_active(osl_t *osh, bool enable) } pme_csr = OSL_PCI_READ_CONFIG(osh, cap_ptr + PME_CSR_OFFSET, sizeof(uint32)); - DHD_RPM(("%s : pme_sts_ctrl 0x%x\n", __FUNCTION__, pme_csr)); + DHD_ERROR(("%s : pme_sts_ctrl 0x%x\n", __FUNCTION__, pme_csr)); pme_csr |= PME_CSR_PME_STAT; if (enable) { @@ -11505,11 +11692,11 @@ void dhd_dump_intr_counters(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) } bcm_bprintf(strbuf, "\n ------- DUMPING INTR enable/disable counters-------\n"); - bcm_bprintf(strbuf, "resume_intr_enable_count=%lu dpc_intr_enable_count=%lu\n" - "isr_intr_disable_count=%lu suspend_intr_disable_count=%lu\n" + bcm_bprintf(strbuf, "host_irq_disable_count=%lu host_irq_enable_count=%lu\n" + "dngl_intmask_disable_count=%lu dngl_intmask_enable_count=%lu\n" "dpc_return_busdown_count=%lu non_ours_irq_count=%lu\n", - bus->resume_intr_enable_count, bus->dpc_intr_enable_count, - bus->isr_intr_disable_count, bus->suspend_intr_disable_count, + bus->host_irq_disable_count, bus->host_irq_enable_count, + bus->dngl_intmask_disable_count, bus->dngl_intmask_enable_count, bus->dpc_return_busdown_count, bus->non_ours_irq_count); #ifdef BCMPCIE_OOB_HOST_WAKE bcm_bprintf(strbuf, "oob_intr_count=%lu oob_intr_enable_count=%lu" @@ -11526,15 +11713,16 @@ void dhd_dump_intr_counters(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) dhdpcie_get_oob_irq_level()); #endif /* BCMPCIE_OOB_HOST_WAKE */ bcm_bprintf(strbuf, "\ncurrent_time="SEC_USEC_FMT" isr_entry_time="SEC_USEC_FMT - " isr_exit_time="SEC_USEC_FMT"\n" + " prev_isr_entry_time="SEC_USEC_FMT" isr_exit_time="SEC_USEC_FMT"\n" "isr_sched_dpc_time="SEC_USEC_FMT" rpm_sched_dpc_time="SEC_USEC_FMT"\n" " last_non_ours_irq_time="SEC_USEC_FMT" dpc_entry_time="SEC_USEC_FMT"\n" "last_process_ctrlbuf_time="SEC_USEC_FMT " last_process_flowring_time="SEC_USEC_FMT " last_process_txcpl_time="SEC_USEC_FMT"\nlast_process_rxcpl_time="SEC_USEC_FMT " last_process_infocpl_time="SEC_USEC_FMT" last_process_edl_time="SEC_USEC_FMT "\ndpc_exit_time="SEC_USEC_FMT" resched_dpc_time="SEC_USEC_FMT"\n" - "last_d3_inform_time="SEC_USEC_FMT"\n", + "last_d3_inform_time="SEC_USEC_FMT" dpc_sched=%u\n", GET_SEC_USEC(current_time), GET_SEC_USEC(bus->isr_entry_time), + GET_SEC_USEC(bus->prev_isr_entry_time), GET_SEC_USEC(bus->isr_exit_time), GET_SEC_USEC(bus->isr_sched_dpc_time), GET_SEC_USEC(bus->rpm_sched_dpc_time), GET_SEC_USEC(bus->last_non_ours_irq_time), GET_SEC_USEC(bus->dpc_entry_time), @@ -11545,7 +11733,7 @@ void dhd_dump_intr_counters(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) GET_SEC_USEC(bus->last_process_infocpl_time), GET_SEC_USEC(bus->last_process_edl_time), GET_SEC_USEC(bus->dpc_exit_time), GET_SEC_USEC(bus->resched_dpc_time), - GET_SEC_USEC(bus->last_d3_inform_time)); + GET_SEC_USEC(bus->last_d3_inform_time), bus->dpc_sched); bcm_bprintf(strbuf, "\nlast_suspend_start_time="SEC_USEC_FMT" last_suspend_end_time=" SEC_USEC_FMT" last_resume_start_time="SEC_USEC_FMT" last_resume_end_time=" @@ -11593,121 +11781,39 @@ void dhd_dump_intr_registers(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) bcm_bprintf(strbuf, "d2h_mb_data=0x%x def_intmask=0x%x\n", d2h_mb_data, dhd->bus->def_intmask); } -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) -void -dhd_bus_dump_awdl_stats(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - int i = 0; - dhd_awdl_stats_t *awdl_stats; - bcm_bprintf(strbuf, "---------- AWDL STATISTICS ---------\n"); - bcm_bprintf(strbuf, "%s %10s %12s %16s %12s %16s %8s %8s %8s\n", - "Slot", "AvgSlotTUs", "AvgSlotTUsFW", "NumSlots", - "AvgTxCmpL_Us", "NumTxStatus", "Acked", "tossed", "noack"); - for (i = 0; i < AWDL_NUM_SLOTS; i++) { - awdl_stats = &dhdp->awdl_stats[i]; - bcm_bprintf(strbuf, "%4d %10llu %12llu %16llu %12llu %16llu ", - i, - awdl_stats->num_slots ? - DIV_U64_BY_U64(awdl_stats->cum_slot_time, - awdl_stats->num_slots) : 0, - awdl_stats->num_slots ? - DIV_U64_BY_U64(awdl_stats->fw_cum_slot_time, - awdl_stats->num_slots) : 0, - awdl_stats->num_slots, - awdl_stats->num_tx_status ? - DIV_U64_BY_U64(awdl_stats->cum_tx_status_latency, - awdl_stats->num_tx_status) : 0, - awdl_stats->num_tx_status); -#ifdef BCMDBG - if (!dhdp->d2h_sync_mode) { - bcm_bprintf(strbuf, "%8d %8d %8d\n", - awdl_stats->tx_status[WLFC_CTL_PKTFLAG_DISCARD], - awdl_stats->tx_status[WLFC_CTL_PKTFLAG_TOSSED_BYWLC], - awdl_stats->tx_status[WLFC_CTL_PKTFLAG_DISCARD_NOACK]); - } else { - bcm_bprintf(strbuf, - "%8s %8s %8s\n", "NA", "NA", "NA"); - } -#else - bcm_bprintf(strbuf, - "%8s %8s %8s\n", "NA", "NA", "NA"); -#endif - } -} -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ -/** Add bus dump output to a buffer */ -void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +void dhd_bus_dump_flowring(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) { uint16 flowid; int ix = 0; flow_ring_node_t *flow_ring_node; flow_info_t *flow_info; -#ifdef BCMDBG - flow_info_t *local_flow_info; -#endif /* BCMDBG */ #ifdef TX_STATUS_LATENCY_STATS uint8 ifindex; if_flow_lkup_t *if_flow_lkup; dhd_if_tx_status_latency_t if_tx_status_latency[DHD_MAX_IFS]; #endif /* TX_STATUS_LATENCY_STATS */ - -#if defined(FW_SIGNATURE) - /* Dump secure firmware status. */ - if (dhdp->busstate <= DHD_BUS_LOAD) { - dhd_bus_dump_fws(dhdp->bus, strbuf); - } -#endif - - if (dhdp->busstate != DHD_BUS_DATA) - return; + unsigned long flags; #ifdef TX_STATUS_LATENCY_STATS - memset(if_tx_status_latency, 0, sizeof(if_tx_status_latency)); + bzero(if_tx_status_latency, sizeof(if_tx_status_latency)); #endif /* TX_STATUS_LATENCY_STATS */ -#ifdef DHD_WAKE_STATUS - bcm_bprintf(strbuf, "wake %u rxwake %u readctrlwake %u\n", - bcmpcie_get_total_wake(dhdp->bus), dhdp->bus->wake_counts.rxwake, - dhdp->bus->wake_counts.rcwake); -#ifdef DHD_WAKE_RX_STATUS - bcm_bprintf(strbuf, " unicast %u muticast %u broadcast %u arp %u\n", - dhdp->bus->wake_counts.rx_ucast, dhdp->bus->wake_counts.rx_mcast, - dhdp->bus->wake_counts.rx_bcast, dhdp->bus->wake_counts.rx_arp); - bcm_bprintf(strbuf, " multi4 %u multi6 %u icmp6 %u multiother %u\n", - dhdp->bus->wake_counts.rx_multi_ipv4, dhdp->bus->wake_counts.rx_multi_ipv6, - dhdp->bus->wake_counts.rx_icmpv6, dhdp->bus->wake_counts.rx_multi_other); - bcm_bprintf(strbuf, " icmp6_ra %u, icmp6_na %u, icmp6_ns %u\n", - dhdp->bus->wake_counts.rx_icmpv6_ra, dhdp->bus->wake_counts.rx_icmpv6_na, - dhdp->bus->wake_counts.rx_icmpv6_ns); -#endif /* DHD_WAKE_RX_STATUS */ -#ifdef DHD_WAKE_EVENT_STATUS - for (flowid = 0; flowid < WLC_E_LAST; flowid++) - if (dhdp->bus->wake_counts.rc_event[flowid] != 0) - bcm_bprintf(strbuf, " %s = %u\n", bcmevent_get_name(flowid), - dhdp->bus->wake_counts.rc_event[flowid]); - bcm_bprintf(strbuf, "\n"); -#endif /* DHD_WAKE_EVENT_STATUS */ -#endif /* DHD_WAKE_STATUS */ - dhd_prot_print_info(dhdp, strbuf); - dhd_dump_intr_registers(dhdp, strbuf); - dhd_dump_intr_counters(dhdp, strbuf); - bcm_bprintf(strbuf, "h2d_mb_data_ptr_addr 0x%x, d2h_mb_data_ptr_addr 0x%x\n", - dhdp->bus->h2d_mb_data_ptr_addr, dhdp->bus->d2h_mb_data_ptr_addr); - bcm_bprintf(strbuf, "dhd cumm_ctr %d\n", DHD_CUMM_CTR_READ(&dhdp->cumm_ctr)); -#ifdef DHD_LIMIT_MULTI_CLIENT_FLOWRINGS - bcm_bprintf(strbuf, "multi_client_flow_rings:%d max_multi_client_flow_rings:%d\n", - dhdp->multi_client_flow_rings, dhdp->max_multi_client_flow_rings); -#endif /* DHD_LIMIT_MULTI_CLIENT_FLOWRINGS */ -#if defined(DHD_HTPUT_TUNABLES) - bcm_bprintf(strbuf, "htput_flow_ring_start:%d total_htput:%d client_htput=%d\n", - dhdp->htput_flow_ring_start, HTPUT_TOTAL_FLOW_RINGS, dhdp->htput_client_flow_rings); -#endif /* DHD_HTPUT_TUNABLES */ + bcm_bprintf(strbuf, "Flowring info:\n==============\n"); + bcm_bprintf(strbuf, "[RD=read ptr; WR=write ptr; T=TCM; H=Host; L=Local; D=DMA index'd]\n"); +#ifndef BCM_ROUTER_DHD + bcm_bprintf(strbuf, + "%4s %4s %2s %4s %17s %4s %10s %17s %17s %17s %17s %14s %14s %10s ", + "Num:", "Flow", "If", "Prio", ":Dest_MacAddress:", "Qlen", + " Overflows", "TRD: HLRD: HDRD", "TWR: HLWR: HDWR", "BASE(VA)", "BASE(PA)", + "WORK_ITEM_SIZE", "MAX_WORK_ITEMS", "TOTAL_SIZE"); +#else bcm_bprintf(strbuf, "%4s %4s %2s %4s %17s %4s %4s %6s %10s %17s %17s %17s %17s %14s %14s %10s ", "Num:", "Flow", "If", "Prio", ":Dest_MacAddress:", "Qlen", "CLen", "L2CLen", " Overflows", "TRD: HLRD: HDRD", "TWR: HLWR: HDWR", "BASE(VA)", "BASE(PA)", "WORK_ITEM_SIZE", "MAX_WORK_ITEMS", "TOTAL_SIZE"); +#endif /* !BCM_ROUTER_DHD */ #ifdef TX_STATUS_LATENCY_STATS /* Average Tx status/Completion Latency in micro secs */ @@ -11717,7 +11823,6 @@ void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) bcm_bprintf(strbuf, "\n"); for (flowid = 0; flowid < dhdp->num_h2d_rings; flowid++) { - unsigned long flags; flow_ring_node = DHD_FLOW_RING(dhdp, flowid); DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); if (flow_ring_node->status != FLOW_RING_STATUS_OPEN) { @@ -11727,12 +11832,18 @@ void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) flow_info = &flow_ring_node->flow_info; bcm_bprintf(strbuf, - "%4d %4d %2d %4d "MACDBG" %4d %4d %6d %10u ", ix++, + "%4d %4d %2d %4d "MACDBG" %4d" +#ifdef BCM_ROUTER_DHD + "%4d %6d" +#endif + "%10u ", ix++, flow_ring_node->flowid, flow_info->ifindex, flow_info->tid, MAC2STRDBG(flow_info->da), DHD_FLOW_QUEUE_LEN(&flow_ring_node->queue), +#ifdef BCM_ROUTER_DHD DHD_CUMM_CTR_READ(DHD_FLOW_QUEUE_CLEN_PTR(&flow_ring_node->queue)), DHD_CUMM_CTR_READ(DHD_FLOW_QUEUE_L2CLEN_PTR(&flow_ring_node->queue)), +#endif DHD_FLOW_QUEUE_FAILURES(&flow_ring_node->queue)); dhd_prot_print_flow_ring(dhdp, flow_ring_node->prot_info, TRUE, strbuf, "%5d:%5d:%5d %5d:%5d:%5d %17p %8x:%8x %14d %14d %10d"); @@ -11758,6 +11869,110 @@ void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); } +#ifdef TX_STATUS_LATENCY_STATS + bcm_bprintf(strbuf, "\n%s %16s %16s\n", "If", "AvgTxCmpL_Us", "NumTxStatus"); + if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; + for (ix = 0; ix < DHD_MAX_IFS; ix++) { + if (!if_flow_lkup[ix].status) { + continue; + } + bcm_bprintf(strbuf, "%2d %16llu %16llu\n", + ix, + if_tx_status_latency[ix].num_tx_status ? + DIV_U64_BY_U64(if_tx_status_latency[ix].cum_tx_status_latency, + if_tx_status_latency[ix].num_tx_status): 0, + if_tx_status_latency[ix].num_tx_status); + } +#endif /* TX_STATUS_LATENCY_STATS */ + + bcm_bprintf(strbuf, "\n"); +} + +void +dhd_bus_counters(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + dhd_prot_counters(dhdp, strbuf, TRUE, TRUE); + + dhd_bus_dump_flowring(dhdp, strbuf); + + dhd_dump_dpc_histos(dhdp, strbuf); +} + +/** Add bus dump output to a buffer */ +void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + uint16 flowid; +#ifdef BCMDBG + int ix = 0; + flow_ring_node_t *flow_ring_node; + flow_info_t *flow_info; + flow_info_t *local_flow_info; +#endif /* BCMDBG */ + + BCM_REFERENCE(flowid); + +#if defined(FW_SIGNATURE) + /* Dump secure firmware status. */ + if (dhdp->busstate <= DHD_BUS_LOAD) { + dhd_bus_dump_fws(dhdp->bus, strbuf); + } +#endif + + if (dhdp->busstate != DHD_BUS_DATA) + return; + +#ifdef DHD_WAKE_STATUS + bcm_bprintf(strbuf, "wake %u rxwake %u readctrlwake %u\n", + bcmpcie_get_total_wake(dhdp->bus), dhdp->bus->wake_counts.rxwake, + dhdp->bus->wake_counts.rcwake); +#ifdef DHD_WAKE_RX_STATUS + bcm_bprintf(strbuf, " unicast %u muticast %u broadcast %u arp %u\n", + dhdp->bus->wake_counts.rx_ucast, dhdp->bus->wake_counts.rx_mcast, + dhdp->bus->wake_counts.rx_bcast, dhdp->bus->wake_counts.rx_arp); + bcm_bprintf(strbuf, " multi4 %u multi6 %u icmp %u icmp6 %u multiother %u\n", + dhdp->bus->wake_counts.rx_multi_ipv4, dhdp->bus->wake_counts.rx_multi_ipv6, + dhdp->bus->wake_counts.rx_icmp, dhdp->bus->wake_counts.rx_icmpv6, + dhdp->bus->wake_counts.rx_multi_other); + bcm_bprintf(strbuf, " icmp6_ra %u, icmp6_na %u, icmp6_ns %u\n", + dhdp->bus->wake_counts.rx_icmpv6_ra, dhdp->bus->wake_counts.rx_icmpv6_na, + dhdp->bus->wake_counts.rx_icmpv6_ns); +#endif /* DHD_WAKE_RX_STATUS */ +#ifdef DHD_WAKE_EVENT_STATUS +#ifdef CUSTOM_WAKE_REASON_STATS + bcm_bprintf(strbuf, "rc_event_idx = %d, which indicates queue head\n", + dhdp->bus->wake_counts.rc_event_idx); + for (flowid = 0; flowid < MAX_WAKE_REASON_STATS; flowid++) + if (dhdp->bus->wake_counts.rc_event[flowid] != -1) +#else + for (flowid = 0; flowid < WLC_E_LAST; flowid++) + if (dhdp->bus->wake_counts.rc_event[flowid] != 0) +#endif /* CUSTOM_WAKE_REASON_STATS */ + bcm_bprintf(strbuf, " %s = %u\n", bcmevent_get_name(flowid), + dhdp->bus->wake_counts.rc_event[flowid]); + bcm_bprintf(strbuf, "\n"); +#endif /* DHD_WAKE_EVENT_STATUS */ +#endif /* DHD_WAKE_STATUS */ + + dhd_prot_print_info(dhdp, strbuf); + dhd_dump_intr_registers(dhdp, strbuf); + dhd_dump_intr_counters(dhdp, strbuf); + bcm_bprintf(strbuf, "h2d_mb_data_ptr_addr 0x%x, d2h_mb_data_ptr_addr 0x%x\n", + dhdp->bus->h2d_mb_data_ptr_addr, dhdp->bus->d2h_mb_data_ptr_addr); + bcm_bprintf(strbuf, "dhd cumm_ctr %d\n", DHD_CUMM_CTR_READ(&dhdp->cumm_ctr)); +#ifdef DHD_LIMIT_MULTI_CLIENT_FLOWRINGS + bcm_bprintf(strbuf, "multi_client_flow_rings:%u max_multi_client_flow_rings:%d\n", + OSL_ATOMIC_READ(dhdp->osh, &dhdp->multi_client_flow_rings), + dhdp->max_multi_client_flow_rings); +#endif /* DHD_LIMIT_MULTI_CLIENT_FLOWRINGS */ + + if (dhdp->htput_support) { + bcm_bprintf(strbuf, "htput_flow_ring_start:%d total_htput:%d client_htput=%d\n", + dhdp->htput_flow_ring_start, HTPUT_TOTAL_FLOW_RINGS, + dhdp->htput_client_flow_rings); + } + + dhd_bus_dump_flowring(dhdp, strbuf); + #ifdef BCMDBG if (!dhdp->d2h_sync_mode) { ix = 0; @@ -11787,65 +12002,8 @@ void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) } #endif /* BCMDBG */ -#ifdef TX_STATUS_LATENCY_STATS - bcm_bprintf(strbuf, "\n%s %16s %16s\n", "If", "AvgTxCmpL_Us", "NumTxStatus"); - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - for (ix = 0; ix < DHD_MAX_IFS; ix++) { - if (!if_flow_lkup[ix].status) { - continue; - } - bcm_bprintf(strbuf, "%2d %16llu %16llu\n", - ix, - if_tx_status_latency[ix].num_tx_status ? - DIV_U64_BY_U64(if_tx_status_latency[ix].cum_tx_status_latency, - if_tx_status_latency[ix].num_tx_status): 0, - if_tx_status_latency[ix].num_tx_status); - } -#endif /* TX_STATUS_LATENCY_STATS */ + dhd_dump_dpc_histos(dhdp, strbuf); -#ifdef DHD_HP2P - if (dhdp->hp2p_capable) { - bcm_bprintf(strbuf, "\n%s %16s %16s", "Flowid", "Tx_t0", "Tx_t1"); - - for (flowid = 0; flowid < MAX_HP2P_FLOWS; flowid++) { - hp2p_info_t *hp2p_info; - int bin; - - hp2p_info = &dhdp->hp2p_info[flowid]; - if (hp2p_info->num_timer_start == 0) - continue; - - bcm_bprintf(strbuf, "\n%d", hp2p_info->flowid); - bcm_bprintf(strbuf, "\n%s", "Bin"); - - for (bin = 0; bin < MAX_TX_HIST_BIN; bin++) { - bcm_bprintf(strbuf, "\n%2d %20llu %16llu", bin, - hp2p_info->tx_t0[bin], hp2p_info->tx_t1[bin]); - } - - bcm_bprintf(strbuf, "\n%s %16s", "Flowid", "Rx_t0"); - bcm_bprintf(strbuf, "\n%d", hp2p_info->flowid); - bcm_bprintf(strbuf, "\n%s", "Bin"); - - for (bin = 0; bin < MAX_RX_HIST_BIN; bin++) { - bcm_bprintf(strbuf, "\n%d %20llu", bin, - hp2p_info->rx_t0[bin]); - } - - bcm_bprintf(strbuf, "\n%s %16s %16s", - "Packet limit", "Timer limit", "Timer start"); - bcm_bprintf(strbuf, "\n%llu %24llu %16llu", hp2p_info->num_pkt_limit, - hp2p_info->num_timer_limit, hp2p_info->num_timer_start); - } - - bcm_bprintf(strbuf, "\n"); - } -#endif /* DHD_HP2P */ - -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) - dhd_bus_dump_awdl_stats(dhdp, strbuf); - dhd_clear_awdl_stats(dhdp); -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ bcm_bprintf(strbuf, "D3 inform cnt %d\n", dhdp->bus->d3_inform_cnt); bcm_bprintf(strbuf, "D0 inform cnt %d\n", dhdp->bus->d0_inform_cnt); bcm_bprintf(strbuf, "D0 inform in use cnt %d\n", dhdp->bus->d0_inform_in_use_cnt); @@ -11883,6 +12041,253 @@ void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) dhdp->db7_trap.debug_db7_timing_error_cnt); } +int +dhd_dump_flowrings(dhd_pub_t *dhdp, char *buf, int buflen) +{ + struct bcmstrbuf b; + struct bcmstrbuf *strbuf = &b; + + if (!dhdp || !dhdp->prot || !buf) { + return BCME_ERROR; + } + + bcm_binit(strbuf, buf, buflen); + dhd_bus_dump_flowring(dhdp, strbuf); + return (!strbuf->size ? BCME_BUFTOOSHORT : strbuf->size); +} + +static void +dhd_bus_dump_txcpl_info(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + tx_cpl_info_t *txcpl_info = &dhdp->txcpl_info; + int i; + + bcm_bprintf(strbuf, "\nTx Completion History\n"); + bcm_bprintf(strbuf, "Host(us)\t\tPTM_high(ns)\t\tPTM_low(ns)\t\t" + "Latency(ms)\t\tTID\t\tFlowID\n"); + for (i = 0; i < MAX_TXCPL_HISTORY; i ++) { + bcm_bprintf(strbuf, "0x%x\t\t0x%x\t\t0x%x\t\t%u\t\t%u\t\t%u\n", + txcpl_info->tx_history[i].host_time, + txcpl_info->tx_history[i].ptm_high, + txcpl_info->tx_history[i].ptm_low, + txcpl_info->tx_history[i].latency, + txcpl_info->tx_history[i].tid, + txcpl_info->tx_history[i].flowid); + } + bzero(txcpl_info->tx_history, + sizeof(tx_cpl_history_t) * MAX_TXCPL_HISTORY); + + bcm_bprintf(strbuf, "\n"); +} + +static void +dhd_bus_dump_mdring_info(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + int i; + int count; + + bcm_bprintf(strbuf, "\nMetadata Ring Dump\n"); + for (i = 0, count = 0; + i < MAX_MDRING_ITEM_DUMP * D2HRING_MDCMPLT_ITEMSIZE; i += 4) { + if ((i % D2HRING_MDCMPLT_ITEMSIZE) == 0) { + bcm_bprintf(strbuf, "\nEntry:%d:", ++count); + } + bcm_bprintf(strbuf, "0x%x%x%x%x:", + dhdp->mdring_info[i], dhdp->mdring_info[i+1], + dhdp->mdring_info[i+2], dhdp->mdring_info[i+3]); + } + bcm_bprintf(strbuf, "\n"); +} + +static bool +dhd_bus_support_dar_sec_status(dhd_bus_t *bus) +{ + DHD_ERROR(("%s: buscorerev=%d chipid=0x%x\n", + __FUNCTION__, bus->sih->buscorerev, si_chipid(bus->sih))); + + /* Support for DAR security status register provided for pcie core + * generation2 at revisions > 73 and for generation3 at revisions > 128 + */ + if ((bus->sih->buscorerev < 74) || (bus->sih->buscorerev == 128)) { + return FALSE; + } + + return TRUE; +} + +static int +dhd_bus_get_security_status(dhd_bus_t *bus, uint32 *status) +{ + uint32 dar_sec_reg; + + if (!dhd_bus_support_dar_sec_status(bus)) { + return BCME_UNSUPPORTED; + } + /* DAR Security Status Register address */ + dar_sec_reg = (uint32)DAR_SEC_STATUS(bus->sih->buscorerev); + + /* read DAR Security Status Register */ + *status = si_corereg(bus->sih, bus->sih->buscoreidx, dar_sec_reg, 0, 0); + + return BCME_OK; +} + +static int +dhd_bus_security_info(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + int ret = BCME_OK; + dhd_bus_t *bus = dhdp->bus; + uint32 dar_sec_val; + + ret = dhd_bus_get_security_status(bus, &dar_sec_val); + if (ret != BCME_OK) { + return ret; + } + + bcm_bprintf(strbuf, "\nDAR Security Status Reg\n"); + bcm_bprintf(strbuf, " Jtag Disable: %d\n", + (dar_sec_val & DAR_SEC_JTAG_MASK) >> DAR_SEC_JTAG_SHIFT); + bcm_bprintf(strbuf, " Secure Boot: %d\n", + (dar_sec_val & DAR_SEC_SBOOT_MASK) >> DAR_SEC_SBOOT_SHIFT); + bcm_bprintf(strbuf, " Arm Dbg Disable: %d\n", + (dar_sec_val & DAR_SEC_ARM_DBG_MASK) >> DAR_SEC_ARM_DBG_SHIFT); + bcm_bprintf(strbuf, " Transient Unlock: %d\n", + (dar_sec_val & DAR_SEC_UNLOCK_MASK) >> DAR_SEC_UNLOCK_SHIFT); + + /* The following bits in security status register provided for pcie core + * generation2 at revisions > 76 and for generation3 at revisions > 129 + */ + if (((bus->sih->buscorerev > 76) && (bus->sih->buscorerev < 128)) || + (bus->sih->buscorerev > 129)) { + bcm_bprintf(strbuf, " Rom Protect: %d\n", + (dar_sec_val & DAR_SEC_ROM_PROT_MASK) >> DAR_SEC_ROM_PROT_SHIFT); + bcm_bprintf(strbuf, " Non Secure Write: %d\n", + (dar_sec_val & DAR_SEC_NSEC_WR_MASK) >> DAR_SEC_NSEC_WR_SHIFT); + bcm_bprintf(strbuf, " Non Secure Read: %d\n", + (dar_sec_val & DAR_SEC_NSEC_RD_MASK) >> DAR_SEC_NSEC_RD_SHIFT); + } + return BCME_OK; +} + +static int +dhd_bus_sboot_disable(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + int ret = BCME_OK; + dhd_bus_t *bus = dhdp->bus; + uint32 save_idx, val; + sysmemregs_t *regs; + uint32 dar_sec_val; + + save_idx = si_coreidx(bus->sih); + ret = dhd_bus_get_security_status(bus, &dar_sec_val); + if (ret != BCME_OK) { + goto exit; + } + + /* check if chip is Transient Unlocked */ + if (!(dar_sec_val & DAR_SEC_UNLOCK_MASK)) { + bcm_bprintf(strbuf, "\nFail: Secure Boot still enabled!\n"); + goto exit; + } + + if ((regs = si_setcore(bus->sih, SYSMEM_CORE_ID, 0)) != NULL) { + /* check if mpu control is unlocked */ + val = R_REG(dhdp->osh, MPU_REG(regs, mpucontrol)); + if (val & BUS_MPU_LOCK_MASK) { + bcm_bprintf(strbuf, "\nFail: Mpu Control is locked!\n"); + goto exit; + } + + /* clear RomProtect and VectorProtect */ + W_REG(dhdp->osh, MPU_REG(regs, mpucontrol), + val & ~(BUS_MPU_ROM_PR_MASK | BUS_MPU_VEC_PR_MASK)); + + /* validate RomProtect and VectorProtect are cleared */ + val = R_REG(dhdp->osh, MPU_REG(regs, mpucontrol)); + if (val & (BUS_MPU_ROM_PR_MASK | BUS_MPU_VEC_PR_MASK)) { + bcm_bprintf(strbuf, "\nFail: Secure Boot still enabled!\n"); + } else { + bcm_bprintf(strbuf, "\nSecure Boot disabled!\n"); + } + + } +exit: + si_setcoreidx(bus->sih, save_idx); + return ret; +} + +static void +dhd_bus_dump_rxlat_info(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + if (dhdp->rx_cpl_lat_capable) { + rx_cpl_lat_info_t *rxcpl_info = &dhdp->rxcpl_lat_info; + int i; + + bcm_bprintf(strbuf, "\nRx Completion History\n"); + bcm_bprintf(strbuf, "Host(us)\t\tPTM_high(ns)\t\tPTM_low(ns)\t\tRx_t0\t\tBand" + "\t\tPrio\t\tRSSI\t\tLatency(us)\n"); + for (i = 0; i < MAX_RXCPL_HISTORY; i ++) { + if (rxcpl_info->rx_history[i].rx_t0 || rxcpl_info->rx_history[i].ptm_low) { + bcm_bprintf(strbuf, "0x%x\t\t0x%x\t\t0x%x\t\t0x%x\t\t%s\t\t%d\t\t%d" + "\t\t%d\n", + rxcpl_info->rx_history[i].host_time, + rxcpl_info->rx_history[i].ptm_high, + rxcpl_info->rx_history[i].ptm_low, + rxcpl_info->rx_history[i].rx_t0, + rxcpl_info->rx_history[i].slice? "5G":"2G", + rxcpl_info->rx_history[i].priority, + rxcpl_info->rx_history[i].rssi, + rxcpl_info->rx_history[i].latency); + } + } + bzero(rxcpl_info->rx_history, + sizeof(rx_cpl_history_t) * MAX_RXCPL_HISTORY); + } + bcm_bprintf(strbuf, "\n"); +} + +static void +dhd_bus_dump_rxlat_histo(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + int bin, prio; + + if (dhdp->rx_cpl_lat_capable) { + rx_cpl_lat_info_t *rxcpl_info = &dhdp->rxcpl_lat_info; + + bcm_bprintf(strbuf, + "\nRx:5G Latency histogram, each bin:%d us\n", RX_LAT_BIN_SCALE); + bcm_bprintf(strbuf, + "Bin\tPrio-0\tPrio-1\tPrio-2\tPrio-3\tPrio-4\tPrio-5\tPrio-6\tPrio-7\n"); + for (bin = 0; bin < MAX_RX_LAT_HIST_BIN; bin++) { + bcm_bprintf(strbuf, "\n%d", bin); + for (prio = 0; prio < MAX_RX_LAT_PRIO; prio++) { + bcm_bprintf(strbuf, "\t"); + if (rxcpl_info->rx_dur_5g[prio][bin]) { + bcm_bprintf(strbuf, "%d", + rxcpl_info->rx_dur_5g[prio][bin]); + } + } + } + bcm_bprintf(strbuf, + "\nRx:2G Latency histogram, each bin:%d us\n", RX_LAT_BIN_SCALE); + bcm_bprintf(strbuf, + "Bin\tPrio-0\tPrio-1\tPrio-2\tPrio-3\tPrio-4\tPrio-5\tPrio-6\tPrio-7\n"); + for (bin = 0; bin < MAX_RX_LAT_HIST_BIN; bin++) { + bcm_bprintf(strbuf, "\n%d", bin); + for (prio = 0; prio < MAX_RX_LAT_PRIO; prio++) { + bcm_bprintf(strbuf, "\t"); + if (rxcpl_info->rx_dur_2g[prio][bin]) { + bcm_bprintf(strbuf, "%d", + rxcpl_info->rx_dur_2g[prio][bin]); + } + } + } + bzero(rxcpl_info->rx_dur_5g, MAX_RX_LAT_PRIO * MAX_RX_LAT_HIST_BIN); + bzero(rxcpl_info->rx_dur_2g, MAX_RX_LAT_PRIO * MAX_RX_LAT_HIST_BIN); + } + bcm_bprintf(strbuf, "\n"); +} + #ifdef DNGL_AXI_ERROR_LOGGING bool dhd_axi_sig_match(dhd_pub_t *dhdp) @@ -12046,7 +12451,7 @@ dhd_log_dump_axi_error(uint8 *axi_err) * Brings transmit packets on all flow rings closer to the dongle, by moving (a subset) from their * flow queue to their flow ring. */ -static void +static bool dhd_update_txflowrings(dhd_pub_t *dhd) { unsigned long flags; @@ -12054,9 +12459,10 @@ dhd_update_txflowrings(dhd_pub_t *dhd) flow_ring_node_t *flow_ring_node; struct dhd_bus *bus = dhd->bus; int count = 0; + bool more = FALSE; if (dhd_query_bus_erros(dhd)) { - return; + return more; } /* Hold flowring_list_lock to ensure no race condition while accessing the List */ @@ -12065,6 +12471,7 @@ dhd_update_txflowrings(dhd_pub_t *dhd) (!dhd_is_device_removed(dhd) && !dll_end(&bus->flowring_active_list, item)); item = next, count++) { if (dhd->hang_was_sent) { + more = FALSE; break; } @@ -12074,6 +12481,7 @@ dhd_update_txflowrings(dhd_pub_t *dhd) dhd->hang_reason = HANG_REASON_UNKNOWN; dhd_os_send_hang_message(dhd); #endif /* OEM_ANDROID */ + more = FALSE; break; } @@ -12086,9 +12494,12 @@ dhd_update_txflowrings(dhd_pub_t *dhd) /* Ensure that the flowring node has valid contents */ ASSERT(flow_ring_node->prot_info != NULL); - dhd_prot_update_txflowring(dhd, flow_ring_node->flowid, flow_ring_node->prot_info); + more = dhd_prot_update_txflowring(dhd, flow_ring_node->flowid, + flow_ring_node->prot_info); } DHD_FLOWRING_LIST_UNLOCK(bus->dhd->flowring_list_lock, flags); + + return more; } /** Mailbox ringbell Function */ @@ -12103,7 +12514,7 @@ dhd_bus_gen_devmb_intr(struct dhd_bus *bus) if (bus->db1_for_mb) { /* this is a pcie core register, not the config register */ /* XXX: make sure we are on PCIE */ - DHD_PCIE_INFO(("%s: writing a mail box interrupt to the device, through doorbell 1\n", __FUNCTION__)); + DHD_INFO(("%s: writing a mail box interrupt to the device, through doorbell 1\n", __FUNCTION__)); if (DAR_PWRREQ(bus)) { dhd_bus_pcie_pwr_req(bus); } @@ -12113,8 +12524,7 @@ dhd_bus_gen_devmb_intr(struct dhd_bus *bus) si_corereg(bus->sih, bus->sih->buscoreidx, dhd_bus_db1_addr_get(bus), ~0, 0x12345678); } else { - DHD_PCIE_INFO(("%s: writing a mail box interrupt to the device," - " through config space\n", __FUNCTION__)); + DHD_INFO(("%s: writing a mail box interrupt to the device, through config space\n", __FUNCTION__)); dhdpcie_bus_cfg_write_dword(bus, PCISBMbx, 4, (1 << 0)); /* XXX CRWLPCIEGEN2-182 requires double write */ dhdpcie_bus_cfg_write_dword(bus, PCISBMbx, 4, (1 << 0)); @@ -12128,9 +12538,11 @@ dhd_bus_gen_devmb_intr(struct dhd_bus *bus) static void dhdpcie_fw_trap(dhd_bus_t *bus) { - DHD_ERROR(("%s: send trap!!!\n", __FUNCTION__)); if (bus->dhd->db7_trap.fw_db7w_trap) { uint32 addr = dhd_bus_db1_addr_3_get(bus); + + DHD_ERROR(("%s: send DB7 trap!!!\n", __FUNCTION__)); + bus->dhd->db7_trap.fw_db7w_trap_recieved = FALSE; bus->dhd->db7_trap.debug_db7_send_time = OSL_LOCALTIME_NS(); bus->dhd->db7_trap.debug_db7_send_cnt++; si_corereg(bus->sih, bus->sih->buscoreidx, addr, ~0, @@ -12138,12 +12550,40 @@ dhdpcie_fw_trap(dhd_bus_t *bus) return; } + DHD_ERROR(("%s: send trap!!!\n", __FUNCTION__)); /* Send the mailbox data and generate mailbox intr. */ dhdpcie_send_mb_data(bus, H2D_FW_TRAP); /* For FWs that cannot interprete H2D_FW_TRAP */ (void)dhd_wl_ioctl_set_intiovar(bus->dhd, "bus:disconnect", 99, WLC_SET_VAR, TRUE, 0); } +void +dhdpcie_db7_trap(struct dhd_bus *bus) +{ + if (bus->dhd->busstate != DHD_BUS_DATA) { + DHD_ERROR(("%s: Bus is NOT up. busstate: %d\n", __FUNCTION__, bus->dhd->busstate)); + return; + } + if (bus->dhd->db7_trap.fw_db7w_trap) { + unsigned long flags = 0; + + DHD_GENERAL_LOCK(bus->dhd, flags); + bus->dhd->db7_trap.fw_db7w_trap_inprogress = TRUE; + DHD_GENERAL_UNLOCK(bus->dhd, flags); + dhdpcie_fw_trap(bus); + OSL_DELAY(100 * 1000); // wait 100 msec + if (!bus->dhd->db7_trap.fw_db7w_trap_recieved) { + DHD_ERROR(("%s : Did not receive DB7 Ack\n", __FUNCTION__)); + } + DHD_GENERAL_LOCK(bus->dhd, flags); + bus->dhd->db7_trap.fw_db7w_trap_inprogress = FALSE; + DHD_GENERAL_UNLOCK(bus->dhd, flags); + } else { + DHD_TRACE(("%s: DB7 Not supported!!!\n", __FUNCTION__)); + } + +} + #ifdef PCIE_INB_DW void @@ -12154,7 +12594,7 @@ dhd_bus_inb_ack_pending_ds_req(dhd_bus_t *bus) */ if ((dhdpcie_bus_get_pcie_inband_dw_state(bus) == DW_DEVICE_DS_DEV_SLEEP_PEND) && - (bus->host_active_cnt == 0)) { + (bus->host_active_cnt == 0) && (!bus->skip_ds_ack)) { dhdpcie_bus_set_pcie_inband_dw_state(bus, DW_DEVICE_DS_DEV_SLEEP); dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK); } @@ -12205,7 +12645,7 @@ dhd_bus_inb_set_device_wake(struct dhd_bus *bus, bool val) "waiting for DS-Exit\n")); } else { - DHD_PCIE_INFO(("Not in DS SLEEP state \n")); + DHD_INFO(("Not in DS SLEEP state \n")); DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ret = BCME_OK; goto exit; @@ -12277,7 +12717,7 @@ dhd_bus_inb_set_device_wake(struct dhd_bus *bus, bool val) bus->inband_dw_deassert_cnt++; } else if ((dhdpcie_bus_get_pcie_inband_dw_state(bus) == DW_DEVICE_DS_DEV_SLEEP_PEND) && - (bus->host_active_cnt == 0)) { + (bus->host_active_cnt == 0) && (!bus->skip_ds_ack)) { dhdpcie_bus_set_pcie_inband_dw_state(bus, DW_DEVICE_DS_DEV_SLEEP); dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK); } @@ -12289,18 +12729,39 @@ dhd_bus_inb_set_device_wake(struct dhd_bus *bus, bool val) exit: return ret; } + +#ifdef PCIE_INB_DSACK_EXT_WAIT +void +dhd_bus_ds_ack_debug_dump(struct dhd_bus *bus) +{ + if ((DIV_U64_BY_U32(bus->isr_entry_time, NSEC_PER_SEC) - + DIV_U64_BY_U32(bus->prev_isr_entry_time, NSEC_PER_SEC)) >= + DW_DS_ACK_RETRY_THRESHOLD) { + bus->dhd->dsack_hc_due_to_isr_delay = TRUE; + DHD_ERROR(("ISR did not run causing DS ack timeout\n")); + } else if ((bus->dpc_entry_time > bus->isr_entry_time) && + (DIV_U64_BY_U32(bus->dpc_entry_time, NSEC_PER_SEC) - + DIV_U64_BY_U32(bus->isr_entry_time, NSEC_PER_SEC)) >= + DW_DS_ACK_RETRY_THRESHOLD) { + bus->dhd->dsack_hc_due_to_dpc_delay = TRUE; + DHD_ERROR(("Delay in scheduling DPC causing DS ack timeout\n")); + } else { + DHD_ERROR(("Failed to send DS ack\n")); + } + DHD_ERROR(("prev_isr_entry_time="SEC_USEC_FMT + " isr_entry_time="SEC_USEC_FMT + " dpc_entry_time="SEC_USEC_FMT"\n", + GET_SEC_USEC(bus->prev_isr_entry_time), + GET_SEC_USEC(bus->isr_entry_time), + GET_SEC_USEC(bus->dpc_entry_time))); +} +#endif /* PCIE_INB_DSACK_EXT_WAIT */ #endif /* PCIE_INB_DW */ #if defined(PCIE_OOB) || defined(PCIE_INB_DW) void dhd_bus_doorbell_timeout_reset(struct dhd_bus *bus) { if (dhd_doorbell_timeout) { -#ifdef DHD_PCIE_RUNTIMEPM - if (dhd_runtimepm_ms) { - dhd_timeout_start(&bus->doorbell_timer, - (dhd_doorbell_timeout * 1000) / dhd_runtimepm_ms); - } -#else #ifdef BCMQT uint wd_scale = 1; #else @@ -12310,7 +12771,6 @@ dhd_bus_doorbell_timeout_reset(struct dhd_bus *bus) dhd_timeout_start(&bus->doorbell_timer, (dhd_doorbell_timeout * 1000) / wd_scale); } -#endif /* DHD_PCIE_RUNTIMEPM */ } else if (!(bus->dhd->busstate == DHD_BUS_SUSPEND)) { dhd_bus_set_device_wake(bus, FALSE); @@ -12411,7 +12871,7 @@ dhd_bus_ringbell(struct dhd_bus *bus, uint32 value) } else { /* this is a pcie core register, not the config regsiter */ /* XXX: makesure we are on PCIE */ - DHD_PCIE_INFO(("%s: writing a door bell to the device\n", __FUNCTION__)); + DHD_INFO(("%s: writing a door bell to the device\n", __FUNCTION__)); if (IDMA_ACTIVE(bus->dhd)) { if (DAR_PWRREQ(bus)) { dhd_bus_pcie_pwr_req(bus); @@ -12447,7 +12907,7 @@ dhd_bus_ringbell_2(struct dhd_bus *bus, uint32 value, bool devwake) return; } - DHD_PCIE_INFO(("writing a door bell 2 to the device\n")); + DHD_INFO(("writing a door bell 2 to the device\n")); if (DAR_PWRREQ(bus)) { dhd_bus_pcie_pwr_req(bus); } @@ -12485,17 +12945,6 @@ dhdpcie_bus_ringbell_fast(struct dhd_bus *bus, uint32 value) dhd_bus_pcie_pwr_req(bus); } -#ifdef DHD_DB0TS - if (bus->dhd->db0ts_capable) { - uint64 ts; - - ts = local_clock(); - do_div(ts, 1000); - - value = htol32(ts & 0xFFFFFFFF); - DHD_INFO(("%s: usec timer = 0x%x\n", __FUNCTION__, value)); - } -#endif /* DHD_DB0TS */ W_REG(bus->pcie_mb_intr_osh, bus->pcie_mb_intr_addr, value); } @@ -12504,7 +12953,7 @@ dhdpcie_bus_ringbell_2_fast(struct dhd_bus *bus, uint32 value, bool devwake) { /* Skip once bus enters low power state (D3_INFORM/D3_ACK) */ if (__DHD_CHK_BUS_IN_LPS(bus)) { - DHD_RPM(("%s: trying to ring the doorbell after D3 inform %d\n", + DHD_ERROR(("%s: trying to ring the doorbell after D3 inform %d\n", __FUNCTION__, bus->bus_low_power_state)); return; } @@ -12599,7 +13048,24 @@ BCMFASTPATH(dhd_bus_dpc)(struct dhd_bus *bus) bus->dpc_entry_time = OSL_LOCALTIME_NS(); if (dhd_query_bus_erros(bus->dhd)) { - return 0; + if (bus->dhd->db7_trap.fw_db7w_trap_inprogress == FALSE) { + DHD_ERROR_RLMT(("%s: db7 not in progress, exit\n", __FUNCTION__)); + return 0; + } + } + + /* Due to irq mismatch WARNING in linux, currently keeping it disabled and + * using dongle intmask to control INTR enable/disable + */ + if (bus->d2h_intr_control == PCIE_HOST_IRQ_CTRL) { + /* + * Disable IRQ at start of DPC if it is not disabled and + * Enable back at the end of dpc if irq is disabled. + */ + if (!dhdpcie_irq_disabled(bus)) { + bus->host_irq_disable_count++; + dhdpcie_disable_irq_nosync(bus); /* Disable host IRQ!! */ + } } DHD_GENERAL_LOCK(bus->dhd, flags); @@ -12615,9 +13081,6 @@ BCMFASTPATH(dhd_bus_dpc)(struct dhd_bus *bus) bus->dpc_return_busdown_count++; return 0; } -#ifdef DHD_PCIE_RUNTIMEPM - bus->idlecount = 0; -#endif /* DHD_PCIE_RUNTIMEPM */ DHD_BUS_BUSY_SET_IN_DPC(bus->dhd); DHD_GENERAL_UNLOCK(bus->dhd, flags); @@ -12633,34 +13096,32 @@ BCMFASTPATH(dhd_bus_dpc)(struct dhd_bus *bus) } #endif /* DHD_READ_INTSTATUS_IN_DPC */ - /* Do not process dpc after receiving D3_ACK */ - if (DHD_CHK_BUS_LPS_D3_ACKED(bus)) { - DHD_ERROR(("%s: D3 Ack Recieved, skip dpc\n", __FUNCTION__)); - goto exit; - } - resched = dhdpcie_bus_process_mailbox_intr(bus, bus->intstatus); if (!resched) { bus->intstatus = 0; #ifdef DHD_READ_INTSTATUS_IN_DPC INTR_ON: #endif /* DHD_READ_INTSTATUS_IN_DPC */ - if (bus->d2h_intr_control == PCIE_D2H_INTMASK_CTRL) { - dhdpcie_bus_intr_enable(bus); /* Enable back interrupt using Intmask!! */ - bus->dpc_intr_enable_count++; - } else { - /* For Linux, Macos etc (otherthan NDIS) enable back the host interrupts - * which has been disabled in the dhdpcie_bus_isr() + bus->dpc_exit_time = OSL_LOCALTIME_NS(); + bus->dpc_time_usec = DIV_U64_BY_U64((bus->dpc_exit_time - bus->dpc_entry_time), NSEC_PER_USEC); + if (!dhd_query_bus_erros(bus->dhd)) { + /* Due to irq mismatch WARNING in linux, currently keeping it disabled and + * using dongle intmask to control INTR enable/disable */ - if ((dhdpcie_irq_disabled(bus)) && (!dhd_query_bus_erros(bus->dhd))) { - dhdpcie_enable_irq(bus); /* Enable back interrupt!! */ - bus->dpc_intr_enable_count++; + if (bus->d2h_intr_control == PCIE_HOST_IRQ_CTRL) { + bus->host_irq_enable_count += dhdpcie_irq_disabled(bus); + dhdpcie_enable_irq_loop(bus); + } else { + /* Enable back interrupt using Intmask! */ + dhdpcie_bus_intr_enable(bus); + bus->dngl_intmask_enable_count++; } } - bus->dpc_exit_time = OSL_LOCALTIME_NS(); } else { bus->resched_dpc_time = OSL_LOCALTIME_NS(); + bus->dpc_time_usec = DIV_U64_BY_U64((bus->resched_dpc_time - bus->dpc_entry_time), NSEC_PER_USEC); } + dhd_histo_update(bus->dhd, bus->dpc_time_histo, (uint32)bus->dpc_time_usec); bus->dpc_sched = resched; #ifdef DHD_FLOW_RING_STATUS_TRACE @@ -12670,7 +13131,6 @@ INTR_ON: } #endif /* DHD_FLOW_RING_STATUS_TRACE */ -exit: DHD_GENERAL_LOCK(bus->dhd, flags); DHD_BUS_BUSY_CLEAR_IN_DPC(bus->dhd); dhd_os_busbusy_wake(bus->dhd); @@ -12690,7 +13150,7 @@ dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data) return BCME_ERROR; } - DHD_PCIE_INFO(("%s: H2D_MB_DATA: 0x%08X\n", __FUNCTION__, h2d_mb_data)); + DHD_INFO(("%s: H2D_MB_DATA: 0x%08X\n", __FUNCTION__, h2d_mb_data)); #ifdef PCIE_INB_DW if (h2d_mb_data == H2D_HOST_DS_ACK) { @@ -12701,8 +13161,8 @@ dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data) dhd_bus_ds_trace(bus, h2d_mb_data, FALSE); #endif /* PCIE_INB_DW */ if (bus->api.fw_rev >= PCIE_SHARED_VERSION_6 && !bus->use_mailbox) { - DHD_PCIE_INFO(("API rev is 6, sending mb data as H2D Ctrl message" - " to dongle, 0x%04x\n", h2d_mb_data)); + DHD_INFO(("API rev is 6, sending mb data as H2D Ctrl message to dongle, 0x%04x\n", + h2d_mb_data)); /* Prevent asserting device_wake during doorbell ring for mb data to avoid loop. */ #ifdef PCIE_OOB bus->oob_enabled = FALSE; @@ -12723,8 +13183,7 @@ dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data) if (cur_h2d_mb_data != 0) { uint32 i = 0; - DHD_PCIE_INFO(("%s: GRRRRRRR: MB transaction is already pending 0x%04x\n", - __FUNCTION__, cur_h2d_mb_data)); + DHD_INFO(("%s: GRRRRRRR: MB transaction is already pending 0x%04x\n", __FUNCTION__, cur_h2d_mb_data)); /* XXX: start a zero length timer to keep checking this to be zero */ while ((i++ < 100) && cur_h2d_mb_data) { OSL_DELAY(10); @@ -12755,6 +13214,12 @@ done: DHD_INFO_HW4(("%s: send H2D_HOST_D0_INFORM to dongle\n", __FUNCTION__)); bus->d0_inform_cnt++; } + if (h2d_mb_data == H2D_HOST_PTM_ENABLE) { + DHD_INFO(("%s: send H2D_HOST_PTM_ENABLE to dongle\n", __FUNCTION__)); + } + if (h2d_mb_data == H2D_HOST_PTM_DISABLE) { + DHD_INFO(("%s: send H2D_HOST_PTM_DISABLE to dongle\n", __FUNCTION__)); + } return BCME_OK; fail: return BCME_ERROR; @@ -12763,19 +13228,13 @@ fail: static void dhd_bus_handle_d3_ack(dhd_bus_t *bus) { - bus->suspend_intr_disable_count++; - /* Disable dongle Interrupts Immediately after D3 */ + bus->dngl_intmask_disable_count++; - /* For Linux, Macos etc (otherthan NDIS) along with disabling - * dongle interrupt by clearing the IntMask, disable directly - * interrupt from the host side as well. Also clear the intstatus + /* Disable dongle interrupts by intmask and clear the intstatus * if it is set to avoid unnecessary intrrupts after D3 ACK. */ dhdpcie_bus_intr_disable(bus); /* Disable interrupt using IntMask!! */ dhdpcie_bus_clear_intstatus(bus); -#ifndef NDIS /* !NDIS */ - dhdpcie_disable_irq_nosync(bus); /* Disable host interrupt!! */ -#endif /* !NDIS */ DHD_SET_BUS_LPS_D3_ACKED(bus); DHD_RPM(("%s: D3_ACK Recieved\n", __FUNCTION__)); @@ -12795,6 +13254,8 @@ dhd_bus_handle_d3_ack(dhd_bus_t *bus) } else { DHD_ERROR(("%s: Inducing D3 ACK timeout\n", __FUNCTION__)); } + + bus->last_d3_ack_time = OSL_LOCALTIME_NS(); } void @@ -12803,11 +13264,8 @@ dhd_bus_handle_mb_data(dhd_bus_t *bus, uint32 d2h_mb_data) #ifdef PCIE_INB_DW unsigned long flags = 0; #endif /* PCIE_INB_DW */ - if (MULTIBP_ENAB(bus->sih)) { - dhd_bus_pcie_pwr_req(bus); - } - DHD_PCIE_INFO(("D2H_MB_DATA: 0x%04x\n", d2h_mb_data)); + DHD_INFO(("D2H_MB_DATA: 0x%04x\n", d2h_mb_data)); #ifdef PCIE_INB_DW DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); dhd_bus_ds_trace(bus, d2h_mb_data, TRUE, dhdpcie_bus_get_pcie_inband_dw_state(bus)); @@ -12846,17 +13304,15 @@ dhd_bus_handle_mb_data(dhd_bus_t *bus, uint32 d2h_mb_data) dhdpcie_handle_dongle_trap(bus); #endif #ifdef OEM_ANDROID -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ dhd_os_check_hang(bus->dhd, 0, -EREMOTEIO); #endif /* OEM_ANDROID */ } if (bus->dhd->db7_trap.fw_db7w_trap_inprogress) { bus->dhd->db7_trap.fw_db7w_trap_inprogress = FALSE; +#if !defined(OEM_ANDROID) + /* Fix for UTF issue */ bus->dhd->dongle_trap_occured = TRUE; +#endif } goto exit; } @@ -12870,14 +13326,14 @@ dhd_bus_handle_mb_data(dhd_bus_t *bus, uint32 d2h_mb_data) goto exit; } /* what should we do */ - DHD_PCIE_INFO(("D2H_MB_DATA: DEEP SLEEP REQ\n")); + DHD_INFO(("D2H_MB_DATA: DEEP SLEEP REQ\n")); #ifdef PCIE_INB_DW if (INBAND_DW_ENAB(bus)) { /* As per inband state machine, host should not send DS-ACK * during suspend or suspend in progress, instead D3 inform will be sent. */ + DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); if (!bus->skip_ds_ack) { - DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); if (dhdpcie_bus_get_pcie_inband_dw_state(bus) == DW_DEVICE_DS_ACTIVE) { dhdpcie_bus_set_pcie_inband_dw_state(bus, @@ -12887,10 +13343,10 @@ dhd_bus_handle_mb_data(dhd_bus_t *bus, uint32 d2h_mb_data) DW_DEVICE_DS_DEV_SLEEP); dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK); ds_acked = TRUE; - DHD_PCIE_INFO(("D2H_MB_DATA: sent DEEP SLEEP" + DHD_INFO(("D2H_MB_DATA: sent DEEP SLEEP" "ACK to DNGL\n")); } else { - DHD_PCIE_INFO(("%s: Host is active, " + DHD_INFO(("%s: Host is active, " "skip sending DS-ACK. " "host_active_cnt is %d\n", __FUNCTION__, bus->host_active_cnt)); @@ -12911,30 +13367,15 @@ dhd_bus_handle_mb_data(dhd_bus_t *bus, uint32 d2h_mb_data) DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); dhd_os_ds_enter_wake(bus->dhd); } else { - DHD_PCIE_INFO(("%s: Skip DS-ACK due to " + DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); + DHD_INFO(("%s: Skip DS-ACK due to " "suspend in progress\n", __FUNCTION__)); } -#ifdef DHD_EFI - if (ds_acked && !bus->ds_enabled) { - /* if 'deep_sleep' is disabled, then need to again assert DW - * from here once we we have acked the DS_ENTER_REQ, so that - * dongle stays awake and honours the user iovar request. - * Note, that this code will be hit only for the pcie_suspend/resume - * case with 'deep_sleep' disabled, and will not get executed in - * the normal path either when 'deep_sleep' is enabled (default) - * or when 'deep_sleep' is disabled, because if 'deep_sleep' is - * disabled, then by definition, dongle will not send DS_ENTER_REQ - * except in the case of D0 -> D3 -> D0 transitions, which is what - * is being handled here. - */ - dhd_bus_inb_set_device_wake(bus, TRUE); - } -#endif /* DHD_EFI */ } else #endif /* PCIE_INB_DW */ { dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK); - DHD_PCIE_INFO(("D2H_MB_DATA: sent DEEP SLEEP ACK\n")); + DHD_INFO(("D2H_MB_DATA: sent DEEP SLEEP ACK\n")); } } if (d2h_mb_data & D2H_DEV_DS_EXIT_NOTE) { @@ -12951,7 +13392,7 @@ dhd_bus_handle_mb_data(dhd_bus_t *bus, uint32 d2h_mb_data) } #endif /* PCIE_INB_DW */ /* what should we do */ - DHD_PCIE_INFO(("D2H_MB_DATA: DEEP SLEEP EXIT\n")); + DHD_INFO(("D2H_MB_DATA: DEEP SLEEP EXIT\n")); #ifdef PCIE_INB_DW if (INBAND_DW_ENAB(bus)) { DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); @@ -12976,8 +13417,7 @@ dhd_bus_handle_mb_data(dhd_bus_t *bus, uint32 d2h_mb_data) dhd_os_ds_exit_wake(bus->dhd); } else if (dhdpcie_bus_get_pcie_inband_dw_state(bus) == DW_DEVICE_DS_DEV_SLEEP) { - DHD_PCIE_INFO(("recvd unsolicited DS-EXIT" - " from dongle in DEV_SLEEP\n")); + DHD_INFO(("recvd unsolicited DS-EXIT from dongle in DEV_SLEEP\n")); /* * unsolicited state change to DW_DEVICE_DS_DEV_WAKE if * D2H_DEV_DS_EXIT_NOTE received in DW_DEVICE_DS_DEV_SLEEP state. @@ -12989,8 +13429,7 @@ dhd_bus_handle_mb_data(dhd_bus_t *bus, uint32 d2h_mb_data) DW_DEVICE_DS_DEV_WAKE); DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); } else { - DHD_PCIE_INFO(("D2H_MB_DATA: not in" - " DS_DISABLED_WAIT/DS_DEV_SLEEP\n")); + DHD_INFO(("D2H_MB_DATA: not in DS_DISABLED_WAIT/DS_DEV_SLEEP\n")); bus->inband_ds_exit_host_cnt++; DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); } @@ -13010,7 +13449,7 @@ dhd_bus_handle_mb_data(dhd_bus_t *bus, uint32 d2h_mb_data) } if (d2h_mb_data & D2HMB_DS_HOST_SLEEP_EXIT_ACK) { /* what should we do */ - DHD_PCIE_INFO(("D2H_MB_DATA: D0 ACK\n")); + DHD_INFO(("D2H_MB_DATA: D0 ACK\n")); #ifdef PCIE_INB_DW if (INBAND_DW_ENAB(bus)) { DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); @@ -13038,10 +13477,16 @@ dhd_bus_handle_mb_data(dhd_bus_t *bus, uint32 d2h_mb_data) } } -exit: - if (MULTIBP_ENAB(bus->sih)) { - dhd_bus_pcie_pwr_req_clear(bus); + if (d2h_mb_data & D2H_DEV_PTM_ENABLED) { + DHD_INFO(("D2H_MB_DATA: PTM ENABLED\n")); } + + if (d2h_mb_data & D2H_DEV_PTM_DISABLED) { + DHD_INFO(("D2H_MB_DATA: PTM DISABLED\n")); + } + +exit: + return; } static void @@ -13080,13 +13525,13 @@ dhdpcie_handle_mb_data(dhd_bus_t *bus) } if (d2h_mb_data & D2H_DEV_DS_ENTER_REQ) { /* what should we do */ - DHD_PCIE_INFO(("%s: D2H_MB_DATA: DEEP SLEEP REQ\n", __FUNCTION__)); + DHD_INFO(("%s: D2H_MB_DATA: DEEP SLEEP REQ\n", __FUNCTION__)); dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK); - DHD_PCIE_INFO(("%s: D2H_MB_DATA: sent DEEP SLEEP ACK\n", __FUNCTION__)); + DHD_INFO(("%s: D2H_MB_DATA: sent DEEP SLEEP ACK\n", __FUNCTION__)); } if (d2h_mb_data & D2H_DEV_DS_EXIT_NOTE) { /* what should we do */ - DHD_PCIE_INFO(("%s: D2H_MB_DATA: DEEP SLEEP EXIT\n", __FUNCTION__)); + DHD_INFO(("%s: D2H_MB_DATA: DEEP SLEEP EXIT\n", __FUNCTION__)); } if (d2h_mb_data & D2H_DEV_D3_ACK) { /* what should we do */ @@ -13141,12 +13586,12 @@ static void dhd_bus_handle_intx_ahead_dma_indices(dhd_bus_t *bus) { if (bus->d2h_intr_method == PCIE_MSI) { - DHD_PCIE_INFO(("%s: not required for msi\n", __FUNCTION__)); + DHD_INFO(("%s: not required for msi\n", __FUNCTION__)); return; } if (bus->dhd->dma_d2h_ring_upd_support == FALSE) { - DHD_PCIE_INFO(("%s: not required for non-dma-indices\n", __FUNCTION__)); + DHD_INFO(("%s: not required for non-dma-indices\n", __FUNCTION__)); return; } @@ -13157,21 +13602,22 @@ dhd_bus_handle_intx_ahead_dma_indices(dhd_bus_t *bus) #ifndef NDIS /* * skip delayed dpc if tasklet is scheduled by non-ISR - * From ISR context, we disable IRQ and enable IRQ back at the end of dpc, - * hence if IRQ is not disabled we can consider it as scheduled from non-ISR context. + * From ISR context, if dpc is scheduled, the isr_sched_dpc_time + * will be lesser than dpc_exit_time. */ - if (dhdpcie_irq_disabled(bus) == FALSE) { - DHD_PCIE_INFO(("%s: skip delayed dpc as tasklet is scheduled from non isr\n", + if (bus->isr_sched_dpc_time < bus->dpc_exit_time) { + DHD_INFO(("%s: skip delayed dpc as tasklet is scheduled from non isr\n", __FUNCTION__)); return; } #endif /* NDIS */ if (DHD_CHK_BUS_LPS_D3_ACKED(bus)) { - DHD_PCIE_INFO(("%s: skip delayed dpc as d3 ack is received\n", __FUNCTION__)); + DHD_INFO(("%s: skip delayed dpc as d3 ack is received\n", __FUNCTION__)); return; } + DHD_INFO(("%s: schedule delayed DPC\n", __FUNCTION__)); dhd_schedule_delayed_dpc_on_dpc_cpu(bus->dhd, DHD_SCHED_RETRY_DPC_DELAY_MS); return; } @@ -13181,9 +13627,12 @@ dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus) { bool resched = FALSE; - if (MULTIBP_ENAB(bus->sih)) { - dhd_bus_pcie_pwr_req(bus); + /* Do not process dpc after receiving D3_ACK */ + if (DHD_CHK_BUS_LPS_D3_ACKED(bus)) { + DHD_RPM(("%s: D3 Ack Received, skip dpc\n", __FUNCTION__)); + return resched; } + if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || (bus->sih->buscorerev == 4)) { /* Msg stream interrupt */ @@ -13214,9 +13663,6 @@ dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus) dhd_bus_handle_intx_ahead_dma_indices(bus); - if (MULTIBP_ENAB(bus->sih)) { - dhd_bus_pcie_pwr_req_clear(bus); - } return resched; } @@ -13255,6 +13701,11 @@ static bool dhdpci_bus_read_frames(dhd_bus_t *bus) { bool more = FALSE; + uint32 ctrlcpl_items = 0; + uint32 txcpl_items = 0; + uint32 rxcpl_items = 0; + uint32 evtlog_items = 0; + uint64 read_frames_entry_time = OSL_LOCALTIME_NS(); /* First check if there a FW trap */ if ((bus->api.fw_rev >= PCIE_SHARED_VERSION_6) && @@ -13278,9 +13729,14 @@ dhdpci_bus_read_frames(dhd_bus_t *bus) dhd_prot_save_dmaidx(bus->dhd); #endif /* DHD_DMA_INDICES_SEQNUM */ /* There may be frames in both ctrl buf and data buf; check ctrl buf first */ - dhd_prot_process_ctrlbuf(bus->dhd); + more |= dhd_prot_process_ctrlbuf(bus->dhd, &ctrlcpl_items); bus->last_process_ctrlbuf_time = OSL_LOCALTIME_NS(); + bus->ctrl_cpl_post_time_usec = + DIV_U64_BY_U64((bus->last_process_ctrlbuf_time - read_frames_entry_time), NSEC_PER_USEC); + dhd_histo_update(bus->dhd, bus->ctrl_cpl_post_time_histo, + (uint32)bus->ctrl_cpl_post_time_usec); + /* Do not process rest of ring buf once bus enters low power state (D3_INFORM/D3_ACK) */ if (DHD_CHK_BUS_IN_LPS(bus)) { DHD_RPM(("%s: Bus is in power save state (%d). " @@ -13290,54 +13746,49 @@ dhdpci_bus_read_frames(dhd_bus_t *bus) } /* update the flow ring cpls */ - dhd_update_txflowrings(bus->dhd); + more |= dhd_update_txflowrings(bus->dhd); bus->last_process_flowring_time = OSL_LOCALTIME_NS(); + bus->tx_post_time_usec = + DIV_U64_BY_U64((bus->last_process_flowring_time - bus->last_process_ctrlbuf_time), NSEC_PER_USEC); + dhd_histo_update(bus->dhd, bus->tx_post_time_histo, (uint32)bus->tx_post_time_usec); + /* With heavy TX traffic, we could get a lot of TxStatus * so add bound */ -#ifdef DHD_HP2P - more |= dhd_prot_process_msgbuf_txcpl(bus->dhd, dhd_txbound, DHD_HP2P_RING); -#endif /* DHD_HP2P */ - more |= dhd_prot_process_msgbuf_txcpl(bus->dhd, dhd_txbound, DHD_REGULAR_RING); + more |= dhd_prot_process_msgbuf_txcpl(bus->dhd, DHD_REGULAR_RING, &txcpl_items); bus->last_process_txcpl_time = OSL_LOCALTIME_NS(); + bus->tx_cpl_time_usec = + DIV_U64_BY_U64((bus->last_process_txcpl_time - bus->last_process_flowring_time), NSEC_PER_USEC); + dhd_histo_update(bus->dhd, bus->tx_cpl_time_histo, (uint32)bus->tx_cpl_time_usec); + /* With heavy RX traffic, this routine potentially could spend some time * processing RX frames without RX bound */ -#ifdef DHD_HP2P - more |= dhd_prot_process_msgbuf_rxcpl(bus->dhd, dhd_rxbound, DHD_HP2P_RING); -#endif /* DHD_HP2P */ - more |= dhd_prot_process_msgbuf_rxcpl(bus->dhd, dhd_rxbound, DHD_REGULAR_RING); + more |= dhd_prot_process_msgbuf_rxcpl(bus->dhd, DHD_REGULAR_RING, &rxcpl_items); bus->last_process_rxcpl_time = OSL_LOCALTIME_NS(); + bus->rx_cpl_post_time_usec = + DIV_U64_BY_U64((bus->last_process_rxcpl_time - bus->last_process_txcpl_time), NSEC_PER_USEC); + dhd_histo_update(bus->dhd, bus->rx_cpl_post_time_histo, (uint32)bus->rx_cpl_post_time_usec); + /* Process info ring completion messages */ #ifdef EWP_EDL if (!bus->dhd->dongle_edl_support) #endif { - more |= dhd_prot_process_msgbuf_infocpl(bus->dhd, DHD_INFORING_BOUND); + more |= dhd_prot_process_msgbuf_infocpl(bus->dhd, DHD_INFORING_BOUND, + &evtlog_items); bus->last_process_infocpl_time = OSL_LOCALTIME_NS(); } #ifdef EWP_EDL else { - more |= dhd_prot_process_msgbuf_edl(bus->dhd); + more |= dhd_prot_process_msgbuf_edl(bus->dhd, &evtlog_items); bus->last_process_edl_time = OSL_LOCALTIME_NS(); } #endif /* EWP_EDL */ -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE - /* Handle the firmware trace data in the logtrace kernel thread */ - dhd_event_logtrace_enqueue_fwtrace(bus->dhd); -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ - -#ifdef BTLOG - /* Process info ring completion messages */ - more |= dhd_prot_process_msgbuf_btlogcpl(bus->dhd, DHD_BTLOGRING_BOUND); -#endif /* BTLOG */ - #ifdef IDLE_TX_FLOW_MGMT if (bus->enable_idle_flowring_mgmt) { /* Look for idle flow rings */ @@ -13350,49 +13801,28 @@ dhdpci_bus_read_frames(dhd_bus_t *bus) more = FALSE; } -#ifdef SUPPORT_LINKDOWN_RECOVERY - /* XXX : It seems that linkdown is occurred without notification, - * In case read shared memory failed, recovery hang is needed - */ - if (bus->read_shm_fail) { - /* Read interrupt state once again to confirm linkdown */ - int intstatus = si_corereg(bus->sih, bus->sih->buscoreidx, - bus->pcie_mailbox_int, 0, 0); - if (intstatus != (uint32)-1) { - DHD_ERROR(("%s: read SHM failed but intstatus is valid\n", __FUNCTION__)); -#ifdef DHD_FW_COREDUMP - if (bus->dhd->memdump_enabled) { - DHD_OS_WAKE_LOCK(bus->dhd); - bus->dhd->memdump_type = DUMP_TYPE_READ_SHM_FAIL; - dhd_bus_mem_dump(bus->dhd); - DHD_OS_WAKE_UNLOCK(bus->dhd); - } -#endif /* DHD_FW_COREDUMP */ - } else { - DHD_ERROR(("%s: Link is Down.\n", __FUNCTION__)); -#ifdef CONFIG_ARCH_MSM - bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ - bus->is_linkdown = 1; - } - - /* XXX The dhd_prot_debug_info_print() function *has* to be - * invoked only if the bus->is_linkdown is updated so that - * host doesn't need to read any pcie registers if - * PCIe link is down. - */ - dhd_prot_debug_info_print(bus->dhd); - bus->dhd->hang_reason = HANG_REASON_PCIE_LINK_DOWN_EP_DETECT; -#ifdef WL_CFGVENDOR_SEND_HANG_EVENT - copy_hang_info_linkdown(bus->dhd); -#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */ - dhd_os_send_hang_message(bus->dhd); - more = FALSE; - } -#endif /* SUPPORT_LINKDOWN_RECOVERY */ #if defined(DHD_H2D_LOG_TIME_SYNC) dhdpci_bus_rte_log_time_sync_poll(bus); #endif /* DHD_H2D_LOG_TIME_SYNC */ + +#if defined(DHD_WAKE_STATUS) + /* Check if host was woken up by any packets */ + if (dhd_bus_get_bus_wake(bus->dhd) > 0) { + /* + * If wake is due to Rx packets, + * pktwake info will be printed and cleared from dhd_rx_frame() + */ + DHD_ERROR(("#### dhdpcie_host_wake: rxcpl:%d ctrlcpl:%d txcpl:%d evtlog:%d ####\n", + rxcpl_items, ctrlcpl_items, txcpl_items, evtlog_items)); + + dhd_bus_set_get_bus_wake(bus->dhd, 0); + + if (rxcpl_items > 0) { + /* Request packet dump for first Rx packet */ + dhd_bus_set_get_bus_wake_pkt_dump(bus->dhd, 1); + } + } +#endif /* DHD_WAKE_STATUS */ return more; } @@ -13465,7 +13895,7 @@ static int dhdpcie_readshared(dhd_bus_t *bus) { uint32 addr = 0; - int rv, dma_indx_wr_buf, dma_indx_rd_buf; + int dma_indx_wr_buf, dma_indx_rd_buf; uint32 shaddr = 0; pciedev_shared_t *sh = bus->pcie_sh; dhd_timeout_t tmo; @@ -13478,9 +13908,8 @@ dhdpcie_readshared(dhd_bus_t *bus) #endif /* defined(PCIE_INB_DW) */ uint32 timeout = MAX_READ_TIMEOUT; uint32 elapsed; -#ifndef CUSTOMER_HW4_DEBUG uint32 intstatus; -#endif /* OEM_ANDROID */ + int ret = BCME_OK; if (MULTIBP_ENAB(bus->sih)) { dhd_bus_pcie_pwr_req(bus); @@ -13497,36 +13926,46 @@ dhdpcie_readshared(dhd_bus_t *bus) DHD_ERROR(("%s: host timeout in QT/FPGA mode %ld ms\n", __FUNCTION__, (timeout * htclkratio) / USEC_PER_MSEC)); #endif /* BCMSLTGT */ - - /* start a timer for 5 seconds */ - dhd_timeout_start(&tmo, timeout); - - while (((addr == 0) || (addr == bus->nvram_csm)) && !dhd_timeout_expired(&tmo)) { - /* Read last word in memory to determine address of pciedev_shared structure */ - addr = LTOH32(dhdpcie_bus_rtcm32(bus, shaddr)); -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE - /* - * FW might fill all trace buffers even before full DHD/FW initialization. - * poll for trace buffers to avoid circular buffer overflow. - */ - process_fw_trace_data(bus->dhd); -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ +#ifdef GDB_PROXY + if (bus->dhd->gdb_proxy_active) { + /* +3s ASLR delay timeout for case of preattachment debugging */ + timeout += 3 * 1000 * 1000; } +#endif /* GDB_PROXY */ +#ifdef GDB_PROXY + /* Loop while timeout is caused by firmware stop in GDB */ + GDB_PROXY_TIMEOUT_DO(bus->dhd) + { +#endif /* GDB_PROXY */ + /* start a timer for 5 seconds */ + dhd_timeout_start(&tmo, timeout); + + while (((addr == 0) || (addr == bus->nvram_csm)) && !dhd_timeout_expired(&tmo)) { + /* Read last word in memory to determine address of pciedev_shared structure + */ + addr = LTOH32(dhdpcie_bus_rtcm32(bus, shaddr)); + if (addr != bus->nvram_csm) { + DHD_ERROR(("%s: addr=0x%x nvram_csm=0x%x\n", + __FUNCTION__, addr, bus->nvram_csm)); + } + } +#ifdef GDB_PROXY + } + GDB_PROXY_TIMEOUT_WHILE(dhd_timeout_expired(&tmo)) +#endif /* GDB_PROXY */ if (addr == (uint32)-1) { DHD_ERROR(("%s: ##### pciedev shared address is 0xffffffff ####\n", __FUNCTION__)); -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ -#ifdef CUSTOMER_HW4_DEBUG +/* In phones sometimes NOC is seen for any further access after readshared fails */ +#ifdef DHD_NO_DUMP_FOR_READSHARED_FAIL + DHD_ERROR(("%s:### NO dumps will be colelcted and will be marked as linkdown ###\n", + __FUNCTION__)); bus->is_linkdown = 1; - DHD_ERROR(("%s : PCIe link might be down\n", __FUNCTION__)); -#else + ret = BCME_ERROR; + goto done; +#endif /* DHD_NO_DUMP_FOR_READSHARED_FAIL */ + dhd_bus_dump_imp_cfg_registers(bus); dhd_bus_dump_dar_registers(bus); /* Check the PCIe link status by reading intstatus register */ @@ -13537,46 +13976,70 @@ dhdpcie_readshared(dhd_bus_t *bus) bus->is_linkdown = TRUE; } else { #if defined(DHD_FW_COREDUMP) +#ifdef DHD_SSSR_DUMP +#ifdef OEM_ANDROID + DHD_ERROR(("%s : Set collect_sssr and fis_enab as TRUE\n", __FUNCTION__)); + bus->dhd->collect_sssr = TRUE; + fis_enab = TRUE; +#endif /* OEM_ANDROID */ +#endif /* DHD_SSSR_DUMP */ /* save core dump or write to a file */ if (bus->dhd->memdump_enabled) { - /* since dhdpcie_readshared() is invoked only during init or trap */ - bus->dhd->memdump_type = bus->dhd->dongle_trap_data ? - DUMP_TYPE_DONGLE_TRAP : DUMP_TYPE_DONGLE_INIT_FAILURE; + bus->dhd->memdump_type = DUMP_TYPE_READ_SHM_FAIL; dhdpcie_mem_dump(bus); } #endif /* DHD_FW_COREDUMP */ } -#endif /* CUSTOMER_HW4_DEBUG */ - return BCME_ERROR; + ret = BCME_ERROR; + goto done; } if ((addr == 0) || (addr == bus->nvram_csm) || (addr < bus->dongle_ram_base) || (addr > shaddr)) { + uint origidx = si_coreidx(bus->sih); + if (si_setcore(bus->sih, ARMCA7_CORE_ID, 0)) { + uint32 ioctrl = si_wrapperreg(bus->sih, AI_IOCTRL, 0, 0); + uint32 resetctrl = si_wrapperreg(bus->sih, AI_RESETCTRL, 0, 0); + DHD_ERROR(("%s: ca7 ioctrl:0x%x resetctrl:0x%x\n", + __FUNCTION__, ioctrl, resetctrl)); + } else { + DHD_ERROR(("%s: Failed to find CA7 core!\n", __FUNCTION__)); + } + + /* Restore back to original core */ + si_setcoreidx(bus->sih, origidx); + elapsed = tmo.elapsed; #ifdef BCMSLTGT elapsed *= htclkratio; #endif /* BCMSLTGT */ DHD_ERROR(("%s: address (0x%08x) of pciedev_shared invalid\n", __FUNCTION__, addr)); - DHD_ERROR(("%s: Waited %u usec, dongle is not ready\n", __FUNCTION__, tmo.elapsed)); -#ifdef DEBUG_DNGL_INIT_FAIL + DHD_ERROR(("%s: Waited %u usec, dongle is not ready\n", __FUNCTION__, elapsed)); +#ifndef OEM_ANDROID if (addr != (uint32)-1) { /* skip further PCIE reads if read this addr */ -#ifdef CUSTOMER_HW4_DEBUG - bus->dhd->memdump_enabled = DUMP_MEMONLY; -#endif /* CUSTOMER_HW4_DEBUG */ +#ifdef DHD_SSSR_DUMP + if (!bus->dhd->sssr_inited) { + bus->dhd->force_sssr_init = TRUE; + /* Hard code sssr_reg_info for 4389 */ + DHD_SSSR_DUMP_INIT(bus->dhd); + } + bus->dhd->collect_sssr = TRUE; +#endif /* DHD_SSSR_DUMP */ if (bus->dhd->memdump_enabled) { bus->dhd->memdump_type = DUMP_TYPE_DONGLE_INIT_FAILURE; dhdpcie_mem_dump(bus); } } -#endif /* DEBUG_DNGL_INIT_FAIL */ +#endif /* !OEM_ANDROID */ #if defined(NDIS) /* This is a very common code path to catch f/w init failures. Capture a socram dump. */ ASSERT(0); #endif /* defined(NDIS) */ - return BCME_ERROR; + ret = BCME_ERROR; + goto done; } else { bus->rd_shared_pass_time = OSL_LOCALTIME_NS(); elapsed = tmo.elapsed; @@ -13591,14 +14054,11 @@ dhdpcie_readshared(dhd_bus_t *bus) "before dongle is ready\n", __FUNCTION__, addr, elapsed)); } -#ifdef DHD_EFI - bus->dhd->pcie_readshared_done = 1; -#endif /* Read hndrte_shared structure */ - if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, (uint8 *)sh, + if ((ret = dhdpcie_bus_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(pciedev_shared_t))) < 0) { - DHD_ERROR(("%s: Failed to read PCIe shared struct with %d\n", __FUNCTION__, rv)); - return rv; + DHD_ERROR(("%s: Failed to read PCIe shared struct with %d\n", __FUNCTION__, ret)); + goto done; } /* Endianness */ @@ -13629,7 +14089,8 @@ dhdpcie_readshared(dhd_bus_t *bus) "is older than pciedev_shared version %d in dongle\n", __FUNCTION__, PCIE_SHARED_VERSION, bus->api.fw_rev)); - return BCME_ERROR; + ret = BCME_ERROR; + goto done; } dhdpcie_update_bus_api_revisions(bus->api.fw_rev, PCIE_SHARED_VERSION); @@ -13687,6 +14148,7 @@ dhdpcie_readshared(dhd_bus_t *bus) bus->dhd->d2h_sync_mode = sh->flags & PCIE_SHARED_D2H_SYNC_MODE_MASK; bus->dhd->dar_enable = (sh->flags & PCIE_SHARED_DAR) ? TRUE : FALSE; + DHD_ERROR(("FW supports DAR ? %s\n", bus->dhd->dar_enable ? "Y":"N")); /* Does the FW support DMA'ing r/w indices */ if (sh->flags & PCIE_SHARED_DMA_INDEX) { @@ -13703,11 +14165,6 @@ dhdpcie_readshared(dhd_bus_t *bus) } } - if (bus->dhd->dma_d2h_ring_upd_support && bus->dhd->d2h_sync_mode) { - DHD_ERROR(("%s: ERROR COMBO: sync (0x%x) enabled for DMA indices\n", - __FUNCTION__, bus->dhd->d2h_sync_mode)); - } - DHD_INFO(("%s: Host support DMAing indices: H2D:%d - D2H:%d. FW supports it\n", __FUNCTION__, (bus->dhd->dma_h2d_ring_upd_support ? 1 : 0), @@ -13715,7 +14172,8 @@ dhdpcie_readshared(dhd_bus_t *bus) } else if (!(sh->flags & PCIE_SHARED_D2H_SYNC_MODE_MASK)) { DHD_ERROR(("%s FW has to support either dma indices or d2h sync\n", __FUNCTION__)); - return BCME_UNSUPPORTED; + ret = BCME_UNSUPPORTED; + goto done; } else { bus->dhd->dma_h2d_ring_upd_support = FALSE; bus->dhd->dma_d2h_ring_upd_support = FALSE; @@ -13740,12 +14198,14 @@ dhdpcie_readshared(dhd_bus_t *bus) if ((sh->rings_info_ptr < bus->dongle_ram_base) || (sh->rings_info_ptr > shaddr)) { DHD_ERROR(("%s: rings_info_ptr is invalid 0x%x, skip reading ring info\n", __FUNCTION__, sh->rings_info_ptr)); - return BCME_ERROR; + ret = BCME_ERROR; + goto done; } - if ((rv = dhdpcie_bus_membytes(bus, FALSE, sh->rings_info_ptr, - (uint8 *)&ring_info, sizeof(ring_info_t))) < 0) - return rv; + if ((ret = dhdpcie_bus_membytes(bus, FALSE, sh->rings_info_ptr, + (uint8 *)&ring_info, sizeof(ring_info_t))) < 0) { + goto done; + } bus->h2d_mb_data_ptr_addr = ltoh32(sh->h2d_mb_data_ptr); bus->d2h_mb_data_ptr_addr = ltoh32(sh->d2h_mb_data_ptr); @@ -13769,16 +14229,19 @@ dhdpcie_readshared(dhd_bus_t *bus) if (bus->max_completion_rings == 0) { DHD_ERROR(("dongle completion rings are invalid %d\n", bus->max_completion_rings)); - return BCME_ERROR; + ret = BCME_ERROR; + goto done; } if (bus->max_submission_rings == 0) { DHD_ERROR(("dongle submission rings are invalid %d\n", bus->max_submission_rings)); - return BCME_ERROR; + ret = BCME_ERROR; + goto done; } if (bus->max_tx_flowrings == 0) { DHD_ERROR(("dongle txflow rings are invalid %d\n", bus->max_tx_flowrings)); - return BCME_ERROR; + ret = BCME_ERROR; + goto done; } /* If both FW and Host support DMA'ing indices, allocate memory and notify FW @@ -13817,12 +14280,14 @@ dhdpcie_readshared(dhd_bus_t *bus) uint32 bufsz = bus->rw_index_sz * bus->max_completion_rings; if (dhd_prot_dma_indx_copybuf_init(bus->dhd, bufsz, D2H_DMA_INDX_WR_BUF) != BCME_OK) { - return BCME_NOMEM; + ret = BCME_NOMEM; + goto done; } bufsz = bus->rw_index_sz * bus->max_submission_rings; if (dhd_prot_dma_indx_copybuf_init(bus->dhd, bufsz, H2D_DMA_INDX_RD_BUF) != BCME_OK) { - return BCME_NOMEM; + ret = BCME_NOMEM; + goto done; } } #endif /* DHD_DMA_INDICES_SEQNUM */ @@ -13872,23 +14337,10 @@ dhdpcie_readshared(dhd_bus_t *bus) /* add an option to let the user select ?? */ bus->dhd->db7_trap.db7_magic_number = PCIE_DB7_MAGIC_NUMBER_DPC_TRAP; } - -#ifdef BTLOG - bus->dhd->bt_logging = (sh->flags2 & PCIE_SHARED2_BT_LOGGING) ? TRUE : FALSE; - /* XXX: WAR is needed for dongle with BTLOG to be backwards compatible with existing DHD. - * The issue is that existing DHD doesn't not compute the INFO cmpl ringid correctly once - * BTLOG dongle increases the max_submission_rings resulting in overwritting ring in the - * dongle. When dongle enables submit_count_WAR, it implies that the sumbit ring has be - * incremented in the dongle but will not be reflected in max_submission_rings. - */ - bus->dhd->submit_count_WAR = (sh->flags2 & PCIE_SHARED2_SUBMIT_COUNT_WAR) ? TRUE : FALSE; - DHD_ERROR(("FW supports BT logging ? %s \n", bus->dhd->bt_logging ? "Y" : "N")); -#endif /* BTLOG */ - -#ifdef SNAPSHOT_UPLOAD - bus->dhd->snapshot_upload = (sh->flags2 & PCIE_SHARED2_SNAPSHOT_UPLOAD) ? TRUE : FALSE; - DHD_ERROR(("FW supports snapshot upload ? %s \n", bus->dhd->snapshot_upload ? "Y" : "N")); -#endif /* SNAPSHOT_UPLOAD */ + if (sh->flags2 & PCIE_SHARED2_LPM_SUPPORT) { + bus->dhd->fw_lpm_support = TRUE; + DHD_ERROR(("FW supports LPM mode\n")); + } #ifdef D2H_MINIDUMP bus->d2h_minidump = (sh->flags2 & PCIE_SHARED2_FW_SMALL_MEMDUMP) ? TRUE : FALSE; @@ -13912,38 +14364,17 @@ dhdpcie_readshared(dhd_bus_t *bus) bus->dhd->debug_buf_dest_support = (sh->flags2 & PCIE_SHARED2_DEBUG_BUF_DEST) ? TRUE : FALSE; - DHD_ERROR(("FW supports debug buf dest ? %s \n", + DHD_ERROR_MEM(("FW supports debug buf dest ? %s \n", bus->dhd->debug_buf_dest_support ? "Y" : "N")); -#ifdef DHD_HP2P - if (bus->dhd->hp2p_enable) { - bus->dhd->hp2p_ts_capable = - (sh->flags2 & PCIE_SHARED2_PKT_TIMESTAMP) == PCIE_SHARED2_PKT_TIMESTAMP; - bus->dhd->hp2p_capable = - (sh->flags2 & PCIE_SHARED2_HP2P) == PCIE_SHARED2_HP2P; - bus->dhd->hp2p_capable |= bus->dhd->hp2p_ts_capable; + bus->dhd->rx_cpl_lat_capable = + (sh->flags2 & PCIE_SHARED2_RX_CMPL_PRIO_VALID) ? TRUE : FALSE; - DHD_ERROR(("FW supports HP2P ? %s\n", - bus->dhd->hp2p_capable ? "Y" : "N")); + bus->dhd->mdring_capable = + (sh->flags2 & PCIE_SHARED2_METADATA_RING) ? TRUE : FALSE; - if (bus->dhd->hp2p_capable) { - bus->dhd->pkt_thresh = HP2P_PKT_THRESH; - bus->dhd->pkt_expiry = HP2P_PKT_EXPIRY; - bus->dhd->time_thresh = HP2P_TIME_THRESH; - for (addr = 0; addr < MAX_HP2P_FLOWS; addr++) { - hp2p_info_t *hp2p_info = &bus->dhd->hp2p_info[addr]; - hp2p_info->hrtimer_init = FALSE; - hrtimer_init(&hp2p_info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - hp2p_info->timer.function = &dhd_hp2p_write; - } - } - } -#endif /* DHD_HP2P */ - -#ifdef DHD_DB0TS - bus->dhd->db0ts_capable = - (sh->flags & PCIE_SHARED_TIMESTAMP_DB0) == PCIE_SHARED_TIMESTAMP_DB0; -#endif /* DHD_DB0TS */ + DHD_ERROR(("FW supports MD ring ? %s\n", + bus->dhd->mdring_capable ? "Y" : "N")); if (MULTIBP_ENAB(bus->sih)) { dhd_bus_pcie_pwr_req_clear(bus); @@ -13957,7 +14388,37 @@ dhdpcie_readshared(dhd_bus_t *bus) DAR_PCIE_PWR_CTRL((bus->sih)->buscorerev), FALSE); } } - return BCME_OK; +done: +#if defined(FW_SIGNATURE) + if ((ret == BCME_ERROR) && (bus->fwsig_filename[0] != 0)) { + bl_verif_status_t status; + + (void)dhdpcie_read_fwstatus(bus, &status); + DHD_ERROR(("Verification status: (%08x)\n" + "\tstatus: %d\n" + "\tstate: %u\n" + "\talloc_bytes: %u\n" + "\tmax_alloc_bytes: %u\n" + "\ttotal_alloc_bytes: %u\n" + "\ttotal_freed_bytes: %u\n" + "\tnum_allocs: %u\n" + "\tmax_allocs: %u\n" + "\tmax_alloc_size: %u\n" + "\talloc_failures: %u\n", + bus->fwstat_download_addr, + status.status, + status.state, + status.alloc_bytes, + status.max_alloc_bytes, + status.total_alloc_bytes, + status.total_freed_bytes, + status.num_allocs, + status.max_allocs, + status.max_alloc_size, + status.alloc_failures)); + } +#endif /* FW_SIGNATURE */ + return ret; } /* dhdpcie_readshared */ /** Read ring mem and ring state ptr info from shared memory area in device memory */ @@ -14047,18 +14508,6 @@ dhd_fillup_ring_sharedptr_info(dhd_bus_t *bus, ring_info_t *ring_info) bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r)); } -#ifdef DHD_HP2P - /* store wr/rd pointers for debug info completion or EDL ring and hp2p rings */ - for (j = 0; j <= MAX_HP2P_CMPL_RINGS; i++, j++) { - bus->ring_sh[i].ring_state_w = d2h_w_idx_ptr; - bus->ring_sh[i].ring_state_r = d2h_r_idx_ptr; - d2h_w_idx_ptr = d2h_w_idx_ptr + bus->rw_index_sz; - d2h_r_idx_ptr = d2h_r_idx_ptr + bus->rw_index_sz; - DHD_INFO(("d2h w/r : idx %d write %x read %x \n", i, - bus->ring_sh[i].ring_state_w, - bus->ring_sh[i].ring_state_r)); - } -#else /* store wr/rd pointers for debug info completion or EDL ring */ bus->ring_sh[i].ring_state_w = d2h_w_idx_ptr; bus->ring_sh[i].ring_state_r = d2h_r_idx_ptr; @@ -14067,7 +14516,6 @@ dhd_fillup_ring_sharedptr_info(dhd_bus_t *bus, ring_info_t *ring_info) DHD_INFO(("d2h w/r : idx %d write %x read %x \n", i, bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r)); -#endif /* DHD_HP2P */ } } /* dhd_fillup_ring_sharedptr_info */ @@ -14086,8 +14534,12 @@ int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) if (!bus->dhd) return 0; + bus->link_state = DHD_PCIE_ALL_GOOD; + dhd_bus_pcie_pwr_req_clear_reload_war(bus); + dhd_init_dpc_histos(bus->dhd); + if (MULTIBP_ENAB(bus->sih)) { dhd_bus_pcie_pwr_req(bus); } @@ -14132,14 +14584,7 @@ int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) /* XXX These need to change w/API updates */ /* bcmsdh_intr_unmask(bus->sdh); */ -#ifdef DHD_PCIE_RUNTIMEPM - bus->idlecount = 0; - bus->idletime = (int32)MAX_IDLE_COUNT; - init_waitqueue_head(&bus->rpm_queue); - mutex_init(&bus->pm_lock); -#else bus->idletime = 0; -#endif /* DHD_PCIE_RUNTIMEPM */ #ifdef PCIE_INB_DW bus->skip_ds_ack = FALSE; /* Initialize the lock to serialize Device Wake Inband activities */ @@ -14156,9 +14601,18 @@ int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) } else { bus->use_d0_inform = FALSE; } + bus->lpm_mode = FALSE; + bus->lpm_mem_kill = FALSE; bus->hostready_count = 0; + bus->host_irq_enable_count = 0; + bus->host_irq_disable_count = 0; + bus->dngl_intmask_disable_count = 0; + bus->dngl_intmask_enable_count = 0; + if (dhdp->rx_cpl_lat_capable) { + bzero(&dhdp->rxcpl_lat_info, sizeof(rx_cpl_lat_info_t)); + } exit: if (MULTIBP_ENAB(bus->sih)) { dhd_bus_pcie_pwr_req_clear(bus); @@ -14172,9 +14626,6 @@ dhdpcie_init_shared_addr(dhd_bus_t *bus) uint32 addr = 0; uint32 val = 0; addr = bus->dongle_ram_base + bus->ramsize - 4; -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(bus->dhd, TRUE, __builtin_return_address(0)); -#endif /* DHD_PCIE_RUNTIMEPM */ dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val)); } @@ -14182,10 +14633,8 @@ bool dhdpcie_chipmatch(uint16 vendor, uint16 device) { if (vendor != PCI_VENDOR_ID_BROADCOM) { -#ifndef DHD_EFI DHD_ERROR(("%s: Unsupported vendor %x device %x\n", __FUNCTION__, vendor, device)); -#endif /* DHD_EFI */ return (-ENODEV); } @@ -14301,6 +14750,14 @@ dhdpcie_chipmatch(uint16 vendor, uint16 device) case BCM43752_D11AX2G_ID: case BCM43752_D11AX5G_ID: case BCM43752_CHIP_ID: + case BCM43756_D11AX_ID: + case BCM43756_CHIP_ID: + case BCM43711_CHIP_ID: + case BCM43711_D11AX_ID: + case BCM4381_CHIP_ID: + case BCM4381_D11AX_ID: + case BCM4382_CHIP_ID: + case BCM4382_D11AX_ID: case BCM4388_CHIP_ID: case BCM4388_D11AX_ID: case BCM4389_CHIP_ID: @@ -14308,16 +14765,10 @@ dhdpcie_chipmatch(uint16 vendor, uint16 device) case BCM4385_D11AX_ID: case BCM4385_CHIP_ID: -#ifdef UNRELEASEDCHIP - case BCM4397_CHIP_ID: - case BCM4397_D11AX_ID: -#endif return 0; default: -#ifndef DHD_EFI DHD_ERROR(("%s: Unsupported vendor %x device %x\n", __FUNCTION__, vendor, device)); -#endif return (-ENODEV); } } /* dhdpcie_chipmatch */ @@ -14365,8 +14816,7 @@ dhdpcie_cc_nvmshadow(dhd_bus_t *bus, struct bcmstrbuf *b) if (((uint16)bus->sih->chip != BCM4350_CHIP_ID) && !BCM4345_CHIP((uint16)bus->sih->chip) && ((uint16)bus->sih->chip != BCM4355_CHIP_ID) && ((uint16)bus->sih->chip != BCM4364_CHIP_ID)) { - DHD_ERROR(("%s: cc_nvmdump cmd. supported for Olympic chips" - "4350/4345/4355/4364 only\n", __FUNCTION__)); + DHD_ERROR(("%s: cc_nvmdump not supported\n", __FUNCTION__)); return BCME_UNSUPPORTED; } @@ -14525,15 +14975,6 @@ void dhd_bus_clean_flow_ring(dhd_bus_t *bus, void *node) dhd_tcpack_info_tbl_clean(bus->dhd); #endif /* DHDTCPACK_SUPPRESS */ -#ifdef DHD_HP2P - if (flow_ring_node->hp2p_ring) { - if (!bus->dhd->hp2p_ring_more) { - bus->dhd->hp2p_ring_more = TRUE; - } - flow_ring_node->hp2p_ring = FALSE; - } -#endif /* DHD_HP2P */ - /* clean up BUS level info */ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); @@ -14574,7 +15015,7 @@ dhd_bus_flow_ring_create_request(dhd_bus_t *bus, void *arg) { flow_ring_node_t *flow_ring_node = (flow_ring_node_t *)arg; - DHD_PCIE_INFO(("%s :Flow create\n", __FUNCTION__)); + DHD_INFO(("%s :Flow create\n", __FUNCTION__)); /* Send Msg to device about flow ring creation */ if (dhd_prot_flow_ring_create(bus->dhd, flow_ring_node) != BCME_OK) @@ -14590,7 +15031,7 @@ dhd_bus_flow_ring_create_response(dhd_bus_t *bus, uint16 flowid, int32 status) flow_ring_node_t *flow_ring_node; unsigned long flags; - DHD_PCIE_INFO(("%s :Flow Response %d \n", __FUNCTION__, flowid)); + DHD_INFO(("%s :Flow Response %d \n", __FUNCTION__, flowid)); /* Boundary check of the flowid */ if (flowid > bus->dhd->max_tx_flowid) { @@ -14645,7 +15086,7 @@ dhd_bus_flow_ring_create_response(dhd_bus_t *bus, uint16 flowid, int32 status) dll_prepend(&bus->flowring_active_list, &flow_ring_node->list); DHD_FLOWRING_LIST_UNLOCK(bus->dhd->flowring_list_lock, flags); - dhd_bus_schedule_queue(bus, flowid, FALSE); /* from queue to flowring */ + dhd_bus_schedule_queue(bus, flowid, FALSE, 0, NULL); /* from queue to flowring */ return; } @@ -14658,7 +15099,7 @@ dhd_bus_flow_ring_delete_request(dhd_bus_t *bus, void *arg) flow_ring_node_t *flow_ring_node; unsigned long flags; - DHD_PCIE_INFO(("%s :Flow Delete\n", __FUNCTION__)); + DHD_INFO(("%s :Flow Delete\n", __FUNCTION__)); flow_ring_node = (flow_ring_node_t *)arg; @@ -14697,7 +15138,7 @@ dhd_bus_flow_ring_delete_response(dhd_bus_t *bus, uint16 flowid, uint32 status) { flow_ring_node_t *flow_ring_node; - DHD_PCIE_INFO(("%s :Flow Delete Response %d \n", __FUNCTION__, flowid)); + DHD_INFO(("%s :Flow Delete Response %d \n", __FUNCTION__, flowid)); /* Boundary check of the flowid */ if (flowid > bus->dhd->max_tx_flowid) { @@ -14739,7 +15180,7 @@ int dhd_bus_flow_ring_flush_request(dhd_bus_t *bus, void *arg) flow_ring_node_t *flow_ring_node; unsigned long flags; - DHD_PCIE_INFO(("%s :Flow Flush\n", __FUNCTION__)); + DHD_INFO(("%s :Flow Flush\n", __FUNCTION__)); flow_ring_node = (flow_ring_node_t *)arg; @@ -14838,6 +15279,12 @@ dhd_bus_get_cto(dhd_pub_t *dhdp) return dhdp->bus->cto_triggered; } +bool +dhd_bus_get_read_shm(dhd_pub_t *dhdp) +{ + return FALSE; +} + #ifdef IDLE_TX_FLOW_MGMT /* resume request */ int @@ -14878,7 +15325,7 @@ dhd_bus_flow_ring_resume_response(dhd_bus_t *bus, uint16 flowid, int32 status) flow_ring_node->status = FLOW_RING_STATUS_OPEN; - dhd_bus_schedule_queue(bus, flowid, FALSE); + dhd_bus_schedule_queue(bus, flowid, FALSE, 0, NULL); return; } @@ -15079,7 +15526,7 @@ dhd_bus_release_dongle(struct dhd_bus *bus) ASSERT(osh); if (bus->dhd) { -#if defined(DEBUGGER) || defined (DHD_DSCOPE) +#if defined(DEBUGGER) || defined(DHD_DSCOPE) debugger_close(); #endif /* DEBUGGER || DHD_DSCOPE */ @@ -15120,7 +15567,8 @@ dhdpcie_cto_init(struct dhd_bus *bus, bool enable) if (bus->cto_threshold == 0) { if ((chipid == BCM4387_CHIP_ID) || (chipid == BCM4388_CHIP_ID) || - (chipid == BCM4389_CHIP_ID)) { + (chipid == BCM4389_CHIP_ID) || + (chipid == BCM4397_CHIP_ID)) { bus->cto_threshold = PCIE_CTO_TO_THRESH_DEFAULT_REV69; } else { bus->cto_threshold = PCIE_CTO_TO_THRESH_DEFAULT; @@ -15315,13 +15763,6 @@ void dhd_bus_flow_ring_cnt_update(dhd_bus_t *bus, uint16 flowid, uint32 txstatus) { flow_ring_node_t *flow_ring_node; -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) - dhd_awdl_stats_t *awdl_stats; - if_flow_lkup_t *if_flow_lkup; - unsigned long flags; - uint8 ifindex; - uint8 role; -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ /* If we have d2h sync enabled due to marker overloading, we cannot update this. */ if (bus->dhd->d2h_sync_mode) return; @@ -15338,17 +15779,6 @@ dhd_bus_flow_ring_cnt_update(dhd_bus_t *bus, uint16 flowid, uint32 txstatus) flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); ASSERT(flow_ring_node->flowid == flowid); flow_ring_node->flow_info.tx_status[txstatus]++; -#if defined(DHD_AWDL) && defined(AWDL_SLOT_STATS) - if_flow_lkup = (if_flow_lkup_t *)bus->dhd->if_flow_lkup; - ifindex = flow_ring_node->flow_info.ifindex; - role = if_flow_lkup[ifindex].role; - if (role == WLC_E_IF_ROLE_AWDL) { - DHD_AWDL_STATS_LOCK(bus->dhd->awdl_stats_lock, flags); - awdl_stats = &bus->dhd->awdl_stats[bus->dhd->awdl_tx_status_slot]; - awdl_stats->tx_status[txstatus]++; - DHD_AWDL_STATS_UNLOCK(bus->dhd->awdl_stats_lock, flags); - } -#endif /* DHD_AWDL && AWDL_SLOT_STATS */ return; } #endif /* BCMDBG */ @@ -15413,20 +15843,6 @@ dhdpcie_bus_get_pcie_dar_supported(dhd_bus_t *bus) } } -#ifdef DHD_HP2P -bool -dhdpcie_bus_get_hp2p_supported(dhd_bus_t *bus) -{ - if (!bus->dhd) { - return FALSE; - } else if (bus->dhd->hp2p_enable) { - return bus->dhd->hp2p_capable; - } else { - return FALSE; - } -} -#endif /* DHD_HP2P */ - #ifdef PCIE_OOB bool dhdpcie_bus_get_pcie_oob_dw_supported(dhd_bus_t *bus) @@ -15467,7 +15883,7 @@ dhdpcie_bus_set_pcie_inband_dw_state(dhd_bus_t *bus, enum dhd_bus_ds_state state if (!INBAND_DW_ENAB(bus)) return; - DHD_PCIE_INFO(("%s:%d\n", __FUNCTION__, state)); + DHD_INFO(("%s:%d\n", __FUNCTION__, state)); bus->dhd->ds_state = state; if (state == DW_DEVICE_DS_DISABLED_WAIT || state == DW_DEVICE_DS_D3_INFORM_WAIT) { bus->ds_exit_timeout = 100; @@ -15949,7 +16365,7 @@ dhdpcie_get_etd_preserve_logs(dhd_pub_t *dhd, /* boundary check */ baseaddr = etd_evtlog->log_arr_addr; - if ((baseaddr < dhd->bus->dongle_ram_base) || + if ((baseaddr < dhd->bus->dongle_ram_base) || (baseaddr > endaddr) || ((baseaddr + arr_size) > endaddr)) { DHD_ERROR(("%s: Error reading invalid address\n", __FUNCTION__)); @@ -15974,7 +16390,7 @@ dhdpcie_get_etd_preserve_logs(dhd_pub_t *dhd, for (i = 0; i < (etd_evtlog->num_elements); ++i) { /* boundary check */ baseaddr = evtlog_buf_arr[i].buf_addr; - if ((baseaddr < dhd->bus->dongle_ram_base) || + if ((baseaddr < dhd->bus->dongle_ram_base) || (baseaddr > endaddr) || ((baseaddr + evtlog_buf_arr[i].len) > endaddr)) { DHD_ERROR(("%s: Error reading invalid address\n", __FUNCTION__)); @@ -16635,6 +17051,55 @@ dhdpcie_sssr_dump_get_after_sr(dhd_pub_t *dhd) return BCME_OK; } +#define GCI_CHIPSTATUS_AUX GCI_CHIPSTATUS_10 +#define GCI_CHIPSTATUS_MAIN GCI_CHIPSTATUS_11 +#define GCI_CHIPSTATUS_DIG GCI_CHIPSTATUS_12 +#define GCI_CHIPSTATUS_SCAN GCI_CHIPSTATUS_13 + +#define GCI_CHIPSTATUS_ILLEGAL_INSTR_BITMASK (1u << 3) +int +dhdpcie_validate_gci_chip_intstatus(dhd_pub_t *dhd) +{ + int gci_intstatus; + si_t *sih = dhd->bus->sih; + + /* For now validate only for 4389 chip */ + if (si_chipid(sih) != BCM4389_CHIP_ID) { + DHD_ERROR(("%s: skipping for chipid:0x%x\n", __FUNCTION__, si_chipid(sih))); + return BCME_OK; + } + + gci_intstatus = si_gci_chipstatus(sih, GCI_CHIPSTATUS_MAIN); + if (gci_intstatus & GCI_CHIPSTATUS_ILLEGAL_INSTR_BITMASK) { + DHD_ERROR(("%s: Illegal instruction set for MAIN core 0x%x\n", + __FUNCTION__, gci_intstatus)); + return BCME_ERROR; + } + + gci_intstatus = si_gci_chipstatus(sih, GCI_CHIPSTATUS_AUX); + if (gci_intstatus & GCI_CHIPSTATUS_ILLEGAL_INSTR_BITMASK) { + DHD_ERROR(("%s: Illegal instruction set for AUX core 0x%x\n", + __FUNCTION__, gci_intstatus)); + return BCME_ERROR; + } + + gci_intstatus = si_gci_chipstatus(sih, GCI_CHIPSTATUS_SCAN); + if (gci_intstatus & GCI_CHIPSTATUS_ILLEGAL_INSTR_BITMASK) { + DHD_ERROR(("%s: Illegal instruction set for SCAN core 0x%x\n", + __FUNCTION__, gci_intstatus)); + return BCME_ERROR; + } + + gci_intstatus = si_gci_chipstatus(sih, GCI_CHIPSTATUS_DIG); + if (gci_intstatus & GCI_CHIPSTATUS_ILLEGAL_INSTR_BITMASK) { + DHD_ERROR(("%s: Illegal instruction set for DIG core 0x%x\n", + __FUNCTION__, gci_intstatus)); + return BCME_ERROR; + } + + return BCME_OK; +} + int dhdpcie_sssr_dump(dhd_pub_t *dhd) { @@ -16650,6 +17115,16 @@ dhdpcie_sssr_dump(dhd_pub_t *dhd) return BCME_ERROR; } + if (dhd->bus->cto_triggered) { + DHD_ERROR(("%s: CTO Triggered\n", __FUNCTION__)); + return BCME_ERROR; + } + + if (dhdpcie_validate_gci_chip_intstatus(dhd) != BCME_OK) { + DHD_ERROR(("%s: ## Invalid GCI Chip intstatus, Abort SSSR ##\n", + __FUNCTION__)); + return BCME_ERROR; + } DHD_ERROR(("%s: Before WL down (powerctl: pcie:0x%x chipc:0x%x) " "PMU rctl:0x%x res_state:0x%x\n", __FUNCTION__, si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, @@ -16722,7 +17197,7 @@ dhdpcie_sssr_dump(dhd_pub_t *dhd) static int dhdpcie_fis_trigger(dhd_pub_t *dhd) { - uint32 fis_ctrl_status; + uint32 fis_ctrl_status, fis_min_res_mask; uint32 cfg_status_cmd; uint32 cfg_pmcsr; @@ -16736,22 +17211,19 @@ dhdpcie_fis_trigger(dhd_pub_t *dhd) return BCME_ERROR; } -#ifdef DHD_PCIE_RUNTIMEPM - /* Bring back to D0 */ - dhdpcie_runtime_bus_wake(dhd, CAN_SLEEP(), __builtin_return_address(0)); - /* Stop RPM timer so that even INB DW DEASSERT should not happen */ - DHD_STOP_RPM_TIMER(dhd); -#endif /* DHD_PCIE_RUNTIMEPM */ - /* Set fis_triggered flag to ignore link down callback from RC */ dhd->fis_triggered = TRUE; + /* set fis_min_res_mask to 0x1 */ + PMU_REG(dhd->bus->sih, fis_min_res_mask, ~0, 0x1); + /* Set FIS PwrswForceOnAll */ PMU_REG(dhd->bus->sih, fis_ctrl_status, PMU_FIS_FORCEON_ALL_MASK, PMU_FIS_FORCEON_ALL_MASK); fis_ctrl_status = PMU_REG(dhd->bus->sih, fis_ctrl_status, 0, 0); - - DHD_ERROR(("%s: fis_ctrl_status=0x%x\n", __FUNCTION__, fis_ctrl_status)); + fis_min_res_mask = PMU_REG(dhd->bus->sih, fis_min_res_mask, 0, 0); + DHD_ERROR(("%s: fis_ctrl_status=0x%x fis_min_res_mask=0x%x\n", + __FUNCTION__, fis_ctrl_status, fis_min_res_mask)); cfg_status_cmd = dhd_pcie_config_read(dhd->bus, PCIECFGREG_STATUS_CMD, sizeof(uint32)); cfg_pmcsr = dhd_pcie_config_read(dhd->bus, PCIE_CFG_PMCSR, sizeof(uint32)); @@ -16886,6 +17358,8 @@ dhdpcie_fis_dump(dhd_pub_t *dhd) { int i; uint8 num_d11cores; + struct dhd_bus *bus = dhd->bus; + uint32 save_idx = 0; DHD_ERROR(("%s\n", __FUNCTION__)); @@ -16923,6 +17397,16 @@ dhdpcie_fis_dump(dhd_pub_t *dhd) dhdpcie_d11_check_outofreset(dhd); + /* take sysmem out of reset - otherwise + * socram collected again will read only + * 0xffff + */ + save_idx = si_coreidx(bus->sih); + if (si_setcore(bus->sih, SYSMEM_CORE_ID, 0)) { + si_core_reset(bus->sih, 0, 0); + si_setcoreidx(bus->sih, save_idx); + } + DHD_ERROR(("%s: Collecting Dump after SR\n", __FUNCTION__)); if (dhdpcie_sssr_dump_get_after_sr(dhd) != BCME_OK) { DHD_ERROR(("%s: dhdpcie_sssr_dump_get_after_sr failed\n", __FUNCTION__)); @@ -16931,6 +17415,14 @@ dhdpcie_fis_dump(dhd_pub_t *dhd) dhd->sssr_dump_collected = TRUE; dhd_write_sssr_dump(dhd, SSSR_DUMP_MODE_FIS); + if (dhd->bus->link_state != DHD_PCIE_ALL_GOOD) { + /* reset link state and collect socram */ + dhd->bus->link_state = DHD_PCIE_ALL_GOOD; + DHD_ERROR(("%s: recollect socram\n", __FUNCTION__)); + /* re-read socram into buffer */ + dhdpcie_get_mem_dump(bus); + } + return BCME_OK; } @@ -16971,14 +17463,6 @@ dhd_bus_get_sdtc_etb(dhd_pub_t *dhd, uint8 *sdtc_etb_mempool, uint addr, uint re } #endif /* DHD_SDTC_ETB_DUMP */ -#ifdef BTLOG -void -BCMFASTPATH(dhd_bus_rx_bt_log)(struct dhd_bus *bus, void* pkt) -{ - dhd_rx_bt_log(bus->dhd, pkt); -} -#endif /* BTLOG */ - #ifdef DHD_WAKE_STATUS wake_counts_t* dhd_bus_get_wakecount(dhd_pub_t *dhd) @@ -16988,7 +17472,18 @@ dhd_bus_get_wakecount(dhd_pub_t *dhd) int dhd_bus_get_bus_wake(dhd_pub_t *dhd) { - return bcmpcie_set_get_wake(dhd->bus, 0); + return bcmpcie_get_wake(dhd->bus); +} +int +dhd_bus_set_get_bus_wake(dhd_pub_t *dhd, int set) +{ + return bcmpcie_set_get_wake(dhd->bus, set); +} + +int +dhd_bus_set_get_bus_wake_pkt_dump(dhd_pub_t *dhd, int wake_pkt_dump) +{ + return bcmpcie_set_get_wake_pkt_dump(dhd->bus, wake_pkt_dump); } #endif /* DHD_WAKE_STATUS */ @@ -16998,55 +17493,16 @@ dhd_bus_get_bus_wake(dhd_pub_t *dhd) static int dhdpcie_wrt_rnd(struct dhd_bus *bus) { - bcm_rand_metadata_t rnd_data; uint8 rand_buf[BCM_ENTROPY_HOST_NBYTES]; - uint32 count = BCM_ENTROPY_HOST_NBYTES; - int ret = 0; - uint32 addr = bus->dongle_ram_base + (bus->ramsize - BCM_NVRAM_OFFSET_TCM) - - ((bus->nvram_csm & 0xffff)* BCM_NVRAM_IMG_COMPRS_FACTOR + sizeof(rnd_data)); - - memset(rand_buf, 0, BCM_ENTROPY_HOST_NBYTES); - rnd_data.signature = htol32(BCM_NVRAM_RNG_SIGNATURE); - rnd_data.count = htol32(count); - /* write the metadata about random number */ - dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&rnd_data, sizeof(rnd_data)); - /* scale back by number of random number counts */ - addr -= count; - - bus->ramtop_addr = addr; - -#ifdef DHD_RND_DEBUG - bus->dhd->rnd_buf = NULL; - /* get random contents from file */ - ret = dhd_get_rnd_info(bus->dhd); - if (bus->dhd->rnd_buf) { - /* write file contents to TCM */ - DHD_ERROR(("%s: use stored .rnd.in content\n", __FUNCTION__)); - dhdpcie_bus_membytes(bus, TRUE, addr, bus->dhd->rnd_buf, bus->dhd->rnd_len); - - /* Dump random content to out file */ - dhd_dump_rnd_info(bus->dhd, bus->dhd->rnd_buf, bus->dhd->rnd_len); - - /* bus->dhd->rnd_buf is allocated in dhd_get_rnd_info, free here */ - MFREE(bus->dhd->osh, bus->dhd->rnd_buf, bus->dhd->rnd_len); - bus->dhd->rnd_buf = NULL; - return BCME_OK; - } -#endif /* DHD_RND_DEBUG */ + int ret = BCME_OK; + memset(rand_buf, 0, sizeof(rand_buf)); /* Now write the random number(s) */ - ret = dhd_get_random_bytes(rand_buf, count); + ret = dhd_get_random_bytes(rand_buf, sizeof(rand_buf)); if (ret != BCME_OK) { return ret; } - dhdpcie_bus_membytes(bus, TRUE, addr, rand_buf, count); - -#ifdef DHD_RND_DEBUG - /* Dump random content to out file */ - dhd_dump_rnd_info(bus->dhd, rand_buf, count); -#endif /* DHD_RND_DEBUG */ - - bus->next_tlv = addr; + dhdpcie_download_rtlv(bus, DNGL_RTLV_TYPE_RNG_SIGNATURE, sizeof(rand_buf), rand_buf); return BCME_OK; } @@ -17066,10 +17522,10 @@ dhd_pcie_intr_count_dump(dhd_pub_t *dhd) uint64 current_time; DHD_ERROR(("\n ------- DUMPING INTR enable/disable counters ------- \r\n")); - DHD_ERROR(("resume_intr_enable_count=%lu dpc_intr_enable_count=%lu\n", - bus->resume_intr_enable_count, bus->dpc_intr_enable_count)); - DHD_ERROR(("isr_intr_disable_count=%lu suspend_intr_disable_count=%lu\n", - bus->isr_intr_disable_count, bus->suspend_intr_disable_count)); + DHD_ERROR(("dngl_intmask_enable_count=%lu host_irq_enable_count=%lu\n", + bus->dngl_intmask_enable_count, bus->host_irq_enable_count)); + DHD_ERROR(("host_irq_disable_count=%lu dngl_intmask_disable_count=%lu\n", + bus->host_irq_disable_count, bus->dngl_intmask_disable_count)); #ifdef BCMPCIE_OOB_HOST_WAKE DHD_ERROR(("oob_intr_count=%lu oob_intr_enable_count=%lu oob_intr_disable_count=%lu\n", bus->oob_intr_count, bus->oob_intr_enable_count, @@ -17085,6 +17541,10 @@ dhd_pcie_intr_count_dump(dhd_pub_t *dhd) DHD_ERROR(("oob_irq_enabled=%d oob_gpio_level=%d\n", dhdpcie_get_oob_irq_status(bus), dhdpcie_get_oob_irq_level())); + +#if defined(__linux__) + dhd_plat_pin_dbg_show(bus->dhd->plat_info); +#endif /* __linux__ */ #endif /* BCMPCIE_OOB_HOST_WAKE */ DHD_ERROR(("dpc_return_busdown_count=%lu non_ours_irq_count=%lu\n", bus->dpc_return_busdown_count, bus->non_ours_irq_count)); @@ -17093,9 +17553,11 @@ dhd_pcie_intr_count_dump(dhd_pub_t *dhd) DHD_ERROR(("\ncurrent_time="SEC_USEC_FMT"\n", GET_SEC_USEC(current_time))); DHD_ERROR(("isr_entry_time="SEC_USEC_FMT - " isr_exit_time="SEC_USEC_FMT"\n", + " prev_isr_entry_time="SEC_USEC_FMT + " isr_exit_time="SEC_USEC_FMT" dpc_sched=%u\n", GET_SEC_USEC(bus->isr_entry_time), - GET_SEC_USEC(bus->isr_exit_time))); + GET_SEC_USEC(bus->prev_isr_entry_time), + GET_SEC_USEC(bus->isr_exit_time), bus->dpc_sched)); DHD_ERROR(("isr_sched_dpc_time="SEC_USEC_FMT " rpm_sched_dpc_time="SEC_USEC_FMT " last_non_ours_irq_time="SEC_USEC_FMT"\n", @@ -17181,6 +17643,8 @@ dhd_pcie_dump_wrapper_regs(dhd_pub_t *dhd) } } + dhd_dump_pcie_slave_wrapper_regs(dhd->bus); + if ((cr4regs = si_setcore(sih, ARMCR4_CORE_ID, 0)) != NULL) { DHD_ERROR(("%s: ARM CR4 wrapper Reg\n", __FUNCTION__)); for (i = 0; i < (uint32)sizeof(wrapper_dump_list) / 4; i++) { @@ -17216,24 +17680,6 @@ dhd_pcie_dump_wrapper_regs(dhd_pub_t *dhd) } /* XXX: Currently dumping CA7 registers causing CTO, temporarily disabling it */ BCM_REFERENCE(ca7regs); -#ifdef NOT_YET - if ((ca7regs = si_setcore(sih, ARMCA7_CORE_ID, 0)) != NULL) { - DHD_ERROR(("%s: ARM CA7 core Reg\n", __FUNCTION__)); - val = R_REG(dhd->osh, ARM_CA7_REG(ca7regs, corecontrol)); - DHD_ERROR(("reg:0x%x val:0x%x\n", (uint)OFFSETOF(ca7regs_t, corecontrol), val)); - val = R_REG(dhd->osh, ARM_CA7_REG(ca7regs, corecapabilities)); - DHD_ERROR(("reg:0x%x val:0x%x\n", - (uint)OFFSETOF(ca7regs_t, corecapabilities), val)); - val = R_REG(dhd->osh, ARM_CA7_REG(ca7regs, corestatus)); - DHD_ERROR(("reg:0x%x val:0x%x\n", (uint)OFFSETOF(ca7regs_t, corestatus), val)); - val = R_REG(dhd->osh, ARM_CA7_REG(ca7regs, tracecontrol)); - DHD_ERROR(("reg:0x%x val:0x%x\n", (uint)OFFSETOF(ca7regs_t, tracecontrol), val)); - val = R_REG(dhd->osh, ARM_CA7_REG(ca7regs, clk_ctl_st)); - DHD_ERROR(("reg:0x%x val:0x%x\n", (uint)OFFSETOF(ca7regs_t, clk_ctl_st), val)); - val = R_REG(dhd->osh, ARM_CA7_REG(ca7regs, powerctl)); - DHD_ERROR(("reg:0x%x val:0x%x\n", (uint)OFFSETOF(ca7regs_t, powerctl), val)); - } -#endif /* NOT_YET */ DHD_ERROR(("%s: OOBR Reg\n", __FUNCTION__)); @@ -17412,79 +17858,6 @@ dhd_pcie_dump_rc_conf_space_cap(dhd_pub_t *dhd) #endif /* EXTENDED_PCIE_DEBUG_DUMP */ } -#ifdef WL_CFGVENDOR_SEND_HANG_EVENT -#define MAX_RC_REG_INFO_VAL 8 -#define PCIE_EXTCAP_ERR_HD_SZ 4 -void -dhd_dump_pcie_rc_regs_for_linkdown(dhd_pub_t *dhd, int *bytes_written) -{ - int i; - int remain_len; - - /* dump link control & status */ - if (dhd->hang_info_cnt < HANG_FIELD_CNT_MAX) { - remain_len = VENDOR_SEND_HANG_EXT_INFO_LEN - *bytes_written; - *bytes_written += scnprintf(&dhd->hang_info[*bytes_written], remain_len, "%08x%c", - dhdpcie_rc_access_cap(dhd->bus, PCIE_CAP_ID_EXP, - PCIE_CAP_LINKCTRL_OFFSET, FALSE, FALSE, 0), HANG_KEY_DEL); - dhd->hang_info_cnt++; - } - - /* dump device control & status */ - if (dhd->hang_info_cnt < HANG_FIELD_CNT_MAX) { - remain_len = VENDOR_SEND_HANG_EXT_INFO_LEN - *bytes_written; - *bytes_written += scnprintf(&dhd->hang_info[*bytes_written], remain_len, "%08x%c", - dhdpcie_rc_access_cap(dhd->bus, PCIE_CAP_ID_EXP, - PCIE_CAP_DEVCTRL_OFFSET, FALSE, FALSE, 0), HANG_KEY_DEL); - dhd->hang_info_cnt++; - } - - /* dump uncorrectable error */ - if (dhd->hang_info_cnt < HANG_FIELD_CNT_MAX) { - remain_len = VENDOR_SEND_HANG_EXT_INFO_LEN - *bytes_written; - *bytes_written += scnprintf(&dhd->hang_info[*bytes_written], remain_len, "%08x%c", - dhdpcie_rc_access_cap(dhd->bus, PCIE_EXTCAP_ID_ERR, - PCIE_EXTCAP_AER_UCERR_OFFSET, TRUE, FALSE, 0), HANG_KEY_DEL); - dhd->hang_info_cnt++; - } - - /* dump correctable error */ - if (dhd->hang_info_cnt < HANG_FIELD_CNT_MAX) { - remain_len = VENDOR_SEND_HANG_EXT_INFO_LEN - *bytes_written; - *bytes_written += scnprintf(&dhd->hang_info[*bytes_written], remain_len, "%08x%c", - dhdpcie_rc_access_cap(dhd->bus, PCIE_EXTCAP_ID_ERR, - /* XXX: use definition in linux/pcie_regs.h */ - PCI_ERR_COR_STATUS, TRUE, FALSE, 0), HANG_KEY_DEL); - dhd->hang_info_cnt++; - } - - /* HG05/06 reserved */ - if (dhd->hang_info_cnt < HANG_FIELD_CNT_MAX) { - remain_len = VENDOR_SEND_HANG_EXT_INFO_LEN - *bytes_written; - *bytes_written += scnprintf(&dhd->hang_info[*bytes_written], remain_len, "%08x%c", - 0, HANG_KEY_DEL); - dhd->hang_info_cnt++; - } - - if (dhd->hang_info_cnt < HANG_FIELD_CNT_MAX) { - remain_len = VENDOR_SEND_HANG_EXT_INFO_LEN - *bytes_written; - *bytes_written += scnprintf(&dhd->hang_info[*bytes_written], remain_len, "%08x%c", - 0, HANG_KEY_DEL); - dhd->hang_info_cnt++; - } - - /* dump error header log in RAW */ - for (i = 0; i < PCIE_EXTCAP_ERR_HD_SZ; i++) { - remain_len = VENDOR_SEND_HANG_EXT_INFO_LEN - *bytes_written; - *bytes_written += scnprintf(&dhd->hang_info[*bytes_written], remain_len, - "%c%08x", HANG_RAW_DEL, dhdpcie_rc_access_cap(dhd->bus, PCIE_EXTCAP_ID_ERR, - PCIE_EXTCAP_ERR_HEADER_LOG_0 + i * PCIE_EXTCAP_ERR_HD_SZ, - TRUE, FALSE, 0)); - } - dhd->hang_info_cnt++; -} -#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */ - int dhd_pcie_debug_info_dump(dhd_pub_t *dhd) { @@ -17505,13 +17878,6 @@ dhd_pcie_debug_info_dump(dhd_pub_t *dhd) DHD_ERROR(("RootPort PCIe linkcap=0x%08x\n", dhd_debug_get_rc_linkcap(dhd->bus))); -#ifdef CUSTOMER_HW4_DEBUG - if (dhd->bus->is_linkdown) { - DHD_ERROR(("Skip dumping the PCIe Config and Core registers. " - "link may be DOWN\n")); - return 0; - } -#endif /* CUSTOMER_HW4_DEBUG */ DHD_ERROR(("\n ------- DUMPING PCIE EP config space Registers ------- \r\n")); /* XXX: hwnbu-twiki.sj.broadcom.com/bin/view/Mwgroup/CurrentPcieGen2ProgramGuide */ dhd_bus_dump_imp_cfg_registers(dhd->bus); @@ -17550,6 +17916,13 @@ dhd_pcie_debug_info_dump(dhd_pub_t *dhd) dhd_bus_pcie_pwr_req(dhd->bus); } + dhd_pcie_dump_wrapper_regs(dhd); + + if (dhd->bus->dar_err_set) { + DHD_ERROR(("Skip dumping the PCIe Core registers. DAR error log set\n")); + goto exit; + } + DHD_ERROR(("\n ------- DUMPING PCIE core Registers ------- \r\n")); /* XXX: hwnbu-twiki.sj.broadcom.com/twiki/pub/Mwgroup/ * CurrentPcieGen2ProgramGuide/pcie_ep.htm @@ -17620,18 +17993,20 @@ dhd_pcie_debug_info_dump(dhd_pub_t *dhd) (uint)OFFSETOF(sbpcieregs_t, u.pcie2.err_hdr_logreg4), si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, OFFSETOF(sbpcieregs_t, u.pcie2.err_hdr_logreg4), 0, 0))); - DHD_ERROR(("err_code(0x%x)=0x%x\n", + DHD_ERROR(("err_code(0x%x)=0x%x PCIH2D_MailBox(%08x)=%08x\n", (uint)OFFSETOF(sbpcieregs_t, u.pcie2.err_code_logreg), si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, - OFFSETOF(sbpcieregs_t, u.pcie2.err_code_logreg), 0, 0))); + OFFSETOF(sbpcieregs_t, u.pcie2.err_code_logreg), 0, 0), + dhd_bus_db0_addr_get(dhd->bus), + si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, + dhd_bus_db0_addr_get(dhd->bus), 0, 0))); - dhd_pcie_dump_wrapper_regs(dhd); dhdpcie_hw_war_regdump(dhd->bus); } #endif /* EXTENDED_PCIE_DEBUG_DUMP */ dhd_pcie_dma_info_dump(dhd); - +exit: if (MULTIBP_ENAB(dhd->bus->sih)) { dhd_bus_pcie_pwr_req_clear(dhd->bus); } @@ -17644,39 +18019,11 @@ dhd_bus_force_bt_quiesce_enabled(struct dhd_bus *bus) { return bus->force_bt_quiesce; } -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE -uint32 dhd_bus_get_bp_base(dhd_pub_t *dhdp) -{ - return (dhdp->bus->bp_base); -} -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ -#ifdef DHD_HP2P -uint16 -dhd_bus_get_hp2p_ring_max_size(struct dhd_bus *bus, bool tx) -{ - if (tx) - return bus->hp2p_txcpl_max_items; - else - return bus->hp2p_rxcpl_max_items; -} - -static uint16 -dhd_bus_set_hp2p_ring_max_size(struct dhd_bus *bus, bool tx, uint16 val) -{ - if (tx) - bus->hp2p_txcpl_max_items = val; - else - bus->hp2p_rxcpl_max_items = val; - return val; -} -#endif /* DHD_HP2P */ uint8 dhd_d11_slices_num_get(dhd_pub_t *dhdp) { - return si_scan_core_present(dhdp->bus->sih) ? + return (dhdp->bus->sih && si_scan_core_present(dhdp->bus->sih)) ? MAX_NUM_D11_CORES_WITH_SCAN : MAX_NUM_D11CORES; } @@ -17693,7 +18040,7 @@ dhd_bus_tcm_test(struct dhd_bus *bus) uint8 init_val[NUM_PATTERNS] = { 0xFFu, /* 11111111 */ 0x00u, /* 00000000 */ -#if !defined(DHD_FW_MEM_CORRUPTION) +#if !defined(DHD_FW_MEM_CORRUPTION) && defined(BCM4375_CHIP) 0x77u, /* 01110111 */ 0x22u, /* 00100010 */ 0x27u, /* 00100111 */ @@ -17807,3 +18154,156 @@ dhdpcie_induce_cbp_hang(dhd_pub_t *dhd) val = 1; dhd_sbreg_op(dhd, addr, &val, FALSE); } + +bool +dhd_bus_init_done(struct dhd_bus *bus) +{ + return bus->intr_enabled; +} + +#ifdef DHD_SSSR_DUMP +void +dhd_fill_sssr_reg_info_4389(dhd_pub_t *dhd) +{ + sssr_reg_info_cmn_t *sssr_reg_info_cmn = dhd->sssr_reg_info; + sssr_reg_info_v3_t *sssr_reg_info; + + sssr_reg_info = (sssr_reg_info_v3_t *)&sssr_reg_info_cmn->rev3; + + DHD_ERROR(("%s:\n", __FUNCTION__)); + sssr_reg_info->version = SSSR_REG_INFO_VER_3; + sssr_reg_info->length = sizeof(sssr_reg_info_v3_t); + + sssr_reg_info->pmu_regs.base_regs.pmuintmask0 = 0x18012700; + sssr_reg_info->pmu_regs.base_regs.pmuintmask1 = 0x18012704; + sssr_reg_info->pmu_regs.base_regs.resreqtimer = 0x18012644; + sssr_reg_info->pmu_regs.base_regs.macresreqtimer = 0x18012688; + sssr_reg_info->pmu_regs.base_regs.macresreqtimer1 = 0x180126f0; + sssr_reg_info->pmu_regs.base_regs.macresreqtimer2 = 0x18012738; + + sssr_reg_info->chipcommon_regs.base_regs.intmask = 0x18000024; + sssr_reg_info->chipcommon_regs.base_regs.powerctrl = 0x180001e8; + sssr_reg_info->chipcommon_regs.base_regs.clockcontrolstatus = 0x180001e0; + sssr_reg_info->chipcommon_regs.base_regs.powerctrl_mask = 0x1f00; + + sssr_reg_info->arm_regs.base_regs.clockcontrolstatus = 0x180201e0; + sssr_reg_info->arm_regs.base_regs.clockcontrolstatus_val = 0x20; + sssr_reg_info->arm_regs.wrapper_regs.resetctrl = 0x18120800; + sssr_reg_info->arm_regs.wrapper_regs.extrsrcreq = 0x18006234; + + sssr_reg_info->pcie_regs.base_regs.ltrstate = 0x18001c38; + sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus = 0x180011e0; + sssr_reg_info->pcie_regs.base_regs.clockcontrolstatus_val = 0x0; + sssr_reg_info->pcie_regs.wrapper_regs.extrsrcreq = 0x180061b4; + + sssr_reg_info->mac_regs[0].base_regs.xmtaddress = 0x18021130; + sssr_reg_info->mac_regs[0].base_regs.xmtdata = 0x18021134; + sssr_reg_info->mac_regs[0].base_regs.clockcontrolstatus = 0x180211e0; + sssr_reg_info->mac_regs[0].base_regs.clockcontrolstatus_val = 0x20; + sssr_reg_info->mac_regs[0].wrapper_regs.resetctrl = 0x18121800; + sssr_reg_info->mac_regs[0].wrapper_regs.extrsrcreq = 0x180062b4; + sssr_reg_info->mac_regs[0].wrapper_regs.ioctrl = 0x18121408; + sssr_reg_info->mac_regs[0].wrapper_regs.ioctrl_resetseq_val[0] = 0xc7; + sssr_reg_info->mac_regs[0].wrapper_regs.ioctrl_resetseq_val[1] = 0x15f; + sssr_reg_info->mac_regs[0].wrapper_regs.ioctrl_resetseq_val[2] = 0x151; + sssr_reg_info->mac_regs[0].wrapper_regs.ioctrl_resetseq_val[3] = 0x155; + sssr_reg_info->mac_regs[0].wrapper_regs.ioctrl_resetseq_val[4] = 0xc5; + sssr_reg_info->mac_regs[0].sr_size = 0x40000; + + sssr_reg_info->mac_regs[1].base_regs.xmtaddress = 0x18022130; + sssr_reg_info->mac_regs[1].base_regs.xmtdata = 0x18022134; + sssr_reg_info->mac_regs[1].base_regs.clockcontrolstatus = 0x180221e0; + sssr_reg_info->mac_regs[1].base_regs.clockcontrolstatus_val = 0x20; + sssr_reg_info->mac_regs[1].wrapper_regs.resetctrl = 0x18122800; + sssr_reg_info->mac_regs[1].wrapper_regs.extrsrcreq = 0x18006334; + sssr_reg_info->mac_regs[1].wrapper_regs.ioctrl = 0x18122408; + sssr_reg_info->mac_regs[1].wrapper_regs.ioctrl_resetseq_val[0] = 0xc7; + sssr_reg_info->mac_regs[1].wrapper_regs.ioctrl_resetseq_val[1] = 0x15f; + sssr_reg_info->mac_regs[1].wrapper_regs.ioctrl_resetseq_val[2] = 0x151; + sssr_reg_info->mac_regs[1].wrapper_regs.ioctrl_resetseq_val[3] = 0x155; + sssr_reg_info->mac_regs[1].wrapper_regs.ioctrl_resetseq_val[4] = 0xc5; + sssr_reg_info->mac_regs[1].sr_size = 0x30000; + + sssr_reg_info->mac_regs[2].base_regs.xmtaddress = 0x18023130; + sssr_reg_info->mac_regs[2].base_regs.xmtdata = 0x18023134; + sssr_reg_info->mac_regs[2].base_regs.clockcontrolstatus = 0x180231e0; + sssr_reg_info->mac_regs[2].base_regs.clockcontrolstatus_val = 0x20; + sssr_reg_info->mac_regs[2].wrapper_regs.resetctrl = 0x18123800; + sssr_reg_info->mac_regs[2].wrapper_regs.extrsrcreq = 0x180063b4; + sssr_reg_info->mac_regs[2].wrapper_regs.ioctrl = 0x18123408; + sssr_reg_info->mac_regs[2].wrapper_regs.ioctrl_resetseq_val[0] = 0xc7; + sssr_reg_info->mac_regs[2].wrapper_regs.ioctrl_resetseq_val[1] = 0x15f; + sssr_reg_info->mac_regs[2].wrapper_regs.ioctrl_resetseq_val[2] = 0x151; + sssr_reg_info->mac_regs[2].wrapper_regs.ioctrl_resetseq_val[3] = 0x155; + sssr_reg_info->mac_regs[2].wrapper_regs.ioctrl_resetseq_val[4] = 0xc5; + sssr_reg_info->mac_regs[2].sr_size = 0x30000; + + sssr_reg_info->dig_mem_info.dig_sr_addr = 0x18520000; + sssr_reg_info->dig_mem_info.dig_sr_size = 0x10000; + + sssr_reg_info->fis_enab = 1; + + sssr_reg_info->hwa_regs.base_regs.clkenable = 0x180242d0; + sssr_reg_info->hwa_regs.base_regs.clkgatingenable = 0x180242d4; + sssr_reg_info->hwa_regs.base_regs.clkext = 0x180242e0; + sssr_reg_info->hwa_regs.base_regs.clkctlstatus = 0x180241e0; + sssr_reg_info->hwa_regs.wrapper_regs.ioctrl = 0x18124408; + sssr_reg_info->hwa_regs.wrapper_regs.resetctrl = 0x18124800; + + sssr_reg_info->hwa_regs.hwa_resetseq_val[0] = 0x3; + sssr_reg_info->hwa_regs.hwa_resetseq_val[1] = 0x1; + sssr_reg_info->hwa_regs.hwa_resetseq_val[2] = 0x0; + sssr_reg_info->hwa_regs.hwa_resetseq_val[3] = 0x1; + sssr_reg_info->hwa_regs.hwa_resetseq_val[4] = 0x1ff; + sssr_reg_info->hwa_regs.hwa_resetseq_val[5] = 0x1ff; + sssr_reg_info->hwa_regs.hwa_resetseq_val[6] = 0x3; + sssr_reg_info->hwa_regs.hwa_resetseq_val[7] = 0x20; + + dhd->sssr_inited = TRUE; +} + +void +dhdpcie_fill_sssr_reg_info(dhd_pub_t *dhd) +{ + if (dhd_get_chipid(dhd->bus) == BCM4389_CHIP_ID) { + dhd_fill_sssr_reg_info_4389(dhd); + } +} + +#endif /* DHD_SSSR_DUMP */ + +#if defined(NDIS) +void * +dhd_bus_get_socram_buf(struct dhd_bus *bus, struct dhd_pub *dhdp) +{ + return dhd_get_fwdump_buf(dhdp, bus->ramsize); +} +#endif /* NDIS */ + +void +dhd_bus_set_signature_path(struct dhd_bus *bus, char *sig_path) +{ + strlcpy(bus->fwsig_filename, sig_path, sizeof(bus->fwsig_filename)); +} + +#define BUS_SLEEP_WAIT_CNT 3 +#define BUS_SLEEP_WAIT_MS 20 +int +dhd_bus_sleep(dhd_pub_t *dhdp, bool sleep, uint32 *intstatus) +{ + dhd_bus_t *bus = dhdp->bus; + int active, cnt = 0; + + if (bus) { + while ((active = dhd_os_check_wakelock_all(bus->dhd)) && + (cnt < BUS_SLEEP_WAIT_CNT)) { + OSL_SLEEP(BUS_SLEEP_WAIT_MS); + cnt++; + } + } else { + DHD_ERROR(("bus is NULL\n")); + active = -1; + } + + return active; +} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h old mode 100755 new mode 100644 index e18bc2bd5d68..68a100912960 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h @@ -1,7 +1,7 @@ /* * Linux DHD Bus Module for PCIE * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -28,28 +28,8 @@ #include #include +#include #include -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM -#ifdef CONFIG_PCI_MSM -#include -#else -#include -#endif /* CONFIG_PCI_MSM */ -#endif /* CONFIG_ARCH_MSM */ -#ifdef CONFIG_ARCH_EXYNOS -#ifndef SUPPORT_EXYNOS7420 -#include -extern int exynos_pcie_register_event(struct exynos_pcie_register_event *reg); -extern int exynos_pcie_deregister_event(struct exynos_pcie_register_event *reg); -#endif /* !SUPPORT_EXYNOS7420 */ -#endif /* CONFIG_ARCH_EXYNOS */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - -#ifdef DHD_PCIE_RUNTIMEPM -#include -#include -#endif /* DHD_PCIE_RUNTIMEPM */ /* defines */ #define PCIE_SHARED_VERSION PCIE_SHARED_VERSION_7 @@ -65,19 +45,6 @@ extern int exynos_pcie_deregister_event(struct exynos_pcie_register_event *reg); #define REMAP_ENAB(bus) ((bus)->remap) #define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize))) -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM -#define struct_pcie_notify struct msm_pcie_notify -#define struct_pcie_register_event struct msm_pcie_register_event -#endif /* CONFIG_ARCH_MSM */ -#ifdef CONFIG_ARCH_EXYNOS -#ifndef SUPPORT_EXYNOS7420 -#define struct_pcie_notify struct exynos_pcie_notify -#define struct_pcie_register_event struct exynos_pcie_register_event -#endif /* !SUPPORT_EXYNOS7420 */ -#endif /* CONFIG_ARCH_EXYNOS */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - #define MAX_DHD_TX_FLOWS 320 /* user defined data structures */ @@ -186,7 +153,7 @@ typedef struct _dhd_ds_trace_t { #define PCIE_FASTLPO_ENABLED(buscorerev) \ ((buscorerev == 66) || (buscorerev == 67) || (buscorerev == 68) || \ - (buscorerev == 70) || (buscorerev == 72)) + (buscorerev == 70) || (buscorerev == 72) || (buscorerev == 76)) /* * HW JIRA - CRWLPCIEGEN2-672 @@ -264,6 +231,16 @@ typedef struct _dhd_flow_ring_status_trace_t { } dhd_frs_trace_t; #endif /* DHD_FLOW_RING_STATUS_TRACE */ +typedef enum dhd_pcie_link_state { + DHD_PCIE_ALL_GOOD = 0, + DHD_PCIE_LINK_DOWN = 1, + DHD_PCIE_COMMON_BP_DOWN = 2, + DHD_PCIE_WLAN_BP_DOWN = 3 +} dhd_pcie_link_state_type_t; + +/* Max length of filename in IOVAR or in module parameter */ +#define DHD_MAX_PATH 2048u + /** Instantiated once for each hardware (dongle) instance that this DHD manages */ typedef struct dhd_bus { dhd_pub_t *dhd; /**< pointer to per hardware (dongle) unique instance */ @@ -271,9 +248,6 @@ typedef struct dhd_bus { struct pci_dev *rc_dev; /* pci RC device handle */ struct pci_dev *dev; /* pci device handle */ #endif /* !defined(NDIS) */ -#ifdef DHD_EFI - void *pcie_dev; -#endif dll_t flowring_active_list; /* constructed list of tx flowring queues */ #ifdef IDLE_TX_FLOW_MGMT uint64 active_list_last_process_ts; @@ -349,14 +323,6 @@ typedef struct dhd_bus { uint32 curr_bar1_win; /* current PCIEBar1Window setting */ osl_t *osh; uint32 nvram_csm; /* Nvram checksum */ -#ifdef BCMINTERNAL - bool msi_sim; - uchar *msi_sim_addr; - dmaaddr_t msi_sim_phys; - dhd_dma_buf_t hostfw_buf; /* Host offload firmware buffer */ - uint32 hostfw_base; /* FW assumed base of host offload mem */ - uint32 bp_base; /* adjusted bp base of host offload mem */ -#endif /* BCMINTERNAL */ uint16 pollrate; uint16 polltick; @@ -403,25 +369,8 @@ typedef struct dhd_bus { bool irq_registered; bool d2h_intr_method; bool d2h_intr_control; -#ifdef SUPPORT_LINKDOWN_RECOVERY -#if defined(CONFIG_ARCH_MSM) || (defined(CONFIG_ARCH_EXYNOS) && \ - !defined(SUPPORT_EXYNOS7420)) -#ifdef CONFIG_ARCH_MSM - uint8 no_cfg_restore; -#endif /* CONFIG_ARCH_MSM */ - struct_pcie_register_event pcie_event; -#endif /* CONFIG_ARCH_MSM || CONFIG_ARCH_EXYNOS && !SUPPORT_EXYNOS7420 */ - bool read_shm_fail; -#endif /* SUPPORT_LINKDOWN_RECOVERY */ int32 idletime; /* Control for activity timeout */ bool rpm_enabled; -#ifdef DHD_PCIE_RUNTIMEPM - int32 idlecount; /* Activity timeout counter */ - int32 bus_wake; /* For wake up the bus */ - bool runtime_resume_done; /* For check runtime suspend end */ - struct mutex pm_lock; /* Synchronize for system PM & runtime PM */ - wait_queue_head_t rpm_queue; /* wait-queue for bus wake up */ -#endif /* DHD_PCIE_RUNTIMEPM */ uint32 d3_inform_cnt; uint32 d0_inform_cnt; uint32 d0_inform_in_use_cnt; @@ -455,14 +404,14 @@ typedef struct dhd_bus { dhd_ds_trace_t ds_trace[MAX_DS_TRACE_SIZE]; uint32 ds_trace_count; uint32 hostready_count; /* Number of hostready issued */ -#if defined(PCIE_OOB) || defined (BCMPCIE_OOB_HOST_WAKE) +#if defined(PCIE_OOB) || defined(BCMPCIE_OOB_HOST_WAKE) bool oob_presuspend; #endif /* PCIE_OOB || BCMPCIE_OOB_HOST_WAKE */ dhdpcie_config_save_t saved_config; - ulong resume_intr_enable_count; - ulong dpc_intr_enable_count; - ulong isr_intr_disable_count; - ulong suspend_intr_disable_count; + ulong host_irq_enable_count; + ulong host_irq_disable_count; + ulong dngl_intmask_disable_count; + ulong dngl_intmask_enable_count; ulong dpc_return_busdown_count; ulong non_ours_irq_count; #ifdef BCMPCIE_OOB_HOST_WAKE @@ -475,6 +424,7 @@ typedef struct dhd_bus { uint64 last_oob_irq_disable_time; #endif /* BCMPCIE_OOB_HOST_WAKE */ uint64 isr_entry_time; + uint64 prev_isr_entry_time; uint64 isr_exit_time; uint64 isr_sched_dpc_time; uint64 rpm_sched_dpc_time; @@ -482,6 +432,7 @@ typedef struct dhd_bus { uint64 dpc_exit_time; uint64 resched_dpc_time; uint64 last_d3_inform_time; + uint64 last_d3_ack_time; uint64 last_process_ctrlbuf_time; uint64 last_process_flowring_time; uint64 last_process_txcpl_time; @@ -493,6 +444,16 @@ typedef struct dhd_bus { uint64 last_resume_start_time; uint64 last_resume_end_time; uint64 last_non_ours_irq_time; + uint64 dpc_time_usec; + uint64 *dpc_time_histo; + uint64 ctrl_cpl_post_time_usec; + uint64 *ctrl_cpl_post_time_histo; + uint64 tx_post_time_usec; + uint64 *tx_post_time_histo; + uint64 tx_cpl_time_usec; + uint64 *tx_cpl_time_histo; + uint64 rx_cpl_post_time_usec; + uint64 *rx_cpl_post_time_histo; bool hwa_enabled; bool idma_enabled; bool ifrm_enabled; @@ -518,9 +479,6 @@ typedef struct dhd_bus { #if defined(PCIE_OOB) || defined(PCIE_INB_DW) bool ds_enabled; #endif -#ifdef DHD_PCIE_RUNTIMEPM - bool chk_pm; /* To avoid counting of wake up from Runtime PM */ -#endif /* DHD_PCIE_RUNTIMEPM */ #if defined(PCIE_INB_DW) bool calc_ds_exit_latency; bool deep_sleep; /* Indicates deep_sleep set or unset by the DHD IOVAR deep_sleep */ @@ -536,6 +494,8 @@ typedef struct dhd_bus { uint32 gdb_proxy_last_id; /* True if firmware was started in bootloader mode */ bool gdb_proxy_bootloader_mode; + /* Counter incremented at each generated memory dump */ + uint32 gdb_proxy_mem_dump_count; #endif /* GDB_PROXY */ uint8 dma_chan; @@ -560,7 +520,7 @@ typedef struct dhd_bus { uint32 fw_memmap_download_addr; /* Dongle address of FWS memory-info download */ uint32 fw_memmap_download_len; /* Length in bytes of FWS memory-info download */ - char fwsig_filename[DHD_FILENAME_MAX]; /* Name of FW signature file */ + char fwsig_filename[DHD_MAX_PATH]; /* Name of FW signature file */ char bootloader_filename[DHD_FILENAME_MAX]; /* Name of bootloader image file */ uint32 bootloader_addr; /* Dongle address of bootloader download */ bool force_bt_quiesce; /* send bt_quiesce command to BT driver. */ @@ -576,12 +536,9 @@ typedef struct dhd_bus { #ifdef BCMSLTGT int xtalfreq; /* Xtal frequency used for htclkratio calculation */ uint32 ilp_tick; /* ILP ticks per second read from pmutimer */ - uint32 xtal_ratio; /* xtal ticks per 4 ILP ticks read from pmu_xtalfreq */ + uint32 alp_to_ilp_ratio; /* ALP ticks per ILP ticks read from pmu_xtalfreq */ + uint32 xtal_to_alp_ratio; /* xtal to ALP ratio which can change from chip to chip */ #endif /* BCMSLTGT */ -#ifdef BT_OVER_PCIE - /* whether the chip is in BT over PCIE mode or not */ - bool btop_mode; -#endif /* BT_OVER_PCIE */ uint16 hp2p_txcpl_max_items; uint16 hp2p_rxcpl_max_items; /* PCIE coherent status */ @@ -591,8 +548,27 @@ typedef struct dhd_bus { uint64 rd_shared_pass_time; uint32 hwa_mem_base; uint32 hwa_mem_size; + dhd_pcie_link_state_type_t link_state; + bool dar_err_set; + uint32 ptm_ctrl_reg; + fwpkg_info_t fwpkg; /* combined fw package info structure */ + bool lpm_mode; /* lpm enabled */ + bool lpm_keep_in_reset; /* during LPM keep in FLR, if FLR force is enabled */ + bool lpm_mem_kill; /* kill WLAN memories in LPM */ + bool lpm_force_flr; /* Force F0 FLR on WLAN when in LPM */ + uint32 lpbk_xfer_data_pattern_type; /* data Pattern type DMA lpbk */ } dhd_bus_t; +#define LPBK_DMA_XFER_DTPTRN_DEFAULT 0 +#define LPBK_DMA_XFER_DTPTRN_0x00 1 +#define LPBK_DMA_XFER_DTPTRN_0xFF 2 +#define LPBK_DMA_XFER_DTPTRN_0x55 3 +#define LPBK_DMA_XFER_DTPTRN_0xAA 4 + +#define LPM_MODE_LPM_ALL 0x1 +#define LPM_MODE_NO_MEMKILL 0x010 +#define LPM_MODE_NO_FLR 0x100 + #ifdef DHD_MSI_SUPPORT extern uint enable_msi; #endif /* DHD_MSI_SUPPORT */ @@ -759,6 +735,7 @@ extern int dhdpcie_disable_irq_nosync(dhd_bus_t *bus); extern int dhdpcie_enable_irq(dhd_bus_t *bus); extern void dhd_bus_dump_dar_registers(struct dhd_bus *bus); +extern void dhd_bus_dump_imp_cfg_registers(struct dhd_bus *bus); #if defined(linux) || defined(LINUX) extern uint32 dhdpcie_rc_config_read(dhd_bus_t *bus, uint offset); @@ -767,6 +744,7 @@ extern uint32 dhdpcie_rc_access_cap(dhd_bus_t *bus, int cap, uint offset, bool i extern uint32 dhdpcie_ep_access_cap(dhd_bus_t *bus, int cap, uint offset, bool is_ext, bool is_write, uint32 writeval); extern uint32 dhd_debug_get_rc_linkcap(dhd_bus_t *bus); +extern void dhdpcie_enable_irq_loop(dhd_bus_t *bus); #else static INLINE uint32 dhdpcie_rc_config_read(dhd_bus_t *bus, uint offset) { return 0;} static INLINE uint32 dhdpcie_rc_access_cap(dhd_bus_t *bus, int cap, uint offset, bool is_ext, @@ -774,7 +752,8 @@ static INLINE uint32 dhdpcie_rc_access_cap(dhd_bus_t *bus, int cap, uint offset, static INLINE uint32 dhdpcie_ep_access_cap(dhd_bus_t *bus, int cap, uint offset, bool is_ext, bool is_write, uint32 writeval) { return -1;} static INLINE uint32 dhd_debug_get_rc_linkcap(dhd_bus_t *bus) { return -1;} -#endif +static INLINE void dhdpcie_enable_irq_loop(dhd_bus_t *bus) { return; } +#endif /* LINUX || linux */ #if defined(linux) || defined(LINUX) extern int dhdpcie_start_host_dev(dhd_bus_t *bus); extern int dhdpcie_stop_host_dev(dhd_bus_t *bus); @@ -794,9 +773,10 @@ uint32 dhdpcie_os_rtcm32(dhd_bus_t *bus, ulong offset); void dhdpcie_os_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data); uint64 dhdpcie_os_rtcm64(dhd_bus_t *bus, ulong offset); #endif +extern void dhd_dpc_kill(dhd_pub_t *dhdp); #endif /* LINUX || linux */ -#if defined(linux) || defined(LINUX) || defined(DHD_EFI) +#if defined(linux) || defined(LINUX) extern int dhdpcie_enable_device(dhd_bus_t *bus); #endif @@ -807,6 +787,9 @@ extern void dhdpcie_oob_intr_set(dhd_bus_t *bus, bool enable); extern int dhdpcie_get_oob_irq_num(struct dhd_bus *bus); extern int dhdpcie_get_oob_irq_status(struct dhd_bus *bus); extern int dhdpcie_get_oob_irq_level(void); +#ifdef PRINT_WAKEUP_GPIO_STATUS +extern int dhdpcie_get_oob_gpio_number(void); +#endif /* PRINT_WAKEUP_GPIO_STATUS */ #endif /* BCMPCIE_OOB_HOST_WAKE */ #ifdef PCIE_OOB extern void dhd_oob_set_bt_reg_on(struct dhd_bus *bus, bool val); @@ -819,93 +802,14 @@ extern void dhd_os_ib_set_device_wake(struct dhd_bus *bus, bool val); extern void dhd_bus_doorbell_timeout_reset(struct dhd_bus *bus); #endif /* defined(PCIE_OOB) || defined(PCIE_INB_DW) */ -#if defined(linux) || defined(LINUX) -/* XXX: SWWLAN-82173 Making PCIe RC D3cold by force during system PM - * exynos_pcie_pm_suspend : RC goes to suspend status & assert PERST - * exynos_pcie_pm_resume : de-assert PERST & RC goes to resume status - */ -#if defined(CONFIG_ARCH_EXYNOS) -#define EXYNOS_PCIE_VENDOR_ID 0x144d -#if defined(CONFIG_MACH_UNIVERSAL7420) || defined(CONFIG_SOC_EXYNOS7420) -#define EXYNOS_PCIE_DEVICE_ID 0xa575 -#define EXYNOS_PCIE_CH_NUM 1 -#elif defined(CONFIG_SOC_EXYNOS8890) -#define EXYNOS_PCIE_DEVICE_ID 0xa544 -#define EXYNOS_PCIE_CH_NUM 0 -#elif defined(CONFIG_SOC_EXYNOS8895) || defined(CONFIG_SOC_EXYNOS9810) || \ - defined(CONFIG_SOC_EXYNOS9820) || defined(CONFIG_SOC_EXYNOS9830) || \ - defined(CONFIG_SOC_EXYNOS2100) || defined(CONFIG_SOC_EXYNOS1000) || \ - defined(CONFIG_SOC_GS101) -#define EXYNOS_PCIE_DEVICE_ID 0xecec -#define EXYNOS_PCIE_CH_NUM 0 -#else -#error "Not supported platform" -#endif /* CONFIG_SOC_EXYNOSXXXX & CONFIG_MACH_UNIVERSALXXXX */ -extern void exynos_pcie_pm_suspend(int ch_num); -extern void exynos_pcie_pm_resume(int ch_num); -#endif /* CONFIG_ARCH_EXYNOS */ - -#if defined(CONFIG_ARCH_MSM) -#define MSM_PCIE_VENDOR_ID 0x17cb -#if defined(CONFIG_ARCH_APQ8084) -#define MSM_PCIE_DEVICE_ID 0x0101 -#elif defined(CONFIG_ARCH_MSM8994) -#define MSM_PCIE_DEVICE_ID 0x0300 -#elif defined(CONFIG_ARCH_MSM8996) -#define MSM_PCIE_DEVICE_ID 0x0104 -#elif defined(CONFIG_ARCH_MSM8998) -#define MSM_PCIE_DEVICE_ID 0x0105 -#elif defined(CONFIG_ARCH_SDM845) || defined(CONFIG_ARCH_SM8150) || \ - defined(CONFIG_ARCH_KONA) || defined(CONFIG_ARCH_LAHAINA) -#define MSM_PCIE_DEVICE_ID 0x0106 -#else -#error "Not supported platform" -#endif -#endif /* CONFIG_ARCH_MSM */ - -#if defined(CONFIG_X86) -#define X86_PCIE_VENDOR_ID 0x8086 -#define X86_PCIE_DEVICE_ID 0x9c1a -#endif /* CONFIG_X86 */ - -#if defined(CONFIG_ARCH_TEGRA) -#define TEGRA_PCIE_VENDOR_ID 0x14e4 -#define TEGRA_PCIE_DEVICE_ID 0x4347 -#endif /* CONFIG_ARCH_TEGRA */ - -#if defined(BOARD_HIKEY) -#define HIKEY_PCIE_VENDOR_ID 0x19e5 -#define HIKEY_PCIE_DEVICE_ID 0x3660 -#endif /* BOARD_HIKEY */ - -#define DUMMY_PCIE_VENDOR_ID 0xffff -#define DUMMY_PCIE_DEVICE_ID 0xffff - -#if defined(CONFIG_ARCH_EXYNOS) -#define PCIE_RC_VENDOR_ID EXYNOS_PCIE_VENDOR_ID -#define PCIE_RC_DEVICE_ID EXYNOS_PCIE_DEVICE_ID -#elif defined(CONFIG_ARCH_MSM) -#define PCIE_RC_VENDOR_ID MSM_PCIE_VENDOR_ID -#define PCIE_RC_DEVICE_ID MSM_PCIE_DEVICE_ID -#elif defined(CONFIG_X86) -#define PCIE_RC_VENDOR_ID X86_PCIE_VENDOR_ID -#define PCIE_RC_DEVICE_ID X86_PCIE_DEVICE_ID -#elif defined(CONFIG_ARCH_TEGRA) -#define PCIE_RC_VENDOR_ID TEGRA_PCIE_VENDOR_ID -#define PCIE_RC_DEVICE_ID TEGRA_PCIE_DEVICE_ID -#elif defined(BOARD_HIKEY) -#define PCIE_RC_VENDOR_ID HIKEY_PCIE_VENDOR_ID -#define PCIE_RC_DEVICE_ID HIKEY_PCIE_DEVICE_ID -#else -/* Use dummy vendor and device IDs */ -#define PCIE_RC_VENDOR_ID DUMMY_PCIE_VENDOR_ID -#define PCIE_RC_DEVICE_ID DUMMY_PCIE_DEVICE_ID -#endif /* CONFIG_ARCH_EXYNOS */ -#endif /* linux || LINUX */ - #define DHD_REGULAR_RING 0 #define DHD_HP2P_RING 1 +#ifdef DHD_SET_PCIE_DMA_MASK_FOR_GS101 +/* This is only for GS101 platform. Others is done on RC side */ +#define DHD_PCIE_DMA_MASK_FOR_GS101 36 +#endif /* DHD_SET_PCIE_DMA_MASK_FOR_GS101 */ + #ifdef CONFIG_ARCH_TEGRA extern int tegra_pcie_pm_suspend(void); extern int tegra_pcie_pm_resume(void); @@ -932,6 +836,8 @@ extern int dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data); #ifdef DHD_WAKE_STATUS int bcmpcie_get_total_wake(struct dhd_bus *bus); int bcmpcie_set_get_wake(struct dhd_bus *bus, int flag); +int bcmpcie_get_wake(struct dhd_bus *bus); +int bcmpcie_set_get_wake_pkt_dump(struct dhd_bus *bus, int wake_pkt_dump); #endif /* DHD_WAKE_STATUS */ #ifdef DHD_MMIO_TRACE extern void dhd_dump_bus_mmio_trace(dhd_bus_t *bus, struct bcmstrbuf *strbuf); @@ -950,6 +856,9 @@ extern enum dhd_bus_ds_state dhdpcie_bus_get_pcie_inband_dw_state(dhd_bus_t *bus extern const char * dhd_convert_inb_state_names(enum dhd_bus_ds_state inbstate); extern const char * dhd_convert_dsval(uint32 val, bool d2h); extern int dhd_bus_inb_set_device_wake(struct dhd_bus *bus, bool val); +#ifdef PCIE_INB_DSACK_EXT_WAIT +extern void dhd_bus_ds_ack_debug_dump(struct dhd_bus *bus); +#endif /* PCIE_INB_DSACK_EXT_WAIT */ extern void dhd_bus_inb_ack_pending_ds_req(dhd_bus_t *bus); #endif /* PCIE_INB_DW */ extern void dhdpcie_bus_enab_pcie_dw(dhd_bus_t *bus, uint8 dw_option); @@ -962,27 +871,11 @@ static INLINE int dhdpcie_set_master_and_d0_pwrstate(struct dhd_bus *bus) { return BCME_ERROR;} #endif /* defined(LINUX) || defined(linux) */ -#ifdef DHD_EFI -extern bool dhdpcie_is_arm_halted(struct dhd_bus *bus); -extern int dhd_os_wifi_platform_set_power(uint32 value); -extern void dhdpcie_dongle_pwr_toggle(dhd_bus_t *bus); -void dhdpcie_dongle_flr_or_pwr_toggle(dhd_bus_t *bus); -int dhd_control_signal(dhd_bus_t *bus, char *arg, int len, int set); -extern int dhd_wifi_properties(struct dhd_bus *bus, char *arg, int len); -extern int dhd_otp_dump(dhd_bus_t *bus, char *arg, int len); -extern int dhdpcie_deinit_phase1(dhd_bus_t *bus); -int dhdpcie_disable_intr_poll(dhd_bus_t *bus); -int dhdpcie_enable_intr_poll(dhd_bus_t *bus); -#ifdef BT_OVER_PCIE -int dhd_btop_test(dhd_bus_t *bus, char *arg, int len); -#endif /* BT_OVER_PCIE */ -#else static INLINE bool dhdpcie_is_arm_halted(struct dhd_bus *bus) {return TRUE;} static INLINE int dhd_os_wifi_platform_set_power(uint32 value) {return BCME_OK; } static INLINE void dhdpcie_dongle_flr_or_pwr_toggle(dhd_bus_t *bus) { return; } -#endif /* DHD_EFI */ int dhdpcie_config_check(dhd_bus_t *bus); int dhdpcie_config_restore(dhd_bus_t *bus, bool restore_pmcsr); @@ -1022,18 +915,10 @@ extern int dhdpcie_get_fwpath_otp(dhd_bus_t *bus, char *fw_path, char *nv_path, extern int dhd_pcie_debug_info_dump(dhd_pub_t *dhd); extern void dhd_pcie_intr_count_dump(dhd_pub_t *dhd); extern void dhdpcie_bus_clear_intstatus(dhd_bus_t *bus); -#ifdef DHD_HP2P -extern uint16 dhd_bus_get_hp2p_ring_max_size(dhd_bus_t *bus, bool tx); -#endif -#if defined(DHD_EFI) -extern wifi_properties_t *dhd_get_props(dhd_bus_t *bus); -#endif - -#if defined(DHD_EFI) || defined(NDIS) +#if defined(NDIS) extern int dhd_get_platform(dhd_pub_t* dhd, char *progname); extern bool dhdpcie_is_chip_supported(uint32 chipid, int *idx); -extern bool dhdpcie_is_sflash_chip(uint32 chipid); #endif extern int dhd_get_pcie_linkspeed(dhd_pub_t *dhd); @@ -1045,4 +930,11 @@ extern void dhd_init_dongle_ds_lock(dhd_bus_t *bus); extern void dhd_deinit_dongle_ds_lock(dhd_bus_t *bus); #endif /* PCIE_INB_DW */ +extern bool dhd_check_htput_chip(dhd_bus_t *bus); + +#if defined(DEVICE_TX_STUCK_DETECT) && defined(ASSOC_CHECK_SR) +void dhd_assoc_check_sr(dhd_pub_t *dhd, bool state); +#endif /* DEVICE_TX_STUCK_DETECT && ASSOC_CHECK_SR */ + +void dhd_init_bar1_switch_lock(dhd_bus_t *bus); #endif /* dhd_pcie_h */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c old mode 100755 new mode 100644 index 0d2cd973a616..db604d27462d --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c @@ -1,7 +1,7 @@ /* * Linux DHD Bus Module for PCIE * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -47,12 +47,12 @@ #include #include #include -#ifdef CUSTOMER_HW_ROCKCHIP +#if defined(CUSTOMER_HW_ROCKCHIP) && defined(CUSTOMER_HW_ROCKCHIP_RK3588) #include -#endif /* CUSTOMER_HW_ROCKCHIP */ +#endif /* CUSTOMER_HW_ROCKCHIP && CUSTOMER_HW_ROCKCHIP_RK3588 */ #ifdef OEM_ANDROID #ifdef CONFIG_ARCH_MSM -#if defined(CONFIG_PCI_MSM) || defined(CONFIG_ARCH_MSM8996) +#if IS_ENABLED(CONFIG_PCI_MSM) || defined(CONFIG_ARCH_MSM8996) #include #else #include @@ -62,27 +62,12 @@ #ifdef DHD_PCIE_NATIVE_RUNTIMEPM #include -#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ -#if defined(CONFIG_SOC_EXYNOS9810) || defined(CONFIG_SOC_EXYNOS9820) || \ - defined(CONFIG_SOC_EXYNOS9830) || defined(CONFIG_SOC_EXYNOS2100) || \ - defined(CONFIG_SOC_EXYNOS1000) || defined(CONFIG_SOC_GS101) -#include -#endif /* CONFIG_SOC_EXYNOS9810 || CONFIG_SOC_EXYNOS9820 || - * CONFIG_SOC_EXYNOS9830 || CONFIG_SOC_EXYNOS2100 || - * CONFIG_SOC_EXYNOS1000 || CONFIG_SOC_GS101 - */ - -#ifdef DHD_PCIE_NATIVE_RUNTIMEPM #ifndef AUTO_SUSPEND_TIMEOUT #define AUTO_SUSPEND_TIMEOUT 1000 #endif /* AUTO_SUSPEND_TIMEOUT */ #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ -#ifdef DHD_PCIE_RUNTIMEPM -#define RPM_WAKE_UP_TIMEOUT 10000 /* ms */ -#endif /* DHD_PCIE_RUNTIMEPM */ - #include #ifdef USE_SMMU_ARCH_MSM #include @@ -96,9 +81,15 @@ #include "ftdi_sio_external.h" #endif /* PCIE_OOB */ -#define PCI_CFG_RETRY 10 /* PR15065: retry count for pci cfg accesses */ +#if defined(WL_CFG80211) +#include +#endif /* WL_CFG80211 */ + +#include + +#define PCI_CFG_RETRY 10 /* PR15065: retry count for pci cfg accesses */ #define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */ -#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ +#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ #ifdef PCIE_OOB #define HOST_WAKE 4 /* GPIO_0 (HOST_WAKE) - Output from WLAN */ @@ -145,6 +136,7 @@ typedef struct dhdpcie_info unsigned int total_wake_count; int pkt_wake; int wake_irq; + int pkt_wake_dump; #endif /* DHD_WAKE_STATUS */ #ifdef USE_SMMU_ARCH_MSM void *smmu_cxt; @@ -172,9 +164,6 @@ typedef struct dhdpcie_os_info { void *dev; /* handle to the underlying device */ } dhdpcie_os_info_t; static irqreturn_t wlan_oob_irq(int irq, void *data); -#ifdef CUSTOMER_HW2 -extern struct brcm_pcie_wake brcm_pcie_wake; -#endif /* CUSTOMER_HW2 */ #endif /* BCMPCIE_OOB_HOST_WAKE */ #ifdef USE_SMMU_ARCH_MSM @@ -188,8 +177,9 @@ typedef struct dhdpcie_smmu_info { /* function declarations */ static int __devinit dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); -static void __devexit -dhdpcie_pci_remove(struct pci_dev *pdev); +static void __devexit dhdpcie_pci_remove(struct pci_dev *pdev); +static void __devexit dhdpcie_pci_shutdown(struct pci_dev *pdev); +static void __devexit dhdpcie_pci_stop(struct pci_dev *pdev); static int dhdpcie_init(struct pci_dev *pdev); static irqreturn_t dhdpcie_isr(int irq, void *arg); /* OS Routine functions for PCI suspend/resume */ @@ -203,23 +193,14 @@ static int dhdpcie_resume_host_dev(dhd_bus_t *bus); static int dhdpcie_suspend_host_dev(dhd_bus_t *bus); static int dhdpcie_resume_dev(struct pci_dev *dev); static int dhdpcie_suspend_dev(struct pci_dev *dev); -#ifdef DHD_PCIE_RUNTIMEPM -static int dhdpcie_pm_suspend(struct device *dev); -static int dhdpcie_pm_prepare(struct device *dev); -static int dhdpcie_pm_resume(struct device *dev); -static void dhdpcie_pm_complete(struct device *dev); -#else #ifdef DHD_PCIE_NATIVE_RUNTIMEPM static int dhdpcie_pm_system_suspend_noirq(struct device * dev); static int dhdpcie_pm_system_resume_noirq(struct device * dev); #else -static int dhdpcie_pci_suspend(struct pci_dev *dev, pm_message_t state); -static int dhdpcie_pci_resume(struct pci_dev *dev); -#if defined(BT_OVER_PCIE) -static int dhdpcie_pci_resume_early(struct pci_dev *dev); -#endif /* BT_OVER_PCIE */ +static int dhdpcie_pci_suspend(struct device * dev); +static int dhdpcie_pci_resume(struct device * dev); +static int dhdpcie_pci_resume_early(struct device * dev); #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ -#endif /* DHD_PCIE_RUNTIMEPM */ #ifdef DHD_PCIE_NATIVE_RUNTIMEPM static int dhdpcie_pm_runtime_suspend(struct device * dev); @@ -228,11 +209,6 @@ static int dhdpcie_pm_system_suspend_noirq(struct device * dev); static int dhdpcie_pm_system_resume_noirq(struct device * dev); #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ -#ifdef SUPPORT_EXYNOS7420 -void exynos_pcie_pm_suspend(int ch_num) {} -void exynos_pcie_pm_resume(int ch_num) {} -#endif /* SUPPORT_EXYNOS7420 */ - static void dhdpcie_config_save_restore_coherent(dhd_bus_t *bus, bool state); uint32 @@ -247,43 +223,59 @@ static struct pci_device_id dhdpcie_pci_devid[] __devinitdata = { class: PCI_CLASS_NETWORK_OTHER << 8, class_mask: 0xffff00, driver_data: 0, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) + override_only: 0, +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) */ }, +#if (BCMPCI_DEV_ID != PCI_ANY_ID) && defined(BCMPCI_NOOTP_DEV_ID) + { vendor: VENDOR_BROADCOM, + device: BCMPCI_NOOTP_DEV_ID, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + class: PCI_CLASS_NETWORK_OTHER << 8, + class_mask: 0xffff00, + driver_data: 0, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) + override_only: 0, +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) */ + }, +#endif /* BCMPCI_DEV_ID != PCI_ANY_ID && BCMPCI_NOOTP_DEV_ID */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) + { 0, 0, 0, 0, 0, 0, 0, 0} +#else { 0, 0, 0, 0, 0, 0, 0} +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) */ }; MODULE_DEVICE_TABLE(pci, dhdpcie_pci_devid); /* Power Management Hooks */ -#ifdef DHD_PCIE_RUNTIMEPM -static const struct dev_pm_ops dhd_pcie_pm_ops = { - .prepare = dhdpcie_pm_prepare, - .suspend = dhdpcie_pm_suspend, - .resume = dhdpcie_pm_resume, - .complete = dhdpcie_pm_complete, -}; -#endif /* DHD_PCIE_RUNTIMEPM */ -#ifdef DHD_PCIE_NATIVE_RUNTIMEPM +#if defined(DHD_PCIE_NATIVE_RUNTIMEPM) static const struct dev_pm_ops dhdpcie_pm_ops = { SET_RUNTIME_PM_OPS(dhdpcie_pm_runtime_suspend, dhdpcie_pm_runtime_resume, NULL) .suspend_noirq = dhdpcie_pm_system_suspend_noirq, .resume_noirq = dhdpcie_pm_system_resume_noirq }; -#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ +#else +/* for linux platforms */ +static const struct dev_pm_ops dhd_pcie_pm_ops = { + .suspend = dhdpcie_pci_suspend, + .resume = dhdpcie_pci_resume, + .resume_early = dhdpcie_pci_resume_early, +}; +#endif static struct pci_driver dhdpcie_driver = { node: {&dhdpcie_driver.node, &dhdpcie_driver.node}, - name: "pcieh", + name: "pcieh"BUS_TYPE, id_table: dhdpcie_pci_devid, probe: dhdpcie_pci_probe, remove: dhdpcie_pci_remove, -#if defined (DHD_PCIE_RUNTIMEPM) || defined (DHD_PCIE_NATIVE_RUNTIMEPM) - .driver.pm = &dhd_pcie_pm_ops, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)) + .driver = {.pm = &dhd_pcie_pm_ops, .coredump = NULL}, #else - suspend: dhdpcie_pci_suspend, - resume: dhdpcie_pci_resume, -#if defined(BT_OVER_PCIE) - resume_early: dhdpcie_pci_resume_early, -#endif /* BT_OVER_PCIE */ -#endif /* DHD_PCIE_RUNTIMEPM || DHD_PCIE_NATIVE_RUNTIMEPM */ + .driver = {.pm = &dhd_pcie_pm_ops, }, +#endif /* LINUX_VERSION_CODE >= 4.16.0 */ + shutdown: dhdpcie_pci_shutdown, }; int dhdpcie_init_succeeded = FALSE; @@ -316,8 +308,8 @@ static int dhdpcie_smmu_init(struct pci_dev *pdev, void *smmu_cxt) smmu_info->smmu_iova_start = smmu_iova_address[0]; smmu_info->smmu_iova_len = smmu_iova_address[1]; } else { - printf("%s : can't get smmu iova address property\n", - __FUNCTION__); + DHD_CONS_ONLY(("%s : can't get smmu iova address property\n", + __FUNCTION__)); return -ENODEV; } @@ -445,59 +437,22 @@ dhdpcie_chip_req_forced_tpoweron(dhd_bus_t *bus) } #endif /* FORCE_TPOWERON */ -#ifdef BT_OVER_PCIE -int dhd_bus_pwr_off(dhd_pub_t *dhdp, int reason) -{ - DHD_ERROR(("%s: WARNING ! function not implemented in %s\n", - __FUNCTION__, __FILE__)); - return BCME_OK; -} - -int dhd_bus_pwr_on(dhd_pub_t *dhdp, int reason) -{ - DHD_ERROR(("%s: WARNING ! function not implemented in %s\n", - __FUNCTION__, __FILE__)); - return BCME_OK; -} - -int dhd_bus_pwr_toggle(dhd_pub_t *dhdp, int reason) -{ - DHD_ERROR(("%s: WARNING ! function not implemented in %s\n", - __FUNCTION__, __FILE__)); - return BCME_OK; -} - -bool dhdpcie_is_btop_chip(struct dhd_bus *bus) -{ - DHD_ERROR(("%s: WARNING ! function not implemented in %s\n", - __FUNCTION__, __FILE__)); - return FALSE; -} - -int dhdpcie_redownload_fw(dhd_pub_t *dhdp) -{ - DHD_ERROR(("%s: WARNING ! function not implemented in %s\n", - __FUNCTION__, __FILE__)); - return BCME_OK; -} -#endif /* BT_OVER_PCIE */ - static bool dhd_bus_aspm_enable_dev(dhd_bus_t *bus, struct pci_dev *dev, bool enable) { uint32 linkctrl_before; uint32 linkctrl_after = 0; - uint8 linkctrl_asm; + uint8 linkctrl_aspm; char *device; device = (dev == bus->dev) ? "EP" : "RC"; linkctrl_before = dhdpcie_access_cap(dev, PCIE_CAP_ID_EXP, PCIE_CAP_LINKCTRL_OFFSET, FALSE, FALSE, 0); - linkctrl_asm = (linkctrl_before & PCIE_ASPM_CTRL_MASK); + linkctrl_aspm = (linkctrl_before & PCIE_ASPM_CTRL_MASK); if (enable) { - if (linkctrl_asm == PCIE_ASPM_L1_ENAB) { + if (linkctrl_aspm == PCIE_ASPM_L1_ENAB) { DHD_ERROR(("%s: %s already enabled linkctrl: 0x%x\n", __FUNCTION__, device, linkctrl_before)); return FALSE; @@ -506,7 +461,7 @@ dhd_bus_aspm_enable_dev(dhd_bus_t *bus, struct pci_dev *dev, bool enable) dhdpcie_access_cap(dev, PCIE_CAP_ID_EXP, PCIE_CAP_LINKCTRL_OFFSET, FALSE, TRUE, (linkctrl_before | PCIE_ASPM_L1_ENAB)); } else { - if (linkctrl_asm == 0) { + if (linkctrl_aspm == 0) { DHD_ERROR(("%s: %s already disabled linkctrl: 0x%x\n", __FUNCTION__, device, linkctrl_before)); return FALSE; @@ -525,6 +480,30 @@ dhd_bus_aspm_enable_dev(dhd_bus_t *bus, struct pci_dev *dev, bool enable) return TRUE; } +static bool +dhd_bus_is_aspm_enab_dev(dhd_bus_t *bus, struct pci_dev *dev) +{ + uint32 linkctrl = dhdpcie_access_cap(dev, PCIE_CAP_ID_EXP, + PCIE_CAP_LINKCTRL_OFFSET, FALSE, FALSE, 0); + + DHD_INFO(("%s: %s: linkctrl:0x%x\n", + __FUNCTION__, (dev == bus->dev) ? "EP" : "RC", linkctrl)); + + return ((linkctrl & PCIE_ASPM_CTRL_MASK) == PCIE_ASPM_L1_ENAB); +} + +bool +dhd_bus_is_aspm_enab_rc_ep(dhd_bus_t *bus) +{ + uint32 rc_aspm_enab; + uint32 ep_aspm_enab; + + rc_aspm_enab = dhd_bus_is_aspm_enab_dev(bus, bus->rc_dev); + ep_aspm_enab = dhd_bus_is_aspm_enab_dev(bus, bus->dev); + + return (rc_aspm_enab && ep_aspm_enab); +} + static bool dhd_bus_is_rc_ep_aspm_capable(dhd_bus_t *bus) { @@ -574,6 +553,33 @@ dhd_bus_aspm_enable_rc_ep(dhd_bus_t *bus, bool enable) return ret; } +static bool +dhd_bus_is_l1ss_enab_dev(dhd_bus_t *bus, struct pci_dev *dev) +{ + uint32 l1ssctrl; + + /* Extendend Capacility Reg */ + l1ssctrl = dhdpcie_access_cap(dev, PCIE_EXTCAP_ID_L1SS, + PCIE_EXTCAP_L1SS_CONTROL_OFFSET, TRUE, FALSE, 0); + + DHD_INFO(("%s: %s: l1ssctrl:0x%x\n", + __FUNCTION__, (dev == bus->dev) ? "EP" : "RC", l1ssctrl)); + + return ((l1ssctrl & PCIE_EXT_L1SS_MASK) == PCIE_EXT_L1SS_ENAB); +} + +bool +dhd_bus_is_l1ss_enab_rc_ep(dhd_bus_t *bus) +{ + uint32 rc_l1ss_enab; + uint32 ep_l1ss_enab; + + rc_l1ss_enab = dhd_bus_is_l1ss_enab_dev(bus, bus->rc_dev); + ep_l1ss_enab = dhd_bus_is_l1ss_enab_dev(bus, bus->dev); + + return (rc_l1ss_enab && ep_l1ss_enab); +} + static void dhd_bus_l1ss_enable_dev(dhd_bus_t *bus, struct pci_dev *dev, bool enable) { @@ -620,10 +626,18 @@ dhd_bus_is_rc_ep_l1ss_capable(dhd_bus_t *bus) uint32 rc_l1ss_cap; uint32 ep_l1ss_cap; -#ifdef CUSTOMER_HW_ROCKCHIP - if (IS_ENABLED(CONFIG_PCIEASPM_ROCKCHIP_WIFI_EXTENSION)) - return rk_dhd_bus_is_rc_ep_l1ss_capable(bus); -#endif +#if defined(CUSTOMER_HW_ROCKCHIP) && defined(CUSTOMER_HW_ROCKCHIP_RK3588) + if (IS_ENABLED(CONFIG_PCIEASPM_ROCKCHIP_WIFI_EXTENSION)) { + if (rk_dhd_bus_is_rc_ep_l1ss_capable(bus)) { + DHD_ERROR(("%s L1ss is capable\n", __FUNCTION__)); + return TRUE; + } else { + DHD_ERROR(("%s L1ss is not capable\n", __FUNCTION__)); + return FALSE; + } + } +#endif /* CUSTOMER_HW_ROCKCHIP && CUSTOMER_HW_ROCKCHIP_RK3588 */ + /* RC Extendend Capacility */ rc_l1ss_cap = dhdpcie_access_cap(bus->rc_dev, PCIE_EXTCAP_ID_L1SS, PCIE_EXTCAP_L1SS_CONTROL_OFFSET, TRUE, FALSE, 0); @@ -678,7 +692,7 @@ dhd_bus_aer_config(dhd_bus_t *bus) { uint32 val; - DHD_ERROR(("%s: Configure AER registers for EP\n", __FUNCTION__)); + DHD_ERROR_MEM(("%s: Configure AER registers for EP\n", __FUNCTION__)); val = dhdpcie_ep_access_cap(bus, PCIE_ADVERRREP_CAPID, PCIE_ADV_CORR_ERR_MASK_OFFSET, TRUE, FALSE, 0); if (val != (uint32)-1) { @@ -690,7 +704,7 @@ dhd_bus_aer_config(dhd_bus_t *bus) __FUNCTION__, val)); } - DHD_ERROR(("%s: Configure AER registers for RC\n", __FUNCTION__)); + DHD_ERROR_MEM(("%s: Configure AER registers for RC\n", __FUNCTION__)); val = dhdpcie_rc_access_cap(bus, PCIE_ADVERRREP_CAPID, PCIE_ADV_CORR_ERR_MASK_OFFSET, TRUE, FALSE, 0); if (val != (uint32)-1) { @@ -703,15 +717,15 @@ dhd_bus_aer_config(dhd_bus_t *bus) } } -#ifdef DHD_PCIE_RUNTIMEPM -static int dhdpcie_pm_suspend(struct device *dev) +static int dhdpcie_pci_suspend(struct device *dev) { int ret = 0; struct pci_dev *pdev = to_pci_dev(dev); dhdpcie_info_t *pch = pci_get_drvdata(pdev); dhd_bus_t *bus = NULL; unsigned long flags; - int msglevel = dhd_msg_level; + int timeleft = 0; + uint bitmask = 0xFFFFFFFF; printf("%s: Enter\n", __FUNCTION__); if (pch) { @@ -721,150 +735,27 @@ static int dhdpcie_pm_suspend(struct device *dev) return ret; } +#if defined(DEVICE_TX_STUCK_DETECT) && defined(ASSOC_CHECK_SR) + dhd_assoc_check_sr(bus->dhd, TRUE); +#endif /* DEVICE_TX_STUCK_DETECT && ASSOC_CHECK_SR */ DHD_GENERAL_LOCK(bus->dhd, flags); if (!DHD_BUS_BUSY_CHECK_IDLE(bus->dhd)) { - DHD_ERROR(("%s: Bus not IDLE!! dhd_bus_busy_state = 0x%x\n", - __FUNCTION__, bus->dhd->dhd_bus_busy_state)); + DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd); DHD_GENERAL_UNLOCK(bus->dhd, flags); - return -EBUSY; - } - DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd); - DHD_GENERAL_UNLOCK(bus->dhd, flags); - - dhd_msg_level |= DHD_RPM_VAL; - if (bus->dhd->up) - ret = dhdpcie_set_suspend_resume(bus, TRUE); - - DHD_GENERAL_LOCK(bus->dhd, flags); - DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd); - dhd_os_busbusy_wake(bus->dhd); - dhd_msg_level = msglevel; - printf("%s: Exit ret=%d\n", __FUNCTION__, ret); - DHD_GENERAL_UNLOCK(bus->dhd, flags); - - return ret; - -} - -static int dhdpcie_pm_prepare(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - dhdpcie_info_t *pch = pci_get_drvdata(pdev); - dhd_bus_t *bus = NULL; - - if (!pch || !pch->bus) { - return 0; - } - - bus = pch->bus; - DHD_DISABLE_RUNTIME_PM(bus->dhd); - bus->chk_pm = TRUE; - - return 0; -} - -static int dhdpcie_pm_resume(struct device *dev) -{ - int ret = 0; - struct pci_dev *pdev = to_pci_dev(dev); - dhdpcie_info_t *pch = pci_get_drvdata(pdev); - dhd_bus_t *bus = NULL; - unsigned long flags; - int msglevel = dhd_msg_level; - - printf("%s: Enter\n", __FUNCTION__); - if (pch) { - bus = pch->bus; - } - if (!bus) { - return ret; - } - - DHD_GENERAL_LOCK(bus->dhd, flags); - DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd); - DHD_GENERAL_UNLOCK(bus->dhd, flags); - - dhd_msg_level |= DHD_RPM_VAL; - if (bus->dhd->up) - ret = dhdpcie_set_suspend_resume(bus, FALSE); - - DHD_GENERAL_LOCK(bus->dhd, flags); - DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd); - dhd_os_busbusy_wake(bus->dhd); - dhd_msg_level = msglevel; - printf("%s: Exit ret=%d\n", __FUNCTION__, ret); - DHD_GENERAL_UNLOCK(bus->dhd, flags); - - return ret; -} - -static void dhdpcie_pm_complete(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - dhdpcie_info_t *pch = pci_get_drvdata(pdev); - dhd_bus_t *bus = NULL; - - if (!pch || !pch->bus) { - return; - } - - bus = pch->bus; - DHD_ENABLE_RUNTIME_PM(bus->dhd); - bus->chk_pm = FALSE; - - return; -} -#else -static int dhdpcie_pci_suspend(struct pci_dev * pdev, pm_message_t state) -{ - int ret = 0; - dhdpcie_info_t *pch = pci_get_drvdata(pdev); - dhd_bus_t *bus = NULL; - unsigned long flags; - uint32 i = 0; - - printf("%s: Enter\n", __FUNCTION__); - if (pch) { - bus = pch->bus; - } - if (!bus) { - return ret; - } - - BCM_REFERENCE(state); - - DHD_GENERAL_LOCK(bus->dhd, flags); - if (!DHD_BUS_BUSY_CHECK_IDLE(bus->dhd)) { - DHD_ERROR(("%s: Bus not IDLE!! dhd_bus_busy_state = 0x%x\n", + DHD_ERROR(("%s: wait to clear dhd_bus_busy_state: 0x%x\n", __FUNCTION__, bus->dhd->dhd_bus_busy_state)); - - DHD_GENERAL_UNLOCK(bus->dhd, flags); - OSL_DELAY(1000); - /* retry till the transaction is complete */ - while (i < 100) { - OSL_DELAY(1000); - i++; - - DHD_GENERAL_LOCK(bus->dhd, flags); - if (DHD_BUS_BUSY_CHECK_IDLE(bus->dhd)) { - DHD_ERROR(("%s: Bus enter IDLE!! after %d ms\n", - __FUNCTION__, i)); - break; - } - if (i != 100) { - DHD_GENERAL_UNLOCK(bus->dhd, flags); - } - } - if (!DHD_BUS_BUSY_CHECK_IDLE(bus->dhd)) { - DHD_GENERAL_UNLOCK(bus->dhd, flags); - DHD_ERROR(("%s: Bus not IDLE!! Failed after %d ms, " - "dhd_bus_busy_state = 0x%x\n", - __FUNCTION__, i, bus->dhd->dhd_bus_busy_state)); + timeleft = dhd_os_busbusy_wait_bitmask(bus->dhd, + &bus->dhd->dhd_bus_busy_state, bitmask, + DHD_BUS_BUSY_SUSPEND_IN_PROGRESS); + if ((timeleft == 0) || (timeleft == 1)) { + DHD_ERROR(("%s: Timed out dhd_bus_busy_state=0x%x\n", + __FUNCTION__, bus->dhd->dhd_bus_busy_state)); return -EBUSY; } + } else { + DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd); + DHD_GENERAL_UNLOCK(bus->dhd, flags); } - DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd); - DHD_GENERAL_UNLOCK(bus->dhd, flags); #ifdef DHD_CFG80211_SUSPEND_RESUME dhd_cfg80211_suspend(bus->dhd); @@ -882,10 +773,10 @@ static int dhdpcie_pci_suspend(struct pci_dev * pdev, pm_message_t state) return ret; } -#if defined(BT_OVER_PCIE) -static int dhdpcie_pci_resume_early(struct pci_dev *pdev) +static int dhdpcie_pci_resume_early(struct device *dev) { int ret = 0; + struct pci_dev *pdev = to_pci_dev(dev); dhdpcie_info_t *pch = pci_get_drvdata(pdev); dhd_bus_t *bus = NULL; uint32 pmcsr; @@ -896,6 +787,9 @@ static int dhdpcie_pci_resume_early(struct pci_dev *pdev) if (!bus) { return ret; } + if (bus->dhd->busstate == DHD_BUS_DOWN) { + return ret; + } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 9)) /* On fc30 (linux ver 5.0.9), @@ -932,11 +826,11 @@ static int dhdpcie_pci_resume_early(struct pci_dev *pdev) return ret; } -#endif /* BT_OVER_PCIE */ -static int dhdpcie_pci_resume(struct pci_dev *pdev) +static int dhdpcie_pci_resume(struct device *dev) { int ret = 0; + struct pci_dev *pdev = to_pci_dev(dev); dhdpcie_info_t *pch = pci_get_drvdata(pdev); dhd_bus_t *bus = NULL; unsigned long flags; @@ -961,6 +855,14 @@ static int dhdpcie_pci_resume(struct pci_dev *pdev) dhd_os_busbusy_wake(bus->dhd); printf("%s: Exit ret=%d\n", __FUNCTION__, ret); DHD_GENERAL_UNLOCK(bus->dhd, flags); +#if defined(DEVICE_TX_STUCK_DETECT) && defined(ASSOC_CHECK_SR) + dhd_assoc_check_sr(bus->dhd, FALSE); +#endif /* DEVICE_TX_STUCK_DETECT && ASSOC_CHECK_SR */ + +#ifdef WL_TWT + dhd_config_twt_event_mask_in_suspend(bus->dhd, FALSE); + dhd_send_twt_info_suspend(bus->dhd, FALSE); +#endif /* WL_TWT */ #ifdef DHD_CFG80211_SUSPEND_RESUME dhd_cfg80211_resume(bus->dhd); @@ -968,8 +870,6 @@ static int dhdpcie_pci_resume(struct pci_dev *pdev) return ret; } -#endif /* DHD_PCIE_RUNTIMEPM */ - static int #ifdef DHD_PCIE_NATIVE_RUNTIMEPM dhdpcie_set_suspend_resume(dhd_bus_t *bus, bool state, bool byint) @@ -981,22 +881,10 @@ dhdpcie_set_suspend_resume(dhd_bus_t *bus, bool state) ASSERT(bus && !bus->dhd->dongle_reset); -#ifdef DHD_PCIE_RUNTIMEPM - /* if wakelock is held during suspend, return failed */ - if (state == TRUE && dhd_os_check_wakelock_all(bus->dhd)) { - return -EBUSY; - } - mutex_lock(&bus->pm_lock); -#endif /* DHD_PCIE_RUNTIMEPM */ - DHD_RPM(("%s: Enter state=%d\n", __FUNCTION__, state)); - /* When firmware is not loaded do the PCI bus */ /* suspend/resume only */ if (bus->dhd->busstate == DHD_BUS_DOWN) { ret = dhdpcie_pci_suspend_resume(bus, state); -#ifdef DHD_PCIE_RUNTIMEPM - mutex_unlock(&bus->pm_lock); -#endif /* DHD_PCIE_RUNTIMEPM */ return ret; } #ifdef DHD_PCIE_NATIVE_RUNTIMEPM @@ -1018,11 +906,6 @@ dhdpcie_set_suspend_resume(dhd_bus_t *bus, bool state) } } #endif /* LINUX_VERSION_CODE > 4.19.0 && DHD_TCP_LIMIT_OUTPUT */ - DHD_RPM(("%s: Exit ret=%d\n", __FUNCTION__, ret)); - -#ifdef DHD_PCIE_RUNTIMEPM - mutex_unlock(&bus->pm_lock); -#endif /* DHD_PCIE_RUNTIMEPM */ return ret; } @@ -1167,20 +1050,15 @@ static int dhdpcie_suspend_dev(struct pci_dev *dev) return BCME_ERROR; } #endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ + DHD_RPM(("%s: Enter\n", __FUNCTION__)); -#if defined(CONFIG_SOC_EXYNOS9810) || defined(CONFIG_SOC_EXYNOS9820) || \ - defined(CONFIG_SOC_EXYNOS9830) || defined(CONFIG_SOC_EXYNOS2100) || \ - defined(CONFIG_SOC_EXYNOS1000) - DHD_ERROR(("%s: Disable L1ss EP side\n", __FUNCTION__)); - exynos_pcie_l1ss_ctrl(0, PCIE_L1SS_CTRL_WIFI); -#endif /* CONFIG_SOC_EXYNOS9810 || CONFIG_SOC_EXYNOS9820 || - * CONFIG_SOC_EXYNOS9830 || CONFIG_SOC_EXYNOS2100 || - * CONFIG_SOC_EXYNOS1000 - */ -#if defined(CONFIG_SOC_GS101) - DHD_ERROR(("%s: Disable L1ss EP side\n", __FUNCTION__)); - exynos_pcie_rc_l1ss_ctrl(0, PCIE_L1SS_CTRL_WIFI, 1); -#endif /* CONFIG_SOC_GS101 */ + + /* + * Disable L1ss on EP and RC side ... defaults to NOP + * If needed implement this function in the dhd_custom_xxx.c + * accordingly. + */ + dhd_plat_l1ss_ctrl(0); dhdpcie_suspend_dump_cfgregs(bus, "BEFORE_EP_SUSPEND"); #if defined(OEM_ANDROID) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) @@ -1225,7 +1103,31 @@ int bcmpcie_set_get_wake(struct dhd_bus *bus, int flag) ret = pch->pkt_wake; pch->total_wake_count += flag; pch->pkt_wake = flag; + DHD_PKT_WAKE_UNLOCK(&pch->pkt_wake_lock, flags); + return ret; +} +int bcmpcie_get_wake(struct dhd_bus *bus) +{ + dhdpcie_info_t *pch = pci_get_drvdata(bus->dev); + unsigned long flags; + int ret; + + DHD_PKT_WAKE_LOCK(&pch->pkt_wake_lock, flags); + ret = pch->pkt_wake; + DHD_PKT_WAKE_UNLOCK(&pch->pkt_wake_lock, flags); + return ret; +} + +int bcmpcie_set_get_wake_pkt_dump(struct dhd_bus *bus, int wake_pkt_dump) +{ + dhdpcie_info_t *pch = pci_get_drvdata(bus->dev); + unsigned long flags; + int ret; + + DHD_PKT_WAKE_LOCK(&pch->pkt_wake_lock, flags); + ret = pch->pkt_wake_dump; + pch->pkt_wake_dump = wake_pkt_dump; DHD_PKT_WAKE_UNLOCK(&pch->pkt_wake_lock, flags); return ret; } @@ -1239,10 +1141,6 @@ static int dhdpcie_resume_dev(struct pci_dev *dev) pci_load_and_free_saved_state(dev, &pch->state); #endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ DHD_RPM(("%s: Enter\n", __FUNCTION__)); -#ifdef OEM_ANDROID -// dev->state_saved = TRUE; -#endif /* OEM_ANDROID */ - pci_restore_state(dev); /* Resture back current bar1 window */ OSL_PCI_WRITE_CONFIG(pch->bus->osh, PCI_BAR1_WIN, 4, pch->bus->curr_bar1_win); @@ -1254,30 +1152,29 @@ static int dhdpcie_resume_dev(struct pci_dev *dev) #endif /* FORCE_TPOWERON */ err = pci_enable_device(dev); if (err) { - printf("%s:pci_enable_device error %d \n", __FUNCTION__, err); + DHD_CONS_ONLY(("%s:pci_enable_device error %d \n", __FUNCTION__, err)); goto out; } pci_set_master(dev); err = pci_set_power_state(dev, PCI_D0); if (err) { - printf("%s:pci_set_power_state error %d \n", __FUNCTION__, err); + DHD_CONS_ONLY(("%s:pci_set_power_state error %d \n", __FUNCTION__, err)); goto out; } + +#ifdef OEM_ANDROID + dev->state_saved = TRUE; +#endif /* OEM_ANDROID */ + pci_restore_state(dev); + BCM_REFERENCE(pch); dhdpcie_suspend_dump_cfgregs(pch->bus, "AFTER_EP_RESUME"); -#if defined(CONFIG_SOC_EXYNOS9810) || defined(CONFIG_SOC_EXYNOS9820) || \ - defined(CONFIG_SOC_EXYNOS9830) || defined(CONFIG_SOC_EXYNOS2100) || \ - defined(CONFIG_SOC_EXYNOS1000) - DHD_ERROR(("%s: Enable L1ss EP side\n", __FUNCTION__)); - exynos_pcie_l1ss_ctrl(1, PCIE_L1SS_CTRL_WIFI); -#endif /* CONFIG_SOC_EXYNOS9810 || CONFIG_SOC_EXYNOS9820 || - * CONFIG_SOC_EXYNOS9830 || CONFIG_SOC_EXYNOS2100 || - * CONFIG_SOC_EXYNOS1000 - */ -#if defined(CONFIG_SOC_GS101) - DHD_ERROR(("%s: Enable L1ss EP side\n", __FUNCTION__)); - exynos_pcie_rc_l1ss_ctrl(1, PCIE_L1SS_CTRL_WIFI, 1); -#endif /* CONFIG_SOC_GS101 */ + + /* + * Re-enable L1ss in Resume path. Implementation defalts to NOP + * If need override in the paltform file + */ + dhd_plat_l1ss_ctrl(1); out: return err; @@ -1292,11 +1189,6 @@ static int dhdpcie_resume_host_dev(dhd_bus_t *bus) DHD_ERROR(("%s: PCIe RC resume failed!!! (%d)\n", __FUNCTION__, bcmerror)); bus->is_linkdown = 1; -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ } return bcmerror; @@ -1316,7 +1208,7 @@ static int dhdpcie_suspend_host_dev(dhd_bus_t *bus) pci_save_state(bus->rc_dev); } else { DHD_ERROR(("%s: RC %x:%x handle is NULL\n", - __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID)); + __FUNCTION__, dhd_plat_get_rc_vendor_id(), dhd_plat_get_rc_device_id())); } #endif /* CONFIG_ARCH_EXYNOS */ bcmerror = dhdpcie_stop_host_dev(bus); @@ -1344,10 +1236,11 @@ dhdpcie_rc_config_read(dhd_bus_t *bus, uint offset) OSL_DELAY(100); } else { DHD_ERROR(("%s: RC %x:%x handle is NULL\n", - __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID)); + __FUNCTION__, dhd_plat_get_rc_vendor_id(), dhd_plat_get_rc_device_id())); } DHD_ERROR(("%s: RC %x:%x offset 0x%x val 0x%x\n", - __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID, offset, val)); + __FUNCTION__, dhd_plat_get_rc_vendor_id(), dhd_plat_get_rc_device_id(), + offset, val)); return (val); } @@ -1423,7 +1316,7 @@ dhdpcie_rc_access_cap(dhd_bus_t *bus, int cap, uint offset, bool is_ext, bool is { if (!(bus->rc_dev)) { DHD_ERROR(("%s: RC %x:%x handle is NULL\n", - __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID)); + __FUNCTION__, dhd_plat_get_rc_vendor_id(), dhd_plat_get_rc_device_id())); return BCME_ERROR; } @@ -1477,7 +1370,10 @@ int dhdpcie_pci_suspend_resume(dhd_bus_t *bus, bool state) struct pci_dev *dev = bus->dev; if (state) { + bus->ptm_ctrl_reg = dhdpcie_bus_cfg_read_dword(bus, PCI_CFG_PTM_CTRL, 4); + dhdpcie_config_save_restore_coherent(bus, state); + #if !defined(BCMPCIE_OOB_HOST_WAKE) && !defined(PCIE_OOB) dhdpcie_pme_active(bus->osh, state); #endif /* !BCMPCIE_OOB_HOST_WAKE && !PCIE_OOB */ @@ -1495,14 +1391,17 @@ int dhdpcie_pci_suspend_resume(dhd_bus_t *bus, bool state) */ dhdpcie_cto_cfg_init(bus, TRUE); } + + dhdpcie_bus_cfg_write_dword(bus, PCI_CFG_PTM_CTRL, 4, bus->ptm_ctrl_reg); + if (PCIE_ENUM_RESET_WAR_ENAB(bus->sih->buscorerev)) { dhdpcie_ssreset_dis_enum_rst(bus); } #if !defined(BCMPCIE_OOB_HOST_WAKE) && !defined(PCIE_OOB) dhdpcie_pme_active(bus->osh, state); #endif /* !BCMPCIE_OOB_HOST_WAKE && !PCIE_OOB */ + dhdpcie_config_save_restore_coherent(bus, state); } - dhdpcie_config_save_restore_coherent(bus, state); #if defined(OEM_ANDROID) #if defined(DHD_HANG_SEND_UP_TEST) if (bus->is_linkdown || @@ -1568,9 +1467,55 @@ dhdpcie_bus_register(void) void dhdpcie_bus_unregister(void) { + unsigned long flags; + dhd_pub_t *dhdp = NULL; + if (!g_dhd_bus) { + DHD_ERROR(("%s: Bus is NULL\n", __FUNCTION__)); + return; + } + dhdp = g_dhd_bus->dhd; + DHD_GENERAL_LOCK(dhdp, flags); + /* Check if bus is in suspend due to wifi off with accel boot */ + if (dhdp->up == FALSE && dhdp->busstate == DHD_BUS_SUSPEND) { + DHD_GENERAL_UNLOCK(dhdp, flags); + DHD_ERROR(("%s Bus is in suspend state\n", __FUNCTION__)); + dhdpcie_pci_suspend_resume(dhdp->bus, FALSE); + } else { + DHD_GENERAL_UNLOCK(dhdp, flags); + } pci_unregister_driver(&dhdpcie_driver); } +#if defined(CONFIG_ARCH_WAIPIO) || defined(CONFIG_SOC_S5E9925) +bool devid_mismatch = FALSE; + +bool dhdpcie_validate_devid(uint16 device) +{ + uint16 config_devid; + +#ifdef BCM4389_CHIP_DEF + config_devid = BCM4389_D11AX_ID; +#elif defined(BCM4375_CHIP) + config_devid = BCM4375_D11AX_ID; +#else + DHD_ERROR(("%s: Unknown dev id, BCMXXXX_CHIP is not defined \n", + __FUNCTION__)); + config_devid = 0; + + return FALSE; +#endif /* BCM4389_CHIP_DEF */ + + DHD_ERROR(("%s: config_devid %X device %X\n", __FUNCTION__, config_devid, device)); + + if ((config_devid == BCM4389_D11AX_ID) && (device == BCM4389_CHIP_ID)) { + /* The dev id is 4389 if OTP is not written. */ + return TRUE; + } + + return config_devid == device; +} +#endif /* CONFIG_ARCH_WAIPIO || CONFIG_SOC_S5E9925 */ + int __devinit dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1583,9 +1528,19 @@ dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto exit; } - printf("PCI_PROBE: bus %X, slot %X,vendor %X, device %X" + DHD_CONS_ONLY(("PCI_PROBE: bus 0x%X, slot 0x%X,vendor 0x%X, device 0x%X" "(good PCI location)\n", pdev->bus->number, - PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device); + PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device)); + +#if defined(CONFIG_ARCH_WAIPIO) || defined(CONFIG_SOC_S5E9925) + if (dhdpcie_validate_devid(pdev->device) == FALSE) { + DHD_ERROR(("%s: dev id and BCMXXXX_CHIP definition is not matched\n", + __FUNCTION__)); + devid_mismatch = TRUE; + err = -ENODEV; + goto exit; + } +#endif /* CONFIG_ARCH_WAIPIO || CONFIG_SOC_S5E9925 */ if (dhdpcie_init_succeeded == TRUE) { DHD_ERROR(("%s(): === Driver Already attached to a BRCM device === \r\n", @@ -1638,16 +1593,13 @@ dhdpcie_detach(dhdpcie_info_t *pch) } void __devexit -dhdpcie_pci_remove(struct pci_dev *pdev) +dhdpcie_pci_stop(struct pci_dev *pdev) { osl_t *osh = NULL; dhdpcie_info_t *pch = NULL; dhd_bus_t *bus = NULL; DHD_TRACE(("%s Enter\n", __FUNCTION__)); - - DHD_MUTEX_LOCK(); - pch = pci_get_drvdata(pdev); bus = pch->bus; osh = pch->osh; @@ -1658,14 +1610,6 @@ dhdpcie_pci_remove(struct pci_dev *pdev) #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ if (bus) { -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - msm_pcie_deregister_event(&bus->pcie_event); -#endif /* CONFIG_ARCH_MSM */ -#ifdef CONFIG_ARCH_EXYNOS - exynos_pcie_deregister_event(&bus->pcie_event); -#endif /* CONFIG_ARCH_EXYNOS */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ bus->rc_dev = NULL; @@ -1696,21 +1640,45 @@ dhdpcie_pci_remove(struct pci_dev *pdev) /* osl detach */ osl_detach(osh); -#if defined(BCMPCIE_OOB_HOST_WAKE) && defined(CUSTOMER_HW2) && \ - defined(CONFIG_ARCH_APQ8084) - brcm_pcie_wake.wake_irq = NULL; - brcm_pcie_wake.data = NULL; -#endif /* BCMPCIE_OOB_HOST_WAKE && CUSTOMR_HW2 && CONFIG_ARCH_APQ8084 */ - dhdpcie_init_succeeded = FALSE; - DHD_MUTEX_UNLOCK(); - DHD_TRACE(("%s Exit\n", __FUNCTION__)); return; } +void __devexit +dhdpcie_pci_remove(struct pci_dev *pdev) +{ + DHD_MUTEX_LOCK(); + DHD_ERROR(("%s Enter\n", __FUNCTION__)); + dhdpcie_pci_stop(pdev); + DHD_MUTEX_UNLOCK(); + return; +} + +void __devexit +dhdpcie_pci_shutdown(struct pci_dev *pdev) +{ + dhdpcie_info_t *pch = NULL; + dhd_bus_t *bus = NULL; + + pch = pci_get_drvdata(pdev); + bus = pch->bus; + DHD_ERROR(("%s Enter\n", __FUNCTION__)); + + /* Stop all interface network queue */ + dhd_bus_stop_queue(bus); + /* Disable IRQ */ + dhdpcie_disable_irq(bus); + /* Kill dpc */ + dhd_dpc_kill(bus->dhd); + /* Stop RPM timer */ + DHD_STOP_RPM_TIMER(bus->dhd); + dhdpcie_busbusy_wait(bus->dhd); + return; +} + /* Enable Linux Msi */ int dhdpcie_enable_msi(struct pci_dev *pdev, unsigned int min_vecs, unsigned int max_vecs) @@ -1744,7 +1712,7 @@ dhdpcie_request_irq(dhdpcie_info_t *dhdpcie_info) { dhd_bus_t *bus = dhdpcie_info->bus; struct pci_dev *pdev = dhdpcie_info->bus->dev; - int host_irq_disabled; + int err = 0; if (!bus->irq_registered) { snprintf(dhdpcie_info->pciname, sizeof(dhdpcie_info->pciname), @@ -1759,13 +1727,14 @@ dhdpcie_request_irq(dhdpcie_info_t *dhdpcie_info) } if (bus->d2h_intr_method == PCIE_MSI) - printf("%s: MSI enabled\n", __FUNCTION__); + printf("%s: MSI enabled, irq=%d\n", __FUNCTION__, pdev->irq); else - printf("%s: INTx enabled\n", __FUNCTION__); + printf("%s: INTx enabled, irq=%d\n", __FUNCTION__, pdev->irq); - if (request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED, - dhdpcie_info->pciname, bus) < 0) { - DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__)); + err = request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED, + dhdpcie_info->pciname, bus); + if (err < 0) { + DHD_ERROR(("%s: request_irq() failed with %d\n", __FUNCTION__, err)); if (bus->d2h_intr_method == PCIE_MSI) { dhdpcie_disable_msi(pdev); } @@ -1778,12 +1747,7 @@ dhdpcie_request_irq(dhdpcie_info_t *dhdpcie_info) DHD_ERROR(("%s: PCI IRQ is already registered\n", __FUNCTION__)); } - host_irq_disabled = dhdpcie_irq_disabled(bus); - if (host_irq_disabled) { - DHD_ERROR(("%s: PCIe IRQ was disabled(%d), so, enabled it again\n", - __FUNCTION__, host_irq_disabled)); - dhdpcie_enable_irq(bus); - } + dhdpcie_enable_irq_loop(bus); DHD_TRACE(("%s %s\n", __FUNCTION__, dhdpcie_info->pciname)); @@ -1837,6 +1801,9 @@ Description: Access PCI configuration space, retrieve PCI allocated resources , updates in resource structure. */ +#ifdef DHD_DEBUG_REG_DUMP +uint64 regs_addr; +#endif /* DHD_DEBUG_REG_DUMP */ int dhdpcie_get_resource(dhdpcie_info_t *dhdpcie_info) { phys_addr_t bar0_addr, bar1_addr; @@ -1865,7 +1832,7 @@ int dhdpcie_get_resource(dhdpcie_info_t *dhdpcie_info) do { if (pci_enable_device(pdev)) { - printf("%s: Cannot enable PCI device\n", __FUNCTION__); + DHD_CONS_ONLY(("%s: Cannot enable PCI device\n", __FUNCTION__)); break; } pci_set_master(pdev); @@ -1876,9 +1843,9 @@ int dhdpcie_get_resource(dhdpcie_info_t *dhdpcie_info) bar1_size = pci_resource_len(pdev, 2); if ((bar1_size == 0) || (bar1_addr == 0)) { - printf("%s: BAR1 Not enabled for this device size(%ld)," + DHD_CONS_ONLY(("%s: BAR1 Not enabled for this device size(%ld)," " addr(0x"PRINTF_RESOURCE")\n", - __FUNCTION__, bar1_size, bar1_addr); + __FUNCTION__, bar1_size, bar1_addr)); goto err; } @@ -1921,7 +1888,10 @@ int dhdpcie_get_resource(dhdpcie_info_t *dhdpcie_info) __FUNCTION__, dhdpcie_info->regs, bar0_addr)); DHD_TRACE(("%s:Phys addr : tcm_space = %p base addr 0x"PRINTF_RESOURCE" \n", __FUNCTION__, dhdpcie_info->tcm, bar1_addr)); - +#ifdef DHD_DEBUG_REG_DUMP + regs_addr = (uint64)dhdpcie_info->regs; + DHD_ERROR(("%s: saved regs_addr = 0x%llx\n", __FUNCTION__, regs_addr)); +#endif /* DHD_DEBUG_REG_DUMP */ return 0; /* SUCCESS */ } while (0); err: @@ -1983,49 +1953,6 @@ void dhdpcie_dump_resource(dhd_bus_t *bus) pch->bar1_size)); } -#ifdef SUPPORT_LINKDOWN_RECOVERY -#if defined(CONFIG_ARCH_MSM) || defined(CONFIG_ARCH_EXYNOS) -void dhdpcie_linkdown_cb(struct_pcie_notify *noti) -{ - struct pci_dev *pdev = (struct pci_dev *)noti->user; - dhdpcie_info_t *pch = NULL; - - if (pdev) { - pch = pci_get_drvdata(pdev); - if (pch) { - dhd_bus_t *bus = pch->bus; - if (bus) { - dhd_pub_t *dhd = bus->dhd; - if (dhd) { -#ifdef CONFIG_ARCH_MSM - DHD_ERROR(("%s: Set no_cfg_restore flag\n", - __FUNCTION__)); - bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ -#ifdef DHD_SSSR_DUMP - if (dhd->fis_triggered) { - DHD_ERROR(("%s: PCIe linkdown due to FIS, Ignore\n", - __FUNCTION__)); - } else -#endif /* DHD_SSSR_DUMP */ - { - DHD_ERROR(("%s: Event HANG send up " - "due to PCIe linkdown\n", - __FUNCTION__)); - bus->is_linkdown = 1; - dhd->hang_reason = - HANG_REASON_PCIE_LINK_DOWN_RC_DETECT; - dhd_os_send_hang_message(dhd); - } - } - } - } - } - -} -#endif /* CONFIG_ARCH_MSM || CONFIG_ARCH_EXYNOS */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - int dhdpcie_init(struct pci_dev *pdev) { @@ -2057,8 +1984,12 @@ int dhdpcie_init(struct pci_dev *pdev) adapter->bus_num = pdev->bus->number; adapter->slot_num = PCI_SLOT(pdev->devfn); adapter->pci_dev = pdev; - } else + } else { DHD_ERROR(("%s: can't find adapter info for this chip\n", __FUNCTION__)); +#ifdef ADAPTER_IDX + break; +#endif + } osl_static_mem_init(osh, adapter); /* allocate linux spcific pcie structure here */ @@ -2110,6 +2041,17 @@ int dhdpcie_init(struct pci_dev *pdev) } #endif /* USE_SMMU_ARCH_MSM */ +#ifdef DHD_SET_PCIE_DMA_MASK_FOR_GS101 + /* S.SLSI PCIe DMA engine cannot support 64 bit bus address. Hence, set 36 bit */ + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(DHD_PCIE_DMA_MASK_FOR_GS101)) || + pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(DHD_PCIE_DMA_MASK_FOR_GS101))) { + DHD_ERROR(("%s: DMA set %d bit mask failed.\n", + __FUNCTION__, DHD_PCIE_DMA_MASK_FOR_GS101)); + return -EINVAL; + } +#endif /* DHD_SET_PCIE_DMA_MASK_FOR_GS101 */ + #ifdef DHD_WAKE_STATUS /* Initialize pkt_wake_lock */ spin_lock_init(&dhdpcie_info->pkt_wake_lock); @@ -2153,9 +2095,11 @@ int dhdpcie_init(struct pci_dev *pdev) /* if rc_dev is still NULL, try to get from vendor/device IDs */ if (bus->rc_dev == NULL) { - bus->rc_dev = pci_get_device(PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID, NULL); + bus->rc_dev = pci_get_device(dhd_plat_get_rc_vendor_id(), + dhd_plat_get_rc_device_id(), NULL); DHD_ERROR(("%s: rc_dev from pci_get_device (%x:%x) is %p\n", __FUNCTION__, - PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID, bus->rc_dev)); + dhd_plat_get_rc_vendor_id(), dhd_plat_get_rc_device_id(), + bus->rc_dev)); } bus->rc_ep_aspm_cap = dhd_bus_is_rc_ep_aspm_capable(bus); @@ -2169,34 +2113,9 @@ int dhdpcie_init(struct pci_dev *pdev) } #endif /* FORCE_TPOWERON */ -#if defined(BCMPCIE_OOB_HOST_WAKE) && defined(CUSTOMER_HW2) && \ - defined(CONFIG_ARCH_APQ8084) - brcm_pcie_wake.wake_irq = wlan_oob_irq; - brcm_pcie_wake.data = bus; -#endif /* BCMPCIE_OOB_HOST_WAKE && CUSTOMR_HW2 && CONFIG_ARCH_APQ8084 */ - #ifdef DONGLE_ENABLE_ISOLATION bus->dhd->dongle_isolation = TRUE; #endif /* DONGLE_ENABLE_ISOLATION */ -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - bus->pcie_event.events = MSM_PCIE_EVENT_LINKDOWN; - bus->pcie_event.user = pdev; - bus->pcie_event.mode = MSM_PCIE_TRIGGER_CALLBACK; - bus->pcie_event.callback = dhdpcie_linkdown_cb; - bus->pcie_event.options = MSM_PCIE_CONFIG_NO_RECOVERY; - msm_pcie_register_event(&bus->pcie_event); - bus->no_cfg_restore = FALSE; -#endif /* CONFIG_ARCH_MSM */ -#ifdef CONFIG_ARCH_EXYNOS - bus->pcie_event.events = EXYNOS_PCIE_EVENT_LINKDOWN; - bus->pcie_event.user = pdev; - bus->pcie_event.mode = EXYNOS_PCIE_TRIGGER_CALLBACK; - bus->pcie_event.callback = dhdpcie_linkdown_cb; - exynos_pcie_register_event(&bus->pcie_event); -#endif /* CONFIG_ARCH_EXYNOS */ - bus->read_shm_fail = FALSE; -#endif /* SUPPORT_LINKDOWN_RECOVERY */ if (bus->intr) { /* Register interrupt callback, but mask it (not operational yet). */ @@ -2227,6 +2146,7 @@ int dhdpcie_init(struct pci_dev *pdev) /* Ensure BAR1 switch feature enable if needed before FW download */ dhdpcie_bar1_window_switch_enab(bus); + dhd_init_bar1_switch_lock(bus); #if defined(BCMDHD_MODULAR) && defined(INSMOD_FW_LOAD) if (1) @@ -2249,16 +2169,16 @@ int dhdpcie_init(struct pci_dev *pdev) } /* Attach to the OS network interface */ - DHD_TRACE(("%s(): Calling dhd_register_if() \n", __FUNCTION__)); + DHD_TRACE(("%s(): Calling dhd_attach_net() \n", __FUNCTION__)); if (dhd_attach_net(bus->dhd, TRUE)) { - DHD_ERROR(("%s(): ERROR.. dhd_register_if() failed\n", __FUNCTION__)); + DHD_ERROR(("%s(): ERROR.. dhd_attach_net() failed\n", __FUNCTION__)); break; } dhdpcie_init_succeeded = TRUE; -#ifdef CONFIG_ARCH_MSM +#if defined(CONFIG_ARCH_MSM) && defined(CONFIG_SEC_PCIE_L1SS) sec_pcie_set_use_ep_loaded(bus->rc_dev); -#endif /* CONFIG_ARCH_MSM */ +#endif /* CONFIG_ARCH_MSM && CONFIG_SEC_PCIE_L1SS */ #ifdef DHD_PCIE_NATIVE_RUNTIMEPM pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); @@ -2293,7 +2213,8 @@ int dhdpcie_init(struct pci_dev *pdev) if (dhdpcie_info) dhdpcie_detach(dhdpcie_info); - pci_disable_device(pdev); + if (adapter) + pci_disable_device(pdev); if (osh) osl_detach(osh); if (adapter != NULL) { @@ -2319,12 +2240,15 @@ dhdpcie_free_irq(dhd_bus_t *bus) if (bus) { pdev = bus->dev; if (bus->irq_registered) { -#if defined(SET_PCIE_IRQ_CPU_CORE) && defined(CONFIG_ARCH_SM8150) +#if defined(SET_PCIE_IRQ_CPU_CORE) || defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON) || \ + defined(CLEAN_IRQ_AFFINITY_HINT) /* clean up the affinity_hint before * the unregistration of PCIe irq */ (void)irq_set_affinity_hint(pdev->irq, NULL); -#endif /* SET_PCIE_IRQ_CPU_CORE && CONFIG_ARCH_SM8150 */ +#endif /* SET_PCIE_IRQ_CPU_CORE || DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON || + * CLEAN_IRQ_AFFINITY_HINT + */ free_irq(pdev->irq, bus); bus->irq_registered = FALSE; if (bus->d2h_intr_method == PCIE_MSI) { @@ -2360,6 +2284,7 @@ irqreturn_t dhdpcie_isr(int irq, void *arg) { dhd_bus_t *bus = (dhd_bus_t*)arg; + bus->prev_isr_entry_time = bus->isr_entry_time; bus->isr_entry_time = OSL_LOCALTIME_NS(); if (!dhdpcie_bus_isr(bus)) { DHD_LOG_MEM(("%s: dhdpcie_bus_isr returns with FALSE\n", __FUNCTION__)); @@ -2410,32 +2335,36 @@ dhdpcie_enable_irq(dhd_bus_t *bus) return BCME_OK; } +void +dhdpcie_enable_irq_loop(dhd_bus_t *bus) +{ + /* Enable IRQ in a loop till host_irq_disable_count becomes 0 */ + uint host_irq_disable_count = dhdpcie_irq_disabled(bus); + while (host_irq_disable_count--) { + dhdpcie_enable_irq(bus); /* Enable back interrupt!! */ + } +} + int dhdpcie_irq_disabled(dhd_bus_t *bus) { struct irq_desc *desc = NULL; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) - desc = irq_data_to_desc(irq_get_irq_data(bus->dev->irq)); -#else +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)) desc = irq_to_desc(bus->dev->irq); +#else // (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)) + desc = irq_data_to_desc(irq_get_irq_data(bus->dev->irq)); #endif // (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)) + /* depth will be zero, if enabled */ return desc->depth; } -#if defined(CONFIG_ARCH_EXYNOS) -int pcie_ch_num = EXYNOS_PCIE_CH_NUM; -#endif /* CONFIG_ARCH_EXYNOS */ - int dhdpcie_start_host_dev(dhd_bus_t *bus) { int ret = 0; #ifdef CONFIG_ARCH_MSM -#ifdef SUPPORT_LINKDOWN_RECOVERY - int options = 0; -#endif /* SUPPORT_LINKDOWN_RECOVERY */ #endif /* CONFIG_ARCH_MSM */ DHD_TRACE(("%s Enter:\n", __FUNCTION__)); @@ -2447,27 +2376,16 @@ dhdpcie_start_host_dev(dhd_bus_t *bus) return BCME_ERROR; } -#ifdef CONFIG_ARCH_EXYNOS - exynos_pcie_pm_resume(pcie_ch_num); -#endif /* CONFIG_ARCH_EXYNOS */ + ret = dhd_plat_pcie_resume(bus->dhd->plat_info); + #ifdef CONFIG_ARCH_MSM -#ifdef SUPPORT_LINKDOWN_RECOVERY - if (bus->no_cfg_restore) { - options = MSM_PCIE_CONFIG_NO_CFG_RESTORE; - } - ret = msm_pcie_pm_control(MSM_PCIE_RESUME, bus->dev->bus->number, - bus->dev, NULL, options); - if (bus->no_cfg_restore && !ret) { - msm_pcie_recover_config(bus->dev); - bus->no_cfg_restore = 0; - } -#else ret = msm_pcie_pm_control(MSM_PCIE_RESUME, bus->dev->bus->number, bus->dev, NULL, 0); -#endif /* SUPPORT_LINKDOWN_RECOVERY */ #endif /* CONFIG_ARCH_MSM */ #ifdef CONFIG_ARCH_TEGRA +#ifndef CONFIG_ARCH_TEGRA_210_SOC ret = tegra_pcie_pm_resume(); +#endif /* CONFIG_ARCH_TEGRA_210_SOC */ #endif /* CONFIG_ARCH_TEGRA */ if (ret) { @@ -2485,9 +2403,6 @@ dhdpcie_stop_host_dev(dhd_bus_t *bus) { int ret = 0; #ifdef CONFIG_ARCH_MSM -#ifdef SUPPORT_LINKDOWN_RECOVERY - int options = 0; -#endif /* SUPPORT_LINKDOWN_RECOVERY */ #endif /* CONFIG_ARCH_MSM */ DHD_TRACE(("%s Enter:\n", __FUNCTION__)); @@ -2500,24 +2415,16 @@ dhdpcie_stop_host_dev(dhd_bus_t *bus) return BCME_ERROR; } -#ifdef CONFIG_ARCH_EXYNOS - exynos_pcie_pm_suspend(pcie_ch_num); -#endif /* CONFIG_ARCH_EXYNOS */ -#ifdef CONFIG_ARCH_MSM -#ifdef SUPPORT_LINKDOWN_RECOVERY - if (bus->no_cfg_restore) { - options = MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN; - } + dhd_plat_pcie_suspend(bus->dhd->plat_info); - ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus->dev->bus->number, - bus->dev, NULL, options); -#else +#ifdef CONFIG_ARCH_MSM ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus->dev->bus->number, bus->dev, NULL, 0); -#endif /* SUPPORT_LINKDOWN_RECOVERY */ #endif /* CONFIG_ARCH_MSM */ #ifdef CONFIG_ARCH_TEGRA +#ifndef CONFIG_ARCH_TEGRA_210_SOC ret = tegra_pcie_pm_suspend(); +#endif /* CONFIG_ARCH_TEGRA_210_SOC */ #endif /* CONFIG_ARCH_TEGRA */ if (ret) { DHD_ERROR(("Failed to stop PCIe link\n")); @@ -2571,8 +2478,8 @@ dhdpcie_enable_device(dhd_bus_t *bus) return BCME_ERROR; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) && \ - (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)) && !defined(CONFIG_SOC_EXYNOS8890) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) && (LINUX_VERSION_CODE < \ + KERNEL_VERSION(3, 19, 0)) && !defined(CONFIG_SOC_EXYNOS8890) /* Updated with pci_load_and_free_saved_state to compatible * with Kernel version 3.14.0 to 3.18.41. */ @@ -2594,11 +2501,6 @@ dhdpcie_enable_device(dhd_bus_t *bus) /* Check if the PCIe link is down */ if (vid == (uint32)-1) { bus->is_linkdown = 1; -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - bus->no_cfg_restore = TRUE; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ } return BCME_ERROR; } @@ -2648,9 +2550,9 @@ dhdpcie_alloc_resource(dhd_bus_t *bus) bar1_size = pci_resource_len(bus->dev, 2); if ((bar1_size == 0) || (bar1_addr == 0)) { - printf("%s: BAR1 Not enabled for this device size(%ld)," + DHD_CONS_ONLY(("%s: BAR1 Not enabled for this device size(%ld)," " addr(0x"PRINTF_RESOURCE")\n", - __FUNCTION__, bar1_size, bar1_addr); + __FUNCTION__, bar1_size, bar1_addr)); break; } @@ -2678,7 +2580,10 @@ dhdpcie_alloc_resource(dhd_bus_t *bus) __FUNCTION__, dhdpcie_info->regs, bar0_addr)); DHD_TRACE(("%s:Phys addr : tcm_space = %p base addr 0x"PRINTF_RESOURCE" \n", __FUNCTION__, dhdpcie_info->tcm, bar1_addr)); - +#ifdef DHD_DEBUG_REG_DUMP + regs_addr = (uint64)dhdpcie_info->regs; + DHD_ERROR(("%s: saved regs_addr = 0x%llx\n", __FUNCTION__, regs_addr)); +#endif /* DHD_DEBUG_REG_DUMP */ return 0; } while (0); @@ -2758,6 +2663,9 @@ dhdpcie_bus_request_irq(struct dhd_bus *bus) #ifdef BCMPCIE_OOB_HOST_WAKE #ifdef CONFIG_BCMDHD_GET_OOB_STATE extern int dhd_get_wlan_oob_gpio(void); +#ifdef PRINT_WAKEUP_GPIO_STATUS +extern int dhd_get_wlan_oob_gpio_number(void); +#endif /* PRINT_WAKEUP_GPIO_STATUS */ #endif /* CONFIG_BCMDHD_GET_OOB_STATE */ int dhdpcie_get_oob_irq_level(void) @@ -2771,7 +2679,16 @@ int dhdpcie_get_oob_irq_level(void) #endif /* CONFIG_BCMDHD_GET_OOB_STATE */ return gpio_level; } - +#ifdef PRINT_WAKEUP_GPIO_STATUS +int dhdpcie_get_oob_gpio_number(void) +{ + int gpio_number = BCME_UNSUPPORTED; +#ifdef CONFIG_BCMDHD_GET_OOB_STATE + gpio_number = dhd_get_wlan_oob_gpio_number(); +#endif /* CONFIG_BCMDHD_GET_OOB_STATE */ + return gpio_number; +} +#endif /* PRINT_WAKEUP_GPIO_STATUS */ int dhdpcie_get_oob_irq_status(struct dhd_bus *bus) { dhdpcie_info_t *pch; @@ -2872,7 +2789,8 @@ void dhdpcie_oob_intr_set(dhd_bus_t *bus, bool enable) static irqreturn_t wlan_oob_irq_isr(int irq, void *data) { dhd_bus_t *bus = (dhd_bus_t *)data; - DHD_TRACE(("%s: IRQ ISR\n", __FUNCTION__)); + dhdpcie_oob_intr_set(bus, FALSE); + DHD_INTR(("%s: IRQ ISR\n", __FUNCTION__)); bus->last_oob_irq_isr_time = OSL_LOCALTIME_NS(); return IRQ_WAKE_THREAD; } @@ -2882,12 +2800,12 @@ static irqreturn_t wlan_oob_irq(int irq, void *data) { dhd_bus_t *bus; bus = (dhd_bus_t *)data; - dhdpcie_oob_intr_set(bus, FALSE); #ifdef DHD_USE_PCIE_OOB_THREADED_IRQ - DHD_TRACE(("%s: IRQ Thread\n", __FUNCTION__)); + DHD_INTR(("%s: IRQ Thread\n", __FUNCTION__)); bus->last_oob_irq_thr_time = OSL_LOCALTIME_NS(); #else - DHD_TRACE(("%s: IRQ ISR\n", __FUNCTION__)); + dhdpcie_oob_intr_set(bus, FALSE); + DHD_INTR(("%s: IRQ ISR\n", __FUNCTION__)); bus->last_oob_irq_isr_time = OSL_LOCALTIME_NS(); #endif /* DHD_USE_PCIE_OOB_THREADED_IRQ */ @@ -2898,17 +2816,10 @@ static irqreturn_t wlan_oob_irq(int irq, void *data) bus->oob_intr_count++; #ifdef DHD_WAKE_STATUS -#ifdef DHD_PCIE_RUNTIMEPM - /* This condition is for avoiding counting of wake up from Runtime PM */ - if (bus->chk_pm) -#endif /* DHD_PCIE_RUNTIMPM */ { bcmpcie_set_get_wake(bus, 1); } #endif /* DHD_WAKE_STATUS */ -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(bus->dhd, FALSE, wlan_oob_irq); -#endif /* DHD_PCIE_RUNTIMPM */ #ifdef DHD_PCIE_NATIVE_RUNTIMEPM dhd_bus_wakeup_work(bus->dhd); #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ @@ -3134,197 +3045,6 @@ dhd_os_ib_set_device_wake(struct dhd_bus *bus, bool val) } #endif /* PCIE_OOB */ -#ifdef DHD_PCIE_RUNTIMEPM -bool dhd_runtimepm_state(dhd_pub_t *dhd) -{ - dhd_bus_t *bus; - unsigned long flags; - bus = dhd->bus; - - DHD_GENERAL_LOCK(dhd, flags); - bus->idlecount++; - - DHD_TRACE(("%s : Enter \n", __FUNCTION__)); - - if (dhd_query_bus_erros(dhd)) { - /* Becasue bus_error/dongle_trap ... etc, - * driver don't allow enter suspend, return FALSE - */ - DHD_GENERAL_UNLOCK(dhd, flags); - return FALSE; - } - - if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) { - bus->idlecount = 0; - if (DHD_BUS_BUSY_CHECK_IDLE(dhd) && !DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd) && - !DHD_CHECK_CFG_IN_PROGRESS(dhd) && !dhd_os_check_wakelock_all(bus->dhd)) { - DHD_RPM(("%s: DHD Idle state!! - idletime :%d, wdtick :%d \n", - __FUNCTION__, bus->idletime, dhd_runtimepm_ms)); - bus->bus_wake = 0; - DHD_BUS_BUSY_SET_RPM_SUSPEND_IN_PROGRESS(dhd); - bus->runtime_resume_done = FALSE; - /* stop all interface network queue. */ - dhd_bus_stop_queue(bus); - DHD_GENERAL_UNLOCK(dhd, flags); - /* RPM suspend is failed, return FALSE then re-trying */ - if (dhdpcie_set_suspend_resume(bus, TRUE)) { - DHD_ERROR(("%s: exit with wakelock \n", __FUNCTION__)); - DHD_GENERAL_LOCK(dhd, flags); - DHD_BUS_BUSY_CLEAR_RPM_SUSPEND_IN_PROGRESS(dhd); - dhd_os_busbusy_wake(bus->dhd); - bus->runtime_resume_done = TRUE; - /* It can make stuck NET TX Queue without below */ - dhd_bus_start_queue(bus); - DHD_GENERAL_UNLOCK(dhd, flags); - if (bus->dhd->rx_pending_due_to_rpm) { - /* Reschedule tasklet to process Rx frames */ - DHD_ERROR(("%s: Schedule DPC to process pending" - " Rx packets\n", __FUNCTION__)); - /* irq will be enabled at the end of dpc */ - dhd_schedule_delayed_dpc_on_dpc_cpu(bus->dhd, 0); - } else { - /* enabling host irq deferred from system suspend */ - if (dhdpcie_irq_disabled(bus)) { - dhdpcie_enable_irq(bus); - /* increasing intrrupt count when it enabled */ - bus->resume_intr_enable_count++; - } - } - smp_wmb(); - wake_up(&bus->rpm_queue); - return FALSE; - } - - DHD_GENERAL_LOCK(dhd, flags); - DHD_BUS_BUSY_CLEAR_RPM_SUSPEND_IN_PROGRESS(dhd); - DHD_BUS_BUSY_SET_RPM_SUSPEND_DONE(dhd); - /* For making sure NET TX Queue active */ - dhd_bus_start_queue(bus); - DHD_GENERAL_UNLOCK(dhd, flags); - - wait_event(bus->rpm_queue, bus->bus_wake); - - DHD_GENERAL_LOCK(dhd, flags); - DHD_BUS_BUSY_CLEAR_RPM_SUSPEND_DONE(dhd); - DHD_BUS_BUSY_SET_RPM_RESUME_IN_PROGRESS(dhd); - DHD_GENERAL_UNLOCK(dhd, flags); - - dhdpcie_set_suspend_resume(bus, FALSE); - - DHD_GENERAL_LOCK(dhd, flags); - DHD_BUS_BUSY_CLEAR_RPM_RESUME_IN_PROGRESS(dhd); - dhd_os_busbusy_wake(bus->dhd); - /* Inform the wake up context that Resume is over */ - bus->runtime_resume_done = TRUE; - /* For making sure NET TX Queue active */ - dhd_bus_start_queue(bus); - DHD_GENERAL_UNLOCK(dhd, flags); - - if (bus->dhd->rx_pending_due_to_rpm) { - /* Reschedule tasklet to process Rx frames */ - DHD_ERROR(("%s: Schedule DPC to process pending Rx packets\n", - __FUNCTION__)); - bus->rpm_sched_dpc_time = OSL_LOCALTIME_NS(); - dhd_sched_dpc(bus->dhd); - } - - /* enabling host irq deferred from system suspend */ - if (dhdpcie_irq_disabled(bus)) { - dhdpcie_enable_irq(bus); - /* increasing intrrupt count when it enabled */ - bus->resume_intr_enable_count++; - } - - smp_wmb(); - wake_up(&bus->rpm_queue); - DHD_RPM(("%s : runtime resume ended \n", __FUNCTION__)); - return TRUE; - } else { - DHD_GENERAL_UNLOCK(dhd, flags); - /* Since one of the contexts are busy (TX, IOVAR or RX) - * we should not suspend - */ - DHD_ERROR(("%s : bus is active with dhd_bus_busy_state = 0x%x\n", - __FUNCTION__, dhd->dhd_bus_busy_state)); - return FALSE; - } - } - - DHD_GENERAL_UNLOCK(dhd, flags); - return FALSE; -} /* dhd_runtimepm_state */ - -/* - * dhd_runtime_bus_wake - * TRUE - related with runtime pm context - * FALSE - It isn't invloved in runtime pm context - */ -bool dhd_runtime_bus_wake(dhd_bus_t *bus, bool wait, void *func_addr) -{ - unsigned long flags; - bus->idlecount = 0; - DHD_TRACE(("%s : enter\n", __FUNCTION__)); - if (bus->dhd->up == FALSE) { - DHD_INFO(("%s : dhd is not up\n", __FUNCTION__)); - return FALSE; - } - - DHD_GENERAL_LOCK(bus->dhd, flags); - if (DHD_BUS_BUSY_CHECK_RPM_ALL(bus->dhd)) { - /* Wake up RPM state thread if it is suspend in progress or suspended */ - if (DHD_BUS_BUSY_CHECK_RPM_SUSPEND_IN_PROGRESS(bus->dhd) || - DHD_BUS_BUSY_CHECK_RPM_SUSPEND_DONE(bus->dhd)) { - bus->bus_wake = 1; - - DHD_GENERAL_UNLOCK(bus->dhd, flags); - - if (dhd_msg_level & DHD_RPM_VAL) - DHD_ERROR_RLMT(("%s: Runtime Resume is called in %pf\n", __FUNCTION__, func_addr)); - smp_wmb(); - wake_up(&bus->rpm_queue); - /* No need to wake up the RPM state thread */ - } else if (DHD_BUS_BUSY_CHECK_RPM_RESUME_IN_PROGRESS(bus->dhd)) { - DHD_GENERAL_UNLOCK(bus->dhd, flags); - } - - /* If wait is TRUE, function with wait = TRUE will be wait in here */ - if (wait) { - if (!wait_event_timeout(bus->rpm_queue, bus->runtime_resume_done, - msecs_to_jiffies(RPM_WAKE_UP_TIMEOUT))) { - DHD_ERROR(("%s: RPM_WAKE_UP_TIMEOUT error\n", __FUNCTION__)); - return FALSE; - } - } else { - DHD_INFO(("%s: bus wakeup but no wait until resume done\n", __FUNCTION__)); - } - /* If it is called from RPM context, it returns TRUE */ - return TRUE; - } - - DHD_GENERAL_UNLOCK(bus->dhd, flags); - - return FALSE; -} - -bool dhdpcie_runtime_bus_wake(dhd_pub_t *dhdp, bool wait, void* func_addr) -{ - dhd_bus_t *bus = dhdp->bus; - return dhd_runtime_bus_wake(bus, wait, func_addr); -} - -void dhdpcie_block_runtime_pm(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - bus->idletime = 0; -} - -bool dhdpcie_is_resume_done(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - return bus->runtime_resume_done; -} -#endif /* DHD_PCIE_RUNTIMEPM */ - struct device * dhd_bus_to_dev(dhd_bus_t *bus) { struct pci_dev *pdev; @@ -3351,23 +3071,23 @@ dhd_dongle_mem_dump(void) g_dhd_bus->dhd->memdump_enabled = DUMP_MEMFILE_BUGON; g_dhd_bus->dhd->memdump_type = DUMP_TYPE_AP_ABNORMAL_ACCESS; -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(g_dhd_bus->dhd, TRUE, __builtin_return_address(0)); -#endif /* DHD_PCIE_RUNTIMEPM */ - dhd_bus_mem_dump(g_dhd_bus->dhd); return 0; } +#ifndef BCMDHD_MDRIVER EXPORT_SYMBOL(dhd_dongle_mem_dump); +#endif #endif /* DHD_FW_COREDUMP */ -#ifdef CONFIG_ARCH_MSM +#if defined(CONFIG_ARCH_MSM) && defined(CONFIG_SEC_PCIE_L1SS) void dhd_bus_inform_ep_loaded_to_rc(dhd_pub_t *dhdp, bool up) { - sec_pcie_set_ep_driver_loaded(dhdp->bus->rc_dev, up); + if (dhdp->bus->rc_dev) { + sec_pcie_set_ep_driver_loaded(dhdp->bus->rc_dev, up); + } } -#endif /* CONFIG_ARCH_MSM */ +#endif /* CONFIG_ARCH_MSM && CONFIG_SEC_PCIE_L1SS */ bool dhd_bus_check_driver_up(void) @@ -3389,4 +3109,6 @@ dhd_bus_check_driver_up(void) return isup; } +#ifndef BCMDHD_MDRIVER EXPORT_SYMBOL(dhd_bus_check_driver_up); +#endif diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pktlog.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pktlog.c old mode 100755 new mode 100644 index 0d573444c593..f6d240d9884f --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pktlog.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pktlog.c @@ -1,7 +1,7 @@ /* * DHD debugability packet logging support * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -32,6 +32,7 @@ #include #include #include +#include #ifdef DHD_COMPACT_PKT_LOG #include @@ -41,6 +42,7 @@ #include #include #include <802.11.h> +#include <802.11u.h> #include #include #include @@ -129,9 +131,37 @@ static int dhd_cpkt_log_init_tt(dhd_pub_t *dhdp); static void dhd_cpkt_log_deinit_tt(dhd_pub_t *dhdp); #endif /* DHD_COMPACT_PKT_LOG */ +#ifdef DHD_PKT_LOGGING_DBGRING +#define DHD_PKT_LOGGING_DBGRING_MAX_SIZE 400u +const char dhd_eap_pattern[] = "12 0xffff 0x888e"; +const char dhd_arp_pattern[] = "12 0xffff 0x0806"; +const char dhd_icmp_pattern[] = + "12 0xffffff0000000000000000ff 0x080045000000000000000001"; +const char dhd_icmpv6_pattern[] = + "12 0xfffff00000000000ff 0x86dd6000000000003a"; +const char dhd_dhcp_pattern_01[] = + "12 0xffffff0000000000000000ff00000000000000000000ffffffff" + " 0x0800450000000000000000110000000000000000000000430044"; +const char dhd_dhcp_pattern_02[] = + "12 0xffffff0000000000000000ff00000000000000000000ffffffff" + " 0x0800450000000000000000110000000000000000000000440043"; +const char dhd_dns_pattern_01[] = + "12 0xffffff0000000000000000ff000000000000000000000000ffff" + " 0x0800450000000000000000110000000000000000000000000035"; +const char dhd_dns_pattern_02[] = + "12 0xffffff0000000000000000ff00000000000000000000ffff0000" + " 0x0800450000000000000000110000000000000000000000350000"; +const char dhd_dns_pattern_03[] = + "12 0xffffff0000000000000000ff00000000000000000000ffffffff" + " 0x0800450000000000000000110000000000000000000014e914e9"; +#endif /* DHD_PKT_LOGGING_DBGRING */ + int dhd_os_attach_pktlog(dhd_pub_t *dhdp) { +#ifdef DHD_PKT_LOGGING_DBGRING + char filter_pattern[MAX_FILTER_PATTERN_LEN]; +#endif /* DHD_PKT_LOGGING_DBGRING */ dhd_pktlog_t *pktlog; if (!dhdp) { @@ -139,7 +169,7 @@ dhd_os_attach_pktlog(dhd_pub_t *dhdp) return -EINVAL; } - pktlog = (dhd_pktlog_t *)MALLOCZ(dhdp->osh, sizeof(dhd_pktlog_t)); + pktlog = (dhd_pktlog_t *)VMALLOCZ(dhdp->osh, sizeof(dhd_pktlog_t)); if (unlikely(!pktlog)) { DHD_ERROR(("%s(): could not allocate memory for - " "dhd_pktlog_t\n", __FUNCTION__)); @@ -150,6 +180,9 @@ dhd_os_attach_pktlog(dhd_pub_t *dhdp) pktlog->dhdp = dhdp; OSL_ATOMIC_INIT(dhdp->osh, &pktlog->pktlog_status); +#ifdef DHD_PKT_LOGGING_DBGRING + OSL_ATOMIC_INIT(dhdp->osh, &pktlog->enable); +#endif /* DHD_PKT_LOGGING_DBGRING */ /* pktlog ring */ dhdp->pktlog->pktlog_ring = dhd_pktlog_ring_init(dhdp, MIN_PKTLOG_LEN); @@ -158,6 +191,16 @@ dhd_os_attach_pktlog(dhd_pub_t *dhdp) dhd_cpkt_log_init_tt(dhdp); #endif +#ifdef DHD_PKT_LOGGING_DBGRING +/* By default, EAP, ARP, ICMP, ICMPV6, DHCP packets are allowed. */ + DHD_PKTLOG_FILTER_ADD(dhd_eap_pattern, filter_pattern, dhdp); + DHD_PKTLOG_FILTER_ADD(dhd_arp_pattern, filter_pattern, dhdp); + DHD_PKTLOG_FILTER_ADD(dhd_icmp_pattern, filter_pattern, dhdp); + DHD_PKTLOG_FILTER_ADD(dhd_icmpv6_pattern, filter_pattern, dhdp); + DHD_PKTLOG_FILTER_ADD(dhd_dhcp_pattern_01, filter_pattern, dhdp); + DHD_PKTLOG_FILTER_ADD(dhd_dhcp_pattern_02, filter_pattern, dhdp); +#endif /* DHD_PKT_LOGGING_DBGRING */ + DHD_ERROR(("%s(): dhd_os_attach_pktlog attach\n", __FUNCTION__)); return BCME_OK; @@ -178,13 +221,80 @@ dhd_os_detach_pktlog(dhd_pub_t *dhdp) dhd_cpkt_log_deinit_tt(dhdp); #endif /* DHD_COMPACT_PKT_LOG */ - DHD_ERROR(("%s(): dhd_os_attach_pktlog detach\n", __FUNCTION__)); + DHD_INFO(("%s(): dhd_os_attach_pktlog detach\n", __FUNCTION__)); - MFREE(dhdp->osh, dhdp->pktlog, sizeof(dhd_pktlog_t)); + VMFREE(dhdp->osh, dhdp->pktlog, sizeof(dhd_pktlog_t)); return BCME_OK; } +#ifdef DHD_PKT_LOGGING_DBGRING +int dhd_pktlog_is_enabled(dhd_pub_t *dhdp) +{ + if (!dhdp || !dhdp->pktlog) { + DHD_ERROR(("%s(): dhdp=%p pktlog=%p\n", + __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL))); + return BCME_ERROR; + } + + if (!dhdp->pktlog->pktlog_ring) { + DHD_ERROR(("%s(): pktlog_ring=%p\n", + __FUNCTION__, dhdp->pktlog->pktlog_ring)); + return BCME_ERROR; + } + + return OSL_ATOMIC_READ(dhdp->osh, &dhdp->pktlog->enable); +} + +void dhd_pktlog_resume(dhd_pub_t *dhdp) +{ + struct dhd_pktlog_ring *pktlog_ring; + + if (!dhdp || !dhdp->pktlog) { + DHD_ERROR(("%s(): dhdp=%p pktlog=%p\n", + __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL))); + return; + } + + if (!dhdp->pktlog->pktlog_ring) { + DHD_ERROR(("%s(): pktlog_ring=%p\n", + __FUNCTION__, dhdp->pktlog->pktlog_ring)); + return; + } + + pktlog_ring = dhdp->pktlog->pktlog_ring; + if (!OSL_ATOMIC_READ(dhdp->osh, &dhdp->pktlog->enable)) { + OSL_ATOMIC_SET(dhdp->osh, &dhdp->pktlog->enable, TRUE); + DHD_INFO(("pktlog ring is resumed. pktcount(%d)\n", + pktlog_ring->pktcount)); + } +} + +void dhd_pktlog_suspend(dhd_pub_t *dhdp) +{ + struct dhd_pktlog_ring *pktlog_ring; + + if (!dhdp || !dhdp->pktlog) { + DHD_ERROR(("%s(): dhdp=%p pktlog=%p\n", + __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL))); + return; + } + + if (!dhdp->pktlog->pktlog_ring) { + DHD_ERROR(("%s(): pktlog_ring=%p\n", + __FUNCTION__, dhdp->pktlog->pktlog_ring)); + return; + } + + pktlog_ring = dhdp->pktlog->pktlog_ring; + if (OSL_ATOMIC_READ(dhdp->osh, &dhdp->pktlog->enable)) { + OSL_ATOMIC_SET(dhdp->osh, &dhdp->pktlog->enable, FALSE); + DHD_INFO(("pktlog ring is suspended. pktcount(%d)\n", + pktlog_ring->pktcount)); + } +} +#endif /* DHD_PKT_LOGGING_DBGRING */ + dhd_pktlog_ring_t* dhd_pktlog_ring_init(dhd_pub_t *dhdp, int size) { @@ -196,7 +306,7 @@ dhd_pktlog_ring_init(dhd_pub_t *dhdp, int size) return NULL; } - ring = (dhd_pktlog_ring_t *)MALLOCZ(dhdp->osh, sizeof(dhd_pktlog_ring_t)); + ring = (dhd_pktlog_ring_t *)VMALLOCZ(dhdp->osh, sizeof(dhd_pktlog_ring_t)); if (unlikely(!ring)) { DHD_ERROR(("%s(): could not allocate memory for - " "dhd_pktlog_ring_t\n", __FUNCTION__)); @@ -206,7 +316,7 @@ dhd_pktlog_ring_init(dhd_pub_t *dhdp, int size) dll_init(&ring->ring_info_head); dll_init(&ring->ring_info_free); - ring->ring_info_mem = (dhd_pktlog_ring_info_t *)MALLOCZ(dhdp->osh, + ring->ring_info_mem = (dhd_pktlog_ring_info_t *)VMALLOCZ(dhdp->osh, sizeof(dhd_pktlog_ring_info_t) * size); if (unlikely(!ring->ring_info_mem)) { DHD_ERROR(("%s(): could not allocate memory for - " @@ -225,13 +335,16 @@ dhd_pktlog_ring_init(dhd_pub_t *dhdp, int size) ring->pktcount = 0; ring->dhdp = dhdp; ring->pktlog_ring_lock = osl_spin_lock_init(dhdp->osh); +#ifdef DHD_PKT_LOGGING_DBGRING + OSL_ATOMIC_SET(dhdp->osh, &dhdp->pktlog->enable, TRUE); +#endif /* DHD_PKT_LOGGING_DBGRING */ - DHD_ERROR(("%s(): pktlog ring init success\n", __FUNCTION__)); + DHD_INFO(("%s(): pktlog ring init success\n", __FUNCTION__)); return ring; fail: if (ring) { - MFREE(dhdp->osh, ring, sizeof(dhd_pktlog_ring_t)); + VMFREE(dhdp->osh, ring, sizeof(dhd_pktlog_ring_t)); } return NULL; @@ -290,7 +403,7 @@ dhd_pktlog_ring_deinit(dhd_pub_t *dhdp, dhd_pktlog_ring_t *ring) } if (ring->ring_info_mem) { - MFREE(ring->dhdp->osh, ring->ring_info_mem, + VMFREE(ring->dhdp->osh, ring->ring_info_mem, sizeof(dhd_pktlog_ring_info_t) * ring->pktlog_len); } @@ -298,13 +411,86 @@ dhd_pktlog_ring_deinit(dhd_pub_t *dhdp, dhd_pktlog_ring_t *ring) osl_spin_lock_deinit(ring->dhdp->osh, ring->pktlog_ring_lock); } - MFREE(dhdp->osh, ring, sizeof(dhd_pktlog_ring_t)); + VMFREE(dhdp->osh, ring, sizeof(dhd_pktlog_ring_t)); - DHD_ERROR(("%s(): pktlog ring deinit\n", __FUNCTION__)); + DHD_INFO(("%s(): pktlog ring deinit\n", __FUNCTION__)); return ret; } +#ifdef DHD_PKT_LOGGING_DBGRING +int +dhd_pktlog_ring_reinit(dhd_pub_t *dhdp) +{ + dhd_pktlog_ring_info_t *ring_info; + dhd_pktlog_ring_t *pktlog_ring; + dll_t *item, *next_p; + int waitcounts = 0; + dhd_dbg_ring_t *ring; + + DHD_ERROR(("%s: ENTER\n", __FUNCTION__)); + + if (!dhdp) { + DHD_ERROR(("%s(): dhdp is NULL\n", __FUNCTION__)); + return -EINVAL; + } + pktlog_ring = dhdp->pktlog->pktlog_ring; + ring = &dhdp->dbg->dbg_rings[PACKET_LOG_RING_ID]; + + if (!ring) { + DHD_ERROR(("%s(): ring is NULL\n", __FUNCTION__)); + return -EINVAL; + } + + /* stop pkt log */ + OSL_ATOMIC_SET(dhdp->osh, &pktlog_ring->start, FALSE); + + /* waiting TX/RX/TXS context is done, max timeout 1 second */ + while ((waitcounts++ < DHD_PKTLOG_WAIT_MAXCOUNT)) { + if (!OSL_ATOMIC_READ(dhdp->osh, &dhdp->pktlog->pktlog_status)) + break; + OSL_SLEEP(1); + } + + if (waitcounts >= DHD_PKTLOG_WAIT_MAXCOUNT) { + DHD_ERROR(("%s(): pktlog wait timeout pktlog_status : 0x%x \n", + __FUNCTION__, + OSL_ATOMIC_READ(dhdp->osh, &dhdp->pktlog->pktlog_status))); + ASSERT(0); + return -EINVAL; + } + + /* free ring_info->info.pkt */ + for (item = dll_head_p(&pktlog_ring->ring_info_head); + !dll_end(&pktlog_ring->ring_info_head, item); + item = next_p) { + next_p = dll_next_p(item); + + ring_info = (dhd_pktlog_ring_info_t *)item; + + dll_delete((dll_t *)item); + if (ring_info->info.pkt) { + PKTFREE(pktlog_ring->dhdp->osh, ring_info->info.pkt, TRUE); + DHD_PKT_LOG(("%s(): pkt free pos %p\n", + __FUNCTION__, ring_info->info.pkt)); + } + dll_append(&pktlog_ring->ring_info_free, (dll_t *)item); + } + + /* reset stats and pktcount */ + pktlog_ring->pktcount = 0; + memset(&ring->stat, 0, sizeof(struct ring_statistics)); + /* start pkt log */ + OSL_ATOMIC_SET(dhdp->osh, &pktlog_ring->start, TRUE); +#ifdef DHD_PKT_LOGGING_DBGRING + OSL_ATOMIC_SET(dhdp->osh, &dhdp->pktlog->enable, TRUE); +#endif /* DHD_PKT_LOGGING_DBGRING */ + DHD_ERROR(("%s: EXIT\n", __FUNCTION__)); + + return BCME_OK; +} +#endif /* DHD_PKT_LOGGING_DBGRING */ + /* * dhd_pktlog_ring_add_pkts : add filtered packets into pktlog ring * pktid : incase of rx, pktid is not used (pass DHD_INVALID_PKID) @@ -316,10 +502,16 @@ dhd_pktlog_ring_add_pkts(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pktid dhd_pktlog_ring_info_t *pkts; dhd_pktlog_ring_t *pktlog_ring; dhd_pktlog_filter_t *pktlog_filter; - u64 ts_nsec; uint32 pktlog_case = 0; - unsigned long rem_nsec; unsigned long flags = 0; +#ifdef DHD_PKT_LOGGING_DBGRING + struct timespec64 ts; + dhd_dbg_ring_t *ring; + ring = &dhdp->dbg->dbg_rings[PACKET_LOG_RING_ID]; +#else + u64 ts_nsec; + unsigned long rem_nsec; +#endif /* DHD_PKT_LOGGING_DBGRING */ /* * dhdp, dhdp->pktlog, dhd->pktlog_ring, pktlog_ring->start @@ -335,6 +527,16 @@ dhd_pktlog_ring_add_pkts(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pktid pktlog_case = PKTLOG_RXPKT_CASE; } + if (pktlog_filter && pktlog_filter->list_cnt == 0) { + /* There is no packet log list */ + return BCME_OK; + } + +#ifdef DHD_PKT_LOGGING_DBGRING + if (ring->log_level == RING_LOG_LEVEL_EXCESSIVE) { + /* In excessive log level, pass through without pattern matching */ + } else +#endif /* DHD_PKT_LOGGING_DBGRING */ if ((direction != PKT_WAKERX) && dhd_pktlog_filter_matched(pktlog_filter, pktdata, pktlog_case) == FALSE) { @@ -361,17 +563,36 @@ dhd_pktlog_ring_add_pkts(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pktid } /* Update packet information */ +#ifdef DHD_PKT_LOGGING_DBGRING + ktime_get_real_ts64(&ts); + + pkts->info.driver_ts_sec = (uint32)ts.tv_sec; + pkts->info.driver_ts_usec = (uint32)(ts.tv_nsec/NSEC_PER_USEC); +#else ts_nsec = local_clock(); rem_nsec = do_div(ts_nsec, NSEC_PER_SEC); - pkts->info.pkt = PKTDUP(dhdp->osh, pkt); - pkts->info.pkt_len = PKTLEN(dhdp->osh, pkt); pkts->info.driver_ts_sec = (uint32)ts_nsec; pkts->info.driver_ts_usec = (uint32)(rem_nsec/NSEC_PER_USEC); +#endif /* DHD_PKT_LOGGING_DBGRING */ + + pkts->info.pkt = PKTDUP(dhdp->osh, pkt); + /* + * skb clone can be NULL, but pktlog feature assume it alway can be cloned + * The dummy pkt info will be added in the list to fit pktcount & list items + * and handled in the dhd_pktlog_dump_write() with ignoring info.pkt + */ + if (pkts->info.pkt == NULL) { + DHD_ERROR(("%s : skb clone returns NULL \n", __FUNCTION__)); + } + pkts->info.pkt_len = PKTLEN(dhdp->osh, pkt); pkts->info.firmware_ts = 0U; pkts->info.payload_type = FRAME_TYPE_ETHERNET_II; pkts->info.direction = direction; + pkts->info.tx_status_ts_sec = 0; + pkts->info.tx_status_ts_usec = 0; + if (direction == PKT_TX) { pkts->info.pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid); pkts->tx_fate = TX_PKT_FATE_DRV_QUEUED; @@ -391,6 +612,12 @@ dhd_pktlog_ring_add_pkts(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pktid dll_append(&pktlog_ring->ring_info_head, (dll_t *)pkts); pktlog_ring->pktcount++; DHD_PKT_LOG_UNLOCK(pktlog_ring->pktlog_ring_lock, flags); +#ifdef DHD_PKT_LOGGING_DBGRING + dhd_dbg_update_to_ring(dhdp, pktlog_ring->dbg_ring, + dhd_pktlog_get_item_length(pkts)); +#endif /* DHD_PKT_LOGGING_DBGRING */ + + DHD_PKT_LOG(("%s(): pktcount=%d\n", __FUNCTION__, pktlog_ring->pktcount)); return BCME_OK; } @@ -405,7 +632,8 @@ dhd_pktlog_ring_tx_status(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pkti dhd_pktlog_filter_t *pktlog_filter; dll_t *item_p, *next_p; unsigned long flags = 0; - + u64 ts_nsec; + unsigned long rem_nsec; #ifdef BDC struct bdc_header *h; BCM_REFERENCE(h); @@ -426,6 +654,9 @@ dhd_pktlog_ring_tx_status(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pkti pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid); pkt_fate = __dhd_dbg_map_tx_status_to_pkt_fate(status); + ts_nsec = local_clock(); + rem_nsec = do_div(ts_nsec, NSEC_PER_SEC); + /* find the sent tx packet and adding pkt_fate info */ DHD_PKT_LOG_LOCK(pktlog_ring->pktlog_ring_lock, flags); /* Inverse traverse from the last packets */ @@ -446,6 +677,8 @@ dhd_pktlog_ring_tx_status(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pkti PKTPULL(dhdp->osh, tx_pkt->info.pkt, BDC_HEADER_LEN); PKTPULL(dhdp->osh, tx_pkt->info.pkt, (h->dataOffset << DHD_WORD_TO_LEN_SHIFT)); #endif /* BDC */ + tx_pkt->info.tx_status_ts_sec = (uint32)ts_nsec; + tx_pkt->info.tx_status_ts_usec = (uint32)(rem_nsec/NSEC_PER_USEC); DHD_PKT_LOG(("%s(): Found pkt hash in prev pos\n", __FUNCTION__)); break; } @@ -491,7 +724,7 @@ dhd_pktlog_filter_init(int size) filter->enable = PKTLOG_TXPKT_CASE | PKTLOG_TXSTATUS_CASE | PKTLOG_RXPKT_CASE; - DHD_ERROR(("%s(): pktlog filter init success\n", __FUNCTION__)); + DHD_INFO(("%s(): pktlog filter init success\n", __FUNCTION__)); return filter; fail: @@ -517,7 +750,7 @@ dhd_pktlog_filter_deinit(dhd_pktlog_filter_t *filter) } kfree(filter); - DHD_ERROR(("%s(): pktlog filter deinit\n", __FUNCTION__)); + DHD_INFO(("%s(): pktlog filter deinit\n", __FUNCTION__)); return ret; } @@ -837,6 +1070,7 @@ dhd_pktlog_filter_matched(dhd_pktlog_filter_t *filter, char *data, uint32 pktlog /* Ethernet Type MAC Header 12 bytes + Frame payload 10 bytes */ #define PKTLOG_MINIMIZE_REPORT_LEN 22 +#ifndef DHD_PKT_LOGGING_DBGRING static char pktlog_minmize_mask_table[] = { 0xff, 0x00, 0x00, 0x00, 0xff, 0x0f, /* Ethernet Type MAC Header - Destination MAC Address */ 0xff, 0x00, 0x00, 0x00, 0xff, 0x0f, /* Ethernet Type MAC Header - Source MAC Address */ @@ -890,6 +1124,7 @@ dhd_pktlog_minimize_report(char *pkt, uint32 frame_len, } vfree(mem_buf); } +#endif /* !DHD_PKT_LOGGING_DBGRING */ dhd_pktlog_ring_t* dhd_pktlog_ring_change_size(dhd_pktlog_ring_t *ringbuf, int size) @@ -1018,27 +1253,39 @@ dhd_pktlog_get_item_length(dhd_pktlog_ring_info_t *report_ptr) } else { frame_len = (uint32)min(report_ptr->info.pkt_len, (size_t)MAX_FRAME_LEN_80211_MGMT); } - - bytes_user_data = sprintf(buf, "%s:%s:%02d\n", DHD_PKTLOG_FATE_INFO_FORMAT, - (report_ptr->tx_fate ? "Failure" : "Succeed"), report_ptr->tx_fate); +#ifdef DHD_PKT_LOGGING_DBGRING + frame_len = (uint32)min(frame_len, DHD_PKT_LOGGING_DBGRING_MAX_SIZE); + bytes_user_data = snprintf(buf, sizeof(buf), "%s:%s:%02d\n", + DHD_PKTLOG_FATE_INFO_FORMAT, + (report_ptr->tx_fate ? "Failure" : "Succeed"), report_ptr->tx_fate); +#else + bytes_user_data = snprintf(buf, sizeof(buf), "%s:%s:%02d:%s:%d.%d s\n", + DHD_PKTLOG_FATE_INFO_FORMAT, + (report_ptr->tx_fate ? "Failure" : "Succeed"), report_ptr->tx_fate, + (report_ptr->info.direction == PKT_TX) ? "TX" : "RX", + report_ptr->info.tx_status_ts_sec, report_ptr->info.tx_status_ts_usec); +#endif /* DHD_PKT_LOGGING_DBGRING */ write_frame_len = frame_len + bytes_user_data; /* pcap pkt head has incl_len and orig_len */ len += (uint32)sizeof(write_frame_len); len += (uint32)sizeof(write_frame_len); - len += frame_len; - len += bytes_user_data; + len += write_frame_len; return len; } -uint32 +int dhd_pktlog_get_dump_length(dhd_pub_t *dhdp) { dhd_pktlog_ring_info_t *report_ptr; dhd_pktlog_ring_t *pktlog_ring; - uint32 len; + uint32 len = 0; dll_t *item_p, *next_p; +#ifdef DHD_PKT_LOGGING_DBGRING + dhd_dbg_ring_t *ring; + ring = &dhdp->dbg->dbg_rings[PACKET_LOG_RING_ID]; +#endif /* DHD_PKT_LOGGING_DBGRING */ if (!dhdp || !dhdp->pktlog) { DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n", @@ -1054,15 +1301,20 @@ dhd_pktlog_get_dump_length(dhd_pub_t *dhdp) pktlog_ring = dhdp->pktlog->pktlog_ring; OSL_ATOMIC_SET(dhdp->osh, &pktlog_ring->start, FALSE); - +#ifndef DHD_PKT_LOGGING_DBGRING len = sizeof(dhd_pktlog_pcap_hdr_t); - +#endif /* !DHD_PKT_LOGGING_DBGRING */ for (item_p = dll_head_p(&pktlog_ring->ring_info_head); !dll_end(&pktlog_ring->ring_info_head, item_p); item_p = next_p) { next_p = dll_next_p(item_p); report_ptr = (dhd_pktlog_ring_info_t *)item_p; len += dhd_pktlog_get_item_length(report_ptr); +#ifdef DHD_PKT_LOGGING_DBGRING + if (len >= ring->threshold) { + break; + } +#endif /* DHD_PKT_LOGGING_DBGRING */ } OSL_ATOMIC_SET(dhdp->osh, &pktlog_ring->start, TRUE); DHD_PKT_LOG(("calcuated pkt log dump len:%d\n", len)); @@ -1071,17 +1323,27 @@ dhd_pktlog_get_dump_length(dhd_pub_t *dhdp) } int +#ifdef DHD_PKT_LOGGING_DBGRING +dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, + uint32 *written_bytes) +#else dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32 size) +#endif /* DHD_PKT_LOGGING_DBGRING */ { dhd_pktlog_ring_info_t *report_ptr; dhd_pktlog_ring_t *pktlog_ring; char buf[DHD_PKTLOG_FATE_INFO_STR_LEN]; +#ifndef DHD_PKT_LOGGING_DBGRING dhd_pktlog_pcap_hdr_t pcap_h; + loff_t pos = 0; +#else + uint32 size = 0; + unsigned long flags = 0; +#endif /* !DHD_PKT_LOGGING_DBGRING */ uint32 write_frame_len; uint32 frame_len; - ulong len; + ulong len = 0; int bytes_user_data = 0; - loff_t pos = 0; int ret = BCME_OK; dll_t *item_p, *next_p; @@ -1097,10 +1359,23 @@ dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32 return -EINVAL; } +#ifdef DHD_PKT_LOGGING_DBGRING + if (user_buf) { + size = *written_bytes; + } else if (file) { + /* With DHD_PKT_LOGGING_DBGRING, this path is not allowed. */ + return BCME_UNSUPPORTED; + } +#endif /* DHD_PKT_LOGGING_DBGRING */ + if (file && !user_buf && (size == 0)) { DHD_ERROR(("Local file pktlog dump requested\n")); } else if (!file && user_buf && (size > 0)) { +#ifdef DHD_PKT_LOGGING_DBGRING + DHD_INFO(("HAL file pktlog dump %d bytes requested\n", size)); +#else DHD_ERROR(("HAL file pktlog dump %d bytes requested\n", size)); +#endif /* DHD_PKT_LOGGING_DBGRING */ } else { DHD_ERROR(("Wrong type pktlog dump requested\n")); return -EINVAL; @@ -1108,7 +1383,7 @@ dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32 pktlog_ring = dhdp->pktlog->pktlog_ring; OSL_ATOMIC_SET(dhdp->osh, &pktlog_ring->start, FALSE); - +#ifndef DHD_PKT_LOGGING_DBGRING pcap_h.magic_number = PKTLOG_PCAP_MAGIC_NUM; pcap_h.version_major = PKTLOG_PCAP_MAJOR_VER; pcap_h.version_minor = PKTLOG_PCAP_MINOR_VER; @@ -1119,20 +1394,90 @@ dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32 ret = dhd_export_debug_data((char *)&pcap_h, file, user_buf, sizeof(pcap_h), &pos); len = sizeof(pcap_h); - +#endif /* !DHD_PKT_LOGGING_DBGRING */ +#ifdef DHD_PKT_LOGGING_DBGRING + DHD_PKT_LOG_LOCK(dhd_os_get_pktlog_lock(dhdp), flags); +#endif /* DHD_PKT_LOGGING_DBGRING */ for (item_p = dll_head_p(&pktlog_ring->ring_info_head); !dll_end(&pktlog_ring->ring_info_head, item_p); item_p = next_p) { +#ifdef DHD_PKT_LOGGING_DBGRING + uint32 captured_frame_len; +#endif /* DHD_PKT_LOGGING_DBGRING */ next_p = dll_next_p(item_p); report_ptr = (dhd_pktlog_ring_info_t *)item_p; - +#ifdef DHD_PKT_LOGGING_DBGRING + if (report_ptr->info.direction == PKT_TX && + report_ptr->tx_fate == TX_PKT_FATE_DRV_QUEUED) { + /* Not updated txfate yet, postpone some time. */ + report_ptr->tx_fate |= TX_PKT_FATE_DRV_WAIT_UPDATE; + continue; + } +#endif /* DHD_PKT_LOGGING_DBGRING */ if ((file == NULL) && (len + dhd_pktlog_get_item_length(report_ptr) > size)) { +#ifdef DHD_PKT_LOGGING_DBGRING + DHD_INFO(("overflowed pkt logs are dropped\n")); +#else DHD_ERROR(("overflowed pkt logs are dropped\n")); +#endif /* DHD_PKT_LOGGING_DBGRING */ break; } + if (report_ptr->info.pkt == NULL) { + DHD_ERROR(("%s : pkt isn't located skip it\n", __FUNCTION__)); + continue; + } + +#ifdef DHD_PKT_LOGGING_DBGRING + ret = memcpy_s((void*)(user_buf + len), size - len, + (char*)&report_ptr->info.driver_ts_sec, + sizeof(report_ptr->info.driver_ts_sec)); + len += sizeof(report_ptr->info.driver_ts_sec); + + ret = memcpy_s((void*)(user_buf + len), size - len, + (char*)&report_ptr->info.driver_ts_usec, + sizeof(report_ptr->info.driver_ts_usec)); + len += sizeof(report_ptr->info.driver_ts_usec); + + if (report_ptr->info.payload_type == FRAME_TYPE_ETHERNET_II) { + frame_len = (uint32)min(report_ptr->info.pkt_len, + (size_t)MAX_FRAME_LEN_ETHERNET); + } else { + frame_len = (uint32)min(report_ptr->info.pkt_len, + (size_t)MAX_FRAME_LEN_80211_MGMT); + } + + bytes_user_data = snprintf(buf, sizeof(buf), "%s:%s:%02d\n", + DHD_PKTLOG_FATE_INFO_FORMAT, + (report_ptr->tx_fate ? "Failure" : "Succeed"), + (report_ptr->tx_fate & ~(TX_PKT_FATE_DRV_WAIT_UPDATE))); + write_frame_len = frame_len + bytes_user_data; + frame_len = (uint32)min(frame_len, DHD_PKT_LOGGING_DBGRING_MAX_SIZE); + captured_frame_len = frame_len + bytes_user_data; + + /* pcap pkt head has incl_len and orig_len */ + ret = memcpy_s((void*)(user_buf + len), size - len, + (char*)&captured_frame_len, sizeof(captured_frame_len)); + len += sizeof(captured_frame_len); + + ret = memcpy_s((void*)(user_buf + len), size - len, + (char*)&write_frame_len, sizeof(write_frame_len)); + len += sizeof(write_frame_len); + + ret = memcpy_s((void*)(user_buf + len), size - len, PKTDATA(pktlog_ring->dhdp->osh, + report_ptr->info.pkt), frame_len); + len += frame_len; + + ret = memcpy_s((void*)(user_buf + len), size - len, buf, bytes_user_data); + len += bytes_user_data; + + dll_delete((dll_t *)report_ptr); + PKTFREE(pktlog_ring->dhdp->osh, report_ptr->info.pkt, TRUE); + pktlog_ring->pktcount--; + dll_append(&pktlog_ring->ring_info_free, (dll_t *)report_ptr); +#else ret = dhd_export_debug_data((char*)&report_ptr->info.driver_ts_sec, file, user_buf, sizeof(report_ptr->info.driver_ts_sec), &pos); len += sizeof(report_ptr->info.driver_ts_sec); @@ -1150,8 +1495,13 @@ dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32 (size_t)MAX_FRAME_LEN_80211_MGMT); } - bytes_user_data = sprintf(buf, "%s:%s:%02d\n", DHD_PKTLOG_FATE_INFO_FORMAT, - (report_ptr->tx_fate ? "Failure" : "Succeed"), report_ptr->tx_fate); + bytes_user_data = snprintf(buf, sizeof(buf), "%s:%s:%02d:%s:%d.%d s\n", + DHD_PKTLOG_FATE_INFO_FORMAT, + (report_ptr->tx_fate ? "Failure" : "Succeed"), + report_ptr->tx_fate, + (report_ptr->info.direction == PKT_TX) ? "TX" : "RX", + report_ptr->info.tx_status_ts_sec, + report_ptr->info.tx_status_ts_usec); write_frame_len = frame_len + bytes_user_data; /* pcap pkt head has incl_len and orig_len */ @@ -1174,7 +1524,12 @@ dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32 ret = dhd_export_debug_data(buf, file, user_buf, bytes_user_data, &pos); len += bytes_user_data; +#endif /* DHD_PKT_LOGGING_DBGRING */ } +#ifdef DHD_PKT_LOGGING_DBGRING + DHD_PKT_LOG_UNLOCK(dhd_os_get_pktlog_lock(dhdp), flags); + *written_bytes = len; +#endif /* DHD_PKT_LOGGING_DBGRING */ OSL_ATOMIC_SET(dhdp->osh, &pktlog_ring->start, TRUE); return ret; @@ -1183,7 +1538,11 @@ dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32 int dhd_pktlog_dump_write_memory(dhd_pub_t *dhdp, const void *user_buf, uint32 size) { +#ifdef DHD_PKT_LOGGING_DBGRING + int ret = dhd_pktlog_dump_write(dhdp, NULL, user_buf, &size); +#else int ret = dhd_pktlog_dump_write(dhdp, NULL, user_buf, size); +#endif /* DHD_PKT_LOGGING_DBGRING */ if (ret < 0) { DHD_ERROR(("dhd_pktlog_dump_write_memory error\n")); } @@ -1195,17 +1554,21 @@ dhd_pktlog_dump_write_file(dhd_pub_t *dhdp) { struct file *w_pcap_fp = NULL; uint32 file_mode; +#ifdef get_fs mm_segment_t old_fs; +#endif /* get_fs */ char pktlogdump_path[128]; int ret = BCME_OK; dhd_pktlog_get_filename(dhdp, pktlogdump_path, 128); +#ifdef get_fs old_fs = get_fs(); set_fs(KERNEL_DS); +#endif /* get_fs */ file_mode = O_CREAT | O_WRONLY; - w_pcap_fp = filp_open(pktlogdump_path, file_mode, 0664); - if (IS_ERR(w_pcap_fp)) { + w_pcap_fp = dhd_filp_open(pktlogdump_path, file_mode, 0664); + if (IS_ERR(w_pcap_fp) || (w_pcap_fp == NULL)) { DHD_ERROR(("%s: Couldn't open file '%s' err %ld\n", __FUNCTION__, pktlogdump_path, PTR_ERR(w_pcap_fp))); ret = BCME_ERROR; @@ -1219,18 +1582,18 @@ dhd_pktlog_dump_write_file(dhd_pub_t *dhdp) } /* Sync file from filesystem to physical media */ - ret = vfs_fsync(w_pcap_fp, 0); + ret = dhd_vfs_fsync(w_pcap_fp, 0); if (ret < 0) { DHD_ERROR(("%s(): sync pcap file error, err = %d\n", __FUNCTION__, ret)); goto fail; } fail: if (!IS_ERR(w_pcap_fp)) { - filp_close(w_pcap_fp, NULL); + dhd_filp_close(w_pcap_fp, NULL); } - +#ifdef get_fs set_fs(old_fs); - +#endif /* get_fs */ #ifdef DHD_DUMP_MNGR if (ret >= 0) { dhd_dump_file_manage_enqueue(dhdp, pktlogdump_path, DHD_PKTLOG_DUMP_TYPE); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pktlog.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pktlog.h old mode 100755 new mode 100644 index bfa38f5c08dd..f4f9f26681f6 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pktlog.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pktlog.h @@ -1,7 +1,7 @@ /* * DHD debugability packet logging header file * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -58,6 +58,8 @@ typedef struct dhd_dbg_pktlog_info { uint32 driver_ts_usec; uint32 firmware_ts; uint32 pkt_hash; + uint32 tx_status_ts_sec; + uint32 tx_status_ts_usec; bool direction; void *pkt; } dhd_dbg_pktlog_info_t; @@ -84,6 +86,9 @@ typedef struct dhd_pktlog_ring spinlock_t *pktlog_ring_lock; dhd_pub_t *dhdp; dhd_pktlog_ring_info_t *ring_info_mem; /* ring_info mem pointer */ +#ifdef DHD_PKT_LOGGING_DBGRING + void *dbg_ring; +#endif /* DHD_PKT_LOGGING_DBGRING */ } dhd_pktlog_ring_t; typedef struct dhd_pktlog_filter_info @@ -112,6 +117,9 @@ typedef struct dhd_pktlog #ifdef DHD_COMPACT_PKT_LOG struct rb_root cpkt_log_tt_rbt; #endif /* DHD_COMPACT_PKT_LOG */ +#ifdef DHD_PKT_LOGGING_DBGRING + osl_atomic_t enable; /* logging suspend/resume */ +#endif /* DHD_PKT_LOGGING_DBGRING */ } dhd_pktlog_t; typedef struct dhd_pktlog_pcap_hdr @@ -133,6 +141,12 @@ typedef struct dhd_pktlog_pcap_hdr extern int dhd_os_attach_pktlog(dhd_pub_t *dhdp); extern int dhd_os_detach_pktlog(dhd_pub_t *dhdp); +#ifdef DHD_PKT_LOGGING_DBGRING +extern int dhd_pktlog_is_enabled(dhd_pub_t *dhdp); +extern void dhd_pktlog_suspend(dhd_pub_t *dhdp); +extern void dhd_pktlog_resume(dhd_pub_t *dhdp); +extern int dhd_pktlog_ring_reinit(dhd_pub_t *dhdp); +#endif /* DHD_PKT_LOGGING_DBGRING */ extern dhd_pktlog_ring_t* dhd_pktlog_ring_init(dhd_pub_t *dhdp, int size); extern int dhd_pktlog_ring_deinit(dhd_pub_t *dhdp, dhd_pktlog_ring_t *ring); extern int dhd_pktlog_ring_set_nextpos(dhd_pktlog_ring_t *ringbuf); @@ -298,7 +312,7 @@ extern int dhd_pktlog_dump_write_file(dhd_pub_t *dhdp); extern void dhd_pktlog_get_filename(dhd_pub_t *dhdp, char *dump_path, int len); extern uint32 dhd_pktlog_get_item_length(dhd_pktlog_ring_info_t *report_ptr); -extern uint32 dhd_pktlog_get_dump_length(dhd_pub_t *dhdp); +extern int dhd_pktlog_get_dump_length(dhd_pub_t *dhdp); extern uint32 __dhd_dbg_pkt_hash(uintptr_t pkt, uint32 pktid); #ifdef DHD_COMPACT_PKT_LOG diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_plat.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_plat.h old mode 100755 new mode 100644 index 8c07b5b0f356..ec19a28efc78 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_plat.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_plat.h @@ -1,7 +1,7 @@ /* * DHD Linux platform header file * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -26,6 +26,8 @@ #ifndef __DHD_PLAT_H__ #define __DHD_PLAT_H__ +#if defined(__linux__) + #include #if !defined(CONFIG_WIFI_CONTROL_FUNC) @@ -38,7 +40,7 @@ struct wifi_platform_data { #ifdef DHD_COREDUMP int (*set_coredump)(const char *buf, int buf_len, const char *info); #endif /* DHD_COREDUMP */ -#ifdef BCMDHD_MDRIVER +#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER) void *(*mem_prealloc)(uint bus_type, int index, int section, unsigned long size); #else void *(*mem_prealloc)(int section, unsigned long size); @@ -53,6 +55,49 @@ struct wifi_platform_data { void *(*get_country_code)(char *ccode); #endif }; -#endif /* CONFIG_WIFI_CONTROL_FUNC */ +#endif +#include + +/* + * Plat Layer defines the interfaces that the BSP specific file should override + * The default implementation of the interfaces are present in dhd_linux_platdev.c + * The data structure/handle to be passed by the DHD to BSP specific file is opaque + * called plat_info. The data structure is to be maintained purely inside the + * BSP specific file and hence its kept opaque. + * + * There are two types of interface functions + * 1) Functions that need the interface structure plat_info to be passed down + * from DHD. + * 2) Functions that queries for certain information in BSP specific way and just + * returns to DHD - These functions does not take the plat_info as argument. + * + * The declarations are grouped accordingly. While adding a new interface function + * declaration based on the group it belongs to add it in the appropriate section + */ + +typedef void (*dhd_pcie_event_cb_t) (struct pci_dev *pdev); +extern int dhd_plat_pcie_register_event(void *plat_info, + struct pci_dev *pdev, dhd_pcie_event_cb_t pfn); +extern void dhd_plat_pcie_deregister_event(void *plat_info); +extern void dhd_plat_report_bh_sched(void *plat_info, int resched); +extern int dhd_plat_pcie_suspend(void *plat_info); +extern int dhd_plat_pcie_resume(void *plat_info); +extern void dhd_plat_pcie_register_dump(void *plat_info); +extern void dhd_plat_pin_dbg_show(void *plat_info); + +extern uint32 dhd_plat_get_info_size(void); +extern void dhd_plat_l1ss_ctrl(bool ctrl); + +/* To be called when we intend to exit L1 while performing wreg, rreg operations */ +extern void dhd_plat_l1_exit_io(void); + +/* To be called when we intend to exit L1 in non-io case */ +extern void dhd_plat_l1_exit(void); + +extern uint32 dhd_plat_get_rc_vendor_id(void); +extern uint32 dhd_plat_get_rc_device_id(void); + +extern uint16 dhd_plat_align_rxbuf_size(uint16 rxbufpost_sz); +#endif /* __linux__ */ #endif /* __DHD_PLAT_H__ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c old mode 100755 new mode 100644 index e002405fc864..cfd7e4e01b2a --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD) * Prefered Network Offload and Wi-Fi Location Service(WLS) code. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * <> */ -#if defined (GSCAN_SUPPORT) && !defined(PNO_SUPPORT) +#if defined(GSCAN_SUPPORT) && !defined(PNO_SUPPORT) #error "GSCAN needs PNO to be enabled!" #endif @@ -35,13 +35,11 @@ #include -#ifdef OEM_ANDROID #include #include #include #include #include -#endif #include #include @@ -74,15 +72,34 @@ #define dtohchanspec(i) (i) #endif /* IL_BIGENDINA */ -#ifdef OEM_ANDROID +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) +#define COMPLETION_WAIT_QUEUE_ACTIVE(wait_queue) swait_active(wait_queue) +#else +#define COMPLETION_WAIT_QUEUE_ACTIVE(wait_queue) waitqueue_active(wait_queue) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) */ + +#ifdef CUSTOM_PREFIX +#define PNO_PRINT_PREFIX "[%s]"CUSTOM_PREFIX, OSL_GET_RTCTIME() +#define PNO_PRINT_SYSTEM_TIME pr_cont(PNO_PRINT_PREFIX) +#define PNO_CONS_ONLY(args) \ +do { \ + PNO_PRINT_SYSTEM_TIME; \ + pr_cont args; \ +} while (0) +#else +#define PNO_PRINT_SYSTEM_TIME +#define PNO_CONS_ONLY(args) do { printf args;} while (0) +#endif /* CUSTOM_PREFIX */ + #define NULL_CHECK(p, s, err) \ - do { \ - if (!(p)) { \ - printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ - err = BCME_ERROR; \ - return err; \ - } \ - } while (0) +do { \ + if (!(p)) { \ + PNO_CONS_ONLY(("NULL POINTER (%s) : %s\n", __FUNCTION__, (s))); \ + err = BCME_ERROR; \ + return err; \ + } \ +} while (0) + #define PNO_GET_PNOSTATE(dhd) ((dhd_pno_status_info_t *)dhd->pno_state) #define PNO_BESTNET_LEN WLC_IOCTL_MEDLEN @@ -103,8 +120,6 @@ - (uint32)(timestamp2/1000))) #define TIME_DIFF_MS(timestamp1, timestamp2) (abs((uint32)(timestamp1) \ - (uint32)(timestamp2))) -#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \ - (ts).tv_nsec / NSEC_PER_USEC) #define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") #define TIME_MIN_DIFF 5 @@ -210,7 +225,7 @@ dhd_is_legacy_pno_enabled(dhd_pub_t *dhd) static uint64 convert_fw_rel_time_to_systime(struct osl_timespec *ts, uint32 fw_ts_ms) { - return ((uint64)(TIMESPEC_TO_US(*ts)) - (uint64)(fw_ts_ms * 1000)); + return ((uint64)(TIMESPEC64_TO_US(*ts)) - (uint64)(fw_ts_ms * USEC_PER_MSEC)); } static void @@ -382,6 +397,7 @@ _dhd_pno_suspend(dhd_pub_t *dhd) exit: return err; } + static int _dhd_pno_enable(dhd_pub_t *dhd, int enable) { @@ -402,15 +418,6 @@ _dhd_pno_enable(dhd_pub_t *dhd, int enable) err = BCME_BADOPTION; goto exit; } - if (enable) { - if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && - dhd_is_associated(dhd, 0, NULL)) { - DHD_ERROR(("%s Legacy PNO mode cannot be enabled " - "in assoc mode , ignore it\n", __FUNCTION__)); - err = BCME_BADOPTION; - goto exit; - } - } /* Enable/Disable PNO */ err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), NULL, 0, TRUE); if (err < 0) { @@ -432,28 +439,71 @@ static int _dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t mode) { int err = BCME_OK; - wl_pfn_param_t pfn_param; + wl_pfn_param_v3_t pfn_param; dhd_pno_params_t *_params; dhd_pno_status_info_t *_pno_state; bool combined_scan = FALSE; + uint16 size; + bool use_v3 = FALSE; DHD_PNO(("%s enter\n", __FUNCTION__)); NULL_CHECK(dhd, "dhd is NULL", err); NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); _pno_state = PNO_GET_PNOSTATE(dhd); - memset(&pfn_param, 0, sizeof(pfn_param)); + /* Query pfn version */ + bzero(&pfn_param, sizeof(pfn_param)); + err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), + (char *)&pfn_param, sizeof(pfn_param), FALSE); + if (err < 0) { + if (err == BCME_UNSUPPORTED) { + DHD_PNO(("%s : PFN versioning not supported. Use v2\n", + __FUNCTION__)); + use_v3 = FALSE; + } else { + DHD_ERROR(("%s : failed to query pfn_set %d\n", __FUNCTION__, err)); + goto exit; + } + } else { + if (pfn_param.version == PFN_VERSION_V3) { + DHD_ERROR(("%s : using pfn_param v3\n", __FUNCTION__)); + use_v3 = TRUE; + } else if (pfn_param.version == PFN_VERSION_V2) { + DHD_ERROR(("%s : using pfn_param v2\n", __FUNCTION__)); + use_v3 = FALSE; + } else { + DHD_ERROR(("unsupported pfn ver:%d\n", pfn_param.version)); + err = BCME_UNSUPPORTED; + goto exit; + } + } /* set pfn parameters */ - pfn_param.version = htod32(PFN_VERSION); + bzero(&pfn_param, sizeof(pfn_param)); + if (use_v3) { + pfn_param.version = PFN_VERSION_V3; + pfn_param.version = htod32(pfn_param.version); + size = sizeof(wl_pfn_param_v3_t); + pfn_param.length = htod32(size); + } else { + wl_pfn_param_v2_t *pfn_param_v2 = (wl_pfn_param_v2_t *)&pfn_param; + pfn_param_v2->version = PFN_VERSION_V2; + pfn_param_v2->version = htod32(pfn_param_v2->version); + size = sizeof(wl_pfn_param_v2_t); + } + pfn_param.flags = ((PFN_LIST_ORDER << SORT_CRITERIA_BIT) | (ENABLE << IMMEDIATE_SCAN_BIT) | (ENABLE << REPORT_SEPERATELY_BIT)); +#ifdef WL_SCHED_SCAN + /* bit to select the pfn partial scan result event logic */ + pfn_param.flags |= htod16(ENABLE << PFN_FULL_SCAN_RESULT_BIT); +#endif /* WL_SCHED_SCAN */ if (mode == DHD_PNO_LEGACY_MODE) { + pfn_param.repeat = (uchar) (pno_params->params_legacy.pno_repeat); /* check and set extra pno params */ - if ((pno_params->params_legacy.pno_repeat != 0) || + if ((pno_params->params_legacy.pno_repeat != 0) && (pno_params->params_legacy.pno_freq_expo_max != 0)) { pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); - pfn_param.repeat = (uchar) (pno_params->params_legacy.pno_repeat); pfn_param.exp = (uchar) (pno_params->params_legacy.pno_freq_expo_max); } /* set up pno scan fr */ @@ -590,7 +640,7 @@ _dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t goto exit; } } -#if (!defined(WL_USE_RANDOMIZED_SCAN)) +#if !defined(WL_USE_RANDOMIZED_SCAN) err = dhd_set_rand_mac_oui(dhd); /* Ignore if chip doesnt support the feature */ if (err < 0 && err != BCME_UNSUPPORTED) { @@ -622,7 +672,7 @@ _dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t DHD_PNO((" returned mscan : %d, set bestn : %d mscan %d\n", _tmp, pfn_param.bestn, pfn_param.mscan)); } - err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), NULL, 0, TRUE); + err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, size, NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : failed to execute pfn_set %d\n", __FUNCTION__, err)); goto exit; @@ -970,6 +1020,15 @@ _dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan) int err = BCME_OK; int i = 0; wl_pfn_cfg_t pfncfg_param; + bool use_chanspec = FALSE; + +#if defined(WL_6G_BAND) || defined(CFG80211_6G_SUPPORT) + /* When enable 6G, force to use chanspec list */ + if (FW_SUPPORTED((dhd), 6g)) { + use_chanspec = TRUE; + } +#endif /* WL_6G_BAND || CFG80211_6G_SUPPORT */ + NULL_CHECK(dhd, "dhd is NULL", err); if (nchan) { if (nchan > WL_NUMCHANNELS) { @@ -980,8 +1039,8 @@ _dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan) pfncfg_param.channel_num = htod32(0); for (i = 0; i < nchan; i++) { - if (dhd->wlc_ver_major >= DHD_PNO_CHSPEC_SUPPORT_VER) { - pfncfg_param.channel_list[i] = CH20MHZ_CHSPEC(channel_list[i]); + if ((dhd->wlc_ver_major >= DHD_PNO_CHSPEC_SUPPORT_VER) || use_chanspec) { + pfncfg_param.channel_list[i] = wf_chspec_ctlchspec(channel_list[i]); } else { pfncfg_param.channel_list[i] = channel_list[i]; } @@ -1564,13 +1623,13 @@ dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params) sizeof(_params->params_batch.chan_list[0]), _dhd_pno_cmpfunc, NULL); } #ifdef PNO_DEBUG -{ + { DHD_PNO(("Channel list : ")); for (i = 0; i < _params->params_batch.nchan; i++) { DHD_PNO(("%d ", _params->params_batch.chan_list[i])); } DHD_PNO(("\n")); -} + } #endif if (_params->params_batch.nchan) { /* copy the channel list into local array */ @@ -2111,7 +2170,7 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) goto exit; } - pfn_gscan_cfg_t->version = WL_GSCAN_CFG_VERSION; + pfn_gscan_cfg_t->version = WL_GSCAN_CFG_VERSION_1; if (gscan_params->mscan) pfn_gscan_cfg_t->buffer_threshold = gscan_params->buffer_threshold; else @@ -2480,7 +2539,7 @@ dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag) if (old_flag != gscan_params->send_all_results_flag) { wl_pfn_gscan_cfg_t gscan_cfg; - gscan_cfg.version = WL_GSCAN_CFG_VERSION; + gscan_cfg.version = WL_GSCAN_CFG_VERSION_1; gscan_cfg.flags = (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK); gscan_cfg.flags |= GSCAN_CFG_FLAGS_ONLY_MASK; @@ -2904,7 +2963,7 @@ exit: } #endif /* GSCAN_SUPPORT */ -#if defined (GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) +#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) static void * dhd_get_gscan_batch_results(dhd_pub_t *dhd, uint32 *len) { @@ -3098,8 +3157,6 @@ _dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) STATIC_ASSERT(sizeof(wl_pfn_net_info_v1_t) == sizeof(wl_pfn_net_info_v2_t)); STATIC_ASSERT(sizeof(wl_pfn_lnet_info_v1_t) == sizeof(wl_pfn_lnet_info_v2_t)); STATIC_ASSERT(sizeof(wl_pfn_subnet_info_v1_t) == sizeof(wl_pfn_subnet_info_v2_t)); - ASSERT(OFFSETOF(wl_pfn_subnet_info_v1_t, SSID) == - OFFSETOF(wl_pfn_subnet_info_v2_t, u.SSID)); DHD_PNO(("%s enter\n", __FUNCTION__)); _pno_state = PNO_GET_PNOSTATE(dhd); @@ -3466,15 +3523,8 @@ exit: } mutex_unlock(&_pno_state->pno_mutex); exit_no_unlock: -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) - if (waitqueue_active(&_pno_state->get_batch_done)) { - _pno_state->batch_recvd = TRUE; - wake_up(&_pno_state->get_batch_done); - } -#else - if (waitqueue_active(&_pno_state->get_batch_done.wait)) + if (COMPLETION_WAIT_QUEUE_ACTIVE(&_pno_state->get_batch_done.wait)) complete(&_pno_state->get_batch_done); -#endif return err; } @@ -3554,15 +3604,8 @@ dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) params_batch->get_batch.bufsize = bufsize; params_batch->get_batch.reason = reason; params_batch->get_batch.bytes_written = 0; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) - _pno_state->batch_recvd = FALSE; -#endif schedule_work(&_pno_state->work); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) - wait_event(_pno_state->get_batch_done, _pno_state->batch_recvd); -#else wait_for_completion(&_pno_state->get_batch_done); -#endif } #ifdef GSCAN_SUPPORT @@ -3749,14 +3792,14 @@ dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, sizeof(_params->params_hotlist.chan_list[0]), _dhd_pno_cmpfunc, NULL); } #ifdef PNO_DEBUG -{ + { int i; DHD_PNO(("Channel list : ")); for (i = 0; i < _params->params_batch.nchan; i++) { DHD_PNO(("%d ", _params->params_batch.chan_list[i])); } DHD_PNO(("\n")); -} + } #endif if (_params->params_hotlist.nchan) { /* copy the channel list into local array */ @@ -3975,8 +4018,8 @@ dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) void * dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int *size) { - wl_bss_info_t *bi = NULL; - wl_gscan_result_t *gscan_result; + wl_bss_info_v109_t *bi = NULL; + wl_gscan_result_v2_t *gscan_result; wifi_gscan_full_result_t *result = NULL; u32 bi_length = 0; uint8 channel; @@ -3987,7 +4030,7 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int *size = 0; GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); - gscan_result = (wl_gscan_result_t *)data; + gscan_result = (wl_gscan_result_v2_t *)data; GCC_DIAGNOSTIC_POP(); if (!gscan_result) { DHD_ERROR(("Invalid gscan result (NULL pointer)\n")); @@ -4006,7 +4049,8 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int bi = &gscan_result->bss_info[0].info; bi_length = dtoh32(bi->length); if (bi_length != (dtoh32(gscan_result->buflen) - - WL_GSCAN_RESULTS_FIXED_SIZE - WL_GSCAN_INFO_FIXED_FIELD_SIZE)) { + OFFSETOF(wl_gscan_result_v2_t, bss_info) - + OFFSETOF(wl_gscan_bss_info_v2_t, info))) { DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); goto exit; } @@ -4039,7 +4083,7 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int result->fixed.rtt = 0; result->fixed.rtt_sd = 0; osl_get_monotonic_boottime(&ts); - result->fixed.ts = (uint64) TIMESPEC_TO_US(ts); + result->fixed.ts = (uint64) TIMESPEC64_TO_US(ts); result->fixed.beacon_period = dtoh16(bi->beacon_period); result->fixed.capability = dtoh16(bi->capability); result->ie_length = bi_ie_length; @@ -4508,12 +4552,7 @@ dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) { struct dhd_pno_batch_params *params_batch; params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) - if (!waitqueue_active(&_pno_state->get_batch_done)) -#else - if (!waitqueue_active(&_pno_state->get_batch_done.wait)) -#endif - { + if (!COMPLETION_WAIT_QUEUE_ACTIVE(&_pno_state->get_batch_done.wait)) { DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__)); params_batch->get_batch.buf = NULL; params_batch->get_batch.bufsize = 0; @@ -4553,11 +4592,7 @@ int dhd_pno_init(dhd_pub_t *dhd) _pno_state->dhd = dhd; mutex_init(&_pno_state->pno_mutex); INIT_WORK(&_pno_state->work, _dhd_pno_get_batch_handler); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) - init_waitqueue_head(&_pno_state->get_batch_done); -#else init_completion(&_pno_state->get_batch_done); -#endif #ifdef GSCAN_SUPPORT init_waitqueue_head(&_pno_state->batch_get_wait); #endif /* GSCAN_SUPPORT */ @@ -4617,7 +4652,6 @@ int dhd_pno_deinit(dhd_pub_t *dhd) dhd->pno_state = NULL; return err; } -#endif /* OEM_ANDROID */ #ifndef OEM_ANDROID #if defined(NDIS) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.h old mode 100755 new mode 100644 index b2dd02122d43..bec41c3ea325 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.h @@ -2,7 +2,7 @@ * Header file of Broadcom Dongle Host Driver (DHD) * Prefered Network Offload code and Wi-Fi Location Service(WLS) code. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -25,7 +25,7 @@ #ifndef __DHD_PNO_H__ #define __DHD_PNO_H__ -#if defined(OEM_ANDROID) && defined(PNO_SUPPORT) +#if defined(PNO_SUPPORT) #define PNO_TLV_PREFIX 'S' #define PNO_TLV_VERSION '1' #define PNO_TLV_SUBTYPE_LEGACY_PNO '2' @@ -458,12 +458,7 @@ typedef struct dhd_pno_status_info { #ifdef GSCAN_SUPPORT wait_queue_head_t batch_get_wait; #endif /* GSCAN_SUPPORT */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) - wait_queue_head_t get_batch_done; - bool batch_recvd; -#else struct completion get_batch_done; -#endif bool wls_supported; /* wifi location service supported or not */ enum dhd_pno_status pno_status; enum dhd_pno_mode pno_mode; @@ -496,7 +491,7 @@ extern int dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, struct dhd_pno_hotlist_params *hotlist_params); extern bool dhd_dev_is_legacy_pno_enabled(struct net_device *dev); -#if defined (GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) +#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) extern void * dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, void *info, uint32 *len); @@ -544,7 +539,7 @@ extern int dhd_pno_init(dhd_pub_t *dhd); extern int dhd_pno_deinit(dhd_pub_t *dhd); extern bool dhd_is_pno_supported(dhd_pub_t *dhd); extern bool dhd_is_legacy_pno_enabled(dhd_pub_t *dhd); -#if defined (GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) +#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) extern void * dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *info, uint32 *len); #endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ @@ -571,7 +566,7 @@ extern int dhd_pno_set_epno(dhd_pub_t *dhd); extern int dhd_pno_flush_fw_epno(dhd_pub_t *dhd); extern void dhd_pno_set_epno_auth_flag(uint32 *wpa_auth); #endif /* GSCAN_SUPPORT */ -#endif /* #if defined(OEM_ANDROID) && defined(PNO_SUPPORT) */ +#endif /* #if defined(PNO_SUPPORT) */ #if defined(NDIS) #if defined(PNO_SUPPORT) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_proto.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_proto.h old mode 100755 new mode 100644 index 7f0b1216c0b9..6241da7dc067 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_proto.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_proto.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -35,12 +35,6 @@ #include #endif -#ifdef BCMINTERNAL -#ifdef DHD_FWTRACE -#include -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ - #define DEFAULT_IOCTL_RESP_TIMEOUT (5 * 1000) /* 5 seconds */ #ifndef IOCTL_RESP_TIMEOUT #if defined(BCMQT_HW) @@ -121,6 +115,10 @@ extern uint dhd_prot_hdrlen(dhd_pub_t *, void *txp); /* Remove any protocol-specific data header. */ extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp, uchar *buf, uint *len); +#ifdef DHD_LOSSLESS_ROAMING +extern int dhd_update_sdio_data_prio_map(dhd_pub_t *dhdp); +#endif // DHD_LOSSLESS_ROAMING + /* Use protocol to issue ioctl to dongle */ extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len); @@ -133,6 +131,8 @@ extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, /* Add prot dump output to a buffer */ extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); +extern void dhd_prot_counters(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf, + bool print_ringinfo, bool print_pktidinfo); /* Dump extended trap data */ extern int dhd_prot_dump_extended_trap(dhd_pub_t *dhdp, struct bcmstrbuf *b, bool raw); @@ -148,13 +148,19 @@ extern int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, void **pkt, uint32 *free_buf_count); #ifdef BCMPCIE -extern bool dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd, uint bound, int ringtype); -extern bool dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd, uint bound, int ringtype); -extern bool dhd_prot_process_msgbuf_infocpl(dhd_pub_t *dhd, uint bound); -#ifdef BTLOG -extern bool dhd_prot_process_msgbuf_btlogcpl(dhd_pub_t *dhd, uint bound); -#endif /* BTLOG */ -extern int dhd_prot_process_ctrlbuf(dhd_pub_t * dhd); +extern bool dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd, int ringtype, uint32 *txcpl_items); +extern bool dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd, int ringtype, uint32 *rxcpl_items); +extern bool dhd_prot_process_msgbuf_infocpl(dhd_pub_t *dhd, uint bound, + uint32 *evtlog_items); +uint32 dhd_prot_get_tx_post_bound(dhd_pub_t *dhd); +uint32 dhd_prot_get_ctrl_cpl_post_bound(dhd_pub_t *dhd); +uint32 dhd_prot_get_tx_cpl_bound(dhd_pub_t *dhd); +uint32 dhd_prot_get_rx_cpl_post_bound(dhd_pub_t *dhd); +void dhd_prot_set_tx_cpl_bound(dhd_pub_t *dhd, uint32 val); +void dhd_prot_set_rx_cpl_post_bound(dhd_pub_t *dhd, uint32 val); +void dhd_prot_set_tx_post_bound(dhd_pub_t *dhd, uint32 val); +void dhd_prot_set_ctrl_cpl_post_bound(dhd_pub_t *dhd, uint32 val); +extern bool dhd_prot_process_ctrlbuf(dhd_pub_t * dhd, uint32 *ctrlcpl_items); extern int dhd_prot_process_trapbuf(dhd_pub_t * dhd); extern bool dhd_prot_dtohsplit(dhd_pub_t * dhd); extern int dhd_post_dummy_msg(dhd_pub_t *dhd); @@ -183,7 +189,7 @@ extern uint32 dhd_prot_metadatalen_get(dhd_pub_t *dhd, bool rx); extern void dhd_prot_print_flow_ring(dhd_pub_t *dhd, void *msgbuf_flow_info, bool h2d, struct bcmstrbuf *strbuf, const char * fmt); extern void dhd_prot_print_info(dhd_pub_t *dhd, struct bcmstrbuf *strbuf); -extern void dhd_prot_update_txflowring(dhd_pub_t *dhdp, uint16 flow_id, void *msgring_info); +extern bool dhd_prot_update_txflowring(dhd_pub_t *dhdp, uint16 flow_id, void *msgring_info); extern void dhd_prot_txdata_write_flush(dhd_pub_t *dhd, uint16 flow_id); extern uint32 dhd_prot_txp_threshold(dhd_pub_t *dhd, bool set, uint32 val); extern void dhd_prot_reset(dhd_pub_t *dhd); @@ -194,13 +200,17 @@ extern int dhd_prot_flow_ring_batch_suspend_request(dhd_pub_t *dhd, uint16 *ring extern int dhd_prot_flow_ring_resume(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node); #endif /* IDLE_TX_FLOW_MGMT */ extern int dhd_prot_init_info_rings(dhd_pub_t *dhd); -#ifdef BTLOG -extern int dhd_prot_init_btlog_rings(dhd_pub_t *dhd); -#endif /* BTLOG */ -#ifdef DHD_HP2P -extern int dhd_prot_init_hp2p_rings(dhd_pub_t *dhd); -#endif /* DHD_HP2P */ +extern int dhd_prot_init_md_rings(dhd_pub_t *dhd); extern int dhd_prot_check_tx_resource(dhd_pub_t *dhd); +#else /* BCMPCIE */ +static INLINE uint32 dhd_prot_get_tx_post_bound(dhd_pub_t *dhd) { return 0; } +static INLINE uint32 dhd_prot_get_ctrl_cpl_post_bound(dhd_pub_t *dhd) { return 0; } +static INLINE uint32 dhd_prot_get_tx_cpl_bound(dhd_pub_t *dhd) { return 0; } +static INLINE uint32 dhd_prot_get_rx_cpl_post_bound(dhd_pub_t *dhd) { return 0; } +static INLINE void dhd_prot_set_tx_cpl_bound(dhd_pub_t *dhd, uint32 val) { } +static INLINE void dhd_prot_set_rx_cpl_post_bound(dhd_pub_t *dhd, uint32 val) { } +static INLINE void dhd_prot_set_tx_post_bound(dhd_pub_t *dhd, uint32 val) { } +static INLINE void dhd_prot_set_ctrl_cpl_post_bound(dhd_pub_t *dhd, uint32 val) { } #endif /* BCMPCIE */ #ifdef DHD_LB @@ -226,17 +236,9 @@ extern bool dhd_prot_pkt_fixed_rate(dhd_pub_t *dhd, bool enable, bool set); extern void dhd_prot_dma_indx_free(dhd_pub_t *dhd); -#ifdef SNAPSHOT_UPLOAD -/* send request to take snapshot */ -int dhd_prot_send_snapshot_request(dhd_pub_t *dhdp, uint8 snapshot_type, uint8 snapshot_param); -/* get uploaded snapshot */ -int dhd_prot_get_snapshot(dhd_pub_t *dhdp, uint8 snapshot_type, uint32 offset, - uint32 dst_buf_size, uint8 *dst_buf, uint32 *dst_size, bool *is_more); -#endif /* SNAPSHOT_UPLOAD */ - #ifdef EWP_EDL int dhd_prot_init_edl_rings(dhd_pub_t *dhd); -bool dhd_prot_process_msgbuf_edl(dhd_pub_t *dhd); +bool dhd_prot_process_msgbuf_edl(dhd_pub_t *dhd, uint32 *evtlog_items); int dhd_prot_process_edl_complete(dhd_pub_t *dhd, void *evt_decode_data); #endif /* EWP_EDL */ @@ -259,44 +261,12 @@ void dhd_local_buf_reset(char *buf, uint32 len); int dhd_get_hscb_info(dhd_pub_t *dhd, void ** va, uint32 *len); int dhd_get_hscb_buff(dhd_pub_t *dhd, uint32 offset, uint32 length, void * buff); -#ifdef BCMINTERNAL -typedef struct host_page_location_info { - uint32 addr_lo; - uint32 addr_hi; - uint32 binary_size; - uint32 tlv_size; - uint32 tlv_signature; -} host_page_location_info_t; -#define BCM_HOST_PAGE_LOCATION_SIGNATURE 0xFEED10C5u - -#ifdef DHD_FWTRACE -typedef struct host_fwtrace_buf_location_info { - fwtrace_hostaddr_info_t host_buf_info; - uint32 tlv_size; - uint32 tlv_signature; -} host_fwtrace_buf_location_info_t; -/* Host buffer info for pushing the trace info */ -#define BCM_HOST_FWTRACE_BUF_LOCATION_SIGNATURE 0xFEED10C6u -#endif /* DHD_FWTRACE */ -#endif /* BCMINTERNAL */ - -#ifdef DHD_HP2P -extern uint8 dhd_prot_hp2p_enable(dhd_pub_t *dhd, bool set, int enable); -extern uint32 dhd_prot_pkt_threshold(dhd_pub_t *dhd, bool set, uint32 val); -extern uint32 dhd_prot_time_threshold(dhd_pub_t *dhd, bool set, uint32 val); -extern uint32 dhd_prot_pkt_expiry(dhd_pub_t *dhd, bool set, uint32 val); -#endif +extern int dhd_prot_mdring_link_unlink(dhd_pub_t *dhd, int idx, bool link); +extern int dhd_prot_mdring_linked_ring(dhd_pub_t *dhd); #ifdef DHD_MAP_LOGGING extern void dhd_prot_smmu_fault_dump(dhd_pub_t *dhdp); #endif /* DHD_MAP_LOGGING */ -extern uint16 dhd_prot_get_h2d_max_txpost(dhd_pub_t *dhd); -extern void dhd_prot_set_h2d_max_txpost(dhd_pub_t *dhd, uint16 max_txpost); - -#if defined(DHD_HTPUT_TUNABLES) -extern uint16 dhd_prot_get_h2d_htput_max_txpost(dhd_pub_t *dhd); -extern void dhd_prot_set_h2d_htput_max_txpost(dhd_pub_t *dhd, uint16 max_txpost); -#endif /* DHD_HTPUT_TUNABLES */ - +void dhd_prot_set_ring_size_ver(dhd_pub_t *dhd, int version); #endif /* _dhd_proto_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_qos_algo.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_qos_algo.h deleted file mode 100755 index 368d1207eca3..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_qos_algo.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Header file for QOS Algorithm on DHD - * - * Provides type definitions and function prototypes for the QOS Algorithm - * Note that this algorithm is a platform independent layer - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - */ - -#ifndef _DHD_QOS_ALGO_H_ -#define _DHD_QOS_ALGO_H_ - -#define LOWLAT_AVG_PKT_SIZE_LOW 50u -#define LOWLAT_AVG_PKT_SIZE_HIGH 200u -#define LOWLAT_NUM_PKTS_LOW 1u -#define LOWLAT_NUM_PKTS_HIGH 8u -#define LOWLAT_DETECT_CNT_INC_THRESH 10u -#define LOWLAT_DETECT_CNT_DEC_THRESH 0u -#define LOWLAT_DETECT_CNT_UPGRADE_THRESH 4u - -typedef struct qos_stat -{ - /* Statistics */ - unsigned long tx_pkts_prev; - unsigned long tx_bytes_prev; - unsigned long tx_pkts; - unsigned long tx_bytes; - - /* low latency flow detection algorithm counts */ - unsigned char lowlat_detect_count; - bool lowlat_flow; -} qos_stat_t; - -/* QoS alogrithm parameter, controllable at runtime */ -typedef struct _qos_algo_params -{ - /* The avg Tx packet size in the sampling interval must be between - * these two thresholds for QoS upgrade to take place. - * default values = LOWLAT_AVG_PKT_SIZE_LOW, LOWLAT_AVG_PKT_SIZE_HIGH - */ - unsigned long avg_pkt_size_low_thresh; - unsigned long avg_pkt_size_high_thresh; - /* The number of Tx packets in the sampling interval must be - * between these two thresholds for QoS upgrade to happen. - * default values = LOWLAT_NUM_PKTS_LOW, LOWLAT_NUM_PKTS_HIGH - */ - unsigned long num_pkts_low_thresh; - unsigned long num_pkts_high_thresh; - /* If low latency traffic is detected, then the low latency count - * is incremented till the first threshold is hit. - * If traffic ceases to be low latency, then the count is - * decremented till the second threshold is hit. - * default values = LOWLAT_DETECT_CNT_INC_THRESH, LOWLAT_DETECT_CNT_DEC_THRESH - */ - unsigned char detect_cnt_inc_thresh; - unsigned char detect_cnt_dec_thresh; - /* If the low latency count crosses this threshold, the flow will be upgraded. - * Default value = LOWLAT_DETECT_CNT_UPGRADE_THRESH - */ - unsigned char detect_cnt_upgrade_thresh; -} qos_algo_params_t; - -#define QOS_PARAMS(x) (&x->psk_qos->qos_params); - -/* - * Operates on a flow and returns 1 for upgrade and 0 for - * no up-grade - */ -int dhd_qos_algo(dhd_info_t *dhd, qos_stat_t *qos, qos_algo_params_t *qos_params); -int qos_algo_params_init(qos_algo_params_t *qos_params); -#endif /* _DHD_QOS_ALGO_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_rtt.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_rtt.c old mode 100755 new mode 100644 index 9f807e944da6..d3bcbdf3fe58 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_rtt.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_rtt.c @@ -1,7 +1,7 @@ /* * Broadcom Dongle Host Driver (DHD), RTT * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -49,11 +49,24 @@ #include #endif /* WL_NAN */ +#ifdef CUSTOM_PREFIX +#define RTT_PRINT_PREFIX "[%s]"CUSTOM_PREFIX, OSL_GET_RTCTIME() +#define RTT_PRINT_SYSTEM_TIME pr_cont(RTT_PRINT_PREFIX) +#define RTT_CONS_ONLY(args) \ +do { \ + RTT_PRINT_SYSTEM_TIME; \ + pr_cont args; \ +} while (0) +#else +#define RTT_PRINT_SYSTEM_TIME +#define RTT_CONS_ONLY(args) do { printf args;} while (0) +#endif /* CUSTOM_PREFIX */ + static DEFINE_SPINLOCK(noti_list_lock); #define NULL_CHECK(p, s, err) \ do { \ if (!(p)) { \ - printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ + RTT_CONS_ONLY(("NULL POINTER (%s) : %s\n", __FUNCTION__, (s))); \ err = BCME_ERROR; \ return err; \ } \ @@ -70,9 +83,6 @@ static DEFINE_SPINLOCK(noti_list_lock); }\ } while (0) -#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \ - (ts).tv_nsec / NSEC_PER_USEC) - #undef DHD_RTT_MEM #undef DHD_RTT_ERR #define DHD_RTT_MEM DHD_LOG_MEM @@ -88,6 +98,7 @@ static DEFINE_SPINLOCK(noti_list_lock); #define FTM_DEFAULT_CNT_20M 24u #define FTM_DEFAULT_CNT_40M 16u #define FTM_DEFAULT_CNT_80M 11u +#define FTM_DEFAULT_CNT_160M 5u /* To handle congestion env, set max dur/timeout */ #define FTM_MAX_BURST_DUR_TMO_MS 128u @@ -105,7 +116,6 @@ static DEFINE_SPINLOCK(noti_list_lock); /* broadcom specific set to have more accurate data */ #define ENABLE_VHT_ACK -#define CH_MIN_5G_CHANNEL 34 /* CUR ETH became obsolete with this major version onwards */ #define RTT_IOV_CUR_ETH_OBSOLETE 12 @@ -196,6 +206,10 @@ static int dhd_rtt_convert_results_to_host_v2(rtt_result_t *rtt_result, const uint8 *p_data, uint16 tlvid, uint16 len); +static int +dhd_rtt_convert_results_to_host_v3(rtt_result_t *rtt_result, const uint8 *p_data, + uint16 tlvid, uint16 len); + static wifi_rate_v1 dhd_rtt_convert_rate_to_host(uint32 ratespec); @@ -213,6 +227,10 @@ static void dhd_rtt_handle_rtt_session_end(dhd_pub_t *dhd); static void dhd_rtt_timeout_work(struct work_struct *work); static bool dhd_rtt_get_report_header(rtt_status_info_t *rtt_status, rtt_results_header_t **rtt_results_header, struct ether_addr *addr); +static void dhd_rtt_set_ftm_config_param(ftm_config_param_info_t *ftm_params, + int *ftm_param_cnt, rtt_target_info_t *rtt_target, uint16 tlvid); +static int dhd_rtt_ftm_config(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, + void *ftm_cfg_opt, int ftm_cfg_opt_cnt, void *ftm_cfg_gen, int ftm_cfg_gen_cnt); #ifdef WL_NAN static void dhd_rtt_trigger_pending_targets_on_session_end(dhd_pub_t *dhd); #endif /* WL_NAN */ @@ -263,6 +281,10 @@ static const ftm_strmap_entry_t ftm_event_type_loginfo[] = { { WL_PROXD_EVENT_DELAY, "delay" }, { WL_PROXD_EVENT_VS_INITIATOR_RPT, "initiator-report " }, /* rx initiator-rpt */ { WL_PROXD_EVENT_RANGING, "ranging " }, +#ifdef WL_RTT_LCI + { WL_PROXD_EVENT_LCI_MEAS_REP, "lci report" }, + { WL_PROXD_EVENT_CIVIC_MEAS_REP, "civic report" }, +#endif /* WL_RTT_LCI */ { WL_PROXD_EVENT_COLLECT, "collect" }, { WL_PROXD_EVENT_MF_STATS, "mf_stats" }, { WL_PROXD_EVENT_START_WAIT, "start-wait"} @@ -468,6 +490,7 @@ ftm_intvl2nsec(const wl_proxd_intvl_t *intvl) } return ret; } + uint64 ftm_intvl2usec(const wl_proxd_intvl_t *intvl) { @@ -507,6 +530,7 @@ ftm_get_statusmap_info(wl_proxd_status_t id, const ftm_status_map_host_entry_t * } return RTT_STATUS_FAILURE; /* not found */ } + /* * lookup 'id' (as a key) from a table * if found, return the entry pointer, otherwise return NULL @@ -701,7 +725,7 @@ rtt_alloc_getset_buf(dhd_pub_t *dhd, wl_proxd_method_t method, wl_proxd_session_ } /* setup proxd-FTM-method iovar header */ - p_proxd_iov->version = htol16(WL_PROXD_API_VERSION); + p_proxd_iov->version = htol16(WL_PROXD_API_VERSION_3); p_proxd_iov->len = htol16(proxd_iovsize); /* caller may adjust it based on #of TLVs */ p_proxd_iov->cmd = htol16(cmdid); p_proxd_iov->method = htol16(method); @@ -953,6 +977,7 @@ rtt_result_ver(uint16 tlvid, const uint8 *p_data) { uint16 ret = BCME_OK; const wl_proxd_rtt_result_v2_t *r_v2 = NULL; + const wl_proxd_rtt_result_v3_t *r_v3 = NULL; switch (tlvid) { case WL_PROXD_TLV_ID_RTT_RESULT: @@ -967,6 +992,14 @@ rtt_result_ver(uint16 tlvid, const uint8 *p_data) } } break; + case WL_PROXD_TLV_ID_RTT_RESULT_V3: + if (p_data) { + r_v3 = (const wl_proxd_rtt_result_v3_t *)p_data; + if (r_v3->version == WL_PROXD_RTT_RESULT_VERSION_3) { + ret = WL_PROXD_RTT_RESULT_VERSION_3; + } + } + break; default: DHD_RTT_ERR(("%s: > Unsupported TLV ID %d\n", __FUNCTION__, tlvid)); @@ -1020,12 +1053,16 @@ rtt_unpack_xtlv_cbfn(void *ctx, const uint8 *p_data, uint16 tlvid, uint16 len) wl_proxd_ftm_session_status_t *p_data_info = NULL; uint32 chan_data_entry = 0; uint16 expected_rtt_result_ver = 0; +#ifdef WL_RTT_LCI + bcm_xtlv_t *tlv = NULL; +#endif /* WL_RTT_LCI */ BCM_REFERENCE(p_data_info); switch (tlvid) { case WL_PROXD_TLV_ID_RTT_RESULT: case WL_PROXD_TLV_ID_RTT_RESULT_V2: + case WL_PROXD_TLV_ID_RTT_RESULT_V3: DHD_RTT(("WL_PROXD_TLV_ID_RTT_RESULT\n")); expected_rtt_result_ver = rtt_result_ver(tlvid, p_data); switch (expected_rtt_result_ver) { @@ -1037,6 +1074,10 @@ rtt_unpack_xtlv_cbfn(void *ctx, const uint8 *p_data, uint16 tlvid, uint16 len) ret = dhd_rtt_convert_results_to_host_v2((rtt_result_t *)ctx, p_data, tlvid, len); break; + case WL_PROXD_RTT_RESULT_VERSION_3: + ret = dhd_rtt_convert_results_to_host_v3((rtt_result_t *)ctx, + p_data, tlvid, len); + break; default: DHD_RTT_ERR((" > Unsupported RTT_RESULT version\n")); ret = BCME_UNSUPPORTED; @@ -1084,6 +1125,30 @@ rtt_unpack_xtlv_cbfn(void *ctx, const uint8 *p_data, uint16 tlvid, uint16 len) DHD_RTT(("\tmf stats len=%u\n", len)); rtt_prhex("", p_data, len); break; +#ifdef WL_RTT_LCI + case WL_PROXD_TLV_ID_LCI: + tlv = (bcm_xtlv_t *)ctx; + DHD_RTT(("WL_PROXD_TLV_ID_LCI, IE data=%lx, len=%d\n", + (unsigned long)p_data, len)); + rtt_prhex("", p_data, len); + if (tlv) { + tlv->id = WL_PROXD_TLV_ID_LCI; + tlv->len = len; + (void)memcpy_s(tlv->data, len, p_data, len); + } + break; + case WL_PROXD_TLV_ID_CIVIC: + tlv = (bcm_xtlv_t *)ctx; + DHD_RTT(("WL_PROXD_TLV_ID_CIVIC, IE data=%lx, len=%d\n", + (unsigned long)p_data, len)); + rtt_prhex("", p_data, len); + if (tlv) { + tlv->id = WL_PROXD_TLV_ID_CIVIC; + tlv->len = len; + (void)memcpy_s(tlv->data, len, p_data, len); + } + break; +#endif /* WL_RTT_LCI */ default: DHD_RTT_ERR(("> Unsupported TLV ID %d\n", tlvid)); ret = BCME_ERROR; @@ -1253,6 +1318,7 @@ dhd_rtt_delete_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id) return dhd_rtt_common_set_handler(dhd, &subcmd_info, WL_PROXD_METHOD_FTM, session_id); } + #ifdef WL_NAN int dhd_rtt_delete_nan_session(dhd_pub_t *dhd) @@ -1264,6 +1330,7 @@ dhd_rtt_delete_nan_session(dhd_pub_t *dhd) wl_cfgnan_terminate_directed_rtt_sessions(dev, cfg); return BCME_OK; } + /* API to find out if the given Peer Mac from FTM events * is nan-peer. Based on this we will handle the SESSION_END * event. For nan-peer FTM_SESSION_END event is ignored and handled in @@ -1408,7 +1475,7 @@ dhd_rtt_event_trigger_failure(dhd_pub_t *dhd, rtt_target_info_t *rtt_target) msg.datalen = hton32(sizeof(p_event)); msg.addr = rtt_target->addr; - p_event.version = htol16(WL_PROXD_API_VERSION); + p_event.version = htol16(WL_PROXD_API_VERSION_3); p_event.type = htol16(WL_PROXD_EVENT_SESSION_END); p_event.len = htol16(OFFSETOF(wl_proxd_event_t, tlvs)); @@ -1425,6 +1492,10 @@ dhd_rtt_nan_start_session(dhd_pub_t *dhd, rtt_target_info_t *rtt_target) struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); nan_ranging_inst_t *ranging_inst = NULL; rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd); + ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS]; + int ftm_param_cnt = 0; + + memset(ftm_params, 0, sizeof(ftm_params)); NAN_MUTEX_LOCK(); @@ -1433,7 +1504,8 @@ dhd_rtt_nan_start_session(dhd_pub_t *dhd, rtt_target_info_t *rtt_target) goto done; } - if (!wl_cfgnan_is_enabled(cfg)) { /* If nan is not enabled report error */ + if (NAN_RTT_ENABLED(cfg) != TRUE) { + /* If nan is not enabled or nan ranging is not enabled report error */ err = BCME_NOTENABLED; goto done; } @@ -1460,6 +1532,11 @@ dhd_rtt_nan_start_session(dhd_pub_t *dhd, rtt_target_info_t *rtt_target) goto done; } + /* apply event mask */ + dhd_rtt_set_ftm_config_param(ftm_params, &ftm_param_cnt, rtt_target, + WL_PROXD_TLV_ID_EVENT_MASK); + dhd_rtt_ftm_config(dhd, 0, NULL, 0, ftm_params, ftm_param_cnt); + DHD_RTT(("Trigger nan based range request\n")); err = wl_cfgnan_trigger_ranging(bcmcfg_to_prmry_ndev(cfg), cfg, ranging_inst, NULL, NAN_RANGE_REQ_CMD, TRUE); @@ -1486,7 +1563,7 @@ done: static int dhd_rtt_ftm_config(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, - ftm_config_category_t catagory, void *ftm_configs, int ftm_cfg_cnt) + void *ftm_cfg_opt, int ftm_cfg_opt_cnt, void *ftm_cfg_gen, int ftm_cfg_gen_cnt) { ftm_subcmd_info_t subcmd_info; wl_proxd_tlv_t *p_tlv; @@ -1514,12 +1591,13 @@ dhd_rtt_ftm_config(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, p_tlv = &p_proxd_iov->tlvs[0]; /* TLV buffer starts with a full size, will decrement for each packed TLV */ buf_space_left = bufsize; - if (catagory == FTM_CONFIG_CAT_OPTIONS) { + if (ftm_cfg_opt) { ret = rtt_handle_config_options(session_id, &p_tlv, &buf_space_left, - (ftm_config_options_info_t *)ftm_configs, ftm_cfg_cnt); - } else if (catagory == FTM_CONFIG_CAT_GENERAL) { + (ftm_config_options_info_t *)ftm_cfg_opt, ftm_cfg_opt_cnt); + } + if (ftm_cfg_gen) { ret = rtt_handle_config_general(session_id, &p_tlv, &buf_space_left, - (ftm_config_param_info_t *)ftm_configs, ftm_cfg_cnt); + (ftm_config_param_info_t *)ftm_cfg_gen, ftm_cfg_gen_cnt); } if (ret == BCME_OK) { /* update the iov header, set len to include all TLVs + header */ @@ -1554,36 +1632,55 @@ dhd_rtt_get_version(dhd_pub_t *dhd, int *out_version) chanspec_t dhd_rtt_convert_to_chspec(wifi_channel_info channel) { - int bw; - chanspec_t chanspec = 0; - uint8 center_chan; - uint8 primary_chan; - /* set witdh to 20MHZ for 2.4G HZ */ - if (channel.center_freq >= 2400 && channel.center_freq <= 2500) { - channel.width = WIFI_CHAN_WIDTH_20; + chanspec_bw_t bw = INVCHANSPEC; + chanspec_t chanspec = INVCHANSPEC; + int primary_chan; + chanspec_band_t band; + uint32 center_freq = channel.center_freq; + + band = wf_mhz2chanspec_band(center_freq); + if (band == INVCHANSPEC) { + DHD_RTT_ERR(("Invalid centre frequency %x\n", center_freq)); + goto done; } + + primary_chan = wf_mhz2channel(center_freq, 0); + if (primary_chan == -1) { + DHD_RTT_ERR(("Failed to get primary channel for frequency %x\n", + center_freq)); + goto done; + } + switch (channel.width) { case WIFI_CHAN_WIDTH_20: bw = WL_CHANSPEC_BW_20; - primary_chan = wf_mhz2channel(channel.center_freq, 0); - chanspec = wf_channel2chspec(primary_chan, bw); break; case WIFI_CHAN_WIDTH_40: bw = WL_CHANSPEC_BW_40; - primary_chan = wf_mhz2channel(channel.center_freq, 0); - chanspec = wf_channel2chspec(primary_chan, bw); break; case WIFI_CHAN_WIDTH_80: bw = WL_CHANSPEC_BW_80; - primary_chan = wf_mhz2channel(channel.center_freq, 0); - center_chan = wf_mhz2channel(channel.center_freq0, 0); - chanspec = wf_chspec_80(center_chan, primary_chan); break; +#ifdef WL_RTT_BW160 + case WIFI_CHAN_WIDTH_160: + bw = WL_CHANSPEC_BW_160; + break; +#endif /* WL_RTT_BW160 */ default: - DHD_RTT_ERR(("doesn't support this bandwith : %d", channel.width)); - bw = -1; + DHD_RTT_ERR(("doesn't support this bandwith : %d\n", channel.width)); + bw = INVCHANSPEC; break; } + + if ((bw != INVCHANSPEC)) { +#ifdef WL_6G_320_SUPPORT + chanspec = wf_create_chspec_from_primary(primary_chan, bw, band, 0); +#else + chanspec = wf_create_chspec_from_primary(primary_chan, bw, band); +#endif /* WL_6G_320_SUPPORT */ + } + +done: return chanspec; } @@ -1629,6 +1726,29 @@ dhd_rtt_set_next_target_idx(dhd_pub_t *dhd, int start_idx) return (int8)rtt_status->cur_idx; } +/* API to know if the all the targets provided in + * startRTT call from framework are of type NAN + */ +bool +dhd_rtt_is_taget_list_mode_nan(dhd_pub_t *dhd) +{ + rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd); + bool nan_mode = FALSE; + + if (!rtt_status) { + goto exit; + } + + if (rtt_status->rtt_config.target_list_mode == + RNG_TARGET_LIST_MODE_NAN) { + nan_mode = TRUE; + goto exit; + } + +exit: + return nan_mode; +} + void dhd_rtt_set_target_list_mode(dhd_pub_t *dhd) { @@ -1865,6 +1985,7 @@ dhd_rtt_update_geofence_sessions_cnt(dhd_pub_t *dhd, bool incr, rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd); rtt_geofence_cfg_t* geofence_cfg = &rtt_status->geofence_cfg; int ret = BCME_OK; + int geofence_ssn_cnt_before_upd = geofence_cfg->geofence_sessions_cnt; if (incr) { //ASSERT(!dhd_rtt_geofence_sessions_maxed_out(dhd)); @@ -1888,16 +2009,18 @@ dhd_rtt_update_geofence_sessions_cnt(dhd_pub_t *dhd, bool incr, geofence_cfg->geofence_sessions_cnt--; } } - if (peer_addr) { - WL_INFORM_MEM(("session cnt update, upd = %d, cnt = %d, peer : "MACDBG", " - " ret = %d\n", incr, geofence_cfg->geofence_sessions_cnt, - MAC2STRDBG(peer_addr), ret)); - } else { - WL_INFORM_MEM(("session cnt update, upd = %d, cnt = %d, ret = %d\n", - incr, geofence_cfg->geofence_sessions_cnt, ret)); - } exit: + if (peer_addr) { + WL_INFORM_MEM(("session cnt update, upd = %d, cnt = %d, cnt_bef_upd = %d, " + " peer : "MACDBG", ret = %d\n", incr, geofence_cfg->geofence_sessions_cnt, + geofence_ssn_cnt_before_upd, MAC2STRDBG(peer_addr), ret)); + } else { + WL_INFORM_MEM(("session cnt update, upd = %d, cnt = %d, cnt_bef_upd = %d, " + "ret = %d\n", incr, geofence_cfg->geofence_sessions_cnt, + geofence_ssn_cnt_before_upd, ret)); + } + return ret; } @@ -1963,6 +2086,8 @@ dhd_rtt_set_geofence_cur_target_idx(dhd_pub_t *dhd, int8 idx) int8 target_cnt = 0; rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd); + UNUSED_PARAMETER(target_cnt); + target_cnt = rtt_status->geofence_cfg.geofence_target_cnt; ASSERT(idx < target_cnt); rtt_status->geofence_cfg.cur_target_idx = idx; @@ -2113,7 +2238,7 @@ dhd_rtt_remove_geofence_target(dhd_pub_t *dhd, struct ether_addr *peer_addr) int err = BCME_OK; rtt_status_info_t *rtt_status; rtt_geofence_target_info_t *geofence_target_info; - int8 geofence_target_cnt, j, index = 0; + int8 geofence_target_cnt, j, index = DHD_RTT_INVALID_TARGET_INDEX; struct net_device *dev; struct bcm_cfg80211 *cfg; @@ -2132,14 +2257,15 @@ dhd_rtt_remove_geofence_target(dhd_pub_t *dhd, struct ether_addr *peer_addr) goto exit; } - /* Get the geofence_target via peer addr */ - geofence_target_info = dhd_rtt_get_geofence_target(dhd, peer_addr, &index); - if (geofence_target_info == NULL) { + /* Get the geofence_target index via peer addr */ + dhd_rtt_get_geofence_target(dhd, peer_addr, &index); + if (index == DHD_RTT_INVALID_TARGET_INDEX) { DHD_RTT(("Geofencing RTT target not found, remove request dropped\n")); err = BCME_NOTFOUND; goto exit; } + geofence_target_info = rtt_status->geofence_cfg.geofence_target_info; /* left shift all the valid entries, as we dont keep holes in list */ for (j = index; j < geofence_target_cnt; j++) { /* @@ -2147,8 +2273,8 @@ dhd_rtt_remove_geofence_target(dhd_pub_t *dhd, struct ether_addr *peer_addr) * statically allocated */ if ((j + 1) < geofence_target_cnt) { - (void)memcpy_s(&geofence_target_info[j], sizeof(geofence_target_info[j]), - &geofence_target_info[j + 1], sizeof(geofence_target_info[j + 1])); + (void)memcpy_s(&geofence_target_info[j], sizeof(rtt_geofence_target_info_t), + &geofence_target_info[j + 1], sizeof(rtt_geofence_target_info_t)); } else { /* reset the last target info */ bzero(&geofence_target_info[j], sizeof(rtt_geofence_target_info_t)); @@ -2372,6 +2498,7 @@ dhd_rtt_retry(dhd_pub_t *dhd) RTT_SCHED_RTT_RETRY_GEOFENCE); } + static void dhd_rtt_retry_work(struct work_struct *work) { @@ -2479,19 +2606,39 @@ dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt) DHD_RTT_ERR(("rtt is not started\n")); return BCME_OK; } - DHD_RTT(("%s enter\n", __FUNCTION__)); + DHD_RTT_ERR(("dhd_rtt_stop tgt_count %d\n", mac_cnt)); mutex_lock(&rtt_status->rtt_mutex); for (i = 0; i < mac_cnt; i++) { for (j = 0; j < rtt_status->rtt_config.rtt_target_cnt; j++) { if (!bcmp(&mac_list[i], &rtt_status->rtt_config.target_info[j].addr, ETHER_ADDR_LEN)) { rtt_status->rtt_config.target_info[j].disable = TRUE; + dhd_rtt_delete_session(dhd, + rtt_status->rtt_config.target_info[j].sid); +#ifdef WL_RTT_LCI + if (rtt_status->rtt_config.target_info[j].LCI) { + MFREE(dhd->osh, rtt_status->rtt_config.target_info[j].LCI, + rtt_status->rtt_config.target_info[j].LCI->len + + BCM_XTLV_HDR_SIZE); + rtt_status->rtt_config.target_info[j].LCI = NULL; + } + if (rtt_status->rtt_config.target_info[j].LCR) { + MFREE(dhd->osh, rtt_status->rtt_config.target_info[j].LCR, + rtt_status->rtt_config.target_info[j].LCR->len + + BCM_XTLV_HDR_SIZE); + rtt_status->rtt_config.target_info[j].LCR = NULL; + } +#endif /* WL_RTT_LCI */ } } } if (rtt_status->all_cancel) { /* cancel all of request */ rtt_status->status = RTT_STOPPED; + for (i = 0; i < rtt_status->rtt_config.rtt_target_cnt; i++) { + dhd_rtt_delete_session(dhd, + rtt_status->rtt_config.target_info[i].sid); + } DHD_RTT(("current RTT process is cancelled\n")); /* remove the rtt results in cache */ if (!list_empty(&rtt_status->rtt_results_cache)) { @@ -2586,21 +2733,26 @@ dhd_rtt_timeout(dhd_pub_t *dhd) #ifdef WL_NAN if (rtt_status->rtt_config.target_list_mode == RNG_TARGET_LIST_MODE_NAN) { for (idx = rtt_status->start_idx; - idx < rtt_status->rtt_config.rtt_target_cnt; idx++) { + idx < rtt_status->rtt_config.rtt_target_cnt; idx++) { rtt_target = &rtt_status->rtt_config.target_info[idx]; if ((!rtt_target->disable) && - (!dhd_rtt_get_report_header(rtt_status, - NULL, &rtt_target->addr))) { + (!dhd_rtt_get_report_header(rtt_status, + NULL, &rtt_target->addr))) { if (wl_cfgnan_ranging_is_in_prog_for_peer(cfg, &rtt_target->addr)) { ranging_inst = wl_cfgnan_check_for_ranging(cfg, - &rtt_target->addr); - ret = wl_cfgnan_cancel_ranging(ndev, cfg, + &rtt_target->addr); + if (ranging_inst) { + ret = wl_cfgnan_cancel_ranging(ndev, cfg, &ranging_inst->range_id, NAN_RNG_TERM_FLAG_IMMEDIATE, &status); - if (unlikely(ret) || unlikely(status)) { - WL_ERR(("%s:nan range cancel failed ret = %d " - "status = %d\n", __FUNCTION__, - ret, status)); + if (unlikely(ret) || unlikely(status)) { + WL_ERR(("%s:nan range cancel failed " + "ret = %d status = %d\n", + __FUNCTION__, ret, status)); + } + } else { + WL_ERR(("%s: Ranging Instance get failed\n", + __FUNCTION__)); } } dhd_rtt_create_failure_result(rtt_status, &rtt_target->addr); @@ -2728,6 +2880,7 @@ dhd_rtt_set_ftm_config_param(ftm_config_param_info_t *ftm_params, { char eabuf[ETHER_ADDR_STR_LEN]; char chanbuf[CHANSPEC_STR_LEN]; + uint32 num_ftm_pref = rtt_target->num_frames_per_burst; switch (tlvid) { case WL_PROXD_TLV_ID_CUR_ETHER_ADDR: @@ -2772,16 +2925,8 @@ dhd_rtt_set_ftm_config_param(ftm_config_param_info_t *ftm_params, break; case WL_PROXD_TLV_ID_BURST_NUM_FTM: /* number of frame per burst */ - rtt_target->num_frames_per_burst = FTM_DEFAULT_CNT_80M; - if (CHSPEC_IS80(rtt_target->chanspec)) { - rtt_target->num_frames_per_burst = FTM_DEFAULT_CNT_80M; - } else if (CHSPEC_IS40(rtt_target->chanspec)) { - rtt_target->num_frames_per_burst = FTM_DEFAULT_CNT_40M; - } else if (CHSPEC_IS20(rtt_target->chanspec)) { - rtt_target->num_frames_per_burst = FTM_DEFAULT_CNT_20M; - } - ftm_params[*ftm_param_cnt].data16 = - htol16(rtt_target->num_frames_per_burst); + /* get pref num_ftm based on chanspec */ + ftm_params[*ftm_param_cnt].data16 = htol16(num_ftm_pref); ftm_params[*ftm_param_cnt].tlvid = WL_PROXD_TLV_ID_BURST_NUM_FTM; *ftm_param_cnt = *ftm_param_cnt + 1; @@ -2855,6 +3000,16 @@ dhd_rtt_set_ftm_config_param(ftm_config_param_info_t *ftm_params, /* set burst end and session end in ev mask by def */ uint32 event_mask = ((1 << WL_PROXD_EVENT_BURST_END) | (1 << WL_PROXD_EVENT_SESSION_END)); +#ifdef WL_RTT_LCI + /* LCI request */ + if (rtt_target && rtt_target->LCI_request) { + event_mask |= (1 << WL_PROXD_EVENT_LCI_MEAS_REP); + } + /* LCR request (CIVIC) */ + if (rtt_target && rtt_target->LCR_request) { + event_mask |= (1 << WL_PROXD_EVENT_CIVIC_MEAS_REP); + } +#endif /* WL_RTT_LCI */ /* only burst end for directed nan-rtt target */ if (rtt_target && (rtt_target->peer == RTT_PEER_NAN)) { event_mask = (1 << WL_PROXD_EVENT_BURST_END); @@ -2872,96 +3027,20 @@ dhd_rtt_set_ftm_config_param(ftm_config_param_info_t *ftm_params, return; } +/* API to configure a legacy/sta RTT session. + * @rtt_target will be having the user configuration for RTT session + */ static int -dhd_rtt_start(dhd_pub_t *dhd) +dhd_rtt_config_sta_rtt(dhd_pub_t *dhd, struct net_device *dev, + rtt_target_info_t *rtt_target) { - int err = BCME_OK; - int err_at = 0; int ftm_cfg_cnt = 0; - int ftm_param_cnt = 0; ftm_config_options_info_t ftm_configs[FTM_MAX_CONFIGS]; ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS]; - rtt_target_info_t *rtt_target; - rtt_status_info_t *rtt_status; - struct net_device *dev = dhd_linux_get_primary_netdev(dhd); + int ftm_param_cnt = 0; + int err = BCME_OK; + uint8 err_at = 0; u8 ioctl_buf[WLC_IOCTL_SMLEN]; - u8 rtt_invalid_reason = RTT_STATE_VALID; - int rtt_sched_type = RTT_TYPE_INVALID; - - NULL_CHECK(dhd, "dhd is NULL", err); - - rtt_status = GET_RTTSTATE(dhd); - NULL_CHECK(rtt_status, "rtt_status is NULL", err); - - DHD_RTT(("Enter %s\n", __FUNCTION__)); - - if (RTT_IS_STOPPED(rtt_status)) { - DHD_RTT(("No Directed RTT target to process, check for geofence\n")); - goto geofence; - } - - if (rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt) { - err = BCME_RANGE; - err_at = 1; - DHD_RTT(("%s : idx %d is out of range\n", __FUNCTION__, rtt_status->cur_idx)); - if (rtt_status->flags == WL_PROXD_SESSION_FLAG_TARGET) { - DHD_RTT_ERR(("STA is set as Target/Responder \n")); - err = BCME_ERROR; - } - goto exit; - } - - /* Get a target information */ - rtt_target = &rtt_status->rtt_config.target_info[rtt_status->cur_idx]; - - DHD_RTT(("%s enter\n", __FUNCTION__)); - - if (ETHER_ISNULLADDR(rtt_target->addr.octet)) { - err = BCME_BADADDR; - err_at = 2; - DHD_RTT(("RTT Target addr is NULL\n")); - goto exit; - } - - /* check for dp/others concurrency */ - rtt_invalid_reason = dhd_rtt_invalid_states(dev, &rtt_target->addr); - if (rtt_invalid_reason != RTT_STATE_VALID) { - err = BCME_BUSY; - err_at = 3; - DHD_RTT(("DRV State is not valid for RTT\n")); - goto exit; - } - - /* enable ftm */ - err = dhd_rtt_ftm_enable(dhd, TRUE); - if (err) { - DHD_RTT_ERR(("failed to enable FTM (%d)\n", err)); - err_at = 4; - goto exit; - } - rtt_status->status = RTT_ENABLED; - -#ifdef WL_NAN - if (rtt_target->peer == RTT_PEER_NAN) { - rtt_sched_type = RTT_TYPE_NAN_DIRECTED; - /* apply event mask */ - DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt, - rtt_target, WL_PROXD_TLV_ID_EVENT_MASK); - dhd_rtt_ftm_config(dhd, 0, FTM_CONFIG_CAT_GENERAL, - ftm_params, ftm_param_cnt); - /* Ignore return value..failure taken care inside the API */ - dhd_rtt_nan_start_session(dhd, rtt_target); - goto exit; - } -#endif /* WL_NAN */ - - /* delete session of index default sesession */ - err = dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION); - if (err < 0 && err != BCME_NOTFOUND) { - DHD_RTT_ERR(("failed to delete session of FTM (%d)\n", err)); - err_at = 5; - goto exit; - } memset(ftm_configs, 0, sizeof(ftm_configs)); memset(ftm_params, 0, sizeof(ftm_params)); @@ -2969,14 +3048,28 @@ dhd_rtt_start(dhd_pub_t *dhd) /* configure the session 1 as initiator */ if (ftm_cfg_cnt < FTM_MAX_CONFIGS) { ftm_configs[ftm_cfg_cnt].enable = TRUE; - ftm_configs[ftm_cfg_cnt++].flags = + ftm_configs[ftm_cfg_cnt].flags = WL_PROXD_SESSION_FLAG_INITIATOR | WL_PROXD_SESSION_FLAG_RANDMAC; - dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS, - ftm_configs, ftm_cfg_cnt); + if (rtt_target->type == RTT_ONE_WAY) { + ftm_configs[ftm_cfg_cnt].flags |= WL_PROXD_SESSION_FLAG_ONE_WAY; + } +#ifdef WL_RTT_LCI + /* LCI request */ + if (rtt_target->LCI_request) { + ftm_configs[ftm_cfg_cnt].flags |= WL_PROXD_SESSION_FLAG_REQ_LCI; + } + /* LCR request (CIVIC) */ + if (rtt_target->LCR_request) { + ftm_configs[ftm_cfg_cnt].flags |= WL_PROXD_SESSION_FLAG_REQ_CIV; + } +#endif /* WL_RTT_LCI */ + DHD_RTT_ERR(("RTT flags for the session %x sid %d\n", + ftm_configs[ftm_cfg_cnt].flags, rtt_target->sid)); + ftm_cfg_cnt++; } else { DHD_RTT_ERR(("Max FTM Config Options exceeded\n")); err = BCME_ERROR; - err_at = 6; + err_at = 1; goto exit; } @@ -2987,7 +3080,7 @@ dhd_rtt_start(dhd_pub_t *dhd) ioctl_buf, WLC_IOCTL_SMLEN, NULL); if (err) { DHD_RTT_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err)); - err_at = 7; + err_at = 2; goto exit; } memcpy(rtt_target->local_addr.octet, ioctl_buf, ETHER_ADDR_LEN); @@ -3045,18 +3138,255 @@ dhd_rtt_start(dhd_pub_t *dhd) DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt, rtt_target, WL_PROXD_TLV_ID_EVENT_MASK); -#if !defined(WL_USE_RANDOMIZED_SCAN) - /* legacy rtt randmac */ - dhd_set_rand_mac_oui(dhd); -#endif /* !defined(WL_USE_RANDOMIZED_SCAN */ - dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_GENERAL, - ftm_params, ftm_param_cnt); + err = dhd_rtt_ftm_config(dhd, rtt_target->sid, ftm_configs, + ftm_cfg_cnt, ftm_params, ftm_param_cnt); + if (err != BCME_OK) { + err_at = 3; + goto exit; + } + +exit: + if (err != BCME_OK) { + DHD_RTT_ERR(("dhd_rtt_config_sta_rtt: err %d err_at %d\n", + err, err_at)); + } + return err; +} + +#ifdef DHD_RTT_USE_FTM_RANGE + +static int +dhd_rtt_stop_ranging(dhd_pub_t *dhd) +{ + ftm_subcmd_info_t subcmd_info; + subcmd_info.name = "stop-ranging"; + subcmd_info.cmdid = WL_PROXD_CMD_STOP_RANGING; + subcmd_info.handler = NULL; + return dhd_rtt_common_set_handler(dhd, &subcmd_info, + WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL); +} + +static int +dhd_rtt_start_ranging(dhd_pub_t *dhd, rtt_config_params_t *config) +{ + wl_proxd_tlv_t *p_tlv; + wl_proxd_iov_t *p_proxd_iov; + uint16 proxd_iovsize = 0; + uint16 bufsize; + uint16 buf_space_left; + uint16 all_tlvsize; + wl_proxd_ranging_flags_t flags; + wl_proxd_ranging_flags_t flags_mask; + uint16 ranging_sids_size = 0; + wl_proxd_session_id_list_t *ranging_sids = NULL; + uint8 i = 0; + int ret = BCME_OK; + + p_proxd_iov = rtt_alloc_getset_buf(dhd, WL_PROXD_METHOD_FTM, + WL_PROXD_SESSION_ID_GLOBAL, WL_PROXD_CMD_START_RANGING, FTM_IOC_BUFSZ, + &proxd_iovsize); + + if (p_proxd_iov == NULL) { + DHD_RTT_ERR(("dhd_rtt_start_ranging: failed to allocate the iovar (size :%d)\n", + FTM_IOC_BUFSZ)); + ret = BCME_NOMEM; + goto done; + } + + /* setup TLVs */ + bufsize = proxd_iovsize - WL_PROXD_IOV_HDR_SIZE; /* adjust available size for TLVs */ + p_tlv = &p_proxd_iov->tlvs[0]; + buf_space_left = bufsize; + + /* flags & mask */ + flags = WL_PROXD_RANGING_FLAG_DEL_SESSIONS_ON_STOP; + flags_mask = WL_PROXD_RANGING_FLAG_ALL; + + ret = bcm_pack_xtlv_entry((uint8 **) &p_tlv, &buf_space_left, + WL_PROXD_TLV_ID_RANGING_FLAGS, + sizeof(uint16), (uint8 *)&flags, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + DHD_RTT_ERR(("dhd_rtt_start_ranging: failed to pack ranging-flags in xtlv," + " err=%d\n", ret)); + goto done; + } + + ret = bcm_pack_xtlv_entry((uint8 **) &p_tlv, &buf_space_left, + WL_PROXD_TLV_ID_RANGING_FLAGS_MASK, + sizeof(uint16), (uint8 *)&flags_mask, BCM_XTLV_OPTION_ALIGN32); + + if (ret != BCME_OK) { + DHD_RTT_ERR(("dhd_rtt_start_ranging: failed to pack ranging flags_mask in xtlv," + " err=%d\n", ret)); + goto done; /* abort */ + } + + /* allocate a temp buffer for parsing cmd-args */ + ranging_sids_size = OFFSETOF(wl_proxd_session_id_list_t, ids) + + (config->rtt_target_cnt) * sizeof(wl_proxd_session_id_t); + ranging_sids = (wl_proxd_session_id_list_t *)MALLOCZ(dhd->osh, + ranging_sids_size); + if (ranging_sids == NULL) { + DHD_RTT_ERR(("dhd_rtt_start_ranging: failed to allocate %d bytes of" + " memory for ranging\n", ranging_sids_size)); + ret = BCME_NOMEM; + goto done; + } + + for (i = 0; i < config->rtt_target_cnt; i++) { + ranging_sids->ids[i] = config->target_info[i].sid; + } + + ranging_sids->num_ids = config->rtt_target_cnt; + + ret = bcm_pack_xtlv_entry((uint8 **) &p_tlv, &buf_space_left, + WL_PROXD_TLV_ID_SESSION_ID_LIST, ranging_sids_size, + (uint8 *)ranging_sids, BCM_XTLV_OPTION_ALIGN32); + + if (ret != BCME_OK) { + DHD_RTT_ERR(("dhd_rtt_start_ranging: failed to pack ranging-ids in xtlv, err=%d\n", + ret)); + goto done; + } + + /* update the iov header, set len to include all TLVs + header */ + all_tlvsize = (bufsize - buf_space_left); + p_proxd_iov->len = htol16(all_tlvsize + WL_PROXD_IOV_HDR_SIZE); + ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, + all_tlvsize + WL_PROXD_IOV_HDR_SIZE, NULL, 0, TRUE); + if (ret != BCME_OK) { + DHD_RTT_ERR(("%s : failed to set config err %d\n", __FUNCTION__, ret)); + goto done; + } + +done: + MFREE(dhd->osh, p_proxd_iov, proxd_iovsize); + MFREE(dhd->osh, ranging_sids, ranging_sids_size); + return ret; +} +#endif /* DHD_RTT_USE_FTM_RANGE */ + +/* Work thread API to start the RTT. + * If all targets are AP only, then this API will confgure all sessions + * and start(FW) the RTT for first session. + * Else, this API will configure and start a single RTT session. + * If no host provided targets present, then this API will check for + * geofence RTT targets and trigger the same. + */ +static int +dhd_rtt_start(dhd_pub_t *dhd) +{ + int err = BCME_OK; + int err_at = 0; + rtt_target_info_t *rtt_target; + rtt_status_info_t *rtt_status; + struct net_device *dev = dhd_linux_get_primary_netdev(dhd); + u8 rtt_invalid_reason = RTT_STATE_VALID; + int rtt_sched_type = RTT_TYPE_INVALID; + int i = 0; + + NULL_CHECK(dhd, "dhd is NULL", err); + + rtt_status = GET_RTTSTATE(dhd); + NULL_CHECK(rtt_status, "rtt_status is NULL", err); + + DHD_RTT(("Enter %s\n", __FUNCTION__)); + + if (RTT_IS_STOPPED(rtt_status)) { + DHD_RTT(("No Directed RTT target to process, check for geofence\n")); + goto geofence; + } + + if (rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt) { + err = BCME_RANGE; + err_at = 1; + DHD_RTT(("%s : idx %d is out of range\n", __FUNCTION__, rtt_status->cur_idx)); + if (rtt_status->flags == WL_PROXD_SESSION_FLAG_TARGET) { + DHD_RTT_ERR(("STA is set as Target/Responder \n")); + err = BCME_ERROR; + } + goto exit; + } + + /* Get a target information */ + rtt_target = &rtt_status->rtt_config.target_info[rtt_status->cur_idx]; + + DHD_RTT(("%s enter\n", __FUNCTION__)); + + if (ETHER_ISNULLADDR(rtt_target->addr.octet)) { + err = BCME_BADADDR; + err_at = 2; + DHD_RTT(("RTT Target addr is NULL\n")); + goto exit; + } + + /* check for dp/others concurrency */ + rtt_invalid_reason = dhd_rtt_invalid_states(dev, &rtt_target->addr); + if (rtt_invalid_reason != RTT_STATE_VALID) { + err = BCME_BUSY; + err_at = 3; + DHD_RTT(("DRV State is not valid for RTT\n")); + goto exit; + } + + /* enable ftm */ + DHD_RTT_MEM(("Enabling FTM \n")); + err = dhd_rtt_ftm_enable(dhd, TRUE); + if (err) { + DHD_RTT_ERR(("failed to enable FTM (%d)\n", err)); + err_at = 4; + goto exit; + } + rtt_status->status = RTT_ENABLED; + +#ifdef WL_NAN + if (rtt_target->peer == RTT_PEER_NAN) { + rtt_sched_type = RTT_TYPE_NAN_DIRECTED; + /* Ignore return value..failure taken care inside the API */ + dhd_rtt_nan_start_session(dhd, rtt_target); + goto exit; + } +#endif /* WL_NAN */ rtt_sched_type = RTT_TYPE_LEGACY; - err = dhd_rtt_start_session(dhd, FTM_DEFAULT_SESSION, TRUE); + mutex_lock(&rtt_status->rtt_mutex); + if (rtt_status->rtt_config.target_list_mode == + RNG_TARGET_LIST_MODE_LEGACY) { + uint16 sid = WL_PROXD_SID_HOST_START; + DHD_RTT_MEM(("Configuring RTT sessions, count %d\n", + rtt_status->rtt_config.rtt_target_cnt)); + for (i = 0; i < rtt_status->rtt_config.rtt_target_cnt; i++) { + rtt_target = &rtt_status->rtt_config.target_info[i]; + rtt_target->sid = sid++; + err = dhd_rtt_config_sta_rtt(dhd, dev, rtt_target); + if (err) { + goto exit; + } + } + rtt_target = &rtt_status->rtt_config.target_info[0]; +#ifdef DHD_RTT_USE_FTM_RANGE + err = dhd_rtt_start_ranging(dhd, &rtt_status->rtt_config); +#else + err = dhd_rtt_start_session(dhd, rtt_target->sid, TRUE); +#endif /* DHD_RTT_USE_FTM_RANGE */ + if (err) { + goto exit; + } + } else { + rtt_target->sid = FTM_DEFAULT_SESSION; + dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION); + err = dhd_rtt_config_sta_rtt(dhd, dev, rtt_target); + if (err) { + goto exit; + } + err = dhd_rtt_start_session(dhd, FTM_DEFAULT_SESSION, TRUE); + } + mutex_unlock(&rtt_status->rtt_mutex); + if (err) { DHD_RTT_ERR(("failed to start session of FTM : error %d\n", err)); - err_at = 8; + err_at = 5; + goto exit; } else { /* schedule proxd timeout */ schedule_delayed_work(&rtt_status->proxd_timeout, @@ -3071,7 +3401,7 @@ geofence: rtt_sched_type = RTT_TYPE_NAN_GEOFENCE; if ((err = dhd_rtt_sched_geofencing_target(dhd)) != BCME_OK) { DHD_RTT_ERR(("geofencing sched failed, err = %d\n", err)); - err_at = 9; + err_at = 6; } #endif /* WL_NAN */ @@ -3208,7 +3538,7 @@ dhd_rtt_convert_results_to_host_v1(rtt_result_t *rtt_result, const uint8 *p_data struct osl_timespec ts; #endif /* LINUX_VER >= 2.6.39 */ uint32 ratespec; - uint32 avg_dist; + int32 avg_dist; const wl_proxd_rtt_result_v1_t *p_data_info = NULL; const wl_proxd_rtt_sample_v1_t *p_sample_avg = NULL; const wl_proxd_rtt_sample_v1_t *p_sample = NULL; @@ -3325,7 +3655,7 @@ dhd_rtt_convert_results_to_host_v1(rtt_result_t *rtt_result, const uint8 *p_data /* get the time elapsed from boot time */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) osl_get_monotonic_boottime(&ts); - rtt_report->ts = (uint64)TIMESPEC_TO_US(ts); + rtt_report->ts = (uint64)TIMESPEC64_TO_US(ts); #endif /* LINUX_VER >= 2.6.39 */ if (proxd_status == WL_PROXD_E_REMOTE_FAIL) { @@ -3421,7 +3751,7 @@ dhd_rtt_convert_results_to_host_v2(rtt_result_t *rtt_result, const uint8 *p_data struct osl_timespec ts; #endif /* LINUX_VER >= 2.6.39 */ uint32 ratespec; - uint32 avg_dist; + int32 avg_dist; const wl_proxd_rtt_result_v2_t *p_data_info = NULL; const wl_proxd_rtt_sample_v2_t *p_sample_avg = NULL; const wl_proxd_rtt_sample_v2_t *p_sample = NULL; @@ -3558,9 +3888,15 @@ dhd_rtt_convert_results_to_host_v2(rtt_result_t *rtt_result, const uint8 *p_data /* rtt_sd */ rtt.tmu = ltoh16_ua(&p_sample_avg->rtt.tmu); rtt.intvl = ltoh32_ua(&p_sample_avg->rtt.intvl); - rtt_report->rtt = (wifi_timespan)FTM_INTVL2NSEC(&rtt) * 1000; /* nano -> pico seconds */ + if (rtt.tmu == WL_PROXD_TMU_PICO_SEC) { + rtt_report->rtt = (wifi_timespan)rtt.intvl; + } else { + /* nano -> pico seconds */ + rtt_report->rtt = (wifi_timespan)(FTM_INTVL2NSEC(&rtt) * 1000); + } + rtt_report->rtt_sd = ltoh16_ua(&p_data_info->sd_rtt); /* nano -> 0.1 nano */ - DHD_RTT(("rtt_report->rtt : %llu\n", rtt_report->rtt)); + DHD_RTT(("rtt_report->rtt : %lld\n", rtt_report->rtt)); DHD_RTT(("rtt_report->rssi : %d (0.5db)\n", rtt_report->rssi)); /* average distance */ @@ -3575,11 +3911,17 @@ dhd_rtt_convert_results_to_host_v2(rtt_result_t *rtt_result, const uint8 *p_data } else { rtt_report->distance = FTM_INVALID; } + + if (p_data_info->flags & WL_PROXD_RESULT_SIGNED) { + rtt_report->rtt *= -1; + rtt_report->distance *= -1; + } + /* time stamp */ /* get the time elapsed from boot time */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) osl_get_monotonic_boottime(&ts); - rtt_report->ts = (uint64)TIMESPEC_TO_US(ts); + rtt_report->ts = (uint64)TIMESPEC64_TO_US(ts); #endif /* LINUX_VER >= 2.6.39 */ if (proxd_status == WL_PROXD_E_REMOTE_FAIL) { @@ -3661,6 +4003,265 @@ dhd_rtt_convert_results_to_host_v2(rtt_result_t *rtt_result, const uint8 *p_data } return err; } + +static int +dhd_rtt_convert_results_to_host_v3(rtt_result_t *rtt_result, const uint8 *p_data, + uint16 tlvid, uint16 len) +{ + int i; + int err = BCME_OK; + char eabuf[ETHER_ADDR_STR_LEN]; + wl_proxd_result_flags_t flags; + wl_proxd_session_state_t session_state; + wl_proxd_status_t proxd_status; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) + struct timespec64 ts; +#endif /* LINUX_VER >= 2.6.39 */ + uint32 ratespec; + int32 avg_dist; + const wl_proxd_rtt_result_v3_t *p_data_info = NULL; + const wl_proxd_rtt_sample_v3_t *p_sample_avg = NULL; + const wl_proxd_rtt_sample_v3_t *p_sample = NULL; + uint16 num_rtt = 0; + wl_proxd_intvl_t rtt; + wl_proxd_intvl_t p_time; + uint16 snr = 0, bitflips = 0; + wl_proxd_phy_error_t tof_phy_error = 0; + wl_proxd_phy_error_t tof_phy_tgt_error = 0; + wl_proxd_snr_t tof_target_snr = 0; + wl_proxd_bitflips_t tof_target_bitflips = 0; + int16 rssi = 0; + int32 dist = 0; + uint32 chanspec = 0, gd_variance = 0; + uint8 num_ftm = 0; + char *ftm_frame_types[] = FTM_FRAME_TYPES; + rtt_report_t *rtt_report = &(rtt_result->report); + + BCM_REFERENCE(ftm_frame_types); + BCM_REFERENCE(dist); + BCM_REFERENCE(rssi); + BCM_REFERENCE(tof_target_bitflips); + BCM_REFERENCE(tof_target_snr); + BCM_REFERENCE(tof_phy_tgt_error); + BCM_REFERENCE(tof_phy_error); + BCM_REFERENCE(bitflips); + BCM_REFERENCE(snr); + BCM_REFERENCE(chanspec); + BCM_REFERENCE(session_state); + BCM_REFERENCE(ftm_session_state_value_to_logstr); + BCM_REFERENCE(gd_variance); + + NULL_CHECK(rtt_report, "rtt_report is NULL", err); + NULL_CHECK(p_data, "p_data is NULL", err); + DHD_RTT(("%s enter\n", __FUNCTION__)); + p_data_info = (const wl_proxd_rtt_result_v3_t *) p_data; + /* unpack and format 'flags' for display */ + flags = ltoh16_ua(&p_data_info->flags); + /* session state and status */ + session_state = ltoh16_ua(&p_data_info->state); + proxd_status = ltoh32_ua(&p_data_info->status); + bcm_ether_ntoa((&(p_data_info->peer)), eabuf); + + if ((proxd_status != BCME_OK) || (p_data_info->num_meas == 0)) { + DHD_RTT_ERR((">\tTarget(%s) session state=%d(%s), status=%d(%s) " + "num_meas_ota %d num_valid_rtt %d result_flags %x\n", + eabuf, session_state, + ftm_session_state_value_to_logstr(session_state), + proxd_status, ftm_status_value_to_logstr(proxd_status), + p_data_info->num_meas, p_data_info->num_valid_rtt, + p_data_info->flags)); + } else { + DHD_RTT((">\tTarget(%s) session state=%d(%s), status=%d(%s)\n", + eabuf, session_state, + ftm_session_state_value_to_logstr(session_state), + proxd_status, ftm_status_value_to_logstr(proxd_status))); + } + /* show avg_dist (1/256m units), burst_num */ + avg_dist = ltoh32_ua(&p_data_info->avg_dist); + if (avg_dist == 0xffffffff) { /* report 'failure' case */ + DHD_RTT((">\tavg_dist=-1m, burst_num=%d, valid_measure_cnt=%d\n", + ltoh16_ua(&p_data_info->burst_num), + p_data_info->num_valid_rtt)); /* in a session */ + avg_dist = FTM_INVALID; + } else { + DHD_RTT((">\tavg_dist=%d.%04dm, burst_num=%d, valid_measure_cnt=%d num_ftm=%d " + "num_meas_ota=%d, result_flags=%x\n", avg_dist >> 8, /* 1/256m units */ + ((avg_dist & 0xff) * 625) >> 4, + ltoh16_ua(&p_data_info->burst_num), + p_data_info->num_valid_rtt, + p_data_info->num_ftm, p_data_info->num_meas, + p_data_info->flags)); /* in a session */ + } + rtt_result->rtt_detail.num_ota_meas = p_data_info->num_meas; + rtt_result->rtt_detail.result_flags = p_data_info->flags; + /* show 'avg_rtt' sample */ + /* in v2, avg_rtt is the first element of the variable rtt[] */ + p_sample_avg = &p_data_info->rtt[0]; + ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample_avg->rtt.tmu)); + DHD_RTT((">\tavg_rtt sample: rssi=%d rtt=%d%s std_deviation =%d.%d" + "ratespec=0x%08x chanspec=0x%08x gd_variance %u\n", + (int16) ltoh16_ua(&p_sample_avg->rssi), + ltoh32_ua(&p_sample_avg->rtt.intvl), + ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample_avg->rtt.tmu)), + ltoh16_ua(&p_data_info->sd_rtt)/10, ltoh16_ua(&p_data_info->sd_rtt)%10, + ltoh32_ua(&p_sample_avg->ratespec), + ltoh32_ua(&p_sample_avg->chanspec), + ltoh32_ua(&p_sample_avg->gd_variance))); + + /* set peer address */ + rtt_report->addr = p_data_info->peer; + + /* burst num */ + rtt_report->burst_num = ltoh16_ua(&p_data_info->burst_num); + + /* success num */ + rtt_report->success_num = p_data_info->num_valid_rtt; + + /* num-ftm configured */ + rtt_report->ftm_num = p_data_info->num_ftm; + + /* actual number of FTM supported by peer */ + rtt_report->num_per_burst_peer = p_data_info->num_ftm; + rtt_report->negotiated_burst_num = p_data_info->num_ftm; + + /* status */ + rtt_report->status = ftm_get_statusmap_info(proxd_status, + &ftm_status_map_info[0], ARRAYSIZE(ftm_status_map_info)); + + /* Framework expects status as SUCCESS else all results will be + * set to zero even if we have partial valid result. + * So setting status as SUCCESS if we have a valid_rtt + * On burst timeout we stop burst with "timeout" reason and + * on msch end we set status as "cancel" + */ + if ((proxd_status == WL_PROXD_E_TIMEOUT || + proxd_status == WL_PROXD_E_CANCELED) && + rtt_report->success_num) { + rtt_report->status = RTT_STATUS_SUCCESS; + } + + /* rssi (0.5db) */ + rtt_report->rssi = ABS((wl_proxd_rssi_t)ltoh16_ua(&p_sample_avg->rssi)) * 2; + + /* rx rate */ + ratespec = ltoh32_ua(&p_sample_avg->ratespec); + rtt_report->rx_rate = dhd_rtt_convert_rate_to_host(ratespec); + + /* tx rate */ + if (flags & WL_PROXD_RESULT_FLAG_VHTACK) { + rtt_report->tx_rate = dhd_rtt_convert_rate_to_host(0x2010010); + } else { + rtt_report->tx_rate = dhd_rtt_convert_rate_to_host(0xc); + } + + /* rtt_sd */ + rtt.tmu = ltoh16_ua(&p_sample_avg->rtt.tmu); + rtt.intvl = ltoh32_ua(&p_sample_avg->rtt.intvl); + rtt_report->rtt = (wifi_timespan)FTM_INTVL2NSEC(&rtt) * 1000; /* nano -> pico seconds */ + rtt_report->rtt_sd = ltoh16_ua(&p_data_info->sd_rtt); /* nano -> 0.1 nano */ + DHD_RTT(("rtt_report->rtt : %llu\n", rtt_report->rtt)); + DHD_RTT(("rtt_report->rssi : %d (0.5db)\n", rtt_report->rssi)); + + /* average distance */ + if (avg_dist != FTM_INVALID) { + rtt_report->distance = (avg_dist >> 8) * 1000; /* meter -> mm */ + rtt_report->distance += (avg_dist & 0xff) * 1000 / 256; + /* rtt_sd is in 0.1 ns. + * host needs distance_sd in milli mtrs + * (0.1 * rtt_sd/2 * 10^-9) * C * 1000 + */ + rtt_report->distance_sd = rtt_report->rtt_sd * 15; /* mm */ + } else { + rtt_report->distance = FTM_INVALID; + } + /* time stamp */ + /* get the time elapsed from boot time */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) + ts = ktime_to_timespec64(ktime_get_boottime()); + rtt_report->ts = (uint64)TIMESPEC64_TO_US(ts); +#endif /* LINUX_VER >= 2.6.39 */ + + if (proxd_status == WL_PROXD_E_REMOTE_FAIL) { + /* retry time after failure */ + p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl); + p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu); + rtt_report->retry_after_duration = FTM_INTVL2SEC(&p_time); /* s -> s */ + DHD_RTT((">\tretry_after: %d%s\n", + ltoh32_ua(&p_data_info->u.retry_after.intvl), + ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.retry_after.tmu)))); + } else { + /* burst duration */ + p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl); + p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu); + rtt_report->burst_duration = FTM_INTVL2MSEC(&p_time); /* s -> ms */ + DHD_RTT((">\tburst_duration: %d%s\n", + ltoh32_ua(&p_data_info->u.burst_duration.intvl), + ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu)))); + DHD_RTT(("rtt_report->burst_duration : %d\n", rtt_report->burst_duration)); + } + /* display detail if available */ + num_rtt = ltoh16_ua(&p_data_info->num_rtt); + if (num_rtt > 0) { + DHD_RTT((">\tnum rtt: %d samples\n", num_rtt)); + p_sample = &p_data_info->rtt[1]; + for (i = 0; i < num_rtt; i++) { + snr = 0; + bitflips = 0; + tof_phy_error = 0; + tof_phy_tgt_error = 0; + tof_target_snr = 0; + tof_target_bitflips = 0; + rssi = 0; + dist = 0; + num_ftm = p_data_info->num_ftm; + /* FTM frames 1,4,7,11 have valid snr, rssi and bitflips */ + if ((i % num_ftm) == 1) { + rssi = (wl_proxd_rssi_t) ltoh16_ua(&p_sample->rssi); + snr = (wl_proxd_snr_t) ltoh16_ua(&p_sample->snr); + bitflips = (wl_proxd_bitflips_t) ltoh16_ua(&p_sample->bitflips); + tof_phy_error = + (wl_proxd_phy_error_t) + ltoh32_ua(&p_sample->tof_phy_error); + tof_phy_tgt_error = + (wl_proxd_phy_error_t) + ltoh32_ua(&p_sample->tof_tgt_phy_error); + tof_target_snr = + (wl_proxd_snr_t) + ltoh16_ua(&p_sample->tof_tgt_snr); + tof_target_bitflips = + (wl_proxd_bitflips_t) + ltoh16_ua(&p_sample->tof_tgt_bitflips); + dist = ltoh32_ua(&p_sample->distance); + chanspec = ltoh32_ua(&p_sample->chanspec); + gd_variance = ltoh32_ua(&p_sample->gd_variance); + } else { + rssi = -1; + snr = 0; + bitflips = 0; + dist = 0; + tof_target_bitflips = 0; + tof_target_snr = 0; + tof_phy_tgt_error = 0; + } + DHD_RTT((">\t sample[%d]: id=%d rssi=%d snr=0x%x bitflips=%d" + " tof_phy_error %x tof_phy_tgt_error %x target_snr=0x%x" + " target_bitflips=%d dist=%d rtt=%d%s status %s Type %s" + " coreid=%d chanspec=0x%08x gd_variance=%u\n", + i, p_sample->id, rssi, snr, + bitflips, tof_phy_error, tof_phy_tgt_error, + tof_target_snr, + tof_target_bitflips, dist, + ltoh32_ua(&p_sample->rtt.intvl), + ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)), + ftm_status_value_to_logstr(ltoh32_ua(&p_sample->status)), + ftm_frame_types[i % num_ftm], p_sample->coreid, + chanspec, gd_variance)); + p_sample++; + } + } + return err; +} + #ifdef WL_CFG80211 /* Common API for handling Session End. * This API will flush out the results for a peer MAC. @@ -3705,11 +4306,22 @@ dhd_rtt_handle_rtt_session_end(dhd_pub_t *dhd) struct net_device *ndev = dhd_linux_get_primary_netdev(dhd); struct bcm_cfg80211 *cfg = wiphy_priv(ndev->ieee80211_ptr->wiphy); #endif /* WL_NAN */ + int i; + rtt_target_info_t *rtt_target = NULL; + rtt_config_params_t *rtt_config = &rtt_status->rtt_config; + + /* Cancel pending proxd timeout work if any */ + if (delayed_work_pending(&rtt_status->proxd_timeout)) { + cancel_delayed_work(&rtt_status->proxd_timeout); + } /* check if all targets results received */ all_targets_done = dhd_rtt_all_directed_targets_done(dhd); if (all_targets_done) { DHD_RTT_MEM(("RTT_STOPPED\n")); +#ifdef DHD_RTT_USE_FTM_RANGE + dhd_rtt_stop_ranging(dhd); +#endif rtt_status->status = RTT_STOPPED; /* notify the completed information to others */ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); @@ -3736,15 +4348,17 @@ dhd_rtt_handle_rtt_session_end(dhd_pub_t *dhd) /* reinitialize the HEAD */ INIT_LIST_HEAD(&rtt_status->rtt_results_cache); /* clear information for rtt_config */ - rtt_status->rtt_config.rtt_target_cnt = 0; - memset_s(rtt_status->rtt_config.target_info, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT), + if (rtt_config->target_list_mode == RNG_TARGET_LIST_MODE_LEGACY) { + for (i = 0; i < rtt_config->rtt_target_cnt; i++) { + rtt_target = &rtt_status->rtt_config.target_info[i]; + dhd_rtt_delete_session(dhd, rtt_target->sid); + } + dhd_rtt_ftm_enable(dhd, FALSE); + } + rtt_config->rtt_target_cnt = 0; + (void)memset_s(rtt_config->target_info, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT), 0, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT)); rtt_status->cur_idx = 0; - - /* Cancel pending proxd timeout work if any */ - if (delayed_work_pending(&rtt_status->proxd_timeout)) { - cancel_delayed_work(&rtt_status->proxd_timeout); - } #ifdef WL_NAN /* Reset for Geofence */ wl_cfgnan_reset_geofence_ranging(cfg, NULL, @@ -3752,28 +4366,30 @@ dhd_rtt_handle_rtt_session_end(dhd_pub_t *dhd) #endif /* WL_NAN */ } else { /* Targets still pending */ - if (rtt_status->rtt_config.target_list_mode == RNG_TARGET_LIST_MODE_LEGACY) { - /* Pure legacy target list */ - - /* Cancel pending proxd timeout work if any */ - if (delayed_work_pending(&rtt_status->proxd_timeout)) { - cancel_delayed_work(&rtt_status->proxd_timeout); - } - - dhd_rtt_set_next_target_idx(dhd, (rtt_status->cur_idx + 1)); - if (rtt_status->cur_idx < rtt_status->rtt_config.rtt_target_cnt) { - /* restart to measure RTT from next device */ - DHD_INFO(("restart to measure rtt\n")); - rtt_status->rtt_sched = TRUE; - schedule_work(&rtt_status->work); - } - } #ifdef WL_NAN - else if (rtt_status->rtt_config.target_list_mode == RNG_TARGET_LIST_MODE_NAN) { + if (rtt_config->target_list_mode == RNG_TARGET_LIST_MODE_NAN) { /* Pure NAN target list */ dhd_rtt_trigger_pending_targets_on_session_end(dhd); - } + } else #endif /* WL_NAN */ + { + /* Pure legacy target list or mixed list */ + dhd_rtt_set_next_target_idx(dhd, (rtt_status->cur_idx + 1)); + if (rtt_status->cur_idx < rtt_config->rtt_target_cnt) { + rtt_target = &rtt_config->target_info[rtt_status->cur_idx]; + /* restart to measure RTT from next device */ + if (rtt_config->target_list_mode == RNG_TARGET_LIST_MODE_LEGACY) { +#ifndef DHD_RTT_USE_FTM_RANGE + dhd_rtt_start_session(dhd, rtt_target->sid, TRUE); +#endif + } else { + dhd_rtt_schedule_rtt_work_thread(dhd, + rtt_status->rtt_sched_reason); + } + } + } + DHD_RTT_MEM(("Triggered/schedlued next target idx %d mode %d\n", + rtt_status->cur_idx, rtt_config->target_list_mode)); } } #endif /* WL_CFG80211 */ @@ -3814,7 +4430,7 @@ dhd_rtt_create_failure_result(rtt_status_info_t *rtt_status, } /* fill out the results from the configuration param */ rtt_result->report.ftm_num = rtt_target_info->num_frames_per_burst; - rtt_result->report.type = RTT_TWO_WAY; + rtt_result->report.type = rtt_target_info->type; DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num)); rtt_result->report_len = RTT_REPORT_SIZE; rtt_result->report.status = RTT_STATUS_FAIL_NO_RSP; @@ -3959,6 +4575,21 @@ dhd_rtt_handle_directed_rtt_burst_end(dhd_pub_t *dhd, struct ether_addr *peer_ad ret = dhd_rtt_parse_result_event(proxd_ev_data, tlvs_len, rtt_result); #ifdef WL_CFG80211 if (ret == BCME_OK) { + rtt_target_info_t *target = + &rtt_status->rtt_config.target_info[rtt_status->cur_idx]; +#ifdef WL_RTT_LCI + /* assign the cached location info */ + if (target->LCI) { + rtt_result->report.LCI = (bcm_tlv_t*)target->LCI->data; + rtt_result->report_len += target->LCI->len; + } + if (target->LCR) { + rtt_result->report.LCR = (bcm_tlv_t*)target->LCR->data; + rtt_result->report_len += target->LCR->len; + } +#endif /* WL_RTT_LCI */ + rtt_result->report.type = target->type; + list_add_tail(&rtt_result->list, &rtt_results_header->result_list); rtt_results_header->result_cnt++; rtt_results_header->result_tot_len += rtt_result->report_len + @@ -4002,7 +4633,9 @@ dhd_rtt_nan_range_report(struct bcm_cfg80211 *cfg, rtt_status = rtt_result->report.status; bzero(&range_res, sizeof(range_res)); - range_res.dist_mm = rtt_result->report.distance; + /* RTT can be negative(for GG req).. for geofence make it zero */ + range_res.dist_mm = (rtt_result->report.distance < 0) ? + 0 : rtt_result->report.distance; /* same src and header len, ignoring ret val here */ (void)memcpy_s(&range_res.peer_m_addr, ETHER_ADDR_LEN, &rtt_result->report.addr, ETHER_ADDR_LEN); @@ -4164,9 +4797,9 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) } p_event = (wl_proxd_event_t *) event_data; version = ltoh16(p_event->version); - if (version < WL_PROXD_API_VERSION) { + if (version < WL_PROXD_API_VERSION_3) { DHD_RTT_ERR(("ignore non-ftm event version = 0x%0x < WL_PROXD_API_VERSION (0x%x)\n", - version, WL_PROXD_API_VERSION)); + version, WL_PROXD_API_VERSION_3)); return ret; } @@ -4266,7 +4899,7 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) * as it would not be needed any further */ MFREE(dhd->osh, rtt_result, - sizeof(rtt_result_t)); + sizeof(rtt_result_t)); goto exit; } break; @@ -4317,6 +4950,46 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) case WL_PROXD_EVENT_VS_INITIATOR_RPT: DHD_RTT(("WL_PROXD_EVENT_VS_INITIATOR_RPT\n ")); break; +#ifdef WL_RTT_LCI + case WL_PROXD_EVENT_LCI_MEAS_REP: + case WL_PROXD_EVENT_CIVIC_MEAS_REP: + DHD_RTT(("WL_PROXD_EVENT_LCI/CIVIC_MEAS_REP\n")); + if (tlvs_len > 0) { + void *buffer = NULL; + if (!(buffer = (void *)MALLOCZ(dhd->osh, tlvs_len))) { + ret = -ENOMEM; + goto exit; + } + /* unpack TLVs and invokes the cbfn to print the event content TLVs */ + ret = bcm_unpack_xtlv_buf(buffer, + (uint8 *)&p_event->tlvs[0], tlvs_len, + BCM_XTLV_OPTION_NONE, rtt_unpack_xtlv_cbfn); + if (ret != BCME_OK) { + DHD_RTT_ERR(("%s : Failed to unpack xtlv for event %d\n", + __FUNCTION__, event_type)); + MFREE(dhd->osh, buffer, tlvs_len); + goto exit; + } + if (event_type == WL_PROXD_EVENT_LCI_MEAS_REP) { + /* free previous one and update it */ + if (target->LCI) { + MFREE(dhd->osh, target->LCI, + target->LCI->len + BCM_XTLV_HDR_SIZE); + } + DHD_RTT(("WL_PROXD_EVENT_LCI_MEAS_REP: cache the LCI tlv\n")); + target->LCI = (bcm_xtlv_t *)buffer; + } else { + /* free previous one and update it */ + if (target->LCR) { + MFREE(dhd->osh, target->LCR, + target->LCR->len + BCM_XTLV_HDR_SIZE); + } + DHD_RTT(("WL_PROXD_EVENT_CIVIC_MEAS_REP: cache the LCR tlv\n")); + target->LCR = (bcm_xtlv_t *)buffer; + } + } + break; +#endif /* WL_RTT_LCI */ case WL_PROXD_EVENT_RANGING: DHD_RTT(("WL_PROXD_EVENT_RANGING\n")); break; @@ -4373,6 +5046,13 @@ exit: return ret; } +/* + * RTT Event Handler + * for builds needing + * only debug purpose + * and not functional + */ + #ifdef WL_CFG80211 static void dhd_rtt_work(struct work_struct *work) @@ -4509,12 +5189,16 @@ dhd_rtt_enable_responder(dhd_pub_t *dhd, wifi_channel_info *channel_info) chanspec = dhd_rtt_convert_to_chspec(channel); DHD_RTT(("chanspec/channel set as %s for rtt.\n", wf_chspec_ntoa(chanspec, chanbuf))); + if (chanspec == INVCHANSPEC) { + DHD_RTT_ERR(("Channel is not valid \n")); + goto exit; + } err = wldev_iovar_setint(dev, "chanspec", chanspec); if (err) { DHD_RTT_ERR(("Failed to set the chanspec \n")); } } - rtt_status->pm = PM_OFF; + err = wldev_ioctl_get(dev, WLC_GET_PM, &rtt_status->pm, sizeof(rtt_status->pm)); DHD_RTT(("Current PM value read %d\n", rtt_status->pm)); if (err) { @@ -4544,8 +5228,8 @@ dhd_rtt_enable_responder(dhd_pub_t *dhd, wifi_channel_info *channel_info) ftm_configs[ftm_cfg_cnt++].flags = WL_PROXD_SESSION_FLAG_TARGET; rtt_status->flags = WL_PROXD_SESSION_FLAG_TARGET; DHD_RTT(("Set the device as responder \n")); - err = dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS, - ftm_configs, ftm_cfg_cnt); + err = dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, + ftm_configs, ftm_cfg_cnt, NULL, 0); exit: if (err) { rtt_status->status = RTT_STOPPED; @@ -4553,7 +5237,7 @@ exit: dhd_rtt_ftm_enable(dhd, FALSE); DHD_RTT(("restoring the PM value \n")); if (rtt_status->pm_restore) { - pm = PM_FAST; + pm = rtt_status->pm; err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm)); if (err) { DHD_RTT_ERR(("Failed to restore PM \n")); @@ -4583,7 +5267,7 @@ dhd_rtt_cancel_responder(dhd_pub_t *dhd) } rtt_status->status = RTT_STOPPED; if (rtt_status->pm_restore) { - pm = PM_FAST; + pm = rtt_status->pm; DHD_RTT(("pm_restore =%d \n", rtt_status->pm_restore)); err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm)); if (err) { @@ -4661,6 +5345,7 @@ dhd_rtt_attach(dhd_pub_t *dhd) goto exit; } rtt_status->dhd = dhd; + rtt_status->pm = PM_FAST; mutex_init(&rtt_status->rtt_mutex); mutex_init(&rtt_status->geofence_mutex); INIT_LIST_HEAD(&rtt_status->noti_fn_list); @@ -4693,6 +5378,10 @@ dhd_rtt_detach(dhd_pub_t *dhd) #ifdef WL_CFG80211 rtt_status_info_t *rtt_status; +#ifdef WL_RTT_LCI + rtt_config_params_t *rtt_config; + int i; +#endif /* WL_RTT_LCI */ NULL_CHECK(dhd, "dhd is NULL", err); rtt_status = GET_RTTSTATE(dhd); @@ -4706,6 +5395,22 @@ dhd_rtt_detach(dhd_pub_t *dhd) } exit: +#ifdef WL_RTT_LCI + /* free the cache of LCI/CIVIC IE */ + rtt_config = &(rtt_status->rtt_config); + for (i = 0; i < rtt_config->rtt_target_cnt; i++) { + if (rtt_config->target_info[i].LCI) { + MFREE(dhd->osh, rtt_config->target_info[i].LCI, + rtt_config->target_info[i].LCI->len + + BCM_XTLV_HDR_SIZE); + } + if (rtt_config->target_info[i].LCR) { + MFREE(dhd->osh, rtt_config->target_info[i].LCR, + rtt_config->target_info[i].LCR->len + + BCM_XTLV_HDR_SIZE); + } + } +#endif /* WL_RTT_LCI */ MFREE(dhd->osh, rtt_status->rtt_config.target_info, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT)); MFREE(dhd->osh, dhd->rtt_state, sizeof(rtt_status_info_t)); @@ -4734,11 +5439,12 @@ dhd_rtt_init(dhd_pub_t *dhd) DHD_RTT_MEM(("dhd_rtt_init ENTRY\n")); ret = dhd_rtt_get_version(dhd, &version); - if (ret == BCME_OK && (version == WL_PROXD_API_VERSION)) { + if (ret == BCME_OK && (version == WL_PROXD_API_VERSION_3)) { DHD_RTT_ERR(("%s : FTM is supported\n", __FUNCTION__)); dhd->rtt_supported = TRUE; - /* TODO : need to find a way to check rtt capability */ - /* rtt_status->rtt_capa.proto |= RTT_CAP_ONE_WAY; */ +#ifdef WL_RTT_ONE_WAY + rtt_status->rtt_capa.proto |= RTT_CAP_ONE_WAY; +#endif /* WIFI_RTT_ONE_WAY */ rtt_status->rtt_capa.proto |= RTT_CAP_FTM_WAY; /* indicate to set tx rate */ @@ -4753,12 +5459,15 @@ dhd_rtt_init(dhd_pub_t *dhd) rtt_status->rtt_capa.bw |= RTT_BW_20; rtt_status->rtt_capa.bw |= RTT_BW_40; rtt_status->rtt_capa.bw |= RTT_BW_80; +#ifdef WL_RTT_BW160 + rtt_status->rtt_capa.bw |= RTT_BW_160; +#endif /* WL_RTT_BW160 */ } else { if ((ret != BCME_OK) || (version == 0)) { DHD_RTT_ERR(("%s : FTM is not supported\n", __FUNCTION__)); } else { DHD_RTT_ERR(("%s : FTM version mismatch between HOST (%d) and FW (%d)\n", - __FUNCTION__, WL_PROXD_API_VERSION, version)); + __FUNCTION__, WL_PROXD_API_VERSION_3, version)); } goto exit; } @@ -4797,20 +5506,15 @@ dhd_rtt_deinit(dhd_pub_t *dhd) DHD_RTT_MEM(("dhd_rtt_deinit: ENTER\n")); #ifdef WL_NAN - if (delayed_work_pending(&rtt_status->rtt_retry_timer)) { - cancel_delayed_work_sync(&rtt_status->rtt_retry_timer); - } + cancel_delayed_work_sync(&rtt_status->rtt_retry_timer); #endif /* WL_NAN */ - if (work_pending(&rtt_status->work)) { - cancel_work_sync(&rtt_status->work); - rtt_status->rtt_sched = FALSE; - } + cancel_work_sync(&rtt_status->work); + rtt_status->rtt_sched = FALSE; - if (delayed_work_pending(&rtt_status->proxd_timeout)) { - cancel_delayed_work_sync(&rtt_status->proxd_timeout); - } + cancel_delayed_work_sync(&rtt_status->proxd_timeout); + mutex_lock(&rtt_status->rtt_mutex); /* * Cleanup attempt is required, * if legacy RTT session is in progress @@ -4848,6 +5552,7 @@ dhd_rtt_deinit(dhd_pub_t *dhd) MFREE(dhd->osh, rtt_header, sizeof(rtt_results_header_t)); } } + mutex_unlock(&rtt_status->rtt_mutex); GCC_DIAGNOSTIC_POP(); DHD_RTT_MEM(("dhd_rtt_deinit: EXIT, err = %d\n", err)); #endif /* WL_CFG80211 */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_rtt.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_rtt.h old mode 100755 new mode 100644 index dd3812234b89..6fb3500771d7 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_rtt.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_rtt.h @@ -1,7 +1,7 @@ /* * Broadcom Dongle Host Driver (DHD), RTT * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -225,6 +225,10 @@ typedef struct rtt_target_info { uint32 num_retries_per_ftmr; uint8 LCI_request; uint8 LCR_request; +#ifdef WL_RTT_LCI + bcm_xtlv_t *LCI; /* LCI Report */ + bcm_xtlv_t *LCR; /* Location Civic Report */ +#endif /* WL_RTT_LCI */ /* * Applies to 1-sided and 2-sided RTT. Valid values will * be 2-11 and 15 as specified by the 802.11mc std for @@ -237,8 +241,9 @@ typedef struct rtt_target_info { */ uint32 burst_duration; uint32 burst_timeout; - uint8 preamble; /* 1 - Legacy, 2 - HT, 4 - VHT */ - uint8 bw; /* 5, 10, 20, 40, 80, 160 */ + uint8 preamble; /* 1 - Legacy, 2 - HT, 4 - VHT */ + uint8 bw; /* 5, 10, 20, 40, 80, 160 */ + uint16 sid; /* session ID for the target */ } rtt_target_info_t; typedef struct rtt_goefence_target_info { @@ -549,6 +554,9 @@ void dhd_rtt_set_geofence_setup_status(dhd_pub_t *dhd, bool inprog, struct ether_addr *peer_addr); int dhd_rtt_get_max_nan_rtt_sessions_supported(dhd_pub_t *dhd); + +bool dhd_rtt_is_taget_list_mode_nan(dhd_pub_t *dhd); + #endif /* WL_NAN */ #endif /* WL_CFG80211 */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c index ed5c314eafee..b0fd358e7b04 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c @@ -1,7 +1,7 @@ /* * DHD Bus Module for SDIO * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -69,6 +69,7 @@ #include #include #include +#include #include #ifdef DHD_PKTDUMP_TOFW #include @@ -93,6 +94,12 @@ #include #endif /* DEBUGGER || DHD_DSCOPE */ +#include +#if defined(FW_SIGNATURE) +#include +#endif /* FW_SIGNATURE */ +#include + bool dhd_mp_halting(dhd_pub_t *dhdp); extern void bcmsdh_waitfor_iodrain(void *sdh); extern void bcmsdh_reject_ioreqs(void *sdh, bool reject); @@ -273,6 +280,9 @@ typedef struct dhd_console { #endif /* defined (BT_OVER_SDIO) */ +/* Max length of filename in IOVAR or in module parameter */ +#define DHD_MAX_PATH 2048u + /* Private data for SDIO bus interaction */ typedef struct dhd_bus { dhd_pub_t *dhd; @@ -368,10 +378,6 @@ typedef struct dhd_bus { uint rxflow_mode; /* Rx flow control mode */ bool rxflow; /* Is rx flow control on */ uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */ -#ifdef BCMINTERNAL - bool _nopmu; /* No PMU (FPGA), don't try it */ - bool clockpoll; /* Force clock polling (no chipactive interrupt) */ -#endif bool alp_only; /* Don't use HT clock (ALP only) */ /* Field to decide if rx of control frames happen in rxbuf or lb-pool */ bool usebufpool; @@ -443,9 +449,6 @@ typedef struct dhd_bus { uint tx_tailpad_chain; /* Number of tail padding by chaining pad_pkt */ uint tx_tailpad_pktget; /* Number of tail padding by new PKTGET */ #endif /* DHDENABLE_TAILPAD */ -#ifdef BCMINTERNAL - uint tx_deferred; /* Tx calls queued while event pending */ -#endif uint8 *ctrl_frame_buf; uint32 ctrl_frame_len; bool ctrl_frame_stat; @@ -478,6 +481,26 @@ typedef struct dhd_bus { char *btfw_path; /* module_param: path to BT firmware image */ uint32 bt_use_count; /* Counter that tracks whether BT is using the bus */ #endif /* defined (BT_OVER_SDIO) */ + uint64 last_suspend_end_time; + + /* Information used to compose the memory map and to write the memory map, + * FW, and FW signature to dongle RAM. + * This information is used by the bootloader. + */ + uint32 ramtop_addr; /* Dongle address of unused space at top of RAM */ + uint32 fw_download_addr; /* Dongle address of FW download */ + uint32 fw_download_len; /* Length in bytes of FW download */ + uint32 fwsig_download_addr; /* Dongle address of FW signature download */ + uint32 fwsig_download_len; /* Length in bytes of FW signature download */ + uint32 fwstat_download_addr; /* Dongle address of FWS status download */ + uint32 fwstat_download_len; /* Length in bytes of FWS status download */ + uint32 fw_memmap_download_addr; /* Dongle address of FWS memory-info download */ + uint32 fw_memmap_download_len; /* Length in bytes of FWS memory-info download */ + + char fwsig_filename[DHD_MAX_PATH]; /* Name of FW signature file */ + char bootloader_filename[DHD_FILENAME_MAX]; /* Name of bootloader image file */ + uint32 bootloader_addr; /* Dongle address of bootloader download */ + fwpkg_info_t fwpkg; /* combined fw package info structure */ uint txglomframes; /* Number of tx glom frames (superframes) */ uint txglompkts; /* Number of packets from tx glom frames */ #ifdef PKT_STATICS @@ -512,11 +535,7 @@ typedef struct dhd_bus { #define CLK_PENDING 2 /* Not used yet */ #define CLK_AVAIL 3 -#ifdef BCMINTERNAL -#define DHD_NOPMU(dhd) ((dhd)->_nopmu) -#else #define DHD_NOPMU(dhd) (FALSE) -#endif #if defined(BCMSDIOH_STD) #define BLK_64_MAXTXGLOM 20 @@ -557,10 +576,13 @@ int dhd_dongle_ramsize; uint dhd_doflow = TRUE; uint dhd_dpcpoll = FALSE; +/* SR memory size */ +uint dhd_srmem = 0; #ifdef linux module_param(dhd_doflow, uint, 0644); module_param(dhd_dpcpoll, uint, 0644); +module_param(dhd_srmem, uint, 0644); #endif static bool dhd_alignctl; @@ -570,7 +592,6 @@ static bool sd1idle; static bool retrydata; #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) -#ifndef BCMINTERNAL #ifdef BCMSPI /* At a watermark around 8 the spid hits underflow error. */ static uint watermark = 32; @@ -584,22 +605,6 @@ uint firstread = DHD_FIRSTREAD; #else static const uint firstread = DHD_FIRSTREAD; #endif -#else /* BCMINTERNAL */ -/* PR47410: low watermark to avoid F2 hang after SD clock stops */ -/* PR48178: read to (not through) bus burst to avoid F2 underflow */ -#ifdef BCMSPI -static uint watermark = 32; -static uint mesbusyctrl = 0; -#else -static uint watermark = 8; -static uint mesbusyctrl = 0; -#endif /* BCMSPI */ -static uint firstread = DHD_FIRSTREAD; -/* Additional knobs in case we need them */ -static bool tstoph = FALSE; -static bool checkfifo = FALSE; -uint dhd_anychip = 0; -#endif /* BCMINTERNAL */ /* Retry count for register access failures */ static const uint retry_limit = 2; @@ -831,6 +836,21 @@ static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt); static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh); static int _dhdsdio_download_firmware(dhd_bus_t *bus); +#if defined(FW_SIGNATURE) +static int dhdsdio_bus_download_fw_signature(dhd_bus_t *bus, bool *do_write); +static int dhdsdio_bus_write_fw_signature(dhd_bus_t *bus); +static int dhdsdio_bus_download_ram_bootloader(dhd_bus_t *bus); +static int dhdsdio_bus_write_fws_status(dhd_bus_t *bus); +static int dhdsdio_bus_write_fws_mem_info(dhd_bus_t *bus); +static int dhdsdio_bus_write_fwsig(dhd_bus_t *bus, char *fwsig_path, char *nvsig_path); +static int dhdsdio_download_rtlv_end(dhd_bus_t *bus); +static int dhdsdio_bus_save_download_info(dhd_bus_t *bus, uint32 download_addr, + uint32 download_size, const char *signature_fname, + const char *bloader_fname, uint32 bloader_download_addr); +static int dhdsdio_read_fwstatus(dhd_bus_t *bus, bl_verif_status_t *status); +static int dhd_bus_dump_fws(dhd_bus_t *bus, struct bcmstrbuf *strbuf); +#endif /* FW_SIGNATURE */ + #ifdef DHD_UCODE_DOWNLOAD static int dhdsdio_download_ucode_file(struct dhd_bus *bus, char *ucode_path); #endif /* DHD_UCODE_DOWNLOAD */ @@ -857,11 +877,6 @@ static int dhdsdio_download_btfw(struct dhd_bus *bus, osl_t *osh, void *sdh); static int _dhdsdio_download_btfw(struct dhd_bus *bus); #endif /* defined (BT_OVER_SDIO) */ -#ifdef DHD_WAKE_STATUS -int bcmsdh_get_total_wake(bcmsdh_info_t *bcmsdh); -int bcmsdh_set_get_wake(bcmsdh_info_t *bcmsdh, int flag); -#endif /* DHD_WAKE_STATUS */ - /* * PR 114233: [4335] Sdio 3.0 overflow due to spur mode PLL change */ @@ -1008,11 +1023,6 @@ dhdsdio_sr_cap(dhd_bus_t *bus) return cap; } if ( -#ifdef UNRELEASEDCHIP - (bus->sih->chip == BCM4347_CHIP_ID) || - (bus->sih->chip == BCM4357_CHIP_ID) || - (bus->sih->chip == BCM4361_CHIP_ID) || -#endif 0) { core_capext = FALSE; } else if ((bus->sih->chip == BCM4330_CHIP_ID) || @@ -1029,11 +1039,15 @@ dhdsdio_sr_cap(dhd_bus_t *bus) (BCM4349_CHIP(bus->sih->chip)) || (bus->sih->chip == BCM4350_CHIP_ID) || (bus->sih->chip == BCM4362_CHIP_ID) || + (bus->sih->chip == BCM4381_CHIP_ID) || + (bus->sih->chip == BCM4382_CHIP_ID) || (bus->sih->chip == BCM43012_CHIP_ID) || (bus->sih->chip == BCM43013_CHIP_ID) || (bus->sih->chip == BCM43014_CHIP_ID) || (bus->sih->chip == BCM43751_CHIP_ID) || - (bus->sih->chip == BCM43752_CHIP_ID)) { + (bus->sih->chip == BCM43752_CHIP_ID) || + (bus->sih->chip == BCM43756_CHIP_ID) || + (bus->sih->chip == BCM43711_CHIP_ID)) { core_capext = TRUE; } else { /* XXX: For AOB, CORE_CAPEXT_ADDR is moved to PMU core */ @@ -1093,7 +1107,7 @@ dhdsdio_sr_cap(dhd_bus_t *bus) static int dhdsdio_sr_init(dhd_bus_t *bus) { - uint8 val; + uint8 val, wkctl; int err = 0; if (bus->sih->chip == BCM43012_CHIP_ID || @@ -1103,13 +1117,18 @@ dhdsdio_sr_init(dhd_bus_t *bus) val |= 1 << SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT; bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, 1 << SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT, &err); - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); + wkctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); } else { val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err); - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); + wkctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); + } + + if (!(wkctl & val)) { + DHD_ERROR(("%s:Set wakeup ctrl failed. SBSDIO_FUNC1_WAKEUPCTRL %08x, expect %08x\n", + __FUNCTION__, wkctl, val)); } #ifdef USE_CMD14 @@ -1122,11 +1141,14 @@ dhdsdio_sr_init(dhd_bus_t *bus) CHIPID(bus->sih->chip) == BCM43018_CHIP_ID || CHIPID(bus->sih->chip) == BCM4339_CHIP_ID || CHIPID(bus->sih->chip) == BCM4362_CHIP_ID || + CHIPID(bus->sih->chip) == BCM4381_CHIP_ID || CHIPID(bus->sih->chip) == BCM43012_CHIP_ID || CHIPID(bus->sih->chip) == BCM43013_CHIP_ID || CHIPID(bus->sih->chip) == BCM43014_CHIP_ID || CHIPID(bus->sih->chip) == BCM43751_CHIP_ID || - CHIPID(bus->sih->chip) == BCM43752_CHIP_ID) + CHIPID(bus->sih->chip) == BCM43752_CHIP_ID || + CHIPID(bus->sih->chip) == BCM43756_CHIP_ID || + CHIPID(bus->sih->chip) == BCM43711_CHIP_ID) dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC); if (bus->sih->chip == BCM43012_CHIP_ID || @@ -1174,6 +1196,21 @@ dhdsdio_clk_kso_init(dhd_bus_t *bus) return 0; } +static void +dhdsdio_set_wakeupctrl(dhd_bus_t *bus) +{ + uint8 val; + int err = 0; + UNUSED_PARAMETER(val); + + /* programme the wakeup wait */ + val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); + val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, + 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err); + val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); +} + #define KSO_DBG(x) /* XXX KSO set typically takes depending on resource up & number of * resources which were down. Max value is PMU_MAX_TRANSITION_DLY usec. @@ -1200,10 +1237,10 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) int err = 0; int try_cnt = 0, try_max = CUSTOM_MAX_KSO_ATTEMPTS; struct dhd_conf *conf = bus->dhd->conf; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) && !defined(ANDROID13_KERNEL515_BKPORT) wifi_adapter_info_t *adapter = NULL; uint32 bus_type = -1, bus_num = -1, slot_num = -1; -#else +#elif (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 2, 0)) struct mmc_host *host; struct sdioh_info *sd = (struct sdioh_info *)(bus->sdh->sdioh); struct sdio_func *func = sd->func[SDIO_FUNC_0]; @@ -1211,13 +1248,13 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"))); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) && !defined(ANDROID13_KERNEL515_BKPORT) dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num); adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num); sdio_retune_crc_disable(adapter->sdio_func); if (on) sdio_retune_hold_now(adapter->sdio_func); -#else +#elif (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 2, 0)) host = func->card->host; mmc_retune_disable(host); #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) */ @@ -1232,6 +1269,8 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) * after clearing KSO bit, to avoid polling of KSO bit. */ if ((!on) && (bus->sih->chip == BCM43012_CHIP_ID || + (bus->sih->chip == BCM4381_CHIP_ID) || + (bus->sih->chip == BCM4382_CHIP_ID) || bus->sih->chip == BCM43013_CHIP_ID || bus->sih->chip == BCM43014_CHIP_ID)) { goto exit; @@ -1343,11 +1382,11 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) #endif /* !defined(NDIS) */ exit: -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) && !defined(ANDROID13_KERNEL515_BKPORT) if (on) sdio_retune_release(adapter->sdio_func); sdio_retune_crc_enable(adapter->sdio_func); -#else +#elif (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 2, 0)) mmc_retune_enable(host); #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) */ @@ -1620,17 +1659,6 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) clkctl = 0; sdh = bus->sdh; -#ifdef BCMINTERNAL - if (DHD_NOPMU(bus)) { - /* There is no PMU present, so just fake the clock state... */ - bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY); - return BCME_OK; - } - - if (bus->clockpoll) - pendok = FALSE; -#endif /* BCMINTERNAL */ - if (!KSO_ENAB(bus)) return BCME_OK; @@ -1979,6 +2007,9 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) #if defined(BCMSDIOH_STD) uint32 sd3_tuning_disable = FALSE; #endif /* BCMSDIOH_STD */ +#if defined(WL_EXT_IAPSTA) && defined(DHD_LOSSLESS_ROAMING) + int state; +#endif /* WL_EXT_IAPSTA && DHD_LOSSLESS_ROAMING */ DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n", (sleep ? "SLEEP" : "WAKE"), @@ -2001,6 +2032,14 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) if (bus->dpc_sched || bus->rxskip || pktq_n_pkts_tot(&bus->txq)) #endif /* DHD_USE_IDLECOUNT */ return BCME_BUSY; +#if defined(WL_EXT_IAPSTA) && defined(DHD_LOSSLESS_ROAMING) + state = wl_ext_any_sta_handshaking(bus->dhd); + if (state) { + if (dump_msg_level & DUMP_EAPOL_VAL) + DHD_ERROR(("handshaking %d\n", state)); + return BCME_BUSY; + } +#endif /* WL_EXT_IAPSTA && DHD_LOSSLESS_ROAMING */ #ifdef BT_OVER_SDIO /* @@ -2109,7 +2148,7 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) if (retries <= retry_limit) W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); #endif -#ifdef BT_OVER_SDIO +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(OEM_ANDROID) if (err < 0) { struct net_device *net = NULL; dhd_pub_t *dhd = bus->dhd; @@ -2123,7 +2162,7 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) DHD_ERROR(("<< WIFI HANG Fail because net is NULL\n")); } } -#endif /* BT_OVER_SDIO */ +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */ } if (err == 0) { @@ -2326,10 +2365,6 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, pktq_n_pkts_tot(&bus->txq))); -#ifdef BCMINTERNAL - if (!bus->fcstate) - bus->tx_deferred++; -#endif /* BCMINTERNAL */ bus->fcqueued++; /* Priority based enq */ @@ -2685,14 +2720,14 @@ static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txs real_pad = pkt_len - act_len; if (PKTTAILROOM(osh, pkt) < real_pad) { - DHD_INFO(("%s : insufficient tailroom %d for %d real_pad\n", + DHD_INFO(("%s : insufficient tailroom %d for %d real_pad\n", __func__, (int)PKTTAILROOM(osh, pkt), real_pad)); if (PKTPADTAILROOM(osh, pkt, real_pad)) { DHD_ERROR(("CHK1: padding error size %d\n", real_pad)); } else frame = (uint8 *)PKTDATA(osh, pkt); } - } else + } else #endif { swhdr_offset += SDPCM_HWEXT_LEN; @@ -2729,7 +2764,7 @@ static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt) /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */ frame = (uint8*)PKTDATA(osh, pkt); - DHD_INFO(("%s PKTLEN before postprocess %d", + DHD_INFO(("%s PKTLEN before postprocess %d\n", __FUNCTION__, PKTLEN(osh, pkt))); /* PKTLEN still includes tail_padding, so exclude it. @@ -3192,19 +3227,10 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) } else { bus->dhd->txcnt_timeout++; if (!bus->dhd->hang_was_sent) { -#ifdef CUSTOMER_HW4_DEBUG - /* XXX Add Debug code for find root cause from CSP:565333 */ - uint32 status, retry = 0; - R_SDREG(status, &bus->regs->intstatus, retry); - DHD_TRACE_HW4(("%s: txcnt_timeout, INT status=0x%08X\n", - __FUNCTION__, status)); - DHD_TRACE_HW4(("%s : tx_max : %d, tx_seq : %d, clkstate : %d \n", - __FUNCTION__, bus->tx_max, bus->tx_seq, bus->clkstate)); -#endif /* CUSTOMER_HW4_DEBUG */ DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", __FUNCTION__, bus->dhd->txcnt_timeout)); #ifdef BCMSDIO_RXLIM_POST - DHD_ERROR(("%s: rxlim_en=%d, rxlim enable=%d, rxlim_addr=%d\n", + DHD_ERROR(("%s: rxlim_en=%d, rxlim enable=%d, rxlim_addr=0x%x\n", __FUNCTION__, bus->dhd->conf->rxlim_en, bus->rxlim_en, bus->rxlim_addr)); #endif /* BCMSDIO_RXLIM_POST */ @@ -3425,6 +3451,7 @@ enum { IOV_SERIALCONS, #endif /* DHD_DEBUG */ IOV_SET_DOWNLOAD_STATE, + IOV_SET_DOWNLOAD_INFO, IOV_SOCRAM_STATE, IOV_FORCEEVEN, IOV_SDIOD_DRIVE, @@ -3434,23 +3461,10 @@ enum { IOV_SDALIGN, IOV_DEVRESET, IOV_CPU, -#if defined(USE_SDIOFIFO_IOVAR) || defined(BCMINTERNAL) +#if defined(USE_SDIOFIFO_IOVAR) IOV_WATERMARK, IOV_MESBUSYCTRL, #endif /* USE_SDIOFIFO_IOVAR */ -#ifdef BCMINTERNAL - IOV_SDRESET, - IOV_SDABORT, - IOV_FIRSTREAD, - IOV_TSTOPH, - IOV_RETRYDATA, - IOV_CHECKFIFO, - IOV_DOFLOW, - IOV_SDF2, - IOV_CLOCKPOLL, - IOV_MAXRAMSIZE, - IOV_SIALL, -#endif /* BCMINTERNAL */ #ifdef SDTEST IOV_PKTGEN, IOV_EXTLOOP, @@ -3494,6 +3508,8 @@ const bcm_iovar_t dhdsdio_iovars[] = { {"ramsize", IOV_RAMSIZE, 0, 0, IOVT_UINT32, 0 }, {"ramstart", IOV_RAMSTART, 0, 0, IOVT_UINT32, 0 }, {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, 0, IOVT_BOOL, 0 }, + {"dwnldinfo", IOV_SET_DOWNLOAD_INFO, 0, 0, IOVT_BUFFER, + sizeof(fw_download_info_t) }, {"socram_state", IOV_SOCRAM_STATE, 0, 0, IOVT_BOOL, 0 }, {"vars", IOV_VARS, 0, 0, IOVT_BUFFER, 0 }, {"sdiod_drive", IOV_SDIOD_DRIVE, 0, 0, IOVT_UINT32, 0 }, @@ -3515,36 +3531,18 @@ const bcm_iovar_t dhdsdio_iovars[] = { {"checkdied", IOV_CHECKDIED, 0, 0, IOVT_BUFFER, 0 }, {"serial", IOV_SERIALCONS, 0, 0, IOVT_UINT32, 0 }, #endif /* DHD_DEBUG */ -#ifdef BCMINTERNAL - {"siregall", IOV_SIALL, 0, 0, IOVT_UINT32, 0 }, -#endif /* BCMINTERNAL */ #endif /* DHD_DEBUG */ -#if defined(BCMINTERNAL) || defined(DHD_SPROM) +#if defined(DHD_SPROM) {"sprom", IOV_SPROM, 0, 0, IOVT_BUFFER, 2 * sizeof(int) }, -#endif /* BCMINTERNAL || DHD_SPROM */ +#endif #ifdef SDTEST {"extloop", IOV_EXTLOOP, 0, 0, IOVT_BOOL, 0 }, {"pktgen", IOV_PKTGEN, 0, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, #endif /* SDTEST */ -#if defined(USE_SDIOFIFO_IOVAR) || defined(BCMINTERNAL) +#if defined(USE_SDIOFIFO_IOVAR) {"watermark", IOV_WATERMARK, 0, 0, IOVT_UINT32, 0 }, {"mesbusyctrl", IOV_MESBUSYCTRL, 0, 0, IOVT_UINT32, 0 }, #endif /* USE_SDIOFIFO_IOVAR */ -#ifdef BCMINTERNAL - {"firstread", IOV_FIRSTREAD, 0, 0, IOVT_UINT32, 0 }, /* INTERNAL */ - {"tstoph", IOV_TSTOPH, 0, 0, IOVT_BOOL, 0 }, - {"retrydata", IOV_RETRYDATA, 0, 0, IOVT_BOOL, 0 }, - {"checkfifo", IOV_CHECKFIFO, 0, 0, IOVT_BOOL, 0 }, - {"sdf2", IOV_SDF2, 0, 0, IOVT_UINT32, 0 }, - {"sdreset", IOV_SDRESET, 0, 0, IOVT_VOID, 0 }, - {"sdabort", IOV_SDABORT, 0, 0, IOVT_UINT32, 0 }, - {"doflow", IOV_DOFLOW, 0, 0, IOVT_BOOL, 0 }, - {"clockpoll", IOV_CLOCKPOLL, 0, 0, IOVT_BOOL, 0 }, - {"maxsocram", IOV_MAXRAMSIZE, 0, 0, IOVT_UINT32, 0 }, -#ifdef DHD_DEBUG - {"serial", IOV_SERIALCONS, 0, 0, IOVT_UINT32, 0 }, -#endif /* DHD_DEBUG */ -#endif /* BCMINTERNAL */ {"devcap", IOV_DEVCAP, 0, 0, IOVT_UINT32, 0 }, {"dngl_isolation", IOV_DONGLEISOLATION, 0, 0, IOVT_UINT32, 0 }, {"kso", IOV_KSO, 0, 0, IOVT_UINT32, 0 }, @@ -3584,6 +3582,12 @@ dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) int i; #endif +#if defined(FW_SIGNATURE) + /* Dump secure firmware status. */ + if (dhdp->busstate <= DHD_BUS_LOAD) { + dhd_bus_dump_fws(dhdp->bus, strbuf); + } +#endif /* FW_SIGNATURE */ bcm_bprintf(strbuf, "Bus SDIO structure:\n"); bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", bus->hostintmask, bus->intstatus, bus->sdpcm_ver); @@ -3601,18 +3605,28 @@ dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) bcm_bprintf(strbuf, " unicast %u multicast %u broadcast %u arp %u\n", bus->wake_counts.rx_ucast, bus->wake_counts.rx_mcast, bus->wake_counts.rx_bcast, bus->wake_counts.rx_arp); - bcm_bprintf(strbuf, " multi4 %u multi6 %u icmp6 %u multiother %u\n", + bcm_bprintf(strbuf, " multi4 %u multi6 %u icmp %u icmp6 %u multiother %u\n", bus->wake_counts.rx_multi_ipv4, bus->wake_counts.rx_multi_ipv6, - bus->wake_counts.rx_icmpv6, bus->wake_counts.rx_multi_other); + bus->wake_counts.rx_icmp, bus->wake_counts.rx_icmpv6, + bus->wake_counts.rx_multi_other); bcm_bprintf(strbuf, " icmp6_ra %u, icmp6_na %u, icmp6_ns %u\n", bus->wake_counts.rx_icmpv6_ra, bus->wake_counts.rx_icmpv6_na, bus->wake_counts.rx_icmpv6_ns); #endif /* DHD_WAKE_RX_STATUS */ #ifdef DHD_WAKE_EVENT_STATUS +#ifdef CUSTOM_WAKE_REASON_STATS + bcm_bprintf(strbuf, "rc_event_idx = %d, which indicates queue head\n", + bus->wake_counts.rc_event_idx); + for (i = 0; i < MAX_WAKE_REASON_STATS; i++) + if (bus->wake_counts.rc_event[i] != -1) + bcm_bprintf(strbuf, " %u = %s\n", i, + bcmevent_get_name(bus->wake_counts.rc_event[i])); +#else for (i = 0; i < WLC_E_LAST; i++) if (bus->wake_counts.rc_event[i] != 0) bcm_bprintf(strbuf, " %s = %u\n", bcmevent_get_name(i), bus->wake_counts.rc_event[i]); +#endif /* CUSTOM_WAKE_REASON_STATS */ bcm_bprintf(strbuf, "\n"); #endif /* DHD_WAKE_EVENT_STATUS */ #endif /* DHD_WAKE_STATUS */ @@ -3689,22 +3703,6 @@ dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) #endif /* DHD_DEBUG */ bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n", bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping); -#ifdef BCMINTERNAL - bcm_bprintf(strbuf, "tx_deferred %d, fc 0x%x\n", bus->tx_deferred, bus->flowcontrol); -#ifdef DHD_DEBUG - { - int i; - bcm_bprintf(strbuf, "qcount: "); - for (i = 0; i < 8; i++) - bcm_bprintf(strbuf, " %d , ", qcount[i]); - bcm_bprintf(strbuf, "\n"); - bcm_bprintf(strbuf, "tx_packets: "); - for (i = 0; i < 8; i++) - bcm_bprintf(strbuf, " %d , ", tx_packets[i]); - bcm_bprintf(strbuf, "\n"); - } -#endif /* DHD_DEBUG */ -#endif /* BCMINTERNAL */ dhd_dump_pct(strbuf, "Tx: glom pct", (100 * bus->txglompkts), bus->dhd->tx_packets); dhd_dump_pct(strbuf, ", pkts/glom", bus->txglompkts, bus->txglomframes); bcm_bprintf(strbuf, "\n"); @@ -3726,9 +3724,6 @@ dhd_bus_clearcounts(dhd_pub_t *dhdp) bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0; bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0; bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0; -#ifdef BCMINTERNAL - bus->tx_deferred = bus->flowcontrol = 0; -#endif bus->txglomframes = bus->txglompkts = 0; } @@ -3954,7 +3949,7 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) addr = ltoh32(addr); - DHD_INFO(("sdpcm_shared address 0x%08X\n", addr)); + DHD_INFO(("sdpcm_shared shaddr %x addr 0x%08X\n", shaddr, addr)); /* * Check if addr is valid. @@ -4009,9 +4004,62 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) return BCME_ERROR; } +#if defined(FW_SIGNATURE) + if ((bus->fwsig_filename[0] != 0)) { + bl_verif_status_t status; + + (void)dhdsdio_read_fwstatus(bus, &status); + DHD_ERROR(("Verification status: (%08x)\n" + "\tstatus: %d\n" + "\tstate: %u\n" + "\talloc_bytes: %u\n" + "\tmax_alloc_bytes: %u\n" + "\ttotal_alloc_bytes: %u\n" + "\ttotal_freed_bytes: %u\n" + "\tnum_allocs: %u\n" + "\tmax_allocs: %u\n" + "\tmax_alloc_size: %u\n" + "\talloc_failures: %u\n", + bus->fwstat_download_addr, + status.status, + status.state, + status.alloc_bytes, + status.max_alloc_bytes, + status.total_alloc_bytes, + status.total_freed_bytes, + status.num_allocs, + status.max_allocs, + status.max_alloc_size, + status.alloc_failures)); + } +#endif /* FW_SIGNATURE */ return BCME_OK; } +void +dhd_bus_check_srmemsize(dhd_pub_t *dhdp) +{ + dhd_bus_t *dhd = dhdp->bus; + uint32 srmem_size = 0; + int err = BCME_OK; + + err = dhd_iovar(dhdp, 0, "bus:srmem_size", NULL, 0, + (char *)&srmem_size, sizeof(srmem_size), FALSE); + if (err) { + DHD_ERROR(("%s : srmem_size no need to change.\n", __FUNCTION__)); + return; + } + + if (srmem_size != dhd->srmemsize) { + sdpcm_shared_t shared; + dhd->srmemsize = srmem_size; + if (dhdsdio_readshared(dhd, &shared) == 0) + dhd->console_addr = shared.console_addr; + } + + return; +} + #define CONSOLE_LINE_MAX 192 #ifdef DHD_DEBUG @@ -4320,19 +4368,30 @@ dhdsdio_get_mem_dump(dhd_bus_t *bus) uint32 start = bus->dongle_ram_base; /* Start address */ uint read_size = 0; /* Read size of each iteration */ uint8 *p_buf = NULL, *databuf = NULL; +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) + dhd_dongledump_status_t dump_status; +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ /* Get full mem size */ p_buf = dhd_get_fwdump_buf(bus->dhd, size); if (!p_buf) { DHD_ERROR(("%s: Out of memory (%d bytes)\n", __FUNCTION__, size)); - return BCME_ERROR; + ret = BCME_ERROR; + goto exit; } dhd_os_sdlock(bus->dhd); BUS_WAKE(bus); dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) + dump_status = dhd_get_dump_status(bus->dhd); + if (dump_status != DUMP_IN_PROGRESS) { + dhd_set_dump_status(bus->dhd, DUMP_IN_PROGRESS); + } +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ + /* Read mem content */ DHD_ERROR(("Dump dongle memory\n")); databuf = p_buf; @@ -4356,6 +4415,13 @@ dhdsdio_get_mem_dump(dhd_bus_t *bus) dhdsdio_clkctl(bus, CLK_NONE, TRUE); } +exit: +#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP) + if (ret != BCME_OK) { + dhd_set_dump_status(bus->dhd, DUMP_FAILURE); + } +#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */ + dhd_os_sdunlock(bus->dhd); return ret; @@ -4469,7 +4535,7 @@ dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) return (int_val & uart_enab); } -#endif /* BCMINTERNAL */ +#endif /* DHD_DEBUG */ static int dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, @@ -4507,21 +4573,6 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch dhdsdio_clk_kso_iovar(bus, bool_val); goto exit; } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) { -#ifdef BCMINTERNAL - /* XXX: Temp for debugging devsleep */ - if (int_val == 2) { - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - } else if (int_val == 3) { - bus->_slpauto = FALSE; - } else if (int_val == 4) { - bus->_slpauto = TRUE; - } else if (int_val == 5) { - bus->kso = TRUE; - } else if (int_val == 6) { - bus->kso = FALSE; - } else -#endif { dhdsdio_clk_devsleep_iovar(bus, bool_val); if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) { @@ -4671,6 +4722,17 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch } #endif /* DHD_BUS_MEM_ACCESS */ +#if defined(FW_SIGNATURE) + case IOV_SVAL(IOV_SET_DOWNLOAD_INFO): + { + fw_download_info_t *info = (fw_download_info_t*)params; + bcmerror = dhdsdio_bus_save_download_info(bus, + info->fw_start_addr, info->fw_size, info->fw_signature_fname, + info->bootloader_fname, info->bootloader_start_addr); + break; + } +#endif /* FW_SIGNATURE */ + case IOV_GVAL(IOV_RAMSIZE): int_val = (int32)bus->ramsize; bcopy(&int_val, arg, val_size); @@ -4882,13 +4944,6 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch break; #endif /* DHD_DEBUG */ -#if defined(BCMINTERNAL) && defined(BCMDBG) - case IOV_SVAL(IOV_SIALL): - DHD_ERROR(("Dumping all the Backplane registers\n")); - si_viewall(bus->sih, TRUE); - break; -#endif /* defined(BCMINTERNAL) && defined(BCMDBG) */ - #endif /* DHD_DEBUG */ #if defined(DHD_SPROM) @@ -4977,7 +5032,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch break; #endif /* SDTEST */ -#if defined(USE_SDIOFIFO_IOVAR) || defined(BCMINTERNAL) +#if defined(USE_SDIOFIFO_IOVAR) case IOV_GVAL(IOV_WATERMARK): int_val = (int32)watermark; bcopy(&int_val, arg, val_size); @@ -5003,168 +5058,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, ((uint8)mesbusyctrl | 0x80), NULL); break; -#endif /* define(USE_SDIOFIFO_IOVAR) || defined(BCMINTERNAL) */ - -#ifdef BCMINTERNAL - case IOV_GVAL(IOV_FIRSTREAD): - int_val = (int32)firstread; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_FIRSTREAD): - if ((int_val < 12) || (int_val > 32)) { - bcmerror = BCME_BADARG; - break; - } - firstread = (uint)int_val; - break; - - case IOV_GVAL(IOV_TSTOPH): - int_val = tstoph; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_TSTOPH): - if (tstoph && bus->dhd->busstate == DHD_BUS_DOWN) { - tstoph = bool_val; - bus->dhd->busstate = DHD_BUS_DATA; - if (bus->intr) { - bus->intdis = FALSE; - bcmsdh_intr_enable(bus->sdh); - } - } else { - tstoph = bool_val; - } - break; - - case IOV_GVAL(IOV_RETRYDATA): - int_val = (int32)retrydata; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_RETRYDATA): - retrydata = bool_val; - break; - - case IOV_GVAL(IOV_CHECKFIFO): - int_val = (int32)checkfifo; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_CHECKFIFO): - checkfifo = bool_val; - break; - - case IOV_GVAL(IOV_SDF2): - case IOV_SVAL(IOV_SDF2): - { - uint8 *buf; - int ret = BCME_OK; - - if (!(buf = MALLOC(bus->dhd->osh, int_val))) { - bcmerror = BCME_NOMEM; - break; - } - - if (actionid == IOV_SVAL(IOV_SDF2)) { - ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, - F2SYNC, buf, int_val, NULL, NULL, NULL, 1); - } else { - ret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, - F2SYNC, buf, int_val, NULL, NULL, NULL); - } - if (ret != BCME_OK) { - bcmerror = BCME_SDIO_ERROR; - } - - MFREE(bus->dhd->osh, buf, int_val); - - break; - } - - case IOV_SVAL(IOV_CPU): - /* Go to the ARM core */ - if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && - !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - break; - } - - /* Take the request action */ - if (bool_val) - si_core_reset(bus->sih, 0, 0); - else - si_core_disable(bus->sih, 0); - - if (bcmsdh_regfail(bus->sdh)) - bcmerror = BCME_SDIO_ERROR; - - /* Return to the SDIO core */ - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) - si_setcore(bus->sih, SDIOD_CORE_ID, 0); - break; - - case IOV_GVAL(IOV_CPU): - /* Go to the ARM core */ - if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && - !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - break; - } - - /* Get its status */ - int_val = (int32)si_iscoreup(bus->sih); - bcopy(&int_val, arg, val_size); - - /* Return to the SDIO core */ - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) - si_setcore(bus->sih, SDIOD_CORE_ID, 0); - break; - - case IOV_SVAL(IOV_SDRESET): - bcmsdh_reset(bus->sdh); - break; - - case IOV_SVAL(IOV_SDABORT): - if (int_val == 1 || int_val == 2) - bcmsdh_abort(bus->sdh, int_val); - else - bcmerror = BCME_BADARG; - break; - - case IOV_GVAL(IOV_DOFLOW): - int_val = (int32)dhd_doflow; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DOFLOW): - dhd_doflow = bool_val; - /* De flowcontrol if turning off flowcontrol */ - if (!dhd_doflow) - dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); - break; - - case IOV_GVAL(IOV_CLOCKPOLL): - int_val = (int32)bus->clockpoll; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_MAXRAMSIZE): - int_val = (int32)bus->ramsize; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MAXRAMSIZE): - dhd_dongle_ramsize = int_val; - dhd_dongle_setramsize(bus, dhd_dongle_ramsize); - break; - - case IOV_SVAL(IOV_CLOCKPOLL): - bus->clockpoll = bool_val; - break; -#endif /* BCMINTERNAL */ +#endif /* USE_SDIOFIFO_IOVAR */ case IOV_GVAL(IOV_DONGLEISOLATION): int_val = bus->dhd->dongle_isolation; @@ -5314,6 +5208,7 @@ dhdsdio_write_vars(dhd_bus_t *bus) } varaddr += bus->dongle_ram_base; + bus->ramtop_addr = varaddr; if (bus->vars) { /* XXX: WAR for PR85623 */ @@ -5423,6 +5318,7 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) uint retries; int bcmerror = 0; int foundcr4 = 0; + bool do_wr_flops = TRUE; if (!bus->sih) return BCME_ERROR; @@ -5541,50 +5437,61 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); goto fail; } +#if defined(FW_SIGNATURE) + if ((bcmerror = dhdsdio_bus_download_fw_signature(bus, &do_wr_flops)) + != BCME_OK) { + goto fail; + } +#endif /* FW_SIGNATURE */ + if (do_wr_flops) { #ifdef BCMSDIOLITE - if (!si_setcore(bus->sih, CC_CORE_ID, 0)) { - DHD_ERROR(("%s: Can't set to Chip Common core?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } -#else - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && - !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { - DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } -#endif - W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); - - /* switch back to arm core again */ - if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - /* write address 0 with reset instruction */ - bcmerror = dhdsdio_membytes(bus, TRUE, 0, - (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); - - if (bcmerror == BCME_OK) { - uint32 tmp; - - /* verify write */ - bcmerror = dhdsdio_membytes(bus, FALSE, 0, - (uint8 *)&tmp, sizeof(tmp)); - - if (bcmerror == BCME_OK && tmp != bus->resetinstr) { - DHD_ERROR(("%s: Failed to write 0x%08x to addr 0\n", - __FUNCTION__, bus->resetinstr)); - DHD_ERROR(("%s: contents of addr 0 is 0x%08x\n", - __FUNCTION__, tmp)); - bcmerror = BCME_SDIO_ERROR; + if (!si_setcore(bus->sih, CC_CORE_ID, 0)) { + DHD_ERROR(("%s: Can't set to Chip Common core?\n", + __FUNCTION__)); + bcmerror = BCME_ERROR; goto fail; } - } +#else + if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && + !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { + DHD_ERROR(("%s: Can't change back to SDIO core?\n", + __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } +#endif + W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); - /* now remove reset and halt and continue to run CR4 */ + /* switch back to arm core again */ + if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", + __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + /* write address 0 with reset instruction */ + bcmerror = dhdsdio_membytes(bus, TRUE, 0, + (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); + + if (bcmerror == BCME_OK) { + uint32 tmp; + + /* verify write */ + bcmerror = dhdsdio_membytes(bus, FALSE, 0, + (uint8 *)&tmp, sizeof(tmp)); + + if (bcmerror == BCME_OK && tmp != bus->resetinstr) { + DHD_ERROR(("%s: Failed to write 0x%08x to addr 0\n", + __FUNCTION__, bus->resetinstr)); + DHD_ERROR(("%s: contents of addr 0 is 0x%08x\n", + __FUNCTION__, tmp)); + bcmerror = BCME_SDIO_ERROR; + goto fail; + } + } + + /* now remove reset and halt and continue to run CR4 */ + } } si_core_reset(bus->sih, 0, 0); @@ -5608,6 +5515,551 @@ fail: return bcmerror; } +#if defined(FW_SIGNATURE) +static int +dhdsdio_bus_download_fw_signature(dhd_bus_t *bus, bool *do_write) +{ + int bcmerror = BCME_OK; + + DHD_ERROR(("FWSIG: bl=%s,%x fw=%x,%u sig=%s,%x,%u" + " stat=%x,%u ram=%x,%x\n", + bus->bootloader_filename, bus->bootloader_addr, + bus->fw_download_addr, bus->fw_download_len, + bus->fwsig_filename, bus->fwsig_download_addr, + bus->fwsig_download_len, + bus->fwstat_download_addr, bus->fwstat_download_len, + bus->dongle_ram_base, bus->ramtop_addr)); + + if (bus->fwsig_filename[0] == 0) { + DHD_INFO(("%s: missing signature file\n", __FUNCTION__)); + goto exit; + } + + /* Write RAM Bootloader to TCM if requested */ + if ((bcmerror = dhdsdio_bus_download_ram_bootloader(bus)) + != BCME_OK) { + DHD_ERROR(("%s: could not write RAM BL to TCM, err %d\n", + __FUNCTION__, bcmerror)); + goto exit; + } + + /* Write FW signature to memory */ + if ((bcmerror = dhdsdio_bus_write_fw_signature(bus))) { + DHD_ERROR(("%s: could not write FWsig , err %d\n", + __FUNCTION__, bcmerror)); + goto exit; + } + + /* In case of BL RAM, do write flops */ + if (bus->bootloader_filename[0] != 0) { + *do_write = TRUE; + } else { + *do_write = FALSE; + } + +exit: + return bcmerror; +} + +/* Complete RAM structure, write the followings + * signature image + * signature verification status + * FW memory map + * end-of-TLVs marker + */ +static int +dhdsdio_bus_write_fw_signature(dhd_bus_t *bus) +{ + int bcmerror = BCME_OK; + + /* Write FW signature rTLV to TCM */ + if ((bcmerror = dhdsdio_bus_write_fwsig(bus, bus->fwsig_filename, + NULL))) { + DHD_ERROR(("%s: could not write FWsig to TCM, err %d\n", + __FUNCTION__, bcmerror)); + goto exit; + } + + /* Write FW signature verification status rTLV to TCM */ + if ((bcmerror = dhdsdio_bus_write_fws_status(bus)) != BCME_OK) { + DHD_ERROR(("%s: could not write FWinfo to TCM, err %d\n", + __FUNCTION__, bcmerror)); + goto exit; + } + + /* Write FW memory map rTLV to TCM */ + if ((bcmerror = dhdsdio_bus_write_fws_mem_info(bus)) != BCME_OK) { + DHD_ERROR(("%s: could not write FWinfo to TCM, err %d\n", + __FUNCTION__, bcmerror)); + goto exit; + } + + /* Write a end-of-TLVs marker to TCM */ + if ((bcmerror = dhdsdio_download_rtlv_end(bus)) != BCME_OK) { + DHD_ERROR(("%s: could not write rTLV-end marker to TCM, err %d\n", + __FUNCTION__, bcmerror)); + goto exit; + } + +exit: + return bcmerror; +} + +/* Download a reversed-TLV to the top of dongle RAM without overlapping any existing rTLVs */ +static int +dhdsdio_download_rtlv(dhd_bus_t *bus, dngl_rtlv_type_t type, dngl_rtlv_len_t len, uint8 *value) +{ + int bcmerror = BCME_OK; +#ifdef DHD_DEBUG + uint8 *readback_buf = NULL; + uint32 readback_val = 0; +#endif /* DHD_DEBUG */ + uint32 dest_addr = 0; /* dongle RAM dest address */ + uint32 dest_size = 0; /* dongle RAM dest size */ + uint32 dest_raw_size = 0; /* dest size with added checksum */ + + /* Calculate the destination dongle RAM address and size */ + dest_size = ROUNDUP(len, 4); + dest_addr = bus->ramtop_addr - sizeof(dngl_rtlv_type_t) - sizeof(dngl_rtlv_len_t) + - dest_size; + bus->ramtop_addr = dest_addr; + + /* Create the rTLV size field. This consists of 2 16-bit fields: + * The lower 16 bits is the size. The higher 16 bits is a checksum + * consisting of the size with all bits reversed. + * +-------------+-------------+ + * | checksum | size | + * +-------------+-------------+ + * High 16 bits Low 16 bits + */ + if (type == DNGL_RTLV_TYPE_RNG_SIGNATURE) { + /* Random number seed TLV (DNGL_RTLV_TYPE_RNG_SIGNATURE) was the very + * first TLV, its length does not have checksum, firmware crashes if + * checksum is present + */ + dest_raw_size = dest_size & 0x0000FFFF; + } else { + dest_raw_size = (~dest_size << 16) | (dest_size & 0x0000FFFF); + } + /* Write the value block */ + if (dest_size > 0) { + bcmerror = dhdsdio_membytes(bus, TRUE, dest_addr, value, dest_size); + if (bcmerror) { + DHD_ERROR(("%s: error %d on writing %d membytes to 0x%08x\n", + __FUNCTION__, bcmerror, dest_size, dest_addr)); + goto exit; + } + } + + /* Write the length word */ + bcmerror = dhdsdio_membytes(bus, TRUE, dest_addr + dest_size, + (uint8*)&dest_raw_size, sizeof(dngl_rtlv_len_t)); + + /* Write the type word */ + bcmerror = dhdsdio_membytes(bus, TRUE, + dest_addr + dest_size + sizeof(dngl_rtlv_len_t), + (uint8*)&type, sizeof(dngl_rtlv_type_t)); + +#ifdef DHD_DEBUG + /* Read back and compare the downloaded data */ + if (dest_size > 0) { + readback_buf = (uint8*)MALLOC(bus->dhd->osh, dest_size); + if (!readback_buf) { + bcmerror = BCME_NOMEM; + goto exit; + } + memset(readback_buf, 0xaa, dest_size); + bcmerror = dhdsdio_membytes(bus, FALSE, dest_addr, readback_buf, dest_size); + if (bcmerror) { + DHD_ERROR(("%s: readback error %d, %d bytes from 0x%08x\n", + __FUNCTION__, bcmerror, dest_size, dest_addr)); + goto exit; + } + if (memcmp(value, readback_buf, dest_size) != 0) { + DHD_ERROR(("%s: Downloaded data mismatch.\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto exit; + } else { + DHD_ERROR(("Download and compare of TLV 0x%x succeeded" + " (size %u, addr %x).\n", type, dest_size, dest_addr)); + } + } + + /* Read back and compare the downloaded len field */ + bcmerror = dhdsdio_membytes(bus, FALSE, dest_addr + dest_size, + (uint8*)&readback_val, sizeof(dngl_rtlv_len_t)); + if (!bcmerror) { + if (readback_val != dest_raw_size) { + bcmerror = BCME_BADLEN; + } + } + if (bcmerror) { + DHD_ERROR(("%s: Downloaded len error %d\n", __FUNCTION__, bcmerror)); + goto exit; + } + + /* Read back and compare the downloaded type field */ + bcmerror = dhdsdio_membytes(bus, FALSE, + dest_addr + dest_size + sizeof(dngl_rtlv_len_t), + (uint8*)&readback_val, sizeof(dngl_rtlv_type_t)); + if (!bcmerror) { + if (readback_val != type) { + bcmerror = BCME_BADOPTION; + } + } + if (bcmerror) { + DHD_ERROR(("%s: Downloaded type error %d\n", __FUNCTION__, bcmerror)); + goto exit; + } +#endif /* DHD_DEBUG */ + + bus->ramtop_addr = dest_addr; + +exit: +#ifdef DHD_DEBUG + if (readback_buf) { + MFREE(bus->dhd->osh, readback_buf, dest_size); + } +#endif /* DHD_DEBUG */ + + return bcmerror; +} /* dhdsdio_download_rtlv */ + +/* Download a reversed-TLV END marker to the top of dongle RAM */ +static int +dhdsdio_download_rtlv_end(dhd_bus_t *bus) +{ + return dhdsdio_download_rtlv(bus, DNGL_RTLV_TYPE_END_MARKER, 0, NULL); +} + +/* Write the FW signature verification status to dongle memory */ +static int +dhdsdio_bus_write_fws_status(dhd_bus_t *bus) +{ + bl_verif_status_t vstatus; + int ret; + + bzero(&vstatus, sizeof(vstatus)); + + ret = dhdsdio_download_rtlv(bus, DNGL_RTLV_TYPE_FWSIGN_STATUS, sizeof(vstatus), + (uint8*)&vstatus); + bus->fwstat_download_addr = bus->ramtop_addr; + bus->fwstat_download_len = sizeof(vstatus); + + return ret; +} /* dhdsdio_bus_write_fws_status */ + +/* Write the FW signature verification memory map to dongle memory */ +static int +dhdsdio_bus_write_fws_mem_info(dhd_bus_t *bus) +{ + bl_mem_info_t memmap; + int ret; + + bzero(&memmap, sizeof(memmap)); + memmap.firmware.start = bus->fw_download_addr; + memmap.firmware.end = memmap.firmware.start + bus->fw_download_len; + memmap.heap.start = ROUNDUP(memmap.firmware.end + BL_HEAP_START_GAP_SIZE, 4); + memmap.heap.end = memmap.heap.start + BL_HEAP_SIZE; + memmap.signature.start = bus->fwsig_download_addr; + memmap.signature.end = memmap.signature.start + bus->fwsig_download_len; + memmap.vstatus.start = bus->fwstat_download_addr; + memmap.vstatus.end = memmap.vstatus.start + bus->fwstat_download_len; + DHD_ERROR(("%s: mem_info: fw=%x-%x heap=%x-%x sig=%x-%x vst=%x-%x res=%x\n", + __FUNCTION__, + memmap.firmware.start, memmap.firmware.end, + memmap.heap.start, memmap.heap.end, + memmap.signature.start, memmap.signature.end, + memmap.vstatus.start, memmap.vstatus.end, + memmap.reset_vec.start)); + + ret = dhdsdio_download_rtlv(bus, DNGL_RTLV_TYPE_FWSIGN_MEM_MAP, sizeof(memmap), + (uint8*)&memmap); + bus->fw_memmap_download_addr = bus->ramtop_addr; + bus->fw_memmap_download_len = sizeof(memmap); + + return ret; +} /* dhdsdio_bus_write_fws_mem_info */ + +/* Download a bootloader image to dongle RAM */ +static int +dhdsdio_bus_download_ram_bootloader(dhd_bus_t *bus) +{ + int ret = BCME_OK; + uint32 dongle_ram_base_save; + + DHD_INFO(("download_bloader: %s,0x%x. ramtop=0x%x\n", + bus->bootloader_filename, bus->bootloader_addr, bus->ramtop_addr)); + if (bus->bootloader_filename[0] == '\0') { + return ret; + } + + /* Save ram base */ + dongle_ram_base_save = bus->dongle_ram_base; + + /* Set ram base to bootloader download start address */ + bus->dongle_ram_base = bus->bootloader_addr; + + /* Download the bootloader image to TCM */ + ret = dhdsdio_download_code_file(bus, bus->bootloader_filename); + + /* Restore ram base */ + bus->dongle_ram_base = dongle_ram_base_save; + + return ret; +} /* dhdsdio_bus_download_ram_bootloader */ + +/* Save the FW download address and size */ +static int +dhdsdio_bus_save_download_info(dhd_bus_t *bus, uint32 download_addr, + uint32 download_size, const char *signature_fname, + const char *bloader_fname, uint32 bloader_download_addr) +{ + /* DHD EXE may not have size of the downloaded FW image in case of swpaging binary */ + if (download_size) { + bus->fw_download_len = download_size; + } + bus->fw_download_addr = download_addr; + strlcpy(bus->fwsig_filename, signature_fname, sizeof(bus->fwsig_filename)); + strlcpy(bus->bootloader_filename, bloader_fname, sizeof(bus->bootloader_filename)); + bus->bootloader_addr = bloader_download_addr; +#ifdef GDB_PROXY + /* GDB proxy bootloader mode - if signature file specified (i.e. + * bootloader is used), but bootloader is not specified (i.e. ROM + * bootloader is uses). + * Bootloader mode is significant only for for preattachment debugging + * of chips, in which debug cell can't be initialized before ARM CPU + * start + */ + bus->gdb_proxy_bootloader_mode = bus->fwsig_filename[0] != 0; +#endif /* GDB_PROXY */ + return BCME_OK; +} /* dhdsdio_bus_save_download_info */ + +/* Read a binary file and write it to the specified socram dest address */ +#ifdef DHD_LINUX_STD_FW_API +static int +dhdsdio_download_sig_file(dhd_bus_t *bus, char *path, uint32 type) +{ + int bcmerror = BCME_OK; + int srcsize = 0; + uint32 dest_size = 0; /* dongle RAM dest size */ + const struct firmware *sig = NULL; + + if (path == NULL || path[0] == '\0') { + DHD_ERROR(("%s: no file\n", __FUNCTION__)); + bcmerror = BCME_NOTFOUND; + goto exit; + } + + bcmerror = dhd_os_get_img_fwreq(&sig, bus->fwsig_filename); + if (bcmerror < 0) { + DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n", + bcmerror)); + goto exit; + } + DHD_ERROR(("%s: dhd_os_get_img(Request Firmware API) success. size %d.\n", + __FUNCTION__, (int)sig->size)); + + srcsize = sig->size; + if (srcsize <= 0 || srcsize > MEMBLOCK) { + DHD_ERROR(("%s: invalid fwsig size %u\n", __FUNCTION__, srcsize)); + bcmerror = BCME_BUFTOOSHORT; + goto exit; + } + + dest_size = ROUNDUP(srcsize, 4); + /* Write the src buffer as a rTLV to the dongle */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + bcmerror = dhdsdio_download_rtlv(bus, type, dest_size, (uint8 *)sig->data); + GCC_DIAGNOSTIC_POP(); + if (bcmerror) { + DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, srcsize, bus->ramtop_addr)); + goto exit; + } + + bus->fwsig_download_addr = bus->ramtop_addr; + bus->fwsig_download_len = dest_size; + +exit: + if (sig) + dhd_os_close_img_fwreq(sig); + + return bcmerror; +} +#else +static int +dhdsdio_download_sig_file(dhd_bus_t *bus, char *path, uint32 type) +{ + int bcmerror = BCME_OK; + void *filep = NULL; + uint8 *srcbuf = NULL; + int srcsize = 0; + int len; + uint32 dest_size = 0; /* dongle RAM dest size */ + fwpkg_info_t *fwpkg = NULL; + + if (path == NULL || path[0] == '\0') { + DHD_ERROR(("%s: no file\n", __FUNCTION__)); + bcmerror = BCME_NOTFOUND; + goto exit; + } + + bcmerror = fwpkg_init(&bus->fwpkg, path); + if (bcmerror == BCME_ERROR) { + printf("%s: fwpkg_init failed %s\n", __FUNCTION__, path); + goto exit; + } + fwpkg = &bus->fwpkg; + + /* Open file, get size */ + bcmerror = fwpkg_open_signature_img(fwpkg, path, &filep); + if (bcmerror == BCME_ERROR) { + DHD_ERROR(("%s: error opening file %s\n", __FUNCTION__, path)); + goto exit; + } + + srcsize = fwpkg_get_signature_img_size(fwpkg); + + if (srcsize <= 0 || srcsize > MEMBLOCK) { + DHD_ERROR(("%s: invalid fwsig size %u\n", __FUNCTION__, srcsize)); + bcmerror = BCME_BUFTOOSHORT; + goto exit; + } + dest_size = ROUNDUP(srcsize, 4); + + /* Allocate src buffer, read in the entire file */ + srcbuf = (uint8 *)MALLOCZ(bus->dhd->osh, dest_size); + if (!srcbuf) { + bcmerror = BCME_NOMEM; + goto exit; + } + len = dhd_os_get_image_block(srcbuf, srcsize, filep); + if (len != srcsize) { + DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); + bcmerror = BCME_BADLEN; + goto exit; + } + + /* Write the src buffer as a rTLV to the dongle */ + bcmerror = dhdsdio_download_rtlv(bus, type, dest_size, srcbuf); + + bus->fwsig_download_addr = bus->ramtop_addr; + bus->fwsig_download_len = dest_size; + +exit: + if (filep) { + dhd_os_close_image1(bus->dhd, filep); + } + if (srcbuf) { + MFREE(bus->dhd->osh, srcbuf, dest_size); + } + + return bcmerror; +} /* dhdsdio_download_sig_file */ +#endif /* DHD_LINUX_STD_FW_API */ + +static int +dhdsdio_bus_write_fwsig(dhd_bus_t *bus, char *fwsig_path, char *nvsig_path) +{ + int bcmerror = BCME_OK; + + /* Download the FW signature file to the chip */ + bcmerror = dhdsdio_download_sig_file(bus, fwsig_path, DNGL_RTLV_TYPE_FW_SIGNATURE); + if (bcmerror) { + goto exit; + } + +exit: + if (bcmerror) { + DHD_ERROR(("%s: error %d\n", __FUNCTION__, bcmerror)); + } + return bcmerror; +} /* dhdsdio_bus_write_fwsig */ + +static int +dhdsdio_read_fwstatus(dhd_bus_t *bus, bl_verif_status_t *status) +{ + int ret = BCME_OK; + + bzero(status, sizeof(*status)); + if (bus->fwstat_download_addr != 0) { + ret = dhdsdio_membytes(bus, FALSE, bus->fwstat_download_addr, + (uint8 *)status, sizeof(*status)); + if (ret != BCME_OK) { + DHD_ERROR(("%s: error %d on reading %zu membytes at 0x%08x\n", + __FUNCTION__, ret, sizeof(*status), bus->fwstat_download_addr)); + } + } + + return ret; +} + +/* Dump secure firmware status. */ +static int +dhd_bus_dump_fws(dhd_bus_t *bus, struct bcmstrbuf *strbuf) +{ + bl_verif_status_t status; + bl_mem_info_t meminfo; + int err = BCME_OK; + + err = dhdsdio_read_fwstatus(bus, &status); + if (err != BCME_OK) { + return (err); + } + + bzero(&meminfo, sizeof(meminfo)); + if (bus->fw_memmap_download_addr != 0) { + err = dhdsdio_membytes(bus, FALSE, bus->fw_memmap_download_addr, + (uint8 *)&meminfo, sizeof(meminfo)); + if (err != BCME_OK) { + DHD_ERROR(("%s: error %d on reading %zu membytes at 0x%08x\n", + __FUNCTION__, err, sizeof(meminfo), bus->fw_memmap_download_addr)); + return (err); + } + } + + bcm_bprintf(strbuf, "Firmware signing\nSignature: (%08x) len (%d)\n", + bus->fwsig_download_addr, bus->fwsig_download_len); + + bcm_bprintf(strbuf, + "Verification status: (%08x)\n" + "\tstatus: %d\n" + "\tstate: %u\n" + "\talloc_bytes: %u\n" + "\tmax_alloc_bytes: %u\n" + "\ttotal_alloc_bytes: %u\n" + "\ttotal_freed_bytes: %u\n" + "\tnum_allocs: %u\n" + "\tmax_allocs: %u\n" + "\tmax_alloc_size: %u\n" + "\talloc_failures: %u\n", + bus->fwstat_download_addr, + status.status, + status.state, + status.alloc_bytes, + status.max_alloc_bytes, + status.total_alloc_bytes, + status.total_freed_bytes, + status.num_allocs, + status.max_allocs, + status.max_alloc_size, + status.alloc_failures); + + bcm_bprintf(strbuf, + "Memory info: (%08x)\n" + "\tfw %08x-%08x\n\theap %08x-%08x\n\tsig %08x-%08x\n\tvst %08x-%08x\n", + bus->fw_memmap_download_addr, + meminfo.firmware.start, meminfo.firmware.end, + meminfo.heap.start, meminfo.heap.end, + meminfo.signature.start, meminfo.signature.end, + meminfo.vstatus.start, meminfo.vstatus.end); + + return (err); +} +#endif /* FW_SIGNATURE */ + int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, void *params, uint plen, void *arg, uint len, bool set) @@ -6138,7 +6590,35 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) exit: if (enforce_mutex) dhd_os_sdunlock(bus->dhd); +#if defined(FW_SIGNATURE) + if ((ret == BCME_ERROR) && (bus->fwsig_filename[0] != 0)) { + bl_verif_status_t status; + (void)dhdsdio_read_fwstatus(bus, &status); + DHD_ERROR(("Verification status: (%08x)\n" + "\tstatus: %d\n" + "\tstate: %u\n" + "\talloc_bytes: %u\n" + "\tmax_alloc_bytes: %u\n" + "\ttotal_alloc_bytes: %u\n" + "\ttotal_freed_bytes: %u\n" + "\tnum_allocs: %u\n" + "\tmax_allocs: %u\n" + "\tmax_alloc_size: %u\n" + "\talloc_failures: %u\n", + bus->fwstat_download_addr, + status.status, + status.state, + status.alloc_bytes, + status.max_alloc_bytes, + status.total_alloc_bytes, + status.total_freed_bytes, + status.num_allocs, + status.max_allocs, + status.max_alloc_size, + status.alloc_failures)); + } +#endif /* FW_SIGNATURE */ /* XXX Temp errnum workaround: return ok, caller checks bus state */ return ret; } @@ -6556,7 +7036,7 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) /* Check window for sanity */ if ((uint8)(txmax - bus->tx_seq) > 0x70) { - DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", + DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n", __FUNCTION__, txmax, bus->tx_seq)); txmax = bus->tx_max; } @@ -6795,6 +7275,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) { maxframes = bus->pktgen_count; sdtest = TRUE; + UNUSED_PARAMETER(sdtest); } #endif @@ -6891,7 +7372,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) rdlen = len = nextlen << 4; /* Pad read to blocksize for efficiency */ - if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { + if (bus->roundup && bus->blocksize) { pad = bus->blocksize - (rdlen % bus->blocksize); if ((pad <= bus->roundup) && (pad < bus->blocksize) && ((rdlen + pad + firstread) < MAX_RX_DATASZ)) @@ -7162,7 +7643,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) txmax = bus->tx_seq + 2; } else { #endif /* BCMSPI */ - DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", + DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n", __FUNCTION__, txmax, bus->tx_seq)); txmax = bus->tx_max; #ifdef BCMSPI @@ -7236,13 +7717,6 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) if (sdret < 0) { DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret)); bus->rx_hdrfail++; -#ifdef BCMINTERNAL - if (tstoph) { - DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__)); - bus->dhd->busstate = DHD_BUS_DOWN; - continue; - } -#endif dhdsdio_rxfail(bus, TRUE, TRUE); continue; } @@ -7330,7 +7804,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) /* Check window for sanity */ if ((uint8)(txmax - bus->tx_seq) > 0x70) { - DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", + DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n", __FUNCTION__, txmax, bus->tx_seq)); txmax = bus->tx_max; } @@ -7349,7 +7823,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) rdlen = (len > firstread) ? (len - firstread) : 0; /* May pad read to blocksize for efficiency */ - if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { + if (bus->roundup && bus->blocksize) { pad = bus->blocksize - (rdlen % bus->blocksize); if ((pad <= bus->roundup) && (pad < bus->blocksize) && ((rdlen + pad + firstread) < MAX_RX_DATASZ)) @@ -7570,14 +8044,15 @@ dhdsdio_hostmail(dhd_bus_t *bus, uint32 *hmbd) } #endif /* BCMSPI */ -#ifdef DHD_DEBUG +// open FW cons and log by default +#if defined(DHD_DEBUG) || defined(DHD_FW_LOG_SUPPORT) || defined(DHD_FW_CONS_SUPPORT) /* Retrieve console state address now that firmware should have updated it */ { sdpcm_shared_t shared; if (dhdsdio_readshared(bus, &shared) == 0) bus->console_addr = shared.console_addr; } -#endif /* DHD_DEBUG */ +#endif /* DHD_DEBUG || DHD_FW_LOG_SUPPORT || DHD_FW_CONS_SUPPORT ) */ } /* @@ -7875,65 +8350,6 @@ exit_ucode: /* On frame indication, read available frames */ if (PKT_AVAILABLE(bus, intstatus)) { -#ifdef BCMINTERNAL - if (checkfifo) { - int count, regerrs = 0; - uint32 fifoaddr, rdptr, rdoffs, endptrs; - uint32 datalow[8], datahigh[8]; - uint coretype = bus->sih->buscoretype; - uint corerev = bus->sdpcmrev; - - /* set fifoaddr to fetch xmt fifo pointers */ - fifoaddr = (0xB << 16); - W_SDREG(fifoaddr, &SDPCMFIFOREG(bus, coretype, corerev)->fifoaddr, retries); - if (bcmsdh_regfail(bus->sdh)) regerrs++; - R_SDREG(rdptr, &SDPCMFIFOREG(bus, coretype, corerev)->fifodatalow, retries); - if (bcmsdh_regfail(bus->sdh)) regerrs++; - - /* Read the first 8 words out of the FIFO */ - for (count = 0, rdoffs = (rdptr & 0x7F); count < 8; count++) { - fifoaddr = (0xA << 16) | rdoffs; - W_SDREG(fifoaddr, - &SDPCMFIFOREG(bus, coretype, corerev)->fifoaddr, - retries); - if (bcmsdh_regfail(bus->sdh)) regerrs++; - R_SDREG(datalow[count], - &SDPCMFIFOREG(bus, coretype, corerev)->fifodatalow, - retries); - if (bcmsdh_regfail(bus->sdh)) regerrs++; - W_SDREG(fifoaddr, - &SDPCMFIFOREG(bus, coretype, corerev)->fifoaddr, - retries); - if (bcmsdh_regfail(bus->sdh)) regerrs++; - R_SDREG(datahigh[count], - &SDPCMFIFOREG(bus, coretype, corerev)->fifodatahigh, - retries); - if (bcmsdh_regfail(bus->sdh)) regerrs++; - rdoffs = (rdoffs + 1) & 0x7F; - } - - /* For the heck of it, read the pointers again */ - fifoaddr = (0xB << 16); - W_SDREG(fifoaddr, - &SDPCMFIFOREG(bus, coretype, corerev)->fifoaddr, retries); - if (bcmsdh_regfail(bus->sdh)) regerrs++; - R_SDREG(endptrs, - &SDPCMFIFOREG(bus, coretype, corerev)->fifodatalow, retries); - if (bcmsdh_regfail(bus->sdh)) regerrs++; - - printf("Initial read of Transmit DMA Pointers: 0x%08x\n", rdptr); - printf("Transmit DMA Data\n"); - for (count = 0, rdoffs = (rdptr & 0x7F); count < 8; count++) { - printf("0x%08x: 0x%08x 0x%08x\n", rdoffs, - datahigh[count], datalow[count]); - rdoffs = (rdoffs + 1) & 0x7F; - } - printf("Final read of Transmit DMA Pointers: 0x%08x\n", endptrs); - printf("Register errors: %d\n", regerrs); - - checkfifo = FALSE; - } -#endif /* BCMINTERNAL */ framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone); if (rxdone || bus->rxskip) @@ -8053,7 +8469,11 @@ clkwait: } else if (bus->clkstate == CLK_PENDING) { /* Awaiting I_CHIPACTIVE; don't resched */ } else if (bus->intstatus || bus->ipend || - (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) || + (!bus->fcstate && (pktq_mlen(&bus->txq, ((~bus->flowcontrol) +#ifdef DHD_LOSSLESS_ROAMING + & bus->dhd->dequeue_prec_map +#endif /* DHD_LOSSLESS_ROAMING */ + ))) && DATAOK(bus)) || PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */ resched = TRUE; } @@ -8127,9 +8547,16 @@ bool dhd_bus_dpc(struct dhd_bus *bus) { bool resched; +#ifdef DHD_WAKE_STATUS + dhd_pub_t *dhdp = bus->dhd; +#endif /* Call the DPC directly. */ DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); +#ifdef DHD_WAKE_STATUS + if (dhdp && dhdp->in_suspend) + bcmsdh_set_get_wake(bus->sdh, 1); +#endif resched = dhdsdio_dpc(bus); return resched; @@ -9008,11 +9435,6 @@ dhd_dump_cis(uint fn, uint8 *cis) DHD_INFO(("Function %d CIS:\n", fn)); for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) { - if ((byte % 16) == 0) - DHD_INFO((" ")); - DHD_INFO(("%02x ", cis[byte])); - if ((byte % 16) == 15) - DHD_INFO(("\n")); if (!tdata--) { tag = cis[byte]; if (tag == 0xff) @@ -9021,12 +9443,9 @@ dhd_dump_cis(uint fn, uint8 *cis) tdata = 0; else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT) tdata = cis[byte + 1] + 1; - else - DHD_INFO(("]")); } } - if ((byte % 16) != 15) - DHD_INFO(("\n")); + prhex(NULL, (const u8 *) cis, byte+1); } #endif /* DHD_DEBUG */ @@ -9067,15 +9486,17 @@ dhdsdio_chipmatch(uint16 chipid) return TRUE; if (BCM4349_CHIP(chipid)) return TRUE; -#ifdef UNRELEASEDCHIP - if ((chipid == BCM4347_CHIP_ID) || - (chipid == BCM4357_CHIP_ID) || - (chipid == BCM4361_CHIP_ID)) - return TRUE; -#endif if (chipid == BCM4364_CHIP_ID) return TRUE; + if (chipid == BCM4381_CHIP_ID) { + return TRUE; + } + + if (chipid == BCM4382_CHIP_ID) { + return TRUE; + } + if (chipid == BCM43012_CHIP_ID) return TRUE; @@ -9098,7 +9519,10 @@ dhdsdio_chipmatch(uint16 chipid) return TRUE; if (chipid == BCM43752_CHIP_ID) return TRUE; - + if (chipid == BCM43756_CHIP_ID) + return TRUE; + if (chipid == BCM43711_CHIP_ID) + return TRUE; return FALSE; } @@ -9163,11 +9587,6 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, /* Check the Device ID and make sure it's one that we support */ switch (devid) { -#ifdef BCMINTERNAL - case SDIOD_FPGA_ID: - DHD_INFO(("%s: found FPGA Dongle\n", __FUNCTION__)); - break; -#endif /* BCMINTERNAL */ case 0: DHD_INFO(("%s: allow device id 0, will check chip internals\n", __FUNCTION__)); @@ -9252,10 +9671,15 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, /* if firmware path present try to download and bring up bus */ bus->dhd->hang_report = TRUE; -#if 0 // terence 20150325: fix for WPA/WPA2 4-way handshake fail in hostapd + +#if defined(BCMDHD_MODULAR) && defined(INSMOD_FW_LOAD) + if (1) +#else #if defined(LINUX) || defined(linux) - if (dhd_download_fw_on_driverload) { + if (!dhd_conf_legacy_otp_chip(bus->dhd)) #endif /* LINUX || linux */ +#endif + { if ((ret = dhd_bus_start(bus->dhd)) != 0) { DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__)); #if !defined(OEM_ANDROID) @@ -9274,7 +9698,6 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, bus->dhd->mac.octet[2] = 0x4C; } #endif /* LINUX || linux */ -#endif #if defined(BT_OVER_SDIO) /* At this point Regulators are turned on and iconditionaly sdio bus is started * based upon dhd_download_fw_on_driverload check, so @@ -9287,8 +9710,9 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, #endif /* BT_OVER_SDIO */ /* Ok, have the per-port tell the stack we're open for business */ - if (dhd_attach_net(bus->dhd, TRUE) != 0) { - DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__)); + DHD_TRACE(("%s(): Calling dhd_attach_net() \n", __FUNCTION__)); + if (dhd_attach_net(bus->dhd, TRUE)) { + DHD_ERROR(("%s(): ERROR.. dhd_attach_net() failed\n", __FUNCTION__)); goto fail; } @@ -9330,10 +9754,10 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__)); } -#if defined(DHD_DEBUG) && !defined(CUSTOMER_HW4_DEBUG) +#if defined(DHD_DEBUG) DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n", bcmsdh_reg_read(bus->sdh, si_enum_base(devid), 4))); -#endif /* DHD_DEBUG && !CUSTOMER_HW4_DEBUG */ +#endif #ifndef BCMSPI /* wake-wlan in gSPI will bring up the htavail/alpavail clocks. */ @@ -9435,28 +9859,20 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) { DHD_ERROR(("%s: unsupported chip: 0x%04x\n", __FUNCTION__, bus->sih->chip)); -#ifdef BCMINTERNAL - if (dhd_anychip) - DHD_ERROR(("Continuing anyway...\n")); - else -#endif /* BCMINTERNAL */ goto fail; } - if (bus->sih->buscorerev >= 12) + if (bus->sih->buscorerev >= 12) { dhdsdio_clk_kso_init(bus); - else + } else { bus->kso = TRUE; + } + + /* to wake up completely incase sleep is triggered before bus start */ + dhdsdio_set_wakeupctrl(bus); si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength); -#ifdef BCMINTERNAL - /* Check if there is a PMU in the chip. The FPGA does not have a PMU. */ - if (!(bus->sih->cccaps & CC_CAP_PMU)) { - DHD_NOPMU(bus) = 1; - } -#endif /* BCMINTERNAL */ - /* Get info on the ARM and SOCRAM cores... */ /* XXX Should really be qualified by device id */ if (!DHD_NOPMU(bus)) { @@ -9508,13 +9924,12 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, case BCM4364_CHIP_ID: bus->dongle_ram_base = CR4_4364_RAM_BASE; break; -#ifdef UNRELEASEDCHIP - case BCM4347_CHIP_ID: - case BCM4357_CHIP_ID: - case BCM4361_CHIP_ID: - bus->dongle_ram_base = CR4_4347_RAM_BASE; + case BCM4381_CHIP_ID: + bus->dongle_ram_base = CR4_4381_RAM_BASE; + break; + case BCM4382_CHIP_ID: + bus->dongle_ram_base = CR4_4382_RAM_BASE; break; -#endif case BCM4362_CHIP_ID: bus->dongle_ram_base = CR4_4362_RAM_BASE; break; @@ -9524,6 +9939,12 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, case BCM43752_CHIP_ID: bus->dongle_ram_base = CR4_43752_RAM_BASE; break; + case BCM43756_CHIP_ID: + bus->dongle_ram_base = CR4_43756_RAM_BASE; + break; + case BCM43711_CHIP_ID: + bus->dongle_ram_base = CR4_43711_RAM_BASE; + break; case BCM4369_CHIP_ID: bus->dongle_ram_base = CR4_4369_RAM_BASE; break; @@ -9546,6 +9967,16 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, bus->srmemsize = si_socram_srmem_size(bus->sih); } + if ((CHIPID(bus->sih->chip) == BCM43430_CHIP_ID) && dhdsdio_sr_cap(bus)) { + if (dhd_srmem) { + bus->srmemsize = dhd_srmem; + } else { + /* 43436/8 default sr size is 64K */ + bus->srmemsize = 0x10000; + } + DHD_ERROR(("%s srmem size is set %x\n", __func__, bus->srmemsize)); + } + /* ...but normally deal with the SDPCMDEV core */ #ifdef BCMSDIOLITE if (!(bus->regs = si_setcore(bus->sih, CC_CORE_ID, 0))) { @@ -9826,6 +10257,9 @@ exit: return ret; } +#ifdef BCM_REQUEST_FW +extern char clm_path[MOD_PARAM_PATHLEN]; +#endif /* BCM_REQUEST_FW */ static int dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) { @@ -10005,6 +10439,14 @@ dhdsdio_disconnect(void *ptr) DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); } +#ifdef PWRSTATS_SYSFS +uint64 +dhdsdio_get_last_suspend_time(dhd_pub_t *dhdp) +{ + return dhdp->bus->last_suspend_end_time; +} +#endif /* PWRSTATS_SYSFS */ + static int dhdsdio_suspend(void *context) { @@ -10082,6 +10524,8 @@ dhdsdio_suspend(void *context) bus->dhd->busstate = DHD_BUS_DATA; /* resume all interface network queue. */ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); + } else { + bus->last_suspend_end_time = OSL_LOCALTIME_NS(); } bus->dhd->hostsleep = 2; DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd); @@ -10287,6 +10731,8 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) bcmerror)); goto err; } + bus->fw_download_len = fw->size; + bus->fw_download_addr = bus->dongle_ram_base; residual_len = fw->size; /* Update the dongle image download block size depending on the F1 block size */ @@ -10305,13 +10751,13 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); #ifdef CHECK_DOWNLOAD_FW - if (bus->dhd->conf->fwchk) { - memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); - if (memptr_tmp == NULL) { - DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); - goto err; - } + if (bus->dhd->conf->fwchk) { + memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); + if (memptr_tmp == NULL) { + DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); + goto err; } + } #endif #ifdef DHD_DEBUG_DOWNLOADTIME @@ -10321,7 +10767,7 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) /* Download image */ while (residual_len) { len = MIN(residual_len, memblock_size); - bcopy((uint8 *)fw->data + buf_offset, (uint8 *)memptr, len); + bcopy((const uint8 *)fw->data + buf_offset, (uint8 *)memptr, len); /* check if CR4 */ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { /* if address is 0, store the reset instruction to be written in 0 */ @@ -10406,6 +10852,8 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct #endif uint memblock_size = MEMBLOCK; + uint32 file_size = 0; + fwpkg_info_t *fwpkg; #ifdef DHD_DEBUG_DOWNLOADTIME unsigned long initial_jiffies = 0; uint firmware_sz = 0; @@ -10416,12 +10864,34 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) /* XXX: Should succeed in opening image if it is actually given through registry * entry or in module param. */ - image = dhd_os_open_image1(bus->dhd, pfw_path); - if (image == NULL) { + bcmerror = fwpkg_init(&bus->fwpkg, pfw_path); + if (bcmerror == BCME_ERROR) { + printf("%s: fwpkg_init failed %s\n", __FUNCTION__, pfw_path); + goto err; + } + fwpkg = &bus->fwpkg; + /* Should succeed in opening image if it is actually given through registry + * entry or in module param. + */ + bcmerror = fwpkg_open_firmware_img(fwpkg, pfw_path, &image); + if (bcmerror == BCME_ERROR) { printf("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path); goto err; } + if (bcmerror == BCME_UNSUPPORTED) { + file_size = fwpkg->file_size; + DHD_ERROR(("%s Using SINGLE image (size %d)\n", + __FUNCTION__, file_size)); + } else { + file_size = fwpkg_get_firmware_img_size(fwpkg); + strlcpy(bus->fwsig_filename, pfw_path, sizeof(bus->fwsig_filename)); + DHD_ERROR(("%s Using COMBINED image (size %d)\n", + __FUNCTION__, file_size)); + } + bus->fw_download_len = file_size; + bus->fw_download_addr = bus->dongle_ram_base; + /* Update the dongle image download block size depending on the F1 block size */ #ifndef NDIS if (sd_f1_blocksize == 512) @@ -10683,11 +11153,7 @@ dhdsdio_download_nvram(struct dhd_bus *bus) if (bcmerror != BCME_OK) goto err; -#ifdef DHD_LINUX_STD_FW_API - memblock_len = len; -#else memblock_len = MAX_NVRAMBUF_SIZE; -#endif /* DHD_LINUX_STD_FW_API */ if (len > 0 && len < MAX_NVRAMBUF_SIZE) { bufp = (char *)memblock; @@ -10705,8 +11171,8 @@ dhdsdio_download_nvram(struct dhd_bus *bus) __FUNCTION__, bcmerror)); } } else { - DHD_ERROR(("%s: error reading nvram file: %d\n", - __FUNCTION__, len)); + DHD_ERROR(("%s: error reading nvram file: %s %d\n", + __FUNCTION__, pnv_path, len)); bcmerror = BCME_SDIO_ERROR; } @@ -10743,7 +11209,8 @@ _dhdsdio_download_firmware(struct dhd_bus *bus) /* External image takes precedence if specified */ if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { if (dhdsdio_download_code_file(bus, bus->fw_path)) { - DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__)); + DHD_ERROR(("%s: dongle image file %s download failed\n", + __FUNCTION__, bus->fw_path)); #ifdef BCMEMBEDIMAGE embed = TRUE; #else @@ -10778,6 +11245,10 @@ _dhdsdio_download_firmware(struct dhd_bus *bus) goto err; } + if (CHIPID(bus->sih->chip) == BCM43711_CHIP_ID) { + si_pmu_43711a0_pll_war(bus->sih); + } + /* Take arm out of reset */ if (dhdsdio_download_state(bus, FALSE)) { DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__)); @@ -11264,15 +11735,10 @@ static int concate_revision_bcm4354(dhd_bus_t *bus, char *fw_path, char *nv_path #if defined(SUPPORT_MULTIPLE_CHIPS) char chipver_tag[10] = "_4354"; #else -#if !defined(CUSTOMER_HW4) char chipver_tag[4] = {0, }; -#endif /* !CUSTOMER_HW4 */ #endif /* SUPPORT_MULTIPLE_CHIPS */ chip_ver = bus->sih->chiprev; -#if !defined(SUPPORT_MULTIPLE_CHIPS) && defined(CUSTOMER_HW4) - DHD_INFO(("----- CHIP 4354, ver=%x -----\n", chip_ver)); -#else if (chip_ver == 1) { DHD_ERROR(("----- CHIP 4354 A1 -----\n")); strcat(chipver_tag, "_a1"); @@ -11282,7 +11748,6 @@ static int concate_revision_bcm4354(dhd_bus_t *bus, char *fw_path, char *nv_path strcat(fw_path, chipver_tag); strcat(nv_path, chipver_tag); -#endif /* !SUPPORT_MULTIPLE_CHIPS && CUSTOMER_HW4 */ return 0; } @@ -11912,18 +12377,28 @@ int dhd_get_idletime(dhd_pub_t *dhd) wake_counts_t* dhd_bus_get_wakecount(dhd_pub_t *dhd) { - if (!dhd->bus) { - return NULL; - } return &dhd->bus->wake_counts; } + int dhd_bus_get_bus_wake(dhd_pub_t *dhd) { return bcmsdh_set_get_wake(dhd->bus->sdh, 0); } + +int +dhd_bus_set_get_bus_wake(dhd_pub_t *dhd, int set) +{ + return bcmsdh_set_get_wake(dhd->bus->sdh, set); +} #endif /* DHD_WAKE_STATUS */ +void +dhd_bus_set_signature_path(struct dhd_bus *bus, char *sig_path) +{ + strlcpy(bus->fwsig_filename, sig_path, sizeof(bus->fwsig_filename)); +} + int dhd_bus_sleep(dhd_pub_t *dhdp, bool sleep, uint32 *intstatus) { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sec_feature.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sec_feature.h deleted file mode 100755 index 671a71a88b9c..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sec_feature.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Customer HW 4 dependant file - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id: dhd_sec_feature.h$ - */ - -/* XXX This File managed by Samsung */ - -/* - * ** Desciption *** - * 1. Module vs COB - * If your model's WIFI HW chip is COB type, you must add below feature - * - #undef USE_CID_CHECK - * - #define READ_MACADDR - * Because COB type chip have not CID and Mac address. - * So, you must add below feature to defconfig file. - * - CONFIG_WIFI_BROADCOM_COB - * - * 2. PROJECTS - * If you want add some feature only own Project, you can add it in 'PROJECTS' part. - * - * 3. Region code - * If you want add some feature only own region model, you can use below code. - * - 100 : EUR OPEN - * - 101 : EUR ORG - * - 200 : KOR OPEN - * - 201 : KOR SKT - * - 202 : KOR KTT - * - 203 : KOR LGT - * - 300 : CHN OPEN - * - 400 : USA OPEN - * - 401 : USA ATT - * - 402 : USA TMO - * - 403 : USA VZW - * - 404 : USA SPR - * - 405 : USA USC - * You can refer how to using it below this file. - * And, you can add more region code, too. - */ - -#ifndef _dhd_sec_feature_h_ -#define _dhd_sec_feature_h_ - -#include - -/* For COB type feature */ -#ifdef CONFIG_WIFI_BROADCOM_COB -#undef USE_CID_CHECK -#define READ_MACADDR -#endif /* CONFIG_WIFI_BROADCOM_COB */ - -#if defined(CONFIG_MACH_UNIVERSAL7420) || defined(CONFIG_ARCH_MSM8994) || \ - defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_SOC_EXYNOS8890) -#define SUPPORT_MULTIPLE_MODULE_CIS -#endif /* CONFIG_MACH_UNIVERSAL7420 || CONFIG_ARCH_MSM8994 || - * CONFIG_ARCH_MSM8996 || CONFIG_SOC_EXYNOS8890 - */ - -#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_SOC_EXYNOS8890) -#define SUPPORT_BCM4359_MIXED_MODULES -#endif /* CONFIG_ARCH_MSM8996 || CONFIG_SOC_EXYNOS8890 */ - -#if defined(CONFIG_ARGOS) -#if defined(CONFIG_SPLIT_ARGOS_SET) -#define ARGOS_IRQ_WIFI_TABLE_LABEL "WIFI TX" -#define ARGOS_WIFI_TABLE_LABEL "WIFI RX" -#else /* CONFIG_SPLIT_ARGOS_SET */ -#define ARGOS_IRQ_WIFI_TABLE_LABEL "WIFI" -#define ARGOS_WIFI_TABLE_LABEL "WIFI" -#endif /* CONFIG_SPLIT_ARGOS_SET */ -#define ARGOS_P2P_TABLE_LABEL "P2P" -#endif /* CONFIG_ARGOS */ - -/* PROJECTS START */ - -#if defined(CONFIG_MACH_UNIVERSAL7420) || defined(CONFIG_SOC_EXYNOS8890) || \ - defined(CONFIG_SOC_EXYNOS8895) -#undef CUSTOM_SET_CPUCORE -#define PRIMARY_CPUCORE 0 -#define DPC_CPUCORE 4 -#define RXF_CPUCORE 5 -#define TASKLET_CPUCORE 5 -#define ARGOS_CPU_SCHEDULER -#define ARGOS_RPS_CPU_CTL - -#ifdef CONFIG_SOC_EXYNOS8895 -#define ARGOS_DPC_TASKLET_CTL -#endif /* CONFIG_SOC_EXYNOS8895 */ - -#ifdef CONFIG_MACH_UNIVERSAL7420 -#define EXYNOS_PCIE_DEBUG -#endif /* CONFIG_MACH_UNIVERSAL7420 */ -#endif /* CONFIG_MACH_UNIVERSAL7420 || CONFIG_SOC_EXYNOS8890 || CONFIG_SOC_EXYNOS8895 */ - -#if defined(CONFIG_SOC_EXYNOS9810) || defined(CONFIG_SOC_EXYNOS9820) || \ - defined(CONFIG_SOC_EXYNOS9830) || defined(CONFIG_SOC_EXYNOS2100) || \ - defined(CONFIG_SOC_EXYNOS1000) -#define PCIE_IRQ_CPU_CORE 5 -#endif /* CONFIG_SOC_EXYNOS9810 || CONFIG_SOC_EXYNOS9820 || defined(CONFIG_SOC_EXYNOS9830 */ - -#if defined(DHD_LB) -#if defined(CONFIG_ARCH_SM8150) || defined(CONFIG_ARCH_KONA) || defined(CONFIG_ARCH_LAHAINA) -#define DHD_LB_PRIMARY_CPUS (0x70) -#define DHD_LB_SECONDARY_CPUS (0x0E) -#elif defined(CONFIG_SOC_EXYNOS9810) || defined(CONFIG_SOC_EXYNOS9820) || \ - defined(CONFIG_SOC_EXYNOS9830) || defined(CONFIG_SOC_EXYNOS2100) || \ - defined(CONFIG_SOC_EXYNOS1000) -#define DHD_LB_PRIMARY_CPUS (0x70) -#define DHD_LB_SECONDARY_CPUS (0x0E) -#elif defined(CONFIG_SOC_EXYNOS8890) -/* - * Removed core 6~7 from NAPI CPU mask. - * Exynos 8890 disabled core 6~7 by default. - */ -#define DHD_LB_PRIMARY_CPUS (0x30) -#define DHD_LB_SECONDARY_CPUS (0x0E) -#elif defined(CONFIG_SOC_EXYNOS8895) -/* using whole big core with NAPI mask */ -#define DHD_LB_PRIMARY_CPUS (0xF0) -#define DHD_LB_SECONDARY_CPUS (0x0E) -#elif defined(CONFIG_ARCH_MSM8998) -#define DHD_LB_PRIMARY_CPUS (0x20) -#define DHD_LB_SECONDARY_CPUS (0x0E) -#elif defined(CONFIG_ARCH_MSM8996) -#define DHD_LB_PRIMARY_CPUS (0x0C) -#define DHD_LB_SECONDARY_CPUS (0x03) -#else /* Default LB masks */ -/* using whole big core with NAPI mask */ -#define DHD_LB_PRIMARY_CPUS (0xF0) -#define DHD_LB_SECONDARY_CPUS (0x0E) -#endif /* CONFIG_SOC_EXYNOS8890 */ -#else /* !DHD_LB */ -#define ARGOS_DPC_TASKLET_CTL -#endif /* !DHD_LB */ - -#if defined(CONFIG_ARCH_MSM) || defined(CONFIG_SOC_EXYNOS8895) || \ - defined(CONFIG_SOC_EXYNOS9810) || defined(CONFIG_SOC_EXYNOS9820) || \ - defined(CONFIG_SOC_EXYNOS9830) || defined(CONFIG_SOC_EXYNOS2100) || \ - defined(CONFIG_SOC_EXYNOS1000) -#if defined(CONFIG_BCMDHD_PCIE) -#define BCMPCIE_DISABLE_ASYNC_SUSPEND -#endif /* CONFIG_BCMDHD_PCIE */ -#endif /* CONFIG_ARCH_MSM */ -/* PROJECTS END */ - -/* REGION CODE START */ - -#ifndef CONFIG_WLAN_REGION_CODE -#define CONFIG_WLAN_REGION_CODE 100 -#endif /* CONFIG_WLAN_REGION_CODE */ - -#if (CONFIG_WLAN_REGION_CODE >= 100) && (CONFIG_WLAN_REGION_CODE < 200) /* EUR */ -#if (CONFIG_WLAN_REGION_CODE == 101) /* EUR ORG */ -/* GAN LITE NAT KEEPALIVE FILTER */ -#define GAN_LITE_NAT_KEEPALIVE_FILTER -#endif /* CONFIG_WLAN_REGION_CODE == 101 */ -#if (CONFIG_WLAN_REGION_CODE == 150) /* EUR FD(DualSIM) */ -#define SUPPORT_MULTIPLE_BOARD_REV_FROM_HW -#endif /* CONFIG_WLAN_REGION_CODE == 150 */ -#endif /* CONFIG_WLAN_REGION_CODE >= 100 && CONFIG_WLAN_REGION_CODE < 200 */ - -#if (CONFIG_WLAN_REGION_CODE >= 200) && (CONFIG_WLAN_REGION_CODE < 300) /* KOR */ -#undef USE_INITIAL_2G_SCAN -#ifndef ROAM_ENABLE -#define ROAM_ENABLE -#endif /* ROAM_ENABLE */ -#ifndef ROAM_API -#define ROAM_API -#endif /* ROAM_API */ -#ifndef ROAM_CHANNEL_CACHE -#define ROAM_CHANNEL_CACHE -#endif /* ROAM_CHANNEL_CACHE */ -#ifndef OKC_SUPPORT -#define OKC_SUPPORT -#endif /* OKC_SUPPORT */ - -#ifndef ROAM_AP_ENV_DETECTION -#define ROAM_AP_ENV_DETECTION -#endif /* ROAM_AP_ENV_DETECTION */ - -#undef WRITE_MACADDR -#ifndef READ_MACADDR -#define READ_MACADDR -#endif /* READ_MACADDR */ -#endif /* CONFIG_WLAN_REGION_CODE >= 200 && CONFIG_WLAN_REGION_CODE < 300 */ - -#if (CONFIG_WLAN_REGION_CODE >= 300) && (CONFIG_WLAN_REGION_CODE < 400) /* CHN */ -#define BCMWAPI_WPI -#define BCMWAPI_WAI -#endif /* CONFIG_WLAN_REGION_CODE >= 300 && CONFIG_WLAN_REGION_CODE < 400 */ - -#if (CONFIG_WLAN_REGION_CODE == 500) /* JP */ -#if defined(BCM4375_CHIP) -#define DISABLE_HE_ENAB -#endif /* BCM4375_CHIP */ -#endif /* CONFIG_WLAN_REGION_CODE == 500 */ - -/* REGION CODE END */ - -#if !defined(READ_MACADDR) && !defined(WRITE_MACADDR) -#define GET_MAC_FROM_OTP -#define SHOW_NVRAM_TYPE -#endif /* !READ_MACADDR && !WRITE_MACADDR */ - -#define WRITE_WLANINFO - -#endif /* _dhd_sec_feature_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c old mode 100755 new mode 100644 index cfbf3053667d..edb2a4a92fa6 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include @@ -7,37 +6,46 @@ #include #include -#define DHD_STATIC_VERSION_STR "101.10.361.18 (wlan=r892223-20220519-1)" -#define STATIC_ERROR_LEVEL (1 << 0) -#define STATIC_TRACE_LEVEL (1 << 1) -#define STATIC_MSG_LEVEL (1 << 0) +#define DHD_STATIC_VERSION_STR "101.10.361.31 (wlan=r892223-20230427-1)" +#define STATIC_ERROR_LEVEL BIT(0) +#define STATIC_TRACE_LEVEL BIT(1) +#define STATIC_MSG_LEVEL BIT(0) uint static_msg_level = STATIC_ERROR_LEVEL | STATIC_MSG_LEVEL; #define DHD_STATIC_MSG(x, args...) \ - do { \ - if (static_msg_level & STATIC_MSG_LEVEL) { \ - pr_err("[dhd] STATIC-MSG) %s : " x, __func__, ## args); \ - } \ - } while (0) +do { \ + if (static_msg_level & STATIC_MSG_LEVEL) { \ + pr_err("[dhd] STATIC-MSG) %s : " x, __func__, ## args); \ + } \ +} while (0) #define DHD_STATIC_ERROR(x, args...) \ - do { \ - if (static_msg_level & STATIC_ERROR_LEVEL) { \ - pr_err("[dhd] STATIC-ERROR) %s : " x, __func__, ## args); \ - } \ - } while (0) +do { \ + if (static_msg_level & STATIC_ERROR_LEVEL) { \ + pr_err("[dhd] STATIC-ERROR) %s : " x, __func__, ## args); \ + } \ +} while (0) #define DHD_STATIC_TRACE(x, args...) \ - do { \ - if (static_msg_level & STATIC_TRACE_LEVEL) { \ - pr_err("[dhd] STATIC-TRACE) %s : " x, __func__, ## args); \ - } \ - } while (0) +do { \ + if (static_msg_level & STATIC_TRACE_LEVEL) { \ + pr_err("[dhd] STATIC-TRACE) %s : " x, __func__, ## args); \ + } \ +} while (0) -#define BCMDHD_SDIO -#define BCMDHD_PCIE -//#define BCMDHD_USB -#define CONFIG_BCMDHD_VTS := y -#define CONFIG_BCMDHD_DEBUG := y +#ifndef DHD_STATIC_IN_DRIVER +#ifndef BCMSDIO +#define BCMSDIO +#endif +#ifndef BCMPCIE +#define BCMPCIE +#endif +#ifndef BCMDBUS +#define BCMDBUS +#endif +#ifndef DHD_USE_STATIC_MEMDUMP +#define DHD_USE_STATIC_MEMDUMP { : = y} +#endif //#define BCMDHD_UNUSE_MEM +#endif #ifndef MAX_NUM_ADAPTERS #define MAX_NUM_ADAPTERS 1 @@ -45,34 +53,34 @@ uint static_msg_level = STATIC_ERROR_LEVEL | STATIC_MSG_LEVEL; enum dhd_prealloc_index { DHD_PREALLOC_PROT = 0, -#if defined(BCMDHD_SDIO) +#if defined(BCMSDIO) DHD_PREALLOC_RXBUF = 1, DHD_PREALLOC_DATABUF = 2, -#endif /* BCMDHD_SDIO */ +#endif /* BCMSDIO */ DHD_PREALLOC_OSL_BUF = 3, DHD_PREALLOC_SKB_BUF = 4, DHD_PREALLOC_WIPHY_ESCAN0 = 5, DHD_PREALLOC_WIPHY_ESCAN1 = 6, DHD_PREALLOC_DHD_INFO = 7, -#if defined(BCMDHD_SDIO) || defined(BCMDHD_USB) +#if defined(BCMSDIO) || defined(BCMDBUS) DHD_PREALLOC_DHD_WLFC_INFO = 8, -#endif /* BCMDHD_SDIO | BCMDHD_USB */ -#ifdef BCMDHD_PCIE +#endif /* BCMSDIO | BCMDBUS */ +#ifdef BCMPCIE DHD_PREALLOC_IF_FLOW_LKUP = 9, -#endif /* BCMDHD_PCIE */ +#endif /* BCMPCIE */ DHD_PREALLOC_MEMDUMP_BUF = 10, -#if defined(CONFIG_BCMDHD_VTS) || defined(CONFIG_BCMDHD_DEBUG) +#if defined(DHD_USE_STATIC_MEMDUMP) || defined(BCMDBUS) DHD_PREALLOC_MEMDUMP_RAM = 11, -#endif /* CONFIG_BCMDHD_VTS | CONFIG_BCMDHD_DEBUG */ -#if defined(BCMDHD_SDIO) || defined(BCMDHD_USB) +#endif /* DHD_USE_STATIC_MEMDUMP | BCMDBUS */ +#if defined(BCMSDIO) || defined(BCMDBUS) DHD_PREALLOC_DHD_WLFC_HANGER = 12, -#endif /* BCMDHD_SDIO | BCMDHD_USB */ +#endif /* BCMSDIO | BCMDBUS */ DHD_PREALLOC_PKTID_MAP = 13, DHD_PREALLOC_PKTID_MAP_IOCTL = 14, -#if defined(CONFIG_BCMDHD_VTS) || defined(CONFIG_BCMDHD_DEBUG) +#ifdef DHD_USE_STATIC_MEMDUMP DHD_PREALLOC_DHD_LOG_DUMP_BUF = 15, DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX = 16, -#endif /* CONFIG_BCMDHD_VTS | CONFIG_BCMDHD_DEBUG */ +#endif /* DHD_USE_STATIC_MEMDUMP */ DHD_PREALLOC_DHD_PKTLOG_DUMP_BUF = 17, DHD_PREALLOC_STAT_REPORT_BUF = 18, DHD_PREALLOC_WL_ESCAN = 19, @@ -86,10 +94,11 @@ enum dhd_prealloc_index { }; #define STATIC_BUF_MAX_NUM 20 -#define STATIC_BUF_SIZE (PAGE_SIZE*2) +#define STATIC_BUF_SIZE (PAGE_SIZE * 2) #ifndef CUSTOM_LOG_DUMP_BUFSIZE_MB -#define CUSTOM_LOG_DUMP_BUFSIZE_MB 4 /* DHD_LOG_DUMP_BUF_SIZE 4 MB static memory in kernel */ +/* DHD_LOG_DUMP_BUF_SIZE 4 MB static memory in kernel */ +#define CUSTOM_LOG_DUMP_BUFSIZE_MB 4 #endif /* CUSTOM_LOG_DUMP_BUFSIZE_MB */ #define DHD_PREALLOC_PROT_SIZE (16 * 1024) @@ -97,15 +106,14 @@ enum dhd_prealloc_index { #define DHD_PREALLOC_DATABUF_SIZE (64 * 1024) #define DHD_PREALLOC_OSL_BUF_SIZE (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE) #define DHD_PREALLOC_WIPHY_ESCAN0_SIZE (64 * 1024) -#define DHD_PREALLOC_DHD_INFO_SIZE (36 * 1024) -#if defined(CONFIG_BCMDHD_VTS) || defined(CONFIG_BCMDHD_DEBUG) +#define DHD_PREALLOC_DHD_INFO_SIZE (44 * 1024) #define DHD_PREALLOC_MEMDUMP_RAM_SIZE (1290 * 1024) -#endif /* CONFIG_BCMDHD_VTS | CONFIG_BCMDHD_DEBUG */ #define DHD_PREALLOC_DHD_WLFC_HANGER_SIZE (73 * 1024) -#if defined(CONFIG_BCMDHD_VTS) || defined(CONFIG_BCMDHD_DEBUG) -#define DHD_PREALLOC_DHD_LOG_DUMP_BUF_SIZE (1024 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) +#ifdef DHD_USE_STATIC_MEMDUMP +#define DHD_PREALLOC_DHD_LOG_DUMP_BUF_SIZE \ + (1024 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB) #define DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX_SIZE (8 * 1024) -#endif /* CONFIG_BCMDHD_VTS | CONFIG_BCMDHD_DEBUG */ +#endif /* DHD_USE_STATIC_MEMDUMP */ #define DHD_PREALLOC_WL_ESCAN_SIZE (70 * 1024) #ifdef CONFIG_64BIT #define DHD_PREALLOC_IF_FLOW_LKUP_SIZE (20 * 1024 * 2) @@ -128,87 +136,87 @@ enum dhd_prealloc_index { #endif /* CONFIG_64BIT */ #define WLAN_DHD_MEMDUMP_SIZE (800 * 1024) -#define DHD_SKB_1PAGE_BUFSIZE (PAGE_SIZE*1) -#define DHD_SKB_2PAGE_BUFSIZE (PAGE_SIZE*2) -#define DHD_SKB_4PAGE_BUFSIZE (PAGE_SIZE*4) +#define DHD_SKB_1PAGE_BUFSIZE (PAGE_SIZE * 1) +#define DHD_SKB_2PAGE_BUFSIZE (PAGE_SIZE * 2) +#define DHD_SKB_4PAGE_BUFSIZE (PAGE_SIZE * 4) -#ifdef BCMDHD_PCIE +#ifdef BCMPCIE #define DHD_SKB_1PAGE_BUF_NUM 0 #define DHD_SKB_2PAGE_BUF_NUM 192 -#elif defined(BCMDHD_SDIO) +#elif defined(BCMSDIO) #define DHD_SKB_1PAGE_BUF_NUM 8 #define DHD_SKB_2PAGE_BUF_NUM 8 -#endif /* BCMDHD_PCIE */ +#endif /* BCMPCIE */ #define DHD_SKB_4PAGE_BUF_NUM 1 /* The number is defined in linux_osl.c * WLAN_SKB_1_2PAGE_BUF_NUM => STATIC_PKT_1_2PAGE_NUM * WLAN_SKB_BUF_NUM => STATIC_PKT_MAX_NUM */ -#if defined(BCMDHD_SDIO) || defined(BCMDHD_PCIE) +#if defined(BCMSDIO) || defined(BCMPCIE) #define WLAN_SKB_1_2PAGE_BUF_NUM ((DHD_SKB_1PAGE_BUF_NUM) + \ (DHD_SKB_2PAGE_BUF_NUM)) #define WLAN_SKB_BUF_NUM ((WLAN_SKB_1_2PAGE_BUF_NUM) + (DHD_SKB_4PAGE_BUF_NUM)) #endif -void *wlan_static_prot[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_rxbuf [MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_databuf[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_osl_buf[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_scan_buf0[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_scan_buf1[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_dhd_info_buf[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_dhd_wlfc_info_buf[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_if_flow_lkup[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_dhd_memdump_ram_buf[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_dhd_wlfc_hanger_buf[MAX_NUM_ADAPTERS] = {NULL}; -#if defined(CONFIG_BCMDHD_VTS) || defined(CONFIG_BCMDHD_DEBUG) -void *wlan_static_dhd_log_dump_buf[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_dhd_log_dump_buf_ex[MAX_NUM_ADAPTERS] = {NULL}; -#endif /* CONFIG_BCMDHD_VTS | CONFIG_BCMDHD_DEBUG */ -void *wlan_static_wl_escan_info_buf[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_fw_verbose_ring_buf[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_fw_event_ring_buf[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_dhd_event_ring_buf[MAX_NUM_ADAPTERS] = {NULL}; -void *wlan_static_nan_event_ring_buf[MAX_NUM_ADAPTERS] = {NULL}; +void *wlan_static_prot[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_rxbuf[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_databuf[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_osl_buf[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_scan_buf0[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_scan_buf1[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_dhd_info_buf[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_dhd_wlfc_info_buf[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_if_flow_lkup[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_dhd_memdump_ram_buf[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_dhd_wlfc_hanger_buf[MAX_NUM_ADAPTERS] = {}; +#ifdef DHD_USE_STATIC_MEMDUMP +void *wlan_static_dhd_log_dump_buf[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_dhd_log_dump_buf_ex[MAX_NUM_ADAPTERS] = {}; +#endif /* DHD_USE_STATIC_MEMDUMP */ +void *wlan_static_wl_escan_info_buf[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_fw_verbose_ring_buf[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_fw_event_ring_buf[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_dhd_event_ring_buf[MAX_NUM_ADAPTERS] = {}; +void *wlan_static_nan_event_ring_buf[MAX_NUM_ADAPTERS] = {}; -#if defined(BCMDHD_SDIO) || defined(BCMDHD_PCIE) -static struct sk_buff *wlan_static_skb[MAX_NUM_ADAPTERS][WLAN_SKB_BUF_NUM] = {{NULL}}; -#endif /* BCMDHD_SDIO | BCMDHD_PCIE */ +#if defined(BCMSDIO) || defined(BCMPCIE) +static struct sk_buff *wlan_static_skb[MAX_NUM_ADAPTERS][WLAN_SKB_BUF_NUM] = {}; +#endif /* BCMSDIO | BCMPCIE */ void * dhd_wlan_mem_prealloc( -#ifdef BCMDHD_MDRIVER +#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER) uint bus_type, int index, #endif int section, unsigned long size) { -#ifndef BCMDHD_MDRIVER +#if !defined(BCMDHD_MDRIVER) || defined(DHD_STATIC_IN_DRIVER) int index = 0; #endif -#ifdef BCMDHD_MDRIVER - DHD_STATIC_MSG("bus_type %d, index %d, sectoin %d, size %ld\n", +#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER) + DHD_STATIC_MSG("bus_type %d, index %d, section %d, size %ld\n", bus_type, index, section, size); #else - DHD_STATIC_MSG("sectoin %d, size %ld\n", section, size); + DHD_STATIC_MSG("section %d, size %ld\n", section, size); #endif if (section == DHD_PREALLOC_PROT) return wlan_static_prot[index]; -#if defined(BCMDHD_SDIO) +#if defined(BCMSDIO) if (section == DHD_PREALLOC_RXBUF) return wlan_static_rxbuf[index]; if (section == DHD_PREALLOC_DATABUF) return wlan_static_databuf[index]; -#endif /* BCMDHD_SDIO */ +#endif /* BCMSDIO */ -#if defined(BCMDHD_SDIO) || defined(BCMDHD_PCIE) +#if defined(BCMSDIO) || defined(BCMPCIE) if (section == DHD_PREALLOC_SKB_BUF) return wlan_static_skb[index]; -#endif /* BCMDHD_SDIO | BCMDHD_PCIE */ +#endif /* BCMSDIO | BCMPCIE */ if (section == DHD_PREALLOC_WIPHY_ESCAN0) return wlan_static_scan_buf0[index]; @@ -233,7 +241,7 @@ dhd_wlan_mem_prealloc( } return wlan_static_dhd_info_buf[index]; } -#if defined(BCMDHD_SDIO) || defined(BCMDHD_USB) +#if defined(BCMSDIO) || defined(BCMDBUS) if (section == DHD_PREALLOC_DHD_WLFC_INFO) { if (size > WLAN_DHD_WLFC_BUF_SIZE) { DHD_STATIC_ERROR("request DHD_WLFC_INFO(%lu) > %d\n", @@ -242,8 +250,8 @@ dhd_wlan_mem_prealloc( } return wlan_static_dhd_wlfc_info_buf[index]; } -#endif /* BCMDHD_SDIO | BCMDHD_USB */ -#ifdef BCMDHD_PCIE +#endif /* BCMSDIO | BCMDBUS */ +#ifdef BCMPCIE if (section == DHD_PREALLOC_IF_FLOW_LKUP) { if (size > DHD_PREALLOC_IF_FLOW_LKUP_SIZE) { DHD_STATIC_ERROR("request DHD_IF_FLOW_LKUP(%lu) > %d\n", @@ -252,8 +260,8 @@ dhd_wlan_mem_prealloc( } return wlan_static_if_flow_lkup[index]; } -#endif /* BCMDHD_PCIE */ -#if defined(CONFIG_BCMDHD_VTS) || defined(CONFIG_BCMDHD_DEBUG) +#endif /* BCMPCIE */ +#if defined(DHD_USE_STATIC_MEMDUMP) || defined(BCMDBUS) if (section == DHD_PREALLOC_MEMDUMP_RAM) { if (size > DHD_PREALLOC_MEMDUMP_RAM_SIZE) { DHD_STATIC_ERROR("request DHD_PREALLOC_MEMDUMP_RAM(%lu) > %d\n", @@ -262,8 +270,8 @@ dhd_wlan_mem_prealloc( } return wlan_static_dhd_memdump_ram_buf[index]; } -#endif /* CONFIG_BCMDHD_VTS | CONFIG_BCMDHD_DEBUG */ -#if defined(BCMDHD_SDIO) || defined(BCMDHD_USB) +#endif /* DHD_USE_STATIC_MEMDUMP | BCMDBUS */ +#if defined(BCMSDIO) || defined(BCMDBUS) if (section == DHD_PREALLOC_DHD_WLFC_HANGER) { if (size > DHD_PREALLOC_DHD_WLFC_HANGER_SIZE) { DHD_STATIC_ERROR("request DHD_WLFC_HANGER(%lu) > %d\n", @@ -272,8 +280,8 @@ dhd_wlan_mem_prealloc( } return wlan_static_dhd_wlfc_hanger_buf[index]; } -#endif /* BCMDHD_SDIO | BCMDHD_USB */ -#if defined(CONFIG_BCMDHD_VTS) || defined(CONFIG_BCMDHD_DEBUG) +#endif /* BCMSDIO | BCMDBUS */ +#ifdef DHD_USE_STATIC_MEMDUMP if (section == DHD_PREALLOC_DHD_LOG_DUMP_BUF) { if (size > DHD_PREALLOC_DHD_LOG_DUMP_BUF_SIZE) { DHD_STATIC_ERROR("request DHD_PREALLOC_DHD_LOG_DUMP_BUF(%lu) > %d\n", @@ -290,7 +298,7 @@ dhd_wlan_mem_prealloc( } return wlan_static_dhd_log_dump_buf_ex[index]; } -#endif /* CONFIG_BCMDHD_VTS | CONFIG_BCMDHD_DEBUG */ +#endif /* DHD_USE_STATIC_MEMDUMP */ if (section == DHD_PREALLOC_WL_ESCAN) { if (size > DHD_PREALLOC_WL_ESCAN_SIZE) { DHD_STATIC_ERROR("request DHD_PREALLOC_WL_ESCAN(%lu) > %d\n", @@ -333,7 +341,7 @@ dhd_wlan_mem_prealloc( return wlan_static_nan_event_ring_buf[index]; } #endif /* BCMDHD_UNUSE_MEM */ - if ((section < 0) || (section > DHD_PREALLOC_MAX)) + if (section < 0 || section > DHD_PREALLOC_MAX) DHD_STATIC_ERROR("request section id(%d) is out of max index %d\n", section, DHD_PREALLOC_MAX); @@ -342,6 +350,7 @@ dhd_wlan_mem_prealloc( return NULL; } + #ifndef DHD_STATIC_IN_DRIVER EXPORT_SYMBOL(dhd_wlan_mem_prealloc); #endif @@ -349,18 +358,18 @@ EXPORT_SYMBOL(dhd_wlan_mem_prealloc); static void dhd_deinit_wlan_mem(int index) { -#if defined(BCMDHD_SDIO) || defined(BCMDHD_PCIE) +#if defined(BCMSDIO) || defined(BCMPCIE) int i; -#endif /* BCMDHD_SDIO | BCMDHD_PCIE */ +#endif /* BCMSDIO | BCMPCIE */ if (wlan_static_prot[index]) kfree(wlan_static_prot[index]); -#if defined(BCMDHD_SDIO) +#if defined(BCMSDIO) if (wlan_static_rxbuf[index]) kfree(wlan_static_rxbuf[index]); if (wlan_static_databuf[index]) kfree(wlan_static_databuf[index]); -#endif /* BCMDHD_SDIO */ +#endif /* BCMSDIO */ if (wlan_static_osl_buf[index]) kfree(wlan_static_osl_buf[index]); if (wlan_static_scan_buf0[index]) @@ -369,28 +378,28 @@ dhd_deinit_wlan_mem(int index) kfree(wlan_static_scan_buf1[index]); if (wlan_static_dhd_info_buf[index]) kfree(wlan_static_dhd_info_buf[index]); -#if defined(BCMDHD_SDIO) || defined(BCMDHD_USB) +#if defined(BCMSDIO) || defined(BCMDBUS) if (wlan_static_dhd_wlfc_info_buf[index]) kfree(wlan_static_dhd_wlfc_info_buf[index]); -#endif /* BCMDHD_SDIO | BCMDHD_USB */ -#ifdef BCMDHD_PCIE +#endif /* BCMSDIO | BCMDBUS */ +#ifdef BCMPCIE if (wlan_static_if_flow_lkup[index]) kfree(wlan_static_if_flow_lkup[index]); -#endif /* BCMDHD_PCIE */ -#if defined(CONFIG_BCMDHD_VTS) || defined(CONFIG_BCMDHD_DEBUG) +#endif /* BCMPCIE */ +#if defined(DHD_USE_STATIC_MEMDUMP) || defined(BCMDBUS) if (wlan_static_dhd_memdump_ram_buf[index]) kfree(wlan_static_dhd_memdump_ram_buf[index]); -#endif /* CONFIG_BCMDHD_VTS | CONFIG_BCMDHD_DEBUG */ -#if defined(BCMDHD_SDIO) || defined(BCMDHD_USB) +#endif /* DHD_USE_STATIC_MEMDUMP | BCMDBUS */ +#if defined(BCMSDIO) || defined(BCMDBUS) if (wlan_static_dhd_wlfc_hanger_buf[index]) kfree(wlan_static_dhd_wlfc_hanger_buf[index]); -#endif /* BCMDHD_SDIO | BCMDHD_USB */ -#if defined(CONFIG_BCMDHD_VTS) || defined(CONFIG_BCMDHD_DEBUG) +#endif /* BCMSDIO | BCMDBUS */ +#ifdef DHD_USE_STATIC_MEMDUMP if (wlan_static_dhd_log_dump_buf[index]) kfree(wlan_static_dhd_log_dump_buf[index]); if (wlan_static_dhd_log_dump_buf_ex[index]) kfree(wlan_static_dhd_log_dump_buf_ex[index]); -#endif /* CONFIG_BCMDHD_VTS | CONFIG_BCMDHD_DEBUG */ +#endif /* DHD_USE_STATIC_MEMDUMP */ if (wlan_static_wl_escan_info_buf[index]) kfree(wlan_static_wl_escan_info_buf[index]); if (wlan_static_fw_verbose_ring_buf[index]) @@ -404,12 +413,12 @@ dhd_deinit_wlan_mem(int index) kfree(wlan_static_nan_event_ring_buf[index]); #endif /* BCMDHD_UNUSE_MEM */ -#if defined(BCMDHD_SDIO) || defined(BCMDHD_PCIE) - for (i=0; i 0 for (i = 0; i < DHD_SKB_1PAGE_BUF_NUM; i++) { wlan_static_skb[index][i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE); - if (!wlan_static_skb[index][i]) { + if (!wlan_static_skb[index][i]) goto err_mem_alloc; - } size += DHD_SKB_1PAGE_BUFSIZE; - DHD_STATIC_TRACE("sectoin %d skb[%d], size=%ld\n", + DHD_STATIC_TRACE("section %d skb[%d], size=%ld\n", DHD_PREALLOC_SKB_BUF, i, DHD_SKB_1PAGE_BUFSIZE); } - +#endif for (i = DHD_SKB_1PAGE_BUF_NUM; i < WLAN_SKB_1_2PAGE_BUF_NUM; i++) { wlan_static_skb[index][i] = dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE); - if (!wlan_static_skb[index][i]) { + if (!wlan_static_skb[index][i]) goto err_mem_alloc; - } size += DHD_SKB_2PAGE_BUFSIZE; - DHD_STATIC_TRACE("sectoin %d skb[%d], size=%ld\n", + DHD_STATIC_TRACE("section %d skb[%d], size=%ld\n", DHD_PREALLOC_SKB_BUF, i, DHD_SKB_2PAGE_BUFSIZE); } -#endif /* BCMDHD_SDIO | BCMDHD_PCIE */ +#endif /* BCMSDIO | BCMPCIE */ -#if defined(BCMDHD_SDIO) +#if defined(BCMSDIO) wlan_static_skb[index][i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE); if (!wlan_static_skb[index][i]) goto err_mem_alloc; size += DHD_SKB_4PAGE_BUFSIZE; - DHD_STATIC_TRACE("sectoin %d skb[%d], size=%ld\n", + DHD_STATIC_TRACE("section %d skb[%d], size=%ld\n", DHD_PREALLOC_SKB_BUF, i, DHD_SKB_4PAGE_BUFSIZE); -#endif /* BCMDHD_SDIO */ +#endif /* BCMSDIO */ wlan_static_prot[index] = kmalloc(DHD_PREALLOC_PROT_SIZE, GFP_KERNEL); if (!wlan_static_prot[index]) goto err_mem_alloc; size += DHD_PREALLOC_PROT_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_PROT, DHD_PREALLOC_PROT_SIZE); -#if defined(BCMDHD_SDIO) +#if defined(BCMSDIO) wlan_static_rxbuf[index] = kmalloc(DHD_PREALLOC_RXBUF_SIZE, GFP_KERNEL); if (!wlan_static_rxbuf[index]) goto err_mem_alloc; size += DHD_PREALLOC_RXBUF_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_RXBUF, DHD_PREALLOC_RXBUF_SIZE); wlan_static_databuf[index] = kmalloc(DHD_PREALLOC_DATABUF_SIZE, GFP_KERNEL); if (!wlan_static_databuf[index]) goto err_mem_alloc; size += DHD_PREALLOC_DATABUF_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_DATABUF, DHD_PREALLOC_DATABUF_SIZE); -#endif /* BCMDHD_SDIO */ +#endif /* BCMSDIO */ wlan_static_osl_buf[index] = kmalloc(DHD_PREALLOC_OSL_BUF_SIZE, GFP_KERNEL); if (!wlan_static_osl_buf[index]) goto err_mem_alloc; size += DHD_PREALLOC_OSL_BUF_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%ld\n", + DHD_STATIC_TRACE("section %d, size=%ld\n", DHD_PREALLOC_OSL_BUF, DHD_PREALLOC_OSL_BUF_SIZE); wlan_static_scan_buf0[index] = kmalloc(DHD_PREALLOC_WIPHY_ESCAN0_SIZE, GFP_KERNEL); if (!wlan_static_scan_buf0[index]) goto err_mem_alloc; size += DHD_PREALLOC_WIPHY_ESCAN0_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_WIPHY_ESCAN0, DHD_PREALLOC_WIPHY_ESCAN0_SIZE); wlan_static_dhd_info_buf[index] = kmalloc(DHD_PREALLOC_DHD_INFO_SIZE, GFP_KERNEL); if (!wlan_static_dhd_info_buf[index]) goto err_mem_alloc; size += DHD_PREALLOC_DHD_INFO_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_DHD_INFO, DHD_PREALLOC_DHD_INFO_SIZE); -#if defined(BCMDHD_SDIO) || defined(BCMDHD_USB) +#if defined(BCMSDIO) || defined(BCMDBUS) wlan_static_dhd_wlfc_info_buf[index] = kmalloc(WLAN_DHD_WLFC_BUF_SIZE, GFP_KERNEL); if (!wlan_static_dhd_wlfc_info_buf[index]) goto err_mem_alloc; size += WLAN_DHD_WLFC_BUF_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_DHD_WLFC_INFO, WLAN_DHD_WLFC_BUF_SIZE); -#endif /* BCMDHD_SDIO | BCMDHD_USB */ +#endif /* BCMSDIO | BCMDBUS */ -#ifdef BCMDHD_PCIE +#ifdef BCMPCIE wlan_static_if_flow_lkup[index] = kmalloc(DHD_PREALLOC_IF_FLOW_LKUP_SIZE, GFP_KERNEL); if (!wlan_static_if_flow_lkup[index]) goto err_mem_alloc; size += DHD_PREALLOC_IF_FLOW_LKUP_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_IF_FLOW_LKUP, DHD_PREALLOC_IF_FLOW_LKUP_SIZE); -#endif /* BCMDHD_PCIE */ +#endif /* BCMPCIE */ -#if defined(CONFIG_BCMDHD_VTS) || defined(CONFIG_BCMDHD_DEBUG) +#if defined(DHD_USE_STATIC_MEMDUMP) || defined(BCMDBUS) wlan_static_dhd_memdump_ram_buf[index] = kmalloc(DHD_PREALLOC_MEMDUMP_RAM_SIZE, GFP_KERNEL); if (!wlan_static_dhd_memdump_ram_buf[index]) goto err_mem_alloc; size += DHD_PREALLOC_MEMDUMP_RAM_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_MEMDUMP_RAM, DHD_PREALLOC_MEMDUMP_RAM_SIZE); -#endif /* CONFIG_BCMDHD_VTS | CONFIG_BCMDHD_DEBUG */ +#endif /* DHD_USE_STATIC_MEMDUMP | BCMDBUS */ -#if defined(BCMDHD_SDIO) || defined(BCMDHD_USB) +#if defined(BCMSDIO) || defined(BCMDBUS) wlan_static_dhd_wlfc_hanger_buf[index] = kmalloc(DHD_PREALLOC_DHD_WLFC_HANGER_SIZE, GFP_KERNEL); if (!wlan_static_dhd_wlfc_hanger_buf[index]) goto err_mem_alloc; size += DHD_PREALLOC_DHD_WLFC_HANGER_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_DHD_WLFC_HANGER, DHD_PREALLOC_DHD_WLFC_HANGER_SIZE); -#endif /* BCMDHD_SDIO | BCMDHD_USB */ +#endif /* BCMSDIO | BCMDBUS */ -#if defined(CONFIG_BCMDHD_VTS) || defined(CONFIG_BCMDHD_DEBUG) +#ifdef DHD_USE_STATIC_MEMDUMP wlan_static_dhd_log_dump_buf[index] = kmalloc(DHD_PREALLOC_DHD_LOG_DUMP_BUF_SIZE, GFP_KERNEL); if (!wlan_static_dhd_log_dump_buf[index]) goto err_mem_alloc; size += DHD_PREALLOC_DHD_LOG_DUMP_BUF_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_DHD_LOG_DUMP_BUF, DHD_PREALLOC_DHD_LOG_DUMP_BUF_SIZE); wlan_static_dhd_log_dump_buf_ex[index] = kmalloc(DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX_SIZE, GFP_KERNEL); if (!wlan_static_dhd_log_dump_buf_ex[index]) goto err_mem_alloc; size += DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX, DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX_SIZE); -#endif /* CONFIG_BCMDHD_VTS | CONFIG_BCMDHD_DEBUG */ +#endif /* DHD_USE_STATIC_MEMDUMP */ wlan_static_wl_escan_info_buf[index] = kmalloc(DHD_PREALLOC_WL_ESCAN_SIZE, GFP_KERNEL); if (!wlan_static_wl_escan_info_buf[index]) goto err_mem_alloc; size += DHD_PREALLOC_WL_ESCAN_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_WL_ESCAN, DHD_PREALLOC_WL_ESCAN_SIZE); wlan_static_fw_verbose_ring_buf[index] = kmalloc(FW_VERBOSE_RING_SIZE, GFP_KERNEL); if (!wlan_static_fw_verbose_ring_buf[index]) goto err_mem_alloc; size += FW_VERBOSE_RING_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_FW_VERBOSE_RING, FW_VERBOSE_RING_SIZE); wlan_static_fw_event_ring_buf[index] = kmalloc(FW_EVENT_RING_SIZE, GFP_KERNEL); if (!wlan_static_fw_event_ring_buf[index]) goto err_mem_alloc; size += FW_EVENT_RING_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_FW_EVENT_RING, FW_EVENT_RING_SIZE); wlan_static_dhd_event_ring_buf[index] = kmalloc(DHD_EVENT_RING_SIZE, GFP_KERNEL); if (!wlan_static_dhd_event_ring_buf[index]) goto err_mem_alloc; size += DHD_EVENT_RING_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_DHD_EVENT_RING, DHD_EVENT_RING_SIZE); #if defined(BCMDHD_UNUSE_MEM) @@ -586,11 +592,11 @@ dhd_init_wlan_mem(int index) if (!wlan_static_nan_event_ring_buf[index]) goto err_mem_alloc; size += NAN_EVENT_RING_SIZE; - DHD_STATIC_TRACE("sectoin %d, size=%d\n", + DHD_STATIC_TRACE("section %d, size=%d\n", DHD_PREALLOC_NAN_EVENT_RING, NAN_EVENT_RING_SIZE); #endif /* BCMDHD_UNUSE_MEM */ - DHD_STATIC_MSG("prealloc ok for index %d: %ld(%ldK)\n", index, size, size/1024); + DHD_STATIC_MSG("prealloc ok for index %d: %ld(%ldK)\n", index, size, size / 1024); return 0; err_mem_alloc: @@ -608,18 +614,20 @@ dhd_static_buf_init(void) { int i, ret = 0; - DHD_STATIC_MSG("%s\n", DHD_STATIC_VERSION_STR); + DHD_STATIC_MSG("%s\n", DHD_STATIC_VERSION_STR); - for (i=0; its_tz; rem_usec = DIV_AND_MOD_U64_BY_U32(ts_sec, USEC_PER_SEC); - rtc_time_to_tm((unsigned long)ts_sec, &tm); + rtc_time_to_tm(ts_sec, &tm); snprintf(buf, buflen, DHD_STATLOG_TZFMT_YYMMDDHHMMSSMS, tm.tm_year - 100, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_statlog.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_statlog.h old mode 100755 new mode 100644 index c6dc5cf5beb9..04e7340fef8f --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_statlog.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_statlog.h @@ -1,7 +1,7 @@ /* * DHD debugability: Header file for the Status Information Logging * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_timesync.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_timesync.c deleted file mode 100755 index 618d234a18c1..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_timesync.c +++ /dev/null @@ -1,1239 +0,0 @@ -/** - * @file Broadcom Dongle Host Driver (DHD), time sync protocol handler - * - * timesync mesasages are exchanged between the host and device to synchronize the source time - * for ingress and egress packets. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$: - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void dhd_msgbuf_delay_post_ts_bufs(dhd_pub_t *dhd); - -#define MAX_FW_CLKINFO_TYPES 8 -#define MAX_SIZE_FW_CLKINFO_TYPE (MAX_FW_CLKINFO_TYPES * sizeof(ts_fw_clock_info_t)) - -#define MAX_FW_TS_LOG_SAMPLES 64 - -#define BCMMSGBUF_HOST_TS_BADTAG 0xF0 - -#define DHD_DEFAULT_TIMESYNC_TIMER_VALUE 20 /* ms */ -#define DHD_DEFAULT_TIMESYNC_TIMER_VALUE_MAX 9000 /* ms */ - -#define MAX_TS_LOG_SAMPLES_DATA 128 -#define TS_NODROP_CONFIG_TO 1 -#define TS_DROP_CONFIG_TO 5 - -typedef struct clksrc_ts_log { - uchar name[4]; - uint32 inuse; - ts_timestamp_srcid_t log[MAX_FW_TS_LOG_SAMPLES]; -} clksrc_ts_log_t; - -typedef struct clk_ts_log { - uint32 clk_ts_inited; - uint32 cur_idx; - uint32 seqnum[MAX_FW_TS_LOG_SAMPLES]; - clksrc_ts_log_t ts_log[MAX_CLKSRC_ID+1]; -} clk_ts_log_t; - -typedef struct dhd_ts_xt_id { - uint16 host_timestamping_config; - uint16 host_clock_selection; - uint16 host_clk_info; - uint16 d2h_clk_correction; -} dhd_ts_xt_id_t; - -typedef struct dhd_ts_log_ts_item { - uint16 flowid; /* interface, Flow ID */ - uint8 intf; /* interface */ - uint8 rsvd; - uint32 ts_low; /* time stamp values */ - uint32 ts_high; /* time stamp values */ - uint32 proto; - uint32 t1; - uint32 t2; -} dhd_ts_log_ts_item_t; - -typedef struct dhd_ts_log_ts { - uint32 max_idx; - uint32 cur_idx; - dhd_ts_log_ts_item_t ts_log[MAX_TS_LOG_SAMPLES_DATA]; -} dhd_ts_log_ts_t; - -#define MAX_BUF_SIZE_HOST_CLOCK_INFO 512 - -#define HOST_TS_CONFIG_FW_TIMESTAMP_PERIOD_DEFAULT 1000 - -struct dhd_ts { - dhd_pub_t *dhdp; - osl_t *osh; - uint32 xt_id; - uint16 host_ts_capture_cnt; - uint32 fw_ts_capture_cnt; - uint32 fw_ts_disc_cnt; - uint32 h_clkid_min; - uint32 h_clkid_max; - uint32 h_tsconf_period; - - /* sould these be per clock source */ - ts_correction_m_t correction_m; - ts_correction_m_t correction_b; - - ts_fw_clock_info_t fw_tlv[MAX_FW_CLKINFO_TYPES]; - uint32 fw_tlv_len; - clk_ts_log_t fw_ts_log; - uchar host_ts_host_clk_info_buffer[MAX_BUF_SIZE_HOST_CLOCK_INFO]; - bool host_ts_host_clk_info_buffer_in_use; - dhd_ts_xt_id_t xt_ids; - uint32 active_ipc_version; - - uint32 fwts2hsts_delay; - uint32 fwts2hsts_delay_wdcount; - uint32 ts_watchdog_calls; - uint64 last_ts_watchdog_time; - uint32 pending_requests; - - dhd_ts_log_ts_t tx_timestamps; - dhd_ts_log_ts_t rx_timestamps; - /* outside modules could stop timesync independent of the user config */ - bool timesync_disabled; - uint32 host_reset_cnt; - bool nodrop_config; - - uint32 suspend_req; - uint32 resume_req; -}; -struct dhd_ts *g_dhd_ts; -static uint32 dhd_timesync_send_D2H_clk_correction(dhd_ts_t *ts); -static uint32 dhd_timesync_send_host_clk_info(dhd_ts_t *ts); -static uint32 dhd_timesync_send_host_clock_selection(dhd_ts_t *ts); -static uint32 dhd_timesync_send_host_timestamping_config(dhd_ts_t *ts, bool inject_err); -static void dhd_timesync_ts_log_dump_item(dhd_ts_log_ts_t *tsl, struct bcmstrbuf *b); - -/* Check for and handle local prot-specific iovar commands */ - -enum { - IOV_TS_INFO_DUMP, - IOV_TS_TX_TS_DUMP, - IOV_TS_RX_TS_DUMP, - IOV_TS_FW_CLKINFO_DUMP, - IOV_TS_HCLK_CLKID_MIN, - IOV_TS_HCLK_CLKID_MAX, - IOV_TS_HTSCONF_PERIOD, - IOV_TS_SEND_TSCONFIG, - IOV_TS_SEND_HCLK_SEL, - IOV_TS_SEND_HCLK_INFO, - IOV_TS_SEND_D2H_CRCT, - IOV_TS_TXS_LOG, - IOV_TS_RXS_LOG, - IOV_TS_INJECT_BAD_XTID, - IOV_TS_INJECT_BAD_TAG, - IOV_TS_FWTS2HSTS_DELAY, - IOV_TS_NODROP_CONFIG, - IOV_TS_CLEAR_LOGS, - IOV_TS_NO_RETRY, - IOV_TS_NO_AGGR, - IOV_TS_FIXED_RATE, - IOV_LAST -}; -const bcm_iovar_t dhd_ts_iovars[] = { - {"ts_info_dump", IOV_TS_INFO_DUMP, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, - {"ts_tx_ts_dump", IOV_TS_TX_TS_DUMP, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, - {"ts_rx_ts_dump", IOV_TS_RX_TS_DUMP, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, - {"ts_fw_clkinfo_dump", IOV_TS_FW_CLKINFO_DUMP, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, - {"ts_hclk_clkid_min", IOV_TS_HCLK_CLKID_MIN, 0, 0, IOVT_UINT32, 0 }, - {"ts_hclk_clkid_max", IOV_TS_HCLK_CLKID_MAX, 0, 0, IOVT_UINT32, 0 }, - {"ts_htsconf_period", IOV_TS_HTSCONF_PERIOD, 0, 0, IOVT_UINT32, 0 }, - {"ts_send_tsconfig", IOV_TS_SEND_TSCONFIG, 0, 0, IOVT_UINT32, 0 }, - {"ts_send_hostclk_sel", IOV_TS_SEND_HCLK_SEL, 0, 0, IOVT_UINT32, 0 }, - {"ts_send_hostclk_info", IOV_TS_SEND_HCLK_INFO, 0, 0, IOVT_UINT32, 0 }, - {"ts_send_d2h_corect ", IOV_TS_SEND_D2H_CRCT, 0, 0, IOVT_UINT32, 0 }, - {"ts_txs_log", IOV_TS_TXS_LOG, 0, 0, IOVT_UINT32, 0 }, - {"ts_rxs_log", IOV_TS_RXS_LOG, 0, 0, IOVT_UINT32, 0 }, - - /* error injection cases */ - {"ts_inject_bad_xtid", IOV_TS_INJECT_BAD_XTID, 0, 0, IOVT_UINT32, 0 }, - {"ts_inject_bad_tag", IOV_TS_INJECT_BAD_TAG, 0, 0, IOVT_UINT32, 0 }, - {"ts_fwts2hsts_delay", IOV_TS_FWTS2HSTS_DELAY, 0, 0, IOVT_UINT32, 0 }, - {"ts_nodrop_config", IOV_TS_NODROP_CONFIG, 0, 0, IOVT_UINT32, 0 }, - {"ts_clear_logs", IOV_TS_CLEAR_LOGS, 0, 0, IOVT_UINT32, 0 }, - {"ts_set_no_retry", IOV_TS_NO_RETRY, 0, 0, IOVT_UINT32, 0 }, - {"ts_set_no_aggr", IOV_TS_NO_AGGR, 0, 0, IOVT_UINT32, 0 }, - {"ts_set_fixed_rate", IOV_TS_FIXED_RATE, 0, 0, IOVT_UINT32, 0 }, - - {NULL, 0, 0, 0, 0, 0 } -}; - -static int dhd_ts_fw_clksrc_dump(dhd_ts_t *ts, char *buf, int buflen); -#ifdef CONFIG_PROC_FS -static int dhd_open_proc_ts_fw_clk_dump(struct inode *inode, struct file *file); -ssize_t dhd_read_proc_ts_fw_clk_dump(struct file *file, char *user_buf, size_t count, loff_t *loff); -static int dhd_open_proc_ts_tx_dump(struct inode *inode, struct file *file); -ssize_t dhd_read_proc_ts_tx_dump(struct file *file, char *user_buf, size_t count, loff_t *loff); -static int dhd_open_proc_ts_rx_dump(struct inode *inode, struct file *file); -ssize_t dhd_read_proc_ts_rx_dump(struct file *file, char *user_buf, size_t count, loff_t *loff); - -static int -dhd_open_proc_ts_fw_clk_dump(struct inode *inode, struct file *file) -{ - return single_open(file, 0, NULL); -} -ssize_t -dhd_read_proc_ts_fw_clk_dump(struct file *file, char *user_buf, size_t count, loff_t *loff) -{ - dhd_ts_t *ts; - char *buf; - ssize_t ret = 0; - - ts = g_dhd_ts; - if (ts == NULL) { - return -EAGAIN; - } - if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(ts->dhdp)) { - DHD_INFO(("%s bus is in suspend or suspend in progress\n", __func__)); - return -EAGAIN; - } - if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(ts->dhdp)) { - DHD_ERROR(("%s rmmod in progress\n", __func__)); - return -ENOENT; - } - buf = kmalloc(count, GFP_KERNEL); - if (buf == NULL) { - DHD_ERROR(("%s failed to allocate buf with size %zu\n", __func__, count)); - return -ENOMEM; - } - ret = dhd_ts_fw_clksrc_dump(ts, buf, count); - if (ret < 0) { - return 0; - } - ret = simple_read_from_buffer(user_buf, count, loff, buf, (count - ret)); - kfree(buf); - return ret; -} -static int dhd_open_proc_ts_tx_dump(struct inode *inode, struct file *file) -{ - return single_open(file, 0, NULL); -} -ssize_t -dhd_read_proc_ts_tx_dump(struct file *file, char *user_buf, size_t count, loff_t *loff) -{ - dhd_ts_t *ts; - char *buf; - ssize_t ret = 0; - struct bcmstrbuf strbuf; - - ts = g_dhd_ts; - if (ts == NULL) { - return -EAGAIN; - } - if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(ts->dhdp)) { - DHD_INFO(("%s bus is in suspend or suspend in progress\n", __func__)); - return -EAGAIN; - } - if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(ts->dhdp)) { - DHD_ERROR(("%s rmmod in progress\n", __func__)); - return -ENOENT; - } - buf = kmalloc(count, GFP_KERNEL); - if (buf == NULL) { - DHD_ERROR(("%s failed to allocate buf with size %zu\n", __func__, count)); - return -ENOMEM; - } - bcm_binit(&strbuf, buf, count); - bcm_bprintf(&strbuf, "Tx Log dump\n"); - dhd_timesync_ts_log_dump_item(&ts->tx_timestamps, &strbuf); - ret = simple_read_from_buffer(user_buf, count, loff, buf, (count - strbuf.size)); - kfree(buf); - return ret; -} - -static int dhd_open_proc_ts_rx_dump(struct inode *inode, struct file *file) -{ - return single_open(file, 0, NULL); -} - -ssize_t -dhd_read_proc_ts_rx_dump(struct file *file, char *user_buf, size_t count, loff_t *loff) -{ - dhd_ts_t *ts; - char *buf; - ssize_t ret = 0; - struct bcmstrbuf strbuf; - - ts = g_dhd_ts; - if (ts == NULL) { - return -EAGAIN; - } - if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(ts->dhdp)) { - DHD_INFO(("%s bus is in suspend or suspend in progress\n", __func__)); - return -EAGAIN; - } - if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(ts->dhdp)) { - DHD_ERROR(("%s rmmod in progress\n", __func__)); - return -ENOENT; - } - buf = kmalloc(count, GFP_KERNEL); - if (buf == NULL) { - DHD_ERROR(("%s failed to allocate buf with size %zu\n", __func__, count)); - return -ENOMEM; - } - bcm_binit(&strbuf, buf, count); - bcm_bprintf(&strbuf, "Rx Log dump\n"); - dhd_timesync_ts_log_dump_item(&ts->rx_timestamps, &strbuf); - ret = simple_read_from_buffer(user_buf, count, loff, buf, (count - strbuf.size)); - kfree(buf); - return ret; -} - -static const struct file_operations proc_fops_ts_fw_clk_dump = { - .read = dhd_read_proc_ts_fw_clk_dump, - .open = dhd_open_proc_ts_fw_clk_dump, - .release = seq_release, -}; -static const struct file_operations proc_fops_ts_tx_dump = { - .read = dhd_read_proc_ts_tx_dump, - .open = dhd_open_proc_ts_tx_dump, - .release = seq_release, -}; -static const struct file_operations proc_fops_ts_rx_dump = { - .read = dhd_read_proc_ts_rx_dump, - .open = dhd_open_proc_ts_rx_dump, - .release = seq_release, -}; -#endif /* CONFIG_PROC_FS */ - -int -dhd_timesync_detach(dhd_pub_t *dhdp) -{ - dhd_ts_t *ts; - - DHD_TRACE(("%s: %d\n", __FUNCTION__, __LINE__)); - - if (!dhdp) { - return BCME_OK; - } - ts = dhdp->ts; -#ifdef CONFIG_PROC_FS - remove_proc_entry("ts_fw_clk_dump", NULL); - remove_proc_entry("ts_tx_dump", NULL); - remove_proc_entry("ts_rx_dump", NULL); -#endif /* CONFIG_PROC_FS */ -#ifndef CONFIG_DHD_USE_STATIC_BUF - MFREE(dhdp->osh, ts, sizeof(dhd_ts_t)); -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - g_dhd_ts = NULL; - dhdp->ts = NULL; - DHD_INFO(("Deallocated DHD TS\n")); - return BCME_OK; -} -int -dhd_timesync_attach(dhd_pub_t *dhdp) -{ - dhd_ts_t *ts; - - DHD_TRACE(("%s: %d\n", __FUNCTION__, __LINE__)); - /* Allocate prot structure */ - if (!(ts = (dhd_ts_t *)DHD_OS_PREALLOC(dhdp, DHD_PREALLOC_PROT, - sizeof(dhd_ts_t)))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - goto fail; - } - memset(ts, 0, sizeof(*ts)); - - g_dhd_ts = ts; - ts->osh = dhdp->osh; - dhdp->ts = ts; - ts->dhdp = dhdp; - - ts->correction_m.low = 1; - ts->correction_m.high = 1; - - ts->correction_b.low = 0; - ts->correction_m.high = 0; - - ts->fwts2hsts_delay = DHD_DEFAULT_TIMESYNC_TIMER_VALUE; - ts->fwts2hsts_delay_wdcount = 0; - - ts->tx_timestamps.max_idx = MAX_TS_LOG_SAMPLES_DATA; - ts->rx_timestamps.max_idx = MAX_TS_LOG_SAMPLES_DATA; - - ts->xt_id = 1; - - DHD_INFO(("allocated DHD TS\n")); - -#ifdef CONFIG_PROC_FS - if (proc_create("ts_fw_clk_dump", S_IRUSR, NULL, &proc_fops_ts_fw_clk_dump) == NULL) { - DHD_ERROR(("Failed to create /proc/ts_fw_clk_dump procfs interface\n")); - } - if (proc_create("ts_tx_dump", S_IRUSR, NULL, &proc_fops_ts_tx_dump) == NULL) { - DHD_ERROR(("Failed to create /proc/ts_tx_dump procfs interface\n")); - } - if (proc_create("ts_rx_dump", S_IRUSR, NULL, &proc_fops_ts_rx_dump) == NULL) { - DHD_ERROR(("Failed to create /proc/ts_rx_dump procfs interface\n")); - } -#endif /* CONFIG_PROC_FS */ - - return BCME_OK; - -fail: - if (dhdp->ts != NULL) { - dhd_timesync_detach(dhdp); - } - return BCME_NOMEM; -} - -static void -dhd_timesync_ts_log_dump_item(dhd_ts_log_ts_t *tsl, struct bcmstrbuf *b) -{ - uint32 i = 0; - - bcm_bprintf(b, "Max_idx: %d, cur_idx %d\n", tsl->max_idx, tsl->cur_idx); - for (i = 0; i < tsl->max_idx; i++) { - bcm_bprintf(b, "\t idx: %03d, (%d: %d) timestamp: 0x%08x:0x%08x " - " proto: %02d, t1: 0x%08x t2: 0x%08x\n", - i, tsl->ts_log[i].intf, tsl->ts_log[i].flowid, - tsl->ts_log[i].ts_high, tsl->ts_log[i].ts_low, - tsl->ts_log[i].proto, tsl->ts_log[i].t1, - tsl->ts_log[i].t2); - } -} - -static int -dhd_timesync_ts_log_dump(dhd_ts_t *ts, char *buf, int buflen, bool tx) -{ - struct bcmstrbuf b; - struct bcmstrbuf *strbuf = &b; - - bcm_binit(strbuf, buf, buflen); - - if (tx) { - bcm_bprintf(strbuf, "Tx Log dump\t"); - dhd_timesync_ts_log_dump_item(&ts->tx_timestamps, strbuf); - } - else { - bcm_bprintf(strbuf, "Rx Log dump\n"); - dhd_timesync_ts_log_dump_item(&ts->rx_timestamps, strbuf); - } - return BCME_OK; -} - -static void -dhd_timesync_clear_logs(dhd_ts_t *ts) -{ - dhd_ts_log_ts_t *tsl; - - tsl = &ts->rx_timestamps; - tsl->cur_idx = 0; - memset(tsl->ts_log, 0, sizeof(dhd_ts_log_ts_item_t) * - MAX_TS_LOG_SAMPLES_DATA); - - tsl = &ts->tx_timestamps; - tsl->cur_idx = 0; - memset(tsl->ts_log, 0, sizeof(dhd_ts_log_ts_item_t) * - MAX_TS_LOG_SAMPLES_DATA); - - return; -} - -void -dhd_timesync_debug_info_print(dhd_pub_t *dhdp) -{ - dhd_ts_t *ts = dhdp->ts; - uint64 current_time; - - if (!ts) { - DHD_ERROR(("%s: %d ts is NULL\n", __FUNCTION__, __LINE__)); - return; - } - - DHD_ERROR(("\nts info dump: active_ipc_version %d\n", ts->active_ipc_version)); - current_time = OSL_LOCALTIME_NS(); - DHD_ERROR(("current_time="SEC_USEC_FMT" last_ts_watchdog_time="SEC_USEC_FMT"\n", - GET_SEC_USEC(current_time), GET_SEC_USEC(ts->last_ts_watchdog_time))); - DHD_ERROR(("timesync disabled %d\n", ts->timesync_disabled)); - DHD_ERROR(("Host TS dump cnt %d, fw TS dump cnt %d, descrepency %d\n", - ts->host_ts_capture_cnt, ts->fw_ts_capture_cnt, ts->fw_ts_disc_cnt)); - DHD_ERROR(("ts_watchdog calls %d reset cnt %d\n", - ts->ts_watchdog_calls, ts->host_reset_cnt)); - DHD_ERROR(("xt_ids tag/ID %d/%d, %d/%d, %d/%d, %d/%d\n", - BCMMSGBUF_HOST_TIMESTAMPING_CONFIG_TAG, ts->xt_ids.host_timestamping_config, - BCMMSGBUF_HOST_CLOCK_SELECT_TAG, ts->xt_ids.host_clock_selection, - BCMMSGBUF_HOST_CLOCK_INFO_TAG, ts->xt_ids.host_clk_info, - BCMMSGBUF_D2H_CLOCK_CORRECTION_TAG, ts->xt_ids.d2h_clk_correction)); - DHD_ERROR(("pending requests %d suspend req %d resume req %d\n", - ts->pending_requests, ts->suspend_req, ts->resume_req)); - -} - -static int -dhd_timesync_dump(dhd_ts_t *ts, char *buf, int buflen) -{ - struct bcmstrbuf b; - struct bcmstrbuf *strbuf = &b; - - bcm_binit(strbuf, buf, buflen); - - bcm_bprintf(strbuf, "ts info dump: active_ipc_version %d\n", ts->active_ipc_version); - bcm_bprintf(strbuf, "timesync disabled %d\n", ts->timesync_disabled); - bcm_bprintf(strbuf, "Host TS dump cnt %d, fw TS dump cnt %d, descrepency %d\n", - ts->host_ts_capture_cnt, ts->fw_ts_capture_cnt, ts->fw_ts_disc_cnt); - bcm_bprintf(strbuf, "ts_watchdog calls %d reset cnt %d\n", - ts->ts_watchdog_calls, ts->host_reset_cnt); - bcm_bprintf(strbuf, "xt_ids tag/ID %d/%d, %d/%d, %d/%d, %d/%d\n", - BCMMSGBUF_HOST_TIMESTAMPING_CONFIG_TAG, ts->xt_ids.host_timestamping_config, - BCMMSGBUF_HOST_CLOCK_SELECT_TAG, ts->xt_ids.host_clock_selection, - BCMMSGBUF_HOST_CLOCK_INFO_TAG, ts->xt_ids.host_clk_info, - BCMMSGBUF_D2H_CLOCK_CORRECTION_TAG, ts->xt_ids.d2h_clk_correction); - bcm_bprintf(strbuf, "pending requests %d suspend req %d resume req %d\n", - ts->pending_requests, ts->suspend_req, ts->resume_req); - - return BCME_OK; -} - -static int -dhd_timesync_doiovar(dhd_ts_t *ts, const bcm_iovar_t *vi, uint32 actionid, const char *name, - void *params, uint plen, void *arg, uint len, int val_size) -{ - int bcmerror = 0; - int32 int_val = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name)); - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) - goto exit; - - if (plen >= sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - switch (actionid) { - case IOV_GVAL(IOV_TS_INFO_DUMP): - dhd_timesync_dump(ts, arg, len); - break; - case IOV_GVAL(IOV_TS_TX_TS_DUMP): - dhd_timesync_ts_log_dump(ts, arg, len, TRUE); - break; - case IOV_GVAL(IOV_TS_RX_TS_DUMP): - dhd_timesync_ts_log_dump(ts, arg, len, FALSE); - break; - case IOV_GVAL(IOV_TS_FW_CLKINFO_DUMP): - dhd_ts_fw_clksrc_dump(ts, arg, len); - break; - case IOV_SVAL(IOV_TS_SEND_TSCONFIG): - if (ts->active_ipc_version < 7) { - bcmerror = BCME_ERROR; - break; - } - bcmerror = dhd_timesync_send_host_timestamping_config(ts, FALSE); - break; - case IOV_SVAL(IOV_TS_SEND_HCLK_SEL): - if (ts->active_ipc_version < 7) { - bcmerror = BCME_ERROR; - break; - } - bcmerror = dhd_timesync_send_host_clock_selection(ts); - break; - case IOV_SVAL(IOV_TS_SEND_HCLK_INFO): - if (ts->active_ipc_version < 7) { - bcmerror = BCME_ERROR; - break; - } - bcmerror = dhd_timesync_send_host_clk_info(ts); - break; - case IOV_SVAL(IOV_TS_SEND_D2H_CRCT): - if (ts->active_ipc_version < 7) { - bcmerror = BCME_ERROR; - break; - } - bcmerror = dhd_timesync_send_D2H_clk_correction(ts); - break; - case IOV_SVAL(IOV_TS_INJECT_BAD_TAG): - if (ts->active_ipc_version < 7) { - bcmerror = BCME_ERROR; - break; - } - bcmerror = dhd_timesync_send_host_timestamping_config(ts, TRUE); - break; - case IOV_SVAL(IOV_TS_INJECT_BAD_XTID): { - uint16 old_xt_id; - - if (ts->active_ipc_version < 7) { - bcmerror = BCME_ERROR; - break; - } - old_xt_id = ts->xt_id; - ts->xt_id += 10; /* will cause the error now */ - DHD_ERROR(("generating bad XTID transaction for the device exp %d, sending %d", - old_xt_id, ts->xt_id)); - bcmerror = dhd_timesync_send_host_timestamping_config(ts, FALSE); - ts->xt_id = old_xt_id; - break; - } - case IOV_GVAL(IOV_TS_FWTS2HSTS_DELAY): - bcopy(&ts->fwts2hsts_delay, arg, val_size); - break; - case IOV_SVAL(IOV_TS_FWTS2HSTS_DELAY): - if (ts->active_ipc_version < 7) { - bcmerror = BCME_ERROR; - break; - } - if (int_val > DHD_DEFAULT_TIMESYNC_TIMER_VALUE_MAX) { - bcmerror = BCME_RANGE; - break; - } - if (int_val <= DHD_DEFAULT_TIMESYNC_TIMER_VALUE) { - bcmerror = BCME_RANGE; - break; - } - ts->fwts2hsts_delay = int_val; - break; - case IOV_GVAL(IOV_TS_NODROP_CONFIG): - bcopy(&ts->nodrop_config, arg, val_size); - break; - case IOV_SVAL(IOV_TS_NODROP_CONFIG): - ts->nodrop_config = int_val; - break; - case IOV_GVAL(IOV_TS_NO_RETRY): - int_val = dhd_prot_pkt_noretry(ts->dhdp, 0, FALSE); - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_TS_NO_RETRY): - dhd_prot_pkt_noretry(ts->dhdp, int_val, TRUE); - break; - case IOV_GVAL(IOV_TS_NO_AGGR): - int_val = dhd_prot_pkt_noaggr(ts->dhdp, 0, FALSE); - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_TS_NO_AGGR): - dhd_prot_pkt_noaggr(ts->dhdp, int_val, TRUE); - break; - case IOV_GVAL(IOV_TS_FIXED_RATE): - int_val = dhd_prot_pkt_fixed_rate(ts->dhdp, 0, FALSE); - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_TS_FIXED_RATE): - dhd_prot_pkt_fixed_rate(ts->dhdp, int_val, TRUE); - break; - case IOV_SVAL(IOV_TS_CLEAR_LOGS): - dhd_timesync_clear_logs(ts); - break; - case IOV_GVAL(IOV_TS_TXS_LOG): - int_val = dhd_prot_data_path_tx_timestamp_logging(ts->dhdp, 0, FALSE); - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_TS_TXS_LOG): - dhd_prot_data_path_tx_timestamp_logging(ts->dhdp, int_val, TRUE); - break; - case IOV_GVAL(IOV_TS_RXS_LOG): - int_val = dhd_prot_data_path_rx_timestamp_logging(ts->dhdp, 0, FALSE); - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_TS_RXS_LOG): - dhd_prot_data_path_rx_timestamp_logging(ts->dhdp, int_val, TRUE); - break; - case IOV_SVAL(IOV_TS_HTSCONF_PERIOD): - if (ts->active_ipc_version < 7) { - bcmerror = BCME_ERROR; - break; - } - ts->h_tsconf_period = int_val; - break; - case IOV_GVAL(IOV_TS_HTSCONF_PERIOD): - if (ts->active_ipc_version < 7) { - bcmerror = BCME_ERROR; - break; - } - bcopy(&ts->h_tsconf_period, arg, val_size); - break; - case IOV_SVAL(IOV_TS_HCLK_CLKID_MAX): - if (ts->active_ipc_version < 7) { - bcmerror = BCME_ERROR; - break; - } - ts->h_clkid_max = int_val; - break; - case IOV_GVAL(IOV_TS_HCLK_CLKID_MAX): - if (ts->active_ipc_version < 7) { - bcmerror = BCME_ERROR; - break; - } - bcopy(&ts->h_clkid_max, arg, val_size); - break; - - case IOV_SVAL(IOV_TS_HCLK_CLKID_MIN): - if (ts->active_ipc_version < 7) { - bcmerror = BCME_ERROR; - break; - } - ts->h_clkid_min = int_val; - break; - case IOV_GVAL(IOV_TS_HCLK_CLKID_MIN): - if (ts->active_ipc_version < 7) { - bcmerror = BCME_ERROR; - break; - } - bcopy(&ts->h_clkid_min, arg, val_size); - break; - default: - bcmerror = BCME_UNSUPPORTED; - break; - } -exit: - DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror)); - return bcmerror; -} - -int -dhd_timesync_iovar_op(dhd_ts_t *ts, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - int bcmerror = 0; - int val_size; - const bcm_iovar_t *vi = NULL; - uint32 actionid; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(name); - ASSERT(len >= 0); - - /* Get MUST have return space */ - ASSERT(set || (arg && len)); - - /* Set does NOT take qualifiers */ - ASSERT(!set || (!params && !plen)); - - if ((vi = bcm_iovar_lookup(dhd_ts_iovars, name)) == NULL) { - DHD_TRACE(("%s: not ours\n", name)); - bcmerror = BCME_UNSUPPORTED; - goto exit; - } - - DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, - name, (set ? "set" : "get"), len, plen)); - - /* set up 'params' pointer in case this is a set command so that - * the convenience int and bool code can be common to set and get - */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - /* all other types are integer sized */ - val_size = sizeof(int); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - - bcmerror = dhd_timesync_doiovar(ts, vi, actionid, name, params, plen, arg, len, val_size); - -exit: - return bcmerror; -} - -void -dhd_timesync_handle_host_ts_complete(dhd_ts_t *ts, uint16 xt_id, uint16 status) -{ - if (ts == NULL) { - DHD_ERROR(("%s: called with ts null\n", __FUNCTION__)); - return; - } - DHD_INFO(("Host send TS complete, for ID %d, status %d\n", xt_id, status)); - if (xt_id == ts->xt_ids.host_clk_info) { - if (ts->host_ts_host_clk_info_buffer_in_use != TRUE) { - DHD_ERROR(("same ID as the host clock info, but buffer not in use: %d\n", - ts->xt_ids.host_clk_info)); - return; - } - ts->host_ts_host_clk_info_buffer_in_use = FALSE; - } - ts->pending_requests--; -} - -void -dhd_timesync_notify_ipc_rev(dhd_ts_t *ts, uint32 ipc_rev) -{ - if (ts != NULL) - ts->active_ipc_version = ipc_rev; -} - -static int -dhd_ts_fw_clksrc_dump(dhd_ts_t *ts, char *buf, int buflen) -{ - struct bcmstrbuf b; - struct bcmstrbuf *strbuf = &b; - clk_ts_log_t *fw_ts_log; - uint32 i = 0, j = 0; - clksrc_ts_log_t *clk_src; - - fw_ts_log = &ts->fw_ts_log; - - bcm_binit(strbuf, buf, buflen); - - while (i <= MAX_CLKSRC_ID) { - clk_src = &fw_ts_log->ts_log[i]; - if (clk_src->inuse == FALSE) { - bcm_bprintf(strbuf, "clkID %d: not in use\n", i); - } - else { - bcm_bprintf(strbuf, "clkID %d: name %s Max idx %d, cur_idx %d\n", - i, clk_src->name, MAX_FW_TS_LOG_SAMPLES, fw_ts_log->cur_idx); - j = 0; - while (j < MAX_FW_TS_LOG_SAMPLES) { - bcm_bprintf(strbuf, "%03d: %03d: 0x%08x-0x%08x\n", j, - fw_ts_log->seqnum[j], clk_src->log[j].ts_high, - clk_src->log[j].ts_low); - j++; - } - } - i++; - } - return b.size; -} - -static void -dhd_ts_fw_clksrc_log(dhd_ts_t *ts, uchar *tlvs, uint32 tlv_len, uint32 seqnum) -{ - ts_fw_clock_info_t *fw_clock_info; - clksrc_ts_log_t *clk_src; - clk_ts_log_t *fw_ts_log; - - fw_ts_log = &ts->fw_ts_log; - - fw_ts_log->seqnum[fw_ts_log->cur_idx] = seqnum; - while (tlv_len) { - fw_clock_info = (ts_fw_clock_info_t *)tlvs; - clk_src = &fw_ts_log->ts_log[(fw_clock_info->ts.ts_high >> 28) & 0xF]; - if (clk_src->inuse == FALSE) { - bcopy(fw_clock_info->clk_src, clk_src->name, sizeof(clk_src->name)); - clk_src->inuse = TRUE; - } - clk_src->log[fw_ts_log->cur_idx].ts_low = fw_clock_info->ts.ts_low; - clk_src->log[fw_ts_log->cur_idx].ts_high = fw_clock_info->ts.ts_high; - - tlvs += sizeof(*fw_clock_info); - tlv_len -= sizeof(*fw_clock_info); - } - fw_ts_log->cur_idx++; - if (fw_ts_log->cur_idx >= MAX_FW_TS_LOG_SAMPLES) - fw_ts_log->cur_idx = 0; -} - -void -dhd_timesync_handle_fw_timestamp(dhd_ts_t *ts, uchar *tlvs, uint32 tlv_len, uint32 seqnum) -{ - ts_fw_clock_info_t *fw_clock_info; - uint16 tag_id; - - DHD_INFO(("FW sent timestamp message, tlv_len %d, seqnum %d\n", tlv_len, seqnum)); - bcm_print_bytes("fw ts", tlvs, tlv_len); - /* we are expecting only one TLV type from the firmware side */ - /* BCMMSGBUF_FW_CLOCK_INFO_TAG */ - /* Validate the tag ID */ - if (ts == NULL) { - DHD_ERROR(("%s: NULL TS \n", __FUNCTION__)); - return; - } - if (tlvs == NULL) { - DHD_ERROR(("%s: NULL TLV \n", __FUNCTION__)); - return; - } - if (tlv_len < BCM_XTLV_HDR_SIZE) { - DHD_ERROR(("%s: bad length %d\n", __FUNCTION__, tlv_len)); - return; - } - if (tlv_len > MAX_SIZE_FW_CLKINFO_TYPE) { - DHD_ERROR(("tlv_len %d more than what is supported in Host %d\n", tlv_len, - (uint32)MAX_SIZE_FW_CLKINFO_TYPE)); - return; - } - if (tlv_len % (sizeof(*fw_clock_info))) { - DHD_ERROR(("bad tlv_len for the packet %d, needs to be multiple of %d\n", tlv_len, - (uint32)(sizeof(*fw_clock_info)))); - return; - } - - /* validate the tag for all the include tag IDs */ - { - uint32 check_len = 0; - uchar *tag_ptr = (uchar *)(tlvs); - while (check_len < tlv_len) { - bcopy(tag_ptr+check_len, &tag_id, sizeof(uint16)); - DHD_INFO(("FWTS: tag_id %d, offset %d \n", - tag_id, check_len)); - if (tag_id != BCMMSGBUF_FW_CLOCK_INFO_TAG) { - DHD_ERROR(("Fatal: invalid tag from FW in TS: %d, offset %d \n", - tag_id, check_len)); - return; - } - check_len += sizeof(*fw_clock_info); - } - } - - if (seqnum != (ts->fw_ts_capture_cnt + 1)) { - DHD_ERROR(("FW TS descrepency: out of sequence exp %d, got %d, resyncing %d\n", - ts->fw_ts_capture_cnt + 1, seqnum, seqnum)); - ts->fw_ts_disc_cnt++; - } - ts->fw_ts_capture_cnt = seqnum; - - /* copy it into local info */ - bcopy(tlvs, &ts->fw_tlv[0], tlv_len); - ts->fw_tlv_len = tlv_len; - - dhd_ts_fw_clksrc_log(ts, tlvs, tlv_len, seqnum); - /* launch the watchdog to send the host time stamp as per the delay programmed */ - if (ts->fwts2hsts_delay_wdcount != 0) { - DHD_ERROR(("FATAL: Last Host sync is not sent out yet\n")); - return; - } - if (dhd_watchdog_ms == 0) { - DHD_ERROR(("FATAL: WATCHDOG is set to 0, timesync can't work properly \n")); - return; - } - /* schedule sending host time sync values to device */ - ts->fwts2hsts_delay_wdcount = ts->fwts2hsts_delay / dhd_watchdog_ms; - if (ts->fwts2hsts_delay_wdcount == 0) - ts->fwts2hsts_delay_wdcount = 1; -} - -static uint32 -dhd_timesync_send_host_timestamping_config(dhd_ts_t *ts, bool inject_err) -{ - ts_host_timestamping_config_t ts_config; - int ret_val; - - if (ts->timesync_disabled) { - DHD_ERROR(("Timesync Disabled: Cannot send HOST TS config msg\n")); - return BCME_ERROR; - } - bzero(&ts_config, sizeof(ts_config)); - - ts_config.xtlv.id = BCMMSGBUF_HOST_TIMESTAMPING_CONFIG_TAG; - if (inject_err) - ts_config.xtlv.id = BCMMSGBUF_HOST_TS_BADTAG; - - ts_config.xtlv.len = sizeof(ts_config) - sizeof(_bcm_xtlv_t); - ts_config.period_ms = ts->h_tsconf_period; - - if (ts_config.period_ms) { - ts_config.flags |= FLAG_HOST_RESET; - ts_config.reset_cnt = ts->host_reset_cnt + 1; - } - - if (ts->nodrop_config) { - ts_config.flags |= FLAG_CONFIG_NODROP; - ts_config.post_delay = TS_NODROP_CONFIG_TO; - } else { - ts_config.post_delay = TS_DROP_CONFIG_TO; - } - - DHD_ERROR(("sending Host Timestamping Config: TLV (ID %d, LEN %d), period %d, seq %d\n", - ts_config.xtlv.id, ts_config.xtlv.len, ts_config.period_ms, - ts->host_ts_capture_cnt)); - ret_val = dhd_prot_send_host_timestamp(ts->dhdp, (uchar *)&ts_config, sizeof(ts_config), - ts->host_ts_capture_cnt, ts->xt_id); - if (ret_val != 0) { - DHD_ERROR(("Fatal: Error sending HOST TS config msg to device: %d\n", ret_val)); - return BCME_ERROR; - } - - if (ts_config.period_ms) { - ts->host_reset_cnt++; - } - - ts->pending_requests++; - ts->xt_ids.host_timestamping_config = ts->xt_id; - ts->xt_id++; - return BCME_OK; -} - -static uint32 -dhd_timesync_send_host_clock_selection(dhd_ts_t *ts) -{ - ts_host_clock_sel_t ts_clk_sel; - int ret_val; - - if (ts->timesync_disabled) { - DHD_ERROR(("Timesync Disabled: Cannot send HOST clock sel msg\n")); - return BCME_ERROR; - } - - bzero(&ts_clk_sel, sizeof(ts_clk_sel)); - - ts_clk_sel.xtlv.id = BCMMSGBUF_HOST_CLOCK_SELECT_TAG; - ts_clk_sel.xtlv.len = sizeof(ts_clk_sel) - sizeof(_bcm_xtlv_t); - ts_clk_sel.min_clk_idx = ts->h_clkid_min; - ts_clk_sel.max_clk_idx = ts->h_clkid_max; - DHD_INFO(("sending Host ClockSel Config: TLV (ID %d, LEN %d), min %d, max %d, seq %d\n", - ts_clk_sel.xtlv.id, ts_clk_sel.xtlv.len, ts_clk_sel.min_clk_idx, - ts_clk_sel.max_clk_idx, - ts->host_ts_capture_cnt)); - ret_val = dhd_prot_send_host_timestamp(ts->dhdp, (uchar *)&ts_clk_sel, sizeof(ts_clk_sel), - ts->host_ts_capture_cnt, ts->xt_id); - if (ret_val != 0) { - DHD_ERROR(("Fatal: Error sending HOST ClockSel msg to device: %d\n", ret_val)); - return BCME_ERROR; - } - ts->xt_ids.host_clock_selection = ts->xt_id; - ts->xt_id++; - ts->pending_requests++; - return BCME_OK; -} - -static uint32 -dhd_timesync_send_host_clk_info(dhd_ts_t *ts) -{ - ts_host_clock_info_t *host_clock_info; - uchar *clk_info_buffer; - uint32 clk_info_bufsize; - int ret_val; - - if (ts->timesync_disabled) { - DHD_ERROR(("Timesync Disabled: Cannot send HOST clock config msg\n")); - return BCME_ERROR; - } - if (ts->host_ts_host_clk_info_buffer_in_use == TRUE) { - DHD_ERROR(("Host Ts Clock info buffer in Use\n")); - return BCME_ERROR; - } - clk_info_buffer = &ts->host_ts_host_clk_info_buffer[0]; - clk_info_bufsize = sizeof(ts->host_ts_host_clk_info_buffer); - - DHD_INFO(("clk_info_buf size %d, tlv_len %d, host clk_info_len %d\n", - clk_info_bufsize, ts->fw_tlv_len, (uint32)sizeof(*host_clock_info))); - - if (clk_info_bufsize < sizeof(*host_clock_info)) { - DHD_ERROR(("clock_info_buf_size too small to fit host clock info %d, %d\n", - clk_info_bufsize, (uint32)sizeof(*host_clock_info))); - return BCME_ERROR; - } - - host_clock_info = (ts_host_clock_info_t *)clk_info_buffer; - host_clock_info->xtlv.id = BCMMSGBUF_HOST_CLOCK_INFO_TAG; - host_clock_info->xtlv.len = sizeof(*host_clock_info) - sizeof(_bcm_xtlv_t); - /* OSL_GET_CYCLES */ - host_clock_info->ticks.low = 0; - host_clock_info->ticks.high = 0; - /* OSL_SYS_UPTIME?? */ - host_clock_info->ns.low = 0; - host_clock_info->ns.high = 0; - clk_info_buffer += (sizeof(*host_clock_info)); - clk_info_bufsize -= sizeof(*host_clock_info); - - /* copy the device clk config as that is the reference for this */ - if (clk_info_bufsize < ts->fw_tlv_len) { - DHD_ERROR(("clock info buffer is small to fit dev clk info %d, %d\n", - clk_info_bufsize, ts->fw_tlv_len)); - return BCME_ERROR; - } - bcopy(ts->fw_tlv, clk_info_buffer, ts->fw_tlv_len); - clk_info_bufsize -= ts->fw_tlv_len; - - DHD_INFO(("sending Host TS msg Len %d, xt_id %d, host_ts_capture_count %d\n", - (uint32)(sizeof(ts->host_ts_host_clk_info_buffer) - clk_info_bufsize), - ts->xt_id, ts->host_ts_capture_cnt)); - - bcm_print_bytes("host ts", (uchar *)ts->host_ts_host_clk_info_buffer, - sizeof(ts->host_ts_host_clk_info_buffer) - clk_info_bufsize); - - ret_val = dhd_prot_send_host_timestamp(ts->dhdp, (uchar *)ts->host_ts_host_clk_info_buffer, - sizeof(ts->host_ts_host_clk_info_buffer) - clk_info_bufsize, - ts->host_ts_capture_cnt, ts->xt_id); - if (ret_val != 0) { - DHD_ERROR(("Fatal: Error sending HOST ClockSel msg to device: %d\n", ret_val)); - return BCME_ERROR; - } - ts->host_ts_host_clk_info_buffer_in_use = TRUE; - ts->xt_ids.host_clk_info = ts->xt_id; - ts->xt_id++; - ts->pending_requests++; - return BCME_OK; -} - -static uint32 -dhd_timesync_send_D2H_clk_correction(dhd_ts_t *ts) -{ - ts_d2h_clock_correction_t ts_clk_crtion; - int ret_val; - - if (ts->timesync_disabled) { - DHD_ERROR(("Timesync Disabled: Cannot send d2h clock correction msg\n")); - return BCME_ERROR; - } - - bzero(&ts_clk_crtion, sizeof(ts_clk_crtion)); - - /* XXX: should this be sending for all the clock sources */ - - ts_clk_crtion.xtlv.id = BCMMSGBUF_D2H_CLOCK_CORRECTION_TAG; - ts_clk_crtion.xtlv.len = sizeof(ts_clk_crtion) - sizeof(_bcm_xtlv_t); - ts_clk_crtion.clk_id = ts->h_clkid_max; - ts_clk_crtion.m.low = ts->correction_m.low; - ts_clk_crtion.m.high = ts->correction_m.high; - ts_clk_crtion.b.low = ts->correction_b.low; - ts_clk_crtion.b.high = ts->correction_b.high; - - DHD_INFO(("sending D2H Correction: ID %d, LEN %d, clkid %d, m %d:%d, b %d:%d, seq %d\n", - ts_clk_crtion.xtlv.id, ts_clk_crtion.xtlv.len, ts_clk_crtion.clk_id, - ts_clk_crtion.m.high, - ts_clk_crtion.m.low, - ts_clk_crtion.b.high, - ts_clk_crtion.b.low, - ts->host_ts_capture_cnt)); - - ret_val = dhd_prot_send_host_timestamp(ts->dhdp, (uchar *)&ts_clk_crtion, - sizeof(ts_clk_crtion), ts->host_ts_capture_cnt, ts->xt_id); - if (ret_val != 0) { - DHD_ERROR(("Fatal: Error sending HOST ClockSel msg to device: %d\n", ret_val)); - return BCME_ERROR; - } - ts->xt_ids.d2h_clk_correction = ts->xt_id; - ts->xt_id++; - ts->pending_requests++; - return BCME_OK; -} - -bool -dhd_timesync_delay_post_bufs(dhd_pub_t *dhdp) -{ - return (dhdp->ts->fwts2hsts_delay != 0); -} - -bool -dhd_timesync_watchdog(dhd_pub_t *dhdp) -{ - dhd_ts_t *ts = dhdp->ts; - - if (ts == NULL) - return FALSE; - - ts->last_ts_watchdog_time = OSL_LOCALTIME_NS(); - ts->ts_watchdog_calls++; - - /* XXX: this is relying the watchdog to be running..which may not hold good */ - if (ts->fwts2hsts_delay_wdcount) { - ts->fwts2hsts_delay_wdcount--; - if (ts->fwts2hsts_delay != 0 && dhdp->busstate == DHD_BUS_DATA && - (ts->fwts2hsts_delay_wdcount == 0)) { - /* see if we need to send the host clock info */ - dhd_timesync_send_host_clk_info(ts); - dhd_msgbuf_delay_post_ts_bufs(dhdp); - } - } - return FALSE; -} - -static void -dhd_timesync_log_timestamp_item(dhd_ts_log_ts_t *tsl, uint16 flowid, uint8 intf, - uint32 ts_low, uint32 ts_high, dhd_pkt_parse_t *pkt) -{ - tsl->ts_log[tsl->cur_idx].ts_low = ts_low; - tsl->ts_log[tsl->cur_idx].ts_high = ts_high; - tsl->ts_log[tsl->cur_idx].intf = intf; - tsl->ts_log[tsl->cur_idx].proto = pkt->proto; - tsl->ts_log[tsl->cur_idx].t1 = pkt->t1; - tsl->ts_log[tsl->cur_idx].t2 = pkt->t2; - tsl->cur_idx++; - if (tsl->cur_idx == tsl->max_idx) - tsl->cur_idx = 0; -} - -void -dhd_timesync_log_tx_timestamp(dhd_ts_t *ts, uint16 flowid, uint8 intf, - uint32 ts_low, uint32 ts_high, dhd_pkt_parse_t *pkt) -{ - if (ts != NULL) { - dhd_timesync_log_timestamp_item(&ts->tx_timestamps, flowid, intf, - ts_low, ts_high, pkt); - } -} - -void -dhd_timesync_log_rx_timestamp(dhd_ts_t *ts, uint8 intf, uint32 ts_low, uint32 ts_high, - dhd_pkt_parse_t *pkt) -{ - if (ts != NULL) { - dhd_timesync_log_timestamp_item(&ts->rx_timestamps, 0, intf, - ts_low, ts_high, pkt); - } -} - -void -dhd_timesync_control(dhd_pub_t *dhdp, bool disabled) -{ - dhd_ts_t *ts; - if (dhdp == NULL) - return; - - ts = dhdp->ts; - if (ts != NULL) { - if (disabled) { - DHD_ERROR(("resetting the timesync counter, current(%d)\n", - ts->fw_ts_capture_cnt)); - - ts->fw_ts_capture_cnt = 0; - - /* Suspend case: Disable timesync after the config message */ - if ((ts->active_ipc_version >= 7) && (ts->h_tsconf_period != 0)) { - uint32 tsconf_period; - - tsconf_period = ts->h_tsconf_period; - ts->h_tsconf_period = 0; - - dhd_timesync_send_host_timestamping_config(ts, FALSE); - ts->h_tsconf_period = tsconf_period; - } - ts->timesync_disabled = TRUE; - ts->suspend_req++; - } else { - /* Resume case: Enable timesync before the config message */ - DHD_ERROR(("enabling the timesync counter, current(%d)\n", - ts->fw_ts_capture_cnt)); - - ts->timesync_disabled = FALSE; - ts->resume_req++; - - if ((ts->active_ipc_version >= 7) && (ts->h_tsconf_period != 0)) - dhd_timesync_send_host_timestamping_config(ts, FALSE); - } - } - /* XXX: may be all the other internal iovar calls should check for disabled state */ -} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_timesync.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_timesync.h deleted file mode 100755 index 0e3afb35eb3f..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_timesync.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Header file describing the common timesync functionality - * - * Provides type definitions and function prototypes used to handle timesync functionality. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$: - */ - -#ifndef _dhd_timesync_h_ -#define _dhd_timesync_h_ - -typedef struct dhd_ts dhd_ts_t; - -/* Linkage, sets "ts" link and updates hdrlen in pub */ -extern int dhd_timesync_attach(dhd_pub_t *dhdp); - -/* Linkage, sets "ts" link and updates hdrlen in pub */ -extern bool dhd_timesync_watchdog(dhd_pub_t *dhdp); - -/* Unlink, frees allocated timesync memory (including dhd_ts_t) */ -extern int dhd_timesync_detach(dhd_pub_t *dhdp); - -/* Check for and handle local prot-specific iovar commands */ -extern int dhd_timesync_iovar_op(dhd_ts_t *ts, const char *name, void *params, int plen, - void *arg, int len, bool set); - -/* handle host time stamp completion */ -extern void dhd_timesync_handle_host_ts_complete(dhd_ts_t *ts, uint16 xt_id, uint16 status); - -/* handle fw time stamp event from firmware */ -extern void dhd_timesync_handle_fw_timestamp(dhd_ts_t *ts, uchar *tlv, uint32 tlv_len, - uint32 seqnum); - -/* get notified of the ipc rev */ -extern void dhd_timesync_notify_ipc_rev(dhd_ts_t *ts, uint32 ipc_rev); - -/* log txs timestamps */ -extern void dhd_timesync_log_tx_timestamp(dhd_ts_t *ts, uint16 flowid, uint8 intf, - uint32 ts_low, uint32 ts_high, dhd_pkt_parse_t *parse); - -/* log rx cpl timestamps */ -extern void dhd_timesync_log_rx_timestamp(dhd_ts_t *ts, uint8 intf, - uint32 ts_low, uint32 ts_high, dhd_pkt_parse_t *parse); - -/* dynamically disabling it based on the host driver suspend/resume state */ -extern void dhd_timesync_control(dhd_pub_t *dhdp, bool disabled); - -extern void dhd_timesync_debug_info_print(dhd_pub_t *dhdp); -#endif /* _dhd_timesync_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wet.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wet.c deleted file mode 100755 index 4537aef9d247..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wet.c +++ /dev/null @@ -1,1187 +0,0 @@ -/** - * @file - * @brief - * Wireless EThernet (WET) Bridge. - * - * WET STA and WET client are inter-exchangable in this file and refer to - * addressable entities whose traffic are sent and received through this - * bridge, including the hosting device. - * - * Supported protocol families: IP v4. - * - * Tx: replace frames' source MAC address with wireless interface's; - * update the IP-MAC address mapping table entry. - * - * Rx: replace frames' the destination MAC address with what found in - * the IP-MAC address mapping table. - * - * All data structures defined in this file are optimized for IP v4. To - * support other protocol families, write protocol specific handlers. - * Doing so may require data structures changes to expand various address - * storages to fit the protocol specific needs, for example, IPX needs 10 - * octets for its network address. Also one may need to define the data - * structures in a more generic way so that they work with all supported - * protocol families, for example, the wet_sta strcture may be defined - * as follow: - * - * struct wet_sta { - * uint8 nal; network address length - * uint8 na[NETA_MAX_LEN]; network address - * uint8 mac[ETHER_ADDR_LEN]; - * ... - * }; - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - */ - -/** - * @file - * @brief - * XXX Twiki: [WirelessEthernet] - */ -#include -#include -#include -#include -#include -#include -#include <802.11.h> -#include -#include -#include <802.3.h> -#include -#include -#include -#include -#include -#include -#include - -#include - -/* IP/MAC address mapping entry */ -typedef struct wet_sta wet_sta_t; -struct wet_sta { - /* client */ - uint8 ip[IPV4_ADDR_LEN]; /* client IP addr */ - struct ether_addr mac; /* client MAC addr */ - uint8 flags[DHCP_FLAGS_LEN]; /* orig. dhcp flags */ - /* internal */ - wet_sta_t *next; /* free STA link */ - wet_sta_t *next_ip; /* hash link by IP */ - wet_sta_t *next_mac; /* hash link by MAC */ -}; -#define WET_NUMSTAS (1 << 8) /* max. # clients, must be multiple of 2 */ -#define WET_STA_HASH_SIZE (WET_NUMSTAS/2) /* must be <= WET_NUMSTAS */ -#define WET_STA_HASH_IP(ip) ((ip)[3]&(WET_STA_HASH_SIZE-1)) /* hash by IP */ -#define WET_STA_HASH_MAC(ea) (((ea)[3]^(ea)[4]^(ea)[5])&(WET_STA_HASH_SIZE-1)) /* hash by MAC */ -#define WET_STA_HASH_UNK -1 /* Unknown hash */ -#define IP_ISMULTI(ip) (((ip) & 0xf0000000) == 0xe0000000) /* Check for multicast by IP */ - -/* WET private info structure */ -struct dhd_wet_info { - /* pointer to dhdpublic info struct */ - dhd_pub_t *pub; - /* Host addresses */ - uint8 ip[IPV4_ADDR_LEN]; - struct ether_addr mac; - /* STA storage, one entry per eth. client */ - wet_sta_t sta[WET_NUMSTAS]; - /* Free sta list */ - wet_sta_t *stafree; - /* Used sta hash by IP */ - wet_sta_t *stahash_ip[WET_STA_HASH_SIZE]; - /* Used sta hash by MAC */ - wet_sta_t *stahash_mac[WET_STA_HASH_SIZE]; -}; - -/* forward declarations */ -static int wet_eth_proc(dhd_wet_info_t *weth, void *sdu, - uint8 *frame, int length, int send); -static int wet_vtag_proc(dhd_wet_info_t *weth, void *sdu, - uint8 * eh, uint8 *vtag, int length, int send); -static int wet_ip_proc(dhd_wet_info_t *weth, void *sdu, - uint8 * eh, uint8 *iph, int length, int send); -static int wet_arp_proc(dhd_wet_info_t *weth, void *sdu, - uint8 *eh, uint8 *arph, int length, int send); -static int wet_udp_proc(dhd_wet_info_t *weth, - uint8 *eh, uint8 *iph, uint8 *udph, int length, int send); -static int wet_dhcpc_proc(dhd_wet_info_t *weth, - uint8 *eh, uint8 *iph, uint8 *udph, uint8 *dhcp, int length, int send); -static int wet_dhcps_proc(dhd_wet_info_t *weth, - uint8 *eh, uint8 *iph, uint8 *udph, uint8 *dhcp, int length, int send); -static int wet_sta_alloc(dhd_wet_info_t *weth, wet_sta_t **saddr); -static int wet_sta_update_all(dhd_wet_info_t *weth, - uint8 *iaddr, struct ether_addr *eaddr, wet_sta_t **saddr); -static int wet_sta_update_mac(dhd_wet_info_t *weth, - struct ether_addr *eaddr, wet_sta_t **saddr); -static int wet_sta_remove_mac_entry(dhd_wet_info_t *weth, struct ether_addr *eaddr); -static int wet_sta_find_ip(dhd_wet_info_t *weth, - uint8 *iaddr, wet_sta_t **saddr); -static int wet_sta_find_mac(dhd_wet_info_t *weth, - struct ether_addr *eaddr, wet_sta_t **saddr); -static void csum_fixup_16(uint8 *chksum, - uint8 *optr, int olen, uint8 *nptr, int nlen); - -/* - * Protocol handler. 'ph' points to protocol specific header, - * for example, it points to IP header if it is IP packet. - */ -typedef int (*prot_proc_t)(dhd_wet_info_t *weth, void *sdu, uint8 *eh, - uint8 *ph, int length, int send); -/* Protocol handlers hash table - hash by ether type */ -typedef struct prot_hdlr prot_hdlr_t; -struct prot_hdlr { - uint16 type; /* ether type */ - prot_proc_t prot_proc; - prot_hdlr_t *next; /* next proto handler that has the same hash */ -}; -#define WET_PROT_HASH_SIZE (1 << 3) -#define WET_PROT_HASH(t) ((t)[1]&(WET_PROT_HASH_SIZE-1)) -static prot_hdlr_t ept_tbl[] = { - /* 0 */ {HTON16(ETHER_TYPE_8021Q), wet_vtag_proc, NULL}, /* 0x8100 */ -}; -static prot_hdlr_t prot_hash[WET_PROT_HASH_SIZE] = { - /* 0 */ {HTON16(ETHER_TYPE_IP), wet_ip_proc, &ept_tbl[0]}, /* 0x0800 */ - /* 1 */ {0, NULL, NULL}, /* unused */ - /* 2 */ {0, NULL, NULL}, /* unused */ - /* 3 */ {0, NULL, NULL}, /* unused */ - /* 4 */ {0, NULL, NULL}, /* unused */ - /* 5 */ {0, NULL, NULL}, /* unused */ - /* 6 */ {HTON16(ETHER_TYPE_ARP), wet_arp_proc, NULL}, /* 0x0806 */ - /* 7 */ {0, NULL, NULL}, /* unused */ -}; - -/* - * IPv4 handler. 'ph' points to protocol specific header, - * for example, it points to UDP header if it is UDP packet. - */ -typedef int (*ipv4_proc_t)(dhd_wet_info_t *weth, uint8 *eh, - uint8 *iph, uint8 *ph, int length, int send); -/* IPv4 handlers hash table - hash by protocol type */ -typedef struct ipv4_hdlr ipv4_hdlr_t; -struct ipv4_hdlr { - uint8 type; /* protocol type */ - ipv4_proc_t ipv4_proc; - ipv4_hdlr_t *next; /* next proto handler that has the same hash */ -}; -#define WET_IPV4_HASH_SIZE (1 << 1) -#define WET_IPV4_HASH(p) ((p)&(WET_IPV4_HASH_SIZE-1)) -static ipv4_hdlr_t ipv4_hash[WET_IPV4_HASH_SIZE] = { - /* 0 */ {0, NULL, NULL}, /* unused */ - /* 1 */ {IP_PROT_UDP, wet_udp_proc, NULL}, /* 0x11 */ -}; - -/* - * UDP handler. 'ph' points to protocol specific header, - * for example, it points to DHCP header if it is DHCP packet. - */ -typedef int (*udp_proc_t)(dhd_wet_info_t *weth, uint8 *eh, - uint8 *iph, uint8 *udph, uint8 *ph, int length, int send); -/* UDP handlers hash table - hash by port number */ -typedef struct udp_hdlr udp_hdlr_t; -struct udp_hdlr { - uint16 port; /* udp dest. port */ - udp_proc_t udp_proc; - udp_hdlr_t *next; /* next proto handler that has the same hash */ -}; -#define WET_UDP_HASH_SIZE (1 << 3) -#define WET_UDP_HASH(p) ((p)[1]&(WET_UDP_HASH_SIZE-1)) -static udp_hdlr_t udp_hash[WET_UDP_HASH_SIZE] = { - /* 0 */ {0, NULL, NULL}, /* unused */ - /* 1 */ {0, NULL, NULL}, /* unused */ - /* 2 */ {0, NULL, NULL}, /* unused */ - /* 3 */ {HTON16(DHCP_PORT_SERVER), wet_dhcpc_proc, NULL}, /* 0x43 */ - /* 4 */ {HTON16(DHCP_PORT_CLIENT), wet_dhcps_proc, NULL}, /* 0x44 */ - /* 5 */ {0, NULL, NULL}, /* unused */ - /* 6 */ {0, NULL, NULL}, /* unused */ - /* 7 */ {0, NULL, NULL}, /* unused */ -}; - -#define WETHWADDR(weth) ((weth)->pub->mac.octet) -#define WETOSH(weth) ((weth)->pub->osh) - -/* special values */ -/* 802.3 llc/snap header */ -static uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; -static uint8 ipv4_bcast[IPV4_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff}; /* IP v4 broadcast address */ -static uint8 ipv4_null[IPV4_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00}; /* IP v4 NULL address */ - -dhd_wet_info_t * -dhd_get_wet_info(dhd_pub_t *pub) -{ - dhd_wet_info_t *p; - int i; - p = (dhd_wet_info_t *)MALLOCZ(pub->osh, sizeof(dhd_wet_info_t)); - if (p == NULL) { - return 0; - } - for (i = 0; i < WET_NUMSTAS - 1; i ++) - p->sta[i].next = &p->sta[i + 1]; - p->stafree = &p->sta[0]; - p->pub = pub; - return p; -} - -void -dhd_free_wet_info(dhd_pub_t *pub, void *wet) -{ - if (wet) { - MFREE(pub->osh, wet, sizeof(dhd_wet_info_t)); - } -} - -void dhd_set_wet_host_ipv4(dhd_pub_t *pub, void *parms, uint32 len) -{ - dhd_wet_info_t *p; - p = (dhd_wet_info_t *)pub->wet_info; - bcopy(parms, p->ip, len); -} - -void dhd_set_wet_host_mac(dhd_pub_t *pub, void *parms, uint32 len) -{ - dhd_wet_info_t *p; - p = (dhd_wet_info_t *)pub->wet_info; - bcopy(parms, &p->mac, len); -} -/* process Ethernet frame */ -/* -* Return: -* = 0 if frame is done ok -* < 0 if unable to handle the frame -* > 0 if no further process -*/ -static int -BCMFASTPATH(wet_eth_proc)(dhd_wet_info_t *weth, void *sdu, uint8 *frame, int length, int send) -{ - uint8 *pt = frame + ETHER_TYPE_OFFSET; - uint16 type; - uint8 *ph; - prot_hdlr_t *phdlr; - /* intercept Ethernet II frame (type > 1500) */ - if (length >= ETHER_HDR_LEN && (pt[0] > (ETHER_MAX_DATA >> 8) || - (pt[0] == (ETHER_MAX_DATA >> 8) && pt[1] > (ETHER_MAX_DATA & 0xff)))) - ; - /* intercept 802.3 LLC/SNAP frame (type <= 1500) */ - else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN) { - uint8 *llc = frame + ETHER_HDR_LEN; - if (bcmp(llc_snap_hdr, llc, SNAP_HDR_LEN)) - return 0; - pt = llc + SNAP_HDR_LEN; - } - /* frame too short bail out */ - else { - DHD_ERROR(("wet_eth_proc: %s short eth frame, ignored\n", - send ? "send" : "recv")); - return -1; - } - ph = pt + ETHER_TYPE_LEN; - length -= ph - frame; - - /* Call protocol specific handler to process frame. */ - type = *(uint16 *)pt; - - for (phdlr = &prot_hash[WET_PROT_HASH(pt)]; - phdlr != NULL; phdlr = phdlr->next) { - if (phdlr->type != type || !phdlr->prot_proc) - continue; - return (phdlr->prot_proc)(weth, sdu, frame, ph, length, send); - } - - if (!bcmp(WETHWADDR(weth), frame + ETHER_SRC_OFFSET, ETHER_ADDR_LEN)) { - return 0; - } - else { - DHD_INFO(("%s: %s unknown type (0x%X), ignored %s\n", - __FUNCTION__, send ? "send" : "recv", type, - (type == 0xDD86) ? "IPv6":"")); - /* ignore unsupported protocol from different mac addr than us */ - return BCME_UNSUPPORTED; - } -} - -/* process 8021p/Q tagged frame */ -/* -* Return: -* = 0 if frame is done ok -* < 0 if unable to handle the frame -* > 0 if no further process -*/ -static int -BCMFASTPATH(wet_vtag_proc)(dhd_wet_info_t *weth, void *sdu, - uint8 * eh, uint8 *vtag, int length, int send) -{ - uint16 type; - uint8 *pt; - prot_hdlr_t *phdlr; - - /* check minimum length */ - if (length < ETHERVLAN_HDR_LEN) { - DHD_ERROR(("wet_vtag_proc: %s short VLAN frame, ignored\n", - send ? "send" : "recv")); - return -1; - } - - /* - * FIXME: check recursiveness to prevent stack from overflow - * in case someone sent frames 8100xxxxxxxx8100xxxxxxxx... - */ - - /* Call protocol specific handler to process frame. */ - type = *(uint16 *)(pt = vtag + VLAN_TAG_LEN); - - for (phdlr = &prot_hash[WET_PROT_HASH(pt)]; - phdlr != NULL; phdlr = phdlr->next) { - if (phdlr->type != type || !phdlr->prot_proc) - continue; - return (phdlr->prot_proc)(weth, sdu, eh, - pt + ETHER_TYPE_LEN, length, send); - } - - return 0; -} - -/* process IP frame */ -/* -* Return: -* = 0 if frame is done ok -* < 0 if unable to handle the frame -* > 0 if no further process -*/ -static int -BCMFASTPATH(wet_ip_proc)(dhd_wet_info_t *weth, void *sdu, - uint8 *eh, uint8 *iph, int length, int send) -{ - uint8 type; - int ihl; - wet_sta_t *sta; - ipv4_hdlr_t *iphdlr; - uint8 *iaddr; - struct ether_addr *ea = NULL; - int ret, ea_off = 0; - char eabuf[ETHER_ADDR_STR_LEN]; - BCM_REFERENCE(eabuf); - - /* IPv4 only */ - if (length < 1 || (IP_VER(iph) != IP_VER_4)) { - DHD_INFO(("wet_ip_proc: %s non IPv4 frame, ignored\n", - send ? "send" : "recv")); - return -1; - } - - ihl = IPV4_HLEN(iph); - - /* minimum length */ - if (length < ihl) { - DHD_ERROR(("wet_ip_proc: %s short IPv4 frame, ignored\n", - send ? "send" : "recv")); - return -1; - } - - /* protocol specific handling */ - type = IPV4_PROT(iph); - for (iphdlr = &ipv4_hash[WET_IPV4_HASH(type)]; - iphdlr; iphdlr = iphdlr->next) { - if (iphdlr->type != type || !iphdlr->ipv4_proc) - continue; - if ((ret = (iphdlr->ipv4_proc)(weth, eh, - iph, iph + ihl, length - ihl, send))) - return ret; - } - - /* generic IP packet handling - * Replace source MAC in Ethernet header with wireless's and - * keep track of IP MAC mapping when sending frame. - */ - if (send) { - uint32 iaddr_dest, iaddr_src; - bool wet_table_upd = TRUE; - iaddr = iph + IPV4_SRC_IP_OFFSET; - iaddr_dest = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET))); - iaddr_src = ntoh32(*(uint32 *)(iaddr)); - - /* Do not process and update knowledge base on receipt of a local IP - * multicast frame - */ - if (IP_ISMULTI(iaddr_dest) && !iaddr_src) { - DHD_INFO(("recv multicast frame from %s.Don't update hash table\n", - bcm_ether_ntoa((struct ether_addr*) - (eh + ETHER_SRC_OFFSET), eabuf))); - wet_table_upd = FALSE; - } - if (wet_table_upd && wet_sta_update_all(weth, iaddr, - (struct ether_addr*)(eh + ETHER_SRC_OFFSET), &sta) < 0) { - DHD_INFO(("wet_ip_proc: unable to update STA %u.%u.%u.%u %s\n", - iaddr[0], iaddr[1], iaddr[2], iaddr[3], - bcm_ether_ntoa( - (struct ether_addr*)(eh + ETHER_SRC_OFFSET), eabuf))); - return -1; - } - ea = (struct ether_addr *)WETHWADDR(weth); - ea_off = ETHER_SRC_OFFSET; - eacopy(ea, eh + ea_off); - } - /* - * Replace dest MAC in Ethernet header using the found one - * when receiving frame. - */ - /* no action for received bcast/mcast ethernet frame */ - else if (!ETHER_ISMULTI(eh)) { - iaddr = iph + IPV4_DEST_IP_OFFSET; - if (wet_sta_find_ip(weth, iaddr, &sta) < 0) { - DHD_ERROR(("wet_ip_proc: unable to find STA %u.%u.%u.%u\n", - iaddr[0], iaddr[1], iaddr[2], iaddr[3])); - return -1; - } - ea = &sta->mac; - ea_off = ETHER_DEST_OFFSET; - eacopy(ea, eh + ea_off); - } - - return 0; -} - -/* process ARP frame - ARP proxy */ -/* - * Return: - * = 0 if frame is done ok - * < 0 if unable to handle the frame - * > 0 if no further process - */ -static int -BCMFASTPATH(wet_arp_proc)(dhd_wet_info_t *weth, void *sdu, - uint8 *eh, uint8 *arph, int length, int send) -{ - wet_sta_t *sta; - uint8 *iaddr; - char eabuf[ETHER_ADDR_STR_LEN]; - BCM_REFERENCE(eabuf); - - /* - * FIXME: validate ARP header: - * h/w Ethernet 2, proto IP x800, h/w addr size 6, proto addr size 4. - */ - - /* - * Replace source MAC in Ethernet header as well as source MAC in - * ARP protocol header when processing frame sent. - */ - if (send) { - iaddr = arph + ARP_SRC_IP_OFFSET; - if (wet_sta_update_all(weth, iaddr, - (struct ether_addr*)(eh + ETHER_SRC_OFFSET), &sta) < 0) { - DHD_INFO(("wet_arp_proc: unable to update STA %u.%u.%u.%u %s\n", - iaddr[0], iaddr[1], iaddr[2], iaddr[3], - bcm_ether_ntoa( - (struct ether_addr*)(eh + ETHER_SRC_OFFSET), eabuf))); - return -1; - } - bcopy(WETHWADDR(weth), eh + ETHER_SRC_OFFSET, ETHER_ADDR_LEN); - bcopy(WETHWADDR(weth), arph+ARP_SRC_ETH_OFFSET, ETHER_ADDR_LEN); - } - /* - * Replace dest MAC in Ethernet header as well as dest MAC in - * ARP protocol header when processing frame recv'd. Process ARP - * replies and Unicast ARP requests. - */ - else if ((*(uint16 *)(arph + ARP_OPC_OFFSET) == HTON16(ARP_OPC_REPLY)) || - ((*(uint16 *)(arph + ARP_OPC_OFFSET) == HTON16(ARP_OPC_REQUEST)) && - (!ETHER_ISMULTI(eh)))) { - iaddr = arph + ARP_TGT_IP_OFFSET; - if (wet_sta_find_ip(weth, iaddr, &sta) < 0) { - DHD_INFO(("wet_arp_proc: unable to find STA %u.%u.%u.%u\n", - iaddr[0], iaddr[1], iaddr[2], iaddr[3])); - return -1; - } - bcopy(&sta->mac, arph + ARP_TGT_ETH_OFFSET, ETHER_ADDR_LEN); - bcopy(&sta->mac, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN); - } - - return 0; -} - -/* process UDP frame */ -/* - * Return: - * = 0 if frame is done ok - * < 0 if unable to handle the frame - * > 0 if no further process - */ -static int -BCMFASTPATH(wet_udp_proc)(dhd_wet_info_t *weth, - uint8 *eh, uint8 *iph, uint8 *udph, int length, int send) -{ - udp_hdlr_t *udphdlr; - uint16 port; - - /* check frame length, at least UDP_HDR_LEN */ - if ((length -= UDP_HDR_LEN) < 0) { - DHD_ERROR(("wet_udp_proc: %s short UDP frame, ignored\n", - send ? "send" : "recv")); - return -1; - } - - /* - * Unfortunately we must spend some time here to deal with - * some higher layer protocol special processings. - * See individual handlers for protocol specific details. - */ - port = *(uint16 *)(udph + UDP_DEST_PORT_OFFSET); - for (udphdlr = &udp_hash[WET_UDP_HASH((uint8 *)&port)]; - udphdlr; udphdlr = udphdlr->next) { - if (udphdlr->port != port || !udphdlr->udp_proc) - continue; - return (udphdlr->udp_proc)(weth, eh, iph, udph, - udph + UDP_HDR_LEN, length, send); - } - - return 0; -} - -/* - * DHCP is a 'complex' protocol for WET, mainly because it - * uses its protocol body to convey IP/MAC info. It is impossible - * to forward frames correctly back and forth without looking - * into the DHCP's body and interpreting it. See RFC2131 sect. - * 4.1 'Constructing and sending DHCP messages' for details - * of using/parsing various fields in the body. - * - * DHCP pass through: - * - * Must alter DHCP flag to broadcast so that the server - * can reply with the broadcast address before we can - * provide DHCP relay functionality. Otherwise the DHCP - * server will send DHCP replies using the DHCP client's - * MAC address. Such replies will not be delivered simply - * because: - * - * 1. The AP's bridge will not forward the replies back to - * this device through the wireless link because it does not - * know such node exists on this link. The bridge's forwarding - * table on the AP will have this device's MAC address only. - * It does not know anything else behind this device. - * - * 2. The AP's wireless driver won't allow such frames out - * either even if they made their way out the AP's bridge - * through the bridge's DLF broadcasting because there is - * no such STA associated with the AP. - * - * 3. This device's MAC won't allow such frames pass - * through in non-promiscuous mode even when they made - * their way out of the AP's wireless interface somehow. - * - * DHCP relay: - * - * Once the WET is configured with the host MAC address it can - * relay the host request as if it were sent from WET itself. - * - * Once the WET is configured with the host IP address it can - * pretend to be the host and act as a relay agent. - * - * process DHCP client frame (client to server, or server to relay agent) - * Return: - * = 0 if frame is done ok - * < 0 if unable to handle the frame - * > 0 if no further process - */ -static int -BCMFASTPATH(wet_dhcpc_proc)(dhd_wet_info_t *weth, - uint8 *eh, uint8 *iph, uint8 *udph, uint8 *dhcp, int length, int send) -{ - wet_sta_t *sta; - uint16 flags; - char eabuf[ETHER_ADDR_STR_LEN]; - uint16 port; - uint8 *ipv4; - const struct ether_addr *ether; - BCM_REFERENCE(eabuf); - - /* - * FIXME: validate DHCP body: - * htype Ethernet 1, hlen Ethernet 6, frame length at least 242. - */ - - /* only interested in requests when sending to server */ - if (send && *(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REQUEST) - return 0; - /* only interested in replies when receiving from server as a relay agent */ - if (!send && *(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REPLY) - return 0; - - /* send request */ - if (send) { - /* find existing or alloc new IP/MAC mapping entry */ - if (wet_sta_update_mac(weth, - (struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), &sta) < 0) { - DHD_INFO(("wet_dhcpc_proc: unable to update STA %s\n", - bcm_ether_ntoa( - (struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), eabuf))); - return -1; - } - bcopy(dhcp + DHCP_FLAGS_OFFSET, &flags, DHCP_FLAGS_LEN); - /* We can always relay the host's request when we know its MAC addr. */ - if (!ETHER_ISNULLADDR(weth->mac.octet) && - !bcmp(dhcp + DHCP_CHADDR_OFFSET, &weth->mac, ETHER_ADDR_LEN)) { - /* replace chaddr with host's MAC */ - csum_fixup_16(udph + UDP_CHKSUM_OFFSET, - dhcp + DHCP_CHADDR_OFFSET, ETHER_ADDR_LEN, - WETHWADDR(weth), ETHER_ADDR_LEN); - bcopy(WETHWADDR(weth), dhcp + DHCP_CHADDR_OFFSET, ETHER_ADDR_LEN); - /* force reply to be unicast */ - flags &= ~HTON16(DHCP_FLAG_BCAST); - } - /* We can relay other clients' requests when we know the host's IP addr. */ - else if (!IPV4_ADDR_NULL(weth->ip)) { - /* we can only handle the first hop otherwise drop it */ - if (!IPV4_ADDR_NULL(dhcp + DHCP_GIADDR_OFFSET)) { - DHD_INFO(("wet_dhcpc_proc: not first hop, ignored\n")); - return -1; - } - /* replace giaddr with host's IP */ - csum_fixup_16(udph + UDP_CHKSUM_OFFSET, - dhcp + DHCP_GIADDR_OFFSET, IPV4_ADDR_LEN, - weth->ip, IPV4_ADDR_LEN); - bcopy(weth->ip, dhcp + DHCP_GIADDR_OFFSET, IPV4_ADDR_LEN); - /* force reply to be unicast */ - flags &= ~HTON16(DHCP_FLAG_BCAST); - } - /* - * Request comes in when we don't know the host's MAC and/or IP - * addresses hence we can't relay the request. We must notify the - * server of our addressing limitation by turning on the broadcast - * bit at this point as what the function comments point out. - */ - else - flags |= HTON16(DHCP_FLAG_BCAST); - /* update flags */ - bcopy(dhcp + DHCP_FLAGS_OFFSET, sta->flags, DHCP_FLAGS_LEN); - if (flags != *(uint16 *)sta->flags) { - csum_fixup_16(udph + UDP_CHKSUM_OFFSET, - dhcp + DHCP_FLAGS_OFFSET, DHCP_FLAGS_LEN, - (uint8 *)&flags, DHCP_FLAGS_LEN); - bcopy((uint8 *)&flags, dhcp + DHCP_FLAGS_OFFSET, - DHCP_FLAGS_LEN); - } - /* replace the Ethernet source MAC with ours */ - bcopy(WETHWADDR(weth), eh + ETHER_SRC_OFFSET, ETHER_ADDR_LEN); - } - /* relay recv'd reply to its destiny */ - else if (!IPV4_ADDR_NULL(weth->ip) && - !bcmp(dhcp + DHCP_GIADDR_OFFSET, weth->ip, IPV4_ADDR_LEN)) { - /* find IP/MAC mapping entry */ - if (wet_sta_find_mac(weth, - (struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), &sta) < 0) { - DHD_INFO(("wet_dhcpc_proc: unable to find STA %s\n", - bcm_ether_ntoa( - (struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), eabuf))); - return -1; - } - /* - * XXX the following code works for the first hop only - */ - /* restore the DHCP giaddr with its original */ - csum_fixup_16(udph + UDP_CHKSUM_OFFSET, - dhcp + DHCP_GIADDR_OFFSET, IPV4_ADDR_LEN, - ipv4_null, IPV4_ADDR_LEN); - bcopy(ipv4_null, dhcp + DHCP_GIADDR_OFFSET, IPV4_ADDR_LEN); - /* restore the original client's dhcp flags */ - if (bcmp(dhcp + DHCP_FLAGS_OFFSET, sta->flags, DHCP_FLAGS_LEN)) { - csum_fixup_16(udph + UDP_CHKSUM_OFFSET, - dhcp + DHCP_FLAGS_OFFSET, DHCP_FLAGS_LEN, - sta->flags, DHCP_FLAGS_LEN); - bcopy(sta->flags, dhcp + DHCP_FLAGS_OFFSET, DHCP_FLAGS_LEN); - } - /* replace the dest UDP port with DHCP client port */ - port = HTON16(DHCP_PORT_CLIENT); - csum_fixup_16(udph + UDP_CHKSUM_OFFSET, - udph + UDP_DEST_PORT_OFFSET, UDP_PORT_LEN, - (uint8 *)&port, UDP_PORT_LEN); - bcopy((uint8 *)&port, udph + UDP_DEST_PORT_OFFSET, UDP_PORT_LEN); - /* replace the dest MAC & IP addr with the client's */ - if (*(uint16 *)sta->flags & HTON16(DHCP_FLAG_BCAST)) { - ipv4 = ipv4_bcast; - ether = ðer_bcast; - } - else { - ipv4 = dhcp + DHCP_YIADDR_OFFSET; - ether = &sta->mac; - } - csum_fixup_16(udph + UDP_CHKSUM_OFFSET, - iph + IPV4_DEST_IP_OFFSET, IPV4_ADDR_LEN, - ipv4, IPV4_ADDR_LEN); - csum_fixup_16(iph + IPV4_CHKSUM_OFFSET, - iph + IPV4_DEST_IP_OFFSET, IPV4_ADDR_LEN, - ipv4, IPV4_ADDR_LEN); - bcopy(ipv4, iph + IPV4_DEST_IP_OFFSET, IPV4_ADDR_LEN); - bcopy(ether, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN); - } - /* it should not recv non-relay reply at all, but just in case */ - else { - DHD_INFO(("wet_dhcpc_proc: ignore recv'd frame from %s\n", - bcm_ether_ntoa((struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), eabuf))); - return -1; - } - - /* no further processing! */ - return 1; -} - -/* process DHCP server frame (server to client) */ -/* - * Return: - * = 0 if frame is done ok - * < 0 if unable to handle the frame - * > 0 if no further process - */ -static int -BCMFASTPATH(wet_dhcps_proc)(dhd_wet_info_t *weth, - uint8 *eh, uint8 *iph, uint8 *udph, uint8 *dhcp, int length, int send) -{ - wet_sta_t *sta; - char eabuf[ETHER_ADDR_STR_LEN]; - BCM_REFERENCE(eabuf); - - /* - * FIXME: validate DHCP body: - * htype Ethernet 1, hlen Ethernet 6, frame length at least 242. - */ - - /* only interested in replies when receiving from server */ - if (send || *(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REPLY) - return 0; - - /* find IP/MAC mapping entry */ - if (wet_sta_find_mac(weth, (struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), &sta) < 0) { - DHD_INFO(("wet_dhcps_proc: unable to find STA %s\n", - bcm_ether_ntoa((struct ether_addr*)(dhcp + DHCP_CHADDR_OFFSET), eabuf))); - return -1; - } - /* relay the reply to the host when we know the host's MAC addr */ - if (!ETHER_ISNULLADDR(weth->mac.octet) && - !bcmp(dhcp + DHCP_CHADDR_OFFSET, WETHWADDR(weth), ETHER_ADDR_LEN)) { - csum_fixup_16(udph + UDP_CHKSUM_OFFSET, - dhcp + DHCP_CHADDR_OFFSET, ETHER_ADDR_LEN, - weth->mac.octet, ETHER_ADDR_LEN); - bcopy(&weth->mac, dhcp + DHCP_CHADDR_OFFSET, ETHER_ADDR_LEN); - } - /* restore the original client's dhcp flags if necessary */ - if (bcmp(dhcp + DHCP_FLAGS_OFFSET, sta->flags, DHCP_FLAGS_LEN)) { - csum_fixup_16(udph + UDP_CHKSUM_OFFSET, - dhcp + DHCP_FLAGS_OFFSET, DHCP_FLAGS_LEN, - sta->flags, DHCP_FLAGS_LEN); - bcopy(sta->flags, dhcp + DHCP_FLAGS_OFFSET, DHCP_FLAGS_LEN); - } - /* replace the dest MAC with that of client's */ - if (*(uint16 *)sta->flags & HTON16(DHCP_FLAG_BCAST)) - bcopy((const uint8 *)ðer_bcast, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN); - else - bcopy(&sta->mac, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN); - - /* no further processing! */ - return 1; -} - -/* alloc IP/MAC mapping entry - * Returns 0 if succeeded; < 0 otherwise. - */ -static int -wet_sta_alloc(dhd_wet_info_t *weth, wet_sta_t **saddr) -{ - wet_sta_t *sta; - - /* allocate a new one */ - if (!weth->stafree) { - DHD_INFO(("wet_sta_alloc: no room for another STA\n")); - return -1; - } - sta = weth->stafree; - weth->stafree = sta->next; - - /* init them just in case */ - sta->next = NULL; - sta->next_ip = NULL; - sta->next_mac = NULL; - - *saddr = sta; - return 0; -} - -/* update IP/MAC mapping entry and hash - * Returns 0 if succeeded; < 0 otherwise. - */ -static int -BCMFASTPATH(wet_sta_update_all)(dhd_wet_info_t *weth, uint8 *iaddr, struct ether_addr *eaddr, - wet_sta_t **saddr) -{ - wet_sta_t *sta; - int i; - char eabuf[ETHER_ADDR_STR_LEN]; - BCM_REFERENCE(eabuf); - - /* find the existing one and remove it from the old IP hash link */ - if (!wet_sta_find_mac(weth, eaddr, &sta)) { - i = WET_STA_HASH_IP(sta->ip); - if (bcmp(sta->ip, iaddr, IPV4_ADDR_LEN)) { - wet_sta_t *sta2, **next; - for (next = &weth->stahash_ip[i], sta2 = *next; - sta2; sta2 = sta2->next_ip) { - if (sta2 == sta) - break; - next = &sta2->next_ip; - } - if (sta2) { - *next = sta2->next_ip; - sta2->next_ip = NULL; - } - i = WET_STA_HASH_UNK; - } - } - /* allocate a new one and hash it by MAC */ - else if (!wet_sta_alloc(weth, &sta)) { - i = WET_STA_HASH_MAC(eaddr->octet); - bcopy(eaddr, &sta->mac, ETHER_ADDR_LEN); - sta->next_mac = weth->stahash_mac[i]; - weth->stahash_mac[i] = sta; - i = WET_STA_HASH_UNK; - } - /* bail out if we can't find nor create any */ - else { - DHD_INFO(("wet_sta_update_all: unable to alloc STA %u.%u.%u.%u %s\n", - iaddr[0], iaddr[1], iaddr[2], iaddr[3], - bcm_ether_ntoa(eaddr, eabuf))); - return -1; - } - - /* update IP and hash by new IP */ - if (i == WET_STA_HASH_UNK) { - i = WET_STA_HASH_IP(iaddr); - bcopy(iaddr, sta->ip, IPV4_ADDR_LEN); - sta->next_ip = weth->stahash_ip[i]; - weth->stahash_ip[i] = sta; - - /* start here and look for other entries with same IP address */ - { - wet_sta_t *sta2, *prev; - prev = sta; - for (sta2 = sta->next_ip; sta2; sta2 = sta2->next_ip) { - /* does this entry have the same IP address? */ - if (!bcmp(sta->ip, sta2->ip, IPV4_ADDR_LEN)) { - /* sta2 currently points to the entry we need to remove */ - /* fix next pointers */ - prev->next_ip = sta2->next_ip; - sta2->next_ip = NULL; - /* now we need to find this guy in the MAC list and - remove it from that list too. - */ - wet_sta_remove_mac_entry(weth, &sta2->mac); - /* entry should be completely out of the table now, - add it to the free list - */ - memset(sta2, 0, sizeof(wet_sta_t)); - sta2->next = weth->stafree; - weth->stafree = sta2; - - sta2 = prev; - } - prev = sta2; - } - } - } - - *saddr = sta; - return 0; -} - -/* update IP/MAC mapping entry and hash */ -static int -BCMFASTPATH(wet_sta_update_mac)(dhd_wet_info_t *weth, struct ether_addr *eaddr, wet_sta_t **saddr) -{ - wet_sta_t *sta; - int i; - char eabuf[ETHER_ADDR_STR_LEN]; - BCM_REFERENCE(eabuf); - - /* find the existing one */ - if (!wet_sta_find_mac(weth, eaddr, &sta)) - ; - /* allocate a new one and hash it */ - else if (!wet_sta_alloc(weth, &sta)) { - i = WET_STA_HASH_MAC(eaddr->octet); - bcopy(eaddr, &sta->mac, ETHER_ADDR_LEN); - sta->next_mac = weth->stahash_mac[i]; - weth->stahash_mac[i] = sta; - } - /* bail out if we can't find nor create any */ - else { - DHD_INFO(("wet_sta_update_mac: unable to alloc STA %s\n", - bcm_ether_ntoa(eaddr, eabuf))); - return -1; - } - - *saddr = sta; - return 0; -} - -/* Remove MAC entry from hash list - * NOTE: This only removes the entry matching "eaddr" from the MAC - * list. The caller needs to remove from the IP list and - * put back onto the free list to completely remove the entry - * from the WET table. - */ -static int -BCMFASTPATH(wet_sta_remove_mac_entry)(dhd_wet_info_t *weth, struct ether_addr *eaddr) -{ - wet_sta_t *sta, *prev; - int i = WET_STA_HASH_MAC(eaddr->octet); - char eabuf[ETHER_ADDR_STR_LEN]; - int found = 0; - BCM_REFERENCE(eabuf); - - /* find the existing one */ - for (sta = prev = weth->stahash_mac[i]; sta; sta = sta->next_mac) { - if (!bcmp(&sta->mac, eaddr, ETHER_ADDR_LEN)) { - found = 1; - break; - } - prev = sta; - } - - /* bail out if we can't find */ - if (!found) { - DHD_INFO(("wet_sta_remove_mac_entry: unable to find STA %s entry\n", - bcm_ether_ntoa(eaddr, eabuf))); - return -1; - } - - /* fix the list */ - if (prev == sta) - weth->stahash_mac[i] = sta->next_mac; /* removing first entry in this bucket */ - else - prev->next_mac = sta->next_mac; - - return 0; -} - -/* find IP/MAC mapping entry by IP address - * Returns 0 if succeeded; < 0 otherwise. - */ -static int -BCMFASTPATH(wet_sta_find_ip)(dhd_wet_info_t *weth, uint8 *iaddr, wet_sta_t **saddr) -{ - int i = WET_STA_HASH_IP(iaddr); - wet_sta_t *sta; - - /* find the existing one by IP */ - for (sta = weth->stahash_ip[i]; sta; sta = sta->next_ip) { - if (bcmp(sta->ip, iaddr, IPV4_ADDR_LEN)) - continue; - *saddr = sta; - return 0; - } - - /* sta has not been learned */ - DHD_INFO(("wet_sta_find_ip: unable to find STA %u.%u.%u.%u\n", - iaddr[0], iaddr[1], iaddr[2], iaddr[3])); - return -1; -} - -/* find IP/MAC mapping entry by MAC address - * Returns 0 if succeeded; < 0 otherwise. - */ -static int -BCMFASTPATH(wet_sta_find_mac)(dhd_wet_info_t *weth, struct ether_addr *eaddr, wet_sta_t **saddr) -{ - int i = WET_STA_HASH_MAC(eaddr->octet); - wet_sta_t *sta; - char eabuf[ETHER_ADDR_STR_LEN]; - BCM_REFERENCE(eabuf); - - /* find the existing one by MAC */ - for (sta = weth->stahash_mac[i]; sta; sta = sta->next_mac) { - if (bcmp(&sta->mac, eaddr, ETHER_ADDR_LEN)) - continue; - *saddr = sta; - return 0; - } - - /* sta has not been learnt */ - DHD_INFO(("wet_sta_find_mac: unable to find STA %s\n", - bcm_ether_ntoa(eaddr, eabuf))); - return -1; -} - -/* Adjust 16 bit checksum - taken from RFC 3022. - * - * The algorithm below is applicable only for even offsets (i.e., optr - * below must be at an even offset from start of header) and even lengths - * (i.e., olen and nlen below must be even). - */ -static void -BCMFASTPATH(csum_fixup_16)(uint8 *chksum, uint8 *optr, int olen, uint8 *nptr, int nlen) -{ - long x, old, new; - - ASSERT(!((uintptr_t)optr&1) && !(olen&1)); - ASSERT(!((uintptr_t)nptr&1) && !(nlen&1)); - - x = (chksum[0]<< 8)+chksum[1]; - if (!x) - return; - x = ~x & 0xFFFF; - while (olen) - { - old = (optr[0]<< 8)+optr[1]; optr += 2; - x -= old & 0xffff; - if (x <= 0) { x--; x &= 0xffff; } - olen -= 2; - } - while (nlen) - { - new = (nptr[0]<< 8)+nptr[1]; nptr += 2; - x += new & 0xffff; - if (x & 0x10000) { x++; x &= 0xffff; } - nlen -= 2; - } - x = ~x & 0xFFFF; - chksum[0] = (uint8)(x >> 8); chksum[1] = (uint8)x; -} - -/* Process frames in transmit direction by replacing source MAC with - * wireless's and keep track of IP MAC address mapping table. - * Return: - * = 0 if frame is done ok; - * < 0 if unable to handle the frame; - * - * To avoid other interfaces to see our changes specially - * changes to broadcast frame which definitely will be seen by - * other bridged interfaces we must copy the frame to our own - * buffer, modify it, and then sent it. - * Return the new sdu in 'new'. - */ -int -BCMFASTPATH(dhd_wet_send_proc)(void *wet, void *sdu, void **new) -{ - dhd_wet_info_t *weth = (dhd_wet_info_t *)wet; - uint8 *frame = PKTDATA(WETOSH(weth), sdu); - int length = PKTLEN(WETOSH(weth), sdu); - void *pkt = sdu; - - /* - * FIXME: need to tell if buffer is shared and only - * do copy on shared buffer. - */ - /* - * copy broadcast/multicast frame to our own packet - * otherwise we will screw up others because we alter - * the frame content. - */ - if (length < ETHER_HDR_LEN) { - DHD_ERROR(("dhd_wet_send_proc: unable to process short frame\n")); - return -1; - } - if (ETHER_ISMULTI(frame)) { - length = pkttotlen(WETOSH(weth), sdu); - if (!(pkt = PKTGET(WETOSH(weth), length, TRUE))) { - DHD_ERROR(("dhd_wet_send_proc: unable to alloc, dropped\n")); - return -1; - } - frame = PKTDATA(WETOSH(weth), pkt); - pktcopy(WETOSH(weth), sdu, 0, length, frame); - /* Transfer priority */ - PKTSETPRIO(pkt, PKTPRIO(sdu)); - PKTFREE(WETOSH(weth), sdu, TRUE); - PKTSETLEN(WETOSH(weth), pkt, length); - } - *new = pkt; - - /* process frame */ - return wet_eth_proc(weth, sdu, frame, length, 1) < 0 ? -1 : 0; -} - -/* - * Process frames in receive direction by replacing destination MAC with - * the one found in IP MAC address mapping table. - * Return: - * = 0 if frame is done ok; - * < 0 if unable to handle the frame; - */ -int -BCMFASTPATH(dhd_wet_recv_proc)(void *wet, void *sdu) -{ - dhd_wet_info_t *weth = (dhd_wet_info_t *)wet; - /* process frame */ - return wet_eth_proc(weth, sdu, PKTDATA(WETOSH(weth), sdu), - PKTLEN(WETOSH(weth), sdu), 0) < 0 ? -1 : 0; -} - -/* Delete WET Database */ -void -dhd_wet_sta_delete_list(dhd_pub_t *dhd_pub) -{ - wet_sta_t *sta; - int i, j; - dhd_wet_info_t *weth = dhd_pub->wet_info; - - for (i = 0; i < WET_STA_HASH_SIZE; i ++) { - for (sta = weth->stahash_mac[i]; sta; sta = sta->next_mac) { - wet_sta_t *sta2, **next; - j = WET_STA_HASH_IP(sta->ip); - for (next = &weth->stahash_ip[j], sta2 = *next; - sta2; sta2 = sta2->next_ip) { - if (sta2 == sta) - break; - next = &sta2->next_ip; - } - if (sta2) { - *next = sta2->next_ip; - sta2->next_ip = NULL; - } - j = WET_STA_HASH_UNK; - - wet_sta_remove_mac_entry(weth, &sta->mac); - memset(sta, 0, sizeof(wet_sta_t)); - } - } -} -void -dhd_wet_dump(dhd_pub_t *dhdp, struct bcmstrbuf *b) -{ - char eabuf[ETHER_ADDR_STR_LEN]; - wet_sta_t *sta; - int i; - dhd_wet_info_t *weth = dhdp->wet_info; - - bcm_bprintf(b, "Host MAC: %s\n", bcm_ether_ntoa(&weth->mac, eabuf)); - bcm_bprintf(b, "Host IP: %u.%u.%u.%u\n", - weth->ip[0], weth->ip[1], weth->ip[2], weth->ip[3]); - bcm_bprintf(b, "Entry\tEnetAddr\t\tInetAddr\n"); - for (i = 0; i < WET_NUMSTAS; i ++) { - /* FIXME: it leaves the last sta entry unfiltered, who cares! */ - if (weth->sta[i].next) - continue; - /* format the entry dump */ - sta = &weth->sta[i]; - bcm_bprintf(b, "%u\t%s\t%u.%u.%u.%u\n", - i, bcm_ether_ntoa(&sta->mac, eabuf), - sta->ip[0], sta->ip[1], sta->ip[2], sta->ip[3]); - } -} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wet.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wet.h deleted file mode 100755 index 21b84296467d..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wet.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Wireless Ethernet (WET) interface - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - */ - -/** XXX Twiki: [WirelessEthernet] */ - -#ifndef _dhd_wet_h_ -#define _dhd_wet_h_ - -#include -#include -#include - -#define DHD_WET_ENAB 1 -#define WET_ENABLED(dhdp) ((dhdp)->info->wet_mode == DHD_WET_ENAB) - -/* forward declaration */ -typedef struct dhd_wet_info dhd_wet_info_t; - -extern dhd_wet_info_t *dhd_get_wet_info(dhd_pub_t *pub); -extern void dhd_free_wet_info(dhd_pub_t *pub, void *wet); - -/* Process frames in transmit direction */ -extern int dhd_wet_send_proc(void *weth, void *sdu, void **new); -extern void dhd_set_wet_host_ipv4(dhd_pub_t *pub, void *parms, uint32 len); -extern void dhd_set_wet_host_mac(dhd_pub_t *pub, void *parms, uint32 len); -/* Process frames in receive direction */ -extern int dhd_wet_recv_proc(void *weth, void *sdu); -extern void dhd_wet_sta_delete_list(dhd_pub_t *dhd_pub); - -#ifdef PLC_WET -extern void dhd_wet_bssid_upd(dhd_wet_info_t *weth, dhd_bsscfg_t *cfg); -#endif /* PLC_WET */ - -int dhd_set_wet_mode(dhd_pub_t *dhdp, uint32 val); -int dhd_get_wet_mode(dhd_pub_t *dhdp); -extern void dhd_wet_dump(dhd_pub_t *dhdp, struct bcmstrbuf *b); - -#endif /* _dhd_wet_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c old mode 100755 new mode 100644 index 11283aa94db8..a27156026ff1 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c @@ -1,7 +1,7 @@ /* * DHD PROP_TXSTATUS Module. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -59,7 +60,7 @@ * */ -#if defined (DHD_WLFC_THREAD) +#if defined(DHD_WLFC_THREAD) #define WLFC_THREAD_QUICK_RETRY_WAIT_MS 10 /* 10 msec */ #define WLFC_THREAD_RETRY_WAIT_MS 10000 /* 10 sec */ #endif /* defined (DHD_WLFC_THREAD) */ @@ -72,122 +73,6 @@ #define DHD_WLFC_QMON_COMPLETE(entry) #endif /* QMONITOR */ -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - -/** for 'out of order' debug */ -static void -_dhd_wlfc_bprint(athost_wl_status_info_t* wlfc, const char *fmt, ...) -{ - va_list ap; - int r, size; - uint8 *buf; - bool bRetry = FALSE; - - if (!wlfc || !wlfc->log_buf) { - return; - } - - va_start(ap, fmt); - -retry: - buf = wlfc->log_buf + wlfc->log_buf_offset; - size = WLFC_LOG_BUF_SIZE -1 - wlfc->log_buf_offset; - - r = vsnprintf(buf, size, fmt, ap); - /* Non Ansi C99 compliant returns -1, - * Ansi compliant return r >= b->size, - * bcmstdlib returns 0, handle all - */ - /* r == 0 is also the case when strlen(fmt) is zero. - * typically the case when "" is passed as argument. - */ - if ((r == -1) || (r >= size)) { - bRetry = TRUE; - } else { - wlfc->log_buf_offset += r; - } - - if ((wlfc->log_buf_offset >= (WLFC_LOG_BUF_SIZE -1)) || bRetry) { - wlfc->log_buf[wlfc->log_buf_offset] = 0; - wlfc->log_buf_offset = 0; - if (!wlfc->log_buf_full) { - wlfc->log_buf_full = TRUE; - } - - if (bRetry) { - bRetry = FALSE; - goto retry; - } - } - - va_end(ap); - - return; -} /* _dhd_wlfc_bprint */ - -/** for 'out of order' debug */ -static void _dhd_wlfc_print_1k_buf(uint8* buf, int size) -{ - /* print last 1024 bytes */ - if (size > 1024) { - buf += (size - 1024); - } - printf("%s", buf); -} - -/** for 'out of order' debug */ -static void -_dhd_wlfc_print_log(athost_wl_status_info_t* wlfc) -{ - if (!wlfc || !wlfc->log_buf) { - return; - } - - printf("%s: log_buf_full(%d), log_buf_offset(%d)\n", - __FUNCTION__, wlfc->log_buf_full, wlfc->log_buf_offset); - if (wlfc->log_buf_full) { - _dhd_wlfc_print_1k_buf(wlfc->log_buf + wlfc->log_buf_offset, - WLFC_LOG_BUF_SIZE - wlfc->log_buf_offset); - } - wlfc->log_buf[wlfc->log_buf_offset] = 0; - _dhd_wlfc_print_1k_buf(wlfc->log_buf, wlfc->log_buf_offset); - printf("\n%s: done\n", __FUNCTION__); - - wlfc->log_buf_offset = 0; - wlfc->log_buf_full = FALSE; -} - -/** for 'out of order' debug */ -static void -_dhd_wlfc_check_send_order(athost_wl_status_info_t* wlfc, wlfc_mac_descriptor_t* entry, void* p) -{ - uint8 seq = WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - uint8 gen = WL_TXSTATUS_GET_GENERATION(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - uint8 prec = DHD_PKTTAG_FIFO(PKTTAG(p)); - - if ((entry->last_send_gen[prec] == gen) && - ((uint8)(entry->last_send_seq[prec] + 1) > seq)) { - printf("%s: prec(%d), last(%u), p(%u)\n", - __FUNCTION__, prec, entry->last_send_seq[prec], seq); - _dhd_wlfc_print_log(wlfc); - } - - entry->last_send_seq[prec] = seq; - entry->last_send_gen[prec] = gen; -} - -/** for 'out of order' debug */ -static void -_dhd_wlfc_check_complete_order(athost_wl_status_info_t* wlfc, wlfc_mac_descriptor_t* entry, void* p) -{ - uint8 seq = WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - uint8 prec = DHD_PKTTAG_FIFO(PKTTAG(p)); - - entry->last_complete_seq[prec] = seq; -} - -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ - /** reordering related */ #if defined(DHD_WLFC_THREAD) @@ -1059,6 +944,12 @@ _dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint dhdp = (dhd_pub_t *)ctx->dhdp; ASSERT(dhdp); + /* Return for the bc/mc and unknown destinations configured by + * &wlfc->destination_entries.other to prevent from out-of-boundary access + * in array (BRK exception) kernel panic issue. */ + if (if_id >= WLFC_MAX_IFNUM) + return; + if (dhdp->skip_fc && dhdp->skip_fc((void *)dhdp, if_id)) return; @@ -1281,10 +1172,6 @@ _dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, } gen = entry->generation; free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(ctx, "d%u.%u.%u-", - (uint8)(entry - &ctx->destination_entries.nodes[0]), gen, free_ctr); -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ } else { if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { htodseq = DHD_PKTTAG_H2DSEQ(PKTTAG(p)); @@ -1301,15 +1188,6 @@ _dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, } free_ctr = WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))); -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(ctx, "s%u.%u.%u-", - (uint8)(entry - &ctx->destination_entries.nodes[0]), gen, free_ctr); - if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { - _dhd_wlfc_bprint(ctx, "%u.%u-", - IS_WL_TO_REUSE_SEQ(DHD_PKTTAG_H2DSEQ(PKTTAG(p))), - WL_SEQ_GET_NUM(DHD_PKTTAG_H2DSEQ(PKTTAG(p)))); - } -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ /* remove old header */ _dhd_wlfc_pullheader(ctx, p); } @@ -1767,9 +1645,6 @@ _dhd_wlfc_pktq_flush(athost_wl_status_info_t* ctx, struct pktq *pq, (!entry->onbus_pkts_count) && (!entry->suppr_transit_count)) entry->suppressed = FALSE; -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(ctx, "[sc]-"); -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ } _dhd_wlfc_return_implied_credit(ctx, p); ctx->stats.cleanup_fw_cnt++; @@ -1807,6 +1682,7 @@ _dhd_wlfc_pktq_flush(athost_wl_status_info_t* ctx, struct pktq *pq, } /* _dhd_wlfc_pktq_flush */ #ifndef BCMDBUS + /** !BCMDBUS specific function. Dequeues a packet from the caller supplied queue. */ static void* _dhd_wlfc_pktq_pdeq_with_fn(struct pktq *pq, int prec, f_processpkt_t fn, void *arg) @@ -1906,9 +1782,6 @@ _dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) (!entry->onbus_pkts_count) && (!entry->suppr_transit_count)) entry->suppressed = FALSE; -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(wlfc, "[sc]-"); -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ } _dhd_wlfc_return_implied_credit(wlfc, pkt); wlfc->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(pkt))][DHD_PKTTAG_FIFO(PKTTAG(pkt))]--; @@ -2063,12 +1936,6 @@ _dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* (int)(entry - &ctx->destination_entries.nodes[0]))); } } -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - for (i = 0; i < (AC_COUNT + 1); i++) { - entry->last_send_seq[i] = 255; - entry->last_complete_seq[i] = 255; - } -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ } else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { /* When the entry is deleted, the packets that are queued in the entry must be cleanup. The cleanup action should be before the occupied is set as 0. @@ -2256,9 +2123,6 @@ _dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, &commit_info->p, commit_info->needs_hdr, &hslot); -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_check_send_order(ctx, commit_info->mac_entry, commit_info->p); -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ if (rc == BCME_OK) { rc = fcommit(commit_ctx, commit_info->p); if (rc == BCME_OK) { @@ -2277,10 +2141,6 @@ _dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, commit_info->mac_entry->suppressed = TRUE; } commit_info->mac_entry->suppr_transit_count++; -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(ctx, "[si%u]-", - commit_info->mac_entry->suppr_transit_count); -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ } commit_info->mac_entry->transit_count++; commit_info->mac_entry->onbus_pkts_count++; @@ -2535,19 +2395,8 @@ _dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len, } entry->suppressed = TRUE; -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(wlfc, "[ss%u.%u.%u]-", - (uint8)(entry - &wlfc->destination_entries.nodes[0]), - entry->generation, - entry->suppr_transit_count); -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ } entry->generation = gen; -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - if (gen == WL_TXSTATUS_GET_GENERATION(DHD_PKTTAG_H2DTAG(PKTTAG(pktbuf)))) { - printf("==%d.%d==\n", gen, hcnt); - } -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ } #ifdef PROP_TXSTATUS_DEBUG @@ -2603,13 +2452,6 @@ _dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len, ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); if (ret != BCME_OK) { -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(wlfc, "f%u.%u.%u-", - (uint8)(entry - &wlfc->destination_entries.nodes[0]), - gen, - hcnt); - _dhd_wlfc_check_complete_order(wlfc, entry, pktbuf); -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ /* delay q is full, drop this packet */ DHD_WLFC_QMON_COMPLETE(entry); _dhd_wlfc_prec_drop(dhd, (fifo_id << 1) + 1, pktbuf, FALSE); @@ -2620,27 +2462,8 @@ _dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len, */ _dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, hslot, gen); } -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(wlfc, "r%u.%u.%u.%u-", - status_flag, - (uint8)(entry - &wlfc->destination_entries.nodes[0]), - gen, - hcnt); - if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { - _dhd_wlfc_bprint(wlfc, "%u.%u-", seq_fromfw, seq_num); - } - -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ } } else { -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(wlfc, "c%u.%u.%u.%u-", - status_flag, - (uint8)(entry - &wlfc->destination_entries.nodes[0]), - gen, - hcnt); - _dhd_wlfc_check_complete_order(wlfc, entry, pktbuf); -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ DHD_WLFC_QMON_COMPLETE(entry); @@ -2665,9 +2488,6 @@ _dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len, (!entry->onbus_pkts_count) && (!entry->suppr_transit_count)) entry->suppressed = FALSE; -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(wlfc, "[sc]-"); -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ } cont: @@ -2741,6 +2561,7 @@ _dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) } /* _dhd_wlfc_fifocreditback_indicate */ #ifndef BCMDBUS + /** !BCMDBUS specific function */ static void _dhd_wlfc_suppress_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) @@ -2984,19 +2805,9 @@ _dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) desc->requested_credit = 0; desc->requested_packet = 0; _dhd_wlfc_remove_requested_entry(wlfc, desc); -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(wlfc, "[op%u.%u]-", - (uint8)(table - &wlfc->destination_entries.nodes[0]), - OSL_SYSUPTIME()); -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ } else { desc->state = WLFC_STATE_CLOSE; DHD_WLFC_CTRINC_MAC_CLOSE(desc); -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(wlfc, "[cl%u.%u]-", - (uint8)(table - &wlfc->destination_entries.nodes[0]), - OSL_SYSUPTIME()); -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ /* Indicate to firmware if there is any traffic pending. */ for (i = 0; i < AC_COUNT; i++) { _dhd_wlfc_traffic_pending_check(wlfc, desc, i); @@ -3032,19 +2843,9 @@ _dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { table[if_id].state = WLFC_STATE_OPEN; /* WLFC_DBGMESG(("INTERFACE[%d] OPEN\n", if_id)); */ -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(wlfc, "[op%u.%u]-", - (uint8)(table - &wlfc->destination_entries.nodes[0]), - OSL_SYSUPTIME()); -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ } else { table[if_id].state = WLFC_STATE_CLOSE; /* WLFC_DBGMESG(("INTERFACE[%d] CLOSE\n", if_id)); */ -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - _dhd_wlfc_bprint(wlfc, "[cl%u.%u]-", - (uint8)(table - &wlfc->destination_entries.nodes[0]), - OSL_SYSUPTIME()); -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ } return BCME_OK; } @@ -3222,7 +3023,7 @@ int dhd_wlfc_enable(dhd_pub_t *dhd) dhd->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; /* default to check rx pkt */ dhd->wlfc_rxpkt_chk = TRUE; -#if defined (LINUX) || defined(linux) +#if defined(LINUX) || defined(linux) if (dhd->op_mode & DHD_FLAG_IBSS_MODE) { dhd->wlfc_rxpkt_chk = FALSE; } @@ -3240,13 +3041,6 @@ int dhd_wlfc_enable(dhd_pub_t *dhd) wlfc->single_ac = 0; wlfc->single_ac_timestamp = 0; -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - wlfc->log_buf = MALLOC(dhd->osh, WLFC_LOG_BUF_SIZE); - wlfc->log_buf[WLFC_LOG_BUF_SIZE - 1] = 0; - wlfc->log_buf_offset = 0; - wlfc->log_buf_full = FALSE; -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ - exit: DHD_ERROR(("%s: ret=%d\n", __FUNCTION__, rc)); dhd_os_wlfc_unblock(dhd); @@ -4147,14 +3941,6 @@ dhd_wlfc_deinit(dhd_pub_t *dhd) _dhd_wlfc_hanger_delete(dhd, h); } -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - if (wlfc->log_buf) { - MFREE(dhd->osh, wlfc->log_buf, WLFC_LOG_BUF_SIZE); - wlfc->log_buf_offset = 0; - wlfc->log_buf_full = FALSE; - } -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ - /* free top structure */ DHD_OS_PREFREE(dhd, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); @@ -4949,8 +4735,17 @@ int dhd_txpkt_log_and_dump(dhd_pub_t *dhdp, void* pkt, uint16 *pktfate_status) pktlen -= bdc_len; pktdata = pktdata + bdc_len; #endif /* BDC */ + +#if defined(DBG_PKT_MON) + if (pktfate_status) { + DHD_DBG_PKT_MON_TX_STATUS(dhdp, pkt, pktid, *pktfate_status); + } else { + DHD_DBG_PKT_MON_TX(dhdp, pkt, pktid, FRAME_TYPE_ETHERNET_II, 0); + } +#endif + dhd_handle_pktdata(dhdp, ifidx, pkt, pktdata, pktid, pktlen, - pktfate_status, NULL, TRUE, FALSE, TRUE); + pktfate_status, NULL, NULL, TRUE, FALSE, TRUE); return BCME_OK; } diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h old mode 100755 new mode 100644 index 1089a2f063fe..aac58fe89e03 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -112,8 +112,8 @@ typedef struct wlfc_hanger { #define WLFC_PSQ_LEN (4096 * 8) #ifdef BCMDBUS -#define WLFC_FLOWCONTROL_HIWATER 512 -#define WLFC_FLOWCONTROL_LOWATER (WLFC_FLOWCONTROL_HIWATER / 4) +#define WLFC_FLOWCONTROL_HIWATER ((4096 * 8) - 256) +#define WLFC_FLOWCONTROL_LOWATER 256 #else #define WLFC_FLOWCONTROL_HIWATER ((4096 * 8) - 256) #define WLFC_FLOWCONTROL_LOWATER 256 @@ -145,11 +145,6 @@ typedef struct wlfc_mac_descriptor { struct pktq psq; /**< contains both 'delayed' and 'suppressed' packets */ /** packets at firmware queue */ struct pktq afq; -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - uint8 last_send_gen[AC_COUNT+1]; - uint8 last_send_seq[AC_COUNT+1]; - uint8 last_complete_seq[AC_COUNT+1]; -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ /** The AC pending bitmap that was reported to the fw at last change */ uint8 traffic_lastreported_bmp; /** The new AC pending bitmap */ @@ -358,12 +353,6 @@ typedef struct athost_wl_status_info { bool bcmc_credit_supported; -#if defined(BCMINTERNAL) && defined(OOO_DEBUG) - uint8* log_buf; - uint32 log_buf_offset; - bool log_buf_full; -#endif /* defined(BCMINTERNAL) && defined(OOO_DEBUG) */ - #ifdef BULK_DEQUEUE uint8 max_release_count; #endif /* total_credit */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/frag.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/frag.c old mode 100755 new mode 100644 index e49c3351be01..e11b78a27d16 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/frag.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/frag.c @@ -2,7 +2,7 @@ * IE/TLV fragmentation/defragmentation support for * Broadcom 802.11bang Networking Device Driver * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -25,18 +25,21 @@ #include #include #include <802.11.h> +#include /* defrag a fragmented dot11 ie/tlv. if space does not permit, return the needed * ie length to contain all the fragments with status BCME_BUFTOOSHORT. * out_len is in/out parameter, max length on input, used/required length on output + * data_len is out parameter, it has the length of de-fragmented data. */ int bcm_tlv_dot11_defrag(const void *buf, uint buf_len, uint8 id, bool id_ext, - uint8 *out, uint *out_len) + uint8 *out, uint *out_len, uint *data_len) { int err = BCME_OK; const bcm_tlv_t *ie; uint tot_len = 0; + uint tot_data_len = 0; uint out_left; /* find the ie; includes validation */ @@ -49,14 +52,18 @@ bcm_tlv_dot11_defrag(const void *buf, uint buf_len, uint8 id, bool id_ext, out_left = (out && out_len) ? *out_len : 0; /* first fragment */ - tot_len = id_ext ? ie->len - 1 : ie->len; + tot_len = id_ext ? ie->len - 1u : ie->len; + tot_data_len = tot_len; /* copy out if output space permits */ if (out_left < tot_len) { err = BCME_BUFTOOSHORT; out_left = 0; /* prevent further copy */ } else { - memcpy(out, &ie->data[id_ext ? 1 : 0], tot_len); + if ((err = memcpy_s(out, out_left, &ie->data[id_ext ? 1u : 0], tot_len)) + != BCME_OK) { + goto fail; + } out += tot_len; out_left -= tot_len; } @@ -79,11 +86,13 @@ bcm_tlv_dot11_defrag(const void *buf, uint buf_len, uint8 id, bool id_ext, err = BCME_BUFTOOSHORT; out_left = 0; } else { - memcpy(out, &ie->data[0], ie->len); + if ((err = memcpy_s(out, out_left, &ie->data[0], ie->len)) != BCME_OK) { + goto fail; + } out += ie->len; out_left -= ie->len; } - + tot_data_len += ie->len; tot_len += ie->len + BCM_TLV_HDR_SIZE; /* all but last should be of max size */ @@ -96,7 +105,10 @@ done: if (out_len) { *out_len = tot_len; } - + if (data_len) { + *data_len = tot_data_len; + } +fail: return err; } @@ -104,5 +116,68 @@ int bcm_tlv_dot11_frag_tot_len(const void *buf, uint buf_len, uint8 id, bool id_ext, uint *ie_len) { - return bcm_tlv_dot11_defrag(buf, buf_len, id, id_ext, NULL, ie_len); + return bcm_tlv_dot11_defrag(buf, buf_len, id, id_ext, NULL, ie_len, NULL); +} + +int +bcm_tlv_dot11_frag_tot_data_len(const void *buf, uint buf_len, + uint8 id, bool id_ext, uint *ie_len, uint *data_len) +{ + return bcm_tlv_dot11_defrag(buf, buf_len, id, id_ext, NULL, ie_len, data_len); +} + +/* To support IE fragmentation. + * data will be fit into a series of elements consisting of one leading element + * followed by Fragment elements if needed. + * data_len is in/out parameter, it has the length of all the elements, including + * the leading element header size. + * Caller can get elements length by passing dst as NULL. + */ +int +bcm_tlv_dot11_frag(uint8 id, bool id_ext, const void *data, uint data_len, + uint8 *buf, uint *buf_len) +{ + uint8 id_ext_len = id_ext ? 1u : 0; + bool is_write = (buf != NULL); + uint8 *ie_data = NULL; + uint ie_len = 0; + uint8 num_frags = 0, last_frag_size = 0; + int err = BCME_OK; + + if ((data_len + id_ext_len) > + BCM_TLV_MAX_DATA_SIZE) { + last_frag_size = (data_len + id_ext_len) % BCM_TLV_MAX_DATA_SIZE; + num_frags = CEIL(data_len + id_ext_len, BCM_TLV_MAX_DATA_SIZE); + } else { + last_frag_size = data_len + id_ext_len; + num_frags = 1u; + } + ie_len = data_len + id_ext_len + num_frags * BCM_TLV_HDR_SIZE; + + if (is_write) { + uint len_to_copy = (num_frags > 1u) ? (uint)(BCM_TLV_MAX_DATA_SIZE - id_ext_len) : + data_len; + uint copied_len = 0; + if (ie_len > *buf_len) { + err = BCME_BUFTOOSHORT; + goto done; + } + if (id_ext) { + ie_data = bcm_write_tlv_ext(DOT11_MNG_ID_EXT_ID, id, + data, len_to_copy, buf); + } else { + ie_data = bcm_write_tlv(id, data, len_to_copy, buf); + } + while (num_frags > 1u) { + copied_len += len_to_copy; + len_to_copy = (num_frags > 2u) ? BCM_TLV_MAX_DATA_SIZE : last_frag_size; + ie_data = bcm_write_tlv(DOT11_MNG_FRAGMENT_ID, + (const uint8 *)data + copied_len, + len_to_copy, ie_data); + num_frags --; + }; + } +done: + *buf_len = ie_len; + return err; } diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/ftdi_sio_external.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/ftdi_sio_external.h deleted file mode 100755 index 8c021a12c55e..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/ftdi_sio_external.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * External driver API to ftdi_sio_brcm driver. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id: $ - */ - -typedef struct usb_serial_port * gpio_handle; - -#define BITMODE_RESET 0x00 -#define BITMODE_BITBANG 0x01 - -int ftdi_usb_reset(int handle); -int ftdi_set_bitmode(int handle, unsigned char bitmask, unsigned char mode); -int gpio_write_port(int handle, unsigned char pins); -int gpio_write_port_non_block(int handle, unsigned char pins); -int gpio_read_port(int handle, unsigned char *pins); -int handle_add(gpio_handle pointer); -int handle_remove(gpio_handle pointer); -int get_handle(const char *dev_filename); -gpio_handle get_pointer_by_handle(int handle); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/fwpkg_utils.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/fwpkg_utils.c new file mode 100644 index 000000000000..0855780562c5 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/fwpkg_utils.c @@ -0,0 +1,391 @@ +/* + * Firmware package functionality + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef BCMDRIVER +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)) +#include +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0) */ +#include +#include +#include +#include +#endif /* BCMDRIVER */ + +#include +#include +#include +#include +#include +#ifdef BCMDRIVER +#include +#else +#include +#endif /* BCMDRIVER */ +#include + +#define FWPKG_UNIT_IDX(tag) (tag-1) + +const uint32 FWPKG_HDR_MGCW0 = 0xDEAD2BAD; +const uint32 FWPKG_HDR_MGCW1 = 0xFEE1DEAD; +const uint32 FWPKG_MAX_SUPPORTED_VER = 1; + +#ifdef BCMDRIVER +#define FWPKG_ERR(msg) DHD_ERROR(msg) +#define fwpkg_open(filename) \ + dhd_os_open_image1(NULL, filename) +#define fwpkg_close(file) \ + dhd_os_close_image1(NULL, (char *)file) +#define fwpkg_seek(file, offset) \ + dhd_os_seek_file(file, offset) +#define fwpkg_read(buf, len, file) \ + dhd_os_get_image_block(buf, len, file) +#define fwpkg_getsize(file) \ + dhd_os_get_image_size(file) + +#else +#if defined(_WIN32) +#define FWPKG_ERR(fmt, ...) +#else +#define FWPKG_ERR(fmt, args...) +#endif /* defined _WIN32 */ +#define fwpkg_open(filename) \ + (void *)fopen(filename, "rb") +#define fwpkg_close(file) \ + fclose((FILE *)file) +#define fwpkg_seek(file, offset) \ + fseek((FILE *)file, offset, SEEK_SET) +#define fwpkg_read(buf, len, file) \ + app_fread(buf, len, file) +#define fwpkg_getsize(file) \ + app_getsize(file) + +#endif /* BCMDRIVER */ + +#define UNIT_TYPE_IDX(type) ((type) - 1) + +static int fwpkg_hdr_validation(fwpkg_hdr_t *hdr, uint32 pkg_len); +static bool fwpkg_parse_rtlvs(fwpkg_info_t *fwpkg, uint32 file_size, char *fname); +static int fwpkg_parse(fwpkg_info_t *fwpkg, char *fname); +static int fwpkg_open_unit(fwpkg_info_t *fwpkg, char *fname, + uint32 unit_type, FWPKG_FILE **fp); +static uint32 fwpkg_get_unit_size(fwpkg_info_t *fwpkg, uint32 unit_type); + +/* open file, if combined fw package parse common header, + * parse each unit header, keep information + */ +int +fwpkg_init(fwpkg_info_t *fwpkg, char *fname) +{ + if (fwpkg == NULL || fname == NULL) { + FWPKG_ERR(("fwpkg_init: missing argument\n")); + return BCME_ERROR; + } + /* if status already set, no need to initialize */ + if (fwpkg->status) { + return BCME_OK; + } + bzero(fwpkg, sizeof(*fwpkg)); + + return fwpkg_parse(fwpkg, fname); +} + +int +fwpkg_open_firmware_img(fwpkg_info_t *fwpkg, char *fname, FWPKG_FILE **fp) +{ + if (fwpkg == NULL || fname == NULL) { + FWPKG_ERR(("fwpkg_open_firmware: missing argument\n")); + return BCME_ERROR; + } + + return fwpkg_open_unit(fwpkg, fname, FWPKG_TAG_FW, fp); +} + +int +fwpkg_open_signature_img(fwpkg_info_t *fwpkg, char *fname, FWPKG_FILE **fp) +{ + if (fwpkg == NULL || fname == NULL) { + FWPKG_ERR(("fwpkg_open_signature: missing argument\n")); + return BCME_ERROR; + } + + return fwpkg_open_unit(fwpkg, fname, FWPKG_TAG_SIG, fp); +} + +uint32 +fwpkg_get_firmware_img_size(fwpkg_info_t *fwpkg) +{ + if (fwpkg == NULL) { + FWPKG_ERR(("fwpkg_get_firmware_size: missing argument\n")); + return 0; + } + + return fwpkg_get_unit_size(fwpkg, FWPKG_TAG_FW); +} + +uint32 +fwpkg_get_signature_img_size(fwpkg_info_t *fwpkg) +{ + if (fwpkg == NULL) { + FWPKG_ERR(("fwpkg_get_signature_img_size: missing argument\n")); + return 0; + } + + return fwpkg_get_unit_size(fwpkg, FWPKG_TAG_SIG); +} + +#ifndef BCMDRIVER +static int +app_getsize(FILE *file) +{ + int len = 0; + + fseek(file, 0, SEEK_END); + len = (int)ftell(file); + fseek(file, 0, SEEK_SET); + + return len; +} + +static int +app_fread(char *buf, int len, void *file) +{ + int status; + + status = fread(buf, sizeof(uint8), len, (FILE *)file); + if (status < len) { + status = -EINVAL; + } + + return status; +} +#endif /* !BCMDRIVER */ + +/* check package header information */ +static int +fwpkg_hdr_validation(fwpkg_hdr_t *hdr, uint32 pkg_len) +{ + int ret = BCME_ERROR; + uint32 len = 0; + + /* check megic word0 */ + len += sizeof(hdr->magic_word0); + if (hdr->magic_word0 != FWPKG_HDR_MGCW0) { + ret = BCME_UNSUPPORTED; + goto done; + } + /* check megic word1 */ + len += sizeof(hdr->magic_word1); + if (hdr->magic_word1 != FWPKG_HDR_MGCW1) { + goto done; + } + /* check length */ + len += sizeof(hdr->length); + if (hdr->length != (pkg_len - len)) { + goto done; + } + /* check version */ + if (hdr->version > FWPKG_MAX_SUPPORTED_VER) { + goto done; + } + + ret = BCME_OK; +done: + return ret; +} + +/* parse rtlvs in combined fw package */ +static bool +fwpkg_parse_rtlvs(fwpkg_info_t *fwpkg, uint32 file_size, char *fname) +{ + bool ret = FALSE; + const uint32 l_len = sizeof(uint32); /* len of rTLV's field length */ + const uint32 t_len = sizeof(uint32); /* len of rTLV's field type */ + uint32 unit_size = 0, unit_type = 0; + FWPKG_FILE *file = NULL; + uint32 left_size = file_size - sizeof(fwpkg_hdr_t); + + while (left_size) { + file = fwpkg_open(fname); + if (file == NULL) { + FWPKG_ERR(("fwpkg_parse_rtlvs: open file fails\n")); + goto done; + } + + /* remove length of rTLV's fields type, length */ + left_size -= (t_len + l_len); + if (fwpkg_seek(file, left_size) != BCME_OK) { + FWPKG_ERR(("fwpkg_parse_rtlvs: can't get to the rtlv position\n")); + goto done; + } + if (fwpkg_read((char *)&unit_size, l_len, file) < 0) { + FWPKG_ERR(("fwpkg_parse_rtlvs: can't read rtlv data len\n")); + goto done; + } + if (fwpkg_read((char *)&unit_type, t_len, file) < 0) { + FWPKG_ERR(("fwpkg_parse_rtlvs: can't read rtlv data type\n")); + goto done; + } + if ((unit_type == 0) || (unit_type >= FWPKG_TAG_LAST)) { + FWPKG_ERR(("fwpkg_parse_rtlvs: unsupported data type(%d)\n", + unit_type)); + goto done; + } + fwpkg->units[UNIT_TYPE_IDX(unit_type)].type = unit_type; + fwpkg->units[UNIT_TYPE_IDX(unit_type)].size = unit_size; + left_size -= unit_size; + fwpkg->units[UNIT_TYPE_IDX(unit_type)].offset = left_size; + + FWPKG_ERR(("fwpkg_parse_rtlvs: type x%04x, len %d, off %d\n", + unit_type, unit_size, left_size)); + + fwpkg_close(file); + file = NULL; + } + + ret = TRUE; +done: + if (file) { + fwpkg_close(file); + } + return ret; +} + +/* parse file if is combined fw package */ +static int +fwpkg_parse(fwpkg_info_t *fwpkg, char *fname) +{ + int ret = BCME_ERROR; + int file_size = 0; + fwpkg_hdr_t hdr = {0}; + FWPKG_FILE *file = NULL; + + file = fwpkg_open(fname); + if (file == NULL) { + FWPKG_ERR(("fwpkg_parse: open file %s fails\n", fname)); + goto done; + } + file_size = fwpkg_getsize(file); + if (!file_size) { + FWPKG_ERR(("fwpkg_parse: get file size fails\n")); + goto done; + } + /* seek to the last sizeof(fwpkg_hdr_t) bytes in the file */ + if (fwpkg_seek(file, file_size-sizeof(fwpkg_hdr_t)) != BCME_OK) { + FWPKG_ERR(("fwpkg_parse: can't get to the pkg header offset\n")); + goto done; + } + /* read the last sizeof(fwpkg_hdr_t) bytes of the file to a buffer */ + if (fwpkg_read((char *)&hdr, sizeof(fwpkg_hdr_t), file) < 0) { + FWPKG_ERR(("fwpkg_parse: can't read from the pkg header offset\n")); + goto done; + } + fwpkg_close(file); + file = NULL; + + /* if combined firmware package validates it's common header + * otherwise return BCME_UNSUPPORTED as it may be + * another type of firmware binary + */ + ret = fwpkg_hdr_validation(&hdr, file_size); + if (ret == BCME_ERROR) { + FWPKG_ERR(("fwpkg_parse: can't parse pkg header\n")); + goto done; + } + /* parse rTLVs only in case of combined firmware package */ + if (ret == BCME_OK) { + fwpkg->status = FWPKG_COMBND_FLG; + if (fwpkg_parse_rtlvs(fwpkg, file_size, fname) == FALSE) { + FWPKG_ERR(("fwpkg_parse: can't parse rtlvs\n")); + ret = BCME_ERROR; + goto done; + } + } else { + fwpkg->status = FWPKG_SINGLE_FLG; + } + + fwpkg->file_size = file_size; +done: + if (file) { + fwpkg_close(file); + } + + return ret; +} + +/* + * opens the package file and seek to requested unit. + * in case of single binary file just open the file. + */ +static int +fwpkg_open_unit(fwpkg_info_t *fwpkg, char *fname, uint32 unit_type, FWPKG_FILE **fp) +{ + int ret = BCME_OK; + fwpkg_unit_t *fw_unit = NULL; + + *fp = fwpkg_open(fname); + if (*fp == NULL) { + FWPKG_ERR(("fwpkg_open_unit: open file %s fails\n", fname)); + ret = BCME_ERROR; + goto done; + } + + /* successfully opened file while status is FWPKG_SINGLE_FLG + * means, this is single binary file format. + */ + if (IS_FWPKG_SINGLE(fwpkg)) { + fwpkg->file_size = fwpkg_getsize(*fp); + ret = BCME_UNSUPPORTED; + goto done; + } + + fw_unit = &fwpkg->units[FWPKG_UNIT_IDX(unit_type)]; + + /* seek to the last sizeof(fwpkg_hdr_t) bytes in the file */ + if (fwpkg_seek(*fp, fw_unit->offset) != BCME_OK) { + FWPKG_ERR(("fwpkg_open_unit: can't get to the pkg header offset\n")); + ret = BCME_ERROR; + goto done; + } + +done: + return ret; +} + +static uint32 +fwpkg_get_unit_size(fwpkg_info_t *fwpkg, uint32 unit_type) +{ + fwpkg_unit_t *fw_unit = NULL; + uint32 size; + + if (IS_FWPKG_SINGLE(fwpkg)) { + size = fwpkg->file_size; + goto done; + } + + fw_unit = &fwpkg->units[FWPKG_UNIT_IDX(unit_type)]; + size = fw_unit->size; + +done: + return size; +} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hnd_pktpool.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hnd_pktpool.c old mode 100755 new mode 100644 index eee518a78515..57a330d735ec --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hnd_pktpool.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hnd_pktpool.c @@ -1,7 +1,7 @@ /* * HND generic packet pool operation primitives * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -54,11 +54,6 @@ #define HND_PKTPOOL_MUTEX_RELEASE(mutex) OSL_EXT_SUCCESS #endif -/* Registry size is one larger than max pools, as slot #0 is reserved */ -#define PKTPOOLREG_RSVD_ID (0U) -#define PKTPOOLREG_RSVD_PTR (POOLPTR(0xdeaddead)) -#define PKTPOOLREG_FREE_PTR (POOLPTR(NULL)) - #define PKTPOOL_REGISTRY_SET(id, pp) (pktpool_registry_set((id), (pp))) #define PKTPOOL_REGISTRY_CMP(id, pp) (pktpool_registry_cmp((id), (pp))) @@ -98,7 +93,30 @@ uint32 total_pool_pktid_count = PKTID_POOL; uint32 total_pool_pktid_count = 0U; #endif /* DONGLEBUILD */ +int last_alloc_err = 0; /* Error reported during last alloc failure */ + +#if defined(BCMPKTIDMAP) || defined(BCMPKTIDMAP_MIN) +#define TOTAL_POOL_PKTID_CNT_INC(pktp) \ + do { \ + if (pktp->type != lbuf_rxdata) { \ + total_pool_pktid_count++; \ + } \ + } while (0) + +#define TOTAL_POOL_PKTID_CNT_DEC(pktp) \ + do { \ + if (pktp->type != lbuf_rxdata) { \ + ASSERT(total_pool_pktid_count > 0); \ + total_pool_pktid_count--; \ + } \ + } while (0) +#else +#define TOTAL_POOL_PKTID_CNT_INC(pktp) +#define TOTAL_POOL_PKTID_CNT_DEC(pktp) +#endif /* BCMPKTIDMAP || BCMPKTIDMAP_MIN */ + #ifdef POOL_HEAP_RECONFIG +static uint32 pktpool_add_fail_cnt = 0; /* Counter if pktpool_add fails */ typedef struct pktpool_heap_cb_reg { pktpool_heap_cb_t fn; void *ctxt; @@ -122,6 +140,31 @@ static int pktpool_deregister(pktpool_t * poolptr); /** add declaration */ static void pktpool_avail_notify(pktpool_t *pktp); +#ifdef DONGLEBUILD +#define PKTPOOL_RXLFRAG(pktp) ((pktp)->type == lbuf_rxfrag) +#else +#define PKTPOOL_RXLFRAG(pktp) FALSE +#endif + +#define RXLRAG_POOL_FREELIST_TAIL(pktp) ((pktp)->freelist_tail) +#ifdef RXLFRAGPOOL_SORT_RXFRAG_DBG +static const char BCMPOST_TRAP_RODATA(pktpool_deq_print_1)[] = + "\n%d removing buffer from the rxlfrag pool\n"; +static const char BCMPOST_TRAP_RODATA(pktpool_enq_print_1)[] = + "\n%d adding non rxfrag buffer to the rxlfrag pool, %p, %p\n"; +static const char BCMPOST_TRAP_RODATA(pktpool_enq_print_2)[] = + "\n%d adding rxfrag buffer to the rxlfrag pool, %p, %p\n"; +uint32 g_rxlfrag_rxfrag_queued = 0; +uint32 g_rxlfrag_non_rxfrag_queued = 0; +#define RXLFRAG_SORT_DBG_PRINT(args) do { printf args;} while (0) +#define INCR_RXLFRAG_QUEUE_RXFRAG() do { g_rxlfrag_rxfrag_queued++; } while (0) +#define INCR_RXLFRAG_QUEUE_NONRXFRAG() do { g_rxlfrag_non_rxfrag_queued++; } while (0) +#else +#define RXLFRAG_SORT_DBG_PRINT(args) do { } while (0) +#define INCR_RXLFRAG_QUEUE_RXFRAG() do { } while (0) +#define INCR_RXLFRAG_QUEUE_NONRXFRAG() do { } while (0) +#endif /* RXLFRAGPOOL_SORT_RXFRAG_DBG */ + /** accessor functions required when ROMming this file, forced into RAM */ pktpool_t * @@ -131,20 +174,20 @@ BCMPOSTTRAPRAMFN(get_pktpools_registry)(int id) } static void -BCMRAMFN(pktpool_registry_set)(int id, pktpool_t *pp) +BCMRAMFN(pktpool_registry_set)(uint id, pktpool_t *pp) { pktpools_registry[id] = pp; } static bool -BCMRAMFN(pktpool_registry_cmp)(int id, pktpool_t *pp) +BCMRAMFN(pktpool_registry_cmp)(uint id, pktpool_t *pp) { return pktpools_registry[id] == pp; } /** Constructs a pool registry to serve a maximum of total_pools */ int -BCMATTACHFN(pktpool_attach)(osl_t *osh, uint32 total_pools) +pktpool_attach(osl_t *osh, uint32 total_pools) { uint32 poolid; BCM_REFERENCE(osh); @@ -169,7 +212,7 @@ BCMATTACHFN(pktpool_attach)(osl_t *osh, uint32 total_pools) /** Destructs the pool registry. Ascertain all pools were first de-inited */ int -BCMATTACHFN(pktpool_dettach)(osl_t *osh) +pktpool_dettach(osl_t *osh) { uint32 poolid; BCM_REFERENCE(osh); @@ -192,7 +235,7 @@ BCMATTACHFN(pktpool_dettach)(osl_t *osh) /** Registers a pool in a free slot; returns the registry slot index */ static int -BCMATTACHFN(pktpool_register)(pktpool_t * poolptr) +pktpool_register(pktpool_t * poolptr) { uint32 poolid; @@ -215,7 +258,7 @@ BCMATTACHFN(pktpool_register)(pktpool_t * poolptr) /** Deregisters a pktpool, given the pool pointer; tag slot as free */ static int -BCMATTACHFN(pktpool_deregister)(pktpool_t * poolptr) +pktpool_deregister(pktpool_t * poolptr) { uint32 poolid; @@ -255,7 +298,7 @@ BCMATTACHFN(pktpool_deregister)(pktpool_t * poolptr) * @param type e.g. 'lbuf_frag' */ int -BCMATTACHFN(pktpool_init)(osl_t *osh, +pktpool_init(osl_t *osh, pktpool_t *pktp, int *n_pkts, int max_pkt_bytes, @@ -268,6 +311,10 @@ BCMATTACHFN(pktpool_init)(osl_t *osh, int i, err = BCME_OK; int pktplen; uint8 pktp_id; +#ifdef BCMPKTPOOL + uint lbufsz; + uint32 flags; +#endif ASSERT(pktp != NULL); ASSERT(osh != NULL); @@ -275,8 +322,6 @@ BCMATTACHFN(pktpool_init)(osl_t *osh, pktplen = *n_pkts; - bzero(pktp, sizeof(pktpool_t)); - /* assign a unique pktpool id */ if ((pktp_id = (uint8) pktpool_register(pktp)) == PKTPOOL_INVALID_ID) { return BCME_ERROR; @@ -288,6 +333,19 @@ BCMATTACHFN(pktpool_init)(osl_t *osh, pktp->max_pkt_bytes = (uint16)max_pkt_bytes; pktp->type = type; +#ifdef BCMPKTPOOL + flags = 0; + lbufsz = 0; + set_lbuf_params(type, &flags, &lbufsz); + /* Size of tx/rx metadata */ + pktp->metasz = lb_get_metasz(type); + /* Offset of tx/rx metadata from lbuf start */ + pktp->metaoff = lbufsz - pktp->metasz; +#else + pktp->metasz = 0u; + pktp->metaoff = 0u; +#endif /* BCMPKTPOOL */ + #ifdef POOL_HEAP_RECONFIG pktp->poolheap_flag = heap_pool_flag; pktp->poolheap_count = 0; @@ -336,11 +394,16 @@ BCMATTACHFN(pktpool_init)(osl_t *osh, PKTSETFREELIST(p, pktp->freelist); /* insert p at head of free list */ pktp->freelist = p; + if (PKTPOOL_RXLFRAG(pktp) && (pktp->pktpool_flags & PKTPOOL_RXLFRAG_SORTED_INSERT)) + { + if (RXLRAG_POOL_FREELIST_TAIL(pktp) == NULL) { + RXLRAG_POOL_FREELIST_TAIL(pktp) = pktp->freelist; + } + } pktp->avail++; - ASSERT(total_pool_pktid_count > 0); - total_pool_pktid_count--; + TOTAL_POOL_PKTID_CNT_DEC(pktp); #ifdef BCMDBG_POOL pktp->dbg_q[pktp->dbg_qlen++].p = p; @@ -363,7 +426,7 @@ exit: * corruption as the pktpool_t structure no longer exists. */ int -BCMATTACHFN(pktpool_deinit)(osl_t *osh, pktpool_t *pktp) +pktpool_deinit(osl_t *osh, pktpool_t *pktp) { uint16 freed = 0; @@ -387,7 +450,7 @@ BCMATTACHFN(pktpool_deinit)(osl_t *osh, pktpool_t *pktp) PKTSETPOOL(osh, p, FALSE, NULL); /* clear pool ID tag in pkt */ - total_pool_pktid_count++; + TOTAL_POOL_PKTID_CNT_INC(pktp); PKTFREE(osh, p, pktp->istx); /* free the packet */ freed++; @@ -424,11 +487,14 @@ pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal) if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) return BCME_ERROR; -#ifdef BCMRXDATAPOOL - ASSERT((pktp->max_pkt_bytes != 0) || (pktp->type == lbuf_rxfrag)); -#else - ASSERT(pktp->max_pkt_bytes != 0); -#endif /* BCMRXDATAPOOL */ +#if defined(BCMRXDATAPOOL) || defined(URB) + if (BCMRXDATAPOOL_ENAB() || URB_ENAB()) { + ASSERT((pktp->max_pkt_bytes != 0) || (pktp->type == lbuf_rxfrag)); + } else +#endif /* BCMRXDATAPOOL || URB */ + { + ASSERT(pktp->max_pkt_bytes != 0); + } maxlen = pktp->maxlen; psize = minimal ? (maxlen >> 2) : maxlen; @@ -463,8 +529,8 @@ pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal) err = BCME_ERROR; break; } - ASSERT(total_pool_pktid_count > 0); - total_pool_pktid_count--; + + TOTAL_POOL_PKTID_CNT_DEC(pktp); } /* protect shared resource */ @@ -559,7 +625,7 @@ pktpool_reclaim(osl_t *osh, pktpool_t *pktp, uint16 free_cnt, uint8 action) pktp->avail--; pktp->n_pkts--; - total_pool_pktid_count++; + TOTAL_POOL_PKTID_CNT_INC(pktp); PKTFREE(osh, p, pktp->istx); /* free the packet */ freed++; @@ -613,7 +679,7 @@ pktpool_empty(osl_t *osh, pktpool_t *pktp) PKTSETPOOL(osh, p, FALSE, NULL); /* clear pool ID tag in pkt */ - total_pool_pktid_count++; + TOTAL_POOL_PKTID_CNT_INC(pktp); PKTFREE(osh, p, pktp->istx); /* free the packet */ freed++; @@ -658,6 +724,14 @@ BCMPOSTTRAPFASTPATH(pktpool_deq)(pktpool_t *pktp) p = pktp->freelist; /* dequeue packet from head of pktpool free list */ pktp->freelist = PKTFREELIST(p); /* free list points to next packet */ + /* rxlfrag list is ordered list rxfrag packets at head followed by non rxfrag packets */ + /* rxfrag is packet which already has associated host buffer */ + if (PKTPOOL_RXLFRAG(pktp) && (pktp->pktpool_flags & PKTPOOL_RXLFRAG_SORTED_INSERT)) { + RXLFRAG_SORT_DBG_PRINT((pktpool_deq_print_1, pktp->avail)); + if (pktp->freelist == NULL) { + RXLRAG_POOL_FREELIST_TAIL(pktp) = NULL; + } + } #if defined(DONGLEBUILD) && defined(SRMEM) if (SRMEM_ENAB()) { @@ -669,6 +743,7 @@ BCMPOSTTRAPFASTPATH(pktpool_deq)(pktpool_t *pktp) pktp->avail--; + PKTSETQCALLER(p, pktp, CALL_SITE); return p; } @@ -677,8 +752,40 @@ BCMPOSTTRAPFASTPATH(pktpool_enq)(pktpool_t *pktp, void *p) { ASSERT_FP(p != NULL); - PKTSETFREELIST(p, pktp->freelist); /* insert at head of pktpool free list */ - pktp->freelist = p; /* free list points to newly inserted packet */ + PKTSETQCALLER(p, pktp, CALL_SITE); + + if (PKTPOOL_RXLFRAG(pktp) && (pktp->pktpool_flags & PKTPOOL_RXLFRAG_SORTED_INSERT)) { + /* rxfrag pkt becomes head of freelist, non rxfrag becomes tail of the freelist */ + /* rxfrag is packet which already has associated host buffer */ + if (PKTISRXFRAG(OSH_NULL, p)) { + INCR_RXLFRAG_QUEUE_RXFRAG(); + RXLFRAG_SORT_DBG_PRINT((pktpool_enq_print_2, pktp->avail, + pktp->freelist, RXLRAG_POOL_FREELIST_TAIL(pktp))); + PKTSETFREELIST(p, pktp->freelist); /* insert at head of pktpool free list */ + if (RXLRAG_POOL_FREELIST_TAIL(pktp) == NULL) { + RXLRAG_POOL_FREELIST_TAIL(pktp) = p; + } + pktp->freelist = p; /* free list points to newly inserted packet */ + } else { + INCR_RXLFRAG_QUEUE_NONRXFRAG(); + RXLFRAG_SORT_DBG_PRINT((pktpool_enq_print_1, pktp->avail, + pktp->freelist, RXLRAG_POOL_FREELIST_TAIL(pktp))); + if (pktp->freelist == NULL) { + pktp->freelist = p; + RXLRAG_POOL_FREELIST_TAIL(pktp) = p; + } + else { + /* this pkt becomes tail */ + PKTSETFREELIST(RXLRAG_POOL_FREELIST_TAIL(pktp), p); + RXLRAG_POOL_FREELIST_TAIL(pktp) = p; + PKTSETFREELIST(p, NULL); + } + } + } + else { + PKTSETFREELIST(p, pktp->freelist); /* insert at head of pktpool free list */ + pktp->freelist = p; /* free list points to newly inserted packet */ + } #if defined(DONGLEBUILD) && defined(SRMEM) if (SRMEM_ENAB()) { @@ -692,7 +799,7 @@ BCMPOSTTRAPFASTPATH(pktpool_enq)(pktpool_t *pktp, void *p) /** utility for registering host addr fill function called from pciedev */ int -BCMATTACHFN(pktpool_hostaddr_fill_register)(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg) +pktpool_hostaddr_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg) { ASSERT(cb != NULL); @@ -704,7 +811,7 @@ BCMATTACHFN(pktpool_hostaddr_fill_register)(pktpool_t *pktp, pktpool_cb_extn_t c } int -BCMATTACHFN(pktpool_rxcplid_fill_register)(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg) +pktpool_rxcplid_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg) { ASSERT(cb != NULL); @@ -730,7 +837,7 @@ pktpool_invoke_dmarxfill(pktpool_t *pktp) /** Registers callback functions for split rx mode */ int -BCMATTACHFN(pkpool_haddr_avail_register_cb)(pktpool_t *pktp, pktpool_cb_t cb, void *arg) +pkpool_haddr_avail_register_cb(pktpool_t *pktp, pktpool_cb_t cb, void *arg) { ASSERT(cb != NULL); @@ -741,6 +848,54 @@ BCMATTACHFN(pkpool_haddr_avail_register_cb)(pktpool_t *pktp, pktpool_cb_t cb, vo return 0; } +#ifdef URB +/** + * @brief API to register the callback which gets invoked when Rx data buffer + * which is part of URB memory is freed while rxfrag is being freed. + * It is used to increment rd_ptr of URB HW in mac. + * + * @param[in] pktp Pointer to rxfrag pool + * @param[in] cb Callback function that needs to get registered + * @param[in] arg Argument that is passed to this callback while invocation + * + * @return Returns error status + */ +int +pkpool_rxurb_register_cb(pktpool_t *pktp, pktpool_rxurb_cb_t cb, void *arg) +{ + + ASSERT(cb != NULL); + + pktp->dmarxurb.cb = cb; + pktp->dmarxurb.arg = arg; + + return BCME_OK; +} + +/** + * @brief API to register the callback which gets invoked during rxfrag free + * to remove rxcplid and host buffer is not used up in rxpath and during rxfill + * to post host buffers to dma rx fifo0 + * + * @param[in] pktp Pointer to rxfrag pool + * @param[in] cb Callback function that needs to get registered + * @param[in] arg Argument that is passed to this callback while invocation + * + * @return Returns error status + */ +int +pktpool_hostaddr_ext_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg) +{ + + ASSERT(cb != NULL); + + ASSERT(pktp->cb_haddr.cb == NULL); + pktp->cb_haddr.cb = cb; + pktp->cb_haddr.arg = arg; + return BCME_OK; +} +#endif /* URB */ + /** * Registers callback functions. * No BCMATTACHFN as it is used in xdc_enable_ep which is not an attach function @@ -837,7 +992,7 @@ done: /** Registers callback functions */ int -BCMATTACHFN(pktpool_empty_register)(pktpool_t *pktp, pktpool_cb_t cb, void *arg) +pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg) { int err = 0; int i; @@ -1167,17 +1322,23 @@ BCMPOSTTRAPFN(pktpool_avail_notify)(pktpool_t *pktp) return; } -#ifdef APP_RX +#ifdef BCMPCIEDEV /* Update freelist and avail count for a given packet pool */ void -BCMFASTPATH(pktpool_update_freelist)(pktpool_t *pktp, void *p, uint pkts_consumed) +BCMPOSTTRAPFASTPATH(pktpool_update_freelist)(pktpool_t *pktp, void *p, uint pkts_consumed) { ASSERT_FP(pktp->avail >= pkts_consumed); pktp->freelist = p; pktp->avail -= pkts_consumed; } -#endif /* APP_RX */ +#endif /* BCMPCIEDEV */ + +int +BCMFASTPATH(pktpool_get_last_err)(pktpool_t *pktp) +{ + return last_alloc_err; +} /** Gets an empty packet from the caller provided pool */ void * @@ -1188,6 +1349,7 @@ BCMPOSTTRAPFASTPATH(pktpool_get_ext)(pktpool_t *pktp, uint8 type, uint *pktcnt) #if defined(DONGLEBUILD) uint pkts_avail; bool rxcpl = (pktp->rxcplidfn.cb != NULL) ? TRUE : FALSE; + BCM_REFERENCE(pkts_avail); #endif /* DONGLEBUILD */ if (pktcnt) { @@ -1217,12 +1379,16 @@ BCMPOSTTRAPFASTPATH(pktpool_get_ext)(pktpool_t *pktp, uint8 type, uint *pktcnt) if (pktp->avail < pkts_requested) { pktpool_emptycb_disable(pktp, FALSE); if (pktp->avail == 0) { + last_alloc_err = PKT_ALLOC_FAIL_NOPKT; + if (pktcnt) { + *pktcnt = 0; + } goto done; } } } -#ifdef APP_RX +#ifdef BCMPCIEDEV if (pktcnt) { p = pktp->freelist; if (pktp->avail < pkts_requested) { @@ -1238,7 +1404,7 @@ BCMPOSTTRAPFASTPATH(pktpool_get_ext)(pktpool_t *pktp, uint8 type, uint *pktcnt) goto done; } } else -#endif /* APP_RX */ +#endif /* BCMPCIEDEV */ { ASSERT_FP(pkts_requested == 1); p = pktpool_deq(pktp); @@ -1247,27 +1413,12 @@ BCMPOSTTRAPFASTPATH(pktpool_get_ext)(pktpool_t *pktp, uint8 type, uint *pktcnt) ASSERT_FP(p); #if defined(DONGLEBUILD) -#ifndef APP_RX - if (BCMSPLITRX_ENAB() && (type == lbuf_rxfrag)) { - /* If pool is shared rx pool, use call back fn to populate host address. - * In case of APP, callback may use lesser number of packets than what - * we have given to callback because of some resource crunch and the exact - * number of packets that are used by the callback are returned using - * (*pktcnt) and the pktpool freelist head is updated accordingly. - */ - ASSERT_FP(pktp->cbext.cb != NULL); - if (pktp->cbext.cb(pktp, pktp->cbext.arg, p, rxcpl, &pkts_avail)) { - pktpool_enq(pktp, p); - p = NULL; - } - } -#endif /* APP_RX */ - if ((type == lbuf_basic) && rxcpl) { /* If pool is shared rx pool, use call back fn to populate Rx cpl ID */ ASSERT_FP(pktp->rxcplidfn.cb != NULL); /* If rxcplblock is allocated */ if (pktp->rxcplidfn.cb(pktp, pktp->rxcplidfn.arg, p, TRUE, NULL)) { + last_alloc_err = PKT_ALLOC_FAIL_NOCMPLID; pktpool_enq(pktp, p); p = NULL; } @@ -1281,28 +1432,56 @@ done: /* protect shared resource */ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) return NULL; - +#ifdef BCMPCIEDEV + if (p && (type == lbuf_alfrag_data)) { + p = (uint8 *)p + LBUFMEMSZ; + } +#endif /* BCMPCIEDEV */ return p; } void BCMFASTPATH(pktpool_nfree)(pktpool_t *pktp, void *head, void *tail, uint count) { -#ifdef BCMRXDATAPOOL void *_head = head; -#endif /* BCMRXDATAPOOL */ + uint count_orig = count; + + BCM_REFERENCE(count_orig); + +#ifdef URB + if (URB_ENAB() && count && PKT_IS_RX_PKT(OSH_NULL, head)) { + pktp->dmarxurb.cb(pktp, pktp->dmarxurb.arg, PKTHEAD(NULL, head), + PKTEND(head) - PKTHEAD(NULL, head)); + PKT_CLR_RX_PKT(OSH_NULL, head); + } +#endif /* URB */ if (count > 1) { pktp->avail += (count - 1); - + if (BCMRXDATAPOOL_ENAB() || URB_ENAB()) { + while (--count) { + _head = PKTLINK(_head); + ASSERT_FP(_head); + if (URB_ENAB()) { +#ifdef URB + if (PKT_IS_RX_PKT(OSH_NULL, _head)) { + pktp->dmarxurb.cb(pktp, pktp->dmarxurb.arg, + PKTHEAD(NULL, _head), + PKTEND(_head) - + PKTHEAD(NULL, _head)); + PKT_CLR_RX_PKT(OSH_NULL, _head); + } +#endif /* URB */ + } else { #ifdef BCMRXDATAPOOL - while (--count) { - _head = PKTLINK(_head); - ASSERT_FP(_head); - pktpool_enq(pktpool_shared_rxdata, PKTDATA(OSH_NULL, _head)); - } + pktpool_enq(pktpool_shared_rxdata, + PKTDATA(OSH_NULL, _head)); #endif /* BCMRXDATAPOOL */ + } + } + } + PKTSETQCALLER_LIST(PKTLINK(head), (count_orig - 1), pktp->freelist, CALL_SITE); PKTSETFREELIST(tail, pktp->freelist); pktp->freelist = PKTLINK(head); PKTSETLINK(head, NULL); @@ -1322,9 +1501,23 @@ BCMPOSTTRAPFASTPATH(pktpool_free)(pktpool_t *pktp, void *p) /* pktpool_stop_trigger(pktp, p); */ #endif +#ifdef URB + if (URB_ENAB()) { + if (PKTISRXFRAG(OSH_NULL, p)) { + pktp->cb_haddr.cb(pktp, pktp->cb_haddr.arg, p, REMOVE_RXCPLID, NULL); + PKTRESETRXFRAG(OSH_NULL, p); + } + if (PKT_IS_RX_PKT(OSH_NULL, p)) { + pktp->dmarxurb.cb(pktp, pktp->dmarxurb.arg, PKTHEAD(OSH_NULL, p), + PKTEND(p) - PKTHEAD(OSH_NULL, p)); + PKT_CLR_RX_PKT(OSH_NULL, p); + } + } +#endif /* URB */ + #ifdef BCMRXDATAPOOL /* Free rx data buffer to rx data buffer pool */ - if (PKT_IS_RX_PKT(OSH_NULL, p)) { + if (BCMRXDATAPOOL_ENAB() && PKT_IS_RX_PKT(OSH_NULL, p)) { pktpool_t *_pktp = pktpool_shared_rxdata; if (PKTISRXFRAG(OSH_NULL, p)) { _pktp->cbext.cb(_pktp, _pktp->cbext.arg, p, REMOVE_RXCPLID, NULL); @@ -1430,10 +1623,10 @@ BCMRAMFN(pktpool_setmaxlen)(pktpool_t *pktp, uint16 maxlen) } void -BCMPOSTTRAPFN(pktpool_emptycb_disable)(pktpool_t *pktp, bool disable) +BCMPOSTTRAPFASTPATH(pktpool_emptycb_disable)(pktpool_t *pktp, bool disable) { bool notify = FALSE; - ASSERT(pktp); + ASSERT_FP(pktp); /** * To more efficiently use the cpu cycles, callbacks can be temporarily disabled. @@ -1485,16 +1678,15 @@ pktpool_t *pktpool_shared = NULL; #ifdef BCMFRAGPOOL pktpool_t *pktpool_shared_lfrag = NULL; -#ifdef BCMRESVFRAGPOOL -pktpool_t *pktpool_resv_lfrag = NULL; -struct resv_info *resv_pool_info = NULL; -#endif /* BCMRESVFRAGPOOL */ -#endif /* BCMFRAGPOOL */ - -#ifdef BCMALFRAGPOOL pktpool_t *pktpool_shared_alfrag = NULL; pktpool_t *pktpool_shared_alfrag_data = NULL; -#endif /* BCMCTFRAGPOOL */ +#endif /* BCMFRAGPOOL */ + +#ifdef BCMRESVFRAGPOOL +resv_info_t *resv_pool_info = NULL; +pktpool_t *pktpool_resv_alfrag = NULL; +pktpool_t *pktpool_resv_alfrag_data = NULL; +#endif /* BCMRESVFRAGPOOL */ pktpool_t *pktpool_shared_rxlfrag = NULL; @@ -1507,7 +1699,7 @@ static osl_t *pktpool_osh = NULL; * Initializes several packet pools and allocates packets within those pools. */ int -BCMATTACHFN(hnd_pktpool_init)(osl_t *osh) +hnd_pktpool_init(osl_t *osh) { int err = BCME_OK; int n, pktsz; @@ -1546,8 +1738,15 @@ BCMATTACHFN(hnd_pktpool_init)(osl_t *osh) ASSERT(0); goto error; } - pktpool_resv_lfrag = resv_pool_info->pktp; - if (pktpool_resv_lfrag == NULL) { + + pktpool_resv_alfrag = resv_pool_info->rip[RESV_FRAGPOOL_ALFRAG]->pktp; + if (pktpool_resv_alfrag == NULL) { + err = BCME_ERROR; + ASSERT(0); + goto error; + } + pktpool_resv_alfrag_data = resv_pool_info->rip[RESV_FRAGPOOL_ALFRAG_DATA]->pktp; + if (pktpool_resv_alfrag_data == NULL) { err = BCME_ERROR; ASSERT(0); goto error; @@ -1555,7 +1754,7 @@ BCMATTACHFN(hnd_pktpool_init)(osl_t *osh) #endif /* RESVFRAGPOOL */ #endif /* FRAGPOOL */ -#if defined(BCMALFRAGPOOL) && !defined(BCMALFRAGPOOL_DISABLED) +#if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED) pktpool_shared_alfrag = MALLOCZ(osh, sizeof(pktpool_t)); if (pktpool_shared_alfrag == NULL) { ASSERT(0); @@ -1578,7 +1777,7 @@ BCMATTACHFN(hnd_pktpool_init)(osl_t *osh) err = BCME_NOMEM; goto error; } -#endif +#endif /* defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED) */ #if defined(BCMRXDATAPOOL) && !defined(BCMRXDATAPOOL_DISABLE) pktpool_shared_rxdata = MALLOCZ(osh, sizeof(pktpool_t)); @@ -1587,7 +1786,7 @@ BCMATTACHFN(hnd_pktpool_init)(osl_t *osh) err = BCME_NOMEM; goto error; } -#endif +#endif /* BCMRXDATAPOOL */ /* * At this early stage, there's not enough memory to allocate all @@ -1613,8 +1812,8 @@ BCMATTACHFN(hnd_pktpool_init)(osl_t *osh) #if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED) n = 1; -#if (((defined(EVENTLOG_D3_PRESERVE) && !defined(EVENTLOG_D3_PRESERVE_DISABLED)) || \ - defined(BCMPOOLRECLAIM))) +#if ((defined(EVENTLOG_D3_PRESERVE) && !defined(EVENTLOG_D3_PRESERVE_DISABLED)) || \ + defined(BCMPOOLRECLAIM)) is_heap_pool = TRUE; #else is_heap_pool = FALSE; @@ -1628,24 +1827,9 @@ BCMATTACHFN(hnd_pktpool_init)(osl_t *osh) } pktpool_setmaxlen(pktpool_shared_lfrag, SHARED_FRAG_POOL_LEN); -#if defined(BCMRESVFRAGPOOL) && !defined(BCMRESVFRAGPOOL_DISABLED) - n = 0; /* IMPORTANT: DO NOT allocate any packets in resv pool */ -#ifdef RESV_POOL_HEAP - is_heap_pool = TRUE; -#else - is_heap_pool = FALSE; -#endif /* RESV_POOL_HEAP */ - - if ((err = pktpool_init(osh, pktpool_resv_lfrag, &n, PKTFRAGSZ, TRUE, lbuf_frag, - is_heap_pool, POOL_HEAP_FLAG_RSRVPOOL, 0)) != BCME_OK) { - ASSERT(0); - goto error; - } - pktpool_setmaxlen(pktpool_resv_lfrag, RESV_FRAG_POOL_LEN); -#endif /* RESVFRAGPOOL */ #endif /* BCMFRAGPOOL */ -#if defined(BCMALFRAGPOOL) && !defined(BCMALFRAGPOOL_DISABLED) +#if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED) n = 1; is_heap_pool = FALSE; @@ -1666,8 +1850,35 @@ BCMATTACHFN(hnd_pktpool_init)(osl_t *osh) #endif /* BCMCTFRAGPOOL */ +#if defined(BCMRESVFRAGPOOL) && !defined(BCMRESVFRAGPOOL_DISABLED) +#ifdef RESV_POOL_HEAP + is_heap_pool = TRUE; +#else + is_heap_pool = FALSE; +#endif /* RESV_POOL_HEAP */ + + /* resv alfrag pool */ + n = 0; /* IMPORTANT: DO NOT allocate any packets in resv pool */ + if ((err = pktpool_init(osh, pktpool_resv_alfrag, &n, PKTFRAGSZ, TRUE, lbuf_alfrag, + is_heap_pool, POOL_HEAP_FLAG_RSRVPOOL, 0)) != BCME_OK) { + ASSERT(0); + goto error; + } + pktpool_setmaxlen(pktpool_resv_alfrag, RESV_ALFRAG_POOL_LEN); + + /* resv alfrag data pool */ + n = 0; /* IMPORTANT: DO NOT allocate any packets in resv pool */ + if ((err = pktpool_init(osh, pktpool_resv_alfrag_data, &n, TXPKTALFRAG_DATA_BUFSZ, TRUE, + lbuf_alfrag_data, is_heap_pool, POOL_HEAP_FLAG_RSRVPOOL, 0)) != BCME_OK) { + ASSERT(0); + goto error; + } + pktpool_setmaxlen(pktpool_resv_alfrag_data, RESV_ALFRAG_DATA_POOL_LEN); +#endif /* RESVFRAGPOOL */ #if defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED) -#if defined(BCMRXDATAPOOL) && !defined(BCMRXDATAPOOL_DISABLED) +#if defined(URB) && !defined(URB_DISABLED) + pktsz = 0; +#elif defined(BCMRXDATAPOOL) && !defined(BCMRXDATAPOOL_DISABLED) n = 1; if ((err = pktpool_init(osh, pktpool_shared_rxdata, &n, RXPKTFRAGDATASZ, TRUE, lbuf_rxdata, FALSE, 0, 0)) != BCME_OK) { @@ -1733,7 +1944,7 @@ error: } /* hnd_pktpool_init */ void -BCMATTACHFN(hnd_pktpool_deinit)(osl_t *osh) +hnd_pktpool_deinit(osl_t *osh) { #if defined(BCMFRWDPOOLREORG) && !defined(BCMFRWDPOOLREORG_DISABLED) if (frwd_poolreorg_info != NULL) { @@ -1761,7 +1972,7 @@ BCMATTACHFN(hnd_pktpool_deinit)(osl_t *osh) hnd_free(pktpool_shared_rxdata); pktpool_shared_rxdata = (pktpool_t *)NULL; } -#endif +#endif /* BCMRXDATAPOOL */ #if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED) if (pktpool_shared_lfrag != NULL) { @@ -1773,7 +1984,7 @@ BCMATTACHFN(hnd_pktpool_deinit)(osl_t *osh) } #endif /* BCMFRAGPOOL */ -#if defined(BCMALFRAGPOOL) && !defined(BCMALFRAGPOOL_DISABLED) +#if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED) if (pktpool_shared_alfrag != NULL) { if (pktpool_shared_alfrag->inited) { pktpool_deinit(osh, pktpool_shared_alfrag); @@ -1793,9 +2004,12 @@ BCMATTACHFN(hnd_pktpool_deinit)(osl_t *osh) #endif /* BCMFRAGPOOL */ #if defined(BCMRESVFRAGPOOL) && !defined(BCMRESVFRAGPOOL_DISABLED) - if (resv_pool_info != NULL) { - if (pktpool_resv_lfrag != NULL) { - pktpool_resv_lfrag = NULL; + if (resv_pool_info) { + if (pktpool_resv_alfrag) { + pktpool_resv_alfrag = NULL; + } + if (pktpool_resv_alfrag_data) { + pktpool_resv_alfrag_data = NULL; } hnd_free(resv_pool_info); } @@ -1826,6 +2040,7 @@ hnd_pktpool_fill(pktpool_t *pktpool, bool minimal) void hnd_pktpool_refill(bool minimal) { + MB_START(hnd_pktpool_refill); if (POOL_ENAB(pktpool_shared)) { #if defined(SRMEM) if (SRMEM_ENAB()) { @@ -1847,10 +2062,8 @@ hnd_pktpool_refill(bool minimal) if (POOL_ENAB(pktpool_shared_lfrag)) { pktpool_fill(pktpool_osh, pktpool_shared_lfrag, minimal); } -#endif /* BCMFRAGPOOL */ /* alfragpool reclaim */ -#ifdef BCMALFRAGPOOL if (POOL_ENAB(pktpool_shared_alfrag)) { pktpool_fill(pktpool_osh, pktpool_shared_alfrag, minimal); } @@ -1858,7 +2071,7 @@ hnd_pktpool_refill(bool minimal) if (POOL_ENAB(pktpool_shared_alfrag_data)) { pktpool_fill(pktpool_osh, pktpool_shared_alfrag_data, minimal); } -#endif /* BCMALFRAGPOOL */ +#endif /* BCMFRAGPOOL */ /* rx fragpool reclaim */ #ifdef BCMRXFRAGPOOL @@ -1871,21 +2084,19 @@ hnd_pktpool_refill(bool minimal) if (POOL_ENAB(pktpool_shared_rxdata)) { pktpool_fill(pktpool_osh, pktpool_shared_rxdata, minimal); } -#endif +#endif /* BCMRXDATAPOOL */ #if defined(BCMFRAGPOOL) && defined(BCMRESVFRAGPOOL) - if (POOL_ENAB(pktpool_resv_lfrag)) { - int resv_size = (pktpool_resv_lfrag->max_pkt_bytes + LBUFFRAGSZ) * - pktpool_resv_lfrag->maxlen; - hnd_resv_pool_init(resv_pool_info, resv_size); + if (resv_pool_info) { hnd_resv_pool_enable(resv_pool_info); } #endif /* BCMRESVFRAGPOOL */ + MB_END(hnd_pktpool_refill, "hnd_pktpool_refill"); } #ifdef POOL_HEAP_RECONFIG -#define hnd_pktpool_release_active_set(pktp) (pktpool_heap_rel_active |= (1 << pktp->id)) -#define hnd_pktpool_release_active_reset(pktp) (pktpool_heap_rel_active &= ~(1 << pktp->id)) +#define hnd_pktpool_release_active_set(pktp) (pktpool_heap_rel_active |= (1u << pktp->id)) +#define hnd_pktpool_release_active_reset(pktp) (pktpool_heap_rel_active &= ~(1u << pktp->id)) /* Function enable/disable heap pool usage */ void @@ -1977,7 +2188,7 @@ hnd_pktpool_heap_pkt_release(osl_t *osh, pktpool_t *pktp, uint32 flag) PKTSETPOOL(osh, p, FALSE, NULL); /* clear pool ID tag in pkt */ lb_set_nofree(p); - total_pool_pktid_count++; + TOTAL_POOL_PKTID_CNT_INC(pktp); PKTFREE(osh, p, pktp->istx); /* free the packet */ rte_freelist_mgr_add(p, pktp->mem_handle); @@ -2049,8 +2260,7 @@ hnd_pktpool_heap_get_cb(uint8 handle, void *ctxt, void *pkt, uint pktsize) pktp->type, pkt, pktsize)) != NULL) { if ((ret = pktpool_add(pktp, lb)) == BCME_OK) { pktp->poolheap_count--; - ASSERT(total_pool_pktid_count > 0); - total_pool_pktid_count--; + TOTAL_POOL_PKTID_CNT_DEC(pktp); if (pktp->poolheap_count == 0) { pktp->release_active = FALSE; hnd_pktpool_release_active_reset(pktp); @@ -2066,6 +2276,7 @@ hnd_pktpool_heap_get_cb(uint8 handle, void *ctxt, void *pkt, uint pktsize) * free this buffer to heap */ PKTFREE(pktpool_osh, lb, pktsize); + pktpool_add_fail_cnt++; } ret = BCME_OK; } diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hnd_pktq.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hnd_pktq.c old mode 100755 new mode 100644 index bd5cc81a7890..2248c57c74fa --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hnd_pktq.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hnd_pktq.c @@ -1,7 +1,7 @@ /* * HND generic pktq operation primitives * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -50,7 +50,7 @@ * hi_prec is always >= the number of the highest non-empty precedence */ void * -BCMFASTPATH(pktq_penq)(struct pktq *pq, int prec, void *p) +BCMPOSTTRAPFASTPATH(pktq_penq)(struct pktq *pq, int prec, void *p) { struct pktq_prec *q; @@ -64,6 +64,8 @@ BCMFASTPATH(pktq_penq)(struct pktq *pq, int prec, void *p) ASSERT_FP(!pktq_full(pq)); ASSERT_FP(!pktqprec_full(pq, prec)); + PKTSETQCALLER(p, pq, CALL_SITE); + q = &pq->q[prec]; if (q->head) @@ -138,6 +140,8 @@ BCMFASTPATH(spktq_enq)(struct spktq *spq, void *p) ASSERT_FP(!spktq_full(spq)); + PKTSETQCALLER(p, spq, CALL_SITE); + PKTSETLINK(p, NULL); q = &spq->q; @@ -172,6 +176,8 @@ BCMPOSTTRAPFASTPATH(pktq_penq_head)(struct pktq *pq, int prec, void *p) ASSERT_FP(!pktq_full(pq)); ASSERT_FP(!pktqprec_full(pq, prec)); + PKTSETQCALLER(p, pq, CALL_SITE); + q = &pq->q[prec]; if (q->head == NULL) @@ -204,6 +210,7 @@ BCMFASTPATH(spktq_enq_head)(struct spktq *spq, void *p) ASSERT_FP(!spktq_full(spq)); + PKTSETQCALLER(p, spq, CALL_SITE); PKTSETLINK(p, NULL); q = &spq->q; @@ -257,6 +264,7 @@ done: if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) return NULL; + PKTSETQCALLER(p, pq, CALL_SITE); return p; } @@ -291,9 +299,53 @@ done: if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS) return NULL; + PKTSETQCALLER(p, spq, CALL_SITE); return p; } +void * +BCMFASTPATH(spktq_delete_node)(struct spktq *spq, void *prev, void *cur) +{ + struct pktq_prec *q; + void *next = NULL; + + /* protect shared resource */ + if (HND_PKTQ_MUTEX_ACQUIRE(&spq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) { + return NULL; + } + + q = &spq->q; + + if (cur == q->head) { + spktq_deq(spq); + next = q->head; + goto done; + } + + if ((cur == NULL) || (prev == NULL)) { + ASSERT(0); + next = NULL; + goto done; + } + + ASSERT_FP(PKTLINK(prev) == cur); + next = PKTLINK(cur); + PKTSETLINK(prev, next); + PKTSETLINK(cur, NULL); + ASSERT_FP(q->n_pkts); + q->n_pkts--; + +#ifdef WL_TXQ_STALL + q->dequeue_count++; +#endif +done: + /* protect shared resource */ + if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS) { + return NULL; + } + return next; +} + void* BCMFASTPATH(spktq_deq_virt)(struct spktq *spq) { @@ -327,6 +379,7 @@ done: if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS) return NULL; + PKTSETQCALLER(p, spq, CALL_SITE); return p; } @@ -368,6 +421,7 @@ done: if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) return NULL; + PKTSETQCALLER(p, pq, CALL_SITE); return p; } @@ -405,6 +459,7 @@ done: if (HND_PKTQ_MUTEX_RELEASE(&spq->mutex) != OSL_EXT_SUCCESS) return NULL; + PKTSETQCALLER(p, spq, CALL_SITE); return p; } @@ -453,6 +508,8 @@ BCMFASTPATH(pktq_append)(struct pktq *pq, int prec, struct spktq *list) list_q = &list->q; + PKTSETQCALLER_LIST(list_q->head, list_q->n_pkts, pq, CALL_SITE); + /* empty list check */ if (list_q->head == NULL) goto done; @@ -506,6 +563,8 @@ BCMFASTPATH(spktq_append)(struct spktq *spq, struct spktq *list) list_q = &list->q; + PKTSETQCALLER_LIST(list_q->head, list_q->n_pkts, spq, CALL_SITE); + /* empty list check */ if (list_q->head == NULL) goto done; @@ -553,6 +612,8 @@ BCMFASTPATH(pktq_prepend)(struct pktq *pq, int prec, struct spktq *list) list_q = &list->q; + PKTSETQCALLER_LIST(list_q->head, list_q->n_pkts, pq, CALL_SITE); + /* empty list check */ if (list_q->head == NULL) goto done; @@ -612,6 +673,8 @@ BCMFASTPATH(spktq_prepend)(struct spktq *spq, struct spktq *list) list_q = &list->q; + PKTSETQCALLER_LIST(list_q->head, list_q->n_pkts, spq, CALL_SITE); + /* empty list check */ if (list_q->head == NULL) goto done; @@ -685,6 +748,7 @@ done: if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) return NULL; + PKTSETQCALLER(p, pq, CALL_SITE); return p; } @@ -739,6 +803,7 @@ done: if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) return NULL; + PKTSETQCALLER(p, pq, CALL_SITE); return p; } @@ -982,11 +1047,11 @@ spktq_filter(struct spktq *spq, pktq_filter_t fltr, void* fltr_ctx, } bool -pktq_init(struct pktq *pq, int num_prec, uint max_pkts) +pktq_init(struct pktq *pq, uint num_prec, uint max_pkts) { - int prec; + uint prec; - ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); + ASSERT_FP(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); /* pq is variable size; only zero out what's requested */ bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); @@ -1018,12 +1083,13 @@ spktq_init(struct spktq *spq, uint max_pkts) } bool -spktq_init_list(struct spktq *spq, uint max_pkts, void *head, void *tail, uint16 n_pkts) +BCMFASTPATH(spktq_init_list)(struct spktq *spq, uint max_pkts, void *head, + void *tail, uint16 n_pkts) { if (HND_PKTQ_MUTEX_CREATE("spktq", &spq->mutex) != OSL_EXT_SUCCESS) return FALSE; - ASSERT(PKTLINK(tail) == NULL); + ASSERT_FP(PKTLINK(tail) == NULL); PKTSETLINK(tail, NULL); spq->q.head = head; spq->q.tail = tail; @@ -1115,6 +1181,7 @@ done: if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) return NULL; + PKTSETQCALLER(p, pq, CALL_SITE); return p; } @@ -1168,11 +1235,12 @@ done: if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) return NULL; + PKTSETQCALLER(p, pq, CALL_SITE); return p; } void * -pktq_peek(struct pktq *pq, int *prec_out) +BCMPOSTTRAPFN(pktq_peek)(struct pktq *pq, int *prec_out) { int prec; void *p = NULL; @@ -1259,9 +1327,17 @@ typedef struct { spktq_cb_t cb; void *arg; } spktq_cbinfo_t; + +typedef struct { + spktq_suppress_cb_t cb; + void *arg; +} spktq_suppress_cbinfo_t; static spktq_cbinfo_t spktq_cbinfo = {NULL, NULL}; static spktq_cbinfo_t *spktq_cbinfo_get(void); +static spktq_suppress_cbinfo_t spktq_suppress_cbinfo = {NULL, NULL}; +static spktq_suppress_cbinfo_t *spktq_suppress_cbinfo_get(void); + /* Accessor function forced into RAM to keep spktq_cbinfo out of shdat */ static spktq_cbinfo_t* BCMRAMFN(spktq_cbinfo_get)(void) @@ -1269,8 +1345,14 @@ BCMRAMFN(spktq_cbinfo_get)(void) return (&spktq_cbinfo); } +static spktq_suppress_cbinfo_t* +BCMRAMFN(spktq_suppress_cbinfo_get)(void) +{ + return (&spktq_suppress_cbinfo); +} + void -BCMATTACHFN(spktq_free_register)(spktq_cb_t cb, void *arg) +spktq_free_register(spktq_cb_t cb, void *arg) { spktq_cbinfo_t *cbinfop = spktq_cbinfo_get(); cbinfop->cb = cb; @@ -1286,6 +1368,24 @@ spktq_cb(void *spq) } } +void +spktq_suppress_register(spktq_suppress_cb_t cb, void *arg) +{ + spktq_suppress_cbinfo_t *cbinfop = spktq_suppress_cbinfo_get(); + cbinfop->cb = cb; + cbinfop->arg = arg; +} + +uint32 +spktq_suppress_cb(void *spq) +{ + spktq_suppress_cbinfo_t *cbinfop = spktq_suppress_cbinfo_get(); + if (cbinfop->cb) { + return cbinfop->cb(cbinfop->arg, spq); + } + return BCME_UNSUPPORTED; +} + void pktq_flush(osl_t *osh, struct pktq *pq, bool dir) { @@ -1328,7 +1428,7 @@ pktq_mlen(struct pktq *pq, uint prec_bmp) len = 0; for (prec = 0; prec <= pq->hi_prec; prec++) - if (prec_bmp & (1 << prec)) + if (prec_bmp & (1u << prec)) len += pq->q[prec].n_pkts; /* protect shared resource */ @@ -1340,7 +1440,7 @@ pktq_mlen(struct pktq *pq, uint prec_bmp) /* Priority peek from a specific set of precedences */ void * -BCMFASTPATH(pktq_mpeek)(struct pktq *pq, uint prec_bmp, int *prec_out) +BCMPOSTTRAPFASTPATH(pktq_mpeek)(struct pktq *pq, uint prec_bmp, int *prec_out) { struct pktq_prec *q; void *p = NULL; @@ -1356,7 +1456,7 @@ BCMFASTPATH(pktq_mpeek)(struct pktq *pq, uint prec_bmp, int *prec_out) while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) pq->hi_prec--; - while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL) + while ((prec_bmp & (1u << prec)) == 0 || pq->q[prec].head == NULL) if (prec-- == 0) goto done; @@ -1375,6 +1475,7 @@ done: return p; } + /* Priority dequeue from a specific set of precedences */ void * BCMPOSTTRAPFASTPATH(pktq_mdeq)(struct pktq *pq, uint prec_bmp, int *prec_out) @@ -1393,7 +1494,7 @@ BCMPOSTTRAPFASTPATH(pktq_mdeq)(struct pktq *pq, uint prec_bmp, int *prec_out) while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) pq->hi_prec--; - while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0)) + while ((pq->q[prec].head == NULL) || ((prec_bmp & (1u << prec)) == 0)) if (prec-- == 0) goto done; @@ -1429,6 +1530,7 @@ done: if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) return NULL; + PKTSETQCALLER(p, pq, CALL_SITE); return p; } diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hndlhl.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hndlhl.c deleted file mode 100755 index 0695e0938820..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hndlhl.c +++ /dev/null @@ -1,1241 +0,0 @@ -/* - * Misc utility routines for accessing lhl specific features - * of the SiliconBackplane-based Broadcom chips. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SI_LHL_EXT_WAKE_REQ_MASK_MAGIC 0x7FBBF7FF /* magic number for LHL EXT */ - -/* PmuRev1 has a 24-bit PMU RsrcReq timer. However it pushes all other bits - * upward. To make the code to run for all revs we use a variable to tell how - * many bits we need to shift. - */ -#define FLAGS_SHIFT 14 -#define LHL_ERROR(args) printf args -static const char BCMATTACHDATA(rstr_rfldo3p3_cap_war)[] = "rfldo3p3_cap_war"; -static const char BCMATTACHDATA(rstr_abuck_volt_sleep)[] = "abuck_volt_sleep"; -static const char BCMATTACHDATA(rstr_cbuck_volt_sleep)[] = "cbuck_volt_sleep"; - -void -si_lhl_setup(si_t *sih, osl_t *osh) -{ - if ((CHIPID(sih->chip) == BCM43012_CHIP_ID) || - (CHIPID(sih->chip) == BCM43013_CHIP_ID) || - (CHIPID(sih->chip) == BCM43014_CHIP_ID)) { - /* Enable PMU sleep mode0 */ -#ifdef BCMQT - LHL_REG(sih, lhl_top_pwrseq_ctl_adr, LHL_PWRSEQ_CTL, PMU_SLEEP_MODE_0); -#else - LHL_REG(sih, lhl_top_pwrseq_ctl_adr, LHL_PWRSEQ_CTL, PMU_SLEEP_MODE_2); -#endif - /* Modify as per the - BCM43012/LHL#LHL-RecommendedsettingforvariousPMUSleepModes: - */ - LHL_REG(sih, lhl_top_pwrup_ctl_adr, LHL_PWRUP_CTL_MASK, LHL_PWRUP_CTL); - LHL_REG(sih, lhl_top_pwrup2_ctl_adr, LHL_PWRUP2_CTL_MASK, LHL_PWRUP2_CTL); - LHL_REG(sih, lhl_top_pwrdn_ctl_adr, LHL_PWRDN_CTL_MASK, LHL_PWRDN_SLEEP_CNT); - LHL_REG(sih, lhl_top_pwrdn2_ctl_adr, LHL_PWRDN2_CTL_MASK, LHL_PWRDN2_CTL); - } - - if (!FWSIGN_ENAB() && si_hib_ext_wakeup_isenab(sih)) { - /* - * Enable wakeup on GPIO1, PCIE clkreq and perst signal, - * GPIO[0] is mapped to GPIO1 - * GPIO[1] is mapped to PCIE perst - * GPIO[2] is mapped to PCIE clkreq - */ - - /* GPIO1 */ - /* Clear any old interrupt status */ - LHL_REG(sih, gpio_int_st_port_adr[0], - 1 << PCIE_GPIO1_GPIO_PIN, 1 << PCIE_GPIO1_GPIO_PIN); - /* active high level trigger */ - LHL_REG(sih, gpio_ctrl_iocfg_p_adr[PCIE_GPIO1_GPIO_PIN], ~0, - 1 << GCI_GPIO_STS_WL_DIN_SELECT); - LHL_REG(sih, gpio_int_en_port_adr[0], - 1 << PCIE_GPIO1_GPIO_PIN, 1 << PCIE_GPIO1_GPIO_PIN); - LHL_REG(sih, gpio_int_st_port_adr[0], - 1 << PCIE_GPIO1_GPIO_PIN, 1 << PCIE_GPIO1_GPIO_PIN); - si_gci_set_functionsel(sih, 1, CC_FNSEL_SAMEASPIN); - - /* PCIE perst */ - LHL_REG(sih, gpio_int_st_port_adr[0], - 1 << PCIE_PERST_GPIO_PIN, 1 << PCIE_PERST_GPIO_PIN); - LHL_REG(sih, gpio_ctrl_iocfg_p_adr[PCIE_PERST_GPIO_PIN], ~0, - (1 << GCI_GPIO_STS_EDGE_TRIG_BIT | - 1 << GCI_GPIO_STS_WL_DIN_SELECT)); - LHL_REG(sih, gpio_int_en_port_adr[0], - 1 << PCIE_PERST_GPIO_PIN, 1 << PCIE_PERST_GPIO_PIN); - LHL_REG(sih, gpio_int_st_port_adr[0], - 1 << PCIE_PERST_GPIO_PIN, 1 << PCIE_PERST_GPIO_PIN); - - /* PCIE clkreq */ - LHL_REG(sih, gpio_int_st_port_adr[0], - 1 << PCIE_CLKREQ_GPIO_PIN, 1 << PCIE_CLKREQ_GPIO_PIN); - LHL_REG(sih, gpio_ctrl_iocfg_p_adr[PCIE_CLKREQ_GPIO_PIN], ~0, - (1 << GCI_GPIO_STS_NEG_EDGE_TRIG_BIT) | - (1 << GCI_GPIO_STS_WL_DIN_SELECT)); - LHL_REG(sih, gpio_int_en_port_adr[0], - 1 << PCIE_CLKREQ_GPIO_PIN, 1 << PCIE_CLKREQ_GPIO_PIN); - LHL_REG(sih, gpio_int_st_port_adr[0], - 1 << PCIE_CLKREQ_GPIO_PIN, 1 << PCIE_CLKREQ_GPIO_PIN); - } -} - -static const uint32 lpo_opt_tab[4][2] = { - { LPO1_PD_EN, LHL_LPO1_SEL }, - { LPO2_PD_EN, LHL_LPO2_SEL }, - { OSC_32k_PD, LHL_32k_SEL}, - { EXTLPO_BUF_PD, LHL_EXT_SEL } -}; - -#define LPO_EN_OFFSET 0u -#define LPO_SEL_OFFSET 1u - -static int -si_lhl_get_lpo_sel(si_t *sih, uint32 lpo) -{ - int sel; - if (lpo <= LHL_EXT_SEL) { - LHL_REG(sih, lhl_main_ctl_adr, lpo_opt_tab[lpo - 1u][LPO_EN_OFFSET], 0u); - sel = lpo_opt_tab[lpo - 1u][LPO_SEL_OFFSET]; - } else { - sel = BCME_NOTFOUND; - } - return sel; -} - -static void -si_lhl_detect_lpo(si_t *sih, osl_t *osh) -{ - uint clk_det_cnt; - int timeout = 0; - gciregs_t *gciregs; - gciregs = si_setcore(sih, GCI_CORE_ID, 0); - ASSERT(gciregs != NULL); - - LHL_REG(sih, lhl_clk_det_ctl_adr, LHL_CLK_DET_CTL_ADR_LHL_CNTR_EN, 0); - LHL_REG(sih, lhl_clk_det_ctl_adr, - LHL_CLK_DET_CTL_ADR_LHL_CNTR_CLR, LHL_CLK_DET_CTL_ADR_LHL_CNTR_CLR); - timeout = 0; - clk_det_cnt = - ((R_REG(osh, &gciregs->lhl_clk_det_ctl_adr) & LHL_CLK_DET_CNT) >> - LHL_CLK_DET_CNT_SHIFT); - while (clk_det_cnt != 0 && timeout <= LPO_SEL_TIMEOUT) { - OSL_DELAY(10); - clk_det_cnt = - ((R_REG(osh, &gciregs->lhl_clk_det_ctl_adr) & LHL_CLK_DET_CNT) >> - LHL_CLK_DET_CNT_SHIFT); - timeout++; - } - - if (clk_det_cnt != 0) { - LHL_ERROR(("Clock not present as clear did not work timeout = %d\n", timeout)); - ROMMABLE_ASSERT(0); - } - LHL_REG(sih, lhl_clk_det_ctl_adr, LHL_CLK_DET_CTL_ADR_LHL_CNTR_CLR, 0); - LHL_REG(sih, lhl_clk_det_ctl_adr, LHL_CLK_DET_CTL_ADR_LHL_CNTR_EN, - LHL_CLK_DET_CTL_ADR_LHL_CNTR_EN); - clk_det_cnt = - ((R_REG(osh, &gciregs->lhl_clk_det_ctl_adr) & LHL_CLK_DET_CNT) >> - LHL_CLK_DET_CNT_SHIFT); - timeout = 0; - - while (clk_det_cnt <= CLK_DET_CNT_THRESH && timeout <= LPO_SEL_TIMEOUT) { - OSL_DELAY(10); - clk_det_cnt = - ((R_REG(osh, &gciregs->lhl_clk_det_ctl_adr) & LHL_CLK_DET_CNT) >> - LHL_CLK_DET_CNT_SHIFT); - timeout++; - } - - if (timeout >= LPO_SEL_TIMEOUT) { - LHL_ERROR(("LPO is not available timeout = %u\n, timeout", timeout)); - ROMMABLE_ASSERT(0); - } -} - -static void -si_lhl_select_lpo(si_t *sih, osl_t *osh, int sel, uint32 lpo) -{ - uint status; - int timeout = 0u; - gciregs_t *gciregs; - uint32 final_clk_sel; - uint32 final_lpo_sel; - gciregs = si_setcore(sih, GCI_CORE_ID, 0); - ASSERT(gciregs != NULL); - - LHL_REG(sih, lhl_main_ctl_adr, - LHL_MAIN_CTL_ADR_LHL_WLCLK_SEL, (sel) << LPO_SEL_SHIFT); - final_clk_sel = (R_REG(osh, &gciregs->lhl_clk_status_adr) - & LHL_MAIN_CTL_ADR_FINAL_CLK_SEL); - final_lpo_sel = (unsigned)(((1u << sel) << LPO_FINAL_SEL_SHIFT)); - - status = (final_clk_sel == final_lpo_sel) ? 1u : 0u; - timeout = 0; - while (!status && timeout <= LPO_SEL_TIMEOUT) { - OSL_DELAY(10); - final_clk_sel = (R_REG(osh, &gciregs->lhl_clk_status_adr) - & LHL_MAIN_CTL_ADR_FINAL_CLK_SEL); - status = (final_clk_sel == final_lpo_sel) ? 1u : 0u; - timeout++; - } - - if (timeout >= LPO_SEL_TIMEOUT) { - LHL_ERROR(("LPO is not available timeout = %u\n, timeout", timeout)); - ROMMABLE_ASSERT(0); - } - - /* for 4377 and chiprev B0 and greater do not power-off other LPOs */ - if (BCM4389_CHIP(sih->chip) || BCM4378_CHIP(sih->chip) || BCM4397_CHIP(sih->chip) || - BCM4388_CHIP(sih->chip) || BCM4387_CHIP(sih->chip) || - (CHIPID(sih->chip) == BCM4377_CHIP_ID)) { - LHL_ERROR(("NOT Power Down other LPO\n")); - } else { - /* Power down the rest of the LPOs */ - - if (lpo != LHL_EXT_LPO_ENAB) { - LHL_REG(sih, lhl_main_ctl_adr, EXTLPO_BUF_PD, EXTLPO_BUF_PD); - } - - if (lpo != LHL_LPO1_ENAB) { - LHL_REG(sih, lhl_main_ctl_adr, LPO1_PD_EN, LPO1_PD_EN); - LHL_REG(sih, lhl_main_ctl_adr, LPO1_PD_SEL, LPO1_PD_SEL_VAL); - } - if (lpo != LHL_LPO2_ENAB) { - LHL_REG(sih, lhl_main_ctl_adr, LPO2_PD_EN, LPO2_PD_EN); - LHL_REG(sih, lhl_main_ctl_adr, LPO2_PD_SEL, LPO2_PD_SEL_VAL); - } - if (lpo != LHL_OSC_32k_ENAB) { - LHL_REG(sih, lhl_main_ctl_adr, OSC_32k_PD, OSC_32k_PD); - } - if (lpo != RADIO_LPO_ENAB) { - si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_06, LPO_SEL, 0); - } - } - -} - -/* To skip this function, specify a invalid "lpo_select" value in nvram */ -int -BCMATTACHFN(si_lhl_set_lpoclk)(si_t *sih, osl_t *osh, uint32 lpo_force) -{ - int lhl_wlclk_sel; - uint32 lpo = 0; - - /* Apply nvram override to lpo */ - if (!FWSIGN_ENAB()) { - if ((lpo = (uint32)getintvar(NULL, "lpo_select")) == 0) { - if (lpo_force == LHL_LPO_AUTO) { - lpo = LHL_OSC_32k_ENAB; - } else { - lpo = lpo_force; - } - } - } else { - lpo = lpo_force; - } - - lhl_wlclk_sel = si_lhl_get_lpo_sel(sih, lpo); - - if (lhl_wlclk_sel < 0) { - return BCME_OK; - } - - LHL_REG(sih, lhl_clk_det_ctl_adr, - LHL_CLK_DET_CTL_AD_CNTR_CLK_SEL, lhl_wlclk_sel); - - /* Detect the desired LPO */ - si_lhl_detect_lpo(sih, osh); - - /* Select the desired LPO */ - si_lhl_select_lpo(sih, osh, lhl_wlclk_sel, lpo); - - return BCME_OK; -} - -void -BCMATTACHFN(si_lhl_timer_config)(si_t *sih, osl_t *osh, int timer_type) -{ - uint origidx; - pmuregs_t *pmu = NULL; - - /* Remember original core before switch to chipc/pmu */ - origidx = si_coreidx(sih); - if (AOB_ENAB(sih)) { - pmu = si_setcore(sih, PMU_CORE_ID, 0); - } else { - pmu = si_setcoreidx(sih, SI_CC_IDX); - } - - ASSERT(pmu != NULL); - - switch (timer_type) { - case LHL_MAC_TIMER: - /* Enable MAC Timer interrupt */ - LHL_REG(sih, lhl_wl_mactim0_intrp_adr, - (LHL_WL_MACTIM_INTRP_EN | LHL_WL_MACTIM_INTRP_EDGE_TRIGGER), - (LHL_WL_MACTIM_INTRP_EN | LHL_WL_MACTIM_INTRP_EDGE_TRIGGER)); - - /* Programs bits for MACPHY_CLK_AVAIL and all its dependent bits in - * MacResourceReqMask0. - */ - PMU_REG(sih, mac_res_req_mask, ~0, si_pmu_rsrc_macphy_clk_deps(sih, osh, 0)); - - /* One time init of mac_res_req_timer to enable interrupt and clock request */ - HND_PMU_SYNC_WR(sih, pmu, pmu, osh, - PMUREGADDR(sih, pmu, pmu, mac_res_req_timer), - ((PRRT_ALP_REQ | PRRT_HQ_REQ | PRRT_INTEN) << FLAGS_SHIFT)); - - /* - * Reset MAC Main Timer if in case it is running due to previous instance - * This also resets the interrupt status - */ - LHL_REG(sih, lhl_wl_mactim_int0_adr, LHL_WL_MACTIMER_MASK, 0x0); - - if (si_pmu_get_mac_rsrc_req_tmr_cnt(sih) > 1) { - LHL_REG(sih, lhl_wl_mactim1_intrp_adr, - (LHL_WL_MACTIM_INTRP_EN | LHL_WL_MACTIM_INTRP_EDGE_TRIGGER), - (LHL_WL_MACTIM_INTRP_EN | LHL_WL_MACTIM_INTRP_EDGE_TRIGGER)); - - PMU_REG(sih, mac_res_req_mask1, ~0, - si_pmu_rsrc_macphy_clk_deps(sih, osh, 1)); - - HND_PMU_SYNC_WR(sih, pmu, pmu, osh, - PMUREGADDR(sih, pmu, pmu, mac_res_req_timer1), - ((PRRT_ALP_REQ | PRRT_HQ_REQ | PRRT_INTEN) << FLAGS_SHIFT)); - - /* - * Reset MAC Aux Timer if in case it is running due to previous instance - * This also resets the interrupt status - */ - LHL_REG(sih, lhl_wl_mactim_int1_adr, LHL_WL_MACTIMER_MASK, 0x0); - } - - if (si_pmu_get_mac_rsrc_req_tmr_cnt(sih) > 2) { - LHL_REG(sih, lhl_wl_mactim2_intrp_adr, - (LHL_WL_MACTIM_INTRP_EN | LHL_WL_MACTIM_INTRP_EDGE_TRIGGER), - (LHL_WL_MACTIM_INTRP_EN | LHL_WL_MACTIM_INTRP_EDGE_TRIGGER)); - - PMU_REG_NEW(sih, mac_res_req_mask2, ~0, - si_pmu_rsrc_macphy_clk_deps(sih, osh, 2)); - - HND_PMU_SYNC_WR(sih, pmu, pmu, osh, - PMUREGADDR(sih, pmu, pmu, mac_res_req_timer2), - ((PRRT_ALP_REQ | PRRT_HQ_REQ | PRRT_INTEN) << FLAGS_SHIFT)); - - /* - * Reset Scan MAC Timer if in case it is running due to previous instance - * This also resets the interrupt status - */ - LHL_REG(sih, lhl_wl_mactim_int2_adr, LHL_WL_MACTIMER_MASK, 0x0); - } - - break; - - case LHL_ARM_TIMER: - /* Enable ARM Timer interrupt */ - LHL_REG(sih, lhl_wl_armtim0_intrp_adr, - (LHL_WL_ARMTIM0_INTRP_EN | LHL_WL_ARMTIM0_INTRP_EDGE_TRIGGER), - (LHL_WL_ARMTIM0_INTRP_EN | LHL_WL_ARMTIM0_INTRP_EDGE_TRIGGER)); - - /* Programs bits for HT_AVAIL and all its dependent bits in ResourceReqMask0 */ - /* Programs bits for CORE_RDY_CB and all its dependent bits in ResourceReqMask0 */ - PMU_REG(sih, res_req_mask, ~0, (si_pmu_rsrc_ht_avail_clk_deps(sih, osh) | - si_pmu_rsrc_cb_ready_deps(sih, osh))); - - /* One time init of res_req_timer to enable interrupt and clock request - * For low power request only ALP (HT_AVAIL is anyway requested by res_req_mask) - */ - HND_PMU_SYNC_WR(sih, pmu, pmu, osh, - PMUREGADDR(sih, pmu, pmu, res_req_timer), - ((PRRT_ALP_REQ | PRRT_HQ_REQ | PRRT_INTEN) << FLAGS_SHIFT)); - break; - } - - /* Return to original core */ - si_setcoreidx(sih, origidx); -} - -void -BCMATTACHFN(si_lhl_timer_enable)(si_t *sih) -{ - /* Enable clks for pmu int propagation */ - PMU_REG(sih, pmuintctrl0, PMU_INTC_ALP_REQ, PMU_INTC_ALP_REQ); - - PMU_REG(sih, pmuintmask0, RSRC_INTR_MASK_TIMER_INT_0, RSRC_INTR_MASK_TIMER_INT_0); -#ifndef BCMQT - LHL_REG(sih, lhl_main_ctl_adr, LHL_FAST_WRITE_EN, LHL_FAST_WRITE_EN); -#endif /* BCMQT */ - PMU_REG(sih, pmucontrol_ext, PCTL_EXT_USE_LHL_TIMER, PCTL_EXT_USE_LHL_TIMER); -} - -void -BCMPOSTTRAPFN(si_lhl_timer_reset)(si_t *sih, uint coreid, uint coreunit) -{ - switch (coreid) { - case D11_CORE_ID: - switch (coreunit) { - case 0: /* MAC_CORE_UNIT_0 */ - LHL_REG(sih, lhl_wl_mactim_int0_adr, LHL_WL_MACTIMER_MASK, 0x0); - LHL_REG(sih, lhl_wl_mactim0_st_adr, - LHL_WL_MACTIMER_INT_ST_MASK, LHL_WL_MACTIMER_INT_ST_MASK); - break; - case 1: /* MAC_CORE_UNIT_1 */ - LHL_REG(sih, lhl_wl_mactim_int1_adr, LHL_WL_MACTIMER_MASK, 0x0); - LHL_REG(sih, lhl_wl_mactim1_st_adr, - LHL_WL_MACTIMER_INT_ST_MASK, LHL_WL_MACTIMER_INT_ST_MASK); - break; - case 2: /* SCAN_CORE_UNIT */ - LHL_REG(sih, lhl_wl_mactim_int2_adr, LHL_WL_MACTIMER_MASK, 0x0); - LHL_REG(sih, lhl_wl_mactim2_st_adr, - LHL_WL_MACTIMER_INT_ST_MASK, LHL_WL_MACTIMER_INT_ST_MASK); - break; - default: - LHL_ERROR(("Cannot reset lhl timer, wrong coreunit = %d\n", coreunit)); - } - break; - case ARMCR4_CORE_ID: /* intentional fallthrough */ - case ARMCA7_CORE_ID: - LHL_REG(sih, lhl_wl_armtim0_adr, LHL_WL_MACTIMER_MASK, 0x0); - LHL_REG(sih, lhl_wl_armtim0_st_adr, - LHL_WL_MACTIMER_INT_ST_MASK, LHL_WL_MACTIMER_INT_ST_MASK); - break; - default: - LHL_ERROR(("Cannot reset lhl timer, wrong coreid = 0x%x\n", coreid)); - } -} - -void -si_lhl_ilp_config(si_t *sih, osl_t *osh, uint32 ilp_period) -{ - gciregs_t *gciregs; - if ((CHIPID(sih->chip) == BCM43012_CHIP_ID) || - (CHIPID(sih->chip) == BCM43013_CHIP_ID) || - (CHIPID(sih->chip) == BCM43014_CHIP_ID)) { - gciregs = si_setcore(sih, GCI_CORE_ID, 0); - ASSERT(gciregs != NULL); - W_REG(osh, &gciregs->lhl_wl_ilp_val_adr, ilp_period); - } -} - -lhl_reg_set_t BCMATTACHDATA(lv_sleep_mode_4369_lhl_reg_set)[] = -{ - /* set wl_sleep_en */ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), (1 << 0), (1 << 0)}, - - /* set top_pwrsw_en, top_slb_en, top_iso_en */ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), BCM_MASK32(5, 3), (0x0 << 3)}, - - /* set VMUX_asr_sel_en */ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), (1 << 8), (1 << 8)}, - - /* lhl_lp_main_ctl_adr, disable lp_mode_en, set CSR and ASR field enables for LV mode */ - {LHL_REG_OFF(lhl_lp_main_ctl_adr), BCM_MASK32(21, 0), 0x3F89FF}, - - /* lhl_lp_main_ctl1_adr, set CSR field values - CSR_adj - 0.64V and trim_adj -5mV */ - {LHL_REG_OFF(lhl_lp_main_ctl1_adr), BCM_MASK32(23, 0), 0x9E9F97}, - - /* lhl_lp_main_ctl2_adr, set ASR field values - ASR_adj - 0.76V and trim_adj +5mV */ - {LHL_REG_OFF(lhl_lp_main_ctl2_adr), BCM_MASK32(13, 0), 0x07EE}, - - /* lhl_lp_dn_ctl_adr, set down count for CSR fields- adj, mode, overi_dis */ - {LHL_REG_OFF(lhl_lp_dn_ctl_adr), ~0, ((LHL4369_CSR_OVERI_DIS_DWN_CNT << 16) | - (LHL4369_CSR_MODE_DWN_CNT << 8) | (LHL4369_CSR_ADJ_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl_adr, set up count for CSR fields- adj, mode, overi_dis */ - {LHL_REG_OFF(lhl_lp_up_ctl_adr), ~0, ((LHL4369_CSR_OVERI_DIS_UP_CNT << 16) | - (LHL4369_CSR_MODE_UP_CNT << 8) | (LHL4369_CSR_ADJ_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl1_adr, set down count for hpbg_chop_dis, ASR_adj, vddc_sw_dis */ - {LHL_REG_OFF(lhl_lp_dn_ctl1_adr), ~0, ((LHL4369_VDDC_SW_DIS_DWN_CNT << 24) | - (LHL4369_ASR_ADJ_DWN_CNT << 16) | (LHL4369_HPBG_CHOP_DIS_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl1_adr, set up count for hpbg_chop_dis, ASR_adj, vddc_sw_dis */ - {LHL_REG_OFF(lhl_lp_up_ctl1_adr), ~0, ((LHL4369_VDDC_SW_DIS_UP_CNT << 24) | - (LHL4369_ASR_ADJ_UP_CNT << 16) | (LHL4369_HPBG_CHOP_DIS_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl4_adr, set down count for ASR fields - - * clk4m_dis, lppfm_mode, mode_sel, manual_mode - */ - {LHL_REG_OFF(lhl_lp_dn_ctl4_adr), ~0, ((LHL4369_ASR_MANUAL_MODE_DWN_CNT << 24) | - (LHL4369_ASR_MODE_SEL_DWN_CNT << 16) | (LHL4369_ASR_LPPFM_MODE_DWN_CNT << 8) | - (LHL4369_ASR_CLK4M_DIS_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl4_adr, set up count for ASR fields - - * clk4m_dis, lppfm_mode, mode_sel, manual_mode - */ - {LHL_REG_OFF(lhl_lp_up_ctl4_adr), ~0, ((LHL4369_ASR_MANUAL_MODE_UP_CNT << 24) | - (LHL4369_ASR_MODE_SEL_UP_CNT << 16)| (LHL4369_ASR_LPPFM_MODE_UP_CNT << 8) | - (LHL4369_ASR_CLK4M_DIS_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl3_adr, set down count for hpbg_pu, srbg_ref, ASR_overi_dis, - * CSR_pfm_pwr_slice_en - */ - {LHL_REG_OFF(lhl_lp_dn_ctl3_adr), ~0, ((LHL4369_PFM_PWR_SLICE_DWN_CNT << 24) | - (LHL4369_ASR_OVERI_DIS_DWN_CNT << 16) | (LHL4369_SRBG_REF_SEL_DWN_CNT << 8) | - (LHL4369_HPBG_PU_EN_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl3_adr, set up count for hpbg_pu, srbg_ref, ASR_overi_dis, - * CSR_pfm_pwr_slice_en - */ - {LHL_REG_OFF(lhl_lp_up_ctl3_adr), ~0, ((LHL4369_PFM_PWR_SLICE_UP_CNT << 24) | - (LHL4369_ASR_OVERI_DIS_UP_CNT << 16) | (LHL4369_SRBG_REF_SEL_UP_CNT << 8) | - (LHL4369_HPBG_PU_EN_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl2_adr, set down count for CSR_trim_adj */ - {LHL_REG_OFF(lhl_lp_dn_ctl2_adr), ~0, (LHL4369_CSR_TRIM_ADJ_DWN_CNT << 16)}, - - /* lhl_lp_up_ctl2_adr, set up count for CSR_trim_adj */ - {LHL_REG_OFF(lhl_lp_up_ctl2_adr), ~0, (LHL4369_CSR_TRIM_ADJ_UP_CNT << 16)}, - - /* lhl_lp_dn_ctl5_adr, set down count for ASR_trim_adj */ - {LHL_REG_OFF(lhl_lp_dn_ctl5_adr), ~0, (LHL4369_ASR_TRIM_ADJ_DWN_CNT << 0)}, - - /* lhl_lp_up_ctl5_adr, set down count for ASR_trim_adj */ - {LHL_REG_OFF(lhl_lp_up_ctl5_adr), ~0, (LHL4369_ASR_TRIM_ADJ_UP_CNT << 0)}, - - /* Change the default down count values for the resources */ - /* lhl_top_pwrdn_ctl_adr, set down count for top_level_sleep, iso, slb and pwrsw */ - {LHL_REG_OFF(lhl_top_pwrdn_ctl_adr), ~0, ((LHL4369_PWRSW_EN_DWN_CNT << 24) | - (LHL4369_SLB_EN_DWN_CNT << 16) | (LHL4369_ISO_EN_DWN_CNT << 8))}, - - /* lhl_top_pwrdn2_ctl_adr, set down count for VMUX_asr_sel */ - {LHL_REG_OFF(lhl_top_pwrdn2_ctl_adr), ~0, (LHL4369_VMUX_ASR_SEL_DWN_CNT << 16)}, - - /* Change the default up count values for the resources */ - /* lhl_top_pwrup_ctl_adr, set up count for top_level_sleep, iso, slb and pwrsw */ - {LHL_REG_OFF(lhl_top_pwrup_ctl_adr), ~0, ((LHL4369_PWRSW_EN_UP_CNT << 24) | - (LHL4369_SLB_EN_UP_CNT << 16) | (LHL4369_ISO_EN_UP_CNT << 8))}, - - /* lhl_top_pwrdn2_ctl_adr, set down count for VMUX_asr_sel */ - {LHL_REG_OFF(lhl_top_pwrup2_ctl_adr), ~0, ((LHL4369_VMUX_ASR_SEL_UP_CNT << 16))}, - - /* Enable lhl interrupt */ - {LHL_REG_OFF(gci_intmask), (1 << 30), (1 << 30)}, - - /* Enable LHL Wake up */ - {LHL_REG_OFF(gci_wakemask), (1 << 30), (1 << 30)}, - - /* Making forceOTPpwrOn 1 */ - {LHL_REG_OFF(otpcontrol), (1 << 16), (1 << 16)} -}; - -lhl_reg_set_t BCMATTACHDATA(lv_sleep_mode_4378_lhl_reg_set)[] = -{ - /* set wl_sleep_en */ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), (1 << 0), (1 << 0)}, - - /* set top_pwrsw_en, top_slb_en, top_iso_en */ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), BCM_MASK32(5, 3), (0x0 << 3)}, - - /* set VMUX_asr_sel_en */ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), (1 << 8), (1 << 8)}, - - /* lhl_lp_main_ctl_adr, disable lp_mode_en, set CSR and ASR field enables for LV mode */ - {LHL_REG_OFF(lhl_lp_main_ctl_adr), BCM_MASK32(21, 0), 0x3F89FF}, - - /* lhl_lp_main_ctl1_adr, set CSR field values - CSR_adj - 0.66V and trim_adj -5mV */ - {LHL_REG_OFF(lhl_lp_main_ctl1_adr), BCM_MASK32(23, 0), 0x9E9F97}, - - /* lhl_lp_main_ctl2_adr, set ASR field values - ASR_adj - 0.76V and trim_adj +5mV */ - {LHL_REG_OFF(lhl_lp_main_ctl2_adr), BCM_MASK32(13, 0), 0x07EE}, - - /* lhl_lp_dn_ctl_adr, set down count for CSR fields- adj, mode, overi_dis */ - {LHL_REG_OFF(lhl_lp_dn_ctl_adr), ~0, ((LHL4378_CSR_OVERI_DIS_DWN_CNT << 16) | - (LHL4378_CSR_MODE_DWN_CNT << 8) | (LHL4378_CSR_ADJ_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl_adr, set up count for CSR fields- adj, mode, overi_dis */ - {LHL_REG_OFF(lhl_lp_up_ctl_adr), ~0, ((LHL4378_CSR_OVERI_DIS_UP_CNT << 16) | - (LHL4378_CSR_MODE_UP_CNT << 8) | (LHL4378_CSR_ADJ_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl1_adr, set down count for hpbg_chop_dis, ASR_adj, vddc_sw_dis */ - {LHL_REG_OFF(lhl_lp_dn_ctl1_adr), ~0, ((LHL4378_VDDC_SW_DIS_DWN_CNT << 24) | - (LHL4378_ASR_ADJ_DWN_CNT << 16) | (LHL4378_HPBG_CHOP_DIS_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl1_adr, set up count for hpbg_chop_dis, ASR_adj, vddc_sw_dis */ - {LHL_REG_OFF(lhl_lp_up_ctl1_adr), ~0, ((LHL4378_VDDC_SW_DIS_UP_CNT << 24) | - (LHL4378_ASR_ADJ_UP_CNT << 16) | (LHL4378_HPBG_CHOP_DIS_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl4_adr, set down count for ASR fields - - * clk4m_dis, lppfm_mode, mode_sel, manual_mode - */ - {LHL_REG_OFF(lhl_lp_dn_ctl4_adr), ~0, ((LHL4378_ASR_MANUAL_MODE_DWN_CNT << 24) | - (LHL4378_ASR_MODE_SEL_DWN_CNT << 16) | (LHL4378_ASR_LPPFM_MODE_DWN_CNT << 8) | - (LHL4378_ASR_CLK4M_DIS_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl4_adr, set up count for ASR fields - - * clk4m_dis, lppfm_mode, mode_sel, manual_mode - */ - {LHL_REG_OFF(lhl_lp_up_ctl4_adr), ~0, ((LHL4378_ASR_MANUAL_MODE_UP_CNT << 24) | - (LHL4378_ASR_MODE_SEL_UP_CNT << 16)| (LHL4378_ASR_LPPFM_MODE_UP_CNT << 8) | - (LHL4378_ASR_CLK4M_DIS_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl3_adr, set down count for hpbg_pu, srbg_ref, ASR_overi_dis, - * CSR_pfm_pwr_slice_en - */ - {LHL_REG_OFF(lhl_lp_dn_ctl3_adr), ~0, ((LHL4378_PFM_PWR_SLICE_DWN_CNT << 24) | - (LHL4378_ASR_OVERI_DIS_DWN_CNT << 16) | (LHL4378_SRBG_REF_SEL_DWN_CNT << 8) | - (LHL4378_HPBG_PU_EN_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl3_adr, set up count for hpbg_pu, srbg_ref, ASR_overi_dis, - * CSR_pfm_pwr_slice_en - */ - {LHL_REG_OFF(lhl_lp_up_ctl3_adr), ~0, ((LHL4378_PFM_PWR_SLICE_UP_CNT << 24) | - (LHL4378_ASR_OVERI_DIS_UP_CNT << 16) | (LHL4378_SRBG_REF_SEL_UP_CNT << 8) | - (LHL4378_HPBG_PU_EN_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl2_adr, set down count for CSR_trim_adj */ - {LHL_REG_OFF(lhl_lp_dn_ctl2_adr), LHL4378_CSR_TRIM_ADJ_CNT_MASK, - (LHL4378_CSR_TRIM_ADJ_DWN_CNT << LHL4378_CSR_TRIM_ADJ_CNT_SHIFT)}, - - /* lhl_lp_up_ctl2_adr, set up count for CSR_trim_adj */ - {LHL_REG_OFF(lhl_lp_up_ctl2_adr), LHL4378_CSR_TRIM_ADJ_CNT_MASK, - (LHL4378_CSR_TRIM_ADJ_UP_CNT << LHL4378_CSR_TRIM_ADJ_CNT_SHIFT)}, - - /* lhl_lp_dn_ctl5_adr, set down count for ASR_trim_adj */ - {LHL_REG_OFF(lhl_lp_dn_ctl5_adr), ~0, (LHL4378_ASR_TRIM_ADJ_DWN_CNT << 0)}, - - /* lhl_lp_up_ctl5_adr, set down count for ASR_trim_adj */ - {LHL_REG_OFF(lhl_lp_up_ctl5_adr), LHL4378_ASR_TRIM_ADJ_CNT_MASK, - (LHL4378_ASR_TRIM_ADJ_UP_CNT << LHL4378_ASR_TRIM_ADJ_CNT_SHIFT)}, - - /* Change the default down count values for the resources */ - /* lhl_top_pwrdn_ctl_adr, set down count for top_level_sleep, iso, slb and pwrsw */ - {LHL_REG_OFF(lhl_top_pwrdn_ctl_adr), ~0, ((LHL4378_PWRSW_EN_DWN_CNT << 24) | - (LHL4378_SLB_EN_DWN_CNT << 16) | (LHL4378_ISO_EN_DWN_CNT << 8))}, - - /* lhl_top_pwrdn2_ctl_adr, set down count for VMUX_asr_sel */ - {LHL_REG_OFF(lhl_top_pwrdn2_ctl_adr), ~0, (LHL4378_VMUX_ASR_SEL_DWN_CNT << 16)}, - - /* Change the default up count values for the resources */ - /* lhl_top_pwrup_ctl_adr, set up count for top_level_sleep, iso, slb and pwrsw */ - {LHL_REG_OFF(lhl_top_pwrup_ctl_adr), ~0, ((LHL4378_PWRSW_EN_UP_CNT << 24) | - (LHL4378_SLB_EN_UP_CNT << 16) | (LHL4378_ISO_EN_UP_CNT << 8))}, - - /* lhl_top_pwrdn2_ctl_adr, set down count for VMUX_asr_sel */ - {LHL_REG_OFF(lhl_top_pwrup2_ctl_adr), ~0, ((LHL4378_VMUX_ASR_SEL_UP_CNT << 16))}, - - /* Enable lhl interrupt */ - {LHL_REG_OFF(gci_intmask), (1 << 30), (1 << 30)}, - - /* Enable LHL Wake up */ - {LHL_REG_OFF(gci_wakemask), (1 << 30), (1 << 30)}, - - /* Making forceOTPpwrOn 1 */ - {LHL_REG_OFF(otpcontrol), (1 << 16), (1 << 16)} -}; - -lhl_reg_set_t BCMATTACHDATA(lv_sleep_mode_4387_lhl_reg_set)[] = -{ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), - LHL_TOP_PWRSEQ_SLEEP_ENAB_MASK | - LHL_TOP_PWRSEQ_MISCLDO_PU_EN_MASK | - LHL_TOP_PWRSEQ_SERDES_SLB_EN_MASK | - LHL_TOP_PWRSEQ_SERDES_CLK_DIS_EN_MASK, - LHL_TOP_PWRSEQ_SLEEP_ENAB_MASK | - LHL_TOP_PWRSEQ_MISCLDO_PU_EN_MASK | - LHL_TOP_PWRSEQ_SERDES_SLB_EN_MASK | - LHL_TOP_PWRSEQ_SERDES_CLK_DIS_EN_MASK}, - - /* lhl_lp_main_ctl_adr, disable lp_mode_en, set CSR and ASR field enables for LV mode */ - {LHL_REG_OFF(lhl_lp_main_ctl_adr), BCM_MASK32(21, 0), 0x3F89FF}, - - /* lhl_lp_main_ctl1_adr, set CSR field values - CSR_adj - 0.64V and trim_adj -5mV */ - {LHL_REG_OFF(lhl_lp_main_ctl1_adr), BCM_MASK32(23, 0), 0x9ED797}, - - /* lhl_lp_main_ctl2_adr, set ASR field values - ASR_adj - 0.64V and trim_adj +5mV */ - {LHL_REG_OFF(lhl_lp_main_ctl2_adr), BCM_MASK32(13, 0), 0x076D}, - - /* lhl_lp_dn_ctl_adr, set down count for CSR fields- adj, mode, overi_dis */ - {LHL_REG_OFF(lhl_lp_dn_ctl_adr), ~0, ((LHL4378_CSR_OVERI_DIS_DWN_CNT << 16) | - (LHL4378_CSR_MODE_DWN_CNT << 8) | (LHL4378_CSR_ADJ_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl_adr, set up count for CSR fields- adj, mode, overi_dis */ - {LHL_REG_OFF(lhl_lp_up_ctl_adr), ~0, ((LHL4378_CSR_OVERI_DIS_UP_CNT << 16) | - (LHL4378_CSR_MODE_UP_CNT << 8) | (LHL4378_CSR_ADJ_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl1_adr, set down count for hpbg_chop_dis, ASR_adj, vddc_sw_dis */ - {LHL_REG_OFF(lhl_lp_dn_ctl1_adr), ~0, ((LHL4378_VDDC_SW_DIS_DWN_CNT << 24) | - (LHL4378_ASR_ADJ_DWN_CNT << 16) | (LHL4378_HPBG_CHOP_DIS_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl1_adr, set up count for hpbg_chop_dis, ASR_adj, vddc_sw_dis */ - {LHL_REG_OFF(lhl_lp_up_ctl1_adr), ~0, ((LHL4378_VDDC_SW_DIS_UP_CNT << 24) | - (LHL4378_ASR_ADJ_UP_CNT << 16) | (LHL4378_HPBG_CHOP_DIS_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl4_adr, set down count for ASR fields - - * clk4m_dis, lppfm_mode, mode_sel, manual_mode - */ - {LHL_REG_OFF(lhl_lp_dn_ctl4_adr), ~0, ((LHL4378_ASR_MANUAL_MODE_DWN_CNT << 24) | - (LHL4378_ASR_MODE_SEL_DWN_CNT << 16) | (LHL4378_ASR_LPPFM_MODE_DWN_CNT << 8) | - (LHL4378_ASR_CLK4M_DIS_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl4_adr, set up count for ASR fields - - * clk4m_dis, lppfm_mode, mode_sel, manual_mode - */ - {LHL_REG_OFF(lhl_lp_up_ctl4_adr), ~0, ((LHL4378_ASR_MANUAL_MODE_UP_CNT << 24) | - (LHL4378_ASR_MODE_SEL_UP_CNT << 16)| (LHL4378_ASR_LPPFM_MODE_UP_CNT << 8) | - (LHL4378_ASR_CLK4M_DIS_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl3_adr, set down count for hpbg_pu, srbg_ref, ASR_overi_dis, - * CSR_pfm_pwr_slice_en - */ - {LHL_REG_OFF(lhl_lp_dn_ctl3_adr), ~0, ((LHL4378_PFM_PWR_SLICE_DWN_CNT << 24) | - (LHL4378_ASR_OVERI_DIS_DWN_CNT << 16) | (LHL4378_SRBG_REF_SEL_DWN_CNT << 8) | - (LHL4378_HPBG_PU_EN_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl3_adr, set up count for hpbg_pu, srbg_ref, ASR_overi_dis, - * CSR_pfm_pwr_slice_en - */ - {LHL_REG_OFF(lhl_lp_up_ctl3_adr), ~0, ((LHL4378_PFM_PWR_SLICE_UP_CNT << 24) | - (LHL4378_ASR_OVERI_DIS_UP_CNT << 16) | (LHL4378_SRBG_REF_SEL_UP_CNT << 8) | - (LHL4378_HPBG_PU_EN_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl2_adr, set down count for CSR_trim_adj */ - {LHL_REG_OFF(lhl_lp_dn_ctl2_adr), LHL4378_CSR_TRIM_ADJ_CNT_MASK, - (LHL4378_CSR_TRIM_ADJ_DWN_CNT << LHL4378_CSR_TRIM_ADJ_CNT_SHIFT)}, - - /* lhl_lp_up_ctl2_adr, set up count for CSR_trim_adj */ - {LHL_REG_OFF(lhl_lp_up_ctl2_adr), LHL4378_CSR_TRIM_ADJ_CNT_MASK, - (LHL4378_CSR_TRIM_ADJ_UP_CNT << LHL4378_CSR_TRIM_ADJ_CNT_SHIFT)}, - - /* lhl_lp_dn_ctl5_adr, set down count for ASR_trim_adj */ - {LHL_REG_OFF(lhl_lp_dn_ctl5_adr), LHL4378_ASR_TRIM_ADJ_CNT_MASK, - (LHL4378_ASR_TRIM_ADJ_DWN_CNT << LHL4378_ASR_TRIM_ADJ_CNT_SHIFT)}, - - /* lhl_lp_up_ctl5_adr, set down count for ASR_trim_adj */ - {LHL_REG_OFF(lhl_lp_up_ctl5_adr), LHL4378_ASR_TRIM_ADJ_CNT_MASK, - (LHL4378_ASR_TRIM_ADJ_UP_CNT << LHL4378_ASR_TRIM_ADJ_CNT_SHIFT)}, - - /* Change the default down count values for the resources */ - /* lhl_top_pwrdn_ctl_adr, set down count for top_level_sleep, iso, slb and pwrsw */ - {LHL_REG_OFF(lhl_top_pwrdn_ctl_adr), ~0, ((LHL4378_PWRSW_EN_DWN_CNT << 24) | - (LHL4378_SLB_EN_DWN_CNT << 16) | (LHL4378_ISO_EN_DWN_CNT << 8))}, - - /* lhl_top_pwrdn2_ctl_adr, set down count for VMUX_asr_sel */ - {LHL_REG_OFF(lhl_top_pwrdn2_ctl_adr), ~0, (LHL4387_VMUX_ASR_SEL_DWN_CNT << 16)}, - - /* Change the default up count values for the resources */ - /* lhl_top_pwrup_ctl_adr, set up count for top_level_sleep, iso, slb and pwrsw */ - {LHL_REG_OFF(lhl_top_pwrup_ctl_adr), ~0, ((LHL4378_PWRSW_EN_UP_CNT << 24) | - (LHL4378_SLB_EN_UP_CNT << 16) | (LHL4378_ISO_EN_UP_CNT << 8))}, - - /* lhl_top_pwrdn2_ctl_adr, set down count for VMUX_asr_sel */ - {LHL_REG_OFF(lhl_top_pwrup2_ctl_adr), ~0, ((LHL4387_VMUX_ASR_SEL_UP_CNT << 16))}, - - /* Enable lhl interrupt */ - {LHL_REG_OFF(gci_intmask), (1 << 30), (1 << 30)}, - - /* Enable LHL Wake up */ - {LHL_REG_OFF(gci_wakemask), (1 << 30), (1 << 30)}, - - /* Making forceOTPpwrOn 1 */ - {LHL_REG_OFF(otpcontrol), (1 << 16), (1 << 16)}, - - /* serdes_clk_dis dn=2, miscldo_pu dn=6; Also include CRWLLHL-48 WAR set bit31 */ - {LHL_REG_OFF(lhl_top_pwrdn3_ctl_adr), ~0, 0x80040c02}, - - /* serdes_clk_dis dn=11, miscldo_pu dn=0 */ - {LHL_REG_OFF(lhl_top_pwrup3_ctl_adr), ~0, 0x00160010} -}; - -lhl_reg_set_t BCMATTACHDATA(lv_sleep_mode_4387_lhl_reg_set_top_off)[] = -{ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), - LHL_TOP_PWRSEQ_SLEEP_ENAB_MASK | - LHL_TOP_PWRSEQ_TOP_ISO_EN_MASK | - LHL_TOP_PWRSEQ_TOP_SLB_EN_MASK | - LHL_TOP_PWRSEQ_TOP_PWRSW_EN_MASK | - LHL_TOP_PWRSEQ_MISCLDO_PU_EN_MASK, - LHL_TOP_PWRSEQ_SLEEP_ENAB_MASK | - LHL_TOP_PWRSEQ_TOP_ISO_EN_MASK | - LHL_TOP_PWRSEQ_TOP_SLB_EN_MASK | - LHL_TOP_PWRSEQ_TOP_PWRSW_EN_MASK | - LHL_TOP_PWRSEQ_MISCLDO_PU_EN_MASK}, - - /* lhl_lp_main_ctl_adr, disable lp_mode_en, set CSR and ASR field enables for LV mode */ - {LHL_REG_OFF(lhl_lp_main_ctl_adr), BCM_MASK32(21, 0), 0x3F87DB}, - - /* lhl_lp_main_ctl1_adr, set CSR field values - CSR_adj - 0.64V and trim_adj -5mV */ - {LHL_REG_OFF(lhl_lp_main_ctl1_adr), BCM_MASK32(23, 0), 0x9ED7B7}, - - /* lhl_lp_main_ctl2_adr, set ASR field values - ASR_adj - 0.64V and trim_adj +5mV */ - {LHL_REG_OFF(lhl_lp_main_ctl2_adr), BCM_MASK32(13, 0), 0x076D}, - - /* lhl_lp_dn_ctl_adr, set down count for CSR fields- adj, mode, overi_dis */ - {LHL_REG_OFF(lhl_lp_dn_ctl_adr), ~0, ((LHL4387_TO_CSR_OVERI_DIS_DWN_CNT << 16) | - (LHL4387_TO_CSR_MODE_DWN_CNT << 8) | (LHL4387_TO_CSR_ADJ_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl_adr, set up count for CSR fields- adj, mode, overi_dis */ - {LHL_REG_OFF(lhl_lp_up_ctl_adr), ~0, ((LHL4387_TO_CSR_OVERI_DIS_UP_CNT << 16) | - (LHL4387_TO_CSR_MODE_UP_CNT << 8) | (LHL4387_TO_CSR_ADJ_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl1_adr, set down count for hpbg_chop_dis, lp_mode_dn_cnt, - * ASR_adj, vddc_sw_dis - */ - {LHL_REG_OFF(lhl_lp_dn_ctl1_adr), ~0, ((LHL4387_TO_VDDC_SW_DIS_DWN_CNT << 24) | - (LHL4387_TO_ASR_ADJ_DWN_CNT << 16) | (LHL4387_TO_LP_MODE_DWN_CNT << 8) | - (LHL4387_TO_HPBG_CHOP_DIS_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl1_adr, set up count for hpbg_chop_dis, lp_mode_dn_cnt, - * ASR_adj, vddc_sw_dis - */ - {LHL_REG_OFF(lhl_lp_up_ctl1_adr), ~0, ((LHL4387_TO_VDDC_SW_DIS_UP_CNT << 24) | - (LHL4387_TO_ASR_ADJ_UP_CNT << 16) | (LHL4387_TO_LP_MODE_UP_CNT << 8) | - (LHL4387_TO_HPBG_CHOP_DIS_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl4_adr, set down count for ASR fields - - * clk4m_dis, lppfm_mode, mode_sel, manual_mode - */ - {LHL_REG_OFF(lhl_lp_dn_ctl4_adr), ~0, ((LHL4387_TO_ASR_MANUAL_MODE_DWN_CNT << 24) | - (LHL4387_TO_ASR_MODE_SEL_DWN_CNT << 16) | (LHL4387_TO_ASR_LPPFM_MODE_DWN_CNT << 8) | - (LHL4387_TO_ASR_CLK4M_DIS_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl4_adr, set up count for ASR fields - - * clk4m_dis, lppfm_mode, mode_sel, manual_mode - */ - {LHL_REG_OFF(lhl_lp_up_ctl4_adr), ~0, ((LHL4387_TO_ASR_MANUAL_MODE_UP_CNT << 24) | - (LHL4387_TO_ASR_MODE_SEL_UP_CNT << 16)| (LHL4387_TO_ASR_LPPFM_MODE_UP_CNT << 8) | - (LHL4387_TO_ASR_CLK4M_DIS_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl3_adr, set down count for hpbg_pu, srbg_ref, ASR_overi_dis, - * CSR_pfm_pwr_slice_en - */ - {LHL_REG_OFF(lhl_lp_dn_ctl3_adr), ~0, ((LHL4387_TO_PFM_PWR_SLICE_DWN_CNT << 24) | - (LHL4387_TO_ASR_OVERI_DIS_DWN_CNT << 16) | (LHL4387_TO_SRBG_REF_SEL_DWN_CNT << 8) | - (LHL4387_TO_HPBG_PU_EN_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl3_adr, set up count for hpbg_pu, srbg_ref, ASR_overi_dis, - * CSR_pfm_pwr_slice_en - */ - {LHL_REG_OFF(lhl_lp_up_ctl3_adr), ~0, ((LHL4387_TO_PFM_PWR_SLICE_UP_CNT << 24) | - (LHL4387_TO_ASR_OVERI_DIS_UP_CNT << 16) | (LHL4387_TO_SRBG_REF_SEL_UP_CNT << 8) | - (LHL4387_TO_HPBG_PU_EN_UP_CNT << 0))}, - - /* ASR_trim_adj downcount=0x3, [30:24] is default value for spmi_*io_sel */ - {LHL_REG_OFF(lhl_lp_dn_ctl5_adr), LHL4378_ASR_TRIM_ADJ_CNT_MASK, 0x3}, - - /* ASR_trim_adj upcount=0x1, [30:24] is default value for spmi_*io_sel */ - {LHL_REG_OFF(lhl_lp_up_ctl5_adr), LHL4378_ASR_TRIM_ADJ_CNT_MASK, 0x1}, - - /* Change the default down count values for the resources */ - /* lhl_top_pwrdn_ctl_adr, set down count for top_level_sleep, iso, slb and pwrsw */ - {LHL_REG_OFF(lhl_top_pwrdn_ctl_adr), ~0, ((LHL4387_TO_PWRSW_EN_DWN_CNT << 24) | - (LHL4387_TO_SLB_EN_DWN_CNT << 16) | (LHL4387_TO_ISO_EN_DWN_CNT << 8) | - (LHL4387_TO_TOP_SLP_EN_DWN_CNT))}, - - /* Change the default up count values for the resources */ - /* lhl_top_pwrup_ctl_adr, set up count for top_level_sleep, iso, slb and pwrsw */ - {LHL_REG_OFF(lhl_top_pwrup_ctl_adr), ~0, ((LHL4387_TO_PWRSW_EN_UP_CNT << 24) | - (LHL4387_TO_SLB_EN_UP_CNT << 16) | (LHL4387_TO_ISO_EN_UP_CNT << 8) | - (LHL4387_TO_TOP_SLP_EN_UP_CNT))}, - - /* lhl_top_pwrup2_ctl, serdes_slb_en_up_cnt=0x7 */ - {LHL_REG_OFF(lhl_top_pwrup2_ctl_adr), LHL4378_CSR_TRIM_ADJ_CNT_MASK, 0xe0000}, - - /* lhl_top_pwrdn2_ctl, serdes_slb_en_dn_cnt=0x2 */ - {LHL_REG_OFF(lhl_top_pwrdn2_ctl_adr), LHL4378_CSR_TRIM_ADJ_CNT_MASK, 0x40000}, - - /* Enable lhl interrupt */ - {LHL_REG_OFF(gci_intmask), (1 << 30), (1 << 30)}, - - /* Enable LHL Wake up */ - {LHL_REG_OFF(gci_wakemask), (1 << 30), (1 << 30)}, - - /* Making forceOTPpwrOn 1 */ - {LHL_REG_OFF(otpcontrol), (1 << 16), (1 << 16)}, - - /* lhl_top_pwrup3_ctl, FLL pu power up count=0x8, miscldo pu power up count=0x0, - * serdes_clk_dis up count=0x7 - */ - {LHL_REG_OFF(lhl_top_pwrup3_ctl_adr), ~0, 0xe0010}, - - /* lhl_top_pwrdn3_ctl, FLL pu power up count=0x1,miscldo pu power up count=0x3, - * serdes_clk_dis up count=0x1 - */ - {LHL_REG_OFF(lhl_top_pwrdn3_ctl_adr), ~0, 0x20602} -}; - -lhl_reg_set_t BCMATTACHDATA(lv_sleep_mode_4389_lhl_reg_set)[] = -{ - /* set wl_sleep_en */ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), (1 << 0), (1 << 0)}, - - /* set top_pwrsw_en, top_slb_en, top_iso_en */ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), BCM_MASK32(5, 3), (0x0 << 3)}, - - /* set VMUX_asr_sel_en */ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), (1 << 8), (1 << 8)}, - - /* lhl_lp_main_ctl_adr, disable lp_mode_en, set CSR and ASR field enables for LV mode */ - {LHL_REG_OFF(lhl_lp_main_ctl_adr), BCM_MASK32(21, 0), 0x3F89FF}, - - /* lhl_lp_main_ctl1_adr, set CSR field values - CSR_adj - 0.64V and trim_adj -5mV */ - {LHL_REG_OFF(lhl_lp_main_ctl1_adr), BCM_MASK32(23, 0), 0x9EDF97}, - - /* lhl_lp_main_ctl2_adr, set ASR field values - ASR_adj - 0.64V and trim_adj +5mV */ - {LHL_REG_OFF(lhl_lp_main_ctl2_adr), BCM_MASK32(13, 0), 0x07ED}, - - /* lhl_lp_dn_ctl_adr, set down count for CSR fields- adj, mode, overi_dis */ - {LHL_REG_OFF(lhl_lp_dn_ctl_adr), ~0, ((LHL4378_CSR_OVERI_DIS_DWN_CNT << 16) | - (LHL4378_CSR_MODE_DWN_CNT << 8) | (LHL4378_CSR_ADJ_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl_adr, set up count for CSR fields- adj, mode, overi_dis */ - {LHL_REG_OFF(lhl_lp_up_ctl_adr), ~0, ((LHL4378_CSR_OVERI_DIS_UP_CNT << 16) | - (LHL4378_CSR_MODE_UP_CNT << 8) | (LHL4378_CSR_ADJ_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl1_adr, set down count for hpbg_chop_dis, ASR_adj, vddc_sw_dis */ - {LHL_REG_OFF(lhl_lp_dn_ctl1_adr), ~0, ((LHL4378_VDDC_SW_DIS_DWN_CNT << 24) | - (LHL4378_ASR_ADJ_DWN_CNT << 16) | (LHL4378_HPBG_CHOP_DIS_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl1_adr, set up count for hpbg_chop_dis, ASR_adj, vddc_sw_dis */ - {LHL_REG_OFF(lhl_lp_up_ctl1_adr), ~0, ((LHL4378_VDDC_SW_DIS_UP_CNT << 24) | - (LHL4378_ASR_ADJ_UP_CNT << 16) | (LHL4378_HPBG_CHOP_DIS_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl4_adr, set down count for ASR fields - - * clk4m_dis, lppfm_mode, mode_sel, manual_mode - */ - {LHL_REG_OFF(lhl_lp_dn_ctl4_adr), ~0, ((LHL4378_ASR_MANUAL_MODE_DWN_CNT << 24) | - (LHL4378_ASR_MODE_SEL_DWN_CNT << 16) | (LHL4378_ASR_LPPFM_MODE_DWN_CNT << 8) | - (LHL4378_ASR_CLK4M_DIS_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl4_adr, set up count for ASR fields - - * clk4m_dis, lppfm_mode, mode_sel, manual_mode - */ - {LHL_REG_OFF(lhl_lp_up_ctl4_adr), ~0, ((LHL4378_ASR_MANUAL_MODE_UP_CNT << 24) | - (LHL4378_ASR_MODE_SEL_UP_CNT << 16)| (LHL4378_ASR_LPPFM_MODE_UP_CNT << 8) | - (LHL4378_ASR_CLK4M_DIS_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl3_adr, set down count for hpbg_pu, srbg_ref, ASR_overi_dis, - * CSR_pfm_pwr_slice_en - */ - {LHL_REG_OFF(lhl_lp_dn_ctl3_adr), ~0, ((LHL4378_PFM_PWR_SLICE_DWN_CNT << 24) | - (LHL4378_ASR_OVERI_DIS_DWN_CNT << 16) | (LHL4378_SRBG_REF_SEL_DWN_CNT << 8) | - (LHL4378_HPBG_PU_EN_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl3_adr, set up count for hpbg_pu, srbg_ref, ASR_overi_dis, - * CSR_pfm_pwr_slice_en - */ - {LHL_REG_OFF(lhl_lp_up_ctl3_adr), ~0, ((LHL4378_PFM_PWR_SLICE_UP_CNT << 24) | - (LHL4378_ASR_OVERI_DIS_UP_CNT << 16) | (LHL4378_SRBG_REF_SEL_UP_CNT << 8) | - (LHL4378_HPBG_PU_EN_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl2_adr, set down count for CSR_trim_adj */ - {LHL_REG_OFF(lhl_lp_dn_ctl2_adr), ~0, (LHL4378_CSR_TRIM_ADJ_DWN_CNT << 16)}, - - /* lhl_lp_up_ctl2_adr, set up count for CSR_trim_adj */ - {LHL_REG_OFF(lhl_lp_up_ctl2_adr), ~0, (LHL4378_CSR_TRIM_ADJ_UP_CNT << 16)}, - - /* lhl_lp_dn_ctl5_adr, set down count for ASR_trim_adj */ - {LHL_REG_OFF(lhl_lp_dn_ctl5_adr), LHL4378_ASR_TRIM_ADJ_CNT_MASK, - (LHL4378_ASR_TRIM_ADJ_DWN_CNT << LHL4378_ASR_TRIM_ADJ_CNT_SHIFT)}, - - /* lhl_lp_up_ctl5_adr, set down count for ASR_trim_adj */ - {LHL_REG_OFF(lhl_lp_up_ctl5_adr), LHL4378_ASR_TRIM_ADJ_CNT_MASK, - (LHL4378_ASR_TRIM_ADJ_UP_CNT << LHL4378_ASR_TRIM_ADJ_CNT_SHIFT)}, - - /* Change the default down count values for the resources */ - /* lhl_top_pwrdn_ctl_adr, set down count for top_level_sleep, iso, slb and pwrsw */ - {LHL_REG_OFF(lhl_top_pwrdn_ctl_adr), ~0, ((LHL4378_PWRSW_EN_DWN_CNT << 24) | - (LHL4378_SLB_EN_DWN_CNT << 16) | (LHL4378_ISO_EN_DWN_CNT << 8))}, - - /* lhl_top_pwrdn2_ctl_adr, set down count for VMUX_asr_sel */ - {LHL_REG_OFF(lhl_top_pwrdn2_ctl_adr), ~0, (LHL4387_VMUX_ASR_SEL_DWN_CNT << 16)}, - - /* Change the default up count values for the resources */ - /* lhl_top_pwrup_ctl_adr, set up count for top_level_sleep, iso, slb and pwrsw */ - {LHL_REG_OFF(lhl_top_pwrup_ctl_adr), ~0, ((LHL4378_PWRSW_EN_UP_CNT << 24) | - (LHL4378_SLB_EN_UP_CNT << 16) | (LHL4378_ISO_EN_UP_CNT << 8))}, - - /* lhl_top_pwrdn2_ctl_adr, set down count for VMUX_asr_sel */ - {LHL_REG_OFF(lhl_top_pwrup2_ctl_adr), ~0, ((LHL4387_VMUX_ASR_SEL_UP_CNT << 16))}, - - /* Enable lhl interrupt */ - {LHL_REG_OFF(gci_intmask), (1 << 30), (1 << 30)}, - - /* Enable LHL Wake up */ - {LHL_REG_OFF(gci_wakemask), (1 << 30), (1 << 30)}, - - /* Making forceOTPpwrOn 1 */ - {LHL_REG_OFF(otpcontrol), (1 << 16), (1 << 16)}, - - /* serdes_clk_dis dn=2, miscldo_pu dn=6; Also include CRWLLHL-48 WAR set bit31 */ - {LHL_REG_OFF(lhl_top_pwrdn3_ctl_adr), ~0, 0x80040c02}, - - /* serdes_clk_dis dn=11, miscldo_pu dn=0 */ - {LHL_REG_OFF(lhl_top_pwrup3_ctl_adr), ~0, 0x00160010} -}; - -/* LV sleep mode summary: - * LV mode is where both ABUCK and CBUCK are programmed to low voltages during - * sleep, and VMUX selects ABUCK as VDDOUT_AON. LPLDO needs to power off. - * With ASR ON, LPLDO OFF - */ -void -BCMATTACHFN(si_set_lv_sleep_mode_lhl_config_4369)(si_t *sih) -{ - uint i; - uint coreidx = si_findcoreidx(sih, GCI_CORE_ID, 0); - lhl_reg_set_t *regs = lv_sleep_mode_4369_lhl_reg_set; - - /* Enable LHL LV mode: - * lhl_top_pwrseq_ctl_adr, set wl_sleep_en, iso_en, slb_en, pwrsw_en,VMUX_asr_sel_en - */ - for (i = 0; i < ARRAYSIZE(lv_sleep_mode_4369_lhl_reg_set); i++) { - si_corereg(sih, coreidx, regs[i].offset, regs[i].mask, regs[i].val); - } - if (getintvar(NULL, rstr_rfldo3p3_cap_war)) { - si_corereg(sih, coreidx, LHL_REG_OFF(lhl_lp_main_ctl1_adr), - BCM_MASK32(23, 0), 0x9E9F9F); - } -} - -void -BCMATTACHFN(si_set_lv_sleep_mode_lhl_config_4378)(si_t *sih) -{ - uint i; - uint coreidx = si_findcoreidx(sih, GCI_CORE_ID, 0); - lhl_reg_set_t *regs = lv_sleep_mode_4378_lhl_reg_set; - - /* Enable LHL LV mode: - * lhl_top_pwrseq_ctl_adr, set wl_sleep_en, iso_en, slb_en, pwrsw_en,VMUX_asr_sel_en - */ - for (i = 0; i < ARRAYSIZE(lv_sleep_mode_4378_lhl_reg_set); i++) { - si_corereg(sih, coreidx, regs[i].offset, regs[i].mask, regs[i].val); - } -} - -void -BCMATTACHFN(si_set_lv_sleep_mode_lhl_config_4387)(si_t *sih) -{ - uint i; - uint coreidx = si_findcoreidx(sih, GCI_CORE_ID, 0); - lhl_reg_set_t *regs; - uint32 abuck_volt_sleep, cbuck_volt_sleep; - uint regs_size; - - if (BCMSRTOPOFF_ENAB()) { - regs = lv_sleep_mode_4387_lhl_reg_set_top_off; - regs_size = ARRAYSIZE(lv_sleep_mode_4387_lhl_reg_set_top_off); - } else { - /* Enable LHL LV mode: - * lhl_top_pwrseq_ctl_adr, set wl_sleep_en, iso_en, slb_en, pwrsw_en,VMUX_asr_sel_en - */ - regs = lv_sleep_mode_4387_lhl_reg_set; - regs_size = ARRAYSIZE(lv_sleep_mode_4387_lhl_reg_set); - } - - for (i = 0; i < regs_size; i++) { - si_corereg(sih, coreidx, regs[i].offset, regs[i].mask, regs[i].val); - } - - if (getvar(NULL, rstr_cbuck_volt_sleep) != NULL) { - cbuck_volt_sleep = getintvar(NULL, rstr_cbuck_volt_sleep); - LHL_REG(sih, lhl_lp_main_ctl1_adr, LHL_CBUCK_VOLT_SLEEP_MASK, - (cbuck_volt_sleep << LHL_CBUCK_VOLT_SLEEP_SHIFT)); - } - - if (getvar(NULL, rstr_abuck_volt_sleep) != NULL) { - abuck_volt_sleep = getintvar(NULL, rstr_abuck_volt_sleep); - LHL_REG(sih, lhl_lp_main_ctl2_adr, LHL_ABUCK_VOLT_SLEEP_MASK, - (abuck_volt_sleep << LHL_ABUCK_VOLT_SLEEP_SHIFT)); - } - - if (BCMSRTOPOFF_ENAB()) { - /* Serdes AFE retention control enable */ - si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_05, - CC_GCI_05_4387C0_AFE_RET_ENB_MASK, - CC_GCI_05_4387C0_AFE_RET_ENB_MASK); - } -} - -void -BCMATTACHFN(si_set_lv_sleep_mode_lhl_config_4389)(si_t *sih) -{ - uint i; - uint coreidx = si_findcoreidx(sih, GCI_CORE_ID, 0); - lhl_reg_set_t *regs = lv_sleep_mode_4389_lhl_reg_set; - uint32 abuck_volt_sleep, cbuck_volt_sleep; - - /* Enable LHL LV mode: - * lhl_top_pwrseq_ctl_adr, set wl_sleep_en, iso_en, slb_en, pwrsw_en,VMUX_asr_sel_en - */ - for (i = 0; i < ARRAYSIZE(lv_sleep_mode_4389_lhl_reg_set); i++) { - si_corereg(sih, coreidx, regs[i].offset, regs[i].mask, regs[i].val); - } - - if (getvar(NULL, rstr_cbuck_volt_sleep) != NULL) { - cbuck_volt_sleep = getintvar(NULL, rstr_cbuck_volt_sleep); - LHL_REG(sih, lhl_lp_main_ctl1_adr, LHL_CBUCK_VOLT_SLEEP_MASK, - (cbuck_volt_sleep << LHL_CBUCK_VOLT_SLEEP_SHIFT)); - } - - if (getvar(NULL, rstr_abuck_volt_sleep) != NULL) { - abuck_volt_sleep = getintvar(NULL, rstr_abuck_volt_sleep); - LHL_REG(sih, lhl_lp_main_ctl2_adr, LHL_ABUCK_VOLT_SLEEP_MASK, - (abuck_volt_sleep << LHL_ABUCK_VOLT_SLEEP_SHIFT)); - } - - OSL_DELAY(100); - LHL_REG(sih, lhl_top_pwrseq_ctl_adr, ~0, 0x00000101); - - /* Clear Misc_LDO override */ - si_pmu_vreg_control(sih, PMU_VREG_5, VREG5_4387_MISCLDO_PU_MASK, 0); -} - -lhl_reg_set_t BCMATTACHDATA(lv_sleep_mode_4362_lhl_reg_set)[] = -{ - /* set wl_sleep_en */ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), (1 << 0), (1 << 0)}, - - /* set top_pwrsw_en, top_slb_en, top_iso_en */ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), BCM_MASK32(5, 3), (0x0 << 3)}, - - /* set VMUX_asr_sel_en */ - {LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), (1 << 8), (1 << 8)}, - - /* lhl_lp_main_ctl_adr, disable lp_mode_en, set CSR and ASR field enables for LV mode */ - {LHL_REG_OFF(lhl_lp_main_ctl_adr), BCM_MASK32(21, 0), 0x3F89FF}, - - /* lhl_lp_main_ctl1_adr, set CSR field values - CSR_adj - 0.66V and trim_adj -5mV */ - {LHL_REG_OFF(lhl_lp_main_ctl1_adr), BCM_MASK32(23, 0), 0x9E9F97}, - - /* lhl_lp_main_ctl2_adr, set ASR field values - ASR_adj - 0.76V and trim_adj +5mV */ - {LHL_REG_OFF(lhl_lp_main_ctl2_adr), BCM_MASK32(13, 0), 0x07EE}, - - /* lhl_lp_dn_ctl_adr, set down count for CSR fields- adj, mode, overi_dis */ - {LHL_REG_OFF(lhl_lp_dn_ctl_adr), ~0, ((LHL4362_CSR_OVERI_DIS_DWN_CNT << 16) | - (LHL4362_CSR_MODE_DWN_CNT << 8) | (LHL4362_CSR_ADJ_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl_adr, set up count for CSR fields- adj, mode, overi_dis */ - {LHL_REG_OFF(lhl_lp_up_ctl_adr), ~0, ((LHL4362_CSR_OVERI_DIS_UP_CNT << 16) | - (LHL4362_CSR_MODE_UP_CNT << 8) | (LHL4362_CSR_ADJ_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl1_adr, set down count for hpbg_chop_dis, ASR_adj, vddc_sw_dis */ - {LHL_REG_OFF(lhl_lp_dn_ctl1_adr), ~0, ((LHL4362_VDDC_SW_DIS_DWN_CNT << 24) | - (LHL4362_ASR_ADJ_DWN_CNT << 16) | (LHL4362_HPBG_CHOP_DIS_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl1_adr, set up count for hpbg_chop_dis, ASR_adj, vddc_sw_dis */ - {LHL_REG_OFF(lhl_lp_up_ctl1_adr), ~0, ((LHL4362_VDDC_SW_DIS_UP_CNT << 24) | - (LHL4362_ASR_ADJ_UP_CNT << 16) | (LHL4362_HPBG_CHOP_DIS_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl4_adr, set down count for ASR fields - - * clk4m_dis, lppfm_mode, mode_sel, manual_mode - */ - {LHL_REG_OFF(lhl_lp_dn_ctl4_adr), ~0, ((LHL4362_ASR_MANUAL_MODE_DWN_CNT << 24) | - (LHL4362_ASR_MODE_SEL_DWN_CNT << 16) | (LHL4362_ASR_LPPFM_MODE_DWN_CNT << 8) | - (LHL4362_ASR_CLK4M_DIS_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl4_adr, set up count for ASR fields - - * clk4m_dis, lppfm_mode, mode_sel, manual_mode - */ - {LHL_REG_OFF(lhl_lp_up_ctl4_adr), ~0, ((LHL4362_ASR_MANUAL_MODE_UP_CNT << 24) | - (LHL4362_ASR_MODE_SEL_UP_CNT << 16)| (LHL4362_ASR_LPPFM_MODE_UP_CNT << 8) | - (LHL4362_ASR_CLK4M_DIS_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl3_adr, set down count for hpbg_pu, srbg_ref, ASR_overi_dis, - * CSR_pfm_pwr_slice_en - */ - {LHL_REG_OFF(lhl_lp_dn_ctl3_adr), ~0, ((LHL4362_PFM_PWR_SLICE_DWN_CNT << 24) | - (LHL4362_ASR_OVERI_DIS_DWN_CNT << 16) | (LHL4362_SRBG_REF_SEL_DWN_CNT << 8) | - (LHL4362_HPBG_PU_EN_DWN_CNT << 0))}, - - /* lhl_lp_up_ctl3_adr, set up count for hpbg_pu, srbg_ref, ASR_overi_dis, - * CSR_pfm_pwr_slice_en - */ - {LHL_REG_OFF(lhl_lp_up_ctl3_adr), ~0, ((LHL4362_PFM_PWR_SLICE_UP_CNT << 24) | - (LHL4362_ASR_OVERI_DIS_UP_CNT << 16) | (LHL4362_SRBG_REF_SEL_UP_CNT << 8) | - (LHL4362_HPBG_PU_EN_UP_CNT << 0))}, - - /* lhl_lp_dn_ctl2_adr, set down count for CSR_trim_adj */ - {LHL_REG_OFF(lhl_lp_dn_ctl2_adr), ~0, (LHL4362_CSR_TRIM_ADJ_DWN_CNT << 16)}, - - /* lhl_lp_up_ctl2_adr, set up count for CSR_trim_adj */ - {LHL_REG_OFF(lhl_lp_up_ctl2_adr), ~0, (LHL4362_CSR_TRIM_ADJ_UP_CNT << 16)}, - - /* lhl_lp_dn_ctl5_adr, set down count for ASR_trim_adj */ - {LHL_REG_OFF(lhl_lp_dn_ctl5_adr), ~0, (LHL4362_ASR_TRIM_ADJ_DWN_CNT << 0)}, - - /* lhl_lp_up_ctl5_adr, set down count for ASR_trim_adj */ - {LHL_REG_OFF(lhl_lp_up_ctl5_adr), ~0, (LHL4362_ASR_TRIM_ADJ_UP_CNT << 0)}, - - /* Change the default down count values for the resources */ - /* lhl_top_pwrdn_ctl_adr, set down count for top_level_sleep, iso, slb and pwrsw */ - {LHL_REG_OFF(lhl_top_pwrdn_ctl_adr), ~0, ((LHL4362_PWRSW_EN_DWN_CNT << 24) | - (LHL4362_SLB_EN_DWN_CNT << 16) | (LHL4362_ISO_EN_DWN_CNT << 8))}, - - /* lhl_top_pwrdn2_ctl_adr, set down count for VMUX_asr_sel */ - {LHL_REG_OFF(lhl_top_pwrdn2_ctl_adr), ~0, (LHL4362_VMUX_ASR_SEL_DWN_CNT << 16)}, - - /* Change the default up count values for the resources */ - /* lhl_top_pwrup_ctl_adr, set up count for top_level_sleep, iso, slb and pwrsw */ - {LHL_REG_OFF(lhl_top_pwrup_ctl_adr), ~0, ((LHL4362_PWRSW_EN_UP_CNT << 24) | - (LHL4362_SLB_EN_UP_CNT << 16) | (LHL4362_ISO_EN_UP_CNT << 8))}, - - /* lhl_top_pwrdn2_ctl_adr, set down count for VMUX_asr_sel */ - {LHL_REG_OFF(lhl_top_pwrup2_ctl_adr), ~0, ((LHL4362_VMUX_ASR_SEL_UP_CNT << 16))}, - - /* Enable lhl interrupt */ - {LHL_REG_OFF(gci_intmask), (1 << 30), (1 << 30)}, - - /* Enable LHL Wake up */ - {LHL_REG_OFF(gci_wakemask), (1 << 30), (1 << 30)}, - - /* Making forceOTPpwrOn 1 */ - {LHL_REG_OFF(otpcontrol), (1 << 16), (1 << 16)} -}; - -/* LV sleep mode summary: - * LV mode is where both ABUCK and CBUCK are programmed to low voltages during - * sleep, and VMUX selects ABUCK as VDDOUT_AON. LPLDO needs to power off. - * With ASR ON, LPLDO OFF - */ -void -BCMATTACHFN(si_set_lv_sleep_mode_lhl_config_4362)(si_t *sih) -{ - uint i; - uint coreidx = si_findcoreidx(sih, GCI_CORE_ID, 0); - lhl_reg_set_t *regs = lv_sleep_mode_4362_lhl_reg_set; - - /* Enable LHL LV mode: - * lhl_top_pwrseq_ctl_adr, set wl_sleep_en, iso_en, slb_en, pwrsw_en,VMUX_asr_sel_en - */ - for (i = 0; i < ARRAYSIZE(lv_sleep_mode_4362_lhl_reg_set); i++) { - si_corereg(sih, coreidx, regs[i].offset, regs[i].mask, regs[i].val); - } -} - -void -si_lhl_mactim0_set(si_t *sih, uint32 val) -{ - LHL_REG(sih, lhl_wl_mactim_int0_adr, LHL_WL_MACTIMER_MASK, val); -} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hndmem.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hndmem.c deleted file mode 100755 index 18dbced23b50..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hndmem.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Utility routines for configuring different memories in Broadcom chips. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define IS_MEMTYPE_VALID(mem) ((mem >= MEM_SOCRAM) && (mem < MEM_MAX)) -#define IS_MEMCONFIG_VALID(cfg) ((cfg >= PDA_CONFIG_CLEAR) && (cfg < PDA_CONFIG_MAX)) - -/* Returns the number of banks in a given memory */ -int -hndmem_num_banks(si_t *sih, int mem) -{ - uint32 savecore, mem_info; - int num_banks = 0; - gciregs_t *gciregs; - osl_t *osh = si_osh(sih); - - if (!IS_MEMTYPE_VALID(mem)) { - goto exit; - } - - savecore = si_coreidx(sih); - - /* TODO: Check whether SOCRAM core is present or not. If not, bail out */ - /* In future we need to add code for TCM based chips as well */ - if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) { - goto exit; - } - - if (GCIREV(sih->gcirev) >= 9) { - gciregs = si_setcore(sih, GCI_CORE_ID, 0); - - mem_info = R_REG(osh, &gciregs->wlan_mem_info); - - switch (mem) { - case MEM_SOCRAM: - num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMSOCRAMBANKS_MASK) >> - WLAN_MEM_INFO_REG_NUMSOCRAMBANKS_SHIFT; - break; - case MEM_BM: - num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMD11MACBM_MASK) >> - WLAN_MEM_INFO_REG_NUMD11MACBM_SHIFT; - break; - case MEM_UCM: - num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMD11MACUCM_MASK) >> - WLAN_MEM_INFO_REG_NUMD11MACUCM_SHIFT; - break; - case MEM_SHM: - num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMD11MACSHM_MASK) >> - WLAN_MEM_INFO_REG_NUMD11MACSHM_SHIFT; - break; - default: - ASSERT(0); - break; - } - } else { - /* TODO: Figure out bank information using SOCRAM registers */ - } - - si_setcoreidx(sih, savecore); -exit: - return num_banks; -} - -/* Returns the size of a give bank in a given memory */ -int -hndmem_bank_size(si_t *sih, hndmem_type_t mem, int bank_num) -{ - uint32 savecore, bank_info, reg_data; - int bank_sz = 0; - gciregs_t *gciregs; - osl_t *osh = si_osh(sih); - - if (!IS_MEMTYPE_VALID(mem)) { - goto exit; - } - - savecore = si_coreidx(sih); - - /* TODO: Check whether SOCRAM core is present or not. If not, bail out */ - /* In future we need to add code for TCM based chips as well */ - if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) { - goto exit; - } - - if (GCIREV(sih->gcirev) >= 9) { - gciregs = si_setcore(sih, GCI_CORE_ID, 0); - - reg_data = ((mem & - GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_MASK) << - GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_SHIFT) | - ((bank_num & GCI_INDIRECT_ADDRESS_REG_REGINDEX_MASK) - << GCI_INDIRECT_ADDRESS_REG_REGINDEX_SHIFT); - W_REG(osh, &gciregs->gci_indirect_addr, reg_data); - - bank_info = R_REG(osh, &gciregs->wlan_bankxinfo); - bank_sz = (bank_info & WLAN_BANKXINFO_BANK_SIZE_MASK) >> - WLAN_BANKXINFO_BANK_SIZE_SHIFT; - } else { - /* TODO: Figure out bank size using SOCRAM registers */ - } - - si_setcoreidx(sih, savecore); -exit: - return bank_sz; -} - -/* Returns the start address of given memory */ -uint32 -hndmem_mem_base(si_t *sih, hndmem_type_t mem) -{ - uint32 savecore, base_addr = 0; - - /* Currently only support of SOCRAM is available in hardware */ - if (mem != MEM_SOCRAM) { - goto exit; - } - - savecore = si_coreidx(sih); - - if (si_setcore(sih, SOCRAM_CORE_ID, 0)) - { - base_addr = si_get_slaveport_addr(sih, CORE_SLAVE_PORT_1, - CORE_BASE_ADDR_0, SOCRAM_CORE_ID, 0); - } else { - /* TODO: Add code to get the base address of TCM */ - base_addr = 0; - } - - si_setcoreidx(sih, savecore); - -exit: - return base_addr; -} - -#ifdef BCMDEBUG -char *hndmem_type_str[] = - { - "SOCRAM", /* 0 */ - "BM", /* 1 */ - "UCM", /* 2 */ - "SHM", /* 3 */ - }; - -/* Dumps the complete memory information */ -void -hndmem_dump_meminfo_all(si_t *sih) -{ - int mem, bank, bank_cnt, bank_sz; - - for (mem = MEM_SOCRAM; mem < MEM_MAX; mem++) { - bank_cnt = hndmem_num_banks(sih, mem); - - printf("\nMemtype: %s\n", hndmem_type_str[mem]); - for (bank = 0; bank < bank_cnt; bank++) { - bank_sz = hndmem_bank_size(sih, mem, bank); - printf("Bank-%d: %d KB\n", bank, bank_sz); - } - } -} -#endif /* BCMDEBUG */ - -/* Configures the Sleep PDA for a particular bank for a given memory type */ -int -hndmem_sleeppda_bank_config(si_t *sih, hndmem_type_t mem, int bank_num, - hndmem_config_t config, uint32 pda) -{ - uint32 savecore, reg_data; - gciregs_t *gciregs; - int err = BCME_OK; - osl_t *osh = si_osh(sih); - - /* TODO: Check whether SOCRAM core is present or not. If not, bail out */ - /* In future we need to add code for TCM based chips as well */ - if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) { - err = BCME_UNSUPPORTED; - goto exit; - } - - /* Sleep PDA is supported only by GCI rev >= 9 */ - if (GCIREV(sih->gcirev) < 9) { - err = BCME_UNSUPPORTED; - goto exit; - } - - if (!IS_MEMTYPE_VALID(mem)) { - err = BCME_BADOPTION; - goto exit; - } - - if (!IS_MEMCONFIG_VALID(config)) { - err = BCME_BADOPTION; - goto exit; - } - - savecore = si_coreidx(sih); - gciregs = si_setcore(sih, GCI_CORE_ID, 0); - - reg_data = ((mem & - GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_MASK) << - GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_SHIFT) | - ((bank_num & GCI_INDIRECT_ADDRESS_REG_REGINDEX_MASK) - << GCI_INDIRECT_ADDRESS_REG_REGINDEX_SHIFT); - - W_REG(osh, &gciregs->gci_indirect_addr, reg_data); - - if (config == PDA_CONFIG_SET_PARTIAL) { - W_REG(osh, &gciregs->wlan_bankxsleeppda, pda); - W_REG(osh, &gciregs->wlan_bankxkill, 0); - } - else if (config == PDA_CONFIG_SET_FULL) { - W_REG(osh, &gciregs->wlan_bankxsleeppda, WLAN_BANKX_SLEEPPDA_REG_SLEEPPDA_MASK); - W_REG(osh, &gciregs->wlan_bankxkill, WLAN_BANKX_PKILL_REG_SLEEPPDA_MASK); - } else { - W_REG(osh, &gciregs->wlan_bankxsleeppda, 0); - W_REG(osh, &gciregs->wlan_bankxkill, 0); - } - - si_setcoreidx(sih, savecore); - -exit: - return err; -} - -/* Configures the Active PDA for a particular bank for a given memory type */ -int -hndmem_activepda_bank_config(si_t *sih, hndmem_type_t mem, - int bank_num, hndmem_config_t config, uint32 pda) -{ - uint32 savecore, reg_data; - gciregs_t *gciregs; - int err = BCME_OK; - osl_t *osh = si_osh(sih); - - if (!IS_MEMTYPE_VALID(mem)) { - err = BCME_BADOPTION; - goto exit; - } - - if (!IS_MEMCONFIG_VALID(config)) { - err = BCME_BADOPTION; - goto exit; - } - - savecore = si_coreidx(sih); - - /* TODO: Check whether SOCRAM core is present or not. If not, bail out */ - /* In future we need to add code for TCM based chips as well */ - if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) { - err = BCME_UNSUPPORTED; - goto exit; - } - - if (GCIREV(sih->gcirev) >= 9) { - gciregs = si_setcore(sih, GCI_CORE_ID, 0); - - reg_data = ((mem & - GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_MASK) << - GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_SHIFT) | - ((bank_num & GCI_INDIRECT_ADDRESS_REG_REGINDEX_MASK) - << GCI_INDIRECT_ADDRESS_REG_REGINDEX_SHIFT); - - W_REG(osh, &gciregs->gci_indirect_addr, reg_data); - - if (config == PDA_CONFIG_SET_PARTIAL) { - W_REG(osh, &gciregs->wlan_bankxactivepda, pda); - } - else if (config == PDA_CONFIG_SET_FULL) { - W_REG(osh, &gciregs->wlan_bankxactivepda, - WLAN_BANKX_SLEEPPDA_REG_SLEEPPDA_MASK); - } else { - W_REG(osh, &gciregs->wlan_bankxactivepda, 0); - } - } else { - /* TODO: Configure SOCRAM PDA using SOCRAM registers */ - err = BCME_UNSUPPORTED; - } - - si_setcoreidx(sih, savecore); - -exit: - return err; -} - -/* Configures the Sleep PDA for all the banks for a given memory type */ -int -hndmem_sleeppda_config(si_t *sih, hndmem_type_t mem, hndmem_config_t config) -{ - int bank; - int num_banks = hndmem_num_banks(sih, mem); - int err = BCME_OK; - - /* Sleep PDA is supported only by GCI rev >= 9 */ - if (GCIREV(sih->gcirev) < 9) { - err = BCME_UNSUPPORTED; - goto exit; - } - - if (!IS_MEMTYPE_VALID(mem)) { - err = BCME_BADOPTION; - goto exit; - } - - if (!IS_MEMCONFIG_VALID(config)) { - err = BCME_BADOPTION; - goto exit; - } - - for (bank = 0; bank < num_banks; bank++) - { - err = hndmem_sleeppda_bank_config(sih, mem, bank, config, 0); - } - -exit: - return err; -} - -/* Configures the Active PDA for all the banks for a given memory type */ -int -hndmem_activepda_config(si_t *sih, hndmem_type_t mem, hndmem_config_t config) -{ - int bank; - int num_banks = hndmem_num_banks(sih, mem); - int err = BCME_OK; - - if (!IS_MEMTYPE_VALID(mem)) { - err = BCME_BADOPTION; - goto exit; - } - - if (!IS_MEMCONFIG_VALID(config)) { - err = BCME_BADOPTION; - goto exit; - } - - for (bank = 0; bank < num_banks; bank++) - { - err = hndmem_activepda_bank_config(sih, mem, bank, config, 0); - } - -exit: - return err; -} - -/* Turn off/on all the possible banks in a given memory range. - * Currently this works only for SOCRAM as this is restricted by HW. - */ -int -hndmem_activepda_mem_config(si_t *sih, hndmem_type_t mem, uint32 mem_start, - uint32 size, hndmem_config_t config) -{ - int bank, bank_sz, num_banks; - int mem_end; - int bank_start_addr, bank_end_addr; - int err = BCME_OK; - - /* We can get bank size for only SOCRAM/TCM only. Support is not avilable - * for other memories (BM, UCM and SHM) - */ - if (mem != MEM_SOCRAM) { - err = BCME_UNSUPPORTED; - goto exit; - } - - num_banks = hndmem_num_banks(sih, mem); - bank_start_addr = hndmem_mem_base(sih, mem); - mem_end = mem_start + size - 1; - - for (bank = 0; bank < num_banks; bank++) - { - /* Bank size is spcified in bankXinfo register in terms on KBs */ - bank_sz = 1024 * hndmem_bank_size(sih, mem, bank); - - bank_end_addr = bank_start_addr + bank_sz - 1; - - if (config == PDA_CONFIG_SET_FULL) { - /* Check if the bank is completely overlapping with the given mem range */ - if ((mem_start <= bank_start_addr) && (mem_end >= bank_end_addr)) { - err = hndmem_activepda_bank_config(sih, mem, bank, config, 0); - } - } else { - /* Check if the bank is completely overlaped with the given mem range */ - if (((mem_start <= bank_start_addr) && (mem_end >= bank_end_addr)) || - /* Check if the bank is partially overlaped with the given range */ - ((mem_start <= bank_end_addr) && (mem_end >= bank_start_addr))) { - err = hndmem_activepda_bank_config(sih, mem, bank, config, 0); - } - } - - bank_start_addr += bank_sz; - } - -exit: - return err; -} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hndpmu.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hndpmu.c old mode 100755 new mode 100644 index 7bd12e33b725..d8b0c954a91e --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hndpmu.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/hndpmu.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing PMU corerev specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -311,6 +311,9 @@ static rsc_per_chip_t rsc_4369 = {RES4369_HT_AVAIL, RES4369_MACPHY_MAIN_CLK_AVAI static rsc_per_chip_t rsc_4378 = {RES4378_HT_AVAIL, RES4378_MACPHY_MAIN_CLK_AVAIL, RES4378_HT_AVAIL, RES4378_PMU_SLEEP, RES4378_MACPHY_AUX_CLK_AVAIL, NO_SUCH_RESOURCE, RES4378_CORE_RDY_CB, RES4378_CORE_RDY_DIG}; +static rsc_per_chip_t rsc_4381 = {RES4387_HT_AVAIL, RES4387_MACPHY_CLK_MAIN, + RES4387_HT_AVAIL, RES4387_PMU_SLEEP, NO_SUCH_RESOURCE, + NO_SUCH_RESOURCE, RES4387_CORE_RDY_CB, RES4387_CORE_RDY_DIG}; static rsc_per_chip_t rsc_4387 = {RES4387_HT_AVAIL, RES4387_MACPHY_CLK_MAIN, RES4387_HT_AVAIL, RES4387_PMU_SLEEP, RES4387_MACPHY_CLK_AUX, RES4387_MACPHY_CLK_SCAN, RES4387_CORE_RDY_CB, RES4387_CORE_RDY_DIG}; @@ -365,6 +368,9 @@ static rsc_per_chip_t* BCMRAMFN(si_pmu_get_rsc_positions)(si_t *sih) case BCM4378_CHIP_GRPID: rsc = &rsc_4378; break; + case BCM4381_CHIP_GRPID: + rsc = &rsc_4381; /* TBD */ + break; case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: rsc = &rsc_4387; @@ -386,28 +392,28 @@ static rsc_per_chip_t* BCMRAMFN(si_pmu_get_rsc_positions)(si_t *sih) return rsc; }; /* si_pmu_get_rsc_positions */ -static const char BCMATTACHDATA(rstr_pllD)[] = "pll%d"; -static const char BCMATTACHDATA(rstr_regD)[] = "reg%d"; -static const char BCMATTACHDATA(rstr_chipcD)[] = "chipc%d"; -static const char BCMATTACHDATA(rstr_rDt)[] = "r%dt"; -static const char BCMATTACHDATA(rstr_rDd)[] = "r%dd"; -static const char BCMATTACHDATA(rstr_Invalid_Unsupported_xtal_value_D)[] = +static const char rstr_pllD[] = "pll%d"; +static const char rstr_regD[] = "reg%d"; +static const char rstr_chipcD[] = "chipc%d"; +static const char rstr_rDt[] = "r%dt"; +static const char rstr_rDd[] = "r%dd"; +static const char rstr_Invalid_Unsupported_xtal_value_D[] = "Invalid/Unsupported xtal value %d"; -static const char BCMATTACHDATA(rstr_xtalfreq)[] = "xtalfreq"; +static const char rstr_xtalfreq[] = "xtalfreq"; #if defined(SAVERESTORE) && defined(LDO3P3_MIN_RES_MASK) -static const char BCMATTACHDATA(rstr_ldo_prot)[] = "ldo_prot"; +static const char rstr_ldo_prot[] = "ldo_prot"; #endif /* SAVERESTORE && LDO3P3_MIN_RES_MASK */ -static const char BCMATTACHDATA(rstr_btldo3p3pu)[] = "btldopu"; +static const char rstr_btldo3p3pu[] = "btldopu"; #if defined(BCM_FASTLPO_PMU) && !defined(BCM_FASTLPO_PMU_DISABLED) -static const char BCMATTACHDATA(rstr_fastlpo_dis)[] = "fastlpo_dis"; +static const char rstr_fastlpo_dis[] = "fastlpo_dis"; #endif /* BCM_FASTLPO_PMU */ -static const char BCMATTACHDATA(rstr_fastlpo_pcie_dis)[] = "fastlpo_pcie_dis"; -static const char BCMATTACHDATA(rstr_memlpldo_volt)[] = "memlpldo_volt"; -static const char BCMATTACHDATA(rstr_lpldo_volt)[] = "lpldo_volt"; -static const char BCMATTACHDATA(rstr_dyn_clksw_en)[] = "dyn_clksw_en"; -static const char BCMATTACHDATA(rstr_abuck_volt)[] = "abuck_volt"; -static const char BCMATTACHDATA(rstr_cbuck_volt)[] = "cbuck_volt"; -static const char BCMATTACHDATA(rstr_csrtune)[] = "csr_tune"; +static const char rstr_fastlpo_pcie_dis[] = "fastlpo_pcie_dis"; +static const char rstr_memlpldo_volt[] = "memlpldo_volt"; +static const char rstr_lpldo_volt[] = "lpldo_volt"; +static const char rstr_dyn_clksw_en[] = "dyn_clksw_en"; +static const char rstr_abuck_volt[] = "abuck_volt"; +static const char rstr_cbuck_volt[] = "cbuck_volt"; +static const char rstr_csrtune[] = "csr_tune"; /* The check for OTP parameters for the PLL control registers is done and if found the * registers are updated accordingly. @@ -419,7 +425,7 @@ static const char BCMATTACHDATA(rstr_csrtune)[] = "csr_tune"; * overwritten, but not yet 'updated'. */ static void -BCMATTACHFN(si_pmu_otp_pllcontrol)(si_t *sih, osl_t *osh) +si_pmu_otp_pllcontrol(si_t *sih, osl_t *osh) { char name[16]; const char *otp_val; @@ -427,10 +433,6 @@ BCMATTACHFN(si_pmu_otp_pllcontrol)(si_t *sih, osl_t *osh) uint32 val; uint8 pll_ctrlcnt = 0; - if (FWSIGN_ENAB()) { - return; - } - if (PMUREV(sih->pmurev) >= 5) { pll_ctrlcnt = (sih->pmucaps & PCAP5_PC_MASK) >> PCAP5_PC_SHIFT; } else { @@ -452,7 +454,7 @@ BCMATTACHFN(si_pmu_otp_pllcontrol)(si_t *sih, osl_t *osh) * registers are updated accordingly. */ static void -BCMATTACHFN(si_pmu_otp_vreg_control)(si_t *sih, osl_t *osh) +si_pmu_otp_vreg_control(si_t *sih, osl_t *osh) { char name[16]; const char *otp_val; @@ -460,10 +462,6 @@ BCMATTACHFN(si_pmu_otp_vreg_control)(si_t *sih, osl_t *osh) uint32 val; uint8 vreg_ctrlcnt = 0; - if (FWSIGN_ENAB()) { - return; - } - if (PMUREV(sih->pmurev) >= 5) { vreg_ctrlcnt = (sih->pmucaps & PCAP5_VC_MASK) >> PCAP5_VC_SHIFT; } else { @@ -485,15 +483,12 @@ BCMATTACHFN(si_pmu_otp_vreg_control)(si_t *sih, osl_t *osh) * registers are updated accordingly. */ static void -BCMATTACHFN(si_pmu_otp_chipcontrol)(si_t *sih, osl_t *osh) +si_pmu_otp_chipcontrol(si_t *sih, osl_t *osh) { uint32 val, cc_ctrlcnt, i; char name[16]; const char *otp_val; - if (FWSIGN_ENAB()) { - return; - } if (PMUREV(sih->pmurev) >= 5) { cc_ctrlcnt = (sih->pmucaps & PCAP5_CC_MASK) >> PCAP5_CC_SHIFT; } else { @@ -581,7 +576,7 @@ si_pmu_set_ldo_voltage(si_t *sih, osl_t *osh, uint8 ldo, uint8 voltage) /* For legacy chips only, will be discarded eventually */ static uint16 -BCMINITFN(si_pmu_fast_pwrup_delay_legacy)(si_t *sih, osl_t *osh, pmuregs_t *pmu) +si_pmu_fast_pwrup_delay_legacy(si_t *sih, osl_t *osh, pmuregs_t *pmu) { uint pmudelay = PMU_MAX_TRANSITION_DLY; uint32 ilp; /* ILP clock frequency in [Hz] */ @@ -643,7 +638,7 @@ BCMINITFN(si_pmu_fast_pwrup_delay_legacy)(si_t *sih, osl_t *osh, pmuregs_t *pmu) * It does not write to the d11 core. */ uint16 -BCMINITFN(si_pmu_fast_pwrup_delay)(si_t *sih, osl_t *osh) +si_pmu_fast_pwrup_delay(si_t *sih, osl_t *osh) { uint pmudelay = PMU_MAX_TRANSITION_DLY; pmuregs_t *pmu; @@ -726,7 +721,7 @@ exit: * Get fast pwrup delay for given resource */ static uint -BCMINITFN(si_pmu_fast_pwrup_delay_rsrc)(si_t *sih, osl_t *osh, uint8 rsrc) +si_pmu_fast_pwrup_delay_rsrc(si_t *sih, osl_t *osh, uint8 rsrc) { uint pmudelay = PMU_MAX_TRANSITION_DLY; pmuregs_t *pmu = NULL; @@ -752,7 +747,7 @@ BCMINITFN(si_pmu_fast_pwrup_delay_rsrc)(si_t *sih, osl_t *osh, uint8 rsrc) * Get fast pwrup delay for given DIG_READY resource */ uint -BCMINITFN(si_pmu_fast_pwrup_delay_dig)(si_t *sih, osl_t *osh) +si_pmu_fast_pwrup_delay_dig(si_t *sih, osl_t *osh) { uint delay = 0; rsc_per_chip_t *rsc = si_pmu_get_rsc_positions(sih); @@ -799,7 +794,7 @@ typedef struct { #define RES_DEPEND_REMOVE -1 /* Remove from the dependencies mask */ /* Using a safe SAVE_RESTORE up/down time, it will get updated after openloop cal */ -static const pmu_res_updown_t BCMATTACHDATA(bcm43012a0_res_updown_ds0)[] = { +static const pmu_res_updown_t bcm43012a0_res_updown_ds0[] = { {RES43012_MEMLPLDO_PU, 0x00200020}, {RES43012_PMU_SLEEP, 0x00a600a6}, {RES43012_FAST_LPO, 0x00D20000}, @@ -831,21 +826,21 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm43012a0_res_updown_ds0)[] = { {RES43012_MACPHY_CLK_AVAIL, 0x00000000}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4360_res_updown)[] = { +static const pmu_res_updown_t bcm4360_res_updown[] = { {RES4360_BBPLLPWRSW_PU, 0x00200001} }; -static const pmu_res_updown_t BCMATTACHDATA(bcm43602_res_updown)[] = { +static const pmu_res_updown_t bcm43602_res_updown[] = { {RES43602_SR_SAVE_RESTORE, 0x00190019}, {RES43602_XTAL_PU, 0x00280002}, {RES43602_RFLDO_PU, 0x00430005} }; -static pmu_res_depend_t BCMATTACHDATA(bcm43012a0_res_depend_ds0)[] = { +static pmu_res_depend_t bcm43012a0_res_depend_ds0[] = { {0, 0, 0, NULL} }; -static pmu_res_depend_t BCMATTACHDATA(bcm43602_res_depend)[] = { +static pmu_res_depend_t bcm43602_res_depend[] = { /* JIRA HW43602-131 : PCIe SERDES dependency problem */ { PMURES_BIT(RES43602_SR_SUBCORE_PWRSW) | PMURES_BIT(RES43602_SR_CLK_STABLE) | @@ -891,7 +886,7 @@ static pmu_res_depend_t BCMATTACHDATA(bcm43602_res_depend)[] = { #ifndef BCM_BOOTLOADER /** switch off LPLDO for 12x12 package because it can cause a problem when chip is reset */ -static const pmu_res_depend_t BCMATTACHDATA(bcm43602_12x12_res_depend)[] = { +static const pmu_res_depend_t bcm43602_12x12_res_depend[] = { /* set rsrc 19, 21, 22, 23 & 24 remove ~(1<<16 | 1<<15 )] */ { /* resources no longer dependent on resource that is going to be removed */ PMURES_BIT(RES43602_LPLDO_PU) | PMURES_BIT(RES43602_REGULATOR) | @@ -915,7 +910,7 @@ static const pmu_res_depend_t BCMATTACHDATA(bcm43602_12x12_res_depend)[] = { } }; -static const pmu_res_depend_t BCMATTACHDATA(bcm43602_res_pciewar)[] = { +static const pmu_res_depend_t bcm43602_res_pciewar[] = { { PMURES_BIT(RES43602_PERST_OVR), RES_DEPEND_ADD, @@ -971,12 +966,12 @@ static const pmu_res_depend_t BCMATTACHDATA(bcm43602_res_pciewar)[] = { }; #endif /* BCM_BOOTLOADER */ -static const pmu_res_updown_t BCMATTACHDATA(bcm4360B1_res_updown)[] = { +static const pmu_res_updown_t bcm4360B1_res_updown[] = { /* Need to change elements here, should get default values for this - 4360B1 */ {RES4360_XTAL_PU, 0x00430002}, /* Changed for 4360B1 */ }; -static pmu_res_depend_t BCMATTACHDATA(bcm4369a0_res_depend)[] = { +static pmu_res_depend_t bcm4369a0_res_depend[] = { {PMURES_BIT(RES4369_DUMMY), RES_DEPEND_SET, 0x00000000, NULL}, {PMURES_BIT(RES4369_ABUCK), RES_DEPEND_SET, 0x00000005, NULL}, {PMURES_BIT(RES4369_PMU_SLEEP), RES_DEPEND_SET, 0x00000001, NULL}, @@ -1010,7 +1005,7 @@ static pmu_res_depend_t BCMATTACHDATA(bcm4369a0_res_depend)[] = { {PMURES_BIT(RES4369_MACPHY_MAIN_CLK_AVAIL), RES_DEPEND_SET, 0x17cbc7df, NULL}, }; -static pmu_res_depend_t BCMATTACHDATA(bcm4369a0_res_depend_fastlpo_pcie)[] = { +static pmu_res_depend_t bcm4369a0_res_depend_fastlpo_pcie[] = { {PMURES_BIT(RES4369_DUMMY), RES_DEPEND_SET, 0x00000000, NULL}, {PMURES_BIT(RES4369_ABUCK), RES_DEPEND_SET, 0x00000005, NULL}, {PMURES_BIT(RES4369_PMU_SLEEP), RES_DEPEND_SET, 0x00000001, NULL}, @@ -1044,7 +1039,7 @@ static pmu_res_depend_t BCMATTACHDATA(bcm4369a0_res_depend_fastlpo_pcie)[] = { {PMURES_BIT(RES4369_MACPHY_MAIN_CLK_AVAIL), RES_DEPEND_SET, 0x17cbc7ff, NULL}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4369a0_res_updown)[] = { +static const pmu_res_updown_t bcm4369a0_res_updown[] = { {RES4369_DUMMY, 0x00220022}, {RES4369_ABUCK, 0x00c80022}, {RES4369_PMU_SLEEP, 0x00c80022}, @@ -1078,7 +1073,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4369a0_res_updown)[] = { {RES4369_MACPHY_MAIN_CLK_AVAIL, 0x00640022}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4369a0_res_updown_fastlpo_pmu)[] = { +static const pmu_res_updown_t bcm4369a0_res_updown_fastlpo_pmu[] = { {RES4369_DUMMY, 0x00220022}, {RES4369_ABUCK, 0x00c80022}, {RES4369_PMU_SLEEP, 0x00c80022}, @@ -1112,7 +1107,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4369a0_res_updown_fastlpo_pmu)[] {RES4369_MACPHY_MAIN_CLK_AVAIL, 0x00640022}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4369b0_res_updown)[] = { +static const pmu_res_updown_t bcm4369b0_res_updown[] = { {RES4369_DUMMY, 0x00220022}, {RES4369_ABUCK, 0x00c80022}, {RES4369_PMU_SLEEP, 0x00c80022}, @@ -1146,7 +1141,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4369b0_res_updown)[] = { {RES4369_MACPHY_MAIN_CLK_AVAIL, 0x00640022}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4369b0_res_updown_fastlpo_pmu)[] = { +static const pmu_res_updown_t bcm4369b0_res_updown_fastlpo_pmu[] = { {RES4369_DUMMY, 0x00220022}, {RES4369_ABUCK, 0x00c80022}, {RES4369_PMU_SLEEP, 0x00c80022}, @@ -1180,7 +1175,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4369b0_res_updown_fastlpo_pmu)[] {RES4369_MACPHY_MAIN_CLK_AVAIL, 0x00640022}, }; -static pmu_res_depend_t BCMATTACHDATA(bcm4362_res_depend)[] = { +static pmu_res_depend_t bcm4362_res_depend[] = { {PMURES_BIT(RES4362_DUMMY), RES_DEPEND_SET, 0x00000000, NULL}, {PMURES_BIT(RES4362_ABUCK), RES_DEPEND_SET, 0x00000005, NULL}, {PMURES_BIT(RES4362_PMU_SLEEP), RES_DEPEND_SET, 0x00000001, NULL}, @@ -1214,7 +1209,7 @@ static pmu_res_depend_t BCMATTACHDATA(bcm4362_res_depend)[] = { {PMURES_BIT(RES4362_MACPHY_MAIN_CLK_AVAIL), RES_DEPEND_SET, 0x17cbc7df, NULL}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4362_res_updown)[] = { +static const pmu_res_updown_t bcm4362_res_updown[] = { {RES4362_DUMMY, 0x00220022}, {RES4362_ABUCK, 0x00c80022}, {RES4362_PMU_SLEEP, 0x00c80022}, @@ -1248,7 +1243,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4362_res_updown)[] = { {RES4362_MACPHY_MAIN_CLK_AVAIL, 0x00640022}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4378b0_res_updown)[] = { +static const pmu_res_updown_t bcm4378b0_res_updown[] = { {RES4378_ABUCK, 0x00c80022}, {RES4378_PMU_SLEEP, 0x011c0022}, {RES4378_MISC_LDO, 0x00c80022}, @@ -1268,7 +1263,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4378b0_res_updown)[] = { {RES4378_MACPHY_MAIN_CLK_AVAIL, 0x00640022}, }; -static pmu_res_depend_t BCMATTACHDATA(bcm4378b0_res_depend)[] = { +static pmu_res_depend_t bcm4378b0_res_depend[] = { {PMURES_BIT(RES4378_ABUCK), RES_DEPEND_SET, 0x00000005, NULL}, {PMURES_BIT(RES4378_PMU_SLEEP), RES_DEPEND_SET, 0x00000001, NULL}, {PMURES_BIT(RES4378_MISC_LDO), RES_DEPEND_SET, 0x00000007, NULL}, @@ -1305,7 +1300,7 @@ static pmu_res_depend_t BCMATTACHDATA(bcm4378b0_res_depend)[] = { {PMURES_BIT(RES4378_MACPHY_MAIN_CLK_AVAIL), RES_DEPEND_SET, 0x17cbc7ff, NULL}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4387b0_res_updown_qt)[] = { +static const pmu_res_updown_t bcm4387b0_res_updown_qt[] = { {RES4387_XTAL_PU, 0x012c0033}, {RES4387_PWRSW_DIG, 0x38993899}, {RES4387_PWRSW_AUX, 0x38993899}, @@ -1314,7 +1309,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4387b0_res_updown_qt)[] = { {RES4387_CORE_RDY_CB, 0x00960033}, }; -static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4387b0_res_subst_trans_tmr_qt)[] = { +static const pmu_res_subst_trans_tmr_t bcm4387b0_res_subst_trans_tmr_qt[] = { {RES4387_PWRSW_DIG, 0, 0x38993800}, {RES4387_PWRSW_DIG, 1, 0x36000600}, {RES4387_PWRSW_DIG, 2, 0x01000002}, @@ -1332,7 +1327,7 @@ static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4387b0_res_subst_trans_t {RES4387_PWRSW_MAIN, 2, 0x01000002}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4387b0_res_updown)[] = { +static const pmu_res_updown_t bcm4387b0_res_updown[] = { {RES4387_PMU_SLEEP, 0x00960022}, {RES4387_MISC_LDO, 0x00320022}, {RES4387_XTAL_HQ, 0x00210021}, @@ -1345,7 +1340,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4387b0_res_updown)[] = { {RES4387_PWRSW_CB, 0x006400ca}, }; -static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4387b0_res_subst_trans_tmr)[] = { +static const pmu_res_subst_trans_tmr_t bcm4387b0_res_subst_trans_tmr[] = { {RES4387_PWRSW_DIG, 0, 0x04b002bc}, {RES4387_PWRSW_DIG, 1, 0x02500210}, {RES4387_PWRSW_DIG, 2, 0x00a00010}, @@ -1363,7 +1358,7 @@ static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4387b0_res_subst_trans_t {RES4387_PWRSW_SCAN, 2, 0x00320002}, }; -static pmu_res_depend_t BCMATTACHDATA(bcm4387b0_res_depend)[] = { +static pmu_res_depend_t bcm4387b0_res_depend[] = { {PMURES_BIT(RES4387_DUMMY), RES_DEPEND_SET, 0x0, NULL}, {PMURES_BIT(RES4387_RESERVED_1), RES_DEPEND_SET, 0x0, NULL}, {PMURES_BIT(RES4387_PMU_SLEEP), RES_DEPEND_SET, 0x1, NULL}, @@ -1397,7 +1392,7 @@ static pmu_res_depend_t BCMATTACHDATA(bcm4387b0_res_depend)[] = { {PMURES_BIT(RES4387_MACPHY_CLK_MAIN), RES_DEPEND_SET, 0x16CA41ED, NULL}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4387c0_res_updown_topoff)[] = { +static const pmu_res_updown_t bcm4387c0_res_updown_topoff[] = { {RES4387_PMU_SLEEP, 0x02000022}, {RES4387_MISC_LDO, 0x00320022}, {RES4387_SERDES_AFE_RET, 0x00010001}, @@ -1411,7 +1406,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4387c0_res_updown_topoff)[] = { {RES4387_PWRSW_CB, 0x006400ca}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4387c0_res_updown)[] = { +static const pmu_res_updown_t bcm4387c0_res_updown[] = { #ifdef BCM_PMU_FLL_PU_MANAGE {RES4387_FAST_LPO_AVAIL, 0x00960001}, #endif @@ -1427,7 +1422,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4387c0_res_updown)[] = { {RES4387_PWRSW_CB, 0x006400ca}, }; -static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4387c0_res_subst_trans_tmr)[] = { +static const pmu_res_subst_trans_tmr_t bcm4387c0_res_subst_trans_tmr[] = { {RES4387_PWRSW_DIG, 0, 0x01320142}, {RES4387_PWRSW_DIG, 1, 0x00e2005a}, {RES4387_PWRSW_DIG, 2, 0x00c20052}, @@ -1449,7 +1444,7 @@ static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4387c0_res_subst_trans_t {RES4387_PWRSW_SCAN, 3, 0x00020002}, }; -static pmu_res_depend_t BCMATTACHDATA(bcm4387c0_res_depend)[] = { +static pmu_res_depend_t bcm4387c0_res_depend[] = { {PMURES_BIT(RES4387_DUMMY), RES_DEPEND_SET, 0x0, NULL}, {PMURES_BIT(RES4387_FAST_LPO_AVAIL), RES_DEPEND_SET, 0x0, NULL}, {PMURES_BIT(RES4387_PMU_LP), RES_DEPEND_SET, 0x1, NULL}, @@ -1483,7 +1478,7 @@ static pmu_res_depend_t BCMATTACHDATA(bcm4387c0_res_depend)[] = { {PMURES_BIT(RES4387_MACPHY_CLK_MAIN), RES_DEPEND_SET, 0x16CAC1FD, NULL}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4388a0_res_updown_qt)[] = { +static const pmu_res_updown_t bcm4388a0_res_updown_qt[] = { {RES4388_XTAL_PU, 0x012c0033}, {RES4388_PWRSW_DIG, 0x38993899}, {RES4388_PWRSW_AUX, 0x38993899}, @@ -1492,7 +1487,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4388a0_res_updown_qt)[] = { {RES4388_CORE_RDY_CB, 0x00960033}, }; -static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4388a0_res_subst_trans_tmr_qt)[] = { +static const pmu_res_subst_trans_tmr_t bcm4388a0_res_subst_trans_tmr_qt[] = { {RES4388_PWRSW_DIG, 0, 0x38993800}, {RES4388_PWRSW_DIG, 1, 0x36c00600}, {RES4388_PWRSW_DIG, 2, 0x360005a0}, @@ -1514,7 +1509,7 @@ static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4388a0_res_subst_trans_t {RES4388_PWRSW_SCAN, 3, 0x01000002}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4388a0_res_updown)[] = { +static const pmu_res_updown_t bcm4388a0_res_updown[] = { #ifdef BCM_PMU_FLL_PU_MANAGE {RES4388_FAST_LPO_AVAIL, 0x00960001}, #endif /* BCM_PMU_FLL_PU_MANAGE */ @@ -1531,7 +1526,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4388a0_res_updown)[] = { {RES4388_MACPHY_CLK_MAIN, 0x00860022}, }; -static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4388a0_res_subst_trans_tmr)[] = { +static const pmu_res_subst_trans_tmr_t bcm4388a0_res_subst_trans_tmr[] = { {RES4388_PWRSW_DIG, 0, 0x0428033c}, {RES4388_PWRSW_DIG, 1, 0x028c0210}, {RES4388_PWRSW_DIG, 2, 0x01cc01b0}, @@ -1553,7 +1548,7 @@ static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4388a0_res_subst_trans_t {RES4388_PWRSW_SCAN, 3, 0x00a00010}, }; -static pmu_res_depend_t BCMATTACHDATA(bcm4388a0_res_depend)[] = { +static pmu_res_depend_t bcm4388a0_res_depend[] = { {PMURES_BIT(RES4388_DUMMY), RES_DEPEND_SET, 0x00000000, NULL}, {PMURES_BIT(RES4388_FAST_LPO_AVAIL), RES_DEPEND_SET, 0x00000000, NULL}, {PMURES_BIT(RES4388_PMU_LP), RES_DEPEND_SET, 0x00000001, NULL}, @@ -1587,7 +1582,7 @@ static pmu_res_depend_t BCMATTACHDATA(bcm4388a0_res_depend)[] = { {PMURES_BIT(RES4388_MACPHY_CLK_MAIN), RES_DEPEND_SET, 0x16ca41fd, NULL}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4389b0_res_updown_qt)[] = { +static const pmu_res_updown_t bcm4389b0_res_updown_qt[] = { {RES4389_XTAL_PU, 0x012c0033}, {RES4389_PWRSW_DIG, 0x38993899}, {RES4389_PWRSW_AUX, 0x38993899}, @@ -1596,7 +1591,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4389b0_res_updown_qt)[] = { {RES4389_CORE_RDY_CB, 0x00960033}, }; -static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4389b0_res_subst_trans_tmr_qt)[] = { +static const pmu_res_subst_trans_tmr_t bcm4389b0_res_subst_trans_tmr_qt[] = { {RES4389_PWRSW_DIG, 0, 0x38993800}, {RES4389_PWRSW_DIG, 1, 0x36c00600}, {RES4389_PWRSW_DIG, 2, 0x360005a0}, @@ -1618,7 +1613,7 @@ static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4389b0_res_subst_trans_t {RES4389_PWRSW_SCAN, 3, 0x01000002}, }; -static const pmu_res_updown_t BCMATTACHDATA(bcm4389b0_res_updown)[] = { +static const pmu_res_updown_t bcm4389b0_res_updown[] = { #ifdef BCM_PMU_FLL_PU_MANAGE {RES4389_FAST_LPO_AVAIL, 0x001e0001}, #endif /* BCM_PMU_FLL_PU_MANAGE */ @@ -1635,7 +1630,7 @@ static const pmu_res_updown_t BCMATTACHDATA(bcm4389b0_res_updown)[] = { {RES4389_MACPHY_CLK_MAIN, 0x00860022}, }; -static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4389b0_res_subst_trans_tmr)[] = { +static const pmu_res_subst_trans_tmr_t bcm4389b0_res_subst_trans_tmr[] = { {RES4389_PWRSW_DIG, 0, 0x0428033c}, {RES4389_PWRSW_DIG, 1, 0x028c0210}, {RES4389_PWRSW_DIG, 2, 0x01cc01b0}, @@ -1657,7 +1652,7 @@ static const pmu_res_subst_trans_tmr_t BCMATTACHDATA(bcm4389b0_res_subst_trans_t {RES4389_PWRSW_SCAN, 3, 0x00a00010}, }; -static pmu_res_depend_t BCMATTACHDATA(bcm4389b0_res_depend)[] = { +static pmu_res_depend_t bcm4389b0_res_depend[] = { {PMURES_BIT(RES4389_DUMMY), RES_DEPEND_SET, 0x00000000, NULL}, {PMURES_BIT(RES4389_FAST_LPO_AVAIL), RES_DEPEND_SET, 0x00000000, NULL}, {PMURES_BIT(RES4389_PMU_LP), RES_DEPEND_SET, 0x00000001, NULL}, @@ -1829,6 +1824,8 @@ si_pmu_res_masks(si_t *sih, uint32 *pmin, uint32 *pmax) #endif /* SAVERESTORE */ max_mask = 0x7FFFFFFF; break; + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: min_mask = 0x64fffff; @@ -1909,10 +1906,8 @@ si_pmu_res_masks(si_t *sih, uint32 *pmin, uint32 *pmax) break; } - if (!FWSIGN_ENAB()) { - /* nvram override */ - si_nvram_res_masks(sih, &min_mask, &max_mask); - } + /* nvram override */ + si_nvram_res_masks(sih, &min_mask, &max_mask); *pmin = min_mask; *pmax = max_mask; @@ -1929,7 +1924,7 @@ si_pmu_resdeptbl_upd(si_t *sih, osl_t *osh, pmuregs_t *pmu, const pmu_res_depend_t *restable, uint tablesz) #else static void -BCMATTACHFN(si_pmu_resdeptbl_upd)(si_t *sih, osl_t *osh, pmuregs_t *pmu, +si_pmu_resdeptbl_upd(si_t *sih, osl_t *osh, pmuregs_t *pmu, const pmu_res_depend_t *restable, uint tablesz) #endif /* DUAL_PMU_SEQUENCE */ { @@ -1979,7 +1974,7 @@ BCMATTACHFN(si_pmu_resdeptbl_upd)(si_t *sih, osl_t *osh, pmuregs_t *pmu, } /* si_pmu_resdeptbl_upd */ static void -BCMATTACHFN(si_pmu_dep_table_fll_pu_fixup)(si_t *sih, osl_t *osh, +si_pmu_dep_table_fll_pu_fixup(si_t *sih, osl_t *osh, pmu_res_depend_t *pmu_res_depend_table, uint pmu_res_depend_table_sz) { uint i; @@ -1989,6 +1984,8 @@ BCMATTACHFN(si_pmu_dep_table_fll_pu_fixup)(si_t *sih, osl_t *osh, } switch (CHIPID(sih->chip)) { + case BCM4381_CHIP_GRPID: /* TBD */ + case BCM4383_CHIP_GRPID: /* TBD */ case BCM4387_CHIP_GRPID: for (i = 0; i < pmu_res_depend_table_sz; i ++) { if (pmu_res_depend_table[i].res_mask == @@ -2051,7 +2048,7 @@ BCMATTACHFN(si_pmu_dep_table_fll_pu_fixup)(si_t *sih, osl_t *osh, /** Initialize PMU hardware resources. */ void -BCMATTACHFN(si_pmu_res_init)(si_t *sih, osl_t *osh) +si_pmu_res_init(si_t *sih, osl_t *osh) { pmuregs_t *pmu; uint origidx; @@ -2346,30 +2343,28 @@ BCMATTACHFN(si_pmu_res_init)(si_t *sih, osl_t *osh) pmu_res_updown_table[pmu_res_updown_table_sz].updown); } - if (!FWSIGN_ENAB()) { - /* # resources */ - rsrcs = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT; + /* # resources */ + rsrcs = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT; - /* Apply nvram overrides to up/down timers */ - for (i = 0; i < rsrcs; i ++) { - uint32 r_val; - snprintf(name, sizeof(name), rstr_rDt, i); - if ((val = getvar(NULL, name)) == NULL) - continue; - r_val = (uint32)bcm_strtoul(val, NULL, 0); - /* PMUrev = 13, pmu resource updown times are 12 bits(0:11 DT, 16:27 UT) */ - /* OLD values are 8 bits for UT/DT, handle the old nvram format */ - if (PMUREV(sih->pmurev) >= 13) { - if (r_val < (1 << 16)) { - uint16 up_time = (r_val >> 8) & 0xFF; - r_val &= 0xFF; - r_val |= (up_time << 16); - } + /* Apply nvram overrides to up/down timers */ + for (i = 0; i < rsrcs; i ++) { + uint32 r_val; + snprintf(name, sizeof(name), rstr_rDt, i); + if ((val = getvar(NULL, name)) == NULL) + continue; + r_val = (uint32)bcm_strtoul(val, NULL, 0); + /* PMUrev = 13, pmu resource updown times are 12 bits(0:11 DT, 16:27 UT) */ + /* OLD values are 8 bits for UT/DT, handle the old nvram format */ + if (PMUREV(sih->pmurev) >= 13) { + if (r_val < (1 << 16)) { + uint16 up_time = (r_val >> 8) & 0xFF; + r_val &= 0xFF; + r_val |= (up_time << 16); } - PMU_MSG(("Applying %s=%s to rsrc %d res_updn_timer\n", name, val, i)); - W_REG(osh, &pmu->res_table_sel, (uint32)i); - W_REG(osh, &pmu->res_updn_timer, r_val); } + PMU_MSG(("Applying %s=%s to rsrc %d res_updn_timer\n", name, val, i)); + W_REG(osh, &pmu->res_table_sel, (uint32)i); + W_REG(osh, &pmu->res_updn_timer, r_val); } /* Program Rsrc Substate Transition Timer */ @@ -2390,16 +2385,14 @@ BCMATTACHFN(si_pmu_res_init)(si_t *sih, osl_t *osh) /* Program resource dependencies table */ si_pmu_resdeptbl_upd(sih, osh, pmu, pmu_res_depend_table, pmu_res_depend_table_sz); - if (!FWSIGN_ENAB()) { - /* Apply nvram overrides to dependencies masks */ - for (i = 0; i < rsrcs; i ++) { - snprintf(name, sizeof(name), rstr_rDd, i); - if ((val = getvar(NULL, name)) == NULL) - continue; - PMU_MSG(("Applying %s=%s to rsrc %d res_dep_mask\n", name, val, i)); - W_REG(osh, &pmu->res_table_sel, (uint32)i); - W_REG(osh, &pmu->res_dep_mask, (uint32)bcm_strtoul(val, NULL, 0)); - } + /* Apply nvram overrides to dependencies masks */ + for (i = 0; i < rsrcs; i ++) { + snprintf(name, sizeof(name), rstr_rDd, i); + if ((val = getvar(NULL, name)) == NULL) + continue; + PMU_MSG(("Applying %s=%s to rsrc %d res_dep_mask\n", name, val, i)); + W_REG(osh, &pmu->res_table_sel, (uint32)i); + W_REG(osh, &pmu->res_dep_mask, (uint32)bcm_strtoul(val, NULL, 0)); } #if !defined(BCM_BOOTLOADER) @@ -2568,7 +2561,7 @@ enum xtaltab0_640 { }; /* the following table is based on 880Mhz fvco */ -static const pmu1_xtaltab0_t BCMINITDATA(pmu1_xtaltab0_880)[] = { +static const pmu1_xtaltab0_t pmu1_xtaltab0_880[] = { {12000, 1, 3, 22, 0x9, 0xFFFFEF}, {13000, 2, 1, 6, 0xb, 0x483483}, {14400, 3, 1, 10, 0xa, 0x1C71C7}, @@ -2607,7 +2600,7 @@ static const pmu1_xtaltab0_t BCMINITDATA(pmu1_xtaltab0_880)[] = { #define PMU1_XTALTAB0_880_40000K 15 /* the following table is based on 1760Mhz fvco */ -static const pmu1_xtaltab0_t BCMINITDATA(pmu1_xtaltab0_1760)[] = { +static const pmu1_xtaltab0_t pmu1_xtaltab0_1760[] = { {12000, 1, 3, 44, 0x9, 0xFFFFEF}, {13000, 2, 1, 12, 0xb, 0x483483}, {14400, 3, 1, 20, 0xa, 0x1C71C7}, @@ -2663,7 +2656,7 @@ enum xtaltab0_960 { * clock. This output clock feeds the clock divider network. The defines of the form * PMU1_XTALTAB0_960_* index into this array. */ -static const pmu1_xtaltab0_t BCMINITDATA(pmu1_xtaltab0_960)[] = { +static const pmu1_xtaltab0_t pmu1_xtaltab0_960[] = { /* fref xf p1div p2div ndiv_int ndiv_frac */ {12000, 1, 1, 1, 0x50, 0x0 }, /* array index 0 */ {13000, 2, 1, 1, 0x49, 0xD89D89}, @@ -2689,7 +2682,7 @@ static const pmu1_xtaltab0_t BCMINITDATA(pmu1_xtaltab0_960)[] = { {0, 0, 0, 0, 0, 0 } }; -static const pmu1_xtaltab0_t BCMINITDATA(pmu1_xtaltab0_4369_963)[] = { +static const pmu1_xtaltab0_t pmu1_xtaltab0_4369_963[] = { /* fref xf p1div NA ndiv_int ndiv_frac */ {12000, 1, 1, 1, 0x50, 0x40000}, /* array index 0 */ {13000, 2, 1, 1, 0x4A, 0x13B14}, @@ -2713,7 +2706,7 @@ static const pmu1_xtaltab0_t BCMINITDATA(pmu1_xtaltab0_4369_963)[] = { {0, 0, 0, 0, 0, 0 } }; -static const pmu1_xtaltab0_t BCMINITDATA(pmu1_xtaltab0_4362_963)[] = { +static const pmu1_xtaltab0_t pmu1_xtaltab0_4362_963[] = { /* fref xf p1div NA ndiv_int ndiv_frac */ {12000, 1, 1, 1, 0x50, 0x40000}, /* array index 0 */ {13000, 2, 1, 1, 0x4A, 0x13B14}, @@ -2821,7 +2814,7 @@ static const uint32 (pmu1_pllctrl_tab_43012_1600mhz)[] = { * There should be a one to one mapping between pmu1_pllctrl_tab_4369_960mhz[] and this table. * Even though macro suggests XTALTAB0_960_37400K --> BBPLL VCO is set to 963MHz */ -static const pllctrl_data_t BCMATTACHDATA(pmu1_xtaltab0_4369)[] = { +static const pllctrl_data_t pmu1_xtaltab0_4369[] = { /* clock mode xf */ {37400, 0, XTALTAB0_960_37400K} }; @@ -2835,7 +2828,7 @@ static const pllctrl_data_t BCMATTACHDATA(pmu1_xtaltab0_4369)[] = { * freq table : pll1 : fvco 960.1M, pll2 for arm : 400 MHz */ #define PMU_PLL3_4369B0_DEFAULT 0x006ABF86 -static const uint32 BCMATTACHDATA(pmu1_pllctrl_tab_4369_960p1mhz)[] = { +static const uint32 pmu1_pllctrl_tab_4369_960p1mhz[] = { /* Default values for unused registers 4-7 as sw loop execution will go for 8 times */ /* Fvco is taken as 963M */ /* PLL 0 PLL 1 PLL 2 PLL 3 PLL 4 PLL 5 PLL 6 PLL 7 PLL 8 PLL 9 PLL 10 */ @@ -2853,7 +2846,7 @@ static const uint32 BCMATTACHDATA(pmu1_pllctrl_tab_4369_960p1mhz)[] = { * There should be a one to one mapping between pmu1_pllctrl_tab_4362_960mhz[] and this table. * Even though macro suggests XTALTAB0_960_37400K --> BBPLL VCO is set to 963MHz */ -static const pllctrl_data_t BCMATTACHDATA(pmu1_xtaltab0_4362)[] = { +static const pllctrl_data_t pmu1_xtaltab0_4362[] = { /* clock mode xf */ {37400, 0, XTALTAB0_960_37400K} }; @@ -2864,7 +2857,7 @@ static const pllctrl_data_t BCMATTACHDATA(pmu1_xtaltab0_4362)[] = { /* This freq actually around 960.123 */ #define PMU_PLL3_4362A0_DEFAULT 0x006ABF86 -static const uint32 BCMATTACHDATA(pmu1_pllctrl_tab_4362_960p1mhz)[] = { +static const uint32 pmu1_pllctrl_tab_4362_960p1mhz[] = { /* Default values for unused registers 4-7 as sw loop execution will go for 8 times */ /* Fvco is taken as 963M */ /* PLL 0 PLL 1 PLL 2 PLL 3 PLL 4 PLL 5 PLL 6 PLL 7 PLL 8 PLL 9 PLL 10 */ @@ -2876,12 +2869,12 @@ static const uint32 BCMATTACHDATA(pmu1_pllctrl_tab_4362_960p1mhz)[] = { /* ************************ tables for 4362a0 END *********************** */ /* ***************************** tables for 4389 *********************** */ -static const pllctrl_data_t BCMATTACHDATA(pmu1_xtaltab0_4389)[] = { +static const pllctrl_data_t pmu1_xtaltab0_4389[] = { /* clock mode xf */ {XTAL_FREQ_59970MHZ, 0, XTALTAB0_960_59970K} }; -static const uint32 BCMATTACHDATA(pmu1_pllctrl_tab_4389_963mhz)[] = { +static const uint32 pmu1_pllctrl_tab_4389_963mhz[] = { /* Default values for all registers */ /* Fvco (BBPLL) is taken as 963M */ /* PLL 0 PLL 1 PLL 2 PLL 3 PLL 4 PLL 5 PLL 6 PLL 7 PLL 8 PLL 9 PLL 10 */ @@ -2915,6 +2908,8 @@ BCMPOSTTRAPFN(si_pmu1_xtaltab0)(si_t *sih) return pmu1_xtaltab0_4362_963; case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -2955,6 +2950,8 @@ BCMPOSTTRAPFN(si_pmu1_xtaldef0)(si_t *sih) case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: return &pmu1_xtaltab0_960[PMU1_XTALTAB0_960_37400K]; + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -3140,6 +3137,8 @@ BCMPOSTTRAPFN(si_pmu1_pllfvco0)(si_t *sih) case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: return FVCO_960p1; + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -3174,6 +3173,8 @@ BCMPOSTTRAPFN(si_pmu1_pllfvco0_pll2)(si_t *sih) return SI_INFO(sih)->armpllclkfreq ? si_get_armpllclkfreq(sih) * 1000 : FVCO_1002p8; case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: return FVCO_400; @@ -3209,6 +3210,8 @@ BCMPOSTTRAPFN(si_pmu1_alpclk0)(si_t *sih, osl_t *osh, pmuregs_t *pmu) switch (CHIPID(sih->chip)) { + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -3249,6 +3252,8 @@ si_pmu_htclk_mask(si_t *sih) case BCM4362_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -3266,7 +3271,7 @@ si_pmu_htclk_mask(si_t *sih) /** returns ALP frequency in [Hz] */ static uint32 -BCMATTACHFN(si_pmu_def_alp_clock)(si_t *sih, osl_t *osh) +si_pmu_def_alp_clock(si_t *sih, osl_t *osh) { uint32 clock = ALP_CLOCK; @@ -3280,15 +3285,14 @@ BCMATTACHFN(si_pmu_def_alp_clock)(si_t *sih, osl_t *osh) case BCM4362_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: case BCM4389_CHIP_GRPID: case BCM4397_CHIP_GRPID: -#ifdef UNRELEASEDCHIP -#endif - clock = 37400*1000; break; CASE_BCM43602_CHIP: @@ -3497,7 +3501,7 @@ si_pmu_armpll_write_required(si_t *sih, uint32 xtal) * This function is only called for pmu1_ type chips, perhaps we should rename it. */ static bool -BCMATTACHFN(si_pmu_update_pllcontrol)(si_t *sih, osl_t *osh, uint32 xtal, bool update_required) +si_pmu_update_pllcontrol(si_t *sih, osl_t *osh, uint32 xtal, bool update_required) { pmuregs_t *pmu; uint origidx; @@ -3567,6 +3571,8 @@ BCMATTACHFN(si_pmu_update_pllcontrol)(si_t *sih, osl_t *osh, uint32 xtal, bool u break; case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: /* TBD : bypass PLL programming, So use chip default values */ @@ -3628,9 +3634,7 @@ BCMATTACHFN(si_pmu_update_pllcontrol)(si_t *sih, osl_t *osh, uint32 xtal, bool u W_REG(osh, &pmu->pmucontrol, tmp); } else { write_en = FALSE; - if (!FWSIGN_ENAB()) { - printf(rstr_Invalid_Unsupported_xtal_value_D, xtal); - } + printf(rstr_Invalid_Unsupported_xtal_value_D, xtal); } write_en = si_pmu_armpll_write_required(sih, xtal); @@ -4113,6 +4117,8 @@ si_pmu_pll_off(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 *min_mask, (BCM4362_CHIP(sih->chip)) || (BCM4376_CHIP(sih->chip)) || (BCM4378_CHIP(sih->chip)) || + (BCM4381_CHIP(sih->chip)) || + (BCM4383_CHIP(sih->chip)) || (BCM4385_CHIP(sih->chip)) || (BCM4387_CHIP(sih->chip)) || (BCM4388_CHIP(sih->chip)) || @@ -4190,6 +4196,8 @@ uint32 *max_mask, uint32 *clk_ctl_st) (BCM4362_CHIP(sih->chip)) || (BCM4376_CHIP(sih->chip)) || (BCM4378_CHIP(sih->chip)) || + (BCM4381_CHIP(sih->chip)) || + (BCM4383_CHIP(sih->chip)) || (BCM4385_CHIP(sih->chip)) || (BCM4387_CHIP(sih->chip)) || (BCM4388_CHIP(sih->chip)) || @@ -4262,7 +4270,7 @@ si_pmu_pll_on(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 min_mask_mask, * when done. */ static void -BCMATTACHFN(si_pmu1_pllinit1)(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 xtal) +si_pmu1_pllinit1(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 xtal) { char name[16]; const char *otp_val; @@ -4273,25 +4281,23 @@ BCMATTACHFN(si_pmu1_pllinit1)(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint32 xtal uint32 otpval = 0, regval = 0; #endif /* defined(BTOVERPCIE) && !defined(BTOVERPCIE_DISABLED) */ - if (!FWSIGN_ENAB()) { - if (PMUREV(sih->pmurev) >= 5) { - pll_ctrlcnt = (sih->pmucaps & PCAP5_PC_MASK) >> PCAP5_PC_SHIFT; - } else { - pll_ctrlcnt = (sih->pmucaps & PCAP_PC_MASK) >> PCAP_PC_SHIFT; - } + if (PMUREV(sih->pmurev) >= 5) { + pll_ctrlcnt = (sih->pmucaps & PCAP5_PC_MASK) >> PCAP5_PC_SHIFT; + } else { + pll_ctrlcnt = (sih->pmucaps & PCAP_PC_MASK) >> PCAP_PC_SHIFT; + } - /* Check if there is any otp enter for PLLcontrol registers */ - for (i = 0; i < pll_ctrlcnt; i++) { - snprintf(name, sizeof(name), rstr_pllD, i); - if ((otp_val = getvar(NULL, name)) == NULL) - continue; + /* Check if there is any otp enter for PLLcontrol registers */ + for (i = 0; i < pll_ctrlcnt; i++) { + snprintf(name, sizeof(name), rstr_pllD, i); + if ((otp_val = getvar(NULL, name)) == NULL) + continue; - /* If OTP entry is found for PLL register, then turn off the PLL - * and set the status of the OTP entry accordingly. - */ - otp_entry_found = TRUE; - break; - } + /* If OTP entry is found for PLL register, then turn off the PLL + * and set the status of the OTP entry accordingly. + */ + otp_entry_found = TRUE; + break; } /* If no OTP parameter is found and no chip-specific updates are needed, return. */ @@ -4421,6 +4427,8 @@ uint32 si_pmu_get_backplaneclkspeed(si_t *sih) uint32 tmp, mdiv = 1; switch (CHIPID(sih->chip)) { + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -4786,6 +4794,8 @@ si_pmu_fvco_macdiv(si_t *sih, uint32 *fvco, uint32 *div) & PMU1_PLL0_PC1_M4DIV_MASK) >> PMU1_PLL0_PC1_M4DIV_SHIFT; } break; + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4389_CHIP_GRPID: @@ -4936,7 +4946,7 @@ si_pmu_switch_off_PARLDO(si_t *sih, osl_t *osh) * Change VCO frequency (slightly), e.g. to avoid PHY errors due to spurs. */ static void -BCMATTACHFN(si_set_bb_vcofreq_frac)(si_t *sih, osl_t *osh, int vcofreq, int frac, int xtalfreq) +si_set_bb_vcofreq_frac(si_t *sih, osl_t *osh, int vcofreq, int frac, int xtalfreq) { uint32 vcofreq_withfrac, p1div, ndiv_int, fraca, ndiv_mode, reg; /* shifts / masks for PMU PLL control register #2 : */ @@ -5135,7 +5145,7 @@ si_pmu_enb_slow_clk(si_t *sih, osl_t *osh, uint32 xtalfreq) * xtalfreq : x-tal frequency in [KHz] */ void -BCMATTACHFN(si_pmu_pll_init)(si_t *sih, osl_t *osh, uint xtalfreq) +si_pmu_pll_init(si_t *sih, osl_t *osh, uint xtalfreq) { pmuregs_t *pmu; uint origidx; @@ -5174,6 +5184,8 @@ BCMATTACHFN(si_pmu_pll_init)(si_t *sih, osl_t *osh, uint xtalfreq) case BCM4362_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -5243,6 +5255,8 @@ BCMPOSTTRAPFN(si_pmu_alp_clock)(si_t *sih, osl_t *osh) case BCM4362_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -5371,6 +5385,8 @@ BCMPOSTTRAPFN(si_pmu_si_clock)(si_t *sih, osl_t *osh) clock = si_pmu1_cpuclk0(sih, osh, pmu); break; + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -5419,6 +5435,8 @@ BCMPOSTTRAPFN(si_pmu_cpu_clock)(si_t *sih, osl_t *osh) if (BCM4369_CHIP(sih->chip) || BCM4376_CHIP(sih->chip) || BCM4378_CHIP(sih->chip) || + BCM4381_CHIP(sih->chip) || + BCM4383_CHIP(sih->chip) || BCM4385_CHIP(sih->chip) || BCM4387_CHIP(sih->chip) || BCM4388_CHIP(sih->chip) || @@ -5510,7 +5528,7 @@ end: /** get memory clock frequency, which is the same as the HT clock for newer chips. Returns [Hz]. */ uint32 -BCMINITFN(si_pmu_mem_clock)(si_t *sih, osl_t *osh) +si_pmu_mem_clock(si_t *sih, osl_t *osh) { pmuregs_t *pmu; uint origidx; @@ -5536,6 +5554,8 @@ BCMINITFN(si_pmu_mem_clock)(si_t *sih, osl_t *osh) (CHIPID(sih->chip) == BCM43014_CHIP_ID) || BCM4376_CHIP(sih->chip) || BCM4378_CHIP(sih->chip) || + BCM4381_CHIP(sih->chip) || + BCM4383_CHIP(sih->chip) || BCM4387_CHIP(sih->chip) || BCM4388_CHIP(sih->chip) || BCM4389_CHIP(sih->chip) || @@ -5583,7 +5603,7 @@ BCMPOSTTRAPFN(si_pmu_ilp_clock_set)(uint32 cycles_per_sec) * turned on and used to feed the CPU and that OSL_DELAY() is calibrated. */ uint32 -BCMINITFN(si_pmu_ilp_clock)(si_t *sih, osl_t *osh) +si_pmu_ilp_clock(si_t *sih, osl_t *osh) { if (ISSIM_ENAB(sih)) return ILP_CLOCK; @@ -5664,7 +5684,7 @@ BCMPOSTTRAPFN(si_pmu_pllcontrol)(si_t *sih, uint reg, uint32 mask, uint32 val) * hardware supports this), if no hw support drive strength is not programmed. */ void -BCMINITFN(si_sdiod_drive_strength_init)(si_t *sih, osl_t *osh, uint32 drivestrength) +si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) { /* * Note: @@ -5683,7 +5703,7 @@ BCMINITFN(si_sdiod_drive_strength_init)(si_t *sih, osl_t *osh, uint32 drivestren #if !defined(BCMDONGLEHOST) /** initialize PMU */ void -BCMATTACHFN(si_pmu_init)(si_t *sih, osl_t *osh) +si_pmu_init(si_t *sih, osl_t *osh) { pmuregs_t *pmu; uint origidx; @@ -5794,7 +5814,7 @@ si_pmu_set_mac_rsrc_req_sc(si_t *sih, osl_t *osh) } uint32 -BCMATTACHFN(si_pmu_rsrc_ht_avail_clk_deps)(si_t *sih, osl_t *osh) +si_pmu_rsrc_ht_avail_clk_deps(si_t *sih, osl_t *osh) { uint32 deps; rsc_per_chip_t *rsc; @@ -5822,7 +5842,7 @@ BCMATTACHFN(si_pmu_rsrc_ht_avail_clk_deps)(si_t *sih, osl_t *osh) } uint32 -BCMATTACHFN(si_pmu_rsrc_cb_ready_deps)(si_t *sih, osl_t *osh) +si_pmu_rsrc_cb_ready_deps(si_t *sih, osl_t *osh) { uint32 deps; rsc_per_chip_t *rsc; @@ -5893,7 +5913,7 @@ si_pmu_set_mac_rsrc_req(si_t *sih, int macunit) * need to check circular dependancies and prevent dead recursion. */ static uint -BCMINITFN(si_pmu_res_uptime)(si_t *sih, osl_t *osh, +si_pmu_res_uptime(si_t *sih, osl_t *osh, pmuregs_t *pmu, uint8 rsrc, bool pmu_fast_trans_en) { uint32 deps; @@ -6050,13 +6070,12 @@ si_pmu_otp_power(si_t *sih, osl_t *osh, bool on, uint32* min_res_mask) case BCM4376_CHIP_GRPID: case BCM4385_CHIP_GRPID: -#ifdef UNRELEASEDCHIP -#endif - rsc = si_pmu_get_rsc_positions(sih); rsrcs = PMURES_BIT(rsc->otp_pu); break; case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: case BCM4389_CHIP_GRPID: @@ -6117,15 +6136,6 @@ si_pmu_otp_power(si_t *sih, osl_t *osh, bool on, uint32* min_res_mask) if (!si_pmu_otp_is_ready_and_wait(sih, on_check)) { PMU_MSG(("OTP ready bit not %s after wait\n", (on_check ? "ON" : "OFF"))); } -#ifdef NOT_YET - /* - * FIXME: Temporarily disabling OTPS_READY ASSERT check. Right now ASSERT in - * ROM is enabled only for 4389B0/C0. Therefore this change anyway will not - * affect other chips. Once the correct spin-wait value is updated by the - * HW team, then this ASSERT will be enabled back. - */ - ASSERT(si_pmu_otp_is_ready(sih) == on_check); -#endif /* NOT_YET */ } /* Return to original core */ @@ -6230,6 +6240,8 @@ si_pmu_is_otp_powered(si_t *sih, osl_t *osh) st = (R_REG(osh, &pmu->res_state) & PMURES_BIT(rsc->otp_pu)) != 0; break; case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: case BCM4389_CHIP_GRPID: @@ -6252,7 +6264,7 @@ si_pmu_is_otp_powered(si_t *sih, osl_t *osh) * savings (due to more accurate sleep intervals). */ static void -BCMATTACHFN(si_pmu_set_lpoclk)(si_t *sih, osl_t *osh) +si_pmu_set_lpoclk(si_t *sih, osl_t *osh) { uint32 ext_lpo_sel, int_lpo_sel, timeout = 0, ext_lpo_avail = 0, lpo_sel = 0; @@ -6411,6 +6423,8 @@ si_pmu_fast_lpo_locked(si_t *sih, osl_t *osh) case BCM4378_CHIP_GRPID: lock = si_gci_chipstatus(sih, GCI_CHIPSTATUS_13) & GCI_CS_4369_FLL1MHZ_LOCK_MASK; break; + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -6426,7 +6440,7 @@ si_pmu_fast_lpo_locked(si_t *sih, osl_t *osh) /* Turn ON FAST LPO FLL (1MHz) */ static void -BCMATTACHFN(si_pmu_fast_lpo_enable)(si_t *sih, osl_t *osh) +si_pmu_fast_lpo_enable(si_t *sih, osl_t *osh) { int i = 0, lock = 0; @@ -6459,6 +6473,8 @@ BCMATTACHFN(si_pmu_fast_lpo_enable)(si_t *sih, osl_t *osh) case BCM4369_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -6502,7 +6518,7 @@ BCMATTACHFN(si_pmu_fast_lpo_enable)(si_t *sih, osl_t *osh) /* Turn ON FAST LPO FLL (1MHz) for PCIE */ bool -BCMATTACHFN(si_pmu_fast_lpo_enable_pcie)(si_t *sih) +si_pmu_fast_lpo_enable_pcie(si_t *sih) { if (!FASTLPO_ENAB()) { return FALSE; @@ -6512,6 +6528,8 @@ BCMATTACHFN(si_pmu_fast_lpo_enable_pcie)(si_t *sih) case BCM4369_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -6538,7 +6556,7 @@ BCMATTACHFN(si_pmu_fast_lpo_enable_pcie)(si_t *sih) /* Turn ON FAST LPO FLL (1MHz) for PMU */ bool -BCMATTACHFN(si_pmu_fast_lpo_enable_pmu)(si_t *sih) +si_pmu_fast_lpo_enable_pmu(si_t *sih) { if (!FASTLPO_ENAB()) { return FALSE; @@ -6548,6 +6566,8 @@ BCMATTACHFN(si_pmu_fast_lpo_enable_pmu)(si_t *sih) case BCM4369_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -6570,7 +6590,7 @@ BCMATTACHFN(si_pmu_fast_lpo_enable_pmu)(si_t *sih) } static uint8 -BCMATTACHFN(fastlpo_dis_get)(void) +fastlpo_dis_get(void) { uint8 fastlpo_dis = 1; @@ -6586,7 +6606,7 @@ BCMATTACHFN(fastlpo_dis_get)(void) } static uint8 -BCMATTACHFN(fastlpo_pcie_dis_get)(void) +fastlpo_pcie_dis_get(void) { uint8 fastlpo_pcie_dis = 1; @@ -6600,7 +6620,7 @@ BCMATTACHFN(fastlpo_pcie_dis_get)(void) } static void -BCMATTACHFN(si_pmu_fll_preload_enable)(si_t *sih) +si_pmu_fll_preload_enable(si_t *sih) { if (!PMU_FLL_PU_ENAB()) { return; @@ -6639,7 +6659,7 @@ BCMATTACHFN(si_pmu_fll_preload_enable)(si_t *sih) */ #if defined(SAVERESTORE) static void -BCMATTACHFN(si_set_lv_sleep_mode_pmu)(si_t *sih, osl_t *osh) +si_set_lv_sleep_mode_pmu(si_t *sih, osl_t *osh) { /* jtag_udr_write USER_REG9W jtag_serdes_pic_enable 1 */ if (BCM4369_CHIP(sih->chip) && (CHIPREV(sih->chiprev) == 0)) { @@ -6691,7 +6711,7 @@ BCMATTACHFN(si_set_lv_sleep_mode_pmu)(si_t *sih, osl_t *osh) * and bypass when in sleep mode */ if (!(BCM4389_CHIP(sih->chip) || BCM4388_CHIP(sih->chip) || BCM4397_CHIP(sih->chip) || - BCM4387_CHIP(sih->chip))) { + BCM4387_CHIP(sih->chip) || BCM4381_CHIP(sih->chip) || BCM4383_CHIP(sih->chip))) { si_pmu_vreg_control(sih, PMU_VREG_5, PMU_4369_VREG_5_MISCLDO_POWER_UP_MASK, ((CHIPREV(sih->chiprev) == 0) ? 1 : 0) << PMU_4369_VREG_5_MISCLDO_POWER_UP_SHIFT); @@ -6751,7 +6771,7 @@ BCMATTACHFN(si_set_lv_sleep_mode_pmu)(si_t *sih, osl_t *osh) } static void -BCMATTACHFN(si_set_lv_sleep_mode_4369)(si_t *sih, osl_t *osh) +si_set_lv_sleep_mode_4369(si_t *sih, osl_t *osh) { si_set_lv_sleep_mode_pmu(sih, osh); @@ -6778,7 +6798,7 @@ void si_set_abuck_mode_4362(si_t *sih, uint8 mode) } static void -BCMATTACHFN(si_set_lv_sleep_mode_4378)(si_t *sih, osl_t *osh) +si_set_lv_sleep_mode_4378(si_t *sih, osl_t *osh) { si_set_lv_sleep_mode_pmu(sih, osh); @@ -6786,7 +6806,7 @@ BCMATTACHFN(si_set_lv_sleep_mode_4378)(si_t *sih, osl_t *osh) } static void -BCMATTACHFN(si_set_lv_sleep_mode_pmu_4387)(si_t *sih, osl_t *osh) +si_set_lv_sleep_mode_pmu_4387(si_t *sih, osl_t *osh) { /* Program pmu VREG resgiter for Resouce based ABUCK and CBUCK modes * cbuck rsrc 0 - PWM and abuck rsrc 0 - Auto, rsrc 1 - PWM @@ -6944,14 +6964,14 @@ BCMATTACHFN(si_set_lv_sleep_mode_pmu_4387)(si_t *sih, osl_t *osh) } static void -BCMATTACHFN(si_set_lv_sleep_mode_4387)(si_t *sih, osl_t *osh) +si_set_lv_sleep_mode_4387(si_t *sih, osl_t *osh) { si_set_lv_sleep_mode_pmu_4387(sih, osh); si_set_lv_sleep_mode_lhl_config_4387(sih); } static void -BCMATTACHFN(si_set_lv_sleep_mode_4389)(si_t *sih, osl_t *osh) +si_set_lv_sleep_mode_4389(si_t *sih, osl_t *osh) { si_set_lv_sleep_mode_pmu(sih, osh); @@ -6975,18 +6995,6 @@ BCMATTACHFN(si_set_lv_sleep_mode_4389)(si_t *sih, osl_t *osh) PMU_CC13_AUX_MEMLPLDO2VDDRET_OFF, 0); -#ifdef NOT_YET - /* FIXME: this setting is causing the load switch from CSR to ASR */ - si_pmu_chipcontrol(sih, PMU_CHIPCTL13, - PMU_CC13_SUBCORE_MEMLPLDO2VDDB_OFF | - PMU_CC13_SUBCORE_MEMLPLDO2VDDRET_OFF | - PMU_CC13_MAIN_MEMLPLDO2VDDB_OFF | - PMU_CC13_MAIN_MEMLPLDO2VDDRET_OFF | - PMU_CC13_AUX_MEMLPLDO2VDDB_OFF | - PMU_CC13_AUX_MEMLPLDO2VDDRET_OFF | - PMU_CC13_CMN_MEMLPLDO2VDDRET_ON, 0); -#endif /* NOT_YET */ - si_pmu_chipcontrol(sih, PMU_CHIPCTL17, PMU_CC17_SCAN_MEMLPLDO2VDDRET_ON | PMU_CC17_SCAN_CBUCK2VDDB_ON | @@ -7013,7 +7021,7 @@ BCMATTACHFN(si_set_lv_sleep_mode_4389)(si_t *sih, osl_t *osh) } static void -BCMATTACHFN(si_set_lv_sleep_mode_4362)(si_t *sih, osl_t *osh) +si_set_lv_sleep_mode_4362(si_t *sih, osl_t *osh) { /* Program pmu VREG resgiter for Resouce based ABUCK and CBUCK modes * cbuck rsrc 0 - PWM and abuck rsrc 0 - Auto, rsrc 1 - PWM @@ -7096,7 +7104,7 @@ BCMATTACHFN(si_set_lv_sleep_mode_4362)(si_t *sih, osl_t *osh) } void -BCMATTACHFN(si_pmu_fis_setup)(si_t *sih) +si_pmu_fis_setup(si_t *sih) { uint origidx; pmuregs_t *pmu; @@ -7160,7 +7168,7 @@ BCMATTACHFN(si_pmu_fis_setup)(si_t *sih) * use nvram to enable */ static void -BCMATTACHFN(si_pmu_dynamic_clk_switch_enab)(si_t *sih) +si_pmu_dynamic_clk_switch_enab(si_t *sih) { if (PMUREV(sih->pmurev) >= 36) { if (getintvar(NULL, rstr_dyn_clksw_en)) { @@ -7176,7 +7184,7 @@ BCMATTACHFN(si_pmu_dynamic_clk_switch_enab)(si_t *sih) /* use pmu rsrc XTAL_PU to count deep sleep of chip */ static void -BCMATTACHFN(si_pmu_enb_slp_cnt_on_rsrc)(si_t *sih, osl_t *osh) +si_pmu_enb_slp_cnt_on_rsrc(si_t *sih, osl_t *osh) { uint origidx; pmuregs_t *pmu; @@ -7223,7 +7231,7 @@ BCMATTACHFN(si_pmu_enb_slp_cnt_on_rsrc)(si_t *sih, osl_t *osh) /** initialize PMU chip controls and other chip level stuff */ void -BCMATTACHFN(si_pmu_chip_init)(si_t *sih, osl_t *osh) +si_pmu_chip_init(si_t *sih, osl_t *osh) { ASSERT(sih->cccaps & CC_CAP_PMU); if (AOB_ENAB(sih)) { @@ -7576,6 +7584,8 @@ BCMATTACHFN(si_pmu_chip_init)(si_t *sih, osl_t *osh) } break; + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: { @@ -8144,7 +8154,7 @@ si_pmu_slow_clk_reinit(si_t *sih, osl_t *osh) /** initialize PMU registers in case default values proved to be suboptimal */ void -BCMATTACHFN(si_pmu_swreg_init)(si_t *sih, osl_t *osh) +si_pmu_swreg_init(si_t *sih, osl_t *osh) { ASSERT(sih->cccaps & CC_CAP_PMU); @@ -8158,6 +8168,8 @@ BCMATTACHFN(si_pmu_swreg_init)(si_t *sih, osl_t *osh) GPIO_DRIVE_4378_VAL); /* fall through */ case BCM4376_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: #ifdef BCM_AVS @@ -8206,7 +8218,7 @@ si_pmu_waitforclk_on_backplane(si_t *sih, osl_t *osh, uint32 clk, uint32 delay_v * Possible only if PMU rev >= 10 and there is an external LPO 32768Hz crystal. */ uint32 -BCMATTACHFN(si_pmu_measure_alpclk)(si_t *sih, osl_t *osh) +si_pmu_measure_alpclk(si_t *sih, osl_t *osh) { uint32 alp_khz; uint32 pmustat_lpo = 0; @@ -8297,6 +8309,8 @@ si_pmu_res_minmax_update(si_t *sih, osl_t *osh) case BCM4362_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -8391,7 +8405,7 @@ static uint32 *rodata_pmuregdump_ptr = NULL; /** size of the buffer needed to store the PMU register dump specifically PMU indirect registers */ uint32 -BCMATTACHFN(si_pmu_dump_buf_size_pmucap)(si_t *sih) +si_pmu_dump_buf_size_pmucap(si_t *sih) { uint32 buf_size = 0; uint32 pmu_size = 0; @@ -9005,7 +9019,7 @@ si_pmu_pll6val_armclk_calc(osl_t *osh, pmuregs_t *pmu, uint32 armclk, uint32 xta } static void -BCMATTACHFN(si_pmu_chipcontrol_xtal_settings_4369)(si_t *sih) +si_pmu_chipcontrol_xtal_settings_4369(si_t *sih) { /* 4369 XTAL Bias settings */ @@ -9044,7 +9058,7 @@ BCMATTACHFN(si_pmu_chipcontrol_xtal_settings_4369)(si_t *sih) } static void -BCMATTACHFN(si_pmu_chipcontrol_xtal_settings_4362)(si_t *sih) +si_pmu_chipcontrol_xtal_settings_4362(si_t *sih) { /* 4369 XTAL Bias settings */ /* @@ -9090,7 +9104,7 @@ BCMATTACHFN(si_pmu_chipcontrol_xtal_settings_4362)(si_t *sih) * xt_res_bypass 0x0 0x2 */ static void -BCMATTACHFN(si_pmu_chipcontrol_xtal_settings_4378)(si_t *sih) +si_pmu_chipcontrol_xtal_settings_4378(si_t *sih) { uint32 u32Val; uint32 u32Mask; @@ -9135,7 +9149,7 @@ BCMATTACHFN(si_pmu_chipcontrol_xtal_settings_4378)(si_t *sih) #ifdef XTAL_BIAS_FROM_OTP static void -BCMATTACHFN(si_pmu_chipcontrol_xtal_bias_from_otp)(si_t *sih, uint8* flag, uint8* val) +si_pmu_chipcontrol_xtal_bias_from_otp(si_t *sih, uint8* flag, uint8* val) { uint8 xtal_bias_adj = 0, xtal_bias_cal_otp_done = 0; #ifndef BCM_OTP_API @@ -9171,7 +9185,7 @@ BCMATTACHFN(si_pmu_chipcontrol_xtal_bias_from_otp)(si_t *sih, uint8* flag, uint8 #ifndef BCM_OTP_API static void -BCMATTACHFN(si_pmu_chipcontrol_xtal_bias_cal_done_offsets)(si_t *sih, uint16* wrd_offset, +si_pmu_chipcontrol_xtal_bias_cal_done_offsets(si_t *sih, uint16* wrd_offset, uint8* wrd_shift, uint8* wrd_mask) { /* Offset is 16 bit aligned address, shift is the starting bit position of the value @@ -9193,7 +9207,7 @@ BCMATTACHFN(si_pmu_chipcontrol_xtal_bias_cal_done_offsets)(si_t *sih, uint16* wr } static void -BCMATTACHFN(si_pmu_chipcontrol_xtal_bias_val_offsets)(si_t *sih, uint16* wrd_offset, +si_pmu_chipcontrol_xtal_bias_val_offsets(si_t *sih, uint16* wrd_offset, uint8* wrd_shift, uint8* wrd_mask) { /* Offset is 16 bit aligned address, shift is the starting bit position of the value @@ -9788,6 +9802,8 @@ BCMPOSTTRAPFN(si_pmu_disable_intr_pwrreq)(si_t *sih) switch (CHIPID(sih->chip)) { case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -9927,3 +9943,13 @@ si_pmu_res_state_wait(si_t *sih, uint rsrc) SPINWAIT(!(PMU_REG(sih, res_state, 0, 0) & PMURES_BIT(rsrc)), PMU_MAX_TRANSITION_DLY); ASSERT(PMU_REG(sih, res_state, 0, 0) & PMURES_BIT(rsrc)); } + +void +si_pmu_43711a0_pll_war(si_t *sih) +{ + uint32 ndiv_int = 0x022; + + pmu_corereg(sih, SI_CC_IDX, pllcontrol_addr, ~0, PMU_PLL_CTRL_REG6); + pmu_corereg(sih, SI_CC_IDX, pllcontrol_data, PMU4369_PLL1_PC6_NDIV_INT_MASK, + ndiv_int << PMU4369_PLL1_PC6_NDIV_INT_SHIFT); +} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11.h old mode 100755 new mode 100644 index c1cc979b7f72..3404aac0a397 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11.h @@ -1,7 +1,13 @@ /* - * Fundamental types and constants relating to 802.11 + * Fundamental types and constants relating to the 802.11 base spec.. * - * Copyright (C) 2020, Broadcom. + * All amendment specific work should be placed in separate + * amendment specific header files e.g. 802.11k.h. + * + * WFA related work should be placed in 802.11wfa.h. + * Broadcom specific work should be placed in 802.11brcm.h. + * + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -180,35 +186,18 @@ BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame { } BWL_POST_PACKED_STRUCT; #define DOT11_CS_END_LEN 16 /* d11 CF-END frame length */ -/** - * RWL wifi protocol: The Vendor Specific Action frame is defined for vendor-specific signaling - * category+OUI+vendor specific content ( this can be variable) - */ -BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific { - uint8 category; - uint8 OUI[3]; - uint8 type; - uint8 subtype; - uint8 data[1040]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t; - /** generic vendor specific action frame with variable length */ BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr { uint8 category; uint8 OUI[3]; uint8 type; uint8 subtype; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT; typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t; #define DOT11_ACTION_VS_HDR_LEN 6 -#define BCM_ACTION_OUI_BYTE0 0x00 -#define BCM_ACTION_OUI_BYTE1 0x90 -#define BCM_ACTION_OUI_BYTE2 0x4c - /* BA/BAR Control parameters */ #define DOT11_BA_CTL_POLICY_NORMAL 0x0000 /* normal ack */ #define DOT11_BA_CTL_POLICY_NOACK 0x0001 /* no ack */ @@ -216,6 +205,7 @@ typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t; #define DOT11_BA_CTL_MTID 0x0002 /* multi tid BA */ #define DOT11_BA_CTL_COMPRESSED 0x0004 /* compressed bitmap */ +#define DOT11_BA_CTL_GCR 0x0008 /* GCR BAR */ #define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 /* num msdu in bitmap mask */ #define DOT11_BA_CTL_NUMMSDU_SHIFT 6 /* num msdu in bitmap shift */ @@ -230,6 +220,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_ctl_header { struct ether_addr ra; /* receiver address */ struct ether_addr ta; /* transmitter address */ } BWL_POST_PACKED_STRUCT; +typedef struct dot11_ctl_header dot11_ctl_header_t; #define DOT11_CTL_HDR_LEN 16 /* control frame hdr len */ /** BAR frame payload */ @@ -239,6 +230,14 @@ BWL_PRE_PACKED_STRUCT struct dot11_bar { } BWL_POST_PACKED_STRUCT; #define DOT11_BAR_LEN 4 /* BAR frame payload length */ +/** GCR BAR frame payload */ +BWL_PRE_PACKED_STRUCT struct dot11_gcr_bar { + uint16 bar_control; /* BAR Control */ + uint16 seqnum; /* Starting Sequence control */ + struct ether_addr gcr; /* GCR address */ +} BWL_POST_PACKED_STRUCT; +#define DOT11_GCR_BAR_LEN 10u /* GCR BAR frame payload length */ + #define DOT11_BA_BITMAP_LEN 128 /* bitmap length */ #define DOT11_BA_CMP_BITMAP_LEN 8 /* compressed bitmap length */ /** BA frame payload */ @@ -306,44 +305,16 @@ BWL_PRE_PACKED_STRUCT struct dot11_action_measure { uint8 category; uint8 action; uint8 token; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT; #define DOT11_ACTION_MEASURE_LEN 3 /* d11 action measurement header length */ -BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width { - uint8 category; - uint8 action; - uint8 ch_width; -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops { - uint8 category; - uint8 action; - uint8 control; -} BWL_POST_PACKED_STRUCT; - BWL_PRE_PACKED_STRUCT struct dot11_action_sa_query { uint8 category; uint8 action; uint16 id; } BWL_POST_PACKED_STRUCT; -BWL_PRE_PACKED_STRUCT struct dot11_action_vht_oper_mode { - uint8 category; - uint8 action; - uint8 mode; -} BWL_POST_PACKED_STRUCT; - -/* These lengths assume 64 MU groups, as specified in 802.11ac-2013 */ -#define DOT11_ACTION_GID_MEMBERSHIP_LEN 8 /* bytes */ -#define DOT11_ACTION_GID_USER_POS_LEN 16 /* bytes */ -BWL_PRE_PACKED_STRUCT struct dot11_action_group_id { - uint8 category; - uint8 action; - uint8 membership_status[DOT11_ACTION_GID_MEMBERSHIP_LEN]; - uint8 user_position[DOT11_ACTION_GID_USER_POS_LEN]; -} BWL_POST_PACKED_STRUCT; - #define SM_PWRSAVE_ENABLE 1 #define SM_PWRSAVE_MODE 2 @@ -379,41 +350,10 @@ BWL_PRE_PACKED_STRUCT struct dot11_supp_channels { } BWL_POST_PACKED_STRUCT; typedef struct dot11_supp_channels dot11_supp_channels_t; -/** - * Extension Channel Offset IE: 802.11n-D1.0 spec. added sideband - * offset for 40MHz operation. The possible 3 values are: - * 1 = above control channel - * 3 = below control channel - * 0 = no extension channel - */ -BWL_PRE_PACKED_STRUCT struct dot11_extch { - uint8 id; /* IE ID, 62, DOT11_MNG_EXT_CHANNEL_OFFSET */ - uint8 len; /* IE length */ - uint8 extch; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_extch dot11_extch_ie_t; - -BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ - uint8 type; /* type indicates what follows */ - uint8 extch; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; - -#define BRCM_EXTCH_IE_LEN 5 -#define BRCM_EXTCH_IE_TYPE 53 /* 802.11n ID not yet assigned */ -#define DOT11_EXTCH_IE_LEN 1 -#define DOT11_EXT_CH_MASK 0x03 /* extension channel mask */ -#define DOT11_EXT_CH_UPPER 0x01 /* ext. ch. on upper sb */ -#define DOT11_EXT_CH_LOWER 0x03 /* ext. ch. on lower sb */ -#define DOT11_EXT_CH_NONE 0x00 /* no extension ch. */ - BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr { uint8 category; uint8 action; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT; typedef struct dot11_action_frmhdr dot11_action_frmhdr_t; @@ -444,13 +384,6 @@ typedef struct dot11_channel_switch dot11_chan_switch_ie_t; #define DOT11_CSA_MODE_ADVISORY 0 /* no DOT11_CSA_MODE_NO_TX restriction imposed */ #define DOT11_CSA_MODE_NO_TX 1 /* no transmission upon receiving CSA frame. */ -BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel { - uint8 category; - uint8 action; - dot11_chan_switch_ie_t chan_switch_ie; /* for switch IE */ - dot11_brcm_extch_ie_t extch_ie; /* extension channel offset */ -} BWL_POST_PACKED_STRUCT; - BWL_PRE_PACKED_STRUCT struct dot11_csa_body { uint8 mode; /* mode 0 or 1 */ uint8 reg; /* regulatory class */ @@ -458,81 +391,12 @@ BWL_PRE_PACKED_STRUCT struct dot11_csa_body { uint8 count; /* number of beacons before switching */ } BWL_POST_PACKED_STRUCT; -/** 11n Extended Channel Switch IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { - uint8 id; /* id DOT11_MNG_EXT_CSA_ID */ - uint8 len; /* length of IE */ - struct dot11_csa_body b; /* body of the ie */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ext_csa dot11_ext_csa_ie_t; -#define DOT11_EXT_CSA_IE_LEN 4 /* length of extended channel switch IE body */ - -BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa { - uint8 category; - uint8 action; - dot11_ext_csa_ie_t chan_switch_ie; /* for switch IE */ -} BWL_POST_PACKED_STRUCT; - BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa { uint8 category; uint8 action; struct dot11_csa_body b; /* body of the ie */ } BWL_POST_PACKED_STRUCT; -/** Wide Bandwidth Channel Switch IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel_switch { - uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ - uint8 len; /* length of IE */ - uint8 channel_width; /* new channel width */ - uint8 center_frequency_segment_0; /* center frequency segment 0 */ - uint8 center_frequency_segment_1; /* center frequency segment 1 */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wide_bw_channel_switch dot11_wide_bw_chan_switch_ie_t; - -#define DOT11_WIDE_BW_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ - -/** Channel Switch Wrapper IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_channel_switch_wrapper { - uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ - uint8 len; /* length of IE */ - dot11_wide_bw_chan_switch_ie_t wb_chan_switch_ie; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_channel_switch_wrapper dot11_chan_switch_wrapper_ie_t; - -/* Proposed wide bandwidth channel IE */ -typedef enum wide_bw_chan_width { - WIDE_BW_CHAN_WIDTH_20 = 0, - WIDE_BW_CHAN_WIDTH_40 = 1, - WIDE_BW_CHAN_WIDTH_80 = 2, - WIDE_BW_CHAN_WIDTH_160 = 3, - WIDE_BW_CHAN_WIDTH_80_80 = 4 -} wide_bw_chan_width_t; - -/** Wide Bandwidth Channel IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel { - uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_ID */ - uint8 len; /* length of IE */ - uint8 channel_width; /* channel width */ - uint8 center_frequency_segment_0; /* center frequency segment 0 */ - uint8 center_frequency_segment_1; /* center frequency segment 1 */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wide_bw_channel dot11_wide_bw_chan_ie_t; - -#define DOT11_WIDE_BW_IE_LEN 3 /* length of IE data, not including 2 byte header */ -/** VHT Transmit Power Envelope IE data structure */ -BWL_PRE_PACKED_STRUCT struct dot11_vht_transmit_power_envelope { - uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ - uint8 len; /* length of IE */ - uint8 transmit_power_info; - uint8 local_max_transmit_power_20; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_vht_transmit_power_envelope dot11_vht_transmit_power_envelope_ie_t; - -/* vht transmit power envelope IE length depends on channel width */ -#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_40MHZ 1 -#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_80MHZ 2 -#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_160MHZ 3 - /* TPE Transmit Power Information Field */ #define DOT11_TPE_INFO_MAX_TX_PWR_CNT_MASK 0x07u #define DOT11_TPE_INFO_MAX_TX_PWR_INTRPN_MASK 0x38u @@ -551,25 +415,28 @@ typedef struct dot11_vht_transmit_power_envelope dot11_vht_transmit_power_envelo DOT11_TPE_INFO_MAX_TX_PWR_CAT_SHIFT) /* Maximum Transmit Power Interpretation subfield */ -#define DOT11_TPE_MAX_TX_PWR_INTRPN_LOCAL_EIRP 0u -#define DOT11_TPE_MAX_TX_PWR_INTRPN_LOCAL_EIRP_PSD 1u -#define DOT11_TPE_MAX_TX_PWR_INTRPN_REG_CLIENT_EIRP 2u -#define DOT11_TPE_MAX_TX_PWR_INTRPN_REG_CLIENT_EIRP_PSD 3u +#define DOT11_TPE_MAX_TX_PWR_INTRPN_LOCAL_EIRP 0u +#define DOT11_TPE_MAX_TX_PWR_INTRPN_LOCAL_EIRP_PSD 1u +#define DOT11_TPE_MAX_TX_PWR_INTRPN_REG_CLIENT_EIRP 2u +#define DOT11_TPE_MAX_TX_PWR_INTRPN_REG_CLIENT_EIRP_PSD 3u +#define DOT11_TPE_MAX_TX_PWR_INTRPN_MAX 4u /* Maximum Transmit Power category subfield */ -#define DOT11_TPE_MAX_TX_PWR_CAT_DEFAULT 0u +#define DOT11_TPE_MAX_TX_PWR_CAT_DEFAULT 0u /* Maximum Transmit Power category subfield in US */ -#define DOT11_TPE_MAX_TX_PWR_CAT_US_DEFAULT 0u -#define DOT11_TPE_MAX_TX_PWR_CAT_US_SUB_DEV 1u +#define DOT11_TPE_MAX_TX_PWR_CAT_US_DEFAULT 0u +#define DOT11_TPE_MAX_TX_PWR_CAT_US_SUB_DEV 1u +#define DOT11_TPE_MAX_TX_PWR_CAT_MAX 2u /* Maximum Transmit Power Count subfield values when * Maximum Transmit Power Interpretation subfield is 0 or 2 */ -#define DOT11_TPE_INFO_MAX_TX_CNT_EIRP_20_MHZ 0u -#define DOT11_TPE_INFO_MAX_TX_CNT_EIRP_20_40_MHZ 1u -#define DOT11_TPE_INFO_MAX_TX_CNT_EIRP_20_40_80_MHZ 2u -#define DOT11_TPE_INFO_MAX_TX_CNT_EIRP_20_40_80_160_MHZ 3u +#define DOT11_TPE_INFO_MAX_TX_CNT_EIRP_20_MHZ 0u +#define DOT11_TPE_INFO_MAX_TX_CNT_EIRP_20_40_MHZ 1u +#define DOT11_TPE_INFO_MAX_TX_CNT_EIRP_20_40_80_MHZ 2u +#define DOT11_TPE_INFO_MAX_TX_CNT_EIRP_20_40_80_160_MHZ 3u +#define DOT11_TPE_INFO_MAX_TX_PWR_CNT_MAX 7u /* Maximum Transmit Power Count subfield values when * Maximum Transmit Power Interpretation subfield is 1 or 3 @@ -597,31 +464,10 @@ typedef struct dot11_transmit_power_envelope dot11_transmit_power_envelope_ie_t; /* id (1) + len (1) + transmit_power_info(1) + max_transmit_power(1) */ #define DOT11_TPE_ELEM_MIN_LEN 4u -BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { - uint8 id; - uint8 len; - uint8 info; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_obss_coex dot11_obss_coex_t; -#define DOT11_OBSS_COEXINFO_LEN 1 /* length of OBSS Coexistence INFO IE */ - -#define DOT11_OBSS_COEX_INFO_REQ 0x01 -#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 -#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 - -BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist { - uint8 id; - uint8 len; - uint8 regclass; - uint8 chanlist[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; -#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 /* fixed length of regclass */ - BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { uint8 id; uint8 len; - uint8 cap[1]; + uint8 cap[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT; typedef struct dot11_extcap_ie dot11_extcap_ie_t; @@ -630,45 +476,39 @@ typedef struct dot11_extcap_ie dot11_extcap_ie_t; #define DOT11_EXTCAP_LEN_IW 4 #define DOT11_EXTCAP_LEN_SI 6 -#define DOT11_EXTCAP_LEN_TDLS 5 -#define DOT11_11AC_EXTCAP_LEN_TDLS 8 - -#define DOT11_EXTCAP_LEN_FMS 2 -#define DOT11_EXTCAP_LEN_PROXY_ARP 2 -#define DOT11_EXTCAP_LEN_TFS 3 -#define DOT11_EXTCAP_LEN_WNM_SLEEP 3 -#define DOT11_EXTCAP_LEN_TIMBC 3 -#define DOT11_EXTCAP_LEN_BSSTRANS 3 -#define DOT11_EXTCAP_LEN_DMS 4 -#define DOT11_EXTCAP_LEN_WNM_NOTIFICATION 6 -#define DOT11_EXTCAP_LEN_TDLS_WBW 8 #define DOT11_EXTCAP_LEN_OPMODE_NOTIFICATION 8 #define DOT11_EXTCAP_LEN_TWT 10u #define DOT11_EXTCAP_LEN_BCN_PROT 11u -/* TDLS Capabilities */ -#define DOT11_TDLS_CAP_TDLS 37 /* TDLS support */ -#define DOT11_TDLS_CAP_PU_BUFFER_STA 28 /* TDLS Peer U-APSD buffer STA support */ -#define DOT11_TDLS_CAP_PEER_PSM 20 /* TDLS Peer PSM support */ -#define DOT11_TDLS_CAP_CH_SW 30 /* TDLS Channel switch */ -#define DOT11_TDLS_CAP_PROH 38 /* TDLS prohibited */ -#define DOT11_TDLS_CAP_CH_SW_PROH 39 /* TDLS Channel switch prohibited */ -#define DOT11_TDLS_CAP_TDLS_WIDER_BW 61 /* TDLS Wider Band-Width */ - -#define TDLS_CAP_MAX_BIT 39 /* TDLS max bit defined in ext cap */ - -/* FIXME: remove redundant DOT11_CAP_SAE_HASH_TO_ELEMENT */ -#define DOT11_CAP_SAE_HASH_TO_ELEMENT 5u /* SAE Hash-to-element support */ +/* Extended RSN capabilities (RSNXE capabilities) */ +#define DOT11_EXT_RSN_CAP_LEN_MASK 0x000fu /* Field length mask */ #define DOT11_EXT_RSN_CAP_SAE_H2E 5u /* SAE Hash-to-element support */ -/* FIXME: Use these temporary IDs until ANA assigns IDs */ +#define DOT11_CAP_SAE_HASH_TO_ELEMENT DOT11_EXT_RSN_CAP_SAE_H2E /* duped. to be removed */ #define DOT11_EXT_RSN_CAP_SAE_PK 6u /* SAE-PK support */ -/* Last bit in extended rsn capabilities (RSNXE) */ -#define DOT11_EXT_RSN_CAP_MAX_BIT DOT11_EXT_RSN_CAP_SAE_PK +/* Draft P802.11az/D2.5 - Table 9-321 Extended RSN Capabilities field */ +#define DOT11_EXT_RSN_CAP_SECURE_LTF 8u /* Secure LTF support */ +#define DOT11_EXT_RSN_CAP_SECURE_RTT 9u /* Secure RTT(EDMG measurement) support */ +/* Protection of Ranging management frame is required */ +#define DOT11_EXT_RSN_CAP_URNM_MFPR_X20 10u /* except BW20 ranging */ +#define DOT11_EXT_RSN_CAP_RANGE_PMF_REQUIRED DOT11_EXT_RSN_CAP_URNM_MFPR_X20 /* to be removed */ +#define DOT11_EXT_RSN_CAP_URNM_MFPR 15u /* P802.11az/D4.1 */ + +/* Last bit in Extended RSN Capabilities defined in P802.11 + * Please update DOT11_EXT_RSN_CAP_LAST_BIT_IDX to the last bit when P802.11 inteoduced new bit + */ +#define DOT11_EXT_RSN_CAP_LAST_BIT_IDX DOT11_EXT_RSN_CAP_URNM_MFPR /* update this */ +#define DOT11_EXT_RSN_CAP_NUM_BITS_MAX (DOT11_EXT_RSN_CAP_LAST_BIT_IDX + 1) /* last bit idx + 1 */ + +/* Please use DOT11_EXT_RSN_CAP_BYTE_LEN_MAX for any of RSNXE cap buffer size ONLY in ATTACH time. + * Othewise, change of DOT11_EXT_RSN_CAP_BYTE_LEN_MAX cause ROM invalidation. + * DOT11_EXT_RSN_CAP_BYTE_LEN_MAX can grow with 802.11 change. + */ +#define DOT11_EXT_RSN_CAP_BYTE_LEN_MAX ((DOT11_EXT_RSN_CAP_NUM_BITS_MAX + 7) >> 3) /* byte len */ BWL_PRE_PACKED_STRUCT struct dot11_rsnxe { uint8 id; /* id DOT11_MNG_RSNXE_ID */ uint8 len; - uint8 cap[1]; + uint8 cap[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT; typedef struct dot11_rsnxe dot11_rsnxe_t; @@ -676,6 +516,10 @@ typedef struct dot11_rsnxe dot11_rsnxe_t; #define RSNXE_CAP_LENGTH(cap) ((uint8)(cap) & RSNXE_CAP_LENGTH_MASK) #define RSNXE_SET_CAP_LENGTH(cap, len)\ (cap = (cap & ~RSNXE_CAP_LENGTH_MASK) | ((uint8)(len) & RSNXE_CAP_LENGTH_MASK)) +/* The first 4 bit of CAPs field is the length of the Extended RSN Capabilities minus 1 */ +#define IS_RSNXE_VALID(ie) ((ie) && (((dot11_rsnxe_t *)(ie))->len >= 1u) && \ + (((dot11_rsnxe_t *)(ie))->len > \ + RSNXE_CAP_LENGTH(((dot11_rsnxe_t *)(ie))->cap[0]))) BWL_PRE_PACKED_STRUCT struct dot11_rejected_groups_ie { uint8 id; /* DOT11_MNG_EXT_ID */ @@ -748,25 +592,25 @@ BWL_PRE_PACKED_STRUCT struct dot11_meas_req_loc { { BWL_PRE_PACKED_STRUCT struct { uint8 subject; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT lci; BWL_PRE_PACKED_STRUCT struct { uint8 subject; uint8 type; /* type of civic location */ uint8 siu; /* service interval units */ uint16 si; /* service interval */ - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT civic; BWL_PRE_PACKED_STRUCT struct { uint8 subject; uint8 siu; /* service interval units */ uint16 si; /* service interval */ - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT locid; BWL_PRE_PACKED_STRUCT struct { uint16 max_init_delay; /* maximum random initial delay */ uint8 min_ap_count; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT ftm_range; } BWL_POST_PACKED_STRUCT req; } BWL_POST_PACKED_STRUCT; @@ -779,7 +623,7 @@ typedef struct dot11_meas_req_loc dot11_meas_req_loc_t; BWL_PRE_PACKED_STRUCT struct dot11_lci_subelement { uint8 subelement; uint8 length; - uint8 lci_data[1]; + uint8 lci_data[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT; typedef struct dot11_lci_subelement dot11_lci_subelement_t; @@ -787,7 +631,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_colocated_bssid_list_se { uint8 sub_id; uint8 length; uint8 max_bssid_ind; /* MaxBSSID Indicator */ - struct ether_addr bssid[1]; /* variable */ + struct ether_addr bssid[BCM_FLEX_ARRAY]; /* variable */ } BWL_POST_PACKED_STRUCT; typedef struct dot11_colocated_bssid_list_se dot11_colocated_bssid_list_se_t; #define DOT11_LCI_COLOCATED_BSSID_LIST_FIXED_LEN 3 @@ -797,7 +641,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_civic_subelement { uint8 type; /* type of civic location */ uint8 subelement; uint8 length; - uint8 civic_data[1]; + uint8 civic_data[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT; typedef struct dot11_civic_subelement dot11_civic_subelement_t; @@ -836,6 +680,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_meas_rep { uint8 entry_count; uint8 data[1]; } BWL_POST_PACKED_STRUCT ftm_range; + /* Flexible arrays like data[] not allowed in unions */ uint8 data[1]; } BWL_POST_PACKED_STRUCT rep; } BWL_POST_PACKED_STRUCT; @@ -880,20 +725,10 @@ BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs { uint8 len; uint8 eaddr[ETHER_ADDR_LEN]; uint8 interval; - chan_map_tuple_t map[1]; + chan_map_tuple_t map[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT; typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; -/* WME Elements */ -#define WME_OUI "\x00\x50\xf2" /* WME OUI */ -#define WME_OUI_LEN 3 -#define WME_OUI_TYPE 2 /* WME type */ -#define WME_TYPE 2 /* WME type, deprecated */ -#define WME_SUBTYPE_IE 0 /* Information Element */ -#define WME_SUBTYPE_PARAM_IE 1 /* Parameter Element */ -#define WME_SUBTYPE_TSPEC 2 /* Traffic Specification */ -#define WME_VER 1 /* WME version */ - /* WME Access Category Indices (ACIs) */ #define AC_BE 0 /* Best Effort */ #define AC_BK 1 /* Background */ @@ -910,24 +745,10 @@ typedef uint8 ac_bitmap_t; /* AC bitmap of (1 << AC_xx) */ #define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac)))) /* Management PKT Lifetime indices */ -/* Removing flag checks 'WLTEST' - * while merging MERGE BIS120RC4 to DINGO2 - */ #define MGMT_ALL 0xffff #define MGMT_AUTH_LT FC_SUBTYPE_AUTH #define MGMT_ASSOC_LT FC_SUBTYPE_ASSOC_REQ -/** WME Information Element (IE) */ -BWL_PRE_PACKED_STRUCT struct wme_ie { - uint8 oui[3]; - uint8 type; - uint8 subtype; - uint8 version; - uint8 qosinfo; -} BWL_POST_PACKED_STRUCT; -typedef struct wme_ie wme_ie_t; -#define WME_IE_LEN 7 /* WME IE length */ - BWL_PRE_PACKED_STRUCT struct edcf_acparam { uint8 ACI; uint8 ECW; @@ -935,39 +756,6 @@ BWL_PRE_PACKED_STRUCT struct edcf_acparam { } BWL_POST_PACKED_STRUCT; typedef struct edcf_acparam edcf_acparam_t; -/** WME Parameter Element (PE) */ -BWL_PRE_PACKED_STRUCT struct wme_param_ie { - uint8 oui[3]; - uint8 type; - uint8 subtype; - uint8 version; - uint8 qosinfo; - uint8 rsvd; - edcf_acparam_t acparam[AC_COUNT]; -} BWL_POST_PACKED_STRUCT; -typedef struct wme_param_ie wme_param_ie_t; -#define WME_PARAM_IE_LEN 24 /* WME Parameter IE length */ - -/* QoS Info field for IE as sent from AP */ -#define WME_QI_AP_APSD_MASK 0x80 /* U-APSD Supported mask */ -#define WME_QI_AP_APSD_SHIFT 7 /* U-APSD Supported shift */ -#define WME_QI_AP_COUNT_MASK 0x0f /* Parameter set count mask */ -#define WME_QI_AP_COUNT_SHIFT 0 /* Parameter set count shift */ - -/* QoS Info field for IE as sent from STA */ -#define WME_QI_STA_MAXSPLEN_MASK 0x60 /* Max Service Period Length mask */ -#define WME_QI_STA_MAXSPLEN_SHIFT 5 /* Max Service Period Length shift */ -#define WME_QI_STA_APSD_ALL_MASK 0xf /* APSD all AC bits mask */ -#define WME_QI_STA_APSD_ALL_SHIFT 0 /* APSD all AC bits shift */ -#define WME_QI_STA_APSD_BE_MASK 0x8 /* APSD AC_BE mask */ -#define WME_QI_STA_APSD_BE_SHIFT 3 /* APSD AC_BE shift */ -#define WME_QI_STA_APSD_BK_MASK 0x4 /* APSD AC_BK mask */ -#define WME_QI_STA_APSD_BK_SHIFT 2 /* APSD AC_BK shift */ -#define WME_QI_STA_APSD_VI_MASK 0x2 /* APSD AC_VI mask */ -#define WME_QI_STA_APSD_VI_SHIFT 1 /* APSD AC_VI shift */ -#define WME_QI_STA_APSD_VO_MASK 0x1 /* APSD AC_VO mask */ -#define WME_QI_STA_APSD_VO_SHIFT 0 /* APSD AC_VO shift */ - /* ACI */ #define EDCF_AIFSN_MIN 1 /* AIFSN minimum value */ #define EDCF_AIFSN_MAX 15 /* AIFSN maximum value */ @@ -990,9 +778,6 @@ typedef struct wme_param_ie wme_param_ie_t; #define EDCF_TXOP_MAX 65535 /* TXOP maximum value */ #define EDCF_TXOP2USEC(txop) ((txop) << 5) -/* Default BE ACI value for non-WME connection STA */ -#define NON_EDCF_AC_BE_ACI_STA 0x02 - /* Default EDCF parameters that AP advertises for STA to use; WMM draft Table 12 */ #define EDCF_AC_BE_ACI_STA 0x03 /* STA ACI value for best effort AC */ #define EDCF_AC_BE_ECW_STA 0xA4 /* STA ECW value for best effort AC */ @@ -1095,50 +880,10 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification { uint8 action; uint8 token; uint8 status; - uint8 data[1]; /* Elements */ + uint8 data[BCM_FLEX_ARRAY]; /* Elements */ } BWL_POST_PACKED_STRUCT; #define DOT11_MGMT_NOTIFICATION_LEN 4 /* Fixed length */ -/** Timeout Interval IE */ -BWL_PRE_PACKED_STRUCT struct ti_ie { - uint8 ti_type; - uint32 ti_val; -} BWL_POST_PACKED_STRUCT; -typedef struct ti_ie ti_ie_t; -#define TI_TYPE_REASSOC_DEADLINE 1 -#define TI_TYPE_KEY_LIFETIME 2 - -#ifndef CISCO_AIRONET_OUI -#define CISCO_AIRONET_OUI "\x00\x40\x96" /* Cisco AIRONET OUI */ -#endif -/* QoS FastLane IE. */ -BWL_PRE_PACKED_STRUCT struct ccx_qfl_ie { - uint8 id; /* 221, DOT11_MNG_VS_ID */ - uint8 length; /* 5 */ - uint8 oui[3]; /* 00:40:96 */ - uint8 type; /* 11 */ - uint8 data; -} BWL_POST_PACKED_STRUCT; -typedef struct ccx_qfl_ie ccx_qfl_ie_t; -#define CCX_QFL_IE_TYPE 11 -#define CCX_QFL_ENABLE_SHIFT 5 -#define CCX_QFL_ENALBE (1 << CCX_QFL_ENABLE_SHIFT) - -/* WME Action Codes */ -#define WME_ADDTS_REQUEST 0 /* WME ADDTS request */ -#define WME_ADDTS_RESPONSE 1 /* WME ADDTS response */ -#define WME_DELTS_REQUEST 2 /* WME DELTS request */ - -/* WME Setup Response Status Codes */ -#define WME_ADMISSION_ACCEPTED 0 /* WME admission accepted */ -#define WME_INVALID_PARAMETERS 1 /* WME invalide parameters */ -#define WME_ADMISSION_REFUSED 3 /* WME admission refused */ - -/* Macro to take a pointer to a beacon or probe response - * body and return the char* pointer to the SSID info element - */ -#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN) - /* Authentication frame payload constants */ #define DOT11_OPEN_SYSTEM 0 /* d11 open authentication */ #define DOT11_SHARED_KEY 1 /* d11 shared authentication */ @@ -1147,7 +892,8 @@ typedef struct ccx_qfl_ie ccx_qfl_ie_t; #define DOT11_FILS_SKEY 4 /* d11 fils shared key authentication w/o pfs */ #define DOT11_FILS_SKEY_PFS 5 /* d11 fils shared key authentication w/ pfs */ #define DOT11_FILS_PKEY 6 /* d11 fils public key authentication */ -#define DOT11_MAX_AUTH_ALG DOT11_FILS_PKEY /* maximum value of an auth alg */ +#define DOT11_PASN 7 /* Pre association security negotiation */ +#define DOT11_MAX_AUTH_ALG DOT11_PASN /* maximum value of an auth alg */ #define DOT11_CHALLENGE_LEN 128 /* d11 challenge text length */ /* Frame control macros */ @@ -1185,6 +931,7 @@ typedef struct ccx_qfl_ie ccx_qfl_ie_t; #define FC_TYPE_MNG 0 /* management type */ #define FC_TYPE_CTL 1 /* control type */ #define FC_TYPE_DATA 2 /* data type */ +#define FC_TYPE_EXT 3 /* extension type */ /* Management Subtypes */ #define FC_SUBTYPE_ASSOC_REQ 0 /* assoc. request */ @@ -1335,9 +1082,9 @@ typedef struct ccx_qfl_ie ccx_qfl_ie_t; #define DOT11_MNG_TIMESTAMP_LEN 8 /* d11 management timestamp length */ /* DUR/ID field in assoc resp is 0xc000 | AID */ -#define DOT11_AID_MASK 0x3fff /* d11 AID mask */ -#define DOT11_AID_OCTET_VAL_SHIFT 3u /* AID octet value shift */ -#define DOT11_AID_BIT_POS_IN_OCTET 0x07 /* AID bit position in octet */ +#define DOT11_AID_MASK 0x3fff /* d11 AID mask */ +#define DOT11_AID_OCTET_VAL_SHIFT 3u /* AID octet value shift */ +#define DOT11_AID_BIT_POS_IN_OCTET 0x07 /* AID bit position in octet */ /* Reason Codes */ #define DOT11_RC_RESERVED 0 /* d11 RC reserved */ @@ -1365,11 +1112,14 @@ typedef struct ccx_qfl_ie ccx_qfl_ie_t; #define DOT11_RC_BAD_PC 10 /* Unacceptable power capability element */ #define DOT11_RC_BAD_CHANNELS 11 /* Unacceptable supported channels element */ -/* 12 is unused by STA but could be used by AP/GO */ +/* 12 is unused by STA but could be used by AP */ #define DOT11_RC_DISASSOC_BTM 12 /* Disassociated due to BSS Transition Magmt */ /* 13-23 are WPA/802.11i reason codes defined in wpa.h */ +#define DOT11_RC_TDLS_PEER_UNREACH 25 +#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26 + /* 32-39 are QSTA specific reasons added in 11e */ #define DOT11_RC_UNSPECIFIED_QOS 32 /* unspecified QoS-related reason */ #define DOT11_RC_INSUFFCIENT_BW 33 /* QAP lacks sufficient bandwidth */ @@ -1380,6 +1130,11 @@ typedef struct ccx_qfl_ie ccx_qfl_ie_t; #define DOT11_RC_SETUP_NEEDED 38 /* mechanism needs a setup */ #define DOT11_RC_TIMEOUT 39 /* timeout */ +#define DOT11_RC_INVALID_FT_ACTION_FC 48 /* Invalid FT Action frame count */ +#define DOT11_RC_INVALID_PMKID 49 /* Invalid PMKID */ +#define DOT11_RC_INVALID_MDE 50 /* Invalid MDE */ +#define DOT11_RC_INVALID_FTE 51 /* Invalid FTE */ + #define DOT11_RC_MESH_PEERING_CANCELLED 52 #define DOT11_RC_MESH_MAX_PEERS 53 #define DOT11_RC_MESH_CONFIG_POLICY_VIOLN 54 @@ -1397,18 +1152,16 @@ typedef struct ccx_qfl_ie ccx_qfl_ie_t; #define DOT11_RC_MESH_CHANSWITCH_REGREQ 65 #define DOT11_RC_MESH_CHANSWITCH_UNSPEC 66 -#define DOT11_RC_POOR_RSSI_CONDITIONS 71 /* Poor RSSI */ +#define DOT11_RC_POOR_RSSI_CONDITIONS 71 /* Poor RSSI */ #define DOT11_RC_MAX 71 /* Reason codes > 71 are reserved */ -#define DOT11_RC_TDLS_PEER_UNREACH 25 -#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26 - /* Status Codes */ #define DOT11_SC_SUCCESS 0 /* Successful */ #define DOT11_SC_FAILURE 1 /* Unspecified failure */ -#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 /* TDLS wakeup schedule rejected but alternative */ - /* schedule provided */ -#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 /* TDLS wakeup schedule rejected */ +#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 /* TDLS wakeup schedule rejected but + * alternative schedule provided + */ +#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 /* TDLS wakeup schedule rejected */ #define DOT11_SC_TDLS_SEC_DISABLED 5 /* TDLS Security disabled */ #define DOT11_SC_LIFETIME_REJ 6 /* Unacceptable lifetime */ #define DOT11_SC_NOT_SAME_BSS 7 /* Not in same BSS */ @@ -1458,9 +1211,9 @@ typedef struct ccx_qfl_ie ccx_qfl_ie_t; * station not supporting the Channel * Agility option */ -#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 /* Association denied because Spectrum - * Management capability is required. - */ +#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 /* Association denied because Spectrum + * Management capability is required. + */ #define DOT11_SC_ASSOC_BAD_POWER_CAP 23 /* Association denied because the info * in the Power Cap element is * unacceptable. @@ -1469,10 +1222,10 @@ typedef struct ccx_qfl_ie ccx_qfl_ie_t; * in the Supported Channel element is * unacceptable */ -#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 /* Association denied due to requesting - * station not supporting the Short Slot - * Time option - */ +#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 /* Association denied due to requesting + * station not supporting the Short Slot + * Time option + */ #define DOT11_SC_ASSOC_DSSSOFDM_REQUIRED 26 /* Association denied because requesting station * does not support the DSSS-OFDM option */ @@ -1491,40 +1244,55 @@ typedef struct ccx_qfl_ie ccx_qfl_ie_t; #define DOT11_SC_POOR_RSSI_CONDN 34 /* Association denied due to poor RSSI */ #define DOT11_SC_DECLINED 37 /* request declined */ #define DOT11_SC_INVALID_PARAMS 38 /* One or more params have invalid values */ -#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 /* invalid pairwise cipher */ + +/* The allocation or TS has not been created because the request cannot be honored; + * however, a suggested TSPEC/DMG TSPEC is provided so that the initiating STA can attempt + * to set another allocation or TS with the suggested changes to the TSPEC/DMG TSPEC. + */ +#define DOT11_SC_REJECTED_WITH_SUGGESTED_CHANGES 39 + +#define DOT11_SC_INVALID_GROUP_CIPHER 41 /* invalid pairwise cipher */ +#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 /* invalid pairwise cipher */ #define DOT11_SC_INVALID_AKMP 43 /* Association denied due to invalid AKMP */ +#define DOT11_SC_UNSUPPORTED_RSNE_VERSION 44 /* Unsupported RSNE version. */ #define DOT11_SC_INVALID_RSNIE_CAP 45 /* invalid RSN IE capabilities */ #define DOT11_SC_DLS_NOT_ALLOWED 48 /* DLS is not allowed in the BSS by policy */ #define DOT11_SC_INVALID_PMKID 53 /* Association denied due to invalid PMKID */ #define DOT11_SC_INVALID_MDID 54 /* Association denied due to invalid MDID */ #define DOT11_SC_INVALID_FTIE 55 /* Association denied due to invalid FTIE */ -#define DOT11_SC_ADV_PROTO_NOT_SUPPORTED 59 /* ad proto not supported */ -#define DOT11_SC_NO_OUTSTAND_REQ 60 /* no outstanding req */ -#define DOT11_SC_RSP_NOT_RX_FROM_SERVER 61 /* no response from server */ -#define DOT11_SC_TIMEOUT 62 /* timeout */ -#define DOT11_SC_QUERY_RSP_TOO_LARGE 63 /* query rsp too large */ -#define DOT11_SC_SERVER_UNREACHABLE 65 /* server unreachable */ +/* Requested TCLAS processing is not supported by the AP or PCP. */ +#define DOT11_SC_REQUESTED_TCLAS_NOT_SUPPORTED_BY_AP 56u -#define DOT11_SC_UNEXP_MSG 70 /* Unexpected message */ +/* The AP or PCP has insufficient TCLAS processing resources to satisfy the request. */ +#define DOT11_SC_INSUFFICIENT_TCLAS_PROCESSING_RESOURCES 57u + +#define DOT11_SC_ADV_PROTO_NOT_SUPPORTED 59 /* ad proto not supported */ +#define DOT11_SC_NO_OUTSTAND_REQ 60 /* no outstanding req */ +#define DOT11_SC_RSP_NOT_RX_FROM_SERVER 61 /* no response from server */ +#define DOT11_SC_TIMEOUT 62 /* timeout */ +#define DOT11_SC_QUERY_RSP_TOO_LARGE 63 /* query rsp too large */ +#define DOT11_SC_SERVER_UNREACHABLE 65 /* server unreachable */ + +#define DOT11_SC_UNEXP_MSG 70 /* Unexpected message */ #define DOT11_SC_INVALID_SNONCE 71 /* Invalid SNonce */ #define DOT11_SC_INVALID_RSNIE 72 /* Invalid contents of RSNIE */ -#define DOT11_SC_ANTICLOG_TOCKEN_REQUIRED 76 /* Anti-clogging tocken required */ -#define DOT11_SC_INVALID_FINITE_CYCLIC_GRP 77 /* Invalid contents of RSNIE */ -#define DOT11_SC_TRANSMIT_FAILURE 79 /* transmission failure */ +#define DOT11_SC_ANTICLOG_TOCKEN_REQUIRED 76 /* Anti-clogging tocken required */ +#define DOT11_SC_INVALID_FINITE_CYCLIC_GRP 77 /* Invalid contents of RSNIE */ +#define DOT11_SC_TRANSMIT_FAILURE 79 /* transmission failure */ +#define DOT11_SC_REQUESTED_TCLAS_NOT_SUPPORTED 80u /* Requested TCLAS not supported */ #define DOT11_SC_TCLAS_RESOURCES_EXHAUSTED 81u /* TCLAS resources exhausted */ +#define DOT11_SC_TCLAS_PROCESSING_TERMINATED 97u /* End traffic classification */ -#define DOT11_SC_TCLAS_PROCESSING_TERMINATED 97 /* End traffic classification */ +#define DOT11_SC_ASSOC_VHT_REQUIRED 104 /* Association denied because the requesting + * station does not support VHT features. + */ +#define DOT11_SC_UNKNOWN_PASSWORD_IDENTIFIER 123u /* mismatch of password id */ -#define DOT11_SC_ASSOC_VHT_REQUIRED 104 /* Association denied because the requesting - * station does not support VHT features. - */ -#define DOT11_SC_UNKNOWN_PASSWORD_IDENTIFIER 123u /* mismatch of password id */ - -#define DOT11_SC_SAE_HASH_TO_ELEMENT 126u /* SAE Hash-to-element PWE required */ -#define DOT11_SC_SAE_PK 127u /* SAE PK required */ +#define DOT11_SC_SAE_HASH_TO_ELEMENT 126u /* SAE Hash-to-element PWE required */ +#define DOT11_SC_SAE_PK 127u /* SAE PK required */ /* Requested TCLAS processing has been terminated by the AP due to insufficient QoS capacity. */ #define DOT11_SC_TCLAS_PROCESSING_TERMINATED_INSUFFICIENT_QOS 128u @@ -1534,6 +1302,38 @@ typedef struct ccx_qfl_ie ccx_qfl_ie_t; */ #define DOT11_SC_TCLAS_PROCESSING_TERMINATED_POLICY_CONFLICT 129u +#define DOT11_SC_INVALID_PUBLIC_KEY 130u /* Public key format is invalid */ +#define DOT11_SC_PASN_BASE_AKM_FAILED 131u /* Failure from Base AKM processing during PASN */ +#define DOT11_SC_OCI_MISMATCH 132u /* OCI does not match received */ + +/* Draft P802.11be D1.4 Table 9-78 Status codes */ +/* DENIED_STA_AFFILIATED_WITH_MLD_WITH_EXISTING_MLD_ASSOCIATION + * Association denied because the requesting STA is affiliated with a non-AP MLD + * that is associated with the AP MLD. + */ +#define DOT11_SC_DENIED_EXIST_MLD_ASSOC 130u +/* EPCS_DENIED_UNAUTHO- RIZED + * EPCS priority access denied because the non-AP MLD or non-AP EHT STA is not authorized + * to use the service. + */ +#define DOT11_SC_EPCS_DENIED_UNAUTH 131u +/* EPCS_DENIED- _OTHER_REASON + * EPCS priority access denied due to reason out- side the scope of this standard. + */ +#define DOT11_SC_EPCS_DENIED_O_REASON 132u +/* DENIED_TID_TO_LINK_MAPPING + * Request denied because the requested TID-to-link map- ping is unacceptable. + */ +#define DOT11_SC_DENIED_TID_MAP 133u +/* PREFERRED_TID_TO_LINK_MAP- PING_SUGGESTED + * Preferred TID-to-link mapping suggested. + */ +#define DOT11_SC_PREFER_TID_MAP 134u +/* DENIED_EHT_NOT_SUPPORTED + * Association denied because the requesting STA does not support EHT features. + */ +#define DOT11_SC_DENIED_EHT_UNSUPPORTED 135u /* TBD */ + /* Info Elts, length of INFORMATION portion of Info Elts */ #define DOT11_MNG_DS_PARAM_LEN 1 /* d11 management DS parameter length */ #define DOT11_MNG_IBSS_PARAM_LEN 2 /* d11 management IBSS parameter length */ @@ -1603,6 +1403,7 @@ enum dot11_tag_ids { DOT11_MNG_FTIE_ID = 55, /* 11r Fast Bss Transition id */ DOT11_MNG_FT_TI_ID = 56, /* 11r Timeout Interval id */ DOT11_MNG_RDE_ID = 57, /* 11r RIC Data Element id */ + DOT11_MNG_DSE_LOC_ID = 58, /* ?? DSE Registered Location */ DOT11_MNG_REGCLASS_ID = 59, /* d11 management regulatory class id */ DOT11_MNG_EXT_CSA_ID = 60, /* d11 Extended CSA */ DOT11_MNG_HT_ADD = 61, /* d11 mgmt additional HT info */ @@ -1622,10 +1423,12 @@ enum dot11_tag_ids { DOT11_MNG_HT_OBSS_ID = 74, /* d11 mgmt OBSS HT info */ DOT11_MNG_MMIE_ID = 76, /* d11 mgmt MIC IE */ DOT11_MNG_NONTRANS_BSSID_CAP_ID = 83, /* 11k nontransmitted BSSID capability */ + DOT11_MNG_SSID_LIST_ID = 84, /* ?? SSID list */ DOT11_MNG_MULTIPLE_BSSIDINDEX_ID = 85, /* 11k multiple BSSID index */ DOT11_MNG_FMS_DESCR_ID = 86, /* 11v FMS descriptor */ DOT11_MNG_FMS_REQ_ID = 87, /* 11v FMS request id */ DOT11_MNG_FMS_RESP_ID = 88, /* 11v FMS response id */ + DOT11_MNG_QOS_TRF_CAP_ID = 89, /* ?? QoS Traffic Capabilities */ DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID = 90, /* 11v bss max idle id */ DOT11_MNG_TFS_REQUEST_ID = 91, /* 11v tfs request id */ DOT11_MNG_TFS_RESPONSE_ID = 92, /* 11v tfs response id */ @@ -1654,6 +1457,12 @@ enum dot11_tag_ids { DOT11_MNG_EXT_PREQ_ID = 130, /* Mesh PREQ IE */ DOT11_MNG_EXT_PREP_ID = 131, /* Mesh PREP IE */ DOT11_MNG_EXT_PERR_ID = 132, /* Mesh PERR IE */ + DOT11_MNG_MIC_ID = 140, /* MIC IE */ + DOT11_MNG_MULTI_BAND_ID = 158, /* Multi-band IE */ + DOT11_MNG_ADDBA_EXT_ID = 159, /* ADDBA ext IE */ + DOT11_MNG_INTRA_AC_PRIO_ID = 184, /* Intra-Access Category Priority IE */ + DOT11_MNG_SCS_DESCR_ID = 185, /* SCS Descriptor IE */ + DOT11_MNG_GCR_GRPADDR_ID = 189, /* GCR group address IE */ DOT11_MNG_VHT_CAP_ID = 191, /* d11 mgmt VHT cap id */ DOT11_MNG_VHT_OPERATION_ID = 192, /* d11 mgmt VHT op id */ DOT11_MNG_EXT_BSSLOAD_ID = 193, /* d11 mgmt VHT extended bss load id */ @@ -1672,8 +1481,8 @@ enum dot11_tag_ids { DOT11_MNG_VS_ID = 221, /* d11 management Vendor Specific IE */ DOT11_MNG_MESH_CSP_ID = 222, /* d11 Mesh Channel Switch Parameter */ DOT11_MNG_FILS_IND_ID = 240, /* 11ai FILS Indication element */ - DOT11_MNG_FRAGMENT_ID = 242, /* IE's fragment ID */ - DOT11_MNG_RSNXE_ID = 244, /* RSN Extension Element (RSNXE) ID */ + DOT11_MNG_FRAGMENT_ID = 242, /* IE's fragment ID */ + DOT11_MNG_RSNXE_ID = 244, /* RSN Extension Element (RSNXE) ID */ /* The follwing ID extensions should be defined >= 255 * i.e. the values should include 255 (DOT11_MNG_ID_EXT_ID + ID Extension). @@ -1698,7 +1507,14 @@ enum dot11_tag_ids { #define FILS_EXTID_MNG_WRAPPED_DATA_ID 8u /* FILS Wrapped Data element */ #define DOT11_MNG_FILS_WRAPPED_DATA (DOT11_MNG_ID_EXT_ID + \ FILS_EXTID_MNG_WRAPPED_DATA_ID) +/* FILS wrapped data element is renamed to wrapped data element. + * The data will be used by FILS and PASN. + */ +#define EXTID_MNG_WRAPPED_DATA_ID FILS_EXTID_MNG_WRAPPED_DATA_ID +#define DOT11_MNG_WRAPPED_DATA DOT11_MNG_FILS_WRAPPED_DATA +#define EXT_MNG_EXT_REQ_ID 10u /* Extended Request element */ +#define DOT11_MNG_EXT_REQ_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_EXT_REQ_ID) #define OCE_EXTID_MNG_ESP_ID 11u /* Estimated Service Parameters element */ #define DOT11_MNG_ESP (DOT11_MNG_ID_EXT_ID + OCE_EXTID_MNG_ESP_ID) #define FILS_EXTID_MNG_PUBLIC_KEY_ID 12u /* FILS Public Key element */ @@ -1724,7 +1540,9 @@ enum dot11_tag_ids { #define EXT_MNG_BSSCOLOR_CHANGE_ID 42u /* BSS Color Change Announcement */ #define DOT11_MNG_BSSCOLOR_CHANGE_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_BSSCOLOR_CHANGE_ID) #define OCV_EXTID_MNG_OCI_ID 54u /* OCI element */ -#define DOT11_MNG_OCI_ID (DOT11_MNG_ID_EXT_ID + OCV_EXT_OCI_ID) +#define DOT11_MNG_OCI_ID (DOT11_MNG_ID_EXT_ID + OCV_EXTID_MNG_OCI_ID) +#define EXT_MNG_NON_INHERITANCE_ID 56u /* Non-Inheritance element */ +#define DOT11_MNG_NON_INHERITANCE_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_NON_INHERITANCE_ID) #define EXT_MNG_SHORT_SSID_ID 58u /* SHORT SSID ELEMENT */ #define DOT11_MNG_SHORT_SSID_LIST_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_SHORT_SSID_ID) #define EXT_MNG_HE_6G_CAP_ID 59u /* HE Extended Capabilities, 11ax */ @@ -1741,21 +1559,47 @@ enum dot11_tag_ids { #define SAE_EXT_ANTICLOG_TOKEN_CONTAINER_ID 93u /* SAE Anti-clogging token container */ #define DOT11_MNG_ANTICLOG_TOKEN_CONTAINER_ID (DOT11_MNG_ID_EXT_ID + \ SAE_EXT_ANTICLOG_TOKEN_CONTAINER_ID) -#define EXT_MNG_EHT_CAP_ID 100u /* EHT Capabilities IE FIXME */ -#define DOT11_MNG_EHT_CAP_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_EHT_CAP_ID) -#define EXT_MNG_EHT_OP_ID 101u /* EHT Operation IE # FIXME */ + +/* P802.11az/D2.5 Table 9-92 */ +#define EXT_MNG_SLTF_PARAMS_ID 94u /* Secure LTF Parameters */ +#define DOT11_MNG_SLTF_PARAMS_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_SLTF_PARAMS_ID) +#define EXT_MNG_ISTA_PASV_TB_RMR_ID 95u /* ISTA Passive TB Ranging Meas. Report */ +#define DOT11_MNG_ISTA_PASV_TB_RMR_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_ISTA_PASV_TB_RMR_ID) +#define EXT_MNG_RSTA_PASV_TB_RMR_ID 96u /* RSTA Passive TB Ranging Meas. Report */ +#define DOT11_MNG_RSTA_PASV_TB_RMR_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_RSTA_PASV_TB_RMR_ID) +#define EXT_MNG_PASV_TB_LCI_TABLE_ID 97u /* Passive TB Ranging LCI Table element */ +#define DOT11_MNG_PASV_TB_LCI_TABLE_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_PASV_TB_LCI_TABLE_ID) +#define EXT_MNG_ISTA_AVAIL_WINDOW_ID 98u /* ISTA Availablity Window */ +#define DOT11_MNG_ISTA_AVAIL_WINDOW_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_ISTA_AVAIL_WINDOW_ID) +#define EXT_MNG_RSTA_AVAIL_WINDOW_ID 99u /* RSTA Availablity Window */ +#define DOT11_MNG_RSTA_AVAIL_WINDOW_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_RSTA_AVAIL_WINDOW_ID) +#define EXT_MNG_PASN_PARAMS_ID 100u /* PASN Parameters */ +#define DOT11_MNG_PASN_PARAMS_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_PASN_PARAMS_ID) +#define EXT_MNG_RANGING_PARAMS_ID 101u /* Ranging Parameters */ +#define DOT11_MNG_RANGING_PARAMS_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_RANGING_PARAMS_ID) +#define EXT_MNG_DIR_MEAS_RESULTS_ID 102u /* Direction Measurement Results */ +#define DOT11_MNG_DIR_MEAS_RESULTS_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_DIR_MEAS_RESULTS_ID) +#define EXT_MNG_MULTI_AOD_FEEDBACK_ID 103u /* Multiple AOD Feedback */ +#define DOT11_MNG_MULTI_AOD_FEEDDBACK_ID (DOT11_MNG_ID_EXT_ID + \ + EXT_MNG_MULTI_AOD_FEEDBACK_ID) +#define EXT_MNG_MULTI_BEST_AWV_ID_ID 104u /* Multiple Best AWV ID */ +#define DOT11_MNG_MULTI_BEST_AWV_ID_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_MULTI_BEST_AWV_ID_ID) +#define EXT_MNG_LOS_LIKELIHOOD_ID 105u /* LOS Likelihood */ +#define DOT11_MNG_LOS_LIKELIHOOD_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_LOS_LIKELIHOOD_ID) +/* Draft P802.11be D1.2 Table 9-92 Element IDs */ +#define EXT_MNG_EHT_OP_ID 106u /* EHT Operation */ #define DOT11_MNG_EHT_OP_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_EHT_OP_ID) - -/* unassigned IDs for ranging parameter elements. To be updated after final - * assignement. - */ -#define DOT11_MNG_FTM_RANGING_EXT_ID 100u /* 11AZ sounding mode parameter element */ -#define DOT11_MNG_FTM_ISTA_AVAIL_EXT_ID 101u /* 11 AZ TN ISTA avaialability window */ -#define DOT11_MNG_FTM_RSTA_AVAIL_EXT_ID 102u /* 11 AZ TN RSTA avaialability window */ -#define DOT11_MNG_FTM_SECURE_LTF_EXT_ID 103u /* 11 AZ Secure LTF parameter element */ - -#define DOT11_FTM_NTB_SUB_ELT_ID 0u /* non-TB ranging parameter sub-element ID */ -#define DOT11_FTM_TB_SUB_ELT_ID 1u /* TB ranging parameter sub-element ID */ +#define EXT_MNG_ML_ID 107u /* Multi-Link */ +#define DOT11_MNG_ML_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_ML_ID) +#define EXT_MNG_EHT_CAP_ID 108u /* EHT Capabilities */ +#define DOT11_MNG_EHT_CAP_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_EHT_CAP_ID) +#define EXT_MNG_TID_MAP_ID 109u /* TID-To-Link Mapping */ +#define DOT11_MNG_TID_MAP_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_TID_MAP_ID) +#define EXT_MNG_ML_TRAFFIC_ID 110u /* Multi-Link Traffic */ +#define DOT11_MNG_ML_TRAFFIC_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_ML_TRAFFIC_ID) +/* P802.11be D1.6 Table 9-128 Element IDs */ +#define EXT_MNG_QOS_CHAR_ID 113u /* QoS Characteristics */ +#define DOT11_MNG_QOS_CHAR_ID (DOT11_MNG_ID_EXT_ID + EXT_MNG_QOS_CHAR_ID) /* deprecated definitions, do not use, to be deleted later */ #define FILS_HLP_CONTAINER_EXT_ID FILS_EXTID_MNG_HLP_CONTAINER_ID @@ -1768,7 +1612,7 @@ enum dot11_tag_ids { #define DOT11_MNG_IE_ID_EXT_MATCH(_ie, _id) (\ ((_ie)->id == DOT11_MNG_ID_EXT_ID) && \ ((_ie)->len > 0) && \ - ((_id) == ((uint8 *)(_ie) + TLV_HDR_LEN)[0])) + ((_id) == ((const uint8 *)(_ie) + TLV_HDR_LEN)[0])) #define DOT11_MNG_IE_ID_EXT_INIT(_ie, _id, _len) do {\ (_ie)->id = DOT11_MNG_ID_EXT_ID; \ @@ -1808,48 +1652,55 @@ enum dot11_tag_ids { #define DOT11_RATE_MASK 0x7F /* mask for numeric part of rate */ /* BSS Membership Selector parameters - * 802.11-2016 (and 802.11ax-D1.1), Sec 9.4.2.3 * These selector values are advertised in Supported Rates and Extended Supported Rates IEs * in the supported rates list with the Basic rate bit set. * Constants below include the basic bit. */ -#define DOT11_BSS_MEMBERSHIP_HT 0xFF /* Basic 0x80 + 127, HT Required to join */ -#define DOT11_BSS_MEMBERSHIP_VHT 0xFE /* Basic 0x80 + 126, VHT Required to join */ -#define DOT11_BSS_MEMBERSHIP_HE 0xFD /* Basic 0x80 + 125, HE Required to join */ -#define DOT11_BSS_SAE_HASH_TO_ELEMENT 123u /* SAE Hash-to-element Required to join */ +/* IEEE Std 802.11-2016 Table 9-78 BSS membership selector value encoding */ +#define DOT11_BSS_MEMBERSHIP_HT 0xFF /* Basic 0x80 + 127, HT Required to join */ +#define DOT11_BSS_MEMBERSHIP_VHT 0xFE /* Basic 0x80 + 126, VHT Required to join */ +/* IEEE P802.11-REVmd D5.0 Table 9-93 BSS membership selector value encoding */ +#define DOT11_BSS_MEMBERSHIP_GLK 0xFD /* Basic 0x80 + 125, GLK Op is required */ +#define DOT11_BSS_MEMBERSHIP_EPD 0xFC /* Basic 0x80 + 124, EPD is required */ +#define DOT11_BSS_SAE_HASH_TO_ELEMENT 0xFB /* Basic 0x80 + 123, SAE Hash-to-element */ +/* Draft P802.11ax D8.0 Table 9-93 BSS membership selector value encoding */ +#define DOT11_BSS_MEMBERSHIP_HE 0xFA /* Basic 0x80 + 122, HE Required to join */ +/* P802.11be D1.6 Table 9-129 BSS membership selector value encoding - TBD */ +#define DOT11_BSS_MEMBERSHIP_EHT 0xF9 /* Basic 0x80 + 121, EHT Required to join */ -/* ERP info element bit values */ -#define DOT11_MNG_ERP_LEN 1 /* ERP is currently 1 byte long */ -#define DOT11_MNG_NONERP_PRESENT 0x01 /* NonERP (802.11b) STAs are present - *in the BSS - */ -#define DOT11_MNG_USE_PROTECTION 0x02 /* Use protection mechanisms for - *ERP-OFDM frames - */ -#define DOT11_MNG_BARKER_PREAMBLE 0x04 /* Short Preambles: 0 == allowed, - * 1 == not allowed - */ /* TS Delay element offset & size */ #define DOT11_MGN_TS_DELAY_LEN 4 /* length of TS DELAY IE */ -#define TS_DELAY_FIELD_SIZE 4 /* TS DELAY field size */ +#define TS_DELAY_FIELD_SIZE 4 /* TS DELAY field size */ +/* ERP info element bit values */ +#define DOT11_MNG_ERP_LEN 1 /* ERP is currently 1 byte long */ +#define DOT11_MNG_NONERP_PRESENT 0x01 /* NonERP (802.11b) STAs are present + *in the BSS + */ +#define DOT11_MNG_USE_PROTECTION 0x02 /* Use protection mechanisms for + *ERP-OFDM frames + */ +#define DOT11_MNG_BARKER_PREAMBLE 0x04 /* Short Preambles: 0 == allowed, + * 1 == not allowed + */ /* Capability Information Field */ -#define DOT11_CAP_ESS 0x0001 /* d11 cap. ESS */ -#define DOT11_CAP_IBSS 0x0002 /* d11 cap. IBSS */ -#define DOT11_CAP_POLLABLE 0x0004 /* d11 cap. pollable */ -#define DOT11_CAP_POLL_RQ 0x0008 /* d11 cap. poll request */ -#define DOT11_CAP_PRIVACY 0x0010 /* d11 cap. privacy */ -#define DOT11_CAP_SHORT 0x0020 /* d11 cap. short */ -#define DOT11_CAP_PBCC 0x0040 /* d11 cap. PBCC */ -#define DOT11_CAP_AGILITY 0x0080 /* d11 cap. agility */ -#define DOT11_CAP_SPECTRUM 0x0100 /* d11 cap. spectrum */ -#define DOT11_CAP_QOS 0x0200 /* d11 cap. qos */ -#define DOT11_CAP_SHORTSLOT 0x0400 /* d11 cap. shortslot */ -#define DOT11_CAP_APSD 0x0800 /* d11 cap. apsd */ -#define DOT11_CAP_RRM 0x1000 /* d11 cap. 11k radio measurement */ -#define DOT11_CAP_CCK_OFDM 0x2000 /* d11 cap. CCK/OFDM */ -#define DOT11_CAP_DELAY_BA 0x4000 /* d11 cap. delayed block ack */ -#define DOT11_CAP_IMMEDIATE_BA 0x8000 /* d11 cap. immediate block ack */ +#define DOT11_CAP_ESS 0x0001 /* ESS */ +#define DOT11_CAP_IBSS 0x0002 /* IBSS */ +#define DOT11_CAP_POLLABLE 0x0004 /* pollable */ +#define DOT11_CAP_POLL_RQ 0x0008 /* poll request */ +#define DOT11_CAP_PRIVACY 0x0010 /* privacy */ +#define DOT11_CAP_SHORT 0x0020 /* short preamble */ +#define DOT11_CAP_PBCC 0x0040 /* reserved (IEEE Std 802.11-2016) */ +#define DOT11_CAP_CRITICAL_UPD 0x0040 /* critical update (Draft P802.11be D0.2) */ +#define DOT11_CAP_AGILITY 0x0080 /* reserved (IEEE Std 802.11-2016) */ +#define DOT11_CAP_SPECTRUM 0x0100 /* spectrum management */ +#define DOT11_CAP_QOS 0x0200 /* qos */ +#define DOT11_CAP_SHORTSLOT 0x0400 /* short slot time */ +#define DOT11_CAP_APSD 0x0800 /* apsd */ +#define DOT11_CAP_RRM 0x1000 /* radio measurement */ +#define DOT11_CAP_CCK_OFDM 0x2000 /* reserved (IEEE Std 802.11-2016) */ +#define DOT11_CAP_DELAY_BA 0x4000 /* delayed block ack */ +#define DOT11_CAP_IMMEDIATE_BA 0x8000 /* immediate block ack */ /* Extended capabilities IE bitfields */ /* 20/40 BSS Coexistence Management support bit position */ @@ -1889,8 +1740,15 @@ enum dot11_tag_ids { #define DOT11_EXT_CAP_IDENT_LOC 44u /* WNM notification */ #define DOT11_EXT_CAP_WNM_NOTIF 46u + +/* SCS (Stream Classification Service) support */ +#define DOT11_EXT_CAP_SCS 54u + /* Operating mode notification - VHT (11ac D3.0 - 8.4.2.29) */ #define DOT11_EXT_CAP_OPER_MODE_NOTIF 62u +/* Number of MSDU-per-AMSDU: 0:unlimited 1:32 2:16 3:8 */ +#define DOT11_EXT_CAP_MDSU_PER_AMSDU_LO 63u +#define DOT11_EXT_CAP_MDSU_PER_AMSDU_HI 64u /* Fine timing measurement - D3.0 */ #define DOT11_EXT_CAP_FTM_RESPONDER 70u #define DOT11_EXT_CAP_FTM_INITIATOR 71u /* tentative 11mcd3.0 */ @@ -1912,6 +1770,34 @@ enum dot11_tag_ids { /* Mirrored SCS (MSCS) support */ #define DOT11_EXT_CAP_MSCS 85u +/* Draft P802.11az/D2.5 - Table 9-153 Extended Capabilities field */ +#define DOT11_EXT_CAP_NTB_RANGING_RESPONDER 90u /* 11az NTB RSTA */ +#define DOT11_EXT_CAP_TB_RANGING_RESPONDER 91u /* 11az TB RSTA */ +#define DOT11_EXT_CAP_PSV_RANGING_RESPONDER 92u /* 11az Passive RSTA */ +#define DOT11_EXT_CAP_PSV_RANGING_INITIATOR 93u /* 11az Passive ISTA */ +#define DOT11_EXT_CAP_AOA_MEASUREMENT 94u /* AOA measurement available */ +#define DOT11_EXT_CAP_PHASE_SHIFT_FEEDBACK 95u /* Phase shift feedback support */ +#define DOT11_EXT_CAP_DMG_LOCATION_SUPPORT_AP 96u /* DMG/Location supporting APs in the area */ +#define DOT11_EXT_CAP_I2R_LMR_FEEDBACK_POLICY 97u /* I2R LMR Feedback policy (of RSTA) */ + +/* Last bit index of Extended Capabilities defined in P802.11 + * Please update DOT11_EXT_CAP_LAST_BIT_IDX to the last bit when P802.11 introduces new bit + */ +#define DOT11_EXT_CAP_LAST_BIT_IDX DOT11_EXT_CAP_I2R_LMR_FEEDBACK_POLICY /* update this */ +#define DOT11_EXT_CAP_NUM_BITS_MAX (DOT11_EXT_CAP_LAST_BIT_IDX + 1) /* last bit index + 1 */ + +/* Please use DOT11_EXT_CAP_BYTE_LEN_MAX for any of ext cap buffer size ONLY in ATTACH time. + * Othewise, change of DOT11_EXT_CAP_BYTE_LEN_MAX cause ROM invalidation. + * DOT11_EXT_CAP_BYTE_LEN_MAX can grow with 802.11 change. + */ +#define DOT11_EXT_CAP_BYTE_LEN_MAX ((DOT11_EXT_CAP_NUM_BITS_MAX + 7) >> 3) /* byte len */ + +/******************************************************************** + * DO NOT use following macros for Trunk/PUMA and later branch + * DOT11_EXT_CAP_MAX_IDX, DOT11_EXT_CAP_MAX_BIT_IDX, + * DOT11_EXTCAP_LEN_MAX and dot11_extcap_t will be cleaned up + */ + /* TODO: Update DOT11_EXT_CAP_MAX_IDX to reflect the highest offset. * Note: DOT11_EXT_CAP_MAX_IDX must only be used in attach path. * It will cause ROM invalidation otherwise. @@ -1934,114 +1820,6 @@ BWL_PRE_PACKED_STRUCT struct dot11_extcap { } BWL_POST_PACKED_STRUCT; typedef struct dot11_extcap dot11_extcap_t; -/* VHT Operating mode bit fields - (11ac D8.0/802.11-2016 - 9.4.1.53) */ -#define DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT 0 -#define DOT11_OPER_MODE_CHANNEL_WIDTH_MASK 0x3 -#define DOT11_OPER_MODE_160_8080_BW_SHIFT 2 -#define DOT11_OPER_MODE_160_8080_BW_MASK 0x04 -#define DOT11_OPER_MODE_NOLDPC_SHIFT 3 -#define DOT11_OPER_MODE_NOLDPC_MASK 0x08 -#define DOT11_OPER_MODE_RXNSS_SHIFT 4 -#define DOT11_OPER_MODE_RXNSS_MASK 0x70 -#define DOT11_OPER_MODE_RXNSS_TYPE_SHIFT 7 -#define DOT11_OPER_MODE_RXNSS_TYPE_MASK 0x80 - -#define DOT11_OPER_MODE_RESET_CHAN_WIDTH_160MHZ(oper_mode) \ - (oper_mode & (~(DOT11_OPER_MODE_CHANNEL_WIDTH_MASK | \ - DOT11_OPER_MODE_160_8080_BW_MASK))) -#define DOT11_OPER_MODE_SET_CHAN_WIDTH_160MHZ(oper_mode) \ - (oper_mode = (DOT11_OPER_MODE_RESET_CHAN_WIDTH_160MHZ(oper_mode) | \ - (DOT11_OPER_MODE_80MHZ | DOT11_OPER_MODE_160_8080_BW_MASK))) - -#ifdef DOT11_OPER_MODE_LEFT_SHIFT_FIX - -#define DOT11_OPER_MODE(type, nss, chanw) (\ - ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ - DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ - (((nss) - 1u) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ - ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ - DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) - -#define DOT11_D8_OPER_MODE(type, nss, ldpc, bw160_8080, chanw) (\ - ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ - DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ - (((nss) - 1u) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ - ((ldpc) << DOT11_OPER_MODE_NOLDPC_SHIFT & DOT11_OPER_MODE_NOLDPC_MASK) |\ - ((bw160_8080) << DOT11_OPER_MODE_160_8080_BW_SHIFT &\ - DOT11_OPER_MODE_160_8080_BW_MASK) |\ - ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ - DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) - -#else - -/* avoid invalidation from above fix on release branches, can be removed when older release - * branches no longer use component/proto from trunk - */ - -#define DOT11_OPER_MODE(type, nss, chanw) (\ - ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ - DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ - (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ - ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ - DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) - -#define DOT11_D8_OPER_MODE(type, nss, ldpc, bw160_8080, chanw) (\ - ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ - DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ - (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ - ((ldpc) << DOT11_OPER_MODE_NOLDPC_SHIFT & DOT11_OPER_MODE_NOLDPC_MASK) |\ - ((bw160_8080) << DOT11_OPER_MODE_160_8080_BW_SHIFT &\ - DOT11_OPER_MODE_160_8080_BW_MASK) |\ - ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ - DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) - -#endif /* DOT11_OPER_MODE_LEFT_SHIFT_FIX */ - -#define DOT11_OPER_MODE_CHANNEL_WIDTH(mode) \ - (((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)\ - >> DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT) -#define DOT11_OPER_MODE_160_8080(mode) \ - (((mode) & DOT11_OPER_MODE_160_8080_BW_MASK)\ - >> DOT11_OPER_MODE_160_8080_BW_SHIFT) -#define DOT11_OPER_MODE_NOLDPC(mode) \ - (((mode) & DOT11_OPER_MODE_NOLDPC_MASK)\ - >> DOT11_OPER_MODE_NOLDPC_SHIFT) -#define DOT11_OPER_MODE_RXNSS(mode) \ - ((((mode) & DOT11_OPER_MODE_RXNSS_MASK) \ - >> DOT11_OPER_MODE_RXNSS_SHIFT) + 1) -#define DOT11_OPER_MODE_RXNSS_TYPE(mode) \ - (((mode) & DOT11_OPER_MODE_RXNSS_TYPE_MASK)\ - >> DOT11_OPER_MODE_RXNSS_TYPE_SHIFT) - -#define DOT11_OPER_MODE_20MHZ 0 -#define DOT11_OPER_MODE_40MHZ 1 -#define DOT11_OPER_MODE_80MHZ 2 -#define DOT11_OPER_MODE_160MHZ 3 -#define DOT11_OPER_MODE_8080MHZ 3 -#define DOT11_OPER_MODE_1608080MHZ 1 - -#define DOT11_OPER_MODE_CHANNEL_WIDTH_20MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_20MHZ) -#define DOT11_OPER_MODE_CHANNEL_WIDTH_40MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_40MHZ) -#define DOT11_OPER_MODE_CHANNEL_WIDTH_80MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_80MHZ) -#define DOT11_OPER_MODE_CHANNEL_WIDTH_160MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_160_8080_BW_MASK)) -#define DOT11_OPER_MODE_CHANNEL_WIDTH_8080MHZ(mode) (\ - ((mode) & DOT11_OPER_MODE_160_8080_BW_MASK)) - -/* Operating mode information element 802.11ac D3.0 - 8.4.2.168 */ -BWL_PRE_PACKED_STRUCT struct dot11_oper_mode_notif_ie { - uint8 mode; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; - -#define DOT11_OPER_MODE_NOTIF_IE_LEN 1 - -/* Extended Capability Information Field */ -#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01 /* 20/40 BSS Coexistence Management support */ - /* * Action Frame Constants */ @@ -2058,7 +1836,7 @@ typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; #define DOT11_ACTION_CAT_BLOCKACK 3 /* category block ack */ #define DOT11_ACTION_CAT_PUBLIC 4 /* category public */ #define DOT11_ACTION_CAT_RRM 5 /* category radio measurements */ -#define DOT11_ACTION_CAT_FBT 6 /* category fast bss transition */ +#define DOT11_ACTION_CAT_FBT 6 /* category fast bss transition */ #define DOT11_ACTION_CAT_HT 7 /* category for HT */ #define DOT11_ACTION_CAT_SA_QUERY 8 /* security association query */ #define DOT11_ACTION_CAT_PDPA 9 /* protected dual of public action */ @@ -2074,9 +1852,15 @@ typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; #define DOT11_ACTION_CAT_VHT 21 /* VHT action */ #define DOT11_ACTION_CAT_S1G 22 /* S1G action */ -/* FIXME: Use temp. ID until ANA assigns one */ -#define DOT11_ACTION_CAT_HE 27 /* HE action frame */ #define DOT11_ACTION_CAT_FILS 26 /* FILS action frame */ +/* HE Action frames - Draft P802.11ax D7.0 Table 9-53 Category values */ +#define DOT11_ACTION_CAT_HE 30 /* HE action frame */ +#define DOT11_ACTION_CAT_HEP 31 /* Protected HE action frame */ +/* Protected Fine Timing action frame - Draft P802.11az/D2.5 Table 9-51 Category values */ +#define DOT11_ACTION_CAT_PFT 34u /* Protected Fine Timing action frame */ +/* EHT Action frames - Draft P802.11be D1.2 Table 9-51 Category values */ +#define DOT11_ACTION_CAT_EHT 36u /* EHT action frame */ +#define DOT11_ACTION_CAT_EHTP 37u /* Protected EHT action frame */ #define DOT11_ACTION_CAT_VSP 126 /* protected vendor specific */ #define DOT11_ACTION_CAT_VS 127 /* category Vendor Specific */ @@ -2095,21 +1879,18 @@ typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; #define DOT11_QOS_ACTION_SCHEDULE 3 /* d11 action schedule */ #define DOT11_QOS_ACTION_QOS_MAP 4 /* d11 action QOS map */ -/* HT action ids */ -#define DOT11_ACTION_ID_HT_CH_WIDTH 0 /* notify channel width action id */ -#define DOT11_ACTION_ID_HT_MIMO_PS 1 /* mimo ps action id */ - /* Public action ids */ #define DOT11_PUB_ACTION_BSS_COEX_MNG 0 /* 20/40 Coexistence Management action id */ #define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ +#define DOT11_PUB_ACTION_MP 7 /* Measurement Pilot public action id */ #define DOT11_PUB_ACTION_VENDOR_SPEC 9 /* Vendor specific */ #define DOT11_PUB_ACTION_GAS_CB_REQ 12 /* GAS Comeback Request */ #define DOT11_PUB_ACTION_FTM_REQ 32 /* FTM request */ #define DOT11_PUB_ACTION_FTM 33 /* FTM measurement */ -/* unassigned value. Will change after final assignement. - * for now, use 34(same as FILS DISC) due to QT/TB/chipsim support from uCode - */ -#define DOT11_PUB_ACTION_FTM_LMR 34 /* FTM 11AZ Location Management Report */ +#define DOT11_PUB_ACTION_LMR 47 /* 11az Location Measurement Report */ +#define DOT11_PUB_ACTION_PSV_TB_RMR_ISTA 48 /* ISTA Passive TB Ranging Measurement Report */ +#define DOT11_PUB_ACTION_PSV_TB_RMR_RSTA_PRI 49 /* Primary RSTA Broadcast Passive TB RMR */ +#define DOT11_PUB_ACTION_PSV_TB_RMR_RSTA_2ND 50 /* Secondary RSTA Broadcast Passive TB RMR */ #define DOT11_PUB_ACTION_FTM_REQ_TRIGGER_START 1u /* FTM request start trigger */ #define DOT11_PUB_ACTION_FTM_REQ_TRIGGER_STOP 0u /* FTM request stop trigger */ @@ -2151,60 +1932,20 @@ typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; #define DOT11_RAV_MSCS_REQ 4 /* MSCS Request */ #define DOT11_RAV_MSCS_RES 5 /* MSCS Response */ -/* Wireless Network Management (WNM) action types */ -#define DOT11_WNM_ACTION_EVENT_REQ 0 -#define DOT11_WNM_ACTION_EVENT_REP 1 -#define DOT11_WNM_ACTION_DIAG_REQ 2 -#define DOT11_WNM_ACTION_DIAG_REP 3 -#define DOT11_WNM_ACTION_LOC_CFG_REQ 4 -#define DOT11_WNM_ACTION_LOC_RFG_RESP 5 -#define DOT11_WNM_ACTION_BSSTRANS_QUERY 6 -#define DOT11_WNM_ACTION_BSSTRANS_REQ 7 -#define DOT11_WNM_ACTION_BSSTRANS_RESP 8 -#define DOT11_WNM_ACTION_FMS_REQ 9 -#define DOT11_WNM_ACTION_FMS_RESP 10 -#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 -#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 -#define DOT11_WNM_ACTION_TFS_REQ 13 -#define DOT11_WNM_ACTION_TFS_RESP 14 -#define DOT11_WNM_ACTION_TFS_NOTIFY_REQ 15 -#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 -#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 -#define DOT11_WNM_ACTION_TIMBC_REQ 18 -#define DOT11_WNM_ACTION_TIMBC_RESP 19 -#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 -#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 -#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 -#define DOT11_WNM_ACTION_DMS_REQ 23 -#define DOT11_WNM_ACTION_DMS_RESP 24 -#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 -#define DOT11_WNM_ACTION_NOTFCTN_REQ 26 -#define DOT11_WNM_ACTION_NOTFCTN_RESP 27 -#define DOT11_WNM_ACTION_TFS_NOTIFY_RESP 28 - -/* Unprotected Wireless Network Management (WNM) action types */ -#define DOT11_UWNM_ACTION_TIM 0 -#define DOT11_UWNM_ACTION_TIMING_MEASUREMENT 1 - #define DOT11_MNG_COUNTRY_ID_LEN 3 -/* VHT category action types - 802.11ac D3.0 - 8.5.23.1 */ -#define DOT11_VHT_ACTION_CBF 0 /* Compressed Beamforming */ -#define DOT11_VHT_ACTION_GID_MGMT 1 /* Group ID Management */ -#define DOT11_VHT_ACTION_OPER_MODE_NOTIF 2 /* Operating mode notif'n */ - /* FILS category action types - 802.11ai D11.0 - 9.6.8.1 */ #define DOT11_FILS_ACTION_DISCOVERY 34 /* FILS Discovery */ /** DLS Request frame header */ BWL_PRE_PACKED_STRUCT struct dot11_dls_req { uint8 category; /* category of action frame (2) */ - uint8 action; /* DLS action: req (0) */ - struct ether_addr da; /* destination address */ - struct ether_addr sa; /* source address */ - uint16 cap; /* capability */ + uint8 action; /* DLS action: req (0) */ + struct ether_addr da; /* destination address */ + struct ether_addr sa; /* source address */ + uint16 cap; /* capability */ uint16 timeout; /* timeout value */ - uint8 data[1]; /* IE:support rate, extend support rate, HT cap */ + uint8 data[BCM_FLEX_ARRAY]; /* IE:support rate, extend support rate, HT cap */ } BWL_POST_PACKED_STRUCT; typedef struct dot11_dls_req dot11_dls_req_t; #define DOT11_DLS_REQ_LEN 18 /* Fixed length */ @@ -2212,156 +1953,15 @@ typedef struct dot11_dls_req dot11_dls_req_t; /** DLS response frame header */ BWL_PRE_PACKED_STRUCT struct dot11_dls_resp { uint8 category; /* category of action frame (2) */ - uint8 action; /* DLS action: req (0) */ - uint16 status; /* status code field */ - struct ether_addr da; /* destination address */ - struct ether_addr sa; /* source address */ - uint8 data[1]; /* optional: capability, rate ... */ + uint8 action; /* DLS action: req (0) */ + uint16 status; /* status code field */ + struct ether_addr da; /* destination address */ + struct ether_addr sa; /* source address */ + uint8 data[BCM_FLEX_ARRAY]; /* optional: capability, rate ... */ } BWL_POST_PACKED_STRUCT; typedef struct dot11_dls_resp dot11_dls_resp_t; #define DOT11_DLS_RESP_LEN 16 /* Fixed length */ -/* ************* 802.11v related definitions. ************* */ - -/** BSS Management Transition Query frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_query { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: trans_query (6) */ - uint8 token; /* dialog token */ - uint8 reason; /* transition query reason */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_bsstrans_query dot11_bsstrans_query_t; -#define DOT11_BSSTRANS_QUERY_LEN 4 /* Fixed length */ - -/* BTM transition reason */ -#define DOT11_BSSTRANS_REASON_UNSPECIFIED 0 -#define DOT11_BSSTRANS_REASON_EXC_FRAME_LOSS 1 -#define DOT11_BSSTRANS_REASON_EXC_TRAFFIC_DELAY 2 -#define DOT11_BSSTRANS_REASON_INSUFF_QOS_CAPACITY 3 -#define DOT11_BSSTRANS_REASON_FIRST_ASSOC 4 -#define DOT11_BSSTRANS_REASON_LOAD_BALANCING 5 -#define DOT11_BSSTRANS_REASON_BETTER_AP_FOUND 6 -#define DOT11_BSSTRANS_REASON_DEAUTH_RX 7 -#define DOT11_BSSTRANS_REASON_8021X_EAP_AUTH_FAIL 8 -#define DOT11_BSSTRANS_REASON_4WAY_HANDSHK_FAIL 9 -#define DOT11_BSSTRANS_REASON_MANY_REPLAYCNT_FAIL 10 -#define DOT11_BSSTRANS_REASON_MANY_DATAMIC_FAIL 11 -#define DOT11_BSSTRANS_REASON_EXCEED_MAX_RETRANS 12 -#define DOT11_BSSTRANS_REASON_MANY_BCAST_DISASSOC_RX 13 -#define DOT11_BSSTRANS_REASON_MANY_BCAST_DEAUTH_RX 14 -#define DOT11_BSSTRANS_REASON_PREV_TRANSITION_FAIL 15 -#define DOT11_BSSTRANS_REASON_LOW_RSSI 16 -#define DOT11_BSSTRANS_REASON_ROAM_FROM_NON_80211 17 -#define DOT11_BSSTRANS_REASON_RX_BTM_REQ 18 -#define DOT11_BSSTRANS_REASON_PREF_LIST_INCLUDED 19 -#define DOT11_BSSTRANS_REASON_LEAVING_ESS 20 - -/** BSS Management Transition Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: trans_req (7) */ - uint8 token; /* dialog token */ - uint8 reqmode; /* transition request mode */ - uint16 disassoc_tmr; /* disassociation timer */ - uint8 validity_intrvl; /* validity interval */ - uint8 data[1]; /* optional: BSS term duration, ... */ - /* ...session info URL, candidate list */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_bsstrans_req dot11_bsstrans_req_t; -#define DOT11_BSSTRANS_REQ_LEN 7 /* Fixed length */ -#define DOT11_BSSTRANS_REQ_FIXED_LEN 7u /* Fixed length */ - -/* BSS Mgmt Transition Request Mode Field - 802.11v */ -#define DOT11_BSSTRANS_REQMODE_PREF_LIST_INCL 0x01 -#define DOT11_BSSTRANS_REQMODE_ABRIDGED 0x02 -#define DOT11_BSSTRANS_REQMODE_DISASSOC_IMMINENT 0x04 -#define DOT11_BSSTRANS_REQMODE_BSS_TERM_INCL 0x08 -#define DOT11_BSSTRANS_REQMODE_ESS_DISASSOC_IMNT 0x10 - -/** BSS Management transition response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: trans_resp (8) */ - uint8 token; /* dialog token */ - uint8 status; /* transition status */ - uint8 term_delay; /* validity interval */ - uint8 data[1]; /* optional: BSSID target, candidate list */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_bsstrans_resp dot11_bsstrans_resp_t; -#define DOT11_BSSTRANS_RESP_LEN 5 /* Fixed length */ - -/* BSS Mgmt Transition Response Status Field */ -#define DOT11_BSSTRANS_RESP_STATUS_ACCEPT 0 -#define DOT11_BSSTRANS_RESP_STATUS_REJECT 1 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_BCN 2 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_CAP 3 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_UNDESIRED 4 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_DELAY_REQ 5 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_BSS_LIST_PROVIDED 6 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_NO_SUITABLE_BSS 7 -#define DOT11_BSSTRANS_RESP_STATUS_REJ_LEAVING_ESS 8 - -/** BSS Max Idle Period element */ -BWL_PRE_PACKED_STRUCT struct dot11_bss_max_idle_period_ie { - uint8 id; /* 90, DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID */ - uint8 len; - uint16 max_idle_period; /* in unit of 1000 TUs */ - uint8 idle_opt; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_bss_max_idle_period_ie dot11_bss_max_idle_period_ie_t; -#define DOT11_BSS_MAX_IDLE_PERIOD_IE_LEN 3 /* bss max idle period IE size */ -#define DOT11_BSS_MAX_IDLE_PERIOD_OPT_PROTECTED 1 /* BSS max idle option */ - -/** TIM Broadcast request element */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc_req_ie { - uint8 id; /* 94, DOT11_MNG_TIMBC_REQ_ID */ - uint8 len; - uint8 interval; /* in unit of beacon interval */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc_req_ie dot11_timbc_req_ie_t; -#define DOT11_TIMBC_REQ_IE_LEN 1 /* Fixed length */ - -/** TIM Broadcast request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: DOT11_WNM_ACTION_TIMBC_REQ(18) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* TIM broadcast request element */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc_req dot11_timbc_req_t; -#define DOT11_TIMBC_REQ_LEN 3 /* Fixed length */ - -/** TIM Broadcast response element */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp_ie { - uint8 id; /* 95, DOT11_MNG_TIM_BROADCAST_RESP_ID */ - uint8 len; - uint8 status; /* status of add request */ - uint8 interval; /* in unit of beacon interval */ - int32 offset; /* in unit of ms */ - uint16 high_rate; /* in unit of 0.5 Mb/s */ - uint16 low_rate; /* in unit of 0.5 Mb/s */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc_resp_ie dot11_timbc_resp_ie_t; -#define DOT11_TIMBC_DENY_RESP_IE_LEN 1 /* Deny. Fixed length */ -#define DOT11_TIMBC_ACCEPT_RESP_IE_LEN 10 /* Accept. Fixed length */ - -#define DOT11_TIMBC_STATUS_ACCEPT 0 -#define DOT11_TIMBC_STATUS_ACCEPT_TSTAMP 1 -#define DOT11_TIMBC_STATUS_DENY 2 -#define DOT11_TIMBC_STATUS_OVERRIDDEN 3 -#define DOT11_TIMBC_STATUS_RESERVED 4 - -/** TIM Broadcast request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* action: DOT11_WNM_ACTION_TIMBC_RESP(19) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* TIM broadcast response element */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc_resp dot11_timbc_resp_t; -#define DOT11_TIMBC_RESP_LEN 3 /* Fixed length */ - /** TIM element */ BWL_PRE_PACKED_STRUCT struct dot11_tim_ie { uint8 id; /* 5, DOT11_MNG_TIM_ID */ @@ -2369,182 +1969,24 @@ BWL_PRE_PACKED_STRUCT struct dot11_tim_ie { uint8 dtim_count; /* DTIM decrementing counter */ uint8 dtim_period; /* DTIM period */ uint8 bitmap_control; /* AID 0 + bitmap offset */ - uint8 pvb[1]; /* Partial Virtual Bitmap, variable length */ + uint8 pvb[BCM_FLEX_ARRAY]; /* Partial Virtual Bitmap, variable length */ } BWL_POST_PACKED_STRUCT; typedef struct dot11_tim_ie dot11_tim_ie_t; #define DOT11_TIM_IE_FIXED_LEN 3 /* Fixed length, without id and len */ #define DOT11_TIM_IE_FIXED_TOTAL_LEN 5 /* Fixed length, with id and len */ -/** TIM Broadcast frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_timbc { - uint8 category; /* category of action frame (11) */ - uint8 action; /* action: TIM (0) */ - uint8 check_beacon; /* need to check-beacon */ - uint8 tsf[8]; /* Time Synchronization Function */ - dot11_tim_ie_t tim_ie; /* TIM element */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_timbc dot11_timbc_t; -#define DOT11_TIMBC_HDR_LEN (sizeof(dot11_timbc_t) - sizeof(dot11_tim_ie_t)) -#define DOT11_TIMBC_FIXED_LEN (sizeof(dot11_timbc_t) - 1) /* Fixed length */ -#define DOT11_TIMBC_LEN 11 /* Fixed length */ - -/** TCLAS frame classifier type */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_hdr { - uint8 type; - uint8 mask; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_hdr dot11_tclas_fc_hdr_t; -#define DOT11_TCLAS_FC_HDR_LEN 2 /* Fixed length */ - -#define DOT11_TCLAS_MASK_0 0x1 -#define DOT11_TCLAS_MASK_1 0x2 -#define DOT11_TCLAS_MASK_2 0x4 -#define DOT11_TCLAS_MASK_3 0x8 -#define DOT11_TCLAS_MASK_4 0x10 -#define DOT11_TCLAS_MASK_5 0x20 -#define DOT11_TCLAS_MASK_6 0x40 -#define DOT11_TCLAS_MASK_7 0x80 - -#define DOT11_TCLAS_FC_0_ETH 0 -#define DOT11_TCLAS_FC_1_IP 1 -#define DOT11_TCLAS_FC_2_8021Q 2 -#define DOT11_TCLAS_FC_3_OFFSET 3 -#define DOT11_TCLAS_FC_4_IP_HIGHER 4 -#define DOT11_TCLAS_FC_5_8021D 5 - -/** TCLAS frame classifier type 0 parameters for Ethernet */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_0_eth { - uint8 type; - uint8 mask; - uint8 sa[ETHER_ADDR_LEN]; - uint8 da[ETHER_ADDR_LEN]; - uint16 eth_type; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_0_eth dot11_tclas_fc_0_eth_t; -#define DOT11_TCLAS_FC_0_ETH_LEN 16 - -/** TCLAS frame classifier type 1 parameters for IPV4 */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_1_ipv4 { - uint8 type; - uint8 mask; - uint8 version; - uint32 src_ip; - uint32 dst_ip; - uint16 src_port; - uint16 dst_port; - uint8 dscp; - uint8 protocol; - uint8 reserved; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_1_ipv4_t; -#define DOT11_TCLAS_FC_1_IPV4_LEN 18 - -/** TCLAS frame classifier type 2 parameters for 802.1Q */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_2_8021q { - uint8 type; - uint8 mask; - uint16 tci; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_2_8021q dot11_tclas_fc_2_8021q_t; -#define DOT11_TCLAS_FC_2_8021Q_LEN 4 - -/** TCLAS frame classifier type 3 parameters for filter offset */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_3_filter { - uint8 type; - uint8 mask; - uint16 offset; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_3_filter dot11_tclas_fc_3_filter_t; -#define DOT11_TCLAS_FC_3_FILTER_LEN 4 - -/** TCLAS frame classifier type 4 parameters for IPV4 is the same as TCLAS type 1 */ -typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_4_ipv4_t; -#define DOT11_TCLAS_FC_4_IPV4_LEN DOT11_TCLAS_FC_1_IPV4_LEN - -/** TCLAS frame classifier type 4 parameters for IPV6 */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_4_ipv6 { - uint8 type; - uint8 mask; - uint8 version; - uint8 saddr[16]; - uint8 daddr[16]; - uint16 src_port; - uint16 dst_port; - uint8 dscp; - uint8 nexthdr; - uint8 flow_lbl[3]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_4_ipv6 dot11_tclas_fc_4_ipv6_t; -#define DOT11_TCLAS_FC_4_IPV6_LEN 44 - -/** TCLAS frame classifier type 5 parameters for 802.1D */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_5_8021d { - uint8 type; - uint8 mask; - uint8 pcp; - uint8 cfi; - uint16 vid; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_fc_5_8021d dot11_tclas_fc_5_8021d_t; -#define DOT11_TCLAS_FC_5_8021D_LEN 6 - -/** TCLAS frame classifier type parameters */ -BWL_PRE_PACKED_STRUCT union dot11_tclas_fc { - uint8 data[1]; - dot11_tclas_fc_hdr_t hdr; - dot11_tclas_fc_0_eth_t t0_eth; - dot11_tclas_fc_1_ipv4_t t1_ipv4; - dot11_tclas_fc_2_8021q_t t2_8021q; - dot11_tclas_fc_3_filter_t t3_filter; - dot11_tclas_fc_4_ipv4_t t4_ipv4; - dot11_tclas_fc_4_ipv6_t t4_ipv6; - dot11_tclas_fc_5_8021d_t t5_8021d; -} BWL_POST_PACKED_STRUCT; -typedef union dot11_tclas_fc dot11_tclas_fc_t; - -#define DOT11_TCLAS_FC_MIN_LEN 4 /* Classifier Type 2 has the min size */ -#define DOT11_TCLAS_FC_MAX_LEN 254 - -/** TCLAS element */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_ie { - uint8 id; /* 14, DOT11_MNG_TCLAS_ID */ +/* Intra-Access Category Priority element */ +BWL_PRE_PACKED_STRUCT struct dot11_intra_ac_prio_ie { + uint8 id; /* 184, DOT11_MNG_INTRA_AC_PRIO_ID */ uint8 len; - uint8 user_priority; - dot11_tclas_fc_t fc; + uint8 priority; /* Bits 0..2 : User Priority + * Bit 3 : Alternate Queue + * Bit 4 : Drop Eligibility + * Bits 5..7 : Reserved + */ } BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_ie dot11_tclas_ie_t; -#define DOT11_TCLAS_IE_LEN 3u /* Fixed length, include id and len */ - -/** TCLAS processing element */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_proc_ie { - uint8 id; /* 44, DOT11_MNG_TCLAS_PROC_ID */ - uint8 len; - uint8 process; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_proc_ie dot11_tclas_proc_ie_t; -#define DOT11_TCLAS_PROC_IE_LEN 3 /* Fixed length, include id and len */ - -#define DOT11_TCLAS_PROC_LEN 1u /* Proc ie length is always 1 byte */ - -#define DOT11_TCLAS_PROC_MATCHALL 0 /* All high level element need to match */ -#define DOT11_TCLAS_PROC_MATCHONE 1 /* One high level element need to match */ -#define DOT11_TCLAS_PROC_NONMATCH 2 /* Non match to any high level element */ - -/* TSPEC element defined in 802.11 std section 8.4.2.32 - Not supported */ -#define DOT11_TSPEC_IE_LEN 57 /* Fixed length */ - -/** TCLAS Mask element */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_mask_ie { - uint8 id; /* DOT11_MNG_ID_EXT_ID (255) */ - uint8 len; - uint8 id_ext; /* TCLAS_EXTID_MNG_MASK_ID (89) */ - dot11_tclas_fc_t fc; /* Variable length frame classifier (fc) */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_mask_ie dot11_tclas_mask_ie_t; -#define DOT11_TCLAS_MASK_IE_LEN 1u /* Fixed length, excludes id and len */ -#define DOT11_TCLAS_MASK_IE_HDR_LEN 3u /* Fixed length */ +typedef struct dot11_intra_ac_prio_ie dot11_intra_ac_prio_ie_t; +#define DOT11_INTRA_AC_PRIO_IE_LEN 3u /* Fixed length, include id and len */ /* Bitmap definitions for the User Priority Bitmap * Each bit in the bitmap corresponds to a user priority. @@ -2621,384 +2063,106 @@ BWL_PRE_PACKED_STRUCT struct dot11_mscs_subelement { typedef struct dot11_mscs_subelement dot11_mscs_subelement_t; #define DOT11_MSCS_DESCR_SUBELEM_IE_STATUS_LEN 2u /* Subelement ID status length */ -/** TFS request element */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_req_ie { - uint8 id; /* 91, DOT11_MNG_TFS_REQUEST_ID */ - uint8 len; - uint8 tfs_id; - uint8 actcode; - uint8 data[1]; +/* SCS Request Types */ +#define DOT11_SCS_REQ_TYPE_ADD 0u +#define DOT11_SCS_REQ_TYPE_REMOVE 1u +#define DOT11_SCS_REQ_TYPE_CHANGE 2u + +/* 9.4.2.316 QoS Characteristics element in Draft P802.11be_D2.2 + * Figure 9-1002as Control Info field in Draft P802.11be_D2.2 + */ +#define DOT11_QOS_CHAR_DATA_RATE_LEN 3u +#define DOT11_QOS_CHAR_DELAY_BOUND_LEN 3u +BWL_PRE_PACKED_STRUCT struct dot11_qos_char_ie { + uint8 id; /* DOT11_MNG_ID_EXT_ID (255) */ + uint8 len; + uint8 id_ext; /* EXT_MNG_QOS_CHAR_ID (133) */ + uint32 ctrl_info; /* bits 0..1 -> direction + * bits 2..5 -> tid + * bits 6..8 -> user priority + * bits 9..24 -> params bitmap + * bits 25..28 -> linkID + * bits 29..31 -> resreved + */ + uint32 min_srv_interval; /* Minimum Service Interval in + * microseconds + */ + uint32 max_srv_interval; /* Maximum Service Interval in + * microseconds + */ + uint8 min_data_rate[DOT11_QOS_CHAR_DATA_RATE_LEN]; /* Minimum Data Rate in kilobits + * per second + */ + uint8 delay_bound[DOT11_QOS_CHAR_DELAY_BOUND_LEN]; /* Delay Bound in microseconds */ + uint8 data[]; + /* optional Maxmimum MSDU Size */ + /* optional Service Start Time */ + /* optional Service Start Time LinkID */ + /* optional Mean Data Rate */ + /* optional Burst Size */ + /* optional MSDU Lifetime */ + /* optional MSDU Delivery Ratio */ + /* optional MSDU Count Exponent */ + /* optional Medium Time */ } BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_req_ie dot11_tfs_req_ie_t; -#define DOT11_TFS_REQ_IE_LEN 2 /* Fixed length, without id and len */ +typedef struct dot11_qos_char_ie dot11_qos_char_ie_t; -/** TFS request action codes (bitfield) */ -#define DOT11_TFS_ACTCODE_DELETE 1 -#define DOT11_TFS_ACTCODE_NOTIFY 2 - -/** TFS request subelement IDs */ -#define DOT11_TFS_REQ_TFS_SE_ID 1 -#define DOT11_TFS_REQ_VENDOR_SE_ID 221 - -/** TFS subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_se { - uint8 sub_id; - uint8 len; - uint8 data[1]; /* TCLAS element(s) + optional TCLAS proc */ +/** SCS Descriptor element */ +BWL_PRE_PACKED_STRUCT struct dot11_scs_descr_ie { + uint8 id; /* DOT11_MNG_SCS_DESCR_ID (185) */ + uint8 len; + uint8 scsid; /* SCS descriptor id */ + uint8 req_type; /* SCS request type(0/1/2) */ + uint8 data[]; + /* optional Intra-Access Category Priority element, dot11_intrac_ac_prio_ie_t */ + /* zero or more tclas elements, dot11_tclas_ie_t */ + /* optional tclas processing element, dot11_tclas_proc_ie_t */ + /* zero or one dot11_qos_char_ie_t */ + /* zero or more SCS sub-elements, dot11_scs_subelement_t */ } BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_se dot11_tfs_se_t; +typedef struct dot11_scs_descr_ie dot11_scs_descr_ie_t; +#define DOT11_SCS_DESCR_IE_LEN 2u /* Fixed length, exludes id and len */ +#define DOT11_SCS_DESCR_IE_HDR_LEN 4u /* Entire descriptor header length */ -/** TFS response element */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp_ie { - uint8 id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ - uint8 len; - uint8 tfs_id; - uint8 data[1]; +/** SCS Request frame, refer section 9.4.18.6 in the spec IEEE802.11REVmd (aka IEEE802.11-2020) */ +BWL_PRE_PACKED_STRUCT struct dot11_scs_req { + uint8 category; /* ACTION_RAV_STREAMING (19) */ + uint8 robust_action; /* action: SCS Req (0) */ + uint8 dialog_token; /* To identify the SCS request and response */ + uint8 data[]; /* SCS descriptor list */ } BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_resp_ie dot11_tfs_resp_ie_t; -#define DOT11_TFS_RESP_IE_LEN 1u /* Fixed length, without id and len */ +typedef struct dot11_scs_req dot11_scs_req_t; +#define DOT11_SCS_REQ_HDR_LEN 3u /* Fixed length */ -/** TFS response subelement IDs (same subelments, but different IDs than in TFS request */ -#define DOT11_TFS_RESP_TFS_STATUS_SE_ID 1 -#define DOT11_TFS_RESP_TFS_SE_ID 2 -#define DOT11_TFS_RESP_VENDOR_SE_ID 221 - -/** TFS status subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_status_se { - uint8 sub_id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ - uint8 len; - uint8 resp_st; - uint8 data[1]; /* Potential dot11_tfs_se_t included */ +BWL_PRE_PACKED_STRUCT struct dot11_scs_status_duple { + uint8 scsid; + uint16 status; } BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_status_se dot11_tfs_status_se_t; -#define DOT11_TFS_STATUS_SE_LEN 1 /* Fixed length, without id and len */ +typedef struct dot11_scs_status_duple dot11_scs_status_duple_t; -/* Following Definition should be merged to FMS_TFS macro below */ -/* TFS Response status code. Identical to FMS Element status, without N/A */ -#define DOT11_TFS_STATUS_ACCEPT 0 -#define DOT11_TFS_STATUS_DENY_FORMAT 1 -#define DOT11_TFS_STATUS_DENY_RESOURCE 2 -#define DOT11_TFS_STATUS_DENY_POLICY 4 -#define DOT11_TFS_STATUS_DENY_UNSPECIFIED 5 -#define DOT11_TFS_STATUS_ALTPREF_POLICY 7 -#define DOT11_TFS_STATUS_ALTPREF_TCLAS_UNSUPP 14 - -/* FMS Element Status and TFS Response Status Definition */ -#define DOT11_FMS_TFS_STATUS_ACCEPT 0 -#define DOT11_FMS_TFS_STATUS_DENY_FORMAT 1 -#define DOT11_FMS_TFS_STATUS_DENY_RESOURCE 2 -#define DOT11_FMS_TFS_STATUS_DENY_MULTIPLE_DI 3 -#define DOT11_FMS_TFS_STATUS_DENY_POLICY 4 -#define DOT11_FMS_TFS_STATUS_DENY_UNSPECIFIED 5 -#define DOT11_FMS_TFS_STATUS_ALT_DIFF_DI 6 -#define DOT11_FMS_TFS_STATUS_ALT_POLICY 7 -#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_DI 8 -#define DOT11_FMS_TFS_STATUS_ALT_MCRATE 9 -#define DOT11_FMS_TFS_STATUS_TERM_POLICY 10 -#define DOT11_FMS_TFS_STATUS_TERM_RESOURCE 11 -#define DOT11_FMS_TFS_STATUS_TERM_HIGHER_PRIO 12 -#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_MDI 13 -#define DOT11_FMS_TFS_STATUS_ALT_TCLAS_UNSUPP 14 - -/** TFS Management Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: TFS request (13) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ +/** SCS Response frame, refer section 9.6.18.3 in 802.11-2020. + * Currently, an approval(doc: 11-21/668r8) is pending in the IEEE802.11REVme. + * Figure 9-1176 SCS Response frame Action field format in Draft P802.11be_D2.2 spec. + */ +BWL_PRE_PACKED_STRUCT struct dot11_scs_res { + uint8 category; /* ACTION_RAV_STREAMING (19) */ + uint8 robust_action; /* action: SCS Res (1) */ + uint8 dialog_token; /* To identify the SCS request and response */ + uint8 count; /* Specifies the number of items in the scs_status_list */ + dot11_scs_status_duple_t scs_status_list[]; + /* optionally SCS descriptor list; dot11_scs_descr_ie_t scs_descr_list[] */ } BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_req dot11_tfs_req_t; -#define DOT11_TFS_REQ_LEN 3 /* Fixed length */ +typedef struct dot11_scs_res dot11_scs_res_t; +#define DOT11_SCS_RES_HDR_LEN 4u /* Fixed length */ -/** TFS Management Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: TFS request (14) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ +/* SCS subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_scs_subelement { + uint8 id; /* SCS specific subelement ID */ + uint8 len; /* Length in bytes */ + uint8 data[]; /* Subelement specific data */ } BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_resp dot11_tfs_resp_t; -#define DOT11_TFS_RESP_LEN 3 /* Fixed length */ - -/** TFS Management Notify frame request header */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: TFS notify request (15) */ - uint8 tfs_id_cnt; /* TFS IDs count */ - uint8 tfs_id[1]; /* Array of TFS IDs */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_notify_req dot11_tfs_notify_req_t; -#define DOT11_TFS_NOTIFY_REQ_LEN 3 /* Fixed length */ - -/** TFS Management Notify frame response header */ -BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: TFS notify response (28) */ - uint8 tfs_id_cnt; /* TFS IDs count */ - uint8 tfs_id[1]; /* Array of TFS IDs */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tfs_notify_resp dot11_tfs_notify_resp_t; -#define DOT11_TFS_NOTIFY_RESP_LEN 3 /* Fixed length */ - -/** WNM-Sleep Management Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: wnm-sleep request (16) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_req dot11_wnm_sleep_req_t; -#define DOT11_WNM_SLEEP_REQ_LEN 3 /* Fixed length */ - -/** WNM-Sleep Management Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: wnm-sleep request (17) */ - uint8 token; /* dialog token */ - uint16 key_len; /* key data length */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_resp dot11_wnm_sleep_resp_t; -#define DOT11_WNM_SLEEP_RESP_LEN 5 /* Fixed length */ - -#define DOT11_WNM_SLEEP_SUBELEM_ID_GTK 0 -#define DOT11_WNM_SLEEP_SUBELEM_ID_IGTK 1 - -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_gtk { - uint8 sub_id; - uint8 len; - uint16 key_info; - uint8 key_length; - uint8 rsc[8]; - uint8 key[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_subelem_gtk dot11_wnm_sleep_subelem_gtk_t; -#define DOT11_WNM_SLEEP_SUBELEM_GTK_FIXED_LEN 11 /* without sub_id, len, and key */ -#define DOT11_WNM_SLEEP_SUBELEM_GTK_MAX_LEN 43 /* without sub_id and len */ - -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_igtk { - uint8 sub_id; - uint8 len; - uint16 key_id; - uint8 pn[6]; - uint8 key[16]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_subelem_igtk dot11_wnm_sleep_subelem_igtk_t; -#define DOT11_WNM_SLEEP_SUBELEM_IGTK_LEN 24 /* Fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_ie { - uint8 id; /* 93, DOT11_MNG_WNM_SLEEP_MODE_ID */ - uint8 len; - uint8 act_type; - uint8 resp_status; - uint16 interval; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_sleep_ie dot11_wnm_sleep_ie_t; -#define DOT11_WNM_SLEEP_IE_LEN 4 /* Fixed length */ - -#define DOT11_WNM_SLEEP_ACT_TYPE_ENTER 0 -#define DOT11_WNM_SLEEP_ACT_TYPE_EXIT 1 - -#define DOT11_WNM_SLEEP_RESP_ACCEPT 0 -#define DOT11_WNM_SLEEP_RESP_UPDATE 1 -#define DOT11_WNM_SLEEP_RESP_DENY 2 -#define DOT11_WNM_SLEEP_RESP_DENY_TEMP 3 -#define DOT11_WNM_SLEEP_RESP_DENY_KEY 4 -#define DOT11_WNM_SLEEP_RESP_DENY_INUSE 5 -#define DOT11_WNM_SLEEP_RESP_LAST 6 - -/** DMS Management Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: dms request (23) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_req dot11_dms_req_t; -#define DOT11_DMS_REQ_LEN 3 /* Fixed length */ - -/** DMS Management Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: dms request (24) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_resp dot11_dms_resp_t; -#define DOT11_DMS_RESP_LEN 3 /* Fixed length */ - -/** DMS request element */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_req_ie { - uint8 id; /* 99, DOT11_MNG_DMS_REQUEST_ID */ - uint8 len; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_req_ie dot11_dms_req_ie_t; -#define DOT11_DMS_REQ_IE_LEN 2 /* Fixed length */ - -/** DMS response element */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_ie { - uint8 id; /* 100, DOT11_MNG_DMS_RESPONSE_ID */ - uint8 len; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_resp_ie dot11_dms_resp_ie_t; -#define DOT11_DMS_RESP_IE_LEN 2 /* Fixed length */ - -/** DMS request descriptor */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_req_desc { - uint8 dms_id; - uint8 len; - uint8 type; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_req_desc dot11_dms_req_desc_t; -#define DOT11_DMS_REQ_DESC_LEN 3 /* Fixed length */ - -#define DOT11_DMS_REQ_TYPE_ADD 0 -#define DOT11_DMS_REQ_TYPE_REMOVE 1 -#define DOT11_DMS_REQ_TYPE_CHANGE 2 - -/** DMS response status */ -BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_st { - uint8 dms_id; - uint8 len; - uint8 type; - uint16 lsc; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dms_resp_st dot11_dms_resp_st_t; -#define DOT11_DMS_RESP_STATUS_LEN 5 /* Fixed length */ - -#define DOT11_DMS_RESP_TYPE_ACCEPT 0 -#define DOT11_DMS_RESP_TYPE_DENY 1 -#define DOT11_DMS_RESP_TYPE_TERM 2 - -#define DOT11_DMS_RESP_LSC_UNSUPPORTED 0xFFFF - -/** WNM-Notification Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_wnm_notif_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: Notification request (26) */ - uint8 token; /* dialog token */ - uint8 type; /* type */ - uint8 data[1]; /* Sub-elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_wnm_notif_req dot11_wnm_notif_req_t; -#define DOT11_WNM_NOTIF_REQ_LEN 4 /* Fixed length */ - -/** FMS Management Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_req { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: fms request (9) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_req dot11_fms_req_t; -#define DOT11_FMS_REQ_LEN 3 /* Fixed length */ - -/** FMS Management Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_resp { - uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: fms request (10) */ - uint8 token; /* dialog token */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_resp dot11_fms_resp_t; -#define DOT11_FMS_RESP_LEN 3 /* Fixed length */ - -/** FMS Descriptor element */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_desc { - uint8 id; - uint8 len; - uint8 num_fms_cnt; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_desc dot11_fms_desc_t; -#define DOT11_FMS_DESC_LEN 1 /* Fixed length */ - -#define DOT11_FMS_CNTR_MAX 0x8 -#define DOT11_FMS_CNTR_ID_MASK 0x7 -#define DOT11_FMS_CNTR_ID_SHIFT 0x0 -#define DOT11_FMS_CNTR_COUNT_MASK 0xf1 -#define DOT11_FMS_CNTR_SHIFT 0x3 - -/** FMS request element */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_req_ie { - uint8 id; - uint8 len; - uint8 fms_token; /* token used to identify fms stream set */ - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_req_ie dot11_fms_req_ie_t; -#define DOT11_FMS_REQ_IE_FIX_LEN 1 /* Fixed length */ - -BWL_PRE_PACKED_STRUCT struct dot11_rate_id_field { - uint8 mask; - uint8 mcs_idx; - uint16 rate; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rate_id_field dot11_rate_id_field_t; -#define DOT11_RATE_ID_FIELD_MCS_SEL_MASK 0x7 -#define DOT11_RATE_ID_FIELD_MCS_SEL_OFFSET 0 -#define DOT11_RATE_ID_FIELD_RATETYPE_MASK 0x18 -#define DOT11_RATE_ID_FIELD_RATETYPE_OFFSET 3 -#define DOT11_RATE_ID_FIELD_LEN sizeof(dot11_rate_id_field_t) - -/** FMS request subelements */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_se { - uint8 sub_id; - uint8 len; - uint8 interval; - uint8 max_interval; - dot11_rate_id_field_t rate; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_se dot11_fms_se_t; -#define DOT11_FMS_REQ_SE_LEN 6 /* Fixed length */ - -#define DOT11_FMS_REQ_SE_ID_FMS 1 /* FMS subelement */ -#define DOT11_FMS_REQ_SE_ID_VS 221 /* Vendor Specific subelement */ - -/** FMS response element */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_resp_ie { - uint8 id; - uint8 len; - uint8 fms_token; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_resp_ie dot11_fms_resp_ie_t; -#define DOT11_FMS_RESP_IE_FIX_LEN 1 /* Fixed length */ - -/* FMS status subelements */ -#define DOT11_FMS_STATUS_SE_ID_FMS 1 /* FMS Status */ -#define DOT11_FMS_STATUS_SE_ID_TCLAS 2 /* TCLAS Status */ -#define DOT11_FMS_STATUS_SE_ID_VS 221 /* Vendor Specific subelement */ - -/** FMS status subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_fms_status_se { - uint8 sub_id; - uint8 len; - uint8 status; - uint8 interval; - uint8 max_interval; - uint8 fmsid; - uint8 counter; - dot11_rate_id_field_t rate; - uint8 mcast_addr[ETHER_ADDR_LEN]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_fms_status_se dot11_fms_status_se_t; -#define DOT11_FMS_STATUS_SE_LEN 15 /* Fixed length */ - -/** TCLAS status subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_tclas_status_se { - uint8 sub_id; - uint8 len; - uint8 fmsid; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_tclas_status_se dot11_tclas_status_se_t; -#define DOT11_TCLAS_STATUS_SE_LEN 1 /* Fixed length */ +typedef struct dot11_scs_subelement dot11_scs_subelement_t; +#define DOT11_SCS_DESCR_SUBELEM_IE_LEN 2u /* Subelement IE length */ BWL_PRE_PACKED_STRUCT struct dot11_addba_req { uint8 category; /* category of action frame (3) */ @@ -3041,899 +2205,6 @@ typedef struct dot11_delba dot11_delba_t; #define SA_QUERY_REQUEST 0 #define SA_QUERY_RESPONSE 1 -/* ************* 802.11r related definitions. ************* */ - -/** Over-the-DS Fast Transition Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_ft_req { - uint8 category; /* category of action frame (6) */ - uint8 action; /* action: ft req */ - uint8 sta_addr[ETHER_ADDR_LEN]; - uint8 tgt_ap_addr[ETHER_ADDR_LEN]; - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ft_req dot11_ft_req_t; -#define DOT11_FT_REQ_FIXED_LEN 14 - -/** Over-the-DS Fast Transition Response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_ft_res { - uint8 category; /* category of action frame (6) */ - uint8 action; /* action: ft resp */ - uint8 sta_addr[ETHER_ADDR_LEN]; - uint8 tgt_ap_addr[ETHER_ADDR_LEN]; - uint16 status; /* status code */ - uint8 data[1]; /* Elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ft_res dot11_ft_res_t; -#define DOT11_FT_RES_FIXED_LEN 16 - -/** RDE RIC Data Element. */ -BWL_PRE_PACKED_STRUCT struct dot11_rde_ie { - uint8 id; /* 11r, DOT11_MNG_RDE_ID */ - uint8 length; - uint8 rde_id; /* RDE identifier. */ - uint8 rd_count; /* Resource Descriptor Count. */ - uint16 status; /* Status Code. */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rde_ie dot11_rde_ie_t; - -/* 11r - Size of the RDE (RIC Data Element) IE, including TLV header. */ -#define DOT11_MNG_RDE_IE_LEN sizeof(dot11_rde_ie_t) - -/* ************* 802.11k related definitions. ************* */ - -/* Radio measurements enabled capability ie */ -#define DOT11_RRM_CAP_LEN 5 /* length of rrm cap bitmap */ -#define RCPI_IE_LEN 1 -#define RSNI_IE_LEN 1 -BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { - uint8 cap[DOT11_RRM_CAP_LEN]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; - -/* Bitmap definitions for cap ie */ -#define DOT11_RRM_CAP_LINK 0 -#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1 -#define DOT11_RRM_CAP_PARALLEL 2 -#define DOT11_RRM_CAP_REPEATED 3 -#define DOT11_RRM_CAP_BCN_PASSIVE 4 -#define DOT11_RRM_CAP_BCN_ACTIVE 5 -#define DOT11_RRM_CAP_BCN_TABLE 6 -#define DOT11_RRM_CAP_BCN_REP_COND 7 -#define DOT11_RRM_CAP_FM 8 -#define DOT11_RRM_CAP_CLM 9 -#define DOT11_RRM_CAP_NHM 10 -#define DOT11_RRM_CAP_SM 11 -#define DOT11_RRM_CAP_LCIM 12 -#define DOT11_RRM_CAP_LCIA 13 -#define DOT11_RRM_CAP_TSCM 14 -#define DOT11_RRM_CAP_TTSCM 15 -#define DOT11_RRM_CAP_AP_CHANREP 16 -#define DOT11_RRM_CAP_RMMIB 17 -/* bit18-bit23, not used for RRM_IOVAR */ -#define DOT11_RRM_CAP_MPC0 24 -#define DOT11_RRM_CAP_MPC1 25 -#define DOT11_RRM_CAP_MPC2 26 -#define DOT11_RRM_CAP_MPTI 27 -#define DOT11_RRM_CAP_NBRTSFO 28 -#define DOT11_RRM_CAP_RCPI 29 -#define DOT11_RRM_CAP_RSNI 30 -#define DOT11_RRM_CAP_BSSAAD 31 -#define DOT11_RRM_CAP_BSSAAC 32 -#define DOT11_RRM_CAP_AI 33 -#define DOT11_RRM_CAP_FTM_RANGE 34 -#define DOT11_RRM_CAP_CIVIC_LOC 35 -#define DOT11_RRM_CAP_IDENT_LOC 36 -#define DOT11_RRM_CAP_LAST 36 - -#ifdef WL11K_ALL_MEAS -#define DOT11_RRM_CAP_LINK_ENAB (1 << DOT11_RRM_CAP_LINK) -#define DOT11_RRM_CAP_FM_ENAB (1 << (DOT11_RRM_CAP_FM - 8)) -#define DOT11_RRM_CAP_CLM_ENAB (1 << (DOT11_RRM_CAP_CLM - 8)) -#define DOT11_RRM_CAP_NHM_ENAB (1 << (DOT11_RRM_CAP_NHM - 8)) -#define DOT11_RRM_CAP_SM_ENAB (1 << (DOT11_RRM_CAP_SM - 8)) -#define DOT11_RRM_CAP_LCIM_ENAB (1 << (DOT11_RRM_CAP_LCIM - 8)) -#define DOT11_RRM_CAP_TSCM_ENAB (1 << (DOT11_RRM_CAP_TSCM - 8)) -#ifdef WL11K_AP -#define DOT11_RRM_CAP_MPC0_ENAB (1 << (DOT11_RRM_CAP_MPC0 - 24)) -#define DOT11_RRM_CAP_MPC1_ENAB (1 << (DOT11_RRM_CAP_MPC1 - 24)) -#define DOT11_RRM_CAP_MPC2_ENAB (1 << (DOT11_RRM_CAP_MPC2 - 24)) -#define DOT11_RRM_CAP_MPTI_ENAB (1 << (DOT11_RRM_CAP_MPTI - 24)) -#else -#define DOT11_RRM_CAP_MPC0_ENAB 0 -#define DOT11_RRM_CAP_MPC1_ENAB 0 -#define DOT11_RRM_CAP_MPC2_ENAB 0 -#define DOT11_RRM_CAP_MPTI_ENAB 0 -#endif /* WL11K_AP */ -#define DOT11_RRM_CAP_CIVIC_LOC_ENAB (1 << (DOT11_RRM_CAP_CIVIC_LOC - 32)) -#define DOT11_RRM_CAP_IDENT_LOC_ENAB (1 << (DOT11_RRM_CAP_IDENT_LOC - 32)) -#else -#define DOT11_RRM_CAP_LINK_ENAB 0 -#define DOT11_RRM_CAP_FM_ENAB 0 -#define DOT11_RRM_CAP_CLM_ENAB 0 -#define DOT11_RRM_CAP_NHM_ENAB 0 -#define DOT11_RRM_CAP_SM_ENAB 0 -#define DOT11_RRM_CAP_LCIM_ENAB 0 -#define DOT11_RRM_CAP_TSCM_ENAB 0 -#define DOT11_RRM_CAP_MPC0_ENAB 0 -#define DOT11_RRM_CAP_MPC1_ENAB 0 -#define DOT11_RRM_CAP_MPC2_ENAB 0 -#define DOT11_RRM_CAP_MPTI_ENAB 0 -#define DOT11_RRM_CAP_CIVIC_LOC_ENAB 0 -#define DOT11_RRM_CAP_IDENT_LOC_ENAB 0 -#endif /* WL11K_ALL_MEAS */ -#ifdef WL11K_NBR_MEAS -#define DOT11_RRM_CAP_NEIGHBOR_REPORT_ENAB (1 << DOT11_RRM_CAP_NEIGHBOR_REPORT) -#else -#define DOT11_RRM_CAP_NEIGHBOR_REPORT_ENAB 0 -#endif /* WL11K_NBR_MEAS */ -#ifdef WL11K_BCN_MEAS -#define DOT11_RRM_CAP_BCN_PASSIVE_ENAB (1 << DOT11_RRM_CAP_BCN_PASSIVE) -#define DOT11_RRM_CAP_BCN_ACTIVE_ENAB (1 << DOT11_RRM_CAP_BCN_ACTIVE) -#else -#define DOT11_RRM_CAP_BCN_PASSIVE_ENAB 0 -#define DOT11_RRM_CAP_BCN_ACTIVE_ENAB 0 -#endif /* WL11K_BCN_MEAS */ -#define DOT11_RRM_CAP_MPA_MASK 0x7 -/* Operating Class (formerly "Regulatory Class") definitions */ -#define DOT11_OP_CLASS_NONE 255 - -BWL_PRE_PACKED_STRUCT struct do11_ap_chrep { - uint8 id; - uint8 len; - uint8 reg; - uint8 chanlist[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct do11_ap_chrep dot11_ap_chrep_t; - -/* Radio Measurements action ids */ -#define DOT11_RM_ACTION_RM_REQ 0 /* Radio measurement request */ -#define DOT11_RM_ACTION_RM_REP 1 /* Radio measurement report */ -#define DOT11_RM_ACTION_LM_REQ 2 /* Link measurement request */ -#define DOT11_RM_ACTION_LM_REP 3 /* Link measurement report */ -#define DOT11_RM_ACTION_NR_REQ 4 /* Neighbor report request */ -#define DOT11_RM_ACTION_NR_REP 5 /* Neighbor report response */ -#define DOT11_PUB_ACTION_MP 7 /* Measurement Pilot public action id */ - -/** Generic radio measurement action frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_rm_action { - uint8 category; /* category of action frame (5) */ - uint8 action; /* radio measurement action */ - uint8 token; /* dialog token */ - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rm_action dot11_rm_action_t; -#define DOT11_RM_ACTION_LEN 3 - -BWL_PRE_PACKED_STRUCT struct dot11_rmreq { - uint8 category; /* category of action frame (5) */ - uint8 action; /* radio measurement action */ - uint8 token; /* dialog token */ - uint16 reps; /* no. of repetitions */ - uint8 data[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq dot11_rmreq_t; -#define DOT11_RMREQ_LEN 5 - -BWL_PRE_PACKED_STRUCT struct dot11_rm_ie { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rm_ie dot11_rm_ie_t; -#define DOT11_RM_IE_LEN 5 - -/* Definitions for "mode" bits in rm req */ -#define DOT11_RMREQ_MODE_PARALLEL 1 -#define DOT11_RMREQ_MODE_ENABLE 2 -#define DOT11_RMREQ_MODE_REQUEST 4 -#define DOT11_RMREQ_MODE_REPORT 8 -#define DOT11_RMREQ_MODE_DURMAND 0x10 /* Duration Mandatory */ - -/* Definitions for "mode" bits in rm rep */ -#define DOT11_RMREP_MODE_LATE 1 -#define DOT11_RMREP_MODE_INCAPABLE 2 -#define DOT11_RMREP_MODE_REFUSED 4 - -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn { - uint8 id; /* use dot11_rm_ie_t ? */ - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 reg; - uint8 channel; - uint16 interval; - uint16 duration; - uint8 bcn_mode; - struct ether_addr bssid; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t; -#define DOT11_RMREQ_BCN_LEN 18u - -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn { - uint8 reg; - uint8 channel; - uint32 starttime[2]; - uint16 duration; - uint8 frame_info; - uint8 rcpi; - uint8 rsni; - struct ether_addr bssid; - uint8 antenna_id; - uint32 parent_tsf; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; -#define DOT11_RMREP_BCN_LEN 26 - -/* Beacon request measurement mode */ -#define DOT11_RMREQ_BCN_PASSIVE 0 -#define DOT11_RMREQ_BCN_ACTIVE 1 -#define DOT11_RMREQ_BCN_TABLE 2 - -/* Sub-element IDs for Beacon Request */ -#define DOT11_RMREQ_BCN_SSID_ID 0 -#define DOT11_RMREQ_BCN_REPINFO_ID 1 -#define DOT11_RMREQ_BCN_REPDET_ID 2 -#define DOT11_RMREQ_BCN_REQUEST_ID 10 -#define DOT11_RMREQ_BCN_APCHREP_ID DOT11_MNG_AP_CHREP_ID -#define DOT11_RMREQ_BCN_LAST_RPT_IND_REQ_ID 164 - -/* Reporting Detail element definition */ -#define DOT11_RMREQ_BCN_REPDET_FIXED 0 /* Fixed length fields only */ -#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 /* + requested information elems */ -#define DOT11_RMREQ_BCN_REPDET_ALL 2 /* All fields */ - -/* Reporting Information (reporting condition) element definition */ -#define DOT11_RMREQ_BCN_REPINFO_LEN 2 /* Beacon Reporting Information length */ -#define DOT11_RMREQ_BCN_REPCOND_DEFAULT 0 /* Report to be issued after each measurement */ - -/* Last Beacon Report Indication Request definition */ -#define DOT11_RMREQ_BCN_LAST_RPT_IND_REQ_ENAB 1 - -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_last_bcn_rpt_ind_req { - uint8 id; /* DOT11_RMREQ_BCN_LAST_RPT_IND_REQ_ID */ - uint8 len; /* length of remaining fields */ - uint8 data; /* data = 1 means last bcn rpt ind requested */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_last_bcn_rpt_ind_req dot11_rmrep_last_bcn_rpt_ind_req_t; - -/* Sub-element IDs for Beacon Report */ -#define DOT11_RMREP_BCN_FRM_BODY 1 -#define DOT11_RMREP_BCN_FRM_BODY_FRAG_ID 2 -#define DOT11_RMREP_BCN_LAST_RPT_IND 164 -#define DOT11_RMREP_BCN_FRM_BODY_LEN_MAX 224 /* 802.11k-2008 7.3.2.22.6 */ - -/* Refer IEEE P802.11-REVmd/D1.0 9.4.2.21.7 Beacon report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn_frm_body_fragmt_id { - uint8 id; /* DOT11_RMREP_BCN_FRM_BODY_FRAG_ID */ - uint8 len; /* length of remaining fields */ - /* More fragments(B15), fragment Id(B8-B14), Bcn rpt instance ID (B0 - B7) */ - uint16 frag_info_rpt_id; -} BWL_POST_PACKED_STRUCT; - -typedef struct dot11_rmrep_bcn_frm_body_fragmt_id dot11_rmrep_bcn_frm_body_fragmt_id_t; - -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn_frm_body_frag_id { - uint8 id; /* DOT11_RMREP_BCN_FRM_BODY_FRAG_ID */ - uint8 len; /* length of remaining fields */ - uint8 bcn_rpt_id; /* Bcn rpt instance ID */ - uint8 frag_info; /* fragment Id(7 bits) | More fragments(1 bit) */ -} BWL_POST_PACKED_STRUCT; - -typedef struct dot11_rmrep_bcn_frm_body_frag_id dot11_rmrep_bcn_frm_body_frag_id_t; -#define DOT11_RMREP_BCNRPT_FRAG_ID_DATA_LEN 2u -#define DOT11_RMREP_BCNRPT_FRAG_ID_SE_LEN sizeof(dot11_rmrep_bcn_frm_body_frag_id_t) -#define DOT11_RMREP_BCNRPT_FRAG_ID_NUM_SHIFT 1u -#define DOT11_RMREP_BCNRPT_FRAGMT_ID_SE_LEN sizeof(dot11_rmrep_bcn_frm_body_fragmt_id_t) -#define DOT11_RMREP_BCNRPT_BCN_RPT_ID_MASK 0x00FFu -#define DOT11_RMREP_BCNRPT_FRAGMT_ID_NUM_SHIFT 8u -#define DOT11_RMREP_BCNRPT_FRAGMT_ID_NUM_MASK 0x7F00u -#define DOT11_RMREP_BCNRPT_MORE_FRAG_SHIFT 15u -#define DOT11_RMREP_BCNRPT_MORE_FRAG_MASK 0x8000u - -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_last_bcn_rpt_ind { - uint8 id; /* DOT11_RMREP_BCN_LAST_RPT_IND */ - uint8 len; /* length of remaining fields */ - uint8 data; /* data = 1 is last bcn rpt */ -} BWL_POST_PACKED_STRUCT; - -typedef struct dot11_rmrep_last_bcn_rpt_ind dot11_rmrep_last_bcn_rpt_ind_t; -#define DOT11_RMREP_LAST_BCN_RPT_IND_DATA_LEN 1 -#define DOT11_RMREP_LAST_BCN_RPT_IND_SE_LEN sizeof(dot11_rmrep_last_bcn_rpt_ind_t) - -/* Sub-element IDs for Frame Report */ -#define DOT11_RMREP_FRAME_COUNT_REPORT 1 - -/* Channel load request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_chanload { - uint8 id; /* use dot11_rm_ie_t ? */ - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 reg; - uint8 channel; - uint16 interval; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_chanload dot11_rmreq_chanload_t; -#define DOT11_RMREQ_CHANLOAD_LEN 11 - -/** Channel load report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_chanload { - uint8 reg; - uint8 channel; - uint32 starttime[2]; - uint16 duration; - uint8 channel_load; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_chanload dot11_rmrep_chanload_t; -#define DOT11_RMREP_CHANLOAD_LEN 13 - -/** Noise histogram request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_noise { - uint8 id; /* use dot11_rm_ie_t ? */ - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 reg; - uint8 channel; - uint16 interval; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_noise dot11_rmreq_noise_t; -#define DOT11_RMREQ_NOISE_LEN 11 - -/** Noise histogram report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_noise { - uint8 reg; - uint8 channel; - uint32 starttime[2]; - uint16 duration; - uint8 antid; - uint8 anpi; - uint8 ipi0_dens; - uint8 ipi1_dens; - uint8 ipi2_dens; - uint8 ipi3_dens; - uint8 ipi4_dens; - uint8 ipi5_dens; - uint8 ipi6_dens; - uint8 ipi7_dens; - uint8 ipi8_dens; - uint8 ipi9_dens; - uint8 ipi10_dens; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_noise dot11_rmrep_noise_t; -#define DOT11_RMREP_NOISE_LEN 25 - -/** Frame request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_frame { - uint8 id; /* use dot11_rm_ie_t ? */ - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 reg; - uint8 channel; - uint16 interval; - uint16 duration; - uint8 req_type; - struct ether_addr ta; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_frame dot11_rmreq_frame_t; -#define DOT11_RMREQ_FRAME_LEN 18 - -/** Frame report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frame { - uint8 reg; - uint8 channel; - uint32 starttime[2]; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_frame dot11_rmrep_frame_t; -#define DOT11_RMREP_FRAME_LEN 12 - -/** Frame report entry */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frmentry { - struct ether_addr ta; - struct ether_addr bssid; - uint8 phy_type; - uint8 avg_rcpi; - uint8 last_rsni; - uint8 last_rcpi; - uint8 ant_id; - uint16 frame_cnt; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_frmentry dot11_rmrep_frmentry_t; -#define DOT11_RMREP_FRMENTRY_LEN 19 - -/** STA statistics request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_stat { - uint8 id; /* use dot11_rm_ie_t ? */ - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - struct ether_addr peer; - uint16 interval; - uint16 duration; - uint8 group_id; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_stat dot11_rmreq_stat_t; -#define DOT11_RMREQ_STAT_LEN 16 - -/** STA statistics report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_stat { - uint16 duration; - uint8 group_id; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_stat dot11_rmrep_stat_t; - -/* Statistics Group Report: Group IDs */ -enum { - DOT11_RRM_STATS_GRP_ID_0 = 0, - DOT11_RRM_STATS_GRP_ID_1, - DOT11_RRM_STATS_GRP_ID_2, - DOT11_RRM_STATS_GRP_ID_3, - DOT11_RRM_STATS_GRP_ID_4, - DOT11_RRM_STATS_GRP_ID_5, - DOT11_RRM_STATS_GRP_ID_6, - DOT11_RRM_STATS_GRP_ID_7, - DOT11_RRM_STATS_GRP_ID_8, - DOT11_RRM_STATS_GRP_ID_9, - DOT11_RRM_STATS_GRP_ID_10, - DOT11_RRM_STATS_GRP_ID_11, - DOT11_RRM_STATS_GRP_ID_12, - DOT11_RRM_STATS_GRP_ID_13, - DOT11_RRM_STATS_GRP_ID_14, - DOT11_RRM_STATS_GRP_ID_15, - DOT11_RRM_STATS_GRP_ID_16 -}; - -/* Statistics Group Report: Group Data length */ -#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_0 28 -typedef struct rrm_stat_group_0 { - uint32 txfrag; - uint32 txmulti; - uint32 txfail; - uint32 rxframe; - uint32 rxmulti; - uint32 rxbadfcs; - uint32 txframe; -} rrm_stat_group_0_t; - -#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_1 24 -typedef struct rrm_stat_group_1 { - uint32 txretry; - uint32 txretries; - uint32 rxdup; - uint32 txrts; - uint32 rtsfail; - uint32 ackfail; -} rrm_stat_group_1_t; - -/* group 2-9 use same qos data structure (tid 0-7), total 52 bytes */ -#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_2_9 52 -typedef struct rrm_stat_group_qos { - uint32 txfrag; - uint32 txfail; - uint32 txretry; - uint32 txretries; - uint32 rxdup; - uint32 txrts; - uint32 rtsfail; - uint32 ackfail; - uint32 rxfrag; - uint32 txframe; - uint32 txdrop; - uint32 rxmpdu; - uint32 rxretries; -} rrm_stat_group_qos_t; - -/* dot11BSSAverageAccessDelay Group (only available at an AP): 8 byte */ -#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_10 8 -typedef BWL_PRE_PACKED_STRUCT struct rrm_stat_group_10 { - uint8 apavgdelay; - uint8 avgdelaybe; - uint8 avgdelaybg; - uint8 avgdelayvi; - uint8 avgdelayvo; - uint16 stacount; - uint8 chanutil; -} BWL_POST_PACKED_STRUCT rrm_stat_group_10_t; - -/* AMSDU, 40 bytes */ -#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_11 40 -typedef struct rrm_stat_group_11 { - uint32 txamsdu; - uint32 amsdufail; - uint32 amsduretry; - uint32 amsduretries; - uint32 txamsdubyte_h; - uint32 txamsdubyte_l; - uint32 amsduackfail; - uint32 rxamsdu; - uint32 rxamsdubyte_h; - uint32 rxamsdubyte_l; -} rrm_stat_group_11_t; - -/* AMPDU, 36 bytes */ -#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_12 36 -typedef struct rrm_stat_group_12 { - uint32 txampdu; - uint32 txmpdu; - uint32 txampdubyte_h; - uint32 txampdubyte_l; - uint32 rxampdu; - uint32 rxmpdu; - uint32 rxampdubyte_h; - uint32 rxampdubyte_l; - uint32 ampducrcfail; -} rrm_stat_group_12_t; - -/* BACK etc, 36 bytes */ -#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_13 36 -typedef struct rrm_stat_group_13 { - uint32 rximpbarfail; - uint32 rxexpbarfail; - uint32 chanwidthsw; - uint32 txframe20mhz; - uint32 txframe40mhz; - uint32 rxframe20mhz; - uint32 rxframe40mhz; - uint32 psmpgrantdur; - uint32 psmpuseddur; -} rrm_stat_group_13_t; - -/* RD Dual CTS etc, 36 bytes */ -#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_14 36 -typedef struct rrm_stat_group_14 { - uint32 grantrdgused; - uint32 grantrdgunused; - uint32 txframeingrantrdg; - uint32 txbyteingrantrdg_h; - uint32 txbyteingrantrdg_l; - uint32 dualcts; - uint32 dualctsfail; - uint32 rtslsi; - uint32 rtslsifail; -} rrm_stat_group_14_t; - -/* bf and STBC etc, 20 bytes */ -#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_15 20 -typedef struct rrm_stat_group_15 { - uint32 bfframe; - uint32 stbccts; - uint32 stbcctsfail; - uint32 nonstbccts; - uint32 nonstbcctsfail; -} rrm_stat_group_15_t; - -/* RSNA, 28 bytes */ -#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_16 28 -typedef struct rrm_stat_group_16 { - uint32 rsnacmacicverr; - uint32 rsnacmacreplay; - uint32 rsnarobustmgmtccmpreplay; - uint32 rsnatkipicverr; - uint32 rsnatkipicvreplay; - uint32 rsnaccmpdecrypterr; - uint32 rsnaccmpreplay; -} rrm_stat_group_16_t; - -/* Transmit stream/category measurement request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_tx_stream { - uint8 id; /* use dot11_rm_ie_t ? */ - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint16 interval; - uint16 duration; - struct ether_addr peer; - uint8 traffic_id; - uint8 bin0_range; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_tx_stream dot11_rmreq_tx_stream_t; -#define DOT11_RMREQ_TXSTREAM_LEN 17 - -/** Transmit stream/category measurement report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_tx_stream { - uint32 starttime[2]; - uint16 duration; - struct ether_addr peer; - uint8 traffic_id; - uint8 reason; - uint32 txmsdu_cnt; - uint32 msdu_discarded_cnt; - uint32 msdufailed_cnt; - uint32 msduretry_cnt; - uint32 cfpolls_lost_cnt; - uint32 avrqueue_delay; - uint32 avrtx_delay; - uint8 bin0_range; - uint32 bin0; - uint32 bin1; - uint32 bin2; - uint32 bin3; - uint32 bin4; - uint32 bin5; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_tx_stream dot11_rmrep_tx_stream_t; -#define DOT11_RMREP_TXSTREAM_LEN 71 - -typedef struct rrm_tscm { - uint32 msdu_tx; - uint32 msdu_exp; - uint32 msdu_fail; - uint32 msdu_retries; - uint32 cfpolls_lost; - uint32 queue_delay; - uint32 tx_delay_sum; - uint32 tx_delay_cnt; - uint32 bin0_range_us; - uint32 bin0; - uint32 bin1; - uint32 bin2; - uint32 bin3; - uint32 bin4; - uint32 bin5; -} rrm_tscm_t; -enum { - DOT11_FTM_LOCATION_SUBJ_LOCAL = 0, /* Where am I? */ - DOT11_FTM_LOCATION_SUBJ_REMOTE = 1, /* Where are you? */ - DOT11_FTM_LOCATION_SUBJ_THIRDPARTY = 2 /* Where is he/she? */ -}; - -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_ftm_lci { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 subj; - - /* Following 3 fields are unused. Keep for ROM compatibility. */ - uint8 lat_res; - uint8 lon_res; - uint8 alt_res; - - /* optional sub-elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_ftm_lci dot11_rmreq_ftm_lci_t; -#define DOT11_RMREQ_LCI_LEN 9 - -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_ftm_lci { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 lci_sub_id; - uint8 lci_sub_len; - /* optional LCI field */ - /* optional sub-elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_ftm_lci dot11_rmrep_ftm_lci_t; - -#define DOT11_FTM_LCI_SUBELEM_ID 0 -#define DOT11_FTM_LCI_SUBELEM_LEN 2 -#define DOT11_FTM_LCI_FIELD_LEN 16 -#define DOT11_FTM_LCI_UNKNOWN_LEN 2 - -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_ftm_civic { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 subj; - uint8 civloc_type; - uint8 siu; /* service interval units */ - uint16 si; /* service interval */ - /* optional sub-elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_ftm_civic dot11_rmreq_ftm_civic_t; -#define DOT11_RMREQ_CIVIC_LEN 10 - -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_ftm_civic { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 civloc_type; - uint8 civloc_sub_id; - uint8 civloc_sub_len; - /* optional location civic field */ - /* optional sub-elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_ftm_civic dot11_rmrep_ftm_civic_t; - -#define DOT11_FTM_CIVIC_LOC_TYPE_RFC4776 0 -#define DOT11_FTM_CIVIC_SUBELEM_ID 0 -#define DOT11_FTM_CIVIC_SUBELEM_LEN 2 -#define DOT11_FTM_CIVIC_LOC_SI_NONE 0 -#define DOT11_FTM_CIVIC_TYPE_LEN 1 -#define DOT11_FTM_CIVIC_UNKNOWN_LEN 3 - -/* Location Identifier measurement request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_locid { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 subj; - uint8 siu; - uint16 si; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_locid dot11_rmreq_locid_t; -#define DOT11_RMREQ_LOCID_LEN 9 - -/* Location Identifier measurement report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_locid { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 exp_tsf[8]; - uint8 locid_sub_id; - uint8 locid_sub_len; - /* optional location identifier field */ - /* optional sub-elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_locid dot11_rmrep_locid_t; -#define DOT11_LOCID_UNKNOWN_LEN 10 -#define DOT11_LOCID_SUBELEM_ID 0 - -BWL_PRE_PACKED_STRUCT struct dot11_ftm_range_subel { - uint8 id; - uint8 len; - uint16 max_age; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm_range_subel dot11_ftm_range_subel_t; -#define DOT11_FTM_RANGE_SUBELEM_ID 4 -#define DOT11_FTM_RANGE_SUBELEM_LEN 2 - -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_ftm_range { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint16 max_init_delay; /* maximum random initial delay */ - uint8 min_ap_count; - uint8 data[1]; - /* neighbor report sub-elements */ - /* optional sub-elements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_ftm_range dot11_rmreq_ftm_range_t; -#define DOT11_RMREQ_FTM_RANGE_LEN 8 - -#define DOT11_FTM_RANGE_LEN 3 -BWL_PRE_PACKED_STRUCT struct dot11_ftm_range_entry { - uint32 start_tsf; /* 4 lsb of tsf */ - struct ether_addr bssid; - uint8 range[DOT11_FTM_RANGE_LEN]; - uint8 max_err[DOT11_FTM_RANGE_LEN]; - uint8 rsvd; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm_range_entry dot11_ftm_range_entry_t; -#define DOT11_FTM_RANGE_ENTRY_MAX_COUNT 15 - -enum { - DOT11_FTM_RANGE_ERROR_AP_INCAPABLE = 2, - DOT11_FTM_RANGE_ERROR_AP_FAILED = 3, - DOT11_FTM_RANGE_ERROR_TX_FAILED = 8, - DOT11_FTM_RANGE_ERROR_MAX -}; - -BWL_PRE_PACKED_STRUCT struct dot11_ftm_range_error_entry { - uint32 start_tsf; /* 4 lsb of tsf */ - struct ether_addr bssid; - uint8 code; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm_range_error_entry dot11_ftm_range_error_entry_t; -#define DOT11_FTM_RANGE_ERROR_ENTRY_MAX_COUNT 11 - -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_ftm_range { - uint8 id; - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint8 entry_count; - uint8 data[2]; /* includes pad */ - /* - dot11_ftm_range_entry_t entries[entry_count]; - uint8 error_count; - dot11_ftm_error_entry_t errors[error_count]; - */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_ftm_range dot11_rmrep_ftm_range_t; - -#define DOT11_FTM_RANGE_REP_MIN_LEN 6 /* No extra byte for error_count */ -#define DOT11_FTM_RANGE_ENTRY_CNT_MAX 15 -#define DOT11_FTM_RANGE_ERROR_CNT_MAX 11 -#define DOT11_FTM_RANGE_REP_FIXED_LEN 1 /* No extra byte for error_count */ -/** Measurement pause request */ -BWL_PRE_PACKED_STRUCT struct dot11_rmreq_pause_time { - uint8 id; /* use dot11_rm_ie_t ? */ - uint8 len; - uint8 token; - uint8 mode; - uint8 type; - uint16 pause_time; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmreq_pause_time dot11_rmreq_pause_time_t; -#define DOT11_RMREQ_PAUSE_LEN 7 - -/* Neighbor Report subelements ID (11k & 11v) */ -#define DOT11_NGBR_TSF_INFO_SE_ID 1 -#define DOT11_NGBR_CCS_SE_ID 2 -#define DOT11_NGBR_BSSTRANS_PREF_SE_ID 3 -#define DOT11_NGBR_BSS_TERM_DUR_SE_ID 4 -#define DOT11_NGBR_BEARING_SE_ID 5 -#define DOT11_NGBR_WIDE_BW_CHAN_SE_ID 6 /* proposed */ - -/** Neighbor Report, BSS Transition Candidate Preference subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bsstrans_pref_se { - uint8 sub_id; - uint8 len; - uint8 preference; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ngbr_bsstrans_pref_se dot11_ngbr_bsstrans_pref_se_t; -#define DOT11_NGBR_BSSTRANS_PREF_SE_LEN 1 -#define DOT11_NGBR_BSSTRANS_PREF_SE_IE_LEN 3 -#define DOT11_NGBR_BSSTRANS_PREF_SE_HIGHEST 0xff - -/** Neighbor Report, BSS Termination Duration subelement */ -BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bss_term_dur_se { - uint8 sub_id; - uint8 len; - uint8 tsf[8]; - uint16 duration; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ngbr_bss_term_dur_se dot11_ngbr_bss_term_dur_se_t; -#define DOT11_NGBR_BSS_TERM_DUR_SE_LEN 10 - -/* Neighbor Report BSSID Information Field */ -#define DOT11_NGBR_BI_REACHABILTY_UNKN 0x0002 -#define DOT11_NGBR_BI_REACHABILTY 0x0003 -#define DOT11_NGBR_BI_SEC 0x0004 -#define DOT11_NGBR_BI_KEY_SCOPE 0x0008 -#define DOT11_NGBR_BI_CAP 0x03f0 -#define DOT11_NGBR_BI_CAP_SPEC_MGMT 0x0010 -#define DOT11_NGBR_BI_CAP_QOS 0x0020 -#define DOT11_NGBR_BI_CAP_APSD 0x0040 -#define DOT11_NGBR_BI_CAP_RDIO_MSMT 0x0080 -#define DOT11_NGBR_BI_CAP_DEL_BA 0x0100 -#define DOT11_NGBR_BI_CAP_IMM_BA 0x0200 -#define DOT11_NGBR_BI_MOBILITY 0x0400 -#define DOT11_NGBR_BI_HT 0x0800 -#define DOT11_NGBR_BI_VHT 0x1000 -#define DOT11_NGBR_BI_FTM 0x2000 - -/** Neighbor Report element (11k & 11v) */ -BWL_PRE_PACKED_STRUCT struct dot11_neighbor_rep_ie { - uint8 id; - uint8 len; - struct ether_addr bssid; - uint32 bssid_info; - uint8 reg; /* Operating class */ - uint8 channel; - uint8 phytype; - uint8 data[1]; /* Variable size subelements */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_neighbor_rep_ie dot11_neighbor_rep_ie_t; -#define DOT11_NEIGHBOR_REP_IE_FIXED_LEN 13u - /* MLME Enumerations */ #define DOT11_BSSTYPE_INFRASTRUCTURE 0 /* d11 infrastructure */ #define DOT11_BSSTYPE_INDEPENDENT 1 /* d11 independent */ @@ -3942,87 +2213,6 @@ typedef struct dot11_neighbor_rep_ie dot11_neighbor_rep_ie_t; #define DOT11_SCANTYPE_ACTIVE 0 /* d11 scan active */ #define DOT11_SCANTYPE_PASSIVE 1 /* d11 scan passive */ -/** Link Measurement */ -BWL_PRE_PACKED_STRUCT struct dot11_lmreq { - uint8 category; /* category of action frame (5) */ - uint8 action; /* radio measurement action */ - uint8 token; /* dialog token */ - uint8 txpwr; /* Transmit Power Used */ - uint8 maxtxpwr; /* Max Transmit Power */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_lmreq dot11_lmreq_t; -#define DOT11_LMREQ_LEN 5 - -BWL_PRE_PACKED_STRUCT struct dot11_lmrep { - uint8 category; /* category of action frame (5) */ - uint8 action; /* radio measurement action */ - uint8 token; /* dialog token */ - dot11_tpc_rep_t tpc; /* TPC element */ - uint8 rxant; /* Receive Antenna ID */ - uint8 txant; /* Transmit Antenna ID */ - uint8 rcpi; /* RCPI */ - uint8 rsni; /* RSNI */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_lmrep dot11_lmrep_t; -#define DOT11_LMREP_LEN 11 - -#define DOT11_MP_CAP_SPECTRUM 0x01 /* d11 cap. spectrum */ -#define DOT11_MP_CAP_SHORTSLOT 0x02 /* d11 cap. shortslot */ -/* Measurement Pilot */ -BWL_PRE_PACKED_STRUCT struct dot11_mprep { - uint8 cap_info; /* Condensed capability Info. */ - uint8 country[2]; /* Condensed country string */ - uint8 opclass; /* Op. Class */ - uint8 channel; /* Channel */ - uint8 mp_interval; /* Measurement Pilot Interval */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_mprep dot11_mprep_t; -#define DOT11_MPREP_LEN 6 - -/* 802.11 BRCM "Compromise" Pre N constants */ -#define PREN_PREAMBLE 24 /* green field preamble time */ -#define PREN_MM_EXT 12 /* extra mixed mode preamble time */ -#define PREN_PREAMBLE_EXT 4 /* extra preamble (multiply by unique_streams-1) */ - -/* 802.11N PHY constants */ -#define RIFS_11N_TIME 2 /* NPHY RIFS time */ - -/* 802.11 HT PLCP format 802.11n-2009, sec 20.3.9.4.3 - * HT-SIG is composed of two 24 bit parts, HT-SIG1 and HT-SIG2 - */ -/* HT-SIG1 */ -#define HT_SIG1_MCS_MASK 0x00007F -#define HT_SIG1_CBW 0x000080 -#define HT_SIG1_HT_LENGTH 0xFFFF00 - -/* HT-SIG2 */ -#define HT_SIG2_SMOOTHING 0x000001 -#define HT_SIG2_NOT_SOUNDING 0x000002 -#define HT_SIG2_RESERVED 0x000004 -#define HT_SIG2_AGGREGATION 0x000008 -#define HT_SIG2_STBC_MASK 0x000030 -#define HT_SIG2_STBC_SHIFT 4 -#define HT_SIG2_FEC_CODING 0x000040 -#define HT_SIG2_SHORT_GI 0x000080 -#define HT_SIG2_ESS_MASK 0x000300 -#define HT_SIG2_ESS_SHIFT 8 -#define HT_SIG2_CRC 0x03FC00 -#define HT_SIG2_TAIL 0x1C0000 - -/* HT Timing-related parameters (802.11-2012, sec 20.3.6) */ -#define HT_T_LEG_PREAMBLE 16 -#define HT_T_L_SIG 4 -#define HT_T_SIG 8 -#define HT_T_LTF1 4 -#define HT_T_GF_LTF1 8 -#define HT_T_LTFs 4 -#define HT_T_STF 4 -#define HT_T_GF_STF 8 -#define HT_T_SYML 4 - -#define HT_N_SERVICE 16 /* bits in SERVICE field */ -#define HT_N_TAIL 6 /* tail bits per BCC encoder */ - /* 802.11 A PHY constants */ #define APHY_SLOT_TIME 9 /* APHY slot time */ #define APHY_SIFS_TIME 16 /* APHY SIFS time */ @@ -4052,219 +2242,6 @@ typedef struct dot11_mprep dot11_mprep_t; #define DOT11_MAXNUMFRAGS 16 /* max # fragments per MSDU */ -/* 802.11 VHT constants */ - -typedef int vht_group_id_t; - -/* for VHT-A1 */ -/* SIG-A1 reserved bits */ -#define VHT_SIGA1_CONST_MASK 0x800004 - -#define VHT_SIGA1_BW_MASK 0x000003 -#define VHT_SIGA1_20MHZ_VAL 0x000000 -#define VHT_SIGA1_40MHZ_VAL 0x000001 -#define VHT_SIGA1_80MHZ_VAL 0x000002 -#define VHT_SIGA1_160MHZ_VAL 0x000003 - -#define VHT_SIGA1_STBC 0x000008 - -#define VHT_SIGA1_GID_MASK 0x0003f0 -#define VHT_SIGA1_GID_SHIFT 4 -#define VHT_SIGA1_GID_TO_AP 0x00 -#define VHT_SIGA1_GID_NOT_TO_AP 0x3f -#define VHT_SIGA1_GID_MAX_GID 0x3f - -#define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00 -#define VHT_SIGA1_NSTS_SHIFT 10 -#define VHT_SIGA1_MAX_USERPOS 3 - -#define VHT_SIGA1_PARTIAL_AID_MASK 0x3fe000 -#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 - -#define VHT_SIGA1_TXOP_PS_NOT_ALLOWED 0x400000 - -/* for VHT-A2 */ -#define VHT_SIGA2_GI_NONE 0x000000 -#define VHT_SIGA2_GI_SHORT 0x000001 -#define VHT_SIGA2_GI_W_MOD10 0x000002 -#define VHT_SIGA2_CODING_LDPC 0x000004 -#define VHT_SIGA2_LDPC_EXTRA_OFDM_SYM 0x000008 -#define VHT_SIGA2_BEAMFORM_ENABLE 0x000100 -#define VHT_SIGA2_MCS_SHIFT 4 - -#define VHT_SIGA2_B9_RESERVED 0x000200 -#define VHT_SIGA2_TAIL_MASK 0xfc0000 -#define VHT_SIGA2_TAIL_VALUE 0x000000 - -/* VHT Timing-related parameters (802.11ac D4.0, sec 22.3.6) */ -#define VHT_T_LEG_PREAMBLE 16 -#define VHT_T_L_SIG 4 -#define VHT_T_SIG_A 8 -#define VHT_T_LTF 4 -#define VHT_T_STF 4 -#define VHT_T_SIG_B 4 -#define VHT_T_SYML 4 - -#define VHT_N_SERVICE 16 /* bits in SERVICE field */ -#define VHT_N_TAIL 6 /* tail bits per BCC encoder */ - -/** dot11Counters Table - 802.11 spec., Annex D */ -typedef struct d11cnt { - uint32 txfrag; /* dot11TransmittedFragmentCount */ - uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ - uint32 txfail; /* dot11FailedCount */ - uint32 txretry; /* dot11RetryCount */ - uint32 txretrie; /* dot11MultipleRetryCount */ - uint32 rxdup; /* dot11FrameduplicateCount */ - uint32 txrts; /* dot11RTSSuccessCount */ - uint32 txnocts; /* dot11RTSFailureCount */ - uint32 txnoack; /* dot11ACKFailureCount */ - uint32 rxfrag; /* dot11ReceivedFragmentCount */ - uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ - uint32 rxcrc; /* dot11FCSErrorCount */ - uint32 txfrmsnt; /* dot11TransmittedFrameCount */ - uint32 rxundec; /* dot11WEPUndecryptableCount */ -} d11cnt_t; - -/* OUI for BRCM proprietary IE */ -#define BRCM_PROP_OUI "\x00\x90\x4C" /* Broadcom proprietary OUI */ - -/* Broadcom Proprietary OUI type list. Please update below page when adding a new type. - * Twiki http://hwnbu-twiki.sj.broadcom.com/bin/view/Mwgroup/WlBrcmPropIE - */ -/* The following BRCM_PROP_OUI types are currently in use (defined in - * relevant subsections). Each of them will be in a separate proprietary(221) IE - * #define RWL_WIFI_DEFAULT 0 - * #define SES_VNDR_IE_TYPE 1 (defined in src/ses/shared/ses.h) - * #define VHT_FEATURES_IE_TYPE 4 - * #define RWL_WIFI_FIND_MY_PEER 9 - * #define RWL_WIFI_FOUND_PEER 10 - * #define PROXD_IE_TYPE 11 - */ - -#define BRCM_FTM_IE_TYPE 14 - -/* #define HT_CAP_IE_TYPE 51 - * #define HT_ADD_IE_TYPE 52 - * #define BRCM_EXTCH_IE_TYPE 53 - * #define MEMBER_OF_BRCM_PROP_IE_TYPE 54 - * #define BRCM_RELMACST_IE_TYPE 55 - * #define BRCM_EVT_WL_BSS_INFO 64 - * #define RWL_ACTION_WIFI_FRAG_TYPE 85 - * #define BTC_INFO_BRCM_PROP_IE_TYPE 90 - * #define ULB_BRCM_PROP_IE_TYPE 91 - * #define SDB_BRCM_PROP_IE_TYPE 92 - */ - -/* Action frame type for RWL */ -#define RWL_WIFI_DEFAULT 0 -#define RWL_WIFI_FIND_MY_PEER 9 /* Used while finding server */ -#define RWL_WIFI_FOUND_PEER 10 /* Server response to the client */ -#define RWL_ACTION_WIFI_FRAG_TYPE 85 /* Fragment indicator for receiver */ - -#define PROXD_AF_TYPE 11 /* Wifi proximity action frame type */ -#define BRCM_RELMACST_AF_TYPE 12 /* RMC action frame type */ - -/* Action frame type for FTM Initiator Report */ -#define BRCM_FTM_VS_AF_TYPE 14 -enum { - BRCM_FTM_VS_INITIATOR_RPT_SUBTYPE = 1, /* FTM Initiator Report */ - BRCM_FTM_VS_COLLECT_SUBTYPE = 2, /* FTM Collect debug protocol */ -}; - -/* Action frame type for vendor specific action frames */ -#define VS_AF_TYPE 221 - -#ifdef WL_VS_AFTX -/* Vendor specific action frame subtype for transmit using SU EDCA */ -#define VS_AF_SUBTYPE_SUEDCA 1 - -#define VENDOR_PROP_OUI "\x00\x17\xF2" -#endif /* WL_VS_AFTX */ - -/* - * This BRCM_PROP_OUI types is intended for use in events to embed additional - * data, and would not be expected to appear on the air -- but having an IE - * format allows IE frame data with extra data in events in that allows for - * more flexible parsing. - */ -#define BRCM_EVT_WL_BSS_INFO 64 - -/** - * Following is the generic structure for brcm_prop_ie (uses BRCM_PROP_OUI). - * DPT uses this format with type set to DPT_IE_TYPE - */ -BWL_PRE_PACKED_STRUCT struct brcm_prop_ie_s { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ - uint8 type; /* type of this IE */ - uint16 cap; /* DPT capabilities */ -} BWL_POST_PACKED_STRUCT; -typedef struct brcm_prop_ie_s brcm_prop_ie_t; - -#define BRCM_PROP_IE_LEN 6 /* len of fixed part of brcm_prop ie */ - -#define DPT_IE_TYPE 2 - -#define BRCM_SYSCAP_IE_TYPE 3 -#define WET_TUNNEL_IE_TYPE 3 - -/* brcm syscap_ie cap */ -#define BRCM_SYSCAP_WET_TUNNEL 0x0100 /* Device with WET_TUNNEL support */ - -/* BRCM OUI: Used in the proprietary(221) IE in all broadcom devices */ -#define BRCM_OUI "\x00\x10\x18" /* Broadcom OUI */ - -/** BRCM info element */ -BWL_PRE_PACKED_STRUCT struct brcm_ie { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[3]; /* Proprietary OUI, BRCM_OUI */ - uint8 ver; /* type/ver of this IE */ - uint8 assoc; /* # of assoc STAs */ - uint8 flags; /* misc flags */ - uint8 flags1; /* misc flags */ - uint16 amsdu_mtu_pref; /* preferred A-MSDU MTU */ - uint8 flags2; /* Bit 0: DTPC TX cap, Bit 1: DTPC Recv Cap */ -} BWL_POST_PACKED_STRUCT; -typedef struct brcm_ie brcm_ie_t; -#define BRCM_IE_LEN 12u /* BRCM IE length */ -#define BRCM_IE_VER 2u /* BRCM IE version */ -#define BRCM_IE_LEGACY_AES_VER 1u /* BRCM IE legacy AES version */ - -/* brcm_ie flags */ -#define BRF_ABCAP 0x1 /* afterburner is obsolete, defined for backward compat */ -#define BRF_ABRQRD 0x2 /* afterburner is obsolete, defined for backward compat */ -#define BRF_LZWDS 0x4 /* lazy wds enabled */ -#define BRF_BLOCKACK 0x8 /* BlockACK capable */ -#define BRF_ABCOUNTER_MASK 0xf0 /* afterburner is obsolete, defined for backward compat */ -#define BRF_PROP_11N_MCS 0x10 /* re-use afterburner bit */ -#define BRF_MEDIA_CLIENT 0x20 /* re-use afterburner bit to indicate media client device */ - -/** - * Support for Broadcom proprietary HT MCS rates. Re-uses afterburner bits since - * afterburner is not used anymore. Checks for BRF_ABCAP to stay compliant with 'old' - * images in the field. - */ -#define GET_BRF_PROP_11N_MCS(brcm_ie) \ - (!((brcm_ie)->flags & BRF_ABCAP) && ((brcm_ie)->flags & BRF_PROP_11N_MCS)) - -/* brcm_ie flags1 */ -#define BRF1_AMSDU 0x1 /* A-MSDU capable */ -#define BRF1_WNM 0x2 /* WNM capable */ -#define BRF1_WMEPS 0x4 /* AP is capable of handling WME + PS w/o APSD */ -#define BRF1_PSOFIX 0x8 /* AP has fixed PS mode out-of-order packets */ -#define BRF1_RX_LARGE_AGG 0x10 /* device can rx large aggregates */ -#define BRF1_RFAWARE_DCS 0x20 /* RFAWARE dynamic channel selection (DCS) */ -#define BRF1_SOFTAP 0x40 /* Configure as Broadcom SOFTAP */ -#define BRF1_DWDS 0x80 /* DWDS capable */ - -/* brcm_ie flags2 */ -#define BRF2_DTPC_TX 0x1u /* DTPC: DTPC TX Cap */ -#define BRF2_DTPC_RX 0x2u /* DTPC: DTPC RX Cap */ -#define BRF2_DTPC_TX_RX 0x3u /* DTPC: Enable Both DTPC TX and RX Cap */ - /** Vendor IE structure */ BWL_PRE_PACKED_STRUCT struct vndr_ie { uchar id; @@ -4280,651 +2257,63 @@ typedef struct vndr_ie vndr_ie_t; #define VNDR_IE_MAX_LEN 255u /* vendor IE max length, without ID and len */ -/** BRCM PROP DEVICE PRIMARY MAC ADDRESS IE */ -BWL_PRE_PACKED_STRUCT struct member_of_brcm_prop_ie { - uchar id; - uchar len; - uchar oui[3]; - uint8 type; /* type indicates what follows */ - struct ether_addr ea; /* Device Primary MAC Adrress */ -} BWL_POST_PACKED_STRUCT; -typedef struct member_of_brcm_prop_ie member_of_brcm_prop_ie_t; - -#define MEMBER_OF_BRCM_PROP_IE_LEN 10 /* IE max length */ -#define MEMBER_OF_BRCM_PROP_IE_HDRLEN (sizeof(member_of_brcm_prop_ie_t)) -#define MEMBER_OF_BRCM_PROP_IE_TYPE 54 /* used in prop IE 221 only */ - -/** BRCM Reliable Multicast IE */ -BWL_PRE_PACKED_STRUCT struct relmcast_brcm_prop_ie { - uint8 id; - uint8 len; - uint8 oui[3]; - uint8 type; /* type indicates what follows */ - struct ether_addr ea; /* The ack sender's MAC Adrress */ - struct ether_addr mcast_ea; /* The multicast MAC address */ - uint8 updtmo; /* time interval(second) for client to send null packet to report its rssi */ -} BWL_POST_PACKED_STRUCT; -typedef struct relmcast_brcm_prop_ie relmcast_brcm_prop_ie_t; - -/* IE length */ -/* BRCM_PROP_IE_LEN = sizeof(relmcast_brcm_prop_ie_t)-((sizeof (id) + sizeof (len)))? */ -#define RELMCAST_BRCM_PROP_IE_LEN (sizeof(relmcast_brcm_prop_ie_t)-(2*sizeof(uint8))) - -#define RELMCAST_BRCM_PROP_IE_TYPE 55 /* used in prop IE 221 only */ - -/* BRCM BTC IE */ -BWL_PRE_PACKED_STRUCT struct btc_brcm_prop_ie { - uint8 id; - uint8 len; - uint8 oui[3]; - uint8 type; /* type inidicates what follows */ - uint32 info; -} BWL_POST_PACKED_STRUCT; -typedef struct btc_brcm_prop_ie btc_brcm_prop_ie_t; - -#define BTC_INFO_BRCM_PROP_IE_TYPE 90 -#define BRCM_BTC_INFO_TYPE_LEN (sizeof(btc_brcm_prop_ie_t) - (2 * sizeof(uint8))) - -/* ************* HT definitions. ************* */ -#define MCSSET_LEN 16 /* 16-bits per 8-bit set to give 128-bits bitmap of MCS Index */ -#define MAX_MCS_NUM (128) /* max mcs number = 128 */ -#define BASIC_HT_MCS 0xFFu /* HT MCS supported rates */ - -BWL_PRE_PACKED_STRUCT struct ht_cap_ie { - uint16 cap; - uint8 params; - uint8 supp_mcs[MCSSET_LEN]; - uint16 ext_htcap; - uint32 txbf_cap; - uint8 as_cap; -} BWL_POST_PACKED_STRUCT; -typedef struct ht_cap_ie ht_cap_ie_t; - -BWL_PRE_PACKED_STRUCT struct dot11_ht_cap_ie { - uint8 id; - uint8 len; - ht_cap_ie_t ht_cap; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ht_cap_ie dot11_ht_cap_ie_t; - -/* CAP IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ -/* the capability IE is primarily used to convey this nodes abilities */ -BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ - uint8 type; /* type indicates what follows */ - ht_cap_ie_t cap_ie; -} BWL_POST_PACKED_STRUCT; -typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; - -#define HT_PROP_IE_OVERHEAD 4 /* overhead bytes for prop oui ie */ -#define HT_CAP_IE_LEN 26 /* HT capability len (based on .11n d2.0) */ -#define HT_CAP_IE_TYPE 51 /* used in prop IE 221 only */ - -#define HT_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ -#define HT_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ -#define HT_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ -#define HT_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ -#define HT_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ -#define HT_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ -#define HT_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ -#define HT_CAP_GF 0x0010 /* Greenfield preamble support */ -#define HT_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ -#define HT_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ -#define HT_CAP_TX_STBC 0x0080 /* Tx STBC support */ -#define HT_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ -#define HT_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ -#define HT_CAP_DELAYED_BA 0x0400 /* delayed BA support */ -#define HT_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ - -#define HT_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ -#define HT_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ -#define HT_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ -#define HT_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ - -#define HT_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ -#define HT_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ -#define HT_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ -#define HT_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ - -#define HT_CAP_TXBF_CAP_IMPLICIT_TXBF_RX 0x1 -#define HT_CAP_TXBF_CAP_NDP_RX 0x8 -#define HT_CAP_TXBF_CAP_NDP_TX 0x10 -#define HT_CAP_TXBF_CAP_EXPLICIT_CSI 0x100 -#define HT_CAP_TXBF_CAP_EXPLICIT_NC_STEERING 0x200 -#define HT_CAP_TXBF_CAP_EXPLICIT_C_STEERING 0x400 -#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_MASK 0x1800 -#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_SHIFT 11 -#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_MASK 0x6000 -#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_SHIFT 13 -#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_MASK 0x18000 -#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_SHIFT 15 -#define HT_CAP_TXBF_CAP_CSI_BFR_ANT_SHIFT 19 -#define HT_CAP_TXBF_CAP_NC_BFR_ANT_SHIFT 21 -#define HT_CAP_TXBF_CAP_C_BFR_ANT_SHIFT 23 -#define HT_CAP_TXBF_CAP_C_BFR_ANT_MASK 0x1800000 - -#define HT_CAP_TXBF_CAP_CHAN_ESTIM_SHIFT 27 -#define HT_CAP_TXBF_CAP_CHAN_ESTIM_MASK 0x18000000 - -#define HT_CAP_TXBF_FB_TYPE_NONE 0 -#define HT_CAP_TXBF_FB_TYPE_DELAYED 1 -#define HT_CAP_TXBF_FB_TYPE_IMMEDIATE 2 -#define HT_CAP_TXBF_FB_TYPE_BOTH 3 - -#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_MASK 0x400 -#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_SHIFT 10 -#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_MASK 0x18000 -#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_SHIFT 15 - -#define HT_CAP_MCS_FLAGS_SUPP_BYTE 12 /* byte offset in HT Cap Supported MCS for various flags */ -#define HT_CAP_MCS_RX_8TO15_BYTE_OFFSET 1 -#define HT_CAP_MCS_FLAGS_TX_RX_UNEQUAL 0x02 -#define HT_CAP_MCS_FLAGS_MAX_SPATIAL_STREAM_MASK 0x0C - -#define VHT_MAX_MPDU 11454 /* max mpdu size for now (bytes) */ -#define VHT_MPDU_MSDU_DELTA 56 /* Difference in spec - vht mpdu, amsdu len */ -/* Max AMSDU len - per spec */ -#define VHT_MAX_AMSDU (VHT_MAX_MPDU - VHT_MPDU_MSDU_DELTA) - -#define HT_MAX_AMSDU 7935 /* max amsdu size (bytes) per the HT spec */ -#define HT_MIN_AMSDU 3835 /* min amsdu size (bytes) per the HT spec */ - -#define HT_PARAMS_RX_FACTOR_MASK 0x03 /* ampdu rcv factor mask */ -#define HT_PARAMS_DENSITY_MASK 0x1C /* ampdu density mask */ -#define HT_PARAMS_DENSITY_SHIFT 2 /* ampdu density shift */ - /* HT/AMPDU specific define */ -#define AMPDU_MAX_MPDU_DENSITY 7 /* max mpdu density; in 1/4 usec units */ -#define AMPDU_DENSITY_NONE 0 /* No density requirement */ -#define AMPDU_DENSITY_1over4_US 1 /* 1/4 us density */ -#define AMPDU_DENSITY_1over2_US 2 /* 1/2 us density */ -#define AMPDU_DENSITY_1_US 3 /* 1 us density */ -#define AMPDU_DENSITY_2_US 4 /* 2 us density */ -#define AMPDU_DENSITY_4_US 5 /* 4 us density */ -#define AMPDU_DENSITY_8_US 6 /* 8 us density */ -#define AMPDU_DENSITY_16_US 7 /* 16 us density */ -#define AMPDU_RX_FACTOR_8K 0 /* max rcv ampdu len (8kb) */ -#define AMPDU_RX_FACTOR_16K 1 /* max rcv ampdu len (16kb) */ -#define AMPDU_RX_FACTOR_32K 2 /* max rcv ampdu len (32kb) */ -#define AMPDU_RX_FACTOR_64K 3 /* max rcv ampdu len (64kb) */ +#define AMPDU_MAX_MPDU_DENSITY 7 /* max mpdu density; in 1/4 usec units */ +#define AMPDU_DENSITY_NONE 0 /* No density requirement */ +#define AMPDU_DENSITY_1over4_US 1 /* 1/4 us density */ +#define AMPDU_DENSITY_1over2_US 2 /* 1/2 us density */ +#define AMPDU_DENSITY_1_US 3 /* 1 us density */ +#define AMPDU_DENSITY_2_US 4 /* 2 us density */ +#define AMPDU_DENSITY_4_US 5 /* 4 us density */ +#define AMPDU_DENSITY_8_US 6 /* 8 us density */ +#define AMPDU_DENSITY_16_US 7 /* 16 us density */ +#define AMPDU_RX_FACTOR_8K 0 /* max rcv ampdu len (8kb) */ +#define AMPDU_RX_FACTOR_16K 1 /* max rcv ampdu len (16kb) */ +#define AMPDU_RX_FACTOR_32K 2 /* max rcv ampdu len (32kb) */ +#define AMPDU_RX_FACTOR_64K 3 /* max rcv ampdu len (64kb) */ /* AMPDU RX factors for VHT rates */ -#define AMPDU_RX_FACTOR_128K 4 /* max rcv ampdu len (128kb) */ -#define AMPDU_RX_FACTOR_256K 5 /* max rcv ampdu len (256kb) */ -#define AMPDU_RX_FACTOR_512K 6 /* max rcv ampdu len (512kb) */ -#define AMPDU_RX_FACTOR_1024K 7 /* max rcv ampdu len (1024kb) */ +#define AMPDU_RX_FACTOR_128K 4 /* max rcv ampdu len (128kb) */ +#define AMPDU_RX_FACTOR_256K 5 /* max rcv ampdu len (256kb) */ +#define AMPDU_RX_FACTOR_512K 6 /* max rcv ampdu len (512kb) */ +#define AMPDU_RX_FACTOR_1024K 7 /* max rcv ampdu len (1024kb) */ -#define AMPDU_RX_FACTOR_BASE 8*1024 /* ampdu factor base for rx len */ +#define AMPDU_RX_FACTOR_BASE 8*1024 /* ampdu factor base for rx len */ #define AMPDU_RX_FACTOR_BASE_PWR 13 /* ampdu factor base for rx len in power of 2 */ - -#define AMPDU_DELIMITER_LEN 4u /* length of ampdu delimiter */ -#define AMPDU_DELIMITER_LEN_MAX 63 /* max length of ampdu delimiter(enforced in HW) */ - -#define HT_CAP_EXT_PCO 0x0001 -#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006 -#define HT_CAP_EXT_PCO_TTIME_SHIFT 1 -#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300 -#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8 -#define HT_CAP_EXT_HTC 0x0400 -#define HT_CAP_EXT_RD_RESP 0x0800 - -/** 'ht_add' is called 'HT Operation' information element in the 802.11 standard */ -BWL_PRE_PACKED_STRUCT struct ht_add_ie { - uint8 ctl_ch; /* control channel number */ - uint8 byte1; /* ext ch,rec. ch. width, RIFS support */ - uint16 opmode; /* operation mode */ - uint16 misc_bits; /* misc bits */ - uint8 basic_mcs[MCSSET_LEN]; /* required MCS set */ -} BWL_POST_PACKED_STRUCT; -typedef struct ht_add_ie ht_add_ie_t; - -/* ADD IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ -/* the additional IE is primarily used to convey the current BSS configuration */ -BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ - uint8 type; /* indicates what follows */ - ht_add_ie_t add_ie; -} BWL_POST_PACKED_STRUCT; -typedef struct ht_prop_add_ie ht_prop_add_ie_t; - -#define HT_ADD_IE_LEN 22 /* HT capability len (based on .11n d1.0) */ -#define HT_ADD_IE_TYPE 52 /* faked out as current spec is illegal */ - -/* byte1 defn's */ -#define HT_BW_ANY 0x04 /* set, STA can use 20 or 40MHz */ -#define HT_RIFS_PERMITTED 0x08 /* RIFS allowed */ - -/* opmode defn's */ -#define HT_OPMODE_MASK 0x0003 /* protection mode mask */ -#define HT_OPMODE_SHIFT 0 /* protection mode shift */ -#define HT_OPMODE_PURE 0x0000 /* protection mode PURE */ -#define HT_OPMODE_OPTIONAL 0x0001 /* protection mode optional */ -#define HT_OPMODE_HT20IN40 0x0002 /* protection mode 20MHz HT in 40MHz BSS */ -#define HT_OPMODE_MIXED 0x0003 /* protection mode Mixed Mode */ -#define HT_OPMODE_NONGF 0x0004 /* protection mode non-GF */ -#define DOT11N_TXBURST 0x0008 /* Tx burst limit */ -#define DOT11N_OBSS_NONHT 0x0010 /* OBSS Non-HT STA present */ -#define HT_OPMODE_CCFS2_MASK 0x1fe0 /* Channel Center Frequency Segment 2 mask */ -#define HT_OPMODE_CCFS2_SHIFT 5 /* Channel Center Frequency Segment 2 shift */ - -/* misc_bites defn's */ -#define HT_BASIC_STBC_MCS 0x007f /* basic STBC MCS */ -#define HT_DUAL_STBC_PROT 0x0080 /* Dual STBC Protection */ -#define HT_SECOND_BCN 0x0100 /* Secondary beacon support */ -#define HT_LSIG_TXOP 0x0200 /* L-SIG TXOP Protection full support */ -#define HT_PCO_ACTIVE 0x0400 /* PCO active */ -#define HT_PCO_PHASE 0x0800 /* PCO phase */ -#define HT_DUALCTS_PROTECTION 0x0080 /* DUAL CTS protection needed */ - -/* Tx Burst Limits */ -#define DOT11N_2G_TXBURST_LIMIT 6160 /* 2G band Tx burst limit per 802.11n Draft 1.10 (usec) */ -#define DOT11N_5G_TXBURST_LIMIT 3080 /* 5G band Tx burst limit per 802.11n Draft 1.10 (usec) */ - -/* Macros for opmode */ -#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - >> HT_OPMODE_SHIFT) -#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - == HT_OPMODE_MIXED) /* mixed mode present */ -#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - == HT_OPMODE_HT20IN40) /* 20MHz HT present */ -#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - == HT_OPMODE_OPTIONAL) /* Optional protection present */ -#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ - HT_MIXEDMODE_PRESENT((add_ie))) /* use protection */ -#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ - == HT_OPMODE_NONGF) /* non-GF present */ -#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ - == DOT11N_TXBURST) /* Tx Burst present */ -#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ - == DOT11N_OBSS_NONHT) /* OBSS Non-HT present */ -#define HT_OPMODE_CCFS2_GET(add_ie) ((ltoh16_ua(&(add_ie)->opmode) & HT_OPMODE_CCFS2_MASK) \ - >> HT_OPMODE_CCFS2_SHIFT) /* get CCFS2 */ -#define HT_OPMODE_CCFS2_SET(add_ie, ccfs2) do { /* set CCFS2 */ \ - (add_ie)->opmode &= htol16(~HT_OPMODE_CCFS2_MASK); \ - (add_ie)->opmode |= htol16(((ccfs2) << HT_OPMODE_CCFS2_SHIFT) & HT_OPMODE_CCFS2_MASK); \ -} while (0) - -/* Macros for HT MCS field access */ -#define HT_CAP_MCS_BITMASK(supp_mcs) \ - ((supp_mcs)[HT_CAP_MCS_RX_8TO15_BYTE_OFFSET]) -#define HT_CAP_MCS_TX_RX_UNEQUAL(supp_mcs) \ - ((supp_mcs)[HT_CAP_MCS_FLAGS_SUPP_BYTE] & HT_CAP_MCS_FLAGS_TX_RX_UNEQUAL) -#define HT_CAP_MCS_TX_STREAM_SUPPORT(supp_mcs) \ - ((supp_mcs)[HT_CAP_MCS_FLAGS_SUPP_BYTE] & HT_CAP_MCS_FLAGS_MAX_SPATIAL_STREAM_MASK) - -BWL_PRE_PACKED_STRUCT struct obss_params { - uint16 passive_dwell; - uint16 active_dwell; - uint16 bss_widthscan_interval; - uint16 passive_total; - uint16 active_total; - uint16 chanwidth_transition_dly; - uint16 activity_threshold; -} BWL_POST_PACKED_STRUCT; -typedef struct obss_params obss_params_t; - -BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { - uint8 id; - uint8 len; - obss_params_t obss_params; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_obss_ie dot11_obss_ie_t; -#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) /* HT OBSS len (based on 802.11n d3.0) */ - -/* HT control field */ -#define HT_CTRL_LA_TRQ 0x00000002 /* sounding request */ -#define HT_CTRL_LA_MAI 0x0000003C /* MCS request or antenna selection indication */ -#define HT_CTRL_LA_MAI_SHIFT 2 -#define HT_CTRL_LA_MAI_MRQ 0x00000004 /* MCS request */ -#define HT_CTRL_LA_MAI_MSI 0x00000038 /* MCS request sequence identifier */ -#define HT_CTRL_LA_MFSI 0x000001C0 /* MFB sequence identifier */ -#define HT_CTRL_LA_MFSI_SHIFT 6 -#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 /* MCS feedback, antenna selection command/data */ -#define HT_CTRL_LA_MFB_ASELC_SH 9 -#define HT_CTRL_LA_ASELC_CMD 0x00000C00 /* ASEL command */ -#define HT_CTRL_LA_ASELC_DATA 0x0000F000 /* ASEL data */ -#define HT_CTRL_CAL_POS 0x00030000 /* Calibration position */ -#define HT_CTRL_CAL_SEQ 0x000C0000 /* Calibration sequence */ -#define HT_CTRL_CSI_STEERING 0x00C00000 /* CSI/Steering */ -#define HT_CTRL_CSI_STEER_SHIFT 22 -#define HT_CTRL_CSI_STEER_NFB 0 /* no fedback required */ -#define HT_CTRL_CSI_STEER_CSI 1 /* CSI, H matrix */ -#define HT_CTRL_CSI_STEER_NCOM 2 /* non-compressed beamforming */ -#define HT_CTRL_CSI_STEER_COM 3 /* compressed beamforming */ -#define HT_CTRL_NDP_ANNOUNCE 0x01000000 /* NDP announcement */ -#define HT_CTRL_AC_CONSTRAINT 0x40000000 /* AC Constraint */ -#define HT_CTRL_RDG_MOREPPDU 0x80000000 /* RDG/More PPDU */ - -/* ************* VHT definitions. ************* */ - -/** - * VHT Capabilites IE (sec 8.4.2.160) - */ - -BWL_PRE_PACKED_STRUCT struct vht_cap_ie { - uint32 vht_cap_info; - /* supported MCS set - 64 bit field */ - uint16 rx_mcs_map; - uint16 rx_max_rate; - uint16 tx_mcs_map; - uint16 tx_max_rate; -} BWL_POST_PACKED_STRUCT; -typedef struct vht_cap_ie vht_cap_ie_t; - -/* 4B cap_info + 8B supp_mcs */ -#define VHT_CAP_IE_LEN 12 - -/* VHT Capabilities Info field - 32bit - in VHT Cap IE */ -#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 -#define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c -#define VHT_CAP_INFO_LDPC 0x00000010 -#define VHT_CAP_INFO_SGI_80MHZ 0x00000020 -#define VHT_CAP_INFO_SGI_160MHZ 0x00000040 -#define VHT_CAP_INFO_TX_STBC 0x00000080 -#define VHT_CAP_INFO_RX_STBC_MASK 0x00000700 -#define VHT_CAP_INFO_RX_STBC_SHIFT 8u -#define VHT_CAP_INFO_SU_BEAMFMR 0x00000800 -#define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000 -#define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000 -#define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13u -#define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000 -#define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16u -#define VHT_CAP_INFO_MU_BEAMFMR 0x00080000 -#define VHT_CAP_INFO_MU_BEAMFMEE 0x00100000 -#define VHT_CAP_INFO_TXOPPS 0x00200000 -#define VHT_CAP_INFO_HTCVHT 0x00400000 -#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000 -#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23u -#define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000 -#define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26u -#define VHT_CAP_INFO_EXT_NSS_BW_SUP_MASK 0xc0000000 -#define VHT_CAP_INFO_EXT_NSS_BW_SUP_SHIFT 30u - -/* get Extended NSS BW Support passing vht cap info */ -#define VHT_CAP_EXT_NSS_BW_SUP(cap_info) \ - (((cap_info) & VHT_CAP_INFO_EXT_NSS_BW_SUP_MASK) >> VHT_CAP_INFO_EXT_NSS_BW_SUP_SHIFT) - -/* VHT CAP INFO extended NSS BW support - refer to IEEE 802.11 REVmc D8.0 Figure 9-559 */ -#define VHT_CAP_INFO_EXT_NSS_BW_HALF_160 1 /* 160MHz at half NSS CAP */ -#define VHT_CAP_INFO_EXT_NSS_BW_HALF_160_80P80 2 /* 160 & 80p80 MHz at half NSS CAP */ - -/* VHT Supported MCS Set - 64-bit - in VHT Cap IE */ -#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff -#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 - -#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff -#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 - -/* defines for field(s) in vht_cap_ie->rx_max_rate */ -#define VHT_CAP_MAX_NSTS_MASK 0xe000 -#define VHT_CAP_MAX_NSTS_SHIFT 13 - -/* defines for field(s) in vht_cap_ie->tx_max_rate */ -#define VHT_CAP_EXT_NSS_BW_CAP 0x2000 - -#define VHT_CAP_MCS_MAP_0_7 0 -#define VHT_CAP_MCS_MAP_0_8 1 -#define VHT_CAP_MCS_MAP_0_9 2 -#define VHT_CAP_MCS_MAP_NONE 3 -#define VHT_CAP_MCS_MAP_S 2 /* num bits for 1-stream */ -#define VHT_CAP_MCS_MAP_M 0x3 /* mask for 1-stream */ -/* assumes VHT_CAP_MCS_MAP_NONE is 3 and 2 bits are used for encoding */ -#define VHT_CAP_MCS_MAP_NONE_ALL 0xffff - -/* VHT rates bitmap */ -#define VHT_CAP_MCS_0_7_RATEMAP 0x00ff -#define VHT_CAP_MCS_0_8_RATEMAP 0x01ff -#define VHT_CAP_MCS_0_9_RATEMAP 0x03ff -#define VHT_CAP_MCS_FULL_RATEMAP VHT_CAP_MCS_0_9_RATEMAP - -#define VHT_PROP_MCS_MAP_10_11 0 -#define VHT_PROP_MCS_MAP_UNUSED1 1 -#define VHT_PROP_MCS_MAP_UNUSED2 2 -#define VHT_PROP_MCS_MAP_NONE 3 -#define VHT_PROP_MCS_MAP_NONE_ALL 0xffff - -/* VHT prop rates bitmap */ -#define VHT_PROP_MCS_10_11_RATEMAP 0x0c00 -#define VHT_PROP_MCS_FULL_RATEMAP VHT_PROP_MCS_10_11_RATEMAP - -#if !defined(VHT_CAP_MCS_MAP_0_9_NSS3) -/* remove after moving define to wlc_rate.h */ -/* mcsmap with MCS0-9 for Nss = 3 */ -#define VHT_CAP_MCS_MAP_0_9_NSS3 \ - ((VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(1)) | \ - (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(2)) | \ - (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(3))) -#endif /* !VHT_CAP_MCS_MAP_0_9_NSS3 */ - -#define VHT_CAP_MCS_MAP_NSS_MAX 8 - -/* get mcsmap with given mcs for given nss streams */ -#define VHT_CAP_MCS_MAP_CREATE(mcsmap, nss, mcs) \ - do { \ - int i; \ - for (i = 1; i <= nss; i++) { \ - VHT_MCS_MAP_SET_MCS_PER_SS(i, mcs, mcsmap); \ - } \ - } while (0) - -/* Map the mcs code to mcs bit map */ -#define VHT_MCS_CODE_TO_MCS_MAP(mcs_code) \ - ((mcs_code == VHT_CAP_MCS_MAP_0_7) ? VHT_CAP_MCS_0_7_RATEMAP : \ - (mcs_code == VHT_CAP_MCS_MAP_0_8) ? VHT_CAP_MCS_0_8_RATEMAP : \ - (mcs_code == VHT_CAP_MCS_MAP_0_9) ? VHT_CAP_MCS_0_9_RATEMAP : 0) - -/* Map the proprietary mcs code to proprietary mcs bitmap */ -#define VHT_PROP_MCS_CODE_TO_PROP_MCS_MAP(mcs_code) \ - ((mcs_code == VHT_PROP_MCS_MAP_10_11) ? VHT_PROP_MCS_10_11_RATEMAP : 0) - -/* Map the mcs bit map to mcs code */ -#define VHT_MCS_MAP_TO_MCS_CODE(mcs_map) \ - ((mcs_map == VHT_CAP_MCS_0_7_RATEMAP) ? VHT_CAP_MCS_MAP_0_7 : \ - (mcs_map == VHT_CAP_MCS_0_8_RATEMAP) ? VHT_CAP_MCS_MAP_0_8 : \ - (mcs_map == VHT_CAP_MCS_0_9_RATEMAP) ? VHT_CAP_MCS_MAP_0_9 : VHT_CAP_MCS_MAP_NONE) - -/* Map the proprietary mcs map to proprietary mcs code */ -#define VHT_PROP_MCS_MAP_TO_PROP_MCS_CODE(mcs_map) \ - (((mcs_map & 0xc00) == 0xc00) ? VHT_PROP_MCS_MAP_10_11 : VHT_PROP_MCS_MAP_NONE) - -/** VHT Capabilities Supported Channel Width */ -typedef enum vht_cap_chan_width { - VHT_CAP_CHAN_WIDTH_SUPPORT_MANDATORY = 0x00, - VHT_CAP_CHAN_WIDTH_SUPPORT_160 = 0x04, - VHT_CAP_CHAN_WIDTH_SUPPORT_160_8080 = 0x08 -} vht_cap_chan_width_t; - -/** VHT Capabilities Supported max MPDU LEN (sec 8.4.2.160.2) */ -typedef enum vht_cap_max_mpdu_len { - VHT_CAP_MPDU_MAX_4K = 0x00, - VHT_CAP_MPDU_MAX_8K = 0x01, - VHT_CAP_MPDU_MAX_11K = 0x02 -} vht_cap_max_mpdu_len_t; - -/* Maximum MPDU Length byte counts for the VHT Capabilities advertised limits */ -#define VHT_MPDU_LIMIT_4K 3895 -#define VHT_MPDU_LIMIT_8K 7991 -#define VHT_MPDU_LIMIT_11K 11454 - -/** - * VHT Operation IE (sec 8.4.2.161) - */ - -BWL_PRE_PACKED_STRUCT struct vht_op_ie { - uint8 chan_width; - uint8 chan1; - uint8 chan2; - uint16 supp_mcs; /* same def as above in vht cap */ -} BWL_POST_PACKED_STRUCT; -typedef struct vht_op_ie vht_op_ie_t; - -/* 3B VHT Op info + 2B Basic MCS */ -#define VHT_OP_IE_LEN 5 - -typedef enum vht_op_chan_width { - VHT_OP_CHAN_WIDTH_20_40 = 0, - VHT_OP_CHAN_WIDTH_80 = 1, - VHT_OP_CHAN_WIDTH_160 = 2, /* deprecated - IEEE 802.11 REVmc D8.0 Table 11-25 */ - VHT_OP_CHAN_WIDTH_80_80 = 3 /* deprecated - IEEE 802.11 REVmc D8.0 Table 11-25 */ -} vht_op_chan_width_t; - -#define VHT_OP_INFO_LEN 3 - -/* AID length */ -#define AID_IE_LEN 2 -/** - * BRCM vht features IE header - * The header if the fixed part of the IE - * On the 5GHz band this is the entire IE, - * on 2.4GHz the VHT IEs as defined in the 802.11ac - * specification follows - * - * - * VHT features rates bitmap. - * Bit0: 5G MCS 0-9 BW 160MHz - * Bit1: 5G MCS 0-9 support BW 80MHz - * Bit2: 5G MCS 0-9 support BW 20MHz - * Bit3: 2.4G MCS 0-9 support BW 20MHz - * Bits:4-7 Reserved for future use - * - */ -#define VHT_FEATURES_IE_TYPE 0x4 -BWL_PRE_PACKED_STRUCT struct vht_features_ie_hdr { - uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ - uint8 type; /* type of this IE = 4 */ - uint8 rate_mask; /* VHT rate mask */ -} BWL_POST_PACKED_STRUCT; -typedef struct vht_features_ie_hdr vht_features_ie_hdr_t; - -/* Def for rx & tx basic mcs maps - ea ss num has 2 bits of info */ -#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1) * VHT_CAP_MCS_MAP_S) -#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ - (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & VHT_CAP_MCS_MAP_M) -#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ - do { \ - (mcsMap) &= (~(VHT_CAP_MCS_MAP_M << VHT_MCS_MAP_GET_SS_IDX(nss))); \ - (mcsMap) |= (((numMcs) & VHT_CAP_MCS_MAP_M) << VHT_MCS_MAP_GET_SS_IDX(nss)); \ - } while (0) -#define VHT_MCS_SS_SUPPORTED(nss, mcsMap) \ - (VHT_MCS_MAP_GET_MCS_PER_SS((nss), (mcsMap)) != VHT_CAP_MCS_MAP_NONE) - -/* Get the max ss supported from the mcs map */ -#define VHT_MAX_SS_SUPPORTED(mcsMap) \ - VHT_MCS_SS_SUPPORTED(8, mcsMap) ? 8 : \ - VHT_MCS_SS_SUPPORTED(7, mcsMap) ? 7 : \ - VHT_MCS_SS_SUPPORTED(6, mcsMap) ? 6 : \ - VHT_MCS_SS_SUPPORTED(5, mcsMap) ? 5 : \ - VHT_MCS_SS_SUPPORTED(4, mcsMap) ? 4 : \ - VHT_MCS_SS_SUPPORTED(3, mcsMap) ? 3 : \ - VHT_MCS_SS_SUPPORTED(2, mcsMap) ? 2 : \ - VHT_MCS_SS_SUPPORTED(1, mcsMap) ? 1 : 0 - -#ifdef IBSS_RMC -/* customer's OUI */ -#define RMC_PROP_OUI "\x00\x16\x32" -#endif - -/* ************* WPA definitions. ************* */ -#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ -#define WPA_OUI_LEN 3 /* WPA OUI length */ -#define WPA_OUI_TYPE 1 -#define WPA_VERSION 1 /* WPA version */ -#define WPA_VERSION_LEN 2 /* WPA version length */ - -/* ************* WPA2 definitions. ************* */ -#define WPA2_OUI "\x00\x0F\xAC" /* WPA2 OUI */ -#define WPA2_OUI_LEN 3 /* WPA2 OUI length */ -#define WPA2_VERSION 1 /* WPA2 version */ -#define WPA2_VERSION_LEN 2 /* WAP2 version length */ -#define MAX_RSNE_SUPPORTED_VERSION WPA2_VERSION /* Max supported version */ - -/* ************* WPS definitions. ************* */ -#define WPS_OUI "\x00\x50\xF2" /* WPS OUI */ -#define WPS_OUI_LEN 3 /* WPS OUI length */ -#define WPS_OUI_TYPE 4 - -/* ************* TPC definitions. ************* */ -#define TPC_OUI "\x00\x50\xF2" /* TPC OUI */ -#define TPC_OUI_LEN 3 /* TPC OUI length */ -#define TPC_OUI_TYPE 8 -#define WFA_OUI_TYPE_TPC 8 /* deprecated */ - -/* ************* WFA definitions. ************* */ -#define WFA_OUI "\x50\x6F\x9A" /* WFA OUI */ -#define WFA_OUI_LEN 3 /* WFA OUI length */ -#define WFA_OUI_TYPE_P2P 9 - -/* WFA definitions for LEGACY P2P */ -#ifdef WL_LEGACY_P2P -#define APPLE_OUI "\x00\x17\xF2" /* MACOSX OUI */ -#define APPLE_OUI_LEN 3 -#define APPLE_OUI_TYPE_P2P 5 -#endif /* WL_LEGACY_P2P */ - -#ifndef WL_LEGACY_P2P -#define P2P_OUI WFA_OUI -#define P2P_OUI_LEN WFA_OUI_LEN -#define P2P_OUI_TYPE WFA_OUI_TYPE_P2P -#else -#define P2P_OUI APPLE_OUI -#define P2P_OUI_LEN APPLE_OUI_LEN -#define P2P_OUI_TYPE APPLE_OUI_TYPE_P2P -#endif /* !WL_LEGACY_P2P */ - -#ifdef WLTDLS -#define WFA_OUI_TYPE_TPQ 4 /* WFD Tunneled Probe ReQuest */ -#define WFA_OUI_TYPE_TPS 5 /* WFD Tunneled Probe ReSponse */ -#define WFA_OUI_TYPE_WFD 10 -#endif /* WTDLS */ -#define WFA_OUI_TYPE_HS20 0x10 -#define WFA_OUI_TYPE_OSEN 0x12 -#define WFA_OUI_TYPE_NAN 0x13 -#define WFA_OUI_TYPE_MBO 0x16 -#define WFA_OUI_TYPE_MBO_OCE 0x16 -#define WFA_OUI_TYPE_OWE 0x1C -#define WFA_OUI_TYPE_SAE_PK 0x1F -#define WFA_OUI_TYPE_TD_INDICATION 0x20 - -#define SAE_PK_MOD_LEN 32u -BWL_PRE_PACKED_STRUCT struct dot11_sae_pk_element { - uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ - uint8 len; /* IE length */ - uint8 oui[WFA_OUI_LEN]; /* WFA_OUI */ - uint8 type; /* SAE-PK */ - uint8 data[SAE_PK_MOD_LEN]; /* Modifier. 32Byte fixed */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_sae_pk_element dot11_sae_pk_element_t; +#define AMPDU_DELIMITER_LEN 4u /* length of ampdu delimiter */ +#define AMPDU_DELIMITER_LEN_MAX 63 /* max length of ampdu delimiter(enforced in HW) */ /* RSN authenticated key managment suite */ -#define RSN_AKM_NONE 0 /* None (IBSS) */ -#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */ -#define RSN_AKM_PSK 2 /* Pre-shared Key */ -#define RSN_AKM_FBT_1X 3 /* Fast Bss transition using 802.1X */ -#define RSN_AKM_FBT_PSK 4 /* Fast Bss transition using Pre-shared Key */ +#define RSN_AKM_NONE 0u /* None (IBSS) */ +#define RSN_AKM_UNSPECIFIED 1u /* Over 802.1x */ +#define RSN_AKM_PSK 2u /* Pre-shared Key */ +#define RSN_AKM_FBT_1X 3u /* Fast Bss transition using 802.1X */ +#define RSN_AKM_FBT_PSK 4u /* Fast Bss transition using Pre-shared Key */ /* RSN_AKM_MFP_1X and RSN_AKM_MFP_PSK are not used any more * Just kept here to avoid build issue in BISON/CARIBOU branch */ -#define RSN_AKM_MFP_1X 5 /* SHA256 key derivation, using 802.1X */ -#define RSN_AKM_MFP_PSK 6 /* SHA256 key derivation, using Pre-shared Key */ -#define RSN_AKM_SHA256_1X 5 /* SHA256 key derivation, using 802.1X */ -#define RSN_AKM_SHA256_PSK 6 /* SHA256 key derivation, using Pre-shared Key */ -#define RSN_AKM_TPK 7 /* TPK(TDLS Peer Key) handshake */ -#define RSN_AKM_SAE_PSK 8 /* AKM for SAE with 4-way handshake */ -#define RSN_AKM_SAE_FBT 9 /* AKM for SAE with FBT */ -#define RSN_AKM_SUITEB_SHA256_1X 11 /* Suite B SHA256 */ -#define RSN_AKM_SUITEB_SHA384_1X 12 /* Suite B-192 SHA384 */ -#define RSN_AKM_FBT_SHA384_1X 13 /* FBT SHA384 */ -#define RSN_AKM_FILS_SHA256 14 /* SHA256 key derivation, using FILS */ -#define RSN_AKM_FILS_SHA384 15 /* SHA384 key derivation, using FILS */ -#define RSN_AKM_FBT_SHA256_FILS 16 -#define RSN_AKM_FBT_SHA384_FILS 17 -#define RSN_AKM_OWE 18 /* RFC 8110 OWE */ -#define RSN_AKM_FBT_SHA384_PSK 19 -#define RSN_AKM_PSK_SHA384 20 +#define RSN_AKM_MFP_1X 5u /* SHA256 key derivation, using 802.1X */ +#define RSN_AKM_MFP_PSK 6u /* SHA256 key derivation, using Pre-shared Key */ +#define RSN_AKM_SHA256_1X 5u /* SHA256 key derivation, using 802.1X */ +#define RSN_AKM_SHA256_PSK 6u /* SHA256 key derivation, using Pre-shared Key */ +#define RSN_AKM_TPK 7u /* TPK(TDLS Peer Key) handshake */ +#define RSN_AKM_SAE_PSK 8u /* AKM for SAE with 4-way handshake */ +#define RSN_AKM_SAE_FBT 9u /* AKM for SAE with FBT */ +#define RSN_AKM_SUITEB_SHA256_1X 11u /* Suite B SHA256 */ +#define RSN_AKM_SUITEB_SHA384_1X 12u /* Suite B-192 SHA384 */ +#define RSN_AKM_FBT_SHA384_1X 13u /* FBT SHA384 */ +#define RSN_AKM_FILS_SHA256 14u /* SHA256 key derivation, using FILS */ +#define RSN_AKM_FILS_SHA384 15u /* SHA384 key derivation, using FILS */ +#define RSN_AKM_FBT_SHA256_FILS 16u +#define RSN_AKM_FBT_SHA384_FILS 17u +#define RSN_AKM_OWE 18u /* RFC 8110 OWE */ +#define RSN_AKM_FBT_SHA384_PSK 19u +#define RSN_AKM_PSK_SHA384 20u +#define RSN_AKM_PASN 21u /* Pre-Association Security Negotiation */ +#define RSN_AKM_FBT_SHA384_1X_UNRSTD 22u /* Unrestricted FBT over 802.1X */ +#define RSN_AKM_SHA384_1X 23u /* Over 802.1X SHA384 */ +#define RSN_AKM_SAE_EXT_PSK 24u /* AKM for SAE (variable length PMK) */ +#define RSN_AKM_SAE_EXT_FBT 25u /* AKM for SAE (variable length PMK) with FBT */ /* OSEN authenticated key managment suite */ #define OSEN_AKM_UNSPECIFIED RSN_AKM_UNSPECIFIED /* Over 802.1x */ /* WFA DPP RSN authenticated key managment */ @@ -4937,8 +2326,8 @@ typedef struct dot11_sae_pk_element dot11_sae_pk_element_t; #define DOT11_MAX_KEY_SIZE 32 /* max size of any key */ #define DOT11_MAX_IV_SIZE 16 /* max size of any IV */ #define DOT11_EXT_IV_FLAG (1<<5) /* flag to indicate IV is > 4 bytes */ +#define DOT11_FTM_PFT_IV_FLAG 0x10 /* Protected Fine Timing frame flag in IV */ #define DOT11_WPA_KEY_RSC_LEN 8 /* WPA RSC key len */ - #define WEP1_KEY_SIZE 5 /* max size of any WEP key */ #define WEP1_KEY_HEX_SIZE 10 /* size of WEP key in hex. */ #define WEP128_KEY_SIZE 13 /* max size of any WEP key */ @@ -4963,74 +2352,6 @@ typedef struct dot11_sae_pk_element dot11_sae_pk_element_t; #define AES256_KEY_SIZE 32 /* size of AES 256 key - .11acD5 */ #define AES256_MIC_SIZE 16 /* size of MIC for 256 bit keys, incl BIP */ -/* WCN */ -#define WCN_OUI "\x00\x50\xf2" /* WCN OUI */ -#define WCN_TYPE 4 /* WCN type */ - -#ifdef BCMWAPI_WPI -#define SMS4_KEY_LEN 16 -#define SMS4_WPI_CBC_MAC_LEN 16 -#endif - -/* 802.11r protocol definitions */ - -/** Mobility Domain IE */ -BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie { - uint8 id; - uint8 len; /* DOT11_MDID_IE_DATA_LEN (3) */ - uint16 mdid; /* Mobility Domain Id */ - uint8 cap; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_mdid_ie dot11_mdid_ie_t; - -/* length of data portion of Mobility Domain IE */ -#define DOT11_MDID_IE_DATA_LEN 3 -#define DOT11_MDID_LEN 2 -#define FBT_MDID_CAP_OVERDS 0x01 /* Fast Bss transition over the DS support */ -#define FBT_MDID_CAP_RRP 0x02 /* Resource request protocol support */ - -/* BITs in FTIE mic control field */ -#define DOT11_FTIE_RSNXE_USED 0x1u - -/* Fast Bss Transition IE */ -#ifdef FT_IE_VER_V2 -typedef BWL_PRE_PACKED_STRUCT struct dot11_ft_ie_v2 { - uint8 id; - uint8 len; - uint16 mic_control; - /* dynamic offset to following mic[], anonce[], snonce[] */ -} BWL_POST_PACKED_STRUCT dot11_ft_ie_v2; -typedef struct dot11_ft_ie_v2 dot11_ft_ie_t; -#else -BWL_PRE_PACKED_STRUCT struct dot11_ft_ie { - uint8 id; - uint8 len; /* At least equal to DOT11_FT_IE_FIXED_LEN (82) */ - uint16 mic_control; /* Mic Control */ - uint8 mic[16]; - uint8 anonce[32]; - uint8 snonce[32]; - /* Optional sub-elements follow */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ft_ie dot11_ft_ie_t; - -/* Fixed length of data portion of Fast BSS Transition IE. There could be - * optional parameters, which if present, could raise the FT IE length to 255. - */ -#define DOT11_FT_IE_FIXED_LEN 82 -#endif /* FT_IE_VER_V2 */ - -#ifdef FT_IE_VER_V2 -#define DOT11_FT_IE_LEN(mic_len) (sizeof(dot11_ft_ie_v2) + mic_len + EAPOL_WPA_KEY_NONCE_LEN *2) -#define FT_IE_MIC(pos) ((uint8 *)pos + sizeof(dot11_ft_ie_v2)) -#define FT_IE_ANONCE(pos, mic_len) ((uint8 *)pos + sizeof(dot11_ft_ie_v2) + mic_len) -#define FT_IE_SNONCE(pos, mic_len) ((uint8 *)pos + sizeof(dot11_ft_ie_v2) + mic_len + \ - EAPOL_WPA_KEY_NONCE_LEN) -#else -#define DOT11_FT_IE_LEN(mic_len) sizeof(dot11_ft_ie) -#define FT_IE_MIC(pos) ((uint8 *)&pos->mic) -#define FT_IE_ANONCE(pos, mic_len) ((uint8 *)&pos->anonce) -#define FT_IE_SNONCE(pos, mic_len) ((uint8 *)&pos->snonce) -#endif /* FT_IE_VER_V2 */ #define TIE_TYPE_RESERVED 0 #define TIE_TYPE_REASSOC_DEADLINE 1 #define TIE_TYPE_KEY_LIEFTIME 2 @@ -5050,780 +2371,13 @@ BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { uint16 key_info; uint8 key_len; uint8 rsc[8]; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT; typedef struct dot11_gtk_ie dot11_gtk_ie_t; -/** Management MIC ie */ -BWL_PRE_PACKED_STRUCT struct mmic_ie { - uint8 id; /* IE ID: DOT11_MNG_MMIE_ID */ - uint8 len; /* IE length */ - uint16 key_id; /* key id */ - uint8 ipn[6]; /* ipn */ - uint8 mic[16]; /* mic */ -} BWL_POST_PACKED_STRUCT; -typedef struct mmic_ie mmic_ie_t; - -#define DOT11_MMIC_IE_HDR_SIZE (OFFSETOF(mmic_ie_t, mic)) - -/* 802.11r-2008, 11A.10.3 - RRB frame format */ -BWL_PRE_PACKED_STRUCT struct dot11_ft_rrb_frame { - uint8 frame_type; /* 1 for RRB */ - uint8 packet_type; /* 0 for Request 1 for Response */ - uint16 len; - uint8 cur_ap_addr[ETHER_ADDR_LEN]; - uint8 data[1]; /* IEs Received/Sent in FT Action Req/Resp Frame */ -} BWL_POST_PACKED_STRUCT; - -typedef struct dot11_ft_rrb_frame dot11_ft_rrb_frame_t; - -#define DOT11_FT_RRB_FIXED_LEN 10 -#define DOT11_FT_REMOTE_FRAME_TYPE 1 -#define DOT11_FT_PACKET_REQ 0 -#define DOT11_FT_PACKET_RESP 1 - #define BSSID_INVALID "\x00\x00\x00\x00\x00\x00" #define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF" -#ifdef BCMWAPI_WAI -#define WAPI_IE_MIN_LEN 20 /* WAPI IE min length */ -#define WAPI_VERSION 1 /* WAPI version */ -#define WAPI_VERSION_LEN 2 /* WAPI version length */ -#define WAPI_OUI "\x00\x14\x72" /* WAPI OUI */ -#define WAPI_OUI_LEN DOT11_OUI_LEN /* WAPI OUI length */ -#endif /* BCMWAPI_WAI */ - -/* ************* WMM Parameter definitions. ************* */ -#define WMM_OUI "\x00\x50\xF2" /* WNN OUI */ -#define WMM_OUI_LEN 3 /* WMM OUI length */ -#define WMM_OUI_TYPE 2 /* WMM OUT type */ -#define WMM_VERSION 1 -#define WMM_VERSION_LEN 1 - -/* WMM OUI subtype */ -#define WMM_OUI_SUBTYPE_PARAMETER 1 -#define WMM_PARAMETER_IE_LEN 24 - -/** Link Identifier Element */ -BWL_PRE_PACKED_STRUCT struct link_id_ie { - uint8 id; - uint8 len; - struct ether_addr bssid; - struct ether_addr tdls_init_mac; - struct ether_addr tdls_resp_mac; -} BWL_POST_PACKED_STRUCT; -typedef struct link_id_ie link_id_ie_t; -#define TDLS_LINK_ID_IE_LEN 18u - -/** Link Wakeup Schedule Element */ -BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie { - uint8 id; - uint8 len; - uint32 offset; /* in ms between TSF0 and start of 1st Awake Window */ - uint32 interval; /* in ms bwtween the start of 2 Awake Windows */ - uint32 awake_win_slots; /* in backof slots, duration of Awake Window */ - uint32 max_wake_win; /* in ms, max duration of Awake Window */ - uint16 idle_cnt; /* number of consecutive Awake Windows */ -} BWL_POST_PACKED_STRUCT; -typedef struct wakeup_sch_ie wakeup_sch_ie_t; -#define TDLS_WAKEUP_SCH_IE_LEN 18 - -/** Channel Switch Timing Element */ -BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie { - uint8 id; - uint8 len; - uint16 switch_time; /* in ms, time to switch channels */ - uint16 switch_timeout; /* in ms */ -} BWL_POST_PACKED_STRUCT; -typedef struct channel_switch_timing_ie channel_switch_timing_ie_t; -#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4 - -/** PTI Control Element */ -BWL_PRE_PACKED_STRUCT struct pti_control_ie { - uint8 id; - uint8 len; - uint8 tid; - uint16 seq_control; -} BWL_POST_PACKED_STRUCT; -typedef struct pti_control_ie pti_control_ie_t; -#define TDLS_PTI_CONTROL_IE_LEN 3 - -/** PU Buffer Status Element */ -BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie { - uint8 id; - uint8 len; - uint8 status; -} BWL_POST_PACKED_STRUCT; -typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; -#define TDLS_PU_BUFFER_STATUS_IE_LEN 1 -#define TDLS_PU_BUFFER_STATUS_AC_BK 1 -#define TDLS_PU_BUFFER_STATUS_AC_BE 2 -#define TDLS_PU_BUFFER_STATUS_AC_VI 4 -#define TDLS_PU_BUFFER_STATUS_AC_VO 8 - -/* TDLS Action Field Values */ -#define TDLS_SETUP_REQ 0 -#define TDLS_SETUP_RESP 1 -#define TDLS_SETUP_CONFIRM 2 -#define TDLS_TEARDOWN 3 -#define TDLS_PEER_TRAFFIC_IND 4 -#define TDLS_CHANNEL_SWITCH_REQ 5 -#define TDLS_CHANNEL_SWITCH_RESP 6 -#define TDLS_PEER_PSM_REQ 7 -#define TDLS_PEER_PSM_RESP 8 -#define TDLS_PEER_TRAFFIC_RESP 9 -#define TDLS_DISCOVERY_REQ 10 - -/* 802.11z TDLS Public Action Frame action field */ -#define TDLS_DISCOVERY_RESP 14 - -/* 802.11u GAS action frames */ -#define GAS_REQUEST_ACTION_FRAME 10 -#define GAS_RESPONSE_ACTION_FRAME 11 -#define GAS_COMEBACK_REQUEST_ACTION_FRAME 12 -#define GAS_COMEBACK_RESPONSE_ACTION_FRAME 13 - -/* FTM - fine timing measurement public action frames */ -BWL_PRE_PACKED_STRUCT struct dot11_ftm_req { - uint8 category; /* category of action frame (4) */ - uint8 action; /* public action (32) */ - uint8 trigger; /* trigger/continue? */ - /* optional lci, civic loc, ftm params */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm_req dot11_ftm_req_t; - -BWL_PRE_PACKED_STRUCT struct dot11_ftm { - uint8 category; /* category of action frame (4) */ - uint8 action; /* public action (33) */ - uint8 dialog; /* dialog token */ - uint8 follow_up; /* follow up dialog token */ - uint8 tod[6]; /* t1 - last depart timestamp */ - uint8 toa[6]; /* t4 - last ack arrival timestamp */ - uint8 tod_err[2]; /* t1 error */ - uint8 toa_err[2]; /* t4 error */ - /* optional lci report, civic loc report, ftm params */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm dot11_ftm_t; - -BWL_PRE_PACKED_STRUCT struct dot11_ftm_lmr { - uint8 category; /* category of action frame (4) */ - uint8 action; /* public action (33) */ - uint8 dialog; /* dialog token */ - uint8 tod[6]; /* RSTA t3 or ISTA t1: - * last departure of NDP - */ - uint8 toa[6]; /* RSTA t2 or ISTA t4: - * last arrival of NDP - */ - uint8 tod_err[2]; /* t3 or t1 error */ - uint8 toa_err[2]; /* t2 or t4 error */ - uint16 cfo; /* I2R LMR: clock difference between ISTA and RSTA. */ - uint8 sec_ltf_params[]; /* Optional Secure LTF parameters */ - /* no AOA feedback */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm_lmr dot11_ftm_lmr_t; - -BWL_PRE_PACKED_STRUCT struct dot11_ftm_ranging_ndpa { - uint16 fc; /* frame control */ - uint16 durid; /* duration/ID */ - struct ether_addr ra; /* receiver address */ - struct ether_addr ta; /* transmitter address */ - uint8 dialog_token; /* sounding dialog token */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm_ranging_ndpa dot11_ftm_ranging_ndpa_t; - -/* NDPA types = dialog token byte lower 2 bits */ -#define DOT11_NDPA_TYPE_MASK 0x03 -#define DOT11_NDPA_TYPE_VHT 0x00 -#define DOT11_NDPA_TYPE_RANGING 0x01 -#define DOT11_NDPA_TYPE_HE 0x02 - -#define DOT11_FTM_ERR_NOT_CONT_OFFSET 1 -#define DOT11_FTM_ERR_NOT_CONT_MASK 0x80 -#define DOT11_FTM_ERR_NOT_CONT_SHIFT 7 -#define DOT11_FTM_ERR_NOT_CONT(_err) (((_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] & \ - DOT11_FTM_ERR_NOT_CONT_MASK) >> DOT11_FTM_ERR_NOT_CONT_SHIFT) -#define DOT11_FTM_ERR_SET_NOT_CONT(_err, _val) do {\ - uint8 _err2 = (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET]; \ - _err2 &= ~DOT11_FTM_ERR_NOT_CONT_MASK; \ - _err2 |= ((_val) << DOT11_FTM_ERR_NOT_CONT_SHIFT) & DOT11_FTM_ERR_NOT_CONT_MASK; \ - (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] = _err2; \ -} while (0) - -#define DOT11_FTM_ERR_MAX_ERR_OFFSET 0 -#define DOT11_FTM_ERR_MAX_ERR_MASK 0x7fff -#define DOT11_FTM_ERR_MAX_ERR_SHIFT 0 -#define DOT11_FTM_ERR_MAX_ERR(_err) (((((_err)[1] & 0x7f) << 8) | (_err)[0])) -#define DOT11_FTM_ERR_SET_MAX_ERR(_err, _val) do {\ - uint16 _val2; \ - uint16 _not_cont; \ - _val2 = (((_val) & DOT11_FTM_ERR_MAX_ERR_MASK) << DOT11_FTM_ERR_MAX_ERR_SHIFT); \ - _val2 = (_val2 > 0x3fff) ? 0 : _val2; /* not expecting > 16ns error */ \ - _not_cont = DOT11_FTM_ERR_NOT_CONT(_err); \ - (_err)[0] = _val2 & 0xff; \ - (_err)[1] = (_val2 >> 8) & 0xff; \ - DOT11_FTM_ERR_SET_NOT_CONT(_err, _not_cont); \ -} while (0) - -#if defined(DOT11_FTM_ERR_ROM_COMPAT) -/* incorrect defs - here for ROM compatibiity */ -#undef DOT11_FTM_ERR_NOT_CONT_OFFSET -#undef DOT11_FTM_ERR_NOT_CONT_MASK -#undef DOT11_FTM_ERR_NOT_CONT_SHIFT -#undef DOT11_FTM_ERR_NOT_CONT -#undef DOT11_FTM_ERR_SET_NOT_CONT - -#define DOT11_FTM_ERR_NOT_CONT_OFFSET 0 -#define DOT11_FTM_ERR_NOT_CONT_MASK 0x0001 -#define DOT11_FTM_ERR_NOT_CONT_SHIFT 0 -#define DOT11_FTM_ERR_NOT_CONT(_err) (((_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] & \ - DOT11_FTM_ERR_NOT_CONT_MASK) >> DOT11_FTM_ERR_NOT_CONT_SHIFT) -#define DOT11_FTM_ERR_SET_NOT_CONT(_err, _val) do {\ - uint8 _err2 = (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET]; \ - _err2 &= ~DOT11_FTM_ERR_NOT_CONT_MASK; \ - _err2 |= ((_val) << DOT11_FTM_ERR_NOT_CONT_SHIFT) & DOT11_FTM_ERR_NOT_CONT_MASK; \ - (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] = _err2; \ -} while (0) - -#undef DOT11_FTM_ERR_MAX_ERR_OFFSET -#undef DOT11_FTM_ERR_MAX_ERR_MASK -#undef DOT11_FTM_ERR_MAX_ERR_SHIFT -#undef DOT11_FTM_ERR_MAX_ERR -#undef DOT11_FTM_ERR_SET_MAX_ERR - -#define DOT11_FTM_ERR_MAX_ERR_OFFSET 0 -#define DOT11_FTM_ERR_MAX_ERR_MASK 0xfff7 -#define DOT11_FTM_ERR_MAX_ERR_SHIFT 1 -#define DOT11_FTM_ERR_MAX_ERR(_err) ((((_err)[1] << 7) | (_err)[0]) >> 1) -#define DOT11_FTM_ERR_SET_MAX_ERR(_err, _val) do {\ - uint16 _val2; \ - _val2 = (((_val) << DOT11_FTM_ERR_MAX_ERR_SHIFT) |\ - ((_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] & DOT11_FTM_ERR_NOT_CONT_MASK)); \ - (_err)[0] = _val2 & 0xff; \ - (_err)[1] = _val2 >> 8 & 0xff; \ -} while (0) -#endif /* DOT11_FTM_ERR_ROM_COMPAT */ - -BWL_PRE_PACKED_STRUCT struct dot11_ftm_params { - uint8 id; /* DOT11_MNG_FTM_PARAM_ID 8.4.2.166 11mcd2.6/2014 - revisit */ - uint8 len; - uint8 info[9]; -} BWL_POST_PACKED_STRUCT; - -typedef struct dot11_ftm_params dot11_ftm_params_t; -#define DOT11_FTM_PARAMS_IE_LEN (sizeof(dot11_ftm_params_t) - 2) - -/* common part for both TB and NTB */ -BWL_PRE_PACKED_STRUCT struct dot11_ftm_ranging_params { - uint8 id; /* 255 */ - uint8 len; - uint8 ext_id; /* DOT11_MNG_FTM_RANGING_EXT_ID */ - uint8 info[6]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm_ranging_params dot11_ftm_ranging_params_t; -#define DOT11_FTM_CMN_RANGING_PARAMS_IE_LEN (sizeof(dot11_ftm_ranging_params_t) - TLV_EXT_HDR_LEN) - -/* FTM NTB specific */ -BWL_PRE_PACKED_STRUCT struct dot11_ftm_ntb_params { - uint8 id; /* DOT11_FTM_NTB_SUB_ELT_ID */ - uint8 len; - uint8 info[6]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm_ntb_params dot11_ftm_ntb_params_t; - -#define DOT11_FTM_NTB_PARAMS_SUB_IE_LEN (sizeof(dot11_ftm_ntb_params_t)) -#define DOT11_FTM_NTB_PARAMS_IE_LEN DOT11_FTM_CMN_RANGING_PARAMS_IE_LEN + \ - DOT11_FTM_NTB_PARAMS_SUB_IE_LEN - -/* FTM TB specific */ -BWL_PRE_PACKED_STRUCT struct dot11_ftm_tb_params { - uint8 id; /* DOT11_FTM_TB_SUB_ELT_ID */ - uint8 len; - uint8 info[1]; /* variable length, minimum 1 */ -} BWL_POST_PACKED_STRUCT; - -typedef struct dot11_ftm_tb_params dot11_ftm_tb_params_t; -#define DOT11_FTM_TB_PARAMS_IE_LEN sizeof(dot11_ftm_tb_params_t) - -BWL_PRE_PACKED_STRUCT struct dot11_ftm_sec_ltf_params { - uint8 id; /* 255 */ - uint8 len; - uint8 ext_id; /* DOT11_MNG_FTM_SECURE_LTF_EXT_ID */ - uint8 info[11]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm_sec_ltf_params dot11_ftm_sec_ltf_params_t; -#define DOT11_FTM_SEC_LTF_PARAMS_IE_LEN (sizeof(dot11_ftm_sec_ltf_params_t) - 3) - -#define FTM_PARAMS_FIELD(_p, _off, _mask, _shift) (((_p)->info[(_off)] & (_mask)) >> (_shift)) -#define FTM_PARAMS_SET_FIELD(_p, _off, _mask, _shift, _val) do {\ - uint8 _ptmp = (_p)->info[_off] & ~(_mask); \ - (_p)->info[(_off)] = _ptmp | (((_val) << (_shift)) & (_mask)); \ -} while (0) - -#define FTM_PARAMS_STATUS_OFFSET 0 -#define FTM_PARAMS_STATUS_MASK 0x03 -#define FTM_PARAMS_STATUS_SHIFT 0 -#define FTM_PARAMS_STATUS(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_STATUS_OFFSET, \ - FTM_PARAMS_STATUS_MASK, FTM_PARAMS_STATUS_SHIFT) -#define FTM_PARAMS_SET_STATUS(_p, _status) FTM_PARAMS_SET_FIELD(_p, \ - FTM_PARAMS_STATUS_OFFSET, FTM_PARAMS_STATUS_MASK, FTM_PARAMS_STATUS_SHIFT, _status) - -#define FTM_PARAMS_VALUE_OFFSET 0 -#define FTM_PARAMS_VALUE_MASK 0x7c -#define FTM_PARAMS_VALUE_SHIFT 2 -#define FTM_PARAMS_VALUE(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_VALUE_OFFSET, \ - FTM_PARAMS_VALUE_MASK, FTM_PARAMS_VALUE_SHIFT) -#define FTM_PARAMS_SET_VALUE(_p, _value) FTM_PARAMS_SET_FIELD(_p, \ - FTM_PARAMS_VALUE_OFFSET, FTM_PARAMS_VALUE_MASK, FTM_PARAMS_VALUE_SHIFT, _value) -#define FTM_PARAMS_MAX_VALUE 32 - -#define FTM_PARAMS_NBURSTEXP_OFFSET 1 -#define FTM_PARAMS_NBURSTEXP_MASK 0x0f -#define FTM_PARAMS_NBURSTEXP_SHIFT 0 -#define FTM_PARAMS_NBURSTEXP(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_NBURSTEXP_OFFSET, \ - FTM_PARAMS_NBURSTEXP_MASK, FTM_PARAMS_NBURSTEXP_SHIFT) -#define FTM_PARAMS_SET_NBURSTEXP(_p, _bexp) FTM_PARAMS_SET_FIELD(_p, \ - FTM_PARAMS_NBURSTEXP_OFFSET, FTM_PARAMS_NBURSTEXP_MASK, FTM_PARAMS_NBURSTEXP_SHIFT, \ - _bexp) - -#define FTM_PARAMS_NBURST(_p) (1 << FTM_PARAMS_NBURSTEXP(_p)) - -enum { - FTM_PARAMS_NBURSTEXP_NOPREF = 15 -}; - -enum { - FTM_PARAMS_BURSTTMO_NOPREF = 15 -}; - -#define FTM_PARAMS_BURSTTMO_OFFSET 1 -#define FTM_PARAMS_BURSTTMO_MASK 0xf0 -#define FTM_PARAMS_BURSTTMO_SHIFT 4 -#define FTM_PARAMS_BURSTTMO(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_BURSTTMO_OFFSET, \ - FTM_PARAMS_BURSTTMO_MASK, FTM_PARAMS_BURSTTMO_SHIFT) -/* set timeout in params using _tmo where timeout = 2^(_tmo) * 250us */ -#define FTM_PARAMS_SET_BURSTTMO(_p, _tmo) FTM_PARAMS_SET_FIELD(_p, \ - FTM_PARAMS_BURSTTMO_OFFSET, FTM_PARAMS_BURSTTMO_MASK, FTM_PARAMS_BURSTTMO_SHIFT, (_tmo)+2) - -#define FTM_PARAMS_BURSTTMO_USEC(_val) ((1 << ((_val)-2)) * 250) -#define FTM_PARAMS_BURSTTMO_VALID(_val) ((((_val) < 12 && (_val) > 1)) || \ - (_val) == FTM_PARAMS_BURSTTMO_NOPREF) -#define FTM_PARAMS_BURSTTMO_MAX_MSEC 128 /* 2^9 * 250us */ -#define FTM_PARAMS_BURSTTMO_MAX_USEC 128000 /* 2^9 * 250us */ - -#define FTM_PARAMS_MINDELTA_OFFSET 2 -#define FTM_PARAMS_MINDELTA_USEC(_p) ((_p)->info[FTM_PARAMS_MINDELTA_OFFSET] * 100) -#define FTM_PARAMS_SET_MINDELTA_USEC(_p, _delta) do { \ - (_p)->info[FTM_PARAMS_MINDELTA_OFFSET] = (_delta) / 100; \ -} while (0) - -enum { - FTM_PARAMS_MINDELTA_NOPREF = 0 -}; - -#define FTM_PARAMS_PARTIAL_TSF(_p) ((_p)->info[4] << 8 | (_p)->info[3]) -#define FTM_PARAMS_SET_PARTIAL_TSF(_p, _partial_tsf) do { \ - (_p)->info[3] = (_partial_tsf) & 0xff; \ - (_p)->info[4] = ((_partial_tsf) >> 8) & 0xff; \ -} while (0) - -#define FTM_PARAMS_PARTIAL_TSF_MASK 0x0000000003fffc00ULL -#define FTM_PARAMS_PARTIAL_TSF_SHIFT 10 -#define FTM_PARAMS_PARTIAL_TSF_BIT_LEN 16 -#define FTM_PARAMS_PARTIAL_TSF_MAX 0xffff - -/* FTM can indicate upto 62k TUs forward and 1k TU backward */ -#define FTM_PARAMS_TSF_FW_HI (63487 << 10) /* in micro sec */ -#define FTM_PARAMS_TSF_BW_LOW (64512 << 10) /* in micro sec */ -#define FTM_PARAMS_TSF_BW_HI (65535 << 10) /* in micro sec */ -#define FTM_PARAMS_TSF_FW_MAX FTM_PARAMS_TSF_FW_HI -#define FTM_PARAMS_TSF_BW_MAX (FTM_PARAMS_TSF_BW_HI - FTM_PARAMS_TSF_BW_LOW) - -#define FTM_PARAMS_PTSFNOPREF_OFFSET 5 -#define FTM_PARAMS_PTSFNOPREF_MASK 0x1 -#define FTM_PARAMS_PTSFNOPREF_SHIFT 0 -#define FTM_PARAMS_PTSFNOPREF(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_PTSFNOPREF_OFFSET, \ - FTM_PARAMS_PTSFNOPREF_MASK, FTM_PARAMS_PTSFNOPREF_SHIFT) -#define FTM_PARAMS_SET_PTSFNOPREF(_p, _nopref) FTM_PARAMS_SET_FIELD(_p, \ - FTM_PARAMS_PTSFNOPREF_OFFSET, FTM_PARAMS_PTSFNOPREF_MASK, \ - FTM_PARAMS_PTSFNOPREF_SHIFT, _nopref) - -#define FTM_PARAMS_ASAP_OFFSET 5 -#define FTM_PARAMS_ASAP_MASK 0x4 -#define FTM_PARAMS_ASAP_SHIFT 2 -#define FTM_PARAMS_ASAP(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_ASAP_OFFSET, \ - FTM_PARAMS_ASAP_MASK, FTM_PARAMS_ASAP_SHIFT) -#define FTM_PARAMS_SET_ASAP(_p, _asap) FTM_PARAMS_SET_FIELD(_p, \ - FTM_PARAMS_ASAP_OFFSET, FTM_PARAMS_ASAP_MASK, FTM_PARAMS_ASAP_SHIFT, _asap) - -/* FTM1 - AKA ASAP Capable */ -#define FTM_PARAMS_FTM1_OFFSET 5 -#define FTM_PARAMS_FTM1_MASK 0x02 -#define FTM_PARAMS_FTM1_SHIFT 1 -#define FTM_PARAMS_FTM1(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_FTM1_OFFSET, \ - FTM_PARAMS_FTM1_MASK, FTM_PARAMS_FTM1_SHIFT) -#define FTM_PARAMS_SET_FTM1(_p, _ftm1) FTM_PARAMS_SET_FIELD(_p, \ - FTM_PARAMS_FTM1_OFFSET, FTM_PARAMS_FTM1_MASK, FTM_PARAMS_FTM1_SHIFT, _ftm1) - -#define FTM_PARAMS_FTMS_PER_BURST_OFFSET 5 -#define FTM_PARAMS_FTMS_PER_BURST_MASK 0xf8 -#define FTM_PARAMS_FTMS_PER_BURST_SHIFT 3 -#define FTM_PARAMS_FTMS_PER_BURST(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_FTMS_PER_BURST_OFFSET, \ - FTM_PARAMS_FTMS_PER_BURST_MASK, FTM_PARAMS_FTMS_PER_BURST_SHIFT) -#define FTM_PARAMS_SET_FTMS_PER_BURST(_p, _nftms) FTM_PARAMS_SET_FIELD(_p, \ - FTM_PARAMS_FTMS_PER_BURST_OFFSET, FTM_PARAMS_FTMS_PER_BURST_MASK, \ - FTM_PARAMS_FTMS_PER_BURST_SHIFT, _nftms) - -enum { - FTM_PARAMS_FTMS_PER_BURST_NOPREF = 0 -}; - -#define FTM_PARAMS_CHAN_INFO_OFFSET 6 -#define FTM_PARAMS_CHAN_INFO_MASK 0xfc -#define FTM_PARAMS_CHAN_INFO_SHIFT 2 -#define FTM_PARAMS_CHAN_INFO(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_CHAN_INFO_OFFSET, \ - FTM_PARAMS_CHAN_INFO_MASK, FTM_PARAMS_CHAN_INFO_SHIFT) -#define FTM_PARAMS_SET_CHAN_INFO(_p, _ci) FTM_PARAMS_SET_FIELD(_p, \ - FTM_PARAMS_CHAN_INFO_OFFSET, FTM_PARAMS_CHAN_INFO_MASK, FTM_PARAMS_CHAN_INFO_SHIFT, _ci) - -/* burst period - units of 100ms */ -#define FTM_PARAMS_BURST_PERIOD(_p) (((_p)->info[8] << 8) | (_p)->info[7]) -#define FTM_PARAMS_SET_BURST_PERIOD(_p, _bp) do {\ - (_p)->info[7] = (_bp) & 0xff; \ - (_p)->info[8] = ((_bp) >> 8) & 0xff; \ -} while (0) - -#define FTM_PARAMS_BURST_PERIOD_MS(_p) (FTM_PARAMS_BURST_PERIOD(_p) * 100) - -enum { - FTM_PARAMS_BURST_PERIOD_NOPREF = 0 -}; - -/* FTM status values - last updated from 11mcD4.0 */ -enum { - FTM_PARAMS_STATUS_RESERVED = 0, - FTM_PARAMS_STATUS_SUCCESSFUL = 1, - FTM_PARAMS_STATUS_INCAPABLE = 2, - FTM_PARAMS_STATUS_FAILED = 3, - /* Below are obsolte */ - FTM_PARAMS_STATUS_OVERRIDDEN = 4, - FTM_PARAMS_STATUS_ASAP_INCAPABLE = 5, - FTM_PARAMS_STATUS_ASAP_FAILED = 6, - /* rest are reserved */ -}; - -enum { - FTM_PARAMS_CHAN_INFO_NO_PREF = 0, - FTM_PARAMS_CHAN_INFO_RESERVE1 = 1, - FTM_PARAMS_CHAN_INFO_RESERVE2 = 2, - FTM_PARAMS_CHAN_INFO_RESERVE3 = 3, - FTM_PARAMS_CHAN_INFO_NON_HT_5 = 4, - FTM_PARAMS_CHAN_INFO_RESERVE5 = 5, - FTM_PARAMS_CHAN_INFO_NON_HT_10 = 6, - FTM_PARAMS_CHAN_INFO_RESERVE7 = 7, - FTM_PARAMS_CHAN_INFO_NON_HT_20 = 8, /* excludes 2.4G, and High rate DSSS */ - FTM_PARAMS_CHAN_INFO_HT_MF_20 = 9, - FTM_PARAMS_CHAN_INFO_VHT_20 = 10, - FTM_PARAMS_CHAN_INFO_HT_MF_40 = 11, - FTM_PARAMS_CHAN_INFO_VHT_40 = 12, - FTM_PARAMS_CHAN_INFO_VHT_80 = 13, - FTM_PARAMS_CHAN_INFO_VHT_80_80 = 14, - FTM_PARAMS_CHAN_INFO_VHT_160_2_RFLOS = 15, - FTM_PARAMS_CHAN_INFO_VHT_160 = 16, - /* Reserved from 17 - 30 */ - FTM_PARAMS_CHAN_INFO_DMG_2160 = 31, - /* Reserved from 32 - 63 */ - FTM_PARAMS_CHAN_INFO_MAX = 63 -}; - -/* tag_ID/length/value_buffer tuple */ -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 id; - uint8 len; - uint8 data[1]; -} BWL_POST_PACKED_STRUCT ftm_vs_tlv_t; - -BWL_PRE_PACKED_STRUCT struct dot11_ftm_vs_ie { - uint8 id; /* DOT11_MNG_VS_ID */ - uint8 len; /* length following */ - uint8 oui[3]; /* BRCM_PROP_OUI (or Customer) */ - uint8 sub_type; /* BRCM_FTM_IE_TYPE (or Customer) */ - uint8 version; - ftm_vs_tlv_t tlvs[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm_vs_ie dot11_ftm_vs_ie_t; - -/* same as payload of dot11_ftm_vs_ie. -* This definition helps in having struct access -* of pay load while building FTM VS IE from other modules(NAN) -*/ -BWL_PRE_PACKED_STRUCT struct dot11_ftm_vs_ie_pyld { - uint8 sub_type; /* BRCM_FTM_IE_TYPE (or Customer) */ - uint8 version; - ftm_vs_tlv_t tlvs[1]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm_vs_ie_pyld dot11_ftm_vs_ie_pyld_t; - -/* ftm vs api version */ -#define BCM_FTM_VS_PARAMS_VERSION 0x01 - -/* ftm vendor specific information tlv types */ -enum { - FTM_VS_TLV_NONE = 0, - FTM_VS_TLV_REQ_PARAMS = 1, /* additional request params (in FTM_REQ) */ - FTM_VS_TLV_MEAS_INFO = 2, /* measurement information (in FTM_MEAS) */ - FTM_VS_TLV_SEC_PARAMS = 3, /* security parameters (in either) */ - FTM_VS_TLV_SEQ_PARAMS = 4, /* toast parameters (FTM_REQ, BRCM proprietary) */ - FTM_VS_TLV_MF_BUF = 5, /* multi frame buffer - may span ftm vs ie's */ - FTM_VS_TLV_TIMING_PARAMS = 6, /* timing adjustments */ - FTM_VS_TLV_MF_STATS_BUF = 7 /* multi frame statistics buffer */ - /* add additional types above */ -}; - -/* the following definitions are *DEPRECATED* and moved to implementation files. They - * are retained here because previous (May 2016) some branches use them - */ -#define FTM_TPK_LEN 16u -#define FTM_RI_RR_BUF_LEN 32u -#define FTM_TPK_RI_RR_LEN 13 -#define FTM_TPK_RI_RR_LEN_SECURE_2_0 28 -#define FTM_TPK_RI_PHY_LEN 7u -#define FTM_TPK_RR_PHY_LEN 7u -#define FTM_TPK_DATA_BUFFER_LEN 88u -#define FTM_TPK_LEN_SECURE_2_0 64u -#define FTM_TPK_RI_PHY_LEN_SECURE_2_0 14u -#define FTM_TPK_RR_PHY_LEN_SECURE_2_0 14u - -#define FTM_RI_RR_BUF_LEN_20MHZ 32u -#define FTM_RI_RR_BUF_LEN_80MHZ 64u - -#define FTM_RI_RR_BUF_LEN_FROM_CHANSPEC(chanspec) \ - (CHSPEC_IS20((chanspec)) ? \ - FTM_RI_RR_BUF_LEN_20MHZ : FTM_RI_RR_BUF_LEN_80MHZ) - -#define FTM_TPK_RI_RR_LEN_SECURE_2_0_20MHZ 28u -#define FTM_TPK_RI_RR_LEN_SECURE_2_0_80MHZ 62u -#define FTM_TPK_RI_RR_LEN_SECURE_2_0_2G FTM_TPK_RI_RR_LEN_SECURE_2_0 -#define FTM_TPK_RI_RR_LEN_SECURE_2_0_5G FTM_TPK_RI_RR_LEN_SECURE_2_0_80MHZ - -#define FTM_TPK_RI_RR_LEN_FROM_CHANSPEC(chanspec) \ - (CHSPEC_IS20((chanspec)) ? FTM_TPK_RI_RR_LEN_SECURE_2_0_20MHZ : \ - FTM_TPK_RI_RR_LEN_SECURE_2_0_80MHZ) - -#define FTM_TPK_RI_PHY_LEN_SECURE_2_0_20MHZ 14u -#define FTM_TPK_RI_PHY_LEN_SECURE_2_0_80MHZ 31u -#define FTM_TPK_RR_PHY_LEN_SECURE_2_0_80MHZ 31u - -#define FTM_TPK_RI_PHY_LEN_FROM_CHANSPEC(chanspec) \ - (CHSPEC_IS20((chanspec)) ? FTM_TPK_RI_PHY_LEN_SECURE_2_0_20MHZ : \ - FTM_TPK_RI_PHY_LEN_SECURE_2_0_80MHZ) - -#define FTM_TPK_RR_PHY_LEN_SECURE_2_0_20MHZ 14u - -#define FTM_TPK_RR_PHY_LEN_FROM_CHANSPEC(chanspec) \ - (CHSPEC_IS20((chanspec)) ? FTM_TPK_RR_PHY_LEN_SECURE_2_0_20MHZ : \ - FTM_TPK_RR_PHY_LEN_SECURE_2_0_80MHZ) - -BWL_PRE_PACKED_STRUCT struct dot11_ftm_vs_params { - uint8 id; /* DOT11_MNG_VS_ID */ - uint8 len; - uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ - uint8 bcm_vs_id; - ftm_vs_tlv_t ftm_tpk_ri_rr[1]; /* ftm_TPK_ri_rr place holder */ -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm_vs_params dot11_ftm_vs_tpk_ri_rr_params_t; -#define DOT11_FTM_VS_LEN (sizeof(dot11_ftm_vs_tpk_ri_rr_params_t) - TLV_HDR_LEN) -/* end *DEPRECATED* ftm definitions */ - -BWL_PRE_PACKED_STRUCT struct dot11_ftm_sync_info { - uint8 id; /* Extended - 255 11mc D4.3 */ - uint8 len; - uint8 id_ext; - uint8 tsf_sync_info[4]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_ftm_sync_info dot11_ftm_sync_info_t; - -/* ftm tsf sync info ie len - includes id ext */ -#define DOT11_FTM_SYNC_INFO_IE_LEN (sizeof(dot11_ftm_sync_info_t) - TLV_HDR_LEN) - -#define DOT11_FTM_IS_SYNC_INFO_IE(_ie) (\ - DOT11_MNG_IE_ID_EXT_MATCH(_ie, DOT11_MNG_FTM_SYNC_INFO) && \ - (_ie)->len == DOT11_FTM_SYNC_INFO_IE_LEN) - -BWL_PRE_PACKED_STRUCT struct dot11_dh_param_ie { - uint8 id; /* OWE */ - uint8 len; - uint8 ext_id; /* EXT_MNG_OWE_DH_PARAM_ID */ - uint16 group; - uint8 pub_key[0]; -} BWL_POST_PACKED_STRUCT; -typedef struct dot11_dh_param_ie dot11_dh_param_ie_t; - -#define DOT11_DH_EXTID_OFFSET (OFFSETOF(dot11_dh_param_ie_t, ext_id)) - -#define DOT11_OWE_DH_PARAM_IE(_ie) (\ - DOT11_MNG_IE_ID_EXT_MATCH(_ie, EXT_MNG_OWE_DH_PARAM_ID)) - -#define DOT11_MNG_OWE_IE_ID_EXT_INIT(_ie, _id, _len) do {\ - (_ie)->id = DOT11_MNG_ID_EXT_ID; \ - (_ie)->len = _len; \ - (_ie)->ext_id = _id; \ -} while (0) - -/* 802.11u interworking access network options */ -#define IW_ANT_MASK 0x0f -#define IW_INTERNET_MASK 0x10 -#define IW_ASRA_MASK 0x20 -#define IW_ESR_MASK 0x40 -#define IW_UESA_MASK 0x80 - -/* 802.11u interworking access network type */ -#define IW_ANT_PRIVATE_NETWORK 0 -#define IW_ANT_PRIVATE_NETWORK_WITH_GUEST 1 -#define IW_ANT_CHARGEABLE_PUBLIC_NETWORK 2 -#define IW_ANT_FREE_PUBLIC_NETWORK 3 -#define IW_ANT_PERSONAL_DEVICE_NETWORK 4 -#define IW_ANT_EMERGENCY_SERVICES_NETWORK 5 -#define IW_ANT_TEST_NETWORK 14 -#define IW_ANT_WILDCARD_NETWORK 15 - -#define IW_ANT_LEN 1 -#define IW_VENUE_LEN 2 -#define IW_HESSID_LEN 6 -#define IW_HESSID_OFF (IW_ANT_LEN + IW_VENUE_LEN) -#define IW_MAX_LEN (IW_ANT_LEN + IW_VENUE_LEN + IW_HESSID_LEN) - -/* 802.11u advertisement protocol */ -#define ADVP_ANQP_PROTOCOL_ID 0 -#define ADVP_MIH_PROTOCOL_ID 1 - -/* 802.11u advertisement protocol masks */ -#define ADVP_QRL_MASK 0x7f -#define ADVP_PAME_BI_MASK 0x80 - -/* 802.11u advertisement protocol values */ -#define ADVP_QRL_REQUEST 0x00 -#define ADVP_QRL_RESPONSE 0x7f -#define ADVP_PAME_BI_DEPENDENT 0x00 -#define ADVP_PAME_BI_INDEPENDENT ADVP_PAME_BI_MASK - -/* 802.11u ANQP information ID */ -#define ANQP_ID_QUERY_LIST 256 -#define ANQP_ID_CAPABILITY_LIST 257 -#define ANQP_ID_VENUE_NAME_INFO 258 -#define ANQP_ID_EMERGENCY_CALL_NUMBER_INFO 259 -#define ANQP_ID_NETWORK_AUTHENTICATION_TYPE_INFO 260 -#define ANQP_ID_ROAMING_CONSORTIUM_LIST 261 -#define ANQP_ID_IP_ADDRESS_TYPE_AVAILABILITY_INFO 262 -#define ANQP_ID_NAI_REALM_LIST 263 -#define ANQP_ID_G3PP_CELLULAR_NETWORK_INFO 264 -#define ANQP_ID_AP_GEOSPATIAL_LOCATION 265 -#define ANQP_ID_AP_CIVIC_LOCATION 266 -#define ANQP_ID_AP_LOCATION_PUBLIC_ID_URI 267 -#define ANQP_ID_DOMAIN_NAME_LIST 268 -#define ANQP_ID_EMERGENCY_ALERT_ID_URI 269 -#define ANQP_ID_EMERGENCY_NAI 271 -#define ANQP_ID_NEIGHBOR_REPORT 272 -#define ANQP_ID_VENDOR_SPECIFIC_LIST 56797 - -/* 802.11u ANQP ID len */ -#define ANQP_INFORMATION_ID_LEN 2 - -/* 802.11u ANQP OUI */ -#define ANQP_OUI_SUBTYPE 9 - -/* 802.11u venue name */ -#define VENUE_LANGUAGE_CODE_SIZE 3 -#define VENUE_NAME_SIZE 255 - -/* 802.11u venue groups */ -#define VENUE_UNSPECIFIED 0 -#define VENUE_ASSEMBLY 1 -#define VENUE_BUSINESS 2 -#define VENUE_EDUCATIONAL 3 -#define VENUE_FACTORY 4 -#define VENUE_INSTITUTIONAL 5 -#define VENUE_MERCANTILE 6 -#define VENUE_RESIDENTIAL 7 -#define VENUE_STORAGE 8 -#define VENUE_UTILITY 9 -#define VENUE_VEHICULAR 10 -#define VENUE_OUTDOOR 11 - -/* 802.11u network authentication type indicator */ -#define NATI_UNSPECIFIED -1 -#define NATI_ACCEPTANCE_OF_TERMS_CONDITIONS 0 -#define NATI_ONLINE_ENROLLMENT_SUPPORTED 1 -#define NATI_HTTP_HTTPS_REDIRECTION 2 -#define NATI_DNS_REDIRECTION 3 - -/* 802.11u IP address type availability - IPv6 */ -#define IPA_IPV6_SHIFT 0 -#define IPA_IPV6_MASK (0x03 << IPA_IPV6_SHIFT) -#define IPA_IPV6_NOT_AVAILABLE 0x00 -#define IPA_IPV6_AVAILABLE 0x01 -#define IPA_IPV6_UNKNOWN_AVAILABILITY 0x02 - -/* 802.11u IP address type availability - IPv4 */ -#define IPA_IPV4_SHIFT 2 -#define IPA_IPV4_MASK (0x3f << IPA_IPV4_SHIFT) -#define IPA_IPV4_NOT_AVAILABLE 0x00 -#define IPA_IPV4_PUBLIC 0x01 -#define IPA_IPV4_PORT_RESTRICT 0x02 -#define IPA_IPV4_SINGLE_NAT 0x03 -#define IPA_IPV4_DOUBLE_NAT 0x04 -#define IPA_IPV4_PORT_RESTRICT_SINGLE_NAT 0x05 -#define IPA_IPV4_PORT_RESTRICT_DOUBLE_NAT 0x06 -#define IPA_IPV4_UNKNOWN_AVAILABILITY 0x07 - -/* 802.11u NAI realm encoding */ -#define REALM_ENCODING_RFC4282 0 -#define REALM_ENCODING_UTF8 1 - -/* 802.11u IANA EAP method type numbers */ -#define REALM_EAP_TLS 13 -#define REALM_EAP_LEAP 17 -#define REALM_EAP_SIM 18 -#define REALM_EAP_TTLS 21 -#define REALM_EAP_AKA 23 -#define REALM_EAP_PEAP 25 -#define REALM_EAP_FAST 43 -#define REALM_EAP_PSK 47 -#define REALM_EAP_AKAP 50 -#define REALM_EAP_EXPANDED 254 - -/* 802.11u authentication ID */ -#define REALM_EXPANDED_EAP 1 -#define REALM_NON_EAP_INNER_AUTHENTICATION 2 -#define REALM_INNER_AUTHENTICATION_EAP 3 -#define REALM_EXPANDED_INNER_EAP 4 -#define REALM_CREDENTIAL 5 -#define REALM_TUNNELED_EAP_CREDENTIAL 6 -#define REALM_VENDOR_SPECIFIC_EAP 221 - -/* 802.11u non-EAP inner authentication type */ -#define REALM_RESERVED_AUTH 0 -#define REALM_PAP 1 -#define REALM_CHAP 2 -#define REALM_MSCHAP 3 -#define REALM_MSCHAPV2 4 - -/* 802.11u credential type */ -#define REALM_SIM 1 -#define REALM_USIM 2 -#define REALM_NFC 3 -#define REALM_HARDWARE_TOKEN 4 -#define REALM_SOFTOKEN 5 -#define REALM_CERTIFICATE 6 -#define REALM_USERNAME_PASSWORD 7 -#define REALM_SERVER_SIDE 8 -#define REALM_RESERVED_CRED 9 -#define REALM_VENDOR_SPECIFIC_CRED 10 - -/* 802.11u 3GPP PLMN */ -#define G3PP_GUD_VERSION 0 -#define G3PP_PLMN_LIST_IE 0 - /* AP Location Public ID Info encoding */ #define PUBLIC_ID_URI_FQDN_SE_ID 0 /* URI/FQDN Descriptor field values */ @@ -5831,21 +2385,12 @@ typedef struct dot11_dh_param_ie dot11_dh_param_ie_t; #define LOCATION_ENCODING_SUPL 2 #define URI_FQDN_SIZE 255 -/** hotspot2.0 indication element (vendor specific) */ -BWL_PRE_PACKED_STRUCT struct hs20_ie { - uint8 oui[3]; - uint8 type; - uint8 config; -} BWL_POST_PACKED_STRUCT; -typedef struct hs20_ie hs20_ie_t; -#define HS20_IE_LEN 5 /* HS20 IE length */ - /* Short SSID list Extended Capabilities element */ BWL_PRE_PACKED_STRUCT struct short_ssid_list_ie { uint8 id; uint8 len; uint8 id_ext; - uint8 data[1]; /* Capabilities Information */ + uint8 data[BCM_FLEX_ARRAY]; /* Capabilities Information */ } BWL_POST_PACKED_STRUCT; typedef struct short_ssid_list_ie short_ssid_list_ie_t; @@ -5874,31 +2419,6 @@ typedef enum { /* QoS map */ #define QOS_MAP_FIXED_LENGTH (8 * 2) /* DSCP ranges fixed with 8 entries */ -/* BCM proprietary IE type for AIBSS */ -#define BCM_AIBSS_IE_TYPE 56 - -/* BCM proprietary flag type for WL_DISCO_VSIE */ -#define SSE_OUI "\x00\x00\xF0" -#define VENDOR_ENTERPRISE_STA_OUI_TYPE 0x22 -#define MAX_VSIE_DISASSOC (1) -#define DISCO_VSIE_LEN 0x09u - -/* Single PMK IE */ -#define CCX_SPMK_TYPE 3 /* CCX Extended Cap IE type for SPMK */ -/* CCX Extended Capability IE */ -BWL_PRE_PACKED_STRUCT struct ccx_spmk_cap_ie { - uint8 id; /* 221, DOT11_MNG_PROPR_ID */ - uint8 len; - uint8 oui[DOT11_OUI_LEN]; /* 00:40:96, CISCO_AIRONET_OUI */ - uint8 type; /* 11 */ - uint8 cap; -} BWL_POST_PACKED_STRUCT; -typedef struct ccx_spmk_cap_ie ccx_spmk_cap_ie_t; - -/* OWE definitions */ -/* ID + len + OUI + OI type + BSSID + SSID_len */ -#define OWE_TRANS_MODE_IE_FIXED_LEN 13u - /* Supported Operating Classes element */ BWL_PRE_PACKED_STRUCT struct supp_op_classes_ie { uint8 id; @@ -5908,13 +2428,62 @@ BWL_PRE_PACKED_STRUCT struct supp_op_classes_ie { } BWL_POST_PACKED_STRUCT; typedef struct supp_op_classes_ie supp_op_classes_ie_t; -/* Transition mode (bit number) */ -#define TRANSISION_MODE_WPA3_PSK 0u -#define TRANSITION_MODE_SAE_PK 1u -#define TRANSITION_MODE_WPA3_ENTERPRISE 2u -#define TRANSITION_MODE_ENHANCED_OPEN 3u +/* Requset IE */ +BWL_PRE_PACKED_STRUCT struct dot11_req_ie { + uint8 id; /* DOT11_MNG_REQUEST_ID */ + uint8 len; + uint8 ids[]; /* requested element IDs */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_req_ie dot11_req_ie_t; + +/* Extended Requset IE */ +BWL_PRE_PACKED_STRUCT struct dot11_ext_req_ie { + uint8 id; /* DOT11_MNG_ID_EXT_ID */ + uint8 len; + uint8 id_ext; /* element ID extension */ + uint8 reqd_id; /* requested element ID */ + uint8 id_exts[]; /* requested element ID extensions */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ext_req_ie dot11_ext_req_ie_t; /* This marks the end of a packed structure section. */ #include +/* Include 802.11*.h here for wlioctl.h compatibility. + * Move them to wlioctl.h when possible. + */ +#include <802.11k.h> +#include <802.11n.h> +#include <802.11v.h> +#include <802.11ac.h> +#include <802.11az.h> + +/* Include 802.11*.h here for nan component shared by older branches. + * Move them to where their contents are referenced when possible. + */ +#include <802.11w.h> +#include <802.11wfa.h> + +/* Include 802.11wapi.h for components/bcmcrypto/src/sms4.c in some older branches. + * Move the inclusion there when possible. + */ +#include <802.11wapi.h> + +/* Include 802.11brcm.h for components/bcmutils/src/bcmevent.c in some older branches. + * Move the inclusion there when possible. + */ +#include <802.11brcm.h> + +/* Include 802.11cust.h here for src/wl/sys/wlc_act_frame.c in some older branches. + * Move it there when possible. + */ +#include <802.11cust.h> + +/* Include 802.11u/owe.h here for host compatibility. + * Move them there when possible. + */ +#include <802.11u.h> +#include <802.11z.h> +#include <802.11owe.h> + #endif /* _802_11_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ac.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ac.h new file mode 100644 index 000000000000..8d40684ace42 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ac.h @@ -0,0 +1,487 @@ +/* + * Fundamental types and constants relating to 802.11ac - + * "Enhancements for Very High Throughput for Operation in Bands below 6 GHz" + * + * VHT - Very High Throughput + * OPER_MODE - Operating Mode + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _802_11ac_h_ +#define _802_11ac_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +#ifndef _NET_ETHERNET_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +BWL_PRE_PACKED_STRUCT struct dot11_action_vht_oper_mode { + uint8 category; + uint8 action; + uint8 mode; +} BWL_POST_PACKED_STRUCT; + +/* These lengths assume 64 MU groups, as specified in 802.11ac-2013 */ +#define DOT11_ACTION_GID_MEMBERSHIP_LEN 8 /* bytes */ +#define DOT11_ACTION_GID_USER_POS_LEN 16 /* bytes */ +BWL_PRE_PACKED_STRUCT struct dot11_action_group_id { + uint8 category; + uint8 action; + uint8 membership_status[DOT11_ACTION_GID_MEMBERSHIP_LEN]; + uint8 user_position[DOT11_ACTION_GID_USER_POS_LEN]; +} BWL_POST_PACKED_STRUCT; + +/** Wide Bandwidth Channel Switch IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel_switch { + uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + uint8 channel_width; /* new channel width */ + uint8 center_frequency_segment_0; /* center frequency segment 0 */ + uint8 center_frequency_segment_1; /* center frequency segment 1 */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wide_bw_channel_switch dot11_wide_bw_chan_switch_ie_t; + +#define DOT11_WIDE_BW_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ + +/** Channel Switch Wrapper IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_channel_switch_wrapper { + uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + dot11_wide_bw_chan_switch_ie_t wb_chan_switch_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_channel_switch_wrapper dot11_chan_switch_wrapper_ie_t; + +/* Proposed wide bandwidth channel IE */ +typedef enum wide_bw_chan_width { + WIDE_BW_CHAN_WIDTH_20 = 0, + WIDE_BW_CHAN_WIDTH_40 = 1, + WIDE_BW_CHAN_WIDTH_80 = 2, + WIDE_BW_CHAN_WIDTH_160 = 3, + WIDE_BW_CHAN_WIDTH_80_80 = 4 +} wide_bw_chan_width_t; + +/** Wide Bandwidth Channel IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel { + uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_ID */ + uint8 len; /* length of IE */ + uint8 channel_width; /* channel width */ + uint8 center_frequency_segment_0; /* center frequency segment 0 */ + uint8 center_frequency_segment_1; /* center frequency segment 1 */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wide_bw_channel dot11_wide_bw_chan_ie_t; + +#define DOT11_WIDE_BW_IE_LEN 3 /* length of IE data, not including 2 byte header */ +/** VHT Transmit Power Envelope IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_vht_transmit_power_envelope { + uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + uint8 transmit_power_info; + uint8 local_max_transmit_power_20; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_vht_transmit_power_envelope dot11_vht_transmit_power_envelope_ie_t; + +/* vht transmit power envelope IE length depends on channel width */ +#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_40MHZ 1 +#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_80MHZ 2 +#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_160MHZ 3 + +/* VHT Operating mode bit fields - (11ac D8.0/802.11-2016 - 9.4.1.53) */ +#define DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT 0 +#define DOT11_OPER_MODE_CHANNEL_WIDTH_MASK 0x3 +#define DOT11_OPER_MODE_160_8080_BW_SHIFT 2 +#define DOT11_OPER_MODE_160_8080_BW_MASK 0x04 +#define DOT11_OPER_MODE_NOLDPC_SHIFT 3 +#define DOT11_OPER_MODE_NOLDPC_MASK 0x08 +#define DOT11_OPER_MODE_RXNSS_SHIFT 4 +#define DOT11_OPER_MODE_RXNSS_MASK 0x70 +#define DOT11_OPER_MODE_RXNSS_TYPE_SHIFT 7 +#define DOT11_OPER_MODE_RXNSS_TYPE_MASK 0x80 + +#define DOT11_OPER_MODE_RESET_CHAN_WIDTH_160MHZ(oper_mode) \ + (oper_mode & (~(DOT11_OPER_MODE_CHANNEL_WIDTH_MASK | \ + DOT11_OPER_MODE_160_8080_BW_MASK))) +#define DOT11_OPER_MODE_SET_CHAN_WIDTH_160MHZ(oper_mode) \ + (oper_mode = (DOT11_OPER_MODE_RESET_CHAN_WIDTH_160MHZ(oper_mode) | \ + (DOT11_OPER_MODE_80MHZ | DOT11_OPER_MODE_160_8080_BW_MASK))) + +#ifdef DOT11_OPER_MODE_LEFT_SHIFT_FIX + +#define DOT11_OPER_MODE(type, nss, chanw) (\ + ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ + DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ + (((nss) - 1u) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ + ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ + DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) + +#define DOT11_D8_OPER_MODE(type, nss, ldpc, bw160_8080, chanw) (\ + ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ + DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ + (((nss) - 1u) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ + ((ldpc) << DOT11_OPER_MODE_NOLDPC_SHIFT & DOT11_OPER_MODE_NOLDPC_MASK) |\ + ((bw160_8080) << DOT11_OPER_MODE_160_8080_BW_SHIFT &\ + DOT11_OPER_MODE_160_8080_BW_MASK) |\ + ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ + DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) + +#else + +/* avoid invalidation from above fix on release branches, can be removed when older release + * branches no longer use component/proto from trunk + */ + +#define DOT11_OPER_MODE(type, nss, chanw) (\ + ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ + DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ + (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ + ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ + DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) + +#define DOT11_D8_OPER_MODE(type, nss, ldpc, bw160_8080, chanw) (\ + ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ + DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ + (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ + ((ldpc) << DOT11_OPER_MODE_NOLDPC_SHIFT & DOT11_OPER_MODE_NOLDPC_MASK) |\ + ((bw160_8080) << DOT11_OPER_MODE_160_8080_BW_SHIFT &\ + DOT11_OPER_MODE_160_8080_BW_MASK) |\ + ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ + DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) + +#endif /* DOT11_OPER_MODE_LEFT_SHIFT_FIX */ + +#define DOT11_OPER_MODE_CHANNEL_WIDTH(mode) \ + (((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)\ + >> DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT) +#define DOT11_OPER_MODE_160_8080(mode) \ + (((mode) & DOT11_OPER_MODE_160_8080_BW_MASK)\ + >> DOT11_OPER_MODE_160_8080_BW_SHIFT) +#define DOT11_OPER_MODE_NOLDPC(mode) \ + (((mode) & DOT11_OPER_MODE_NOLDPC_MASK)\ + >> DOT11_OPER_MODE_NOLDPC_SHIFT) +#define DOT11_OPER_MODE_RXNSS(mode) \ + ((((mode) & DOT11_OPER_MODE_RXNSS_MASK) \ + >> DOT11_OPER_MODE_RXNSS_SHIFT) + 1) +#define DOT11_OPER_MODE_RXNSS_TYPE(mode) \ + (((mode) & DOT11_OPER_MODE_RXNSS_TYPE_MASK)\ + >> DOT11_OPER_MODE_RXNSS_TYPE_SHIFT) + +#define DOT11_OPER_MODE_20MHZ 0 +#define DOT11_OPER_MODE_40MHZ 1 +#define DOT11_OPER_MODE_80MHZ 2 +#define DOT11_OPER_MODE_160MHZ 3 +#define DOT11_OPER_MODE_8080MHZ 3 +#define DOT11_OPER_MODE_1608080MHZ 1 + +#define DOT11_OPER_MODE_CHANNEL_WIDTH_20MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_20MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_40MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_40MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_80MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_80MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_160MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_160_8080_BW_MASK)) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_8080MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_160_8080_BW_MASK)) + +/* Operating mode information element 802.11ac D3.0 - 8.4.2.168 */ +BWL_PRE_PACKED_STRUCT struct dot11_oper_mode_notif_ie { + uint8 mode; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; + +#define DOT11_OPER_MODE_NOTIF_IE_LEN 1 + +/* VHT category action types - 802.11ac D3.0 - 8.5.23.1 */ +#define DOT11_VHT_ACTION_CBF 0 /* Compressed Beamforming */ +#define DOT11_VHT_ACTION_GID_MGMT 1 /* Group ID Management */ +#define DOT11_VHT_ACTION_OPER_MODE_NOTIF 2 /* Operating mode notif'n */ + +/* 802.11 VHT constants */ + +typedef int vht_group_id_t; + +/* for VHT-A1 */ +/* SIG-A1 reserved bits */ +#define VHT_SIGA1_CONST_MASK 0x800004 + +#define VHT_SIGA1_BW_MASK 0x000003 +#define VHT_SIGA1_20MHZ_VAL 0x000000 +#define VHT_SIGA1_40MHZ_VAL 0x000001 +#define VHT_SIGA1_80MHZ_VAL 0x000002 +#define VHT_SIGA1_160MHZ_VAL 0x000003 + +#define VHT_SIGA1_STBC 0x000008 + +#define VHT_SIGA1_GID_MASK 0x0003f0 +#define VHT_SIGA1_GID_SHIFT 4 +#define VHT_SIGA1_GID_TO_AP 0x00 +#define VHT_SIGA1_GID_NOT_TO_AP 0x3f +#define VHT_SIGA1_GID_MAX_GID 0x3f + +#define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00 +#define VHT_SIGA1_NSTS_SHIFT 10 +#define VHT_SIGA1_MAX_USERPOS 3 + +#define VHT_SIGA1_PARTIAL_AID_MASK 0x3fe000 +#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 + +#define VHT_SIGA1_TXOP_PS_NOT_ALLOWED 0x400000 + +/* for VHT-A2 */ +#define VHT_SIGA2_GI_NONE 0x000000 +#define VHT_SIGA2_GI_SHORT 0x000001 +#define VHT_SIGA2_GI_W_MOD10 0x000002 +#define VHT_SIGA2_CODING_LDPC 0x000004 +#define VHT_SIGA2_LDPC_EXTRA_OFDM_SYM 0x000008 +#define VHT_SIGA2_BEAMFORM_ENABLE 0x000100 +#define VHT_SIGA2_MCS_SHIFT 4 + +#define VHT_SIGA2_B9_RESERVED 0x000200 +#define VHT_SIGA2_TAIL_MASK 0xfc0000 +#define VHT_SIGA2_TAIL_VALUE 0x000000 + +/* VHT Timing-related parameters (802.11ac D4.0, sec 22.3.6) */ +#define VHT_T_LEG_PREAMBLE 16 +#define VHT_T_L_SIG 4 +#define VHT_T_SIG_A 8 +#define VHT_T_LTF 4 +#define VHT_T_STF 4 +#define VHT_T_SIG_B 4 +#define VHT_T_SYML 4 + +#define VHT_N_SERVICE 16 /* bits in SERVICE field */ +#define VHT_N_TAIL 6 /* tail bits per BCC encoder */ + +#define VHT_MAX_MPDU 11454 /* max mpdu size for now (bytes) */ +#define VHT_MPDU_MSDU_DELTA 56 /* Difference in spec - vht mpdu, amsdu len */ +/* Max AMSDU len - per spec */ +#define VHT_MAX_AMSDU (VHT_MAX_MPDU - VHT_MPDU_MSDU_DELTA) + +/* ************* VHT definitions. ************* */ + +/** + * VHT Capabilites IE (sec 8.4.2.160) + */ + +BWL_PRE_PACKED_STRUCT struct vht_cap_ie { + uint32 vht_cap_info; + /* supported MCS set - 64 bit field */ + uint16 rx_mcs_map; + uint16 rx_max_rate; + uint16 tx_mcs_map; + uint16 tx_max_rate; +} BWL_POST_PACKED_STRUCT; +typedef struct vht_cap_ie vht_cap_ie_t; + +/* 4B cap_info + 8B supp_mcs */ +#define VHT_CAP_IE_LEN 12 + +/* VHT Capabilities Info field - 32bit - in VHT Cap IE */ +#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 +#define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c +#define VHT_CAP_INFO_LDPC 0x00000010 +#define VHT_CAP_INFO_SGI_80MHZ 0x00000020 +#define VHT_CAP_INFO_SGI_160MHZ 0x00000040 +#define VHT_CAP_INFO_TX_STBC 0x00000080 +#define VHT_CAP_INFO_RX_STBC_MASK 0x00000700 +#define VHT_CAP_INFO_RX_STBC_SHIFT 8u +#define VHT_CAP_INFO_SU_BEAMFMR 0x00000800 +#define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000 +#define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000 +#define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13u +#define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000 +#define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16u +#define VHT_CAP_INFO_MU_BEAMFMR 0x00080000 +#define VHT_CAP_INFO_MU_BEAMFMEE 0x00100000 +#define VHT_CAP_INFO_TXOPPS 0x00200000 +#define VHT_CAP_INFO_HTCVHT 0x00400000 +#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000 +#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23u +#define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000 +#define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26u +#define VHT_CAP_INFO_EXT_NSS_BW_SUP_MASK 0xc0000000 +#define VHT_CAP_INFO_EXT_NSS_BW_SUP_SHIFT 30u + +/* get Extended NSS BW Support passing vht cap info */ +#define VHT_CAP_EXT_NSS_BW_SUP(cap_info) \ + (((cap_info) & VHT_CAP_INFO_EXT_NSS_BW_SUP_MASK) >> VHT_CAP_INFO_EXT_NSS_BW_SUP_SHIFT) + +/* VHT CAP INFO extended NSS BW support - refer to IEEE 802.11 REVmc D8.0 Figure 9-559 */ +#define VHT_CAP_INFO_EXT_NSS_BW_HALF_160 1 /* 160MHz at half NSS CAP */ +#define VHT_CAP_INFO_EXT_NSS_BW_HALF_160_80P80 2 /* 160 & 80p80 MHz at half NSS CAP */ + +/* VHT Supported MCS Set - 64-bit - in VHT Cap IE */ +#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff +#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 + +#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff +#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 + +/* defines for field(s) in vht_cap_ie->rx_max_rate */ +#define VHT_CAP_MAX_NSTS_MASK 0xe000 +#define VHT_CAP_MAX_NSTS_SHIFT 13 + +/* defines for field(s) in vht_cap_ie->tx_max_rate */ +#define VHT_CAP_EXT_NSS_BW_CAP 0x2000 + +#define VHT_CAP_MCS_MAP_0_7 0 +#define VHT_CAP_MCS_MAP_0_8 1 +#define VHT_CAP_MCS_MAP_0_9 2 +#define VHT_CAP_MCS_MAP_NONE 3 +#define VHT_CAP_MCS_MAP_S 2 /* num bits for 1-stream */ +#define VHT_CAP_MCS_MAP_M 0x3 /* mask for 1-stream */ +/* assumes VHT_CAP_MCS_MAP_NONE is 3 and 2 bits are used for encoding */ +#define VHT_CAP_MCS_MAP_NONE_ALL 0xffff + +/* VHT rates bitmap */ +#define VHT_CAP_MCS_0_7_RATEMAP 0x00ff +#define VHT_CAP_MCS_0_8_RATEMAP 0x01ff +#define VHT_CAP_MCS_0_9_RATEMAP 0x03ff +#define VHT_CAP_MCS_FULL_RATEMAP VHT_CAP_MCS_0_9_RATEMAP + +#define VHT_PROP_MCS_MAP_10_11 0 +#define VHT_PROP_MCS_MAP_UNUSED1 1 +#define VHT_PROP_MCS_MAP_UNUSED2 2 +#define VHT_PROP_MCS_MAP_NONE 3 +#define VHT_PROP_MCS_MAP_NONE_ALL 0xffff + +/* VHT prop rates bitmap */ +#define VHT_PROP_MCS_10_11_RATEMAP 0x0c00 +#define VHT_PROP_MCS_FULL_RATEMAP VHT_PROP_MCS_10_11_RATEMAP + +#if !defined(VHT_CAP_MCS_MAP_0_9_NSS3) +/* remove after moving define to wlc_rate.h */ +/* mcsmap with MCS0-9 for Nss = 3 */ +#define VHT_CAP_MCS_MAP_0_9_NSS3 \ + ((VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(1)) | \ + (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(2)) | \ + (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(3))) +#endif /* !VHT_CAP_MCS_MAP_0_9_NSS3 */ + +#define VHT_CAP_MCS_MAP_NSS_MAX 8 + +/* get mcsmap with given mcs for given nss streams */ +#define VHT_CAP_MCS_MAP_CREATE(mcsmap, nss, mcs) \ + do { \ + int i; \ + for (i = 1; i <= nss; i++) { \ + VHT_MCS_MAP_SET_MCS_PER_SS(i, mcs, mcsmap); \ + } \ + } while (0) + +/* Map the mcs code to mcs bit map */ +#define VHT_MCS_CODE_TO_MCS_MAP(mcs_code) \ + ((mcs_code == VHT_CAP_MCS_MAP_0_7) ? VHT_CAP_MCS_0_7_RATEMAP : \ + (mcs_code == VHT_CAP_MCS_MAP_0_8) ? VHT_CAP_MCS_0_8_RATEMAP : \ + (mcs_code == VHT_CAP_MCS_MAP_0_9) ? VHT_CAP_MCS_0_9_RATEMAP : 0) + +/* Map the proprietary mcs code to proprietary mcs bitmap */ +#define VHT_PROP_MCS_CODE_TO_PROP_MCS_MAP(mcs_code) \ + ((mcs_code == VHT_PROP_MCS_MAP_10_11) ? VHT_PROP_MCS_10_11_RATEMAP : 0) + +/* Map the mcs bit map to mcs code */ +#define VHT_MCS_MAP_TO_MCS_CODE(mcs_map) \ + ((mcs_map == VHT_CAP_MCS_0_7_RATEMAP) ? VHT_CAP_MCS_MAP_0_7 : \ + (mcs_map == VHT_CAP_MCS_0_8_RATEMAP) ? VHT_CAP_MCS_MAP_0_8 : \ + (mcs_map == VHT_CAP_MCS_0_9_RATEMAP) ? VHT_CAP_MCS_MAP_0_9 : VHT_CAP_MCS_MAP_NONE) + +/* Map the proprietary mcs map to proprietary mcs code */ +#define VHT_PROP_MCS_MAP_TO_PROP_MCS_CODE(mcs_map) \ + (((mcs_map & 0xc00) == 0xc00) ? VHT_PROP_MCS_MAP_10_11 : VHT_PROP_MCS_MAP_NONE) + +/** VHT Capabilities Supported Channel Width */ +typedef enum vht_cap_chan_width { + VHT_CAP_CHAN_WIDTH_SUPPORT_MANDATORY = 0x00, + VHT_CAP_CHAN_WIDTH_SUPPORT_160 = 0x04, + VHT_CAP_CHAN_WIDTH_SUPPORT_160_8080 = 0x08 +} vht_cap_chan_width_t; + +/** VHT Capabilities Supported max MPDU LEN (sec 8.4.2.160.2) */ +typedef enum vht_cap_max_mpdu_len { + VHT_CAP_MPDU_MAX_4K = 0x00, + VHT_CAP_MPDU_MAX_8K = 0x01, + VHT_CAP_MPDU_MAX_11K = 0x02 +} vht_cap_max_mpdu_len_t; + +/* Maximum MPDU Length byte counts for the VHT Capabilities advertised limits */ +#define VHT_MPDU_LIMIT_4K 3895 +#define VHT_MPDU_LIMIT_8K 7991 +#define VHT_MPDU_LIMIT_11K 11454 + +/** + * VHT Operation IE (sec 8.4.2.161) + */ + +BWL_PRE_PACKED_STRUCT struct vht_op_ie { + uint8 chan_width; + uint8 chan1; + uint8 chan2; + uint16 supp_mcs; /* same def as above in vht cap */ +} BWL_POST_PACKED_STRUCT; +typedef struct vht_op_ie vht_op_ie_t; + +/* 3B VHT Op info + 2B Basic MCS */ +#define VHT_OP_IE_LEN 5 + +typedef enum vht_op_chan_width { + VHT_OP_CHAN_WIDTH_20_40 = 0, + VHT_OP_CHAN_WIDTH_80 = 1, + VHT_OP_CHAN_WIDTH_160 = 2, /* deprecated - IEEE 802.11 REVmc D8.0 Table 11-25 */ + VHT_OP_CHAN_WIDTH_80_80 = 3 /* deprecated - IEEE 802.11 REVmc D8.0 Table 11-25 */ +} vht_op_chan_width_t; + +#define VHT_OP_INFO_LEN 3 + +/* AID length */ +#define AID_IE_LEN 2 + +/* Def for rx & tx basic mcs maps - ea ss num has 2 bits of info */ +#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1) * VHT_CAP_MCS_MAP_S) +#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ + (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & VHT_CAP_MCS_MAP_M) +#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ + do { \ + (mcsMap) &= (~(VHT_CAP_MCS_MAP_M << VHT_MCS_MAP_GET_SS_IDX(nss))); \ + (mcsMap) |= (((numMcs) & VHT_CAP_MCS_MAP_M) << VHT_MCS_MAP_GET_SS_IDX(nss)); \ + } while (0) +#define VHT_MCS_SS_SUPPORTED(nss, mcsMap) \ + (VHT_MCS_MAP_GET_MCS_PER_SS((nss), (mcsMap)) != VHT_CAP_MCS_MAP_NONE) + +/* Get the max ss supported from the mcs map */ +#define VHT_MAX_SS_SUPPORTED(mcsMap) \ + VHT_MCS_SS_SUPPORTED(8, mcsMap) ? 8 : \ + VHT_MCS_SS_SUPPORTED(7, mcsMap) ? 7 : \ + VHT_MCS_SS_SUPPORTED(6, mcsMap) ? 6 : \ + VHT_MCS_SS_SUPPORTED(5, mcsMap) ? 5 : \ + VHT_MCS_SS_SUPPORTED(4, mcsMap) ? 4 : \ + VHT_MCS_SS_SUPPORTED(3, mcsMap) ? 3 : \ + VHT_MCS_SS_SUPPORTED(2, mcsMap) ? 2 : \ + VHT_MCS_SS_SUPPORTED(1, mcsMap) ? 1 : 0 + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11ac_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ah.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ah.h old mode 100755 new mode 100644 index 637284beb04d..6e30f3a21218 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ah.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ah.h @@ -2,7 +2,7 @@ * Basic types and constants relating to 802.11ah standard. * This is a portion of 802.11ah definition. The rest are in 802.11.h. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -19,7 +19,7 @@ * modifications of the software. * * - * <> + * <> */ #ifndef _802_11ah_h_ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ax.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ax.h old mode 100755 new mode 100644 index 49c5e4812f62..15672ade9e34 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ax.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11ax.h @@ -2,7 +2,7 @@ * Basic types and constants relating to 802.11ax/HE STA * This is a portion of 802.11ax definition. The rest are in 802.11.h. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -312,6 +312,8 @@ typedef uint8 he_phy_cap_t[HE_PHY_CAP_INFO_SIZE]; #define HE_PHY_RX_FULL_BW_MU_COMP_SIGB_FSZ 1 #define HE_PHY_RX_FULL_BW_MU_NON_COMP_SIGB_IDX 77 /* Rx Full BW MU PPDU Non-Comp SIGB */ #define HE_PHY_RX_FULL_BW_MU_NON_COMP_SIGB_FSZ 1 +#define HE_PHY_NOMINAL_PACKET_PADDING_IDX 78 /* Nominal Packet Padding */ +#define HE_PHY_NOMINAL_PACKET_PADDING_FSZ 2 /* HE Mac Capabilities values */ /* b3-b4: Fragmentation Support field (table 9-262z) */ @@ -407,6 +409,12 @@ typedef uint8 he_phy_cap_t[HE_PHY_CAP_INFO_SIZE]; #define HE_PHY_DCM_MAX_BW_80 2 #define HE_PHY_DCM_MAX_BW_160 3 +/* b78-b79 */ +#define HE_PHY_NOMINAL_PKT_PADDING_0_US 0 +#define HE_PHY_NOMINAL_PKT_PADDING_8_US 1 +#define HE_PHY_NOMINAL_PKT_PADDING_16_US 2 +#define HE_PHY_NOMINAL_PKT_PADDING_RESERVED 3 + /* HE Duration based RTS Threshold Figure 9-589cr */ #define HE_RTS_THRES_DISABLED 1023 #define HE_RTS_THRES_ALL_FRAMES 0 @@ -433,6 +441,12 @@ typedef uint8 he_phy_cap_t[HE_PHY_CAP_INFO_SIZE]; #define HE_MCS_CODE_SIZE 2u /* num bits */ #define HE_MCS_CODE_MASK 0x3u /* mask for 1-stream */ +/* Whenever SSID is not known and short ssid is included in the +* 6g probe request SSID element contains one octet value +* 128 in the SSID element +*/ +#define WLC_SSID_VAL_IN_SHORT_SSID 128u + /* Defines for The Max HE MCS For n SS subfield (where n = 1, ..., 8) */ #define HE_MCS_MAP_NSS_MAX 8u /* Max number of streams possible */ #define HE_MCS_NSS_SET_MASK 0xffffu /* Field is to be 16 bits long */ @@ -463,7 +477,7 @@ typedef uint8 he_phy_cap_t[HE_PHY_CAP_INFO_SIZE]; #define HE_MCS_NSS_SUP_FLD_MAX_LEN (HE_MCS_NSS_SUP_FLD_TXRX_MAP_LEN * 3u) /* HE Capabilities element */ -BWL_PRE_PACKED_STRUCT struct he_cap_ie { +typedef BWL_PRE_PACKED_STRUCT struct he_cap_ie { uint8 id; uint8 len; uint8 id_ext; @@ -471,55 +485,50 @@ BWL_PRE_PACKED_STRUCT struct he_cap_ie { he_phy_cap_t phy_cap; /* PHY Capabilities Information */ /* he_tx_rx_mcs_nss_sup_t txx_rx_mcs_nss_sup; */ /* Tx Rx HE MCS NSS Support (variable) */ /* he_ppe_ths_t ppe_ths; */ /* PPE Thresholds (optional) */ -} BWL_POST_PACKED_STRUCT; - -typedef struct he_cap_ie he_cap_ie_t; +} BWL_POST_PACKED_STRUCT he_cap_ie_t; /* Multiple BSSID element */ -BWL_PRE_PACKED_STRUCT struct nontrans_BSSID_cap { +typedef BWL_PRE_PACKED_STRUCT struct nontrans_bssid_cap { uint8 id; /* 83 */ uint8 len; uint16 capability; -} BWL_POST_PACKED_STRUCT; +} BWL_POST_PACKED_STRUCT nontrans_bssid_cap_t; +typedef nontrans_bssid_cap_t nontrans_BSSID_cap_t; -typedef struct nontrans_BSSID_cap nontrans_BSSID_cap_t; - -BWL_PRE_PACKED_STRUCT struct multi_BSSID_index { +typedef BWL_PRE_PACKED_STRUCT struct multi_bssid_index { uint8 id; /* 85 */ uint8 len; /* 3 in beacon, 1 in probe response */ uint8 bssid_index; /* between 1 and 2^n - 1 */ uint8 dtim_period; /* only valid in beacon */ uint8 dtim_count; /* only valid in beacon */ -} BWL_POST_PACKED_STRUCT; +} BWL_POST_PACKED_STRUCT multi_bssid_index_t; +typedef multi_bssid_index_t multi_BSSID_index_t; -typedef struct multi_BSSID_index multi_BSSID_index_t; - -BWL_PRE_PACKED_STRUCT struct fms_descriptor { +typedef BWL_PRE_PACKED_STRUCT struct fms_descriptor { uint8 id; /* 86 */ uint8 len; uint8 num_FMS_counters; uint8 *FMS_counters; uint8 *FMSID; -} BWL_POST_PACKED_STRUCT; +} BWL_POST_PACKED_STRUCT fms_descriptor_t; -typedef struct fms_descriptor fms_descriptor_t; - -BWL_PRE_PACKED_STRUCT struct nontrans_BSSID_profile_subie { +typedef BWL_PRE_PACKED_STRUCT struct nontrans_bssid_profile_subie { uint8 subie_id; /* 0 */ uint8 subie_len; - uint8 moreie[1]; -} BWL_POST_PACKED_STRUCT; + uint8 moreie[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT nontrans_bssid_profile_subie_t; +typedef nontrans_bssid_profile_subie_t nontrans_BSSID_profile_subie_t; -typedef struct nontrans_BSSID_profile_subie nontrans_BSSID_profile_subie_t; +#define maxBSSID_indicator maxbssid_indicator -BWL_PRE_PACKED_STRUCT struct multi_BSSID_ie { +typedef BWL_PRE_PACKED_STRUCT struct multi_bssid_ie { uint8 id; uint8 len; - uint8 maxBSSID_indicator; - nontrans_BSSID_profile_subie_t profile[1]; -} BWL_POST_PACKED_STRUCT; + uint8 maxbssid_indicator; + nontrans_bssid_profile_subie_t profile[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT multi_bssid_ie_t; +typedef multi_bssid_ie_t multi_BSSID_ie_t; -typedef struct multi_BSSID_ie multi_BSSID_ie_t; #define DOT11_MULTIPLE_BSSID_PROFILE_SUBID 0 /* Table 9-262ab, Highest MCS Supported subfield encoding */ @@ -619,16 +628,14 @@ typedef uint8 he_basic_mcs_nss_set_t[HE_BASIC_MCS_NSS_SIZE]; #define HE_OP_MAX_BSSID_IND_LEN 1u #define HE_OP_6G_OPER_INFO_LEN 5u /* HE Operation element */ -BWL_PRE_PACKED_STRUCT struct he_op_ie { +typedef BWL_PRE_PACKED_STRUCT struct he_op_ie { uint8 id; uint8 len; uint8 id_ext; he_op_parms_t parms; uint8 bsscolor_info; he_basic_mcs_nss_set_t mcs_nss_op; /* Basic HE MCS & NSS Set */ -} BWL_POST_PACKED_STRUCT; - -typedef struct he_op_ie he_op_ie_t; +} BWL_POST_PACKED_STRUCT he_op_ie_t; #define HE_OP_IE_MIN_LEN (sizeof(he_op_ie_t) - TLV_HDR_LEN) #define HE_OP_IE_MAX_LEN (sizeof(he_op_ie_t) - TLV_HDR_LEN + VHT_OP_INFO_LEN +\ @@ -652,26 +659,34 @@ typedef struct he_op_ie he_op_ie_t; #define HE_6G_OP_CTL_REG_INFO(ctl) \ ((ctl & HE_6G_CTL_REG_INFO_MASK) >> HE_6G_CTL_REG_INFO_SHIFT) +#define HE_6G_OP_REG_INFO_LOW_PWR 0u /* INDOOR Low Power */ +#define HE_6G_OP_REG_INFO_STD_PWR 1u /* Standard Power */ +#define HE_6G_OP_REG_INFO_VLP_PWR 2u /* Very low Power */ +#define HE_6G_OP_REG_INFO_INDR_ENAB 3u /* Indoor Enabled */ +#define HE_6G_OP_REG_INFO_INDR_STD_PWR 4u /* Indoor Standard Power */ +#define HE_6G_OP_REG_INFO_CAT_MAX 5u /* Category reserved */ + +#define HE_6G_CTL_DUP_BCN_SHIFT 0x02u +#define HE_6G_OP_CTL_DUP_BCN(ctl) \ + ((ctl & HE_6G_CTL_DUP_BCN_MASK) >> HE_6G_CTL_DUP_BCN_SHIFT) + /* HE 6G Operation info */ -BWL_PRE_PACKED_STRUCT struct he_6g_op_info { +typedef BWL_PRE_PACKED_STRUCT struct he_6g_op_info { uint8 pri_chan; uint8 control; uint8 seg0; uint8 seg1; uint8 min_rate; -} BWL_POST_PACKED_STRUCT; - -typedef struct he_6g_op_info he_6g_op_info_t; +} BWL_POST_PACKED_STRUCT he_6g_op_info_t; /* HE Extended Capabilities element */ -BWL_PRE_PACKED_STRUCT struct he_6g_cap_ie { +typedef BWL_PRE_PACKED_STRUCT struct he_6g_cap_ie { uint8 id; uint8 len; uint8 id_ext; uint16 cap_info; /* Capabilities Information */ -} BWL_POST_PACKED_STRUCT; +} BWL_POST_PACKED_STRUCT he_6g_cap_ie_t; -typedef struct he_6g_cap_ie he_6g_cap_ie_t; #define HE_6G_CAP_IE_LEN sizeof(he_6g_cap_ie_t) /* HE Capabilities Information bit position and fieldwidth. @@ -706,14 +721,12 @@ typedef struct he_6g_cap_ie he_6g_cap_ie_t; /** * UORA parameter set element (sec 9.4.2.244) */ -BWL_PRE_PACKED_STRUCT struct he_uora_ie { +typedef BWL_PRE_PACKED_STRUCT struct he_uora_ie { uint8 id; uint8 len; uint8 id_ext; uint8 ocw_range; -} BWL_POST_PACKED_STRUCT; - -typedef struct he_uora_ie he_uora_ie_t; +} BWL_POST_PACKED_STRUCT he_uora_ie_t; /* Bit field Masks */ #define HE_UORA_EOCW_MIN_IDX 0u @@ -725,23 +738,19 @@ typedef struct he_uora_ie he_uora_ie_t; /** * MU EDCA parameter set element (sec 9.4.2.245) */ -BWL_PRE_PACKED_STRUCT struct he_mu_ac_param_record { +typedef BWL_PRE_PACKED_STRUCT struct he_mu_ac_param_record { uint8 aci_aifsn; uint8 ecw_min_max; uint8 muedca_timer; -} BWL_POST_PACKED_STRUCT; +} BWL_POST_PACKED_STRUCT he_mu_ac_param_record_t; -typedef struct he_mu_ac_param_record he_mu_ac_param_record_t; - -BWL_PRE_PACKED_STRUCT struct he_muedca_ie { +typedef BWL_PRE_PACKED_STRUCT struct he_muedca_ie { uint8 id; uint8 len; uint8 id_ext; uint8 mu_qos_info; he_mu_ac_param_record_t param_ac[AC_COUNT]; -} BWL_POST_PACKED_STRUCT; - -typedef struct he_muedca_ie he_muedca_ie_t; +} BWL_POST_PACKED_STRUCT he_muedca_ie_t; #define HE_MU_EDCA_PARAM_UPD_CNT_IDX 0u /* EDCA Parameter Set Update Count */ #define HE_MU_EDCA_PARAM_UPD_CNT_LEN 4u @@ -767,14 +776,12 @@ typedef struct he_muedca_ie he_muedca_ie_t; /* Reserved b5-b7 */ /* Spatial reuse element element */ -BWL_PRE_PACKED_STRUCT struct he_srp_ie { +typedef BWL_PRE_PACKED_STRUCT struct he_srp_ie { uint8 id; uint8 len; uint8 id_ext; uint8 sr_control; -} BWL_POST_PACKED_STRUCT; - -typedef struct he_srp_ie he_srp_ie_t; +} BWL_POST_PACKED_STRUCT he_srp_ie_t; #define HE_SRP_NON_SRG_OBSS_PD_MAX_OFFSET_LEN 1u #define HE_SRP_SRG_OBSS_PD_MIN_OFFSET_LEN 1u @@ -815,15 +822,13 @@ typedef struct he_srp_ie he_srp_ie_t; #define HE_BSSCOLOR_CHANGE_NEWCOLOR_FSZ 6u /* HE Bsscolor change element */ -BWL_PRE_PACKED_STRUCT struct he_bsscolor_change_ie { +typedef BWL_PRE_PACKED_STRUCT struct he_bsscolor_change_ie { uint8 id; uint8 len; uint8 id_ext; uint8 color_switch_cntdwn; uint8 new_bsscolor_info; -} BWL_POST_PACKED_STRUCT; - -typedef struct he_bsscolor_change_ie he_bsscolor_change_ie_t; +} BWL_POST_PACKED_STRUCT he_bsscolor_change_ie_t; /* HE SU bit position and field width */ #define HE_SU_PPDU_FORMAT_IDX 0u @@ -1177,4 +1182,20 @@ typedef uint8 he_trig_usrinfo_set_t[HE_TRIG_USRINFO_SZ]; #define HE_N_SERVICE 16 /* bits in service field */ #define HE_T_MAX_PE 16 /* max Packet extension duration */ +/* BSS Parameters subfield (Draft D8.0 Figure 9-632a) */ +#define HE_BSS_PARMS_OCT_REC_POS 0u /* OCT Recommended */ +#define HE_BSS_PARMS_OCT_REC_SZ 1u +#define HE_BSS_PARMS_SAME_SSID_POS 1u /* Same SSID */ +#define HE_BSS_PARMS_SAME_SSID_SZ 1u +#define HE_BSS_PARMS_MULTI_BSSID_POS 2u /* Multiple BSSID */ +#define HE_BSS_PARMS_MULTI_BSSID_SZ 1u +#define HE_BSS_PARMS_TR_BSSID_POS 3u /* Transmitted BSSID */ +#define HE_BSS_PARMS_TR_BSSID_SZ 1u +#define HE_BSS_PARMS_MEM_CO_AP_POS 4u /* Member Of ESS With 2.4/5 GHz Co-Located AP */ +#define HE_BSS_PARMS_MEM_CO_AP_SZ 1u +#define HE_BSS_PARMS_UNSOL_PRB_RSP_POS 5u /* Unsolicited Probe Responses Active */ +#define HE_BSS_PARMS_UNSOL_PRB_RSP_SZ 1u +#define HE_BSS_PARMS_CO_AP_POS 6u /* Co-Located AP */ +#define HE_BSS_PARMS_CO_AP_SZ 1u + #endif /* _802_11ax_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11az.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11az.h new file mode 100644 index 000000000000..d9fdf0e3ab61 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11az.h @@ -0,0 +1,637 @@ +/* + * Fundamental types and constants relating to 802.11az - + * "Enhancements for positioning" + * + * PFT - Protected Fine Timeing + * FTM - Fine Timing Measuremant + * PASN - Preassociation security negotiation + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _802_11az_h_ +#define _802_11az_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +/* P802.11az/D2.5 - Table 9-322h23fd Ranging Subelement IDs for Ranging Parameters */ +#define RANGING_PARAMS_NTB_SUB_ELT_ID 0u /* Non-TB specific subelement */ +#define RANGING_PARAMS_TB_SUB_ELT_ID 1u /* TB specific subelement */ +#define RANGING_PARAMS_SLTF_SUB_ELT_ID 2u /* Secure LTF subelement */ +#define RANGING_PARAMS_STLF_SUB_ELT_ID RANGING_PARAMS_SLTF_SUB_ELT_ID /* to be obsoleted */ +#define RANGING_PARAMS_VNDR_SUB_ELT_ID 221u /* Vendor specific subelement */ + +/* P802.11az/D3.1 - Table 9-788edm1 Secure LTF subelement format */ +#define FTM_PARAM_SLTF_REQUIRED_BIT 0x08 + +/* Protected Fine Timing frame action field values - 802.11az/D2.5 - Table 9.353 */ +#define DOT11_PFT_ACTION_RESERVED0 0u /* Reserved */ +#define DOT11_PFT_ACTION_FTM_REQ 1u /* Protected Fine Timing Measurement Request */ +#define DOT11_PFT_ACTION_FTM 2u /* Protected Fine Timing Measurement */ +#define DOT11_PFT_ACTION_LMR 3u /* Protected Location Measurement Report */ + +/* FTM - fine timing measurement public action frames */ +BWL_PRE_PACKED_STRUCT struct dot11_ftm_req { + uint8 category; /* category of action frame (4) */ + uint8 action; /* public action (32) */ + uint8 trigger; /* trigger/continue? */ + /* optional lci, civic loc, ftm params */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_req dot11_ftm_req_t; + +BWL_PRE_PACKED_STRUCT struct dot11_ftm { + uint8 category; /* category of action frame (4) */ + uint8 action; /* public action (33) */ + uint8 dialog; /* dialog token */ + uint8 follow_up; /* follow up dialog token */ + uint8 tod[6]; /* t1 - last depart timestamp */ + uint8 toa[6]; /* t4 - last ack arrival timestamp */ + uint8 tod_err[2]; /* t1 error */ + uint8 toa_err[2]; /* t4 error */ + /* optional lci report, civic loc report, ftm params */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm dot11_ftm_t; + +BWL_PRE_PACKED_STRUCT struct dot11_ftm_lmr { + uint8 category; /* category of action frame (4) */ + uint8 action; /* public action (33) */ + uint8 dialog; /* dialog token */ + uint8 tod[6]; /* RSTA t3 or ISTA t1: + * last departure of NDP + */ + uint8 toa[6]; /* RSTA t2 or ISTA t4: + * last arrival of NDP + */ + uint8 tod_err; /* t3 or t1 error */ + uint8 toa_err; /* t2 or t4 error */ + uint16 cfo; /* I2R LMR: clock difference between ISTA and RSTA. */ + uint8 r2i_ndp_tx_pw; /* average power of previous R2I NDP */ + uint8 i2r_ndp_tgt_rssi; /* desired power for next I2R NDP */ + uint8 sec_ltf_params[]; /* Optional Secure LTF parameters */ + /* no AOA feedback */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_lmr dot11_ftm_lmr_t; + +BWL_PRE_PACKED_STRUCT struct dot11_ranging_ndpa { + uint8 dialog_token; /* sounding dialog token */ + uint8 sta_info[]; /* STA infos */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ranging_ndpa dot11_ranging_ndpa_t; + +/* NDPA types = dialog token byte lower 2 bits */ +#define DOT11_NDPA_TYPE_MASK 0x03u +#define DOT11_NDPA_TYPE_VHT 0x00u +#define DOT11_NDPA_TYPE_RANGING 0x01u +#define DOT11_NDPA_TYPE_HE 0x02u +#define DOT11_NPDA_TOKEN_SHIFT 2u + +/* NDPA STA info size */ +#define DOT11_NDPA_STA_INFO_SIZE 4u + +#define DOT11_RANGING_TF_CMN_INFO_FIXED_SIZE 8u +BWL_PRE_PACKED_STRUCT struct dot11_ranging_trigger { + uint8 cmn_info[DOT11_RANGING_TF_CMN_INFO_FIXED_SIZE]; /* trigger common info */ + uint8 dep_cmn_info[BCM_FLEX_ARRAY]; /* type dependent common info */ + /* followed by user info list */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ranging_trigger dot11_ranging_trigger_t; + +/* Trigger frame types + * P802.11ax/D8.0 & P802.11az/D4.0 Table 9-20c Trigger Type subfield encoding + */ +#define DOT11_TF_TYPE_MASK 0x0Fu +#define DOT11_TF_TYPE_BASIC 0u /* basic */ +#define DOT11_TF_TYPE_BFRP 1u /* Beamforming Report Poll */ +#define DOT11_TF_TYPE_MUBAR 2u /* MU-BAR */ +#define DOT11_TF_TYPE_MURTS 3u /* MU-RTS */ +#define DOT11_TF_TYPE_BSRP 4u /* Buffer Status Report Poll */ +#define DOT11_TF_TYPE_GCR_MUBAR 5u /* GCR MU-BAR */ +#define DOT11_TF_TYPE_BQRP 6u /* Bandwidth Query Report Poll */ +#define DOT11_TF_TYPE_NFRP 7u /* NDP Feedback Report Poll */ +#define DOT11_TF_TYPE_RANGING 8u /* Ranging */ + +/* Ranging TF subtypes in Ranging trigger dependent common info + * P802.11az/D4.0 Table 9-30ka Ranging Trigger Subtype subfield encoding + */ +#define DOT11_RANGING_TF_SUBTYPE_MASK 0x0Fu +#define DOT11_RANGING_TF_SUBTYPE_POLL 0u /* Ranging TF Poll */ +#define DOT11_RANGING_TF_SUBTYPE_SND 1u /* Ranging TF Sounding */ +#define DOT11_RANGING_TF_SUBTYPE_SSND 2u /* Ranging TF Secure Sounding */ +#define DOT11_RANGING_TF_SUBTYPE_RPT 3u /* Ranging TF Report */ +#define DOT11_RANGING_TF_SUBTYPE_PSND 4u /* Ranging TF Passive Sounding */ + +/* Ranging TF dependent common info len */ +#define DOT11_RANGING_TF_DEP_CMN_INFO_LEN 1u /* Ranging TF variant */ +#define DOT11_RANGING_TF_PSND_DEP_CMN_INFO_LEN 2u /* Ranging TF Passive sounding */ + +/* Ranging TF user info fixed len - followed by TF dependent user info */ +#define DOT11_RANGING_TF_USER_INFO_FIXED_LEN 5u + +/* start of padding marker in user info */ +#define DOT11_TF_USER_INFO_PADDING_START 4095u + +#define DOT11_FTM_ERR_NOT_CONT_OFFSET 1 +#define DOT11_FTM_ERR_NOT_CONT_MASK 0x80 +#define DOT11_FTM_ERR_NOT_CONT_SHIFT 7 +#define DOT11_FTM_ERR_NOT_CONT(_err) (((_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] & \ + DOT11_FTM_ERR_NOT_CONT_MASK) >> DOT11_FTM_ERR_NOT_CONT_SHIFT) +#define DOT11_FTM_ERR_SET_NOT_CONT(_err, _val) do {\ + uint8 _err2 = (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET]; \ + _err2 &= ~DOT11_FTM_ERR_NOT_CONT_MASK; \ + _err2 |= ((_val) << DOT11_FTM_ERR_NOT_CONT_SHIFT) & DOT11_FTM_ERR_NOT_CONT_MASK; \ + (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] = _err2; \ +} while (0) + +#define DOT11_FTM_ERR_MAX_ERR_OFFSET 0 +#define DOT11_FTM_ERR_MAX_ERR_MASK 0x7fff +#define DOT11_FTM_ERR_MAX_ERR_SHIFT 0 +#define DOT11_FTM_ERR_MAX_ERR(_err) (((((_err)[1] & 0x7f) << 8) | (_err)[0])) +#define DOT11_FTM_ERR_SET_MAX_ERR(_err, _val) do {\ + uint16 _val2; \ + uint16 _not_cont; \ + _val2 = (((_val) & DOT11_FTM_ERR_MAX_ERR_MASK) << DOT11_FTM_ERR_MAX_ERR_SHIFT); \ + _val2 = (_val2 > 0x3fff) ? 0 : _val2; /* not expecting > 16ns error */ \ + _not_cont = DOT11_FTM_ERR_NOT_CONT(_err); \ + (_err)[0] = _val2 & 0xff; \ + (_err)[1] = (_val2 >> 8) & 0xff; \ + DOT11_FTM_ERR_SET_NOT_CONT(_err, _not_cont); \ +} while (0) + +BWL_PRE_PACKED_STRUCT struct dot11_ftm_params { + uint8 id; /* DOT11_MNG_FTM_PARAM_ID 8.4.2.166 11mcd2.6/2014 - revisit */ + uint8 len; + uint8 info[9]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_params dot11_ftm_params_t; +#define DOT11_FTM_PARAMS_IE_LEN (sizeof(dot11_ftm_params_t) - OFFSETOF(dot11_ftm_params_t, info)) + +/* FTM Ranging parameters element */ +#define DOT11_FTM_RANGING_PARAMS_FIXED_SIZE 7u +BWL_PRE_PACKED_STRUCT struct dot11_ftm_ranging_params { + uint8 id; /* 255 */ + uint8 len; + uint8 ext_id; /* EXT_MNG_RANGING_PARAMS_ID */ + uint8 info[DOT11_FTM_RANGING_PARAMS_FIXED_SIZE]; + uint8 subelmts[]; /* sub-elements (NTB/TB/SLTF/Vendor) */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_ranging_params dot11_ftm_ranging_params_t; +#define DOT11_FTM_RANGING_PARAMS_MIN_LEN \ + (sizeof(dot11_ftm_ranging_params_t) - OFFSETOF(dot11_ftm_ranging_params_t, ext_id)) + +/* FTM NTB specific sub-element */ +#define DOT11_FTM_NTB_SUBELMT_FIXED_SIZE 6u +BWL_PRE_PACKED_STRUCT struct dot11_ftm_ntb_subelmt { + uint8 id; /* RANGING_PARAMS_NTB_SUB_ELT_ID */ + uint8 len; + uint8 info[DOT11_FTM_NTB_SUBELMT_FIXED_SIZE]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_ntb_subelmt dot11_ftm_ntb_subelmt_t; + +/* FTM TB specific sub-element */ +#define DOT11_FTM_TB_SUBELMT_FIXED_SIZE 4u +BWL_PRE_PACKED_STRUCT struct dot11_ftm_tb_subelmt { + uint8 id; /* RANGING_PARAMS_TB_SUB_ELT_ID */ + uint8 len; + uint8 info[DOT11_FTM_TB_SUBELMT_FIXED_SIZE]; + uint8 aw_elmts[]; /* AW elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_tb_subelmt dot11_ftm_tb_subelmt_t; + +/* FTM ISTA availability window element */ +BWL_PRE_PACKED_STRUCT struct dot11_ftm_ista_aw { + uint8 id; /* 255 */ + uint8 len; + uint8 ext_id; /* EXT_MNG_ISTA_AVAIL_WINDOW_ID */ + uint16 count; + uint8 bitmap[]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_ista_aw dot11_ftm_ista_aw_t; +#define DOT11_FTM_ISTA_AW_MIN_LEN \ + (sizeof(dot11_ftm_ista_aw_t) - OFFSETOF(dot11_ftm_ista_aw_t, ext_id)) + +/* FTM RSTA availability window element */ +BWL_PRE_PACKED_STRUCT struct dot11_ftm_rsta_aw { + uint8 id; /* 255 */ + uint8 len; + uint8 ext_id; /* EXT_MNG_RSTA_AVAIL_WINDOW_ID */ + uint8 hdr; + uint8 aw_info[]; /* AW info subfields */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_rsta_aw dot11_ftm_rsta_aw_t; +#define DOT11_FTM_RSTA_AW_MIN_LEN \ + (sizeof(dot11_ftm_rsta_aw_t) - OFFSETOF(dot11_ftm_rsta_aw_t, ext_id)) + +/* FTM Secure LTF sub-element */ +BWL_PRE_PACKED_STRUCT struct dot11_ftm_sltf_subelmt { + uint8 id; /* RANGING_PARAMS_STLF_SUB_ELT_ID */ + uint8 len; + uint8 info; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_sltf_subelmt dot11_ftm_sltf_subelmt_t; +#define DOT11_FTM_SLTF_SUBELMT_LEN \ + (sizeof(dot11_ftm_sltf_subelmt_t) - OFFSETOF(dot11_ftm_sltf_subelmt_t, info)) + +/* FTM Secure LTF parameters element */ +#define DOT11_FTM_SLTF_PARAMS_SLTF_COUNTER_LEN 6u +#define DOT11_FTM_SLTF_PARAMS_SAC_LEN 2u +BWL_PRE_PACKED_STRUCT struct dot11_ftm_sltf_params { + uint8 id; /* 255 */ + uint8 len; + uint8 ext_id; /* EXT_MNG_SLTF_PARAMS_ID */ + uint8 sltf_counter[DOT11_FTM_SLTF_PARAMS_SLTF_COUNTER_LEN]; + uint8 validation_sac[DOT11_FTM_SLTF_PARAMS_SAC_LEN]; + uint8 measurement_sac[DOT11_FTM_SLTF_PARAMS_SAC_LEN]; + uint8 meas_result_ltf_offset; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_sltf_params dot11_ftm_sltf_params_t; +#define DOT11_FTM_SLTF_PARAMS_LEN \ + (sizeof(dot11_ftm_sltf_params_t) - OFFSETOF(dot11_ftm_sltf_params_t, ext_id)) + +BWL_PRE_PACKED_STRUCT struct dot11_ftm_ranging_ndpa { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ + struct ether_addr ta; /* transmitter address */ + uint8 dialog_token; /* sounding dialog token */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_ranging_ndpa dot11_ftm_ranging_ndpa_t; + +typedef struct dot11_ftm_sltf_subelmt dot11_ftm_sec_ltf_subie_params_t; +#define DOT11_FTM_SLTF_PARAMS_SUB_IE_LEN (sizeof(dot11_ftm_sec_ltf_subie_params_t)) + +#define DOT11_FTM_RANGING_CMN_PARAM_SIZE DOT11_FTM_RANGING_PARAMS_FIXED_SIZE +#define DOT11_FTM_CMN_RANGING_PARAMS_IE_LEN (sizeof(dot11_ftm_ranging_params_t) - TLV_EXT_HDR_LEN) + +/* FTM NTB specific */ +BWL_PRE_PACKED_STRUCT struct dot11_ftm_ntb_params { + uint8 id; /* RANGING_PARAMS_NTB_SUB_ELT_ID */ + uint8 len; + uint8 info[6]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_ntb_params dot11_ftm_ntb_params_t; +#define DOT11_FTM_NTB_PARAMS_SUB_IE_LEN (sizeof(dot11_ftm_ntb_params_t)) +#define DOT11_FTM_NTB_PARAMS_IE_LEN (DOT11_FTM_CMN_RANGING_PARAMS_IE_LEN + \ + DOT11_FTM_NTB_PARAMS_SUB_IE_LEN) + +/* FTM TB specific */ +BWL_PRE_PACKED_STRUCT struct dot11_ftm_tb_params { + uint8 id; /* RANGING_PARAMS_TB_SUB_ELT_ID */ + uint8 len; + uint8 info[]; /* variable length */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_tb_params dot11_ftm_tb_params_t; +#define DOT11_FTM_TB_PARAMS_IE_LEN sizeof(dot11_ftm_tb_params_t) + +BWL_PRE_PACKED_STRUCT struct dot11_ftm_tb_avail_window { + uint8 id; /* 255 */ + uint8 len; + uint8 ext_id; /* EXT_MNG_ISTA_AVAIL_WINDOW_ID or + * EXT_MNG_RSTA_AVAIL_WINDOW_ID + */ + uint8 info[]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_tb_avail_window dot11_ftm_tb_avail_window_t; +#define DOT11_FTM_TB_AVAIL_WINDOW_HDR_LEN sizeof(dot11_ftm_tb_avail_window_t) + +BWL_PRE_PACKED_STRUCT struct dot11_ftm_sec_ltf_params { + uint8 id; /* 255 */ + uint8 len; + uint8 ext_id; /* DOT11_MNG_FTM_SECURE_LTF_EXT_ID */ + uint8 info[11]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_sec_ltf_params dot11_ftm_sec_ltf_params_t; +#define DOT11_FTM_SEC_LTF_PARAMS_IE_LEN (sizeof(dot11_ftm_sec_ltf_params_t) - TLV_EXT_HDR_LEN) + +#define FTM_PARAMS_FIELD(_p, _off, _mask, _shift) (((_p)->info[(_off)] & (_mask)) >> (_shift)) +#define FTM_PARAMS_SET_FIELD(_p, _off, _mask, _shift, _val) do {\ + uint8 _ptmp = (_p)->info[_off] & ~(_mask); \ + (_p)->info[(_off)] = _ptmp | (((_val) << (_shift)) & (_mask)); \ +} while (0) + +#define FTM_PARAMS_STATUS_OFFSET 0 +#define FTM_PARAMS_STATUS_MASK 0x03 +#define FTM_PARAMS_STATUS_SHIFT 0 +#define FTM_PARAMS_STATUS(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_STATUS_OFFSET, \ + FTM_PARAMS_STATUS_MASK, FTM_PARAMS_STATUS_SHIFT) +#define FTM_PARAMS_SET_STATUS(_p, _status) FTM_PARAMS_SET_FIELD(_p, \ + FTM_PARAMS_STATUS_OFFSET, FTM_PARAMS_STATUS_MASK, FTM_PARAMS_STATUS_SHIFT, _status) + +#define FTM_PARAMS_VALUE_OFFSET 0 +#define FTM_PARAMS_VALUE_MASK 0x7c +#define FTM_PARAMS_VALUE_SHIFT 2 +#define FTM_PARAMS_VALUE(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_VALUE_OFFSET, \ + FTM_PARAMS_VALUE_MASK, FTM_PARAMS_VALUE_SHIFT) +#define FTM_PARAMS_SET_VALUE(_p, _value) FTM_PARAMS_SET_FIELD(_p, \ + FTM_PARAMS_VALUE_OFFSET, FTM_PARAMS_VALUE_MASK, FTM_PARAMS_VALUE_SHIFT, _value) +#define FTM_PARAMS_MAX_VALUE 32 + +#define FTM_PARAMS_NBURSTEXP_OFFSET 1 +#define FTM_PARAMS_NBURSTEXP_MASK 0x0f +#define FTM_PARAMS_NBURSTEXP_SHIFT 0 +#define FTM_PARAMS_NBURSTEXP(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_NBURSTEXP_OFFSET, \ + FTM_PARAMS_NBURSTEXP_MASK, FTM_PARAMS_NBURSTEXP_SHIFT) +#define FTM_PARAMS_SET_NBURSTEXP(_p, _bexp) FTM_PARAMS_SET_FIELD(_p, \ + FTM_PARAMS_NBURSTEXP_OFFSET, FTM_PARAMS_NBURSTEXP_MASK, FTM_PARAMS_NBURSTEXP_SHIFT, \ + _bexp) + +#define FTM_PARAMS_NBURST(_p) (1 << FTM_PARAMS_NBURSTEXP(_p)) + +enum { + FTM_PARAMS_NBURSTEXP_NOPREF = 15 +}; + +enum { + FTM_PARAMS_BURSTTMO_NOPREF = 15 +}; + +#define FTM_PARAMS_BURSTTMO_OFFSET 1 +#define FTM_PARAMS_BURSTTMO_MASK 0xf0 +#define FTM_PARAMS_BURSTTMO_SHIFT 4 +#define FTM_PARAMS_BURSTTMO(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_BURSTTMO_OFFSET, \ + FTM_PARAMS_BURSTTMO_MASK, FTM_PARAMS_BURSTTMO_SHIFT) +/* set timeout in params using _tmo where timeout = 2^(_tmo) * 250us */ +#define FTM_PARAMS_SET_BURSTTMO(_p, _tmo) FTM_PARAMS_SET_FIELD(_p, \ + FTM_PARAMS_BURSTTMO_OFFSET, FTM_PARAMS_BURSTTMO_MASK, FTM_PARAMS_BURSTTMO_SHIFT, (_tmo)+2) + +#define FTM_PARAMS_BURSTTMO_USEC(_val) ((1 << ((_val)-2)) * 250) +#define FTM_PARAMS_BURSTTMO_VALID(_val) ((((_val) < 12 && (_val) > 1)) || \ + (_val) == FTM_PARAMS_BURSTTMO_NOPREF) +#define FTM_PARAMS_BURSTTMO_MAX_MSEC 128 /* 2^9 * 250us */ +#define FTM_PARAMS_BURSTTMO_MAX_USEC 128000 /* 2^9 * 250us */ + +#define FTM_PARAMS_MINDELTA_OFFSET 2 +#define FTM_PARAMS_MINDELTA_USEC(_p) ((_p)->info[FTM_PARAMS_MINDELTA_OFFSET] * 100) +#define FTM_PARAMS_SET_MINDELTA_USEC(_p, _delta) do { \ + (_p)->info[FTM_PARAMS_MINDELTA_OFFSET] = (_delta) / 100; \ +} while (0) + +enum { + FTM_PARAMS_MINDELTA_NOPREF = 0 +}; + +#define FTM_PARAMS_PARTIAL_TSF(_p) ((_p)->info[4] << 8 | (_p)->info[3]) +#define FTM_PARAMS_SET_PARTIAL_TSF(_p, _partial_tsf) do { \ + (_p)->info[3] = (_partial_tsf) & 0xff; \ + (_p)->info[4] = ((_partial_tsf) >> 8) & 0xff; \ +} while (0) + +#define FTM_PARAMS_PARTIAL_TSF_MASK 0x0000000003fffc00ULL +#define FTM_PARAMS_PARTIAL_TSF_SHIFT 10 +#define FTM_PARAMS_PARTIAL_TSF_BIT_LEN 16 +#define FTM_PARAMS_PARTIAL_TSF_MAX 0xffff + +/* FTM can indicate upto 62k TUs forward and 1k TU backward */ +#define FTM_PARAMS_TSF_FW_HI (63487 << 10) /* in micro sec */ +#define FTM_PARAMS_TSF_BW_LOW (64512 << 10) /* in micro sec */ +#define FTM_PARAMS_TSF_BW_HI (65535 << 10) /* in micro sec */ +#define FTM_PARAMS_TSF_FW_MAX FTM_PARAMS_TSF_FW_HI +#define FTM_PARAMS_TSF_BW_MAX (FTM_PARAMS_TSF_BW_HI - FTM_PARAMS_TSF_BW_LOW) + +#define FTM_PARAMS_PTSFNOPREF_OFFSET 5 +#define FTM_PARAMS_PTSFNOPREF_MASK 0x1 +#define FTM_PARAMS_PTSFNOPREF_SHIFT 0 +#define FTM_PARAMS_PTSFNOPREF(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_PTSFNOPREF_OFFSET, \ + FTM_PARAMS_PTSFNOPREF_MASK, FTM_PARAMS_PTSFNOPREF_SHIFT) +#define FTM_PARAMS_SET_PTSFNOPREF(_p, _nopref) FTM_PARAMS_SET_FIELD(_p, \ + FTM_PARAMS_PTSFNOPREF_OFFSET, FTM_PARAMS_PTSFNOPREF_MASK, \ + FTM_PARAMS_PTSFNOPREF_SHIFT, _nopref) + +#define FTM_PARAMS_ASAP_OFFSET 5 +#define FTM_PARAMS_ASAP_MASK 0x4 +#define FTM_PARAMS_ASAP_SHIFT 2 +#define FTM_PARAMS_ASAP(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_ASAP_OFFSET, \ + FTM_PARAMS_ASAP_MASK, FTM_PARAMS_ASAP_SHIFT) +#define FTM_PARAMS_SET_ASAP(_p, _asap) FTM_PARAMS_SET_FIELD(_p, \ + FTM_PARAMS_ASAP_OFFSET, FTM_PARAMS_ASAP_MASK, FTM_PARAMS_ASAP_SHIFT, _asap) + +/* FTM1 - AKA ASAP Capable */ +#define FTM_PARAMS_FTM1_OFFSET 5 +#define FTM_PARAMS_FTM1_MASK 0x02 +#define FTM_PARAMS_FTM1_SHIFT 1 +#define FTM_PARAMS_FTM1(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_FTM1_OFFSET, \ + FTM_PARAMS_FTM1_MASK, FTM_PARAMS_FTM1_SHIFT) +#define FTM_PARAMS_SET_FTM1(_p, _ftm1) FTM_PARAMS_SET_FIELD(_p, \ + FTM_PARAMS_FTM1_OFFSET, FTM_PARAMS_FTM1_MASK, FTM_PARAMS_FTM1_SHIFT, _ftm1) + +#define FTM_PARAMS_MAX_FTMS_PER_BURST 31u +#define FTM_PARAMS_FTMS_PER_BURST_OFFSET 5 +#define FTM_PARAMS_FTMS_PER_BURST_MASK 0xf8 +#define FTM_PARAMS_FTMS_PER_BURST_SHIFT 3 +#define FTM_PARAMS_FTMS_PER_BURST(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_FTMS_PER_BURST_OFFSET, \ + FTM_PARAMS_FTMS_PER_BURST_MASK, FTM_PARAMS_FTMS_PER_BURST_SHIFT) +#define FTM_PARAMS_SET_FTMS_PER_BURST(_p, _nftms) FTM_PARAMS_SET_FIELD(_p, \ + FTM_PARAMS_FTMS_PER_BURST_OFFSET, FTM_PARAMS_FTMS_PER_BURST_MASK, \ + FTM_PARAMS_FTMS_PER_BURST_SHIFT, _nftms) + +enum { + FTM_PARAMS_FTMS_PER_BURST_NOPREF = 0 +}; + +#define FTM_PARAMS_CHAN_INFO_OFFSET 6 +#define FTM_PARAMS_CHAN_INFO_MASK 0xfc +#define FTM_PARAMS_CHAN_INFO_SHIFT 2 +#define FTM_PARAMS_CHAN_INFO(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_CHAN_INFO_OFFSET, \ + FTM_PARAMS_CHAN_INFO_MASK, FTM_PARAMS_CHAN_INFO_SHIFT) +#define FTM_PARAMS_SET_CHAN_INFO(_p, _ci) FTM_PARAMS_SET_FIELD(_p, \ + FTM_PARAMS_CHAN_INFO_OFFSET, FTM_PARAMS_CHAN_INFO_MASK, FTM_PARAMS_CHAN_INFO_SHIFT, _ci) + +/* burst period - units of 100ms */ +#define FTM_PARAMS_BURST_PERIOD(_p) (((_p)->info[8] << 8) | (_p)->info[7]) +#define FTM_PARAMS_SET_BURST_PERIOD(_p, _bp) do {\ + (_p)->info[7] = (_bp) & 0xff; \ + (_p)->info[8] = ((_bp) >> 8) & 0xff; \ +} while (0) + +#define FTM_PARAMS_BURST_PERIOD_MS(_p) (FTM_PARAMS_BURST_PERIOD(_p) * 100) + +enum { + FTM_PARAMS_BURST_PERIOD_NOPREF = 0 +}; + +/* FTM status values - last updated from 11mcD4.0 */ +enum { + FTM_PARAMS_STATUS_RESERVED = 0, + FTM_PARAMS_STATUS_SUCCESSFUL = 1, + FTM_PARAMS_STATUS_INCAPABLE = 2, + FTM_PARAMS_STATUS_FAILED = 3, + /* Below are obsolte */ + FTM_PARAMS_STATUS_OVERRIDDEN = 4, + FTM_PARAMS_STATUS_ASAP_INCAPABLE = 5, + FTM_PARAMS_STATUS_ASAP_FAILED = 6, + /* rest are reserved */ +}; + +enum { + FTM_PARAMS_CHAN_INFO_NO_PREF = 0, + FTM_PARAMS_CHAN_INFO_RESERVE1 = 1, + FTM_PARAMS_CHAN_INFO_RESERVE2 = 2, + FTM_PARAMS_CHAN_INFO_RESERVE3 = 3, + FTM_PARAMS_CHAN_INFO_NON_HT_5 = 4, + FTM_PARAMS_CHAN_INFO_RESERVE5 = 5, + FTM_PARAMS_CHAN_INFO_NON_HT_10 = 6, + FTM_PARAMS_CHAN_INFO_RESERVE7 = 7, + FTM_PARAMS_CHAN_INFO_NON_HT_20 = 8, /* excludes 2.4G, and High rate DSSS */ + FTM_PARAMS_CHAN_INFO_HT_MF_20 = 9, + FTM_PARAMS_CHAN_INFO_VHT_20 = 10, + FTM_PARAMS_CHAN_INFO_HT_MF_40 = 11, + FTM_PARAMS_CHAN_INFO_VHT_40 = 12, + FTM_PARAMS_CHAN_INFO_VHT_80 = 13, + FTM_PARAMS_CHAN_INFO_VHT_80_80 = 14, + FTM_PARAMS_CHAN_INFO_VHT_160_2_RFLOS = 15, + FTM_PARAMS_CHAN_INFO_VHT_160 = 16, + FTM_PARAMS_CHAN_INFO_HE_20 = 17, + FTM_PARAMS_CHAN_INFO_HE_40 = 18, + FTM_PARAMS_CHAN_INFO_HE_80 = 19, + FTM_PARAMS_CHAN_INFO_HE_80_80 = 20, + FTM_PARAMS_CHAN_INFO_HE_160_2_RFLOS = 21, + FTM_PARAMS_CHAN_INFO_HE_160 = 22, + /* Reserved from 23 - 30 */ + FTM_PARAMS_CHAN_INFO_DMG_2160 = 31, + /* Reserved from 32 - 63 */ + FTM_PARAMS_CHAN_INFO_MAX = 63 +}; + +/* the following definitions are *DEPRECATED* and moved to implementation files. They + * are retained here because previous (May 2016) some branches use them + */ +#define FTM_TPK_LEN 16u +#define FTM_RI_RR_BUF_LEN 32u +#define FTM_TPK_RI_RR_LEN 13 +#define FTM_TPK_RI_RR_LEN_SECURE_2_0 28 +#define FTM_TPK_RI_PHY_LEN 7u +#define FTM_TPK_RR_PHY_LEN 7u +#define FTM_TPK_LEN_SECURE_2_0 64u +#define FTM_TPK_RI_PHY_LEN_SECURE_2_0 14u +#define FTM_TPK_RR_PHY_LEN_SECURE_2_0 14u + +#define FTM_RI_RR_BUF_LEN_20MHZ 32u +#define FTM_RI_RR_BUF_LEN_80MHZ 64u + +#define FTM_RI_RR_BUF_LEN_FROM_CHANSPEC(chanspec) \ + (CHSPEC_IS20((chanspec)) ? \ + FTM_RI_RR_BUF_LEN_20MHZ : FTM_RI_RR_BUF_LEN_80MHZ) + +#define FTM_TPK_RI_RR_LEN_SECURE_2_0_20MHZ 28u +#define FTM_TPK_RI_RR_LEN_SECURE_2_0_80MHZ 62u +#define FTM_TPK_RI_RR_LEN_SECURE_2_0_2G FTM_TPK_RI_RR_LEN_SECURE_2_0 +#define FTM_TPK_RI_RR_LEN_SECURE_2_0_5G FTM_TPK_RI_RR_LEN_SECURE_2_0_80MHZ + +#define FTM_TPK_RI_RR_LEN_FROM_CHANSPEC(chanspec) \ + (CHSPEC_IS20((chanspec)) ? FTM_TPK_RI_RR_LEN_SECURE_2_0_20MHZ : \ + FTM_TPK_RI_RR_LEN_SECURE_2_0_80MHZ) + +#define FTM_TPK_RI_PHY_LEN_SECURE_2_0_20MHZ 14u +#define FTM_TPK_RI_PHY_LEN_SECURE_2_0_80MHZ 31u + +#define FTM_TPK_RI_PHY_LEN_FROM_CHANSPEC(chanspec) \ + (CHSPEC_IS20((chanspec)) ? FTM_TPK_RI_PHY_LEN_SECURE_2_0_20MHZ : \ + FTM_TPK_RI_PHY_LEN_SECURE_2_0_80MHZ) + +#define FTM_TPK_RR_PHY_LEN_SECURE_2_0_20MHZ 14u +#define FTM_TPK_RR_PHY_LEN_SECURE_2_0_80MHZ 31u + +#define FTM_TPK_RR_PHY_LEN_FROM_CHANSPEC(chanspec) \ + (CHSPEC_IS20((chanspec)) ? FTM_TPK_RR_PHY_LEN_SECURE_2_0_20MHZ : \ + FTM_TPK_RR_PHY_LEN_SECURE_2_0_80MHZ) +/* end *DEPRECATED* ftm definitions */ + +BWL_PRE_PACKED_STRUCT struct dot11_ftm_sync_info { + uint8 id; /* Extended - 255 11mc D4.3 */ + uint8 len; + uint8 id_ext; + uint8 tsf_sync_info[4]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_sync_info dot11_ftm_sync_info_t; + +/* ftm tsf sync info ie len - includes id ext */ +#define DOT11_FTM_SYNC_INFO_IE_LEN (sizeof(dot11_ftm_sync_info_t) - TLV_HDR_LEN) + +#define DOT11_FTM_IS_SYNC_INFO_IE(_ie) (\ + DOT11_MNG_IE_ID_EXT_MATCH(_ie, DOT11_MNG_FTM_SYNC_INFO) && \ + (_ie)->len == DOT11_FTM_SYNC_INFO_IE_LEN) + +/* 11az d2.5 table 9-92 */ +#define DOT11_PASN_PARAMS_EXT_ID 100u +#define DOT11_MNG_PASN_PARAMS (DOT11_MNG_ID_EXT_ID + \ + DOT11_PASN_PARAMS_EXT_ID) + +#define PASN_PARAMS_CTRL_CBINFO_PRESENT (1u << 0) +#define PASN_PARAMS_CTRL_GROUP_KEY_PRESENT (1u << 1) + +enum { + PASN_WRAPPED_NO_DATA = 0, + PASN_WRAPPED_FBT_DATA = 1u, + PASN_WRAPPED_FILS_DATA = 2u, + PASN_WRAPPED_SAE_DATA = 3u +}; + +BWL_PRE_PACKED_STRUCT struct dot11_pasn_params_ie { + uint8 id; /* 255 */ + uint8 len; + uint8 id_ext; /* DOT11_PASN_PARAMS_EXT_ID */ + uint8 ctrl; + uint8 wd_format; + /* optional comback info, group id and public key */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_pasn_params_ie dot11_pasn_params_ie_t; + +BWL_PRE_PACKED_STRUCT struct pasn_params_ap_cbinfo_field { + uint16 after_tu; /* ask STA to retry in TU times */ + uint8 cookie_len; /* length of cookie */ + uint8 cookie[]; /* variable cookie */ +} BWL_POST_PACKED_STRUCT; +typedef struct pasn_params_ap_cbinfo_field pasn_params_ap_cbinfo_field_t; + +BWL_PRE_PACKED_STRUCT struct pasn_params_sta_cbinfo_field { + uint8 cookie_len; /* length of cookie */ + uint8 cookie[]; /* variable cookie */ +} BWL_POST_PACKED_STRUCT; +typedef struct pasn_params_sta_cbinfo_field pasn_params_sta_cbinfo_field_t; + +BWL_PRE_PACKED_STRUCT union pasn_params_cbinfo_field { + pasn_params_ap_cbinfo_field_t ap_cbinfo; + pasn_params_sta_cbinfo_field_t sta_cbinfo; +} BWL_POST_PACKED_STRUCT; +typedef union pasn_params_cbinfo_field pasn_params_cbinfo_field_t; + +BWL_PRE_PACKED_STRUCT struct pasn_params_group_key { + uint16 group_id; /* IANA id of Finite Cyclic Group */ + uint8 len; /* Public key length */ + uint8 key[]; /* public key encoded using RFC 5480 conventions */ +} BWL_POST_PACKED_STRUCT; +typedef struct pasn_params_group_key pasn_params_group_key_t; + +/* MIC ie */ +BWL_PRE_PACKED_STRUCT struct mic_ie { + uint8 id; /* IE ID: DOT11_MNG_MIE_ID */ + uint8 len; /* IE length */ + uint8 mic[]; /* mic: 16 or 24 octets */ +} BWL_POST_PACKED_STRUCT; +typedef struct mic_ie mic_ie_t; + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11az_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11brcm.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11brcm.h new file mode 100644 index 000000000000..040d1c25a1d0 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11brcm.h @@ -0,0 +1,348 @@ +/* + * Broadcom proprietary types and constants relating to 802.11 + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _802_11brcm_h_ +#define _802_11brcm_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +#ifndef _NET_ETHERNET_H_ +#include +#endif + +#include <802.11n.h> + +/* This marks the start of a packed structure section. */ +#include + +/** + * RWL wifi protocol: The Vendor Specific Action frame is defined for vendor-specific signaling + * category+OUI+vendor specific content ( this can be variable) + */ +BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific { + uint8 category; + uint8 OUI[3]; + uint8 type; + uint8 subtype; + uint8 data[1040]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t; + +#define BCM_ACTION_OUI_BYTE0 0x00 +#define BCM_ACTION_OUI_BYTE1 0x90 +#define BCM_ACTION_OUI_BYTE2 0x4c + +BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ + uint8 type; /* type indicates what follows */ + uint8 extch; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; + +#define BRCM_EXTCH_IE_LEN 5 + +/* OUI for BRCM proprietary IE */ +#define BRCM_PROP_OUI "\x00\x90\x4C" /* Broadcom proprietary OUI */ + +/* Broadcom Proprietary OUI type list. Please update below page when adding a new type. + * Twiki https://hwnbu-twiki.lvn.broadcom.net/bin/view/Mwgroup/WlDriverIOVars?topic=WlBrcmPropIE + */ +/* The following BRCM_PROP_OUI types are currently in use (defined in + * relevant subsections). Each of them will be in a separate proprietary(221) IE + * #define SES_VNDR_IE_TYPE 1 (defined in src/ses/shared/ses.h) + * #define BRCM_SYSCAP_IE_TYPE 3 + * #define WET_TUNNEL_IE_TYPE 3 + * #define ULB_BRCM_PROP_IE_TYPE 91 + * #define SDB_BRCM_PROP_IE_TYPE 92 + * #define BCM_RESERVED_ACCESS 93 (Reserved, definition pending) + */ +#define RWL_WIFI_DEFAULT 0 +#define DPT_IE_TYPE 2 +#define VHT_FEATURES_IE_TYPE 4 +#define RWL_WIFI_FIND_MY_PEER 9 /* Used while finding server */ +#define RWL_WIFI_FOUND_PEER 10 /* Server response to the client */ +#define PROXD_IE_TYPE 11 /* Wifi proximity action frame type */ +#define BRCM_FTM_IE_TYPE 14 +#define HT_CAP_IE_TYPE 51 /* used in prop IE 221 only */ +#define HT_ADD_IE_TYPE 52 /* faked out as current spec is illegal */ +#define BRCM_EXTCH_IE_TYPE 53 /* 802.11n ID not yet assigned */ +#define MEMBER_OF_BRCM_PROP_IE_TYPE 54 /* used in prop IE 221 only */ +#define RELMCAST_BRCM_PROP_IE_TYPE 55 /* used in prop IE 221 only */ +/* BCM proprietary IE type for AIBSS */ +#define BCM_AIBSS_IE_TYPE 56 +/* + * This BRCM_PROP_OUI types is intended for use in events to embed additional + * data, and would not be expected to appear on the air -- but having an IE + * format allows IE frame data with extra data in events in that allows for + * more flexible parsing. + */ +#define BRCM_EVT_WL_BSS_INFO 64 +#define RWL_ACTION_WIFI_FRAG_TYPE 85 /* Fragment indicator for receiver */ +#define BTC_INFO_BRCM_PROP_IE_TYPE 90 + +/* Action frame type */ +#define PROXD_AF_TYPE 11 /* Wifi proximity action frame type */ +#define BRCM_RELMACST_AF_TYPE 12 /* RMC action frame type */ +/* Action frame type for FTM Initiator Report */ +#define BRCM_FTM_VS_AF_TYPE 14 + +enum { + BRCM_FTM_VS_INITIATOR_RPT_SUBTYPE = 1, /* FTM Initiator Report */ + BRCM_FTM_VS_COLLECT_SUBTYPE = 2, /* FTM Collect debug protocol */ +}; + +/** + * Following is the generic structure for brcm_prop_ie (uses BRCM_PROP_OUI). + * DPT uses this format with type set to DPT_IE_TYPE + */ +#ifdef NEW_BRCM_PROP_IE +BWL_PRE_PACKED_STRUCT struct brcm_prop_ie_s { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ + uint8 type; /* type of this IE */ +} BWL_POST_PACKED_STRUCT; +typedef struct brcm_prop_ie_s brcm_prop_ie_t; +#else +typedef struct dpt_brcm_prop_ie_s brcm_prop_ie_t; +#endif /* NEW_BRCM_PROP_IE */ +#define BRCM_PROP_IE_LEN 6 /* len of fixed part of brcm_prop ie */ + +/** + * Following is the generic structure for brcm_prop_ie (uses BRCM_PROP_OUI). + * DPT uses this format with type set to DPT_IE_TYPE + */ +BWL_PRE_PACKED_STRUCT struct dpt_brcm_prop_ie_s { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ + uint8 type; /* type of this IE */ + uint16 cap; +} BWL_POST_PACKED_STRUCT; +typedef struct brcm_prop_ie_s dpt_brcm_prop_ie_t; + +/* BRCM OUI: Used in the proprietary(221) IE in all broadcom devices */ +#define BRCM_OUI "\x00\x10\x18" /* Broadcom OUI */ + +/** BRCM info element */ +BWL_PRE_PACKED_STRUCT struct brcm_ie { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; /* Proprietary OUI, BRCM_OUI */ + uint8 ver; /* type/ver of this IE */ + uint8 assoc; /* # of assoc STAs */ + uint8 flags; /* misc flags */ + uint8 flags1; /* misc flags */ + uint16 amsdu_mtu_pref; /* preferred A-MSDU MTU */ + uint8 flags2; /* DTPC Cap flags */ +} BWL_POST_PACKED_STRUCT; +typedef struct brcm_ie brcm_ie_t; +#define BRCM_IE_LEN 12u /* BRCM IE length */ +#define BRCM_IE_VER 2u /* BRCM IE version */ +#define BRCM_IE_LEGACY_AES_VER 1u /* BRCM IE legacy AES version */ + +/* brcm_ie flags */ +#define BRF_ABCAP 0x01 /* afterburner is obsolete, defined for backward compat */ +#define BRF_ABRQRD 0x02 /* afterburner is obsolete, defined for backward compat */ +#define BRF_LZWDS 0x04 /* lazy wds enabled */ +#define BRF_BLOCKACK 0x08 /* BlockACK capable */ +#define BRF_ABCOUNTER_MASK 0xf0 /* afterburner is obsolete, defined for backward compat */ +#define BRF_PROP_11N_MCS 0x10 /* re-use afterburner bit */ +#define BRF_MEDIA_CLIENT 0x20 /* re-use afterburner bit to indicate media client device */ + +/** + * Support for Broadcom proprietary HT MCS rates. Re-uses afterburner bits since + * afterburner is not used anymore. Checks for BRF_ABCAP to stay compliant with 'old' + * images in the field. + */ +#define GET_BRF_PROP_11N_MCS(brcm_ie) \ + (!((brcm_ie)->flags & BRF_ABCAP) && ((brcm_ie)->flags & BRF_PROP_11N_MCS)) + +/* brcm_ie flags1 */ +#define BRF1_AMSDU 0x01 /* A-MSDU capable */ +#define BRF1_WNM 0x02 /* WNM capable */ +#define BRF1_WMEPS 0x04 /* AP is capable of handling WME + PS w/o APSD */ +#define BRF1_PSOFIX 0x08 /* AP has fixed PS mode out-of-order packets */ +#define BRF1_RX_LARGE_AGG 0x10 /* device can rx large aggregates */ +#define BRF1_RFAWARE_DCS 0x20 /* RFAWARE dynamic channel selection (DCS) */ +#define BRF1_SOFTAP 0x40 /* Configure as Broadcom SOFTAP */ +#define BRF1_DWDS 0x80 /* DWDS capable */ + +/* brcm_ie flags2 */ +#define BRF2_DTPC_TX 0x01u /* DTPC: DTPC TX Cap */ +#define BRF2_DTPC_RX 0x02u /* DTPC: DTPC RX Cap */ +#define BRF2_DTPC_TX_RX 0x03u /* DTPC: Enable Both DTPC TX and RX Cap */ +#define BRF2_DTPC_NONBF 0x04u /* DTPC: Enable DTPC for NON-TXBF */ +#define BRF2_TWT_RESP_CAP 0x08u /* TWT responder Cap for Brcm Softap + * only brcm sta parse this + */ +#define BRF2_TWT_REQ_CAP 0x10u /* TWT requester Cap for BRCM STA + * only brcm softap parse this + */ + +/** BRCM PROP DEVICE PRIMARY MAC ADDRESS IE */ +BWL_PRE_PACKED_STRUCT struct member_of_brcm_prop_ie { + uchar id; + uchar len; + uchar oui[3]; + uint8 type; /* type indicates what follows */ + struct ether_addr ea; /* Device Primary MAC Adrress */ +} BWL_POST_PACKED_STRUCT; +typedef struct member_of_brcm_prop_ie member_of_brcm_prop_ie_t; + +#define MEMBER_OF_BRCM_PROP_IE_LEN 10 /* IE max length */ +#define MEMBER_OF_BRCM_PROP_IE_HDRLEN (sizeof(member_of_brcm_prop_ie_t)) + +/** BRCM Reliable Multicast IE */ +BWL_PRE_PACKED_STRUCT struct relmcast_brcm_prop_ie { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; /* type indicates what follows */ + struct ether_addr ea; /* The ack sender's MAC Adrress */ + struct ether_addr mcast_ea; /* The multicast MAC address */ + uint8 updtmo; /* time interval(second) for client to send null packet to report its rssi */ +} BWL_POST_PACKED_STRUCT; +typedef struct relmcast_brcm_prop_ie relmcast_brcm_prop_ie_t; + +/* IE length */ +/* BRCM_PROP_IE_LEN = sizeof(relmcast_brcm_prop_ie_t)-((sizeof (id) + sizeof (len)))? */ +#define RELMCAST_BRCM_PROP_IE_LEN (sizeof(relmcast_brcm_prop_ie_t)-(2*sizeof(uint8))) + +/* BRCM BTC IE */ +BWL_PRE_PACKED_STRUCT struct btc_brcm_prop_ie { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; /* type inidicates what follows */ + uint32 info; +} BWL_POST_PACKED_STRUCT; +typedef struct btc_brcm_prop_ie btc_brcm_prop_ie_t; + +#define BRCM_BTC_INFO_TYPE_LEN (sizeof(btc_brcm_prop_ie_t) - (2 * sizeof(uint8))) + +/* CAP IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ +/* the capability IE is primarily used to convey this nodes abilities */ +BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ + uint8 type; /* type indicates what follows */ + ht_cap_ie_t cap_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; + +#define HT_PROP_IE_OVERHEAD 4 /* overhead bytes for prop oui ie */ + +/* ADD IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ +/* the additional IE is primarily used to convey the current BSS configuration */ +BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ + uint8 type; /* indicates what follows */ + ht_add_ie_t add_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_prop_add_ie ht_prop_add_ie_t; + +/** + * BRCM vht features IE header + * The header if the fixed part of the IE + * On the 5GHz band this is the entire IE, + * on 2.4GHz the VHT IEs as defined in the 802.11ac + * specification follows + * + * + * VHT features rates bitmap. + * Bit0: 5G MCS 0-9 BW 160MHz + * Bit1: 5G MCS 0-9 support BW 80MHz + * Bit2: 5G MCS 0-9 support BW 20MHz + * Bit3: 2.4G MCS 0-9 support BW 20MHz + * Bits:4-7 Reserved for future use + * + */ +BWL_PRE_PACKED_STRUCT struct vht_features_ie_hdr { + uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ + uint8 type; /* type of this IE = 4 */ + uint8 rate_mask; /* VHT rate mask */ +} BWL_POST_PACKED_STRUCT; +typedef struct vht_features_ie_hdr vht_features_ie_hdr_t; + +/* tag_ID/length/value_buffer tuple */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 id; + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT ftm_vs_tlv_t; + +BWL_PRE_PACKED_STRUCT struct dot11_ftm_vs_ie { + uint8 id; /* DOT11_MNG_VS_ID */ + uint8 len; /* length following */ + uint8 oui[3]; /* BRCM_PROP_OUI (or Customer) */ + uint8 sub_type; /* BRCM_FTM_IE_TYPE (or Customer) */ + uint8 version; + ftm_vs_tlv_t tlvs[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_vs_ie dot11_ftm_vs_ie_t; + +/* same as payload of dot11_ftm_vs_ie. +* This definition helps in having struct access +* of pay load while building FTM VS IE from other modules(NAN) +*/ +BWL_PRE_PACKED_STRUCT struct dot11_ftm_vs_ie_pyld { + uint8 sub_type; /* BRCM_FTM_IE_TYPE (or Customer) */ + uint8 version; + ftm_vs_tlv_t tlvs[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_vs_ie_pyld dot11_ftm_vs_ie_pyld_t; + +/* ftm vs api version */ +#define BCM_FTM_VS_PARAMS_VERSION 0x01 + +/* ftm vendor specific information tlv types */ +enum { + FTM_VS_TLV_NONE = 0, + FTM_VS_TLV_REQ_PARAMS = 1, /* additional request params (in FTM_REQ) */ + FTM_VS_TLV_MEAS_INFO = 2, /* measurement information (in FTM_MEAS) */ + FTM_VS_TLV_SEC_PARAMS = 3, /* security parameters (in either) */ + FTM_VS_TLV_SEQ_PARAMS = 4, /* toast parameters (FTM_REQ, BRCM proprietary) */ + FTM_VS_TLV_MF_BUF = 5, /* multi frame buffer - may span ftm vs ie's */ + FTM_VS_TLV_TIMING_PARAMS = 6, /* timing adjustments */ + FTM_VS_TLV_MF_STATS_BUF = 7 /* multi frame statistics buffer */ + /* add additional types above */ +}; + +/* BCM proprietary flag type for WL_DISCO_VSIE */ +#define SSE_OUI "\x00\x00\xF0" +#define VENDOR_ENTERPRISE_STA_OUI_TYPE 0x22 +#define MAX_VSIE_DISASSOC (1) +#define DISCO_VSIE_LEN 0x09u + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11brcm_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11cust.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11cust.h new file mode 100644 index 000000000000..7cbe2fc4f6ba --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11cust.h @@ -0,0 +1,76 @@ +/* + * Customer specific types and constants relating to 802.11 + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _802_11cust_h_ +#define _802_11cust_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +/* Action frame type for vendor specific action frames */ +#define VS_AF_TYPE 221 + +#ifdef IBSS_RMC +/* customer's OUI */ +#define RMC_PROP_OUI "\x00\x16\x32" +#endif + +/* WFA definitions for LEGACY P2P */ + +#ifndef CISCO_AIRONET_OUI +#define CISCO_AIRONET_OUI "\x00\x40\x96" /* Cisco AIRONET OUI */ +#endif + +/* Single PMK IE */ +#define CCX_SPMK_TYPE 3 /* CCX Extended Cap IE type for SPMK */ +/* CCX Extended Capability IE */ +BWL_PRE_PACKED_STRUCT struct ccx_spmk_cap_ie { + uint8 id; /* 221, DOT11_MNG_PROPR_ID */ + uint8 len; + uint8 oui[DOT11_OUI_LEN]; /* 00:40:96, CISCO_AIRONET_OUI */ + uint8 type; /* 11 */ + uint8 cap; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_spmk_cap_ie ccx_spmk_cap_ie_t; + +/* QoS FastLane IE. */ +BWL_PRE_PACKED_STRUCT struct ccx_qfl_ie { + uint8 id; /* 221, DOT11_MNG_VS_ID */ + uint8 length; /* 5 */ + uint8 oui[3]; /* 00:40:96 */ + uint8 type; /* 11 */ + uint8 data; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_qfl_ie ccx_qfl_ie_t; +#define CCX_QFL_IE_TYPE 11 +#define CCX_QFL_ENABLE_SHIFT 5 +#define CCX_QFL_ENALBE (1 << CCX_QFL_ENABLE_SHIFT) + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11cust_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11e.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11e.h deleted file mode 100755 index 0fbf58c43e86..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11e.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 802.11e protocol header file - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -#ifndef _802_11e_H_ -#define _802_11e_H_ - -#ifndef _TYPEDEFS_H_ -#include -#endif - -/* This marks the start of a packed structure section. */ -#include - -/* WME Traffic Specification (TSPEC) element */ -#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */ -#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */ - -#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */ -#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */ -#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */ -#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */ - -BWL_PRE_PACKED_STRUCT struct tsinfo { - uint8 octets[3]; -} BWL_POST_PACKED_STRUCT; - -typedef struct tsinfo tsinfo_t; - -/* 802.11e TSPEC IE */ -typedef BWL_PRE_PACKED_STRUCT struct tspec { - uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */ - uint8 type; /* WME_TYPE */ - uint8 subtype; /* WME_SUBTYPE_TSPEC */ - uint8 version; /* WME_VERSION */ - tsinfo_t tsinfo; /* TS Info bit field */ - uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ - uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ - uint32 min_srv_interval; /* Minimum Service Interval (us) */ - uint32 max_srv_interval; /* Maximum Service Interval (us) */ - uint32 inactivity_interval; /* Inactivity Interval (us) */ - uint32 suspension_interval; /* Suspension Interval (us) */ - uint32 srv_start_time; /* Service Start Time (us) */ - uint32 min_data_rate; /* Minimum Data Rate (bps) */ - uint32 mean_data_rate; /* Mean Data Rate (bps) */ - uint32 peak_data_rate; /* Peak Data Rate (bps) */ - uint32 max_burst_size; /* Maximum Burst Size (bytes) */ - uint32 delay_bound; /* Delay Bound (us) */ - uint32 min_phy_rate; /* Minimum PHY Rate (bps) */ - uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0-8.0) */ - uint16 medium_time; /* Medium Time (32 us/s periods) */ -} BWL_POST_PACKED_STRUCT tspec_t; - -#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */ - -/* ts_info */ -/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */ -#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */ -#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */ -#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */ -#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */ -#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */ -#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */ -#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */ -#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */ -#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */ -#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */ -#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */ -#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */ -/* TS info. user priority mask */ -#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT) - -/* Macro to get/set bit(s) field in TSINFO */ -#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT) -#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \ - TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT) -#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & TS_INFO_PSB_MASK) >> TS_INFO_PSB_SHIFT) -#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \ - TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT) - -#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \ - ((id) << TS_INFO_TID_SHIFT)) -#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \ - ((prio) << TS_INFO_USER_PRIO_SHIFT)) - -/* 802.11e QBSS Load IE */ -#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */ -#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */ - -#define CAC_ADDTS_RESP_TIMEOUT 1000 /* default ADDTS response timeout in ms */ - /* DEFVAL dot11ADDTSResponseTimeout = 1s */ - -/* 802.11e ADDTS status code */ -#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */ -#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */ -#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */ -#define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */ -#ifdef BCMCCX -#define CCX_STATUS_ASSOC_DENIED_UNKNOWN 0xc8 /* unspecified QoS related failure */ -#define CCX_STATUS_ASSOC_DENIED_AP_POLICY 0xc9 /* TSPEC refused due to AP policy */ -#define CCX_STATUS_ASSOC_DENIED_NO_BW 0xca /* Assoc denied due to AP insufficient BW */ -#define CCX_STATUS_ASSOC_DENIED_BAD_PARAM 0xcb /* one or more TSPEC with invalid parameter */ -#endif /* BCMCCX */ - -/* 802.11e DELTS status code */ -#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */ -#define DOT11E_STATUS_END_TS 37 /* END TS */ -#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */ -#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */ - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _802_11e_CAC_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11k.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11k.h new file mode 100644 index 000000000000..7439c8206dca --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11k.h @@ -0,0 +1,928 @@ +/* + * Fundamental types and constants relating to 802.11k - + * "Radio Resource Measurement of Wireless LANs" & + * Fundamental types and constants relating to 802.11v - + * "Wireless Network Management" extensions + * + * RRM - Radio Resource Measurement + * RM - same as RRM? + * NGBR - Neighbor Report + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _802_11k_h_ +#define _802_11k_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +/* ************* 802.11k related definitions. ************* */ + +/* Radio measurements enabled capability ie */ +#define DOT11_RRM_CAP_LEN 5 /* length of rrm cap bitmap */ +#define RCPI_IE_LEN 1 +#define RSNI_IE_LEN 1 +BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { + uint8 cap[DOT11_RRM_CAP_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; + +/* Bitmap definitions for cap ie */ +#define DOT11_RRM_CAP_LINK 0 +#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1 +#define DOT11_RRM_CAP_PARALLEL 2 +#define DOT11_RRM_CAP_REPEATED 3 +#define DOT11_RRM_CAP_BCN_PASSIVE 4 +#define DOT11_RRM_CAP_BCN_ACTIVE 5 +#define DOT11_RRM_CAP_BCN_TABLE 6 +#define DOT11_RRM_CAP_BCN_REP_COND 7 +#define DOT11_RRM_CAP_FM 8 +#define DOT11_RRM_CAP_CLM 9 +#define DOT11_RRM_CAP_NHM 10 +#define DOT11_RRM_CAP_SM 11 +#define DOT11_RRM_CAP_LCIM 12 +#define DOT11_RRM_CAP_LCIA 13 +#define DOT11_RRM_CAP_TSCM 14 +#define DOT11_RRM_CAP_TTSCM 15 +#define DOT11_RRM_CAP_AP_CHANREP 16 +#define DOT11_RRM_CAP_RMMIB 17 +/* bit18-bit23, not used for RRM_IOVAR */ +#define DOT11_RRM_CAP_MPC0 24 +#define DOT11_RRM_CAP_MPC1 25 +#define DOT11_RRM_CAP_MPC2 26 +#define DOT11_RRM_CAP_MPTI 27 +#define DOT11_RRM_CAP_NBRTSFO 28 +#define DOT11_RRM_CAP_RCPI 29 +#define DOT11_RRM_CAP_RSNI 30 +#define DOT11_RRM_CAP_BSSAAD 31 +#define DOT11_RRM_CAP_BSSAAC 32 +#define DOT11_RRM_CAP_AI 33 +#define DOT11_RRM_CAP_FTM_RANGE 34 +#define DOT11_RRM_CAP_CIVIC_LOC 35 +#define DOT11_RRM_CAP_IDENT_LOC 36 +#define DOT11_RRM_CAP_LAST 36 + +#ifdef WL11K_ALL_MEAS +#define DOT11_RRM_CAP_LINK_ENAB (1 << DOT11_RRM_CAP_LINK) +#define DOT11_RRM_CAP_FM_ENAB (1 << (DOT11_RRM_CAP_FM - 8)) +#define DOT11_RRM_CAP_CLM_ENAB (1 << (DOT11_RRM_CAP_CLM - 8)) +#define DOT11_RRM_CAP_NHM_ENAB (1 << (DOT11_RRM_CAP_NHM - 8)) +#define DOT11_RRM_CAP_SM_ENAB (1 << (DOT11_RRM_CAP_SM - 8)) +#define DOT11_RRM_CAP_LCIM_ENAB (1 << (DOT11_RRM_CAP_LCIM - 8)) +#define DOT11_RRM_CAP_TSCM_ENAB (1 << (DOT11_RRM_CAP_TSCM - 8)) +#ifdef WL11K_AP +#define DOT11_RRM_CAP_MPC0_ENAB (1 << (DOT11_RRM_CAP_MPC0 - 24)) +#define DOT11_RRM_CAP_MPC1_ENAB (1 << (DOT11_RRM_CAP_MPC1 - 24)) +#define DOT11_RRM_CAP_MPC2_ENAB (1 << (DOT11_RRM_CAP_MPC2 - 24)) +#define DOT11_RRM_CAP_MPTI_ENAB (1 << (DOT11_RRM_CAP_MPTI - 24)) +#else +#define DOT11_RRM_CAP_MPC0_ENAB 0 +#define DOT11_RRM_CAP_MPC1_ENAB 0 +#define DOT11_RRM_CAP_MPC2_ENAB 0 +#define DOT11_RRM_CAP_MPTI_ENAB 0 +#endif /* WL11K_AP */ +#define DOT11_RRM_CAP_CIVIC_LOC_ENAB (1 << (DOT11_RRM_CAP_CIVIC_LOC - 32)) +#define DOT11_RRM_CAP_IDENT_LOC_ENAB (1 << (DOT11_RRM_CAP_IDENT_LOC - 32)) +#else +#define DOT11_RRM_CAP_LINK_ENAB 0 +#define DOT11_RRM_CAP_FM_ENAB 0 +#define DOT11_RRM_CAP_CLM_ENAB 0 +#define DOT11_RRM_CAP_NHM_ENAB 0 +#define DOT11_RRM_CAP_SM_ENAB 0 +#define DOT11_RRM_CAP_LCIM_ENAB 0 +#define DOT11_RRM_CAP_TSCM_ENAB 0 +#define DOT11_RRM_CAP_MPC0_ENAB 0 +#define DOT11_RRM_CAP_MPC1_ENAB 0 +#define DOT11_RRM_CAP_MPC2_ENAB 0 +#define DOT11_RRM_CAP_MPTI_ENAB 0 +#define DOT11_RRM_CAP_CIVIC_LOC_ENAB 0 +#define DOT11_RRM_CAP_IDENT_LOC_ENAB 0 +#endif /* WL11K_ALL_MEAS */ +#ifdef WL11K_NBR_MEAS +#define DOT11_RRM_CAP_NEIGHBOR_REPORT_ENAB (1 << DOT11_RRM_CAP_NEIGHBOR_REPORT) +#else +#define DOT11_RRM_CAP_NEIGHBOR_REPORT_ENAB 0 +#endif /* WL11K_NBR_MEAS */ +#ifdef WL11K_BCN_MEAS +#define DOT11_RRM_CAP_BCN_PASSIVE_ENAB (1 << DOT11_RRM_CAP_BCN_PASSIVE) +#define DOT11_RRM_CAP_BCN_ACTIVE_ENAB (1 << DOT11_RRM_CAP_BCN_ACTIVE) +#else +#define DOT11_RRM_CAP_BCN_PASSIVE_ENAB 0 +#define DOT11_RRM_CAP_BCN_ACTIVE_ENAB 0 +#endif /* WL11K_BCN_MEAS */ +#define DOT11_RRM_CAP_MPA_MASK 0x7 +/* Operating Class (formerly "Regulatory Class") definitions */ +#define DOT11_OP_CLASS_NONE 255 + +BWL_PRE_PACKED_STRUCT struct do11_ap_chrep { + uint8 id; + uint8 len; + uint8 reg; + uint8 chanlist[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct do11_ap_chrep dot11_ap_chrep_t; + +/* Radio Measurements action ids */ +#define DOT11_RM_ACTION_RM_REQ 0 /* Radio measurement request */ +#define DOT11_RM_ACTION_RM_REP 1 /* Radio measurement report */ +#define DOT11_RM_ACTION_LM_REQ 2 /* Link measurement request */ +#define DOT11_RM_ACTION_LM_REP 3 /* Link measurement report */ +#define DOT11_RM_ACTION_NR_REQ 4 /* Neighbor report request */ +#define DOT11_RM_ACTION_NR_REP 5 /* Neighbor report response */ + +/** Generic radio measurement action frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_rm_action { + uint8 category; /* category of action frame (5) */ + uint8 action; /* radio measurement action */ + uint8 token; /* dialog token */ + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rm_action dot11_rm_action_t; +#define DOT11_RM_ACTION_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq { + uint8 category; /* category of action frame (5) */ + uint8 action; /* radio measurement action */ + uint8 token; /* dialog token */ + uint16 reps; /* no. of repetitions */ + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq dot11_rmreq_t; +#define DOT11_RMREQ_LEN 5 + +BWL_PRE_PACKED_STRUCT struct dot11_rm_ie { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rm_ie dot11_rm_ie_t; +#define DOT11_RM_IE_LEN 5 + +/* Definitions for "mode" bits in rm req */ +#define DOT11_RMREQ_MODE_PARALLEL 1 +#define DOT11_RMREQ_MODE_ENABLE 2 +#define DOT11_RMREQ_MODE_REQUEST 4 +#define DOT11_RMREQ_MODE_REPORT 8 +#define DOT11_RMREQ_MODE_DURMAND 0x10 /* Duration Mandatory */ + +/* Definitions for "mode" bits in rm rep */ +#define DOT11_RMREP_MODE_LATE 1 +#define DOT11_RMREP_MODE_INCAPABLE 2 +#define DOT11_RMREP_MODE_REFUSED 4 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn { + uint8 id; /* use dot11_rm_ie_t ? */ + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; + uint8 bcn_mode; + struct ether_addr bssid; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t; +#define DOT11_RMREQ_BCN_LEN 18u + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 frame_info; + uint8 rcpi; + uint8 rsni; + struct ether_addr bssid; + uint8 antenna_id; + uint32 parent_tsf; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; +#define DOT11_RMREP_BCN_LEN 26 + +/* Beacon request measurement mode */ +#define DOT11_RMREQ_BCN_PASSIVE 0 +#define DOT11_RMREQ_BCN_ACTIVE 1 +#define DOT11_RMREQ_BCN_TABLE 2 + +/* Sub-element IDs for Beacon Request */ +#define DOT11_RMREQ_BCN_SSID_ID 0 +#define DOT11_RMREQ_BCN_REPINFO_ID 1 +#define DOT11_RMREQ_BCN_REPDET_ID 2 +#define DOT11_RMREQ_BCN_REQUEST_ID 10 +#define DOT11_RMREQ_BCN_APCHREP_ID DOT11_MNG_AP_CHREP_ID +#define DOT11_RMREQ_BCN_LAST_RPT_IND_REQ_ID 164 + +/* Reporting Detail element definition */ +#define DOT11_RMREQ_BCN_REPDET_FIXED 0 /* Fixed length fields only */ +#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 /* + requested information elems */ +#define DOT11_RMREQ_BCN_REPDET_ALL 2 /* All fields */ + +/* Reporting Information (reporting condition) element definition */ +#define DOT11_RMREQ_BCN_REPINFO_LEN 2 /* Beacon Reporting Information length */ +#define DOT11_RMREQ_BCN_REPCOND_DEFAULT 0 /* Report to be issued after each measurement */ + +/* Last Beacon Report Indication Request definition */ +#define DOT11_RMREQ_BCN_LAST_RPT_IND_REQ_ENAB 1 + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_last_bcn_rpt_ind_req { + uint8 id; /* DOT11_RMREQ_BCN_LAST_RPT_IND_REQ_ID */ + uint8 len; /* length of remaining fields */ + uint8 data; /* data = 1 means last bcn rpt ind requested */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_last_bcn_rpt_ind_req dot11_rmrep_last_bcn_rpt_ind_req_t; + +/* Sub-element IDs for Beacon Report */ +#define DOT11_RMREP_BCN_FRM_BODY 1 +#define DOT11_RMREP_BCN_FRM_BODY_FRAG_ID 2 +#define DOT11_RMREP_BCN_LAST_RPT_IND 164 +#define DOT11_RMREP_BCN_FRM_BODY_LEN_MAX 224 /* 802.11k-2008 7.3.2.22.6 */ + +/* Refer IEEE P802.11-REVmd/D1.0 9.4.2.21.7 Beacon report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn_frm_body_fragmt_id { + uint8 id; /* DOT11_RMREP_BCN_FRM_BODY_FRAG_ID */ + uint8 len; /* length of remaining fields */ + /* More fragments(B15), fragment Id(B8-B14), Bcn rpt instance ID (B0 - B7) */ + uint16 frag_info_rpt_id; +} BWL_POST_PACKED_STRUCT; + +typedef struct dot11_rmrep_bcn_frm_body_fragmt_id dot11_rmrep_bcn_frm_body_fragmt_id_t; + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn_frm_body_frag_id { + uint8 id; /* DOT11_RMREP_BCN_FRM_BODY_FRAG_ID */ + uint8 len; /* length of remaining fields */ + uint8 bcn_rpt_id; /* Bcn rpt instance ID */ + uint8 frag_info; /* fragment Id(7 bits) | More fragments(1 bit) */ +} BWL_POST_PACKED_STRUCT; + +typedef struct dot11_rmrep_bcn_frm_body_frag_id dot11_rmrep_bcn_frm_body_frag_id_t; +#define DOT11_RMREP_BCNRPT_FRAG_ID_DATA_LEN 2u +#define DOT11_RMREP_BCNRPT_FRAG_ID_SE_LEN sizeof(dot11_rmrep_bcn_frm_body_frag_id_t) +#define DOT11_RMREP_BCNRPT_FRAG_ID_NUM_SHIFT 1u +#define DOT11_RMREP_BCNRPT_FRAGMT_ID_SE_LEN sizeof(dot11_rmrep_bcn_frm_body_fragmt_id_t) +#define DOT11_RMREP_BCNRPT_BCN_RPT_ID_MASK 0x00FFu +#define DOT11_RMREP_BCNRPT_FRAGMT_ID_NUM_SHIFT 8u +#define DOT11_RMREP_BCNRPT_FRAGMT_ID_NUM_MASK 0x7F00u +#define DOT11_RMREP_BCNRPT_MORE_FRAG_SHIFT 15u +#define DOT11_RMREP_BCNRPT_MORE_FRAG_MASK 0x8000u + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_last_bcn_rpt_ind { + uint8 id; /* DOT11_RMREP_BCN_LAST_RPT_IND */ + uint8 len; /* length of remaining fields */ + uint8 data; /* data = 1 is last bcn rpt */ +} BWL_POST_PACKED_STRUCT; + +typedef struct dot11_rmrep_last_bcn_rpt_ind dot11_rmrep_last_bcn_rpt_ind_t; +#define DOT11_RMREP_LAST_BCN_RPT_IND_DATA_LEN 1 +#define DOT11_RMREP_LAST_BCN_RPT_IND_SE_LEN sizeof(dot11_rmrep_last_bcn_rpt_ind_t) + +/* Sub-element IDs for Frame Report */ +#define DOT11_RMREP_FRAME_COUNT_REPORT 1 + +/* Channel load request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_chanload { + uint8 id; /* use dot11_rm_ie_t ? */ + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_chanload dot11_rmreq_chanload_t; +#define DOT11_RMREQ_CHANLOAD_LEN 11 + +/** Channel load report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_chanload { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 channel_load; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_chanload dot11_rmrep_chanload_t; +#define DOT11_RMREP_CHANLOAD_LEN 13 + +/** Noise histogram request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_noise { + uint8 id; /* use dot11_rm_ie_t ? */ + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_noise dot11_rmreq_noise_t; +#define DOT11_RMREQ_NOISE_LEN 11 + +/** Noise histogram report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_noise { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 antid; + uint8 anpi; + uint8 ipi0_dens; + uint8 ipi1_dens; + uint8 ipi2_dens; + uint8 ipi3_dens; + uint8 ipi4_dens; + uint8 ipi5_dens; + uint8 ipi6_dens; + uint8 ipi7_dens; + uint8 ipi8_dens; + uint8 ipi9_dens; + uint8 ipi10_dens; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_noise dot11_rmrep_noise_t; +#define DOT11_RMREP_NOISE_LEN 25 + +/** Frame request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_frame { + uint8 id; /* use dot11_rm_ie_t ? */ + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; + uint8 req_type; + struct ether_addr ta; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_frame dot11_rmreq_frame_t; +#define DOT11_RMREQ_FRAME_LEN 18 + +/** Frame report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frame { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_frame dot11_rmrep_frame_t; +#define DOT11_RMREP_FRAME_LEN 12 + +/** Frame report entry */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frmentry { + struct ether_addr ta; + struct ether_addr bssid; + uint8 phy_type; + uint8 avg_rcpi; + uint8 last_rsni; + uint8 last_rcpi; + uint8 ant_id; + uint16 frame_cnt; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_frmentry dot11_rmrep_frmentry_t; +#define DOT11_RMREP_FRMENTRY_LEN 19 + +/** STA statistics request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_stat { + uint8 id; /* use dot11_rm_ie_t ? */ + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + struct ether_addr peer; + uint16 interval; + uint16 duration; + uint8 group_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_stat dot11_rmreq_stat_t; +#define DOT11_RMREQ_STAT_LEN 16 + +/** STA statistics report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_stat { + uint16 duration; + uint8 group_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_stat dot11_rmrep_stat_t; + +/* Statistics Group Report: Group IDs */ +enum { + DOT11_RRM_STATS_GRP_ID_0 = 0, + DOT11_RRM_STATS_GRP_ID_1, + DOT11_RRM_STATS_GRP_ID_2, + DOT11_RRM_STATS_GRP_ID_3, + DOT11_RRM_STATS_GRP_ID_4, + DOT11_RRM_STATS_GRP_ID_5, + DOT11_RRM_STATS_GRP_ID_6, + DOT11_RRM_STATS_GRP_ID_7, + DOT11_RRM_STATS_GRP_ID_8, + DOT11_RRM_STATS_GRP_ID_9, + DOT11_RRM_STATS_GRP_ID_10, + DOT11_RRM_STATS_GRP_ID_11, + DOT11_RRM_STATS_GRP_ID_12, + DOT11_RRM_STATS_GRP_ID_13, + DOT11_RRM_STATS_GRP_ID_14, + DOT11_RRM_STATS_GRP_ID_15, + DOT11_RRM_STATS_GRP_ID_16 +}; + +/* Statistics Group Report: Group Data length */ +#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_0 28 +typedef struct rrm_stat_group_0 { + uint32 txfrag; + uint32 txmulti; + uint32 txfail; + uint32 rxframe; + uint32 rxmulti; + uint32 rxbadfcs; + uint32 txframe; +} rrm_stat_group_0_t; + +#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_1 24 +typedef struct rrm_stat_group_1 { + uint32 txretry; + uint32 txretries; + uint32 rxdup; + uint32 txrts; + uint32 rtsfail; + uint32 ackfail; +} rrm_stat_group_1_t; + +/* group 2-9 use same qos data structure (tid 0-7), total 52 bytes */ +#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_2_9 52 +typedef struct rrm_stat_group_qos { + uint32 txfrag; + uint32 txfail; + uint32 txretry; + uint32 txretries; + uint32 rxdup; + uint32 txrts; + uint32 rtsfail; + uint32 ackfail; + uint32 rxfrag; + uint32 txframe; + uint32 txdrop; + uint32 rxmpdu; + uint32 rxretries; +} rrm_stat_group_qos_t; + +/* dot11BSSAverageAccessDelay Group (only available at an AP): 8 byte */ +#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_10 8 +typedef BWL_PRE_PACKED_STRUCT struct rrm_stat_group_10 { + uint8 apavgdelay; + uint8 avgdelaybe; + uint8 avgdelaybg; + uint8 avgdelayvi; + uint8 avgdelayvo; + uint16 stacount; + uint8 chanutil; +} BWL_POST_PACKED_STRUCT rrm_stat_group_10_t; + +/* AMSDU, 40 bytes */ +#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_11 40 +typedef struct rrm_stat_group_11 { + uint32 txamsdu; + uint32 amsdufail; + uint32 amsduretry; + uint32 amsduretries; + uint32 txamsdubyte_h; + uint32 txamsdubyte_l; + uint32 amsduackfail; + uint32 rxamsdu; + uint32 rxamsdubyte_h; + uint32 rxamsdubyte_l; +} rrm_stat_group_11_t; + +/* AMPDU, 36 bytes */ +#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_12 36 +typedef struct rrm_stat_group_12 { + uint32 txampdu; + uint32 txmpdu; + uint32 txampdubyte_h; + uint32 txampdubyte_l; + uint32 rxampdu; + uint32 rxmpdu; + uint32 rxampdubyte_h; + uint32 rxampdubyte_l; + uint32 ampducrcfail; +} rrm_stat_group_12_t; + +/* BACK etc, 36 bytes */ +#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_13 36 +typedef struct rrm_stat_group_13 { + uint32 rximpbarfail; + uint32 rxexpbarfail; + uint32 chanwidthsw; + uint32 txframe20mhz; + uint32 txframe40mhz; + uint32 rxframe20mhz; + uint32 rxframe40mhz; + uint32 psmpgrantdur; + uint32 psmpuseddur; +} rrm_stat_group_13_t; + +/* RD Dual CTS etc, 36 bytes */ +#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_14 36 +typedef struct rrm_stat_group_14 { + uint32 grantrdgused; + uint32 grantrdgunused; + uint32 txframeingrantrdg; + uint32 txbyteingrantrdg_h; + uint32 txbyteingrantrdg_l; + uint32 dualcts; + uint32 dualctsfail; + uint32 rtslsi; + uint32 rtslsifail; +} rrm_stat_group_14_t; + +/* bf and STBC etc, 20 bytes */ +#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_15 20 +typedef struct rrm_stat_group_15 { + uint32 bfframe; + uint32 stbccts; + uint32 stbcctsfail; + uint32 nonstbccts; + uint32 nonstbcctsfail; +} rrm_stat_group_15_t; + +/* RSNA, 28 bytes */ +#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_16 28 +typedef struct rrm_stat_group_16 { + uint32 rsnacmacicverr; + uint32 rsnacmacreplay; + uint32 rsnarobustmgmtccmpreplay; + uint32 rsnatkipicverr; + uint32 rsnatkipicvreplay; + uint32 rsnaccmpdecrypterr; + uint32 rsnaccmpreplay; +} rrm_stat_group_16_t; + +/* Transmit stream/category measurement request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_tx_stream { + uint8 id; /* use dot11_rm_ie_t ? */ + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint16 interval; + uint16 duration; + struct ether_addr peer; + uint8 traffic_id; + uint8 bin0_range; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_tx_stream dot11_rmreq_tx_stream_t; +#define DOT11_RMREQ_TXSTREAM_LEN 17 + +/** Transmit stream/category measurement report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_tx_stream { + uint32 starttime[2]; + uint16 duration; + struct ether_addr peer; + uint8 traffic_id; + uint8 reason; + uint32 txmsdu_cnt; + uint32 msdu_discarded_cnt; + uint32 msdufailed_cnt; + uint32 msduretry_cnt; + uint32 cfpolls_lost_cnt; + uint32 avrqueue_delay; + uint32 avrtx_delay; + uint8 bin0_range; + uint32 bin0; + uint32 bin1; + uint32 bin2; + uint32 bin3; + uint32 bin4; + uint32 bin5; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_tx_stream dot11_rmrep_tx_stream_t; +#define DOT11_RMREP_TXSTREAM_LEN 71 + +typedef struct rrm_tscm { + uint32 msdu_tx; + uint32 msdu_exp; + uint32 msdu_fail; + uint32 msdu_retries; + uint32 cfpolls_lost; + uint32 queue_delay; + uint32 tx_delay_sum; + uint32 tx_delay_cnt; + uint32 bin0_range_us; + uint32 bin0; + uint32 bin1; + uint32 bin2; + uint32 bin3; + uint32 bin4; + uint32 bin5; +} rrm_tscm_t; +enum { + DOT11_FTM_LOCATION_SUBJ_LOCAL = 0, /* Where am I? */ + DOT11_FTM_LOCATION_SUBJ_REMOTE = 1, /* Where are you? */ + DOT11_FTM_LOCATION_SUBJ_THIRDPARTY = 2 /* Where is he/she? */ +}; + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_ftm_lci { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 subj; + /* optional sub-elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_ftm_lci dot11_rmreq_ftm_lci_t; + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_ftm_lci { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 lci_sub_id; + uint8 lci_sub_len; + /* optional LCI field */ + /* optional sub-elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_ftm_lci dot11_rmrep_ftm_lci_t; + +#define DOT11_FTM_LCI_SUBELEM_ID 0 +#define DOT11_FTM_LCI_SUBELEM_LEN 2 +#define DOT11_FTM_LCI_FIELD_LEN 16 +#define DOT11_FTM_LCI_UNKNOWN_LEN 2 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_ftm_civic { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 subj; + uint8 civloc_type; + uint8 siu; /* service interval units */ + uint16 si; /* service interval */ + /* optional sub-elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_ftm_civic dot11_rmreq_ftm_civic_t; +#define DOT11_RMREQ_CIVIC_LEN 10 + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_ftm_civic { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 civloc_type; + uint8 civloc_sub_id; + uint8 civloc_sub_len; + /* optional location civic field */ + /* optional sub-elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_ftm_civic dot11_rmrep_ftm_civic_t; + +#define DOT11_FTM_CIVIC_LOC_TYPE_RFC4776 0 +#define DOT11_FTM_CIVIC_SUBELEM_ID 0 +#define DOT11_FTM_CIVIC_SUBELEM_LEN 2 +#define DOT11_FTM_CIVIC_LOC_SI_NONE 0 +#define DOT11_FTM_CIVIC_TYPE_LEN 1 +#define DOT11_FTM_CIVIC_UNKNOWN_LEN 3 + +/* Location Identifier measurement request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_locid { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 subj; + uint8 siu; + uint16 si; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_locid dot11_rmreq_locid_t; +#define DOT11_RMREQ_LOCID_LEN 9 + +/* Location Identifier measurement report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_locid { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 exp_tsf[8]; + uint8 locid_sub_id; + uint8 locid_sub_len; + /* optional location identifier field */ + /* optional sub-elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_locid dot11_rmrep_locid_t; +#define DOT11_LOCID_UNKNOWN_LEN 10 +#define DOT11_LOCID_SUBELEM_ID 0 + +BWL_PRE_PACKED_STRUCT struct dot11_ftm_range_subel { + uint8 id; + uint8 len; + uint16 max_age; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_range_subel dot11_ftm_range_subel_t; +#define DOT11_FTM_RANGE_SUBELEM_ID 4 +#define DOT11_FTM_RANGE_SUBELEM_LEN 2 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_ftm_range { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint16 max_init_delay; /* maximum random initial delay */ + uint8 min_ap_count; + uint8 data[BCM_FLEX_ARRAY]; + /* neighbor report sub-elements */ + /* optional sub-elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_ftm_range dot11_rmreq_ftm_range_t; +#define DOT11_RMREQ_FTM_RANGE_LEN 8 + +#define DOT11_FTM_RANGE_LEN 3 +BWL_PRE_PACKED_STRUCT struct dot11_ftm_range_entry { + uint32 start_tsf; /* 4 lsb of tsf */ + struct ether_addr bssid; + uint8 range[DOT11_FTM_RANGE_LEN]; + uint8 max_err[DOT11_FTM_RANGE_LEN]; + uint8 rsvd; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_range_entry dot11_ftm_range_entry_t; +#define DOT11_FTM_RANGE_ENTRY_MAX_COUNT 15 + +enum { + DOT11_FTM_RANGE_ERROR_AP_INCAPABLE = 2, + DOT11_FTM_RANGE_ERROR_AP_FAILED = 3, + DOT11_FTM_RANGE_ERROR_TX_FAILED = 8, + DOT11_FTM_RANGE_ERROR_MAX +}; + +BWL_PRE_PACKED_STRUCT struct dot11_ftm_range_error_entry { + uint32 start_tsf; /* 4 lsb of tsf */ + struct ether_addr bssid; + uint8 code; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ftm_range_error_entry dot11_ftm_range_error_entry_t; +#define DOT11_FTM_RANGE_ERROR_ENTRY_MAX_COUNT 11 + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_ftm_range { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 entry_count; + uint8 data[2]; /* includes pad */ + /* + dot11_ftm_range_entry_t entries[entry_count]; + uint8 error_count; + dot11_ftm_error_entry_t errors[error_count]; + */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_ftm_range dot11_rmrep_ftm_range_t; + +#define DOT11_FTM_RANGE_REP_MIN_LEN 6 /* No extra byte for error_count */ +#define DOT11_FTM_RANGE_ENTRY_CNT_MAX 15 +#define DOT11_FTM_RANGE_ERROR_CNT_MAX 11 +#define DOT11_FTM_RANGE_REP_FIXED_LEN 1 /* No extra byte for error_count */ +/** Measurement pause request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_pause_time { + uint8 id; /* use dot11_rm_ie_t ? */ + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint16 pause_time; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_pause_time dot11_rmreq_pause_time_t; +#define DOT11_RMREQ_PAUSE_LEN 7 + +/* Neighbor Report subelements ID (11k & 11v) */ +#define DOT11_NGBR_TSF_INFO_SE_ID 1 +#define DOT11_NGBR_CCS_SE_ID 2 +#define DOT11_NGBR_BSSTRANS_PREF_SE_ID 3 +#define DOT11_NGBR_BSS_TERM_DUR_SE_ID 4 +#define DOT11_NGBR_BEARING_SE_ID 5 +#define DOT11_NGBR_WIDE_BW_CHAN_SE_ID 6 /* proposed */ + +/** Neighbor Report, BSS Transition Candidate Preference subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bsstrans_pref_se { + uint8 sub_id; + uint8 len; + uint8 preference; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ngbr_bsstrans_pref_se dot11_ngbr_bsstrans_pref_se_t; +#define DOT11_NGBR_BSSTRANS_PREF_SE_LEN 1 +#define DOT11_NGBR_BSSTRANS_PREF_SE_IE_LEN 3 +#define DOT11_NGBR_BSSTRANS_PREF_SE_HIGHEST 0xff + +/** Neighbor Report, BSS Termination Duration subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bss_term_dur_se { + uint8 sub_id; + uint8 len; + uint8 tsf[8]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ngbr_bss_term_dur_se dot11_ngbr_bss_term_dur_se_t; +#define DOT11_NGBR_BSS_TERM_DUR_SE_LEN 10 + +/* Neighbor Report BSSID Information Field */ +#define DOT11_NGBR_BI_REACHABILTY_UNKN 0x0002 +#define DOT11_NGBR_BI_REACHABILTY 0x0003 +#define DOT11_NGBR_BI_SEC 0x0004 +#define DOT11_NGBR_BI_KEY_SCOPE 0x0008 +#define DOT11_NGBR_BI_CAP 0x03f0 +#define DOT11_NGBR_BI_CAP_SPEC_MGMT 0x0010 +#define DOT11_NGBR_BI_CAP_QOS 0x0020 +#define DOT11_NGBR_BI_CAP_APSD 0x0040 +#define DOT11_NGBR_BI_CAP_RDIO_MSMT 0x0080 +#define DOT11_NGBR_BI_CAP_DEL_BA 0x0100 +#define DOT11_NGBR_BI_CAP_IMM_BA 0x0200 +#define DOT11_NGBR_BI_MOBILITY 0x0400 +#define DOT11_NGBR_BI_HT 0x0800 +#define DOT11_NGBR_BI_VHT 0x1000 +#define DOT11_NGBR_BI_FTM 0x2000 + +/** Neighbor Report element (11k & 11v) */ +BWL_PRE_PACKED_STRUCT struct dot11_neighbor_rep_ie { + uint8 id; + uint8 len; + struct ether_addr bssid; + uint32 bssid_info; + uint8 reg; /* Operating class */ + uint8 channel; + uint8 phytype; + uint8 data[BCM_FLEX_ARRAY]; /* Variable size subelements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_neighbor_rep_ie dot11_neighbor_rep_ie_t; +#define DOT11_NEIGHBOR_REP_IE_FIXED_LEN 13u + +/** Link Measurement */ +BWL_PRE_PACKED_STRUCT struct dot11_lmreq { + uint8 category; /* category of action frame (5) */ + uint8 action; /* radio measurement action */ + uint8 token; /* dialog token */ + uint8 txpwr; /* Transmit Power Used */ + uint8 maxtxpwr; /* Max Transmit Power */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_lmreq dot11_lmreq_t; +#define DOT11_LMREQ_LEN 5 + +BWL_PRE_PACKED_STRUCT struct dot11_lmrep { + uint8 category; /* category of action frame (5) */ + uint8 action; /* radio measurement action */ + uint8 token; /* dialog token */ + dot11_tpc_rep_t tpc; /* TPC element */ + uint8 rxant; /* Receive Antenna ID */ + uint8 txant; /* Transmit Antenna ID */ + uint8 rcpi; /* RCPI */ + uint8 rsni; /* RSNI */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_lmrep dot11_lmrep_t; +#define DOT11_LMREP_LEN 11 + +#define DOT11_MP_CAP_SPECTRUM 0x01 /* d11 cap. spectrum */ +#define DOT11_MP_CAP_SHORTSLOT 0x02 /* d11 cap. shortslot */ +/* Measurement Pilot */ +BWL_PRE_PACKED_STRUCT struct dot11_mprep { + uint8 cap_info; /* Condensed capability Info. */ + uint8 country[2]; /* Condensed country string */ + uint8 opclass; /* Op. Class */ + uint8 channel; /* Channel */ + uint8 mp_interval; /* Measurement Pilot Interval */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_mprep dot11_mprep_t; +#define DOT11_MPREP_LEN 6 + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11k_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11n.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11n.h new file mode 100644 index 000000000000..e86dd0f644e1 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11n.h @@ -0,0 +1,384 @@ +/* + * Fundamental types and constants relating to 802.11n - + * "Enhancements for Higher Throughput" + * + * HT - Higher Throughput + * OBSS - Overlapping BSS + * EXTCH/EXT_CH - Extension Channel + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _802_11n_h_ +#define _802_11n_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +#ifndef _NET_ETHERNET_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width { + uint8 category; + uint8 action; + uint8 ch_width; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops { + uint8 category; + uint8 action; + uint8 control; +} BWL_POST_PACKED_STRUCT; + +/* 802.11 BRCM "Compromise" Pre N constants */ +#define PREN_PREAMBLE 24 /* green field preamble time */ +#define PREN_MM_EXT 12 /* extra mixed mode preamble time */ +#define PREN_PREAMBLE_EXT 4 /* extra preamble (multiply by unique_streams-1) */ + +/* 802.11N PHY constants */ +#define RIFS_11N_TIME 2 /* NPHY RIFS time */ + +/* 802.11 HT PLCP format 802.11n-2009, sec 20.3.9.4.3 + * HT-SIG is composed of two 24 bit parts, HT-SIG1 and HT-SIG2 + */ +/* HT-SIG1 */ +#define HT_SIG1_MCS_MASK 0x00007F +#define HT_SIG1_CBW 0x000080 +#define HT_SIG1_CBW_SHIFT 7u +#define HT_SIG1_HT_LENGTH 0xFFFF00 +#define HT_SIG1_HT_LENGTH_SHIFT 8u + +/* HT-SIG2 */ +#define HT_SIG2_SMOOTHING 0x000001 +#define HT_SIG2_NOT_SOUNDING 0x000002 +#define HT_SIG2_RESERVED 0x000004 +#define HT_SIG2_AGGREGATION 0x000008 +#define HT_SIG2_STBC_MASK 0x000030 +#define HT_SIG2_STBC_SHIFT 4 +#define HT_SIG2_FEC_CODING 0x000040 +#define HT_SIG2_SHORT_GI 0x000080 +#define HT_SIG2_ESS_MASK 0x000300 +#define HT_SIG2_ESS_SHIFT 8 +#define HT_SIG2_CRC 0x03FC00 +#define HT_SIG2_TAIL 0x1C0000 + +/* HT Timing-related parameters (802.11-2012, sec 20.3.6) */ +#define HT_T_LEG_PREAMBLE 16 +#define HT_T_L_SIG 4 +#define HT_T_SIG 8 +#define HT_T_LTF1 4 +#define HT_T_GF_LTF1 8 +#define HT_T_LTFs 4 +#define HT_T_STF 4 +#define HT_T_GF_STF 8 +#define HT_T_SYML 4 + +#define HT_N_SERVICE 16 /* bits in SERVICE field */ +#define HT_N_TAIL 6 /* tail bits per BCC encoder */ + +/* ************* HT definitions. ************* */ +#define MCSSET_LEN 16 /* 16-bits per 8-bit set to give 128-bits bitmap of MCS Index */ +#define MAX_MCS_NUM (128) /* max mcs number = 128 */ +#define BASIC_HT_MCS 0xFFu /* HT MCS supported rates */ + +BWL_PRE_PACKED_STRUCT struct ht_cap_ie { + uint16 cap; + uint8 params; + uint8 supp_mcs[MCSSET_LEN]; + uint16 ext_htcap; + uint32 txbf_cap; + uint8 as_cap; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_cap_ie ht_cap_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_ht_cap_ie { + uint8 id; + uint8 len; + ht_cap_ie_t ht_cap; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ht_cap_ie dot11_ht_cap_ie_t; + +#define HT_CAP_IE_LEN 26 /* HT capability len (based on .11n d2.0) */ + +#define HT_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ +#define HT_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ +#define HT_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ +#define HT_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ +#define HT_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ +#define HT_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ +#define HT_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ +#define HT_CAP_GF 0x0010 /* Greenfield preamble support */ +#define HT_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ +#define HT_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ +#define HT_CAP_TX_STBC 0x0080 /* Tx STBC support */ +#define HT_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ +#define HT_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ +#define HT_CAP_DELAYED_BA 0x0400 /* delayed BA support */ +#define HT_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ + +#define HT_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ +#define HT_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ +#define HT_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ +#define HT_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ + +#define HT_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ +#define HT_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ +#define HT_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ +#define HT_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ + +#define HT_CAP_TXBF_CAP_IMPLICIT_TXBF_RX 0x1 +#define HT_CAP_TXBF_CAP_NDP_RX 0x8 +#define HT_CAP_TXBF_CAP_NDP_TX 0x10 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI 0x100 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_STEERING 0x200 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_STEERING 0x400 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_MASK 0x1800 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_SHIFT 11 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_MASK 0x6000 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_SHIFT 13 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_MASK 0x18000 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_SHIFT 15 +#define HT_CAP_TXBF_CAP_CSI_BFR_ANT_SHIFT 19 +#define HT_CAP_TXBF_CAP_NC_BFR_ANT_SHIFT 21 +#define HT_CAP_TXBF_CAP_C_BFR_ANT_SHIFT 23 +#define HT_CAP_TXBF_CAP_C_BFR_ANT_MASK 0x1800000 + +#define HT_CAP_TXBF_CAP_CHAN_ESTIM_SHIFT 27 +#define HT_CAP_TXBF_CAP_CHAN_ESTIM_MASK 0x18000000 + +#define HT_CAP_TXBF_FB_TYPE_NONE 0 +#define HT_CAP_TXBF_FB_TYPE_DELAYED 1 +#define HT_CAP_TXBF_FB_TYPE_IMMEDIATE 2 +#define HT_CAP_TXBF_FB_TYPE_BOTH 3 + +#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_MASK 0x400 +#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_SHIFT 10 +#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_MASK 0x18000 +#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_SHIFT 15 + +#define HT_CAP_MCS_FLAGS_SUPP_BYTE 12 /* byte offset in HT Cap Supported MCS for various flags */ +#define HT_CAP_MCS_RX_8TO15_BYTE_OFFSET 1 +#define HT_CAP_MCS_FLAGS_TX_RX_UNEQUAL 0x02 +#define HT_CAP_MCS_FLAGS_MAX_SPATIAL_STREAM_MASK 0x0C + +#define HT_MAX_AMSDU 7935 /* max amsdu size (bytes) per the HT spec */ +#define HT_MIN_AMSDU 3835 /* min amsdu size (bytes) per the HT spec */ + +#define HT_PARAMS_RX_FACTOR_MASK 0x03 /* ampdu rcv factor mask */ +#define HT_PARAMS_DENSITY_MASK 0x1C /* ampdu density mask */ +#define HT_PARAMS_DENSITY_SHIFT 2 /* ampdu density shift */ + +#define HT_CAP_EXT_PCO 0x0001 +#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006 +#define HT_CAP_EXT_PCO_TTIME_SHIFT 1 +#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300 +#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8 +#define HT_CAP_EXT_HTC 0x0400 +#define HT_CAP_EXT_RD_RESP 0x0800 + +/** 'ht_add' is called 'HT Operation' information element in the 802.11 standard */ +BWL_PRE_PACKED_STRUCT struct ht_add_ie { + uint8 ctl_ch; /* control channel number */ + uint8 byte1; /* ext ch,rec. ch. width, RIFS support */ + uint16 opmode; /* operation mode */ + uint16 misc_bits; /* misc bits */ + uint8 basic_mcs[MCSSET_LEN]; /* required MCS set */ +} BWL_POST_PACKED_STRUCT; +typedef struct ht_add_ie ht_add_ie_t; + +#define HT_ADD_IE_LEN 22 /* HT capability len (based on .11n d1.0) */ + +/* byte1 defn's */ +#define HT_BW_ANY 0x04 /* set, STA can use 20 or 40MHz */ +#define HT_RIFS_PERMITTED 0x08 /* RIFS allowed */ + +/* opmode defn's */ +#define HT_OPMODE_MASK 0x0003 /* protection mode mask */ +#define HT_OPMODE_SHIFT 0 /* protection mode shift */ +#define HT_OPMODE_PURE 0x0000 /* protection mode PURE */ +#define HT_OPMODE_OPTIONAL 0x0001 /* protection mode optional */ +#define HT_OPMODE_HT20IN40 0x0002 /* protection mode 20MHz HT in 40MHz BSS */ +#define HT_OPMODE_MIXED 0x0003 /* protection mode Mixed Mode */ +#define HT_OPMODE_NONGF 0x0004 /* protection mode non-GF */ +#define DOT11N_TXBURST 0x0008 /* Tx burst limit */ +#define DOT11N_OBSS_NONHT 0x0010 /* OBSS Non-HT STA present */ +#define HT_OPMODE_CCFS2_MASK 0x1fe0 /* Channel Center Frequency Segment 2 mask */ +#define HT_OPMODE_CCFS2_SHIFT 5 /* Channel Center Frequency Segment 2 shift */ + +/* misc_bites defn's */ +#define HT_BASIC_STBC_MCS 0x007f /* basic STBC MCS */ +#define HT_DUAL_STBC_PROT 0x0080 /* Dual STBC Protection */ +#define HT_SECOND_BCN 0x0100 /* Secondary beacon support */ +#define HT_LSIG_TXOP 0x0200 /* L-SIG TXOP Protection full support */ +#define HT_PCO_ACTIVE 0x0400 /* PCO active */ +#define HT_PCO_PHASE 0x0800 /* PCO phase */ +#define HT_DUALCTS_PROTECTION 0x0080 /* DUAL CTS protection needed */ + +/* Tx Burst Limits */ +#define DOT11N_2G_TXBURST_LIMIT 6160 /* 2G band Tx burst limit per 802.11n Draft 1.10 (usec) */ +#define DOT11N_5G_TXBURST_LIMIT 3080 /* 5G band Tx burst limit per 802.11n Draft 1.10 (usec) */ + +/* Macros for opmode */ +#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + >> HT_OPMODE_SHIFT) +#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_MIXED) /* mixed mode present */ +#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_HT20IN40) /* 20MHz HT present */ +#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_OPTIONAL) /* Optional protection present */ +#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ + HT_MIXEDMODE_PRESENT((add_ie))) /* use protection */ +#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ + == HT_OPMODE_NONGF) /* non-GF present */ +#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ + == DOT11N_TXBURST) /* Tx Burst present */ +#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ + == DOT11N_OBSS_NONHT) /* OBSS Non-HT present */ +#define HT_OPMODE_CCFS2_GET(add_ie) ((ltoh16_ua(&(add_ie)->opmode) & HT_OPMODE_CCFS2_MASK) \ + >> HT_OPMODE_CCFS2_SHIFT) /* get CCFS2 */ +#define HT_OPMODE_CCFS2_SET(add_ie, ccfs2) do { /* set CCFS2 */ \ + (add_ie)->opmode &= htol16(~HT_OPMODE_CCFS2_MASK); \ + (add_ie)->opmode |= htol16(((ccfs2) << HT_OPMODE_CCFS2_SHIFT) & HT_OPMODE_CCFS2_MASK); \ +} while (0) + +/* Macros for HT MCS field access */ +#define HT_CAP_MCS_BITMASK(supp_mcs) \ + ((supp_mcs)[HT_CAP_MCS_RX_8TO15_BYTE_OFFSET]) +#define HT_CAP_MCS_TX_RX_UNEQUAL(supp_mcs) \ + ((supp_mcs)[HT_CAP_MCS_FLAGS_SUPP_BYTE] & HT_CAP_MCS_FLAGS_TX_RX_UNEQUAL) +#define HT_CAP_MCS_TX_STREAM_SUPPORT(supp_mcs) \ + ((supp_mcs)[HT_CAP_MCS_FLAGS_SUPP_BYTE] & HT_CAP_MCS_FLAGS_MAX_SPATIAL_STREAM_MASK) + +BWL_PRE_PACKED_STRUCT struct obss_params { + uint16 passive_dwell; + uint16 active_dwell; + uint16 bss_widthscan_interval; + uint16 passive_total; + uint16 active_total; + uint16 chanwidth_transition_dly; + uint16 activity_threshold; +} BWL_POST_PACKED_STRUCT; +typedef struct obss_params obss_params_t; + +BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { + uint8 id; + uint8 len; + obss_params_t obss_params; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_ie dot11_obss_ie_t; +#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) /* HT OBSS len (based on 802.11n d3.0) */ + +/* HT control field */ +#define HT_CTRL_LA_TRQ 0x00000002 /* sounding request */ +#define HT_CTRL_LA_MAI 0x0000003C /* MCS request or antenna selection indication */ +#define HT_CTRL_LA_MAI_SHIFT 2 +#define HT_CTRL_LA_MAI_MRQ 0x00000004 /* MCS request */ +#define HT_CTRL_LA_MAI_MSI 0x00000038 /* MCS request sequence identifier */ +#define HT_CTRL_LA_MFSI 0x000001C0 /* MFB sequence identifier */ +#define HT_CTRL_LA_MFSI_SHIFT 6 +#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 /* MCS feedback, antenna selection command/data */ +#define HT_CTRL_LA_MFB_ASELC_SH 9 +#define HT_CTRL_LA_ASELC_CMD 0x00000C00 /* ASEL command */ +#define HT_CTRL_LA_ASELC_DATA 0x0000F000 /* ASEL data */ +#define HT_CTRL_CAL_POS 0x00030000 /* Calibration position */ +#define HT_CTRL_CAL_SEQ 0x000C0000 /* Calibration sequence */ +#define HT_CTRL_CSI_STEERING 0x00C00000 /* CSI/Steering */ +#define HT_CTRL_CSI_STEER_SHIFT 22 +#define HT_CTRL_CSI_STEER_NFB 0 /* no fedback required */ +#define HT_CTRL_CSI_STEER_CSI 1 /* CSI, H matrix */ +#define HT_CTRL_CSI_STEER_NCOM 2 /* non-compressed beamforming */ +#define HT_CTRL_CSI_STEER_COM 3 /* compressed beamforming */ +#define HT_CTRL_NDP_ANNOUNCE 0x01000000 /* NDP announcement */ +#define HT_CTRL_AC_CONSTRAINT 0x40000000 /* AC Constraint */ +#define HT_CTRL_RDG_MOREPPDU 0x80000000 /* RDG/More PPDU */ + +/* HT action ids */ +#define DOT11_ACTION_ID_HT_CH_WIDTH 0 /* notify channel width action id */ +#define DOT11_ACTION_ID_HT_MIMO_PS 1 /* mimo ps action id */ + +/** + * Extension Channel Offset IE: 802.11n-D1.0 spec. added sideband + * offset for 40MHz operation. The possible 3 values are: + * 1 = above control channel + * 3 = below control channel + * 0 = no extension channel + */ +BWL_PRE_PACKED_STRUCT struct dot11_extch { + uint8 id; /* IE ID, 62, DOT11_MNG_EXT_CHANNEL_OFFSET */ + uint8 len; /* IE length */ + uint8 extch; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extch dot11_extch_ie_t; + +#define DOT11_EXTCH_IE_LEN 1 +#define DOT11_EXT_CH_MASK 0x03 /* extension channel mask */ +#define DOT11_EXT_CH_UPPER 0x01 /* ext. ch. on upper sb */ +#define DOT11_EXT_CH_LOWER 0x03 /* ext. ch. on lower sb */ +#define DOT11_EXT_CH_NONE 0x00 /* no extension ch. */ + +/** 11n Extended Channel Switch IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { + uint8 id; /* id DOT11_MNG_EXT_CSA_ID */ + uint8 len; /* length of IE */ + struct dot11_csa_body b; /* body of the ie */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ext_csa dot11_ext_csa_ie_t; +#define DOT11_EXT_CSA_IE_LEN 4 /* length of extended channel switch IE body */ + +BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa { + uint8 category; + uint8 action; + dot11_ext_csa_ie_t chan_switch_ie; /* for switch IE */ +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { + uint8 id; + uint8 len; + uint8 info; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_coex dot11_obss_coex_t; +#define DOT11_OBSS_COEXINFO_LEN 1 /* length of OBSS Coexistence INFO IE */ + +#define DOT11_OBSS_COEX_INFO_REQ 0x01 +#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 +#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 + +BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist { + uint8 id; + uint8 len; + uint8 regclass; + uint8 chanlist[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; +#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 /* fixed length of regclass */ + +/* Extended Capability Information Field */ +#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01 /* 20/40 BSS Coexistence Management support */ + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11n_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11owe.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11owe.h new file mode 100644 index 000000000000..2af77fbef570 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11owe.h @@ -0,0 +1,62 @@ +/* + * Fundamental types and constants relating to OWE (RFC 8110 and WFA spec) - + * "Opportunistic Wireless Encryption" + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _802_11owe_h_ +#define _802_11owe_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +BWL_PRE_PACKED_STRUCT struct dot11_dh_param_ie { + uint8 id; /* OWE */ + uint8 len; + uint8 ext_id; /* EXT_MNG_OWE_DH_PARAM_ID */ + uint16 group; + uint8 pub_key[]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dh_param_ie dot11_dh_param_ie_t; + +#define DOT11_DH_EXTID_OFFSET (OFFSETOF(dot11_dh_param_ie_t, ext_id)) + +#define DOT11_OWE_DH_PARAM_IE(_ie) (\ + DOT11_MNG_IE_ID_EXT_MATCH(_ie, EXT_MNG_OWE_DH_PARAM_ID)) + +#define DOT11_MNG_OWE_IE_ID_EXT_INIT(_ie, _id, _len) do {\ + (_ie)->id = DOT11_MNG_ID_EXT_ID; \ + (_ie)->len = _len; \ + (_ie)->ext_id = _id; \ +} while (0) + +/* OWE definitions */ +/* ID + len + OUI + OI type + BSSID + SSID_len */ +#define OWE_TRANS_MODE_IE_FIXED_LEN 13u + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11owe_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11r.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11r.h deleted file mode 100755 index 7bb872856dbb..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11r.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * Fundamental constants relating to 802.11r - */ - -#ifndef _802_11r_H_ -#define _802_11r_H_ - -#define FBT_R0KH_ID_LEN 49 /* includes null termination */ -#define FBT_REASSOC_TIME_DEF 1000 - -#define DOT11_FBT_SUBELEM_ID_R1KH_ID 1 -#define DOT11_FBT_SUBELEM_ID_GTK 2 -#define DOT11_FBT_SUBELEM_ID_R0KH_ID 3 -#define DOT11_FBT_SUBELEM_ID_IGTK 4 -#define DOT11_FBT_SUBELEM_ID_OCI 5u - -/* -* FBT Subelement id lenths -*/ - -#define DOT11_FBT_SUBELEM_R1KH_LEN 6 -/* GTK_FIXED_LEN = Key_Info (2Bytes) + Key_Length (1Byte) + RSC (8Bytes) */ -#define DOT11_FBT_SUBELEM_GTK_FIXED_LEN 11 -/* GTK_MIN_LEN = GTK_FIXED_LEN + key (min 16 Bytes) + key_wrap (8Bytes) */ -#define DOT11_FBT_SUBELEM_GTK_MIN_LEN (DOT11_FBT_SUBELEM_GTK_FIXED_LEN + 24) -/* GTK_MAX_LEN = GTK_FIXED_LEN + key (max 32 Bytes) + key_wrap (8Bytes) */ -#define DOT11_FBT_SUBELEM_GTK_MAX_LEN (DOT11_FBT_SUBELEM_GTK_FIXED_LEN + 40) -#define DOT11_FBT_SUBELEM_R0KH_MIN_LEN 1 -#define DOT11_FBT_SUBELEM_R0KH_MAX_LEN 48 -/* IGTK_LEN = KeyID (2Bytes) + IPN (6Bytes) + Key_Length (1Byte) + -* Wrapped_Key (key (16Bytes) + key_wrap (8Bytes)) -*/ -#define DOT11_FBT_SUBELEM_IGTK_LEN 33 -#define DOT11_FBT_SUBELEM_OCI_LEN 3u - -#endif /* #ifndef _802_11r_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11s.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11s.h old mode 100755 new mode 100644 index 7c0869fbe399..6ddbde466a66 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11s.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11s.h @@ -1,7 +1,8 @@ /* - * Fundamental types and constants relating to 802.11s Mesh + * Fundamental types and constants relating to 802.11s - + * "Mesh Networking" * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -256,7 +257,6 @@ typedef struct mesh_config_ie mesh_config_ie_t; #define MESH_PEERING_STATE_STRINGS \ {"IDLE ", "OPNSNT", "CNFRCV", "OPNRCV", "ESTAB ", "HOLDNG"} -#ifdef WLMESH typedef BWL_PRE_PACKED_STRUCT struct mesh_peer_info { /* mesh_peer_instance as given in the spec. Note that, peer address * is stored in scb @@ -277,27 +277,6 @@ typedef BWL_PRE_PACKED_STRUCT struct mesh_peer_info { */ } BWL_POST_PACKED_STRUCT mesh_peer_info_t; -typedef BWL_PRE_PACKED_STRUCT struct mesh_peer_info_ext { - mesh_peer_info_t peer_info; - uint16 local_aid; /* AID generated by *local* to peer */ - struct ether_addr ea; /* peer ea */ - uint32 entry_state; /* see MESH_PEER_ENTRY_STATE_ACTIVE etc; valid - * ONLY for internal peering requests - */ - int rssi; -} BWL_POST_PACKED_STRUCT mesh_peer_info_ext_t; - -/* #ifdef WLMESH */ -typedef BWL_PRE_PACKED_STRUCT struct mesh_peer_info_dump { - uint32 buflen; - uint32 version; - uint32 count; /* number of results */ - mesh_peer_info_ext_t mpi_ext[1]; -} BWL_POST_PACKED_STRUCT mesh_peer_info_dump_t; -#define WL_MESH_PEER_RES_FIXED_SIZE (sizeof(mesh_peer_info_dump_t) - sizeof(mesh_peer_info_ext_t)) - -#endif /* WLMESH */ - /* once an entry is added into mesh_peer_list, if peering is lost, it will * get retried for peering, MAX_MESH_PEER_ENTRY_RETRIES times. after wards, it * wont get retried and will be moved to MESH_PEER_ENTRY_STATE_TIMEDOUT state, diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11u.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11u.h new file mode 100644 index 000000000000..11852217d6ad --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11u.h @@ -0,0 +1,200 @@ +/* + * Fundamental types and constants relating to 802.11u - + * "Interworking with External Networks" + * + * IW - InterWorking + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _802_11u_h_ +#define _802_11u_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +/* 802.11u GAS action frames */ +#define GAS_REQUEST_ACTION_FRAME 10 +#define GAS_RESPONSE_ACTION_FRAME 11 +#define GAS_COMEBACK_REQUEST_ACTION_FRAME 12 +#define GAS_COMEBACK_RESPONSE_ACTION_FRAME 13 + +/* 802.11u interworking access network options */ +#define IW_ANT_MASK 0x0f +#define IW_INTERNET_MASK 0x10 +#define IW_ASRA_MASK 0x20 +#define IW_ESR_MASK 0x40 +#define IW_UESA_MASK 0x80 + +/* 802.11u interworking access network type */ +#define IW_ANT_PRIVATE_NETWORK 0 +#define IW_ANT_PRIVATE_NETWORK_WITH_GUEST 1 +#define IW_ANT_CHARGEABLE_PUBLIC_NETWORK 2 +#define IW_ANT_FREE_PUBLIC_NETWORK 3 +#define IW_ANT_PERSONAL_DEVICE_NETWORK 4 +#define IW_ANT_EMERGENCY_SERVICES_NETWORK 5 +#define IW_ANT_TEST_NETWORK 14 +#define IW_ANT_WILDCARD_NETWORK 15 + +#define IW_ANT_LEN 1 +#define IW_VENUE_LEN 2 +#define IW_HESSID_LEN 6 +#define IW_HESSID_OFF (IW_ANT_LEN + IW_VENUE_LEN) +#define IW_MAX_LEN (IW_ANT_LEN + IW_VENUE_LEN + IW_HESSID_LEN) + +/* 802.11u advertisement protocol */ +#define ADVP_ANQP_PROTOCOL_ID 0 +#define ADVP_MIH_PROTOCOL_ID 1 + +/* 802.11u advertisement protocol masks */ +#define ADVP_QRL_MASK 0x7f +#define ADVP_PAME_BI_MASK 0x80 + +/* 802.11u advertisement protocol values */ +#define ADVP_QRL_REQUEST 0x00 +#define ADVP_QRL_RESPONSE 0x7f +#define ADVP_PAME_BI_DEPENDENT 0x00 +#define ADVP_PAME_BI_INDEPENDENT ADVP_PAME_BI_MASK + +/* 802.11u ANQP information ID */ +#define ANQP_ID_QUERY_LIST 256 +#define ANQP_ID_CAPABILITY_LIST 257 +#define ANQP_ID_VENUE_NAME_INFO 258 +#define ANQP_ID_EMERGENCY_CALL_NUMBER_INFO 259 +#define ANQP_ID_NETWORK_AUTHENTICATION_TYPE_INFO 260 +#define ANQP_ID_ROAMING_CONSORTIUM_LIST 261 +#define ANQP_ID_IP_ADDRESS_TYPE_AVAILABILITY_INFO 262 +#define ANQP_ID_NAI_REALM_LIST 263 +#define ANQP_ID_G3PP_CELLULAR_NETWORK_INFO 264 +#define ANQP_ID_AP_GEOSPATIAL_LOCATION 265 +#define ANQP_ID_AP_CIVIC_LOCATION 266 +#define ANQP_ID_AP_LOCATION_PUBLIC_ID_URI 267 +#define ANQP_ID_DOMAIN_NAME_LIST 268 +#define ANQP_ID_EMERGENCY_ALERT_ID_URI 269 +#define ANQP_ID_EMERGENCY_NAI 271 +#define ANQP_ID_NEIGHBOR_REPORT 272 +#define ANQP_ID_VENDOR_SPECIFIC_LIST 56797 + +/* 802.11u ANQP ID len */ +#define ANQP_INFORMATION_ID_LEN 2 + +/* 802.11u ANQP OUI */ +#define ANQP_OUI_SUBTYPE 9 + +/* 802.11u venue name */ +#define VENUE_LANGUAGE_CODE_SIZE 3 +#define VENUE_NAME_SIZE 255 + +/* 802.11u venue groups */ +#define VENUE_UNSPECIFIED 0 +#define VENUE_ASSEMBLY 1 +#define VENUE_BUSINESS 2 +#define VENUE_EDUCATIONAL 3 +#define VENUE_FACTORY 4 +#define VENUE_INSTITUTIONAL 5 +#define VENUE_MERCANTILE 6 +#define VENUE_RESIDENTIAL 7 +#define VENUE_STORAGE 8 +#define VENUE_UTILITY 9 +#define VENUE_VEHICULAR 10 +#define VENUE_OUTDOOR 11 + +/* 802.11u network authentication type indicator */ +#define NATI_UNSPECIFIED -1 +#define NATI_ACCEPTANCE_OF_TERMS_CONDITIONS 0 +#define NATI_ONLINE_ENROLLMENT_SUPPORTED 1 +#define NATI_HTTP_HTTPS_REDIRECTION 2 +#define NATI_DNS_REDIRECTION 3 + +/* 802.11u IP address type availability - IPv6 */ +#define IPA_IPV6_SHIFT 0 +#define IPA_IPV6_MASK (0x03 << IPA_IPV6_SHIFT) +#define IPA_IPV6_NOT_AVAILABLE 0x00 +#define IPA_IPV6_AVAILABLE 0x01 +#define IPA_IPV6_UNKNOWN_AVAILABILITY 0x02 + +/* 802.11u IP address type availability - IPv4 */ +#define IPA_IPV4_SHIFT 2 +#define IPA_IPV4_MASK (0x3f << IPA_IPV4_SHIFT) +#define IPA_IPV4_NOT_AVAILABLE 0x00 +#define IPA_IPV4_PUBLIC 0x01 +#define IPA_IPV4_PORT_RESTRICT 0x02 +#define IPA_IPV4_SINGLE_NAT 0x03 +#define IPA_IPV4_DOUBLE_NAT 0x04 +#define IPA_IPV4_PORT_RESTRICT_SINGLE_NAT 0x05 +#define IPA_IPV4_PORT_RESTRICT_DOUBLE_NAT 0x06 +#define IPA_IPV4_UNKNOWN_AVAILABILITY 0x07 + +/* 802.11u NAI realm encoding */ +#define REALM_ENCODING_RFC4282 0 +#define REALM_ENCODING_UTF8 1 + +/* 802.11u IANA EAP method type numbers */ +#define REALM_EAP_TLS 13 +#define REALM_EAP_LEAP 17 +#define REALM_EAP_SIM 18 +#define REALM_EAP_TTLS 21 +#define REALM_EAP_AKA 23 +#define REALM_EAP_PEAP 25 +#define REALM_EAP_FAST 43 +#define REALM_EAP_PSK 47 +#define REALM_EAP_AKAP 50 +#define REALM_EAP_EXPANDED 254 + +/* 802.11u authentication ID */ +#define REALM_EXPANDED_EAP 1 +#define REALM_NON_EAP_INNER_AUTHENTICATION 2 +#define REALM_INNER_AUTHENTICATION_EAP 3 +#define REALM_EXPANDED_INNER_EAP 4 +#define REALM_CREDENTIAL 5 +#define REALM_TUNNELED_EAP_CREDENTIAL 6 +#define REALM_VENDOR_SPECIFIC_EAP 221 + +/* 802.11u non-EAP inner authentication type */ +#define REALM_RESERVED_AUTH 0 +#define REALM_PAP 1 +#define REALM_CHAP 2 +#define REALM_MSCHAP 3 +#define REALM_MSCHAPV2 4 + +/* 802.11u credential type */ +#define REALM_SIM 1 +#define REALM_USIM 2 +#define REALM_NFC 3 +#define REALM_HARDWARE_TOKEN 4 +#define REALM_SOFTOKEN 5 +#define REALM_CERTIFICATE 6 +#define REALM_USERNAME_PASSWORD 7 +#define REALM_SERVER_SIDE 8 +#define REALM_RESERVED_CRED 9 +#define REALM_VENDOR_SPECIFIC_CRED 10 + +/* 802.11u 3GPP PLMN */ +#define G3PP_GUD_VERSION 0 +#define G3PP_PLMN_LIST_IE 0 + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11u_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11v.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11v.h new file mode 100644 index 000000000000..88b407fdb3fa --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11v.h @@ -0,0 +1,794 @@ +/* + * Fundamental types and constants relating to 802.11v - + * "Wireless Network Management" extending certain 802.11k - + * "Radio Resource Measurement of Wireless LANs" features + * + * WNM - Wireless Network Management + * UWNM - Unprotected Wireless Network Management + * BSSTRANS - BSS Management Transition + * TIMBC - TIM Broadcast + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _802_11v_h_ +#define _802_11v_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +#define DOT11_EXTCAP_LEN_FMS 2 +#define DOT11_EXTCAP_LEN_PROXY_ARP 2 +#define DOT11_EXTCAP_LEN_TFS 3 +#define DOT11_EXTCAP_LEN_WNM_SLEEP 3 +#define DOT11_EXTCAP_LEN_TIMBC 3 +#define DOT11_EXTCAP_LEN_BSSTRANS 3 +#define DOT11_EXTCAP_LEN_DMS 4 +#define DOT11_EXTCAP_LEN_WNM_NOTIFICATION 6 + +/* ************* 802.11v related definitions. ************* */ + +/** BSS Management Transition Query frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_query { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: trans_query (6) */ + uint8 token; /* dialog token */ + uint8 reason; /* transition query reason */ + uint8 data[BCM_FLEX_ARRAY]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_query dot11_bsstrans_query_t; +#define DOT11_BSSTRANS_QUERY_LEN 4 /* Fixed length */ + +/* BTM transition reason */ +#define DOT11_BSSTRANS_REASON_UNSPECIFIED 0 +#define DOT11_BSSTRANS_REASON_EXC_FRAME_LOSS 1 +#define DOT11_BSSTRANS_REASON_EXC_TRAFFIC_DELAY 2 +#define DOT11_BSSTRANS_REASON_INSUFF_QOS_CAPACITY 3 +#define DOT11_BSSTRANS_REASON_FIRST_ASSOC 4 +#define DOT11_BSSTRANS_REASON_LOAD_BALANCING 5 +#define DOT11_BSSTRANS_REASON_BETTER_AP_FOUND 6 +#define DOT11_BSSTRANS_REASON_DEAUTH_RX 7 +#define DOT11_BSSTRANS_REASON_8021X_EAP_AUTH_FAIL 8 +#define DOT11_BSSTRANS_REASON_4WAY_HANDSHK_FAIL 9 +#define DOT11_BSSTRANS_REASON_MANY_REPLAYCNT_FAIL 10 +#define DOT11_BSSTRANS_REASON_MANY_DATAMIC_FAIL 11 +#define DOT11_BSSTRANS_REASON_EXCEED_MAX_RETRANS 12 +#define DOT11_BSSTRANS_REASON_MANY_BCAST_DISASSOC_RX 13 +#define DOT11_BSSTRANS_REASON_MANY_BCAST_DEAUTH_RX 14 +#define DOT11_BSSTRANS_REASON_PREV_TRANSITION_FAIL 15 +#define DOT11_BSSTRANS_REASON_LOW_RSSI 16 +#define DOT11_BSSTRANS_REASON_ROAM_FROM_NON_80211 17 +#define DOT11_BSSTRANS_REASON_RX_BTM_REQ 18 +#define DOT11_BSSTRANS_REASON_PREF_LIST_INCLUDED 19 +#define DOT11_BSSTRANS_REASON_LEAVING_ESS 20 + +/** BSS Management Transition Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: trans_req (7) */ + uint8 token; /* dialog token */ + uint8 reqmode; /* transition request mode */ + uint16 disassoc_tmr; /* disassociation timer */ + uint8 validity_intrvl; /* validity interval */ + uint8 data[BCM_FLEX_ARRAY]; /* optional: BSS term duration, ... */ + /* ...session info URL, candidate list */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_req dot11_bsstrans_req_t; +#define DOT11_BSSTRANS_REQ_LEN 7 /* Fixed length */ +#define DOT11_BSSTRANS_REQ_FIXED_LEN 7u /* Fixed length */ + +/* BSS Mgmt Transition Request Mode Field - 802.11v */ +#define DOT11_BSSTRANS_REQMODE_PREF_LIST_INCL 0x01 +#define DOT11_BSSTRANS_REQMODE_ABRIDGED 0x02 +#define DOT11_BSSTRANS_REQMODE_DISASSOC_IMMINENT 0x04 +#define DOT11_BSSTRANS_REQMODE_BSS_TERM_INCL 0x08 +#define DOT11_BSSTRANS_REQMODE_ESS_DISASSOC_IMNT 0x10 + +/** BSS Management transition response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: trans_resp (8) */ + uint8 token; /* dialog token */ + uint8 status; /* transition status */ + uint8 term_delay; /* validity interval */ + uint8 data[BCM_FLEX_ARRAY]; /* optional: BSSID target, candidate list */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_resp dot11_bsstrans_resp_t; +#define DOT11_BSSTRANS_RESP_LEN 5 /* Fixed length */ + +/* BSS Mgmt Transition Response Status Field */ +#define DOT11_BSSTRANS_RESP_STATUS_ACCEPT 0 +#define DOT11_BSSTRANS_RESP_STATUS_REJECT 1 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_BCN 2 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_CAP 3 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_UNDESIRED 4 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_DELAY_REQ 5 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_BSS_LIST_PROVIDED 6 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_NO_SUITABLE_BSS 7 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_LEAVING_ESS 8 + +/* Wireless Network Management (WNM) action types */ +#define DOT11_WNM_ACTION_EVENT_REQ 0 +#define DOT11_WNM_ACTION_EVENT_REP 1 +#define DOT11_WNM_ACTION_DIAG_REQ 2 +#define DOT11_WNM_ACTION_DIAG_REP 3 +#define DOT11_WNM_ACTION_LOC_CFG_REQ 4 +#define DOT11_WNM_ACTION_LOC_RFG_RESP 5 +#define DOT11_WNM_ACTION_BSSTRANS_QUERY 6 +#define DOT11_WNM_ACTION_BSSTRANS_REQ 7 +#define DOT11_WNM_ACTION_BSSTRANS_RESP 8 +#define DOT11_WNM_ACTION_FMS_REQ 9 +#define DOT11_WNM_ACTION_FMS_RESP 10 +#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 +#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 +#define DOT11_WNM_ACTION_TFS_REQ 13 +#define DOT11_WNM_ACTION_TFS_RESP 14 +#define DOT11_WNM_ACTION_TFS_NOTIFY_REQ 15 +#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 +#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 +#define DOT11_WNM_ACTION_TIMBC_REQ 18 +#define DOT11_WNM_ACTION_TIMBC_RESP 19 +#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 +#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 +#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 +#define DOT11_WNM_ACTION_DMS_REQ 23 +#define DOT11_WNM_ACTION_DMS_RESP 24 +#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 +#define DOT11_WNM_ACTION_NOTFCTN_REQ 26 +#define DOT11_WNM_ACTION_NOTFCTN_RESP 27 +#define DOT11_WNM_ACTION_TFS_NOTIFY_RESP 28 + +/* Unprotected Wireless Network Management (WNM) action types */ +#define DOT11_UWNM_ACTION_TIM 0 +#define DOT11_UWNM_ACTION_TIMING_MEASUREMENT 1 + +/** BSS Max Idle Period element */ +BWL_PRE_PACKED_STRUCT struct dot11_bss_max_idle_period_ie { + uint8 id; /* 90, DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID */ + uint8 len; + uint16 max_idle_period; /* in unit of 1000 TUs */ + uint8 idle_opt; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bss_max_idle_period_ie dot11_bss_max_idle_period_ie_t; +#define DOT11_BSS_MAX_IDLE_PERIOD_IE_LEN 3 /* bss max idle period IE size */ +#define DOT11_BSS_MAX_IDLE_PERIOD_OPT_PROTECTED 1 /* BSS max idle option */ + +/** TIM Broadcast request element */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_req_ie { + uint8 id; /* 94, DOT11_MNG_TIMBC_REQ_ID */ + uint8 len; + uint8 interval; /* in unit of beacon interval */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_req_ie dot11_timbc_req_ie_t; +#define DOT11_TIMBC_REQ_IE_LEN 1 /* Fixed length */ + +/** TIM Broadcast request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: DOT11_WNM_ACTION_TIMBC_REQ(18) */ + uint8 token; /* dialog token */ + uint8 data[BCM_FLEX_ARRAY]; /* TIM broadcast request element */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_req dot11_timbc_req_t; +#define DOT11_TIMBC_REQ_LEN 3 /* Fixed length */ + +/** TIM Broadcast response element */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp_ie { + uint8 id; /* 95, DOT11_MNG_TIM_BROADCAST_RESP_ID */ + uint8 len; + uint8 status; /* status of add request */ + uint8 interval; /* in unit of beacon interval */ + int32 offset; /* in unit of ms */ + uint16 high_rate; /* in unit of 0.5 Mb/s */ + uint16 low_rate; /* in unit of 0.5 Mb/s */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_resp_ie dot11_timbc_resp_ie_t; +#define DOT11_TIMBC_DENY_RESP_IE_LEN 1 /* Deny. Fixed length */ +#define DOT11_TIMBC_ACCEPT_RESP_IE_LEN 10 /* Accept. Fixed length */ + +#define DOT11_TIMBC_STATUS_ACCEPT 0 +#define DOT11_TIMBC_STATUS_ACCEPT_TSTAMP 1 +#define DOT11_TIMBC_STATUS_DENY 2 +#define DOT11_TIMBC_STATUS_OVERRIDDEN 3 +#define DOT11_TIMBC_STATUS_RESERVED 4 + +/** TIM Broadcast request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* action: DOT11_WNM_ACTION_TIMBC_RESP(19) */ + uint8 token; /* dialog token */ + uint8 data[BCM_FLEX_ARRAY]; /* TIM broadcast response element */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_resp dot11_timbc_resp_t; +#define DOT11_TIMBC_RESP_LEN 3 /* Fixed length */ + +/** TIM Broadcast frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc { + uint8 category; /* category of action frame (11) */ + uint8 action; /* action: TIM (0) */ + uint8 check_beacon; /* need to check-beacon */ + uint8 tsf[8]; /* Time Synchronization Function */ + dot11_tim_ie_t tim_ie; /* TIM element */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc dot11_timbc_t; +#define DOT11_TIMBC_HDR_LEN (sizeof(dot11_timbc_t) - sizeof(dot11_tim_ie_t)) +#define DOT11_TIMBC_FIXED_LEN (sizeof(dot11_timbc_t) - 1) /* Fixed length */ +#define DOT11_TIMBC_LEN 11 /* Fixed length */ + +/** TFS request element */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_req_ie { + uint8 id; /* 91, DOT11_MNG_TFS_REQUEST_ID */ + uint8 len; + uint8 tfs_id; + uint8 actcode; + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_req_ie dot11_tfs_req_ie_t; +#define DOT11_TFS_REQ_IE_LEN 2 /* Fixed length, without id and len */ + +/** TFS request action codes (bitfield) */ +#define DOT11_TFS_ACTCODE_DELETE 1 +#define DOT11_TFS_ACTCODE_NOTIFY 2 + +/** TFS request subelement IDs */ +#define DOT11_TFS_REQ_TFS_SE_ID 1 +#define DOT11_TFS_REQ_VENDOR_SE_ID 221 + +/** TFS subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_se { + uint8 sub_id; + uint8 len; + uint8 data[BCM_FLEX_ARRAY]; /* TCLAS element(s) + optional TCLAS proc */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_se dot11_tfs_se_t; + +/** TFS response element */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp_ie { + uint8 id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ + uint8 len; + uint8 tfs_id; + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_resp_ie dot11_tfs_resp_ie_t; +#define DOT11_TFS_RESP_IE_LEN 1u /* Fixed length, without id and len */ + +/** TFS response subelement IDs (same subelments, but different IDs than in TFS request */ +#define DOT11_TFS_RESP_TFS_STATUS_SE_ID 1 +#define DOT11_TFS_RESP_TFS_SE_ID 2 +#define DOT11_TFS_RESP_VENDOR_SE_ID 221 + +/** TFS status subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_status_se { + uint8 sub_id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ + uint8 len; + uint8 resp_st; + uint8 data[BCM_FLEX_ARRAY]; /* Potential dot11_tfs_se_t included */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_status_se dot11_tfs_status_se_t; +#define DOT11_TFS_STATUS_SE_LEN 1 /* Fixed length, without id and len */ + +/* Following Definition should be merged to FMS_TFS macro below */ +/* TFS Response status code. Identical to FMS Element status, without N/A */ +#define DOT11_TFS_STATUS_ACCEPT 0 +#define DOT11_TFS_STATUS_DENY_FORMAT 1 +#define DOT11_TFS_STATUS_DENY_RESOURCE 2 +#define DOT11_TFS_STATUS_DENY_POLICY 4 +#define DOT11_TFS_STATUS_DENY_UNSPECIFIED 5 +#define DOT11_TFS_STATUS_ALTPREF_POLICY 7 +#define DOT11_TFS_STATUS_ALTPREF_TCLAS_UNSUPP 14 + +/* FMS Element Status and TFS Response Status Definition */ +#define DOT11_FMS_TFS_STATUS_ACCEPT 0 +#define DOT11_FMS_TFS_STATUS_DENY_FORMAT 1 +#define DOT11_FMS_TFS_STATUS_DENY_RESOURCE 2 +#define DOT11_FMS_TFS_STATUS_DENY_MULTIPLE_DI 3 +#define DOT11_FMS_TFS_STATUS_DENY_POLICY 4 +#define DOT11_FMS_TFS_STATUS_DENY_UNSPECIFIED 5 +#define DOT11_FMS_TFS_STATUS_ALT_DIFF_DI 6 +#define DOT11_FMS_TFS_STATUS_ALT_POLICY 7 +#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_DI 8 +#define DOT11_FMS_TFS_STATUS_ALT_MCRATE 9 +#define DOT11_FMS_TFS_STATUS_TERM_POLICY 10 +#define DOT11_FMS_TFS_STATUS_TERM_RESOURCE 11 +#define DOT11_FMS_TFS_STATUS_TERM_HIGHER_PRIO 12 +#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_MDI 13 +#define DOT11_FMS_TFS_STATUS_ALT_TCLAS_UNSUPP 14 + +/** TFS Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: TFS request (13) */ + uint8 token; /* dialog token */ + uint8 data[BCM_FLEX_ARRAY]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_req dot11_tfs_req_t; +#define DOT11_TFS_REQ_LEN 3 /* Fixed length */ + +/** TFS Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: TFS request (14) */ + uint8 token; /* dialog token */ + uint8 data[BCM_FLEX_ARRAY]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_resp dot11_tfs_resp_t; +#define DOT11_TFS_RESP_LEN 3 /* Fixed length */ + +/** TFS Management Notify frame request header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: TFS notify request (15) */ + uint8 tfs_id_cnt; /* TFS IDs count */ + uint8 tfs_id[BCM_FLEX_ARRAY]; /* Array of TFS IDs */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_notify_req dot11_tfs_notify_req_t; +#define DOT11_TFS_NOTIFY_REQ_LEN 3 /* Fixed length */ + +/** TFS Management Notify frame response header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: TFS notify response (28) */ + uint8 tfs_id_cnt; /* TFS IDs count */ + uint8 tfs_id[BCM_FLEX_ARRAY]; /* Array of TFS IDs */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_notify_resp dot11_tfs_notify_resp_t; +#define DOT11_TFS_NOTIFY_RESP_LEN 3 /* Fixed length */ + +/** WNM-Sleep Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: wnm-sleep request (16) */ + uint8 token; /* dialog token */ + uint8 data[BCM_FLEX_ARRAY]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_req dot11_wnm_sleep_req_t; +#define DOT11_WNM_SLEEP_REQ_LEN 3 /* Fixed length */ + +/** WNM-Sleep Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: wnm-sleep request (17) */ + uint8 token; /* dialog token */ + uint16 key_len; /* key data length */ + uint8 data[BCM_FLEX_ARRAY]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_resp dot11_wnm_sleep_resp_t; +#define DOT11_WNM_SLEEP_RESP_LEN 5 /* Fixed length */ + +#define DOT11_WNM_SLEEP_SUBELEM_ID_GTK 0 +#define DOT11_WNM_SLEEP_SUBELEM_ID_IGTK 1 + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_gtk { + uint8 sub_id; + uint8 len; + uint16 key_info; + uint8 key_length; + uint8 rsc[8]; + uint8 key[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_subelem_gtk dot11_wnm_sleep_subelem_gtk_t; +#define DOT11_WNM_SLEEP_SUBELEM_GTK_FIXED_LEN 11 /* without sub_id, len, and key */ +#define DOT11_WNM_SLEEP_SUBELEM_GTK_MAX_LEN 43 /* without sub_id and len */ + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_igtk { + uint8 sub_id; + uint8 len; + uint16 key_id; + uint8 pn[6]; + uint8 key[16]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_subelem_igtk dot11_wnm_sleep_subelem_igtk_t; +#define DOT11_WNM_SLEEP_SUBELEM_IGTK_LEN 24 /* Fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_ie { + uint8 id; /* 93, DOT11_MNG_WNM_SLEEP_MODE_ID */ + uint8 len; + uint8 act_type; + uint8 resp_status; + uint16 interval; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_ie dot11_wnm_sleep_ie_t; +#define DOT11_WNM_SLEEP_IE_LEN 4 /* Fixed length */ + +#define DOT11_WNM_SLEEP_ACT_TYPE_ENTER 0 +#define DOT11_WNM_SLEEP_ACT_TYPE_EXIT 1 + +#define DOT11_WNM_SLEEP_RESP_ACCEPT 0 +#define DOT11_WNM_SLEEP_RESP_UPDATE 1 +#define DOT11_WNM_SLEEP_RESP_DENY 2 +#define DOT11_WNM_SLEEP_RESP_DENY_TEMP 3 +#define DOT11_WNM_SLEEP_RESP_DENY_KEY 4 +#define DOT11_WNM_SLEEP_RESP_DENY_INUSE 5 +#define DOT11_WNM_SLEEP_RESP_LAST 6 + +/** DMS Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: dms request (23) */ + uint8 token; /* dialog token */ + uint8 data[BCM_FLEX_ARRAY]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req dot11_dms_req_t; +#define DOT11_DMS_REQ_LEN 3 /* Fixed length */ + +/** DMS Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: dms request (24) */ + uint8 token; /* dialog token */ + uint8 data[BCM_FLEX_ARRAY]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp dot11_dms_resp_t; +#define DOT11_DMS_RESP_LEN 3 /* Fixed length */ + +/** DMS request element */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_req_ie { + uint8 id; /* 99, DOT11_MNG_DMS_REQUEST_ID */ + uint8 len; + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req_ie dot11_dms_req_ie_t; +#define DOT11_DMS_REQ_IE_LEN 2 /* Fixed length */ + +/** DMS response element */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_ie { + uint8 id; /* 100, DOT11_MNG_DMS_RESPONSE_ID */ + uint8 len; + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp_ie dot11_dms_resp_ie_t; +#define DOT11_DMS_RESP_IE_LEN 2 /* Fixed length */ + +/** DMS request descriptor */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_req_desc { + uint8 dms_id; + uint8 len; + uint8 type; + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req_desc dot11_dms_req_desc_t; +#define DOT11_DMS_REQ_DESC_LEN 3 /* Fixed length */ + +#define DOT11_DMS_REQ_TYPE_ADD 0 +#define DOT11_DMS_REQ_TYPE_REMOVE 1 +#define DOT11_DMS_REQ_TYPE_CHANGE 2 + +/** DMS response status */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_st { + uint8 dms_id; + uint8 len; + uint8 type; + uint16 lsc; + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp_st dot11_dms_resp_st_t; +#define DOT11_DMS_RESP_STATUS_LEN 5 /* Fixed length */ + +#define DOT11_DMS_RESP_TYPE_ACCEPT 0 +#define DOT11_DMS_RESP_TYPE_DENY 1 +#define DOT11_DMS_RESP_TYPE_TERM 2 + +#define DOT11_DMS_RESP_LSC_UNSUPPORTED 0xFFFF + +/** WNM-Notification Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_wnm_notif_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: Notification request (26) */ + uint8 token; /* dialog token */ + uint8 type; /* type */ + uint8 data[BCM_FLEX_ARRAY]; /* Sub-elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_notif_req dot11_wnm_notif_req_t; +#define DOT11_WNM_NOTIF_REQ_LEN 4 /* Fixed length */ + +/** FMS Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: fms request (9) */ + uint8 token; /* dialog token */ + uint8 data[BCM_FLEX_ARRAY]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_req dot11_fms_req_t; +#define DOT11_FMS_REQ_LEN 3 /* Fixed length */ + +/** FMS Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: fms request (10) */ + uint8 token; /* dialog token */ + uint8 data[BCM_FLEX_ARRAY]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_resp dot11_fms_resp_t; +#define DOT11_FMS_RESP_LEN 3 /* Fixed length */ + +/** FMS Descriptor element */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_desc { + uint8 id; + uint8 len; + uint8 num_fms_cnt; + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_desc dot11_fms_desc_t; +#define DOT11_FMS_DESC_LEN 1 /* Fixed length */ + +#define DOT11_FMS_CNTR_MAX 0x8 +#define DOT11_FMS_CNTR_ID_MASK 0x7 +#define DOT11_FMS_CNTR_ID_SHIFT 0x0 +#define DOT11_FMS_CNTR_COUNT_MASK 0xf1 +#define DOT11_FMS_CNTR_SHIFT 0x3 + +/** FMS request element */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_req_ie { + uint8 id; + uint8 len; + uint8 fms_token; /* token used to identify fms stream set */ + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_req_ie dot11_fms_req_ie_t; +#define DOT11_FMS_REQ_IE_FIX_LEN 1 /* Fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_rate_id_field { + uint8 mask; + uint8 mcs_idx; + uint16 rate; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rate_id_field dot11_rate_id_field_t; +#define DOT11_RATE_ID_FIELD_MCS_SEL_MASK 0x7 +#define DOT11_RATE_ID_FIELD_MCS_SEL_OFFSET 0 +#define DOT11_RATE_ID_FIELD_RATETYPE_MASK 0x18 +#define DOT11_RATE_ID_FIELD_RATETYPE_OFFSET 3 +#define DOT11_RATE_ID_FIELD_LEN sizeof(dot11_rate_id_field_t) + +/** FMS request subelements */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_se { + uint8 sub_id; + uint8 len; + uint8 interval; + uint8 max_interval; + dot11_rate_id_field_t rate; + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_se dot11_fms_se_t; +#define DOT11_FMS_REQ_SE_LEN 6 /* Fixed length */ + +#define DOT11_FMS_REQ_SE_ID_FMS 1 /* FMS subelement */ +#define DOT11_FMS_REQ_SE_ID_VS 221 /* Vendor Specific subelement */ + +/** FMS response element */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_resp_ie { + uint8 id; + uint8 len; + uint8 fms_token; + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_resp_ie dot11_fms_resp_ie_t; +#define DOT11_FMS_RESP_IE_FIX_LEN 1 /* Fixed length */ + +/* FMS status subelements */ +#define DOT11_FMS_STATUS_SE_ID_FMS 1 /* FMS Status */ +#define DOT11_FMS_STATUS_SE_ID_TCLAS 2 /* TCLAS Status */ +#define DOT11_FMS_STATUS_SE_ID_VS 221 /* Vendor Specific subelement */ + +/** FMS status subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_fms_status_se { + uint8 sub_id; + uint8 len; + uint8 status; + uint8 interval; + uint8 max_interval; + uint8 fmsid; + uint8 counter; + dot11_rate_id_field_t rate; + uint8 mcast_addr[ETHER_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_status_se dot11_fms_status_se_t; +#define DOT11_FMS_STATUS_SE_LEN 15 /* Fixed length */ + +/** TCLAS status subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_status_se { + uint8 sub_id; + uint8 len; + uint8 fmsid; + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_status_se dot11_tclas_status_se_t; +#define DOT11_TCLAS_STATUS_SE_LEN 1 /* Fixed length */ + +/** TCLAS frame classifier type */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_hdr { + uint8 type; + uint8 mask; + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_hdr dot11_tclas_fc_hdr_t; +#define DOT11_TCLAS_FC_HDR_LEN 2 /* Fixed length */ + +#define DOT11_TCLAS_MASK_0 0x1 +#define DOT11_TCLAS_MASK_1 0x2 +#define DOT11_TCLAS_MASK_2 0x4 +#define DOT11_TCLAS_MASK_3 0x8 +#define DOT11_TCLAS_MASK_4 0x10 +#define DOT11_TCLAS_MASK_5 0x20 +#define DOT11_TCLAS_MASK_6 0x40 +#define DOT11_TCLAS_MASK_7 0x80 + +#define DOT11_TCLAS_FC_0_ETH 0 +#define DOT11_TCLAS_FC_1_IP 1 +#define DOT11_TCLAS_FC_2_8021Q 2 +#define DOT11_TCLAS_FC_3_OFFSET 3 +#define DOT11_TCLAS_FC_4_IP_HIGHER 4 +#define DOT11_TCLAS_FC_5_8021D 5 +#define DOT11_TCLAS_FC_10_IP_HIGHER 10 /* classifier type 10, IP extensions and + * higher layer parameters + */ + +/** TCLAS frame classifier type 0 parameters for Ethernet */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_0_eth { + uint8 type; + uint8 mask; + uint8 sa[ETHER_ADDR_LEN]; + uint8 da[ETHER_ADDR_LEN]; + uint16 eth_type; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_0_eth dot11_tclas_fc_0_eth_t; +#define DOT11_TCLAS_FC_0_ETH_LEN 16 + +/** TCLAS frame classifier type 1 parameters for IPV4 */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_1_ipv4 { + uint8 type; + uint8 mask; + uint8 version; + uint32 src_ip; + uint32 dst_ip; + uint16 src_port; + uint16 dst_port; + uint8 dscp; + uint8 protocol; + uint8 reserved; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_1_ipv4_t; +#define DOT11_TCLAS_FC_1_IPV4_LEN 18 + +/** TCLAS frame classifier type 2 parameters for 802.1Q */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_2_8021q { + uint8 type; + uint8 mask; + uint16 tci; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_2_8021q dot11_tclas_fc_2_8021q_t; +#define DOT11_TCLAS_FC_2_8021Q_LEN 4 + +/** TCLAS frame classifier type 3 parameters for filter offset */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_3_filter { + uint8 type; + uint8 mask; + uint16 offset; + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_3_filter dot11_tclas_fc_3_filter_t; +#define DOT11_TCLAS_FC_3_FILTER_LEN 4 + +/** TCLAS frame classifier type 4 parameters for IPV4 is the same as TCLAS type 1 */ +typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_4_ipv4_t; +#define DOT11_TCLAS_FC_4_IPV4_LEN DOT11_TCLAS_FC_1_IPV4_LEN + +/** TCLAS frame classifier type 4 parameters for IPV6 */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_4_ipv6 { + uint8 type; + uint8 mask; + uint8 version; + uint8 saddr[16]; + uint8 daddr[16]; + uint16 src_port; + uint16 dst_port; + uint8 dscp; + uint8 nexthdr; + uint8 flow_lbl[3]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_4_ipv6 dot11_tclas_fc_4_ipv6_t; +#define DOT11_TCLAS_FC_4_IPV6_LEN 44 + +/** TCLAS frame classifier type 5 parameters for 802.1D */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_5_8021d { + uint8 type; + uint8 mask; + uint8 pcp; + uint8 cfi; + uint16 vid; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_5_8021d dot11_tclas_fc_5_8021d_t; +#define DOT11_TCLAS_FC_5_8021D_LEN 6 + +/** TCLAS frame classifier type 10 parameters for IP extensions and higher layer parameters */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_10_ip_ext { + uint8 type; + uint8 proto_inst; /* protocol instance */ + uint8 proto_or_nh; /* protocol(for IPv4) or next header(for IPv6) */ + uint8 data[]; + /* variable filter value */ + /* variable filer mask */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_10_ip_ext dot11_tclas_fc_10_ip_ext_t; +#define DOT11_TCLAS_FC_10_IP_EXT_LEN 3u + +/** TCLAS frame classifier type parameters */ +BWL_PRE_PACKED_STRUCT union dot11_tclas_fc { + uint8 data[1]; + dot11_tclas_fc_hdr_t hdr; + dot11_tclas_fc_0_eth_t t0_eth; + dot11_tclas_fc_1_ipv4_t t1_ipv4; + dot11_tclas_fc_2_8021q_t t2_8021q; + dot11_tclas_fc_3_filter_t t3_filter; + dot11_tclas_fc_4_ipv4_t t4_ipv4; + dot11_tclas_fc_4_ipv6_t t4_ipv6; + dot11_tclas_fc_5_8021d_t t5_8021d; +} BWL_POST_PACKED_STRUCT; +typedef union dot11_tclas_fc dot11_tclas_fc_t; + +#define DOT11_TCLAS_FC_MIN_LEN 4 /* Classifier Type 2 has the min size */ +#define DOT11_TCLAS_FC_MAX_LEN 254 + +/** TCLAS element */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_ie { + uint8 id; /* 14, DOT11_MNG_TCLAS_ID */ + uint8 len; + uint8 user_priority; + dot11_tclas_fc_t fc; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_ie dot11_tclas_ie_t; +#define DOT11_TCLAS_IE_LEN 3u /* Fixed length, include id and len */ + +/** TCLAS processing element */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_proc_ie { + uint8 id; /* 44, DOT11_MNG_TCLAS_PROC_ID */ + uint8 len; + uint8 process; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_proc_ie dot11_tclas_proc_ie_t; +#define DOT11_TCLAS_PROC_IE_LEN 3 /* Fixed length, include id and len */ + +#define DOT11_TCLAS_PROC_LEN 1u /* Proc ie length is always 1 byte */ + +#define DOT11_TCLAS_PROC_MATCHALL 0 /* All high level element need to match */ +#define DOT11_TCLAS_PROC_MATCHONE 1 /* One high level element need to match */ +#define DOT11_TCLAS_PROC_NONMATCH 2 /* Non match to any high level element */ + +/* TSPEC element defined in 802.11 std section 8.4.2.32 - Not supported */ +#define DOT11_TSPEC_IE_LEN 57 /* Fixed length */ + +/** TCLAS Mask element */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_mask_ie { + uint8 id; /* DOT11_MNG_ID_EXT_ID (255) */ + uint8 len; + uint8 id_ext; /* TCLAS_EXTID_MNG_MASK_ID (89) */ + dot11_tclas_fc_t fc; /* Variable length frame classifier (fc) */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_mask_ie dot11_tclas_mask_ie_t; +#define DOT11_TCLAS_MASK_IE_LEN 1u /* Fixed length, excludes id and len */ +#define DOT11_TCLAS_MASK_IE_HDR_LEN 3u /* Fixed length */ + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11v_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmspi.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11w.h old mode 100755 new mode 100644 similarity index 53% rename from drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmspi.h rename to drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11w.h index bfdbab289c9a..1d46d71b7d9e --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmspi.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11w.h @@ -1,7 +1,8 @@ /* - * Broadcom SPI Low-Level Hardware Driver API + * Fundamental types and constants relating to 802.11w - + * "Protected Management Frames" * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -20,18 +21,30 @@ * * <> */ -#ifndef _BCM_SPI_H -#define _BCM_SPI_H -extern void spi_devintr_off(sdioh_info_t *sd); -extern void spi_devintr_on(sdioh_info_t *sd); -extern bool spi_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor); -extern bool spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode); -extern bool spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr); -extern bool spi_hw_attach(sdioh_info_t *sd); -extern bool spi_hw_detach(sdioh_info_t *sd); -extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen); -extern void spi_spinbits(sdioh_info_t *sd); -extern void spi_waitbits(sdioh_info_t *sd, bool yield); +#ifndef _802_11w_h_ +#define _802_11w_h_ -#endif /* _BCM_SPI_H */ +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +/** Management MIC ie */ +BWL_PRE_PACKED_STRUCT struct mmic_ie { + uint8 id; /* IE ID: DOT11_MNG_MMIE_ID */ + uint8 len; /* IE length */ + uint16 key_id; /* key id */ + uint8 ipn[6]; /* ipn */ + uint8 mic[16]; /* mic */ +} BWL_POST_PACKED_STRUCT; +typedef struct mmic_ie mmic_ie_t; + +#define DOT11_MMIC_IE_HDR_SIZE (OFFSETOF(mmic_ie_t, mic)) + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11w_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11wapi.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11wapi.h new file mode 100644 index 000000000000..4f0899078619 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11wapi.h @@ -0,0 +1,70 @@ +/* + * WAPI specific types and constants relating to 802.11 + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _802_11wapi_h_ +#define _802_11wapi_h_ + +#include <802.11.h> +#include + +#ifdef BCMWAPI_WPI +#define SMS4_KEY_LEN 16 +#define SMS4_WPI_CBC_MAC_LEN 16 +#endif + +#ifdef BCMWAPI_WAI +#define WAPI_IE_MIN_LEN 20 /* WAPI IE min length */ +#define WAPI_VERSION 1 /* WAPI version */ +#define WAPI_VERSION_LEN 2 /* WAPI version length */ +#define WAPI_OUI "\x00\x14\x72" /* WAPI OUI */ +#define WAPI_OUI_LEN DOT11_OUI_LEN /* WAPI OUI length */ + +#define WAPI_CIPHER_NONE WPA_CIPHER_NONE +#define WAPI_CIPHER_SMS4 11 + +#define WAPI_CSE_WPI_SMS4 1 + +#define IS_WAPI_CIPHER(cipher) ((cipher) == WAPI_CIPHER_NONE || \ + (cipher) == WAPI_CSE_WPI_SMS4) + +/* convert WAPI_CSE_WPI_XXX to WAPI_CIPHER_XXX */ +#define WAPI_CSE_WPI_2_CIPHER(cse) ((cse) == WAPI_CSE_WPI_SMS4 ? \ + WAPI_CIPHER_SMS4 : WAPI_CIPHER_NONE) + +#define WAPI_CIPHER_2_CSE_WPI(cipher) ((cipher) == WAPI_CIPHER_SMS4 ? \ + WAPI_CSE_WPI_SMS4 : WAPI_CIPHER_NONE) + +#define WAPI_CAP_PREAUTH RSN_CAP_PREAUTH + +/* Other WAI definition */ +#define WAPI_WAI_REQUEST 0x00F1 +#define WAPI_UNICAST_REKEY 0x00F2 +#define WAPI_STA_AGING 0x00F3 +#define WAPI_MUTIL_REKEY 0x00F4 +#define WAPI_STA_STATS 0x00F5 + +#define WAPI_USK_REKEY_COUNT 0x4000000 /* 0xA00000 */ +#define WAPI_MSK_REKEY_COUNT 0x4000000 /* 0xA00000 */ +#endif /* BCMWAPI_WAI */ + +#endif /* _802_11wapi_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11wfa.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11wfa.h new file mode 100644 index 000000000000..39d91e610963 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11wfa.h @@ -0,0 +1,245 @@ +/* + * WFA specific types and constants relating to 802.11 + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _802_11wfa_h_ +#define _802_11wfa_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +#ifndef _NET_ETHERNET_H_ +#include +#endif + +#include <802.11.h> + +/* This marks the start of a packed structure section. */ +#include + +/* WME Elements */ +#define WME_OUI "\x00\x50\xf2" /* WME OUI */ +#define WME_OUI_LEN 3 +#define WME_OUI_TYPE 2 /* WME type */ +#define WME_TYPE 2 /* WME type, deprecated */ +#define WME_SUBTYPE_IE 0 /* Information Element */ +#define WME_SUBTYPE_PARAM_IE 1 /* Parameter Element */ +#define WME_SUBTYPE_TSPEC 2 /* Traffic Specification */ +#define WME_VER 1 /* WME version */ + +/** WME Information Element (IE) */ +BWL_PRE_PACKED_STRUCT struct wme_ie { + uint8 oui[3]; + uint8 type; + uint8 subtype; + uint8 version; + uint8 qosinfo; +} BWL_POST_PACKED_STRUCT; +typedef struct wme_ie wme_ie_t; +#define WME_IE_LEN 7 /* WME IE length */ + +/** WME Parameter Element (PE) */ +BWL_PRE_PACKED_STRUCT struct wme_param_ie { + uint8 oui[3]; + uint8 type; + uint8 subtype; + uint8 version; + uint8 qosinfo; + uint8 rsvd; + edcf_acparam_t acparam[AC_COUNT]; +} BWL_POST_PACKED_STRUCT; +typedef struct wme_param_ie wme_param_ie_t; +#define WME_PARAM_IE_LEN 24 /* WME Parameter IE length */ + +/* QoS Info field for IE as sent from AP */ +#define WME_QI_AP_APSD_MASK 0x80 /* U-APSD Supported mask */ +#define WME_QI_AP_APSD_SHIFT 7 /* U-APSD Supported shift */ +#define WME_QI_AP_COUNT_MASK 0x0f /* Parameter set count mask */ +#define WME_QI_AP_COUNT_SHIFT 0 /* Parameter set count shift */ + +/* QoS Info field for IE as sent from STA */ +#define WME_QI_STA_MAXSPLEN_MASK 0x60 /* Max Service Period Length mask */ +#define WME_QI_STA_MAXSPLEN_SHIFT 5 /* Max Service Period Length shift */ +#define WME_QI_STA_APSD_ALL_MASK 0xf /* APSD all AC bits mask */ +#define WME_QI_STA_APSD_ALL_SHIFT 0 /* APSD all AC bits shift */ +#define WME_QI_STA_APSD_BE_MASK 0x8 /* APSD AC_BE mask */ +#define WME_QI_STA_APSD_BE_SHIFT 3 /* APSD AC_BE shift */ +#define WME_QI_STA_APSD_BK_MASK 0x4 /* APSD AC_BK mask */ +#define WME_QI_STA_APSD_BK_SHIFT 2 /* APSD AC_BK shift */ +#define WME_QI_STA_APSD_VI_MASK 0x2 /* APSD AC_VI mask */ +#define WME_QI_STA_APSD_VI_SHIFT 1 /* APSD AC_VI shift */ +#define WME_QI_STA_APSD_VO_MASK 0x1 /* APSD AC_VO mask */ +#define WME_QI_STA_APSD_VO_SHIFT 0 /* APSD AC_VO shift */ + +/* Default BE ACI value for non-WME connection STA */ +#define NON_EDCF_AC_BE_ACI_STA 0x02 + +/* WME Action Codes */ +#define WME_ADDTS_REQUEST 0 /* WME ADDTS request */ +#define WME_ADDTS_RESPONSE 1 /* WME ADDTS response */ +#define WME_DELTS_REQUEST 2 /* WME DELTS request */ + +/* WME Setup Response Status Codes */ +#define WME_ADMISSION_ACCEPTED 0 /* WME admission accepted */ +#define WME_INVALID_PARAMETERS 1 /* WME invalide parameters */ +#define WME_ADMISSION_REFUSED 3 /* WME admission refused */ + +/* ************* WPA definitions. ************* */ +#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ +#define WPA_OUI_LEN 3 /* WPA OUI length */ +#define WPA_OUI_TYPE 1 +#define WPA_VERSION 1 /* WPA version */ +#define WPA_VERSION_LEN 2 /* WPA version length */ + +/* ************* WPA2 definitions. ************* */ +#define WPA2_OUI "\x00\x0F\xAC" /* WPA2 OUI */ +#define WPA2_OUI_LEN 3 /* WPA2 OUI length */ +#define WPA2_VERSION 1 /* WPA2 version */ +#define WPA2_VERSION_LEN 2 /* WAP2 version length */ +#define MAX_RSNE_SUPPORTED_VERSION WPA2_VERSION /* Max supported version */ + +/* ************* WPS definitions. ************* */ +#define WPS_OUI "\x00\x50\xF2" /* WPS OUI */ +#define WPS_OUI_LEN 3 /* WPS OUI length */ +#define WPS_OUI_TYPE 4 + +/* ************* TPC definitions. ************* */ +#define TPC_OUI "\x00\x50\xF2" /* TPC OUI */ +#define TPC_OUI_LEN 3 /* TPC OUI length */ +#define TPC_OUI_TYPE 8 +#define WFA_OUI_TYPE_TPC 8 /* deprecated */ + +/* ************* WFA definitions. ************* */ +#define WFA_OUI "\x50\x6F\x9A" /* WFA OUI */ +#define WFA_OUI_LEN 3 /* WFA OUI length */ +#define WFA_OUI_TYPE_P2P 9 + +#define P2P_OUI WFA_OUI +#define P2P_OUI_LEN WFA_OUI_LEN +#define P2P_OUI_TYPE WFA_OUI_TYPE_P2P + +#ifdef WLTDLS +#define WFA_OUI_TYPE_TPQ 4 /* WFD Tunneled Probe ReQuest */ +#define WFA_OUI_TYPE_TPS 5 /* WFD Tunneled Probe ReSponse */ +#define WFA_OUI_TYPE_WFD 10 +#endif /* WTDLS */ +#define WFA_OUI_TYPE_HS20 0x10 +#define WFA_OUI_TYPE_OSEN 0x12 +#define WFA_OUI_TYPE_NAN 0x13 +#define WFA_OUI_TYPE_MBO 0x16 +#define WFA_OUI_TYPE_MBO_OCE 0x16 +#define WFA_OUI_TYPE_OWE 0x1C +#define WFA_OUI_TYPE_SAE_PK 0x1F +#define WFA_OUI_TYPE_TD_INDICATION 0x20 + +/* WCN */ +#define WCN_OUI "\x00\x50\xf2" /* WCN OUI */ +#define WCN_TYPE 4 /* WCN type */ + +/* ************* WMM Parameter definitions. ************* */ +#define WMM_OUI "\x00\x50\xF2" /* WNN OUI */ +#define WMM_OUI_LEN 3 /* WMM OUI length */ +#define WMM_OUI_TYPE 2 /* WMM OUT type */ +#define WMM_VERSION 1 +#define WMM_VERSION_LEN 1 + +/* WMM OUI subtype */ +#define WMM_OUI_SUBTYPE_PARAMETER 1 +#define WMM_PARAMETER_IE_LEN 24 + +#define SAE_PK_MOD_LEN 32u +BWL_PRE_PACKED_STRUCT struct dot11_sae_pk_element { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[WFA_OUI_LEN]; /* WFA_OUI */ + uint8 type; /* SAE-PK */ + uint8 data[SAE_PK_MOD_LEN]; /* Modifier. 32Byte fixed */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_sae_pk_element dot11_sae_pk_element_t; + +/* WPA3 Transition Mode bits */ +#define TRANSISION_MODE_WPA3_PSK BCM_BIT(0) +#define TRANSITION_MODE_WPA3_PSK BCM_BIT(0) +#define TRANSITION_MODE_SAE_PK BCM_BIT(1) +#define TRANSITION_MODE_WPA3_ENTERPRISE BCM_BIT(2) +#define TRANSITION_MODE_ENHANCED_OPEN BCM_BIT(3) + +#define TRANSITION_MODE_SUPPORTED_MASK (\ + TRANSITION_MODE_WPA3_PSK | \ + TRANSITION_MODE_SAE_PK | \ + TRANSITION_MODE_WPA3_ENTERPRISE | \ + TRANSITION_MODE_ENHANCED_OPEN) + +/** Transition Disable Indication element */ +BWL_PRE_PACKED_STRUCT struct dot11_tdi_element { + uint8 id; /* DOT11_MNG_VS_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; /* WFA_OUI */ + uint8 type; /* WFA_OUI_TYPE_TD_INDICATION */ + uint8 tdi; /* Transition Disable Indication bitmap */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tdi_element dot11_tdi_element_t; + +#define DOT11_TDI_ELEM_LENGTH sizeof(dot11_tdi_element_t) + +/* WiFi OWE transition OUI values */ +#define OWE_TRANS_OUI WFA_OUI /* WiFi OUI 50:6F:9A */ +/* oui_type field identifying the type and version of the OWE transition mode IE. */ +#define OWE_OUI_TYPE WFA_OUI_TYPE_OWE /* OUI Type/Version */ +/* IEEE 802.11 vendor specific information element. */ +#define OWE_IE_ID 0xdd + +/* 2.3.1 OWE transition mode IE (WFA OWE spec 1.1) */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_owe_ie_s { + uint8 id; /* IE ID: OWE_IE_ID 0xDD */ + uint8 len; /* IE length */ + uint8 oui[WFA_OUI_LEN]; /* OWE OUI 50:6F:9A */ + uint8 oui_type; /* WFA_OUI_TYPE_OWE 0x1A */ + uint8 attr[]; /* var len attributes */ +} wifi_owe_ie_t; + +/* owe transition mode ie */ +typedef BWL_PRE_PACKED_STRUCT struct owe_transition_mode_ie_s { + uint8 bssid[ETHER_ADDR_LEN]; /* Contains the BSSID of the other virtual AP */ + uint8 ssid_len; + uint8 *ssid; /* SSID of the other virtual AP */ + uint8 band_info; /* operating band info of the other virtual AP */ + uint8 chan; /* operating channel number of the other virtual AP */ +} BWL_POST_PACKED_STRUCT owe_transition_mode_ie_t; +#define OWE_IE_HDR_SIZE (OFFSETOF(wifi_owe_ie_t, attr)) +/* oui:3 bytes + oui type:1 byte */ +#define OWE_IE_NO_ATTR_LEN 4 + +/** hotspot2.0 indication element (vendor specific) */ +BWL_PRE_PACKED_STRUCT struct hs20_ie { + uint8 oui[3]; + uint8 type; + uint8 config; +} BWL_POST_PACKED_STRUCT; +typedef struct hs20_ie hs20_ie_t; +#define HS20_IE_LEN 5 /* HS20 IE length */ + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11wfa_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11z.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11z.h new file mode 100644 index 000000000000..125f4ccd1810 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.11z.h @@ -0,0 +1,142 @@ +/* + * Fundamental types and constants relating to 802.11z - + * "Extensions to Direct-Link Setup (DLS)" + * + * TDLS - Tunneled DLS + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _802_11z_h_ +#define _802_11z_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +#ifndef _NET_ETHERNET_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +#define DOT11_EXTCAP_LEN_TDLS 5 +#define DOT11_11AC_EXTCAP_LEN_TDLS 8 + +#define DOT11_EXTCAP_LEN_TDLS_WBW 8 + +/* TDLS Capabilities */ +#define DOT11_TDLS_CAP_TDLS 37 /* TDLS support */ +#define DOT11_TDLS_CAP_PU_BUFFER_STA 28 /* TDLS Peer U-APSD buffer STA support */ +#define DOT11_TDLS_CAP_PEER_PSM 20 /* TDLS Peer PSM support */ +#define DOT11_TDLS_CAP_CH_SW 30 /* TDLS Channel switch */ +#define DOT11_TDLS_CAP_PROH 38 /* TDLS prohibited */ +#define DOT11_TDLS_CAP_CH_SW_PROH 39 /* TDLS Channel switch prohibited */ +#define DOT11_TDLS_CAP_TDLS_WIDER_BW 61 /* TDLS Wider Band-Width */ + +#define TDLS_CAP_MAX_BIT 39 /* TDLS max bit defined in ext cap */ + +/** Timeout Interval IE */ +BWL_PRE_PACKED_STRUCT struct ti_ie { + uint8 ti_type; + uint32 ti_val; +} BWL_POST_PACKED_STRUCT; +typedef struct ti_ie ti_ie_t; +#define TI_TYPE_REASSOC_DEADLINE 1 +#define TI_TYPE_KEY_LIFETIME 2 + +/** Link Identifier Element */ +BWL_PRE_PACKED_STRUCT struct link_id_ie { + uint8 id; + uint8 len; + struct ether_addr bssid; + struct ether_addr tdls_init_mac; + struct ether_addr tdls_resp_mac; +} BWL_POST_PACKED_STRUCT; +typedef struct link_id_ie link_id_ie_t; +#define TDLS_LINK_ID_IE_LEN 18u + +/** Link Wakeup Schedule Element */ +BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie { + uint8 id; + uint8 len; + uint32 offset; /* in ms between TSF0 and start of 1st Awake Window */ + uint32 interval; /* in ms bwtween the start of 2 Awake Windows */ + uint32 awake_win_slots; /* in backof slots, duration of Awake Window */ + uint32 max_wake_win; /* in ms, max duration of Awake Window */ + uint16 idle_cnt; /* number of consecutive Awake Windows */ +} BWL_POST_PACKED_STRUCT; +typedef struct wakeup_sch_ie wakeup_sch_ie_t; +#define TDLS_WAKEUP_SCH_IE_LEN 18 + +/** Channel Switch Timing Element */ +BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie { + uint8 id; + uint8 len; + uint16 switch_time; /* in ms, time to switch channels */ + uint16 switch_timeout; /* in ms */ +} BWL_POST_PACKED_STRUCT; +typedef struct channel_switch_timing_ie channel_switch_timing_ie_t; +#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4 + +/** PTI Control Element */ +BWL_PRE_PACKED_STRUCT struct pti_control_ie { + uint8 id; + uint8 len; + uint8 tid; + uint16 seq_control; +} BWL_POST_PACKED_STRUCT; +typedef struct pti_control_ie pti_control_ie_t; +#define TDLS_PTI_CONTROL_IE_LEN 3 + +/** PU Buffer Status Element */ +BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie { + uint8 id; + uint8 len; + uint8 status; +} BWL_POST_PACKED_STRUCT; +typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; +#define TDLS_PU_BUFFER_STATUS_IE_LEN 1 +#define TDLS_PU_BUFFER_STATUS_AC_BK 1 +#define TDLS_PU_BUFFER_STATUS_AC_BE 2 +#define TDLS_PU_BUFFER_STATUS_AC_VI 4 +#define TDLS_PU_BUFFER_STATUS_AC_VO 8 + +/* TDLS Action Field Values */ +#define TDLS_SETUP_REQ 0 +#define TDLS_SETUP_RESP 1 +#define TDLS_SETUP_CONFIRM 2 +#define TDLS_TEARDOWN 3 +#define TDLS_PEER_TRAFFIC_IND 4 +#define TDLS_CHANNEL_SWITCH_REQ 5 +#define TDLS_CHANNEL_SWITCH_RESP 6 +#define TDLS_PEER_PSM_REQ 7 +#define TDLS_PEER_PSM_RESP 8 +#define TDLS_PEER_TRAFFIC_RESP 9 +#define TDLS_DISCOVERY_REQ 10 + +/* 802.11z TDLS Public Action Frame action field */ +#define TDLS_DISCOVERY_RESP 14 + +/* This marks the end of a packed structure section. */ +#include + +#endif /* _802_11z_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.1d.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.1d.h old mode 100755 new mode 100644 index a05bb28000b9..45a94c0f98a8 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.1d.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.1d.h @@ -1,7 +1,7 @@ /* * Fundamental types and constants relating to 802.1D * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.3.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.3.h old mode 100755 new mode 100644 index af9de3841d2f..263e9e793f9c --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.3.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/802.3.h @@ -1,7 +1,7 @@ /* * Fundamental constants relating to 802.3 * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/aidmp.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/aidmp.h old mode 100755 new mode 100644 index 57c60aea1400..d76c8881e8e1 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/aidmp.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/aidmp.h @@ -1,7 +1,7 @@ /* * Broadcom AMBA Interconnect definitions. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_fwtrace.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_fwtrace.h deleted file mode 100755 index ae0836a2ff37..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_fwtrace.h +++ /dev/null @@ -1,111 +0,0 @@ - -/* - * Firmware trace implementation common header file between DHD and the firmware. - * - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ - -#ifndef _bcm_fwtrace_h -#define _bcm_fwtrace_h - -#include -#include - -#define FWTRACE_VERSION 1u - -/* - * Number of trace entries per trace buffer. - * Both DHD and FW must use same number. - */ -#define FWTRACE_NUM_ENTRIES (2u * 1024u) /* 2KB, power of 2 */ -/* - * Number of buffers provided by the host. - * DHD may allocate smaller number of trace buffers based on continuous memory availability. - */ -#define FWTRACE_NUM_HOST_BUFFERS 32u - -/* Magic value to differentiate between regural trace data Vs other blobs */ -#define FWTRACE_BLOB_MAGIC (0xFFu) -#define FWTRACE_BLOB_MGIC_SHIFT (24u) - -/* The lower 24 bits of the fwtrace_entry->func_ptr is used to push different type of - * information to host such as ACK bitmap, interrupts DPC is going to process etc. - */ -#define FWTRACE_BLOB_TYPE_MASK (0xFFFFFFu) -#define FWTRACE_BLOB_TYPE_SHIFT (0) - -#define FWTRACE_BLOB_TYPE_NUM_PKTS (0x1u) -#define FWTRACE_BLOB_TYPE_ACK_BMAP1 (0x2u) /* Ack bits (0-31 ) */ -#define FWTRACE_BLOB_TYPE_ACK_BMAP2 (0x4u) /* Ack bits (32-63) */ -#define FWTRACE_BLOB_TYPE_ACK_BMAP3 (0x8u) /* Ack bits (64-95) */ -#define FWTRACE_BLOB_TYPE_ACK_BMAP4 (0x10u) /* Ack bits (96-127) */ -#define FWTRACE_BLOB_TYPE_INTR1 (0x20u) /* interrupts the DPC is going to process */ -#define FWTRACE_BLOB_TYPE_INTR2 (0x40u) /* interrupts the DPC is going to process */ -/* The blob data for LFRAGS_INFO will contain - * Bit31-16: Available buffer/lfrags info - * Bit15-0 : # of lfrags requested by FW in the fetch request - */ -#define FWTRACE_BLOB_TYPE_LFRAGS_INFO (0x80u) /* Available and fetch requested lfrags */ - -#define FWTRACE_BLOB_DATA_MASK (0xFFFFFu) - -#define FWTRACE_BLOB_ADD_CUR (0) /* updates with in the existing trace entry */ -#define FWTRACE_BLOB_ADD_NEW (1u) /* Creates new trace entry */ - -/* - * Host sends host memory location to FW via iovar. - * FW will push trace information here. - */ -typedef struct fwtrace_hostaddr_info { - bcm_addr64_t haddr; /* host address for the firmware to DMA trace data */ - uint32 buf_len; - uint32 num_bufs; /* Number of trace buffers */ -} fwtrace_hostaddr_info_t; - -/* - * Eact trace info buffer pushed to host will have this header. - */ -typedef struct fwtrace_dma_header_info { - uint16 length; /* length in bytes */ - uint16 seq_num; /* sequence number */ - uint32 version; - uint32 hostmem_addr; -} fwtrace_dma_header_info_t; - -/* - * Content of each trace entry - */ -typedef struct fwtrace_entry { - uint32 func_ptr; - /* How the pkts_cycle being used? - * Bit31-23: (If present) Used to indicate the number of packets processed by the - * current function - * Bit22-1 : Used to indicate the CPU cycles(in units of 2Cycles). So to get the actual - * cycles multiply the cycles by 2. - * Bit0 : Used to indicate whether this entry is valid or not - */ - uint32 pkts_cycles; -} fwtrace_entry_t; - -#define FWTRACE_CYCLES_VALID (1u << 0u) - -/* - * Format of firmware trace buffer pushed to host memory - */ -typedef struct fwtrace_buf { - fwtrace_dma_header_info_t info; /* includes the sequence number and the length */ - fwtrace_entry_t entry[FWTRACE_NUM_ENTRIES]; -} fwtrace_buf_t; - -void fwtracing_add_blob(uint32 update_type, uint32 trace_type, uint32 blob); -#endif /* _bcm_fwtrace_h */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_l2_filter.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_l2_filter.h deleted file mode 100755 index d594285fccca..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_l2_filter.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * L2 Filter handling functions - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - */ -#ifndef _l2_filter_h_ -#define _l2_filter_h_ - -/* Proxy ARP processing return values */ -#define PARP_DROP 0 -#define PARP_NOP 1 -#define PARP_TAKEN 2 -/* Adjust for ETHER_HDR_LEN pull in linux - * which makes pkt nonaligned - */ -#define ALIGN_ADJ_BUFLEN 2 - -#define BCM_PARP_TABLE_SIZE 32 /* proxyarp hash table bucket size */ -#define BCM_PARP_TABLE_MASK 0x1f /* proxyarp hash table index mask */ -#define BCM_PARP_TABLE_INDEX(val) (val & BCM_PARP_TABLE_MASK) -#define BCM_PARP_TIMEOUT 600 /* proxyarp cache entry timerout duration(10 min) */ - -#define BCM_PARP_IS_TIMEOUT(pub_tick, entry) \ - (pub_tick - entry->used > BCM_PARP_TIMEOUT) - -#define BCM_PARP_ANNOUNCE_WAIT 2 /* proxyarp announce wait duration(2 sec) */ - -#define BCM_PARP_ANNOUNCE_WAIT_REACH(pub_tick, entry) \ - (pub_tick - entry->used > BCM_PARP_ANNOUNCE_WAIT) - -#define BCM_ARP_TABLE_UPDATE_TIMEOUT 100 - -/* Taken from wlc_tdls.h for block_tdls iovar */ -#define TDLS_PAYLOAD_TYPE 2 -#define TDLS_PAYLOAD_TYPE_LEN 1 - -/* TDLS Action Category code */ -#define TDLS_ACTION_CATEGORY_CODE 12 - -typedef struct parp_entry { - struct parp_entry *next; - uint32 used; /* time stamp */ - struct ether_addr ea; - bcm_tlv_t ip; -} parp_entry_t; - -typedef struct arp_table arp_table_t; - -extern int bcm_l2_filter_gratuitous_arp(osl_t *osh, void *pktbuf); -extern int bcm_l2_filter_block_ping(osl_t *osh, void *pktbuf); -extern int bcm_l2_filter_get_mac_addr_dhcp_pkt(osl_t *osh, void *pktbuf, - int ifidx, uint8** addr); - -arp_table_t* init_l2_filter_arp_table(osl_t* osh); -void deinit_l2_filter_arp_table(osl_t* osh, arp_table_t* ptable); -int get_pkt_ether_type(osl_t *osh, void *skb, uint8 **data_ptr, - int *len_ptr, uint16 *et_ptr, bool *snap_ptr); -int get_pkt_ip_type(osl_t *osh, void *pktbuf, - uint8 **data_ptr, int *len_ptr, uint8 *prot_ptr); -int bcm_l2_filter_parp_addentry(osl_t *osh, arp_table_t* arp_tbl, struct ether_addr *ea, - uint8 *ip, uint8 ip_ver, bool cached, unsigned int entry_tickcnt); -int bcm_l2_filter_parp_delentry(osl_t *osh, arp_table_t* arp_tbl, struct ether_addr *ea, - uint8 *ip, uint8 ip_ver, bool cached); -parp_entry_t *bcm_l2_filter_parp_findentry(arp_table_t* arp_tbl, uint8 *ip, - uint8 ip_ver, bool cached, unsigned int entry_tickcnt); - -int bcm_l2_filter_parp_modifyentry(arp_table_t* arp_tbl, struct ether_addr *ea, - uint8 *ip, uint8 ip_ver, bool cached, unsigned int entry_tickcnt); -extern void bcm_l2_filter_arp_table_update(osl_t *osh, arp_table_t* arp_tbl, bool all, - uint8 *del_ea, bool periodic, unsigned int tickcnt); - -void *bcm_l2_filter_proxyarp_alloc_reply(osl_t* osh, uint16 pktlen, struct ether_addr *src_ea, - struct ether_addr *dst_ea, uint16 ea_type, bool snap, void **p); -void bcm_l2_filter_parp_get_smac(arp_table_t* ptable, void* smac); -void bcm_l2_filter_parp_get_cmac(arp_table_t* ptable, void* cmac); -void bcm_l2_filter_parp_set_smac(arp_table_t* ptable, void* smac); -void bcm_l2_filter_parp_set_cmac(arp_table_t* ptable, void* cmac); -bcm_tlv_t* parse_nd_options(void *buf, int buflen, uint key); -uint16 calc_checksum(uint8 *src_ipa, uint8 *dst_ipa, uint32 ul_len, uint8 prot, uint8 *ul_data); -extern int bcm_l2_filter_block_tdls(osl_t *osh, void *pktbuf); -#endif /* _l2_filter_h */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_mpool_pub.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_mpool_pub.h old mode 100755 new mode 100644 index 76c4ce8a7501..a19fc20052f0 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_mpool_pub.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_mpool_pub.h @@ -35,7 +35,7 @@ * and instrumentation on top of the heap, without modifying the heap * allocation implementation. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -169,10 +169,10 @@ int bcm_mpm_deinit(bcm_mpm_mgr_h *mgrp); */ int bcm_mpm_create_prealloc_pool(bcm_mpm_mgr_h mgr, unsigned int obj_sz, - int nobj, + uint nobj, void *memstart, unsigned int memsize, - const char poolname[BCM_MP_NAMELEN], + const char *poolname, bcm_mp_pool_h *newp); /* @@ -210,7 +210,7 @@ int bcm_mpm_delete_prealloc_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); * */ int bcm_mpm_create_heap_pool(bcm_mpm_mgr_h mgr, unsigned int obj_sz, - const char poolname[BCM_MP_NAMELEN], + const char *poolname, bcm_mp_pool_h *newp); /* diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_ring.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_ring.h old mode 100755 new mode 100644 index 0a454323402e..fc45bf48f3b2 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_ring.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcm_ring.h @@ -6,7 +6,7 @@ * * NOTE: A ring of size N, may only hold N-1 elements. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -429,7 +429,7 @@ bcm_ring_cons_avail(const bcm_ring_t *ring, const int ring_size) } else { cons_avail = ring->write - ring->read; } - ASSERT(cons_avail < ring_size); + ASSERT_FP(cons_avail < ring_size); return cons_avail; } diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmarp.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmarp.h old mode 100755 new mode 100644 index 2e6d92de5f46..21f5e2463ec4 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmarp.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmarp.h @@ -1,7 +1,7 @@ /* * Fundamental constants relating to ARP Protocol * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmbloom.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmbloom.h old mode 100755 new mode 100644 index dabfb26456de..a978d4d45d01 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmbloom.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmbloom.h @@ -1,7 +1,7 @@ /* * Bloom filter support * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmcdc.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmcdc.h old mode 100755 new mode 100644 index cc03c7a059eb..ed029055f990 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmcdc.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmcdc.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdefs.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdefs.h old mode 100755 new mode 100644 index 58e1ca37ea60..19b907f44225 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdefs.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdefs.h @@ -1,7 +1,7 @@ /* * Misc system wide definitions * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -24,11 +24,20 @@ #ifndef _bcmdefs_h_ #define _bcmdefs_h_ +#ifndef BCM_FLEX_ARRAY +#define BCM_FLEX_ARRAY (1) +#endif /* BCM_FLEX_ARRAY */ + /* * One doesn't need to include this file explicitly, gets included automatically if * typedefs.h is included. */ +/* For all the corerevs of the chip being built */ +#ifdef VLSI_COREREVS +#include /* auto-generated definitions from vlsi_data */ +#endif /* VLSI_COREREVS */ + /* Use BCM_REFERENCE to suppress warnings about intentionally-unused function * arguments or local variables. */ @@ -36,37 +45,60 @@ /* Allow for suppressing unused variable warnings. */ #ifdef __GNUC__ -#define UNUSED_VAR __attribute__ ((unused)) +#define BCM_UNUSED_VAR __attribute__ ((unused)) #else -#define UNUSED_VAR +#define BCM_UNUSED_VAR +#endif + +/* Allow for suppressing a warning for a switch case without break */ +#ifdef __GNUC__ +#define GCC_SUPPRESS_FALLTHROUGH_WARNING __attribute__ ((fallthrough)) +#else +#define GCC_SUPPRESS_FALLTHROUGH_WARNING #endif /* GNU GCC 4.6+ supports selectively turning off a warning. * Define these diagnostic macros to help suppress cast-qual warning * until all the work can be done to fix the casting issues. */ -#if (defined(__GNUC__) && defined(STRICT_GCC_WARNINGS) && \ - (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) || \ - defined(__clang__)) +#if (defined(__GNUC__) && defined(STRICT_GCC_WARNINGS) && (__GNUC__ > 4 || (__GNUC__ == \ + 4 && __GNUC_MINOR__ >= 6)) || defined(__clang__)) + #define GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST() \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") + #define GCC_DIAGNOSTIC_PUSH_SUPPRESS_NULL_DEREF() \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wnull-dereference\"") + +#if !defined(__clang__) || __clang_major__ >= 13 +#define GCC_DIAGNOSTIC_PUSH_SUPPRESS_FN_TYPE() \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wcast-function-type\"") +#else +#define GCC_DIAGNOSTIC_PUSH_SUPPRESS_FN_TYPE() \ + _Pragma("GCC diagnostic push") +#endif // !__clang__ || __clang_major__ >= 13 + #define GCC_DIAGNOSTIC_POP() \ _Pragma("GCC diagnostic pop") + #elif defined(_MSC_VER) + #define GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST() \ __pragma(warning(push)) \ __pragma(warning(disable:4090)) #define GCC_DIAGNOSTIC_PUSH_SUPPRESS_NULL_DEREF() \ __pragma(warning(push)) +#define GCC_DIAGNOSTIC_PUSH_SUPPRESS_FN_TYPE() \ + __pragma(warning(push)) #define GCC_DIAGNOSTIC_POP() \ __pragma(warning(pop)) #else #define GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST() #define GCC_DIAGNOSTIC_PUSH_SUPPRESS_NULL_DEREF() +#define GCC_DIAGNOSTIC_PUSH_SUPPRESS_FN_TYPE() #define GCC_DIAGNOSTIC_POP() #endif /* Diagnostic macros not defined */ @@ -104,9 +136,9 @@ */ #define STATIC_ASSERT(expr) { \ /* Make sure the expression is constant. */ \ - typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e UNUSED_VAR; \ + typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e BCM_UNUSED_VAR; \ /* Make sure the expression is true. */ \ - typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1] UNUSED_VAR; \ + typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1] BCM_UNUSED_VAR; \ } /* Reclaiming text and data : @@ -128,8 +160,8 @@ extern bool bcm_postattach_part_reclaimed; #define POSTATTACH_PART_RECLAIMED() (bcm_postattach_part_reclaimed) /* Place _fn/_data symbols in various reclaimed output sections */ -#define BCMATTACHDATA(_data) __attribute__ ((__section__ (".dataini2." #_data))) _data -#define BCMATTACHFN(_fn) __attribute__ ((__section__ (".textini2." #_fn), noinline)) _fn +#define _data __attribute__ ((__section__ (".dataini2." #_data))) _data +#define _fn __attribute__ ((__section__ (".textini2." #_fn), noinline)) _fn #define BCMPREATTACHDATA(_data) __attribute__ ((__section__ (".dataini3." #_data))) _data #define BCMPREATTACHFN(_fn) __attribute__ ((__section__ (".textini3." #_fn), noinline)) _fn #define BCMPOSTATTACHDATA(_data) __attribute__ ((__section__ (".dataini5." #_data))) _data @@ -142,6 +174,12 @@ extern bool bcm_postattach_part_reclaimed; /* Explicitly place data in .rodata section so it can be write-protected after attach */ #define BCMRODATA(_data) __attribute__ ((__section__ (".shrodata." #_data))) _data +#ifdef _WIN32 +#define BCMSIZEOFDATA(_data) _data +#else +#define BCMSIZEOFDATA(_data) __attribute__ ((__section__ (".shrodata." #_data))) _data +#endif + #ifdef BCMDBG_SR /* * Don't reclaim so we can compare SR ASM @@ -153,20 +191,33 @@ extern bool bcm_postattach_part_reclaimed; #else #define BCMPREATTACHDATASR(_data) BCMPREATTACHDATA(_data) #define BCMPREATTACHFNSR(_fn) BCMPREATTACHFN(_fn) -#define BCMATTACHDATASR(_data) BCMATTACHDATA(_data) -#define BCMATTACHFNSR(_fn) BCMATTACHFN(_fn) +#define BCMATTACHDATASR(_data) _data +#define BCMATTACHFNSR(_fn) _fn #endif -#define BCMINITDATA(_data) _data -#define BCMINITFN(_fn) _fn +/* In case of coex cpu reinit, we should not relcaim the functions that are needed for reinit */ +#if defined(COEX_CPU_REINIT) && !defined(COEX_CPU_REINIT_DISABLED) +#define BCMCOEXCPUATTACHDATA(_data) _data +#define BCMCOEXCPUATTACHFN(_fn) _fn +#define BCMCOEXCPUPREATTACHDATA(_data) _data +#define BCMCOEXCPUPREATTACHFN(_fn) _fn +#else +#define BCMCOEXCPUATTACHDATA(_data) _data +#define BCMCOEXCPUATTACHFN(_fn) _fn +#define BCMCOEXCPUPREATTACHDATA(_data) BCMPREATTACHDATA(_data) +#define BCMCOEXCPUPREATTACHFN(_fn) BCMPREATTACHFN(_fn) +#endif /* COEX_CPU_REINIT && !COEX_CPU_REINIT_DISABLED */ + +#define _data _data +#define _fn _fn #ifndef CONST #define CONST const #endif /* Non-manufacture or internal attach function/dat */ #if !(defined(WLTEST) || defined(ATE_BUILD)) -#define BCMNMIATTACHFN(_fn) BCMATTACHFN(_fn) -#define BCMNMIATTACHDATA(_data) BCMATTACHDATA(_data) +#define BCMNMIATTACHFN(_fn) _fn +#define BCMNMIATTACHDATA(_data) _data #else #define BCMNMIATTACHFN(_fn) _fn #define BCMNMIATTACHDATA(_data) _data @@ -197,27 +248,32 @@ extern bool bcm_postattach_part_reclaimed; #define BCMSROMCISDUMPATTACHDATA(_data) BCMSROMATTACHDATA(_data) #endif /* BCM_CISDUMP_NO_RECLAIM */ -#define BCMUNINITFN(_fn) _fn +#define _fn _fn #else /* BCM_RECLAIM */ -#define bcm_reclaimed (1) -#define bcm_attach_part_reclaimed (1) -#define bcm_preattach_part_reclaimed (1) -#define bcm_postattach_part_reclaimed (1) -#define BCMATTACHDATA(_data) _data -#define BCMATTACHFN(_fn) _fn +#define bcm_reclaimed (TRUE) +#define bcm_attach_part_reclaimed (TRUE) +#define bcm_preattach_part_reclaimed (TRUE) +#define bcm_postattach_part_reclaimed (TRUE) +#define _data _data +#define _fn _fn #define BCM_SRM_ATTACH_DATA(_data) _data #define BCM_SRM_ATTACH_FN(_fn) _fn /* BCMRODATA data is written into at attach time so it cannot be in .rodata */ #define BCMRODATA(_data) __attribute__ ((__section__ (".data." #_data))) _data +#ifdef _WIN32 +#define BCMSIZEOFDATA(_data) _data +#else +#define BCMSIZEOFDATA(_data) __attribute__ ((__section__ (".data." #_data))) _data +#endif #define BCMPREATTACHDATA(_data) _data #define BCMPREATTACHFN(_fn) _fn #define BCMPOSTATTACHDATA(_data) _data #define BCMPOSTATTACHFN(_fn) _fn -#define BCMINITDATA(_data) _data -#define BCMINITFN(_fn) _fn -#define BCMUNINITFN(_fn) _fn +#define _data _data +#define _fn _fn +#define _fn _fn #define BCMNMIATTACHFN(_fn) _fn #define BCMNMIATTACHDATA(_data) _data #define BCMSROMATTACHFN(_fn) _fn @@ -241,12 +297,13 @@ extern bool bcm_postattach_part_reclaimed; #endif /* BCM_RECLAIM */ -#define BCMUCODEDATA(_data) BCMINITDATA(_data) +#define BCMUCODEDATA(_data) _data -#if defined(BCM_AQM_DMA_DESC) && !defined(BCM_AQM_DMA_DESC_DISABLED) && !defined(DONGLEBUILD) -#define BCMUCODEFN(_fn) BCMINITFN(_fn) +#if defined(BCM_AQM_DMA_DESC) && !defined(BCM_AQM_DMA_DESC_DISABLED) && \ + !defined(DONGLEBUILD) +#define BCMUCODEFN(_fn) _fn #else -#define BCMUCODEFN(_fn) BCMATTACHFN(_fn) +#define BCMUCODEFN(_fn) _fn #endif /* BCM_AQM_DMA_DESC */ /* This feature is for dongle builds only. @@ -364,6 +421,9 @@ extern bool bcm_postattach_part_reclaimed; #ifdef BCMPCIEREV #define PCIECOREREV(rev) (BCMPCIEREV) +#elif defined(BCMPCIEGEN2REV) +#define BCMPCIEREV (BCMPCIEGEN2REV) +#define PCIECOREREV(rev) (BCMPCIEGEN2REV) #else #define PCIECOREREV(rev) (rev) #endif @@ -374,8 +434,17 @@ extern bool bcm_postattach_part_reclaimed; #define PMUREV(rev) (rev) #endif +#ifdef BCMSDTCREV +#define SDTCREV(rev) (BCMSDTCREV) +#else +#define SDTCREV(rev) (rev) +#endif + #ifdef BCMCCREV #define CCREV(rev) (BCMCCREV) +#elif defined(BCMCHIPCOMMONREV) +#define BCMCCREV (BCMCHIPCOMMONREV) +#define CCREV(rev) (BCMCHIPCOMMONREV) #else #define CCREV(rev) (rev) #endif @@ -394,14 +463,29 @@ extern bool bcm_postattach_part_reclaimed; #define CR4REV_GE(rev, val) ((rev) >= (val)) #endif +#ifdef BCMARMCA7REV +#define CA7REV(rev) (BCMARMCA7REV) +#define CA7REV_GE(rev, val) ((BCMARMCA7REV) >= (val)) +#else +#define CA7REV(rev) (rev) +#define CA7REV_GE(rev, val) ((rev) >= (val)) +#endif + #ifdef BCMLHLREV #define LHLREV(rev) (BCMLHLREV) #else #define LHLREV(rev) (rev) #endif +#if defined(BCMHND_OOBRREV) && !defined(BCMHNDOOBRREV) +#define BCMHNDOOBRREV BCMHND_OOBRREV +#endif + #ifdef BCMSPMISREV #define SPMISREV(rev) (BCMSPMISREV) +#elif defined(BCMSPMI_SLAVEREV) +#define BCMSPMISREV (BCMSPMI_SLAVEREV) +#define SPMISREV(rev) (BCMSPMI_SLAVEREV) #else #define SPMISREV(rev) (rev) #endif @@ -434,6 +518,8 @@ typedef struct { (_pa).loaddr = (_val); \ } while (0) +#define PHYSADDR64ISZERO(_pa) (PHYSADDR64LO(_pa) == 0 && PHYSADDR64HI(_pa) == 0) + #ifdef BCMDMA64OSL typedef dma64addr_t dmaaddr_t; #define PHYSADDRHI(_pa) PHYSADDR64HI(_pa) @@ -571,12 +657,12 @@ typedef struct { #if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) #define BCM_SH_SFLASH_ENAB() (_bcm_sh_sflash) #elif defined(BCM_SH_SFLASH_DISABLED) - #define BCM_SH_SFLASH_ENAB() (0) + #define BCM_SH_SFLASH_ENAB() (FALSE) #else - #define BCM_SH_SFLASH_ENAB() (1) + #define BCM_SH_SFLASH_ENAB() (TRUE) #endif #else - #define BCM_SH_SFLASH_ENAB() (0) + #define BCM_SH_SFLASH_ENAB() (FALSE) #endif /* BCM_SH_SFLASH */ #ifdef BCM_SFLASH @@ -584,12 +670,12 @@ typedef struct { #if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) #define BCM_SFLASH_ENAB() (_bcm_sflash) #elif defined(BCM_SFLASH_DISABLED) - #define BCM_SFLASH_ENAB() (0) + #define BCM_SFLASH_ENAB() (FALSE) #else - #define BCM_SFLASH_ENAB() (1) + #define BCM_SFLASH_ENAB() (TRUE) #endif #else - #define BCM_SFLASH_ENAB() (0) + #define BCM_SFLASH_ENAB() (FALSE) #endif /* BCM_SFLASH */ #ifdef BCM_DELAY_ON_LTR @@ -597,12 +683,12 @@ typedef struct { #if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) #define BCM_DELAY_ON_LTR_ENAB() (_bcm_delay_on_ltr) #elif defined(BCM_DELAY_ON_LTR_DISABLED) - #define BCM_DELAY_ON_LTR_ENAB() (0) + #define BCM_DELAY_ON_LTR_ENAB() (FALSE) #else - #define BCM_DELAY_ON_LTR_ENAB() (1) + #define BCM_DELAY_ON_LTR_ENAB() (TRUE) #endif #else - #define BCM_DELAY_ON_LTR_ENAB() (0) + #define BCM_DELAY_ON_LTR_ENAB() (FALSE) #endif /* BCM_DELAY_ON_LTR */ /* Max. nvram variable table size */ @@ -631,12 +717,12 @@ typedef struct { #if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) #define BCMLFRAG_ENAB() (_bcmlfrag) #elif defined(BCMLFRAG_DISABLED) - #define BCMLFRAG_ENAB() (0) + #define BCMLFRAG_ENAB() (FALSE) #else - #define BCMLFRAG_ENAB() (1) + #define BCMLFRAG_ENAB() (TRUE) #endif #else - #define BCMLFRAG_ENAB() (0) + #define BCMLFRAG_ENAB() (FALSE) #endif /* BCMLFRAG_ENAB */ #ifdef BCMPCIEDEV /* BCMPCIEDEV support enab macros */ @@ -644,12 +730,12 @@ extern bool _pciedevenab; #if defined(ROM_ENAB_RUNTIME_CHECK) #define BCMPCIEDEV_ENAB() (_pciedevenab) #elif defined(BCMPCIEDEV_ENABLED) - #define BCMPCIEDEV_ENAB() 1 + #define BCMPCIEDEV_ENAB() (TRUE) #else - #define BCMPCIEDEV_ENAB() 0 + #define BCMPCIEDEV_ENAB() (FALSE) #endif #else - #define BCMPCIEDEV_ENAB() 0 + #define BCMPCIEDEV_ENAB() (FALSE) #endif /* BCMPCIEDEV */ #ifdef BCMRESVFRAGPOOL /* BCMRESVFRAGPOOL support enab macros */ @@ -657,12 +743,12 @@ extern bool _resvfragpool_enab; #if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) #define BCMRESVFRAGPOOL_ENAB() (_resvfragpool_enab) #elif defined(BCMRESVFRAGPOOL_DISABLED) - #define BCMRESVFRAGPOOL_ENAB() (0) + #define BCMRESVFRAGPOOL_ENAB() (FALSE) #else - #define BCMRESVFRAGPOOL_ENAB() (1) + #define BCMRESVFRAGPOOL_ENAB() (TRUE) #endif #else - #define BCMRESVFRAGPOOL_ENAB() 0 + #define BCMRESVFRAGPOOL_ENAB() (FALSE) #endif /* BCMPCIEDEV */ #ifdef BCMSDIODEV /* BCMSDIODEV support enab macros */ @@ -670,25 +756,30 @@ extern bool _sdiodevenab; #if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) #define BCMSDIODEV_ENAB() (_sdiodevenab) #elif defined(BCMSDIODEV_ENABLED) - #define BCMSDIODEV_ENAB() 1 + #define BCMSDIODEV_ENAB() (TRUE) #else - #define BCMSDIODEV_ENAB() 0 + #define BCMSDIODEV_ENAB() (FALSE) #endif #else - #define BCMSDIODEV_ENAB() 0 + #define BCMSDIODEV_ENAB() (FALSE) #endif /* BCMSDIODEV */ #ifdef BCMSPMIS extern bool _bcmspmi_enab; +extern bool _bcmspmi_plat_enab; #if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) #define BCMSPMIS_ENAB() (_bcmspmi_enab) + #define BCMSPMIS_PLAT_ENAB() (_bcmspmi_plat_enab) #elif defined(BCMSPMIS_DISABLED) - #define BCMSPMIS_ENAB() 0 + #define BCMSPMIS_ENAB() (FALSE) + #define BCMSPMIS_PLAT_ENAB() (FALSE) #else - #define BCMSPMIS_ENAB() 1 + #define BCMSPMIS_ENAB() (TRUE) + #define BCMSPMIS_PLAT_ENAB() (_bcmspmi_plat_enab) #endif #else - #define BCMSPMIS_ENAB() 0 + #define BCMSPMIS_ENAB() (FALSE) + #define BCMSPMIS_PLAT_ENAB() (FALSE) #endif /* BCMSPMIS */ #ifdef BCMDVFS /* BCMDVFS support enab macros */ @@ -696,12 +787,12 @@ extern bool _dvfsenab; #if defined(ROM_ENAB_RUNTIME_CHECK) #define BCMDVFS_ENAB() (_dvfsenab) #elif !defined(BCMDVFS_DISABLED) - #define BCMDVFS_ENAB() (1) + #define BCMDVFS_ENAB() (TRUE) #else - #define BCMDVFS_ENAB() (0) + #define BCMDVFS_ENAB() (FALSE) #endif #else - #define BCMDVFS_ENAB() (0) + #define BCMDVFS_ENAB() (FALSE) #endif /* BCMDVFS */ /* Max size for reclaimable NVRAM array */ @@ -717,30 +808,19 @@ extern bool _dvfsenab; extern uint32 gFWID; -#ifdef BCMFRWDPKT /* BCMFRWDPKT support enab macros */ - extern bool _bcmfrwdpkt; -#if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) - #define BCMFRWDPKT_ENAB() (_bcmfrwdpkt) -#elif defined(BCMFRWDPKT_DISABLED) - #define BCMFRWDPKT_ENAB() (0) -#else - #define BCMFRWDPKT_ENAB() (1) -#endif -#else - #define BCMFRWDPKT_ENAB() (0) -#endif /* BCMFRWDPKT */ + #define BCMFRWDPKT_ENAB() (FALSE) #ifdef BCMFRWDPOOLREORG /* BCMFRWDPOOLREORG support enab macros */ extern bool _bcmfrwdpoolreorg; #if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) #define BCMFRWDPOOLREORG_ENAB() (_bcmfrwdpoolreorg) #elif defined(BCMFRWDPOOLREORG_DISABLED) - #define BCMFRWDPOOLREORG_ENAB() (0) + #define BCMFRWDPOOLREORG_ENAB() (FALSE) #else - #define BCMFRWDPOOLREORG_ENAB() (1) + #define BCMFRWDPOOLREORG_ENAB() (TRUE) #endif #else - #define BCMFRWDPOOLREORG_ENAB() (0) + #define BCMFRWDPOOLREORG_ENAB() (FALSE) #endif /* BCMFRWDPOOLREORG */ #ifdef BCMPOOLRECLAIM /* BCMPOOLRECLAIM support enab macros */ @@ -748,14 +828,53 @@ extern uint32 gFWID; #if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) #define BCMPOOLRECLAIM_ENAB() (_bcmpoolreclaim) #elif defined(BCMPOOLRECLAIM_DISABLED) - #define BCMPOOLRECLAIM_ENAB() (0) + #define BCMPOOLRECLAIM_ENAB() (FALSE) #else - #define BCMPOOLRECLAIM_ENAB() (1) + #define BCMPOOLRECLAIM_ENAB() (TRUE) #endif #else - #define BCMPOOLRECLAIM_ENAB() (0) + #define BCMPOOLRECLAIM_ENAB() (FALSE) #endif /* BCMPOOLRECLAIM */ +#ifdef BCMRXDATAPOOL /* BCMRXDATAPOOL support enab macros */ + extern bool _bcmrxdatapool; +#if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define BCMRXDATAPOOL_ENAB() (_bcmrxdatapool) +#elif defined(BCMRXDATAPOOL_DISABLED) + #define BCMRXDATAPOOL_ENAB() (FALSE) +#else + #define BCMRXDATAPOOL_ENAB() (TRUE) +#endif +#else + #define BCMRXDATAPOOL_ENAB() (FALSE) +#endif /* BCMRXDATAPOOL */ + +#ifdef URB /* URB support enab macros */ + extern bool _urb_enab; +#if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define URB_ENAB() (_urb_enab) +#elif defined(URB_DISABLED) + #define URB_ENAB() (FALSE) +#else + #define URB_ENAB() (TRUE) +#endif +#else + #define URB_ENAB() (FALSE) +#endif /* URB */ + +#ifdef TX_HISTOGRAM +extern bool _tx_histogram_enabled; +#if defined(ROM_ENAB_RUNTIME_CHECK) + #define TX_HISTOGRAM_ENAB() (_tx_histogram_enabled) +#elif defined(TX_HISTOGRAM_DISABLED) + #define TX_HISTOGRAM_ENAB() (FALSE) +#else + #define TX_HISTOGRAM_ENAB() (TRUE) +#endif +#else + #define TX_HISTOGRAM_ENAB() (FALSE) +#endif /* TX_HISTOGRAM */ + /* Chip related low power flags (lpflags) */ #ifndef PAD @@ -764,22 +883,20 @@ extern uint32 gFWID; #define PAD _XSTR(__LINE__) #endif -#if defined(DONGLEBUILD) && ! defined(__COVERITY__) -#define MODULE_DETACH(var, detach_func)\ +#if defined(DONGLEBUILD) && !defined(__COVERITY__) +#define MODULE_DETACH(var, detach_func) \ + do { \ + BCM_REFERENCE(detach_func); \ + OSL_SYS_HALT(); \ + } while (0); +#define MODULE_DETACH_2(var1, var2, detach_func) \ do { \ BCM_REFERENCE(detach_func); \ OSL_SYS_HALT(); \ } while (0); -#define MODULE_DETACH_2(var1, var2, detach_func) MODULE_DETACH(var1, detach_func) -#define MODULE_DETACH_TYPECASTED(var, detach_func) #else -#define MODULE_DETACH(var, detach_func)\ - if (var) { \ - detach_func(var); \ - (var) = NULL; \ - } +#define MODULE_DETACH(var, detach_func) detach_func(var) #define MODULE_DETACH_2(var1, var2, detach_func) detach_func(var1, var2) -#define MODULE_DETACH_TYPECASTED(var, detach_func) detach_func(var) #endif /* DONGLEBUILD */ /* When building ROML image use runtime conditional to cause the compiler @@ -797,21 +914,20 @@ extern uint32 gFWID; #endif /* For ROM builds, keep it in const section so that it gets ROMmed. If abandoned, move it to - * RO section but before ro region start so that FATAL log buf doesn't use this. + * RO section but after the other ro data so that FATAL log buf doesn't use this. */ -// Temporary - leave old definition in place until all references are removed elsewhere -#if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) -#define BCMRODATA_ONTRAP(_data) _data -#else -#define BCMRODATA_ONTRAP(_data) __attribute__ ((__section__ (".ro_ontrap." #_data))) _data -#endif -// Renamed for consistency with post trap function definition #if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) #define BCMPOST_TRAP_RODATA(_data) _data #else #define BCMPOST_TRAP_RODATA(_data) __attribute__ ((__section__ (".ro_ontrap." #_data))) _data #endif +#if defined(BCMROMBUILD) +#define BCMPOST_TRAP_RAM_RODATA(data) BCMRAMDATA(data) +#else +#define BCMPOST_TRAP_RAM_RODATA(data) BCMPOST_TRAP_RODATA(data) +#endif + /* Similar to RO data on trap, we want code that's used after a trap to be placed in a special area * as this means we can use all of the rest of the .text for post trap dumps. Functions with * the BCMPOSTTRAPFN macro applied will either be in ROM or this protected area. @@ -829,15 +945,22 @@ extern uint32 gFWID; #else #if defined(DONGLEBUILD) #define BCMPOSTTRAPFN(_fn) __attribute__ ((__section__ (".text_posttrap." #_fn))) _fn +#define BCMPOSTTRAPFASTPATH(_fn) __attribute__ ((__section__ (".text_posttrapfp." #_fn))) _fn #else #define BCMPOSTTRAPFN(_fn) _fn +#define BCMPOSTTRAPFASTPATH(_fn) _fn #endif /* DONGLEBUILD */ #define BCMPOSTTRAPRAMFN(fn) BCMPOSTTRAPFN(fn) -#define BCMPOSTTRAPFASTPATH(fn) BCMPOSTTRAPFN(fn) #endif /* ROMBUILD */ typedef struct bcm_rng * bcm_rng_handle_t; +/* Explicitly locate initialized data and uninitialized data (bss) in memory regions that + * are NOT write-protected by the BUS-MPU. + */ +#define BCM_BMPU_RW_DATA(_data) __attribute__ ((__section__ (".data_bmpu_rw." #_data))) _data +#define BCM_BMPU_RW_BSS(_data) __attribute__ ((__section__ (".bss_bmpu_rw." #_data))) _data + /* Use BCM_FUNC_PTR() to tag function pointers for ASLR code implementation. It will perform * run-time relocation of a function pointer by translating it from a physical to virtual address. * @@ -877,8 +1000,8 @@ void* BCM_ASLR_CODE_FNPTR_RELOCATOR(void *func_ptr); #define WLBANDINITDATA(_data) _data #define WLBANDINITFN(_fn) _fn #else -#define WLBANDINITDATA(_data) BCMINITDATA(_data) -#define WLBANDINITFN(_fn) BCMINITFN(_fn) +#define WLBANDINITDATA(_data) _data +#define WLBANDINITFN(_fn) _fn #endif /* Tag struct members to make it explicitly clear that they are physical addresses. These are @@ -891,6 +1014,33 @@ void* BCM_ASLR_CODE_FNPTR_RELOCATOR(void *func_ptr); #define PHYS_ADDR_N(name) name #endif +/* As we modify struct sizes during the natural course of development, existing + * ROM functions that malloc, memset, bzero or memcpy such structs using the + * sizeof operator are invalidated. Such functions are rarely patchable. Here we + * mitigate this. A struct's size, computed at compile time, is to be stored in + * a constant to which a macro then refers. + */ +#ifdef ROM_ENAB_RUNTIME_CHECK +#define SIZEOF_MACRO_USE +#endif /* ROM_ENAB_RUNTIME_CHECK */ +#ifdef SIZEOF_MACRO_USE +#define VAR_SIZEOF(t) static uint16 BCMSIZEOFDATA(sizeof_##t) = sizeof(t) +#define VAR_SIZEOF_STRUCT(t) static uint16 BCMSIZEOFDATA(sizeof_##t) = sizeof(struct t) +#define SIZEOF_DYN(t) (sizeof_##t) +#define SIZEOF_STRUCT_DYN(t) SIZEOF_DYN(t) +#else /* SIZEOF_MACRO_USE */ +#define VAR_SIZEOF(t) +#define VAR_SIZEOF_STRUCT(t) +#define SIZEOF_DYN(t) (sizeof(t)) +#define SIZEOF_STRUCT_DYN(t) (sizeof(struct t)) +#endif /* SIZEOF_MACRO_USE */ + +/* Disable function inlining. */ +#define BCM_NOINLINE __attribute__ ((noinline)) + +/* Disable compiler optimizations for a function. */ +#define BCM_NO_OPTIMIZE __attribute__ ((optimize(0))) + /* * A compact form for a list of valid register address offsets. * Used for when dumping the contents of the register set for the user. @@ -906,4 +1056,8 @@ typedef struct _regs_bmp_list { uint8 bmp_cnt[4]; /* bit[31]=1, bit[30:0] is count else it is a bitmap */ } regs_list_t; +#ifndef WL_UNITTEST +typedef union d11rxhdr d11rxhdr_t; +#endif /* WL_UNITTEST */ + #endif /* _bcmdefs_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h old mode 100755 new mode 100644 index 87a884c0f97b..8dddde5024ae --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h @@ -1,7 +1,7 @@ /* * Broadcom device-specific manifest constants. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -41,13 +41,6 @@ #define VENDOR_RICOH 0x1180 /* Ricoh */ #define VENDOR_JMICRON 0x197b -/* precommit failed when this is removed */ -/* BLAZAR_BRANCH_101_10_DHD_001/build/dhd/linux-fc19/brix-brcm */ -/* TBD: Revisit later */ -#ifdef BCMINTERNAL -#define VENDOR_JINVANI 0x1947 /* Jinvani Systech, Inc. */ -#endif - /* PCMCIA vendor IDs */ #define VENDOR_BROADCOM_PCMCIA 0x02d0 @@ -59,6 +52,7 @@ #define BCM_DNGL_BL_PID_4328 0xbd12 #define BCM_DNGL_BL_PID_4332 0xbd18 #define BCM_DNGL_BL_PID_4360 0xbd1d +#define BCM_DNGL_BL_PID_4381 0xbd2a #define BCM_DNGL_BDC_PID 0x0bdc #define BCM_DNGL_JTAG_PID 0x4a44 @@ -135,6 +129,10 @@ #define BCM4378_D11AX2G_ID 0x4426 /* 4378 802.11ax 2.4G device */ #define BCM4378_D11AX5G_ID 0x4427 /* 4378 802.11ax 5G device */ +#define BCM4381_D11AX_ID 0x4446 /* 4381 802.11ax dualband device */ +#define BCM4382_D11AX_ID 0x4447 /* 4382 802.11ax dualband device */ +#define BCM43852_D11AX_ID 0x4448 /* 43852 802.11ax dualband device */ + #define BCM4387_D11AX_ID 0x4433 /* 4387 802.11ax dualband device */ #define BCM4388_D11AX_ID 0x4434 /* 4388 802.11ax dualband device */ #define BCM4385_D11AX_ID 0x4442 /* 4385 802.11ax dualband device */ @@ -151,6 +149,12 @@ #define BCM43752_D11AX2G_ID 0x449e /* 43752 802.11ax 2.4G device */ #define BCM43752_D11AX5G_ID 0x449f /* 43752 802.11ax 5G device */ +#define BCM43756_D11AX_ID 0x44a0 /* 43756 802.11ax dualband device */ + +#define BCM43711_D11AX6E_ID 0x44b0 /* 43711 802.11ax dualband device */ +#define BCM43711_D11AC_ID 0x44b1 /* 43711 802.11ax 2.4G device */ +#define BCM43711_D11AX_ID 0x44b2 /* 43711 802.11ax 5G device */ + /* TBD change below values */ #define BCM4369_D11AX_ID 0x4470 /* 4369 802.11ax dualband device */ #define BCM4369_D11AX2G_ID 0x4471 /* 4369 802.11ax 2.4G device */ @@ -171,7 +175,8 @@ #define BCM43143_CHIP_ID 43143 /* 43143 chipcommon chipid */ #define BCM43242_CHIP_ID 43242 /* 43242 chipcommon chipid */ -#define BCM43460_CHIP_ID 43460 /* 4360 chipcommon chipid (OTP, RBBU) */ +#define BCM43430_CHIP_ID 43430 /* 43430 chipcommon chipid */ +#define BCM43460_CHIP_ID 43460 /* 4360 chipcommon chipid (OTP, RBBU) */ #define BCM4360_CHIP_ID 0x4360 /* 4360 chipcommon chipid */ #define BCM43362_CHIP_ID 43362 /* 43362 chipcommon chipid */ #define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */ @@ -197,22 +202,38 @@ #define BCM4345_CHIP_ID 0x4345 /* 4345 chipcommon chipid */ #define BCM43454_CHIP_ID 43454 /* 43454 chipcommon chipid */ -#define BCM43430_CHIP_ID 43430 /* 43430 chipcommon chipid */ #define BCM4359_CHIP_ID 0x4359 /* 4359 chipcommon chipid */ #define BCM4362_CHIP_ID 0x4362 /* 4362 chipcommon chipid */ #define BCM43751_CHIP_ID 0xAAE7 /* 43751 chipcommon chipid */ #define BCM43752_CHIP_ID 0xAAE8 /* 43752 chipcommon chipid */ +#define BCM43756_CHIP_ID 0xAAEC /* 43756 chipcommon chipid */ +#define BCM43711_CHIP_ID 0xAABF /* 43711 chipcommon chipid */ #define BCM4369_CHIP_ID 0x4369 /* 4369 chipcommon chipid */ #define BCM4377_CHIP_ID 0x4377 /* 4377 chipcommon chipid */ #define BCM4378_CHIP_ID 0x4378 /* 4378 chipcommon chipid */ +#define BCM4381_CHIP_ID 0x4381 /* 4381 chipcommon chipid */ +#define BCM4382_CHIP_ID 0x4382 /* 4382 chipcommon chipid */ +#define BCM43852_CHIP_ID 0xAB4C /* 43852 chipcommon chipid */ #define BCM4385_CHIP_ID 0x4385 /* 4385 chipcommon chipid */ #define BCM4387_CHIP_ID 0x4387 /* 4387 chipcommon chipid */ #define BCM4388_CHIP_ID 0x4388 /* 4388 chipcommon chipid */ #define BCM4389_CHIP_ID 0x4389 /* 4389 chipcommon chipid */ #define BCM4397_CHIP_ID 0x4397 /* 4397 chipcommon chipid */ -#define BCM4362_CHIP(chipid) (CHIPID(chipid) == BCM4362_CHIP_ID) -#define BCM4362_CHIP_GRPID BCM4362_CHIP_ID +#define BCM4383_CHIP_ID 0x4383 /* 4383 chipcommon chipid */ +#define BCM4383_D11AX_ID 0x4449 /* 4383 802.11ax triband device */ + +#define BCM4383_CHIP(chipid) (CHIPID(chipid) == BCM4383_CHIP_ID) +#define BCM4383_CHIP_GRPID BCM4383_CHIP_ID + +#define BCM4362_CHIP(chipid) ((CHIPID(chipid) == BCM4362_CHIP_ID) || \ + (CHIPID(chipid) == BCM43751_CHIP_ID) || \ + (CHIPID(chipid) == BCM43752_CHIP_ID) || \ + (CHIPID(chipid) == BCM43756_CHIP_ID)) +#define BCM4362_CHIP_GRPID BCM4362_CHIP_ID: \ + case BCM43751_CHIP_ID: \ + case BCM43752_CHIP_ID: \ + case BCM43756_CHIP_ID #define BCM4369_CHIP(chipid) ((CHIPID(chipid) == BCM4369_CHIP_ID) || \ (CHIPID(chipid) == BCM4377_CHIP_ID) || \ @@ -221,6 +242,15 @@ case BCM4377_CHIP_ID: \ case BCM4375_CHIP_ID +#define BCM4381_CHIP(chipid) (CHIPID(chipid) == BCM4381_CHIP_ID) +#define BCM4381_CHIP_GRPID BCM4381_CHIP_ID + +#define BCM4382_CHIP(chipid) (CHIPID(chipid) == BCM4382_CHIP_ID) +#define BCM4382_CHIP_GRPID BCM4382_CHIP_ID + +#define BCM43852_CHIP(chipid) (CHIPID(chipid) == BCM43852_CHIP_ID) +#define BCM43852_CHIP_GRPID BCM43852_CHIP_ID + #define BCM4385_CHIP(chipid) (CHIPID(chipid) == BCM4385_CHIP_ID) #define BCM4385_CHIP_GRPID BCM4385_CHIP_ID @@ -599,6 +629,10 @@ /* chip RAM specifications */ #define RDL_RAM_SIZE_4360 0xA0000 #define RDL_RAM_BASE_4360 0x60000000 +#define RDL_RAM_SIZE_4381 0x180000 +#define RDL_RAM_BASE_4381 0x740000 +#define RDL_RAM_SIZE_4382 0x200000 +#define RDL_RAM_BASE_4382 0x700000 /* generic defs for nvram "muxenab" bits * Note: these differ for 4335a0. refer bcmchipc.h for specific mux options. diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs_legacy.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs_legacy.h old mode 100755 new mode 100644 index 6e57c427b36d..11632968fb51 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs_legacy.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs_legacy.h @@ -1,7 +1,7 @@ /* * Broadcom device-specific manifest constants used by DHD, but deprecated in firmware. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -25,12 +25,8 @@ #define _bcmdevs_legacy_h_ /* DONGLE VID/PIDs */ -#define BCM_DNGL_BL_PID_4322 0xbd13 -#define BCM_DNGL_BL_PID_4319 0xbd16 -#define BCM_DNGL_BL_PID_43236 0xbd17 #define BCM_DNGL_BL_PID_43143 0xbd1e #define BCM_DNGL_BL_PID_43242 0xbd1f -#define BCM_DNGL_BL_PID_4350 0xbd23 #define BCM_DNGL_BL_PID_43569 0xbd27 /* PCI Device IDs */ @@ -151,16 +147,6 @@ (CHIPID(chipid) == BCM43570_CHIP_ID) || \ (CHIPID(chipid) == BCM4358_CHIP_ID)) /* 4350 variations */ -#define BCM43598_CHIP_ID 0xaa4c /* 4371 chipcommon chipid */ -#define BCM43234_CHIP_ID 43234 /* 43234 chipcommon chipid */ -#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */ -#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */ -#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */ -#define BCM43556_CHIP_ID 0xAA24 /* 43556 chipcommon chipid */ -#define BCM43558_CHIP_ID 0xAA26 /* 43558 chipcommon chipid */ -#define BCM43566_CHIP_ID 0xAA2E /* 43566 chipcommon chipid */ -#define BCM43568_CHIP_ID 0xAA30 /* 43568 chipcommon chipid */ - /* Board Flags */ /* Package IDs */ @@ -168,16 +154,6 @@ /* Board IDs */ /* chip RAM specifications */ -#define RDL_RAM_BASE_4319 0x60000000 -#define RDL_RAM_BASE_4329 0x60000000 -#define RDL_RAM_SIZE_4319 0x48000 -#define RDL_RAM_SIZE_4329 0x48000 -#define RDL_RAM_SIZE_43236 0x70000 -#define RDL_RAM_BASE_43236 0x60000000 -#define RDL_RAM_SIZE_4328 0x60000 -#define RDL_RAM_BASE_4328 0x80000000 -#define RDL_RAM_SIZE_4322 0x60000 -#define RDL_RAM_BASE_4322 0x60000000 #define RDL_RAM_SIZE_43242 0x90000 #define RDL_RAM_BASE_43242 0x60000000 #define RDL_RAM_SIZE_43143 0x70000 diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdhcp.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdhcp.h old mode 100755 new mode 100644 index 0051ebff97dc..6f89292fab6d --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdhcp.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdhcp.h @@ -1,7 +1,7 @@ /* * Fundamental constants relating to DHCP Protocol * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -83,4 +83,6 @@ #define DHCP6_PORT_SERVER 547 /* DHCP6 server UDP port */ #define DHCP6_PORT_CLIENT 546 /* DHCP6 client UDP port */ +#define UDP_PORT_DNS 53 /* UDP DNS port */ + #endif /* #ifndef _bcmdhcp_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmendian.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmendian.h old mode 100755 new mode 100644 index 097e5eac67bf..82968b4592c2 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmendian.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmendian.h @@ -1,7 +1,7 @@ /* * Byte order utilities * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmerror.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmerror.h old mode 100755 new mode 100644 index ef2a440095f9..836e6ce59730 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmerror.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmerror.h @@ -1,7 +1,7 @@ /* * Common header file for all error codes. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -29,20 +29,12 @@ #include -/* Use error codes from this file only if BCMUTILS_ERR_CODES is defined. */ -#ifdef BCMUTILS_ERR_CODES - /* NOTE re: Module specific error codes. * * BCME_.. error codes are extended by various features - e.g. FTM, NAN, SAE etc. * The current process is to allocate a range of 1024 negative 32 bit integers to * each module that extends the error codes to indicate a module specific status. * - * The next range to use is below. If that range is used for a new feature, please - * update the range to be used by the next feature. - * - * Next available (inclusive) range: [-8*1024 + 1, -7*1024] - * * Common error codes use BCME_ prefix. Firmware (wl) components should use the * convention to prefix the error code name with WL__E_ (e.g. WL_NAN_E_?). * Non-wl components, other than common error codes use BCM__E_ @@ -60,7 +52,6 @@ typedef int bcmerror_t; * please update errorstring table with the related error string and * update osl files with os specific errorcode map */ - #define BCME_OK 0 /* Success */ #define BCME_ERROR -1 /* Error generic */ #define BCME_BADARG -2 /* Bad Argument */ @@ -109,6 +100,7 @@ typedef int bcmerror_t; #define BCME_IOCTL_ERROR -45 /* WLCMD ioctl error */ #define BCME_SERIAL_PORT_ERR -46 /* RWL serial port error */ #define BCME_DISABLED -47 /* Disabled in this build */ +#define BCME_NOTENABLED BCME_DISABLED #define BCME_DECERR -48 /* Decrypt error */ #define BCME_ENCERR -49 /* Encrypt error */ #define BCME_MICERR -50 /* Integrity/MIC error */ @@ -136,10 +128,14 @@ typedef int bcmerror_t; #define BCME_DNGL_DEVRESET -72 /* dongle re-attach during DEVRESET */ #define BCME_ROAM -73 /* Roam related failures */ #define BCME_NO_SIG_FILE -74 /* Signature file is missing */ +#define BCME_RESP_PENDING -75 /* Command response is pending */ +#define BCME_ACTIVE -76 /* Command/context is already active */ +#define BCME_IN_PROGRESS -77 /* Command/context is in progress */ +#define BCME_NOP -78 /* No action taken i.e. NOP */ +#define BCME_6GCH_EPERM -79 /* 6G channel is not permitted */ +#define BCME_6G_NO_TPE -80 /* TPE for a 6G channel does not exist */ -#define BCME_LAST BCME_NO_SIG_FILE - -#define BCME_NOTENABLED BCME_DISABLED +#define BCME_LAST BCME_6G_NO_TPE /* add new one above and update this */ /* This error code is *internal* to the driver, and is not propogated to users. It should * only be used by IOCTL patch handlers as an indication that it did not handle the IOCTL. @@ -228,11 +224,93 @@ typedef int bcmerror_t; "Dongle Devreset", \ "Critical roam in progress", \ "Signature file is missing", \ + "Command response pending", \ + "Command/context already active", \ + "Command/context is in progress", \ + "No action taken i.e. NOP", \ + "6G Not permitted", \ + "tpe for 6g channel(s) does not exist", \ } -/** status - TBD BCME_ vs proxd status - range reserved for BCME_ */ +/* FTM error codes [-1024, -2047] */ enum { - WL_PROXD_E_LAST = -1057, + WL_FTM_E_LAST = -1089, + WL_FTM_E_PRIMARY_CLONE_START = -1089, + WL_FTM_E_DEFER_ACK_LOST = -1088, + WL_FTM_E_NSTS_INCAPABLE = -1087, + WL_FTM_E_KDK_NOT_READY = -1086, + WL_FTM_E_INVALID_SLTF_COUNTER = -1085, + WL_FTM_E_BAD_KEY_INFO_IDX = -1084, + WL_FTM_E_VALID_SAC_GEN_FAIL = -1083, + WL_FTM_E_NDPA_SAC_MISMATCH = -1082, + WL_FTM_E_MEAS_SAC_MISMATCH = -1081, + WL_FTM_E_VALID_SAC_MISMATCH = -1080, + WL_FTM_E_OUTSIDE_RSTA_AW = -1079, + WL_FTM_E_NO_STA_INFO = -1078, + WL_FTM_E_NO_SLTF_KEY_INFO = -1077, + WL_FTM_E_TOKEN_MISMATCH = -1076, + WL_FTM_E_IE_NOTFOUND = -1075, + WL_FTM_E_IE_BADLEN = -1074, + WL_FTM_E_INVALID_BW = -1073, + WL_FTM_E_INVALID_ST_CH = -1072, + WL_FTM_E_RSTA_AND_ISTA = -1071, + WL_FTM_E_NO_SLTF_INFO = -1070, + WL_FTM_E_INVALID_NBURST = -1069, + WL_FTM_E_FATAL = -1068, + WL_FTM_E_PASN = -1067, + WL_FTM_E_PERM = -1066, + WL_FTM_E_BURST = -1065, + WL_FTM_E_RESCHED = -1064, + WL_FTM_E_OFF_CHAN = -1063, + WL_FTM_E_NO_SCB = -1062, + WL_FTM_E_NOT_READY = -1061, + WL_FTM_E_DELETED = -1060, + WL_FTM_E_TX_PENDING = -1059, + WL_FTM_E_BAD_CONFIG = -1058, + WL_FTM_E_ASSOC_INPROG = -1057, + WL_FTM_E_NOAVAIL = -1056, + WL_FTM_E_EXT_SCHED = -1055, + WL_FTM_E_NOT_BCM = -1054, + WL_FTM_E_FRAME_TYPE = -1053, + WL_FTM_E_VERNOSUPPORT = -1052, + WL_FTM_E_SEC_NOKEY = -1051, + WL_FTM_E_SEC_POLICY = -1050, + WL_FTM_E_SCAN_INPROCESS = -1049, + WL_FTM_E_BAD_PARTIAL_TSF = -1048, + WL_FTM_E_SCANFAIL = -1047, + WL_FTM_E_NOTSF = -1046, + WL_FTM_E_POLICY = -1045, + WL_FTM_E_INCOMPLETE = -1044, + WL_FTM_E_OVERRIDDEN = -1043, + WL_FTM_E_ASAP_FAILED = -1042, + WL_FTM_E_NOTSTARTED = -1041, + WL_FTM_E_INVALIDMEAS = -1040, + WL_FTM_E_INCAPABLE = -1039, + WL_FTM_E_MISMATCH = -1038, + WL_FTM_E_DUP_SESSION = -1037, + WL_FTM_E_REMOTE_FAIL = -1036, + WL_FTM_E_REMOTE_INCAPABLE = -1035, + WL_FTM_E_SCHED_FAIL = -1034, + WL_FTM_E_PROTO = -1033, + WL_FTM_E_EXPIRED = -1032, + WL_FTM_E_TIMEOUT = -1031, + WL_FTM_E_NOACK = -1030, + WL_FTM_E_DEFERRED = -1029, + WL_FTM_E_INVALID_SID = -1028, + WL_FTM_E_REMOTE_CANCEL = -1027, + WL_FTM_E_CANCELED = -1026, /**< local */ + WL_FTM_E_INVALID_SESSION = -1025, + WL_FTM_E_BAD_STATE = -1024, + WL_FTM_E_OK = 0 +}; +typedef int32 wl_ftm_status_t; + +/* TODO: remove another copy in wlioctl.h */ +#ifdef BCMUTILS_ERR_CODES +/* begin proxd codes compatible w/ ftm above - obsolete DO NOT extend */ +enum { + WL_PROXD_E_LAST = -1058, + WL_PROXD_E_PKTFREED = -1058, WL_PROXD_E_ASSOC_INPROG = -1057, WL_PROXD_E_NOAVAIL = -1056, WL_PROXD_E_EXT_SCHED = -1055, @@ -272,10 +350,12 @@ enum { WL_PROXD_E_OK = 0 }; typedef int32 wl_proxd_status_t; +/* end proxd codes - obsolete DO NOT extend */ /** status - TBD BCME_ vs NAN status - range reserved for BCME_ */ enum { /* add new status here... */ + WL_NAN_E_GRP_REKEY_FAIL = -2137, WL_NAN_E_NO_ACTION = -2136, /* status for no action */ WL_NAN_E_INVALID_TOKEN = -2135, /* invalid token or mismatch */ WL_NAN_E_INVALID_ATTR = -2134, /* generic invalid attr error */ @@ -425,99 +505,194 @@ enum { /* Anti-clogging token mismatch */ WL_SAE_E_AUTH_ANTI_CLOG_MISMATCH = -3096, /* SAE PWE method mismatch */ - WL_SAE_E_AUTH_PWE_MISMATCH = -3097 + WL_SAE_E_AUTH_PWE_MISMATCH = -3097, + /* SAE-PK validation failed */ + WL_SAE_E_AUTH_PK_VALIDATION = -3098 }; +#endif /* BCMUTILS_ERR_CODES */ /* - * Firmware signing error code range: -4096...-5119 + * Bootloader error code range: -4096...-5119 */ enum { /* okay */ - BCM_FWSIGN_E_OK = 0, + BL_E_OK = 0, /* Operation is in progress */ - BCM_FWSIGN_E_INPROGRESS = -4096, + BL_E_INPROGRESS = -4096, /* version mismatch */ - BCM_FWSIGN_E_VERSION = -4097, + BL_E_VERSION = -4097, /* key not found */ - BCM_FWSIGN_E_KEY_NOT_FOUND = -4098, + BL_E_KEY_NOT_FOUND = -4098, /* key found, but is not valid (revoked) */ - BCM_FWSIGN_E_KEY_NOT_VALID = -4099, + BL_E_KEY_NOT_VALID = -4099, /* Cipher suite id mismatch for the key */ - BCM_FWSIGN_E_CS_ID_MISMATCH = -4100, + BL_E_CS_ID_MISMATCH = -4100, /* Signature does not match */ - BCM_FWSIGN_E_SIGNATURE = -4101, + BL_E_SIGNATURE = -4101, /* Continue */ - BCM_FWSIGN_E_CONTINUE = -4102, + BL_E_CONTINUE = -4102, - /* Heap is too small */ - BCM_FWSIGN_E_HEAP_TOO_SMALL = -4103, + BL_E_HEAP_TOO_SMALL = -4103, /* Allocation of bn ctx failed */ - BCM_FWSIGN_E_BN_CTX_ALLOC_FAILED = -4104, + BL_E_BN_CTX_ALLOC_FAILED = -4104, /* possible bug */ - BCM_FWSIGN_E_BUGCHECK = -4105, + BL_E_BUGCHECK = -4105, /* chosen key is invalid */ - BCM_FWSIGN_E_INVALID_KEY = -4106, + BL_E_INVALID_KEY = -4106, /* signature is invalid */ - BCM_FWSIGN_E_INVALID_SIGNATURE = -4107, + BL_E_INVALID_SIGNATURE = -4107, /* signature tlv missing */ - BCM_FWSIGN_E_NO_CSID_SIG = -4108, + BL_E_NO_CSID_SIG = -4108, /* chosen key is invalid */ - BCM_FWSIGN_E_REVOKED_KEY = -4109, + BL_E_REVOKED_KEY = -4109, /* signature has no matching valid key in ROM */ - BCM_FWSIGN_E_NO_OTP_FOR_ROM_KEY = -4110, + BL_E_NO_OTP_FOR_ROM_KEY = -4110, /* Compression not supported */ - BCM_FWSIGN_E_COMPNOTSUP = -4111, + BL_E_COMPNOTSUP = -4111, /* OTP read error */ - BCM_FWSIGN_E_OTP_READ = -4112, + BL_E_OTP_READ = -4112, /* heap address overlaps with FW address space */ - BCM_FWSIGN_E_HEAP_OVR_FW = -4113, + BL_E_HEAP_OVR_FW = -4113, /* heap address overlaps with bootloader data/bss region */ - BCM_FWSIGN_E_HEAP_OVR_BSS = -4114, + BL_E_HEAP_OVR_BSS = -4114, /* heap address overlaps with bootloader stack region */ - BCM_FWSIGN_E_HEAP_OVR_STACK = -4115, + BL_E_HEAP_OVR_STACK = -4115, /* firmware encryption header tlv is missing */ - BCM_FWSIGN_E_NO_FWENC_HDR = -4116, + BL_E_NO_FWENC_HDR = -4116, /* firmware encryption algo not supported */ - BCM_FWSIGN_E_FWENC_ALGO_NOTSUP = -4117, + BL_E_FWENC_ALGO_NOTSUP = -4117, /* firmware encryption tag tlv is missing */ - BCM_FWSIGN_E_NO_FW_TAG = -4118, + BL_E_NO_FW_TAG = -4118, /* firmware encryption tag tlv is not valid */ - BCM_FWSIGN_E_FW_TAG_INVALID_TLV = -4119, + BL_E_FW_TAG_INVALID_TLV = -4119, /* firmware encryption tag verification fail */ - BCM_FWSIGN_E_FW_TAG_MISMATCH = -4120, + BL_E_FW_TAG_MISMATCH = -4120, /* signature package is invalid */ - BCM_FWSIGN_E_PACKAGE_INVALID = -4121, + BL_E_PACKAGE_INVALID = -4121, + + /* chip info mismatch */ + BL_E_CHIP_INFO_MISMATCH = -4122, + + /* key use is not valid */ + BL_E_KEY_USE_NOT_VALID = -4123, + + /* fw tag type invalid */ + BL_E_TAG_TYPE_INVALID = -4124, + + /* fwenc header invalid */ + BL_E_FWENC_HDR_INVALID = -4125, + + /* firmware encryption header version mismatch */ + BL_E_FWENC_HDR_VERSION = -4126, + + /* firmware encryption cipher type not supported */ + BL_E_FWENC_CIPHER_TYPE_UNSUPPORTED = -4127, + + /* firmware encryption tlv type not supported */ + BL_E_FWENC_TLV_TYPE_UNSUPPORTED = -4128, + + /* firmware encryption invalid kdf info */ + BL_E_FWENC_INVALID_KDFINFO = -4129, + + /* firmware encryption invalid ec group type length */ + BL_E_FWENC_INVALID_ECG_TYPE_LEN = -4130, + + /* firmware encryption invalid epub */ + BL_E_FWENC_INVALID_EPUB = -4131, + + /* firmware encryption invalid iv */ + BL_E_FWENC_INVALID_IV = -4132, + + /* firmware encryption invalid aad */ + BL_E_FWENC_INVALID_AAD = -4133, + + /* firmware encryption invalid ROM key */ + BL_E_FWENC_INVALID_ROMKEY = -4134, + + /* firmware encryption invalid sysmem key */ + BL_E_FWENC_INVALID_SYSMEMKEY = -4135, + + /* firmware encryption invalid OTP key */ + BL_E_FWENC_INVALID_OTPKEY = -4136, + + /* firmware encryption key unwrap fail */ + BL_E_FWENC_KEY_UNWRAP_FAIL = -4137, + + /* firmware encryption generate share secret fail */ + BL_E_FWENC_GEN_SECRET_FAIL = -4138, + + /* firmware encryption symmetric key derivation fail */ + BL_E_FWENC_KEY_DERIVATION_FAIL = -4139, + + /* firmware encryption RNG read fail */ + BL_E_FWENC_RNG_FAIL = -4140, + + /* firmware encryption MAC tampered during decryption */ + BL_E_FWENC_MAC_TAMPERED = -4141, + + /* firmware encryption decryption failed */ + BL_E_FWENC_DECRYPT_FAIL = -4142, + + /* firmware encryption decryption in progress */ + BL_E_FWENC_DECRYPT_IN_PROGRESS = -4143, + + /* signature patch tlv is missing */ + BL_E_PATCH_TLV_MISSING = -4144, + + /* signature patch tlv invalid */ + BL_E_PATCH_TLV_INVALID = -4145, + + /* signature patch is empty */ + BL_E_PATCH_EMPTY = -4146, + + /* signature patch bad addr */ + BL_E_PATCH_BAD_ADDR = -4147, + + /* signature patch unsupported version */ + BL_E_PATCH_VERSION = -4148, + + /* signature patch cmd error */ + BL_E_PATCH_CMD = -4149, + + /* signature patch invalid length */ + BL_E_PATCH_INVALID_LENGTH = -4150, + + /* bmpu configuration error */ + BL_E_BUS_MPU_CONFIG_FAIL = -4151, /* last error */ - BCM_FWSIGN_E_LAST = -5119 + BL_E_LAST = -5119 }; -typedef int32 bcm_fwsign_status_t; +typedef int32 bl_status_t; + +/* TODO: remove another copy in wlioctl.h */ +#ifdef BCMUTILS_ERR_CODES /* PMK manager block. Event codes from -5120 to -6143 */ /* PSK hashing event codes */ enum { @@ -545,9 +720,10 @@ enum { /* Failure to get NAF3 params */ WL_SOE_E_NAF3_PARAMS_GET_ERROR = -6147 }; +#endif /* BCMUTILS_ERR_CODES */ /* BCM crypto ASN.1 status codes. */ -/* Reserved range is from -7168 to -8291 */ +/* Reserved range is from -7168 to -8191 */ enum { /* tag mismatch */ BCM_CRYPTO_E_ASN1_TAG_MISMATCH = -7168, @@ -568,6 +744,168 @@ enum { BCM_CRYPTO_E_ASN1_UNSUPPORTED_ECG = -7173 }; -#endif /* BCMUTILS_ERR_CODES */ +/* PASN authentication status codes. */ +/* Reserved from -8192 to -9215(1K). */ +enum { + /* Terminate PASN authentication if off channel. */ + WL_PASN_E_OFF_CHANNEL = -8192, + /* Terminate PASN authentication if infra attempt to join. */ + WL_PASN_E_JOIN_ATTEMPT = -8193, + /* Host requests to stop current session. */ + WL_PASN_E_STOP_ON_REQUEST = -8194, + /* Received PASN auth frame carries failure status code. */ + WL_PASN_E_AUTH_FAILURE = -8195, + /* Transmitted PASN auth frame is not acknowledged by peer. */ + WL_PASN_E_AUTH_NO_ACK = -8196, + /* Timeout waiting for PASN auth frame. */ + WL_PASN_E_AUTH_RX_TIMEOUT = -8197, + /* RSN element in PASN auth frame is invalid. */ + WL_PASN_E_AUTH_INVALID_RSNIE = -8198, + /* PMKID in PASN auth frame is not found. */ + WL_PASN_E_AUTH_PMKID_NOT_FOUND = -8199, + /* Base AKM in PASN parameters element is not supported. */ + WL_PASN_E_AUTH_BASE_AKM_NOT_SUPPORTED = -8200, + /* PASN AKM is not supported. */ + WL_PASN_E_AUTH_PASN_AKM_NOT_SUPPORTED = -8201, + /* Timeout waiting for wrapped data processing completion. */ + WL_PASN_E_AUTH_WRAPPED_DATA_TIMEOUT = -8202, + /* Wrapped data handler returns error. */ + WL_PASN_E_AUTH_WRAPPED_DATA_ERROR = -8203, + /* PASN authentication frame is not correctly constructed. */ + WL_PASN_E_AUTH_FRAME_CORRUPTED = -8204, + /* Retry time is exhausted. */ + WL_PASN_E_AUTH_RETRY_LIMIT_REACHED = -8205, + /* cookie carried by STA is invalid. */ + WL_PASN_E_AUTH_COOKIE_MISMATCH = -8206, + /* Invalid PASN state transition. */ + WL_PASN_E_SM_INVALID = -8207, + /* PASN state not found */ + WL_PASN_E_SM_NOTFOUND = -8208, + /* Finite cyclic group indicated in PASN parameters element is not supported. */ + WL_PASN_E_CRYPTO_UNSUPPORTED_GROUP = -8209, + /* Ephemeral public key in PASN parameters element is not valid. */ + WL_PASN_E_CRYPTO_INVALID_PUBLIC_KEY = -8210, + /* Generic cryto failure. */ + WL_PASN_E_CRYPTO_FAILURE = -8211, + /* PASN failed to generate DHss */ + WL_PASN_E_CRYPTO_DHSS_FAILURE = -8212, + /* Fail to get hash type. */ + WL_PASN_E_CRYPTO_HASH_TYPE_FAILURE = -8213, + /* PASN state is unexpected */ + WL_PASN_E_INVALID_STATE = -8214, + /* Unsolicited authentication frame */ + WL_PASN_E_AUTH_UNSOLICITED = -8215, + /* Not a valid scenario for transmission */ + WL_PASN_E_AUTH_TX_INVALID = -8216, + /* PASN session not found */ + WL_PASN_E_SESSION_NOTFOUND = -8217, + /* PASN session can't allocate SCB to install key */ + WL_PASN_E_NO_SCB = -8218, + /* Buffer provided to construct public key is too short */ + WL_PASN_E_AUTH_PK_BUFTOOSHORT = -8219, + /* Abandon the PASN session in progress if received non PASN auth frame from peer. */ + WL_PASN_E_AUTH_NON_PASN_RCVD = -8220, + /* Unexpected SAE msg from SAE module. */ + WL_PASN_E_SAE_UNEXPECTED_MSG = -8221, + /* SAE module rejects tunneled commit msg. */ + WL_PASN_E_SAE_COMMIT_REJECTED = -8222, + /* Receive deauthentication frame from peer. */ + WL_PASN_E_RX_DEAUTH = -8223, + /* PMKSA is not establisthed. */ + WL_PASN_E_AUTH_NO_PMKSA = -8224, + /* Terminate PASN authentication if Non-PASN authentication is successful. */ + WL_PASN_E_NON_PASN_AUTHENTICATED = -8225, + /* PTKSA is derived and installed. */ + WL_PASN_E_PTK_EXISTS = -8226, + /* The session is in progress */ + WL_PASN_E_SESSION_IN_PROGRESS = -8227, + /* cached PMK used in the session is expired */ + WL_PASN_E_AUTH_PMKSA_EXPIRED = -8228, + /* PTKSA installed is deleted by keymgmt */ + WL_PASN_E_AUTH_PTKSA_DELETED = -8229, + /* SA query timeout notification */ + WL_PASN_E_SA_QUERY_TIMEOUT = -8230, + /* PTKSA lifetime expired */ + WL_PASN_E_AUTH_PTKSA_EXPIRED = -8231, + /* Local to deauth peer. */ + WL_PASN_E_DEAUTH_PEER = -8232 +}; +/* bcm fsm status codes. [-9216, -10239] */ +enum { + BCM_FSM_E_INVALID_STATE = -9216, + BCM_FSM_E_INVALID_EVENT = -9217, + BCM_FSM_E_BAD_TRANSITION = -9218, + BCM_FSM_E_NO_ALLOC = -9219, + BCM_FSM_E_NO_TIMER = -9220, + BCM_FSM_E_EXISTS = -9221, + BCM_FSM_E_NO_HANDLER = -9222, + BCM_FSM_E_NO_TIMER_INFO = -9223, + BCM_FSM_E_TIME_NON_MONOTONIC = -9224, + BCM_FSM_E_IN_EVH_ALREADY = -9225, + BCM_FSM_E_NOT_IN_EVH = -9226, + BCM_FSM_E_NO_ERR_HANDLER = -9227, + BCM_FSM_E_FATAL_ERROR = -9228, + BCM_FSM_E_NO_TRANSITION = -9229, + BCM_FSM_E_DESTROY_FSM = -9230, + BCM_FSM_E_ASYNC_REQUIRED = -9231, + BCM_FSM_E_INVALID_FSM = -9232, + BCM_FSM_E_CHILD_EXISTS = -9233, + BCM_FSM_E_BAD_POST_OPTIONS = -9234, + BCM_FSM_E_NO_OSH = -9235, + + /* add additional errors above this line */ + BCM_FSM_E_MAX = -10239 +}; + +/* QoS Mgmt status codes. [-10240 ... -11263] (1K) + */ +typedef enum wl_mscs_status { + /* MSCS is already active */ + WL_MSCS_E_ACTIVE = -10240, + + /* MSCS activation is in progress */ + WL_MSCS_E_IN_PROGRESS = -10241 +} wl_mscs_status_e; + +/* bcmsm error code [-11264 ... -12287] */ +typedef enum { + BCMSM_IN_RTC = -11264, /**< In Run to completion loop */ + BCMSM_TRANS_NOT_FOUND = -11265, /**< Transition was not found */ + BCMSM_TRANS_GUARD_FAILED = -11266, /**< guard for a transition failed */ + BCMSM_TRANS_EFFECT_FAILED = -11267, /**< transition effect returned err */ + BCMSM_TRANS_ERROR = -11268, /**< Error while taking transition */ + BCMSM_STATE_ENTRY_FAILED = -11269, /**< Entry to state failed */ + BCMSM_STATE_EXIT_FAILED = -11270, /**< Failure while executing a state */ + BCMSM_STATE_ID_EXISTS = -11271, /**< Same ID exists */ + BCMSM_STATE_CONFIG_ERROR = -11272, /**< SM configuration has error */ + BCMSM_Q_FULL = -11273, /**< Event queue is full */ + BCMSM_Q_EMPTY = -11274, /**< Event queue is empty */ + BCMSM_Q_NO_DEQUEUE = -11275, /**< Dequeue attempted was unsuccessful */ + BCMSM_CHOICE_STATE_NO_TRANS = -11276, /**< Choice has no valid out transition */ + BCMSM_EVENT_ALLOC_FAILED = -11277, /**< Event allocation failed */ + BCMSM_EVENT_EXPIRED = -11278, /**< Event expired */ + BCMSM_EVENT_NOT_POSTED = -11279, /**< Event was not posted */ + BCMSM_HALTED = -11280, /**< State machine is in final state */ + BCMSM_TMR_NOT_STOPPED = -11281, /**< Error in stopping a timer */ + BCMSM_TMR_NOT_STARTED = -11282, /**< Error in starting a timer */ + BCMSM_TMR_NOT_FOUND = -11283, /**< No timer available to be scheduled */ + BCMSM_TMR_ERROR = -11284, /**< Error in starting a timer */ + + BCMSM_MAX = -12287 +} bcmsm_status_t; + +/* +* 6G scan error code [-12288 .. -13311] (1K) +*/ +enum { + /* TPE cache does not exit for the given 6G channel */ + BCME_6G_SCAN_NO_TPE_CACHE = -12288, + /* TPE cache in the FW has expired */ + BCME_6G_SCAN_TPE_CACHE_EXPIRED = -12289, + /* Wild card directed scan requested */ + BCME_6G_SCAN_DIRECTED_WILDCARD = -12290, + /* TPE cache in the FW is invalid */ + BCME_6G_SCAN_TPE_CACHE_INVALID = -12291 +}; #endif /* _bcmerror_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmeth.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmeth.h old mode 100755 new mode 100644 index f43343759df9..814691053572 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmeth.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmeth.h @@ -1,7 +1,7 @@ /* * Broadcom Ethernettype protocol definitions * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmevent.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmevent.h old mode 100755 new mode 100644 index e7876c7f68a9..6ff269d01ac0 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmevent.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmevent.h @@ -3,7 +3,7 @@ * * Dependencies: bcmeth.h * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -35,6 +35,7 @@ #include /* #include -- TODO: req., excluded to overwhelming coupling (break up ethernet.h) */ #include +#include #if defined(HEALTH_CHECK) || defined(DNGL_EVENT_SUPPORT) #include #endif /* HEALTH_CHECK || DNGL_EVENT_SUPPORT */ @@ -51,6 +52,7 @@ #define WLC_EVENT_MSG_GROUP 0x04 /* group MIC error */ #define WLC_EVENT_MSG_UNKBSS 0x08 /* unknown source bsscfg */ #define WLC_EVENT_MSG_UNKIF 0x10 /* unknown source OS i/f */ +#define WLC_EVENT_MSG_MULTILINK 0x20 /* used to indicate that connection is multilink */ /* these fields are stored in network order */ @@ -169,8 +171,8 @@ typedef union bcm_event_msg_u { #define WLC_E_ACTION_FRAME_COMPLETE 60 /* Action frame Tx complete */ #define WLC_E_PRE_ASSOC_IND 61 /* assoc request received */ #define WLC_E_PRE_REASSOC_IND 62 /* re-assoc request received */ -#ifdef CSI_SUPPORT -#define WLC_E_CSI 63 +#if defined(CSI_SUPPORT) +#define WLC_E_CSI 63 /* CSI used obsoleted event number */ #else #define WLC_E_CHANNEL_ADOPTED 63 /* channel adopted (obsoleted) */ #endif /* CSI_SUPPORT */ @@ -214,12 +216,6 @@ typedef union bcm_event_msg_u { #define WLC_E_NATIVE 94 /* port-specific event and payload (e.g. NDIS) */ #define WLC_E_PKTDELAY_IND 95 /* event for tx pkt delay suddently jump */ -#ifdef WLAWDL -#define WLC_E_AWDL_AW 96 /* AWDL AW period starts */ -#define WLC_E_AWDL_ROLE 97 /* AWDL Master/Slave/NE master role event */ -#define WLC_E_AWDL_EVENT 98 /* Generic AWDL event */ -#endif /* WLAWDL */ - #define WLC_E_PSTA_PRIMARY_INTF_IND 99 /* psta primary interface indication */ #define WLC_E_NAN 100 /* NAN event - Reserved for future */ #define WLC_E_BEACON_FRAME_RX 101 @@ -248,7 +244,8 @@ typedef union bcm_event_msg_u { #define WLC_E_TX_STAT_ERROR 126 /* tx error indication */ #define WLC_E_BCMC_CREDIT_SUPPORT 127 /* credit check for BCMC supported */ #define WLC_E_PEER_TIMEOUT 128 /* silently drop a STA because of inactivity */ -#define WLC_E_BT_WIFI_HANDOVER_REQ 130 /* Handover Request Initiated */ +// 129 unused +// 130 unused #define WLC_E_SPW_TXINHIBIT 131 /* Southpaw TxInhibit notification */ #define WLC_E_FBT_AUTH_REQ_IND 132 /* FBT Authentication Request Indication */ #define WLC_E_RSSI_LQM 133 /* Enhancement addition for WLC_E_RSSI */ @@ -273,8 +270,7 @@ typedef union bcm_event_msg_u { #define WLC_E_TEMP_THROTTLE 154 /* Temperature throttling control event */ #define WLC_E_LINK_QUALITY 155 /* Link quality measurement complete */ #define WLC_E_BSSTRANS_RESP 156 /* BSS Transition Response received */ -#define WLC_E_TWT_SETUP 157 /* TWT Setup Complete event */ -#define WLC_E_HE_TWT_SETUP 157 /* TODO:Remove after merging TWT changes to trunk */ +#define WLC_E_TWT_SETUP 157 /* Use this as WLC_E_TWT as umbrella TWT event */ #define WLC_E_NAN_CRITICAL 158 /* NAN Critical Event */ #define WLC_E_NAN_NON_CRITICAL 159 /* NAN Non-Critical Event */ #define WLC_E_RADAR_DETECTED 160 /* Radar Detected event */ @@ -313,17 +309,23 @@ typedef union bcm_event_msg_u { #define WLC_E_AP_BCN_DRIFT 192 /* Beacon Drift event */ #define WLC_E_PFN_SCAN_ALLGONE_EXT 193 /* last found PFN network gets lost. */ #define WLC_E_AUTH_START 194 /* notify upper layer to start auth */ -#define WLC_E_TWT_TEARDOWN 195 /* TWT Teardown Complete Event */ -#define WLC_E_TWT_INFO_FRM 196 /* TWT Info Event Notification */ -#define WLC_E_LAST 197 /* highest val + 1 for range checking */ -#if (WLC_E_LAST > 197) -#error "WLC_E_LAST: Invalid value for last event; must be <= 197." -#endif /* WLC_E_LAST */ +#define WLC_E_TWT 195 /* TWT event */ +#define WLC_E_AMT 196 /* Address Management Table (AMT) */ +#define WLC_E_ROAM_SCAN_RESULT 197 /* roam/reassoc scan result event */ + +#define WLC_E_MSCS 200 /* MSCS success/failure events */ +#define WLC_E_RXDMA_RECOVERY_ATMPT 201 /* RXDMA Recovery Attempted Event */ +#define WLC_E_PFN_PARTIAL_RESULT 202 +#define WLC_E_MLO_LINK_INFO 203 /* 11be MLO link information */ +#define WLC_E_C2C 204 /* Client to client (C2C) for 6GHz TX */ +#define WLC_E_BCN_TSF 205 /* Report Beacon TSF */ +#define WLC_E_OWE_INFO 206 /* OWE Information */ +#define WLC_E_ULMU_DISABLED_REASON_UPD 207 /* OMI ULMU disable reason code update */ +#define WLC_E_AMSDU_RX_WAKEUP 208 /* When amsdu deagg SM is stuck in D3 condition */ +#define WLC_E_LAST 209 /* highest val + 1 for range checking */ /* define an API for getting the string name of an event */ extern const char *bcmevent_get_name(uint event_type); -extern void wl_event_to_host_order(wl_event_msg_t * evt); -extern void wl_event_to_network_order(wl_event_msg_t * evt); /* validate if the event is proper and if valid copy event header to event */ extern int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, @@ -363,14 +365,17 @@ typedef struct wlc_roam_start_event { uint16 length; /* total length */ int16 rssi; /* current bss rssi */ int8 pad[2]; /* padding */ - uint8 xtlvs[]; /* optional xtlvs */ + uint8 xtlvs[]; /* optional xtlvs (wl_roam_start_xtlv_id) */ } wlc_roam_start_event_t; typedef struct wlc_roam_prep_event { uint16 version; /* version */ uint16 length; /* total length */ int16 rssi; /* target bss rssi */ - int8 pad[2]; /* padding */ + union { + int8 pad[2]; /* padding */ + chanspec_t chanspec; /**< Channel num, bw, ctrl_sb and band */ + }; uint8 xtlvs[]; /* optional xtlvs */ } wlc_roam_prep_event_t; @@ -432,6 +437,8 @@ typedef enum wlc_roam_cache_update_reason { #define WLC_E_STATUS_RXBCN 19 /* Rx Beacon event for FAKEAP feature */ #define WLC_E_STATUS_RXBCN_ABORT 20 /* Rx Beacon abort event for FAKEAP feature */ #define WLC_E_STATUS_LOWPOWER_ON_LOWSPAN 21 /* LOWPOWER scan request during LOWSPAN */ +#define WLC_E_STATUS_WAIT_RXBCN_TIMEOUT 22 /* Time out happened waiting of beacon */ +#define WLC_E_STATUS_6G_NO_TPE 23 /* No tpe in the fw cache for 6g channels */ #define WLC_E_STATUS_INVALID 0xff /* Invalid status code to init variables. */ /* 4-way handshake event type */ @@ -439,6 +446,7 @@ typedef enum wlc_roam_cache_update_reason { #define WLC_E_PSK_AUTH_SUB_EAPOL_DONE 2 /* EAPOL end */ /* GTK event type */ #define WLC_E_PSK_AUTH_SUB_GTK_DONE 3 /* GTK end */ +#define WLC_E_PSK_AUTH_SUB_PTK_DONE 4 /* PTK end */ /* 4-way handshake event status code */ #define WLC_E_STATUS_PSK_AUTH_WPA_TIMOUT 1 /* operation timed out */ @@ -449,23 +457,26 @@ typedef enum wlc_roam_cache_update_reason { #define WLC_E_STATUS_PSK_AUTH_GTK_REKEY_FAIL 6 /* GTK event status code */ /* SDB transition status code */ -#define WLC_E_STATUS_SDB_START 1 -#define WLC_E_STATUS_SDB_COMPLETE 2 +#define WLC_E_STATUS_SDB_START 1u +#define WLC_E_STATUS_SDB_COMPLETE 2u /* Slice-swap status code */ -#define WLC_E_STATUS_SLICE_SWAP_START 3 -#define WLC_E_STATUS_SLICE_SWAP_COMPLETE 4 +#define WLC_E_STATUS_SLICE_SWAP_START 3u +#define WLC_E_STATUS_SLICE_SWAP_COMPLETE 4u +#define WLC_E_STATUS_SDB_FAILED 5u /* SDB transition reason code */ -#define WLC_E_REASON_HOST_DIRECT 0 -#define WLC_E_REASON_INFRA_ASSOC 1 -#define WLC_E_REASON_INFRA_ROAM 2 -#define WLC_E_REASON_INFRA_DISASSOC 3 -#define WLC_E_REASON_NO_MODE_CHANGE_NEEDED 4 +#define WLC_E_REASON_HOST_DIRECT 0u +#define WLC_E_REASON_INFRA_ASSOC 1u +#define WLC_E_REASON_INFRA_ROAM 2u +#define WLC_E_REASON_INFRA_DISASSOC 3u +#define WLC_E_REASON_NO_MODE_CHANGE_NEEDED 4u -#ifdef WLAWDL -#define WLC_E_REASON_AWDL_ENABLE 5 -#define WLC_E_REASON_AWDL_DISABLE 6 -#endif /* WLAWDL */ +#define WLC_E_REASON_SDB_MODESW_SLICE_CHANGE 7u +#define WLC_E_REASON_SDB_MODESW_CHAIN_CHANGE 8u +#define WLC_E_REASON_SDB_MODESW_SLICE_AND_CHAIN_CHANGE 9u +#define WLC_E_REASON_SDB_MODESW_UNKNOWN 10u +#define WLC_E_REASON_SDB_MODESW_TIMEOUT 11u +#define WLC_E_REASON_SDB_MODESW_FAILED 12u /* TX STAT ERROR REASON CODE */ #define WLC_E_REASON_TXBACKOFF_NOT_DECREMENTED 0x1 @@ -491,10 +502,6 @@ typedef struct wl_event_sdb_trans { /* reason codes for WLC_E_GTK_KEYROT_NO_CHANSW event */ #define WLC_E_GTKKEYROT_SCANDELAY 0 /* Delay scan while gtk in progress */ -#ifdef WLAWDL -#define WLC_E_GTKKEYROT_SKIPCHANSW_AWDL 1 /* Avoid chansw by awdl while gtk in progress */ -#endif /* WLAWDL */ - #define WLC_E_GTKKEYROT_SKIPCHANSW_P2P 2 /* Avoid chansw by p2p while gtk in progress */ /* roam reason codes */ @@ -518,41 +525,60 @@ typedef struct wl_event_sdb_trans { #define WLC_E_REASON_ESTM_LOW 15 /* roamed due to ESTM low tput */ #define WLC_E_REASON_SILENT_ROAM 16 /* roamed due to Silent roam */ #define WLC_E_REASON_INACTIVITY 17 /* full roam scan due to inactivity */ -#define WLC_E_REASON_ROAM_SCAN_TIMEOUT 18 /* roam scan timer timeout */ +#define WLC_E_REASON_ROAM_SCAN_TIMEOUT 18 /* roam scan timer timeout */ #define WLC_E_REASON_REASSOC 19 /* roamed due to reassoc iovar */ -#define WLC_E_REASON_LAST 20 /* NOTE: increment this as you add reasons above */ +#define WLC_E_REASON_CCA 20 /* roamed due to better AP from cca measurement */ +#define WLC_E_REASON_BTCX_ROAM 21 /* roamed due to Btcx roam */ +#define WLC_E_REASON_MLD_REASSOC 22 /* MLD reassoc */ +#define WLC_E_REASON_LAST 23 /* NOTE: increment this as you add reasons above */ /* prune reason codes */ -#define WLC_E_PRUNE_ENCR_MISMATCH 1 /* encryption mismatch */ -#define WLC_E_PRUNE_BCAST_BSSID 2 /* AP uses a broadcast BSSID */ -#define WLC_E_PRUNE_MAC_DENY 3 /* STA's MAC addr is in AP's MAC deny list */ -#define WLC_E_PRUNE_MAC_NA 4 /* STA's MAC addr is not in AP's MAC allow list */ -#define WLC_E_PRUNE_REG_PASSV 5 /* AP not allowed due to regulatory restriction */ -#define WLC_E_PRUNE_SPCT_MGMT 6 /* AP does not support STA locale spectrum mgmt */ -#define WLC_E_PRUNE_RADAR 7 /* AP is on a radar channel of STA locale */ -#define WLC_E_RSN_MISMATCH 8 /* STA does not support AP's RSN */ -#define WLC_E_PRUNE_NO_COMMON_RATES 9 /* No rates in common with AP */ -#define WLC_E_PRUNE_BASIC_RATES 10 /* STA does not support all basic rates of BSS */ +#define WLC_E_PRUNE_ENCR_MISMATCH 1u /* encryption mismatch */ +#define WLC_E_PRUNE_BCAST_BSSID 2u /* AP uses a broadcast BSSID */ +#define WLC_E_PRUNE_MAC_DENY 3u /* STA's MAC addr is in AP's MAC deny list */ +#define WLC_E_PRUNE_MAC_NA 4u /* STA's MAC addr is not in AP's MAC allow list */ +#define WLC_E_PRUNE_REG_PASSV 5u /* AP not allowed due to regulatory restriction */ +#define WLC_E_PRUNE_SPCT_MGMT 6u /* AP does not support STA locale spectrum mgmt */ +#define WLC_E_PRUNE_RADAR 7u /* AP is on a radar channel of STA locale */ +#define WLC_E_RSN_MISMATCH 8u /* STA does not support AP's RSN */ +#define WLC_E_PRUNE_NO_COMMON_RATES 9u /* No rates in common with AP */ +#define WLC_E_PRUNE_BASIC_RATES 10u /* STA does not support all basic rates of BSS */ #ifdef BCMCCX -#define WLC_E_PRUNE_CCXFAST_PREVAP 11 /* CCX FAST ROAM: prune previous AP */ +#define WLC_E_PRUNE_CCXFAST_PREVAP 11u /* CCX FAST ROAM: prune previous AP */ #endif /* def BCMCCX */ -#define WLC_E_PRUNE_CIPHER_NA 12 /* BSS's cipher not supported */ -#define WLC_E_PRUNE_KNOWN_STA 13 /* AP is already known to us as a STA */ +#define WLC_E_PRUNE_CIPHER_NA 12u /* BSS's cipher not supported */ +#define WLC_E_PRUNE_KNOWN_STA 13u /* AP is already known to us as a STA */ #ifdef BCMCCX -#define WLC_E_PRUNE_CCXFAST_DROAM 14 /* CCX FAST ROAM: prune unqualified AP */ +#define WLC_E_PRUNE_CCXFAST_DROAM 14u /* CCX FAST ROAM: prune unqualified AP */ #endif /* def BCMCCX */ -#define WLC_E_PRUNE_WDS_PEER 15 /* AP is already known to us as a WDS peer */ -#define WLC_E_PRUNE_QBSS_LOAD 16 /* QBSS LOAD - AAC is too low */ -#define WLC_E_PRUNE_HOME_AP 17 /* prune home AP */ +#define WLC_E_PRUNE_WDS_PEER 15u /* AP is already known to us as a WDS peer */ +#define WLC_E_PRUNE_QBSS_LOAD 16u /* QBSS LOAD - AAC is too low */ +#define WLC_E_PRUNE_HOME_AP 17u /* prune home AP */ #ifdef BCMCCX -#define WLC_E_PRUNE_AP_BLOCKED 18 /* prune blocked AP */ -#define WLC_E_PRUNE_NO_DIAG_SUPPORT 19 /* prune due to diagnostic mode not supported */ +#define WLC_E_PRUNE_AP_BLOCKED 18u /* prune blocked AP */ +#define WLC_E_PRUNE_NO_DIAG_SUPPORT 19u /* prune due to diagnostic mode not supported */ #endif /* BCMCCX */ -#define WLC_E_PRUNE_AUTH_RESP_MAC 20 /* suppress auth resp by MAC filter */ -#define WLC_E_PRUNE_ASSOC_RETRY_DELAY 21 /* MBO assoc retry delay */ -#define WLC_E_PRUNE_RSSI_ASSOC_REJ 22 /* OCE RSSI-based assoc rejection */ -#define WLC_E_PRUNE_MAC_AVOID 23 /* AP's MAC addr is in STA's MAC avoid list */ -#define WLC_E_PRUNE_TRANSITION_DISABLE 24 /* AP's Transition Disable Policy */ +#define WLC_E_PRUNE_AUTH_RESP_MAC 20u /* suppress auth resp by MAC filter */ +#define WLC_E_PRUNE_ASSOC_RETRY_DELAY 21u /* MBO assoc retry delay */ +#define WLC_E_PRUNE_RSSI_ASSOC_REJ 22u /* OCE RSSI-based assoc rejection */ +#define WLC_E_PRUNE_MAC_AVOID 23u /* AP's MAC addr is in STA's MAC avoid list */ +#define WLC_E_PRUNE_TRANSITION_DISABLE 24u /* AP's Transition Disable Policy */ +#define WLC_E_PRUNE_WRONG_COUNTRY_CODE 25u /* Prune AP due to Wrong Country Code */ +#define WLC_E_PRUNE_CHANNEL_NOT_IN_VLP 26u /* Prune AP due to Chanspec not in VLP cat */ +#define WLC_E_PRUNE_MFP_COMPAT_MISMATCH 27u /* Prune AP due to MFP compatibility mismatch */ +#define WLC_E_PRUNE_CHAN_MISMATCH 28u /* Prune AP due to channel mismatch */ +#define WLC_E_PRUNE_MSTA 29u /* mSTA: Prune join to AP from multiple bsscfgs */ +#define WLC_E_PRUNE_BLIST_BTM 30u /* Prune AP due to BTM Black listing */ +#define WLC_E_PRUNE_BCN_MUTE_LOW_RSSI 31u /* Prune low rssi beacon muted AP */ +#define WLC_E_PRUNE_6G_RSN_MISMATCH 32u /* Prune AP due to RSN mismatch in 6G */ +#define WLC_E_PRUNE_INVALID_CHAN 33u /* Prune AP due to invalid channel */ +#define WLC_E_PRUNE_MESH_CFG_MISMATCH 34u /* Prune due to Mesh AP config mismatch */ +#define WLC_E_PRUNE_6G_RNR_INVALID_CHAN 35u /* Prune RNR due to invalid channel reporting */ +#define WLC_E_PRUNE_BY_OWE 36u /* Pruned by OWE */ +#define WLC_E_PRUNE_AP_RESTRICT_POLICY 37u /* Prune by AP restrict policy */ +#define WLC_E_PRUNE_SAE_PWE_PWDID 38u /* Prune by SAE PWE/PWD ID restriction */ +#define WLC_E_PRUNE_SAE_TRANSITION_DISABLE 39u /* Prune by SAE transition disable */ +#define WLC_E_PRUNE_BCNPROT_DISABLED 40u /* Prune AP due to no Beacon protection */ /* WPA failure reason codes carried in the WLC_E_PSK_SUP event */ #define WLC_E_SUP_OTHER 0 /* Other reason */ @@ -578,6 +604,9 @@ typedef struct wl_event_sdb_trans { #define WLC_E_SUP_KEY_INSTALL_FAIL 20 /* Buffered key install failure */ #define WLC_E_SUP_PTK_UPDATE 21 /* PTK update */ #define WLC_E_SUP_MSG1_PMKID_MISMATCH 22 /* MSG1 PMKID not matched to PMKSA cache list */ +#define WLC_E_SUP_GTK_UPDATE 23 /* GTK update */ +#define WLC_E_SUP_KDK_UPDATE_FAIL 24 /* KDK update failure */ +#define WLC_E_SUP_MSG3_NO_MLO_GTK 25 /* encapsulated MLO GTK missing from msg 3 */ /* event msg for WLC_E_SUP_PTK_UPDATE */ typedef struct wlc_sup_ptk_update { @@ -637,11 +666,6 @@ typedef struct wlc_wsec_event { * WLC_E_ACTION_FRAME_RX */ -#ifdef WLAWDL -#define WLC_E_AWDL_SCAN_START 1 /* Scan start indication to host */ -#define WLC_E_AWDL_SCAN_DONE 0 /* Scan Done indication to host */ -#endif /* WLAWDL */ - #define MAX_PHY_CORE_NUM 4u #define BCM_RX_FRAME_DATA_VERSION_2 2u @@ -701,10 +725,6 @@ typedef struct wl_event_data_natoe { #define WLC_E_IF_ROLE_P2P_GO 3 /* P2P Group Owner */ #define WLC_E_IF_ROLE_P2P_CLIENT 4 /* P2P Client */ -#ifdef WLAWDL -#define WLC_E_IF_ROLE_AWDL 7 /* AWDL */ -#endif /* WLAWDL */ - #define WLC_E_IF_ROLE_IBSS 8 /* IBSS */ #define WLC_E_IF_ROLE_NAN 9 /* NAN */ @@ -735,6 +755,7 @@ typedef struct wl_event_wa_lqm { /* WLC_E_IF flag */ #define WLC_E_IF_FLAGS_BSSCFG_NOIF 0x1 /* no host I/F creation needed */ +#define WLC_E_IF_FLAGS_MESH_USE 0x2 /* interface uses mesh */ /* Reason codes for LINK */ /* Reason codes for LINK */ @@ -746,6 +767,7 @@ typedef struct wl_event_wa_lqm { #define WLC_E_LINK_REASSOC_ROAM_FAIL 6 /* Link down due to reassoc roaming failed */ #define WLC_E_LINK_LOWRSSI_ROAM_FAIL 7 /* Link down due to Low rssi roaming failed */ #define WLC_E_LINK_NO_FIRST_BCN_RX 8 /* Link down due to 1st beacon rx failure */ +#define WLC_E_LINK_COUNTRY_CHANGE 9 /* Link down due to Country Code Change */ /* WLC_E_NDIS_LINK event data */ typedef BWL_PRE_PACKED_STRUCT struct ndis_link_parms { @@ -765,6 +787,40 @@ typedef BWL_PRE_PACKED_STRUCT struct ndis_link_parms { #define WLC_E_TDLS_PEER_CONNECTED 1 #define WLC_E_TDLS_PEER_DISCONNECTED 2 +#ifdef WLTDLS +/* Make sure to update reason code strings corresponding to the below enum + * wl_cfgvif.c >> static const char *teardown_rc_str[]; + */ +/* reason codes for TDLS teardown */ +enum { + TDLS_DISCONN_RC_DUMMY = 0, + TDLS_DISCONN_RC_RCVD_TEARDOWN = 1, + TDLS_DISCONN_RC_TPKSA_LIFETIME_EXPIERED = 2, + TDLS_DISCONN_RC_MAX_HEARTBEAT_MISSED = 3, + TDLS_DISCONN_RC_PTI_RESP_TIMEDOUT = 4, + TDLS_DISCONN_RC_NO_ACTIVITY = 5, + TDLS_DISCONN_RC_LOW_RSSI = 6, + TDLS_DISCONN_RC_BY_THE_HOST = 7, + TDLS_DISCONN_RC_BY_THE_FW = 8, + TDLS_DISCONN_RC_UNSPECIFIED = 9, + TDLS_DISCONN_RC_MAX = 10 +}; + +/* string mapping table for TDLS teardown reason codes */ +#define TDLS_TEARDOWN_RC_STRINGS { \ + "RC_DUMMY", \ + "RC_RCVD_TEARDOWN", \ + "RC_TPKSA_LIFETIME_EXPIERED", \ + "RC_MAX_HEARTBEAT_MISSED", \ + "RC_PTI_RESP_TIMEOUT", \ + "RC_NO_ACTIVITY", \ + "RC_LOW_RSSI", \ + "RC_BY_THE_HOST", \ + "RC_BY_THE_FW", \ + "RC_UNSPECIFIED", \ +} +#endif /* WLTDLS */ + /* reason codes for WLC_E_RMC_EVENT event */ #define WLC_E_REASON_RMC_NONE 0 #define WLC_E_REASON_RMC_AR_LOST 1 @@ -802,86 +858,14 @@ typedef struct wlc_phy_cal_info { uint8 slice; } wlc_phy_cal_info_t; -#ifdef WLAWDL -/* WLC_E_AWDL_EVENT subtypes */ -#define WLC_E_AWDL_SCAN_STATUS 0 -#define WLC_E_AWDL_RX_ACT_FRAME 1 -#define WLC_E_AWDL_RX_PRB_RESP 2 -#define WLC_E_AWDL_PHYCAL_STATUS 3 -#define WLC_E_AWDL_WOWL_NULLPKT 4 -#define WLC_E_AWDL_OOB_AF_STATUS 5 -/* WLC_E_AWDL_RANGING_RESULTS will be removed and only WLC_E_AWDL_UNUSED will be here - * Keeping both of them to avoid compilation errot on trunk - * It will be removed after wlc_ranging merge from IGUANA - */ -#define WLC_E_AWDL_RANGING_RESULTS 6 -#define WLC_E_AWDL_UNUSED 6 -#define WLC_E_AWDL_SUB_PEER_STATE 7 -#define WLC_E_AWDL_SUB_INTERFACE_STATE 8 -#define WLC_E_AWDL_UCAST_AF_TXSTATUS 9 -#define WLC_E_AWDL_NAN_CLUSTER_MERGE 10 -#define WLC_E_AWDL_NAN_RX_BEACON 11 -#define WLC_E_AWDL_SD_DISCOVERY_RESULT 12 -#define WLC_E_AWDL_SD_REPLIED 13 -#define WLC_E_AWDL_SD_TERMINATED 14 -#define WLC_E_AWDL_SD_RECEIVE 15 -#define WLC_E_AWDL_SD_VNDR_IE 16 -#define WLC_E_AWDL_SD_DEVICE_STATE_IE 17 -#define WLC_E_AWDL_DFSP_NOTIF 18 -#define WLC_E_AWDL_DFSP_SUSPECT 19 -#define WLC_E_AWDL_DFSP_RESUME 20 - -/* WLC_E_AWDL_SCAN_STATUS status values */ -#define WLC_E_AWDL_SCAN_START 1 /* Scan start indication to host */ -#define WLC_E_AWDL_SCAN_DONE 0 /* Scan Done indication to host */ -#define WLC_E_AWDL_PHYCAL_START 1 /* Phy calibration start indication to host */ -#define WLC_E_AWDL_PHYCAL_DONE 0 /* Phy calibration done indication to host */ - -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 subscribe_id; /* local subscribe instance id */ - uint8 publish_id; /* publiser's insance id */ - struct ether_addr addr; /* publsher's address */ - uint8 service_info_len; /* length of the service specific information in data[] */ - uint8 data[1]; /* service specific info */ -} BWL_PRE_PACKED_STRUCT awdl_sd_discovery_result_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 instance_id; - struct ether_addr addr; /* publsher's address */ -} BWL_PRE_PACKED_STRUCT awdl_sd_replied_event_t; - -#define AWDL_SD_TERM_REASON_TIMEOUT 1 -#define AWDL_SD_TERM_REASON_USERREQ 2 -#define AWDL_SD_TERM_REASON_FAIL 3 -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 instance_id; /* publish instance id */ - uint8 reason; /* 1=timeout, 2=user request, 3=failure */ -} BWL_PRE_PACKED_STRUCT awdl_sd_term_event_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - uint8 instance_id; /* local publish/subscribe instance id */ - uint8 sender_instance_id; - struct ether_addr addr; /* sender's address */ - uint8 service_info_len; /* length of the service specific information in data[] */ - uint8 data[1]; /* service specific info */ -} BWL_PRE_PACKED_STRUCT awdl_sd_receive_t; - -typedef BWL_PRE_PACKED_STRUCT struct { - struct ether_addr addr; /* sender's address */ - uint16 len; /* length of data[] */ - uint8 data[1]; /* vndr specific info */ -} BWL_PRE_PACKED_STRUCT awdl_sd_vndr_ie_event_t; - -#endif /* WLAWDL */ - /* GAS event data */ typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas { - uint16 channel; /* channel of GAS protocol */ - uint8 dialog_token; /* GAS dialog token */ - uint8 fragment_id; /* fragment id */ - uint16 status_code; /* status code on GAS completion */ - uint16 data_len; /* length of data to follow */ - uint8 data[1]; /* variable length specified by data_len */ + uint16 channel; /* channel of GAS protocol */ + uint8 dialog_token; /* GAS dialog token */ + uint8 fragment_id; /* fragment id */ + uint16 status_code; /* status code on GAS completion */ + uint16 data_len; /* length of data to follow */ + uint8 data[BCM_FLEX_ARRAY]; /* variable length specified by data_len */ } BWL_POST_PACKED_STRUCT wl_event_gas_t; /* service discovery TLV */ @@ -895,9 +879,9 @@ typedef BWL_PRE_PACKED_STRUCT struct wl_sd_tlv { /* service discovery event data */ typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd { - uint16 channel; /* channel */ - uint8 count; /* number of tlvs */ - wl_sd_tlv_t tlv[1]; /* service discovery TLV */ + uint16 channel; /* channel */ + uint8 count; /* number of tlvs */ + wl_sd_tlv_t tlv[BCM_FLEX_ARRAY]; /* service discovery TLV */ } BWL_POST_PACKED_STRUCT wl_event_sd_t; /* WLC_E_PKT_FILTER event sub-classification codes */ @@ -958,7 +942,7 @@ typedef BWL_PRE_PACKED_STRUCT struct proxd_event_data { /* raw Fine Time Measurements (ftm) data */ uint16 ftm_unit; /* ftm cnt resolution in picoseconds , 6250ps - default */ uint16 ftm_cnt; /* num of rtd measurments/length in the ftm buffer */ - ftm_sample_t ftm_buff[1]; /* 1 ... ftm_cnt */ + ftm_sample_t ftm_buff[BCM_FLEX_ARRAY]; /* 1 ... ftm_cnt */ } BWL_POST_PACKED_STRUCT wl_proxd_event_data_t; typedef BWL_PRE_PACKED_STRUCT struct proxd_event_ts_results { @@ -968,35 +952,9 @@ typedef BWL_PRE_PACKED_STRUCT struct proxd_event_ts_results { uint8 err_code; /* error classification */ uint8 TOF_type; /* one way or two way TOF */ uint16 ts_cnt; /* number of timestamp measurements */ - ts_sample_t ts_buff[1]; /* Timestamps */ + ts_sample_t ts_buff[BCM_FLEX_ARRAY]; /* Timestamps */ } BWL_POST_PACKED_STRUCT wl_proxd_event_ts_results_t; -#ifdef WLAWDL -/* WLC_E_AWDL_AW event data */ -typedef BWL_PRE_PACKED_STRUCT struct awdl_aws_event_data { - uint32 fw_time; /* firmware PMU time */ - struct ether_addr current_master; /* Current master Mac addr */ - uint16 aw_counter; /* AW seq# */ - uint8 aw_ext_count; /* AW extension count */ - uint8 aw_role; /* AW role */ - uint8 flags; /* AW event flag */ - uint16 aw_chan; - uint8 infra_rssi; /* rssi on the infra channel */ - uint32 infra_rxbcn_count; /* number of beacons received */ - struct ether_addr top_master; /* Top master */ -} BWL_POST_PACKED_STRUCT awdl_aws_event_data_t; - -/* For awdl_aws_event_data_t.flags */ -#define AWDL_AW_LAST_EXT 0x01 - -/* WLC_E_AWDL_OOB_AF_STATUS event data */ -typedef BWL_PRE_PACKED_STRUCT struct awdl_oob_af_status_data { - uint32 tx_time_diff; - uint16 pkt_tag; - uint8 tx_chan; -} BWL_POST_PACKED_STRUCT awdl_oob_af_status_data_t; -#endif /* WLAWDL */ - /* Video Traffic Interference Monitor Event */ #define INTFER_EVENT_VERSION 1 #define INTFER_STREAM_TYPE_NONTCP 1 @@ -1012,9 +970,9 @@ typedef struct wl_intfer_event { typedef struct wl_rrm_event { int16 version; int16 len; - int16 cat; /* Category */ + int16 cat; /* Category */ int16 subevent; - char payload[1]; /* Measurement payload */ + char payload[BCM_FLEX_ARRAY]; /* Measurement payload */ } wl_rrm_event_t; /* WLC_E_PSTA_PRIMARY_INTF_IND event data */ @@ -1034,7 +992,7 @@ typedef struct wl_dpsta_intf_event { /* ********** NAN protocol events/subevents ********** */ #ifndef NAN_EVENT_BUFFER_SIZE -#define NAN_EVENT_BUFFER_SIZE 512 /* max size */ +#define NAN_EVENT_BUFFER_SIZE 1600 /* max size */ #endif /* NAN_EVENT_BUFFER_SIZE */ /* NAN Events sent by firmware */ @@ -1091,11 +1049,24 @@ typedef enum wl_nan_events { WL_NAN_EVENT_DISC_CACHE_TIMEOUT = 46, /* Disc cache timeout */ WL_NAN_EVENT_OOB_AF_TXS = 47, /* OOB AF transmit status */ WL_NAN_EVENT_OOB_AF_RX = 48, /* OOB AF receive event */ + WL_NAN_EVENT_NMI_ADDR = 49, /* NMI address change event */ + WL_NAN_EVENT_SCHED_CHANGE = 50, /* Sched change event */ + + /* Pairing events */ + WL_NAN_EVENT_PAIRING_IND = 51, /* Pairing start indication, at responder */ + WL_NAN_EVENT_PAIRING_END = 52, /* Pairing ended */ + WL_NAN_EVENT_PAIRING_ESTBL = 53, /* Pairing Established */ + + WL_NAN_EVENT_OOB_AF_RXTIMEOUT = 54, /* OOB AF rx timeout */ /* keep WL_NAN_EVENT_INVALID as the last element */ WL_NAN_EVENT_INVALID /* delimiter for max value */ } nan_app_events_e; +/* WL_NAN_EVENT_STOP reason codes */ +#define WL_NAN_EVENT_STOP_HOSTCMD 0u +#define WL_NAN_EVENT_STOP_CNTRY_CODE_CHNG 1u + /* remove after precommit */ #define NAN_EV_MASK(ev) (1 << (ev - 1)) #define IS_NAN_EVT_ON(var, evt) ((var & (1 << (evt-1))) != 0) @@ -1111,7 +1082,8 @@ typedef enum wl_nan_events { typedef enum wl_scan_events { WL_SCAN_START = 1, - WL_SCAN_END = 2 + WL_SCAN_END = 2, + WL_SCAN_ADD = 3 } wl_scan_events; /* WLC_E_ULP event data */ @@ -1229,6 +1201,26 @@ typedef struct { uint8 data[]; /* type specific data; could be empty */ } wl_event_fbt_t; +#define WL_TWT_EVENT_HDR_LEN (SIZE_OF(wl_twt_event_t, version) + SIZE_OF(wl_twt_event_t, length)) +#define WL_TWT_EVENT_BASE_LEN sizeof(wl_twt_event_t) +typedef enum wl_twt_event_type { + WL_TWT_EVENT_SETUP = 1, + WL_TWT_EVENT_TEARDOWN = 2, + WL_TWT_EVENT_INFOFRM = 3, + WL_TWT_EVENT_NOTIFY = 4 +} wl_twt_event_type_t; + +#define WL_TWT_EVENT_VER 0u + +/* WLC_E_TWT event Main-event */ +typedef struct wl_twt_event { + uint16 version; + uint16 length; /* the byte count of fields from 'event_type' onwards */ + uint8 event_type; /* See sub event types in wl_twt_event_type_t */ + uint8 PAD[3]; + uint8 event_info[]; +} wl_twt_event_t; + /* TWT Setup Completion is designed to notify the user of TWT Setup process * status. When 'status' field is value of BCME_OK, the user must check the * 'setup_cmd' field value in 'wl_twt_sdesc_t' structure that at the end of @@ -1242,12 +1234,14 @@ typedef struct { /* TWT Setup Reason code */ typedef enum wl_twt_setup_rc { - WL_TWT_SETUP_RC_ACCEPT = 0, /* TWT Setup Accepted */ - WL_TWT_SETUP_RC_REJECT = 1, /* TWT Setup Rejected */ - WL_TWT_SETUP_RC_TIMEOUT = 2, /* TWT Setup Time-out */ - WL_TWT_SETUP_RC_IE = 3, /* TWT Setup IE Validation failed */ - WL_TWT_SETUP_RC_PARAMS = 4, /* TWT Setup IE Params invalid */ - WL_TWT_SETUP_RC_ERROR = 5, /* Generic Error cases */ + WL_TWT_SETUP_RC_ACCEPT = 0u, /* TWT Setup Accepted */ + WL_TWT_SETUP_RC_REJECT = 1u, /* TWT Setup Rejected */ + WL_TWT_SETUP_RC_TIMEOUT = 2u, /* TWT Setup Time-out */ + WL_TWT_SETUP_RC_IE = 3u, /* TWT Setup IE Validation failed */ + WL_TWT_SETUP_RC_PARAMS = 4u, /* TWT Setup IE Params invalid */ + WL_TWT_SETUP_RC_INF_UNAVAIL = 5u, /* TWT Info Frame Disabled Peer device */ + /* Any new reason code add before this */ + WL_TWT_SETUP_RC_ERROR = 255u, /* Generic Error cases */ } wl_twt_setup_rc_t; /* TWT Setup Completion event data */ @@ -1256,7 +1250,8 @@ typedef struct wl_twt_setup_cplt { uint16 length; /* the byte count of fields from 'dialog' onwards */ uint8 dialog; /* Setup frame dialog token */ uint8 reason_code; /* see WL_TWT_SETUP_RC_XXXX */ - uint8 pad[2]; + uint8 configID; /* TWT Configuration ID */ + uint8 pad[1]; int32 status; /* wl_twt_sdesc_t desc; - defined in wlioctl.h */ } wl_twt_setup_cplt_t; @@ -1265,24 +1260,27 @@ typedef struct wl_twt_setup_cplt { /* TWT teardown Reason code */ typedef enum wl_twt_td_rc { - WL_TWT_TD_RC_SUCCESS = 0, /* Teardown complete Successful */ - WL_TWT_TD_RC_HOST = 1, /* Teardown triggered by Host */ - WL_TWT_TD_RC_PEER = 2, /* Peer initiated teardown */ - WL_TWT_TD_RC_MCHAN = 3, /* Teardown due to MCHAN Active */ - WL_TWT_TD_RC_MCNX = 4, /* Teardown due to MultiConnection */ - WL_TWT_TD_RC_SETUP_FAIL = 5, /* Setup fail midway. Teardown all connections */ - WL_TWT_TD_RC_SCHED = 6, /* Teardown by TWT Scheduler */ - WL_TWT_TD_RC_CSA = 7, /* Teardown due to CSA */ - WL_TWT_TD_RC_BTCX = 8, /* Teardown due to BTCX */ - WL_TWT_TD_RC_ERROR = 9, /* Generic Error cases */ + WL_TWT_TD_RC_HOST = 0u, /* Teardown triggered by Host */ + WL_TWT_TD_RC_PEER = 1u, /* Peer initiated teardown */ + WL_TWT_TD_RC_MCHAN = 2u, /* Teardown due to MCHAN Active */ + WL_TWT_TD_RC_MCNX = 3u, /* Teardown due to MultiConnection */ + WL_TWT_TD_RC_CSA = 4u, /* Teardown due to CSA */ + WL_TWT_TD_RC_BTCX = 5u, /* Teardown due to BTCX */ + WL_TWT_TD_RC_SETUP_FAIL = 6u, /* Setup fail midway. Teardown all connections */ + WL_TWT_TD_RC_SCHED = 7u, /* Teardown by TWT Scheduler */ + WL_TWT_TD_RC_TIMEOUT = 8u, /* NoAck/Ack timeout for Teardown */ + WL_TWT_TD_RC_PM_OFF = 9u, /* Teardown due to PM Mode 0 */ + /* Any new reason code add before this */ + WL_TWT_TD_RC_ERROR = 255u, /* Generic Error cases */ } wl_twt_td_rc_t; /* TWT Teardown complete event data */ typedef struct wl_twt_teardown_cplt { uint16 version; - uint16 length; /* the byte count of fields from 'reason_code' onwards */ + uint16 length; /* the byte count of fields from 'reason_code' onwards */ uint8 reason_code; /* WL_TWT_TD_RC_XXXX */ - uint8 pad[3]; + uint8 configID; /* TWT Configuration ID */ + uint8 pad[2]; int32 status; /* wl_twt_teardesc_t; - defined in wlioctl.h */ } wl_twt_teardown_cplt_t; @@ -1291,21 +1289,51 @@ typedef struct wl_twt_teardown_cplt { /* TWT Info Reason code */ typedef enum wl_twt_info_rc { - WL_TWT_INFO_RC_HOST = 0, /* Host initiated Info complete */ - WL_TWT_INFO_RC_PEER = 1, /* Peer initiated TWT Info */ - WL_TWT_INFO_RC_ERROR = 2, /* generic error conditions */ + WL_TWT_INFO_RC_HOST = 0u, /* Host initiated Info complete */ + WL_TWT_INFO_RC_PEER = 1u, /* Peer initiated TWT Info */ + WL_TWT_INFO_RC_TIMEOUT = 2u, /* NoAck/Ack Timeout for TWT info Frame */ + /* Any new reason code add before this */ + WL_TWT_INFO_RC_ERROR = 255u, /* generic error conditions */ } wl_twt_info_rc_t; /* TWT Info complete event data */ typedef struct wl_twt_info_cplt { uint16 version; uint16 length; /* the byte count of fields from 'reason_code' onwards */ - uint8 reason_code; /* WL_TWT_INFO_RC_XXXX */ - uint8 pad[3]; + uint8 reason_code; /* WL_TWT_INFO_RC_XXXX */ + uint8 configID; /* TWT Configuration ID */ + uint8 pad[2]; int32 status; /* wl_twt_infodesc_t; - defined in wlioctl.h */ } wl_twt_info_cplt_t; +#define WL_TWT_NOTIFY_VER 0u +#define WL_TWT_NOTIFY_LEN sizeof(wl_twt_notify_t) +#define WL_TWT_NOTIFY_HDR_LEN (SIZE_OF(wl_twt_notify_t, version) + SIZE_OF(wl_twt_notify_t, length)) + +typedef enum wl_twt_notification { + WL_TWT_NOTIF_ALLOW_TWT = 1, /* Dongle indication of allowing TWT setup */ +} wl_twt_notification_t; + +/* TWT notification event */ +typedef struct wl_twt_notify { + uint16 version; + uint16 length; /* the byte count of fields from 'reason_code' onwards */ + uint8 notification; + uint8 PAD[3]; +} wl_twt_notify_t; + +/* Beacon TSF Event */ +typedef struct wl_bcn_tsf { + uint16 version; + uint16 length; /* the byte count of fields from 'reason_code' onwards */ + uint32 bcn_tsf_h; + uint32 bcn_tsf_l; +} wl_bcn_tsf_t; + +#define WL_BCN_TSF_VER_0 0u +#define WL_BCN_TSF_LEN sizeof(wl_bcn_tsf_t) + #define WL_INVALID_IE_EVENT_VERSION 0 /* Invalid IE Event data */ @@ -1335,6 +1363,25 @@ typedef enum ie_error_code { /* reason of channel switch */ typedef enum { +/* The complete enum definition should be moved to here + * When adding new one, please add it here + */ +#define WL_CHANSW_REASONS_0TO13_INCLUDED +#if defined(WL_CHANSW_REASONS_0TO13_INCLUDED) + CHANSW_UNKNOWN = 0, /* channel switch due to unknown reason */ + CHANSW_SCAN = 1, /* channel switch due to scan */ + CHANSW_PHYCAL = 2, /* channel switch due to phy calibration */ + CHANSW_INIT = 3, /* channel set at WLC up time */ + CHANSW_ASSOC = 4, /* channel switch due to association */ + CHANSW_ROAM = 5, /* channel switch due to roam */ + CHANSW_MCHAN = 6, /* channel switch triggered by mchan module */ + CHANSW_IOVAR = 7, /* channel switch due to IOVAR */ + CHANSW_CSA_DFS = 8, /* channel switch due to chan switch announcement from AP */ + CHANSW_APCS = 9, /* Channel switch from AP channel select module */ + CHANSW_FBT = 11, /* Channel switch from FBT module for action frame response */ + CHANSW_UPDBW = 12, /* channel switch at update bandwidth */ + CHANSW_ULB = 13, /* channel switch at ULB */ +#endif /* WL_CHANSW_REASONS_0TO13_INCLUDED */ CHANSW_DFS = 10, /* channel switch due to DFS module */ CHANSW_HOMECH_REQ = 14, /* channel switch due to HOME Channel Request */ CHANSW_STA = 15, /* channel switch due to STA */ @@ -1344,20 +1391,13 @@ typedef enum { CHANSW_NAN_DISC = 19, /* channel switch due to NAN Disc */ CHANSW_NAN_SCHED = 20, /* channel switch due to NAN Sched */ -#ifdef WLAWDL - CHANSW_AWDL_AW = 21, /* channel switch due to AWDL aw */ - CHANSW_AWDL_SYNC = 22, /* channel switch due to AWDL sync */ - CHANSW_AWDL_CAL = 23, /* channel switch due to AWDL Cal */ - CHANSW_AWDL_PSF = 24, /* channel switch due to AWDL PSF */ - CHANSW_AWDL_OOB_AF = 25, /* channel switch due to AWDL OOB action frame */ -#endif /* WLAWDL */ - CHANSW_TDLS = 26, /* channel switch due to TDLS */ CHANSW_PROXD = 27, /* channel switch due to PROXD */ CHANSW_SLOTTED_BSS = 28, /* channel switch due to slotted bss */ CHANSW_SLOTTED_CMN_SYNC = 29, /* channel switch due to Common Sync Layer */ CHANSW_SLOTTED_BSS_CAL = 30, /* channel switch due to Cal request from slotted bss */ - CHANSW_MAX_NUMBER = 31 /* max channel switch reason */ + CHANSW_PASN = 31, /* channel switch due to PASN authentication */ + CHANSW_MAX_NUMBER = 32 /* max channel switch reason */ } wl_chansw_reason_t; #define CHANSW_REASON(reason) (1 << reason) @@ -1564,17 +1604,25 @@ typedef struct wlc_obss_hw_event_data { uint16 available_chanspec; /* Contains band, channel and BW info */ } wlc_obss_hw_event_data_t; -/* status when WLC_E_OBSS_DETECTION */ -#define WLC_OBSS_BW_UPDATED 1 /* Sent when BW is update at SW */ -#define WLC_OBSS_BW_AVAILABLE 2 /* Sent When a change in BW is detected / noticed */ +/* status for WLC_E_OBSS_DETECTION */ +/* Sent when OMI is complete and mitigation filter is applied */ +#define WLC_OBSS_BW_UPDATED_FILTER 1u +/* Temporarily keeping old MACRO */ +#define WLC_OBSS_BW_UPDATED 1u +/* Currently not being used */ +#define WLC_OBSS_BW_AVAILABLE 2u +/* Sent when OMI is complete and mitigation filter is not applied */ +#define WLC_OBSS_BW_UPDATED_NO_FILTER 3u /* WLC_E_DYNSAR event structure version */ -#define WL_DYNSAR_VERSION 1 +#define WL_DYNSAR_VERSION 1u +#define WL_DYNSAR_VERSION_2 2u /* bits used in status field */ #define WL_STATUS_DYNSAR_PWR_OPT (1 << 0) /* power optimized */ #define WL_STATUS_DYNSAR_FAILSAFE (1 << 1) /* radio is using failsafe cap values */ #define WL_STATUS_DYNSAR_NOMUTE_OPT (1 << 2) /* ack mute */ +#define WL_STATUS_DYNSAR_TXDC_OPT (1 << 3) /* limit txdc */ /* Event structure for WLC_E_DYNSAR */ typedef struct wl_event_dynsar { @@ -1586,15 +1634,42 @@ typedef struct wl_event_dynsar { uint8 status; /* WL_STATUS_DYNSAR_XXX, to indicate which optimization * is being applied */ - uint8 pad; + uint8 fs_reason; /* failsafe reason */ } wl_event_dynsar_t; -/* status when WLC_E_AP_BCN_MUTE event is sent */ +/* Reason code when WLC_E_AP_BCN_MUTE event is sent */ #define BCN_MUTE_MITI_ACTIVE 1u /* Mitigation is activated when probe response received * but Beacon is not received */ #define BCN_MUTE_MITI_END 2u /* Sent when beacon is received */ #define BCN_MUTE_MITI_TIMEOUT 3u /* Mitigation period is reached */ +#define BCN_MUTE_MITI_FAILED 4u /* Mitigation attempt failed */ + +/* Status code for sending event */ +#define BCN_MUTE_MITI_UNKNOWN 0u /* Mitigation status unknown */ +#define BCN_MUTE_MITI_ASSOC_COMP 1u /* Mitigation during Assoc phase */ +#define BCN_MUTE_MITI_BCN_LOST 2u /* Mitigation due to beacon lost */ +#define BCN_MUTE_MITI_BCN_RECV 3u /* Mitigation end due to bcn reception */ +#define BCN_MUTE_MITI_ROAM 4u /* Mitigation end due to Roam */ +#define BCN_MUTE_MITI_LINK_DOWN 5u /* Mitigation end due to link down */ +#define BCN_MUTE_MITI_RX_DEAUTH 6u /* Mitigation end due to AP deauth */ +#define BCN_MUTE_MITI_RX_DISASSOC 7u /* Mitigation end due to AP disassoc */ +#define BCN_MUTE_MITI_LOW_RSSI 8u /* Mitigation end due to Low RSSI */ +#define BCN_MUTE_MITI_ASSOC_COMP_RX_UPR 9u /* Assoc succeeded using UPR reception */ +#define BCN_MUTE_MITI_BCN_LOST_RX_UPR 10u /* Beacon lost and Mitigation success with + * recent UPR Reception + */ +#define BCN_MUTE_MITI_ASSOC_COMP_RX_FILS 11u /* Assoc succeeded using FILS reception */ +#define BCN_MUTE_MITI_BCN_LOST_RX_FILS 12u /* Beacon lost and Mitigation success with + * recent FILS Reception + */ +#define BCN_MUTE_MITI_NO_PRB_RESP 13u /* Beacon lost and mitigation failed due to + * no Rx probe response. + */ +#define BCN_MUTE_MITI_PRB_RESP_LOW_RSSI 14u /* Beacon lost and mitigation failed due Rx + * Probe response with Low RSSI. + */ +#define BCN_MUTE_MITI_CSA 15u /* Mitigation end due to CSA */ /* bcn_mute_miti event data */ #define WLC_BCN_MUTE_MITI_EVENT_DATA_VER_1 1u @@ -1605,6 +1680,15 @@ typedef struct wlc_bcn_mute_miti_event_data_v1 { uint8 PAD[2]; /* Pad to fit to 32 bit alignment */ } wlc_bcn_mute_miti_event_data_v1_t; +#define WLC_BCN_MUTE_MITI_EVENT_DATA_VER_2 2u +typedef struct wlc_bcn_mute_miti_event_data_v2 { + uint16 version; /* Structure version number */ + uint16 length; /* Length of the whole struct */ + uint16 uatbtt_count; /* Number of UATBTT during mitigation */ + int8 rssi; /* Mitigation Probe response RSSI */ + uint8 PAD[1]; /* Pad to fit to 32 bit alignment */ +} wlc_bcn_mute_miti_event_data_v2_t; + /* bcn_drift event data */ #define WLC_BCN_DRIFT_EVENT_DATA_VER_1 (1u) typedef struct wlc_bcn_drift_event_data_v1 { @@ -1614,4 +1698,97 @@ typedef struct wlc_bcn_drift_event_data_v1 { int16 jitter; /* in ms */ } wlc_bcn_drift_event_data_v1_t; +/** Channel Switch Announcement param */ +typedef struct wl_csa_switch_event { + uint8 mode; /**< value 0 or 1 */ + uint8 count; /**< count # of beacons before switching */ + chanspec_t chspec; /**< chanspec */ + uint8 reg; /**< regulatory class */ + uint8 frame_type; /**< csa frame type, unicast or broadcast */ + uint8 PAD[2]; /**> padding to 32-bit struct alignment */ +} wl_csa_switch_event_t; + +/** Channel Switch Announcement event data */ +typedef struct wl_csa_event { + wl_csa_switch_event_t csa; /**< Channel Switch Announcement parameters */ + uint32 switch_time; /**< csa switch time: TSF + BI * count, msec */ +} wl_csa_event_t; + +/* SIB sub events */ + +/* Event structure for WLC_E_MSCS */ +typedef struct wl_event_mscs { + uint16 version; /* structure version */ + uint16 length; /* length of this structure */ + uint8 data[]; /* MSCS event data */ + /* The data is of type wl_qos_rav_mscs_config_t -- defined in wlioctl.h */ +} wl_event_mscs_t; + +/* WLC_E_MSCS event structure version */ +#define WL_MSCS_EVENT_VERSION 1u + +/* MLO link information (WLC_E_MLO_LINK_INFO) event data */ +#define WL_MLO_LINK_INFO_EVENT_VERSION_1 (1u) + +typedef enum wl_mlo_link_info_opcode { + WL_MLO_LINK_INFO_OPCODE_ADD = 1, /* MLO links addition */ + WL_MLO_LINK_INFO_OPCODE_DEL = 2 /* MLO links deletion */ +} wl_mlo_link_info_opcode_t; + +typedef enum wl_mlo_link_info_role { + WL_MLO_LINK_INFO_ROLE_STA = 1, /* infrastructure mode station */ + WL_MLO_LINK_INFO_ROLE_AP = 2 /* access point */ +} wl_mlo_link_info_role_t; + +/* MLO per link information structure */ +typedef struct wl_mlo_per_link_info_v1 { + uint8 if_idx; /* RTE virtual device index (for dongle) */ + uint8 cfg_idx; /* bsscfg index */ + uint8 link_id; /* link identifier - AP managed unique identifier */ + uint8 link_idx; /* link index - local link config index */ + struct ether_addr link_addr; /* link specific address */ + uint8 PAD[2]; +} wl_mlo_per_link_info_v1_t; + +/* MLO link information event structure */ +typedef struct wl_mlo_link_info_event_v1 { + uint16 version; /* structure version */ + uint16 length; /* length of this structure */ + uint8 opcode; /* link opcode - wl_mlo_link_info_opcode */ + uint8 role; /* link role - wl_mlo_link_info_role */ + struct ether_addr mld_addr; /* mld addres */ + uint8 num_links; /* number of operative links */ + uint8 PAD[3]; + wl_mlo_per_link_info_v1_t link_info[]; /* per link information */ +} wl_mlo_link_info_event_v1_t; + +/* ===== C2C event definitions ===== */ +#define C2C_EVENT_BUFFER_SIZE 1024u +#define IS_C2C_EVT_ON(param, evt) ((param) & (1u << (evt))) +#define C2C_ALLOWED_EVENT_MASK (1u << WL_EVT_C2C_START | \ + (1u << WL_EVT_C2C_END) | (1u << WL_EVT_C2C_PRE_EXPIRY) | \ + (1u << WL_EVT_C2C_EXTN) | \ + (1u << WL_EVT_C2C_CACHE_ADD) | (1u << WL_EVT_C2C_CACHE_DEL) | \ + (1u << WL_EVT_C2C_MUTE_ON) | (1u << WL_EVT_C2C_MUTE_OFF)) + +/* WLC_E_C2C subevent ID */ +typedef enum wl_c2c_events { + WL_EVT_C2C_START, /* first enabling signal, c2c starts */ + WL_EVT_C2C_END, /* enabling signal expired, c2c ends */ + WL_EVT_C2C_PRE_EXPIRY, /* esig expiring soon; do scan or let expire */ + WL_EVT_C2C_EXTN, /* received new esig, c2c continues */ + WL_EVT_C2C_CACHE_ADD, /* added new LPI AP to cache */ + WL_EVT_C2C_CACHE_DEL, /* removed LPI AP from cache */ + WL_EVT_C2C_MUTE_ON, /* p2p tx is muted for 6GHz channels */ + WL_EVT_C2C_MUTE_OFF /* p2p tx unmuted for 6GHz channels */ +} wl_c2c_events_e; + +/* OMI ULMU disabled reason code update event */ +#define WL_ULMU_DISABLE_REASON_UPD_EVENT_VERSION_1 (1u) +typedef struct wl_ulmu_disable_reason_upd_event_v1 { + uint16 version; + uint16 length; + uint16 ulmu_disable_reason; + uint8 PAD[2]; +} wl_ulmu_disable_reason_upd_event_v1_t; #endif /* _BCMEVENT_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmicmp.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmicmp.h old mode 100755 new mode 100644 index 31e809afb6bd..3a58a850617a --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmicmp.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmicmp.h @@ -1,7 +1,7 @@ /* * Fundamental constants relating to ICMP Protocol * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmigmp.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmigmp.h new file mode 100644 index 000000000000..559c964b86cb --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmigmp.h @@ -0,0 +1,74 @@ +/* + * Fundamental constants relating to IGMP Protocol + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _bcmigmp_h_ +#define _bcmigmp_h_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +/* This marks the start of a packed structure section. */ +#include + +#define IGMP_V2 2u +#define IGMP_V3 3u + +/* These fields are stored in network order */ +BWL_PRE_PACKED_STRUCT struct igmpv2_hdr { + uint8 type; /* type */ + uint8 max_resp_time; /* time */ + uint16 chksum; /* checksum */ + uint8 group_addr[IPV4_ADDR_LEN]; /* group address */ +} BWL_POST_PACKED_STRUCT; + +/* these fields are stored in network order */ +BWL_PRE_PACKED_STRUCT struct igmpv3_hdr { + uint8 type; /* type */ + uint8 rsvd_1; /* reserved */ + uint16 chksum; /* checksum */ + uint16 rsvd_2; /* reserved */ + uint16 num_groups; /* number of groups */ + uint8 data[]; /* data */ +} BWL_POST_PACKED_STRUCT; + +#define IGMPV3_MODE_IS_INCLUDE 1u +#define IGMPV3_MODE_IS_EXCLUDE 2u +#define IGMPV3_CHANGE_TO_INCLUDE_MODE 3u +#define IGMPV3_CHANGE_TO_EXCLUDE_MODE 4u +#define IGMPV3_ALLOW_NEW_SOURCES 5u +#define IGMPV3_BLOCK_OLD_SOURCES 6u + +/* these fields are stored in network order */ +BWL_PRE_PACKED_STRUCT struct igmpv3_group { + uint8 record_type; /* Record Type */ + uint8 aux_data_len; /* Aux Data Len */ + uint16 number_sources; /* Number of Sources */ + uint8 group_addr[IPV4_ADDR_LEN]; /* group address */ + uint8 data[]; /* data */ +} BWL_POST_PACKED_STRUCT; + +/* This marks the end of a packed structure section. */ +#include + +#endif /* #ifndef _bcmigmp_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmiov.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmiov.h old mode 100755 new mode 100644 index 05a9f583ddc2..3e5a6fa2ad6f --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmiov.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmiov.h @@ -4,7 +4,7 @@ * To be used in firmware and host apps or dhd - reducing code size, * duplication, and maintenance overhead. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -97,7 +97,7 @@ typedef int (*bcm_iov_cmd_set_t)(const bcm_iov_cmd_digest_t *dig, #define BCM_IOV_STATUS_LEN sizeof(uint32) /* batch version is indicated by setting high bit. */ -#define BCM_IOV_BATCH_MASK 0x8000 +#define BCM_IOV_BATCH_MASK 0x8000u /* * Batched commands will have the following memory layout @@ -106,41 +106,113 @@ typedef int (*bcm_iov_cmd_set_t)(const bcm_iov_cmd_digest_t *dig, * +--------+---------+--------+-------+ * version >= 0x8000 * count = number of sub-commands encoded in the iov buf + * is_set = not used. All batch sub-commands are of the same type, get or set, + * as determined by the action id passed in to the IOVAR handler bcm_iov_doiovar(). * sub-cmd one or more sub-commands for processing * Where sub-cmd is padded byte buffer with memory layout as follows * +--------+---------+-----------------------+-------------+------ * |cmd-id |length |IN(options) OUT(status)|command data |...... * +--------+---------+-----------------------+-------------+------ * cmd-id =sub-command ID - * length = length of this sub-command + * length = length of this sub-command, starting with options/status * IN(options) = On input processing options/flags for this command * OUT(status) on output processing status for this command * command data = encapsulated IOVAR data as a single structure or packed TLVs for each * individual sub-command. + * + * Note that if there is no data in the IN direction, the data field + * is empty, even if there is return data in the OUT direction. That is, the buffer does + * not need to include 'space' for the return parameter. + * + * For example, a batch command with one sub-command for a GET of a uint32 might look + * like this when sent to the device (IN direction). + * Note that the multi-byte values below are in litte-endian order in the IO buffers, so + * for example, the version '0x8000' is in the IO buffer as the byte sequence '0x00', '0x80'. + * +--------+------+--------+ + * |version |count | is_set | + * +--------+------+--------+ + * | 0x8000 | 0x01 | 0x00 | + * +--------+------+--------+ + * +--------+--------+-------------+----------------+ + * | cmd-id | length | IN(options) | (command data) | + * +--------+--------+------------------------------+ + * | 0x0111 | 0x0004 | 0x00000000 | (not present) + * +--------+--------+-------------- + * + * The 'length' field = 4 bytes to cover the options field. + * + * The reply might look like this (OUT direction): + * +--------+------+--------+ + * |version |count | is_set | + * +--------+------+--------+ + * | 0x8000 | 0x01 | 0x00 | + * +--------+------+--------+ + * +--------+--------+-------------+--------------+ + * | cmd-id | length | OUT(status) | command data | + * +--------+--------+-------------+--------------+ + * | 0x0111 | 0x0008 | 0x00000000 | 0x1234abcd | + * +--------+--------+-------------+--------------+ + * + * The 'length' field = 8 bytes to cover the status and data fields. + * */ struct bcm_iov_batch_subcmd { uint16 id; - uint16 len; + uint16 len; /* length of subcmd, including options */ union { uint32 options; uint32 status; } u; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; }; struct bcm_iov_batch_buf { uint16 version; uint8 count; - uint8 is_set; /* to differentiate set or get */ + uint8 is_set; /* obsolete */ struct bcm_iov_batch_subcmd cmds[0]; }; -/* non-batched command version = major|minor w/ major <= 127 */ +/* Non-Batched commands will have the following memory layout + * +---------+--------+--------+-------------+ + * | version | length | cmd-id |command data | + * +---------+--------+--------+-------------+ + * version = major|minor w/ major <= 127 + * length = length of this command, not including version, length, and cmd-id + * cmd-id = command ID + * command data = encapsulated IOVAR data as a single structure or packed TLVs + * + * Note that if there is no data in the IN direction, the data field + * is empty, even if there is return data in the OUT direction. That is, the buffer does + * not need to include 'space' for the return parameter. + * + * For example, a command for a GET of a uint32 might look + * like this when sent to the device (IN direction). + * Note that the multi-byte values below are in litte-endian order in the IO buffers, so + * for example, the version '0x0001' is in the IO buffer as the byte sequence '0x01', '0x00'. + * +---------+--------+--------+----------------+ + * | version | length | cmd-id | (command data) | + * +---------+--------+--------+----------------+ + * | 0x0001 | 0x0000 | 0x0111 | (not present) + * +---------+--------+--------+ + * + * The 'length' field = 0 bytes since there is no data field. + * + * The reply might look like this (OUT direction): + * +---------+--------+--------+--------------+ + * | version | length | cmd-id | command data | + * +---------+--------+--------+--------------+ + * | 0x0001 | 0x0004 | 0x0111 | 0x1234abcd | + * +---------+--------+--------+--------------+ + * + * The 'length' field = 4 bytes to cover the 4 byte data field. + * + */ struct bcm_iov_buf { uint16 version; - uint16 len; + uint16 len; /* length of data, after id */ bcm_iov_cmd_id_t id; - uint16 data[1]; /* 32 bit alignment may be repurposed by the command */ + uint16 data[BCM_FLEX_ARRAY]; /* 32 bit alignment may be repurposed by the command */ /* command specific data follows */ }; @@ -253,8 +325,20 @@ struct bcm_iov_cmd_tlv_info { /* Command parsing options with respect to validation */ /* Possible values for parse context options */ -/* Bit 0 - Validate only */ -#define BCM_IOV_PARSE_OPT_BATCH_VALIDATE 0x00000001 + +/* Validate all the commands in batch first */ +#define BCM_IOV_PARSE_OPT_BATCH_VALIDATE 0x00000001u + +/* implement version command within bcmiov. ver_cmd and api_ver in + * parse config (see below) need to specified along with this option. + */ +#define BCM_IOV_PARSE_OPT_AUTO_VER 0x00000002u + +/* option for non-batched commands to not copy when input and outputs + * overlap. this means that the api user/iov handers are able to handle + * overlapping input/output, copying as necessary. + */ +#define BCM_IOV_PARSE_OPT_NBOVLPOK 0x00000004u typedef uint32 bcm_iov_parse_opts_t; @@ -266,8 +350,10 @@ typedef struct bcm_iov_parse_config { bcm_iov_malloc_t alloc_fn; bcm_iov_free_t free_fn; bcm_iov_get_digest_t dig_fn; - int max_regs; + uint max_regs; void *alloc_ctx; + uint16 ver_cmd; /* version command */ + uint16 api_ver; /* version of the API/iovar */ } bcm_iov_parse_config_t; /* API */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmip.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmip.h old mode 100755 new mode 100644 index 898a231f6f5d..7eb5736f5ab2 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmip.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmip.h @@ -1,7 +1,7 @@ /* * Fundamental constants relating to IP Protocol * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -125,6 +125,18 @@ BWL_PRE_PACKED_STRUCT struct ipv4_hdr { uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */ } BWL_POST_PACKED_STRUCT; +#define IPOPTION_RA 148u /* router alert */ +#define IPOPTION_RA_LEN 4u /* router alert length */ + +/* + * Router Alert option structure. + */ +BWL_PRE_PACKED_STRUCT struct ip_router_alert { + uint8 ipra_code; /* IPOPT_RA */ + uint8 ipra_len; /* size of structure (variable) */ + uint16 ipra_data; /* index of current entry */ +} BWL_POST_PACKED_STRUCT; + /* IPV6 field offsets */ #define IPV6_PAYLOAD_LEN_OFFSET 4 /* payload length offset */ #define IPV6_NEXT_HDR_OFFSET 6 /* next header/protocol offset */ @@ -262,6 +274,7 @@ ipv6_exthdr_len_check(uint8 *h, uint16 plen, uint8 *proto) } return len; } + #define IPV4_ISMULTI(a) (((a) & 0xf0000000) == 0xe0000000) #define IPV4_MCAST_TO_ETHER_MCAST(ipv4, ether) \ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmipv6.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmipv6.h old mode 100755 new mode 100644 index 89a151505c58..fbeb8ce3c369 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmipv6.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmipv6.h @@ -1,7 +1,7 @@ /* * Fundamental constants relating to Neighbor Discovery Protocol * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmmsgbuf.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmmsgbuf.h old mode 100755 new mode 100644 index d9177d722ac6..884d79506a41 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmmsgbuf.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmmsgbuf.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -27,7 +27,29 @@ #define _bcmmsgbuf_h_ #include + +#ifndef BCMWIFI_DISSECTOR_BUILD +/* + * This header file i.e bcmmsgbuf.h is needed for bcmwifi dissecotor + * to prase host to dongle msgbuf traffic. + * + * BCMWIFI_DISSECTOR_BUILD is defined only while building bcmwifi dissecotor(BWD). + * wlioctl.h and the bunch of files being invoked by wlioctl.h are not needed for + * BWD build as of now. When need be wlioctl.h can be invoked unconditionally. + * + */ #include +#endif /* !BCMWIFI_DISSECTOR_BUILD */ + +#ifdef BCMWIFI_DISSECTOR_BUILD +/* + * This header file needs someof the definitons from osl_decl.h. + * Hence include the same for BCMWIFI_DISSECTOR_BUILD. + */ +#include +#define DECLSPEC_ALIGN(x) __attribute__ ((aligned(x))) +#endif /* BCMWIFI_DISSECTOR_BUILD */ + #include #define MSGBUF_MAX_MSG_SIZE ETHER_MAX_LEN @@ -62,6 +84,8 @@ #define D2HRING_TXCMPLT_ITEMSIZE 24 #define D2HRING_RXCMPLT_ITEMSIZE 40 +#define D2HRING_MDCMPLT_ITEMSIZE 80 + #define D2HRING_TXCMPLT_ITEMSIZE_PREREV7 16 #define D2HRING_RXCMPLT_ITEMSIZE_PREREV7 32 @@ -75,6 +99,7 @@ #define D2HRING_DYNAMIC_INFO_MAX_ITEM 32 #define H2DRING_TXPOST_MAX_ITEM 512 +#define D2HRING_MDRING_MAX_ITEM 2048 #if defined(DHD_HTPUT_TUNABLES) #define H2DRING_RXPOST_MAX_ITEM 2048 @@ -120,11 +145,14 @@ enum { }; #define MESSAGE_PAYLOAD(a) (a & MSG_TYPE_INTERNAL_USE_START) ? TRUE : FALSE -#define PCIEDEV_FIRMWARE_TSINFO 0x1 -#define PCIEDEV_FIRMWARE_TSINFO_FIRST 0x1 -#define PCIEDEV_FIRMWARE_TSINFO_MIDDLE 0x2 -#define PCIEDEV_BTLOG_POST 0x3 -#define PCIEDEV_BT_SNAPSHOT_POST 0x4 +#define PCIEDEV_FIRMWARE_TSINFO 0x1u +#define PCIEDEV_FIRMWARE_TSINFO_FIRST 0x1u +#define PCIEDEV_FIRMWARE_TSINFO_MIDDLE 0x2u +#define PCIEDEV_BTLOG_POST 0x3u +#define PCIEDEV_BT_SNAPSHOT_POST 0x4u + +/* Asynchronous response types */ +#define BCMMSGBUF_SEND_CMD_RESP 0x1u #ifdef PCIE_API_REV1 @@ -266,6 +294,7 @@ typedef enum bcmpcie_msgtype { MSG_TYPE_TX_STATUS_AGGR = 0x30, MSG_TYPE_RXBUF_POST_AGGR = 0x31, MSG_TYPE_RX_CMPLT_AGGR = 0x32, + MSG_TYPE_MDATA_CPL = 0x33, MSG_TYPE_API_MAX_RSVD = 0x3F } bcmpcie_msg_type_t; @@ -286,7 +315,8 @@ typedef enum bcmpcie_msgtype_int { MSG_TYPE_HMAPTEST_PYLD = 0x4C, MSG_TYPE_PVT_BT_SNAPSHOT_CMPLT = 0x4D, MSG_TYPE_BT_SNAPSHOT_PYLD = 0x4E, - MSG_TYPE_LPBK_DMAXFER_PYLD_ADDR = 0x4F /* loopback from addr pkt */ + MSG_TYPE_LPBK_DMAXFER_PYLD_ADDR = 0x4F, /* loopback from addr pkt */ + MSG_TYPE_PCIE_BUS_TPUT = 0x50 /* payload for pcie bus tput measurements */ } bcmpcie_msgtype_int_t; typedef enum bcmpcie_msgtype_u { @@ -349,6 +379,10 @@ typedef struct bcmpcie_msi_offset_config { bcmpcie_msi_offset_t bcmpcie_msi_offset[MSI_INTR_IDX_MAX]; } bcmpcie_msi_offset_config_t; +typedef struct bcmpcie_mdata_config { + uint16 ringid; +} bcmpcie_mdata_config_t; + #define BCMPCIE_D2H_MSI_OFFSET_DEFAULT BCMPCIE_D2H_MSI_OFFSET_DB1 #define BCMPCIE_D2H_MSI_SINGLE 0xFFFE @@ -367,8 +401,12 @@ typedef struct bcmpcie_msi_offset_config { #define BCMPCIE_CMNHDR_FLAGS_DMA_R_IDX 0x1 #define BCMPCIE_CMNHDR_FLAGS_DMA_R_IDX_INTR 0x2 #define BCMPCIE_CMNHDR_FLAGS_TS_SEQNUM_INIT 0x4 +#define BCMPCIE_CMNHDR_FLAGS_WAKE_PACKET 0x8 +#define BCMPCIE_CMNHDR_FLAGS_MDATA_PRESENT 0x10 #define BCMPCIE_CMNHDR_FLAGS_PHASE_BIT 0x80 #define BCMPCIE_CMNHDR_PHASE_BIT_INIT 0x80 +#define BCMPCIE_FLOWRING_PHASE_NIBBLE_INIT 0xA0 +#define BCMPCIE_FLOWRING_PHASE_NIBBLE_WRAP 0x50 /* IOCTL request message */ typedef struct ioctl_req_msg { @@ -406,11 +444,7 @@ typedef struct ioctl_resp_evt_buf_post_msg { /* buffer post messages for device to use to return dbg buffers */ typedef ioctl_resp_evt_buf_post_msg_t info_buf_post_msg_t; -#ifdef DHD_EFI -#define DHD_INFOBUF_RX_BUFPOST_PKTSZ 1800 -#else #define DHD_INFOBUF_RX_BUFPOST_PKTSZ (2 * 1024) -#endif #define DHD_BTLOG_RX_BUFPOST_PKTSZ (2 * 1024) @@ -420,14 +454,14 @@ typedef ioctl_resp_evt_buf_post_msg_t info_buf_post_msg_t; * is wrapped previously/also in a WLC_E_TRACE event. See structure * msgrace_hdr_t in msgtrace.h. */ -#define PCIE_INFOBUF_V1_TYPE_MSGTRACE 1 +#define PCIE_INFOBUF_V1_TYPE_MSGTRACE 1u /* Infobuf v1 type LOGTRACE data is exactly the same as the LOGTRACE data that * is wrapped previously/also in a WLC_E_TRACE event. See structure * msgrace_hdr_t in msgtrace.h. (The only difference between a MSGTRACE * and a LOGTRACE is the "trace type" field.) */ -#define PCIE_INFOBUF_V1_TYPE_LOGTRACE 2 +#define PCIE_INFOBUF_V1_TYPE_LOGTRACE 2u /* An infobuf version 1 host buffer has a single TLV. The information on the * version 1 types follow this structure definition. (int's LE) @@ -502,6 +536,7 @@ typedef struct pcie_dma_xfer_params { #define BCMPCIE_FLOW_RING_INTF_HP2P 0x01u /* bit0 */ #define BCMPCIE_FLOW_RING_OPT_EXT_TXSTATUS 0x02u /* bit1 */ #define BCMPCIE_FLOW_RING_INTF_MESH 0x04u /* bit2, identifies the mesh flow ring */ +#define BCMPCIE_FLOW_RING_INTF_LLW 0x08u /* bit3, identifies the llw flow ring */ /** Complete msgbuf hdr for flow ring update from host to dongle */ typedef struct tx_flowring_create_request { @@ -543,7 +578,9 @@ typedef struct tx_flowring_flush_request { typedef enum ring_config_subtype { /** Default D2H PCIE doorbell override using ring_config_req msg */ D2H_RING_CONFIG_SUBTYPE_SOFT_DOORBELL = 1, /* Software doorbell */ - D2H_RING_CONFIG_SUBTYPE_MSI_DOORBELL = 2 /* MSI configuration */ + D2H_RING_CONFIG_SUBTYPE_MSI_DOORBELL = 2, /* MSI configuration */ + D2H_RING_CONFIG_SUBTYPE_MDATA_LINK = 3, /* Metadata ring link */ + D2H_RING_CONFIG_SUBTYPE_MDATA_UNLINK = 4 /* Metadata ring unlink */ } ring_config_subtype_t; typedef struct ring_config_req { /* pulled from upcoming rev6 ... */ @@ -557,6 +594,7 @@ typedef struct ring_config_req { /* pulled from upcoming rev6 ... */ bcmpcie_soft_doorbell_t soft_doorbell; /** D2H_RING_CONFIG_SUBTYPE_MSI_DOORBELL */ bcmpcie_msi_offset_config_t msi_offset; + bcmpcie_mdata_config_t mdata_assoc; }; } ring_config_req_t; @@ -990,6 +1028,14 @@ typedef union rxbuf_submit_item { unsigned char check[H2DRING_RXPOST_ITEMSIZE]; } rxbuf_submit_item_t; +/* marker */ +#define BCMPCIE_RX_PKT_RSSI_MASK 0xFFu +#define BCMPCIE_RX_PKT_RSSI_SHIFT 0u +#define BCMPCIE_RX_PKT_DUR0_MASK 0xFFFF00u +#define BCMPCIE_RX_PKT_DUR0_SHIFT 8u +#define BCMPCIE_RX_PKT_BAND_MASK 0x3000000u +#define BCMPCIE_RX_PKT_BAND_SHIFT 24u + /* D2H Rxcompletion ring work items for IPC rev7 */ typedef struct host_rxbuf_cmpl { /** common message header */ @@ -1126,7 +1172,7 @@ typedef host_txbuf_post_v1_t host_txbuf_post_t; #define BCMPCIE_PKT_FLAGS_FRAME_NORETRY 0x01 /* Disable retry on this frame */ #define BCMPCIE_PKT_FLAGS_FRAME_NOAGGR 0x02 /* Disable aggregation for this frame */ #define BCMPCIE_PKT_FLAGS_FRAME_UDR 0x04 /* User defined rate for this frame */ -#define BCMPCIE_PKT_FLAGS_FRAME_ATTR_MASK 0x07 /* Attribute mask */ +#define BCMPCIE_PKT_FLAGS_FRAME_ATTR_MASK 0x27 /* Attribute mask */ #define BCMPCIE_PKT_FLAGS_FRAME_EXEMPT_MASK 0x03 /* Exempt uses 2 bits */ #define BCMPCIE_PKT_FLAGS_FRAME_EXEMPT_SHIFT 0x02 /* needs to be shifted past other bits */ @@ -1134,6 +1180,14 @@ typedef host_txbuf_post_v1_t host_txbuf_post_t; #define BCMPCIE_PKT_FLAGS_EPOCH_SHIFT 3u #define BCMPCIE_PKT_FLAGS_EPOCH_MASK (1u << BCMPCIE_PKT_FLAGS_EPOCH_SHIFT) +#define BCMPCIE_PKT_FLAGS_IGMP 0x10 +#define BCMPCIE_PKT_FLAGS_IGMP_SHIFT 4u +#define BCMPCIE_PKT_FLAGS_IGMP_MASK (1u << BCMPCIE_PKT_FLAGS_IGMP_SHIFT) + +#define BCMPCIE_PKT_FLAGS_FRAME_RTS 0x20 /* RTS protection for this frame */ +#define BCMPCIE_PKT_FLAGS_RTS_SHIFT 5u +#define BCMPCIE_PKT_FLAGS_RTS_MASK (1u << BCMPCIE_PKT_FLAGS_RTS_SHIFT) + #define BCMPCIE_PKT_FLAGS_PRIO_SHIFT 5 #define BCMPCIE_PKT_FLAGS_PRIO_MASK (7 << BCMPCIE_PKT_FLAGS_PRIO_SHIFT) #define BCMPCIE_PKT_FLAGS_MONITOR_NO_AMSDU 0x00 @@ -1146,6 +1200,7 @@ typedef host_txbuf_post_v1_t host_txbuf_post_t; #define BCMPCIE_PKT_FLAGS_FRAME_MESH 0x400u /* Indicate RX checksum verified and passed */ #define BCMPCIE_PKT_FLAGS_RCSUM_VALID 0x800u +#define BCMPCIE_PKT_FLAGS_RCSUM_VALID_AGGR 0x01u /* These are added to fix up compile issues */ #define BCMPCIE_TXPOST_FLAGS_FRAME_802_3 BCMPCIE_PKT_FLAGS_FRAME_802_3 @@ -1163,6 +1218,10 @@ typedef union txbuf_submit_item { unsigned char check[H2DRING_TXPOST_ITEMSIZE]; } txbuf_submit_item_t; +/* metadata_len */ +#define BCMPCIE_TX_PKT_LATENCY_MASK 0xFFFu +#define BCMPCIE_TX_PKT_LATENCY_SHIFT 0u + /* D2H Txcompletion ring work items - extended for IOC rev7 */ typedef struct host_txbuf_cmpl { /** common message header */ @@ -1478,76 +1537,6 @@ typedef struct tx_idle_flowring_resume_response { dma_done_t marker; } tx_idle_flowring_resume_response_t; -/* timesync related additions */ - -/* defined similar to bcm_xtlv_t */ -typedef struct _bcm_xtlv { - uint16 id; /* TLV idenitifier */ - uint16 len; /* TLV length in bytes */ -} _bcm_xtlv_t; - -#define BCMMSGBUF_FW_CLOCK_INFO_TAG 0 -#define BCMMSGBUF_HOST_CLOCK_INFO_TAG 1 -#define BCMMSGBUF_HOST_CLOCK_SELECT_TAG 2 -#define BCMMSGBUF_D2H_CLOCK_CORRECTION_TAG 3 -#define BCMMSGBUF_HOST_TIMESTAMPING_CONFIG_TAG 4 -#define BCMMSGBUF_MAX_TSYNC_TAG 5 - -/* Flags in fw clock info TLV */ -#define CAP_DEVICE_TS (1 << 0) -#define CAP_CORRECTED_TS (1 << 1) -#define TS_CLK_ACTIVE (1 << 2) - -typedef struct ts_fw_clock_info { - _bcm_xtlv_t xtlv; /* BCMMSGBUF_FW_CLOCK_INFO_TAG */ - ts_timestamp_srcid_t ts; /* tick count */ - uchar clk_src[4]; /* clock source acronym ILP/AVB/TSF */ - uint32 nominal_clock_freq; - uint32 reset_cnt; - uint8 flags; - uint8 rsvd[3]; -} ts_fw_clock_info_t; - -typedef struct ts_host_clock_info { - _bcm_xtlv_t xtlv; /* BCMMSGBUF_HOST_CLOCK_INFO_TAG */ - tick_count_64_t ticks; /* 64 bit host tick counter */ - ts_timestamp_ns_64_t ns; /* 64 bit host time in nano seconds */ -} ts_host_clock_info_t; - -typedef struct ts_host_clock_sel { - _bcm_xtlv_t xtlv; /* BCMMSGBUF_HOST_CLOCK_SELECT_TAG */ - uint32 seqnum; /* number of times GPIO time sync toggled */ - uint8 min_clk_idx; /* clock idenitifer configured for packet tiem stamping */ - uint8 max_clk_idx; /* clock idenitifer configured for packet tiem stamping */ - uint16 rsvd[1]; -} ts_host_clock_sel_t; - -typedef struct ts_d2h_clock_correction { - _bcm_xtlv_t xtlv; /* BCMMSGBUF_HOST_CLOCK_INFO_TAG */ - uint8 clk_id; /* clock source in the device */ - uint8 rsvd[3]; - ts_correction_m_t m; /* y = 'm' x + b */ - ts_correction_b_t b; /* y = 'm' x + 'c' */ -} ts_d2h_clock_correction_t; - -typedef struct ts_host_timestamping_config { - _bcm_xtlv_t xtlv; /* BCMMSGBUF_HOST_TIMESTAMPING_CONFIG_TAG */ - /* time period to capture the device time stamp and toggle WLAN_TIME_SYNC_GPIO */ - uint16 period_ms; - uint8 flags; - uint8 post_delay; - uint32 reset_cnt; -} ts_host_timestamping_config_t; - -/* Flags in host timestamping config TLV */ -#define FLAG_HOST_RESET (1 << 0) -#define IS_HOST_RESET(x) ((x) & FLAG_HOST_RESET) -#define CLEAR_HOST_RESET(x) ((x) & ~FLAG_HOST_RESET) - -#define FLAG_CONFIG_NODROP (1 << 1) -#define IS_CONFIG_NODROP(x) ((x) & FLAG_CONFIG_NODROP) -#define CLEAR_CONFIG_NODROP(x) ((x) & ~FLAG_CONFIG_NODROP) - /* HP2P RLLW Extended TxStatus info when host enables the same */ #define D2H_TXSTATUS_EXT_PKT_WITH_OVRRD 0x8000 /**< set when pkt had override bit on */ #define D2H_TXSTATUS_EXT_PKT_XMIT_ON5G 0x4000 /**< set when pkt xmitted on 5G */ @@ -1655,7 +1644,9 @@ typedef struct host_rxbuf_post_aggr { /* each rx buffer work item */ typedef struct host_rxbuf_cmpl_pkt { /** offset in the host rx buffer where the data starts */ - uint16 data_offset; + uint8 data_offset; + /** d2h flags */ + uint8 flags; /** filled up buffer len to receive data */ uint16 data_len; /** packet Identifier for the associated host buffer */ @@ -1698,6 +1689,14 @@ enum { TXPOST_EXT_TAG_LEN_MESH = 20u }; +/* CSO specific information for the cso enabled txpost workitem */ +typedef struct txpost_wi_cso_info_s { + txpost_ext_tag_type_t ext_tag; /* extended tag (TXPOST_EXT_TAG_TYPE_CSO) */ + uint8 pkt_csum_type; /* ipv4|ipv6|tcp|udp|nwk_csum|trans_csum|ph_csum */ + uint8 nwk_hdr_len; /* IP header length */ + uint8 trans_hdr_len; /* TCP header length */ +} txpost_wi_cso_info_t; + /* * Note: The only requirement is that the overall size of the workitem be multiple of 8. * However, each individual ext tag not necessarily 8x. diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmnvram.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmnvram.h old mode 100755 new mode 100644 index 498fb992ae26..0ad290aa6c0b --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmnvram.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmnvram.h @@ -1,7 +1,7 @@ /* * NVRAM variable manipulation * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2023, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmpcie.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmpcie.h old mode 100755 new mode 100644 index f464e2089c2a..b0796d96a042 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmpcie.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmpcie.h @@ -3,7 +3,7 @@ * Software-specific definitions shared between device and host side * Explains the shared area between host and dongle * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -153,9 +153,17 @@ typedef struct { #define PCIE_SHARED2_TXCSO 0x00200000u /* Tx Checksum offload support */ #define PCIE_SHARED2_TXPOST_EXT 0x00400000u /* extended txpost work item support */ +#define PCIE_SHARED2_PTM 0x01000000u /* PCIe PTM */ +#define PCIE_SHARED2_LLW2 0x02000000u /* GCR based LLW2 */ +#define PCIE_SHARED2_RX_CMPL_PRIO_VALID 0x04000000u /* Prio is valid in Rx Cmpl */ +#define PCIE_SHARED2_LPM_SUPPORT 0x08000000u /* LPM mode support */ +#define PCIE_SHARED2_METADATA_RING 0x10000000u /* Metadata Ring support */ + #define PCIE_SHARED2_D2H_D11_TX_STATUS 0x40000000 #define PCIE_SHARED2_H2D_D11_TX_STATUS 0x80000000 +#define PCIE_SHARED3_CFG_TRAP_SUPPORT 0x00000001 /* special trap sig supported in config space */ + #define PCIE_SHARED_D2H_MAGIC 0xFEDCBA09 #define PCIE_SHARED_H2D_MAGIC 0x12345678 @@ -197,8 +205,10 @@ typedef uint16 pcie_hwa_db_index_t; /* 16 bit HWA index (IPC Rev 7) */ #define BCMPCIE_D2H_RING_TYPE_AC_RX_COMPLETE 0x5 #define BCMPCIE_D2H_RING_TYPE_BTLOG_CPL 0x6 #define BCMPCIE_D2H_RING_TYPE_EDL 0x7 -#define BCMPCIE_D2H_RING_TYPE_HPP_TX_CPL 0x8 -#define BCMPCIE_D2H_RING_TYPE_HPP_RX_CPL 0x9 +#define BCMPCIE_D2H_RING_TYPE_HPP_TX_CPL 0x8 +#define BCMPCIE_D2H_RING_TYPE_HPP_RX_CPL 0x9 +#define BCMPCIE_D2H_RING_TYPE_MESH_RX_CPL 0xA +#define BCMPCIE_D2H_RING_TYPE_MDATA_CPL 0xB /** * H2D and D2H, WR and RD index, are maintained in the following arrays: @@ -328,6 +338,19 @@ typedef struct ring_info { } ring_info_t; +/** + * A structure to share information about aggregated work item between host and dongle + */ +typedef struct { + uint8 flags; /* dongle supported aggregated work items */ + uint8 hostcap; /* host supported aggregated work items */ + uint8 txpost_max; /* max aggregated work items in txpost, filled by host */ + uint8 rxpost_max; /* max aggregated work items in rxpost, filled by host */ + uint8 txcpl_max; /* max aggregated work items in txcpl, filled by dongle */ + uint8 rxcpl_max; /* max aggregated work items in rxcpl, filled by dongle */ + uint16 resvd; /* reserved */ +} pcie_aggr_sh_t; + /** * A structure located in TCM that is shared between host and device, primarily used during * initialization. @@ -402,6 +425,11 @@ typedef struct { /* Device advertises the txpost extended tag capabilities */ uint32 device_txpost_ext_tags_bitmask; + /* Pointer to ewp_info_t data structure [ipc v9] */ + uint32 PHYS_ADDR_N(ewp_info_addr); + + /* aggregated work item shared information [ipc v9] */ + pcie_aggr_sh_t aggr_sh_info; } pciedev_shared_t; /* Device F/W provides the following access function: @@ -438,6 +466,7 @@ typedef struct { #define HOSTCAP_HWA 0x80000000 #define HOSTCAP2_DURATION_SCALE_MASK 0x0000003Fu +#define HOSTCAP2_PCIE_PTM 0x00000100u /* extended trap debug buffer allocation sizes. Note that this buffer can be used for * other trap related purposes also. @@ -463,6 +492,8 @@ typedef struct { #define H2D_HOST_ACK_NOINT 0x00010000 /* d2h_ack interrupt ignore */ #define H2D_HOST_CONS_INT 0x80000000 /**< h2d int for console cmds */ #define H2D_FW_TRAP 0x20000000 /**< h2d force TRAP */ +#define H2D_HOST_PTM_ENABLE 0x01000000 /**< h2d enable PTM */ +#define H2D_HOST_PTM_DISABLE 0x02000000 /**< h2d disable PTM */ #define H2DMB_DS_HOST_SLEEP_INFORM H2D_HOST_D3_INFORM #define H2DMB_DS_DEVICE_SLEEP_ACK H2D_HOST_DS_ACK #define H2DMB_DS_DEVICE_SLEEP_NAK H2D_HOST_DS_NAK @@ -472,6 +503,8 @@ typedef struct { #define H2DMB_HOST_CONS_INT H2D_HOST_CONS_INT #define H2DMB_DS_DEVICE_WAKE_ASSERT H2DMB_DS_DEVICE_WAKE #define H2DMB_DS_DEVICE_WAKE_DEASSERT H2DMB_DS_ACTIVE +#define H2DMB_PTM_ENABLE H2D_HOST_PTM_ENABLE +#define H2DMB_PTM_DISABLE H2D_HOST_PTM_DISABLE /* D2H mail box Data */ #define D2H_DEV_D3_ACK 0x00000001 @@ -479,9 +512,13 @@ typedef struct { #define D2H_DEV_DS_EXIT_NOTE 0x00000004 #define D2HMB_DS_HOST_SLEEP_EXIT_ACK 0x00000008 #define D2H_DEV_IDMA_INITED 0x00000010 +#define D2H_DEV_PTM_ENABLED 0x02000000 +#define D2H_DEV_PTM_DISABLED 0x04000000 #define D2HMB_DS_HOST_SLEEP_ACK D2H_DEV_D3_ACK #define D2HMB_DS_DEVICE_SLEEP_ENTER_REQ D2H_DEV_DS_ENTER_REQ #define D2HMB_DS_DEVICE_SLEEP_EXIT D2H_DEV_DS_EXIT_NOTE +#define D2HMB_PTM_ENABLED D2H_DEV_PTM_ENABLED +#define D2HMB_PTM_DISABLED D2H_DEV_PTM_DISABLED #define D2H_DEV_MB_MASK (D2H_DEV_D3_ACK | D2H_DEV_DS_ENTER_REQ | \ D2H_DEV_DS_EXIT_NOTE | D2H_DEV_IDMA_INITED) @@ -498,6 +535,7 @@ typedef struct { /* Indicates whether HMAP violation was Write */ #define D2H_DEV_TRAP_HMAP_WRITE 0x04000000 #define D2H_DEV_TRAP_PING_HOST_FAILURE 0x08000000 +#define D2H_DEV_TRAP_DS_ACK_TIMEOUT 0x00100000u #define D2H_FWTRAP_MASK 0x0000001F /* Adding maskbits for TRAP information */ #define D2HMB_FWHALT D2H_DEV_FWHALT @@ -526,6 +564,17 @@ typedef struct { #define CHECK_NOWRITE_SPACE(r, w, d) \ (((uint32)(r) == (uint32)((w) + 1)) || (((r) == 0) && ((w) == ((d) - 1)))) +/* Validate if w_new is in the valid range of existing r & w values */ +#define BCMPCIE_IS_WRITE_VALID(w_new, r, w) (((w) >= (r)) ? \ + ((w_new) < (w) && (w_new) >= (r) ? FALSE : TRUE) : \ + ((w_new) < (w) || (w_new) >= (r) ? FALSE : TRUE)) + +/* Validate if r_new is in the valid range of existing r & w values */ +#define BCMPCIE_IS_READ_VALID(r_new, r, w) (((w) >= (r)) ? \ + ((r_new) > (w) || (r_new) < (r) ? FALSE : TRUE) : \ + ((r_new) < (r) && (r_new) > (w) ? FALSE : TRUE)) + +#ifndef PRIV_PCIE_RING_MACROS /* These should be moved into pciedev.h --- */ #define WRT_PEND(x) ((x)->wr_pending) #define DNGL_RING_WPTR(msgbuf) (*((msgbuf)->tcm_rs_w_ptr)) /**< advanced by producer */ @@ -545,6 +594,9 @@ typedef struct { #define HOST_RING_END(x) ((uint8 *)HOST_RING_BASE((x)) + \ ((RING_MAX_ITEM((x))-1)*RING_LEN_ITEMS((x)))) +#define RING_MESH(x) (((x)->txpost_ext_cap_flags) & PCIE_SHARED2_DEV_TXPOST_EXT_TAG_CAP_MESH) +#endif /* PRIV_PCIE_RING_MACROS */ + /* Trap types copied in the pciedev_shared.trap_addr */ #define FW_INITIATED_TRAP_TYPE (0x1 << 7) #define HEALTHCHECK_NODS_TRAP_TYPE (0x1 << 6) @@ -554,6 +606,9 @@ typedef struct { #define PCIE_SHARED2_DEV_TXPOST_EXT_TAG_CAP_CSO (1u << 1u) /* CSO */ #define PCIE_SHARED2_DEV_TXPOST_EXT_TAG_CAP_MESH (1u << 2u) /* MESH */ -#define RING_MESH(x) (((x)->txpost_ext_cap_flags) & PCIE_SHARED2_DEV_TXPOST_EXT_TAG_CAP_MESH) - +/* Aggregated Work Item definitions */ +#define PCIE_AGGR_WI_TXPOST (1u << 0u) +#define PCIE_AGGR_WI_RXPOST (1u << 1u) +#define PCIE_AGGR_WI_TXCPL (1u << 2u) +#define PCIE_AGGR_WI_RXCPL (1u << 3u) #endif /* _bcmpcie_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmpcispi.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmpcispi.h deleted file mode 100755 index bd0455759bce..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmpcispi.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Broadcom PCI-SPI Host Controller Register Definitions - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ -#ifndef _BCM_PCI_SPI_H -#define _BCM_PCI_SPI_H - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif /* PAD */ - -/* -+---------------------------------------------------------------------------+ -| | -| 7 6 5 4 3 2 1 0 | -| 0x0000 SPI_CTRL SPIE SPE 0 MSTR CPOL CPHA SPR1 SPR0 | -| 0x0004 SPI_STAT SPIF WCOL ST1 ST0 WFFUL WFEMP RFFUL RFEMP | -| 0x0008 SPI_DATA Bits 31:0, data to send out on MOSI | -| 0x000C SPI_EXT ICNT1 ICNT0 BSWAP *HSMODE ESPR1 ESPR0 | -| 0x0020 GPIO_OE 0=input, 1=output PWR_OE CS_OE | -| 0x0024 GPIO_DATA CARD:1=missing, 0=present CARD PWR_DAT CS_DAT | -| 0x0040 INT_EDGE 0=level, 1=edge DEV_E SPI_E | -| 0x0044 INT_POL 1=active high, 0=active low DEV_P SPI_P | -| 0x0048 INTMASK DEV SPI | -| 0x004C INTSTATUS DEV SPI | -| 0x0060 HEXDISP Reset value: 0x14e443f5. In hexdisp mode, value | -| shows on the Raggedstone1 4-digit 7-segment display. | -| 0x0064 CURRENT_MA Low 16 bits indicate card current consumption in mA | -| 0x006C DISP_SEL Display mode (0=hexdisp, 1=current) DSP | -| 0x00C0 PLL_CTL bit31=ext_clk, remainder unused. | -| 0x00C4 PLL_STAT LOCK | -| 0x00C8 CLK_FREQ | -| 0x00CC CLK_CNT | -| | -| *Notes: HSMODE is not implemented, never set this bit! | -| BSWAP is available in rev >= 8 | -| | -+---------------------------------------------------------------------------+ -*/ - -typedef volatile struct { - uint32 spih_ctrl; /* 0x00 SPI Control Register */ - uint32 spih_stat; /* 0x04 SPI Status Register */ - uint32 spih_data; /* 0x08 SPI Data Register, 32-bits wide */ - uint32 spih_ext; /* 0x0C SPI Extension Register */ - uint32 PAD[4]; /* 0x10-0x1F PADDING */ - - uint32 spih_gpio_ctrl; /* 0x20 SPI GPIO Control Register */ - uint32 spih_gpio_data; /* 0x24 SPI GPIO Data Register */ - uint32 PAD[6]; /* 0x28-0x3F PADDING */ - - uint32 spih_int_edge; /* 0x40 SPI Interrupt Edge Register (0=Level, 1=Edge) */ - uint32 spih_int_pol; /* 0x44 SPI Interrupt Polarity Register (0=Active Low, */ - /* 1=Active High) */ - uint32 spih_int_mask; /* 0x48 SPI Interrupt Mask */ - uint32 spih_int_status; /* 0x4C SPI Interrupt Status */ - uint32 PAD[4]; /* 0x50-0x5F PADDING */ - - uint32 spih_hex_disp; /* 0x60 SPI 4-digit hex display value */ - uint32 spih_current_ma; /* 0x64 SPI SD card current consumption in mA */ - uint32 PAD[1]; /* 0x68 PADDING */ - uint32 spih_disp_sel; /* 0x6c SPI 4-digit hex display mode select (1=current) */ - uint32 PAD[4]; /* 0x70-0x7F PADDING */ - uint32 PAD[8]; /* 0x80-0x9F PADDING */ - uint32 PAD[8]; /* 0xA0-0xBF PADDING */ - uint32 spih_pll_ctrl; /* 0xC0 PLL Control Register */ - uint32 spih_pll_status; /* 0xC4 PLL Status Register */ - uint32 spih_xtal_freq; /* 0xC8 External Clock Frequency in units of 10000Hz */ - uint32 spih_clk_count; /* 0xCC External Clock Count Register */ - -} spih_regs_t; - -typedef volatile struct { - uint32 cfg_space[0x40]; /* 0x000-0x0FF PCI Configuration Space (Read Only) */ - uint32 P_IMG_CTRL0; /* 0x100 PCI Image0 Control Register */ - - uint32 P_BA0; /* 0x104 32 R/W PCI Image0 Base Address register */ - uint32 P_AM0; /* 0x108 32 R/W PCI Image0 Address Mask register */ - uint32 P_TA0; /* 0x10C 32 R/W PCI Image0 Translation Address register */ - uint32 P_IMG_CTRL1; /* 0x110 32 R/W PCI Image1 Control register */ - uint32 P_BA1; /* 0x114 32 R/W PCI Image1 Base Address register */ - uint32 P_AM1; /* 0x118 32 R/W PCI Image1 Address Mask register */ - uint32 P_TA1; /* 0x11C 32 R/W PCI Image1 Translation Address register */ - uint32 P_IMG_CTRL2; /* 0x120 32 R/W PCI Image2 Control register */ - uint32 P_BA2; /* 0x124 32 R/W PCI Image2 Base Address register */ - uint32 P_AM2; /* 0x128 32 R/W PCI Image2 Address Mask register */ - uint32 P_TA2; /* 0x12C 32 R/W PCI Image2 Translation Address register */ - uint32 P_IMG_CTRL3; /* 0x130 32 R/W PCI Image3 Control register */ - uint32 P_BA3; /* 0x134 32 R/W PCI Image3 Base Address register */ - uint32 P_AM3; /* 0x138 32 R/W PCI Image3 Address Mask register */ - uint32 P_TA3; /* 0x13C 32 R/W PCI Image3 Translation Address register */ - uint32 P_IMG_CTRL4; /* 0x140 32 R/W PCI Image4 Control register */ - uint32 P_BA4; /* 0x144 32 R/W PCI Image4 Base Address register */ - uint32 P_AM4; /* 0x148 32 R/W PCI Image4 Address Mask register */ - uint32 P_TA4; /* 0x14C 32 R/W PCI Image4 Translation Address register */ - uint32 P_IMG_CTRL5; /* 0x150 32 R/W PCI Image5 Control register */ - uint32 P_BA5; /* 0x154 32 R/W PCI Image5 Base Address register */ - uint32 P_AM5; /* 0x158 32 R/W PCI Image5 Address Mask register */ - uint32 P_TA5; /* 0x15C 32 R/W PCI Image5 Translation Address register */ - uint32 P_ERR_CS; /* 0x160 32 R/W PCI Error Control and Status register */ - uint32 P_ERR_ADDR; /* 0x164 32 R PCI Erroneous Address register */ - uint32 P_ERR_DATA; /* 0x168 32 R PCI Erroneous Data register */ - - uint32 PAD[5]; /* 0x16C-0x17F PADDING */ - - uint32 WB_CONF_SPC_BAR; /* 0x180 32 R WISHBONE Configuration Space Base Address */ - uint32 W_IMG_CTRL1; /* 0x184 32 R/W WISHBONE Image1 Control register */ - uint32 W_BA1; /* 0x188 32 R/W WISHBONE Image1 Base Address register */ - uint32 W_AM1; /* 0x18C 32 R/W WISHBONE Image1 Address Mask register */ - uint32 W_TA1; /* 0x190 32 R/W WISHBONE Image1 Translation Address reg */ - uint32 W_IMG_CTRL2; /* 0x194 32 R/W WISHBONE Image2 Control register */ - uint32 W_BA2; /* 0x198 32 R/W WISHBONE Image2 Base Address register */ - uint32 W_AM2; /* 0x19C 32 R/W WISHBONE Image2 Address Mask register */ - uint32 W_TA2; /* 0x1A0 32 R/W WISHBONE Image2 Translation Address reg */ - uint32 W_IMG_CTRL3; /* 0x1A4 32 R/W WISHBONE Image3 Control register */ - uint32 W_BA3; /* 0x1A8 32 R/W WISHBONE Image3 Base Address register */ - uint32 W_AM3; /* 0x1AC 32 R/W WISHBONE Image3 Address Mask register */ - uint32 W_TA3; /* 0x1B0 32 R/W WISHBONE Image3 Translation Address reg */ - uint32 W_IMG_CTRL4; /* 0x1B4 32 R/W WISHBONE Image4 Control register */ - uint32 W_BA4; /* 0x1B8 32 R/W WISHBONE Image4 Base Address register */ - uint32 W_AM4; /* 0x1BC 32 R/W WISHBONE Image4 Address Mask register */ - uint32 W_TA4; /* 0x1C0 32 R/W WISHBONE Image4 Translation Address reg */ - uint32 W_IMG_CTRL5; /* 0x1C4 32 R/W WISHBONE Image5 Control register */ - uint32 W_BA5; /* 0x1C8 32 R/W WISHBONE Image5 Base Address register */ - uint32 W_AM5; /* 0x1CC 32 R/W WISHBONE Image5 Address Mask register */ - uint32 W_TA5; /* 0x1D0 32 R/W WISHBONE Image5 Translation Address reg */ - uint32 W_ERR_CS; /* 0x1D4 32 R/W WISHBONE Error Control and Status reg */ - uint32 W_ERR_ADDR; /* 0x1D8 32 R WISHBONE Erroneous Address register */ - uint32 W_ERR_DATA; /* 0x1DC 32 R WISHBONE Erroneous Data register */ - uint32 CNF_ADDR; /* 0x1E0 32 R/W Configuration Cycle register */ - uint32 CNF_DATA; /* 0x1E4 32 R/W Configuration Cycle Generation Data reg */ - - uint32 INT_ACK; /* 0x1E8 32 R Interrupt Acknowledge register */ - uint32 ICR; /* 0x1EC 32 R/W Interrupt Control register */ - uint32 ISR; /* 0x1F0 32 R/W Interrupt Status register */ -} spih_pciregs_t; - -/* - * PCI Core interrupt enable and status bit definitions. - */ - -/* PCI Core ICR Register bit definitions */ -#define PCI_INT_PROP_EN (1 << 0) /* Interrupt Propagation Enable */ -#define PCI_WB_ERR_INT_EN (1 << 1) /* Wishbone Error Interrupt Enable */ -#define PCI_PCI_ERR_INT_EN (1 << 2) /* PCI Error Interrupt Enable */ -#define PCI_PAR_ERR_INT_EN (1 << 3) /* Parity Error Interrupt Enable */ -#define PCI_SYS_ERR_INT_EN (1 << 4) /* System Error Interrupt Enable */ -#define PCI_SOFTWARE_RESET (1U << 31) /* Software reset of the PCI Core. */ - -/* PCI Core ISR Register bit definitions */ -#define PCI_INT_PROP_ST (1 << 0) /* Interrupt Propagation Status */ -#define PCI_WB_ERR_INT_ST (1 << 1) /* Wishbone Error Interrupt Status */ -#define PCI_PCI_ERR_INT_ST (1 << 2) /* PCI Error Interrupt Status */ -#define PCI_PAR_ERR_INT_ST (1 << 3) /* Parity Error Interrupt Status */ -#define PCI_SYS_ERR_INT_ST (1 << 4) /* System Error Interrupt Status */ - -/* Registers on the Wishbone bus */ -#define SPIH_CTLR_INTR (1 << 0) /* SPI Host Controller Core Interrupt */ -#define SPIH_DEV_INTR (1 << 1) /* SPI Device Interrupt */ -#define SPIH_WFIFO_INTR (1 << 2) /* SPI Tx FIFO Empty Intr (FPGA Rev >= 8) */ - -/* GPIO Bit definitions */ -#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */ -#define SPIH_SLOT_POWER (1 << 1) /* SD Card Slot Power Enable */ -#define SPIH_CARD_DETECT (1 << 2) /* SD Card Detect */ - -/* SPI Status Register Bit definitions */ -#define SPIH_STATE_MASK 0x30 /* SPI Transfer State Machine state mask */ -#define SPIH_STATE_SHIFT 4 /* SPI Transfer State Machine state shift */ -#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */ -#define SPIH_WFEMPTY (1 << 2) /* SPI Write FIFO Empty */ -#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */ -#define SPIH_RFEMPTY (1 << 0) /* SPI Read FIFO Empty */ - -#define SPIH_EXT_CLK (1U << 31) /* Use External Clock as PLL Clock source. */ - -#define SPIH_PLL_NO_CLK (1 << 1) /* Set to 1 if the PLL's input clock is lost. */ -#define SPIH_PLL_LOCKED (1 << 3) /* Set to 1 when the PLL is locked. */ - -/* Spin bit loop bound check */ -#define SPI_SPIN_BOUND 0xf4240 /* 1 million */ - -#endif /* _BCM_PCI_SPI_H */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmperf.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmperf.h old mode 100755 new mode 100644 index fd37d2749fb2..8bc2d0ebbbe7 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmperf.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmperf.h @@ -1,7 +1,7 @@ /* * Performance counters software interface. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmproto.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmproto.h old mode 100755 new mode 100644 index 2770caff2d1f..afc4616a30da --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmproto.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmproto.h @@ -1,7 +1,7 @@ /* * Fundamental constants relating to IP Protocol * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmrand.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmrand.h old mode 100755 new mode 100644 index 3bebca68d914..b2fdf820ff64 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmrand.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmrand.h @@ -1,7 +1,7 @@ /* * bcmrand.h. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdbus.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdbus.h old mode 100755 new mode 100644 index d2d89e83e73b..6f265a8f1c1d --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdbus.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdbus.h @@ -2,7 +2,7 @@ * Definitions for API from sdio common code (bcmsdh) to individual * host controller drivers. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -25,7 +25,7 @@ #ifndef _sdio_api_h_ #define _sdio_api_h_ -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) #include #endif /* defined (BT_OVER_SDIO) */ @@ -99,7 +99,7 @@ typedef struct sdioh_info sdioh_info_t; /* callback function, taking one arg */ typedef void (*sdioh_cb_fn_t)(void *); -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) extern void sdioh_sdmmc_card_enable_func_f3(sdioh_info_t *sd, struct sdio_func *func); #endif /* defined (BT_OVER_SDIO) */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdh.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdh.h old mode 100755 new mode 100644 index 3ed679b049d2..27417dcb1b0b --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdh.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdh.h @@ -3,7 +3,7 @@ * export functions to client drivers * abstract OS and BUS specific details of SDIO * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -42,7 +42,8 @@ extern const uint bcmsdh_msglevel; #define BCMSDH_INFO(x) #endif /* BCMDBG */ -#if defined(BCMSDIO) && (defined(BCMSDIOH_STD) || defined(BCMSDIOH_BCM) || defined(BCMSDIOH_SPI)) +#if defined(BCMSDIO) && (defined(BCMSDIOH_STD) || defined(BCMSDIOH_BCM) || \ + defined(BCMSDIOH_SPI)) #define BCMSDH_ADAPTER #endif /* BCMSDIO && (BCMSDIOH_STD || BCMSDIOH_BCM || BCMSDIOH_SPI) */ @@ -288,4 +289,10 @@ extern bool bcmsdh_gpioin(void *sd, uint32 gpio); extern int bcmsdh_gpioouten(void *sd, uint32 gpio); extern int bcmsdh_gpioout(void *sd, uint32 gpio, bool enab); -#endif /* _bcmsdh_h_ */ +#ifdef DHD_WAKE_STATUS +extern int bcmsdh_get_total_wake(bcmsdh_info_t *bcmsdh); +extern int bcmsdh_set_get_wake(bcmsdh_info_t *bcmsdh, int flag); + +#endif /* DHD_WAKE_STATUS */ + +#endif /* _bcmsdh_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdh_sdmmc.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdh_sdmmc.h old mode 100755 new mode 100644 index c79682e2567c..989e0a4eda5b --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdh_sdmmc.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdh_sdmmc.h @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -85,6 +85,9 @@ struct sdioh_info { struct sdio_func *func[SDIOD_MAX_IOFUNCS]; uint sd_clk_rate; uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */ +#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF) + uint8 *copy_buf; +#endif #ifdef PKT_STATICS uint32 sdio_spent_time_us; #endif diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdpcm.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdpcm.h old mode 100755 new mode 100644 index 3e01299a0c10..173e100a2b3d --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdpcm.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsdpcm.h @@ -2,7 +2,7 @@ * Broadcom SDIO/PCMCIA * Software-specific definitions shared between device and host side * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmspibrcm.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmspibrcm.h deleted file mode 100755 index 298eddaf4e05..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmspibrcm.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * SD-SPI Protocol Conversion - BCMSDH->gSPI Translation Layer - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ -#ifndef _BCM_SPI_BRCM_H -#define _BCM_SPI_BRCM_H - -#ifndef SPI_MAX_IOFUNCS -/* Maximum number of I/O funcs */ -#define SPI_MAX_IOFUNCS 4 -#endif -/* global msglevel for debug messages - bitvals come from sdiovar.h */ - -#if defined(BCMDBG) || defined(DHD_DEBUG) -#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) -#define sd_trace(x) do { if (sd_msglevel & SDH_TRACE_VAL) printf x; } while (0) -#define sd_info(x) do { if (sd_msglevel & SDH_INFO_VAL) printf x; } while (0) -#define sd_debug(x) do { if (sd_msglevel & SDH_DEBUG_VAL) printf x; } while (0) -#define sd_data(x) do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0) -#define sd_ctrl(x) do { if (sd_msglevel & SDH_CTRL_VAL) printf x; } while (0) -#else -#define sd_err(x) -#define sd_trace(x) -#define sd_info(x) -#define sd_debug(x) -#define sd_data(x) -#define sd_ctrl(x) -#endif - -#ifdef BCMPERFSTATS -#define sd_log(x) do { if (sd_msglevel & SDH_LOG_VAL) bcmlog x; } while (0) -#else -#define sd_log(x) -#endif - -#define SDIOH_ASSERT(exp) \ - do { if (!(exp)) \ - printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ - } while (0) - -#define BLOCK_SIZE_F1 64 -#define BLOCK_SIZE_F2 2048 -#define BLOCK_SIZE_F3 2048 - -/* internal return code */ -#define SUCCESS 0 -#undef ERROR -#define ERROR 1 -#define ERROR_UF 2 -#define ERROR_OF 3 - -/* private bus modes */ -#define SDIOH_MODE_SPI 0 - -#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ -#define USE_MULTIBLOCK 0x4 - -struct sdioh_info { - uint cfg_bar; /* pci cfg address for bar */ - uint32 caps; /* cached value of capabilities reg */ -#ifndef BCMSPI_ANDROID - void *bar0; /* BAR0 for PCI Device */ -#endif /* !BCMSPI_ANDROID */ - osl_t *osh; /* osh handler */ - void *controller; /* Pointer to SPI Controller's private data struct */ - uint lockcount; /* nest count of spi_lock() calls */ - bool client_intr_enabled; /* interrupt connnected flag */ - bool intr_handler_valid; /* client driver interrupt handler valid */ - sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ - void *intr_handler_arg; /* argument to call interrupt handler */ - bool initialized; /* card initialized */ - uint32 target_dev; /* Target device ID */ - uint32 intmask; /* Current active interrupts */ - void *sdos_info; /* Pointer to per-OS private data */ - uint32 controller_type; /* Host controller type */ - uint8 version; /* Host Controller Spec Compliance Version */ - uint irq; /* Client irq */ - uint32 intrcount; /* Client interrupts */ - uint32 local_intrcount; /* Controller interrupts */ - bool host_init_done; /* Controller initted */ - bool card_init_done; /* Client SDIO interface initted */ - bool polled_mode; /* polling for command completion */ - - bool sd_use_dma; /* DMA on CMD53 */ - bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ - /* Must be on for sd_multiblock to be effective */ - bool use_client_ints; /* If this is false, make sure to restore */ - /* polling hack in wl_linux.c:wl_timer() */ - int adapter_slot; /* Maybe dealing with multiple slots/controllers */ - int sd_mode; /* SD1/SD4/SPI */ - int client_block_size[SPI_MAX_IOFUNCS]; /* Blocksize */ - uint32 data_xfer_count; /* Current transfer */ - uint16 card_rca; /* Current Address */ - uint8 num_funcs; /* Supported funcs on client */ - uint32 card_dstatus; /* 32bit device status */ - uint32 com_cis_ptr; - uint32 func_cis_ptr[SPI_MAX_IOFUNCS]; - void *dma_buf; - ulong dma_phys; - int r_cnt; /* rx count */ - int t_cnt; /* tx_count */ - uint32 wordlen; /* host processor 16/32bits */ - uint32 prev_fun; - uint32 chip; - uint32 chiprev; - bool resp_delay_all; - bool dwordmode; - bool resp_delay_new; - - struct spierrstats_t spierrstats; -}; - -/************************************************************ - * Internal interfaces: per-port references into bcmspibrcm.c - */ - -/* Global message bits */ -extern uint sd_msglevel; - -/************************************************************** - * Internal interfaces: bcmspibrcm.c references to per-port code - */ - -/* Interrupt (de)registration routines */ -extern int spi_register_irq(sdioh_info_t *sd, uint irq); -extern void spi_free_irq(uint irq, sdioh_info_t *sd); - -/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ -extern void spi_lock(sdioh_info_t *sd); -extern void spi_unlock(sdioh_info_t *sd); - -/* Allocate/init/free per-OS private data */ -extern int spi_osinit(sdioh_info_t *sd); -extern void spi_osfree(sdioh_info_t *sd); - -#define SPI_RW_FLAG_M BITFIELD_MASK(1) /* Bit [31] - R/W Command Bit */ -#define SPI_RW_FLAG_S 31 -#define SPI_ACCESS_M BITFIELD_MASK(1) /* Bit [30] - Fixed/Incr Access */ -#define SPI_ACCESS_S 30 -#define SPI_FUNCTION_M BITFIELD_MASK(2) /* Bit [29:28] - Function Number */ -#define SPI_FUNCTION_S 28 -#define SPI_REG_ADDR_M BITFIELD_MASK(17) /* Bit [27:11] - Address */ -#define SPI_REG_ADDR_S 11 -#define SPI_LEN_M BITFIELD_MASK(11) /* Bit [10:0] - Packet length */ -#define SPI_LEN_S 0 - -#endif /* _BCM_SPI_BRCM_H */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsrom.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsrom.h deleted file mode 100755 index f3008b2e805c..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsrom.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Misc useful routines to access NIC local SROM/OTP . - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -#ifndef _bcmsrom_h_ -#define _bcmsrom_h_ - -#include -#include -#include - -#include - -typedef struct srom_info { - char *_srom_vars; - bool is_caldata_prsnt; -} srom_info_t; - -/* Prototypes */ -extern int srom_var_init(si_t *sih, uint bus, volatile void *curmap, osl_t *osh, - char **vars, uint *count); -extern void srom_var_deinit(si_t *sih); - -extern int srom_read(si_t *sih, uint bus, volatile void *curmap, osl_t *osh, - uint byteoff, uint nbytes, uint16 *buf, - bool check_crc); - -extern int srom_write(si_t *sih, uint bus, volatile void *curmap, osl_t *osh, - uint byteoff, uint nbytes, uint16 *buf); - -extern int srom_write_short(si_t *sih, uint bustype, volatile void *curmap, osl_t *osh, - uint byteoff, uint16 value); -extern int srom_otp_cisrwvar(si_t *sih, osl_t *osh, char *vars, int *count); -extern int srom_otp_write_region_crc(si_t *sih, uint nbytes, uint16* buf16, bool write); - -/* parse standard PCMCIA cis, normally used by SB/PCMCIA/SDIO/SPI/OTP - * and extract from it into name=value pairs - */ -extern int srom_parsecis(si_t *sih, osl_t *osh, uint8 **pcis, uint ciscnt, - char **vars, uint *count); -extern int _initvars_srom_pci_caldata(si_t *sih, uint16 *srom, uint32 sromrev); -extern void srom_set_sromvars(char *vars); -extern char * srom_get_sromvars(void); -extern srom_info_t * srom_info_init(osl_t *osh); -extern int get_srom_pci_caldata_size(uint32 sromrev); -extern uint32 get_srom_size(uint32 sromrev); - -/* Return sprom size in 16-bit words */ -extern uint srom_size(si_t *sih, osl_t *osh); - -extern bool srom_caldata_prsnt(si_t *sih); -extern int srom_get_caldata(si_t *sih, uint16 *srom); -#endif /* _bcmsrom_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsrom_fmt.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsrom_fmt.h old mode 100755 new mode 100644 index 97e3e4dbed4a..a9fd1695efdc --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsrom_fmt.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsrom_fmt.h @@ -1,7 +1,7 @@ /* * SROM format definition. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2023, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsrom_tbl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsrom_tbl.h deleted file mode 100755 index 248560362a4e..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmsrom_tbl.h +++ /dev/null @@ -1,1303 +0,0 @@ -/* - * Table that encodes the srom formats for PCI/PCIe NICs. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -#ifndef _bcmsrom_tbl_h_ -#define _bcmsrom_tbl_h_ - -#include -#include - -typedef struct { - const char *name; - uint32 revmask; - uint32 flags; - uint16 off; - uint16 mask; -} sromvar_t; - -#define SRFL_MORE 1 /* value continues as described by the next entry */ -#define SRFL_NOFFS 2 /* value bits can't be all one's */ -#define SRFL_PRHEX 4 /* value is in hexdecimal format */ -#define SRFL_PRSIGN 8 /* value is in signed decimal format */ -#define SRFL_CCODE 0x10 /* value is in country code format */ -#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */ -#define SRFL_UNUSED 0x40 /* unused, was SRFL_LEDDC */ -#define SRFL_NOVAR 0x80 /* do not generate a nvram param, entry is for mfgc */ -#define SRFL_ARRAY 0x100 /* value is in an array. All elements EXCEPT FOR THE LAST - * ONE in the array should have this flag set. - */ -#define PRHEX_N_MORE (SRFL_PRHEX | SRFL_MORE) - -#define SROM_DEVID_PCIE 48 - -/** - * Assumptions: - * - Ethernet address spans across 3 consecutive words - * - * Table rules: - * - Add multiple entries next to each other if a value spans across multiple words - * (even multiple fields in the same word) with each entry except the last having - * it's SRFL_MORE bit set. - * - Ethernet address entry does not follow above rule and must not have SRFL_MORE - * bit set. Its SRFL_ETHADDR bit implies it takes multiple words. - * - The last entry's name field must be NULL to indicate the end of the table. Other - * entries must have non-NULL name. - */ -#if !defined(SROM15_MEMOPT) -static const sromvar_t BCMATTACHDATA(pci_sromvars)[] = { -/* name revmask flags off mask */ -#if defined(BCMPCIEDEV) && defined(BCMPCIEDEV_ENABLED) - {"devid", 0xffffff00, SRFL_PRHEX, SROM_DEVID_PCIE, 0xffff}, -#else - {"devid", 0xffffff00, SRFL_PRHEX|SRFL_NOVAR, PCI_F0DEVID, 0xffff}, -#endif /* BCMPCIEDEV && BCMPCIEDEV_ENABLED */ - {"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK}, - {"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff}, - {"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff}, - {"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff}, - {"boardflags", 0x00000004, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, - {"", 0, 0, SROM_BFL2, 0xffff}, - {"boardflags", 0x00000008, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, - {"", 0, 0, SROM3_BFL2, 0xffff}, - {"boardflags", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL0, 0xffff}, - {"", 0, 0, SROM4_BFL1, 0xffff}, - {"boardflags", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL0, 0xffff}, - {"", 0, 0, SROM5_BFL1, 0xffff}, - {"boardflags", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL0, 0xffff}, - {"", 0, 0, SROM8_BFL1, 0xffff}, - {"boardflags2", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL2, 0xffff}, - {"", 0, 0, SROM4_BFL3, 0xffff}, - {"boardflags2", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL2, 0xffff}, - {"", 0, 0, SROM5_BFL3, 0xffff}, - {"boardflags2", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL2, 0xffff}, - {"", 0, 0, SROM8_BFL3, 0xffff}, - {"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff}, - {"subvid", 0xfffffffc, SRFL_PRHEX, SROM_SVID, 0xffff}, - {"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff}, - {"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff}, - {"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff}, - {"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff}, - {"boardnum", 0x00000700, 0, SROM8_MACLO, 0xffff}, - {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK}, - {"regrev", 0x00000008, 0, SROM_OPO, 0xff00}, - {"regrev", 0x00000010, 0, SROM4_REGREV, 0xffff}, - {"regrev", 0x000000e0, 0, SROM5_REGREV, 0xffff}, - {"regrev", 0x00000700, 0, SROM8_REGREV, 0xffff}, - {"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff}, - {"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff}, - {"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff}, - {"pa0itssit", 0x0000000e, 0, SROM_ITT, 0x00ff}, - {"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0x00ff}, - {"pa0b0", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff}, - {"pa0b1", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff}, - {"pa0b2", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff}, - {"pa0itssit", 0x00000700, 0, SROM8_W0_ITTMAXP, 0xff00}, - {"pa0maxpwr", 0x00000700, 0, SROM8_W0_ITTMAXP, 0x00ff}, - {"opo", 0x0000000c, 0, SROM_OPO, 0x00ff}, - {"opo", 0x00000700, 0, SROM8_2G_OFDMPO, 0x00ff}, - {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK}, - {"aa2g", 0x000000f0, 0, SROM4_AA, 0x00ff}, - {"aa2g", 0x00000700, 0, SROM8_AA, 0x00ff}, - {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK}, - {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00}, - {"aa5g", 0x00000700, 0, SROM8_AA, 0xff00}, - {"ag0", 0x0000000e, 0, SROM_AG10, 0x00ff}, - {"ag1", 0x0000000e, 0, SROM_AG10, 0xff00}, - {"ag0", 0x000000f0, 0, SROM4_AG10, 0x00ff}, - {"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00}, - {"ag2", 0x000000f0, 0, SROM4_AG32, 0x00ff}, - {"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00}, - {"ag0", 0x00000700, 0, SROM8_AG10, 0x00ff}, - {"ag1", 0x00000700, 0, SROM8_AG10, 0xff00}, - {"ag2", 0x00000700, 0, SROM8_AG32, 0x00ff}, - {"ag3", 0x00000700, 0, SROM8_AG32, 0xff00}, - {"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff}, - {"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff}, - {"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff}, - {"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff}, - {"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff}, - {"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff}, - {"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff}, - {"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff}, - {"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff}, - {"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00}, - {"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00}, - {"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00}, - {"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff}, - {"pa1b0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff}, - {"pa1b1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff}, - {"pa1b2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff}, - {"pa1lob0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff}, - {"pa1lob1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff}, - {"pa1lob2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff}, - {"pa1hib0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff}, - {"pa1hib1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff}, - {"pa1hib2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff}, - {"pa1itssit", 0x00000700, 0, SROM8_W1_ITTMAXP, 0xff00}, - {"pa1maxpwr", 0x00000700, 0, SROM8_W1_ITTMAXP, 0x00ff}, - {"pa1lomaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0xff00}, - {"pa1himaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0x00ff}, - {"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800}, - {"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700}, - {"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0}, - {"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f}, - {"bxa2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x1800}, - {"rssisav2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x0700}, - {"rssismc2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x00f0}, - {"rssismf2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x000f}, - {"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800}, - {"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700}, - {"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0}, - {"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f}, - {"bxa5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x1800}, - {"rssisav5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x0700}, - {"rssismc5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x00f0}, - {"rssismf5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x000f}, - {"tri2g", 0x00000008, 0, SROM_TRI52G, 0x00ff}, - {"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00}, - {"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0x00ff}, - {"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00}, - {"tri2g", 0x00000700, 0, SROM8_TRI52G, 0x00ff}, - {"tri5g", 0x00000700, 0, SROM8_TRI52G, 0xff00}, - {"tri5gl", 0x00000700, 0, SROM8_TRI5GHL, 0x00ff}, - {"tri5gh", 0x00000700, 0, SROM8_TRI5GHL, 0xff00}, - {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff}, - {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00}, - {"rxpo2g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff}, - {"rxpo5g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00}, - {"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK}, - {"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK}, - {"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK}, - {"txchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK}, - {"rxchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK}, - {"antswitch", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK}, - {"tssipos2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TSSIPOS_MASK}, - {"extpagain2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_EXTPA_GAIN_MASK}, - {"pdetrange2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_PDET_RANGE_MASK}, - {"triso2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK}, - {"antswctl2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_ANTSWLUT_MASK}, - {"tssipos5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TSSIPOS_MASK}, - {"extpagain5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_EXTPA_GAIN_MASK}, - {"pdetrange5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_PDET_RANGE_MASK}, - {"triso5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK}, - {"antswctl5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_ANTSWLUT_MASK}, - {"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0x00ff}, - {"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00}, - {"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff}, - {"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00}, - {"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0x00ff}, - {"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00}, - {"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff}, - {"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00}, - {"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff}, - {"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00}, - {"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff}, - {"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00}, - {"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff}, - {"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00}, - {"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff}, - {"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00}, - - {"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff}, - {"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff}, - {"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff}, - {"ccode", 0x00000700, SRFL_CCODE, SROM8_CCODE, 0xffff}, - {"macaddr", 0x00000700, SRFL_ETHADDR, SROM8_MACHI, 0xffff}, - {"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff}, - {"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff}, - {"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff}, - {"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff}, - {"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff}, - - {"tempthresh", 0x00000700, 0, SROM8_THERMAL, 0xff00}, - {"tempoffset", 0x00000700, 0, SROM8_THERMAL, 0x00ff}, - {"rawtempsense", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0x01ff}, - {"measpower", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0xfe00}, - {"tempsense_slope", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x00ff}, - {"tempcorrx", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0xfc00}, - {"tempsense_option", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x0300}, - {"freqoffset_corr", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x000f}, - {"iqcal_swp_dis", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0010}, - {"hw_iqcal_en", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0020}, - {"elna2g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0x00ff}, - {"elna5g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0xff00}, - {"phycal_tempdelta", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x00ff}, - {"temps_period", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x0f00}, - {"temps_hysteresis", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0xf000}, - {"measpower1", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x007f}, - {"measpower2", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x3f80}, - - {"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff}, - {"cck2gpo", 0x00000100, 0, SROM8_2G_CCKPO, 0xffff}, - {"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff}, - {"", 0, 0, SROM4_2G_OFDMPO + 1, 0xffff}, - {"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff}, - {"", 0, 0, SROM4_5G_OFDMPO + 1, 0xffff}, - {"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff}, - {"", 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff}, - {"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff}, - {"", 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff}, - {"ofdm2gpo", 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff}, - {"", 0, 0, SROM8_2G_OFDMPO + 1, 0xffff}, - {"ofdm5gpo", 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff}, - {"", 0, 0, SROM8_5G_OFDMPO + 1, 0xffff}, - {"ofdm5glpo", 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff}, - {"", 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff}, - {"ofdm5ghpo", 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff}, - {"", 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff}, - {"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff}, - {"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff}, - {"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff}, - {"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff}, - {"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff}, - {"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff}, - {"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff}, - {"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff}, - {"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff}, - {"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff}, - {"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff}, - {"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff}, - {"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff}, - {"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff}, - {"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff}, - {"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff}, - {"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff}, - {"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff}, - {"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff}, - {"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff}, - {"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff}, - {"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff}, - {"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff}, - {"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff}, - {"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff}, - {"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff}, - {"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff}, - {"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff}, - {"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff}, - {"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff}, - {"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff}, - {"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff}, - {"mcs2gpo0", 0x00000100, 0, SROM8_2G_MCSPO, 0xffff}, - {"mcs2gpo1", 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff}, - {"mcs2gpo2", 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff}, - {"mcs2gpo3", 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff}, - {"mcs2gpo4", 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff}, - {"mcs2gpo5", 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff}, - {"mcs2gpo6", 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff}, - {"mcs2gpo7", 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff}, - {"mcs5gpo0", 0x00000100, 0, SROM8_5G_MCSPO, 0xffff}, - {"mcs5gpo1", 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff}, - {"mcs5gpo2", 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff}, - {"mcs5gpo3", 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff}, - {"mcs5gpo4", 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff}, - {"mcs5gpo5", 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff}, - {"mcs5gpo6", 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff}, - {"mcs5gpo7", 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff}, - {"mcs5glpo0", 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff}, - {"mcs5glpo1", 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff}, - {"mcs5glpo2", 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff}, - {"mcs5glpo3", 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff}, - {"mcs5glpo4", 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff}, - {"mcs5glpo5", 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff}, - {"mcs5glpo6", 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff}, - {"mcs5glpo7", 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff}, - {"mcs5ghpo0", 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff}, - {"mcs5ghpo1", 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff}, - {"mcs5ghpo2", 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff}, - {"mcs5ghpo3", 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff}, - {"mcs5ghpo4", 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff}, - {"mcs5ghpo5", 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff}, - {"mcs5ghpo6", 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff}, - {"mcs5ghpo7", 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff}, - {"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff}, - {"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff}, - {"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff}, - {"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff}, - {"cddpo", 0x00000100, 0, SROM8_CDDPO, 0xffff}, - {"stbcpo", 0x00000100, 0, SROM8_STBCPO, 0xffff}, - {"bw40po", 0x00000100, 0, SROM8_BW40PO, 0xffff}, - {"bwduppo", 0x00000100, 0, SROM8_BWDUPPO, 0xffff}, - - /* power per rate from sromrev 9 */ - {"cckbw202gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20, 0xffff}, - {"cckbw20ul2gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20UL, 0xffff}, - {"legofdmbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20, 0xffff}, - {"", 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff}, - {"legofdmbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20UL, 0xffff}, - {"", 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff}, - {"legofdmbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20, 0xffff}, - {"", 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff}, - {"legofdmbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff}, - {"legofdmbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20, 0xffff}, - {"", 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff}, - {"legofdmbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff}, - {"legofdmbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20, 0xffff}, - {"", 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff}, - {"legofdmbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff}, - {"mcsbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20, 0xffff}, - {"", 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff}, - {"mcsbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20UL, 0xffff}, - {"", 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff}, - {"mcsbw402gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW40, 0xffff}, - {"", 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff}, - {"mcsbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20, 0xffff}, - {"", 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff}, - {"mcsbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff}, - {"mcsbw405glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW40, 0xffff}, - {"", 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff}, - {"mcsbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20, 0xffff}, - {"", 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff}, - {"mcsbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff}, - {"mcsbw405gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW40, 0xffff}, - {"", 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff}, - {"mcsbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20, 0xffff}, - {"", 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff}, - {"mcsbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20UL, 0xffff}, - {"", 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff}, - {"mcsbw405ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW40, 0xffff}, - {"", 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff}, - {"mcs32po", 0x00000600, 0, SROM9_PO_MCS32, 0xffff}, - {"legofdm40duppo", 0x00000600, 0, SROM9_PO_LOFDM40DUP, 0xffff}, - {"pcieingress_war", 0x00000700, 0, SROM8_PCIEINGRESS_WAR, 0xf}, - {"eu_edthresh2g", 0x00000100, 0, SROM8_EU_EDCRSTH, 0x00ff}, - {"eu_edthresh5g", 0x00000100, 0, SROM8_EU_EDCRSTH, 0xff00}, - {"eu_edthresh2g", 0x00000200, 0, SROM9_EU_EDCRSTH, 0x00ff}, - {"eu_edthresh5g", 0x00000200, 0, SROM9_EU_EDCRSTH, 0xff00}, - {"rxgainerr2ga0", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x003f}, - {"rxgainerr2ga0", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x003f}, - {"rxgainerr2ga1", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x07c0}, - {"rxgainerr2ga2", 0x00000700, 0, SROM8_RXGAINERR_2G, 0xf800}, - {"rxgainerr5gla0", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x003f}, - {"rxgainerr5gla1", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x07c0}, - {"rxgainerr5gla2", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0xf800}, - {"rxgainerr5gma0", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x003f}, - {"rxgainerr5gma1", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x07c0}, - {"rxgainerr5gma2", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0xf800}, - {"rxgainerr5gha0", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x003f}, - {"rxgainerr5gha1", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x07c0}, - {"rxgainerr5gha2", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0xf800}, - {"rxgainerr5gua0", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x003f}, - {"rxgainerr5gua1", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x07c0}, - {"rxgainerr5gua2", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0xf800}, - {"sar2g", 0x00000600, 0, SROM9_SAR, 0x00ff}, - {"sar5g", 0x00000600, 0, SROM9_SAR, 0xff00}, - {"noiselvl2ga0", 0x00000700, 0, SROM8_NOISELVL_2G, 0x001f}, - {"noiselvl2ga1", 0x00000700, 0, SROM8_NOISELVL_2G, 0x03e0}, - {"noiselvl2ga2", 0x00000700, 0, SROM8_NOISELVL_2G, 0x7c00}, - {"noiselvl5gla0", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x001f}, - {"noiselvl5gla1", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x03e0}, - {"noiselvl5gla2", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x7c00}, - {"noiselvl5gma0", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x001f}, - {"noiselvl5gma1", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x03e0}, - {"noiselvl5gma2", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x7c00}, - {"noiselvl5gha0", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x001f}, - {"noiselvl5gha1", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x03e0}, - {"noiselvl5gha2", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x7c00}, - {"noiselvl5gua0", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x001f}, - {"noiselvl5gua1", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x03e0}, - {"noiselvl5gua2", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x7c00}, - {"noisecaloffset", 0x00000300, 0, SROM8_NOISECALOFFSET, 0x00ff}, - {"noisecaloffset5g", 0x00000300, 0, SROM8_NOISECALOFFSET, 0xff00}, - {"subband5gver", 0x00000700, 0, SROM8_SUBBAND_PPR, 0x7}, - - {"cckPwrOffset", 0x00000400, 0, SROM10_CCKPWROFFSET, 0xffff}, - {"eu_edthresh2g", 0x00000400, 0, SROM10_EU_EDCRSTH, 0x00ff}, - {"eu_edthresh5g", 0x00000400, 0, SROM10_EU_EDCRSTH, 0xff00}, - /* swctrlmap_2g array, note that the last element doesn't have SRFL_ARRAY flag set */ - {"swctrlmap_2g", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G, 0xffff}, - {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 1, 0xffff}, - {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 2, 0xffff}, - {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 3, 0xffff}, - {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 4, 0xffff}, - {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 5, 0xffff}, - {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 6, 0xffff}, - {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 7, 0xffff}, - {"", 0x00000400, SRFL_PRHEX, SROM10_SWCTRLMAP_2G + 8, 0xffff}, - - /* sromrev 11 */ - {"boardflags3", 0xfffff800, SRFL_PRHEX|SRFL_MORE, SROM11_BFL4, 0xffff}, - {"", 0, 0, SROM11_BFL5, 0xffff}, - {"boardnum", 0xfffff800, 0, SROM11_MACLO, 0xffff}, - {"macaddr", 0xfffff800, SRFL_ETHADDR, SROM11_MACHI, 0xffff}, - {"ccode", 0xfffff800, SRFL_CCODE, SROM11_CCODE, 0xffff}, - {"regrev", 0xfffff800, 0, SROM11_REGREV, 0xffff}, - {"aa2g", 0xfffff800, 0, SROM11_AA, 0x00ff}, - {"aa5g", 0xfffff800, 0, SROM11_AA, 0xff00}, - {"agbg0", 0xfffff800, 0, SROM11_AGBG10, 0xff00}, - {"agbg1", 0xfffff800, 0, SROM11_AGBG10, 0x00ff}, - {"agbg2", 0xfffff800, 0, SROM11_AGBG2A0, 0xff00}, - {"aga0", 0xfffff800, 0, SROM11_AGBG2A0, 0x00ff}, - {"aga1", 0xfffff800, 0, SROM11_AGA21, 0xff00}, - {"aga2", 0xfffff800, 0, SROM11_AGA21, 0x00ff}, - {"txchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_TXCHAIN_MASK}, - {"rxchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_RXCHAIN_MASK}, - {"antswitch", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_SWITCH_MASK}, - - {"tssiposslope2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0001}, - {"epagain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x000e}, - {"pdgain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x01f0}, - {"tworangetssi2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0200}, - {"papdcap2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0400}, - {"femctrl", 0xfffff800, 0, SROM11_FEM_CFG1, 0xf800}, - - {"tssiposslope5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0001}, - {"epagain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x000e}, - {"pdgain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x01f0}, - {"tworangetssi5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0200}, - {"papdcap5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0400}, - {"gainctrlsph", 0xfffff800, 0, SROM11_FEM_CFG2, 0xf800}, - - {"tempthresh", 0xfffff800, 0, SROM11_THERMAL, 0xff00}, - {"tempoffset", 0xfffff800, 0, SROM11_THERMAL, 0x00ff}, - {"rawtempsense", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0x01ff}, - {"measpower", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0xfe00}, - {"tempsense_slope", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x00ff}, - {"tempcorrx", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0xfc00}, - {"tempsense_option", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x0300}, - {"xtalfreq", 0xfffff800, 0, SROM11_XTAL_FREQ, 0xffff}, - {"txpwrbckof", 0x00000800, SRFL_PRHEX, SROM11_PATH0 + SROM11_2G_MAXP, 0xff00}, - /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #1 */ - {"pa5gbw4080a1", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W0_A1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W1_A1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W2_A1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_4080_W0_A1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_4080_PA + 2, 0xffff}, - {"phycal_tempdelta", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x00ff}, - {"temps_period", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x0f00}, - {"temps_hysteresis", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0xf000}, - {"measpower1", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x007f}, - {"measpower2", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x3f80}, - {"tssifloor2g", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_2G, 0x03ff}, - {"tssifloor5g", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GL, 0x03ff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GM, 0x03ff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GH, 0x03ff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_5GU, 0x03ff}, - {"pdoffset2g40ma0", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x000f}, - {"pdoffset2g40ma1", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x00f0}, - {"pdoffset2g40ma2", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x0f00}, - {"pdoffset2g40mvalid", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x8000}, - {"pdoffset40ma0", 0xfffff800, 0, SROM11_PDOFF_40M_A0, 0xffff}, - {"pdoffset40ma1", 0xfffff800, 0, SROM11_PDOFF_40M_A1, 0xffff}, - {"pdoffset40ma2", 0xfffff800, 0, SROM11_PDOFF_40M_A2, 0xffff}, - {"pdoffset80ma0", 0xfffff800, 0, SROM11_PDOFF_80M_A0, 0xffff}, - {"pdoffset80ma1", 0xfffff800, 0, SROM11_PDOFF_80M_A1, 0xffff}, - {"pdoffset80ma2", 0xfffff800, 0, SROM11_PDOFF_80M_A2, 0xffff}, - - {"subband5gver", 0xfffff800, SRFL_PRHEX, SROM11_SUBBAND5GVER, 0xffff}, - {"paparambwver", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0xf000}, - {"rx5ggainwar", 0xfffff800, 0, SROM11_MCSLR5GMPO, 0x2000}, - /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #0 */ - {"pa5gbw4080a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 +SROM11_5GB0_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, - /* Special PA Params for 4335 5G Band, 40 MHz BW */ - {"pa5gbw40a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_5GB3_PA + 2, 0xffff}, - /* Special PA Params for 4335 5G Band, 80 MHz BW */ - {"pa5gbw80a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, - /* Special PA Params for 4335 2G Band, CCK */ - {"pa2gccka0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA + 1, 0xffff}, - {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_2G_PA + 2, 0xffff}, - - /* power per rate */ - {"cckbw202gpo", 0xfffff800, 0, SROM11_CCKBW202GPO, 0xffff}, - {"cckbw20ul2gpo", 0xfffff800, 0, SROM11_CCKBW20UL2GPO, 0xffff}, - {"mcsbw202gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW202GPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW202GPO_1, 0xffff}, - {"mcsbw402gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW402GPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW402GPO_1, 0xffff}, - {"dot11agofdmhrbw202gpo", 0xfffff800, 0, SROM11_DOT11AGOFDMHRBW202GPO, 0xffff}, - {"ofdmlrbw202gpo", 0xfffff800, 0, SROM11_OFDMLRBW202GPO, 0xffff}, - {"mcsbw205glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GLPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW205GLPO_1, 0xffff}, - {"mcsbw405glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GLPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW405GLPO_1, 0xffff}, - {"mcsbw805glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GLPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW805GLPO_1, 0xffff}, - {"mcsbw205gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GMPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW205GMPO_1, 0xffff}, - {"mcsbw405gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GMPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW405GMPO_1, 0xffff}, - {"mcsbw805gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GMPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW805GMPO_1, 0xffff}, - {"mcsbw205ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GHPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW205GHPO_1, 0xffff}, - {"mcsbw405ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GHPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW405GHPO_1, 0xffff}, - {"mcsbw805ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GHPO, 0xffff}, - {"", 0xfffff800, 0, SROM11_MCSBW805GHPO_1, 0xffff}, - {"mcslr5glpo", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0x0fff}, - {"mcslr5gmpo", 0xfffff800, 0, SROM11_MCSLR5GMPO, 0xffff}, - {"mcslr5ghpo", 0xfffff800, 0, SROM11_MCSLR5GHPO, 0xffff}, - {"sb20in40hrpo", 0xfffff800, 0, SROM11_SB20IN40HRPO, 0xffff}, - {"sb20in80and160hr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GLPO, 0xffff}, - {"sb40and80hr5glpo", 0xfffff800, 0, SROM11_SB40AND80HR5GLPO, 0xffff}, - {"sb20in80and160hr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GMPO, 0xffff}, - {"sb40and80hr5gmpo", 0xfffff800, 0, SROM11_SB40AND80HR5GMPO, 0xffff}, - {"sb20in80and160hr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GHPO, 0xffff}, - {"sb40and80hr5ghpo", 0xfffff800, 0, SROM11_SB40AND80HR5GHPO, 0xffff}, - {"sb20in40lrpo", 0xfffff800, 0, SROM11_SB20IN40LRPO, 0xffff}, - {"sb20in80and160lr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GLPO, 0xffff}, - {"sb40and80lr5glpo", 0xfffff800, 0, SROM11_SB40AND80LR5GLPO, 0xffff}, - {"sb20in80and160lr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GMPO, 0xffff}, - {"sb40and80lr5gmpo", 0xfffff800, 0, SROM11_SB40AND80LR5GMPO, 0xffff}, - {"sb20in80and160lr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GHPO, 0xffff}, - {"sb40and80lr5ghpo", 0xfffff800, 0, SROM11_SB40AND80LR5GHPO, 0xffff}, - {"dot11agduphrpo", 0xfffff800, 0, SROM11_DOT11AGDUPHRPO, 0xffff}, - {"dot11agduplrpo", 0xfffff800, 0, SROM11_DOT11AGDUPLRPO, 0xffff}, - - /* Misc */ - {"sar2g", 0xfffff800, 0, SROM11_SAR, 0x00ff}, - {"sar5g", 0xfffff800, 0, SROM11_SAR, 0xff00}, - - {"noiselvl2ga0", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x001f}, - {"noiselvl2ga1", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x03e0}, - {"noiselvl2ga2", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x7c00}, - {"noiselvl5ga0", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x001f}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x001f}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x001f}, - {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x001f}, - {"noiselvl5ga1", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x03e0}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x03e0}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x03e0}, - {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x03e0}, - {"noiselvl5ga2", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x7c00}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x7c00}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x7c00}, - {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x7c00}, - {"eu_edthresh2g", 0x00000800, 0, SROM11_EU_EDCRSTH, 0x00ff}, - {"eu_edthresh5g", 0x00000800, 0, SROM11_EU_EDCRSTH, 0xff00}, - - {"rxgainerr2ga0", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x003f}, - {"rxgainerr2ga1", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x07c0}, - {"rxgainerr2ga2", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0xf800}, - {"rxgainerr5ga0", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x003f}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x003f}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x003f}, - {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x003f}, - {"rxgainerr5ga1", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x07c0}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x07c0}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x07c0}, - {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x07c0}, - {"rxgainerr5ga2", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0xf800}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0xf800}, - {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0xf800}, - {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0xf800}, - {"rpcal2g", 0xfffff800, 0, SROM11_RPCAL_2G, 0xffff}, - {"rpcal5gb0", 0xfffff800, 0, SROM11_RPCAL_5GL, 0xffff}, - {"rpcal5gb1", 0xfffff800, 0, SROM11_RPCAL_5GM, 0xffff}, - {"rpcal5gb2", 0xfffff800, 0, SROM11_RPCAL_5GH, 0xffff}, - {"rpcal5gb3", 0xfffff800, 0, SROM11_RPCAL_5GU, 0xffff}, - {"txidxcap2g", 0xfffff800, 0, SROM11_TXIDXCAP2G, 0x0ff0}, - {"txidxcap5g", 0xfffff800, 0, SROM11_TXIDXCAP5G, 0x0ff0}, - {"pdoffsetcckma0", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x000f}, - {"pdoffsetcckma1", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x00f0}, - {"pdoffsetcckma2", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x0f00}, - - /* sromrev 12 */ - {"boardflags4", 0xfffff000, SRFL_PRHEX|SRFL_MORE, SROM12_BFL6, 0xffff}, - {"", 0, 0, SROM12_BFL7, 0xffff}, - {"pdoffsetcck", 0xfffff000, 0, SROM12_PDOFF_2G_CCK, 0xffff}, - {"pdoffset20in40m5gb0", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B0, 0xffff}, - {"pdoffset20in40m5gb1", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B1, 0xffff}, - {"pdoffset20in40m5gb2", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B2, 0xffff}, - {"pdoffset20in40m5gb3", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B3, 0xffff}, - {"pdoffset20in40m5gb4", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B4, 0xffff}, - {"pdoffset40in80m5gb0", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B0, 0xffff}, - {"pdoffset40in80m5gb1", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B1, 0xffff}, - {"pdoffset40in80m5gb2", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B2, 0xffff}, - {"pdoffset40in80m5gb3", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B3, 0xffff}, - {"pdoffset40in80m5gb4", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B4, 0xffff}, - {"pdoffset20in80m5gb0", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B0, 0xffff}, - {"pdoffset20in80m5gb1", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B1, 0xffff}, - {"pdoffset20in80m5gb2", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B2, 0xffff}, - {"pdoffset20in80m5gb3", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B3, 0xffff}, - {"pdoffset20in80m5gb4", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B4, 0xffff}, - - /* power per rate */ - {"mcsbw205gx1po", 0xfffff000, SRFL_MORE, SROM12_MCSBW205GX1PO, 0xffff}, - {"", 0xfffff000, 0, SROM12_MCSBW205GX1PO_1, 0xffff}, - {"mcsbw405gx1po", 0xfffff000, SRFL_MORE, SROM12_MCSBW405GX1PO, 0xffff}, - {"", 0xfffff000, 0, SROM12_MCSBW405GX1PO_1, 0xffff}, - {"mcsbw805gx1po", 0xfffff000, SRFL_MORE, SROM12_MCSBW805GX1PO, 0xffff}, - {"", 0xfffff000, 0, SROM12_MCSBW805GX1PO_1, 0xffff}, - {"mcsbw205gx2po", 0xfffff000, SRFL_MORE, SROM12_MCSBW205GX2PO, 0xffff}, - {"", 0xfffff000, 0, SROM12_MCSBW205GX2PO_1, 0xffff}, - {"mcsbw405gx2po", 0xfffff000, SRFL_MORE, SROM12_MCSBW405GX2PO, 0xffff}, - {"", 0xfffff000, 0, SROM12_MCSBW405GX2PO_1, 0xffff}, - {"mcsbw805gx2po", 0xfffff000, SRFL_MORE, SROM12_MCSBW805GX2PO, 0xffff}, - {"", 0xfffff000, 0, SROM12_MCSBW805GX2PO_1, 0xffff}, - - {"sb20in80and160hr5gx1po", 0xfffff000, 0, SROM12_SB20IN80AND160HR5GX1PO, 0xffff}, - {"sb40and80hr5gx1po", 0xfffff000, 0, SROM12_SB40AND80HR5GX1PO, 0xffff}, - {"sb20in80and160lr5gx1po", 0xfffff000, 0, SROM12_SB20IN80AND160LR5GX1PO, 0xffff}, - {"sb40and80hr5gx1po", 0xfffff000, 0, SROM12_SB40AND80HR5GX1PO, 0xffff}, - {"sb20in80and160hr5gx2po", 0xfffff000, 0, SROM12_SB20IN80AND160HR5GX2PO, 0xffff}, - {"sb40and80hr5gx2po", 0xfffff000, 0, SROM12_SB40AND80HR5GX2PO, 0xffff}, - {"sb20in80and160lr5gx2po", 0xfffff000, 0, SROM12_SB20IN80AND160LR5GX2PO, 0xffff}, - {"sb40and80hr5gx2po", 0xfffff000, 0, SROM12_SB40AND80HR5GX2PO, 0xffff}, - - {"rxgains5gmelnagaina0", 0xfffff000, 0, SROM12_RXGAINS10, 0x0007}, - {"rxgains5gmelnagaina1", 0xfffff000, 0, SROM12_RXGAINS11, 0x0007}, - {"rxgains5gmelnagaina2", 0xfffff000, 0, SROM12_RXGAINS12, 0x0007}, - {"rxgains5gmtrisoa0", 0xfffff000, 0, SROM12_RXGAINS10, 0x0078}, - {"rxgains5gmtrisoa1", 0xfffff000, 0, SROM12_RXGAINS11, 0x0078}, - {"rxgains5gmtrisoa2", 0xfffff000, 0, SROM12_RXGAINS12, 0x0078}, - {"rxgains5gmtrelnabypa0", 0xfffff000, 0, SROM12_RXGAINS10, 0x0080}, - {"rxgains5gmtrelnabypa1", 0xfffff000, 0, SROM12_RXGAINS11, 0x0080}, - {"rxgains5gmtrelnabypa2", 0xfffff000, 0, SROM12_RXGAINS12, 0x0080}, - {"rxgains5ghelnagaina0", 0xfffff000, 0, SROM12_RXGAINS10, 0x0700}, - {"rxgains5ghelnagaina1", 0xfffff000, 0, SROM12_RXGAINS11, 0x0700}, - {"rxgains5ghelnagaina2", 0xfffff000, 0, SROM12_RXGAINS12, 0x0700}, - {"rxgains5ghtrisoa0", 0xfffff000, 0, SROM12_RXGAINS10, 0x7800}, - {"rxgains5ghtrisoa1", 0xfffff000, 0, SROM12_RXGAINS11, 0x7800}, - {"rxgains5ghtrisoa2", 0xfffff000, 0, SROM12_RXGAINS12, 0x7800}, - {"rxgains5ghtrelnabypa0", 0xfffff000, 0, SROM12_RXGAINS10, 0x8000}, - {"rxgains5ghtrelnabypa1", 0xfffff000, 0, SROM12_RXGAINS11, 0x8000}, - {"rxgains5ghtrelnabypa2", 0xfffff000, 0, SROM12_RXGAINS12, 0x8000}, - {"eu_edthresh2g", 0x00001000, 0, SROM12_EU_EDCRSTH, 0x00ff}, - {"eu_edthresh5g", 0x00001000, 0, SROM12_EU_EDCRSTH, 0xff00}, - - {"gpdn", 0xfffff000, SRFL_PRHEX|SRFL_MORE, SROM12_GPDN_L, 0xffff}, - {"", 0, 0, SROM12_GPDN_H, 0xffff}, - - {"rpcal2gcore3", 0xffffe000, 0, SROM13_RPCAL2GCORE3, 0x00ff}, - {"rpcal5gb0core3", 0xffffe000, 0, SROM13_RPCAL5GB01CORE3, 0x00ff}, - {"rpcal5gb1core3", 0xffffe000, 0, SROM13_RPCAL5GB01CORE3, 0xff00}, - {"rpcal5gb2core3", 0xffffe000, 0, SROM13_RPCAL5GB23CORE3, 0x00ff}, - {"rpcal5gb3core3", 0xffffe000, 0, SROM13_RPCAL5GB23CORE3, 0xff00}, - - {"sw_txchain_mask", 0xffffe000, 0, SROM13_SW_TXRX_MASK, 0x000f}, - {"sw_rxchain_mask", 0xffffe000, 0, SROM13_SW_TXRX_MASK, 0x00f0}, - - {"eu_edthresh2g", 0x00002000, 0, SROM13_EU_EDCRSTH, 0x00ff}, - {"eu_edthresh5g", 0x00002000, 0, SROM13_EU_EDCRSTH, 0xff00}, - - {"agbg3", 0xffffe000, 0, SROM13_ANTGAIN_BANDBGA, 0xff00}, - {"aga3", 0xffffe000, 0, SROM13_ANTGAIN_BANDBGA, 0x00ff}, - {"noiselvl2ga3", 0xffffe000, 0, SROM13_NOISELVLCORE3, 0x001f}, - {"noiselvl5ga3", 0xffffe000, SRFL_ARRAY, SROM13_NOISELVLCORE3, 0x03e0}, - {"", 0xffffe000, SRFL_ARRAY, SROM13_NOISELVLCORE3, 0x7c00}, - {"", 0xffffe000, SRFL_ARRAY, SROM13_NOISELVLCORE3_1, 0x001f}, - {"", 0xffffe000, 0, SROM13_NOISELVLCORE3_1, 0x03e0}, - {"rxgainerr2ga3", 0xffffe000, 0, SROM13_RXGAINERRCORE3, 0x001f}, - {"rxgainerr5ga3", 0xffffe000, SRFL_ARRAY, SROM13_RXGAINERRCORE3, 0x03e0}, - {"", 0xffffe000, SRFL_ARRAY, SROM13_RXGAINERRCORE3, 0x7c00}, - {"", 0xffffe000, SRFL_ARRAY, SROM13_RXGAINERRCORE3_1, 0x001f}, - {"", 0xffffe000, 0, SROM13_RXGAINERRCORE3_1, 0x03e0}, - {"rxgains5gmelnagaina3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x0007}, - {"rxgains5gmtrisoa3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x0078}, - {"rxgains5gmtrelnabypa3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x0080}, - {"rxgains5ghelnagaina3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x0700}, - {"rxgains5ghtrisoa3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x7800}, - {"rxgains5ghtrelnabypa3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x8000}, - - /* pdoffset */ - {"pdoffset20in40m5gcore3", 0xffffe000, 0, SROM13_PDOFFSET20IN40M5GCORE3, 0xffff}, - {"pdoffset20in40m5gcore3_1", 0xffffe000, 0, SROM13_PDOFFSET20IN40M5GCORE3_1, 0xffff}, - {"pdoffset20in80m5gcore3", 0xffffe000, 0, SROM13_PDOFFSET20IN80M5GCORE3, 0xffff}, - {"pdoffset20in80m5gcore3_1", 0xffffe000, 0, SROM13_PDOFFSET20IN80M5GCORE3_1, 0xffff}, - {"pdoffset40in80m5gcore3", 0xffffe000, 0, SROM13_PDOFFSET40IN80M5GCORE3, 0xffff}, - {"pdoffset40in80m5gcore3_1", 0xffffe000, 0, SROM13_PDOFFSET40IN80M5GCORE3_1, 0xffff}, - - {"pdoffset20in40m2g", 0xffffe000, 0, SROM13_PDOFFSET20IN40M2G, 0xffff}, - {"pdoffset20in40m2gcore3", 0xffffe000, 0, SROM13_PDOFFSET20IN40M2GCORE3, 0xffff}, - {"pdoffsetcck20m", 0xffffe000, 0, SROM13_PDOFF_2G_CCK_20M, 0xffff}, - - /* power per rate */ - {"mcs1024qam2gpo", 0xffffe000, 0, SROM13_MCS1024QAM2GPO, 0xffff}, - {"mcs1024qam5glpo", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GLPO, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCS1024QAM5GLPO_1, 0xffff}, - {"mcs1024qam5gmpo", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GMPO, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCS1024QAM5GMPO_1, 0xffff}, - {"mcs1024qam5ghpo", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GHPO, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCS1024QAM5GHPO_1, 0xffff}, - {"mcs1024qam5gx1po", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GX1PO, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCS1024QAM5GX1PO_1, 0xffff}, - {"mcs1024qam5gx2po", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GX2PO, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCS1024QAM5GX2PO_1, 0xffff}, - - {"mcsbw1605glpo", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GLPO, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCSBW1605GLPO_1, 0xffff}, - {"mcsbw1605gmpo", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GMPO, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCSBW1605GMPO_1, 0xffff}, - {"mcsbw1605ghpo", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GHPO, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCSBW1605GHPO_1, 0xffff}, - {"mcsbw1605gx1po", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GX1PO, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCSBW1605GX1PO_1, 0xffff}, - {"mcsbw1605gx2po", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GX2PO, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCSBW1605GX2PO_1, 0xffff}, - - {"ulbpproffs2g", 0xffffe000, 0, SROM13_ULBPPROFFS2G, 0xffff}, - - {"mcs8poexp", 0xffffe000, SRFL_MORE, SROM13_MCS8POEXP, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCS8POEXP_1, 0xffff}, - {"mcs9poexp", 0xffffe000, SRFL_MORE, SROM13_MCS9POEXP, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCS9POEXP_1, 0xffff}, - {"mcs10poexp", 0xffffe000, SRFL_MORE, SROM13_MCS10POEXP, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCS10POEXP_1, 0xffff}, - {"mcs11poexp", 0xffffe000, SRFL_MORE, SROM13_MCS11POEXP, 0xffff}, - {"", 0xffffe000, 0, SROM13_MCS11POEXP_1, 0xffff}, - - {"ulbpdoffs5gb0a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB0A0, 0xffff}, - {"ulbpdoffs5gb0a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB0A1, 0xffff}, - {"ulbpdoffs5gb0a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB0A2, 0xffff}, - {"ulbpdoffs5gb0a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB0A3, 0xffff}, - {"ulbpdoffs5gb1a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB1A0, 0xffff}, - {"ulbpdoffs5gb1a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB1A1, 0xffff}, - {"ulbpdoffs5gb1a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB1A2, 0xffff}, - {"ulbpdoffs5gb1a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB1A3, 0xffff}, - {"ulbpdoffs5gb2a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB2A0, 0xffff}, - {"ulbpdoffs5gb2a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB2A1, 0xffff}, - {"ulbpdoffs5gb2a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB2A2, 0xffff}, - {"ulbpdoffs5gb2a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB2A3, 0xffff}, - {"ulbpdoffs5gb3a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB3A0, 0xffff}, - {"ulbpdoffs5gb3a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB3A1, 0xffff}, - {"ulbpdoffs5gb3a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB3A2, 0xffff}, - {"ulbpdoffs5gb3a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB3A3, 0xffff}, - {"ulbpdoffs5gb4a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB4A0, 0xffff}, - {"ulbpdoffs5gb4a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB4A1, 0xffff}, - {"ulbpdoffs5gb4a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB4A2, 0xffff}, - {"ulbpdoffs5gb4a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB4A3, 0xffff}, - {"ulbpdoffs2ga0", 0xffffe000, 0, SROM13_ULBPDOFFS2GA0, 0xffff}, - {"ulbpdoffs2ga1", 0xffffe000, 0, SROM13_ULBPDOFFS2GA1, 0xffff}, - {"ulbpdoffs2ga2", 0xffffe000, 0, SROM13_ULBPDOFFS2GA2, 0xffff}, - {"ulbpdoffs2ga3", 0xffffe000, 0, SROM13_ULBPDOFFS2GA3, 0xffff}, - - {"rpcal5gb4", 0xffffe000, 0, SROM13_RPCAL5GB4, 0xffff}, - - {"sb20in40hrlrpox", 0xffffe000, 0, SROM13_SB20IN40HRLRPOX, 0xffff}, - - {"swctrlmap4_cfg", 0xffffe000, 0, SROM13_SWCTRLMAP4_CFG, 0xffff}, - {"swctrlmap4_TX2g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_TX2G_FEM3TO0, 0xffff}, - {"swctrlmap4_RX2g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_RX2G_FEM3TO0, 0xffff}, - {"swctrlmap4_RXByp2g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_RXBYP2G_FEM3TO0, 0xffff}, - {"swctrlmap4_misc2g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_MISC2G_FEM3TO0, 0xffff}, - {"swctrlmap4_TX5g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_TX5G_FEM3TO0, 0xffff}, - {"swctrlmap4_RX5g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_RX5G_FEM3TO0, 0xffff}, - {"swctrlmap4_RXByp5g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_RXBYP5G_FEM3TO0, 0xffff}, - {"swctrlmap4_misc5g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_MISC5G_FEM3TO0, 0xffff}, - {"swctrlmap4_TX2g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_TX2G_FEM7TO4, 0xffff}, - {"swctrlmap4_RX2g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_RX2G_FEM7TO4, 0xffff}, - {"swctrlmap4_RXByp2g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_RXBYP2G_FEM7TO4, 0xffff}, - {"swctrlmap4_misc2g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_MISC2G_FEM7TO4, 0xffff}, - {"swctrlmap4_TX5g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_TX5G_FEM7TO4, 0xffff}, - {"swctrlmap4_RX5g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_RX5G_FEM7TO4, 0xffff}, - {"swctrlmap4_RXByp5g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_RXBYP5G_FEM7TO4, 0xffff}, - {"swctrlmap4_misc5g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_MISC5G_FEM7TO4, 0xffff}, - {NULL, 0, 0, 0, 0} -}; -#endif /* !defined(SROM15_MEMOPT) */ - -static const sromvar_t BCMATTACHDATA(pci_srom15vars)[] = { - {"macaddr", 0x00008000, SRFL_ETHADDR, SROM15_MACHI, 0xffff}, - {"caldata_offset", 0x00008000, 0, SROM15_CAL_OFFSET_LOC, 0xffff}, - {"boardrev", 0x00008000, SRFL_PRHEX, SROM15_BRDREV, 0xffff}, - {"ccode", 0x00008000, SRFL_CCODE, SROM15_CCODE, 0xffff}, - {"regrev", 0x00008000, 0, SROM15_REGREV, 0xffff}, - {NULL, 0, 0, 0, 0} -}; - -static const sromvar_t BCMATTACHDATA(pci_srom16vars)[] = { - {"macaddr", 0x00010000, SRFL_ETHADDR, SROM16_MACHI, 0xffff}, - {"caldata_offset", 0x00010000, 0, SROM16_CALDATA_OFFSET_LOC, 0xffff}, - {"boardrev", 0x00010000, SRFL_PRHEX, SROM16_BOARDREV, 0xffff}, - {"ccode", 0x00010000, SRFL_CCODE, SROM16_CCODE, 0xffff}, - {"regrev", 0x00010000, 0, SROM16_REGREV, 0xffff}, - {NULL, 0, 0, 0, 0} -}; - -static const sromvar_t BCMATTACHDATA(pci_srom17vars)[] = { - {"boardrev", 0x00020000, SRFL_PRHEX, SROM17_BRDREV, 0xffff}, - {"macaddr", 0x00020000, SRFL_ETHADDR, SROM17_MACADDR, 0xffff}, - {"ccode", 0x00020000, SRFL_CCODE, SROM17_CCODE, 0xffff}, - {"caldata_offset", 0x00020000, 0, SROM17_CALDATA, 0xffff}, - {"gain_cal_temp", 0x00020000, SRFL_PRHEX, SROM17_GCALTMP, 0xffff}, - {"rssi_delta_2gb0_c0", 0x00020000, PRHEX_N_MORE, SROM17_C0SRD202G, 0xffff}, - {"", 0x00020000, 0, SROM17_C0SRD202G_1, 0xffff}, - {"rssi_delta_5gl_c0", 0x00020000, PRHEX_N_MORE, SROM17_C0SRD205GL, 0xffff}, - {"", 0x00020000, 0, SROM17_C0SRD205GL_1, 0xffff}, - {"rssi_delta_5gml_c0", 0x00020000, PRHEX_N_MORE, SROM17_C0SRD205GML, 0xffff}, - {"", 0x00020000, 0, SROM17_C0SRD205GML_1, 0xffff}, - {"rssi_delta_5gmu_c0", 0x00020000, PRHEX_N_MORE, SROM17_C0SRD205GMU, 0xffff}, - {"", 0x00020000, 0, SROM17_C0SRD205GMU_1, 0xffff}, - {"rssi_delta_5gh_c0", 0x00020000, PRHEX_N_MORE, SROM17_C0SRD205GH, 0xffff}, - {"", 0x00020000, 0, SROM17_C0SRD205GH_1, 0xffff}, - {"rssi_delta_2gb0_c1", 0x00020000, PRHEX_N_MORE, SROM17_C1SRD202G, 0xffff}, - {"", 0x00020000, 0, SROM17_C1SRD202G_1, 0xffff}, - {"rssi_delta_5gl_c1", 0x00020000, PRHEX_N_MORE, SROM17_C1SRD205GL, 0xffff}, - {"", 0x00020000, 0, SROM17_C1SRD205GL_1, 0xffff}, - {"rssi_delta_5gml_c1", 0x00020000, PRHEX_N_MORE, SROM17_C1SRD205GML, 0xffff}, - {"", 0x00020000, 0, SROM17_C1SRD205GML_1, 0xffff}, - {"rssi_delta_5gmu_c1", 0x00020000, PRHEX_N_MORE, SROM17_C1SRD205GMU, 0xffff}, - {"", 0x00020000, 0, SROM17_C1SRD205GMU_1, 0xffff}, - {"rssi_delta_5gh_c1", 0x00020000, PRHEX_N_MORE, SROM17_C1SRD205GH, 0xffff}, - {"", 0x00020000, 0, SROM17_C1SRD205GH_1, 0xffff}, - {"txpa_trim_magic", 0x00020000, PRHEX_N_MORE, SROM17_TRAMMAGIC, 0xffff}, - {"", 0x00020000, 0, SROM17_TRAMMAGIC_1, 0xffff}, - {"txpa_trim_data", 0x00020000, SRFL_PRHEX, SROM17_TRAMDATA, 0xffff}, - {NULL, 0, 0, 0, 0x00} -}; - -static const sromvar_t BCMATTACHDATA(pci_srom18vars)[] = { - {"macaddr", 0x00040000, SRFL_ETHADDR, SROM18_MACHI, 0xffff}, - {"caldata_offset", 0x00040000, 0, SROM18_CALDATA_OFFSET_LOC, 0xffff}, - {"boardrev", 0x00040000, SRFL_PRHEX, SROM18_BOARDREV, 0xffff}, - {"ccode", 0x00040000, SRFL_CCODE, SROM18_CCODE, 0xffff}, - {"regrev", 0x00040000, 0, SROM18_REGREV, 0xffff}, - {NULL, 0, 0, 0, 0} -}; - -static const sromvar_t BCMATTACHDATA(perpath_pci_sromvars)[] = { - {"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff}, - {"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00}, - {"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00}, - {"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff}, - {"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff}, - {"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff}, - {"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff}, - {"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff}, - {"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff}, - {"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00}, - {"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff}, - {"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff}, - {"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff}, - {"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff}, - {"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff}, - {"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, 0xffff}, - {"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, 0xffff}, - {"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, 0xffff}, - {"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff}, - {"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, 0xffff}, - {"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, 0xffff}, - {"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, 0xffff}, - {"maxp2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0x00ff}, - {"itt2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0xff00}, - {"itt5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0xff00}, - {"pa2gw0a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA, 0xffff}, - {"pa2gw1a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff}, - {"pa2gw2a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff}, - {"maxp5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0x00ff}, - {"maxp5gha", 0x00000700, 0, SROM8_5GLH_MAXP, 0x00ff}, - {"maxp5gla", 0x00000700, 0, SROM8_5GLH_MAXP, 0xff00}, - {"pa5gw0a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA, 0xffff}, - {"pa5gw1a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff}, - {"pa5gw2a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff}, - {"pa5glw0a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA, 0xffff}, - {"pa5glw1a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 1, 0xffff}, - {"pa5glw2a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 2, 0xffff}, - {"pa5ghw0a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA, 0xffff}, - {"pa5ghw1a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 1, 0xffff}, - {"pa5ghw2a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 2, 0xffff}, - - /* sromrev 11 */ - {"maxp2ga", 0xfffff800, 0, SROM11_2G_MAXP, 0x00ff}, - {"pa2ga", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA, 0xffff}, - {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA + 1, 0xffff}, - {"", 0x00000800, SRFL_PRHEX, SROM11_2G_PA + 2, 0xffff}, - {"rxgains5gmelnagaina", 0x00000800, 0, SROM11_RXGAINS1, 0x0007}, - {"rxgains5gmtrisoa", 0x00000800, 0, SROM11_RXGAINS1, 0x0078}, - {"rxgains5gmtrelnabypa", 0x00000800, 0, SROM11_RXGAINS1, 0x0080}, - {"rxgains5ghelnagaina", 0x00000800, 0, SROM11_RXGAINS1, 0x0700}, - {"rxgains5ghtrisoa", 0x00000800, 0, SROM11_RXGAINS1, 0x7800}, - {"rxgains5ghtrelnabypa", 0x00000800, 0, SROM11_RXGAINS1, 0x8000}, - {"rxgains2gelnagaina", 0x00000800, 0, SROM11_RXGAINS, 0x0007}, - {"rxgains2gtrisoa", 0x00000800, 0, SROM11_RXGAINS, 0x0078}, - {"rxgains2gtrelnabypa", 0x00000800, 0, SROM11_RXGAINS, 0x0080}, - {"rxgains5gelnagaina", 0x00000800, 0, SROM11_RXGAINS, 0x0700}, - {"rxgains5gtrisoa", 0x00000800, 0, SROM11_RXGAINS, 0x7800}, - {"rxgains5gtrelnabypa", 0x00000800, 0, SROM11_RXGAINS, 0x8000}, - {"maxp5ga", 0x00000800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0x00ff}, - {"", 0x00000800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0xff00}, - {"", 0x00000800, SRFL_ARRAY, SROM11_5GB3B2_MAXP, 0x00ff}, - {"", 0x00000800, 0, SROM11_5GB3B2_MAXP, 0xff00}, - {"pa5ga", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA, 0xffff}, - {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 1, 0xffff}, - {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 2, 0xffff}, - {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA, 0xffff}, - {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 1, 0xffff}, - {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 2, 0xffff}, - {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA, 0xffff}, - {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 1, 0xffff}, - {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 2, 0xffff}, - {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA, 0xffff}, - {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA + 1, 0xffff}, - {"", 0x00000800, SRFL_PRHEX, SROM11_5GB3_PA + 2, 0xffff}, - - /* sromrev 12 */ - {"maxp5gb4a", 0xfffff000, 0, SROM12_5GB42G_MAXP, 0x00ff00}, - {"pa2ga", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2GB0_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2GB0_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2GB0_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX, SROM12_2GB0_PA_W3, 0x00ffff}, - - {"pa2g40a", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2G40B0_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2G40B0_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2G40B0_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX, SROM12_2G40B0_PA_W3, 0x00ffff}, - {"maxp5gb0a", 0xfffff000, 0, SROM12_5GB1B0_MAXP, 0x00ff}, - {"maxp5gb1a", 0xfffff000, 0, SROM12_5GB1B0_MAXP, 0x00ff00}, - {"maxp5gb2a", 0xfffff000, 0, SROM12_5GB3B2_MAXP, 0x00ff}, - {"maxp5gb3a", 0xfffff000, 0, SROM12_5GB3B2_MAXP, 0x00ff00}, - - {"pa5ga", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB0_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB0_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB0_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB0_PA_W3, 0x00ffff}, - - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB1_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB1_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB1_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB1_PA_W3, 0x00ffff}, - - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB2_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB2_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB2_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB2_PA_W3, 0x00ffff}, - - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB3_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB3_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB3_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB3_PA_W3, 0x00ffff}, - - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB4_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB4_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB4_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX, SROM12_5GB4_PA_W3, 0x00ffff}, - - {"pa5g40a", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B0_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B0_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B0_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B0_PA_W3, 0x00ffff}, - - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B1_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B1_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B1_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B1_PA_W3, 0x00ffff}, - - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B2_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B2_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B2_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B2_PA_W3, 0x00ffff}, - - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B3_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B3_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B3_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B3_PA_W3, 0x00ffff}, - - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B4_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B4_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B4_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX, SROM12_5G40B4_PA_W3, 0x00ffff}, - - {"pa5g80a", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B0_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B0_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B0_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B0_PA_W3, 0x00ffff}, - - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B1_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B1_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B1_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B1_PA_W3, 0x00ffff}, - - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B2_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B2_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B2_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B2_PA_W3, 0x00ffff}, - - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B3_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B3_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B3_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B3_PA_W3, 0x00ffff}, - - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B4_PA_W0, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B4_PA_W1, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B4_PA_W2, 0x00ffff}, - {"", 0xfffff000, SRFL_PRHEX, SROM12_5G80B4_PA_W3, 0x00ffff}, - /* sromrev 13 */ - {"rxgains2gelnagaina", 0xffffe000, 0, SROM13_RXGAINS, 0x0007}, - {"rxgains2gtrisoa", 0xffffe000, 0, SROM13_RXGAINS, 0x0078}, - {"rxgains2gtrelnabypa", 0xffffe000, 0, SROM13_RXGAINS, 0x0080}, - {"rxgains5gelnagaina", 0xffffe000, 0, SROM13_RXGAINS, 0x0700}, - {"rxgains5gtrisoa", 0xffffe000, 0, SROM13_RXGAINS, 0x7800}, - {"rxgains5gtrelnabypa", 0xffffe000, 0, SROM13_RXGAINS, 0x8000}, - {NULL, 0, 0, 0, 0} -}; - -typedef struct { - uint8 tag; /* Broadcom subtag name */ - uint32 revmask; /* Supported cis_sromrev bitmask. Some of the parameters in - * different tuples have the same name. Therefore, the MFGc tool - * needs to know which tuple to generate when seeing these - * parameters (given that we know sromrev from user input, like the - * nvram file). - */ - uint8 len; /* Length field of the tuple, note that it includes the - * subtag name (1 byte): 1 + tuple content length - */ - const char *params; /* Each param is in this form: length(1 byte ascii) + var name - * Note that the order here has to match the parsing - * order in parsecis() in src/shared/bcmsrom.c - */ -} cis_tuple_t; - -#define OTP_RAW (0xff - 1) /* Reserved tuple number for wrvar Raw input */ -/* quick hacks for supporting standard CIS tuples. */ -#define OTP_VERS_1 (0xff - 2) /* CISTPL_VERS_1 */ -#define OTP_MANFID (0xff - 3) /* CISTPL_MANFID */ -#define OTP_RAW1 (0xff - 4) /* Like RAW, but comes first */ - -/** this array is used by CIS creating/writing applications */ -static const cis_tuple_t cis_hnbuvars[] = { -/* tag revmask len params */ - {OTP_RAW1, 0xffffffff, 0, ""}, /* special case */ - {OTP_VERS_1, 0xffffffff, 0, "smanf sproductname"}, /* special case (non BRCM tuple) */ - {OTP_MANFID, 0xffffffff, 4, "2manfid 2prodid"}, /* special case (non BRCM tuple) */ - /* Unified OTP: tupple to embed USB manfid inside SDIO CIS */ - {HNBU_UMANFID, 0xffffffff, 8, "8usbmanfid"}, - {HNBU_SROMREV, 0xffffffff, 2, "1sromrev"}, - /* NOTE: subdevid is also written to boardtype. - * Need to write HNBU_BOARDTYPE to change it if it is different. - */ - {HNBU_CHIPID, 0xffffffff, 11, "2vendid 2devid 2chiprev 2subvendid 2subdevid"}, - {HNBU_BOARDREV, 0xffffffff, 3, "2boardrev"}, - {HNBU_PAPARMS, 0xffffffff, 10, "2pa0b0 2pa0b1 2pa0b2 1pa0itssit 1pa0maxpwr 1opo"}, - {HNBU_AA, 0xffffffff, 3, "1aa2g 1aa5g"}, - {HNBU_AA, 0xffffffff, 3, "1aa0 1aa1"}, /* backward compatibility */ - {HNBU_AG, 0xffffffff, 5, "1ag0 1ag1 1ag2 1ag3"}, - {HNBU_BOARDFLAGS, 0xffffffff, 21, "4boardflags 4boardflags2 4boardflags3 " - "4boardflags4 4boardflags5 "}, - {HNBU_CCODE, 0xffffffff, 4, "2ccode 1cctl"}, - {HNBU_CCKPO, 0xffffffff, 3, "2cckpo"}, - {HNBU_OFDMPO, 0xffffffff, 5, "4ofdmpo"}, - {HNBU_PAPARMS5G, 0xffffffff, 23, "2pa1b0 2pa1b1 2pa1b2 2pa1lob0 2pa1lob1 2pa1lob2 " - "2pa1hib0 2pa1hib1 2pa1hib2 1pa1itssit " - "1pa1maxpwr 1pa1lomaxpwr 1pa1himaxpwr"}, - {HNBU_RDLID, 0xffffffff, 3, "2rdlid"}, - {HNBU_RSSISMBXA2G, 0xffffffff, 3, "0rssismf2g 0rssismc2g " - "0rssisav2g 0bxa2g"}, /* special case */ - {HNBU_RSSISMBXA5G, 0xffffffff, 3, "0rssismf5g 0rssismc5g " - "0rssisav5g 0bxa5g"}, /* special case */ - {HNBU_XTALFREQ, 0xffffffff, 5, "4xtalfreq"}, - {HNBU_TRI2G, 0xffffffff, 2, "1tri2g"}, - {HNBU_TRI5G, 0xffffffff, 4, "1tri5gl 1tri5g 1tri5gh"}, - {HNBU_RXPO2G, 0xffffffff, 2, "1rxpo2g"}, - {HNBU_RXPO5G, 0xffffffff, 2, "1rxpo5g"}, - {HNBU_BOARDNUM, 0xffffffff, 3, "2boardnum"}, - {HNBU_MACADDR, 0xffffffff, 7, "6macaddr"}, /* special case */ - {HNBU_RDLSN, 0xffffffff, 3, "2rdlsn"}, - {HNBU_BOARDTYPE, 0xffffffff, 3, "2boardtype"}, - {HNBU_RDLRNDIS, 0xffffffff, 2, "1rdlndis"}, - {HNBU_CHAINSWITCH, 0xffffffff, 5, "1txchain 1rxchain 2antswitch"}, - {HNBU_REGREV, 0xffffffff, 3, "2regrev"}, - {HNBU_FEM, 0x000007fe, 5, "0antswctl2g 0triso2g 0pdetrange2g 0extpagain2g " - "0tssipos2g 0antswctl5g 0triso5g 0pdetrange5g 0extpagain5g 0tssipos5g"}, /* special case */ - {HNBU_PAPARMS_C0, 0x000007fe, 31, "1maxp2ga0 1itt2ga0 2pa2gw0a0 2pa2gw1a0 " - "2pa2gw2a0 1maxp5ga0 1itt5ga0 1maxp5gha0 1maxp5gla0 2pa5gw0a0 2pa5gw1a0 2pa5gw2a0 " - "2pa5glw0a0 2pa5glw1a0 2pa5glw2a0 2pa5ghw0a0 2pa5ghw1a0 2pa5ghw2a0"}, - {HNBU_PAPARMS_C1, 0x000007fe, 31, "1maxp2ga1 1itt2ga1 2pa2gw0a1 2pa2gw1a1 " - "2pa2gw2a1 1maxp5ga1 1itt5ga1 1maxp5gha1 1maxp5gla1 2pa5gw0a1 2pa5gw1a1 2pa5gw2a1 " - "2pa5glw0a1 2pa5glw1a1 2pa5glw2a1 2pa5ghw0a1 2pa5ghw1a1 2pa5ghw2a1"}, - {HNBU_PO_CCKOFDM, 0xffffffff, 19, "2cck2gpo 4ofdm2gpo 4ofdm5gpo 4ofdm5glpo " - "4ofdm5ghpo"}, - {HNBU_PO_MCS2G, 0xffffffff, 17, "2mcs2gpo0 2mcs2gpo1 2mcs2gpo2 2mcs2gpo3 " - "2mcs2gpo4 2mcs2gpo5 2mcs2gpo6 2mcs2gpo7"}, - {HNBU_PO_MCS5GM, 0xffffffff, 17, "2mcs5gpo0 2mcs5gpo1 2mcs5gpo2 2mcs5gpo3 " - "2mcs5gpo4 2mcs5gpo5 2mcs5gpo6 2mcs5gpo7"}, - {HNBU_PO_MCS5GLH, 0xffffffff, 33, "2mcs5glpo0 2mcs5glpo1 2mcs5glpo2 2mcs5glpo3 " - "2mcs5glpo4 2mcs5glpo5 2mcs5glpo6 2mcs5glpo7 " - "2mcs5ghpo0 2mcs5ghpo1 2mcs5ghpo2 2mcs5ghpo3 " - "2mcs5ghpo4 2mcs5ghpo5 2mcs5ghpo6 2mcs5ghpo7"}, - {HNBU_CCKFILTTYPE, 0xffffffff, 2, "1cckdigfilttype"}, - {HNBU_PO_CDD, 0xffffffff, 3, "2cddpo"}, - {HNBU_PO_STBC, 0xffffffff, 3, "2stbcpo"}, - {HNBU_PO_40M, 0xffffffff, 3, "2bw40po"}, - {HNBU_PO_40MDUP, 0xffffffff, 3, "2bwduppo"}, - {HNBU_RDLRWU, 0xffffffff, 2, "1rdlrwu"}, - {HNBU_WPS, 0xffffffff, 3, "1wpsgpio 1wpsled"}, - {HNBU_USBFS, 0xffffffff, 2, "1usbfs"}, - {HNBU_ELNA2G, 0xffffffff, 2, "1elna2g"}, - {HNBU_ELNA5G, 0xffffffff, 2, "1elna5g"}, - {HNBU_CUSTOM1, 0xffffffff, 5, "4customvar1"}, - {OTP_RAW, 0xffffffff, 0, ""}, /* special case */ - {HNBU_OFDMPO5G, 0xffffffff, 13, "4ofdm5gpo 4ofdm5glpo 4ofdm5ghpo"}, - {HNBU_USBEPNUM, 0xffffffff, 3, "2usbepnum"}, - {HNBU_CCKBW202GPO, 0xffffffff, 7, "2cckbw202gpo 2cckbw20ul2gpo 2cckbw20in802gpo"}, - {HNBU_LEGOFDMBW202GPO, 0xffffffff, 9, "4legofdmbw202gpo 4legofdmbw20ul2gpo"}, - {HNBU_LEGOFDMBW205GPO, 0xffffffff, 25, "4legofdmbw205glpo 4legofdmbw20ul5glpo " - "4legofdmbw205gmpo 4legofdmbw20ul5gmpo 4legofdmbw205ghpo 4legofdmbw20ul5ghpo"}, - {HNBU_MCS2GPO, 0xffffffff, 17, "4mcsbw202gpo 4mcsbw20ul2gpo 4mcsbw402gpo 4mcsbw802gpo"}, - {HNBU_MCS5GLPO, 0xffffffff, 13, "4mcsbw205glpo 4mcsbw20ul5glpo 4mcsbw405glpo"}, - {HNBU_MCS5GMPO, 0xffffffff, 13, "4mcsbw205gmpo 4mcsbw20ul5gmpo 4mcsbw405gmpo"}, - {HNBU_MCS5GHPO, 0xffffffff, 13, "4mcsbw205ghpo 4mcsbw20ul5ghpo 4mcsbw405ghpo"}, - {HNBU_MCS32PO, 0xffffffff, 3, "2mcs32po"}, - {HNBU_LEG40DUPPO, 0xffffffff, 3, "2legofdm40duppo"}, - {HNBU_TEMPTHRESH, 0xffffffff, 7, "1tempthresh 0temps_period 0temps_hysteresis " - "1tempoffset 1tempsense_slope 0tempcorrx 0tempsense_option " - "1phycal_tempdelta"}, /* special case */ - {HNBU_MUXENAB, 0xffffffff, 2, "1muxenab"}, - {HNBU_FEM_CFG, 0xfffff800, 5, "0femctrl 0papdcap2g 0tworangetssi2g 0pdgain2g " - "0epagain2g 0tssiposslope2g 0gainctrlsph 0papdcap5g 0tworangetssi5g 0pdgain5g 0epagain5g " - "0tssiposslope5g"}, /* special case */ - {HNBU_ACPA_C0, 0x00001800, 39, "2subband5gver 2maxp2ga0 2*3pa2ga0 " - "1*4maxp5ga0 2*12pa5ga0"}, - {HNBU_ACPA_C1, 0x00001800, 37, "2maxp2ga1 2*3pa2ga1 1*4maxp5ga1 2*12pa5ga1"}, - {HNBU_ACPA_C2, 0x00001800, 37, "2maxp2ga2 2*3pa2ga2 1*4maxp5ga2 2*12pa5ga2"}, - {HNBU_MEAS_PWR, 0xfffff800, 5, "1measpower 1measpower1 1measpower2 2rawtempsense"}, - {HNBU_PDOFF, 0xfffff800, 13, "2pdoffset40ma0 2pdoffset40ma1 2pdoffset40ma2 " - "2pdoffset80ma0 2pdoffset80ma1 2pdoffset80ma2"}, - {HNBU_ACPPR_2GPO, 0xfffff800, 13, "2dot11agofdmhrbw202gpo 2ofdmlrbw202gpo " - "2sb20in40dot11agofdm2gpo 2sb20in80dot11agofdm2gpo 2sb20in40ofdmlrbw202gpo " - "2sb20in80ofdmlrbw202gpo"}, - {HNBU_ACPPR_5GPO, 0xfffff800, 59, "4mcsbw805glpo 4mcsbw1605glpo 4mcsbw805gmpo " - "4mcsbw1605gmpo 4mcsbw805ghpo 4mcsbw1605ghpo 2mcslr5glpo 2mcslr5gmpo 2mcslr5ghpo " - "4mcsbw80p805glpo 4mcsbw80p805gmpo 4mcsbw80p805ghpo 4mcsbw80p805gx1po 2mcslr5gx1po " - "2mcslr5g80p80po 4mcsbw805gx1po 4mcsbw1605gx1po"}, - {HNBU_MCS5Gx1PO, 0xfffff800, 9, "4mcsbw205gx1po 4mcsbw405gx1po"}, - {HNBU_ACPPR_SBPO, 0xfffff800, 49, "2sb20in40hrpo 2sb20in80and160hr5glpo " - "2sb40and80hr5glpo 2sb20in80and160hr5gmpo 2sb40and80hr5gmpo 2sb20in80and160hr5ghpo " - "2sb40and80hr5ghpo 2sb20in40lrpo 2sb20in80and160lr5glpo 2sb40and80lr5glpo " - "2sb20in80and160lr5gmpo 2sb40and80lr5gmpo 2sb20in80and160lr5ghpo 2sb40and80lr5ghpo " - "4dot11agduphrpo 4dot11agduplrpo 2sb20in40and80hrpo 2sb20in40and80lrpo " - "2sb20in80and160hr5gx1po 2sb20in80and160lr5gx1po 2sb40and80hr5gx1po 2sb40and80lr5gx1po " - }, - {HNBU_ACPPR_SB8080_PO, 0xfffff800, 23, "2sb2040and80in80p80hr5glpo " - "2sb2040and80in80p80lr5glpo 2sb2040and80in80p80hr5gmpo " - "2sb2040and80in80p80lr5gmpo 2sb2040and80in80p80hr5ghpo 2sb2040and80in80p80lr5ghpo " - "2sb2040and80in80p80hr5gx1po 2sb2040and80in80p80lr5gx1po 2sb20in80p80hr5gpo " - "2sb20in80p80lr5gpo 2dot11agduppo"}, - {HNBU_NOISELVL, 0xfffff800, 16, "1noiselvl2ga0 1noiselvl2ga1 1noiselvl2ga2 " - "1*4noiselvl5ga0 1*4noiselvl5ga1 1*4noiselvl5ga2"}, - {HNBU_RXGAIN_ERR, 0xfffff800, 16, "1rxgainerr2ga0 1rxgainerr2ga1 1rxgainerr2ga2 " - "1*4rxgainerr5ga0 1*4rxgainerr5ga1 1*4rxgainerr5ga2"}, - {HNBU_AGBGA, 0xfffff800, 7, "1agbg0 1agbg1 1agbg2 1aga0 1aga1 1aga2"}, - {HNBU_USBDESC_COMPOSITE, 0xffffffff, 3, "2usbdesc_composite"}, - {HNBU_UUID, 0xffffffff, 17, "16uuid"}, - {HNBU_WOWLGPIO, 0xffffffff, 2, "1wowl_gpio"}, - {HNBU_ACRXGAINS_C0, 0xfffff800, 5, "0rxgains5gtrelnabypa0 0rxgains5gtrisoa0 " - "0rxgains5gelnagaina0 0rxgains2gtrelnabypa0 0rxgains2gtrisoa0 0rxgains2gelnagaina0 " - "0rxgains5ghtrelnabypa0 0rxgains5ghtrisoa0 0rxgains5ghelnagaina0 0rxgains5gmtrelnabypa0 " - "0rxgains5gmtrisoa0 0rxgains5gmelnagaina0"}, /* special case */ - {HNBU_ACRXGAINS_C1, 0xfffff800, 5, "0rxgains5gtrelnabypa1 0rxgains5gtrisoa1 " - "0rxgains5gelnagaina1 0rxgains2gtrelnabypa1 0rxgains2gtrisoa1 0rxgains2gelnagaina1 " - "0rxgains5ghtrelnabypa1 0rxgains5ghtrisoa1 0rxgains5ghelnagaina1 0rxgains5gmtrelnabypa1 " - "0rxgains5gmtrisoa1 0rxgains5gmelnagaina1"}, /* special case */ - {HNBU_ACRXGAINS_C2, 0xfffff800, 5, "0rxgains5gtrelnabypa2 0rxgains5gtrisoa2 " - "0rxgains5gelnagaina2 0rxgains2gtrelnabypa2 0rxgains2gtrisoa2 0rxgains2gelnagaina2 " - "0rxgains5ghtrelnabypa2 0rxgains5ghtrisoa2 0rxgains5ghelnagaina2 0rxgains5gmtrelnabypa2 " - "0rxgains5gmtrisoa2 0rxgains5gmelnagaina2"}, /* special case */ - {HNBU_TXDUTY, 0xfffff800, 9, "2tx_duty_cycle_ofdm_40_5g " - "2tx_duty_cycle_thresh_40_5g 2tx_duty_cycle_ofdm_80_5g 2tx_duty_cycle_thresh_80_5g"}, - {HNBU_PDOFF_2G, 0xfffff800, 3, "0pdoffset2g40ma0 0pdoffset2g40ma1 " - "0pdoffset2g40ma2 0pdoffset2g40mvalid"}, - {HNBU_ACPA_CCK_C0, 0xfffff800, 7, "2*3pa2gccka0"}, - {HNBU_ACPA_CCK_C1, 0xfffff800, 7, "2*3pa2gccka1"}, - {HNBU_ACPA_40, 0xfffff800, 25, "2*12pa5gbw40a0"}, - {HNBU_ACPA_80, 0xfffff800, 25, "2*12pa5gbw80a0"}, - {HNBU_ACPA_4080, 0xfffff800, 49, "2*12pa5gbw4080a0 2*12pa5gbw4080a1"}, - {HNBU_ACPA_4X4C0, 0xffffe000, 23, "1maxp2ga0 2*4pa2ga0 2*4pa2g40a0 " - "1maxp5gb0a0 1maxp5gb1a0 1maxp5gb2a0 1maxp5gb3a0 1maxp5gb4a0"}, - {HNBU_ACPA_4X4C1, 0xffffe000, 23, "1maxp2ga1 2*4pa2ga1 2*4pa2g40a1 " - "1maxp5gb0a1 1maxp5gb1a1 1maxp5gb2a1 1maxp5gb3a1 1maxp5gb4a1"}, - {HNBU_ACPA_4X4C2, 0xffffe000, 23, "1maxp2ga2 2*4pa2ga2 2*4pa2g40a2 " - "1maxp5gb0a2 1maxp5gb1a2 1maxp5gb2a2 1maxp5gb3a2 1maxp5gb4a2"}, - {HNBU_ACPA_4X4C3, 0xffffe000, 23, "1maxp2ga3 2*4pa2ga3 2*4pa2g40a3 " - "1maxp5gb0a3 1maxp5gb1a3 1maxp5gb2a3 1maxp5gb3a3 1maxp5gb4a3"}, - {HNBU_ACPA_BW20_4X4C0, 0xffffe000, 41, "2*20pa5ga0"}, - {HNBU_ACPA_BW40_4X4C0, 0xffffe000, 41, "2*20pa5g40a0"}, - {HNBU_ACPA_BW80_4X4C0, 0xffffe000, 41, "2*20pa5g80a0"}, - {HNBU_ACPA_BW20_4X4C1, 0xffffe000, 41, "2*20pa5ga1"}, - {HNBU_ACPA_BW40_4X4C1, 0xffffe000, 41, "2*20pa5g40a1"}, - {HNBU_ACPA_BW80_4X4C1, 0xffffe000, 41, "2*20pa5g80a1"}, - {HNBU_ACPA_BW20_4X4C2, 0xffffe000, 41, "2*20pa5ga2"}, - {HNBU_ACPA_BW40_4X4C2, 0xffffe000, 41, "2*20pa5g40a2"}, - {HNBU_ACPA_BW80_4X4C2, 0xffffe000, 41, "2*20pa5g80a2"}, - {HNBU_ACPA_BW20_4X4C3, 0xffffe000, 41, "2*20pa5ga3"}, - {HNBU_ACPA_BW40_4X4C3, 0xffffe000, 41, "2*20pa5g40a3"}, - {HNBU_ACPA_BW80_4X4C3, 0xffffe000, 41, "2*20pa5g80a3"}, - {HNBU_SUBBAND5GVER, 0xfffff800, 3, "2subband5gver"}, - {HNBU_PAPARAMBWVER, 0xfffff800, 2, "1paparambwver"}, - {HNBU_TXBFRPCALS, 0xfffff800, 11, - "2rpcal2g 2rpcal5gb0 2rpcal5gb1 2rpcal5gb2 2rpcal5gb3"}, /* txbf rpcalvars */ - {HNBU_GPIO_PULL_DOWN, 0xffffffff, 5, "4gpdn"}, - {HNBU_MACADDR2, 0xffffffff, 7, "6macaddr2"}, /* special case */ - {HNBU_RSSI_DELTA_2G_B0, 0xffffffff, 17, "1*16rssi_delta_2gb0"}, - {HNBU_RSSI_DELTA_2G_B1, 0xffffffff, 17, "1*16rssi_delta_2gb1"}, - {HNBU_RSSI_DELTA_2G_B2, 0xffffffff, 17, "1*16rssi_delta_2gb2"}, - {HNBU_RSSI_DELTA_2G_B3, 0xffffffff, 17, "1*16rssi_delta_2gb3"}, - {HNBU_RSSI_DELTA_2G_B4, 0xffffffff, 17, "1*16rssi_delta_2gb4"}, - {HNBU_RSSI_CAL_FREQ_GRP_2G, 0xffffffff, 8, "1*7rssi_cal_freq_grp"}, - {HNBU_RSSI_DELTA_5GL, 0xffffffff, 25, "1*24rssi_delta_5gl"}, - {HNBU_RSSI_DELTA_5GML, 0xffffffff, 25, "1*24rssi_delta_5gml"}, - {HNBU_RSSI_DELTA_5GMU, 0xffffffff, 25, "1*24rssi_delta_5gmu"}, - {HNBU_RSSI_DELTA_5GH, 0xffffffff, 25, "1*24rssi_delta_5gh"}, - {HNBU_ACPA_6G_C0, 0x00000800, 45, "2subband6gver 1*6maxp6ga0 2*18pa6ga0 "}, - {HNBU_ACPA_6G_C1, 0x00000800, 43, "1*6maxp6ga1 2*18pa6ga1 "}, - {HNBU_ACPA_6G_C2, 0x00000800, 43, "1*6maxp6ga2 2*18pa6ga2 "}, - {0xFF, 0xffffffff, 0, ""} -}; - -#endif /* _bcmsrom_tbl_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmstdlib_s.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmstdlib_s.h old mode 100755 new mode 100644 index dad66b8167ad..c70493353a9c --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmstdlib_s.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmstdlib_s.h @@ -1,7 +1,7 @@ /* * Broadcom Secure Standard Library. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -25,8 +25,8 @@ #define _bcmstdlib_s_h_ #ifndef BWL_NO_INTERNAL_STDLIB_S_SUPPORT -#if !defined(__STDC_WANT_SECURE_LIB__) && \ - !(defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) +#if !defined(__STDC_WANT_SECURE_LIB__) && !(defined(__STDC_LIB_EXT1__) && \ + defined(__STDC_WANT_LIB_EXT1__)) extern int memmove_s(void *dest, size_t destsz, const void *src, size_t n); extern int memcpy_s(void *dest, size_t destsz, const void *src, size_t n); extern int memset_s(void *dest, size_t destsz, int c, size_t n); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmtcp.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmtcp.h old mode 100755 new mode 100644 index 3e580a274bec..804026bd14f6 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmtcp.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmtcp.h @@ -1,7 +1,7 @@ /* * Fundamental constants relating to TCP Protocol * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmtlv.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmtlv.h old mode 100755 new mode 100644 index 78710b6a8348..7a9fbab17ae4 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmtlv.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmtlv.h @@ -1,7 +1,7 @@ /* * TLV and XTLV support * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -36,7 +36,7 @@ extern "C" { typedef struct bcm_tlv { uint8 id; uint8 len; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; } bcm_tlv_t; /* size of tlv including data */ @@ -62,7 +62,7 @@ typedef struct bcm_tlv_ext { uint8 id; uint8 len; uint8 ext; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; } bcm_tlv_ext_t; /* get next tlv_ext - no length checks */ @@ -132,6 +132,10 @@ bcm_tlv_t *bcm_parse_tlvs_dot11(const void *buf, uint buflen, uint key, bool id /* same as parse_tlvs, but stops when found id > key */ const bcm_tlv_t *bcm_parse_ordered_tlvs(const void *buf, uint buflen, uint key); +/* sub-buffer ptr/len contained inside the elt starting at the given body_offset */ +void bcm_tlv_sub_buffer(const bcm_tlv_t *elt, uint body_offset, + const uint8 **buffer, uint8 *buflen); + /* find a tlv with DOT11_MNG_PROPR_ID as id, and the given oui and type */ bcm_tlv_t *bcm_find_vendor_ie(const void *tlvs, uint tlvs_len, const char *voui, uint8 *type, uint type_len); @@ -163,7 +167,7 @@ uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, uint dst_maxlen); typedef struct bcm_xtlv { uint16 id; uint16 len; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; } bcm_xtlv_t; /* xtlv options */ @@ -343,10 +347,13 @@ void bcm_xtlv_unpack_xtlv(const bcm_xtlv_t *xtlv, uint16 *type, uint16 *len, /* length value pairs */ struct bcm_xlv { uint16 len; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; }; typedef struct bcm_xlv bcm_xlv_t; +#define XLV_HDR_LEN (OFFSETOF(bcm_xlv_t, data)) +#define XLV_TOTAL_LEN(xlv) (BCM_XTLV_LEN(xlv) + XLV_HDR_LEN) + struct bcm_xlvp { uint16 len; uint8 *data; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmudp.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmudp.h old mode 100755 new mode 100644 index 5a5113d6e59f..8e4405afa85d --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmudp.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmudp.h @@ -1,7 +1,7 @@ /* * Fundamental constants relating to UDP Protocol * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmutils.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmutils.h old mode 100755 new mode 100644 index 2971d8b38d63..558345d57f09 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmutils.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmutils.h @@ -1,7 +1,7 @@ /* * Misc useful os-independent macros and functions. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -25,11 +25,7 @@ #define _bcmutils_h_ #include - -/* For now, protect the bcmerror.h */ -#ifdef BCMUTILS_ERR_CODES #include -#endif #ifdef __cplusplus extern "C" { @@ -143,19 +139,35 @@ extern int bcm_ether_atoe(const char *p, struct ether_addr *ea); } \ } +#define SPINWAIT_TRAP(exp, us) SPINWAIT(exp, us) + #elif defined(PHY_REG_TRACE_FRAMEWORK) #include #define SPINWAIT(exp, us) { \ uint countdown = (us) + (SPINWAIT_POLL_PERIOD - 1U); \ - phy_utils_log_spinwait_start(); \ + phy_utils_log_spinwait_start_api(); \ while (((exp) != 0) && (uint)(countdown >= SPINWAIT_POLL_PERIOD)) { \ OSL_DELAY(SPINWAIT_POLL_PERIOD); \ countdown -= SPINWAIT_POLL_PERIOD; \ } \ - phy_utils_log_spinwait_end(us, countdown); \ + phy_utils_log_spinwait_end_api(us, countdown); \ +} + +#define SPINWAIT_TRAP(exp, us) { \ + uint countdown = (us) + (SPINWAIT_POLL_PERIOD - 1U); \ + phy_utils_log_spinwait_start_api(); \ + while (((exp) != 0) && (uint)(countdown >= SPINWAIT_POLL_PERIOD)) { \ + OSL_DELAY(SPINWAIT_POLL_PERIOD); \ + countdown -= SPINWAIT_POLL_PERIOD; \ + } \ + phy_utils_log_spinwait_end_api(us, countdown); \ + if ((exp)) { \ + OSL_SYS_HALT(); \ + } \ } #else + #define SPINWAIT(exp, us) { \ uint countdown = (us) + (SPINWAIT_POLL_PERIOD - 1U); \ while (((exp) != 0) && (uint)(countdown >= SPINWAIT_POLL_PERIOD)) { \ @@ -163,6 +175,25 @@ extern int bcm_ether_atoe(const char *p, struct ether_addr *ea); countdown -= SPINWAIT_POLL_PERIOD; \ } \ } + +/* No TRAP in bootloader */ +#if defined(BCM_BOOTLOADER) +#define SPINWAIT_TRAP(x, y) SPINWAIT(x, y) + +#else /* !BCM_BOOTLOADER */ + +#define SPINWAIT_TRAP(exp, us) { \ + uint countdown = (us) + (SPINWAIT_POLL_PERIOD - 1U); \ + while (((exp) != 0) && (uint)(countdown >= SPINWAIT_POLL_PERIOD)) { \ + OSL_DELAY(SPINWAIT_POLL_PERIOD); \ + countdown -= SPINWAIT_POLL_PERIOD; \ + } \ + if ((exp)) { \ + OSL_SYS_HALT(); \ + } \ +} +#endif /* BCM_BOOTLOADER */ + #endif /* BCMFUZZ */ /* forward definition of ether_addr structure used by some function prototypes */ @@ -208,10 +239,14 @@ extern uint pkttotlen_no_sfhtoe_hdr(osl_t *osh, void *p, uint toe_hdr_len); #define PKTPRIO_DSCP 0x800u /* DSCP prio found */ /* DSCP type definitions (RFC4594) */ +/* DF: Standard (RFC2474) */ +#define DSCP_DF 0x00u /* AF1x: High-Throughput Data (RFC2597) */ #define DSCP_AF11 0x0Au #define DSCP_AF12 0x0Cu #define DSCP_AF13 0x0Eu +/* CS1: Low-Priority Data (RFC3662) */ +#define DSCP_CS1 0x08u /* AF2x: Low-Latency Data (RFC2597) */ #define DSCP_AF21 0x12u #define DSCP_AF22 0x14u @@ -224,6 +259,14 @@ extern uint pkttotlen_no_sfhtoe_hdr(osl_t *osh, void *p, uint toe_hdr_len); #define DSCP_AF33 0x1Eu /* CS3: Broadcast Video (RFC2474) */ #define DSCP_CS3 0x18u +/* AF4x: Multimedia Conferencing (RFC2597) */ +#define DSCP_AF41 0x22u +#define DSCP_AF42 0x24u +#define DSCP_AF43 0x26u +/* CS4: Real-Time Interactive (RFC2474) */ +#define DSCP_CS4 0x20u +/* CS5: Signaling (RFC2474) */ +#define DSCP_CS5 0x28u /* VA: VOCIE-ADMIT (RFC5865) */ #define DSCP_VA 0x2Cu /* EF: Telephony (RFC3246) */ @@ -276,17 +319,13 @@ extern bool _nvram_reclaim_enb; #define NVRAM_RECLAIM_CHECK(name) #endif /* BCM_RECLAIM */ -#ifdef WL_FWSIGN -#define getvar(vars, name) (NULL) -#define getintvar(vars, name) (0) -#define getintvararray(vars, name, index) (0) -#define getintvararraysize(vars, name) (0) -#else /* WL_FWSIGN */ -extern char *getvar(char *vars, const char *name); -extern int getintvar(char *vars, const char *name); -extern int getintvararray(char *vars, const char *name, int index); -extern int getintvararraysize(char *vars, const char *name); -#endif /* WL_FWSIGN */ +#ifndef ATE_BUILD +const +#endif /* ATE_BUILD */ +char *getvar(char *vars, const char *name); +int getintvar(char *vars, const char *name); +int getintvararray(char *vars, const char *name, int index); +int getintvararraysize(char *vars, const char *name); /* Read an array of values from a possibly slice-specific nvram string */ extern int get_uint8_vararray_slicespecific(osl_t *osh, char *vars, char *vars_table_accessor, @@ -297,7 +336,9 @@ extern int get_int16_vararray_slicespecific(osl_t *osh, char *vars, char *vars_t extern uint get_slicespecific_var_name(osl_t *osh, char *vars_table_accessor, const char *name, char **name_out); +#if defined(BCMNVRAMR) || defined(BCMNVRAMW) extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); +#endif /* BCMNVRAMR || BCMNVRAMW */ #ifdef BCMDBG extern void prpkt(const char *msg, osl_t *osh, void *p0); #endif /* BCMDBG */ @@ -444,188 +485,46 @@ uint16 bcmhex2bin(const uint8* hex, uint hex_len, uint8 *buf, uint buf_len); #define DBG_BUS_INC(s, cnt) #endif /* DBG_BUS */ -/* BCMUTILS_ERR_CODES is defined to use the error codes from bcmerror.h - * otherwise use from this file. +#ifndef STRIP_PARENS +/* DROP Parenthesis from the ARGS + * if ARG=(a,b,c) including parens, then ARG is evaluated as 1 argument not 3 + * MACRO(ARG)==MACRO((a,b,c)), but MACRO(STRIP_PARENS(ARG))==MACRO(a,b,c) */ -#ifndef BCMUTILS_ERR_CODES - -/* - * error codes could be added but the defined ones shouldn't be changed/deleted - * these error codes are exposed to the user code - * when ever a new error code is added to this list - * please update errorstring table with the related error string and - * update osl files with os specific errorcode map -*/ - -#define BCME_OK 0 /* Success */ -#define BCME_ERROR -1 /* Error generic */ -#define BCME_BADARG -2 /* Bad Argument */ -#define BCME_BADOPTION -3 /* Bad option */ -#define BCME_NOTUP -4 /* Not up */ -#define BCME_NOTDOWN -5 /* Not down */ -#define BCME_NOTAP -6 /* Not AP */ -#define BCME_NOTSTA -7 /* Not STA */ -#define BCME_BADKEYIDX -8 /* BAD Key Index */ -#define BCME_RADIOOFF -9 /* Radio Off */ -#define BCME_NOTBANDLOCKED -10 /* Not band locked */ -#define BCME_NOCLK -11 /* No Clock */ -#define BCME_BADRATESET -12 /* BAD Rate valueset */ -#define BCME_BADBAND -13 /* BAD Band */ -#define BCME_BUFTOOSHORT -14 /* Buffer too short */ -#define BCME_BUFTOOLONG -15 /* Buffer too long */ -#define BCME_BUSY -16 /* Busy */ -#define BCME_NOTASSOCIATED -17 /* Not Associated */ -#define BCME_BADSSIDLEN -18 /* Bad SSID len */ -#define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */ -#define BCME_BADCHAN -20 /* Bad Channel */ -#define BCME_BADADDR -21 /* Bad Address */ -#define BCME_NORESOURCE -22 /* Not Enough Resources */ -#define BCME_UNSUPPORTED -23 /* Unsupported */ -#define BCME_BADLEN -24 /* Bad length */ -#define BCME_NOTREADY -25 /* Not Ready */ -#define BCME_EPERM -26 /* Not Permitted */ -#define BCME_NOMEM -27 /* No Memory */ -#define BCME_ASSOCIATED -28 /* Associated */ -#define BCME_RANGE -29 /* Not In Range */ -#define BCME_NOTFOUND -30 /* Not Found */ -#define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */ -#define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */ -#define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */ -#define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */ -#define BCME_SDIO_ERROR -35 /* SDIO Bus Error */ -#define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */ -#define BCME_VERSION -37 /* Incorrect version */ -#define BCME_TXFAIL -38 /* TX failure */ -#define BCME_RXFAIL -39 /* RX failure */ -#define BCME_NODEVICE -40 /* Device not present */ -#define BCME_NMODE_DISABLED -41 /* NMODE disabled */ -#define BCME_MSCH_DUP_REG -42 /* Duplicate slot registration */ -#define BCME_SCANREJECT -43 /* reject scan request */ -#define BCME_USAGE_ERROR -44 /* WLCMD usage error */ -#define BCME_IOCTL_ERROR -45 /* WLCMD ioctl error */ -#define BCME_SERIAL_PORT_ERR -46 /* RWL serial port error */ -#define BCME_DISABLED -47 /* Disabled in this build */ -#define BCME_DECERR -48 /* Decrypt error */ -#define BCME_ENCERR -49 /* Encrypt error */ -#define BCME_MICERR -50 /* Integrity/MIC error */ -#define BCME_REPLAY -51 /* Replay */ -#define BCME_IE_NOTFOUND -52 /* IE not found */ -#define BCME_DATA_NOTFOUND -53 /* Complete data not found in buffer */ -#define BCME_NOT_GC -54 /* expecting a group client */ -#define BCME_PRS_REQ_FAILED -55 /* GC presence req failed to sent */ -#define BCME_NO_P2P_SE -56 /* Could not find P2P-Subelement */ -#define BCME_NOA_PND -57 /* NoA pending, CB shuld be NULL */ -#define BCME_FRAG_Q_FAILED -58 /* queueing 80211 frag failedi */ -#define BCME_GET_AF_FAILED -59 /* Get p2p AF pkt failed */ -#define BCME_MSCH_NOTREADY -60 /* scheduler not ready */ -#define BCME_IOV_LAST_CMD -61 /* last batched iov sub-command */ -#define BCME_MINIPMU_CAL_FAIL -62 /* MiniPMU cal failed */ -#define BCME_RCAL_FAIL -63 /* Rcal failed */ -#define BCME_LPF_RCCAL_FAIL -64 /* RCCAL failed */ -#define BCME_DACBUF_RCCAL_FAIL -65 /* RCCAL failed */ -#define BCME_VCOCAL_FAIL -66 /* VCOCAL failed */ -#define BCME_BANDLOCKED -67 /* interface is restricted to a band */ -#define BCME_BAD_IE_DATA -68 /* Recieved ie with invalid/bad data */ -#define BCME_REG_FAILED -69 /* Generic registration failed */ -#define BCME_NOCHAN -70 /* Registration with 0 chans in list */ -#define BCME_PKTTOSS -71 /* Pkt tossed */ -#define BCME_DNGL_DEVRESET -72 /* dongle re-attach during DEVRESET */ -#define BCME_ROAM -73 /* Roam related failures */ -#define BCME_NO_SIG_FILE -74 /* Signature file is missing */ - -#define BCME_LAST BCME_NO_SIG_FILE - -#define BCME_NOTENABLED BCME_DISABLED - -/* This error code is *internal* to the driver, and is not propogated to users. It should - * only be used by IOCTL patch handlers as an indication that it did not handle the IOCTL. - * (Since the error code is internal, an entry in 'BCMERRSTRINGTABLE' is not required, - * nor does it need to be part of any OSL driver-to-OS error code mapping). - */ -#define BCME_IOCTL_PATCH_UNSUPPORTED -9999 -#if (BCME_LAST <= BCME_IOCTL_PATCH_UNSUPPORTED) - #error "BCME_LAST <= BCME_IOCTL_PATCH_UNSUPPORTED" +#undef __STRIP_PARENS +#undef _STRIP_PARENS +#define __STRIP_PARENS(...) __VA_ARGS__ +#define _STRIP_PARENS(X) X +#define STRIP_PARENS(X) _STRIP_PARENS(__STRIP_PARENS X) #endif -/* These are collection of BCME Error strings */ -#define BCMERRSTRINGTABLE { \ - "OK", \ - "Undefined error", \ - "Bad Argument", \ - "Bad Option", \ - "Not up", \ - "Not down", \ - "Not AP", \ - "Not STA", \ - "Bad Key Index", \ - "Radio Off", \ - "Not band locked", \ - "No clock", \ - "Bad Rate valueset", \ - "Bad Band", \ - "Buffer too short", \ - "Buffer too long", \ - "Busy", \ - "Not Associated", \ - "Bad SSID len", \ - "Out of Range Channel", \ - "Bad Channel", \ - "Bad Address", \ - "Not Enough Resources", \ - "Unsupported", \ - "Bad length", \ - "Not Ready", \ - "Not Permitted", \ - "No Memory", \ - "Associated", \ - "Not In Range", \ - "Not Found", \ - "WME Not Enabled", \ - "TSPEC Not Found", \ - "ACM Not Supported", \ - "Not WME Association", \ - "SDIO Bus Error", \ - "Dongle Not Accessible", \ - "Incorrect version", \ - "TX Failure", \ - "RX Failure", \ - "Device Not Present", \ - "NMODE Disabled", \ - "Host Offload in device", \ - "Scan Rejected", \ - "WLCMD usage error", \ - "WLCMD ioctl error", \ - "RWL serial port error", \ - "Disabled", \ - "Decrypt error", \ - "Encrypt error", \ - "MIC error", \ - "Replay", \ - "IE not found", \ - "Data not found", \ - "NOT GC", \ - "PRS REQ FAILED", \ - "NO P2P SubElement", \ - "NOA Pending", \ - "FRAG Q FAILED", \ - "GET ActionFrame failed", \ - "scheduler not ready", \ - "Last IOV batched sub-cmd", \ - "Mini PMU Cal failed", \ - "R-cal failed", \ - "LPF RC Cal failed", \ - "DAC buf RC Cal failed", \ - "VCO Cal failed", \ - "band locked", \ - "Recieved ie with invalid data", \ - "registration failed", \ - "Registration with zero channels", \ - "pkt toss", \ - "Dongle Devreset", \ - "Critical roam in progress", \ - "Signature file is missing", \ -} -#endif /* BCMUTILS_ERR_CODES */ +/* CONCAT 2 args to make single string that can be evaluated as MACRO */ +#ifndef CONCATENATE +#undef __CONCATENATE +#define __CONCATENATE(a, b) a ## b +#define CONCATENATE(a, b) __CONCATENATE(a, b) +#endif + +/* CONCAT as synonym to CONCATENATE */ +#ifndef CONCAT +#define CONCAT(a, b) CONCATENATE(a, b) +#endif + +#ifdef COUNT_ARGS +/* returns the count of argument passed to COUNT_ARGS + * order or arguments to COUNT_ARGS_ is dummy, __VA_ARGS__, 30..0 + * a30 is returned if NARGS is 30 and a0 if NARGS is 0 + * e.g. for case when + * 30 Args are prsent, we will have dummy, a30-a1(args passed), and a0 == 30 + * 5 Args present, dummy, a30-a26(args passed) a25-a1==30-6, and a0 == 5 + */ +#undef __COUNT_ARGS +#undef COUNT_ARGS +#endif /* COUNT_ARGS */ + +#define __COUNT_ARGS(dummy, a30, a29, a28, a27, a26, a25, a24, a23, a22, a21, a20, a19, a18, \ + a17, a16, a15, a14, a13, a12, a11, a10, a9, a8, a7, a6, a5, a4, a3, a2, a1, a0, ...) a0 +#define COUNT_ARGS(...) __COUNT_ARGS(dummy, ##__VA_ARGS__, 30, 29, 28, 27, 26, 25, 24, 23, 22, \ + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) #ifndef ABS #define ABS(a) (((a) < 0) ? -(a) : (a)) @@ -692,9 +591,13 @@ uint16 bcmhex2bin(const uint8* hex, uint hex_len, uint8 *buf, uint buf_len); #endif /* CONTAINEROF */ /* substruct size up to and including a member of the struct */ +/* use 0x10 offset to avoid undefined behavior error due to NULL access */ +#define SIZETHROUGHOF(type, member) (OFFSETOF(type, member) + sizeof(((type *)0x10)->member)) + +/* The STRUCT_SIZE_THROUGH will be obsolete. Please use SIZETHROUGHOF macro above */ #ifndef STRUCT_SIZE_THROUGH #define STRUCT_SIZE_THROUGH(sptr, fname) \ - (((uint8*)&((sptr)->fname) - (uint8*)(sptr)) + sizeof((sptr)->fname)) + (((uintptr)&((sptr)->fname) - (uintptr)(sptr)) + sizeof((sptr)->fname)) #endif /* Extracting the size of element in a structure */ @@ -729,10 +632,10 @@ extern void clrbit(void *array, uint bit); extern bool isset(const void *array, uint bit); extern bool isclr(const void *array, uint bit); #else -#define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY)) -#define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) -#define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) -#define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) +#define setbit(a, i) ((*((uint8 *)a + ((i) / NBBY))) |= 1 << ((i) % NBBY)) +#define clrbit(a, i) ((*((uint8 *)a + ((i) / NBBY))) &= ~(1 << ((i) % NBBY))) +#define isset(a, i) ((*((const uint8 *)a + ((i) / NBBY))) & (1 << ((i) % NBBY))) +#define isclr(a, i) (((*((const uint8 *)a + ((i) / NBBY))) & (1 << ((i) % NBBY))) == 0) #endif #endif /* setbit */ @@ -755,15 +658,15 @@ extern void clr_bitrange_u32(void *array, uint start, uint end, uint maxbit); extern int bcm_find_fsb(uint32 num); -#define isbitset(a, i) (((a) & (1 << (i))) != 0) +#define isbitset(a, i) (((a) & (1u << (i))) != 0) #if defined DONGLEBUILD #define NBITS(type) (sizeof(type) * 8) #else #define NBITS(type) ((uint32)(sizeof(type) * 8)) #endif /* DONGLEBUILD */ -#define NBITVAL(nbits) (1 << (nbits)) -#define MAXBITVAL(nbits) ((1 << (nbits)) - 1) +#define NBITVAL(nbits) (1u << (nbits)) +#define MAXBITVAL(nbits) ((1u << (nbits)) - 1u) #define NBITMASK(nbits) MAXBITVAL(nbits) #define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8) @@ -885,19 +788,25 @@ DECLARE_MAP_API(8, 2, 3, 3u, 0x00FFu) /* setbit8() and getbit8() */ * If you want to use this macro to the logic, * USE MACF instead */ -#if !defined(SIMPLE_MAC_PRINT) -#define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x" -#define MAC2STRDBG(ea) ((const uint8*)(ea))[0], \ +#define MACDBG_FULL "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC2STRDBG_FULL(ea) ((const uint8*)(ea))[0], \ ((const uint8*)(ea))[1], \ ((const uint8*)(ea))[2], \ ((const uint8*)(ea))[3], \ ((const uint8*)(ea))[4], \ ((const uint8*)(ea))[5] -#else -#define MACDBG "%02x:xx:xx:xx:x%x:%02x" -#define MAC2STRDBG(ea) ((const uint8*)(ea))[0], \ + +#define MACDBG_SIMPLE "%02x:xx:xx:xx:x%x:%02x" +#define MAC2STRDBG_SIMPLE(ea) ((const uint8*)(ea))[0], \ (((const uint8*)(ea))[4] & 0xf), \ ((const uint8*)(ea))[5] + +#if !defined(SIMPLE_MAC_PRINT) +#define MACDBG MACDBG_FULL +#define MAC2STRDBG MAC2STRDBG_FULL +#else +#define MACDBG MACDBG_SIMPLE +#define MAC2STRDBG MAC2STRDBG_SIMPLE #endif /* SIMPLE_MAC_PRINT */ #define MACOUIDBG "%02x:%x:%02x" @@ -983,6 +892,8 @@ extern char *bcm_brev_str(uint32 brev, char *buf); extern void printbig(char *buf); extern void prhex(const char *msg, const uchar *buf, uint len); extern void prhexstr(const char *prefix, const uint8 *buf, uint len, bool newline); +/* print the buffer in hex string format with the most significant byte first */ +extern void prhexstr_msb(const char *prefix, const uint8 *buf, uint len, bool newline); /* bcmerror */ extern const char *bcmerrorstr(int bcmerror); @@ -1000,7 +911,9 @@ extern int wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie); typedef uint32 mbool; #define mboolset(mb, bit) ((mb) |= (bit)) /* set one bool */ #define mboolclr(mb, bit) ((mb) &= ~(bit)) /* clear one bool */ +#define mbooltgl(mb, bit) ((mb) ^= (bit)) /* toggle one bool */ #define mboolisset(mb, bit) (((mb) & (bit)) != 0) /* TRUE if one bool is set */ +#define mboolisclr(mb, bit) (((mb) & (bit)) == 0) /* TRUE if one bool is clear */ #define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) /* generic datastruct to help dump routines */ @@ -1015,6 +928,10 @@ extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); #define bcm_breset(b) do {bcm_binit(b, (b)->origbuf, (b)->origsize);} while (0) extern void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, uint len); +/* print the buffer in hex string format with the most significant byte first */ +extern void bcm_bprhex_msb(struct bcmstrbuf *b, const char *msg, bool newline, + const uint8 *buf, uint len); +extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount); extern int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes); @@ -1024,8 +941,7 @@ typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset); extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str, char *buf, uint32 bufsize); extern uint bcm_bitcount(const uint8 *bitmap, uint bytelength); - -extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); +uint bcm_count_bits(const uint8 *buf, uint buf_len, uint from_bit, uint to_bit, bool val_1); /* power conversion */ extern uint16 bcm_qdbm_to_mw(uint8 qdbm); @@ -1078,7 +994,7 @@ bool replace_nvram_variable(char *varbuf, unsigned int buflen, const char *varia unsigned int *datalen); /* trace any object allocation / free, with / without features (flags) set to the object */ -#if (defined(DONGLEBUILD) && defined(BCMDBG_MEM) && (!defined(BCM_OBJECT_TRACE))) +#if (defined(DONGLEBUILD) && defined(BCMDBG_MEM) && !defined(BCM_OBJECT_TRACE)) #define BCM_OBJECT_TRACE #endif /* (defined(DONGLEBUILD) && defined(BCMDBG_MEM) && (!defined(BCM_OBJECT_TRACE))) */ @@ -1095,7 +1011,8 @@ bool replace_nvram_variable(char *varbuf, unsigned int buflen, const char *varia #define BCM_OBJECT_FEATURE_2 (1 << 2) /* object feature: clear flag bits field set with this flag */ #define BCM_OBJECT_FEATURE_CLEAR (1 << 31) -#if defined(BCM_OBJECT_TRACE) && !defined(BINCMP) +#if defined(BCM_OBJECT_TRACE) +#if !defined(BINCMP) #define bcm_pkt_validate_chk(obj, func) do { \ void * pkttag; \ bcm_object_trace_chk(obj, 0, 0, \ @@ -1105,6 +1022,18 @@ bool replace_nvram_variable(char *varbuf, unsigned int buflen, const char *varia func, __LINE__); \ } \ } while (0) +#else /* BINCMP */ +/* Suppress line numbers in binary-comparison builds. Otherwise identical to above. */ +#define bcm_pkt_validate_chk(obj, func) do { \ + void * pkttag; \ + bcm_object_trace_chk(obj, 0, 0, \ + func, 1); \ + if ((pkttag = PKTTAG(obj))) { \ + bcm_object_trace_chk(obj, 1, DHD_PKTTAG_SN(pkttag), \ + func, 1); \ + } \ +} while (0) +#endif /* !BINCMP */ extern void bcm_object_trace_opr(void *obj, uint32 opt, const char *caller, int line); extern void bcm_object_trace_upd(void *obj, void *obj_new); extern void bcm_object_trace_chk(void *obj, uint32 chksn, uint32 sn, @@ -1122,7 +1051,7 @@ extern void bcm_object_trace_deinit(void); #define bcm_object_feature_get(a, b, c) #define bcm_object_trace_init() #define bcm_object_trace_deinit() -#endif /* BCM_OBJECT_TRACE && !BINCMP */ +#endif /* BCM_OBJECT_TRACE */ /* Public domain bit twiddling hacks/utilities: Sean Eron Anderson */ @@ -1145,14 +1074,14 @@ bcm_cntsetbits(const uint32 u32arg) return ((uint32)_CSBTBL[p[0]] + _CSBTBL[p[1]] + _CSBTBL[p[2]] + _CSBTBL[p[3]]); } -static INLINE int /* C equivalent count of leading 0's in a u32 */ +static INLINE uint /* C equivalent count of leading 0's in a u32 */ C_bcm_count_leading_zeros(uint32 u32arg) { - int shifts = 0; + uint shifts = 0; while (u32arg) { shifts++; u32arg >>= 1; } - return (32 - shifts); + return (32u - shifts); } typedef struct bcm_rand_metadata { @@ -1178,11 +1107,11 @@ typedef struct bcm_rand_metadata { #endif /* __ARM_ARCH_7R__ */ #endif /* __arm__ */ -static INLINE int +static INLINE uint bcm_count_leading_zeros(uint32 u32arg) { #if defined(__USE_ASM_CLZ__) - int zeros; + uint zeros; __asm__ volatile("clz %0, %1 \n" : "=r" (zeros) : "r" (u32arg)); return zeros; #else /* C equivalent */ @@ -1195,9 +1124,9 @@ bcm_count_leading_zeros(uint32 u32arg) * */ #if defined(__GNUC__) -#define CLZ(x) __builtin_clzl(x) +#define CLZ(x) ((uint)__builtin_clzl(x)) #elif defined(__arm__) -#define CLZ(x) __clz(x) +#define CLZ(x) ((uint)__clz(x)) #else #define CLZ(x) bcm_count_leading_zeros(x) #endif /* __GNUC__ */ @@ -1337,52 +1266,53 @@ typedef struct dll { struct dll * prev_p; } dll_t; -static INLINE void +static INLINE_ALWAYS void dll_init(dll_t *node_p) { node_p->next_p = node_p; node_p->prev_p = node_p; } + /* dll macros returing a pointer to dll_t */ -static INLINE dll_t * +static INLINE_ALWAYS dll_t * BCMPOSTTRAPFN(dll_head_p)(dll_t *list_p) { return list_p->next_p; } -static INLINE dll_t * +static INLINE_ALWAYS dll_t * BCMPOSTTRAPFN(dll_tail_p)(dll_t *list_p) { return (list_p)->prev_p; } -static INLINE dll_t * +static INLINE_ALWAYS dll_t * BCMPOSTTRAPFN(dll_next_p)(dll_t *node_p) { return (node_p)->next_p; } -static INLINE dll_t * +static INLINE_ALWAYS dll_t * BCMPOSTTRAPFN(dll_prev_p)(dll_t *node_p) { return (node_p)->prev_p; } -static INLINE bool +static INLINE_ALWAYS bool BCMPOSTTRAPFN(dll_empty)(dll_t *list_p) { return ((list_p)->next_p == (list_p)); } -static INLINE bool +static INLINE_ALWAYS bool BCMPOSTTRAPFN(dll_end)(dll_t *list_p, dll_t * node_p) { return (list_p == node_p); } /* inserts the node new_p "after" the node at_p */ -static INLINE void +static INLINE_ALWAYS void BCMPOSTTRAPFN(dll_insert)(dll_t *new_p, dll_t * at_p) { new_p->next_p = at_p->next_p; @@ -1391,20 +1321,20 @@ BCMPOSTTRAPFN(dll_insert)(dll_t *new_p, dll_t * at_p) (new_p->next_p)->prev_p = new_p; } -static INLINE void +static INLINE_ALWAYS void BCMPOSTTRAPFN(dll_append)(dll_t *list_p, dll_t *node_p) { dll_insert(node_p, dll_tail_p(list_p)); } -static INLINE void +static INLINE_ALWAYS void BCMPOSTTRAPFN(dll_prepend)(dll_t *list_p, dll_t *node_p) { dll_insert(node_p, list_p); } /* deletes a node from any list that it "may" be in, if at all. */ -static INLINE void +static INLINE_ALWAYS void BCMPOSTTRAPFN(dll_delete)(dll_t *node_p) { node_p->prev_p->next_p = node_p->next_p; @@ -1419,7 +1349,7 @@ typedef struct dll_pool { uint16 free_count; uint16 elems_max; uint16 elem_size; - dll_t elements[1]; + dll_t elements[BCM_FLEX_ARRAY]; } dll_pool_t; dll_pool_t * dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size); @@ -1508,8 +1438,8 @@ void counter_printlog(counter_tbl_t *ctr_tbl); #define CALL_SITE ((void*) 0) #endif #ifdef SHOW_LOGTRACE -#define TRACE_LOG_BUF_MAX_SIZE 1700 -#define RTT_LOG_BUF_MAX_SIZE 1700 +#define TRACE_LOG_BUF_MAX_SIZE 1900 +#define RTT_LOG_BUF_MAX_SIZE 1900 #define BUF_NOT_AVAILABLE 0 #define NEXT_BUF_NOT_AVAIL 1 #define NEXT_BUF_AVAIL 2 @@ -1533,11 +1463,11 @@ typedef struct { } dump_dongle_in_t; typedef struct { - uint32 address; /**< e.g. backplane address of register */ - uint32 id; /**< id, e.g. core id */ - uint32 rev; /**< rev, e.g. core rev */ - uint32 n_bytes; /**< nbytes in array val[] */ - uint32 val[1]; /**< out: values that were read out of registers or memory */ + uint32 address; /**< e.g. backplane address of register */ + uint32 id; /**< id, e.g. core id */ + uint32 rev; /**< rev, e.g. core rev */ + uint32 n_bytes; /**< nbytes in array val[] */ + uint32 val[BCM_FLEX_ARRAY]; /**< out: values that were read out of registers or memory */ } dump_dongle_out_t; extern uint32 sqrt_int(uint32 value); @@ -1583,13 +1513,6 @@ extern void (*const print_btrace_fn)(int depth); #define PRINT_BACKTRACE_INT(depth, pc, lr, sp) \ if (print_btrace_int_fn) print_btrace_int_fn(depth, pc, lr, sp) -/* FW Signing - only in bootloader builds, never in dongle FW builds */ -#ifdef WL_FWSIGN - #define FWSIGN_ENAB() (1) -#else - #define FWSIGN_ENAB() (0) -#endif /* WL_FWSIGN */ - /* Utilities for reading SROM/SFlash vars */ typedef struct varbuf { @@ -1614,9 +1537,9 @@ static INLINE uint32 count_trailing_zeros(uint32 val) { #ifdef BCMDRIVER - uint32 c = (uint32)CLZ(val & ((uint32)(-(int)val))); + uint32 c = CLZ(val & ((uint32)(-(int)val))); #else - uint32 c = (uint32)C_bcm_count_leading_zeros(val & ((uint32)(-(int)val))); + uint32 c = C_bcm_count_leading_zeros(val & ((uint32)(-(int)val))); #endif /* BCMDRIVER */ return val ? 31u - c : c; } @@ -1636,4 +1559,55 @@ count_trailing_zeros(uint32 val) (sizeof((list)->last_var_len_field[0]) * (size_t)(num_elems))) int buf_shift_right(uint8 *buf, uint16 len, uint8 bits); + +#ifdef DONGLEBUILD +extern int print_string(const char *str); + +#define _NUM_ARGS_FN(fn, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _A, _B, _C, _D, _E, _F, N, ...) fn ## N +#define NUM_ARGS_FN(fn, ...) \ + _NUM_ARGS_FN(fn, __VA_ARGS__, x, x, x, x, x, x, x, x, x, x, x, x, x, x, 0) + +#define FIRST_ARG(a1, ...) a1 +#define NEXT_ARGS(a1, ...) __VA_ARGS__ + +#define printf_ps_0(str, ...) print_string(str) +#define printf_ps_x(str, ...) printf(str, __VA_ARGS__) + +#define posttrap_printf(...) \ + do { \ + static const char BCMPOST_TRAP_RODATA(p_str)[] = FIRST_ARG(__VA_ARGS__); \ + NUM_ARGS_FN(printf_ps_, __VA_ARGS__)(p_str, NEXT_ARGS(__VA_ARGS__)); \ + BCM_REFERENCE(p_str); \ + } while (0) + +#else +#define posttrap_printf(...) printf(__VA_ARGS__) +#endif /* DONGLEBUILD */ + +typedef enum dbg_seq_log_id_e { + DBG_SEQ_LOG_ID_RX = 0u, + DBG_SEQ_LOG_ID_TX = 1u, + DBG_SEQ_LOG_ID_MAX +} dbg_seq_log_id_t; + +#ifdef DBG_SEQ_LOG +extern void dbg_seq_log_seq(dbg_seq_log_id_t id, uint16 seq, void *arg1, void *arg2); +#else +#define dbg_seq_log_seq(id, seq, arg1, arg2) +#endif /* DBG_SEQ_LOG */ + +/* common time computation function shared between FW and other SW entities */ +int bcmutils_event_log_compute_current_time(void *ets_msg, uint64 log_record_time, + uint64 *current_time); + +#ifdef DBG_PKTID_POOLPKT_PROCESS +extern uint16 bcm_mwbmap_total_pktid(struct bcm_mwbmap * mwbmap_hdl); +#endif /* DBG_PKTID_POOLPKT_PROCESS */ + +extern uint64 div_1K(uint64 q); +extern uint64 div_1M(uint64 q); + +#define NS_PER_MS (1000000u) + #endif /* _bcmutils_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_channels.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_channels.h old mode 100755 new mode 100644 index d3744de83b74..ccbe138e93c7 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_channels.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_channels.h @@ -3,7 +3,7 @@ * This header file housing the define and function prototype use by * both the wl driver, tools & Apps. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -44,6 +44,8 @@ typedef uint16 chanspec_subband_t; #define CH_MAX_2G_CHANNEL 14u /* Max channel in 2G band */ #define CH_MIN_2G_40M_CHANNEL 3u /* Min 40MHz center channel in 2G band */ #define CH_MAX_2G_40M_CHANNEL 11u /* Max 40MHz center channel in 2G band */ +#define CH_MIN_5G_CHANNEL 34u /* Min channel in 5G band */ +#define CH_MAX_5G_CHANNEL 177u /* Max channel in 5G band */ #define CH_MIN_6G_CHANNEL 1u /* Min 20MHz channel in 6G band */ #define CH_MAX_6G_CHANNEL 253u /* Max 20MHz channel in 6G band */ @@ -219,7 +221,13 @@ typedef struct { #ifndef CHSPEC_IS160 #define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) #endif +#ifndef CHSPEC_IS8080 +#ifdef WFC_NON_CONT_CHAN +#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) +#else #define CHSPEC_IS8080(chspec) (FALSE) +#endif +#endif /* CHSPEC_IS8080 */ #ifndef CHSPEC_IS320 #ifdef WL11BE #define CHSPEC_IS320(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_320) @@ -234,6 +242,13 @@ typedef struct { #define CHSPEC_IS240(chspec) (FALSE) #endif #endif /* CHSPEC_IS240 */ +#ifndef CHSPEC_IS160160 +#ifdef WFC_NON_CONT_CHAN +#define CHSPEC_IS160160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160160) +#else +#define CHSPEC_IS160160(chspec) (FALSE) +#endif +#endif /* CHSPEC_IS160160 */ /* pass a center channel and get channel offset from it by 10MHz */ #define CH_OFF_10MHZ_MULTIPLES(channel, offset) \ @@ -245,45 +260,6 @@ typedef struct { uint wf_chspec_first_20_sb(chanspec_t chspec); -#if defined(WL_BW160MHZ) -/* pass a 160MHz center channel to get 20MHz subband channel numbers */ -#define LLL_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, -7) -#define LLU_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, -5) -#define LUL_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, -3) -#define LUU_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, -1) -#define ULL_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, 1) -#define ULU_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, 3) -#define UUL_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, 5) -#define UUU_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, 7) - -/* get lowest 20MHz sideband of a given chspec - * (works with 20, 40, 80, 160) - */ -#define CH_FIRST_20_SB(chspec) ((uint8) (\ - CHSPEC_IS160(chspec) ? LLL_20_SB_160(CHSPEC_CHANNEL(chspec)) : (\ - CHSPEC_IS80(chspec) ? LL_20_SB(CHSPEC_CHANNEL(chspec)) : (\ - CHSPEC_IS40(chspec) ? LOWER_20_SB(CHSPEC_CHANNEL(chspec)) : \ - CHSPEC_CHANNEL(chspec))))) - -/* get upper most 20MHz sideband of a given chspec - * (works with 20, 40, 80, 160) - */ -#define CH_LAST_20_SB(chspec) ((uint8) (\ - CHSPEC_IS160(chspec) ? UUU_20_SB_160(CHSPEC_CHANNEL(chspec)) : (\ - CHSPEC_IS80(chspec) ? UU_20_SB(CHSPEC_CHANNEL(chspec)) : (\ - CHSPEC_IS40(chspec) ? UPPER_20_SB(CHSPEC_CHANNEL(chspec)) : \ - CHSPEC_CHANNEL(chspec))))) - -/* call this with chspec and a valid 20MHz sideband of this channel to get the next 20MHz sideband - * (works with 20, 40, 80, 160) - * resolves to 0 if called with upper most channel - */ -#define CH_NEXT_20_SB(chspec, channel) ((uint8) (\ - ((uint8) ((channel) + CH_20MHZ_APART) > CH_LAST_20_SB(chspec) ? 0 : \ - ((channel) + CH_20MHZ_APART)))) - -#else /* WL_BW160MHZ */ - #define LLL_20_SB_160(channel) 0 #define LLU_20_SB_160(channel) 0 #define LUL_20_SB_160(channel) 0 @@ -293,6 +269,10 @@ uint wf_chspec_first_20_sb(chanspec_t chspec); #define UUL_20_SB_160(channel) 0 #define UUU_20_SB_160(channel) 0 +#define LOWER_80_SB(chspec) 0 + +#define UPPER_80_SB(chspec) 0 + /* get lowest 20MHz sideband of a given chspec * (works with 20, 40, 80) */ @@ -316,8 +296,6 @@ uint wf_chspec_first_20_sb(chanspec_t chspec); ((uint8) ((channel) + CH_20MHZ_APART) > CH_LAST_20_SB(chspec) ? 0 : \ ((channel) + CH_20MHZ_APART)))) -#endif /* WL_BW160MHZ */ - /* Iterator for 20MHz side bands of a chanspec: (chanspec_t chspec, uint8 channel) * 'chspec' chanspec_t of interest (used in loop, better to pass a resolved value than a macro) * 'channel' must be a variable (not an expression). @@ -356,7 +334,7 @@ uint wf_chspec_first_20_sb(chanspec_t chspec); ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) -#ifdef WL_BAND6G +#ifdef WL_6G_BAND #define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS2G(chspec) ? WLC_BAND_2G : CHSPEC_IS5G(chspec) ? \ WLC_BAND_5G : WLC_BAND_6G) #else @@ -394,11 +372,32 @@ extern bool wf_chspec_coexist(chanspec_t chspec1, chanspec_t chspec2); #define CHSPEC_IS_BW_160_WIDE(chspec) (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_160 ||\ CHSPEC_BW(chspec) == WL_CHANSPEC_BW_8080) -/* BW inequality comparisons, GE (>=), GT (>) */ +/* BW inequality comparisons, LE (<=), GE (>=), LT (<), GT (>), comparisons can be made +* as simple numeric comparisons, with the exception that 160 is the same BW as 80+80, +* but have different numeric values; (WL_CHANSPEC_BW_160 < WL_CHANSPEC_BW_8080). +* +* The LT/LE/GT/GE macros check first checks whether both chspec bandwidth and bw are 160 wide. +* If both chspec bandwidth and bw is not 160 wide, then the comparison is made. +*/ +#define CHSPEC_BW_GE(chspec, bw) \ + ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ + ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ + (CHSPEC_BW(chspec) >= (bw))) -#define CHSPEC_BW_GE(chspec, bw) (CHSPEC_BW(chspec) >= (bw)) +#define CHSPEC_BW_LE(chspec, bw) \ + ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ + ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ + (CHSPEC_BW(chspec) <= (bw))) -#define CHSPEC_BW_GT(chspec, bw) (CHSPEC_BW(chspec) > (bw)) +#define CHSPEC_BW_GT(chspec, bw) \ + (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ + ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ + (CHSPEC_BW(chspec) > (bw))) + +#define CHSPEC_BW_LT(chspec, bw) \ + (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ + ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ + (CHSPEC_BW(chspec) < (bw))) /* Legacy Chanspec defines * These are the defines for the previous format of the chanspec_t @@ -604,7 +603,7 @@ chanspec_t wf_create_320MHz_chspec(uint primary_channel, uint center_channel, * the center channel numbers for each frequency segment, and the band. */ chanspec_t wf_create_8080MHz_chspec(uint primary_channel, uint chan0, uint chan1, - chanspec_band_t band); + chanspec_band_t band); /** * Returns the chanspec for an 160+160MHz channel given the primary 20MHz channel number, @@ -616,7 +615,8 @@ chanspec_t wf_create_160160MHz_chspec(uint primary_channel, uint chan0, uint cha * Returns the chanspec given the primary 20MHz channel number, * the center channel number, channel width, and the band. * - * The channel width must be 20, 40, 80, or 160 MHz. + * The channel width must be 20, 40, 80, or 160 MHz. 80+80 MHz chanspec creation + * is not handled by this function, use wf_create_8080MHz_chspec() instead. */ chanspec_t wf_create_chspec(uint primary_channel, uint center_channel, chanspec_bw_t bw, chanspec_band_t band); @@ -632,11 +632,20 @@ chanspec_t wf_create_chspec_from_primary(uint primary_channel, chanspec_bw_t bw, * Returns the chanspec given the index of primary 20MHz channel within whole * channel, the center channel number, channel width, and the band. * - * The channel width must be 20, 40, 80, or 160 MHz. + * The channel width must be 20, 40, 80, or 160 MHz. 80+80 MHz chanspec creation + * is not handled by this function, use wf_create_8080MHz_chspec_prim_idx() instead. */ chanspec_t wf_create_chspec_sb(uint sb, uint center_channel, chanspec_bw_t bw, chanspec_band_t band); +/** + * Returns the chanspec for an 80+80MHz channel given the index of primary 20MHz + * channel within whole channel pair (0-3 if within chan0, 4-7 if within chan1), + * the center channel numbers for each frequency segment, and the band. + */ +chanspec_t wf_create_8080MHz_chspec_sb(uint sb, uint chan0, uint chan1, + chanspec_band_t band); + /** * Returns the chanspec for an 160+160MHz channel given the index of primary 20MHz * channel within whole channel pair (0-3 if within chan0, 4-7 if within chan1), @@ -666,6 +675,11 @@ chanspec_t wf_chspec_primary20_chspec(chanspec_t chspec); */ chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec); +/** + * Return the chanspec band for a given frequency. + */ +chanspec_band_t wf_mhz2chanspec_band(uint freq); + /** * Return the channel number for a given frequency and base frequency */ @@ -885,4 +899,8 @@ uint8 wf_chspec_320_id2cch(chanspec_t chanspec); uint8 wf_chspec_240_id2cch(chanspec_t chanspec); +#ifndef WL_BW320MHZ +#define wf_chspec_center_channel(chspec) CHSPEC_CHANNEL(chspec) +#endif /* !WL_BW320MHZ */ + #endif /* _bcmwifi_channels_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_monitor.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_monitor.h deleted file mode 100755 index 41f1f94b17a2..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_monitor.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Monitor Mode routines. - * This header file housing the define and function use by DHD - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ -#ifndef _BCMWIFI_MONITOR_H_ -#define _BCMWIFI_MONITOR_H_ - -#include - -typedef struct monitor_info monitor_info_t; - -typedef struct monitor_pkt_ts { - union { - uint32 ts_low; /* time stamp low 32 bits */ - uint32 reserved; /* If timestamp not used */ - }; - union { - uint32 ts_high; /* time stamp high 28 bits */ - union { - uint32 ts_high_ext :28; /* time stamp high 28 bits */ - uint32 clk_id_ext :3; /* clock ID source */ - uint32 phase :1; /* Phase bit */ - uint32 marker_ext; - }; - }; -} monitor_pkt_ts_t; - -typedef struct monitor_pkt_info { - uint32 marker; - /* timestamp */ - monitor_pkt_ts_t ts; -} monitor_pkt_info_t; - -typedef struct monitor_pkt_rssi { - int8 dBm; /* number of full dBms */ - /* sub-dbm resolution */ - int8 decidBm; /* sub dBms : value after the decimal point */ -} monitor_pkt_rssi_t; - -/* structure to add specific information to rxsts structure - * otherwise non available to all modules like core RSSI and qdbm resolution -*/ - -typedef struct monitor_pkt_rxsts { - wl_rxsts_t *rxsts; - uint8 corenum; /* number of cores/antennas */ - monitor_pkt_rssi_t rxpwr[4]; -} monitor_pkt_rxsts_t; - -#define HE_EXTRACT_FROM_PLCP(plcp, ppdu_type, field) \ - (getbits(plcp, D11_PHY_HDR_LEN, \ - HE_ ## ppdu_type ## _PPDU_ ## field ## _IDX, \ - HE_ ## ppdu_type ## _PPDU_ ## field ## _FSZ)) - -#define HE_PACK_RTAP_FROM_PLCP(plcp, ppdu_type, field) \ - (HE_EXTRACT_FROM_PLCP(plcp, ppdu_type, field) << \ - HE_RADIOTAP_ ## field ## _SHIFT) - -#define HE_PACK_RTAP_GI_LTF_FROM_PLCP(plcp, ppdu_type, field, member) \ - ((he_plcp2ltf_gi[HE_EXTRACT_FROM_PLCP(plcp, ppdu_type, field)].member) << \ - HE_RADIOTAP_ ## field ## _SHIFT) - -#define HE_PACK_RTAP_FROM_VAL(val, field) \ - ((val) << HE_RADIOTAP_ ## field ## _SHIFT) - -#define HE_PACK_RTAP_FROM_PRXS(rxh, corerev, corerev_minor, field) \ - (HE_PACK_RTAP_FROM_VAL(D11PPDU_ ## field(rxh, corerev, corerev_minor), field)) - -/* channel bandwidth */ -#define WLC_20_MHZ 20 /**< 20Mhz channel bandwidth */ -#define WLC_40_MHZ 40 /**< 40Mhz channel bandwidth */ -#define WLC_80_MHZ 80 /**< 80Mhz channel bandwidth */ -#define WLC_160_MHZ 160 /**< 160Mhz channel bandwidth */ -#define WLC_240_MHZ 240 /**< 240Mhz channel bandwidth */ -#define WLC_320_MHZ 320 /**< 320Mhz channel bandwidth */ - -extern uint16 bcmwifi_monitor_create(monitor_info_t**); -extern void bcmwifi_set_corerev_major(monitor_info_t* info, int8 corerev); -extern void bcmwifi_set_corerev_minor(monitor_info_t* info, int8 corerev); -extern void bcmwifi_monitor_delete(monitor_info_t* info); -extern uint16 bcmwifi_monitor(monitor_info_t* info, - monitor_pkt_info_t* pkt_info, void *pdata, uint16 len, void* pout, - uint16* offset, uint16 pad_req, void *wrxh_in, void *wrxh_last); -extern uint16 wl_rxsts_to_rtap(monitor_pkt_rxsts_t* pkt_rxsts, void *pdata, - uint16 len, void* pout, uint16 pad_req); - -#endif /* _BCMWIFI_MONITOR_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_radiotap.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_radiotap.h old mode 100755 new mode 100644 index 77fc0e72e490..d90b5af7ec77 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_radiotap.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_radiotap.h @@ -3,7 +3,7 @@ * This header file housing the define and function prototype use by * both the wl driver, tools & Apps. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_rates.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_rates.h old mode 100755 new mode 100644 index 9be50eb57748..36b6e72b8a47 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_rates.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_rates.h @@ -1,7 +1,7 @@ /* * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_rspec.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_rspec.h old mode 100755 new mode 100644 index a90f3a38cb0d..7ab1f093ca48 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_rspec.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwifi_rspec.h @@ -1,7 +1,7 @@ /* * Common OS-independent driver header for rate management. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwpa.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwpa.h deleted file mode 100755 index 45d4a9fe4423..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmwpa.h +++ /dev/null @@ -1,634 +0,0 @@ -/* - * bcmwpa.h - interface definitions of shared WPA-related functions - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ - -#ifndef _BCMWPA_H_ -#define _BCMWPA_H_ -#ifdef BCM_EXTERNAL_APP -typedef int osl_t; -#endif -#include -#if defined(BCMSUP_PSK) || defined(BCMSUPPL) || \ - defined(MFP) || defined(BCMAUTH_PSK) || defined(WLFBT) || \ - defined(WL_OKC) || defined(GTKOE) || defined(WL_FILS) -#include -#endif -#include <802.11.h> -#ifdef WLP2P -#include -#endif -#include -#include -#include -#include -#ifdef WL_OCV -#include -#endif /* WL_OCV */ - -/* Field sizes for WPA key hierarchy */ -#define WPA_TEMP_TX_KEY_LEN 8u -#define WPA_TEMP_RX_KEY_LEN 8u - -#define PMK_LEN 32u -#define TKIP_PTK_LEN 64u -#define TKIP_TK_LEN 32u -#define AES_PTK_LEN 48u -#define AES_TK_LEN 16u -#define AES_GCM_PTK_LEN 48u -#define AES_GCM_TK_LEN 16u -#define AES_GCM256_PTK_LEN 64u -#define AES_GCM256_TK_LEN 32u - -/* limits for pre-shared key lengths */ -#define WPA_MIN_PSK_LEN 8u -#define WPA_MAX_PSK_LEN 64u - -#define WPA_KEY_DATA_LEN_256 256u /* allocation size of 256 for temp data pointer. */ -#define WPA_KEY_DATA_LEN_128 128u /* allocation size of 128 for temp data pointer. */ - -/* Minimum length of WPA2 GTK encapsulation in EAPOL */ -#define EAPOL_WPA2_GTK_ENCAP_MIN_LEN (EAPOL_WPA2_ENCAP_DATA_HDR_LEN - \ - TLV_HDR_LEN + EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN) - -/* Minimum length of WPA2 IGTK encapsulation in EAPOL */ -#define EAPOL_WPA2_IGTK_ENCAP_MIN_LEN (EAPOL_WPA2_ENCAP_DATA_HDR_LEN - \ - TLV_HDR_LEN + EAPOL_WPA2_KEY_IGTK_ENCAP_HDR_LEN) - -/* Minimum length of BIGTK encapsulation in EAPOL */ -#define EAPOL_WPA2_BIGTK_ENCAP_MIN_LEN (EAPOL_WPA2_ENCAP_DATA_HDR_LEN - \ - TLV_HDR_LEN + EAPOL_WPA2_KEY_BIGTK_ENCAP_HDR_LEN) - -#ifdef WL_OCV -/* Size of the OCI element */ -#define WPA_OCV_OCI_IE_SIZE \ - (bcm_ocv_get_oci_len() + BCM_TLV_EXT_HDR_SIZE) - -/* Size of the OCI KDE */ -#define WPA_OCV_OCI_KDE_SIZE \ - (bcm_ocv_get_oci_len() + EAPOL_WPA2_ENCAP_DATA_HDR_LEN) - -/* Size of the OCI subelement */ -#define WPA_OCV_OCI_SUBELEM_SIZE \ - (bcm_ocv_get_oci_len() + TLV_HDR_LEN) - -/* Minimum length of WPA2 OCI encapsulation in EAPOL */ -#define EAPOL_WPA2_OCI_ENCAP_MIN_LEN \ - (WPA_OCV_OCI_KDE_SIZE - TLV_HDR_LEN) -#endif /* WL_OCV */ - -#ifdef WLFIPS -#define WLC_SW_KEYS(wlc, bsscfg) ((((wlc)->wsec_swkeys) || \ - ((bsscfg)->wsec & (WSEC_SWFLAG | FIPS_ENABLED)))) -#else -#define WLC_SW_KEYS(wlc, bsscfg) ((((wlc)->wsec_swkeys) || \ - ((bsscfg)->wsec & WSEC_SWFLAG))) -#endif /* WLFIPS */ - -/* This doesn't really belong here, but neither does WSEC_CKIP* */ -/* per-packet encryption exemption policy */ -/* no exemption...follow whatever standard rules apply */ -#define WSEC_EXEMPT_NO 0 -/* send unencrypted */ -#define WSEC_EXEMPT_ALWAYS 1 -/* send unencrypted if no pairwise key */ -#define WSEC_EXEMPT_NO_PAIRWISE 2 - -#define WPA_CIPHER_UNSPECIFIED 0xff -#define WPA_P_CIPHERS_UNSPECIFIED 0x80000000 - -#ifdef RSN_IE_INFO_STRUCT_RELOCATED -#define WPA_AKMS_UNSPECIFIED 0x80000000 -#else -#define WPA_AKMS_UNSPECIFIED 0 -#endif - -#ifdef BCMWAPI_WAI -#define IS_WAPI_AUTH(auth) ((auth) == WAPI_AUTH_UNSPECIFIED || \ - (auth) == WAPI_AUTH_PSK) -#define INCLUDES_WAPI_AUTH(auth) \ - ((auth) & (WAPI_AUTH_UNSPECIFIED | \ - WAPI_AUTH_PSK)) -#endif /* BCMWAPI_WAI */ - -#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \ - (akm) == RSN_AKM_UNSPECIFIED || \ - (akm) == RSN_AKM_PSK) - -#define IS_WPA2_AKM(akm) ((akm) == RSN_AKM_UNSPECIFIED || \ - (akm) == RSN_AKM_PSK || \ - (akm) == RSN_AKM_FILS_SHA256 || \ - (akm) == RSN_AKM_FILS_SHA384) - -/* this doesn't mean much. A WPA (not RSN) akm type would match this */ -#define RSN_AKM_MASK (\ - BCM_BIT(RSN_AKM_UNSPECIFIED) | \ - BCM_BIT(RSN_AKM_PSK) | \ - BCM_BIT(RSN_AKM_SAE_PSK) | \ - BCM_BIT(RSN_AKM_FILS_SHA256) | \ - BCM_BIT(RSN_AKM_FILS_SHA384) | \ - BCM_BIT(RSN_AKM_OWE) | \ - BCM_BIT(RSN_AKM_SUITEB_SHA256_1X) | \ - BCM_BIT(RSN_AKM_SUITEB_SHA384_1X)) - -/* verify less than 32 before shifting bits */ -#define VALID_AKM_BIT(akm) ((akm) < 32u ? BCM_BIT((akm)) : 0u) - -#define IS_RSN_AKM(akm) (VALID_AKM_BIT((akm)) & RSN_AKM_MASK) - -#define FBT_AKM_MASK (BCM_BIT(RSN_AKM_FBT_1X) | \ - BCM_BIT(RSN_AKM_FBT_PSK) | \ - BCM_BIT(RSN_AKM_SAE_FBT) | \ - BCM_BIT(RSN_AKM_FBT_SHA256_FILS) | \ - BCM_BIT(RSN_AKM_FBT_SHA384_FILS) | \ - BCM_BIT(RSN_AKM_FBT_SHA384_1X) | \ - BCM_BIT(RSN_AKM_FBT_SHA384_PSK)) - -#define IS_FBT_AKM(akm) (VALID_AKM_BIT((akm)) & FBT_AKM_MASK) - -#define FILS_AKM_MASK (\ - BCM_BIT(RSN_AKM_FILS_SHA256) | \ - BCM_BIT(RSN_AKM_FILS_SHA384)) - -#define IS_FILS_AKM(akm) (VALID_AKM_BIT((akm)) & FILS_AKM_MASK) - -#define MFP_AKM_MASK (\ - BCM_BIT(RSN_AKM_SHA256_1X) | \ - BCM_BIT(RSN_AKM_SHA256_PSK)) - -#define IS_MFP_AKM(akm) (MFP_AKM_MASK & VALID_AKM_BIT((akm))) - -#ifdef BCMWAPI_WAI -#define IS_WAPI_AKM(akm) ((akm) == RSN_AKM_NONE || \ - (akm) == RSN_AKM_UNSPECIFIED || \ - (akm) == RSN_AKM_PSK) -#endif /* BCMWAPI_WAI */ - -#define IS_TDLS_AKM(akm) ((akm) == RSN_AKM_TPK) - -/* Broadcom(OUI) authenticated key managment suite */ -#define BRCM_AKM_NONE 0 -#define BRCM_AKM_PSK 1u /* Proprietary PSK AKM */ - -#define IS_BRCM_AKM(akm) ((akm) == BRCM_AKM_PSK) - -#define ONE_X_AKM_MASK (BCM_BIT(RSN_AKM_FBT_1X) | \ - BCM_BIT(RSN_AKM_MFP_1X) | \ - BCM_BIT(RSN_AKM_SHA256_1X) | \ - BCM_BIT(RSN_AKM_SUITEB_SHA256_1X) | \ - BCM_BIT(RSN_AKM_SUITEB_SHA384_1X) | \ - BCM_BIT(RSN_AKM_FBT_SHA384_1X) | \ - BCM_BIT(RSN_AKM_UNSPECIFIED)) - -#define IS_1X_AKM(akm) (VALID_AKM_BIT((akm)) & ONE_X_AKM_MASK) - -#define SUITEB_AKM_MASK (BCM_BIT(RSN_AKM_SUITEB_SHA256_1X) | \ - BCM_BIT(RSN_AKM_SUITEB_SHA384_1X)) -#define IS_1X_SUITEB_AKM(akm) (VALID_AKM_BIT((akm)) & SUITEB_AKM_MASK) - -#define SAE_AKM_MASK (BCM_BIT(RSN_AKM_SAE_PSK) | BCM_BIT(RSN_AKM_SAE_FBT)) -#define IS_SAE_AKM(akm) (VALID_AKM_BIT((akm)) & SAE_AKM_MASK) - -#define SHA256_AKM_MASK (BCM_BIT(RSN_AKM_SHA256_1X) | \ - BCM_BIT(RSN_AKM_SHA256_PSK) | \ - BCM_BIT(RSN_AKM_SAE_PSK) | \ - BCM_BIT(RSN_AKM_SAE_FBT) | \ - BCM_BIT(RSN_AKM_SUITEB_SHA256_1X) | \ - BCM_BIT(RSN_AKM_FILS_SHA256) | \ - BCM_BIT(RSN_AKM_FBT_SHA256_FILS) | \ - BCM_BIT(RSN_AKM_OWE)) -#define IS_SHA256_AKM(akm) (VALID_AKM_BIT((akm)) & SHA256_AKM_MASK) - -#define SHA384_AKM_MASK (BCM_BIT(RSN_AKM_SUITEB_SHA384_1X) | \ - BCM_BIT(RSN_AKM_FBT_SHA384_1X) | \ - BCM_BIT(RSN_AKM_FILS_SHA384) | \ - BCM_BIT(RSN_AKM_FBT_SHA384_FILS) | \ - BCM_BIT(RSN_AKM_PSK_SHA384)) -#define IS_SHA384_AKM(akm) (VALID_AKM_BIT((akm)) & SHA384_AKM_MASK) - -#define OPEN_AUTH_AKM_MASK (\ - BCM_BIT(RSN_AKM_UNSPECIFIED) | \ - BCM_BIT(RSN_AKM_PSK) | \ - BCM_BIT(RSN_AKM_SHA256_1X) | \ - BCM_BIT(RSN_AKM_SHA256_PSK) | \ - BCM_BIT(RSN_AKM_SUITEB_SHA256_1X) | \ - BCM_BIT(RSN_AKM_SUITEB_SHA384_1X) | \ - BCM_BIT(RSN_AKM_PSK_SHA384)) -#define IS_OPEN_AUTH_AKM(akm) (VALID_AKM_BIT((akm)) & OPEN_AUTH_AKM_MASK) - -typedef enum akm_type { - WPA_AUTH_IE = 0x01, - RSN_AUTH_IE = 0x02, - OSEN_AUTH_IE = 0x04 -} akm_type_t; - -#define MAX_ARRAY 1 -#define MIN_ARRAY 0 - -#define WPS_ATID_SEL_REGISTRAR 0x1041 - -/* move these to appropriate file(s) */ -#define WPS_IE_FIXED_LEN 6 - -/* GTK indices we use - 0-3 valid per IEEE/802.11 2012 */ -#define GTK_INDEX_1 1 -#define GTK_INDEX_2 2 - -/* IGTK indices we use - 4-5 are valid per IEEE 802.11 2012 */ -#define IGTK_INDEX_1 4 -#define IGTK_INDEX_2 5 - -/* following needed for compatibility for router code because it automerges */ -#define IGTK_ID_TO_WSEC_INDEX(_id) (_id) -#define WPA_AES_CMAC_CALC aes_cmac_calc - -#define IS_IGTK_INDEX(x) ((x) == IGTK_INDEX_1 || (x) == IGTK_INDEX_2) - -#ifdef RSN_IE_INFO_STRUCT_RELOCATED -typedef struct rsn_ie_info { - uint8 version; - int parse_status; - device_type_t dev_type; /* AP or STA */ - auth_ie_type_mask_t auth_ie_type; /* bit field of WPA, WPA2 and (not yet) WAPI */ - rsn_cipher_t g_cipher; - rsn_akm_t sta_akm; /* single STA akm */ - uint16 caps; - rsn_ciphers_t rsn_p_ciphers; - rsn_ciphers_t wpa_p_ciphers; - rsn_akm_mask_t rsn_akms; - rsn_akm_mask_t wpa_akms; - uint8 pmkid_count; - uint8 pmkids_offset; /* offset into the IE */ - rsn_cipher_t g_mgmt_cipher; - rsn_cipher_t sta_cipher; /* single STA cipher */ - uint16 key_desc; /* key descriptor version as STA */ - uint16 mic_len; /* unused. keep for ROM compatibility. */ - uint8 pmk_len; /* EAPOL PMK */ - uint8 kck_mic_len; /* EAPOL MIC (by KCK) */ - uint8 kck_len; /* EAPOL KCK */ - uint8 kek_len; /* EAPOL KEK */ - uint8 tk_len; /* EAPOL TK */ - uint8 ptk_len; /* EAPOL PTK */ - uint8 kck2_len; /* EAPOL KCK2 */ - uint8 kek2_len; /* EAPOL KEK2 */ - uint8* rsn_ie; /* RSN IE from beacon or assoc request */ - uint16 rsn_ie_len; /* RSN IE length */ - uint8* wpa_ie; /* WPA IE */ - uint16 wpa_ie_len; /* WPA IE length (is it fixed ? */ - /* the following are helpers in the AP rsn info to be filled in by the STA - * after determination of which IE is being used.in wsec_filter. - */ - uint32 p_ciphers; /* current ciphers for the chosen auth IE */ - uint32 akms; /* current ciphers for the chosen auth IE */ - uint8 *auth_ie; /* pointer to current chosen auth IE */ - uint16 auth_ie_len; - uint8 ref_count; /* external reference count to decide if structure must be freed */ - uint8 rsnxe_len; /* RSNXE IE length */ - uint8 PAD[3]; - uint8* rsnxe; /* RSNXE IE TLV buffer */ - uint32 rsnxe_cap; /* RSNXE IE cap flag, refer to 802.11.h */ -} rsn_ie_info_t; -#endif /* RSN_IE_INFO_STRUCT_RELOCATED */ - -/* WiFi WPS Attribute fixed portion */ -typedef struct wps_at_fixed { - uint8 at[2]; - uint8 len[2]; - uint8 data[1]; -} wps_at_fixed_t; - -typedef const struct oui_akm_wpa_tbl { - const char *oui; /* WPA auth category */ - uint16 rsn_akm; - uint32 wpa_auth; -} oui_akm_wpa_tbl_t; - -#define WPS_AT_FIXED_LEN 4 - -#define wps_ie_fixed_t wpa_ie_fixed_t - -/* What should be the multicast mask for AES ? */ -#define WPA_UNICAST_AES_MASK (\ - BCM_BIT(WPA_CIPHER_AES_CCM) | \ - BCM_BIT(WPA_CIPHER_AES_GCM) | \ - BCM_BIT(WPA_CIPHER_AES_GCM256)) - -#define WPA_CIPHER_WEP_MASK (\ - BCM_BIT(WPA_CIPHER_WEP_104) | \ - BCM_BIT(WPA_CIPHER_WEP_40)) - -/* temporary to pass pre-commit */ -#ifdef TMP_USE_RSN_INFO -/* wsec macros */ -#ifdef EXT_STA -#define UCAST_NONE(rsn_info) (((rsn_info)->p_ciphers == (1 << WPA_CIPHER_NONE)) && \ - (!WLEXTSTA_ENAB(wlc->pub) || wlc->use_group_enabled)) -#else -#define UCAST_NONE(rsn_info) (rsn_info->p_ciphers == (1 << WPA_CIPHER_NONE)) -#endif /* EXT_STA */ - -#define UCAST_AES(rsn_info) (rsn_info->p_ciphers & WPA_UNICAST_AES_MASK) -#define UCAST_TKIP(rsn_info) (rsn_info->p_ciphers & (1 << WPA_CIPHER_TKIP)) -#define UCAST_WEP(rsn_info) (rsn_info->p_ciphers & WPA_CIPHER_WEP_MASK) - -#define MCAST_NONE(rsn_info) ((rsn_info)->g_cipher == WPA_CIPHER_NONE) -#define MCAST_AES(rsn_info) ((1 << rsn_info->g_cipher) & WPA_UNICAST_AES_MASK) -#define MCAST_TKIP(rsn_info) (rsn_info->g_cipher == WPA_CIPHER_TKIP) -#define MCAST_WEP(rsn_info) ((1 << rsn_info->g_cipher) & WPA_CIPHER_WEP_MASK) - -#endif /* TMP_USE_RSN_INFO */ - -#define AKM_SHA256_MASK (\ - BCM_BIT(RSN_AKM_SHA256_1X) | \ - BCM_BIT(RSN_AKM_SHA256_PSK) | \ - BCM_BIT(RSN_AKM_SAE_PSK) | \ - BCM_BIT(RSN_AKM_OWE) | \ - BCM_BIT(RSN_AKM_SUITEB_SHA256_1X) | \ - BCM_BIT(RSN_AKM_FILS_SHA256) | \ - BCM_BIT(RSN_AKM_FBT_SHA256_FILS) | \ - BCM_BIT(RSN_AKM_SAE_FBT)) - -#define AKM_SHA384_MASK (\ - BCM_BIT(RSN_AKM_SUITEB_SHA384_1X) | \ - BCM_BIT(RSN_AKM_FBT_SHA384_1X) | \ - BCM_BIT(RSN_AKM_FILS_SHA384) | \ - BCM_BIT(RSN_AKM_FBT_SHA384_FILS) | \ - BCM_BIT(RSN_AKM_FBT_SHA384_PSK) | \ - BCM_BIT(RSN_AKM_PSK_SHA384)) - -/* these AKMs require MFP capable set in their IE */ -#define RSN_MFPC_AKM_MASK (\ - BCM_BIT(RSN_AKM_SAE_PSK) | \ - BCM_BIT(RSN_AKM_OWE) | \ - BCM_BIT(RSN_AKM_SAE_FBT)) - -/* AKMs that supported by in-driver supplicant. - * TODO: have to redesign this to include 1x and other PSK AKMs. - */ -#define IS_BCMSUP_AKM(akm) \ - ((akm == RSN_AKM_PSK) | \ - (akm == RSN_AKM_SAE_PSK) | \ - (akm == RSN_AKM_OWE) | \ - (akm == RSN_AKM_FBT_PSK) | \ - (akm == RSN_AKM_SAE_FBT) | \ - (akm == RSN_AKM_FBT_SHA384_1X) | \ - (akm == RSN_AKM_FBT_SHA384_PSK)) - -/* AKMs use common PSK which identified by broadcast addr */ -#define IS_SHARED_PMK_AKM(akm) \ - ((akm == RSN_AKM_PSK) | \ - (akm == RSN_AKM_FBT_PSK) | \ - (akm == RSN_AKM_SHA256_PSK) | \ - (akm == RSN_AKM_FBT_SHA384_PSK) | \ - (akm == RSN_AKM_PSK_SHA384)) - -#define RSN_AKM_USE_KDF(akm) (akm >= RSN_AKM_FBT_1X ? 1u : 0) - -/* Macro to abstract access to the rsn_ie_info strucuture in case - * we want to move it to a cubby or something else. - * Gives the rsn_info pointer - */ - -#define RSN_INFO_GET(s) (s->rsn_info) -/* where the rsn_info resides */ -#define RSN_INFO_GET_PTR(s) (&s->rsn_info) - -#define AUTH_AKM_INCLUDED(s) (s->rsn_info != NULL && s->rsn_info->parse_status == BCME_OK && \ - s->rsn_info->akms != WPA_AKMS_UNSPECIFIED) - -#define AKM_IS_MEMBER(akm, mask) ((mask) & VALID_AKM_BIT((akm)) || ((akm) == 0 && (mask) == 0)) - -typedef enum eapol_key_type { - EAPOL_KEY_NONE = 0, - EAPOL_KEY_PMK = 1, - EAPOL_KEY_KCK_MIC = 2, - EAPOL_KEY_KEK = 3, - EAPOL_KEY_TK = 4, - EAPOL_KEY_PTK = 5, - EAPOL_KEY_KCK = 6, - EAPOL_KEY_KCK2 = 7, - EAPOL_KEY_KEK2 = 8 -} eapol_key_type_t; - -/* Return address of max or min array depending first argument. - * Return NULL in case of a draw. - */ -extern const uint8 *wpa_array_cmp(int max_array, const uint8 *x, const uint8 *y, uint len); - -/* Increment the array argument */ -extern void wpa_incr_array(uint8 *array, uint len); - -/* Convert WPA IE cipher suite to locally used value */ -extern bool wpa_cipher(wpa_suite_t *suite, ushort *cipher, bool wep_ok); - -/* Look for a WPA IE; return it's address if found, NULL otherwise */ -extern wpa_ie_fixed_t *bcm_find_wpaie(uint8 *parse, uint len); -extern bcm_tlv_t *bcm_find_wmeie(uint8 *parse, uint len, uint8 subtype, uint8 subtype_len); -/* Look for a WPS IE; return it's address if found, NULL otherwise */ -extern wps_ie_fixed_t *bcm_find_wpsie(const uint8 *parse, uint len); -extern wps_at_fixed_t *bcm_wps_find_at(wps_at_fixed_t *at, uint len, uint16 id); -int bcm_find_security_ies(uint8 *buf, uint buflen, void **wpa_ie, - void **rsn_ie); - -#ifdef WLP2P -/* Look for a WiFi P2P IE; return it's address if found, NULL otherwise */ -extern wifi_p2p_ie_t *bcm_find_p2pie(const uint8 *parse, uint len); -#endif -/* Look for a hotspot2.0 IE; return it's address if found, NULL otherwise */ -bcm_tlv_t *bcm_find_hs20ie(uint8 *parse, uint len); -/* Look for a OSEN IE; return it's address if found, NULL otherwise */ -bcm_tlv_t *bcm_find_osenie(uint8 *parse, uint len); - -/* Check whether the given IE has the specific OUI and the specific type. */ -extern bool bcm_has_ie(uint8 *ie, uint8 **tlvs, uint *tlvs_len, - const uint8 *oui, uint oui_len, uint8 type); - -/* Check whether pointed-to IE looks like WPA. */ -#define bcm_is_wpa_ie(ie, tlvs, len) bcm_has_ie(ie, tlvs, len, \ - (const uint8 *)WPA_OUI, WPA_OUI_LEN, WPA_OUI_TYPE) -/* Check whether pointed-to IE looks like WPS. */ -#define bcm_is_wps_ie(ie, tlvs, len) bcm_has_ie(ie, tlvs, len, \ - (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE) -#ifdef WLP2P -/* Check whether the given IE looks like WFA P2P IE. */ -#define bcm_is_p2p_ie(ie, tlvs, len) bcm_has_ie(ie, tlvs, len, \ - (const uint8 *)P2P_OUI, P2P_OUI_LEN, P2P_OUI_TYPE) -#endif - -/* Convert WPA2 IE cipher suite to locally used value */ -extern bool wpa2_cipher(wpa_suite_t *suite, ushort *cipher, bool wep_ok); - -#if defined(BCMSUP_PSK) || defined(BCMSUPPL) || defined(GTKOE) || defined(WL_FILS) -/* Look for an encapsulated GTK; return it's address if found, NULL otherwise */ -extern eapol_wpa2_encap_data_t *wpa_find_gtk_encap(uint8 *parse, uint len); - -/* Check whether pointed-to IE looks like an encapsulated GTK. */ -extern bool wpa_is_gtk_encap(uint8 *ie, uint8 **tlvs, uint *tlvs_len); - -/* Look for encapsulated key data; return it's address if found, NULL otherwise */ -extern eapol_wpa2_encap_data_t *wpa_find_kde(const uint8 *parse, uint len, uint8 type); - -/* Find kde data given eapol header. */ -extern int wpa_find_eapol_kde_data(eapol_header_t *eapol, uint8 eapol_mic_len, - uint8 subtype, eapol_wpa2_encap_data_t **out_data); - -/* Look for kde data in key data. */ -extern int wpa_find_kde_data(const uint8 *kde_buf, uint16 buf_len, - uint8 subtype, eapol_wpa2_encap_data_t **out_data); - -#ifdef WL_OCV -/* Check if both local and remote are OCV capable */ -extern bool wpa_check_ocv_caps(uint16 local_caps, uint16 peer_caps); - -/* Write OCI KDE into the buffer */ -extern int wpa_add_oci_encap(chanspec_t chspec, uint8* buf, uint buf_len); - -/* Validate OCI KDE */ -extern int wpa_validate_oci_encap(chanspec_t chspec, const uint8* buf, uint buf_len); - -/* Write OCI IE into the buffer */ -extern int wpa_add_oci_ie(chanspec_t chspec, uint8* buf, uint buf_len); - -/* Validate OCI IE */ -extern int wpa_validate_oci_ie(chanspec_t chspec, const uint8* buf, uint buf_len); - -/* Write OCI subelement into the FTE buffer */ -extern int wpa_add_oci_ft_subelem(chanspec_t chspec, uint8* buf, uint buf_len); - -/* Validate OCI FTE subelement */ -extern int wpa_validate_oci_ft_subelem(chanspec_t chspec, - const uint8* buf, uint buf_len); -#endif /* WL_OCV */ -#endif /* defined(BCMSUP_PSK) || defined(BCMSUPPL) || defined(GTKOE) || defined(WL_FILS) */ - -#if defined(BCMSUP_PSK) || defined(WLFBT) || defined(BCMAUTH_PSK)|| \ - defined(WL_OKC) || defined(GTKOE) -/* Calculate a pair-wise transient key */ -extern int wpa_calc_ptk(rsn_akm_t akm, const struct ether_addr *auth_ea, - const struct ether_addr *sta_ea, const uint8 *anonce, uint8 anonce_len, - const uint8* snonce, uint8 snonce_len, const uint8 *pmk, - uint pmk_len, uint8 *ptk, uint ptk_len); - -/* Compute Message Integrity Code (MIC) over EAPOL message */ -extern int wpa_make_mic(eapol_header_t *eapol, uint key_desc, uint8 *mic_key, - rsn_ie_info_t *rsn_info, uchar *mic, uint mic_len); - -/* Check MIC of EAPOL message */ -extern bool wpa_check_mic(eapol_header_t *eapol, - uint key_desc, uint8 *mic_key, rsn_ie_info_t *rsn_info); - -/* Calculate PMKID */ -extern void wpa_calc_pmkid(const struct ether_addr *auth_ea, - const struct ether_addr *sta_ea, const uint8 *pmk, uint pmk_len, uint8 *pmkid); - -/* Encrypt key data for a WPA key message */ -extern bool wpa_encr_key_data(eapol_wpa_key_header_t *body, uint16 key_info, - uint8 *ekey, uint8 *gtk, uint8 *data, uint8 *encrkey, rc4_ks_t *rc4key, - const rsn_ie_info_t *rsn_info); - -typedef uint8 wpa_rc4_ivkbuf_t[EAPOL_WPA_KEY_IV_LEN + EAPOL_WPA_ENCR_KEY_MAX_LEN]; -/* Decrypt key data from a WPA key message */ -extern int wpa_decr_key_data(eapol_wpa_key_header_t *body, uint16 key_info, - uint8 *ekey, wpa_rc4_ivkbuf_t ivk, rc4_ks_t *rc4key, const rsn_ie_info_t *rsn_info, - uint16 *dec_len); -#endif /* BCMSUP_PSK || WLFBT || BCMAUTH_PSK || defined(GTKOE) */ - -#if defined(BCMSUP_PSK) || defined(WLFBT) || defined(BCMAUTH_PSK)|| \ - defined(WL_OKC) || defined(GTKOE) || defined(WLHOSTFBT) - -/* Calculate PMKR0 for FT association */ -extern void wpa_calc_pmkR0(sha2_hash_type_t hash_type, const uint8 *ssid, uint ssid_len, - uint16 mdid, const uint8 *r0kh, uint r0kh_len, const struct ether_addr *sta_ea, - const uint8 *pmk, uint pmk_len, uint8 *pmkr0, uint8 *pmkr0name); - -/* Calculate PMKR1 for FT association */ -extern void wpa_calc_pmkR1(sha2_hash_type_t hash_type, const struct ether_addr *r1kh, - const struct ether_addr *sta_ea, const uint8 *pmk, uint pmk_len, - const uint8 *pmkr0name, uint8 *pmkr1, uint8 *pmkr1name); - -/* Calculate PTK for FT association */ -extern void wpa_calc_ft_ptk(sha2_hash_type_t hash_type, const struct ether_addr *bssid, - const struct ether_addr *sta_ea, const uint8 *anonce, const uint8* snonce, - const uint8 *pmk, uint pmk_len, uint8 *ptk, uint ptk_len); - -extern void wpa_derive_pmkR1_name(sha2_hash_type_t hash_type, struct ether_addr *r1kh, - struct ether_addr *sta_ea, uint8 *pmkr0name, uint8 *pmkr1name); - -#endif /* defined(BCMSUP_PSK) || defined(WLFBT) || defined(BCMAUTH_PSK) || - * defined(WL_OKC) || defined(WLTDLS) || defined(GTKOE) || defined(WLHOSTFBT) - */ - -#if defined(BCMSUP_PSK) || defined(BCMSUPPL) - -/* Translate RSNE group mgmt cipher to CRYPTO_ALGO_XXX */ -extern uint8 bcmwpa_find_group_mgmt_algo(rsn_cipher_t g_mgmt_cipher); - -#endif /* BCMSUP_PSK || BCMSUPPL */ - -extern bool bcmwpa_akm2WPAauth(uint8 *akm, uint32 *auth, bool sta_iswpa); - -extern bool bcmwpa_cipher2wsec(uint8 *cipher, uint32 *wsec); - -#ifdef RSN_IE_INFO_STRUCT_RELOCATED -extern uint32 bcmwpa_wpaciphers2wsec(uint32 unicast); -extern int bcmwpa_decode_ie_type(const bcm_tlv_t *ie, rsn_ie_info_t *info, - uint32 *remaining, uint8 *type); - -/* to be removed after merge to NEWT (changed into bcmwpa_rsn_ie_info_reset) */ -void rsn_ie_info_reset(rsn_ie_info_t *rsn_info, osl_t *osh); -uint32 wlc_convert_rsn_to_wsec_bitmap(uint32 ap_cipher_mask); -#else -uint32 bcmwpa_wpaciphers2wsec(uint8 wpacipher); -int bcmwpa_decode_ie_type(const bcm_tlv_t *ie, rsn_ie_info_t *info, uint32 *remaining); -#endif /* RSN_IE_INFO_STRUCT_RELOCATED */ - -extern int bcmwpa_parse_rsnie(const bcm_tlv_t *ie, rsn_ie_info_t *info, device_type_t dev_type); - -/* Calculate PMKID */ -extern void kdf_calc_pmkid(const struct ether_addr *auth_ea, - const struct ether_addr *sta_ea, const uint8 *key, uint key_len, uint8 *pmkid, - rsn_ie_info_t *rsn_info); - -extern void kdf_calc_ptk(const struct ether_addr *auth_ea, const struct ether_addr *sta_ea, - const uint8 *anonce, const uint8 *snonce, const uint8 *pmk, uint pmk_len, - uint8 *ptk, uint ptk_len); - -#ifdef WLTDLS -/* Calculate TPK for TDLS association */ -extern void wpa_calc_tpk(const struct ether_addr *init_ea, - const struct ether_addr *resp_ea, const struct ether_addr *bssid, - const uint8 *anonce, const uint8* snonce, uint8 *tpk, uint tpk_len); -#endif -extern bool bcmwpa_is_wpa_auth(uint32 wpa_auth); -extern bool bcmwpa_includes_wpa_auth(uint32 wpa_auth); -extern bool bcmwpa_is_rsn_auth(uint32 wpa_auth); -extern bool bcmwpa_includes_rsn_auth(uint32 wpa_auth); -extern int bcmwpa_get_algo_key_len(uint8 algo, uint16 *key_len); - -/* macro to pass precommit on ndis builds */ -#define bcmwpa_is_wpa2_auth(wpa_auth) bcmwpa_is_rsn_auth(wpa_auth) -extern uint8 bcmwpa_eapol_key_length(eapol_key_type_t key, rsn_akm_t akm, rsn_cipher_t cipher); - -/* rsn info allocation utilities. */ -void bcmwpa_rsn_ie_info_reset(rsn_ie_info_t *rsn_info, osl_t *osh); -void bcmwpa_rsn_ie_info_rel_ref(rsn_ie_info_t **rsn_info, osl_t *osh); -int bcmwpa_rsn_ie_info_add_ref(rsn_ie_info_t *rsn_info); -int bcmwpa_rsn_akm_cipher_match(rsn_ie_info_t *rsn_info); -int bcmwpa_rsnie_eapol_key_len(rsn_ie_info_t *info); -#if defined(WL_BAND6G) -/* Return TRUE if any of the akm in akms_bmp is invalid in 6Ghz */ -bool bcmwpa_is_invalid_6g_akm(const rsn_akm_mask_t akms_bmp); -/* Return TRUE if any of the cipher in ciphers_bmp is invalid in 6Ghz */ -bool bcmwpa_is_invalid_6g_cipher(const rsn_ciphers_t ciphers_bmp); -#endif /* WL_BAND6G */ -#endif /* _BCMWPA_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bootrommem.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bootrommem.h new file mode 100644 index 000000000000..ebebdab93651 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bootrommem.h @@ -0,0 +1,97 @@ +/* + * bootrommem.h + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +/* This header defines structures shared between dongle and host */ + +#ifndef _BOOTROMMEM_H_ +#define _BOOTROMMEM_H_ + +#include +#ifdef BCMDRIVER +#include +#else +#include +#endif + +#if defined(TEST_BOOTROM_BUILD) +typedef uint8 *bl_ptr_t; +#else +typedef uint32 bl_ptr_t; +#endif /* TEST_BOOROM_BUILD */ + +/* Memory layout + * Addresses have to be uint32 instead of uint8* because the host and dongle + * may have different pointer sizes. + */ +struct bl_mem_region { + bl_ptr_t start; /* start of region */ + bl_ptr_t end; /* location after the region */ +}; +typedef struct bl_mem_region bl_mem_region_t; + +#define BL_MEM_REGION_LEN(_r) ((_r)->end > (_r)->start ? \ + (_r)->end - (_r)->start : 0) + +/* memory regions - not all of these are included in signature */ +struct bl_mem_info { + bl_mem_region_t reset_vec; /* read-only - jmp to BL */ + bl_mem_region_t int_vec; /* copied from RAM, jmp here on success */ + /* ... */ + bl_mem_region_t rom; /* Bootloader at ROM start */ + /* ... */ + /* start of RAM */ + bl_mem_region_t mmap; /* struct/memory map written by host/dhd */ + bl_mem_region_t vstatus; /* verification status */ + /* ... */ + bl_mem_region_t firmware; /* firmware data and code */ + bl_mem_region_t signature; /* signature and signing information */ + bl_mem_region_t heap; /* region for heap allocations */ + /* ... */ + bl_mem_region_t stack; /* stack allocations region */ + bl_mem_region_t prng; /* PRNG data - may be 0 len */ + bl_mem_region_t nvram; /* nvram data */ + /* end of RAM */ +}; +typedef struct bl_mem_info bl_mem_info_t; + +typedef uint16 bl_state_t; +typedef uint32 bl_counter_t; + +/* verification status - populated on return */ +struct bl_verif_status { + bl_status_t status; + bl_state_t state; + uint16 alloc_fail_size; /* Size of the failled alloc request */ + bl_counter_t alloc_bytes; /* currently allocated */ + bl_counter_t max_alloc_bytes; /* max ever allocated */ + bl_counter_t total_alloc_bytes; /* running count of allocated */ + bl_counter_t total_freed_bytes; /* running count of freed */ + bl_counter_t num_allocs; /* number of allocations */ + bl_counter_t max_allocs; /* max number of allocations */ + bl_counter_t max_alloc_size; /* max allocation size */ + bl_counter_t alloc_failures; /* allocation failure count */ + /* add other information as necessary */ +}; +typedef struct bl_verif_status bl_verif_status_t; + +#endif /* _BOOTROMMEM_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/brcm_nl80211.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/brcm_nl80211.h old mode 100755 new mode 100644 index 29a42818ab23..fb61d4596eb0 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/brcm_nl80211.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/brcm_nl80211.h @@ -1,7 +1,7 @@ /* * Definitions for nl80211 vendor command/event access to host driver * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -39,7 +39,9 @@ enum wl_vendor_subcmd { BRCM_VENDOR_SCMD_SET_MAC = 6, BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS = 7, BRCM_VENDOR_SCMD_SET_START_AP_PARAMS = 8, - BRCM_VENDOR_SCMD_MAX = 9 + BRCM_VENDOR_SCMD_ACS = 9, + BRCM_VENDOR_SCMD_SET_TD_POLICY = 10, + BRCM_VENDOR_SCMD_MAX = 11 }; struct bcm_nlmsg_hdr { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11.h deleted file mode 100755 index 5e8e7b23e340..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11.h +++ /dev/null @@ -1,6055 +0,0 @@ -/* - * Chip-specific hardware definitions for - * Broadcom 802.11abg Networking Device Driver - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ - -#ifndef _D11_H -#define _D11_H - -/* - * Notes: - * 1. pre40/pre rev40: corerev < 40 - * 2. pre80/pre rev80: 40 <= corerev < 80 - * 3. rev40/D11AC: 80 > corerev >= 40 - * 4. rev80: corerev >= 80 - */ - -#include -#include -#include -#include <802.11.h> - -#if defined(BCMDONGLEHOST) || defined(WL_UNITTEST) -typedef struct { - uint32 pad; -} shmdefs_t; -#else /* defined(BCMDONGLEHOST)|| defined(WL_UNITTEST) */ -#include -#ifdef USE_BCMCONF_H -#include -#else -#include -#endif -#endif /* !defined(BCMDONGLEHOST)|| !defined(WL_UNITTEST) */ - -#include - -/* This marks the start of a packed structure section. */ -#include - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif - -#define D11AC_BCN_TMPL_LEN 640 /**< length of the BCN template area for 11AC */ - -#define LPRS_TMPL_LEN 512 /**< length of the legacy PRS template area */ - -/* RX FIFO numbers */ -#define RX_FIFO 0 /**< data and ctl frames */ -#define RX_FIFO1 1 /**< ctl frames */ -#define RX_FIFO2 2 /**< ctl frames */ -#define RX_FIFO_NUMBER 3 - -/* TX FIFO numbers using WME Access Classes */ -#define TX_AC_BK_FIFO 0 /**< Access Category Background TX FIFO */ -#define TX_AC_BE_FIFO 1 /**< Access Category Best-Effort TX FIFO */ -#define TX_AC_VI_FIFO 2 /**< Access Class Video TX FIFO */ -#define TX_AC_VO_FIFO 3 /**< Access Class Voice TX FIFO */ -#define TX_BCMC_FIFO 4 /**< Broadcast/Multicast TX FIFO */ -#define TX_ATIM_FIFO 5 /**< TX fifo for ATIM window info */ -#define TX_AC_N_DATA_FIFO 4 /**< Number of legacy Data Fifos (BK, BE, VI, VO) */ - -/* TX FIFO numbers for trigger queues for HE STA only chips (i.e - * This is valid only for 4369 or similar STA chips that supports - * a single HE STA connection. - */ -#define TX_TRIG_BK_FIFO 6 /**< Access Category Background TX FIFO */ -#define TX_TRIG_BE_FIFO 7 /**< Access Category Best-Effort TX FIFO */ -#define TX_TRIG_VI_FIFO 8 /**< Access Class Video TX FIFO */ -#define TX_TRIG_VO_FIFO 9 /**< Access Class Voice TX FIFO */ -#define TX_TRIG_HP_FIFO 10 /**< Access High Priority TX FIFO */ -#define TX_TRIG_N_DATA_FIFO 4 /**< Number of Trigger Data Fifos (BK, BE, VI, VO) */ - -#if defined(WL11AX_TRIGGERQ) && !defined(WL11AX_TRIGGERQ_DISABLED) -#define IS_TRIG_FIFO(fifo) \ - (((fifo) >= TX_TRIG_BK_FIFO) && ((fifo) < (TX_TRIG_BK_FIFO + TX_TRIG_N_DATA_FIFO))) -#else -#define IS_TRIG_FIFO(fifo) FALSE -#endif /* defined(WL11AX_TRIGGERQ) && !defined(WL11AX_TRIGGERQ_DISABLED) */ - -#define IS_AC_FIFO(fifo) \ - ((fifo) < (TX_AC_BK_FIFO + TX_AC_N_DATA_FIFO)) - -/** Legacy TX FIFO numbers */ -#define TX_DATA_FIFO TX_AC_BE_FIFO -#define TX_CTL_FIFO TX_AC_VO_FIFO - -/** Trig TX FIFO numbers */ -#define TX_TRIG_DATA_FIFO TX_TRIG_BE_FIFO -#define TX_TRIG_CTL_FIFO TX_TRIG_VO_FIFO - -/* Extended FIFOs for corerev >= 64 */ -#define TX_FIFO_6 6 -#define TX_FIFO_7 7 -#define TX_FIFO_16 16 -#define TX_FIFO_23 23 -#define TX_FIFO_25 25 - -#define TX_FIFO_EXT_START TX_FIFO_6 /* Starting index of extendied HW TX FIFOs */ -#define TX_FIFO_MU_START 8 /* index at which MU TX FIFOs start */ - -#define D11REG_IHR_WBASE 0x200 -#define D11REG_IHR_BASE (D11REG_IHR_WBASE << 1) - -#define PIHR_BASE 0x0400 /**< byte address of packed IHR region */ - -/* biststatus */ -#define BT_DONE (1U << 31) /**< bist done */ -#define BT_B2S (1 << 30) /**< bist2 ram summary bit */ - -/* DMA intstatus and intmask */ -#define I_PC (1 << 10) /**< pci descriptor error */ -#define I_PD (1 << 11) /**< pci data error */ -#define I_DE (1 << 12) /**< descriptor protocol error */ -#define I_RU (1 << 13) /**< receive descriptor underflow */ -#define I_RO (1 << 14) /**< receive fifo overflow */ -#define I_XU (1 << 15) /**< transmit fifo underflow */ -#define I_RI (1 << 16) /**< receive interrupt */ -#define I_XI (1 << 24) /**< transmit interrupt */ - -/* interrupt receive lazy */ -#define IRL_TO_MASK 0x00ffffff /**< timeout */ -#define IRL_FC_MASK 0xff000000 /**< frame count */ -#define IRL_FC_SHIFT 24 /**< frame count */ -#define IRL_DISABLE 0x01000000 /**< Disabled value: int on 1 frame, zero time */ - -/** for correv >= 80. prev rev uses bit 21 */ -#define MCTL_BCNS_PROMISC_SHIFT 21 -/** for correv < 80. prev rev uses bit 20 */ -#define MCTL_BCNS_PROMISC_SHIFT_LT80 20 - -/* maccontrol register */ -#define MCTL_GMODE (1U << 31) -#define MCTL_DISCARD_PMQ (1 << 30) -#define MCTL_DISCARD_TXSTATUS (1 << 29) -#define MCTL_TBTT_HOLD (1 << 28) -#define MCTL_CLOSED_NETWORK (1 << 27) -#define MCTL_WAKE (1 << 26) -#define MCTL_HPS (1 << 25) -#define MCTL_PROMISC (1 << 24) -#define MCTL_KEEPBADFCS (1 << 23) -#define MCTL_KEEPCONTROL (1 << 22) -#define MCTL_BCNS_PROMISC (1 << MCTL_BCNS_PROMISC_SHIFT) -#define MCTL_BCNS_PROMISC_LT80 (1 << MCTL_BCNS_PROMISC_SHIFT_LT80) -#define MCTL_NO_TXDMA_LAST_PTR (1 << 20) /** for correv >= 85 */ -#define MCTL_LOCK_RADIO (1 << 19) -#define MCTL_AP (1 << 18) -#define MCTL_INFRA (1 << 17) -#define MCTL_BIGEND (1 << 16) -#define MCTL_DISABLE_CT (1 << 14) /** for corerev >= 83.1 */ -#define MCTL_GPOUT_SEL_MASK (3 << 14) -#define MCTL_GPOUT_SEL_SHIFT 14 -#define MCTL_EN_PSMDBG (1 << 13) -#define MCTL_IHR_EN (1 << 10) -#define MCTL_SHM_UPPER (1 << 9) -#define MCTL_SHM_EN (1 << 8) -#define MCTL_PSM_JMP_0 (1 << 2) -#define MCTL_PSM_RUN (1 << 1) -#define MCTL_EN_MAC (1 << 0) - -/* maccontrol1 register */ -#define MCTL1_GCPS (1u << 0u) -#define MCTL1_EGS_MASK 0x0000c000 -#define MCTL1_EGS_SHIFT 14u -#define MCTL1_AVB_ENABLE (1u << 1u) -#define MCTL1_GPIOSEL_SHIFT 8u -#define MCTL1_GPIOSEL (0x3F) -#define MCTL1_GPIOSEL_MASK (MCTL1_GPIOSEL << MCTL1_GPIOSEL_SHIFT) -/* Select MAC_SMPL_CPTR debug data that is placed in pc<7:1> & ifs_gpio_out<8:0> GPIOs */ -#define MCTL1_GPIOSEL_TSF_PC_IFS(_corerev) (D11REV_GE(_corerev, 85) ? 0x3b : 0x36) -#define MCTL1_AVB_TRIGGER (1u << 2u) -#define MCTL1_THIRD_AXI1_FOR_PSM (1u << 3u) -#define MCTL1_AXI1_FOR_RX (1u << 4u) -#define MCTL1_TXDMA_ENABLE_PASS (1u << 5u) -/* SampleCollectPlayCtrl */ -#define SC_PLAYCTRL_MASK_ENABLE (1u << 8u) -#define SC_PLAYCTRL_TRANS_MODE (1u << 6u) -#define SC_PLAYCTRL_SRC_SHIFT 3u -#define SC_PLAYCTRL_SRC_MASK (3u << SC_PLAYCTRL_SRC_SHIFT) -#define SC_PLAYCTRL_SRC_PHY_DBG (3u << SC_PLAYCTRL_SRC_SHIFT) -#define SC_PLAYCTRL_SRC_GPIO_OUT (2u << SC_PLAYCTRL_SRC_SHIFT) -#define SC_PLAYCTRL_SRC_GPIO_IN (1u << SC_PLAYCTRL_SRC_SHIFT) -#define SC_PLAYCTRL_SRC_PHY_SMPL (0u << SC_PLAYCTRL_SRC_SHIFT) -#define SC_PLAYCTRL_STOP (1u << 2u) -#define SC_PLAYCTRL_PAUSE (1u << 1u) -#define SC_PLAYCTRL_START (1u << 0u) -/* SCPortalSel fields */ -#define SC_PORTAL_SEL_AUTO_INCR (1u << 15u) /* Autoincr */ -#define SC_PORTAL_SEL_STORE_MASK (0u << 5u) /* Bits 14:5 SCStoreMask15to0 */ -#define SC_PORTAL_SEL_MATCH_MASK (4u << 5u) /* Bits 14:5 SCMatchMask15to0 */ -#define SC_PORTAL_SEL_MATCH_VALUE (8u << 5u) /* Bits 14:5 SCMatchValue15to0 */ -#define SC_PORTAL_SEL_TRIGGER_MASK (12u << 0u) /* Bits 4:0 SCTriggerMask15to0 */ -#define SC_PORTAL_SEL_TRIGGER_VALUE (16u << 0u) /* Bits 4:0 SCTriggerValue15to0 */ -#define SC_PORTAL_SEL_TRANS_MASK (20u << 0u) /* Bits 4:0 SCTransMask15to0 */ - -/* GpioOut register */ -#define MGPIO_OUT_RXQ1_IFIFO_CNT_MASK 0x1fc0u -#define MGPIO_OUT_RXQ1_IFIFO_CNT_SHIFT 6u - -#define MAC_RXQ1_IFIFO_CNT_ADDR 0x26u -#define MAC_RXQ1_IFIFO_MAXLEN 3u - -/* maccommand register */ -#define MCMD_BCN0VLD (1 << 0) -#define MCMD_BCN1VLD (1 << 1) -#define MCMD_DIRFRMQVAL (1 << 2) -#define MCMD_CCA (1 << 3) -#define MCMD_BG_NOISE (1 << 4) -#define MCMD_SKIP_SHMINIT (1 << 5) /**< only used for simulation */ -#define MCMD_SLOWCAL (1 << 6) -#define MCMD_SAMPLECOLL MCMD_SKIP_SHMINIT /**< reuse for sample collect */ -#define MCMD_IF_DOWN (1 << 8 ) /**< indicate interface is going down */ -#define MCMD_TOF (1 << 9) /**< wifi ranging processing in ucode for rxd frames */ -#define MCMD_TSYNC (1 << 10) /**< start timestamp sync process in ucode */ -#define MCMD_RADIO_DOWN (1 << 11) /**< radio down by ucode */ -#define MCMD_RADIO_UP (1 << 12) /**< radio up by ucode */ -#define MCMD_TXPU (1 << 13) /**< txpu control by ucode */ - -/* macintstatus/macintmask */ -#define MI_MACSSPNDD (1 << 0) /**< MAC has gracefully suspended */ -#define MI_BCNTPL (1 << 1) /**< beacon template available */ -#define MI_TBTT (1 << 2) /**< TBTT indication */ -#define MI_BCNSUCCESS (1 << 3) /**< beacon successfully tx'd */ -#define MI_BCNCANCLD (1 << 4) /**< beacon canceled (IBSS) */ -#define MI_ATIMWINEND (1 << 5) /**< end of ATIM-window (IBSS) */ -#define MI_PMQ (1 << 6) /**< PMQ entries available */ -#define MI_ALTTFS (1 << 7) /**< TX status interrupt for ARM offloads */ -#define MI_NSPECGEN_1 (1 << 8) /**< non-specific gen-stat bits that are set by PSM */ -#define MI_MACTXERR (1 << 9) /**< MAC level Tx error */ -#define MI_PMQERR (1 << 10) -#define MI_PHYTXERR (1 << 11) /**< PHY Tx error */ -#define MI_PME (1 << 12) /**< Power Management Event */ -#define MI_GP0 (1 << 13) /**< General-purpose timer0 */ -#define MI_GP1 (1 << 14) /**< General-purpose timer1 */ -#define MI_DMAINT (1 << 15) /**< (ORed) DMA-interrupts */ -#define MI_TXSTOP (1 << 16) /**< MAC has completed a TX FIFO Suspend/Flush */ -#define MI_CCA (1 << 17) /**< MAC has completed a CCA measurement */ -#define MI_BG_NOISE (1 << 18) /**< MAC has collected background noise samples */ -#define MI_DTIM_TBTT (1 << 19) /**< MBSS DTIM TBTT indication */ -#define MI_PRQ (1 << 20) /**< Probe response queue needs attention */ -#define MI_HEB (1 << 21) /**< HEB (Hardware Event Block) interrupt - 11ax cores */ -#define MI_BT_RFACT_STUCK (1 << 22) /**< MAC has detected invalid BT_RFACT pin, - * valid when rev < 15 - */ -#define MI_TTTT (1 << 22) /**< Target TIM Transmission Time, - * valid in rev = 26/29, or rev >= 42 - */ -#define MI_BT_PRED_REQ (1 << 23) /**< MAC requested driver BTCX predictor calc */ -#define MI_BCNTRIM_RX (1 << 24) /**< PSM received a partial beacon */ -#define MI_P2P (1 << 25) /**< WiFi P2P interrupt */ -#define MI_DMATX (1 << 26) /**< MAC new frame ready */ -#define MI_TSSI_LIMIT (1 << 27) /**< Tssi Limit Reach, TxIdx=0/127 Interrupt */ -#define MI_HWACI_NOTIFY (1 << 27) /**< HWACI detects ACI, Apply Mitigation settings */ -#define MI_RFDISABLE (1 << 28) /**< MAC detected a change on RF Disable input - * (corerev >= 10) - */ -#define MI_TFS (1 << 29) /**< MAC has completed a TX (corerev >= 5) */ -#define MI_LEGACY_BUS_ERROR (1 << 30) /**< uCode indicated bus error */ -#define MI_TO (1U << 31) /**< general purpose timeout (corerev >= 3) */ - -#define MI_RXOV MI_NSPECGEN_1 /**< rxfifo overflow interrupt */ - -/* macintstatus_ext/macintmask_ext */ -#define MI_BUS_ERROR (1U << 0u) /**< uCode indicated bus error */ -#define MI_VCOPLL (1U << 1u) /**< uCode indicated PLL lock issue */ -#define MI_EXT_PS_CHG (1U << 2u) /**< Power state is changing (PS 0 <-> 1) */ -#define MI_DIS_ULOFDMA (1U << 3u) /**< ucode indicated disabling ULOFDMA request */ -#define MI_EXT_PM_OFFLOAD (1U << 4u) /**< PM offload */ -#define MI_OBSS_INTR (1U << 5u) /**< OBSS detection interrupt */ -#define MI_SENSORC_CX_REQ (1U << 6u) /**< SensorC Mitigation Request interrupt */ -#define MI_RLL_NAV_HOF (1U << 7u) /**< RLLW Switch */ - -#define MI_EXT_TXE_SHARED_ERR (1U << 28u) /* Error event in blocks inside TXE shared - * (BMC/AQM/AQM-DMA/MIF) - */ - -/* Mac capabilities registers */ -#define MCAP_TKIPMIC 0x80000000 /**< TKIP MIC hardware present */ -#define MCAP_TKIPPH2KEY 0x40000000 /**< TKIP phase 2 key hardware present */ -#define MCAP_BTCX 0x20000000 /**< BT coexistence hardware and pins present */ -#define MCAP_MBSS 0x10000000 /**< Multi-BSS hardware present */ -#define MCAP_RXFSZ_MASK 0x0ff80000 /**< Rx fifo size in blocks (revid >= 16) */ -#define MCAP_RXFSZ_SHIFT 19 -#define MCAP_NRXQ_MASK 0x00070000 /**< Max Rx queues supported - 1 */ -#define MCAP_NRXQ_SHIFT 16 -#define MCAP_UCMSZ_MASK 0x0000e000 /**< Ucode memory size */ -#define MCAP_UCMSZ_3K3 0 /**< 3328 Words Ucode memory, in unit of 50-bit */ -#define MCAP_UCMSZ_4K 1 /**< 4096 Words Ucode memory */ -#define MCAP_UCMSZ_5K 2 /**< 5120 Words Ucode memory */ -#define MCAP_UCMSZ_6K 3 /**< 6144 Words Ucode memory */ -#define MCAP_UCMSZ_8K 4 /**< 8192 Words Ucode memory */ -#define MCAP_UCMSZ_SHIFT 13 -#define MCAP_TXFSZ_MASK 0x00000ff8 /**< Tx fifo size (* 512 bytes) */ -#define MCAP_TXFSZ_SHIFT 3 -#define MCAP_NTXQ_MASK 0x00000007 /**< Max Tx queues supported - 1 */ -#define MCAP_NTXQ_SHIFT 0 - -#define MCAP_BTCX_SUP(corerev) (MCAP_BTCX) - -#define MCAP_UCMSZ_TYPES 8 /**< different Ucode memory size types */ - -/* machwcap1 */ -#define MCAP1_ERC_MASK 0x00000001 /**< external radio coexistence */ -#define MCAP1_ERC_SHIFT 0 -#define MCAP1_SHMSZ_MASK 0x0000000e /**< shm size (corerev >= 16) */ -#define MCAP1_SHMSZ_SHIFT 1 -#define MCAP1_SHMSZ_1K 0 /**< 1024 words in unit of 32-bit */ -#define MCAP1_SHMSZ_2K 1 /**< 1536 words in unit of 32-bit */ -#define MCAP1_NUMMACCHAINS 0x00003000 /**< Indicates one less than the - number of MAC Chains in the MAC. - */ -#define MCAP1_NUMMACCHAINS_SHIFT 12 -#define MCAP1_RXBLMAX_MASK 0x1800000u -#define MCAP1_RXBLMAX_SHIFT 23u -#define MCAP1_NUM_HEB_MASK 0xE0000000u -#define MCAP1_NUM_HEB_SHIFT 29u -#define MCAP1_NUM_HEB_FACTOR 3u -#define MCAP1_CT_CAPABLE_SHIFT 17 - -/* BTCX control */ -#define BTCX_CTRL_EN 0x0001 /**< Enable BTCX module */ -#define BTCX_CTRL_SW 0x0002 /**< Enable software override */ -#define BTCX_CTRL_DSBLBTCXOUT 0x8000 /* Disable txconf/prisel signal output from btcx module */ - -#define BTCX_CTRL_PRI_POL 0x0080 /* Invert prisel polarity */ -#define BTCX_CTRL_TXC_POL 0x0020 /* Invert txconf polarity */ - -#define SW_PRI_ON 1 /* switch prisel polarity */ -#define SW_TXC_ON 2 /* switch txconf polarity */ - -/* BTCX status */ -#define BTCX_STAT_RA 0x0001 /**< RF_ACTIVE state */ - -/* BTCX transaction control */ -#define BTCX_TRANS_ANTSEL 0x0040 /**< ANTSEL output */ -#define BTCX_TRANS_TXCONF 0x0080 /**< TX_CONF output */ - -/* pmqhost data */ -#define PMQH_DATA_MASK 0xffff0000 /**< data entry of head pmq entry */ -#define PMQH_BSSCFG 0x00100000 /**< PM entry for BSS config */ -#define PMQH_PMOFF 0x00010000 /**< PM Mode OFF: power save off */ -#define PMQH_PMON 0x00020000 /**< PM Mode ON: power save on */ -#define PMQH_PMPS 0x00200000 /**< PM Mode PRETEND */ -#define PMQH_DASAT 0x00040000 /**< Dis-associated or De-authenticated */ -#define PMQH_ATIMFAIL 0x00080000 /**< ATIM not acknowledged */ -#define PMQH_DEL_ENTRY 0x00000001 /**< delete head entry */ -#define PMQH_DEL_MULT 0x00000002 /**< delete head entry to cur read pointer -1 */ -#define PMQH_OFLO 0x00000004 /**< pmq overflow indication */ -#define PMQH_NOT_EMPTY 0x00000008 /**< entries are present in pmq */ - -/* phydebug (corerev >= 3) */ -#define PDBG_CRS (1 << 0) /**< phy is asserting carrier sense */ -#define PDBG_TXA (1 << 1) /**< phy is taking xmit byte from mac this cycle */ -#define PDBG_TXF (1 << 2) /**< mac is instructing the phy to transmit a frame */ -#define PDBG_TXE (1 << 3) /**< phy is signaling a transmit Error to the mac */ -#define PDBG_RXF (1 << 4) /**< phy detected the end of a valid frame preamble */ -#define PDBG_RXS (1 << 5) /**< phy detected the end of a valid PLCP header */ -#define PDBG_RXFRG (1 << 6) /**< rx start not asserted */ -#define PDBG_RXV (1 << 7) /**< mac is taking receive byte from phy this cycle */ -#define PDBG_RFD (1 << 16) /**< RF portion of the radio is disabled */ - -/* objaddr register */ -#define OBJADDR_UCM_SEL 0x00000000 -#define OBJADDR_SHM_SEL 0x00010000 -#define OBJADDR_SCR_SEL 0x00020000 -#define OBJADDR_IHR_SEL 0x00030000 -#define OBJADDR_RCMTA_SEL 0x00040000 -#define OBJADDR_AMT_SEL 0x00040000 -#define OBJADDR_SRCHM_SEL 0x00060000 -#define OBJADDR_KEYTBL_SEL 0x000c0000 -#define OBJADDR_HEB_SEL 0x00120000 -#define OBJADDR_TXDC_TBL_SEL 0x00140000 -#define OBJADDR_TXDC_RIB_SEL 0x00150000 -#define OBJADDR_FCBS_SEL 0x00160000 -#define OBJADDR_LIT_SEL 0x00170000 -#define OBJADDR_LIB_SEL 0x00180000 -#define OBJADDR_WINC 0x01000000 -#define OBJADDR_RINC 0x02000000 -#define OBJADDR_AUTO_INC 0x03000000 -/* SHM/SCR/IHR/SHMX/SCRX/IHRX allow 2 bytes read/write, else only 4 bytes */ -#define OBJADDR_2BYTES_ACCESS(sel) \ - (((sel & 0x70000) == OBJADDR_SHM_SEL) || \ - ((sel & 0x70000) == OBJADDR_SCR_SEL) || \ - ((sel & 0x70000) == OBJADDR_IHR_SEL)) - -/* objdata register */ -#define OBJDATA_WR_COMPLT 0x00000001 - -/* frmtxstatus */ -#define TXS_V (1 << 0) /**< valid bit */ - -#define TXS_STATUS_MASK 0xffff -/* sw mask to map txstatus for corerevs <= 4 to be the same as for corerev > 4 */ -#define TXS_COMPAT_MASK 0x3 -#define TXS_COMPAT_SHIFT 1 -#define TXS_FID_MASK 0xffff0000 -#define TXS_FID_SHIFT 16 - -/* frmtxstatus2 */ -#define TXS_SEQ_MASK 0xffff -#define TXS_PTX_MASK 0xff0000 -#define TXS_PTX_SHIFT 16 -#define TXS_MU_MASK 0x01000000 -#define TXS_MU_SHIFT 24 - -/* clk_ctl_st, corerev >= 17 */ -#define CCS_ERSRC_REQ_D11PLL 0x00000100 /**< d11 core pll request */ -#define CCS_ERSRC_REQ_PHYPLL 0x00000200 /**< PHY pll request */ -#define CCS_ERSRC_REQ_PTMPLL 0x00001000 /* PTM clock request */ -#define CCS_ERSRC_AVAIL_D11PLL 0x01000000 /**< d11 core pll available */ -#define CCS_ERSRC_AVAIL_PHYPLL 0x02000000 /**< PHY pll available */ -#define CCS_ERSRC_AVAIL_PTMPLL 0x10000000 /**< PHY pll available */ - -/* tsf_cfprep register */ -#define CFPREP_CBI_MASK 0xffffffc0 -#define CFPREP_CBI_SHIFT 6 -#define CFPREP_CFPP 0x00000001 - -/* receive fifo control */ -#define RFC_FR (1 << 0) /**< frame ready */ -#define RFC_DR (1 << 1) /**< data ready */ - -/* tx fifo sizes for corerev >= 9 */ -/* tx fifo sizes values are in terms of 256 byte blocks */ -#define TXFIFOCMD_RESET_MASK (1 << 15) /**< reset */ -#define TXFIFOCMD_FIFOSEL_SHIFT 8 /**< fifo */ -#define TXFIFOCMD_FIFOSEL_SET(val) ((val & 0x7) << TXFIFOCMD_FIFOSEL_SHIFT) /* fifo */ -#define TXFIFOCMD_FIFOSEL_GET(val) ((val >> TXFIFOCMD_FIFOSEL_SHIFT) & 0x7) /* fifo */ -#define TXFIFO_FIFOTOP_SHIFT 8 /**< fifo start */ - -#define TXFIFO_FIFO_START(def, def1) ((def & 0xFF) | ((def1 & 0xFF) << 8)) -#define TXFIFO_FIFO_END(def, def1) (((def & 0xFF00) >> 8) | (def1 & 0xFF00)) - -/* Must redefine to 65 for 16 MBSS */ -#ifdef WLLPRS -#define TXFIFO_START_BLK16 (65+16) /**< Base address + 32 * 512 B/P + 8 * 512 11g P */ -#else /* WLLPRS */ -#define TXFIFO_START_BLK16 65 /**< Base address + 32 * 512 B/P */ -#endif /* WLLPRS */ -#define TXFIFO_START_BLK 6 /**< Base address + 6 * 256 B */ -#define TXFIFO_START_BLK_NIN 7 /**< Base address + 6 * 256 B */ - -#define TXFIFO_AC_SIZE_PER_UNIT 512 /**< one unit corresponds to 512 bytes */ - -#define MBSS16_TEMPLMEM_MINBLKS 65 /**< one unit corresponds to 256 bytes */ - -/* phy versions, PhyVersion:Revision field */ -#define PV_AV_MASK 0xf000 /**< analog block version */ -#define PV_AV_SHIFT 12 /**< analog block version bitfield offset */ -#define PV_PT_MASK 0x0f00 /**< phy type */ -#define PV_PT_SHIFT 8 /**< phy type bitfield offset */ -#define PV_PV_MASK 0x00ff /**< phy version */ -#define PHY_TYPE(v) ((v & PV_PT_MASK) >> PV_PT_SHIFT) - -/* phy types, PhyVersion:PhyType field */ -#ifndef USE_BCMCONF_H -#define PHY_TYPE_A 0 /**< A-Phy value */ -#define PHY_TYPE_B 1 /**< B-Phy value */ -#define PHY_TYPE_G 2 /**< G-Phy value */ -#define PHY_TYPE_N 4 /**< N-Phy value */ -/* #define PHY_TYPE_LP 5 */ /**< LP-Phy value */ -/* #define PHY_TYPE_SSN 6 */ /**< SSLPN-Phy value */ -#define PHY_TYPE_HT 7 /**< 3x3 HTPhy value */ -#define PHY_TYPE_LCN 8 /**< LCN-Phy value */ -#define PHY_TYPE_LCNXN 9 /**< LCNXN-Phy value */ -#define PHY_TYPE_LCN40 10 /**< LCN40-Phy value */ -#define PHY_TYPE_AC 11 /**< AC-Phy value */ -#define PHY_TYPE_LCN20 12 /**< LCN20-Phy value */ -#define PHY_TYPE_HE 13 /**< HE-Phy value */ -#define PHY_TYPE_NULL 0xf /**< Invalid Phy value */ -#endif /* USE_BCMCONF_H */ - -/* analog types, PhyVersion:AnalogType field */ -#define ANA_11G_018 1 -#define ANA_11G_018_ALL 2 -#define ANA_11G_018_ALLI 3 -#define ANA_11G_013 4 -#define ANA_11N_013 5 -#define ANA_11LP_013 6 - -/** 802.11a PLCP header def */ -typedef struct ofdm_phy_hdr ofdm_phy_hdr_t; -BWL_PRE_PACKED_STRUCT struct ofdm_phy_hdr { - uint8 rlpt[3]; /**< rate, length, parity, tail */ - uint16 service; - uint8 pad; -} BWL_POST_PACKED_STRUCT; - -#define D11A_PHY_HDR_GRATE(phdr) ((phdr)->rlpt[0] & 0x0f) -#define D11A_PHY_HDR_GRES(phdr) (((phdr)->rlpt[0] >> 4) & 0x01) -#define D11A_PHY_HDR_GLENGTH(phdr) (((*((uint32 *)((phdr)->rlpt))) >> 5) & 0x0fff) -#define D11A_PHY_HDR_GPARITY(phdr) (((phdr)->rlpt[3] >> 1) & 0x01) -#define D11A_PHY_HDR_GTAIL(phdr) (((phdr)->rlpt[3] >> 2) & 0x3f) - -/** rate encoded per 802.11a-1999 sec 17.3.4.1 */ -#define D11A_PHY_HDR_SRATE(phdr, rate) \ - ((phdr)->rlpt[0] = ((phdr)->rlpt[0] & 0xf0) | ((rate) & 0xf)) -/** set reserved field to zero */ -#define D11A_PHY_HDR_SRES(phdr) ((phdr)->rlpt[0] &= 0xef) -/** length is number of octets in PSDU */ -#define D11A_PHY_HDR_SLENGTH(phdr, length) \ - (*(uint32 *)((phdr)->rlpt) = *(uint32 *)((phdr)->rlpt) | \ - (((length) & 0x0fff) << 5)) -/** set the tail to all zeros */ -#define D11A_PHY_HDR_STAIL(phdr) ((phdr)->rlpt[3] &= 0x03) - -#define D11A_PHY_HDR_LEN_L 3 /**< low-rate part of PLCP header */ -#define D11A_PHY_HDR_LEN_R 2 /**< high-rate part of PLCP header */ - -#define D11A_PHY_TX_DELAY (2) /**< 2.1 usec */ - -#define D11A_PHY_HDR_TIME (4) /**< low-rate part of PLCP header */ -#define D11A_PHY_PRE_TIME (16) -#define D11A_PHY_PREHDR_TIME (D11A_PHY_PRE_TIME + D11A_PHY_HDR_TIME) - -/** 802.11b PLCP header def */ -typedef struct cck_phy_hdr cck_phy_hdr_t; -BWL_PRE_PACKED_STRUCT struct cck_phy_hdr { - uint8 signal; - uint8 service; - uint16 length; - uint16 crc; -} BWL_POST_PACKED_STRUCT; - -#define D11B_PHY_HDR_LEN 6 - -#define D11B_PHY_TX_DELAY (3) /**< 3.4 usec */ - -#define D11B_PHY_LHDR_TIME (D11B_PHY_HDR_LEN << 3) -#define D11B_PHY_LPRE_TIME (144) -#define D11B_PHY_LPREHDR_TIME (D11B_PHY_LPRE_TIME + D11B_PHY_LHDR_TIME) - -#define D11B_PHY_SHDR_TIME (D11B_PHY_LHDR_TIME >> 1) -#define D11B_PHY_SPRE_TIME (D11B_PHY_LPRE_TIME >> 1) -#define D11B_PHY_SPREHDR_TIME (D11B_PHY_SPRE_TIME + D11B_PHY_SHDR_TIME) - -#define D11B_PLCP_SIGNAL_LOCKED (1 << 2) -#define D11B_PLCP_SIGNAL_LE (1 << 7) - -/* AMPDUXXX: move to ht header file once it is ready: Mimo PLCP */ -#define MIMO_PLCP_MCS_MASK 0x7f /**< mcs index */ -#define MIMO_PLCP_40MHZ 0x80 /**< 40 Hz frame */ -#define MIMO_PLCP_AMPDU 0x08 /**< ampdu */ - -#define WLC_GET_CCK_PLCP_LEN(plcp) (plcp[4] + (plcp[5] << 8)) -#define WLC_GET_MIMO_PLCP_LEN(plcp) (plcp[1] + (plcp[2] << 8)) -#define WLC_SET_MIMO_PLCP_LEN(plcp, len) \ - plcp[1] = len & 0xff; plcp[2] = ((len >> 8) & 0xff); - -#define WLC_SET_MIMO_PLCP_AMPDU(plcp) (plcp[3] |= MIMO_PLCP_AMPDU) -#define WLC_CLR_MIMO_PLCP_AMPDU(plcp) (plcp[3] &= ~MIMO_PLCP_AMPDU) -#define WLC_IS_MIMO_PLCP_AMPDU(plcp) (plcp[3] & MIMO_PLCP_AMPDU) - -/** - * The dot11a PLCP header is 5 bytes. To simplify the software (so that we don't need eg different - * tx DMA headers for 11a and 11b), the PLCP header has padding added in the ucode. - */ -#define D11_PHY_HDR_LEN 6u - -/** For the AC phy PLCP is 12 bytes and not all bytes are used for all the modulations */ -#define D11AC_PHY_HDR_LEN 12 -#define D11AC_PHY_VHT_PLCP_OFFSET 0 -#define D11AC_PHY_HTMM_PLCP_OFFSET 0 -#define D11AC_PHY_HTGF_PLCP_OFFSET 3 -#define D11AC_PHY_OFDM_PLCP_OFFSET 3 -#define D11AC_PHY_CCK_PLCP_OFFSET 6 -#define D11AC_PHY_BEACON_PLCP_OFFSET 0 - -#define D11_PHY_RXPLCP_LEN(rev) (D11_PHY_HDR_LEN) -#define D11_PHY_RXPLCP_OFF(rev) (0) - -/** TX descriptor - pre40 */ -typedef struct d11txh_pre40 d11txh_pre40_t; -BWL_PRE_PACKED_STRUCT struct d11txh_pre40 { - uint16 MacTxControlLow; /* 0x0 */ - uint16 MacTxControlHigh; /* 0x1 */ - uint16 MacFrameControl; /* 0x2 */ - uint16 TxFesTimeNormal; /* 0x3 */ - uint16 PhyTxControlWord; /* 0x4 */ - uint16 PhyTxControlWord_1; /* 0x5 */ - uint16 PhyTxControlWord_1_Fbr; /* 0x6 */ - uint16 PhyTxControlWord_1_Rts; /* 0x7 */ - uint16 PhyTxControlWord_1_FbrRts; /* 0x8 */ - uint16 MainRates; /* 0x9 */ - uint16 XtraFrameTypes; /* 0xa */ - uint8 IV[16]; /* 0x0b - 0x12 */ - uint8 TxFrameRA[6]; /* 0x13 - 0x15 */ - uint16 TxFesTimeFallback; /* 0x16 */ - uint8 RTSPLCPFallback[6]; /* 0x17 - 0x19 */ - uint16 RTSDurFallback; /* 0x1a */ - uint8 FragPLCPFallback[6]; /* 0x1b - 1d */ - uint16 FragDurFallback; /* 0x1e */ - uint16 MModeLen; /* 0x1f */ - uint16 MModeFbrLen; /* 0x20 */ - uint16 TstampLow; /* 0x21 */ - uint16 TstampHigh; /* 0x22 */ - uint16 ABI_MimoAntSel; /* 0x23 */ - uint16 PreloadSize; /* 0x24 */ - uint16 AmpduSeqCtl; /* 0x25 */ - uint16 TxFrameID; /* 0x26 */ - uint16 TxStatus; /* 0x27 */ - uint16 MaxNMpdus; /* 0x28 corerev >=16 */ - BWL_PRE_PACKED_STRUCT union { - uint16 MaxAggDur; /* 0x29 corerev >=16 */ - uint16 MaxAggLen; - } BWL_POST_PACKED_STRUCT u1; - BWL_PRE_PACKED_STRUCT union { - BWL_PRE_PACKED_STRUCT struct { /* 0x29 corerev >=16 */ - uint8 MaxRNum; - uint8 MaxAggBytes; /* Max Agg Bytes in power of 2 */ - } BWL_POST_PACKED_STRUCT s1; - uint16 MaxAggLen_FBR; - } BWL_POST_PACKED_STRUCT u2; - uint16 MinMBytes; /* 0x2b corerev >=16 */ - uint8 RTSPhyHeader[D11_PHY_HDR_LEN]; /* 0x2c - 0x2e */ - struct dot11_rts_frame rts_frame; /* 0x2f - 0x36 */ - uint16 pad; /* 0x37 */ -} BWL_POST_PACKED_STRUCT; - -#define D11_TXH_LEN 112 /**< bytes */ - -/* Frame Types */ -#define FT_LEGACY (-1) -#define FT_CCK 0 -#define FT_OFDM 1 -#define FT_HT 2 -#define FT_VHT 3 -#define FT_HE 4 -#define FT_EHT 6 - -/* HE PPDU type */ -#define HE_SU_PPDU 0 -#define HE_SU_RE_PPDU 1 -#define HE_MU_PPDU 2 -#define HE_TRIG_PPDU 3 - -/* Position of MPDU inside A-MPDU; indicated with bits 10:9 of MacTxControlLow */ -#define TXC_AMPDU_SHIFT 9 /**< shift for ampdu settings */ -#define TXC_AMPDU_NONE 0 /**< Regular MPDU, not an A-MPDU */ -#define TXC_AMPDU_FIRST 1 /**< first MPDU of an A-MPDU */ -#define TXC_AMPDU_MIDDLE 2 /**< intermediate MPDU of an A-MPDU */ -#define TXC_AMPDU_LAST 3 /**< last (or single) MPDU of an A-MPDU */ - -/* MacTxControlLow */ -#define TXC_AMIC 0x8000 -#define TXC_USERIFS 0x4000 -#define TXC_LIFETIME 0x2000 -#define TXC_FRAMEBURST 0x1000 -#define TXC_SENDCTS 0x0800 -#define TXC_AMPDU_MASK 0x0600 -#define TXC_BW_40 0x0100 -#define TXC_FREQBAND_5G 0x0080 -#define TXC_DFCS 0x0040 -#define TXC_IGNOREPMQ 0x0020 -#define TXC_HWSEQ 0x0010 -#define TXC_STARTMSDU 0x0008 -#define TXC_SENDRTS 0x0004 -#define TXC_LONGFRAME 0x0002 -#define TXC_IMMEDACK 0x0001 - -/* MacTxControlHigh */ -#define TXC_PREAMBLE_RTS_FB_SHORT 0x8000 /* RTS fallback preamble type 1 = SHORT 0 = LONG */ -#define TXC_PREAMBLE_RTS_MAIN_SHORT 0x4000 /* RTS main rate preamble type 1 = SHORT 0 = LONG */ -#define TXC_PREAMBLE_DATA_FB_SHORT 0x2000 /**< Main fallback rate preamble type - * 1 = SHORT for OFDM/GF for MIMO - * 0 = LONG for CCK/MM for MIMO - */ -/* TXC_PREAMBLE_DATA_MAIN is in PhyTxControl bit 5 */ -#define TXC_AMPDU_FBR 0x1000 /**< use fallback rate for this AMPDU */ -#define TXC_SECKEY_MASK 0x0FF0 -#define TXC_SECKEY_SHIFT 4 -#define TXC_ALT_TXPWR 0x0008 /**< Use alternate txpwr defined at loc. M_ALT_TXPWR_IDX */ -#define TXC_SECTYPE_MASK 0x0007 -#define TXC_SECTYPE_SHIFT 0 - -/* Null delimiter for Fallback rate */ -#define AMPDU_FBR_NULL_DELIM 5 /**< Location of Null delimiter count for AMPDU */ - -/* PhyTxControl for Mimophy */ -#define PHY_TXC_PWR_MASK 0xFC00 -#define PHY_TXC_PWR_SHIFT 10 -#define PHY_TXC_ANT_MASK 0x03C0 /**< bit 6, 7, 8, 9 */ -#define PHY_TXC_ANT_SHIFT 6 -#define PHY_TXC_ANT_0_1 0x00C0 /**< auto, last rx */ -#define PHY_TXC_LPPHY_ANT_LAST 0x0000 -#define PHY_TXC_ANT_3 0x0200 /**< virtual antenna 3 */ -#define PHY_TXC_ANT_2 0x0100 /**< virtual antenna 2 */ -#define PHY_TXC_ANT_1 0x0080 /**< virtual antenna 1 */ -#define PHY_TXC_ANT_0 0x0040 /**< virtual antenna 0 */ - -#define PHY_TXC_SHORT_HDR 0x0010 -#define PHY_TXC_FT_MASK 0x0003 - -#define PHY_TXC_FT_CCK 0x0000 -#define PHY_TXC_FT_OFDM 0x0001 -#define PHY_TXC_FT_HT 0x0002 -#define PHY_TXC_FT_VHT 0x0003 -#define PHY_TXC_FT_HE 0x0004 -#define PHY_TXC_FT_EHT 0x0006 - -#define PHY_TXC_OLD_ANT_0 0x0000 -#define PHY_TXC_OLD_ANT_1 0x0100 -#define PHY_TXC_OLD_ANT_LAST 0x0300 - -/** PhyTxControl_1 for Mimophy */ -#define PHY_TXC1_BW_MASK 0x0007 -#define PHY_TXC1_BW_10MHZ 0 -#define PHY_TXC1_BW_10MHZ_UP 1 -#define PHY_TXC1_BW_20MHZ 2 -#define PHY_TXC1_BW_20MHZ_UP 3 -#define PHY_TXC1_BW_40MHZ 4 -#define PHY_TXC1_BW_40MHZ_DUP 5 -#define PHY_TXC1_MODE_SHIFT 3 -#define PHY_TXC1_MODE_MASK 0x0038 -#define PHY_TXC1_MODE_SISO 0 -#define PHY_TXC1_MODE_CDD 1 -#define PHY_TXC1_MODE_STBC 2 -#define PHY_TXC1_MODE_SDM 3 -#define PHY_TXC1_CODE_RATE_SHIFT 8 -#define PHY_TXC1_CODE_RATE_MASK 0x0700 -#define PHY_TXC1_CODE_RATE_1_2 0 -#define PHY_TXC1_CODE_RATE_2_3 1 -#define PHY_TXC1_CODE_RATE_3_4 2 -#define PHY_TXC1_CODE_RATE_4_5 3 -#define PHY_TXC1_CODE_RATE_5_6 4 -#define PHY_TXC1_CODE_RATE_7_8 6 -#define PHY_TXC1_MOD_SCHEME_SHIFT 11 -#define PHY_TXC1_MOD_SCHEME_MASK 0x3800 -#define PHY_TXC1_MOD_SCHEME_BPSK 0 -#define PHY_TXC1_MOD_SCHEME_QPSK 1 -#define PHY_TXC1_MOD_SCHEME_QAM16 2 -#define PHY_TXC1_MOD_SCHEME_QAM64 3 -#define PHY_TXC1_MOD_SCHEME_QAM256 4 - -/* PhyTxControl for HTphy that are different from Mimophy */ -#define PHY_TXC_HTANT_MASK 0x3fC0 /**< bit 6, 7, 8, 9, 10, 11, 12, 13 */ -#define PHY_TXC_HTCORE_MASK 0x03C0 /**< core enable core3:core0, 1=enable, 0=disable */ -#define PHY_TXC_HTCORE_SHIFT 6 /**< bit 6, 7, 8, 9 */ -#define PHY_TXC_HTANT_IDX_MASK 0x3C00 /**< 4-bit, 16 possible antenna configuration */ -#define PHY_TXC_HTANT_IDX_SHIFT 10 -#define PHY_TXC_HTANT_IDX0 0 -#define PHY_TXC_HTANT_IDX1 1 -#define PHY_TXC_HTANT_IDX2 2 -#define PHY_TXC_HTANT_IDX3 3 - -/* PhyTxControl_1 for HTphy that are different from Mimophy */ -#define PHY_TXC1_HTSPARTIAL_MAP_MASK 0x7C00 /**< bit 14:10 */ -#define PHY_TXC1_HTSPARTIAL_MAP_SHIFT 10 -#define PHY_TXC1_HTTXPWR_OFFSET_MASK 0x01f8 /**< bit 8:3 */ -#define PHY_TXC1_HTTXPWR_OFFSET_SHIFT 3 - -/* TxControl word follows new interface for AX */ -/* PhyTxControl_6 for AXphy */ -#define PHY_TXC5_AXTXPWR_OFFSET_C0_MASK 0xff00 /**< bit 15:8 */ -#define PHY_TXC5_AXTXPWR_OFFSET_C0_SHIFT 8 -#define PHY_TXC6_AXTXPWR_OFFSET_C1_MASK 0x00ff /**< bit 7:0 */ -#define PHY_TXC6_AXTXPWR_OFFSET_C1_SHIFT 0 -#define PHY_TXC5_AXTXPWR_OFFSET_C2_MASK 0x00ff /**< bit 7:0 */ -#define PHY_TXC5_AXTXPWR_OFFSET_C2_SHIFT 0 - -/* XtraFrameTypes */ -#define XFTS_RTS_FT_SHIFT 2 -#define XFTS_FBRRTS_FT_SHIFT 4 -#define XFTS_CHANNEL_SHIFT 8 - -/** Antenna diversity bit in ant_wr_settle */ -#define PHY_AWS_ANTDIV 0x2000 - -/* IFS ctl */ -#define IFS_USEEDCF (1 << 2) - -/* IFS ctl1 */ -#define IFS_CTL1_EDCRS (1 << 3) -#define IFS_CTL1_EDCRS_20L (1 << 4) -#define IFS_CTL1_EDCRS_40 (1 << 5) -#define IFS_EDCRS_MASK (IFS_CTL1_EDCRS | IFS_CTL1_EDCRS_20L | IFS_CTL1_EDCRS_40) -#define IFS_EDCRS_SHIFT 3 - -/* IFS ctl sel pricrs */ -#define IFS_CTL_CRS_SEL_20LL 1 -#define IFS_CTL_CRS_SEL_20LU 2 -#define IFS_CTL_CRS_SEL_20UL 4 -#define IFS_CTL_CRS_SEL_20UU 8 -#define IFS_CTL_CRS_SEL_MASK (IFS_CTL_CRS_SEL_20LL | IFS_CTL_CRS_SEL_20LU | \ - IFS_CTL_CRS_SEL_20UL | IFS_CTL_CRS_SEL_20UU) -#define IFS_CTL_ED_SEL_20LL (1 << 8) -#define IFS_CTL_ED_SEL_20LU (1 << 9) -#define IFS_CTL_ED_SEL_20UL (1 << 10) -#define IFS_CTL_ED_SEL_20UU (1 << 11) -#define IFS_CTL_ED_SEL_MASK (IFS_CTL_ED_SEL_20LL | IFS_CTL_ED_SEL_20LU | \ - IFS_CTL_ED_SEL_20UL | IFS_CTL_ED_SEL_20UU) - -/* ABI_MimoAntSel */ -#define ABI_MAS_ADDR_BMP_IDX_MASK 0x0f00 -#define ABI_MAS_ADDR_BMP_IDX_SHIFT 8 -#define ABI_MAS_FBR_ANT_PTN_MASK 0x00f0 -#define ABI_MAS_FBR_ANT_PTN_SHIFT 4 -#define ABI_MAS_MRT_ANT_PTN_MASK 0x000f - -#ifdef WLAWDL -#define ABI_MAS_AWDL_TS_INSERT 0x1000 /**< bit 12 */ -#endif - -#define ABI_MAS_TIMBC_TSF 0x2000 /**< Enable TIMBC tsf field present */ - -/* MinMBytes */ -#define MINMBYTES_PKT_LEN_MASK 0x0300 -#define MINMBYTES_FBRATE_PWROFFSET_MASK 0xFC00 -#define MINMBYTES_FBRATE_PWROFFSET_SHIFT 10 - -/* Rev40 template constants */ - -/** templates include a longer PLCP header that matches the MAC / PHY interface */ -#define D11_VHT_PLCP_LEN 12 - -/* 11AC TX DMA buffer header */ - -#define D11AC_TXH_NUM_RATES 4 - -/** per rate info - rev40 */ -typedef struct d11actxh_rate d11actxh_rate_t; -BWL_PRE_PACKED_STRUCT struct d11actxh_rate { - uint16 PhyTxControlWord_0; /* 0 - 1 */ - uint16 PhyTxControlWord_1; /* 2 - 3 */ - uint16 PhyTxControlWord_2; /* 4 - 5 */ - uint8 plcp[D11_PHY_HDR_LEN]; /* 6 - 11 */ - uint16 FbwInfo; /* 12 -13, fall back bandwidth info */ - uint16 TxRate; /* 14 */ - uint16 RtsCtsControl; /* 16 */ - uint16 Bfm0; /* 18 */ -} BWL_POST_PACKED_STRUCT; - -/* Bit definition for FbwInfo field */ -#define FBW_BW_MASK 3 -#define FBW_BW_SHIFT 0 -#define FBW_TXBF 4 -#define FBW_TXBF_SHIFT 2 -/* this needs to be re-visited if we want to use this feature */ -#define FBW_BFM0_TXPWR_MASK 0x1F8 -#define FBW_BFM0_TXPWR_SHIFT 3 -#define FBW_BFM_TXPWR_MASK 0x7E00 -#define FBW_BFM_TXPWR_SHIFT 9 - -/* Bit definition for Bfm0 field */ -#define BFM0_TXPWR_MASK 0x3f -#define BFM0_STBC_SHIFT 6 -#define BFM0_STBC (1 << BFM0_STBC_SHIFT) -/* should find a chance to converge the two */ -#define D11AC2_BFM0_TXPWR_MASK 0x7f -#define D11AC2_BFM0_STBC_SHIFT 7 -#define D11AC2_BFM0_STBC (1 << D11AC2_BFM0_STBC_SHIFT) - -/* per packet info */ -typedef struct d11pktinfo_common d11pktinfo_common_t; -typedef struct d11pktinfo_common d11actxh_pkt_t; -BWL_PRE_PACKED_STRUCT struct d11pktinfo_common { - /* Per pkt info */ - uint16 TSOInfo; /* 0 */ - uint16 MacTxControlLow; /* 2 */ - uint16 MacTxControlHigh; /* 4 */ - uint16 Chanspec; /* 6 */ - uint8 IVOffset; /* 8 */ - uint8 PktCacheLen; /* 9 */ - uint16 FrameLen; /* 10. In [bytes] units. */ - uint16 TxFrameID; /* 12 */ - uint16 Seq; /* 14 */ - uint16 Tstamp; /* 16 */ - uint16 TxStatus; /* 18 */ -} BWL_POST_PACKED_STRUCT; - -/* common cache info between rev40 and rev80 formats */ -typedef struct d11txh_cache_common d11txh_cache_common_t; -BWL_PRE_PACKED_STRUCT struct d11txh_cache_common { - uint8 BssIdEncAlg; /* 0 */ - uint8 KeyIdx; /* 1 */ - uint8 PrimeMpduMax; /* 2 */ - uint8 FallbackMpduMax; /* 3 */ - uint16 AmpduDur; /* 4 - 5 */ - uint8 BAWin; /* 6 */ - uint8 MaxAggLen; /* 7 */ -} BWL_POST_PACKED_STRUCT; - -/** Per cache info - rev40 */ -typedef struct d11actxh_cache d11actxh_cache_t; -BWL_PRE_PACKED_STRUCT struct d11actxh_cache { - d11txh_cache_common_t common; /* 0 - 7 */ - uint8 TkipPH1Key[10]; /* 8 - 17 */ - uint8 TSCPN[6]; /* 18 - 23 */ -} BWL_POST_PACKED_STRUCT; - -/** Long format tx descriptor - rev40 */ -typedef struct d11actxh d11actxh_t; -BWL_PRE_PACKED_STRUCT struct d11actxh { - /* Per pkt info */ - d11actxh_pkt_t PktInfo; /* 0 - 19 */ - - union { - - /** Rev 40 to rev 63 layout */ - struct { - /** Per rate info */ - d11actxh_rate_t RateInfo[D11AC_TXH_NUM_RATES]; /* 20 - 99 */ - - /** Per cache info */ - d11actxh_cache_t CacheInfo; /* 100 - 123 */ - } rev40; - - /** Rev >= 64 layout */ - struct { - /** Per cache info */ - d11actxh_cache_t CacheInfo; /* 20 - 43 */ - - /** Per rate info */ - d11actxh_rate_t RateInfo[D11AC_TXH_NUM_RATES]; /* 44 - 123 */ - } rev64; - - }; -} BWL_POST_PACKED_STRUCT; - -#define D11AC_TXH_LEN sizeof(d11actxh_t) /* 124 bytes */ - -/* Short format tx descriptor only has per packet info */ -#define D11AC_TXH_SHORT_LEN sizeof(d11actxh_pkt_t) /* 20 bytes */ - -/* -TXDC-TxH Excluding Rate Info 41 bytes (Note 1 byte of RATEINFO is removed */ -#define D11AC_TXH_SHORT_EXT_LEN (sizeof(d11txh_rev80_t) - 1) - -/* Retry limit regs */ -/* Current retries for the fallback rates are hardcoded */ -#define D11AC_TXDC_SRL_FB (3u) /* Short Retry Limit - Fallback */ -#define D11AC_TXDC_LRL_FB (2u) /* Long Retry Limit - Fallback */ - -#define D11AC_TXDC_RET_LIM_MASK (0x000Fu) -#define D11AC_TXDC_SRL_SHIFT (0u) /* Short Retry Limit */ -#define D11AC_TXDC_SRL_FB_SHIFT (4u) /* Short Retry Limit - Fallback */ -#define D11AC_TXDC_LRL_SHIFT (8u) /* Long Retry Limit */ -#define D11AC_TXDC_LRL_FB_SHIFT (12u) /* Long Retry Limit - Fallback */ - -/* MacTxControlLow */ -#define D11AC_TXC_HDR_FMT_SHORT 0x0001 /**< 0: long format, 1: short format */ -#define D11AC_TXC_UPD_CACHE 0x0002 -#define D11AC_TXC_CACHE_IDX_MASK 0x003C /**< Cache index 0 .. 15 */ -#define D11AC_TXC_CACHE_IDX_SHIFT 2 - -#define D11AC_TXDC_IDX_SHIFT 1 -#define D11AC_TXDC_CPG_SHIFT 5 -#define D11REV80_TXDC_RIB_CPG 0x0020 /**< Cache Index CPG (Bit 5) -TXDC- */ -#define D11REV80_TXDC_RIB_DEL_MASK 0x001E /**< Cache index CIPX 0 .. 15 (Bit 1-4 -TXDC- */ -#define D11REV80_TXDC_RIB_IMM_MASK 0x003E /**< Cache index CIPX 0 .. 31 (Bit 1-5) -TXDC- */ -#define D11AC_TXC_AMPDU 0x0040 /**< Is aggregate-able */ -#define D11AC_TXC_IACK 0x0080 /**< Expect immediate ACK */ -#define D11AC_TXC_LFRM 0x0100 /**< Use long/short retry frame count/limit */ -#define D11AC_TXC_IPMQ 0x0200 /**< Ignore PMQ */ -#define D11AC_TXC_MBURST 0x0400 /**< Burst mode */ -#define D11AC_TXC_ASEQ 0x0800 /**< Add ucode generated seq num */ -#define D11AC_TXC_AGING 0x1000 /**< Use lifetime */ -#define D11AC_TXC_AMIC 0x2000 /**< Compute and add TKIP MIC */ -#define D11AC_TXC_STMSDU 0x4000 /**< First MSDU */ -#define D11AC_TXC_URIFS 0x8000 /**< Use RIFS */ - -/* MacTxControlHigh */ -#define D11AC_TXC_DISFCS 0x0001 /**< Discard FCS */ -#define D11AC_TXC_FIX_RATE 0x0002 /**< Use primary rate only */ -#define D11AC_TXC_SVHT 0x0004 /**< Single VHT mpdu ampdu */ -#define D11AC_TXC_PPS 0x0008 /**< Enable PS Pretend feature */ -#define D11AC_TXC_UCODE_SEQ 0x0010 /* Sequence counter for BK traffic, for offloads */ -#define D11AC_TXC_TIMBC_TSF 0x0020 /**< Enable TIMBC tsf field present */ -#define D11AC_TXC_TCPACK 0x0040 -#define D11AC_TXC_AWDL_PHYTT 0x0080 /**< Fill in PHY Transmission Time for AWDL action frames */ -#define D11AC_TXC_TOF 0x0100 /**< Enable wifi ranging processing for rxd frames */ -#define D11AC_TXC_MU 0x0200 /**< MU Tx data */ -#define D11AC_TXC_BFIX 0x0800 /**< BFI from SHMx */ -#define D11AC_TXC_NORETRY 0x0800 /**< Disable retry for tsync frames */ -#define D11AC_TXC_UFP 0x1000 /**< UFP */ -#define D11AC_TXC_OVERRIDE_NAV 0x1000 /**< if set, ucode will tx without honoring NAV */ -#define D11AC_TXC_DYNBW 0x2000 /**< Dynamic BW */ -#define D11AC_TXC_TXPROF_EN 0x8000 /**< TxProfile Enable TODO: support multiple idx */ -#define D11AC_TXC_SLTF 0x8000 /**< 11az Secure Ranging frame */ - -#define D11AC_TSTAMP_SHIFT 8 /**< Tstamp in 256us units */ - -/* PhyTxControlWord_0 */ -#define D11AC_PHY_TXC_FT_MASK 0x0003 - -/* vht txctl0 */ -#define D11AC_PHY_TXC_NON_SOUNDING 0x0004 -#define D11AC_PHY_TXC_BFM 0x0008 -#define D11AC_PHY_TXC_SHORT_PREAMBLE 0x0010 -#define D11AC2_PHY_TXC_STBC 0x0020 -#define D11AC_PHY_TXC_ANT_MASK 0x3FC0 -#define D11AC_PHY_TXC_CORE_MASK 0x03C0 -#define D11AC_PHY_TXC_CORE_SHIFT 6 -#define D11AC_PHY_TXC_ANT_IDX_MASK 0x3C00 -#define D11AC_PHY_TXC_ANT_IDX_SHIFT 10 -#define D11AC_PHY_TXC_BW_MASK 0xC000 -#define D11AC_PHY_TXC_BW_SHIFT 14 -#define D11AC_PHY_TXC_BW_20MHZ 0x0000 -#define D11AC_PHY_TXC_BW_40MHZ 0x4000 -#define D11AC_PHY_TXC_BW_80MHZ 0x8000 -#define D11AC_PHY_TXC_BW_160MHZ 0xC000 - -/* PhyTxControlWord_1 */ -#define D11AC_PHY_TXC_PRIM_SUBBAND_MASK 0x0007 -#define D11AC_PHY_TXC_PRIM_SUBBAND_LLL 0x0000 -#define D11AC_PHY_TXC_PRIM_SUBBAND_LLU 0x0001 -#define D11AC_PHY_TXC_PRIM_SUBBAND_LUL 0x0002 -#define D11AC_PHY_TXC_PRIM_SUBBAND_LUU 0x0003 -#define D11AC_PHY_TXC_PRIM_SUBBAND_ULL 0x0004 -#define D11AC_PHY_TXC_PRIM_SUBBAND_ULU 0x0005 -#define D11AC_PHY_TXC_PRIM_SUBBAND_UUL 0x0006 -#define D11AC_PHY_TXC_PRIM_SUBBAND_UUU 0x0007 -#define D11AC_PHY_TXC_TXPWR_OFFSET_MASK 0x01F8 -#define D11AC_PHY_TXC_TXPWR_OFFSET_SHIFT 3 -#define D11AC2_PHY_TXC_TXPWR_OFFSET_MASK 0x03F8 -#define D11AC2_PHY_TXC_TXPWR_OFFSET_SHIFT 3 -#define D11AC_PHY_TXC_TXBF_USER_IDX_MASK 0x7C00 -#define D11AC_PHY_TXC_TXBF_USER_IDX_SHIFT 10 -#define D11AC2_PHY_TXC_DELTA_TXPWR_OFFSET_MASK 0x7C00 -#define D11AC2_PHY_TXC_DELTA_TXPWR_OFFSET_SHIFT 10 -/* Rather awkward bit mapping to keep pctl1 word same as legacy, for proprietary 11n rate support */ -#define D11AC_PHY_TXC_11N_PROP_MCS 0x8000 /* this represents bit mcs[6] */ -#define D11AC2_PHY_TXC_MU 0x8000 - -/* PhyTxControlWord_2 phy rate */ -#define D11AC_PHY_TXC_PHY_RATE_MASK 0x003F -#define D11AC2_PHY_TXC_PHY_RATE_MASK 0x007F - -/* 11b phy rate */ -#define D11AC_PHY_TXC_11B_PHY_RATE_MASK 0x0003 -#define D11AC_PHY_TXC_11B_PHY_RATE_1 0x0000 -#define D11AC_PHY_TXC_11B_PHY_RATE_2 0x0001 -#define D11AC_PHY_TXC_11B_PHY_RATE_5_5 0x0002 -#define D11AC_PHY_TXC_11B_PHY_RATE_11 0x0003 - -/* 11a/g phy rate */ -#define D11AC_PHY_TXC_11AG_PHY_RATE_MASK 0x0007 -#define D11AC_PHY_TXC_11AG_PHY_RATE_6 0x0000 -#define D11AC_PHY_TXC_11AG_PHY_RATE_9 0x0001 -#define D11AC_PHY_TXC_11AG_PHY_RATE_12 0x0002 -#define D11AC_PHY_TXC_11AG_PHY_RATE_18 0x0003 -#define D11AC_PHY_TXC_11AG_PHY_RATE_24 0x0004 -#define D11AC_PHY_TXC_11AG_PHY_RATE_36 0x0005 -#define D11AC_PHY_TXC_11AG_PHY_RATE_48 0x0006 -#define D11AC_PHY_TXC_11AG_PHY_RATE_54 0x0007 - -/* 11ac phy rate */ -#define D11AC_PHY_TXC_11AC_MCS_MASK 0x000F -#define D11AC_PHY_TXC_11AC_NSS_MASK 0x0030 -#define D11AC_PHY_TXC_11AC_NSS_SHIFT 4 - -/* 11n phy rate */ -#define D11AC_PHY_TXC_11N_MCS_MASK 0x003F -#define D11AC2_PHY_TXC_11N_MCS_MASK 0x007F -#define D11AC2_PHY_TXC_11N_PROP_MCS 0x0040 /* this represents bit mcs[6] */ - -/* PhyTxControlWord_2 rest */ -#define D11AC_PHY_TXC_STBC 0x0040 -#define D11AC_PHY_TXC_DYN_BW_IN_NON_HT_PRESENT 0x0080 -#define D11AC_PHY_TXC_DYN_BW_IN_NON_HT_DYNAMIC 0x0100 -#define D11AC2_PHY_TXC_TXBF_USER_IDX_MASK 0xFE00 -#define D11AC2_PHY_TXC_TXBF_USER_IDX_SHIFT 9 - -/* RtsCtsControl */ -#define D11AC_RTSCTS_FRM_TYPE_MASK 0x0001 /**< frame type */ -#define D11AC_RTSCTS_FRM_TYPE_11B 0x0000 /**< 11b */ -#define D11AC_RTSCTS_FRM_TYPE_11AG 0x0001 /**< 11a/g */ -#define D11AC_RTSCTS_USE_RTS 0x0004 /**< Use RTS */ -#define D11AC_RTSCTS_USE_CTS 0x0008 /**< Use CTS */ -#define D11AC_RTSCTS_SHORT_PREAMBLE 0x0010 /**< Long/short preamble: 0 - long, 1 - short? */ -#define D11AC_RTSCTS_LAST_RATE 0x0020 /**< this is last rate */ -#define D11AC_RTSCTS_IMBF 0x0040 /**< Implicit TxBF */ -#define D11AC_RTSCTS_MIMOPS_RTS 0x8000 /**< Use RTS for mimops */ -#define D11AC_RTSCTS_DPCU_VALID 0x0080 /**< DPCU Valid : Same bitfield as above */ -#define D11AC_RTSCTS_BF_IDX_MASK 0xF000 /**< 4-bit index to the beamforming block */ -#define D11AC_RTSCTS_BF_IDX_SHIFT 12 -#define D11AC_RTSCTS_RATE_MASK 0x0F00 /**< Rate table offset: bit 3-0 of PLCP byte 0 */ -#define D11AC_RTSCTS_USE_RATE_SHIFT 8 - -/* BssIdEncAlg */ -#define D11AC_BSSID_MASK 0x000F /**< BSS index */ -#define D11AC_BSSID_SHIFT 0 -#define D11AC_ENCRYPT_ALG_MASK 0x00F0 /**< Encryption algoritm */ -#define D11AC_ENCRYPT_ALG_SHIFT 4 -#define D11AC_ENCRYPT_ALG_NOSEC 0x0000 /**< No security */ -#define D11AC_ENCRYPT_ALG_WEP 0x0010 /**< WEP */ -#define D11AC_ENCRYPT_ALG_TKIP 0x0020 /**< TKIP */ -#define D11AC_ENCRYPT_ALG_AES 0x0030 /**< AES */ -#define D11AC_ENCRYPT_ALG_WEP128 0x0040 /**< WEP128 */ -#define D11AC_ENCRYPT_ALG_NA 0x0050 /**< N/A */ -#define D11AC_ENCRYPT_ALG_WAPI 0x0060 /**< WAPI */ - -/* AmpduDur */ -#define D11AC_AMPDU_MIN_DUR_IDX_MASK 0x000F /**< AMPDU minimum duration index */ -#define D11AC_AMPDU_MIN_DUR_IDX_SHIFT 0 -#define D11AC_AMPDU_MAX_DUR_MASK 0xFFF0 /**< AMPDU maximum duration in unit 16 usec */ -#define D11AC_AMPDU_MAX_DUR_SHIFT 4 - -/** - * TX Descriptor definitions for supporting rev80 (HE) - */ -/* Maximum number of TX fallback rates per packet */ -#define D11_REV80_TXH_NUM_RATES 4 -#define D11_REV80_TXH_PHYTXCTL_MIN_LENGTH 1 - -/** per rate info - fixed portion - rev80 */ -typedef struct d11txh_rev80_rate_fixed d11txh_rev80_rate_fixed_t; -BWL_PRE_PACKED_STRUCT struct d11txh_rev80_rate_fixed { - uint16 TxRate; /* rate in 500Kbps */ - uint16 RtsCtsControl; /* RTS - CTS control */ - uint8 plcp[D11_PHY_HDR_LEN]; /* 6 bytes */ -} BWL_POST_PACKED_STRUCT; - -/* rev80 specific per packet info fields */ -typedef struct d11pktinfo_rev80 d11pktinfo_rev80_t; -BWL_PRE_PACKED_STRUCT struct d11pktinfo_rev80 { - uint16 HEModeControl; /* 20 */ - uint16 length; /* 22 - length of txd in bytes */ -} BWL_POST_PACKED_STRUCT; - -#define D11_REV80_TXH_TX_MODE_SHIFT 0 /* Bits 2:0 of HeModeControl */ -#define D11_REV80_TXH_TX_MODE_MASK 0x3 -#define D11_REV80_TXH_HTC_OFFSET_SHIFT 4 /* Bits 8:4 of HeModeControl */ -#define D11_REV80_TXH_HTC_OFFSET_MASK 0x01F0u -#define D11_REV80_TXH_TWT_EOSP 0x0200u /* bit 9 indicate TWT EOSP */ -#define D11_REV80_TXH_QSZ_QOS_CTL_IND_SHIFT 10 /* Bit 10 of HeModeControl */ -#define D11_REV80_TXH_QSZ_QOS_CTL_IND_MASK (1 << D11_REV80_TXH_QSZ_QOS_CTL_IND_SHIFT) -#define D11_REV80_TXH_USE_BSSCOLOR_SHM_SHIFT 15 /* Bit 15 of HEModeControl */ -#define D11_REV80_TXH_USE_BSSCOLOR_SHM_MASK (1 << D11_REV80_TXH_USE_BSSCOLOR_SHM_SHIFT) - -/* Calculate Length for short format TXD */ -#define D11_TXH_SHORT_LEN(__corerev__) (D11REV_GE(__corerev__, 80) ? \ - D11_REV80_TXH_SHORT_LEN : \ - D11AC_TXH_SHORT_LEN) - -/* Calculate Length for short format TXD (TXDC and/or FMF) */ -#define D11_TXH_SHORT_EX_LEN(__corerev__) (D11REV_GE(__corerev__, 80) ? \ - D11_REV80_TXH_SHORT_EX_LEN : \ - D11AC_TXH_SHORT_LEN) - -#define D11_REV80_TXH_IS_HE_AMPDU_SHIFT 11 /* Bit 11 of HeModeControl */ -#define D11_REV80_TXH_IS_HE_AMPDU_MASK (1 << D11_REV80_TXH_IS_HE_AMPDU_SHIFT) - -#define D11_REV80_PHY_TXC_EDCA 0x00 -#define D11_REV80_PHY_TXC_OFDMA_RA 0x01 /* Use Random Access Trigger for Tx */ -#define D11_REV80_PHY_TXC_OFDMA_DT 0x02 /* Use Directed Trigger for Tx */ -#define D11_REV80_PHY_TXC_OFDMA_ET 0x03 /* Use earliest Trigger Opportunity */ - -/** Per cache info - rev80 */ -typedef struct d11txh_rev80_cache d11txh_rev80_cache_t; -BWL_PRE_PACKED_STRUCT struct d11txh_rev80_cache { - d11txh_cache_common_t common; /* 0 - 7 */ - uint16 ampdu_mpdu_all; /* 8 - 9 */ - uint16 aggid; /* 10 - 11 */ - uint8 tkipph1_index; /* 12 */ - uint8 pktext; /* 13 */ - uint16 hebid_map; /* 14 -15: HEB ID bitmap */ -} BWL_POST_PACKED_STRUCT; - -/** Fixed size portion of TX descriptor - rev80 */ -typedef struct d11txh_rev80 d11txh_rev80_t; -BWL_PRE_PACKED_STRUCT struct d11txh_rev80 { - /** - * Per pkt info fields (common + rev80 specific) - * - * Note : Ensure that PktInfo field is always the first member - * of the d11txh_rev80 struct (that is at OFFSET - 0) - */ - d11pktinfo_common_t PktInfo; /* 0 - 19 */ - d11pktinfo_rev80_t PktInfoExt; /* 20 - 23 */ - - /** Per cache info */ - d11txh_rev80_cache_t CacheInfo; /* 24 - 39 */ - - /** - * D11_REV80_TXH_NUM_RATES number of Rate Info blocks - * contribute to the variable size portion of the TXD. - * Each Rate Info element (block) is a funtion of - * (N_PwrOffset, N_RU, N_User). - */ - uint8 RateInfoBlock[1]; -} BWL_POST_PACKED_STRUCT; - -/* Size of fixed portion in TX descriptor (without CacheInfo(Link info) and RateInfoBlock) - * this portion never change regardless of TXDC/FMF support. - */ -/* OFFSETOF() is available in bcmutils.h but including it will cause - * recursive inclusion of d11.h specifically on NDIS platforms. - */ -#ifdef BCMFUZZ - /* use 0x10 offset to avoid undefined behavior error due to NULL access */ -#define D11_REV80_TXH_FIXED_LEN (((uint)(uintptr)&((d11txh_rev80_t *)0x10)->CacheInfo) - 0x10) -#else -#define D11_REV80_TXH_FIXED_LEN ((uint)(uintptr)&((d11txh_rev80_t *)0)->CacheInfo) -#endif /* BCMFUZZ */ - -/* Short format tx descriptor only has per packet info (24 bytes) */ -#define D11_REV80_TXH_SHORT_LEN (sizeof(d11pktinfo_common_t) + sizeof(d11pktinfo_rev80_t)) - -/* Size of CacheInfo(Link info) in TX descriptor */ -#define D11_REV80_TXH_LINK_INFO_LEN (sizeof(d11txh_rev80_cache_t)) - -/* Size of Short format TX descriptor - * with TXDC - Short TXD(40 bytes) shall include PktInfo and Cache info without Rate info - * with TXDC+FMF - Short TXD(24 bytes) shall include PktInfo only without Link info and Rate info - * do NOT use D11_REV80_TXH_SHORT_EX_LEN to calculate long TXD length, value depends on FMF feature - */ -#if defined(FMF_LIT) && !defined(FMF_LIT_DISABLED) -#define D11_REV80_TXH_SHORT_EX_LEN D11_REV80_TXH_FIXED_LEN -#else -#define D11_REV80_TXH_SHORT_EX_LEN (D11_REV80_TXH_FIXED_LEN + D11_REV80_TXH_LINK_INFO_LEN) -#endif /* FMF_LIT && !FMF_LIT_DISABLED */ - -/* Length of BFM0 field in RateInfo Blk */ -#define D11_REV80_TXH_BFM0_FIXED_LEN(pwr_offs) 2u - -/** - * Length of FBWInfo field in RateInfo Blk - * - * Note : for now return fixed length of 1 word - */ -#define D11_REV80_TXH_FBWINFO_FIXED_LEN(pwr_offs) 2 - -#define D11_REV80_TXH_FIXED_RATEINFO_LEN sizeof(d11txh_rev80_rate_fixed_t) - -/** - * Macros to find size of N-RUs field in the PhyTxCtlWord. - */ -#define D11_REV80_TXH_TXC_N_RUs_FIELD_SIZE 1 -#define D11_REV80_TXH_TXC_PER_RU_INFO_SIZE 4 -#define D11_REV80_TXH_TXC_PER_RU_MIN_SIZE 2 - -#define D11_REV80_TXH_TXC_RU_FIELD_SIZE(n_rus) ((n_rus == 1) ? \ - (D11_REV80_TXH_TXC_PER_RU_MIN_SIZE) : \ - ((D11_REV80_TXH_TXC_N_RUs_FIELD_SIZE) + \ - ((n_rus) * D11_REV80_TXH_TXC_PER_RU_INFO_SIZE))) - -/** - * Macros to find size of N-Users field in the TXCTL_EXT - */ -#define D11_REV80_TXH_TXC_EXT_N_USERs_FIELD_SIZE 1 -#define D11_REV80_TXH_TXC_EXT_PER_USER_INFO_SIZE 4 - -#define D11_REV80_TXH_TXC_N_USERs_FIELD_SIZE(n_users) \ - ((n_users) ? \ - (((n_users) * \ - (D11_REV80_TXH_TXC_EXT_PER_USER_INFO_SIZE)) + \ - (D11_REV80_TXH_TXC_EXT_N_USERs_FIELD_SIZE)) : \ - (n_users)) - -/** - * Size of each Tx Power Offset field in PhyTxCtlWord. - */ -#define D11_REV80_TXH_TXC_PWR_OFFSET_SIZE 1u - -/** - * Size of fixed / static fields in PhyTxCtlWord (all fields except N-RUs, N-Users and Pwr offsets) - */ -#define D11_REV80_TXH_TXC_CONST_FIELDS_SIZE 6u - -/** - * Macros used for filling PhyTxCtlWord - */ - -/* PhyTxCtl Byte 0 */ -#define D11_REV80_PHY_TXC_FT_MASK 0x0007u -#define D11_REV80_PHY_TXC_HE_FMT_MASK 0x0018u -#define D11_REV80_PHY_TXC_SOFT_AP_MODE 0x0020u -#define D11_REV80_PHY_TXC_NON_SOUNDING 0x0040u -#define D11_REV80_PHY_TXC_SHORT_PREAMBLE 0x0080u -#define D11_REV80_PHY_TXC_FRAME_TYPE_VHT 0X0003u -#define D11_REV80_PHY_TXC_FRAME_TYPE_HT 0X0002u -#define D11_REV80_PHY_TXC_FRAME_TYPE_LEG 0X0001u - -#define D11_REV80_PHY_TXC_HE_FMT_SHIFT 3u - -/* PhyTxCtl Byte 1 */ -#define D11_REV80_PHY_TXC_STBC 0x0080u - -/* PhyTxCtl Word 1 (Bytes 2 - 3) */ -#define D11_REV80_PHY_TXC_DPCU_SUBBAND_SHIFT 5u -#define D11_REV80_PHY_TXC_DYNBW_PRESENT 0x2000u -#define D11_REV80_PHY_TXC_DYNBW_MODE 0x4000u -#define D11_REV80_PHY_TXC_MU 0x8000u -#define D11_REV80_PHY_TXC_BW_MASK 0x0003u -#define D11_REV80_PHY_TXC_BW_20MHZ 0x0000u -#define D11_REV80_PHY_TXC_BW_40MHZ 0x0001u -#define D11_REV80_PHY_TXC_BW_80MHZ 0x0002u -#define D11_REV80_PHY_TXC_BW_160MHZ 0x0003u -/* PhyTxCtl Word 2 (Bytes 4 -5) */ -/* Though the width antennacfg, coremask fields are 8-bits, - * only 4 bits is valid for 4369a0, hence masking only 4 bits - */ -#define D11_REV80_PHY_TXC_ANT_CONFIG_MASK 0x00F0u -#define D11_REV80_PHY_TXC_CORE_MASK 0x000Fu -#define D11_REV80_PHY_TXC_ANT_CONFIG_SHIFT 4u -/* upper byte- Ant. cfg, lower byte - Core */ -#define D11_REV80_PHY_TXC_ANT_CORE_MASK 0x0F0Fu - -/* PhyTxCtl BFM field */ -#define D11_REV80_PHY_TXC_BFM 0x80u - -/* PhyTxCtl power offsets */ -#define D11_REV80_PHY_TXC_PWROFS0_BYTE_POS 6u - -/* Phytx Ctl Sub band location */ -#define D11_REV80_PHY_TXC_SB_SHIFT 2u -#define D11_REV80_PHY_TXC_SB_MASK 0x001Cu - -/* 11n phy rate */ -#define D11_REV80_PHY_TXC_11N_MCS_MASK 0x003Fu -#define D11_REV80_PHY_TXC_11N_PROP_MCS 0x0040u /* this represents bit mcs[6] */ - -/* 11ac phy rate */ -#define D11_REV80_PHY_TXC_11AC_NSS_SHIFT 4u - -/* PhyTxCtl Word0 */ -#define D11_REV80_PHY_TXC_MCS_NSS_MASK 0x7F00u -#define D11_REV80_PHY_TXC_MCS_MASK 0xF00u -#define D11_REV80_PHY_TXC_MCS_NSS_SHIFT 8u - -/* 11ax phy rate */ -#define D11_REV80_PHY_TXC_11AX_NSS_SHIFT 4u - -#define D11_PHY_TXC_FT_MASK(corerev) ((D11REV_GE(corerev, 80)) ? D11_REV80_PHY_TXC_FT_MASK : \ - D11AC_PHY_TXC_FT_MASK) - -/* PhyTxCtl Word 4 */ -#define D11_REV80_PHY_TXC_HEHL_ENABLE 0x2000u - -/* PhyTxCtl Word 5 */ -#define D11_REV80_PHY_TXC_CORE0_PWR_OFFSET_SHIFT 8u -#define D11_REV80_PHY_TXC_CORE0_PWR_OFFSET_MASK 0xFF00u -/* PhyTxCtl Word 6 */ -#define D11_REV80_PHY_TXC_CORE1_PWR_OFFSET_MASK 0x00FFu -/* Number of RU assigned */ -#define D11_REV80_PHY_TXC_NRU 0x0100u - -/* A wrapper structure for all versions of TxD/d11txh structures */ -typedef union d11txhdr { - d11txh_pre40_t pre40; - d11actxh_t rev40; - d11txh_rev80_t rev80; -} d11txhdr_t; - -/** - * Generic tx status packet for software use. This is independent of hardware - * structure for a particular core. Hardware structure should be read and converted - * to this structure before being sent for the sofware consumption. - */ -typedef struct tx_status tx_status_t; -typedef struct tx_status_macinfo tx_status_macinfo_t; - -BWL_PRE_PACKED_STRUCT struct tx_status_macinfo { - int8 pad0; - int8 is_intermediate; - int8 pm_indicated; - int8 pad1; - uint8 suppr_ind; - int8 was_acked; - uint16 rts_tx_cnt; - uint16 frag_tx_cnt; - uint16 cts_rx_cnt; - uint16 raw_bits; - uint32 s3; - uint32 s4; - uint32 s5; - uint32 s8; - uint32 s9; - uint32 s10; - uint32 s11; - uint32 s12; - uint32 s13; - uint32 s14; - /* 128BA support */ - uint16 ncons_ext; - uint16 s15; - uint32 ack_map[8]; - /* pktlat */ - uint16 pkt_fetch_ts; /* PSM Packet Fetch Time */ - uint16 med_acc_dly; /* Medium Access Delay */ - uint16 rx_dur; /* Rx duration */ - uint16 mac_susp_dur; /* Mac Suspend Duration */ - uint16 txstatus_ts; /* TxStatus Time */ - uint16 tx_en_cnt; /* Number of times Tx was enabled */ - uint16 oac_txs_cnt; /* Other AC TxStatus count */ - uint16 data_retx_cnt; /* DataRetry count */ - uint16 pktlat_rsvd; /* reserved */ -} BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct tx_status { - uint16 framelen; - uint16 frameid; - uint16 sequence; - uint16 phyerr; - uint32 lasttxtime; - uint16 ackphyrxsh; - uint16 procflags; /* tx status processing flags */ - uint32 dequeuetime; - tx_status_macinfo_t status; -} BWL_POST_PACKED_STRUCT; - -/* Bits in struct tx_status procflags */ -#define TXS_PROCFLAG_AMPDU_BA_PKG2_READ_REQD 0x1 /* AMPDU BA txs pkg2 read required */ - -/* status field bit definitions */ -#define TX_STATUS_FRM_RTX_MASK 0xF000 -#define TX_STATUS_FRM_RTX_SHIFT 12 -#define TX_STATUS_RTS_RTX_MASK 0x0F00 -#define TX_STATUS_RTS_RTX_SHIFT 8 -#define TX_STATUS_MASK 0x00FE -#define TX_STATUS_PMINDCTD (1 << 7) /**< PM mode indicated to AP */ -#define TX_STATUS_INTERMEDIATE (1 << 6) /**< intermediate or 1st ampdu pkg */ -#define TX_STATUS_AMPDU (1 << 5) /**< AMPDU status */ -#define TX_STATUS_SUPR_MASK 0x1C /**< suppress status bits (4:2) */ -#define TX_STATUS_SUPR_SHIFT 2 -#define TX_STATUS_ACK_RCV (1 << 1) /**< ACK received */ -#define TX_STATUS_VALID (1 << 0) /**< Tx status valid (corerev >= 5) */ -#define TX_STATUS_NO_ACK 0 -#define TX_STATUS_BE (TX_STATUS_ACK_RCV | TX_STATUS_PMINDCTD) - -/* TX_STATUS for fw initiated pktfree event */ -#define TX_STATUS_SW_Q_FLUSH 0x10000 - -/* status field bit definitions phy rev > 40 */ -#define TX_STATUS40_FIRST 0x0002 -#define TX_STATUS40_INTERMEDIATE 0x0004 -#define TX_STATUS40_PMINDCTD 0x0008 - -#define TX_STATUS40_SUPR 0x00f0 -#define TX_STATUS40_SUPR_SHIFT 4 - -#define TX_STATUS40_NCONS 0x7f00 - -#define TX_STATUS40_NCONS_SHIFT 8 - -#define TX_STATUS40_ACK_RCV 0x8000 - -/* tx status bytes 8-16 */ -#define TX_STATUS40_TXCNT_RATE0_MASK 0x000000ff -#define TX_STATUS40_TXCNT_RATE0_SHIFT 0 - -#define TX_STATUS40_TXCNT_RATE1_MASK 0x00ff0000 -#define TX_STATUS40_TXCNT_RATE1_SHIFT 16 - -#define TX_STATUS40_MEDIUM_DELAY_MASK 0xFFFF - -#define TX_STATUS40_TXCNT(s3, s4) \ - (((s3 & TX_STATUS40_TXCNT_RATE0_MASK) >> TX_STATUS40_TXCNT_RATE0_SHIFT) + \ - ((s3 & TX_STATUS40_TXCNT_RATE1_MASK) >> TX_STATUS40_TXCNT_RATE1_SHIFT) + \ - ((s4 & TX_STATUS40_TXCNT_RATE0_MASK) >> TX_STATUS40_TXCNT_RATE0_SHIFT) + \ - ((s4 & TX_STATUS40_TXCNT_RATE1_MASK) >> TX_STATUS40_TXCNT_RATE1_SHIFT)) - -#define TX_STATUS40_TXCNT_RT0(s3) \ - ((s3 & TX_STATUS40_TXCNT_RATE0_MASK) >> TX_STATUS40_TXCNT_RATE0_SHIFT) - -#define TX_STATUS_EXTBA_TXCNT_BITS 0x3u -#define TX_STATUS_EXTBA_TXSUCCNT_BITS 0x1u -#define TX_STATUS_EXTBA_TXSIZE_RT 0x4u - -#define TX_STATUS_EXTBA_TXCNT_RATE_MASK 0x7u -#define TX_STATUS_EXTBA_TXSUCCNT_RATE_MASK 0x8u - -#define TX_STATUS_EXTBA_TXCNT_RATE_SHIFT 0x8u -#define TX_STATUS_EXTBA_TXSUCCNT_RATE_SHIFT 0x8u - -#define TX_STATUS_EXTBA_TXCNT_RT(s15, rt) \ - ((((s15) & (TX_STATUS_EXTBA_TXCNT_RATE_MASK << ((rt) * TX_STATUS_EXTBA_TXSIZE_RT))) >> \ - ((rt) * TX_STATUS_EXTBA_TXSIZE_RT)) << TX_STATUS_EXTBA_TXCNT_RATE_SHIFT) - -#define TX_STATUS_EXTBA_TXSUCCNT_RT(s15, rt) \ - ((((s15) & (TX_STATUS_EXTBA_TXSUCCNT_RATE_MASK << ((rt) * TX_STATUS_EXTBA_TXSIZE_RT))) >> \ - (((rt) * TX_STATUS_EXTBA_TXSIZE_RT))) << TX_STATUS_EXTBA_TXSUCCNT_RATE_SHIFT) - -#define TX_STATUS40_TX_MEDIUM_DELAY(txs) ((txs)->status.s8 & TX_STATUS40_MEDIUM_DELAY_MASK) - -/* chip rev 40 pkg 2 fields */ -#define TX_STATUS40_IMPBF_MASK 0x0000000Cu /* implicit bf applied */ -#define TX_STATUS40_IMPBF_BAD_MASK 0x00000010u /* impl bf applied but ack frm has no bfm */ -#define TX_STATUS40_IMPBF_LOW_MASK 0x00000020u /* ack received with low rssi */ -#define TX_STATUS40_BFTX 0x00000040u /* Beamformed pkt TXed */ -/* pkt two status field bit definitions mac rev > 64 */ -#define TX_STATUS64_MUTX 0x00000080u /* Not used in STA-dongle chips */ - -/* pkt two status field bit definitions mac rev > 80 */ - -/* TXS rate cookie contains - * mac rev 81/82 : RIT idx in bit[4:0] of RIB CtrlStat[0] - * mac rev >= 83 : RIB version in bit[4:0] of RIB CtrlStat[1] - */ -#define TX_STATUS80_RATE_COOKIE_MASK 0x00003E00u -#define TX_STATUS80_RATE_COOKIE_SHIFT 9u -#define TX_STATUS80_NAV_HDR 0x00004000u /* NAV Overriden */ - -#define TX_STATUS80_TBPPDU_MASK 0x00000040u /* Indicates TBPPDU TX */ -#define TX_STATUS80_TBPPDU_SHIFT 6u -#define TX_STATUS40_RTS_RTX_MASK 0x00ff0000u -#define TX_STATUS40_RTS_RTX_SHIFT 16u -#define TX_STATUS40_CTS_RRX_MASK 0xff000000u -#define TX_STATUS40_CTS_RRX_SHIFT 24u - -/* - * Intermediate status for TBPPDU (for stats purposes) - * First uint16 word (word0 - status): VALID, !FIRST, INTERMEDIATE - * Remaining word0 bits (3 - 15) are unasisgned - */ -#define TX_ITBSTATUS(status) \ - (((status) & (TX_STATUS40_FIRST | TX_STATUS40_INTERMEDIATE)) == TX_STATUS40_INTERMEDIATE) -/* Remainder of first uint32 (words 0 and 1) */ -#define TX_ITBSTATUS_LSIG_MASK 0x0000fff0u -#define TX_ITBSTATUS_LSIG_SHIFT 4u -#define TX_ITBSTATUS_TXPOWER_MASK 0xffff0000u -#define TX_ITBSTATUS_TXPOWER_SHIFT 16u -/* Second uint32 (words 2 and 3) */ -#define TX_ITBSTATUS_NULL_DELIMS_MASK 0x0007ffffu /* 19 bits * 4B => ~2M bytes */ -#define TX_ITBSTATUS_NULL_DELIMS_SHIFT 0u -#define TX_ITBSTATUS_ACKED_MPDUS_MASK 0x3ff80000u /* 11 bits: 0-2047 */ -#define TX_ITBSTATUS_ACKED_MPDUS_SHIFT 19u -/* Third uint32 (words 4 and 5) */ -#define TX_ITBSTATUS_SENT_MPDUS_MASK 0x0000ffe0u /* 11 bits: 0-2047 */ -#define TX_ITBSTATUS_SENT_MPDUS_SHIFT 5u -#define TX_ITBSTATUS_APTXPWR_MASK 0x003f0000u /* 0-60 => -20 - 40 */ -#define TX_ITBSTATUS_APTXPWR_SHIFT 16u -#define TX_ITBSTATUS_ULPKTEXT_MASK 0x01c00000u -#define TX_ITBSTATUS_ULPKTEXT_SHIFT 22u -#define TX_ITBSTATUS_MORETF_MASK 0x02000000u -#define TX_ITBSTATUS_MORETF_SHIFT 25u -#define TX_ITBSTATUS_CSREQ_MASK 0x04000000u -#define TX_ITBSTATUS_CSREQ_SHIFT 26u -#define TX_ITBSTATUS_ULBW_MASK 0x18000000u -#define TX_ITBSTATUS_ULBW_SHIFT 27u -#define TX_ITBSTATUS_GI_LTF_MASK 0x60000000u -#define TX_ITBSTATUS_GI_LTF_SHIFT 29u -#define TX_ITBSTATUS_MUMIMO_LTF_MASK 0x80000000u -#define TX_ITBSTATUS_MUMIMO_LTF_SHIFT 30u -/* Fourth uint32 (words 6 and 7) */ -#define TX_ITBSTATUS_CODING_TYPE_MASK 0x00000001u -#define TX_ITBSTATUS_CODING_TYPE_SHIFT 0u -#define TX_ITBSTATUS_MCS_MASK 0x0000001eu -#define TX_ITBSTATUS_MCS_SHIFT 1u -#define TX_ITBSTATUS_DCM_MASK 0x00000020u -#define TX_ITBSTATUS_DCM_SHIFT 5u -#define TX_ITBSTATUS_RU_ALLOC_MASK 0x00003fc0u -#define TX_ITBSTATUS_RU_ALLOC_SHIFT 6u -/* Bits 14 and 15 unassigned */ -#define TX_ITBSTATUS_NSS_MASK 0x00030000u -#define TX_ITBSTATUS_NSS_SHIFT 16u -#define TX_ITBSTATUS_TARGET_RSSI_MASK 0x03fc0000u -#define TX_ITBSTATUS_TARGET_RSSI_SHIFT 18u -#define TX_ITBSTATUS_RA_RU_MASK 0x04000000u -#define TX_ITBSTATUS_RA_RU_SHIFT 26u -/* Bits 27 through 31 unassigned */ -/* End of intermediate TBPPDU txstatus definitions */ - -/* MU group info txstatus field (s3 b[31:16]) */ -#define TX_STATUS64_MU_GID_MASK 0x003f0000u -#define TX_STATUS64_MU_GID_SHIFT 16u -#define TX_STATUS64_MU_BW_MASK 0x00c00000u -#define TX_STATUS64_MU_BW_SHIFT 22u -#define TX_STATUS64_MU_TXPWR_MASK 0x7f000000u -#define TX_STATUS64_MU_TXPWR_SHIFT 24u -#define TX_STATUS64_MU_SGI_MASK 0x80000080u -#define TX_STATUS64_MU_SGI_SHIFT 31u -#define TX_STATUS64_INTERM_MUTXCNT(s3) \ - ((s3 & TX_STATUS40_TXCNT_RATE0_MASK) >> TX_STATUS40_TXCNT_RATE0_SHIFT) - -#define TX_STATUS64_MU_GID(s3) ((s3 & TX_STATUS64_MU_GID_MASK) >> TX_STATUS64_MU_GID_SHIFT) -#define TX_STATUS64_MU_BW(s3) ((s3 & TX_STATUS64_MU_BW_MASK) >> TX_STATUS64_MU_BW_SHIFT) -#define TX_STATUS64_MU_TXPWR(s3) ((s3 & TX_STATUS64_MU_TXPWR_MASK) >> TX_STATUS64_MU_TXPWR_SHIFT) -#define TX_STATUS64_MU_SGI(s3) ((s3 & TX_STATUS64_MU_SGI_MASK) >> TX_STATUS64_MU_SGI_SHIFT) - -/* MU user info0 txstatus field (s4 b[15:0]) */ -#define TX_STATUS64_MU_MCS_MASK 0x0000000f -#define TX_STATUS64_MU_MCS_SHIFT 0 -#define TX_STATUS64_MU_NSS_MASK 0x00000070 -#define TX_STATUS64_MU_NSS_SHIFT 4 -#define TX_STATUS64_MU_SNR_MASK 0x0000ff00 -#define TX_STATUS64_MU_SNR_SHIFT 8 - -#define TX_STATUS64_MU_MCS(s4) ((s4 & TX_STATUS64_MU_MCS_MASK) >> TX_STATUS64_MU_MCS_SHIFT) -#define TX_STATUS64_MU_NSS(s4) ((s4 & TX_STATUS64_MU_NSS_MASK) >> TX_STATUS64_MU_NSS_SHIFT) -#define TX_STATUS64_MU_SNR(s4) ((s4 & TX_STATUS64_MU_SNR_MASK) >> TX_STATUS64_MU_SNR_SHIFT) - -/* MU txstatus rspec field (NSS | MCS) */ -#define TX_STATUS64_MU_RSPEC_MASK (TX_STATUS64_MU_NSS_MASK | TX_STATUS64_MU_MCS_MASK) -#define TX_STATUS64_MU_RSPEC_SHIFT 0 - -#define TX_STATUS64_MU_RSPEC(s4) ((s4 & TX_STATUS64_MU_RSPEC_MASK) >> TX_STATUS64_MU_RSPEC_SHIFT) - -/* MU user info0 txstatus field (s4 b[31:16]) */ -#define TX_STATUS64_MU_GBMP_MASK 0x000f0000 -#define TX_STATUS64_MU_GBMP_SHIFT 16 -#define TX_STATUS64_MU_GPOS_MASK 0x00300000 -#define TX_STATUS64_MU_GPOS_SHIFT 20 -#define TX_STATUS64_MU_TXCNT_MASK 0x0fc00000 -#define TX_STATUS64_MU_TXCNT_SHIFT 22 - -#define TX_STATUS64_MU_GBMP(s4) ((s4 & TX_STATUS64_MU_GBMP_MASK) >> TX_STATUS64_MU_GBMP_SHIFT) -#define TX_STATUS64_MU_GPOS(s4) ((s4 & TX_STATUS64_MU_GPOS_MASK) >> TX_STATUS64_MU_GPOS_SHIFT) -#define TX_STATUS64_MU_TXCNT(s4) ((s4 & TX_STATUS64_MU_TXCNT_MASK) >> TX_STATUS64_MU_TXCNT_SHIFT) - -#define HE_MU_APTX_PWR_MAX 60u -#define HE_TXS_MU_APTX_PWR_DBM(aptx_pwr) ((aptx_pwr) - 20u) - -#define HE_TXS_MU_TARGET_RSSI_RANG 90 -#define HE_TXS_MU_TARGET_RSSI_MAX_PWR 127 -#define HE_TXS_MU_TARGET_RSSI_DBM(rssi) ((rssi) - 110) - -#define HE_TXS_W4_MU_GET_RU_INDEX(index) ((index <= HE_MAX_26_TONE_RU_INDX) ? 0u : \ - ((index) <= HE_MAX_52_TONE_RU_INDX) ? 1u : \ - ((index) <= HE_MAX_106_TONE_RU_INDX) ? 2u : \ - ((index) <= HE_MAX_242_TONE_RU_INDX) ? 3u : \ - ((index) <= HE_MAX_484_TONE_RU_INDX) ? 4u :\ - ((index) <= HE_MAX_996_TONE_RU_INDX) ? 5u : 6u) - -/* Bit 8 indicates upper 80 MHz */ -#define HE_TXS_W4_MU_RU_INDEX_RU_INDEX_MASK 0x7Fu -#define HE_TXS_W4_MU_RU_INDEX_TONE(index) HE_TXS_W4_MU_GET_RU_INDEX(((index) & \ - HE_TXS_W4_MU_RU_INDEX_RU_INDEX_MASK)) - -#define HE_TXS_W3_MU_APTX_PWR_MASK 0x003F0000u -#define HE_TXS_W3_MU_APTX_PWR_SHIFT 16u -#define HE_TXS_W3_MU_PKT_EXT_MASK 0x01C00000u -#define HE_TXS_W3_MU_PKT_EXT_SHIFT 22u -#define HE_TXS_W3_MU_MORE_TF_MASK 0x02000000u -#define HE_TXS_W3_MU_MORE_TF_SHIFT 25u -#define HE_TXS_W3_MU_CS_REQ_MASK 0x04000000u -#define HE_TXS_W3_MU_CS_REQ_SHIFT 26u -#define HE_TXS_W3_MU_UL_BW_MASK 0x18000000u -#define HE_TXS_W3_MU_UL_BW_SHIFT 27u -#define HE_TXS_W3_MU_GI_LTF_MASK 0x60000000u -#define HE_TXS_W3_MU_GI_LTF_SHIFT 29u -#define HE_TXS_W3_MU_MIMO_LTF_MASK 0x80000000u -#define HE_TXS_W3_MU_MIMO_LTF_SHIFT 31u - -#define HE_TXS_W3_MU_APTX_PWR(s3) (((s3) & HE_TXS_W3_MU_APTX_PWR_MASK) >> \ - HE_TXS_W3_MU_APTX_PWR_SHIFT) -#define HE_TXS_W3_MU_PKT_EXT(s3) (((s3) & HE_TXS_W3_MU_PKT_EXT_MASK) >> \ - HE_TXS_W3_MU_PKT_EXT_SHIFT) -#define HE_TXS_W3_MU_MORE_TF(s3) (((s3) & HE_TXS_W3_MU_MORE_TF_MASK) >> \ - HE_TXS_W3_MU_MORE_TF_SHIFT) -#define HE_TXS_W3_MU_CS_REQ(s3) (((s3) & HE_TXS_W3_MU_CS_REQ_MASK) >> \ - HE_TXS_W3_MU_CS_REQ_SHIFT) -#define HE_TXS_W3_MU_UL_BW(s3) (((s3) & HE_TXS_W3_MU_UL_BW_MASK) >> \ - HE_TXS_W3_MU_UL_BW_SHIFT) -#define HE_TXS_W3_MU_GI_LTF(s3) (((s3) & HE_TXS_W3_MU_GI_LTF_MASK) >> \ - HE_TXS_W3_MU_GI_LTF_SHIFT) -#define HE_TXS_W3_MU_MIMO_LT(s3) (((s3) & HE_TXS_W3_MU_MIMO_LTF_MASK) >> \ - HE_TXS_W3_MU_MIMO_LTF_SHIFT) - -#define HE_TXS_W4_MU_CODINF_TYPE_MASK 0x00000001u -#define HE_TXS_W4_MU_CODINF_TYPE_SHIFT 0u -#define HE_TXS_W4_MU_MCS_MASK 0x0000001Eu -#define HE_TXS_W4_MU_MCS_SHIFT 1u -#define HE_TXS_W4_MU_DCM_MASK 0x00000020u -#define HE_TXS_W4_MU_DCM_SHIFT 5u -#define HE_TXS_W4_RU_ALLOCATION_MASK 0x00003FC0u -#define HE_TXS_W4_RU_ALLOCATION_SHIFT 6u - -#define HE_TXS_W4_MU_CODINF_TYPE(s4) (((s4) & HE_TXS_W4_MU_CODINF_TYPE_MASK) >> \ - HE_TXS_W4_MU_CODINF_TYPE_SHIFT) -#define HE_TXS_W4_MU_MCS(s4) (((s4) & HE_TXS_W4_MU_MCS_MASK) >> \ - HE_TXS_W4_MU_MCS_SHIFT) -#define HE_TXS_W4_MU_DCM(s4) (((s4) & HE_TXS_W4_MU_DCM_MASK) >> \ - HE_TXS_W4_MU_DCM_SHIFT) -#define HE_TXS_W4_RU_ALLOCATION(s4) (((s4) & HE_TXS_W4_RU_ALLOCATION_MASK) >> \ - HE_TXS_W4_RU_ALLOCATION_SHIFT) - -#define HE_TXS_W4_MU_NSS_MASK 0x00030000u -#define HE_TXS_W4_MU_NSS_SHIFT 16u -#define HE_TXS_W4_MU_TARGET_RSSI_MASK 0x03FC0000u -#define HE_TXS_W4_MU_TARGET_RSSI_SHIFT 18u - -#define HE_TXS_W4_MU_NSS(s4) (((s4) & HE_TXS_W4_MU_NSS_MASK) >> \ - HE_TXS_W4_MU_NSS_SHIFT) -#define HE_TXS_W4_MU_TARGET_RSSI(s4) (((s4) & HE_TXS_W4_MU_TARGET_RSSI_MASK) >> \ - HE_TXS_W4_MU_TARGET_RSSI_SHIFT) - -/* WARNING: Modifying suppress reason codes? - * Update wlc_tx_status_t and TX_STS_REASON_STRINGS and - * wlc_tx_status_map_hw_to_sw_supr_code() also - */ -/* status field bit definitions */ -/** suppress status reason codes */ -enum { - TX_STATUS_SUPR_NONE = 0, - TX_STATUS_SUPR_PMQ = 1, /**< PMQ entry */ - TX_STATUS_SUPR_FLUSH = 2, /**< flush request */ - TX_STATUS_SUPR_FRAG = 3, /**< previous frag failure */ - TX_STATUS_SUPR_TBTT = 3, /**< SHARED: Probe response supr for TBTT */ - TX_STATUS_SUPR_BADCH = 4, /**< channel mismatch */ - TX_STATUS_SUPR_EXPTIME = 5, /**< lifetime expiry */ - TX_STATUS_SUPR_UF = 6, /**< underflow */ -#ifdef WLP2P_UCODE - TX_STATUS_SUPR_NACK_ABS = 7, /**< BSS entered ABSENCE period */ -#endif - TX_STATUS_SUPR_PPS = 8, /**< Pretend PS */ - TX_STATUS_SUPR_PHASE1_KEY = 9, /**< Request new TKIP phase-1 key */ - TX_STATUS_UNUSED = 10, /**< Unused in trunk */ - TX_STATUS_INT_XFER_ERR = 11, /**< Internal DMA xfer error */ - TX_STATUS_SUPR_TWT_SP_OUT = 12, /**< Suppress Tx outside TWTSP */ - NUM_TX_STATUS_SUPR -}; - -/** Unexpected tx status for rate update */ -#define TX_STATUS_UNEXP(status) \ - ((((status.is_intermediate))) && \ - TX_STATUS_UNEXP_AMPDU(status)) - -/** Unexpected tx status for A-MPDU rate update */ -#ifdef WLP2P_UCODE -#define TX_STATUS_UNEXP_AMPDU(status) \ - ((((status.suppr_ind)) != TX_STATUS_SUPR_NONE) && \ - (((status.suppr_ind)) != TX_STATUS_SUPR_EXPTIME) && \ - (((status.suppr_ind)) != TX_STATUS_SUPR_NACK_ABS)) -#else -#define TX_STATUS_UNEXP_AMPDU(status) \ - ((((status.suppr_ind)) != TX_STATUS_SUPR_NONE) && \ - (((status.suppr_ind)) != TX_STATUS_SUPR_EXPTIME)) -#endif - -/** - * This defines the collection of supp reasons (including none) - * for which mac has done its (re-)transmission in any of ucode retx schemes - * which include ucode/hw/aqm agg - */ -#define TXS_SUPR_MAGG_DONE_MASK ((1 << TX_STATUS_SUPR_NONE) | \ - (1 << TX_STATUS_SUPR_UF) | \ - (1 << TX_STATUS_SUPR_FRAG) | \ - (1 << TX_STATUS_SUPR_EXPTIME)) -#define TXS_SUPR_MAGG_DONE(suppr_ind) \ - ((1 << (suppr_ind)) & TXS_SUPR_MAGG_DONE_MASK) - -#define TX_STATUS_BA_BMAP03_MASK 0xF000 /**< ba bitmap 0:3 in 1st pkg */ -#define TX_STATUS_BA_BMAP03_SHIFT 12 /**< ba bitmap 0:3 in 1st pkg */ -#define TX_STATUS_BA_BMAP47_MASK 0x001E /**< ba bitmap 4:7 in 2nd pkg */ -#define TX_STATUS_BA_BMAP47_SHIFT 3 /**< ba bitmap 4:7 in 2nd pkg */ - -/* RXE (Receive Engine) */ - -/* RCM_CTL */ -#define RCM_INC_MASK_H 0x0080 -#define RCM_INC_MASK_L 0x0040 -#define RCM_INC_DATA 0x0020 -#define RCM_INDEX_MASK 0x001F -#define RCM_SIZE 15 - -#define RCM_MAC_OFFSET 0 /**< current MAC address */ -#define RCM_BSSID_OFFSET 3 /**< current BSSID address */ -#define RCM_F_BSSID_0_OFFSET 6 /**< foreign BSS CFP tracking */ -#define RCM_F_BSSID_1_OFFSET 9 /**< foreign BSS CFP tracking */ -#define RCM_F_BSSID_2_OFFSET 12 /**< foreign BSS CFP tracking */ - -#define RCM_WEP_TA0_OFFSET 16 -#define RCM_WEP_TA1_OFFSET 19 -#define RCM_WEP_TA2_OFFSET 22 -#define RCM_WEP_TA3_OFFSET 25 - -/* AMT - Address Match Table */ - -/* AMT Attribute bits */ -#define AMT_ATTR_VALID 0x8000 /**< Mark the table entry valid */ -#define AMT_ATTR_A1 0x0008 /**< Match for A1 */ -#define AMT_ATTR_A2 0x0004 /**< Match for A2 */ -#define AMT_ATTR_A3 0x0002 /**< Match for A3 */ - -/* AMT Index defines */ -#define AMT_SIZE_64 64 /* number of AMT entries */ -#define AMT_SIZE_128 128 /* number of AMT entries for corerev >= 64 */ -#define AMT_IDX_MAC 63 /**< device MAC */ -#define AMT_IDX_BSSID 62 /**< BSSID match */ -#define AMT_IDX_TRANSMITTED_BSSID 60 /**< transmitted BSSID in multiple BSSID set */ -#define AMT_WORD_CNT 2 /* Number of word count per AMT entry */ - -#define AMT_SIZE(_corerev) (D11REV_GE(_corerev, 64) ? \ - (D11REV_GE(_corerev, 80) ? AMT_SIZE_64 : AMT_SIZE_128) : \ - AMT_SIZE_64) - -/* RMC entries */ -#define AMT_IDX_MCAST_ADDR 61 /**< MCAST address for Reliable Mcast feature */ -#define AMT_IDX_MCAST_ADDR1 59 /**< MCAST address for Reliable Mcast feature */ -#define AMT_IDX_MCAST_ADDR2 58 /**< MCAST address for Reliable Mcast feature */ -#define AMT_IDX_MCAST_ADDR3 57 /**< MCAST address for Reliable Mcast feature */ - -#ifdef WLMESH -/* note: this is max supported by ucode. But ARM-driver can - * only mesh_info->mesh_max_peers which should be <= this value. - */ - -#define AMT_MAX_MESH_PEER 10 -#define AMT_MAXIDX_MESH_PEER 60 -#define AMT_MAXIDX_P2P_USE \ - (AMT_MAXIDX_MESH_PEER - AMT_MAX_MESH_PEER) -#else -#define AMT_MAXIDX_P2P_USE 60 /**< Max P2P entry to use */ -#endif /* WL_STA_MONITOR */ -#define AMT_MAX_TXBF_ENTRIES 7 /**< Max tx beamforming entry */ -/* PSTA AWARE AP: Max PSTA Tx beamforming entry */ -#define AMT_MAX_TXBF_PSTA_ENTRIES 20 - -/* M_AMT_INFO SHM bit field definition */ -#define AMTINFO_BMP_IBSS (1u << 0u) /* IBSS Station */ -#define AMTINFO_BMP_MESH (1u << 1u) /* MESH Station */ -#define AMTINFO_BMP_BSSID (1u << 2u) /* BSSID-only */ -#define AMTINFO_BMP_IS_WAPI (1u << 3u) /* For WAPI keyid extraction */ -#define AMTINFO_BMP_IS_HE (1u << 13u) /* For HE peer indication */ - -#define AUXPMQ_ENTRIES 64 /* number of AUX PMQ entries */ -#define AUXPMQ_ENTRY_SIZE 8 - -/* PSM Block */ - -/* psm_phy_hdr_param bits */ -#define MAC_PHY_RESET 1 -#define MAC_PHY_CLOCK_EN 2 -#define MAC_PHY_FORCE_CLK 4 -#define MAC_IHRP_CLOCK_EN 15 - -/* PSMCoreControlStatus (IHR Address 0x078) bit definitions */ -#define PSM_CORE_CTL_AR (1 << 0) -#define PSM_CORE_CTL_HR (1 << 1) -#define PSM_CORE_CTL_IR (1 << 2) -#define PSM_CORE_CTL_AAR (1 << 3) -#define PSM_CORE_CTL_HAR (1 << 4) -#define PSM_CORE_CTL_PPAR (1 << 5) -#define PSM_CORE_CTL_SS (1 << 6) -#define PSM_CORE_CTL_REHE (1 << 7) -#define PSM_CORE_CTL_PPAS (1 << 13) -#define PSM_CORE_CTL_AAS (1 << 14) -#define PSM_CORE_CTL_HAS (1 << 15) - -#define PSM_CORE_CTL_LTR_BIT 9 -#define PSM_CORE_CTL_LTR_MASK 0x3 - -#define PSM_SBACCESS_FIFO_MODE (1 << 1) -#define PSM_SBACCESS_EXT_ERR (1 << 11) - -/* WEP Block */ - -/* WEP_WKEY */ -#define WKEY_START (1 << 8) -#define WKEY_SEL_MASK 0x1F - -/* WEP data formats */ - -/* the number of RCMTA entries */ -#define RCMTA_SIZE 50 - -/* max keys in M_TKMICKEYS_BLK - 96 * sizeof(uint16) */ -#define WSEC_MAX_TKMIC_ENGINE_KEYS(_corerev) ((D11REV_GE(_corerev, 64)) ? \ - AMT_SIZE(_corerev) : 12) /* 8 + 4 default - 2 mic keys 8 bytes each */ - -/* max keys in M_WAPIMICKEYS_BLK - 64 * sizeof(uint16) */ -#define WSEC_MAX_SMS4MIC_ENGINE_KEYS(_corerev) ((D11REV_GE(_corerev, 64)) ? \ - AMT_SIZE(_corerev) : 8) /* 4 + 4 default - 16 bytes each */ - -/* max RXE match registers */ -#define WSEC_MAX_RXE_KEYS 4 - -/* SECKINDXALGO (Security Key Index & Algorithm Block) word format */ -/* SKL (Security Key Lookup) */ -#define SKL_POST80_ALGO_MASK 0x000F -#define SKL_PRE80_ALGO_MASK 0x0007 -#define SKL_ALGO_SHIFT 0 - -#define SKL_ALGO_MASK(_corerev) (D11REV_GE(_corerev, 80) ? SKL_POST80_ALGO_MASK : \ - SKL_PRE80_ALGO_MASK) - -#define SKL_WAPI_KEYID_MASK 0x8000 -#define SKL_WAPI_KEYID_SHIFT 15 -#define SKL_INDEX_SHIFT 4 - -#define SKL_PRE80_WAPI_KEYID_MASK 0x0008 -#define SKL_PRE80_WAPI_KEYID_SHIFT 3 - -#define SKL_INDEX_MASK(_corerev) ((D11REV_GE(_corerev, 64)) ? \ - (0x0FF0) : (0x03F0)) -#define SKL_GRP_ALGO_MASK(_corerev) ((D11REV_GE(_corerev, 64)) ? \ - ((D11REV_GE(_corerev, 80)) ? (0xE000) : (0x7000)) : (0x1c00)) -#define SKL_GRP_ALGO_SHIFT(_corerev) ((D11REV_GE(_corerev, 64)) ? \ - ((D11REV_GE(_corerev, 80)) ? (13) : (12)) : (10)) - -#define SKL_STAMON_NBIT 0x8000 /* STA monitor bit */ - -/* additional bits defined for IBSS group key support */ -#define SKL_IBSS_INDEX_MASK 0x01F0 -#define SKL_IBSS_INDEX_SHIFT 4 -#define SKL_IBSS_KEYID1_MASK 0x0600 -#define SKL_IBSS_KEYID1_SHIFT 9 -#define SKL_IBSS_KEYID2_MASK 0x1800 -#define SKL_IBSS_KEYID2_SHIFT 11 -#define SKL_IBSS_KEYALGO_MASK 0xE000 -#define SKL_IBSS_KEYALGO_SHIFT 13 - -#define WSEC_MODE_OFF 0 -#define WSEC_MODE_HW 1 -#define WSEC_MODE_SW 2 - -/* Mapped as per HW_ALGO */ -#define WSEC_ALGO_OFF 0 -#define WSEC_ALGO_WEP1 1 -#define WSEC_ALGO_TKIP 2 -#define WSEC_ALGO_WEP128 3 -#define WSEC_ALGO_AES_LEGACY 4 -#define WSEC_ALGO_AES 5 -#define WSEC_ALGO_SMS4 6 -#define WSEC_ALGO_SMS4_DFT_2005_09_07 7 /**< Not used right now */ -#define WSEC_ALGO_NALG 8 - -/* For CORE_REV 80 */ -#define WSEC_ALGO_AES_GCM 8 -#define WSEC_ALGO_AES_GCM256 9 - -/* For CORE_REV Less than 80 and */ -#define WSEC_ALGO_AES_PRE80_GCM 6 -#define WSEC_ALGO_AES_PRE80_GCM256 8 - -/* D11 MAX TTAK INDEX */ -#define TSC_TTAK_PRE80_MAX_INDEX 50 -#define TSC_TTAK_MAX_INDEX 8 -/* D11 COREREV 80 TTAK KEY INDEX SHIFT */ -#define SKL_TTAK_INDEX_SHIFT 13 -#define SKL_TTAK_INDEX_MASK 0xE000 - -/* D11 PRECOREREV 40 Hw algos...changed from corerev 40 */ -#define D11_PRE40_WSEC_ALGO_AES 3 -#define D11_PRE40_WSEC_ALGO_WEP128 4 -#define D11_PRE40_WSEC_ALGO_AES_LEGACY 5 -#define D11_PRE40_WSEC_ALGO_SMS4 6 -#define D11_PRE40_WSEC_ALGO_NALG 7 - -#define D11_WSEC_ALGO_AES(_corerev) WSEC_ALGO_AES - -#define AES_MODE_NONE 0 -#define AES_MODE_CCM 1 -#define AES_MODE_OCB_MSDU 2 -#define AES_MODE_OCB_MPDU 3 -#define AES_MODE_CMAC 4 -#define AES_MODE_GCM 5 -#define AES_MODE_GMAC 6 - -/* WEP_CTL (Rev 0) */ -#define WECR0_KEYREG_SHIFT 0 -#define WECR0_KEYREG_MASK 0x7 -#define WECR0_DECRYPT (1 << 3) -#define WECR0_IVINLINE (1 << 4) -#define WECR0_WEPALG_SHIFT 5 -#define WECR0_WEPALG_MASK (0x7 << 5) -#define WECR0_WKEYSEL_SHIFT 8 -#define WECR0_WKEYSEL_MASK (0x7 << 8) -#define WECR0_WKEYSTART (1 << 11) -#define WECR0_WEPINIT (1 << 14) -#define WECR0_ICVERR (1 << 15) - -/* Frame template map byte offsets */ -#define T_ACTS_TPL_BASE (0) -#define T_NULL_TPL_BASE (0xc * 2) -#define T_QNULL_TPL_BASE (0x1c * 2) -#define T_RR_TPL_BASE (0x2c * 2) -#define T_BCN0_TPL_BASE (0x34 * 2) -#define T_PRS_TPL_BASE (0x134 * 2) -#define T_BCN1_TPL_BASE (0x234 * 2) -#define T_P2P_NULL_TPL_BASE (0x340 * 2) -#define T_P2P_NULL_TPL_SIZE (32) -#define T_TRIG_TPL_BASE (0x90 * 2) - -/* FCBS base addresses and sizes in BM */ - -#define FCBS_DS0_BM_CMD_SZ_CORE0 0x0200 /* 512 bytes */ -#define FCBS_DS0_BM_DAT_SZ_CORE0 0x0200 /* 512 bytes */ - -#ifndef FCBS_DS0_BM_CMDPTR_BASE_CORE0 -#define FCBS_DS0_BM_CMDPTR_BASE_CORE0 0x3000 -#endif -#define FCBS_DS0_BM_DATPTR_BASE_CORE0 (FCBS_DS0_BM_CMDPTR_BASE_CORE0 + FCBS_DS0_BM_CMD_SZ_CORE0) - -#define FCBS_DS0_BM_CMD_SZ_CORE1 0x0200 /* 512 bytes */ -#define FCBS_DS0_BM_DAT_SZ_CORE1 0x0200 /* 512 bytes */ - -#ifndef FCBS_DS0_BM_CMDPTR_BASE_CORE1 -#define FCBS_DS0_BM_CMDPTR_BASE_CORE1 0x2400 -#endif -#define FCBS_DS0_BM_DATPTR_BASE_CORE1 (FCBS_DS0_BM_CMDPTR_BASE_CORE1 + FCBS_DS0_BM_CMD_SZ_CORE1) - -#define FCBS_DS0_BM_CMD_SZ_CORE2 0x0200 /* 512 bytes */ -#define FCBS_DS0_BM_DAT_SZ_CORE2 0x0200 /* 512 bytes */ - -#define FCBS_DS1_BM_CMD_SZ_CORE0 0x2000 /* Not used */ -#define FCBS_DS1_BM_DAT_SZ_CORE0 0x2000 /* Not used */ - -#define FCBS_DS1_BM_CMDPTR_BASE_CORE0 0x17B4 -#define FCBS_DS1_BM_DATPTR_BASE_CORE0 (FCBS_DS1_BM_CMDPTR_BASE_CORE0 + FCBS_DS1_BM_CMD_SZ_CORE0) - -#define FCBS_DS1_BM_CMD_SZ_CORE1 0x2000 /* Not used */ -#define FCBS_DS1_BM_DAT_SZ_CORE1 0x2000 /* Not used */ - -#define FCBS_DS1_BM_CMDPTR_BASE_CORE1 0x17B4 -#define FCBS_DS1_BM_DATPTR_BASE_CORE1 (FCBS_DS1_BM_CMDPTR_BASE_CORE1 + FCBS_DS1_BM_CMD_SZ_CORE1) - -#define T_BA_TPL_BASE T_QNULL_TPL_BASE /**< template area for BA */ - -#define T_RAM_ACCESS_SZ 4 /**< template ram is 4 byte access only */ - -#define TPLBLKS_PER_BCN_NUM 2 -#define TPLBLKS_AC_PER_BCN_NUM 1 - -#if defined(WLLPRS) && defined(MBSS) -#define TPLBLKS_PER_PRS_NUM 4 -#define TPLBLKS_AC_PER_PRS_NUM 2 -#else -#define TPLBLKS_PER_PRS_NUM 2 -#define TPLBLKS_AC_PER_PRS_NUM 1 -#endif /* WLLPRS && MBSS */ - -/* MAC Sample Collect Params */ - -/* SampleCapture set-up options in - * different registers based on CoreRev - */ -/* CoreRev >= 50, use SMP_CTRL in TXE_IHR */ -#define SC_SRC_MAC 2 /* MAC as Sample Collect Src */ -#define SC_SRC_SHIFT 3 /* SC_SRC bits [3:4] */ -#define SC_TRIG_SHIFT 5 -#define SC_TRANS_SHIFT 6 -#define SC_MATCH_SHIFT 7 -#define SC_STORE_SHIFT 8 - -#define SC_STRT 1 -#define SC_TRIG_EN (1 << SC_TRIG_SHIFT) -#define SC_TRANS_EN (1 << SC_TRANS_SHIFT) -#define SC_MATCH_EN (1 << SC_MATCH_SHIFT) -#define SC_STORE_EN (1 << SC_STORE_SHIFT) - -/* CoreRev < 50, use PHY_CTL in PSM_IHR */ -#define PHYCTL_PHYCLKEN (1 << 1) -#define PHYCTL_FORCE_GATED_CLK_ON (1 << 2) -#define PHYCTL_SC_STRT (1 << 4) -#define PHYCTL_SC_SRC_LB (1 << 7) -#define PHYCTL_SC_TRIG_EN (1 << 8) -#define PHYCTL_SC_TRANS_EN (1 << 9) -#define PHYCTL_SC_STR_EN (1 << 10) -#define PHYCTL_IHRP_CLK_EN (1 << 15) -/* End MAC Sample Collect Params */ - -#define ANTSEL_CLKDIV_4MHZ 6 -#define MIMO_ANTSEL_BUSY 0x4000 /**< bit 14 (busy) */ -#define MIMO_ANTSEL_SEL 0x8000 /**< bit 15 write the value */ -#define MIMO_ANTSEL_WAIT 50 /**< 50us wait */ -#define MIMO_ANTSEL_OVERRIDE 0x8000 /**< flag */ - -typedef struct shm_acparams shm_acparams_t; -BWL_PRE_PACKED_STRUCT struct shm_acparams { - uint16 txop; - uint16 cwmin; - uint16 cwmax; - uint16 cwcur; - uint16 aifs; - uint16 bslots; - uint16 reggap; - uint16 status; - uint16 txcnt; - uint16 rsvd[7]; -} BWL_POST_PACKED_STRUCT; - -#define WME_STATUS_NEWAC (1 << 8) - -/* M_HOST_FLAGS */ -#define MHFMAX 5 /* Number of valid hostflag half-word (uint16) */ -#define MHF1 0 /* Hostflag 1 index */ -#define MHF2 1 /* Hostflag 2 index */ -#define MHF3 2 /* Hostflag 3 index */ -#define MHF4 3 /* Hostflag 4 index */ -#define MHF5 4 /* Hostflag 5 index */ - -#define MXHFMAX 1 /* Number of valid PSMx hostflag half-word (uint16) */ -#define MXHF0 64 /* PSMx Hostflag 0 index */ - -/* Flags in M_HOST_FLAGS */ -#define MHF1_D11AC_DYNBW 0x0001 /**< dynamic bw */ -#define MHF1_WLAN_CRITICAL 0x0002 /**< WLAN is in critical state */ -#define MHF1_MBSS_EN 0x0004 /**< Enable MBSS: RXPUWAR deprecated for rev >= 9 */ -#define MHF1_BTCOEXIST 0x0010 /**< Enable Bluetooth / WLAN coexistence */ -#define MHF1_P2P_SKIP_TIME_UPD 0x0020 /**< Skip P2P SHM updates and P2P event generations */ -#define MHF1_TXMUTE_WAR 0x0040 /**< ucode based Tx mute */ -#define MHF1_RXFIFO1 0x0080 /**< Switch data reception from RX fifo 0 to fifo 1 */ -#define MHF1_EDCF 0x0100 /**< Enable EDCF access control */ -#define MHF1_ULP 0x0200 /**< Force Ucode to put chip in low power state */ -#define MHF1_FORCE_SEND_BCN 0x0800 /**< Force send bcn, even if rcvd from peer STA (IBSS) */ -#define MHF1_TIMBC_EN 0x1000 /**< Enable Target TIM Transmission Time function */ -#define MHF1_RADARWAR 0x2000 /**< Enable Radar Detect WAR PR 16559 */ -#define MHF1_DEFKEYVALID 0x4000 /**< Enable use of the default keys */ -#define MHF1_CTS2SELF 0x8000 /**< Enable CTS to self full phy bw protection */ - -/* Flags in M_HOST_FLAGS2 */ -#define MHF2_DISABLE_PRB_RESP 0x0001 /**< disable Probe Response in ucode */ -#define MHF2_HIB_FEATURE_ENABLE 0x0008 /* Enable HIB feature in ucode (60<=rev<80) */ -#define MHF2_SKIP_ADJTSF 0x0010 /**< skip TSF update when receiving bcn/probeRsp */ -#define MHF2_RSPBW20 0x0020 /**< Uses bw20 for response frames ack/ba/cts */ -#define MHF2_TXBCMC_NOW 0x0040 /**< Flush BCMC FIFO immediately */ -#define MHF2_PPR_HWPWRCTL 0x0080 /**< TSSI_DIV WAR (rev<80) */ -#define MHF2_BTC2WIRE_ALTGPIO 0x0100 /**< BTC 2wire in alternate pins */ -#define MHF2_BTCPREMPT 0x0200 /**< BTC enable bluetooth check during tx */ -#define MHF2_SKIP_CFP_UPDATE 0x0400 /**< Skip CFP update ; for d11 rev <= 80 */ -#define MHF2_TX_TMSTMP 0x0800 /**< Enable passing tx-timestamps in tx-status */ -#define MHF2_UFC_GE84 0x2000 /**< Enable UFC in CT mode */ -#define MHF2_NAV_NORST_WAR 0x4000 /**< WAR to use rogue NAV duration */ -#define MHF2_BTCANTMODE 0x4000 // OBSOLETE (TO BE REMOVED) - -/* Flags in M_HOST_FLAGS3 */ -#define MHF3_ANTSEL_EN 0x0001 /**< enabled mimo antenna selection (REV<80) */ -#define MHF3_TKIP_FRAG_WAR 0x0001 /**< TKIP fragment corrupt WAR (REV>=80) */ -#define MHF3_TXSHAPER_EN 0x0002 /** enable tx shaper for non-OFDM-A frames */ -#define MHF3_ANTSEL_MODE 0x0002 /**< antenna selection mode: 0: 2x3, 1: 2x4 (REV<80) */ -#define MHF3_BTCX_DEF_BT 0x0004 /**< corerev >= 13 BT Coex. */ -#define MHF3_BTCX_ACTIVE_PROT 0x0008 /**< corerev >= 13 BT Coex. */ -#define MHF3_PKTENG_PROMISC 0x0010 /**< pass frames to driver in packet engine Rx mode */ -#define MHF3_SCANCORE_PM_EN 0x0040 /**< enable ScanCore PM from ucode */ -#define MHF3_PM_BCNRX 0x0080 /**< PM single core beacon RX for power reduction */ -#define MHF3_BTCX_SIM_RSP 0x0100 /**< allow limited lwo power tx when BT is active */ -#define MHF3_BTCX_PS_PROTECT 0x0200 /**< use PS mode to protect BT activity */ -#define MHF3_BTCX_SIM_TX_LP 0x0400 /**< use low power for simultaneous tx responses */ -#define MHF3_SELECT_RXF1 0x0800 /**< enable frame classification in pcie FD */ -#define MHF3_BTCX_ECI 0x1000 /**< Enable BTCX ECI interface */ -#define MHF3_NOISECAL_ENHANCE 0x2000 - -/* Flags in M_HOST_FLAGS4 */ -#define MHF4_RCMTA_BSSID_EN 0x0002 /**< BTAMP: multiSta BSSIDs matching in RCMTA area */ -#define MHF4_SC_MIX_EN 0x0002 /**< set to enable 4389a0 specific changes */ -#define MHF4_BCN_ROT_RR 0x0004 /**< MBSSID: beacon rotate in round-robin fashion */ -#define MHF4_OPT_SLEEP 0x0008 /**< enable opportunistic sleep (REV<80) */ -#define MHF4_PM_OFFLOAD 0x0008 /**< enable PM offload */ -#define MHF4_PROXY_STA 0x0010 /**< enable proxy-STA feature */ -#define MHF4_AGING 0x0020 /**< Enable aging threshold for RF awareness */ -#define MHF4_STOP_BA_ON_NDP 0x0080 /**< Stop BlockAck to AP to get chance to send NULL data */ -#define MHF4_NOPHYHANGWAR 0x0100 /**< disable ucode WAR for idletssi cal (rev=61) */ -#define MHF4_WMAC_ACKTMOUT 0x0200 /**< reserved for WMAC testing */ -#define MHF4_NAPPING_ENABLE 0x0400 /**< Napping enable (REV<80) */ -#define MHF4_IBSS_SEC 0x0800 /**< IBSS WPA2-PSK operating mode */ -#define MHF4_SISO_BCMC_RX 0x1000 /* Disable switch to MIMO on recving multicast TIM */ -#define MHF4_RSDB_CR1_MINIPMU_CAL_EN 0x8000 /* for 4349B0. JIRA:SW4349-1469 */ - -/* Flags in M_HOST_FLAGS5 */ -#define MHF5_BTCX_LIGHT 0x0002 /**< light coex mode, off txpu only for critical BT */ -#define MHF5_BTCX_PARALLEL 0x0004 /**< BT and WLAN run in parallel. */ -#define MHF5_BTCX_DEFANT 0x0008 /**< default position for shared antenna */ -#define MHF5_P2P_MODE 0x0010 /**< Enable P2P mode */ -#define MHF5_LEGACY_PRS 0x0020 /**< Enable legacy probe resp support */ -#define MHF5_HWRSSI_EN 0x0800 /**< Enable HW RSSI (ac) */ -#define MHF5_HIBERNATE 0x1000 /**< Force ucode to power save until wake-bit */ -#define MHF5_BTCX_GPIO_DEBUG 0x4000 /**< Enable gpio pins for btcoex ECI signals */ -#define MHF5_SUPPRESS_PRB_REQ 0x8000 /**< Suppress probe requests at ucode level */ - -/* Flags in M_HOST_FLAGS6 */ -#define MHF6_TXPWRCAP_RST_EN 0x0001 /** < Ucode clear phyreg after each tx */ -#define MHF6_TXPWRCAP_EN 0x0002 /** < Enable TX power capping in ucode */ -#define MHF6_TSYNC_AVB 0x0004 /** Enable AVB for timestamping */ -#define MHF6_TSYNC_3PKG 0x0020 /** < Enable 3rd txstatus package */ -#define MHF6_TDMTX 0x0040 /** < Enable SDB TDM in ucode */ -#define MHF6_TSYNC_NODEEPSLP 0x0080 /** < Disable deep sleep to keep AVB clock */ -#define MHF6_TSYNC_CAL 0x0100 /** < Enable Tsync cal in ucode */ -#define MHF6_TXPWRCAP_IOS_NBIT 0x0200 /** < Enable IOS mode of operation for Txpwrcap (REV>=80) */ -#define MHF6_MULBSSID_NBIT 0x0400 /** < associated to AP belonging to a multiple BSSID set */ -#define MHF6_HEBCN_TX_NBIT 0x0800 /** < HE BCN-TX */ -#define MHF6_LATENCY_EN 0x2000 /** < Enable Latency instrumentation in ucode */ -#define MHF6_PTMSTS_EN 0x4000 /** < Enable PTM Status */ - -/* MX_HOST_FLAGS */ -/* Flags for MX_HOST_FLAGS0 */ -#define MXHF0_RSV0 0x0001 /* ucode internal, not exposed yet */ -#define MXHF0_TXDRATE 0x0002 /* mu txrate to use rate from txd */ -#define MXHF0_CHKFID 0x0004 /* check if frameid->fifo matches hw txfifo idx */ -#define MXHF0_DISWAR 0x0008 /* disable some WAR. */ - -/* M_AXC_HOST_FLAGS0 */ -#define MAXCHF0_WAIT_TRIG 0x0001 /* Hold frames till trigger frame is rxed */ -#define MAXCHF0_HTC_SUPPORT 0x0002 /* 11AX HTC field support */ -#define MAXCHF0_AX_ASSOC_SHIFT 0x0003 /* 11AX association indicator */ -#define MAXCHF0_HEB_CONFIG 0x0004 /* HEB configuration */ -#define MAXCHF0_ACI_DET 0x0008 /* ACI detect soft enable */ -#define MAXCHF0_TRIGRES_LP 0x0010 /* Lite-Point testing */ -#define MAXCHF0_HDRCONV_SHIFT 5u /* Enable header conversion */ -#define MAXCHF0_HDRCONV (1 << MAXCHF0_HDRCONV_SHIFT) -#define MAXCHF0_FORCE_ZERO_PPR_SHIFT 6u /* Force PPR value to 0 for ULTPC */ -#define MAXCHF0_FORCE_ZERO_PPR (1 << MAXCHF0_FORCE_ZERO_PPR_SHIFT) -#define MAXCHF0_DISABLE_PYLDECWAR_SHIFT 7u /* Disable WAR for Paydecode issue */ -#define MAXCHF0_DISABLE_PYLDECWAR (1 << MAXCHF0_DISABLE_PYLDECWAR_SHIFT) -#define MAXCHF0_BSR_SUPPORT_SHIFT 8u /* BSR is supported */ -#define MAXCHF0_BSR_SUPPORT (1 << MAXCHF0_BSR_SUPPORT_SHIFT) -#define MAXCHF0_MUEDCA_VALID_SHIFT 9u /* MUEDCA information is valid */ -#define MAXCHF0_MUEDCA_VALID (1 << MAXCHF0_MUEDCA_VALID_SHIFT) -/* Bit 10 definition missing? */ -#define MAXCHF0_TWT_PKTSUPP_SHIFT 11u /* Enable pkt suppress outside TWT SP */ -#define MAXCHF0_TWT_PKTSUPP_EN (1 << MAXCHF0_TWT_PKTSUPP_SHIFT) -#define MAXCHF0_TBPPDU_STATUS_SHIFT 12u -#define MAXCHF0_TBPPDU_STATUS_EN (1 << MAXCHF0_TBPPDU_STATUS_SHIFT) -#define MAXCHF0_11AX_TXSTATUS_EXT_SHIFT 13u /* Enable 128 BA pkg in TX status */ -#define MAXCHF0_11AX_TXSTATUS_EXT_EN (1u << MAXCHF0_11AX_TXSTATUS_EXT_SHIFT) -#define MAXCHF1_11AX_TXSTATUS_EXT_SHIFT 0u /* Enable 256 BA pkg in TX status */ -#define MAXCHF1_11AX_TXSTATUS_EXT_EN (1u << MAXCHF1_11AX_TXSTATUS_EXT_SHIFT) -/* Bit 14 for UORA_EN */ -#define MAXCHF0_11AX_UORA_SHIFT 14u /* Enable UORA support */ -#define MAXCHF0_11AX_UORA_EN (1u << MAXCHF0_11AX_UORA_SHIFT) - -/* M_AXC_HOST_FLAGS1 */ -#define MAXCHF1_ITXSTATUS_EN 0x0004u /* Enable intermediate txs for TB PPDU */ -#define MAXCHF1_OBSSHWSTATS_EN 0x0008u /* Enable ucode OBSS stats monitoring */ - -/* M_SC_HOST_FLAGS */ -#define C_SCCX_STATS_EN 0x0001u /* Enable SC stats */ -#define C_SC_BTMC_COEX_EN 0x0002u /* Enable WLSC-BTMC coex */ - -/** Short version of receive frame status. Only used for non-last MSDU of AMSDU - rev61.1 */ -typedef struct d11rxhdrshort_rev61_1 d11rxhdrshort_rev61_1_t; -BWL_PRE_PACKED_STRUCT struct d11rxhdrshort_rev61_1 { - uint16 RxFrameSize; /**< Actual byte length of the frame data received */ - - /* These two 8-bit fields remain in the same order regardless of - * processor byte order. - */ - uint8 dma_flags; /**< bit 0 indicates short or long rx status. 1 == short. */ - uint8 fifo; /**< rx fifo number */ - uint16 mrxs; /**< MAC Rx Status */ - uint16 RxFrameSize0; /**< rxframesize for fifo-0 (in bytes). */ - uint16 HdrConvSt; /**< hdr conversion status. Copy of ihr(RCV_HDR_CTLSTS). */ - uint16 RxTSFTimeL; /**< RxTSFTime time of first MAC symbol + M_PHY_PLCPRX_DLY */ - uint16 RxTSFTimeH; /**< RxTSFTime time of first MAC symbol + M_PHY_PLCPRX_DLY */ - uint16 aux_status; /**< DMA writes into this field. ucode treats as reserved. */ -} BWL_POST_PACKED_STRUCT; - -/** Short version of receive frame status. Only used for non-last MSDU of AMSDU - pre80 */ -typedef struct d11rxhdrshort_lt80 d11rxhdrshort_lt80_t; -BWL_PRE_PACKED_STRUCT struct d11rxhdrshort_lt80 { - uint16 RxFrameSize; /**< Actual byte length of the frame data received */ - - /* These two 8-bit fields remain in the same order regardless of - * processor byte order. - */ - uint8 dma_flags; /**< bit 0 indicates short or long rx status. 1 == short. */ - uint8 fifo; /**< rx fifo number */ - uint16 mrxs; /**< MAC Rx Status */ - uint16 RxTSFTime; /**< RxTSFTime time of first MAC symbol + M_PHY_PLCPRX_DLY */ - uint16 HdrConvSt; /**< hdr conversion status. Copy of ihr(RCV_HDR_CTLSTS). */ - uint16 aux_status; /**< DMA writes into this field. ucode treats as reserved. */ -} BWL_POST_PACKED_STRUCT; - -/* Errflag bits for ge80 */ -#define ERRFLAGS_ERR_STATE 0x0003u -#define ERRFLAGS_GREATER_MSDU_LEN 0x0001u -#define ERRFLAGS_AMSDU_TRUNCATED 0x0002u -#define ERRFLAGS_HDRCONV_MASK 0x00F0u -#define ERRFLAGS_HDRCONV_SHIFT 4u -#define ERRFLAGS_CSI_LEN_64K 0x0100u -#define ERRFLAGS_MESH_FMT_ERR 0x0200u - -/* Register 'D11_RXE_ERRVAL' bits for ge80 */ -#define RXEERR_GREATER_MSDU_LEN (1u << 6) - -/* 128 BA configuration */ -/* Register D11_TXBA_DataSel bits for ge80 */ -#define TXBA_DATASEL_WSIZE_BITMAP_LEN_ENC_SEL (1u << 0u) - -/* Register D11_TXBA_Data bits (ge80) */ -#define TXBA_DATA_WSIZE_256 (0x100u) -#define TXBA_DATA_WSIZE_128 (0x80u) -#define TXBA_DATA_WSIZE_64 (0x40u) - -/* HW optimisation to generate bitmap based on start SSN & max SSN */ -#define TXBA_DATA_HW_CONST (0xfu << 12) - -/* Register D11_RXE_BA_LEN bits (ge80) */ -#define RXE_BA_LEN_RXBA_64 (0x0u) -#define RXE_BA_LEN_RXBA_128 (0x1u) -#define RXE_BA_LEN_RXBA_256 (0x2u) -#define RXE_BA_LEN_TID0_SHIFT (0u) -#define RXE_BA_LEN_TID1_SHIFT (2u) -#define RXE_BA_LEN_TID2_SHIFT (4u) -#define RXE_BA_LEN_TID3_SHIFT (6u) -#define RXE_BA_LEN_TID4_SHIFT (8u) -#define RXE_BA_LEN_TID5_SHIFT (10u) -#define RXE_BA_LEN_TID6_SHIFT (12u) -#define RXE_BA_LEN_TID7_SHIFT (14u) - -/* Register D11_RXE_BA_LEN_ENC bits (ge80) */ -#define RXE_BA_LEN_ENC_BA32_VAL (0x3u << 0u) -#define RXE_BA_LEN_ENC_BA64_VAL (0x0u << 2u) -#define RXE_BA_LEN_ENC_BA128_VAL (0x1u << 4u) -#define RXE_BA_LEN_ENC_BA256_VAL (0x2u << 6u) - -/* Register D11_RXE_TXBA_CTL2 (ge80) */ -#define RXE_TXBA_CTL2_CONIG_SINGLE_TID (0x0u << 0u) -#define RXE_TXBA_CTL2_CONIG_ALL_TID (0x1u << 0u) -#define RXE_TXBA_CTL2_SEL_TID0 (0x0u << 12u) -#define RXE_TXBA_CTL2_SEL_TID1 (0x1u << 12u) -#define RXE_TXBA_CTL2_SEL_TID2 (0x2u << 12u) -#define RXE_TXBA_CTL2_SEL_TID3 (0x3u << 12u) -#define RXE_TXBA_CTL2_SEL_TID4 (0x4u << 12u) -#define RXE_TXBA_CTL2_SEL_TID5 (0x5u << 12u) -#define RXE_TXBA_CTL2_SEL_TID6 (0x6u << 12u) -#define RXE_TXBA_CTL2_SEL_TID7 (0x7u << 12u) - -/** - * Special Notes - * #1: dma_flags, fifo - * These two 8-bit fields remain in the same order regardless of - * processor byte order. - * #2: pktclass - * 16 bit bitmap is a result of Packet (or Flow ) Classification. - * - * 0 : Flow ID Different - * 1,2,3 : A1, A2, A3 Different - * 4 : TID Different - * 5, 6 : DA, SA from AMSDU SubFrame Different - * 7 : FC Different - * 8 : AMPDU boundary - * 9 - 15 : Reserved - * #3: errflags - * These bits indicate specific errors detected by the HW on the Rx Path. - * However, these will be relevant for Last MSDU Status only. - * - * Whenever there is an error at any MSDU, HW treats it as last - * MSDU and send out last MSDU status. - */ - -#define D11RXHDR_HW_STATUS_GE80 \ - uint16 RxFrameSize; /**< Actual byte length of the frame data received */ \ - /* For comments see special note #1 above */\ - uint8 dma_flags; /**< bit 0 indicates short or long rx status. 1 == short. */ \ - uint8 fifo; /**< rx fifo number */ \ - \ - uint16 mrxs; /**< MAC Rx Status */ \ - uint16 RxFrameSize0; /**< rxframesize for fifo-0 (in bytes). */ \ - uint16 HdrConvSt; /**< hdr conversion status. Copy of ihr(RCV_HDR_CTLSTS). */ \ - uint16 pktclass; \ - uint32 filtermap; /**< 32 bit bitmap indicates which "Filters" have matched. */ \ - /* For comments see special note #2 above */ \ - uint16 flowid; /**< result of Flow ID Look Up performed by the HW. */ \ - /* For comments see special note #3 above */\ - uint16 errflags; - -#define D11RXHDR_UCODE_STATUS_GE80 \ - /**< Ucode Generated Status (16 Bytes) */ \ - uint16 RxStatus1; /**< MAC Rx Status */ \ - uint16 RxStatus2; /**< extended MAC Rx status */ \ - uint16 RxChan; /**< Rx channel info or chanspec */ \ - uint16 AvbRxTimeL; /**< AVB RX timestamp low16 */ \ - uint16 AvbRxTimeH; /**< AVB RX timestamp high16 */ \ - uint16 RxTSFTime; /**< Lower 16 bits of Rx timestamp */ \ - uint16 RxTsfTimeH; /**< Higher 16 bits of Rx timestamp */ \ - uint16 MuRate; /**< MU rate info (bit3:0 MCS, bit6:4 NSTS) */ - -#define D11RXHDR_HW_STATUS_GE87_1 /**< HW Generated 24 bytes RX Status */ \ - D11RXHDR_HW_STATUS_GE80 /**< First 20 bytes are same as mac rev >= 80 */ \ - uint16 roe_hw_sts; /**< ROE HW status */ \ - uint16 roe_err_flags; /**< ROE error flags */ - -#define D11RXHDR_UCODE_STATUS_GE87_1 /**< Ucode Generated Status (22 Bytes) */ \ - uint16 RxStatus1; /**< MAC Rx Status */ \ - uint16 RxStatus2; /**< extended MAC Rx status */ \ - uint16 RxChan; /**< Rx channel info or chanspec */ \ - uint16 MuRate; /**< MU rate info (bit3:0 MCS, bit6:4 NSTS) */ \ - uint32 AVBRxTime; /**< 32 bit AVB timestamp */ \ - uint32 TSFRxTime; /**< 32 bit TSF timestamp */ \ - uint64 PTMRxTime; /**< 64 bit PTM timestamp */ - - /**< HW Generated Status (20 Bytes) */ -/** Short version of receive frame status. Only used for non-last MSDU of AMSDU - rev80 */ -typedef struct d11rxhdrshort_ge87_1 d11rxhdrshort_ge87_1_t; -BWL_PRE_PACKED_STRUCT struct d11rxhdrshort_ge87_1 { - - D11RXHDR_HW_STATUS_GE87_1 - -} BWL_POST_PACKED_STRUCT; - -/** Mid version of receive frame status. Only used for MPDU of AMPDU - rev80 */ -typedef struct d11rxhdrmid_ge87_1 d11rxhdrmid_ge87_1_t; -BWL_PRE_PACKED_STRUCT struct d11rxhdrmid_ge87_1 { - - D11RXHDR_HW_STATUS_GE87_1 - D11RXHDR_UCODE_STATUS_GE87_1 -} BWL_POST_PACKED_STRUCT; - -/** Short version of receive frame status. Only used for non-last MSDU of AMSDU - rev80 */ -typedef struct d11rxhdrshort_ge80 d11rxhdrshort_ge80_t; -BWL_PRE_PACKED_STRUCT struct d11rxhdrshort_ge80 { - - D11RXHDR_HW_STATUS_GE80 - -} BWL_POST_PACKED_STRUCT; - -/** Mid version of receive frame status. Only used for MPDU of AMPDU - rev80 */ -typedef struct d11rxhdrmid_ge80 d11rxhdrmid_ge80_t; -BWL_PRE_PACKED_STRUCT struct d11rxhdrmid_ge80 { - - D11RXHDR_HW_STATUS_GE80 - D11RXHDR_UCODE_STATUS_GE80 - -} BWL_POST_PACKED_STRUCT; - -/** Receive Frame Data Header - pre80 */ -typedef struct d11rxhdr_lt80 d11rxhdr_lt80_t; -BWL_PRE_PACKED_STRUCT struct d11rxhdr_lt80 { - uint16 RxFrameSize; /**< Actual byte length of the frame data received */ - - /** - * These two 8-bit fields remain in the same order regardless of - * processor byte order. - */ - uint8 dma_flags; /* bit 0 indicates short or long rx status. 1 == short. */ - uint8 fifo; /* rx fifo number */ - - uint16 PhyRxStatus_0; /**< PhyRxStatus 15:0 */ - uint16 PhyRxStatus_1; /**< PhyRxStatus 31:16 */ - uint16 PhyRxStatus_2; /**< PhyRxStatus 47:32 */ - uint16 PhyRxStatus_3; /**< PhyRxStatus 63:48 */ - uint16 PhyRxStatus_4; /**< PhyRxStatus 79:64 */ - uint16 PhyRxStatus_5; /**< PhyRxStatus 95:80 */ - uint16 RxStatus1; /**< MAC Rx Status */ - uint16 RxStatus2; /**< extended MAC Rx status */ - - /** - * - RxTSFTime time of first MAC symbol + M_PHY_PLCPRX_DLY - */ - uint16 RxTSFTime; - - uint16 RxChan; /**< Rx channel info or chanspec */ - uint16 RxFrameSize0; /**< size of rx-frame in fifo-0 in case frame is copied to fifo-1 */ - uint16 HdrConvSt; /**< hdr conversion status. Copy of ihr(RCV_HDR_CTLSTS). */ - uint16 AvbRxTimeL; /**< AVB RX timestamp low16 */ - uint16 AvbRxTimeH; /**< AVB RX timestamp high16 */ - uint16 MuRate; /**< MU rate info (bit3:0 MCS, bit6:4 NSTS) */ - /** - * These bits indicate specific errors detected by the HW on the Rx Path. - * However, these will be relevant for Last MSDU Status only. - * - * Whenever there is an error at any MSDU, HW treats it as last - * MSDU and send out last MSDU status. - */ - uint16 errflags; -} BWL_POST_PACKED_STRUCT; - -#define N_PRXS_GE80 16 /* Total number of PhyRx status words for corerev >= 80 */ -#define N_PRXS_LT80 6 /* Total number of PhyRx status words for corerev < 80 */ - -/* number of PhyRx status words newly added for (corerev >= 80) */ -#define N_PRXS_REM_GE80 (N_PRXS_GE80 - N_PRXS_LT80) - -/** RX Hdr definition - rev80 */ -typedef struct d11rxhdr_ge80 d11rxhdr_ge80_t; -BWL_PRE_PACKED_STRUCT struct d11rxhdr_ge80 { - /** - * Even though rxhdr can be in short or long format, always declare it here - * to be in long format. So the offsets for the other fields are always the same. - */ - - /**< HW Generated Status (20 Bytes) */ - D11RXHDR_HW_STATUS_GE80 - D11RXHDR_UCODE_STATUS_GE80 - - /**< PHY Generated Status (32 Bytes) */ - uint16 PhyRxStatus_0; /**< PhyRxStatus 15:0 */ - uint16 PhyRxStatus_1; /**< PhyRxStatus 31:16 */ - uint16 PhyRxStatus_2; /**< PhyRxStatus 47:32 */ - uint16 PhyRxStatus_3; /**< PhyRxStatus 63:48 */ - uint16 PhyRxStatus_4; /**< PhyRxStatus 79:64 */ - uint16 PhyRxStatus_5; /**< PhyRxStatus 95:80 */ - uint16 phyrxs_rem[N_PRXS_REM_GE80]; /**< 20 bytes of remaining prxs (corerev >= 80) */ - /* Currently only 6 words are being pushed out of uCode: 6, 9, 16, 17, 21, 23 */ -} BWL_POST_PACKED_STRUCT; - -#define N_PRXS_GE85 32u // total number of PhyRxStatus BYTEs for rev >= 85 - -typedef struct d11rxhdr_ge87_1 d11rxhdr_ge87_1_t; -BWL_PRE_PACKED_STRUCT struct d11rxhdr_ge87_1 { - /** - * Even though rxhdr can be in short or long format, always declare it here - * to be in long format. So the offsets for the other fields are always the same. - */ - - D11RXHDR_HW_STATUS_GE87_1 /**< HW Generated Status (24 Bytes) */ - D11RXHDR_UCODE_STATUS_GE87_1 /**< uCode Generated Status (24 Bytes) */ - uint8 PHYRXSTATUS[N_PRXS_GE85]; /**< PHY Generated Status (32 Bytes) */ -} BWL_POST_PACKED_STRUCT; - -/* A wrapper structure for all versions of d11rxh short structures */ -typedef struct d11rxhdr_ge85 d11rxhdr_ge85_t; -BWL_PRE_PACKED_STRUCT struct d11rxhdr_ge85 { - /** - * Even though rxhdr can be in short or long format, always declare it here - * to be in long format. So the offsets for the other fields are always the same. - */ - - /**< HW Generated Status (20 Bytes) */ - D11RXHDR_HW_STATUS_GE80 - D11RXHDR_UCODE_STATUS_GE80 - - /**< PHY Generated Status (32 Bytes) */ - uint8 PHYRXSTATUS[N_PRXS_GE85]; -} BWL_POST_PACKED_STRUCT; - -/* A wrapper structure for all versions of d11rxh short structures */ -typedef union d11rxhdrshort { - d11rxhdrshort_rev61_1_t rev61_1; - d11rxhdrshort_lt80_t lt80; - d11rxhdrshort_ge80_t ge80; - d11rxhdrshort_ge87_1_t ge87_1; -} d11rxhdrshort_t; - -/* A wrapper structure for all versions of d11rxh mid structures */ -typedef union d11rxhdrmid { - d11rxhdrmid_ge80_t ge80; - d11rxhdrmid_ge87_1_t ge87_1; -} d11rxhdrmid_t; - -/* A wrapper structure for all versions of d11rxh structures */ -typedef union d11rxhdr { - d11rxhdr_lt80_t lt80; - d11rxhdr_ge80_t ge80; - d11rxhdr_ge85_t ge85; - d11rxhdr_ge87_1_t ge87_1; -} d11rxhdr_t; - -#define D11RXHDRSHORT_GE87_1_ACCESS_REF(srxh, member) \ - (&((((d11rxhdrshort_t *)(srxh))->ge87_1).member)) - -#define D11RXHDRMID_GE87_1_ACCESS_REF(mrxh, member) \ - (&((((d11rxhdrmid_t *)(mrxh))->ge87_1).member)) - -#define D11RXHDRSHORT_GE87_1_ACCESS_VAL(srxh, member) \ - ((((d11rxhdrshort_t *)(srxh))->ge87_1).member) - -#define D11RXHDRMID_GE87_1_ACCESS_VAL(mrxh, member) \ - ((((d11rxhdrmid_t *)(mrxh))->ge87_1).member) - -#define D11RXHDR_GE87_1_ACCESS_REF(rxh, member) \ - (&((rxh)->ge87_1).member) - -#define D11RXHDR_GE87_1_ACCESS_VAL(rxh, member) \ - (((rxh)->ge87_1).member) - -#define D11RXHDR_GE87_1_SET_VAL(rxh, member, value) \ - (((rxh)->ge87_1).member = value) - -#define D11RXHDRSHORT_GE80_ACCESS_REF(srxh, member) \ - (&((((d11rxhdrshort_t *)(srxh))->ge80).member)) - -#define D11RXHDRMID_GE80_ACCESS_REF(mrxh, member) \ - (&((((d11rxhdrmid_t *)(mrxh))->ge80).member)) - -#define D11RXHDRSHORT_LT80_ACCESS_REF(srxh, member) \ - (&((((d11rxhdrshort_t *)(srxh))->lt80).member)) - -#define D11RXHDRSHORT_GE80_ACCESS_VAL(srxh, member) \ - ((((d11rxhdrshort_t *)(srxh))->ge80).member) - -#define D11RXHDRMID_GE80_ACCESS_VAL(mrxh, member) \ - ((((d11rxhdrmid_t *)(mrxh))->ge80).member) - -#define D11RXHDRSHORT_LT80_ACCESS_VAL(srxh, member) \ - ((((d11rxhdrshort_t *)(srxh))->lt80).member) - -#define D11RXHDR_GE80_ACCESS_REF(rxh, member) \ - (&((rxh)->ge80).member) - -#define D11RXHDR_LT80_ACCESS_REF(rxh, member) \ - (&((rxh)->lt80).member) - -#define D11RXHDR_GE80_ACCESS_VAL(rxh, member) \ - (((rxh)->ge80).member) - -#define D11RXHDR_GE80_SET_VAL(rxh, member, value) \ - (((rxh)->ge80).member = value) - -#define D11RXHDR_LT80_ACCESS_VAL(rxh, member) \ - (((rxh)->lt80).member) - -#define D11RXHDR_LT80_SET_VAL(rxh, member, value) \ - (((rxh)->lt80).member = value) - -/** For accessing members of d11rxhdrshort_t by reference (address of members) */ -#define D11RXHDRSHORT_ACCESS_REF(srxh, corerev, corerev_minor, member) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDRSHORT_GE87_1_ACCESS_REF(srxh, member) : \ - D11REV_GE(corerev, 80) ? D11RXHDRSHORT_GE80_ACCESS_REF(srxh, member) : \ - D11RXHDRSHORT_LT80_ACCESS_REF(srxh, member)) - -/** For accessing members of d11rxhdrshort_t by value (only value stored inside members accessed) */ -#define D11RXHDRSHORT_ACCESS_VAL(srxh, corerev, corerev_minor, member) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDRSHORT_GE87_1_ACCESS_VAL(srxh, member) : \ - D11REV_GE(corerev, 80) ? D11RXHDRSHORT_GE80_ACCESS_VAL(srxh, member) : \ - D11RXHDRSHORT_LT80_ACCESS_VAL(srxh, member)) - -/** For accessing members of d11rxhdrmid_t by reference (address of members) */ -#define D11RXHDRMID_ACCESS_REF(mrxh, corerev, corerev_minor, member) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDRMID_GE87_1_ACCESS_REF(mrxh, member) : \ - D11REV_GE(corerev, 80) ? D11RXHDRMID_GE80_ACCESS_REF(mrxh, member) : NULL) - -/** For accessing members of d11rxhdrmid_t by value (only value stored inside members accessed) */ -#define D11RXHDRMID_ACCESS_VAL(mrxh, corerev, corerev_minor, member) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDRMID_GE87_1_ACCESS_VAL(mrxh, member) : \ - D11REV_GE(corerev, 80) ? D11RXHDRMID_GE80_ACCESS_VAL(mrxh, member) : NULL) - -/** For accessing members of d11rxhdr_t by reference (address of members) */ -#define D11RXHDR_ACCESS_REF(rxh, corerev, corerev_minor, member) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDR_GE87_1_ACCESS_REF(rxh, member) : \ - D11REV_GE(corerev, 80) ? D11RXHDR_GE80_ACCESS_REF(rxh, member) : \ - D11RXHDR_LT80_ACCESS_REF(rxh, member)) - -/** For accessing members of d11rxhdr_t by value (only value stored inside members accessed) */ -#define D11RXHDR_ACCESS_VAL(rxh, corerev, corerev_minor, member) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDR_GE87_1_ACCESS_VAL(rxh, member) : \ - D11REV_GE(corerev, 80) ? D11RXHDR_GE80_ACCESS_VAL(rxh, member) : \ - D11RXHDR_LT80_ACCESS_VAL(rxh, member)) - -/** For accessing members of d11rxhdr_t by value (only value stored inside members accessed) */ -#define D11RXHDR_SET_VAL(rxh, corerev, corerev_minor, member, value) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDR_GE87_1_SET_VAL(rxh, member, value) : \ - D11REV_GE(corerev, 80) ? D11RXHDR_GE80_SET_VAL(rxh, member, value) : \ - D11RXHDR_LT80_SET_VAL(rxh, member, value)) - -#define D11RXHDR_PTM(rxh, corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDR_GE87_1_ACCESS_VAL(rxh, PTMRxTime) : 0) - -#define D11RXHDR_AVB(rxh, corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - (uint32)D11RXHDR_GE87_1_ACCESS_VAL(rxh, AVBRxTime) : \ - D11REV_GE(corerev, 80) ? ((uint32)D11RXHDR_GE80_ACCESS_VAL(rxh, AvbRxTimeL) | \ - ((uint32)D11RXHDR_GE80_ACCESS_VAL(rxh, AvbRxTimeH) << 16u)) : \ - ((uint32)D11RXHDR_LT80_ACCESS_VAL(rxh, AvbRxTimeL) | \ - ((uint32)D11RXHDR_LT80_ACCESS_VAL(rxh, AvbRxTimeH) << 16u))) - -#define D11RXHDR_TSF_REF(rxh, corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDR_GE87_1_ACCESS_REF(rxh, TSFRxTime) : \ - D11REV_GE(corerev, 80) ? (uint32*)D11RXHDR_GE80_ACCESS_REF(rxh, RxTSFTime) : \ - (uint32*)D11RXHDR_LT80_ACCESS_REF(rxh, RxTSFTime)) - -#define D11RXHDR_TSF(rxh, corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDR_GE87_1_ACCESS_VAL(rxh, TSFRxTime) : \ - D11REV_GE(corerev, 80) ? D11RXHDR_GE80_ACCESS_VAL(rxh, RxTSFTime) : \ - D11RXHDR_LT80_ACCESS_VAL(rxh, RxTSFTime)) - -#define RXS_SHORT_ENAB(rev) (D11REV_GE(rev, 64) || \ - D11REV_IS(rev, 60) || \ - D11REV_IS(rev, 62)) - -#define RXS_MID_ENAB(rev) (D11REV_GE(rev, 80)) -#define RXS_LONG_ENAB(rev) (D11REV_GE(rev, 80)) - -#define IS_D11RXHDRSHORT(rxh, rev, rev_min) ((RXS_SHORT_ENAB(rev) && \ - ((D11RXHDR_ACCESS_VAL((rxh), (rev), (rev_min), dma_flags)) & RXS_SHORT_MASK)) != 0) - -#define IS_D11RXHDRMID(rxh, rev, rev_min) ((RXS_MID_ENAB(rev) && \ - ((D11RXHDR_ACCESS_VAL((rxh), (rev), (rev_min), dma_flags)) == 0))) - -#define IS_D11RXHDRLONG(rxh, rev, rev_min) \ - ((!(IS_D11RXHDRSHORT((rxh), (rev), (rev_min)))) && \ - (!(IS_D11RXHDRMID((rxh), (rev), (rev_min))))) - -#define D11RXHDR_HAS_UCODE_STATUS(rxhdr, corerev, corerev_minor) \ - ((!IS_D11RXHDRSHORT((rxhdr), (corerev), (corerev_minor))) || \ - (IS_D11RXHDRMID((rxhdr), (corerev), (corerev_minor)))) - -#define IS_PHYRXHDR_VALID(rxh, corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - (D11RXHDR_GE87_1_ACCESS_VAL(rxh, dma_flags) == RXS_PHYRXST_VALID_REV_GE80) : \ - D11REV_GE(corerev, 80) ? \ - (D11RXHDR_GE80_ACCESS_VAL(rxh, dma_flags) == RXS_PHYRXST_VALID_REV_GE80) : \ - (D11RXHDR_LT80_ACCESS_VAL(rxh, RxStatus2) & RXS_PHYRXST_VALID)) - -#define RXHDR_GET_PAD_LEN(rxh, corerev, corerev_minor) (D11REV_GE(corerev, 80) ? \ - ((((D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDR_GE87_1_ACCESS_VAL(rxh, mrxs) : \ - D11RXHDR_GE80_ACCESS_VAL(rxh, mrxs)) & RXSS_PBPRES) != 0) ? HDRCONV_PAD : 0) : \ - (IS_D11RXHDRSHORT(rxh, corerev, corerev_minor) ? \ - (((D11RXHDRSHORT_ACCESS_VAL(rxh, corerev, corerev_minor, mrxs) & \ - RXSS_PBPRES) != 0) ? HDRCONV_PAD : 0) : \ - (((D11RXHDR_LT80_ACCESS_VAL(rxh, RxStatus1) & RXS_PBPRES) != 0) ? HDRCONV_PAD : 0))) - -#define RXHDR_GET_PAD_PRES(rxh, corerev, corerev_minor) (D11REV_GE(corerev, 80) ? \ - (((D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDR_GE87_1_ACCESS_VAL(rxh, mrxs) : \ - D11RXHDR_GE80_ACCESS_VAL(rxh, mrxs)) & RXSS_PBPRES) != 0) : \ - (IS_D11RXHDRSHORT(rxh, corerev, corerev_minor) ? \ - ((D11RXHDRSHORT_ACCESS_VAL(rxh, corerev, corerev_minor, mrxs) & \ - RXSS_PBPRES) != 0) : \ - (((D11RXHDR_LT80_ACCESS_VAL(rxh, RxStatus1) & RXS_PBPRES) != 0)))) - -#define RXHDR_GET_CONV_TYPE(rxh, corerev, corerev_minor) \ - (IS_D11RXHDRSHORT(rxh, corerev, corerev_minor) ? \ - ((D11RXHDRSHORT_ACCESS_VAL(rxh, corerev, corerev_minor, \ - HdrConvSt) & HDRCONV_ETH_FRAME) != 0) : ((D11RXHDR_ACCESS_VAL(rxh, \ - corerev, corerev_minor, HdrConvSt) & HDRCONV_ETH_FRAME) != 0)) - -#define RXHDR_GET_ROE_ERR_STS(rxh, corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - ((D11RXHDR_GE87_1_ACCESS_VAL(rxh, roe_err_flags))) : 0) - -#define RXHDR_GET_ROE_L3_TYPE(rxh, corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - ((D11RXHDR_GE87_1_ACCESS_VAL(rxh, roe_hw_sts)) & ROE_L3_PROT_TYPE_MASK) : 0) - -#define RXHDR_GET_ROE_L4_TYPE(rxh, corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - ((D11RXHDR_GE87_1_ACCESS_VAL(rxh, roe_hw_sts)) & ROE_L4_PROT_TYPE_MASK) : 0) - -#define RXHDR_GET_ROE_L3_STATUS(rxh, corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - ((D11RXHDR_GE87_1_ACCESS_VAL(rxh, roe_hw_sts)) & ROE_L3_CHKSUM_STATUS_MASK) : 0) - -#define RXHDR_GET_ROE_L4_STATUS(rxh, corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - ((D11RXHDR_GE87_1_ACCESS_VAL(rxh, roe_hw_sts)) & ROE_L4_CHKSUM_STATUS_MASK) : 0) - -#define RXHDR_GET_AGG_TYPE(rxh, corerev, corerev_minor) \ - (D11REV_GE(corerev, 80) ? \ - (((D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDR_GE87_1_ACCESS_VAL(rxh, mrxs) : \ - D11RXHDR_GE80_ACCESS_VAL(rxh, mrxs)) & RXSS_AGGTYPE_MASK) >> RXSS_AGGTYPE_SHIFT) : \ - (IS_D11RXHDRSHORT(rxh, corerev, corerev_minor) ? \ - ((D11RXHDRSHORT_ACCESS_VAL(rxh, corerev, corerev_minor, mrxs) \ - & RXSS_AGGTYPE_MASK) >> RXSS_AGGTYPE_SHIFT) : \ - ((D11RXHDR_LT80_ACCESS_VAL(rxh, RxStatus2) & RXS_AGGTYPE_MASK) >> RXS_AGGTYPE_SHIFT))) - -#define RXHDR_GET_PBPRS_REF(rxh, corerev, corerev_minor) (D11REV_GE(corerev, 80) ? \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDR_GE87_1_ACCESS_REF(rxh, mrxs) : \ - D11RXHDR_GE80_ACCESS_REF(rxh, mrxs)) : \ - (IS_D11RXHDRSHORT(rxh, corerev, corerev_minor) ? \ - ((D11RXHDRSHORT_ACCESS_REF(rxh, corerev, corerev_minor, mrxs))) : \ - (D11RXHDR_LT80_ACCESS_REF(rxh, RxStatus1)))) - -#define RXHDR_GET_IS_DEFRAG(rxh, corerev, corerev_minor) (D11REV_GE(corerev, 80) ? \ - (D11RXHDR_ACCESS_VAL(rxh, corerev, corerev_minor, RxStatus1) & RXS_IS_DEFRAG) : 0) - -#define SET_RXHDR_PBPRS_REF_VAL(rxh, corerev, corerev_minor, val) \ - (D11REV_GE(corerev, 80) ? \ - (*val |= RXSS_PBPRES) : \ - (IS_D11RXHDRSHORT(rxh, corerev, corerev_minor) ? (*val |= RXSS_PBPRES) : \ - (*val |= RXS_PBPRES))) - -#define CLEAR_RXHDR_PBPRS_REF_VAL(rxh, corerev, corerev_minor, val) \ - (D11REV_GE(corerev, 80) ? \ - (*val &= ~RXSS_PBPRES) : \ - (IS_D11RXHDRSHORT(rxh, corerev, corerev_minor) ? (*val &= ~RXSS_PBPRES) : \ - (*val &= ~RXS_PBPRES))) - -#define RXHDR_GET_AMSDU(rxh, corerev, corerev_minor) (D11REV_GE(corerev, 80) ? \ - (((D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDR_GE87_1_ACCESS_VAL(rxh, mrxs) : \ - D11RXHDR_GE80_ACCESS_VAL(rxh, mrxs)) & RXSS_AMSDU_MASK) != 0) : \ - (IS_D11RXHDRSHORT(rxh, corerev, corerev_minor) ? \ - ((D11RXHDRSHORT_ACCESS_VAL(rxh, corerev, corerev_minor, \ - mrxs) & RXSS_AMSDU_MASK) != 0) : \ - ((D11RXHDR_LT80_ACCESS_VAL(rxh, RxStatus2) & RXS_AMSDU_MASK) != 0))) - -#ifdef BCMDBG -#define RXHDR_GET_MSDU_COUNT(rxh, corerev, corerev_minor) (D11REV_GE(corerev, 80) ? \ - (((D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? \ - D11RXHDR_GE87_1_ACCESS_VAL(rxh, mrxs) : \ - D11RXHDR_GE80_ACCESS_VAL(rxh, mrxs)) & RXSS_MSDU_CNT_MASK) >> RXSS_MSDU_CNT_SHIFT) : \ - IS_D11RXHDRSHORT(rxh, corerev, corerev_minor) ? \ - (((D11RXHDRSHORT_ACCESS_VAL(rxh, corerev, corerev_minor, mrxs)) & \ - RXSS_MSDU_CNT_MASK) >> RXSS_MSDU_CNT_SHIFT) : 0) - -#endif /* BCMDBG */ - -/** Length of HW RX status in RxStatus */ -#define HW_RXHDR_LEN_REV_GE87_1 (sizeof(d11rxhdrshort_ge87_1_t)) /* 24 bytes */ -#define HW_RXHDR_LEN_REV_GE80 (sizeof(d11rxhdrshort_ge80_t)) /* 20 bytes */ -#define HW_RXHDR_LEN_REV_LT80 (sizeof(d11rxhdrshort_lt80_t)) /* 12 bytes */ -#define HW_RXHDR_LEN_REV_61_1 (sizeof(d11rxhdrshort_rev61_1_t)) /* 16 bytes */ - -/** Length of HW RX status + ucode Rx status in RxStatus */ -#define MID_RXHDR_LEN_REV_GE87_1 (sizeof(d11rxhdrmid_ge87_1_t)) /* 48 bytes */ -#define MID_RXHDR_LEN_REV_GE80 (sizeof(d11rxhdrmid_ge80_t)) /* 36 bytes */ - -/** Length of HW RX status + ucode RX status + PHY RX status + padding(if need align) */ -#define D11_RXHDR_LEN_REV_GE87_1 (sizeof(d11rxhdr_ge87_1_t)) /* 80 bytes */ -#define D11_RXHDR_LEN_REV_GE80 (sizeof(d11rxhdr_ge80_t)) /* 68 bytes */ -#define D11_RXHDR_LEN_REV_LT80 (sizeof(d11rxhdr_lt80_t)) /* 36 bytes */ - -#define HW_RXHDR_LEN(corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? HW_RXHDR_LEN_REV_GE87_1 : \ - D11REV_GE(corerev, 80) ? HW_RXHDR_LEN_REV_GE80 : HW_RXHDR_LEN_REV_LT80) - -#define MID_RXHDR_LEN(corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? MID_RXHDR_LEN_REV_GE87_1 : \ - D11REV_GE(corerev, 80) ? \ - MID_RXHDR_LEN_REV_GE80 : NULL) - -#define D11_RXHDR_LEN(corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? D11_RXHDR_LEN_REV_GE87_1 : \ - D11REV_GE(corerev, 80) ? D11_RXHDR_LEN_REV_GE80 : \ - D11_RXHDR_LEN_REV_LT80) - -#define FRAMELEN(corerev, corerev_minor, rxh) \ - D11RXHDR_ACCESS_VAL(rxh, corerev, corerev_minor, RxFrameSize) - -#define RXS_SHORT_MASK 0x01 /**< Short vs full rx status in dma_flags field of d11rxhdr */ - -/** validate chip specific phychain info for MCSSQ snr. - * should sync with uCode reporting. - * please add a condition with decending order to avoid any wrong skip - * Note: this macro can be removed once NEWT no longer needs 4368a0. - */ -#define IS_MCSSQ_ANT3_VALID_GE80(corerev, corerev_minor) \ - (D11REV_IS(corerev, 83) && (D11MINORREV_IS(corerev_minor, 1))) - -/* Header conversion status register bit fields */ -#define HDRCONV_USR_ENAB 0x0001 -#define HDRCONV_ENAB 0x0100 -#define HDRCONV_ETH_FRAME 0x0200 -#define HDRCONV_STATUS_VALID 0x8000 - -#define ROE_L3_PROT_TYPE_IPV4 (0x10u) -#define ROE_L3_PROT_TYPE_IPV6 (0x20u) -#define ROE_L3_PROT_TYPE_MASK (0x30u) -#define ROE_L3_PROT_TYPE_SHIFT (4u) - -#define ROE_L4_PROT_TYPE_TCP (0x40u) -#define ROE_L4_PROT_TYPE_UDP (0x80u) -#define ROE_L4_PROT_TYPE_MASK (0xC0u) -#define ROE_L4_PROT_TYPE_SHIFT (6u) - -#define ROE_L3_CHKSUM_STATUS_FAIL (0x100u) -#define ROE_L3_CHKSUM_STATUS_SUCCESS (0x200u) -#define ROE_L3_CHKSUM_STATUS_MASK (0x300u) -#define ROE_L3_CHKSUM_STATUS_SHIFT (8u) - -#define ROE_L4_CHKSUM_STATUS_FAIL (0x400u) -#define ROE_L4_CHKSUM_STATUS_SUCCESS (0x800u) -#define ROE_L4_CHKSUM_STATUS_MASK (0xC00u) -#define ROE_L4_CHKSUM_STATUS_SHIFT (10u) - -/** NOTE: Due to precommit issue, _d11_autophyrxsts_ will be moved - * to a separated file when 4387 trunk build is stable - */ -#ifndef _d11_autophyrxsts_ -#define _d11_autophyrxsts_ - -#define APRXS_WD0_L_EN_GE85 1u -#define APRXS_WD0_H_EN_GE85 1u -#define APRXS_WD1_L_EN_GE85 1u -#define APRXS_WD1_H_EN_GE85 1u -#define APRXS_WD2_L_EN_GE85 1u -#define APRXS_WD2_H_EN_GE85 1u -#define APRXS_WD3_L_EN_GE85 1u -#define APRXS_WD3_H_EN_GE85 0u // DO NOT ENABLE WD3_H -#define APRXS_WD4_L_EN_GE85 1u -#define APRXS_WD4_H_EN_GE85 1u -#define APRXS_WD5_L_EN_GE85 1u -#define APRXS_WD5_H_EN_GE85 1u -#define APRXS_WD6_L_EN_GE85 0u -#define APRXS_WD6_H_EN_GE85 0u -#define APRXS_WD7_L_EN_GE85 0u -#define APRXS_WD7_H_EN_GE85 0u -#define APRXS_WD8_L_EN_GE85 0u -#define APRXS_WD8_H_EN_GE85 1u -#define APRXS_WD9_L_EN_GE85 0u -#define APRXS_WD9_H_EN_GE85 0u -#define APRXS_WD10_L_EN_GE85 0u -#define APRXS_WD10_H_EN_GE85 0u -#define APRXS_WD11_L_EN_GE85 0u -#define APRXS_WD11_H_EN_GE85 0u -#define APRXS_WD12_L_EN_GE85 0u -#define APRXS_WD12_H_EN_GE85 0u -#define APRXS_WD13_L_EN_GE85 0u -#define APRXS_WD13_H_EN_GE85 0u -#define APRXS_WD14_L_EN_GE85 0u -#define APRXS_WD14_H_EN_GE85 0u -#define APRXS_WD15_L_EN_GE85 0u -#define APRXS_WD15_H_EN_GE85 0u -#define APRXS_WD16_L_EN_GE85 1u -#define APRXS_WD16_H_EN_GE85 0u -#define APRXS_WD17_L_EN_GE85 0u -#define APRXS_WD17_H_EN_GE85 0u -#define APRXS_WD18_L_EN_GE85 1u -#define APRXS_WD18_H_EN_GE85 0u -#define APRXS_WD19_L_EN_GE85 0u -#define APRXS_WD19_H_EN_GE85 0u -#define APRXS_WD20_L_EN_GE85 1u -#define APRXS_WD20_H_EN_GE85 1u -#define APRXS_WD21_L_EN_GE85 0u -#define APRXS_WD21_H_EN_GE85 1u -#define APRXS_WD22_L_EN_GE85 1u -#define APRXS_WD22_H_EN_GE85 1u -#define APRXS_WD23_L_EN_GE85 1u -#define APRXS_WD23_H_EN_GE85 1u -#define APRXS_WD24_L_EN_GE85 0u -#define APRXS_WD24_H_EN_GE85 0u -#define APRXS_WD25_L_EN_GE85 0u -#define APRXS_WD25_H_EN_GE85 0u - -enum { - APRXS_WD0_L_SHIFT = 0, // frameType, unsupportedRate, band, lostCRS, shortPreamble - APRXS_WD0_H_SHIFT, // PLCPViolation, MFCRSFired, ACCRSFired, MUPPDU, OBSSStat - APRXS_WD1_L_SHIFT, // coremask, antcfg, - APRXS_WD1_H_SHIFT, // BWclassification - APRXS_WD2_L_SHIFT, // RxPwrAnt0 - APRXS_WD2_H_SHIFT, // RxPwrAnt1 - APRXS_WD3_L_SHIFT, // RxPwrAnt2 - APRXS_WD3_H_SHIFT, // RxPwrAnt3, OCL - APRXS_WD4_L_SHIFT, // RSSI factional bit - APRXS_WD4_H_SHIFT, // AGC type, ACI mitigation state, ClipCount, DynBWInNonHT - APRXS_WD5_L_SHIFT, // MCSSQSNRCore0 - APRXS_WD5_H_SHIFT, // MCSSQSNRCore1 - APRXS_WD6_L_SHIFT, // MCSSQSNRCore2 - APRXS_WD6_H_SHIFT, // MCSSQSNRCore3, OCL 1 - APRXS_WD7_L_SHIFT, // MUIntProcessType, - APRXS_WD7_H_SHIFT, // coarse freq_offset, packet abort - APRXS_WD8_L_SHIFT = 0, // fine freq offset - APRXS_WD8_H_SHIFT, // ChBWInNonHT, MLUsed, SINRBasedACIDet - APRXS_WD9_L_SHIFT, // SpatialSQCnt - APRXS_WD9_H_SHIFT, // packet gain - APRXS_WD10_L_SHIFT, // RxPwrAntExt - APRXS_WD10_H_SHIFT, // coarse freq_offset of 2nd 80mhz - APRXS_WD11_L_SHIFT, // fine freq_offset of 2nd 80mhz - APRXS_WD11_H_SHIFT, - APRXS_WD12_L_SHIFT, - APRXS_WD12_H_SHIFT, - APRXS_WD13_L_SHIFT, - APRXS_WD13_H_SHIFT, - APRXS_WD14_L_SHIFT, - APRXS_WD14_H_SHIFT, - APRXS_WD15_L_SHIFT, - APRXS_WD15_H_SHIFT, - APRXS_WD16_L_SHIFT = 0, - APRXS_WD16_H_SHIFT, - APRXS_WD17_L_SHIFT, - APRXS_WD17_H_SHIFT, - APRXS_WD18_L_SHIFT, - APRXS_WD18_H_SHIFT, - APRXS_WD19_L_SHIFT, - APRXS_WD19_H_SHIFT, - APRXS_WD20_L_SHIFT, - APRXS_WD20_H_SHIFT, - APRXS_WD21_L_SHIFT, - APRXS_WD21_H_SHIFT, - APRXS_WD22_L_SHIFT, // STA ID - APRXS_WD22_H_SHIFT, // STA ID, NSTS, TXBF, DCM - APRXS_WD23_L_SHIFT, - APRXS_WD23_H_SHIFT, - APRXS_WD24_L_SHIFT = 0, - APRXS_WD24_H_SHIFT, - APRXS_WD25_L_SHIFT, - APRXS_WD25_H_SHIFT -}; - -#define APRXS_WD0_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD0_L_EN_GE85 : 0) -#define APRXS_WD0_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD0_H_EN_GE85 : 0) -#define APRXS_WD1_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD1_L_EN_GE85 : 0) -#define APRXS_WD1_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD1_H_EN_GE85 : 0) -#define APRXS_WD2_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD2_L_EN_GE85 : 0) -#define APRXS_WD2_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD2_H_EN_GE85 : 0) -#define APRXS_WD3_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD3_L_EN_GE85 : 0) -#define APRXS_WD3_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD3_H_EN_GE85 : 0) -#define APRXS_WD4_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD4_L_EN_GE85 : 0) -#define APRXS_WD4_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD4_H_EN_GE85 : 0) -#define APRXS_WD5_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD5_L_EN_GE85 : 0) -#define APRXS_WD5_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD5_H_EN_GE85 : 0) -#define APRXS_WD6_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD6_L_EN_GE85 : 0) -#define APRXS_WD6_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD6_H_EN_GE85 : 0) -#define APRXS_WD7_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD7_L_EN_GE85 : 0) -#define APRXS_WD7_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD7_H_EN_GE85 : 0) -#define APRXS_WD8_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD8_L_EN_GE85 : 0) -#define APRXS_WD8_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD8_H_EN_GE85 : 0) -#define APRXS_WD9_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD9_L_EN_GE85 : 0) -#define APRXS_WD9_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD9_H_EN_GE85 : 0) -#define APRXS_WD10_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD10_L_EN_GE85 : 0) -#define APRXS_WD10_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD10_H_EN_GE85 : 0) -#define APRXS_WD11_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD11_L_EN_GE85 : 0) -#define APRXS_WD11_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD11_H_EN_GE85 : 0) -#define APRXS_WD12_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD12_L_EN_GE85 : 0) -#define APRXS_WD12_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD12_H_EN_GE85 : 0) -#define APRXS_WD13_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD13_L_EN_GE85 : 0) -#define APRXS_WD13_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD13_H_EN_GE85 : 0) -#define APRXS_WD14_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD14_L_EN_GE85 : 0) -#define APRXS_WD14_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD14_H_EN_GE85 : 0) -#define APRXS_WD15_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD15_L_EN_GE85 : 0) -#define APRXS_WD15_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD15_H_EN_GE85 : 0) -#define APRXS_WD16_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD16_L_EN_GE85 : 0) -#define APRXS_WD16_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD16_H_EN_GE85 : 0) -#define APRXS_WD17_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD17_L_EN_GE85 : 0) -#define APRXS_WD17_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD17_H_EN_GE85 : 0) -#define APRXS_WD18_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD18_L_EN_GE85 : 0) -#define APRXS_WD18_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD18_H_EN_GE85 : 0) -#define APRXS_WD19_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD19_L_EN_GE85 : 0) -#define APRXS_WD19_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD19_H_EN_GE85 : 0) -#define APRXS_WD20_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD20_L_EN_GE85 : 0) -#define APRXS_WD20_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD20_H_EN_GE85 : 0) -#define APRXS_WD21_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD21_L_EN_GE85 : 0) -#define APRXS_WD21_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD21_H_EN_GE85 : 0) -#define APRXS_WD22_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD22_L_EN_GE85 : 0) -#define APRXS_WD22_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD22_H_EN_GE85 : 0) -#define APRXS_WD23_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD23_L_EN_GE85 : 0) -#define APRXS_WD23_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD23_H_EN_GE85 : 0) -#define APRXS_WD24_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD24_L_EN_GE85 : 0) -#define APRXS_WD24_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD24_H_EN_GE85 : 0) -#define APRXS_WD25_L_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD25_L_EN_GE85 : 0) -#define APRXS_WD25_H_EN(rev) ((D11REV_GE(rev, 85)) ? \ - APRXS_WD25_H_EN_GE85 : 0) - -#define APRXS_BMAP0(rev) ((APRXS_WD0_L_EN(rev) << APRXS_WD0_L_SHIFT) | \ - (APRXS_WD0_H_EN(rev) << APRXS_WD0_H_SHIFT) |\ - (APRXS_WD1_L_EN(rev) << APRXS_WD1_L_SHIFT) |\ - (APRXS_WD1_H_EN(rev) << APRXS_WD1_H_SHIFT) |\ - (APRXS_WD2_L_EN(rev) << APRXS_WD2_L_SHIFT) |\ - (APRXS_WD2_H_EN(rev) << APRXS_WD2_H_SHIFT) |\ - (APRXS_WD3_L_EN(rev) << APRXS_WD3_L_SHIFT) |\ - (APRXS_WD3_H_EN(rev) << APRXS_WD3_H_SHIFT) |\ - (APRXS_WD4_L_EN(rev) << APRXS_WD4_L_SHIFT) |\ - (APRXS_WD4_H_EN(rev) << APRXS_WD4_H_SHIFT) |\ - (APRXS_WD5_L_EN(rev) << APRXS_WD5_L_SHIFT) |\ - (APRXS_WD5_H_EN(rev) << APRXS_WD5_H_SHIFT) |\ - (APRXS_WD6_L_EN(rev) << APRXS_WD6_L_SHIFT) |\ - (APRXS_WD6_H_EN(rev) << APRXS_WD6_H_SHIFT) |\ - (APRXS_WD7_L_EN(rev) << APRXS_WD7_L_SHIFT) |\ - (APRXS_WD7_H_EN(rev) << APRXS_WD7_H_SHIFT)) - -#define APRXS_BMAP1(rev) ((APRXS_WD8_L_EN(rev) << APRXS_WD8_L_SHIFT) | \ - (APRXS_WD8_H_EN(rev) << APRXS_WD8_H_SHIFT) |\ - (APRXS_WD9_L_EN(rev) << APRXS_WD9_L_SHIFT) |\ - (APRXS_WD9_H_EN(rev) << APRXS_WD9_H_SHIFT) |\ - (APRXS_WD10_L_EN(rev) << APRXS_WD10_L_SHIFT) |\ - (APRXS_WD10_H_EN(rev) << APRXS_WD10_H_SHIFT) |\ - (APRXS_WD11_L_EN(rev) << APRXS_WD11_L_SHIFT) |\ - (APRXS_WD11_H_EN(rev) << APRXS_WD11_H_SHIFT) |\ - (APRXS_WD12_L_EN(rev) << APRXS_WD12_L_SHIFT) |\ - (APRXS_WD12_H_EN(rev) << APRXS_WD12_H_SHIFT) |\ - (APRXS_WD13_L_EN(rev) << APRXS_WD13_L_SHIFT) |\ - (APRXS_WD13_H_EN(rev) << APRXS_WD13_H_SHIFT) |\ - (APRXS_WD14_L_EN(rev) << APRXS_WD14_L_SHIFT) |\ - (APRXS_WD14_H_EN(rev) << APRXS_WD14_H_SHIFT) |\ - (APRXS_WD15_L_EN(rev) << APRXS_WD15_L_SHIFT) |\ - (APRXS_WD15_H_EN(rev) << APRXS_WD15_H_SHIFT)) - -#define APRXS_BMAP2(rev) ((APRXS_WD16_L_EN(rev) << APRXS_WD16_L_SHIFT) | \ - (APRXS_WD16_H_EN(rev) << APRXS_WD16_H_SHIFT) |\ - (APRXS_WD17_L_EN(rev) << APRXS_WD17_L_SHIFT) |\ - (APRXS_WD17_H_EN(rev) << APRXS_WD17_H_SHIFT) |\ - (APRXS_WD18_L_EN(rev) << APRXS_WD18_L_SHIFT) |\ - (APRXS_WD18_H_EN(rev) << APRXS_WD18_H_SHIFT) |\ - (APRXS_WD19_L_EN(rev) << APRXS_WD19_L_SHIFT) |\ - (APRXS_WD19_H_EN(rev) << APRXS_WD19_H_SHIFT) |\ - (APRXS_WD20_L_EN(rev) << APRXS_WD20_L_SHIFT) |\ - (APRXS_WD20_H_EN(rev) << APRXS_WD20_H_SHIFT) |\ - (APRXS_WD21_L_EN(rev) << APRXS_WD21_L_SHIFT) |\ - (APRXS_WD21_H_EN(rev) << APRXS_WD21_H_SHIFT) |\ - (APRXS_WD22_L_EN(rev) << APRXS_WD22_L_SHIFT) |\ - (APRXS_WD22_H_EN(rev) << APRXS_WD22_H_SHIFT) |\ - (APRXS_WD23_L_EN(rev) << APRXS_WD23_L_SHIFT) |\ - (APRXS_WD23_H_EN(rev) << APRXS_WD23_H_SHIFT)) - -#define APRXS_BMAP3(rev) ((APRXS_WD24_L_EN(rev) << APRXS_WD24_L_SHIFT) | \ - (APRXS_WD24_H_EN(rev) << APRXS_WD24_H_SHIFT) |\ - (APRXS_WD25_L_EN(rev) << APRXS_WD25_L_SHIFT) |\ - (APRXS_WD25_H_EN(rev) << APRXS_WD25_H_SHIFT)) -/* byte position */ -#define APRXS_WD0_L_POS(rev) 0u -#define APRXS_WD0_H_POS(rev) (APRXS_WD0_L_POS(rev) + APRXS_WD0_L_EN(rev)) /* 1 */ -#define APRXS_WD1_L_POS(rev) (APRXS_WD0_H_POS(rev) + APRXS_WD0_H_EN(rev)) /* 2 */ -#define APRXS_WD1_H_POS(rev) (APRXS_WD1_L_POS(rev) + APRXS_WD1_L_EN(rev)) /* 3 */ -#define APRXS_WD2_L_POS(rev) (APRXS_WD1_H_POS(rev) + APRXS_WD1_H_EN(rev)) /* 4 */ -#define APRXS_WD2_H_POS(rev) (APRXS_WD2_L_POS(rev) + APRXS_WD2_L_EN(rev)) /* 5 */ -#define APRXS_WD3_L_POS(rev) (APRXS_WD2_H_POS(rev) + APRXS_WD2_H_EN(rev)) /* 6 */ -#define APRXS_WD3_H_POS(rev) (APRXS_WD3_L_POS(rev) + APRXS_WD3_L_EN(rev)) /* 7 */ -#define APRXS_WD4_L_POS(rev) (APRXS_WD3_H_POS(rev) + APRXS_WD3_H_EN(rev)) /* 7 */ -#define APRXS_WD4_H_POS(rev) (APRXS_WD4_L_POS(rev) + APRXS_WD4_L_EN(rev)) /* 8 */ -#define APRXS_WD5_L_POS(rev) (APRXS_WD4_H_POS(rev) + APRXS_WD4_H_EN(rev)) /* 9 */ -#define APRXS_WD5_H_POS(rev) (APRXS_WD5_L_POS(rev) + APRXS_WD5_L_EN(rev)) /* 10 */ -#define APRXS_WD6_L_POS(rev) (APRXS_WD5_H_POS(rev) + APRXS_WD5_H_EN(rev)) /* 11 */ -#define APRXS_WD6_H_POS(rev) (APRXS_WD6_L_POS(rev) + APRXS_WD6_L_EN(rev)) /* 11 */ -#define APRXS_WD7_L_POS(rev) (APRXS_WD6_H_POS(rev) + APRXS_WD6_H_EN(rev)) /* 11 */ -#define APRXS_WD7_H_POS(rev) (APRXS_WD7_L_POS(rev) + APRXS_WD7_L_EN(rev)) /* 11 */ -#define APRXS_WD8_L_POS(rev) (APRXS_WD7_H_POS(rev) + APRXS_WD7_H_EN(rev)) /* 11 */ -#define APRXS_WD8_H_POS(rev) (APRXS_WD8_L_POS(rev) + APRXS_WD8_L_EN(rev)) /* 11 */ -#define APRXS_WD9_L_POS(rev) (APRXS_WD8_H_POS(rev) + APRXS_WD8_H_EN(rev)) /* 12 */ -#define APRXS_WD9_H_POS(rev) (APRXS_WD9_L_POS(rev) + APRXS_WD9_L_EN(rev)) /* 12 */ -#define APRXS_WD10_L_POS(rev) (APRXS_WD9_H_POS(rev) + APRXS_WD9_H_EN(rev)) /* 12 */ -#define APRXS_WD10_H_POS(rev) (APRXS_WD10_L_POS(rev) + APRXS_WD10_L_EN(rev)) /* 12 */ -#define APRXS_WD11_L_POS(rev) (APRXS_WD10_H_POS(rev) + APRXS_WD10_H_EN(rev)) /* 12 */ -#define APRXS_WD11_H_POS(rev) (APRXS_WD11_L_POS(rev) + APRXS_WD11_L_EN(rev)) /* 12 */ -#define APRXS_WD12_L_POS(rev) (APRXS_WD11_H_POS(rev) + APRXS_WD11_H_EN(rev)) /* 12 */ -#define APRXS_WD12_H_POS(rev) (APRXS_WD12_L_POS(rev) + APRXS_WD12_L_EN(rev)) /* 12 */ -#define APRXS_WD13_L_POS(rev) (APRXS_WD12_H_POS(rev) + APRXS_WD12_H_EN(rev)) /* 12 */ -#define APRXS_WD13_H_POS(rev) (APRXS_WD13_L_POS(rev) + APRXS_WD13_L_EN(rev)) /* 12 */ -#define APRXS_WD14_L_POS(rev) (APRXS_WD13_H_POS(rev) + APRXS_WD13_H_EN(rev)) /* 12 */ -#define APRXS_WD14_H_POS(rev) (APRXS_WD14_L_POS(rev) + APRXS_WD14_L_EN(rev)) /* 12 */ -#define APRXS_WD15_L_POS(rev) (APRXS_WD14_H_POS(rev) + APRXS_WD14_H_EN(rev)) /* 12 */ -#define APRXS_WD15_H_POS(rev) (APRXS_WD15_L_POS(rev) + APRXS_WD15_L_EN(rev)) /* 12 */ -#define APRXS_WD16_L_POS(rev) (APRXS_WD15_H_POS(rev) + APRXS_WD15_H_EN(rev)) /* 12 */ -#define APRXS_WD16_H_POS(rev) (APRXS_WD16_L_POS(rev) + APRXS_WD16_L_EN(rev)) /* 13 */ -#define APRXS_WD17_L_POS(rev) (APRXS_WD16_H_POS(rev) + APRXS_WD16_H_EN(rev)) /* 13 */ -#define APRXS_WD17_H_POS(rev) (APRXS_WD17_L_POS(rev) + APRXS_WD17_L_EN(rev)) /* 13 */ -#define APRXS_WD18_L_POS(rev) (APRXS_WD17_H_POS(rev) + APRXS_WD17_H_EN(rev)) /* 13 */ -#define APRXS_WD18_H_POS(rev) (APRXS_WD18_L_POS(rev) + APRXS_WD18_L_EN(rev)) /* 14 */ -#define APRXS_WD19_L_POS(rev) (APRXS_WD18_H_POS(rev) + APRXS_WD18_H_EN(rev)) /* 14 */ -#define APRXS_WD19_H_POS(rev) (APRXS_WD19_L_POS(rev) + APRXS_WD19_L_EN(rev)) /* 14 */ -#define APRXS_WD20_L_POS(rev) (APRXS_WD19_H_POS(rev) + APRXS_WD19_H_EN(rev)) /* 14 */ -#define APRXS_WD20_H_POS(rev) (APRXS_WD20_L_POS(rev) + APRXS_WD20_L_EN(rev)) /* 15 */ -#define APRXS_WD21_L_POS(rev) (APRXS_WD20_H_POS(rev) + APRXS_WD20_H_EN(rev)) /* 16 */ -#define APRXS_WD21_H_POS(rev) (APRXS_WD21_L_POS(rev) + APRXS_WD21_L_EN(rev)) /* 16 */ -#define APRXS_WD22_L_POS(rev) (APRXS_WD21_H_POS(rev) + APRXS_WD21_H_EN(rev)) /* 17 */ -#define APRXS_WD22_H_POS(rev) (APRXS_WD22_L_POS(rev) + APRXS_WD22_L_EN(rev)) /* 18 */ -#define APRXS_WD23_L_POS(rev) (APRXS_WD22_H_POS(rev) + APRXS_WD22_H_EN(rev)) /* 19 */ -#define APRXS_WD23_H_POS(rev) (APRXS_WD23_L_POS(rev) + APRXS_WD23_L_EN(rev)) /* 20 */ -#define APRXS_WD24_L_POS(rev) (APRXS_WD23_H_POS(rev) + APRXS_WD23_H_EN(rev)) /* 21 */ -#define APRXS_WD24_H_POS(rev) (APRXS_WD24_L_POS(rev) + APRXS_WD24_L_EN(rev)) /* 21 */ -#define APRXS_WD25_L_POS(rev) (APRXS_WD24_H_POS(rev) + APRXS_WD24_H_EN(rev)) /* 22 */ -#define APRXS_WD25_H_POS(rev) (APRXS_WD25_L_POS(rev) + APRXS_WD25_L_EN(rev)) /* 23 */ - -#define APRXS_NBYTES(rev) (APRXS_WD25_H_POS(rev)) // total number of bytes enabled - -// frame type -#define APRXS_FT_POS(rev) APRXS_WD0_L_POS(rev) -#define APRXS_FT_MASK 0xFu -#define APRXS_FT(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_FT_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_FT_POS(rev)]) & \ - APRXS_FT_MASK) - -// unsupported rate -#define APRXS_UNSRATE_POS(rev) APRXS_WD0_L_POS(rev) -#define APRXS_UNSRATE_MASK 0x10u -#define APRXS_UNSRATE_SHIFT 4u -#define APRXS_UNSRATE(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_UNSRATE_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_UNSRATE_POS(rev)]) & \ - APRXS_UNSRATE_MASK) >> APRXS_UNSRATE_SHIFT) - -// band -#define APRXS_BAND_POS(rev) APRXS_WD0_L_POS(rev) -#define APRXS_BAND_MASK 0x20u -#define APRXS_BAND_SHIFT 5u -#define APRXS_BAND(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_BAND_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_BAND_POS(rev)]) & \ - APRXS_BAND_MASK) >> APRXS_BAND_SHIFT) - -// lost CRS -#define APRXS_LOSTCRS_POS(rev) APRXS_WD0_L_POS(rev) -#define APRXS_LOSTCRS_MASK 0x40u -#define APRXS_LOSTCRS_SHIFT 6u -#define APRXS_LOSTCRS(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_LOSTCRS_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_LOSTCRS_POS(rev)]) & \ - APRXS_LOSTCRS_MASK) >> APRXS_LOSTCRS_SHIFT) - -// short preamble -#define APRXS_SHORTH_POS(rev) APRXS_WD0_L_POS(rev) -#define APRXS_SHORTH_MASK 0x80u -#define APRXS_SHORTH_SHIFT 7u -#define APRXS_SHORTH(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_SHORTH_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_SHORTH_POS(rev)]) & \ - APRXS_SHORTH_MASK) >> APRXS_SHORTH_SHIFT) - -// plcp format violation -#define APRXS_PLCPFV_POS(rev) APRXS_WD0_H_POS(rev) -#define APRXS_PLCPFV_MASK 0x1u -#define APRXS_PLCPFV(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_PLCPFV_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_PLCPFV_POS(rev)]) & \ - APRXS_PLCPFV_MASK) - -// plcp header CRC failed -#define APRXS_PLCPHCF_POS(rev) APRXS_WD0_H_POS(rev) -#define APRXS_PLCPHCF_MASK 0x2u -#define APRXS_PLCPHCF_SHIFT 1u -#define APRXS_PLCPHCF(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_PLCPHCF_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_PLCPHCF_POS(rev)]) & \ - APRXS_PLCPHCF_MASK) >> APRXS_PLCPHCF_SHIFT) - -// MFCRS fired -#define APRXS_MFCRS_FIRED_POS(rev) APRXS_WD0_H_POS(rev) -#define APRXS_MFCRS_FIRED_MASK 0x4u -#define APRXS_MFCRS_FIRED_SHIFT 2u -#define APRXS_MFCRS_FIRED(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_MFCRS_FIRED_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_MFCRS_FIRED_POS(rev)]) & \ - APRXS_MFCRS_FIRED_MASK) >> APRXS_MFCRS_FIRED_SHIFT) - -// ACCRS fired -#define APRXS_ACCRS_FIRED_POS(rev) APRXS_WD0_H_POS(rev) -#define APRXS_ACCRS_FIRED_MASK 0x8u -#define APRXS_ACCRS_FIRED_SHIFT 3u -#define APRXS_ACCRS_FIRED(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_ACCRS_FIRED_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_ACCRS_FIRED_POS(rev)]) & \ - APRXS_ACCRS_FIRED_MASK) >> APRXS_ACCRS_FIRED_SHIFT) - -// MU PPDU -#define APRXS_MUPPDU_POS(rev) APRXS_WD0_H_POS(rev) -#define APRXS_MUPPDU_MASK 0x10u -#define APRXS_MUPPDU_SHIFT 4u -#define APRXS_MUPPDU(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_MUPPDU_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_MUPPDU_POS(rev)]) & \ - APRXS_MUPPDU_MASK) >> APRXS_MUPPDU_SHIFT) - -// OBSS status -#define APRXS_OBSS_STS_POS(rev) APRXS_WD0_H_POS(rev) -#define APRXS_OBSS_STS_MASK 0xE0u -#define APRXS_OBSS_STS_SHIFT 5u -#define APRXS_OBSS_STS(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_OBSS_STS_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_OBSS_STS_POS(rev)]) & \ - APRXS_OBSS_STS_MASK) >> APRXS_OBSS_STS_SHIFT) - -// coremask -#define APRXS_COREMASK_POS(rev) APRXS_WD1_L_POS(rev) -#define APRXS_COREMASK_MASK 0xFu -#define APRXS_COREMASK(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_COREMASK_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_COREMASK_POS(rev)]) & \ - APRXS_COREMASK_MASK) - -// antcfg -#define APRXS_ANTCFG_POS(rev) APRXS_WD1_L_POS(rev) -#define APRXS_ANTCFG_MASK 0xF0u -#define APRXS_ANTCFG_SHIFT 4u -#define APRXS_ANTCFG(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_ANTCFG_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_ANTCFG_POS(rev)]) & \ - APRXS_ANTCFG_MASK) >> APRXS_ANTCFG_SHIFT) - -// final BW classification -#define APRXS_SUBBAND_POS(rev) APRXS_WD1_H_POS(rev) -#define APRXS_SUBBAND_MASK 0xFFu -#define APRXS_SUBBAND(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_SUBBAND_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_SUBBAND_POS(rev)]) & \ - APRXS_SUBBAND_MASK) - -// Rx power Antenna0 -#define APRXS_RXPWR_ANT0_POS(rev) APRXS_WD2_L_POS(rev) -#define APRXS_RXPWR_ANT0_MASK 0xFFu -#define APRXS_RXPWR_ANT0(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_RXPWR_ANT0_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_RXPWR_ANT0_POS(rev)]) & \ - APRXS_RXPWR_ANT0_MASK) - -// Rx power Antenna1 -#define APRXS_RXPWR_ANT1_POS(rev) APRXS_WD2_H_POS(rev) -#define APRXS_RXPWR_ANT1_MASK 0xFFu -#define APRXS_RXPWR_ANT1(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_RXPWR_ANT1_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_RXPWR_ANT1_POS(rev)]) & \ - APRXS_RXPWR_ANT1_MASK) - -// Rx power Antenna2 -#define APRXS_RXPWR_ANT2_POS(rev) APRXS_WD3_L_POS(rev) -#define APRXS_RXPWR_ANT2_MASK 0xFFu -#define APRXS_RXPWR_ANT2(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_RXPWR_ANT2_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_RXPWR_ANT2_POS(rev)]) & \ - APRXS_RXPWR_ANT2_MASK) - -// Rx power Antenna3 -#define APRXS_RXPWR_ANT3_POS(rev) APRXS_WD3_H_POS(rev) -#define APRXS_RXPWR_ANT3_MASK 0xFFu -#define APRXS_RXPWR_ANT3(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_RXPWR_ANT3_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_RXPWR_ANT3_POS(rev)]) & \ - APRXS_RXPWR_ANT3_MASK) - -// RX ELNA INDEX ANT0 -#define APRXS_ELNA_IDX_ANT0_POS(rev) APRXS_WD20_L_POS(rev) -#define APRXS_ELNA_IDX_ANT0_MASK 0x2u -#define APRXS_ELNA_IDX_ANT0_SHIFT 1u -#define APRXS_ELNA_IDX_ANT0(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_ELNA_IDX_ANT0_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_ELNA_IDX_ANT0_POS(rev)]) & \ - APRXS_ELNA_IDX_ANT0_MASK) >> APRXS_ELNA_IDX_ANT0_SHIFT) - -// RX ELNA INDEX ANT1 -#define APRXS_ELNA_IDX_ANT1_POS(rev) APRXS_WD20_L_POS(rev) -#define APRXS_ELNA_IDX_ANT1_MASK 0x20u -#define APRXS_ELNA_IDX_ANT1_SHIFT 5u -#define APRXS_ELNA_IDX_ANT1(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_ELNA_IDX_ANT1_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_ELNA_IDX_ANT1_POS(rev)]) & \ - APRXS_ELNA_IDX_ANT1_MASK) >> APRXS_ELNA_IDX_ANT1_SHIFT) - -// RX TIA INDEX ANT0 LO -#define APRXS_TIA_IDX_ANT0_POS(rev) APRXS_WD16_L_POS(rev) -#define APRXS_TIA_IDX_ANT0_MASK 0x1Cu -#define APRXS_TIA_IDX_ANT0_SHIFT 2u -#define APRXS_TIA_IDX_ANT0(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_TIA_IDX_ANT0_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_TIA_IDX_ANT0_POS(rev)]) & \ - APRXS_TIA_IDX_ANT0_MASK) >> APRXS_TIA_IDX_ANT0_SHIFT) - -// RX TIA INDEX ANT1 LO -#define APRXS_TIA_IDX_ANT1_POS(rev) APRXS_WD18_L_POS(rev) -#define APRXS_TIA_IDX_ANT1_MASK 0x1Cu -#define APRXS_TIA_IDX_ANT1_SHIFT 2u -#define APRXS_TIA_IDX_ANT1(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_TIA_IDX_ANT1_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_TIA_IDX_ANT1_POS(rev)]) & \ - APRXS_TIA_IDX_ANT1_MASK) >> APRXS_TIA_IDX_ANT1_SHIFT) - -// RX VSW INDEX ANT0 -#define APRXS_VSW_IDX_ANT0_POS(rev) APRXS_WD20_L_POS(rev) -#define APRXS_VSW_IDX_ANT0_MASK 0x8u -#define APRXS_VSW_IDX_ANT0_SHIFT 3u -#define APRXS_VSW_IDX_ANT0(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_VSW_IDX_ANT0_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_VSW_IDX_ANT0_POS(rev)]) & \ - APRXS_VSW_IDX_ANT0_MASK) >> APRXS_VSW_IDX_ANT0_SHIFT) - -// RX VSW INDEX ANT1 -#define APRXS_VSW_IDX_ANT1_POS(rev) APRXS_WD20_L_POS(rev) -#define APRXS_VSW_IDX_ANT1_MASK 0x80u -#define APRXS_VSW_IDX_ANT1_SHIFT 7u -#define APRXS_VSW_IDX_ANT1(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_VSW_IDX_ANT1_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_VSW_IDX_ANT1_POS(rev)]) & \ - APRXS_VSW_IDX_ANT1_MASK) >> APRXS_VSW_IDX_ANT1_SHIFT) - -// RSSI fractional bits -#define APRXS_RXPWR_FRAC_POS(rev) APRXS_WD4_L_POS(rev) -#define APRXS_RXPWR_FRAC_MASK 0xFFu -#define APRXS_RXPWR_FRAC(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_RXPWR_FRAC_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_RXPWR_FRAC_POS(rev)]) & \ - APRXS_RXPWR_FRAC_MASK) - -// Ucode overwrites ClipCount with GILTF -#define APRXS_GILTF_POS(rev) APRXS_WD4_H_POS(rev) -#define APRXS_GILTF_MASK 0x18u -#define APRXS_GILTF_SHIFT 3u -#define APRXS_GILTF(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_GILTF_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_GILTF_POS(rev)]) & \ - APRXS_GILTF_MASK) >> APRXS_GILTF_SHIFT) - -#define APRXS_DYNBWINNONHT_POS(rev) APRXS_WD4_H_POS(rev) -#define APRXS_DYNBWINNONHT_MASK 0x20u -#define APRXS_DYNBWINNONHT_SHIFT 5u -#define APRXS_DYNBWINNONHT(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_DYNBWINNONHT_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_DYNBWINNONHT_POS(rev)]) & \ - APRXS_DYNBWINNONHT_MASK) >> APRXS_DYNBWINNONHT_SHIFT) - -#define APRXS_MCSSQSNR0_POS(rev) APRXS_WD5_L_POS(rev) -#define APRXS_MCSSQSNR0_MASK 0xFFu -#define APRXS_MCSSQSNR0(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_MCSSQSNR0_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_MCSSQSNR0_POS(rev)]) & \ - APRXS_MCSSQSNR0_MASK) - -#define APRXS_MCSSQSNR1_POS(rev) APRXS_WD5_H_POS(rev) -#define APRXS_MCSSQSNR1_MASK 0xFFu -#define APRXS_MCSSQSNR1(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_MCSSQSNR1_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_MCSSQSNR1_POS(rev)]) & \ - APRXS_MCSSQSNR1_MASK) - -#define APRXS_MCSSQSNR2_POS(rev) APRXS_WD6_L_POS(rev) -#define APRXS_MCSSQSNR2_MASK 0xFFu -#define APRXS_MCSSQSNR2(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_MCSSQSNR2_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_MCSSQSNR2_POS(rev)]) & \ - APRXS_MCSSQSNR2_MASK) - -#define APRXS_CHBWINNONHT_POS(rev) APRXS_WD8_H_POS(rev) -#define APRXS_CHBWINNONHT_MASK 0x3u -#define APRXS_CHBWINNONHT(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_CHBWINNONHT_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_CHBWINNONHT_POS(rev)]) & \ - APRXS_CHBWINNONHT_MASK) - -// User type -#define APRXS_USTY_POS(rev) APRXS_WD23_H_POS(rev) -#define APRXS_USTY_MASK 0xE0u -#define APRXS_USTY_SHIFT 0x5u -#define APRXS_USTY(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_USTY_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_USTY_POS(rev)]) & \ - APRXS_USTY_MASK) >> APRXS_USTY_SHIFT) - -// 11ax frame format -#define APRXS_AXFF_POS(rev) APRXS_WD20_H_POS(rev) -#define APRXS_AXFF_MASK 0x7u -#define APRXS_AXFF(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_AXFF_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_AXFF_POS(rev)]) & \ - APRXS_AXFF_MASK) - -// MCS -#define APRXS_AXMCS_POS(rev) APRXS_WD21_H_POS(rev) -#define APRXS_AXMCS_MASK 0xFu -#define APRXS_AXMCS(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_AXMCS_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_AXMCS_POS(rev)]) & \ - APRXS_AXMCS_MASK) - -// Coding -#define APRXS_CODING_POS(rev) APRXS_WD21_H_POS(rev) -#define APRXS_CODING_MASK 0x10u -#define APRXS_CODING_SHIFT 4u -#define APRXS_CODING(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_CODING_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_CODING_POS(rev)]) & \ - APRXS_CODING_MASK) >> APRXS_CODING_SHIFT) - -// STAID -#define APRXS_AX_STAID_L_POS(rev) APRXS_WD22_L_POS(rev) -#define APRXS_AX_STAID_L_MASK 0xFFu -#define APRXS_AX_STAID_L(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_AX_STAID_L_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_AX_STAID_L_POS(rev)]) & \ - APRXS_AX_STAID_L_MASK) - -#define APRXS_AX_STAID_H_POS(rev) APRXS_WD22_H_POS(rev) -#define APRXS_AX_STAID_H_MASK 0x03u -#define APRXS_AX_STAID_H(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_AX_STAID_H_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_AX_STAID_H_POS(rev)]) & \ - APRXS_AX_STAID_H_MASK) - -#define APRXS_AX_STAID(rxh, rev, min_rev) ((APRXS_AX_STAID_H(rxh, rev, min_rev) << 1) |\ - APRXS_AX_STAID_L(rxh, rev, min_rev)) - -// NSTS -#define APRXS_NSTS_POS(rev) APRXS_WD22_H_POS(rev) -#define APRXS_NSTS_MASK 0x38u -#define APRXS_NSTS_SHIFT 3u -#define APRXS_NSTS(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_DCM_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_DCM_POS(rev)]) & \ - APRXS_NSTS_MASK) >> APRXS_NSTS_SHIFT) - -// TXBF -#define APRXS_TXBF_POS(rev) APRXS_WD22_H_POS(rev) -#define APRXS_TXBF_MASK 0x40u -#define APRXS_TXBF_SHIFT 6u -#define APRXS_TXBF(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_TXBF_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_TXBF_POS(rev)]) & \ - APRXS_TXBF_MASK) >> APRXS_TXBF_SHIFT) - -//DCM -#define APRXS_DCM_POS(rev) APRXS_WD22_H_POS(rev) -#define APRXS_DCM_MASK 0x80u -#define APRXS_DCM_SHIFT 7u -#define APRXS_DCM(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_DCM_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_DCM_POS(rev)]) & \ - APRXS_DCM_MASK) >> APRXS_DCM_SHIFT) - -// RU Offset -#define APRXS_AX_RUALLOC_POS(rev) APRXS_WD23_L_POS(rev) -#define APRXS_AX_RUALLOC_MASK 0x7Fu -#define APRXS_AX_RUALLOC_SHIFT 0u -#define APRXS_AX_RUALLOC(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_AX_RUALLOC_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_AX_RUALLOC_POS(rev)]) & \ - APRXS_AX_RUALLOC_MASK) >> APRXS_AX_RUALLOC_SHIFT) - -#define APRXS_PE_L_POS(rev) APRXS_WD23_L_POS(rev) -#define APRXS_PE_L_MASK 0x80u -#define APRXS_PE_L_SHIFT 7u -#define APRXS_PE_L(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_PE_L_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_PE_L_POS(rev)]) & \ - APRXS_PE_L_MASK) >> APRXS_PE_L_SHIFT) - -#define APRXS_PE_H_POS(rev) APRXS_WD23_H_POS(rev) -#define APRXS_PE_H_MASK 0x3u -#define APRXS_PE_H(rxh, rev, min_rev) \ - ((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_PE_H_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_PE_H_POS(rev)]) & \ - APRXS_PE_H_MASK) - -#define APRXS_PE(rxh, rev, rev_min) \ - ((APRXS_PE_H(rxh, rev, rev_min) << 1) | APRXS_PE_L(rxh, rev, rev_min)) - -#define APRXS_RU_POS(rev) APRXS_WD23_H_POS(rev) -#define APRXS_RU_MASK 0x1Cu -#define APRXS_RU_SHIFT 2u -#define APRXS_RU(rxh, rev, min_rev) \ - (((D11REV_MAJ_MIN_GE(rev, min_rev, 87, 1) ? \ - (rxh)->ge87_1.PHYRXSTATUS[APRXS_RU_POS(rev)] : \ - (rxh)->ge85.PHYRXSTATUS[APRXS_RU_POS(rev)]) & \ - APRXS_RU_MASK) >> APRXS_RU_SHIFT) - -#endif /* _d11_autophyrxsts_ */ - -#if defined(AUTO_PHYRXSTS) -#define AUTO_PHYRXSTS_ENAB() 1u -#else -#define AUTO_PHYRXSTS_ENAB() 0u -#endif /* AUTO_PHYRXSTS */ - -/* PhyRxStatus_0: */ -#define PRXS0_FT_MASK 0x0003u /**< [PRE-HE] NPHY only: CCK, OFDM, HT, VHT */ -#define PRXS0_CLIP_MASK 0x000Cu /**< NPHY only: clip count adjustment steps by AGC */ -#define PRXS0_CLIP_SHIFT 2u /**< SHIFT bits for clip count adjustment */ -#define PRXS0_UNSRATE 0x0010u /**< PHY received a frame with unsupported rate */ -#define PRXS0_UNSRATE_SHIFT 4u -#define PRXS0_RXANT_UPSUBBAND 0x0020u /**< GPHY: rx ant, NPHY: upper sideband */ -#define PRXS0_LCRS 0x0040u /**< CCK frame only: lost crs during cck frame reception */ -#define PRXS0_SHORTH 0x0080u /**< Short Preamble */ -#define PRXS0_SHORTH_SHIFT 7u -#define PRXS0_PLCPFV 0x0100u /**< PLCP violation */ -#define PRXS0_PLCPFV_SHIFT 8u -#define PRXS0_PLCPHCF 0x0200u /**< PLCP header integrity check failed */ -#define PRXS0_PLCPHCF_SHIFT 9u -#define PRXS0_GAIN_CTL 0x4000u /**< legacy PHY gain control */ -#define PRXS0_ANTSEL_MASK 0xF000u /**< NPHY: Antennas used for received frame, bitmask */ -#define PRXS0_ANTSEL_SHIFT 12u /**< SHIFT bits for Antennas used for received frame */ -#define PRXS0_PPDU_MASK 0x1000u /**< PPDU type SU/MU */ - -/* subfield PRXS0_FT_MASK [PRXS0_PRE_HE_FT_MASK] */ -#define PRXS0_CCK 0x0000u -#define PRXS0_OFDM 0x0001u /**< valid only for G phy, use rxh->RxChan for A phy */ -#define PRXS0_PREN 0x0002u -#define PRXS0_STDN 0x0003u - -/* subfield PRXS0_ANTSEL_MASK */ -#define PRXS0_ANTSEL_0 0x0u /**< antenna 0 is used */ -#define PRXS0_ANTSEL_1 0x2u /**< antenna 1 is used */ -#define PRXS0_ANTSEL_2 0x4u /**< antenna 2 is used */ -#define PRXS0_ANTSEL_3 0x8u /**< antenna 3 is used */ - -/* PhyRxStatus_1: */ -#define PRXS1_JSSI_MASK 0x00FFu -#define PRXS1_JSSI_SHIFT 0u -#define PRXS1_SQ_MASK 0xFF00u -#define PRXS1_SQ_SHIFT 8u -#define PRXS1_COREMAP 0x000Fu /**< core enable bits for core 0/1/2/3 */ -#define PRXS1_ANTCFG 0x00F0u /**< anttenna configuration bits */ - -#define PHY_COREMAP_LT85(rxh, rev) \ - ((D11REV_GE(rev, 80) ? D11RXHDR_GE80_ACCESS_VAL(rxh, PhyRxStatus_1) : \ - D11RXHDR_LT80_ACCESS_VAL(rxh, PhyRxStatus_1)) & \ - PRXS1_COREMAP) -#define PHY_COREMAP(rev, rev_min, rxh) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_COREMASK(rxh, rev, rev_min) : PHY_COREMAP_LT85(rxh, rev)) - -#define PHY_ANTMAP_LT85(rxh, corerev) \ - (((D11REV_GE(corerev, 80) ? D11RXHDR_GE80_ACCESS_VAL(rxh, PhyRxStatus_1) : \ - D11RXHDR_LT80_ACCESS_VAL(rxh, PhyRxStatus_1)) & \ - PRXS1_ANTCFG) >> 4) -#define PHY_ANTMAP(rev, rev_min, rxh) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_ANTCFG(rxh, rev, rev_min) : PHY_ANTMAP_LT85(rxh, rev)) - -/* nphy PhyRxStatus_1: */ -#define PRXS1_nphy_PWR0_MASK 0x00FF -#define PRXS1_nphy_PWR1_MASK 0xFF00 - -/* PhyRxStatus_2: */ -#define PRXS2_LNAGN_MASK 0xC000 -#define PRXS2_LNAGN_SHIFT 14 -#define PRXS2_PGAGN_MASK 0x3C00 -#define PRXS2_PGAGN_SHIFT 10 -#define PRXS2_FOFF_MASK 0x03FF - -/* nphy PhyRxStatus_2: */ -#define PRXS2_nphy_SQ_ANT0 0x000F /**< nphy overall signal quality for antenna 0 */ -#define PRXS2_nphy_SQ_ANT1 0x00F0 /**< nphy overall signal quality for antenna 0 */ -#define PRXS2_nphy_cck_SQ 0x00FF /**< bphy signal quality(when FT field is 0) */ -#define PRXS3_nphy_SSQ_MASK 0xFF00 /**< spatial conditioning of the two receive channels */ -#define PRXS3_nphy_SSQ_SHIFT 8 - -/* PhyRxStatus_3: */ -#define PRXS3_DIGGN_MASK 0x1800 -#define PRXS3_DIGGN_SHIFT 11 -#define PRXS3_TRSTATE 0x0400 - -/* nphy PhyRxStatus_3: */ -#define PRXS3_nphy_MMPLCPLen_MASK 0x0FFF /**< Mixed-mode preamble PLCP length */ -#define PRXS3_nphy_MMPLCP_RATE_MASK 0xF000 /**< Mixed-mode preamble rate field */ -#define PRXS3_nphy_MMPLCP_RATE_SHIFT 12 - -/* HTPHY Rx Status defines */ -/* htphy PhyRxStatus_0: those bit are overlapped with PhyRxStatus_0 */ -#define PRXS0_BAND 0x0400 /**< 0 = 2.4G, 1 = 5G */ -#define PRXS0_RSVD 0x0800 /**< reserved; set to 0 */ -#define PRXS0_UNUSED 0xF000 /**< unused and not defined; set to 0 */ - -/* htphy PhyRxStatus_1: */ -#define PRXS1_HTPHY_MMPLCPLenL_MASK 0xFF00 /**< Mixmode PLCP Length low byte mask */ - -/* htphy PhyRxStatus_2: */ -#define PRXS2_HTPHY_MMPLCPLenH_MASK 0x000F /**< Mixmode PLCP Length high byte maskw */ -#define PRXS2_HTPHY_MMPLCH_RATE_MASK 0x00F0 /**< Mixmode PLCP rate mask */ -#define PRXS2_HTPHY_RXPWR_ANT0 0xFF00 /**< Rx power on core 0 */ - -/* htphy PhyRxStatus_3: */ -#define PRXS3_HTPHY_RXPWR_ANT1 0x00FF /**< Rx power on core 1 */ -#define PRXS3_HTPHY_RXPWR_ANT2 0xFF00 /**< Rx power on core 2 */ - -/* htphy PhyRxStatus_4: */ -#define PRXS4_HTPHY_RXPWR_ANT3 0x00FF /**< Rx power on core 3 */ -#define PRXS4_HTPHY_CFO 0xFF00 /**< Coarse frequency offset */ - -/* htphy PhyRxStatus_5: */ -#define PRXS5_HTPHY_FFO 0x00FF /**< Fine frequency offset */ -#define PRXS5_HTPHY_AR 0xFF00 /**< Advance Retard */ - -/* ACPHY RxStatus defs */ - -/* ACPHY PhyRxStatus_0: */ -#define PRXS0_ACPHY_FT_MASK 0x0003 /**< CCK, OFDM, HT, VHT */ -#define PRXS0_ACPHY_CLIP_MASK 0x000C /**< clip count adjustment steps by AGC */ -#define PRXS0_ACPHY_CLIP_SHIFT 2 -#define PRXS0_ACPHY_UNSRATE 0x0010 /**< PHY received a frame with unsupported rate */ -#define PRXS0_ACPHY_BAND5G 0x0020 /**< Rx Band indication: 0 -> 2G, 1 -> 5G */ -#define PRXS0_ACPHY_LCRS 0x0040 /**< CCK frame only: lost crs during cck frame reception */ -#define PRXS0_ACPHY_SHORTH 0x0080 /**< Short Preamble (CCK), GF preamble (HT) */ -#define PRXS0_ACPHY_PLCPFV 0x0100 /**< PLCP violation */ -#define PRXS0_ACPHY_PLCPHCF 0x0200 /**< PLCP header integrity check failed */ -#define PRXS0_ACPHY_MFCRS 0x0400 /**< Matched Filter CRS fired */ -#define PRXS0_ACPHY_ACCRS 0x0800 /**< Autocorrelation CRS fired */ -#define PRXS0_ACPHY_SUBBAND_MASK 0xF000 /**< FinalBWClassification: - * lower nibble Bitfield of sub-bands occupied by Rx frame - */ -/* ACPHY PhyRxStatus_1: */ -#define PRXS1_ACPHY_ANT_CORE0 0x0001 /* Antenna Config for core 0 */ -#define PRXS1_ACPHY_SUBBAND_MASK_GEN2 0xFF00 /**< FinalBWClassification: - * lower byte Bitfield of sub-bands occupied by Rx frame - */ -#define PRXS0_ACPHY_SUBBAND_SHIFT 12 -#define PRXS1_ACPHY_SUBBAND_SHIFT_GEN2 8 - -/* acphy PhyRxStatus_3: */ -#define PRXS2_ACPHY_RXPWR_ANT0 0xFF00 /**< Rx power on core 1 */ -#define PRXS3_ACPHY_RXPWR_ANT1 0x00FF /**< Rx power on core 1 */ -#define PRXS3_ACPHY_RXPWR_ANT2 0xFF00 /**< Rx power on core 2 */ -#define PRXS3_ACPHY_SNR_ANT0 0xFF00 /* SNR on core 0 */ - -/* acphy PhyRxStatus_4: */ -/** FinalBWClassification:upper nibble of sub-bands occupied by Rx frame */ -#define PRXS4_ACPHY_SUBBAND_MASK 0x000F -#define PRXS4_ACPHY_RXPWR_ANT3 0x00FF /**< Rx power on core 3 */ -#define PRXS4_ACPHY_SNR_ANT1 0xFF00 /* SNR on core 1 */ - -#define PRXS5_ACPHY_CHBWINNONHT_MASK 0x0003 -#define PRXS5_ACPHY_CHBWINNONHT_20MHZ 0 -#define PRXS5_ACPHY_CHBWINNONHT_40MHZ 1 -#define PRXS5_ACPHY_CHBWINNONHT_80MHZ 2 -#define PRXS5_ACPHY_CHBWINNONHT_160MHZ 3 /* includes 80+80 */ -#define PRXS5_ACPHY_DYNBWINNONHT_MASK 0x0004 - -/** Get Rx power on core 0 */ -#define ACPHY_RXPWR_ANT0(rxs) (((rxs)->lt80.PhyRxStatus_2 & PRXS2_ACPHY_RXPWR_ANT0) >> 8) -/** Get Rx power on core 1 */ -#define ACPHY_RXPWR_ANT1(rxs) ((rxs)->lt80.PhyRxStatus_3 & PRXS3_ACPHY_RXPWR_ANT1) -/** Get Rx power on core 2 */ -#define ACPHY_RXPWR_ANT2(rxs) (((rxs)->lt80.PhyRxStatus_3 & PRXS3_ACPHY_RXPWR_ANT2) >> 8) -/** Get Rx power on core 3 */ -#define ACPHY_RXPWR_ANT3(rxs) ((rxs)->lt80.PhyRxStatus_4 & PRXS4_ACPHY_RXPWR_ANT3) - -/** MCSSQSNR location access. MCSSQ usage is limited by chip specific impl, - * and there is no way to commonize these status location yet. - * TODO: When the storage locations are settled we need to revisit - * this defs controls. - */ - -/* exception handling */ -#ifdef PHY_CORE_MAX -#if PHY_CORE_MAX > 4 -#error "PHY_CORE_MAX is exceeded more than MCSSQSNR defs (4)" -#endif -#endif /* PHY_CORE_MAX */ - -/* rev 48/55/59 are obsoleted for SNR in trunk */ -#define D11_PRXS_MCSSQ_SNR_SUPPORT(corerev) (D11REV_GE((corerev), 80)) - -#define ACPHY_SNR_MASK (0xFF) -#define ACPHY_SNR_SHIFT (8) - -#define PRXS5_ACPHY_DYNBWINNONHT(rxs) ((rxs)->lt80.PhyRxStatus_5 & PRXS5_ACPHY_DYNBWINNONHT_MASK) -#define PRXS5_ACPHY_CHBWINNONHT(rxs) ((rxs)->lt80.PhyRxStatus_5 & PRXS5_ACPHY_CHBWINNONHT_MASK) - -#define D11N_MMPLCPLen(rxs) ((rxs)->lt80.PhyRxStatus_3 & PRXS3_nphy_MMPLCPLen_MASK) -#define D11HT_MMPLCPLen(rxs) ((((rxs)->lt80.PhyRxStatus_1 & PRXS1_HTPHY_MMPLCPLenL_MASK) >> 8) | \ - (((rxs)->lt80.PhyRxStatus_2 & PRXS2_HTPHY_MMPLCPLenH_MASK) << 8)) - -/* REV80 Defintions (corerev >= 80) */ - -/** Dma_flags Masks */ -#define RXS_PHYRXST_VALID_REV_GE80 0x02 - -/** Get RxStatus1 */ -#define RXSTATUS1_REV_GE87_1(rxs) ((rxs)->ge87_1.RxStatus1) -#define RXSTATUS1_REV_GE80(rxs) ((rxs)->ge80.RxStatus1) -#define RXSTATUS1_REV_LT80(rxs) ((rxs)->lt80.RxStatus1) - -#define PHY_RXSTATUS1(corerev, corerev_minor, rxs) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? RXSTATUS1_REV_GE87_1(rxs) : \ - D11REV_GE(corerev, 80) ? RXSTATUS1_REV_GE80(rxs) : \ - RXSTATUS1_REV_LT80(rxs)) - -/* (FT Mask) PhyRxStatus_0: */ -#define PRXS0_FT_MASK_REV_LT80 PRXS0_FT_MASK /**< (corerev < 80) frame type field mask */ - -#define PRXS0_FT_SHIFT_REV_GE80 8 -#define PRXS0_FT_MASK_REV_GE80 0x0700 /** - * (corerev >= 80) frame type field mask. - * - * 0 = CCK, 1 = 11a/g legacy OFDM, - * 2 = HT, 3 = VHT, 4 = 11ah, 5 = HE, - * 6-15 Rsvd. - */ - -/* * -* Macro to find Frame type from RX Hdr based on corerev. -* -* Note: From rev80 onwards frame type is indicated only -* in the phyrxstatus, which is valid only for the last -* MPDU of an AMPDU. Since FT is required for every MPDU, -* frametype for core-revs >= 80, shall be -* provided in bits (8:10) of MuRate field in RXH. -* -*/ -#define D11PPDU_FT(rxh, rev) (\ - (D11REV_GE(rev, 80) ? \ - ((D11RXHDR_ACCESS_VAL(rxh, rev, 0, MuRate) & PRXS_FT_MASK(rev)) >> \ - (PRXS0_FT_SHIFT_REV_GE80)) : \ - (D11RXHDR_LT80_ACCESS_VAL(rxh, PhyRxStatus_0) & PRXS_FT_MASK(rev)))) - -#define PRXS_UNSRATE_LT85(rxh, rev) \ - (((D11REV_GE(rev, 80) ? D11RXHDR_GE80_ACCESS_VAL(rxh, PhyRxStatus_0) : \ - D11RXHDR_LT80_ACCESS_VAL(rxh, PhyRxStatus_0)) & \ - PRXS0_UNSRATE) >> PRXS0_UNSRATE_SHIFT) - -#define PRXS_UNSRATE(rxh, rev, min_rev) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_UNSRATE(rxh, rev, min_rev) : PRXS_UNSRATE_LT85(rxh, rev)) - -// 1: short (or GF) preamble, 0: long (or MM) preamble -#define PRXS_SHORTH_LT85(rxh, rev) \ - (((D11REV_GE(rev, 80) ? D11RXHDR_GE80_ACCESS_VAL(rxh, PhyRxStatus_0) : \ - D11RXHDR_LT80_ACCESS_VAL(rxh, PhyRxStatus_0)) & \ - PRXS0_SHORTH) >> PRXS0_SHORTH_SHIFT) -#define PRXS_SHORTH(rxh, rev, min_rev) \ - (AUTO_PHYRXSTS_ENAB() ? APRXS_SHORTH(rxh, rev, min_rev) : \ - PRXS_SHORTH_LT85(rxh, rev)) - -#define PRXS_PLCPFV_LT85(rxh, rev) \ - (((D11REV_GE(rev, 80) ? D11RXHDR_GE80_ACCESS_VAL(rxh, PhyRxStatus_0) : \ - D11RXHDR_LT80_ACCESS_VAL(rxh, PhyRxStatus_0)) & \ - PRXS0_PLCPFV) >> PRXS0_PLCPFV_SHIFT) -#define PRXS_PLCPFV(rxh, rev, rev_min) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_PLCPFV(rxh, rev, rev_min) : PRXS_PLCPFV_LT85(rxh, rev)) - -#define PRXS_PLCPHCF_LT85(rxh, rev) \ - (((D11REV_GE(rev, 80) ? D11RXHDR_GE80_ACCESS_VAL(rxh, PhyRxStatus_0) : \ - D11RXHDR_LT80_ACCESS_VAL(rxh, PhyRxStatus_0)) & \ - PRXS0_PLCPHCF) >> PRXS0_PLCPHCF_SHIFT) -#define PRXS_PLCPHCF(rxh, rev, rev_min) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_PLCPHCF(rxh, rev, rev_min) : PRXS_PLCPHCF_LT85(rxh, rev)) - -// final BW classification -#define PRXS_SUBBAND_ACPHY(rxh, rev, rev_min) \ - (((D11RXHDR_LT80_ACCESS_VAL(rxh, PhyRxStatus_0) & \ - PRXS0_ACPHY_SUBBAND_MASK) >> PRXS0_ACPHY_SUBBAND_SHIFT) | \ - ((D11RXHDR_LT80_ACCESS_VAL(rxh, PhyRxStatus_4) & \ - PRXS4_ACPHY_SUBBAND_MASK) << 4)) -#define PRXS_SUBBAND_ACPHY2(rxh, rev, rev_min) \ - (((D11REV_GE(rev, 80) ? D11RXHDR_GE80_ACCESS_VAL(rxh, PhyRxStatus_1) : \ - D11RXHDR_LT80_ACCESS_VAL(rxh, PhyRxStatus_1)) & PRXS1_ACPHY2_SUBBAND_MASK) >> \ - PRXS1_ACPHY2_SUBBAND_SHIFT) - -#define PRXS_SUBBAND(rxh, rev, rev_min, phyrev) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_SUBBAND(rxh, rev, rev_min) : (ACREV_GE(phyrev, 32) ? \ - PRXS_SUBBAND_ACPHY2(rxh, rev, rev_min) : \ - PRXS_SUBBAND_ACPHY(rxh, rev, rev_min))) - -/* Macros to access MCS, NSTS and MU valididity from MuRate field in corerev > 80 RXH */ -#define RXS_MU_VALID_MASK_REV80 0x0080 -#define RXS_MU_VALID_SHIFT_REV80 7 -#define RXS_MCS_MASK_REV80 0x000F -#define RXS_MCS_SHIFT_REV80 0 -#define RXS_NSTS_MASK_REV80 0x0070 -#define RXS_NSTS_SHIFT_REV80 4 - -#define D11PPDU_ISMU_REV80(rxh, corerev, corerev_minor) \ - ((D11RXHDR_ACCESS_VAL(rxh, corerev, corerev_minor, MuRate) & \ - (RXS_MU_VALID_MASK_REV80)) >> RXS_MU_VALID_SHIFT_REV80) -#define D11RXHDR_GE80_GET_MCS(rxh, corerev, corerev_minor) \ - ((D11RXHDR_ACCESS_VAL(rxh, corerev, corerev_minor, MuRate) & \ - (RXS_MCS_MASK_REV80)) >> RXS_MCS_SHIFT_REV80) -#define D11RXHDR_GE80_GET_NSTS(rxh, corerev, corerev_minor) \ - ((D11RXHDR_ACCESS_VAL(rxh, corerev, corerev_minor, MuRate) & \ - (RXS_NSTS_MASK_REV80)) >> RXS_NSTS_SHIFT_REV80) - -/* subfield PRXS0_FT_MASK_REV_GE80 */ -#define PRXS0_HE 0x0004 /**< HE frame type */ - -/* (Corerev >= 80) PhyRxStatus_2: */ -#define PRXS2_RXPWR_ANT0_REV_GE80 0x00FF /**< (corerev >= 80) Rx power on first antenna */ -#define PRXS2_RXPWR_ANT1_REV_GE80 0xFF00 /**< (corerev >= 80) Rx power on second antenna */ - -/* (Corerev >= 80) PhyRxStatus_3: */ -#define PRXS3_RXPWR_ANT2_REV_GE80 0x00FF /**< (corerev >= 80) Rx power on third antenna */ -#define PRXS3_RXPWR_ANT3_REV_GE80 0xFF00 /** - * (corerev >= 80) Rx power on fourth antenna. - * - * Note: For PHY revs 3 and > 4, OCL Status - * byte 0 will be reported if PHY register - * OCL_RxStatus_Ctrl is set to 0x2 or 0x6. - */ -#define PRXS3_RXPWR_FRAC_REV_GE80 0xFFu - -/** Get Rx power on ANT 0 */ -#define RXPWR_ANT0_REV_GE80(rxs) ((rxs)->ge80.PhyRxStatus_2 & \ - (PRXS2_RXPWR_ANT0_REV_GE80)) - -#define PHY_RXPWR_ANT0(corerev, corerev_minor, rxs) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_RXPWR_ANT0(rxs, corerev, corerev_minor) : (D11REV_GE(corerev, 80) ? \ - RXPWR_ANT0_REV_GE80(rxs) : ACPHY_RXPWR_ANT0(rxs))) - -/** Get Rx power on ANT 1 */ -#define RXPWR_ANT1_REV_GE80(rxs) (((rxs)->ge80.PhyRxStatus_2 & \ - (PRXS2_RXPWR_ANT1_REV_GE80)) >> 8) - -#define PHY_RXPWR_ANT1(corerev, corerev_minor, rxs) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_RXPWR_ANT1(rxs, corerev, corerev_minor) : (D11REV_GE(corerev, 80) ? \ - RXPWR_ANT1_REV_GE80(rxs) : ACPHY_RXPWR_ANT1(rxs))) - -/** Get Rx power on ANT 2 */ -#define RXPWR_ANT2_REV_GE80(rxs) ((rxs)->ge80.PhyRxStatus_3 & \ - (PRXS3_RXPWR_ANT2_REV_GE80)) - -#define PHY_RXPWR_ANT2(corerev, corerev_minor, rxs) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_RXPWR_ANT2(rxs, corerev, corerev_minor) : (D11REV_GE(corerev, 80) ? \ - RXPWR_ANT2_REV_GE80(rxs) : ACPHY_RXPWR_ANT2(rxs))) - -/** Get Rx power on ANT 3 */ -#define RXPWR_ANT3_REV_GE80(rxs) (((rxs)->ge80.PhyRxStatus_3 & \ - (PRXS3_RXPWR_ANT3_REV_GE80)) >> 8) - -#define PHY_RXPWR_ANT3(corerev, corerev_minor, rxs) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_RXPWR_ANT3(rxs, corerev, corerev_minor) : (D11REV_GE(corerev, 80) ? \ - RXPWR_ANT3_REV_GE80(rxs) : ACPHY_RXPWR_ANT3(rxs))) - -/* Get the following entries from RXStatus bytes -* for RSSI compensation -* based on factory calibration -* TIA Index -* eLNA Index -* V_path Switch -*/ -#define PHY_ELNA_IDX_ANT0_REV_GE85(corerev, corerev_min, rxs) \ - APRXS_ELNA_IDX_ANT0(rxs, corerev, corerev_min) -#define PHY_ELNA_IDX_ANT1_REV_GE85(corerev, corerev_min, rxs) \ - APRXS_ELNA_IDX_ANT1(rxs, corerev, corerev_min) -#define PHY_TIA_IDX_ANT0_REV_GE85(corerev, corerev_min, rxs) \ - APRXS_TIA_IDX_ANT0(rxs, corerev, corerev_min) -#define PHY_TIA_IDX_ANT1_REV_GE85(corerev, corerev_min, rxs) \ - APRXS_TIA_IDX_ANT1(rxs, corerev, corerev_min) -#define PHY_VSW_IDX_ANT0_REV_GE85(corerev, corerev_min, rxs) \ - APRXS_VSW_IDX_ANT0(rxs, corerev, corerev_min) -#define PHY_VSW_IDX_ANT1_REV_GE85(corerev, corerev_min, rxs) \ - APRXS_VSW_IDX_ANT1(rxs, corerev, corerev_min) - -/** Get RSSI fractional bits */ -#define RXPWR_FRAC_REV_GE80(rxs) ((rxs)->ge80.PhyRxStatus_4 & \ - (PRXS3_RXPWR_FRAC_REV_GE80)) - -#define RXPWR_FRAC(corerev, corerev_minor, rxs) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_RXPWR_FRAC(rxs, corerev, corerev_minor) : (D11REV_GE(corerev, 80) ? \ - RXPWR_FRAC_REV_GE80(rxs) : 0)) - -/* HECAPPHY PhyRxStatus_4: */ -#define PRXS4_DYNBWINNONHT_MASK_REV_GE80 0x1000 -#define PRXS4_DYNBWINNONHT_REV_GE80(rxs) ((rxs)->ge80.PhyRxStatus_4 & \ - PRXS4_DYNBWINNONHT_MASK_REV_GE80) - -#define PRXS_PHY_DYNBWINNONHT(corerev, corerev_minor, rxs) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_DYNBWINNONHT(rxs, corerev, corerev_minor) : (D11REV_GE(corerev, 80) ? \ - PRXS4_DYNBWINNONHT_REV_GE80(rxs) : PRXS5_ACPHY_DYNBWINNONHT(rxs))) - -/** (corerev >= 80) PhyRxStatus_5: MCSSQ SNR for core 0 and 1 */ -#define PRXS5_MCSSQ_SHIFT (8u) -#define PRXS5_MCSSQ_CORE0_REV_GE80 (0x00FF) -#define PRXS5_MCSSQ_CORE1_REV_GE80 (0xFF00) - -#define MCSSQ_SNR_ANT0_GE80(rxs) ((rxs)->ge80.PhyRxStatus_5 & PRXS5_MCSSQ_CORE0_REV_GE80) -#define MCSSQ_SNR_ANT0(rxs, rev, rev_min) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_MCSSQSNR0(rxs, rev, rev_min) : \ - ((rxs)->ge80.PhyRxStatus_5 & PRXS5_MCSSQ_CORE0_REV_GE80)) - -#define MCSSQ_SNR_ANT1_GE80(rxs) (((rxs)->ge80.PhyRxStatus_5 & PRXS5_MCSSQ_CORE1_REV_GE80) \ - >> PRXS5_MCSSQ_SHIFT) -#define MCSSQ_SNR_ANT1(rxs, rev, rev_min) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_MCSSQSNR1(rxs, rev, rev_min) : \ - (((rxs)->ge80.PhyRxStatus_5 & PRXS5_MCSSQ_CORE1_REV_GE80) \ - >> PRXS5_MCSSQ_SHIFT)) - -/** (corerev >= 80) PhyRxStatus_6: MCSSQ SNR for core 2 and 3 */ -#define PRXS6_MCSSQ_SHIFT (8u) -#define PRXS6_MCSSQ_CORE2_REV_GE80 (0x00FF) -#define PRXS6_MCSSQ_CORE3_REV_GE80 (0xFF00) - -#define MCSSQ_SNR_ANT2_GE80(rxs) (((rxs)->ge80.phyrxs_rem[0] & \ - PRXS6_MCSSQ_CORE2_REV_GE80)) -#define MCSSQ_SNR_ANT2(rxs, rev, rev_min) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_MCSSQSNR2(rxs, rev, rev_min) : \ - (((rxs)->ge80.phyrxs_rem[0] & PRXS6_MCSSQ_CORE2_REV_GE80))) - -/* HECAPPHY PhyRxStatus_8 (part of phyrxs_rem[2]) : */ -#define PRXS8_CHBWINNONHT_MASK_REV_GE80 0x0100 -#define PRXS8_CHBWINNONHT_REV_GE80(rxs) ((rxs)->ge80.phyrxs_rem[2] & \ - PRXS8_CHBWINNONHT_MASK_REV_GE80) - -#define PRXS_PHY_CHBWINNONHT(corerev, corerev_minor, rxs) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_CHBWINNONHT(rxs, corerev, corerev_minor) : (D11REV_GE(corerev, 80) ? \ - PRXS8_CHBWINNONHT_REV_GE80(rxs) : PRXS5_ACPHY_CHBWINNONHT(rxs))) - -/* HE phyrxs_rem[4] */ -#define PRXS_REM4_PE_MASK_REV80 0x0380 -#define PRXS_REM4_PE_SHIFT_REV80 7u -#define PRXS_REM4_RU_TYPE_MASK_REV80 0x1c00 -#define PRXS_REM4_RU_TYPE_SHIFT_REV80 10u -#define PRXS_REM4_NUM_USER_SHIFT_REV80 13u -#define PRXS_REM4_NUM_USER_BIT_MASK_REV80 0xe000 - -/* HE phyrxs_rem[5] */ -#define PRXS_REM5_GI_LTF_MASK_REV80 0x0003 -#define PRXS_REM5_GI_LTF_SHIFT_REV80 0u -#define PRXS_REM5_11AX_FF_MASK_REV80 0x0700 -#define PRXS_REM5_11AX_FF_SHIFT_REV80 8u - -/* HE phyrxs_rem[6] */ -#define PRXS_REM6_MCS_MASK_REV80 0x0f00 -#define PRXS_REM6_MCS_SHIFT_REV80 8u -#define PRXS_REM6_CODING_MASK_REV80 0x1000 -#define PRXS_REM6_CODING_SHIFT_REV80 12u - -/* HE phyrxs_rem[7] */ -#define PRXS_REM7_DCM_MASK_REV80 0x8000 -#define PRXS_REM7_DCM_SHIFT_REV80 15u -#define PRXS_REM7_TXBF_MASK_REV80 0x4000 -#define PRXS_REM7_TXBF_SHIFT_REV80 14u -#define PRXS_REM7_NSTS_MASK_REV80 0x3800 -#define PRXS_REM7_NSTS_SHIFT_REV80 11u -#define PRXS_REM7_RU_ALLOC_MASK_REV80 0x007f -#define PRXS_REM7_RU_ALLOC_SHIFT_REV80 0u - -#define PRXS_STAID_MASK 0x07ff -#define PRXS_STAID_SHIFT 0u - -enum { - HE_RU_TYPE_26T = 0, /* 26 tone RU, 0 - 36 */ - HE_RU_TYPE_52T = 1, /* 52 tone RU, 37 - 52 */ - HE_RU_TYPE_106T = 2, /* 106 tone RU, 53 - 60 */ - HE_RU_TYPE_242T = 3, /* 242 tone RU, 61 - 64 */ - HE_RU_TYPE_484T = 4, /* 484 tone RU, 65 - 66 */ - HE_RU_TYPE_996T = 5, /* 996 tone RU, 67 - 68 */ - HE_RU_TYPE_2x996T = 6, /* 2x996 tone RU, 69 */ - HE_RU_TYPE_LAST = 7 /* Reserved, Invalid */ -}; - -#define HE_RU_TYPE_MAX 6 - -/* received PE duration is present in phyrxs_rem[4] bit position [7-9] */ -#define D11PPDU_PE_GE80(rxh, corerev) ((D11RXHDR_GE80_ACCESS_VAL(rxh, phyrxs_rem[4]) & \ - (PRXS_REM4_PE_MASK_REV80)) >> PRXS_REM4_PE_SHIFT_REV80) - -#define D11PPDU_PE(rxh, corerev, corerev_minor) (AUTO_PHYRXSTS_ENAB() ? \ - APRXS_PE(rxh, corerev, corerev_minor) : D11PPDU_PE_GE80(rxh, corerev)) - -/* received RU type is present in phyrxs_rem[4] bit position [10-11] */ -#define D11PPDU_RU_TYPE(rxh, corerev, corerev_minor) \ - (AUTO_PHYRXSTS_ENAB() ? APRXS_RU(rxh, corerev, corerev_minor) : \ - (D11REV_GE(corerev, 80) ? ((D11RXHDR_GE80_ACCESS_VAL(rxh, phyrxs_rem[4]) & \ - (PRXS_REM4_RU_TYPE_MASK_REV80)) >> PRXS_REM4_RU_TYPE_SHIFT_REV80) : 0)) - -/* received he num of user type is present in phyrxs_rem[4] bit position [13-15] */ -#define D11PPDU_HE_NUM_USER_TYPE(rxh, corerev, corerev_min) \ - (AUTO_PHYRXSTS_ENAB() ? APRXS_USTY(rxh, corerev, corerev_min) : \ - (D11REV_GE(corerev, 80) ? ((D11RXHDR_GE80_ACCESS_VAL(rxh, phyrxs_rem[4]) & \ - (PRXS_REM4_NUM_USER_BIT_MASK_REV80)) >> PRXS_REM4_NUM_USER_SHIFT_REV80) : 0)) - -#define D11PPDU_FF_TYPE(rxh, corerev, corerev_minor) \ - (AUTO_PHYRXSTS_ENAB() ? APRXS_AXFF(rxh, corerev, corerev_minor) : \ - (D11REV_GE(corerev, 80) ? ((D11RXHDR_GE80_ACCESS_VAL(rxh, phyrxs_rem[5]) & \ - (PRXS_REM5_11AX_FF_MASK_REV80)) >> PRXS_REM5_11AX_FF_SHIFT_REV80) : 0)) - -/* DCM is present in phyrxs_rem[7] byte 27, bit position [7] */ -#define D11PPDU_DCM(rxh, corerev, corerev_minor) \ - (AUTO_PHYRXSTS_ENAB() ? APRXS_DCM(rxh, corerev, corerev_minor) : \ - (D11REV_GE(corerev, 80) ? ((D11RXHDR_GE80_ACCESS_VAL(rxh, phyrxs_rem[7]) & \ - (PRXS_REM7_DCM_MASK_REV80)) >> PRXS_REM7_DCM_SHIFT_REV80) : 0)) - -/* coding used is present in phyrxs_rem[6] byte:25, bit position [12] */ -#define D11PPDU_CODING(rxh, corerev, corerev_minor) \ - (AUTO_PHYRXSTS_ENAB() ? APRXS_CODING(rxh, corerev, corerev_minor) : \ - (D11REV_GE(corerev, 80) ? ((D11RXHDR_GE80_ACCESS_VAL(rxh, phyrxs_rem[6]) & \ - (PRXS_REM6_CODING_MASK_REV80)) >> PRXS_REM6_CODING_SHIFT_REV80) : 0)) - -/* spatial reuse 2 / STA-ID */ -#define D11PPDU_STAID(rxh, corerev, corerev_minor) \ - (AUTO_PHYRXSTS_ENAB() ? APRXS_AX_STAID(rxh, corerev, corerev_minor) : \ - (D11REV_GE(corerev, 80) ? ((D11RXHDR_GE80_ACCESS_VAL(rxh, phyrxs_rem[7]) & \ - (PRXS_STAID_MASK)) >> PRXS_STAID_SHIFT) : 0)) - -#define D11PPDU_TXBF(rxh, corerev, corerev_minor) \ - (AUTO_PHYRXSTS_ENAB() ? APRXS_TXBF(rxh, corerev, corerev_minor) : \ - (D11REV_GE(corerev, 80) ? ((D11RXHDR_GE80_ACCESS_VAL(rxh, phyrxs_rem[7]) & \ - (PRXS_REM7_TXBF_MASK_REV80)) >> PRXS_REM7_TXBF_SHIFT_REV80) : 0)) - -/* GI_LTF is present in phyrxs_rem[5] bit position [0-1] */ -#define D11PPDU_GI_LTF(rxh, corerev, corerev_minor) \ - (AUTO_PHYRXSTS_ENAB() ? APRXS_GILTF(rxh, corerev, corerev_minor) : \ - (D11REV_GE(corerev, 80) ? ((D11RXHDR_GE80_ACCESS_VAL(rxh, phyrxs_rem[5]) & \ - (PRXS_REM5_GI_LTF_MASK_REV80)) >> PRXS_REM5_GI_LTF_SHIFT_REV80) : 0)) - -/* MCS is present in phyrxs_rem[6] - byte 25, bit position [8-11] */ -#define D11PPDU_MCS(rxh, corerev, corerev_minor) \ - (AUTO_PHYRXSTS_ENAB() ? APRXS_AXMCS(rxh, corerev, corerev_minor) : \ - (D11REV_GE(corerev, 80) ? ((D11RXHDR_GE80_ACCESS_VAL(rxh, phyrxs_rem[6]) & \ - (PRXS_REM6_MCS_MASK_REV80)) >> PRXS_REM6_MCS_SHIFT_REV80) : 0)) - -/* NSTS present in phyrxs_rem[7] bit position [11-13] */ -#define D11PPDU_NSTS(rxh, corerev, corerev_minor) \ - (AUTO_PHYRXSTS_ENAB() ? APRXS_NSTS(rxh, corerev, corerev_minor) : \ - (D11REV_GE(corerev, 80) ? ((D11RXHDR_GE80_ACCESS_VAL(rxh, phyrxs_rem[7]) & \ - (PRXS_REM7_NSTS_MASK_REV80)) >> PRXS_REM7_NSTS_SHIFT_REV80) : 0)) - -/* RU ALLOC present in phyrxs_rem[7]- byte 26; bit position [6:0] */ -#define D11PPDU_RU_ALLOC(rxh, corerev, corerev_minor) \ - (AUTO_PHYRXSTS_ENAB() ? APRXS_AX_RUALLOC(rxh, corerev, corerev_minor) : \ - (D11REV_GE(corerev, 80) ? ((D11RXHDR_GE80_ACCESS_VAL(rxh, phyrxs_rem[7]) & \ - (PRXS_REM7_RU_ALLOC_MASK_REV80)) >> PRXS_REM7_RU_ALLOC_SHIFT_REV80) : 0) - -/* PHY RX status "Frame Type" field mask. */ -#define PRXS_FT_MASK(corerev) \ - (D11REV_GE(corerev, 80) ? (PRXS0_FT_MASK_REV_GE80) : \ - (PRXS0_FT_MASK_REV_LT80)) - -/** - * ACPHY PhyRxStatus0 SubBand (FinalBWClassification) bit defs - * FinalBWClassification is a 4 bit field, each bit representing one 20MHz sub-band - * of a channel. - */ -enum prxs_subband { - PRXS_SUBBAND_20LL = 0x0001, - PRXS_SUBBAND_20LU = 0x0002, - PRXS_SUBBAND_20UL = 0x0004, - PRXS_SUBBAND_20UU = 0x0008, - PRXS_SUBBAND_40L = 0x0003, - PRXS_SUBBAND_40U = 0x000C, - PRXS_SUBBAND_80 = 0x000F, - PRXS_SUBBAND_20LLL = 0x0001, - PRXS_SUBBAND_20LLU = 0x0002, - PRXS_SUBBAND_20LUL = 0x0004, - PRXS_SUBBAND_20LUU = 0x0008, - PRXS_SUBBAND_20ULL = 0x0010, - PRXS_SUBBAND_20ULU = 0x0020, - PRXS_SUBBAND_20UUL = 0x0040, - PRXS_SUBBAND_20UUU = 0x0080, - PRXS_SUBBAND_40LL = 0x0003, - PRXS_SUBBAND_40LU = 0x000c, - PRXS_SUBBAND_40UL = 0x0030, - PRXS_SUBBAND_40UU = 0x00c0, - PRXS_SUBBAND_80L = 0x000f, - PRXS_SUBBAND_80U = 0x00f0, - PRXS_SUBBAND_160 = 0x00ff -}; - -enum prxs_subband_bphy { - PRXS_SUBBAND_BPHY_20L = 0x0000, - PRXS_SUBBAND_BPHY_20U = 0x0001 -}; - -/* ACPHY Gen2 RxStatus defs */ - -/* ACPHY Gen2 PhyRxStatus_0: */ -#define PRXS0_ACPHY2_MUPPDU 0x1000 /**< 0: SU PPDU; 1: MU PPDU */ -#define PRXS0_ACPHY2_OBSS 0xE000 /**< OBSS mitigation state */ - -/* ACPHY Gen2 PhyRxStatus_1: */ -#define PRXS1_ACPHY2_SUBBAND_MASK 0xFF00 /**< FinalBWClassification: - * 8-bit bitfield of sub-bands occupied by Rx frame - */ -#define PRXS1_ACPHY2_SUBBAND_SHIFT 8 - -/* ACPHY Gen2 PhyRxStatus_2: */ -#define PRXS2_ACPHY2_MU_INT 0x003F /**< MU interference processing type */ - -/* ACPHY Gen2 PhyRxStatus_5: */ -#define PRXS5_ACPHY2_RSSI_FRAC 0xFF00 /**< RSSI fractional bits */ - -/* ucode RxStatus1: */ -#define RXS_BCNSENT 0x8000 -#define RXS_TOFINFO 0x4000 /**< Rxed measurement frame processed by ucode */ -#define RXS_GRANTBT 0x2000 /* Indicate medium given to BT */ -#define RXS_SECKINDX_MASK_GE64 0x1fe0 -#define RXS_SECKINDX_MASK 0x07e0 -#define RXS_IS_DEFRAG 0x4 -#define RXS_DEFRAG_SHIFT 2 -#define RXS_SECKINDX_SHIFT 5 -#define RXS_DECERR (1 << 4) -#define RXS_DECATMPT (1 << 3) -#define RXS_PBPRES (1 << 2) /**< PAD bytes to make IP data 4 bytes aligned */ -#define RXS_RESPFRAMETX (1 << 1) -#define RXS_FCSERR (1 << 0) - -/* ucode RxStatus2: */ -#define RXS_AMSDU_MASK 1 -#define RXS_AGGTYPE_MASK 0x6 -#define RXS_AGGTYPE_SHIFT 1 -#define RXS_AMSDU_FIRST 1 -#define RXS_AMSDU_INTERMEDIATE 0 -#define RXS_AMSDU_LAST 2 -#define RXS_AMSDU_N_ONE 3 -#define RXS_TKMICATMPT (1 << 3) -#define RXS_TKMICERR (1 << 4) -#define RXS_PHYRXST_PRISEL_CLR (1 << 5) /**< PR113291: When '1', Indicates that the Rx */ - /* packet was received while the antenna */ - /* (prisel) had been granted to BT. */ -#define RXS_PHYRXST_VALID (1 << 8) -#define RXS_BCNCLSG (1 << 9) /**< Coleasced beacon packet */ -#define RXS_RXANT_MASK 0x3 -#define RXS_RXANT_SHIFT_LT80 12 -#define RXS_RXANT_SHIFT_GE80 5 -#define RXS_LOOPBACK_MODE 4 - -/* Bit definitions for MRXS word for short rx status. */ -/* RXSS = RX Status Short */ -#define RXSS_AMSDU_MASK 1 /**< 1: AMSDU */ -#define RXSS_AGGTYPE_MASK 0x6 /**< 0 intermed, 1 first, 2 last, 3 single/non-AMSDU */ -#define RXSS_AGGTYPE_SHIFT 1 -#define RXSS_PBPRES (1 << 3) /**< two-byte PAD prior to plcp */ -#define RXSS_HDRSTS (1 << 4) /**< header conversion status. 1 enabled, 0 disabled */ -#define RXSS_RES_MASK 0xE0 /**< reserved */ -#define RXSS_MSDU_CNT_MASK 0xFF00 /**< index of this AMSDU sub-frame in the AMSDU */ -#define RXSS_MSDU_CNT_SHIFT 8 - -/* RX signal control definitions */ -/** PHYRXSTAUS validity checker; in-between ampdu, or rxs status isn't valid */ -#define PRXS_IS_VALID(rxh, rev, rev_min) \ - ((D11REV_GE(rev, 80) && \ - (D11RXHDR_ACCESS_VAL(rxh, rev, rev_min, dma_flags) & \ - RXS_PHYRXST_VALID_REV_GE80)) || \ - (D11REV_GE(rev, 64) && !(D11RXHDR_ACCESS_VAL(rxh, \ - rev, rev_min, dma_flags) & RXS_SHORT_MASK)) || \ - (D11RXHDR_ACCESS_VAL(rxh, rev, rev_min, RxStatus2) & RXS_PHYRXST_VALID)) - -/* RxChan */ -#define RXS_CHAN_40 0x1000 -#define RXS_CHAN_5G 0x0800 -#define RXS_CHAN_ID_MASK 0x07f8 -#define RXS_CHAN_ID_SHIFT 3 - -#define C_BTCX_AGGOFF_BLE (1 << 0) -#define C_BTCX_AGGOFF_A2DP (1 << 1) -#define C_BTCX_AGGOFF_PER (1 << 2) -#define C_BTCX_AGGOFF_MULTIHID (1 << 3) -#define C_BTCX_AGG_LMT_SET_HIGH (1 << 4) -#define C_BTCX_AGGOFF_ESCO_SLAVE (1 << 5) - -#define BTCX_HFLG_NO_A2DP_BFR (1 << 0) /**< no check a2dp buffer */ -#define BTCX_HFLG_NO_CCK (1 << 1) /**< no cck rate for null or cts2self */ -#define BTCX_HFLG_NO_OFDM_FBR (1 << 2) /**< no ofdm fbr for null or cts2self */ -#define BTCX_HFLG_NO_INQ_DEF (1 << 3) /**< no defer inquery */ -#define BTCX_HFLG_GRANT_BT (1 << 4) /**< always grant bt */ -#define BTCX_HFLG_ANT2WL (1 << 5) /**< force prisel to wl */ -#define BTCX_HFLG_PS4ACL (1 << 7) /**< use ps null for unsniff acl */ -#define BTCX_HFLG_DYAGG (1 << 8) /**< dynamic tx aggregation */ -#define BTCX_HFLG_SKIPLMP (1 << 10) /**< no LMP check for 4331 (w 20702 A1/A3) */ -#define BTCX_HFLG_ACL_BSD_BLE_SCAN_GRNT (1 << 14) /**< ACL based grant for BLE scan */ - /* indication to ucode */ -#define BTCX_HFLG2_TRAP_RFACTIVE (1 << 0) /* trap when RfActive too long */ -#define BTCX_HFLG2_TRAP_TXCONF (1 << 1) /* trap when coex grants txconf late */ -#define BTCX_HFLG2_TRAP_ANTDLY (1 << 2) /* trap when coex grants antdly late */ -#define BTCX_HFLG2_TRAP_BTTYPE (1 << 3) /* trap when illegal BT tasktype receive */ -/* Bit definitions for M_BTCX_CONFIG */ -#define BTCX_CONFIG_FORCE_TRAP (1 << 13) /* Force a specific BTCoex TRAP when set */ - -/* BTCX_CONFIG bits */ -#define C_BTCX_CONFIG_SLOTTED_STATE_1 (1 << 3) -#define C_BTCX_CONFIG_SLOTTED_STATE_2 (1 << 4) -#define C_BTCX_CONFIG_SLOTTED_STATE_3 (1 << 5) -#define C_BTCX_CONFIG_LOW_RSSI (1 << 7) -#define C_BTCX_CONFIG_BT_STROBE (1 << 9) -#define C_BTCX_CONFIG_SCO_PROT (1 << 10) -#define C_BTCX_CFG_CMN_CTS2SELF (1 << 11) -#define C_BTCX_CONFIG_HPP_STATE (1 << 15) - -#define BTC_PARAMS_FW_START_IDX 1000 /**< starting index of FW only btc params */ -/** BTC_PARAMS_FW definitions */ -typedef enum -{ - // allow rx-agg to be re-enabled after SCO session completes - BTC_FW_RX_REAGG_AFTER_SCO = BTC_PARAMS_FW_START_IDX, - // RSSI threshold at which SCO grant/deny limits are changed dynamically - BTC_FW_RSSI_THRESH_SCO = BTC_PARAMS_FW_START_IDX + 1, - // Enable the dynamic LE scan priority - BTC_FW_ENABLE_DYN_LESCAN_PRI = BTC_PARAMS_FW_START_IDX + 2, - // If Tput(mbps) is above this, then share antenna with BT's LE_SCAN packet type. - BTC_FW_LESCAN_LO_TPUT_THRESH = BTC_PARAMS_FW_START_IDX + 3, - // If Tput(mbps) is below this, then share antenna with BT's LE_SCAN packet type. - // sampled once a second. - BTC_FW_LESCAN_HI_TPUT_THRESH = BTC_PARAMS_FW_START_IDX + 4, - // Numbers of denials before granting LS scans - BTC_FW_LESCAN_GRANT_INT = BTC_PARAMS_FW_START_IDX + 5, - // number of times algorighm changes lescn pri - BTC_FW_LESCAN_ALG_CNT = BTC_PARAMS_FW_START_IDX + 6, - // RSSI threshold at which aggregation will be disabled during frequent BLE activity - BTC_FW_RSSI_THRESH_BLE = BTC_PARAMS_FW_START_IDX + 7, - // AMPDU Aggregation state requested by BTC - BTC_FW_AGG_STATE_REQ = BTC_PARAMS_FW_START_IDX + 8, - // Reserving space for parameters used in other projects - BTC_FW_RSVD_1 = BTC_PARAMS_FW_START_IDX + 9, - BTC_FW_HOLDSCO_LIMIT = BTC_PARAMS_FW_START_IDX + 10, // Lower Limit - BTC_FW_HOLDSCO_LIMIT_HI = BTC_PARAMS_FW_START_IDX + 11, // Higher Limit - BTC_FW_SCO_GRANT_HOLD_RATIO = BTC_PARAMS_FW_START_IDX + 12, // Low Ratio - BTC_FW_SCO_GRANT_HOLD_RATIO_HI = BTC_PARAMS_FW_START_IDX + 13, // High Ratio - BTC_FW_HOLDSCO_HI_THRESH = BTC_PARAMS_FW_START_IDX + 14, // BT Period Threshold - BTC_FW_MOD_RXAGG_PKT_SZ_FOR_SCO = BTC_PARAMS_FW_START_IDX + 15, - /* Modify Rx Aggregation size when SCO/eSCO detected */ - BTC_FW_AGG_SIZE_LOW = BTC_PARAMS_FW_START_IDX + 16, - /* Agg size when BT period < 7500 ms */ - BTC_FW_AGG_SIZE_HIGH = BTC_PARAMS_FW_START_IDX + 17, - /* Agg size when BT period >= 7500 ms */ - BTC_FW_MOD_RXAGG_PKT_SZ_FOR_A2DP = BTC_PARAMS_FW_START_IDX + 18, - /* Enable COEX constraints for TWT scheduling */ - BTC_FW_TWT_COEX_CONSTRAINTS_EN = BTC_PARAMS_FW_START_IDX + 19, - /* Enable Rx Aggregation for P2P_GO and SOFTAP when ACL/A2DP detected */ - BTC_FW_MOD_RXAGG_PKT_SZ_FOR_APMODE_ACL_A2DP = BTC_PARAMS_FW_START_IDX + 20, - /* Disable amsdu dynamicaly during Rx limited aggregation */ - BTC_FW_DISABLE_AMSDU_DURING_LIM_AGG = BTC_PARAMS_FW_START_IDX + 21, - /* Enable acl based grant for ble scan based on number of 2G slots */ - BTC_FW_ENABLE_ACL_GRNT_FOR_BLE_SCAN = BTC_PARAMS_FW_START_IDX + 22, - /* Threshold slot count for 2g band to Enable acl based grant for ble scan during NAN */ - BTC_FW_NAN_THRESHOLD_SLOTS_FOR_2G = BTC_PARAMS_FW_START_IDX + 23, - /* BT task bm override for critical chansw slots */ - BTC_FW_CHANSW_CRT_OVR_BTTASK_BM_L = BTC_PARAMS_FW_START_IDX + 24, - BTC_FW_CHANSW_CRT_OVR_BTTASK_BM_H = BTC_PARAMS_FW_START_IDX + 25, - /* Limited Aggr AP check grace period, # of BTC watchdog timeout */ - BTC_FW_AGG_AP_GRACE_PERIOD = BTC_PARAMS_FW_START_IDX + 26, - /* Limited Aggr AP check buffer limit, sample interval, # of BTC watchdog timeout */ - BTC_FW_AGG_AP_BUFLIM_SMPLINTV = BTC_PARAMS_FW_START_IDX + 27, - /* Limited Aggr AP check excessive DELBA, sample interval, # of BTC watchdog timeout */ - BTC_FW_AGG_AP_DELBA_SMPLINTV = BTC_PARAMS_FW_START_IDX + 28, - /* Limited Aggr AP check excessive DELBA, threshold, # of DELBA */ - BTC_FW_AGG_AP_DELBA_THRESHOLD = BTC_PARAMS_FW_START_IDX + 29, - BTC_FW_MAX_INDICES // Maximum number of btc_fw sw registers -} btcParamsFirmwareDefinitions; - -#define BTC_FW_NUM_INDICES (BTC_FW_MAX_INDICES - BTC_PARAMS_FW_START_IDX) - -// 1: Re-enable aggregation after SCO -#define BTC_FW_RX_REAGG_AFTER_SCO_INIT_VAL 1 - -// 1: Enable limited aggregation for SCO -#define BTC_FW_MOD_RXAGG_PKT_SZ_FOR_SCO_INIT_VAL 0 - -/* Enable Limited aggregation for HI interval BT periodic task only (>=7.5ms) */ -#ifdef WL_BTC_LIMAGG_HI_INT -/* RX aggregation packet size when SCO */ -#define BTC_FW_AGG_SIZE_LOW_INIT_VAL 0 -#else -/* RX aggregation packet size when SCO */ -#define BTC_FW_AGG_SIZE_LOW_INIT_VAL 1 -#endif - -/* aggregation size when BT period < BT_AMPDU_RESIZE_THRESH */ -#define BTC_FW_AGG_SIZE_HIGH_INIT_VAL 2 -/* aggregation size when BT period > BT_AMPDU_RESIZE_THRESH */ -// 0: disable weak-rssi SCO coex feature. If > 0, adjust SCO COEX algorithm for weak RSSI scenario. -#define BTC_FW_RSSI_THRESH_SCO_INIT_VAL 0 - -// 1: Enable limited aggregation for A2DP -#define BTC_FW_MOD_RXAGG_PKT_SZ_FOR_A2DP_INIT_VAL 0 - -// Enable LE Scan Priority Algorithm 0: Disable, 1: Enable -#define BTC_FW_ENABLE_DYN_LESCAN_PRI_INIT_VAL 0 -// If WL Tput below 7 mbps, don't grant background LE Scans -#define BTC_FW_LESCAN_LO_TPUT_THRESH_INIT_VAL 7 -// If WL Tput above 30 mbps, don't grant background LE Scans -#define BTC_FW_LESCAN_HI_TPUT_THRESH_INIT_VAL 30 -// If LE Priority algorithm is triggered, grant one out of 2 LE_SCAN requests -#define BTC_FW_LESCAN_GRANT_INT_INIT_VAL 2 -// If RSSI is weaker than -70 dBm and BLE activity is frequent, then disable -// RX aggregation, and clamp TX aggregation. -#ifdef WL_BTCX_UDM -#define BTC_FW_RSSI_THRESH_BLE_INIT_VAL 100 -#else -#define BTC_FW_RSSI_THRESH_BLE_INIT_VAL 70 -#endif -#define BTC_FW_HOLDSCO_LIMIT_INIT_VAL 100 -#define BTC_FW_HOLDSCO_LIMIT_HI_INIT_VAL 10 -#define BTC_FW_SCO_GRANT_HOLD_RATIO_INIT_VAL 1500 -#define BTC_FW_SCO_GRANT_HOLD_RATIO_HI_INIT_VAL 1000 -#define BTC_FW_HOLDSCO_HI_THRESH_INIT_VAL 7400 -#define BTC_FW_TWT_COEX_CONSTRAINTS_EN_INIT_VAL 1 -/* Aggregation in AP mode (P2P_GO and SOFTAP) when ACL and A2DP */ -#define BTC_FW_MOD_RXAGG_PKT_SZ_FOR_APMODE_ACL_A2DP_INIT_VAL 16 -/* Disable amsdu dynamicaly during Rx limited aggregation */ -#define BTC_FW_DISABLE_AMSDU_DURING_LIM_AGG_INIT_VAL 1 -/* Enable acl based grant for ble scan based on number of 2G slots during NAN */ -#define BTC_FW_ENABLE_ACL_GRNT_FOR_BLE_SCAN_INIT_VAL 0 -/* Threshold slot count for 2g band to Enable acl based grant for ble - * scan during NAN. Setting current value to 8, considering time line is 512ms - * Threshold changes dynamically based on different time line - */ -#define BTC_FW_NAN_THRESHOLD_SLOTS_FOR_2G_INIT_VAL 8 -/* BT task bm override for critical chansw slots -initval */ -#define BTC_FW_CHANSW_CRT_OVR_BTTASK_BM_L_INIT_VAL 0x0000 -#define BTC_FW_CHANSW_CRT_OVR_BTTASK_BM_H_INIT_VAL 0x0020 -#define BTC_FW_AGG_AP_GRACE_PERIOD_VAL 1 -#define BTC_FW_AGG_AP_BUFLIM_SMPLINTV_VAL 1 -#define BTC_FW_AGG_AP_DELBA_SMPLINTV_VAL 5 -#define BTC_FW_AGG_AP_DELBA_THRESHOLD_VAL 3 - -/* NR Coex Params Set/Get via wl btc_params, starting index */ -#define NR5GCX_PARAMS_FW_START_IDX 1200 - -typedef enum NR5GCX_Params { - // Min # of PPDU to be tracked for hysteresis - NR5GCX_FW_MIN_NUM_PPDU = NR5GCX_PARAMS_FW_START_IDX, - // Threshold for data stall detection, percentage - NR5GCX_FW_DATA_STALL_TH = NR5GCX_PARAMS_FW_START_IDX + 1, - // max number of rate recovery attempts - NR5GCX_FW_MAX_NUM_ATTEMPTS = NR5GCX_PARAMS_FW_START_IDX + 2, - // Rate recovery rate check duration - NR5GCX_FW_RR_RATE_CHK_DUR = NR5GCX_PARAMS_FW_START_IDX + 3, - // Rate recovery attempt duration - NR5GCX_FW_RR_ATTEMPT_DUR = NR5GCX_PARAMS_FW_START_IDX + 4, - // NR grant duration after a unsuccessful rate recovery - NR5GCX_FW_RR_UNSC_DUR = NR5GCX_PARAMS_FW_START_IDX + 5, - // Threshold for rate recovery, percentage - NR5GCX_FW_RECOVERY_TH = NR5GCX_PARAMS_FW_START_IDX + 6, - // Threshold for low RSSI - NR5GCX_FW_LOWRSSI_TH = NR5GCX_PARAMS_FW_START_IDX + 7, - // Maximum number of nr5gcx fw params - NR5GCX_FW_MAX_INDICES -} NR5GCXParamsFirmwareDefinitions; - -#define NR5GCX_FW_NUM_INDICES (NR5GCX_FW_MAX_INDICES - NR5GCX_PARAMS_FW_START_IDX) - -#define NR5GCX_FW_MIN_NUM_PPDU_INIT 10u -#define NR5GCX_FW_DATA_STALL_TH_INIT 75u -#define NR5GCX_FW_MAX_NUM_ATTEMPTS_INIT 5u -#define NR5GCX_FW_RR_RATE_CHK_DUR_INIT_MS 60u /* ms */ -#define NR5GCX_FW_RR_ATTEMPT_DUR_INIT_MS 60u /* ms */ -#define NR5GCX_FW_RR_UNSC_DUR_INIT_MS 10000u /* ms */ -#define NR5GCX_FW_RECOVERY_TH_INIT 50u -#define NR5GCX_FW_LOWRSSI_TH_INIT 85u /* dBm */ - -/* RC1 Coex Params Set/Get via wl btc_params, starting index */ -#define RC1CX_PARAMS_FW_START_IDX 1200 - -typedef enum RC1CX_Params { - // Min # of PPDU to be tracked for hysteresis - RC1CX_FW_MIN_NUM_PPDU = RC1CX_PARAMS_FW_START_IDX, - // Threshold for data stall detection, percentage - RC1CX_FW_DATA_STALL_TH = RC1CX_PARAMS_FW_START_IDX + 1, - // max number of rate recovery attempts - RC1CX_FW_MAX_NUM_ATTEMPTS = RC1CX_PARAMS_FW_START_IDX + 2, - // Rate recovery rate check duration - RC1CX_FW_RR_RATE_CHK_DUR = RC1CX_PARAMS_FW_START_IDX + 3, - // Rate recovery attempt duration - RC1CX_FW_RR_ATTEMPT_DUR = RC1CX_PARAMS_FW_START_IDX + 4, - // NR grant duration after a unsuccessful rate recovery - RC1CX_FW_RR_UNSC_DUR = RC1CX_PARAMS_FW_START_IDX + 5, - // Threshold for rate recovery, percentage - RC1CX_FW_RECOVERY_TH = RC1CX_PARAMS_FW_START_IDX + 6, - // Threshold for low RSSI - RC1CX_FW_LOWRSSI_TH = RC1CX_PARAMS_FW_START_IDX + 7, - // Maximum number of rc1cx fw params - RC1CX_FW_MAX_INDICES -} RC1CXParamsFirmwareDefinitions; - -#define RC1CX_FW_NUM_INDICES (RC1CX_FW_MAX_INDICES - RC1CX_PARAMS_FW_START_IDX) - -#define RC1CX_FW_MIN_NUM_PPDU_INIT 10u -#define RC1CX_FW_DATA_STALL_TH_INIT 75u -#define RC1CX_FW_MAX_NUM_ATTEMPTS_INIT 5u -#define RC1CX_FW_RR_RATE_CHK_DUR_INIT_MS 60u /* ms */ -#define RC1CX_FW_RR_ATTEMPT_DUR_INIT_MS 60u /* ms */ -#define RC1CX_FW_RR_UNSC_DUR_INIT_MS 10000u /* ms */ -#define RC1CX_FW_RECOVERY_TH_INIT 50u -#define RC1CX_FW_LOWRSSI_TH_INIT 85u /* dBm */ - -#ifdef GPIO_TXINHIBIT -/* GPIO based TX_INHIBIT:SWWLAN-109270 */ -typedef enum shm_macintstatus_ext_e { - C_MISE_GPIO_TXINHIBIT_VAL_NBIT = 0, - C_MISE_GPIO_TXINHIBIT_INT_NBIT = 1 -} shm_macintstatus_ext_t; -#define C_MISE_GPIO_TXINHIBIT_VAL_MASK (1 << C_MISE_GPIO_TXINHIBIT_VAL_NBIT) -#define C_MISE_GPIO_TXINHIBIT_INT_MASK (1 << C_MISE_GPIO_TXINHIBIT_INT_NBIT) -#endif -#define M_PSM_SOFT_REGS 0x0 - -/** Scratch Reg defs */ -typedef enum -{ - S_RSV0 = 0, - S_RSV1, - S_RSV2, - - /* scratch registers for Dot11-constants */ - S_DOT11_CWMIN, /**< CW-minimum 0x03 */ - S_DOT11_CWMAX, /**< CW-maximum 0x04 */ - S_DOT11_CWCUR, /**< CW-current 0x05 */ - S_DOT11_SRC_LMT, /**< short retry count limit 0x06 */ - S_DOT11_LRC_LMT, /**< long retry count limit 0x07 */ - S_DOT11_DTIMCOUNT, /**< DTIM-count 0x08 */ - - /* Tx-side scratch registers */ - S_SEQ_NUM, /**< hardware sequence number reg 0x09 */ - S_SEQ_NUM_FRAG, /**< seq-num for frags (Set at the start os MSDU 0x0A */ - S_FRMRETX_CNT, /**< frame retx count 0x0B */ - S_SSRC, /**< Station short retry count 0x0C */ - S_SLRC, /**< Station long retry count 0x0D */ - S_EXP_RSP, /**< Expected response frame 0x0E */ - S_OLD_BREM, /**< Remaining backoff ctr 0x0F */ - S_OLD_CWWIN, /**< saved-off CW-cur 0x10 */ - S_TXECTL, /**< TXE-Ctl word constructed in scr-pad 0x11 */ - S_CTXTST, /**< frm type-subtype as read from Tx-descr 0x12 */ - - /* Rx-side scratch registers */ - S_RXTST, /**< Type and subtype in Rxframe 0x13 */ - - /* Global state register */ - S_STREG, /**< state storage actual bit maps below 0x14 */ - - S_TXPWR_SUM, /**< Tx power control: accumulator 0x15 */ - S_TXPWR_ITER, /**< Tx power control: iteration 0x16 */ - S_RX_FRMTYPE, /**< Rate and PHY type for frames 0x17 */ - S_THIS_AGG, /**< Size of this AGG (A-MSDU) 0x18 */ - - S_KEYINDX, /* 0x19 */ - S_RXFRMLEN, /**< Receive MPDU length in bytes 0x1A */ - - /* Receive TSF time stored in SCR */ - S_RXTSFTMRVAL_WD3, /**< TSF value at the start of rx 0x1B */ - S_RXTSFTMRVAL_WD2, /**< TSF value at the start of rx 0x1C */ - S_RXTSFTMRVAL_WD1, /**< TSF value at the start of rx 0x1D */ - S_RXTSFTMRVAL_WD0, /**< TSF value at the start of rx 0x1E */ - S_RXSSN, /**< Received start seq number for A-MPDU BA 0x1F */ - S_RXQOSFLD, /**< Rx-QoS field (if present) 0x20 */ - - /* Scratch pad regs used in microcode as temp storage */ - S_TMP0, /**< stmp0 0x21 */ - S_TMP1, /**< stmp1 0x22 */ - S_TMP2, /**< stmp2 0x23 */ - S_TMP3, /**< stmp3 0x24 */ - S_TMP4, /**< stmp4 0x25 */ - S_TMP5, /**< stmp5 0x26 */ - S_PRQPENALTY_CTR, /**< Probe response queue penalty counter 0x27 */ - S_ANTCNT, /**< unsuccessful attempts on current ant. 0x28 */ - S_SYMBOL, /**< flag for possible symbol ctl frames 0x29 */ - S_RXTP, /**< rx frame type 0x2A */ - S_STREG2, /**< extra state storage 0x2B */ - S_STREG3, /**< even more extra state storage 0x2C */ - S_STREG4, /**< ... 0x2D */ - S_STREG5, /**< remember to initialize it to zero 0x2E */ - - S_UNUSED_0X2F, /**< No longer used 0x2F */ - S_UPTR, /* Use this to initialize utrace 0x30 */ - S_ADJPWR_IDX, /**< PR 37101 WAR, adj_pwr_idx 0x31 */ - S_CUR_PTR, /**< Temp pointer for A-MPDU re-Tx SHM table 0x32 */ - S_REVID4, /**< 0x33 */ - S_INDX, /**< 0x34 */ - S_ADDR0, /**< 0x35 */ - S_ADDR1, /**< 0x36 */ - S_ADDR2, /**< 0x37 */ - S_ADDR3, /**< 0x38 */ - S_ADDR4, /**< 0x39 */ - S_ADDR5, /**< 0x3A */ - S_TMP6, /**< 0x3B */ - S_KEYINDX_BU, /**< Backup for Key index 0x3C */ - S_MFGTEST_TMP0, /**< Temp register used for RX test calculations 0x3D */ - S_RXESN, /**< Received end sequence number for A-MPDU BA 0x3E */ - S_STREG6, /**< 0x3F */ -} ePsmScratchPadRegDefinitions; - -#define C_STREG_SLOWCAL_PD_NBIT 0x00000004 /* BIT 2 slow clock cal is pending */ -#define C_STREG_SLOWCAL_DN_NBIT 0x00000008 /* BIT 3 slow clock cal is done */ - -#define S_BEACON_INDX S_OLD_BREM -#define S_PRS_INDX S_OLD_CWWIN -#define S_BTCX_BT_DUR S_REVID4 -#define S_PHYTYPE S_SSRC -#define S_PHYVER S_SLRC - -/* IHR GPT_2 is corerev >= 3 */ -#define TSF_GPT_2_STAT 0x133 -#define TSF_GPT_2_CTR_L 0x134 -#define TSF_GPT_2_CTR_H 0x135 -#define TSF_GPT_2_VAL_L 0x136 -#define TSF_GPT_2_VAL_H 0x137 - -/* IHR TSF_GPT STAT values */ -#define TSF_GPT_PERIODIC (1 << 12) -#define TSF_GPT_ADJTSF (1 << 13) -#define TSF_GPT_USETSF (1 << 14) -#define TSF_GPT_ENABLE (1 << 15) - -/** ucode mac statistic counters in shared memory */ -#define MACSTAT_OFFSET_SZ 64 -#define MACSTAT_REV80_OFFSET_SZ 118 - -/* ucode macstat txfunflw offset */ -#define UCODEMSTAT_TXFUNFL_BLK ((0x70 * 2) + (0x76 * 2)) - -/* MACSTAT offset to SHM address */ -#define MACSTAT_ADDR(x, offset) (M_PSM2HOST_STATS(x) + (offset)) - -/** ucode mac statistic counters in shared memory, base addr defined in M_UCODE_MACSTAT1 */ -typedef struct macstat1 { - uint16 txndpa; /* + 0 (0x0) */ - uint16 txndp; /* + 1*2 (0x2) */ - uint16 txsf; /* + 2*2 (0x4) */ - uint16 txcwrts; /* + 3*2 (0x6) */ - uint16 txcwcts; /* + 4*2 (0x8) */ - uint16 txbfm; /* + 5*2 (0xa) */ - uint16 rxndpaucast; /* + 6*2 (0xc) */ - uint16 bferptrdy; /* + 7*2 (0xe) */ - uint16 rxsfucast; /* + 8*2 (0x10) */ - uint16 rxcwrtsucast; /* + 9*2 (0x12) */ - uint16 rxcwctsucast; /* +10*2 (0x14) */ - uint16 rx20s; /* +11*2 (0x16) */ - uint16 bcntrim; /* +12*2 (0x18) */ - uint16 btc_rfact_l; /* +13*2 (0x1a) */ - uint16 btc_rfact_h; /* +14*2 (0x1c) */ - uint16 btc_txconf_l; /* +15*2 (0x1e) : cnt */ - uint16 btc_txconf_h; /* +16*2 (0x20) : cnt */ - uint16 btc_txconf_durl; /* +17*2 (0x22) : dur */ - uint16 btc_txconf_durh; /* +18*2 (0x24) : dur */ - uint16 rxsecrssi0; /* +19*2 (0x26) : high bin */ - uint16 rxsecrssi1; /* +20*2 (0x28) : med bin */ - uint16 rxsecrssi2; /* +21*2 (0x2a) : low bin */ - uint16 rxpri_durl; /* +22*2 (0x2c) : dur */ - uint16 rxpri_durh; /* +23*2 (0x2e) : dur */ - uint16 rxsec20_durl; /* +24*2 (0x30) : dur */ - uint16 rxsec20_durh; /* +25*2 (0x32) : dur */ - uint16 rxsec40_durl; /* +26*2 (0x34) : dur */ - uint16 rxsec40_durh; /* +27*2 (0x36) : dur */ -} macstat1_t; - -#define MX_UCODEX_MACSTAT (0x40 * 2) -/* ucodex mac statistic counters in shared memory */ -#define MACXSTAT_OFFSET_SZ 6 - -/* psm2 statistic counters in shared memory, base addr defined in MX_PSM2HOST_STATS */ -typedef enum { - MCXSTOFF_MACXSUSP = 0, - MCXSTOFF_M2VMSG = 1, - MCXSTOFF_V2MMSG = 2, - MCXSTOFF_MBOXOUT = 3, - MCXSTOFF_MUSND = 4, - MCXSTOFF_SFB2V = 5 -} macxstat_offset_t; - -/* dot11 core-specific control flags */ -#define SICF_MCLKE 0x0001 /* Mac core clock Enable */ -#define SICF_FCLKON 0x0002 /* Force clocks On */ -#define SICF_PCLKE 0x0004 /**< PHY clock enable */ -#define SICF_PRST 0x0008 /**< PHY reset */ -#define SICF_MPCLKE 0x0010 /**< MAC PHY clockcontrol enable */ -#define SICF_FREF 0x0020 /**< PLL FreqRefSelect (corerev >= 5) */ -/* NOTE: the following bw bits only apply when the core is attached - * to a NPHY (and corerev >= 11 which it will always be for NPHYs). - */ -#ifdef SICF_160M_BWMASK_DEF -#define SICF_BWMASK(macrev) (D11REV_GE(macrev, 86) ? 0x00e0 : 0x00c0) /**< phy clkmsk */ -#define SICF_BW160(macrev) (D11REV_GE(macrev, 86) ? 0x0080 : 0x00c0) /**< 160MHz BW */ -#define SICF_BW80(macrev) (D11REV_GE(macrev, 86) ? 0x0060 : 0x00c0) /**< 80MHz BW */ -#define SICF_BW40(macrev) (D11REV_GE(macrev, 86) ? 0x0040 : 0x0080) /**< 40MHz BW */ -#define SICF_BW20(macrev) (D11REV_GE(macrev, 86) ? 0x0020 : 0x0040) /**< 20MHz BW */ -#define SICF_BW10(macrev) (D11REV_GE(macrev, 86) ? 0x0000 : 0x0000) /**< 10MHz BW */ -#else -#define SICF_BWMASK 0x00c0 /**< phy clock mask (b6 & b7) */ -#define SICF_BW160 0x00c0 /**< 160MHz BW */ -#define SICF_BW80 0x00c0 /**< 80MHz BW */ -#define SICF_BW40 0x0080 /**< 40MHz BW (160MHz phyclk) */ -#define SICF_BW20 0x0040 /**< 20MHz BW (80MHz phyclk) */ -#define SICF_BW10 0x0000 /**< 10MHz BW (40MHz phyclk) */ -#endif -#define SICF_DAC 0x0300 /**< Highspeed DAC mode control field */ -#define SICF_GMODE 0x2000 /**< gmode enable */ - -/* Macmode / Phymode / Opmode are used interchangebly sometimes - * even though they all mean the same. Going ahead with the HW - * signal name - using phymode here on (even though we know its - * a misnomer). Applicable to d11 corerev >= 50 ---- ACPHY only - */ -#define SICF_PHYMODE_SHIFT 16 -#define SICF_PHYMODE 0xf0000 /**< mask */ - -#define SICF_160CLKSEL 0x100000u /* main phy clock speed selection */ - -/* dot11 core-specific status flags */ -#define SISF_2G_PHY 0x0001 /**< 2.4G capable phy (corerev >= 5) */ -#define SISF_5G_PHY 0x0002 /**< 5G capable phy (corerev >= 5) */ -#define SISF_FCLKA 0x0004 /**< FastClkAvailable (corerev >= 5) */ -#define SISF_DB_PHY 0x0008 /**< Dualband phy (corerev >= 11) */ - -/* === End of MAC reg, Beginning of PHY(b/a/g/n) reg, radio and LPPHY regs are separated === */ - -/* Bits in phytest(0x0a): */ -#define TST_DDFS 0x2000 -#define TST_TXFILT1 0x0800 -#define TST_UNSCRAM 0x0400 -#define TST_CARR_SUPP 0x0200 -#define TST_DC_COMP_LOOP 0x0100 -#define TST_LOOPBACK 0x0080 -#define TST_TXFILT0 0x0040 -#define TST_TXTEST_ENABLE 0x0020 -#define TST_TXTEST_RATE 0x0018 -#define TST_TXTEST_PHASE 0x0007 - -/* phytest txTestRate values */ -#define TST_TXTEST_RATE_1MBPS 0 -#define TST_TXTEST_RATE_2MBPS 1 -#define TST_TXTEST_RATE_5_5MBPS 2 -#define TST_TXTEST_RATE_11MBPS 3 -#define TST_TXTEST_RATE_SHIFT 3 - -typedef struct shm_mbss_prq_entry_s shm_mbss_prq_entry_t; -BWL_PRE_PACKED_STRUCT struct shm_mbss_prq_entry_s { - struct ether_addr ta; - uint8 prq_info[2]; - uint8 time_stamp; - uint8 flags; /**< bit 0 HT STA Indication, bit 7:1 Reserved */ -} BWL_POST_PACKED_STRUCT; - -typedef enum shm_mbss_prq_ft_e { - SHM_MBSS_PRQ_FT_CCK, - SHM_MBSS_PRQ_FT_OFDM, - SHM_MBSS_PRQ_FT_MIMO, - SHM_MBSS_PRQ_FT_RESERVED -} shm_mbss_prq_ft_t; - -#define SHM_MBSS_PRQ_FT_COUNT SHM_MBSS_PRQ_FT_RESERVED - -#define SHM_MBSS_PRQ_ENT_FRAMETYPE(entry) ((entry)->prq_info[0] & 0x3) -#define SHM_MBSS_PRQ_ENT_UPBAND(entry) ((((entry)->prq_info[0] >> 2) & 0x1) != 0) - -/** What was the index matched? */ -#define SHM_MBSS_PRQ_ENT_UC_BSS_IDX(entry) (((entry)->prq_info[0] >> 2) & 0x3) -#define SHM_MBSS_PRQ_ENT_PLCP0(entry) ((entry)->prq_info[1]) - -/** Was this directed to a specific SSID or BSSID? If bit clear, quantity known */ -#define SHM_MBSS_PRQ_ENT_DIR_SSID(entry) \ - ((((entry)->prq_info[0] >> 6) == 0) || ((entry)->prq_info[0] >> 6) == 1) -#define SHM_MBSS_PRQ_ENT_DIR_BSSID(entry) \ - ((((entry)->prq_info[0] >> 6) == 0) || ((entry)->prq_info[0] >> 6) == 2) - -#define SHM_MBSS_PRQ_ENT_TIMESTAMP(entry) ((entry)->time_stamp) -/** Was the probe request from a ht STA or a legacy STA */ -#define SHM_MBSS_PRQ_ENT_HTSTA(entry) ((entry)->flags & 0x1) - -typedef struct d11ac_tso_s d11ac_tso_t; - -BWL_PRE_PACKED_STRUCT struct d11ac_tso_s { - uint8 flag[3]; - uint8 sfh_hdr_offset; - uint16 tso_mss; /**< tso segment size */ - uint16 msdu_siz; /**< msdu size */ - uint32 tso_payload_siz; /**< total byte cnt in tcp payload */ - uint16 ip_hdr_offset; /**< relative to the start of txd header */ - uint16 tcp_hdr_offset; /**< relative to start of txd header */ -} BWL_POST_PACKED_STRUCT; - -/* toe_ctl TCP offload engine register definitions */ -#define TOE_CTL_DISAB (1u << 0) -#define TOE_CTL_MASK (1u << 0) -#define TOE_CTL_ENAB (0xFFFEu) -#define TOE_CLK_GATING_DISAB (1u << 1) - -#define TSO_HDR_TOE_FLAG_OFFSET (0u) - -#define TOE_F0_HDRSIZ_NORMAL (1u << 0) -#define TOE_F0_PASSTHROUGH (1u << 1) -#define TOE_F0_TCPSEG_EN (1u << 3) -#define TOE_F0_IPV4 (1u << 4) -#define TOE_F0_IPV6 (1u << 5) -#define TOE_F0_TCP (1u << 6) -#define TOE_F0_UDP (1u << 7) - -#define TOE_F1_IPV4_CSUM_EN (1u << 0) -#define TOE_F1_TCPUDP_CSUM_EN (1u << 1) -#define TOE_F1_PSEUDO_CSUM_EN (1u << 2) -#define TOE_F1_FRAG_ALLOW (1u << 5) -#define TOE_F1_FRAMETYPE_1 (1u << 6) -#define TOE_F1_FRAMETYPE_2 (1u << 7) -#define TOE_F1_FT_MASK (TOE_F1_FRAMETYPE_1 | TOE_F1_FRAMETYPE_2) -#define TOE_F1_FT_SHIFT (6u) - -#define TOE_F2_TXD_HEAD_SHORT (1u << 0) -#define TOE_F2_EPOCH_SHIFT (1u) -#define TOE_F2_EPOCH (1u << TOE_F2_EPOCH_SHIFT) -#define TOE_F2_EPOCH_EXT (1u << 2) -#define TOE_F2_EPOCH_EXT_MASK (TOE_F2_EPOCH | TOE_F2_EPOCH_EXT) -#define TOE_F2_AMSDU_AGGR_EN (1u << 4) -#define TOE_F2_AMSDU_CSUM_EN (1u << 5) -#define TOE_F2_AMSDU_FS_MID (1u << 6) -#define TOE_F2_AMSDU_FS_LAST (1u << 7) - -#define TOE_TXDMA_FLAGS_AMSDU_FIRST (0x14u) -#define TOE_TXDMA_FLAGS_AMSDU_MID (0x24u) -#define TOE_TXDMA_FLAGS_AMSDU_LAST (0x34u) - -/* This marks the end of a packed structure section. */ -#include - -#define SHM_BYT_CNT 0x2 /**< IHR location */ -#define MAX_BYT_CNT 0x600 /**< Maximum frame len */ - -/* WOWL Template Regions */ -#define WOWL_NS_CHKSUM (0x57 * 2) -#define WOWL_PSP_TPL_BASE (0x334 * 2) -#define WOWL_GTK_MSG2 (0x434 * 2) -#define WOWL_NS_OFFLOAD (0x634 * 2) -#define T_KEEPALIVE_0 (0x6b4 * 2) -#define T_KEEPALIVE_1 ((0x6b4 + 0x40) * 2) -#define WOWL_ARP_OFFLOAD (0x734 * 2) -#define WOWL_TX_FIFO_TXRAM_BASE (0x774 * 2) /**< conservative, leave 1KB for GTKM2 */ - -/* template regions for 11ac */ -#define D11AC_WOWL_PSP_TPL_BASE (0x4c0 * 2) -#define D11AC_WOWL_GTK_MSG2 (0x5c0 * 2) /**< for core rev >= 42 */ -#define WOWL_NS_OFFLOAD_GE42 (0x7c0 * 2) -#define T_KEEPALIVE_0_GE42 (0x840 * 2) -#define T_KEEPALIVE_1_GE42 ((0x840 + 0x40) * 2) -#define WOWL_ARP_OFFLOAD_GE42 (0x8c0 * 2) -#define D11AC_WOWL_TX_FIFO_TXRAM_BASE (0x900 * 2) /**< GTKM2 for core rev >= 42 */ - -/* Event definitions */ -#define WOWL_MAGIC (1 << 0) /**< Wakeup on Magic packet */ -#define WOWL_NET (1 << 1) /**< Wakeup on Netpattern */ -#define WOWL_DIS (1 << 2) /**< Wakeup on loss-of-link due to Disassoc/Deauth */ -#define WOWL_RETR (1 << 3) /**< Wakeup on retrograde TSF */ -#define WOWL_BCN (1 << 4) /**< Wakeup on loss of beacon */ -#define WOWL_TST (1 << 5) /**< Wakeup after test */ -#define WOWL_M1 (1 << 6) /**< Wakeup after PTK refresh */ -#define WOWL_EAPID (1 << 7) /**< Wakeup after receipt of EAP-Identity Req */ -#define WOWL_PME_GPIO (1 << 8) /**< Wakeind via PME(0) or GPIO(1) */ -#define WOWL_NEEDTKIP1 (1 << 9) /**< need tkip phase 1 key to be updated by the driver */ -#define WOWL_GTK_FAILURE (1 << 10) /**< enable wakeup if GTK fails */ -#define WOWL_EXTMAGPAT (1 << 11) /**< support extended magic packets */ -#define WOWL_ARPOFFLOAD (1 << 12) /**< support ARP/NS offloading */ -#define WOWL_WPA2 (1 << 13) /**< read protocol version for EAPOL frames */ -#define WOWL_KEYROT (1 << 14) /**< If the bit is set, use key rotaton */ -#define WOWL_BCAST (1 << 15) /**< If the bit is set, frm received was bcast frame */ - -#define MAXBCNLOSS (1 << 13) - 1 /**< max 12-bit value for bcn loss */ - -/* UCODE shm view: - * typedef struct { - * uint16 offset; // byte offset - * uint16 patternsize; // the length of value[.] in bytes - * uchar bitmask[MAXPATTERNSIZE/8]; // 16 bytes, the effect length is (patternsize+7)/8 - * uchar value[MAXPATTERNSIZE]; // 128 bytes, the effect length is patternsize. - * } netpattern_t; - */ -#define NETPATTERNSIZE (148) /* 128 value + 16 mask + 4 offset + 4 patternsize */ -#define MAXPATTERNSIZE 128 -#define MAXMASKSIZE MAXPATTERNSIZE/8 - -/** Security Algorithm defines */ -#define WOWL_TSCPN_SIZE 6 -#define WOWL_TSCPN_COUNT 4 /**< 4 ACs */ -#define WOWL_TSCPN_BLK_SIZE (WOWL_TSCPN_SIZE * WOWL_TSCPN_COUNT) - -#define WOWL_SECSUITE_GRP_ALGO_MASK 0x0007 -#define WOWL_SECSUITE_GRP_ALGO_SHIFT 0 -#define WOWL_SECSUITE_ALGO_MASK 0x0700 -#define WOWL_SECSUITE_ALGO_SHIFT 8 - -#define EXPANDED_KEY_RNDS 10 -#define EXPANDED_KEY_LEN 176 /* the expanded key from KEK (4*11*4, 16-byte state, 11 rounds) */ - -/* Organization of Template RAM is as follows - * typedef struct { - * uint8 AES_XTIME9DBE[1024]; - * uint8 AES_INVSBOX[256]; - * uint8 AES_KEYW[176]; - * } AES_TABLES_t; - */ -/* See dot11_firmware/diag/wmac_tcl/wmac_762_wowl_gtk_aes: proc write_aes_tables, - * for an example of writing those tables into the tx fifo buffer. - */ - -typedef struct { - uint16 MacTxControlLow; /**< mac-tx-ctl-low word */ - uint16 MacTxControlHigh; /**< mac-tx-ctl-high word */ - uint16 PhyTxControlWord; /**< phy control word */ - uint16 PhyTxControlWord_1; /**< extra phy control word for mimophy */ - union { - uint16 XtraFrameTypes; /**< frame type for RTS/FRAG fallback (used only for AES) */ - uint16 bssenc_pos; /**< BssEnc includes key ID , for corerev >= 42 */ - } u1; - uint8 plcp[6]; /**< plcp of template */ - - uint16 mac_frmtype; /**< MAC frame type for GTK MSG2, can be - * dot11_data frame (0x20) or dot11_QoS_Data frame (0x22). - */ - uint16 frm_bytesize; /**< number of bytes in the template, it includes: - * PLCP, MAC header, IV/EIV, the data payload - * (eth-hdr and EAPOL-Key), TKIP MIC - */ - uint16 payload_wordoffset; /**< the word offset of the data payload */ - - /* ALIGN */ - uint16 seqnum; /**< Sequence number for this frame */ - uint8 seciv[18]; /**< 10-byte TTAK used for TKIP, 8-byte IV/EIV. - * See in the general tx descriptor. - */ -} wowl_templ_ctxt_t; - -#define WOWL_TEMPL_CTXT_LEN 42 /**< For making sure that no PADs are needed */ -#define WOWL_TEMPL_CTXT_FRMTYPE_DATA 0x2 -#define WOWL_TEMPL_CTXT_FRMTYPE_QOS 0x22 - -/** constant tables required for AES key unwrapping for key rotation */ -extern uint16 aes_invsbox[128]; -extern uint16 aes_xtime9dbe[512]; - -#define MAX_MPDU_SPACE (D11_TXH_LEN + 1538) - -/* Bits in TXE_BMCCTL */ -#define BMCCTL_INITREQ_SHIFT 0 -#define BMC_CTL_DONE (1 << BMCCTL_INITREQ_SHIFT) -#define BMCCTL_RESETSTATS_SHIFT 1 -#define BMCCTL_TXBUFSIZE_SHIFT 2 -#define BMCCTL_LOOPBACK_SHIFT 5 -#define BMCCTL_TXBUFSZ_MASK ((1 << BMCCTL_LOOPBACK_SHIFT) - (1 << BMCCTL_TXBUFSIZE_SHIFT)) -#define BMCCTL_CLKGATEEN_SHIFT 8 - -/* Bits in TXE_BMCConfig */ -#define BMCCONFIG_BUFCNT_SHIFT 0 -#define BMCCONFIG_DISCLKGATE_SHIFT 13 -#define BMCCONFIG_BUFCNT_MASK ((1 << BMCCONFIG_DISCLKGATE_SHIFT) - (1 << BMCCONFIG_BUFCNT_SHIFT)) - -/* Bits in TXE_BMCStartAddr */ -#define BMCSTARTADDR_STRTADDR_MASK 0x3ff - -/* Bits in TXE_BMCDescrLen */ -#define BMCDescrLen_ShortLen_SHIFT 0 -#define BMCDescrLen_LongLen_SHIFT 8 - -/* Bits in TXE_BMCAllocCtl */ -#define BMCAllocCtl_AllocCount_SHIFT 0 -/* Rev==50 || Rev>52 -* BMCAllocCtl.AllocCount [0:10] -* BMCAllocCtl.AllocThreshold [11:14] -* !Rev50 -* BMCAllocCtl.AllocCount [0:7] -* BMCAllocCtl.AllocThreshold [8:15] -*/ -#define BMCAllocCtl_AllocThreshold_SHIFT_Rev50 11 -#define BMCAllocCtl_AllocThreshold_SHIFT 8 - -/* Bits in TXE_BMCCmd1 */ -#define BMCCMD1_TIDSEL_SHIFT 1 -#define BMCCMD1_RDSRC_SHIFT 6 -#define BMCCmd1_RXMapPassThru_SHIFT 12 -#define BMCCMD1_BQSelNum_SHIFT 1u -#define BMCCMD1_BQSelType_SHIFT 7u -#define BMCCMD1_RDSRC_Group0 0u /* register itself */ -#define BMCCMD1_RDSRC_Group1 1u /* staged max/min */ -#define BMCCMD1_RDSRC_Group2 2u /* staged max/previous min */ -#define BMCCMD1_RDSRC_Group3 3u /* active max/min */ -#define BMCCMD1_RDSRC_SHIFT_rev80 10u -#define BMCCMD1_CoreSel_SHIFT 13u -#define BMCCMD1_CoreSel_SHIFT_rev80 15u - -/* Bits in TXE_BMCCmd */ -#define BMCCmd_TIDSel_SHIFT 0 -#define BMCCmd_Enable_SHIFT 4 -#define BMCCmd_ReleasePreAlloc_SHIFT 5 -#define BMCCmd_ReleasePreAllocAll_SHIFT 6 -#define BMCCmd_UpdateBA_SHIFT 7 -#define BMCCmd_Consume_SHIFT 8 -#define BMCCmd_Aggregate_SHIFT 9 -#define BMCCmd_UpdateRetryCount_SHIFT 10 -#define BMCCmd_DisableTID_SHIFT 11 - -#define BMCCmd_BQSelType_TX 0 -#define BMCCmd_BQSelType_RX 1 -#define BMCCmd_BQSelType_Templ 2 - -/* Bits in TXE_BMCCMD for rev >= 80 */ -#define BMCCmd_BQSelType_MASK_Rev80 0x00c0 -#define BMCCmd_BQSelType_SHIFT_Rev80 6 -#define BMCCmd_Enable_SHIFT_rev80 8 -#define BMCCmd_ReleasePreAllocAll_SHIFT_rev80 10 - -/* Bits in TXE_BMCCmd1 */ -#define BMCCmd1_Minmaxappall_SHIFT 0 -#define BMCCmd1_Minmaxlden_SHIFT 5 -#define BMCCmd1_Minmaxffszlden_SHIFT 8 -#define BMCCmd_Core1_Sel_MASK 0x2000 - -/* Bits in TXE_BMCStatCtl */ -#define BMCStatCtl_TIDSel_SHIFT 0u -#define BMCStatCtl_STATSel_SHIFT 4u -#define BMCStatCtl_BQSelNum_SHIFT 0u -#define BMCStatCtl_BQSelType_SHIFT 6u -#define BMCStatCtl_STATSel_SHIFT_rev80 8u - -/* Bits in BMVpConfig */ -#define BMCVPConfig_SingleVpModePortA_SHIFT 4 - -/* Bits in TXE_PsmMSDUAccess */ -#define PsmMSDUAccess_TIDSel_SHIFT 0 -#define PsmMSDUAccess_MSDUIdx_SHIFT 4 -#define PsmMSDUAccess_ReadBusy_SHIFT 14 -#define PsmMSDUAccess_WriteBusy_SHIFT 15 - -/* Bits in TXE_PsmMSDUAccess for rev >= 80 */ -#define PsmMSDUAccess_BQSelType_SHIFT 5 -#define PsmMSDUAccess_MSDUIdx_SHIFT_rev80 7 -#define PsmMSDUAccess_BQSelType_Templ 2 -#define PsmMSDUAccess_BQSelType_TX 0 - -#ifdef WLRSDB -#define MAX_RSDB_MAC_NUM 2 -#else -#define MAX_RSDB_MAC_NUM 1 -#endif -#define MAX_MIMO_MAC_NUM 1 - -#ifdef WL_SCAN_CORE -#define MAX_MAC_CORE_NUM (MAX_RSDB_MAC_NUM + 1) -#else -#define MAX_MAC_CORE_NUM (MAX_RSDB_MAC_NUM) -#endif /* WL_SCAN_CORE */ - -#define MAC_CORE_UNIT_0 0x0u /**< First mac core unit */ -#define MAC_CORE_UNIT_1 0x1u /**< Second mac core unit */ - -/* HW unit of scan core. - * This is used to overwrite the tunables specific to scan core - */ -#define SCAN_CORE_UNIT 0x2u - -/* Supported phymodes / macmodes / opmodes */ -#define SINGLE_MAC_MODE 0x0 /**< only single mac is enabled */ -#define DUAL_MAC_MODE 0x1 /**< enables dual mac */ -/* (JIRA: CRDOT11ACPHY-652) Following two #defines support - * exclusive reg access to core 0/1 in MIMO mode - */ -#define SUPPORT_EXCLUSIVE_REG_ACCESS_CORE0 0x2 -#define SUPPORT_EXCLUSIVE_REG_ACCESS_CORE1 0x4 /**< not functional in 4349A0 */ -#define SUPPORT_CHANNEL_BONDING 0x8 /**< enables channel bonding, - * supported in single mac mode only - */ -#define SCAN_CORE_ACTIVE 0x10 /* scan core enabled for background DFS */ - -#define PHYMODE_MIMO (SINGLE_MAC_MODE) -#define PHYMODE_80P80 (SINGLE_MAC_MODE | SUPPORT_CHANNEL_BONDING) -#define PHYMODE_RSDB_SISO_0 (DUAL_MAC_MODE | SUPPORT_EXCLUSIVE_REG_ACCESS_CORE0) -#define PHYMODE_RSDB_SISO_1 (DUAL_MAC_MODE | SUPPORT_EXCLUSIVE_REG_ACCESS_CORE1) -#define PHYMODE_RSDB (PHYMODE_RSDB_SISO_0 | PHYMODE_RSDB_SISO_1) -#define PHYMODE_BGDFS 31 -#define PHYMODE_3x3_1x1 31 - -#define RX_INTR_FIFO_0 0x1 /**< FIFO-0 interrupt */ -#define RX_INTR_FIFO_1 0x2 /**< FIFO-1 interrupt */ -#define RX_INTR_FIFO_2 0x4 /**< FIFO-2 interrupt */ - -#define MAX_RX_FIFO 3 - -#define RX_CTL_FIFOSEL_SHIFT 8 -#define RX_CTL_FIFOSEL_MASK (0x3 << RX_CTL_FIFOSEL_SHIFT) - -#define RCO_EN (0x1u) /**< Receive checksum offload */ - -/* MAC_PTM_CTRL1 bit definitions */ -#define PTM_RX_TMSTMP_CAPTURE_EN 0x0001u -#define PTM_TX_TMSTMP_CAPTURE_EN 0x0001u -#define PTM_TMSTMP_OVERRIDE_EN 0x1000u - -/* For corerev >= 64 - * Additional DMA descriptor flags for AQM Descriptor. These are used in - * conjunction with the descriptor control flags defined in sbhnddma.h - */ -/* AQM DMA Descriptor control flags 1 */ -#define D64_AQM_CTRL1_SOFPTR 0x0000FFFF /* index of the descr which - * is SOF decriptor in DMA table - */ -#define D64_AQM_CTRL1_EPOCH 0x00010000 /* Epoch bit for the frame */ -#define D64_AQM_CTRL1_NUMD_MASK 0x00F00000 /* NumberofDescriptors(NUMD) */ -#define D64_AQM_CTRL1_NUMD_SHIFT 20 -#define D64_AQM_CTRL1_AC_MASK 0x0F000000 /* AC of the current frame */ -#define D64_AQM_CTRL1_AC_SHIFT 24 - -/* AQM DMA Descriptor control flags 2 */ -#define D64_AQM_CTRL2_MPDULEN_MASK 0x00003FFF /* Length of the entire MPDU */ -#define D64_AQM_CTRL2_TXDTYPE 0x00080000 /* When set to 1 the long form of the - * TXD is used for the frame. - */ -/* For corerev >= 83 - * DMA descriptor flags for AQM Descriptor. These are used in - * conjunction with the descriptor control flags defined in sbhnddma.h - */ -/* AQM DMA Descriptor control flags 1 */ -#define D11_REV83_AQM_DESC_CTRL1_SOFPTR 0x0000FFFFu /* index of the descr which - * is SOF decriptor in DMA table - */ -#define D11_REV83_AQM_DESC_CTRL1_EPOCH_SHIFT 16u -#define D11_REV83_AQM_DESC_CTRL1_EPOCH (1u << D11_REV83_AQM_DESC_CTRL1_EPOCH_SHIFT) -#define D11_REV83_AQM_DESC_CTRL1_EPOCH_EXT_SHIFT 17u -#define D11_REV83_AQM_DESC_CTRL1_EPOCH_EXT (1u << \ - D11_REV83_AQM_DESC_CTRL1_EPOCH_EXT_SHIFT) -#define D11_REV83_AQM_DESC_CTRL1_EPOCH_MASK (D11_REV83_AQM_DESC_CTRL1_EPOCH | \ - D11_REV83_AQM_DESC_CTRL1_EPOCH_EXT) -#define D11_REV83_AQM_DESC_CTRL1_RESV1 0x00040000u /* RESERVED */ -#define D11_REV83_AQM_DESC_CTRL1_FRAGALLOW_SHIFT 19u /* Fragmentation allowance flag - * shift. - */ -#define D11_REV83_AQM_DESC_CTRL1_FRAGALLOW (1u << D11_REV83_AQM_DESC_CTRL1_FRAGALLOW_SHIFT) - /* Fragmentation allowance flag - * of the frame - */ -#define D11_REV83_AQM_DESC_CTRL1_NUMD_SHIFT 20u /* NumberofDescriptors(NUMD) */ -#define D11_REV83_AQM_DESC_CTRL1_NUMD_MASK (0xFu << D11_REV83_AQM_DESC_CTRL1_NUMD_SHIFT) -#define D11_REV83_AQM_DESC_CTRL1_AC_SHIFT 24u /* AC of the current frame */ -#define D11_REV83_AQM_DESC_CTRL1_AC_MASK (0xFu << D11_REV83_AQM_DESC_CTRL1_AC_SHIFT) -#define D11_REV83_AQM_DESC_CTRL1_ET 0x10000000u /* End of table */ -#define D11_REV83_AQM_DESC_CTRL1_IC 0x20000000u /* Interrupt on Completion */ -#define D11_REV83_AQM_DESC_CTRL1_RESV2 0x40000000u /* Used to be EF: End of frame, - * and would have been set to 1. - */ -#define D11_REV83_AQM_DESC_CTRL1_RESV3 0x80000000u /* Used to be SF: Start of Frame, - * and would have been set to 1 - */ - -/* AQM DMA Descriptor control flags 2 */ -#define D11_REV83_AQM_DESC_CTRL2_MPDULEN_MASK 0x00003FFFu /* Length of the entire MPDU */ -#define D11_REV83_AQM_DESC_CTRL2_FTYPE_SHIFT 14u /* Frame Type, Indicate whether - * frame is Data, Management or - * Control Frame. 2 bits: - * 2'b00=Data, 2'b01=Management, - * 2'b10=Control, 2'b11=Invalid - * value - */ -#define D11_REV83_AQM_DESC_CTRL2_FTYPE_MASK (0x3u << D11_REV83_AQM_DESC_CTRL2_FTYPE_SHIFT) -#define D11_REV83_AQM_DESC_CTRL2_PTXDLENIDX_SHIFT 16u /* pTxD length index in 4-deep table */ -#define D11_REV83_AQM_DESC_CTRL2_PTXDLENIDX_MASK (0x3u << \ - D11_REV83_AQM_DESC_CTRL2_PTXDLENIDX_SHIFT) -#define D11_REV83_AQM_DESC_CTRL2_PT 0x00040000u /* Parity bit. Choose a - * value such that the entire - * descriptor haseven parity - */ -#define D11_REV83_AQM_DESC_CTRL2_USERIT 0x00080000u /* If set, the Rate Table Index and - * RIT entry are fetched into SHM by - * hardware. Otherwise, software - * uses pTxD to convey this - * information to ucode - */ -#define D11_REV83_AQM_DESC_CTRL2_USELIT 0x00100000u /* If set, the Link Info Table Index - * and LIT entry are fetched into - * SHM by hardware. Otherwise, - * software uses pTxD to convey this - * information to ucode - */ -#define D11_REV83_AQM_DESC_CTRL2_LIT_SHIFT 21u /* LTI(Link info Table Index) */ -#define D11_REV83_AQM_DESC_CTRL2_LIT_MASK (0x3Fu << D11_REV83_AQM_DESC_CTRL2_LIT_SHIFT) -#define D11_REV83_AQM_DESC_CTRL2_RIT_SHIFT 27u /* bit[4:0] of RTI(Rate info Table Index) */ -#define D11_REV83_AQM_DESC_CTRL2_RIT_MASK (0x1Fu << D11_REV83_AQM_DESC_CTRL2_RIT_SHIFT) - -/* AQM DMA Descriptor control flags 3 */ -#define D11_REV86_AQM_DESC_CTRL3_RTI_BIT5 0x00000001u /* bit[5] of RTI (cont'd from ctrl2) */ -#define D11_REV86_AQM_DESC_CTRL3_RTI_BIT5_MASK 1u /* bit[5] of RTI (cont'd from ctrl2) */ -#define D11_REV86_AQM_DESC_CTRL3_RTI_BIT5_SHIFT 0u -#define D11_REV83_AQM_DESC_CTRL3_AGGR_ID 0x0000000Eu /* Aggregation ID */ -#define D11_REV83_AQM_DESC_CTRL3_CO 0x00000010u /* Coherency */ -#define D11_REV84_AQM_DESC_CTRL3_TXDPTR_SHIFT 5u /* TxD ptr */ -#define D11_REV84_AQM_DESC_CTRL3_TXDPTR_MASK 0xFFFFFFu /* bit[23:0] of TxD addr */ -#define D11_REV86_AQM_DESC_CTRL3_TID_SHIFT 29u /* TID for BSR */ -#define D11_REV86_AQM_DESC_CTRL3_TID_MASK (0x7u << D11_REV86_AQM_DESC_CTRL3_TID_SHIFT) - -/* values for psm_patchcopy_ctrl (0x1AC) post corerev 60 */ -#define PSM_PATCHCC_PMODE_MASK (0x3) -#define PSM_PATCHCC_PMODE_RAM (0) /* default */ -#define PSM_PATCHCC_PMODE_ROM_RO (1) -#define PSM_PATCHCC_PMODE_ROM_PATCH (2) - -#define PSM_PATCHCC_PENG_TRIGGER_SHIFT (2) -#define PSM_PATCHCC_PENG_TRIGGER_MASK (1 << PSM_PATCHCC_PENG_TRIGGER_SHIFT) -#define PSM_PATCHCC_PENG_TRIGGER (1 << PSM_PATCHCC_PENG_TRIGGER_SHIFT) - -#define PSM_PATCHCC_PCTRL_RST_SHIFT (3) -#define PSM_PATCHCC_PCTRL_RST_MASK (0x3 << PSM_PATCHCC_PCTRL_RST_SHIFT) -#define PSM_PATCHCC_PCTRL_RST_RESET (0x0 << PSM_PATCHCC_PCTRL_RST_SHIFT) -#define PSM_PATCHCC_PCTRL_RST_HW (0x1 << PSM_PATCHCC_PCTRL_RST_SHIFT) - -#define PSM_PATCHCC_COPYEN_SHIFT (5) -#define PSM_PATCHCC_COPYEN_MASK (1 << PSM_PATCHCC_COPYEN_SHIFT) -#define PSM_PATCHCC_COPYEN (1 << PSM_PATCHCC_COPYEN_SHIFT) - -#define PSM_PATCHCC_UCIMGSEL_SHIFT (16) -#define PSM_PATCHCC_UCIMGSEL_MASK (0x30000) -#define PSM_PATCHCC_UCIMGSEL_DS0 (0x00000) /* default image */ -#define PSM_PATCHCC_UCIMGSEL_DS1 (0x10000) /* image 1 */ - -/* patch copy delay for psm: 2millisec */ -#define PSM_PATCHCOPY_DELAY (2000) - -/* START-below WAS in d11_if_shm.h which we can move to auto shm. - * Some of them are offsets, but some of them are not given by ucode [possibly legacy] - * so, not taken care by autoshm. - */ - -/* Addr is byte address used by SW; offset is word offset used by uCode */ - -/** Per AC TX limit settings */ -#define M_AC_TXLMT_ADDR(x, _ac) (M_AC_TXLMT_BLK(x) + (2 * (_ac))) - -/** delay from end of PLCP reception to RxTSFTime */ -#define M_APHY_PLCPRX_DLY 3 -#define M_BPHY_PLCPRX_DLY 4 - -/* btcx debug shmem size */ -#define C_BTCX_DBGBLK_SZ 6 /**< Number of 16bit words */ -#define C_BTCX_DBGBLK2_SZ 11 /* size of statistics at 2nd SHM segment */ - -#define C_BTCX_STATS_DBGBLK_SZ 18 /* total size of statistics at A2DP stats */ -#define C_BTCX_A2DP_PRI_SZ 6 /* size of a2dp priority counters stats */ -#define C_BTCX_A2DP_BUFCNT_SZ 8 /* size of a2dp buffer counters stats */ -#define C_BTCX_ANT_GRANT_SZ 4 /* size of ant granted duration to BT */ -#define C_BTCX_STATS_ECNTR_BLK_SZ C_BTCX_STATS_DBGBLK_SZ /* blk size for btcx ecounters */ - -#define D11_DMA_CHANNELS 6 - -/* WME shared memory */ -#define M_EDCF_STATUS_OFF(x) (0x007 * 2) - -/* Beacon-related parameters */ -#define M_BCN_LI(x) M_PS_MORE_DTIM_TBTT(x) /**< beacon listen interval */ - -/* prerev 40 defines */ -#define D11_PRE40_M_SECKINDXALGO_BLK(x) (0x2ea * 2) - -/* corerev 40 defines */ -/* BLK SIZE needs to change for GE64 */ -#define D11_POST80_MAX_KEY_SIZE 32 -#define D11_PRE80_MAX_KEY_SIZE 16 - -#define D11_MAX_KEY_SIZE(_corerev) ((D11REV_GE(_corerev, 80)) ? \ - D11_POST80_MAX_KEY_SIZE : D11_PRE80_MAX_KEY_SIZE) - -#define M_SECKINDXALGO_BLK_SZ(_corerev) (AMT_SIZE(_corerev) + 4 /* default keys */) - -#define C_CTX_PCTLWD_POS (0x4 * 2) - -#define D11_MAX_TX_FRMS 32 /**< max frames allowed in tx fifo */ - -/* Current channel number plus upper bits */ -#define D11_CURCHANNEL_5G 0x0100; -#define D11_CURCHANNEL_40 0x0200; -#define D11_CURCHANNEL_MAX 0x00FF; - -#define INVALIDFID 0xffff - -#define D11_RT_DIRMAP_SIZE 16 - -/** Rate table entry offsets */ -#define M_RT_PRS_PLCP_POS(x) 10 -#define M_RT_PRS_DUR_POS(x) 16 -#define M_RT_OFDM_PCTL1_POS(x) 18 -#define M_RT_TXPWROFF_POS(x) 20 -#define M_REV40_RT_TXPWROFF_POS(x) 14 - -#define MIMO_MAXSYM_DEF 0x8000 /* 32k */ -#define MIMO_MAXSYM_MAX 0xffff /* 64k */ - -#define WATCHDOG_8TU_DEF_LT42 5 -#define WATCHDOG_8TU_MAX_LT42 10 -#define WATCHDOG_8TU_DEF 3 -#define WATCHDOG_8TU_MAX 4 - -#define M_PKTENG_RXAVGPWR_ANT(x, w) (M_MFGTEST_RXAVGPWR_ANT0(x) + (w) * 2) - -/* M_MFGTEST_NUM (pkt eng) bit definitions */ -#define MFGTEST_TXMODE 0x0001 /* TX frames indefinitely */ -#define MFGTEST_RXMODE 0x0002 /* RX frames */ -#define MFGTEST_RXMODE_ACK 0x0402 /* RX frames with sending ACKs back */ -#define MFGTEST_RXMODE_FWD2FW 0x8000 /* RX frames - forward packet to the fw */ -#define MFGTEST_TXMODE_FRMCNT 0x0101 /* TX frames by frmcnt */ -#define MFGTEST_RU_TXMODE 0x0011 /* RU frames TX indefinetly */ -#define MFGTEST_RU_TXMODE_FRMCNT 0x0111 /* RU TX frames by frmcnt */ - -/* UOTA interface bit definitions */ -enum { - C_UOTA_CNTSRT_NBIT = 0, /* 0 OTA rx frame count start bit (14 LSB's) */ - C_UOTA_RXFST_NBIT = 14, /* 14 indicating first frame */ - C_UOTA_RSSION_NBIT = 15, /* 15 OTA rx ON bit position */ -}; - -#define M_EDCF_QLEN(x) (M_EDCF_QINFO1_OFFSET(x)) -#define M_PWRIND_MAP(x, core) (M_PWRIND_BLKS(x) + ((core)<<1)) - -#define M_BTCX_MAX_INDEX 320u -#define M_BTCX_BACKUP_SIZE 130 -#define BTCX_AMPDU_MAX_DUR 2500 - -#define ADDR_STAMON_NBIT (1 << 10) /* STA monitor bit in AMT_INFO_BLK entity */ - -#ifdef WLP2P_UCODE - -/** The number of scheduling blocks */ -#ifdef BCMFUZZ /* need more for fuzzing */ -#define M_P2P_BSS_MAX 8 -#else -#define M_P2P_BSS_MAX 4 -#endif /* BCMFUZZ */ - -/** WiFi P2P interrupt block positions */ -#define M_P2P_I_BLK_SZ 4 -#define M_P2P_I_BLK_OFFSET(x) (M_P2P_INTR_BLK(x) - M_P2P_INTF_BLK(x)) -#define M_P2P_I_BLK(x, b) (M_P2P_I_BLK_OFFSET(x) + (M_P2P_I_BLK_SZ * (b) * 2)) -#define M_P2P_I(x, b, i) (M_P2P_I_BLK(x, b) + ((i) * 2)) - -#define M_P2P_I_PRE_TBTT 0 /**< pretbtt, wake up just before beacon reception */ -#define M_P2P_I_CTW_END 1 /**< CTWindow ends */ -#define M_P2P_I_ABS 2 /**< absence period start, trigger for switching channels */ -#define M_P2P_I_PRS 3 /**< presence period starts */ - -/** P2P hps flags */ -#define M_P2P_HPS_CTW(b) (1 << (b)) -#define M_P2P_HPS_NOA(b) (1 << ((b) + M_P2P_BSS_MAX)) - -/** WiFi P2P address attribute block */ -#define M_ADDR_BMP_BLK_SZ 12 -#define M_ADDR_RANDMAC_BMP_BLK_SZ 40u - -#define M_ADDR_BMP_BLK(x, b) (M_ADDR_BMP_BLK_OFFSET(x) + ((b) * 2)) - -#define ADDR_BMP_RA (1 << 0) /**< Receiver Address (RA) */ -#define ADDR_BMP_TA (1 << 1) /**< Transmitter Address (TA) */ -#define ADDR_BMP_BSSID (1 << 2) /**< BSSID */ -#define ADDR_BMP_AP (1 << 3) /**< Infra-BSS Access Point (AP) */ -#define ADDR_BMP_STA (1 << 4) /**< Infra-BSS Station (STA) */ -#define ADDR_BMP_P2P_DISC (1 << 5) /**< P2P Device */ -#define ADDR_BMP_P2P_GO (1 << 6) /**< P2P Group Owner */ -#define ADDR_BMP_P2P_GC (1 << 7) /**< P2P Client */ -#define ADDR_BMP_BSS_IDX_MASK (3 << 8) /**< BSS control block index */ -#define ADDR_BMP_BSS_IDX_SHIFT 8 - -/** WiFi P2P address starts from this entry in RCMTA */ -#define P2P_ADDR_STRT_INDX (RCMTA_SIZE - M_ADDR_BMP_BLK_SZ) - -/* WiFi P2P per BSS control block positions. - * all time related fields are in units of (1< 29 && corerev < 40 */ -#define M_COREMASK_BLK_WOWL (0x7e8 *2) - -/* corerev >= 42 */ -#define D11AC_M_COREMASK_BLK_WOWL (0x1b0*2) - -#define M_EXTLNA_PWRSAVE(x) M_RADIO_PWR(x) /**< External LNA power control support */ - -/* D11AC shm location changes */ -#define D11AC_T_NULL_TPL_BASE (0x16 * 2) -#define D11AC_T_NULL_TPL_SIZE_BYTES (24) -#define D11_T_BCN0_TPL_BASE T_BCN0_TPL_BASE -#define D11AC_T_BCN0_TPL_BASE (0x100 * 2) -#define D11_T_BCN1_TPL_BASE T_BCN1_TPL_BASE -#define D11AC_T_BCN1_TPL_BASE (0x240 * 2) -#define D11AC_T_GACT_TWT_INFO_TPL_BASE (0xB0 * 2) -#define D11AC_T_GACT_TWT_INFO_TPL_SIZE_BYTES (36) - -/* The response (ACK/BA) phyctrl words */ -#define D11AC_RSP_TXPCTL0 (0x4c * 2) -#define D11AC_RSP_TXPCTL1 (0x4d * 2) - -#define D11AC_T_PRS_TPL_BASE (0x380 * 2) - -#define D11_M_RT_PRS_PLCP_POS(x) M_RT_PRS_PLCP_POS(x) -#define D11_M_RT_PRS_DUR_POS(x) M_RT_PRS_DUR_POS(x) -#define D11AC_M_RT_PRS_PLCP_POS 8 -#define D11AC_M_RT_PRS_DUR_POS 12 - -/* Field definitions for M_REV40_RT_TXPWROFF_POS */ -#define M_REV40_RT_HTTXPWR_OFFSET_MASK 0x01f8 /**< bit 8:3 */ -#define M_REV40_RT_HTTXPWR_OFFSET_SHIFT 3 - -/* for axphy */ -#define M_REV80_RT_TXPWR_OFFSET_MASK 0xff00 /* bit 15:8 */ -#define M_REV80_RT_TXPWR_OFFSET_SHIFT 9 /* 8 (byte align) + 1 (convert from S5.1 to S5.2) */ - -/* shmem locations for Beamforming */ -/* shmem defined with prefix M_ are in shmem */ -#define shm_addr(base, offset) (((base)+(offset))*2) - -#define C_BFI_REFRESH_THR_OFFSET (1u) -#define C_BFI_NDPA_TXLMT_OFFSET (2u) -#define C_BFI_NRXC_OFFSET (3u) -#define C_BFI_MLBF_LUT_OFFSET (4u) // for corerev < 64 only - -#define C_BFI_BLK_SIZE(corerev) ((D11REV_GE(corerev, 86) ? 18u: 16u)) - -/* BFI block definitions (Beamforming) */ -#define C_BFI_BFRIDX_POS (0) -#define C_BFI_NDPA_TST_POS (1) -#define C_BFI_NDPA_TXCNT_POS (2) -#define C_BFI_NDPA_SEQ_POS (3) -#define C_BFI_NDPA_FCTST_POS (4) -#define C_BFI_BFRCTL_POS (5) -#define C_BFI_BFR_CONFIG0_POS (6) -#define C_BFI_BFE_CONFIG0_POS (7) -#define C_BFI_BFE_MIMOCTL_POS (8) -#define C_BFI_BSSID0_POS (9) -#define C_BFI_BSSID1_POS (10) -#define C_BFI_BSSID2_POS (11) -#define C_BFI_STAINFO_POS (12) -#define C_BFI_STAINFO1_POS (13) -#define C_BFI_BFE_MYAID_POS (13) /* stainfo1 is mutually exclusive */ -#define C_BFI_BFMSTAT_POS (14) -#define C_BFI_BFE_MIMOCTL_EXT_POS (15) -/* below SHMs for rev >= 86 */ -#define C_BFI_BFE_11AXMIMOCTL_POS (16) /* phyreg bfeMimoCtlReg for 11AX */ -#define C_BFI_BFE_NDPNR_POS (17) -/* used by BFR */ -#define C_BFI_STA_ADDR_POS C_BFI_BSSID0_POS - -/* to be removed -start */ -#define M_BFI_BLK_SIZE (16u) -#define BFI_BLK_SIZE 18 -/* to be removed -end */ - -/* Phy cache index Bit<8> indicates the validity. Cleared during TxBf link Init - * to trigger a new sounding sequence. - */ -#define C_BFRIDX_VLD_NBIT 8 /* valid */ -#define C_BFRIDX_EN_NBIT 7 /* BFI block is enabled (has valid info), - * applicable only for MU BFI block in shmemx - */ -#define C_BFRIDX_BW_NBIT 12 - -#define C_STAINFO_FBT_NBIT 12 /* 0: SU; 1: MU */ -#define C_STAINFO_NCIDX_NBIT 13 /* Bits13-15: NC IDX; Reserved if Feedback Type is SU */ - -/* NDP control blk */ -#define C_BFI_BFRCTL_POS_NDP_TYPE_SHIFT (0) /* 0: HT NDP; 1: VHT NDP; HE no need */ -#define C_BFI_BFRCTL_POS_NSTS_SHIFT (1) /* 0: 2ss; 1: 3ss; 2: 4ss */ -#define C_BFI_BFRCTL_POS_MLBF_SHIFT (4) /* 1 enable MLBF(used for corerev < 64) */ -#define C_BFI_BFRCTL_POS_BFM_SHIFT (8) /* Bits15-8: BFM mask for BFM frame tx */ - -/** dynamic rflo ucode WAR defines */ -#define UCODE_WAR_EN 1 -#define UCODE_WAR_DIS 0 - -/** LTE coex definitions */ -#define LTECX_FLAGS_LPBK_OFF 0 - -/** LTECX shares BTCX shmem block */ -#define M_LTECX_BLK_PTR(x) M_BTCX_BLK_PTR(x) - -/** NR5GCX shares BTCX shmem block */ -#define M_NR5GCX_BLK_PTR(x) M_BTCX_BLK_PTR(x) - -/** RC1CX shares BTCX shmem block */ -#define M_RC1CX_BLK_PTR(x) M_BTCX_BLK_PTR(x) - -/** RC2CX shares BTCX shmem block */ -#define M_RC2CX_BLK_PTR(x) M_BTCX_BLK_PTR(x) - -/* CORE0 MODE */ -#define CORE0_MODE_RSDB 0x0 -#define CORE0_MODE_MIMO 0x1 -#define CORE0_MODE_80P80 0x2 - -#define CORE1_MODE_RSDB 0x100 - -#define HWACI_HOST_FLAG_ADDR (0x186) -#define HWACI_SET_SW_MITIGATION_MODE (0x0008) - -/* split RX war shm locations */ -#define RXFIFO_0_OFFSET 0x1A0 -#define RXFIFO_1_OFFSET 0x19E -#define HDRCONV_FIFO0_STSLEN 0x4 /* status length in header conversion mode */ - -/* GE80: - * [15:8]: Phy status length - * [7:0]: Ucode status length - */ -#define DEFAULT_FIFO0_STSLEN(corerev, corerev_minor) \ - (D11REV_MAJ_MIN_GE(corerev, corerev_minor, 87, 1) ? 0x2018 : \ - D11REV_GE(corerev, 80) ? 0x2010: 0x24) - -/* M_ULP_WAKEIND bits */ -#define C_WATCHDOG_EXPIRY (1 << 0) -#define C_FCBS_ERROR (1 << 1) -#define C_RETX_FAILURE (1 << 2) -#define C_HOST_WAKEUP (1 << 3) -#define C_INVALID_FCBS_BLOCK (1 << 4) -#define C_HUDI_DS1_EXIT (1 << 5) -#define C_LOB_SLEEP (1 << 6) - -/* values for M_ULP_FEATURES */ -#define C_P2P_NOA (0x0001) -#define C_INFINITE_NOA (0x0002) -#define C_P2P_CTWIN (0x0004) -#define C_P2P_GC (0x0008) -#define C_BCN_TRIM (0x0010) -#define C_BT_COEX (0x0020) -#define C_LTE_COEX (0x0040) -#define C_ADS1 (0x0080) -#define C_LTECX_PSPOLL_PRIO_EN (0x0100) -#define C_ULP_SLOWCAL_SKIP (0x0200) -#define C_HUDI_ENABLE (0x0400) - -#define M_WOWL_ULP_SW_DAT_BLK (0xBFF * 2) /* (0xFFF * 2) - 1024 */ -#define M_WOWL_ULP_SW_DAT_BLK_MAX_SZ (0x400) /* 1024 bytes */ - -#define RX_INTR_FIFO_0 0x1 /* FIFO-0 interrupt */ -#define RX_INTR_FIFO_1 0x2 /* FIFO-1 interrupt */ -#define RX_INTR_FIFO_2 0x4 /* FIFO-2 interrupt */ - -/* M_TOF_FLAG bits */ -typedef enum { - TOF_RX_FTM_NBIT = 0, - TOF_SEQ_DISRXENTX_RFCTL = 1, - TOF_IS_TARGET = 2, - TOF_TPC_FREEZE = 3 -} eTOFFlags; - -/* TOF feature flags */ -#define M_UCODE_F2_TOF_BIT 7 /* part of features_2 shm */ -#define M_UCODE_F3_AVB_BIT 2 /* part of features_3 shm */ -#define M_UCODE_F3_SEQ_BIT 3 /* part of features_3 shm */ - -/* New SHM definitions required for tsync based time stamping of FTM frames. -* More details in below conf -* http://confluence.broadcom.com/display/WLAN/NewUcodeInterfaceForProxdFeature -*/ -#define FTM_TIMESTAMP_SHIFT 16 -#define TXS_ACK_INDEX_SHIFT 3 -#define FTM_ACK_TS_BLOCK_SIZE 3 -#define RXH_ACK_SHIFT(corerev) (D11REV_GE((corerev), 80) ? 12u:8u) -#define FTM_INVALID_SHM_INDEX(corerev) (D11REV_GE((corerev), 80) ? 0x04u:0x0Fu) -#define FTM_ACK_INDEX_MASK 0x0F -#define NUM_UCODE_ACK_TS_BLKS 4 - -#define FTM_TXSTATUS_ACK_RSPEC_BLOCK_MASK 0xFF -#define FTM_TXSTATUS_ACK_RSPEC_BW_MASK 0x3 -#define FTM_TXSTATUS_ACK_RSPEC_BW_SHIFT 2 -#define FTM_TXSTATUS_ACK_RSPEC_BW_20 0 -#define FTM_TXSTATUS_ACK_RSPEC_BW_40 1 -#define FTM_TXSTATUS_ACK_RSPEC_BW_80 2 -#define FTM_TXSTATUS_ACK_RSPEC_BW_160 3 -#define FTM_TXSTATUS_ACK_RSPEC_TYPE_SHIFT 4 -#define FTM_TXSTATUS_ACK_RSPEC_TYPE_MASK 0x7 -#define FTM_TXSTATUS_ACK_RSPEC_TYPE_CCK 0 -#define FTM_TXSTATUS_ACK_RSPEC_TYPE_LEG 1 /* Legacy */ -#define FTM_TXSTATUS_ACK_RSPEC_TYPE_HT 2 -#define FTM_TXSTATUS_ACK_RSPEC_TYPE_VHT 3 -#define FTM_TXSTATUS_ACK_RSPEC_TYPE_HE 4 -#define FTM_TXSTATUS_ACK_RSPEC_RATE_6M(ackword) (ackword >> 7) -/* Following are the offsets in M_DRVR_UCODE_IF_PTR block. Start address of - * M_DRVR_UCODE_IF_PTR block is present in M_DRVR_UCODE_IF_PTR. - */ -#define M_ULP_FEATURES (0x0 * 2) - -/* M_HOST_FLAGS5 offset changed in ULP ucode */ -#define M_ULP_HOST_FLAGS5 (0x3d * 2) - -#define M_RADAR_REG_TMP (0x033 * 2) - -/* Bit masks for ClkGateUcodeReq2: Ucode MAC Clock Request2 (IHR Address 0x375) register */ -#define D11_FUNC16_MAC_CLOCKREQ_MASK (0x3) - -/* - * Clock gating registers - */ -#define CLKREQ_BLOCK 0 -#define CLKREQ_MAC_ILP 1 -#define CLKREQ_MAC_ALP 2 -#define CLKREQ_MAC_HT 3 - -/* ClkGateSts */ -#define CLKGTE_FORCE_MAC_CLK_REQ_SHIFT 0 -#define CLKGTE_MAC_PHY_CLK_REQ_SHIFT 4 - -/* ClkGateReqCtrl0 */ -#define CLKGTE_PSM_PATCHCOPY_CLK_REQ_SHIFT 0 -#define CLKGTE_RXKEEP_OCP_CLK_REQ_SHIFT 2 -#define CLKGTE_PSM_MAC_CLK_REQ_SHIFT 4 -#define CLKGTE_TSF_CLK_REQ_SHIFT 6 -#define CLKGTE_AQM_CLK_REQ_SHIFT 8 -#define CLKGTE_SERIAL_CLK_REQ_SHIFT 10 -#define CLKGTE_TX_CLK_REQ_SHIFT 12 -#define CLKGTE_POSTTX_CLK_REQ_SHIFT 14 - -/* ClkGateReqCtrl1 */ -#define CLKGTE_RX_CLK_REQ_SHIFT 0 -#define CLKGTE_TXKEEP_OCP_CLK_REQ_SHIFT 2 -#define CLKGTE_HOST_RW_CLK_REQ_SHIFT 4 -#define CLKGTE_IHR_WR_CLK_REQ_SHIFT 6 -#define CLKGTE_TKIP_KEY_CLK_REQ_SHIFT 8 -#define CLKGTE_TKIP_MISC_CLK_REQ_SHIFT 10 -#define CLKGTE_AES_CLK_REQ_SHIFT 12 -#define CLKGTE_WAPI_CLK_REQ_SHIFT 14 - -/* ClkGateReqCtrl2 */ -#define CLKGTE_WEP_CLK_REQ_SHIFT 0 -#define CLKGTE_PSM_CLK_REQ_SHIFT 2 -#define CLKGTE_MACPHY_CLK_REQ_BY_PHY_SHIFT 4 -#define CLKGTE_FCBS_CLK_REQ_SHIFT 6 -#define CLKGTE_HIN_AXI_MAC_CLK_REQ_SHIFT 8 - -/* ClkGateStretch0 */ -#define CLKGTE_MAC_HT_CLOCK_STRETCH_SHIFT 0 -#define CLKGTE_MAC_ALP_CLOCK_STRETCH_SHIFT 8 -#define CLKGTE_MAC_HT_CLOCK_STRETCH_VAL 0x4 - -/* ClkGateStretch1 */ -#define CLKGTE_MAC_PHY_CLOCK_STRETCH_SHIFT 13 - -/* ClkGateMisc */ -#define CLKGTE_TPF_CLK_REQTHRESH 0xF -#define CLKGTE_AQM_CLK_REQEXT 0x70 - -/* ClkGateDivCtrl */ -#define CLKGTE_MAC_ILP_OFF_COUNT_MASK 0x0007 -#define CLKGTE_MAC_ILP_OFF_COUNT_SHIFT 0 -#define CLKGTE_MAC_ILP_ON_COUNT_MASK 0x0020 -#define CLKGTE_MAC_ILP_ON_COUNT_MASK_GE_REV80 0x0030 -#define CLKGTE_MAC_ALP_OFF_COUNT_MASK 0x03C0 -#define CLKGTE_MAC_ALP_OFF_COUNT_SHIFT 6 - -/* ClkGatePhyClkCtrl */ -#define CLKGTE_PHY_MAC_PHY_CLK_REQ_EN_SHIFT 0 -#define CLKGTE_O2C_HIN_PHY_CLK_EN_SHIFT 1 -#define CLKGTE_HIN_PHY_CLK_EN_SHIFT 2 -#define CLKGTE_IHRP_PHY_CLK_EN_SHIFT 3 -#define CLKGTE_CCA_MAC_PHY_CLK_REQ_EN_SHIFT 4 -#define CLKGTE_TX_MAC_PHY_CLK_REQ_EN_SHIFT 5 -#define CLKGTE_HRP_MAC_PHY_CLK_REQ_EN_SHIFT 6 -#define CLKGTE_SYNC_MAC_PHY_CLK_REQ_EN_SHIFT 7 -#define CLKGTE_RX_FRAME_MAC_PHY_CLK_REQ_EN_SHIFT 8 -#define CLKGTE_RX_START_MAC_PHY_CLK_REQ_EN_SHIFT 9 -#define CLKGTE_FCBS_MAC_PHY_CLK_REQ_SHIFT 10 -#define CLKGTE_POSTRX_MAC_PHY_CLK_REQ_EN_SHIFT 11 -#define CLKGTE_DOT11_MAC_PHY_RXVALID_SHIFT 12 -#define CLKGTE_NOT_PHY_FIFO_EMPTY_SHIFT 13 -#define CLKGTE_DOT11_MAC_PHY_BFE_REPORT_DATA_READY 14 -#define CLKGTE_DOT11_MAC_PHY_CLK_BIT15 15 - -/* ClkGateExtReq0 */ -#define CLKGTE_TOE_SYNC_MAC_CLK_REQ_SHIFT 0 -#define CLKGTE_TXBF_SYNC_MAC_CLK_REQ_SHIFT 2 -#define CLKGTE_HIN_SYNC_MAC_CLK_REQ_SHIFT 4 -#define CLKGTE_SLOW_SYNC_CLK_REQ_SHIFT 6 -#define CLKGTE_ERCX_SYNC_CLK_REQ_SHIFT 8 -#define CLKGTE_BTCX_SYNC_CLK_REQ_SHIFT 10 -#define CLKGTE_IFS_CRS_SYNC_CLK_REQ_SHIFT 12 -#define CLKGTE_IFS_GCI_SYNC_CLK_REQ_SHIFT 14 - -#define CLKGTE_TOE_SYNC_MAC_CLK_REQ_80_SHIFT 2 -#define CLKGTE_TXBF_SYNC_MAC_CLK_REQ_80_SHIFT 4 -#define CLKGTE_HIN_SYNC_MAC_CLK_REQ_80_SHIFT 6 -#define CLKGTE_SLOW_SYNC_CLK_REQ_80_SHIFT 8 -#define CLKGTE_ERCX_SYNC_CLK_REQ_80_SHIFT 10 -#define CLKGTE_BTCX_SYNC_CLK_REQ_80_SHIFT 12 -#define CLKGTE_IFS_CRS_SYNC_CLK_REQ_80_SHIFT 14 - -#define CLKGTE_TOE_SYNC_MAC_CLK_REQ_83_SHIFT 2 -#define CLKGTE_TXBF_SYNC_MAC_CLK_REQ_83_SHIFT 4 -#define CLKGTE_HIN_SYNC_MAC_CLK_REQ_83_SHIFT 6 -#define CLKGTE_SLOW_SYNC_CLK_REQ_83_SHIFT 8 -#define CLKGTE_ERCX_SYNC_CLK_REQ_83_SHIFT 10 -#define CLKGTE_BTCX2_SYNC_CLK_REQ_83_SHIFT 12 -#define CLKGTE_BTCX_SYNC_CLK_REQ_83_SHIFT 14 - -/* ClkGateExtReq1 */ -#define CLKGTE_PHY_FIFO_SYNC_CLK_REQ_SHIFT 0 -#define CLKGTE_RXE_CHAN_SYNC_CLK_REQ_SHIFT 2 -#define CLKGTE_PMU_MDIS_SYNC_MAC_CLK_REQ_SHIFT 4 -#define CLKGTE_PSM_IPC_SYNC_CLK_REQ_SHIFT 6 - -#define CLKGTE_IFS_GCI_SYNC_CLK_REQ_80_SHIFT 0 -#define CLKGTE_PHY_FIFO_SYNC_CLK_REQ_80_SHIFT 2 -#define CLKGTE_RXE_CHAN_SYNC_CLK_REQ_80_SHIFT 4 -#define CLKGTE_PMU_MDIS_SYNC_MAC_CLK_REQ_80_SHIFT 6 -#define CLKGTE_PSM_IPC_SYNC_CLK_REQ_80_SHIFT 8 - -#define CLKGTE_IFS_CRS_SYNC_CLK_REQ_83_SHIFT 0 -#define CLKGTE_IFS_GCI_SYNC_CLK_REQ_83_SHIFT 2 -#define CLKGTE_PHY_FIFO_SYNC_CLK_REQ_83_SHIFT 4 -#define CLKGTE_RXE_CHAN_SYNC_CLK_REQ_83_SHIFT 6 -#define CLKGTE_PMU_MDIS_SYNC_MAC_CLK_REQ_83_SHIFT 8 -#define CLKGTE_PSM_IPC_SYNC_CLK_REQ_83_SHIFT 10 - -/* PFE CtlStat1 register */ -#define PFE_CTLSTAT1_ROUTE_PFE_TO_BMSTAT (1u << 15u) -#define PFE_CTLSTAT1_PFE_ENABLE (1u << 0u) - -/* PPR Ctrl1 register */ -#define PPR_CTMODE_SHIFT 8u -#define PPR_CTMODE_MASK (3u << PPR_CTMODE_SHIFT) - -#define PPR_CTMODE_A (0u << PPR_CTMODE_SHIFT) -#define PPR_CTMODE_B (1u << PPR_CTMODE_SHIFT) -#define PPR_CTMODE_C (2u << PPR_CTMODE_SHIFT) - -/* Ptxd Len */ -#define PTXD_LEN0_SHIFT (0u) -#define PTXD_LEN1_SHIFT (8u) -#define PTXD_LEN2_SHIFT (0u) -#define PTXD_LEN3_SHIFT (8u) -/* =========== LHL regs =========== */ -/* WL ARM Timer0 Interrupt Status (lhl_wl_armtim0_st_adr) */ -#define LHL_WL_ARMTIM0_ST_WL_ARMTIM_INT_ST 0x00000001 - -#define D11_AUTO_MEM_STBY_RET_SHIFT (4u) -#define D11_AUTO_MEM_STBY_RET_83_SHIFT (5u) -#define D11_AUTO_MEM_STBY_NON_RET_SHIFT (6u) -#define D11_AUTO_MEM_STBY_BM_SHIFT (9u) - -#define D11_AUTO_MEM_STBY_RET_SHIFT_REV(d11rev) \ - (((d11rev) >= 83) ? D11_AUTO_MEM_STBY_RET_83_SHIFT : D11_AUTO_MEM_STBY_RET_SHIFT) - -/* WiFi P2P TX stop timestamp block (only applicable with AC ucode) */ -#define P2P_TXSTOP_SHMPERBSS 2u /* 2 shmems per BSS */ -#define M_P2P_TXSTOP_TS(x, b, w) (M_P2P_TXSTOP_T_BLK(x) +\ - (P2P_TXSTOP_SHMPERBSS * (b) + (w)) * 2) - -#define D11TXHDR_RATEINFO_ACCESS_VAL(txh, corerev, member) \ - ((((txh)->corerev).RateInfo[3]).member) - -/* QoS + BSR information */ -#define D11_QOS_BSR_TIDQS_SHIFT 0u -#define D11_QOS_BSR_TIDQS_SZ 8u -#define D11_QOS_BSR_TIDQS_MASK (((1 << D11_QOS_BSR_TIDQS_SZ) - 1) << D11_QOS_BSR_TIDQS_SHIFT) - -#define D11_QOS_BSR_UV_SHIFT 8u -#define D11_QOS_BSR_UV_SZ 6u -#define D11_QOS_BSR_UV_MASK (((1 << D11_QOS_BSR_UV_SZ) - 1) << D11_QOS_BSR_UV_SHIFT) - -#define D11_QOS_BSR_SF_SHIFT 14u -#define D11_QOS_BSR_SF_SZ 2u -#define D11_QOS_BSR_SF_MASK (((1 << D11_QOS_BSR_SF_SZ) - 1) << D11_QOS_BSR_SF_SHIFT) - -/* Queue size in QoS control */ -#define D11_QOS_BSR_SF_0 0u -#define D11_QOS_BSR_SF_1 1u -#define D11_QOS_BSR_SF_2 2u -#define D11_QOS_BSR_SF_3 3u - -#define D11_QS_OFFSET_SF_0 0u -#define D11_QS_OFFSET_SF_1 1024u -#define D11_QS_OFFSET_SF_2 17408u -#define D11_QS_OFFSET_SF_3 148480u - -#define D11_QOS_BSR_SF_0_SHIFT 4u /* Scale: 16 bytes */ -#define D11_QOS_BSR_SF_1_SHIFT 8u /* Scale: 256 bytes */ -#define D11_QOS_BSR_SF_2_SHIFT 11u /* Scale: 2048 bytes */ -#define D11_QOS_BSR_SF_3_SHIFT 15u /* Scale: 32768 bytes */ - -#define D11_MIN_QS_UV 0u -#define D11_MAX_QS_UV 63u -#define D11_MAX_QS_UV_SF3 ((D11_MAX_QS_UV) - 1) - -/* 1008: 16 * UV when the Scaling Factor subfield is 0 */ -#define D11_MAX_QS_SF_0 (D11_QS_OFFSET_SF_0 + (D11_MAX_QS_UV << D11_QOS_BSR_SF_0_SHIFT)) -/* 17152: 1024 + 256 * UV when the Scaling Factor subfield is 1 */ -#define D11_MAX_QS_SF_1 (D11_QS_OFFSET_SF_1 + (D11_MAX_QS_UV << D11_QOS_BSR_SF_1_SHIFT)) -/* 146432: 17408 + 2048 * UV when the Scaling Factor subfield is 2 */ -#define D11_MAX_QS_SF_2 (D11_QS_OFFSET_SF_2 + (D11_MAX_QS_UV << D11_QOS_BSR_SF_2_SHIFT)) -/* 2147328: 148480 + 32768 * UV when the Scaling Factor subfield is 3 */ -#define D11_MAX_QS_SF_3 (D11_QS_OFFSET_SF_3 + ((D11_MAX_QS_UV_SF3-1) << D11_QOS_BSR_SF_3_SHIFT)) - -/* 2 bits for HE signature and 4 bits for control ID */ -#define D11_BSR_HE_SIG_SHIFT 6u -/* HE Variant with BSR control ID */ -#define D11_BSR_HE_SIG (0xf) -#define D11_BSR_ACI_BMAP_SHIFT (0 + D11_BSR_HE_SIG_SHIFT) -#define D11_BSR_DELTA_TID_SHIFT (4 + D11_BSR_HE_SIG_SHIFT) -#define D11_BSR_SF_SHIFT (8 + D11_BSR_HE_SIG_SHIFT) -#define D11_BSR_QUEUE_SIZE_HIGH_SHIFT (10 + D11_BSR_HE_SIG_SHIFT) -#define D11_BSR_QUEUE_SIZE_ALL_SHIFT (18 + D11_BSR_HE_SIG_SHIFT) - -#define D11_BSR_DELTA_TID_ALLTID_SIGNATURE 3u - -#define D11_BSR_QUEUE_SIZE_WIDTH 8u -#define D11_BSR_QUEUE_SIZE_WIDTH_VAL ((1 << D11_BSR_QUEUE_SIZE_WIDTH) - 1) -#define D11_BSR_QUEUE_SIZE_UNKNOWN (255u) -#define D11_BSR_QUEUE_SIZE_MAX (254u) -#define D11_BSR_QUEUE_SIZE_HIGH_MASK (D11_BSR_QUEUE_SIZE_WIDTH_VAL <<\ - D11_BSR_QUEUE_SIZE_HIGH_SHIFT) -#define D11_BSR_QUEUE_SIZE_ALL_MASK (D11_BSR_QUEUE_SIZE_WIDTH_VAL <<\ - D11_BSR_QUEUE_SIZE_ALL_SHIFT) - -#define D11_BSR_WD1_SHIFT 16u - -enum { - D11_BSR_SF_ID_16 = 0, /* 0 */ - D11_BSR_SF_ID_256 = 1, /* 1 */ - D11_BSR_SF_ID_2048 = 2, /* 2 */ - D11_BSR_SF_ID_32768 = 3 /* 3 */ -}; - -enum { - D11_PING_BLOCK_VALID = 0, /* 0 */ - D11_PONG_BLOCK_VALID = 1, /* 1 */ - D11_UC_READING_PING_BLOCK = 2, /* 2 */ - D11_UC_READING_PONG_BLOCK = 3 /* 3 */ -}; - -enum { - D11_BSR_TID0_POS = 0, /* 0 */ - D11_BSR_TID1_POS = 1, /* 1 */ - D11_BSR_TID2_POS = 2, /* 2 */ - D11_BSR_TID3_POS = 3, /* 3 */ - D11_BSR_TID4_POS = 4, /* 4 */ - D11_BSR_TID5_POS = 5, /* 5 */ - D11_BSR_TID6_POS = 6, /* 6 */ - D11_BSR_TID7_POS = 7, /* 7 */ - D11_BSR_WD0_POS = 8, /* 8 */ - D11_BSR_WD1_POS = 9, /* 9 */ -}; - -#define D11_IS_PING_PONG_IN_RESET(i) (((i) & ((1 << D11_PING_BLOCK_VALID) |\ - (1 << D11_UC_READING_PING_BLOCK) | (1 << D11_PONG_BLOCK_VALID) |\ - (1 << D11_UC_READING_PONG_BLOCK))) == 0) -#define D11_PING_BLOCK_VALID_MASK ((1 << D11_PONG_BLOCK_VALID) |\ - (1 << D11_UC_READING_PING_BLOCK)) -#define D11_PONG_BLOCK_VALID_MASK ((1 << D11_PING_BLOCK_VALID) |\ - (1 << D11_UC_READING_PONG_BLOCK)) -#define D11_PING_PONG_UPDATE_MASK ((1 << D11_PING_BLOCK_VALID) |\ - (1 << D11_PONG_BLOCK_VALID)) -#define D11_IS_PING_BLOCK_WRITABLE(i) (((i) & D11_PING_BLOCK_VALID_MASK) == \ - (1 << D11_PONG_BLOCK_VALID)) -#define D11_IS_PONG_BLOCK_WRITABLE(i) (((i) & D11_PONG_BLOCK_VALID_MASK) == \ - (1 << D11_PING_BLOCK_VALID)) -#define D11_SET_PING_BLOCK_VALID(i) (((i) & ~(1 << D11_PONG_BLOCK_VALID)) |\ - (1 << D11_PING_BLOCK_VALID)) -#define D11_SET_PONG_BLOCK_VALID(i) (((i) & ~(1 << D11_PING_BLOCK_VALID)) |\ - (1 << D11_PONG_BLOCK_VALID)) -#define D11_SET_PING_PONG_INVALID(i) (((i) & ~(1 << D11_PING_BLOCK_VALID)) |\ - ((i) & ~(1 << D11_PONG_BLOCK_VALID))) - -/* valid rx plcp check */ -#define PLCP_VALID(plcp) (((plcp)[0] | (plcp)[1] | (plcp)[2]) != 0) -enum { - D11_TXTRIG_EN = 0, /* 0 */ - D11_TXTRIG_PROG = 1, /* 1 */ - D11_TXTRIG_DONE = 2, /* 2 */ - D11_TXTRIG_TYPE = 4, /* 4 */ -}; - -#define D11_SET_TXTRIG_EN (1 << D11_TXTRIG_EN) -#define D11_TXTRIG_TYPE_MASK ((1 << D11_TXTRIG_TYPE) | (1 << (D11_TXTRIG_TYPE+1))) -#define D11_SET_TXTRIG_TYPE(i) (((i) << D11_TXTRIG_TYPE) & D11_TXTRIG_TYPE_MASK) - -enum { - D11_MUEDCA_AIFSN = 0, /* 0 */ - D11_MUEDCA_CWMIN = 1, /* 1 */ - D11_MUEDCA_CWMAX = 2, /* 2 */ - D11_MUEDCA_TIMER = 3, /* 3 */ - D11_MUEDCA_SU_AIFSN = 4, /* 4 */ - D11_MUEDCA_SU_CWMIN = 5, /* 5 */ - D11_MUEDCA_SU_CWMAX = 6, /* 6 */ - D11_MUEDCA_EXPIRY_TSF = 7, /* 7 */ - D11_MUEDCA_QINFO = 8, /* 8 */ - D11_MUEDCA_STAT = 9, /* 9 */ - D11_MUEDCA_BLK_SIZE = 10 /* 10 */ -}; -#define D11_MUEDCA_BLK(x, idx, offset) (M_MUEDCA_BLK((x)) +\ - (idx * (D11_MUEDCA_BLK_SIZE << 1)) + (offset << 1)) - -#define D11_BSSCOLOR_VALID_SHIFT 15u -#define D11_BSSCOLOR_VALID_MASK (1 << D11_BSSCOLOR_VALID_SHIFT) - -#ifdef BCMPCIE_HP2P -/* HP2P (High Priority P2P) shared memory EDCA parameters */ -typedef struct shm_hp2p_edca_params { - uint16 txop; - uint16 cwmin; - uint16 cwmax; - uint16 cwcur; - uint16 aifs; - uint16 bslots; - uint16 reggap; - uint16 status; -} shm_hp2p_edca_params_t; - -#define HP2P_STATUS_NEWPARAMS (1u << 8u) -#endif /* BCMPCIE_HP2P */ - -#define MAX_D11_GPIOS 16 - -/* Workaround register */ -#define WAR_TXDMA_NONMODIFIABLE_EN 0x00000010 /* For TxDMA initiated AXI reads */ -#define WAR_AQMDMA_NONMODIFIABLE_EN 0x00000020 /* For AQMDMA initiated AXI reads */ - -/* noise cal timeout when NAN is enabled. -* 54 * 256 = ~14ms . -* smallest NAN CRB possible is 16ms..choose 14ms -* as timeout to ensure noise cal happens within this 16ms -*/ -#define M_NOISE_CALTIMEOUT_FOR_NAN 54u - -#define TXPU_CMD_SET 1u /**< txpu set command */ - -#endif /* _D11_H */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11_cfg.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11_cfg.h deleted file mode 100755 index b45c951ff2d0..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11_cfg.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Header file for splitrx mode definitions - * Explains different splitrx modes, macros for classify, conversion. - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ - -#ifndef _d11_cfg_h_ -#define _d11_cfg_h_ - -#ifdef USE_BCMCONF_H -#include -#else -#if defined(BCMDONGLEHOST) && !defined(WINNT) -#define D11REV_IS(var, val) ((var) == (val)) -#define D11REV_GE(var, val) ((var) >= (val)) -#define D11REV_GT(var, val) ((var) > (val)) -#define D11REV_LT(var, val) ((var) < (val)) -#define D11REV_LE(var, val) ((var) <= (val)) - -#define D11MINORREV_IS(var, val) ((var) == (val)) -#define D11MINORREV_GE(var, val) ((var) >= (val)) -#define D11MINORREV_GT(var, val) ((var) > (val)) -#define D11MINORREV_LT(var, val) ((var) < (val)) -#define D11MINORREV_LE(var, val) ((var) <= (val)) - -#define D11REV_MAJ_MIN_GE(corerev, corerev_minor, maj, min) \ - ((D11REV_IS((corerev), (maj)) && D11MINORREV_GE((corerev_minor), (min))) || \ - D11REV_GT(corerev, (maj))) - -#endif /* BCMDONGLEHOST */ -#endif /* USE_BCMCONF_H */ - -#define RXMODE0 0 /* no split */ -#define RXMODE1 1 /* descriptor split */ -#define RXMODE2 2 /* descriptor split + classification */ -#define RXMODE3 3 /* fifo split + classification */ -#define RXMODE4 4 /* fifo split + classification + hdr conversion */ - -#ifdef BCMSPLITRX - extern bool _bcmsplitrx; -#if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) - #define BCMSPLITRX_ENAB() (_bcmsplitrx) -#elif defined(BCMSPLITRX_DISABLED) - #define BCMSPLITRX_ENAB() (0) -#else - #define BCMSPLITRX_ENAB() (1) -#endif - - extern uint8 _bcmsplitrx_mode; -#if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) - #define BCMSPLITRX_MODE() (_bcmsplitrx_mode) -#elif defined(BCMSPLITRX_DISABLED) - #define BCMSPLITRX_MODE() (0) -#else - #define BCMSPLITRX_MODE() (_bcmsplitrx_mode) -#endif -#else - #define BCMSPLITRX_ENAB() (0) - #define BCMSPLITRX_MODE() (0) -#endif /* BCMSPLITRX */ - -#define SPLIT_RXMODE1() ((BCMSPLITRX_MODE() == RXMODE1)) -#define SPLIT_RXMODE2() ((BCMSPLITRX_MODE() == RXMODE2)) -#define SPLIT_RXMODE3() ((BCMSPLITRX_MODE() == RXMODE3)) -#define SPLIT_RXMODE4() ((BCMSPLITRX_MODE() == RXMODE4)) - -#define PKT_CLASSIFY() (SPLIT_RXMODE2() || SPLIT_RXMODE3() || SPLIT_RXMODE4()) -#define RXFIFO_SPLIT() (SPLIT_RXMODE3() || SPLIT_RXMODE4()) -#define HDR_CONV() (SPLIT_RXMODE4()) -#define HDRCONV_PAD 2 - -#define FRAG_CMN_MSG_HDROOM (16u) /* Common msg headroom required by PCIe to push txstatus */ - -#if defined(FMF_LIT) && !defined(FMF_LIT_DISABLED) -/* (188-4*24-16) required HEADROOM - 4 Rate info Block - CacheInfo */ -#define FRAG_HEADROOM_D11REV_GE83 76u -#else -#if (defined(WLC_TXDC) && !defined(WLC_TXDC_DISABLED)) || \ - (defined(FMF_RIT) && !defined(FMF_RIT_DISABLED)) -#define FRAG_HEADROOM_D11REV_GE83 92u /* (188-4*24) required HEADROOM - 4 Rate info Block */ -#else -/* required HEADROOM = PTXD (24) + LIT (16) + RIT (96) - + max dot11hdr (44):: - "FC+DUR+SEQ+A1+A2+A3"(24) + QOS(2) + max("HTC(4) + AES IV(8)", WAPI IV(18)) - + MSDU data size (22):: SFH (14) + LLC (8) - - ETHER_HDR_LEN - */ -#define FRAG_HEADROOM_D11REV_GE83 188u -#endif /* (WLC_TXDC && !WLC_TXDC_DISABLED) || (FMF_RIT && !FMF_RIT_DISABLED) */ -#endif /* defined(FMF_LIT) && !defined(FMF_LIT_DISABLED) */ -#define FRAG_HEADROOM_D11REV_LT80 226u /* TXOFF + amsdu header */ -#define FRAG_HEADROOM_D11REV_GE80 \ - (FRAG_HEADROOM_D11REV_GE83 + 4u) /* + TSO_HEADER_PASSTHROUGH_LENGTH(4) */ - -#ifdef USE_NEW_COREREV_API -#define FRAG_HEAD_ROOM(corerev) (D11REV_GE(corerev, 83) ? \ - FRAG_HEADROOM_D11REV_GE83 : D11REV_GE(corerev, 80) ? \ - FRAG_HEADROOM_D11REV_GE80 : FRAG_HEADROOM_D11REV_LT80) -#else -#define FRAG_HEAD_ROOM(sih, coreid) ((si_get_corerev(sih, coreid) >= 83) ? \ - FRAG_HEADROOM_D11REV_GE83 : ((si_get_corerev(sih, coreid) >= 80) ? \ - FRAG_HEADROOM_D11REV_GE80 : FRAG_HEADROOM_D11REV_LT80)) -#endif - -#endif /* _d11_cfg_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11reglist_proto.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11reglist_proto.h deleted file mode 100755 index a7a0004dde70..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11reglist_proto.h +++ /dev/null @@ -1,66 +0,0 @@ -/* D11reglist prototype for Broadcom 802.11abgn - * Networking Adapter Device Drivers. - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ -#ifndef _d11reglist_proto_h_ -#define _d11reglist_proto_h_ - -/* this is for dump_mac */ -enum { - D11REG_TYPE_IHR16 = 0, - D11REG_TYPE_IHR32 = 1, - D11REG_TYPE_SCR = 2, - D11REG_TYPE_SHM = 3, - D11REG_TYPE_TPL = 4, - D11REG_TYPE_GE64 = 5, - D11REG_TYPE_KEYTB = D11REG_TYPE_GE64, - D11REG_TYPE_IHRX16 = 6, - D11REG_TYPE_SCRX = 7, - D11REG_TYPE_SHMX = 8, - D11REG_TYPE_MAX = 9 -}; - -#define D11REGTYPENAME { \ - "ihr", "ihr", "scr", "shm", \ - "tpl", "keytb", "ihrx", "scrx", \ - "shmx" \ -} - -typedef struct _d11regs_bmp_list { - uint8 type; - uint16 addr; - uint32 bitmap; - uint8 step; - uint16 cnt; /* can be used together with bitmap or by itself */ -} d11regs_list_t; - -#define D11REG_BLK_SIZE 32 -typedef struct _d11regs_addr_list { - uint8 type; - uint16 cnt; - uint16 addr[D11REG_BLK_SIZE]; /* allow up to 32 per list */ -} d11regs_addr_t; - -typedef struct _d11obj_cache_t { - uint32 sel; - uint32 val; - uint16 addr32; - bool cache_valid; -} d11obj_cache_t; - -typedef struct _svmp_list { - uint32 addr; - uint16 cnt; -} svmp_list_t; - -#endif /* _d11reglist_proto_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11regs.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11regs.h deleted file mode 100755 index 95b726ff8eb2..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/d11regs.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Chip-specific hardware definitions for - * Broadcom 802.11abg Networking Device Driver - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ - -#ifndef _D11REGS_H -#define _D11REGS_H - -#include -#include -#include -#include - -#if !defined(BCMDONGLEHOST) -#include -#include -#endif - -#if defined(BCMDONGLEHOST) || defined(WL_UNITTEST) -typedef struct { - uint32 pad; -} d11regdefs_t; - -typedef volatile uint8 d11regs_t; -typedef struct _d11regs_info { - uint32 pad; -} d11regs_info_t; - -#else /* defined(BCMDONGLEHOST) || defined(WL_UNITTEST) */ - -typedef volatile struct d11regs d11regs_t; - -typedef struct _d11regs_info { - d11regs_t *regs; -} d11regs_info_t; - -#endif /* !defined(BCMDONGLEHOST) || !defined(WL_UNITTEST) */ - -typedef volatile struct { - uint32 intstatus; - uint32 intmask; -} intctrlregs_t; - -/** - * read: 32-bit register that can be read as 32-bit or as 2 16-bit - * write: only low 16b-it half can be written - */ -typedef volatile union { - uint32 pmqhostdata; /**< read only! */ - struct { - uint16 pmqctrlstatus; /**< read/write */ - uint16 PAD; - } w; -} pmqreg_t; - -/** dma corerev >= 11 */ -typedef volatile struct { - dma64regs_t dmaxmt; /* dma tx */ - pio4regs_t piotx; /* pio tx */ - dma64regs_t dmarcv; /* dma rx */ - pio4regs_t piorx; /* pio rx */ -} fifo64_t; - -/** indirect dma corerev >= 64 */ -typedef volatile struct { - dma64regs_t dma; /**< dma tx */ - uint32 indintstatus; - uint32 indintmask; -} ind_dma_t; - -/** indirect dma corerev 80, 81, 82 */ -typedef volatile struct { - uint32 indintstatus; - uint32 indintmask; - dma64regs_t dma; /**< dma tx, */ -} ind_dma_axc_t; - -/* access to register offsets and fields defined in dot11mac_all_regs.h */ - -#define D11_REG_OFF(regname) \ - dot11mac_##regname##_ADDR -#define D11_REG_FIELD_MASK(regname, regfield) \ - dot11mac_##regname##__##regfield##_MASK -#define D11_REG_FIELD_SHIFT(regname, regfield) \ - dot11mac_##regname##__##regfield##_SHIFT - -/* convert register offset to backplane address */ - -#ifndef D11_REG_ADDR_CHK -// #define D11_REG_ADDR_CHK -#endif - -#ifdef D11_REG_ADDR_CHK -#define D11_REG_ADDR_EXEMPT(regname) \ - (D11_REG_OFF(regname) == D11_REG_OFF(PHY_REG_ADDR) || \ - D11_REG_OFF(regname) == D11_REG_OFF(radioregaddr) || \ - D11_REG_OFF(regname) == D11_REG_OFF(radioregdata) || \ - D11_REG_OFF(regname) == D11_REG_OFF(OBJ_DATA) || \ - 0) -#define D11_REG32_ADDR(regbase, regname) \ - ({ \ - STATIC_ASSERT(D11_REG_ADDR_EXEMPT(regname) || D11_REG_OFF(regname) < 0x3e0); \ - (volatile uint32 *)((uintptr)(regbase) + D11_REG_OFF(regname)); \ - }) -#define D11_REG16_ADDR(regbase, regname) \ - ({ \ - STATIC_ASSERT(D11_REG_ADDR_EXEMPT(regname) || D11_REG_OFF(regname) >= 0x3e0); \ - (volatile uint16 *)((uintptr)(regbase) + D11_REG_OFF(regname)); \ - }) -#else /* !D11_REG_ADDR_CHK */ -#define D11_REG32_ADDR(regbase, regname) \ - (volatile uint32 *)((uintptr)(regbase) + D11_REG_OFF(regname)) -#define D11_REG16_ADDR(regbase, regname) \ - (volatile uint16 *)((uintptr)(regbase) + D11_REG_OFF(regname)) -#endif /* !D11_REG_ADDR_CHK */ - -/* used in table */ -#define D11_REG32_ADDR_ENTRY(regbase, regname) \ - (volatile uint32 *)((uintptr)(regbase) + D11_REG_OFF(regname)) -#define D11_REG16_ADDR_ENTRY(regbase, regname) \ - (volatile uint16 *)((uintptr)(regbase) + D11_REG_OFF(regname)) - -#ifndef D11_NEW_ACCESS_MACROS -/* MOVED TO src/wl/sys/wlc_hw_priv.h */ -#define GET_MACINTSTATUS(osh, hw) R_REG((osh), D11_MACINTSTATUS(hw)) -#define SET_MACINTSTATUS(osh, hw, val) W_REG((osh), D11_MACINTSTATUS(hw), (val)) -#define GET_MACINTMASK(osh, hw) R_REG((osh), D11_MACINTMASK(hw)) -#define SET_MACINTMASK(osh, hw, val) W_REG((osh), D11_MACINTMASK(hw), (val)) - -#define GET_MACINTSTATUS_X(osh, hw) R_REG((osh), D11_MACINTSTATUS_psmx(hw)) -#define SET_MACINTSTATUS_X(osh, hw, val) W_REG((osh), D11_MACINTSTATUS_psmx(hw), (val)) -#define GET_MACINTMASK_X(osh, hw) R_REG((osh), D11_MACINTMASK_psmx(hw)) -#define SET_MACINTMASK_X(osh, hw, val) W_REG((osh), D11_MACINTMASK_psmx(hw), (val)) - -#define GET_MACINTSTATUS_EXT(osh, hw) R_REG((osh), D11_MACINTSTATUS_EXT(hw)) -#define SET_MACINTSTATUS_EXT(osh, hw, val) W_REG((osh), D11_MACINTSTATUS_EXT(hw), (val)) -#define GET_MACINTMASK_EXT(osh, hw) R_REG((osh), D11_MACINTMASK_EXT(hw)) -#define SET_MACINTMASK_EXT(osh, hw, val) W_REG((osh), D11_MACINTMASK_EXT(hw), (val)) - -#define GET_MACINTSTATUS_EXT_X(osh, hw) R_REG((osh), D11_MACINTSTATUS_EXT_psmx(hw)) -#define SET_MACINTSTATUS_EXT_X(osh, hw, val) W_REG((osh), D11_MACINTSTATUS_EXT_psmx(hw), (val)) -#define GET_MACINTMASK_EXT_X(osh, hw) R_REG((osh), D11_MACINTMASK_EXT_psmx(hw)) -#define SET_MACINTMASK_EXT_X(osh, hw, val) W_REG((osh), D11_MACINTMASK_EXT_psmx(hw), (val)) - -#define D11Reggrp_intctrlregs(hw, ix) ((intctrlregs_t*)(((volatile uint8*)D11_intstat0(hw)) + \ - (sizeof(intctrlregs_t)*ix))) -#define D11Reggrp_inddma(hw, ix) (D11REV_GE(hw->corerev, 86) ? \ - ((ind_dma_t*)(((volatile uint8*)D11_ind_xmt_control(hw)) + (sizeof(ind_dma_t)*ix))) : \ - ((ind_dma_t*)(((volatile uint8*)D11_inddma(hw)) + (sizeof(ind_dma_t)*ix)))) -#define D11Reggrp_inddma_axc(hw, ix) ((ind_dma_axc_t*)(((volatile uint8*)D11_inddma(hw)) + \ - (sizeof(ind_dma_axc_t)*ix))) -#define D11Reggrp_indaqm(hw, ix) (D11REV_GE(hw->corerev, 86) ? \ - ((ind_dma_t*)(((volatile uint8*)D11_IndAQMctl(hw)) + (sizeof(ind_dma_t)*ix))) : \ - ((ind_dma_t*)(((volatile uint8*)D11_indaqm(hw)) + (sizeof(ind_dma_t)*ix)))) -#define D11Reggrp_pmqreg(hw, ix) ((pmqreg_t*)(((volatile uint8*)D11_PMQHOSTDATA(hw)) + \ - (sizeof(pmqreg_t)*ix))) -#define D11Reggrp_f64regs(hw, ix) ((fifo64_t*)(((volatile uint8*)D11_xmt0ctl(hw)) + \ - (sizeof(fifo64_t)*ix))) -#define D11Reggrp_dmafifo(hw, ix) ((dma32diag_t*)(((volatile uint8*)D11_fifobase(hw)) + \ - (sizeof(dma32diag_t)*ix))) -#define D11Reggrp_intrcvlazy(hw, ix) ((volatile uint32*)(((volatile uint8*)D11_intrcvlzy0(hw)) + \ - (sizeof(uint32)*ix))) -#define D11Reggrp_altintmask(hw, ix) ((volatile uint32*)(((volatile uint8*)D11_alt_intmask0(hw)) + \ - (sizeof(uint32)*ix))) -#define D11REG_ISVALID(ptr, addr) ((volatile uint16 *)(addr) != \ - ((volatile uint16 *) &((ptr)->regs->INVALID_ID))) -#endif /* D11_NEW_ACCESS_MACROS */ - -#endif /* _D11REGS_H */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dbus.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dbus.h old mode 100755 new mode 100644 index 7761dffe9fe7..64f0636b0960 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dbus.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dbus.h @@ -2,7 +2,7 @@ * Dongle BUS interface Abstraction layer * target serial buses like USB, SDIO, SPI, etc. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -19,7 +19,7 @@ * modifications of the software. * * - * <> + * <> */ #ifndef __DBUS_H__ @@ -251,7 +251,7 @@ typedef struct { void *(*pktget)(void *bus, int len); void (*pktfree)(void *bus, void *pkt); - int (*iovar_op)(void *bus, const char *name, void *params, int plen, void *arg, int len, + int (*iovar_op)(void *bus, const char *name, void *params, uint plen, void *arg, uint len, bool set); void (*dump)(void *bus, struct bcmstrbuf *strbuf); int (*set_config)(void *bus, dbus_config_t *config); @@ -316,9 +316,9 @@ typedef struct dbus_pub { * For NDIS60, param2 is WdfDevice * Under Linux, param1 and param2 are NULL; */ -extern int dbus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, - void *param1, void *param2); -extern int dbus_deregister(void); +//extern int dbus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, +// void *param1, void *param2); +//extern int dbus_deregister(void); //extern int dbus_download_firmware(dbus_pub_t *pub); //extern int dbus_up(struct dhd_bus *pub); @@ -327,13 +327,13 @@ extern int dbus_down(dbus_pub_t *pub); extern int dbus_shutdown(dbus_pub_t *pub); extern void dbus_flowctrl_rx(dbus_pub_t *pub, bool on); -extern int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf); +//extern int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf); extern int dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info); -extern int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info); +//extern int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info); //extern int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len); //extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len); -extern int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx); -extern int dbus_poll_intr(dbus_pub_t *pub); +//extern int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx); +//extern int dbus_poll_intr(dbus_pub_t *pub); extern int dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats); extern int dbus_get_device_speed(dbus_pub_t *pub); extern int dbus_set_config(dbus_pub_t *pub, dbus_config_t *config); @@ -407,6 +407,18 @@ typedef struct dbus_intf_callbacks { void (*rxerr_indicate)(void *cbarg, bool on); } dbus_intf_callbacks_t; +/* callback functions */ +typedef struct { + /* probe the device */ + void *(*probe)(uint16 bus, uint16 slot, uint32 hdrlen); + /* remove the device */ + void (*remove)(void *context); + /* can we suspend now */ + int (*suspend)(void *context); + /* resume from suspend */ + int (*resume)(void *context); +} dbus_driver_t; + /* * Porting: To support new bus, port these functions below */ @@ -415,8 +427,7 @@ typedef struct dbus_intf_callbacks { * Bus specific Interface * Implemented by dbus_usb.c/dbus_sdio.c */ -extern int dbus_bus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, - dbus_intf_t **intf, void *param1, void *param2); +extern int dbus_bus_register(dbus_driver_t *driver, dbus_intf_t **intf); extern int dbus_bus_deregister(void); extern void dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp); @@ -424,8 +435,7 @@ extern void dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp); * Bus-specific and OS-specific Interface * Implemented by dbus_usb_[linux/ndis].c/dbus_sdio_[linux/ndis].c */ -extern int dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, - void *prarg, dbus_intf_t **intf, void *param1, void *param2); +extern int dbus_bus_osl_register(dbus_driver_t *driver, dbus_intf_t **intf); extern int dbus_bus_osl_deregister(void); /* @@ -439,7 +449,7 @@ extern int dbus_bus_osl_hw_deregister(void); extern uint usbdev_bulkin_eps(void); #if defined(BCM_REQUEST_FW) extern void *dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, - uint16 boardtype, uint16 boardrev); + uint16 boardtype, uint16 boardrev, char *path); extern void dbus_release_fw_nvfile(void *firmware); #endif /* #if defined(BCM_REQUEST_FW) */ @@ -624,4 +634,7 @@ void optimize_submit_rx_request(const dbus_pub_t *pub, int epn, struct ehci_qtd #endif /* EHCI_FASTPATH_TX || EHCI_FASTPATH_RX */ void dbus_flowctrl_tx(void *dbi, bool on); +#ifdef LINUX +struct device * dbus_get_dev(void); +#endif /* LINUX */ #endif /* __DBUS_H__ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dhd_daemon.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dhd_daemon.h old mode 100755 new mode 100644 index d0cb12d3750c..f71d02907540 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dhd_daemon.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dhd_daemon.h @@ -1,7 +1,7 @@ /* * Header file for DHD daemon to handle timeouts * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dhdioctl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dhdioctl.h old mode 100755 new mode 100644 index 6404b2cdc211..dc558e21d4b9 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dhdioctl.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dhdioctl.h @@ -5,7 +5,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -170,10 +170,6 @@ typedef enum dhd_iftype { DHD_IF_TYPE_STA = 0, DHD_IF_TYPE_AP = 1, -#ifdef DHD_AWDL - DHD_IF_TYPE_AWDL = 2, -#endif /* DHD_AWDL */ - DHD_IF_TYPE_NAN_NMI = 3, DHD_IF_TYPE_NAN = 4, DHD_IF_TYPE_P2P_GO = 5, @@ -225,9 +221,11 @@ typedef enum dhd_iface_mgmt_policy { /* * For cases where 16K buf is not sufficient. - * Ex:- DHD dump output beffer is more than 16K. + * Ex:- DHD dump output buffer is more than 16K. */ +#define DHD_IOCTL_MAXLEN_48K (48 * 1024) #define DHD_IOCTL_MAXLEN_32K (32768u) +#define DHD_DUMP_IOCTL_MAXLEN DHD_IOCTL_MAXLEN_48K /* common ioctl definitions */ #define DHD_GET_MAGIC 0 @@ -262,11 +260,7 @@ typedef enum dhd_iface_mgmt_policy { #define DHD_MSGTRACE_VAL 0x200000 #define DHD_FWLOG_VAL 0x400000 #define DHD_DBGIF_VAL 0x800000 -#ifdef DHD_PCIE_RUNTIMEPM #define DHD_RPM_VAL 0x1000000 -#else -#define DHD_RPM_VAL DHD_ERROR_VAL -#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ #define DHD_PKT_MON_VAL 0x2000000 #define DHD_PKT_MON_DUMP_VAL 0x4000000 #define DHD_ERROR_MEM_VAL 0x8000000 @@ -286,6 +280,9 @@ typedef enum dhd_iface_mgmt_policy { #define DUMP_DNS_VAL 0x0010 #define DUMP_TRX_VAL 0x0080 +/* Message levels for Mesh */ +#define MESH_MSG_HDR_VAL 0x00000001u /* Header details */ + #ifdef SDTEST /* For pktgen iovar */ typedef struct dhd_pktgen { @@ -313,6 +310,17 @@ typedef struct dhd_pktgen { #define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */ #endif /* SDTEST */ +/* For membytes iovar - flags param bit definitions and accessor macros */ +#define DHD_MEMBYTES_FLAGS_MAGIC 0x5DA60900 /* indicates flags presence */ +#define DHD_MEMBYTES_FLAGS_MAGIC_MASK 0xFFFFFF00 /* magic bytes mask */ +#define DHD_MEMBYTES_FLAGS_BAR_MASK 0x00000007 /* bar region mask */ +#define DHD_MEMBYTES_FLAGS_BAR_MIN 0 /* Min valid value for BAR region */ +#define DHD_MEMBYTES_FLAGS_BAR_MAX 5 /* Max valid value for BAR region */ +#define DHD_MEMBYTES_FLAGS_INIT(x) ((x) = ((uint32)DHD_MEMBYTES_FLAGS_MAGIC)) +#define DHD_MEMBYTES_FLAGS_GET_MAGIC(x) ((x) & DHD_MEMBYTES_FLAGS_MAGIC_MASK) +#define DHD_MEMBYTES_FLAGS_GET_BAR(x) ((x) & DHD_MEMBYTES_FLAGS_BAR_MASK) +#define DHD_MEMBYTES_FLAGS_SET_BAR(x, b) ((x) |= ((b) & DHD_MEMBYTES_FLAGS_BAR_MASK)) + /* Enter idle immediately (no timeout) */ #define DHD_IDLE_IMMEDIATE (-1) @@ -327,22 +335,22 @@ enum dhd_maclist_xtlv_type { }; typedef struct _dhd_maclist_t { - uint16 version; /* Version */ - uint16 bytes_len; /* Total bytes length of lists, XTLV headers and paddings */ - uint8 plist[1]; /* Pointer to the first list */ + uint16 version; /* Version */ + uint16 bytes_len; /* Total bytes length of lists, XTLV headers and paddings */ + uint8 plist[BCM_FLEX_ARRAY]; /* Pointer to the first list */ } dhd_maclist_t; typedef struct _dhd_pd11regs_param { uint16 start_idx; uint8 verbose; uint8 pad; - uint8 plist[1]; + uint8 plist[BCM_FLEX_ARRAY]; } dhd_pd11regs_param; typedef struct _dhd_pd11regs_buf { uint16 idx; uint8 pad[2]; - uint8 pbuf[1]; + uint8 pbuf[BCM_FLEX_ARRAY]; } dhd_pd11regs_buf; /* BT logging and memory dump */ @@ -383,64 +391,6 @@ typedef struct debug_buf_dest_stat { uint32 stat[DEBUG_BUF_DEST_MAX]; } debug_buf_dest_stat_t; -#ifdef DHD_PKTTS -/* max pktts flow config supported */ -#define PKTTS_CONFIG_MAX 8 - -#define PKTTS_OFFSET_INVALID ((uint32)(~0)) - -/* pktts flow configuration */ -typedef struct pktts_flow { - uint16 ver; /**< version of this struct */ - uint16 len; /**< length in bytes of this structure */ - uint32 src_ip; /**< source ip address */ - uint32 dst_ip; /**< destination ip address */ - uint32 src_port; /**< source port */ - uint32 dst_port; /**< destination port */ - uint32 proto; /**< protocol */ - uint32 ip_prec; /**< ip precedence */ - uint32 pkt_offset; /**< offset from data[0] (TCP/UDP payload) */ - uint32 chksum; /**< 5 tuple checksum */ -} pktts_flow_t; - -#define BCM_TS_MAGIC 0xB055B055 -#define BCM_TS_MAGIC_V2 0xB055B056 -#define BCM_TS_TX 1u -#define BCM_TS_RX 2u -#define BCM_TS_UTX 3u /* ucode tx timestamps */ - -#define PKTTS_MAX_FWTX 4u -#define PKTTS_MAX_UCTX 5u -#define PKTTS_MAX_UCCNT 8u -#define PKTTS_MAX_FWRX 2u - -/* Firmware timestamp header */ -typedef struct bcm_to_info_hdr { - uint magic; /**< magic word */ - uint type; /**< tx/rx type */ - uint flowid; /**< 5 tuple checksum */ - uint prec; /**< ip precedence (IP_PREC) */ - uint8 xbytes[16]; /**< 16bytes info from pkt offset */ -} bcm_to_info_hdr_t; - -/* Firmware tx timestamp payload structure */ -typedef struct bcm_to_info_tx_ts { - bcm_to_info_hdr_t hdr; - uint64 dhdt0; /**< system time - DHDT0 */ - uint64 dhdt5; /**< system time - DHDT5 */ - uint fwts[PKTTS_MAX_FWTX]; /**< fw timestamp - FWT0..FWT4 */ - uint ucts[PKTTS_MAX_UCTX]; /**< uc timestamp - UCT0..UCT4 */ - uint uccnt[PKTTS_MAX_UCCNT]; /**< uc counters */ -} bcm_to_info_tx_ts_t; - -/* Firmware rx timestamp payload structure */ -typedef struct bcm_to_info_rx_ts { - bcm_to_info_hdr_t hdr; - uint64 dhdr3; /**< system time - DHDR3 */ - uint fwts[PKTTS_MAX_FWRX]; /**< fw timestamp - FWT0, FWT1 */ -} bcm_to_info_rx_ts_t; -#endif /* DHD_PKTTS */ - /* devreset */ #define DHD_DEVRESET_VERSION 1 @@ -475,4 +425,26 @@ typedef struct dhd_tx_profile_protocol { #define DHD_MAX_PROFILES (1u) /* ucode only supports 1 profile atm */ #endif /* defined(DHD_TX_PROFILE) */ + +typedef struct dhd_loglevel_data { + uint32 type; + uint32 component; + uint32 dhd_print_lv; + uint32 dhd_log_lv; + uint32 wl_print_lv; + uint32 wl_log_lv; +} dhd_loglevel_data_t; + +typedef enum dhd_loglevel_type { + DHD_LOGLEVEL_TYPE_ALL = 0, + DHD_LOGLEVEL_TYPE_PRINT = 1, + DHD_LOGLEVEL_TYPE_LOG = 2, + DHD_LOGLEVEL_TYPE_INVALID = 3 +} dhd_loglevel_type_t; + +typedef enum dhd_loglevel_comp { + DHD_LOGLEVEL_COMP_DHD = 0, + DHD_LOGLEVEL_COMP_WL = 1, + DHD_LOGLEVEL_COMP_INVALID = 2 +} dhd_loglevel_comp_t; #endif /* _dhdioctl_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_rtlv.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_rtlv.h old mode 100755 new mode 100644 index 450caa237999..a1a14add605e --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_rtlv.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_rtlv.h @@ -1,7 +1,7 @@ /* * Interface definitions for reversed TLVs * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -24,6 +24,8 @@ #ifndef _dngl_rtlv_h_ #define _dngl_rtlv_h_ +#ifndef _LANGUAGE_ASSEMBLY + #include /* Types of reverse TLVs downloaded to the top of dongle RAM. @@ -32,16 +34,7 @@ * len <4 bytes> * type <4 bytes> */ -enum { - DNGL_RTLV_TYPE_NONE = 0, - /* replaces bcmrand.h BCM_NVRAM_RNG_SIGNATURE */ - DNGL_RTLV_TYPE_RNG_SIGNATURE = 0xFEEDC0DEu, /* RNG random data */ - DNGL_RTLV_TYPE_FW_SIGNATURE = 0xFEEDFE51, /* FW signature */ - DNGL_RTLV_TYPE_NVRAM_SIGNATURE = 0xFEEDFE52, /* NVRAM signature */ - DNGL_RTLV_TYPE_FWSIGN_MEM_MAP = 0xFEEDFE53, /* FW signing memory map */ - DNGL_RTLV_TYPE_FWSIGN_STATUS = 0xFEEDFE54, /* signature verification status */ - DNGL_RTLV_TYPE_END_MARKER = 0xFEED0E2D, /* end of rTLVs marker */ -}; + typedef uint32 dngl_rtlv_type_t; typedef uint32 dngl_rtlv_len_t; @@ -63,4 +56,28 @@ void dbg_log_rtlv(const char* str, const void* p1, const void* p2, const void *p #define dbg_log_rtlv(str, p1, p2, p3, p4, p5) #endif /* RTLV_DEBUG */ +#endif /* !_LANGUAGE_ASSEMBLY */ + +/* All DHD->firmware TLV type codes are declared here. + * This file may be included into assembly files + */ + +#define DNGL_RTLV_TYPE_NONE 0 +/* RNG random data. replaces bcmrand.h BCM_NVRAM_RNG_SIGNATURE */ +#define DNGL_RTLV_TYPE_RNG_SIGNATURE 0xFEEDC0DEu +/* FW signature */ +#define DNGL_RTLV_TYPE_FW_SIGNATURE 0xFEEDFE51u +/* NVRAM signature */ +#define DNGL_RTLV_TYPE_NVRAM_SIGNATURE 0xFEEDFE52u +/* FW signing memory map */ +#define DNGL_RTLV_TYPE_FWSIGN_MEM_MAP 0xFEEDFE53u +/* signature verification status */ +#define DNGL_RTLV_TYPE_FWSIGN_STATUS 0xFEEDFE54u +/* host page location */ +#define DNGL_RTLV_TYPE_HOST_PAGE_LOCATION 0xFEED10C5u +/* host fwtrace buffer location */ +#define DNGL_RTLV_HOST_FWTRACE_BUF_LOCATION 0xFEED10C6u +/* end of rTLVs marker */ +#define DNGL_RTLV_TYPE_END_MARKER 0xFEED0E2Du + #endif /* _dngl_rtlv_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_stats.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_stats.h old mode 100755 new mode 100644 index 12195f209559..0d38086b0f36 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_stats.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_stats.h @@ -2,7 +2,7 @@ * Common stats definitions for clients of dongle * ports * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -19,19 +19,12 @@ * modifications of the software. * * - * <> - * - * $Id$ + * <> */ #ifndef _dngl_stats_h_ #define _dngl_stats_h_ -#include -#include <802.11.h> -#include - -/* XXX happens to mirror a section of linux's net_device_stats struct */ typedef struct { unsigned long rx_packets; /* total packets received */ unsigned long tx_packets; /* total packets transmitted */ @@ -41,348 +34,10 @@ typedef struct { unsigned long tx_errors; /* packet transmit problems */ unsigned long rx_dropped; /* packets dropped by dongle */ unsigned long tx_dropped; /* packets dropped by dongle */ - unsigned long multicast; /* multicast packets received */ + unsigned long multicast; /* multicast packets received */ } dngl_stats_t; -typedef int32 wifi_radio; -typedef int32 wifi_channel; -typedef int32 wifi_rssi; -typedef struct { uint16 version; uint16 length; } ver_len; - -typedef enum wifi_channel_width { - WIFI_CHAN_WIDTH_20 = 0, - WIFI_CHAN_WIDTH_40 = 1, - WIFI_CHAN_WIDTH_80 = 2, - WIFI_CHAN_WIDTH_160 = 3, - WIFI_CHAN_WIDTH_80P80 = 4, - WIFI_CHAN_WIDTH_5 = 5, - WIFI_CHAN_WIDTH_10 = 6, - WIFI_CHAN_WIDTH_INVALID = -1 -} wifi_channel_width_t; - -typedef enum { - WIFI_DISCONNECTED = 0, - WIFI_AUTHENTICATING = 1, - WIFI_ASSOCIATING = 2, - WIFI_ASSOCIATED = 3, - WIFI_EAPOL_STARTED = 4, /* if done by firmware/driver */ - WIFI_EAPOL_COMPLETED = 5, /* if done by firmware/driver */ -} wifi_connection_state; - -typedef enum { - WIFI_ROAMING_IDLE = 0, - WIFI_ROAMING_ACTIVE = 1 -} wifi_roam_state; - -typedef enum { - WIFI_INTERFACE_STA = 0, - WIFI_INTERFACE_SOFTAP = 1, - WIFI_INTERFACE_IBSS = 2, - WIFI_INTERFACE_P2P_CLIENT = 3, - WIFI_INTERFACE_P2P_GO = 4, - WIFI_INTERFACE_NAN = 5, - WIFI_INTERFACE_MESH = 6 -} wifi_interface_mode; - -#define WIFI_CAPABILITY_QOS 0x00000001 /* set for QOS association */ -#define WIFI_CAPABILITY_PROTECTED 0x00000002 /* set for protected association (802.11 - * beacon frame control protected bit set) - */ -#define WIFI_CAPABILITY_INTERWORKING 0x00000004 /* set if 802.11 Extended Capabilities - * element interworking bit is set - */ -#define WIFI_CAPABILITY_HS20 0x00000008 /* set for HS20 association */ -#define WIFI_CAPABILITY_SSID_UTF8 0x00000010 /* set is 802.11 Extended Capabilities - * element UTF-8 SSID bit is set - */ -#define WIFI_CAPABILITY_COUNTRY 0x00000020 /* set is 802.11 Country Element is present */ -#ifdef LINUX -#define PACK_ATTRIBUTE __attribute__ ((packed)) -#else -#define PACK_ATTRIBUTE -#endif -typedef struct { - wifi_interface_mode mode; /* interface mode */ - uint8 mac_addr[6]; /* interface mac address (self) */ - uint8 PAD[2]; - wifi_connection_state state; /* connection state (valid for STA, CLI only) */ - wifi_roam_state roaming; /* roaming state */ - uint32 capabilities; /* WIFI_CAPABILITY_XXX (self) */ - uint8 ssid[DOT11_MAX_SSID_LEN+1]; /* null terminated SSID */ - uint8 bssid[ETHER_ADDR_LEN]; /* bssid */ - uint8 PAD[1]; - uint8 ap_country_str[3]; /* country string advertised by AP */ - uint8 country_str[3]; /* country string for this association */ - uint8 PAD[2]; -} wifi_interface_info; - -typedef wifi_interface_info *wifi_interface_handle; - -/* channel information */ -typedef struct { - wifi_channel_width_t width; /* channel width (20, 40, 80, 80+80, 160) */ - wifi_channel center_freq; /* primary 20 MHz channel */ - wifi_channel center_freq0; /* center frequency (MHz) first segment */ - wifi_channel center_freq1; /* center frequency (MHz) second segment */ -} wifi_channel_info; - -/* wifi rate */ -typedef struct { - uint32 preamble; /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ - uint32 nss; /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ - uint32 bw; /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ - uint32 rateMcsIdx; /* OFDM/CCK rate code would be as per ieee std - * in the units of 0.5mbps - */ - /* HT/VHT it would be mcs index */ - uint32 reserved; /* reserved */ - uint32 bitrate; /* units of 100 Kbps */ -} wifi_rate; - -typedef struct { - uint32 preamble :3; /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ - uint32 nss :2; /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ - uint32 bw :3; /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ - uint32 rateMcsIdx :8; /* OFDM/CCK rate code would be as per ieee std - * in the units of 0.5mbps HT/VHT it would be - * mcs index - */ - uint32 reserved :16; /* reserved */ - uint32 bitrate; /* units of 100 Kbps */ -} wifi_rate_v1; - -/* channel statistics */ -typedef struct { - wifi_channel_info channel; /* channel */ - uint32 on_time; /* msecs the radio is awake (32 bits number - * accruing over time) - */ - uint32 cca_busy_time; /* msecs the CCA register is busy (32 bits number - * accruing over time) - */ -} wifi_channel_stat; - -/* radio statistics */ -typedef struct { - struct { - uint16 version; - uint16 length; - }; - wifi_radio radio; /* wifi radio (if multiple radio supported) */ - uint32 on_time; /* msecs the radio is awake (32 bits number - * accruing over time) - */ - uint32 tx_time; /* msecs the radio is transmitting (32 bits - * number accruing over time) - */ - uint32 rx_time; /* msecs the radio is in active receive (32 bits - * number accruing over time) - */ - uint32 on_time_scan; /* msecs the radio is awake due to all scan (32 bits - * number accruing over time) - */ - uint32 on_time_nbd; /* msecs the radio is awake due to NAN (32 bits - * number accruing over time) - */ - uint32 on_time_gscan; /* msecs the radio is awake due to G?scan (32 bits - * number accruing over time) - */ - uint32 on_time_roam_scan; /* msecs the radio is awake due to roam?scan (32 bits - * number accruing over time) - */ - uint32 on_time_pno_scan; /* msecs the radio is awake due to PNO scan (32 bits - * number accruing over time) - */ - uint32 on_time_hs20; /* msecs the radio is awake due to HS2.0 scans and - * GAS exchange (32 bits number accruing over time) - */ - uint32 num_channels; /* number of channels */ - wifi_channel_stat channels[1]; /* channel statistics */ -} wifi_radio_stat; - -typedef struct { - wifi_radio radio; - uint32 on_time; - uint32 tx_time; - uint32 rx_time; - uint32 on_time_scan; - uint32 on_time_nbd; - uint32 on_time_gscan; - uint32 on_time_roam_scan; - uint32 on_time_pno_scan; - uint32 on_time_hs20; - uint32 num_channels; -} wifi_radio_stat_h; - -/* per rate statistics */ -typedef struct { - wifi_rate_v1 rate; /* rate information */ - uint32 tx_mpdu; /* number of successfully transmitted data pkts (ACK rcvd) */ - uint32 rx_mpdu; /* number of received data pkts */ - uint32 mpdu_lost; /* number of data packet losses (no ACK) */ - uint32 retries; /* total number of data pkt retries */ - uint32 retries_short; /* number of short data pkt retries */ - uint32 retries_long; /* number of long data pkt retries */ -} wifi_rate_stat_v1; - -typedef struct { - uint16 version; - uint16 length; - uint32 tx_mpdu; /* number of successfully transmitted data pkts (ACK rcvd) */ - uint32 rx_mpdu; /* number of received data pkts */ - uint32 mpdu_lost; /* number of data packet losses (no ACK) */ - uint32 retries; /* total number of data pkt retries */ - uint32 retries_short; /* number of short data pkt retries */ - uint32 retries_long; /* number of long data pkt retries */ - wifi_rate rate; -} wifi_rate_stat; - -/* access categories */ -typedef enum { - WIFI_AC_VO = 0, - WIFI_AC_VI = 1, - WIFI_AC_BE = 2, - WIFI_AC_BK = 3, - WIFI_AC_MAX = 4 -} wifi_traffic_ac; - -/* wifi peer type */ -typedef enum -{ - WIFI_PEER_STA, - WIFI_PEER_AP, - WIFI_PEER_P2P_GO, - WIFI_PEER_P2P_CLIENT, - WIFI_PEER_NAN, - WIFI_PEER_TDLS, - WIFI_PEER_INVALID -} wifi_peer_type; - -/* per peer statistics */ -typedef struct { - wifi_peer_type type; /* peer type (AP, TDLS, GO etc.) */ - uint8 peer_mac_address[6]; /* mac address */ - uint32 capabilities; /* peer WIFI_CAPABILITY_XXX */ - uint32 num_rate; /* number of rates */ - wifi_rate_stat rate_stats[1]; /* per rate statistics, number of entries = num_rate */ -} wifi_peer_info; - -/* per access category statistics */ -typedef struct { - wifi_traffic_ac ac; /* access category (VI, VO, BE, BK) */ - uint32 tx_mpdu; /* number of successfully transmitted unicast data pkts - * (ACK rcvd) - */ - uint32 rx_mpdu; /* number of received unicast mpdus */ - uint32 tx_mcast; /* number of succesfully transmitted multicast - * data packets - */ - /* STA case: implies ACK received from AP for the - * unicast packet in which mcast pkt was sent - */ - uint32 rx_mcast; /* number of received multicast data packets */ - uint32 rx_ampdu; /* number of received unicast a-mpdus */ - uint32 tx_ampdu; /* number of transmitted unicast a-mpdus */ - uint32 mpdu_lost; /* number of data pkt losses (no ACK) */ - uint32 retries; /* total number of data pkt retries */ - uint32 retries_short; /* number of short data pkt retries */ - uint32 retries_long; /* number of long data pkt retries */ - uint32 contention_time_min; /* data pkt min contention time (usecs) */ - uint32 contention_time_max; /* data pkt max contention time (usecs) */ - uint32 contention_time_avg; /* data pkt avg contention time (usecs) */ - uint32 contention_num_samples; /* num of data pkts used for contention statistics */ -} wifi_wmm_ac_stat; - -/* interface statistics */ -typedef struct { - wifi_interface_handle iface; /* wifi interface */ - wifi_interface_info info; /* current state of the interface */ - uint32 beacon_rx; /* access point beacon received count from - * connected AP - */ - uint64 average_tsf_offset; /* average beacon offset encountered (beacon_TSF - TBTT) - * The average_tsf_offset field is used so as to calculate - * the typical beacon contention time on the channel as well - * may be used to debug beacon synchronization and related - * power consumption issue - */ - uint32 leaky_ap_detected; /* indicate that this AP - * typically leaks packets beyond - * the driver guard time. - */ - uint32 leaky_ap_avg_num_frames_leaked; /* average number of frame leaked by AP after - * frame with PM bit set was ACK'ed by AP - */ - uint32 leaky_ap_guard_time; /* guard time currently in force - * (when implementing IEEE power management - * based on frame control PM bit), How long - * driver waits before shutting down the radio and after - * receiving an ACK for a data frame with PM bit set) - */ - uint32 mgmt_rx; /* access point mgmt frames received count from - * connected AP (including Beacon) - */ - uint32 mgmt_action_rx; /* action frames received count */ - uint32 mgmt_action_tx; /* action frames transmit count */ - wifi_rssi rssi_mgmt; /* access Point Beacon and Management frames RSSI - * (averaged) - */ - wifi_rssi rssi_data; /* access Point Data Frames RSSI (averaged) from - * connected AP - */ - wifi_rssi rssi_ack; /* access Point ACK RSSI (averaged) from - * connected AP - */ - wifi_wmm_ac_stat ac[WIFI_AC_MAX]; /* per ac data packet statistics */ - uint32 num_peers; /* number of peers */ - wifi_peer_info peer_info[1]; /* per peer statistics */ -} wifi_iface_stat; - -#ifdef CONFIG_COMPAT -/* interface statistics */ -typedef struct { - compat_uptr_t iface; /* wifi interface */ - wifi_interface_info info; /* current state of the interface */ - uint32 beacon_rx; /* access point beacon received count from - * connected AP - */ - uint64 average_tsf_offset; /* average beacon offset encountered (beacon_TSF - TBTT) - * The average_tsf_offset field is used so as to calculate - * the typical beacon contention time on the channel as well - * may be used to debug beacon synchronization and related - * power consumption issue - */ - uint32 leaky_ap_detected; /* indicate that this AP - * typically leaks packets beyond - * the driver guard time. - */ - uint32 leaky_ap_avg_num_frames_leaked; /* average number of frame leaked by AP after - * frame with PM bit set was ACK'ed by AP - */ - uint32 leaky_ap_guard_time; /* guard time currently in force - * (when implementing IEEE power management - * based on frame control PM bit), How long - * driver waits before shutting down the radio and after - * receiving an ACK for a data frame with PM bit set) - */ - uint32 mgmt_rx; /* access point mgmt frames received count from - * connected AP (including Beacon) - */ - uint32 mgmt_action_rx; /* action frames received count */ - uint32 mgmt_action_tx; /* action frames transmit count */ - wifi_rssi rssi_mgmt; /* access Point Beacon and Management frames RSSI - * (averaged) - */ - wifi_rssi rssi_data; /* access Point Data Frames RSSI (averaged) from - * connected AP - */ - wifi_rssi rssi_ack; /* access Point ACK RSSI (averaged) from - * connected AP - */ - wifi_wmm_ac_stat ac[WIFI_AC_MAX]; /* per ac data packet statistics */ - uint32 num_peers; /* number of peers */ - wifi_peer_info peer_info[1]; /* per peer statistics */ -} compat_wifi_iface_stat; -#endif /* CONFIG_COMPAT */ +// remove the conditional after moving all branches to use the new code +#define USE_WIFI_STATS_H #endif /* _dngl_stats_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_wlhdr.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_wlhdr.h deleted file mode 100755 index 6e1f74eadedd..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dngl_wlhdr.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Dongle WL Header definitions - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - */ - -#ifndef _dngl_wlhdr_h_ -#define _dngl_wlhdr_h_ - -typedef struct wl_header { - uint8 type; /* Header type */ - uint8 version; /* Header version */ - int8 rssi; /* RSSI */ - uint8 pad; /* Unused */ -} wl_header_t; - -#define WL_HEADER_LEN sizeof(wl_header_t) -#define WL_HEADER_TYPE 0 -#define WL_HEADER_VER 1 -#endif /* _dngl_wlhdr_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dnglevent.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dnglevent.h old mode 100755 new mode 100644 index 40a1676b5dcf..5cff81d5cba4 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dnglevent.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dnglevent.h @@ -3,7 +3,7 @@ * * Dependencies: bcmeth.h * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -50,6 +50,7 @@ #define DNGL_E_RSRVD_2 0x1 #define DNGL_E_SOCRAM_IND 0x2 #define DNGL_E_PROFILE_DATA_IND 0x3 +#define DNGL_E_SPMI_RESET_IND 0x4 typedef BWL_PRE_PACKED_STRUCT struct { uint16 version; /* Current version is 1 */ @@ -68,7 +69,7 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_event { typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_socramind { uint16 tag; /* data tag */ uint16 length; /* data length */ - uint8 value[1]; /* data value with variable length specified by length */ + uint8 value[BCM_FLEX_ARRAY]; /* variable length specified by length */ } BWL_POST_PACKED_STRUCT bcm_dngl_socramind_t; typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_profile_data_ind_t { @@ -77,6 +78,16 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_profile_data_ind_t { uint8 value[]; } BWL_POST_PACKED_STRUCT bcm_dngl_profile_data_ind_t; +#define DNGL_E_SPMI_RESET_IND_VERSION_1 1u +#define DNGL_E_SPMI_RESET_IND_VERSION DNGL_E_SPMI_RESET_IND_VERSION_1 + +typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_spmi_reset_ind_v1_t { + uint16 version; /* Current version is 1 */ + uint16 num_resets; /* number of resets seen since last message */ + uint8 slave_idx; /* Slave idx of the SPMI core that was reset */ + uint8 PAD[3]; +} BWL_POST_PACKED_STRUCT bcm_dngl_spmi_reset_ind_v1_t; + typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_arm_event { uint32 type; uint32 value; @@ -112,7 +123,7 @@ typedef enum socram_ind_tag { typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_healthcheck { uint16 top_module_tag; /* top level module tag */ uint16 top_module_len; /* Type of PCIE issue indication */ - uint8 value[1]; /* data value with variable length specified by length */ + uint8 value[BCM_FLEX_ARRAY]; /* variable length specified by length */ } BWL_POST_PACKED_STRUCT bcm_dngl_healthcheck_t; /* Health check top level module tags */ @@ -142,6 +153,9 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_healthcheck { #define HEALTH_CHECK_PCIEDEV_FLOWRING_IND 0x9 #define HEALTH_CHECK_PCIEDEV_HW_ASSERT_LONG_IND 0xA #define HEALTH_CHECK_PCIEDEV_RXPOST_LONG_IND 0xB +#define HEALTH_CHECK_PCIEDEV_PTM_DRIFT_IND 0xC +#define HEALTH_CHECK_PCIEDEV_PTM_FAIL_IND 0xD +#define HEALTH_CHECK_PCIEDEV_PTM_TIMEOUT_IND 0xE #define HC_PCIEDEV_CONFIG_REGLIST_MAX 25 typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_pcie_hc { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dnglioctl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dnglioctl.h old mode 100755 new mode 100644 index a18c716ed776..4a9769a62085 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dnglioctl.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dnglioctl.h @@ -1,7 +1,7 @@ /* * HND Run Time Environment ioctl. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2023, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/eap.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/eap.h deleted file mode 100755 index cfd9e580b44c..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/eap.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Extensible Authentication Protocol (EAP) definitions - * - * See - * RFC 2284: PPP Extensible Authentication Protocol (EAP) - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -#ifndef _eap_h_ -#define _eap_h_ - -/* This marks the start of a packed structure section. */ -#include - -/* EAP packet format */ -typedef BWL_PRE_PACKED_STRUCT struct { - unsigned char code; /* EAP code */ - unsigned char id; /* Current request ID */ - unsigned short length; /* Length including header */ - unsigned char type; /* EAP type (optional) */ - unsigned char data[1]; /* Type data (optional) */ -} BWL_POST_PACKED_STRUCT eap_header_t; - -#define EAP_HEADER_LEN 4u -#define EAP_HEADER_LEN_WITH_TYPE 5u -#define ERP_FLAGS_LEN 1u -#define ERP_SEQ_LEN 2u -#define ERP_KEYNAMENAI_HEADER_LEN 2u -#define ERP_CRYPTOSUITE_LEN 1u - -/* EAP codes */ -#define EAP_REQUEST 1u -#define EAP_RESPONSE 2u -#define EAP_SUCCESS 3u -#define EAP_FAILURE 4u -#define EAP_INITIATE 5u -#define EAP_FINISH 6u - -/* EAP types */ -#define EAP_IDENTITY 1 -#define EAP_NOTIFICATION 2 -#define EAP_NAK 3 -#define EAP_MD5 4 -#define EAP_OTP 5 -#define EAP_GTC 6 -#define EAP_TLS 13 -#define EAP_EXPANDED 254 -#define BCM_EAP_SES 10 -#define BCM_EAP_EXP_LEN 12 /* EAP_LEN 5 + 3 bytes for SMI ID + 4 bytes for ven type */ -#define BCM_SMI_ID 0x113d -#define WFA_VENDOR_SMI 0x009F68 - -/* ERP types */ -#define EAP_ERP_TYPE_REAUTH_START 1u -#define EAP_ERP_TYPE_REAUTH 2u - -/* EAP FLAGS */ -#define ERP_R_FLAG 0x80 /* result flag, set = failure */ -#define ERP_B_FLAG 0x40 /* bootstrap flag, set = bootstrap */ -#define ERP_L_FLAG 0x20 /* rrk lifetime tlv is present */ - -/* ERP TV/TLV types */ -#define EAP_ERP_TLV_KEYNAME_NAI 1u - -/* ERP Cryptosuite */ -#define EAP_ERP_CS_HMAC_SHA256_128 2u - -#ifdef BCMCCX -#define EAP_LEAP 17 - -#define LEAP_VERSION 1 -#define LEAP_CHALLENGE_LEN 8 -#define LEAP_RESPONSE_LEN 24 - -/* LEAP challenge */ -typedef struct { - unsigned char version; /* should be value of LEAP_VERSION */ - unsigned char reserved; /* not used */ - unsigned char chall_len; /* always value of LEAP_CHALLENGE_LEN */ - unsigned char challenge[LEAP_CHALLENGE_LEN]; /* random */ - unsigned char username[1]; -} leap_challenge_t; - -#define LEAP_CHALLENGE_HDR_LEN 12 - -/* LEAP challenge reponse */ -typedef struct { - unsigned char version; /* should be value of LEAP_VERSION */ - unsigned char reserved; /* not used */ - unsigned char resp_len; /* always value of LEAP_RESPONSE_LEN */ - /* MS-CHAP hash of challenge and user's password */ - unsigned char response[LEAP_RESPONSE_LEN]; - unsigned char username[1]; -} leap_response_t; - -#define LEAP_RESPONSE_HDR_LEN 28 - -#endif /* BCMCCX */ - -/* This marks the end of a packed structure section. */ -#include - -#endif /* _eap_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/eapol.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/eapol.h old mode 100755 new mode 100644 index 84b8b26c0292..e170a338c817 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/eapol.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/eapol.h @@ -5,7 +5,7 @@ * IEEE Std 802.1X-2001 * IEEE 802.1X RADIUS Usage Guidelines * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -41,11 +41,11 @@ /* EAPOL for 802.3/Ethernet */ typedef BWL_PRE_PACKED_STRUCT struct { - struct ether_header eth; /* 802.3/Ethernet header */ - unsigned char version; /* EAPOL protocol version */ - unsigned char type; /* EAPOL type */ - unsigned short length; /* Length of body */ - unsigned char body[1]; /* Body (optional) */ + struct ether_header eth; /* 802.3/Ethernet header */ + unsigned char version; /* EAPOL protocol version */ + unsigned char type; /* EAPOL type */ + unsigned short length; /* Length of body */ + unsigned char body[BCM_FLEX_ARRAY]; /* Body (optional) */ } BWL_POST_PACKED_STRUCT eapol_header_t; #define EAPOL_HEADER_LEN 18 @@ -83,13 +83,13 @@ typedef struct { /* RC4 EAPOL-Key */ typedef BWL_PRE_PACKED_STRUCT struct { - unsigned char type; /* Key Descriptor Type */ - unsigned short length; /* Key Length (unaligned) */ + unsigned char type; /* Key Descriptor Type */ + unsigned short length; /* Key Length (unaligned) */ unsigned char replay[EAPOL_KEY_REPLAY_LEN]; /* Replay Counter */ unsigned char iv[EAPOL_KEY_IV_LEN]; /* Key IV */ unsigned char index; /* Key Flags & Index */ unsigned char signature[EAPOL_KEY_SIG_LEN]; /* Key Signature */ - unsigned char key[1]; /* Key (optional) */ + unsigned char key[BCM_FLEX_ARRAY]; /* Key (optional) */ } BWL_POST_PACKED_STRUCT eapol_key_header_t; #define EAPOL_KEY_HEADER_LEN 44u @@ -123,6 +123,7 @@ typedef BWL_PRE_PACKED_STRUCT struct { #define EAPOL_WPA_KCK_MIC_DEFAULT_LEN 16u #define EAPOL_WPA_KCK_MIC_SHA384_LEN 24u #define EAPOL_WPA_ENCR_KEY_DEFAULT_LEN 16u +#define EAPOL_WPA_ENCR_KEY_SHA384_LEN 32u #define EAPOL_WPA_KEK2_SHA256_LEN 16u #define EAPOL_WPA_KEK2_SHA384_LEN 32u @@ -134,11 +135,15 @@ typedef BWL_PRE_PACKED_STRUCT struct { #define EAPOL_WPA_KEY_LEN 95u /* deprecated */ #endif +/* If a KDK is derived, KDK bits is equal to PMK bits */ +#define EAPOL_WPA_KDK_MAX_LEN EAPOL_WPA_PMK_MAX_LEN + #define EAPOL_PTK_KEY_MAX_LEN (EAPOL_WPA_KEY_MAX_MIC_LEN +\ EAPOL_WPA_ENCR_KEY_MAX_LEN +\ EAPOL_WPA_TEMP_ENCR_KEY_MAX_LEN +\ EAPOL_WPA_KCK2_SHA384_LEN +\ - EAPOL_WPA_KEK2_SHA384_LEN) + EAPOL_WPA_KEK2_SHA384_LEN +\ + EAPOL_WPA_KDK_MAX_LEN) #ifndef EAPOL_KEY_HDR_VER_V2 @@ -230,18 +235,29 @@ typedef BWL_PRE_PACKED_STRUCT struct { uint8 length; uint8 oui[3]; uint8 subtype; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT eapol_wpa2_encap_data_t; -#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6 +#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6u -#define WPA2_KEY_DATA_SUBTYPE_GTK 1 -#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2 -#define WPA2_KEY_DATA_SUBTYPE_MAC 3 -#define WPA2_KEY_DATA_SUBTYPE_PMKID 4 -#define WPA2_KEY_DATA_SUBTYPE_IGTK 9 -#define WPA2_KEY_DATA_SUBTYPE_OCI 13 -#define WPA2_KEY_DATA_SUBTYPE_BIGTK 14 +#define WPA2_KEY_DATA_SUBTYPE_GTK 1 +#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2 +#define WPA2_KEY_DATA_SUBTYPE_MAC 3 +#define WPA2_KEY_DATA_SUBTYPE_PMKID 4 +#define WPA2_KEY_DATA_SUBTYPE_IGTK 9 +#define WPA2_KEY_DATA_SUBTYPE_OCI 13 +#define WPA2_KEY_DATA_SUBTYPE_BIGTK 14 +#define WPA2_KEY_DATA_SUBTYPE_MLO_GTK 16 +#define WPA2_KEY_DATA_SUBTYPE_MLO_IGTK 17 +#define WPA2_KEY_DATA_SUBTYPE_MLO_BIGTK 18 +#define WPA2_KEY_DATA_SUBTYPE_MLO_LINK_KDE 19 + +#define WPA2_GTK_INDEX_MASK 0x03 +#define WPA2_GTK_INDEX_SHIFT 0x00 +#define WPA2_GTK_TRANSMIT 0x04 +#define WPA2_MLO_GTK_LINK_ID_MASK 0xF0u +#define WPA2_MLO_GTK_LINK_ID_SHIFT 0x4u +#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2u /* GTK encapsulation */ typedef BWL_PRE_PACKED_STRUCT struct { @@ -250,12 +266,15 @@ typedef BWL_PRE_PACKED_STRUCT struct { uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE]; } BWL_POST_PACKED_STRUCT eapol_wpa2_key_gtk_encap_t; -#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2 +#define EAPOL_WPA2_KEY_MLO_GTK_ENCAP_HDR_LEN 7u +/* MLO GTK encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 flags; /* KeyID [0-1], Tx [2], rsvd [3], link_id [4-7] */ + uint8 PN[6]; /* Packet number */ + uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_key_mlo_gtk_encap_t; -#define WPA2_GTK_INDEX_MASK 0x03 -#define WPA2_GTK_INDEX_SHIFT 0x00 - -#define WPA2_GTK_TRANSMIT 0x04 +#define EAPOL_WPA2_KEY_IGTK_ENCAP_HDR_LEN 8u /* IGTK encapsulation */ #define EAPOL_RSN_IPN_SIZE 6u @@ -265,17 +284,51 @@ typedef BWL_PRE_PACKED_STRUCT struct { uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; } BWL_POST_PACKED_STRUCT eapol_wpa2_key_igtk_encap_t; -#define EAPOL_WPA2_KEY_IGTK_ENCAP_HDR_LEN 8u +#define EAPOL_WPA2_KEY_MLO_IGTK_ENCAP_HDR_LEN 9u + +/* MLO IGTK encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 key_id; + uint8 ipn[EAPOL_RSN_IPN_SIZE]; + uint8 link_id; /* rsvd [0-3], link_id [4-7] */ + uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_key_mlo_igtk_encap_t; /* BIGTK encapsulation */ #define EAPOL_RSN_BIPN_SIZE 6u +#define EAPOL_WPA2_KEY_BIGTK_ENCAP_HDR_LEN 8u + typedef BWL_PRE_PACKED_STRUCT struct { - uint16 key_id; - uint8 bipn[EAPOL_RSN_BIPN_SIZE]; - uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; + uint16 key_id; + uint8 bipn[EAPOL_RSN_BIPN_SIZE]; + uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; } BWL_POST_PACKED_STRUCT eapol_wpa2_key_bigtk_encap_t; -#define EAPOL_WPA2_KEY_BIGTK_ENCAP_HDR_LEN 8u +/* MLO BIGTK encapsulation */ +#define EAPOL_RSN_MLO_BIPN_SIZE 6u +#define EAPOL_WPA2_KEY_MLO_BIGTK_ENCAP_HDR_LEN 9u + +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 key_id; + uint8 bipn[EAPOL_RSN_MLO_BIPN_SIZE]; + uint8 link_id; /* rsvd [0-3], link_id [4-7] */ + uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_key_mlo_bigtk_encap_t; + +#define EAPOL_WPA2_LINK_INFO_LINKID_MASK (0xFu) +#define EAPOL_WPA2_LINK_INFO_RSNE_PRESENT (0x1u << 4u) +#define EAPOL_WPA2_LINK_INFO_RSNXE_PRESENT (0x1u << 5u) +#define EAPOL_WPA2_LINK_KDE_ENCAP_HDR_LEN 7u +/* Minimum length of WPA2 GTK encapsulation in EAPOL */ +#define EAPOL_WPA2_LINK_KDE_ENCAP_MIN_LEN (EAPOL_WPA2_ENCAP_DATA_HDR_LEN - \ + TLV_HDR_LEN + EAPOL_WPA2_LINK_KDE_ENCAP_HDR_LEN) + +/* MLO KDE encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 link_info; /* link_id [0-3], Rxneinfo [4], rsvd [5-7] */ + uint8 mac[ETHER_ADDR_LEN]; + uint8 data[BCM_FLEX_ARRAY]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_key_mlo_link_encap_t; /* STAKey encapsulation */ typedef BWL_PRE_PACKED_STRUCT struct { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/epivers.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/epivers.h old mode 100755 new mode 100644 index ac7bdb4a278c..b7f91141cc90 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/epivers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2023, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -23,29 +23,33 @@ #ifndef _epivers_h_ #define _epivers_h_ +#define EPI_VERGEN_VERSION 1 + #define EPI_MAJOR_VERSION 101 #define EPI_MINOR_VERSION 10 -#define EPI_RC_NUMBER 361 +#define EPI_RC_NUMBER 591 -#define EPI_INCREMENTAL_NUMBER 0 +#define EPI_INCREMENTAL_NUMBER 46 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 101, 10, 361, 0 +#define EPI_VERSION 101, 10, 591, 46 -#define EPI_VERSION_NUM 0x650a1690 +#define EPI_VERSION_NUM 0x650a24f2 -#define EPI_VERSION_DEV 101.10.361 +#define EPI_VERSION_DEV 101.10.591 + +#define EPI_COMMIT_ID "(a5ec15e)" /* Driver Version String, ASCII, 32 chars max */ #if defined (WLTEST) -#define EPI_VERSION_STR "101.10.361 (wlan=r892223 WLTEST)" +#define EPI_VERSION_STR "101.10.591.46 (WLTEST)" #elif (defined (BCMDBG_ASSERT) && !defined (BCMDBG_ASSERT_DISABLED)) -#define EPI_VERSION_STR "101.10.361 (wlan=r892223 ASSRT)" +#define EPI_VERSION_STR "101.10.591.46 (ASSRT)" #else -#define EPI_VERSION_STR "101.10.361.20 (wlan=r892223-20220701-3)" +#define EPI_VERSION_STR "101.10.591.46.22 (20231003-3)" #endif /* BCMINTERNAL */ #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/etd.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/etd.h old mode 100755 new mode 100644 index 013037bde084..9c97574ef71c --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/etd.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/etd.h @@ -1,7 +1,7 @@ /* * Extended Trap data component interface file. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -28,6 +28,7 @@ #include #endif #include + /* Tags for structures being used by etd info iovar. * Related structures are defined in wlioctl.h. */ @@ -141,7 +142,7 @@ typedef struct hnd_ext_trap_axi_sr_err_v1 uint32 sr_dig_gci_status_0; } hnd_ext_trap_axi_sr_err_v1_t; -#define HND_EXT_TRAP_PSMWD_INFO_VER 1 +#define HND_EXT_TRAP_PSMWD_INFO_VER_1 (1u) typedef struct hnd_ext_trap_psmwd_v1 { uint16 xtag; uint16 version; /* version of the information following this */ @@ -177,7 +178,8 @@ typedef struct hnd_ext_trap_psmwd_v1 { uint16 pad; } hnd_ext_trap_psmwd_v1_t; -typedef struct hnd_ext_trap_psmwd { +#define HND_EXT_TRAP_PSMWD_INFO_VER_2 (2u) +typedef struct hnd_ext_trap_psmwd_v2 { uint16 xtag; uint16 version; /* version of the information following this */ uint32 i32_maccontrol; @@ -214,7 +216,44 @@ typedef struct hnd_ext_trap_psmwd { uint16 shm_prewds_cnt; uint16 shm_txtplufl_cnt; uint16 shm_txphyerr_cnt; -} hnd_ext_trap_psmwd_t; +} hnd_ext_trap_psmwd_v2_t; + +#define HND_EXT_TRAP_PSMWD_INFO_VER_3 (3u) +typedef struct hnd_ext_trap_psmwd_v3 { + uint16 xtag; + uint16 version; /* version of the information following this */ + uint32 i32_maccontrol; + uint32 i32_maccommand; + uint32 i32_macintstatus; + uint32 i32_phydebug; + uint32 i32_clk_ctl_st; + uint32 i32_psmdebug[PSMDBG_REG_READ_CNT_FOR_PSMWDTRAP_V1]; + uint32 i32_gated_clock_en; /* gated clock en */ + uint16 rcv_fifo_ctrl; + uint16 rx_ctrl1; + uint16 rxe_status1; + uint16 rxe_status2; + uint16 rcv_wrd_count0; + uint16 rcv_wrd_count1; + uint16 rcv_lfifo_sts; + uint16 psm_slp_tmr; + uint16 psm_brc; + uint16 txe_ctrl; + uint16 txe_status; + uint16 txe_xmtdmabusy; + uint16 txe_xmt_fifo_susp_flush; + uint16 ifs_stat; + uint16 ifs_medbusy_ctr; + uint16 ifs_tx_dur; + uint16 slow_ctl; + uint16 txe_aqm_fifo_ready; + uint16 dagg_ctrl; + uint16 shm_prewds_cnt; + uint16 shm_txtplufl_cnt; + uint16 shm_txphyerr_cnt; + uint16 shm_ucode_dbgst; + uint16 PAD; +} hnd_ext_trap_psmwd_v3_t; #define HEAP_HISTOGRAM_DUMP_LEN 6 #define HEAP_MAX_SZ_BLKS_LEN 2 @@ -348,8 +387,8 @@ typedef struct hnd_ext_trap_macsusp { uint16 shm_ucode_dbgst; } hnd_ext_trap_macsusp_t; -#define HND_EXT_TRAP_MACENAB_INFO_VER 1 -typedef struct hnd_ext_trap_macenab { +#define HND_EXT_TRAP_MACENAB_INFO_VER_1 (1u) +typedef struct hnd_ext_trap_macenab_v1 { uint16 xtag; uint8 version; /* version of the information following this */ uint8 trap_reason; @@ -371,7 +410,33 @@ typedef struct hnd_ext_trap_macenab { uint16 i16_0x6aa; /* SLow_PER */ uint16 shm_ucode_dbgst; uint16 PAD; -} hnd_ext_trap_macenab_t; +} hnd_ext_trap_macenab_v1_t; + +#define HND_EXT_TRAP_MACENAB_INFO_VER_2 (2u) +typedef struct hnd_ext_trap_macenab_v2 { + uint16 xtag; + uint8 version; /* version of the information following this */ + uint8 trap_reason; + uint32 i32_maccontrol; + uint32 i32_maccommand; + uint32 i32_macintstatus; + uint32 i32_psmdebug[8]; + uint32 i32_clk_ctl_st; + uint32 i32_powerctl; + uint32 i32_gated_clock_en; + uint16 psm_slp_tmr; + uint16 psm_brc; + uint16 tsf_ctl; + uint16 ifs_stat; + uint16 ifs_medbusy_ctr; + uint16 slow_ctl; + uint16 slow_frac; + uint16 fast_powerup_delay; + uint16 slow_per; + uint16 shm_ucode_dbgst; + uint16 shm_prewds_cnt; + uint16 PAD; +} hnd_ext_trap_macenab_v2_t; #define HND_EXT_TRAP_PHY_INFO_VER_1 (1) typedef struct hnd_ext_trap_phydbg { @@ -450,7 +515,7 @@ typedef struct hnd_ext_trap_phydbg_v2 { uint16 gpioSel; uint16 pktprocdebug; uint32 gpioOut[3]; - uint32 additional_regs[1]; + uint32 additional_regs[BCM_FLEX_ARRAY]; } hnd_ext_trap_phydbg_v2_t; #define HND_EXT_TRAP_PHY_INFO_VER_3 (3) @@ -487,7 +552,7 @@ typedef struct hnd_ext_trap_phydbg_v3 { uint32 gpioOut[3]; uint16 HESigURateFlagStatus; uint16 HESigUsRateFlagStatus; - uint32 additional_regs[1]; + uint32 additional_regs[BCM_FLEX_ARRAY]; } hnd_ext_trap_phydbg_v3_t; /* Phy TxErr Dump Structure */ @@ -620,15 +685,15 @@ uint etd_get_reg_dump_config_len(void); extern bool _etd_enab; #if defined(ROM_ENAB_RUNTIME_CHECK) - #define ETD_ENAB(pub) (_etd_enab) + #define ETD_ENAB(pub) (_etd_enab) #elif defined(ETD_DISABLED) - #define ETD_ENAB(pub) (0) + #define ETD_ENAB(pub) (FALSE) #else - #define ETD_ENAB(pub) (1) + #define ETD_ENAB(pub) (TRUE) #endif #else -#define ETD_ENAB(pub) (0) +#define ETD_ENAB(pub) (FALSE) #endif /* WLETD */ #endif /* !LANGUAGE_ASSEMBLY */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/ethernet.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/ethernet.h old mode 100755 new mode 100644 index f378dd2cd7e2..a8e13bc084e0 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/ethernet.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/ethernet.h @@ -1,7 +1,7 @@ /* * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -175,10 +175,22 @@ BWL_PRE_PACKED_STRUCT struct ether_addr { (((const uint16 *)(a))[6] ^ ((const uint16 *)(b))[6])) #endif /* DONGLEBUILD && __ARM_ARCH_7A__ */ +#define eacmp_nogrp(a, b) \ + (((((const uint8 *)(a))[0] & 0x0e) ^ (((const uint8 *)(b))[0] & 0x0e)) | \ + (((const uint8 *)(a))[1] ^ ((const uint8 *)(b))[1]) | \ + (((const uint8 *)(a))[2] ^ ((const uint8 *)(b))[2]) | \ + (((const uint8 *)(a))[3] ^ ((const uint8 *)(b))[3]) | \ + (((const uint8 *)(a))[4] ^ ((const uint8 *)(b))[4]) | \ + (((const uint8 *)(a))[5] ^ ((const uint8 *)(b))[5])) + #define ether_cmp(a, b) eacmp(a, b) +#ifdef BCMFUZZ +/* memcpy_s to avoid alignment warnings for fuzzer */ +#define eacopy(s, d) ((void)memcpy_s((d), ETHER_ADDR_LEN, (s), ETHER_ADDR_LEN)) +#else /* copy an ethernet address - assumes the pointers can be referenced as shorts */ -#if defined(DONGLEBUILD) && defined(__ARM_ARCH_7A__) && !defined(BCMFUZZ) +#if defined(DONGLEBUILD) && defined(__ARM_ARCH_7A__) #define eacopy(s, d) \ do { \ (*(uint32 *)(d)) = (*(const uint32 *)(s)); \ @@ -192,6 +204,7 @@ do { \ ((uint16 *)(d))[2] = ((const uint16 *)(s))[2]; \ } while (0) #endif /* DONGLEBUILD && __ARM_ARCH_7A__ */ +#endif /* BCMFUZZ */ #define ether_copy(s, d) eacopy(s, d) @@ -244,7 +257,7 @@ do { \ *(struct ether_header *)(d) = t; \ } while (0) -#define ETHER_ISUCAST(ea) ((((uint8 *)(ea))[0] & 0x01) == 0) +#define ETHER_ISUCAST(ea) ((((const uint8 *)(ea))[0] & 0x01) == 0) /* This marks the end of a packed structure section. */ #include diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log.h old mode 100755 new mode 100644 index 8ede661f75c6..c2b0ee25a49e --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log.h @@ -1,7 +1,7 @@ /* * EVENT_LOG system definitions * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -36,44 +36,61 @@ /* max log size */ #define EVENT_LOG_MAX_SIZE (64u * 1024u) +#define EVENT_LOG_MIN_BLOCKS (2u) + /* We make sure that the block size will fit in a single packet * (allowing for a bit of overhead on each packet */ -#if defined(BCMPCIEDEV) -#define EVENT_LOG_MAX_BLOCK_SIZE 1648 +#ifndef EVENT_LOG_MAX_BLOCK_SIZE +#if (defined(BCMPCIEDEV) && defined(BCMPCIEDEV_ENABLED)) || defined(BCMPCIE) +#define EVENT_LOG_MAX_BLOCK_SIZE 1832 #else #define EVENT_LOG_MAX_BLOCK_SIZE 1400 #endif +#endif /* EVENT_LOG_MAX_BLOCK_SIZE */ #define EVENT_LOG_BLOCK_SIZE_1K 0x400u -#define EVENT_LOG_WL_BLOCK_SIZE 0x200 -#define EVENT_LOG_PSM_BLOCK_SIZE 0x200 -#define EVENT_LOG_MEM_API_BLOCK_SIZE 0x200 -#define EVENT_LOG_BUS_BLOCK_SIZE 0x200 -#define EVENT_LOG_ERROR_BLOCK_SIZE 0x400 -#define EVENT_LOG_MSCH_BLOCK_SIZE 0x400 -#define EVENT_LOG_WBUS_BLOCK_SIZE 0x100 -#define EVENT_LOG_PRSV_PERIODIC_BLOCK_SIZE (0x200u) - -#define EVENT_LOG_WL_BUF_SIZE (EVENT_LOG_WL_BLOCK_SIZE * 3u) +#define EVENT_LOG_BLOCK_SIZE_512B 0x200u +#define EVENT_LOG_BLOCK_SIZE_256B 0x100u +#define EVENT_LOG_BLOCK_SIZE_1648B 0x670u #define EVENT_LOG_TOF_INLINE_BLOCK_SIZE 1300u #define EVENT_LOG_TOF_INLINE_BUF_SIZE (EVENT_LOG_TOF_INLINE_BLOCK_SIZE * 3u) -#define EVENT_LOG_PRSRV_BUF_SIZE (EVENT_LOG_MAX_BLOCK_SIZE * 2) -#define EVENT_LOG_BUS_PRSRV_BUF_SIZE (EVENT_LOG_BUS_BLOCK_SIZE * 2) -#define EVENT_LOG_WBUS_PRSRV_BUF_SIZE (EVENT_LOG_WBUS_BLOCK_SIZE * 2) - -#define EVENT_LOG_BLOCK_SIZE_PRSRV_CHATTY (EVENT_LOG_MAX_BLOCK_SIZE * 1) -#define EVENT_LOG_BLOCK_SIZE_BUS_PRSRV_CHATTY (EVENT_LOG_MAX_BLOCK_SIZE * 1) - /* Maximum event log record payload size = 1016 bytes or 254 words. */ #define EVENT_LOG_MAX_RECORD_PAYLOAD_SIZE 254 +/* A format number entry in event header is shifted left by 2. + * To get the lower bits of actual format number used, shift the format number field in the + * event log header right by 2. + * When extended headers are not present, the actual format number is 14 bits long. + * Actual format number is used to index into the string table as mentioned in logstrs.bin + */ +#define EVENT_LOG_ACTUAL_FMT_NUM_LS_SHIFT (2u) +/* When extended headers are present, the actual format number is 18 bits long. + * The extended format number represents top 4 bits of the actual format number + * Actual format number = (hdr->fmt_num >> EVENT_LOG_ACTUAL_FMT_NUM_LS_SHIFT) | + * ((ext_hdr->extended_fmt_num & EVENT_LOG_EXT_HDR_FMT_NUM_MASK) << + * EVENT_LOG_ACTUAL_FMT_NUM_MS_SHIFT) + */ +#define EVENT_LOG_ACTUAL_FMT_NUM_MS_SHIFT (14u) +/* Only 4 bits of extended format number are valid */ +#define EVENT_LOG_EXT_HDR_FMT_NUM_MASK (0xFu) + +/* Extended and binary data indication bits in the format number field in event log header */ #define EVENT_LOG_EXT_HDR_IND (0x01) #define EVENT_LOG_EXT_HDR_BIN_DATA_IND (0x01 << 1) + +/* Actual format number for binary records with regular header */ +#define EVENT_LOG_ACTUAL_REG_BIN_FMT_NUM (0x3FFFu) +/* Actual format number for binary records with extended header */ +#define EVENT_LOG_ACTUAL_EXT_BIN_FMT_NUM (0x3FFEu) + /* Format number to send binary data with extended event log header */ -#define EVENT_LOG_EXT_HDR_BIN_FMT_NUM (0x3FFE << 2) +#define EVENT_LOG_EXT_HDR_BIN_FMT_NUM (EVENT_LOG_ACTUAL_EXT_BIN_FMT_NUM << 2) + +/* Format number to send binary data with regular event log header */ +#define EVENT_LOG_REG_HDR_BIN_FMT_NUM (EVENT_LOG_ACTUAL_REG_BIN_FMT_NUM << 2) #define EVENT_LOGSET_ID_MASK 0x3F /* For event_log_get iovar, set values from 240 to 255 mean special commands for a group of sets */ @@ -125,37 +142,46 @@ typedef struct event_log_block { /* Start of packet sent for log tracing */ uint16 pktlen; /* Size of rest of block */ uint16 count; /* Logtrace counter */ - uint32 extra_hdr_info; /* LSB: 6 bits set id. MSB 24 bits reserved */ + uint32 extra_hdr_info; /* LSB: 6 bits set id. 18 bits rsvd, 8 bits block flags */ uint32 event_logs; /* Pointer to BEGINNING of event logs */ /* Event logs go here. Do not put extra fields below. */ } event_log_block_t; +/* Block specific data */ +#define EVENT_LOG_PRESERVE_BLOCK (1u) +#define EVENT_LOG_BLOCK_FLAG_MASK 0xFFu /* MSB 8 bits of extra_hdr_info for block flags */ +#define EVENT_LOG_BLOCK_FLAG_SHIFT (24u) +#define EVENT_LOG_SETID_MASK (0x3Fu) /* set id: LSB 6 bits of extra_hdr_info */ +#define EVENT_LOG_SETID_EXT_RSVD (0xC0u) /* 2 bits after setid_mask rsvd for extension */ + /* Relative offset of extra_hdr_info field frpm pktlen field in log block */ #define EVENT_LOG_BUF_EXTRA_HDR_INFO_REL_PKTLEN_OFFSET \ (OFFSETOF(event_log_block_t, extra_hdr_info) - OFFSETOF(event_log_block_t, pktlen)) -#define EVENT_LOG_SETID_MASK (0x3Fu) - #define EVENT_LOG_BLOCK_HDRLEN (sizeof(((event_log_block_t *) 0)->pktlen) \ + sizeof(((event_log_block_t *) 0)->count) \ + sizeof(((event_log_block_t *) 0)->extra_hdr_info)) #define EVENT_LOG_BLOCK_LEN (EVENT_LOG_BLOCK_HDRLEN + sizeof(event_log_hdr_t)) -#define EVENT_LOG_PRESERVE_BLOCK (1 << 0) -#define EVENT_LOG_BLOCK_FLAG_MASK 0xff000000u -#define EVENT_LOG_BLOCK_FLAG_SHIFT 24u +#define EVENT_LOG_BLOCK_GET_PREV_BLOCK(block) ((block)->prev_block) -#define EVENT_LOG_BLOCK_GET_PREV_BLOCK(block) ((_EL_BLOCK_PTR)(((uint32)((block)->prev_block)) & \ - ~EVENT_LOG_BLOCK_FLAG_MASK)) -#define EVENT_LOG_BLOCK_SET_PREV_BLOCK(block, prev) ((block)->prev_block = \ - ((_EL_BLOCK_PTR)((((uint32)(block)->prev_block) & EVENT_LOG_BLOCK_FLAG_MASK) | \ - (((uint32)(prev)) & ~EVENT_LOG_BLOCK_FLAG_MASK)))) -#define EVENT_LOG_BLOCK_GET_FLAG(block) ((((uint32)(block)->prev_block) & \ - EVENT_LOG_BLOCK_FLAG_MASK) >> EVENT_LOG_BLOCK_FLAG_SHIFT) -#define EVENT_LOG_BLOCK_SET_FLAG(block, flag) ((block)->prev_block = \ - (_EL_BLOCK_PTR)(((uint32)EVENT_LOG_BLOCK_GET_PREV_BLOCK(block)) | flag)) -#define EVENT_LOG_BLOCK_OR_FLAG(block, flag) EVENT_LOG_BLOCK_SET_FLAG(block, \ - (EVENT_LOG_BLOCK_GET_FLAG(block) | flag) << EVENT_LOG_BLOCK_FLAG_SHIFT) +#define EVENT_LOG_BLOCK_SET_PREV_BLOCK(block, prev) ((block)->prev_block = (prev)) + +#define EVENT_LOG_BLOCK_GET_FLAG(block) \ + (((uint32)(block)->extra_hdr_info) >> EVENT_LOG_BLOCK_FLAG_SHIFT) + +#define EVENT_LOG_BLOCK_SET_FLAG(block, flag) \ + ((block)->extra_hdr_info |= (((flag) & EVENT_LOG_BLOCK_FLAG_MASK) << \ + EVENT_LOG_BLOCK_FLAG_SHIFT)) + +#define EVENT_LOG_BLOCK_OR_FLAG(block, flag) \ + EVENT_LOG_BLOCK_SET_FLAG(block, (EVENT_LOG_BLOCK_GET_FLAG(block) | (flag))) + +#define EVENT_LOG_BLOCK_GET_SETNUM(block) \ + (((uint32)(block)->extra_hdr_info) & EVENT_LOG_SETID_MASK) + +#define EVENT_LOG_BLOCK_SET_SETNUM(block, setnum) \ + ((block)->extra_hdr_info |= (((uint32)(setnum)) & EVENT_LOG_SETID_MASK)) typedef enum { SET_DESTINATION_INVALID = -1, @@ -169,6 +195,7 @@ typedef enum { SET_DESTINATION_FLUSH_ON_WATERMARK = 3, /* Buffers are sent to host when the watermark is * reached, defined by the feature /chip */ + SET_DESTINATION_LOCAL = 4, /* Same as none but must stay in dongle at all times */ SET_DESTINATION_MAX } event_log_set_destination_t; @@ -185,32 +212,37 @@ typedef enum { * associated events (i.e, "fast" and "slow" events). */ typedef struct event_log_set { - _EL_BLOCK_PTR first_block; /* Pointer to first event_log block */ - _EL_BLOCK_PTR last_block; /* Pointer to last event_log block */ + _EL_BLOCK_PTR first_block; /* Pointer to first event_log block */ + _EL_BLOCK_PTR last_block; /* Pointer to last event_log block */ _EL_BLOCK_PTR logtrace_block; /* next block traced */ - _EL_BLOCK_PTR cur_block; /* Pointer to current event_log block */ - _EL_TYPE_PTR cur_ptr; /* Current event_log pointer */ + _EL_BLOCK_PTR cur_block; /* Pointer to current event_log block */ + _EL_TYPE_PTR cur_ptr; /* Current event_log pointer */ uint32 blockcount; /* Number of blocks */ uint16 logtrace_count; /* Last count for logtrace */ uint16 blockfill_count; /* Fill count for logtrace */ - uint32 timestamp; /* Last timestamp event */ + bool is_shdw_set; /* true if log set is a shadow set */ + uint8 pad[3]; /* explicit padding */ uint32 cyclecount; /* Cycles at last timestamp event */ event_log_set_destination_t destination; uint16 size; /* same size for all buffers in one set */ uint16 flags; uint16 num_preserve_blocks; event_log_set_sub_destination_t sub_destination; - uint16 water_mark; /* not used yet: threshold to flush host in percent */ - uint32 period; /* period to flush host in ms */ - uint32 last_rpt_ts; /* last time to flush in ms */ + uint16 water_mark; /* not used yet: threshold to flush host in percent */ + uint32 period; /* period to flush host in ms */ + uint32 last_rpt_ts; /* last time to flush in ms */ + uint64 ets_write_ptm_time; /* Raw PTM count in ns on PTM enabled devices */ + uint64 timestamp; /* Last timestamp event in ns */ } event_log_set_t; /* Definition of flags in set */ -#define EVENT_LOG_SET_SHRINK_ACTIVE (1 << 0) -#define EVENT_LOG_SET_CONFIG_PARTIAL_BLK_SEND (0x1 << 1) -#define EVENT_LOG_SET_CHECK_LOG_RATE (1 << 2) -#define EVENT_LOG_SET_PERIODIC (1 << 3) -#define EVENT_LOG_SET_D3PRSV (1 << 4) +#define EVENT_LOG_SET_SHRINK_ACTIVE BCM_BIT(0) +#define EVENT_LOG_SET_CONFIG_PARTIAL_BLK_SEND BCM_BIT(1) +#define EVENT_LOG_SET_CHECK_LOG_RATE BCM_BIT(2) +#define EVENT_LOG_SET_PERIODIC BCM_BIT(3) +#define EVENT_LOG_SET_D3PRSV BCM_BIT(4) +#define EVENT_LOG_SET_SHADOW BCM_BIT(5) +#define EVENT_LOG_SET_PARTIAL_SENT BCM_BIT(6) /* Top data structure for access to everything else */ typedef struct event_log_top { @@ -229,6 +261,8 @@ typedef struct event_log_top { bool cpu_freq_changed; /* Set to TRUE when CPU freq changed */ bool hostmem_access_enabled; /* Is host memory access enabled for log delivery */ bool event_trace_enabled; /* WLC_E_TRACE enabled/disabled */ + uint64 t0_time; /* Time at system startup. Stored for debug */ + uint64 cur_log_write_ptm_time; /* current raw PTM time in ns at log write time */ } event_log_top_t; /* structure of the trailing 3 words in logstrs.bin */ @@ -281,9 +315,9 @@ extern bool d3_preserve_enab; #if defined(ROM_ENAB_RUNTIME_CHECK) #define D3_PRESERVE_ENAB() (d3_preserve_enab) #elif defined(EVENTLOG_D3_PRESERVE_DISABLED) - #define D3_PRESERVE_ENAB() (0) + #define D3_PRESERVE_ENAB() (FALSE) #else - #define D3_PRESERVE_ENAB() (1) + #define D3_PRESERVE_ENAB() (TRUE) #endif #if defined(EVENTLOG_PRSV_PERIODIC) @@ -291,9 +325,9 @@ extern bool prsv_periodic_enab; #if defined(ROM_ENAB_RUNTIME_CHECK) #define PRSV_PRD_ENAB() (prsv_periodic_enab) #elif defined(EVENTLOG_PRSV_PERIODIC_DISABLED) - #define PRSV_PRD_ENAB() (0) + #define PRSV_PRD_ENAB() (FALSE) #else - #define PRSV_PRD_ENAB() (1) + #define PRSV_PRD_ENAB() (TRUE) #endif #endif /* EVENTLOG_PRSV_PERIODIC */ @@ -327,7 +361,7 @@ extern bool prsv_periodic_enab; * */ -#if !defined(EVENT_LOG_DUMPER) && !defined(DHD_EFI) +#if !defined(EVENT_LOG_DUMPER) #ifndef EVENT_LOG_COMPILE @@ -353,6 +387,15 @@ extern bool prsv_periodic_enab; #define EVENT_LOG_FORCE_FLUSH_ALL() #define EVENT_LOG_FORCE_FLUSH_PRSRV_LOG_ALL() +#define event_log_tag_start(tag, set_num, flags) +#define event_log_tag_stop(tag) + +#define event_log_num_blocks_get(set, num_blocks) BCME_OK +#define event_log_block_get(set, buf, len) BCME_OK + +#define event_log_enable_hostmem_access(hostmem_access_enabled) +#define event_log_enable_event_trace(event_trace_enabled) + #else /* EVENT_LOG_COMPILE */ /* The first few _EVENT_LOGX() macros are special because they can be done more @@ -373,6 +416,21 @@ extern bool prsv_periodic_enab; #define _EVENT_LOG4(tag, fmt_num, fmt, t1, t2, t3, t4) \ event_log4(tag, fmt_num, t1, t2, t3, t4) +#ifdef EVENT_LOG_FIXED_ARGS_ONLY +/* Only 4 or less argumenents are supported */ +#define _EVENT_LOG_VA_ARGS_ERR() STATIC_ASSERT(0) +#define _EVENT_LOG5(tag, fmt_num, fmt, ...) _EVENT_LOG_VA_ARGS_ERR() +#define _EVENT_LOG6(tag, fmt_num, fmt, ...) _EVENT_LOG_VA_ARGS_ERR() +#define _EVENT_LOG7(tag, fmt_num, fmt, ...) _EVENT_LOG_VA_ARGS_ERR() +#define _EVENT_LOG8(tag, fmt_num, fmt, ...) _EVENT_LOG_VA_ARGS_ERR() +#define _EVENT_LOG9(tag, fmt_num, fmt, ...) _EVENT_LOG_VA_ARGS_ERR() +#define _EVENT_LOGA(tag, fmt_num, fmt, ...) _EVENT_LOG_VA_ARGS_ERR() +#define _EVENT_LOGB(tag, fmt_num, fmt, ...) _EVENT_LOG_VA_ARGS_ERR() +#define _EVENT_LOGC(tag, fmt_num, fmt, ...) _EVENT_LOG_VA_ARGS_ERR() +#define _EVENT_LOGD(tag, fmt_num, fmt, ...) _EVENT_LOG_VA_ARGS_ERR() +#define _EVENT_LOGE(tag, fmt_num, fmt, ...) _EVENT_LOG_VA_ARGS_ERR() +#define _EVENT_LOGF(tag, fmt_num, fmt, ...) _EVENT_LOG_VA_ARGS_ERR() +#else /* The rest call the generic routine that takes a count */ #define _EVENT_LOG5(tag, fmt_num, fmt, ...) event_logn(5, tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG6(tag, fmt_num, fmt, ...) event_logn(6, tag, fmt_num, __VA_ARGS__) @@ -385,6 +443,7 @@ extern bool prsv_periodic_enab; #define _EVENT_LOGD(tag, fmt_num, fmt, ...) event_logn(13, tag, fmt_num, __VA_ARGS__) #define _EVENT_LOGE(tag, fmt_num, fmt, ...) event_logn(14, tag, fmt_num, __VA_ARGS__) #define _EVENT_LOGF(tag, fmt_num, fmt, ...) event_logn(15, tag, fmt_num, __VA_ARGS__) +#endif /* EVENT_LOG_FIXED_ARGS_ONLY */ /* Casting low level macros */ #define _EVENT_LOG_CAST0(tag, fmt_num, fmt) \ @@ -555,10 +614,36 @@ extern bool prsv_periodic_enab; extern uint8 *event_log_tag_sets; -extern int event_log_init(osl_t *osh); -extern int event_log_set_init(osl_t *osh, int set_num, int size); -extern int event_log_set_expand(osl_t *osh, int set_num, int size); -extern int event_log_set_shrink(osl_t *osh, int set_num, int size); +/* Initialize event log top and tag_sets context on given buffers. */ +int event_log_init_context(event_log_top_t *top, uint8 *tag_sets, uint16 tag_sets_len, + uint8 *tag_sets_ext, uint16 tag_sets_ext_len); +/* Initialize event log set context on a given buffer */ +int event_log_set_init_context(event_log_set_t *ts, int size, int set_num); +/* Add a newly allocated block to a specific set */ +void event_log_set_add_block(event_log_set_t *ts, event_log_block_t *tb); +/* Rest a set after adding new blocks */ +void event_log_set_reset(event_log_set_t *ts); +int event_log_set_reset_by_num(int set_num); +int event_log_init(osl_t *osh); +void event_log_timestamp_init(osl_t *osh); +int event_log_set_init(osl_t *osh, int set_num, int size); +int event_log_set_expand(osl_t *osh, int set_num, int size); +int event_log_set_expand_align(osl_t *osh, int set_num, int size, uint align_bits); +int event_log_set_shrink(osl_t *osh, int set_num, int size); + +/** + * @brief Event log host access state change notification callback function type + * @param[in] ctx Context pointer provided when registering the callback + * @param[in] start New state, TRUE if access is allowed otherwise FALSE + */ +typedef void (*event_log_state_change_cb_t)(void* ctx, bool start); +/* Register host access state change notification callback */ +void event_log_state_change_register_cb(event_log_state_change_cb_t fn, void *ctx); + +#ifdef BOOTMEM_ALLOCATOR +int event_log_set_init_bootmem(osl_t *osh, int set_num, uint bootmem_id); +void event_log_set_deinit_bootmem(osl_t *osh, int set_num, uint bootmem_id); +#endif /* BOOTMEM_ALLOCATOR */ extern int event_log_tag_start(int tag, int set_num, int flags); extern int event_log_tag_set_retrieve(int tag); @@ -570,7 +655,7 @@ void event_log_set_logtrace_trigger_fn(event_log_logtrace_trigger_fn_t fn, void event_log_top_t *event_log_get_top(void); -extern int event_log_get(int set_num, int buflen, void *buf); +extern int event_log_get(int set_num, uint buflen, void *buf); extern uint8 *event_log_next_logtrace(int set_num); extern uint32 event_log_logtrace_max_buf_count(int set_num); @@ -583,12 +668,14 @@ extern void event_log2(int tag, int fmtNum, uint32 t1, uint32 t2); extern void event_log3(int tag, int fmtNum, uint32 t1, uint32 t2, uint32 t3); extern void event_log4(int tag, int fmtNum, uint32 t1, uint32 t2, uint32 t3, uint32 t4); extern void event_logn(int num_args, int tag, int fmtNum, ...); -#ifdef ROM_COMPAT_MSCH_PROFILER -/* For compatibility with ROM, for old msch event log function to pass parameters in stack */ -extern void event_logv(int num_args, int tag, int fmtNum, va_list ap); -#endif /* ROM_COMPAT_MSCH_PROFILER */ -extern void event_log_time_sync(uint32 ms); +/* Use PTM based timestamping of event log records if PTM is available. */ +#if defined(GTIMER_PTM) && !defined(GTIMER_PTM_DISABLED) +#define event_log_time_sync(ns) +#else +extern void event_log_time_sync(uint64 ns); +#endif /* GTIMER_PTM && !GTIMER_PTM_DISABLED */ + extern bool event_log_time_sync_required(void); extern void event_log_cpu_freq_changed(void); extern void event_log_buffer(int tag, const uint8 *buf, int size); @@ -618,8 +705,10 @@ extern void event_log_d3_preserve_active_set(osl_t* osh, int set, bool active); extern void event_log_d3_prsv_set_all(osl_t *osh, bool active); #endif /* EVENTLOG_D3_PRESERVE */ -#ifdef EVENTLOG_PRSV_PERIODIC +#if defined(EVENTLOG_PRSV_PERIODIC) || defined(EVENTLOG_D3_PRESERVE) #define EVENT_LOG_SET_SIZE_INVALID 0xFFFFFFFFu +#endif /* EVENTLOG_PRSV_PERIODIC || EVENTLOG_D3_PRESERVE */ +#ifdef EVENTLOG_PRSV_PERIODIC #define EVENT_LOG_DEFAULT_PERIOD 3000u extern void event_log_prsv_periodic_wd_trigger(osl_t *osh); #endif /* EVENTLOG_PRSV_PERIODIC */ @@ -641,6 +730,12 @@ extern int event_log_num_blocks_get(int set, uint32 *num_blocks); extern int event_log_block_get(int set, uint32 **buf, uint16 *len); extern uint32 event_log_get_maxsets(void); +/* Get cur_block of a specific set */ +event_log_block_t * event_log_block_get_cur(int set); + +/* API to notify event log framework that cur_block of the specific set is filled */ +void event_log_shadow_set_post(int set); + /* For all other non-logtrace consumers */ extern int event_log_set_is_valid(int set); @@ -657,7 +752,7 @@ extern int event_log_enable_hostmem_access(bool hostmem_access_enabled); extern int event_log_enable_event_trace(bool event_trace_enabled); #endif /* EVENT_LOG_COMPILE */ -#endif /* !EVENT_LOG_DUMPER && !DHD_EFI */ +#endif #endif /* BCMDRIVER */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_payload.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_payload.h old mode 100755 new mode 100644 index 4485fcc8f44b..9c17e079841f --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_payload.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_payload.h @@ -4,7 +4,7 @@ * This file describes the payloads of event log entries that are data buffers * rather than formatted string entries. The contents are generally XTLVs. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -28,9 +28,12 @@ #define _EVENT_LOG_PAYLOAD_H_ #include +#include #include #include #include +#include +#include /** * A (legacy) timestamp message @@ -61,6 +64,16 @@ typedef struct enhanced_ts_message_v1 { uint32 cpu_freq; } ets_msg_v1_t; +/** + * Enhanced timestamp message, version 2 + */ +#define ENHANCED_TS_MSG_VERSION_2 (2u) +typedef struct enhanced_ts_message_v2 { + uint64 sysuptime_ns; /* sysuptime in ns */ + uint64 ets_write_ptm_time; /* PTM time at ETS message */ + uint64 host_time_offset; /* Host time offset in ns from PTM time */ +} ets_msg_v2_t; + #define EVENT_LOG_XTLV_ID_STR 0 /**< XTLV ID for a string */ #define EVENT_LOG_XTLV_ID_TXQ_SUM 1 /**< XTLV ID for txq_summary_t */ #define EVENT_LOG_XTLV_ID_SCBDATA_SUM 2 /**< XTLV ID for cb_subq_summary_t */ @@ -75,9 +88,9 @@ typedef struct enhanced_ts_message_v1 { * String is not null terminated, length is the XTLV len. */ typedef struct xtlv_string { - uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_STR */ - uint16 len; /* XTLV Len (String length) */ - char str[1]; /* var len array characters */ + uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_STR */ + uint16 len; /* XTLV Len (String length) */ + char str[BCM_FLEX_ARRAY]; /* var len array characters */ } xtlv_string_t; #define XTLV_STRING_FULL_LEN(str_len) (BCM_XTLV_HDR_SIZE + (str_len) * sizeof(char)) @@ -91,27 +104,27 @@ typedef struct xtlv_string { * The excursion queue will have no bsscfgs associated and is the first queue dumped. */ typedef struct txq_summary { - uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_TXQ_SUM */ - uint16 len; /* XTLV Len */ - uint32 bsscfg_map; /* bitmap of bsscfg indexes associated with this queue */ - uint32 stopped; /* flow control bitmap */ - uint8 prec_count; /* count of precedences/fifos and len of following array */ + uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_TXQ_SUM */ + uint16 len; /* XTLV Len */ + uint32 bsscfg_map; /* bitmap of bsscfg indexes associated with this queue */ + uint32 stopped; /* flow control bitmap */ + uint8 prec_count; /* count of precedences/fifos and len of following array */ uint8 pad; - uint16 plen[1]; /* var len array of lengths of each prec/fifo in the queue */ + uint16 plen[BCM_FLEX_ARRAY]; /* array of lengths of each prec/fifo in the queue */ } txq_summary_t; #define TXQ_SUMMARY_LEN (OFFSETOF(txq_summary_t, plen)) #define TXQ_SUMMARY_FULL_LEN(num_q) (TXQ_SUMMARY_LEN + (num_q) * sizeof(uint16)) typedef struct txq_summary_v2 { - uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_TXQ_SUM_V2 */ - uint16 len; /* XTLV Len */ - uint32 bsscfg_map; /* bitmap of bsscfg indexes associated with this queue */ - uint32 stopped; /* flow control bitmap */ - uint32 hw_stopped; /* flow control bitmap */ - uint8 prec_count; /* count of precedences/fifos and len of following array */ + uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_TXQ_SUM_V2 */ + uint16 len; /* XTLV Len */ + uint32 bsscfg_map; /* bitmap of bsscfg indexes associated with this queue */ + uint32 stopped; /* flow control bitmap */ + uint32 hw_stopped; /* flow control bitmap */ + uint8 prec_count; /* count of precedences/fifos and len of following array */ uint8 pad; - uint16 plen[1]; /* var len array of lengths of each prec/fifo in the queue */ + uint16 plen[BCM_FLEX_ARRAY]; /* array of lengths of each prec/fifo in the queue */ } txq_summary_v2_t; #define TXQ_SUMMARY_V2_LEN (OFFSETOF(txq_summary_v2_t, plen)) @@ -123,14 +136,14 @@ typedef struct txq_summary_v2 { * a cubby ID and sub-ID to differentiate SCB cubby types and possible sub-queues. */ typedef struct scb_subq_summary { - uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_SCBDATA_SUM */ - uint16 len; /* XTLV Len */ - uint32 flags; /* cubby specficic flags */ - uint8 cubby_id; /* ID registered for cubby */ - uint8 sub_id; /* sub ID if a cubby has more than one queue */ - uint8 prec_count; /* count of precedences/fifos and len of following array */ + uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_SCBDATA_SUM */ + uint16 len; /* XTLV Len */ + uint32 flags; /* cubby specficic flags */ + uint8 cubby_id; /* ID registered for cubby */ + uint8 sub_id; /* sub ID if a cubby has more than one queue */ + uint8 prec_count; /* count of precedences/fifos and len of following array */ uint8 pad; - uint16 plen[1]; /* var len array of lengths of each prec/fifo in the queue */ + uint16 plen[BCM_FLEX_ARRAY]; /* array of lengths of each prec/fifo in the queue */ } scb_subq_summary_t; #define SCB_SUBQ_SUMMARY_LEN (OFFSETOF(scb_subq_summary_t, plen)) @@ -176,14 +189,14 @@ typedef struct scb_ampdu_tx_summary { /** XTLV stuct to summarize a BSSCFG's packet queue */ typedef struct bsscfg_q_summary { - uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_BSSCFGDATA_SUM */ - uint16 len; /* XTLV Len */ - struct ether_addr BSSID; /* BSSID */ - uint8 bsscfg_idx; /* bsscfg index */ - uint8 type; /* bsscfg type enumeration: BSSCFG_TYPE_XXX */ - uint8 subtype; /* bsscfg subtype enumeration: BSSCFG_SUBTYPE_XXX */ - uint8 prec_count; /* count of precedences/fifos and len of following array */ - uint16 plen[1]; /* var len array of lengths of each prec/fifo in the queue */ + uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_BSSCFGDATA_SUM */ + uint16 len; /* XTLV Len */ + struct ether_addr BSSID; /* BSSID */ + uint8 bsscfg_idx; /* bsscfg index */ + uint8 type; /* bsscfg type enumeration: BSSCFG_TYPE_XXX */ + uint8 subtype; /* bsscfg subtype enumeration: BSSCFG_SUBTYPE_XXX */ + uint8 prec_count; /* count of precedences/fifos and len of following array */ + uint16 plen[BCM_FLEX_ARRAY]; /* array of lengths of each prec/fifo in the queue */ } bsscfg_q_summary_t; #define BSSCFG_Q_SUMMARY_LEN (OFFSETOF(bsscfg_q_summary_t, plen)) @@ -196,11 +209,11 @@ typedef struct bsscfg_q_summary { * Array is uint32 words */ typedef struct xtlv_uc_txs { - uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_UCTXSTATUS */ - uint16 len; /* XTLV Len */ - uint8 entry_size; /* num uint32 words per entry */ - uint8 pad[3]; /* reserved, zero */ - uint32 w[1]; /* var len array of words */ + uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_UCTXSTATUS */ + uint16 len; /* XTLV Len */ + uint8 entry_size; /* num uint32 words per entry */ + uint8 pad[3]; /* reserved, zero */ + uint32 w[BCM_FLEX_ARRAY]; /* var len array of words */ } xtlv_uc_txs_t; #define XTLV_UCTXSTATUS_LEN (OFFSETOF(xtlv_uc_txs_t, w)) @@ -244,6 +257,7 @@ typedef struct xtlv_uc_txs { #define SCAN_SUM_WLC_CORE1 0x8 #define HOME_CHAN 0x10 #define SCAN_SUM_SCAN_CORE 0x20 +#define FILS_SCAN_SCN_SUM 0x40 /* The 6G channels was dwelled only for FILS dur 25ms */ typedef struct wl_scan_ssid_info { @@ -254,11 +268,11 @@ typedef struct wl_scan_ssid_info typedef struct wl_scan_channel_info { uint16 chanspec; /* chanspec scanned */ uint16 reserv; - uint32 start_time; /* Scan start time in + uint32 start_time; /* Scan start time in * milliseconds for the chanspec * or home_dwell time start */ - uint32 end_time; /* Scan end time in + uint32 end_time; /* Scan end time in * milliseconds for the chanspec * or home_dwell time end */ @@ -269,15 +283,56 @@ typedef struct wl_scan_channel_info { */ } wl_scan_channel_info_t; +typedef struct wl_scan_channel_info_v2 { + uint16 chanspec; /* chanspec scanned */ + uint16 reserv; + uint32 start_time; /* Scan start time in + * milliseconds for the chanspec + * or home_dwell time start + */ + uint32 end_time; /* Scan end time in + * milliseconds for the chanspec + * or home_dwell time end + */ + union { + uint32 active_scan_conv_time; /* passsive/fils scan can be converted to active */ + uint32 chan_6g_act_scn_strt_time; /* 6G active scan start, valid for 6G chan only */ + }; + uint16 probe_count; /* No of probes sent out. For future use + */ + uint16 scn_res_count; /* Count of scan_results found per + * channel. For future use + */ +} wl_scan_channel_info_v2_t; + typedef struct wl_scan_summary_info { - uint32 total_chan_num; /* Total number of channels scanned */ - uint32 scan_start_time; /* Scan start time in milliseconds */ - uint32 scan_end_time; /* Scan end time in milliseconds */ - wl_scan_ssid_info_t ssid[1]; /* SSID being scanned in current - * channel. For future use - */ + uint32 total_chan_num; /* Total number of channels scanned */ + uint32 scan_start_time; /* Scan start time in milliseconds */ + uint32 scan_end_time; /* Scan end time in milliseconds */ + wl_scan_ssid_info_t ssid[BCM_FLEX_ARRAY]; /* SSID being scanned in current + * channel. For future use + */ } wl_scan_summary_info_t; +typedef struct wl_scan_summary_info_v2 { + uint32 scan_start_time; /* Scan start time in milliseconds */ + uint32 scan_end_time; /* Scan end time in milliseconds */ + uint32 scan_dur_2g; /* 2g Scan duartion time in milliseconds */ + uint32 scan_dur_5g; /* 5g Scan duartion time in milliseconds */ + uint32 scan_dur_6g; /* 6g Scan duartion time in milliseconds */ + uint8 total_chan_num; /* Total number of channels scanned */ + /* scan_channel_ctx_t chan_cnt; */ + uint8 channel_cnt_2g; /* Number of 2g channels to be scanned */ + uint8 channel_cnt_5g; /* Number of 5g channels to be scanned */ + uint8 channel_cnt_6g; /* Number of 6g channels to be scanned */ + uint8 channel_cnt_sc_2g; /* Number of channels to be scanned on Scan core */ + uint8 channel_cnt_sc_5g; /* Number of channels to be scanned on Scan core */ + uint8 channel_cnt_sc_6g; /* Number of channels to be scanned on Scan core */ + uint8 active_channel_cnt; /* Number of active channels to be scanned */ + uint8 passive_channel_cnt; /* Number of passive channels to be scanned */ + uint8 pad[3]; /* Pad to keep it 32 bit aligned */ +} wl_scan_summary_info_v2_t; + struct wl_scan_summary { uint8 version; /* Version */ uint8 reserved; @@ -387,6 +442,120 @@ struct wl_scan_summary_v2 { */ } u; }; + +#define SCAN_SUMMARY_VERSION_3 3u +struct wl_scan_summary_v3 { + uint8 version; /* Version */ + uint8 reserved; + uint16 len; /* Length of the data buffer including SSID + * list. + */ + uint16 sync_id; /* Scan Sync ID */ + uint16 scan_flags; /* flags [0] or SCAN_SUM_CHAN_INFO = */ + /* channel_info, if not set */ + /* it is scan_summary_info */ + /* when channel_info is used, */ + /* the following flag bits are overridden: */ + /* flags[1] or ACTIVE_SCAN_SCN_SUM = active channel if set */ + /* passive if not set */ + /* flags[2] or WLC_CORE0 = if set, represents wlc_core0 */ + /* flags[3] or WLC_CORE1 = if set, represents wlc_core1 */ + /* flags[4] or HOME_CHAN = if set, represents home-channel */ + /* flags[5] or SCAN_SUM_SCAN_CORE = if set, + * represents chan_info from scan core. + */ + /* flags[6] or FILS_SCAN_SCN_SUM = if set, + * 6G channels was dwelled only for FILS duration. + */ + /* flags[12] SCAN_SUM_CHAN_RESHED indicate scan rescheduled */ + /* flags[7:11, 13:15] = reserved */ + /* when scan_summary_info is used, */ + /* the following flag bits are used: */ + /* flags[1] or BAND5G_SIB_ENAB = */ + /* allowSIBParallelPassiveScan on 5G band */ + /* flags[2] or BAND2G_SIB_ENAB = */ + /* allowSIBParallelPassiveScan on 2G band */ + /* flags[3] or PARALLEL_SCAN = Parallel scan enabled or not */ + /* flags[4] or SCAN_ABORT = SCAN_ABORTED scenario */ + /* flags[5] = reserved */ + /* flags[6:8] is used as count value to identify SCAN CLIENT + * WL_SSUM_CLIENT_ASSOCSCAN 0x0u, WL_SSUM_CLIENT_ROAMSCAN 0x1u, + * WL_SSUM_CLIENT_FWSCAN 0x2u, WL_SSUM_CLIENT_HOSTSCAN 0x3u + */ + /* flags[9:11] is used as count value to identify SCAN MODE + * WL_SCAN_MODE_HIGH_ACC 0u, WL_SCAN_MODE_LOW_SPAN 1u, + * WL_SCAN_MODE_LOW_POWER 2u + */ + /* flags[12] SCAN_SUM_CHAN_RESHED indicate scan rescheduled */ + /* flags[13:15] = reserved */ + union { + wl_scan_channel_info_v2_t scan_chan_info; /* scan related information + * for each channel scanned + */ + wl_scan_summary_info_v2_t scan_sum_info; /* Cumulative scan related + * information. + */ + } u; +}; + +/* Raom target evaluation detail data type */ +typedef enum { + WL_ROAM_TRGT_EVAL_BASIC = 1u, + WL_ROAM_TRGT_EVAL_RSSI_SCORE = 2u, + WL_ROAM_TRGT_EVAL_LOAD_SCORE = 3u, + WL_ROAM_TRGT_EVAL_SUMMARY = 4u, + WL_ROAM_TRGT_EVAL_MAX +} wl_roam_trgt_eval_msg_type_t; + +struct wl_roam_target_cur_state { + uint32 type; /* = WL_ROAM_TRGT_EVAL_BASIC (1) */ + uint32 roam_reason; /* existing definition of roam reasons */ + uint32 roam_type; /* 0:ROAM_FULL 1:ROAM_PARTIAL 2:ROAM_SPLIT_PHASE */ + uint32 home_bssid_hi; /* 32-bit MSB MAC address */ + uint32 home_bssid_lo; /* 16-bit LSB MAC address */ + uint32 channel; /* chanspec_t */ + int32 rssi; /* raw value */ + int32 roam_prof_idx; /* Roam profile index */ + uint32 prof_flags; /* Info related to the current applicable roam profile */ + int32 prof_trigger; + uint32 prof_delta; + uint32 user_ov; /* User roam cache override mode */ +}; + +struct wl_roam_target_rssi_score { + uint32 type; /* = WL_ROAM_TRGT_EVAL_RSSI_SCORE (2) */ + uint32 bssid_hi; /* 32-bit MSB MAC address */ + uint32 bssid_lo; /* 16-bit LSB MAC address */ + uint32 channel; /* chanspec_t */ + int32 rssi; /* raw value */ + int32 rssi_boosted; + uint32 rssi_score; /* = 65536 + MIN(0, rssi_boosted) */ + uint32 load_aac; /* qbss load available admission capacity (when available) */ + uint32 chan_free; /* IEEE802.11 format with 255 = 100% (when available) */ +}; + +struct wl_roam_target_load_score { + uint32 type; /* = WL_ROAM_TRGT_EVAL_LOAD_SCORE (3) */ + uint32 bssid_hi; /* 32-bit MSB MAC address */ + uint32 bssid_lo; /* 16-bit LSB MAC address */ + uint32 channel; /* chanspec_t */ + int32 rssi; /* raw value */ + int32 rssi_boosted; + uint32 rate_family; /* two-letter for A/ B/ G/ N/AC/AX/ */ + uint32 rate; /* mapped rate (x500Kbps) */ + uint32 bw; /* 20, 40, 80, 160, or ... */ + uint32 nss; + uint32 chan_free; /* IEEE802.11 format with 255 = 100% */ + uint32 load_score; /* = rate * nss * bw * chan_free */ +}; + +struct wl_roam_target_summary { + uint32 type; /* = WL_ROAM_TRGT_EVAL_SUMMARY (4) */ + uint32 ref_score; /* score reference (minimum score to beat) */ + uint32 score_delta; /* score delta - additional marging */ + uint32 num_of_targets; /* number of qualifying target */ +}; + /* Channel switch log record structure * Host may map the following structure on channel switch event log record * received from dongle. Note that all payload entries in event log record are @@ -410,6 +579,23 @@ typedef struct wl_chansw_event_log_record_v2 { int32 phychanswtime; /* channel switch time */ } wl_chansw_event_log_record_v2_t; +/* Beacon Report structure + * Host may map the following structure to the RRM beacon report event log record + */ +#define WL_RRM_BCN_RPT_RECORD_V1 1u +typedef struct wl_rrm_bcn_rpt_record_v1 { + uint32 ver; /* structure version */ + uint32 index; /* Index of AP inclided in the report */ + uint32 num_aps; /* total number of APs reported */ + uint32 measure_mode; /* Beacon measurement mode */ + uint32 bssid_lo; /* BSSID[3:0] */ + uint32 bssid_hi; /* BSSID[5:4] */ + uint32 ssid_match; /* 0: not-match 1:match */ + uint32 chanspec; + int32 rssi; + int32 snr; +} wl_rrm_bcn_rpt_record_v1_t; + /* Sub-block type for EVENT_LOG_TAG_AMPDU_DUMP */ typedef enum { WL_AMPDU_STATS_TYPE_RXMCSx1 = 0, /* RX MCS rate (Nss = 1) */ @@ -460,8 +646,17 @@ typedef enum { WL_AMPDU_STATS_TYPE_RX_COUNTERS = 45, /* Additional AMPDU_RX module counters * per-slice */ - WL_AMPDU_STATS_MAX_CNTS = 64 + WL_AMPDU_STATS_TYPE_RXHEx1 = 46, /* RX HE rate (Nss = 1) */ + WL_AMPDU_STATS_TYPE_RXHEx2 = 47, + WL_AMPDU_STATS_TYPE_RXHEx3 = 48, + WL_AMPDU_STATS_TYPE_RXHEx4 = 49, + WL_AMPDU_STATS_TYPE_TXHEx1 = 50, /* TX HE rate (Nss = 1) */ + WL_AMPDU_STATS_TYPE_TXHEx2 = 51, + WL_AMPDU_STATS_TYPE_TXHEx3 = 52, + WL_AMPDU_STATS_TYPE_TXHEx4 = 53 } wl_ampdu_stat_enum_t; +#define WL_AMPDU_STATS_MAX_CNTS (64) /* Possible max number of counters in any sub-categary */ + typedef struct { uint16 type; /* AMPDU statistics sub-type */ uint16 len; /* Number of 32-bit counters */ @@ -489,7 +684,11 @@ typedef struct wlc_ampdu_rx_stats { /* responder side counters */ uint32 rxampdu; /**< ampdus recd */ uint32 rxmpdu; /**< mpdus recd in a ampdu */ - uint32 rxht; /**< mpdus recd at ht rate and not in a ampdu */ + /* Using union to have a smooth transition for renaming rxht ro rxsingle for all branches */ + union { + uint32 rxht; /**< obsolete - mpdus recd at ht rate and not in a ampdu */ + uint32 rxsingle; /**< mpdus recd not in a ampdu */ + }; uint32 rxlegacy; /**< mpdus recd at legacy rate */ uint32 rxampdu_sgi; /**< ampdus recd with sgi */ uint32 rxampdu_stbc; /**< ampdus recd with stbc */ @@ -509,6 +708,8 @@ typedef struct wlc_ampdu_rx_stats { uint32 rxunexp; /**< unexpected packets */ uint32 txdelba; /**< delba sent */ uint32 rxdelba; /**< delba recd */ + + uint32 rxretrynobapol; /**< retried mpdus rxed without a ba policy */ } wlc_ampdu_rx_stats_t; /* Sub-block type for WL_IFSTATS_XTLV_HE_TXMU_STATS */ @@ -622,7 +823,7 @@ typedef enum { typedef struct msch_collect_tlv { uint16 type; uint16 size; - char value[1]; + char value[BCM_FLEX_ARRAY]; } msch_collect_tlv_t; typedef struct msch_profiler_event_data { @@ -637,9 +838,9 @@ typedef struct msch_start_profiler_event_data { } msch_start_profiler_event_data_t; typedef struct msch_message_profiler_event_data { - uint32 time_lo; /* Request time */ + uint32 time_lo; /* Request time */ uint32 time_hi; - char message[1]; /* message */ + char message[BCM_FLEX_ARRAY]; /* message */ } msch_message_profiler_event_data_t; typedef struct msch_event_log_profiler_event_data { @@ -858,628 +1059,6 @@ typedef struct msch_register_params { uint16 chanspec_list[WL_MSCH_NUMCHANNELS]; } msch_register_params_t; -typedef struct { - uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS, - * Control Management (includes retransmissions) - */ - uint32 rxrsptmout; /**< number of response timeouts for transmitted frames - * expecting a response - */ - uint32 rxstrt; /**< number of received frames with a good PLCP */ - uint32 rxbadplcp; /**< number of parity check of the PLCP header failed */ - uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ - uint32 rxnodelim; /**< number of no valid delimiter detected by ampdu parser */ - uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ - uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ - uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ - uint32 rxanyerr; /**< Any RX error that is not counted by other counters. */ - uint32 rxbeaconmbss; /**< beacons received from member of BSS */ - uint32 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */ - uint32 rxdtocast; /**< number of received DATA frames (good FCS and no matching RA) */ - uint32 rxtoolate; /**< receive too late */ - uint32 goodfcs; /**< Good fcs counters */ - uint32 rxf0ovfl; /** < Rx FIFO0 overflow counters information */ - uint32 rxf1ovfl; /** < Rx FIFO1 overflow counters information */ -} phy_periodic_counters_v1_t; - -typedef struct { - - /* RX error related */ - uint32 rxrsptmout; /* number of response timeouts for transmitted frames - * expecting a response - */ - uint32 rxbadplcp; /* number of parity check of the PLCP header failed */ - uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ - uint32 rxnodelim; /* number of no valid delimiter detected by ampdu parser */ - uint32 bphy_badplcp; /* number of bad PLCP reception on BPHY rate */ - uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ - uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ - uint32 rxtoolate; /* receive too late */ - uint32 rxf0ovfl; /* Rx FIFO0 overflow counters information */ - uint32 rxf1ovfl; /* Rx FIFO1 overflow counters information */ - uint32 rxanyerr; /* Any RX error that is not counted by other counters. */ - uint32 rxdropped; /* Frame dropped */ - uint32 rxnobuf; /* Rx error due to no buffer */ - uint32 rxrunt; /* Runt frame counter */ - uint32 rxfrmtoolong; /* Number of received frame that are too long */ - uint32 rxdrop20s; - - /* RX related */ - uint32 rxstrt; /* number of received frames with a good PLCP */ - uint32 rxbeaconmbss; /* beacons received from member of BSS */ - uint32 rxdtucastmbss; /* number of received DATA frames with good FCS and matching RA */ - uint32 rxdtocast; /* number of received DATA frames (good FCS and no matching RA) */ - uint32 goodfcs; /* Good fcs counters */ - uint32 rxctl; /* Number of control frames */ - uint32 rxaction; /* Number of action frames */ - uint32 rxback; /* Number of block ack frames rcvd */ - uint32 rxctlucast; /* Number of received unicast ctl frames */ - uint32 rxframe; /* Number of received frames */ - - /* TX related */ - uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, - * Control Management (includes retransmissions) - */ - uint32 txmpdu; /* Numer of transmitted mpdus */ - uint32 txackbackctsfrm; /* Number of ACK + BACK + CTS */ - - /* TX error related */ - uint32 txrtsfail; /* RTS TX failure count */ - uint32 txphyerr; /* PHY TX error count */ - - uint16 nav_cntr_l; /* The state of the NAV */ - uint16 nav_cntr_h; -} phy_periodic_counters_v3_t; - -typedef struct phy_periodic_counters_v4 { - uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS, - * Control Management (includes retransmissions) - */ - uint32 rxrsptmout; /**< number of response timeouts for transmitted frames - * expecting a response - */ - uint32 rxstrt; /**< number of received frames with a good PLCP */ - uint32 rxbadplcp; /**< number of parity check of the PLCP header failed */ - uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ - uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ - uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ - uint32 rxbeaconmbss; /**< beacons received from member of BSS */ - uint32 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */ - uint32 rxf0ovfl; /** < Rx FIFO0 overflow counters information */ - uint32 rxf1ovfl; /** < Rx FIFO1 overflow counters information */ - uint32 rxdtocast; /**< number of received DATA frames (good FCS and no matching RA) */ - uint32 rxtoolate; /**< receive too late */ - uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ - uint32 rxdropped; - uint32 rxcrc; - uint32 rxnobuf; - uint32 rxrunt; - uint32 rxgiant; - uint32 rxctl; - uint32 rxaction; - uint32 rxdrop20s; - uint32 rxctsucast; - uint32 rxrtsucast; - uint32 txctsfrm; - uint32 rxackucast; - uint32 rxback; - uint32 txphyerr; - uint32 txrtsfrm; - uint32 txackfrm; - uint32 txback; - uint32 rxnodelim; - uint32 rxfrmtoolong; - uint32 rxctlucast; - uint32 txbcnfrm; - uint32 txdnlfrm; - uint32 txampdu; - uint32 txmpdu; - uint32 txinrtstxop; - uint32 prs_timeout; -} phy_periodic_counters_v4_t; - -typedef struct phycal_log_cmn { - uint16 chanspec; /* Current phy chanspec */ - uint8 last_cal_reason; /* Last Cal Reason */ - uint8 pad1; /* Padding byte to align with word */ - uint32 last_cal_time; /* Last cal time in sec */ -} phycal_log_cmn_t; - -typedef struct phycal_log_cmn_v2 { - uint16 chanspec; /* current phy chanspec */ - uint8 reason; /* cal reason */ - uint8 phase; /* cal phase */ - uint32 time; /* time at which cal happened in sec */ - uint16 temp; /* temperature at the time of cal */ - uint16 dur; /* duration of cal in usec */ - - /* Misc general purpose debug counters (will be used for future debugging) */ - uint16 debug_01; - uint16 debug_02; - uint16 debug_03; - uint16 debug_04; -} phycal_log_cmn_v2_t; - -typedef struct phycal_log_core { - uint16 ofdm_txa; /* OFDM Tx IQ Cal a coeff */ - uint16 ofdm_txb; /* OFDM Tx IQ Cal b coeff */ - uint16 ofdm_txd; /* contain di & dq */ - uint16 bphy_txa; /* BPHY Tx IQ Cal a coeff */ - uint16 bphy_txb; /* BPHY Tx IQ Cal b coeff */ - uint16 bphy_txd; /* contain di & dq */ - - uint16 rxa; /* Rx IQ Cal A coeffecient */ - uint16 rxb; /* Rx IQ Cal B coeffecient */ - int32 rxs; /* FDIQ Slope coeffecient */ - - uint8 baseidx; /* TPC Base index */ - uint8 adc_coeff_cap0_adcI; /* ADC CAP Cal Cap0 I */ - uint8 adc_coeff_cap1_adcI; /* ADC CAP Cal Cap1 I */ - uint8 adc_coeff_cap2_adcI; /* ADC CAP Cal Cap2 I */ - uint8 adc_coeff_cap0_adcQ; /* ADC CAP Cal Cap0 Q */ - uint8 adc_coeff_cap1_adcQ; /* ADC CAP Cal Cap1 Q */ - uint8 adc_coeff_cap2_adcQ; /* ADC CAP Cal Cap2 Q */ - uint8 pad; /* Padding byte to align with word */ -} phycal_log_core_t; - -typedef struct phycal_log_core_v3 { - uint16 ofdm_txa; /* OFDM Tx IQ Cal a coeff */ - uint16 ofdm_txb; /* OFDM Tx IQ Cal b coeff */ - uint16 ofdm_txd; /* contain di & dq */ - uint16 bphy_txa; /* BPHY Tx IQ Cal a coeff */ - uint16 bphy_txb; /* BPHY Tx IQ Cal b coeff */ - uint16 bphy_txd; /* contain di & dq */ - - uint16 rxa; /* Rx IQ Cal A coeffecient */ - uint16 rxb; /* Rx IQ Cal B coeffecient */ - int32 rxs; /* FDIQ Slope coeffecient */ - - uint8 baseidx; /* TPC Base index */ - uint8 adc_coeff_cap0_adcI; /* ADC CAP Cal Cap0 I */ - uint8 adc_coeff_cap1_adcI; /* ADC CAP Cal Cap1 I */ - uint8 adc_coeff_cap2_adcI; /* ADC CAP Cal Cap2 I */ - uint8 adc_coeff_cap0_adcQ; /* ADC CAP Cal Cap0 Q */ - uint8 adc_coeff_cap1_adcQ; /* ADC CAP Cal Cap1 Q */ - uint8 adc_coeff_cap2_adcQ; /* ADC CAP Cal Cap2 Q */ - uint8 pad; /* Padding byte to align with word */ - - /* Gain index based txiq ceffiecients for 2G(3 gain indices) */ - uint16 txiqlo_2g_a0; /* 2G TXIQ Cal a coeff for high TX gain */ - uint16 txiqlo_2g_b0; /* 2G TXIQ Cal b coeff for high TX gain */ - uint16 txiqlo_2g_a1; /* 2G TXIQ Cal a coeff for mid TX gain */ - uint16 txiqlo_2g_b1; /* 2G TXIQ Cal b coeff for mid TX gain */ - uint16 txiqlo_2g_a2; /* 2G TXIQ Cal a coeff for low TX gain */ - uint16 txiqlo_2g_b2; /* 2G TXIQ Cal b coeff for low TX gain */ - - uint16 rxa_vpoff; /* Rx IQ Cal A coeff Vp off */ - uint16 rxb_vpoff; /* Rx IQ Cal B coeff Vp off */ - uint16 rxa_ipoff; /* Rx IQ Cal A coeff Ip off */ - uint16 rxb_ipoff; /* Rx IQ Cal B coeff Ip off */ - int32 rxs_vpoff; /* FDIQ Slope coeff Vp off */ - int32 rxs_ipoff; /* FDIQ Slope coeff Ip off */ -} phycal_log_core_v3_t; - -#define PHYCAL_LOG_VER1 (1u) - -typedef struct phycal_log_v1 { - uint8 version; /* Logging structure version */ - uint8 numcores; /* Numbe of cores for which core specific data present */ - uint16 length; /* Length of the entire structure */ - phycal_log_cmn_t phycal_log_cmn; /* Logging common structure */ - /* This will be a variable length based on the numcores field defined above */ - phycal_log_core_t phycal_log_core[1]; -} phycal_log_v1_t; - -typedef struct phy_periodic_log_cmn { - uint16 chanspec; /* Current phy chanspec */ - uint16 vbatmeas; /* Measured VBAT sense value */ - uint16 featureflag; /* Currently active feature flags */ - int8 chiptemp; /* Chip temparature */ - int8 femtemp; /* Fem temparature */ - - uint32 nrate; /* Current Tx nrate */ - - uint8 cal_phase_id; /* Current Multi phase cal ID */ - uint8 rxchain; /* Rx Chain */ - uint8 txchain; /* Tx Chain */ - uint8 ofdm_desense; /* OFDM desense */ - - uint8 bphy_desense; /* BPHY desense */ - uint8 pll_lockstatus; /* PLL Lock status */ - uint8 pad1; /* Padding byte to align with word */ - uint8 pad2; /* Padding byte to align with word */ - - uint32 duration; /**< millisecs spent sampling this channel */ - uint32 congest_ibss; /**< millisecs in our bss (presumably this traffic will */ - /**< move if cur bss moves channels) */ - uint32 congest_obss; /**< traffic not in our bss */ - uint32 interference; /**< millisecs detecting a non 802.11 interferer. */ - -} phy_periodic_log_cmn_t; - -typedef struct phy_periodic_log_cmn_v2 { - uint16 chanspec; /* Current phy chanspec */ - uint16 vbatmeas; /* Measured VBAT sense value */ - uint16 featureflag; /* Currently active feature flags */ - int8 chiptemp; /* Chip temparature */ - int8 femtemp; /* Fem temparature */ - - uint32 nrate; /* Current Tx nrate */ - - uint8 cal_phase_id; /* Current Multi phase cal ID */ - uint8 rxchain; /* Rx Chain */ - uint8 txchain; /* Tx Chain */ - uint8 ofdm_desense; /* OFDM desense */ - - uint8 bphy_desense; /* BPHY desense */ - uint8 pll_lockstatus; /* PLL Lock status */ - - uint32 duration; /* millisecs spent sampling this channel */ - uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ - /* move if cur bss moves channels) */ - uint32 congest_obss; /* traffic not in our bss */ - uint32 interference; /* millisecs detecting a non 802.11 interferer. */ - - uint8 slice; - uint8 version; /* version of fw/ucode for debug purposes */ - bool phycal_disable; /* Set if calibration is disabled */ - uint8 pad; - uint16 phy_log_counter; - uint16 noise_mmt_overdue; /* Count up if ucode noise mmt is overdue for 5 sec */ - uint16 chan_switch_tm; /* Channel switch time */ - - /* HP2P related params */ - uint16 shm_mpif_cnt_val; - uint16 shm_thld_cnt_val; - uint16 shm_nav_cnt_val; - uint16 shm_cts_cnt_val; - - uint16 shm_m_prewds_cnt; /* Count of pre-wds fired in the ucode */ - uint32 last_cal_time; /* Last cal execution time */ - uint16 deaf_count; /* Depth of stay_in_carrier_search function */ - uint32 ed20_crs0; /* ED-CRS status on core 0 */ - uint32 ed20_crs1; /* ED-CRS status on core 1 */ - uint32 noise_cal_req_ts; /* Time-stamp when noise cal was requested */ - uint32 noise_cal_intr_ts; /* Time-stamp when noise cal was completed */ - uint32 phywdg_ts; /* Time-stamp when wd was fired */ - uint32 phywd_dur; /* Duration of the watchdog */ - uint32 noise_mmt_abort_crs; /* Count of CRS during noise mmt */ - uint32 chanspec_set_ts; /* Time-stamp when chanspec was set */ - uint32 vcopll_failure_cnt; /* Number of VCO cal failures - * (including failures detected in ucode). - */ - uint32 dcc_fail_counter; /* Number of DC cal failures */ - uint32 log_ts; /* Time-stamp when this log was collected */ - - uint16 btcxovrd_dur; /* Cumulative btcx overide between WDGs */ - uint16 btcxovrd_err_cnt; /* BTCX override flagged errors */ - - uint16 femtemp_read_fail_counter; /* Fem temparature read fail counter */ - /* Misc general purpose debug counters (will be used for future debugging) */ - uint16 debug_01; - uint16 debug_02; -} phy_periodic_log_cmn_v2_t; - -typedef struct phy_periodic_log_cmn_v3 { - uint32 nrate; /* Current Tx nrate */ - uint32 duration; /**< millisecs spent sampling this channel */ - uint32 congest_ibss; /**< millisecs in our bss (presumably this traffic will */ - /**< move if cur bss moves channels) */ - uint32 congest_obss; /**< traffic not in our bss */ - uint32 interference; /**< millisecs detecting a non 802.11 interferer. */ - uint32 noise_cfg_exit1; - uint32 noise_cfg_exit2; - uint32 noise_cfg_exit3; - uint32 noise_cfg_exit4; - uint32 ed20_crs0; - uint32 ed20_crs1; - uint32 noise_cal_req_ts; - uint32 noise_cal_crs_ts; - uint32 log_ts; - uint32 last_cal_time; - uint32 phywdg_ts; - uint32 chanspec_set_ts; - uint32 noise_zero_inucode; - uint32 phy_crs_during_noisemmt; - uint32 wd_dur; - - int32 deaf_count; - - uint16 chanspec; /* Current phy chanspec */ - uint16 vbatmeas; /* Measured VBAT sense value */ - uint16 featureflag; /* Currently active feature flags */ - uint16 nav_cntr_l; - uint16 nav_cntr_h; - uint16 chanspec_set_last; - uint16 ucode_noise_fb_overdue; - uint16 phy_log_counter; - uint16 shm_mpif_cnt_val; - uint16 shm_thld_cnt_val; - uint16 shm_nav_cnt_val; - uint16 shm_dc_cnt_val; - uint16 shm_txff_cnt_val; - uint16 shm_cts_cnt_val; - uint16 shm_m_prewds_cnt; - - uint8 cal_phase_id; /* Current Multi phase cal ID */ - uint8 rxchain; /* Rx Chain */ - uint8 txchain; /* Tx Chain */ - uint8 ofdm_desense; /* OFDM desense */ - uint8 bphy_desense; /* BPHY desense */ - uint8 pll_lockstatus; /* PLL Lock status */ - int8 chiptemp; /* Chip temparature */ - int8 femtemp; /* Fem temparature */ - - bool phycal_disable; - uint8 pad; /* Padding byte to align with word */ -} phy_periodic_log_cmn_v3_t; - -typedef struct phy_periodic_log_cmn_v4 { - uint16 chanspec; /* Current phy chanspec */ - uint16 vbatmeas; /* Measured VBAT sense value */ - - uint16 featureflag; /* Currently active feature flags */ - int8 chiptemp; /* Chip temparature */ - int8 femtemp; /* Fem temparature */ - - uint32 nrate; /* Current Tx nrate */ - - uint8 cal_phase_id; /* Current Multi phase cal ID */ - uint8 rxchain; /* Rx Chain */ - uint8 txchain; /* Tx Chain */ - uint8 ofdm_desense; /* OFDM desense */ - - uint8 slice; - uint8 dbgfw_ver; /* version of fw/ucode for debug purposes */ - uint8 bphy_desense; /* BPHY desense */ - uint8 pll_lockstatus; /* PLL Lock status */ - - uint32 duration; /* millisecs spent sampling this channel */ - uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ - /* move if cur bss moves channels) */ - uint32 congest_obss; /* traffic not in our bss */ - uint32 interference; /* millisecs detecting a non 802.11 interferer. */ - - /* HP2P related params */ - uint16 shm_mpif_cnt_val; - uint16 shm_thld_cnt_val; - uint16 shm_nav_cnt_val; - uint16 shm_cts_cnt_val; - - uint16 shm_m_prewds_cnt; /* Count of pre-wds fired in the ucode */ - uint16 deaf_count; /* Depth of stay_in_carrier_search function */ - uint32 last_cal_time; /* Last cal execution time */ - uint32 ed20_crs0; /* ED-CRS status on core 0 */ - uint32 ed20_crs1; /* ED-CRS status on core 1 */ - uint32 noise_cal_req_ts; /* Time-stamp when noise cal was requested */ - uint32 noise_cal_intr_ts; /* Time-stamp when noise cal was completed */ - uint32 phywdg_ts; /* Time-stamp when wd was fired */ - uint32 phywd_dur; /* Duration of the watchdog */ - uint32 noise_mmt_abort_crs; /* Count of CRS during noise mmt */ - uint32 chanspec_set_ts; /* Time-stamp when chanspec was set */ - uint32 vcopll_failure_cnt; /* Number of VCO cal failures - * (including failures detected in ucode). - */ - uint16 dcc_attempt_counter; /* Number of DC cal attempts */ - uint16 dcc_fail_counter; /* Number of DC cal failures */ - uint32 log_ts; /* Time-stamp when this log was collected */ - - uint16 btcxovrd_dur; /* Cumulative btcx overide between WDGs */ - uint16 btcxovrd_err_cnt; /* BTCX override flagged errors */ - - uint16 femtemp_read_fail_counter; /* Fem temparature read fail counter */ - uint16 phy_log_counter; - uint16 noise_mmt_overdue; /* Count up if ucode noise mmt is overdue for 5 sec */ - uint16 chan_switch_tm; /* Channel switch time */ - - bool phycal_disable; /* Set if calibration is disabled */ - - /* dccal dcoe & idacc */ - uint8 dcc_err; /* dccal health check error status */ - uint8 dcoe_num_tries; /* number of retries on dcoe cal */ - uint8 idacc_num_tries; /* number of retries on idac cal */ - - uint8 dccal_phyrxchain; /* phy rxchain during dc calibration */ - uint8 dccal_type; /* DC cal type: single/multi phase, chan change, etc. */ - uint16 dcc_hcfail; /* dcc health check failure count */ - uint16 dcc_calfail; /* dcc failure count */ - - /* Misc general purpose debug counters (will be used for future debugging) */ - uint16 debug_01; - uint16 debug_02; - uint16 debug_03; - uint16 debug_04; - uint16 debug_05; -} phy_periodic_log_cmn_v4_t; - -typedef struct phy_periodic_log_core { - uint8 baseindxval; /* TPC Base index */ - int8 tgt_pwr; /* Programmed Target power */ - int8 estpwradj; /* Current Est Power Adjust value */ - int8 crsmin_pwr; /* CRS Min/Noise power */ - int8 rssi_per_ant; /* RSSI Per antenna */ - int8 snr_per_ant; /* SNR Per antenna */ - int8 pad1; /* Padding byte to align with word */ - int8 pad2; /* Padding byte to align with word */ -} phy_periodic_log_core_t; - -typedef struct phy_periodic_log_core_v3 { - uint8 baseindxval; /* TPC Base index */ - int8 tgt_pwr; /* Programmed Target power */ - int8 estpwradj; /* Current Est Power Adjust value */ - int8 crsmin_pwr; /* CRS Min/Noise power */ - int8 rssi_per_ant; /* RSSI Per antenna */ - int8 snr_per_ant; /* SNR Per antenna */ - - /* dccal dcoe & idacc */ - uint16 dcoe_done_0; /* dccal control register 44 */ - uint16 dcoe_done_1; /* dccal control register 45 */ - uint16 dcoe_done_2; /* dccal control register 46 */ - uint16 idacc_done_0; /* dccal control register 21 */ - uint16 idacc_done_1; /* dccal control register 60 */ - uint16 idacc_done_2; /* dccal control register 61 */ - int16 psb; /* psb read during dccal health check */ - uint8 pktproc; /* pktproc read during dccal health check */ - - int8 pad1; /* Padding byte to align with word */ - int8 pad2; /* Padding byte to align with word */ - int8 pad3; /* Padding byte to align with word */ -} phy_periodic_log_core_v3_t; - -typedef struct phy_periodic_log_core_v2 { - int32 rxs; /* FDIQ Slope coeffecient */ - - uint16 ofdm_txa; /* OFDM Tx IQ Cal a coeff */ - uint16 ofdm_txb; /* OFDM Tx IQ Cal b coeff */ - uint16 ofdm_txd; /* contain di & dq */ - uint16 rxa; /* Rx IQ Cal A coeffecient */ - uint16 rxb; /* Rx IQ Cal B coeffecient */ - uint16 baseidx; /* TPC Base index */ - - uint8 baseindxval; /* TPC Base index */ - - int8 tgt_pwr; /* Programmed Target power */ - int8 estpwradj; /* Current Est Power Adjust value */ - int8 crsmin_pwr; /* CRS Min/Noise power */ - int8 rssi_per_ant; /* RSSI Per antenna */ - int8 snr_per_ant; /* SNR Per antenna */ - int8 pad1; /* Padding byte to align with word */ - int8 pad2; /* Padding byte to align with word */ -} phy_periodic_log_core_v2_t; - -#define PHY_PERIODIC_LOG_VER1 (1u) - -typedef struct phy_periodic_log_v1 { - uint8 version; /* Logging structure version */ - uint8 numcores; /* Number of cores for which core specific data present */ - uint16 length; /* Length of the entire structure */ - phy_periodic_log_cmn_t phy_perilog_cmn; - phy_periodic_counters_v1_t counters_peri_log; - /* This will be a variable length based on the numcores field defined above */ - phy_periodic_log_core_t phy_perilog_core[1]; -} phy_periodic_log_v1_t; - -#define PHYCAL_LOG_VER3 (3u) -#define PHY_PERIODIC_LOG_VER3 (3u) - -/* 4387 onwards */ -typedef struct phy_periodic_log_v3 { - uint8 version; /* Logging structure version */ - uint8 numcores; /* Number of cores for which core specific data present */ - uint16 length; /* Length of the structure */ - - /* Logs general PHY parameters */ - phy_periodic_log_cmn_v2_t phy_perilog_cmn; - - /* Logs ucode counters and NAVs */ - phy_periodic_counters_v3_t counters_peri_log; - - /* Logs data pertaining to each core */ - phy_periodic_log_core_t phy_perilog_core[1]; -} phy_periodic_log_v3_t; - -#define PHY_PERIODIC_LOG_VER5 (5u) - -typedef struct phy_periodic_log_v5 { - uint8 version; /* Logging structure version */ - uint8 numcores; /* Number of cores for which core specific data present */ - uint16 length; /* Length of the structure */ - - /* Logs general PHY parameters */ - phy_periodic_log_cmn_v4_t phy_perilog_cmn; - - /* Logs ucode counters and NAVs */ - phy_periodic_counters_v3_t counters_peri_log; - - /* Logs data pertaining to each core */ - phy_periodic_log_core_v3_t phy_perilog_core[1]; -} phy_periodic_log_v5_t; - -typedef struct phycal_log_v3 { - uint8 version; /* Logging structure version */ - uint8 numcores; /* Number of cores for which core specific data present */ - uint16 length; /* Length of the entire structure */ - phycal_log_cmn_v2_t phycal_log_cmn; /* Logging common structure */ - /* This will be a variable length based on the numcores field defined above */ - phycal_log_core_v3_t phycal_log_core[1]; -} phycal_log_v3_t; - -/* Note: The version 2 is reserved for 4357 only. Future chips must not use this version. */ - -#define MAX_CORE_4357 (2u) -#define PHYCAL_LOG_VER2 (2u) -#define PHY_PERIODIC_LOG_VER2 (2u) - -typedef struct { - uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS, - * Control Management (includes retransmissions) - */ - uint32 rxrsptmout; /**< number of response timeouts for transmitted frames - * expecting a response - */ - uint32 rxstrt; /**< number of received frames with a good PLCP */ - uint32 rxbadplcp; /**< number of parity check of the PLCP header failed */ - uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ - uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ - uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ - uint32 rxbeaconmbss; /**< beacons received from member of BSS */ - uint32 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */ - uint32 rxf0ovfl; /** < Rx FIFO0 overflow counters information */ - uint32 rxf1ovfl; /** < Rx FIFO1 overflow counters information */ - uint32 rxdtocast; /**< number of received DATA frames (good FCS and no matching RA) */ - uint32 rxtoolate; /**< receive too late */ - uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ -} phy_periodic_counters_v2_t; - -/* Note: The version 2 is reserved for 4357 only. All future chips must not use this version. */ - -typedef struct phycal_log_core_v2 { - uint16 ofdm_txa; /* OFDM Tx IQ Cal a coeff */ - uint16 ofdm_txb; /* OFDM Tx IQ Cal b coeff */ - uint16 ofdm_txd; /* contain di & dq */ - uint16 rxa; /* Rx IQ Cal A coeffecient */ - uint16 rxb; /* Rx IQ Cal B coeffecient */ - uint8 baseidx; /* TPC Base index */ - uint8 pad; - int32 rxs; /* FDIQ Slope coeffecient */ -} phycal_log_core_v2_t; - -/* Note: The version 2 is reserved for 4357 only. All future chips must not use this version. */ - -typedef struct phycal_log_v2 { - uint8 version; /* Logging structure version */ - uint16 length; /* Length of the entire structure */ - uint8 pad; - phycal_log_cmn_t phycal_log_cmn; /* Logging common structure */ - phycal_log_core_v2_t phycal_log_core[MAX_CORE_4357]; -} phycal_log_v2_t; - -/* Note: The version 2 is reserved for 4357 only. All future chips must not use this version. */ - -typedef struct phy_periodic_log_v2 { - uint8 version; /* Logging structure version */ - uint16 length; /* Length of the entire structure */ - uint8 pad; - phy_periodic_log_cmn_t phy_perilog_cmn; - phy_periodic_counters_v2_t counters_peri_log; - phy_periodic_log_core_t phy_perilog_core[MAX_CORE_4357]; -} phy_periodic_log_v2_t; - -#define PHY_PERIODIC_LOG_VER4 (4u) - -/* - * Note: The version 4 is reserved for 4357 Deafness Debug only. - * All future chips must not use this version. - */ -typedef struct phy_periodic_log_v4 { - uint8 version; /* Logging structure version */ - uint8 pad; - uint16 length; /* Length of the entire structure */ - phy_periodic_log_cmn_v3_t phy_perilog_cmn; - phy_periodic_counters_v4_t counters_peri_log; - phy_periodic_log_core_v2_t phy_perilog_core[MAX_CORE_4357]; -} phy_periodic_log_v4_t; - /* Event log payload for enhanced roam log */ typedef enum { ROAM_LOG_SCANSTART = 1, /* EVT log for roam scan start */ @@ -1489,8 +1068,12 @@ typedef enum { ROAM_LOG_NBR_REP = 5, /* EVT log for Neighbor REP */ ROAM_LOG_BCN_REQ = 6, /* EVT log for BCNRPT REQ */ ROAM_LOG_BCN_REP = 7, /* EVT log for BCNRPT REP */ - ROAM_LOG_BTM_REP = 8, /* EVT log for BTM REP */ + ROAM_LOG_BTM_REP = 8, /* EVT log for BTM Response */ ROAM_LOG_WIPS_EVENT = 9, /* EVT log for WIPS Event */ + ROAM_LOG_6G_NOVLP_REP = 10, /* EVT log for 6G NoVLP Report */ + ROAM_LOG_WTC_BTM_REP = 11, /* EVT log for WTC BTM Req/Resp Report */ + ROAM_LOG_BTM_QUERY = 12, /* EVT log for WTC BTM Query */ + ROAM_LOG_BTM_REQ = 13, /* EVT log for BTM Request */ PRSV_PERIODIC_ID_MAX } prsv_periodic_id_enum_t; @@ -1503,6 +1086,7 @@ typedef struct prsv_periodic_log_hdr { #define ROAM_LOG_VER_1 (1u) #define ROAM_LOG_VER_2 (2u) #define ROAM_LOG_VER_3 (3u) +#define ROAM_LOG_VER_4 (4u) #define ROAM_SSID_LEN (32u) typedef struct roam_log_trig_v1 { prsv_periodic_log_hdr_t hdr; @@ -1557,7 +1141,8 @@ typedef struct roam_log_trig_v2 { typedef struct roam_scan_ap_info { int8 rssi; uint8 cu; - uint8 pad[2]; + uint8 cu_avail; + uint8 pad; uint32 score; uint16 chanspec; struct ether_addr addr; @@ -1718,6 +1303,80 @@ typedef struct roam_log_wips_evt_v3 { int16 deauth_rssi; } roam_log_wips_evt_v3_t; +typedef struct roam_log_6g_novlp_v3 { + prsv_periodic_log_hdr_t hdr; + struct ether_addr bssid; /* ether addr */ + uint16 chanspec; /* Chanspec */ +} roam_log_6g_novlp_v3_t; + +#define WTC_BTMREQ 0 /* WTC BTM request type */ +#define WTC_BTMRESP 1 /* WTC BTM response type */ + +typedef struct roam_log_wtc_btmrep_v3 { + prsv_periodic_log_hdr_t hdr; + uint8 wtc_type; /* 0:WTC_BTMREQ, 1:WTC_BTMRESP */ + uint8 ie_length; + uint8 wtc_ver; + uint8 pad; + union { + struct { + /* WTC configuration from iovar */ + uint8 mode; + uint8 scantype; + int8 rssithresh[WTC_MAX_BAND]; + int8 ap_rssithresh[WTC_MAX_BAND]; + /* WTC Request IE */ + uint8 rsn_code; + uint8 subcode; + uint8 duration; /* by default 0 */ + uint8 status; /* WTC request is invalid */ + } wtcreq; + struct { + /* WTC Response IE */ + uint8 rsn_code; /* WTC VSIE reason code */ + uint8 status; /* BTM response status */ + uint16 pad; + } wtcresp; + }; +} roam_log_wtc_btmrep_v3_t; + +typedef struct roam_log_btm_query_v3 { + prsv_periodic_log_hdr_t hdr; + uint8 token; + uint8 reason; + uint8 pad[2]; +} roam_log_btm_query_v3_t; + +/* ROAM_LOG_VER_4 specific structures */ +typedef struct roam_log_btm_resp_v4 { + prsv_periodic_log_hdr_t hdr; + uint8 req_mode; /* d11 BSSTRANS req mode */ + uint8 status; /* d11 BSSTRANS response status code */ + uint8 token; /* d11 BSSTRANS response token */ + uint8 term_delay; /* d11 BSSTRANS response BSS Termination delay */ + struct ether_addr target_addr; /* bssid to move */ + uint16 pad[1]; + int result; +} roam_log_btm_resp_v4_t; + +#define ROAM_NBR_RPT_LIST_SIZE 4 +typedef struct roam_nbr_rpt_info { + struct ether_addr bssid; + uint8 preference; + uint8 pad[1]; +} roam_nbr_rpt_info_t; + +typedef struct roam_log_btm_req_v4 { + prsv_periodic_log_hdr_t hdr; + uint8 req_mode; /* d11 BSSTRANS req mode */ + uint8 token; /* d11 BSSTRANS response token */ + uint16 nbrlist_size; /* num of nbr in Preferred Candidate List */ + uint32 disassoc_dur; + uint32 validity_dur; + uint32 bss_term_dur; + roam_nbr_rpt_info_t nbr_list[ROAM_NBR_RPT_LIST_SIZE]; +} roam_log_btm_req_v4_t; + #define EVENT_LOG_BUFFER_ID_PMK 0 #define EVENT_LOG_BUFFER_ID_ANONCE 1 #define EVENT_LOG_BUFFER_ID_SNONCE 2 @@ -1769,7 +1428,118 @@ typedef struct event_log_wl_fsm_struct { /* To be used by DVFS event log FSM logging */ typedef struct event_log_rte_dvfs_fsm_struct { event_log_generic_fsm_struct_t generic_fsm; - uint32 data[]; /* Any other information relevant to this state transition */ + uint32 data[]; /* Any other information relevant to this state transition */ } event_log_rte_dvfs_fsm_struct_t; +/* Slotted BSS timer reference for RX deafness debug */ +#define WLC_SLOTTED_BSS_TIMEREF_VERSION_1 (1u) +typedef struct wlc_slotted_bss_timeref_v1 { + uint16 version; + uint8 wlc_unit; /* WLC unit that triggered generation of this timestamp */ + uint8 idx; /* Slotted BSS index for which this timestamp is present */ + uint32 nan_timeref_h; /* NAN reference TSF high */ + uint32 nan_timeref_l; /* NAN reference TSF low */ + uint32 aw_timeref; /* aw counter value in AWDL case */ +} wlc_slotted_bss_timeref_v1_t; + +/* Slotted BSS timer reference for RX deafness debug */ +typedef struct wlc_slotted_bss_timeref_values_v1 { + uint32 nan_timeref_h; /* NAN reference TSF high */ + uint32 nan_timeref_l; /* NAN reference TSF low */ + uint32 aw_timeref; /* aw counter value in AWDL case */ +} wlc_slotted_bss_timeref_values_v1_t; + +typedef struct wlc_slotted_bss_timeref_v2 { + uint16 length; /* Length of the entire structure */ + uint8 wlc_unit; /* WLC unit that triggered generation of this timestamp */ + uint8 pad; + wlc_slotted_bss_timeref_values_v1_t timerefs[]; +} wlc_slotted_bss_timeref_v2_t; + +#define TRIG_LOG_EVENTS_XTLV_CONTAINER_VERSION_1 (1u) +typedef struct trig_log_events_xtlv_container { + uint16 version; /**< see definition of TRIG_LOG_EVENTS_XTLV_CONTAINER_VERSION */ + uint16 len; /**< length of data including all paddings. */ + uint8 data []; /**< variable length payload: + * 1 or more bcm_xtlv_t type of tuples. + * each tuple is padded to multiple of 4 bytes. + * 'len' field of this structure includes all paddings. + */ +} trig_log_events_xtlv_container_v1_t; + +/* Bus device HTOD RX dump info. Sent in triggered log events container above */ +#define PCIEDEV_HTOD_RX_INFO_VERSION_1 (1u) +typedef struct pciedev_htod_rx_ring_info_v1 { + uint16 version; + uint16 g_rxcplist_max; + uint16 g_rxcplist_avail; + uint16 htod_rx_rd_idx; + uint16 htod_rx_wr_idx; + uint16 dtoh_rxcpl_rd_idx; + uint16 dtoh_rxcpl_wr_idx; + uint16 htod_rx_buf_pool_buf_cnt; + uint16 htod_rx_buf_pool_item_cnt; + uint16 htod_rx_buf_pool_availcnt; + uint16 htod_rx_buf_pool_pend_item_cnt; +} pciedev_htod_rx_ring_info_v1_t; + +/* WL RX fifo overflow info. Sent in triggered log events container above */ +#define WLC_RX_FIFO_DMA_NUM (3u) +typedef struct wlc_rx_fifo_overflow_info_v1 { + uint8 unit; + uint8 rxfifo_bitmap; + uint8 d3_state; + uint8 pad; + uint32 macintstatus; + + /* portions of DMA registers */ + uint32 rx_dma_reg_status0; + uint32 rx_dma_reg_status1; + uint32 rx_dma_reg_addrlow; + uint32 rx_dma_reg_addrhigh; + uint32 rx_dma_reg_control; + uint32 rx_dma_reg_ptr; + uint16 pktpool_avail; + uint16 pktpool_n_pkts; + + uint32 dma_stall_check_wd_time; + uint32 rxfifo0ovfl; + uint32 rxfifo1ovfl; + uint32 dma_stall_check_rxfifo0ovfl; + uint32 dma_stall_check_rxfifo1ovfl; + + uint32 rxfill[WLC_RX_FIFO_DMA_NUM]; + uint32 dma_stall_check_rxfill[WLC_RX_FIFO_DMA_NUM]; + uint64 rx_dma_fill_success_time[WLC_RX_FIFO_DMA_NUM]; /* in ns */ + uint64 rx_dma_fill_fail_time[WLC_RX_FIFO_DMA_NUM]; /* in ns */ + + uint32 rxposts[WLC_RX_FIFO_DMA_NUM]; + uint32 dma_stall_check_rxposts[WLC_RX_FIFO_DMA_NUM]; + uint64 rx_dma_posts_success_time[WLC_RX_FIFO_DMA_NUM]; /* in ns */ + + uint32 rx_dma_desc_count[WLC_RX_FIFO_DMA_NUM]; +} wlc_rx_fifo_overflow_info_v1_t; + +/* Data structures for transferring channel switch histogram data to host */ + +#define CHSW_HISTOGRAM_HOST_ENTRY_VERSION_1 (1u) + +typedef struct chsw_histogram_host_entry_v1 { + uint8 version; + uint8 PAD[3]; + chanspec_t from_chanspec; + chanspec_t to_chanspec; + uint32 buckets[BCM_FLEX_ARRAY]; +} chsw_histogram_host_entry_v1_t; + +#define CHSW_HISTOGRAM_HOST_DATA_VERSION_1 (1u) + +typedef struct chsw_histogram_host_data_v1 { + uint8 version; + uint8 num_host_entries; /* Number of host entries */ + uint8 num_buckets; /* Number of buckets in each host entry */ + uint8 PAD; + chsw_histogram_host_entry_v1_t host_entries[BCM_FLEX_ARRAY]; +} chsw_histogram_host_data_v1_t; + #endif /* _EVENT_LOG_PAYLOAD_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_set.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_set.h old mode 100755 new mode 100644 index 5e098d87bdcd..08f048cbd259 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_set.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_set.h @@ -1,7 +1,7 @@ /* * EVENT_LOG system definitions * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -25,13 +25,56 @@ #define _EVENT_LOG_SET_H_ /* Set assignments */ +/* set 0 */ #define EVENT_LOG_SET_BUS (0u) -#define EVENT_LOG_SET_WL (1u) -#define EVENT_LOG_SET_PSM (2u) -#define EVENT_LOG_SET_ERROR (3u) +#ifndef EVENT_LOG_SET_BUS_NUM_BLOCKS +#define EVENT_LOG_SET_BUS_NUM_BLOCKS (2u) +#endif -/* MSCH logging */ +#ifndef EVENT_LOG_SET_BUS_BLOCK_SIZE +#define EVENT_LOG_SET_BUS_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +/* set 1 */ +#define EVENT_LOG_SET_WL (1u) +#ifndef EVENT_LOG_SET_WL_NUM_BLOCKS +#define EVENT_LOG_SET_WL_NUM_BLOCKS (4u) +#endif + +#ifndef EVENT_LOG_SET_WL_BLOCK_SIZE +#define EVENT_LOG_SET_WL_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +/* Set 2 */ +#define EVENT_LOG_SET_PSM (2u) +#ifndef EVENT_LOG_SET_PSM_NUM_BLOCKS +#define EVENT_LOG_SET_PSM_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_PSM_BLOCK_SIZE +#define EVENT_LOG_SET_PSM_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +/* set 3 */ +#define EVENT_LOG_SET_ERROR (3u) +#ifndef EVENT_LOG_SET_ERROR_NUM_BLOCKS +#define EVENT_LOG_SET_ERROR_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_ERROR_BLOCK_SIZE +#define EVENT_LOG_SET_ERROR_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_1K) +#endif + +/* Set 4: MSCH logging */ #define EVENT_LOG_SET_MSCH_PROFILER (4u) +#ifndef EVENT_LOG_SET_MSCH_NUM_BLOCKS +#define EVENT_LOG_SET_MSCH_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_MSCH_BLOCK_SIZE +/* Updated the size as per comment in the msch profiler attach code */ +#define EVENT_LOG_SET_MSCH_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_1K) +#endif /* A particular customer uses sets 5, 6, and 7. There is a request * to not name these log sets as that could limit their ability to @@ -50,6 +93,13 @@ */ #define EVENT_LOG_SET_8 (8u) #define EVENT_LOG_SET_PRSRV (EVENT_LOG_SET_8) +#ifndef EVENT_LOG_SET_PRSRV_NUM_BLOCKS +#define EVENT_LOG_SET_PRSRV_NUM_BLOCKS (3u) +#endif + +#ifndef EVENT_LOG_SET_PRSRV_BLOCK_SIZE +#define EVENT_LOG_SET_PRSRV_BLOCK_SIZE (EVENT_LOG_MAX_BLOCK_SIZE) +#endif #define EVENT_LOG_SET_9 (9u) /* General purpose preserve chatty. @@ -59,30 +109,97 @@ */ #define EVENT_LOG_SET_GP_PRSRV_CHATTY (EVENT_LOG_SET_9) #define EVENT_LOG_SET_PRSRV_CHATTY (EVENT_LOG_SET_6) +/* Log set 9 */ +#ifndef EVENT_LOG_SET_GP_PRSRV_CHATTY_NUM_BLOCKS +#define EVENT_LOG_SET_GP_PRSRV_CHATTY_NUM_BLOCKS (2u) +#endif -/* BUS preserve */ +#ifndef EVENT_LOG_SET_GP_PRSRV_CHATTY_BLOCK_SIZE +#define EVENT_LOG_SET_GP_PRSRV_CHATTY_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_1K) +#endif + +/* Set 10: BUS preserve */ #define EVENT_LOG_SET_PRSRV_BUS (10u) +#ifndef EVENT_LOG_SET_PRSRV_BUS_NUM_BLOCKS +#define EVENT_LOG_SET_PRSRV_BUS_NUM_BLOCKS (3u) +#endif -/* WL preserve */ +#ifndef EVENT_LOG_SET_PRSRV_BUS_BLOCK_SIZE +#define EVENT_LOG_SET_PRSRV_BUS_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +/* Set 11: WL preserve */ #define EVENT_LOG_SET_PRSRV_WL (11u) +#ifndef EVENT_LOG_SET_PRSRV_WL_NUM_BLOCKS +#define EVENT_LOG_SET_PRSRV_WL_NUM_BLOCKS (2u) +#endif -/* Slotted BSS set */ +#ifndef EVENT_LOG_SET_PRSRV_WL_BLOCK_SIZE +#define EVENT_LOG_SET_PRSRV_WL_BLOCK_SIZE (EVENT_LOG_MAX_BLOCK_SIZE) +#endif + +/* Set 12: Slotted BSS set */ #define EVENT_LOG_SET_WL_SLOTTED_BSS (12u) +#ifndef EVENT_LOG_SET_WL_SLOTTED_BSS_NUM_BLOCKS +#define EVENT_LOG_SET_WL_SLOTTED_BSS_NUM_BLOCKS (5u) +#endif -/* PHY entity logging */ +#ifndef EVENT_LOG_SET_WL_SLOTTED_BSS_BLOCK_SIZE +#define EVENT_LOG_SET_WL_SLOTTED_BSS_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +/* Set 13: PHY entity logging */ #define EVENT_LOG_SET_PHY (13u) +#ifndef EVENT_LOG_SET_PHY_NUM_BLOCKS +#define EVENT_LOG_SET_PHY_NUM_BLOCKS (2u) +#endif -/* PHY preserve */ +#ifndef EVENT_LOG_SET_PHY_BLOCK_SIZE +#define EVENT_LOG_SET_PHY_BLOCK_SIZE (EVENT_LOG_MAX_BLOCK_SIZE) +#endif + +/* Set 14: PHY preserve */ #define EVENT_LOG_SET_PRSRV_PHY (14u) +/* PHY periodic */ +/* Use the newer name in future */ +#define EVENT_LOG_SET_PERIODIC_PHY (14u) +#ifndef EVENT_LOG_SET_PHY_PERIODIC_NUM_BLOCKS +#define EVENT_LOG_SET_PHY_PERIODIC_NUM_BLOCKS (4u) +#endif -/* RTE entity */ +#ifndef EVENT_LOG_SET_PHY_PERIODIC_BLOCK_SIZE +#define EVENT_LOG_SET_PHY_PERIODIC_BLOCK_SIZE (EVENT_LOG_MAX_BLOCK_SIZE) +#endif + +/* set 15: RTE entity */ #define EVENT_LOG_SET_RTE (15u) +#ifndef EVENT_LOG_SET_RTE_NUM_BLOCKS +#define EVENT_LOG_SET_RTE_NUM_BLOCKS (2u) +#endif -/* Malloc and free logging */ +#ifndef EVENT_LOG_SET_RTE_BLOCK_SIZE +#define EVENT_LOG_SET_RTE_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +/* set 16: Malloc and free logging */ #define EVENT_LOG_SET_MEM_API (16u) +#ifndef EVENT_LOG_SET_MEM_API_NUM_BLOCKS +#define EVENT_LOG_SET_MEM_API_NUM_BLOCKS (7u) +#endif -/* Console buffer */ -#define EVENT_LOG_SET_RTE_CONS_BUF (17u) +#ifndef EVENT_LOG_SET_MEM_API_BLOCK_SIZE +#define EVENT_LOG_SET_MEM_API_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +/* set 17: summary log set to hold various summaries i.e. channel switch, scan, etc */ +#define EVENT_LOG_SET_SUMMARY (17u) +#ifndef EVENT_LOG_SET_SUMMARY_NUM_BLOCKS +#define EVENT_LOG_SET_SUMMARY_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_SUMMARY_BLOCK_SIZE +#define EVENT_LOG_SET_SUMMARY_BLOCK_SIZE (EVENT_LOG_MAX_BLOCK_SIZE) +#endif /* three log sets for general debug purposes */ #define EVENT_LOG_SET_GENERAL_DBG_1 (18u) @@ -92,33 +209,183 @@ /* Log sets for capturing power related logs. Note that these sets * are to be used across entire system and not just WL. */ +/* set 21: power related logs */ #define EVENT_LOG_SET_POWER_1 (21u) +#ifndef EVENT_LOG_SET_POWER_1_NUM_BLOCKS +#define EVENT_LOG_SET_POWER_1_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_POWER_1_BLOCK_SIZE +#define EVENT_LOG_SET_POWER_1_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_1K) +#endif + +/* set 22: power related logs */ #define EVENT_LOG_SET_POWER_2 (22u) +#ifndef EVENT_LOG_SET_POWER_2_NUM_BLOCKS +#define EVENT_LOG_SET_POWER_2_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_POWER_2_BLOCK_SIZE +#define EVENT_LOG_SET_POWER_2_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_1K) +#endif /* Used for timestamp plotting, TS_LOG() */ #define EVENT_LOG_SET_TS_LOG (23u) +#ifndef EVENT_LOG_SET_TS_LOG_NUM_BLOCKS +#define EVENT_LOG_SET_TS_LOG_NUM_BLOCKS (4u) +#endif -/* BUS preserve chatty */ +#ifndef EVENT_LOG_SET_TS_LOG_BLOCK_SIZE +#define EVENT_LOG_SET_TS_LOG_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +/* set 24: BUS preserve chatty */ #define EVENT_LOG_SET_PRSRV_BUS_CHATTY (24u) +#ifndef EVENT_LOG_SET_PRSRV_BUS_CHATTY_NUM_BLOCKS +#define EVENT_LOG_SET_PRSRV_BUS_CHATTY_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_PRSRV_BUS_CHATTY_BLOCK_SIZE +#define EVENT_LOG_SET_PRSRV_BUS_CHATTY_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif /* PRESERVE_PREIODIC_LOG_SET */ /* flush if host is in D0 at every period */ #define EVENT_LOG_SET_PRSV_PERIODIC (25u) +#ifndef EVENT_LOG_SET_PRSRV_PERIODIC_NUM_BLOCKS +#define EVENT_LOG_SET_PRSRV_PERIODIC_NUM_BLOCKS (3u) +#endif -/* AMT logging and other related information */ +#ifndef EVENT_LOG_SET_PRSRV_PERIODIC_BLOCK_SIZE +#define EVENT_LOG_SET_PRSRV_PERIODIC_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +/* set 26: AMT logging and other related information */ #define EVENT_LOG_SET_AMT (26u) +#ifndef EVENT_LOG_SET_AMT_NUM_BLOCKS +#define EVENT_LOG_SET_AMT_NUM_BLOCKS (2u) +#endif -/* State machine logging. Part of preserve logs */ +#ifndef EVENT_LOG_SET_AMT_BLOCK_SIZE +#define EVENT_LOG_SET_AMT_BLOCK_SIZE (EVENT_LOG_MAX_BLOCK_SIZE) +#endif + +/* set: 27 State machine logging. Part of preserve logs */ #define EVENT_LOG_SET_FSM (27u) +#ifndef EVENT_LOG_SET_FSM_NUM_BLOCKS +#define EVENT_LOG_SET_FSM_NUM_BLOCKS (2u) +#endif -/* wbus related logging */ +#ifndef EVENT_LOG_SET_FSM_BLOCK_SIZE +#define EVENT_LOG_SET_FSM_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_1K) +#endif + +/* set: 28 wbus related logging */ #define EVENT_LOG_SET_WBUS (28u) +#ifndef EVENT_LOG_SET_WBUS_NUM_BLOCKS +#define EVENT_LOG_SET_WBUS_NUM_BLOCKS (3u) +#endif -/* bcm trace logging */ +#ifndef EVENT_LOG_SET_WBUS_BLOCK_SIZE +#define EVENT_LOG_SET_WBUS_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_256B) +#endif + +/* set 29: bcm trace logging */ #define EVENT_LOG_SET_BCM_TRACE (29u) +#ifndef EVENT_LOG_SET_BCM_TRACE_NUM_BLOCKS +#define EVENT_LOG_SET_BCM_TRACE_NUM_BLOCKS (2u) +#endif -/* For PM alert related logging */ +#ifndef EVENT_LOG_SET_BCM_TRACE_BLOCK_SIZE +#define EVENT_LOG_SET_BCM_TRACE_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_1K) +#endif + +/* set 30: For PM alert related logging */ #define EVENT_LOG_SET_WL_PS_LOG (30u) +#ifndef EVENT_LOG_SET_WL_PS_NUM_BLOCKS +#define EVENT_LOG_SET_WL_PS_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_WL_PS_BLOCK_SIZE +#define EVENT_LOG_SET_WL_PS_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_1K) +#endif + +/* set 31: For SIB co-ex logging */ +#define EVENT_LOG_SET_WL_SIB_LOG (31u) +#ifndef EVENT_LOG_SET_WL_SIB_LOG_NUM_BLOCKS +#define EVENT_LOG_SET_WL_SIB_LOG_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_WL_SIB_LOG_BLOCK_SIZE +#define EVENT_LOG_SET_WL_SIB_LOG_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +/* set 32: For EWP HW Init logging */ +#define EVENT_LOG_SET_EWP_HW_INIT_LOG (32u) +#ifndef EVENT_LOG_SET_EWP_HW_INIT_LOG_NUM_BLOCKS +#define EVENT_LOG_SET_EWP_HW_INIT_LOG_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_EWP_HW_INIT_LOG_BLOCK_SIZE +#define EVENT_LOG_SET_EWP_HW_INIT_LOG_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +#ifdef COEX_CPU +/* set 35: Shdow log sets for coex cpu */ +#define EVENT_LOG_SET_COEX_SHADOW_INFO (35u) +#ifndef EVENT_LOG_SET_COEX_SHADOW_INFO_NUM_BLOCKS +#define EVENT_LOG_SET_COEX_SHADOW_INFO_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_COEX_SHADOW_INFO_BLOCK_SIZE +#define EVENT_LOG_SET_COEX_SHADOW_INFO_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +/* set 36 */ +#define EVENT_LOG_SET_COEX_SHADOW_ERR (36u) +#ifndef EVENT_LOG_SET_COEX_SHADOW_ERR_NUM_BLOCKS +#define EVENT_LOG_SET_COEX_SHADOW_ERR_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_COEX_SHADOW_ERR_BLOCK_SIZE +#define EVENT_LOG_SET_COEX_SHADOW_ERR_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +/* TODO: Rename coex shadow set PRSRV to TIMELINE. The old name will be removed once changes in + * all user components are submitted. + */ +/* set 37 */ +#define EVENT_LOG_SET_COEX_SHADOW_PRSRV (37u) +#define EVENT_LOG_SET_COEX_SHADOW_TIMELINE (37u) + +#ifndef EVENT_LOG_SET_COEX_SHADOW_TIMELINE_NUM_BLOCKS +#define EVENT_LOG_SET_COEX_SHADOW_TIMELINE_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_COEX_SHADOW_TIMELINE_BLOCK_SIZE +#define EVENT_LOG_SET_COEX_SHADOW_TIMELINE_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +#endif /* COEX_CPU */ + +/* set 38: For all BCM HAL logging. */ +#define EVENT_LOG_SET_BCMHAL (38u) +#ifndef EVENT_LOG_SET_BCMHAL_NUM_BLOCKS +#define EVENT_LOG_SET_BCMHAL_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_BCMHAL_BLOCK_SIZE +#define EVENT_LOG_SET_BCMHAL_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_512B) +#endif + +#define EVENT_LOG_SET_OBP_TRACE_LOG (39u) +#ifndef EVENT_LOG_SET_OBP_TRACE_LOG_NUM_BLOCKS +#define EVENT_LOG_SET_OBP_TRACE_LOG_NUM_BLOCKS (2u) +#endif + +#ifndef EVENT_LOG_SET_OBP_TRACE_LOG_BLOCK_SIZE +#define EVENT_LOG_SET_OBP_TRACE_LOG_BLOCK_SIZE (EVENT_LOG_BLOCK_SIZE_1K) +#endif #ifndef NUM_EVENT_LOG_SETS /* Set a maximum number of sets here. It is not dynamic for @@ -128,9 +395,9 @@ */ #ifdef NUM_EVENT_LOG_SETS_V2 /* for v2, everything has became unsigned */ -#define NUM_EVENT_LOG_SETS (31u) +#define NUM_EVENT_LOG_SETS (40u) #else /* NUM_EVENT_LOG_SETS_V2 */ -#define NUM_EVENT_LOG_SETS (31) +#define NUM_EVENT_LOG_SETS (40) #endif /* NUM_EVENT_LOG_SETS_V2 */ #endif /* NUM_EVENT_LOG_SETS */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_tag.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_tag.h old mode 100755 new mode 100644 index 54d93c6f37c4..6490a12ba483 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_tag.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_log_tag.h @@ -1,7 +1,7 @@ /* * EVENT_LOG system definitions * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -43,32 +43,14 @@ #define EVENT_LOG_TAG_BUS_SETUP 10 #define EVENT_LOG_TAG_BUS_MISC 11 -#ifdef WLAWDL -#define EVENT_LOG_TAG_AWDL_ERR 12 -#define EVENT_LOG_TAG_AWDL_WARN 13 -#define EVENT_LOG_TAG_AWDL_INFO 14 -#define EVENT_LOG_TAG_AWDL_DEBUG 15 -#define EVENT_LOG_TAG_AWDL_TRACE_TIMER 16 -#define EVENT_LOG_TAG_AWDL_TRACE_SYNC 17 -#define EVENT_LOG_TAG_AWDL_TRACE_CHAN 18 -#define EVENT_LOG_TAG_AWDL_TRACE_DP 19 -#define EVENT_LOG_TAG_AWDL_TRACE_MISC 20 -#define EVENT_LOG_TAG_AWDL_TEST 21 -#endif /* WLAWDL */ - #define EVENT_LOG_TAG_SRSCAN 22 #define EVENT_LOG_TAG_PWRSTATS_INFO 23 -#ifdef WLAWDL -#define EVENT_LOG_TAG_AWDL_TRACE_CHANSW 24 -#define EVENT_LOG_TAG_AWDL_TRACE_PEER_OPENCLOSE 25 -#endif /* WLAWDL */ - /* Timestamp logging for plotting. */ #define EVENT_LOG_TAG_TSLOG 26 -/* Possible candidates for reuse */ -#define EVENT_LOG_TAG_UCODE_FIFO 27 +/* Used wlc specific information in preserve log */ +#define EVENT_LOG_TAG_WL_INFORM 27 #define EVENT_LOG_TAG_SCAN_TRACE_LOW 28 #define EVENT_LOG_TAG_SCAN_TRACE_HIGH 29 @@ -98,13 +80,6 @@ #define EVENT_LOG_TAG_PCI_DATA 53 #define EVENT_LOG_TAG_PCI_RING 54 -#ifdef WLAWDL -/* EVENT_LOG_TAG_AWDL_TRACE_RANGING will be removed after wlc_ranging merge from IGUANA - * keeping it here to avoid compilation error on trunk - */ -#define EVENT_LOG_TAG_AWDL_TRACE_RANGING 55 -#endif /* WLAWDL */ - #define EVENT_LOG_TAG_RANGING_TRACE 55 #define EVENT_LOG_TAG_WL_ERROR 56 #define EVENT_LOG_TAG_PHY_ERROR 57 @@ -148,18 +123,10 @@ #define EVENT_LOG_TAG_BTCX_STATS 95 #define EVENT_LOG_TAG_LEAKY_AP_STATS 96 -#ifdef WLAWDL -#define EVENT_LOG_TAG_AWDL_TRACE_ELECTION 97 -#endif /* WLAWDL */ - #define EVENT_LOG_TAG_MIMO_PS_STATS 98 #define EVENT_LOG_TAG_PWRSTATS_PHY 99 #define EVENT_LOG_TAG_PWRSTATS_SCAN 100 -#ifdef WLAWDL -#define EVENT_LOG_TAG_PWRSTATS_AWDL 101 -#endif /* WLAWDL */ - #define EVENT_LOG_TAG_PWRSTATS_WAKE_V2 102 #define EVENT_LOG_TAG_LQM 103 #define EVENT_LOG_TAG_TRACE_WL_INFO 104 @@ -215,20 +182,10 @@ #define EVENT_LOG_TAG_BAM 154 #define EVENT_LOG_TAG_TXFAIL 155 -#ifdef WLAWDL -#define EVENT_LOG_TAG_AWDL_CONFIG_DBG 156 -#define EVENT_LOG_TAG_AWDL_SYNC_DBG 157 -#define EVENT_LOG_TAG_AWDL_PEER_DBG 158 -#endif /* WLAWDL */ - #define EVENT_LOG_TAG_RANDMAC_INFO 159 #define EVENT_LOG_TAG_RANDMAC_DBG 160 #define EVENT_LOG_TAG_RANDMAC_ERR 161 -#ifdef WLAWDL -#define EVENT_LOG_TAG_AWDL_DFSP_DBG 162 -#endif /* WLAWDL */ - #define EVENT_LOG_TAG_MSCH_CAL 163 #define EVENT_LOG_TAG_MSCH_OPP_CAL 164 #define EVENT_LOG_TAG_MSCH 165 @@ -264,10 +221,6 @@ #define EVENT_LOG_TAG_WL_COUNTERS_AUX 209 #define EVENT_LOG_TAG_AMPDU_DUMP_AUX 210 -#ifdef WLAWDL -#define EVENT_LOG_TAG_PWRSTATS_AWDL_AUX 211 -#endif /* WLAWDL */ - #define EVENT_LOG_TAG_PWRSTATS_PHY_AUX 212 #define EVENT_LOG_TAG_PWRSTATS_SCAN_AUX 213 #define EVENT_LOG_TAG_PWRSTATS_WAKE_V2_AUX 214 @@ -278,12 +231,12 @@ #define EVENT_LOG_TAG_FILS_DBG 219 #define EVENT_LOG_TAG_FILS_INFO 220 #define EVENT_LOG_TAG_FILS_ERROR 221 -#define EVENT_LOG_TAG_UNUSED1 222 -#define EVENT_LOG_TAG_UNUSED2 223 +#define EVENT_LOG_TAG_BTCX_STATS_AUX 222 +#define EVENT_LOG_TAG_ROAM_TGT_EVAL 223 #define EVENT_LOG_TAG_PPR_ERROR 224 /* Arbitrator callback log tags */ -#define EVENT_LOG_TAG_STF_ARB_CB_TRACE 224 +#define EVENT_LOG_TAG_STF_ARB_CB_TRACE 225 /* Intentional duplicated value as ERROR */ #define EVENT_LOG_TAG_STF_ARB_CB_ERROR 225 #define EVENT_LOG_TAG_PHY_PERIODIC_SEC 226 #define EVENT_LOG_TAG_RTE_ERROR 227 @@ -294,6 +247,7 @@ #define EVENT_LOG_TAG_HP2P_ERR 232 #define EVENT_LOG_TAG_SB_SCHED_DBG_SYNC 233 #define EVENT_LOG_TAG_ENHANCED_TS 234 +#define EVENT_LOG_TAG_PHY_OBSS_INFO 235 /* Available space for new tags for Dingo, Iguana and branches * prior to Koala only. From Koala onwards, new tags must be greater @@ -444,10 +398,6 @@ #define EVENT_LOG_TAG_BTCEC_INFO 341 #define EVENT_LOG_TAG_BTCEC_SCHED 342 -#ifdef WLAWDL -#define EVENT_LOG_TAG_AWDL_HC 343 -#endif /* WLAWDL */ - #ifdef SLOT_SCHED #define EVENT_LOG_TAG_SBSS_HC 344 #endif /* SLOT_SCHED */ @@ -535,8 +485,107 @@ #define EVENT_LOG_TAG_PKTFLTR_TRACE 390 #define EVENT_LOG_TAG_PKTFLTR_WARN 391 #define EVENT_LOG_TAG_PKTFLTR_ERROR 392 + +/* LLW */ +#define EVENT_LOG_TAG_LLW_ERR 393 +#define EVENT_LOG_TAG_LLW_INFO 394 + +#define EVENT_LOG_TAG_SPMI_INFO 395 +#define EVENT_LOG_TAG_SPMI_ERROR 396 +#define EVENT_LOG_TAG_SPMI_TRACE 397 + +#define EVENT_LOG_TAG_PROXD_DBG 400 +#define EVENT_LOG_TAG_RXOVFL 401 + +/* MLO EVEVNT_LOG_TAG */ +#define EVENT_LOG_TAG_WL_MLO_INFO 402 +#define EVENT_LOG_TAG_WL_MLO_TRACE 403 +#define EVENT_LOG_TAG_WL_MLO_WARN 404 +#define EVENT_LOG_TAG_WL_MLO_ERROR 405 +#define EVENT_LOG_TAG_RX_DEAFNESS_DBG 406 /* Used with triggered log events */ + +/* BCMSM event log tags */ +#define EVENT_LOG_TAG_BCMSM_ERROR 407 +#define EVENT_LOG_TAG_BCMSM_INFO 408 +#define EVENT_LOG_TAG_BCMSM_TRACE 409 + +/* EWP HW event log tags */ +#define EVENT_LOG_TAG_EWP_HW 410 + +#define EVENT_LOG_TAG_COEXCPU_ERROR 413 + +/* QoS and SCS (Stream Classification Service) */ +#define EVENT_LOG_TAG_RAV_QOS_ERROR 418 +#define EVENT_LOG_TAG_RAV_QOS_INFO 419 + +#define EVENT_LOG_TAG_RAV_SCS_ERROR 420 +#define EVENT_LOG_TAG_RAV_SCS_INFO 421 + +#define EVENT_LOG_TAG_AMPDU_BARDBG 422 + +#define EVENT_LOG_TAG_PASN_ERROR 423 +#define EVENT_LOG_TAG_PASN_INFO 424 + +#define EVENT_LOG_TAG_IGMP_DBG 425 +#define EVENT_LOG_TAG_IGMP_INFO 426 +#define EVENT_LOG_TAG_IGMP_ERR 427 + +#define EVENT_LOG_TAG_DNGL_CAPEXT_ERROR 428 +#define EVENT_LOG_TAG_DVFS_INFO 429 +#define EVENT_LOG_TAG_DVFS_ERROR 430 + +#define EVENT_LOG_TAG_BTCX_ERR 431 +#define EVENT_LOG_TAG_BTCX_INFO 432 +#define EVENT_LOG_TAG_BTCX_TRACE 433 + +#define EVENT_LOG_TAG_BCMHAL_SOCI_NCI_ERROR 434 +#define EVENT_LOG_TAG_BCMHAL_SOCI_NCI_TRACE 435 +#define EVENT_LOG_TAG_BCMHAL_SOCI_NCI_INFO 436 +#define EVENT_LOG_TAG_WL_TOSS 437 + +/* 6GHz Client-to-Client (C2C) logging */ +#define EVENT_LOG_TAG_C2C_ERROR 438 +#define EVENT_LOG_TAG_C2C_DBG 439 + +#define EVENT_LOG_TAG_OCT_INFO 440 + +#define EVENT_LOG_TAG_PHY_AZ_INFO 441 +#define EVENT_LOG_TAG_PHY_AZ_INFO_DBG 442 +#define EVENT_LOG_TAG_PHY_AZ_INFO_CSI 443 + +#define EVENT_LOG_TAG_WL_RATE_ERR 444 + +#define EVENT_LOG_TAG_6GCHANPROF_ERROR 445 +#define EVENT_LOG_TAG_6GCHANPROF_INFO 446 +#define EVENT_LOG_TAG_6GCHANPROF_TRACE 447 + +/* OWE STUFF */ +#define EVENT_LOG_TAG_OWE_DBG 448 +#define EVENT_LOG_TAG_OWE_INFO 449 +#define EVENT_LOG_TAG_OWE_ERR 450 + +/* Additional RRM event log (for Beacon report specifically) */ +#define EVENT_LOG_TAG_RRM_BCN_RPT 451 + +/* NAN pairing sub-module */ +#define EVENT_LOG_TAG_NAN_PAIRING 452 +#define EVENT_LOG_TAG_NAN_PAIRING_INFO 453 +#define EVENT_LOG_TAG_NAN_PAIRING_ERR 454 + +/* Scan abort related debug msgs */ +#define EVENT_LOG_TAG_WL_SCAN_ABORT_LOG 455 + +/* OBP - On Board Packet event log msgs. */ +#define EVENT_LOG_TAG_OBP 456 + +#define EVENT_LOG_TAG_SCAN_DEBUG 458 +#define EVENT_LOG_TAG_API_STRING 459 + +/* Channel Switch Function Runtime Profiling */ +#define EVENT_LOG_TAG_CHANSW_PROFILING 460 + /* EVENT_LOG_TAG_MAX = Set to the same value of last tag, not last tag + 1 */ -#define EVENT_LOG_TAG_MAX 392 +#define EVENT_LOG_TAG_MAX 460 typedef enum wl_el_set_type_def { EVENT_LOG_SET_TYPE_DEFAULT = 0, /* flush the log buffer when it is full - Default option */ @@ -609,7 +658,8 @@ typedef union event_log_extended_hdr { struct { uint8 extended_tag; /* Extended tag, bits[7..4] are reserved */ uint8 extended_count; /* Extended count. Reserved for now. */ - uint16 rsvd; /* Reserved */ + uint8 extended_fmtnum; /* bits[3..0] used. Rest reserved */ + uint8 rsvd; /* Reserved */ }; uint32 t; /* Type cheat */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_trace.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_trace.h old mode 100755 new mode 100644 index 3be93c633b5d..e760301763ea --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_trace.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/event_trace.h @@ -1,7 +1,7 @@ /* * Trace log blocks sent over HBUS * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/fils.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/fils.h old mode 100755 new mode 100644 index 1797abfa6ae2..935cd30f218b --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/fils.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/fils.h @@ -1,7 +1,7 @@ /* * Fundamental types and constants relating to FILS AUTHENTICATION * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -135,6 +135,26 @@ typedef BWL_PRE_PACKED_STRUCT union rnr_tbtt_info_field { uint8 bss_params; uint8 psd_20mhz; } BWL_POST_PACKED_STRUCT len13_t; + + /* Draft P802.11be Table 9-281 */ + BWL_PRE_PACKED_STRUCT struct len15 { + uint8 tbtt_offset; + tbtt_bssid_t bssid; + uint32 short_ssid; + uint8 bss_params; + uint8 mld_params[3]; + } BWL_POST_PACKED_STRUCT len15_t; + + /* Draft P802.11be Table 9-281 */ + BWL_PRE_PACKED_STRUCT struct len16 { + uint8 tbtt_offset; + tbtt_bssid_t bssid; + uint32 short_ssid; + uint8 bss_params; + uint8 psd_20mhz; + uint8 mld_params[3]; + } BWL_POST_PACKED_STRUCT len16_t; + } BWL_POST_PACKED_STRUCT rnr_tbtt_info_field_t; /* 11ai D11.0 9.4.2.171.1 TBTT Information field */ @@ -182,6 +202,16 @@ typedef BWL_PRE_PACKED_STRUCT struct fils_rnr_element { #define TBTT_INFO_HDR_LENGTH(hdr)\ (((hdr) & TBTT_INFO_HDR_LENGTH_MASK) >> 8u) +/* TBTT Information Header subfield - Draft P802.11REVmd D5.0 Figure 9-631 */ +#define TBTT_INFO_HDR_TI_FLD_TYPE_POS 0u /* TBTT Information Field Type */ +#define TBTT_INFO_HDR_TI_FLD_TYPE_SZ 2u +#define TBTT_INFO_HDR_FLTR_NAP_POS 2u /* Filtered Neighbor AP */ +#define TBTT_INFO_HDR_FLTR_NAP_SZ 1u +#define TBTT_INFO_HDR_TI_CNT_POS 4u /* TBTT Information Count */ +#define TBTT_INFO_HDR_TI_CNT_SZ 4u +#define TBTT_INFO_HDR_TI_LEN_POS 8u /* TBTT Information Length */ +#define TBTT_INFO_HDR_TI_LEN_SZ 8u + /* BSS Params Macros */ #define RNR_BSS_PARAMS_OCT_REC_MASK (0x01u) #define RNR_BSS_PARAMS_SAME_SSID_MASK (0x02u) @@ -239,6 +269,18 @@ typedef BWL_PRE_PACKED_STRUCT struct fils_rnr_element { */ #define NBR_AP_TBTT_BSSID_SHORT_SSID_BSS_PSD_LEN 13U +/* NBR_AP TBTT OFFSETfield(1) + BSSID(6)+SHORTSSID (4)+ + * BSS(1) + MLD (3) = 15 BYTES + */ +/* Draft P802.11be Table 9-281 */ +#define NBR_AP_TBTT_BSSID_SHORT_SSID_BSS_MLD_LEN 15U + +/* NBR_AP TBTT OFFSETfield(1) + BSSID(6) + + * SHORTSSID (4)+BSS(1) + 20Mhz PSD(1) + MLD (3) = 16 BYTES + */ +/* Draft P802.11be Table 9-281 */ +#define NBR_AP_TBTT_BSSID_SHORT_SSID_BSS_PSD_MLD_LEN 16U + /* FILS Nonce element */ #define FILS_NONCE_LENGTH 16u diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/frag.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/frag.h new file mode 100644 index 000000000000..f2f8abda89ec --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/frag.h @@ -0,0 +1,46 @@ +/* + * IE/TLV (de)fragmentation declarations/definitions for + * Broadcom 802.11abgn Networking Device Driver + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + * + */ + +#ifndef __FRAG_H__ +#define __FRAG_H__ + +int bcm_tlv_dot11_defrag(const void *buf, uint buf_len, uint8 id, bool id_ext, + uint8 *out, uint *out_len, uint *data_len); + +int bcm_tlv_dot11_frag_tot_len(const void *buf, uint buf_len, + uint8 id, bool id_ext, uint *ie_len); +int bcm_tlv_dot11_frag_tot_data_len(const void *buf, uint buf_len, + uint8 id, bool id_ext, uint *ie_len, uint *data_len); + +/* To support IE fragmentation. + * data will be fit into a series of elements consisting of one leading element + * followed by Fragment elements if needed. + * data_len is in/out parameter, it has the length of all the elements, including + * the leading element header size. + * Caller can get elements length by passing dst as NULL. + */ +int bcm_tlv_dot11_frag(uint8 id, bool id_ext, const void *data, uint data_len, + uint8 *dst, uint *ie_len); +#endif /* __FRAG_H__ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/fwpkg_utils.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/fwpkg_utils.h new file mode 100644 index 000000000000..899b4fa09c19 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/fwpkg_utils.h @@ -0,0 +1,80 @@ +/* + * Firmware package defines + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _fwpkg_utils_h_ +#define _fwpkg_utils_h_ + +enum { + FWPKG_TAG_FW = 1, + FWPKG_TAG_SIG = 2, + FWPKG_TAG_INFO = 3, + FWPKG_TAG_LAST +}; +#define NBR_OF_FWPKG_UNITS (FWPKG_TAG_LAST-1) + +/* internal firmware package header */ +typedef struct fwpkg_hdr { + uint32 options; + uint32 version; /* fw package version */ + uint32 length; /* length of data after the length field */ + uint32 magic_word0; /* hardcoded value */ + uint32 magic_word1; /* hardcoded value */ +} fwpkg_hdr_t; + +/* internal firmware package unit header */ +typedef struct fwpkg_unit +{ + uint32 offset; /* offset to the data in the file */ + uint32 size; /* the data size */ + uint32 type; +} fwpkg_unit_t; + +#define FWPKG_SINGLE_FLG 1U +#define FWPKG_COMBND_FLG 2U + +typedef struct fwpkg_info +{ + fwpkg_unit_t units[NBR_OF_FWPKG_UNITS]; + uint32 file_size; + uint8 status; + uint8 pad[3]; +} fwpkg_info_t; + +#define IS_FWPKG_SINGLE(fwpkg) \ + ((fwpkg->status == FWPKG_SINGLE_FLG) ? TRUE : FALSE) +#define IS_FWPKG_COMBND(fwpkg) \ + ((fwpkg->status == FWPKG_COMBND_FLG) ? TRUE : FALSE) + +#ifdef BCMDRIVER +#define FWPKG_FILE void +#else +#define FWPKG_FILE FILE +#endif /* BCMDRIVER */ + +int fwpkg_init(fwpkg_info_t *fwpkg, char *fname); +int fwpkg_open_firmware_img(fwpkg_info_t *fwpkg, char *fname, FWPKG_FILE **fp); +int fwpkg_open_signature_img(fwpkg_info_t *fwpkg, char *fname, FWPKG_FILE **fp); +uint32 fwpkg_get_firmware_img_size(fwpkg_info_t *fwpkg); +uint32 fwpkg_get_signature_img_size(fwpkg_info_t *fwpkg); + +#endif /* _fwpkg_utils_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_armtrap.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_armtrap.h old mode 100755 new mode 100644 index ca4185146786..370ded15ed0a --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_armtrap.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_armtrap.h @@ -1,7 +1,7 @@ /* * HND arm trap handling. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_cons.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_cons.h old mode 100755 new mode 100644 index d8ade3d2b1bf..5482c27cb0e6 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_cons.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_cons.h @@ -1,7 +1,7 @@ /* * Console support for RTE - for host use only. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -37,7 +37,7 @@ #endif /* RWL_DONGLE || UART_REFLECTOR */ #ifndef LOG_BUF_LEN -#if defined(BCMDBG) || defined (BCM_BIG_LOG) +#if defined(BCMDBG) || defined(BCM_BIG_LOG) #define LOG_BUF_LEN (16 * 1024) #elif defined(ATE_BUILD) #define LOG_BUF_LEN (2 * 1024) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_debug.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_debug.h old mode 100755 new mode 100644 index c7ffe2a57051..141fc31654da --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_debug.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_debug.h @@ -1,7 +1,7 @@ /* * HND Run Time Environment debug info area * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -48,9 +48,11 @@ extern uint32 gFWID; #endif enum hnd_debug_reloc_entry_type { - HND_DEBUG_RELOC_ENTRY_TYPE_ROM = 0u, - HND_DEBUG_RELOC_ENTRY_TYPE_RAM = 1u, - HND_DEBUG_RELOC_ENTRY_TYPE_MTH_STACK = 2u, /* main thread stack */ + HND_DEBUG_RELOC_ENTRY_TYPE_ROM = 0u, + HND_DEBUG_RELOC_ENTRY_TYPE_RAM = 1u, + HND_DEBUG_RELOC_ENTRY_TYPE_MTH_STACK = 2u, /* main thread stack */ + HND_DEBUG_RELOC_ENTRY_TYPE_MTH_STACK_OVFL = 3u, /* main thread stack overflow */ + RELOC_NUM_ENTRIES }; typedef uint32 hnd_debug_reloc_entry_type_t; @@ -86,9 +88,6 @@ typedef struct hnd_debug_reloc { uint32 hnd_reloc_ptr_size; /* Specifies the size of the MMU reloc table */ } hnd_debug_reloc_t; -/* Number of MMU relocation entries supported in v2 */ -#define RELOC_NUM_ENTRIES 4u - /* Total MMU relocation table size for v2 */ #define HND_DEBUG_RELOC_PTR_SIZE (RELOC_NUM_ENTRIES * sizeof(hnd_debug_reloc_entry_t)) @@ -134,7 +133,7 @@ typedef struct hnd_debug { #else /* Note: The original uint32 version is split into two fields: * uint16 version and uint16 length to accomidate future expansion - * of the strucutre. + * of the structure. * * The length field is not populated for the version 1 of the structure. */ @@ -231,6 +230,8 @@ typedef struct prstatus { #define DUMP_INFO_PTR_PTR_3 0xf8 #define DUMP_INFO_PTR_PTR_4 0x874 #define DUMP_INFO_PTR_PTR_5 0x878 +#define DUMP_INFO_PTR_PTR_6 0x4f0 +#define DUMP_INFO_PTR_PTR_7 0x4f8 #define DUMP_INFO_PTR_PTR_END 0xffffffff #define DUMP_INFO_PTR_PTR_LIST DUMP_INFO_PTR_PTR_0, \ DUMP_INFO_PTR_PTR_1, \ @@ -238,6 +239,8 @@ typedef struct prstatus { DUMP_INFO_PTR_PTR_3, \ DUMP_INFO_PTR_PTR_4, \ DUMP_INFO_PTR_PTR_5, \ + DUMP_INFO_PTR_PTR_6, \ + DUMP_INFO_PTR_PTR_7, \ DUMP_INFO_PTR_PTR_END extern bool hnd_debug_info_in_trap_context(void); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_pktpool.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_pktpool.h old mode 100755 new mode 100644 index ce241e802b2c..dcaeb648b9c4 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_pktpool.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_pktpool.h @@ -1,7 +1,7 @@ /* * HND generic packet pool operation primitives * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -42,7 +42,7 @@ extern "C" { #ifdef BCMPKTPOOL #define POOL_ENAB(pool) ((pool) && (pool)->inited) #else /* BCMPKTPOOL */ -#define POOL_ENAB(bus) 0 +#define POOL_ENAB(bus) (FALSE) #endif /* BCMPKTPOOL */ #ifndef PKTPOOL_LEN_MAX @@ -59,6 +59,13 @@ extern "C" { #define FREE_ALL_PKTS 0 #define FREE_ALL_FRAG_PKTS 1 +/* PKTPOOL_ALLOC ISSUES */ +#define PKT_ALLOC_SUCCESS 0 +#define PKT_ALLOC_FAIL_GENERIC -1 +#define PKT_ALLOC_FAIL_NOPKT -2 +#define PKT_ALLOC_FAIL_NOCMPLID -3 +#define PKT_ALLOC_FAIL_NOHOSTADDR -4 + /* forward declaration */ struct pktpool; @@ -69,6 +76,12 @@ typedef struct { uint8 refcnt; } pktpool_cbinfo_t; +typedef void (*pktpool_rxurb_cb_t)(struct pktpool *pool, void *arg, uint8 *addr, uint16 len); +typedef struct { + pktpool_rxurb_cb_t cb; + void *arg; +} pktpool_rxurb_cbinfo_t; + /** PCIe SPLITRX related: call back fn extension to populate host address in pool pkt */ typedef int (*pktpool_cb_extn_t)(struct pktpool *pool, void *arg1, void* pkt, int arg2, uint *pktcnt); @@ -123,6 +136,8 @@ typedef struct pktpool { uint8 cbcnt; uint8 ecbcnt; uint8 emptycb_disable; /**< Value of type enum pktpool_empty_cb_state */ + uint8 metasz; /**< size of tx or rx metadata allocated after lbuf struct */ + uint16 metaoff; /**< offset of tx or rx metadata allocated after lbuf struct */ pktpool_cbinfo_t *availcb_excl; pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX_AVL]; pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX]; @@ -136,6 +151,15 @@ typedef struct pktpool { bool is_heap_pool; /* Whether this pool can be used as heap */ bool release_active; uint8 mem_handle; + + struct resv_info *resv_info; /* Resv frag pool info */ + uint resv_pool_idx; + pktpool_cbextn_info_t cb_haddr; /**< PCIe SPLITRX related */ + pktpool_rxurb_cbinfo_t dmarxurb; /**< dma rx urb related */ + + uint32 pktpool_flags; /* different packet pool flags */ + void *freelist_tail; /* free list tail, used only in specific rxlfrag pools */ + #ifdef BCMDBG_POOL uint8 dbg_cbcnt; pktpool_cbinfo_t dbg_cbs[PKTPOOL_CB_MAX]; @@ -144,6 +168,14 @@ typedef struct pktpool { #endif } pktpool_t; +/* Flags to indicate the packet pool status. + * PKTPOOL_RXLFRAG_SORTED_INSERT: Ordered list of rxfrag packets. + * PKTPOOL_POOL_ZERO: Allow reset of private packet pool memory + * and verify prior usage + */ +#define PKTPOOL_RXLFRAG_SORTED_INSERT 0x00000001u +#define PKTPOOL_POOL_ZERO 0x00000002u + pktpool_t *get_pktpools_registry(int id); #define pktpool_get(pktp) (pktpool_get_ext((pktp), (pktp)->type, NULL)) @@ -172,9 +204,11 @@ extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 max_pkts extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); extern bool pktpool_emptycb_disabled(pktpool_t *pktp); extern int pktpool_hostaddr_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg1); +extern int pktpool_hostaddr_ext_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg1); extern int pktpool_rxcplid_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg); extern void pktpool_invoke_dmarxfill(pktpool_t *pktp); extern int pkpool_haddr_avail_register_cb(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pkpool_rxurb_register_cb(pktpool_t *pktp, pktpool_rxurb_cb_t cb, void *arg); extern int pktpool_avail(pktpool_t *pktpool); #define POOLPTR(pp) ((pktpool_t *)(pp)) @@ -207,12 +241,20 @@ extern int pktpool_avail(pktpool_t *pktpool); #define PKTPOOL_ID2PTR(id) (get_pktpools_registry(id)) #define PKTPOOL_PTR2ID(pp) (POOLID(pp)) +/* Registry size is one larger than max pools, as slot #0 is reserved */ +#define PKTPOOLREG_RSVD_ID (0U) +#define PKTPOOLREG_RSVD_PTR (POOLPTR(0xdeaddead)) +#define PKTPOOLREG_FREE_PTR (POOLPTR(NULL)) + #ifndef PKTID_POOL /* max pktids reserved for pktpool is updated properly in Makeconf */ #define PKTID_POOL (PKT_MAXIMUM_ID - 32u) #endif /* PKTID_POOL */ extern uint32 total_pool_pktid_count; +extern int pktpool_get_last_err(pktpool_t *pktp); +#define PKTPOOL_ERR_TYPE_SPLIT_SUPPORTED + #ifdef BCMDBG_POOL extern int pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); extern int pktpool_start_trigger(pktpool_t *pktp, void *p); @@ -227,18 +269,16 @@ extern pktpool_t *pktpool_shared; #ifdef BCMFRAGPOOL #define SHARED_FRAG_POOL (pktpool_shared_lfrag) extern pktpool_t *pktpool_shared_lfrag; -#endif - -#ifdef BCMALFRAGPOOL #define SHARED_ALFRAG_POOL (pktpool_shared_alfrag) extern pktpool_t *pktpool_shared_alfrag; - #define SHARED_ALFRAG_DATA_POOL (pktpool_shared_alfrag_data) extern pktpool_t *pktpool_shared_alfrag_data; -#endif +#endif /* BCMFRAGPOOL */ #ifdef BCMRESVFRAGPOOL -#define RESV_FRAG_POOL (pktpool_resv_lfrag) +#define RESV_FRAG_POOL (NULL) +#define RESV_ALFRAG_POOL (pktpool_resv_alfrag) +#define RESV_ALFRAG_DATA_POOL (pktpool_resv_alfrag_data) #define RESV_POOL_INFO (resv_pool_info) #else #define RESV_FRAG_POOL ((struct pktpool *)NULL) @@ -258,7 +298,8 @@ int hnd_pktpool_fill(pktpool_t *pktpool, bool minimal); void hnd_pktpool_refill(bool minimal); #ifdef BCMRESVFRAGPOOL -extern pktpool_t *pktpool_resv_lfrag; +extern pktpool_t *pktpool_resv_alfrag; +extern pktpool_t *pktpool_resv_alfrag_data; extern struct resv_info *resv_pool_info; #endif /* BCMRESVFRAGPOOL */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_pktq.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_pktq.h old mode 100755 new mode 100644 index 375ebd871e2d..cea32415c030 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_pktq.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_pktq.h @@ -1,7 +1,7 @@ /* * HND generic pktq operation primitives * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -292,7 +292,7 @@ extern bool spktq_full(struct spktq *spq); #define spktqfilter(spq, fltr, fltr_ctx, defer, defer_ctx, flush, flush_ctx) \ spktq_filter((spq), (fltr), (fltr_ctx), (defer), (defer_ctx), (flush), (flush_ctx)) -extern bool pktq_init(struct pktq *pq, int num_prec, uint max_pkts); +extern bool pktq_init(struct pktq *pq, uint num_prec, uint max_pkts); extern bool pktq_deinit(struct pktq *pq); extern bool spktq_init(struct spktq *spq, uint max_pkts); extern bool spktq_init_list(struct spktq *spq, uint max_pkts, @@ -319,9 +319,14 @@ extern void spktq_flush_ext(osl_t *osh, struct spktq *spq, bool dir, extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir); typedef void (*spktq_cb_t)(void *arg, struct spktq *spq); +typedef uint32 (*spktq_suppress_cb_t)(void *arg, struct spktq *spq); extern void spktq_free_register(spktq_cb_t cb, void *arg); extern void spktq_cb(void *spq); +uint32 spktq_suppress_cb(void *spq); +void spktq_suppress_register(spktq_suppress_cb_t cb, void *arg); +void *(spktq_delete_node)(struct spktq *spq, void *prev, void *cur); #define SPKTQFREE spktq_cb +#define SPKTQFREE_SUPPRESS spktq_suppress_cb #ifdef __cplusplus } diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_trap.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_trap.h old mode 100755 new mode 100644 index eded5da4ddf6..47d6e8515702 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_trap.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnd_trap.h @@ -1,7 +1,7 @@ /* * HND Trap handling. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndchipc.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndchipc.h old mode 100755 new mode 100644 index 26e53b3d602d..38664c9d9e37 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndchipc.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndchipc.h @@ -1,7 +1,7 @@ /* * HND SiliconBackplane chipcommon support - OS independent. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndd11.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndd11.h deleted file mode 100755 index bd6f1da188ca..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndd11.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Generic functions for d11 access - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ - -#ifndef _hndd11_h_ -#define _hndd11_h_ - -#include -#include -#include -#include -#include - -/* This marks the start of a packed structure section. */ -#include - -#ifndef WL_RSSI_ANT_MAX -#define WL_RSSI_ANT_MAX 4 /**< max possible rx antennas */ -#elif WL_RSSI_ANT_MAX != 4 -#error "WL_RSSI_ANT_MAX does not match" -#endif - -BWL_PRE_PACKED_STRUCT struct wl_d11rxrssi { - int8 dBm; /* number of full dBms */ - /* sub-dbm resolution */ - int8 decidBm; /* sub dBms : value after the decimal point */ -} BWL_POST_PACKED_STRUCT; - -typedef struct wl_d11rxrssi wlc_d11rxrssi_t; - -BWL_PRE_PACKED_STRUCT struct wlc_d11rxhdr { - /* SW header */ - uint32 tsf_l; /**< TSF_L reading */ - int8 rssi; /**< computed instantaneous rssi */ - int8 rssi_qdb; /**< qdB portion of the computed rssi */ - int16 snr; /**< computed snginal-to-noise instantaneous snr */ - int8 rxpwr[ROUNDUP(WL_RSSI_ANT_MAX,2)]; /**< rssi for supported antennas */ - /** - * Even though rxhdr can be in short or long format, always declare it here - * to be in long format. So the offsets for the other fields are always the same. - */ - d11rxhdr_t rxhdr; -} BWL_POST_PACKED_STRUCT; - -/* SW RXHDR + HW RXHDR */ -typedef struct wlc_d11rxhdr wlc_d11rxhdr_t; - -/* extension of wlc_d11rxhdr.. - * This extra block can be used to store extra internal information that cannot fit into - * wlc_d11rxhdr. - * At the moment, it is only used to store and possibly transmit the per-core quater dbm rssi - * information produced by the phy. - * NOTE: To avoid header overhead and amsdu handling complexities this usage is limited to - * only in case that host need to get the extra info. e.g., monitoring mode packet. - */ - -BWL_PRE_PACKED_STRUCT struct wlc_d11rxhdr_ext { -#ifdef BCM_MON_QDBM_RSSI - wlc_d11rxrssi_t rxpwr[WL_RSSI_ANT_MAX]; -#endif - wlc_d11rxhdr_t wlc_d11rx; -} BWL_POST_PACKED_STRUCT; - -typedef struct wlc_d11rxhdr_ext wlc_d11rxhdr_ext_t; - -/* Length of software rx header extension */ -#define WLC_SWRXHDR_EXT_LEN (OFFSETOF(wlc_d11rxhdr_ext_t, wlc_d11rx)) - -/* Length of SW header (12 bytes) */ -#define WLC_RXHDR_LEN (OFFSETOF(wlc_d11rxhdr_t, rxhdr)) -/* Length of RX headers - SW header + HW/ucode/PHY RX status */ -#define WL_RXHDR_LEN(corerev, corerev_minor) \ - (WLC_RXHDR_LEN + D11_RXHDR_LEN(corerev, corerev_minor)) -#define WL_RXHDR_LEN_TMP(corerev, corerev_minor) \ - (WLC_RXHDR_LEN + D11_RXHDR_LEN_TMP(corerev, corerev_minor)) - -/* This marks the end of a packed structure section. */ -#include - -/* Structure to hold d11 corerev information */ -typedef struct d11_info d11_info_t; -struct d11_info { - uint major_revid; - uint minor_revid; -}; - -/* ulp dbg macro */ -#define HNDD11_DBG(x) -#define HNDD11_ERR(x) printf x - -/* d11 slice index */ -#define DUALMAC_MAIN 0 -#define DUALMAC_AUX 1 -#define DUALMAC_SCAN 2 - -extern void hndd11_read_shm(si_t *sih, uint coreunit, uint offset, void* buf); -extern void hndd11_write_shm(si_t *sih, uint coreunit, uint offset, const void* buf); - -extern void hndd11_copyfrom_shm(si_t *sih, uint coreunit, uint offset, void* buf, int len); -extern void hndd11_copyto_shm(si_t *sih, uint coreunit, uint offset, const void* buf, int len); - -extern uint32 hndd11_bm_read(osl_t *osh, d11regs_info_t *regsinfo, uint32 offset, uint32 len, - uint32 *buf); -extern uint32 hndd11_bm_write(osl_t *osh, d11regs_info_t *regsinfo, uint32 offset, uint32 len, - const uint32 *buf); -extern void hndd11_bm_dump(osl_t *osh, d11regs_info_t *regsinfo, uint32 offset, uint32 len); - -extern int hndd11_get_reginfo(si_t *sih, d11regs_info_t *regsinfo, uint coreunit); - -#endif /* _hndd11_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnddma.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnddma.h deleted file mode 100755 index bbc84554a9e5..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hnddma.h +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Generic Broadcom Home Networking Division (HND) DMA engine SW interface - * This supports the following chips: BCM42xx, 44xx, 47xx . - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -#ifndef _hnddma_h_ -#define _hnddma_h_ - -#include -#include -#include -#include -#include -#include - -#ifndef _hnddma_pub_ -#define _hnddma_pub_ -typedef const struct hnddma_pub hnddma_t; -#endif /* _hnddma_pub_ */ - -/* range param for dma_getnexttxp() and dma_txreclaim */ -typedef enum txd_range { - HNDDMA_RANGE_ALL = 1, - HNDDMA_RANGE_TRANSMITTED, - HNDDMA_RANGE_TRANSFERED -} txd_range_t; - -/* dma parameters id */ -enum dma_param_id { - HNDDMA_PID_TX_MULTI_OUTSTD_RD = 0, - HNDDMA_PID_TX_PREFETCH_CTL, - HNDDMA_PID_TX_PREFETCH_THRESH, - HNDDMA_PID_TX_BURSTLEN, - HNDDMA_PID_TX_CHAN_SWITCH, - - HNDDMA_PID_RX_PREFETCH_CTL = 0x100, - HNDDMA_PID_RX_PREFETCH_THRESH, - HNDDMA_PID_RX_BURSTLEN, - HNDDMA_PID_BURSTLEN_CAP, - HNDDMA_PID_BURSTLEN_WAR, - HNDDMA_SEP_RX_HDR, /**< SPLITRX related */ - HNDDMA_SPLIT_FIFO, - HNDDMA_PID_D11RX_WAR, - HNDDMA_PID_RX_WAIT_CMPL, - HNDDMA_NRXPOST, - HNDDMA_NRXBUFSZ, - HNDDMA_PID_RXCTL_MOW, - HNDDMA_M2M_RXBUF_RAW /* rx buffers are raw buffers, not lbufs/lfrags */ -}; - -#define SPLIT_FIFO_0 1 -#define SPLIT_FIFO_1 2 - -typedef void (*setup_context_t)(void *ctx, void *p, uint8 **desc0, uint16 *len0, - uint8 **desc1, uint16 *len1); - -/** - * Exported data structure (read-only) - */ -/* export structure */ -struct hnddma_pub { - uint dmastflags; /* dma status flags */ - uint dmactrlflags; /**< dma control flags */ - - /* rx error counters */ - uint rxgiants; /**< rx giant frames */ - uint rxnobuf; /**< rx out of dma descriptors */ - /* tx error counters */ - uint txnobuf; /**< tx out of dma descriptors */ - uint txnodesc; /**< tx out of dma descriptors running count */ -}; - -/* DMA status flags */ -#define BCM_DMA_STF_RX (1u << 0u) /* the channel is RX DMA */ - -typedef struct dma_common dma_common_t; -typedef struct dma_dd_pool dma_dd_pool_t; - -/* Flags for dma_attach_ext function */ -#define BCM_DMA_IND_INTF_FLAG 0x00000001 /* set for using INDIRECT DMA INTERFACE */ -#define BCM_DMA_DESC_ONLY_FLAG 0x00000002 /* For DMA that posts descriptors only and - * no packets - */ -#define BCM_DMA_CHAN_SWITCH_EN 0x00000008 /* for d11 corerev 64+ to help arbitrate - * btw dma channels. - */ -#define BCM_DMA_ROEXT_SUPPORT 0x00000010 /* for d11 corerev 128+ to support receive - * frame offset >=128B and <= 255B - */ -#define BCM_DMA_RX_ALIGN_8BYTE 0x00000020 /* RXDMA address 8-byte aligned */ -#define BCM_DMA_DESC_SHARED_POOL 0x00000100 /* For TX DMA that uses shared desc pool */ -#define BCM_DMA_RXP_LIST 0x00000200 /* linked list for RXP instead of array */ - -typedef int (*rxpkt_error_check_t)(const void* ctx, void* pkt); - -extern dma_common_t * dma_common_attach(osl_t *osh, volatile uint32 *indqsel, - volatile uint32 *suspreq, volatile uint32 *flushreq, rxpkt_error_check_t cb, void *ctx); -extern void dma_common_detach(dma_common_t *dmacommon); -extern void dma_common_set_ddpool_ctx(dma_common_t *dmacommon, void *desc_pool); -extern void * dma_common_get_ddpool_ctx(dma_common_t *dmacommon, void **va); -extern bool dma_check_last_desc(hnddma_t *dmah); -extern void dma_txfrwd(hnddma_t *dmah); - -#ifdef BCM_DMA_INDIRECT -/* Use indirect registers for non-ctmode */ -#define DMA_INDQSEL_IA (1 << 31) -extern void dma_set_indqsel(hnddma_t *di, bool force); -extern bool dma_is_indirect(hnddma_t *dmah); -#else -#define dma_set_indqsel(a, b) -#define dma_is_indirect(a) FALSE -#endif /* #ifdef BCM_DMA_INDIRECT */ - -extern hnddma_t * dma_attach_ext(dma_common_t *dmac, osl_t *osh, const char *name, si_t *sih, - volatile void *dmaregstx, volatile void *dmaregsrx, uint32 flags, uint8 qnum, - uint ntxd, uint nrxd, uint rxbufsize, int rxextheadroom, uint nrxpost, uint rxoffset, - uint *msg_level, uint coreunit); - -extern hnddma_t * dma_attach(osl_t *osh, const char *name, si_t *sih, - volatile void *dmaregstx, volatile void *dmaregsrx, - uint ntxd, uint nrxd, uint rxbufsize, int rxextheadroom, uint nrxpost, - uint rxoffset, uint *msg_level); - -void dma_rx_desc_init(hnddma_t *dmah, uint rxfifo); -void dma_detach(hnddma_t *dmah); -bool dma_txreset(hnddma_t *dmah); -bool dma_rxreset(hnddma_t *dmah); -bool dma_rxidle(hnddma_t *dmah); -void dma_txinit(hnddma_t *dmah); -bool dma_txenabled(hnddma_t *dmah); -void dma_rxinit(hnddma_t *dmah); -void dma_txsuspend(hnddma_t *dmah); -void dma_txresume(hnddma_t *dmah); -bool dma_txsuspended(hnddma_t *dmah); -bool dma_txsuspendedidle(hnddma_t *dmah); -void dma_txflush(hnddma_t *dmah); -void dma_txflush_clear(hnddma_t *dmah); -int dma_txfast_ext(hnddma_t *dmah, void *p0, bool commit, uint16 *pre_txout, uint16 *numd); -int dma_txfast_alfrag(hnddma_t *dmah, hnddma_t *aqm_dmah, void *p, bool commit, dma64dd_t *aqmdesc, - uint d11_txh_len, bool ptxd_hw_enab); -#define dma_txfast(dmah, p0, commit) \ - dma_txfast_ext((dmah), (p0), (commit), NULL, NULL) -void dma_txcommit(hnddma_t *dmah); -int dma_txunframed(hnddma_t *dmah, void *buf, uint len, bool commit); -void *dma_getpos(hnddma_t *dmah, bool direction); -void dma_fifoloopbackenable(hnddma_t *dmah); -void dma_fifoloopbackdisable(hnddma_t *dmah); -bool dma_txstopped(hnddma_t *dmah); -bool dma_rxstopped(hnddma_t *dmah); -void dma_rxenable(hnddma_t *dmah); -bool dma_rxenabled(hnddma_t *dmah); -void *dma_rx(hnddma_t *dmah); -#ifdef APP_RX -void dma_getnextrxp_app(hnddma_t *dmah, bool forceall, uint *pktcnt, - void **head, void **tail); -void dma_rxfill_haddr_getparams(hnddma_t *dmah, uint *nrxd, uint16 *rxout, - dma64dd_t **ddring, uint *rxextrahdrroom, uint32 **rxpktid); -void dma_rxfill_haddr_setparams(hnddma_t *dmah, uint16 rxout); -#endif /* APP_RX */ -uint dma_rx_get_rxoffset(hnddma_t *dmah); -bool dma_rxfill(hnddma_t *dmah); -bool dma_rxfill_required(hnddma_t *dmah); -void dma_txreclaim(hnddma_t *dmah, txd_range_t range); -void dma_rxreclaim(hnddma_t *dmah); -#define _DMA_GETUINTVARPTR_ -uint *dma_getuintvarptr(hnddma_t *dmah, const char *name); -uint8 dma_getuint8var(hnddma_t *dmah, const char *name); -uint16 dma_getuint16var(hnddma_t *dmah, const char *name); -uint32 dma_getuint32var(hnddma_t *dmah, const char *name); -void * dma_getnexttxp(hnddma_t *dmah, txd_range_t range); -void * dma_getnextp(hnddma_t *dmah); -void * dma_getnextrxp(hnddma_t *dmah, bool forceall); -void * dma_peeknexttxp(hnddma_t *dmah, txd_range_t range); -int dma_peekntxp(hnddma_t *dmah, int *len, void *txps[], txd_range_t range); -void * dma_peeknextrxp(hnddma_t *dmah); -void dma_rxparam_get(hnddma_t *dmah, uint16 *rxoffset, uint16 *rxbufsize); -bool dma_is_rxfill_suspend(hnddma_t *dmah); -void dma_txblock(hnddma_t *dmah); -void dma_txunblock(hnddma_t *dmah); -uint dma_txactive(hnddma_t *dmah); -uint dma_rxactive(hnddma_t *dmah); -void dma_txrotate(hnddma_t *dmah); -void dma_counterreset(hnddma_t *dmah); -uint dma_ctrlflags(hnddma_t *dmah, uint mask, uint flags); -uint dma_txpending(hnddma_t *dmah); -uint dma_txcommitted(hnddma_t *dmah); -int dma_pktpool_set(hnddma_t *dmah, pktpool_t *pool); -int dma_rxdatapool_set(hnddma_t *dmah, pktpool_t *pktpool); -pktpool_t *dma_rxdatapool_get(hnddma_t *dmah); - -void dma_dump_txdmaregs(hnddma_t *dmah, uint32 **buf); -void dma_dump_rxdmaregs(hnddma_t *dmah, uint32 **buf); -#if defined(BCMDBG) || defined(BCMDBG_DUMP) || defined(BCMDBG_DMA) -void dma_dump(hnddma_t *dmah, struct bcmstrbuf *b, bool dumpring); -void dma_dumptx(hnddma_t *dmah, struct bcmstrbuf *b, bool dumpring); -void dma_dumprx(hnddma_t *dmah, struct bcmstrbuf *b, bool dumpring); -#endif -bool dma_rxtxerror(hnddma_t *dmah, bool istx); -void dma_burstlen_set(hnddma_t *dmah, uint8 rxburstlen, uint8 txburstlen); -uint dma_avoidance_cnt(hnddma_t *dmah); -void dma_param_set(hnddma_t *dmah, uint16 paramid, uint16 paramval); -void dma_param_get(hnddma_t *dmah, uint16 paramid, uint *paramval); -void dma_context(hnddma_t *dmah, setup_context_t fn, void *ctx); - -bool dma_glom_enable(hnddma_t *dmah, uint32 val); -uint dma_activerxbuf(hnddma_t *dmah); -bool dma_rxidlestatus(hnddma_t *dmah); -uint dma_get_rxpost(hnddma_t *dmah); - -/* return addresswidth allowed - * This needs to be done after SB attach but before dma attach. - * SB attach provides ability to probe backplane and dma core capabilities - * This info is needed by DMA_ALLOC_CONSISTENT in dma attach - */ -extern uint dma_addrwidth(si_t *sih, void *dmaregs); - -/* count the number of tx packets that are queued to the dma ring */ -extern uint dma_txp(hnddma_t *di); - -extern void dma_txrewind(hnddma_t *di); - -/* pio helpers */ -extern int dma_msgbuf_txfast(hnddma_t *di, dma64addr_t p0, bool com, uint32 ln, bool fst, bool lst); -extern int dma_ptrbuf_txfast(hnddma_t *dmah, dma64addr_t p0, void *p, bool commit, - uint32 len, bool first, bool last); - -extern int dma_rxfast(hnddma_t *di, dma64addr_t p, uint32 len); -extern int dma_rxfill_suspend(hnddma_t *dmah, bool suspended); -extern void dma_link_handle(hnddma_t *dmah1, hnddma_t *dmah2); -extern void dma_unlink_handle(hnddma_t *dmah1, hnddma_t *dmah2); -extern int dma_rxfill_unframed(hnddma_t *di, void *buf, uint len, bool commit); - -extern uint16 dma_get_next_txd_idx(hnddma_t *di, bool txout); -extern uint16 dma_get_txd_count(hnddma_t *dmah, uint16 start, bool txout); -extern uintptr dma_get_txd_addr(hnddma_t *di, uint16 idx); - -/* returns the memory address (hi and low) of the buffer associated with the dma descriptor - * having index idx. - */ -extern void dma_get_txd_memaddr(hnddma_t *dmah, uint32 *addrlo, uint32 *addrhi, uint idx); - -extern int dma_txdesc(hnddma_t *dmah, dma64dd_t *dd, bool commit); -extern int dma_nexttxdd(hnddma_t *dmah, txd_range_t range, uint32 *flags1, uint32 *flags2, - bool advance); - -extern void dma_update_rxfill(hnddma_t *dmah); -extern void dma_rxchan_reset(hnddma_t *di); -extern void dma_txchan_reset(hnddma_t *di); -extern void dma_chan_reset(hnddma_t *dmah); -extern pktpool_t* dma_pktpool_get(hnddma_t *dmah); -extern void dma_clearrxp(hnddma_t *dmah); -extern void dma_cleartxp(hnddma_t *dmah); - -#define dma_getnexttxdd(dmah, range, flags1, flags2) \ - dma_nexttxdd((dmah), (range), (flags1), (flags2), TRUE) - -#define dma_peeknexttxdd(dmah, range, flags1, flags2) \ - dma_nexttxdd((dmah), (range), (flags1), (flags2), FALSE) - -#define NUM_VEC_PCIE 4 - -#define XFER_FROM_LBUF 0x1 -#define XFER_TO_LBUF 0x2 -#define XFER_INJ_ERR 0x4 - -typedef struct m2m_vec_s { - dma64addr_t addr; - uint32 len; -} m2m_vec_t; - -typedef struct m2m_desc_s { - uint8 num_rx_vec; - uint8 num_tx_vec; - uint8 flags; - bool commit; - m2m_vec_t vec[]; -} m2m_desc_t; - -#define INIT_M2M_DESC(desc) \ -{\ - desc->num_rx_vec = 0; \ - desc->num_tx_vec = 0; \ - desc->flags = 0; \ - desc->commit = TRUE; \ -} - -#define SETUP_RX_DESC(desc, rxaddr, rxlen) \ -{\ - ASSERT(desc->num_tx_vec == 0); \ - desc->vec[desc->num_rx_vec].addr = rxaddr; \ - desc->vec[desc->num_rx_vec].len = rxlen; \ - desc->num_rx_vec++; \ -} - -#define SETUP_TX_DESC(desc, txaddr, txlen) \ -{\ - desc->vec[desc->num_tx_vec + desc->num_rx_vec].addr = txaddr; \ - desc->vec[desc->num_tx_vec + desc->num_rx_vec].len = txlen; \ - desc->num_tx_vec++; \ -} - -#define SETUP_XFER_FLAGS(desc, flag) \ -{\ - desc->flags |= flag; \ -} - -#define DD_IS_SHARED_POOL(di) ((di)->dmactrlflags & DMA_CTRL_SHARED_POOL) - -extern int dma_m2m_submit(hnddma_t *dmah, m2m_desc_t *desc, bool implicit); -extern void dma_chan_enable(hnddma_t *dmah, bool enable); - -extern bool dma_rxfill_p(hnddma_t *dmah, void *p); -extern void dma_aqm_di_link(hnddma_t *dmah_aqm, hnddma_t *dmah_hw); -extern void dma_dump_aqminfo(hnddma_t * dmah, struct bcmstrbuf *b, uint16 fifonum); - -/* To dump ntxd and nrxd from the DMA ring */ -void dma_dump_info(hnddma_t *dmah, uint16 fifonum, struct bcmstrbuf *b); - -#endif /* _hnddma_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndlhl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndlhl.h old mode 100755 new mode 100644 index e2068a3e5341..558aee07ce8c --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndlhl.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndlhl.h @@ -1,7 +1,7 @@ /* * HND SiliconBackplane PMU support. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -55,13 +55,13 @@ extern void si_set_lv_sleep_mode_lhl_config_4389(si_t *sih); #define HIB_EXT_WAKEUP_CAP(sih) (PMUREV(sih->pmurev) >= 33) -#ifdef WL_FWSIGN +#ifdef BCM_BOOTLOADER #define LHL_IS_PSMODE_0(sih) (1) #define LHL_IS_PSMODE_1(sih) (0) #else #define LHL_IS_PSMODE_0(sih) (si_lhl_ps_mode(sih) == LHL_PS_MODE_0) #define LHL_IS_PSMODE_1(sih) (si_lhl_ps_mode(sih) == LHL_PS_MODE_1) -#endif /* WL_FWSIGN */ +#endif /* BCM_BOOTLOADER */ /* LHL revid in capabilities register */ #define LHL_CAP_REV_MASK 0x000000ff diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndmem.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndmem.h deleted file mode 100755 index b77b7519f02f..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndmem.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Utility routines for configuring different memories in Broadcom chips. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -#ifndef _HNDMEM_H_ -#define _HNDMEM_H_ - -typedef enum { - MEM_SOCRAM = 0, - MEM_BM = 1, - MEM_UCM = 2, - MEM_SHM = 3, - MEM_MAX = 4 -} hndmem_type_t; - -/* PDA (Power Down Array) configuration */ -typedef enum { - PDA_CONFIG_CLEAR = 0, /* Clear PDA, i.e. Turns on the memory bank */ - PDA_CONFIG_SET_FULL = 1, /* Set PDA, i.e. Truns off the memory bank */ - PDA_CONFIG_SET_PARTIAL = 2, /* Set PDA, i.e. Truns off the memory bank */ - PDA_CONFIG_MAX = 3 -} hndmem_config_t; - -/* Returns the number of banks in a given memory */ -extern int hndmem_num_banks(si_t *sih, int mem); - -/* Returns the size of a give bank in a given memory */ -extern int hndmem_bank_size(si_t *sih, hndmem_type_t mem, int bank_num); - -/* Returns the start address of given memory */ -extern uint32 hndmem_mem_base(si_t *sih, hndmem_type_t mem); - -#ifdef BCMDEBUG -/* Dumps the complete memory information */ -extern void hndmem_dump_meminfo_all(si_t *sih); -#endif /* BCMDEBUG */ - -/* Configures the Sleep PDA for a particular bank for a given memory type */ -extern int hndmem_sleeppda_bank_config(si_t *sih, hndmem_type_t mem, - int bank_num, hndmem_config_t config, uint32 pda); -/* Configures the Active PDA for a particular bank for a given memory type */ -extern int hndmem_activepda_bank_config(si_t *sih, hndmem_type_t mem, - int bank_num, hndmem_config_t config, uint32 pda); - -/* Configures the Sleep PDA for all the banks for a given memory type */ -extern int hndmem_sleeppda_config(si_t *sih, hndmem_type_t mem, - hndmem_config_t config); -/* Configures the Active PDA for all the banks for a given memory type */ -extern int hndmem_activepda_config(si_t *sih, hndmem_type_t mem, - hndmem_config_t config); - -/* Turn off/on all the possible banks in a given memory range */ -extern int hndmem_activepda_mem_config(si_t *sih, hndmem_type_t mem, - uint32 mem_start, uint32 size, hndmem_config_t config); -#endif /* _HNDMEM_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndoobr.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndoobr.h old mode 100755 new mode 100644 index c27070e8d674..1fbb87421462 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndoobr.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndoobr.h @@ -1,7 +1,7 @@ /* * HND OOBR interface header * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -86,7 +86,10 @@ typedef volatile struct hndoobr_reg { uint32 capability; /* 0x00 */ uint32 reserved[3]; uint32 intstatus[4]; /* 0x10 - 0x1c */ - uint32 reserved1[56]; /* 0x20 - 0xfc */ + uint32 reserved1[4]; /* 0x20 - 0x2c */ + uint32 topintdestsel[4]; /* 0x30 - 0x3c */ + uint32 topextrsrcmap[4]; /* 0x40 - 0x4c */ + uint32 reserved2[44]; /* 0x50 - 0xfc */ hndoobr_percore_reg_t percore_reg[1]; /* 0x100 */ } hndoobr_reg_t; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndpmu.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndpmu.h old mode 100755 new mode 100644 index 63d14f9de85e..2901ba1dc708 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndpmu.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndpmu.h @@ -1,7 +1,7 @@ /* * HND SiliconBackplane PMU support. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -324,7 +324,7 @@ extern void si_pmu_reg_on_war_ext_wake_perst_set(si_t *sih); extern void si_pmu_reg_on_war_ext_wake_perst_clear(si_t *sih); #endif /* BT_WLAN_REG_ON_WAR */ -#if defined (BCMSRTOPOFF) +#if defined(BCMSRTOPOFF) extern bool _srtopoff_enab; #if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) #define BCMSRTOPOFF_ENAB() (_srtopoff_enab) @@ -345,4 +345,5 @@ extern void si_pmu_reg_on_war_ext_wake_perst_clear(si_t *sih); extern pmuregs_t *hnd_pmur; /* PMU core regs */ extern void si_pmu_res_state_wait(si_t *sih, uint rsrc); +extern void si_pmu_43711a0_pll_war(si_t *sih); #endif /* _hndpmu_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndsoc.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndsoc.h old mode 100755 new mode 100644 index 734958660c69..f2d9f59587a5 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndsoc.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/hndsoc.h @@ -1,7 +1,7 @@ /* * Broadcom HND chip & on-chip-interconnect-related definitions. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/ieee80211_radiotap.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/ieee80211_radiotap.h old mode 100755 new mode 100644 index 1f08faa8f45d..89e2021291c1 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/ieee80211_radiotap.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/ieee80211_radiotap.h @@ -32,7 +32,7 @@ */ /* - * <> + * <> */ #ifndef _NET80211_IEEE80211_RADIOTAP_H_ @@ -220,12 +220,18 @@ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_AMPDU = 20, IEEE80211_RADIOTAP_VHT = 21, IEEE80211_RADIOTAP_HE = 23, + IEEE80211_RADIOTAP_TLVS = 28, IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30, IEEE80211_RADIOTAP_EXT = 31, - + IEEE80211_RADIOTAP_USIG = 33, + IEEE80211_RADIOTAP_EHT = 34 }; +/* TLV lengths */ +#define IEEE80211_RADIOTAP_EHT_TLV_LEN 0x2C +#define IEEE80211_RADIOTAP_USIG_TLV_LEN 0xC + #ifndef _KERNEL /* channel attributes */ #define IEEE80211_CHAN_TURBO 0x00000010 /* Turbo channel */ @@ -314,13 +320,13 @@ enum ieee80211_radiotap_type { #define IEEE80211_RADIOTAP_VHT_CODING_LDPC 0x01 -#define IEEE80211_RADIOTAP_VHT_BW_20 IEEE80211_RADIOTAP_MCS_BW_20 -#define IEEE80211_RADIOTAP_VHT_BW_40 IEEE80211_RADIOTAP_MCS_BW_40 -#define IEEE80211_RADIOTAP_VHT_BW_20L IEEE80211_RADIOTAP_MCS_BW_20L -#define IEEE80211_RADIOTAP_VHT_BW_20U IEEE80211_RADIOTAP_MCS_BW_20U -#define IEEE80211_RADIOTAP_VHT_BW_80 4 -#define IEEE80211_RADIOTAP_VHT_BW_40L 5 -#define IEEE80211_RADIOTAP_VHT_BW_40U 6 +#define IEEE80211_RADIOTAP_VHT_BW_20 IEEE80211_RADIOTAP_MCS_BW_20 +#define IEEE80211_RADIOTAP_VHT_BW_40 IEEE80211_RADIOTAP_MCS_BW_40 +#define IEEE80211_RADIOTAP_VHT_BW_20L IEEE80211_RADIOTAP_MCS_BW_20L +#define IEEE80211_RADIOTAP_VHT_BW_20U IEEE80211_RADIOTAP_MCS_BW_20U +#define IEEE80211_RADIOTAP_VHT_BW_80 4 +#define IEEE80211_RADIOTAP_VHT_BW_40L 5 +#define IEEE80211_RADIOTAP_VHT_BW_40U 6 #define IEEE80211_RADIOTAP_VHT_BW_20LL 7 #define IEEE80211_RADIOTAP_VHT_BW_20LU 8 #define IEEE80211_RADIOTAP_VHT_BW_20UL 9 @@ -397,4 +403,13 @@ enum ieee80211_radiotap_type { #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020 #define IEEE80211_RADIOTAP_AMPDU_MPDU_ONLY 0x8000 +/* For IEEE80211_RADIOTAP_EHT */ +#define IEEE80211_RADIOTAP_EHT_HAVE_TXOP_PS 0x0002 +#define IEEE80211_RADIOTAP_EHT_HAVE_GI 0x0004 +#define IEEE80211_RADIOTAP_EHT_HAVE_SGI_NSYM_DA 0x0008 +#define IEEE80211_RADIOTAP_EHT_HAVE_LDPC_EXTRA 0x0010 +#define IEEE80211_RADIOTAP_EHT_HAVE_BF 0x0020 +#define IEEE80211_RADIOTAP_EHT_HAVE_BW 0x0040 +#define IEEE80211_RADIOTAP_EHT_HAVE_GID 0x0080 +#define IEEE80211_RADIOTAP_EHT_HAVE_PAID 0x0100 #endif /* !_NET80211_IEEE80211_RADIOTAP_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h old mode 100755 new mode 100644 index a0a0937bcdf2..6f7afd539414 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -25,13 +25,19 @@ #define _linux_osl_h_ #include +#include + #define DECLSPEC_ALIGN(x) __attribute__ ((aligned(x))) /* Linux Kernel: File Operations: start */ -extern void * osl_os_open_image(char * filename); -extern int osl_os_get_image_block(char * buf, int len, void * image); -extern void osl_os_close_image(void * image); -extern int osl_os_image_size(void *image); +static INLINE void * osl_os_open_image(char * filename) + { return NULL; } +static INLINE void osl_os_close_image(void * image) + { return; } +static INLINE int osl_os_get_image_block(char * buf, int len, void * image) + { return 0; } +static INLINE int osl_os_image_size(void *image) + { return 0; } /* Linux Kernel: File Operations: end */ #ifdef BCMDRIVER @@ -119,14 +125,6 @@ extern uint osl_pcie_bus(osl_t *osh); extern struct pci_dev *osl_pci_device(osl_t *osh); #endif -/* precommit failed when this is removed */ -/* BLAZAR_BRANCH_101_10_DHD_003/build/dhd/linux-fc30/brix-brcm */ -/* TBD: Revisit later */ -#if defined(BCMINTERNAL) -/* Flags that can be used to handle OSL specifcs */ -#define OSL_PHYS_MEM_LESS_THAN_16MB (1<<0L) -#endif /* BCMINTERNAL */ - #define OSL_ACP_COHERENCE (1<<1L) #define OSL_FWDERBUF (1<<2L) @@ -182,7 +180,15 @@ extern bool osl_is_flag_set(osl_t *osh, uint32 mask); ({osl_debug_mfree((osh), ((void *)addr), (size), __LINE__, __FILE__);(addr) = NULL;}) #define VMALLOC(osh, size) osl_debug_vmalloc((osh), (size), __LINE__, __FILE__) #define VMALLOCZ(osh, size) osl_debug_vmallocz((osh), (size), __LINE__, __FILE__) - #define VMFREE(osh, addr, size) osl_debug_vmfree((osh), (addr), (size), __LINE__, __FILE__) + #define VMFREE(osh, addr, size) \ + ({osl_debug_vmfree((osh), ((void *)addr), (size), __LINE__, __FILE__);(addr) = NULL;}) + /* From the linux kernel 4.12, kvmalloc introduced which tries basically to + * allocate even large blocks with kmalloc and falls back to vmalloc if fail. + */ + #define KVMALLOC(osh, size) osl_debug_kvmalloc((osh), (size), __LINE__, __FILE__) + #define KVMALLOCZ(osh, size) osl_debug_kvmallocz((osh), (size), __LINE__, __FILE__) + #define KVMFREE(osh, addr, size) \ + ({osl_debug_kvmfree((osh), ((void *)addr), (size), __LINE__, __FILE__);(addr) = NULL;}) #define MALLOCED(osh) osl_malloced((osh)) #define MEMORY_LEFTOVER(osh) osl_check_memleak(osh) #define MALLOC_DUMP(osh, b) osl_debug_memdump((osh), (b)) @@ -192,6 +198,10 @@ extern bool osl_is_flag_set(osl_t *osh, uint32 mask); extern void *osl_debug_vmalloc(osl_t *osh, uint size, int line, const char* file); extern void *osl_debug_vmallocz(osl_t *osh, uint size, int line, const char* file); extern void osl_debug_vmfree(osl_t *osh, void *addr, uint size, int line, const char* file); + extern void *osl_debug_kvmalloc(osl_t *osh, uint size, int line, const char* file); + extern void *osl_debug_kvmallocz(osl_t *osh, uint size, int line, const char* file); + extern void osl_debug_kvmfree(osl_t *osh, void *addr, uint size, int line, + const char* file); extern uint osl_malloced(osl_t *osh); struct bcmstrbuf; extern int osl_debug_memdump(osl_t *osh, struct bcmstrbuf *b); @@ -200,22 +210,43 @@ extern bool osl_is_flag_set(osl_t *osh, uint32 mask); #define MALLOC(osh, size) osl_malloc((osh), (size)) #define MALLOCZ(osh, size) osl_mallocz((osh), (size)) #define MALLOC_RA(osh, size, callsite) osl_mallocz((osh), (size)) - #define MFREE(osh, addr, size) ({osl_mfree((osh), ((void *)addr), (size));(addr) = NULL;}) + #define MFREE(osh, addr, size) \ + ({osl_mfree((osh), ((void *)addr), (size));(addr) = NULL;}) #define VMALLOC(osh, size) osl_vmalloc((osh), (size)) #define VMALLOCZ(osh, size) osl_vmallocz((osh), (size)) - #define VMFREE(osh, addr, size) osl_vmfree((osh), (addr), (size)) + #define VMFREE(osh, addr, size) \ + ({osl_vmfree((osh), ((void *)addr), (size));(addr) = NULL;}) + /* From the linux kernel 4.12, kvmalloc introduced which tries basically to + * allocate even large blocks with kmalloc and falls back to vmalloc if fail. + */ + #define KVMALLOC(osh, size) osl_kvmalloc((osh), (size)) + #define KVMALLOCZ(osh, size) osl_kvmallocz((osh), (size)) + #define KVMFREE(osh, addr, size) \ + ({osl_kvmfree((osh), ((void *)addr), (size));(addr) = NULL;}) #define MALLOCED(osh) osl_malloced((osh)) #define MEMORY_LEFTOVER(osh) osl_check_memleak(osh) - extern void *osl_malloc(osl_t *osh, uint size); - extern void *osl_mallocz(osl_t *osh, uint size); - extern void osl_mfree(osl_t *osh, void *addr, uint size); extern void *osl_vmalloc(osl_t *osh, uint size); extern void *osl_vmallocz(osl_t *osh, uint size); extern void osl_vmfree(osl_t *osh, void *addr, uint size); + extern void *osl_kvmalloc(osl_t *osh, uint size); + extern void *osl_kvmallocz(osl_t *osh, uint size); + extern void osl_kvmfree(osl_t *osh, void *addr, uint size); extern uint osl_malloced(osl_t *osh); extern uint osl_check_memleak(osl_t *osh); #endif /* BCMDBG_MEM && !BINCMP */ +#define DMA_MALLOCZ(osh, size, dmable_size, dmah) osl_dma_mallocz((osh), (size), (dmable_size)) +#define DMA_MFREE(osh, addr, size, dmah) osl_dma_mfree((osh), (addr), (size)) + +extern void *osl_malloc(osl_t *osh, uint size); +extern void *osl_mallocz(osl_t *osh, uint size); +extern void *osl_dma_mallocz(osl_t *osh, uint size, uint *dmable_size); +extern void osl_mfree(osl_t *osh, void *addr, uint size); +extern void osl_dma_mfree(osl_t *osh, void *addr, uint size); +#define MALLOC_NODBG(osh, size) osl_malloc((osh), (size)) +#define MALLOCZ_NODBG(osh, size) osl_mallocz((osh), (size)) +#define MFREE_NODBG(osh, addr, size) ({osl_mfree((osh), ((void *)addr), (size));(addr) = NULL;}) + extern int memcpy_s(void *dest, size_t destsz, const void *src, size_t n); extern int memset_s(void *dest, size_t destsz, int c, size_t n); #define MALLOC_FAILED(osh) osl_malloc_failed((osh)) @@ -238,10 +269,12 @@ extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align, uint *tot, dmaaddr_t *pap); extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa); -/* map/unmap direction */ -#define DMA_NO 0 /* Used to skip cache op */ -#define DMA_TX 1 /* TX direction for DMA */ -#define DMA_RX 2 /* RX direction for DMA */ +/* map/unmap direction, refer enum dma_data_direction */ +#include +#define DMA_RXTX DMA_BIDIRECTIONAL /* 0, Bidirectional DMA */ +#define DMA_TX DMA_TO_DEVICE /* 1, TX direction for DMA */ +#define DMA_RX DMA_FROM_DEVICE /* 2, RX direction for DMA */ +#define DMA_NO DMA_NONE /* 3, Used to skip cache op */ /* map/unmap shared (dma-able) memory */ #define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ @@ -264,7 +297,17 @@ extern void * osl_virt_to_phys(void * va); /* API for DMA addressing capability */ #define OSL_DMADDRWIDTH(osh, addrwidth) ({BCM_REFERENCE(osh); BCM_REFERENCE(addrwidth);}) -#define OSL_SMP_WMB() smp_wmb() +#define OSL_MB() mb() +#define OSL_WMB() wmb() +#define OSL_RMB() rmb() +#define OSL_SMP_WMB() smp_wmb() +#define OSL_SMP_RMB() smp_rmb() + +#if defined(__aarch64__) +#define OSL_ISB() isb() +#else +#define OSL_ISB() do { /* noop */ } while (0) +#endif /* __aarch64__ */ /* API for CPU relax */ extern void osl_cpu_relax(void); @@ -276,7 +319,6 @@ extern void osl_preempt_enable(osl_t *osh); #define OSL_ENABLE_PREEMPTION(osh) osl_preempt_enable(osh) #if (defined(BCMPCIE) && !defined(DHD_USE_COHERENT_MEM_FOR_RING) && defined(__ARM_ARCH_7A__)) - extern void osl_cache_flush(void *va, uint size); extern void osl_cache_inv(void *va, uint size); extern void osl_prefetch(const void *ptr); @@ -289,11 +331,6 @@ extern void osl_preempt_enable(osl_t *osh); #define OSL_PREFETCH(ptr) BCM_REFERENCE(ptr) #endif /* !__ARM_ARCH_7A__ */ -#ifdef AXI_TIMEOUTS_NIC -extern void osl_set_bpt_cb(osl_t *osh, void *bpt_cb, void *bpt_ctx); -extern void osl_bpt_rreg(osl_t *osh, ulong addr, volatile void *v, uint size); -#endif /* AXI_TIMEOUTS_NIC */ - /* register access macros */ #if defined(BCMSDIO) #include @@ -301,29 +338,20 @@ extern void osl_bpt_rreg(osl_t *osh, ulong addr, volatile void *v, uint size); (uintptr)(r), sizeof(*(r)), (v))) #define OSL_READ_REG(osh, r) (bcmsdh_reg_read(osl_get_bus_handle(osh), \ (uintptr)(r), sizeof(*(r)))) -#elif defined(AXI_TIMEOUTS_NIC) -#define OSL_READ_REG(osh, r) \ - ({\ - __typeof(*(r)) __osl_v; \ - osl_bpt_rreg(osh, (uintptr)(r), &__osl_v, sizeof(*(r))); \ - __osl_v; \ - }) -#endif -#if defined(AXI_TIMEOUTS_NIC) - #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;}) - #define SELECT_BUS_READ(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); bus_op;}) -#else /* !AXI_TIMEOUTS_NIC */ -#if defined(BCMSDIO) - #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \ - mmap_op else bus_op + #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) do { \ + if (((osl_pubinfo_t*)(osh))->mmbus) { \ + mmap_op; \ + } else { \ + bus_op; \ + } \ + } while(0) #define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \ mmap_op : bus_op #else #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;}) #define SELECT_BUS_READ(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;}) #endif /* defined(BCMSDIO) */ -#endif /* AXI_TIMEOUTS_NIC */ #define OSL_ERROR(bcmerror) osl_error(bcmerror) extern int osl_error(int bcmerror); @@ -344,13 +372,22 @@ extern int osl_error(int bcmerror); extern uint64 osl_sysuptime_us(void); #define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) #define OSL_SYSUPTIME_US() osl_sysuptime_us() +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) +extern uint64 osl_sysuptime_ns(void); +#define OSL_SYSUPTIME_NS() osl_sysuptime_ns() +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) */ extern uint64 osl_localtime_ns(void); extern void osl_get_localtime(uint64 *sec, uint64 *usec); extern uint64 osl_systztime_us(void); +extern char* osl_get_rtctime(void); #define OSL_LOCALTIME_NS() osl_localtime_ns() #define OSL_GET_LOCALTIME(sec, usec) osl_get_localtime((sec), (usec)) #define OSL_SYSTZTIME_US() osl_systztime_us() +#define OSL_GET_RTCTIME() osl_get_rtctime() +/* RTC format %02d:%02d:%02d.%06lu, LEN including the trailing null space */ +#define RTC_TIME_BUF_LEN 16u #define printf(fmt, args...) printk(PERCENT_S DHD_LOG_PREFIXS fmt, PRINTF_SYSTEM_TIME, ## args) +#define vprintf(fmt, ap) vprintk(fmt, ap) #include /* for vsn/printf's */ #include /* for mem*, str* */ /* bcopy's: Linux kernel doesn't provide these (anymore) */ @@ -361,14 +398,6 @@ extern uint64 osl_systztime_us(void); #define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) #define bzero(b, len) memset((b), '\0', (len)) -#if defined(CONFIG_SOC_EXYNOS9810) || defined(CONFIG_SOC_EXYNOS9820) || \ - defined(CONFIG_SOC_EXYNOS9830) || defined(CONFIG_SOC_GS101) -extern int pcie_ch_num; -extern int exynos_pcie_l1_exit(int ch_num); -#endif /* CONFIG_SOC_EXYNOS9810 || CONFIG_SOC_EXYNOS9820 - * CONFIG_SOC_EXYNOS9830 || CONFIG_SOC_GS101 - */ - /* register access macros */ #if defined(OSLREGOPS) #define R_REG(osh, r) (\ @@ -398,54 +427,50 @@ extern void osl_writeq(osl_t *osh, volatile uint64 *r, uint64 v); #else /* OSLREGOPS */ +#ifdef DHD_DEBUG_REG_DUMP +extern uint64 regs_addr; + +#define DUMP_R_REG_OFFSET(r) \ +{ \ + if ((((uint64)r - regs_addr) >> 16) == 0) \ + printf("**** R_REG : 0x%llx\n", (uint64)r - regs_addr); \ +} + +#define DUMP_W_REG_OFFSET(r, v) \ +{ \ + if ((((uint64)r - regs_addr) >> 16) == 0) \ + printf("$$$$ W_REG : 0x%llx %llu\n", (uint64)(r) - regs_addr, (uint64)(v)); \ +} +#else /* !DHD_DEBUG_REG_DUMP */ +#define DUMP_R_REG_OFFSET(r) +#define DUMP_W_REG_OFFSET(r, v) +#endif /* DHD_DEBUG_REG_DUMP */ + +extern void dhd_plat_l1_exit_io(void); + #ifndef IL_BIGENDIAN #ifdef CONFIG_64BIT /* readq is defined only for 64 bit platform */ -#if defined(CONFIG_SOC_EXYNOS9810) || defined(CONFIG_SOC_EXYNOS9820) || \ - defined(CONFIG_SOC_EXYNOS9830) || defined(CONFIG_SOC_GS101) -#define R_REG(osh, r) (\ +#define NO_WIN_CHECK_R_REG(osh, r, addr) (\ SELECT_BUS_READ(osh, \ ({ \ __typeof(*(r)) __osl_v = 0; \ - exynos_pcie_l1_exit(pcie_ch_num); \ + dhd_plat_l1_exit_io(); \ BCM_REFERENCE(osh); \ switch (sizeof(*(r))) { \ case sizeof(uint8): __osl_v = \ - readb((volatile uint8*)(r)); break; \ + readb((volatile uint8*)(addr)); break; \ case sizeof(uint16): __osl_v = \ - readw((volatile uint16*)(r)); break; \ + readw((volatile uint16*)(addr)); break; \ case sizeof(uint32): __osl_v = \ - readl((volatile uint32*)(r)); break; \ + readl((volatile uint32*)(addr)); break; \ case sizeof(uint64): __osl_v = \ - readq((volatile uint64*)(r)); break; \ + readq((volatile uint64*)(addr)); break; \ } \ __osl_v; \ }), \ OSL_READ_REG(osh, r)) \ ) -#else -#define R_REG(osh, r) (\ - SELECT_BUS_READ(osh, \ - ({ \ - __typeof(*(r)) __osl_v = 0; \ - BCM_REFERENCE(osh); \ - switch (sizeof(*(r))) { \ - case sizeof(uint8): __osl_v = \ - readb((volatile uint8*)(r)); break; \ - case sizeof(uint16): __osl_v = \ - readw((volatile uint16*)(r)); break; \ - case sizeof(uint32): __osl_v = \ - readl((volatile uint32*)(r)); break; \ - case sizeof(uint64): __osl_v = \ - readq((volatile uint64*)(r)); break; \ - } \ - __osl_v; \ - }), \ - OSL_READ_REG(osh, r)) \ -) -#endif /* CONFIG_SOC_EXYNOS9810 || CONFIG_SOC_EXYNOS9820 - * CONFIG_SOC_EXYNOS9830 || CONFIG_SOC_GS101 - */ #else /* !CONFIG_64BIT */ #define R_REG(osh, r) (\ SELECT_BUS_READ(osh, \ @@ -467,39 +492,23 @@ extern void osl_writeq(osl_t *osh, volatile uint64 *r, uint64 v); #ifdef CONFIG_64BIT /* writeq is defined only for 64 bit platform */ -#if defined(CONFIG_SOC_EXYNOS9810) || defined(CONFIG_SOC_EXYNOS9820) || \ - defined(CONFIG_SOC_EXYNOS9830) || defined(CONFIG_SOC_GS101) -#define W_REG(osh, r, v) do { \ +#define NO_WIN_CHECK_W_REG(osh, r, addr, v) do { \ SELECT_BUS_WRITE(osh, \ ({ \ - exynos_pcie_l1_exit(pcie_ch_num); \ + dhd_plat_l1_exit_io(); \ switch (sizeof(*(r))) { \ case sizeof(uint8): writeb((uint8)(v), \ - (volatile uint8*)(r)); break; \ + (volatile uint8*)(addr)); break; \ case sizeof(uint16): writew((uint16)(v), \ - (volatile uint16*)(r)); break; \ + (volatile uint16*)(addr)); break; \ case sizeof(uint32): writel((uint32)(v), \ - (volatile uint32*)(r)); break; \ + (volatile uint32*)(addr)); break; \ case sizeof(uint64): writeq((uint64)(v), \ - (volatile uint64*)(r)); break; \ + (volatile uint64*)(addr)); break; \ } \ }), \ (OSL_WRITE_REG(osh, r, v))); \ } while (0) -#else -#define W_REG(osh, r, v) do { \ - SELECT_BUS_WRITE(osh, \ - switch (sizeof(*(r))) { \ - case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ - case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ - case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ - case sizeof(uint64): writeq((uint64)(v), (volatile uint64*)(r)); break; \ - }, \ - (OSL_WRITE_REG(osh, r, v))); \ - } while (0) -#endif /* CONFIG_SOC_EXYNOS9810 || CONFIG_SOC_EXYNOS9820 - * CONFIG_SOC_EXYNOS9830 || CONFIG_SOC_GS101 - */ #else /* !CONFIG_64BIT */ #define W_REG(osh, r, v) do { \ SELECT_BUS_WRITE(osh, \ @@ -583,9 +592,6 @@ extern void osl_writeq(osl_t *osh, volatile uint64 *r, uint64 v); #endif /* OSLREGOPS */ -#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) -#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) - /* bcopy, bcmp, and bzero functions */ #define bcopy(src, dst, len) memcpy((dst), (src), (len)) #define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) @@ -608,13 +614,18 @@ extern void osl_writeq(osl_t *osh, volatile uint64 *r, uint64 v); /* dereference an address that may cause a bus exception */ #define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; }) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) +/* 'ioremap_nocache' was deprecated in kernels >= 5.6, so instead we use 'ioremap' which + * is no-cache by default since kernels 2.6.25. + */ +#define IOREMAP_NO_CACHE(address, size) ioremap(address, size) +#else /* KERNEL_VERSION < 2.6.25 */ +#define IOREMAP_NO_CACHE(address, size) ioremap_nocache(address, size) +#endif + /* map/unmap physical to virtual I/O */ #if !defined(CONFIG_MMC_MSM7X00A) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) -#define REG_MAP(pa, size) ioremap((unsigned long)(pa), (unsigned long)(size)) -#else -#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size)) -#endif +#define REG_MAP(pa, size) IOREMAP_NO_CACHE((unsigned long)(pa), (unsigned long)(size)) #else #define REG_MAP(pa, size) (void *)(0) #endif /* !defined(CONFIG_MMC_MSM7X00A */ @@ -657,6 +668,7 @@ extern void osl_writeq(osl_t *osh, volatile uint64 *r, uint64 v); * a GNU binutil such as objcopy via a symbol rename (i.e. memcpy to osl_memcpy). */ #define printf(fmt, args...) printk(fmt , ## args) + #define vprintf(fmt, ap) vprintk(fmt, ap) #include /* for vsn/printf's */ #include /* for mem*, str* */ /* bcopy's: Linux kernel doesn't provide these (anymore) */ @@ -711,8 +723,6 @@ extern void osl_writeq(osl_t *osh, volatile uint64 *r, uint64 v); #define W_REG(osh, r, v) do { OSL_WRITE_REG(osh, r, v); } while (0) #endif /* !defined(BCMSDIO) */ -#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) -#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) extern uint8 osl_readb(volatile uint8 *r); extern uint16 osl_readw(volatile uint16 *r); extern uint32 osl_readl(volatile uint32 *r); @@ -794,6 +804,78 @@ extern int bcmp(const void *b1, const void *b2, size_t len); extern void bzero(void *b, size_t len); #endif /* ! BCMDRIVER */ +#if defined(NIC_REG_ACCESS_LEGACY) || defined(NIC_REG_ACCESS_LEGACY_DBG) +/* TODO: For now check only for NICBUILD flag. Need to find PCIE + NIC equivalent flag */ +#if !defined(NICBUILD) +#error NIC_REG_ACCESS_LEGACY is only compatible with NICBUILD +#endif /* defined(NICBUILD) */ + +typedef struct osl_pcie_window { + void *bp_access_lock; + unsigned long window_offset; + unsigned long bp_addr; + volatile void *bar_addr; +} osl_pcie_window_t; + +extern osl_pcie_window_t osl_reg_access_pcie_window; + +/** + * Initialize osl_reg_access_pcie_window. + * @param[in] osh OS handle. + * @param[in] bp_access_lock Lock for restricting backplane access. + * @param[in] window_offset Offset of the window to be managed. + * @param[in] bar_addr ioremap address of this window. + */ +void osl_reg_access_pcie_window_init(osl_t *osh, void *bp_access_lock, unsigned long window_offset, + volatile void *bar_addr); + +/** + * Check that the osl_reg_access_pcie_window is configured to access the reg_addr and return the + * window address. If the window is not properly configured, then it will be reconfigured. + * @param[in] osh OS handle. + * @param[in] reg_addr Address that the window should be able to access after this function call. + * @return Address of the pcie bar window that is configured to access the provided + * address. + */ +volatile void *osl_update_pcie_win(osl_t *osh, volatile void *reg_addr); + +#define BAR0_WINDOW_OFFSET_MASK 0xFFFu +#define BAR0_WINDOW_ADDRESS_MASK ~BAR0_WINDOW_OFFSET_MASK + +#define WIN_CHECK_R_REG(osh, r) ({ \ + unsigned long _lock_flags_r_ = osl_spin_lock(osl_reg_access_pcie_window.bp_access_lock); \ + volatile void *_bar_addr_r_ = osl_update_pcie_win(osh, (volatile void *)r); \ + typeof(*r) _retval_; \ + _retval_ = (typeof(*r))NO_WIN_CHECK_R_REG(osh, r, _bar_addr_r_); \ + osl_spin_unlock(osl_reg_access_pcie_window.bp_access_lock, _lock_flags_r_); \ + _retval_; \ +}) + +#define WIN_CHECK_W_REG(osh, r, v) ({ \ + unsigned long _lock_flags_w_ = osl_spin_lock(osl_reg_access_pcie_window.bp_access_lock); \ + volatile void *_bar_addr_w_ = osl_update_pcie_win(osh, (volatile void *)r); \ + NO_WIN_CHECK_W_REG(osh, r, _bar_addr_w_, v); \ + osl_spin_unlock(osl_reg_access_pcie_window.bp_access_lock, _lock_flags_w_); \ +}) + +#endif /* defined(NIC_REG_ACCESS_LEGACY) || defined(NIC_REG_ACCESS_LEGACY_DBG) */ + +#ifdef NIC_REG_ACCESS_LEGACY +#define R_REG(osh, r) WIN_CHECK_R_REG(osh, r) +#define W_REG(osh, r, v) WIN_CHECK_W_REG(osh, r, v) +#else /* NIC_REG_ACCESS_LEGACY */ + +#if !defined(IL_BIGENDIAN) && defined(CONFIG_64BIT) + +#define R_REG(osh, r) NO_WIN_CHECK_R_REG(osh, r, r) +#define W_REG(osh, r, v) NO_WIN_CHECK_W_REG(osh, r, r, v) + +#endif /* !defined(IL_BIGENDIAN) && defined(CONFIG_64BIT) */ +#endif /* NIC_REG_ACCESS_LEGACY */ + +#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) +#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) + typedef struct sk_buff_head PKT_LIST; #define PKTLIST_INIT(x) skb_queue_head_init((x)) #define PKTLIST_ENQ(x, y) skb_queue_head((struct sk_buff_head *)(x), (struct sk_buff *)(y)) @@ -814,7 +896,7 @@ typedef struct osl_timer { typedef void (*linux_timer_fn)(ulong arg); -extern osl_timer_t * osl_timer_init(osl_t *osh, const char *name, void (*fn)(void *arg), void *arg); +extern osl_timer_t * osl_timer_init(osl_t *osh, const char *name, void (*fn)(ulong arg), void *arg); extern void osl_timer_add(osl_t *osh, osl_timer_t *t, uint32 ms, bool periodic); extern void osl_timer_update(osl_t *osh, osl_timer_t *t, uint32 ms, bool periodic); extern bool osl_timer_del(osl_t *osh, osl_timer_t *t); @@ -825,6 +907,7 @@ typedef atomic_t osl_atomic_t; #define OSL_ATOMIC_INIT(osh, v) atomic_set(v, 0) #define OSL_ATOMIC_INC(osh, v) atomic_inc(v) #define OSL_ATOMIC_INC_RETURN(osh, v) atomic_inc_return(v) +#define OSL_ATOMIC_INC_AND_TEST(osh, v) atomic_inc_and_test(v) #define OSL_ATOMIC_DEC(osh, v) atomic_dec(v) #define OSL_ATOMIC_DEC_RETURN(osh, v) atomic_dec_return(v) #define OSL_ATOMIC_READ(osh, v) atomic_read(v) @@ -839,6 +922,15 @@ typedef atomic_t osl_atomic_t; #endif #endif /* BCMDRIVER */ +/* kvmalloc was added from kernel ver 4.12 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) +#define KVZALLOC(size, flags) kzalloc(size, flags) +#define KVFREE(osh, addr) kfree(addr) +#else +#define KVZALLOC(size, flags) kvzalloc(size, flags) +#define KVFREE(osh, addr) kvfree(addr) +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */ + extern void *osl_spin_lock_init(osl_t *osh); extern void osl_spin_lock_deinit(osl_t *osh, void *lock); extern unsigned long osl_spin_lock(void *lock); @@ -853,6 +945,26 @@ extern void osl_mutex_lock_deinit(osl_t *osh, void *lock); extern unsigned long osl_mutex_lock(void *lock); void osl_mutex_unlock(void *lock, unsigned long flags); +/* -Wimplicit-fallthrough=5 requires attribute to be used + * Use the attribute when defined and rely on FALLTHROUGH + * comment otherwisely. + */ +#ifndef fallthrough +#if defined(__GNUC__) +#if (__GNUC__ >= 7) +#define fallthrough __attribute__ ((__fallthrough__)) +#else +#define fallthrough do {} while (0) /* FALLTHROUGH */ +#endif /* GCC >= 7 */ +#else /* !GCC */ +#if __has_attribute(__fallthrough__) +#define fallthrough __attribute__ ((__fallthrough__)) +#else +#define fallthrough do {} while (0) /* FALLTHROUGH */ +#endif /* __has_attribute */ +#endif /* GCC */ +#endif /* fallthrough */ + typedef struct osl_timespec { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) __kernel_old_time_t tv_sec; /* seconds */ @@ -865,4 +977,18 @@ typedef struct osl_timespec { extern void osl_do_gettimeofday(struct osl_timespec *ts); extern void osl_get_monotonic_boottime(struct osl_timespec *ts); extern uint32 osl_do_gettimediff(struct osl_timespec *cur_ts, struct osl_timespec *old_ts); + +#ifndef CUSTOM_PREFIX +#define OSL_PRINT(args) \ +do { \ + printf args; \ +} while (0) +#else +#define OSL_PRINT_PREFIX "[%s]"CUSTOM_PREFIX, OSL_GET_RTCTIME() +#define OSL_PRINT(args) \ +do { \ + pr_cont(OSL_PRINT_PREFIX); \ + pr_cont args; \ +} while (0) +#endif /* CUSTOM_PREFIX */ #endif /* _linux_osl_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_pkt.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_pkt.h old mode 100755 new mode 100644 index f2fcf5fd48f7..fb4da88589c6 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_pkt.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_pkt.h @@ -1,7 +1,7 @@ /* * Linux Packet (skb) interface * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -141,6 +141,14 @@ extern void osl_pkt_orphan_partial(struct sk_buff *skb, int tsq); #define PKTORPHAN(skb, tsq) ({BCM_REFERENCE(skb); 0;}) #endif /* Linux Version >= 3.6 */ +#ifdef RX_PKT_POOL +#ifdef DHD_USE_ATOMIC_PKTGET +#error "Don't enable both DHD_USE_ATOMIC_PKTGET and RX_PKT_POOL, " + "as RX_PKT_POOL runs in non atomic context" +#endif /* DHD_USE_ATOMIC_PKTGET */ +#define PKTGET_RX_POOL(osh, dhd, len, send) dhd_rxpool_pktget((osh), (dhd), (len)) +#endif /* RX_PKT_POOL */ + #ifdef BCMDBG_CTRACE #define DEL_CTRACE(zosh, zskb) { \ unsigned long zflags; \ @@ -180,26 +188,40 @@ extern void osl_pkt_orphan_partial(struct sk_buff *skb, int tsq); #define PKTCALLER(zskb) UPDATE_CTRACE((struct sk_buff *)zskb, (char *)__FUNCTION__, __LINE__) #endif /* BCMDBG_CTRACE */ -#define PKTSETFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTCLRFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTISFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) -#define PKTLITIDX(skb) ({BCM_REFERENCE(skb); 0;}) -#define PKTSETLITIDX(skb, idx) ({BCM_REFERENCE(skb); BCM_REFERENCE(idx);}) -#define PKTRESETLITIDX(skb) ({BCM_REFERENCE(skb);}) -#define PKTRITIDX(skb) ({BCM_REFERENCE(skb); 0;}) -#define PKTSETRITIDX(skb, idx) ({BCM_REFERENCE(skb); BCM_REFERENCE(idx);}) -#define PKTRESETRITIDX(skb) ({BCM_REFERENCE(skb);}) +#define PKTSETFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTCLRFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTISFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) -#define PKTSETSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTCLRSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTLITIDX(skb) ({BCM_REFERENCE(skb); 0;}) +#define PKTSETLITIDX(skb, idx) ({BCM_REFERENCE(skb); BCM_REFERENCE(idx);}) +#define PKTRESETLITIDX(skb) ({BCM_REFERENCE(skb);}) +#define PKTLITIDX_1(skb) ({BCM_REFERENCE(skb); 0;}) +#define PKTSETLITIDX_1(skb, idx) ({BCM_REFERENCE(skb); BCM_REFERENCE(idx);}) +#define PKTRESETLITIDX_1(skb) ({BCM_REFERENCE(skb);}) +#define PKTLITIDX_2(skb) ({BCM_REFERENCE(skb); 0;}) +#define PKTSETLITIDX_2(skb, idx) ({BCM_REFERENCE(skb); BCM_REFERENCE(idx);}) +#define PKTRESETLITIDX_2(skb) ({BCM_REFERENCE(skb);}) -#define PKTFRAGLEN(osh, lb, ix) (0) -#define PKTSETFRAGLEN(osh, lb, ix, len) BCM_REFERENCE(osh) +#define PKTRITIDX(skb) ({BCM_REFERENCE(skb); 0;}) +#define PKTSETRITIDX(skb, idx) ({BCM_REFERENCE(skb); BCM_REFERENCE(idx);}) +#define PKTRESETRITIDX(skb) ({BCM_REFERENCE(skb);}) +#define PKTRITIDX_1(skb) ({BCM_REFERENCE(skb); 0;}) +#define PKTSETRITIDX_1(skb, idx) ({BCM_REFERENCE(skb); BCM_REFERENCE(idx);}) +#define PKTRESETRITIDX_1(skb) ({BCM_REFERENCE(skb);}) +#define PKTRITIDX_2(skb) ({BCM_REFERENCE(skb); 0;}) +#define PKTSETRITIDX_2(skb, idx) ({BCM_REFERENCE(skb); BCM_REFERENCE(idx);}) +#define PKTRESETRITIDX_2(skb) ({BCM_REFERENCE(skb);}) -#define PKTSETTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTCLRTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) -#define PKTISTOBR(skb) ({BCM_REFERENCE(skb); FALSE;}) +#define PKTSETSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTCLRSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) + +#define PKTFRAGLEN(osh, lb, ix) (0) +#define PKTSETFRAGLEN(osh, lb, ix, len) BCM_REFERENCE(osh) + +#define PKTSETTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTCLRTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) +#define PKTISTOBR(skb) ({BCM_REFERENCE(skb); FALSE;}) #ifdef BCMFA #ifdef BCMFA_HW_HASH diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/frag.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linuxerrmap.h old mode 100755 new mode 100644 similarity index 74% rename from drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/frag.h rename to drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linuxerrmap.h index e14edd96f251..3cc5a012c36a --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/frag.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linuxerrmap.h @@ -1,8 +1,7 @@ /* - * IE/TLV (de)fragmentation declarations/definitions for - * Broadcom 802.11abgn Networking Device Driver + * Linux Error mappings * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -20,13 +19,10 @@ * * * <> - * */ -#ifndef __FRAG_H__ -#define __FRAG_H__ +#ifndef _linuxerrmap_h_ +#define _linuxerrmap_h_ +extern int linux_get_errmap(int bcmerror); -int bcm_tlv_dot11_frag_tot_len(const void *buf, uint buf_len, - uint8 id, bool id_ext, uint *ie_len); - -#endif /* __FRAG_H__ */ +#endif /* _linuxerrmap_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linuxver.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linuxver.h old mode 100755 new mode 100644 index f405a5d94f3e..d5bf94b41295 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linuxver.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linuxver.h @@ -2,7 +2,7 @@ * Linux-specific abstractions to gain some independence from linux kernel versions. * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -42,6 +42,14 @@ #include #include + +#ifndef RHEL_RELEASE_CODE +#define RHEL_RELEASE_CODE (0) +#endif +#ifndef RHEL_RELEASE_VERSION +#define RHEL_RELEASE_VERSION(a, b) (((a) << 8) + (b)) +#endif + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) #include #else @@ -146,7 +154,8 @@ #define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func) #else #define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func, _work) -#if (!(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18) && defined(RHEL_MAJOR) && (RHEL_MAJOR == 5))) +#if !(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18) && defined(RHEL_MAJOR) && \ + (RHEL_MAJOR == 5)) /* Exclude RHEL 5 */ typedef void (*work_func_t)(void *work); #endif @@ -348,11 +357,13 @@ static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, } return ret; } + static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { free_pages((unsigned long)vaddr, get_order(size)); } + #ifdef ILSIM extern uint pci_map_single(void *dev, void *va, uint size, int direction); extern void pci_unmap_single(void *dev, uint pa, uint size, int direction); @@ -468,6 +479,7 @@ static inline void tasklet_init(struct tasklet_struct *tasklet, tasklet->routine = (void (*)(void *))func; tasklet->data = (void *)data; } + #define tasklet_kill(tasklet) { do {} while (0); } /* 2.4.x introduced del_timer_sync() */ @@ -589,6 +601,21 @@ pci_restore_state(struct pci_dev *dev, u32 *buffer) #endif #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0) +#define DEV_CHANGE_FLAGS(ndev, flags) dev_change_flags((ndev), flags) +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) */ +#define DEV_CHANGE_FLAGS(ndev, flags) dev_change_flags((ndev), flags, NULL) +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) +#define DEV_ADDR_SET(ndev, mac_addr) (void)memcpy_s(((ndev)->dev_addr), \ + ETHER_ADDR_LEN, mac_addr, ETHER_ADDR_LEN) +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) */ +#define DEV_ADDR_SET(ndev, mac_addr) dev_addr_set(ndev, (const u8*)mac_addr) +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0) */ +#define DEV_ADDR_GET(ndev, pBuf) (void)memcpy_s(pBuf, \ + ETHER_ADDR_LEN, ((ndev)->dev_addr), ETHER_ADDR_LEN) + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) /* struct packet_type redefined in 2.6.x */ #define af_packet_priv data @@ -642,11 +669,21 @@ extern char* dhd_dbg_get_system_timestamp(void); #endif #define DHD_LOG_PREFIXS DHD_LOG_PREFIX" " #ifdef DHD_DEBUG +#ifndef CUSTOM_PREFIX #define printf_thr(fmt, args...) printk(PERCENT_S DHD_LOG_PREFIXS fmt, PRINTF_SYSTEM_TIME, ## args) #define DBG_THR(args) do {printf_thr args;} while (0) #else +extern char* osl_get_rtctime(void); +#define DBG_THR_PREFIX "[%s]"CUSTOM_PREFIX, osl_get_rtctime() +#define DBG_THR(x) \ +do { \ + pr_cont(DBG_THR_PREFIX); \ + pr_cont x; \ +} while (0) +#endif /* !CUSTOM_PREFIX */ +#else #define DBG_THR(x) -#endif +#endif /* DHD_DEBUG */ extern unsigned long osl_spin_lock(void *lock); extern void osl_spin_unlock(void *lock, unsigned long flags); @@ -692,7 +729,7 @@ static inline bool binary_sema_up(tsk_ctl_t *tsk) return sem_up; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 6, 0)) #define SMP_RD_BARRIER_DEPENDS(x) #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) #define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) @@ -789,6 +826,10 @@ static inline bool binary_sema_up(tsk_ctl_t *tsk) (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)) +#define complete_and_exit kthread_complete_and_exit +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0) */ + /* ----------------------- */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) @@ -886,18 +927,19 @@ not match our unaligned address for < 2.6.24 #define KMALLOC_FLAG (CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) -#define RANDOM32 prandom_u32 -#define RANDOM_BYTES prandom_bytes -#else -#define RANDOM32 random32 -#define RANDOM_BYTES get_random_bytes -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) -#define SRANDOM32(entropy) prandom_seed(entropy) -#else -#define SRANDOM32(entropy) srandom32(entropy) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)) +#define RANDOM32 get_random_u32 +#define RANDOM_BYTES get_random_bytes +#define SRANDOM32(entropy) do { uint _entropy = (entropy); \ + add_device_randomness(&_entropy, sizeof(uint)); } while (0) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#define RANDOM32 prandom_u32 +#define RANDOM_BYTES prandom_bytes +#define SRANDOM32 prandom_seed +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ +#define RANDOM32 random32 +#define RANDOM_BYTES get_random_bytes +#define SRANDOM32 srandom32 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ /* @@ -931,27 +973,86 @@ static inline struct inode *file_inode(const struct file *f) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) -#ifdef CONFIG_NO_GKI +// New google android GKI not allow kernel_write/kernel_read, and use +// below for temporary overcome, and waiting for get rid of that for future +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); +#endif // LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) #define vfs_write(fp, buf, len, pos) kernel_write(fp, buf, len, pos) #define vfs_read(fp, buf, len, pos) kernel_read(fp, buf, len, pos) -#else -#define vfs_write(fp, buf, len, pos) ({ UNUSED_PARAMETER(fp); UNUSED_PARAMETER(buf); UNUSED_PARAMETER(len); UNUSED_PARAMETER(pos); -EPERM; }) -#define vfs_read(fp, buf, len, pos) ({ UNUSED_PARAMETER(fp); UNUSED_PARAMETER(buf); UNUSED_PARAMETER(len); UNUSED_PARAMETER(pos); -EPERM; }) -#define filp_open(filename, flags, mode) ({ UNUSED_PARAMETER(filename); UNUSED_PARAMETER(flags); UNUSED_PARAMETER(mode); ERR_PTR(-EPERM); }) -#endif int kernel_read_compat(struct file *file, loff_t offset, char *addr, unsigned long count); #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) */ #define kernel_read_compat(file, offset, addr, count) kernel_read(file, offset, addr, count) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) +#define timespec64 timespec +#define ktime_get_real_ts64(timespec) ktime_get_real_ts(timespec) +#define ktime_to_timespec64(timespec) ktime_to_timespec(timespec) +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)) && (LINUX_VERSION_CODE >= \ + KERNEL_VERSION(4, 20, 0)) +static inline void get_monotonic_boottime(struct timespec *ts) +{ + *ts = ktime_to_timespec(ktime_get_boottime()); +} +#endif /* LINUX_VER >= 4.20 */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)) && (LINUX_VERSION_CODE >= \ + KERNEL_VERSION(5, 0, 0)) +static inline void do_gettimeofday(struct timeval *tv) +{ + struct timespec64 now; + + ktime_get_real_ts64(&now); + tv->tv_sec = now.tv_sec; + tv->tv_usec = now.tv_nsec/1000; +} +#endif /* LINUX_VER >= 5.0 */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) +#define GETFS_AND_SETFS_TO_KERNEL_DS(fs) \ +{ \ + fs = get_fs(); \ + set_fs(KERNEL_DS); \ +} + +#define SETFS(fs) set_fs(fs) +#else +/* From 5.10 kernel get/set_fs are obsolete and direct kernel_read/write operations can be used */ +#define GETFS_AND_SETFS_TO_KERNEL_DS(fs) BCM_REFERENCE(fs) +#define SETFS(fs) BCM_REFERENCE(fs) +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) +#include +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)) +#define PDE_DATA(inode) pde_data(inode) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) +/* already has the Macro definition */ +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)) */ +#define PDE_DATA(inode) NULL +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)) */ + +#ifdef ANDROID_BKPORT +#if (ANDROID_VERSION >= 13) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 41)) +#define ANDROID13_KERNEL515_BKPORT +#define CFG80211_BKPORT_MLO +#endif /* ANDROID_VERSION >= 13 && KERNEL >= 5.15.41 */ +#endif /* ANDROID_BKPORT */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) +#define WDEV_CLIENT(wdev, field) (wdev->u.client.field) +#else +#define WDEV_CLIENT(wdev, field) (wdev->field) +#endif /* LINUX_VER >= 5.19.2 || CFG80211_BKPORT_MLO */ + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) #define netdev_tx_t int #endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)) -#define complete_and_exit(a, b) kthread_complete_and_exit(a, b) -#else -#define dev_addr_set(net, addr) memcpy(net->dev_addr, addr, ETHER_ADDR_LEN) -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(5, 17, 0) */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)) #define netif_rx_ni(skb) netif_rx(skb) #define pci_free_consistent(a, b, c, d) dma_free_coherent(&((struct pci_dev *)a)->dev, b, c, d) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/lpflags.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/lpflags.h old mode 100755 new mode 100644 index f284bbb59c55..6ff882a14c19 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/lpflags.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/lpflags.h @@ -1,7 +1,7 @@ /* * Chip related low power flags * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/mbo.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/mbo.h old mode 100755 new mode 100644 index 14bd92b17a32..c9130a910d78 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/mbo.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/mbo.h @@ -1,7 +1,7 @@ /* * Fundamental types and constants relating to WFA MBO * (Multiband Operation) - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -24,6 +24,8 @@ #ifndef _MBO_H_ #define _MBO_H_ +#include <802.11wfa.h> + /* This marks the start of a packed structure section. */ #include @@ -67,11 +69,11 @@ enum { }; typedef BWL_PRE_PACKED_STRUCT struct wifi_mbo_ie_s { - uint8 id; /* IE ID: MBO_IE_ID 0xDD */ - uint8 len; /* IE length */ - uint8 oui[WFA_OUI_LEN]; /* MBO_OUI 50:6F:9A */ - uint8 oui_type; /* MBO_OUI_TYPE 0x16 */ - uint8 attr[1]; /* var len attributes */ + uint8 id; /* IE ID: MBO_IE_ID 0xDD */ + uint8 len; /* IE length */ + uint8 oui[WFA_OUI_LEN]; /* MBO_OUI 50:6F:9A */ + uint8 oui_type; /* MBO_OUI_TYPE 0x16 */ + uint8 attr[BCM_FLEX_ARRAY]; /* var len attributes */ } BWL_POST_PACKED_STRUCT wifi_mbo_ie_t; #define MBO_IE_HDR_SIZE (OFFSETOF(wifi_mbo_ie_t, attr)) @@ -245,7 +247,7 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_mbo_anqp_elem_s { /* MBO ANQP element type */ uint8 sub_type; /* variable len payload */ - uint8 payload[1]; + uint8 payload[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT wifi_mbo_anqp_elem_t; #define MBO_ANQP_ELEM_HDR_SIZE (OFFSETOF(wifi_mbo_anqp_elem_t, payload)) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/miniopt.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/miniopt.h deleted file mode 100755 index b486c072f2df..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/miniopt.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Command line options parser. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -#ifndef MINI_OPT_H -#define MINI_OPT_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* ---- Include Files ---------------------------------------------------- */ - -/* ---- Constants and Types ---------------------------------------------- */ - -#define MINIOPT_MAXKEY 128 /* Max options */ -typedef struct miniopt { - - /* These are persistent after miniopt_init() */ - const char* name; /* name for prompt in error strings */ - const char* flags; /* option chars that take no args */ - bool longflags; /* long options may be flags */ - bool opt_end; /* at end of options (passed a "--") */ - - /* These are per-call to miniopt() */ - - int consumed; /* number of argv entries cosumed in - * the most recent call to miniopt() - */ - bool positional; - bool good_int; /* 'val' member is the result of a sucessful - * strtol conversion of the option value - */ - char opt; - char key[MINIOPT_MAXKEY]; - char* valstr; /* positional param, or value for the option, - * or null if the option had - * no accompanying value - */ - uint uval; /* strtol translation of valstr */ - int val; /* strtol translation of valstr */ -} miniopt_t; - -void miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags); -int miniopt(miniopt_t *t, char **argv); - -/* ---- Variable Externs ------------------------------------------------- */ -/* ---- Function Prototypes ---------------------------------------------- */ - -#ifdef __cplusplus - } -#endif - -#endif /* MINI_OPT_H */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/monitor.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/monitor.h deleted file mode 100755 index 4b92cdae94b8..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/monitor.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Monitor Mode definitions. - * This header file housing the define and function prototype use by - * both the wl firmware and drivers. - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ -#ifndef _MONITOR_H_ -#define _MONITOR_H_ - -#include - -#include -/* wl_monitor rx status per packet */ -typedef struct BWL_PRE_PACKED_STRUCT wl_rxsts { - uint pkterror; /* error flags per pkt */ - uint phytype; /* 802.11 A/B/G /N */ - chanspec_t chanspec; /* channel spec */ - uint16 datarate; /* rate in 500kbps */ - uint8 mcs; /* MCS for HT frame */ - uint8 htflags; /* HT modulation flags */ - uint antenna; /* antenna pkts received on */ - uint pktlength; /* pkt length minus bcm phy hdr */ - uint32 mactime; /* time stamp from mac, count per 1us */ - uint sq; /* signal quality */ - int32 signal; /* in dBm */ - int32 noise; /* in dBm */ - uint preamble; /* Unknown, short, long */ - uint encoding; /* Unknown, CCK, PBCC, OFDM, HT, VHT */ - uint nfrmtype; /* special 802.11n frames(AMPDU, AMSDU) */ - uint8 nss; /* Number of spatial streams for VHT frame */ - uint8 coding; - uint16 aid; /* Partial AID for VHT frame */ - uint8 gid; /* Group ID for VHT frame */ - uint8 bw; /* Bandwidth for VHT frame */ - uint16 vhtflags; /* VHT modulation flags */ - uint16 bw_nonht; /* non-HT bw advertised in rts/cts */ - uint32 ampdu_counter; /* AMPDU counter for sniffer */ - uint32 sig_a1; /* TODO: this unused field needs to be removed */ - uint32 sig_a2; /* TODO: this unused field needs to be removed */ - uint16 data1; - uint16 data2; - uint16 data3; - uint16 data4; - uint16 data5; - uint16 data6; - uint8 ru_channel1[4]; - uint8 ru_channel2[4]; - uint16 flag1; - uint16 flag2; -} BWL_POST_PACKED_STRUCT wl_rxsts_t, wl_mon_rxsts_t; -#include - -#define WLMONRXSTS_SIZE sizeof(wl_rxsts_t) - -/* phy type */ -#define WL_RXS_PHY_N 0x00000004 /* N phy type */ - -/* encoding */ -#define WL_RXS_ENCODING_UNKNOWN 0x00000000 -#define WL_RXS_ENCODING_DSSS_CCK 0x00000001 /* DSSS/CCK encoding (1, 2, 5.5, 11) */ -#define WL_RXS_ENCODING_OFDM 0x00000002 /* OFDM encoding */ -#define WL_RXS_ENCODING_HT 0x00000003 /* HT encoding */ -#define WL_RXS_ENCODING_VHT 0x00000004 /* VHT encoding */ -#define WL_RXS_ENCODING_HE 0x00000005 /* HE encoding */ -#define WL_RXS_ENCODING_EHT 0x00000006 /* EHT encoding */ - -/* status per error RX pkt */ -#define WL_RXS_CRC_ERROR 0x00000001 /* CRC Error in packet */ -#define WL_RXS_RUNT_ERROR 0x00000002 /* Runt packet */ -#define WL_RXS_ALIGN_ERROR 0x00000004 /* Misaligned packet */ -#define WL_RXS_OVERSIZE_ERROR 0x00000008 /* packet bigger than RX_LENGTH (usually 1518) */ -#define WL_RXS_WEP_ICV_ERROR 0x00000010 /* Integrity Check Value error */ -#define WL_RXS_WEP_ENCRYPTED 0x00000020 /* Encrypted with WEP */ -#define WL_RXS_PLCP_SHORT 0x00000040 /* Short PLCP error */ -#define WL_RXS_DECRYPT_ERR 0x00000080 /* Decryption error */ -#define WL_RXS_OTHER_ERR 0x80000000 /* Other errors */ - -/* preamble */ -#define WL_RXS_UNUSED_STUB 0x0 /**< stub to match with wlc_ethereal.h */ -#define WL_RXS_PREAMBLE_SHORT 0x00000001 /**< Short preamble */ -#define WL_RXS_PREAMBLE_LONG 0x00000002 /**< Long preamble */ -#define WL_RXS_PREAMBLE_HT_MM 0x00000003 /**< HT mixed mode preamble */ -#define WL_RXS_PREAMBLE_HT_GF 0x00000004 /**< HT green field preamble */ - -/* htflags */ -#define WL_RXS_HTF_BW_MASK 0x07 -#define WL_RXS_HTF_40 0x01 -#define WL_RXS_HTF_20L 0x02 -#define WL_RXS_HTF_20U 0x04 -#define WL_RXS_HTF_SGI 0x08 -#define WL_RXS_HTF_STBC_MASK 0x30 -#define WL_RXS_HTF_STBC_SHIFT 4 -#define WL_RXS_HTF_LDPC 0x40 - -#ifdef WLTXMONITOR -/* reuse bw-bits in ht for vht */ -#define WL_RXS_VHTF_BW_MASK 0x87 -#define WL_RXS_VHTF_40 0x01 -#define WL_RXS_VHTF_20L WL_RXS_VHTF_20LL -#define WL_RXS_VHTF_20U WL_RXS_VHTF_20LU -#define WL_RXS_VHTF_80 0x02 -#define WL_RXS_VHTF_20LL 0x03 -#define WL_RXS_VHTF_20LU 0x04 -#define WL_RXS_VHTF_20UL 0x05 -#define WL_RXS_VHTF_20UU 0x06 -#define WL_RXS_VHTF_40L 0x07 -#define WL_RXS_VHTF_40U 0x80 -#endif /* WLTXMONITOR */ - -/* vhtflags */ -#define WL_RXS_VHTF_STBC 0x01 -#define WL_RXS_VHTF_TXOP_PS 0x02 -#define WL_RXS_VHTF_SGI 0x04 -#define WL_RXS_VHTF_SGI_NSYM_DA 0x08 -#define WL_RXS_VHTF_LDPC_EXTRA 0x10 -#define WL_RXS_VHTF_BF 0x20 -#define WL_RXS_VHTF_DYN_BW_NONHT 0x40 -#define WL_RXS_VHTF_CODING_LDCP 0x01 - -#define WL_RXS_VHT_BW_20 0 -#define WL_RXS_VHT_BW_40 1 -#define WL_RXS_VHT_BW_20L 2 -#define WL_RXS_VHT_BW_20U 3 -#define WL_RXS_VHT_BW_80 4 -#define WL_RXS_VHT_BW_40L 5 -#define WL_RXS_VHT_BW_40U 6 -#define WL_RXS_VHT_BW_20LL 7 -#define WL_RXS_VHT_BW_20LU 8 -#define WL_RXS_VHT_BW_20UL 9 -#define WL_RXS_VHT_BW_20UU 10 -#define WL_RXS_VHT_BW_160 11 -#define WL_RXS_VHT_BW_80L 12 -#define WL_RXS_VHT_BW_80U 13 -#define WL_RXS_VHT_BW_40LL 14 -#define WL_RXS_VHT_BW_40LU 15 -#define WL_RXS_VHT_BW_40UL 16 -#define WL_RXS_VHT_BW_40UU 17 -#define WL_RXS_VHT_BW_20LLL 18 -#define WL_RXS_VHT_BW_20LLU 19 -#define WL_RXS_VHT_BW_20LUL 20 -#define WL_RXS_VHT_BW_20LUU 21 -#define WL_RXS_VHT_BW_20ULL 22 -#define WL_RXS_VHT_BW_20ULU 23 -#define WL_RXS_VHT_BW_20UUL 24 -#define WL_RXS_VHT_BW_20UUU 25 - -#define WL_RXS_NFRM_AMPDU_FIRST 0x00000001 /* first MPDU in A-MPDU */ -#define WL_RXS_NFRM_AMPDU_SUB 0x00000002 /* subsequent MPDU(s) in A-MPDU */ -#define WL_RXS_NFRM_AMSDU_FIRST 0x00000004 /* first MSDU in A-MSDU */ -#define WL_RXS_NFRM_AMSDU_SUB 0x00000008 /* subsequent MSDU(s) in A-MSDU */ - -/* HE flags */ -#define WL_RXS_HEF_SIGA_PPDU_SU 0x0000 -#define WL_RXS_HEF_SIGA_PPDU_EXT_SU 0x0001 -#define WL_RXS_HEF_SIGA_PPDU_MU 0x0002 -#define WL_RXS_HEF_SIGA_PPDU_TRIG 0x0003 -#define WL_RXS_HEF_SIGA_BSS_COLOR 0x0004 -#define WL_RXS_HEF_SIGA_BEAM_CHANGE 0x0008 -#define WL_RXS_HEF_SIGA_DL_UL 0x0010 -#define WL_RXS_HEF_SIGA_MCS 0x0020 -#define WL_RXS_HEF_SIGA_DCM 0x0040 -#define WL_RXS_HEF_SIGA_CODING 0x0080 -#define WL_RXS_HEF_SIGA_LDPC 0x0100 -#define WL_RXS_HEF_SIGA_STBC 0x0200 -#define WL_RXS_HEF_SIGA_SPATIAL_REUSE 0x0400 -#define WL_RXS_HEF_SIGA_STA_ID 0x0800 -#define WL_RXS_HEF_SIGA_SPATIAL_REUSE2 0x0800 -#define WL_RXS_HEF_SIGA_SPATIAL_REUSE3 0x1000 -#define WL_RXS_HEF_SIGA_SPATIAL_REUSE4 0x2000 -#define WL_RXS_HEF_SIGA_BW 0x4000 -#define WL_RXS_HEF_SIGA_RU_ALLOC 0x4000 -#define WL_RXS_HEF_SIGA_DOPPLER 0x8000 -#define WL_RXS_HEF_SIGA_GI 0x0002 -#define WL_RXS_HEF_SIGA_LTF_SIZE 0x0004 /* no explicit known field */ -#define WL_RXS_HEF_SIGA_NUM_LTF 0x0004 -#define WL_RXS_HEF_SIGA_PADDING 0x0008 -#define WL_RXS_HEF_SIGA_TXBF 0x0010 -#define WL_RXS_HEF_SIGA_PE 0x0020 -#define WL_RXS_HEF_SIGA_TXOP 0x0040 -#define WL_RXS_HEF_SIGA_MIDAMBLE 0x0080 - -/* https://www.radiotap.org/fields/HE-MU.html */ -#define WL_RXS_HEF_SIGB_MCS_KNOWN 0x0010 -#define WL_RXS_HEF_SIGB_DCM_KNOWN 0x0040 -#define WL_RXS_HEF_CH2_26TONE_RU_KNOWN 0x0080 -#define WL_RXS_HEF_CH1_RU_KNOWN 0x0100 -#define WL_RXS_HEF_CH2_RU_KNOWN 0x0200 -#define WL_RXS_HEF_CH1_26TONE_RU_KNOWN 0x1000 -#define WL_RXS_HEF_SIGB_COMP_KNOWN 0x4000 -#define WL_RXS_HEF_NUM_SIGB_SYMB_KNOWN 0x8000 -#define WL_RXS_HEF_BW_SIGA_KNOWN 0x0004 -#define WL_RXS_HEF_PREPUNCR_SIGA_KNOWN 0x0400 -#define WL_RXS_HEF_SIGB_SYMB_KNOWN 0x8000 -#define WL_RXS_HEF_PREPUNCR_KNOWN 0x0400 - -#include -typedef struct BWL_PRE_PACKED_STRUCT wl_txsts { - uint pkterror; /**< error flags per pkt */ - uint phytype; /**< 802.11 A/B/G /N */ - chanspec_t chanspec; /**< channel spec */ - uint16 datarate; /**< rate in 500kbps */ - uint8 mcs; /**< MCS for HT frame */ - uint8 htflags; /**< HT modulation flags */ - uint antenna; /**< antenna pkt transmitted on */ - uint pktlength; /**< pkt length minus bcm phy hdr */ - uint32 mactime; /**< ? time stamp from mac, count per 1us */ - uint preamble; /**< Unknown, short, long */ - uint encoding; /**< Unknown, CCK, PBCC, OFDM, HT */ - uint nfrmtype; /**< special 802.11n frames(AMPDU, AMSDU) */ - uint txflags; /**< As defined in radiotap field 15 */ - uint retries; /**< Number of retries */ - struct wl_if *wlif; /**< wl interface */ -} BWL_POST_PACKED_STRUCT wl_txsts_t; -#include - -#define WL_TXS_TXF_FAIL 0x01 /**< TX failed due to excessive retries */ -#define WL_TXS_TXF_CTS 0x02 /**< TX used CTS-to-self protection */ -#define WL_TXS_TXF_RTSCTS 0x04 /**< TX used RTS/CTS */ - -#endif /* _MONITOR_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/msf.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/msf.h deleted file mode 100755 index 1511ef15773b..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/msf.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Common interface to MSF (multi-segment format) definitions. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -#ifndef _WLC_MSF_H_ -#define _WLC_MSF_H_ - -struct wl_segment { - uint32 type; - uint32 offset; - uint32 length; - uint32 crc32; - uint32 flags; -}; -typedef struct wl_segment wl_segment_t; - -struct wl_segment_info { - uint8 magic[4]; - uint32 hdr_len; - uint32 crc32; - uint32 file_type; - uint32 num_segments; - wl_segment_t segments[1]; -}; -typedef struct wl_segment_info wl_segment_info_t; - -typedef struct wlc_blob_segment { - uint32 type; - uint8 *data; - uint32 length; -} wlc_blob_segment_t; - -/** Segment types in Binary Eventlog Archive file */ -enum bea_seg_type_e { - MSF_SEG_TYP_RTECDC_BIN = 1, - MSF_SEG_TYP_LOGSTRS_BIN = 2, - MSF_SEG_TYP_FW_SYMBOLS = 3, - MSF_SEG_TYP_ROML_BIN = 4 -}; - -#endif /* _WLC_MSF_H */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/msgtrace.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/msgtrace.h old mode 100755 new mode 100644 index f564999d050f..46df878f9d8f --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/msgtrace.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/msgtrace.h @@ -1,7 +1,7 @@ /* * Trace messages sent over HBUS * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -33,12 +33,15 @@ #define MSGTRACE_VERSION 1 +enum msgtrace_hdr_type { + MSGTRACE_HDR_TYPE_MSG = 0u, + MSGTRACE_HDR_TYPE_LOG = 1u +}; + /* Message trace header */ typedef BWL_PRE_PACKED_STRUCT struct msgtrace_hdr { uint8 version; uint8 trace_type; -#define MSGTRACE_HDR_TYPE_MSG 0 -#define MSGTRACE_HDR_TYPE_LOG 1 uint16 len; /* Len of the trace */ uint32 seqnum; /* Sequence number of message. Useful if the messsage has been lost * because of DMA error or a bus reset (ex: SDIO Func2) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/nan.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/nan.h old mode 100755 new mode 100644 index dbbb8eef551a..3ced5eb92c7d --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/nan.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/nan.h @@ -2,7 +2,7 @@ * Fundamental types and constants relating to WFA NAN * (Neighbor Awareness Networking) * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -36,12 +36,18 @@ /* WiFi NAN OUI values */ #define NAN_OUI "\x50\x6F\x9A" /* WFA OUI. WiFi-Alliance OUI */ +#define NAN_OUI_LEN 3u /* NAN OUI length */ /* For oui_type field identifying the type and version of the NAN IE. */ #define NAN_OUI_TYPE 0x13 /* Type/Version */ #define NAN_AF_OUI_TYPE 0x18 /* Type/Version */ /* IEEE 802.11 vendor specific information element. (Same as P2P_IE_ID.) */ #define NAN_IE_ID 0xdd +#define NAN_IDENTITY_KEY_LIFETIME_SECONDS (24u*3600u) /* 24 hours. */ + +/* Default cipher version for pairing NIK KDE */ +#define NAN_SEC_NIK_DEFAULT_CIPHER_VER 0 + /* Same as P2P_PUB_AF_CATEGORY and DOT11_ACTION_CAT_PUBLIC */ #define NAN_PUB_AF_CATEGORY DOT11_ACTION_CAT_PUBLIC /* Protected dual public action frame category */ @@ -159,39 +165,45 @@ enum { NAN_ATTR_COUNTRY_CODE = 11, NAN_ATTR_RANGING = 12, NAN_ATTR_CLUSTER_DISC = 13, + /* nan 2.0 */ - NAN_ATTR_SVC_DESC_EXTENSION = 14, - NAN_ATTR_NAN_DEV_CAP = 15, - NAN_ATTR_NAN_NDP = 16, - NAN_ATTR_NAN_NMSG = 17, - NAN_ATTR_NAN_AVAIL = 18, - NAN_ATTR_NAN_NDC = 19, - NAN_ATTR_NAN_NDL = 20, - NAN_ATTR_NAN_NDL_QOS = 21, - NAN_ATTR_MCAST_SCHED = 22, - NAN_ATTR_UNALIGN_SCHED = 23, - NAN_ATTR_PAGING_UCAST = 24, - NAN_ATTR_PAGING_MCAST = 25, - NAN_ATTR_RANGING_INFO = 26, - NAN_ATTR_RANGING_SETUP = 27, - NAN_ATTR_FTM_RANGE_REPORT = 28, - NAN_ATTR_ELEMENT_CONTAINER = 29, - NAN_ATTR_WLAN_INFRA_EXT = 30, - NAN_ATTR_EXT_P2P_OPER = 31, - NAN_ATTR_EXT_IBSS = 32, - NAN_ATTR_EXT_MESH = 33, - NAN_ATTR_CIPHER_SUITE_INFO = 34, - NAN_ATTR_SEC_CTX_ID_INFO = 35, - NAN_ATTR_SHARED_KEY_DESC = 36, - NAN_ATTR_MCAST_SCHED_CHANGE = 37, - NAN_ATTR_MCAST_SCHED_OWNER_CHANGE = 38, - NAN_ATTR_PUBLIC_AVAILABILITY = 39, - NAN_ATTR_SUB_SVC_ID_LIST = 40, - NAN_ATTR_NDPE = 41, + NAN_ATTR_SVC_DESC_EXTENSION = 14, + NAN_ATTR_NAN_DEV_CAP = 15, + NAN_ATTR_NAN_NDP = 16, + NAN_ATTR_NAN_NMSG = 17, + NAN_ATTR_NAN_AVAIL = 18, + NAN_ATTR_NAN_NDC = 19, + NAN_ATTR_NAN_NDL = 20, + NAN_ATTR_NAN_NDL_QOS = 21, + NAN_ATTR_MCAST_SCHED = 22, + NAN_ATTR_UNALIGN_SCHED = 23, + NAN_ATTR_PAGING_UCAST = 24, + NAN_ATTR_PAGING_MCAST = 25, + NAN_ATTR_RANGING_INFO = 26, + NAN_ATTR_RANGING_SETUP = 27, + NAN_ATTR_FTM_RANGE_REPORT = 28, + NAN_ATTR_ELEMENT_CONTAINER = 29, + NAN_ATTR_WLAN_INFRA_EXT = 30, + NAN_ATTR_EXT_P2P_OPER = 31, + NAN_ATTR_EXT_IBSS = 32, + NAN_ATTR_EXT_MESH = 33, + NAN_ATTR_CIPHER_SUITE_INFO = 34, + NAN_ATTR_SEC_CTX_ID_INFO = 35, + NAN_ATTR_SHARED_KEY_DESC = 36, + NAN_ATTR_MCAST_SCHED_CHANGE = 37, + NAN_ATTR_MCAST_SCHED_OWNER_CHANGE = 38, + NAN_ATTR_PUBLIC_AVAILABILITY = 39, + NAN_ATTR_SUB_SVC_ID_LIST = 40, + NAN_ATTR_NDPE = 41, + NAN_ATTR_DEV_CAP_EXT = 42, /* NAN R4, Device Capability Extension */ + NAN_ATTR_NIRA = 43, /* NAN R4, Identity Resolution Attribute */ + NAN_ATTR_NPBA = 44, /* NAN R4, Pairing Bootstrapping Attribute */ + NAN_ATTR_S3 = 45, /* NAN R4, Sub Slot Schedule (S3) attribute */ + /* change NAN_ATTR_MAX_ID to max ids + 1, excluding NAN_ATTR_VENDOR_SPECIFIC. * This is used in nan_parse.c */ - NAN_ATTR_MAX_ID = NAN_ATTR_NDPE + 1, + NAN_ATTR_MAX_ID = NAN_ATTR_S3 + 1, NAN_ATTR_VENDOR_SPECIFIC = 221 }; @@ -252,6 +264,8 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_id_attr_s { #define NAN_SC_RANGE_LIMITED 0x20 /* Set to 1 if binding bitamp is present in descriptors */ #define NAN_SC_BINDING_BITMAP_PRESENT 0x40 +/* Max olength used for KDK in NAN R4 */ +#define NAN_SEC_MAX_KDK_LEN 32u /* Service descriptor */ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_descriptor_attr_s { @@ -287,7 +301,7 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ibss_attr_s { */ uint8 map_ctrl; /* avail. intervals bitmap, var len */ - uint8 avail_bmp[1]; + uint8 avail_bmp[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT wifi_nan_ibss_attr_t; /* Country code attribute */ @@ -309,7 +323,7 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_favail_attr_s { /* MAP id: val [0..15], values[16-255] reserved */ uint8 map_id; /* availibility entry, var len */ - uint8 avil_entry[1]; + uint8 avil_entry[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT wifi_nan_favail_attr_t; /* Further Availability MAP attr */ @@ -325,7 +339,7 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_avail_entry_s { /* channel number */ uint8 chan; /* avail bmp, var len */ - uint8 avail_bmp[1]; + uint8 avail_bmp[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT wifi_nan_avail_entry_t; /* Map control Field */ @@ -342,10 +356,10 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_avail_entry_s { /* TODO remove */ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_vendor_attr_s { uint8 id; /* 0xDD */ - uint16 len; /* IE length */ - uint8 oui[DOT11_OUI_LEN]; /* 00-90-4C */ - uint8 type; /* attribute type */ - uint8 attr[1]; /* var len attributes */ + uint16 len; /* IE length */ + uint8 oui[DOT11_OUI_LEN]; /* 00-90-4C */ + uint8 type; /* attribute type */ + uint8 attr[BCM_FLEX_ARRAY]; /* var len attributes */ } BWL_POST_PACKED_STRUCT wifi_nan_vendor_attr_t; #define NAN_VENDOR_HDR_SIZE (OFFSETOF(wifi_nan_vendor_attr_t, attr)) @@ -377,7 +391,7 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_p2p_op_attr_s { */ uint8 map_ctrl; /* avail. intervals bitmap */ - uint8 avail_bmp[1]; + uint8 avail_bmp[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT wifi_nan_p2p_op_attr_t; /* ranging attribute */ @@ -557,7 +571,7 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_container_attr_s { uint8 id; /* id - 0x20 */ uint16 len; /* Total length of following IEs */ uint8 map_id; /* map id */ - uint8 data[1]; /* Data pointing to one or more IEs */ + uint8 data[BCM_FLEX_ARRAY]; /* Data pointing to one or more IEs */ } BWL_POST_PACKED_STRUCT wifi_nan_container_attr_t; /* NAN 2.0 NAN avail attribute */ @@ -568,7 +582,7 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_avail_attr_s { uint16 len; /* total length */ uint8 seqid; /* sequence id */ uint16 ctrl; /* attribute control */ - uint8 entry[1]; /* availability entry list */ + uint8 entry[BCM_FLEX_ARRAY]; /* availability entry list */ } BWL_POST_PACKED_STRUCT wifi_nan_avail_attr_t; /* for processing/building time bitmap info in nan_avail_entry */ @@ -669,7 +683,7 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_channel_entry_s { typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_channel_entry_list_s { uint8 chan_info; - uint8 var[0]; + uint8 var[]; } BWL_POST_PACKED_STRUCT wifi_nan_channel_entry_list_t; /* define for chan_info */ @@ -786,6 +800,16 @@ enum #define NAN_CHAN_ENTRY_BW_LT_80MHZ 0 #define NAN_CHAN_ENTRY_BW_EQ_160MHZ 1 +/* Channel bitmap field for when opclass >=131 */ +#define NAN_CHAN_BITMAP_EXT_START_CHANNEL_MASK 0x00FF +#define NAN_CHAN_BITMAP_EXT_START_CHANNEL_SHIFT 0 +#define NAN_CHAN_BITMAP_EXT_NUM_CHANNEL_MASK 0xFF00 +#define NAN_CHAN_BITMAP_EXT_NUM_CHANNEL_SHIFT 8 +#define NAN_CHAN_BITMAP_EXT_NUM_CHANNEL(bmap) (((bmap) & NAN_CHAN_BITMAP_EXT_NUM_CHANNEL_MASK) \ + >> NAN_CHAN_BITMAP_EXT_NUM_CHANNEL_SHIFT) +#define NAN_CHAN_BITMAP_EXT_START_CHANNEL(bmap) (((bmap) & NAN_CHAN_BITMAP_EXT_START_CHANNEL_MASK) \ + >> NAN_CHAN_BITMAP_EXT_START_CHANNEL_SHIFT) + /* * NDL Attribute WFA Tech. Spec ver 1.0.r12 (section 10.7.19.2) */ @@ -899,6 +923,89 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_dev_cap_s { uint8 capabilities; /* DFS Master, Extended key id etc */ } BWL_POST_PACKED_STRUCT wifi_nan_dev_cap_t; +/* Regulatory info - operation types in 6G band, Table 126, NAN R4 spec. + * Also, see Table E-12, REVme_D1.0 + */ +typedef enum nan_mac_6g_op_type { + /* Indoor AP, i.e., LPI(Low Power Indoor) AP. + * AFC is not required but with some regulations to be indoor opeation. + */ + NAN_MAC_6G_OP_INDOOR_AP = 0, + + /* Standard Power AP, needs AFC coordination */ + NAN_MAC_6G_OP_SP_AP = 1, + + /* Very Low Power AP - VLP AP + * AFC is not required. Resticted with very low transmit power + * This is the default mode of all P2P devices. + */ + NAN_MAC_6G_OP_VLP_AP = 2, + + /* Indoor Enabled AP. + * Devices capable of receiving the "enabling signal" and configures itself to use + * C2C power level which is 10dB Higher than VLP AP. + */ + NAN_MAC_6G_OP_INDOOR_ENABLED_AP = 3, + + /* This is kind of hybrid mode (AFC in indoors). + * Devices opering in indoors and standard power mode with AFC. + */ + NAN_MAC_6G_OP_INDOOR_SP_AP = 4 +} nan_mac_6g_op_type_e; + +/* First byte of the extended capabilities is the regulatory info */ +typedef struct nan_mac_dev_cap_ext_reg_info_s { + uint8 reg_info_6g_present:1; /* bit0 */ + uint8 reg_info_6g:3; /* bits 1-3, see nan_mac_6g_op_type_e */ + uint8 reserved:4; /* bits 4-7 */ +} nan_mac_dev_cap_ext_reg_info_t; + +/* Byte1 (bits 8..15) of the extended capabilities */ +typedef struct nan_mac_dev_cap_ext_byte1_s { + uint8 pairing_setup:1; /* 1 -> NAN pairing enabled, 0 disabled */ + uint8 npk_nik_caching:1; /* 1 -> NPK/NIK caching enabled, 0 disabled */ + uint8 reserved:6; /* reserved */ +} nan_mac_dev_cap_ext_byte1_t; + +typedef struct nan_mac_dev_cap_ext_cap_data_s { + nan_mac_dev_cap_ext_reg_info_t reg_info; /* Byte0 (bits 0..7) in the data */ + nan_mac_dev_cap_ext_byte1_t byte1; /* Byte1 (bits 8..15) */ + /* add more bytes */ +} nan_mac_dev_cap_ext_cap_data_t; + +/* NAN R4 - Device Capability Extension Attribute */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_dev_cap_ext_s { + uint8 id; /* 0x2A */ + uint16 len; /* Length */ + /* Bit field with variable length in octets as indicated in the len field */ + uint8 data[]; +} BWL_POST_PACKED_STRUCT wifi_nan_dev_cap_ext_t; + +/* Fixed string for the NIK (NAN Identity Key) generation algorithm */ +static const uint8 nan_pairing_nik_prefix[] = "NIK Generation"; + +/* Caching NPK prefix */ +static const uint8 nan_pairing_npk_prefix[] = "NAN Opportunistic NPK Derivation"; + +/* Tag prefix */ +static const uint8 nan_pairing_tag_prefix[] = "NIR"; + +/* NAN Pairing (R4) reklated definitions */ +#define NAN_PAIRING_MAX_NPK_LEN 32u /* bytes */ +#define NAN_PAIRING_NPK_PREFIXES 4u /* Number of prefixes for NPK caching */ +#define NAN_PAIRING_NIK_PREFIXES 3u /* max number of prefixes */ +#define NAN_PAIRING_TAG_PREFIXES 3u /* Tag prefixes */ +#define NAN_PAIRING_RAND_BUF_LEN 32u /* random buffer length */ +#define NAN_PAIRING_SID_MAP_FULL 0xFFFFFFFFu /* session IDs in map are Full */ + +/* Cipher vesion lengths */ +#define NAN_PAIRING_CIPHER_VER_0_NIK_BITS 128u /* Number of bits */ +#define NAN_PAIRING_CIPHER_VER_0_NONCE_BITS 64u +#define NAN_PAIRING_CIPHER_VER_0_TAG_BITS 64u + +#define NAN_SSID "516F9A010000" /* NAN Network ID */ +#define NAN_SSID_len (sizeof(NAN_SSID) - 1) + /* map id related */ /* all maps */ @@ -937,12 +1044,15 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_dev_cap_s { #define NAN_DEV_CAP_COMMIT_DW_5G_SHIFT 3 #define NAN_DEV_CAP_COMMIT_DW_2G_OVERWRITE_SHIFT 6 #define NAN_DEV_CAP_COMMIT_DW_5G_OVERWRITE_SHIFT 10 + /* Operation Mode */ #define NAN_DEV_CAP_OP_PHY_MODE_HT_ONLY 0x00 #define NAN_DEV_CAP_OP_PHY_MODE_VHT 0x01 #define NAN_DEV_CAP_OP_PHY_MODE_VHT_8080 0x02 #define NAN_DEV_CAP_OP_PHY_MODE_VHT_160 0x04 +#define NAN_DEV_CAP_OP_PHY_MODE_HE_160 0x04 #define NAN_DEV_CAP_OP_PAGING_NDL 0x08 +#define NAN_DEV_CAP_OP_PHY_MODE_HE 0x10 #define NAN_DEV_CAP_OP_MODE_VHT_MASK 0x01 #define NAN_DEV_CAP_OP_MODE_VHT_SHIFT 0 @@ -952,6 +1062,8 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_dev_cap_s { #define NAN_DEV_CAP_OP_MODE_VHT160_SHIFT 2 #define NAN_DEV_CAP_OP_MODE_PAGING_NDL_MASK 0x08 #define NAN_DEV_CAP_OP_MODE_PAGING_NDL_SHIFT 3 +#define NAN_DEV_CAP_OP_MODE_HE_MASK 0x10 +#define NAN_DEV_CAP_OP_MODE_HE_SHIFT 4 #define NAN_DEV_CAP_RX_ANT_SHIFT 4 #define NAN_DEV_CAP_TX_ANT_MASK 0x0F @@ -964,15 +1076,31 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_dev_cap_s { /* DFS master capability */ #define NAN_DEV_CAP_DFS_MASTER_MASK 0x01 -#define NAN_DEV_CAP_DFS_MASTER_SHIFT 0 +#define NAN_DEV_CAP_DFS_MASTER_SHIFT 0u /* extended iv cap */ #define NAN_DEV_CAP_EXT_KEYID_MASK 0x02 -#define NAN_DEV_CAP_EXT_KEYID_SHIFT 1 +#define NAN_DEV_CAP_EXT_KEYID_SHIFT 1u +/* Simultaneous NDP data reception capability */ +#define NAN_DEV_CAP_SIMULTANEOUS_DATA_RECV_MASK 0x04 +#define NAN_DEV_CAP_SIMULTANEOUS_DATA_RECV_SHIFT 2u /* NDPE attribute support */ #define NAN_DEV_CAP_NDPE_ATTR_SUPPORT_MASK 0x08 +#define NAN_DEV_CAP_NDPE_ATTR_SUPPORT_SHIFT 3u #define NAN_DEV_CAP_NDPE_ATTR_SUPPORT(_cap) ((_cap) & NAN_DEV_CAP_NDPE_ATTR_SUPPORT_MASK) +/* S3 capability */ +#define NAN_DEV_CAP_S3_CAPABLE_MASK 0x10 +#define NAN_DEV_CAP_S3_CAPABLE_SHIFT 4u +#define NAN_DEV_CAP_S3_CAPABLE(_cap) ((_cap) & NAN_DEV_CAP_S3_CAPABLE_MASK) -/* Band IDs */ +#ifdef NAN_REKEY +#define NAN_DEV_CAP_PTK_REKEY_SUPPORT_MASK 0x10 +#define NAN_DEV_CAP_PTK_REKEY_SUPPORT_SHIFT 4u + +#define NAN_DEV_CAP_GTK_REKEY_SUPPORT_MASK 0x20 +#define NAN_DEV_CAP_GTK_REKEY_SUPPORT_SHIFT 5u +#endif /* NAN_REKEY */ + +/* Band IDs: See Table 99 in NAN R4 spec */ enum { NAN_BAND_ID_TVWS = 0, NAN_BAND_ID_SIG = 1, /* Sub 1 GHz */ @@ -980,14 +1108,29 @@ enum { NAN_BAND_ID_3G = 3, /* 3.6 GHz */ NAN_BAND_ID_5G = 4, /* 4.9 & 5 GHz */ NAN_BAND_ID_60G = 5, /* 60 GHz */ - NAN_BAND_ID_6G = 6 /* 6 GHz (proprietary) */ + NAN_BAND_ID_45G = 6, /* 45 GHz */ + NAN_BAND_ID_6G = 7 /* 6 GHz */ }; typedef uint8 nan_band_id_t; /* NAN supported band in device capability */ #define NAN_DEV_CAP_SUPPORTED_BANDS_2G (1 << NAN_BAND_ID_2G) #define NAN_DEV_CAP_SUPPORTED_BANDS_5G (1 << NAN_BAND_ID_5G) +#define NAN_DEV_CAP_SUPPORTED_BANDS_6G (1 << NAN_BAND_ID_6G) +/* NAN Supported Band ID bitmap, Table 72 in NAN R4 spec, + * bitmap of supported bands in the device capability attribute. + */ +typedef enum nan_mac_supp_band_flags { + NAN_MAC_SUPP_BAND_TV_WHITE_SPACES = (1u << 0u), /* bit0 */ + NAN_MAC_SUPP_BAND_SUB_1GHZ = (1u << 1u), + NAN_MAC_SUPP_BAND_2G = (1u << 2u), + NAN_MAC_SUPP_BAND_3G = (1u << 3u), + NAN_MAC_SUPP_BAND_5G = (1u << 4u), + NAN_MAC_SUPP_BAND_60G = (1u << 5u), + NAN_MAC_SUPP_BAND_45G = (1u << 6u), + NAN_MAC_SUPP_BAND_6G = (1u << 7u) /* bit7 */ +} nan_mac_supp_band_flags_e; /* * Unaligned schedule attribute section 10.7.19.6 spec. ver r15 */ @@ -1084,6 +1227,14 @@ typedef BWL_PRE_PACKED_STRUCT struct nan2_pub_act_frame_s { #define NAN_MGMT_FRM_SUBTYPE_SCHED_CONF 12 /* Schedule Update */ #define NAN_MGMT_FRM_SUBTYPE_SCHED_UPD 13 +#ifdef NAN_REKEY +/* Rekey Trigger frame */ +#define NAN_MGMT_FRM_SUBTYPE_REKEY_TRIGGER 14 +/* Group key request frame */ +#define NAN_MGMT_FRM_SUBTYPE_GRP_REKEY_REQ 15 +/* Group key response frame */ +#define NAN_MGMT_FRM_SUBTYPE_GRP_REKEY_RESP 16 +#endif /* NAN_REKEY */ /* Vendor specific NAN OOB AF subtype */ #define NAN_MGMT_FRM_SUBTYPE_NAN_OOB_AF 0xDD @@ -1105,6 +1256,7 @@ typedef BWL_PRE_PACKED_STRUCT struct nan2_pub_act_frame_s { #define NAN_REASON_QOS_UNACCEPT 0x9 #define NAN_REASON_NDP_REJECT 0xa #define NAN_REASON_NDL_UNACCEPTABLE 0xb +#define NAN_REASON_RNG_SCHED_UNACCEPTALE 0xc /* nan 2.0 qos (not attribute) */ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndp_qos_s { @@ -1116,12 +1268,27 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndp_qos_s { /* NDP control bitmap defines */ #define NAN_NDP_CTRL_CONFIRM_REQUIRED 0x01 +#ifdef NAN_REKEY +/* 0 = NDP setup, 1 = rekey handshake */ +#define NAN_NDP_CTRL_NDP_REKEY 0x02 +#endif /* NAN_REKEY */ #define NAN_NDP_CTRL_SECURTIY_PRESENT 0x04 #define NAN_NDP_CTRL_PUB_ID_PRESENT 0x08 #define NAN_NDP_CTRL_RESP_NDI_PRESENT 0x10 #define NAN_NDP_CTRL_SPEC_INFO_PRESENT 0x20 #define NAN_NDP_CTRL_RESERVED 0xA0 +#if defined(WL_NAN_GAF_PROTECT) || defined(NAN_GTK) +/* + * NDPE control bitmap defines + * currently NDP & NDPE share same control bitmap before b5 + * GTK/IGTK Required b5 + * 0: GTK/IGTK protection is not required + * 1: GTK/IGTK protection is required + */ +#define NAN_NDPE_CTRL_GTK_REQUIRED 0x20 +#endif /* WL_NAN_GAF_PROTECT || NAN_GTK */ + /* Used for both NDP Attribute and NDPE Attribute, since the structures are identical */ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndp_attr_s { uint8 id; /* NDP: 0x10, NDPE: 0x29 */ @@ -1141,13 +1308,26 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndp_attr_s { #define NAN_NDP_TYPE_CONFIRM 0x2 #define NAN_NDP_TYPE_SECURITY 0x3 #define NAN_NDP_TYPE_TERMINATE 0x4 +#ifdef NAN_REKEY +#define NAN_NDP_TYPE_REKEY 0x5 +#define NAN_NDP_TYPE_GRP_REKEY_REQ 0x6 +#define NAN_NDP_TYPE_GRP_REKEY_RESP 0x7 +#endif /* NAN_REKEY */ #define NAN_NDP_REQUEST(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == NAN_NDP_TYPE_REQUEST) #define NAN_NDP_RESPONSE(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == NAN_NDP_TYPE_RESPONSE) #define NAN_NDP_CONFIRM(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == NAN_NDP_TYPE_CONFIRM) #define NAN_NDP_SECURITY_INST(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == \ - NAN_NDP_TYPE_SECURITY) + NAN_NDP_TYPE_SECURITY) #define NAN_NDP_TERMINATE(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == \ - NAN_NDP_TYPE_TERMINATE) + NAN_NDP_TYPE_TERMINATE) +#ifdef NAN_REKEY +#define NAN_NDP_REKEY(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == \ + NAN_NDP_TYPE_REKEY) +#define NAN_NDP_GRP_REKEY_REQ(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == \ + NAN_NDP_TYPE_GRP_REKEY_REQ) +#define NAN_NDP_GRP_REKEY_RESP(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == \ + NAN_NDP_TYPE_GRP_REKEY_RESP) +#endif /* NAN_REKEY */ #define NAN_NDP_STATUS_SHIFT 4 #define NAN_NDP_STATUS_MASK 0xF0 #define NAN_NDP_STATUS_CONT (0 << NAN_NDP_STATUS_SHIFT) @@ -1268,6 +1448,60 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndc_attr_s { (((value) << NAN_NDC_ATTR_PROPOSED_NDC_SHIFT) & NAN_NDC_ATTR_PROPOSED_NDC_MASK)); \ } while (0) +/* NAN Subslot attribute */ +/* Subslot S3 schedule entry */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_s3_entry_s { + uint8 entry_ctrl; /* entry control */ + uint16 tbmp_ctrl; /* time bitmap control */ + uint16 tbmp_len; /* time bitmap len */ + uint8 tbmp[]; /* time bitmap */ +} BWL_POST_PACKED_STRUCT wifi_nan_s3_entry_t; + +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_subslot_attr_s { + uint8 id; + uint16 len; + uint8 var[]; /* One or more wifi_nan_s3_entry_t */ +} BWL_POST_PACKED_STRUCT wifi_nan_s3_attr_t; + +enum +{ + NAN_S3_TIME_BMP_BIT_DUR_1TU_IDX = 0, + NAN_S3_TIME_BMP_BIT_DUR_2TU_IDX = 1, + NAN_S3_TIME_BMP_BIT_DUR_4TU_IDX = 2, + NAN_S3_TIME_BMP_BIT_DUR_8TU_IDX = 3 +}; + +#define NAN_SUBSLOT_CTRL_MAP_ID_FULL 0x1F +#define NAN_SUBSLOT_CTRL_MAP_ID_MASK 0x1E +#define NAN_SUBSLOT_CTRL_MAP_ID_ALL 0x01 + +#define NAN_SUBSLOT_CTRL_MAP_ID(_ctrl) (((_ctrl) & NAN_SUBSLOT_CTRL_MAP_ID_MASK) >> 1) +#define NAN_SUBSLOT_CTRL_MAP_ID_ALLMAP(_ctrl) ((_ctrl) & NAN_SUBSLOT_CTRL_MAP_ID_ALL) +#define NAN_SUBSLOT_CTRL_IMMUTABLE(_ctrl) ((_ctrl) & 0x20) +#define NAN_SUBSLOT_SET_CTRL_IMMUTABLE(_ctrl) ((_ctrl) |= ((_ctrl) | 0x20)) + +#define NAN_S3_TIME_BMAP_CTRL_BITDUR_MASK 0x03 +#define NAN_S3_TIME_BMAP_CTRL_BITDUR(_flags) ((_flags) & NAN_S3_TIME_BMAP_CTRL_BITDUR_MASK) + +#define NAN_S3_TIME_BMAP_CTRL_PERIOD_MASK 0x3C +#define NAN_S3_TIME_BMAP_CTRL_PERIOD_SHIFT 0x2 +#define NAN_S3_TIME_BMAP_CTRL_PERIOD(_flags) (((_flags) & NAN_S3_TIME_BMAP_CTRL_PERIOD_MASK) \ + >> NAN_S3_TIME_BMAP_CTRL_PERIOD_SHIFT) + +#define NAN_S3_TIME_BMAP_CTRL_OFFSET_MASK 0x7FC0 +#define NAN_S3_TIME_BMAP_CTRL_OFFSET_SHIFT 6 +#define NAN_S3_TIME_BMAP_CTRL_OFFSET(_flags) (((_flags) & NAN_S3_TIME_BMAP_CTRL_OFFSET_MASK) \ + >> NAN_S3_TIME_BMAP_CTRL_OFFSET_SHIFT) +#define NAN_S3_MIN_AVAIL_ATTR_SIZE(n) (OFFSETOF(wifi_nan_s3_attr_t, var) + \ + ((n) * OFFSETOF(wifi_nan_s3_entry_t, tbmp))) +#define NAN_S3_ENTRY_MIN_SIZE OFFSETOF(wifi_nan_s3_entry_t, tbmp) +#define NAN_S3_ENTRY_SIZE(_entry) (NAN_S3_ENTRY_MIN_SIZE + (_entry)->tbmp_len) + +/* mandatory fields in subslot attribute for given avail entries */ +#define NAN_AVAIL_MIN_SUBSLOT_ATTR_SIZE(n) (OFFSETOF(wifi_nan_s3_attr_t, var) + \ + ((n) * OFFSETOF(wifi_nan_s3_entry_t, tbmp))) +#define NAN_SUBSLOT_TIME_BITMAP_HDR_LEN OFFSETOF(wifi_nan_s3_entry_t, bitmap) + /* Service descriptor extension attribute */ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_desc_ext_attr_s { /* Attribute ID - 0x11 */ @@ -1305,6 +1539,9 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_desc_ext_attr_s { #define NAN_SDE_CF_RANGING_REQUIRED (1 << 7) #define NAN_SDE_CF_RANGE_PRESENT (1 << 8) #define NAN_SDE_CF_SVC_UPD_IND_PRESENT (1 << 9) +#if defined(WL_NAN_GAF_PROTECT) || defined(NAN_GTK) +#define NAN_SDE_CF_GTK_REQUIRED (1u << 10u) +#endif /* WL_NAN_GAF_PROTECT || NAN_GTK */ /* Using Reserved Bits as per Spec */ #define NAN_SDE_CF_LIFE_CNT_PUB_RX (1 << 15) #define NAN_SDE_FSD_REQUIRED(_sde) ((_sde)->control & NAN_SDE_CF_FSD_REQUIRED) @@ -1324,19 +1561,78 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_desc_ext_attr_s { /* * Cipher suite information Attribute. * WFA Tech. Spec ver 1.0.r21 (section 10.7.24.2) + * Bit 0 is 0 for 4 PTKSA replay counters + * Bit 0 is 1 for 16 PTKSA replay counters + * Bit 1 and 2: + * 00: GTKSA, IGTKSA, BIGTKSA are not supported; + * 01: GTKSA and IGTKSA are supported, and BIGTKSA is not supported; + * 10: GTKSA, IGTKSA, and BIGTKSA are supported; + * 11: Reserved; + * Bit 3 is 0 for 4 GTKSA replay counters, if GTKSA is supported + * Bit 3 is 1 for 16 GTKSA replay counters, if GTKSA is supported + * Bit 4 is 0: BIP-CMAC-128 is selected for transmit, if IGTKSA or BIGTKSA is supported + * Bit 4 is 1: BIP-GMAC-256 is selected for transmit, if IGTKSA or BIGTKSA is supported + * Bit 5 is 0 if IRK is not supported + * Bit 5 is 1 if IRK is supported + * Bit 7 is reserved */ -#define NAN_SEC_CIPHER_SUITE_CAP_REPLAY_4 0 -#define NAN_SEC_CIPHER_SUITE_CAP_REPLAY_16 (1 << 0) +#define NAN_SEC_CIPHER_SUITE_CAP_REPLAY_4 0u +#define NAN_SEC_CIPHER_SUITE_CAP_REPLAY_16 (1u << 0u) -/* enum security algo. -*/ +#if defined(WL_NAN_GAF_PROTECT) || defined(NAN_GTK) +/* Defines for GTK, IGTK and BIGTK */ +/* + * Bit 1 and 2: + * 00: GTKSA, IGTKSA, BIGTKSA are not supported; + * 01: GTKSA and IGTKSA are supported, and BIGTKSA is not supported; + * 10: GTKSA, IGTKSA, and BIGTKSA are supported; + * 11: Reserved; + */ +#define NAN_SEC_CIPHER_SUITE_CAP_DIS_GTK_IGTK_BIGTK (0 << 1) +#define NAN_SEC_CIPHER_SUITE_CAP_DIS_BIGTK (1 << 1) +#define NAN_SEC_CIPHER_SUITE_CAP_ENAB_GTK_IGTK_BIGTK (1 << 2) + +/* + * Bit 3 is 0 for 4 GTKSA replay counters, if GTKSA is supported + * Bit 3 is 1 for 16 GTKSA replay counters, if GTKSA is supported + */ +#define NAN_SEC_CIPHER_SUITE_CAP_GTK_REPLAY_4 (0 << 4) +#define NAN_SEC_CIPHER_SUITE_CAP_GTK_REPLAY_16 (1 << 4) + +/* + * Bit 4 is 0: BIP-CMAC-128 is selected for transmit, if IGTKSA or BIGTKSA is supported + * Bit 4 is 1: BIP-GMAC-256 is selected for transmit, if IGTKSA or BIGTKSA is supported + */ +#define NAN_SEC_CIPHER_SUITE_CAP_BIP_CMAC_128 (0) +#define NAN_SEC_CIPHER_SUITE_CAP_BIP_GMAC_256 (1 << 5) + +#define NAN_SEC_BIP_ENABLED(cap) ((cap) & \ + (NAN_SEC_CIPHER_SUITE_CAP_ENAB_GTK_IGTK_BIGTK | \ + NAN_SEC_CIPHER_SUITE_CAP_DIS_BIGTK)) + +#define NAN_SEC_BIP_CAP_TO_CIPER(cap) \ + (((cap) & NAN_SEC_CIPHER_SUITE_CAP_BIP_GMAC_256) ?\ + CRYPTO_ALGO_BIP_GMAC256 : CRYPTO_ALGO_BIP) +#define NAN_SEC_IGTK_ENABLED(cap) NAN_SEC_BIP_ENABLED(cap) + +#define NAN_SEC_BIGTK_ENABLED(cap) ((cap) & \ + (NAN_SEC_CIPHER_SUITE_CAP_ENAB_GTK_IGTK_BIGTK)) +#endif /* WL_NAN_GAF_PROTECT || NAN_GTK */ + +/* enum security algo. */ enum nan_sec_csid { - NAN_SEC_ALGO_NONE = 0, + NAN_SEC_ALGO_NONE = 0, /* default, open */ NAN_SEC_ALGO_NCS_SK_CCM_128 = 1, /* CCMP 128 */ NAN_SEC_ALGO_NCS_SK_GCM_256 = 2, /* GCMP 256 */ - NAN_SEC_ALGO_LAST = 3 + NAN_SEC_ALGO_NCS_PK_CCM_128 = 3, /* CCMP 128 */ + NAN_SEC_ALGO_NCS_PK_GCM_256 = 4, /* GCMP 256 */ + NAN_SEC_ALGO_NCS_GK_CCM_128 = 5, /* CCMP 128 */ + NAN_SEC_ALGO_NCS_GK_GCM_256 = 6, /* GCMP 256 */ + NAN_SEC_ALGO_NCS_PK_PASN_CCM_128 = 7, /* CCMP 128, NAN R4 */ + NAN_SEC_ALGO_NCS_PK_PASN_GCM_256 = 8, /* GCMP 256, NAN R4 */ + NAN_SEC_ALGO_LAST }; -typedef int8 nan_sec_csid_e; +typedef uint8 nan_sec_csid_e; /* nan2 cipher suite attribute field */ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_sec_cipher_suite_field_s { @@ -1352,6 +1648,13 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_sec_cipher_suite_info_attr_s { uint8 var[]; /* cipher suite list */ } BWL_POST_PACKED_STRUCT wifi_nan_sec_cipher_suite_info_attr_t; +/* Currently cipher suite list supports maximum of 2 entries */ +#define NAN_SEC_CIPHER_SUITE_LIST_MAX_ENTRIES 2u +#define NAN_SEC_CIPHER_SUITE_FIELD_LEN 2u +#define NAN_SEC_CIPHER_SUITE_INFO_LEN_MIN 1u /* capabilities field only */ +#define NAN_SEC_CIPHER_SUITE_INFO_LEN_MAX (NAN_SEC_CIPHER_SUITE_INFO_LEN_MIN + \ + (NAN_SEC_CIPHER_SUITE_FIELD_LEN * NAN_SEC_CIPHER_SUITE_LIST_MAX_ENTRIES)) + /* * Security context identifier attribute * WFA Tech. Spec ver 1.0.r21 (section 10.7.24.4) @@ -1379,8 +1682,10 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_sec_ctx_id_info_attr_s { * WFA Tech. Spec ver 23 */ -#define NAN_SEC_NCSSK_DESC_REPLAY_CNT_LEN 8 -#define NAN_SEC_NCSSK_DESC_KEY_NONCE_LEN 32 +#define NAN_SEC_NCSSK_DESC_REPLAY_CNT_LEN 8u +#define NAN_SEC_NCSSK_DESC_KEY_NONCE_LEN 32u +#define NAN_SEC_NCSSK_DESC_KEY_IV_LEN 16u +#define NAN_SEC_NCSSK_DESC_KEY_RSC_LEN 8u /* nan shared key descriptor attr field */ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_sec_ncssk_key_desc_attr_s { @@ -1392,7 +1697,9 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_sec_ncssk_key_desc_attr_s { uint16 key_len; uint8 key_replay_cntr[NAN_SEC_NCSSK_DESC_REPLAY_CNT_LEN]; uint8 key_nonce[NAN_SEC_NCSSK_DESC_KEY_NONCE_LEN]; - uint8 reserved[32]; /* EAPOL IV + Key RSC + Rsvd fields in EAPOL Key */ + uint8 key_iv[NAN_SEC_NCSSK_DESC_KEY_IV_LEN]; + uint8 key_rsc[NAN_SEC_NCSSK_DESC_KEY_RSC_LEN]; + uint8 reserved[8]; uint8 mic[]; /* mic + key data len + key data */ } BWL_POST_PACKED_STRUCT wifi_nan_sec_ncssk_key_desc_attr_t; @@ -1556,6 +1863,50 @@ typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_fac_chan_entry_s { NAN_FRM_RNG_RESP_AF | NAN_FRM_RNG_REPORT_AF | \ NAN_FRM_RNG_TERM_AF) +/* Generic NAN attribute data strucutre */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_attr_s { + uint8 id; /* attribute id */ + uint16 len; /* length following */ + uint8 data[]; /* attribute data */ +} BWL_POST_PACKED_STRUCT wifi_nan_attr_t; + +/* NIRA cipher versions */ + +/* Version 0 means 128-bit NIK, 64-bit Nonce, 64-bit Tag, HMAC-SHA-256 */ +#define NAN_MAC_CIPHER_VERSION_0 0u + +/* NIRA (NAN Identity Resolution Attribute) */ +typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_nira_attr_s { + uint8 id; /* attribute id */ + uint16 len; /* length following */ + uint8 cipher_version; /* cipher version */ + + /* Nonce and Tag lengths are determined based on the cipher_verison */ + /* variable Nonce */ + /* variable Tag */ +} BWL_POST_PACKED_STRUCT wifi_nan_nira_attr_t; + +#define NAN_SEC_NCS_SK_PMKID_CONST "NAN PMK Name" +#define NAN_SEC_NCS_SK_PTK_CONST "NAN Pairwise key expansion" +#define NAN_SEC_NCS_PK_KEK_CONST "NAN Management KEK Derivation" +#define NAN_SEC_NCS_PK_PMK_CONST "NDP PMK Derivation" + +#define NAN_IDENTITY_KEY_LENGTH 16u +/* NIK KDE */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 cipher; + uint8 nik[]; +} BWL_POST_PACKED_STRUCT nan_identity_key_t; + +/* Lifetime KDE */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 key_bitmap; + uint32 lifetime; +} BWL_POST_PACKED_STRUCT nan_key_lifetime_t; + +#define NAN_KEY_DATA_SUBTYPE_NIK 36 +#define NAN_KEY_DATA_SUBTYPE_LIFETIME 37 + /* This marks the end of a packed structure section. */ #include diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/nci.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/nci.h deleted file mode 100755 index 188016ad1203..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/nci.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Misc utility routines for accessing chip-specific features - * of the BOOKER NCI (non coherent interconnect) based Broadcom chips. - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - * - */ - -#ifndef _NCI_H -#define _NCI_H - -#include - -#ifdef SOCI_NCI_BUS -void nci_uninit(void *nci); -uint32 nci_scan(si_t *sih); -void nci_dump_erom(void *nci); -void* nci_init(si_t *sih, chipcregs_t *cc, uint bustype); -volatile void *nci_setcore(si_t *sih, uint coreid, uint coreunit); -volatile void *nci_setcoreidx(si_t *sih, uint coreidx); -uint nci_findcoreidx(const si_t *sih, uint coreid, uint coreunit); -volatile uint32 *nci_corereg_addr(si_t *sih, uint coreidx, uint regoff); -uint nci_corereg_writeonly(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); -uint nci_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); -uint nci_corerev_minor(const si_t *sih); -uint nci_corerev(const si_t *sih); -uint nci_corevendor(const si_t *sih); -uint nci_get_wrap_reg(const si_t *sih, uint32 offset, uint32 mask, uint32 val); -void nci_core_reset(const si_t *sih, uint32 bits, uint32 resetbits); -void nci_core_disable(const si_t *sih, uint32 bits); -bool nci_iscoreup(const si_t *sih); -uint32 nci_coreid(const si_t *sih, uint coreidx); -uint nci_numcoreunits(const si_t *sih, uint coreid); -uint32 nci_addr_space(const si_t *sih, uint spidx, uint baidx); -uint32 nci_addr_space_size(const si_t *sih, uint spidx, uint baidx); -bool nci_iscoreup(const si_t *sih); -uint nci_intflag(si_t *sih); -uint nci_flag(si_t *sih); -uint nci_flag_alt(const si_t *sih); -void nci_setint(const si_t *sih, int siflag); -uint32 nci_oobr_baseaddr(const si_t *sih, bool second); -uint nci_coreunit(const si_t *sih); -uint nci_corelist(const si_t *sih, uint coreid[]); -int nci_numaddrspaces(const si_t *sih); -uint32 nci_addrspace(const si_t *sih, uint spidx, uint baidx); -uint32 nci_addrspacesize(const si_t *sih, uint spidx, uint baidx); -void nci_coreaddrspaceX(const si_t *sih, uint asidx, uint32 *addr, uint32 *size); -uint32 nci_core_cflags(const si_t *sih, uint32 mask, uint32 val); -void nci_core_cflags_wo(const si_t *sih, uint32 mask, uint32 val); -uint32 nci_core_sflags(const si_t *sih, uint32 mask, uint32 val); -uint nci_wrapperreg(const si_t *sih, uint32 offset, uint32 mask, uint32 val); -void nci_invalidate_second_bar0win(si_t *sih); -int nci_backplane_access(si_t *sih, uint addr, uint size, uint *val, bool read); -int nci_backplane_access_64(si_t *sih, uint addr, uint size, uint64 *val, bool read); -uint nci_num_slaveports(const si_t *sih, uint coreid); -#if defined(BCMDBG) || defined(BCMDBG_DUMP) || defined(BCMDBG_PHYDUMP) -void nci_dumpregs(const si_t *sih, struct bcmstrbuf *b); -#endif /* BCMDBG || BCMDBG_DUMP || BCMDBG_PHYDUMP */ -#ifdef BCMDBG -void nci_view(si_t *sih, bool verbose); -void nci_viewall(si_t *sih, bool verbose); -#endif /* BCMDBG */ -uint32 nci_get_nth_wrapper(const si_t *sih, int32 wrap_pos); -uint32 nci_get_axi_addr(const si_t *sih, uint32 *size); -uint32* nci_wrapper_dump_binary_one(const si_info_t *sii, uint32 *p32, uint32 wrap_ba); -uint32 nci_wrapper_dump_binary(const si_t *sih, uchar *p); -uint32 nci_wrapper_dump_last_timeout(const si_t *sih, uint32 *error, - uint32 *core, uint32 *ba, uchar *p); -bool nci_check_enable_backplane_log(const si_t *sih); -uint32 nci_get_core_baaddr(const si_t *sih, uint32 *size, int32 baidx); -uint32 nci_clear_backplane_to(si_t *sih); -uint32 nci_clear_backplane_to_per_core(si_t *sih, uint coreid, uint coreunit, void *wrap); -bool nci_ignore_errlog(const si_info_t *sii, const aidmp_t *ai, - uint32 lo_addr, uint32 hi_addr, uint32 err_axi_id, uint32 errsts); -void nci_wrapper_get_last_error(const si_t *sih, uint32 *error_status, uint32 *core, uint32 *lo, - uint32 *hi, uint32 *id); -uint32 nci_get_axi_timeout_reg(void); -uint32 nci_findcoreidx_by_axiid(const si_t *sih, uint32 axiid); -uint32* nci_wrapper_dump_binary_one(const si_info_t *sii, uint32 *p32, uint32 wrap_ba); -uint32 nci_wrapper_dump_binary(const si_t *sih, uchar *p); -uint32 nci_wrapper_dump_last_timeout(const si_t *sih, uint32 *error, - uint32 *core, uint32 *ba, uchar *p); -bool nci_check_enable_backplane_log(const si_t *sih); -uint32 ai_wrapper_dump_buf_size(const si_t *sih); -uint32 nci_wrapper_dump_buf_size(const si_t *sih); -#endif /* SOCI_NCI_BUS */ -#endif /* _NCI_H */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl.h old mode 100755 new mode 100644 index 7ea182e1c9cb..175a4ea621a8 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl.h @@ -1,7 +1,7 @@ /* * OS Abstraction Layer * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -32,9 +32,7 @@ enum { TAIL_BYTES_TYPE_MIC = 3 }; -#ifdef DHD_EFI -#define OSL_PKTTAG_SZ 40 /* Size of PktTag */ -#elif defined(MACOSX) +#if defined(MACOSX) #define OSL_PKTTAG_SZ 56 #elif defined(__linux__) #define OSL_PKTTAG_SZ 48 /* standard linux pkttag size is 48 bytes */ @@ -42,7 +40,7 @@ enum { #ifndef OSL_PKTTAG_SZ #define OSL_PKTTAG_SZ 32 /* Size of PktTag */ #endif /* !OSL_PKTTAG_SZ */ -#endif /* DHD_EFI */ +#endif /* Drivers use PKTFREESETCB to register a callback function when a packet is freed by OSL */ typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status); @@ -63,6 +61,8 @@ typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, #elif defined(_RTE_) #include #include +#elif defined(COEX_OSL) +#include #elif defined(MACOSX) #include #else @@ -91,6 +91,25 @@ typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, #define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) #endif /* !OR_REG */ +/** + * @brief API to either read or read, modify, write, read a 32bit register. + * Modify the value in a register. If the mask or val are not zero, this will bitwise-or val into + * the register at the address after masking the value read from the register with the provided + * mask. This process is sometimes referred to as Read-Modify-Write (RMW). This replaces the + * functionality provided by si_corereg for the dongle. When mask and val are zero, this macro + * behaves the same as R_REG. + * @param addr Backplane address to perform an operation on as a uint32. + * @param mask Bitmask for the value that will be written. + * @param val Value to and into the register at the address. + * @return The value in the register at the provided address after the optional write. + */ +#define RMWR_REG(addr, mask, val) ({ \ + if ((mask != 0) || (val != 0)) { \ + SET_REG(NULL, (uint32 *)(addr), (mask), (val)); \ + } \ + R_REG(NULL, (uint32 *)(addr)); \ +}) + #if !defined(OSL_SYSUPTIME) #define OSL_SYSUPTIME() (0) #define OSL_SYSUPTIME_NOT_DEFINED 1 @@ -128,6 +147,14 @@ typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, #define OSL_CPU_COUNTS_PER_US_NOT_DEFINED 1 #endif /* !defined(OSL_CPU_COUNTS_PER_US) */ +#if !defined(OSL_GET_PMU_ACCU_TICK_US) +#define OSL_GET_PMU_ACCU_TICK_US(val) (0) +#endif /* !OSL_GET_PMU_ACCU_TICK_US */ + +#if !defined(OSL_GET_PMU_ACCU_TICK64_US) +#define OSL_GET_PMU_ACCU_TICK64_US(val) (0) +#endif /* !OSL_GET_PMU_ACCU_TICK64_US */ + #ifndef OSL_SYS_HALT #ifdef __COVERITY__ /* @@ -151,29 +178,9 @@ typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, #endif #ifndef OSL_OBFUSCATE_BUF -#if defined (_RTE_) -#define OSL_OBFUSCATE_BUF(x) osl_obfuscate_ptr(x) -#else #define OSL_OBFUSCATE_BUF(x) (x) -#endif /* _RTE_ */ #endif /* OSL_OBFUSCATE_BUF */ -#ifndef OSL_GET_HCAPISTIMESYNC -#if defined (_RTE_) -#define OSL_GET_HCAPISTIMESYNC() osl_get_hcapistimesync() -#else -#define OSL_GET_HCAPISTIMESYNC() -#endif /* _RTE_ */ -#endif /* OSL_GET_HCAPISTIMESYNC */ - -#ifndef OSL_GET_HCAPISPKTTXS -#if defined (_RTE_) -#define OSL_GET_HCAPISPKTTXS() osl_get_hcapispkttxs() -#else -#define OSL_GET_HCAPISPKTTXS() -#endif /* _RTE_ */ -#endif /* OSL_GET_HCAPISPKTTXS */ - #if !defined(PKTC_DONGLE) #define PKTCGETATTR(skb) (0) #define PKTCSETATTR(skb, f, p, b) BCM_REFERENCE(skb) @@ -226,7 +233,6 @@ do { \ #define PKTSETPROFILEIDX(p, idx) BCM_REFERENCE(idx) #endif -#ifndef _RTE_ /* Lbuf with fraglist */ #ifndef PKTFRAGPKTID #define PKTFRAGPKTID(osh, lb) (0) @@ -401,9 +407,8 @@ do { \ #ifndef PKTSETUDR #define PKTRESETUDR(osh, lb) BCM_REFERENCE(osh) #endif -#endif /* _RTE_ */ -#if !(defined(__linux__)) +#if !defined(__linux__) #define PKTLIST_INIT(x) BCM_REFERENCE(x) #define PKTLIST_ENQ(x, y) BCM_REFERENCE(x) #define PKTLIST_DEQ(x) BCM_REFERENCE(x) @@ -427,14 +432,6 @@ do { \ #define MALLOC_RA(osh, size, callsite) MALLOCZ(osh, size) #endif /* !MALLOC_RA */ -#ifndef MALLOC_PERSIST_ATTACH - #define MALLOC_PERSIST_ATTACH MALLOC -#endif /* !MALLOC_PERSIST_ATTACH */ - -#ifndef MALLOCZ_PERSIST_ATTACH - #define MALLOCZ_PERSIST_ATTACH MALLOCZ -#endif /* !MALLOCZ_PERSIST_ATTACH */ - #ifndef MALLOCZ_NOPERSIST #define MALLOCZ_NOPERSIST MALLOCZ #endif /* !MALLOCZ_NOPERSIST */ @@ -479,4 +476,55 @@ do { \ #define OSL_PHYS_TO_VIRT_ADDR(pa) ((void*)(uintptr)(pa)) #endif +#ifndef DBG_PKTLEAK +#define PKTSETQCALLER(lb, queue, caller_addr) +#define PKTSETQCALLER_LIST(head, npkts, queue, caller_addr) +#endif /* DBG_PKTLEAK */ + +/* Memory breakup capturing macros */ +#ifdef BCMDBG_MEM_BREAKUP +#define MB_START(var) \ + uint mb_memuse_before_##var = MALLOCED(NULL) + +#define MB_END(var, fmt, ...) \ + do { \ + uint mb_memuse_##var = MALLOCED(NULL) - mb_memuse_before_##var; \ + if (mb_memuse_##var) { \ + printf("[MB] " fmt, ##__VA_ARGS__); \ + printf(" %d\n", mb_memuse_##var); \ + } \ + } while (0) +#else +#define MB_START(var) +#define MB_END(var, fmt, ...) +#endif /* BCMDBG_MEM_BREAKUP */ + +/* ASSERT NULL check should not be enabled for ROM build */ +#if defined(BCMROMBUILD) && defined(ENABLE_ASSERT_NULL) +#error "Do not enable ENABLE_ASSERT_NULL for ROM builds..." +#endif + +#ifdef ENABLE_ASSERT_NULL +#define ASSERT_NULL(expr) ASSERT(expr) +#else +#define ASSERT_NULL(expr) // do nothing +#endif /* ENABLE_ASSERT_NULL */ + +#if defined(DONGLEBUILD) && !defined(BCM_MEM_PERSIST_ENABLE) +#ifdef MALLOC_PERSIST +#undef MALLOC_PERSIST +#endif /* MALLOC_PERSIST */ +#define MALLOC_PERSIST MALLOC + +#ifdef MALLOCZ_PERSIST +#undef MALLOCZ_PERSIST +#endif /* MALLOCZ_PERSIST */ +#define MALLOCZ_PERSIST MALLOCZ + +#ifdef MFREE_PERSIST +#undef MFREE_PERSIST +#endif /* MFREE_PERSIST */ +#define MFREE_PERSIST MFREE +#endif /* DONGLEBUILD && !BCM_MEM_PERSIST_ENABLE */ + #endif /* _osl_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl_decl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl_decl.h old mode 100755 new mode 100644 index a86805a5a629..898fb0f9ca41 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl_decl.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl_decl.h @@ -1,7 +1,7 @@ /* * osl forward declarations * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl_ext.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl_ext.h old mode 100755 new mode 100644 index 460bc3a23fd6..33084e3df4f4 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl_ext.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/osl_ext.h @@ -2,7 +2,7 @@ * OS Abstraction Layer Extension - the APIs defined by the "extension" API * are only supported by a subset of all operating systems. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/p2p.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/p2p.h old mode 100755 new mode 100644 index 727fe969cb9c..87d9057db402 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/p2p.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/p2p.h @@ -1,7 +1,7 @@ /* * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -40,11 +40,11 @@ /* WiFi P2P IE */ BWL_PRE_PACKED_STRUCT struct wifi_p2p_ie { - uint8 id; /* IE ID: 0xDD */ - uint8 len; /* IE length */ - uint8 OUI[3]; /* WiFi P2P specific OUI: P2P_OUI */ - uint8 oui_type; /* Identifies P2P version: P2P_VER */ - uint8 subelts[1]; /* variable length subelements */ + uint8 id; /* IE ID: 0xDD */ + uint8 len; /* IE length */ + uint8 OUI[3]; /* WiFi P2P specific OUI: P2P_OUI */ + uint8 oui_type; /* Identifies P2P version: P2P_VER */ + uint8 subelts[BCM_FLEX_ARRAY]; /* variable length subelements */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2p_ie wifi_p2p_ie_t; @@ -157,20 +157,20 @@ typedef struct wifi_p2p_grp_bssid_se_s wifi_p2p_grp_bssid_se_t; /* WiFi P2P IE subelement: P2P Group ID */ BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_id_se_s { - uint8 eltId; /* SE ID: P2P_SEID_GROUP_ID */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mac[6]; /* P2P device address */ - uint8 ssid[1]; /* ssid. device id. variable length */ + uint8 eltId; /* SE ID: P2P_SEID_GROUP_ID */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* P2P device address */ + uint8 ssid[BCM_FLEX_ARRAY]; /* ssid. device id. variable length */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2p_grp_id_se_s wifi_p2p_grp_id_se_t; /* WiFi P2P IE subelement: P2P Interface */ BWL_PRE_PACKED_STRUCT struct wifi_p2p_intf_se_s { - uint8 eltId; /* SE ID: P2P_SEID_P2P_IF */ - uint8 len[2]; /* SE length not including eltId, len fields */ - uint8 mac[6]; /* P2P device address */ - uint8 ifaddrs; /* P2P Interface Address count */ - uint8 ifaddr[1][6]; /* P2P Interface Address list */ + uint8 eltId; /* SE ID: P2P_SEID_P2P_IF */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* P2P device address */ + uint8 ifaddrs; /* P2P Interface Address count */ + uint8 ifaddr[BCM_FLEX_ARRAY][6]; /* P2P Interface Address list */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2p_intf_se_s wifi_p2p_intf_se_t; @@ -369,7 +369,7 @@ BWL_PRE_PACKED_STRUCT struct wifi_p2p_serv_hash_se_s { uint8 len[2]; /* SE length not including eltId, len fields * in multiple of 6 Bytes */ - uint8 hash[1]; /* Variable length - SHA256 hash of + uint8 hash[BCM_FLEX_ARRAY]; /* Variable length - SHA256 hash of * service names (can be more than one hashes) */ } BWL_POST_PACKED_STRUCT; @@ -377,11 +377,11 @@ typedef struct wifi_p2p_serv_hash_se_s wifi_p2p_serv_hash_se_t; /* WiFi P2P IE subelement: Service Instance Data */ BWL_PRE_PACKED_STRUCT struct wifi_p2p_serv_inst_data_se_s { - uint8 eltId; /* SE ID: P2P_SEID_SESSION */ - uint8 len[2]; /* SE length not including eltId, len */ - uint8 ssn_info[1]; /* Variable length - Session information as specified by - * the service layer, type matches serv. name - */ + uint8 eltId; /* SE ID: P2P_SEID_SESSION */ + uint8 len[2]; /* SE length not including eltId, len */ + uint8 ssn_info[BCM_FLEX_ARRAY]; /* Session information as specified by + * the service layer, type matches serv. name + */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2p_serv_inst_data_se_s wifi_p2p_serv_inst_data_se_t; @@ -408,10 +408,10 @@ typedef struct wifi_p2p_advt_id_se_s wifi_p2p_advt_id_se_t; /* WiFi P2P IE subelement: Advertise Service Hash */ BWL_PRE_PACKED_STRUCT struct wifi_p2p_adv_serv_info_s { - uint8 advt_id[4]; /* SE Advertise ID for the service */ - uint16 nw_cfg_method; /* SE Network Config method for the service */ - uint8 serv_name_len; /* SE length of the service name */ - uint8 serv_name[1]; /* Variable length service name field */ + uint8 advt_id[4]; /* SE Advertise ID for the service */ + uint16 nw_cfg_method; /* SE Network Config method for the service */ + uint8 serv_name_len; /* SE length of the service name */ + uint8 serv_name[1]; /* service name field */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2p_adv_serv_info_s wifi_p2p_adv_serv_info_t; @@ -421,7 +421,8 @@ BWL_PRE_PACKED_STRUCT struct wifi_p2p_advt_serv_se_s { uint8 len[2]; /* SE length not including eltId, len fields mutiple len of * wifi_p2p_adv_serv_info_t entries */ - wifi_p2p_adv_serv_info_t p_advt_serv_info[1]; /* Variable length + wifi_p2p_adv_serv_info_t p_advt_serv_info[BCM_FLEX_ARRAY]; + /* Variable length of multiple instances of the advertise service info */ @@ -446,14 +447,14 @@ typedef struct wifi_p2p_ssn_id_se_s wifi_p2p_ssn_id_se_t; /* WiFi P2P Action Frame */ BWL_PRE_PACKED_STRUCT struct wifi_p2p_action_frame { - uint8 category; /* P2P_AF_CATEGORY */ - uint8 OUI[3]; /* OUI - P2P_OUI */ - uint8 type; /* OUI Type - P2P_VER */ - uint8 subtype; /* OUI Subtype - P2P_AF_* */ - uint8 dialog_token; /* nonzero, identifies req/resp tranaction */ - uint8 elts[1]; /* Variable length information elements. Max size = - * ACTION_FRAME_SIZE - sizeof(this structure) - 1 - */ + uint8 category; /* P2P_AF_CATEGORY */ + uint8 OUI[3]; /* OUI - P2P_OUI */ + uint8 type; /* OUI Type - P2P_VER */ + uint8 subtype; /* OUI Subtype - P2P_AF_* */ + uint8 dialog_token; /* nonzero, identifies req/resp tranaction */ + uint8 elts[BCM_FLEX_ARRAY]; /* information elements. Max size = + * ACTION_FRAME_SIZE - sizeof(this structure) - 1 + */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2p_action_frame wifi_p2p_action_frame_t; #define P2P_AF_CATEGORY 0x7f @@ -468,15 +469,15 @@ typedef struct wifi_p2p_action_frame wifi_p2p_action_frame_t; /* WiFi P2P Public Action Frame */ BWL_PRE_PACKED_STRUCT struct wifi_p2p_pub_act_frame { - uint8 category; /* P2P_PUB_AF_CATEGORY */ - uint8 action; /* P2P_PUB_AF_ACTION */ - uint8 oui[3]; /* P2P_OUI */ - uint8 oui_type; /* OUI type - P2P_VER */ - uint8 subtype; /* OUI subtype - P2P_TYPE_* */ - uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ - uint8 elts[1]; /* Variable length information elements. Max size = - * ACTION_FRAME_SIZE - sizeof(this structure) - 1 - */ + uint8 category; /* P2P_PUB_AF_CATEGORY */ + uint8 action; /* P2P_PUB_AF_ACTION */ + uint8 oui[3]; /* P2P_OUI */ + uint8 oui_type; /* OUI type - P2P_VER */ + uint8 subtype; /* OUI subtype - P2P_TYPE_* */ + uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ + uint8 elts[BCM_FLEX_ARRAY]; /* information elements. Max size = + * ACTION_FRAME_SIZE - sizeof(this structure) - 1 + */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2p_pub_act_frame wifi_p2p_pub_act_frame_t; #define P2P_PUB_AF_FIXED_LEN 8 @@ -510,11 +511,11 @@ BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_desc { typedef struct wifi_p2p_noa_desc wifi_p2p_noa_desc_t; BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_se { - uint8 eltId; /* Subelement ID */ - uint8 len[2]; /* Length */ - uint8 index; /* Index */ - uint8 ops_ctw_parms; /* CTWindow and OppPS Parameters */ - wifi_p2p_noa_desc_t desc[1]; /* Notice of Absence Descriptor(s) */ + uint8 eltId; /* Subelement ID */ + uint8 len[2]; /* Length */ + uint8 index; /* Index */ + uint8 ops_ctw_parms; /* CTWindow and OppPS Parameters */ + wifi_p2p_noa_desc_t desc[BCM_FLEX_ARRAY]; /* Notice of Absence Descriptor(s) */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2p_noa_se wifi_p2p_noa_se_t; @@ -602,38 +603,38 @@ typedef struct wifi_p2psd_adp_ie wifi_p2psd_adp_ie_t; /* NQP Vendor-specific Content */ BWL_PRE_PACKED_STRUCT struct wifi_p2psd_nqp_query_vsc { - uint8 oui_subtype; /* OUI Subtype: 0x09 */ - uint16 svc_updi; /* Service Update Indicator */ - uint8 svc_tlvs[1]; /* wifi_p2psd_qreq_tlv_t type for service request, - * wifi_p2psd_qresp_tlv_t type for service response - */ + uint8 oui_subtype; /* OUI Subtype: 0x09 */ + uint16 svc_updi; /* Service Update Indicator */ + uint8 svc_tlvs[BCM_FLEX_ARRAY]; /* wifi_p2psd_qreq_tlv_t type for service request, + * wifi_p2psd_qresp_tlv_t type for service response + */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2psd_nqp_query_vsc wifi_p2psd_nqp_query_vsc_t; /* Service Request TLV */ BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_tlv { - uint16 len; /* Length: 5 plus size of Query Data */ - uint8 svc_prot; /* Service Protocol Type */ - uint8 svc_tscid; /* Service Transaction ID */ - uint8 query_data[1]; /* Query Data, passed in from above Layer 2 */ + uint16 len; /* Length: 5 plus size of Query Data */ + uint8 svc_prot; /* Service Protocol Type */ + uint8 svc_tscid; /* Service Transaction ID */ + uint8 query_data[BCM_FLEX_ARRAY]; /* Query Data, passed in from above Layer 2 */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2psd_qreq_tlv wifi_p2psd_qreq_tlv_t; /* Query Request Frame, defined in generic format, instead of NQP specific */ BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_frame { - uint16 info_id; /* Info ID: 0xDDDD */ - uint16 len; /* Length of service request TLV, 5 plus the size of request data */ - uint8 oui[3]; /* WFA OUI: 0x0050F2 */ - uint8 qreq_vsc[1]; /* Vendor-specific Content: wifi_p2psd_nqp_query_vsc_t type for NQP */ + uint16 info_id; /* Info ID: 0xDDDD */ + uint16 len; /* service request len, 5 plus the size of request data */ + uint8 oui[3]; /* WFA OUI: 0x0050F2 */ + uint8 qreq_vsc[BCM_FLEX_ARRAY]; /* Vendor-specific : for NQP */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2psd_qreq_frame wifi_p2psd_qreq_frame_t; /* GAS Initial Request AF body, "elts" in wifi_p2p_pub_act_frame */ BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_ireq_frame { - wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ - uint16 qreq_len; /* Query Request Length */ - uint8 qreq_frm[1]; /* Query Request Frame wifi_p2psd_qreq_frame_t */ + wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ + uint16 qreq_len; /* Query Request Length */ + uint8 qreq_frm[BCM_FLEX_ARRAY]; /* Query Request Frame wifi_p2psd_qreq_frame_t */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2psd_gas_ireq_frame wifi_p2psd_gas_ireq_frame_t; @@ -643,7 +644,7 @@ BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_tlv { uint8 svc_prot; /* Service Protocol Type */ uint8 svc_tscid; /* Service Transaction ID */ uint8 status; /* Value defined in Table 57 of P2P spec. */ - uint8 query_data[1]; /* Response Data, passed in from above Layer 2 */ + uint8 query_data[BCM_FLEX_ARRAY]; /* Response Data, passed in from above Layer 2 */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2psd_qresp_tlv wifi_p2psd_qresp_tlv_t; @@ -652,40 +653,40 @@ BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_frame { uint16 info_id; /* Info ID: 0xDDDD */ uint16 len; /* Lenth of service response TLV, 6 plus the size of resp data */ uint8 oui[3]; /* WFA OUI: 0x0050F2 */ - uint8 qresp_vsc[1]; /* Vendor-specific Content: wifi_p2psd_qresp_tlv_t type for NQP */ + uint8 qresp_vsc[BCM_FLEX_ARRAY]; /* Vendor-specific : for NQP */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2psd_qresp_frame wifi_p2psd_qresp_frame_t; /* GAS Initial Response AF body, "elts" in wifi_p2p_pub_act_frame */ BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_iresp_frame { - uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ - uint16 cb_delay; /* GAS Comeback Delay */ + uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ + uint16 cb_delay; /* GAS Comeback Delay */ wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ - uint16 qresp_len; /* Query Response Length */ - uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ + uint16 qresp_len; /* Query Response Length */ + uint8 qresp_frm[BCM_FLEX_ARRAY]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2psd_gas_iresp_frame wifi_p2psd_gas_iresp_frame_t; /* GAS Comeback Response AF body, "elts" in wifi_p2p_pub_act_frame */ BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_cresp_frame { - uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ - uint8 fragment_id; /* Fragmentation ID */ - uint16 cb_delay; /* GAS Comeback Delay */ + uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ + uint8 fragment_id; /* Fragmentation ID */ + uint16 cb_delay; /* GAS Comeback Delay */ wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ - uint16 qresp_len; /* Query Response Length */ - uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ + uint16 qresp_len; /* Query Response Length */ + uint8 qresp_frm[BCM_FLEX_ARRAY]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2psd_gas_cresp_frame wifi_p2psd_gas_cresp_frame_t; /* Wi-Fi GAS Public Action Frame */ BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_pub_act_frame { - uint8 category; /* 0x04 Public Action Frame */ - uint8 action; /* 0x6c Advertisement Protocol */ - uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ - uint8 query_data[1]; /* Query Data. wifi_p2psd_gas_ireq_frame_t - * or wifi_p2psd_gas_iresp_frame_t format - */ + uint8 category; /* 0x04 Public Action Frame */ + uint8 action; /* 0x6c Advertisement Protocol */ + uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ + uint8 query_data[BCM_FLEX_ARRAY]; /* Query Data. wifi_p2psd_gas_ireq_frame_t + * or wifi_p2psd_gas_iresp_frame_t format + */ } BWL_POST_PACKED_STRUCT; typedef struct wifi_p2psd_gas_pub_act_frame wifi_p2psd_gas_pub_act_frame_t; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/packed_section_end.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/packed_section_end.h old mode 100755 new mode 100644 index fcdad85cff77..566b15c71124 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/packed_section_end.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/packed_section_end.h @@ -15,7 +15,7 @@ * #include * * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/packed_section_start.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/packed_section_start.h old mode 100755 new mode 100644 index d6c35a25bf9b..1cda56d8ebec --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/packed_section_start.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/packed_section_start.h @@ -15,7 +15,7 @@ * #include * * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/pcicfg.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/pcicfg.h old mode 100755 new mode 100644 index 663be79b2c9c..ac082a7fb39d --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/pcicfg.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/pcicfg.h @@ -1,7 +1,7 @@ /* * pcicfg.h: PCI configuration constants and structures. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -510,8 +510,15 @@ typedef struct _pcie_enhanced_caphdr { #define PCIE2_BAR0_CORE2_WIN2_OFFSET 0x5000u #define PCI_GPIO_OUTEN 0xb8 /* pci config space gpio output enable (>=rev3) */ +#ifdef PCI_L1SS_CTRL2 +#undef PCI_L1SS_CTRL2 +#endif /* PCI_L1SS_CTRL2 */ #define PCI_L1SS_CTRL2 0x24c /* The L1 PM Substates Control register */ +#define PCI_CFG_PTM_CAP 0x204 +#define PCI_CFG_PTM_CTRL 0x208 +#define PCI_CFG_PTM_ENABLED (1u << 0) + /* Private Registers */ #define PCI_STAT_CTRL 0xa80 #define PCI_L0_EVENTCNT 0xa84 diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/pcie_core.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/pcie_core.h old mode 100755 new mode 100644 index 80bc4c294bc5..d1d3cf49d2eb --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/pcie_core.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/pcie_core.h @@ -1,7 +1,7 @@ /* * BCM43XX PCIE core hardware definitions. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -26,6 +26,7 @@ #include #include +#define REV_GE_74(rev) (PCIECOREREV((rev)) >= 74) #define REV_GE_73(rev) (PCIECOREREV((rev)) >= 73) #define REV_GE_69(rev) (PCIECOREREV((rev)) >= 69) #define REV_GE_68(rev) (PCIECOREREV((rev)) >= 68) @@ -209,8 +210,8 @@ typedef struct pcie_hmapviolation { uint32 PAD[1]; } pcie_hmapviolation_t; -#if !defined(DONGLEBUILD) || defined(BCMSTANDALONE_TEST) || \ - defined(ATE_BUILD) || defined(BCMDVFS) +#if !defined(DONGLEBUILD) || defined(BCMSTANDALONE_TEST) || defined(ATE_BUILD) || \ + defined(BCMDVFS) /* SB side: PCIE core and host control registers */ typedef volatile struct sbpcieregs { uint32 control; /* host mode only */ @@ -390,7 +391,9 @@ typedef volatile struct sbpcieregs { uint32 erraddr; /* 0xA64 */ uint32 mbox_int; /* 0xA68 */ uint32 fis_ctrl; /* 0xA6C */ - uint32 PAD[36]; /* 0xA70-0xAFF */ + uint32 dar_gpio_dbg; /* 0xA70 */ + uint32 dar_sec_stat; /* 0xA74 */ + uint32 PAD[34]; /* 0xA78-0xAFF */ } dar_64; } u1; uint32 PAD[64]; /* 0xB00-0xBFF */ @@ -428,6 +431,14 @@ typedef volatile struct sbpcieregs { #define PCIE_TER_BAR0_WIN 0xc50 #define PCIE_TER_BAR0_WRAPPER 0xc54 +#define PCIE_TER_BAR0_WIN_DAR 0xa78 +#define PCIE_TER_BAR0_WRAPPER_DAR 0xa7c + +#define PCIE_TER_BAR0_WIN_REG(rev) \ + REV_GE_74(rev) ? PCIE_TER_BAR0_WIN_DAR : PCIE_TER_BAR0_WIN +#define PCIE_TER_BAR0_WRAPPER_REG(rev) \ + REV_GE_74(rev) ? PCIE_TER_BAR0_WRAPPER_DAR : PCIE_TER_BAR0_WRAPPER + /* PCI control */ #define PCIE_RST_OE 0x01 /* When set, drives PCI_RESET out to pin */ #define PCIE_RST 0x02 /* Value driven out to pin */ @@ -1143,6 +1154,23 @@ typedef volatile struct sbpcieregs { #define DAR_PCIE_DAR_CTRL(rev) PCIE_dar_control_OFFSET(rev) #endif +#define DAR_SEC_STATUS(rev) OFFSETOF(sbpcieregs_t, u1.dar_64.dar_sec_stat) + +#define DAR_SEC_JTAG_MASK 0x1u +#define DAR_SEC_JTAG_SHIFT 0u +#define DAR_SEC_SBOOT_MASK 0x2u +#define DAR_SEC_SBOOT_SHIFT 1u +#define DAR_SEC_ARM_DBG_MASK 0x4u +#define DAR_SEC_ARM_DBG_SHIFT 2u +#define DAR_SEC_UNLOCK_MASK 0x8u +#define DAR_SEC_UNLOCK_SHIFT 3u +#define DAR_SEC_ROM_PROT_MASK 0x10u +#define DAR_SEC_ROM_PROT_SHIFT 4u +#define DAR_SEC_NSEC_WR_MASK 0x20u +#define DAR_SEC_NSEC_WR_SHIFT 5u +#define DAR_SEC_NSEC_RD_MASK 0x40u +#define DAR_SEC_NSEC_RD_SHIFT 6u + #define DAR_FIS_CTRL(rev) OFFSETOF(sbpcieregs_t, u1.dar_64.fis_ctrl) #define DAR_FIS_START_SHIFT 0u diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/phy_event_log_payload.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/phy_event_log_payload.h new file mode 100644 index 000000000000..336fdea42324 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/phy_event_log_payload.h @@ -0,0 +1,3430 @@ +/* + * PHY related EVENT_LOG System Definitions + * + * This file describes the payloads of PHY related event log entries that are data buffers + * rather than formatted string entries. + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ + +#ifndef _PHY_EVENT_LOG_PAYLOAD_H_ +#define _PHY_EVENT_LOG_PAYLOAD_H_ + +#include +#include +#include +#include +#include + +typedef struct { + uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 rxrsptmout; /**< number of response timeouts for transmitted frames + * expecting a response + */ + uint32 rxstrt; /**< number of received frames with a good PLCP */ + uint32 rxbadplcp; /**< number of parity check of the PLCP header failed */ + uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ + uint32 rxnodelim; /**< number of no valid delimiter detected by ampdu parser */ + uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ + uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ + uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ + uint32 rxanyerr; /**< Any RX error that is not counted by other counters. */ + uint32 rxbeaconmbss; /**< beacons received from member of BSS */ + uint32 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */ + uint32 rxdtocast; /**< number of received DATA frames (good FCS and no matching RA) */ + uint32 rxtoolate; /**< receive too late */ + uint32 goodfcs; /**< Good fcs counters */ + uint32 rxf0ovfl; /** < Rx FIFO0 overflow counters information */ + uint32 rxf1ovfl; /** < Rx FIFO1 overflow counters information */ +} phy_periodic_counters_v1_t; + +typedef struct { + uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, + * CTS, Control Management + * (includes retransmissions) + */ + uint32 rxrsptmout; /**< number of response timeouts for transmitted frames + * expecting a response + */ + uint32 rxstrt; /**< number of received frames with a good PLCP */ + uint32 rxbadplcp; /**< number of parity check of the PLCP header failed */ + uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ + uint32 rxnodelim; /**< number of no valid delimiter detected by ampdu parser */ + uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ + uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ + uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ + uint32 rxanyerr; /**< Any RX error that is not counted by other counters. */ + uint32 rxbeaconmbss; /**< beacons received from member of BSS */ + uint32 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */ + uint32 rxdtocast; /**< number of received DATA frames (good FCS and no matching RA) */ + uint32 rxtoolate; /**< receive too late */ + uint32 goodfcs; /**< Good fcs counters */ + uint32 rxf0ovfl; /** < Rx FIFO0 overflow counters information */ + uint32 rxf1ovfl; /** < Rx FIFO1 overflow counters information */ + + uint32 txctl; + uint32 rxctl; + uint32 txbar; + uint32 rxbar; + uint32 rxbeaconbss; + + uint32 txrts; + uint32 txucast; /**< number of unicast tx expecting response other than cts/cwcts */ + uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */ + uint32 txackfrm; /**< number of ACK frames sent out */ + + uint32 txrtsfrm; /**< number of RTS sent out by the MAC */ + uint32 txrtsfail; /**< number of rts transmission failure that reach retry limit */ + uint32 rxctsucast; /**< number of unicast CTS addressed to the MAC (good FCS) */ + + uint32 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */ + uint32 txctsfrm; /**< number of CTS sent out by the MAC */ + + uint32 rxback; /**< blockack rxcnt */ + uint32 txback; /**< blockack txcnt */ + uint32 rxctlucast; /**< number of received CNTRL frames + * with good FCS and matching RA + */ + + uint32 last_bcn_seq_num; /**< * L_TSF and Seq # from the last beacon received */ + uint32 last_bcn_ltsf; /**< * L_TSF and Seq # from the last beacon received */ + + uint16 counter_noise_request; /**< counters of requesting noise samples for noisecal> */ + uint16 counter_noise_crsbit; /**< counters of noise mmt being interrupted + * due to PHYCRS> + */ + uint16 counter_noise_apply; /**< counts of applying noisecal result> */ + + uint8 phylog_noise_mode; /**< noise cal mode> */ + uint8 total_desense_on; /**< total desense on flag> */ + uint8 initgain_desense; /**< initgain desense when total desense is on> */ + uint8 crsmin_init; /**< crsmin_init threshold when total desense is on> */ + uint8 lna1_gainlmt_desense; /**< lna1_gain limit desense when applying desense> */ + uint8 clipgain_desense0; /**< clipgain desense when applying desense > */ + + uint32 desense_reason; /**< desense paraemters to indicate reasons + * for bphy and ofdm_desense> + */ + uint8 lte_ofdm_desense; /**< ofdm desense dut to lte> */ + uint8 lte_bphy_desense; /**< bphy desense due to lte> */ + + uint8 hw_aci_status; /**< HW ACI status flag> */ + uint8 aci_clipgain_desense0; /**< clipgain desense due to aci> */ + uint8 lna1_tbl_desense; /**< LNA1 table desense due to aci> */ + + int8 crsmin_high; /**< crsmin high when applying desense> */ + int8 weakest_rssi; /**< weakest link RSSI> */ + int8 phylog_noise_pwr_array[8][2]; /**< noise buffer array> */ +} phy_periodic_counters_v5_t; + +typedef struct { + + /* RX error related */ + uint32 rxrsptmout; /* number of response timeouts for transmitted frames + * expecting a response + */ + uint32 rxbadplcp; /* number of parity check of the PLCP header failed */ + uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ + uint32 rxnodelim; /* number of no valid delimiter detected by ampdu parser */ + uint32 bphy_badplcp; /* number of bad PLCP reception on BPHY rate */ + uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ + uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ + uint32 rxtoolate; /* receive too late */ + uint32 rxf0ovfl; /* Rx FIFO0 overflow counters information */ + uint32 rxf1ovfl; /* Rx FIFO1 overflow counters information */ + uint32 rxanyerr; /* Any RX error that is not counted by other counters. */ + uint32 rxdropped; /* Frame dropped */ + uint32 rxnobuf; /* Rx error due to no buffer */ + uint32 rxrunt; /* Runt frame counter */ + uint32 rxfrmtoolong; /* Number of received frame that are too long */ + uint32 rxdrop20s; + + /* RX related */ + uint32 rxstrt; /* number of received frames with a good PLCP */ + uint32 rxbeaconmbss; /* beacons received from member of BSS */ + uint32 rxdtucastmbss; /* number of received DATA frames with good FCS and matching RA */ + uint32 rxdtocast; /* number of received DATA frames (good FCS and no matching RA) */ + uint32 goodfcs; /* Good fcs counters */ + uint32 rxctl; /* Number of control frames */ + uint32 rxaction; /* Number of action frames */ + uint32 rxback; /* Number of block ack frames rcvd */ + uint32 rxctlucast; /* Number of received unicast ctl frames */ + uint32 rxframe; /* Number of received frames */ + + /* TX related */ + uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txmpdu; /* Numer of transmitted mpdus */ + uint32 txackbackctsfrm; /* Number of ACK + BACK + CTS */ + + /* TX error related */ + uint32 txrtsfail; /* RTS TX failure count */ + uint32 txphyerr; /* PHY TX error count */ + + uint16 nav_cntr_l; /* The state of the NAV */ + uint16 nav_cntr_h; +} phy_periodic_counters_v3_t; + +typedef struct phy_periodic_counters_v4 { + uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 rxrsptmout; /**< number of response timeouts for transmitted frames + * expecting a response + */ + uint32 rxstrt; /**< number of received frames with a good PLCP */ + uint32 rxbadplcp; /**< number of parity check of the PLCP header failed */ + uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ + uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ + uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ + uint32 rxbeaconmbss; /**< beacons received from member of BSS */ + uint32 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */ + uint32 rxf0ovfl; /** < Rx FIFO0 overflow counters information */ + uint32 rxf1ovfl; /** < Rx FIFO1 overflow counters information */ + uint32 rxdtocast; /**< number of received DATA frames (good FCS and no matching RA) */ + uint32 rxtoolate; /**< receive too late */ + uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ + uint32 rxdropped; + uint32 rxcrc; + uint32 rxnobuf; + uint32 rxrunt; + uint32 rxgiant; + uint32 rxctl; + uint32 rxaction; + uint32 rxdrop20s; + uint32 rxctsucast; + uint32 rxrtsucast; + uint32 txctsfrm; + uint32 rxackucast; + uint32 rxback; + uint32 txphyerr; + uint32 txrtsfrm; + uint32 txackfrm; + uint32 txback; + uint32 rxnodelim; + uint32 rxfrmtoolong; + uint32 rxctlucast; + uint32 txbcnfrm; + uint32 txdnlfrm; + uint32 txampdu; + uint32 txmpdu; + uint32 txinrtstxop; + uint32 prs_timeout; +} phy_periodic_counters_v4_t; + +/* phy_periodic_counters_v5_t reserved for 4378 */ +typedef struct phy_periodic_counters_v6 { + /* RX error related */ + uint32 rxrsptmout; /* number of response timeouts for transmitted frames + * expecting a response + */ + uint32 rxbadplcp; /* number of parity check of the PLCP header failed */ + uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ + uint32 rxnodelim; /* number of no valid delimiter detected by ampdu parser */ + uint32 bphy_badplcp; /* number of bad PLCP reception on BPHY rate */ + uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ + uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ + uint32 rxtoolate; /* receive too late */ + uint32 rxf0ovfl; /* Rx FIFO0 overflow counters information */ + uint32 rxf1ovfl; /* Rx FIFO1 overflow counters information */ + uint32 rxanyerr; /* Any RX error that is not counted by other counters. */ + uint32 rxdropped; /* Frame dropped */ + uint32 rxnobuf; /* Rx error due to no buffer */ + uint32 rxrunt; /* Runt frame counter */ + uint32 rxfrmtoolong; /* Number of received frame that are too long */ + uint32 rxdrop20s; + + /* RX related */ + uint32 rxstrt; /* number of received frames with a good PLCP */ + uint32 rxbeaconmbss; /* beacons received from member of BSS */ + uint32 rxdtucastmbss; /* number of received DATA frames with good FCS and matching RA */ + uint32 rxdtocast; /* number of received DATA frames (good FCS and no matching RA) */ + uint32 goodfcs; /* Good fcs counters */ + uint32 rxctl; /* Number of control frames */ + uint32 rxaction; /* Number of action frames */ + uint32 rxback; /* Number of block ack frames rcvd */ + uint32 rxctlucast; /* Number of received unicast ctl frames */ + uint32 rxframe; /* Number of received frames */ + + uint32 rxbar; /* Number of block ack requests rcvd */ + uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ + uint32 rxbeaconobss; /* number of OBSS beacons received */ + uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ + uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ + + /* TX related */ + uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txmpdu; /* Numer of transmitted mpdus */ + uint32 txackbackctsfrm; /* Number of ACK + BACK + CTS */ + uint32 txackfrm; /* number of ACK frames sent out */ + uint32 txrtsfrm; /* number of RTS sent out by the MAC */ + uint32 txctsfrm; /* number of CTS sent out by the MAC */ + + uint32 txctl; /* Number of control frames txd */ + uint32 txbar; /* Number of block ack requests txd */ + uint32 txrts; /* Number of RTS txd */ + uint32 txback; /* Number of block ack frames txd */ + uint32 txucast; /* number of unicast tx expecting response other than cts/cwcts */ + + /* TX error related */ + uint32 txrtsfail; /* RTS TX failure count */ + uint32 txphyerr; /* PHY TX error count */ + + uint32 last_bcn_seq_num; /* last beacon seq no. */ + uint32 last_bcn_ltsf; /* last beacon ltsf */ + + uint16 nav_cntr_l; /* The state of the NAV */ + uint16 nav_cntr_h; +} phy_periodic_counters_v6_t; + +typedef struct { + uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, + * CTS, Control Management + * (includes retransmissions) + */ + uint32 rxrsptmout; /* number of response timeouts for transmitted frames + * expecting a response + */ + uint32 rxstrt; /* number of received frames with a good PLCP */ + uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not + * the header + */ + uint32 bphy_badplcp; /* number of bad PLCP reception on BPHY rate */ + uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ + uint32 rxbadfcs; /* number of frames for which the CRC check failed + * in the MAC + */ + uint32 rxbeaconmbss; /* beacons received from member of BSS */ + uint32 rxdtucastmbss; /* number of received DATA frames with good FCS and + * matching RA + */ + uint32 rxdtocast; /* number of received DATA frames + * (good FCS and no matching RA) + */ + uint32 goodfcs; /* Good fcs counters */ + + uint32 txctl; + uint32 rxctl; + uint32 txbar; + uint32 rxbar; + uint32 rxbeaconobss; + + uint32 txrts; + uint32 txucast; /* number of unicast tx expecting response + * other than cts/cwcts + */ + uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ + uint32 txackfrm; /* number of ACK frames sent out */ + + uint32 txrtsfrm; /* number of RTS sent out by the MAC */ + uint32 txrtsfail; /* number of rts transmission failure + * that reach retry limit + */ + uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ + + uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ + uint32 txctsfrm; /* number of CTS sent out by the MAC */ + + uint32 rxback; /* blockack rxcnt */ + uint32 txback; /* blockack txcnt */ + uint32 rxctlucast; /* number of received CNTRL frames + * with good FCS and matching RA + */ + + uint32 last_bcn_seq_num; /* L_TSF and Seq # from the last beacon received */ + uint32 last_bcn_ltsf; /* L_TSF and Seq # from the last beacon received */ + + uint32 desense_reason; /* desense paraemters to indicate reasons + * for bphy and ofdm_desense + */ + + /* RX error related */ + uint32 rxdropped; /* Frame dropped */ + uint32 rxnobuf; /* Rx error due to no buffer */ + uint32 rxrunt; /* Runt frame counter */ + + uint32 rxframe; /* Number of received frames */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint32 tbtt; /* Per-interface stats report tbtt count */ + uint32 p2ptbtt; /* MCNX TBTT */ + uint32 p2ptbttmiss; /* TBTT coming when the radio is on an off channel */ + uint32 missbcn_dbg; /* Number of beacon missed to receive */ + uint32 noise_iqest_to; /* Count of IQ Est timeout during noise measurement */ + + uint32 rxanyerr; /* Any RX error that is not counted by other counters. */ + + uint32 phyovfl_cnt; /* RX PHY FIFO overflow */ + uint32 rxf0ovfl; /* Rx FIFO0 overflow counters information */ + uint32 rxf1ovfl; /* Rx FIFO1 overflow counters information */ + + uint32 lenfovfl_cnt; /* RX LFIFO overflow */ + uint32 weppeof_cnt; /* WEP asserted premature end-of-frame */ + uint32 rxbadplcp; /* number of parity check of the PLCP header failed */ + uint32 strmeof_cnt; /* RX frame got aborted because PHY FIFO did not have + * sufficient bytes + */ + uint32 pfifo_drop; /* PHY FIFO was not empty when a new frame arrived */ + uint32 ctx_fifo_full; /* Low Priority Context FIFO is full */ + uint32 ctx_fifo2_full; /* High Priority Context FIFO is full */ + uint32 rxnodelim; /* number of no valid delimiter detected by ampdu parser */ + uint32 rx20s_cnt; /* secondary 20 counter */ + uint32 rxdrop20s; /* RX was discarded as the CRS was not seen on + * primary channel + */ + uint32 new_rxin_plcp_wait_cnt; /* A new reception started waiting for PLCP bytes + * from a previous receive + */ + uint32 rxtoolate; /* receive too late */ + uint32 laterx_cnt; /* RX frame dropped as it was seen too (30us) late + * from the start of reception + */ + uint32 rxfrmtoolong; /* Number of received frame that are too long */ + uint32 rxfrmtooshrt; /* RX frame was dropped as it did not meet minimum + * number of bytes to be a valid 802.11 frame + */ + + uint32 rxlegacyfrminvalid; /* Invalid BPHY or L-OFDM reception */ + uint32 txsifserr; /* A frame arrived in SIFS while we were about to + * transmit B/ACK + */ + uint32 ooseq_macsusp; /* Ucode is out of sequence in processing reception + * (especially due to macsuspend). + * RX MEND is seen without RX STRT + */ + + uint16 counter_noise_request; /* counters of requesting noise samples for noisecal */ + uint16 counter_noise_crsbit; /* counters of noise mmt being interrupted + * due to PHYCRS> + */ + uint16 counter_noise_apply; /* counts of applying noisecal result */ + + uint16 deaf_count; /* Depth of stay_in_carrier_search function */ + + uint8 phylog_noise_mode; /* noise cal mode */ + uint8 total_desense_on; /* total desense on flag */ + uint8 initgain_desense; /* initgain desense when total desense is on */ + uint8 crsmin_init; /* crsmin_init threshold when total desense is on */ + uint8 lna1_gainlmt_desense; /* lna1_gain limit desense when applying desense */ + uint8 clipgain_desense0; /* clipgain desense when applying desense */ + + uint8 lte_ofdm_desense; /* ofdm desense dut to lte */ + uint8 lte_bphy_desense; /* bphy desense due to lte */ + + uint8 hw_aci_status; /* HW ACI status flag */ + uint8 aci_clipgain_desense0; /* clipgain desense due to aci */ + uint8 lna1_tbl_desense; /* LNA1 table desense due to aci */ + + int8 crsmin_high; /* crsmin high when applying desense */ + int8 weakest_rssi; /* weakest link RSSI */ + + uint8 max_fp; + uint8 crsminpwr_initgain; + uint8 crsminpwr_clip1_high; + uint8 crsminpwr_clip1_med; + uint8 crsminpwr_clip1_lo; + uint8 pad1; + uint8 pad2; +} phy_periodic_counters_v7_t; + +typedef struct phy_periodic_counters_v8 { + /* RX error related */ + uint32 rxrsptmout; /* number of response timeouts for transmitted frames + * expecting a response + */ + uint32 rxcrsglitch; /* PHY was able to correlate the preamble + * but not the header + */ + uint32 bphy_badplcp; /* number of bad PLCP reception on BPHY rate */ + uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ + uint32 rxdropped; /* Frame dropped */ + uint32 rxnobuf; /* Rx error due to no buffer */ + uint32 rxrunt; /* Runt frame counter */ + uint32 rxbadfcs; /* number of frames for which the CRC check failed + * in the MAC + */ + + /* RX related */ + uint32 rxstrt; /* number of received frames with a good PLCP */ + uint32 rxbeaconmbss; /* beacons received from member of BSS */ + uint32 rxdtucastmbss; /* number of received DATA frames with good FCS + * and matching RA + */ + uint32 rxdtocast; /* number of received DATA frames + * (good FCS and no matching RA) + */ + uint32 goodfcs; /* Good fcs counters */ + uint32 rxctl; /* Number of control frames */ + uint32 rxaction; /* Number of action frames */ + uint32 rxback; /* Number of block ack frames rcvd */ + uint32 rxctlucast; /* Number of received unicast ctl frames */ + uint32 rxframe; /* Number of received frames */ + + uint32 rxbar; /* Number of block ack requests rcvd */ + uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ + uint32 rxbeaconobss; /* number of OBSS beacons received */ + uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ + uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ + + /* TX related */ + uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txmpdu; /* Numer of transmitted mpdus */ + uint32 txackbackctsfrm; /* Number of ACK + BACK + CTS */ + uint32 txackfrm; /* number of ACK frames sent out */ + uint32 txrtsfrm; /* number of RTS sent out by the MAC */ + uint32 txctsfrm; /* number of CTS sent out by the MAC */ + + uint32 txctl; /* Number of control frames txd */ + uint32 txbar; /* Number of block ack requests txd */ + uint32 txrts; /* Number of RTS txd */ + uint32 txback; /* Number of block ack frames txd */ + uint32 txucast; /* number of unicast tx expecting response + * other than cts/cwcts + */ + + /* TX error related */ + uint32 txrtsfail; /* RTS TX failure count */ + uint32 txphyerr; /* PHY TX error count */ + + uint32 last_bcn_seq_num; /* last beacon seq no. */ + uint32 last_bcn_ltsf; /* last beacon ltsf */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint32 tbtt; /* Per-interface stats report tbtt count */ + uint32 p2ptbtt; /* MCNX TBTT */ + uint32 p2ptbttmiss; /* TBTT coming when the radio is on an off channel */ + uint32 missbcn_dbg; /* Number of beacon missed to receive */ + uint32 noise_iqest_to; /* Count of IQ Est timeout during noise measurement */ + + uint32 rxanyerr; /* Any RX error that is not counted by other counters. */ + + uint32 phyovfl_cnt; /* RX PHY FIFO overflow */ + uint32 rxf0ovfl; /* Rx FIFO0 overflow counters information */ + uint32 rxf1ovfl; /* Rx FIFO1 overflow counters information */ + + uint32 lenfovfl_cnt; /* RX LFIFO overflow */ + uint32 weppeof_cnt; /* WEP asserted premature end-of-frame */ + uint32 rxbadplcp; /* number of parity check of the PLCP header failed */ + uint32 strmeof_cnt; /* RX frame got aborted because PHY FIFO did not have + * sufficient bytes + */ + uint32 pfifo_drop; /* PHY FIFO was not empty when a new frame arrived */ + uint32 ctx_fifo_full; /* Low Priority Context FIFO is full */ + uint32 ctx_fifo2_full; /* High Priority Context FIFO is full */ + uint32 rxnodelim; /* number of no valid delimiter detected by ampdu parser */ + uint32 rx20s_cnt; /* secondary 20 counter */ + uint32 rxdrop20s; /* RX was discarded as the CRS was not seen on + * primary channel + */ + uint32 new_rxin_plcp_wait_cnt; /* A new reception started waiting for PLCP bytes + * from a previous receive + */ + uint32 rxtoolate; /* receive too late */ + uint32 laterx_cnt; /* RX frame dropped as it was seen too (30us) late + * from the start of reception + */ + uint32 rxfrmtoolong; /* Number of received frame that are too long */ + uint32 rxfrmtooshrt; /* RX frame was dropped as it did not meet minimum + * number of bytes to be a valid 802.11 frame + */ + + uint32 rxlegacyfrminvalid; /* Invalid BPHY or L-OFDM reception */ + uint32 txsifserr; /* A frame arrived in SIFS while we were about to + * transmit B/ACK + */ + uint32 ooseq_macsusp; /* Ucode is out of sequence in processing reception + * (especially due to macsuspend). + * RX MEND is seen without RX STRT + */ + uint32 desense_reason; /* desense paraemters to indicate reasons + * for bphy and ofdm_desense + */ + + uint16 nav_cntr_l; /* The state of the NAV */ + uint16 nav_cntr_h; +} phy_periodic_counters_v8_t; + +typedef struct phy_periodic_counters_v9 { + /* RX error related */ + uint32 rxrsptmout; /* number of response timeouts for transmitted frames + * expecting a response + */ + uint32 rxcrsglitch; /* PHY was able to correlate the preamble + * but not the header + */ + uint32 bphy_badplcp; /* number of bad PLCP reception on BPHY rate */ + uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ + uint32 rxdropped; /* Frame dropped */ + uint32 rxnobuf; /* Rx error due to no buffer */ + uint32 rxrunt; /* Runt frame counter */ + uint32 rxbadfcs; /* number of frames for which the CRC check failed + * in the MAC + */ + + /* RX related */ + uint32 rxstrt; /* number of received frames with a good PLCP */ + uint32 rxbeaconmbss; /* beacons received from member of BSS */ + uint32 rxdtucastmbss; /* number of received DATA frames with good FCS + * and matching RA + */ + uint32 rxdtocast; /* number of received DATA frames + * (good FCS and no matching RA) + */ + uint32 goodfcs; /* Good fcs counters */ + uint32 rxctl; /* Number of control frames */ + uint32 rxaction; /* Number of action frames */ + uint32 rxback; /* Number of block ack frames rcvd */ + uint32 rxctlucast; /* Number of received unicast ctl frames */ + uint32 rxframe; /* Number of received frames */ + + uint32 rxbar; /* Number of block ack requests rcvd */ + uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ + uint32 rxbeaconobss; /* number of OBSS beacons received */ + uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ + uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ + + /* TX related */ + uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txmpdu; /* Numer of transmitted mpdus */ + uint32 txackbackctsfrm; /* Number of ACK + BACK + CTS */ + uint32 txackfrm; /* number of ACK frames sent out */ + uint32 txrtsfrm; /* number of RTS sent out by the MAC */ + uint32 txctsfrm; /* number of CTS sent out by the MAC */ + + uint32 txctl; /* Number of control frames txd */ + uint32 txbar; /* Number of block ack requests txd */ + uint32 txrts; /* Number of RTS txd */ + uint32 txback; /* Number of block ack frames txd */ + uint32 txucast; /* number of unicast tx expecting response + * other than cts/cwcts + */ + + /* TX error related */ + uint32 txrtsfail; /* RTS TX failure count */ + uint32 txphyerr; /* PHY TX error count */ + + uint32 last_bcn_seq_num; /* last beacon seq no. */ + uint32 last_bcn_ltsf; /* last beacon ltsf */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint32 debug_01; + uint32 debug_02; + uint32 debug_03; + uint32 debug_04; + uint32 debug_05; + + uint32 rxanyerr; /* Any RX error that is not counted by other counters. */ + + uint32 phyovfl_cnt; /* RX PHY FIFO overflow */ + uint32 rxf0ovfl; /* Rx FIFO0 overflow counters information */ + uint32 rxf1ovfl; /* Rx FIFO1 overflow counters information */ + + uint32 lenfovfl_cnt; /* RX LFIFO overflow */ + uint32 weppeof_cnt; /* WEP asserted premature end-of-frame */ + uint32 rxbadplcp; /* number of parity check of the PLCP header failed */ + uint32 strmeof_cnt; /* RX frame got aborted because PHY FIFO did not have + * sufficient bytes + */ + uint32 pfifo_drop; /* PHY FIFO was not empty when a new frame arrived */ + uint32 ctx_fifo_full; /* Low Priority Context FIFO is full */ + uint32 ctx_fifo2_full; /* High Priority Context FIFO is full */ + uint32 rxnodelim; /* number of no valid delimiter detected by ampdu parser */ + uint32 rx20s_cnt; /* secondary 20 counter */ + uint32 rxdrop20s; /* RX was discarded as the CRS was not seen on + * primary channel + */ + uint32 new_rxin_plcp_wait_cnt; /* A new reception started waiting for PLCP bytes + * from a previous receive + */ + uint32 rxtoolate; /* receive too late */ + uint32 laterx_cnt; /* RX frame dropped as it was seen too (30us) late + * from the start of reception + */ + uint32 rxfrmtoolong; /* Number of received frame that are too long */ + uint32 rxfrmtooshrt; /* RX frame was dropped as it did not meet minimum + * number of bytes to be a valid 802.11 frame + */ + + uint32 rxlegacyfrminvalid; /* Invalid BPHY or L-OFDM reception */ + uint32 txsifserr; /* A frame arrived in SIFS while we were about to + * transmit B/ACK + */ + uint32 ooseq_macsusp; /* Ucode is out of sequence in processing reception + * (especially due to macsuspend). + * RX MEND is seen without RX STRT + */ + uint32 desense_reason; /* desense paraemters to indicate reasons + * for bphy and ofdm_desense + */ + + uint16 nav_cntr_l; /* The state of the NAV */ + uint16 nav_cntr_h; + + uint32 tbtt; /* Per-interface stats report tbtt count */ + uint32 p2ptbtt; /* MCNX TBTT */ + uint32 p2ptbttmiss; /* TBTT coming when the radio is on an off channel */ + uint32 noise_iqest_to; /* Count of IQ Est timeout during noise measurement */ + uint16 missbcn_dbg; /* Number of beacon missed to receive */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 debug_06; + uint16 debug_07; + uint16 debug_08; + uint16 debug_09; + uint16 debug_10; + + uint8 sc_dccal_incc_cnt; /* scan dccal counter */ + uint8 sc_rxiqcal_skip_cnt; /* scan rxiqcal counter */ + uint8 sc_noisecal_incc_cnt; /* scan noise cal counter */ + uint8 debug_14; +} phy_periodic_counters_v9_t; + +typedef struct phy_periodic_counters_v255 { + /* RX error related */ + uint32 rxrsptmout; /* number of response timeouts for transmitted frames + * expecting a response + */ + uint32 rxcrsglitch; /* PHY was able to correlate the preamble + * but not the header + */ + uint32 bphy_badplcp; /* number of bad PLCP reception on BPHY rate */ + uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ + uint32 rxdropped; /* Frame dropped */ + uint32 rxnobuf; /* Rx error due to no buffer */ + uint32 rxrunt; /* Runt frame counter */ + uint32 rxbadfcs; /* number of frames for which the CRC check failed + * in the MAC + */ + + /* RX related */ + uint32 rxstrt; /* number of received frames with a good PLCP */ + uint32 rxbeaconmbss; /* beacons received from member of BSS */ + uint32 rxdtucastmbss; /* number of received DATA frames with good FCS + * and matching RA + */ + uint32 rxdtocast; /* number of received DATA frames + * (good FCS and no matching RA) + */ + uint32 goodfcs; /* Good fcs counters */ + uint32 rxctl; /* Number of control frames */ + uint32 rxaction; /* Number of action frames */ + uint32 rxback; /* Number of block ack frames rcvd */ + uint32 rxctlucast; /* Number of received unicast ctl frames */ + uint32 rxframe; /* Number of received frames */ + + uint32 rxbar; /* Number of block ack requests rcvd */ + uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ + uint32 rxbeaconobss; /* number of OBSS beacons received */ + uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ + uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ + + /* TX related */ + uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txmpdu; /* Numer of transmitted mpdus */ + uint32 txackbackctsfrm; /* Number of ACK + BACK + CTS */ + uint32 txackfrm; /* number of ACK frames sent out */ + uint32 txrtsfrm; /* number of RTS sent out by the MAC */ + uint32 txctsfrm; /* number of CTS sent out by the MAC */ + + uint32 txctl; /* Number of control frames txd */ + uint32 txbar; /* Number of block ack requests txd */ + uint32 txrts; /* Number of RTS txd */ + uint32 txback; /* Number of block ack frames txd */ + uint32 txucast; /* number of unicast tx expecting response + * other than cts/cwcts + */ + + /* TX error related */ + uint32 txrtsfail; /* RTS TX failure count */ + uint32 txphyerr; /* PHY TX error count */ + + uint32 last_bcn_seq_num; /* last beacon seq no. */ + uint32 last_bcn_ltsf; /* last beacon ltsf */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint32 debug_01; + uint32 debug_02; + uint32 debug_03; + uint32 debug_04; + uint32 debug_05; + + uint32 rxanyerr; /* Any RX error that is not counted by other counters. */ + + uint32 phyovfl_cnt; /* RX PHY FIFO overflow */ + uint32 rxf0ovfl; /* Rx FIFO0 overflow counters information */ + uint32 rxf1ovfl; /* Rx FIFO1 overflow counters information */ + + uint32 lenfovfl_cnt; /* RX LFIFO overflow */ + uint32 weppeof_cnt; /* WEP asserted premature end-of-frame */ + uint32 rxbadplcp; /* number of parity check of the PLCP header failed */ + uint32 strmeof_cnt; /* RX frame got aborted because PHY FIFO did not have + * sufficient bytes + */ + uint32 pfifo_drop; /* PHY FIFO was not empty when a new frame arrived */ + uint32 ctx_fifo_full; /* Low Priority Context FIFO is full */ + uint32 ctx_fifo2_full; /* High Priority Context FIFO is full */ + uint32 rxnodelim; /* number of no valid delimiter detected by ampdu parser */ + uint32 rx20s_cnt; /* secondary 20 counter */ + uint32 rxdrop20s; /* RX was discarded as the CRS was not seen on + * primary channel + */ + uint32 new_rxin_plcp_wait_cnt; /* A new reception started waiting for PLCP bytes + * from a previous receive + */ + uint32 rxtoolate; /* receive too late */ + uint32 laterx_cnt; /* RX frame dropped as it was seen too (30us) late + * from the start of reception + */ + uint32 rxfrmtoolong; /* Number of received frame that are too long */ + uint32 rxfrmtooshrt; /* RX frame was dropped as it did not meet minimum + * number of bytes to be a valid 802.11 frame + */ + + uint32 rxlegacyfrminvalid; /* Invalid BPHY or L-OFDM reception */ + uint32 txsifserr; /* A frame arrived in SIFS while we were about to + * transmit B/ACK + */ + uint32 ooseq_macsusp; /* Ucode is out of sequence in processing reception + * (especially due to macsuspend). + * RX MEND is seen without RX STRT + */ + uint32 desense_reason; /* desense paraemters to indicate reasons + * for bphy and ofdm_desense + */ + + uint16 nav_cntr_l; /* The state of the NAV */ + uint16 nav_cntr_h; + + uint32 tbtt; /* Per-interface stats report tbtt count */ + uint32 p2ptbtt; /* MCNX TBTT */ + uint32 p2ptbttmiss; /* TBTT coming when the radio is on an off channel */ + uint32 noise_iqest_to; /* Count of IQ Est timeout during noise measurement */ + uint16 missbcn_dbg; /* Number of beacon missed to receive */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 debug_06; + uint16 debug_07; + uint16 debug_08; + uint16 debug_09; + uint16 debug_10; + + uint8 sc_dccal_incc_cnt; /* scan dccal counter */ + uint8 sc_rxiqcal_skip_cnt; /* scan rxiqcal counter */ + uint8 sc_noisecal_incc_cnt; /* scan noise cal counter */ + uint8 debug_14; +} phy_periodic_counters_v255_t; + +typedef struct phycal_log_cmn { + uint16 chanspec; /* Current phy chanspec */ + uint8 last_cal_reason; /* Last Cal Reason */ + uint8 pad1; /* Padding byte to align with word */ + uint32 last_cal_time; /* Last cal time in sec */ +} phycal_log_cmn_t; + +typedef struct phycal_log_cmn_v2 { + uint16 chanspec; /* current phy chanspec */ + uint8 reason; /* cal reason */ + uint8 phase; /* cal phase */ + uint32 time; /* time at which cal happened in sec */ + uint16 temp; /* temperature at the time of cal */ + uint16 dur; /* duration of cal in usec */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 debug_01; /* reused for slice info */ + uint16 debug_02; + uint16 debug_03; + uint16 debug_04; +} phycal_log_cmn_v2_t; + +typedef struct phycal_log_core { + uint16 ofdm_txa; /* OFDM Tx IQ Cal a coeff */ + uint16 ofdm_txb; /* OFDM Tx IQ Cal b coeff */ + uint16 ofdm_txd; /* contain di & dq */ + uint16 bphy_txa; /* BPHY Tx IQ Cal a coeff */ + uint16 bphy_txb; /* BPHY Tx IQ Cal b coeff */ + uint16 bphy_txd; /* contain di & dq */ + + uint16 rxa; /* Rx IQ Cal A coeffecient */ + uint16 rxb; /* Rx IQ Cal B coeffecient */ + int32 rxs; /* FDIQ Slope coeffecient */ + + uint8 baseidx; /* TPC Base index */ + uint8 adc_coeff_cap0_adcI; /* ADC CAP Cal Cap0 I */ + uint8 adc_coeff_cap1_adcI; /* ADC CAP Cal Cap1 I */ + uint8 adc_coeff_cap2_adcI; /* ADC CAP Cal Cap2 I */ + uint8 adc_coeff_cap0_adcQ; /* ADC CAP Cal Cap0 Q */ + uint8 adc_coeff_cap1_adcQ; /* ADC CAP Cal Cap1 Q */ + uint8 adc_coeff_cap2_adcQ; /* ADC CAP Cal Cap2 Q */ + uint8 pad; /* Padding byte to align with word */ +} phycal_log_core_t; + +typedef struct phycal_log_core_v3 { + uint16 ofdm_txa; /* OFDM Tx IQ Cal a coeff */ + uint16 ofdm_txb; /* OFDM Tx IQ Cal b coeff */ + uint16 ofdm_txd; /* contain di & dq */ + uint16 bphy_txa; /* BPHY Tx IQ Cal a coeff */ + uint16 bphy_txb; /* BPHY Tx IQ Cal b coeff */ + uint16 bphy_txd; /* contain di & dq */ + + uint16 rxa; /* Rx IQ Cal A coeffecient */ + uint16 rxb; /* Rx IQ Cal B coeffecient */ + int32 rxs; /* FDIQ Slope coeffecient */ + + uint8 baseidx; /* TPC Base index */ + uint8 adc_coeff_cap0_adcI; /* ADC CAP Cal Cap0 I */ + uint8 adc_coeff_cap1_adcI; /* ADC CAP Cal Cap1 I */ + uint8 adc_coeff_cap2_adcI; /* ADC CAP Cal Cap2 I */ + uint8 adc_coeff_cap0_adcQ; /* ADC CAP Cal Cap0 Q */ + uint8 adc_coeff_cap1_adcQ; /* ADC CAP Cal Cap1 Q */ + uint8 adc_coeff_cap2_adcQ; /* ADC CAP Cal Cap2 Q */ + uint8 pad; /* Padding byte to align with word */ + + /* Gain index based txiq ceffiecients for 2G(3 gain indices) */ + uint16 txiqlo_2g_a0; /* 2G TXIQ Cal a coeff for high TX gain */ + uint16 txiqlo_2g_b0; /* 2G TXIQ Cal b coeff for high TX gain */ + uint16 txiqlo_2g_a1; /* 2G TXIQ Cal a coeff for mid TX gain */ + uint16 txiqlo_2g_b1; /* 2G TXIQ Cal b coeff for mid TX gain */ + uint16 txiqlo_2g_a2; /* 2G TXIQ Cal a coeff for low TX gain */ + uint16 txiqlo_2g_b2; /* 2G TXIQ Cal b coeff for low TX gain */ + + uint16 rxa_vpoff; /* Rx IQ Cal A coeff Vp off */ + uint16 rxb_vpoff; /* Rx IQ Cal B coeff Vp off */ + uint16 rxa_ipoff; /* Rx IQ Cal A coeff Ip off */ + uint16 rxb_ipoff; /* Rx IQ Cal B coeff Ip off */ + int32 rxs_vpoff; /* FDIQ Slope coeff Vp off */ + int32 rxs_ipoff; /* FDIQ Slope coeff Ip off */ +} phycal_log_core_v3_t; + +#define PHYCAL_LOG_VER1 (1u) + +typedef struct phycal_log_v1 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Numbe of cores for which core specific data present */ + uint16 length; /* Length of the entire structure */ + phycal_log_cmn_t phycal_log_cmn; /* Logging common structure */ + /* This will be a variable length based on the numcores field defined above */ + phycal_log_core_t phycal_log_core[BCM_FLEX_ARRAY]; +} phycal_log_v1_t; + +typedef struct phy_periodic_log_cmn { + uint16 chanspec; /* Current phy chanspec */ + uint16 vbatmeas; /* Measured VBAT sense value */ + uint16 featureflag; /* Currently active feature flags */ + int8 chiptemp; /* Chip temparature */ + int8 femtemp; /* Fem temparature */ + + uint32 nrate; /* Current Tx nrate */ + + uint8 cal_phase_id; /* Current Multi phase cal ID */ + uint8 rxchain; /* Rx Chain */ + uint8 txchain; /* Tx Chain */ + uint8 ofdm_desense; /* OFDM desense */ + + uint8 bphy_desense; /* BPHY desense */ + uint8 pll_lockstatus; /* PLL Lock status */ + uint8 pad1; /* Padding byte to align with word */ + uint8 pad2; /* Padding byte to align with word */ + + uint32 duration; /**< millisecs spent sampling this channel */ + uint32 congest_ibss; /**< millisecs in our bss (presumably this traffic will */ + /**< move if cur bss moves channels) */ + uint32 congest_obss; /**< traffic not in our bss */ + uint32 interference; /**< millisecs detecting a non 802.11 interferer. */ + +} phy_periodic_log_cmn_t; + +typedef struct phy_periodic_log_cmn_v2 { + uint16 chanspec; /* Current phy chanspec */ + uint16 vbatmeas; /* Measured VBAT sense value */ + uint16 featureflag; /* Currently active feature flags */ + int8 chiptemp; /* Chip temparature */ + int8 femtemp; /* Fem temparature */ + + uint32 nrate; /* Current Tx nrate */ + + uint8 cal_phase_id; /* Current Multi phase cal ID */ + uint8 rxchain; /* Rx Chain */ + uint8 txchain; /* Tx Chain */ + uint8 ofdm_desense; /* OFDM desense */ + + uint8 bphy_desense; /* BPHY desense */ + uint8 pll_lockstatus; /* PLL Lock status */ + + uint32 duration; /* millisecs spent sampling this channel */ + uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ + /* move if cur bss moves channels) */ + uint32 congest_obss; /* traffic not in our bss */ + uint32 interference; /* millisecs detecting a non 802.11 interferer. */ + + uint8 slice; + uint8 version; /* version of fw/ucode for debug purposes */ + bool phycal_disable; /* Set if calibration is disabled */ + uint8 pad; + uint16 phy_log_counter; + uint16 noise_mmt_overdue; /* Count up if ucode noise mmt is overdue for 5 sec */ + uint16 chan_switch_tm; /* Channel switch time */ + + /* HP2P related params */ + uint16 shm_mpif_cnt_val; + uint16 shm_thld_cnt_val; + uint16 shm_nav_cnt_val; + uint16 shm_cts_cnt_val; + + uint16 shm_m_prewds_cnt; /* Count of pre-wds fired in the ucode */ + uint32 last_cal_time; /* Last cal execution time */ + uint16 deaf_count; /* Depth of stay_in_carrier_search function */ + uint32 ed20_crs0; /* ED-CRS status on core 0 */ + uint32 ed20_crs1; /* ED-CRS status on core 1 */ + uint32 noise_cal_req_ts; /* Time-stamp when noise cal was requested */ + uint32 noise_cal_intr_ts; /* Time-stamp when noise cal was completed */ + uint32 phywdg_ts; /* Time-stamp when wd was fired */ + uint32 phywd_dur; /* Duration of the watchdog */ + uint32 noise_mmt_abort_crs; /* Count of CRS during noise mmt */ + uint32 chanspec_set_ts; /* Time-stamp when chanspec was set */ + uint32 vcopll_failure_cnt; /* Number of VCO cal failures + * (including failures detected in ucode). + */ + uint32 dcc_fail_counter; /* Number of DC cal failures */ + uint32 log_ts; /* Time-stamp when this log was collected */ + + uint16 btcxovrd_dur; /* Cumulative btcx overide between WDGs */ + uint16 btcxovrd_err_cnt; /* BTCX override flagged errors */ + + uint16 femtemp_read_fail_counter; /* Fem temparature read fail counter */ + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 debug_01; + uint16 debug_02; +} phy_periodic_log_cmn_v2_t; + +typedef struct phy_periodic_log_cmn_v3 { + uint32 nrate; /* Current Tx nrate */ + uint32 duration; /**< millisecs spent sampling this channel */ + uint32 congest_ibss; /**< millisecs in our bss (presumably this traffic will */ + /**< move if cur bss moves channels) */ + uint32 congest_obss; /**< traffic not in our bss */ + uint32 interference; /**< millisecs detecting a non 802.11 interferer. */ + uint32 noise_cfg_exit1; + uint32 noise_cfg_exit2; + uint32 noise_cfg_exit3; + uint32 noise_cfg_exit4; + uint32 ed20_crs0; + uint32 ed20_crs1; + uint32 noise_cal_req_ts; + uint32 noise_cal_crs_ts; + uint32 log_ts; + uint32 last_cal_time; + uint32 phywdg_ts; + uint32 chanspec_set_ts; + uint32 noise_zero_inucode; + uint32 phy_crs_during_noisemmt; + uint32 wd_dur; + + int32 deaf_count; + + uint16 chanspec; /* Current phy chanspec */ + uint16 vbatmeas; /* Measured VBAT sense value */ + uint16 featureflag; /* Currently active feature flags */ + uint16 nav_cntr_l; + uint16 nav_cntr_h; + uint16 chanspec_set_last; + uint16 ucode_noise_fb_overdue; + uint16 phy_log_counter; + uint16 shm_mpif_cnt_val; + uint16 shm_thld_cnt_val; + uint16 shm_nav_cnt_val; + uint16 shm_dc_cnt_val; + uint16 shm_txff_cnt_val; + uint16 shm_cts_cnt_val; + uint16 shm_m_prewds_cnt; + + uint8 cal_phase_id; /* Current Multi phase cal ID */ + uint8 rxchain; /* Rx Chain */ + uint8 txchain; /* Tx Chain */ + uint8 ofdm_desense; /* OFDM desense */ + uint8 bphy_desense; /* BPHY desense */ + uint8 pll_lockstatus; /* PLL Lock status */ + int8 chiptemp; /* Chip temparature */ + int8 femtemp; /* Fem temparature */ + + bool phycal_disable; + uint8 pad; /* Padding byte to align with word */ +} phy_periodic_log_cmn_v3_t; + +typedef struct phy_periodic_log_cmn_v4 { + uint16 chanspec; /* Current phy chanspec */ + uint16 vbatmeas; /* Measured VBAT sense value */ + + uint16 featureflag; /* Currently active feature flags */ + int8 chiptemp; /* Chip temparature */ + int8 femtemp; /* Fem temparature */ + + uint32 nrate; /* Current Tx nrate */ + + uint8 cal_phase_id; /* Current Multi phase cal ID */ + uint8 rxchain; /* Rx Chain */ + uint8 txchain; /* Tx Chain */ + uint8 ofdm_desense; /* OFDM desense */ + + uint8 slice; + uint8 dbgfw_ver; /* version of fw/ucode for debug purposes */ + uint8 bphy_desense; /* BPHY desense */ + uint8 pll_lockstatus; /* PLL Lock status */ + + uint32 duration; /* millisecs spent sampling this channel */ + uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ + /* move if cur bss moves channels) */ + uint32 congest_obss; /* traffic not in our bss */ + uint32 interference; /* millisecs detecting a non 802.11 interferer. */ + + /* HP2P related params */ + uint16 shm_mpif_cnt_val; + uint16 shm_thld_cnt_val; + uint16 shm_nav_cnt_val; + uint16 shm_cts_cnt_val; + + uint16 shm_m_prewds_cnt; /* Count of pre-wds fired in the ucode */ + uint16 deaf_count; /* Depth of stay_in_carrier_search function */ + uint32 last_cal_time; /* Last cal execution time */ + uint32 ed20_crs0; /* ED-CRS status on core 0: TODO change to uint16 */ + uint32 ed20_crs1; /* ED-CRS status on core 1: TODO change to uint16 */ + uint32 noise_cal_req_ts; /* Time-stamp when noise cal was requested */ + uint32 noise_cal_intr_ts; /* Time-stamp when noise cal was completed */ + uint32 phywdg_ts; /* Time-stamp when wd was fired */ + uint32 phywd_dur; /* Duration of the watchdog */ + uint32 noise_mmt_abort_crs; /* Count of CRS during noise mmt: TODO change to uint16 */ + uint32 chanspec_set_ts; /* Time-stamp when chanspec was set */ + uint32 vcopll_failure_cnt; /* Number of VCO cal failures + * (including failures detected in ucode). + */ + uint16 dcc_attempt_counter; /* Number of DC cal attempts */ + uint16 dcc_fail_counter; /* Number of DC cal failures */ + uint32 log_ts; /* Time-stamp when this log was collected */ + + uint16 btcxovrd_dur; /* Cumulative btcx overide between WDGs */ + uint16 btcxovrd_err_cnt; /* BTCX override flagged errors */ + + uint16 femtemp_read_fail_counter; /* Fem temparature read fail counter */ + uint16 phy_log_counter; + uint16 noise_mmt_overdue; /* Count up if ucode noise mmt is overdue for 5 sec */ + uint16 chan_switch_tm; /* Channel switch time */ + + bool phycal_disable; /* Set if calibration is disabled */ + + /* dccal dcoe & idacc */ + uint8 dcc_err; /* dccal health check error status */ + uint8 dcoe_num_tries; /* number of retries on dcoe cal */ + uint8 idacc_num_tries; /* number of retries on idac cal */ + + uint8 dccal_phyrxchain; /* phy rxchain during dc calibration */ + uint8 dccal_type; /* DC cal type: single/multi phase, chan change, etc. */ + uint16 dcc_hcfail; /* dcc health check failure count */ + uint16 dcc_calfail; /* dcc failure count */ + + uint16 noise_mmt_request_cnt; /* Count of ucode noise cal request from phy */ + uint16 crsmin_pwr_apply_cnt; /* Count of desense power threshold update to phy */ + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 debug_03; + uint16 debug_04; + uint16 debug_05; +} phy_periodic_log_cmn_v4_t; + +typedef struct phy_periodic_log_cmn_v5 { + + uint32 nrate; /* Current Tx nrate */ + uint32 duration; /* millisecs spent sampling this channel */ + uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ + /* move if cur bss moves channels) */ + uint32 congest_obss; /* traffic not in our bss */ + uint32 interference; /* millisecs detecting a non 802.11 interferer. */ + uint32 last_cal_time; /* Last cal execution time */ + + uint32 noise_cal_req_ts; /* Time-stamp when noise cal was requested */ + uint32 noise_cal_intr_ts; /* Time-stamp when noise cal was completed */ + uint32 phywdg_ts; /* Time-stamp when wd was fired */ + uint32 phywd_dur; /* Duration of the watchdog */ + uint32 chanspec_set_ts; /* Time-stamp when chanspec was set */ + uint32 vcopll_failure_cnt; /* Number of VCO cal failures including */ + /* failures detected in ucode */ + uint32 log_ts; /* Time-stamp when this log was collected */ + + /* glitch based desense input from cca */ + uint32 cca_stats_total_glitch; + uint32 cca_stats_bphy_glitch; + uint32 cca_stats_total_badplcp; + uint32 cca_stats_bphy_badplcp; + uint32 cca_stats_mbsstime; + + uint32 counter_noise_request; /* count of noisecal request */ + uint32 counter_noise_crsbit; /* count of crs high during noisecal request */ + uint32 counter_noise_apply; /* count of applying noisecal result to crsmin */ + uint32 fullphycalcntr; /* count of performing single phase cal */ + uint32 multiphasecalcntr; /* count of performing multi-phase cal */ + + uint16 chanspec; /* Current phy chanspec */ + uint16 vbatmeas; /* Measured VBAT sense value */ + uint16 featureflag; /* Currently active feature flags */ + + /* HP2P related params */ + uint16 shm_mpif_cnt_val; + uint16 shm_thld_cnt_val; + uint16 shm_nav_cnt_val; + uint16 shm_cts_cnt_val; + + uint16 shm_m_prewds_cnt; /* Count of pre-wds fired in the ucode */ + uint16 deaf_count; /* Depth of stay_in_carrier_search function */ + + uint16 ed20_crs0; /* ED-CRS status on core 0 */ + uint16 ed20_crs1; /* ED-CRS status on core 1 */ + + uint16 dcc_attempt_counter; /* Number of DC cal attempts */ + uint16 dcc_fail_counter; /* Number of DC cal failures */ + + uint16 btcxovrd_dur; /* Cumulative btcx overide between WDGs */ + uint16 btcxovrd_err_cnt; /* BTCX override flagged errors */ + + uint16 femtemp_read_fail_counter; /* Fem temparature read fail counter */ + uint16 phy_log_counter; + uint16 noise_mmt_overdue; /* Count up if ucode noise mmt is overdue for 5 sec */ + uint16 chan_switch_tm; /* Channel switch time */ + + uint16 dcc_hcfail; /* dcc health check failure count */ + uint16 dcc_calfail; /* dcc failure count */ + uint16 crsmin_pwr_apply_cnt; /* Count of desense power threshold update to phy */ + + uint16 txpustatus; /* txpu off definations */ + uint16 tempinvalid_count; /* Count no. of invalid temp. measurements */ + uint16 log_event_id; /* reuse debug_01, logging event id */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 debug_02; + uint16 debug_03; + uint16 debug_04; + uint16 debug_05; + + int8 chiptemp; /* Chip temparature */ + int8 femtemp; /* Fem temparature */ + + uint8 cal_phase_id; /* Current Multi phase cal ID */ + uint8 rxchain; /* Rx Chain */ + uint8 txchain; /* Tx Chain */ + uint8 ofdm_desense; /* OFDM desense */ + + uint8 slice; + uint8 dbgfw_ver; /* version of fw/ucode for debug purposes */ + uint8 bphy_desense; /* BPHY desense */ + uint8 pll_lockstatus; /* PLL Lock status */ + + /* dccal dcoe & idacc */ + uint8 dcc_err; /* dccal health check error status */ + uint8 dcoe_num_tries; /* number of retries on dcoe cal */ + uint8 idacc_num_tries; /* number of retries on idac cal */ + + uint8 dccal_phyrxchain; /* phy rxchain during dc calibration */ + uint8 dccal_type; /* DC cal type: single/multi phase, chan change, etc. */ + + uint8 gbd_bphy_sleep_counter; /* gbd sleep counter */ + uint8 gbd_ofdm_sleep_counter; /* gbd sleep counter */ + uint8 curr_home_channel; /* gbd input channel from cca */ + + /* desense data */ + int8 btcx_mode; /* btcoex desense mode */ + int8 ltecx_mode; /* lte coex desense mode */ + uint8 gbd_ofdm_desense; /* gbd ofdm desense level */ + uint8 gbd_bphy_desense; /* gbd bphy desense level */ + uint8 current_elna_bypass; /* init gain desense: elna bypass */ + uint8 current_tia_idx; /* init gain desense: tia index */ + uint8 current_lpf_idx; /* init gain desense: lpf index */ + uint8 crs_auto_thresh; /* crs auto threshold after desense */ + + int8 weakest_rssi; /* weakest link RSSI */ + uint8 noise_cal_mode; /* noisecal mode */ + + bool phycal_disable; /* Set if calibration is disabled */ + bool hwpwrctrlen; /* tx hwpwrctrl enable */ +} phy_periodic_log_cmn_v5_t; + +typedef struct phy_periodic_log_cmn_v6 { + uint32 nrate; /* Current Tx nrate */ + uint32 duration; /* millisecs spent sampling this channel */ + uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ + /* move if cur bss moves channels) */ + uint32 congest_obss; /* traffic not in our bss */ + uint32 interference; /* millisecs detecting a non 802.11 interferer. */ + + uint32 macsusp_dur; /* mac suspend duration */ + + uint16 chanspec; /* Current phy chanspec */ + uint16 vbatmeas; /* Measured VBAT sense value */ + uint16 featureflag; /* Currently active feature flags */ + + uint16 macsusp_cnt; /* mac suspend counter */ + uint16 log_event_id; /* logging event id */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 measurehold_high; /* PHY hold activities high16 */ + uint16 measurehold_low; /* PHY hold activities low16 */ + uint16 btcx_ackpwroffset; /* CoreMask (low8) and ack_pwr_offset (high8) */ + uint16 debug_04; + uint16 debug_05; + + int8 chiptemp; /* Chip temparature */ + int8 femtemp; /* Fem temparature */ + + uint8 cal_phase_id; /* Current Multi phase cal ID */ + uint8 rxchain; /* Rx Chain */ + + uint8 txchain; /* Tx Chain */ + uint8 ofdm_desense; /* OFDM desense */ + + uint8 bphy_desense; /* BPHY desense */ + uint8 pll_lockstatus; /* PLL Lock status */ + + uint8 amtbitmap; /* AMT status bitamp */ + uint8 pad1; /* Padding byte to align with word */ + uint8 pad2; /* Padding byte to align with word */ + uint8 pad3; /* Padding byte to align with word */ +} phy_periodic_log_cmn_v6_t; + +typedef struct phy_periodic_log_cmn_v7 { + + uint32 nrate; /* Current Tx nrate */ + uint32 duration; /* millisecs spent sampling this channel */ + uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ + /* move if cur bss moves channels) */ + uint32 congest_obss; /* traffic not in our bss */ + uint32 interference; /* millisecs detecting a non 802.11 interferer. */ + uint32 last_cal_time; /* Last cal execution time */ + + uint32 noise_cal_req_ts; /* Time-stamp when noise cal was requested */ + uint32 noise_cal_intr_ts; /* Time-stamp when noise cal was completed */ + uint32 phywdg_ts; /* Time-stamp when wd was fired */ + uint32 phywd_dur; /* Duration of the watchdog */ + uint32 chanspec_set_ts; /* Time-stamp when chanspec was set */ + uint32 vcopll_failure_cnt; /* Number of VCO cal failures including */ + /* failures detected in ucode */ + uint32 log_ts; /* Time-stamp when this log was collected */ + + /* glitch based desense input from cca */ + uint32 cca_stats_total_glitch; + uint32 cca_stats_bphy_glitch; + uint32 cca_stats_total_badplcp; + uint32 cca_stats_bphy_badplcp; + uint32 cca_stats_mbsstime; + + uint32 counter_noise_request; /* count of noisecal request */ + uint32 counter_noise_crsbit; /* count of crs high during noisecal request */ + uint32 counter_noise_apply; /* count of applying noisecal result to crsmin */ + uint32 fullphycalcntr; /* count of performing single phase cal */ + uint32 multiphasecalcntr; /* count of performing multi-phase cal */ + + uint32 macsusp_dur; /* mac suspend duration */ + + uint16 chanspec; /* Current phy chanspec */ + uint16 vbatmeas; /* Measured VBAT sense value */ + + uint16 featureflag; /* Currently active feature flags */ + + /* HP2P related params */ + uint16 shm_mpif_cnt_val; + uint16 shm_thld_cnt_val; + uint16 shm_nav_cnt_val; + uint16 shm_cts_cnt_val; + uint16 shm_m_prewds_cnt; /* Count of pre-wds fired in the ucode */ + + uint16 deaf_count; /* Depth of stay_in_carrier_search function */ + + uint16 ed20_crs0; /* ED-CRS status on core 0 */ + uint16 ed20_crs1; /* ED-CRS status on core 1 */ + + uint16 dcc_attempt_counter; /* Number of DC cal attempts */ + uint16 dcc_fail_counter; /* Number of DC cal failures */ + + uint16 btcxovrd_dur; /* Cumulative btcx overide between WDGs */ + uint16 btcxovrd_err_cnt; /* BTCX override flagged errors */ + + uint16 femtemp_read_fail_counter; /* Fem temparature read fail counter */ + uint16 phy_log_counter; + uint16 noise_mmt_overdue; /* Count up if ucode noise mmt is overdue for 5 sec */ + uint16 chan_switch_tm; /* Channel switch time */ + + uint16 dcc_hcfail; /* dcc health check failure count */ + uint16 dcc_calfail; /* dcc failure count */ + uint16 crsmin_pwr_apply_cnt; /* Count of desense power threshold update to phy */ + + uint16 txpustatus; /* txpu off definations */ + uint16 tempinvalid_count; /* Count no. of invalid temp. measurements */ + uint16 log_event_id; /* logging event id */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 debug_01; + uint16 debug_02; + uint16 debug_03; + uint16 debug_04; + uint16 debug_05; + + uint16 macsusp_cnt; /* mac suspend counter */ + uint8 amtbitmap; /* AMT status bitamp */ + + int8 chiptemp; /* Chip temparature */ + int8 femtemp; /* Fem temparature */ + + uint8 cal_phase_id; /* Current Multi phase cal ID */ + uint8 rxchain; /* Rx Chain */ + uint8 txchain; /* Tx Chain */ + uint8 ofdm_desense; /* OFDM desense */ + + uint8 slice; + uint8 dbgfw_ver; /* version of fw/ucode for debug purposes */ + uint8 bphy_desense; /* BPHY desense */ + uint8 pll_lockstatus; /* PLL Lock status */ + + /* dccal dcoe & idacc */ + uint8 dcc_err; /* dccal health check error status */ + uint8 dcoe_num_tries; /* number of retries on dcoe cal */ + uint8 idacc_num_tries; /* number of retries on idac cal */ + + uint8 dccal_phyrxchain; /* phy rxchain during dc calibration */ + uint8 dccal_type; /* DC cal type: single/multi phase, chan change, etc. */ + + uint8 gbd_bphy_sleep_counter; /* gbd sleep counter */ + uint8 gbd_ofdm_sleep_counter; /* gbd sleep counter */ + uint8 curr_home_channel; /* gbd input channel from cca */ + + /* desense data */ + int8 btcx_mode; /* btcoex desense mode */ + int8 ltecx_mode; /* lte coex desense mode */ + uint8 gbd_ofdm_desense; /* gbd ofdm desense level */ + uint8 gbd_bphy_desense; /* gbd bphy desense level */ + uint8 current_elna_bypass; /* init gain desense: elna bypass */ + uint8 current_tia_idx; /* init gain desense: tia index */ + uint8 current_lpf_idx; /* init gain desense: lpf index */ + uint8 crs_auto_thresh; /* crs auto threshold after desense */ + + int8 weakest_rssi; /* weakest link RSSI */ + uint8 noise_cal_mode; /* noisecal mode */ + + bool phycal_disable; /* Set if calibration is disabled */ + bool hwpwrctrlen; /* tx hwpwrctrl enable */ + uint8 pad1; /* Padding byte to align with word */ + uint8 pad2; /* Padding byte to align with word */ + uint8 pad3; /* Padding byte to align with word */ +} phy_periodic_log_cmn_v7_t; + +typedef struct phy_periodic_log_cmn_v8 { + + uint32 nrate; /* Current Tx nrate */ + uint32 duration; /* millisecs spent sampling this channel */ + uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ + /* move if cur bss moves channels) */ + uint32 congest_obss; /* traffic not in our bss */ + uint32 interference; /* millisecs detecting a non 802.11 interferer. */ + uint32 last_cal_time; /* Last cal execution time */ + + uint32 noise_cal_req_ts; /* Time-stamp when noise cal was requested */ + uint32 noise_cal_intr_ts; /* Time-stamp when noise cal was completed */ + uint32 phywdg_ts; /* Time-stamp when wd was fired */ + uint32 phywd_dur; /* Duration of the watchdog */ + uint32 chanspec_set_ts; /* Time-stamp when chanspec was set */ + uint32 vcopll_failure_cnt; /* Number of VCO cal failures including */ + /* failures detected in ucode */ + uint32 log_ts; /* Time-stamp when this log was collected */ + + /* glitch based desense input from cca */ + uint32 cca_stats_total_glitch; + uint32 cca_stats_bphy_glitch; + uint32 cca_stats_total_badplcp; + uint32 cca_stats_bphy_badplcp; + uint32 cca_stats_mbsstime; + + uint32 counter_noise_request; /* count of noisecal request */ + uint32 counter_noise_crsbit; /* count of crs high during noisecal request */ + uint32 counter_noise_apply; /* count of applying noisecal result to crsmin */ + uint32 fullphycalcntr; /* count of performing single phase cal */ + uint32 multiphasecalcntr; /* count of performing multi-phase cal */ + + uint32 macsusp_dur; /* mac suspend duration */ + + uint16 chanspec; /* Current phy chanspec */ + uint16 vbatmeas; /* Measured VBAT sense value */ + + uint16 featureflag; /* Currently active feature flags */ + + /* HP2P related params */ + uint16 shm_mpif_cnt_val; + uint16 shm_thld_cnt_val; + uint16 shm_nav_cnt_val; + uint16 shm_cts_cnt_val; + uint16 shm_m_prewds_cnt; /* Count of pre-wds fired in the ucode */ + + uint16 deaf_count; /* Depth of stay_in_carrier_search function */ + + uint16 ed20_crs0; /* ED-CRS status on core 0 */ + uint16 ed20_crs1; /* ED-CRS status on core 1 */ + + uint16 dcc_attempt_counter; /* Number of DC cal attempts */ + uint16 dcc_fail_counter; /* Number of DC cal failures */ + + uint16 btcxovrd_dur; /* Cumulative btcx overide between WDGs */ + uint16 btcxovrd_err_cnt; /* BTCX override flagged errors */ + + uint16 femtemp_read_fail_counter; /* Fem temparature read fail counter */ + uint16 phy_log_counter; + uint16 noise_mmt_overdue; /* Count up if ucode noise mmt is overdue for 5 sec */ + uint16 chan_switch_tm; /* Channel switch time */ + + uint16 dcc_hcfail; /* dcc health check failure count */ + uint16 dcc_calfail; /* dcc failure count */ + uint16 crsmin_pwr_apply_cnt; /* Count of desense power threshold update to phy */ + + uint16 txpustatus; /* txpu off definations */ + uint16 tempinvalid_count; /* Count no. of invalid temp. measurements */ + uint16 log_event_id; /* logging event id */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 measurehold_high; /* PHY hold activities high16 */ + uint16 measurehold_low; /* PHY hold activities low16 */ + uint16 tpc_hc_count; /* RAM A HC counter */ + uint16 tpc_hc_bkoff; /* RAM A HC core0 power backoff */ + uint16 btcx_ackpwroffset; /* CoreMask (low8) and ack_pwr_offset (high8) */ + + uint16 macsusp_cnt; /* mac suspend counter */ + uint8 amtbitmap; /* AMT status bitamp */ + + int8 chiptemp; /* Chip temparature */ + int8 femtemp; /* Fem temparature */ + + uint8 cal_phase_id; /* Current Multi phase cal ID */ + uint8 rxchain; /* Rx Chain */ + uint8 txchain; /* Tx Chain */ + uint8 ofdm_desense; /* OFDM desense */ + + uint8 slice; + uint8 dbgfw_ver; /* version of fw/ucode for debug purposes */ + uint8 bphy_desense; /* BPHY desense */ + uint8 pll_lockstatus; /* PLL Lock status */ + + /* dccal dcoe & idacc */ + uint8 dcc_err; /* dccal health check error status */ + uint8 dcoe_num_tries; /* number of retries on dcoe cal */ + uint8 idacc_num_tries; /* number of retries on idac cal */ + + uint8 dccal_phyrxchain; /* phy rxchain during dc calibration */ + uint8 dccal_type; /* DC cal type: single/multi phase, chan change, etc. */ + + uint8 gbd_bphy_sleep_counter; /* gbd sleep counter */ + uint8 gbd_ofdm_sleep_counter; /* gbd sleep counter */ + uint8 curr_home_channel; /* gbd input channel from cca */ + + /* desense data */ + int8 btcx_mode; /* btcoex desense mode */ + int8 ltecx_mode; /* lte coex desense mode */ + uint8 gbd_ofdm_desense; /* gbd ofdm desense level */ + uint8 gbd_bphy_desense; /* gbd bphy desense level */ + uint8 current_elna_bypass; /* init gain desense: elna bypass */ + uint8 current_tia_idx; /* init gain desense: tia index */ + uint8 current_lpf_idx; /* init gain desense: lpf index */ + uint8 crs_auto_thresh; /* crs auto threshold after desense */ + + int8 weakest_rssi; /* weakest link RSSI */ + uint8 noise_cal_mode; /* noisecal mode */ + + bool phycal_disable; /* Set if calibration is disabled */ + bool hwpwrctrlen; /* tx hwpwrctrl enable */ + int8 ed_threshold; /* Threshold applied for ED */ + uint16 ed_crs_status; /* Status of ED and CRS during noise cal */ + uint16 preempt_status1; /* status of preemption */ + uint16 preempt_status2; /* status of preemption */ + uint16 preempt_status3; /* status of preemption */ + uint16 preempt_status4; /* status of preemption */ + uint32 ed_duration; /* ccastats: ed_duration */ +} phy_periodic_log_cmn_v8_t; + +/* Inherited from v8 */ +typedef struct phy_periodic_log_cmn_v9 { + + uint32 nrate; /* Current Tx nrate */ + uint32 duration; /* millisecs spent sampling this channel */ + uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ + /* move if cur bss moves channels) */ + uint32 congest_obss; /* traffic not in our bss */ + uint32 interference; /* millisecs detecting a non 802.11 interferer. */ + uint32 last_cal_time; /* Last cal execution time */ + + uint32 noise_cal_req_ts; /* Time-stamp when noise cal was requested */ + uint32 noise_cal_intr_ts; /* Time-stamp when noise cal was completed */ + uint32 phywdg_ts; /* Time-stamp when wd was fired */ + uint32 phywd_dur; /* Duration of the watchdog */ + uint32 chanspec_set_ts; /* Time-stamp when chanspec was set */ + uint32 vcopll_failure_cnt; /* Number of VCO cal failures including */ + /* failures detected in ucode */ + uint32 log_ts; /* Time-stamp when this log was collected */ + + /* glitch based desense input from cca */ + uint32 cca_stats_total_glitch; + uint32 cca_stats_bphy_glitch; + uint32 cca_stats_total_badplcp; + uint32 cca_stats_bphy_badplcp; + uint32 cca_stats_mbsstime; + + uint32 counter_noise_request; /* count of noisecal request */ + uint32 counter_noise_crsbit; /* count of crs high during noisecal request */ + uint32 counter_noise_apply; /* count of applying noisecal result to crsmin */ + uint32 fullphycalcntr; /* count of performing single phase cal */ + uint32 multiphasecalcntr; /* count of performing multi-phase cal */ + + uint32 macsusp_dur; /* mac suspend duration */ + + uint32 featureflag; /* Currently active feature flags */ + + uint16 chanspec; /* Current phy chanspec */ + uint16 vbatmeas; /* Measured VBAT sense value */ + + /* HP2P related params */ + uint16 shm_mpif_cnt_val; + uint16 shm_thld_cnt_val; + uint16 shm_nav_cnt_val; + uint16 shm_cts_cnt_val; + uint16 shm_m_prewds_cnt; /* Count of pre-wds fired in the ucode */ + + uint16 deaf_count; /* Depth of stay_in_carrier_search function */ + + uint16 ed20_crs0; /* ED-CRS status on core 0 */ + uint16 ed20_crs1; /* ED-CRS status on core 1 */ + + uint16 dcc_attempt_counter; /* Number of DC cal attempts */ + uint16 dcc_fail_counter; /* Number of DC cal failures */ + + uint16 btcxovrd_dur; /* Cumulative btcx overide between WDGs */ + uint16 btcxovrd_err_cnt; /* BTCX override flagged errors */ + + uint16 femtemp_read_fail_counter; /* Fem temparature read fail counter */ + uint16 phy_log_counter; + uint16 noise_mmt_overdue; /* Count up if ucode noise mmt is overdue for 5 sec */ + uint16 chan_switch_tm; /* Channel switch time */ + + uint16 dcc_hcfail; /* dcc health check failure count */ + uint16 dcc_calfail; /* dcc failure count */ + uint16 crsmin_pwr_apply_cnt; /* Count of desense power threshold update to phy */ + + uint16 txpustatus; /* txpu off definations */ + uint16 tempinvalid_count; /* Count no. of invalid temp. measurements */ + uint16 log_event_id; /* logging event id */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + int8 ed_threshold0; /* Threshold applied for ED core 0 */ + int8 ed_threshold1; /* Threshold applied for ED core 1 */ + uint16 debug_01; + uint16 debug_02; + uint16 debug_03; + uint16 debug_04; + + uint16 macsusp_cnt; /* mac suspend counter */ + uint8 amtbitmap; /* AMT status bitamp */ + + int8 chiptemp; /* Chip temparature */ + int8 femtemp; /* Fem temparature */ + + uint8 cal_phase_id; /* Current Multi phase cal ID */ + uint8 rxchain; /* Rx Chain */ + uint8 txchain; /* Tx Chain */ + uint8 ofdm_desense; /* OFDM desense */ + + uint8 slice; + uint8 dbgfw_ver; /* version of fw/ucode for debug purposes */ + uint8 bphy_desense; /* BPHY desense */ + uint8 pll_lockstatus; /* PLL Lock status */ + + /* dccal dcoe & idacc */ + uint8 dcc_err; /* dccal health check error status */ + uint8 dcoe_num_tries; /* number of retries on dcoe cal */ + uint8 idacc_num_tries; /* number of retries on idac cal */ + + uint8 dccal_phyrxchain; /* phy rxchain during dc calibration */ + uint8 dccal_type; /* DC cal type: single/multi phase, chan change, etc. */ + + uint8 gbd_bphy_sleep_counter; /* gbd sleep counter */ + uint8 gbd_ofdm_sleep_counter; /* gbd sleep counter */ + uint8 curr_home_channel; /* gbd input channel from cca */ + + /* desense data */ + int8 btcx_mode; /* btcoex desense mode */ + int8 ltecx_mode; /* lte coex desense mode */ + uint8 gbd_ofdm_desense; /* gbd ofdm desense level */ + uint8 gbd_bphy_desense; /* gbd bphy desense level */ + uint8 current_elna_bypass; /* init gain desense: elna bypass */ + uint8 current_tia_idx; /* init gain desense: tia index */ + uint8 current_lpf_idx; /* init gain desense: lpf index */ + uint8 crs_auto_thresh; /* crs auto threshold after desense */ + + int8 weakest_rssi; /* weakest link RSSI */ + uint8 noise_cal_mode; /* noisecal mode */ + + bool phycal_disable; /* Set if calibration is disabled */ + bool hwpwrctrlen; /* tx hwpwrctrl enable */ + int8 ed_threshold; /* Threshold applied for ED */ + uint16 ed_crs_status; /* Status of ED and CRS during noise cal */ + uint16 preempt_status1; /* status of preemption */ + uint16 preempt_status2; /* status of preemption */ + uint16 preempt_status3; /* status of preemption */ + uint16 preempt_status4; /* status of preemption */ + uint8 debug_05; + uint8 cal_suppressed_cntr_ed; /* counter including ss, mp cals, MSB is current state */ + uint32 ed_duration; /* ccastats: ed_duration */ +} phy_periodic_log_cmn_v9_t; + +/* Inherited from v9 */ +typedef struct phy_periodic_log_cmn_v10 { + + uint32 nrate; /* Current Tx nrate */ + uint32 duration; /* millisecs spent sampling this channel */ + uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ + /* move if cur bss moves channels) */ + uint32 congest_obss; /* traffic not in our bss */ + uint32 interference; /* millisecs detecting a non 802.11 interferer. */ + uint32 last_cal_time; /* Last cal execution time */ + + uint32 noise_cal_req_ts; /* Time-stamp when noise cal was requested */ + uint32 noise_cal_intr_ts; /* Time-stamp when noise cal was completed */ + uint32 phywdg_ts; /* Time-stamp when wd was fired */ + uint32 phywd_dur; /* Duration of the watchdog */ + uint32 chanspec_set_ts; /* Time-stamp when chanspec was set */ + uint32 vcopll_failure_cnt; /* Number of VCO cal failures including */ + /* failures detected in ucode */ + uint32 log_ts; /* Time-stamp when this log was collected */ + + /* glitch based desense input from cca */ + uint32 cca_stats_total_glitch; + uint32 cca_stats_bphy_glitch; + uint32 cca_stats_total_badplcp; + uint32 cca_stats_bphy_badplcp; + uint32 cca_stats_mbsstime; + + uint32 counter_noise_request; /* count of noisecal request */ + uint32 counter_noise_crsbit; /* count of crs high during noisecal request */ + uint32 counter_noise_apply; /* count of applying noisecal result to crsmin */ + uint32 fullphycalcntr; /* count of performing single phase cal */ + uint32 multiphasecalcntr; /* count of performing multi-phase cal */ + + uint32 macsusp_dur; /* mac suspend duration */ + + uint32 featureflag; /* Currently active feature flags */ + + uint16 chanspec; /* Current phy chanspec */ + uint16 vbatmeas; /* Measured VBAT sense value */ + + /* HP2P related params */ + uint16 shm_mpif_cnt_val; + uint16 shm_thld_cnt_val; + uint16 shm_nav_cnt_val; + uint16 shm_cts_cnt_val; + uint16 shm_m_prewds_cnt; /* Count of pre-wds fired in the ucode */ + + uint16 deaf_count; /* Depth of stay_in_carrier_search function */ + + uint16 ed20_crs0; /* ED-CRS status on core 0 */ + uint16 ed20_crs1; /* ED-CRS status on core 1 */ + + uint16 dcc_attempt_counter; /* Number of DC cal attempts */ + uint16 dcc_fail_counter; /* Number of DC cal failures */ + + uint16 btcxovrd_dur; /* Cumulative btcx overide between WDGs */ + uint16 btcxovrd_err_cnt; /* BTCX override flagged errors */ + + uint16 femtemp_read_fail_counter; /* Fem temparature read fail counter */ + uint16 phy_log_counter; + uint16 noise_mmt_overdue; /* Count up if ucode noise mmt is overdue for 5 sec */ + uint16 chan_switch_tm; /* Channel switch time */ + + uint16 dcc_hcfail; /* dcc health check failure count */ + uint16 dcc_calfail; /* dcc failure count */ + uint16 crsmin_pwr_apply_cnt; /* Count of desense power threshold update to phy */ + + uint16 txpustatus; /* txpu off definations */ + uint16 tempinvalid_count; /* Count no. of invalid temp. measurements */ + uint16 log_event_id; /* logging event id */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 pktprocdebug; + uint16 pktprocdebug2; + uint16 timeoutstatus; + uint16 debug_04; + uint16 debug_05; + + uint16 macsusp_cnt; /* mac suspend counter */ + uint8 amtbitmap; /* AMT status bitamp */ + + int8 chiptemp; /* Chip temparature */ + int8 femtemp; /* Fem temparature */ + + uint8 cal_phase_id; /* Current Multi phase cal ID */ + uint8 rxchain; /* Rx Chain */ + uint8 txchain; /* Tx Chain */ + uint8 ofdm_desense; /* OFDM desense */ + + uint8 slice; + uint8 dbgfw_ver; /* version of fw/ucode for debug purposes */ + uint8 bphy_desense; /* BPHY desense */ + uint8 pll_lockstatus; /* PLL Lock status */ + + /* dccal dcoe & idacc */ + uint8 dcc_err; /* dccal health check error status */ + uint8 dcoe_num_tries; /* number of retries on dcoe cal */ + uint8 idacc_num_tries; /* number of retries on idac cal */ + + uint8 dccal_phyrxchain; /* phy rxchain during dc calibration */ + uint8 dccal_type; /* DC cal type: single/multi phase, chan change, etc. */ + + uint8 gbd_bphy_sleep_counter; /* gbd sleep counter */ + uint8 gbd_ofdm_sleep_counter; /* gbd sleep counter */ + uint8 curr_home_channel; /* gbd input channel from cca */ + + /* desense data */ + int8 btcx_mode; /* btcoex desense mode */ + int8 ltecx_mode; /* lte coex desense mode */ + uint8 gbd_ofdm_desense; /* gbd ofdm desense level */ + uint8 gbd_bphy_desense; /* gbd bphy desense level */ + uint8 current_elna_bypass; /* init gain desense: elna bypass */ + uint8 current_tia_idx; /* init gain desense: tia index */ + uint8 current_lpf_idx; /* init gain desense: lpf index */ + uint8 crs_auto_thresh; /* crs auto threshold after desense */ + + int8 weakest_rssi; /* weakest link RSSI */ + uint8 noise_cal_mode; /* noisecal mode */ + + bool phycal_disable; /* Set if calibration is disabled */ + bool hwpwrctrlen; /* tx hwpwrctrl enable */ + int8 ed_threshold; /* Threshold applied for ED */ + uint32 measurehold; /* PHY hold activities */ + uint32 ed_duration; /* ccastats: ed_duration */ + uint16 ed_crs_status; /* Status of ED and CRS during noise cal */ + uint16 preempt_status1; /* status of preemption */ + uint16 preempt_status2; /* status of preemption */ + uint16 preempt_status3; /* status of preemption */ + uint16 preempt_status4; /* status of preemption */ + + uint16 counter_noise_iqest_to; /* count of IQ_Est time out */ + uint16 rfemstate2g; /* rFEM state register for 2g */ + uint16 rfemstate5g; /* rFEM state register for 5g */ + uint16 txiqcal_max_retry_cnt; /* txiqlocal retries reached max allowed count */ + uint16 txiqcal_max_slope_cnt; /* txiqlocal slope reached max allowed count */ + uint16 mppc_cal_failed_cnt; /* MPPC cal failure count */ + + uint16 gci_lst_inv_ctr; + uint16 gci_lst_rst_ctr; + uint16 gci_lst_sem_fail; + uint16 gci_lst_rb_state; + uint16 gci_lst_pad01; + uint16 gci_lst_pad02; + uint16 gci_lst_pad03; + uint16 gci_lst_pad04; + uint16 gci_lst_pad05; + uint16 gci_lst_state_mask; + uint16 gci_inv_tx; /* Tx inv cnt */ + uint16 gci_inv_rx; /* Rx inv cnt */ + uint16 gci_rst_tx; /* gci Tx reset cnt */ + uint16 gci_rst_rx; /* gci Rx reset cnt */ + uint16 gci_sem_fail; + uint16 gci_invstate; /* inv state */ + uint16 gci_phyctl0; /* TX_PHYCTL0 */ + uint16 gci_phyctl1; /* TX_PHYCTL1 */ + uint16 gci_phyctl2; /* TX_PHYCTL2 */ + uint16 gci_ctxtst; /* S_CTXTST */ + uint16 gci_invts; /* When gci read request was placed and completed */ + uint16 gci_invtsdn; /* */ + uint16 gci_invtxs; /* timestamp for TXCRS assertion */ + uint16 gci_invtxdur; /* IFS_TX_DUR */ + uint16 gci_invifs; /* IFS status */ + uint16 gci_chan; /* For additional ucode data */ + uint16 gci_pad02; /* For additional ucode data */ + uint16 gci_pad03; /* For additional ucode data */ + uint16 gci_pad04; /* For additional ucode data */ + + uint32 rxsense_disable_req_ch; /* channel disable requests */ + uint32 ocl_disable_reqs; /* OCL disable bitmap */ + + int8 rxsense_noise_idx; /* rxsense detection threshold desense index */ + int8 rxsense_offset; /* rxsense min power desense index */ + uint8 ocl_en_status; /* OCL requested state and OCL HW state */ + uint8 lpc_status; /* Flag to enable/disable LPC, and runtime flag status */ + + uint16 rspfrm_ed_txncl_cnt; /* Response frame not sent due to ED */ + + int16 last_cal_temp; + uint8 cal_reason; /* reason for the cal */ + uint8 cal_suppressed_cntr_ed; /* counter including ss, mp cals, MSB is current state */ + uint8 phylog_noise_mode; /* Noise mode used */ + uint8 debug_08; + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint32 interference_mode; /* interference mitigation mode */ + uint32 power_mode; /* LP/VLP logging */ + uint32 debug_11; + uint32 debug_12; +} phy_periodic_log_cmn_v10_t; + +typedef struct phy_periodic_log_cmn_v11 { + uint32 nrate; /* Current Tx nrate */ + uint32 duration; /* millisecs spent sampling this channel */ + uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ + /* move if cur bss moves channels) */ + uint32 congest_obss; /* traffic not in our bss */ + uint32 interference; /* millisecs detecting a non 802.11 interferer. */ + uint32 last_cal_time; /* Last cal execution time */ + + uint32 noise_cal_req_ts; /* Time-stamp when noise cal was requested */ + uint32 noise_cal_intr_ts; /* Time-stamp when noise cal was completed */ + uint32 phywdg_ts; /* Time-stamp when wd was fired */ + uint32 phywd_dur; /* Duration of the watchdog */ + uint32 chanspec_set_ts; /* Time-stamp when chanspec was set */ + uint32 vcopll_failure_cnt; /* Number of VCO cal failures including */ + /* failures detected in ucode */ + uint32 log_ts; /* Time-stamp when this log was collected */ + + /* glitch based desense input from cca */ + uint32 cca_stats_total_glitch; + uint32 cca_stats_bphy_glitch; + uint32 cca_stats_total_badplcp; + uint32 cca_stats_bphy_badplcp; + uint32 cca_stats_mbsstime; + + uint32 counter_noise_request; /* count of noisecal request */ + uint32 counter_noise_crsbit; /* count of crs high during noisecal request */ + uint32 counter_noise_apply; /* count of applying noisecal result to crsmin */ + uint32 fullphycalcntr; /* count of performing single phase cal */ + uint32 multiphasecalcntr; /* count of performing multi-phase cal */ + + uint32 macsusp_dur; /* mac suspend duration */ + + uint32 featureflag; /* Currently active feature flags */ + + uint16 chanspec; /* Current phy chanspec */ + uint16 vbatmeas; /* Measured VBAT sense value */ + + /* HP2P related params */ + uint16 shm_mpif_cnt_val; + uint16 shm_thld_cnt_val; + uint16 shm_nav_cnt_val; + uint16 shm_cts_cnt_val; + uint16 shm_m_prewds_cnt; /* Count of pre-wds fired in the ucode */ + + uint16 deaf_count; /* Depth of stay_in_carrier_search function */ + + uint16 ed20_crs0; /* ED-CRS status on core 0 */ + uint16 ed20_crs1; /* ED-CRS status on core 1 */ + + uint16 dcc_attempt_counter; /* Number of DC cal attempts */ + uint16 dcc_fail_counter; /* Number of DC cal failures */ + + uint16 btcxovrd_dur; /* Cumulative btcx overide between WDGs */ + uint16 btcxovrd_err_cnt; /* BTCX override flagged errors */ + + uint16 femtemp_read_fail_counter; /* Fem temparature read fail counter */ + uint16 phy_log_counter; + uint16 noise_mmt_overdue; /* Count up if ucode noise mmt is overdue for 5 sec */ + uint16 chan_switch_tm; /* Channel switch time */ + + uint16 dcc_hcfail; /* dcc health check failure count */ + uint16 dcc_calfail; /* dcc failure count */ + uint16 crsmin_pwr_apply_cnt; /* Count of desense power threshold update to phy */ + + uint16 txpustatus; /* txpu off definations */ + uint16 tempinvalid_count; /* Count no. of invalid temp. measurements */ + uint16 log_event_id; /* logging event id */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 debug_01; + uint16 debug_02; + uint16 debug_03; + uint16 debug_04; + uint16 debug_05; + + uint16 macsusp_cnt; /* mac suspend counter */ + uint8 amtbitmap; /* AMT status bitamp */ + + int8 chiptemp; /* Chip temparature */ + int8 femtemp; /* Fem temparature */ + + uint8 cal_phase_id; /* Current Multi phase cal ID */ + uint8 rxchain; /* Rx Chain */ + uint8 txchain; /* Tx Chain */ + uint8 ofdm_desense; /* OFDM desense */ + + uint8 slice; + uint8 bphy_desense; /* BPHY desense */ + uint8 pll_lockstatus; /* PLL Lock status */ + + /* dccal dcoe & idacc */ + uint8 dcc_err; /* dccal health check error status */ + uint8 dcoe_num_tries; /* number of retries on dcoe cal */ + uint8 idacc_num_tries; /* number of retries on idac cal */ + + uint8 dccal_phyrxchain; /* phy rxchain during dc calibration */ + uint8 dccal_type; /* DC cal type: single/multi phase, chan change, etc. */ + + uint8 gbd_bphy_sleep_counter; /* gbd sleep counter */ + uint8 gbd_ofdm_sleep_counter; /* gbd sleep counter */ + + /* desense data */ + int8 btcx_mode; /* btcoex desense mode */ + int8 ltecx_mode; /* lte coex desense mode */ + uint8 gbd_ofdm_desense; /* gbd ofdm desense level */ + uint8 gbd_bphy_desense; /* gbd bphy desense level */ + uint8 current_elna_bypass; /* init gain desense: elna bypass */ + uint8 current_tia_idx; /* init gain desense: tia index */ + uint8 current_lpf_idx; /* init gain desense: lpf index */ + + int8 weakest_rssi; /* weakest link RSSI */ + + bool phycal_disable; /* Set if calibration is disabled */ + bool hwpwrctrlen; /* tx hwpwrctrl enable */ + int8 debug_15; /* multipurpose debug counter */ + uint32 ed_duration; /* ccastats: ed_duration */ + uint16 ed_crs_status; /* Status of ED and CRS during noise cal */ + uint16 preempt_status1; /* status of preemption */ + uint16 preempt_status2; /* status of preemption */ + uint16 preempt_status3; /* status of preemption */ + uint16 preempt_status4; /* status of preemption */ + + uint16 timeoutstatus; + uint32 measurehold; /* PHY hold activities */ + uint16 pktprocdebug; + uint16 pktprocdebug2; + + uint16 counter_noise_iqest_to; /* count of IQ_Est time out */ + uint16 rfemstate2g; /* rFEM state register for 2g */ + uint16 rfemstate5g; /* rFEM state register for 5g */ + uint16 txiqcal_max_retry_cnt; /* txiqlocal retries reached max allowed count */ + uint16 txiqcal_max_slope_cnt; /* txiqlocal slope reached max allowed count */ + uint16 mppc_cal_failed_cnt; /* MPPC cal failure count */ + + uint16 gci_lst_inv_ctr; + uint16 gci_lst_rst_ctr; + uint16 gci_lst_sem_fail; + uint16 gci_lst_rb_state; + uint16 gci_lst_pad01; + uint16 gci_lst_pad02; + uint16 gci_lst_pad03; + uint16 gci_lst_pad04; + uint16 gci_lst_pad05; + uint16 gci_lst_state_mask; + uint16 gci_inv_tx; /* Tx inv cnt */ + uint16 gci_inv_rx; /* Rx inv cnt */ + uint16 gci_rst_tx; /* gci Tx reset cnt */ + uint16 gci_rst_rx; /* gci Rx reset cnt */ + uint16 gci_sem_fail; + uint16 gci_invstate; /* inv state */ + uint16 gci_phyctl0; /* TX_PHYCTL0 */ + uint16 gci_phyctl2; /* TX_PHYCTL2 */ + uint16 gci_ctxtst; /* S_CTXTST */ + uint16 gci_chan; /* GCI channel */ + uint16 gci_cm; + uint16 gci_inv_intr; + uint16 gci_rst_intr; + uint16 gci_rst_prdc_rx; + uint16 gci_rst_wk_rx; + uint16 gci_rst_rmac_rx; + uint16 gci_rst_tx_rx; + uint16 gci_pad01; /* For additional ucode data */ + uint16 gci_pad02; /* For additional ucode data */ + uint16 gci_pad03; /* For additional ucode data */ + uint16 gci_pad04; /* For additional ucode data */ + + uint32 rxsense_disable_req_ch; /* channel disable requests */ + uint32 ocl_disable_reqs; /* OCL disable bitmap */ + + int8 rxsense_noise_idx; /* rxsense detection threshold desense index */ + int8 rxsense_offset; /* rxsense min power desense index */ + uint8 ocl_en_status; /* OCL requested state and OCL HW state */ + uint8 lpc_status; /* Flag to enable/disable LPC, and runtime flag status */ + + uint16 rspfrm_ed_txncl_cnt; /* Response frame not sent due to ED */ + + int16 last_cal_temp; + uint8 cal_reason; /* reason for the cal */ + uint8 cal_suppressed_cntr_ed; /* counter including ss, mp cals, MSB is current state */ + uint8 phylog_noise_mode; /* Noise mode used */ + uint8 noise_cal_mode; /* noisecal mode */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + int8 ed_threshold0; /* Threshold applied for ED core 0 */ + int8 ed_threshold1; /* Threshold applied for ED core 1 */ + uint8 debug_08; + uint8 debug_09; + + uint32 interference_mode; /* interference mitigation mode */ + uint32 power_mode; /* LP/VLP logging */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint32 debug_10; + uint32 debug_11; + uint32 debug_12; + uint32 debug_13; + uint32 debug_14; +} phy_periodic_log_cmn_v11_t; + +typedef struct phy_periodic_log_cmn_v255 { + uint32 nrate; /* Current Tx nrate */ + uint32 duration; /* millisecs spent sampling this channel */ + uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ + /* move if cur bss moves channels) */ + uint32 congest_obss; /* traffic not in our bss */ + uint32 interference; /* millisecs detecting a non 802.11 interferer. */ + uint32 last_cal_time; /* Last cal execution time */ + + uint32 noise_cal_req_ts; /* Time-stamp when noise cal was requested */ + uint32 noise_cal_intr_ts; /* Time-stamp when noise cal was completed */ + uint32 phywdg_ts; /* Time-stamp when wd was fired */ + uint32 phywd_dur; /* Duration of the watchdog */ + uint32 chanspec_set_ts; /* Time-stamp when chanspec was set */ + uint32 vcopll_failure_cnt; /* Number of VCO cal failures including */ + /* failures detected in ucode */ + uint32 log_ts; /* Time-stamp when this log was collected */ + + /* glitch based desense input from cca */ + uint32 cca_stats_total_glitch; + uint32 cca_stats_bphy_glitch; + uint32 cca_stats_total_badplcp; + uint32 cca_stats_bphy_badplcp; + uint32 cca_stats_mbsstime; + + uint32 counter_noise_request; /* count of noisecal request */ + uint32 counter_noise_crsbit; /* count of crs high during noisecal request */ + uint32 counter_noise_apply; /* count of applying noisecal result to crsmin */ + uint32 fullphycalcntr; /* count of performing single phase cal */ + uint32 multiphasecalcntr; /* count of performing multi-phase cal */ + + uint32 macsusp_dur; /* mac suspend duration */ + + uint32 featureflag; /* Currently active feature flags */ + + uint16 chanspec; /* Current phy chanspec */ + uint16 vbatmeas; /* Measured VBAT sense value */ + + /* HP2P related params */ + uint16 shm_mpif_cnt_val; + uint16 shm_thld_cnt_val; + uint16 shm_nav_cnt_val; + uint16 shm_cts_cnt_val; + uint16 shm_m_prewds_cnt; /* Count of pre-wds fired in the ucode */ + + uint16 deaf_count; /* Depth of stay_in_carrier_search function */ + + uint16 ed20_crs0; /* ED-CRS status on core 0 */ + uint16 ed20_crs1; /* ED-CRS status on core 1 */ + + uint16 dcc_attempt_counter; /* Number of DC cal attempts */ + uint16 dcc_fail_counter; /* Number of DC cal failures */ + + uint16 btcxovrd_dur; /* Cumulative btcx overide between WDGs */ + uint16 btcxovrd_err_cnt; /* BTCX override flagged errors */ + + uint16 femtemp_read_fail_counter; /* Fem temparature read fail counter */ + uint16 phy_log_counter; + uint16 noise_mmt_overdue; /* Count up if ucode noise mmt is overdue for 5 sec */ + uint16 chan_switch_tm; /* Channel switch time */ + + uint16 dcc_hcfail; /* dcc health check failure count */ + uint16 dcc_calfail; /* dcc failure count */ + uint16 crsmin_pwr_apply_cnt; /* Count of desense power threshold update to phy */ + + uint16 txpustatus; /* txpu off definations */ + uint16 tempinvalid_count; /* Count no. of invalid temp. measurements */ + uint16 log_event_id; /* logging event id */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 debug_01; + uint16 debug_02; + uint16 debug_03; + uint16 debug_04; + uint16 debug_05; + + uint16 macsusp_cnt; /* mac suspend counter */ + uint8 amtbitmap; /* AMT status bitamp */ + + int8 chiptemp; /* Chip temparature */ + int8 femtemp; /* Fem temparature */ + + uint8 cal_phase_id; /* Current Multi phase cal ID */ + uint8 rxchain; /* Rx Chain */ + uint8 txchain; /* Tx Chain */ + uint8 ofdm_desense; /* OFDM desense */ + + uint8 slice; + uint8 bphy_desense; /* BPHY desense */ + uint8 pll_lockstatus; /* PLL Lock status */ + + /* dccal dcoe & idacc */ + uint8 dcc_err; /* dccal health check error status */ + uint8 dcoe_num_tries; /* number of retries on dcoe cal */ + uint8 idacc_num_tries; /* number of retries on idac cal */ + + uint8 dccal_phyrxchain; /* phy rxchain during dc calibration */ + uint8 dccal_type; /* DC cal type: single/multi phase, chan change, etc. */ + + uint8 gbd_bphy_sleep_counter; /* gbd sleep counter */ + uint8 gbd_ofdm_sleep_counter; /* gbd sleep counter */ + + /* desense data */ + int8 btcx_mode; /* btcoex desense mode */ + int8 ltecx_mode; /* lte coex desense mode */ + uint8 gbd_ofdm_desense; /* gbd ofdm desense level */ + uint8 gbd_bphy_desense; /* gbd bphy desense level */ + uint8 current_elna_bypass; /* init gain desense: elna bypass */ + uint8 current_tia_idx; /* init gain desense: tia index */ + uint8 current_lpf_idx; /* init gain desense: lpf index */ + + int8 weakest_rssi; /* weakest link RSSI */ + + bool phycal_disable; /* Set if calibration is disabled */ + bool hwpwrctrlen; /* tx hwpwrctrl enable */ + uint8 phylog_noise_mode; /* Noise mode used */ + + uint32 ed_duration; /* ccastats: ed_duration */ + uint16 ed_crs_status; /* Status of ED and CRS during noise cal */ + uint16 preempt_status1; /* status of preemption */ + uint16 preempt_status2; /* status of preemption */ + uint16 preempt_status3; /* status of preemption */ + uint16 preempt_status4; /* status of preemption */ + + uint16 timeoutstatus; + uint32 measurehold; /* PHY hold activities */ + uint16 pktprocdebug; + uint16 pktprocdebug2; + + uint16 counter_noise_iqest_to; /* count of IQ_Est time out */ + uint16 rfemstate2g; /* rFEM state register for 2g */ + uint16 rfemstate5g; /* rFEM state register for 5g */ + uint16 txiqcal_max_retry_cnt; /* txiqlocal retries reached max allowed count */ + uint16 txiqcal_max_slope_cnt; /* txiqlocal slope reached max allowed count */ + uint16 mppc_cal_failed_cnt; /* MPPC cal failure count */ + + uint16 gci_lst_inv_ctr; + uint16 gci_lst_rst_ctr; + uint16 gci_lst_sem_fail; + uint16 gci_lst_rb_state; + uint16 gci_lst_pad01; + uint16 gci_lst_pad02; + uint16 gci_lst_pad03; + uint16 gci_lst_pad04; + uint16 gci_lst_pad05; + uint16 gci_lst_state_mask; + uint16 gci_inv_tx; /* Tx inv cnt */ + uint16 gci_inv_rx; /* Rx inv cnt */ + uint16 gci_rst_tx; /* gci Tx reset cnt */ + uint16 gci_rst_rx; /* gci Rx reset cnt */ + uint16 gci_sem_fail; + uint16 gci_invstate; /* inv state */ + uint16 gci_phyctl0; /* TX_PHYCTL0 */ + uint16 gci_phyctl2; /* TX_PHYCTL2 */ + uint16 gci_ctxtst; /* S_CTXTST */ + uint16 gci_chan; /* GCI channel */ + uint16 gci_cm; + uint16 gci_inv_intr; + uint16 gci_rst_intr; + uint16 gci_rst_prdc_rx; + uint16 gci_rst_wk_rx; + uint16 gci_rst_rmac_rx; + uint16 gci_rst_tx_rx; + uint16 gci_pad01; /* For additional ucode data */ + uint16 gci_pad02; /* For additional ucode data */ + uint16 gci_pad03; /* For additional ucode data */ + uint16 gci_pad04; /* For additional ucode data */ + + uint32 rxsense_disable_req_ch; /* channel disable requests */ + uint32 ocl_disable_reqs; /* OCL disable bitmap */ + + int8 rxsense_noise_idx; /* rxsense detection threshold desense index */ + int8 rxsense_offset; /* rxsense min power desense index */ + uint8 ocl_en_status; /* OCL requested state and OCL HW state */ + uint8 lpc_status; /* Flag to enable/disable LPC, and runtime flag status */ + + uint16 rspfrm_ed_txncl_cnt; /* Response frame not sent due to ED */ + + int16 last_cal_temp; + uint8 cal_reason; /* reason for the cal */ + uint8 cal_suppressed_cntr_ed; /* counter including ss, mp cals, MSB is current state */ + uint8 noise_cal_mode; /* noisecal mode */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint8 debug_06; + uint8 debug_07; + uint8 debug_08; + uint8 debug_09; + uint8 debug_10; + + uint32 interference_mode; /* interference mitigation mode */ + uint32 power_mode; /* LP/VLP logging */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint32 debug_11; + uint32 debug_12; + uint32 debug_13; + uint32 debug_14; +} phy_periodic_log_cmn_v255_t; + +typedef struct phy_periodic_log_core { + uint8 baseindxval; /* TPC Base index */ + int8 tgt_pwr; /* Programmed Target power */ + int8 estpwradj; /* Current Est Power Adjust value */ + int8 crsmin_pwr; /* CRS Min/Noise power */ + int8 rssi_per_ant; /* RSSI Per antenna */ + int8 snr_per_ant; /* SNR Per antenna */ + int8 pad1; /* Padding byte to align with word */ + int8 pad2; /* Padding byte to align with word */ +} phy_periodic_log_core_t; + +typedef struct phy_periodic_log_core_v3 { + uint8 baseindxval; /* TPC Base index */ + int8 tgt_pwr; /* Programmed Target power */ + int8 estpwradj; /* Current Est Power Adjust value */ + int8 crsmin_pwr; /* CRS Min/Noise power */ + int8 rssi_per_ant; /* RSSI Per antenna */ + int8 snr_per_ant; /* SNR Per antenna */ + + /* dccal dcoe & idacc */ + uint16 dcoe_done_0; /* dccal control register 44 */ + uint16 dcoe_done_1; /* dccal control register 45 */ + uint16 dcoe_done_2; /* dccal control register 46 */ + uint16 idacc_done_0; /* dccal control register 21 */ + uint16 idacc_done_1; /* dccal control register 60 */ + uint16 idacc_done_2; /* dccal control register 61 */ + int16 psb; /* psb read during dccal health check */ + uint8 pktproc; /* pktproc read during dccal health check */ + + int8 noise_level; /* noise level = crsmin_pwr if gdb desense is lesser */ + int8 pad2; /* Padding byte to align with word */ + int8 pad3; /* Padding byte to align with word */ +} phy_periodic_log_core_v3_t; + +typedef struct phy_periodic_log_core_v4 { + /* dccal dcoe & idacc */ + uint16 dcoe_done_0; /* dccal control register 44 */ + uint16 dcoe_done_1; /* dccal control register 45 */ + uint16 dcoe_done_2; /* dccal control register 46 */ + uint16 idacc_done_0; /* dccal control register 21 */ + uint16 idacc_done_1; /* dccal control register 60 */ + uint16 idacc_done_2; /* dccal control register 61 */ + int16 psb; /* psb read during dccal health check */ + int16 txcap; /* Txcap value */ + + uint16 debug_01; /* multipurpose debug register */ + uint16 debug_02; /* multipurpose debug register */ + uint16 debug_03; /* multipurpose debug register */ + uint16 debug_04; /* multipurpose debug register */ + + uint8 pktproc; /* pktproc read during dccal health check */ + uint8 baseindxval; /* TPC Base index */ + int8 tgt_pwr; /* Programmed Target power */ + int8 estpwradj; /* Current Est Power Adjust value */ + int8 crsmin_pwr; /* CRS Min/Noise power */ + int8 rssi_per_ant; /* RSSI Per antenna */ + int8 snr_per_ant; /* SNR Per antenna */ + + int8 noise_level; /* noise pwr after filtering & averageing */ + int8 noise_level_inst; /* instantaneous noise cal pwr */ + int8 estpwr; /* tx powerDet value */ +} phy_periodic_log_core_v4_t; + +typedef struct phy_periodic_log_core_v5 { + uint8 baseindxval; /* TPC Base index */ + int8 tgt_pwr; /* Programmed Target power */ + int8 estpwradj; /* Current Est Power Adjust value */ + int8 crsmin_pwr; /* CRS Min/Noise power */ + int8 rssi_per_ant; /* RSSI Per antenna */ + int8 snr_per_ant; /* SNR Per antenna */ + uint8 fp; + int8 phylog_noise_pwr_array[8]; /* noise buffer array */ + int8 noise_dbm_ant; /* from uCode shm read, afer converting to dBm */ +} phy_periodic_log_core_v5_t; + +#define PHY_NOISE_PWR_ARRAY_SIZE (8u) +typedef struct phy_periodic_log_core_v6 { + /* dccal dcoe & idacc */ + uint16 dcoe_done_0; /* dccal control register 44 */ + uint16 dcoe_done_1; /* dccal control register 45 */ + uint16 dcoe_done_2; /* dccal control register 46 */ + uint16 idacc_done_0; /* dccal control register 21 */ + uint16 idacc_done_1; /* dccal control register 60 */ + uint16 idacc_done_2; /* dccal control register 61 */ + int16 psb; /* psb read during dccal health check */ + int16 txcap; /* Txcap value */ + + uint16 curr_tssival; /* TxPwrCtrlInit_path[01].TSSIVal */ + uint16 pwridx_init; /* TxPwrCtrlInit_path[01].pwrIndex_init_path[01] */ + uint16 tpc_hc_tssi; /* RAM A HC TSSI value */ + uint16 btcx_antmask; /* antenna to be used by BT */ + + uint8 pktproc; /* pktproc read during dccal health check */ + uint8 baseindxval; /* TPC Base index */ + int8 tgt_pwr; /* Programmed Target power */ + int8 estpwradj; /* Current Est Power Adjust value */ + int8 crsmin_pwr; /* CRS Min/Noise power */ + int8 rssi_per_ant; /* RSSI Per antenna */ + int8 snr_per_ant; /* SNR Per antenna */ + + int8 noise_level; /* noise pwr after filtering & averageing */ + int8 noise_level_inst; /* instantaneous noise cal pwr */ + int8 estpwr; /* tx powerDet value */ + int8 crsmin_th_idx; /* idx used to lookup crs min thresholds */ + int8 tpc_hc_bidx; /* RAM A HC base index */ + + int8 phy_noise_pwr_array[PHY_NOISE_PWR_ARRAY_SIZE]; /* noise buffer array */ +} phy_periodic_log_core_v6_t; + +typedef struct phy_periodic_log_core_v7 { + /* dccal dcoe & idacc */ + uint16 dcoe_done_0; /* dccal control register 44 */ + uint16 dcoe_done_1; /* dccal control register 45 */ + uint16 dcoe_done_2; /* dccal control register 46 */ + uint16 idacc_done_0; /* dccal control register 21 */ + uint16 idacc_done_1; /* dccal control register 60 */ + uint16 idacc_done_2; /* dccal control register 61 */ + int16 psb; /* psb read during dccal health check */ + int16 txcap; /* Txcap value */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 bad_txbaseidx_cnt; /* cntr for tx_baseidx=127 in healthcheck */ + uint16 debug_02; + uint16 debug_03; + uint16 debug_04; + + uint8 pktproc; /* pktproc read during dccal health check */ + uint8 baseindxval; /* TPC Base index */ + int8 tgt_pwr; /* Programmed Target power */ + int8 estpwradj; /* Current Est Power Adjust value */ + int8 crsmin_pwr; /* CRS Min/Noise power */ + int8 rssi_per_ant; /* RSSI Per antenna */ + int8 snr_per_ant; /* SNR Per antenna */ + + int8 noise_level; /* noise pwr after filtering & averageing */ + int8 noise_level_inst; /* instantaneous noise cal pwr */ + int8 estpwr; /* tx powerDet value */ + int8 crsmin_th_idx; /* idx used to lookup crs min thresholds */ + uint8 pad01; + + uint16 curr_tssival; /* TxPwrCtrlInit_path[01].TSSIVal */ + uint16 pwridx_init; /* TxPwrCtrlInit_path[01].pwrIndex_init_path[01] */ + uint16 auxphystats; + uint16 phystatsgaininfo; + uint16 flexpwrAFE; + uint16 flexpwrdig1; + uint16 flexpwrdig2; + uint16 flexpwrdig3; + uint16 flexpwrdig4; + uint16 flexgaininfo_A; + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint8 debug_05; + uint8 debug_06; + uint8 debug_07; + uint8 debug_08; + + int8 phy_noise_pwr_array[PHY_NOISE_PWR_ARRAY_SIZE]; /* noise buffer array */ +} phy_periodic_log_core_v7_t; + +typedef struct phy_periodic_log_core_v255 { + /* dccal dcoe & idacc */ + uint16 dcoe_done_0; /* dccal control register 44 */ + uint16 dcoe_done_1; /* dccal control register 45 */ + uint16 dcoe_done_2; /* dccal control register 46 */ + uint16 idacc_done_0; /* dccal control register 21 */ + uint16 idacc_done_1; /* dccal control register 60 */ + uint16 idacc_done_2; /* dccal control register 61 */ + int16 psb; /* psb read during dccal health check */ + int16 txcap; /* Txcap value */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 debug_01; + uint16 debug_02; + uint16 debug_03; + uint16 debug_04; + + uint8 pktproc; /* pktproc read during dccal health check */ + uint8 baseindxval; /* TPC Base index */ + int8 tgt_pwr; /* Programmed Target power */ + int8 estpwradj; /* Current Est Power Adjust value */ + int8 crsmin_pwr; /* CRS Min/Noise power */ + int8 rssi_per_ant; /* RSSI Per antenna */ + int8 snr_per_ant; /* SNR Per antenna */ + + int8 noise_level; /* noise pwr after filtering & averageing */ + int8 noise_level_inst; /* instantaneous noise cal pwr */ + int8 estpwr; /* tx powerDet value */ + int8 crsmin_th_idx; /* idx used to lookup crs min thresholds */ + int8 ed_threshold; /* ed threshold */ + + uint16 bad_txbaseidx_cnt; /* cntr for tx_baseidx=127 in healthcheck */ + uint16 curr_tssival; /* TxPwrCtrlInit_path[01].TSSIVal */ + uint16 pwridx_init; /* TxPwrCtrlInit_path[01].pwrIndex_init_path[01] */ + uint16 auxphystats; + uint16 phystatsgaininfo; + uint16 flexpwrAFE; + uint16 flexpwrdig1; + uint16 flexpwrdig2; + uint16 flexpwrdig3; + uint16 flexpwrdig4; + uint16 flexgaininfo_A; + uint16 debug_05; /* multipurpose debug register */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint8 debug_06; + uint8 debug_07; + uint8 debug_08; + uint8 debug_09; + + int8 phy_noise_pwr_array[PHY_NOISE_PWR_ARRAY_SIZE]; /* noise buffer array */ +} phy_periodic_log_core_v255_t; + +typedef struct phy_periodic_log_core_v2 { + int32 rxs; /* FDIQ Slope coeffecient */ + + uint16 ofdm_txa; /* OFDM Tx IQ Cal a coeff */ + uint16 ofdm_txb; /* OFDM Tx IQ Cal b coeff */ + uint16 ofdm_txd; /* contain di & dq */ + uint16 rxa; /* Rx IQ Cal A coeffecient */ + uint16 rxb; /* Rx IQ Cal B coeffecient */ + uint16 baseidx; /* TPC Base index */ + + uint8 baseindxval; /* TPC Base index */ + + int8 tgt_pwr; /* Programmed Target power */ + int8 estpwradj; /* Current Est Power Adjust value */ + int8 crsmin_pwr; /* CRS Min/Noise power */ + int8 rssi_per_ant; /* RSSI Per antenna */ + int8 snr_per_ant; /* SNR Per antenna */ + int8 pad1; /* Padding byte to align with word */ + int8 pad2; /* Padding byte to align with word */ +} phy_periodic_log_core_v2_t; + +/* Shared BTCX Statistics for BTCX and PHY Logging, storing the accumulated values. */ +#define BTCX_STATS_PHY_LOGGING_VER 1 +typedef struct wlc_btc_shared_stats { + uint32 bt_req_cnt; /* #BT antenna requests since last stats sampl */ + uint32 bt_gnt_cnt; /* #BT antenna grants since last stats sample */ + uint32 bt_gnt_dur; /* usec BT owns antenna since last stats sample */ + uint16 bt_pm_attempt_cnt; /* PM1 attempts */ + uint16 bt_succ_pm_protect_cnt; /* successful PM protection */ + uint16 bt_succ_cts_cnt; /* successful CTS2A protection */ + uint16 bt_wlan_tx_preempt_cnt; /* WLAN TX Preemption */ + uint16 bt_wlan_rx_preempt_cnt; /* WLAN RX Preemption */ + uint16 bt_ap_tx_after_pm_cnt; /* AP TX even after PM protection */ + uint16 bt_crtpri_cnt; /* Ant grant by critical BT task */ + uint16 bt_pri_cnt; /* Ant grant by high BT task */ + uint16 antgrant_lt10ms; /* Ant grant duration cnt 0~10ms */ + uint16 antgrant_lt30ms; /* Ant grant duration cnt 10~30ms */ + uint16 antgrant_lt60ms; /* Ant grant duration cnt 30~60ms */ + uint16 antgrant_ge60ms; /* Ant grant duration cnt 60~ms */ +} wlc_btc_shared_stats_v1_t; + +#define BTCX_STATS_PHY_LOGGING_VER2 2u +typedef struct wlc_btc_shared_stats_v2 { + uint32 bt_req_cnt; /* #BT antenna requests since last stats sampl */ + uint32 bt_gnt_cnt; /* #BT antenna grants since last stats sample */ + uint32 bt_gnt_dur; /* usec BT owns antenna since last stats sample */ + uint16 bt_pm_attempt_cnt; /* PM1 attempts */ + uint16 bt_succ_pm_protect_cnt; /* successful PM protection */ + uint16 bt_succ_cts_cnt; /* successful CTS2A protection */ + uint16 bt_wlan_tx_preempt_cnt; /* WLAN TX Preemption */ + uint16 bt_wlan_rx_preempt_cnt; /* WLAN RX Preemption */ + uint16 bt_ap_tx_after_pm_cnt; /* AP TX even after PM protection */ + uint16 bt_crtpri_cnt; /* Ant grant by critical BT task */ + uint16 bt_pri_cnt; /* Ant grant by high BT task */ + uint16 antgrant_lt10ms; /* Ant grant duration cnt 0~10ms */ + uint16 antgrant_lt30ms; /* Ant grant duration cnt 10~30ms */ + uint16 antgrant_lt60ms; /* Ant grant duration cnt 30~60ms */ + uint16 antgrant_ge60ms; /* Ant grant duration cnt 60~ms */ + uint16 ackpwroffset; /* CoreMask (low8) and ack_pwr_offset (high8) */ + uint8 prisel_ant_mask; /* antenna to be used by BT */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint8 debug_01; + uint16 debug_02; + uint16 debug_03; + uint16 debug_04; + uint16 debug_05; + uint8 debug_06; + uint8 debug_07; + uint8 debug_08; + uint8 debug_09; +} wlc_btc_shared_stats_v2_t; + +#define BTCX_STATS_PHY_LOGGING_VER255 255u +typedef struct wlc_btc_shared_stats_v255 { + uint32 bt_req_cnt; /* #BT antenna requests since last stats sampl */ + uint32 bt_gnt_cnt; /* #BT antenna grants since last stats sample */ + uint32 bt_gnt_dur; /* usec BT owns antenna since last stats sample */ + uint16 bt_pm_attempt_cnt; /* PM1 attempts */ + uint16 bt_succ_pm_protect_cnt; /* successful PM protection */ + uint16 bt_succ_cts_cnt; /* successful CTS2A protection */ + uint16 bt_wlan_tx_preempt_cnt; /* WLAN TX Preemption */ + uint16 bt_wlan_rx_preempt_cnt; /* WLAN RX Preemption */ + uint16 bt_ap_tx_after_pm_cnt; /* AP TX even after PM protection */ + uint16 bt_crtpri_cnt; /* Ant grant by critical BT task */ + uint16 bt_pri_cnt; /* Ant grant by high BT task */ + uint16 antgrant_lt10ms; /* Ant grant duration cnt 0~10ms */ + uint16 antgrant_lt30ms; /* Ant grant duration cnt 10~30ms */ + uint16 antgrant_lt60ms; /* Ant grant duration cnt 30~60ms */ + uint16 antgrant_ge60ms; /* Ant grant duration cnt 60~ms */ + uint16 ackpwroffset; /* CoreMask (low8) and ack_pwr_offset (high8) */ + uint8 prisel_ant_mask; /* antenna to be used by BT */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint8 debug_01; + uint16 debug_02; + uint16 debug_03; + uint16 debug_04; + uint16 debug_05; + uint8 debug_06; + uint8 debug_07; + uint8 debug_08; + uint8 debug_09; +} wlc_btc_shared_stats_v255_t; + +/* BTCX Statistics for PHY Logging */ +typedef struct wlc_btc_stats_phy_logging { + uint16 ver; + uint16 length; + uint32 btc_status; /* btc status log */ + uint32 bt_req_type_map; /* BT Antenna Req types since last stats sample */ + wlc_btc_shared_stats_v1_t shared; +} phy_periodic_btc_stats_v1_t; + +/* BTCX Statistics for PHY Logging */ +typedef struct wlc_btc_stats_phy_logging_v2 { + uint16 ver; + uint16 length; + uint32 btc_status; /* btc status log */ + uint32 bt_req_type_map; /* BT Antenna Req types since last stats sample */ + wlc_btc_shared_stats_v2_t shared; +} phy_periodic_btc_stats_v2_t; + +/* BTCX Statistics for PHY Logging */ +typedef struct wlc_btc_stats_phy_logging_v255 { + uint16 ver; + uint16 length; + uint32 btc_status; /* btc status log */ + uint32 bt_req_type_map; /* BT Antenna Req types since last stats sample */ + wlc_btc_shared_stats_v255_t shared; +} phy_periodic_btc_stats_v255_t; + +/* OBSS Statistics for PHY Logging */ +typedef struct phy_periodic_obss_stats_v1 { + uint32 obss_last_read_time; /* last stats read time */ + uint16 obss_mit_bw; /* selected mitigation BW */ + uint16 obss_stats_cnt; /* stats count */ + uint8 obss_mit_mode; /* mitigation mode */ + uint8 obss_mit_status; /* obss mitigation status */ + uint8 obss_curr_det[ACPHY_OBSS_SUBBAND_CNT]; /* obss curr detection */ + uint16 dynbw_init_reducebw_cnt; /* + * bandwidth reduction cnt of + * initiator (txrts+rxcts) + */ + uint16 dynbw_resp_reducebw_cnt; /* + * bandwidth reduction cnt of + * responder (rxrts+txcts) + */ + uint16 dynbw_rxdata_reducebw_cnt; /* + * rx data cnt with reduced bandwidth + * as txcts requested + */ +} phy_periodic_obss_stats_v1_t; + +/* OBSS Statistics for PHY Logging */ +typedef struct phy_periodic_obss_stats_v2 { + uint32 obss_last_read_time; /* last stats read time */ + uint16 obss_mit_bw; /* selected mitigation BW */ + uint16 obss_stats_cnt; /* stats count */ + uint8 obss_need_updt; /* BW update needed flag */ + uint8 obss_mit_status; /* obss mitigation status */ + uint8 obss_curr_det[ACPHY_OBSS_SUBBAND_CNT]; /* obss curr detection */ + uint16 dynbw_init_reducebw_cnt; /* + * bandwidth reduction cnt of + * initiator (txrts+rxcts) + */ + uint16 dynbw_resp_reducebw_cnt; /* + * bandwidth reduction cnt of + * responder (rxrts+txcts) + */ + uint16 dynbw_rxdata_reducebw_cnt; /* + * rx data cnt with reduced bandwidth + * as txcts requested + */ + uint16 obss_mmt_skip_cnt; /* mmt skipped due to powersave */ + uint16 obss_mmt_no_result_cnt; /* mmt with no result */ + uint16 obss_mmt_intr_err_cnt; /* obss reg mismatch between ucode and fw */ + uint8 obss_final_rec_bw; /* final recommended bw to wlc-Sent to SW */ + uint8 debug01; + uint16 obss_det_stats[ACPHY_OBSS_SUBBAND_CNT]; +} phy_periodic_obss_stats_v2_t; + +typedef struct phy_periodic_obss_stats_v3 { + uint32 obss_last_read_time; /* last stats read time */ + uint16 obss_mit_bw; /* selected mitigation BW */ + uint16 obss_stats_cnt; /* stats count */ + uint8 obss_need_updt; /* BW update needed flag */ + uint8 obss_mit_status; /* obss mitigation status */ + uint8 obss_curr_det[ACPHY_OBSS_SUBBAND_CNT]; /* obss curr detection */ + uint16 dynbw_init_reducebw_cnt; /* + * bandwidth reduction cnt of + * initiator (txrts+rxcts) + */ + uint16 dynbw_resp_reducebw_cnt; /* + * bandwidth reduction cnt of + * responder (rxrts+txcts) + */ + uint16 dynbw_rxdata_reducebw_cnt; /* + * rx data cnt with reduced bandwidth + * as txcts requested + */ + uint16 obss_mmt_skip_cnt; /* mmt skipped due to powersave */ + uint16 obss_mmt_no_result_cnt; /* mmt with no result */ + uint16 obss_mmt_intr_err_cnt; /* obss reg mismatch between ucode and fw */ + uint8 obss_last_rec_bw; /* last recommended bw to wlc-Sent to SW */ + uint8 debug_01; + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint16 debug_02; + uint16 debug_03; + uint16 debug_04; + uint16 debug_05; +} phy_periodic_obss_stats_v3_t; + +typedef struct phy_periodic_obss_stats_v255 { + uint32 obss_last_read_time; /* last stats read time */ + uint16 obss_mit_bw; /* selected mitigation BW */ + uint16 obss_stats_cnt; /* stats count */ + uint8 obss_need_updt; /* BW update needed flag */ + uint8 obss_mit_status; /* obss mitigation status */ + uint8 obss_curr_det[ACPHY_OBSS_SUBBAND_CNT]; /* obss curr detection */ + uint16 dynbw_init_reducebw_cnt; /* + * bandwidth reduction cnt of + * initiator (txrts+rxcts) + */ + uint16 dynbw_resp_reducebw_cnt; /* + * bandwidth reduction cnt of + * responder (rxrts+txcts) + */ + uint16 dynbw_rxdata_reducebw_cnt; /* + * rx data cnt with reduced bandwidth + * as txcts requested + */ + uint16 obss_mmt_skip_cnt; /* mmt skipped due to powersave */ + uint16 obss_mmt_no_result_cnt; /* mmt with no result */ + uint16 obss_mmt_intr_err_cnt; /* obss reg mismatch between ucode and fw */ + uint8 obss_last_rec_bw; /* last recommended bw to wlc-Sent to SW */ + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint8 debug_01; + uint16 debug_02; + uint16 debug_03; + uint16 debug_04; + uint16 debug_05; +} phy_periodic_obss_stats_v255_t; + +/* SmartCCA related PHY Logging */ +typedef struct phy_periodic_scca_stats_v1 { + uint32 asym_intf_cmplx_pwr[2]; + uint32 asym_intf_ncal_time; + uint32 asym_intf_host_req_mit_turnon_time; + uint32 core1_smask_val_bk; /* bt fem control related */ + int32 asym_intf_ed_thresh; + + int16 crsminpoweru0; /* crsmin thresh */ + int16 crsminpoweroffset0; /* ac_offset core0 */ + int16 crsminpoweroffset1; /* ac_offset core1 */ + int16 Core0InitGainCodeB; /* rx mitigation: eLNA bypass setting */ + int16 Core1InitGainCodeB; /* rx mitigation: eLNA bypass setting */ + int16 ed_crsEn; /* phyreg(ed_crsEn) */ + int16 nvcfg0; /* LLR deweighting coefficient */ + int16 SlnaRxMaskCtrl0; + int16 SlnaRxMaskCtrl1; + uint16 save_SlnaRxMaskCtrl0; + uint16 save_SlnaRxMaskCtrl1; + uint16 asym_intf_ncal_req_chspec; /* channel request noisecal */ + /* asym_intf_stats includes the following bits: + * b[0]: bool asym_intf_rx_noise_mit_on; + * b[1]: bool asym_intf_tx_smartcca_on; + * b[3:2]: bool asym_intf_elna_bypass[2]; + * b[4]: bool asym_intf_valid_noise_samp; + * b[5]: bool asym_intf_fill_noise_buf; + * b[6]: bool asym_intf_ncal_discard; + * b[7]: bool slna_reg_saved; + * b[8]: bool asym_intf_host_ext_usb; //Host control related variable + * b[9]: bool asym_intf_host_ext_usb_chg; // Host control related variable + * b[10]: bool asym_intf_host_en; // Host control related variable + * b[11]: bool asym_intf_host_enable; + * b[12]: bool asym_intf_pending_host_req; // Set request pending if clk not present + */ + uint16 asym_intf_stats; + + uint8 elna_bypass; /* from bt_desense.elna_bypass in gainovr_shm_config() */ + uint8 btc_mode; /* from bt_desense in gainovr_shm_config() */ + /* noise at antenna from phy_ac_noise_ant_noise_calc() */ + int8 noise_dbm_ant[2]; + /* in phy_ac_noise_calc(), also used by wl noise */ + int8 noisecalc_cmplx_pwr_dbm[2]; + uint8 gain_applied; /* from phy_ac_rxgcrs_set_init_clip_gain() */ + + int8 asym_intf_tx_smartcca_cm; + int8 asym_intf_rx_noise_mit_cm; + int8 asym_intf_avg_noise[2]; + int8 asym_intf_latest_noise[2]; + /* used to calculate noise_delta for rx mitigation on/off */ + int8 asym_intf_prev_noise_lvl[2]; + uint8 asym_intf_noise_calc_gain_2g[2]; + uint8 asym_intf_noise_calc_gain_5g[2]; + uint8 asym_intf_ant_noise_idx; + uint8 asym_intf_least_core_idx; + uint8 phy_crs_thresh_save[2]; + uint8 asym_intf_initg_desense[2]; + uint8 asym_intf_pending_host_req_type; /* Set request pending if clk not present */ +} phy_periodic_scca_stats_v1_t; + +/* SmartCCA related PHY Logging */ +typedef struct phy_periodic_scca_stats_v2 { + uint32 asym_intf_cmplx_pwr[2]; + uint32 asym_intf_ncal_time; + uint32 asym_intf_host_req_mit_turnon_time; + uint32 core1_smask_val_bk; /* bt fem control related */ + int32 asym_intf_ed_thresh; + + int16 crsminpoweru0; /* crsmin thresh */ + int16 crsminpoweroffset0; /* ac_offset core0 */ + int16 crsminpoweroffset1; /* ac_offset core1 */ + int16 Core0InitGainCodeB; /* rx mitigation: eLNA bypass setting */ + int16 Core1InitGainCodeB; /* rx mitigation: eLNA bypass setting */ + int16 ed_crsEn; /* phyreg(ed_crsEn) */ + int16 nvcfg0; /* LLR deweighting coefficient */ + int16 SlnaRxMaskCtrl0; + int16 SlnaRxMaskCtrl1; + uint16 save_SlnaRxMaskCtrl0; + uint16 save_SlnaRxMaskCtrl1; + uint16 asym_intf_ncal_req_chspec; /* channel request noisecal */ + /* asym_intf_stats includes the following bits: + * b[0]: bool asym_intf_rx_noise_mit_on; + * b[1]: bool asym_intf_tx_smartcca_on; + * b[3:2]: bool asym_intf_elna_bypass[2]; + * b[4]: bool asym_intf_valid_noise_samp; + * b[5]: bool asym_intf_fill_noise_buf; + * b[6]: bool asym_intf_ncal_discard; + * b[7]: bool slna_reg_saved; + * b[8]: bool asym_intf_host_ext_usb; //Host control related variable + * b[9]: bool asym_intf_host_ext_usb_chg; // Host control related variable + * b[10]: bool asym_intf_host_en; // Host control related variable + * b[11]: bool asym_intf_host_enable; + * b[12]: bool asym_intf_pending_host_req; // Set request pending if clk not present + */ + uint16 asym_intf_stats; + + uint8 elna_bypass; /* from bt_desense.elna_bypass in gainovr_shm_config() */ + uint8 btc_mode; /* from bt_desense in gainovr_shm_config() */ + /* noise at antenna from phy_ac_noise_ant_noise_calc() */ + int8 noise_dbm_ant[2]; + /* in phy_ac_noise_calc(), also used by wl noise */ + int8 noisecalc_cmplx_pwr_dbm[2]; + uint8 gain_applied; /* from phy_ac_rxgcrs_set_init_clip_gain() */ + + int8 asym_intf_tx_smartcca_cm; + int8 asym_intf_rx_noise_mit_cm; + int8 asym_intf_avg_noise[2]; + int8 asym_intf_latest_noise[2]; + /* used to calculate noise_delta for rx mitigation on/off */ + int8 asym_intf_prev_noise_lvl[2]; + uint8 asym_intf_noise_calc_gain_2g[2]; + uint8 asym_intf_noise_calc_gain_5g[2]; + uint8 asym_intf_ant_noise_idx; + uint8 asym_intf_least_core_idx; + uint8 phy_crs_thresh_save[2]; + uint8 asym_intf_initg_desense[2]; + uint8 asym_intf_pending_host_req_type; /* Set request pending if clk not present */ + uint16 asym_intf_ncal_crs_stat[12]; + uint8 asym_intf_ncal_crs_stat_idx; +} phy_periodic_scca_stats_v2_t; + +/* SmartCCA related PHY Logging - v3 NEWT SmartCCA based */ +typedef struct phy_periodic_scca_stats_v3 { + uint32 asym_intf_ncal_time; + uint32 asym_intf_host_req_mit_turnon_time; + int32 asym_intf_ed_thresh; + + int16 crsminpoweru0; /* crsmin thresh */ + int16 crsminpoweroffset0; /* ac_offset core0 */ + int16 crsminpoweroffset1; /* ac_offset core1 */ + int16 ed_crsEn; /* phyreg(ed_crsEn) */ + int16 nvcfg0; /* LLR deweighting coefficient */ + int16 SlnaRxMaskCtrl0; + int16 SlnaRxMaskCtrl1; + int16 CRSMiscellaneousParam; + int16 AntDivConfig2059; + int16 HPFBWovrdigictrl; + uint16 save_SlnaRxMaskCtrl0; + uint16 save_SlnaRxMaskCtrl1; + uint16 asym_intf_ncal_req_chspec; /* channel request noisecal */ + /* asym_intf_stats includes the following bits: + * b[0]: bool asym_intf_rx_noise_mit_on; // SmartCCA Rx mititagion enabled + * b[1]: bool asym_intf_tx_smartcca_on; // SmartCCA Tx mititagion enabled + * b[2]: bool asym_intf_valid_noise_samp; // Latest noise sample is valid + * b[3]: bool asym_intf_fill_noise_buf; // Fill the same sample to entire buffer + * b[4]: bool asym_intf_ncal_discard; // Discard current noise sample + * b[5]: bool slna_reg_saved; // SLNA register values are saved + * b[6]: bool asym_intf_host_ext_usb; // Host control related variable + * b[7]: bool asym_intf_host_ext_usb_chg; // Host control related variable + * b[8]: bool asym_intf_host_en; // Host control related variable + * b[9]: bool asym_intf_host_enable; // Host control related variable + * b[10]: bool asym_intf_pending_host_req; // Set request pending if clk not present + */ + uint16 asym_intf_stats; + + uint8 btc_mode; /* from bt_desense in gainovr_shm_config() */ + + /* noise at antenna from phy_ac_noise_calc() */ + int8 noisecalc_cmplx_pwr_dbm[2]; + int8 asym_intf_ant_noise[2]; + + int8 asym_intf_tx_smartcca_cm; + int8 asym_intf_rx_noise_mit_cm; + int8 asym_intf_avg_noise[2]; + int8 asym_intf_latest_noise[2]; + /* used to calculate noise_delta for rx mitigation on/off */ + int8 asym_intf_prev_noise_lvl[2]; + uint8 asym_intf_ant_noise_idx; + uint8 asym_intf_least_core_idx; + uint8 asym_intf_pending_host_req_type; + /* Set request pending if clk not present */ + uint16 asym_intf_ncal_crs_stat; + uint8 asym_intf_ncal_crs_stat_idx; + uint8 pad; +} phy_periodic_scca_stats_v3_t; + +/* SmartCCA related PHY Logging */ +typedef struct phy_periodic_scca_stats_v255 { + uint32 asym_intf_ncal_time; + uint32 asym_intf_host_req_mit_turnon_time; + int32 asym_intf_ed_thresh; + + int16 crsminpoweru0; /* crsmin thresh */ + int16 crsminpoweroffset0; /* ac_offset core0 */ + int16 crsminpoweroffset1; /* ac_offset core1 */ + int16 ed_crsEn; /* phyreg(ed_crsEn) */ + int16 nvcfg0; /* LLR deweighting coefficient */ + int16 SlnaRxMaskCtrl0; + int16 SlnaRxMaskCtrl1; + int16 CRSMiscellaneousParam; + int16 AntDivConfig2059; + int16 HPFBWovrdigictrl; + uint16 save_SlnaRxMaskCtrl0; + uint16 save_SlnaRxMaskCtrl1; + uint16 asym_intf_ncal_req_chspec; /* channel request noisecal */ + /* asym_intf_stats includes the following bits: + * b[0]: bool asym_intf_rx_noise_mit_on; // SmartCCA Rx mititagion enabled + * b[1]: bool asym_intf_tx_smartcca_on; // SmartCCA Tx mititagion enabled + * b[2]: bool asym_intf_valid_noise_samp; // Latest noise sample is valid + * b[3]: bool asym_intf_fill_noise_buf; // Fill the same sample to entire buffer + * b[4]: bool asym_intf_ncal_discard; // Discard current noise sample + * b[5]: bool slna_reg_saved; // SLNA register values are saved + * b[6]: bool asym_intf_host_ext_usb; // Host control related variable + * b[7]: bool asym_intf_host_ext_usb_chg; // Host control related variable + * b[8]: bool asym_intf_host_en; // Host control related variable + * b[9]: bool asym_intf_host_enable; // Host control related variable + * b[10]: bool asym_intf_pending_host_req; // Set request pending if clk not present + */ + uint16 asym_intf_stats; + + uint8 btc_mode; /* from bt_desense in gainovr_shm_config() */ + + /* noise at antenna from phy_ac_noise_calc() */ + int8 noisecalc_cmplx_pwr_dbm[2]; + int8 asym_intf_ant_noise[2]; + + int8 asym_intf_tx_smartcca_cm; + int8 asym_intf_rx_noise_mit_cm; + int8 asym_intf_avg_noise[2]; + int8 asym_intf_latest_noise[2]; + /* used to calculate noise_delta for rx mitigation on/off */ + int8 asym_intf_prev_noise_lvl[2]; + uint8 asym_intf_ant_noise_idx; + uint8 asym_intf_least_core_idx; + uint8 asym_intf_pending_host_req_type; + /* Set request pending if clk not present */ + uint16 asym_intf_ncal_crs_stat; + uint8 asym_intf_ncal_crs_stat_idx; + uint8 pad; +} phy_periodic_scca_stats_v255_t; + +#define PHY_PERIODIC_LOG_VER1 (1u) + +typedef struct phy_periodic_log_v1 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the entire structure */ + phy_periodic_log_cmn_t phy_perilog_cmn; + phy_periodic_counters_v1_t counters_peri_log; + /* This will be a variable length based on the numcores field defined above */ + phy_periodic_log_core_t phy_perilog_core[BCM_FLEX_ARRAY]; +} phy_periodic_log_v1_t; + +#define PHYCAL_LOG_VER3 (3u) +#define PHY_PERIODIC_LOG_VER3 (3u) + +/* 4387 onwards */ +typedef struct phy_periodic_log_v3 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v2_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v3_t counters_peri_log; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_t phy_perilog_core[BCM_FLEX_ARRAY]; +} phy_periodic_log_v3_t; + +#define PHY_PERIODIC_LOG_VER5 (5u) + +typedef struct phy_periodic_log_v5 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v4_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v3_t counters_peri_log; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_v3_t phy_perilog_core[BCM_FLEX_ARRAY]; +} phy_periodic_log_v5_t; + +#define PHY_PERIODIC_LOG_VER6 (6u) + +typedef struct phy_periodic_log_v6 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v5_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v6_t counters_peri_log; + + /* log data for BTcoex */ + phy_periodic_btc_stats_v1_t phy_perilog_btc_stats; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_v4_t phy_perilog_core[BCM_FLEX_ARRAY]; +} phy_periodic_log_v6_t; + +typedef struct phycal_log_v3 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the entire structure */ + phycal_log_cmn_v2_t phycal_log_cmn; /* Logging common structure */ + /* This will be a variable length based on the numcores field defined above */ + phycal_log_core_v3_t phycal_log_core[BCM_FLEX_ARRAY]; +} phycal_log_v3_t; + +#define PHY_CAL_EVENTLOG_VER4 (4u) +typedef struct phycal_log_v4 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the entire structure */ + phy_phycal_v2_t phy_calibration; +} phycal_log_v4_t; + +/* Trunk ONLY */ +#define PHY_CAL_EVENTLOG_VER255 (255u) +typedef struct phycal_log_v255 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the entire structure */ + phy_phycal_v255_t phy_calibration; +} phycal_log_v255_t; + +/* Note: The version 2 is reserved for 4357 only. Future chips must not use this version. */ + +#define MAX_CORE_4357 (2u) +#define PHYCAL_LOG_VER2 (2u) +#define PHY_PERIODIC_LOG_VER2 (2u) + +typedef struct { + uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 rxrsptmout; /**< number of response timeouts for transmitted frames + * expecting a response + */ + uint32 rxstrt; /**< number of received frames with a good PLCP */ + uint32 rxbadplcp; /**< number of parity check of the PLCP header failed */ + uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ + uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ + uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ + uint32 rxbeaconmbss; /**< beacons received from member of BSS */ + uint32 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */ + uint32 rxf0ovfl; /** < Rx FIFO0 overflow counters information */ + uint32 rxf1ovfl; /** < Rx FIFO1 overflow counters information */ + uint32 rxdtocast; /**< number of received DATA frames (good FCS and no matching RA) */ + uint32 rxtoolate; /**< receive too late */ + uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ +} phy_periodic_counters_v2_t; + +/* Note: The version 2 is reserved for 4357 only. All future chips must not use this version. */ + +typedef struct phycal_log_core_v2 { + uint16 ofdm_txa; /* OFDM Tx IQ Cal a coeff */ + uint16 ofdm_txb; /* OFDM Tx IQ Cal b coeff */ + uint16 ofdm_txd; /* contain di & dq */ + uint16 rxa; /* Rx IQ Cal A coeffecient */ + uint16 rxb; /* Rx IQ Cal B coeffecient */ + uint8 baseidx; /* TPC Base index */ + uint8 pad; + int32 rxs; /* FDIQ Slope coeffecient */ +} phycal_log_core_v2_t; + +/* Note: The version 2 is reserved for 4357 only. All future chips must not use this version. */ + +typedef struct phycal_log_v2 { + uint8 version; /* Logging structure version */ + uint16 length; /* Length of the entire structure */ + uint8 pad; + phycal_log_cmn_t phycal_log_cmn; /* Logging common structure */ + phycal_log_core_v2_t phycal_log_core[MAX_CORE_4357]; +} phycal_log_v2_t; + +/* Note: The version 2 is reserved for 4357 only. All future chips must not use this version. */ + +typedef struct phy_periodic_log_v2 { + uint8 version; /* Logging structure version */ + uint16 length; /* Length of the entire structure */ + uint8 pad; + phy_periodic_log_cmn_t phy_perilog_cmn; + phy_periodic_counters_v2_t counters_peri_log; + phy_periodic_log_core_t phy_perilog_core[MAX_CORE_4357]; +} phy_periodic_log_v2_t; + +#define PHY_PERIODIC_LOG_VER4 (4u) + +/* + * Note: The version 4 is reserved for 4357 Deafness Debug only. + * All future chips must not use this version. + */ +typedef struct phy_periodic_log_v4 { + uint8 version; /* Logging structure version */ + uint8 pad; + uint16 length; /* Length of the entire structure */ + phy_periodic_log_cmn_v3_t phy_perilog_cmn; + phy_periodic_counters_v4_t counters_peri_log; + phy_periodic_log_core_v2_t phy_perilog_core[MAX_CORE_4357]; +} phy_periodic_log_v4_t; + +#define PHY_PERIODIC_LOG_VER7 (7u) +typedef struct phy_periodic_log_v7 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the entire structure */ + phy_periodic_log_cmn_t phy_perilog_cmn; + phy_periodic_counters_v5_t counters_peri_log; + phy_periodic_btc_stats_v1_t btc_stats_peri_log; + /* This will be a variable length based on the numcores field defined above */ + phy_periodic_log_core_t phy_perilog_core[BCM_FLEX_ARRAY]; +} phy_periodic_log_v7_t; + +#define PHY_PERIODIC_LOG_VER8 (8u) +typedef struct phy_periodic_log_v8 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the entire structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v6_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v7_t counters_peri_log; + + /* log data for BTcoex */ + phy_periodic_btc_stats_v1_t btc_stats_peri_log; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_v5_t phy_perilog_core[BCM_FLEX_ARRAY]; +} phy_periodic_log_v8_t; + +#define PHY_PERIODIC_LOG_VER9 (9u) +typedef struct phy_periodic_log_v9 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v7_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v8_t counters_peri_log; + + /* log data for BTcoex */ + phy_periodic_btc_stats_v1_t phy_perilog_btc_stats; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_v4_t phy_perilog_core[BCM_FLEX_ARRAY]; +} phy_periodic_log_v9_t; + +#define PHY_PERIODIC_LOG_VER10 10u +typedef struct phy_periodic_log_v10 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the entire structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v6_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v7_t counters_peri_log; + + /* log data for BTcoex */ + phy_periodic_btc_stats_v1_t btc_stats_peri_log; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_v5_t phy_perilog_core[2]; + + /* log data for smartCCA */ + phy_periodic_scca_stats_v1_t scca_counters_peri_log; +} phy_periodic_log_v10_t; + +#define PHY_PERIODIC_LOG_VER11 (11u) +typedef struct phy_periodic_log_v11 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v8_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v8_t counters_peri_log; + + /* log data for BTcoex */ + phy_periodic_btc_stats_v1_t phy_perilog_btc_stats; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_v6_t phy_perilog_core[2]; + + /* log data for smartCCA */ + phy_periodic_scca_stats_v3_t scca_counters_peri_log; +} phy_periodic_log_v11_t; + +#define AMT_MATCH_INFRA_BSSID (1 << 0) +#define AMT_MATCH_INFRA_MYMAC (1 << 1) + +#define PHY_PERIODIC_LOG_VER20 20u +typedef struct phy_periodic_log_v20 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v9_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v8_t counters_peri_log; + + /* log data for BTcoex */ + phy_periodic_btc_stats_v1_t phy_perilog_btc_stats; + + /* log data for obss/dynbw */ + phy_periodic_obss_stats_v1_t phy_perilog_obss_stats; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_v6_t phy_perilog_core[2]; + + /* log data for smartCCA */ + phy_periodic_scca_stats_v2_t scca_counters_peri_log; +} phy_periodic_log_v20_t; + +#define PHY_PERIODIC_LOG_VER21 21u +typedef struct phy_periodic_log_v21 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v9_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v8_t counters_peri_log; + + /* log data for BTcoex */ + phy_periodic_btc_stats_v1_t phy_perilog_btc_stats; + + /* log data for obss/dynbw */ + phy_periodic_obss_stats_v1_t phy_perilog_obss_stats; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_v6_t phy_perilog_core[2]; + + /* log data for smartCCA */ + phy_periodic_scca_stats_v2_t scca_counters_peri_log; +} phy_periodic_log_v21_t; + +#define PHY_PERIODIC_LOG_VER22 22u +typedef struct phy_periodic_log_v22 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v10_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v9_t counters_peri_log; + + /* log data for BTcoex */ + phy_periodic_btc_stats_v2_t phy_perilog_btc_stats; + + /* log data for obss/dynbw */ + phy_periodic_obss_stats_v1_t phy_perilog_obss_stats; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_v7_t phy_perilog_core[2]; + + /* log data for smartCCA */ + phy_periodic_scca_stats_v2_t scca_counters_peri_log; +} phy_periodic_log_v22_t; + +#define PHY_PERIODIC_LOG_VER23 23u +typedef struct phy_periodic_log_v23 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v10_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v9_t counters_peri_log; + + /* log data for BTcoex */ + phy_periodic_btc_stats_v2_t phy_perilog_btc_stats; + + /* log data for obss/dynbw */ + phy_periodic_obss_stats_v1_t phy_perilog_obss_stats; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_v7_t phy_perilog_core[2]; + + /* log data for smartCCA */ + phy_periodic_scca_stats_v3_t scca_counters_peri_log; +} phy_periodic_log_v23_t; + +#define PHY_PERIODIC_LOG_VER24 24u +typedef struct phy_periodic_log_v24 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v10_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v9_t counters_peri_log; + + /* log data for BTcoex */ + phy_periodic_btc_stats_v2_t phy_perilog_btc_stats; + + /* log data for obss/dynbw */ + phy_periodic_obss_stats_v2_t phy_perilog_obss_stats; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_v7_t phy_perilog_core[2]; + + /* log data for smartCCA */ + phy_periodic_scca_stats_v3_t scca_counters_peri_log; +} phy_periodic_log_v24_t; + +#define PHY_PERIODIC_LOG_VER25 25u +typedef struct phy_periodic_log_v25 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v11_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v9_t counters_peri_log; + + /* log data for BTcoex */ + phy_periodic_btc_stats_v2_t phy_perilog_btc_stats; + + /* log data for obss/dynbw */ + phy_periodic_obss_stats_v3_t phy_perilog_obss_stats; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_v7_t phy_perilog_core[2]; + + /* log data for smartCCA */ + phy_periodic_scca_stats_v3_t scca_counters_peri_log; +} phy_periodic_log_v25_t; + +/* ************************************************** */ +/* The version 255 for the logging data structures */ +/* is for use in trunk ONLY. In release branches the */ +/* next available version for the particular data */ +/* structure should be used. */ +/* ************************************************** */ + +#define PHY_PERIODIC_LOG_VER255 255u +typedef struct phy_periodic_log_v255 { + uint8 version; /* Logging structure version */ + uint8 numcores; /* Number of cores for which core specific data present */ + uint16 length; /* Length of the structure */ + + /* Logs general PHY parameters */ + phy_periodic_log_cmn_v255_t phy_perilog_cmn; + + /* Logs ucode counters and NAVs */ + phy_periodic_counters_v255_t counters_peri_log; + + /* log data for BTcoex */ + phy_periodic_btc_stats_v255_t phy_perilog_btc_stats; + + /* log data for obss/dynbw */ + phy_periodic_obss_stats_v255_t phy_perilog_obss_stats; + + /* Logs data pertaining to each core */ + phy_periodic_log_core_v255_t phy_perilog_core[2]; + + /* log data for smartCCA */ + phy_periodic_scca_stats_v255_t scca_counters_peri_log; +} phy_periodic_log_v255_t; +#endif /* _PHY_EVENT_LOG_PAYLOAD_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h old mode 100755 new mode 100644 index 94f3c70dcbcd..558f940283c9 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h @@ -5,7 +5,7 @@ * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, * GPIO interface, extbus, and support for serial and parallel flashes. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -2825,6 +2825,8 @@ typedef volatile struct { #define PMU4369_PLL6VAL_PRE_SCALE (1 << 17) #define PMU4369_PLL6VAL_POST_SCALE (1 << 3) +#define PMU_PLL_CTRL_REG6 6 + /* PLL usage in 4378 * Temporay setting, update is needed. */ @@ -2934,6 +2936,42 @@ typedef volatile struct { /* 4360 Chip specific Regulator Control register bits */ #define RCTRL4360_RFLDO_PWR_DOWN (1 << 1) +/* +* 4383 PMU Resources +*/ +#define RES4383_DUMMY 0 +#define RES4383_FAST_LPO_AVAIL 1 +#define RES4383_PMU_LP 2 +#define RES4383_MISC_LDO 3 +#define RES4383_SERDES_AFE_RET 4 +#define RES4383_XTAL_HQ 5 +#define RES4383_XTAL_PU 6 +#define RES4383_XTAL_STABLE 7 +#define RES4383_PWRSW_DIG 8 +#define RES4383_CORE_RDY_BTMAIN 9 +#define RES4383_CORE_RDY_BTSC 10 +#define RES4383_PWRSW_AUX 11 +#define RES4383_PWRSW_SCAN 12 +#define RES4383_CORE_RDY_SCAN 13 +#define RES4383_PWRSW_MAIN 14 +#define RES4383_USBLDO_PU 15 +#define RES4383_USBPHY_RDY 16 +#define RES4383_CORE_RDY_DIG 17 +#define RES4383_CORE_RDY_AUX 18 +#define RES4383_ALP_AVAIL 19 +#define RES4383_RADIO_PU_AUX 20 +#define RES4383_RADIO_PU_SCAN 21 +#define RES4383_CORE_RDY_MAIN 22 +#define RES4383_RADIO_PU_MAIN 23 +#define RES4383_MACPHY_CLK_SCAN 24 +#define RES4383_CORE_RDY_CB 25 +#define RES4383_PWRSW_CB 26 +#define RES4383_ARMCLK_AVAIL 27 +#define RES4383_HT_AVAIL 28 +#define RES4383_MACPHY_CLK_AUX 29 +#define RES4383_MACPHY_CLK_MAIN 30 +#define RES4383_RESERVED_31 31 + /* 4360 PMU resources and chip status bits */ #define RES4360_REGULATOR 0 #define RES4360_ILP_AVAIL 1 @@ -3050,6 +3088,7 @@ typedef volatile struct { #define CC4387_FNSEL_FUART (3u) #define CC4387_FNSEL_DBG_UART (6u) #define CC4387_FNSEL_SPI (7u) +#define CC4387_FNSEL_SFLASH (8u) /* Indices of PMU voltage regulator registers */ #define PMU_VREG_0 (0u) @@ -3461,7 +3500,7 @@ typedef volatile struct { #define CST4378_CHIPMODE_BTOP(cs) (((cs) & (1 << 6)) == 0) #define CST4378_SPROM_PRESENT 0x00000010 -#define CST4387_SFLASH_PRESENT 0x00000010U +#define CST_SFLASH_PRESENT 0x00000010U #define CST4387_CHIPMODE_BTOU(cs) (((cs) & (1 << 6)) != 0) #define CST4387_CHIPMODE_BTOP(cs) (((cs) & (1 << 6)) == 0) @@ -3699,6 +3738,46 @@ typedef volatile struct { #define SR_ASM_ADDR_DIG_4397 (0x18520000) +/* Txfifo is 512KB for main core and 128KB for aux core + * We use first 12kB (0x3000) in BMC buffer for template in main core and + * 6.5kB (0x1A00) in aux core, followed by ASM code + */ +#define SR_ASM_ADDR_MAIN_4383A0 BM_ADDR_TO_SR_ADDR(0xC00) +#define SR_ASM_ADDR_AUX_4383A0 BM_ADDR_TO_SR_ADDR(0xC00) + +/* + * LAst 32K of (B)TCM Memory is used for DIG SR ASM + * => 0X900000 - 0X8000 (2176KB from 0x6E0000) + */ +#define SR_ASM_ADDR_DIG_4383A0 (0x8F8000) + +/* srcontrol2 reg has to be programmed with asm download address + * It is 14 bit address but with RAM address range in 0x8yyyyy + * additionally bit 15 also gets set when address is derived as + * addr >> 9 in sr_asm_addr. This by default enables sr self test + * feature which is not yet ready for 4383. Hence masking it + */ +#define SR_ASM_ADDR_DIG_4381A0_SRCTRL2 (0x0b8000) +#define SR_ASM_ADDR_DIG_4382A0_SRCTRL2 (0x0f8000) +#define SR_ASM_ADDR_DIG_4383A0_SRCTRL2 (0x0b8000) + +/* TODO: Update the right value after confirmation with RTL, Ucode. +*/ +/* SR Control0 bits for 4383 */ +#define SR0_4383_SR_ENG_EN_MASK 0x1 +#define SR0_4383_SR_ENG_EN_SHIFT 0 +#define SR0_4383_SR_ENG_CLK_EN (1 << 1) +#define SR0_4383_RSRC_TRIGGER (0xC << 2) +#define SR0_4383_WD_MEM_MIN_DIV (0x2 << 6) +#define SR0_4383_WD_MEM_MIN_DIV_AUX (0x4 << 6) +#define SR0_4383_INVERT_SR_CLK (1 << 11) +#define SR0_4383_MEM_STBY_ALLOW (1 << 16) +#define SR0_4383_ENABLE_SR_ILP (1 << 17) +#define SR0_4383_ENABLE_SR_ALP (1 << 18) +#define SR0_4383_ENABLE_SR_HT (1 << 19) +#define SR0_4383_ALLOW_PIC (3 << 20) +#define SR0_4383_ENB_PMU_MEM_DISABLE (1 << 30) + /* SR Control0 bits */ #define SR0_SR_ENG_EN_MASK 0x1 #define SR0_SR_ENG_EN_SHIFT 0 @@ -4120,6 +4199,11 @@ typedef volatile struct { #define PMU_4362_MACCORE_0_RES_REQ_MASK (0x3FCBF7FFu) #define PMU_4362_MACCORE_1_RES_REQ_MASK (0x7FFB3647u) +/* 4381 related */ +#define CST4381_CHIPMODE_PCIE(cs) (((cs) & (1 << 7)) != 0) /* PCIE */ +#define CST4381_CHIPMODE_SDIO(cs) (((cs) & (1 << 31)) != 0) /* SDIO */ +#define CST4381_CHIPMODE_USB(cs) (((cs) & (1 << 20)) != 0) /* USB */ + #define PMU_MACCORE_0_RES_REQ_TIMER 0x1d000000 #define PMU_MACCORE_0_RES_REQ_MASK 0x5FF2364F @@ -4154,8 +4238,12 @@ typedef volatile struct { #define CR4_4377_RAM_BASE (0x170000) #define CR4_43751_RAM_BASE (0x170000) #define CR4_43752_RAM_BASE (0x170000) +#define CR4_43756_RAM_BASE (0x170000) +#define CR4_43711_RAM_BASE (0x170000) #define CR4_4376_RAM_BASE (0x352000) #define CR4_4378_RAM_BASE (0x352000) +#define CR4_4381_RAM_BASE (0x740000) +#define CR4_4382_RAM_BASE (0x700000) #define CR4_4387_RAM_BASE (0x740000) #define CR4_4385_RAM_BASE (0x740000) #define CA7_4388_RAM_BASE (0x200000) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbconfig.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbconfig.h old mode 100755 new mode 100644 index 283eb0e9e9f2..424a3621cce3 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbconfig.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbconfig.h @@ -1,7 +1,7 @@ /* * Broadcom SiliconBackplane hardware register definitions. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbgci.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbgci.h old mode 100755 new mode 100644 index 0b265b611a69..55afc79d30bb --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbgci.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbgci.h @@ -1,7 +1,7 @@ /* * SiliconBackplane GCI core hardware definitions * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhndarm.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhndarm.h old mode 100755 new mode 100644 index bdddbcedd247..92660123db22 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhndarm.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhndarm.h @@ -1,7 +1,7 @@ /* * Broadcom SiliconBackplane ARM definitions * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhnddma.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhnddma.h old mode 100755 new mode 100644 index bf7f3baa4064..86422ebc65c2 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhnddma.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhnddma.h @@ -2,7 +2,7 @@ * Generic Broadcom Home Networking Division (HND) DMA engine HW interface * This supports the following chips: BCM42xx, 44xx, 47xx . * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhndpio.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhndpio.h old mode 100755 new mode 100644 index f4038f31e454..289a40b5e7f9 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhndpio.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbhndpio.h @@ -2,7 +2,7 @@ * Generic Broadcom Home Networking Division (HND) PIO engine HW interface * This supports the following chips: BCM42xx, 44xx, 47xx . * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbpcmcia.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbpcmcia.h old mode 100755 new mode 100644 index 77f65f4b2818..297898f2a68f --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbpcmcia.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbpcmcia.h @@ -1,7 +1,7 @@ /* * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsdio.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsdio.h old mode 100755 new mode 100644 index 0a2c2271f791..18ba61233618 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsdio.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsdio.h @@ -4,7 +4,7 @@ * * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsdpcmdev.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsdpcmdev.h old mode 100755 new mode 100644 index ced0afff9e7c..91e04882acd8 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsdpcmdev.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsdpcmdev.h @@ -2,7 +2,7 @@ * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific * device core support * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsocram.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsocram.h old mode 100755 new mode 100644 index f8d6b0d90d69..a8802bf60427 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsocram.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsocram.h @@ -1,7 +1,7 @@ /* * BCM47XX Sonics SiliconBackplane embedded ram core * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsprom.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsprom.h deleted file mode 100755 index f43da2d4d71d..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsprom.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - * SPROM format definitions for the Broadcom 47xx and 43xx chip family. - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ - -#ifndef _SBSPROM_H -#define _SBSPROM_H - -#include "typedefs.h" -#include "bcmdevs.h" - -/* A word is this many bytes */ -#define SRW 2 - -/* offset into PCI config space for write enable bit */ -#define CFG_SROM_WRITABLE_OFFSET 0x88 -#define SROM_WRITEABLE 0x10 - -/* enumeration space consists of N contiguous 4Kbyte core register sets */ -#define SBCORES_BASE 0x18000000 -#define SBCORES_EACH 0x1000 - -/* offset from BAR0 for srom space */ -#define SROM_BASE 4096 - -/* number of 2-byte words in srom */ -#define SROM_SIZE 64 - -#define SROM_BYTES (SROM_SIZE * SRW) - -#define MAX_FN 4 - -/* Word 0, Hardware control */ -#define SROM_HWCTL 0 -#define HW_FUNMSK 0x000f -#define HW_FCLK 0x0200 -#define HW_CBM 0x0400 -#define HW_PIMSK 0xf000 -#define HW_PISHIFT 12 -#define HW_PI4402 0x2 -#define HW_FUN4401 0x0001 -#define HW_FCLK4402 0x0000 - -/* Word 1, common-power/boot-rom */ -#define SROM_COMMPW 1 -/* boot rom present bit */ -#define BR_PRESSHIFT 8 -/* 15:9 for n; boot rom size is 2^(14 + n) bytes */ -#define BR_SIZESHIFT 9 - -/* Word 2, SubsystemId */ -#define SROM_SSID 2 - -/* Word 3, VendorId */ -#define SROM_VID 3 - -/* Function 0 info, function info length */ -#define SROM_FN0 4 -#define SROM_FNSZ 8 - -/* Within each function: */ -/* Word 0, deviceID */ -#define SRFN_DID 0 - -/* Words 1-2, ClassCode */ -#define SRFN_CCL 1 -/* Word 2, D0 Power */ -#define SRFN_CCHD0 2 - -/* Word 3, PME and D1D2D3 power */ -#define SRFN_PMED123 3 - -#define PME_IL 0 -#define PME_ENET0 1 -#define PME_ENET1 2 -#define PME_CODEC 3 - -#define PME_4402_ENET 0 -#define PME_4402_CODEC 1 -#define PMEREP_4402_ENET (PMERD3CV | PMERD3CA | PMERD3H | PMERD2 | PMERD1 | PMERD0 | PME) - -/* Word 4, Bar1 enable, pme reports */ -#define SRFN_B1PMER 4 -#define B1E 1 -#define B1SZMSK 0xe -#define B1SZSH 1 -#define PMERMSK 0x0ff0 -#define PME 0x0010 -#define PMERD0 0x0020 -#define PMERD1 0x0040 -#define PMERD2 0x0080 -#define PMERD3H 0x0100 -#define PMERD3CA 0x0200 -#define PMERD3CV 0x0400 -#define IGNCLKRR 0x0800 -#define B0LMSK 0xf000 - -/* Words 4-5, Bar0 Sonics value */ -#define SRFN_B0H 5 -/* Words 6-7, CIS Pointer */ -#define SRFN_CISL 6 -#define SRFN_CISH 7 - -/* Words 36-38: iLine MAC address */ -#define SROM_I_MACHI 36 -#define SROM_I_MACMID 37 -#define SROM_I_MACLO 38 - -/* Words 36-38: wireless0 MAC address on 43xx */ -#define SROM_W0_MACHI 36 -#define SROM_W0_MACMID 37 -#define SROM_W0_MACLO 38 - -/* Words 39-41: enet0 MAC address */ -#define SROM_E0_MACHI 39 -#define SROM_E0_MACMID 40 -#define SROM_E0_MACLO 41 - -/* Words 42-44: enet1 MAC address */ -#define SROM_E1_MACHI 42 -#define SROM_E1_MACMID 43 -#define SROM_E1_MACLO 44 - -#define SROM_EPHY 45 - -/* Words 47-51 wl0 PA bx */ -#define SROM_WL0_PAB0 47 -#define SROM_WL0_PAB1 48 -#define SROM_WL0_PAB2 49 -#define SROM_WL0_PAB3 50 -#define SROM_WL0_PAB4 51 - -/* Word 52: wl0/wl1 MaxPower */ -#define SROM_WL_MAXPWR 52 - -/* Words 53-55 wl1 PA bx */ -#define SROM_WL1_PAB0 53 -#define SROM_WL1_PAB1 54 -#define SROM_WL1_PAB2 55 - -/* Woprd 56: itt */ -#define SROM_ITT 56 - -/* Words 59-62: OEM Space */ -#define SROM_WL_OEM 59 -#define SROM_OEM_SIZE 4 - -/* Contents for the srom */ - -#define BU4710_SSID 0x0400 -#define VSIM4710_SSID 0x0401 -#define QT4710_SSID 0x0402 - -#define BU4610_SSID 0x0403 -#define VSIM4610_SSID 0x0404 - -#define BU4402_SSID 0x4402 - -#define CLASS_OTHER 0x8000 -#define CLASS_ETHER 0x0000 -#define CLASS_NET 0x0002 -#define CLASS_COMM 0x0007 -#define CLASS_MODEM 0x0300 -#define CLASS_MIPS 0x3000 -#define CLASS_PROC 0x000b -#define CLASS_FLASH 0x0100 -#define CLASS_MEM 0x0005 -#define CLASS_SERIALBUS 0x000c -#define CLASS_OHCI 0x0310 - -/* Broadcom IEEE MAC addresses are 00:90:4c:xx:xx:xx */ -#define MACHI 0x90 - -#define MACMID_BU4710I 0x4c17 -#define MACMID_BU4710E0 0x4c18 -#define MACMID_BU4710E1 0x4c19 - -#define MACMID_94710R1I 0x4c1a -#define MACMID_94710R1E0 0x4c1b -#define MACMID_94710R1E1 0x4c1c - -#define MACMID_94710R4I 0x4c1d -#define MACMID_94710R4E0 0x4c1e -#define MACMID_94710R4E1 0x4c1f - -#define MACMID_94710DEVI 0x4c20 -#define MACMID_94710DEVE0 0x4c21 -#define MACMID_94710DEVE1 0x4c22 - -#define MACMID_BU4402 0x4c23 - -#define MACMID_BU4610I 0x4c24 -#define MACMID_BU4610E0 0x4c25 -#define MACMID_BU4610E1 0x4c26 - -#define MACMID_BU4401 0x4c37 - -/* Enet phy settings one or two singles or a dual */ -/* Bits 4-0 : MII address for enet0 (0x1f for not there */ -/* Bits 9-5 : MII address for enet1 (0x1f for not there */ -/* Bit 14 : Mdio for enet0 */ -/* Bit 15 : Mdio for enet1 */ - -/* bu4710 with only one phy on enet1 with address 7: */ -#define SROM_EPHY_ONE 0x80ff - -/* bu4710 with two individual phys, at 6 and 7, */ -/* each mdio connected to its own mac: */ -#define SROM_EPHY_TWO 0x80e6 - -/* bu4710 with a dual phy addresses 0 & 1, mdio-connected to enet0 */ -/* bringup board has phyaddr0 and phyaddr1 swapped */ -#define SROM_EPHY_DUAL 0x0001 - -/* r1 board with a dual phy at 0, 1 (NOT swapped and mdc0 */ -#define SROM_EPHY_R1 0x0010 - -/* r4 board with a single phy on enet0 at address 5 and a switch */ -/* chip on enet1 (speciall case: 0x1e */ -#define SROM_EPHY_R4 0x83e5 - -/* 4402 uses an internal phy at phyaddr 1; want mdcport == coreunit == 0 */ -#define SROM_EPHY_INTERNAL 0x0001 - -#define SROM_VERS 0x0001 - -#endif /* _SBSPROM_H */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsysmem.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsysmem.h old mode 100755 new mode 100644 index 5c86c0c20356..dc7f8a783e12 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsysmem.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbsysmem.h @@ -1,7 +1,7 @@ /* * SiliconBackplane System Memory core * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdio.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdio.h old mode 100755 new mode 100644 index b0343f06e972..70721f1bced3 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdio.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdio.h @@ -2,7 +2,7 @@ * SDIO spec header file * Protocol and standard (common) device definitions * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -112,7 +112,7 @@ typedef volatile struct { /* io_en */ #define SDIO_FUNC_ENABLE_1 0x02 /* function 1 I/O enable */ #define SDIO_FUNC_ENABLE_2 0x04 /* function 2 I/O enable */ -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) #define SDIO_FUNC_ENABLE_3 0x08 /* function 2 I/O enable */ #define SDIO_FUNC_DISABLE_3 0xF0 /* function 2 I/O enable */ #endif /* defined (BT_OVER_SDIO) */ @@ -125,7 +125,7 @@ typedef volatile struct { #define INTR_CTL_MASTER_EN 0x1 /* interrupt enable master */ #define INTR_CTL_FUNC1_EN 0x2 /* interrupt enable for function 1 */ #define INTR_CTL_FUNC2_EN 0x4 /* interrupt enable for function 2 */ -#if defined (BT_OVER_SDIO) +#if defined(BT_OVER_SDIO) #define INTR_CTL_FUNC3_EN 0x8 /* interrupt enable for function 3 */ #endif /* defined (BT_OVER_SDIO) */ /* intr_status */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdioh.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdioh.h old mode 100755 new mode 100644 index 805f0611d5f0..20200c131fdc --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdioh.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdioh.h @@ -2,7 +2,7 @@ * SDIO Host Controller Spec header file * Register map and definitions for the Standard Host Controller * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdiovar.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdiovar.h old mode 100755 new mode 100644 index 33c8825987cb..cd10d991eac3 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdiovar.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdiovar.h @@ -2,7 +2,7 @@ * Structure used by apps whose drivers access SDIO drivers. * Pulled out separately so dhdu and wlu can both use it. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdspi.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdspi.h deleted file mode 100755 index b030c69e6207..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sdspi.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SD-SPI Protocol Standard - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ -#ifndef _SD_SPI_H -#define _SD_SPI_H - -#define SPI_START_M BITFIELD_MASK(1) /* Bit [31] - Start Bit */ -#define SPI_START_S 31 -#define SPI_DIR_M BITFIELD_MASK(1) /* Bit [30] - Direction */ -#define SPI_DIR_S 30 -#define SPI_CMD_INDEX_M BITFIELD_MASK(6) /* Bits [29:24] - Command number */ -#define SPI_CMD_INDEX_S 24 -#define SPI_RW_M BITFIELD_MASK(1) /* Bit [23] - Read=0, Write=1 */ -#define SPI_RW_S 23 -#define SPI_FUNC_M BITFIELD_MASK(3) /* Bits [22:20] - Function Number */ -#define SPI_FUNC_S 20 -#define SPI_RAW_M BITFIELD_MASK(1) /* Bit [19] - Read After Wr */ -#define SPI_RAW_S 19 -#define SPI_STUFF_M BITFIELD_MASK(1) /* Bit [18] - Stuff bit */ -#define SPI_STUFF_S 18 -#define SPI_BLKMODE_M BITFIELD_MASK(1) /* Bit [19] - Blockmode 1=blk */ -#define SPI_BLKMODE_S 19 -#define SPI_OPCODE_M BITFIELD_MASK(1) /* Bit [18] - OP Code */ -#define SPI_OPCODE_S 18 -#define SPI_ADDR_M BITFIELD_MASK(17) /* Bits [17:1] - Address */ -#define SPI_ADDR_S 1 -#define SPI_STUFF0_M BITFIELD_MASK(1) /* Bit [0] - Stuff bit */ -#define SPI_STUFF0_S 0 - -#define SPI_RSP_START_M BITFIELD_MASK(1) /* Bit [7] - Start Bit (always 0) */ -#define SPI_RSP_START_S 7 -#define SPI_RSP_PARAM_ERR_M BITFIELD_MASK(1) /* Bit [6] - Parameter Error */ -#define SPI_RSP_PARAM_ERR_S 6 -#define SPI_RSP_RFU5_M BITFIELD_MASK(1) /* Bit [5] - RFU (Always 0) */ -#define SPI_RSP_RFU5_S 5 -#define SPI_RSP_FUNC_ERR_M BITFIELD_MASK(1) /* Bit [4] - Function number error */ -#define SPI_RSP_FUNC_ERR_S 4 -#define SPI_RSP_CRC_ERR_M BITFIELD_MASK(1) /* Bit [3] - COM CRC Error */ -#define SPI_RSP_CRC_ERR_S 3 -#define SPI_RSP_ILL_CMD_M BITFIELD_MASK(1) /* Bit [2] - Illegal Command error */ -#define SPI_RSP_ILL_CMD_S 2 -#define SPI_RSP_RFU1_M BITFIELD_MASK(1) /* Bit [1] - RFU (Always 0) */ -#define SPI_RSP_RFU1_S 1 -#define SPI_RSP_IDLE_M BITFIELD_MASK(1) /* Bit [0] - In idle state */ -#define SPI_RSP_IDLE_S 0 - -/* SD-SPI Protocol Definitions */ -#define SDSPI_COMMAND_LEN 6 /* Number of bytes in an SD command */ -#define SDSPI_START_BLOCK 0xFE /* SD Start Block Token */ -#define SDSPI_IDLE_PAD 0xFF /* SD-SPI idle value for MOSI */ -#define SDSPI_START_BIT_MASK 0x80 - -#endif /* _SD_SPI_H */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/siutils.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/siutils.h old mode 100755 new mode 100644 index 0078bbd230c0..52b326612dea --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/siutils.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/siutils.h @@ -2,7 +2,7 @@ * Misc utility routines for accessing the SOC Interconnects * of Broadcom HNBU chips. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -349,14 +349,6 @@ extern void *si_osh(si_t *sih); extern void si_setosh(si_t *sih, osl_t *osh); extern int si_backplane_access(si_t *sih, uint addr, uint size, uint *val, bool read); -/* precommit failed when this is removed */ -/* BLAZAR_BRANCH_101_10_DHD_002/build/dhd/linux-fc30/brix-brcm */ -/* TBD: Revisit later */ -#ifdef BCMINTERNAL -extern int si_backplane_access_64(si_t *sih, uint addr, uint size, - uint64 *val, bool read); -#endif /* BCMINTERNAL */ - extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); extern uint si_corereg_writeonly(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); extern uint si_pmu_corereg(si_t *sih, uint32 idx, uint regoff, uint mask, uint val); @@ -546,8 +538,8 @@ extern int si_cis_source(const si_t *sih); /* bp_ind_access default timeout */ #define BP_ACCESS_TO (500u * 1000u) -extern uint16 BCMATTACHFN(si_fabid)(si_t *sih); -extern uint16 BCMINITFN(si_chipid)(const si_t *sih); +extern uint16 si_fabid(si_t *sih); +extern uint16 si_chipid(const si_t *sih); /* * Build device path. Path size must be >= SI_DEVPATH_BUFSZ. @@ -697,6 +689,7 @@ extern uint32 si_gci_get_functionsel(si_t *sih, uint32 pin); extern void si_gci_clear_functionsel(si_t *sih, uint8 fnsel); extern uint8 si_gci_get_chipctrlreg_idx(uint32 pin, uint32 *regidx, uint32 *pos); extern uint32 si_gci_chipcontrol(si_t *sih, uint reg, uint32 mask, uint32 val); +extern void sflash_gpio_config(si_t *sih); extern uint32 si_gci_chipstatus(si_t *sih, uint reg); extern uint8 si_enable_device_wake(si_t *sih, uint8 *wake_status, uint8 *cur_status); extern uint8 si_get_device_wake_opt(si_t *sih); @@ -967,7 +960,9 @@ bool si_srpwr_cap(si_t *sih); * ARM, TCM, Main, Aux * Host needs to power up */ -#define MULTIBP_CAP(sih) (BCM4378_CHIP(sih->chip) || \ +#define MULTIBP_CAP(sih) (BCM4378_CHIP(sih->chip) || BCM4381_CHIP(sih->chip) || \ + BCM4383_CHIP(sih->chip) || \ + BCM43852_CHIP(sih->chip) || BCM4382_CHIP(sih->chip) || \ BCM4387_CHIP(sih->chip) || BCM4388_CHIP(sih->chip) || \ BCM4389_CHIP(sih->chip) || BCM4385_CHIP(sih->chip) || \ BCM4376_CHIP(sih->chip) || BCM4397_CHIP(sih->chip)) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/spid.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/spid.h deleted file mode 100755 index 0fbbb233cedd..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/spid.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * SPI device spec header file - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -#ifndef _SPI_H -#define _SPI_H - -/* - * Brcm SPI Device Register Map. - * - */ - -typedef volatile struct { - uint8 config; /* 0x00, len, endian, clock, speed, polarity, wakeup */ - uint8 response_delay; /* 0x01, read response delay in bytes (corerev < 3) */ - uint8 status_enable; /* 0x02, status-enable, intr with status, response_delay - * function selection, command/data error check - */ - uint8 reset_bp; /* 0x03, reset on wlan/bt backplane reset (corerev >= 1) */ - uint16 intr_reg; /* 0x04, Intr status register */ - uint16 intr_en_reg; /* 0x06, Intr mask register */ - uint32 status_reg; /* 0x08, RO, Status bits of last spi transfer */ - uint16 f1_info_reg; /* 0x0c, RO, enabled, ready for data transfer, blocksize */ - uint16 f2_info_reg; /* 0x0e, RO, enabled, ready for data transfer, blocksize */ - uint16 f3_info_reg; /* 0x10, RO, enabled, ready for data transfer, blocksize */ - uint32 test_read; /* 0x14, RO 0xfeedbead signature */ - uint32 test_rw; /* 0x18, RW */ - uint8 resp_delay_f0; /* 0x1c, read resp delay bytes for F0 (corerev >= 3) */ - uint8 resp_delay_f1; /* 0x1d, read resp delay bytes for F1 (corerev >= 3) */ - uint8 resp_delay_f2; /* 0x1e, read resp delay bytes for F2 (corerev >= 3) */ - uint8 resp_delay_f3; /* 0x1f, read resp delay bytes for F3 (corerev >= 3) */ -} spi_regs_t; - -/* SPI device register offsets */ -#define SPID_CONFIG 0x00 -#define SPID_RESPONSE_DELAY 0x01 -#define SPID_STATUS_ENABLE 0x02 -#define SPID_RESET_BP 0x03 /* (corerev >= 1) */ -#define SPID_INTR_REG 0x04 /* 16 bits - Interrupt status */ -#define SPID_INTR_EN_REG 0x06 /* 16 bits - Interrupt mask */ -#define SPID_STATUS_REG 0x08 /* 32 bits */ -#define SPID_F1_INFO_REG 0x0C /* 16 bits */ -#define SPID_F2_INFO_REG 0x0E /* 16 bits */ -#define SPID_F3_INFO_REG 0x10 /* 16 bits */ -#define SPID_TEST_READ 0x14 /* 32 bits */ -#define SPID_TEST_RW 0x18 /* 32 bits */ -#define SPID_RESP_DELAY_F0 0x1c /* 8 bits (corerev >= 3) */ -#define SPID_RESP_DELAY_F1 0x1d /* 8 bits (corerev >= 3) */ -#define SPID_RESP_DELAY_F2 0x1e /* 8 bits (corerev >= 3) */ -#define SPID_RESP_DELAY_F3 0x1f /* 8 bits (corerev >= 3) */ - -/* Bit masks for SPID_CONFIG device register */ -#define WORD_LENGTH_32 0x1 /* 0/1 16/32 bit word length */ -#define ENDIAN_BIG 0x2 /* 0/1 Little/Big Endian */ -#define CLOCK_PHASE 0x4 /* 0/1 clock phase delay */ -#define CLOCK_POLARITY 0x8 /* 0/1 Idle state clock polarity is low/high */ -#define HIGH_SPEED_MODE 0x10 /* 1/0 High Speed mode / Normal mode */ -#define INTR_POLARITY 0x20 /* 1/0 Interrupt active polarity is high/low */ -#define WAKE_UP 0x80 /* 0/1 Wake-up command from Host to WLAN */ - -/* Bit mask for SPID_RESPONSE_DELAY device register */ -#define RESPONSE_DELAY_MASK 0xFF /* Configurable rd response delay in multiples of 8 bits */ - -/* Bit mask for SPID_STATUS_ENABLE device register */ -#define STATUS_ENABLE 0x1 /* 1/0 Status sent/not sent to host after read/write */ -#define INTR_WITH_STATUS 0x2 /* 0/1 Do-not / do-interrupt if status is sent */ -#define RESP_DELAY_ALL 0x4 /* Applicability of resp delay to F1 or all func's read */ -#define DWORD_PKT_LEN_EN 0x8 /* Packet len denoted in dwords instead of bytes */ -#define CMD_ERR_CHK_EN 0x20 /* Command error check enable */ -#define DATA_ERR_CHK_EN 0x40 /* Data error check enable */ - -/* Bit mask for SPID_RESET_BP device register */ -#define RESET_ON_WLAN_BP_RESET 0x4 /* enable reset for WLAN backplane */ -#define RESET_ON_BT_BP_RESET 0x8 /* enable reset for BT backplane */ -#define RESET_SPI 0x80 /* reset the above enabled logic */ - -/* Bit mask for SPID_INTR_REG device register */ -#define DATA_UNAVAILABLE 0x0001 /* Requested data not available; Clear by writing a "1" */ -#define F2_F3_FIFO_RD_UNDERFLOW 0x0002 -#define F2_F3_FIFO_WR_OVERFLOW 0x0004 -#define COMMAND_ERROR 0x0008 /* Cleared by writing 1 */ -#define DATA_ERROR 0x0010 /* Cleared by writing 1 */ -#define F2_PACKET_AVAILABLE 0x0020 -#define F3_PACKET_AVAILABLE 0x0040 -#define F1_OVERFLOW 0x0080 /* Due to last write. Bkplane has pending write requests */ -#define MISC_INTR0 0x0100 -#define MISC_INTR1 0x0200 -#define MISC_INTR2 0x0400 -#define MISC_INTR3 0x0800 -#define MISC_INTR4 0x1000 -#define F1_INTR 0x2000 -#define F2_INTR 0x4000 -#define F3_INTR 0x8000 - -/* Bit mask for 32bit SPID_STATUS_REG device register */ -#define STATUS_DATA_NOT_AVAILABLE 0x00000001 -#define STATUS_UNDERFLOW 0x00000002 -#define STATUS_OVERFLOW 0x00000004 -#define STATUS_F2_INTR 0x00000008 -#define STATUS_F3_INTR 0x00000010 -#define STATUS_F2_RX_READY 0x00000020 -#define STATUS_F3_RX_READY 0x00000040 -#define STATUS_HOST_CMD_DATA_ERR 0x00000080 -#define STATUS_F2_PKT_AVAILABLE 0x00000100 -#define STATUS_F2_PKT_LEN_MASK 0x000FFE00 -#define STATUS_F2_PKT_LEN_SHIFT 9 -#define STATUS_F3_PKT_AVAILABLE 0x00100000 -#define STATUS_F3_PKT_LEN_MASK 0xFFE00000 -#define STATUS_F3_PKT_LEN_SHIFT 21 - -/* Bit mask for 16 bits SPID_F1_INFO_REG device register */ -#define F1_ENABLED 0x0001 -#define F1_RDY_FOR_DATA_TRANSFER 0x0002 -#define F1_MAX_PKT_SIZE 0x01FC - -/* Bit mask for 16 bits SPID_F2_INFO_REG device register */ -#define F2_ENABLED 0x0001 -#define F2_RDY_FOR_DATA_TRANSFER 0x0002 -#define F2_MAX_PKT_SIZE 0x3FFC - -/* Bit mask for 16 bits SPID_F3_INFO_REG device register */ -#define F3_ENABLED 0x0001 -#define F3_RDY_FOR_DATA_TRANSFER 0x0002 -#define F3_MAX_PKT_SIZE 0x3FFC - -/* Bit mask for 32 bits SPID_TEST_READ device register read in 16bit LE mode */ -#define TEST_RO_DATA_32BIT_LE 0xFEEDBEAD - -/* Maximum number of I/O funcs */ -#define SPI_MAX_IOFUNCS 4 - -#define SPI_MAX_PKT_LEN (2048*4) - -/* Misc defines */ -#define SPI_FUNC_0 0 -#define SPI_FUNC_1 1 -#define SPI_FUNC_2 2 -#define SPI_FUNC_3 3 - -/* with gspi mode, we observed that it almost takes 110ms to come up */ -/* check the register 20ms, for 100 times. 2 seconds would be enough */ -#define WAIT_F2RXFIFORDY 100 -#define WAIT_F2RXFIFORDY_DELAY 20 - -#endif /* _SPI_H */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/trxhdr.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/trxhdr.h old mode 100755 new mode 100644 index 5af956c819b9..e87ce64e10d7 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/trxhdr.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/trxhdr.h @@ -1,7 +1,7 @@ /* * TRX image file header format. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2023, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/typedefs.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/typedefs.h old mode 100755 new mode 100644 index 6a251302736e..df09e00be80d --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/typedefs.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/typedefs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -23,7 +23,7 @@ #define _TYPEDEFS_H_ #if (!defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)) || \ - !defined(BWL_NO_INTERNAL_STDLIB_SUPPORT) + !defined(BWL_NO_INTERNAL_STDLIB_SUPPORT) #ifdef SITE_TYPEDEFS @@ -88,7 +88,7 @@ typedef unsigned long long int uintptr; #endif #endif /* TYPEDEF_UINTPTR */ -#if defined(_RTE_) +#if defined(_RTE_) || defined(COEX_CPU_BUILD) #define _NEED_SIZE_T_ #endif @@ -96,9 +96,9 @@ typedef unsigned long long int uintptr; ** math.h header file. Don't re-typedef them here. */ -#if defined(MACOSX) +#if defined(MACOSX) || defined(__linux__) #define TYPEDEF_FLOAT_T -#endif /* MACOSX */ +#endif /* MACOSX || Linux */ #if defined(_NEED_SIZE_T_) typedef long unsigned int size_t; @@ -143,15 +143,14 @@ typedef unsigned __int64 uint64; #endif /* __KERNEL__ */ #endif /* linux && !EFI */ -#if !defined(__linux__) && !defined(_WIN32) && \ - !defined(_RTE_) && !defined(__DJGPP__) && \ - !defined(__BOB__) && !defined(EFI) +#if !defined(__linux__) && !defined(_WIN32) && !defined(_RTE_) && !defined(__DJGPP__) \ + && !defined(__BOB__) && !defined(EFI) && !defined(COEX_CPU_BUILD) #define TYPEDEF_UINT #define TYPEDEF_USHORT #endif /* Do not support the (u)int64 types with strict ansi for GNU C */ -#if defined(__GNUC__) && defined(__STRICT_ANSI__) +#if defined(__GNUC__) && defined(__STRICT_ANSI__) && (__STDC_VERSION__ < 199901L) #define TYPEDEF_INT64 #define TYPEDEF_UINT64 #endif /* defined(__GNUC__) && defined(__STRICT_ANSI__) */ @@ -163,13 +162,13 @@ typedef unsigned __int64 uint64; #define TYPEDEF_INT64 -#if defined(__STDC__) +#if defined(__STDC__) && (__STDC_VERSION__ < 199901L) #define TYPEDEF_UINT64 #endif #endif /* __ICL */ -#if !defined(_WIN32) && !defined(_RTE_) && \ +#if !defined(_WIN32) && !defined(_RTE_) && !defined(COEX_CPU_BUILD) && \ !defined(__DJGPP__) && !defined(__BOB__) && !defined(EFI) /* pick up ushort & uint from standard types.h */ @@ -202,9 +201,12 @@ typedef unsigned __int64 uint64; #ifdef USE_TYPEDEF_DEFAULTS #undef USE_TYPEDEF_DEFAULTS +#ifndef BCMWIFI_DISSECTOR_BUILD +/* BWD build throws errors for two or more data types in declaration */ #ifndef TYPEDEF_BOOL typedef /* @abstract@ */ unsigned char bool; #endif /* endif TYPEDEF_BOOL */ +#endif /* !BCMWIFI_DISSECTOR_BUILD */ /* define uchar, ushort, uint, ulong */ @@ -341,6 +343,13 @@ typedef float64 float_t; #endif /* _MSC_VER */ #endif /* INLINE */ +/* Force inlining. */ +#if defined(BWL_COMPILER_GNU) +#define INLINE_ALWAYS inline __attribute__ ((always_inline)) +#else +#define INLINE_ALWAYS INLINE +#endif + #undef TYPEDEF_BOOL #undef TYPEDEF_UCHAR #undef TYPEDEF_USHORT @@ -394,12 +403,19 @@ typedef UINTN uintptr; #define UNUSED_PARAMETER(x) (void)(x) #define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) #define INLINE +#define INLINE_ALWAYS INLINE #define AUTO (-1) /* Auto = -1 */ #define ON 1 /* ON = 1 */ #define OFF 0 #endif /* !EDK_RELEASE_VERSION || (EDK_RELEASE_VERSION < 0x00020000) */ +#ifndef SIZE_CONST_STRING +/* use two level Macro mapping to make some CONSTANT value into number string */ +#define _SIZE_CONST_STRING(x) #x +#define SIZE_CONST_STRING(x) _SIZE_CONST_STRING(x) +#endif /* SIZE_CONST_STRING */ + /* * Including the bcmdefs.h here, to make sure everyone including typedefs.h * gets this automatically diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h old mode 100755 new mode 100644 index f15fbd697cea..91bdd07ab3af --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h @@ -1,15 +1,14 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /* * Broadcom USB remote download definitions * - * Copyright (C) 1999-2016, Broadcom Corporation - * + * Copyright (C) 2022, Broadcom. + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -17,15 +16,9 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. * * - * <> - * - * $Id: usbrdl.h 597933 2015-11-06 18:52:06Z $ + * <> */ #ifndef _USB_RDL_H @@ -59,8 +52,52 @@ #define DL_WRHW 0x14 /* Write a hardware address (Ctl-out) */ #define DL_WRHW_BLK 0x13 /* Block write to hardware access */ -#define DL_CMD_WRHW 2 +#define DL_CMD_WRHW 2 /* write data to a backplane address */ +#define DL_CMD_RDHW 1 /* read data from a backplane address */ + +#define DL_JTCONF 0x15 /* Get JTAG configuration (Ctl_in) + * Set JTAG configuration (Ctl-out) + */ +#define DL_JTON 0x16 /* Turn on jtag master (Ctl-in) */ +#define DL_JTOFF 0x17 /* Turn on jtag master (Ctl-in) */ +#define DL_RDRJT 0x18 /* Read a JTAG register (Ctl-in) */ +#define DL_WRJT 0x19 /* Write a hardware address over JTAG (Ctl/Bulk-out) */ +#define DL_WRRJT 0x1a /* Write a JTAG register (Ctl/Bulk-out) */ +#define DL_JTRST 0x1b /* Reset jtag fsm on jtag DUT (Ctl-in) */ + +#define DL_RDJT 0x1c /* Read a hardware address over JTAG (Ctl-in) */ +#define DL_RDJT32 0x1c /* Read 32 bits */ +#define DL_RDJT16 0x1e /* Read 16 bits (sz = 4 - low bits) */ +#define DL_RDJT8 0x1f /* Read 8 bits */ + +#define DL_MRDJT 0x20 /* Multiple read over JTAG (Ctl-out+Bulk-in) */ +#define DL_MRDJT32 0x20 /* M-read 32 bits */ +#define DL_MRDJT16 0x22 /* M-read 16 bits (sz = 4 - low bits) */ +#define DL_MRDJT6 0x23 /* M-read 8 bits */ +#define DL_MRDIJT 0x24 /* M-read over JTAG (Ctl-out+Bulk-in) with auto-increment */ +#define DL_MRDIJT32 0x24 /* M-read 32 bits w/ai */ +#define DL_MRDIJT16 0x26 /* M-read 16 bits w/ai (sz = 4 - low bits) */ +#define DL_MRDIJT8 0x27 /* M-read 8 bits w/ai */ +#define DL_MRDDJT 0x28 /* M-read over JTAG (Ctl-out+Bulk-in) with auto-decrement */ +#define DL_MRDDJT32 0x28 /* M-read 32 bits w/ad */ +#define DL_MRDDJT16 0x2a /* M-read 16 bits w/ad (sz = 4 - low bits) */ +#define DL_MRDDJT8 0x2b /* M-read 8 bits w/ad */ +#define DL_MWRJT 0x2c /* Multiple write over JTAG (Bulk-out) */ +#define DL_MWRIJT 0x2d /* With auto-increment */ +#define DL_MWRDJT 0x2e /* With auto-decrement */ +#define DL_VRDJT 0x2f /* Vector read over JTAG (Bulk-out+Bulk-in) */ +#define DL_VWRJT 0x30 /* Vector write over JTAG (Bulk-out+Bulk-in) */ +#define DL_SCJT 0x31 /* Jtag scan (Bulk-out+Bulk-in) */ + +#define DL_CFRD 0x33 /* Reserved for dmamem use */ +#define DL_CFWR 0x34 /* Reserved for dmamem use */ +#define DL_GET_NVRAM 0x35 /* Query nvram parameter */ +#define DL_ENABLE_U1U2 0x36 /* Enable U1 and U2 */ + +#define DL_DBGTRIG 0xFF /* Trigger bRequest type to aid debug */ + +#define DL_JTERROR 0x80000000 /* states */ #define DL_WAITING 0 /* waiting to rx first pkt that includes the hdr info */ @@ -102,6 +139,51 @@ typedef struct { uint32 data; /* data to write */ } hwacc_t; +/* struct for backplane */ +typedef struct { + uint32 cmd; /* tag to identify the cmd */ + uint32 addr; /* backplane address for write */ + uint32 len; /* length of data: 1, 2, 4 bytes */ + uint8 data[BCM_FLEX_ARRAY]; /* data to write */ +} hwacc_blk_t; + +typedef struct { + uint32 chip; /* Chip id */ + uint32 chiprev; /* Chip rev */ + uint32 ccrev; /* Chipcommon core rev */ + uint32 siclock; /* Backplane clock */ +} jtagd_id_t; + +/* Jtag configuration structure */ +typedef struct { + uint32 cmd; /* tag to identify the cmd */ + uint8 clkd; /* Jtag clock divisor */ + uint8 disgpio; /* Gpio to disable external driver */ + uint8 irsz; /* IR size for readreg/writereg */ + uint8 drsz; /* DR size for readreg/writereg */ + + uint8 bigend; /* Big endian */ + uint8 mode; /* Current mode */ + uint16 delay; /* Delay between jtagm "simple commands" */ + + uint32 retries; /* Number of retries for jtagm operations */ + uint32 ctrl; /* Jtag control reg copy */ + uint32 ir_lvbase; /* Bits to add to IR values in LV tap */ + uint32 dretries; /* Number of retries for dma operations */ +} jtagconf_t; + +/* struct for jtag scan */ +#define MAX_USB_IR_BITS 256 +#define MAX_USB_DR_BITS 3072 +#define USB_IR_WORDS (MAX_USB_IR_BITS / 32) +#define USB_DR_WORDS (MAX_USB_DR_BITS / 32) +typedef struct { + uint32 cmd; /* tag to identify the cmd */ + uint32 irsz; /* IR size in bits */ + uint32 drsz; /* DR size in bits */ + uint32 ts; /* Terminal state (def, pause, rti) */ + uint32 data[USB_IR_WORDS + USB_DR_WORDS]; /* IR & DR data */ +} scjt_t; /* struct for querying nvram params from bootloader */ #define QUERY_STRING_MAX 32 @@ -126,6 +208,10 @@ typedef void (*exec_fn_t)(void *sih); #define TRX_OFFSETS_JUMPTO_IDX 1 /* RAM address for jumpto after download */ #define TRX_OFFSETS_NVM_LEN_IDX 2 /* Length of appended NVRAM data */ #ifdef BCMTRXV2 +/* The NVRAM region part of trx will be digitally signed in SDR image, + * so is the need for new cfg region which could pass parameters + * which dones not need to be digitally signed + */ #define TRX_OFFSETS_DSG_LEN_IDX 3 /* Length of digital signature for the first image */ #define TRX_OFFSETS_CFG_LEN_IDX 4 /* Length of config region, which is not digitally signed */ #endif /* BCMTRXV2 */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/vlan.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/vlan.h old mode 100755 new mode 100644 index bbf5e508099b..e22e1900e411 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/vlan.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/vlan.h @@ -1,7 +1,7 @@ /* * 802.1Q VLAN protocol definitions * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wl_bam.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wl_bam.h old mode 100755 new mode 100644 index 2c7d59c98e1f..c816b6ade818 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wl_bam.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wl_bam.h @@ -1,7 +1,7 @@ /* * Bad AP Manager for ADPS * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -37,20 +37,11 @@ typedef struct wl_bad_ap_mngr { uint32 num; spinlock_t lock; -#if !defined(DHD_ADPS_BAM_EXPORT) - struct mutex fs_lock; /* lock for bad ap file list */ -#endif /* !DHD_ADPS_BAM_EXPORT */ struct list_head list; } wl_bad_ap_mngr_t; typedef struct wl_bad_ap_info { struct ether_addr bssid; -#if !defined(DHD_ADPS_BAM_EXPORT) - struct tm tm; - uint32 status; - uint32 reason; - uint32 connect_count; -#endif /* !DHD_ADPS_BAM_EXPORT */ } wl_bad_ap_info_t; typedef struct wl_bad_ap_info_entry { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wl_bigdata.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wl_bigdata.h deleted file mode 100755 index bdd40196c942..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wl_bigdata.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Bigdata logging and report. None EWP and Hang event. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ -#ifndef __WL_BIGDATA_H_ -#define __WL_BIGDATA_H_ - -#include <802.11.h> -#include -#include - -#define MAX_STA_INFO_AP_CNT 20 - -#define DOT11_11B_MAX_RATE 11 -#define DOT11_2GHZ_MAX_CH_NUM 14 -#define DOT11_HT_MCS_RATE_MASK 0xFF - -enum { - BIGDATA_DOT11_11B_MODE = 0, - BIGDATA_DOT11_11G_MODE = 1, - BIGDATA_DOT11_11N_MODE = 2, - BIGDATA_DOT11_11A_MODE = 3, - BIGDATA_DOT11_11AC_MODE = 4, - BIGDATA_DOT11_11AX_MODE = 5, - BIGDATA_DOT11_MODE_MAX -}; - -typedef struct wl_ap_sta_data -{ - struct ether_addr mac; - uint32 mode_80211; - uint32 nss; - chanspec_t chanspec; - int16 rssi; - uint32 rate; - uint8 channel; - uint32 mimo; - uint32 disconnected; - uint32 is_empty; - uint32 reason_code; -} wl_ap_sta_data_t; - -typedef struct ap_sta_wq_data -{ - wl_event_msg_t e; - void *dhdp; - void *bcm_cfg; - void *ndev; -} ap_sta_wq_data_t; - -typedef struct wl_ap_sta_info -{ - wl_ap_sta_data_t *ap_sta_data; - uint32 sta_list_cnt; - struct mutex wq_data_sync; -} wl_ap_sta_info_t; - -int wl_attach_ap_stainfo(void *bcm_cfg); -int wl_detach_ap_stainfo(void *bcm_cfg); -int wl_ap_stainfo_init(void *bcm_cfg); -void wl_gather_ap_stadata(void *handle, void *event_info, u8 event); -int wl_get_ap_stadata(void *bcm_cfg, struct ether_addr *sta_mac, void **data); -#endif /* __WL_BIGDATA_H_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wldev_common.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wldev_common.h old mode 100755 new mode 100644 index 529704eec982..bfd998c84191 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wldev_common.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wldev_common.h @@ -1,7 +1,7 @@ /* * Common function shared by Linux WEXT, cfg80211 and p2p drivers * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -86,6 +86,14 @@ s32 wldev_iovar_getint_bsscfg( s32 wldev_iovar_setint_bsscfg( struct net_device *dev, s8 *iovar, s32 val, s32 bssidx); +#if defined(BCMDONGLEHOST) && defined(WL_CFG80211) +extern s32 wldev_iovar_no_wl(struct net_device *dev, s8 *iovar, s8 *param_buf, + u32 param_len, s8 *res_buf, u32 res_len, bool set); +extern s32 wldev_ioctl_no_wl(struct net_device *dev, u32 cmd, s8 *buf, u32 len, bool set); +extern s32 wldev_iovar_setint_no_wl(struct net_device *dev, s8 *iovar, s32 val); +extern s32 wldev_iovar_getint_no_wl(struct net_device *dev, s8 *iovar, s32 *val); +#endif /* BCMDONGLEHOST && WL_CFG80211 */ + extern int dhd_net_set_fw_path(struct net_device *dev, char *fw); extern int dhd_net_bus_suspend(struct net_device *dev); extern int dhd_net_bus_resume(struct net_device *dev, uint8 stage); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlfc_proto.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlfc_proto.h old mode 100755 new mode 100644 index d8d10093d1d0..bf5d3972cae1 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlfc_proto.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlfc_proto.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -122,6 +122,15 @@ typedef enum { WLFC_CTL_TYPE_HP2P_EXT_TXSTATUS = 32, /* Hp2p extended tx status */ WLFC_CTL_TYPE_HP2P_ACTIVE_STATE = 33, /* Get status of HP2P ring active or not */ WLFC_CTL_TYPE_HP2P_QUERY_LIFETIME = 34, /* Query lifetime for last unacked */ + + WLFC_CTL_TYPE_FLOWID_MAC = 35, /* Get flow's MAC (used by WLMESH) */ + + WLFC_CTL_TYPE_LLW_OPEN = 36, /* Open LLW interface */ + WLFC_CTL_TYPE_LLW_CLOSE = 37, /* Close LLW interface */ + + WLFC_CTL_TYPE_D2HQ_STATUS = 38, + WLFC_CTL_TYPE_LLW_LATENCY = 39, /* LLW latency TLV */ + WLFC_CTL_TYPE_FILLER = 255 } wlfc_ctl_type_t; @@ -144,6 +153,9 @@ typedef enum { #define WLFC_CTL_EXT_TXSTATUS_PAYLOAD_LEN 8u /* Payload legnth of extention tx status */ +#define WLFC_CTL_VALUE_LEN_LLW 8u /** tid, ifindex, MAC */ +#define WLFC_CTL_VALUE_LEN_LLW_LATENCY 16u /* Peer latency information */ + /* Reset the flags set for the corresponding flowring of the SCB which is de-inited */ /* FLOW_RING_FLAG_LAST_TIM | FLOW_RING_FLAG_INFORM_PKTPEND | FLOW_RING_FLAG_PKT_REQ */ #define WLFC_RESET_ALL_FLAGS 0 @@ -186,8 +198,8 @@ typedef enum { #define WLFC_PKTFLAG_PKT_FLUSHED_MASK 0x08 #endif /* WLFC_PKTFLAG_COMPAT */ -#define WL_TXSTATUS_STATUS_MASK 0xff /* allow 8 bits */ -#define WL_TXSTATUS_STATUS_SHIFT 24 +#define WL_TXSTATUS_STATUS_MASK 0xffu /* allow 8 bits */ +#define WL_TXSTATUS_STATUS_SHIFT 24u #define WL_TXSTATUS_SET_STATUS(x, status) ((x) = \ ((x) & ~(WL_TXSTATUS_STATUS_MASK << WL_TXSTATUS_STATUS_SHIFT)) | \ @@ -201,8 +213,8 @@ typedef enum { * firmware accepts a packet when the generation matches; on reset (startup) both "current" and * "expected" are set to 0. */ -#define WL_TXSTATUS_GENERATION_MASK 1 /* allow 1 bit */ -#define WL_TXSTATUS_GENERATION_SHIFT 31 +#define WL_TXSTATUS_GENERATION_MASK 1u /* allow 1 bit */ +#define WL_TXSTATUS_GENERATION_SHIFT 31u #define WL_TXSTATUS_SET_GENERATION(x, gen) ((x) = \ ((x) & ~(WL_TXSTATUS_GENERATION_MASK << WL_TXSTATUS_GENERATION_SHIFT)) | \ @@ -211,8 +223,8 @@ typedef enum { #define WL_TXSTATUS_GET_GENERATION(x) (((x) >> WL_TXSTATUS_GENERATION_SHIFT) & \ WL_TXSTATUS_GENERATION_MASK) -#define WL_TXSTATUS_FLAGS_MASK 0xf /* allow 4 bits only */ -#define WL_TXSTATUS_FLAGS_SHIFT 27 +#define WL_TXSTATUS_FLAGS_MASK 0xfu /* allow 4 bits only */ +#define WL_TXSTATUS_FLAGS_SHIFT 27u #define WL_TXSTATUS_SET_FLAGS(x, flags) ((x) = \ ((x) & ~(WL_TXSTATUS_FLAGS_MASK << WL_TXSTATUS_FLAGS_SHIFT)) | \ @@ -222,21 +234,21 @@ typedef enum { #define WL_TXSTATUS_CLEAR_FLAGS(x, flags) ((x) = \ ((x) & ~(((flags) & WL_TXSTATUS_FLAGS_MASK) << WL_TXSTATUS_FLAGS_SHIFT))) -#define WL_TXSTATUS_FIFO_MASK 0x7 /* allow 3 bits for FIFO ID */ -#define WL_TXSTATUS_FIFO_SHIFT 24 +#define WL_TXSTATUS_FIFO_MASK 0x7u /* allow 3 bits for FIFO ID */ +#define WL_TXSTATUS_FIFO_SHIFT 24u #define WL_TXSTATUS_SET_FIFO(x, flags) ((x) = \ ((x) & ~(WL_TXSTATUS_FIFO_MASK << WL_TXSTATUS_FIFO_SHIFT)) | \ (((flags) & WL_TXSTATUS_FIFO_MASK) << WL_TXSTATUS_FIFO_SHIFT)) #define WL_TXSTATUS_GET_FIFO(x) (((x) >> WL_TXSTATUS_FIFO_SHIFT) & WL_TXSTATUS_FIFO_MASK) -#define WL_TXSTATUS_PKTID_MASK 0xffffff /* allow 24 bits */ +#define WL_TXSTATUS_PKTID_MASK 0xffffffu /* allow 24 bits */ #define WL_TXSTATUS_SET_PKTID(x, num) ((x) = \ ((x) & ~WL_TXSTATUS_PKTID_MASK) | (num)) #define WL_TXSTATUS_GET_PKTID(x) ((x) & WL_TXSTATUS_PKTID_MASK) -#define WL_TXSTATUS_HSLOT_MASK 0xffff /* allow 16 bits */ -#define WL_TXSTATUS_HSLOT_SHIFT 8 +#define WL_TXSTATUS_HSLOT_MASK 0xffffu /* allow 16 bits */ +#define WL_TXSTATUS_HSLOT_SHIFT 8u #define WL_TXSTATUS_SET_HSLOT(x, hslot) ((x) = \ ((x) & ~(WL_TXSTATUS_HSLOT_MASK << WL_TXSTATUS_HSLOT_SHIFT)) | \ @@ -244,7 +256,7 @@ typedef enum { #define WL_TXSTATUS_GET_HSLOT(x) (((x) >> WL_TXSTATUS_HSLOT_SHIFT)& \ WL_TXSTATUS_HSLOT_MASK) -#define WL_TXSTATUS_FREERUNCTR_MASK 0xff /* allow 8 bits */ +#define WL_TXSTATUS_FREERUNCTR_MASK 0xffu /* allow 8 bits */ #define WL_TXSTATUS_SET_FREERUNCTR(x, ctr) ((x) = \ ((x) & ~(WL_TXSTATUS_FREERUNCTR_MASK)) | \ @@ -377,6 +389,8 @@ typedef enum { #define WLFC_CTL_PKTFLAG_DROPPED 7 /* Firmware free this packet */ #define WLFC_CTL_PKTFLAG_MKTFREE 8 +/* Firmware drop this packet due to AMPDU cleanup */ +#define WLFC_CTL_PKTFLAG_AMPDU_CLEANUP 8 /* Firmware dropped the frame after suppress retries reached max */ #define WLFC_CTL_PKTFLAG_MAX_SUP_RETR 9 @@ -423,30 +437,30 @@ typedef enum { #define WLFC_MODE_AFQ 2 /* use afq (At Firmware Queue) */ #define WLFC_IS_OLD_DEF(x) ((x & 1) || (x & 2)) -#define WLFC_MODE_AFQ_SHIFT 2 /* afq bit */ +#define WLFC_MODE_AFQ_SHIFT 2u /* afq bit */ #define WLFC_SET_AFQ(x, val) ((x) = \ - ((x) & ~(1 << WLFC_MODE_AFQ_SHIFT)) | \ - (((val) & 1) << WLFC_MODE_AFQ_SHIFT)) + ((x) & ~(1u << WLFC_MODE_AFQ_SHIFT)) | \ + (((val) & 1u) << WLFC_MODE_AFQ_SHIFT)) /** returns TRUE if firmware supports 'at firmware queue' feature */ #define WLFC_GET_AFQ(x) (((x) >> WLFC_MODE_AFQ_SHIFT) & 1) -#define WLFC_MODE_REUSESEQ_SHIFT 3 /* seq reuse bit */ +#define WLFC_MODE_REUSESEQ_SHIFT 3u /* seq reuse bit */ #define WLFC_SET_REUSESEQ(x, val) ((x) = \ - ((x) & ~(1 << WLFC_MODE_REUSESEQ_SHIFT)) | \ - (((val) & 1) << WLFC_MODE_REUSESEQ_SHIFT)) + ((x) & ~(1u << WLFC_MODE_REUSESEQ_SHIFT)) | \ + (((val) & 1u) << WLFC_MODE_REUSESEQ_SHIFT)) /** returns TRUE if 'd11 sequence reuse' has been agreed upon between host and dongle */ -#if defined(BCMPCIEDEV_ENABLED) && !defined(ROM_ENAB_RUNTIME_CHECK) +#if defined(BCMPCIEDEV_ENABLED) /* GET_REUSESEQ is always TRUE in pciedev */ #define WLFC_GET_REUSESEQ(x) (TRUE) #else #define WLFC_GET_REUSESEQ(x) (((x) >> WLFC_MODE_REUSESEQ_SHIFT) & 1) -#endif /* defined(BCMPCIEDEV_ENABLED) && !defined(ROM_ENAB_RUNTIME_CHECK) */ +#endif /* defined(BCMPCIEDEV_ENABLED) */ -#define WLFC_MODE_REORDERSUPP_SHIFT 4 /* host reorder suppress pkt bit */ +#define WLFC_MODE_REORDERSUPP_SHIFT 4u /* host reorder suppress pkt bit */ #define WLFC_SET_REORDERSUPP(x, val) ((x) = \ - ((x) & ~(1 << WLFC_MODE_REORDERSUPP_SHIFT)) | \ - (((val) & 1) << WLFC_MODE_REORDERSUPP_SHIFT)) + ((x) & ~(1u << WLFC_MODE_REORDERSUPP_SHIFT)) | \ + (((val) & 1u) << WLFC_MODE_REORDERSUPP_SHIFT)) /** returns TRUE if 'reorder suppress' has been agreed upon between host and dongle */ #define WLFC_GET_REORDERSUPP(x) (((x) >> WLFC_MODE_REORDERSUPP_SHIFT) & 1) @@ -467,6 +481,8 @@ typedef enum { #define FLOW_RING_GET_BUFFERED_TIME 15u #define FLOW_RING_HP2P_TXQ_STRT 16u #define FLOW_RING_HP2P_TXQ_STOP 17u +#define FLOW_RING_GET_TXPARAMS 18u +#define FLOW_RING_GET_ONCHAN_TIME 19u /* bit 7, indicating if is TID(1) or AC(0) mapped info in tid field) */ #define PCIEDEV_IS_AC_TID_MAP_MASK 0x80 @@ -483,7 +499,9 @@ typedef enum { APP_STS_FLOWRING_CLOSED = 1u, /* Disable APP as flowring is closed */ APP_STS_CRYPTO_UNSUPPORTED = 2u, /* Secuirity type doesn't support APP */ APP_STS_80211_FRAGMENTATION = 3u, /* 802.11 fragmentation enabled */ - APP_STS_MAX = 4u /* MAX */ + APP_STS_DISABLE_FOR_BTCX = 4u, /* BTCX requested APP disable */ + APP_STS_DISABLE_FOR_QOS = 5u, /* Disable APP for QoS */ + APP_STS_MAX = 6u /* MAX */ } app_disable_reason_s; /* shared structure between wlc and pciedev layer to set/reset a reason code */ @@ -493,4 +511,10 @@ typedef struct app_upd_sts { app_disable_reason_s rsn; /* APP disable reason codes. */ } app_upd_sts_t; +/* shared structure between wlc and pciedev layer for info exchange. */ +typedef struct d2h_queue_status { + bool status; /* pciedev layer updates its status */ + void *pkt; /* wlc layer argument to be validated in PCIE layer. */ +} d2h_queue_status_t; + #endif /* __wlfc_proto_definitions_h__ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h old mode 100755 new mode 100644 index 97f0148fbe6f..65edb4b10d86 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h @@ -6,7 +6,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -57,6 +57,14 @@ #endif /* BCMUTILS_ERR_CODES */ #include +#ifndef USE_LEGACY_RSPEC_DEFS +#include +#endif + +#ifdef FTM +#include +#endif + /* NOTE re: Module specific error codes. * * BCME_.. error codes are extended by various features - e.g. FTM, NAN, SAE etc. @@ -75,10 +83,15 @@ /* 11ax trigger frame format - versioning info */ #define TRIG_FRAME_FORMAT_11AX_DRAFT_1P1 0 +#define TRIG_FRAME_INFO_VER2 1 // support 11AX and 11BE triggers +#define TRIGGER_FRAME_SPEC_11AX 0 +#define TRIGGER_FRAME_SPEC_11BE 1 + +#define WL_NAN_REKEY WL_NAN_CMD_CFG_REKEY typedef struct { uint32 num; - chanspec_t list[1]; + chanspec_t list[BCM_FLEX_ARRAY]; } chanspec_list_t; #define RSN_KCK_LENGTH 16 @@ -88,12 +101,13 @@ typedef struct { #define INTF_NAME_SIZ 16 #endif -#define WL_ASSOC_START_EVT_DATA_VERSION 1 +#define WL_ASSOC_START_EVT_DATA_VERSION_1 1 typedef struct assoc_event_data { uint32 version; uint32 flags; chanspec_t join_chspec; + uint16 PAD; } assoc_event_data_t; /**Used to send ioctls over the transport pipe */ @@ -104,9 +118,10 @@ typedef struct remote_ioctl { } rem_ioctl_t; #define REMOTE_SIZE sizeof(rem_ioctl_t) -#define BCM_IOV_XTLV_VERSION 0 +#define BCM_IOV_XTLV_VERSION_0 0 #define MAX_NUM_D11CORES 2 +#define PHY_SAMP_TXTONE_MAX_NUM 2u /**DFS Forced param */ typedef struct wl_dfs_forced_params { @@ -128,10 +143,10 @@ typedef struct wl_dfs_forced_params { /**association decision information */ typedef struct { uint8 assoc_approved; /**< (re)association approved */ - uint8 pad; + uint8 PAD; uint16 reject_reason; /**< reason code for rejecting association */ struct ether_addr da; - uint8 pad1[6]; + uint8 PAD[6]; #if defined(NDIS) && (NDISVER >= 0x0620) LARGE_INTEGER sys_time; /**< current system time */ #else @@ -148,15 +163,26 @@ typedef struct { #define DFS_SCAN_S_MAX 5 #define ACTION_FRAME_SIZE 1800 +#define WL_RAND_GAS_MAC (0x01 << 0u) +typedef struct wl_action_frame_v1 { + struct ether_addr da; + uint16 len; + uint32 packetId; + uint8 data[ACTION_FRAME_SIZE]; +} wl_action_frame_v1_t; -typedef struct wl_action_frame { - struct ether_addr da; - uint16 len; - uint32 packetId; - uint8 data[ACTION_FRAME_SIZE]; -} wl_action_frame_t; - -#define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame) +typedef struct wl_action_frame_v2 { + uint16 version; + uint16 len_total; + uint16 data_offset; + struct ether_addr da; + uint32 packetId; + struct ether_addr rand_mac_addr; + struct ether_addr rand_mac_mask; + uint16 flags; + uint16 len_data; + uint8 data[]; +} wl_action_frame_v2_t; typedef struct ssid_info { @@ -164,15 +190,43 @@ typedef struct ssid_info uint8 ssid[32]; /**< SSID string */ } ssid_info_t; -typedef struct wl_af_params { +typedef struct wl_af_params_v1 { uint32 channel; int32 dwell_time; struct ether_addr BSSID; uint8 PAD[2]; - wl_action_frame_t action_frame; -} wl_af_params_t; + wl_action_frame_v1_t action_frame; +} wl_af_params_v1_t; -#define WL_WIFI_AF_PARAMS_SIZE sizeof(struct wl_af_params) +#define WL_WIFI_ACTION_FRAME_SIZE_V1 sizeof(wl_action_frame_v1_t) +#define WL_WIFI_AF_PARAMS_SIZE_V1 sizeof(wl_af_params_v1_t) + +typedef struct wl_af_params_v2 { + uint16 version; + uint16 length; + uint32 channel; + int32 dwell_time; + struct ether_addr BSSID; + uint8 PAD[2]; + wl_action_frame_v2_t action_frame; +} wl_af_params_v2_t; + +#define WL_WIFI_ACTION_FRAME_SIZE_V2 sizeof(wl_action_frame_v2_t) +#define WL_WIFI_AF_PARAMS_SIZE_V2 sizeof(wl_af_params_v2_t) + +/* version of actframe iovar to be returned as part of wl_actframe_version structure */ +#define WL_ACTFRAME_VERSION_MAJOR_2 2u + +/**< current version of actframe_version structure */ +#define WL_ACTFRAME_VERSION_V1 1u + +/** actframe interface version */ +typedef struct wl_actframe_version_v1 { + uint16 version; /**< version of the structure */ + uint16 length; /**< length of the entire structure */ + /* actframe interface version numbers */ + uint16 actframe_ver_major; /**< actframe interface major version number */ +} wl_actframe_version_v1_t; #define MFP_TEST_FLAG_NORMAL 0 #define MFP_TEST_FLAG_ANY_KEY 1 @@ -213,7 +267,7 @@ typedef struct { #define WL_OBSS_DYN_BWSW_FLAG_TXOP_PERIOD (0x40) /* OBSS IOVAR Version information */ -#define WL_PROT_OBSS_CONFIG_PARAMS_VERSION 1 +#define WL_PROT_OBSS_CONFIG_PARAMS_VERSION_1 1 #include typedef BWL_PRE_PACKED_STRUCT struct { @@ -296,7 +350,8 @@ typedef struct ulp_shm_info { * Cf PR53622 */ -#define WL_BSS_INFO_VERSION 109 /**< current version of wl_bss_info struct */ +#define WL_BSS_INFO_VER_109 109 +#define WL_BSS_INFO_VER_114 114 /** * BSS info structure @@ -326,15 +381,16 @@ typedef struct wl_bss_info { int8 phy_noise; /**< noise (in dBm) */ uint8 n_cap; /**< BSS is 802.11N Capable */ uint8 freespace1; /* make implicit padding explicit */ - uint8 load; /**< BSS Load from QBSS load IE if available */ + uint8 load; /**< BSS Load (channel utilization of BSSLoad IE) */ uint32 nbss_cap; /**< 802.11N+AC BSS Capabilities */ uint8 ctl_ch; /**< 802.11N BSS control channel number */ - uint8 padding1[3]; /**< explicit struct alignment padding */ + uint8 PAD[3]; /**< explicit struct alignment padding */ uint16 vht_rxmcsmap; /**< VHT rx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ uint16 vht_txmcsmap; /**< VHT tx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ uint8 flags; /**< flags */ uint8 vht_cap; /**< BSS is vht capable */ - uint8 reserved[2]; /**< Reserved for expansion of BSS properties */ + uint8 flags2; /**< extended flags */ + uint8 reserved; /**< Reserved for expansion of BSS properties */ uint8 basic_mcs[MCSSET_LEN]; /**< 802.11N BSS required MCS set */ uint16 ie_offset; /**< offset at which IEs start, from beginning */ @@ -374,15 +430,16 @@ typedef struct wl_bss_info_v109_1 { int8 phy_noise; /**< noise (in dBm) */ uint8 n_cap; /**< BSS is 802.11N Capable */ uint8 he_cap; /**< BSS is he capable */ - uint8 load; /**< BSS Load from QBSS load IE if available */ + uint8 load; /**< BSS Load (channel utilization of BSSLoad IE) */ uint32 nbss_cap; /**< 802.11N+AC BSS Capabilities */ uint8 ctl_ch; /**< 802.11N BSS control channel number */ - uint8 padding1[3]; /**< explicit struct alignment padding */ + uint8 PAD[3]; /**< explicit struct alignment padding */ uint16 vht_rxmcsmap; /**< VHT rx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ uint16 vht_txmcsmap; /**< VHT tx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ uint8 flags; /**< flags */ uint8 vht_cap; /**< BSS is vht capable */ - uint8 reserved[2]; /**< Reserved for expansion of BSS properties */ + uint8 flags2; /**< extended flags */ + uint8 reserved; /**< Reserved for expansion of BSS properties */ uint8 basic_mcs[MCSSET_LEN]; /**< 802.11N BSS required MCS set */ uint16 ie_offset; /**< offset at which IEs start, from beginning */ @@ -425,7 +482,7 @@ typedef struct wl_bss_info_v109_2 { int8 phy_noise; /**< noise (in dBm) */ uint8 n_cap; /**< BSS is 802.11N Capable */ uint8 he_cap; /**< BSS is he capable */ - uint8 load; /**< BSS Load from QBSS load IE if available */ + uint8 load; /**< BSS Load (channel utilization of BSSLoad IE) */ uint32 nbss_cap; /**< 802.11N+AC BSS Capabilities */ uint8 ctl_ch; /**< 802.11N BSS control channel number */ uint8 RSVD1[3]; @@ -433,7 +490,8 @@ typedef struct wl_bss_info_v109_2 { uint16 vht_txmcsmap; /**< VHT tx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ uint8 flags; /**< flags */ uint8 vht_cap; /**< BSS is vht capable */ - uint8 RSVD2[2]; + uint8 flags2; /**< extended flags */ + uint8 RSVD2; uint8 basic_mcs[MCSSET_LEN]; /**< 802.11N BSS required MCS set */ uint16 ie_offset; /**< offset at which IEs start, from beginning */ @@ -463,7 +521,9 @@ typedef struct wl_bss_info_v112 { uint16 beacon_period; /**< units are Kusec */ uint16 capability; /**< Capability information */ uint8 SSID_len; - uint8 SSID[32]; + uint8 SSID[32]; /* values can be short ssid or ssid indicates + * in flags2 WL_BSS3_FLAGS_SHORT_SSID + */ uint8 bcnflags; /* additional flags w.r.t. beacon */ struct { uint32 count; /**< # rates in this set */ @@ -477,7 +537,7 @@ typedef struct wl_bss_info_v112 { int8 phy_noise; /**< noise (in dBm) */ uint8 n_cap; /**< BSS is 802.11N Capable */ uint8 he_cap; /**< BSS is he capable */ - uint8 load; /**< BSS Load from QBSS load IE if available */ + uint8 load; /**< BSS Load (channel utilization of BSSLoad IE) */ uint32 nbss_cap; /**< 802.11N+AC BSS Capabilities */ uint8 ctl_ch; /**< 802.11N BSS control channel number */ uint8 RSVD1[3]; @@ -485,7 +545,8 @@ typedef struct wl_bss_info_v112 { uint16 vht_txmcsmap; /**< VHT tx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ uint8 flags; /**< flags */ uint8 vht_cap; /**< BSS is vht capable */ - uint8 RSVD2[2]; + uint8 flags2; /**< extended flags */ + uint8 RSVD2; uint8 basic_mcs[MCSSET_LEN]; /**< 802.11N BSS required MCS set */ uint16 ie_offset; /**< offset at which IEs start, from beginning */ uint16 freespace2; /* making implicit padding explicit */ @@ -498,23 +559,85 @@ typedef struct wl_bss_info_v112 { uint32 he_rxmcsmap; /**< HE rx mcs map (802.11ax IE, HE_CAP_MCS_MAP_*) */ uint32 he_txmcsmap; /**< HE tx mcs map (802.11ax IE, HE_CAP_MCS_MAP_*) */ uint32 timestamp[2]; /* Beacon Timestamp for FAKEAP req */ - uint8 eht_cap; /* BSS is EHT capable */ - uint8 RSVD3[3]; - /* by the spec. it is maximum 16 streams hence all mcs code for all nss may not fit - * in a 32 bit mcs nss map but since this field only reflects the common mcs nss map - * between that of the peer and our device so it's probably ok to make it 32 bit and - * allow only a limited number of nss e.g. upto 8 of them in the map given the fact - * that our device probably won't exceed 4 streams anyway... - */ - uint32 eht_mcsmap; /* STA's associated EHT mcs code map */ - /* FIXME: change the following mcs code map to uint32 if all mcs+nss can fit in */ - uint8 eht_rxmcsmap[6]; /* EHT rx mcs code map */ - uint8 eht_txmcsmap[6]; /* EHT tx mcs code map */ + uint8 pad1[20]; } wl_bss_info_v112_t; -#ifndef WL_BSS_INFO_TYPEDEF_HAS_ALIAS -typedef wl_bss_info_v109_t wl_bss_info_t; -#endif +/* EHT-MCS Map for the current operating channel width. + * + * The map consists of two parts: + * + * 1. EHT-MCS Map subfield defined in IEEE P802.11be D1.2 EHT-MCS Map (20MHz-Only Non-AP STA) + * for mcs 0 - 13 + * 2. EHT-MCS Bitmap defined in this file for mcs 14 & 15 (See WL_EHT_MCS_BMP_MCS_x_POS) + */ +typedef struct wl_eht_mcsmap { + uint8 mcs_0_13[4]; /* mcs 0 - 13 mcsmap */ + uint8 mcs_14_15[1]; /* mcs 14 & 15 bitmap */ +} wl_eht_mcsmap_t; + +/* EHT mcs 14 & 15 bit positions */ +#define WL_EHT_MCS_BMP_MCS_14_POS 0u +#define WL_EHT_MCS_BMP_MCS_15_POS 1u +/* EHT mcs 14 & 15 field width */ +#define WL_EHT_MCS_BMP_MCS_SZ 1u /* 1 bit per mcs */ + +/** + * BSS info structure + * Applications MUST CHECK ie_offset field and length field to access IEs and + * next bss_info structure in a vector (in wl_scan_results_t) + */ +typedef struct wl_bss_info_v114 { + uint32 version; /**< version field */ + uint32 length; /**< byte length of data in this record, + * starting at version and including IEs + */ + struct ether_addr BSSID; + uint16 beacon_period; /**< units are Kusec */ + uint16 capability; /**< Capability information */ + uint8 SSID_len; + uint8 SSID[32]; /* values can be short ssid or ssid indicates + * in flags2 WL_BSS3_FLAGS_SHORT_SSID + */ + uint8 bcnflags; /* additional flags w.r.t. beacon */ + struct { + uint32 count; /**< # rates in this set */ + uint8 rates[16]; /**< rates in 500kbps units w/hi bit set if basic */ + } rateset; /**< supported rates */ + chanspec_t chanspec; /**< chanspec for bss */ + uint16 atim_window; /**< units are Kusec */ + uint8 dtim_period; /**< DTIM period */ + uint8 accessnet; /* from beacon interwork IE (if bcnflags) */ + int16 RSSI; /**< receive signal strength (in dBm) */ + int8 phy_noise; /**< noise (in dBm) */ + uint8 n_cap; /**< BSS is 802.11N Capable */ + uint8 he_cap; /**< BSS is he capable */ + uint8 load; /**< BSS Load (channel utilization of BSSLoad IE) */ + uint32 nbss_cap; /**< 802.11N+AC BSS Capabilities */ + uint8 ctl_ch; /**< 802.11N BSS control channel number */ + uint8 RSVD1[3]; + uint16 vht_rxmcsmap; /**< VHT rx mcs map (802.11ac) */ + uint16 vht_txmcsmap; /**< VHT tx mcs map (802.11ac) */ + uint8 flags; /**< flags */ + uint8 vht_cap; /**< BSS is vht capable */ + uint8 flags2; /**< extended flags */ + uint8 RSVD2[1]; + uint8 basic_mcs[MCSSET_LEN]; /**< 802.11N BSS required MCS set */ + uint16 ie_offset; /**< offset at which IEs start, from beginning */ + uint8 RSVD3[2]; /* making implicit padding explicit */ + uint32 ie_length; /**< byte length of Information Elements */ + int16 SNR; /**< average SNR of during frame reception */ + uint16 vht_mcsmap; /**< STA's Associated vhtmcsmap */ + uint16 vht_mcsmap_prop; /**< STA's Associated prop vhtmcsmap */ + uint16 vht_txmcsmap_prop; /**< prop VHT tx mcs prop */ + uint32 he_mcsmap; /**< STA's Associated hemcsmap */ + uint32 he_rxmcsmap; /**< HE rx mcs map (802.11ax) */ + uint32 he_txmcsmap; /**< HE tx mcs map (802.11ax) */ + uint32 timestamp[2]; /* Beacon Timestamp for FAKEAP req */ + uint8 eht_cap; /* BSS is EHT capable */ + uint8 RSVD4[1]; + wl_eht_mcsmap_t eht_mcsmap_sta; /* EHT-MCS Map for the STA in associated state */ + wl_eht_mcsmap_t eht_mcsmap; /* EHT-MCS Map for the BSS operating chan width */ +} wl_bss_info_v114_t; #define WL_GSCAN_FULL_RESULT_VERSION 2 /* current version of wl_gscan_result_t struct */ @@ -532,11 +655,6 @@ typedef struct wl_gscan_bss_info_v3 { /* and variable length Information Elements to follow */ } wl_gscan_bss_info_v3_t; -#ifndef WL_BSS_INFO_TYPEDEF_HAS_ALIAS -typedef wl_gscan_bss_info_v2_t wl_gscan_bss_info_t; -#define WL_GSCAN_INFO_FIXED_FIELD_SIZE (sizeof(wl_gscan_bss_info_t) - sizeof(wl_bss_info_t)) -#endif - typedef struct wl_bsscfg { uint32 bsscfg_idx; uint32 wsec; @@ -608,9 +726,10 @@ typedef struct wl_bsscolor_info { #define DLOAD_FLAG_VER_MASK 0xf000 /**< Downloader version mask */ #define DLOAD_FLAG_VER_SHIFT 12 /**< Downloader version shift */ -#define DL_CRC_NOT_INUSE 0x0001 -#define DL_BEGIN 0x0002 -#define DL_END 0x0004 +#define DL_CRC_NOT_INUSE 0x0001u +#define DL_BEGIN 0x0002u /* First BLOB fragment */ +#define DL_END 0x0004u /* Last BLOB fragment */ +#define DL_FORCE 0x0008u /* Force download */ /* Flags for Major/Minor/Date number shift and mask */ #define EPI_VER_SHIFT 16 @@ -618,7 +737,8 @@ typedef struct wl_bsscolor_info { /** generic download types & flags */ enum { DL_TYPE_UCODE = 1, - DL_TYPE_CLM = 2 + DL_TYPE_CLM = 2, + DL_TYPE_DRRBLOB = 3 }; /** ucode type values */ @@ -633,7 +753,7 @@ struct wl_dload_data { uint16 dload_type; uint32 len; uint32 crc; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; }; typedef struct wl_dload_data wl_dload_data_t; @@ -642,7 +762,7 @@ struct wl_ucode_info { uint32 num_chunks; uint32 chunk_len; uint32 chunk_num; - uint8 data_chunk[1]; + uint8 data_chunk[BCM_FLEX_ARRAY]; }; typedef struct wl_ucode_info wl_ucode_info_t; @@ -652,10 +772,54 @@ struct wl_clm_dload_info { uint32 num_chunks; uint32 chunk_len; uint32 chunk_offset; - uint8 data_chunk[1]; + uint8 data_chunk[BCM_FLEX_ARRAY]; }; typedef struct wl_clm_dload_info wl_clm_dload_info_t; +/* Max size for MSF fw version field */ +#define WL_MSFVER_MAX_FW_VERSION_LEN (64u) + +/* Indication for an undefined MSF calibration content version */ +#define WL_MSFVER_UNDEFINED (0xFFFFFFFFu) + +typedef struct wl_msf_ver_s { + char fw_ver[WL_MSFVER_MAX_FW_VERSION_LEN]; /* FW Version */ + uint32 main_rx_ver; /* Main core Rx MSF content version */ + uint32 main_tx_ver; /* Main core Tx MSF content version */ + uint32 aux_rx_ver; /* Aux core Rx MSF content version */ + uint32 aux_tx_ver; /* Aux core Tx MSF content version */ + uint32 scan_rx_ver; /* Scan core Rx MSF content version */ + uint8 main_rx_is_generic; /* Flag - Main core Rx MSF content is generic */ + uint8 main_tx_is_generic; /* Flag - Main core Tx MSF content is generic */ + uint8 aux_rx_is_generic; /* Flag - Aux core Rx MSF content is generic */ + uint8 aux_tx_is_generic; /* Flag - Aux core Tx MSF content is generic */ + uint8 scan_rx_is_generic; /* Flag - Scan core Rx MSF content is generic */ + uint8 PAD[3]; +} wl_msf_ver_t; + +/* CALLOAD IOVAR - uses bcm iov sub-command framework */ +#define WL_CAL_IOV_MAJOR_VER_1 1 +#define WL_CAL_IOV_MINOR_VER_1 1 +#define WL_CAL_IOV_MAJOR_VER_SHIFT 8 +#define WL_CAL_IOV_VERSION_1_1 ((WL_CAL_IOV_MAJOR_VER_1 << WL_CAL_IOV_MAJOR_VER_SHIFT) | \ + WL_CAL_IOV_MINOR_VER_1) + +/* CALLOAD subcommand ids */ +enum wl_cal_subcmd_ids { + WL_CAL_SUBCMD_VERSION = 0u, /* Get cal iovar version */ + WL_CAL_SUBCMD_LOAD = 1u, /* FW MSF calibration content version */ + WL_CAL_SUBCMD_FW_VER = 2u, /* FW MSF calibration content version */ + WL_CAL_SUBCMD_STATUS = 3u, /* MSF load status */ + WL_CAL_SUBCMD_LAST +}; + +typedef struct wl_cal_status_ver_s { + uint32 status; /* calload status */ + uint32 flags; /* Copy of calload flags - Mainly DL_FORCE */ + wl_msf_ver_t fw_ver; /* FW MSF content versions for all cores */ + wl_msf_ver_t msf_ver; /* Downloaded MSF content versions for all cores */ +} wl_cal_status_ver_t; + typedef struct wlc_ssid { uint32 SSID_len; uint8 SSID[DOT11_MAX_SSID_LEN]; @@ -678,12 +842,12 @@ typedef struct wlc_fastssidinfo { typedef struct wnm_url { uint8 len; - uint8 data[1]; + uint8 data[BCM_FLEX_ARRAY]; } wnm_url_t; typedef struct chan_scandata { uint8 txpower; - uint8 pad; + uint8 PAD; chanspec_t channel; /**< Channel num, bw, ctrl_sb and band */ uint32 channel_mintime; uint32 channel_maxtime; @@ -698,22 +862,21 @@ typedef enum wl_scan_type { #define WLC_EXTDSCAN_MAX_SSID 5 typedef struct wl_extdscan_params { - int8 nprobes; /**< 0, passive, otherwise active */ - int8 split_scan; /**< split scan */ - int8 band; /**< band */ - int8 pad; - wlc_ssid_t ssid[WLC_EXTDSCAN_MAX_SSID]; /**< ssid list */ - uint32 tx_rate; /**< in 500ksec units */ - wl_scan_type_t scan_type; /**< enum */ + int8 nprobes; /**< 0, passive, otherwise active */ + int8 split_scan; /**< split scan */ + int8 band; /**< band */ + int8 PAD; + wlc_ssid_t ssid[WLC_EXTDSCAN_MAX_SSID]; /**< ssid list */ + uint32 tx_rate; /**< in 500ksec units */ + wl_scan_type_t scan_type; /**< enum */ int32 channel_num; - chan_scandata_t channel_list[1]; /**< list of chandata structs */ + chan_scandata_t channel_list[BCM_FLEX_ARRAY]; /**< list of chandata structs */ } wl_extdscan_params_t; -#define WL_EXTDSCAN_PARAMS_FIXED_SIZE (sizeof(wl_extdscan_params_t) - sizeof(chan_scandata_t)) - +#define WL_EXTDSCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_extdscan_params_t, channel_list)) #define WL_SCAN_PARAMS_SSID_MAX 10 -struct wl_scan_params { +typedef struct wl_scan_params_v1 { wlc_ssid_t ssid; /**< default: {0, ""} */ struct ether_addr bssid; /**< default: bcast */ int8 bss_type; /**< default: any, @@ -744,8 +907,13 @@ struct wl_scan_params { * parameter portion is assumed, otherwise ssid in * the fixed portion is ignored */ - uint16 channel_list[1]; /**< list of chanspecs */ -}; + uint16 channel_list[BCM_FLEX_ARRAY]; +} wl_scan_params_v1_t; + +/** size of wl_scan_params_v1 not including variable length array */ +#define WL_SCAN_PARAMS_V1_FIXED_SIZE (OFFSETOF(wl_scan_params_v1_t, channel_list)) +#define WL_MAX_ROAMSCAN_V1_DATSZ \ + (WL_SCAN_PARAMS_V1_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(uint16))) /* changes in wl_scan_params_v2 as comapred to wl_scan_params (v1) * unit8 scantype to uint32 @@ -790,15 +958,13 @@ typedef struct wl_scan_params_v2 { * parameter portion is assumed, otherwise ssid in * the fixed portion is ignored */ - uint16 channel_list[1]; /**< list of chanspecs */ + uint16 channel_list[BCM_FLEX_ARRAY]; } wl_scan_params_v2_t; #define WL_SCAN_PARAMS_VERSION_V2 2 /** size of wl_scan_params not including variable length array */ #define WL_SCAN_PARAMS_V2_FIXED_SIZE (OFFSETOF(wl_scan_params_v2_t, channel_list)) -#define WL_MAX_ROAMSCAN_DATSZ \ - (WL_SCAN_PARAMS_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(uint16))) #define WL_MAX_ROAMSCAN_V2_DATSZ \ (WL_SCAN_PARAMS_V2_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(uint16))) @@ -857,16 +1023,16 @@ typedef struct wl_scan_params_v3 { #define WL_MAX_ROAMSCAN_V3_DATSZ \ (WL_SCAN_PARAMS_V3_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(uint16))) -#define ISCAN_REQ_VERSION 1 +#define ISCAN_REQ_VERSION_V1 1 #define ISCAN_REQ_VERSION_V2 2 /** incremental scan struct */ -struct wl_iscan_params { +typedef struct wl_iscan_params_v1 { uint32 version; uint16 action; uint16 scan_duration; - struct wl_scan_params params; -}; + struct wl_scan_params_v1 params; +} wl_iscan_params_v1_t; /** incremental scan struct */ typedef struct wl_iscan_params_v2 { @@ -895,8 +1061,9 @@ typedef struct wl_scan_results_v109 { uint32 buflen; uint32 version; uint32 count; - wl_bss_info_v109_t bss_info[1]; + wl_bss_info_v109_t bss_info[BCM_FLEX_ARRAY]; } wl_scan_results_v109_t; +#define WL_SCAN_RESULTS_V109_FIXED_SIZE (OFFSETOF(wl_scan_results_v109_t, bss_info)) typedef struct wl_scan_results_v2 { uint32 buflen; @@ -904,31 +1071,26 @@ typedef struct wl_scan_results_v2 { uint32 count; uint8 bss_info[]; /* var length wl_bss_info_X structures */ } wl_scan_results_v2_t; - -#ifndef WL_BSS_INFO_TYPEDEF_HAS_ALIAS -typedef wl_scan_results_v109_t wl_scan_results_t; -/** size of wl_scan_results not including variable length array */ -#define WL_SCAN_RESULTS_FIXED_SIZE (sizeof(wl_scan_results_t) - sizeof(wl_bss_info_t)) -#endif +#define WL_SCAN_RESULTS_V2_FIXED_SIZE (OFFSETOF(wl_scan_results_v2_t, bss_info)) #if defined(SIMPLE_ISCAN) -/** the buf lengh can be WLC_IOCTL_MAXLEN (8K) to reduce iteration */ +/** the buf length can be WLC_IOCTL_MAXLEN (8K) to reduce iteration */ #define WLC_IW_ISCAN_MAXLEN 2048 typedef struct iscan_buf { struct iscan_buf * next; int8 iscan_buf[WLC_IW_ISCAN_MAXLEN]; } iscan_buf_t; #endif /* SIMPLE_ISCAN */ -#define ESCAN_REQ_VERSION 1 +#define ESCAN_REQ_VERSION_V1 1 #define ESCAN_REQ_VERSION_V2 2 +#define ESCAN_REQ_VERSION_V3 3 -/** event scan reduces amount of SOC memory needed to store scan results */ -struct wl_escan_params { +typedef struct wl_escan_params_v1 { uint32 version; uint16 action; uint16 sync_id; - struct wl_scan_params params; -}; + struct wl_scan_params_v1 params; +} wl_escan_params_v1_t; typedef struct wl_escan_params_v2 { uint32 version; @@ -944,34 +1106,9 @@ typedef struct wl_escan_params_v3 { wl_scan_params_v3_t params; } wl_escan_params_v3_t; -#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t)) +#define WL_ESCAN_PARAMS_V1_FIXED_SIZE (OFFSETOF(wl_escan_params_v1_t, params) + sizeof(wlc_ssid_t)) #define WL_ESCAN_PARAMS_V2_FIXED_SIZE (OFFSETOF(wl_escan_params_v2_t, params) + sizeof(wlc_ssid_t)) #define WL_ESCAN_PARAMS_V3_FIXED_SIZE (OFFSETOF(wl_escan_params_v3_t, params) + sizeof(wlc_ssid_t)) -/* New scan version is defined then change old version of scan to - * wl_scan_params_v1_t and new one to wl_scan_params_t - */ -#if defined (WL_SCAN_PARAMS_V3) -typedef struct wl_scan_params wl_scan_params_v1_t; -typedef struct wl_escan_params wl_escan_params_v1_t; -typedef struct wl_iscan_params wl_iscan_params_v1_t; -typedef struct wl_scan_params_v3 wl_scan_params_t; -typedef struct wl_escan_params_v3 wl_escan_params_t; -typedef struct wl_iscan_params_v3 wl_iscan_params_t; -#define WL_SCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_scan_params_t, channel_list)) -#elif defined(WL_SCAN_PARAMS_V2) -typedef struct wl_scan_params wl_scan_params_v1_t; -typedef struct wl_escan_params wl_escan_params_v1_t; -typedef struct wl_iscan_params wl_iscan_params_v1_t; -typedef struct wl_scan_params_v2 wl_scan_params_t; -typedef struct wl_escan_params_v2 wl_escan_params_t; -typedef struct wl_iscan_params_v2 wl_iscan_params_t; -#define WL_SCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_scan_params_t, channel_list)) -#else -typedef struct wl_scan_params wl_scan_params_t; -typedef struct wl_escan_params wl_escan_params_t; -typedef struct wl_iscan_params wl_iscan_params_t; -#define WL_SCAN_PARAMS_FIXED_SIZE 64 -#endif /* WL_SCAN_PARAMS_V3 */ /** event scan reduces amount of SOC memory needed to store scan results */ typedef struct wl_escan_result_v109 { @@ -979,8 +1116,9 @@ typedef struct wl_escan_result_v109 { uint32 version; uint16 sync_id; uint16 bss_count; - wl_bss_info_v109_t bss_info[1]; + wl_bss_info_v109_t bss_info[BCM_FLEX_ARRAY]; } wl_escan_result_v109_t; +#define WL_ESCAN_RESULTS_V109_FIXED_SIZE (OFFSETOF(wl_escan_result_v109_t, bss_info)) /** event scan reduces amount of SOC memory needed to store scan results */ typedef struct wl_escan_result_v2 { @@ -990,17 +1128,13 @@ typedef struct wl_escan_result_v2 { uint16 bss_count; uint8 bss_info[]; /* var length wl_bss_info_X structures */ } wl_escan_result_v2_t; - -#ifndef WL_BSS_INFO_TYPEDEF_HAS_ALIAS -typedef wl_escan_result_v109_t wl_escan_result_t; -#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(wl_escan_result_t) - sizeof(wl_bss_info_t)) -#endif +#define WL_ESCAN_RESULTS_V2_FIXED_SIZE (OFFSETOF(wl_escan_result_v2_t, bss_info)) typedef struct wl_gscan_result_v2 { uint32 buflen; uint32 version; uint32 scan_ch_bucket; - wl_gscan_bss_info_v2_t bss_info[1]; + wl_gscan_bss_info_v2_t bss_info[BCM_FLEX_ARRAY]; } wl_gscan_result_v2_t; typedef struct wl_gscan_result_v2_1 { @@ -1010,11 +1144,6 @@ typedef struct wl_gscan_result_v2_1 { uint8 bss_info[]; /* var length wl_bss_info_X structures */ } wl_gscan_result_v2_1_t; -#ifndef WL_BSS_INFO_TYPEDEF_HAS_ALIAS -typedef wl_gscan_result_v2_t wl_gscan_result_t; -#define WL_GSCAN_RESULTS_FIXED_SIZE (sizeof(wl_gscan_result_t) - sizeof(wl_gscan_bss_info_t)) -#endif - /** incremental scan results struct */ typedef struct wl_iscan_results { uint32 status; @@ -1027,12 +1156,9 @@ typedef struct wl_iscan_results_v2 { wl_scan_results_v2_t results; } wl_iscan_results_v2_t; -#ifndef WL_BSS_INFO_TYPEDEF_HAS_ALIAS -typedef wl_iscan_results_v109_t wl_iscan_results_t; /** size of wl_iscan_results not including variable length array */ -#define WL_ISCAN_RESULTS_FIXED_SIZE \ - (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results)) -#endif +#define WL_ISCAN_RESULTS_V109_FIXED_SIZE \ + (WL_SCAN_RESULTS_V109_FIXED_SIZE + OFFSETOF(wl_iscan_results_v109_t, results)) typedef struct wl_probe_params { wlc_ssid_t ssid; @@ -1068,11 +1194,6 @@ typedef struct wl_rateset_args_v1 { * [d] in wlc_types.h: in respective branch and trunk: redefine wl_rateset_args_t with * new wl_rateset_args_vX_t */ -#ifndef RATESET_VERSION_ENABLED -/* rateset structure before versioning. legacy. DONOT update anymore here */ -#define RATESET_ARGS_VERSION (RATESET_ARGS_V1) -typedef wl_rateset_args_v1_t wl_rateset_args_t; -#endif /* RATESET_VERSION_ENABLED */ /* Note: dependent structures: sta_info_vX_t. When any update to this structure happens, * update sta_info_vX_t also. @@ -1097,7 +1218,7 @@ typedef struct wl_rateset_args_v2 { /* Note: dependent structures: sta_info_vX_t. When any update to this structure happens, * update sta_info_vX_t also. */ -#define WL_EHT_CAP_MCS_MAP_NSS_MAX 8u /* could be max. 16 streams by the spec, +#define WL_EHT_MCS_MAP_NSS_MAX 8u /* could be max. 16 streams by the spec, * but it's to control our own rateset * so it probably won't exceed 4 streams * anyway... @@ -1111,14 +1232,16 @@ typedef struct wl_rateset_args_v3 { uint8 mcs[MCSSET_LEN]; /**< supported mcs index bit map */ uint16 vht_mcs[WL_VHT_CAP_MCS_MAP_NSS_MAX]; /**< supported VHT mcs per nss */ uint16 he_mcs[WL_HE_CAP_MCS_MAP_NSS_MAX]; /**< supported HE mcs per nss */ - uint16 eht_mcs[WL_EHT_CAP_MCS_MAP_NSS_MAX]; /**< supported EHT mcs bitmap per nss */ + uint16 eht_mcs[WL_EHT_MCS_MAP_NSS_MAX]; /**< supported EHT mcs bitmap per nss */ } wl_rateset_args_v3_t; -/* EHT MCS BITMAP */ -#define WL_EHT_CAP_MCS_0_7_MAP 0x00ffu -#define WL_EHT_CAP_MCS_0_9_MAP 0x03ffu -#define WL_EHT_CAP_MCS_0_11_MAP 0x0fffu -#define WL_EHT_CAP_MCS_0_13_MAP 0x3fffu +/* 20MHz only EHT-MCS Map mcs range bitmap */ +#define WL_EHT_MCS_BMP_MCS_0_7 0x00ffu /* mcs 0 - 7 */ +#define WL_EHT_MCS_BMP_MCS_8_9 0x0300u /* mcs 8 & 9 */ +#define WL_EHT_MCS_BMP_MCS_10_11 0x0c00u /* mcs 10 & 11 */ +#define WL_EHT_MCS_BMP_MCS_12_13 0x3000u /* mcs 12 & 13 */ +#define WL_EHT_MCS_BMP_MCS_14 0x4000u /* mcs 14 */ +#define WL_EHT_MCS_BMP_MCS_15 0x8000u /* mcs 15 */ #define TXBF_RATE_MCS_ALL 4 #define TXBF_RATE_VHT_ALL 4 @@ -1175,7 +1298,7 @@ typedef struct wl_uint32_list { /** in - # of elements, out - # of entries */ uint32 count; /** variable length uint32 list */ - uint32 element[1]; + uint32 element[BCM_FLEX_ARRAY]; } wl_uint32_list_t; /* Size in bytes for wl_uint32_list_t with 'count' elements */ #define WL_UINT32_LIST_SIZE(count) (((count) + 1) * sizeof(uint32)) @@ -1193,7 +1316,7 @@ typedef struct wl_chanspec_list_s_v1 { /** in - # of chanspecs, out - # of entries */ uint16 count; /** variable length chanspecs list */ - wl_chanspec_attr_v1_t chspecs[1]; + wl_chanspec_attr_v1_t chspecs[BCM_FLEX_ARRAY]; } wl_chanspec_list_v1_t; /* WLC_SET_ALLOW_MODE values */ @@ -1213,7 +1336,7 @@ typedef struct wl_assoc_params { int32 chanspec_num; /**< 0: all available channels, * otherwise count of chanspecs in chanspec_list */ - chanspec_t chanspec_list[1]; /**< list of chanspecs */ + chanspec_t chanspec_list[BCM_FLEX_ARRAY]; /**< list of chanspecs */ } wl_assoc_params_t; @@ -1230,17 +1353,27 @@ typedef struct wl_assoc_params_v1 { int32 chanspec_num; /**< 0: all available channels, * otherwise count of chanspecs in chanspec_list */ - chanspec_t chanspec_list[1]; /**< list of chanspecs */ + chanspec_t chanspec_list[BCM_FLEX_ARRAY]; /**< list of chanspecs */ } wl_assoc_params_v1_t; -#define ASSOC_HINT_BSSID_PRESENT (1 << 0) +/** Assoc params flags */ +#define ASSOC_HINT_BSSID_PRESENT 0x0001u +/* FW to delete PMKSA of bssid listed in assoc params */ +#define WL_ASSOC_PARAM_FLAG_DEL_PMKSA 0x0002u +#define WL_ASSOC_PARAM_FLAG_ACTIVE6G 0x0004u #define WL_ASSOC_PARAMS_FIXED_SIZE OFFSETOF(wl_assoc_params_t, chanspec_list) #define WL_ASSOC_PARAMS_FIXED_SIZE_V1 OFFSETOF(wl_assoc_params_v1_t, chanspec_list) + /** used for reassociation/roam to a specific BSSID and channel */ typedef wl_assoc_params_t wl_reassoc_params_t; -#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE +typedef wl_assoc_params_v1_t wl_reassoc_params_v1_t; + +#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE +#define WL_REASSOC_PARAMS_FIXED_SIZE_V1 WL_ASSOC_PARAMS_FIXED_SIZE_V1 + #define WL_EXT_REASSOC_VER 1 +#define WL_EXT_REASSOC_VER_1 2 typedef struct wl_ext_reassoc_params { uint16 version; @@ -1250,16 +1383,26 @@ typedef struct wl_ext_reassoc_params { } wl_ext_reassoc_params_t; /* Flags field defined above in wl_ext_reassoc_params - * The value in bits [2:0] is used to specify the type + * The below flag bit is used to specify the type * of scan to be used for reassoc */ -#define WL_SCAN_MODE_HIGH_ACC 0u /**< use high accuracy scans for roam */ -#define WL_SCAN_MODE_LOW_SPAN 1u /**< use low span scans for roam */ -#define WL_SCAN_MODE_LOW_POWER 2u /**< use low power scans for roam */ +#define WL_SCAN_MODE_HIGH_ACC 0u /**< use high accuracy scans for roam */ +#define WL_SCAN_MODE_LOW_SPAN 1u /**< use low span scans for roam */ +#define WL_SCAN_MODE_LOW_POWER 2u /**< use low power scans for roam */ +#define WL_SCAN_MODE_NO_6GHZ_FOLLOWUP 4u /* 6G active scan not done due to RNR or FILS */ #define WL_EXTREASSOC_PARAMS_FIXED_SIZE (OFFSETOF(wl_ext_reassoc_params_t, params) + \ WL_REASSOC_PARAMS_FIXED_SIZE) +typedef struct wl_ext_reassoc_params_v1 { + uint16 version; + uint16 length; + uint32 flags; + wl_reassoc_params_v1_t params; +} wl_ext_reassoc_params_v1_t; + +#define WL_EXTREASSOC_PARAMS_FIXED_SIZE_V1 (OFFSETOF(wl_ext_reassoc_params_v1_t, params) + \ + WL_REASSOC_PARAMS_FIXED_SIZE_V1) /** used for association to a specific BSSID and channel */ typedef wl_assoc_params_t wl_join_assoc_params_t; @@ -1296,10 +1439,8 @@ typedef struct wlc_roam_exp_params { int16 a_band_max_boost; } wlc_roam_exp_params_t; -#define ROAM_EXP_CFG_VERSION 1 - +#define ROAM_EXP_CFG_VERSION_1 1 #define ROAM_EXP_ENABLE_FLAG (1 << 0) - #define ROAM_EXP_CFG_PRESENT (1 << 1) typedef struct wl_roam_exp_cfg { @@ -1315,7 +1456,7 @@ typedef struct wl_bssid_pref_list { int8 flags; } wl_bssid_pref_list_t; -#define BSSID_PREF_LIST_VERSION 1 +#define BSSID_PREF_LIST_VERSION_1 1 #define ROAM_EXP_CLEAR_BSSID_PREF (1 << 0) typedef struct wl_bssid_pref_cfg { @@ -1326,7 +1467,7 @@ typedef struct wl_bssid_pref_cfg { wl_bssid_pref_list_t bssids[]; } wl_bssid_pref_cfg_t; -#define SSID_WHITELIST_VERSION 1 +#define SSID_WHITELIST_VERSION_1 1 #define ROAM_EXP_CLEAR_SSID_WHITELIST (1 << 0) @@ -1343,7 +1484,7 @@ typedef struct wl_ssid_whitelist { wlc_ssid_t ssids[]; } wl_ssid_whitelist_t; -#define ROAM_EXP_EVENT_VERSION 1 +#define ROAM_EXP_EVENT_VERSION_1 1 typedef struct wl_roam_exp_event { @@ -1382,6 +1523,7 @@ typedef struct wl_extjoin_params { typedef struct wl_extjoin_params_v1 { uint16 version; + uint16 PAD; wlc_ssid_t ssid; /**< {0, ""}: wildcard scan */ wl_join_scan_params_t scan; wl_join_assoc_params_v1_t assoc; /**< optional field, but it must include the fixed portion @@ -1401,6 +1543,53 @@ typedef struct { uint8 num_antcfg; /**< number of available antenna configurations */ } wlc_antselcfg_t; +#define WIFI_RADIO_STAT_VERSION_1 (1u) +#define WIFI_RADIO_STAT_VERSION_2 (2u) + +typedef enum wl_radiostats_slice_index { + WL_RADIOSTAT_SLICE_INDEX_MAIN = 0u, + WL_RADIOSTAT_SLICE_INDEX_AUX = 1u, + WL_RADIOSTAT_SLICE_INDEX_SCAN = 2u, + WL_RADIOSTAT_SLICE_INDEX_MAX = 3u +} wl_radiostats_slice_index_t; + +#define WIFI_RADIO_STAT_FIXED_LEN OFFSETOF(wifi_radio_stat, channels) + +typedef struct wifi_radio_stat_v1 { + uint16 version; + uint16 length; + uint32 radio; + uint32 on_time; + uint32 tx_time; + uint32 rx_time; + uint32 on_time_scan; + uint32 on_time_nbd; + uint32 on_time_gscan; + uint32 on_time_roam_scan; + uint32 on_time_pno_scan; + uint32 on_time_hs20; + uint32 num_channels; + uint8 channels[]; +} wifi_radio_stat_v1_t; + +typedef struct wifi_radio_stat_v2 { + uint16 version; + uint16 length; + uint32 radio; + uint32 on_time; + uint32 tx_time; + uint32 rx_time; + uint32 on_time_scan; + uint32 on_time_nbd; + uint32 on_time_gscan; + uint32 on_time_roam_scan; + uint32 on_time_pno_scan; + uint32 on_time_hs20; + uint32 myrx_time; + uint32 num_channels; + uint8 channels[]; +} wifi_radio_stat_v2_t; + /* This is obsolete.Pls add new fields by extending versioned structure. * cca_congest_ext_vX_t [X is latest version] */ @@ -1425,7 +1614,7 @@ typedef struct cca_congest { typedef struct cca_congest_channel_req { chanspec_t chanspec; /**< Which channel? */ uint16 num_secs; /**< How many secs worth of data */ - cca_congest_t secs[1]; /**< Data */ + cca_congest_t secs[BCM_FLEX_ARRAY]; /**< Data */ } cca_congest_channel_req_t; typedef struct cca_congest_ext { @@ -1489,13 +1678,14 @@ typedef struct cca_congest_ext_v2 { #define WL_CCA_EXT_REQ_VER 0u #define WL_CCA_EXT_REQ_VER_V2 2u #define WL_CCA_EXT_REQ_VER_V3 3u +#define WL_CCA_EXT_REQ_VER_V4 4u typedef struct cca_congest_ext_channel_req { - uint16 ver; /**< version of this struct */ - uint16 len; /**< len of this structure */ - chanspec_t chanspec; /**< Which channel? */ - uint16 num_secs; /**< How many secs worth of data */ - struct cca_congest_ext secs[1]; /**< Data - 3 sets for ALL - non-PM - PM */ + uint16 ver; /**< version of this struct */ + uint16 len; /**< len of this structure */ + chanspec_t chanspec; /**< Which channel? */ + uint16 num_secs; /**< How many secs worth of data */ + struct cca_congest_ext secs[BCM_FLEX_ARRAY]; /**< Data - 3 sets for ALL - non-PM - PM */ } cca_congest_ext_channel_req_t; typedef struct cca_congest_ext_channel_req_v2 { @@ -1503,33 +1693,65 @@ typedef struct cca_congest_ext_channel_req_v2 { uint16 len; /**< len of this structure */ chanspec_t chanspec; /**< Which channel? */ uint16 num_secs; /* How many secs worth of data */ - cca_congest_ext_v2_t secs[1]; /* Data - 3 sets for ALL - non-PM - PM */ + cca_congest_ext_v2_t secs[1]; /* Data - 3 sets for ALL - non-PM - PM */ } cca_congest_ext_channel_req_v2_t; -/* Struct holding all channels cca statistics */ +/* Struct holding all channels cca statistics V3 */ typedef struct cca_congest_ext_channel_req_v3 { uint16 ver; uint16 len; uint8 PAD[2]; uint16 num_of_entries; - cca_congest_ext_channel_req_v2_t per_chan_stats[1]; + cca_congest_ext_channel_req_v2_t per_chan_stats[BCM_FLEX_ARRAY]; } cca_congest_ext_channel_req_v3_t; +#define BANDMASK_2G BCM_BIT(0) +#define BANDMASK_5G BCM_BIT(1) +#define BANDMASK_6G BCM_BIT(2) +/* Struct holding all channels cca statistics V4 */ +typedef struct cca_congest_ext_channel_req_v4 { + uint16 ver; + uint16 len; + uint8 bandmask; /* BIT(0)-2G BIT(1)-5G BIT(2)-6G */ + uint8 PAD[1]; + uint16 num_of_entries; + cca_congest_ext_channel_req_v2_t per_chan_stats[BCM_FLEX_ARRAY]; +} cca_congest_ext_channel_req_v4_t; + typedef struct { uint32 duration; /**< millisecs spent sampling this channel */ uint32 congest; /**< millisecs detecting busy CCA */ uint32 timestamp; /**< second timestamp */ } cca_congest_simple_t; +// ED: Energy Detection Thresholds +#define PHY_EDTHRESH_MAX_COUNT 2u /* WLC_API_VERSION_MAJOR >= 17u */ + +// Desense Reasons +#define BPHY_DESENSE_ACI_MASK (1 << 0u) // Desense due to GBD +#define OFDM_DESENSE_ACI_MASK (1 << 1u) +#define BPHY_DESENSE_BTC_MASK (1 << 2u) // Desense due to BT Coex operation +#define OFDM_DESENSE_BTC_MASK (1 << 3u) +#define BPHY_DESENSE_LTE_MASK (1 << 4u) // Desense due to LTE Coex operation +#define OFDM_DESENSE_LTE_MASK (1 << 5u) +#define DESENSE_ON_LTE_MASK (1 << 6u) // Desense due to InitGain or CRS desense +#define DESENSE_ON_BTC_MASK (1 << 7u) + +typedef struct { + int32 ofdm_desense; + int32 bphy_desense; + uint32 reason; /**< bit flags for desense reasons */ +} wl_phy_rxdesense_t; + /* The following two structure must have same first 4 fields. * The cca_chan_qual_event_t is used to report CCA in older formats and NF. * The cca_only_chan_qual_event_t is used to report CCA only with newer format. */ typedef struct { - uint16 status; - uint16 id; + uint16 status; /**< misc status */ + uint16 id; /**< sub-event ID */ chanspec_t chanspec; /**< Which channel? */ - uint16 len; + uint16 len; /**< number of bytes to follow */ union { cca_congest_simple_t cca_busy; /**< CCA busy */ cca_congest_t cca_busy_ext; /**< Extended CCA report */ @@ -1538,10 +1760,10 @@ typedef struct { } cca_chan_qual_event_t; typedef struct { - uint16 status; - uint16 id; + uint16 status; /**< misc status */ + uint16 id; /**< sub-event ID */ chanspec_t chanspec; /**< Which channel? */ - uint16 len; + uint16 len; /**< number of bytes to follow */ union { cca_congest_simple_t cca_busy; /**< CCA busy */ struct { @@ -1553,11 +1775,11 @@ typedef struct { } cca_only_chan_qual_event_t; typedef struct { - uint16 status; /* Indicates the status of event */ - uint16 id; + uint16 status; /**< misc status */ + uint16 id; /**< sub-event ID */ /* id is used to indicate the number of bytes to read */ chanspec_t chanspec; /**< Which channel? */ - uint16 len; + uint16 len; /**< number of bytes to follow */ union { cca_congest_simple_t cca_busy; /**< CCA busy */ struct { @@ -1569,6 +1791,17 @@ typedef struct { int32 ofdm_desense; } cca_only_chan_qual_event_v2_t; +typedef struct { + uint16 status; /**< misc status */ + uint16 id; /**< sub-event ID */ + chanspec_t chanspec; /**< Which channel? */ + uint16 len; /**< number of bytes to follow */ + cca_congest_t cca_busy_ext; /**< Extended CCA report */ + cca_congest_t cca_busy_nopm; /**< Extedned CCA report (PM awake time) */ + cca_congest_t cca_busy_pm; /**< Extedned CCA report (PM sleep time) */ + wl_phy_rxdesense_t desense; /**< PHY RX desense states & reasons */ +} cca_only_chan_qual_event_v3_t; + typedef struct { uint32 msrmnt_time; /**< Time for Measurement (msec) */ uint32 msrmnt_done; /**< flag set when measurement complete */ @@ -1620,7 +1853,7 @@ typedef struct wl_country { */ } wl_country_t; -#define CCODE_INFO_VERSION 1 +#define CCODE_INFO_VERSION_1 1 typedef enum wl_ccode_role { WLC_CCODE_ROLE_ACTIVE = 0, @@ -1643,7 +1876,7 @@ typedef struct wl_ccode_entry { typedef struct wl_ccode_info { uint16 version; uint16 count; /**< Number of ccodes entries in the set */ - wl_ccode_entry_t ccodelist[1]; + wl_ccode_entry_t ccodelist[BCM_FLEX_ARRAY]; } wl_ccode_info_t; #define WL_CCODE_INFO_FIXED_LEN OFFSETOF(wl_ccode_info_t, ccodelist) typedef struct wl_channels_in_country { @@ -1651,7 +1884,7 @@ typedef struct wl_channels_in_country { uint32 band; char country_abbrev[WLC_CNTRY_BUF_SZ]; uint32 count; - uint32 channel[1]; + uint32 channel[BCM_FLEX_ARRAY]; } wl_channels_in_country_t; typedef struct wl_country_list { @@ -1659,7 +1892,7 @@ typedef struct wl_country_list { uint32 band_set; uint32 band; uint32 count; - char country_abbrev[1]; + char country_abbrev[BCM_FLEX_ARRAY]; } wl_country_list_t; typedef struct wl_rm_req_elt { @@ -1673,11 +1906,11 @@ typedef struct wl_rm_req_elt { } wl_rm_req_elt_t; typedef struct wl_rm_req { - uint32 token; /**< overall measurement set token */ - uint32 count; /**< number of measurement requests */ - void *cb; /**< completion callback function: may be NULL */ - void *cb_arg; /**< arg to completion callback function */ - wl_rm_req_elt_t req[1]; /**< variable length block of requests */ + uint32 token; /**< overall measurement set token */ + uint32 count; /**< number of measurement requests */ + void *cb; /**< completion callback function: may be NULL */ + void *cb_arg; /**< arg to completion callback function */ + wl_rm_req_elt_t req[BCM_FLEX_ARRAY]; /**< variable length block of requests */ } wl_rm_req_t; #define WL_RM_REQ_FIXED_LEN OFFSETOF(wl_rm_req_t, req) @@ -1685,12 +1918,12 @@ typedef struct wl_rm_rep_elt { int8 type; int8 flags; chanspec_t chanspec; - uint32 token; /**< token for this measurement */ - uint32 tsf_h; /**< TSF high 32-bits of Measurement start time */ - uint32 tsf_l; /**< TSF low 32-bits */ - uint32 dur; /**< TUs */ - uint32 len; /**< byte length of data block */ - uint8 data[1]; /**< variable length data block */ + uint32 token; /**< token for this measurement */ + uint32 tsf_h; /**< TSF high 32-bits of Measurement start time */ + uint32 tsf_l; /**< TSF low 32-bits */ + uint32 dur; /**< TUs */ + uint32 len; /**< byte length of data block */ + uint8 data[1]; /**< variable length data block */ } wl_rm_rep_elt_t; #define WL_RM_REP_ELT_FIXED_LEN 24 /**< length excluding data block */ @@ -1703,7 +1936,7 @@ typedef struct wl_rm_rpi_rep { typedef struct wl_rm_rep { uint32 token; /**< overall measurement set token */ uint32 len; /**< length of measurement report block */ - wl_rm_rep_elt_t rep[1]; /**< variable length block of reports */ + wl_rm_rep_elt_t rep[BCM_FLEX_ARRAY]; } wl_rm_rep_t; #define WL_RM_REP_FIXED_LEN 8 @@ -1727,10 +1960,32 @@ typedef struct wl_leap_list { uint32 buflen; uint32 version; uint32 count; - wl_leap_info_t leap_info[1]; + wl_leap_info_t leap_info[BCM_FLEX_ARRAY]; } wl_leap_list_t; #endif /* BCMCCX */ +#define WL_SUP_IOV_VERSION_1 0x0001u +enum { + WL_SUP_CMD_NONE = 0, + /* Get SUP IOVAR bersion */ + WL_SUP_CMD_GET_VERSION = 1u, + /* IOVAR to send GTK rekey request */ + WL_SUP_CMD_SEND_GTK_REQ = 2u, + /* Set/Get skip GTK M1 processing state */ + WL_SUP_CMD_IGNORE_GTK_M1 = 3u +}; + +typedef uint16 wl_sup_cmd_t; + +typedef struct wl_sup_iov_v1 { + uint16 version; /* structure version will be incremented + * when header is changed. + */ + uint16 len; /* data field lenth. */ + wl_sup_cmd_t cmd; /* sub-command id. */ + uint8 data[]; /* variable */ +} wl_sup_iov_v1_t; + typedef enum sup_auth_status { /* Basic supplicant authentication states */ WLC_SUP_DISCONNECTED = 0, @@ -1755,24 +2010,28 @@ typedef enum sup_auth_status { WLC_SUP_KEYXCHANGE_PREP_G2 /**< Preparing to send handshake msg G2 */ } sup_auth_status_t; +#define WLC_SUP_TD_POLICY_XTLV_ID 0x1u +#define WLC_SUP_TD_POLICY_XTLV_ELEM_SIZE 0x4u /* 4B aligned */ +#define WLC_SUP_TD_POLICY_XTLV_SIZE (BCM_XTLV_HDR_SIZE + WLC_SUP_TD_POLICY_XTLV_ELEM_SIZE) + typedef struct wl_wsec_key { uint32 index; /**< key index */ uint32 len; /**< key length */ uint8 data[DOT11_MAX_KEY_SIZE]; /**< key data */ - uint32 pad_1[18]; + uint32 PAD[18]; uint32 algo; /**< CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ uint32 flags; /**< misc flags */ - uint32 pad_2[2]; - int32 pad_3; + uint32 PAD[2]; + int32 PAD; int32 iv_initialized; /**< has IV been initialized already? */ - int32 pad_4; + int32 PAD; /* Rx IV */ struct { uint32 hi; /**< upper 32 bits of IV */ uint16 lo; /**< lower 16 bits of IV */ uint16 PAD; } rxiv; - uint32 pad_5[2]; + uint32 PAD[2]; struct ether_addr ea; /**< per station */ uint16 PAD; } wl_wsec_key_t; @@ -1794,11 +2053,11 @@ typedef struct wl_wsec_key { /**receptacle for WLC_SET_WSEC_PMK parameter */ typedef struct wsec_pmk { - ushort key_len; /* octets in key material */ - ushort flags; /* key handling qualification */ + uint16 key_len; /* octets in key material */ + uint16 flags; /* key handling qualification */ uint8 key[WSEC_MAX_PASSPHRASE_LEN]; /* PMK material */ - uint16 opt_len; /* optional field length */ - uint8 opt_tlvs[1]; /* optional filed in bcm_xtlv_t format */ + uint16 opt_len; /* optional field length */ + uint8 opt_tlvs[BCM_FLEX_ARRAY]; /* optional filed in bcm_xtlv_t format */ } wsec_pmk_t; typedef enum { @@ -1811,10 +2070,10 @@ typedef enum { #define WL_AUTH_EVENT_DATA_V2 0x2 /* tlv ids for auth event */ -#define WL_AUTH_PMK_TLV_ID 1u +#define WL_AUTH_PMK_TLV_ID 1u #define WL_AUTH_PMKID_TLV_ID 2u #define WL_AUTH_PMKID_TYPE_TLV_ID 3u -#define WL_AUTH_SSID_TLV_ID 4u +#define WL_AUTH_SSID_TLV_ID 4u #define WL_AUTH_PMKID_TYPE_BSSID 1u #define WL_AUTH_PMKID_TYPE_SSID 2u @@ -1852,20 +2111,21 @@ typedef struct wl_pmksa_event { typedef struct _pmkid_v1 { struct ether_addr BSSID; - uint8 PMKID[WPA2_PMKID_LEN]; + uint8 PMKID[WPA2_PMKID_LEN]; } pmkid_v1_t; #define PMKID_ELEM_V2_LENGTH (sizeof(struct ether_addr) + WPA2_PMKID_LEN + PMK_LEN_MAX + \ sizeof(ssid_info_t) + FILS_CACHE_ID_LEN) typedef struct _pmkid_v2 { - uint16 length; /* Should match PMKID_ELEM_VX_LENGTH */ + uint16 length; /* Should match PMKID_ELEM_VX_LENGTH */ struct ether_addr BSSID; - uint8 PMKID[WPA2_PMKID_LEN]; - uint8 pmk[PMK_LEN_MAX]; /* for FILS key deriviation */ - uint16 pmk_len; - ssid_info_t ssid; - uint8 fils_cache_id[FILS_CACHE_ID_LEN]; + uint8 PMKID[WPA2_PMKID_LEN]; + uint8 pmk[PMK_LEN_MAX]; /* for FILS key deriviation */ + uint16 pmk_len; + ssid_info_t ssid; + uint8 fils_cache_id[FILS_CACHE_ID_LEN]; + uint8 PAD; } pmkid_v2_t; #define PMKID_LIST_VER_2 2 @@ -1888,33 +2148,28 @@ typedef struct _pmkid_v3 { #define PMKID_LIST_VER_3 3 typedef struct _pmkid_list_v1 { uint32 npmkid; - pmkid_v1_t pmkid[1]; + pmkid_v1_t pmkid[BCM_FLEX_ARRAY]; } pmkid_list_v1_t; typedef struct _pmkid_list_v2 { uint16 version; uint16 length; - pmkid_v2_t pmkid[1]; + pmkid_v2_t pmkid[BCM_FLEX_ARRAY]; } pmkid_list_v2_t; -#define PMKDB_SET_IOVAR 1u -#define PMKDB_GET_IOVAR 2u -#define PMKDB_CLEAR_IOVAR 4u +#define PMKDB_SET_IOVAR 0x0001u +#define PMKDB_GET_IOVAR 0x0002u +#define PMKDB_CLEAR_IOVAR 0x0004u +#define PMKDB_ALL_CFGS 0x0008u /* option for PMKDB_GET_IOVAR */ typedef struct _pmkid_list_v3 { uint16 version; uint16 length; uint16 count; - uint16 flag; + uint16 flag; pmkid_v3_t pmkid[]; } pmkid_list_v3_t; -#ifndef PMKID_VERSION_ENABLED -/* pmkid structure before versioning. legacy. DONOT update anymore here */ -typedef pmkid_v1_t pmkid_t; -typedef pmkid_list_v1_t pmkid_list_t; -#endif /* PMKID_VERSION_ENABLED */ - typedef struct _pmkid_cand { struct ether_addr BSSID; uint8 preauth; @@ -1922,7 +2177,7 @@ typedef struct _pmkid_cand { typedef struct _pmkid_cand_list { uint32 npmkid_cand; - pmkid_cand_t pmkid_cand[1]; + pmkid_cand_t pmkid_cand[BCM_FLEX_ARRAY]; } pmkid_cand_list_t; #define WL_STA_ANT_MAX 4 /**< max possible rx antennas */ @@ -2304,13 +2559,13 @@ typedef struct sta_info_v7 { */ #define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_tot_pkts) -#define WL_STA_VER_4 4 -#define WL_STA_VER_5 5 -/* FIXME: the user/branch should make the selection! */ -#define WL_STA_VER WL_STA_VER_4 +#define WL_STA_VER_4 4u +#define WL_STA_VER_5 5u +#define WL_STA_VER_6 6u +#define WL_STA_VER_7 7u -#define SWDIV_STATS_VERSION_2 2 -#define SWDIV_STATS_CURRENT_VERSION SWDIV_STATS_VERSION_2 +#define SWDIV_STATS_VERSION_1 1u +#define SWDIV_STATS_VERSION_2 2u struct wlc_swdiv_stats_v1 { uint32 auto_en; @@ -2348,8 +2603,8 @@ struct wlc_swdiv_stats_v1 { struct wlc_swdiv_stats_v2 { uint16 version; /* version of the structure - * as defined by SWDIV_STATS_CURRENT_VERSION - */ + * as defined by SWDIV_STATS_CURRENT_VERSION + */ uint16 length; /* length of the entire structure */ uint32 auto_en; uint32 active_ant; @@ -2408,8 +2663,8 @@ typedef struct channel_info { /** For ioctls that take a list of MAC addresses */ typedef struct maclist { - uint32 count; /**< number of MAC addresses */ - struct ether_addr ea[1]; /**< variable length array of MAC addresses */ + uint32 count; /**< number of MAC addresses */ + struct ether_addr ea[BCM_FLEX_ARRAY]; /**< variable length array of MAC addresses */ } maclist_t; typedef struct wds_client_info { @@ -2422,10 +2677,10 @@ typedef struct wds_client_info { /* For wds MAC list ioctls */ typedef struct wds_maclist { - uint32 count; /* Number of WDS clients */ - uint32 magic; /* Magic number */ - uint32 version; /* Version number */ - struct wds_client_info client_list[1]; /* Variable length array of WDS clients */ + uint32 count; /* Number of WDS clients */ + uint32 magic; /* Magic number */ + uint32 version; /* Version number */ + struct wds_client_info client_list[BCM_FLEX_ARRAY]; /* Var len array of WDS clients */ } wds_maclist_t; /**get pkt count struct passed through ioctl */ @@ -2505,6 +2760,7 @@ typedef struct wl_ioctl { void *buf; /**< pointer to user buffer */ uint32 len; /**< length of user buffer */ uint8 set; /**< 1=set IOCTL; 0=query IOCTL */ + uint8 PAD[3]; uint32 used; /**< bytes read or written (optional) */ uint32 needed; /**< bytes needed (optional) */ } wl_ioctl_t; @@ -2515,6 +2771,7 @@ typedef struct compat_wl_ioctl { uint32 buf; /**< pointer to user buffer */ uint32 len; /**< length of user buffer */ uint8 set; /**< 1=set IOCTL; 0=query IOCTL */ + uint8 PAD[3]; uint32 used; /**< bytes read or written (optional) */ uint32 needed; /**< bytes needed (optional) */ } compat_wl_ioctl_t; @@ -2527,7 +2784,7 @@ typedef struct compat_wl_ioctl { #define WL_NUM_RATES_VHT 10 #define WL_NUM_RATES_VHT_ALL (WL_NUM_RATES_VHT + WL_NUM_RATES_EXTRA_VHT) #define WL_NUM_RATES_HE 12 -#define WL_NUM_RATES_EHT 14 +#define WL_NUM_RATES_EHT 16u #define WL_NUM_RATES_MCS32 1 #define UC_PATH_LEN 128u /**< uCode path length */ @@ -2676,6 +2933,7 @@ enum wl_macfifo_play_flags { WL_MACFIFO_PLAY_LOAD = 0x02u, /* for set: load samples for get: samples are loaded */ + WL_MACFIFO_PLAY_CAL = 0x08u, /* macfifo play for calibration */ WL_MACFIFO_PLAY_GET_MAX_SIZE = 0x10u, /* get the macfifo buffer size */ WL_MACFIFO_PLAY_GET_STATUS = 0x20u, /* get macfifo play status */ }; @@ -2894,7 +3152,7 @@ typedef struct stamon_data { typedef struct stamon_info { int32 version; uint32 count; - stamon_data_t sta_data[1]; + stamon_data_t sta_data[BCM_FLEX_ARRAY]; } stamon_info_t; typedef struct wl_ota_rx_rssi { @@ -2907,9 +3165,9 @@ typedef struct wl_ota_rx_rssi { #define WL_OTA_TEST_RSSI_FIXED_SIZE OFFSETOF(wl_ota_test_rssi_t, rx_rssi) typedef struct wl_ota_test_rssi { - uint8 version; - uint8 testcnt; /* total measured RSSI values, valid on output only */ - wl_ota_rx_rssi_t rx_rssi[1]; /* Variable length array of wl_ota_rx_rssi_t */ + uint8 version; + uint8 testcnt; /* total RSSI values, valid on o/p only */ + wl_ota_rx_rssi_t rx_rssi[BCM_FLEX_ARRAY]; /* Variable len array */ } wl_ota_test_rssi_t; /* WL_OTA END */ @@ -2953,7 +3211,7 @@ typedef struct { uint8 PAD[2]; } wl_radar_args_t; -#define WL_RADAR_ARGS_VERSION 2 +#define WL_RADAR_ARGS_VERSION_2 2 typedef struct { uint32 version; /**< version */ @@ -3023,11 +3281,18 @@ typedef struct { /* SNR per antenna */ typedef struct { - uint32 version; /* version field */ - uint32 count; /* number of valid antenna snr */ + uint32 version; /* version field */ + uint32 count; /* number of valid antenna snr */ int8 snr_ant[WL_RSSI_ANT_MAX]; /* snr per antenna */ } wl_snr_ant_t; +/* Noise per antenna */ +typedef struct { + uint32 version; /* version field */ + uint32 count; /* number of valid antenna NF */ + int8 noise_ant[WL_RSSI_ANT_MAX]; /* NF per antenna */ +} wl_noise_ant_t; + /* Weighted average support */ #define WL_WA_VER 0 /* Initial version - Basic WA algorithm only */ @@ -3061,7 +3326,7 @@ typedef struct { */ chanspec_t chanspec_cleared; /** chanspec cleared used to be a uint32, add another to uint16 to maintain size */ - uint16 pad; + uint16 PAD; } wl_dfs_status_t; typedef struct { @@ -3070,14 +3335,14 @@ typedef struct { chanspec_t chanspec; /* chanspec of this core */ chanspec_t chanspec_last_cleared; /* chanspec last cleared for operation by scanning */ uint16 sub_type; /* currently just the index of the core or the respective PLL */ - uint16 pad; + uint16 PAD; } wl_dfs_sub_status_t; #define WL_DFS_STATUS_ALL_VERSION (1) typedef struct { uint16 version; /* version field; current max version 1 */ uint16 num_sub_status; - wl_dfs_sub_status_t dfs_sub_status[1]; /* struct array of length num_sub_status */ + wl_dfs_sub_status_t dfs_sub_status[BCM_FLEX_ARRAY]; /* Array of len num_sub_status */ } wl_dfs_status_all_t; #define WL_DFS_AP_MOVE_VERSION (1) @@ -3172,23 +3437,30 @@ typedef struct { chanspec_t chanspec; /**< txpwr report for this channel */ chanspec_t local_chanspec; /**< channel on which we are associated */ uint32 buflen; /**< ppr buffer length */ - uint8 pprbuf[1]; /**< Latest target power buffer */ + uint8 pprbuf[BCM_FLEX_ARRAY]; /**< Latest target power buffer */ } wl_txppr_t; #define WL_TXPPR_VERSION 1 #define WL_TXPPR_LENGTH (sizeof(wl_txppr_t)) #define TX_POWER_T_VERSION 45 #define TX_POWER_T_VERSION_V2 46 +#define TX_POWER_T_VERSION_V3 47 /* curpower ppr types */ enum { - PPRTYPE_TARGETPOWER = 1, - PPRTYPE_BOARDLIMITS = 2, - PPRTYPE_REGLIMITS = 3, - PPRTYPE_RU_REGLIMITS = 4, - PPRTYPE_RU_BOARDLIMITS = 5, - PPRTYPE_RU_TARGETPOWER = 6, - PPRTYPE_DYNAMIC_INFO = 7, + PPRTYPE_TARGETPOWER = 1u, + PPRTYPE_BOARDLIMITS = 2u, + PPRTYPE_REGLIMITS = 3u, + PPRTYPE_RU_REGLIMITS = 4u, + PPRTYPE_RU_BOARDLIMITS = 5u, + PPRTYPE_RU_TARGETPOWER = 6u, + PPRTYPE_DYNAMIC_INFO = 7u, + PPRTYPE_TGT_PWR_PSU = 8u, + PPRTYPE_BOARDLIMITS_PSU = 9u, + PPRTYPE_REGLIMITS_PSU = 10u, + PPRTYPE_TGT_PWR_MRU = 11u, + PPRTYPE_BOARDLIMITS_MRU = 12u, + PPRTYPE_REGLIMITS_MRU = 13u, PPRTYPE_LAST }; @@ -3197,15 +3469,15 @@ enum { typedef struct chanspec_txpwr_max { chanspec_t chanspec; /**< chanspec */ - uint8 txpwr_max; /**< max txpwr in all the rates */ - uint8 padding; + int8 txpwr_max; /**< max txpwr in all the rates */ + uint8 txpwr_cat; /**< txpwr category for 6g */ } chanspec_txpwr_max_t; typedef struct wl_chanspec_txpwr_max { - uint16 ver; /**< version of this struct */ - uint16 len; /**< length in bytes of this structure */ - uint32 count; /**< number of elements of (chanspec, txpwr_max) pair */ - chanspec_txpwr_max_t txpwr[1]; /**< array of (chanspec, max_txpwr) pair */ + uint16 ver; /**< version of this struct */ + uint16 len; /**< length in bytes of this structure */ + uint32 count; /**< number of (chanspec, txpwr_max) pair */ + chanspec_txpwr_max_t txpwr[BCM_FLEX_ARRAY]; /**< array of (chanspec, max_txpwr) pair */ } wl_chanspec_txpwr_max_t; #define WL_CHANSPEC_TXPWR_MAX_VER 1 @@ -3217,6 +3489,10 @@ typedef struct tx_inst_power { } tx_inst_power_t; #define WL_NUM_TXCHAIN_MAX 4 +#if WL_NUM_TXCHAIN_MAX > 4 +#error "WL_NUM_TXCHAIN_MAX is exceeded more than MCSSQSNR defs (4)" +#endif + typedef struct wl_txchain_pwr_offsets { int8 offset[WL_NUM_TXCHAIN_MAX]; /**< quarter dBm signed offset for each chain */ } wl_txchain_pwr_offsets_t; @@ -3237,7 +3513,7 @@ typedef struct wl_mimops_cfg { /* bandwidth = Full (0), 20M (1), 40M (2), 80M (3). */ uint8 bandwidth; uint8 applychangesafterlearning; - uint8 pad[3]; + uint8 PAD[3]; } wl_mimops_cfg_t; /* This event is for tracing MIMO PS metrics snapshot calls. @@ -3312,7 +3588,7 @@ typedef struct wl_mimo_ps_status_v1 { uint8 hw_rxchain; /* actual HW rxchain bitmask */ uint8 hw_txchain; /* actual HW txchain bitmask */ uint8 hw_bw; /* bandwidth: Full (0), 20M (1), 40M (2), 80M (3), etc */ - uint8 pad[3]; + uint8 PAD[3]; } wl_mimo_ps_status_v1_t; #define WL_MIMO_PS_STATUS_AP_CAP(ap_cap) (ap_cap & 0x0F) @@ -3347,10 +3623,6 @@ enum { #define WL_MIMO_PS_STATUS_HW_STATE_LTECOEX (0x1 << 0) #define WL_MIMO_PS_STATUS_HW_STATE_MIMOPS_BSS (0x1 << 1) -#ifdef WLAWDL -#define WL_MIMO_PS_STATUS_HW_STATE_AWDL_BSS (0x1 << 2) -#endif /* WLAWDL */ - #define WL_MIMO_PS_STATUS_HW_STATE_SCAN (0x1 << 3) #define WL_MIMO_PS_STATUS_HW_STATE_TXPPR (0x1 << 4) #define WL_MIMO_PS_STATUS_HW_STATE_PWRTHOTTLE (0x1 << 5) @@ -3405,50 +3677,131 @@ typedef struct wl_mimops_learning_cfg { wl_mimo_ps_learning_event_data_t mimops_learning_data; } wl_mimops_learning_cfg_t; -#define WL_OCL_STATUS_VERSION 1 +/* ocl status is reported per slice */ +#define WL_OCL_STATUS_VERSION_1 1 typedef struct ocl_status_info { uint8 version; uint8 len; - uint16 fw_status; /* Bits representing FW disable reasons */ - uint8 hw_status; /* Bits for actual HW config and SISO/MIMO coremask */ - uint8 coremask; /* The ocl core mask (indicating listening core) */ + uint16 fw_status; /* Bits representing FW disable reasons */ + uint8 hw_status; /* Bits for actual HW config and SISO/MIMO coremask */ + uint8 coremask; /* The ocl core mask (indicating listening core) */ } ocl_status_info_t; +#define WL_OCL_STATUS_VERSION_2 2 /* v2 supports disable stats */ +typedef struct ocl_status_info_v2 { + uint8 version; + uint8 len; + uint8 hw_status; /* Bits for actual HW config and SISO/MIMO coremask */ + uint8 coremask; /* The ocl core mask (indicating listening core) */ + uint32 fw_status; /* Bits representing FW disable reasons */ + uint32 disable_start_req; /* disable reason which triggered the ocl state change + * from enable to disable, afterwards there could be more + * disable reason(s) active before ocl state is enabled + * again. All current disable reason(s) are + * indicated in fw_status and at snapshot maynot include + * the disable reason which actually triggered ocl disable + * as reasons become active/inactive independently. + */ + uint32 enable_start_req; /* disable reason which triggered the ocl state change + * from disable to enable. This is the reason which very + * recently turned off which caused the ocl to enable. + */ + uint32 cur_ts; /* current timestamp (ms) */ + uint32 disable_start_ts; /* disable_start_req timestamp (ms) */ + uint32 enable_start_ts; /* enable_start_req timestamp (ms) */ + uint32 disable_count_as; /* total effective-disable (i.e., ocl state changing + * from enable-to-disable) count since last assoc + */ + uint32 disable_reqs_count_as; /* total disable requests since last assoc */ + uint32 disable_dur_as; /* total disable duration (ms) since last assoc */ + uint32 disable_count; /* total effective-disable count */ + uint32 disable_reqs_count; /* total disable requests */ + uint32 disable_dur; /* total disable duration (ms) */ +} ocl_status_info_v2_t; + +/* v3 shows per-chanspec OCL status, active link type + * on that chanspec, and user's ocl configuration + */ +#define WL_OCL_STATUS_VERSION_3 3 +typedef struct ocl_status_info_v3 { + uint8 version; + uint8 len; + uint8 hw_status; /* Bits for actual HW config and SISO/MIMO coremask */ + uint8 coremask; /* The ocl core mask (indicating listening core) */ + uint32 fw_status; /* Bits representing FW disable reasons */ + uint32 disable_start_req; /* disable reason which triggered the ocl state change + * from enable to disable, afterwards there could be more + * disable reason(s) active before ocl state is enabled + * again. All current disable reason(s) are + * indicated in fw_status and at snapshot maynot include + * the disable reason which actually triggered ocl disable + * as reasons become active/inactive independently. + */ + uint32 enable_start_req; /* disable reason which triggered the ocl state change + * from disable to enable. This is the reason which very + * recently turned off which caused the ocl to enable. + */ + uint32 cur_ts; /* current timestamp (ms) */ + uint32 disable_start_ts; /* disable_start_req timestamp (ms) */ + uint32 enable_start_ts; /* enable_start_req timestamp (ms) */ + uint32 disable_count_as; /* total effective-disable (i.e., ocl state changing + * from enable-to-disable) count since last assoc + */ + uint32 disable_reqs_count_as; /* total disable requests since last assoc */ + uint32 disable_dur_as; /* total disable duration (ms) since last assoc */ + uint32 disable_count; /* total effective-disable count */ + uint32 disable_reqs_count; /* total disable requests */ + uint32 disable_dur; /* total disable duration (ms) */ + uint16 chanspec; /* chanspec on which ocl_status is reported */ + uint8 active_link; /* Bits showing which link is active */ + uint8 ocl_en; /* user's configuation */ +} ocl_status_info_v3_t; + +#define OCL_SET_INFRA (1u << 0u) /* host OCL enable/disable for INFRA */ +#define OCL_SET_NAN (1u << 1u) /* host OCL enable/disable for NAN */ +#define OCL_SET_AWDL (1u << 2u) /* host OCL enable/disable for AWDL */ + /* MWS OCL map */ -#define WL_MWS_OCL_OVERRIDE_VERSION 1 +#define WL_MWS_OCL_OVERRIDE_VERSION_1 1 typedef struct wl_mws_ocl_override { - uint16 version; /* Structure version */ - uint16 bitmap_2g; /* bitmap for 2.4G channels bits 1-13 */ - uint16 bitmap_5g_lo; /* bitmap for 5G low channels by 2: - *34-48, 52-56, 60-64, 100-102 - */ - uint16 bitmap_5g_mid; /* bitmap for 5G mid channels by 2: - * 104, 108-112, 116-120, 124-128, - * 132-136, 140, 149-151 - */ - uint16 bitmap_5g_high; /* bitmap for 5G high channels by 2 - * 153, 157-161, 165 - */ + uint16 version; /* Structure version */ + uint16 bitmap_2g; /* bitmap for 2.4G channels bits 1-13 */ + uint16 bitmap_5g_lo; /* bitmap for 5G low channels by 2: + * 34-48, 52-56, 60-64, 100-102 + */ + uint16 bitmap_5g_mid; /* bitmap for 5G mid channels by 2: + * 104, 108-112, 116-120, 124-128, + * 132-136, 140, 149-151 + */ + uint16 bitmap_5g_high; /* bitmap for 5G high channels by 2 + * 153, 157-161, 165 + */ } wl_mws_ocl_override_t; -/* Bits for fw_status */ -#define OCL_DISABLED_HOST 0x01 /* Host has disabled through ocl_enable */ -#define OCL_DISABLED_RSSI 0x02 /* Disabled because of ocl_rssi_threshold */ -#define OCL_DISABLED_LTEC 0x04 /* Disabled due to LTE Coex activity */ -#define OCL_DISABLED_SISO 0x08 /* Disabled while in SISO mode */ -#define OCL_DISABLED_CAL 0x10 /* Disabled during active calibration */ -#define OCL_DISABLED_CHANSWITCH 0x20 /* Disabled during active channel switch */ -#define OCL_DISABLED_ASPEND 0x40 /* Disabled due to assoc pending */ -#define OCL_DISABLED_SEQ_RANGE 0x80 /* Disabled during SEQ Ranging */ -#define OCL_DISABLED_RXIQ_EST_BTLOWAR 0x100 /* Disabled if the bt-lo-war is active */ -#define OCL_DISABLED_IDLE_TSSICAL 0x200 -#define OCL_DISABLED_TONE 0x400 /* Disabled if the tone is active */ -#define OCL_DISABLED_NOISECAL 0x800 /* Disabled if the noise cal is active */ +/* Bits for fw_status and disable/enable start request */ +#define OCL_DISABLED_HOST (1u << 0u) /* Disabled by host through ocl_enable */ +#define OCL_DISABLED_RSSI (1u << 1u) /* Disabled because of ocl_rssi_threshold */ +#define OCL_DISABLED_LTEC (1u << 2u) /* Disabled due to LTE Coex activity */ +#define OCL_DISABLED_SISO (1u << 3u) /* Disabled while in SISO mode */ +#define OCL_DISABLED_CAL (1u << 4u) /* Disabled during active calibration */ +#define OCL_DISABLED_CHANSWITCH (1u << 5u) /* Disabled during channel switch */ +#define OCL_DISABLED_ASPEND (1u << 6u) /* Disabled due to assoc pending */ +#define OCL_DISABLED_SEQ_RANGE (1u << 7u) /* Disabled during SEQ Ranging */ +#define OCL_DISABLED_RXIQ_EST_BTLOWAR (1u << 8u) /* Disabled if the bt-lo-war is active */ +#define OCL_DISABLED_IDLE_TSSICAL (1u << 9u) /* Disabled if TSSI Cal in progress */ +#define OCL_DISABLED_TONE (1u << 10u) /* Disabled if the tone is active */ +#define OCL_DISABLED_NOISECAL (1u << 11u) /* Disabled if the noise cal is active */ +#define OCL_DISABLED_INIT (1u << 12u) /* Disabled during phy init */ +#define OCL_DISABLED_AZ (1u << 13u) /* Disabled during 802.11az ranging */ +#define OCL_DISABLED_PHYTS (1u << 14u) /* Disabled during PHYTS */ +#define OCL_DISABLED_SCPEND (1u << 15u) /* Disabled due to scan pending */ +#define OCL_DISABLED_EMLSR (1u << 16u) /* Disabled due to EMLSR enabled */ +#define OCL_DISABLED_BTBPHYWAR (1u << 17u) /* Disabled during BT eSCO traffic */ /* Bits for hw_status */ -#define OCL_HWCFG 0x01 /* State of OCL config bit in phy HW */ -#define OCL_HWMIMO 0x02 /* Set if current coremask is > 1 bit */ -#define OCL_COREDOWN 0x80 /* Set if core is currently down */ +#define OCL_HWCFG 0x01u /* State of OCL config bit in phy HW */ +#define OCL_HWMIMO 0x02u /* Set if current coremask is > 1 bit */ +#define OCL_COREDOWN 0x80u /* Set if core is currently down */ #define WL_OPS_CFG_VERSION_1 1 /* Common IOVAR struct */ @@ -3539,6 +3892,7 @@ typedef struct wl_ops_status_v1 { #define OPS_DISABLED_UNASSOC 0x02 /* Disabled because the slice is in unassociated state */ #define OPS_DISABLED_SCAN 0x04 /* Disabled because the slice is in scan state */ #define OPS_DISABLED_BCN_MISS 0x08 /* Disabled because beacon missed for a duration */ +#define OPS_DISABLED_OBSS_MMT 0x10 /* Disabled because of OBSS measurement */ #define WL_PSBW_CFG_VERSION_1 1 /* Common IOVAR struct */ @@ -3663,6 +4017,7 @@ enum { /* Bit value for DVFS status */ #define DVFS_STATUS_LDV 0u #define DVFS_STATUS_NDV 1u +#define DVFS_STATUS_HDV 3u /* DVFS bits are for status, raw request and active request */ /* 4387b0 supports only status bits for aux, main, and bt */ /* 4387c0 supports all eight status and request bits */ @@ -3706,6 +4061,9 @@ enum { #define DVFS_BIT_SYSMEM_SHIFT 9u #define DVFS_BIT_SYSMEM_VAL(_val) (((_val) & DVFS_BIT_SYSMEM_MASK) \ >> DVFS_BIT_SYSMEM_SHIFT) + +#define DVFS_BIT_SAQM_SHIFT 10u + /* to convert voltage to volt from multiple of 10mVolt */ #define DVFS_CONVERT_TO_VOLT 100u @@ -3721,7 +4079,7 @@ typedef struct dvfs_status_v1 { uint32 ldv_duration; /* total time (ms) in LDV */ uint32 ndv_duration; /* total time (ms) in NDV */ uint16 status; /* status bits */ - uint16 pad; /* word aligned for size */ + uint16 PAD; /* word aligned for size */ } dvfs_status_v1_t; #define DVFS_STATUS_VER_1_LEN (sizeof(dvfs_status_v1_t)) /* status version for 4387c0 */ @@ -3746,6 +4104,113 @@ typedef struct dvfs_status_v2 { #define DVFS_STATUS_VER_3_LEN (sizeof(dvfs_status_v2_t)) #define DVFS_STATUS_VER_2_LEN (DVFS_STATUS_VER_3_LEN - (sizeof(uint16))) +#define DVFS_STATUS_VERSION_4 4 +typedef struct dvfs_status_v4 { + uint16 version; /* version of dvfs_status */ + uint16 len; /* total length including all fixed fields */ + uint8 info; /* current dvfs state request and status */ + uint8 voltage; /* voltage (multiple of 10mV) */ + uint16 freq; /* arm clock frequency (in MHz) */ + uint32 state_change_count; /* total state (LDV/NDV) transition count */ + uint32 ldv_duration; /* total time (ms) in LDV */ + uint32 ndv_duration; /* total time (ms) in NDV */ + uint16 status; /* status bits */ + uint16 raw_request; /* raw request bits */ + uint16 active_request; /* active request bits */ + /* DVFS_STATUS_VERSION_3 for pmurev >= 40 */ + uint16 valid_cores; /* bitmap to indicate valid cores status */ + /* DVFS_STATUS_VERSION_4 for pmurev >= 43 */ + uint32 state_change_count_hw_ldv; /* total state (LDV/NDV) transition count by HW */ + uint32 state_change_count_hw_ndv; /* total state (LDV/NDV) transition count by HW */ + uint32 ldv_duration_hw; /* total time (ms) in LDV reported by HW */ + uint32 ndv_duration_hw; /* total time (ms) in NDV reported by HW */ +} dvfs_status_v4_t; +#define DVFS_STATUS_VER_4_LEN (sizeof(dvfs_status_v4_t)) + +typedef struct dvfs_supply_stats_v5 { + uint16 version; + uint16 len; + + uint16 supply_num; /* Supply num that has this dvfs supply stats. */ + uint8 dvfs_status; /* current dvfs status LDV/NDV/HDV */ + uint8 voltage; /* voltage (multiple of 10mV) */ + + uint32 state_change_count; /* total state (LDV/NDV) transition count */ + + uint32 fw_ldv_duration; /* total time (ms) in LDV */ + uint32 hw_ldv_duration; /* total time (ms) in LDV reported by HW */ + uint32 state_change_count_hw_ldv; /* HDV transition count by HW */ + + uint32 fw_ndv_duration; /* total time (ms) in LDV */ + uint32 hw_ndv_duration; /* total time (ms) in LDV reported by HW */ + uint32 state_change_count_hw_ndv; /* HDV transition count by HW */ + + uint32 fw_hdv_duration; /* total time (ms) in LDV */ + uint32 hw_hdv_duration; /* total time (ms) in LDV reported by HW */ + uint32 state_change_count_hw_hdv; /* HDV transition count by HW */ +} dvfs_supply_stats_v5_t; + +#define DVFS_STATUS_CORE_NAME_MASK 0x3Fu +#define DVFS_STATUS_CORE_NAME_SHIFT 0u +#define DVFS_STATUS_CORE_STATUS_MASK 0x3u +#define DVFS_STATUS_CORE_STATUS_SHIFT 0x6u +#define DVFS_STATUS_CORE_ACTIVE_REQ_MASK 0x3u +#define DVFS_STATUS_CORE_ACTIVE_REQ_SHIFT 8u +#define DVFS_STATUS_CORE_RAW_REQ_MASK 0x3u +#define DVFS_STATUS_CORE_RAW_REQ_SHIFT 10u +#define DVFS_STATUS_CORE_SUPPLY_NUM_MASK 0x3u +#define DVFS_STATUS_CORE_SUPPLY_NUM_SHIFT 12u + +typedef struct dvfs_core_info_v5 { + uint16 version; + uint16 len; + uint8 num_cores; + uint8 PAD; + uint16 powercontrol; /* PowerControl from chipcommon */ + uint16 dvfs_core_stats[]; /* Per core statistics, + * BITs 5:0 dvfs_core_name + * BITs 7:6 DVFS Status + * BITs 9:8 Active Request + * BITs 11:10 RAW Request + * BITs 13:12 Supply Num + * BIT 14:14 if set CoreReady rsrc is active + * BITs 15 reserved + */ +} dvfs_core_info_v5_t; + +typedef struct dvfs_freq_info_v5 { + uint16 version; + uint16 len; + uint32 freq_common_bp; + uint32 freq_wlan_bp; + uint32 freq_main_mac; + uint32 freq_aux_mac; + uint32 freq_scan_mac; + uint32 freq_saqm; +} dvfs_freq_info_v5_t; + +typedef enum dvfs_tlv_id { + DVFS_SUPPLY_STATS_ID = 0u, + DVFS_CORE_STATUS_ID = 1u, + DVFS_FREQ_STATS_ID = 2u, + DVFS_XTLV_MAX = 3u +} dvfs_tlv_id_s; + +#define DVFS_STATUS_CORE_INFO_VER 0 +#define DVFS_STATUS_FREQ_INFO_VER 0 +#define DVFS_STATUS_VERSION_5 5 + +typedef struct dvfs_status_v5 { + uint16 version; /* version of dvfs_status */ + uint16 len; /* total length including all fixed fields */ + + uint16 armfreq; /* arm clock frequency (in MHz) */ + uint16 num_dvfs_supplies; /* Total number of supplies */ + uint8 tlv_params[]; /* xtlvs for variable ext params, id dvfs_tlv_id_s */ + +} dvfs_status_v5_t; +#define DVFS_STATUS_VER_5_LEN (sizeof(dvfs_status_v5_t)) + /* DVFS_SUBCMD_HIST */ #define DVFS_HIST_CMD_VERSION_1 1 typedef struct dvfs_hist_cmd_v1 { @@ -3777,6 +4242,7 @@ typedef struct dvfs_hist_v1 { #define WL_DVFS_REASON_ASSOC 0x0800u /* ASSOC */ #define WL_DVFS_REASON_WD 0x1000u /* WD */ #define WL_DVFS_REASON_SOFTAP 0x2000u /* SoftAP */ +#define WL_DVFS_REASON_PHYBW 0x4000u /* Channel BW Change */ /* * Join preference iovar value is an array of tuples. Each tuple has a one-byte type, @@ -3837,10 +4303,22 @@ struct tsinfo_arg { #define RATE_LEGACY_OFDM_48MBPS 6 #define RATE_LEGACY_OFDM_54MBPS 7 -#define WL_BSSTRANS_RSSI_RATE_MAP_VERSION 1 -#define WL_BSSTRANS_RSSI_RATE_MAP_VERSION_V1 1 -#define WL_BSSTRANS_RSSI_RATE_MAP_VERSION_V2 2 -#define WL_BSSTRANS_RSSI_RATE_MAP_VERSION_V3 3 +#define WL_BSSTRANS_RSSI_RATE_MAP_VERSION_V1 1 +#define WL_BSSTRANS_RSSI_RATE_MAP_VERSION_V2 2 +#define WL_BSSTRANS_RSSI_RATE_MAP_VERSION_V3 3 +#define WL_BSSTRANS_RSSI_RATE_MAP_VERSION_V4 4 + +#define WL_BSSTRANS_RSSI_VERSION_V1 1u + +#ifdef WL_BAND6G +#define MAXBANDS 3 /**< Maximum # of bands */ +#else +#define MAXBANDS 2 /**< Maximum # of bands */ +#endif /* WL_BAND6G */ + +typedef struct wl_bsstrans_rssi_v1 { + int8 rssi[MAXBANDS]; /**< RSSI in dbm */ +} wl_bsstrans_rssi_v1_t; typedef struct wl_bsstrans_rssi { int8 rssi_2g; /**< RSSI in dbm for 2.4 G */ @@ -3849,6 +4327,18 @@ typedef struct wl_bsstrans_rssi { #define RSSI_RATE_MAP_MAX_STREAMS 4 /**< max streams supported */ +/** RSSI to rate mapping, all 20Mhz, no SGI */ +typedef struct wl_bsstrans_rssi_rate_map_v4 { + uint16 ver; + uint16 len; /**< length of entire structure */ + wl_bsstrans_rssi_v1_t cck[WL_NUM_RATES_CCK]; /**< 2.4G only */ + wl_bsstrans_rssi_v1_t ofdm[WL_NUM_RATES_OFDM]; /**< 6 to 54mbps */ + wl_bsstrans_rssi_v1_t phy_n[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_MCS_1STREAM]; /* MCS7 */ + wl_bsstrans_rssi_v1_t phy_ac[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_VHT_ALL]; /* MCS0-11 */ + wl_bsstrans_rssi_v1_t phy_ax[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_HE]; /* MCS0-11 */ + wl_bsstrans_rssi_v1_t phy_be[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_EHT]; /* MCS0-15 */ +} wl_bsstrans_rssi_rate_map_v4_t; + /** RSSI to rate mapping, all 20Mhz, no SGI */ typedef struct wl_bsstrans_rssi_rate_map_v3 { uint16 ver; @@ -3858,7 +4348,7 @@ typedef struct wl_bsstrans_rssi_rate_map_v3 { wl_bsstrans_rssi_t phy_n[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_MCS_1STREAM]; /* MCS0-7 */ wl_bsstrans_rssi_t phy_ac[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_VHT_ALL]; /* MCS0-11 */ wl_bsstrans_rssi_t phy_ax[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_HE]; /* MCS0-11 */ - wl_bsstrans_rssi_t phy_be[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_EHT]; /* MCS0-13 */ + wl_bsstrans_rssi_t phy_be[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_EHT]; /* MCS0-15 */ } wl_bsstrans_rssi_rate_map_v3_t; /** RSSI to rate mapping, all 20Mhz, no SGI */ @@ -3892,7 +4382,22 @@ typedef struct wl_bsstrans_rssi_rate_map { wl_bsstrans_rssi_t phy_ac[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_VHT]; /**< MCS0-9 */ } wl_bsstrans_rssi_rate_map_t; -#define WL_BSSTRANS_ROAMTHROTTLE_VERSION 1 +#define WL_CCA_CHAN_LOAD_VERSION_1 1 +#define CCA_LOAD_MAP_MAX_TABLE_ENTRY 16u + +typedef struct wl_cca_chnl_load { + uint8 cca; /* CCA value */ + uint8 chnl_load; /* Channel load percent */ +} wl_cca_chnl_load_t; + +/* CCA to Channel Load mapping */ +typedef struct wl_cca_chnl_load_map { + uint16 ver; + uint16 len; /**< No of cca load levels */ + wl_cca_chnl_load_t cca_load[CCA_LOAD_MAP_MAX_TABLE_ENTRY]; +} wl_cca_chnl_load_map_t; + +#define WL_BSSTRANS_ROAMTHROTTLE_VERSION_1 1 /** Configure number of scans allowed per throttle period */ typedef struct wl_bsstrans_roamthrottle { @@ -3905,7 +4410,7 @@ typedef struct wl_bsstrans_roamthrottle { #ifndef NFIFO_EXT #if defined(BCM_AQM_DMA_DESC) && !defined(BCM_AQM_DMA_DESC_DISABLED) -#ifdef WL_LLW +#if (defined(LLW) && !defined(SWLLW)) || defined(BCM_SAQM_FOR_ALL_TX_QUEUES) #define NFIFO_EXT 11 /* 4EDCA + 4 TWT + 1 Mcast/Bcast + 1 Spare + 1 LLQ */ #else #define NFIFO_EXT 10 /* 4EDCA + 4 TWT + 1 Mcast/Bcast + 1 Spare */ @@ -4000,15 +4505,15 @@ enum { */ #define REINIT_RSN_IDX_V2(_x) (((_x) <= WL_REINIT_RC_LAST_V2) ? (_x) : 0) -#define WL_CNT_T_VERSION 30 /**< current version of wl_cnt_t struct */ #define WL_CNT_VERSION_6 6 #define WL_CNT_VERSION_7 7 #define WL_CNT_VERSION_11 11 #define WL_CNT_VERSION_XTLV 30 +#define WL_CNT_VERSION_XTLV_ML 31 #define WL_COUNTERS_IOV_VERSION_1 1 #define WL_SUBCNTR_IOV_VER WL_COUNTERS_IOV_VERSION_1 -/* First two uint16 are version and lenght fields. So offset of the first counter will be 4 */ +/* First two uint16 are version and length fields. So offset of the first counter will be 4 */ #define FIRST_COUNTER_OFFSET 0x04 /* need for now due to src/wl/ndis automerged to other branches. e.g. BISON */ @@ -4016,8 +4521,30 @@ enum { /* Number of xtlv info as required to calculate subcounter offsets */ #define WL_CNT_XTLV_ID_NUM 12 -#define WL_TLV_IOV_VER 1 +#define WL_TLV_IOV_VERSION_1 1u +#define WL_TLV_IOV_VERSION_2 2u +#define WL_TLV_DATASET_V2_LEN 2u /* First 32 bit - TLV type + * Second 32 bit - TLV Len + */ +#define SUBC_SUBFLD_NUMTLV_MASK 0x00ff +#define SUBC_SUBFLD_NUMTLV_GET(val) (val & SUBC_SUBFLD_NUMTLV_MASK) + +#define SUBC_SUBFLD_NUMLINKS_MASK 0x0f00 +#define SUBC_SUBFLD_NUMLINKS_SHIFT 8 +#define SUBC_SUBFLD_NUMLINKS_UPD(val, nl) \ + (val) |= (((((uint16)nl)) << SUBC_SUBFLD_NUMLINKS_SHIFT) & \ + SUBC_SUBFLD_NUMLINKS_MASK) +#define SUBC_SUBFLD_NUMLINKS_GET(val) \ + (val & SUBC_SUBFLD_NUMLINKS_MASK) >> SUBC_SUBFLD_NUMLINKS_SHIFT + +#define SUBC_SUBFLD_SLICEIX_MASK 0x7000 +#define SUBC_SUBFLD_SLICEIX_SHIFT 12 +#define SUBC_SUBFLD_SLICEIX_UPD(val, slix) \ + (val) |= (((((uint16)slix)) << SUBC_SUBFLD_SLICEIX_SHIFT) & \ + SUBC_SUBFLD_SLICEIX_MASK) +#define SUBC_SUBFLD_SLICEIX_GET(val) \ + (val & SUBC_SUBFLD_SLICEIX_MASK) >> SUBC_SUBFLD_SLICEIX_SHIFT /** * tlv IDs uniquely identifies counter component * packed into wl_cmd_t container @@ -4030,12 +4557,27 @@ enum wl_cnt_xtlv_id { WL_CNT_XTLV_WLC_SECVLN = 0x103, /* security vulnerabilities counters */ WL_CNT_XTLV_WLC_HE_OMI = 0x104, /* he omi counters */ WL_CNT_XTLV_WLC_RINIT_RSN_V2 = 0x105, /**< WLC layer reinitreason extension */ + WL_CNT_XTLV_WLC_MESH_PKT_V1 = 0x106, /**< WLC layer Mesh pkt counters */ + WL_CNT_XTLV_WLC_HE_TX = 0x107, /* HE Tx counters */ + WL_CNT_XTLV_WLC_HE_RX = 0x108, /* HE Rx counters */ WL_CNT_XTLV_CNTV_LE10_UCODE = 0x200, /**< wl counter ver < 11 UCODE MACSTAT */ WL_CNT_XTLV_LT40_UCODE_V1 = 0x300, /**< corerev < 40 UCODE MACSTAT */ WL_CNT_XTLV_GE40_UCODE_V1 = 0x400, /**< corerev >= 40 UCODE MACSTAT */ WL_CNT_XTLV_GE64_UCODEX_V1 = 0x800, /* corerev >= 64 UCODEX MACSTAT */ WL_CNT_XTLV_GE80_UCODE_V1 = 0x900, /* corerev >= 80 UCODEX MACSTAT */ - WL_CNT_XTLV_GE80_TXFUNFL_UCODE_V1 = 0x1000 /* corerev >= 80 UCODEX MACSTAT */ + WL_CNT_XTLV_GE80_RXERR_UCODE_V1 = 0x901, /* corerev >= 80 UCODE RXERR mac stat */ + WL_CNT_XTLV_GE80_TXFUNFL_UCODE_V1 = 0x1000, /* corerev >= 80 UCODEX MACSTAT */ + WL_CNT_XTLV_GE88_UCODE_TX_V1 = 0x1001, /* corerev >= 88 ucode macstats V1 - tx */ + WL_CNT_XTLV_GE88_UCODE_RX_V1 = 0x1002, /* corerev >= 88 ucode macstats V1 - rx */ + WL_CNT_XTLV_GE88_UCODE_TX_V2 = 0x1003, /* corerev >= 88 ucode macstats V2 - tx */ + WL_CNT_XTLV_GE88_UCODE_RX_V2 = 0x1004, /* corerev >= 88 ucode macstats V2 - rx */ + WL_CNT_XTLV_GE88_UCODE_TX_U32_V1 = 0x1005, /* corerev >= 88 ucode macstats V1 - tx */ + WL_CNT_XTLV_GE88_UCODE_RX_U32_V1 = 0x1006, /* corerev >= 88 ucode macstats V1 - rx */ + WL_CNT_XTLV_GE88_UCODE_TX_V3 = 0x1007, /* corerev >= 88 ucode macstats V3 - tx */ + WL_CNT_XTLV_GE88_UCODE_RX_V3 = 0x1008, /* corerev >= 88 ucode macstats V3 - rx */ + WL_CNT_XTLV_GE88_UCODE_TX_U32_V2 = 0x1009, /* corerev >= 88 ucode macstats V2 - tx */ + WL_CNT_XTLV_GE88_UCODE_RX_U32_V2 = 0x100a, /* corerev >= 88 ucode macstats V2 - rx */ + WL_CNT_XTLV_DYN_BW_STATS_V1 = 0x100b, /* corerev >= 88 DynBW stats */ }; /* tlv IDs uniquely identifies periodic state component */ @@ -4056,7 +4598,7 @@ enum wl_periodic_chan_xtlv_id { typedef struct wlc_chan_periodic_cntr { uint16 version; - uint16 pad; + uint16 PAD; uint32 rxstrt; } wlc_chan_periodic_cntr_t; #endif /* WLC_CHAN_ECNTR_TEST */ @@ -4065,9 +4607,9 @@ typedef struct wlc_chan_periodic_cntr typedef struct wlc_chan_cntr_hdr_v1 { uint16 version; - uint16 pad; + uint16 PAD; chanspec_t chanspec; /* Dont add any fields above this */ - uint16 pad1; + uint16 PAD; uint32 total_time; uint32 chan_entry_cnt; } wlc_chan_cntr_hdr_v1_t; @@ -4117,7 +4659,7 @@ typedef struct { uint16 ver; uint16 length; /* length of the data portion */ uint16 cnt; - uint16 pad; /* pad to align to 32 bit */ + uint16 PAD; /* pad to align to 32 bit */ uint8 data[]; /* array of tdmtx_cnt_v1_t */ } tdmtx_status_t; @@ -4207,89 +4749,20 @@ enum { IOV_TDMTX_LAST }; -/* iovar structure for beacon simulator */ -typedef struct wl_bcnsim_ioc { - uint16 id; /* ID of the sub-command */ - uint16 len; /* total length of all data[] */ - uint8 data[]; /* var len payload */ -} wl_bcnsim_ioc_t; +/* SFLASH iovar sub commands */ +#define WL_SFLASH_IOV_VERSION_V1 1u -/* iovar subcmd ids */ -enum { - IOV_BCNSIM_ENB = 1, - IOV_BCNSIM_ERRMAX = 2, - IOV_BCNSIM_ERRDSTRB = 3, - IOV_BCNSIM_DRIFT = 4, - IOV_BCNSIM_RNDLYMAX = 5, - IOV_BCNSIM_RNDDLY_DSTRB = 6, - IOV_BCNSIM_CONSDLY = 7, - IOV_BCNSIM_OMT_PROB = 8, - IOV_BCNSIM_OMT_MIN_N = 9, - IOV_BCNSIM_OMT_MAX_N = 10, - IOV_BCNSIM_OMT_DSTRB = 11, - IOV_BCNSIM_TSF_JUMP = 12, - IOV_BCNSIM_PATTERN = 13, - IOV_BCNSIM_STATUS = 14, - IOV_BCNSIM_AUTH = 15, - IOV_BCNSIM_RNDDLY_PROB = 16, - IOV_BCNSIM_LAST +enum wl_sflash_subcmd_id { + WL_SFLASH_SUBCMD_CALWRITE = 0, + WL_SFLASH_SUBCMD_CALERASE = 1u, + WL_SFLASH_SUBCMD_WRITE = 2u, + WL_SFLASH_SUBCMD_ERASE = 3u, + WL_SFLASH_SUBCMD_DUMP = 4u, + WL_SFLASH_SUBCMD_DATASIZE = 5u, + WL_SFLASH_SUBCMD_SIZE = 6u, + WL_SFLASH_SUBCMD_READ = 7u }; -/* tlv id for beacon simulator */ -enum wl_bcnsim_xtlv_id { - WL_BCNSIM_XTLV_ENABLE = 0x1, - WL_BCNSIM_XTLV_ERRMAX = 0x2, - WL_BCNSIM_XTLV_ERRDSTRB = 0x3, - WL_BCNSIM_XTLV_DRIFT = 0x4, - WL_BCNSIM_XTLV_RNDLYMAX = 0x5, - WL_BCNSIM_XTLV_RNDDLY_DSTRB = 0x6, - WL_BCNSIM_XTLV_CONSDLY = 0x7, - WL_BCNSIM_XTLV_OMT_PROB = 0x8, - WL_BCNSIM_XTLV_OMT_MIN_N = 0x9, - WL_BCNSIM_XTLV_OMT_MAX_N = 0xa, - WL_BCNSIM_XTLV_OMT_DSTRB = 0xb, - WL_BCNSIM_XTLV_TSF_JUMP = 0xc, - WL_BCNSIM_XTLV_PATTERN = 0xd, - WL_BCNSIM_XTLV_STATUS = 0xe, - WL_BCNSIM_XTLV_AUTH = 0xf, - WL_BCNSIM_XTLV_RNDDLY_PROB = 0x10 -}; - -/* structure to store different pattern params */ -typedef struct wlc_bcnsim_bcn_diff_v1 { - uint16 version; - uint16 dtim_cnt; - uint32 tx_delta; - uint32 ts_delta; -} wlc_bcnsim_bcn_diff_v1_t; - -/* structure to store/pass pattern */ -typedef struct wlc_bcnsim_pattern_info_v1 { - uint16 version; - uint16 pattern_count; - uint16 current_pos; - wlc_bcnsim_bcn_diff_v1_t bcnsim_bcn_diff[]; -} wlc_bcnsim_pattern_info_v1_t; - -/* struct to store bcn sim status */ -typedef struct bcnsim_status_v1 { - uint16 ver; - uint16 length; /* length of this structure */ - uint32 rnd_delay_max; /* random delay */ - int32 const_delay; /* cons delay */ - int32 tsf_jump; /* change tsf */ - int16 drift; /* add drift */ - uint16 error_max; /* max error */ - uint8 error_dstrb; /* error dstrb */ - uint8 rnd_delay_dstrb; /* rnd delay distr */ - uint8 rnd_delay_prob; /* random delay prob */ - uint8 omit_prob; /* control omit prob */ - uint8 omit_min_n; /* min omit */ - uint8 omit_max_n; /* max omit */ - uint8 omit_dstrb; /* omit dstrb % */ - uint8 padding1; -} bcnsim_status_v1_t; - /** * The number of variables in wl macstat cnt struct. * (wl_cnt_ge40mcst_v1_t, wl_cnt_lt40mcst_v1_t, wl_cnt_v_le10_mcst_t) @@ -4303,14 +4776,18 @@ typedef struct bcnsim_status_v1 { #define WL_CNT_REV80_MCST_TXFUNFl_STRUCT_SZ(fcnt) \ (WL_CNT_REV80_MCST_TXFUNFlW_STRUCT_FIXED_SZ + (fcnt * sizeof(uint32))) #define WL_CNT_REV80_MCST_TXFUNFlW_STRUCT_SZ (WL_CNT_REV80_MCST_TXFUNFl_STRUCT_SZ(NFIFO_EXT)) +#define WL_CNT_REV80_RXERR_MCST_STRUCT_SZ ((uint32)sizeof(wl_cnt_ge80_rxerr_mcst_v1_t)) #define WL_CNT_MCXST_STRUCT_SZ ((uint32)sizeof(wl_cnt_ge64mcxst_v1_t)) -#define WL_CNT_HE_STRUCT_SZ ((uint32)sizeof(wl_he_cnt_wlc_t)) +#define WL_CNT_HE_STRUCT_V5_SZ ((uint32)sizeof(wl_he_cnt_wlc_v5_t)) +#define WL_CNT_HE_STRUCT_V6_SZ ((uint32)sizeof(wl_he_cnt_wlc_v6_t)) #define WL_CNT_SECVLN_STRUCT_SZ ((uint32)sizeof(wl_secvln_cnt_t)) #define WL_CNT_HE_OMI_STRUCT_SZ ((uint32)sizeof(wl_he_omi_cnt_wlc_v1_t)) +#define WL_CNT_DYN_BW_STRUCT_SZ ((uint32)sizeof(wlc_dyn_bw_cnt_v1_t)) + #define INVALID_CNT_VAL (uint32)(-1) #define WL_XTLV_CNTBUF_MAX_SIZE ((uint32)(OFFSETOF(wl_cnt_info_t, data)) + \ @@ -4352,7 +4829,7 @@ typedef struct { * set in this field. */ uint16 num_subcounters; /* Number of counter offset passed by wl app to FW. */ - uint32 data[1]; /* variable length payload: + uint32 data[BCM_FLEX_ARRAY]; /* variable length payload: * Offsets to the counters will be passed to FW * throught this data field. FW will return the value of counters * at the offsets passed by wl app in this fiels itself. @@ -4374,8 +4851,10 @@ typedef struct { * so to calculate offset of supported TLVs. * If there is a mismatch in the version, FW will update an error */ - uint16 num_tlv; /* Max number of TLV info passed by FW to WL app. - * and vice-versa + uint16 num_tlv; /* for WL_CNT_VERSION_XTLV: Max number of TLV info passed by FW + * to WL app. and vice-versa + * For WL_CNT_VERSION_XTLV_ML: this field carries links and sliceix- + * additionally. see SUBC_SUBFLD_xxx */ uint32 data[]; /* variable length payload: * This stores the tlv as supported by F/W to the wl app. @@ -4611,7 +5090,20 @@ typedef struct { uint32 rxnofrag; /* # of nobuf failure due to no pkt availability */ uint32 rxnocmplid; /* # of nobuf failure due to rxcmplid non-availability */ uint32 rxnohaddr; /* # of nobuf failure due to host address non-availability */ - + uint32 txnull_pm; /**< Number of TX NULL_DATA total */ + uint32 txnull_pm_succ; /**< Number of TX NULL_DATA successes */ + uint32 ccmpreplay_qosdata_nobapol_rxretry; /**< Retried QOS data MPDUs RX without + * BA policy and tossed by key mgmt as + * replays + */ + uint32 txnoalfdatabuf; /**< out of alfrag data buffers errors */ + uint32 txalfdatabuf; /**< number of tx alfrag data buffers attepted for transmission */ + uint32 txalfrag; /**< number of txalfrags attepted for transmission */ + uint32 txlfrag; /**< number of txlfrags attepted for transmission */ + uint32 rxunsolicitedproberesp; /**< number of "unsoliocited" probe responses RXed */ + uint32 rco_passthrough; /**< hw rco required but passthrough */ + uint32 rco_normal; /**< hw rco hdr for normal process */ + uint32 rxnodatabuf; /**< # of nobuf failure due to rxdata buf non-availability */ /* Do not remove or rename in the middle of this struct. * All counter variables have to be of uint32. */ @@ -4666,6 +5158,7 @@ typedef struct wl_he_cnt_wlc_v2 { /* he counters Version 3 */ #define WL_RU_TYPE_MAX 6 +#define WL_EHT_RU_TYPE_MAX (16u) #define HE_COUNTERS_V3 (3) typedef struct wl_he_cnt_wlc_v3 { @@ -4710,6 +5203,7 @@ typedef struct wl_he_cnt_wlc_v3 { uint32 he_rxtrig_nfrp; uint32 he_rxtrig_bqrp; uint32 he_rxtrig_gcrmubar; + uint32 he_txtbppdu_cnt[AC_COUNT]; } wl_he_cnt_wlc_v3_t; /* he counters Version 4 */ @@ -4758,15 +5252,16 @@ typedef struct wl_he_cnt_wlc_v4 { uint32 he_rxtrig_gcrmubar; uint32 he_rxtrig_basic_htpack; /**< triggers received with HTP ack policy */ uint32 he_rxtrig_ed_cncl; /**< count of cancelled packets - * becasue of cs_req in trigger frame + * because of cs_req in trigger frame */ - uint32 he_rxtrig_suppr_null_tbppdu; /**< count of null frame sent becasue of + uint32 he_rxtrig_suppr_null_tbppdu; /**< count of null frame sent because of * suppression scenarios */ uint32 he_ulmu_disable; /**< number of UL MU disable scenario's handled in ucode */ uint32 he_ulmu_data_disable; /** ampdu parser */ + uint32 rxbad_ampdu; /**< number of rx'd bad ampdus */ + uint32 rxcgprsqovfl; /**< Rx Probe Request Que overflow in the AP */ + uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ + uint32 rxdrop20s; /**< drop secondary cnt */ + uint32 rxtoolate; /**< receive too late */ + uint32 m_pfifo_drop; /**< # of pfifo dropped frames */ + uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ + uint32 phyovfl; /**< number of phy overflows */ + uint32 rxf0ovfl; /**< number of rx fifo 0 overflows */ + uint32 rxf1ovfl; /**< number of rx fifo 1 overflows */ + uint32 lenfovfl; /**< number of length overflows */ + uint32 badplcp; /**< parity check of the PLCP header failed */ + uint32 rxerr_stat; /**< rx error statistics */ + uint32 stsfifofull; /**< status fifo full */ + uint32 stsfifoerr; /**< status fifo error */ + uint32 ctx_fifo_full; /**< fw not draining frames fast enough */ + uint32 ctx_fifo2_full; /**< fw not draining frames fast enough */ + uint32 missbcn_dbg; /**< number of beacon missed to receive */ + uint32 rxrsptmout; /**< number of response timeouts for tx'd frames */ + uint32 laterx_cnt; /**< ucode sees frame 30us late */ + uint32 bcn_drop_cnt; /**< number of BCNs dropped in ucode */ + uint32 bfr_timeout; /**< number of bfr timeouts */ + uint32 rxgaininfo_ant0; /**< ANT-0 phy RX gain info - main? */ + uint32 rxauxgaininfo_ant0; /**< ANT-0 phy RX gain info - aux */ + uint32 he_rxtrig_myaid; /**< number of rx'd valid trigger frame with myaid */ + uint32 he_rxtrig_rand; /**< number of rx'd valid trigger frame with random aid */ + uint32 he_rxtrig_basic; /**< number of rx'd of basic trigger frame */ + uint32 he_rxtrig_bfm_cnt; /**< number of rx'd trigger frame with bfm */ + uint32 he_rxtrig_mubar; /**< number of rx'd MUBAR trigger frame variant */ + uint32 he_rxtrig_murts; /**< number of rx'd MU-RTS trigger frame variant */ + uint32 he_rxtrig_bsrp; /**< number of rx'd of BSR poll trigger frame variant */ + uint32 he_rxtrig_gcrmubar; /**< number of rx'd gcr mu bar trigger frame variant? */ + uint32 he_rxtrig_bqrp; /**< number of rx'd bqrp trigger frame variant? */ + uint32 he_rxtrig_nfrp; /**< Todo: check on functionality */ + uint32 he_rxtrig_basic_htpack; /**< triggers received with HTP ack policy */ + uint32 he_cs_req_tx_cancel; /**< tx cancelled due to trigger rx or ch sw? */ + uint32 he_rxtrig_rngpoll; /**< todo: check functionality */ + uint32 he_rxtrig_rngsnd; /**< todo: check functionality */ + uint32 he_rxtrig_rngssnd; /**< todo: check functionality */ + uint32 he_rxtrig_rngrpt; /**< todo: check functionality */ + uint32 he_rxtrig_rngpasv; /**< todo: check functionality */ + uint32 he_rxtrig_ru_2x996T; /**< Rx'd trigger frame with STA RU index 160mhz */ + uint32 he_rxtrig_invalid_ru; /**< Rx'd trigger frame with invalid STA20 RU index */ + uint32 he_rxtrig_inv_ru_cnt; /**< # of Rx'd trigger frames with invalid RU cnt */ + uint32 he_rxtrig_drop_cnt; /**< # of trigger frames dropped */ + uint32 ndp_fail_cnt; /**< # of NDP fails */ + uint32 rxfrmtoolong2_cnt; /**< # of Rx'd too long pkts */ + uint32 hwaci_status; /**< HW ACI status */ + uint32 pmqovfl; /**< number of PMQ overflows */ +} wl_cnt_ge88mcst_rx_v1_t; + +/* Rev GE88 per ML link supportive wl counters (macstats) - version 1 */ +typedef struct wl_macst_rx_ge88mcst { + uint8 num_links; /* Number of per-link stats supported on slice */ + uint8 pad[3]; + + /* Per ML Link RX macstats (esp. eMLSR) */ + wl_cnt_ge88mcst_rx_v1_t cnt[]; +} wl_macst_rx_ge88mcst_v1_t; + +/* Rev GE88 per ML link supportive wl counters (macstats) - version 1 */ +typedef struct wl_macst_tx_ge88mcst { + uint8 num_links; /* Number of per-link stats supported on slice */ + uint8 pad[3]; + + /* Per ML Link TX macstats (esp. eMLSR) */ + wl_cnt_ge88mcst_tx_v1_t cnt[]; +} wl_macst_tx_ge88mcst_v1_t; + +/* Rev Ge88 TX specific macstats - version 2 */ +typedef struct { + uint32 txallfrm; /**< num of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txrtsfrm; /**< number of RTS sent out by the MAC */ + uint32 txctsfrm; /**< number of CTS sent out by the MAC */ + uint32 txackfrm; /**< number of ACK frames sent out */ + uint32 txback; /**< blockack txcnt */ + uint32 he_txmtid_back; /**< number of mtid BAs */ + uint32 txdnlfrm; /**< number of Null-Data tx from template */ + uint32 txbcnfrm; /**< beacons transmitted */ + uint32 txndpa; /**< Number of TX NDPAs */ + uint32 txndp; /**< Number of TX NDPs */ + uint32 txbfm; /**< Number of TX Bfm cnt */ + uint32 txcwrts; /**< Number of tx cw rts */ + uint32 txcwcts; /**< Number of tx cw cts */ + uint32 txbfpoll; /**< Number of tx bfpolls */ + uint32 txfbw; /**< transmit at fallback bw (dynamic bw) */ + uint32 txampdu; /**< number of AMPDUs transmitted */ + uint32 he_txmampdu; /**< Number of tx m-ampdus */ + uint32 txucast; /**< # of ucast tx expecting resp (not cts/cwcts) */ + uint32 he_txfrag; /**< Number of tx frags */ + uint32 he_txtbppdu; /**< increments on transmission of every TB PPDU */ + uint32 he_txtbppdu_ack; /**< Number of tx HE TBPPDU acks */ + uint32 txinrtstxop; /**< number of data frame tx during rts txop */ + uint32 null_txsts_empty; /**< Number empty null-txstatus' */ + uint32 he_ulmu_disable; /**< # of ULMU disables handled in ucode */ + uint32 he_ulmu_data_disable; /**< number of UL MU data disable scenarios + * handled in ucode + */ + uint32 he_rxtrig_suppr_null_tbppdu; /**< count of null frame sent because of + * suppression scenarios + */ + uint32 he_null_zero_agg; /**< nullAMPDU's transmitted in response to + * basic trigger because of zero aggregation + */ + uint32 he_null_tbppdu; /**< null TBPPDU's sent as a response to + * basic trigger frame + */ + uint32 he_null_bsrp_rsp; /**< null AMPDU's txed in response to BSR poll */ + uint32 he_null_fifo_empty; /**< null AMPDU's in response to basic trigger + * because of no frames in fifo's + */ + uint32 txrtsfail; /**< # of rts TX fails that reach retry limit */ + uint32 txcgprsfail; /**< Tx Probe Response Fail. + * AP sent probe response but did not get ACK. + */ + uint32 bcntxcancl; /**< TX bcns canceled due to rx of beacon (IBSS) */ + uint32 txtplunfl; /**< Template unfl + * (mac too slow to tx ACK/CTS or BCN) + */ + uint32 txphyerror; /**< TX phyerr - reported in txs for + * driver queued frames + */ + uint32 txshmunfl_cnt; /**< TX SHM unfl cnt */ + uint32 txfunfl[11]; /**< per-fifo tx underflows */ + uint32 txfmlunfl[9]; /**< ML fifos underflow cnts */ + uint32 bferpt_inv_cfg; /**< Invalid bfe report cfg */ + uint32 bferpt_drop_cnt1; /**< bfe rpt drop cnt 1 */ + uint32 bferpt_drop_cnt2; /**< bfe rpt drop cnt 2 */ + uint32 bferot_txcrs_high; /**< bfe rpt tx crs high */ + uint32 txbfm_errcnt; /**< TX bfm error cnt */ + uint32 tx_murts_cnt; /**< Tx MURTS Count */ + uint32 tx_noavail_cnt; /**< Tx Not avail Count */ + uint32 tx_null_link_pref; /**< Null Link Pref */ + uint32 btcx_rfact_ctr_l; /**< btcx rxfact counter low */ + uint32 btcx_rfact_ctr_h; /**< btcx rxfact counter high */ + uint32 btcx_txconf_ctr_l; /**< btcx txconf counter low */ + uint32 btcx_txconf_ctr_h; /**< btcx txconf counter high */ + uint32 btcx_txconf_dur_ctr_l; /**< btcx txconf duration counter low */ + uint32 btcx_txconf_dur_ctr_h; /**< btcx txconf duration counter high */ + uint32 txcgprssuc; /**< Tx Probe Response succ cnt */ + uint32 txsf; /**< # of Tx'd SF */ + uint32 macsusp_cnt; /**< # of macsuspends */ + uint32 prs_timeout; /**< # of pre wds */ + uint32 emlsr_tx_nosrt; /**< # of no TX starts for eMLSR */ + uint32 rts_to_self_cnt; /**< # of RTS to self */ + uint32 saqm_sendfrm_agg_cnt; /**< # SAQM Send frame aggregation */ + uint32 txbcn_phyerr_cnt; /**< # Tx Beacon Phy error */ + uint32 he_txtrig; /**< # Tx Trigger Frames */ +} wl_cnt_ge88mcst_tx_v2_t; + +/* Rev Ge88 RX specific macstats - version 2 */ +typedef struct { + uint32 rxstrt; /**< Number of received frames with a good PLCP + * (i.e. passing parity check) + */ + uint32 rx20s_cnt; /**< Increments if RXFrame does not include primary 20 */ + uint32 C_SECRSSI0; /**< SEC RSSI0 info */ + uint32 C_SECRSSI1; /**< SEC RSSI1 info */ + uint32 C_SECRSSI2; /**< SEC RSSI2 info */ + uint32 C_CCA_RXPRI_LO; /**< SEC RXPRI Low */ + uint32 C_CCA_RXPRI_HI; /**< SEC RXPRI High */ + uint32 C_CCA_RXSEC20_LO; /**< SEC CCA RX 20mhz low */ + uint32 C_CCA_RXSEC20_HI; /**< SEC CCA RX 20mhz high */ + uint32 C_CCA_RXSEC40_LO; /**< SEC CCA RX 40mhz low */ + uint32 C_CCA_RXSEC40_HI; /**< SEC CCA RX 40mhz high */ + uint32 C_CCA_RXSEC80_LO; /**< SEC CCA RX 80mhz low */ + uint32 C_CCA_RXSEC80_HI; /**< SEC CCA RX 80mhz high */ + uint32 rxctlmcast; /**< # of RX ctrl mcast frames */ + uint32 rxmgmcast; /**< # of rx'd Management mcast frames */ + uint32 rxbeaconmbss; /**< beacons rx'd from member of BSS */ + uint32 rxndpa_m; /**< number of RX NDPA Multicast */ + uint32 rxrtsucast; /**< # of ucast RTS (good FCS) */ + uint32 rxctsucast; /**< # of ucast CTS (good FCS) */ + uint32 rxctlucast; /**< # of rx'd CNTRL frames (good FCS & matching RA) */ + uint32 rxmgucastmbss; /**< # of rx'd mgmt frames (good FCS & matching RA) */ + uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */ + uint32 rxndpa_u; /**< number of unicast RX NDPAs */ + uint32 rxsf; /**< number of rxsfucast */ + uint32 rxcwrts; /**< number of rx'd cw ucast rts */ + uint32 rxcwcts; /**< number of rx'd cw ucast cts */ + uint32 rxbfpoll; /**< number of rx'd BF ucast poll */ + uint32 rxmgocast; /**< # of rx'd MGMT frames (good FCS & not matching RA) */ + uint32 rxctlocast; /**< # of rx'd CNTRL frame (good FCS & not matching RA) */ + uint32 rxrtsocast; /**< # of rx'd RTS not addressed */ + uint32 rxctsocast; /**< # of rx'd CTS not addressed */ + uint32 rxbeaconobss; /* beacons rx'd from other BSS */ + uint32 he_rxstrt_hesuppdu_cnt; /**< rx'd HE su PPDU cnt */ + uint32 he_rxstrt_hesureppdu_cnt; /**< rx'd HE SU RE PPDU cnt */ + uint32 he_rxtsrt_hemuppdu_cnt; /**< rx'd HE MU PPDU cnt */ + uint32 rxbar; /**< number of rx'd BARs */ + uint32 rxback; /**< number of rx'd BARs */ + uint32 he_rxmtid_back; /**< number of rx'd HE RX MultiTID BAs */ + uint32 he_rxmsta_back; /**< number of rx'd HE RX MultiSTA BAs */ + uint32 bferpt; /**< number of rx'd BFE report ready cnts */ + uint32 he_colormiss_cnt; /**< HE BSS color mismatch counts cnts */ + uint32 he_rxdefrag; /**< number of rx'd HE dynamic fragmented pkts */ + uint32 he_rxdlmu; /**< number of rx'd DL MU frames */ + uint32 rxcgprqfrm; /**< number of received Probe requests that made it into + * the PRQ fifo + */ + uint32 rx_fp_shm_corrupt_cnt; /**< SHM corrupt count */ + uint32 he_physu_rx; /**< Number of PHY SU Frames received */ + uint32 he_phyru_rx; /**< Number of PHY RU Frames received */ + uint32 PAD[17]; /**< PAD Gap */ + uint32 rxbadplcp; /**< parity check of the PLCP header failed */ + uint32 rxcrsglitch; /**< PHY able to correlate the plcp but not the hdr */ + uint32 rxfrmtoolong; /**< rx'd frame longer than legal limit (2346 bytes) */ + uint32 rxfrmtooshrt; /**< rx'd frame not enough bytes for ft */ + uint32 rxnodelim; /**< # of not valid delim -> ampdu parser */ + uint32 rxbad_ampdu; /**< number of rx'd bad ampdus */ + uint32 rxcgprsqovfl; /**< Rx Probe Request Que overflow in the AP */ + uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ + uint32 rxdrop20s; /**< drop secondary cnt */ + uint32 rxtoolate; /**< receive too late */ + uint32 m_pfifo_drop; /**< # of pfifo dropped frames */ + uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ + uint32 phyovfl; /**< number of phy overflows */ + uint32 rxf0ovfl; /**< number of rx fifo 0 overflows */ + uint32 rxf1ovfl; /**< number of rx fifo 1 overflows */ + uint32 lenfovfl; /**< number of length overflows */ + uint32 weppeof; /**< number of weppeof */ + uint32 badplcp; /**< parity check of the PLCP header failed */ + uint32 stsfifofull; /**< status fifo full */ + uint32 stsfifoerr; /**< status fifo error */ + uint32 ctx_fifo_full; /**< fw not draining frames fast enough */ + uint32 ctx_fifo2_full; /**< fw not draining frames fast enough */ + uint32 missbcn_dbg; /**< number of beacon missed to receive */ + uint32 rxrsptmout; /**< number of response timeouts for tx'd frames */ + uint32 laterx_cnt; /**< ucode sees frame 30us late */ + uint32 bcn_drop_cnt; /**< number of BCNs dropped in ucode */ + uint32 bfr_timeout; /**< number of bfr timeouts */ + uint32 rxgaininfo_ant0; /**< ANT-0 phy RX gain info - main? */ + uint32 rxauxgaininfo_ant0; /**< ANT-0 phy RX gain info - aux */ + uint32 he_rxtrig_myaid; /**< number of rx'd valid trigger frame with myaid */ + uint32 he_rxtrig_rand; /**< number of rx'd valid trigger frame with random aid */ + uint32 he_rxtrig_basic; /**< number of rx'd of basic trigger frame */ + uint32 he_rxtrig_bfm_cnt; /**< number of rx'd trigger frame with bfm */ + uint32 he_rxtrig_mubar; /**< number of rx'd MUBAR trigger frame variant */ + uint32 he_rxtrig_murts; /**< number of rx'd MU-RTS trigger frame variant */ + uint32 he_rxtrig_bsrp; /**< number of rx'd of BSR poll trigger frame variant */ + uint32 he_rxtrig_gcrmubar; /**< number of rx'd gcr mu bar trigger frame variant? */ + uint32 he_rxtrig_bqrp; /**< number of rx'd bqrp trigger frame variant? */ + uint32 he_rxtrig_nfrp; /**< Todo: check on functionality */ + uint32 he_rxtrig_basic_htpack; /**< triggers received with HTP ack policy */ + uint32 he_cs_req_tx_cancel; /**< tx cancelled due to trigger rx or ch sw? */ + uint32 he_rxtrig_rngpoll; /**< todo: check functionality */ + uint32 he_rxtrig_rngsnd; /**< todo: check functionality */ + uint32 he_rxtrig_rngssnd; /**< todo: check functionality */ + uint32 he_rxtrig_rngrpt; /**< todo: check functionality */ + uint32 he_rxtrig_rngpasv; /**< todo: check functionality */ + uint32 he_rxtrig_ru_2x996T; /**< Rx'd trigger frame with STA RU index 160mhz */ + uint32 he_rxtrig_invalid_ru; /**< Rx'd trigger frame with invalid STA20 RU index */ + uint32 he_rxtrig_inv_ru_cnt; /**< # of Rx'd trigger frames with invalid RU cnt */ + uint32 he_rxtrig_drop_cnt; /**< # of trigger frames dropped */ + uint32 ndp_fail_cnt; /**< # of NDP fails */ + uint32 rxfrmtoolong2_cnt; /**< # of Rx'd too long pkts */ + uint32 hwaci_status; /**< HW ACI status */ + uint32 pmqovfl; /**< number of PMQ overflows */ + uint32 sctrg_rxcrs_drop_cnt; /**< Number of scan trigger dropped due to rxcrs */ + uint32 inv_punc_usig_cnt; /**< Number of invalid punctured USIG */ + uint32 sctrg_drop_cnt; /**< Number of scan trigger drop */ + uint32 he_wrong_nss; /**< Number of triggers with wrong NSS */ + uint32 he_trig_unsupp_rate; /**< Number of triggers with unsupported rates */ +} wl_cnt_ge88mcst_rx_v2_t; + +/* Rev GE88 per ML link supportive wl counters (macstats) - version 1 */ +typedef struct wl_macst_rx_ge88mcst_v2 { + uint8 num_links; /* Number of per-link stats supported on slice */ + uint8 pad[3]; + + /* Per ML Link RX macstats (esp. eMLSR) */ + wl_cnt_ge88mcst_rx_v2_t cnt[]; +} wl_macst_rx_ge88mcst_v2_t; + +/* Rev GE88 per ML link supportive wl counters (macstats) - version 1 */ +typedef struct wl_macst_tx_ge88mcst_v2 { + uint8 num_links; /* Number of per-link stats supported on slice */ + uint8 pad[3]; + + /* Per ML Link TX macstats (esp. eMLSR) */ + wl_cnt_ge88mcst_tx_v2_t cnt[]; +} wl_macst_tx_ge88mcst_v2_t; + +/* Rev Ge88 TX 32 specific macstats - version 1 */ +typedef struct { + uint32 txmpdu; /**< number of MPDUs transmitted */ + uint32 ctmode_ufc_cnt; /**< Number of UFCs with CT mode enabled */ +} wl_cnt_ge88mcst_tx_u32_v1_t; + +/* Rev Ge88 RX 32 specific macstats - version 1 */ +typedef struct { + uint32 rxdtucastmbss; /**< # of rx'd DATA frames (good FCS & matching RA) */ + uint32 pktengrxducast; /**< number of rx'd good fcs ucast frames */ + uint32 pktengrxdmcast; /**< number of rx'd good fcs mcast frames */ + uint32 rxdtocast; /**< # of rx'd DATA frames (good FCS & not matching RA) */ + uint32 rxdtucastobss; /**< number of unicast frames addressed to the MAC from + * other BSS (WDS FRAME) + */ + uint32 goodfcs; /**< number of rx'd goodfcs cnts */ + uint32 rxdtmcast; /**< # of rx'd Data mcast frames */ + uint32 rxanyerr; /**< Any RX error that is not counted by other counters */ + uint32 rxbadfcs; /**< # of frames with CRC check failed */ +} wl_cnt_ge88mcst_rx_u32_v1_t; + +/* Rev GE88 per ML link supportive wl counters (macstats) - version 1 */ +typedef struct wl_macst_rx_ge88mcst_u32 { + uint8 num_links; /* Number of per-link stats supported on slice */ + uint8 pad[3]; + + /* Per ML Link RX macstats (esp. eMLSR) */ + wl_cnt_ge88mcst_rx_u32_v1_t cnt[]; +} wl_macst_rx_ge88mcst_u32_v1_t; + +/* Rev GE88 per ML link supportive wl counters (macstats) - version 1 */ +typedef struct wl_macst_tx_ge88mcst_u32 { + uint8 num_links; /* Number of per-link stats supported on slice */ + uint8 pad[3]; + + /* Per ML Link TX macstats (esp. eMLSR) */ + wl_cnt_ge88mcst_tx_u32_v1_t cnt[]; +} wl_macst_tx_ge88mcst_u32_v1_t; + +/* ********** v3 start ************* */ +/* wrapper structure contain link_idx values which might not be same as the actual array ix */ +typedef struct wl_cnt_ge88mcst_rx_wrap_v1 { + uint8 link_idx; + uint8 pad[3]; + wl_cnt_ge88mcst_rx_v2_t cnt; +} wl_cnt_ge88mcst_rx_wrap_v1_t; + +typedef struct wl_cnt_ge88mcst_tx_wrap_v1 { + uint8 link_idx; + uint8 pad[3]; + wl_cnt_ge88mcst_tx_v2_t cnt; +} wl_cnt_ge88mcst_tx_wrap_v1_t; + +typedef struct wl_cnt_ge88mcst_rx_u32_wrap_v1 { + uint8 link_idx; + uint8 pad[3]; + wl_cnt_ge88mcst_rx_u32_v1_t cnt; +} wl_cnt_ge88mcst_rx_u32_wrap_v1_t; + +typedef struct wl_cnt_ge88mcst_tx_u32_wrap_v1 { + uint8 link_idx; + uint8 pad[3]; + wl_cnt_ge88mcst_tx_u32_v1_t cnt; +} wl_cnt_ge88mcst_tx_u32_wrap_v1_t; + +/* Rev GE88 per ML link supportive wl counters (macstats) - version 3 */ +typedef struct wl_macst_rx_ge88mcst_v3 { + uint8 num_links; /* Number of per-link stats supported on slice */ + uint8 pad[3]; + /* Per ML Link RX macstats (esp. eMLSR) */ + wl_cnt_ge88mcst_rx_wrap_v1_t cnt_wrap[]; +} wl_macst_rx_ge88mcst_v3_t; + +/* Rev GE88 per ML link supportive wl counters (macstats) - version 3 */ +typedef struct wl_macst_tx_ge88mcst_v3 { + uint8 num_links; /* Number of per-link stats supported on slice */ + uint8 pad[3]; + /* Per ML Link TX macstats (esp. eMLSR) */ + wl_cnt_ge88mcst_tx_wrap_v1_t cnt_wrap[]; +} wl_macst_tx_ge88mcst_v3_t; + +/* Rev GE88 per ML link supportive wl counters (macstats) - version 3 */ +typedef struct wl_macst_rx_ge88mcst_u32_v3 { + uint8 num_links; /* Number of per-link stats supported on slice */ + uint8 pad[3]; + /* Per ML Link RX macstats (esp. eMLSR) */ + wl_cnt_ge88mcst_rx_u32_wrap_v1_t cnt_wrap[]; +} wl_macst_rx_ge88mcst_u32_v3_t; + +/* Rev GE88 per ML link supportive wl counters (macstats) - version 3 */ +typedef struct wl_macst_tx_ge88mcst_u32_v3 { + uint8 num_links; /* Number of per-link stats supported on slice */ + uint8 pad[3]; + /* Per ML Link TX macstats (esp. eMLSR) */ + wl_cnt_ge88mcst_tx_u32_wrap_v1_t cnt_wrap[]; +} wl_macst_tx_ge88mcst_u32_v3_t; +/* ********** v3 end ************* */ + /** MACSTAT counters for ucode (corerev >= 80) */ typedef struct { /* MAC counters: 32-bit version of d11.h's macstat_t */ @@ -5184,7 +6302,6 @@ typedef struct { uint32 rxmtidback; uint32 rxmstaback; uint32 txfrag; - /* End of PSM2HOST stats block */ /* start of rxerror overflow counter(24) block which are modified/added in corerev 80 */ uint32 phyovfl; uint32 rxf0ovfl; /**< number of receive fifo 0 overflows */ @@ -5196,14 +6313,34 @@ typedef struct { uint32 strmeof; uint32 stsfifofull; uint32 stsfifoerr; - uint32 PAD[6]; uint32 rxerr_stat; - uint32 ctx_fifo_full; - uint32 PAD0[9]; + uint32 ctx_fifo_full; /* Firmware not draining frames fast enough */ + uint32 PAD[20]; uint32 ctmode_ufc_cnt; - uint32 PAD1[28]; /* PAD added for counter elements to be added soon */ + uint32 PAD[12]; /* PAD added for counter elements to be added soon */ + uint32 ctx_fifo2_full; /* Firmware not draining frames fast enough */ + uint32 PAD[10]; /* PAD to match to the struct size before ctx_fifo2_full count was + * introduced. Can be repurposed to a different counter + */ } wl_cnt_ge80mcst_v1_t; +/* RX error related counters in addition to RX counters in MAC stats above. + * Counters collected from noncontiguous SHM locations. + */ +typedef struct { + uint32 rx20s_cnt; /* Increments if RXFrame does not include primary 20 */ + uint32 m_pfifo_drop; /* ucode is late processing RX frame */ + uint32 new_rxin_plcp_wait_cnt; /* invalid reception/ ucode late in processing rx/ something + * wrong over MACPHY interface + */ + uint32 laterx_cnt; /* ucode sees frame 30us late */ + uint32 rxlegacyfrminvalid; /* Invalid BPHY or L-OFDM reception */ + uint32 txsifserr; /* Frame arrived in SIF when about to TX (B)ACK */ + uint32 ooseq_macsusp; /* ucode out of seq in processing reception due to mac + * suspend + */ +} wl_cnt_ge80_rxerr_mcst_v1_t; + typedef struct { uint32 fifocount; uint32 txfunfl[]; @@ -5223,7 +6360,7 @@ typedef struct { uint32 txbcnfrm; /**< beacons transmitted */ uint32 txfunfl[6]; /**< per-fifo tx underflows */ uint32 txfbw; /**< transmit at fallback bw (dynamic bw) */ - uint32 PAD0; /**< number of MPDUs transmitted */ + uint32 PAD; /**< number of MPDUs transmitted */ uint32 txtplunfl; /**< Template underflows (mac was too slow to transmit ACK/CTS * or BCN) */ @@ -5268,7 +6405,7 @@ typedef struct { * expecting a response */ uint32 bcntxcancl; /**< transmit beacons canceled due to receipt of beacon (IBSS) */ - uint32 PAD1; + uint32 PAD; uint32 rxf0ovfl; /**< number of receive fifo 0 overflows */ uint32 rxf1ovfl; /**< Number of receive fifo 1 overflows (obsolete) */ uint32 rxf2ovfl; /**< Number of receive fifo 2 overflows (obsolete) */ @@ -5299,7 +6436,7 @@ typedef struct { } wl_cnt_v_le10_mcst_t; #define MAX_RX_FIFO 3 -#define WL_RXFIFO_CNT_VERSION 1 /* current version of wl_rxfifo_cnt_t */ +#define WL_RXFIFO_CNT_VERSION_1 1 /* current version of wl_rxfifo_cnt_t */ typedef struct { /* Counters for frames received from rx fifos */ uint16 version; @@ -6213,8 +7350,8 @@ typedef struct wl_msglevel_v1 { /* add another uint32 when full */ } wl_msglevel_v1_t; -#define WL_ICMP_IPV6_CFG_VERSION 1 -#define WL_ICMP_IPV6_CLEAR_ALL (1 << 0) +#define WL_ICMP_IPV6_CFG_VERSION_1 1u +#define WL_ICMP_IPV6_CLEAR_ALL (1u << 0u) typedef struct wl_icmp_ipv6_cfg { uint16 version; @@ -6230,22 +7367,35 @@ typedef struct wl_icmp_ipv6_cfg { #define WL_ICMP_CFG_IPV6_LEN(count) (WL_ICMP_CFG_IPV6_FIXED_LEN + \ ((count) * sizeof(struct ipv6_addr))) -typedef struct wl_mkeep_alive_pkt { +typedef struct wl_mkeep_alive_pkt_v1 { uint16 version; /* Version for mkeep_alive */ uint16 length; /* length of fixed parameters in the structure */ uint32 period_msec; /* high bit on means immediate send */ uint16 len_bytes; uint8 keep_alive_id; /* 0 - 3 for N = 4 */ - uint8 data[1]; -} wl_mkeep_alive_pkt_t; + uint8 data[BCM_FLEX_ARRAY]; +} wl_mkeep_alive_pkt_v1_t; -#define WL_MKEEP_ALIVE_VERSION 1 -#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) +#define WL_MKEEP_ALIVE_VERSION_1 1u +#define WL_MKEEP_ALIVE_VERSION_2 2u /* 1/2 second precision since idle time is a seconds counter anyway */ #define WL_MKEEP_ALIVE_PRECISION 500 #define WL_MKEEP_ALIVE_PERIOD_MASK 0x7FFFFFFF #define WL_MKEEP_ALIVE_IMMEDIATE 0x80000000 +#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_v1_t, data) + +typedef struct wl_mkeep_alive_pkt_v2 { + uint16 version; /* Version for mkeep_alive */ + uint16 length; /* length of fixed parameters in the structure */ + uint32 period_msec; /* high bit on means immediate send */ + uint16 len_bytes; + uint16 retry_cnt; /* keep alive alive pkt retry count */ + uint8 PAD[2]; + uint8 keep_alive_id; /* 0 - 3 for N = 4 */ + uint8 data[BCM_FLEX_ARRAY]; +} wl_mkeep_alive_pkt_v2_t; + typedef struct wl_mkeep_alive_hist_info_v1 { uint32 first_pktsend_ts; /**< timestamp(ms): packet was sent */ uint32 first_txs_ts; /**< timestamp(ms): received the first txstatus */ @@ -6263,6 +7413,7 @@ typedef struct wl_mkeep_alive_hist_req_v1 { uint16 flags; /**< mkeepalive idx, operation codes */ uint16 count; /**< number of results */ uint16 max; /**< maximum number of history */ + uint16 PAD; wl_mkeep_alive_hist_info_v1_t info[]; /**< struct array of length count */ } wl_mkeep_alive_hist_req_v1_t; @@ -6314,7 +7465,7 @@ typedef struct wake_pkt { /* #ifdef WLBA */ -#define WLC_BA_CNT_VERSION 1 /**< current version of wlc_ba_cnt_t */ +#define WLC_BA_CNT_VERSION_1 1 /**< current version of wlc_ba_cnt_t */ /** block ack related stats */ typedef struct wlc_ba_cnt { @@ -6361,7 +7512,6 @@ struct ampdu_tid_control { /** Support for ampdu_tx_ba_window_cfg */ #define WL_AMPDU_TX_BA_WINDOW_CFG_VER_1 1u -#define WL_AMPDU_TX_BA_WINDOW_CFG_CUR_VER WL_AMPDU_TX_BA_WINDOW_CFG_VER_1 /* 16 bits Config (5 bits reserved) and Status (2 bits reserved) */ #define WL_AMPDU_TX_BA_WINDOW_CFG_BA_WSIZE_IDX 0u @@ -6428,6 +7578,25 @@ typedef struct wl_ampdu_tx_ba_window_cfg_v1 { uint16 status[NUMPRIO]; } wl_ampdu_tx_ba_window_cfg_v1_t; +/** Support for ampdu_rx_ba_window_cfg */ +#define WL_AMPDU_RX_BA_WINDOW_CFG_VER_1 1u + +/** structure for per tid ampdu BA window configuration */ +typedef struct wl_ampdu_rx_ba_window_cfg_v1 { + uint16 version; + uint16 length; /* length of the entire structurer+len+payload. */ + /* tid bitmap:0-7 bit 0 is zero TID and follow on. + * input (SET): select tid to configure. + */ + uint8 tidbmp; + uint8 PAD[3]; + + /* Per-tid configuration. Used for GET and SET. + * * User configured RX BA window size. Range {0, max. FW supported}. + */ + uint16 ba_wsize[NUMPRIO]; +} wl_ampdu_rx_ba_window_cfg_v1_t; + /** struct for ampdu tx/rx aggregation control */ struct ampdu_aggr { int8 aggr_override; /**< aggr overrided by dongle. Not to be set by host. */ @@ -6448,6 +7617,11 @@ struct ampdu_retry_tid { uint8 retry; /**< retry value */ }; +struct ampdu_timeout_tid { + uint8 timeout[NUMPRIO]; /* Timeout per TID */ + uint8 bitmap; /* Bitmap for each TID */ +}; + #define BDD_FNAME_LEN 32 /**< Max length of friendly name */ typedef struct bdd_fname { uint8 len; /**< length of friendly name */ @@ -6568,11 +7742,11 @@ typedef enum { typedef struct wl_maccapture_params { uint8 gpio_sel; uint8 la_mode; /* TRUE: GPIO Out Enabled */ - uint8 PAD[2]; + uint8 PAD[2]; uint32 start_ptr; /* Start address to store */ uint32 stop_ptr; /* Stop address to store */ uint8 optn_bmp; /* Options */ - uint8 PAD[3]; + uint8 PAD[3]; /* Don't change the order after this nor * add anything in betw. Code uses offsets to populate * registers @@ -6624,6 +7798,7 @@ enum { #define ENABLE_NET_OFFLOAD_BIT 10 /** report found/lost events for SSID and BSSID networks seperately */ #define REPORT_SEPERATELY_BIT 11 +#define PFN_FULL_SCAN_RESULT_BIT 12 #define SORT_CRITERIA_MASK 0x0001 #define AUTO_NET_SWITCH_MASK 0x0002 @@ -6637,7 +7812,9 @@ enum { #define SUPPRESS_SSID_MASK 0x0200 #define ENABLE_NET_OFFLOAD_MASK 0x0400 /** report found/lost events for SSID and BSSID networks seperately */ -#define REPORT_SEPERATELY_MASK 0x0800 +#define REPORT_SEPARATELY_MASK 0x0800 +#define REPORT_SEPERATELY_MASK REPORT_SEPARATELY_MASK // Legacy typo +#define PFNFULLSCAN_RESULT_MASK 0x1000 #define PFN_COMPLETE 1 #define PFN_INCOMPLETE 0 @@ -6657,11 +7834,16 @@ enum { #define MAX_EPNO_HIDDEN_SSID 8 #define MAX_WHITELIST_SSID 2 +#define WL_PFN_SHORTSSID_LEN 4u +#define WL_PFN_SUBNET_FLAGS_IS_SHORT_SSID 0x01u /* subnet flags bit 0 */ +#define WL_PFN_SUBNET_FLAGS_MATCH_SHORT_SSID 0x02u /* subnet flags bit 1 */ + /* Version 1 and 2 for various scan results structures defined below */ #define PFN_SCANRESULTS_VERSION_V1 1u #define PFN_SCANRESULTS_VERSION_V2 2u #define PFN_SCANRESULTS_VERSION_V3 3u #define PFN_SCANRESULTS_VERSION_V4 4u +#define PFN_SCANRESULTS_VERSION_V5 5u /** PFN network info structure */ typedef struct wl_pfn_subnet_info_v1 { @@ -6685,7 +7867,8 @@ typedef struct wl_pfn_subnet_info_v3 { struct ether_addr BSSID; chanspec_t chanspec; /**< with 6G chanspec only */ uint8 SSID_len; - uint8 PAD[3]; + uint8 PAD; + uint16 flags; union { uint8 SSID[32]; uint16 index; @@ -6748,7 +7931,7 @@ typedef struct wl_pfn_lscanresults_v1 { uint32 version; uint32 status; uint32 count; - wl_pfn_lnet_info_v1_t netinfo[1]; + wl_pfn_lnet_info_v1_t netinfo[BCM_FLEX_ARRAY]; } wl_pfn_lscanresults_v1_t; typedef struct wl_pfn_lscanresults_v2 { @@ -6756,7 +7939,7 @@ typedef struct wl_pfn_lscanresults_v2 { uint16 status; uint16 count; uint32 scan_ch_buckets[MAX_CHBKT_PER_RESULT]; - wl_pfn_lnet_info_v2_t netinfo[1]; + wl_pfn_lnet_info_v2_t netinfo[BCM_FLEX_ARRAY]; } wl_pfn_lscanresults_v2_t; typedef struct wl_pfn_lscanresults_v3 { @@ -6764,7 +7947,7 @@ typedef struct wl_pfn_lscanresults_v3 { uint16 status; uint16 count; uint32 scan_ch_buckets[MAX_CHBKT_PER_RESULT]; - wl_pfn_lnet_info_v3_t netinfo[1]; + wl_pfn_lnet_info_v3_t netinfo[BCM_FLEX_ARRAY]; } wl_pfn_lscanresults_v3_t; /**this is used to report on 1-* pfn scan results */ @@ -6772,7 +7955,7 @@ typedef struct wl_pfn_scanresults_v1 { uint32 version; uint32 status; uint32 count; - wl_pfn_net_info_v1_t netinfo[1]; + wl_pfn_net_info_v1_t netinfo[BCM_FLEX_ARRAY]; } wl_pfn_scanresults_v1_t; typedef struct wl_pfn_scanresults_v2 { @@ -6780,7 +7963,7 @@ typedef struct wl_pfn_scanresults_v2 { uint32 status; uint32 count; uint32 scan_ch_bucket; - wl_pfn_net_info_v2_t netinfo[1]; + wl_pfn_net_info_v2_t netinfo[BCM_FLEX_ARRAY]; } wl_pfn_scanresults_v2_t; typedef struct wl_pfn_scanresults_v3 { @@ -6788,7 +7971,7 @@ typedef struct wl_pfn_scanresults_v3 { uint32 status; uint32 count; uint32 scan_ch_bucket; - wl_pfn_net_info_v3_t netinfo[1]; + wl_pfn_net_info_v3_t netinfo[BCM_FLEX_ARRAY]; } wl_pfn_scanresults_v3_t; #define WL_PFN_SCANRESULTS_SCAN_TYPE_HA 0u @@ -6803,9 +7986,19 @@ typedef struct wl_pfn_scanresults_v4 { uint16 flags; uint32 count; uint32 scan_ch_bucket; - wl_pfn_net_info_v2_t netinfo[1]; + wl_pfn_net_info_v2_t netinfo[BCM_FLEX_ARRAY]; } wl_pfn_scanresults_v4_t; +typedef struct wl_pfn_scanresults_v5 { + uint16 version; + uint16 length; + uint16 status; + uint16 flags; + uint32 count; + uint32 scan_ch_bucket; + wl_pfn_net_info_v3_t netinfo[BCM_FLEX_ARRAY]; +} wl_pfn_scanresults_v5_t; + typedef struct wl_pfn_significant_net { uint16 flags; uint16 channel; @@ -6813,7 +8006,7 @@ typedef struct wl_pfn_significant_net { int8 rssi[PFN_SWC_RSSI_WINDOW_MAX]; } wl_pfn_significant_net_t; -#define PFN_SWC_SCANRESULT_VERSION 1 +#define PFN_SWC_SCANRESULT_VERSION_1 1 typedef struct wl_pfn_swc_results { uint32 version; @@ -6833,7 +8026,7 @@ typedef struct wl_pfn_scanhist_bssid_v1 { uint32 version; uint32 status; uint32 count; - wl_pfn_net_info_bssid_v1_t netinfo[1]; + wl_pfn_net_info_bssid_v1_t netinfo[BCM_FLEX_ARRAY]; } wl_pfn_scanhist_bssid_v1_t; /* v2 for this struct is skiped to match with other struct v3 version */ @@ -6843,21 +8036,16 @@ typedef struct wl_pfn_net_info_bssid_v3 { uint16 flags; /**< (e.g. partial scan, off channel) */ uint16 timestamp; /**< age in seconds */ int8 RSSI; /**< receive signal strength (in dBm) */ - uint8 PAD[2]; + uint8 PAD[3]; } wl_pfn_net_info_bssid_v3_t; typedef struct wl_pfn_scanhist_bssid_v3 { uint32 version; uint32 status; uint32 count; - wl_pfn_net_info_bssid_v3_t netinfo[1]; + wl_pfn_net_info_bssid_v3_t netinfo[BCM_FLEX_ARRAY]; } wl_pfn_scanhist_bssid_v3_t; -#ifndef WL_PFN_NET_INFO_BSSID_TYPEDEF_HAS_ALIAS -typedef wl_pfn_net_info_bssid_v1_t wl_pfn_net_info_bssid_t; -typedef wl_pfn_scanhist_bssid_v1_t wl_pfn_scanhist_bssid_t; -#endif /* WL_PFN_NET_INFO_BSSID_TYPEDEF_HAS_ALIAS */ - /* Version 1 and 2 for various single scan result */ #define PFN_SCANRESULT_VERSION_V1 1 #define PFN_SCANRESULT_VERSION_V2 2 @@ -6903,7 +8091,7 @@ typedef struct wl_pfn_scan_all_gone_event_v1 { uint16 version; uint16 length; uint16 flags; - uint16 pad; + uint16 PAD; } wl_pfn_scan_all_gone_event_v1_t; #define WL_PFN_MAX_RAND_LIMIT 20u @@ -6955,15 +8143,11 @@ typedef struct wl_pfn_param_v3 { int32 slow_freq; /**< slow scan period */ uint8 min_bound; /**< pfn scan period randomization - lower bound % */ uint8 max_bound; /**< pfn scan period randomization - upper bound % */ - uint8 pfn_lp_scan_disable; /* add support to enable/disable scan-core scan for PNO */ - uint8 PAD[1]; /**< Pad to 32-bit alignment */ + uint8 pfn_lp_scan_disable; /**< unused */ + uint8 pfn_lp_scan_cnt; /* add support to insert LP PNO scan */ + /* interleaved with HP PNO scan */ } wl_pfn_param_v3_t; -#ifndef PFN_PARAM_HAS_ALIAS -typedef wl_pfn_param_v2_t wl_pfn_param_t; -#define PFN_VERSION PFN_VERSION_V2 -#endif - typedef struct wl_pfn_bssid { struct ether_addr macaddr; /* Bit4: suppress_lost, Bit3: suppress_found */ @@ -7049,7 +8233,7 @@ typedef struct wl_pfn_capabilities { #define GSCAN_SEND_ALL_RESULTS_MASK (1 << 0) #define GSCAN_ALL_BUCKETS_IN_FIRST_SCAN_MASK (1 << 3) #define GSCAN_CFG_FLAGS_ONLY_MASK (1 << 7) -#define WL_GSCAN_CFG_VERSION 1 +#define WL_GSCAN_CFG_VERSION_1 1 typedef struct wl_pfn_gscan_cfg { uint16 version; /** @@ -7072,7 +8256,7 @@ typedef struct wl_pfn_gscan_cfg { uint8 count_of_channel_buckets; uint8 retry_threshold; uint16 lost_ap_window; - wl_pfn_gscan_ch_bucket_cfg_t channel_bucket[1]; + wl_pfn_gscan_ch_bucket_cfg_t channel_bucket[BCM_FLEX_ARRAY]; } wl_pfn_gscan_cfg_t; #define WL_PFN_REPORT_ALLNET 0 @@ -7095,10 +8279,10 @@ typedef struct wl_pfn_list { uint32 version; uint32 enabled; uint32 count; - wl_pfn_t pfn[1]; + wl_pfn_t pfn[BCM_FLEX_ARRAY]; } wl_pfn_list_t; -#define PFN_SSID_EXT_VERSION 1 +#define PFN_SSID_EXT_VERSION_1 1 typedef struct wl_pfn_ext { uint8 flags; @@ -7106,12 +8290,12 @@ typedef struct wl_pfn_ext { uint16 wpa_auth; /* Match the wpa auth type defined in wlioctl_defs.h */ uint8 ssid[DOT11_MAX_SSID_LEN]; uint8 ssid_len; - uint8 pad; + uint8 PAD; } wl_pfn_ext_t; typedef struct wl_pfn_ext_list { uint16 version; uint16 count; - wl_pfn_ext_t pfn_ext[1]; + wl_pfn_ext_t pfn_ext[BCM_FLEX_ARRAY]; } wl_pfn_ext_list_t; #define WL_PFN_SSID_EXT_FOUND 0x1 @@ -7128,7 +8312,7 @@ typedef struct wl_pfn_result_ssid { typedef struct wl_pfn_ssid_ext_result { uint16 version; uint16 count; - wl_pfn_result_ssid_crc32_t net[1]; + wl_pfn_result_ssid_crc32_t net[BCM_FLEX_ARRAY]; } wl_pfn_ssid_ext_result_t; #define PFN_EXT_AUTH_CODE_OPEN 1 /* open */ @@ -7148,7 +8332,7 @@ typedef struct wl_pfn_ssid_ext_result { /* Dynamic scan configuration for motion profiles */ -#define WL_PFN_MPF_VERSION 1 +#define WL_PFN_MPF_VERSION_1 1 /* Valid group IDs, may be expanded in the future */ #define WL_PFN_MPF_GROUP_SSID 0 @@ -7198,9 +8382,9 @@ typedef struct wl_pfn_override_param { * Definitions for base MPF configuration */ -#define WL_MPF_VERSION 1 -#define WL_MPF_MAX_BITS 3 -#define WL_MPF_MAX_STATES (1 << WL_MPF_MAX_BITS) +#define WL_MPF_VERSION_1 1 +#define WL_MPF_MAX_BITS 3 +#define WL_MPF_MAX_STATES (1 << WL_MPF_MAX_BITS) #define WL_MPF_STATE_NAME_MAX 12 @@ -7233,7 +8417,7 @@ typedef struct wl_mpf_state { * WLFCTS definition */ typedef struct wl_txstatus_additional_info { - uint32 rspec; + ratespec_t rspec; uint32 enq_ts; uint32 last_ts; uint32 entry_ts; @@ -7255,7 +8439,7 @@ typedef struct { uint16 period; /**< extended listen period */ uint16 interval; /**< extended listen interval */ uint16 count; /* count to repeat */ - uint16 pad; /* pad for 32bit align */ + uint16 PAD; /* pad for 32bit align */ } wl_p2po_listen_t; /** GAS state machine tunable parameters. Structure field values of 0 means use the default. */ @@ -7286,12 +8470,13 @@ typedef struct wl_p2po_find_config { * 0 means use default social channels. */ uint8 flags; - uint16 social_channels[1]; /**< Variable length array of social channels */ + uint16 social_channels[BCM_FLEX_ARRAY]; /**< Variable length array of social channels */ } wl_p2po_find_config_t; -#define WL_P2PO_FIND_CONFIG_VERSION 2 /**< value for version field */ + +#define WL_P2PO_FIND_CONFIG_VERSION_2 2u /**< value for version field */ /** wl_p2po_find_config_t flags */ -#define P2PO_FIND_FLAG_SCAN_ALL_APS 0x01 /**< Whether to scan for all APs in the p2po_find +#define P2PO_FIND_FLAG_SCAN_ALL_APS 0x01u /**< Whether to scan for all APs in the p2po_find * periodic scans of all channels. * 0 means scan for only P2P devices. * 1 means scan for P2P devices plus non-P2P APs. @@ -7308,7 +8493,8 @@ typedef struct { uint8 service_name[MAX_WFDS_SEEK_SVC_NAME_LEN]; /**< Service name to seek, not null terminated */ uint8 service_info_req_len; - uint8 service_info_req[1]; /**< Service info request, not null terminated. + uint8 service_info_req[BCM_FLEX_ARRAY]; + /**< Service info request, not null terminated. * Variable length specified by service_info_req_len. * Maximum length is MAX_WFDS_SEEK_SVC_INFO_LEN. */ @@ -7331,7 +8517,8 @@ typedef BWL_PRE_PACKED_STRUCT struct { /**< Service name , not null terminated */ uint8 service_status; uint16 service_info_len; - uint8 service_info[1]; /**< Service info, not null terminated. + uint8 service_info[BCM_FLEX_ARRAY]; + /**< Service info, not null terminated. * Variable length specified by service_info_len. * Maximum length is MAX_WFDS_ADV_SVC_INFO_LEN. */ @@ -7355,11 +8542,11 @@ typedef enum { #define ANQPO_MAX_QUERY_SIZE 256 typedef struct { uint16 max_retransmit; /**< ~0 use default, max retransmit on no ACK from peer */ - uint16 response_timeout; /**< ~0 use default, msec to wait for resp after tx packet */ + uint16 response_timeout; /**< ~0 use default, msec to wait for resp after tx pkt */ uint16 max_comeback_delay; /**< ~0 use default, max comeback delay in resp else fail */ uint16 max_retries; /**< ~0 use default, max retries on failure */ uint16 query_len; /**< length of ANQP query */ - uint8 query_data[1]; /**< ANQP encoded query (max ANQPO_MAX_QUERY_SIZE) */ + uint8 query_data[BCM_FLEX_ARRAY]; /**< ANQP encoded query (max ANQPO_MAX_QUERY_SIZE) */ } wl_anqpo_set_t; #define WL_ANQPO_FLAGS_BSSID_WILDCARD 0x0001 @@ -7383,35 +8570,31 @@ typedef struct { #define ANQPO_MAX_PEER_LIST 64 typedef struct { - uint16 count; /**< number of peers in list */ - wl_anqpo_peer_v1_t peer[1]; /**< max ANQPO_MAX_PEER_LIST */ + uint16 count; /**< number of peers in list */ + wl_anqpo_peer_v1_t peer[BCM_FLEX_ARRAY]; /**< max ANQPO_MAX_PEER_LIST */ } wl_anqpo_peer_list_v1_t; typedef struct { - uint16 version; /** -typedef BWL_PRE_PACKED_STRUCT struct awdl_dfsp_params_tlv { - uint8 type; - uint16 len; - uint8 ie[]; /* variable length */ -} BWL_POST_PACKED_STRUCT awdl_dfsp_params_tlv_t; -#include - -#define AWDL_DFSP_BCN_TLV_VALUE_OFFSET OFFSETOF(awdl_dfsp_bcn_tlv_t, time_since_bcn) -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_dfsp_bcn_tlv { - uint8 type; - uint16 len; - uint16 time_since_bcn; /* last time beacon seen in ms */ -} BWL_POST_PACKED_STRUCT awdl_dfsp_bcn_tlv_t; -#include - -#if !defined(WLDFSP) -#define AWDL_DFSP_EVT_OFFSET OFFSETOF(awdl_dfsp_event_data_t, ie) -#define AWDL_DFSP_EVT_FLAGS_AP_ASSOC (1 << 0) -#define AWDL_DFSP_EVT_FLAGS_AP_BCNMON (1 << 1) -#define AWDL_DFSP_EVT_FLAGS_PROXY_BCSA (1 << 2) -#define AWDL_DFSP_EVT_FLAGS_PROXY_UCSA (1 << 3) -#define AWDL_DFSP_EVT_FLAGS_PROXY_PCSA (1 << 4) - -typedef struct awdl_dfsp_event_data { - uint16 flags; /* indicate what triggers the event */ - uint16 ie_len; - uint8 ie[]; /* variable length */ -} awdl_dfsp_event_data_t; - -typedef struct awdl_dfsp_stats { - uint32 dfsp_csainfra; - uint32 dfsp_csabcnmon; - uint32 dfsp_bcsarx; - uint32 dfsp_ucsarx; - uint32 dfsp_pcsarx; - uint32 dfsp_bcsatx; - uint32 dfsp_ucsatx; - uint32 dfsp_pcsatx; - uint32 dfsp_ucsatxfail; - uint32 dfsp_evtnotif; - uint32 dfsp_evtsuspect; - uint32 dfsp_evtresume; -} awdl_dfsp_stats_t; - -/* awdl peer as a DFS Proxy */ -#define AWDL_DFSP_CFG_VERSION 1 -#define AWDL_DFSP_FLAGS_ENAB 0x1 -typedef struct awdl_dfsp_cfg { - uint16 version; - uint16 len; - uint16 flags; /**< bit 1 to enable/disable the feature */ - uint16 max_bcn_miss_dur; /**< maximum beacon miss duration before ceasing data tx */ - uint8 mcsp_ttl; /**< remaining number of hops allowed for pcsa message */ - uint8 bcsa_cnt; /**< repeat numbers of broadcast CSA */ - chanspec_t mon_chan; /**< passive monitoring channel spec */ - struct ether_addr mon_bssid; /**< broadcast means monitoring all */ - uint16 max_bcn_miss_dur_af; /**< maximum beacon miss duration before ceasing AF tx */ -} awdl_dfsp_cfg_t; - -#define AWDL_DFSP_UCSA_VERSION 1 -typedef struct awdl_dfsp_ucsa { - uint16 version; - uint16 len; - struct ether_addr address; - uint8 enable; - uint8 retry_cnt; /**< just in case host needs to control the value */ -} awdl_dfsp_ucsa_t; - -typedef struct awdl_dfsp_ucsa_tbl { - uint8 tbl_num; - uint8 tbl[]; -} awdl_dfsp_ucsa_tbl_t; -#endif /* defined(WLDFSP) */ - -#if defined(WLDFSP) -/* backward compatibility */ -typedef dfsp_stats_t awdl_dfsp_stats_t; -#define AWDL_DFSP_EVT_OFFSET DFSP_EVT_OFFSET -#define AWDL_DFSP_EVT_FLAGS_AP_ASSOC DFSP_EVT_FLAGS_AP_ASSOC -#define AWDL_DFSP_EVT_FLAGS_AP_BCNMON DFSP_EVT_FLAGS_AP_BCNMON -#define AWDL_DFSP_EVT_FLAGS_PROXY_BCSA DFSP_EVT_FLAGS_PROXY_BCSA -#define AWDL_DFSP_EVT_FLAGS_PROXY_UCSA DFSP_EVT_FLAGS_PROXY_UCSA -#define AWDL_DFSP_EVT_FLAGS_PROXY_PCSA DFSP_EVT_FLAGS_PROXY_PCSA -#define AWDL_DFSP_CFG_VERSION 1 -#define AWDL_DFSP_FLAGS_ENAB DFSP_FLAGS_ENAB -typedef dfsp_cfg_t awdl_dfsp_cfg_t; -#define AWDL_DFSP_UCSA_VERSION 1 -typedef dfsp_ucsa_t awdl_dfsp_ucsa_t; -typedef dfsp_ucsa_tbl_t awdl_dfsp_ucsa_tbl_t; -#endif /* !WLDFSP */ - -/* AWDL additional capability indicator */ -typedef uint32 awdl_cap_mask_t; - -#define WLC_AWDL_CAP_SEC_PAYLOAD 0x1u -#define WLC_AWDL_CAP_CCA_STATS 0x2u -#define WLC_AWDL_CAP_VERSION 2u -#define WLC_AWDL_CAP_BMAP_SIZE sizeof(awdl_cap_mask_t) - -typedef struct awdl_cap_info { - uint16 version; /* Cap structure version */ - uint16 length; /* Length: Includes version - + length + variable - data - 1byte(uint8) - */ - uint8 awdl_cap[0]; /* Variable size data */ -} awdl_cap_info_t; - -typedef struct awdl_af_sec_payload { - uint16 version; /* Version of this structure */ - uint16 length; /* Length of this entire struct including payload */ - uint16 pri_pload_bm; /* Primary payload bitmask */ - uint16 sec_pload_bm; /* Secondary payload bitmask */ - uint8 payload[]; /* Secondary Payload */ -} awdl_af_sec_payload_t; - -typedef struct awdl_config_params { - uint32 version; - uint8 awdl_chan; /**< awdl channel */ - uint8 guard_time; /**< Guard Time */ - uint16 aw_period; /**< AW interval period */ - uint16 aw_cmn_length; /**< Radio on Time AW */ - uint16 action_frame_period; /**< awdl action frame period */ - uint16 awdl_pktlifetime; /**< max packet life time in msec for awdl action frames */ - uint16 awdl_maxnomaster; /**< max master missing time */ - uint16 awdl_extcount; /**< Max extended period count for traffic */ - uint16 aw_ext_length; /**< AW ext period */ - uint16 awdl_nmode; /**< Operation mode of awdl interface; * 0 - Legacy mode - * 1 - 11n rate only * 2 - 11n + ampdu rx/tx - */ - struct ether_addr ea; /**< destination bcast/mcast address to which action frame - * need to be sent - */ -} awdl_config_params_t; - -typedef struct wl_awdl_action_frame { - uint16 len_bytes; - uint8 awdl_action_frame_data[1]; -} wl_awdl_action_frame_t; - -#define WL_AWDL_ACTION_FRAME_FIXED_LEN OFFSETOF(wl_awdl_action_frame_t, awdl_sync_frame) - -typedef struct awdl_peer_node { - uint32 type_state; /**< Master, slave , etc.. */ - uint16 aw_counter; /**< avail window counter */ - int8 rssi; /**< rssi last af was received at */ - int8 last_rssi; /**< rssi in the last AF */ - uint16 tx_counter; /** -typedef BWL_PRE_PACKED_STRUCT struct awdl_oob_af_params { - struct ether_addr bssid; - struct ether_addr dst_mac; - uint32 channel; - uint32 dwell_time; - uint32 flags; - uint32 pkt_lifetime; - uint32 tx_rate; - uint32 max_retries; /**< for unicast frames only */ - uint16 payload_len; - uint8 payload[1]; /**< complete AF payload */ -} BWL_POST_PACKED_STRUCT awdl_oob_af_params_t; -#include - -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_oob_af_params_async { - uint32 tx_time; /**< tsf time to transmit, in usec */ - uint16 tag; /**< packet tag */ - struct ether_addr bssid; - struct ether_addr dst_mac; - uint32 channel; - uint32 dwell_time; - uint32 flags; - uint32 pkt_lifetime; - uint32 tx_rate; - uint32 max_retries; /**< for unicast frames only */ - uint16 payload_len; - uint8 payload[1]; /**< complete AF payload */ -} BWL_POST_PACKED_STRUCT awdl_oob_af_params_async_t; -#include - -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_oob_af_params_auto { - uint32 tx_chan_map; /**< bitmap for the channels in the chan seq to transmit the af */ - uint32 tx_aws_offset; /**< time to transmit from the aw start, in usec */ - struct ether_addr bssid; - struct ether_addr dst_mac; - uint32 channel; - uint32 dwell_time; - uint32 flags; - uint32 pkt_lifetime; - uint32 tx_rate; - uint32 max_retries; /**< for unicast frames only */ - uint16 payload_len; - uint8 payload[1]; /**< complete AF payload */ -} BWL_POST_PACKED_STRUCT awdl_oob_af_params_auto_t; -#include - -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_sync_params { - uint8 type; /**< Type */ - uint16 param_len; /**< sync param length */ - uint8 tx_chan; /**< tx channel */ - uint16 tx_counter; /**< tx down counter */ - uint8 master_chan; /**< master home channel */ - uint8 guard_time; /**< Guard Time */ - uint16 aw_period; /**< AW period */ - uint16 action_frame_period; /**< awdl action frame period */ - uint16 awdl_flags; /**< AWDL Flags */ - uint16 aw_ext_length; /**< AW extention len */ - uint16 aw_cmn_length; /**< AW common len */ - uint16 aw_remaining; /**< Remaining AW length */ - uint8 min_ext; /**< Minimum Extention count */ - uint8 max_ext_multi; /**< Max multicast Extention count */ - uint8 max_ext_uni; /**< Max unicast Extention count */ - uint8 max_ext_af; /**< Max af Extention count */ - struct ether_addr current_master; /**< Current Master mac addr */ - uint8 presence_mode; /**< Presence mode */ - uint8 reserved; - uint16 aw_counter; /**< AW seq# */ - uint16 ap_bcn_alignment_delta; /**< AP Beacon alignment delta */ -} BWL_POST_PACKED_STRUCT awdl_sync_params_t; -#include - -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_channel_sequence { - uint8 aw_seq_len; /**< AW seq length */ - uint8 aw_seq_enc; /**< AW seq encoding */ - uint8 aw_seq_duplicate_cnt; /**< AW seq dupilcate count */ - uint8 seq_step_cnt; /**< Seq spet count */ - uint16 seq_fill_chan; /**< channel to fill in; 0xffff repeat current channel */ - uint8 chan_sequence[1]; /**< Variable list of channel Sequence */ -} BWL_POST_PACKED_STRUCT awdl_channel_sequence_t; -#include -#define WL_AWDL_CHAN_SEQ_FIXED_LEN OFFSETOF(awdl_channel_sequence_t, chan_sequence) - -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_election_info { - uint8 election_flags; /**< Election Flags */ - uint16 election_ID; /**< Election ID */ - uint32 self_metrics; -} BWL_POST_PACKED_STRUCT awdl_election_info_t; -#include - -/* This is the super set of the one above. Will retire that one once this one is established */ -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_election_tree_info { - uint8 election_flags; /**< Election Flags */ - uint16 election_ID; /**< Election ID */ - uint32 self_metrics; - int8 close_sync_rssi_thld; - int8 master_rssi_boost; - int8 edge_sync_rssi_thld; - int8 close_range_rssi_thld; - int8 mid_range_rssi_thld; - uint8 max_higher_masters_close_range; - uint8 max_higher_masters_mid_range; - uint8 max_tree_depth; - /* read only */ - struct ether_addr top_master; /**< top Master mac addr */ - uint32 top_master_self_metric; - uint8 current_tree_depth; - - uint8 edge_master_dwell_cnt; - struct ether_addr private_top_master; /**< private top Master mac addr */ - uint32 private_top_master_metric; - uint32 private_election_ID; - uint8 private_distance_from_top; -} BWL_POST_PACKED_STRUCT awdl_election_tree_info_t; -#include - -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_election_params_tlv { - uint8 type; /**< Type */ - uint16 param_len; /**< Election param length */ - uint8 election_flags; /**< Election Flags */ - uint16 election_ID; /**< Election ID */ - uint8 dist_top; /**< Distance from Top */ - uint8 rsvd; /**< Reserved */ - struct ether_addr top_master; /**< Top Master mac addr */ - uint32 top_master_metrics; - uint32 self_metrics; - uint8 pad[2]; /**< Padding */ -} BWL_POST_PACKED_STRUCT awdl_election_params_tlv_t; -#include - -/* - * Definition in DINGO - */ -typedef struct awdl_opmode_v2 { - uint8 mode; /* 0 - Auto; 1 - Fixed; 2 - Forced */ - uint8 role; /* 0 - slave; 1 - non-elect master; 2 - master */ - uint16 bcast_tu; /* Bcasting period(TU) for non-elect master */ - struct ether_addr master; /* Address of master to sync to */ - uint16 cur_bcast_tu; /* Current Bcasting Period(TU) */ - uint8 master_type; - uint8 dist_top; - uint16 cluster_id; - uint32 tsf_offset_h; - uint32 tsf_offset_l; -} awdl_opmode_v2_t; - -typedef struct awdl_payload { - uint16 len; /**< Payload length */ - uint8 payload[1]; /**< Payload */ -} awdl_payload_t; - -typedef struct awdl_long_payload { - uint8 long_psf_period; /**< transmit every long_psf_perios AWs */ - uint8 long_psf_tx_offset; /**< delay from aw_start */ - uint16 len; /**< Payload length */ - uint8 payload[1]; /**< Payload */ -} awdl_long_payload_t; - -/* Values for awdl_opmode_t.role */ -#define AWDL_ROLE_SLAVE 0 -#define AWDL_ROLE_NE_MASTER 1 -#define AWDL_ROLE_MASTER 2 - -#define SYNC_ROLE(role) (role & 0x0f) - -/* For NAN-AWDL concurrent master type */ -/* - SELF: self master, mac address can be NULL and mgmt interface mac is used - AWDL: align to AWDL master, AWDL desired mac master address must be provided. - NAN: align to NAN master, NAN target master mac address must be provided. - BOTH: align to both NAN/AWDL master, both mac addresses must be provided. - has to guarantee the NAN and AWDL master is in the same tree. -*/ -#define SYNC_MASTER_SELF 1 -#define SYNC_MASTER_AWDL 2 -#define SYNC_MASTER_NAN 3 -#define SYNC_MASTER_BOTH 4 - -/* use uper 4-bit to be the SYNC_MASTER_TYPE */ -#define SYNC_MASTER_TYPE(role) ((role & 0xf0) >> 4) - -/* - * Definitions on PHO, BIS, TRUNK & IGU branches - */ -typedef struct awdl_opmode_v1 { - uint8 mode; /* 0 - Auto; 1 - Fixed */ - uint8 role; /* 0 - slave; 1 - non-elect master; 2 - master */ - uint16 bcast_tu; /* Bcasting period(TU) for non-elect master */ - struct ether_addr master; /* Address of master to sync to */ - uint16 cur_bcast_tu; /* Current Bcasting Period(TU) */ -} awdl_opmode_v1_t; - -typedef awdl_opmode_v1_t awdl_opmode_t; - -typedef union awdl_opmode_un { - awdl_opmode_v1_t opmode_v1; - awdl_opmode_v2_t opmode_v2; -} awdl_opmode_un_t; - -typedef struct awdl_extcount { - uint8 minExt; /**< Min extension count */ - uint8 maxExtMulti; /**< Max extension count for mcast packets */ - uint8 maxExtUni; /**< Max extension count for unicast packets */ - uint8 maxAfExt; /**< Max extension count */ -} awdl_extcount_t; - -#define AWDL_OPMODE_AUTO 0 -#define AWDL_OPMODE_FIXED 1 -#define AWDL_OPMODE_FORCED 2 /* Fixed Mode with Forced_mode on */ - -/** peer add/del operation */ -typedef struct awdl_peer_op { - uint8 version; - uint8 opcode; /**< see opcode definition */ - struct ether_addr addr; - uint8 mode; - /* add other fixed fields here and increase the version number */ - /* 0 or more TLVs at the end */ -} awdl_peer_op_t; - -/** peer op table */ -typedef struct awdl_peer_op_tbl { - uint16 len; /**< length */ - uint8 tbl[1]; /**< Peer table */ -} awdl_peer_op_tbl_t; - -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_peer_op_node { - struct ether_addr addr; - uint32 flags; /**< Flags to indicate various states */ - uint16 chanseq_len; - uint8 chanseq[1]; -} BWL_POST_PACKED_STRUCT awdl_peer_op_node_t; -#include - -/* awdl_peer_op_node_t flags */ -#define AWDL_PEER_NODE_OP_FLAG_HT 0x01 -#define AWDL_PEER_NODE_OP_FLAG_AMPDU 0x02 -#define AWDL_PEER_NODE_OP_FLAG_PM 0x04 -#define AWDL_PEER_NODE_OP_FLAG_ABAND 0x08 -#define AWDL_PEER_NODE_OP_FLAG_QOS 0x10 -#define AWDL_PEER_NODE_OP_FLAG_AWDL 0x20 -#define AWDL_PEER_NODE_OP_FLAG_VHT 0x40 -#define AWDL_PEER_OP_CUR_VER 0 - -#define AWDL_STATS_VERSION_3 3 -#define AWDL_STATS_CURRENT_VERSION AWDL_STATS_VERSION_3 - -/** AWDL related statistics */ -typedef struct awdl_stats_core_v3 { - uint32 slotstart; /* AW slot_start */ - uint32 slotend; /* AW slot_end */ - uint32 slotskip; /* AW slot_skip */ - uint32 slotstart_partial; /* AW slot resume */ - uint32 slotend_partial; /* AW slot pre-empt */ - uint32 psfstart; /* PSF slot_start */ - uint32 psfend; /* PSF slot_end */ - uint32 psfskip; /* PSF slot_skip */ - uint32 psfreqfail; /* PSF timeslot register fail */ - uint32 psfcnt; /* Number of PSFs */ - uint32 micnt; /* Number of MI frames */ - uint32 chansw; /* Total number of chan switches */ - uint32 awrealignfail; /* No of awrealign failures */ - uint32 datatx; - uint32 datarx; - uint32 txdrop; - uint32 rxdrop; - uint32 monrx; - uint32 txsupr; - uint32 rx80211; -} awdl_stats_core_v3_t; - -typedef struct awdl_stats_cmn_v3 { - uint32 afrx; - uint32 aftx; - uint32 lostmaster; - uint32 misalign; - uint32 aws; - uint32 aw_dur; - uint32 debug; - uint32 afrxdrop; - uint32 awdrop; - uint32 noawchansw; - uint32 peeropdrop; - uint16 chancal; /* Used as a counter to track AWDL slots < 60TU */ - uint16 nopreawint; - uint32 awdropchsw; - uint32 nopreawchsw; - uint32 nopreawprep; - uint32 aws_misalign; - uint32 txeval_fail; - uint32 infra_reqrcq; - uint32 awdl_reqtxq; - uint32 psfchanswtchskip; /* # chan. sw skipped during PSF xmit */ - uint32 psfstateupdskip; /* # of PM updates skipped */ - uint32 infra_offchpsf; - uint32 awdl_offchpsf; - uint32 chseqreq; - uint32 peerdelreq; - uint32 awend; - uint32 awrealign; /* No of AW realigns */ - uint32 awchmismatch; /* Channel mismatch between expcted ch and scheduled ch */ -} awdl_stats_cmn_v3_t; - -typedef struct awdl_stats_v3 { - uint16 version; - uint16 length; - awdl_stats_cmn_v3_t cmnstats; - awdl_stats_core_v3_t corestats[MAX_NUM_D11CORES]; - awdl_dfsp_stats_t dfspstats; -} awdl_stats_v3_t; - -typedef struct awdl_stats_v2 { - uint32 afrx; - uint32 aftx; - uint32 datatx; - uint32 datarx; - uint32 txdrop; - uint32 rxdrop; - uint32 monrx; - uint32 lostmaster; - uint32 misalign; - uint32 aws; - uint32 aw_dur; - uint32 debug; - uint32 txsupr; - uint32 afrxdrop; - uint32 awdrop; - uint32 noawchansw; - uint32 rx80211; - uint32 peeropdrop; - uint16 chancal; - uint16 nopreawint; - uint32 awdropchsw; - uint32 nopreawchsw; - uint32 nopreawprep; - uint32 aws_misalign; - uint32 txeval_fail; - uint32 infra_reqrcq; - uint32 awdl_reqtxq; - uint32 psfchanswtchskip; /* # chan. sw skipped during PSF xmit */ - uint32 psfstateupdskip; /* # of PM updates skipped */ - uint32 dfsp_csainfra; - uint32 dfsp_csabcnmon; - uint32 dfsp_bcsarx; - uint32 dfsp_ucsarx; - uint32 dfsp_pcsarx; - uint32 dfsp_bcsatx; - uint32 dfsp_ucsatx; - uint32 dfsp_pcsatx; - uint32 dfsp_ucsatxfail; - uint32 dfsp_evtnotif; - uint32 dfsp_evtsuspect; - uint32 dfsp_evtresume; -} awdl_stats_v2_t; - -typedef struct awdl_stats_v1 { - uint32 afrx; - uint32 aftx; - uint32 datatx; - uint32 datarx; - uint32 txdrop; - uint32 rxdrop; - uint32 monrx; - uint32 lostmaster; - uint32 misalign; - uint32 aws; - uint32 aw_dur; - uint32 debug; - uint32 txsupr; - uint32 afrxdrop; - uint32 awdrop; - uint32 noawchansw; - uint32 rx80211; - uint32 peeropdrop; - uint16 chancal; - uint16 nopreawint; - uint32 awdropchsw; - uint32 nopreawchsw; - uint32 nopreawprep; - uint32 infra_offchpsf; - uint32 awdl_offchpsf; - uint32 pmnoack; - uint32 scanreq; - uint32 chseqreq; - uint32 peerdelreq; - uint32 aws_misalign; - uint32 txeval_fail; - uint32 infra_reqrcq; - uint32 awdl_reqtxq; - uint32 psfchanswtchskip; /* # chan. sw skipped during PSF xmit */ - uint32 psfstateupdskip; /* # of PM updates skipped */ - uint32 dfsp_csainfra; - uint32 dfsp_csabcnmon; - uint32 dfsp_bcsarx; - uint32 dfsp_ucsarx; - uint32 dfsp_pcsarx; - uint32 dfsp_bcsatx; - uint32 dfsp_ucsatx; - uint32 dfsp_pcsatx; - uint32 dfsp_ucsatxfail; - uint32 dfsp_evtnotif; - uint32 dfsp_evtsuspect; - uint32 dfsp_evtresume; -} awdl_stats_v1_t; - -typedef struct awdl_uct_stats { - uint32 aw_proc_in_aw_sched; - uint32 aw_upd_in_pre_aw_proc; - uint32 pre_aw_proc_in_aw_set; - uint32 ignore_pre_aw_proc; - uint32 miss_pre_aw_intr; - uint32 aw_dur_zero; - uint32 aw_sched; - uint32 aw_proc; - uint32 pre_aw_proc; - uint32 not_init; - uint32 null_awdl; -} awdl_uct_stats_t; - -/* peer opcode */ -#define AWDL_PEER_OP_ADD 0 -#define AWDL_PEER_OP_DEL 1 -#define AWDL_PEER_OP_INFO 2 -#define AWDL_PEER_OP_UPD 3 - -/**AWDL Piggy backed scan */ -typedef struct wl_awdl_pscan_params { - wlc_ssid_t ssid; /**< default: {0, ""} */ - struct ether_addr bssid; /**< default: bcast */ - uint8 scan_type; /**< active or passive, 0 use default */ - uint8 pad; /**< pad */ - int32 nprobes; /**< -1 use default, number of probes per channel */ - int32 aw_seq_num; /**< count AW sequence nunbers to be piggy backed for scan */ - int32 nssid; /**< count of ssid in list */ - int32 rsvd; /**< Reserved */ - uint16 aw_counter_list[1]; /**< This is a list contains in following order - * - List aw seq numbers - * - List of SSID's 4 byte aligned. - */ -} wl_awdl_pscan_params_t; - -typedef struct wl_pscan_params { - uint32 version; - uint16 action; /**< PSCAN action type: FW or Host initiated pscan or abort pscan */ - uint16 sync_id; - wl_awdl_pscan_params_t params; -} wl_pscan_params_t; - -#define WL_AWDL_PSCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_awdl_pscan_params_t, aw_counter_list)) -#define WL_AWDL_MAX_NUM_AWSEQ 64 -#define AWDL_PSCAN_REQ_VERSION 1 - -/** awdl pscan action type values */ -#define AWDL_HOST_PSCAN 0 /**< Host Initiated PSCAN */ -#define AWDL_FW_PSCAN 1 /**< Firmware Initiated PSCAN */ -#define AWDL_ABORT_PSCAN 2 /**< Abort any PSCAN */ - -/* "aftxmode" iovar values */ -#define AWDL_AFTXMODE_AUTO 0 /**< Send AF on AWDL channel best effort while outside AW */ - -/* --- Deprecated ---- */ -#define AWDL_AFTXMODE_INFRA 1 /**< Send AF on Infra channel while outside AW */ -#define AWDL_AFTXMODE_CUR_CHAN 2 /**< Send AF on Current channel while outside AW */ -/* --- Deprecated ---- */ - -#define AWDL_AFTXMODE_SUPPRESS 3 /**< Suppress AF Tx */ -#define AWDL_AFTXMODE_SYNC_PREAW 4 /**< Send AF on master channel/s always in pre AW time */ -#define AWDL_AFTXMODE_LAST 4 /**< Last AWDL_AFTXMODE_XXX */ - -typedef struct awdl_pw_opmode { - struct ether_addr top_master; /**< Peer mac addr */ - uint8 mode; /**< 0 - normal; 1 - fast mode */ -} awdl_pw_opmode_t; - -/** i/f request */ -typedef struct wl_awdl_if2 { - int32 cfg_idx; - int32 up; - struct ether_addr bssid; - struct ether_addr if_addr; -} wl_awdl_if2_t; - -typedef struct _aw_start { - uint8 role; - struct ether_addr master; - uint8 aw_seq_num; -} aw_start_t; - -typedef struct _aw_extension_start { - uint8 aw_ext_num; -} aw_extension_start_t; - -typedef struct _awdl_peer_state { - struct ether_addr peer; - uint8 state; -} awdl_peer_state_t; -#define AWDL_PEER_STATE_OPEN 0 -#define AWDL_PEER_STATE_CLOSE 1 - -typedef struct _awdl_sync_state_changed { - uint8 new_role; - struct ether_addr master; -} awdl_sync_state_changed_t; - -typedef struct _awdl_sync_state { - uint8 role; - struct ether_addr master; - uint8 PAD; - uint32 continuous_election_enable; -} awdl_sync_state_t; - -typedef struct _awdl_aw_ap_alignment { - uint32 enabled; - int32 offset; - uint32 align_on_dtim; -} awdl_aw_ap_alignment_t; - -typedef struct _awdl_peer_stats { - uint32 version; - struct ether_addr address; - uint8 clear; - int8 rssi; - int8 avg_rssi; - uint8 txRate; - uint8 rxRate; - uint8 PAD; - uint32 numTx; - uint32 numTxRetries; - uint32 numTxFailures; -} awdl_peer_stats_t; - -#define MAX_NUM_AWDL_KEYS 4 -typedef struct _awdl_aes_key { - uint32 version; - int32 enable; - struct ether_addr awdl_peer; - uint8 keys[MAX_NUM_AWDL_KEYS][16]; - uint8 PAD[2]; -} awdl_aes_key_t; - -/* AWDL CCA Stats */ - -/* CCA Counters Delta @ Chan. boundary sent by FW to host */ - -typedef struct wlc_awdl_cca_stats { - chanspec_t chanspec; /* Chanspec when CCA stats were read */ - uint16 pad; - uint32 sample_dur; /* Duration in MS for which stats were sampled */ - uint32 congest_ibss; /* Delta between IBSS - TxDUR */ - uint32 congest_obss; /* Delta between OBSS - noctg */ - uint32 interference; /* Delta between nopkt */ -} wlc_awdl_cca_stats_t; - -/* AWDL TLVs */ -typedef enum wl_awdl_tlv { - WL_AWDL_XTLV_CCA_STATS = 0x1u /* CCA Stats sent to host on chan. boundary */ -} wl_awdl_tlv_t; - -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_scan_event_data { - uint8 scan_usage; /**< Kind of scan in progress */ - uint8 nscan_chans; /**< number of channels to be scanned */ - uint8 ncached_chans; /**< number of cached channels */ - uint8 flags; - uint8 chan_list[1]; /**< List of cached channels followed by - * channels to be scanned - */ -} BWL_POST_PACKED_STRUCT awdl_scan_event_data_t; - -/* Flags */ -/* bit-0 : Used to indicate if the flags/pad is valid -* bit-1 : Slice-0 is blocked on scan. -* bit-2 : Slice-1 is blocked on scan. -* bit-7 : reserved -*/ - -#define AWDL_SCAN_EVT_DATA_FLAGS_VALID (1<<0) -#define AWDL_SCAN_EVT_DATA_FLAGS_SLICE0_BLOCKED (1<<1) -#define AWDL_SCAN_EVT_DATA_FLAGS_SLICE1_BLOCKED (1<<2) - -#include - -/* - * This structure will be supported only for pre-Koala builds. - * From Koala onwards use local adv_struct_master_local_t structure - * defined in wlc_awdl.c - */ - -#ifndef WLAWDL_USE_MASTER_LOCAL -typedef struct adv_struct_norm { - uint16 aw_counter; /**< avail window counter */ - uint16 tx_counter; - uint16 tx_delay; /**< ts_hw - ts_fw */ - uint16 period_tu; - uint16 aw_cmn_length; - uint16 aw_ext_length; - uint16 aw_period; - uint16 chan_seq0; - int8 rssi; /**< averaged RSSI value */ - uint8 guard_time; - uint8 presence_mode; - uint8 age; /**< age of this record */ - uint8 dist_top; /**< Distance from Top */ - uint8 PAD[3]; - uint32 ms; /**< time at which we received the AF */ - uint32 self_metrics; /**< election metric */ - uint32 top_master_metrics; - struct ether_addr top_master; /**< Top Master address */ - struct ether_addr addr; - struct rssi_struct rssi_win; /**< RSSI values */ -} adv_struct_norm_t; -#endif /* WLAWDL_USE_MASTER_LOCAL */ - -/* AWDL configuration/operation flags */ -#define AWDL_CONFIG_NON_AWDL_INTERFACE_FLOW_CONTROL 0x00000001 -#define AWDL_CONFIG_AWDL_INTERFACE_UPDATE 0x00000002 -/* While scanning configure channel from chan seq */ -#define AWDL_CONFIG_CHANNEL_HOP_FROM_CHAN_SEQ 0x00000004 -#define AWDL_CONFIG_TX_OFF_BEFORE_INFRA_BEACON 0x00000008 -#define AWDL_CONFIG_SUPP_PSFTX_PREAW 0x00000010 -#define AWDL_CONFIG_SUPP_PSFTX_NOACK 0x00000020 -#define AWDL_CONFIG_SUPP_PSFTX_CHANSW 0x00000040 -/* - * awdl ranging - * all the fields with multple bytes are in the little Endian order - */ - -/* Bit defines for global flags */ -#define AWDL_RANGING_ENABLE (1<<0) /**< Global enable bit */ -#define AWDL_RANGING_RESPOND (1<<1) /**< Enable responding to peer's range req */ -#define AWDL_RANGING_RANGED (1<<2) /**< V2: Report to host if ranged as target */ - -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_ranging_config { - uint16 flags; - uint8 sounding_count; /**< self initiated ranging: number of probes per peer */ - uint8 reserved; - struct ether_addr allow_mac; - /**< peer initiated ranging: the allowed peer mac - * address, a unicast (for one peer) or - * a broadcast for all. Setting it to all zeros - * means responding to none,same as not setting - * the flag bit AWDL_RANGING_RESPOND - */ -} BWL_POST_PACKED_STRUCT awdl_ranging_config_t; -#include - -/* list of peers for self initiated ranging */ -/* Bit defines for per peer flags */ -#define AWDL_RANGING_REPORT (1<<0) /**< V2: Enable reporting range to target */ -#define AWDL_SEQ_EN (1<<1) - -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_ranging_peer { - chanspec_t ranging_chanspec; /**< desired chanspec for this peer */ - uint16 flags; /**< per peer flags, report or not */ - struct ether_addr ea; /**< peer MAC address */ -} BWL_POST_PACKED_STRUCT awdl_ranging_peer_t; -#include - -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_ranging_list { - uint8 count; /**< number of MAC addresses */ - uint8 num_peers_done; /**< host set to 0, when read, shows number of peers - * completed, success or fail - */ - uint8 num_aws; /**< time period to do the ranging, specified in aws */ - awdl_ranging_peer_t rp[1]; /**< variable length array of peers */ -} BWL_POST_PACKED_STRUCT awdl_ranging_list_t; -#include - -/* ranging results, a list for self initiated ranging and one for peer initiated ranging */ -/* There will be one structure for each peer */ -#define AWDL_RANGING_STATUS_SUCCESS 1 -#define AWDL_RANGING_STATUS_FAIL 2 -#define AWDL_RANGING_STATUS_TIMEOUT 3 -#define AWDL_RANGING_STATUS_ABORT 4 /**< with partial results if sounding count > 0 */ -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_ranging_result { - uint8 status; /**< 1: Success, 2: Fail 3: Timeout 4: Aborted */ - uint8 sounding_count; /**< number of measurements completed (0 = failure) */ - struct ether_addr ea; /**< peer MAC address */ - chanspec_t ranging_chanspec; /**< Chanspec where the ranging was done */ - uint32 timestamp; /**< 32bits of the TSF timestamp ranging was completed at */ - uint32 distance; /**< mean distance in meters expressed as Q4 number. - * Only valid when sounding_count > 0. Examples: - * 0x08 = 0.5m - * 0x10 = 1m - * 0x18 = 1.5m - * set to 0xffffffff to indicate invalid number - */ - int32 rtt_var; /**< standard deviation in 10th of ns of RTTs measured. - * Only valid when sounding_count > 0 - */ -} BWL_POST_PACKED_STRUCT awdl_ranging_result_t; -#include -#define AWDL_RANGING_TYPE_HOST 1 -#define AWDL_RANGING_TYPE_PEER 2 - -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_ranging_event_data { - uint8 type; /**< 1: Result of host initiated ranging */ - /* V2: 2: Result of peer initiated ranging */ - uint8 reserved; - uint8 success_count; /**< number of peers completed successfully */ - uint8 count; /**< number of peers in the list */ - awdl_ranging_result_t rr[1]; /**< variable array of ranging peers */ -} BWL_POST_PACKED_STRUCT awdl_ranging_event_data_t; -typedef BWL_PRE_PACKED_STRUCT struct awdl_ftm_ranging_config { - uint16 flags; /* config flags */ - uint8 num_aws; /* time period to do the ranging, specified in aws */ -} BWL_POST_PACKED_STRUCT awdl_ftm_ranging_config_t; -#include - -/** awdl event config bit mask definitions */ -#define AWDL_EVENT_AW_EXT 0x01 -#define AWDL_EVENT_RANGING 0x02 -#define AWDL_RANGING_MAX_PEERS 8 -#endif /* WLAWDL */ - /* * ptk_start: iovar to start 4-way handshake for secured ranging */ @@ -8619,8 +8783,8 @@ typedef struct wl_ptk_start_iov { wl_ptk_start_sec_type_t sec_type; wl_ptk_start_role_t role; struct ether_addr peer_addr; - uint16 pad; /* reserved/32 bit alignment */ - wl_ptk_start_tlv_t tlvs[1]; + uint16 PAD; /* reserved/32 bit alignment */ + wl_ptk_start_tlv_t tlvs[BCM_FLEX_ARRAY]; } wl_ptk_start_iov_t; /* @@ -8702,7 +8866,7 @@ typedef struct wl_pkt_filter_pattern_list { uint8 list_cnt; /**< Number of elements in the list */ uint8 PAD1[1]; /**< Reserved (possible version: reserved) */ uint16 totsize; /**< Total size of this pattern list (includes this struct) */ - uint8 patterns[]; /**< Variable number of wl_pkt_filter_pattern_listel_t elements */ + uint8 patterns[]; /**< Variable number of wl_pkt_filter_pattern_listel_t elements */ } wl_pkt_filter_pattern_list_t; typedef struct wl_apf_program { @@ -8755,12 +8919,14 @@ typedef struct wl_tcp_keep_set { OFFSETOF(wl_pkt_filter_pattern_timeout_t, mask_and_pattern) #define WL_APF_INTERNAL_VERSION 1 -#define WL_APF_PROGRAM_MAX_SIZE (2 * 1024) #define WL_APF_PROGRAM_FIXED_LEN OFFSETOF(wl_apf_program_t, instrs) #define WL_APF_PROGRAM_LEN(apf_program) \ ((apf_program)->instr_len * sizeof((apf_program)->instrs[0])) #define WL_APF_PROGRAM_TOTAL_LEN(apf_program) \ (WL_APF_PROGRAM_FIXED_LEN + WL_APF_PROGRAM_LEN(apf_program)) +#ifndef WL_APF_PROGRAM_MAX_SIZE +#define WL_APF_PROGRAM_MAX_SIZE (2u * 1024u) +#endif /* WL_APF_PROGRAM_MAX_SIZE */ /** IOVAR "pkt_filter_enable" parameter. */ typedef struct wl_pkt_filter_enable { @@ -8785,11 +8951,11 @@ typedef struct wl_pkt_filter_stats { /** IOVAR "pkt_filter_ports" parameter. Configure TCP/UDP port filters. */ typedef struct wl_pkt_filter_ports { - uint8 version; /**< Be proper */ - uint8 reserved; /**< Be really proper */ - uint16 count; /**< Number of ports following */ + uint8 version; /**< Be proper */ + uint8 reserved; /**< Be really proper */ + uint16 count; /**< Number of ports following */ /* End of fixed data */ - uint16 ports[1]; /**< Placeholder for ports[] */ + uint16 ports[BCM_FLEX_ARRAY]; /**< Placeholder for ports[] */ } wl_pkt_filter_ports_t; #define WL_PKT_FILTER_PORTS_FIXED_LEN OFFSETOF(wl_pkt_filter_ports_t, ports) @@ -8806,7 +8972,7 @@ typedef struct _gtkrefresh { uint8 KCK[RSN_KCK_LENGTH]; uint8 KEK[RSN_KEK_LENGTH]; uint8 ReplayCounter[RSN_REPLAY_LEN]; -} gtk_keyinfo_t, *pgtk_keyinfo_t; +} gtk_keyinfo_t; /** Sequential Commands ioctl */ typedef struct wl_seq_cmd_ioctl { @@ -8857,7 +9023,7 @@ enum wl_pkgeng_estpwr_id { }; /* IOVAR pkteng_sweep_counters response structure */ -#define WL_PKTENG_SWEEP_COUNTERS_VERSION 1 +#define WL_PKTENG_SWEEP_COUNTERS_VERSION_1 1 typedef struct wl_pkteng_sweep_ctrs { uint16 version; /**< Version - 1 */ uint16 size; /**< Complete Size including sweep_counters */ @@ -8867,7 +9033,7 @@ typedef struct wl_pkteng_sweep_ctrs { } wl_pkteng_sweep_ctrs_t; /* IOVAR pkteng_rx_pkt response structure */ -#define WL_PKTENG_RX_PKT_VERSION 1 +#define WL_PKTENG_RX_PKT_VERSION_1 1 typedef struct wl_pkteng_rx_pkt { uint16 version; /**< Version - 1 */ uint16 size; /**< Complete Size including the packet */ @@ -8877,6 +9043,7 @@ typedef struct wl_pkteng_rx_pkt { #define WL_PKTENG_RU_FILL_VER_1 1u #define WL_PKTENG_RU_FILL_VER_2 2u #define WL_PKTENG_RU_FILL_VER_3 3u +#define WL_PKTENG_RU_FILL_VER_4 4u // struct for ru packet engine typedef struct wl_pkteng_ru_v1 { @@ -8920,7 +9087,7 @@ typedef struct wl_pkteng_ru_v2 { uint8 trig_type; /* type of trigger frame */ uint8 trig_period; /* trigger tx periodicity TBD */ uint8 tgt_rssi; /* target rssi value in encoded format */ - uint8 pad[3]; /* 2 byte padding to make structure size a multiple of 32bits */ + uint8 PAD[3]; /* 2 byte padding to make structure size a multiple of 32bits */ } wl_pkteng_ru_v2_t; typedef struct wl_pkteng_ru_v3 { @@ -8942,17 +9109,45 @@ typedef struct wl_pkteng_ru_v3 { uint8 trig_tx; /* form and transmit the trigger frame */ uint8 trig_type; /* type of trigger frame */ uint8 trig_period; /* trigger tx periodicity TBD */ - uint8 tgt_rssi; /* target rssi value in encoded format */ - uint8 sub_band; /* in 160MHz case, 80L, 80U */ - uint8 pad[2]; /* 2 byte padding to make structure size a multiple of 32bits */ + uint8 tgt_rssi; /* target rssi value in encoded format */ + uint8 sub_band; /* in 160MHz case, 80L, 80U */ + uint8 betrig; /* 11BE (EHT) trigger format */ + uint8 ps160; /* PS160 indicator, 160L, 160U */ } wl_pkteng_ru_v3_t; +/* To be deleted. Keep V4 until TRUNK/RHINO SRC updated to use V3 */ +typedef struct wl_pkteng_ru_v4 { + uint16 version; /* ver is 4 */ + uint16 length; /* size of complete structure */ + uint32 num_bytes; /* approx num of bytes to calculate other required params */ + struct ether_addr dest; /* destination address for un-associated mode */ + uint16 ru_alloc_val; /* ru allocation index number */ + uint8 bw; /* bandwidth info */ + uint8 mcs_val; /* mcs allocated value */ + uint8 nss_val; /* num of spatial streams */ + uint8 cp_ltf_val ; /* GI and LTF symbol size */ + uint8 he_ltf_symb ; /* num of HE-LTF symbols */ + uint8 stbc; /* STBC support */ + uint8 coding_val; /* BCC/LDPC coding support */ + uint8 pe_category; /* PE duration 0/8/16usecs */ + uint8 dcm; /* dual carrier modulation */ + uint8 mumimo_ltfmode; /* ltf mode */ + uint8 trig_tx; /* form and transmit the trigger frame */ + uint8 trig_type; /* type of trigger frame */ + uint8 trig_period; /* trigger tx periodicity TBD */ + uint8 tgt_rssi; /* target rssi value in encoded format */ + uint8 sub_band; /* in 160MHz case, 80L, 80U */ + uint8 betrig; /* 11BE (EHT) trigger format */ + uint8 ps160; /* PS160 indicator, 160L, 160U */ + uint8 PAD[3]; /* 3B padding to make structure size a multiple of 32b */ +} wl_pkteng_ru_v4_t; + #ifndef WL_PKTENG_RU_VER /* App uses the latest version - source picks it up from wlc_types.h */ typedef wl_pkteng_ru_v3_t wl_pkteng_ru_fill_t; #endif -typedef struct wl_trig_frame_info { +typedef struct wl_trig_frame_info_v1 { /* Structure versioning and structure length params */ uint16 version; uint16 length; @@ -8984,7 +9179,58 @@ typedef struct wl_trig_frame_info { uint16 ss_alloc; uint16 tgt_rssi; uint16 usr_info_rsvd; -} wl_trig_frame_info_t; +} wl_trig_frame_info_v1_t; + +typedef struct wl_trig_frame_info_v2 { + /* Structure versioning and structure length params */ + uint16 version; + uint16 length; + /* Below params are the fields related to trigger frame contents */ + /* Common Info Params Figure 9-52d - 11ax Draft 1.1 */ + uint16 lsig_len; + uint16 trigger_type; + uint16 cascade_indication; + uint16 cs_req; + uint16 bw; + uint16 cp_ltf_type; + uint16 mu_mimo_ltf_mode; + uint16 num_he_ltf_syms; + uint16 stbc; + uint16 ldpc_extra_symb; + uint16 ap_tx_pwr; + uint16 afactor; + uint16 pe_disambiguity; + uint16 spatial_resuse; + uint16 doppler; + uint16 he_siga_rsvd; + uint16 cmn_info_rsvd; + /* User Info Params Figure 9-52e - 11ax Draft 1.1 */ + uint16 aid12; + uint16 ru_alloc; + uint16 coding_type; + uint16 mcs; + uint16 dcm; + uint16 ss_alloc; + uint16 tgt_rssi; + uint16 usr_info_rsvd; + uint16 trigger_spec; // 0: AX trigger, 1: BE trigger + /* 11BE additional Common Info fields */ + uint16 p160; + uint16 susrinfoflg; + /* 11BE additional User Info fields */ + uint16 ps160; + /* 11BE Special User Info fields */ + uint16 bwext; + uint16 eht_spatial_reuse1; + uint16 eht_spatial_reuse2; + uint16 PAD; +} wl_trig_frame_info_v2_t; + +#ifdef WL11BE +typedef wl_trig_frame_info_v2_t wl_trig_frame_info_t; +#else +typedef wl_trig_frame_info_v1_t wl_trig_frame_info_t; +#endif /* wl pkteng_stats related definitions */ #define WL_PKTENG_STATS_V1 (1) @@ -9007,15 +9253,11 @@ typedef struct wl_pkteng_stats_v2 { uint8 rssi_qdb; /**< qdB portion of the computed rssi */ uint8 version; uint16 length; - uint16 pad; + uint16 PAD; int32 rssi_per_core[WL_RSSI_ANT_MAX]; int32 rssi_per_core_qdb[WL_RSSI_ANT_MAX]; } wl_pkteng_stats_v2_t; -#ifndef WL_PKTENG_STATS_TYPEDEF_HAS_ALIAS -typedef wl_pkteng_stats_v1_t wl_pkteng_stats_t; -#endif /* WL_PKTENG_STATS_TYPEDEF_HAS_ALIAS */ - typedef struct wl_txcal_params { wl_pkteng_t pkteng; uint8 gidx_start; @@ -9046,6 +9288,7 @@ typedef struct wl_txtone_idxsweep_params { int8 gidx_step; uint8 gidx_start_percore[WL_STA_ANT_MAX]; uint8 gidx_stop_percore[WL_STA_ANT_MAX]; + uint8 PAD[3]; uint32 dwell_time; } wl_txtone_idxsweep_params; @@ -9055,7 +9298,7 @@ typedef struct wl_rssilog_params { uint8 enable; uint8 rssi_threshold; uint8 time_threshold; - uint8 pad; + uint8 PAD; } wl_rssilog_params_t; typedef struct wl_sslpnphy_papd_debug_data { @@ -9114,7 +9357,7 @@ typedef struct wl_wowl_pattern { typedef struct wl_wowl_pattern_list { uint32 count; - wl_wowl_pattern_t pattern[1]; + wl_wowl_pattern_t pattern[BCM_FLEX_ARRAY]; } wl_wowl_pattern_list_t; typedef struct wl_wowl_wakeind { @@ -9152,10 +9395,10 @@ typedef struct wl_rssi_event { * will be posted each time the RSSI of received * beacons/packets crosses a level. */ - int8 pad[3]; + int8 PAD[3]; } wl_rssi_event_t; -#define RSSI_MONITOR_VERSION 1 +#define RSSI_MONITOR_VERSION_1 1 #define RSSI_MONITOR_STOP (1 << 0) typedef struct wl_rssi_monitor_cfg { uint8 version; @@ -9179,17 +9422,20 @@ typedef struct wl_rssi_monitor_evt { * Notice that uint8 is used in configuration struct wl_chan_qual_metric_t, but uint16 is * used for report in struct cca_chan_qual_event_t. So the ID values beyond 8-bit are used * for reporting purpose only. + * (The MSBs are not used as bit-mask. These defines are values) */ #define WL_CHAN_QUAL_FULL_CCA (0x100u | WL_CHAN_QUAL_CCA) /* CCA: ibss vs. obss */ #define WL_CHAN_QUAL_FULLPM_CCA (0x200u | WL_CHAN_QUAL_CCA) /* CCA: me vs. notme, PM vs. !PM */ +#define WL_CHAN_QUAL_FULLPM_CCA_UNUSED (0x300u | WL_CHAN_QUAL_CCA) #define WL_CHAN_QUAL_FULLPM_CCA_OFDM_DESENSE (0x400u | WL_CHAN_QUAL_CCA) +#define WL_CHAN_QUAL_FULLPM_CCA_ALL_DESENSE (0x500u | WL_CHAN_QUAL_CCA) /* CCA: me vs. notme, PM vs. !PM with OFDM Desense */ #define MAX_CHAN_QUAL_LEVELS 8 typedef struct wl_chan_qual_metric { uint8 id; /**< metric ID */ - uint8 num_levels; /**< Number of entries in rssi_levels[] below */ + uint8 num_levels; /**< Number of entries in rssi_levels[] below */ uint16 flags; int16 htol[MAX_CHAN_QUAL_LEVELS]; /**< threshold level array: hi-to-lo */ int16 ltoh[MAX_CHAN_QUAL_LEVELS]; /**< threshold level array: lo-to-hi */ @@ -9206,7 +9452,7 @@ typedef struct wl_chan_qual_event { typedef struct wl_action_obss_coex_req { uint8 info; uint8 num; - uint8 ch_list[1]; + uint8 ch_list[BCM_FLEX_ARRAY]; } wl_action_obss_coex_req_t; /** IOVar parameter block for small MAC address array with type indicator */ @@ -9374,7 +9620,7 @@ typedef BWL_PRE_PACKED_STRUCT struct { typedef BWL_PRE_PACKED_STRUCT struct { uint16 structure_version; /**< Structure version number (for wl/wlu matching) */ uint16 structure_count; /**< Number of iov_bs_data_record_t records following */ - iov_bs_data_record_t structure_record[1]; /**< 0 - structure_count records */ + iov_bs_data_record_t structure_record[BCM_FLEX_ARRAY]; /**< 0 - structure_count records */ } BWL_POST_PACKED_STRUCT iov_bs_data_struct_t; #include @@ -9402,7 +9648,7 @@ typedef struct log_record { uint8 level; uint8 sub_unit; uint8 seq_num; - uint8 pad; + uint8 PAD; int32 arg; char str[MAX_ARGSTR_LEN]; char PAD[4-MAX_ARGSTR_LEN%4]; @@ -9417,7 +9663,7 @@ typedef struct wlc_extlog_results { uint16 version; uint16 record_len; uint32 num; - log_record_t logs[1]; + log_record_t logs[BCM_FLEX_ARRAY]; } wlc_extlog_results_t; typedef struct log_idstr { @@ -9476,7 +9722,7 @@ typedef struct nbr_element { uint8 reg; uint8 channel; uint8 phytype; - uint8 pad; + uint8 PAD; } nbr_element_t; #define NBR_ADD_STATIC 0 #define NBR_ADD_DYNAMIC 1 @@ -9489,7 +9735,7 @@ typedef struct nbr_rpt_elem { uint8 version; uint8 id; uint8 len; - uint8 pad; + uint8 PAD; struct ether_addr bssid; uint8 pad_1[2]; uint32 bssid_info; @@ -9523,7 +9769,7 @@ typedef struct eventmsgs_ext uint8 command; uint8 len; uint8 maxgetsize; - uint8 mask[1]; + uint8 mask[BCM_FLEX_ARRAY]; } eventmsgs_ext_t; #include @@ -9544,13 +9790,53 @@ typedef struct pcie_bus_tput_stats { uint32 count; } pcie_bus_tput_stats_t; +/* limits of dma length */ +#define DMA_LEN_MAX (65527u) +#define DMA_LEN_MIN (8u) + +/* direction of DMA */ +#define BUS_TPUT_PARAMS_FLAG_DIR_H2D 0x0u +#define BUS_TPUT_PARAMS_FLAG_DIR_D2H 0x1u + +#define BUS_TPUT_PARAMS_VERSION_1 (1u) +#include +BWL_PRE_PACKED_STRUCT struct bus_tput_params_v1 { + uint16 ver; /** + +/* direction of DMA */ +#define BUS_TPUT_STATS_FLAG_DIR_H2D 0x0u +#define BUS_TPUT_STATS_FLAG_DIR_D2H 0x1u + +/* after stats, if buf is available with string to print */ +#define BUS_TPUT_STATS_FLAG_BUF_PRINT 0x2u + +#define BUS_TPUT_STATS_VERSION_1 (1u) +#include +BWL_PRE_PACKED_STRUCT struct bus_tput_stats_v1 { + uint16 ver; /** + #define HOST_WAKEUP_DATA_VER 1 #include /* Bus interface host wakeup data */ typedef BWL_PRE_PACKED_STRUCT struct wl_host_wakeup_data { uint16 ver; uint16 len; - uchar data[1]; /* wakeup data */ + uchar data[BCM_FLEX_ARRAY]; /* wakeup data */ } BWL_POST_PACKED_STRUCT wl_host_wakeup_data_t; #include @@ -9561,7 +9847,7 @@ typedef BWL_PRE_PACKED_STRUCT struct wl_host_wakeup_data_v2 { uint16 ver; uint16 len; uint32 gpio_toggle_time; /* gpio toggle time in ms */ - uchar data[1]; /* wakeup data */ + uchar data[BCM_FLEX_ARRAY]; /* wakeup data */ } BWL_POST_PACKED_STRUCT wl_host_wakeup_data_v2_t; #include @@ -9576,14 +9862,14 @@ typedef struct keepalives_max_idle { #define PM_IGNORE_BCMC_ALL_DMS_ACCEPTED (1 << 1) /* ##### HMAP section ##### */ -#define PCIE_MAX_HMAP_WINDOWS 8 -#define PCIE_HMAPTEST_VERSION 2 +#define PCIE_MAX_HMAP_WINDOWS 8u +#define PCIE_HMAPTEST_VERSION_2 2u #define HMAPTEST_INVALID_OFFSET 0xFFFFFFFFu #define HMAPTEST_DEFAULT_WRITE_PATTERN 0xBABECAFEu -#define HMAPTEST_ACCESS_ARM 0 -#define HMAPTEST_ACCESS_M2M 1 -#define HMAPTEST_ACCESS_D11 2 -#define HMAPTEST_ACCESS_NONE 3 +#define HMAPTEST_ACCESS_ARM 0u +#define HMAPTEST_ACCESS_M2M 1u +#define HMAPTEST_ACCESS_D11 2u +#define HMAPTEST_ACCESS_NONE 3u typedef struct pcie_hmaptest { uint16 version; /* Version */ @@ -9606,7 +9892,7 @@ typedef struct hmapwindow { uint32 windowlength; /* Window Length */ } hmapwindow_t; -#define PCIE_HMAP_VERSION 1 +#define PCIE_HMAP_VERSION_1 1u typedef struct pcie_hmap { uint16 version; /**< Version */ uint16 length; /**< Length of entire structure */ @@ -9625,18 +9911,18 @@ typedef struct pcie_hmap { /** Input structure for pwrstats IOVAR */ typedef struct wl_pwrstats_query { - uint16 length; /**< Number of entries in type array. */ - uint16 type[1]; /**< Types (tags) to retrieve. - * Length 0 (no types) means get all. - */ + uint16 length; /**< Number of entries in type array. */ + uint16 type[BCM_FLEX_ARRAY]; /**< Types (tags) to retrieve. + * Length 0 (no types) means get all. + */ } wl_pwrstats_query_t; /** This structure is for version 2; version 1 will be deprecated in by FW */ #include typedef BWL_PRE_PACKED_STRUCT struct wl_pwrstats { - uint16 version; /**< Version = 2 is TLV format */ - uint16 length; /**< Length of entire structure */ - uint8 data[1]; /**< TLV data, a series of structures, + uint16 version; /**< Version = 2 is TLV format */ + uint16 length; /**< Length of entire structure */ + uint8 data[BCM_FLEX_ARRAY]; /**< TLV data, a series of structures, * each starting with type and length. * * Padded as necessary so each section @@ -9665,17 +9951,14 @@ typedef BWL_PRE_PACKED_STRUCT struct wl_pwrstats { #define WLC_PMD_NAN_AWAKE 0x400u /* Reusing for NAN */ #define WLC_PMD_GPTIMER_STAY_AWAKE 0x800u -#ifdef WLAWDL -#define WLC_PMD_AWDL_AWAKE 0x1000u -#endif /* WLAWDL */ - #define WLC_PMD_PM2_RADIO_SOFF_PEND 0x2000u #define WLC_PMD_NON_PRIM_STA_UP 0x4000u #define WLC_PMD_AP_UP 0x8000u #define WLC_PMD_TX_IN_PROGRESS 0x10000u /* Dongle awake due to packet TX */ #define WLC_PMD_4WAYHS_IN_PROGRESS 0x20000u /* Dongle awake due to 4 way handshake */ #define WLC_PMD_PM_OVERRIDE 0x40000u /* Dongle awake due to PM override */ -#define WLC_PMD_WAKE_OTHER 0x80000u +#define WLC_PMD_PASN_IN_PROGRESS 0x80000u /* Dongle awake due to PASN exchange */ +#define WLC_PMD_WAKE_OTHER 0x100000u typedef struct wlc_pm_debug { uint32 timestamp; /**< timestamp in millisecond */ @@ -9750,7 +10033,7 @@ typedef struct pm_awake_data_v2 { uint32 drift_cnt; /**< Count of drift readings over which avg_drift was computed */ uint8 pmwake_idx; /**< for stepping through pm_state */ uint8 flags; /**< bit0: 1-sleep, 0- wake. bit1: 0-bit0 invlid, 1-bit0 valid */ - uint8 pad[2]; + uint8 PAD[2]; uint32 frts_time; /**< Cumulative ms spent in frts since driver load */ uint32 frts_end_cnt; /**< No of times frts ended since driver load */ } pm_awake_data_v2_t; @@ -9961,6 +10244,19 @@ typedef struct bus_metrics { uint32 disconnect_dur; /**< msecs in bus, usecs for user */ } bus_metrics_t; +#define BUS_DUMP_PARAM_VER_1 (1u) +#define SUB_CMD_MAX (32u) +typedef struct bus_dump_param { + uint16 version; /**< version */ + uint16 len; /**< length */ + uint32 flags; /**< flags */ + uint32 value; /**< value to set */ + char sub_cmd[SUB_CMD_MAX]; /**< sub command name */ +} bus_dump_param_t; + +#define BUS_DUMP_FLAGS_CLEAR (1u << 0u) +#define BUS_DUMP_FLAGS_SET (1u << 1u) + /** Bus interface info for USB/HSIC */ #include typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_usb_hsic_stats { @@ -10034,7 +10330,7 @@ typedef struct pcie_cnt { uint32 last_host_ready; /**< Timestamp of last Host ready */ bool hw_asserted; /**< Flag to indicate if Host wake is Asserted */ bool event_delivery_pend; /**< No resources to send event */ - uint16 pad; /**< Word alignment for scripts */ + uint16 PAD; /**< Word alignment for scripts */ } pcie_cnt_t; /** Bus interface info for PCIE */ @@ -10044,6 +10340,24 @@ typedef struct wl_pwr_pcie_stats { pcie_bus_metrics_t pcie; /**< stats from pcie bus driver */ } wl_pwr_pcie_stats_t; +typedef struct scan_data_ext_v1 { + uint32 count; /**< Number of scans performed */ + uint32 dur; /**< Total time (in us) used */ + uint32 off_chan_dur; /**< Total time excluding home channel time */ +} scan_data_ext_v1_t; + +typedef struct wl_pwr_scan_stats_ext_v1 { + uint16 type; /**< WL_PWRSTATS_TYPE_SCAN_EXT */ + uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ + + /* Scan history */ + scan_data_ext_v1_t user_scans; /**< User-requested scans: (i/e/p)scan */ + scan_data_ext_v1_t assoc_scans; /**< Scans initiated by association requests */ + scan_data_ext_v1_t roam_scans; /**< Scans initiated by the roam engine */ + scan_data_ext_v1_t pno_scans[8]; /**< For future PNO bucketing (BSSID, SSID, etc) */ + scan_data_ext_v1_t other_scans; /**< Scan engine usage not assigned to the above */ +} wl_pwr_scan_stats_ext_v1_t; + /** Scan information history per category */ typedef struct scan_data { uint32 count; /**< Number of scans performed */ @@ -10051,19 +10365,19 @@ typedef struct scan_data { } scan_data_t; typedef struct wl_pwr_scan_stats { - uint16 type; /**< WL_PWRSTATS_TYPE_SCAN */ - uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ + uint16 type; /**< WL_PWRSTATS_TYPE_SCAN */ + uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ /* Scan history */ - scan_data_t user_scans; /**< User-requested scans: (i/e/p)scan */ - scan_data_t assoc_scans; /**< Scans initiated by association requests */ - scan_data_t roam_scans; /**< Scans initiated by the roam engine */ - scan_data_t pno_scans[8]; /**< For future PNO bucketing (BSSID, SSID, etc) */ - scan_data_t other_scans; /**< Scan engine usage not assigned to the above */ + scan_data_t user_scans; /**< User-requested scans: (i/e/p)scan */ + scan_data_t assoc_scans; /**< Scans initiated by association requests */ + scan_data_t roam_scans; /**< Scans initiated by the roam engine */ + scan_data_t pno_scans[8]; /**< For future PNO bucketing (BSSID, SSID, etc) */ + scan_data_t other_scans; /**< Scan engine usage not assigned to the above */ } wl_pwr_scan_stats_t; typedef struct wl_pwr_connect_stats { - uint16 type; /**< WL_PWRSTATS_TYPE_SCAN */ + uint16 type; /**< WL_PWRSTATS_TYPE_CONNECTION */ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ /* Connection (Association + Key exchange) data */ @@ -10078,17 +10392,6 @@ typedef struct wl_pwr_phy_stats { uint32 rx_dur; /**< RX Active duration in us */ } wl_pwr_phy_stats_t; -#ifdef WLAWDL -typedef struct wl_pwr_awdl_stats { - uint16 type; /**< WL_PWRSTATS_TYPE_AWDL */ - uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ - uint32 tx_dur; /**< AWDL TX Active duration in usec */ - uint32 rx_dur; /**< AWDL RX Active duration in usec */ - uint32 aw_dur; /**< AWDL AW duration in msec */ - uint32 awpscan_dur; /**< AWDL pscans dur in msec */ -} wl_pwr_awdl_stats_t; -#endif /* WLAWDL */ - typedef struct wl_mimo_meas_metrics_v1 { uint16 type; uint16 len; @@ -10162,7 +10465,7 @@ typedef struct wl_pwr_bcntrim_stats { uint16 len; /* total length includes fixed fields */ uint8 associated; /* STA is associated ? */ uint8 slice_idx; /* on which slice STA is associated */ - uint16 pad; /* padding */ + uint16 PAD; /* padding */ uint32 slice_beacon_seen; /* number of beacons seen on the Infra * interface on this slice */ @@ -10182,11 +10485,23 @@ typedef struct wl_pwr_psbw_stats { uint16 type; /* WL_PWRSTATS_TYPE_PSBW_STATS */ uint16 len; /* total length includes fixed fields */ uint8 slice_idx; /* on which slice STA is associated */ - uint8 pad[3]; + uint8 PAD[3]; uint32 slice_enable_dur; /* time(ms) psbw remains enabled on this slice */ uint32 total_enable_dur; /* time(ms) psbw remains enabled total */ } wl_pwr_psbw_stats_t; +typedef struct wl_pwr_scan_6E_stats { + uint16 type; /* WL_PWRSTATS_TYPE_SCAN_6E */ + uint16 len; /* total length includes fixed fields */ + uint32 rx_upr_processed; /* total unsolicited probe responses processed */ + uint32 rx_upr_ignored; /* total unsolicited probe responses ignored */ + + uint32 rx_fils_processed; /* total FILS processed */ + uint32 rx_fils_ignored; /* total FILS ignored */ + + uint32 referred_6g_scans; /* Referred scans to 6G channels due to RNR */ +} wl_pwr_scan_6E_stats_t; + /* ##### End of Power Stats section ##### */ /** IPV4 Arp offloads for ndis context */ @@ -10229,7 +10544,7 @@ typedef struct wl_pfn_roam_thresh { #define MIN_PM_ALERT_LEN 9 /** Data sent in EXCESS_PM_WAKE event */ -#define WL_PM_ALERT_VERSION 3 +#define WL_PM_ALERT_VERSION_3 3 /** This structure is for version 3; version 2 will be deprecated in by FW */ #include @@ -10237,7 +10552,8 @@ typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert { uint16 version; /**< Version = 3 is TLV format */ uint16 length; /**< Length of entire structure */ uint32 reasons; /**< reason(s) for pm_alert */ - uint8 data[1]; /**< TLV data, a series of structures, + uint8 data[BCM_FLEX_ARRAY]; + /**< TLV data, a series of structures, * each starting with type and length. * * Padded as necessary so each section @@ -10323,9 +10639,9 @@ typedef struct wl_pmalert_pmstate { uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ uint8 pmwake_idx; /**< for stepping through pm_state */ - uint8 pad[3]; + uint8 PAD[3]; /* Array of pmstate; len of array is based on tlv len */ - wlc_pm_debug_t pmstate[1]; + wlc_pm_debug_t pmstate[BCM_FLEX_ARRAY]; } wl_pmalert_pmstate_t; typedef struct wl_pmalert_event_dur { @@ -10333,7 +10649,7 @@ typedef struct wl_pmalert_event_dur { uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ /* Array of event_dur, len of array is based on tlv len */ - uint32 event_dur[1]; + uint32 event_dur[BCM_FLEX_ARRAY]; } wl_pmalert_event_dur_t; #include @@ -10412,7 +10728,7 @@ typedef struct wl_pmalert_ps_allowed_hist { uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ uint32 ps_allowed_start_idx; /* Array of ps_debug, len of array is based on tlv len */ - wlc_ps_debug_t ps_debug[1]; + wlc_ps_debug_t ps_debug[BCM_FLEX_ARRAY]; } wl_pmalert_ps_allowed_hist_t; /* Structures and constants used for "vndr_ie" IOVar interface */ @@ -10431,8 +10747,8 @@ typedef BWL_PRE_PACKED_STRUCT struct { #include typedef BWL_PRE_PACKED_STRUCT struct { - int32 iecount; /**< number of entries in the vndr_ie_list[] array */ - vndr_ie_info_t vndr_ie_list[1]; /**< variable size list of vndr_ie_info_t structs */ + int32 iecount; /**< entries in the vndr_ie_list[] */ + vndr_ie_info_t vndr_ie_list[BCM_FLEX_ARRAY]; /**< var len list of vndr_ie_info_t */ } BWL_POST_PACKED_STRUCT vndr_ie_buf_t; #include @@ -10454,15 +10770,15 @@ typedef BWL_PRE_PACKED_STRUCT struct { #include typedef BWL_PRE_PACKED_STRUCT struct { - uint32 pktflag; /**< bitmask indicating which packet(s) contain this IE */ + uint32 pktflag; /**< bitmask indicating which packet(s) contain this IE */ tlv_t ie_data; /**< IE data */ } BWL_POST_PACKED_STRUCT ie_info_t; #include #include typedef BWL_PRE_PACKED_STRUCT struct { - int32 iecount; /**< number of entries in the ie_list[] array */ - ie_info_t ie_list[1]; /**< variable size list of ie_info_t structs */ + int32 iecount; /**< number of entries in the ie_list[] array */ + ie_info_t ie_list[BCM_FLEX_ARRAY]; /**< variable size list of ie_info_t structs */ } BWL_POST_PACKED_STRUCT ie_buf_t; #include @@ -10490,41 +10806,47 @@ typedef struct sta_prbreq_wps_ie_hdr { #include typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data { sta_prbreq_wps_ie_hdr_t hdr; - uint8 ieData[1]; + uint8 ieData[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t; #include #include typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list { uint32 totLen; - uint8 ieDataList[1]; + uint8 ieDataList[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t; #include +/* + * Structure tx_pwr_rpt_t is variable-length, new fields can be endcoded in the buffer. + * Please see "Curpower TLV Buffer Guide" before changing the structure + */ + #include typedef BWL_PRE_PACKED_STRUCT struct { uint32 flags; - chanspec_t chanspec; /**< txpwr report for this channel */ - chanspec_t local_chanspec; /**< channel on which we are associated */ - uint8 local_max; /**< local max according to the AP */ - uint8 local_constraint; /**< local constraint according to the AP */ - int8 antgain[2]; /**< Ant gain for each band - from SROM */ - uint8 rf_cores; /**< count of RF Cores being reported */ - uint8 est_Pout[4]; /**< Latest tx power out estimate per RF chain */ - uint8 est_Pout_act[4]; /**< Latest tx power out estimate per RF chain w/o adjustment */ - uint8 est_Pout_cck; /**< Latest CCK tx power out estimate */ - uint8 tx_power_max[4]; /**< Maximum target power among all rates */ + chanspec_t chanspec; /**< txpwr report for this channel */ + chanspec_t local_chanspec; /**< channel on which we are associated */ + uint8 local_max; /**< local max according to the AP */ + uint8 local_constraint; /**< local constraint according to the AP */ + int8 antgain[2]; /**< Ant gain for each band - from SROM */ + uint8 rf_cores; /**< count of RF Cores being reported */ + uint8 est_Pout[4]; /**< Latest tx power out estimate per RF chain */ + uint8 est_Pout_act[4]; /**< Latest tx power out estimate per RF chain w/o adjustment */ + uint8 est_Pout_cck; /**< Latest CCK tx power out estimate */ + uint8 tx_power_max[4]; /**< Maximum target power among all rates */ uint32 tx_power_max_rate_ind[4]; /**< Index of the rate with the max target power */ - int8 sar; /**< SAR limit for display by wl executable */ + int8 sar; /**< SAR limit for display by wl executable */ int8 channel_bandwidth; /**< 20, 40 or 80 MHz bandwidth? */ - uint8 version; /**< Version of the data format wlu <--> driver */ - uint8 display_core; /**< Displayed curpower core */ + uint8 version; /**< Version of the data format wlu <--> driver */ + uint8 display_core; /**< Displayed curpower core */ int8 target_offsets[4]; /**< Target power offsets for current rate per core */ uint32 last_tx_ratespec; /**< Ratespec for last transmition */ uint32 user_target; /**< user limit */ - uint32 ppr_len; /**< length of each ppr serialization buffer */ + uint32 ppr_len; /**< length of each ppr serialization buffer */ int8 SARLIMIT[MAX_STREAMS_SUPPORTED]; - uint8 pprdata[1]; /**< ppr serialization buffer */ + /* Please see the document before changing this structure */ + uint8 pprdata[BCM_FLEX_ARRAY]; /**< TLV buffer for ppr and other data */ } BWL_POST_PACKED_STRUCT tx_pwr_rpt_t; typedef BWL_PRE_PACKED_STRUCT struct { @@ -10533,7 +10855,7 @@ typedef BWL_PRE_PACKED_STRUCT struct { chanspec_t local_chanspec; /**< channel on which we are associated */ uint8 local_max; /**< local max according to the AP */ uint8 local_constraint; /**< local constraint according to the AP */ - int8 pad[2]; /**< unused */ + int8 PAD[2]; /**< unused */ uint8 rf_cores; /**< count of RF Cores being reported */ uint8 est_Pout[4]; /**< Latest tx power out estimate per RF chain */ uint8 est_Pout_act[4]; /**< Latest tx power out estimate per RF chain w/o adjustment */ @@ -10550,8 +10872,56 @@ typedef BWL_PRE_PACKED_STRUCT struct { uint32 ppr_len; /**< length of each ppr serialization buffer */ int8 SARLIMIT[MAX_STREAMS_SUPPORTED]; int8 antgain[3]; /**< Ant gain for each band - from SROM */ - uint8 pprdata[1]; /**< ppr serialization buffer */ + /* Please see the document before changing this structure */ + uint8 pprdata[BCM_FLEX_ARRAY]; /**< TLV buffer for ppr and other data */ } BWL_POST_PACKED_STRUCT tx_pwr_rpt_v2_t; + +#define WL_TPC_MAX_BW_TX_PWR_LEN 8u +#define WL_TPC_MAX_RU_TX_PWR_LEN 8u +#define WL_TPE_MAX_TX_PWRS_LEN 16u + +typedef BWL_PRE_PACKED_STRUCT struct wl_tpc_bw_txpwr { + wl_tx_bw_t bw; + int8 txpwr; +} BWL_POST_PACKED_STRUCT wl_tpc_bw_txpwr_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_tpc_ru_txpwr { + int ru; /* RU of wl_he_rate_type_t type */ + int8 txpwr; +} BWL_POST_PACKED_STRUCT wl_tpc_ru_txpwr_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 flags; + chanspec_t chanspec; /**< txpwr report for this channel */ + chanspec_t local_chanspec; /**< channel on which we are associated */ + uint8 local_max; /**< local max according to the AP */ + uint8 local_constraint; /**< local constraint according to the AP */ + int8 PAD[2]; /**< unused */ + uint8 rf_cores; /**< count of RF Cores being reported */ + uint8 est_Pout[4]; /**< Latest tx power out estimate per RF chain */ + uint8 est_Pout_act[4]; /**< Latest tx power out estimate per RF chain w/o adjustment */ + uint8 est_Pout_cck; /**< Latest CCK tx power out estimate */ + uint8 tx_power_max[4]; /**< Maximum target power among all rates */ + uint32 tx_power_max_rate_ind[4]; /**< Index of the rate with the max target power */ + int8 sar; /**< SAR limit for display by wl executable */ + int8 channel_bandwidth; /**< 20, 40 or 80 MHz bandwidth? */ + uint8 version; /**< Version of the data format wlu <--> driver */ + uint8 display_core; /**< Displayed curpower core */ + int8 target_offsets[4]; /**< Target power offsets for current rate per core */ + uint32 last_tx_ratespec; /**< Ratespec for last transmition */ + uint32 user_target; /**< user limit */ + uint32 ppr_len; /**< length of each ppr serialization buffer */ + int8 SARLIMIT[MAX_STREAMS_SUPPORTED]; + int8 antgain[3]; /**< Ant gain for each band - from SROM */ + uint8 tpe_txpwrs_len; /**< # max txpwrs rcvd in TPE elem */ + int8 tpe_txpwrs[WL_TPE_MAX_TX_PWRS_LEN]; /**< TPE parsed max txpwrs */ + uint8 sb_txpwrs_len; /**< No of TPE sb_txpwrs present */ + wl_tpc_bw_txpwr_t sb_txpwrs[WL_TPC_MAX_BW_TX_PWR_LEN]; /**< TPE Subband max txpwrs */ + uint8 ru_txpwrs_len; /**< No of TPE RU txpwrs present */ + wl_tpc_ru_txpwr_t ru_txpwrs[WL_TPC_MAX_RU_TX_PWR_LEN]; /**< TPE RU max txpwrs */ + /* Please see the document before changing this structure */ + uint8 pprdata[BCM_FLEX_ARRAY]; /**< TLV buffer for ppr and other data */ +} BWL_POST_PACKED_STRUCT tx_pwr_rpt_v3_t; #include typedef struct tx_pwr_ru_rate_info { @@ -10569,9 +10939,11 @@ typedef struct tx_pwr_ru_rate_info { #define TX_PWR_RU_RATE_INFO_VER 1 -/* TLV ID for curpower report, ID < 63 is reserved for ppr module */ +/* TLV ID for curpower report, ID <= 63 is reserved for ppr module */ typedef enum tx_pwr_tlv_id { - TX_PWR_RPT_RU_RATE_INFO_ID = 64 + TX_PWR_RPT_RU_RATE_INFO_ID = 64u, + TX_PWR_RPT_RUPDOFFSET_ID = 65u, + TX_PWR_RPT_DEV_CAT_ID = 66u } tx_pwr_tlv_id_t; #include @@ -10584,13 +10956,13 @@ typedef BWL_PRE_PACKED_STRUCT struct { #include typedef BWL_PRE_PACKED_STRUCT struct { uint32 num_entry; - ibss_route_entry_t route_entry[1]; + ibss_route_entry_t route_entry[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT ibss_route_tbl_t; #include #define MAX_IBSS_ROUTE_TBL_ENTRY 64 -#define TXPWR_TARGET_VERSION 0 +#define TXPWR_TARGET_VERSION_0 0 #include typedef BWL_PRE_PACKED_STRUCT struct { int32 version; /**< version number */ @@ -10600,7 +10972,7 @@ typedef BWL_PRE_PACKED_STRUCT struct { } BWL_POST_PACKED_STRUCT txpwr_target_max_t; #include -#define BSS_PEER_INFO_PARAM_CUR_VER 0 +#define BSS_PEER_INFO_PARAM_VER_0 0u /** Input structure for IOV_BSS_PEER_INFO */ #include typedef BWL_PRE_PACKED_STRUCT struct { @@ -10609,7 +10981,7 @@ typedef BWL_PRE_PACKED_STRUCT struct { } BWL_POST_PACKED_STRUCT bss_peer_info_param_t; #include -#define BSS_PEER_INFO_CUR_VER 0 +#define BSS_PEER_INFO_VER_0 0u #include typedef BWL_PRE_PACKED_STRUCT struct { @@ -10623,20 +10995,20 @@ typedef BWL_PRE_PACKED_STRUCT struct { } BWL_POST_PACKED_STRUCT bss_peer_info_t; #include -#define BSS_PEER_LIST_INFO_CUR_VER 0 +#define BSS_PEER_LIST_INFO_VER_0 0u #include typedef BWL_PRE_PACKED_STRUCT struct { uint16 version; uint16 bss_peer_info_len; /**< length of bss_peer_info_t */ uint32 count; /**< number of peer info */ - bss_peer_info_t peer_info[1]; /**< peer info */ + bss_peer_info_t peer_info[BCM_FLEX_ARRAY]; /**< peer info */ } BWL_POST_PACKED_STRUCT bss_peer_list_info_t; #include #define BSS_PEER_LIST_INFO_FIXED_LEN OFFSETOF(bss_peer_list_info_t, peer_info) -#define AIBSS_BCN_FORCE_CONFIG_VER_0 0 +#define AIBSS_BCN_FORCE_CONFIG_VER_0 0u /** structure used to configure AIBSS beacon force xmit */ #include @@ -10649,9 +11021,8 @@ typedef BWL_PRE_PACKED_STRUCT struct { } BWL_POST_PACKED_STRUCT aibss_bcn_force_config_t; #include -#define AIBSS_TXFAIL_CONFIG_VER_0 0 -#define AIBSS_TXFAIL_CONFIG_VER_1 1 -#define AIBSS_TXFAIL_CONFIG_CUR_VER AIBSS_TXFAIL_CONFIG_VER_1 +#define AIBSS_TXFAIL_CONFIG_VER_0 0u +#define AIBSS_TXFAIL_CONFIG_VER_1 1u /** structure used to configure aibss tx fail event */ #include @@ -10684,13 +11055,315 @@ typedef BWL_PRE_PACKED_STRUCT struct wlc_ipfo_route_entry { #include typedef BWL_PRE_PACKED_STRUCT struct wlc_ipfo_route_tbl { uint32 num_entry; - wlc_ipfo_route_entry_t route_entry[1]; + wlc_ipfo_route_entry_t route_entry[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT wlc_ipfo_route_tbl_t; #include /* Version of wlc_btc_stats_t structure. * Increment whenever a change is made to wlc_btc_stats_t */ +#define BTCX_STATS_VER_10 10 +typedef struct wlc_btc_stats_v10 { + uint16 version; /* version number of struct */ + uint16 valid; /* Size of this struct */ + uint32 stats_update_timestamp; /* tStamp when data is updated. */ + uint32 btc_status; /* btc status log */ + uint32 bt_gcishm_active_task_bm; /* Active task bitmap of BT shared thru gci shm */ + uint32 bt_gcishm_bt_tasks; /* BT Tasks info shared in GCI Shm */ + uint32 bt_req_type_map; /* BT Antenna Req types since last stats sample */ + uint32 bt_req_cnt; /* #BT antenna requests since last stats sampl */ + uint32 bt_gnt_cnt; /* #BT antenna grants since last stats sample */ + uint32 bt_gnt_dur; /* usec BT owns antenna since last stats sample */ + uint16 bt_abort_cnt; /* #Times WL was preempted due to BT since WL up */ + uint16 bt_latency_cnt; /* #Time ucode high latency detected since WL up */ + uint16 bt_pm_protect_cnt; /* PM protection count requested by Coex */ + uint16 bt_succ_pm_protect_cnt; /* successful PM protection */ + uint16 bt_succ_cts_cnt; /* successful CTS2A protection */ + uint16 bt_wlan_tx_preempt_cnt; /* WLAN TX Preemption */ + uint16 bt_wlan_rx_preempt_cnt; /* WLAN RX Preemption */ + uint16 bt_ap_tx_after_pm_cnt; /* AP TX even after PM protection */ + uint16 bt_peraud_cumu_gnt_cnt; /* Grant cnt for periodic audio */ + uint16 bt_peraud_cumu_deny_cnt; /* Deny cnt for periodic audio */ + uint16 bt_a2dp_cumu_gnt_cnt; /* Grant cnt for A2DP */ + uint16 bt_a2dp_cumu_deny_cnt; /* Deny cnt for A2DP */ + uint16 bt_sniff_cumu_gnt_cnt; /* Grant cnt for Sniff */ + uint16 bt_sniff_cumu_deny_cnt; /* Deny cnt for Sniff */ + uint16 bt_frameburst_ack_cncl_cnt; /* Count of Ack Cancel for Frame Burst */ + uint16 bt_le_scan_tx_intr_cnt; /* LE Scan Tx Interrupt Count */ + uint16 bt_le_scan_intr_cnt; /* LE Scan INterrupt Count */ + uint16 bt_a2dp_grant_ext_intr; /* A2DP Grant Extension Count */ + uint16 bt_a2dp_uhp_intr_cnt; /* A2DP UHP Interrupt Count */ + uint16 bt_pred_out_of_sync_cnt; /* Predictor Out Of Sync Count */ + uint16 bt_isoc_intr_cnt; /* ISOC Interrupt count */ + uint16 bt_ampdu_collision_cnt; /* BTCX ampdu collision count */ + uint16 bt_back_collision_cnt; /* BTCX BACK collision count */ + uint16 bt_dcsn_map; /* Accumulated decision bitmap once Ant grant */ + uint16 bt_dcsn_cnt; /* Accumulated decision bitmap counters once Ant grant */ + uint16 bt_a2dp_hiwat_cnt; /* Ant grant by a2dp high watermark */ + uint16 bt_datadelay_cnt; /* Ant grant by acl/a2dp datadelay */ + uint16 bt_crtpri_cnt; /* Ant grant by critical BT task */ + uint16 bt_pri_cnt; /* Ant grant by high BT task */ + uint16 a2dpbuf1cnt; /* Ant request with a2dp buffercnt 1 */ + uint16 a2dpbuf2cnt; /* Ant request with a2dp buffercnt 2 */ + uint16 a2dpbuf3cnt; /* Ant request with a2dp buffercnt 3 */ + uint16 a2dpbuf4cnt; /* Ant request with a2dp buffercnt 4 */ + uint16 a2dpbuf5cnt; /* Ant request with a2dp buffercnt 5 */ + uint16 a2dpbuf6cnt; /* Ant request with a2dp buffercnt 6 */ + uint16 a2dpbuf7cnt; /* Ant request with a2dp buffercnt 7 */ + uint16 a2dpbuf8cnt; /* Ant request with a2dp buffercnt 8 */ + uint16 antgrant_lt10ms; /* Ant grant duration cnt 0~10ms */ + uint16 antgrant_lt30ms; /* Ant grant duration cnt 10~30ms */ + uint16 antgrant_lt60ms; /* Ant grant duration cnt 30~60ms */ + uint16 antgrant_ge60ms; /* Ant grant duration cnt 60~ms */ + uint16 wldurn_ge0ms; /* WL duration count between 0-5ms */ + uint16 wldurn_ge5ms; /* WL duration count between 5-12ms */ + uint16 wldurn_ge12ms; /* WL duration count between 12-21ms */ + uint16 wldurn_ge21ms; /* WL duration count between 21-30ms */ + uint16 wldurn_ge30ms; /* WL duration count between 30-65ms */ + uint16 wldurn_ge65ms; /* WL Duration greater than 65ms */ + uint16 nan_idle_cnt; /* Nan Idle Slot Count */ + uint16 nan_pre_dw_cnt; /* Nan Pre Dw Slot Count */ + uint16 nan_pre_data_cnt; /* Nan Pre Data Slot Count */ + uint16 nan_post_dw_cnt; /* Nan Post Dw Slot Count */ + uint16 nan_dw_cnt; /* Nan Dw Slot Count */ + uint16 nan_data_p1_cnt; /* Nan P1 Data Slot Count */ + uint16 nan_data_p2_cnt; /* Nan P2 Data Slot Count */ + uint16 nan_pri_deny_cnt; /* Nan Priority Slot Denial Count */ + uint16 PAD; /* Padding */ +} wlc_btc_stats_v10_t; + +#define BTCX_STATS_VER_9 9 +typedef struct wlc_btc_stats_v9 { + uint16 version; /* version number of struct */ + uint16 valid; /* Size of this struct */ + uint32 stats_update_timestamp; /* tStamp when data is updated. */ + uint32 btc_status; /* Hybrid/TDM indicator: Bit2:Hybrid, Bit1:TDM,Bit0:CoexEnabled */ + uint32 bt_req_type_map; /* BT Antenna Req types since last stats sample */ + uint32 bt_req_cnt; /* #BT antenna requests since last stats sampl */ + uint32 bt_gnt_cnt; /* #BT antenna grants since last stats sample */ + uint32 bt_gnt_dur; /* usec BT owns antenna since last stats sample */ + uint16 bt_abort_cnt; /* #Times WL was preempted due to BT since WL up */ + uint16 bt_rxf1ovfl_cnt; /* #Time PSNULL retry count exceeded since WL up */ + uint16 bt_latency_cnt; /* #Time ucode high latency detected since WL up */ + uint16 bt_pm_attempt_cnt; /* PM protection attempts */ + uint16 bt_succ_pm_protect_cnt; /* successful PM protection */ + uint16 bt_succ_cts_cnt; /* successful CTS2A protection */ + uint16 bt_wlan_tx_preempt_cnt; /* WLAN TX Preemption */ + uint16 bt_wlan_rx_preempt_cnt; /* WLAN RX Preemption */ + uint16 bt_ap_tx_after_pm_cnt; /* AP TX even after PM protection */ + uint16 bt_peraud_cumu_gnt_cnt; /* Grant cnt for periodic audio */ + uint16 bt_peraud_cumu_deny_cnt; /* Deny cnt for periodic audio */ + uint16 bt_a2dp_cumu_gnt_cnt; /* Grant cnt for A2DP */ + uint16 bt_a2dp_cumu_deny_cnt; /* Deny cnt for A2DP */ + uint16 bt_sniff_cumu_gnt_cnt; /* Grant cnt for Sniff */ + uint16 bt_sniff_cumu_deny_cnt; /* Deny cnt for Sniff */ + uint16 bt_crtpri_cnt; /* Ant grant by critical BT task */ + uint16 bt_pri_cnt; /* Ant grant by high BT task */ + uint16 antgrant_lt10ms; /* Ant grant duration cnt 0~10ms */ + uint16 antgrant_lt30ms; /* Ant grant duration cnt 10~30ms */ + uint16 antgrant_lt60ms; /* Ant grant duration cnt 30~60ms */ + uint16 antgrant_ge60ms; /* Ant grant duration cnt 60~ms */ + uint16 ap_leakiness; /* AP leakines, ms */ + uint8 rr_cnt; /* WLAN rate recovery count */ + uint8 rr_succ_cnt; /* WLAN successful rate recovery count */ + uint8 slice_index; /* Slice to report */ + uint8 PAD; /* Padding */ +} wlc_btc_stats_v9_t; + +#define BTCX_STATS_VER_8 8 +typedef struct wlc_btc_stats_v8 { + uint16 version; /* version number of struct */ + uint16 valid; /* Size of this struct */ + uint32 stats_update_timestamp; /* tStamp when data is updated. */ + uint32 btc_status; /* btc status log */ + uint32 bt_gcishm_active_task_bm; /* Active task bitmap of BT shared thru gci shm */ + uint32 bt_gcishm_bt_tasks; /* BT Tasks info shared in GCI Shm */ + uint32 bt_req_type_map; /* BT Antenna Req types since last stats sample */ + uint32 bt_req_cnt; /* #BT antenna requests since last stats sampl */ + uint32 bt_gnt_cnt; /* #BT antenna grants since last stats sample */ + uint32 bt_gnt_dur; /* usec BT owns antenna since last stats sample */ + uint16 bt_abort_cnt; /* #Times WL was preempted due to BT since WL up */ + uint16 bt_latency_cnt; /* #Time ucode high latency detected since WL up */ + uint16 bt_pm_protect_cnt; /* PM protection count requested by Coex */ + uint16 bt_succ_pm_protect_cnt; /* successful PM protection */ + uint16 bt_succ_cts_cnt; /* successful CTS2A protection */ + uint16 bt_wlan_tx_preempt_cnt; /* WLAN TX Preemption */ + uint16 bt_wlan_rx_preempt_cnt; /* WLAN RX Preemption */ + uint16 bt_ap_tx_after_pm_cnt; /* AP TX even after PM protection */ + uint16 bt_peraud_cumu_gnt_cnt; /* Grant cnt for periodic audio */ + uint16 bt_peraud_cumu_deny_cnt; /* Deny cnt for periodic audio */ + uint16 bt_a2dp_cumu_gnt_cnt; /* Grant cnt for A2DP */ + uint16 bt_a2dp_cumu_deny_cnt; /* Deny cnt for A2DP */ + uint16 bt_sniff_cumu_gnt_cnt; /* Grant cnt for Sniff */ + uint16 bt_sniff_cumu_deny_cnt; /* Deny cnt for Sniff */ + uint16 bt_frameburst_ack_cncl_cnt; /* Count of Ack Cancel for Frame Burst */ + uint16 bt_le_scan_tx_intr_cnt; /* LE Scan Tx Interrupt Count */ + uint16 bt_le_scan_intr_cnt; /* LE Scan INterrupt Count */ + uint16 bt_a2dp_grant_ext_intr; /* A2DP Grant Extension Count */ + uint16 bt_a2dp_grant_ext_prcsd_cnt; /* A2DP Grant Extension Processed Count */ + uint16 bt_pred_out_of_sync_cnt; /* Predictor Out Of Sync Count */ + uint16 bt_dcsn_map; /* Accumulated decision bitmap once Ant grant */ + uint16 bt_dcsn_cnt; /* Accumulated decision bitmap counters once Ant grant */ + uint16 bt_a2dp_hiwat_cnt; /* Ant grant by a2dp high watermark */ + uint16 bt_datadelay_cnt; /* Ant grant by acl/a2dp datadelay */ + uint16 bt_crtpri_cnt; /* Ant grant by critical BT task */ + uint16 bt_pri_cnt; /* Ant grant by high BT task */ + uint16 a2dpbuf1cnt; /* Ant request with a2dp buffercnt 1 */ + uint16 a2dpbuf2cnt; /* Ant request with a2dp buffercnt 2 */ + uint16 a2dpbuf3cnt; /* Ant request with a2dp buffercnt 3 */ + uint16 a2dpbuf4cnt; /* Ant request with a2dp buffercnt 4 */ + uint16 a2dpbuf5cnt; /* Ant request with a2dp buffercnt 5 */ + uint16 a2dpbuf6cnt; /* Ant request with a2dp buffercnt 6 */ + uint16 a2dpbuf7cnt; /* Ant request with a2dp buffercnt 7 */ + uint16 a2dpbuf8cnt; /* Ant request with a2dp buffercnt 8 */ + uint16 antgrant_lt10ms; /* Ant grant duration cnt 0~10ms */ + uint16 antgrant_lt30ms; /* Ant grant duration cnt 10~30ms */ + uint16 antgrant_lt60ms; /* Ant grant duration cnt 30~60ms */ + uint16 antgrant_ge60ms; /* Ant grant duration cnt 60~ms */ + uint16 wldurn_ge0ms; /* WL duration count between 0-5ms */ + uint16 wldurn_ge5ms; /* WL duration count between 5-12ms */ + uint16 wldurn_ge12ms; /* WL duration count between 12-21ms */ + uint16 wldurn_ge21ms; /* WL duration count between 21-30ms */ + uint16 wldurn_ge30ms; /* WL duration count between 30-65ms */ + uint16 wldurn_ge65ms; /* WL Duration greater than 65ms */ + uint16 nan_idle_cnt; /* Nan Idle Slot Count */ + uint16 nan_pre_dw_cnt; /* Nan Pre Dw Slot Count */ + uint16 nan_pre_data_cnt; /* Nan Pre Data Slot Count */ + uint16 nan_post_dw_cnt; /* Nan Post Dw Slot Count */ + uint16 nan_dw_cnt; /* Nan Dw Slot Count */ + uint16 nan_data_p1_cnt; /* Nan P1 Data Slot Count */ + uint16 nan_data_p2_cnt; /* Nan P2 Data Slot Count */ + uint16 nan_pri_deny_cnt; /* Nan Priority Slot Denial Count */ +} wlc_btc_stats_v8_t; + +#define BTCX_STATS_VER_7 7 +typedef struct wlc_btc_stats_v7 { + uint16 version; /* version number of struct */ + uint16 valid; /* Size of this struct */ + uint32 stats_update_timestamp; /* tStamp when data is updated. */ + uint32 btc_status; /* Hybrid/TDM indicator: Bit2:Hybrid, Bit1:TDM,Bit0:CoexEnabled */ + uint32 bt_req_type_map; /* BT Antenna Req types since last stats sample */ + uint32 bt_req_cnt; /* #BT antenna requests since last stats sampl */ + uint32 bt_gnt_cnt; /* #BT antenna grants since last stats sample */ + uint32 bt_gnt_dur; /* usec BT owns antenna since last stats sample */ + uint16 bt_abort_cnt; /* #Times WL was preempted due to BT since WL up */ + uint16 bt_rxf1ovfl_cnt; /* #Time PSNULL retry count exceeded since WL up */ + uint16 bt_latency_cnt; /* #Time ucode high latency detected since WL up */ + uint16 bt_pm_attempt_cnt; /* PM protection attempts */ + uint16 bt_succ_pm_protect_cnt; /* successful PM protection */ + uint16 bt_succ_cts_cnt; /* successful CTS2A protection */ + uint16 bt_wlan_tx_preempt_cnt; /* WLAN TX Preemption */ + uint16 bt_wlan_rx_preempt_cnt; /* WLAN RX Preemption */ + uint16 bt_ap_tx_after_pm_cnt; /* AP TX even after PM protection */ + uint16 bt_peraud_cumu_gnt_cnt; /* Grant cnt for periodic audio */ + uint16 bt_peraud_cumu_deny_cnt; /* Deny cnt for periodic audio */ + uint16 bt_a2dp_cumu_gnt_cnt; /* Grant cnt for A2DP */ + uint16 bt_a2dp_cumu_deny_cnt; /* Deny cnt for A2DP */ + uint16 bt_sniff_cumu_gnt_cnt; /* Grant cnt for Sniff */ + uint16 bt_sniff_cumu_deny_cnt; /* Deny cnt for Sniff */ + uint16 bt_crtpri_cnt; /* Ant grant by critical BT task */ + uint16 bt_pri_cnt; /* Ant grant by high BT task */ + uint16 antgrant_lt10ms; /* Ant grant duration cnt 0~10ms */ + uint16 antgrant_lt30ms; /* Ant grant duration cnt 10~30ms */ + uint16 antgrant_lt60ms; /* Ant grant duration cnt 30~60ms */ + uint16 antgrant_ge60ms; /* Ant grant duration cnt 60~ms */ + uint8 slice_index; /* Slice to report */ + uint8 PAD; /* Padding */ +} wlc_btc_stats_v7_t; + +#define BTCX_STATS_VER_6 6 +typedef struct wlc_btc_stats_v6 { + uint16 version; /* version number of struct */ + uint16 valid; /* Size of this struct */ + uint32 stats_update_timestamp; /* tStamp when data is updated. */ + uint32 btc_status; /* Hybrid/TDM indicator: Bit2:Hybrid, Bit1:TDM,Bit0:CoexEnabled */ + uint32 bt_req_type_map; /* BT Antenna Req types since last stats sample */ + uint32 bt_req_cnt; /* #BT antenna requests since last stats sampl */ + uint32 bt_gnt_cnt; /* #BT antenna grants since last stats sample */ + uint32 bt_gnt_dur; /* usec BT owns antenna since last stats sample */ + uint16 bt_abort_cnt; /* #Times WL was preempted due to BT since WL up */ + uint16 bt_rxf1ovfl_cnt; /* #Time PSNULL retry count exceeded since WL up */ + uint16 bt_latency_cnt; /* #Time ucode high latency detected since WL up */ + uint16 bt_pm_attempt_cnt; /* PM protection attempts */ + uint16 bt_succ_pm_protect_cnt; /* successful PM protection */ + uint16 bt_succ_cts_cnt; /* successful CTS2A protection */ + uint16 bt_wlan_tx_preempt_cnt; /* WLAN TX Preemption */ + uint16 bt_wlan_rx_preempt_cnt; /* WLAN RX Preemption */ + uint16 bt_ap_tx_after_pm_cnt; /* AP TX even after PM protection */ + uint16 bt_peraud_cumu_gnt_cnt; /* Grant cnt for periodic audio */ + uint16 bt_peraud_cumu_deny_cnt; /* Deny cnt for periodic audio */ + uint16 bt_a2dp_cumu_gnt_cnt; /* Grant cnt for A2DP */ + uint16 bt_a2dp_cumu_deny_cnt; /* Deny cnt for A2DP */ + uint16 bt_sniff_cumu_gnt_cnt; /* Grant cnt for Sniff */ + uint16 bt_sniff_cumu_deny_cnt; /* Deny cnt for Sniff */ + uint8 PAD; /* Padding */ + uint8 slice_index; /* Slice to report */ +} wlc_btc_stats_v6_t; + +#define BTCX_STATS_VER_5 5 +typedef struct wlc_btc_stats_v5 { + uint16 version; /* version number of struct */ + uint16 valid; /* Size of this struct */ + uint32 stats_update_timestamp; /* tStamp when data is updated. */ + uint32 btc_status; /* btc status log */ + uint32 bt_req_type_map; /* BT Antenna Req types since last stats sample */ + uint32 bt_req_cnt; /* #BT antenna requests since last stats sampl */ + uint32 bt_gnt_cnt; /* #BT antenna grants since last stats sample */ + uint32 bt_gnt_dur; /* usec BT owns antenna since last stats sample */ + uint16 bt_abort_cnt; /* #Times WL was preempted due to BT since WL up */ + uint16 bt_latency_cnt; /* #Time ucode high latency detected since WL up */ + uint16 bt_pm_protect_cnt; /* PM protection count requested by Coex */ + uint16 bt_succ_pm_protect_cnt; /* successful PM protection */ + uint16 bt_succ_cts_cnt; /* successful CTS2A protection */ + uint16 bt_wlan_tx_preempt_cnt; /* WLAN TX Preemption */ + uint16 bt_wlan_rx_preempt_cnt; /* WLAN RX Preemption */ + uint16 bt_ap_tx_after_pm_cnt; /* AP TX even after PM protection */ + uint16 bt_peraud_cumu_gnt_cnt; /* Grant cnt for periodic audio */ + uint16 bt_peraud_cumu_deny_cnt; /* Deny cnt for periodic audio */ + uint16 bt_a2dp_cumu_gnt_cnt; /* Grant cnt for A2DP */ + uint16 bt_a2dp_cumu_deny_cnt; /* Deny cnt for A2DP */ + uint16 bt_sniff_cumu_gnt_cnt; /* Grant cnt for Sniff */ + uint16 bt_sniff_cumu_deny_cnt; /* Deny cnt for Sniff */ + uint16 bt_frameburst_ack_cncl_cnt; /* Count of Ack Cancel for Frame Burst */ + uint16 bt_le_scan_tx_intr_cnt; /* LE Scan Tx Interrupt Count */ + uint16 bt_le_scan_intr_cnt; /* LE Scan INterrupt Count */ + uint16 bt_a2dp_grant_ext_intr; /* A2DP Grant Extension Count */ + uint16 bt_a2dp_grant_ext_prcsd_cnt; /* A2DP Grant Extension Processed Count */ + uint16 bt_pred_out_of_sync_cnt; /* Predictor Out Of Sync Count */ + uint16 bt_dcsn_map; /* Accumulated decision bitmap once Ant grant */ + uint16 bt_dcsn_cnt; /* Accumulated decision bitmap counters once Ant grant */ + uint16 bt_a2dp_hiwat_cnt; /* Ant grant by a2dp high watermark */ + uint16 bt_datadelay_cnt; /* Ant grant by acl/a2dp datadelay */ + uint16 bt_crtpri_cnt; /* Ant grant by critical BT task */ + uint16 bt_pri_cnt; /* Ant grant by high BT task */ + uint16 a2dpbuf1cnt; /* Ant request with a2dp buffercnt 1 */ + uint16 a2dpbuf2cnt; /* Ant request with a2dp buffercnt 2 */ + uint16 a2dpbuf3cnt; /* Ant request with a2dp buffercnt 3 */ + uint16 a2dpbuf4cnt; /* Ant request with a2dp buffercnt 4 */ + uint16 a2dpbuf5cnt; /* Ant request with a2dp buffercnt 5 */ + uint16 a2dpbuf6cnt; /* Ant request with a2dp buffercnt 6 */ + uint16 a2dpbuf7cnt; /* Ant request with a2dp buffercnt 7 */ + uint16 a2dpbuf8cnt; /* Ant request with a2dp buffercnt 8 */ + uint16 antgrant_lt10ms; /* Ant grant duration cnt 0~10ms */ + uint16 antgrant_lt30ms; /* Ant grant duration cnt 10~30ms */ + uint16 antgrant_lt60ms; /* Ant grant duration cnt 30~60ms */ + uint16 antgrant_ge60ms; /* Ant grant duration cnt 60~ms */ + uint16 wldurn_ge0ms; /* WL duration count between 0-5ms */ + uint16 wldurn_ge5ms; /* WL duration count between 5-12ms */ + uint16 wldurn_ge12ms; /* WL duration count between 12-21ms */ + uint16 wldurn_ge21ms; /* WL duration count between 21-30ms */ + uint16 wldurn_ge30ms; /* WL duration count between 30-65ms */ + uint16 wldurn_ge65ms; /* WL Duration greater than 65ms */ + uint16 nan_idle_cnt; /* Nan Idle Slot Count */ + uint16 nan_pre_dw_cnt; /* Nan Pre Dw Slot Count */ + uint16 nan_pre_data_cnt; /* Nan Pre Data Slot Count */ + uint16 nan_post_dw_cnt; /* Nan Post Dw Slot Count */ + uint16 nan_dw_cnt; /* Nan Dw Slot Count */ + uint16 nan_data_p1_cnt; /* Nan P1 Data Slot Count */ + uint16 nan_data_p2_cnt; /* Nan P2 Data Slot Count */ + uint16 nan_pri_deny_cnt; /* Nan Priority Slot Denial Count */ +} wlc_btc_stats_v5_t; + #define BTCX_STATS_VER_4 4 typedef struct wlc_btc_stats_v4 { uint16 version; /* version number of struct */ @@ -10761,7 +11434,7 @@ typedef struct wlc_btc_stats_v3 { uint16 bt_a2dp_cumu_deny_cnt; /* Deny cnt for A2DP */ uint16 bt_sniff_cumu_gnt_cnt; /* Grant cnt for Sniff */ uint16 bt_sniff_cumu_deny_cnt; /* Deny cnt for Sniff */ - uint8 pad; /* Padding */ + uint8 PAD; /* Padding */ uint8 slice_index; /* Slice to report */ } wlc_btc_stats_v3_t; @@ -10782,7 +11455,904 @@ typedef struct wlc_btc_stats_v2 { uint16 rsvd; /* pad to align struct to 32bit bndry */ } wlc_btc_stats_v2_t; +#define TXCAL_MAX_PA_MODE 4 /* signed for assigning minus for undefined */ + +#define ACPHY_OBSS_SUBBAND_CNT 8u /* Max sub band counts i.e., 160Mhz = 8 * 20MHZ */ + +typedef struct phy_ecounter_v1 { + chanspec_t chanspec; + uint8 slice; + uint8 PAD; + uint16 phy_wdg; /* Count of times watchdog happened. */ + uint16 noise_req; /* Count of phy noise sample requests. */ + uint16 noise_crsbit; /* Count of CRS high during noisecal request. */ + uint16 noise_apply; /* Count of applying noisecal result to crsmin. */ + uint16 cal_counter; /* Count of performing single and multi phase cal. */ +} phy_ecounter_v1_t; + +typedef struct phy_ecounter_log_core_v1 { + int8 crsmin_pwr; /* Noise level for applied desense */ + int8 noise_level_inst; /* Instantaneous noise cal pwr */ +} phy_ecounter_log_core_v1_t; + +typedef struct phy_ecounter_log_core_v2 { + int8 crsmin_pwr; /* Noise level for applied desense */ + int8 rssi_per_ant; /* Instantaneous noise cal pwr */ + int8 phylog_noise_pwr_array[8]; /* noise buffer array */ +} phy_ecounter_log_core_v2_t; + +typedef struct phy_ecounter_log_core_v3 { + uint16 bad_txbaseidx_cnt; /* cntr for tx_baseidx=127 in healthcheck */ + uint16 curr_tssival; /* TxPwrCtrlInit_path[01].TSSIVal */ + uint16 pwridx_init; /* TxPwrCtrlInit_path[01].pwrIndex_init_path[01] */ + uint16 auxphystats; /* Indicates the PHY stats for aux slice */ + uint16 phystatsgaininfo; /* Indicates the gain stats */ + uint16 flexgaininfo_A; /* Indicates the gain settings */ + uint8 crsmin_pwr_idx; /* Index to the crsminpower threshold array */ + uint8 baseindxval; /* TPC Base index */ + int8 crsmin_pwr; /* Noise level for applied desense */ + int8 noise_level_inst; /* Instantaneous noise cal pwr */ + int8 tgt_pwr; /* Programmed Target power */ + int8 estpwradj; /* Current Est Power Adjust value */ + uint8 PAD1[2]; +} phy_ecounter_log_core_v3_t; + +typedef struct phy_ecounter_log_core_v4 { + uint16 bad_txbaseidx_cnt; /* cntr for tx_baseidx=127 in healthcheck */ + uint16 curr_tssival; /* TxPwrCtrlInit_path[01].TSSIVal */ + uint16 pwridx_init; /* TxPwrCtrlInit_path[01].pwrIndex_init_path[01] */ + uint16 auxphystats; /* Indicates the PHY stats for aux slice */ + uint16 phystatsgaininfo; /* Indicates the gain stats */ + uint16 flexgaininfo_A; /* Indicates the gain settings */ + uint8 crsmin_pwr_idx; /* Index to the crsminpower threshold array */ + uint8 baseindxval; /* TPC Base index */ + int8 crsmin_pwr; /* Noise level for applied desense */ + int8 noise_level_inst; /* Instantaneous noise cal pwr */ + int8 tgt_pwr; /* Programmed Target power */ + int8 estpwradj; /* Current Est Power Adjust value */ + int8 ed_threshold; /* Energy detection threshold */ + uint8 PAD1; + int8 obss_pwrest[ACPHY_OBSS_SUBBAND_CNT]; /* OBSS signal power per sub-band in dBm */ +} phy_ecounter_log_core_v4_t; + +/* For trunk ONLY */ +typedef struct phy_ecounter_log_core_v255 { + uint16 bad_txbaseidx_cnt; /* cntr for tx_baseidx=127 in healthcheck */ + uint16 curr_tssival; /* TxPwrCtrlInit_path[01].TSSIVal */ + uint16 pwridx_init; /* TxPwrCtrlInit_path[01].pwrIndex_init_path[01] */ + uint16 auxphystats; /* Indicates the PHY stats for aux slice */ + uint16 phystatsgaininfo; /* Indicates the gain stats */ + uint16 flexgaininfo_A; /* Indicates the gain settings */ + uint8 crsmin_pwr_idx; /* Index to the crsminpower threshold array */ + uint8 baseindxval; /* TPC Base index */ + int8 crsmin_pwr; /* Noise level for applied desense */ + int8 noise_level_inst; /* Instantaneous noise cal pwr */ + int8 tgt_pwr; /* Programmed Target power */ + int8 estpwradj; /* Current Est Power Adjust value */ + int8 ed_threshold; /* Energy detection threshold */ + uint8 PAD1; + int8 obss_pwrest[ACPHY_OBSS_SUBBAND_CNT]; /* OBSS signal power per sub-band in dBm */ +} phy_ecounter_log_core_v255_t; + +/* Do not remove phy_ecounter_v1_t parameters */ +typedef struct phy_ecounter_v2 { + chanspec_t chanspec; + uint8 slice; + uint8 PAD1; /* padding */ + uint16 phy_wdg; /* Count of times watchdog happened. */ + uint16 noise_req; /* Count of phy noise sample requests. */ + uint16 noise_crsbit; /* Count of CRS high during noisecal request. */ + uint16 noise_apply; /* Count of applying noisecal result to crsmin. */ + uint16 cal_counter; /* Count of performing single&multi phase cal. */ + uint16 featureflag; /* Currently active feature flags */ + uint32 chan_switch_cnt; /* channel switch count */ + int8 chiptemp; /* Chip temparature */ + int8 femtemp; /* Fem temparature */ + uint8 rxchain; /* Rx Chain */ + uint8 txchain; /* Tx Chain */ + uint8 ofdm_desense; /* OFDM desense */ + uint8 bphy_desense; /* BPHY desense */ + uint16 deaf_count; /* Depth of stay_in_carrier_search function */ + uint8 phylog_noise_mode; /* noise cal mode */ + uint8 total_desense_on; /* total desense on flag */ + uint8 initgain_desense; /* initgain desense when total desense is on */ + uint8 crsmin_init; /* crsmin_init threshold when total desense is on */ + uint8 lte_ofdm_desense; /* ofdm desense dut to lte */ + uint8 lte_bphy_desense; /* ofdm desense dut to bphy */ + int8 crsmin_high; /* crsmin high when applying desense */ + int8 weakest_rssi; /* weakest link RSSI */ + int8 ed_threshold; /* Threshold applied for ED */ + uint8 PAD2; /* padding */ + uint16 ed_crs_status; /* Status of ED and CRS during noise cal */ + uint16 preempt_status1; /* status of preemption */ + uint16 preempt_status2; /* status of preemption */ + uint16 preempt_status3; /* status of preemption */ + uint16 preempt_status4; /* status of preemption */ + uint32 cca_stats_total_glitch; /* ccastats: count of total glitches */ + uint32 cca_stats_bphy_glitch; /* ccastats: count of bphy glitches */ + uint32 cca_stats_total_badplcp; /* ccastats: count of total badplcp */ + uint32 cca_stats_bphy_badplcp; /* ccastats: count of bphy badplcp */ + uint32 cca_stats_mbsstime; /* ccastats: monitor duration in msec */ + uint32 cca_stats_ed_duration; /* ccastats: ed_duration */ + phy_ecounter_log_core_v2_t phy_ecounter_core[2]; +} phy_ecounter_v2_t; + +/* Do not remove phy_ecounter_v1_t parameters */ +typedef struct phy_ecounter_v3 { + chanspec_t chanspec; + uint16 phy_wdg; /* Count of times watchdog happened. */ + uint16 noise_req; /* Count of phy noise sample requests. */ + uint16 noise_crsbit; /* Count of CRS high during noisecal request. */ + uint16 noise_apply; /* Count of applying noisecal result to crsmin. */ + uint16 cal_counter; /* Count of performing single and multi phase cal. */ + uint8 crsmin_pwr_idx; /* Index to the crsminpower threshold array */ + uint8 slice; /* Slice # 0 - MAIN, 1 - AUX, 2 - SCAN */ + uint8 rxchain; /* Status of active RX chains */ + uint8 txchain; /* Status of active TX chains */ + uint8 gbd_bphy_sleep_counter; /* Sleep count for bphy GBD */ + uint8 gbd_ofdm_sleep_counter; /* Sleep count for ofdm GBD */ + uint8 curr_home_channel; /* Current home channel */ + uint8 gbd_ofdm_desense; /* Glitch based desense level for ofdm reception */ + uint8 gbd_bphy_desense; /* Glitch based desense level for bphy reception */ + int8 chiptemp; /* Chip temperature */ + int8 femtemp; /* Fem temperature */ + int8 btcx_mode; /* BT coex desense mode */ + int8 ltecx_mode; /* LTE coex desense mode */ + int8 weakest_rssi; /* Weakest link RSSI */ + int8 ed_threshold; /* Threshold applied for ED */ + uint8 chan_switch_cnt; /* Count to track channel change */ + uint8 phycal_disable; /* Status of phy calibration */ + uint8 scca_txstall_precondition; /* SmartCCA TX stall precondition */ + uint16 featureflag; /* Currently active feature flags */ + uint16 deaf_count; /* Count for RX stay in carrier search state */ + uint16 noise_mmt_overdue; /* Noise measurement overdue status */ + uint16 crsmin_pwr_apply_cnt; /* Count for desense updates */ + uint16 ed_crs_status; /* Status of ED and CRS during noise cal */ + uint16 preempt_status1; /* status of preemption */ + uint16 preempt_status2; /* status of preemption */ + uint16 preempt_status3; /* status of preemption */ + uint16 preempt_status4; /* status of preemption */ + uint32 cca_stats_total_glitch; /* ccastats: count of total glitches */ + uint32 cca_stats_bphy_glitch; /* ccastats: count of bphy glitches */ + uint32 cca_stats_total_badplcp; /* ccastats: count of total badplcp */ + uint32 cca_stats_bphy_badplcp; /* ccastats: count of bphy badplcp */ + uint32 cca_stats_mbsstime; /* ccastats: monitor duration in msec */ + uint32 cca_stats_ed_duration; /* ccastats: ed_duration */ + phy_ecounter_log_core_v1_t phy_ecounter_core[2]; +} phy_ecounter_v3_t; + +/* Do not remove phy_ecounter_v1_t parameters */ +typedef struct phy_ecounter_v4 { + chanspec_t chanspec; + uint16 phy_wdg; /* Count of times watchdog happened. */ + uint16 noise_req; /* Count of phy noise sample requests. */ + uint16 noise_crsbit; /* Count of CRS high during noisecal request. */ + uint16 noise_apply; /* Count of applying noisecal result to crsmin. */ + uint16 cal_counter; /* Count of performing single and multi phase cal. */ + uint8 slice; /* Slice # 0 - MAIN, 1 - AUX, 2 - SCAN */ + uint8 rxchain; /* Status of active RX chains */ + uint8 txchain; /* Status of active TX chains */ + uint8 gbd_bphy_sleep_counter; /* Sleep count for bphy GBD */ + uint8 gbd_ofdm_sleep_counter; /* Sleep count for ofdm GBD */ + uint8 curr_home_channel; /* Current home channel */ + uint8 gbd_ofdm_desense; /* Glitch based desense level for ofdm reception */ + uint8 gbd_bphy_desense; /* Glitch based desense level for bphy reception */ + int8 chiptemp; /* Chip temperature */ + int8 femtemp; /* Fem temperature */ + int8 weakest_rssi; /* Weakest link RSSI */ + int8 ltecx_mode; /* LTE coex desense mode */ + int32 btcx_mode; /* BT coex desense mode */ + int8 ed_threshold; /* Threshold applied for ED */ + uint8 chan_switch_cnt; /* Count to track channel change */ + uint8 phycal_disable; /* Status of phy calibration */ + uint8 scca_txstall_precondition; /* SmartCCA TX stall precondition */ + uint16 featureflag; /* Currently active feature flags */ + uint16 deaf_count; /* Count for RX stay in carrier search state */ + uint16 noise_mmt_overdue; /* Noise measurement overdue status */ + uint16 crsmin_pwr_apply_cnt; /* Count for desense updates */ + uint16 ed_crs_status; /* Status of ED and CRS during noise cal */ + uint16 preempt_status1; /* status of preemption */ + uint16 preempt_status2; /* status of preemption */ + uint16 preempt_status3; /* status of preemption */ + uint16 preempt_status4; /* status of preemption */ + uint16 counter_noise_iqest_to; /* count of IQ_Est time out */ + uint32 cca_stats_total_glitch; /* ccastats: count of total glitches */ + uint32 cca_stats_bphy_glitch; /* ccastats: count of bphy glitches */ + uint32 cca_stats_total_badplcp; /* ccastats: count of total badplcp */ + uint32 cca_stats_bphy_badplcp; /* ccastats: count of bphy badplcp */ + uint32 cca_stats_mbsstime; /* ccastats: monitor duration in msec */ + uint32 cca_stats_ed_duration; /* ccastats: ed_duration */ + uint32 measurehold; /* PHY hold activities */ + uint32 rxsense_disable_req_ch; /* channel disable requests */ + uint32 ocl_disable_reqs; /* OCL disable bitmap */ + uint32 interference_mode; /* interference mitigation mode */ + uint32 power_mode; /* power mode */ + uint32 obss_last_read_time; /* last stats read time */ + int32 asym_intf_ed_thresh; /* smartcca ed threshold %d */ + uint16 obss_mit_bw; /* selected mitigation BW */ + uint16 obss_stats_cnt; /* stats count */ + uint16 dynbw_init_reducebw_cnt; /* BW reduction cnt of initiator */ + uint16 dynbw_resp_reducebw_cnt; /* BW reduction cnt of responder */ + uint16 dynbw_rxdata_reducebw_cnt; /* rx data cnt with reduced BW */ + uint16 obss_mmt_skip_cnt; /* mmt skipped due to powersave */ + uint16 obss_mmt_no_result_cnt; /* mmt with no result */ + uint16 obss_mmt_intr_err_cnt; /* obss reg mismatch between ucode and fw */ + uint16 gci_lst_inv_ctr; /* last gci invalid */ + uint16 gci_lst_rst_ctr; /* last gci restore 0x%04x */ + uint16 gci_lst_sem_ctr; /* last gci seq number 0x%04x */ + uint16 gci_lst_rb_st; /* last gci status */ + uint16 gci_dbg01; /* gci dbg1 readback */ + uint16 gci_dbg02; /* gci dbg2 readback */ + uint16 gci_dbg03; /* gci dbg3 readback */ + uint16 gci_dbg04; /* gci dbg4 readback */ + uint16 gci_dbg05; /* gci dbg5 readback */ + uint16 gci_lst_st_msk; /* gci last status mask */ + uint16 gci_inv_tx; /* invalid gci during tx */ + uint16 gci_inv_rx; /* invalid gci during rx */ + uint16 gci_rst_tx; /* gci restore during tx */ + uint16 gci_rst_rx; /* gci restore during rx */ + uint16 gci_sem_ctr; /* gci seq number ctr */ + uint16 gci_invstate; /* gci status 0x%04x */ + uint16 gci_ctl2; /* gci ctrl 2 */ + uint16 gci_chan; /* channel during gci read 0x%04x */ + uint16 gci_cm; /* channel during gci read */ + uint16 gci_sc; /* gci read during scan */ + uint16 gci_rst_sc; /* gci restore during scan */ + uint16 gci_prdc_rx; /* periodic gci hc */ + uint16 gci_wk_rx; /* gci hc during wake */ + uint16 gci_rmac_rx; /* gci hc during mac read */ + uint16 gci_tx_rx; /* gci hc during tx/rx */ + uint16 asym_intf_stats; /* smartCCA status 0x%04x */ + uint16 asym_intf_ncal_crs_stat; /* noise cal and crs status %d */ + int16 ed_crsEn; /* ed enable 0x%04x */ + int16 nvcfg0; /* noise update to hw 0x%04x */ + uint8 cal_suppressed_cntr_ed; /* cnt including ss, mp cals, MSB is cur state */ + uint8 sc_dccal_incc_cnt; /* scan dccal counter */ + uint8 sc_noisecal_incc_cnt; /* scan noise cal counter */ + uint8 obss_need_updt; /* BW update needed flag */ + uint8 obss_mit_status; /* obss mitigation status */ + uint8 obss_final_rec_bw; /* final recommended bw to wlc-Sent to SW */ + uint8 btc_mode; /* btc mode */ + uint8 asym_intf_ant_noise_idx; /* current noise storage index */ + uint8 asym_intf_pending_host_req_type; /* usb plugin request */ + uint8 asym_intf_ncal_crs_stat_idx; /* crs status storage index %d */ + int8 rxsense_noise_idx; /* rxsense det thresh desense idx */ + int8 rxsense_offset; /* rxsense min power desense idx */ + int8 asym_intf_tx_smartcca_cm; /* smartCCA tx coremask %d */ + int8 asym_intf_rx_noise_mit_cm; /* smartCCA rx coremask %d */ + int8 asym_intf_avg_noise[2]; /* average noise %d */ + int8 asym_intf_latest_noise[2]; /* current noise %d */ + uint8 obss_curr_det[ACPHY_OBSS_SUBBAND_CNT]; /* obss curr detection */ + phy_ecounter_log_core_v3_t phy_ecounter_core[2]; +} phy_ecounter_v4_t; + +typedef struct phy_ecounter_v5 { + chanspec_t chanspec; + uint16 phy_wdg; /* Count of times watchdog happened */ + uint16 noise_req; /* Count of phy noise sample requests */ + uint16 noise_crsbit; /* Count of CRS high during noisecal request */ + uint16 noise_apply; /* Count of applying noisecal result to crsmin */ + uint16 cal_counter; /* Count of performing single and multi phase cal */ + uint8 slice; /* Slice # 0 - MAIN, 1 - AUX, 2 - SCAN */ + uint8 rxchain; /* Status of active RX chains */ + uint8 txchain; /* Status of active TX chains */ + uint8 gbd_bphy_sleep_counter; /* Sleep count for bphy GBD */ + uint8 gbd_ofdm_sleep_counter; /* Sleep count for ofdm GBD */ + uint8 btc_mode; /* btc mode */ + uint8 gbd_ofdm_desense; /* Glitch based desense level for ofdm reception */ + uint8 gbd_bphy_desense; /* Glitch based desense level for bphy reception */ + int8 chiptemp; /* Chip temperature */ + int8 femtemp; /* Fem temperature */ + int8 weakest_rssi; /* Weakest link RSSI */ + int8 ltecx_mode; /* LTE coex desense mode */ + int32 btcx_mode; /* BT coex desense mode */ + uint8 chan_switch_cnt; /* Count to track channel change */ + uint8 phycal_disable; /* Status of phy calibration */ + int8 rxsense_noise_idx; /* rxsense det thresh desense idx */ + int8 rxsense_offset; /* rxsense min power desense idx */ + uint16 featureflag; /* Currently active feature flags */ + uint16 deaf_count; /* Count for RX stay in carrier search state */ + uint16 noise_mmt_overdue; /* Noise measurement overdue status */ + uint16 crsmin_pwr_apply_cnt; /* Count for desense updates */ + uint16 ed_crs_status; /* Status of ED and CRS during noise cal */ + uint16 preempt_status1; /* status of preemption */ + uint16 preempt_status2; /* status of preemption */ + uint16 preempt_status3; /* status of preemption */ + uint16 preempt_status4; /* status of preemption */ + uint16 counter_noise_iqest_to; /* count of IQ_Est time out */ + uint32 cca_stats_total_glitch; /* ccastats: count of total glitches */ + uint32 cca_stats_bphy_glitch; /* ccastats: count of bphy glitches */ + uint32 cca_stats_total_badplcp; /* ccastats: count of total badplcp */ + uint32 cca_stats_bphy_badplcp; /* ccastats: count of bphy badplcp */ + uint32 cca_stats_mbsstime; /* ccastats: monitor duration in msec */ + uint32 cca_stats_ed_duration; /* ccastats: ed_duration */ + uint32 measurehold; /* PHY hold activities */ + uint32 rxsense_disable_req_ch; /* channel disable requests */ + uint32 ocl_disable_reqs; /* OCL disable bitmap */ + uint32 interference_mode; /* interference mitigation mode */ + uint32 power_mode; /* power mode */ + uint32 obss_last_read_time; /* last stats read time */ + int32 asym_intf_ed_thresh; /* smartcca ed threshold %d */ + uint16 obss_mit_bw; /* selected mitigation BW */ + uint16 obss_stats_cnt; /* stats count */ + uint16 dynbw_init_reducebw_cnt; /* BW reduction cnt of initiator */ + uint16 dynbw_resp_reducebw_cnt; /* BW reduction cnt of responder */ + uint16 dynbw_rxdata_reducebw_cnt; /* rx data cnt with reduced BW */ + uint16 obss_mmt_skip_cnt; /* mmt skipped due to powersave */ + uint16 obss_mmt_no_result_cnt; /* mmt with no result */ + uint16 obss_mmt_intr_err_cnt; /* obss reg mismatch between ucode and fw */ + uint16 gci_lst_inv_ctr; /* last gci invalid */ + uint16 gci_lst_rst_ctr; /* last gci restore 0x%04x */ + uint16 gci_lst_sem_ctr; /* last gci seq number 0x%04x */ + uint16 gci_lst_rb_st; /* last gci status */ + uint16 gci_dbg01; /* gci dbg1 readback */ + uint16 gci_dbg02; /* gci dbg2 readback */ + uint16 gci_dbg03; /* gci dbg3 readback */ + uint16 gci_dbg04; /* gci dbg4 readback */ + uint16 gci_dbg05; /* gci dbg5 readback */ + uint16 gci_lst_st_msk; /* gci last status mask */ + uint16 gci_inv_tx; /* invalid gci during tx */ + uint16 gci_inv_rx; /* invalid gci during rx */ + uint16 gci_rst_tx; /* gci restore during tx */ + uint16 gci_rst_rx; /* gci restore during rx */ + uint16 gci_sem_ctr; /* gci seq number ctr */ + uint16 gci_invstate; /* gci status 0x%04x */ + uint16 gci_ctl2; /* gci ctrl 2 */ + uint16 gci_chan; /* channel during gci read 0x%04x */ + uint16 gci_cm; /* channel during gci read */ + uint16 gci_sc; /* gci read during scan */ + uint16 gci_rst_sc; /* gci restore during scan */ + uint16 gci_prdc_rx; /* periodic gci hc */ + uint16 gci_wk_rx; /* gci hc during wake */ + uint16 gci_rmac_rx; /* gci hc during mac read */ + uint16 gci_tx_rx; /* gci hc during tx/rx */ + uint16 asym_intf_stats; /* smartCCA status 0x%04x */ + uint16 asym_intf_ncal_crs_stat; /* noise cal and crs status %d */ + int16 ed_crsEn; /* ed enable 0x%04x */ + int16 nvcfg0; /* noise update to hw 0x%04x */ + uint8 cal_suppressed_cntr_ed; /* cnt including ss, mp cals, MSB is cur state */ + uint8 sc_dccal_incc_cnt; /* scan dccal counter */ + uint8 sc_noisecal_incc_cnt; /* scan noise cal counter */ + uint8 obss_need_updt; /* BW update needed flag */ + uint8 obss_mit_status; /* obss mitigation status */ + uint8 obss_last_rec_bw; /* last recommended bw to wlc-Sent to SW */ + uint8 asym_intf_ant_noise_idx; /* current noise storage index */ + uint8 asym_intf_pending_host_req_type; /* usb plugin request */ + uint8 asym_intf_ncal_crs_stat_idx; /* crs status storage index %d */ + int8 asym_intf_tx_smartcca_cm; /* smartCCA tx coremask %d */ + int8 asym_intf_rx_noise_mit_cm; /* smartCCA rx coremask %d */ + int8 asym_intf_avg_noise[2]; /* average noise %d */ + int8 asym_intf_latest_noise[2]; /* current noise %d */ + uint8 obss_curr_det[ACPHY_OBSS_SUBBAND_CNT]; /* obss curr detection */ + uint8 debug_01; /* padding */ + uint8 debug_02; /* padding */ + uint8 debug_03; /* padding */ + phy_ecounter_log_core_v4_t phy_ecounter_core[2]; +} phy_ecounter_v5_t; + +/* For trunk ONLY */ +/* Do not remove phy_ecounter_v1_t parameters */ +typedef struct phy_ecounter_v255 { + chanspec_t chanspec; + uint16 phy_wdg; /* Count of times watchdog happened. */ + uint16 noise_req; /* Count of phy noise sample requests. */ + uint16 noise_crsbit; /* Count of CRS high during noisecal request. */ + uint16 noise_apply; /* Count of applying noisecal result to crsmin. */ + uint16 cal_counter; /* Count of performing single and multi phase cal. */ + uint8 slice; /* Slice # 0 - MAIN, 1 - AUX, 2 - SCAN */ + uint8 rxchain; /* Status of active RX chains */ + uint8 txchain; /* Status of active TX chains */ + uint8 gbd_bphy_sleep_counter; /* Sleep count for bphy GBD */ + uint8 gbd_ofdm_sleep_counter; /* Sleep count for ofdm GBD */ + uint8 btc_mode; /* btc mode */ + uint8 gbd_ofdm_desense; /* Glitch based desense level for ofdm reception */ + uint8 gbd_bphy_desense; /* Glitch based desense level for bphy reception */ + int8 chiptemp; /* Chip temperature */ + int8 femtemp; /* Fem temperature */ + int8 weakest_rssi; /* Weakest link RSSI */ + int8 ltecx_mode; /* LTE coex desense mode */ + int32 btcx_mode; /* BT coex desense mode */ + uint8 chan_switch_cnt; /* Count to track channel change */ + uint8 phycal_disable; /* Status of phy calibration */ + int8 rxsense_noise_idx; /* rxsense det thresh desense idx */ + int8 rxsense_offset; /* rxsense min power desense idx */ + uint16 featureflag; /* Currently active feature flags */ + uint16 deaf_count; /* Count for RX stay in carrier search state */ + uint16 noise_mmt_overdue; /* Noise measurement overdue status */ + uint16 crsmin_pwr_apply_cnt; /* Count for desense updates */ + uint16 ed_crs_status; /* Status of ED and CRS during noise cal */ + uint16 preempt_status1; /* status of preemption */ + uint16 preempt_status2; /* status of preemption */ + uint16 preempt_status3; /* status of preemption */ + uint16 preempt_status4; /* status of preemption */ + uint16 counter_noise_iqest_to; /* count of IQ_Est time out */ + uint32 cca_stats_total_glitch; /* ccastats: count of total glitches */ + uint32 cca_stats_bphy_glitch; /* ccastats: count of bphy glitches */ + uint32 cca_stats_total_badplcp; /* ccastats: count of total badplcp */ + uint32 cca_stats_bphy_badplcp; /* ccastats: count of bphy badplcp */ + uint32 cca_stats_mbsstime; /* ccastats: monitor duration in msec */ + uint32 cca_stats_ed_duration; /* ccastats: ed_duration */ + uint32 measurehold; /* PHY hold activities */ + uint32 rxsense_disable_req_ch; /* channel disable requests */ + uint32 ocl_disable_reqs; /* OCL disable bitmap */ + uint32 interference_mode; /* interference mitigation mode */ + uint32 power_mode; /* power mode */ + uint32 obss_last_read_time; /* last stats read time */ + int32 asym_intf_ed_thresh; /* smartcca ed threshold %d */ + uint16 obss_mit_bw; /* selected mitigation BW */ + uint16 obss_stats_cnt; /* stats count */ + uint16 dynbw_init_reducebw_cnt; /* BW reduction cnt of initiator */ + uint16 dynbw_resp_reducebw_cnt; /* BW reduction cnt of responder */ + uint16 dynbw_rxdata_reducebw_cnt; /* rx data cnt with reduced BW */ + uint16 obss_mmt_skip_cnt; /* mmt skipped due to powersave */ + uint16 obss_mmt_no_result_cnt; /* mmt with no result */ + uint16 obss_mmt_intr_err_cnt; /* obss reg mismatch between ucode and fw */ + uint16 gci_lst_inv_ctr; /* last gci invalid */ + uint16 gci_lst_rst_ctr; /* last gci restore 0x%04x */ + uint16 gci_lst_sem_ctr; /* last gci seq number 0x%04x */ + uint16 gci_lst_rb_st; /* last gci status */ + uint16 gci_dbg01; /* gci dbg1 readback */ + uint16 gci_dbg02; /* gci dbg2 readback */ + uint16 gci_dbg03; /* gci dbg3 readback */ + uint16 gci_dbg04; /* gci dbg4 readback */ + uint16 gci_dbg05; /* gci dbg5 readback */ + uint16 gci_lst_st_msk; /* gci last status mask */ + uint16 gci_inv_tx; /* invalid gci during tx */ + uint16 gci_inv_rx; /* invalid gci during rx */ + uint16 gci_rst_tx; /* gci restore during tx */ + uint16 gci_rst_rx; /* gci restore during rx */ + uint16 gci_sem_ctr; /* gci seq number ctr */ + uint16 gci_invstate; /* gci status 0x%04x */ + uint16 gci_ctl2; /* gci ctrl 2 */ + uint16 gci_chan; /* channel during gci read 0x%04x */ + uint16 gci_cm; /* channel during gci read */ + uint16 gci_sc; /* gci read during scan */ + uint16 gci_rst_sc; /* gci restore during scan */ + uint16 gci_prdc_rx; /* periodic gci hc */ + uint16 gci_wk_rx; /* gci hc during wake */ + uint16 gci_rmac_rx; /* gci hc during mac read */ + uint16 gci_tx_rx; /* gci hc during tx/rx */ + uint16 asym_intf_stats; /* smartCCA status 0x%04x */ + uint16 asym_intf_ncal_crs_stat; /* noise cal and crs status %d */ + int16 ed_crsEn; /* ed enable 0x%04x */ + int16 nvcfg0; /* noise update to hw 0x%04x */ + uint8 cal_suppressed_cntr_ed; /* cnt including ss, mp cals, MSB is cur state */ + uint8 sc_dccal_incc_cnt; /* scan dccal counter */ + uint8 sc_noisecal_incc_cnt; /* scan noise cal counter */ + uint8 obss_need_updt; /* BW update needed flag */ + uint8 obss_mit_status; /* obss mitigation status */ + uint8 obss_last_rec_bw; /* last recommended bw to wlc-Sent to SW */ + uint8 asym_intf_ant_noise_idx; /* current noise storage index */ + uint8 asym_intf_pending_host_req_type; /* usb plugin request */ + uint8 asym_intf_ncal_crs_stat_idx; /* crs status storage index %d */ + int8 asym_intf_tx_smartcca_cm; /* smartCCA tx coremask %d */ + int8 asym_intf_rx_noise_mit_cm; /* smartCCA rx coremask %d */ + int8 asym_intf_avg_noise[2]; /* average noise %d */ + int8 asym_intf_latest_noise[2]; /* current noise %d */ + uint8 obss_curr_det[ACPHY_OBSS_SUBBAND_CNT]; /* obss curr detection */ + uint8 debug_01; /* padding */ + uint8 debug_02; /* padding */ + uint8 debug_03; /* padding */ + phy_ecounter_log_core_v255_t phy_ecounter_core[2]; +} phy_ecounter_v255_t; + +typedef struct phy_ecounter_phycal_core_v1 { + /* RxIQ imbalance coeff */ + int32 rxs; + int32 rxs_vpoff; + int32 rxs_ipoff; + /* OFDM and BPHY TxIQ imbalance coeff */ + uint16 ofdm_txa; + uint16 ofdm_txb; + uint16 ofdm_txd; /* contain di & dq */ + uint16 bphy_txa; + uint16 bphy_txb; + uint16 bphy_txd; /* contain di & dq */ + /* the number of times the baseidx is + * greater than a certain threshold + */ + uint16 txbaseidx_gtthres_cnt; + /* RxIQ imbalance coeff */ + uint16 rxa; + uint16 rxb; + uint8 PAD2; + uint8 PAD3; + /* Rx IQ Cal coeff */ + uint16 rxa_vpoff; /* not present in 4378 */ + uint16 rxb_vpoff; /* not present in 4378 */ + uint16 rxa_ipoff; /* not present in 4378 */ + uint16 rxb_ipoff; /* not present in 4378 */ + /* Tx IQ/LO calibration coeffs */ + uint16 txiqlo_2g_a0; + uint16 txiqlo_2g_b0; + uint16 txiqlo_2g_a1; + uint16 txiqlo_2g_b1; + uint16 txiqlo_2g_a2; + uint16 txiqlo_2g_b2; + /* tx baseindex */ + uint8 baseidx; + uint8 baseidx_cck; + /* adc cap cal */ + uint8 adc_coeff_cap0_adcI; + uint8 adc_coeff_cap1_adcI; + uint8 adc_coeff_cap2_adcI; + uint8 adc_coeff_cap0_adcQ; + uint8 adc_coeff_cap1_adcQ; + uint8 adc_coeff_cap2_adcQ; +} phy_ecounter_phycal_core_v1_t; + +typedef struct phy_phycal_core_v2 { + /* RxIQ imbalance coeff */ + int32 rxs; + + /* OFDM and BPHY TxIQ imbalance coeff */ + uint16 ofdm_txa; + uint16 ofdm_txb; + uint16 ofdm_txd; /* contain di & dq */ + uint16 bphy_txa; + uint16 bphy_txb; + uint16 bphy_txd; + + /* RxIQ imbalance coeff */ + uint16 rxa; + uint16 rxb; + + /* Rx IQ Cal coeff */ + uint16 rxa_vpoff; + uint16 rxb_vpoff; + uint16 rxa_ipoff; + uint16 rxb_ipoff; + int32 rxs_vpoff; + int32 rxs_ipoff; + /* Tx IQ/LO calibration coeffs */ + uint16 txiqlo_2g_a0; + uint16 txiqlo_2g_b0; + uint16 txiqlo_2g_a1; + uint16 txiqlo_2g_b1; + uint16 txiqlo_2g_a2; + uint16 txiqlo_2g_b2; + /* tx baseindex */ + uint8 baseidx; + uint8 baseidx_cck; + /* adc cap cal */ + uint8 adc_coeff_cap0_adcI; + uint8 adc_coeff_cap1_adcI; + uint8 adc_coeff_cap2_adcI; + uint8 adc_coeff_cap0_adcQ; + uint8 adc_coeff_cap1_adcQ; + uint8 adc_coeff_cap2_adcQ; + + int32 txs; + int16 txs_mean; + uint16 txbaseidx_gtthres_cnt; /* cntr for tx_baseidx > hi_thres in healthcheck */ + uint16 txgain_rad_gain; + uint16 txgain_rad_gain_mi; + uint16 txgain_rad_gain_hi; + uint16 txgain_dac_gain; + uint16 txgain_bbmult; + int16 rxs_mean_vpoff; + int16 rxs_mean_ipoff; + int16 rxs_mean; + uint8 rxms; + uint8 rxms_vpoff; + uint8 rxms_ipoff; + uint8 ccktxgain_offset; + int8 mppc_gain_offset_qdB[TXCAL_MAX_PA_MODE]; + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint8 debug_01; + uint8 debug_02; + uint8 debug_03; + uint8 debug_04; + uint16 debug_05; + uint16 debug_06; + uint16 debug_07; + uint16 debug_08; + uint32 debug_09; + uint32 debug_10; + uint32 debug_11; + uint32 debug_12; +} phy_phycal_core_v2_t; + +/* For trunk ONLY */ +typedef struct phy_phycal_core_v255 { + /* RxIQ imbalance coeff */ + int32 rxs; + + /* OFDM and BPHY TxIQ imbalance coeff */ + uint16 ofdm_txa; + uint16 ofdm_txb; + uint16 ofdm_txd; /* contain di & dq */ + uint16 bphy_txa; + uint16 bphy_txb; + uint16 bphy_txd; + + /* RxIQ imbalance coeff */ + uint16 rxa; + uint16 rxb; + + /* Rx IQ Cal coeff */ + uint16 rxa_vpoff; + uint16 rxb_vpoff; + uint16 rxa_ipoff; + uint16 rxb_ipoff; + int32 rxs_vpoff; + int32 rxs_ipoff; + /* Tx IQ/LO calibration coeffs */ + uint16 txiqlo_2g_a0; + uint16 txiqlo_2g_b0; + uint16 txiqlo_2g_a1; + uint16 txiqlo_2g_b1; + uint16 txiqlo_2g_a2; + uint16 txiqlo_2g_b2; + /* tx baseindex */ + uint8 baseidx; + uint8 baseidx_cck; + /* adc cap cal */ + uint8 adc_coeff_cap0_adcI; + uint8 adc_coeff_cap1_adcI; + uint8 adc_coeff_cap2_adcI; + uint8 adc_coeff_cap0_adcQ; + uint8 adc_coeff_cap1_adcQ; + uint8 adc_coeff_cap2_adcQ; + + int32 txs; + int16 txs_mean; + uint16 txbaseidx_gtthres_cnt; /* cntr for tx_baseidx > hi_thres in healthcheck */ + uint16 txgain_rad_gain; + uint16 txgain_rad_gain_mi; + uint16 txgain_rad_gain_hi; + uint16 txgain_dac_gain; + uint16 txgain_bbmult; + int16 rxs_mean_vpoff; + int16 rxs_mean_ipoff; + int16 rxs_mean; + uint8 rxms; + uint8 rxms_vpoff; + uint8 rxms_ipoff; + uint8 ccktxgain_offset; + int8 mppc_gain_offset_qdB[TXCAL_MAX_PA_MODE]; + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint8 debug_01; + uint8 debug_02; + uint8 debug_03; + uint8 debug_04; + uint16 debug_05; + uint16 debug_06; + uint16 debug_07; + uint16 debug_08; + uint32 debug_09; + uint32 debug_10; + uint32 debug_11; + uint32 debug_12; +} phy_phycal_core_v255_t; + +typedef struct phy_ecounter_phycal_v1 { + uint32 last_cal_time; /* in [sec], covers 136 years if 32 bit */ + chanspec_t chanspec; + int16 last_cal_temp; + bool txiqlocal_retry; + bool rxe; + uint8 cal_phase_id; + uint8 slice; + phy_ecounter_phycal_core_v1_t phy_ecounter_phycal_core[2]; +} phy_ecounter_phycal_v1_t; + +typedef struct phy_phycal_v2 { + uint32 last_cal_time; /* in [sec], covers 136 years if 32 bit */ + chanspec_t chanspec; + int16 last_cal_temp; + bool txiqlocal_retry; + bool rxe; + uint8 cal_phase_id; + uint8 slice; + uint32 desense_reason; + uint16 dur; /* duration of cal in usec */ + + uint8 reason; + uint8 hc_retry_count_vpoff; + uint8 hc_retry_count_ipoff; + uint8 hc_retry_count_rx; + uint8 hc_dev_exceed_log_rx_vpoff; + uint8 hc_dev_exceed_log_rx_ipoff; + uint8 hc_dev_exceed_log_rx; + uint8 sc_rxiqcal_skip_cnt; + + uint8 hc_retry_count_tx; + uint8 hc_dev_exceed_log_tx; + uint16 txiqcal_max_retry_cnt; + uint16 txiqcal_max_slope_cnt; + uint16 mppc_cal_failed_count; + uint16 pad01; + uint16 txiqlocal_coeffs[20]; + bool is_mppc_gain_offset_cal_success; + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint8 debug_01; + uint8 debug_02; + uint8 debug_03; + uint16 debug_04; + uint16 debug_05; + uint16 debug_06; + uint16 debug_07; + uint32 debug_08; + uint32 debug_09; + uint32 debug_10; + uint32 debug_11; + + phy_phycal_core_v2_t phy_phycal_core[2]; +} phy_phycal_v2_t; + +/* For trunk ONLY */ +typedef struct phy_phycal_v255 { + uint32 last_cal_time; /* in [sec], covers 136 years if 32 bit */ + chanspec_t chanspec; + int16 last_cal_temp; + uint8 txiqlocal_retry; + uint8 rxe; + uint8 cal_phase_id; + uint8 slice; + uint32 desense_reason; + uint16 dur; /* duration of cal in usec */ + + uint8 reason; + uint8 hc_retry_count_vpoff; + uint8 hc_retry_count_ipoff; + uint8 hc_retry_count_rx; + uint8 hc_dev_exceed_log_rx_vpoff; + uint8 hc_dev_exceed_log_rx_ipoff; + uint8 hc_dev_exceed_log_rx; + uint8 sc_rxiqcal_skip_cnt; + + uint8 hc_retry_count_tx; + uint8 hc_dev_exceed_log_tx; + uint16 txiqcal_max_retry_cnt; + uint16 txiqcal_max_slope_cnt; + uint16 mppc_cal_failed_count; + uint16 pad01; + uint16 txiqlocal_coeffs[20]; + uint8 is_mppc_gain_offset_cal_success; + + /* Misc general purpose debug counters (will be used for future debugging) */ + uint8 debug_01; + uint8 debug_02; + uint8 debug_03; + uint16 debug_04; + uint16 debug_05; + uint16 debug_06; + uint16 debug_07; + uint32 debug_08; + uint32 debug_09; + uint32 debug_10; + uint32 debug_11; + + phy_phycal_core_v255_t phy_phycal_core[2]; +} phy_phycal_v255_t; + +#define PHY_ECOUNTERS_PHYCAL_STATS_VER1 1u +typedef struct phy_ecounter_phycal_stats_v1 { + uint16 version; + uint16 length; + uint8 num_channel; /* Number of active channels. */ + uint8 PAD[3]; + phy_ecounter_phycal_v1_t phy_counter[]; +} phy_ecounter_phycal_stats_v1_t; + +#define PHY_ECOUNTERS_PHYCAL_STATS_VER2 2u +typedef struct phy_ecounter_phycal_stats_v2 { + uint16 version; + uint16 length; + uint8 num_channel; /* Number of active channels. */ + uint8 PAD[3]; + phy_phycal_v2_t phy_counter[]; +} phy_ecounter_phycal_stats_v2_t; + +/* For trunk ONLY */ +#define PHY_ECOUNTERS_PHYCAL_STATS_VER255 255u +typedef struct phy_ecounter_phycal_stats_v255 { + uint16 version; + uint16 length; + uint8 num_channel; /* Number of active channels. */ + uint8 PAD[3]; + phy_phycal_v255_t phy_counter[]; +} phy_ecounter_phycal_stats_v255_t; + +#define PHY_ECOUNTERS_STATS_VER1 1u +typedef struct phy_ecounter_stats_v1 { + uint16 version; + uint16 length; + uint8 num_channel; /* Number of active channels. */ + uint8 PAD; + phy_ecounter_v1_t phy_counter[]; +} phy_ecounter_stats_v1_t; + +#define PHY_ECOUNTERS_STATS_VER2 2u +typedef struct phy_ecounter_stats_v2 { + uint16 version; + uint16 length; + uint8 num_channel; /* Number of active channels. */ + uint8 PAD[3]; + phy_ecounter_v2_t phy_counter[]; +} phy_ecounter_stats_v2_t; + +#define PHY_ECOUNTERS_STATS_VER3 3u +typedef struct phy_ecounter_stats_v3 { + uint16 version; + uint16 length; + uint8 num_channel; /* Number of active channels. */ + uint8 PAD[3]; + phy_ecounter_v3_t phy_counter[]; +} phy_ecounter_stats_v3_t; + +#define PHY_ECOUNTERS_STATS_VER4 4u +typedef struct phy_ecounter_stats_v4 { + uint16 version; + uint16 length; + uint8 num_channel; /* Number of active channels. */ + uint8 PAD[3]; + phy_ecounter_v4_t phy_counter[]; +} phy_ecounter_stats_v4_t; + +#define PHY_ECOUNTERS_STATS_VER5 5u +typedef struct phy_ecounter_stats_v5 { + uint16 version; + uint16 length; + uint8 num_channel; /* Number of active channels. */ + uint8 PAD[3]; + phy_ecounter_v5_t phy_counter[]; +} phy_ecounter_stats_v5_t; + +/* For trunk ONLY */ +#define PHY_ECOUNTERS_STATS_VER255 255u +typedef struct phy_ecounter_stats_v255 { + uint16 version; + uint16 length; + uint8 num_channel; /* Number of active channels. */ + uint8 PAD[3]; + phy_ecounter_v255_t phy_counter[]; +} phy_ecounter_stats_v255_t; + /* Durations for each bt task in millisecond */ +#define WL_BTCX_DURSTATS_VER_2 (2u) +typedef struct wlc_btcx_durstats_v2 { + uint16 version; /* version number of struct */ + uint16 valid; /* validity of this struct */ + uint32 stats_update_timestamp; /* tStamp when data is updated */ + uint16 bt_acl_dur; /* acl duration in ms */ + uint16 bt_sco_dur; /* sco duration in ms */ + uint16 bt_esco_dur; /* esco duration in ms */ + uint16 bt_a2dp_dur; /* a2dp duration in ms */ + uint16 bt_sniff_dur; /* sniff duration in ms */ + uint16 bt_pscan_dur; /* page scan duration in ms */ + uint16 bt_iscan_dur; /* inquiry scan duration in ms */ + uint16 bt_page_dur; /* paging duration in ms */ + uint16 bt_inquiry_dur; /* inquiry duration in ms */ + uint16 bt_mss_dur; /* mss duration in ms */ + uint16 bt_park_dur; /* park duration in ms */ + uint16 bt_rssiscan_dur; /* rssiscan duration in ms */ + uint16 bt_iscan_sco_dur; /* inquiry scan sco duration in ms */ + uint16 bt_pscan_sco_dur; /* page scan sco duration in ms */ + uint16 bt_tpoll_dur; /* tpoll duration in ms */ + uint16 bt_sacq_dur; /* sacq duration in ms */ + uint16 bt_sdata_dur; /* sdata duration in ms */ + uint16 bt_rs_listen_dur; /* rs listen duration in ms */ + uint16 bt_rs_burst_dur; /* rs brust duration in ms */ + uint16 bt_ble_adv_dur; /* ble adv duration in ms */ + uint16 bt_ble_scan_dur; /* ble scan duration in ms */ + uint16 bt_ble_init_dur; /* ble init duration in ms */ + uint16 bt_ble_conn_dur; /* ble connection duration in ms */ + uint16 bt_task_lmp_dur; /* lmp duration in ms */ + uint16 bt_esco_retran_dur; /* esco retransmission duration in ms */ + uint16 bt_task26_dur; /* task26 duration in ms */ + uint16 bt_task27_dur; /* task27 duration in ms */ + uint16 bt_task28_dur; /* task28 duration in ms */ + uint16 bt_task_pred_dur; /* prediction task duration in ms */ + uint16 bt_multihid_dur; /* multihid duration in ms */ + uint16 bt_scan_tx_dur; /* Scan Tx duration in ms */ + uint16 bt_disable_dual_bt_dur; /* Duration of Dual BT disable */ +} wlc_btcx_durstats_v2_t; + #define WL_BTCX_DURSTATS_VER_1 (1u) typedef struct wlc_btcx_durstats_v1 { uint16 version; /* version number of struct */ @@ -10823,57 +12393,60 @@ typedef struct wlc_btcx_durstats_v1 { #define WL_IPFO_ROUTE_TBL_FIXED_LEN 4 #define WL_MAX_IPFO_ROUTE_TBL_ENTRY 64 - /* Global ASSERT Logging */ -#define ASSERTLOG_CUR_VER 0x0100 +/* Global ASSERT Logging */ +#define ASSERTLOG_VERSION_0x0100 0x0100u #define MAX_ASSRTSTR_LEN 64 - typedef struct assert_record { - uint32 time; - uint8 seq_num; - int8 str[MAX_ASSRTSTR_LEN]; - } assert_record_t; +typedef struct assert_record { + uint32 time; + uint8 seq_num; + int8 str[MAX_ASSRTSTR_LEN]; + uint8 PAD[3]; +} assert_record_t; - typedef struct assertlog_results { - uint16 version; - uint16 record_len; - uint32 num; - assert_record_t logs[1]; - } assertlog_results_t; +typedef struct assertlog_results { + uint16 version; + uint16 record_len; + uint32 num; + assert_record_t logs[BCM_FLEX_ARRAY]; +} assertlog_results_t; #define LOGRRC_FIX_LEN 8 #define IOBUF_ALLOWED_NUM_OF_LOGREC(type, len) ((len - LOGRRC_FIX_LEN)/sizeof(type)) /* BCMWAPI_WAI */ #define IV_LEN 16 /* same as SMS4_WPI_PN_LEN */ - struct wapi_sta_msg_t - { - uint16 msg_type; - uint16 datalen; - uint8 vap_mac[6]; - uint8 reserve_data1[2]; - uint8 sta_mac[6]; - uint8 reserve_data2[2]; - uint8 gsn[IV_LEN]; - uint8 wie[TLV_BODY_LEN_MAX + TLV_HDR_LEN]; /* 257 */ - uint8 pad[3]; /* padding for alignment */ - }; +struct wapi_sta_msg_t { + uint16 msg_type; + uint16 datalen; + uint8 vap_mac[6]; + uint8 reserve_data1[2]; + uint8 sta_mac[6]; + uint8 reserve_data2[2]; + uint8 gsn[IV_LEN]; + uint8 wie[TLV_BODY_LEN_MAX + TLV_HDR_LEN]; /* 257 */ + uint8 PAD[3]; /* padding for alignment */ +}; /* #endif BCMWAPI_WAI */ - /* chanim acs record */ - typedef struct { - uint8 valid; - uint8 trigger; - chanspec_t selected_chspc; - int8 bgnoise; - uint32 glitch_cnt; - uint8 ccastats; - uint8 chan_idle; - uint32 timestamp; - } chanim_acs_record_t; +/* chanim acs record */ +typedef struct { + uint8 valid; + uint8 trigger; + chanspec_t selected_chspc; + int8 bgnoise; + uint8 PAD[3]; + uint32 glitch_cnt; + uint8 ccastats; + uint8 chan_idle; + uint8 PAD[2]; + uint32 timestamp; +} chanim_acs_record_t; - typedef struct { - chanim_acs_record_t acs_record[CHANIM_ACS_RECORD]; - uint8 count; - uint32 timestamp; - } wl_acs_record_t; +typedef struct { + chanim_acs_record_t acs_record[CHANIM_ACS_RECORD]; + uint8 count; + uint8 PAD[3]; + uint32 timestamp; +} wl_acs_record_t; #define WL_CHANIM_STATS_V2 2 #define CCASTATS_V2_MAX 9 @@ -10905,12 +12478,12 @@ typedef struct chanim_stats { uint8 PAD[3]; } chanim_stats_t; -#define WL_CHANIM_STATS_VERSION 3 +#define WL_CHANIM_STATS_VERSION_3 3 typedef struct { uint32 buflen; uint32 version; uint32 count; - chanim_stats_t stats[1]; + chanim_stats_t stats[BCM_FLEX_ARRAY]; } wl_chanim_stats_t; #define WL_SC_CHANIM_STATS_V1 1u @@ -10945,7 +12518,7 @@ typedef struct { * WL_CHANIM_COUNT_ONE */ uint8 PAD; - sc_chanim_stats_v1_t sc_stats[1]; + sc_chanim_stats_v1_t sc_stats[BCM_FLEX_ARRAY]; } wl_chanim_sc_stats_v1_t; /* WL_CHANIM_SC_STATS_FIXED_LEN: when we change size of any field above sc_stats, this macro @@ -10989,7 +12562,7 @@ typedef struct { * WL_CHANIM_COUNT_ONE */ uint8 PAD; - sc_chanim_stats_v2_t sc_stats[1]; + sc_chanim_stats_v2_t sc_stats[BCM_FLEX_ARRAY]; } wl_chanim_sc_stats_v2_t; #define WL_SC_CHANIM_STATS_V3 3u @@ -11029,7 +12602,7 @@ typedef struct { * WL_CHANIM_COUNT_ONE */ uint8 PAD; - sc_chanim_stats_v3_t sc_stats[1]; + sc_chanim_stats_v3_t sc_stats[BCM_FLEX_ARRAY]; } wl_chanim_sc_stats_v3_t; #define WL_SC_CHANIM_STATS_V4 4u @@ -11070,7 +12643,7 @@ typedef struct { * WL_CHANIM_COUNT_ONE */ uint8 PAD; - sc_chanim_stats_v4_t sc_stats[1]; + sc_chanim_stats_v4_t sc_stats[BCM_FLEX_ARRAY]; } wl_chanim_sc_stats_v4_t; #define WL_SC_CHANIM_STATS_V5 5u @@ -11111,9 +12684,53 @@ typedef struct { * WL_CHANIM_COUNT_ONE */ uint8 PAD; - sc_chanim_stats_v5_t sc_stats[1]; + sc_chanim_stats_v5_t sc_stats[BCM_FLEX_ARRAY]; } wl_chanim_sc_stats_v5_t; +#define WL_SC_CHANIM_STATS_V6 6u +/* sc chanim interface stats */ +typedef struct sc_chanim_stats_v6 { + uint32 stats_ms; /* duraion for which stats are collected, in ms */ + chanspec_t chanspec; + uint16 sc_btrx_trans_cnt; /* BT RX transitions */ + uint32 sc_only_rx_dur; /* rx only on sc, in ms */ + uint32 sc_rx_mc_rx_dur; /* Rx on SC when MC is active, in ms */ + uint32 sc_rx_ac_rx_dur; /* Rx on SC when AC is active, in ms */ + uint32 sc_rx_mc_tx_dur; /* sc rx with MC tx, in ms */ + uint32 sc_rx_ac_bt_tx_dur; /* sc rx with AC-BT tx, in ms */ + uint32 sc_rx_bt_rx_dur; /* sc rx when BT Main is active, in ms */ + uint32 sc_btle_overlap_dur; /* wlsc was awake and btsc le scan overlapped, in ms */ + uint32 sc_btpage_overlap_dur; /* wlsc was awake and btsc page scan overlapped, in ms */ + uint32 ac_btle_blnk_dur; /* wlauxtx blanked btsc le scan, in ms */ + uint32 ac_btpage_blnk_dur; /* wlauxtx blanked btsc page scan, in ms */ + uint32 ac_btle_overlap_dur; /* wlaux was awake and btsc le scan overlapped, in ms */ + uint32 ac_btpage_overlap_dur; /* wlaux was awake and btsc page scan overlapped, in ms */ + uint32 timestamp; /* Time when stats last updated */ + uint32 sc_rx_5g_bt_rx_dur; /* sc rx when 5G BT Main is active, in ms */ + uint16 sc_5g_btrx_trans_cnt; /* 5G BT RX transitions */ + uint16 pad; +} sc_chanim_stats_v6_t; + +typedef struct { + uint32 version; + uint32 length; + uint8 flags; /* flags: to print the stats, + * WL_CHANIM_COUNT_ONE ==> Query stats for Home channel, + * WL_CHANIM_COUNT_ALL ==> Query stats for all channels + */ + uint8 id; /* Module id, to know which module has sent the stats + * SC_CHANIM_ID_SCAN ==> For SCAN + * SC_CHANIM_ID_STA ==> For STA + */ + uint8 count; /* o/p: Count of channels for which stats needs to be displayed. + * This value is number of channels supported in particular locale when + * flags is WL_CHANIM_COUNT_ALL, one when flag is + * WL_CHANIM_COUNT_ONE + */ + uint8 PAD; + sc_chanim_stats_v6_t sc_stats[]; +} wl_chanim_sc_stats_v6_t; + /* sc_chanim periodic ecounters structs for WL_IFSTATS_XTLV_SC_CHANIM_PERIODIC_STATS * [similar to wl_chanim_sc_stats_vX_t, but constrained in size due to its known periodicity * of reporting] @@ -11122,7 +12739,7 @@ typedef struct { #define WLC_SC_STATS_MAX_BANDS_V1 2u typedef struct sc_chanim_stats_perband_periodic_v2 { - uint8 pad[3]; + uint8 PAD[3]; uint8 band_id; /* band for which stats reported; 0:5G,1:2G */ uint16 sc_only_rx_dur; /* rx only on sc, in ms */ uint16 sc_rx_mc_rx_dur; /* Rx on SC when MC is active, in ms */ @@ -11139,7 +12756,7 @@ typedef struct sc_chanim_stats_perband_periodic_v2 { typedef struct wl_chanim_sc_periodic_stats_v2 { uint16 ver; uint16 len; - uint8 pad[3]; + uint8 PAD[3]; uint8 count; /* number of sc_stats below */ /* per band accum stats */ sc_chanim_stats_perband_periodic_v2_t sc_stats[WLC_SC_STATS_MAX_BANDS_V1]; @@ -11148,7 +12765,7 @@ typedef struct wl_chanim_sc_periodic_stats_v2 { #define WLC_SC_CHANIM_PERIODIC_STATS_V3 (3u) typedef struct sc_chanim_stats_perband_periodic_v3 { - uint8 pad[3]; + uint8 PAD[3]; uint8 band_id; /* band for which stats reported; 0:5G,1:2G */ uint16 sc_only_rx_dur; /* rx only on sc, in ms */ uint16 sc_rx_mc_rx_dur; /* Rx on SC when MC is active, in ms */ @@ -11167,7 +12784,7 @@ typedef struct sc_chanim_stats_perband_periodic_v3 { typedef struct wl_chanim_sc_periodic_stats_v3 { uint16 ver; uint16 len; - uint8 pad[3]; + uint8 PAD[3]; uint8 count; /* number of sc_stats below */ /* per band accum stats */ sc_chanim_stats_perband_periodic_v3_t sc_stats[WLC_SC_STATS_MAX_BANDS_V1]; @@ -11185,7 +12802,7 @@ typedef struct { /* structure/defines for selective mgmt frame (smf) stats support */ -#define SMFS_VERSION 1 +#define SMFS_VERSION_1 1 /** selected mgmt frame (smf) stats element */ typedef struct wl_smfs_elem { uint32 count; @@ -11201,7 +12818,7 @@ typedef struct wl_smf_stats { uint32 ignored_cnt; uint32 malformed_cnt; uint32 count_total; /**< count included the interested group */ - wl_smfs_elem_t elem[1]; + wl_smfs_elem_t elem[BCM_FLEX_ARRAY]; } wl_smf_stats_t; #define WL_SMFSTATS_FIXED_LEN OFFSETOF(wl_smf_stats_t, elem); @@ -11224,7 +12841,7 @@ typedef enum smfs_type { /* #ifdef PHYMON */ -#define PHYMON_VERSION 1 +#define PHYMON_VERSION_1 1 typedef struct wl_phycal_core_state { /* Tx IQ/LO calibration coeffs */ @@ -11267,7 +12884,7 @@ typedef struct wl_phycal_state { uint16 crsminpower; /**< crsminpower required for ACI */ uint16 crsminpowerl; /**< crsminpowerl required for ACI */ uint16 crsminpoweru; /**< crsminpoweru required for ACI */ - wl_phycal_core_state_t phycal_core[1]; + wl_phycal_core_state_t phycal_core[BCM_FLEX_ARRAY]; } wl_phycal_state_t; #define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core) @@ -11321,7 +12938,7 @@ typedef struct wl_p2p_sched { uint8 action; /**< see schedule action */ uint8 option; /**< see schedule option */ uint8 PAD; - wl_p2p_sched_desc_t desc[1]; + wl_p2p_sched_desc_t desc[BCM_FLEX_ARRAY]; } wl_p2p_sched_t; typedef struct wl_p2p_wfds_hash { @@ -11351,7 +12968,7 @@ typedef struct wl_bcmdcs_data { typedef struct _IHV_NIC_SPECIFIC_EXTENSION { uint8 oui[4]; /**< vendor specific OUI value */ uint32 event; /**< event code */ - uint8 ihvData[1]; /**< ihv data */ + uint8 ihvData[BCM_FLEX_ARRAY]; /**< ihv data */ } IHV_NIC_SPECIFIC_EXTENSION, *PIHV_NIC_SPECIFIC_EXTENSION; #define IHV_NIC_SPECIFIC_EXTENTION_HEADER OFFSETOF(IHV_NIC_SPECIFIC_EXTENSION, ihvData[0]) /* EXT_STA */ @@ -11394,24 +13011,40 @@ enum { SPATIAL_MODE_MAX_IDX }; -#define WLC_TXCORE_MAX 4 /**< max number of txcore supports */ -#define WLC_TXCORE_MAX_OLD 2 /**< backward compatibilty for TXCAL */ -#define WLC_SUBBAND_MAX 4 /**< max number of sub-band supports */ +#define WLC_TXCORE_MAX 4 /**< max number of txcore supports */ +#define WLC_TXCORE_MAX_OLD 2 /**< backward compatibilty for TXCAL */ +#define WLC_TXCORE_MAX_GAINSWEEP_MEAS 2 /* 2 cores max for macos */ +#define WLC_SUBBAND_MAX 4 /**< max number of sub-band supports */ typedef struct { uint8 band2g[WLC_TXCORE_MAX]; uint8 band5g[WLC_SUBBAND_MAX][WLC_TXCORE_MAX]; } sar_limit_t; -#define MAX_NUM_TXCAL_MEAS 128 -#define MAX_NUM_PWR_STEP 40 -#define TXCAL_IOVAR_VERSION 0x1 +#define MAX_NUM_TXCAL_MEAS 128u +#define MIN_NUM_PWR_STEP 2u -#define TXCAL_GAINSWEEP_VER (TXCAL_GAINSWEEP_VERSION_V2) -#define TXCAL_GAINSWEEP_VERSION_V2 2 +#define MAX_NUM_PWR_STEP 40 /* leave it as signed for backward compatibility */ -/* Below macro defines the latest txcal iovar version updated */ -/* This macro also reflects in the 'txcal_ver' iovar */ -#define TXCAL_IOVAR_LATEST TXCAL_GAINSWEEP_VER +#define TXCAL_IOVAR_VERSION 0x1 /* need to leave it as signed one + * for backward compatibility + */ +#define TXCAL_IOVAR_VERSION_0 0x0u +#define TXCAL_IOVAR_VERSION_1 0x1u +#define TXCAL_IOVAR_VERSION_2 0x2u +#define TXCAL_IOVAR_VERSION_3 0x3u +#define TXCAL_IOVAR_VERSION_4 0x4u /* TXCAL_GAINSWEEP_MEAS_VER_V2 */ +#define TXCAL_IOVAR_VERSION_5 0x5u /* TXCAL_GAINSWEEP_MEAS_VER_V2 no pa_modes */ + +#define TXCAL_GAINSWEEP_VER (TXCAL_GAINSWEEP_VERSION_V2) +#define TXCAL_GAINSWEEP_VERSION_V2 2 + +#define TXCAL_GAINSWEEP_MEAS_VER 0x1u +#define TXCAL_GAINSWEEP_MEAS_VER_V2 0x2u + +/* Below macro will no longer be used. + * Please specifiy the current supporting version in the 'txcal_ver' iovar. + */ +#define TXCAL_IOVAR_LATEST TXCAL_GAINSWEEP_VER /* below are used for bphy/ofdm separated LSC */ #define TXCAL_PWR_BPHY 0 @@ -11426,7 +13059,7 @@ typedef struct wl_txcal_meas_ncore { uint16 version; uint8 valid_cnt; uint8 num_core; - wl_txcal_meas_percore_t txcal_percore[1]; + wl_txcal_meas_percore_t txcal_percore[BCM_FLEX_ARRAY]; } wl_txcal_meas_ncore_t; typedef struct wl_txcal_power_tssi_percore { @@ -11434,7 +13067,7 @@ typedef struct wl_txcal_power_tssi_percore { int16 pwr_start; uint8 pwr_start_idx; uint8 num_entries; - uint16 pad; + uint16 PAD; uint8 tssi[MAX_NUM_PWR_STEP]; } wl_txcal_power_tssi_percore_t; @@ -11445,10 +13078,23 @@ typedef struct wl_txcal_power_tssi_ncore { uint8 num_core; uint8 gen_tbl; uint8 ofdm; - uint8 pad; + uint8 PAD; wl_txcal_power_tssi_percore_t tssi_percore[WLC_TXCORE_MAX]; } wl_txcal_power_tssi_ncore_t; +typedef struct wl_txcal_power_tssi_ncore_v2 { + uint16 version; /* structure version */ + uint16 length; /* structure length */ + uint8 set_core; /* set core */ + uint8 num_core; /* number of core */ + uint8 gen_tbl; /* generate table */ + uint8 ofdm; /* ofdm:1 or bphy:0 */ + chanspec_t chanspec; /* chanspec */ + uint8 pa_mode; /* TX PA mode */ + uint8 PAD; /* explict padding */ + wl_txcal_power_tssi_percore_t tssi_percore[WLC_TXCORE_MAX]; /* tssi value entries */ +} wl_txcal_power_tssi_ncore_v2_t; + typedef struct wl_txcal_meas { uint16 tssi[WLC_TXCORE_MAX][MAX_NUM_TXCAL_MEAS]; int16 pwr[WLC_TXCORE_MAX][MAX_NUM_TXCAL_MEAS]; @@ -11475,6 +13121,18 @@ typedef struct wl_txcal_power_tssi { uint8 ofdm; } wl_txcal_power_tssi_t; +typedef struct wl_txcal_power_tssi_v2 { + uint16 version; /* structure version */ + uint16 length; /* structure length */ + chanspec_t chanspec; /* chanspec */ + uint8 set_core; /* set core */ + uint8 gen_tbl; /* generate table */ + uint8 ofdm; /* ofdm:1 or bphy:0 */ + uint8 pa_mode; /* TX PA mode */ + uint8 PAD[2]; /* explicit padding */ + wl_txcal_power_tssi_percore_t per_core[]; /* info per core */ +} wl_txcal_power_tssi_v2_t; + typedef struct wl_txcal_power_tssi_old { uint8 set_core; uint8 channel; @@ -11496,34 +13154,36 @@ typedef struct wl_olpc_pwr { uint8 ofdm; } wl_olpc_pwr_t; -typedef struct wl_rfem_temp_vdet_temp { - uint8 vdet_fem_t1; - int8 rfem_temp_t1; - uint8 vdet_fem_t2; - int8 rfem_temp_t2; -} wl_rfem_temp_vdet_temp_t; +typedef struct wl_olpc_pwr_v2 { + uint16 version; /* structure version */ + uint16 length; /* structure length */ + chanspec_t chanspec; /* chanspec */ + int16 tempsense; /* tempsense */ + uint8 core; /* core selection */ + uint8 olpc_idx; /* tx power index */ + uint8 ofdm; /* ofdm:1 or bphy:0 */ + uint8 pa_mode; /* TX PA mode */ +} wl_olpc_pwr_v2_t; -typedef struct wl_rfem_temp_vin_tssi { - uint16 vin_chip_v1; - int16 tssi_chip_v1; - uint16 vin_chip_v2; - int16 tssi_chip_v2; -} wl_rfem_temp_vin_tssi_t; +/* mode select for olpc_anchor iovar */ +enum olpc_anchor_band { + ANCHOR_MODE_2G = 0, /* anchor mode for 2G */ + ANCHOR_MODE_5G = 1, /* anchor mode for 5G */ + ANCHOR_MODE_6G = 2 /* anchor mode for 6G */ +}; -typedef struct wl_txcal_tempsense { - uint16 version; - uint8 valid_cnt; - uint8 core; - int16 ref_temperature; - int16 meas_temperature; - wl_rfem_temp_vdet_temp_t vdet_temp; - wl_rfem_temp_vin_tssi_t vin_tssi; -} wl_txcal_tempsense_t; +typedef struct wl_olpc_anchor { + uint16 version; /* structure version */ + uint16 length; /* structure length */ + uint8 band; /* 2G/5G/6G/XX */ + uint8 anchor; /* anchor point power level */ + uint8 PAD[2]; /* explicit padding */ +} wl_olpc_anchor_t; /** IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */ typedef struct wl_mempool_stats { int32 num; /**< Number of memory pools */ - bcm_mp_stats_t s[1]; /**< Variable array of memory pool stats. */ + bcm_mp_stats_t s[BCM_FLEX_ARRAY]; /**< Variable array of memory pool stats. */ } wl_mempool_stats_t; typedef struct { @@ -11544,14 +13204,13 @@ typedef struct powersel_params { uint8 PAD; } powersel_params_t; -#define WL_LPC_PARAMS_VER_2 2 -#define WL_LPC_PARAMS_CURRENT_VERSION WL_LPC_PARAMS_VER_2 +#define WL_LPC_PARAMS_VER_2 2u typedef struct lpc_params { uint16 version; uint16 length; /* LPC Params exposed via IOVAR */ - uint8 rate_stab_thresh; /**< Thresh for rate stability based on nupd */ + uint8 rate_stab_thresh; /**< Lowest power reached by algorithm */ uint8 pwr_stab_thresh; /**< Number of successes before power step down */ uint8 lpc_exp_time; /**< Time lapse for expiry of database */ uint8 pwrup_slow_step; /**< Step size for slow step up */ @@ -11559,6 +13218,22 @@ typedef struct lpc_params { uint8 pwrdn_slow_step; /**< Step size for slow step down */ } lpc_params_t; +#define WL_LPC_EPABYPASS_PARAMS_VER 1u +typedef struct wl_lpc_epabypass_ioc_v1 { + uint16 version; /* structure version */ + uint16 len; /* structure length */ + uint16 id; /* ID of the sub-command */ + uint8 data; + uint8 PAD; +} wl_lpc_epabypass_ioc_t; + +/* EPABYPASS sub command IDs */ +enum { + IOV_LPC_EPABYPASS_CMD_ENABLE = 0u, /* enable/disable */ + IOV_LPC_EPABYPASS_CMD_FORCED = 1u, /* forced epabypass */ + IOV_LPC_EPABYPASS_CMD_MAXPWR = 2u /* maxpwr */ +}; + /* tx pkt delay statistics */ #define SCB_RETRY_SHORT_DEF 7 /**< Default Short retry Limit */ #define WLPKTDLY_HIST_NBINS 16 /**< number of bins used in the Delay histogram */ @@ -11597,7 +13272,7 @@ typedef struct txdelay_params { uint8 PAD; } txdelay_params_t; #define MAX_TXDELAY_STATS_SCBS 6 -#define TXDELAY_STATS_VERSION 1 +#define TXDELAY_STATS_VERSION_1 1 enum { TXDELAY_STATS_PARTIAL_RESULT = 0, @@ -11606,7 +13281,7 @@ enum { typedef struct scb_total_delay_stats { struct ether_addr ea; - uint8 pad[2]; + uint8 PAD[2]; scb_delay_stats_t dlystats[AC_COUNT]; } scb_total_delay_stats_t; @@ -11614,7 +13289,7 @@ typedef struct txdelay_stats { uint32 version; uint32 full_result; /* 0:Partial, 1:full */ uint32 scb_cnt; /* in:requested, out:returned */ - scb_total_delay_stats_t scb_delay_stats[1]; + scb_total_delay_stats_t scb_delay_stats[BCM_FLEX_ARRAY]; } txdelay_stats_t; #define WL_TXDELAY_STATS_FIXED_SIZE \ @@ -11651,7 +13326,7 @@ typedef struct wl_tfs_filter { uint8 status; /**< Status returned by the AP */ uint8 tclas_proc; /**< TCLAS processing value (0:and, 1:or) */ uint8 tclas_cnt; /**< count of all wl_tclas_t in tclas array */ - uint8 tclas[1]; /**< VLA of wl_tclas_t */ + uint8 tclas[BCM_FLEX_ARRAY]; /**< VLA of wl_tclas_t */ } wl_tfs_filter_t; #define WL_TFS_FILTER_FIXED_SIZE OFFSETOF(wl_tfs_filter_t, tclas) @@ -11678,8 +13353,8 @@ enum { }; typedef struct wl_tfs_status { - uint8 fset_cnt; /**< count of all wl_tfs_fset_t in fset array */ - wl_tfs_fset_t fset[1]; /**< VLA of wl_tfs_fset_t */ + uint8 fset_cnt; /**< count of all wl_tfs_fset_t in fset array */ + wl_tfs_fset_t fset[BCM_FLEX_ARRAY]; /**< VLA of wl_tfs_fset_t */ } wl_tfs_status_t; typedef struct wl_tfs_set { @@ -11720,14 +13395,14 @@ typedef struct wl_dms_desc { uint8 tclas_proc; uint8 mac_len; /**< length of all ether_addr in data array, 0 if STA */ uint8 tclas_len; /**< length of all wl_tclas_t in data array */ - uint8 data[1]; /**< VLA of 'ether_addr' and 'wl_tclas_t' (in this order ) */ + uint8 data[1]; /**< VLA of ether_addr and wl_tclas_t (in this order ) */ } wl_dms_desc_t; #define WL_DMS_DESC_FIXED_SIZE OFFSETOF(wl_dms_desc_t, data) typedef struct wl_dms_status { uint32 cnt; - wl_dms_desc_t desc[1]; + wl_dms_desc_t desc[BCM_FLEX_ARRAY]; } wl_dms_status_t; typedef struct wl_dms_set { @@ -11755,7 +13430,7 @@ typedef struct wl_bsstrans_query { uint16 pad0; /* padding for 4-byte allignment */ wlc_ssid_t ssid; /* SSID of NBR elem to be queried for */ uint8 reason; /* Reason code of the BTQ */ - uint8 pad1[3]; /* padding for 4-byte allignment */ + uint8 PAD[3]; /* padding for 4-byte allignment */ } wl_bsstrans_query_t; #define BTM_QUERY_NBR_COUNT_MAX 16 @@ -11764,7 +13439,7 @@ typedef struct wl_bsstrans_query { typedef struct wl_btq_nbr_list { uint16 version; /* structure version */ uint8 count; /* No. of BTQ NBRs returned */ - uint8 pad; /* padding for 4-byte allignment */ + uint8 PAD; /* padding for 4-byte allignment */ nbr_rpt_elem_t btq_nbt_elem[]; /* BTQ NBR elem in a BTQ NBR list */ } wl_btq_nbr_list_t; @@ -11801,8 +13476,8 @@ typedef enum { WL_BSSTRANS_POLICY_ROAM_IF_MODE = 1, /**< Roam only if requested by Request Mode field */ WL_BSSTRANS_POLICY_ROAM_IF_PREF = 2, /**< Roam only if Preferred BSS provided */ WL_BSSTRANS_POLICY_WAIT = 3, /**< Wait for deauth and send Accepted status */ - WL_BSSTRANS_POLICY_PRODUCT = 4, /**< Policy for real product use cases (Olympic) */ - WL_BSSTRANS_POLICY_PRODUCT_WBTEXT = 5, /**< Policy for real product use cases (SS) */ + WL_BSSTRANS_POLICY_PRODUCT = 4, /**< Policy for real product use cases */ + WL_BSSTRANS_POLICY_PRODUCT_WBTEXT = 5, /**< Policy for real product use cases */ WL_BSSTRANS_POLICY_MBO = 6, /**< Policy for MBO certification */ WL_BSSTRANS_POLICY_MAX = 7 } wnm_bsstrans_policy_type_t; @@ -11834,7 +13509,7 @@ typedef struct wl_timbc_status { uint8 status_sta; /**< Status from internal state machine (check below) */ uint8 status_ap; /**< From AP response frame (check 8.4.2.86 from 802.11) */ uint8 interval; - uint8 pad; + uint8 PAD; int32 offset; uint16 rate_high; uint16 rate_low; @@ -12015,22 +13690,20 @@ enum proxd_method { #define WL_PROXD_ACTION_STOP 0 #define WL_PROXD_ACTION_START 1 -#define WL_PROXD_FLAG_TARGET_REPORT 0x1 -#define WL_PROXD_FLAG_REPORT_FAILURE 0x2 -#define WL_PROXD_FLAG_INITIATOR_REPORT 0x4 -#define WL_PROXD_FLAG_NOCHANSWT 0x8 -#define WL_PROXD_FLAG_NETRUAL 0x10 -#define WL_PROXD_FLAG_INITIATOR_RPTRTT 0x20 -#define WL_PROXD_FLAG_ONEWAY 0x40 -#define WL_PROXD_FLAG_SEQ_EN 0x80 +#define WL_PROXD_FLAG_TARGET_REPORT 0x1 +#define WL_PROXD_FLAG_REPORT_FAILURE 0x2 +#define WL_PROXD_FLAG_INITIATOR_REPORT 0x4 +#define WL_PROXD_FLAG_NOCHANSWT 0x8 +#define WL_PROXD_FLAG_NETRUAL 0x10 +#define WL_PROXD_FLAG_INITIATOR_RPTRTT 0x20 +#define WL_PROXD_FLAG_ONEWAY 0x40 +#define WL_PROXD_FLAG_SEQ_EN 0x80 +#define WL_PROXD_FLAG_DUMP_CHANNEL_ESTIMATES 0x100 -#define WL_PROXD_SETFLAG_K 0x1 -#define WL_PROXD_SETFLAG_N 0x2 -#define WL_PROXD_SETFLAG_S 0x4 - -#define WL_PROXD_SETFLAG_K 0x1 -#define WL_PROXD_SETFLAG_N 0x2 -#define WL_PROXD_SETFLAG_S 0x4 +#define WL_PROXD_SETFLAG_K 0x1 /**< Delay K factor for initiator/target */ +#define WL_PROXD_SETFLAG_N 0x2 /**< Thresh crossing params for 5g/2g sequence */ +#define WL_PROXD_SETFLAG_S 0x4 /**< Simple threshold crossing values for 5g/2g */ +#define WL_PROXD_SETFLAG_C 0x8 /**< 2G GD offsets for core 0/1 */ #define WL_PROXD_RANDOM_WAKEUP 0x8000 #define WL_PROXD_MAXREPORT 8 @@ -12074,6 +13747,16 @@ typedef struct wl_proxd_params_rssi_method { /* Number of total index including seq tx/rx idx */ #define TOF_BW_SEQ_NUM 5 +#define TOF_SEQ_KVAL_2G_CHANOFFS_LEN 4u /* Channel offets for 2G, 1, 2-7, 8-10, 11-13 */ + +enum tof_seq_kval_2g_chan_offset { + TOF_SEQ_KVAL_2G_CHANOFF_COREID = 0, /* core id */ + TOF_SEQ_KVAL_2G_CHANOFF_GROUP1 = 1, /* channels: 1 */ + TOF_SEQ_KVAL_2G_CHANOFF_GROUP2 = 2, /* channels: 2-7 */ + TOF_SEQ_KVAL_2G_CHANOFF_GROUP3 = 3, /* channels: 8-10 */ + TOF_SEQ_KVAL_2G_CHANOFF_GROUP4 = 4 /* channels: 11-13 */ +}; + enum tof_bw_index { TOF_BW_20MHZ_INDEX = 0, TOF_BW_40MHZ_INDEX = 1, @@ -12223,22 +13906,22 @@ typedef struct wl_proxd_params_tof_tune_v3 { uint32 Ki; /**< h/w delay K factor for initiator */ uint32 Kt; /**< h/w delay K factor for target */ int16 vhtack; /**< enable/disable VHT ACK */ - uint16 PAD; + int16 ch_offset_2gcore_val1; /**< ch 1 offset for core 0/1 */ int16 N_log2[TOF_BW_SEQ_NUM]; /**< simple threshold crossing */ - uint16 PAD; + int16 ch_offset_2gcore_val2; /**< ch 2-7 offset for core 0/1 */ int16 w_offset[TOF_BW_NUM]; /**< offset of threshold crossing window(per BW) */ - uint16 PAD; + int16 ch_offset_2gcore_val3; /**< ch 8-10 offset for core 0/1 */ int16 w_len[TOF_BW_NUM]; /**< length of threshold crossing window(per BW) */ - uint16 PAD; + int16 ch_offset_2gcore_val4; /**< ch 11-13 offset for core 0/1 */ int32 maxDT; /**< max time difference of T4/T1 or T3/T2 */ int32 minDT; /**< min time difference of T4/T1 or T3/T2 */ uint8 totalfrmcnt; /**< total count of transfered measurement frames */ uint8 PAD[3]; uint16 rsv_media; /**< reserve media value for TOF */ - uint16 PAD; + uint16 ch_offset_2gcore; /**< 2g core id */ uint32 flags; /**< flags */ uint8 core; /**< core to use for tx */ - uint8 setflags; /* set flags of K, N. S values */ + uint8 setflags; /* set flags of K, N, S, C values */ uint16 PAD; int16 N_scale[TOF_BW_SEQ_NUM]; /**< simple threshold crossing */ uint8 sw_adj; /**< enable sw assisted timestamp adjustment */ @@ -12309,6 +13992,60 @@ typedef struct wl_proxd_params_tof_tune_v4 { wl_proxd_seq_config_t seq_2g20; /* Thresh crossing params for 2G Sequence */ } wl_proxd_params_tof_tune_v4_t; +/* + * tof tune v5 + */ +#define WL_PROXD_TUNE_VERSION_5 5u +typedef struct wl_proxd_params_tof_tune_v5 { + uint16 version; + uint16 len; + uint8 core; /**< core to use for tx */ + uint8 setflags; /* set flags of K, N. S values */ + uint8 totalfrmcnt; /**< total count of transfered measurement frames */ + uint8 sw_adj; /**< enable sw assisted timestamp adjustment */ + uint8 hw_adj; /**< enable hw assisted timestamp adjustment */ + uint8 seq_en; /**< enable ranging sequence */ + uint8 smooth_win_en; /**< enable smooth win with ifft from matched filter */ + uint8 core_mask; /* core mask selection */ + int8 recv_2g_thresh; /* 2g recieve sensitivity threshold */ + int8 acs_rssi_thresh; /* RSSI threshold below which core will not be used + * for auto core selection. + */ + int8 acs_delta_rssi_thresh; /* threshold for RSSI delta from max. RSSI among cores */ + uint8 ftm_cnt[TOF_BW_SEQ_NUM_V2]; /**< no. of ftm frames based on bw */ + uint8 PAD; /* Use this for any int8/uint8 ext in future */ + uint16 ch_offset_2gcore; /**< 2g core (0/1) to apply ch_offset_2g_core_valN values */ + uint16 rsv_media; /**< reserve media value for TOF */ + uint16 bitflip_thresh; /* bitflip threshold */ + uint16 snr_thresh; /* SNR threshold */ + int16 vhtack; /**< enable/disable VHT ACK */ + int16 N_log2_2g; /**< simple threshold crossing for 2g channel */ + int16 N_scale_2g; /**< simple threshold crossing for 2g channel */ + int16 N_log2[TOF_BW_SEQ_NUM_V2]; /**< simple threshold crossing */ + int16 w_offset[TOF_BW_NUM_V2]; /**< offset of thresh crossing window(per BW) */ + int16 w_len[TOF_BW_NUM_V2]; /**< length of thresh crossing window(per BW) */ + int16 N_scale[TOF_BW_SEQ_NUM_V2]; /**< simple threshold crossing */ + uint32 Ki; /**< h/w delay K factor for initiator */ + uint32 Kt; /**< h/w delay K factor for target */ + uint32 flags; /**< flags */ + uint32 acs_gdv_thresh; /* Group delay variance threshold below which + * core not used for auto core selection. + */ + int32 maxDT; /**< max time difference of T4/T1 or T3/T2 */ + int32 minDT; /**< min time difference of T4/T1 or T3/T2 */ + int32 acs_gdmm_thresh; /**< Threshold for group delay max - min */ + int32 emu_delay; /**< Inserted delay by the chan emulator 10th of nano-sec */ + wl_proxd_seq_config_t seq_5g20; /* Thresh crossing params for 5G Sequence */ + wl_proxd_seq_config_t seq_2g20; /* Thresh crossing params for 2G Sequence */ + /* ch_offset_2gcore_valN: Group Delay offset values used to correct distance calculation. + * units are in tenth of nano-sec. + */ + int16 ch_offset_2gcore_val1; /* ch 1 offset for core specified by ch_offset_2gcore */ + int16 ch_offset_2gcore_val2; /* ch 2-7 offset for core specified by ch_offset_2gcore */ + int16 ch_offset_2gcore_val3; /* ch 8-10 offset for core specified by ch_offset_2gcore */ + int16 ch_offset_2gcore_val4; /* ch 11-13 offset for core specified by ch_offset_2gcore */ +} wl_proxd_params_tof_tune_v5_t; + typedef struct wl_proxd_params_iovar { uint16 method; /**< Proximity Detection method */ uint8 PAD[2]; @@ -12344,6 +14081,24 @@ typedef struct wl_proxd_params_iovar_v2 { uint8 tlv_params[]; /* xtlvs for variable ext params */ } wl_proxd_params_iovar_v2_t; +#define WL_PROXD_IOVAR_VERSION_3 3u +typedef struct wl_proxd_params_iovar_v3 { + uint16 version; + uint16 len; + uint16 method; /**< Proximity Detection method */ + uint16 PAD; + union { + /* common params for pdsvc */ + wl_proxd_params_common_t cmn_params; /**< common parameters */ + /* method specific */ + wl_proxd_params_rssi_method_t rssi_params; /**< RSSI method parameters */ + wl_proxd_params_tof_method_t tof_params; /**< TOF method parameters */ + /* tune parameters */ + wl_proxd_params_tof_tune_v5_t tof_tune; /**< TOF tune parameters */ + } u; /**< Method specific optional parameters */ + uint8 tlv_params[]; /* xtlvs for variable ext params */ +} wl_proxd_params_iovar_v3_t; + #define PROXD_COLLECT_GET_STATUS 0 #define PROXD_COLLECT_SET_STATUS 1 #define PROXD_COLLECT_QUERY_HEADER 2 @@ -12401,6 +14156,35 @@ typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_header { /* * proxd collect header with 160 MHz support */ +#define WL_PROXD_COLLECT_HEADER_VERSION_3 3u +typedef struct wl_proxd_collect_header_v3 { + uint16 version; + uint16 len; + uint8 chiprev; /**< chip revision */ + uint8 phyver; /**< phy version */ + uint8 PAD[2]; /* Use this for any int8/16 uint8/16 ext in future */ + uint16 total_frames; /**< The total frames for this collect. */ + uint16 nfft; /**< nfft value */ + uint16 bandwidth; /**< bandwidth */ + uint16 channel; /**< channel number */ + uint16 fpfactor_shift; /**< avb timer value shift bits */ + uint16 chipnum; /**< chip type */ + uint32 chanspec; /**< channel spec */ + uint32 fpfactor; /**< avb timer value factor */ + uint32 meanrtt; /**< mean of RTTs */ + uint32 modertt; /**< mode of RTTs */ + uint32 medianrtt; /**< median of RTTs */ + uint32 sdrtt; /**< standard deviation of RTTs */ + uint32 clkdivisor; /**< clock divisor */ + int32 distance; /**< distance calculated by fw */ + struct ether_addr localMacAddr; /**< local mac address */ + uint16 PAD; /* Use this for any int8/16 uint8/16 ext in future */ + struct ether_addr remoteMacAddr; /**< remote mac address */ + uint16 PAD; /* Use this for any int8/16 uint8/16 ext in future */ + wl_proxd_params_tof_tune_v5_t params; /* TOF tune params */ + uint8 tlv_params[]; /* xtlvs for variable ext params */ +} wl_proxd_collect_header_v3_t; + #define WL_PROXD_COLLECT_HEADER_VERSION_2 2u typedef struct wl_proxd_collect_header_v2 { uint16 version; @@ -12552,6 +14336,27 @@ typedef struct wl_proxd_collect_header_v2 { /* MAX security params length PMK field */ #define WL_NAN_NCS_SK_PMK_LEN 32 +/* NAN pairing max password length */ +#define WL_NAN_PAIRING_PASSWORD_LEN 255u + +/* NAN pairing max NPBA attr length */ +#define WL_NAN_NPBA_INFO_MAX_LEN 255u + +/* NAN pairing max NIRA attr length */ +#define WL_NAN_NIRA_INFO_MAX_LEN 255u + +/* NAN pairing key max length */ +#define WL_NAN_NPK_MAX_LEN 255u + +/* NAN identity key max length */ +#define WL_NAN_NIK_MAX_LEN 255u + +/* NAN pairing XTLV list max length; x2 for local NIK and peer NIK */ +#define WL_NAN_XTLV_LIST_MAX_LEN (WL_NAN_NPK_MAX_LEN + (2 * WL_NAN_NIK_MAX_LEN)) + +/* NAN S3 ALL maps */ +#define WL_NAN_AVAIL_S3_ALLMAPS 0xFF + /* Post disc attr ID type */ typedef uint8 wl_nan_post_disc_attr_id_t; @@ -12584,7 +14389,7 @@ typedef struct wl_nan_ev_replied { wl_nan_instance_id_t pub_id; /* Publisher Instance ID */ uint8 sub_id; /* Subscriber ID */ int8 sub_rssi; /* Subscriber RSSI */ - uint8 pad[3]; + uint8 PAD[3]; } wl_nan_ev_replied_t; typedef struct wl_nan_event_replied { @@ -12628,6 +14433,10 @@ enum wl_nan_frame_type { WL_NAN_FRM_TYPE_RNG_REPORT = 16, WL_NAN_FRM_TYPE_UNSOLICIT_SDF = 17, + + WL_NAN_FRM_REKEY_TRIGGER = 18, + WL_NAN_FRM_GRP_REKEY_REQ = 19, + WL_NAN_FRM_GRP_REKEY_RESP = 20, WL_NAN_FRM_TYPE_INVALID }; typedef uint8 wl_nan_frame_type_t; @@ -12646,7 +14455,7 @@ typedef struct wl_nan_event_txs { uint8 reason_code; /* to identify reason when status is failure */ uint16 host_seq; /* seq num to keep track of pkts sent by host */ uint8 type; /* wl_nan_frame_type_t */ - uint8 pad; + uint8 PAD; uint16 opt_tlvs_len; uint8 opt_tlvs[]; } wl_nan_event_txs_t; @@ -12661,7 +14470,7 @@ typedef struct wl_nan_event_sd_txs { typedef struct wl_nan_event_nanho_txs { uint32 fsm_id; /* nho fsm id */ uint16 seq_id; /* nho seq id */ - uint16 pad; + uint16 PAD; } wl_nan_event_nanho_txs_t; /* Subscribe or Publish instance Terminated */ @@ -12677,7 +14486,7 @@ typedef struct wl_nan_ev_terminated { uint8 instance_id; /* publish / subscribe instance id */ uint8 reason; /* 1=timeout, 2=Host/IOVAR, 3=FW Terminated 4=Failure */ uint8 svctype; /* 0 - Publish, 0x1 - Subscribe */ - uint8 pad; /* Align */ + uint8 PAD; /* Align */ uint32 tx_cnt; /* Number of SDFs sent */ } wl_nan_ev_terminated_t; @@ -12705,7 +14514,7 @@ typedef struct wl_nan_disc_expired_cache_entry { typedef struct wl_nan_ev_disc_cache_timeout { uint16 count; /* no. of expired cache entries */ - uint16 pad; + uint16 PAD; wl_nan_disc_expired_cache_entry_t cache_exp_list[]; } wl_nan_ev_disc_cache_timeout_t; @@ -12724,7 +14533,7 @@ typedef struct wl_nan_event_extn { typedef struct wl_nan_data_dp_txs { uint8 ndp_id; - uint8 pad; + uint8 PAD; struct ether_addr indi; /* initiator ndi */ } wl_nan_data_dp_txs_t; @@ -12732,7 +14541,7 @@ typedef struct wl_nan_data_dp_txs { typedef struct wl_nan_range_txs { uint8 range_id; - uint8 pad[3]; + uint8 PAD[3]; } wl_nan_range_txs_t; #define NAN_MAX_BANDS 2 @@ -12814,6 +14623,8 @@ enum wl_nan_cmd_xtlv_id { #define WL_NAN_CMD_NSR_COMP_ID 0x0a /* NAN Save Restore */ #define WL_NAN_CMD_NANHO_COMP_ID 0x0b /* NAN Host offload */ #define WL_NAN_CMD_DBG_COMP_ID 0x0f +#define WL_NAN_CMD_PAIRING_COMP_ID 0x10 +#define WL_NAN_CMD_PAIRING_PEER_COMP_ID 0x11 #define WL_NAN_CMD_COMP_SHIFT 8 #define NAN_CMD(x, y) (((x) << WL_NAN_CMD_COMP_SHIFT) | (y)) @@ -12840,6 +14651,18 @@ typedef enum wl_nan_tlv { WL_NAN_XTLV_CFG_MAC_ADDR = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0E), /* fast disc time bitmap config */ WL_NAN_XTLV_CFG_FDISC_TBMP = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0F), + WL_NAN_XTLV_CFG_SEC_GTK_CSID = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x10), + + /* NAN R4, host constucted NPBA (NAN Pairing Bootstrapping Attribute), the entire + * NPBA attibute is in bcm_xlv_t: + * len: contains the NABA attribute length + * data: contains the NABA attrbute data, including id. + * The Host exchanges this attribute during the + * NAN pairing and bootstrapping in SDF Follow-ups and SDF Publish. + */ + WL_NAN_XTLV_CFG_NPBA_INFO = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x11), + /* multicast data slot bitmap config */ + WL_NAN_XTLV_CFG_MCAST_AVAIL_BMP = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x12), WL_NAN_XTLV_SD_SVC_INFO = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x01), WL_NAN_XTLV_SD_FOLLOWUP = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x02), @@ -12860,6 +14683,8 @@ typedef enum wl_nan_tlv { WL_NAN_XTLV_SD_NDL_QOS_UPD = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x11), WL_NAN_XTLV_SD_DISC_CACHE_TIMEOUT = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x12), WL_NAN_XTLV_SD_PEER_NMI = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x13), + WL_NAN_XTLV_SD_FUP_UNSYNC_CHANSPEC = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x14), + WL_NAN_XTLV_SD_CHANSPEC = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x15), WL_NAN_XTLV_SYNC_BCN_RX = NAN_CMD(WL_NAN_CMD_SYNC_COMP_ID, 0x01), WL_NAN_XTLV_EV_MR_CHANGED = NAN_CMD(WL_NAN_CMD_SYNC_COMP_ID, 0x02), @@ -12891,6 +14716,7 @@ typedef enum wl_nan_tlv { WL_NAN_XTLV_OOB_AF = NAN_CMD(WL_NAN_CMD_GENERIC_COMP_ID, 0x03), WL_NAN_XTLV_SCHED_INFO = NAN_CMD(WL_NAN_CMD_SCHED_COMP_ID, 0x01), + WL_NAN_XTLV_NDL_SCHED_INFO = NAN_CMD(WL_NAN_CMD_SCHED_COMP_ID, 0x02), /* Nan Save-Restore XTLVs */ WL_NAN_XTLV_NSR2_PEER = NAN_CMD(WL_NAN_CMD_NSR_COMP_ID, 0x21), @@ -12909,7 +14735,25 @@ typedef enum wl_nan_tlv { WL_NAN_XTLV_NANHO_OOB_TXS = NAN_CMD(WL_NAN_CMD_NANHO_COMP_ID, 0x0A), WL_NAN_XTLV_NANHO_DCAP_ATTR = NAN_CMD(WL_NAN_CMD_NANHO_COMP_ID, 0x0B), WL_NAN_XTLV_NANHO_ELEM_ATTR = NAN_CMD(WL_NAN_CMD_NANHO_COMP_ID, 0x0C), - WL_NAN_XTLV_NANHO_SEC_SA = NAN_CMD(WL_NAN_CMD_NANHO_COMP_ID, 0x0D) + WL_NAN_XTLV_NANHO_SEC_SA = NAN_CMD(WL_NAN_CMD_NANHO_COMP_ID, 0x0D), + + /* NAN pairing XTLVs */ + WL_NAN_XTLV_PAIRING_PASSWORD = NAN_CMD(WL_NAN_CMD_PAIRING_COMP_ID, 0x01), + + /* Caching NPK */ + WL_NAN_XTLV_PAIRING_CACHING_NPK = NAN_CMD(WL_NAN_CMD_PAIRING_COMP_ID, 0x02), + + /* Local NIK */ + WL_NAN_XTLV_PAIRING_LOCAL_NIK = NAN_CMD(WL_NAN_CMD_PAIRING_COMP_ID, 0x03), + + /* Local NIRA */ + WL_NAN_XTLV_PAIRING_LOCAL_NIRA = NAN_CMD(WL_NAN_CMD_PAIRING_COMP_ID, 0x04), + + /* Peer NIK */ + WL_NAN_XTLV_PAIRING_PEER_NIK = NAN_CMD(WL_NAN_CMD_PAIRING_COMP_ID, 0x05), + + /* XTLV list to include NPK, local NIK and peer NIK */ + WL_NAN_XTLV_PAIRING_XTLV_LIST = NAN_CMD(WL_NAN_CMD_PAIRING_COMP_ID, 0x06) } wl_nan_tlv_t; /* Sub Module ID's for NAN */ @@ -12921,13 +14765,22 @@ enum { NAN_PEER_ENTRY = 4, /* nan peer entry */ NAN_AVAIL = 5, /* nan avail */ NAN_DAM = 6, /* nan dam */ - NAN_FSM = 7, /* nan fsm registry */ + NAN_FSM = 7, /* nan fsm registry */ NAN_NDP = 8, /* nan ndp */ NAN_NDL = 9, /* nan ndl */ NAN_DP = 10, /* nan dp core */ NAN_RNG = 11, /* nan ranging */ NAN_SEC = 12, /* nan sec */ - NAN_LAST = 13 +/* + * Need to make sure NAN branches update their nan_init tables before + * removing this check. Otherwise it causes odt/smoketest failures + */ +#ifdef WL_NAN_PAIRING + NAN_PAIRING = 13, /* nan pairing */ + NAN_LAST = 14 +#else + NAN_LAST = 13 +#endif /* WL_NAN_PAIRING */ }; enum wl_nan_sub_cmd_xtlv_id { @@ -12967,7 +14820,11 @@ enum wl_nan_sub_cmd_xtlv_id { WL_NAN_CMD_CFG_FASTDISC = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x1C), WL_NAN_CMD_CFG_MIN_TX_RATE = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x1D), WL_NAN_CMD_CFG_FSM_TIMEOUT = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x1E), - WL_NAN_CMD_CFG_MAX = WL_NAN_CMD_CFG_FSM_TIMEOUT, + WL_NAN_CMD_CFG_REKEY = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x1F), /* REKEY */ + WL_NAN_CMD_CFG_INSTANT_CHAN = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x20), + WL_NAN_CMD_CFG_TSF = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x21), + WL_NAN_CMD_CFG_MCAST_AVAIL = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x22), + WL_NAN_CMD_CFG_MAX = WL_NAN_CMD_CFG_MCAST_AVAIL, /* Add new commands before and update */ @@ -13080,10 +14937,16 @@ enum wl_nan_sub_cmd_xtlv_id { WL_NAN_CMD_NANHO_VER = NAN_CMD(WL_NAN_CMD_NANHO_COMP_ID, 0x05), WL_NAN_CMD_NANHO_MAX = WL_NAN_CMD_NANHO_VER, + /* NAN pairing sub-commands */ + WL_NAN_CMD_PAIRING = NAN_CMD(WL_NAN_CMD_PAIRING_COMP_ID, 0x01), + WL_NAN_CMD_PAIRING_KEY_INFO = NAN_CMD(WL_NAN_CMD_PAIRING_COMP_ID, 0x02), + WL_NAN_CMD_PAIRING_PEER_INFO = NAN_CMD(WL_NAN_CMD_PAIRING_COMP_ID, 0x03), + WL_NAN_CMD_PAIRING_MAX = WL_NAN_CMD_PAIRING_PEER_INFO, + /* Add submodules below, and update WL_NAN_CMD_MAX */ /* ROML check for this enum should use WL_NAN_CMD_MAX */ - WL_NAN_CMD_MAX = WL_NAN_CMD_NANHO_MAX + WL_NAN_CMD_MAX = WL_NAN_CMD_PAIRING_MAX }; /* @@ -13106,6 +14969,13 @@ typedef enum wl_nan_stats_tlv { WL_NAN_XTLV_GEN_AVAIL_STATS_SCHED = NAN_CMD(WL_NAN_CMD_GENERIC_COMP_ID, 0x06), WL_NAN_XTLV_GEN_NDP_STATS = NAN_CMD(WL_NAN_CMD_GENERIC_COMP_ID, 0x07), WL_NAN_XTLV_GEN_PARSE_STATS = NAN_CMD(WL_NAN_CMD_GENERIC_COMP_ID, 0x08), + WL_NAN_XTLV_GEN_BIP_STATS = NAN_CMD(WL_NAN_CMD_GENERIC_COMP_ID, 0x09), + WL_NAN_XTLV_GEN_PEER_BIP_STATS = NAN_CMD(WL_NAN_CMD_GENERIC_COMP_ID, 0x0A), + WL_NAN_XTLV_GEN_GTK_STATS = NAN_CMD(WL_NAN_CMD_GENERIC_COMP_ID, 0x0B), + WL_NAN_XTLV_GEN_PEER_REKEY_STATS = NAN_CMD(WL_NAN_CMD_GENERIC_COMP_ID, 0x0C), + WL_NAN_XTLV_GEN_PEER_GTK_STATS = NAN_CMD(WL_NAN_CMD_GENERIC_COMP_ID, 0x0D), + WL_NAN_XTLV_GEN_PEER_PAIRING_STATS = NAN_CMD(WL_NAN_CMD_GENERIC_COMP_ID, 0x0E), + WL_NAN_XTLV_GEN_PEER_KA_OOB_AF_STAT = NAN_CMD(WL_NAN_CMD_GENERIC_COMP_ID, 0x0F), WL_NAN_XTLV_DAM_STATS = NAN_CMD(WL_NAN_CMD_DAM_COMP_ID, 0x01), WL_NAN_XTLV_DAM_AVAIL_STATS = NAN_CMD(WL_NAN_CMD_DAM_COMP_ID, 0x02), @@ -13122,7 +14992,7 @@ typedef struct wl_nan_cmn_get_stat { uint8 operation; /* Get, Get and Clear */ uint8 arg1; /* Submodule control variable1 */ uint8 arg2; /* Submodule control variable2 */ - uint8 pad; /* May not be needed as TLV's are aligned,add to pass compile chk */ + uint8 PAD; /* May not be needed as TLV's are aligned,add to pass compile chk */ } wl_nan_cmn_get_stat_t; /* Output for Stats container */ @@ -13175,6 +15045,22 @@ typedef struct wl_nan_mac_stats_v1 { uint32 merge_scan_cnt_5g; /* 5G band merge scan cnt */ } wl_nan_mac_stats_v1_t; +typedef struct wl_nan_mac_stats_v2 { + wl_nan_mac_band_stats_t band[NAN_MAX_BANDS]; /* MAC sync band specific stats */ + uint32 naf_tx; /* NAN AF tx */ + uint32 naf_rx; /* NAN AF rx */ + uint32 sdf_tx; /* SDF tx */ + uint32 sdf_rx; /* SDF rx */ + uint32 cnt_sync_bcn_rx_tu[3]; /* delta bw */ + uint32 cnt_bcn_tx_out_dw; /* TX sync beacon outside dw */ + uint32 cnt_role_am_dw; /* anchor master role due to dw */ + uint32 cnt_am_hop_err; /* wrong hopcount set for AM */ + uint32 merge_scan_cnt_2g; /* 2G band merge scan cnt */ + uint32 merge_scan_cnt_5g; /* 5G band merge scan cnt */ + uint16 ucast_sdf_oth_bssid; /* ucast sdf sent by peer that is in other custer */ + uint16 ucast_naf_oth_bssid; /* ucast naf sent by peer that is in other cluster */ +} wl_nan_mac_stats_v2_t; + /* NAN Sched stats */ /* Per core Sched stats */ typedef struct nan_sched_stats_core { @@ -13184,7 +15070,7 @@ typedef struct nan_sched_stats_core { uint32 slotstart_partial; /* slot resume */ uint32 slotend_partial; /* slot pre-empt */ uint8 avail_upd_cnt; /* count to track num of times avail has been updated */ - uint8 pad[3]; + uint8 PAD[3]; } nan_sched_stats_core_t; /* Common Sched stats */ typedef struct nan_sched_stats_cmn { @@ -13211,6 +15097,8 @@ typedef struct nan_disc_stats { uint32 fup_rx; /* Followup rx */ uint32 pub_resp_ignored; /* response to incoming publish ignored */ uint32 sub_resp_ignored; /* response to incoming subscribe ignored */ + uint32 auto_resp_ignored; /* response to incoming disc bcn ignored */ + uint32 disc_cache_ovfl; /* Number of seen once disc cache overflows in system */ } nan_disc_stats_t; /* NAN Discovery stats end */ @@ -13231,17 +15119,83 @@ typedef struct nan_sec_stats_s { uint32 nonce_mismatch; /* nonce mismatch */ } nan_sec_stats_t; +typedef struct nan_peer_rekey_stats { + uint32 ptk_rekey_start_i; /* number of ptk rekeys as initiator */ + uint32 ptk_rekey_start_r; /* number of ptk rekeys as responder */ + uint32 ptk_rekey_success_i; /* ptk rekey failures as initiator */ + uint32 ptk_rekey_success_r; /* ptk rekey failures as responder */ + uint32 grp_rekey_start; /* Number of group rekey starts */ + uint32 grp_rekey_success; /* Number of group rekey success */ +} nan_peer_rekey_stats_t; + +/* statistics for nan BIP security: WL_NAN_XTLV_GEN_BIP_STATS */ +typedef struct nan_sec_bip_stats_s { + uint8 bip_algo; /* CSID/Algo used */ + uint8 bigtk_tx_id; /* BIGTK txid used */ + uint8 igtk_tx_id; /* IGTK txid used */ + uint8 PAD[1]; + uint32 igtk_sessions; /* Number of igtk exchanges */ + uint32 bigtk_sessions; /* Number of bigtk exchanges */ + uint32 igtk_tx; /* Number of igtk pks tx */ + uint32 bigtk_tx; /* Number of bigtk pks tx */ + uint32 igtk_rx; /* Number of igtk pks tx */ + uint32 bigtk_rx; /* Number of bigtk pks tx */ + uint32 igtk_rx_err; /* Number of igtk rx error */ + uint32 bigtk_rx_err; /* Number of bigtk rx error */ + uint32 igtk_reject; /* Number of mgmt frames rejected */ + uint32 bigtk_reject; /* Number of bcns rejected */ +} nan_sec_bip_stats_t; + +/* statistics for nan Peer BIP security : WL_NAN_XTLV_GEN_PEER_BIP_STATS */ +typedef struct nan_sec_peer_bip_stats_s { + uint8 bip_algo; /* CSID/Algo used */ + uint8 bigtk_rx_id; /* BIGTK rxid used for peer */ + uint8 igtk_rx_id; /* IGTK rxid used for peer */ + uint8 PAD[1]; + uint32 igtk_tx; /* Number of igtk pks tx */ + uint32 bigtk_tx; /* Number of bigtk pks tx */ + uint32 igtk_rx; /* Number of igtk pks tx */ + uint32 bigtk_rx; /* Number of bigtk pks tx */ + uint32 igtk_rx_err; /* Number of igtk rx error */ + uint32 bigtk_rx_err; /* Number of bigtk rx error */ + uint32 igtk_reject; /* Number of mgmt frames rejected */ + uint32 bigtk_reject; /* Number of bcns rejected */ +} nan_sec_peer_bip_stats_t; +#define NAN_SEC_STAT_MAX_NDI 2 +/* WL_NAN_XTLV_GEN_GTK_STATS */ +typedef struct nan_sec_gtk_stats_s { + uint32 gtk_sessions; /* Number of gtk exchanges */ + uint32 gtk_tx; /* Number of gtk pks tx */ + uint32 gtk_rx; /* Number of gtk pks rx */ + uint8 gtk_tx_csid; /* CSID tx */ + uint8 PAD[3]; + uint32 gtk_tx_err; /* Number of gtk tx error */ + uint32 gtk_rx_err; /* Number of gtk rx error */ + struct ether_addr ndi_addr[NAN_SEC_STAT_MAX_NDI]; /* NDI addr to dump for gtk txid */ + uint8 gtk_tx_id[NAN_SEC_STAT_MAX_NDI]; /* gtkid stat per NDI */ + uint8 PAD[2]; +} nan_sec_gtk_stats_t; + +/* WL_NAN_XTLV_GEN_PEER_GTK_STATS */ +typedef struct nan_sec_peer_gtk_stats_s { + uint8 gtk_csid; + uint8 gtk_rx_id; /* GTK rx id used for peer */ + uint8 PAD[2]; + uint32 gtk_rx; /* Number of gtk pks rx */ + uint32 gtk_rx_err; /* Number of gtk rx error */ +} nan_sec_peer_gtk_stats_t; + /* WL_NAN_XTLV_GEN_PEER_STATS */ typedef struct wl_nan_peer_stats { struct ether_addr nmi; - uint8 pad[2]; + uint8 PAD[2]; uint32 pkt_enq; /* counter for queued pkt of peer */ /* NDL */ bool ndl_exist; uint8 ndl_state; bool counter_proposed; - uint8 pad1; + uint8 PAD; /* NDL QoS */ uint16 local_max_latency; @@ -13253,7 +15207,7 @@ typedef struct wl_nan_peer_stats { struct ether_addr sec_laddr; /* local mac addr */ struct ether_addr sec_raddr; /* remote mac addr */ uint8 sec_csid; - uint8 pad2; + uint8 PAD; } wl_nan_peer_stats_t; /* WL_NAN_XTLV_GEN_PEER_STATS_DEVCAP */ @@ -13266,7 +15220,7 @@ typedef struct wl_nan_peer_stats_dev_cap { uint8 num_antennas; uint16 chan_switch_time; uint8 capabilities; - uint8 pad[3]; + uint8 PAD[3]; } wl_nan_peer_stats_dev_cap_t; /* WL_NAN_XTLV_GEN_PEER_STATS_NDP */ @@ -13306,7 +15260,7 @@ typedef struct wl_nan_stats_sched { uint8 map_id; uint8 seq_id; /* seq id from NA attr */ uint8 slot_dur; - uint8 pad; + uint8 PAD; uint16 period; uint16 num_slot; wl_nan_stats_sched_slot_t slot[]; @@ -13317,12 +15271,20 @@ typedef struct wl_nan_peer_stats_sched { uint8 map_id; uint8 seq_id; /* seq id from NA attr */ uint8 slot_dur; - uint8 pad; + uint8 PAD; uint16 period; uint16 num_slot; wl_nan_stats_sched_slot_t slot[]; } wl_nan_peer_stats_sched_t; +/* WL_NAN_XTLV_GEN_PEER_KA_OOB_AF_STAT */ +typedef struct nan_peer_oob_af_stat { + uint32 tx_ok; + uint32 rx_ok; + uint32 tx_fail; + uint32 rx_timeout; +} nan_peer_oob_af_stat_t; + /* WL_NAN_XTLV_RANGE_STATS */ typedef struct wl_nan_range_stats { uint16 rng_ssn_estb; @@ -13337,15 +15299,18 @@ typedef struct wl_nan_range_stats { /* defines for ndp stats flag */ -#define NAN_NDP_STATS_FLAG_ROLE_MASK 0x01 -#define NAN_NDP_STATS_FLAG_ROLE_INIT 0x00 -#define NAN_NDP_STATS_FLAG_ROLE_RESP 0x01 +#define NAN_NDP_STATS_FLAG_ROLE_MASK 0x01u +#define NAN_NDP_STATS_FLAG_ROLE_INIT 0x00u +#define NAN_NDP_STATS_FLAG_ROLE_RESP 0x01u + +#define NAN_NDP_STATS_STATE_BIT_SHIFT 1u +#define NAN_NDP_STATS_FLAG_STATE_MASK 0x07u +#define NAN_NDP_STATS_FLAG_STATE_IN_PROG 0x00u +#define NAN_NDP_STATS_FLAG_STATE_ESTB 0x01u +#define NAN_NDP_STATS_FLAG_STATE_TEARDOWN_WAIT 0x02u + +#define NAN_NDP_STATS_FLAG_MESH 0x10u -#define NAN_NDP_STATS_STATE_BIT_SHIFT 1 -#define NAN_NDP_STATS_FLAG_STATE_MASK 0x07 -#define NAN_NDP_STATS_FLAG_STATE_IN_PROG 0x00 -#define NAN_NDP_STATS_FLAG_STATE_ESTB 0x01 -#define NAN_NDP_STATS_FLAG_STATE_TEARDOWN_WAIT 0x02 /* More states can be added here, when needed */ /* WL_NAN_XTLV_GEN_NDP_STATS */ @@ -13394,6 +15359,7 @@ typedef uint8 wl_nan_mr_changed_t; /** status - TBD BCME_ vs NAN status - range reserved for BCME_ */ enum { /* add new status here... */ + WL_NAN_E_GRP_REKEY_FAIL = -2136, /* Group rekey failure */ WL_NAN_E_INVALID_TOKEN = -2135, /* invalid token or mismatch */ WL_NAN_E_INVALID_ATTR = -2134, /* generic invalid attr error */ WL_NAN_E_INVALID_NDL_ATTR = -2133, /* invalid NDL attribute */ @@ -13482,8 +15448,9 @@ enum { WL_NAN_E_INVALID_BAND = -2050, WL_NAN_E_INVALID_MAC = -2049, WL_NAN_E_BAD_INSTANCE = -2048, - /* NAN status code reserved from -2048 to -3071 */ - /* Do NOT add new status below -2048 */ + WL_NAN_E_INVALID_S3_ATTR = -2047, + /* NAN status code reserved from -2046 to -3071 */ + /* Do NOT add new status below -2046 */ WL_NAN_E_ERROR = -1, WL_NAN_E_OK = 0 }; @@ -13529,7 +15496,7 @@ typedef struct wl_nan_ioc { uint16 version; /**< interface command or event version */ uint16 id; /**< nan ioctl cmd ID */ uint16 len; /**< total length of all tlv records in data[] */ - uint16 pad; /**< pad to be 32 bit aligment */ + uint16 PAD; /**< pad to be 32 bit aligment */ uint8 data []; /**< var len payload of bcm_xtlv_t type */ } wl_nan_ioc_t; @@ -13568,33 +15535,88 @@ enum wl_nan_cfg_ctrl2_flags1 { /* Allows unicast SDF TX while local device is under NDP/NDL negotiation, * but Not with the peer SDF destined to. */ - WL_NAN_CTRL2_FLAG1_ALLOW_SDF_TX_UCAST_IN_PROG = 0x00000001, + WL_NAN_CTRL2_FLAG1_ALLOW_SDF_TX_UCAST_IN_PROG = 0x00000001, /* Allows broadcast SDF TX while local device is under NDP/NDL negotiation */ - WL_NAN_CTRL2_FLAG1_ALLOW_SDF_TX_BCAST_IN_PROG = 0x00000002, + WL_NAN_CTRL2_FLAG1_ALLOW_SDF_TX_BCAST_IN_PROG = 0x00000002, /* Allows the device to send schedule update automatically on local schedule change */ - WL_NAN_CTRL2_FLAG1_AUTO_SCHEDUPD = 0x00000004, + WL_NAN_CTRL2_FLAG1_AUTO_SCHEDUPD = 0x00000004, /* Allows the device to handle slot pre_close operations */ - WL_NAN_CTRL2_FLAG1_SLOT_PRE_CLOSE = 0x00000008, + WL_NAN_CTRL2_FLAG1_SLOT_PRE_CLOSE = 0x00000008, /* Control flag to enable/disable NDPE capability */ - WL_NAN_CTRL2_FLAG1_NDPE_CAP = 0x000000010, + WL_NAN_CTRL2_FLAG1_NDPE_CAP = 0x00000010, /* Control flag to enable/disable AUTO DAM LWT mode */ - WL_NAN_CTRL2_FLAG1_AUTODAM_LWT_MODE = 0x000000020, + WL_NAN_CTRL2_FLAG1_AUTODAM_LWT_MODE = 0x00000020, /* Control flag to enable/disable PMK per NDP */ - WL_NAN_CTRL2_FLAG1_PMK_PER_NDP = 0x000000040, + WL_NAN_CTRL2_FLAG1_PMK_PER_NDP = 0x00000040, /* Control flag to enable/disable allowing clear Schedule Update on Secured connection */ - WL_NAN_CTRL2_FLAG1_SEC_ALLOW_CLEAR_SCHED_UPD_PKT = 0x000000080, + WL_NAN_CTRL2_FLAG1_SEC_ALLOW_CLEAR_SCHED_UPD_PKT = 0x00000080, /* Control flag to disable/enable 5G FAW */ - WL_NAN_CTRL2_FLAG1_DISABLE_5G_FAW = 0x000000100, + WL_NAN_CTRL2_FLAG1_DISABLE_5G_FAW = 0x00000100, /* Control flag to disable/enable AUTO DAM 6G CAP */ - WL_NAN_CTRL2_FLAG1_DISABLE_AUTODAM_6G_CAP = 0x000000200, + WL_NAN_CTRL2_FLAG1_DISABLE_AUTODAM_6G_CAP = 0x00000200, /* Control flag to disable/enable allowing of unsecured OOB AF in a secured connection */ - WL_NAN_CTRL2_FLAG1_ALLOW_UNSECURED_OOB_AF = 0x000000400, + WL_NAN_CTRL2_FLAG1_ALLOW_UNSECURED_OOB_AF = 0x00000400, /* Control flag to enable/disable 6G FULL avail */ - WL_NAN_CTRL2_FLAG1_6G_FULL_AVAIL = 0x000000800 + WL_NAN_CTRL2_FLAG1_6G_FULL_AVAIL = 0x00000800, + /* Control flag to enable/disable PTK REKEY */ + WL_NAN_CTRL2_FLAG1_PTK_REKEY = 0x00001000, + /* Control flag to enable/disable GRP REKEY */ + WL_NAN_CTRL2_FLAG1_GTK_REKEY = 0x00002000, + /* Control flag to enable/disable GTK */ + WL_NAN_CTRL2_FLAG1_GTK = 0x00004000, + /* Control flag to enable/disable IGTK */ + WL_NAN_CTRL2_FLAG1_IGTK = 0x00008000, + /* Control flag to enable/disable BIGTK */ + WL_NAN_CTRL2_FLAG1_BIGTK = 0x00010000, + /* Control flag to enable/disable BIP_CMAC_128 */ + WL_NAN_CTRL2_FLAG1_BIP_CMAC_128 = 0x00020000, + /* Control flag to enable/disable BIP_GMAC_256 */ + WL_NAN_CTRL2_FLAG1_BIP_GMAC_256 = 0x00040000, + /* Control flag to enable/disable Notifs to BTcoex */ + WL_NAN_CTRL2_FLAG1_BTCX_NOTIF = 0x00080000, + /* Control flag to enable/disable NAN 3.1 Instant mode */ + WL_NAN_CTRL2_FLAG1_INSTANT_MODE = 0x00100000, + /* Control flag to disable/enable AUTO DAM dynamic schedule upgrade/downgrade */ + WL_NAN_CTRL2_FLAG1_DISABLE_AUTODAM_DYN_UPDOWN = 0x00200000, + /* Control flag to reject group addressed AFs w/o IGTK */ + WL_NAN_CTRL2_FLAG1_IGTK_REJECT_UNPROT = 0x00400000, + /* Control flag to reject bcn w/o BIGTK */ + WL_NAN_CTRL2_FLAG1_BIGTK_REJECT_UNPROT = 0x00800000, + /* Control flags to set infra slot duration. + * Two Bits[MSB:LSB], 00 -128ms, 01 - 64ms, 10 - 32ms, 11 - Reserved + */ + WL_NAN_CTRL2_FLAG1_INFRA_SLOT_INTRVL_LSB = 0x01000000, + WL_NAN_CTRL2_FLAG1_INFRA_SLOT_INTRVL_MSB = 0x02000000, + /* Control flag to enable NAN EHT */ + WL_NAN_CTRL2_FLAG1_EHT_ENABLE = 0x04000000, + /* Control flag to enable NAN STRML */ + WL_NAN_CTRL2_FLAG1_STRML_ENABLE = 0x08000000, + /* Control flag to enable NAN EMLSR */ + WL_NAN_CTRL2_FLAG1_EMLSR_ENABLE = 0x10000000, + /* Allow election (role change) outside of DW */ + WL_NAN_CTRL2_FLAG1_ELECTION_OUTOF_DW = 0x40000000 }; -#define WL_NAN_CTRL2_FLAGS1_MASK 0x00000FFF +#define WL_NAN_CTRL2_FLAGS1_MASK 0xFFFFFFFF -#define WL_NAN_CTRL2_FLAGS2_MASK 0x00000000 +enum wl_nan_cfg_ctrl2_flags2 { + /* Control flag to enable/disable NAN Pairing */ + WL_NAN_CTRL2_FLAG2_PAIRING = (1u << 0u), /* bit 0 */ + /* Control flag to enable/disable NAN Pairing NPK/NIK caching */ + WL_NAN_CTRL2_FLAG2_PAIRING_NPK_CACHING = (1u << 1u), /* bit 1 */ + /* Control flag to enable/disable NAN Pairing verification */ + WL_NAN_CTRL2_FLAG2_PAIRING_VERIFICATION = (1u << 2u), /* bit 2 */ + /* + * When a NAN device acting as a WFA test bed, is forced to include certain + * attributes than the default ones. For example, disabling use of NDPE attribute. + * + * Use this flag along with the WFA test mode flags (WL_NAN_WFA_TM_*) to + * enable WFA test mode operations. NAN R4 onwards, this flag is not + * needed. + */ + WL_NAN_CTRL2_FLAG2_USE_WFA_MODE = (1u << 3u), /* bit 3 */ + WL_NAN_CTRL2_FLAG2_S3_CAPABLE = (1u << 4u) /* bit 4 */ +}; +#define WL_NAN_CTRL2_FLAGS2_MASK 0x0000001f /* * WL_NAN_CMD_CFG_BAND, WL_NAN_CMD_CFG_RSSI_THRESHOLD(Get only) @@ -13648,7 +15670,7 @@ typedef struct wl_nan_rssi_threshold { wl_nan_band_t band; int8 rssi_close; int8 rssi_mid; - uint8 pad; + uint8 PAD; } wl_nan_rssi_threshold_t; /* WL_NAN_CMD_ELECTION_RSSI_THRESHOLD */ @@ -13687,7 +15709,8 @@ typedef struct wl_nan_conf_status { uint8 election_mode; /* Election mode, host or firmware */ uint8 hop_count; /* Current Hop count */ uint8 imr[8]; /* Immediate Master Rank */ - uint8 pad[4]; /* remove after precommit */ + uint8 status; /* Genenric status for nan events */ + uint8 PAD[3]; /* remove after precommit */ uint16 opt_tlvs_len; uint8 opt_tlvs[]; } wl_nan_conf_status_t; @@ -13724,6 +15747,14 @@ enum wl_nan_enable_flags { */ typedef uint8 wl_nan_host_enable_t; +/* + * WL_NAN_CMD_CFG_TSF + */ +typedef struct wl_nan_tsf_config { + uint32 tsf_hi; + uint32 tsf_lo; +} wl_nan_tsf_config_t; + /* * WL_NAN_CMD_ELECTION_METRICS_CONFIG */ @@ -13731,7 +15762,7 @@ typedef uint8 wl_nan_host_enable_t; typedef struct wl_nan_election_metric_config { uint8 random_factor; /* Configured random factor */ uint8 master_pref; /* configured master preference */ - uint8 pad[2]; + uint8 PAD[2]; } wl_nan_election_metric_config_t; /* @@ -13741,7 +15772,7 @@ typedef struct wl_nan_election_metric_config { typedef struct wl_nan_election_metric_state { uint8 random_factor; /* random factor used in MIs */ uint8 master_pref; /* Master advertised in MIs */ - uint8 pad[2]; + uint8 PAD[2]; } wl_nan_election_metric_state_t; /* @@ -13772,7 +15803,7 @@ typedef struct nanho_sec_sa { uint8 kek_len; /* KEK len in key_buf */ uint8 tk_len; /* Transient key len in key_buf */ uint16 flags; - uint16 pad; + uint16 PAD; struct ether_addr laddr; /* local mac addr */ struct ether_addr raddr; /* remote mac addr */ uint8 key_krc[NHO_SEC_NCS_SK_REPLAY_CNT_LEN]; /* Key Replay ctr */ @@ -13791,8 +15822,8 @@ typedef uint8 wl_nan_merge_enable_t; * role = 0 means configuration by firmware(obsolete); otherwise by host * when host configures role, also need target master address to sync to */ -#define NAN_SYNC_MASTER_SELF 1 -#define NAN_SYNC_MASTER_USE_TIMING 2 /* Use the tsf timing provided */ +#define NAN_SYNC_MASTER_SELF 1 +#define NAN_SYNC_MASTER_USE_TIMING 2 /* Use the tsf timing provided */ #define NAN_SYNC_MASTER_AMREC_UPD 4 /* provide AM record update */ /* @@ -13821,39 +15852,6 @@ typedef struct nan_sync_master { uint32 ambtt; } nan_sync_master_t; -#ifdef WLAWDL -/* -* NAN Sync TLV(NSTLV): -* To keep NAN/AWDL concurrency time sync. -* It is generated at hybrid device, and propogated by AWDL only device. -* It contains the information needed to run NAN election -*/ -#include -typedef BWL_PRE_PACKED_STRUCT struct awdl_nan_sync_tlv { - uint16 hop_count; /* total hop_count */ - struct ether_addr src_addr; /* macaddr of the hybrid originator of nstlv */ - struct ether_addr cluster_id; /* NAN cluster ID of hybrid originator of nstlv */ - uint32 nan_tsf_h; /* NAN cluster TSF of the hybrid originator of nstlv */ - uint32 nan_tsf_l; - uint8 master_preference; - uint8 random_factor; - uint8 amr[WL_NAN_MASTER_RANK_LEN]; - uint8 orig_hop_count; /* hop_count of the origin hybrid NAN device */ - uint32 ambtt; /* Anchor Master Beacon Transmission Time */ - uint8 opt_xtlv_len; /* xtlv len */ -} BWL_POST_PACKED_STRUCT awdl_nan_sync_tlv_t; - -typedef BWL_PRE_PACKED_STRUCT struct wl_awdl_nan_sync_tlv { - uint8 type; /* 23 for NTLV */ - uint16 param_len; - awdl_nan_sync_tlv_t ntlv; -} BWL_POST_PACKED_STRUCT wl_awdl_nan_sync_tlv_t; - -/* External NAN sync TLV which can be used by other modules to pass NAN sync info */ -typedef awdl_nan_sync_tlv_t external_nan_sync_tlv_t; -#include -#endif /* WLAWDL */ - /* NAN advertiser structure */ /* TODO RSDB: add chspec to indicates core corresponds correct core */ typedef struct nan_adv_entry { @@ -13896,21 +15894,21 @@ typedef struct nac_stats { typedef struct nan_adv_table { uint8 num_adv; uint8 adv_size; - uint8 pad[2]; + uint8 PAD[2]; nan_adv_entry_t adv_nodes[0]; } nan_adv_table_t; typedef struct wl_nan_role_cfg { wl_nan_role_t cfg_role; wl_nan_role_t cur_role; - uint8 pad[2]; + uint8 PAD[2]; nan_sync_master_t target_master; } wl_nan_role_cfg_t; typedef struct wl_nan_role_config { wl_nan_role_t role; struct ether_addr target_master; - uint8 pad; + uint8 PAD; } wl_nan_role_config_t; typedef int8 wl_nan_sd_optional_field_types_t; @@ -13923,11 +15921,6 @@ typedef int8 wl_nan_sd_optional_field_types_t; */ #define WL_NAN_RANGE_LIMITED 0x0040 -/* Event generation indicator (default is continuous) */ - -#define WL_NAN_MATCH_ONCE 0x100000 -#define WL_NAN_MATCH_NEVER 0x200000 - /* Bits specific to Publish */ #define WL_NAN_PUB_UNSOLICIT 0x1000 /* Unsolicited Tx */ @@ -13940,6 +15933,14 @@ typedef int8 wl_nan_sd_optional_field_types_t; #define WL_NAN_FOLLOWUP 0x20000 /* Follow-up frames */ #define WL_NAN_TX_FOLLOWUP 0x40000 /* host generated transmit Follow-up frames */ +#define WL_NAN_TX_FOLLOWUP_UNSYNC 0x80000 /* host generated TX Follow-up in unsync disc */ + +/* Event generation indicator (default is continuous) */ +#define WL_NAN_MATCH_ONCE 0x100000 +#define WL_NAN_MATCH_NEVER 0x200000 + +#define WL_NAN_SVC_BCN_CARRY 0x400000 /* Include SVC in beacons */ +#define WL_NAN_SVC_AUTO_RSP 0x800000 /* auto response SDF */ /* Bits specific to Subscribe */ @@ -13968,6 +15969,10 @@ typedef int8 wl_nan_sd_optional_field_types_t; /* If set, host wont rec event "terminated" */ #define WL_NAN_SVC_CTRL_SUPPRESS_EVT_TERMINATED 0x8000000 +#define NAN_REKEY_PTK 0x01 +#define NAN_REKEY_GTK 0x02 +#define NAN_REKEY_MAX (NAN_REKEY_PTK | NAN_REKEY_GTK) + /* * WL_NAN_CMD_SD_PARAMS */ @@ -13981,7 +15986,7 @@ typedef struct wl_nan_sd_params int8 proximity_rssi; /* RSSI limit to Rx subscribe or pub SDF 0 no effect */ uint32 flags; /* bitmap representing aforesaid optional flags */ int32 ttl; /* TTL for this instance id, -1 will run till cancelled */ - tlv_t optional[1]; /* optional fields in the SDF as appropriate */ + tlv_t optional[BCM_FLEX_ARRAY]; /* optional fields in the SDF as appropriate */ } wl_nan_sd_params_t; /* @@ -13997,7 +16002,7 @@ typedef struct wl_nan_service_info typedef struct wl_nan_service_list { uint16 id_count; /* Number of registered publish/subscribe services */ - wl_nan_service_info_t list[1]; /* service info defined by nan_service instance */ + wl_nan_service_info_t list[BCM_FLEX_ARRAY]; /* service info defined by nan_service */ } wl_nan_service_list_t; /* @@ -14020,6 +16025,12 @@ typedef uint16 wl_nan_stop_bcn_tx_t; */ typedef uint32 wl_nan_fsm_timeout_t; +// nan rekey cfg iovar +typedef struct wl_nan_rekey { + struct ether_addr ndi_addr; + uint8 rekey_ctrl; +} wl_nan_rekey_t; + /* * WL_NAN_CMD_CFG_SID_BEACON */ @@ -14027,7 +16038,7 @@ typedef struct wl_nan_sid_beacon_control { uint8 sid_enable; /* Flag to indicate the inclusion of Service IDs in Beacons */ uint8 sid_count; /* Limit for number of publish SIDs to be included in Beacons */ uint8 sub_sid_count; /* Limit for number of subscribe SIDs to be included in Beacons */ - uint8 pad; + uint8 PAD; } wl_nan_sid_beacon_control_t; /* @@ -14041,7 +16052,7 @@ typedef uint16 wl_nan_dw_len_t; typedef struct wl_nan_awake_dw { wl_nan_band_t band; /* 0 - b mode 1- a mode */ uint8 interval; /* 1 or 2 or 4 or 8 or 16 */ - uint16 pad; + uint16 PAD; } wl_nan_awake_dw_t; /* @@ -14050,7 +16061,7 @@ typedef struct wl_nan_awake_dw { typedef struct wl_nan_awake_dws { uint8 dw_interval_2g; /* 2G DW interval */ uint8 dw_interval_5g; /* 5G DW interval */ - uint16 pad; + uint16 PAD; } wl_nan_awake_dws_t; /* WL_NAN_CMD_SYNC_BCN_RSSI_NOTIF_THRESHOLD */ @@ -14058,7 +16069,7 @@ typedef struct wl_nan_awake_dws { typedef struct wl_nan_rssi_notif_thld { int8 bcn_rssi_2g; int8 bcn_rssi_5g; - int16 pad; + int16 PAD; } wl_nan_rssi_notif_thld_t; /* @@ -14067,7 +16078,7 @@ typedef struct wl_nan_rssi_notif_thld { typedef struct wl_nan_social_channels { uint8 soc_chan_2g; /* 2G social channel */ uint8 soc_chan_5g; /* 5G social channel */ - uint16 pad; + uint16 PAD; } wl_nan_social_channels_t; /* @@ -14106,6 +16117,10 @@ typedef struct wl_nan_sd_stats { /* If set, host wont rec "tx status" event for tx-followup msg */ #define WL_NAN_FUP_SUPR_EVT_TXS 0x01 +/* If set, insert shared key descr attribute in tx-followup msg */ +#define WL_NAN_FUP_ADD_SKDA 0x02 +/* If set, send tx-followup msg without peer availability check */ +#define WL_NAN_FUP_UNSYNC_TX 0x04 /* more flags can be added here */ /* @@ -14159,6 +16174,7 @@ typedef struct wl_nan_scan_params { uint16 scan_period; /* band index of discovery channel */ uint8 band_index; + uint8 PAD; } wl_nan_scan_params_t; /* @@ -14166,7 +16182,7 @@ typedef struct wl_nan_scan_params { */ typedef struct wl_nan_dbg_scan { struct ether_addr cid; - uint8 pad[2]; + uint8 PAD[2]; } wl_nan_dbg_scan_t; /* NAN_DBG_LEVEL */ @@ -14298,12 +16314,13 @@ enum wl_nan_dp_cmds { #define WL_NAN_DATA_NDP_INST_SUPPORT 16 /* Nan flags (16 bits) */ -#define WL_NAN_DP_FLAG_SVC_INFO 0x0001 -#define WL_NAN_DP_FLAG_CONFIRM 0x0002 -#define WL_NAN_DP_FLAG_EXPLICIT_CFM 0x0004 -#define WL_NAN_DP_FLAG_SECURITY 0x0008 -#define WL_NAN_DP_FLAG_HAST_NDL_COUNTER 0x0010 /* Host assisted NDL counter */ - +#define WL_NAN_DP_FLAG_SVC_INFO 0x0001u +#define WL_NAN_DP_FLAG_CONFIRM 0x0002u +#define WL_NAN_DP_FLAG_EXPLICIT_CFM 0x0004u +#define WL_NAN_DP_FLAG_SECURITY 0x0008u +#define WL_NAN_DP_FLAG_HAST_NDL_COUNTER 0x0010u /* Host assisted NDL counter */ +/* If it is a rekey or new NDP setup 0 = new NDP, 1 = REKEY */ +#define WL_NAN_DP_FLAG_REKEY 0x0020u /* NAN Datapath host status */ #define WL_NAN_DP_STATUS_ACCEPTED 1 #define WL_NAN_DP_STATUS_REJECTED 0 @@ -14365,7 +16382,7 @@ typedef struct wl_nan_ev_p2p_avail { uint8 dev_role; uint8 resolution; uint8 repeat; - uint8 pad[3]; + uint8 PAD[3]; chanspec_t chanspec; uint32 avail_bmap; } wl_nan_ev_p2p_avail_t; @@ -14400,7 +16417,7 @@ typedef struct wl_nan_oob_af_params_s uint16 flags; /* wl_nan_oob_af_flags_t */ uint32 fsm_id; /* unique fsm id */ uint16 payload_len; - uint8 payload[1]; + uint8 payload[BCM_FLEX_ARRAY]; } wl_nan_oob_af_params_t; /* NAN Ranging */ @@ -14440,7 +16457,7 @@ typedef struct nan_ranging_list { */ uint8 num_dws; /**< time period to do the ranging, specified in dws */ uint8 reserve; /**< reserved field */ - wl_nan_ranging_peer_t rp[1]; /**< variable length array of peers */ + wl_nan_ranging_peer_t rp[BCM_FLEX_ARRAY]; /**< variable length array of peers */ } wl_nan_ranging_list_t; /* ranging results, a list for self initiated ranging and one for peer initiated ranging */ @@ -14474,7 +16491,7 @@ typedef struct nan_ranging_event_data { uint8 reserved; uint8 success_count; /**< number of peers completed successfully */ uint8 count; /**< number of peers in the list */ - wl_nan_ranging_result_t rr[1]; /**< variable array of ranging peers */ + wl_nan_ranging_result_t rr[BCM_FLEX_ARRAY]; /**< variable array of ranging peers */ } wl_nan_ranging_event_data_t; enum { @@ -14562,14 +16579,14 @@ typedef struct wl_nan_peer_rssi_entry { typedef struct wl_nan_nbr_rssi_data { uint8 flags; /* this is a list or single rssi data */ uint8 peer_cnt; /* number of peers */ - uint16 pad; /* padding */ - wl_nan_peer_rssi_entry_t peers[1]; /* peers data list */ + uint16 PAD; /* padding */ + wl_nan_peer_rssi_entry_t peers[BCM_FLEX_ARRAY]; /* peers data list */ } wl_nan_peer_rssi_data_t; /* WL_NAN_CMD_DBG_DUMP, GET Resp */ typedef struct wl_nan_dbg_dump_rsp { wl_nan_dbg_dump_type_t dump_type; /* dump data type */ - uint8 pad[3]; + uint8 PAD[3]; union { wl_nan_peer_rssi_data_t peer_rssi; wl_nan_stats_t nan_stats; @@ -14591,7 +16608,7 @@ enum nan_termination_status { typedef struct wl_nan_dp_qos { uint8 tid; - uint8 pad; + uint8 PAD; uint16 pkt_size; uint16 mean_rate; uint16 svc_interval; @@ -14603,7 +16620,7 @@ typedef struct wl_nan_dp_qos typedef struct wl_nan_ndl_qos { uint8 min_slots; /* min slots per dw interval */ - uint8 pad; + uint8 PAD; uint16 max_latency; /* max latency */ } wl_nan_ndl_qos_t; @@ -14618,8 +16635,8 @@ typedef struct wl_nan_ndp_config uint8 svc_spec_info[WL_NAN_DATA_SVC_SPEC_INFO_LEN]; wl_nan_dp_qos_t qos; uint16 avail_len; - uint8 pad[3]; - uint8 data[1]; + uint8 PAD[3]; + uint8 data[BCM_FLEX_ARRAY]; } wl_nan_ndp_config_t; /* nan2 device capabilities */ @@ -14647,39 +16664,131 @@ typedef struct wl_nan_dp_req { uint8 tlv_params[]; /* xtlv parameters for command */ } wl_nan_dp_req_t; +/* NAN pairing flags */ +/* Support for npk caching */ +#define WL_NAN_PAIRING_FLAGS_NPK_CACHING (1u << 0u) +/* Support for pairing setup */ +#define WL_NAN_PAIRING_FLAGS_SETUP (1u << 1u) + +enum wl_nan_pairing_role { + WL_NAN_PAIRING_ROLE_INITIATOR = 0, + WL_NAN_PAIRING_ROLE_RESPONDER = 1, + WL_NAN_PAIRING_ROLE_MAX = WL_NAN_PAIRING_ROLE_RESPONDER +}; + +typedef uint8 wl_nan_pairing_role_t; + +enum wl_nan_pairing_type { + WL_NAN_PAIRING_TYPE_SETUP = 0, + WL_NAN_PAIRING_TYPE_VERIFICATION = 1, + WL_NAN_PAIRING_TYPE_MAX = WL_NAN_PAIRING_TYPE_VERIFICATION +}; + +typedef uint8 wl_nan_pairing_type_t; + +typedef uint8 wl_pasn_policy_t; + +typedef uint8 wl_nan_pairing_state_t; +enum wl_nan_pairing_state { + WL_NAN_PAIRING_STATUS_IDLE = 0, + WL_NAN_PAIRING_STATUS_CREATED = 1, + WL_NAN_PAIRING_STATUS_PAIRED = 2, + WL_NAN_PAIRING_STATUS_FAILED = 3, + WL_NAN_PAIRING_STATUS_UNKNOWN = 4, + WL_NAN_PAIRING_STATUS_MAX = 4 +}; + +/* WL_NAN_XTLV_GEN_PEER_PAIRING_STATS */ +typedef struct wl_nan_peer_stats_pairing { + wl_nan_pairing_role_t role; /* Current Role - Initiator or Responder */ + wl_nan_pairing_state_t state; /* Current paired state */ + uint8 sid; /* current session id */ + wl_nan_pairing_type_t type; /* Current type setup or verification */ + wl_pasn_policy_t policy; /* Current policy PASN Auth or non-Auth */ + uint8 csid; /* Selected CSID */ + uint8 PAD[2]; + uint16 sessions_pass; /* Number of successful sessions */ + uint16 sessions_fail; /* Number of failed sessions */ +} wl_nan_peer_stats_pairing_t; + +typedef uint8 wl_nan_pairing_bootstr_meth_t; + +typedef struct wl_nan_pairing_oper { + uint32 key_lifetime_ms; /* PTKSA timeout interval configured. */ + struct ether_addr peer_addr; /* Peer's addr */ + uint16 flags; /* bit 0: NPK/NIK caching enabled */ + wl_nan_pairing_role_t role; /* operation - Initiator or responder */ + wl_nan_pairing_type_t type; /* Setup or verification */ + uint8 pub_id; /* Publisher ID */ + uint8 pasn_policy; /* specify policy supported by the session */ + uint8 pasn_csid; /* PASN Cipher suite ID */ + uint8 pad[3]; + uint8 tlv_params[]; /* xtlv parameters for command */ +} wl_nan_pairing_oper_t; + +typedef uint8 wl_nan_pairing_peer_info_operation_t; +enum wl_nan_pairing_peer_info_operation { + WL_NAN_PAIRING_PEER_INFO_ADD = 0, + WL_NAN_PAIRING_PEER_INFO_DELETE = 1, + WL_NAN_PAIRING_PEER_INFO_DELETE_ALL = 2 +}; + +/* WL_NAN_CMD_PAIRING_PEER_INFO */ +typedef struct wl_nan_pairing_peer_info { + struct ether_addr peer_addr; /* Peer's addr */ + uint8 pub_id; /* Publisher ID */ + uint8 operation; /* add , delete */ + uint16 flags; /* Flags for auto response setup/verify, csid/s */ + uint8 pad[2]; + uint8 tlv_params[]; /* xtlv parameters for command */ +} wl_nan_pairing_peer_info_t; + +/* Common event structure for Nan pairing + * Used for sending pairing Indication, Response, Establish events + */ +typedef struct wl_nan_ev_pairing_cmn { + uint8 type; + uint8 security; + struct ether_addr peer_nmi; + uint8 status; + uint8 role; + uint16 opt_tlv_len; + uint8 opt_tlvs[]; +} wl_nan_ev_pairing_cmn_t; + /* TODO Need to replace ndp_id with lndp_id */ /* Return structure to data req IOVAR */ typedef struct wl_nan_dp_req_ret { struct ether_addr indi; /* Initiators data mac addr */ uint8 ndp_id; /* Initiators ndpid */ - uint8 pad; + uint8 PAD; } wl_nan_dp_req_ret_t; typedef struct wl_nan_dp_resp { - uint8 type; /* 0- unicast 1 - multicast */ - uint8 status; /* Accepted or Rejected */ + uint8 type; /* 0- unicast 1 - multicast */ + uint8 status; /* Accepted or Rejected */ uint8 reason_code; /* Local NDP ID for unicast, mc_id for multicast, 0 for implicit NMSG */ - uint8 ndp_id; /* can be host indp id also */ + uint8 ndp_id; /* can be host indp id also */ wl_nan_dp_qos_t qos; /* Initiator data address for unicast or multicast address for multicast */ struct ether_addr mac_addr; struct ether_addr ndi; uint16 flags; wl_nan_ndl_qos_t ndl_qos; /* ndl qos */ - uint8 tlv_params[]; /* xtlv parameters for command */ + uint8 tlv_params[]; /* xtlv parameters for command */ } wl_nan_dp_resp_t; /* Return structure to data resp IOVAR */ typedef struct wl_nan_dp_resp_ret { uint8 nmsgid; /* NMSG ID or for multicast else 0 */ - uint8 pad[3]; + uint8 PAD[3]; } wl_nan_dp_resp_ret_t; typedef struct wl_nan_dp_conf { uint8 lndp_id; /* can be host ndp id */ uint8 status; /* Accepted or Rejected */ - uint8 pad[2]; + uint8 PAD[2]; } wl_nan_dp_conf_t; /* WL_NAN_CMD_DATA_DATAEND */ @@ -14712,7 +16821,7 @@ typedef struct wl_nan_dp_schedupd { wl_nan_dp_qos_t qos; wl_nan_ndl_qos_t ndl_qos; /* ndl qos */ uint8 map_id; - uint8 pad; + uint8 PAD; uint16 hostseq; } wl_nan_dp_schedupd_t; @@ -14730,7 +16839,7 @@ typedef struct ndp_session { uint8 lndp_id; uint8 state; uint8 pub_id; - uint8 pad; + uint8 PAD; } ndp_session_t; typedef struct wl_nan_ndp_status { @@ -14738,7 +16847,7 @@ typedef struct wl_nan_ndp_status { struct ether_addr peer_ndi; ndp_session_t session; struct ether_addr lndi; - uint8 pad[2]; + uint8 PAD[2]; } wl_nan_ndp_status_t; #define NAN_DP_OPAQUE_INFO_DP_RESP 0x01 @@ -14749,7 +16858,7 @@ typedef struct wl_nan_dp_opaque_info { struct ether_addr initiator_ndi; /* NDI to match in the dp_req. */ uint8 pub_id; /* publish id where the opaque data is included. */ uint8 len; /* len of opaque_info[]. */ - uint8 pad[3]; + uint8 PAD[3]; uint8 opaque_info[0]; } wl_nan_dp_opaque_info_t; @@ -14800,7 +16909,7 @@ typedef struct wl_nan_ev_datapath_cmn { typedef struct wl_nan_ev_datapath_end { uint8 ndp_id; uint8 status; - uint8 pad[2]; + uint8 PAD[2]; struct ether_addr peer_nmi; struct ether_addr peer_ndi; } wl_nan_ev_datapath_end_t; @@ -14813,7 +16922,7 @@ typedef struct wl_tsf { typedef struct wl_nan_ev_rx_bcn { wl_tsf_t tsf; uint16 bcn_len; - uint8 pad[2]; + uint8 PAD[2]; uint8 bcn[0]; } wl_nan_ev_rx_bcn_t; @@ -14842,7 +16951,7 @@ typedef struct wl_nan_host_assist_req { wl_nan_frame_type_t frm_type; /* received NAF type */ wl_nan_host_assist_reason_t reason; /* reason of host assist request */ uint8 pub_id; /* Publish ID (valid for WL_NAN_FRM_TYPE_DP_REQ) */ - uint8 pad[2]; + uint8 PAD[2]; } wl_nan_host_assist_req_t; /* nan sub-features */ @@ -14869,7 +16978,16 @@ enum wl_nan_fw_cap_flag1 { WL_NAN_FW_CAP_FLAG1_NANHO = 0x00040000, WL_NAN_FW_CAP_FLAG1_NDPE = 0x00080000, WL_NAN_FW_CAP_FLAG1_OOB_AF = 0x00100000, - WL_NAN_FW_CAP_FLAG1_PMK_PER_NDP = 0x00200000 + WL_NAN_FW_CAP_FLAG1_PMK_PER_NDP = 0x00200000, + WL_NAN_FW_CAP_FLAG1_INSTANT_MODE = 0x00400000, + /* Group Addressed Frames Protect (GTK/IGTK/BIGTK) */ + WL_NAN_FW_CAP_FLAG1_GAF_PROTECT = 0x00800000, + WL_NAN_FW_CAP_FLAG1_REKEY = 0x01000000, + WL_NAN_FW_CAP_FLAG1_S3 = 0x02000000, + WL_NAN_FW_CAP_FLAG1_PAIRING = 0x04000000, + WL_NAN_FW_CAP_FLAG1_6G = 0x08000000, + WL_NAN_FW_CAP_FLAG1_MCAST_AVAIL_BMP = 0x10000000, + WL_NAN_FW_CAP_FLAG1_WOW_OFFLOAD = 0x20000000 }; /* WL_NAN_XTLV_GEN_FW_CAP */ @@ -14897,7 +17015,7 @@ typedef struct wl_nan_fw_cap { uint8 ndp_supported_bands; /* number of ndp supported bands */ uint8 is_ndp_security_supported; /* if secure ndp is supported */ uint8 cipher_suites_supported_mask; /* bitmask for suites supported */ - uint8 pad[3]; + uint8 PAD[3]; } wl_nan_fw_cap_t; /* WL_NAN_XTLV_GEN_FW_CAP_V2 */ @@ -14920,8 +17038,14 @@ typedef struct wl_nan_fw_cap_v2 { } wl_nan_fw_cap_v2_t; /* nan cipher suite support mask bits */ -#define WL_NAN_CIPHER_SUITE_SHARED_KEY_128_MASK 0x01 -#define WL_NAN_CIPHER_SUITE_SHARED_KEY_256_MASK 0x02 +#define WL_NAN_CIPHER_SUITE_SHARED_KEY_128_MASK 0x01u +#define WL_NAN_CIPHER_SUITE_SHARED_KEY_256_MASK 0x02u +#define WL_NAN_CIPHER_SUITE_PUBLIC_KEY_128_MASK 0x04u +#define WL_NAN_CIPHER_SUITE_PUBLIC_KEY_256_MASK 0x08u +#define WL_NAN_CIPHER_SUITE_GROUP_KEY_128_MASK 0x10u +#define WL_NAN_CIPHER_SUITE_GROUP_KEY_256_MASK 0x20u +#define WL_NAN_CIPHER_SUITE_BIP_KEY_128_MASK 0x40u +#define WL_NAN_CIPHER_SUITE_BIP_KEY_256_MASK 0x80u /* NAN Save Restore */ #define WL_NAN_NSR2_INFO_MAX_SIZE 2048 /* arbitrary */ @@ -14934,7 +17058,7 @@ typedef struct wl_nan_nsr_peer_info { uint16 l_max_latency; /* local QoS max latency */ uint16 p_max_latency; /* peer QoS max latency */ uint8 num_map; /* num of NA map */ - uint8 pad; + uint8 PAD; uint16 attrs_len; /* total len of following attrs */ uint8 attrs[]; /* peer attributes (NA/NDC/ULW/DevCap/Element container) */ } wl_nan_nsr_peer_info_t; @@ -14954,7 +17078,7 @@ typedef struct wl_nan_nsr_ndp_info { uint8 pub_id; /* publish id */ uint8 indp_id; /* initiator's ndp id */ uint8 last_token; /* last NDP dialog token */ - uint8 pad; + uint8 PAD; } wl_nan_nsr_ndp_info_t; /* NAN2.0 Ranging definitions */ @@ -15004,7 +17128,7 @@ typedef struct wl_nan_range_resp { typedef struct wl_nan_range_cancel_ext { wl_nan_range_id range_id; uint8 flags; - uint8 pad[2]; + uint8 PAD[2]; } wl_nan_range_cancel_ext_t; #define NAN_RNG_CANCEL_IOV_FIXED_LEN 4u @@ -15023,7 +17147,7 @@ typedef struct wl_nan_ev_rng_req_ind { uint8 lc_info_avail; /* Last movement indication */ uint16 last_movement; - uint8 pad[2]; + uint8 PAD[2]; } wl_nan_ev_rng_req_ind_t; #define NAN_RNG_REQ_IND_SIZE 14 @@ -15085,7 +17209,7 @@ typedef struct wl_nan_ev_rng_resp { typedef struct wl_nan_ev_sched_info { struct ether_addr peer_nmi; uint8 ndl_status; /* applies only to sched resp/conf */ - uint8 pad; + uint8 PAD; uint16 opt_tlv_len; uint8 opt_tlvs[]; } wl_nan_ev_sched_info_t; @@ -15104,18 +17228,18 @@ typedef struct wl_nan_chbound_info { /* WL_NAN_XTLV_CCA_STATS */ typedef struct wl_nan_cca_stats { uint16 chanspec; - uint8 pad[2]; - uint32 sample_dur; + int16 noise; + uint32 sample_dur; /* CCA measurement duration (in ms) */ - uint32 congest_ibss; - uint32 congest_obss; - uint32 interference; + uint32 congest_ibss; /* IBSS & TxDUR (in us) */ + uint32 congest_obss; /* OBSS & noctg (in us) */ + uint32 interference; /* nopkt & ED (in us) */ } wl_nan_cca_stats_t; /* WL_NAN_XTLV_PER_STATS */ typedef struct wl_nan_per_stats_s { uint16 chanspec; - uint8 pad[2]; + uint8 PAD[2]; uint32 sample_dur; uint32 txframe; /* tx data frames */ @@ -15143,203 +17267,52 @@ typedef struct wl_nan_per_stats_s { typedef struct wl_nan_fastdisc_s { uint8 id; uint8 bitmap_len; - uint8 pad[2]; + uint8 PAD[2]; uint8 bitmap[]; } wl_nan_fastdisc_t; #define WL_NAN_FASTDISC_CFG_SIZE 1024 /* arbitrary */ -#ifdef WL_NANHO -/* ****************** NAN Host offload specific strucures ****************** */ +/* NAN NDL schedule info for a particular negotiation. + * WL_NAN_XTLV_NDL_SCHED_INFO + */ +typedef struct wl_nan_ndl_slot_info { + uint16 chanspec; + uint8 nss; + uint8 PAD; +} wl_nan_ndl_slot_info_t; -enum wl_nan_rx_mgmt_frm_type { - WL_NAN_RX_MGMT_FRM_BCN = 0, - WL_NAN_RX_MGMT_FRM_SDF = 1, - WL_NAN_RX_MGMT_FRM_NAF = 2 -}; -typedef uint8 wl_nan_rx_mgmt_frm_type_t; +typedef struct wl_nan_ndl_sched_info { + uint16 num_slot; + uint16 period; + wl_nan_ndl_slot_info_t slot[]; +} wl_nan_ndl_sched_info_t; -/* WL_NAN_EVENT_RX_MGMT_FRM */ -typedef struct wl_nan_event_rx_mgmt_frm { - uint8 frm_type; /* wl_nan_rx_mgmt_frm_type_t */ - uint8 pad; - uint16 frm_len; - uint8 frm[]; -} wl_nan_event_rx_mgmt_frm_t; +/* + * NAN multicast data slot bitmap config + * WL_NAN_XTLV_CFG_MCAST_AVAIL_BMP + */ +typedef struct wl_nan_mcast_avail_bmp_s { + uint8 mapid; + uint8 bitmap_len; + uint8 PAD[2]; + uint8 bitmap[BCM_FLEX_ARRAY]; +} wl_nan_mcast_avail_bmp_t; +#define WL_NAN_MCAST_AVAIL_BMP_LEN_FIXED (OFFSETOF(wl_nan_mcast_avail_bmp_t, bitmap)) +#define WL_NAN_MCAST_AVAIL_BMP_LEN_MAX (WL_NAN_MCAST_AVAIL_BMP_LEN_FIXED + 8u) /* 1024/16TU */ -#define WL_NAN_NANHO_UPDATE_MAX_SIZE 2048 /* arbitrary */ - -enum wl_nan_peer_entry_action { - WL_NAN_PEER_ENTRY_ACT_ADD = 0, /* add peer entry */ - WL_NAN_PEER_ENTRY_ACT_REMOVE = 1 /* remove peer entry */ -}; -typedef uint8 wl_nan_peer_entry_action_t; - -/* WL_NAN_XTLV_NANHO_PEER_ENTRY */ -typedef struct wl_nan_peer_entry -{ - struct ether_addr nmi; /* nmi of peer device */ - uint8 action; /* wl_nan_peer_entry_action_t */ - uint8 pad; -} wl_nan_peer_entry_t; - -enum wl_nan_dcaplist_action { - WL_NAN_DCAPLIST_ACT_UPDATE = 0, /* update or add */ - WL_NAN_DCAPLIST_ACT_REMOVE = 1 /* remove (only for peer dcap cache entry) */ -}; -typedef uint8 wl_nan_dcaplist_action_t; - -/* WL_NAN_XTLV_NANHO_DCAPLIST */ -typedef struct wl_nan_dev_cap_list -{ - struct ether_addr nmi; /* null for local device */ - uint8 action; /* wl_nan_dcaplist_action_t */ - /* optional fields for WL_NAN_DCAPLIST_ACT_UPDATE */ - uint8 num_maps; - uint8 dcap[]; /* list of nan_dev_cap_t */ -} wl_nan_dev_cap_list_t; - -typedef struct wl_nan_dev_chan_sched { - uint16 num_slots; /* number of slot in schedule */ - uint16 period; /* period of channel schedule (TU) */ - uint8 slot_dur; /* slot duration (TU) */ - uint8 map_id; /* map id (TBD) */ - uint8 pad[2]; - uint8 data[]; - /* chanspec_t chan_sched[num_slot] */ - /* uint8 slot_info[num_slot] */ -} wl_nan_dev_chan_sched_t; - -/* WL_NAN_XTLV_NANHO_DCSLIST */ -typedef struct wl_nan_dev_chan_sched_list { - struct ether_addr nmi; /* null for local device */ - uint8 num_maps; - uint8 pad; - wl_nan_dev_chan_sched_t dcs[]; -} wl_nan_dev_chan_sched_list_t; - -/* WL_NAN_XTLV_NANHO_BLOB */ -typedef struct wl_nan_dev_blob { - struct ether_addr nmi; /* null for local device */ - uint16 blob_len; /* blob len in blob[] buffer */ - uint8 blob_type; - uint8 pad[3]; - uint8 blob[]; -} wl_nan_dev_blob_t; - -typedef struct wl_nan_peer_ndl_state { - struct ether_addr nmi; - uint8 ndl_state; /* nan_peer_ndl_state_t */ - uint8 pad; -} wl_nan_peer_ndl_state_t; - -enum wl_nan_ndp_state_action { - WL_NAN_NDP_STATE_ACT_ESTABLISHED = 0, - WL_NAN_NDP_STATE_ACT_TERMINATED = 1 -}; -typedef uint8 wl_nan_ndp_state_action_t; - -/* WL_NAN_XTLV_NANHO_NDP_STATE */ -typedef struct wl_nan_ndp_state { - struct ether_addr peer_nmi; - struct ether_addr peer_ndi; - struct ether_addr lcl_ndi; - uint8 action; /* wl_nan_ndp_state_action_t */ - uint8 pad; - /* TODO: secured NDP information */ -} wl_nan_ndp_state_t; - -/* *************** end of NAN Host offload specific strucures ************** */ -#endif /* WL_NANHO */ +typedef struct wl_nan_mcast_avail_s { + struct ether_addr ndi; + uint8 PAD[2]; + wl_nan_mcast_avail_bmp_t bmp[]; +} wl_nan_mcast_avail_t; +#define WL_NAN_MCAST_AVAIL_LEN_FIXED (OFFSETOF(wl_nan_mcast_avail_t, bmp)) +#define WL_NAN_MCAST_AVAIL_LEN_MAX (WL_NAN_MCAST_AVAIL_LEN_FIXED + 64u) /* arbitrary */ /* ********************* end of NAN section ******************************** */ /* endif WL_NAN */ -#define P2P_NAN_IOC_BUFSZ 512 /* some sufficient ioc buff size */ -#define WL_P2P_NAN_IOCTL_VERSION 0x1 - -/* container for p2p nan iovtls & events */ -typedef struct wl_p2p_nan_ioc { - uint16 version; /* interface command or event version */ - uint16 id; /* p2p nan ioctl cmd ID */ - uint16 len; /* total length of data[] */ - uint16 pad; /* padding */ - uint8 data []; /* var len payload of bcm_xtlv_t type */ -} wl_p2p_nan_ioc_t; - -/* p2p nan cmd IDs */ -enum wl_p2p_nan_cmds { - /* p2p nan cfg ioctls */ - WL_P2P_NAN_CMD_ENABLE = 1, - WL_P2P_NAN_CMD_CONFIG = 2, - WL_P2P_NAN_CMD_DEL_CONFIG = 3, - WL_P2P_NAN_CMD_GET_INSTS = 4 -}; - -#define WL_P2P_NAN_CONFIG_VERSION 1 - -#define WL_P2P_NAN_DEVICE_P2P 0x0 -#define WL_P2P_NAN_DEVICE_GO 0x1 -#define WL_P2P_NAN_DEVICE_GC 0x2 -#define WL_P2P_NAN_DEVICE_INVAL 0xFF - /* NAN P2P operation */ -typedef struct p2p_nan_config { - uint16 version; /* wl_p2p_nan_config_t structure version */ - uint16 len; /* total length including version and variable IE */ - uint32 flags; /* 0x1 to NEW, 0x2 to ADD, 0x4 to DEL */ - uint8 inst_id; /* publisher/subscriber id */ - uint8 inst_type; /* publisher/subscriber */ - uint8 dev_role; /* P2P device role: 'P2P','GO' or 'GC' */ - uint8 pad1; /* padding */ - uint8 resolution; /* Availability bitmap resolution */ - uint8 repeat; /* Whether Availabilty repeat across DW */ - uint16 ie_len; /* variable ie len */ - struct ether_addr dev_mac; /* P2P device addres */ - uint16 pad2; /* Padding */ - uint32 avail_bmap; /* availability interval bitmap */ - uint32 chanspec; /* Chanspec */ - uint8 ie[]; /* hex ie data */ -} wl_p2p_nan_config_t; - -#define WL_P2P_NAN_SERVICE_LIST_VERSION 1 -typedef enum wl_nan_service_type { - WL_NAN_SVC_INST_PUBLISHER = 1, - WL_NAN_SVC_INST_SUBSCRIBER = 2 -} wl_nan_service_type_t; - -#define WL_P2P_NAN_CONFIG_NEW 0x1 -#define WL_P2P_NAN_CONFIG_ADD 0x2 -#define WL_P2P_NAN_CONFIG_DEL 0x4 - -typedef struct wl_nan_svc_inst { - uint8 inst_id; /* publisher/subscriber id */ - uint8 inst_type; /* publisher/subscriber */ -} wl_nan_svc_inst_t; - -typedef struct wl_nan_svc_inst_list { - uint16 version; /* this structure version */ - uint16 len; /* total length including version and variable svc list */ - uint16 count; /* service instance count */ - uint16 pad; /* padding */ - wl_nan_svc_inst_t svc[1]; /* service instance list */ -} wl_nan_svc_inst_list_t; - -#define NAN_POST_DISC_P2P_DATA_VER 1 -/* This structure will be used send peer p2p data with - * NAN discovery result - */ -typedef struct nan_post_disc_p2p_data { - uint8 ver; /* this structure version */ - uint8 dev_role; /* P2P Device role */ - uint8 resolution; /* Availability bitmap resolution */ - uint8 repeat; /* Whether Availabilty repeat across DW */ - struct ether_addr dev_mac; /* P2P device addres */ - uint16 pad1; /* Padding */ - uint32 chanspec; /* Chanspec */ - uint32 avl_bmp; /* availability interval bitmap */ -} nan_post_disc_p2p_data_t; - enum { WL_AVAIL_NONE = 0x0000, WL_AVAIL_LOCAL = 0x0001, @@ -15353,9 +17326,11 @@ enum { WL_AVAIL_UPD_COM_COND = 0x0009, /* modify committed/conditional, keep potential */ WL_AVAIL_REMOVE_MAP = 0x000A, /* remove map */ WL_AVAIL_FRM_TYPE = 0x000B, /* specify frame types containing NA */ - WL_AVAIL_TYPE_MAX = WL_AVAIL_FRM_TYPE /* New ones before and update */ + WL_AVAIL_SUBSLOT = 0x000C, /* Sub slot attribute */ + WL_AVAIL_TYPE_MAX = WL_AVAIL_SUBSLOT /* New ones before and update */ }; #define WL_AVAIL_TYPE_MASK 0x000F +#define WL_AVAIL_FLAG_ALL_MAPS 0x1000 /* All maps */ #define WL_AVAIL_FLAG_REMOVE 0x2000 /* remove schedule attr of given type & map id */ #define WL_AVAIL_FLAG_SELECTED_NDC 0x4000 #define WL_AVAIL_FLAG_RAW_MODE 0x8000 @@ -15376,6 +17351,7 @@ enum { WL_AVAIL_ENTRY_BAND_PRESENT = 0x0100, /* band present */ WL_AVAIL_ENTRY_CHAN_PRESENT = 0x0200, /* channel information present */ WL_AVAIL_ENTRY_CHAN_ENTRY_PRESENT = 0x0400, /* channel entry (opclass+bitmap) */ + WL_AVAIL_ENTRY_SUBSLOT_IMMUTABLE = 0x0800, /* Sub slot is immutable */ /* free to use 0x0800 */ WL_AVAIL_ENTRY_RXNSS = 0xF000 /* max num of spatial stream RX */ }; @@ -15400,7 +17376,7 @@ enum { WL_AVAIL_PERIOD_8192 = 7, /* 8192TU */ }; -/* band */ +/* Band ID values: See Table 99 in NAN R4 spec */ enum { WL_AVAIL_BAND_NONE = 0, /* reserved */ WL_AVAIL_BAND_SUB1G = 1, /* sub-1 GHz */ @@ -15408,6 +17384,8 @@ enum { WL_AVAIL_BAND_3G = 3, /* reserved (for 3.6 GHz) */ WL_AVAIL_BAND_5G = 4, /* 4.9 and 5 GHz */ WL_AVAIL_BAND_60G = 5, /* reserved (for 60 GHz) */ + WL_AVAIL_BAND_45G = 6, /* 45 GHz */ + WL_AVAIL_BAND_6G = 7, /* 6 GHz */ }; #define WL_AVAIL_ENTRY_TYPE_MASK 0x000F @@ -15443,6 +17421,9 @@ enum { #define WL_AVAIL_ENTRY_CHAN_BITMAP_VAL(_info) (((_info) & WL_AVAIL_ENTRY_CHAN_BITMAP_MASK) \ >> WL_AVAIL_ENTRY_CHAN_BITMAP_SHIFT) +/* Max allowed timebitmap bits length: Worst case allowed with 1tu duration for 1024tu period */ +#define NAN_S3_MAX_TMB_LEN (NAN_SLOT_DUR_1024TU / NBBY) + /* Used for raw channel entry field input */ #define MAX_CHAN_ENTRY_LEN 6 @@ -15462,7 +17443,7 @@ typedef struct wl_avail_entry { */ } u; /* band or channel value, 0=all band/channels */ uint8 sched_map_id; /* avail map id associated with sched entry */ - uint8 pad; + uint8 PAD; uint8 period; /* in TUs, defined by WL_AVAIL_PERIOD enum * 1:128, 2:256, 3:512, 4:1024, 5:2048, 6:4096, * 7:8192 @@ -15485,7 +17466,7 @@ typedef struct wl_avail { uint8 id; /* id used for multiple maps/avail */ uint8 lndc_id; /* ndc id used in multi-ndc case */ uint8 version; - uint8 pad; + uint8 PAD; struct ether_addr addr; /* peer mac address or ndc id */ uint8 num_entries; uint8 unused_byte; @@ -15510,10 +17491,10 @@ typedef struct wl_avail_ulw { uint32 chanspec; uint32 band; uint8 chan_entry[MAX_CHAN_ENTRY_LEN]; - uint8 pad[8]; + uint8 PAD[8]; } u; uint8 cntdwn; /* remaining ULWs before schedule ends */ - uint8 pad[3]; + uint8 PAD[3]; } wl_avail_ulw_t; /* unset: NAN is not available during ULW, set: NAN is avail depending on ctrl flags */ @@ -15574,16 +17555,16 @@ typedef uint32 wl_nan_wfa_testmode_t; typedef struct wl_nan_vndr_ie { uint32 flags; /* bitmask indicating which packet(s) contain this IE */ uint16 body_len; /* length of body (does not include oui field) */ - uint8 pad[2]; + uint8 PAD[2]; uint8 oui[DOT11_OUI_LEN]; - uint8 pad2; + uint8 PAD; uint8 body[]; /* vendor IE payload */ } wl_nan_vndr_ie_t; typedef struct wl_nan_vndr_payload { uint32 flags; /* bitmask indicating which packet(s) contain payload */ uint16 payload_len; /* length of payload */ - uint8 pad[2]; + uint8 PAD[2]; uint8 payload[]; /* payload to be appended to NAN frame */ } wl_nan_vndr_payload_t; @@ -15594,7 +17575,7 @@ typedef struct wl_nan_dev_cap { uint8 mapid; /* dev cap mapid */ uint8 all_maps; /* applies to device */ uint8 paging; - uint8 pad[3]; + uint8 PAD[3]; } wl_nan_dev_cap_t; /* arbitrary max len for frame template */ @@ -15602,7 +17583,7 @@ typedef struct wl_nan_dev_cap { typedef struct wl_nan_frm_tplt { wl_nan_frame_type_t type; - uint8 pad; + uint8 PAD; uint16 len; /* length of template */ uint8 data[]; /* template */ } wl_nan_frm_tplt_t; @@ -15711,6 +17692,7 @@ typedef struct wl_proxd_collect_data_v4 { uint16 len; wl_proxd_collect_info_t info; uint8 ri_rr[FTM_TPK_RI_RR_LEN_SECURE_2_0_5G]; + uint8 PAD[2]; /**< raw data read from phy used to adjust timestamps */ uint32 H[K_TOF_COLLECT_H_SIZE_20MHZ]; uint32 chan[4 * K_TOF_COLLECT_CHAN_SIZE]; @@ -15752,7 +17734,7 @@ typedef struct wl_proxd_debug_data { } wl_proxd_debug_data_t; /** version of the wl_wsec_info structure */ -#define WL_WSEC_INFO_VERSION 0x01 +#define WL_WSEC_INFO_VERSION_1 0x01 /** start enum value for BSS properties */ #define WL_WSEC_INFO_BSS_BASE 0x0100 @@ -15784,20 +17766,28 @@ typedef enum { WL_WSEC_INFO_BSS_SAE_PWE = (WL_WSEC_INFO_BSS_BASE + 9), WL_WSEC_INFO_BSS_SAE_PK = (WL_WSEC_INFO_BSS_BASE + 0xA), WL_WSEC_INFO_6G_LEGACY_SEC = (WL_WSEC_INFO_BSS_BASE + 0xB), + WL_WSEC_INFO_BSS_TD_POLICY = (WL_WSEC_INFO_BSS_BASE + 0xC), /* set TD policy */ + WL_WSEC_INFO_SAE_GROUPS = (WL_WSEC_INFO_BSS_BASE + 0xD), + WL_WSEC_INFO_OCV = (WL_WSEC_INFO_BSS_BASE + 0xE), + WL_WSEC_INFO_BSS_KEY_IDLE_TIME = (WL_WSEC_INFO_BSS_BASE + 0xF), + WL_WSEC_INFO_BSS_INCLUDE_RSNXE = (WL_WSEC_INFO_BSS_BASE + 0x10), /**< + Include RSNXE in pure + WPA-PSK mode + */ + /* * ADD NEW ENUM ABOVE HERE */ /* WPA3 CTT testbed specific requirement. refer to WFA CAPI command list */ - WL_WSEC_INFO_TEST_SAE_GROUPS = (WL_WSEC_INFO_TEST_BASE), /* supported SAE groups */ + WL_WSEC_INFO_TEST_UNUSED = (WL_WSEC_INFO_TEST_BASE), /* reserved for future use */ WL_WSEC_INFO_TEST_SAE_GROUP_REJ = (WL_WSEC_INFO_TEST_BASE + 1), /* rejected group ID */ WL_WSEC_INFO_TEST_SAE_INVALID_VEC = (WL_WSEC_INFO_TEST_BASE + 2), /* test SAE vector */ WL_WSEC_INFO_TEST_PMK = (WL_WSEC_INFO_TEST_BASE + 3), /* query PMK */ - WL_WSEC_INFO_OCV = (WL_WSEC_INFO_TEST_BASE + 4), /* OCV enable/disable */ + WL_WSEC_INFO_TEST_UNUSED1 = (WL_WSEC_INFO_TEST_BASE + 4), /* reserved for future */ WL_WSEC_INFO_TEST_INVALID_OCI = (WL_WSEC_INFO_TEST_BASE + 5), /* OCV invalid OCI */ WL_WSEC_INFO_TEST_PMKSA_CACHE = (WL_WSEC_INFO_TEST_BASE + 6), /* PMKSA cache on/off */ WL_WSEC_INFO_TEST_IGNORE_CSA = (WL_WSEC_INFO_TEST_BASE + 7), /* Ignore CSA */ WL_WSEC_INFO_TEST_IGNORE_ASSOCRESP = (WL_WSEC_INFO_TEST_BASE + 8), /* Ignore reassoc_resp */ - WL_WSEC_INFO_TEST_TD_POLICY = (WL_WSEC_INFO_TEST_BASE + 9), /* set TD policy */ WL_WSEC_INFO_TEST_DISASSOC_MFP_TMO = (WL_WSEC_INFO_TEST_BASE + 0xA), /* sending disassoc frame when MFP query timed out */ @@ -15823,6 +17813,13 @@ struct bcm_xlo { }; typedef struct bcm_xlo bcm_xlo_t; +/* Supported operations (actions) for PMK info */ + +/* Add passphrase/pmk entry with the info provided..this is default behaviour */ +#define WL_WSEC_PMK_INFO_ADD 0x0u +/* Search passphrase entry with info provided and delete it */ +#define WL_WSEC_PMK_INFO_DEL 0x1u + /* ** all offsets are from the beginning of the structure that starts ** with the version field and length field is the total length of the structure @@ -15835,7 +17832,8 @@ typedef struct wl_wsec_info_pmk_info { wl_wsec_info_pmk_info_flags_t flags; /* Fill in the input based on the flags */ wl_wsec_info_pmk_lifetime_t pmk_lifetime; wl_wsec_info_akm_mask_t akm_mask; /* RSN authenticated key management suite */ - uint8 rsvd[3]; /* reserved for future use */ + uint8 action; /* add/del */ + uint8 rsvd[2]; /* reserved for future use */ bcm_xlo_t ssid; /* ssid - key, zero length is allowed for SSID */ bcm_xlo_t bssid; /* bssid - key, zero length = broadcast/wildcard */ bcm_xlo_t pass_id; /* key - optional password id for SAE */ @@ -15859,21 +17857,43 @@ typedef struct { /** input/output data type for wsec_info iovar */ typedef struct wl_wsec_info { uint8 version; /**< structure version */ - uint8 pad[2]; + uint8 PAD[2]; uint8 num_tlvs; - wl_wsec_info_tlv_t tlvs[1]; /**< tlv data follows */ + wl_wsec_info_tlv_t tlvs[BCM_FLEX_ARRAY]; /**< tlv data follows */ } wl_wsec_info_t; -#define AP_BLOCK_NONE 0x0000 /* default: No restriction */ -#define AP_ALLOW_WPA2 0x0001 /* allow WPA2PSK AP */ -#define AP_ALLOW_TSN 0x0002 /* WPA3 transition AP */ -#define AP_ALLOW_WPA3_ONLY 0x0004 /* WPA3 only AP */ + +#define AP_BLOCK_NONE 0x00000000u /* No restriction (default) */ +/* Policy when WPA3/SAE is configured for the BSS */ +#define AP_ALLOW_WPA2 0x00000001u /* Allow WPA2PSK AP during join or roam */ +#define AP_ALLOW_TSN 0x00000002u /* Allow WPA3 transition AP during join or roam */ +#define AP_ALLOW_WPA3_ONLY 0x00000004u /* Allow WPA3 only AP during join or roam */ +/* AP_ALLOW_WPA3_ONLY is write only +** supports AP_ALLOW_WPA3_2G_5G_ONLY and AP_ALLOW_WPA3_6G_ONLY +** DEPRECATED moving forward +*/ +/* Policy when WPA2 PSK, but not SAE is configured for the BSS */ +#define AP_WPA2_PSK_NO_MIX_SEC 0x00000008u /* Disallow Mixed WPA/WPA2 security during roam */ + +#define AP_ALLOW_WPA3_2G_5G_ONLY 0x00000010u /* Allow WPA3 only 2G/5G AP join or roam */ +#define AP_ALLOW_WPA3_6G_ONLY 0x00000020u /* Allow WPA3 only 6G AP during join or roam */ +/* All flags */ #define AP_ALLOW_MAX (AP_ALLOW_WPA2 | AP_ALLOW_TSN | \ - AP_ALLOW_WPA3_ONLY) + AP_ALLOW_WPA3_ONLY | AP_WPA2_PSK_NO_MIX_SEC) /* DEPRECATED moving forward */ +/* AP_ALLOW_MAX will be defined in the src component */ + +/* OWE roaming policy bit definitions */ + +#define AP_ALLOW_OPEN_ONLY 0x00010000u /* Allow roam to open APs (2G and 5G) */ +#define AP_ALLOW_OWE_TRANS_2G_5G 0x00020000u /* Allow roam to owe transition n/w */ +#define AP_ALLOW_OWE_ONLY_IN_2G_5G 0x00040000u /* Allow roam to owe only APs in 2G or 5G */ +#define AP_ALLOW_OWE_ONLY_IN_6G 0x00080000u /* Allow roam to owe only APs in 6g only */ + typedef struct { uint32 wpa_ap_restrict; /* set WPA2 / WPA3 AP restriction policy */ } wl_wsec_info_wpa_ap_restrict_t; /* SAE PWE derivation method */ +#define SAE_PWE_INVALID 0x0u #define SAE_PWE_LOOP 0x1u #define SAE_PWE_H2E 0x2u @@ -15920,7 +17940,7 @@ typedef struct wl_randmac { /* randmac version subcommand */ typedef struct wl_randmac_version { uint16 version; /* Randmac method version info */ - uint8 pad[2]; /* Align on 4 byte boundary */ + uint8 PAD[2]; /* Align on 4 byte boundary */ } wl_randmac_version_t; /* @@ -16000,12 +18020,12 @@ typedef struct wl_randmac_tlv { /** randmac event */ typedef struct wl_randmac_event { - uint16 version; - uint16 len; /* Length of all variables */ - wl_randmac_event_type_t type; - wl_randmac_method_t method; - uint8 pad[2]; - wl_randmac_tlv_t tlvs[1]; /**< variable */ + uint16 version; + uint16 len; /* Length of all variables */ + wl_randmac_event_type_t type; + wl_randmac_method_t method; + uint8 PAD[2]; + wl_randmac_tlv_t tlvs[BCM_FLEX_ARRAY]; /**< variable */ } wl_randmac_event_t; /* @@ -16028,7 +18048,7 @@ typedef struct wl_scanmac { /** scanmac enable data struct */ typedef struct wl_scanmac_enable { uint8 enable; /**< 1 - enable, 0 - disable */ - uint8 pad[3]; /**< 4-byte struct alignment */ + uint8 PAD[3]; /**< 4-byte struct alignment */ } wl_scanmac_enable_t; /** scanmac bsscfg data struct */ @@ -16041,7 +18061,7 @@ typedef struct wl_scanmac_config { struct ether_addr mac; /**< 6 bytes of MAC address or MAC prefix (i.e. OUI) */ struct ether_addr random_mask; /**< randomized bits on each scan */ uint16 scan_bitmap; /**< scans to use this MAC address */ - uint8 pad[2]; /**< 4-byte struct alignment */ + uint8 PAD[2]; /**< 4-byte struct alignment */ } wl_scanmac_config_t; /** scanmac mac addr data struct */ @@ -16078,24 +18098,16 @@ typedef struct scan_event_data { typedef struct scan_chan_tlv { uint16 type; /* slice index */ uint16 len; /* data length */ - uint8 data[1]; /* chanspec list */ + uint8 data[BCM_FLEX_ARRAY]; /* chanspec list */ } scan_chan_tlv_t; typedef struct scan_event_data_v2 { uint32 version; uint32 flags; uint32 num_tlvs; /* no of chanspec list tlvs */ - scan_chan_tlv_t tlvs[1]; + uint8 tlvs[BCM_FLEX_ARRAY]; } scan_event_data_v2_t; - -#ifdef WL_SCAN_EVENT_V2 -typedef scan_event_data_v2_t scan_event_data_t; -#define WL_SCAN_EVENT_FIXED_LEN_V2 OFFSETOF(scan_event_data_t, tlvs) -#define WL_SCAN_EVENT_VERSION WL_SCAN_EVENT_VER2 -#else -#define WL_SCAN_EVENT_VERSION WL_SCAN_EVENT_VER1 -typedef scan_event_data_v1_t scan_event_data_t; -#endif +#define WL_SCAN_EVENT_FIXED_LEN_V2 OFFSETOF(scan_event_data_v2_t, tlvs) /* * bonjour dongle offload definitions @@ -16128,7 +18140,7 @@ typedef struct wl_bdo_download { uint16 total_size; /* total database size */ uint16 frag_num; /* fragment number, 0 for first fragment, N-1 for last fragment */ uint16 frag_size; /* size of fragment (max BDO_MAX_FRAGMENT_SIZE) */ - uint8 pad[2]; /* 4-byte struct alignment */ + uint8 PAD[2]; /* 4-byte struct alignment */ uint8 fragment[BDO_MAX_FRAGMENT_SIZE]; /* fragment data */ } wl_bdo_download_t; @@ -16138,7 +18150,7 @@ typedef struct wl_bdo_download { */ typedef struct wl_bdo_enable { uint8 enable; /* 1 - enable, 0 - disable */ - uint8 pad[3]; /* 4-byte struct alignment */ + uint8 PAD[3]; /* 4-byte struct alignment */ } wl_bdo_enable_t; /* @@ -16146,7 +18158,7 @@ typedef struct wl_bdo_enable { */ typedef struct wl_bdo_max_download { uint16 size; /* Max download size in bytes */ - uint8 pad[2]; /* 4-byte struct alignment */ + uint8 PAD[2]; /* 4-byte struct alignment */ } wl_bdo_max_download_t; /* @@ -16170,7 +18182,7 @@ typedef struct wl_tko { /* WL_TKO_SUBCMD_MAX_CONNECT subcommand data */ typedef struct wl_tko_max_tcp { uint8 max; /* max TCP connections supported */ - uint8 pad[3]; /* 4-byte struct alignment */ + uint8 PAD[3]; /* 4-byte struct alignment */ } wl_tko_max_tcp_t; /* WL_TKO_SUBCMD_PARAM subcommand data */ @@ -16178,7 +18190,7 @@ typedef struct wl_tko_param { uint16 interval; /* keepalive tx interval (secs) */ uint16 retry_interval; /* keepalive retry interval (secs) */ uint16 retry_count; /* retry_count */ - uint8 pad[2]; /* 4-byte struct alignment */ + uint8 PAD[2]; /* 4-byte struct alignment */ } wl_tko_param_t; /* WL_TKO_SUBCMD_CONNECT subcommand data @@ -16212,12 +18224,12 @@ typedef struct wl_tko_connect { /* WL_TKO_SUBCMD_CONNECT subcommand data to GET configured info for specific index */ typedef struct wl_tko_get_connect { uint8 index; /* TCP connection index, 0 to max-1 */ - uint8 pad[3]; /* 4-byte struct alignment */ + uint8 PAD[3]; /* 4-byte struct alignment */ } wl_tko_get_connect_t; typedef struct wl_tko_enable { uint8 enable; /* 1 - enable, 0 - disable */ - uint8 pad[3]; /* 4-byte struct alignment */ + uint8 PAD[3]; /* 4-byte struct alignment */ } wl_tko_enable_t; /* WL_TKO_SUBCMD_STATUS subcommand data */ @@ -16226,7 +18238,7 @@ typedef struct wl_tko_status { uint8 count; /* number of status entries (i.e. equals * max TCP connections supported) */ - uint8 status[1]; /* variable length field contain status for + uint8 status[BCM_FLEX_ARRAY]; /* variable length field contain status for * each TCP connection index */ } wl_tko_status_t; @@ -16470,7 +18482,7 @@ typedef struct civicreq { uint8 subj; /* Local/Remote/Thid party */ uint8 civloc_type; /* Format of location info */ uint8 siu; /* Unit of Location service interval */ - uint8 pad; + uint8 PAD; uint16 si; /* Location service interval */ } civicreq_t; @@ -16486,8 +18498,8 @@ typedef struct wl_rrm_config_ioc { uint16 version; /* command version */ uint16 id; /* subiovar cmd ID */ uint16 len; /* total length of all bytes in data[] */ - uint16 pad; /* 4-byte boundary padding */ - uint8 data[1]; /* payload */ + uint16 PAD; /* 4-byte boundary padding */ + uint8 data[BCM_FLEX_ARRAY]; /* payload */ } wl_rrm_config_ioc_t; enum { @@ -16518,7 +18530,7 @@ typedef struct frngreq_target { uint8 channel; uint8 phytype; uint8 reg; - uint8 pad; + uint8 PAD; struct ether_addr bssid; chanspec_t chanspec; uint32 sid; @@ -16532,24 +18544,24 @@ typedef struct frngreq { uint8 num_aps; /* Number of APs to range, at least min_ap_count */ uint16 max_age; /* Max elapsed time before FTM request, 0xFFFF = any */ uint16 reps; /* Number of repetitions of this measurement type */ - frngreq_target_t targets[1]; /* Target BSSIDs to range */ + frngreq_target_t targets[BCM_FLEX_ARRAY]; /* Target BSSIDs to range */ } frngreq_t; typedef struct frngrep_range { uint32 start_tsf; /* 4 lsb of tsf */ struct ether_addr bssid; - uint8 pad[2]; + uint8 PAD[2]; uint32 range; uint32 max_err; uint8 rsvd; - uint8 pad2[3]; + uint8 PAD[3]; } frngrep_range_t; typedef struct frngrep_error { uint32 start_tsf; /* 4 lsb of tsf */ struct ether_addr bssid; uint8 code; - uint8 pad[1]; + uint8 PAD[1]; } frngrep_error_t; typedef struct frngrep { @@ -16566,7 +18578,7 @@ typedef struct wl_rrm_frng_ioc { uint16 version; /* command version */ uint16 id; /* subiovar cmd ID */ uint16 len; /* total length of all bytes in data[] */ - uint16 pad; /* 4-byte boundary padding */ + uint16 PAD; /* 4-byte boundary padding */ uint8 data[]; /* payload */ } wl_rrm_frng_ioc_t; @@ -16613,7 +18625,7 @@ typedef struct wl_el_tag_params_s { uint8 flags; } wl_el_tag_params_t; -#define EVENT_LOG_SET_TYPE_CURRENT_VERSION 0 +#define EVENT_LOG_SET_TYPE_VERSION_0 0u typedef struct wl_el_set_type_s { uint16 version; uint16 len; @@ -16622,7 +18634,7 @@ typedef struct wl_el_set_type_s { uint16 PAD; } wl_el_set_type_t; -#define EVENT_LOG_SET_TYPE_ALL_V1 1 +#define EVENT_LOG_SET_TYPE_ALL_V1 1u typedef struct wl_el_set_type_s_v1 { uint8 set_val; @@ -16633,7 +18645,7 @@ typedef struct wl_el_set_all_type_s_v1 { uint16 version; uint16 len; uint32 max_sets; - wl_el_set_type_v1_t set_type[1]; /* set-Type Values Array */ + wl_el_set_type_v1_t set_type[BCM_FLEX_ARRAY]; /* set-Type Values Array */ } wl_el_set_all_type_v1_t; typedef struct wl_staprio_cfg { @@ -16661,7 +18673,7 @@ typedef struct wlc_stamon_sta_config { struct ether_addr ea; uint16 version; /* Command structure version */ uint16 length; /* Command structure length */ - uint8 pad[2]; + uint8 PAD[2]; /* Time (ms) for which STA's are monitored. Value ZERO indicates no time limit */ uint32 monitor_time; } wlc_stamon_sta_config_t; @@ -16701,7 +18713,7 @@ typedef struct wlc_bcn_len_hist { uint32 max_bcnlen; /**< Max beacon length received */ uint32 min_bcnlen; /**< Min beacon length received */ uint32 ringbuff_len; /**< Length of the ring buffer 'bcnlen_ring' */ - uint32 bcnlen_ring[1]; /**< ring buffer storing received beacon lengths */ + uint32 bcnlen_ring[BCM_FLEX_ARRAY]; /**< ring buffer storing received beacon lengths */ } wlc_bcn_len_hist_t; /* WDS net interface types */ @@ -16785,7 +18797,40 @@ typedef enum wl_gpaio_option { GPAIO_LPBK_OUT, GPAIO_ADC_LPBK_INN, GPAIO_ADC_LPBK_INP, - GPAIO_ETSSI + GPAIO_ETSSI, + GPAIO_PAD5G_GM_BIAS_V, + GPAIO_PAD5G_GM_DRAIN_V, + GPAIO_PAD5G_CAS_BIAS_V, + GPAIO_PMU_LDO1P8, + GPAIO_RX_GM_VDD, + GPAIO_RX_TIA_FINAL_CM_V, + GPAIO_RX_TIA_FINAL_CM_V1, + GPAIO_RX_TIA_FINAL_CM_V2, + GPAIO_PA5G_GM_BIAS_V, + GPAIO_PA5G_GM_DRAIN_V, + GPAIO_PA5G_CAS_BIAS_V, + GPAIO_PMU_LOGENLDO1, + GPAIO_PMU_RX5G_RF_LDO, + GPAIO_PMU_LPF_LDO, + GPAIO_VCO_LDO_TX, + GPAIO_VCO_LDO_RX, + GPAIO_RX_PD_LDO, + GPAIO_RX_MMD_LDO, + GPAIO_DTX_DIG_LDO, + GPAIO_DTX_RF_LDO, + GPAIO_RX_LDO_LOGIC, + GPAIO_RX_LDO_BB, + GPAIO_PMU_PLL_VCO_LDO, + GPAIO_PMU_PLL_RO_LDO, + GPAIO_PMU_BTVCO_LDO, + GPAIO_PMU_BTPLL_LDO, + GPAIO_PMU_PLLMMD_LDO, + GPAIO_PMU_BBLDO, + GPAIO_PMU_IF_LDO, + GPAIO_AFEDIV_LDO_OUT, + GPAIO_WBADC_REF_LDO_OUT, + GPAIO_DTX_RF_LDO_BYPASS, + RETRIGGER_MINIPMUCAL } wl_gpaio_option_t; /** IO Var Operations - the Value of iov_op In wlc_ap_doiovar */ @@ -16860,6 +18905,26 @@ typedef struct { uint16 combo[16]; /* mws ant selection 2nd */ } mws_ant_map_t_2nd; +#define LTECX_MWS_ANTMAP_VERSION_V3 3u + +/** flags indicating changed field */ +enum { + WL_MWS_ANT_MAP_2G = 1, /* 2g filed updated */ + WL_MWS_ANT_MAP_5G = 2, /* 5g filed updated */ + WL_MWS_ANT_MAP_6G = 3 /* 6g filed updated */ +}; + +/* MWS ANT map 3rd generation */ +typedef struct { + uint16 version; /* Structure version */ + uint16 length; /* Length of whole struct */ + uint16 band; /* 2G/5G/6G */ + uint16 combo_2g[16]; /* mws ant selection 2g */ + uint16 combo_5g[16]; /* mws ant selection 5g */ + uint16 combo_6g[16]; /* mws ant selection 6g */ + uint8 PAD[2]; /* Padding for 4byte alignment */ +} mws_ant_map_v3_t; + /* MWS Coex bitmap v2 map for Type0/Type6 */ typedef struct { uint16 bitmap_2G; /* 2G Bitmap */ @@ -16868,6 +18933,77 @@ typedef struct { uint16 bitmap_5G_hi; /* 5G hi bitmap */ } mws_coex_bitmap_v2_t; +/* MWS Coex bitmap v3 map for LTECX features */ + +#define LTECX_COEX_BITMAP_VERSION_V3 3u + +/** flags indicating changed field */ +enum { + WL_MWS_COEX_BITMAP_2G = (1 << 0), /* 2g filed updated */ + WL_MWS_COEX_BITMAP_5G = (1 << 1), /* 5g filed updated */ + WL_MWS_COEX_BITMAP_6G = (1 << 2) /* 6g filed updated */ +}; + +typedef struct { + uint16 version; /* Structure version */ + uint16 length; /* Length of whole struct */ + uint8 flags; /* Flags to indicate the updated field */ + uint8 PAD; + uint16 bitmap_2G; /* 2G Bitmap */ + uint16 bitmap_5G_lo; /* 5G lo bitmap */ + uint16 bitmap_5G_mid; /* 5G mid bitmap */ + uint16 bitmap_5G_hi; /* 5G hi bitmap */ + uint16 bitmap_6G_lo_unii5; /* 6G lo bitmap UNII5 */ + uint16 bitmap_6G_hi_unii5; /* 6G hi bitmap UNII5 */ + uint16 bitmap_6G_unii6; /* 6G UNII6 bitmap */ + uint16 bitmap_6G_unii7; /* 6G UNII7 bitmap */ + uint16 bitmap_6G_unii8; /* 6G UNII8 bitmap */ +} mws_coex_bitmap_v3_t; + +/* MWS OCL bitmap v2 map for LTECX features */ +/* v2 map is for 4388 and future chips */ +/* to cover 6g Channels */ +/* The first generation map is defined */ +/* by wl_mws_ocl_override_t */ +/* Not a ltecoex sub commands */ + +#define LTECX_OCL_BITMAP_VERSION_V2 2u + +/** flags indicating changed field */ +enum { + WL_MWS_OCL_BITMAP_2G = (1 << 0), /* 2g field updated */ + WL_MWS_OCL_BITMAP_5G = (1 << 1), /* 5g field updated */ + WL_MWS_OCL_BITMAP_6G = (1 << 2) /* 6g field updated */ +}; + +typedef struct { + uint16 version; /* Structure version */ + uint16 length; /* Length of whole struct */ + uint8 flags; /* Flags to indicate the updated field */ + uint8 PAD; + uint16 bitmap_2G; /* 2G Bitmap */ + uint16 bitmap_5G_lo; /* 5G lo bitmap */ + uint16 bitmap_5G_mid; /* 5G mid bitmap */ + uint16 bitmap_5G_hi; /* 5G hi bitmap */ + uint16 bitmap_6G_lo_unii5; /* 6G lo bitmap UNII5 */ + uint16 bitmap_6G_hi_unii5; /* 6G hi bitmap UNII5 */ + uint16 bitmap_6G_unii6; /* 6G UNII6 bitmap */ + uint16 bitmap_6G_unii7; /* 6G UNII7 bitmap */ + uint16 bitmap_6G_unii8; /* 6G UNII8 bitmap */ +} mws_ocl_bitmap_t; + +/* To define the ctrl map */ +/* to enable or disable spmi tx message */ +#define LTECX_SPMITX_CTRL_VER 1u + +typedef struct { + uint16 version; /* Structure version */ + uint16 length; /* Length of whole struct */ + uint16 spmimsg_type; /* SPMI MSG type */ + uint16 spmimsg_id; /* SPMI MSG id */ + uint16 spmimsg_dis; /* Disable or enable */ +} mws_spmitx_ctrl_v1_t; + /* MWS SCAN_REQ Bitmap */ typedef struct mws_scanreq_params { uint16 idx; @@ -16877,8 +19013,84 @@ typedef struct mws_scanreq_params { uint16 bm_5g_hi; } mws_scanreq_params_t; +/* MWS BLNK bitmap v2 map for LTECX features */ +/* v2 map is for 4388 and future chips */ +/* to cover all 2g/5g/6g Channels */ +/* The first generation map is defined */ +/* by mws_scanreq_params_t */ +/* Not a ltecoex sub commands */ + +#define LTECX_BLNK_BITMAP_VERSION_V2 2u + +/** flags indicating changed field */ +enum { + WL_MWS_BLNK_BITMAP_2G = (1 << 0), /* 2g field updated */ + WL_MWS_BLNK_BITMAP_5G = (1 << 1), /* 5g field updated */ + WL_MWS_BLNK_BITMAP_6G = (1 << 2) /* 6g field updated */ +}; + +typedef struct { + uint16 version; /* Structure version */ + uint16 length; /* Length of whole struct */ + uint8 flags; /* Flags to indicate the updated field */ + uint8 PAD; + uint16 idx; + uint16 bm_2G; /* 2G Bitmap */ + uint16 bm_5G_lo; /* 5G lo bitmap */ + uint16 bm_5G_mid; /* 5G mid bitmap */ + uint16 bm_5G_hi; /* 5G hi bitmap */ + uint16 bm_6G_lo_unii5; /* 6G lo bitmap UNII5 */ + uint16 bm_6G_hi_unii5; /* 6G hi bitmap UNII5 */ + uint16 bm_6G_unii6; /* 6G UNII6 bitmap */ + uint16 bm_6G_unii7; /* 6G UNII7 bitmap */ + uint16 bm_6G_unii8; /* 6G UNII8 bitmap */ + uint8 PAD1[2]; /* Additional padding for 4byte alignment */ +} mws_blnk_bitmap_t; + +/* Definitions for LTE coex iovar */ +#define WL_LTECX_VERSION_1 1 + +/* LTE coex IOV sub command IDs */ +typedef enum ltecx_cmd_id { + WL_LTECX_CMD_VER = 0, /* LTECX version sub command */ + WL_LTECX_TYPE7_2G_COEX_BITMAP = 1, /* Type7 enable/disable bitmap for 2G */ + WL_LTECX_COEX_BITMAP = 2, /* bitmaps to enable/disable Coex */ + WL_LTECX_OCL_BITMAP = 3, /* bitmaps to enable/disable OCL by ltecoex */ + WL_LTECX_ANT_MAP = 4, /* bitmaps for antenna selection */ + WL_LTECX_SPMITX_CTRL = 5, /* to enable/disable SPMI TX MSG */ + WL_LTECX_TYPE7_BITMAP = 6, /* bitmaps to enable/disable sending type7 */ + WL_LTECX_BLNKREQ_BM = 7 /* to enable/disable blnk req */ +} ltecx_cmd_id_t; + +/* MWS Type7 bitmap for LTECX feature */ +/* v1 bitmap is for 4388 and future chips */ +#define LTECX_TYPE7_BITMAP_VERSION_V1 1u + +/** flags indicating changed field */ +enum { + WL_MWS_TYPE7_BITMAP_2G = (1 << 0), /* 2g field updated */ + WL_MWS_TYPE7_BITMAP_5G = (1 << 1), /* 5g field updated */ + WL_MWS_TYPE7_BITMAP_6G = (1 << 2) /* 6g field updated */ +}; + +typedef struct { + uint16 version; /* Structure version */ + uint16 length; /* Length of whole struct */ + uint8 flags; /* Flags to indicate the updated field */ + uint8 PAD; + uint16 bitmap_2G; /* 2G Bitmap */ + uint16 bitmap_5G_lo; /* 5G lo bitmap */ + uint16 bitmap_5G_mid; /* 5G mid bitmap */ + uint16 bitmap_5G_hi; /* 5G hi bitmap */ + uint16 bitmap_6G_lo_unii5; /* 6G lo bitmap UNII5 */ + uint16 bitmap_6G_hi_unii5; /* 6G hi bitmap UNII5 */ + uint16 bitmap_6G_unii6; /* 6G UNII6 bitmap */ + uint16 bitmap_6G_unii7; /* 6G UNII7 bitmap */ + uint16 bitmap_6G_unii8; /* 6G UNII8 bitmap */ +} mws_type7_bitmap_v1_t; + /* MWS NR Coex Channel map */ -#define WL_MWS_NR_COEXMAP_VERSION 1 +#define WL_MWS_NR_COEXMAP_VERSION_1 1 typedef struct wl_mws_nr_coexmap { uint16 version; /* Structure version */ uint16 bitmap_5g_lo; /* bitmap for 5G low channels by 2: @@ -16907,7 +19119,7 @@ typedef struct { uint16 interval; /* interval between responses to the request */ } shub_req_t; -#define WL_IF_STATS_T_VERSION 1 /**< current version of wl_if_stats structure */ +#define WL_IF_STATS_T_VERSION_1 1 /**< current version of wl_if_stats structure */ /** per interface counters */ typedef struct wl_if_stats { @@ -16942,16 +19154,14 @@ typedef struct wl_if_stats { uint64 txnocts; /* RTS/CTS faled count */ uint64 txretrans; /* Number of frame retransmissions */ -} -wl_if_stats_t; +} wl_if_stats_t; typedef struct wl_band { - uint16 bandtype; /**< WL_BAND_2G, WL_BAND_5G */ - uint16 bandunit; /**< bandstate[] index */ - uint16 phytype; /**< phytype */ + uint16 bandtype; /**< WL_BAND_2G, WL_BAND_5G */ + uint16 bandunit; /**< bandstate[] index */ + uint16 phytype; /**< phytype */ uint16 phyrev; -} -wl_band_t; +} wl_band_t; #define WL_ROAM_STATS_VER_1 (1u) /**< current version of wl_if_stats structure */ @@ -16975,9 +19185,10 @@ typedef struct { uint16 full_roam_scan_cnt; uint16 most_roam_reason; uint16 most_roam_reason_cnt; + uint16 PAD; } wl_roam_stats_v1_t; -#define WL_WLC_VERSION_T_VERSION 1 /**< current version of wlc_version structure */ +#define WL_WLC_VERSION_T_VERSION_1 1 /**< current version of wlc_version structure */ /** wlc interface version */ typedef struct wl_wlc_version { @@ -16994,9 +19205,10 @@ typedef struct wl_wlc_version { uint16 wlc_ver_major; /**< wlc interface major version number */ uint16 wlc_ver_minor; /**< wlc interface minor version number */ } + wl_wlc_version_t; -#define WL_SCAN_VERSION_T_VERSION 1 /**< current version of scan_version structure */ +#define WL_SCAN_VERSION_T_VERSION_1 1 /**< current version of scan_version structure */ /** scan interface version */ typedef struct wl_scan_version { uint16 version; /**< version of the structure */ @@ -17006,20 +19218,16 @@ typedef struct wl_scan_version { uint16 scan_ver_major; /**< scan interface major version number */ } wl_scan_version_t; -/* Highest version of WLC_API_VERSION supported */ -#define WLC_API_VERSION_MAJOR_MAX 8 -#define WLC_API_VERSION_MINOR_MAX 0 - /* begin proxd definitions */ #include -#define WL_PROXD_API_VERSION 0x0300u /**< version 3.0 */ +#define WL_PROXD_API_VERSION_3 0x0300u /**< version 3.0 */ /* proxd version with 11az */ #define WL_PROXD_11AZ_API_VERSION_1 0x0400u /** Minimum supported API version */ -#define WL_PROXD_API_MIN_VERSION 0x0300u +#define WL_PROXD_API_MIN_VERSION_3 0x0300u /** proximity detection methods */ enum { @@ -17032,31 +19240,23 @@ enum { }; typedef int16 wl_proxd_method_t; -/** 11az ftm types */ -enum { - WL_FTM_TYPE_NONE = 0, /* ftm type unspecified */ - WL_FTM_TYPE_MC = 1, /* Legacy MC ftm */ - WL_FTM_TYPE_TB = 2, /* 11az Trigger based */ - WL_FTM_TYPE_NTB = 3, /* 11az Non-trigger based */ - WL_FTM_TYPE_MAX -}; -typedef uint8 wl_ftm_type_t; - /** global and method configuration flags */ enum { WL_PROXD_FLAG_NONE = 0x00000000, - WL_PROXD_FLAG_RX_ENABLED = 0x00000001, /**< respond to requests, per bss */ - WL_PROXD_FLAG_RX_RANGE_REQ = 0x00000002, /**< 11mc range requests enabled */ - WL_PROXD_FLAG_TX_LCI = 0x00000004, /**< tx lci, if known */ - WL_PROXD_FLAG_TX_CIVIC = 0x00000008, /**< tx civic, if known */ - WL_PROXD_FLAG_RX_AUTO_BURST = 0x00000010, /**< auto respond w/o host action */ - WL_PROXD_FLAG_TX_AUTO_BURST = 0x00000020, /**< continue tx w/o host action */ - WL_PROXD_FLAG_AVAIL_PUBLISH = 0x00000040, /**< publish availability */ - WL_PROXD_FLAG_AVAIL_SCHEDULE = 0x00000080, /**< schedule using availability */ + WL_PROXD_FLAG_RX_ENABLED = 0x00000001, /* respond to requests, per bss */ + WL_PROXD_FLAG_RX_RANGE_REQ = 0x00000002, /* 11mc range requests enabled */ + WL_PROXD_FLAG_TX_LCI = 0x00000004, /* tx lci, if known */ + WL_PROXD_FLAG_TX_CIVIC = 0x00000008, /* tx civic, if known */ + WL_PROXD_FLAG_RX_AUTO_BURST = 0x00000010, /* auto respond w/o host action */ + WL_PROXD_FLAG_TX_AUTO_BURST = 0x00000020, /* continue tx w/o host action */ + WL_PROXD_FLAG_AVAIL_PUBLISH = 0x00000040, /* publish availability */ + WL_PROXD_FLAG_AVAIL_SCHEDULE = 0x00000080, /* schedule using availability */ WL_PROXD_FLAG_ASAP_CAPABLE = 0x00000100, /* ASAP capable */ WL_PROXD_FLAG_MBURST_FOLLOWUP = 0x00000200, /* new multi-burst algorithm */ WL_PROXD_FLAG_SECURE = 0x00000400, /* per bsscfg option */ WL_PROXD_FLAG_NO_TSF_SYNC = 0x00000800, /* disable tsf sync */ + WL_PROXD_FLAG_AVB_TS = 0x00001000, /* Force AVB TimeStamping */ + WL_PROXD_FLAG_SIGNED_RTT = 0x00002000, /* Send negative RTT to host */ WL_PROXD_FLAG_ALL = 0xffffffff }; typedef uint32 wl_proxd_flags_t; @@ -17103,98 +19303,6 @@ typedef enum wl_proxd_session_flags { WL_PROXD_SESSION_FLAG_ALL = 0xffffffff } wl_proxd_session_flags_t; -/** session flags for 11AZ */ - -/** session flags */ -#define WL_FTM_SESSION_FLAG_NONE 0x0000000000000000llu /* no flags */ -#define WL_FTM_SESSION_FLAG_INITIATOR 0x0000000000000001llu /* local is initiator */ -#define WL_FTM_SESSION_FLAG_TARGET 0x0000000000000002llu /* local is target */ -#define WL_FTM_SESSION_FLAG_CORE_ROTATE 0x0000000000000004llu /* initiator core rotate */ -#define WL_FTM_SESSION_FLAG_AUTO_BURST 0x0000000000000008llu /* rx_auto_burst */ -#define WL_FTM_SESSION_FLAG_PERSIST 0x0000000000000010llu /* good until cancelled */ -#define WL_FTM_SESSION_FLAG_RTT_DETAIL 0x0000000000000020llu /* rtt detail results */ -#define WL_FTM_SESSION_FLAG_SECURE 0x0000000000000040llu /* session is secure */ -#define WL_FTM_SESSION_FLAG_AOA 0x0000000000000080llu /* AOA along w/ RTT */ -#define WL_FTM_SESSION_FLAG_RX_AUTO_BURST 0x0000000000000100llu /* see flags above */ -#define WL_FTM_SESSION_FLAG_TX_AUTO_BURST 0x0000000000000200llu /* see flags above */ -#define WL_FTM_SESSION_FLAG_NAN_BSS 0x0000000000000400llu /* NAN BSS */ -#define WL_FTM_SESSION_FLAG_ASAP_CAPABLE 0x0000000000000800llu /* ASAP-capable */ -#define WL_FTM_SESSION_FLAG_RANDMAC 0x0000000000001000llu /* use random mac */ -#define WL_FTM_SESSION_FLAG_REPORT_FAILURE 0x0000000000002000llu /* failure to target */ -#define WL_FTM_SESSION_FLAG_INITIATOR_RPT 0x0000000000004000llu /* distance to target */ -#define WL_FTM_SESSION_FLAG_NOCHANSWT 0x0000000000008000llu -#define WL_FTM_SESSION_FLAG_NETRUAL 0x0000000000010000llu /* TODO: remove/reserved */ -#define WL_FTM_SESSION_FLAG_SEQ_EN 0x0000000000020000llu /* Toast */ -#define WL_FTM_SESSION_FLAG_NO_PARAM_OVRD 0x0000000000040000llu /* no override from tgt */ -#define WL_FTM_SESSION_FLAG_ASAP 0x0000000000080000llu /* ASAP session */ -#define WL_FTM_SESSION_FLAG_REQ_LCI 0x0000000000100000llu /* tx LCI req */ -#define WL_FTM_SESSION_FLAG_REQ_CIV 0x0000000000200000llu /* tx civic loc req */ -#define WL_FTM_SESSION_FLAG_PRE_SCAN 0x0000000000400000llu /* pre-scan for asap=1 */ -#define WL_FTM_SESSION_FLAG_AUTO_VHTACK 0x0000000000800000llu /* vhtack based on brcmie */ -#define WL_FTM_SESSION_FLAG_VHTACK 0x0000000001000000llu /* vht ack is in use */ -#define WL_FTM_SESSION_FLAG_BDUR_NOPREF 0x0000000002000000llu /* burst-duration no pref */ -#define WL_FTM_SESSION_FLAG_NUM_FTM_NOPREF 0x0000000004000000llu /* num of FTM: no pref */ -#define WL_FTM_SESSION_FLAG_FTM_SEP_NOPREF 0x0000000008000000llu /* time btw FTM: no pref */ -#define WL_FTM_SESSION_FLAG_NUM_BURST_NOPREF 0x0000000010000000llu /* num of bursts: no pref */ -#define WL_FTM_SESSION_FLAG_BURST_PERIOD_NOPREF 0x0000000020000000llu /* burst period: no pref */ -#define WL_FTM_SESSION_FLAG_MBURST_FOLLOWUP 0x0000000040000000llu /* new mburst algo */ -#define WL_FTM_SESSION_FLAG_MBURST_NODELAY 0x0000000080000000llu /* good until cancelled */ -#define WL_FTM_SESSION_FLAG_FULL_BW 0x0000000100000000llu /* use all bandwidth */ -#define WL_FTM_SESSION_FLAG_R2I_TOA_PHASE_SHIFT 0x0000000200000000llu /* phase shft average toa */ -#define WL_FTM_SESSION_FLAG_I2R_TOA_PHASE_SHIFT 0x0000000400000000llu /* phase shft average toa */ -#define WL_FTM_SESSION_FLAG_I2R_IMMEDIATE_RPT 0x0000000800000000llu /* immediate I2R feedback */ -#define WL_FTM_SESSION_FLAG_R2I_IMMEDIATE_RPT 0x0000001000000000llu /* immediate R2R report */ -#define WL_FTM_SESSION_FLAG_DEV_CLASS_A 0x0000002000000000llu /* class A device */ -#define WL_FTM_SESSION_FLAG_ALL 0xffffffffffffffffllu -typedef uint64 wl_ftm_session_flags_t; -typedef uint64 wl_ftm_session_mask_t; - -/* flags common across mc/ntb/tb. - * Explicit for the ones that are currently used. - * Currently not used ones still reserve their bits in above. - */ -#define FTM_COMMON_CONFIG_MASK \ - (WL_FTM_SESSION_FLAG_INITIATOR \ - | WL_FTM_SESSION_FLAG_INITIATOR_RPT \ - | WL_FTM_SESSION_FLAG_TARGET \ - | WL_FTM_SESSION_FLAG_SECURE \ - | WL_FTM_SESSION_FLAG_CORE_ROTATE \ - | WL_FTM_SESSION_FLAG_RANDMAC \ - | WL_FTM_SESSION_FLAG_RX_AUTO_BURST \ - | WL_FTM_SESSION_FLAG_TX_AUTO_BURST \ - | WL_FTM_SESSION_FLAG_REQ_LCI \ - | WL_FTM_SESSION_FLAG_REQ_CIV \ - | WL_FTM_SESSION_FLAG_RTT_DETAIL \ - | WL_FTM_SESSION_FLAG_NO_PARAM_OVRD \ - | WL_FTM_SESSION_FLAG_AUTO_BURST) - -/* flags relevant to MC sessions */ -#define FTM_MC_CONFIG_MASK \ - (FTM_COMMON_CONFIG_MASK) | \ - (WL_FTM_SESSION_FLAG_AUTO_VHTACK \ - | WL_FTM_SESSION_FLAG_MBURST_NODELAY \ - | WL_FTM_SESSION_FLAG_ASAP_CAPABLE \ - | WL_FTM_SESSION_FLAG_ASAP \ - | WL_FTM_SESSION_FLAG_VHTACK \ - | WL_FTM_SESSION_FLAG_BDUR_NOPREF \ - | WL_FTM_SESSION_FLAG_NUM_FTM_NOPREF \ - | WL_FTM_SESSION_FLAG_FTM_SEP_NOPREF \ - | WL_FTM_SESSION_FLAG_NUM_BURST_NOPREF \ - | WL_FTM_SESSION_FLAG_BURST_PERIOD_NOPREF \ - | WL_FTM_SESSION_FLAG_SEQ_EN \ - | WL_FTM_SESSION_FLAG_MBURST_FOLLOWUP) - -/* flags relevant to NTB sessions */ -#define FTM_NTB_CONFIG_MASK \ - (FTM_COMMON_CONFIG_MASK) | \ - (WL_FTM_SESSION_FLAG_R2I_TOA_PHASE_SHIFT \ - | WL_FTM_SESSION_FLAG_I2R_TOA_PHASE_SHIFT \ - | WL_FTM_SESSION_FLAG_I2R_IMMEDIATE_RPT \ - | WL_FTM_SESSION_FLAG_R2I_IMMEDIATE_RPT) - -/* flages relevant to TB sessions. To be expanded */ -#define FTM_TB_CONFIG_MASK (FTM_NTB_CONFIG_MASK) - /** time units - mc supports up to 0.1ns resolution */ enum { WL_PROXD_TMU_TU = 0, /**< 1024us */ @@ -17207,11 +19315,12 @@ enum { typedef int16 wl_proxd_tmu_t; /** time interval e.g. 10ns */ -typedef struct wl_proxd_intvl { +struct wl_proxd_intvl { uint32 intvl; wl_proxd_tmu_t tmu; uint8 pad[2]; -} wl_proxd_intvl_t; +}; +typedef struct wl_proxd_intvl wl_proxd_intvl_t; /** commands that can apply to proxd, method or a session */ enum { @@ -17237,6 +19346,8 @@ enum { WL_PROXD_CMD_STOP_RANGING = 19, WL_PROXD_CMD_GET_RANGING_INFO = 20, WL_PROXD_CMD_IS_TLV_SUPPORTED = 21, + WL_PROXD_CMD_TEST_MODE = 22, /* for test mode (i.e. WFA CTT) */ + WL_PROXD_CMD_DBG_EVENT_CHECK = 23, /* for debugging */ WL_PROXD_CMD_MAX }; @@ -17268,17 +19379,49 @@ enum { #define WL_PROXD_SID_NAN_START WL_PROXD_SID_EXT_BLK_START(2) #define WL_PROXD_SID_NAN_END WL_PROXD_SID_EXT_BLK_END(WL_PROXD_SID_NAN_START) +/* host block */ +#define WL_PROXD_SID_HOST_START WL_PROXD_SID_EXT_BLK_START(4) +#define WL_PROXD_SID_HOST_END WL_PROXD_SID_EXT_BLK_END(WL_PROXD_SID_HOST_START) + /** maximum number sessions that can be allocated, may be less if tunable */ #define WL_PROXD_MAX_SESSIONS 16 +#ifndef FTM +typedef struct wl_proxd_tlv { + uint16 id; + uint16 len; + uint8 data[1]; +} wl_proxd_tlv_t; + +typedef uint8 wl_proxd_type_t; typedef uint16 wl_proxd_session_id_t; +/** proxd iovar - applies to proxd, method or session */ +typedef struct wl_proxd_iov { + uint16 version; + uint16 len; + wl_proxd_cmd_t cmd; + wl_proxd_method_t method; + wl_proxd_session_id_t sid; + wl_proxd_type_t ftm_type; /* 11az ftm type. valid for PROXD ver >= 0x0400 */ + uint8 PAD[1]; + wl_proxd_tlv_t tlvs[BCM_FLEX_ARRAY]; /**< variable */ +} wl_proxd_iov_t; + +#else /* !FTM */ +typedef wl_ftm_session_id_t wl_proxd_session_id_t; +typedef wl_ftm_tlv_t wl_proxd_tlv_t; +typedef wl_ftm_iov_t wl_proxd_iov_t; +#endif /* FTM */ + /* Use WL_PROXD_E_* errorcodes from this file if BCMUTILS_ERR_CODES not defined */ #ifndef BCMUTILS_ERR_CODES /** status - TBD BCME_ vs proxd status - range reserved for BCME_ */ enum { - WL_PROXD_E_LAST = -1056, + WL_PROXD_E_LAST = -1058, + WL_PROXD_E_PKTFREED = -1058, + WL_PROXD_E_ASSOC_INPROG = -1057, WL_PROXD_E_NOAVAIL = -1056, WL_PROXD_E_EXT_SCHED = -1055, WL_PROXD_E_NOT_BCM = -1054, @@ -17336,7 +19479,7 @@ enum { }; typedef uint32 wl_proxd_phy_error_t; -/** session states */ +/** PROXD session states */ enum { WL_PROXD_SESSION_STATE_NONE = 0, WL_PROXD_SESSION_STATE_CREATED = 1, @@ -17352,18 +19495,6 @@ enum { WL_PROXD_SESSION_STATE_DESTROYING = -1 }; -typedef enum wl_ftm_session_state { - WL_FTM_SESSION_STATE_NONE = 0, - WL_FTM_SESSION_STATE_CREATED = 1, - WL_FTM_SESSION_STATE_CONFIGURED = 2, - WL_FTM_SESSION_STATE_STARTED = 3, - WL_FTM_SESSION_STATE_DELAY = 4, - WL_FTM_SESSION_STATE_USER_WAIT = 5, - WL_FTM_SESSION_STATE_SCHED_WAIT = 6, - WL_FTM_SESSION_STATE_BURST = 7, - WL_FTM_SESSION_STATE_ENDED = 8 -} wl_ftm_session_state_t; - typedef int16 wl_proxd_session_state_t; /** RTT sample flags */ @@ -17375,6 +19506,7 @@ typedef uint8 wl_proxd_rtt_sample_flags_t; typedef int16 wl_proxd_rssi_t; typedef uint16 wl_proxd_snr_t; typedef uint16 wl_proxd_bitflips_t; +typedef uint32 wl_proxd_phy_gd_variance_t; /** result flags */ enum { @@ -17386,6 +19518,7 @@ enum { WL_PROXD_REQUEST_SENT = 0x0010, /* FTM request was sent */ WL_PROXD_REQUEST_ACKED = 0x0020, /* FTM request was acked */ WL_PROXD_LTFSEQ_STARTED = 0x0040, /* LTF sequence started */ + WL_PROXD_RESULT_SIGNED = 0x0080, /* RTT result is negative */ WL_PROXD_RESULT_FLAG_ALL = 0xffff }; typedef int16 wl_proxd_result_flags_t; @@ -17429,8 +19562,8 @@ typedef struct wl_proxd_rtt_result_v1 { uint16 burst_num; /* in a session */ uint16 num_rtt; /* 0 if no detail */ uint16 num_meas; /* number of ftm frames seen OTA */ - uint8 pad[2]; - wl_proxd_rtt_sample_v1_t rtt[1]; /* variable */ + uint8 pad[2]; + wl_proxd_rtt_sample_v1_t rtt[BCM_FLEX_ARRAY]; /* variable */ } wl_proxd_rtt_result_v1_t; #define WL_PROXD_RTT_SAMPLE_VERSION_2 2 @@ -17476,10 +19609,58 @@ typedef struct wl_proxd_rtt_result_v2 { uint16 burst_num; /* in a session */ uint16 num_rtt; /* 0 if no detail */ uint16 num_meas; /* number of ftm frames seen OTA */ - uint8 pad[2]; - wl_proxd_rtt_sample_v2_t rtt[1]; /* variable, first element is avg_rtt */ + uint8 pad[2]; + wl_proxd_rtt_sample_v2_t rtt[BCM_FLEX_ARRAY]; /* variable len: first is avg_rtt */ } wl_proxd_rtt_result_v2_t; +#define WL_PROXD_RTT_SAMPLE_VERSION_3 3 +typedef struct wl_proxd_rtt_sample_v3 { + uint16 version; + uint16 length; + uint8 id; /**< id for the sample - non-zero */ + wl_proxd_rtt_sample_flags_t flags; + wl_proxd_rssi_t rssi; + wl_proxd_intvl_t rtt; /**< round trip time */ + uint32 ratespec; + wl_proxd_snr_t snr; + wl_proxd_bitflips_t bitflips; + wl_proxd_status_t status; + int32 distance; + wl_proxd_phy_error_t tof_phy_error; + wl_proxd_phy_error_t tof_tgt_phy_error; /* target phy error bit map */ + wl_proxd_snr_t tof_tgt_snr; + wl_proxd_bitflips_t tof_tgt_bitflips; + uint8 coreid; + uint8 pad[3]; + uint32 chanspec; + uint32 gd_variance; /* group delay variance */ +} wl_proxd_rtt_sample_v3_t; + +#define WL_PROXD_RTT_RESULT_VERSION_3 3 +/** rtt measurement result */ +typedef struct wl_proxd_rtt_result_v3 { + uint16 version; + uint16 length; /* up to rtt[] */ + wl_proxd_session_id_t sid; + wl_proxd_result_flags_t flags; + wl_proxd_status_t status; + struct ether_addr peer; + wl_proxd_session_state_t state; /**< current state */ + union { + wl_proxd_intvl_t retry_after; /* hint for errors */ + wl_proxd_intvl_t burst_duration; /* burst duration */ + } u; + uint32 avg_dist; /* 1/256m units */ + uint16 sd_rtt; /* RTT standard deviation */ + uint8 num_valid_rtt; /* valid rtt cnt */ + uint8 num_ftm; /* actual num of ftm cnt (Configured) */ + uint16 burst_num; /* in a session */ + uint16 num_rtt; /* 0 if no detail */ + uint16 num_meas; /* number of ftm frames seen OTA */ + uint8 pad[2]; + wl_proxd_rtt_sample_v3_t rtt[]; /* variable len: first is avg_rtt */ +} wl_proxd_rtt_result_v3_t; + /** aoa measurement result */ typedef struct wl_proxd_aoa_result { wl_proxd_session_id_t sid; @@ -17488,7 +19669,7 @@ typedef struct wl_proxd_aoa_result { struct ether_addr peer; wl_proxd_session_state_t state; uint16 burst_num; - uint8 pad[2]; + uint8 PAD[2]; /* wl_proxd_aoa_sample_t sample_avg; TBD */ } BWL_POST_PACKED_STRUCT wl_proxd_aoa_result_t; #include @@ -17520,14 +19701,14 @@ typedef struct wl_proxd_counters { uint32 off_chan; /* count of scheduler offchan */ uint32 tsf_lo; /* local tsf or session tsf */ uint32 tsf_hi; - uint32 num_meas; + uint32 num_meas; /* number of measurements */ } wl_proxd_counters_t; - typedef struct wl_proxd_counters wl_proxd_session_counters_t; +typedef struct wl_proxd_counters wl_ftm_counters_v1_t; enum { - WL_PROXD_CAP_NONE = 0x0000, - WL_PROXD_CAP_ALL = 0xffff + WL_PROXD_CAP_NONE = 0x0000, + WL_PROXD_CAP_ALL = 0xffff }; typedef int16 wl_proxd_caps_t; @@ -17540,12 +19721,12 @@ typedef uint16 wl_proxd_ftm_caps_t; typedef struct wl_proxd_tlv_id_list { uint16 num_ids; - uint16 ids[1]; + uint16 ids[BCM_FLEX_ARRAY]; } wl_proxd_tlv_id_list_t; typedef struct wl_proxd_session_id_list { uint16 num_ids; - wl_proxd_session_id_t ids[1]; + wl_proxd_session_id_t ids[BCM_FLEX_ARRAY]; } wl_proxd_session_id_list_t; typedef struct wl_proxd_tpk { @@ -17604,16 +19785,16 @@ typedef struct wl_proxd_ftm_session_status { /** rrm range request */ typedef struct wl_proxd_range_req { - uint16 num_repeat; + uint16 num_repeat; uint16 init_delay_range; /**< in TUs */ - uint8 pad; + uint8 PAD; uint8 num_nbr; /**< number of (possible) neighbors */ - nbr_element_t nbr[1]; + nbr_element_t nbr[BCM_FLEX_ARRAY]; } wl_proxd_range_req_t; -#define WL_PROXD_LCI_LAT_OFF 0 -#define WL_PROXD_LCI_LONG_OFF 5 -#define WL_PROXD_LCI_ALT_OFF 10 +#define WL_PROXD_LCI_LAT_OFF 0 +#define WL_PROXD_LCI_LONG_OFF 5 +#define WL_PROXD_LCI_ALT_OFF 10 #define WL_PROXD_LCI_GET_LAT(_lci, _lat, _lat_err) { \ unsigned _off = WL_PROXD_LCI_LAT_OFF; \ @@ -17683,8 +19864,8 @@ typedef struct wl_proxd_avail24 { uint16 max_slots; /**< for query only */ uint16 num_slots; wl_proxd_time_slot_t slots[1]; /**< ROM compat - not used */ - wl_proxd_intvl_t repeat; - wl_proxd_time_slot_t ts0[1]; + wl_proxd_intvl_t repeat; + wl_proxd_time_slot_t ts0[BCM_FLEX_ARRAY]; } wl_proxd_avail24_t; #define WL_PROXD_AVAIL24_TIMESLOT(_avail24, _i) (&(_avail24)->ts0[(_i)]) #define WL_PROXD_AVAIL24_TIMESLOT_OFFSET(_avail24) OFFSETOF(wl_proxd_avail24_t, ts0) @@ -17698,8 +19879,8 @@ typedef struct wl_proxd_avail { wl_proxd_time_ref_t time_ref; uint16 max_slots; /**< for query only */ uint16 num_slots; - wl_proxd_intvl_t repeat; - wl_proxd_time_slot_t slots[1]; + wl_proxd_intvl_t repeat; + wl_proxd_time_slot_t slots[BCM_FLEX_ARRAY]; } wl_proxd_avail_t; #define WL_PROXD_AVAIL_TIMESLOT(_avail, _i) (&(_avail)->slots[(_i)]) #define WL_PROXD_AVAIL_TIMESLOT_OFFSET(_avail) OFFSETOF(wl_proxd_avail_t, slots) @@ -17724,6 +19905,10 @@ enum { WL_PROXD_DEBUG_NAN = 0x00000080, WL_PROXD_DEBUG_PKT = 0x00000100, WL_PROXD_DEBUG_SEC = 0x00000200, + WL_PROXD_DEBUG_FSM = 0x00000400, /* BCM FSM log for FTM session */ + WL_PROXD_DEBUG_CSI = 0x00000800, /* Enable CSI logging */ + WL_PROXD_DEBUG_AZ_MEAS = 0x00001000, /* AZ measurement substate */ + WL_PROXD_DEBUG_PM = 0x00002000, WL_PROXD_DEBUG_EVENTLOG = 0x80000000, /* map/enable EVNET_LOG_TAG_PROXD_INFO */ WL_PROXD_DEBUG_ALL = 0xffffffff }; @@ -17771,10 +19956,25 @@ typedef enum { WL_PROXD_TLV_ID_RI_RR = 36, /* RI_RR */ WL_PROXD_TLV_ID_TUNE = 37, /* wl_proxd_pararms_tof_tune_t */ WL_PROXD_TLV_ID_CUR_ETHER_ADDR = 38, /* Source Address used for Tx */ + WL_PROXD_TLV_ID_RESERVED_ID39 = 39, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID40 = 40, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID41 = 41, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID42 = 42, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID43 = 43, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID44 = 44, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID45 = 45, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID46 = 46, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID47 = 47, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID48 = 48, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID49 = 49, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID50 = 50, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID51 = 51, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID52 = 52, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID53 = 53, /* ftm component only */ /* output - 512 + x */ WL_PROXD_TLV_ID_STATUS = 512, - WL_PROXD_TLV_ID_COUNTERS = 513, + WL_PROXD_TLV_ID_COUNTERS = 513, /* wl_proxd_counters_t */ WL_PROXD_TLV_ID_INFO = 514, WL_PROXD_TLV_ID_RTT_RESULT = 515, WL_PROXD_TLV_ID_AOA_RESULT = 516, @@ -17782,6 +19982,12 @@ typedef enum { WL_PROXD_TLV_ID_SESSION_STATUS = 518, WL_PROXD_TLV_ID_SESSION_ID_LIST = 519, WL_PROXD_TLV_ID_RTT_RESULT_V2 = 520, + WL_PROXD_TLV_ID_RTT_RESULT_V3 = 521, + WL_PROXD_TLV_ID_RESERVED_ID522 = 522, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID523 = 523, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID524 = 524, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID525 = 525, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID526 = 526, /* ftm component only */ /* debug tlvs can be added starting 1024 */ WL_PROXD_TLV_ID_DEBUG_MASK = 1024, @@ -17798,6 +20004,11 @@ typedef enum { WL_PROXD_TLV_ID_COLLECT_INLINE_FRAME_INFO = 1033, WL_PROXD_TLV_ID_COLLECT_INLINE_FRAME_DATA = 1034, WL_PROXD_TLV_ID_COLLECT_INLINE_RESULTS = 1035, + WL_PROXD_TLV_ID_RESERVED_ID1036 = 1036, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID1037 = 1037, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID1038 = 1038, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID1039 = 1039, /* ftm component only */ + WL_PROXD_TLV_ID_RESERVED_ID1040 = 1040, /* ftm component only */ WL_PROXD_TLV_ID_MAX } wl_proxd_tlv_types_t; @@ -17807,7 +20018,7 @@ typedef enum { typedef struct wl_proxd_collect_inline_header_info_v1 { uint16 version; - uint16 pad1; + uint16 PAD; uint32 ratespec; /* override */ chanspec_t chanspec; uint16 num_ftm; @@ -17839,7 +20050,7 @@ typedef struct wl_proxd_collect_inline_frame_info_v1 uint32 prev_t4; int32 hadj; int8 rssi; - uint8 pad[3]; + uint8 pad3[3]; } wl_proxd_collect_inline_frame_info_v1_t; #define TOF_COLLECT_INLINE_FRAME_INFO_VER_2 2 @@ -17854,24 +20065,6 @@ typedef struct wl_proxd_collect_inline_frame_info_v2 uint8 pad[3]; } wl_proxd_collect_inline_frame_info_v2_t; -typedef struct wl_proxd_tlv { - uint16 id; - uint16 len; - uint8 data[1]; -} wl_proxd_tlv_t; - -/** proxd iovar - applies to proxd, method or session */ -typedef struct wl_proxd_iov { - uint16 version; - uint16 len; - wl_proxd_cmd_t cmd; - wl_proxd_method_t method; - wl_proxd_session_id_t sid; - wl_ftm_type_t ftm_type; /* 11az ftm type. Only valid with PROXD vers >= 0x0400 */ - uint8 PAD[1]; - wl_proxd_tlv_t tlvs[1]; /**< variable */ -} wl_proxd_iov_t; - #define WL_PROXD_IOV_HDR_SIZE OFFSETOF(wl_proxd_iov_t, tlvs) /* The following event definitions may move to bcmevent.h, but sharing proxd types @@ -17898,7 +20091,11 @@ enum { WL_PROXD_EVENT_COLLECT = 17, WL_PROXD_EVENT_START_WAIT = 18, /* waiting to start */ WL_PROXD_EVENT_MF_STATS = 19, /* mf stats event */ - + WL_PROXD_EVENT_RES_WAIT = 20, /* waiting to resources */ + WL_PROXD_EVENT_SESSION_READY = 21, /* ready to burst */ + WL_PROXD_EVENT_RESERVED22 = 22, /* reserved by ftm */ + WL_PROXD_EVENT_RESERVED23 = 23, /* reserved by ftm */ + WL_PROXD_EVENT_RESERVED24 = 24, /* reserved by ftm */ WL_PROXD_EVENT_MAX }; typedef int16 wl_proxd_event_type_t; @@ -17919,7 +20116,7 @@ typedef struct wl_proxd_event { wl_proxd_method_t method; wl_proxd_session_id_t sid; uint8 pad[2]; /* This field is used fragmentation purpose */ - wl_proxd_tlv_t tlvs[1]; /**< variable */ + wl_proxd_tlv_t tlvs[BCM_FLEX_ARRAY]; /**< variable */ } wl_proxd_event_t; enum { @@ -17984,6 +20181,7 @@ typedef struct wl_proxd_collect_event_data_v4 { uint32 H_LB[K_TOF_COLLECT_H_SIZE_20MHZ]; uint32 H_RX[K_TOF_COLLECT_H_SIZE_20MHZ]; uint8 ri_rr[FTM_TPK_RI_RR_LEN_SECURE_2_0_5G]; + uint8 PAD[2]; wl_proxd_phy_error_t phy_err_mask; } wl_proxd_collect_event_data_v4_t; @@ -18053,16 +20251,36 @@ typedef struct wl_user_roamcache { #define WL_ROAM_PROF_VER_1 1 #define WL_ROAM_PROF_VER_2 2 #define WL_ROAM_PROF_VER_3 3 +#define WL_ROAM_PROF_VER_4 4 +#define WL_ROAM_PROF_VER_5 5 #define WL_MAX_ROAM_PROF_VER WL_ROAM_PROF_VER_1 -#define WL_ROAM_PROF_NONE (0 << 0) -#define WL_ROAM_PROF_LAZY (1 << 0) -#define WL_ROAM_PROF_NO_CI (1 << 1) -#define WL_ROAM_PROF_SUSPEND (1 << 2) -#define WL_ROAM_PROF_EXTSCAN (1 << 3) -#define WL_ROAM_PROF_SYNC_DTIM (1 << 6) -#define WL_ROAM_PROF_DEFAULT (1 << 7) /**< backward compatible single default profile */ +#define WL_ROAM_PROF_NONE (0u << 0u) +#define WL_ROAM_PROF_LAZY (1u << 0u) +#define WL_ROAM_PROF_NO_CI (1u << 1u) +#define WL_ROAM_PROF_SUSPEND (1u << 2u) +#define WL_ROAM_PROF_EXTSCAN (1u << 3u) +#define WL_ROAM_FIND_HIGHER_BAND_ONLY (1u << 4u) /* Flag to find better higher band AP + * Not valid 4388 onwards + */ +#define WL_ROAM_PROF_SYNC_DTIM (1u << 6u) +#define WL_ROAM_PROF_DEFAULT (1u << 7u) /* backward compatible single default profile */ +#define WL_ROAM_PROF_5G_PREF (1u << 8u) /* Flag to restrict low rssi roam scan to 5G */ +#define WL_ROAM_PROF_6G_PREF (1u << 9u) /* Flag to restrict low rssi roam scan to 6G */ +#define WL_ROAM_FORCE_6G_SC (1u << 10u) /* Force 6G lowrssi LP roam scan on Scan core */ +#define WL_ROAM_PROF_TIE_BREAKER_POLICY (1u << 11u) /* Prefer higher band target with same score */ +#define WL_ROAM_PROF_NONDFS_PREF (1u << 12u) /* Prefer non-DFS target with similar score */ +/* 2-bit flags to indicate AP with preferred TX power */ +#define WL_ROAM_PROF_POWER_PREF_BIT_OFFSET 13u /* Offset for Power Pref bit */ +#define WL_ROAM_PROF_POWER_PREF_BIT_MASK 0x3u /* Bit mask: bits 13 and 14 indicate power pref */ +#define WL_ROAM_PROF_SKIP_FILS (1u << 15u) /* Flag to skip FILS */ + +typedef enum wl_roam_prof_power_pref { + WL_NO_POWER_PREF = 0x0u, + WL_LOW_POWER_PREF = 0x1u, + WL_HIGH_POWER_PREF = 0x2u +} wl_roam_prof_power_pref_t; #define WL_FACTOR_TABLE_MAX_LIMIT 5 @@ -18077,12 +20295,72 @@ typedef struct wl_user_roamcache { #define WL_CU_PERCENTAGE_MAX 100 #define WL_CU_CALC_DURATION_DEFAULT 10 /* seconds */ #define WL_CU_CALC_DURATION_MAX 60 /* seconds */ +#define WL_CU_NOT_AVAIL -1 #define WL_ESTM_LOW_TRIGGER_DISABLE 0 #define WL_ESTM_LOW_TRIGGER_DEFAULT 5 /* Mbps */ #define WL_ESTM_LOW_TRIGGER_MAX 250 /* Mbps */ #define WL_ESTM_ROAM_DELTA_DEFAULT 10 +typedef struct wl_rssi_boost_v1 { + int8 thresh; /**< Min RSSI to qualify for RSSI boost */ + int8 delta; /**< RSSI boost for AP in the other band */ +} wl_rssi_boost_v1_t; + +typedef struct wl_roam_prof_v6 { + uint32 roam_flags; /**< bit flags */ + int8 roam_trigger; /**< RSSI trigger level per profile/RSSI bracket */ + int8 rssi_lower; + int8 roam_delta; + int8 pad1; + /* if channel_usage if zero, roam_delta is rssi delta required for new AP */ + /* if channel_usage if non-zero, roam_delta is score delta(%) required for new AP */ + uint16 nfscan; /**< number of full scan to start with */ + uint16 fullscan_period; + uint16 init_scan_period; + uint16 backoff_multiplier; + uint16 max_scan_period; + uint8 channel_usage; + uint8 cu_avg_calc_dur; + uint16 estm_low_trigger; /**< ESTM low throughput roam trigger */ + int8 estm_roam_delta; /**< ESTM low throughput roam delta */ + uint8 boost_bitmap; /* bitmap boost configuration for bands + * provided by user + */ + uint16 cca_meas_span; /* cca meas start time in s before partial + * or full scan period + */ + uint16 lp_roamscan_period; + uint16 max_fullscan_period; + wl_rssi_boost_v1_t rssi_boost[WL_BAND_MAX_CNT]; +} wl_roam_prof_v6_t; + +typedef struct wl_roam_prof_v5 { + uint8 roam_flags; /**< bit flags */ + int8 roam_trigger; /**< RSSI trigger level per profile/RSSI bracket */ + int8 rssi_lower; + int8 roam_delta; + /* if channel_usage if zero, roam_delta is rssi delta required for new AP */ + /* if channel_usage if non-zero, roam_delta is score delta(%) required for new AP */ + int8 rssi_boost_thresh; /**< Min RSSI to qualify for RSSI boost */ + int8 rssi_boost_delta; /**< RSSI boost for AP in the other band */ + uint16 nfscan; /**< number of full scan to start with */ + uint16 fullscan_period; + uint16 init_scan_period; + uint16 backoff_multiplier; + uint16 max_scan_period; + uint8 channel_usage; + uint8 cu_avg_calc_dur; + uint16 estm_low_trigger; /**< ESTM low throughput roam trigger */ + int8 estm_roam_delta; /**< ESTM low throughput roam delta */ + int8 pad; + uint16 cca_meas_span; /* cca meas start time in s before partial + * or full scan period + */ + uint16 lp_roamscan_period; + uint16 max_fullscan_period; +} wl_roam_prof_v5_t; + typedef struct wl_roam_prof_v4 { uint8 roam_flags; /**< bit flags */ int8 roam_trigger; /**< RSSI trigger level per profile/RSSI bracket */ @@ -18102,7 +20380,7 @@ typedef struct wl_roam_prof_v4 { uint8 cu_avg_calc_dur; uint16 estm_low_trigger; /**< ESTM low throughput roam trigger */ int8 estm_roam_delta; /**< ESTM low throughput roam delta */ - int8 pad[3]; + int8 PAD[3]; uint16 lp_roamscan_period; uint16 max_fullscan_period; } wl_roam_prof_v4_t; @@ -18126,7 +20404,7 @@ typedef struct wl_roam_prof_v3 { uint8 cu_avg_calc_dur; uint16 estm_low_trigger; /**< ESTM low throughput roam trigger */ int8 estm_roam_delta; /**< ESTM low throughput roam delta */ - uint8 pad; + uint8 PAD; } wl_roam_prof_v3_t; typedef struct wl_roam_prof_v2 { @@ -18146,7 +20424,7 @@ typedef struct wl_roam_prof_v2 { uint16 max_scan_period; uint8 channel_usage; uint8 cu_avg_calc_dur; - uint8 pad[2]; + uint8 PAD[2]; } wl_roam_prof_v2_t; typedef struct wl_roam_prof_v1 { @@ -18166,6 +20444,20 @@ typedef struct wl_roam_prof_v1 { uint16 max_scan_period; } wl_roam_prof_v1_t; +typedef struct wl_roam_prof_band_v6 { + uint32 band; /**< Must be just one band */ + uint16 ver; /**< version of this struct */ + uint16 len; /**< length in bytes of this structure */ + wl_roam_prof_v6_t roam_prof[WL_MAX_ROAM_PROF_BRACKETS]; +} wl_roam_prof_band_v6_t; + +typedef struct wl_roam_prof_band_v5 { + uint32 band; /**< Must be just one band */ + uint16 ver; /**< version of this struct */ + uint16 len; /**< length in bytes of this structure */ + wl_roam_prof_v5_t roam_prof[WL_MAX_ROAM_PROF_BRACKETS]; +} wl_roam_prof_band_v5_t; + typedef struct wl_roam_prof_band_v4 { uint32 band; /**< Must be just one band */ uint16 ver; /**< version of this struct */ @@ -18195,12 +20487,12 @@ typedef struct wl_roam_prof_band_v1 { } wl_roam_prof_band_v1_t; #define BSS_MAXTABLE_SIZE 10 -#define WNM_BSS_SELECT_FACTOR_VERSION 1 +#define WNM_BSS_SELECT_FACTOR_VERSION_1 1 typedef struct wnm_bss_select_factor_params { uint8 low; uint8 high; uint8 factor; - uint8 pad; + uint8 PAD; } wnm_bss_select_factor_params_t; #define WNM_BSS_SELECT_FIXED_SIZE OFFSETOF(wnm_bss_select_factor_cfg_t, params) @@ -18208,9 +20500,9 @@ typedef struct wnm_bss_select_factor_cfg { uint8 version; uint8 band; uint16 type; - uint16 pad; + uint16 PAD; uint16 count; - wnm_bss_select_factor_params_t params[1]; + wnm_bss_select_factor_params_t params[BCM_FLEX_ARRAY]; } wnm_bss_select_factor_cfg_t; #define WNM_BSS_SELECT_WEIGHT_VERSION 1 @@ -18227,6 +20519,7 @@ typedef struct wnm_bss_select_weight_cfg { typedef struct wnm_btm_default_score_cfg { uint32 default_score; /* default score */ uint8 band; + uint8 PAD[3]; } wnm_btm_default_score_cfg_t; /* For branches from koala and above .. wbtext is @@ -18235,20 +20528,21 @@ typedef struct wnm_btm_default_score_cfg { typedef struct wbtext_btm_default_score_cfg { uint32 default_score; /* default score */ uint8 band; + uint8 PAD[3]; } wbtext_btm_default_score_cfg_t; #define WNM_BSS_SELECT_TYPE_RSSI 0 #define WNM_BSS_SELECT_TYPE_CU 1 #define WNM_BSS_SELECT_TYPE_ESTM_DL 2 -#define WNM_BSSLOAD_MONITOR_VERSION 1 +#define WNM_BSSLOAD_MONITOR_VERSION_1 1 typedef struct wnm_bssload_monitor_cfg { uint8 version; uint8 band; uint8 duration; /* duration between 1 to 20sec */ } wnm_bssload_monitor_cfg_t; -#define WNM_ROAM_TRIGGER_VERSION 1 +#define WNM_ROAM_TRIGGER_VERSION_1 1 typedef struct wnm_roam_trigger_cfg { uint8 version; uint8 band; @@ -18277,8 +20571,8 @@ typedef struct wnm_roam_trigger_cfg { * 1 - Create an AP interface * NOTE: This Bit 0 is applicable for the WL_INTERFACE_CREATE_VER < 2 */ -#define WL_INTERFACE_CREATE_STA (0 << 0) -#define WL_INTERFACE_CREATE_AP (1 << 0) +#define WL_INTERFACE_CREATE_STA (0u << 0u) +#define WL_INTERFACE_CREATE_AP (1u << 0u) /* * From revision >= 2 Bit 0 of flags field will not used be for STA or AP interface creation. @@ -18288,10 +20582,6 @@ typedef enum wl_interface_type { WL_INTERFACE_TYPE_STA = 0, WL_INTERFACE_TYPE_AP = 1, -#ifdef WLAWDL - WL_INTERFACE_TYPE_AWDL = 2, -#endif /* WLAWDL */ - WL_INTERFACE_TYPE_NAN = 3, WL_INTERFACE_TYPE_P2P_GO = 4, WL_INTERFACE_TYPE_P2P_GC = 5, @@ -18307,8 +20597,8 @@ typedef enum wl_interface_type { * 0 - Ignore mac_addr field * 1 - Use the mac_addr field */ -#define WL_INTERFACE_MAC_DONT_USE (0 << 1) -#define WL_INTERFACE_MAC_USE (1 << 1) +#define WL_INTERFACE_MAC_DONT_USE (0u << 1u) +#define WL_INTERFACE_MAC_USE (1u << 1u) /* * Bit 2 of flags field is used to inform whether core or wlc index @@ -18316,45 +20606,58 @@ typedef enum wl_interface_type { * 0 - Ignore wlc_index field * 1 - Use the wlc_index field */ -#define WL_INTERFACE_WLC_INDEX_DONT_USE (0 << 2) -#define WL_INTERFACE_WLC_INDEX_USE (1 << 2) +#define WL_INTERFACE_WLC_INDEX_DONT_USE (0u << 2u) +#define WL_INTERFACE_WLC_INDEX_USE (1u << 2u) /* * Bit 3 of flags field is used to create interface on the host requested interface index * 0 - Ignore if_index field * 1 - Use the if_index field */ -#define WL_INTERFACE_IF_INDEX_USE (1 << 3) +#define WL_INTERFACE_IF_INDEX_USE (1u << 3u) /* * Bit 4 of flags field is used to assign BSSID * 0 - Ignore bssid field * 1 - Use the bssid field */ -#define WL_INTERFACE_BSSID_INDEX_USE (1 << 4) +#define WL_INTERFACE_BSSID_INDEX_USE (1u << 4u) + +/* + * Bit 5 of flags field indicates mesh usage on this interface + */ +#define WL_INTERFACE_MESH_USE (1u << 5u) + +#define WL_INTERFACE_IOV_ALLOWED_FLAGS (WL_INTERFACE_CREATE_AP | WL_INTERFACE_MAC_USE | \ + WL_INTERFACE_WLC_INDEX_USE | WL_INTERFACE_IF_INDEX_USE | \ + WL_INTERFACE_BSSID_INDEX_USE | WL_INTERFACE_MESH_USE) + +#define WL_INTERFACE_IOV_FLAGS_VALID(_f) (((_f) & ~WL_INTERFACE_IOV_ALLOWED_FLAGS) == 0u) typedef struct wl_interface_create_v0 { uint16 ver; /**< version of this struct */ + uint16 PAD; uint32 flags; /**< flags that defines the operation */ struct ether_addr mac_addr; /**< Optional Mac address */ + uint8 PAD[2]; /**< Padding bytes */ } wl_interface_create_v0_t; typedef struct wl_interface_create { uint16 ver; /**< version of this struct */ - uint8 pad1[2]; /**< Padding bytes */ + uint8 PAD[2]; /**< Padding bytes */ uint32 flags; /**< flags that defines the operation */ struct ether_addr mac_addr; /**< Optional Mac address */ - uint8 pad2[2]; /**< Padding bytes */ + uint8 PAD[2]; /**< Padding bytes */ uint32 wlc_index; /**< Optional wlc index */ } wl_interface_create_v1_t; typedef struct wl_interface_create_v2 { uint16 ver; /**< version of this struct */ - uint8 pad1[2]; /**< Padding bytes */ + uint8 PAD[2]; /**< Padding bytes */ uint32 flags; /**< flags that defines the operation */ struct ether_addr mac_addr; /**< Optional Mac address */ uint8 iftype; /**< Type of interface created */ - uint8 pad2; /**< Padding bytes */ + uint8 PAD; /**< Padding bytes */ uint32 wlc_index; /**< Optional wlc index */ } wl_interface_create_v2_t; @@ -18368,7 +20671,7 @@ typedef struct wl_interface_create_v3 { struct ether_addr mac_addr; /**< Optional Mac address */ struct ether_addr bssid; /**< Optional BSSID */ uint8 if_index; /**< interface index requested by Host */ - uint8 pad[3]; /**< Padding bytes to ensure data[] is at 32 bit aligned */ + uint8 PAD[3]; /**< Padding bytes to ensure data[] is at 32 bit aligned */ uint8 data[]; /**< Optional application/Module specific data */ } wl_interface_create_v3_t; @@ -18381,6 +20684,7 @@ typedef struct wl_interface_info_v0 { struct ether_addr mac_addr; /**< MAC address of the interface */ char ifname[BCM_MSG_IFNAME_MAX]; /**< name of interface */ uint8 bsscfgidx; /**< source bsscfg index */ + uint8 PAD; } wl_interface_info_v0_t; typedef struct wl_interface_info_v1 { @@ -18424,7 +20728,7 @@ typedef struct wl_iqest_value { typedef struct wl_iqest_result { uint8 nvalues; uint8 PAD[3]; - wl_iqest_value_t value[1]; + wl_iqest_value_t value[BCM_FLEX_ARRAY]; } wl_iqest_result_t; #define WL_PRIO_ROAM_PROF_V1 (1u) @@ -18468,7 +20772,7 @@ typedef struct wlc_btc_aibss_info { uint8 strobe_init_err_cnt; // Strobe init err cnt uint8 tsf_jump_cnt; // TSF jump cnt uint8 acl_grant_cnt; // ALC grant cnt - uint8 pad1; + uint8 PAD; uint16 ibss_tsf_shm; // SHM address of strobe TSF uint16 pad2; } wlc_btc_aibss_info_t; @@ -18483,81 +20787,10 @@ typedef struct wlc_btc_aibss_status { uint16 bth_period; // bt coex period. read from shm. uint16 agg_off_bm; // AGG OFF BM read from SHM uint8 bth_active; // bt active session - uint8 pad[3]; + uint8 PAD[3]; wlc_btc_aibss_info_t aibss_info; // Structure definition above } wlc_btc_aibss_status_t; -typedef enum { - STATE_NONE = 0, - - /* WLAN -> BT */ - W2B_DATA_SET = 21, - B2W_ACK_SET = 22, - W2B_DATA_CLEAR = 23, - B2W_ACK_CLEAR = 24, - - /* BT -> WLAN */ - B2W_DATA_SET = 31, - W2B_ACK_SET = 32, - B2W_DATA_CLEAR = 33, - W2B_ACK_CLEAR = 34 -} bwte_gci_intstate_t; - -#define WL_BWTE_STATS_VERSION 1 /* version of bwte_stats_t */ -typedef struct { - uint32 version; - - bwte_gci_intstate_t inttobt; - bwte_gci_intstate_t intfrombt; - - uint32 bt2wl_intrcnt; /* bt->wlan interrrupt count */ - uint32 wl2bt_intrcnt; /* wlan->bt interrupt count */ - - uint32 wl2bt_dset_cnt; - uint32 wl2bt_dclear_cnt; - uint32 wl2bt_aset_cnt; - uint32 wl2bt_aclear_cnt; - - uint32 bt2wl_dset_cnt; - uint32 bt2wl_dclear_cnt; - uint32 bt2wl_aset_cnt; - uint32 bt2wl_aclear_cnt; - - uint32 state_error_1; - uint32 state_error_2; - uint32 state_error_3; - uint32 state_error_4; -} bwte_stats_t; - -#define TBOW_MAX_SSID_LEN 32 -#define TBOW_MAX_PASSPHRASE_LEN 63 - -#define WL_TBOW_SETUPINFO_T_VERSION 1 /* version of tbow_setup_netinfo_t */ -typedef struct tbow_setup_netinfo { - uint32 version; - uint8 opmode; - uint8 pad; - uint8 macaddr[ETHER_ADDR_LEN]; - uint32 ssid_len; - uint8 ssid[TBOW_MAX_SSID_LEN]; - uint8 passphrase_len; - uint8 passphrase[TBOW_MAX_PASSPHRASE_LEN]; - chanspec_t chanspec; - uint8 PAD[2]; - uint32 channel; -} tbow_setup_netinfo_t; - -typedef enum tbow_ho_opmode { - TBOW_HO_MODE_START_GO = 0, - TBOW_HO_MODE_START_STA, - TBOW_HO_MODE_START_GC, - TBOW_HO_MODE_TEST_GO, - TBOW_HO_MODE_STOP_GO = 0x10, - TBOW_HO_MODE_STOP_STA, - TBOW_HO_MODE_STOP_GC, - TBOW_HO_MODE_TEARDOWN -} tbow_ho_opmode_t; - /* Beacon trim feature statistics */ /* configuration */ #define BCNTRIMST_PER 0 /* Number of beacons to trim (0: disable) */ @@ -18591,7 +20824,7 @@ typedef struct wl_bcntrim_status_query_v1 { uint16 version; uint16 len; /* Total length includes fixed fields */ uint8 reset; /* reset after reading the stats */ - uint8 pad[3]; /* 4-byte alignment */ + uint8 PAD[3]; /* 4-byte alignment */ } wl_bcntrim_status_query_v1_t; /* bits for curr_slice_id */ @@ -18705,8 +20938,9 @@ typedef struct wl_bcntrim_cfg_sc_bcntrim { #define TXPWRCAPSTATE_HOST_HIGH_WCI2_HIGH_CAP 3 /* IOVAR txcapconfig and txcapstate structure is shared: SET and GET */ -#define TXPWRCAPCTL_VERSION 2 +#define TXPWRCAPCTL_VERSION_2 2 #define TXPWRCAPCTL_VERSION_3 3 +#define TXPWRCAPCTL_VERSION_4 4 typedef struct wl_txpwrcap_ctl { uint8 version; @@ -18718,8 +20952,14 @@ typedef struct wl_txpwrcap_ctl_v3 { uint8 ctl[TXPWRCAP_MAX_NUM_SUBGRPS]; } wl_txpwrcap_ctl_v3_t; +typedef struct wl_txpwrcap_ctl_v4 { + uint8 version; /* TXPWRCAPCTL_VERSION_4 */ + uint8 len; /* length of whole structure */ + uint8 ctl; /* one single value common for all subgroup. */ +} wl_txpwrcap_ctl_v4_t; + /* IOVAR txcapdump structure: GET only */ -#define TXPWRCAP_DUMP_VERSION 2 +#define TXPWRCAP_DUMP_VERSION_2 2 typedef struct wl_txpwrcap_dump { uint8 version; uint8 pad0; @@ -18799,6 +21039,11 @@ typedef struct wl_txpwrcap_dump_v3 { #define TXHDR_SEC_SDB_AUX_2G 6 #define TXHDR_SEC_SDB_AUX_5G 7 #define TXHDR_MAX_SECTION 8 +#define TXHDR_SEC_NONSDB_MAIN_6G 8 +#define TXHDR_SEC_NONSDB_AUX_6G 9 +#define TXHDR_SEC_SDB_MAIN_6G 10 +#define TXHDR_SEC_SDB_AUX_6G 11 +#define TXHDR_MAX_SECTION_6G 12 #define WL_TXPWRCAP_MAX_SLICES 2 #define WL_TXPWRCAPDUMP_VER 4 @@ -18824,6 +21069,7 @@ typedef struct { #define TXPWRCAP_DUMP_VERSION_4 4u #define TXPWRCAP_DUMP_VERSION_5 5u #define TXPWRCAP_DUMP_VERSION_6 6u +#define TXPWRCAP_DUMP_VERSION_7 7u typedef struct wl_txpwrcap_dump_v4 { uint8 version; @@ -18838,7 +21084,7 @@ typedef struct wl_txpwrcap_dump_v4 { * On main,-non-sdb follows by sdb2g and then sdb5g * On aux slice - aux2g then aux5g. */ - wl_txpwrcap_t pwrcap; /* first power cap */ + uint8 pwrcap[BCM_FLEX_ARRAY]; /* variable size power caps (wl_txpwrcap_t) */ } wl_txpwrcap_dump_v4_t; typedef struct wl_txpwrcap_dump_v5 { @@ -18854,7 +21100,7 @@ typedef struct wl_txpwrcap_dump_v5 { uint8 current_country_cc_group_info_index; uint8 ant_tx; /* current value of ant_tx */ uint8 cell_status; /* current value of cell status */ - int8 pwrcap[]; /* variable size power caps (wl_txpwrcap_v2_t) */ + uint8 pwrcap[]; /* variable size power caps (wl_txpwrcap_v2_t) */ } wl_txpwrcap_dump_v5_t; typedef struct wl_txpwrcap_dump_v6 { @@ -18870,10 +21116,27 @@ typedef struct wl_txpwrcap_dump_v6 { uint8 current_country_cc_group_info_index; uint8 ant_tx; /* current value of ant_tx */ uint8 cell_status; /* current value of cell status */ - uint16 capability[TXHDR_MAX_SECTION]; /* capabilities */ - int8 pwrcap[]; /* variable size power caps (wl_txpwrcap_v2_t) */ + uint16 capability[TXHDR_MAX_SECTION]; /* capabilities */ + uint8 pwrcap[]; /* variable size power caps (wl_txpwrcap_v2_t) */ } wl_txpwrcap_dump_v6_t; +typedef struct wl_txpwrcap_dump_v7 { + uint8 version; + uint8 num_pwrcap; + uint8 current_country[2]; + uint8 current_channel; + uint8 high_cap_state_enabled; + uint8 reserved[2]; + uint8 download_present; + uint8 num_ants; /* number antenna slice */ + uint8 num_cc_groups; /* number cc groups */ + uint8 current_country_cc_group_info_index; + uint8 ant_tx; /* current value of ant_tx */ + uint8 cell_status; /* current value of cell status */ + uint16 capability[TXHDR_MAX_SECTION_6G]; /* capabilities */ + int8 pwrcap[]; /* variable size power caps (wl_txpwrcap_v2_t) */ +} wl_txpwrcap_dump_v7_t; + #define TXCAPINFO_VERSION_1 1 typedef struct wl_txpwrcap_ccgrp_info { uint8 num_cc; @@ -18885,7 +21148,7 @@ typedef struct { uint16 length; /* length in bytes */ uint8 num_ccgrp; /* followed by one or more wl_txpwrcap_ccgrp_info_t */ - wl_txpwrcap_ccgrp_info_t ccgrp_data[1]; + wl_txpwrcap_ccgrp_info_t ccgrp_data[BCM_FLEX_ARRAY]; } wl_txpwrcap_info_t; typedef struct wl_txpwrcap_tbl { @@ -18907,6 +21170,72 @@ typedef struct wl_txpwrcap_tbl_v2 { uint8 pwrs[][TXPWRCAP_MAX_NUM_CORES]; /* qdBm units */ } wl_txpwrcap_tbl_v2_t; +/* Supported sar modes value for sar_enable IOVAR */ +typedef enum { + SAR_MODE_DISABLE = (0u), + SAR_MODE_HEAD = (1u << 0u), + SAR_MODE_GRIP = (1u << 1u), + SAR_MODE_NR_MW = (1u << 2u), + SAR_MODE_NR_SUB6 = (1u << 3u), + SAR_MODE_BT = (1u << 4u), + SAR_MODE_HS = (1u << 5u), + SAR_MODE_MHS = (1u << 6u), + SAR_MODE_FLIP = (1u << 7u), + SAR_MODE_MAX = (1u << 8u) +} sar_modes_new; + +/* sub6 bandinfo valuse for s6bandinfo iovar */ +typedef enum { + NR_SUB6_BAND2 = 2u, + NR_SUB6_BAND25 = 25u, + NR_SUB6_BAND41 = 41u, + NR_SUB6_BAND48 = 48u, + NR_SUB6_BAND66 = 66u, + NR_SUB6_BAND77 = 77u, + NR_SUB6_BAND_UN = 0u +} sar_sub6bandinfo_mode; + +/* sar cap states values */ +typedef enum { + SAR_CAP_AIR = (1u << 0u), + SAR_CAP_HEAD = (1u << 1u), + SAR_CAP_GRIP = (1u << 2u), + SAR_CAP_NRMW = (1u << 3u), + SAR_CAP_NRS6 = (1u << 4u), + SAR_CAP_BT = (1u << 5u), + SAR_CAP_HS = (1u << 6u), + SAR_CAP_RU = (1u << 7u), + SAR_CAP_MHS = (1u << 8u), + SAR_CAP_S6_BAND2 = (1u << 9u), + SAR_CAP_S6_BAND25 = (1u << 10u), + SAR_CAP_S6_BAND41 = (1u << 11u), + SAR_CAP_S6_BAND48 = (1u << 12u), + SAR_CAP_S6_BAND66 = (1u << 13u), + SAR_CAP_S6_BAND77 = (1u << 14u), + SAR_CAP_FLIP = (1u << 15u), + SAR_CAP_MAX = SAR_CAP_FLIP +} sar_caps; + +#define SAR_DISABLE_PWR_BIT (1u << 31u) +#define SAR_ALL_MODE_CAP_MASK (SAR_CAP_HEAD | SAR_CAP_GRIP | SAR_CAP_NRMW | SAR_CAP_NRS6 |\ + SAR_CAP_BT | SAR_CAP_HS | SAR_CAP_MHS | SAR_CAP_FLIP) + +#define SAR_ABS_CAP_MASK (SAR_CAP_HEAD | SAR_CAP_GRIP | SAR_CAP_BT | SAR_CAP_HS |\ + SAR_CAP_MHS | SAR_CAP_FLIP) +#define SAR_COND_CAP_MASK (SAR_CAP_NRMW | SAR_CAP_NRS6) +#define SAR_OFFSET_CAP_MASK (SAR_CAP_NRMW | SAR_CAP_NRS6) +#define SAR_SUB6_BAND_CAP_MASK (SAR_CAP_S6_BAND2 | SAR_CAP_S6_BAND25 | SAR_CAP_S6_BAND41 | \ + SAR_CAP_S6_BAND48 | SAR_CAP_S6_BAND66 | SAR_CAP_S6_BAND77) + +#define TXPWRCAP_SAR_STATE_SU 0u +#define TXPWRCAP_SAR_MAX_STATES_SU_V3 1u + +#define TXPWRCAP_SAR_STATE_RU_26 1u +#define TXPWRCAP_SAR_STATE_RU_56 2u +#define TXPWRCAP_SAR_STATE_RU_106 3u +#define TXPWRCAP_SAR_MAX_STATES_RU_V3 3u +#define TXPWRCAP_SAR_MAX_STATES_SU_RU_V3 4u + typedef struct wl_txpwrcap_tbl_v3 { uint8 version; uint8 length; /* size of entire structure, including the pwrs */ @@ -18934,6 +21263,9 @@ enum { IOV_DYNSAR_EVENT = 9, IOV_DYNSAR_VAR = 10, IOV_DYNSAR_SUM_AGG = 11, + IOV_DYNSAR_PROFILE = 12, + IOV_DYNSAR_PROFILES = 13, + IOV_DYNSAR_STAT_DET_V2 = 14, IOV_DYNSAR_CMD_LAST }; @@ -18948,6 +21280,8 @@ enum { #define DYNSAR_CNT_VERSION_V1 1u #define DYNSAR_CNT_VERSION_V2 2u +#define DYNSAR_CNT_VERSION_V3 3u +#define DYNSAR_CNT_VERSION_V4 4u #define DYNSAR_STS_OBS_WIN 20u #define DYNSAR_MAX_ANT WL_STA_ANT_MAX #define DYNSAR_MAX_AGG_IDX (DYNSAR_MAX_ANT << 1u) /* max antenna aggregation index */ @@ -18961,6 +21295,22 @@ enum { #define DYNSAR_ANT_NUM_MISMATCH (1u << 4u) #define DYNSAR_COUNTRY_DISABLED (1u << 5u) +/* TLVs for DYNSAR related IOVARs */ +typedef enum wl_dynsar_tlv { + DYNSAR_AGG_IDX = 1u, + DYNSAR_FS_RSN = 2u +} wl_dynsar_tlv_t; + +/* bit position corresponding to each failsafe reason */ +typedef enum wlc_fs_rsn_bit { + FS_FORCED = 0, /* Forced */ + FS_UX_SAFE = 1, /* Ux Safe exceeds limit */ + FS_UTIL_MEAN = 2, /* Mean Util exceeds limit */ + FS_TXDC_AVG = 3, /* Average Txdc exceeds limit */ +} wlc_dynsar_fs_rsn_bit_t; + +typedef uint8 wlc_dynsar_fs_rsn_t; + typedef struct wlc_dynsar_sts_mon_ctr_st { uint32 tx_dur; /* in usec */ uint32 tx_dur_raw; /* in usec */ @@ -18972,10 +21322,33 @@ typedef struct wlc_dynsar_sts_mon_ctr_st { uint8 util_pred; /* utilization of past (observe - budget) & predicted budget sec */ } wlc_dynsar_sts_mon_ctr_t; +typedef struct wlc_dynsar_sts_mon_ctr_v2_st { + uint32 tx_dur; /* in usec */ + uint32 tx_dur_raw; /* in usec */ + uint32 plim_avg; /* In uw. plim averaged over mon win. */ + uint32 energy; /* pavg * dur in mw * ms */ + uint32 qsar; /* plim * dur in mw * ms */ + uint16 fs; /* failsafe duration in usec */ + uint16 util_hist; /* 10 x utilization in past observe sec */ + uint16 util_pred; /* 10 x utilization of past (observe - budget) & predicted + * budget sec + */ + uint16 pad; +} wlc_dynsar_sts_mon_ctr_v2_t; + +/* DSA v2 support */ +typedef struct wlc_dynsar_sts_mon_ctr_v3 { + uint32 tx_dur; /* in usec */ + uint16 util; /* 10 x Tmon utilization */ + uint16 util_hist; /* 10 x Twin utilization */ + uint16 util_pred; /* 10 x Twin utilization forecast after budget num sec */ + uint16 pad; +} wlc_dynsar_sts_mon_ctr_v3_t; + typedef struct wlc_dynsar_sts_obs_win { uint8 opt; uint8 valid; - uint16 pad; + uint16 PAD; uint32 dur; /* monitor duration in usec */ uint64 ts; /* timestamp in usec */ } wlc_dynsar_sts_obs_win_t; @@ -18992,12 +21365,23 @@ typedef struct dynsar_agg_stat { uint16 len; /* length of this structure including data */ uint16 num_ent; /* number of entries per aggregated slot */ uint16 num_agg; /* number of aggregated slots */ - uint16 pad; /* pad */ + uint16 PAD; /* pad */ uint64 buf[]; /* num_ent entries wlc_dynsar_sts_obs_win_t * followed by num_ent entries dynsar_agg_ent_t */ } dynsar_agg_stat_t; +/* Common header for the detailed stats IOVAR */ +typedef struct dynsar_cnt_head { + uint16 ver; + uint16 len; /* length of this structure */ + uint8 num_ant; /* num_antennas */ + uint8 win; /* number of valid entries in the observe window */ + uint8 slice; + uint8 PAD; + uint64 sync_ts; /* time of first mon period collection after last sync */ +} dynsar_cnt_head_t; + /* structure holding dynsar per slice counters that interface to iovar */ typedef struct dynsar_cnt_v1 { uint16 ver; @@ -19005,16 +21389,42 @@ typedef struct dynsar_cnt_v1 { uint8 num_ant; /* num_antennas */ uint8 win; /* number of valid entries in the observe window */ uint8 slice; - uint8 pad; /* num_antennas */ + uint8 PAD; /* num_antennas */ uint64 sync_ts; /* time of first mon period collection after last sync */ wlc_dynsar_sts_obs_win_t obs[DYNSAR_STS_OBS_WIN]; wlc_dynsar_sts_mon_ctr_t mon_ctr[DYNSAR_STS_OBS_WIN][DYNSAR_MAX_ANT]; } dynsar_cnt_v1_t; +/* structure holding dynsar per slice counters that interface to iovar */ +typedef struct dynsar_cnt_v2 { + uint16 ver; + uint16 len; /* length of this structure */ + uint8 num_ant; /* num_antennas */ + uint8 win; /* number of valid entries in the observe window */ + uint8 slice; + uint8 PAD; + uint64 sync_ts; /* time of first mon period collection after last sync */ + wlc_dynsar_sts_obs_win_t obs[DYNSAR_STS_OBS_WIN]; + wlc_dynsar_sts_mon_ctr_v2_t mon_ctr[DYNSAR_STS_OBS_WIN][DYNSAR_MAX_ANT]; +} dynsar_cnt_v2_t; + +/* structure holding dynsar per slice counters that interface to iovar */ +typedef struct dynsar_cnt_v3 { + uint16 ver; + uint16 len; /* length of this structure */ + uint8 num_ant; /* num_antennas */ + uint8 win; /* number of valid entries in the observe window */ + uint8 slice; + uint8 PAD; + uint64 sync_ts; /* time of first mon period collection after last sync */ + wlc_dynsar_sts_obs_win_t obs[DYNSAR_STS_OBS_WIN]; + wlc_dynsar_sts_mon_ctr_v3_t mon_ctr[DYNSAR_STS_OBS_WIN][DYNSAR_MAX_ANT]; +} dynsar_cnt_v3_t; + typedef struct dynsar_shared_ant_stats { uint32 tx_dur; /* tx duration */ uint8 sar_util; /* sar utilization */ - uint8 pad[3]; /* pad */ + uint8 PAD[3]; /* pad */ } dynsar_shared_ant_stats_t; typedef struct dynsar_unshared_ant_stats { @@ -19023,6 +21433,13 @@ typedef struct dynsar_unshared_ant_stats { uint32 tx_dur; /* tx duration */ } dynsar_unshared_ant_stats_t; +typedef struct dynsar_ant_stats { + uint32 tx_dur; /* tx duration */ + uint16 sar_util; /* sar utilization */ + uint8 valid; /* valid record */ + uint8 PAD; /* pad */ +} dynsar_ant_stats_t; + typedef struct dynsar_sum_v1 { uint16 ver; uint16 len; /* length of this structure */ @@ -19045,6 +21462,7 @@ typedef struct dynsar_sum_v1 { uint32 qsar; /* mw * ms */ uint32 energy; /* mw * ms */ } unshared[DYNSAR_MAX_ANT]; + uint8 PAD[4]; } dynsar_sum_v1_t; typedef struct dynsar_sum_v2 { @@ -19053,17 +21471,22 @@ typedef struct dynsar_sum_v2 { uint32 dur; /* duration in us */ uint64 ts; /* time stamp of report in us */ uint64 sync_ts; /* time of first mon period collection after last sync */ - uint8 num_ant; /* max number of antennas between 2 slices */ + uint8 num_ant; /* max number of antennas between 2 slices */ uint8 opt; uint8 sync; - uint8 max_mac; /* number of slices */ - uint8 num_agg; /* number of aggregated antennas */ - uint8 offset_shared; /* offset from beginning of structure to shared antenna data */ - uint8 offset_unshared; /* offset from beginning of structure to unshared antenna data */ - uint8 pad; + uint8 max_mac; /* number of slices */ + uint8 num_agg; /* number of aggregated antennas */ + uint8 offset_shared; /* offset from beginning of structure to physical antenna data */ + uint8 offset_unshared; /* offset from beginning of structure to aggregated antenna data */ + uint8 PAD; /* Variable length data sections follow as per above offsets: + * DYNSAR_CNT_VERSION_V2: * dynsar_unshared_ant_stats_t [max_mac][num_ant] * dynsar_shared_ant_stats_t [num_agg] + * + * DYNSAR_CNT_VERSION_V4: + * dynsar_ant_stats_t [max_mac][num_ant] // Per Physical antenna + * dynsar_ant_stats_t [num_agg] // Per Aggregated antenna */ } dynsar_sum_v2_t; @@ -19089,8 +21512,8 @@ typedef struct dynsar_status { } dynsar_status_t; typedef struct dynsar_var_info { - uint lim; /* variance limit */ - uint off; /* hysterysis offset applied to variance while optimized */ + uint32 lim; /* variance limit */ + uint32 off; /* hysterysis offset applied to variance while optimized */ } dynsar_var_info_t; typedef struct dynsar_status_v2 { @@ -19115,18 +21538,127 @@ typedef struct dynsar_status_v2 { uint8 agg[]; /* aggregation indices */ } dynsar_status_v2_t; +typedef struct dynsar_status_v3 { + uint16 ver; + uint16 len; /* length of this structure */ + uint8 slice; /* slice number */ + uint8 mode; /* optimization mode */ + uint8 util_thrhd; /* utilization threshold */ + uint8 opt_txdc; /* txdc prediction percentage */ + uint8 opt_dur; /* optimization prediction duration */ + uint8 event; /* if wl event is configured */ + uint8 time_sync; /* if gpio pulse is configured */ + uint8 power_off; /* power offset in db */ + uint8 num_ant; /* num antenna */ + uint8 status; /* status bitmap. e.g. WL_DYNSAR_STS_PWR_OPT. + * These are same as status field in wl_event + */ + uint8 error; /* error bits */ + uint8 gpio_pin; /* gpio pin */ + dynsar_var_info_t var; /* variance information */ + uint8 data[]; /* variable length data of type bcm_xtlv_t */ +} dynsar_status_v3_t; + +typedef struct dynsar_opt_profile_key { + uint8 pwr_off; + uint8 mode; +} dynsar_opt_profile_key_t; + +typedef struct dynsar_opt_profile { /* Obsolete structure */ + dynsar_opt_profile_key_t key; +// uint8 PAD[2]; + dynsar_var_info_t var; /* variance */ + uint8 fs_offset; /* offset percentage to kick in failsafe */ + uint8 opt_dur; /* number of mon periods in future to predict optimization */ + uint8 util_thrhd; /* Max history utilization before turning off optimization */ + uint8 util_mean; /* Mean utilization percentage before turning off optimization */ + uint8 util_mean_fs; /* Mean utilization to force failsafe */ + uint8 opt_txdc; /* txdc cap when optimized */ + uint8 avg_txdc_fs; /* mean txdc threshold for failsafe */ + uint8 avg_txdc_th; /* mean txdc threshold for throttling txdc */ + uint8 opt_txdc_tgt; /* target txdc */ +// uint8 PAD[3]; +} dynsar_opt_profile_t; + +typedef struct dynsar_opt_profile_v1 { + uint32 var_lim; /* variance limit */ + uint32 var_off; /* hysterysis offset applied to variance while optimized */ + uint8 pwr_off; /* power boost offset */ + uint8 mode; /* DSA mode */ + /* optimization parameters */ + uint8 opt_dur; /* number of mon periods in future to predict optimization */ + uint8 util_thrhd; /* Max history utilization before turning off optimization */ + uint8 util_mean; /* Mean utilization percentage before turning off optimization */ + /* failsafe parameters */ + uint8 fs; /* historical util percentage to start failsafe */ + uint8 util_mean_fs; /* Mean utilization to force failsafe */ + uint8 avg_txdc_fs; /* mean txdc threshold for failsafe */ + /* txdc limits */ + uint8 util_mean_ddc; /* mean utilization threshold to apply avg_txdc_th */ + uint8 opt_txdc; /* txdc cap when optimized */ + uint8 avg_txdc_th; /* mean txdc threshold for throttling txdc */ + uint8 opt_txdc_tgt; /* target txdc */ +} dynsar_opt_profile_v1_t; + +typedef struct dynsar_opt_profile_v2 { + uint32 var_lim; /* variance limit */ + uint32 var_off; /* hysterysis offset applied to variance while optimized */ + uint8 pwr_off; /* power boost offset */ + uint8 mode; /* DSA mode */ + /* optimization parameters */ + uint8 opt_dur; /* number of mon periods in future to predict optimization */ + uint8 util_thrhd; /* Max history utilization before turning off optimization */ + uint8 util_mean; /* Mean utilization percentage before turning off optimization */ + /* failsafe parameters */ + uint8 fs; /* historical util percentage to start failsafe */ + uint8 util_mean_fs; /* Mean utilization to force failsafe */ + uint8 avg_txdc_fs; /* mean txdc threshold for failsafe */ + /* txdc limits */ + uint8 util_mean_ddc; /* mean utilization threshold to apply avg_txdc_th */ + uint8 opt_txdc; /* txdc cap when optimized */ + uint8 avg_txdc_th; /* mean txdc threshold for throttling txdc */ + uint8 opt_txdc_tgt; /* target txdc */ + uint8 twin; /* Twin in seconds */ + uint8 pad[3]; +} dynsar_opt_profile_v2_t; + +typedef struct dynsar_opt_profiles_v1 { + uint16 ver; + uint16 len; /* length of this structure */ + uint16 active; /* active profile */ + uint16 num_profiles; /* number of profiles in variable length below */ + dynsar_opt_profile_v1_t profiles[]; +} dynsar_opt_profiles_v1_t; + +typedef struct dynsar_opt_profiles_v2 { + uint16 ver; + uint16 len; /* length of this structure */ + uint16 active; /* active profile */ + uint16 num_profiles; /* number of profiles in variable length below */ + dynsar_opt_profile_v2_t profiles[]; +} dynsar_opt_profiles_v2_t; + +typedef dynsar_opt_profiles_v2_t dynsar_opt_profiles_t; + typedef struct wl_dynsar_ioc { uint16 id; /* ID of the sub-command */ uint16 len; /* total length of all data[] */ + uint8 PAD[4]; union { /* var len payload */ uint8 cnt; dynsar_cnt_v1_t det; + dynsar_cnt_v2_t detv2; + dynsar_cnt_v3_t detv3; dynsar_agg_stat_t agg_stat; dynsar_sum_v1_t sum; dynsar_sum_v2_t sumv2; dynsar_status_t status; dynsar_status_v2_t statusv2; + dynsar_status_v3_t statusv3; dynsar_var_info_t var; + dynsar_opt_profile_t profile; + dynsar_opt_profiles_v1_t profiles; + dynsar_opt_profiles_v2_t profilesv2; } data; } wl_dynsar_ioc_t; @@ -19146,7 +21678,7 @@ typedef struct ecounters_config_request { uint16 timeout; /* timeout in seconds. */ uint16 num_events; /* Number of events to report. */ uint16 ntypes; /* Number of entries in type array. */ - uint16 type[1]; /* Statistics Types (tags) to retrieve. */ + uint16 type[BCM_FLEX_ARRAY]; /* Statistics Types (tags) to retrieve. */ } ecounters_config_request_t; #define ECOUNTERS_EVENTMSGS_VERSION_1 1 @@ -19161,16 +21693,16 @@ typedef struct ecounters_config_request { typedef struct ecounters_eventmsgs_ext { uint8 version; uint8 len; - uint8 mask[1]; + uint8 mask[BCM_FLEX_ARRAY]; } ecounters_eventmsgs_ext_t; typedef struct ecounters_trigger_config { uint16 version; /* version */ uint16 set; /* set where data should go */ uint16 rsvd; /* reserved */ - uint16 pad; /* pad/reserved */ + uint16 PAD; /* pad/reserved */ uint16 ntypes; /* number of types/tags */ - uint16 type[1]; /* list of types */ + uint16 type[BCM_FLEX_ARRAY]; /* list of types */ } ecounters_trigger_config_t; #define ECOUNTERS_TRIGGER_REASON_VERSION_1 1 @@ -19200,10 +21732,9 @@ typedef struct ecounters_trigger_reason { #define WL_LQM_TARGET_BSS_VALID 0x2 #define WL_PERIODIC_COMPACT_CNTRS_VER_1 (1) -#define WL_PERIODIC_TXBF_CNTRS_VER_1 (1) typedef struct { uint16 version; - uint16 pad; + uint16 PAD; /* taken from wl_wlc_cnt_t */ uint32 txfail; /* taken from wl_cnt_ge40mcst_v1_t */ @@ -19261,7 +21792,7 @@ typedef struct { #define WL_PERIODIC_COMPACT_CNTRS_VER_2 (2) typedef struct { uint16 version; - uint16 pad; + uint16 PAD; /* taken from wl_wlc_cnt_t */ uint32 txfail; /* taken from wl_cnt_ge40mcst_v1_t */ @@ -19323,7 +21854,7 @@ typedef struct { #define WL_PERIODIC_COMPACT_CNTRS_VER_3 (3) typedef struct { uint16 version; - uint16 pad; + uint16 PAD; /* taken from wl_wlc_cnt_t */ uint32 txfail; /* taken from wl_cnt_ge40mcst_v1_t */ @@ -19386,7 +21917,7 @@ typedef struct { #define WL_PERIODIC_COMPACT_CNTRS_VER_4 (4) typedef struct { uint16 version; - uint16 pad; + uint16 PAD; /* taken from wl_wlc_cnt_t */ uint32 txfail; /* taken from wl_cnt_ge40mcst_v1_t */ @@ -19453,9 +21984,83 @@ typedef struct { uint32 pktfilter_discard; /* Filtered packtets by pkt filter */ uint32 pktfilter_forward; /* Forwared packets by pkt filter */ uint32 mac_rxfilter; /* Pkts filtered due to class/auth state mismatch */ - } wl_periodic_compact_cntrs_v4_t; +#define WL_PERIODIC_COMPACT_CNTRS_VER_5 (5) +typedef struct { + uint16 version; + uint8 PAD; + uint8 link_id; /**< link id corr to slice. NOT cfg idx */ + /* taken from wl_wlc_cnt_t */ + uint32 txfail; + /* taken from wl_cnt_ge88mcst_v1_t */ + /* --------- TX ------------------- */ + uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txrtsfrm; /**< number of RTS sent out by the MAC */ + uint32 txctsfrm; /**< number of CTS sent out by the MAC */ + uint32 txback; /**< blockack txcnt */ + uint32 txucast; /**< number of unicast tx expecting response other than cts/cwcts */ + uint32 txnoack; /**< dot11ACKFailureCount */ + uint32 txframe; /**< tx data frames */ + uint32 txretrans; /**< tx mac retransmits */ + uint32 txpspoll; /**< Number of TX PS-poll */ + uint32 txrtsfail; /**< number of rts transmission failure that reach retry limit */ + uint32 tx_toss_cnt; /* number of tx packets tossed */ + uint32 last_tx_toss_rsn; /* reason because of which last tx pkt tossed */ + uint32 txbcnfrm; /**< beacons transmitted */ + + /* --------- RX ------------------- */ + uint32 rxrsptmout; /**< number of response timeouts for transmitted frames + * expecting a response + */ + uint32 rxstrt; /**< number of received frames with a good PLCP */ + uint32 rxbadplcp; /**< number of parity check of the PLCP header failed */ + uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ + uint32 rxnodelim; /**< number of no valid delimiter detected by ampdu parser */ + uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ + uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ + uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ + uint32 rxf0ovfl; /**< number of receive fifo 0 overflows */ + uint32 rxf1ovfl; /**< number of receive fifo 0 overflows */ + uint32 rxhlovfl; /**< number of length / header fifo overflows */ + uint32 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */ + uint32 rxctsucast; /**< number of unicast CTS addressed to the MAC (good FCS) */ + uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */ + uint32 rxback; /**< blockack rxcnt */ + uint32 rxbeaconmbss; /**< beacons received from member of BSS */ + uint32 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */ + uint32 rxbeaconobss; /**< beacons received from other BSS */ + uint32 rxdtucastobss; /**< number of unicast frames addressed to the MAC from + * other BSS (WDS FRAME) + */ + uint32 rxdtocast; /**< number of received DATA frames (good FCS and no matching RA) */ + uint32 rxrtsocast; /**< number of received RTS not addressed to the MAC */ + uint32 rxctsocast; /**< number of received CTS not addressed to the MAC */ + uint32 rxdtmcast; /**< number of RX Data multicast frames received by the MAC */ + uint32 rxmpdu_mu; /**< Number of MU MPDUs received */ + uint32 rxtoolate; /**< receive too late */ + uint32 rxframe; /**< rx data frames */ + uint32 rx_toss_cnt; /* number of rx packets tossed */ + uint32 last_rx_toss_rsn; /* reason because of which last rx pkt tossed */ + uint32 rxretry; /* Number of rx packets received after retry */ + uint32 rxdup; /* Number of dump packet. Indicates whether peer is receiving ack */ + uint32 rxholes; /* Count of missed packets from peer */ + uint32 rxundec; /* Decrypt failures */ + uint32 rxundec_mcst; /* Decrypt failures multicast */ + uint16 replay; /* replay failures */ + uint16 replay_mcst; /* ICV failures */ + + /* -------------OTHERS--------------- */ + uint32 lqcm_report; /**< lqcm metric tx/rx idx */ + uint32 chswitch_cnt; /* Number of channel switches */ + uint32 pm_dur; /* Total sleep time in PM, msecs */ + uint32 pktfilter_discard; /* Filtered packtets by pkt filter */ + uint32 pktfilter_forward; /* Forwared packets by pkt filter */ + uint32 mac_rxfilter; /* Pkts filtered due to class/auth state mismatch */ +} wl_periodic_compact_cntrs_v5_t; + #define WL_PERIODIC_COMPACT_HE_CNTRS_VER_1 (1) typedef struct { uint16 version; @@ -19502,6 +22107,38 @@ typedef struct { uint32 he_null_fifo_empty; } wl_compact_he_cnt_wlc_v2_t; +#define WL_PERIODIC_COMPACT_HE_CNTRS_VER_3 (3) +typedef struct { + uint16 version; + uint16 len; + uint8 link_id; + uint8 pad[3]; + uint32 he_rxtrig_myaid; + uint32 he_rxtrig_rand; + uint32 he_colormiss_cnt; + uint32 he_txmampdu; + uint32 he_txmtid_back; + uint32 he_rxmtid_back; + uint32 he_rxmsta_back; + uint32 he_txfrag; + uint32 he_rxdefrag; + uint32 he_txtrig; + uint32 he_rxtrig_basic; + uint32 he_rxtrig_murts; + uint32 he_rxtrig_bsrp; + uint32 he_rxhemuppdu_cnt; + uint32 he_physu_rx; + uint32 he_phyru_rx; + uint32 he_txtbppdu; + uint32 he_null_tbppdu; + uint32 he_rxhesuppdu_cnt; + uint32 he_rxhesureppdu_cnt; + uint32 he_null_zero_agg; + uint32 he_null_bsrp_rsp; + uint32 he_null_fifo_empty; +} wl_compact_he_cnt_wlc_v3_t; + +#define WL_PERIODIC_TXBF_CNTRS_VER_1 (1) /* for future versions of this data structure, can consider wl_txbf_ecounters_t * which contains the full list of txbf dump counters */ @@ -19519,6 +22156,23 @@ typedef struct { uint32 txsf; } wl_periodic_txbf_cntrs_v1_t; +#define WL_PERIODIC_TXBF_CNTRS_VER_2 (2) +typedef struct { + uint16 version; + uint8 link_id; + uint8 pad[3]; + uint16 coreup; + uint32 txndpa; + uint32 txndp; + uint32 rxsf; + uint32 txbfm; + uint32 rxndpa_u; + uint32 rxndpa_m; + uint32 bferpt; + uint32 rxbfpoll; + uint32 txsf; +} wl_periodic_txbf_cntrs_v2_t; + typedef struct { struct ether_addr BSSID; chanspec_t chanspec; @@ -19529,7 +22183,7 @@ typedef struct { typedef struct { uint8 version; uint8 flags; - uint16 pad; + uint16 PAD; int32 noise_level; /* current noise level */ wl_rx_signal_metric_t current_bss; wl_rx_signal_metric_t target_bss; @@ -19543,7 +22197,7 @@ typedef struct wl_if_state_compact { int8 noise_level; /**< noise right after tx (in dBm) */ int8 snr; /* current noise level */ int8 rssi_sum; /**< summed rssi across all antennas */ - uint16 pad16; + uint16 PAD; int8 rssi_ant[WL_RSSI_ANT_MAX]; /**< rssi per antenna */ struct ether_addr BSSID; chanspec_t chanspec; @@ -19553,8 +22207,9 @@ typedef struct wl_if_state_compact { /* Event based statistics ecounters */ typedef struct { uint16 version; - uint16 pad; + uint16 PAD; struct ether_addr BSSID; /* BSSID of the BSS */ + uint16 PAD; uint32 txdeauthivalclass; } wl_event_based_statistics_v1_t; @@ -19562,8 +22217,9 @@ typedef struct { /* Event based statistics ecounters */ typedef struct { uint16 version; - uint16 pad; + uint16 PAD; struct ether_addr BSSID; /* BSSID of the BSS */ + uint16 PAD; uint32 txdeauthivalclass; /* addition for v2 */ int32 timestamp; /* last deauth time */ @@ -19577,7 +22233,7 @@ typedef struct { /* Event based statistics ecounters */ typedef struct { uint16 version; - uint16 pad; + uint16 PAD; struct ether_addr BSSID; /* BSSID of the BSS */ uint16 PAD; uint32 txdeauthivalclass; @@ -19604,13 +22260,14 @@ typedef struct { uint16 full_roam_scan_cnt; uint16 most_roam_reason; uint16 most_roam_reason_cnt; + uint16 PAD; } wl_event_based_statistics_v3_t; #define WL_EVENT_STATISTICS_VER_4 (4u) /* Event based statistics ecounters */ typedef struct { uint16 version; - uint16 pad; + uint16 PAD; struct ether_addr BSSID; /* BSSID of the BSS */ uint16 PAD; uint32 txdeauthivalclass; @@ -19627,7 +22284,7 @@ typedef struct { #define WL_SC_PERIODIC_COMPACT_CNTRS_VER_1 (1) typedef struct { uint16 version; - uint16 pad; + uint16 PAD; uint32 rxstrt; /**< number of received frames with a good PLCP */ uint32 rxbadplcp; /**< number of parity check of the PLCP header failed */ uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ @@ -19652,16 +22309,48 @@ typedef struct { uint16 sc_down_cnt; /* Number of times sc down happened */ } wl_sc_periodic_compact_cntrs_v1_t; +#define WL_SC_PERIODIC_COMPACT_CNTRS_VER_2 (2) +typedef struct { + uint16 version; + uint8 PAD; + uint8 link_id; /**< link id corr to slice. NOT cfg idx */ + /* -----RX------------- */ + uint32 rxstrt; /**< number of received frames with a good PLCP */ + uint32 rxbadplcp; /**< number of parity check of the PLCP header failed */ + uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ + uint32 rxnodelim; /**< number of no valid delimiter detected by ampdu parser */ + uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ + uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ + uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ + uint16 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */ + uint16 rxf0ovfl; /**< number of receive fifo 0 overflows */ + uint16 rxf1ovfl; /**< number of receive fifo 0 overflows */ + uint16 rxhlovfl; /**< number of length / header fifo overflows */ + uint16 rxbeaconmbss; /**< beacons received from member of BSS */ + uint16 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */ + uint16 rxbeaconobss; /**< beacons received from other BSS */ + uint16 rxdtmcast; /**< number of RX Data multicast frames received by the MAC */ + uint16 rxtoolate; /**< receive too late */ + + /* --------OTHERS------------ */ + uint16 chswitch_cnt; /* Number of channel switches */ + uint32 pm_dur; /* Total sleep time in PM, msecs */ + uint16 hibernate_cnt; /* Number of times sc went to hibernate */ + uint16 awake_cnt; /* Number of times sc awake is called */ + uint16 sc_up_cnt; /* Number of times sc up/down happened */ + uint16 sc_down_cnt; /* Number of times sc down happened */ +} wl_sc_periodic_compact_cntrs_v2_t; + #define WL_WBUS_PERIODIC_CNTRS_VER_1 (1) typedef struct { uint16 version; - uint16 pad; + uint16 PAD; uint16 num_register; /* Number of registrations */ uint16 num_deregister; /* Number of deregistrations */ uint8 num_pending; /* Number of pending non-bt */ uint8 num_active; /* Number of active non-bt */ uint8 num_bt; /* Number of bt users */ - uint8 pad1; + uint8 PAD; uint16 num_rej; /* Number of reject */ uint16 num_rej_bt; /* Number of rejects for bt */ uint16 num_accept_attempt; /* Numbber of accept attempt */ @@ -19671,7 +22360,7 @@ typedef struct { #define WL_STA_OFLD_CNTRS_VER_1 (1) typedef struct { uint16 version; - uint16 pad; + uint16 PAD; uint16 sc_ofld_enter_cnt; uint16 sc_ofld_exit_cnt; @@ -19682,6 +22371,24 @@ typedef struct { uint8 sc_ofld_last_enter_fail_reason; } wl_sta_ofld_cntrs_v1_t; +#define WL_STA_OFLD_CNTRS_VER_2 (2u) +typedef struct { + uint16 version; + uint16 PAD; + + uint16 sc_ofld_enter_cnt; /* offload entry cnt */ + uint16 sc_ofld_exit_cnt; /* offload exit cnt */ + uint16 sc_ofld_wbus_reject_cnt; /* wbus rejected cnt */ + uint16 sc_ofld_wbus_cb_fail_cnt; /* wbus callbk fail cnt */ + uint16 sc_ofld_missed_bcn_cnt; /* missed bcn cnt */ + uint8 sc_ofld_last_exit_reason; /* reason of last exit */ + uint8 PAD[5]; + uint32 sc_ofld_last_enter_fail_reason; /* reason preventing entry */ + uint32 sc_ofld_last_sc_bcn_ts; /* SC ofld last bcn ts */ + uint32 sc_ofld_last_enter_ts; /* SC ofld last enter ts */ + uint32 sc_ofld_last_exit_ts; /* SC ofld last exit ts */ +} wl_sta_ofld_cntrs_v2_t; + /* ##### Ecounters v2 section ##### */ #define ECOUNTERS_VERSION_2 2 @@ -19700,7 +22407,7 @@ typedef struct ecounters_config_request_v2 { uint16 logset; /* Set where data will go. */ uint16 reporting_period; /* reporting_period */ uint16 num_reports; /* Number of timer expirations to report on */ - uint8 pad[2]; /* Reserved for future use */ + uint8 PAD[2]; /* Reserved for future use */ uint8 ecounters_xtlvs[]; /* Statistics Types (tags) to retrieve. */ } ecounters_config_request_v2_t; @@ -19721,7 +22428,7 @@ typedef struct ecounters_stats_types_report_req { uint16 flags; uint16 if_index; /* host interface index */ uint16 slice_mask; /* bit0 = slice0, bit1=slice1, rest reserved */ - uint8 pad[2]; /* padding */ + uint8 PAD[2]; /* padding */ uint8 stats_types_req[]; /* XTLVs of requested types */ } ecounters_stats_types_report_req_t; @@ -19735,7 +22442,7 @@ typedef struct event_ecounters_config_request_v2 { uint16 logset; /* Set where data will go. */ uint16 event_id; /* Event id for which this config is meant for */ uint8 flags; /* Config flags */ - uint8 pad[3]; /* Reserved for future use */ + uint8 PAD[3]; /* Reserved for future use */ uint8 ecounters_xtlvs[]; /* Statistics Types (tags) to retrieve. */ } event_ecounters_config_request_v2_t; @@ -19882,7 +22589,7 @@ typedef struct wpa_gtk { /** FBT Auth Response Data structure */ typedef struct wlc_fbt_auth_resp { uint8 macaddr[ETHER_ADDR_LEN]; /**< station mac address */ - uint8 pad[2]; + uint8 PAD[2]; uint8 pmk_r1_name[WPA2_PMKID_LEN]; wpa_ptk_t ptk; /**< pairwise key */ wpa_gtk_t gtk; /**< group key */ @@ -19890,7 +22597,7 @@ typedef struct wlc_fbt_auth_resp { uint8 status; /**< Status of parsing FBT authentication Request in application */ - uint8 ies[1]; /**< IEs contains MDIE, RSNIE, + uint8 ies[BCM_FLEX_ARRAY]; /**< IEs contains MDIE, RSNIE, FBTIE (ANonce, SNonce,R0KH-ID, R1KH-ID) */ } wlc_fbt_auth_resp_t; @@ -19901,7 +22608,7 @@ typedef struct wlc_fbt_action_resp { uint16 length; /**< length of structure */ uint8 macaddr[ETHER_ADDR_LEN]; /**< station mac address */ uint8 data_len; /**< len of ie from Category */ - uint8 data[1]; /**< data contains category, action, sta address, target ap, + uint8 data[BCM_FLEX_ARRAY]; /**< data contains category, action, sta address, target ap, status code,fbt response frame body */ } wlc_fbt_action_resp_t; @@ -20033,7 +22740,7 @@ typedef struct mu_rate { /** IOVAR 'mu_group' parameter. Used to set and read MU group recommendation setting */ #define WL_MU_GROUP_AUTO_COMMAND -1 -#define WL_MU_GROUP_PARAMS_VERSION 3 +#define WL_MU_GROUP_PARAMS_VERSION_3 3 #define WL_MU_GROUP_METHOD_NAMELEN 64 #define WL_MU_GROUP_NGROUP_MAX 15 #define WL_MU_GROUP_NUSER_MAX 4 @@ -20069,7 +22776,7 @@ typedef struct mupkteng_sta { } mupkteng_sta_t; typedef struct mupkteng_client { - int32 rspec; + ratespec_t rspec; int32 idx; int32 flen; int32 nframes; @@ -20092,7 +22799,7 @@ typedef struct mupkteng_tx { #define WL_MUPKTENG_PER_TX_STOP 0x20 /** IOVAR 'mu_policy' parameter. Used to configure MU admission control policies */ -#define WL_MU_POLICY_PARAMS_VERSION 1 +#define WL_MU_POLICY_PARAMS_VERSION_1 1 #define WL_MU_POLICY_SCHED_DEFAULT 60 #define WL_MU_POLICY_DISABLED 0 #define WL_MU_POLICY_ENABLED 1 @@ -20145,15 +22852,39 @@ typedef enum { } ulb_bw_type_t; /* endif WL11ULB */ -#define WL_MESH_IOCTL_VERSION 1 +#define WL_MESH_IOCTL_VERSION_1 1 #define MESH_IOC_BUFSZ 512 /* sufficient ioc buff size for mesh */ +#ifdef WLMESH +typedef struct mesh_peer_info_ext { + mesh_peer_info_t peer_info; + uint8 PAD; + uint16 local_aid; /* AID generated by *local* to peer */ + uint32 entry_state; /* see MESH_PEER_ENTRY_STATE_ACTIVE etc; valid + * ONLY for internal peering requests + */ + int8 rssi; + uint8 PAD; + struct ether_addr ea; /* peer ea */ +} mesh_peer_info_ext_t; + +typedef struct mesh_peer_info_dump { + uint32 buflen; + uint32 version; + uint16 count; /* number of results */ + uint16 remaining; /* remaining rsults */ + mesh_peer_info_ext_t mpi_ext[BCM_FLEX_ARRAY]; +} mesh_peer_info_dump_t; + +#define WL_MESH_PEER_RES_FIXED_SIZE (OFFSETOF(mesh_peer_info_dump_t, mpi_ext)) +#endif /* WLMESH */ + /* container for mesh ioctls & events */ typedef struct wl_mesh_ioc { uint16 version; /* interface command or event version */ uint16 id; /* mesh ioctl cmd ID */ uint16 len; /* total length of all tlv records in data[] */ - uint16 pad; /* pad to be 32 bit aligment */ + uint16 PAD; /* pad to be 32 bit aligment */ uint8 data[]; /* var len payload of bcm_xtlv_t type */ } wl_mesh_ioc_t; @@ -20181,7 +22912,7 @@ enum wl_mesh_cmd_xtlv_id { /* endif WLMESH */ /* Fast BSS Transition parameter configuration */ -#define FBT_PARAM_CURRENT_VERSION 0 +#define FBT_PARAM_VERSION_0 0u typedef struct _wl_fbt_params { uint16 version; /* version of the structure @@ -20191,7 +22922,7 @@ typedef struct _wl_fbt_params { uint16 param_type; /* type of parameter defined below */ uint16 param_len; /* length of the param_value */ - uint8 param_value[1]; /* variable length */ + uint8 param_value[BCM_FLEX_ARRAY]; /* variable length */ } wl_fbt_params_t; #define WL_FBT_PARAM_TYPE_RSNIE 0 @@ -20204,7 +22935,8 @@ typedef struct _wl_fbt_params { #define WL_FBT_PARAM_TYPE_FIRST_INVALID 0x7 /* Assoc Mgr commands for fine control of assoc */ -#define WL_ASSOC_MGR_CURRENT_VERSION 0x0 +#define WL_ASSOC_MGR_VERSION_0 0u +#define WL_ASSOC_MGR_CURRENT_VERSION 0x0 typedef struct { uint16 version; /* version of the structure as @@ -20213,7 +22945,11 @@ typedef struct { uint16 length; /* length of the entire structure */ uint16 cmd; - uint16 params; + + union { /* the command buffer may end in a simple uint16 params, */ + uint16 params; /* or may have a variable length set of parameters */ + uint8 data[1]; /* represented by the 'data' member. */ + }; } wl_assoc_mgr_cmd_t; enum wl_sae_auth_xtlv_id { @@ -20296,6 +23032,10 @@ enum { }; typedef enum { +/* The complete enum definition should be moved to bcmevent.h. + * When add new, add it to bcmevent.h + */ +#if !defined(WL_CHANSW_REASONS_0TO13_INCLUDED) CHANSW_UNKNOWN = 0, /* channel switch due to unknown reason */ CHANSW_SCAN = 1, /* channel switch due to scan */ CHANSW_PHYCAL = 2, /* channel switch due to phy calibration */ @@ -20306,15 +23046,11 @@ typedef enum { CHANSW_IOVAR = 7, /* channel switch due to IOVAR */ CHANSW_CSA_DFS = 8, /* channel switch due to chan switch announcement from AP */ CHANSW_APCS = 9, /* Channel switch from AP channel select module */ - -#ifdef WLAWDL - CHANSW_AWDL = 10, /* channel switch due to AWDL */ -#endif /* WLAWDL */ - CHANSW_FBT = 11, /* Channel switch from FBT module for action frame response */ CHANSW_UPDBW = 12, /* channel switch at update bandwidth */ CHANSW_ULB = 13, /* channel switch at ULB */ - CHANSW_LAST = 14 /* last channel switch reason */ +#endif /* WL_CHANSW_REASONS_0TO13_INCLUDED */ + CHANSW_DUMMY /* dummy entry to avoid empty enum */ } chansw_reason_t; /* @@ -20329,7 +23065,7 @@ typedef struct nd_ra_ol_limits { uint16 version; /* version of the iovar buffer */ uint16 type; /* type of data provided */ uint16 length; /* length of the entire structure */ - uint16 pad1; /* pad union to 4 byte boundary */ + uint16 PAD; /* pad union to 4 byte boundary */ union { struct { uint16 min_time; /* seconds, min time for RA offload hold */ @@ -20338,7 +23074,7 @@ typedef struct nd_ra_ol_limits { } lifetime_relative; struct { uint16 hold_time; /* seconds, RA offload hold time */ - uint16 pad2; /* unused */ + uint16 PAD; /* unused */ } fixed; } limits; } nd_ra_ol_limits_t; @@ -20364,8 +23100,8 @@ typedef struct wl_temp_control { /* SensorHub Interworking mode */ -#define SHUB_CONTROL_VERSION 1 -#define SHUB_CONTROL_LEN 12 +#define SHUB_CONTROL_VERSION_1 1u +#define SHUB_CONTROL_LEN 12u typedef struct { uint16 verison; @@ -20401,7 +23137,7 @@ typedef struct rsdb_caps_response { uint8 rsdb; /* TRUE for rsdb chip */ uint8 num_of_cores; /* no of d11 cores */ uint16 flags; /* Flags to indicate various capabilities */ - uint8 num_chains[1]; /* Tx/Rx chains for each core */ + uint8 num_chains[BCM_FLEX_ARRAY]; /* Tx/Rx chains for each core */ } rsdb_caps_response_t; /* Data structures for rsdb bands */ @@ -20414,7 +23150,7 @@ typedef struct rsdb_bands uint8 ver; uint8 len; uint16 num_cores; /* num of D11 cores */ - int16 band[1]; /* The band operating on each of the d11 cores */ + int16 band[BCM_FLEX_ARRAY]; /* The band operating on each of the d11 cores */ } rsdb_bands_t; /* rsdb config */ @@ -20444,7 +23180,7 @@ typedef struct rsdb_config { rsdb_opmode_t infra_mode[MAX_BANDS]; rsdb_flags_t flags[MAX_BANDS]; rsdb_opmode_t current_mode; /* Valid only in GET, returns the current mode */ - uint8 pad[3]; + uint8 PAD[3]; } rsdb_config_t; /* WLC_MAJOR_VER > =5 */ @@ -20472,21 +23208,21 @@ typedef struct rsdb_caps_response_v1 { typedef struct rsdb_bands_v1 { uint8 num_cores; /* num of D11 cores */ - uint8 pad; /* padding bytes for 4 byte alignment */ + uint8 PAD; /* padding bytes for 4 byte alignment */ int8 band[MAX_NUM_D11CORES]; /* The band operating on each of the d11 cores */ } rsdb_bands_v1_t; typedef struct rsdb_config_xtlv { rsdb_opmode_t reserved1; /* Non_infra mode is no more applicable */ rsdb_opmode_t infra_mode[MAX_BANDS]; /* Target mode for Infra association */ - uint8 pad; /* pad bytes for 4 byte alignment */ + uint8 PAD; /* pad bytes for 4 byte alignment */ rsdb_flags_t flags[MAX_BANDS]; rsdb_opmode_t current_mode; /* GET only; has current mode of operation */ - uint8 pad1[3]; + uint8 PAD[3]; } rsdb_config_xtlv_t; /* Definitions for slot_bss chanseq iovar */ -#define WL_SLOT_BSS_VERSION 1 +#define WL_SLOT_BSS_VERSION_1 1 /* critical slots max size */ #define WL_SLOTTED_BSS_CS_BMP_CFG_MAX_SZ 128 /* arbitrary */ @@ -20534,16 +23270,16 @@ typedef struct chan_seq_tlv { typedef struct sb_channel_sequence { sched_flag_t sched_flags; /* (sdb-tdm or sdb-sb or Dual-Time) */ uint8 num_seq; /* number of chan_seq_tlv following */ - uint16 pad; - chan_seq_tlv_t seq[1]; + uint16 PAD; + chan_seq_tlv_t seq[BCM_FLEX_ARRAY]; } sb_channel_sequence_t; typedef struct slice_chan_seq { uint8 slice_index; /* 0(Main) or 1 (Aux) */ uint8 num_chanspecs; uint8 dur; - uint8 pad; - chanspec_t chanspecs[1]; + uint8 PAD; + chanspec_t chanspecs[BCM_FLEX_ARRAY]; } slice_chan_seq_t; #define SLOT_BSS_SLICE_TYPE_DUR_MAX_RANGE 2u @@ -20553,8 +23289,8 @@ typedef struct slice_chan_seq { #define WL_SLICE_CHAN_SEQ_FIXED_LEN OFFSETOF(slice_chan_seq_t, chanspecs) /* Definitions for slotted_bss stats */ -#define SBSS_STATS_VERSION 1 -#define SBSS_STATS_CURRENT_VERSION SBSS_STATS_VERSION + +#define SBSS_STATS_VERSION_1 1 #define SBSS_MAX_CHAN_STATS 4 @@ -20567,6 +23303,7 @@ typedef struct sbss_core_stats { typedef struct sbss_chan_stats { chanspec_t chanspec; + uint16 PAD; uint32 slot_start; uint32 slot_end; uint32 slot_skip; @@ -20582,7 +23319,7 @@ typedef struct sbss_stats_v1 { /* slotted bss critical slots */ typedef struct wl_sbss_cs_bmp_s { uint8 bitmap_len; - uint8 pad[3]; + uint8 PAD[3]; uint8 bitmap[]; } wl_sbss_cs_bmp_t; @@ -20612,6 +23349,9 @@ typedef struct wl_nap_status_v1 { #define NAP_DISABLED_ACI 0x0020 /* Disabled because of ACI mitigation */ #define NAP_DISABLED_SEQ_RANGE 0x0040 /* Disabled during SEQ Ranging */ #define NAP_DISABLED_CHANSWITCH 0x0080 /* Disabled during channel switch */ +#define NAP_DISABLED_AZ 0x0100 /* Disabled during 802.11az ranging */ +#define NAP_DISABLED_PHYTS 0x0200 /* Disabled during PHYTS */ +#define NAP_DISABLED_CAL 0x0400 /* Disabled during rxiqcal */ /* Bits for hw_status */ #define NAP_HWCFG 0x01 /* State of NAP config bit in phy HW */ @@ -20663,7 +23403,7 @@ typedef struct { uint16 dst_port_num; /* for SIP type protocol, dst_port_num info can be ignored by FW */ uint32 ip; /* for SIP ip is APcli_ip and for port clash it is dst_ip */ uint8 entry_type; /* Create/Destroy */ - uint8 pad[3]; + uint8 PAD[3]; } wl_natoe_exception_port_t; /* container for natoe ioctls & events */ @@ -20671,7 +23411,7 @@ typedef struct wl_natoe_ioc { uint16 version; /* interface command or event version */ uint16 id; /* natoe ioctl cmd ID */ uint16 len; /* total length of all tlv records in data[] */ - uint16 pad; /* pad to be 32 bit aligment */ + uint16 PAD; /* pad to be 32 bit aligment */ uint8 data[]; /* var len payload of bcm_xtlv_t type */ } wl_natoe_ioc_t; @@ -20751,6 +23491,7 @@ typedef struct wl_natoe_dbg_stats_v1 { uint8 pubnw_cfg_ID; uint8 pvtnw_cfg_ID; uint16 natoe_flags; + uint16 PAD; } wl_natoe_dbg_stats_v1_t; typedef struct wl_natoe_exception_port_inf_v1 { @@ -20763,6 +23504,7 @@ typedef struct wl_natoe_dstnat_entry_v1 { struct ether_addr client_mac_addr; uint16 client_listenport; uint8 opcode; + uint8 PAD; } wl_natoe_dstnat_entry_v1_t; typedef struct wl_pcie_frwd_stats_v1 { @@ -20831,7 +23573,8 @@ enum wl_idauth_xtlv_id { WL_IDAUTH_XTLV_BLKLIST_COUNT = 0x5, WL_IDAUTH_XTLV_BLKLIST_AGE = 0x6, WL_IDAUTH_XTLV_PEERS_INFO = 0x7, - WL_IDAUTH_XTLV_COUNTERS = 0x8 + WL_IDAUTH_XTLV_COUNTERS = 0x8, + WL_IDAUTH_XTLV_PTK_ROTATION = 0x9 }; enum wl_idauth_stats { WL_AUTH_PEER_STATE_AUTHORISED = 0x01, @@ -20879,6 +23622,8 @@ typedef struct wl_utrace_capture_args_v2 { #define WLC_REGVAL_DUMP_PHYREG 0 #define WLC_REGVAL_DUMP_RADREG 1 +#define WLC_REGVAL_DUMP_RFEMREG 2 +#define WLC_REGVAL_DUMP_SRCBREG 3 #define PHYREGVAL_CAPTURE_BUFFER_LEN 2048 @@ -20926,6 +23671,7 @@ enum { WL_HC_RX_XTLV_ID_VAL_STALL_FORCE = 5, /* stall test trigger */ WL_HC_RX_XTLV_ID_VAL_STALL_UC_DECRYPT_FAIL = 6, /* trigger uc decrypt failures */ WL_HC_RX_XTLV_ID_VAL_STALL_BCMC_DECRYPT_FAIL = 7, /* trigger bcmc decrypt failures */ + WL_HC_RX_XTLV_ID_VAL_STALL_NOUDATA_TO_RXRTS = 8, /* No data to RX CTS TX CTS */ }; /* Health Check: Datapath SCAN IDs */ @@ -20964,12 +23710,9 @@ typedef enum wl_hc_dd_type { WL_HC_DD_TXQ_STALL = 7, /* TXQ stall */ WL_HC_DD_RX_STALL_V2 = 8, /* RX stall check v2 */ -#ifdef WLAWDL - WL_HC_DD_AWDL = 9, /* AWDL health check */ -#endif /* WLAWDL */ - WL_HC_DD_SBSS =10, /* Slotted bss health check */ WL_HC_DD_NAN =11, /* NAN health check */ + WL_HC_DD_CHSW =12, /* Channel Switch health check */ WL_HC_DD_MAX } wl_hc_dd_type_t; @@ -20982,6 +23725,9 @@ typedef enum bcm_rx_hc_stall_reason { BCM_RX_HC_UNICAST_REPLAY = 4, /* Unicast replay */ BCM_RX_HC_BCMC_REPLAY = 5, /* BCMC replay */ BCM_RX_HC_AMPDU_DUP = 6, /* AMPDU DUP */ + BCM_RX_HC_BCMC_KEYIDMATCH_FAIL = 7, /* BCMC decrypt fail due to key index mismatch */ + /* Stall because no unicast data frames for RX RTS TX CTS transaction */ + BCM_RX_HC_NOUDATA_RXRTS_TXCTS = 8, BCM_RX_HC_MAX } bcm_rx_hc_stall_reason_t; @@ -21031,6 +23777,7 @@ typedef struct { uint32 rx_hc_alert_th; uint32 reason; /* refer to bcm_rx_hc_stall_reason_t above */ struct ether_addr peer_ea; + uint8 PAD[2]; /* Reserved */ } wl_rx_hc_info_v2_t; /* HE top level command IDs */ @@ -21055,6 +23802,10 @@ enum { WL_HE_CMD_ULMU_DISABLE_STATS = 17u, WL_HE_CMD_OMI_DLMU_RSD_RCM_MPF_MAP = 18u, WL_HE_CMD_SR_PROHIBIT = 19u, + WL_HE_CMD_TRIG_PREFERRED_AC_ENAB = 20u, + WL_HE_CMD_ULMU_DISABLE_NS_TXPWR = 21u, + WL_HE_CMD_ULMU_FAKE_NS_TXPWR = 22u, + WL_HE_CMD_RXMPDU_MAXLEN_4K_ENAB = 23u, WL_HE_CMD_LAST }; @@ -21064,6 +23815,23 @@ enum { WL_HE_MUEDCA_LAST }; +typedef enum _opmode_cap_t { + OMC_NONE = 0, /* no requirements for STA to associate to BSS */ + OMC_ERP = 1, /* STA must advertise ERP (11g) capabilities + * to be allowed to associate to 2G band BSS. + */ + OMC_HT = 2, /* STA must advertise HT (11n) capabilities to + * be allowed to associate to the BSS. + */ + OMC_VHT = 3, /* Devices must advertise VHT (11ac) capabilities + * to be allowed to associate to the BSS. + */ + OMC_HE = 4, /* Devices must advertise HE (11ax) capabilities + * to be allowed to associate to the BSS. + */ + OMC_MAX +} opmode_cap_t; + #ifdef WL11AX /* struct for dump MU EDCA IE/SHM paramters */ @@ -21071,7 +23839,8 @@ typedef struct wl_he_muedca_ie_v1 { uint16 version; /* structure version */ uint16 length; /* data length (starting after this field) */ uint8 mu_qos_info; - he_mu_ac_param_record_t param_ac[AC_COUNT]; + he_mu_ac_param_record_t param_ac[AC_COUNT]; /* 3*4 */ + uint8 PAD; } wl_he_muedca_ie_v1_t; typedef wl_he_muedca_ie_v1_t wl_he_muedca_ie_t; @@ -21094,6 +23863,7 @@ enum { WL_TWT_CMD_CAP = 9, WL_TWT_CMD_STATUS = 10, WL_TWT_CMD_CONFIG = 11, + WL_TWT_CMD_BTWT_CONFIG = 12, WL_TWT_CMD_LAST }; @@ -21122,7 +23892,7 @@ typedef struct wl_heb_cnt_v1 { /* structure control */ uint16 version; /* structure version */ uint16 length; /* data length (starting after this field) */ - wl_heb_int_cnt_v1_t heb_int_cnt[1]; + wl_heb_int_cnt_v1_t heb_int_cnt[BCM_FLEX_ARRAY]; } wl_heb_cnt_v1_t; // struct for configuring HEB @@ -21150,6 +23920,7 @@ typedef struct wl_heb_blk_params_v1 { uint16 param1; uint8 event_count; uint8 noa_invert; + uint32 pre_end_event_intmsk_bmp; } wl_heb_blk_params_v1_t; typedef struct wl_heb_int_status_v1 { @@ -21160,7 +23931,7 @@ typedef struct wl_heb_int_status_v1 { typedef struct wl_heb_status_v1 { uint16 version; /* structure version */ uint16 length; /* data length (starting after this field) */ - wl_heb_reg_status_v1_t heb_status[1]; + wl_heb_reg_status_v1_t heb_status[BCM_FLEX_ARRAY]; } wl_heb_status_v1_t; /* HWA */ @@ -21209,11 +23980,7 @@ typedef struct wl_hwa_cnts_v1 { #define HWA_SUBMODULES_NUM 8u /**< number of submodules */ #define HWA_SUBMODULES_ALL 0xFF /* Bitmaps for all submodules */ -#ifdef HWA -#define HWA_SUBMODULE_MASK(submodule) (1u << (submodule)) -#else #define HWA_SUBMODULE_MASK(submodule) (0) -#endif /* HWA */ /* * NOTES: * wl_twt_sdesc_t is used to support both broadcast TWT and individual TWT. @@ -21227,10 +23994,11 @@ typedef struct wl_hwa_cnts_v1 { */ /* TWT Setup descriptor */ -typedef struct wl_twt_sdesc { + +typedef struct wl_twt_sdesc_v0 { /* Setup Command. */ - uint8 setup_cmd; /* See TWT_SETUP_CMD_XXXX in 802.11ah.h */ - uint8 flow_flags; /* Flow attributes. See WL_TWT_FLOW_FLAG_XXXX below */ + uint8 setup_cmd; /* See TWT_SETUP_CMD_XXXX in 802.11ah.h */ + uint8 flow_flags; /* Flow attributes. See WL_TWT_FLOW_FLAG_XXXX below */ uint8 flow_id; /* must be between 0 and 7. Set 0xFF for auto assignment */ uint8 bid; /* must be between 0 and 31. Set 0xFF for auto assignment */ uint8 channel; /* Twt channel - Not used for now */ @@ -21244,13 +24012,12 @@ typedef struct wl_twt_sdesc { uint32 btwt_persistence; /* Broadcast TWT Persistence */ uint32 wake_int_max; /* max wake interval(uS) for TWT */ uint8 duty_cycle_min; /* min duty cycle for TWT(Percentage) */ - uint8 pad; + uint8 PAD; /* deprecated - to be removed */ uint16 li; -} wl_twt_sdesc_t; +} wl_twt_sdesc_v0_t; #define WL_TWT_SETUP_DESC_VER 1u - /* TWT Setup descriptor (Version controlled) */ typedef struct wl_twt_sdesc_v1 { /* structure control */ @@ -21283,7 +24050,9 @@ typedef struct wl_twt_cdesc { uint16 version; /* structure version */ uint16 length; /* data length (starting after this field) */ uint8 negotiation_type; /* Negotiation Type: See macros TWT_NEGO_TYPE_X */ - uint8 PAD[3]; + uint8 configID; /* TWT Configuration ID */ + uint8 flow_flags; /* Flow Flags Configuration. See WL_TWT_FLOW_FLAG_XXXX */ + uint8 PAD; uint32 wake_time_h; /* target wake time - BSS TSF (us) */ uint32 wake_time_l; uint32 wake_dur; /* target wake duration in unit of microseconds */ @@ -21293,6 +24062,7 @@ typedef struct wl_twt_cdesc { uint32 wake_dur_min; /* Min. wake duration allowed for TWT Setup */ uint32 wake_dur_max; /* Max. wake duration allowed for TWT Setup */ uint32 avg_pkt_num; /* Average Number of Packets per interval */ + uint32 avg_pkt_size; /* Average packet size for TWT SP */ } wl_twt_cdesc_t; /* Flow flags */ @@ -21316,6 +24086,14 @@ typedef struct wl_twt_cdesc { #define WL_TWT_INV_BCAST_ID 0xFFu #define WL_TWT_INV_FLOW_ID 0xFFu +#define WL_TWT_INV_CONFIG_ID 0xFFu +#define WL_TWT_ALL_TWT_CONFIG_ID 0u /* ConfigID 0 corresponds to All TWT */ + +#define WL_TWT_INV_WAKE_DUR 0xFFFFFFFFu +#define WL_TWT_INV_WAKE_INT 0xFFFFFFFFu +#define WL_TWT_INV_PKT_NUM 0xFFFFFFFFu +#define WL_TWT_INV_PKT_SIZE 0xFFFFFFFFu +#define WL_TWT_INV_WAKE_TIME 0xFFFFFFFFu /* auto flow_id */ #define WL_TWT_SETUP_FLOW_ID_AUTO 0xFFu @@ -21332,10 +24110,11 @@ typedef struct wl_twt_cdesc { #define WL_TWT_STATS_MAX_BTWT WL_TWT_MAX_BTWT #define WL_TWT_STATS_MAX_ITWT WL_TWT_MAX_ITWT +/* TWT States */ #define WL_TWT_INACTIVE 0u /* Resource is not allotted */ -#define WL_TWT_RESERVED 1u /* Resource is allotted but HEB is not yet programmed */ -#define WL_TWT_ACTIVE 2u /* Resource is allotted and HEB is programmed */ -#define WL_TWT_SUSPEND 3u /* Resource is suspended and HEB released */ +#define WL_TWT_ACTIVE 1u /* Resource is allotted and HEB is programmed */ +#define WL_TWT_SUSPEND 2u /* Resource is suspended and HEB released */ +#define WL_TWT_RESERVED 3u /* Resource is allotted but HEB is not yet programmed */ /* Wake type */ /* TODO: not yet finalized */ @@ -21350,16 +24129,28 @@ typedef struct wl_twt_cdesc { #define WL_TWT_SETUP_VER 0u /* HE TWT Setup command */ -typedef struct wl_twt_setup { +typedef struct wl_twt_setup_v0 { /* structure control */ uint16 version; /* structure version */ uint16 length; /* data length (starting after this field) */ struct ether_addr peer; /* Peer address - leave it all 0s' for AP */ - uint8 pad[2]; - wl_twt_sdesc_t desc; /* Setup Descriptor */ + uint8 PAD[2]; + struct wl_twt_sdesc_v0 desc; uint16 dialog; /* Deprecated - to be removed */ - uint8 pad1[2]; -} wl_twt_setup_t; + uint8 PAD[2]; +} wl_twt_setup_v0_t; + +/* HE TWT Setup command */ +typedef struct wl_twt_setup_v1 { + /* structure control */ + uint16 version; /* structure version */ + uint16 length; /* data length (starting after this field) */ + struct ether_addr peer; /* Peer address - leave it all 0s' for AP */ + uint8 PAD[2]; + struct wl_twt_sdesc_v1 desc; + uint16 dialog; /* Deprecated - to be removed */ + uint8 PAD[2]; +} wl_twt_setup_v1_t; #define WL_TWT_CONFIG_VER 0u @@ -21369,7 +24160,7 @@ typedef struct wl_twt_config { uint16 version; /* structure version */ uint16 length; /* data length (starting after this field) */ struct ether_addr peer; /* Peer address. leave it all 0s' for AP */ - uint8 pad[2]; + uint8 PAD[2]; wl_twt_cdesc_t desc; /* Config Descriptor */ } wl_twt_config_t; @@ -21392,23 +24183,25 @@ typedef struct wl_twt_teardown { struct ether_addr peer; /* leave it all 0s' for AP */ wl_twt_teardesc_t teardesc; /* Teardown descriptor */ - /* deprecated - to be removed */ + /* deprecated - to be removed - Start here */ uint8 flow_flags; uint8 flow_id; uint8 bid; - uint8 pad; + /* deprecated - to be removed - End here */ + + uint8 configID; /* TWT Configuration ID */ } wl_twt_teardown_t; /* twt information descriptor */ typedef struct wl_twt_infodesc { uint8 flow_flags; /* See WL_TWT_INFO_FLAG_XXX below */ uint8 flow_id; - uint8 pad[2]; + uint8 PAD[2]; uint32 next_twt_h; uint32 next_twt_l; /* deprecated - to be removed */ uint8 wake_type; - uint8 pad1[3]; + uint8 PAD[3]; } wl_twt_infodesc_t; /* Flow flags */ @@ -21430,7 +24223,8 @@ typedef struct wl_twt_info { uint16 length; /* data length (starting after this field) */ /* peer address */ struct ether_addr peer; /* leave it all 0s' for AP */ - uint8 pad[2]; + uint8 configID; /* TWT Configuration ID */ + uint8 PAD[1]; wl_twt_infodesc_t infodesc; /* information descriptor */ /* deprecated - to be removed */ wl_twt_idesc_t desc; @@ -21443,14 +24237,19 @@ typedef struct wl_twt_info { #define WL_TWT_STATUS_FLAG_WAKE_STATE (1u << 1u) #define WL_TWT_STATUS_FLAG_WAKE_OVERRIDE (1u << 2u) -typedef struct wl_twt_status { +typedef struct wl_twt_status_v0 { uint8 state; /* TWT State */ uint8 heb_id; /* HEB ID */ - uint8 PAD[2]; + uint8 configID; /* TWT Configuration ID */ + uint8 PAD[1]; struct ether_addr peer; uint8 PAD[2]; - wl_twt_sdesc_t desc; /* TWT Descriptor */ -} wl_twt_status_t; + uint32 avg_pkt_num; /* Average Packet number per TWT SP Interval */ + uint32 avg_pkt_size; /* Average Packet size for TWT SP */ + struct wl_twt_sdesc_v0 desc; +} wl_twt_status_v0_t; + +typedef wl_twt_status_v0_t wl_twt_status_t; /* wl twt status output */ typedef struct wl_twt_status_v1 { @@ -21459,8 +24258,8 @@ typedef struct wl_twt_status_v1 { uint8 num_fid; /* Number of individual TWT setup */ uint8 num_bid; /* Number of Broadcast TWT setup */ uint16 status_flags; /* see WL_TWT_STATUS_FLAGS_XX */ - wl_twt_status_t itwt_status[WL_TWT_MAX_ITWT]; - wl_twt_status_t btwt_status[WL_TWT_MAX_BTWT]; + wl_twt_status_v0_t itwt_status[WL_TWT_MAX_ITWT]; + wl_twt_status_v0_t btwt_status[WL_TWT_MAX_BTWT]; } wl_twt_status_v1_t; /* wl twt status command input */ @@ -21468,7 +24267,8 @@ typedef struct wl_twt_status_cmd_v1 { uint16 version; uint16 length; struct ether_addr peer; - uint8 PAD[2]; + uint8 configID; + uint8 PAD; } wl_twt_status_cmd_v1_t; #define WL_TWT_PEER_STATS_VERSION_1 1u @@ -21501,6 +24301,40 @@ typedef struct wl_twt_stats_v1 { wl_twt_peer_stats_v1_t peer_stats_list[]; } wl_twt_stats_v1_t; +#define WL_TWT_PEER_STATS_VERSION_2 2u +typedef struct wl_twt_peer_stats_v2 { + uint16 version; + uint16 length; + struct ether_addr peer; + uint8 id; /* TWT session ID */ + uint8 flow_flags; + uint8 configID; /* TWT Configuration ID */ + uint8 PAD[3]; + uint32 sp_seq; /* sequence number of the service period */ + uint32 tx_ucast_pkts; /* Number of unicast Tx packets in TWT SPs */ + uint32 tx_pkts_min; /* Minimum number of Tx packets in a TWT SP */ + uint32 tx_pkts_max; /* Maximum number of Tx packets in a TWT SP */ + uint32 tx_pkts_avg; /* Average number of Tx packets in each TWT SP */ + uint32 tx_failures; /* Tx packets failure count */ + uint32 rx_ucast_pkts; /* Number of unicast Rx packets in TWT SPs */ + uint32 rx_pkts_min; /* Minimum number of Rx packets in a TWT SP */ + uint32 rx_pkts_max; /* Maximum number of Rx packets in a TWT SP */ + uint32 rx_pkts_avg; /* Average number of Rx packets in each TWT SP */ + uint32 rx_pkts_retried; /* retried Rx packets count */ + uint32 tx_pkt_sz_avg; /* Average Tx packet size in TWT SPs */ + uint32 rx_pkt_sz_avg; /* Average Rx Packet size in TWT SPs */ + uint32 eosp_dur_avg; /* Average Wake duration in SPs ended due to EOSP */ + uint32 eosp_count; /* Count of TWT SPs ended due to EOSP */ +} wl_twt_peer_stats_v2_t; + +#define WL_TWT_STATS_VERSION_2 2u +typedef struct wl_twt_stats_v2 { + uint16 version; + uint16 length; + uint32 num_stats; /* number of peer stats in the peer_stats_list */ + wl_twt_peer_stats_v2_t peer_stats_list[]; +} wl_twt_stats_v2_t; + #define WL_TWT_STATS_CMD_VERSION_1 1 #define WL_TWT_STATS_CMD_FLAGS_RESET (1u << 0u) /* HE TWT stats command */ @@ -21508,7 +24342,8 @@ typedef struct wl_twt_stats_cmd_v1 { uint16 version; uint16 length; struct ether_addr peer; - uint8 PAD[2]; + uint8 configID; /* TWT Configuration ID */ + uint8 PAD; uint16 flags; /* see WL_TWT_STATS_CMD_FLAGS */ uint8 num_fid; uint8 num_bid; @@ -21527,6 +24362,8 @@ typedef struct wl_twt_resp_cfg { uint16 length; /* Data length (starting after this field) */ uint8 dc_max; /* Max supported duty cycle for single TWT */ uint8 resp_type; /* Resp. type(Alt/dict) if duty cycle>max duty cycle */ + bool twt_resp_enab; /* TWT Responder Mode enable/disable */ + uint8 PAD; } wl_twt_resp_cfg_t; #define WL_TWT_CAP_CMD_VERSION_1 1u @@ -21553,16 +24390,463 @@ typedef struct wl_twt_cap_cmd { uint8 PAD[2]; } wl_twt_cap_cmd_t; +#define WL_TWT_BTWT_CONFIG_SCHED_BID0 (1u << 0u) /* Enable/disable BTWT id 0 schedule */ +#define WL_TWT_BTWT_TEARDOWN_BID0 (1u << 1u) /* Enable/disable teardown of BTWT + * with BTWT id 0 + */ + /* EHT sub command IDs */ enum { WL_EHT_CMD_ENAB = 0u, /* enable/disable EHT feature as a whole */ - WL_EHT_CMD_DBG = 1u, /* configure EHT debug facilities */ WL_EHT_CMD_FEATURES = 2u, /* configure EHT sub-features */ - WL_EHT_CMD_LAST + + WL_EHT_CMD_SIGMCS = 3u, /* configure EHT SIG MCS Index */ + WL_EHT_CMD_NUMLTF = 4u, /* configure EHT Number of LTFs */ + WL_EHT_CMD_NONHT_PUNC_PATT = 5u, /* configure nonHT puncture pattern */ + WL_EHT_CMD_PUNC_PAT = 6u, /* configure per BSS puncture pattern */ + WL_EHT_CMD_TESTBED_MODE = 7u, /* EHT Testbed STA Configuration */ + + /* Add new sub command IDs here... */ + + /* debug/test related sub-commands, mogrify? */ + WL_EHT_CMD_DBG = 0x1000u, /* configure EHT debug facilities */ }; +/* MLO sub command IDs */ +enum { + WL_MLO_CMD_ENAB = 0u, /* enable/disable MLO feature as a whole */ + WL_MLO_CMD_CONFIG = 1u, /* configure MLO feature - bsscfg specific */ + WL_MLO_CMD_STATUS = 2u, /* status on MLO feature - interface specific */ + WL_MLO_CMD_EMLSR_CTRL = 3u, /* emlsr control - interface specific */ + WL_MLO_CMD_TID_MAP = 4u, /* configure TID-To-Link Mapping */ + WL_MLO_CMD_CAP = 5u, /* capability of MLO feature as a whole */ + WL_MLO_CMD_ACT_LINK_BMAP = 6u, /* Set active link for MLO TX and RX */ + WL_MLO_CMD_MULTILINK_ACTIVE = 7u, /* Set use of multi links in MLO mode */ + WL_MLO_CMD_LINK_PS_BMAP = 8u, /* Modify PS state of a particular link in MLO. */ + /* Add new sub command IDs here... */ + + /* debug/test related sub-commands, mogrify? */ + WL_MLO_CMD_MLD_PRB = 0x1000u, /* send a mld probe request frame */ + WL_MLO_CMD_TID_MAP_NEG = 0x1001u, /* start a TID2Link Mapping negotiation */ + WL_MLO_CMD_MLD_AP_OP = 0x1002u, /* add/remove MLD AP(s) to/from MLD */ + WL_MLO_CMD_MLOSIM = 0x2000u, /* to set mlo simulation option */ +}; + +/* MLO config Flags definition */ +#define WL_MLO_USE_FW_GEN_LINKADDR (1u << 0u) /* fw generates the link addresses */ +#define WL_MLO_USE_FW_GEN_MLDADDR (1u << 1u) /* fw generates the mld address */ +#define WL_MLO_UPDATE_CHANNELS (1u << 2u) /* channels are present in the config req */ +#define WL_MLO_LINK_INTERFACES (1u << 3u) /* link existing interfaces as mlo links */ +#define WL_MLO_MLSR_MODE_ENAB (1u << 4u) /* Enable MLSR mode */ + +typedef struct wl_mlo_link_config_v1 { + struct ether_addr link_addr; /* Link specific address */ + chanspec_t chspec; /* Chanspec */ +} wl_mlo_link_config_v1_t; + +/* MLO modes of operation */ +#define MLO_STR (0u) +/* MLO_TDM is being deprecated, pls use MLO_EMLSR */ +#define MLO_TDM (1u) +#define MLO_EMLSR (1u) +#define MLO_AUTO (2u) +#define WL_MLO_MODE_INVALID (0xFFu) + +#define WL_MLO_CONFIG_VER_1 (1u) + +/* mlo status structure for an interface */ +/* ================================================== */ +#define WL_MLO_STATUS_VER_1 (1u) + +typedef struct wl_mlo_config_v1 { + uint16 version; + uint16 length; + uint32 flags; /* Flags */ + uint8 num_links; /* Number of links */ + uint8 mode; /* Mode of operation */ + struct ether_addr mld_addr; + wl_mlo_link_config_v1_t link_config[]; +} wl_mlo_config_v1_t; + +/* mlo info structure per link */ +typedef struct wl_mlo_link_status_v1 { + uint8 link_id; /* link ID - AP managed unique # */ + uint8 link_idx; /* link index - link config idx */ + struct ether_addr link_addr; /* Link specific address */ + chanspec_t chanspec; /* Chanspec */ +} wl_mlo_link_status_v1_t; + +/* Note: mlo mode for an interface is "operative" means + * - mode: value NOT 0. either STR and TDM. + * - for sta: mlo association; more than 1 link operative + * - for softap: more than 1 link operative for clients to join + * Note: 'operative' is different from active/PM or + * link disabled using tid2link mapping + * mlo mode for an interface is NOT "operative" means + * - when AP is down OR sta is down + * - when STA is not assoced OR associated in non mlo mode + * link_info array is present and has valid values only if mode is "operative" + */ +typedef struct wl_mlo_status_v1 { + uint16 version; + uint16 length; + struct ether_addr mld_addr; /* if mode is STR/TDM --> mld_addr + * else cfg->curether_addr + */ + uint8 mode; /* Present Mode of operation + * - MLO_STR, MLO_TDM + */ + uint8 num_links_operative; /* Number of operative links. see above */ + wl_mlo_link_status_v1_t link_status[]; /* status on operative links */ +} wl_mlo_status_v1_t; +/* ================================================== */ +#define WL_MLO_STATUS_VER_2 (2u) +/* peer's info for each link */ +typedef struct wl_mlo_link_peer_info_v2 { + struct ether_addr link_addr; /* peer Link specific address */ + struct ether_addr mld_addr; /* peer mld address. If this is 0, means + * legacy peer + */ +} wl_mlo_link_peer_info_v2_t; + +/* mlo info structure per link */ +typedef struct wl_mlo_link_status_v2 { + uint8 link_id; /* link ID - AP managed unique # */ + uint8 link_idx; /* link index - link config idx */ + struct ether_addr link_addr; /* Link specific address */ + chanspec_t chanspec; /* Chanspec */ + uint8 num_peers; /* number of peers for this link. For STA, this + * will be 1, for AP, can be multiple + */ + uint8 pad[1]; + wl_mlo_link_peer_info_v2_t pi[]; /* number of peers for this link */ +} wl_mlo_link_status_v2_t; + +/* see comments for wl_mlo_status_v1_t */ +typedef struct wl_mlo_status_v2 { + uint16 version; + uint16 length; + struct ether_addr mld_addr; /* if mode is STR/TDM --> mld_addr + * else cfg->curether_addr + */ + uint8 mode; /* Present Mode of operation + * - MLO_STR, MLO_TDM + */ + uint8 num_links_operative; /* Number of operative links. see above */ + uint8 link_status[]; /* status on operative links of + * type wl_mlo_link_status_v2_t + */ +} wl_mlo_status_v2_t; +/* ================================================== */ +/* mlo cap structure + * + * max_mlo_links : value 0 means MLO is unsupported + * max_str_links : value 0 means STR is unsupported + * max_emlsr_links : value 0 means EMLSR is unsupported + * + * The number of links is represented as the actual value similar to 'mlo config' IOVar and + * is not like how it is in the 11be MLO spec (num links - 1). + */ +#define WL_MLO_CAP_VER_1 (1u) + +typedef struct wl_mlo_cap_v1 { + uint16 version; + uint16 length; + uint8 max_mlo_links; /* Maximum number of MLO links supported */ + uint8 max_str_links; /* Maximum number of STR links supported */ + uint8 max_emlsr_links; /* Maximum number of EMLSR links supported */ + uint8 PAD; +} wl_mlo_cap_v1_t; + +// #ifdef EHT_MAC_SW_TEST +/* IDs list/ID extensions list */ +typedef struct wl_mlo_prb_ids_reqs { + uint8 pad[3]; + /* (Extended) Request parameters (max. 2 entries with max. 14 IDs each) */ + uint8 num_req; /* # valid reqs */ + struct { + uint8 id_base; /* 0 for Request IE; 255 for Extended Request IE */ + uint8 ids_num; /* # valid IDs */ + uint8 ids_list[14]; + } req[2]; +} wl_mlo_prb_ids_reqs_t; + +/* Per-STA profile parameters */ +typedef struct wl_mlo_prb_psta_prfs { + uint8 pad[3]; + /* Per-STA Profile parameters (max. 1 entry) */ + uint8 num_prf; /* # valid prfs */ + struct { + uint8 link_id; + uint8 cplt_sta_prf; /* complete/partial STA profile */ + uint8 pad[2]; + wl_mlo_prb_ids_reqs_t ids; + } prf[1]; +} wl_mlo_prb_psta_prfs_t; + +/* MLD probe parameters */ +typedef struct wl_probe_mld_parms { + uint8 flags; /* see WL_MLO_PRB_FLAG_x */ + uint8 mld_id; /* spec. MLD ID of this ML prbreq */ + uint8 pad[2]; + wl_mlo_prb_ids_reqs_t ids; /* Request IDs in reporting STA */ + wl_mlo_prb_psta_prfs_t psta; /* Per-STA profile for reported STA */ +} wl_probe_mld_parms_t; + +/* wl_probe_mld_parms_t.flags definitions */ +#define WL_MLO_PRB_FLAG_MLD_ID (1u << 0) /* mld_id field is present */ + +/* current mld prb subcommand */ +typedef struct wl_mlo_mld_prb_parms { + wl_probe_params_t probe; /* destination parameters */ + wl_probe_mld_parms_t mld; /* MLD probe parameters */ +} wl_mlo_mld_prb_parms_t; +// #endif /* EHT_MAC_SW_TEST */ + +/* TID-to-Link Mapping negotiation */ +typedef struct wl_mlo_tid_map_neg_v1 { + uint16 version; + uint16 length; + uint8 action; /* EHT_PAF_ACT_TID_MAP_x in 802.11be.h */ + uint8 pad[3]; + uint8 data[]; /* action specific data: + * - EHT_PAF_ACT_TID_MAP_REQ: struct ether_addr; + */ +} wl_mlo_tid_map_neg_v1_t; + +/* TID-to-Link mapping */ +#define WL_MLO_TID_MAP_VER_1 (1u) + +typedef struct wl_mlo_link_tid_map_v1 { + uint8 link_id; /* id of the link */ + uint8 tid_map; /* tids mapped to the link (represented as bit position) */ + uint8 pad[2]; +} wl_mlo_link_tid_map_v1_t; + +typedef struct wl_mlo_tid_map_v1 { + uint16 version; + uint16 length; + uint8 direction; /* direction */ + uint8 num_links; /* number of links */ + uint8 pad[2]; + wl_mlo_link_tid_map_v1_t link_tid_map[]; /* TID to link mapping */ +} wl_mlo_tid_map_v1_t; + +#define TID_TO_LINK_MAP_SIZE(tid_map) \ + (OFFSETOF(wl_mlo_tid_map_v1_t, link_tid_map) + \ + (tid_map->num_links * sizeof(wl_mlo_link_tid_map_v1_t))) + +#define WL_MLO_TID_MAP_VER_2 (2u) + +typedef struct wl_mlo_tid_map_v2 { + uint16 version; + uint16 length; + uint8 control; /* Control bitmap as defined below: + * bits 0-1: direction (0-DL, 1-UL, 2-BOTH) + * bits 2-3: number of links + * bit 4: trigger TID-to-link mapping negotiation (0/1) + */ + uint8 pad[3]; + wl_mlo_link_tid_map_v1_t link_tid_map[]; /* TID map per link */ +} wl_mlo_tid_map_v2_t; + +#define WL_MLO_TID_MAP_VER_3 (3u) + +typedef struct wl_mlo_tid_map_v3 { + uint16 version; + uint16 length; + uint16 control; + /* Control bitmap definition: + * bit 0: default mapping (0/1) + * - when set wl_mlo_link_tid_map_v1_t is not incliuded + * bits 1-2: direction (0-DL, 1-UL, 2-BOTH) + * bits 3-5: number of links (0-7) + * bit 6: negotiate(d) TID-to-link mapping + * bit 7: advertise(d) TID-to-link mapping + * - when set wl_mlo_tid_map_adv_v1_t is included after the control field + * bit 8: + * set - negotiate preferred mapping if indicated by the AP + * get - negotiated mapping is AP's preferred + * bit 9: configure TID-to-link mapping (0/1) + * - when set wl_mlo_tid_map_cfg_v1_t is included after the control field + */ + uint8 status; /* status of the TID-to-link mapping (wl_mlo_tid_map_sts) */ + uint8 pad[1]; + /* optional params based on the control flags */ + uint8 params[]; + /* wl_mlo_tid_map_adv_v1_t Advertised TID-to-link mapping params */ + /* wl_mlo_tid_map_cfg_v1_t TID-to-link mapping config */ + /* wl_mlo_link_tid_map_v1_t TID map per link[] */ +} wl_mlo_tid_map_v3_t; + +/* TID-to-link mapping status */ +enum wl_mlo_tid_map_sts { + WL_MLO_TID_MAP_STS_IDLE = 0, + WL_MLO_TID_MAP_STS_EST = 1, + WL_MLO_TID_MAP_STS_FAIL = 2, + WL_MLO_TID_MAP_STS_PREF = 3, + WL_MLO_TID_MAP_STS_DENY = 4 +}; + +/* MLO tid_map control definitions */ +#define WL_MLO_TID_MAP_DEF_MASK (0x1u) +#define WL_MLO_TID_MAP_DEF_SHIFT (0u) +#define WL_MLO_TID_MAP_DIR_MASK (0x06u) +#define WL_MLO_TID_MAP_DIR_SHIFT (1u) +#define WL_MLO_TID_MAP_LINK_NUM_MASK (0x38u) +#define WL_MLO_TID_MAP_LINK_NUM_SHIFT (3u) +#define WL_MLO_TID_MAP_NEG_MASK (0x40u) +#define WL_MLO_TID_MAP_NEG_SHIFT (6u) +#define WL_MLO_TID_MAP_ADV_MASK (0x80u) +#define WL_MLO_TID_MAP_ADV_SHIFT (7u) +#define WL_MLO_TID_MAP_NEG_PREF_MASK (0x100u) +#define WL_MLO_TID_MAP_NEG_PREF_SHIFT (8u) +#define WL_MLO_TID_MAP_CFG_MASK (0x200u) +#define WL_MLO_TID_MAP_CFG_SHIFT (9u) + +#define WL_MLO_TID_MAP_DEF_GET(tidmap) \ + ((tidmap)->control & WL_MLO_TID_MAP_DEF_MASK) + +#define WL_MLO_TID_MAP_DEF_SET(tidmap, val) \ + ((tidmap)->control = ((tidmap)->control & ~WL_MLO_TID_MAP_DEF_MASK) | \ + ((val) << WL_MLO_TID_MAP_DEF_SHIFT)) + +#define WL_MLO_TID_MAP_DIR_GET(tidmap) \ + (((tidmap)->control & WL_MLO_TID_MAP_DIR_MASK) >> \ + WL_MLO_TID_MAP_DIR_SHIFT) + +#define WL_MLO_TID_MAP_DIR_SET(tidmap, val) \ + ((tidmap)->control = ((tidmap)->control & ~WL_MLO_TID_MAP_DIR_MASK) | \ + ((val) << WL_MLO_TID_MAP_DIR_SHIFT)) + +#define WL_MLO_TID_MAP_LINK_NUM_GET(tidmap) \ + (((tidmap)->control & WL_MLO_TID_MAP_LINK_NUM_MASK) >> \ + WL_MLO_TID_MAP_LINK_NUM_SHIFT) + +#define WL_MLO_TID_MAP_LINK_NUM_SET(tidmap, val) \ + ((tidmap)->control = ((tidmap)->control & ~WL_MLO_TID_MAP_LINK_NUM_MASK) | \ + ((val) << WL_MLO_TID_MAP_LINK_NUM_SHIFT)) + +#define WL_MLO_TID_MAP_NEG_GET(tidmap) \ + (((tidmap)->control & WL_MLO_TID_MAP_NEG_MASK) >> \ + WL_MLO_TID_MAP_NEG_SHIFT) + +#define WL_MLO_TID_MAP_NEG_SET(tidmap, val) \ + ((tidmap)->control = ((tidmap)->control & ~WL_MLO_TID_MAP_NEG_MASK) | \ + ((val) << WL_MLO_TID_MAP_NEG_SHIFT)) + +#define WL_MLO_TID_MAP_ADV_GET(tidmap) \ + (((tidmap)->control & WL_MLO_TID_MAP_ADV_MASK) >> \ + WL_MLO_TID_MAP_ADV_SHIFT) + +#define WL_MLO_TID_MAP_ADV_SET(tidmap, val) \ + ((tidmap)->control = ((tidmap)->control & ~WL_MLO_TID_MAP_ADV_MASK) | \ + ((val) << WL_MLO_TID_MAP_ADV_SHIFT)) + +#define WL_MLO_TID_MAP_NEG_PREF_GET(tidmap) \ + (((tidmap)->control & WL_MLO_TID_MAP_NEG_PREF_MASK) >> \ + WL_MLO_TID_MAP_NEG_PREF_SHIFT) + +#define WL_MLO_TID_MAP_NEG_PREF_SET(tidmap, val) \ + ((tidmap)->control = ((tidmap)->control & ~WL_MLO_TID_MAP_NEG_PREF_MASK) | \ + ((val) << WL_MLO_TID_MAP_NEG_PREF_SHIFT)) + +#define WL_MLO_TID_MAP_CFG_GET(tidmap) \ + (((tidmap)->control & WL_MLO_TID_MAP_CFG_MASK) >> \ + WL_MLO_TID_MAP_CFG_SHIFT) + +#define WL_MLO_TID_MAP_CFG_SET(tidmap, val) \ + ((tidmap)->control = ((tidmap)->control & ~WL_MLO_TID_MAP_CFG_MASK) | \ + ((val) << WL_MLO_TID_MAP_CFG_SHIFT)) + +/* TID-to-link mapping configuration */ +typedef struct wl_mlo_tid_map_cfg_v1 { + uint32 flags; /* configuration flags */ +} wl_mlo_tid_map_cfg_v1_t; + +/* TID-To-Link Mapping Negotiation Supported */ +#define WL_MLO_TID_MAP_CFG_NEG_SUPPORT_MASK (0x03u) + +#define WL_MLO_TID_MAP_CFG_NEG_SUPPORT_GET(tidmapcfg) \ + ((tidmapcfg)->flags & WL_MLO_TID_MAP_CFG_NEG_SUPPORT_MASK) + +#define WL_MLO_TID_MAP_CFG_NEG_SUPPORT_SET(tidmapcfg, val) \ + ((tidmapcfg)->flags = ((tidmapcfg)->flags & ~WL_MLO_TID_MAP_CFG_NEG_SUPPORT_MASK) | \ + (val)) + +typedef struct wl_mlo_tid_map_adv_v1 { + uint16 bcn_cnt; /* num of beacons until TID-to-link mapping establishment */ + uint8 pad[2]; + uint32 duration; /* duration in ms the established mapping will be effective */ +} wl_mlo_tid_map_adv_v1_t; + +#define WL_MLO_TID_MAP_SIZE_V3(tidmap) \ + (OFFSETOF(wl_mlo_tid_map_v3_t, params) + \ + (WL_MLO_TID_MAP_ADV_GET(tidmap) ? sizeof(wl_mlo_tid_map_adv_v1_t) : 0u) + \ + (WL_MLO_TID_MAP_CFG_GET(tidmap) ? sizeof(wl_mlo_tid_map_cfg_v1_t) : 0u) + \ + (sizeof(wl_mlo_link_tid_map_v1_t) * WL_MLO_TID_MAP_LINK_NUM_GET(tidmap))) + +#define WL_MLO_TID_MAP_ADV_OFFSET_V3(tidmap) \ + (OFFSETOF(wl_mlo_tid_map_v3_t, params)) + +#define WL_MLO_TID_MAP_CFG_OFFSET_V3(tidmap) \ + (OFFSETOF(wl_mlo_tid_map_v3_t, params) + \ + (WL_MLO_TID_MAP_ADV_GET(tidmap) ? sizeof(wl_mlo_tid_map_adv_v1_t) : 0u)) + +#define WL_MLO_LINK_TID_MAP_OFFSET_V3(tidmap) \ + (OFFSETOF(wl_mlo_tid_map_v3_t, params) + \ + (WL_MLO_TID_MAP_ADV_GET(tidmap) ? sizeof(wl_mlo_tid_map_adv_v1_t) : 0u) + \ + (WL_MLO_TID_MAP_CFG_GET(tidmap) ? sizeof(wl_mlo_tid_map_cfg_v1_t) : 0u)) + +/* MLO emlsr ctrl shift definition */ +#define WL_MLO_EMLSR_CTRL_FLAGS_MURTS_EN_SHIFT (0u) +#define WL_MLO_EMLSR_CTRL_FLAGS_SWITCH_EN_SHIFT (1u) +#define WL_MLO_EMLSR_CTRL_FLAGS_GPIO_CFG_SHIFT (2u) +#define WL_MLO_EMLSR_CTRL_FLAGS_LINK_PRIO_CFG_SHIFT (3u) + +/* MLO emlsr ctrl Flags definition */ +#define WL_MLO_EMLSR_CTRL_FLAGS_MURTS_EN (1u << WL_MLO_EMLSR_CTRL_FLAGS_MURTS_EN_SHIFT) +#define WL_MLO_EMLSR_CTRL_FLAGS_SWITCH_EN (1u << WL_MLO_EMLSR_CTRL_FLAGS_SWITCH_EN_SHIFT) +#define WL_MLO_EMLSR_CTRL_FLAGS_GPIO_CFG (1u << WL_MLO_EMLSR_CTRL_FLAGS_GPIO_CFG_SHIFT) +#define WL_MLO_EMLSR_CTRL_FLAGS_LINK_PRIO_EN\ + (1u << WL_MLO_EMLSR_CTRL_FLAGS_LINK_PRIO_CFG_SHIFT) + +/* setting values in params: note: reusing some of the flags */ +#define WL_MLO_EMLSR_CTRL_SET_MURTS_EN(val, en) \ + (en) ? (val |= WL_MLO_EMLSR_CTRL_FLAGS_MURTS_EN) : \ + (val &= ~WL_MLO_EMLSR_CTRL_FLAGS_MURTS_EN) +#define WL_MLO_EMLSR_CTRL_SET_SWITCH_EN(val, en) \ + (en) ? (val |= WL_MLO_EMLSR_CTRL_FLAGS_SWITCH_EN) : \ + (val &= ~WL_MLO_EMLSR_CTRL_FLAGS_SWITCH_EN) + +/* Note: flags reused here for checking params also. DONOT use for mac addr */ +#define WL_MLO_EMLSR_CTRL_IS_SET(val, flag) (val & flag) ? 1u : 0u + +#define WL_MLO_EMLSR_CTRL_VER_1 (1u) +typedef struct wl_mlo_emlsr_ctrl_v1 { + uint16 version; + uint16 length; + uint32 flags; /* Flags to enable/disable */ + uint32 params; /* params corresponding to flags */ + uint16 murts_ctrl; /* murts_ctrl value if murts_en is 1 */ + bool link_prio_en; /* EMLSR link priority feature enable if 1 */ + uint8 PAD; + uint32 gpio_cfg; /* GPIO pin numbers used in EMLSR emulation */ +} wl_mlo_emlsr_ctrl_v1_t; + +/* WL_MLO_CMD_MLD_AP_OP opcode */ +#define WL_MLO_CMD_MLD_AP_OP_DEL 0u +#define WL_MLO_CMD_MLD_AP_OP_ADD 1u + +/* MLD AP operation parameters */ +typedef struct wl_mlo_mld_ap_op { + uint8 op_code; /* WL_MLO_CMD_MLD_AP_OP_ADD/DEL */ + uint8 link_id; + uint16 del_timer; /* delete timer in units of TBTT */ +} wl_mlo_mld_ap_op_t; + /* Current version for wlc_clm_power_limits_req_t structure and flags */ -#define WLC_CLM_POWER_LIMITS_REQ_VERSION 1 +#define WLC_CLM_POWER_LIMITS_REQ_VERSION_1 1 /* "clm_power_limits" iovar request structure */ typedef struct wlc_clm_power_limits_req { /* Input. Structure and flags version */ @@ -21588,7 +24872,7 @@ typedef struct wlc_clm_power_limits_req { /* Output. Length of TLV-encoded PPR data that follows this structure */ uint32 ppr_tlv_size; /* Output. Beginning of buffer for TLV-encoded PPR data */ - uint8 ppr_tlv[1]; + uint8 ppr_tlv[BCM_FLEX_ARRAY]; } wlc_clm_power_limits_req_t; /* Input. Do not apply SAR limits */ @@ -21602,11 +24886,12 @@ typedef struct wlc_clm_power_limits_req { /* Output. Limits taken from country-default (all-product) data */ #define WLC_CLM_POWER_LIMITS_OUTPUT_FLAG_DEFAULT_COUNTRY_LIMITS 0x00000004 -#define WL_MBO_IOV_MAJOR_VER 1 -#define WL_MBO_IOV_MINOR_VER 1 #define WL_MBO_IOV_MAJOR_VER_SHIFT 8 -#define WL_MBO_IOV_VERSION \ - ((WL_MBO_IOV_MAJOR_VER << WL_MBO_IOV_MAJOR_VER_SHIFT)| WL_MBO_IOV_MINOR_VER) +#define WL_MBO_IOV_MAJOR_VER_1 1u +#define WL_MBO_IOV_MINOR_VER_1 1u + +#define WL_MBO_IOV_VERSION_1_1 \ + ((WL_MBO_IOV_MAJOR_VER_1 << WL_MBO_IOV_MAJOR_VER_SHIFT) | WL_MBO_IOV_MINOR_VER_1) #define MBO_MAX_CHAN_PREF_ENTRIES 16 @@ -21700,11 +24985,13 @@ typedef struct wl_mbo_counters { uint16 wifi_to_cell; } wl_mbo_counters_t; -#define WL_FILS_IOV_MAJOR_VER 1 -#define WL_FILS_IOV_MINOR_VER 1 -#define WL_FILS_IOV_MAJOR_VER_SHIFT 8 -#define WL_FILS_IOV_VERSION \ - ((WL_FILS_IOV_MAJOR_VER << WL_FILS_IOV_MAJOR_VER_SHIFT)| WL_FILS_IOV_MINOR_VER) +#define WL_FILS_IOV_MAJOR_VER_SHIFT 8u + +#define WL_FILS_IOV_MAJOR_VER_1 1u +#define WL_FILS_IOV_MINOR_VER_1 1u + +#define WL_FILS_IOV_VERSION_1_1 \ + ((WL_FILS_IOV_MAJOR_VER_1 << WL_FILS_IOV_MAJOR_VER_SHIFT) | WL_FILS_IOV_MINOR_VER_1) enum wl_fils_cmd_ids { WL_FILS_CMD_ADD_IND_IE = 1, @@ -21730,76 +25017,226 @@ enum wl_fils_xtlv_id { WL_FILS_XTLV_PMKID = 0xb }; -#define WL_OCE_IOV_MAJOR_VER 1 -#define WL_OCE_IOV_MINOR_VER 1 +#define WL_OCE_IOV_MAJOR_VER_1 1 +#define WL_OCE_IOV_MINOR_VER_1 1 #define WL_OCE_IOV_MAJOR_VER_SHIFT 8 -#define WL_OCE_IOV_VERSION \ - ((WL_OCE_IOV_MAJOR_VER << WL_OCE_IOV_MAJOR_VER_SHIFT)| WL_OCE_IOV_MINOR_VER) +#define WL_OCE_IOV_VERSION_1_1 \ + ((WL_OCE_IOV_MAJOR_VER_1 << WL_OCE_IOV_MAJOR_VER_SHIFT)| WL_OCE_IOV_MINOR_VER_1) enum wl_oce_cmd_ids { - WL_OCE_CMD_ENABLE = 1, - WL_OCE_CMD_PROBE_DEF_TIME = 2, - WL_OCE_CMD_FD_TX_PERIOD = 3, - WL_OCE_CMD_FD_TX_DURATION = 4, - WL_OCE_CMD_RSSI_TH = 5, - WL_OCE_CMD_RWAN_LINKS = 6, - WL_OCE_CMD_CU_TRIGGER = 7, - WL_OCE_CMD_TXPWR_USED = 8, + WL_OCE_CMD_VERSION = 0u, + WL_OCE_CMD_ENABLE = 1u, + WL_OCE_CMD_PROBE_DEF_TIME = 2u, + WL_OCE_CMD_FD_TX_PERIOD = 3u, + WL_OCE_CMD_FD_TX_DURATION = 4u, + WL_OCE_CMD_RSSI_TH = 5u, + WL_OCE_CMD_RWAN_LINKS = 6u, + WL_OCE_CMD_CU_TRIGGER = 7u, + WL_OCE_CMD_TXPWR_USED = 8u, + WL_OCE_CMD_FEATURE_FLAGS = 9u, /* Add before this !! */ WL_OCE_CMD_LAST }; enum wl_oce_xtlv_id { - WL_OCE_XTLV_ENABLE = 0x1, - WL_OCE_XTLV_PROBE_DEF_TIME = 0x2, - WL_OCE_XTLV_FD_TX_PERIOD = 0x3, - WL_OCE_XTLV_FD_TX_DURATION = 0x4, - WL_OCE_XTLV_RSSI_TH = 0x5, - WL_OCE_XTLV_RWAN_LINKS = 0x6, - WL_OCE_XTLV_CU_TRIGGER = 0x7, - WL_OCE_XTLV_TXPWR_USED = 0x8 + WL_OCE_XTLV_ENABLE = 0x1u, + WL_OCE_XTLV_PROBE_DEF_TIME = 0x2u, + WL_OCE_XTLV_FD_TX_PERIOD = 0x3u, + WL_OCE_XTLV_FD_TX_DURATION = 0x4u, + WL_OCE_XTLV_RSSI_TH = 0x5u, + WL_OCE_XTLV_RWAN_LINKS = 0x6u, + WL_OCE_XTLV_CU_TRIGGER = 0x7u, + WL_OCE_XTLV_TXPWR_USED = 0x8u, + WL_OCE_XTLV_FEATURE_FLAGS = 0x9u, /* to control OCE features on the fly */ }; -/* Robust Audio Video (RAV), MSCS (Mirrored Stream Classification Service) commands */ -#define WL_RAV_MSCS_IOV_MAJOR_VER 1u -#define WL_RAV_MSCS_IOV_MINOR_VER 1u -#define WL_RAV_MSCS_IOV_MAJOR_VER_SHIFT 8u +/* OCE feature control flags to enable/dsiable various features. */ +typedef enum oce_feature_flags_e { + OCE_FEATURE_FLAG_UCAST_PROBE_RESP = (1u << 0u) /* bit 0 */ +} oce_feature_flags_t; -#define WL_RAV_MSCS_IOV_VERSION \ - ((WL_RAV_MSCS_IOV_MAJOR_VER << WL_RAV_MSCS_IOV_MAJOR_VER_SHIFT)| WL_RAV_MSCS_IOV_MINOR_VER) - -enum wl_rav_mscs_cmd_ids { - WL_RAV_MSCS_CMD_CONFIG = 1u, /* MSCS configuration */ - WL_RAV_MSCS_CMD_ENABLE = 2u, /* Activate/deactivate MSCS */ - WL_RAV_MSCS_CMD_UP_BITMAP = 3u, /* User priority bitmap */ - WL_RAV_MSCS_CMD_UP_LIMIT = 4u, /* User priority limit */ - WL_RAV_MSCS_CMD_STREAM_TIMEOUT = 5u, /* Stream timeout for MSCS Request */ - WL_RAV_MSCS_CMD_FC_TYPE = 6u, /* Frame classifier type, IPv4, IPv6, etc. */ - WL_RAV_MSCS_CMD_FC_MASK = 7u, /* Specifies the frame classifier mask */ - WL_RAV_MSCS_CMD_REQ_TYPE = 8u, /* Indicates the MSCS Request type (add/remove) */ - WL_RAV_MSCS_CMD_ASSOC_NEG = 9u, /* MSCS negotiation in the association */ +#define WL_IGMPOE_IOV_MAJOR_VER_1 1 +#define WL_IGMPOE_IOV_MINOR_VER_1 1 +#define WL_IGMPOE_IOV_MAJOR_VER_SHIFT 8 +#define WL_IGMPOE_IOV_VERSION_1_1 \ + ((WL_IGMPOE_IOV_MAJOR_VER_1 << WL_IGMPOE_IOV_MAJOR_VER_SHIFT)| WL_IGMPOE_IOV_MINOR_VER_1) +enum wl_igmpoe_cmd_ids { + WL_IGMPOE_CMD_VERSION = 0u, + WL_IGMPOE_CMD_ENABLE = 1u, + WL_IGMPOE_CMD_TABLE = 2u, + WL_IGMPOE_CMD_STATS = 3u, /* Add before this !! */ - WL_RAV_MSCS_CMD_LAST + WL_IGMPOE_CMD_LAST }; -typedef enum wl_rav_mscs_xtlv_id { - WL_RAV_MSCS_XTLV_CONFIG = 1u, - WL_RAV_MSCS_XTLV_ENABLE = 2u, - WL_RAV_MSCS_XTLV_UP_BITMAP = 3u, - WL_RAV_MSCS_XTLV_UP_LIMIT = 4u, - WL_RAV_MSCS_XTLV_STREAM_TIMEOUT = 5u, - WL_RAV_MSCS_XTLV_FC_TYPE = 6u, - WL_RAV_MSCS_XTLV_FC_MASK = 7u, - WL_RAV_MSCS_XTLV_REQ_TYPE = 8u, - WL_RAV_MSCS_XTLV_ASSOC_NEG = 9u -} wl_rav_mscs_xtlv_id_t; +enum wl_igmpoe_xtlv_id { + WL_IGMPOE_XTLV_VERSION = 0x0u, + WL_IGMPOE_XTLV_ENABLE = 0x1u, + WL_IGMPOE_XTLV_TABLE = 0x2u, + WL_IGMPOE_XTLV_STATS = 0x3u +}; -#define WL_ESP_IOV_MAJOR_VER 1 -#define WL_ESP_IOV_MINOR_VER 1 +typedef struct wl_igmp_entry { + struct ipv4_addr ipaddr; /* multicast ip address */ + uint32 timestamp; /* time when entry is added or deleted */ + bool valid; /* true when entry is added and false when deleted */ + uint8 PAD[3]; /* Reserved */ +} wl_igmp_entry_t; + +#define WL_IGMP_TABLE_VERSION 1u /* igmpoe table IOVA version */ +typedef struct wl_igmp_table_v1 { + uint16 version; + uint16 len; + wl_igmp_entry_t data[]; +} wl_igmp_table_t; + +#define WL_IGMP_STATS_VERSION_1 1u /* igmpoe stats IOVAR version */ +typedef struct wl_igmp_stats_v1 { + uint16 version; + uint16 len; + + uint32 igmp_add_success; /* # of times igmp entry is added */ + uint32 igmp_del_success; /* # of times igmp entry is deleted */ + + uint32 igmp_add_skipped; /* # of times igmp entry add is skipped */ + uint32 igmp_add_nospace; /* # of times igmp entry add failed due to no space */ + uint32 igmp_del_noentry; /* # of times igmp entry delete failed due to no etnry */ + + uint32 igmp_rx_query_general; /* # of times igmp general query received */ + uint32 igmp_rx_query_specific; /* # of times igmp specific query received */ + + uint32 igmp_tx_report; /* # of times igmp report is txed from fw */ + + uint32 igmp_nohostip; /* # of times igmp query is fwded to host */ + uint32 igmp_del_source_succ; /* # of times igmp source entry delete succeeded */ + uint32 igmp_del_source_fail; /* # of times igmp source entry delete failed */ + uint32 igmp_add_source_succ; /* # of times igmp source entry add succeeded */ + uint32 igmp_add_source_fail; /* # of times igmp source entry add failed */ +} wl_igmp_stats_t; + +/* qos commands */ + +/* Definitions for qos iovar */ +#define WL_QOS_VERSION_1 1u /* qos IOVAR/API version */ + +/* qos IOV subcommand IDs */ +typedef enum wl_qos_cmd_id { + WL_QOS_CMD_VERSION = 0u, /* qos ver subcommand */ + WL_QOS_CMD_ENABLE = 1u, /* qos enable subcommand */ + WL_QOS_CMD_RAV_MSCS = 2u, /* qos rav_mscs subcommand */ + WL_QOS_CMD_RAV_SCS = 3u, /* qos rav_scs */ + WL_QOS_CMD_RAV_SCS_DESCR_PARAMS = 4u, /* qos rav_scs descr_params */ + WL_QOS_CMD_RAV_SCS_CT4 = 5u, /* qos rav_scs ct4 */ + WL_QOS_CMD_RAV_SCS_CT10 = 6u /* qos rav_scs ct10 */ +} wl_qos_cmd_id_e; + +/* QoS enable subcommand flags */ +typedef enum qos_cmd_enable_flags { + WL_QOS_CMD_ENABLE_FLAG_RAV_MSCS = (1u << 0u), /* bit 0 */ + WL_QOS_CMD_ENABLE_FLAG_RAV_MSCS_NEG_IN_ASSOC = (1u << 1u), /* bit 1 */ + WL_QOS_CMD_ENABLE_FLAG_RAV_SCS = (1u << 2u) /* bit 2 */ +} qos_cmd_enable_flags_e; + +/* MSCS activation status flags */ +typedef enum wl_qos_rav_mscs_status_flags { + /* MSCS status during the association */ + WL_QOS_RAV_MSCS_STATUS_PRE_ASSOC = (1u << 0u), /* bit 0 */ + + /* MSCS status after association, using action frames */ + WL_QOS_RAV_MSCS_STATUS_POST_ASSOC = (1u << 1u), /* bit 1 */ + + /* Unsolicited request from the AP */ + WL_QOS_RAV_MSCS_STATUS_UNSOLICIT_FROM_AP = (1u << 2u), /* bit 2 */ + + /* Indicates the failure in receiving the MSCS response */ + WL_QOS_RAV_MSCS_STATUS_TIMEOUT = (1u << 3u), /* bit 3 */ + + /* Unable to transmit the action frame */ + WL_QOS_RAV_MSCS_STATUS_TX_FAILURE = (1u << 4u), /* bit 4 */ + + /* Indicates that the MSCS is active */ + WL_QOS_RAV_MSCS_STATUS_ACTIVE = (1u << 5u), /* bit 5 */ + +} wl_qos_rav_mscs_status_flags_e; + +#define WL_QOS_RAV_MSCS_SC_VERSION_1 1u /* rav_mscs subcommand version */ +typedef struct wl_qos_rav_mscs_config_v1 { + uint16 version; /* version of this structure */ + uint16 length; /* length of this structure */ + uint32 stream_timeout; /* MSCS stream timeout */ + uint8 up_bitmap; /* user priority bitmap */ + uint8 up_limit; /* user priority limit */ + uint8 fc_type; /* Frame classifier type, IPv4, IPv6, etc. */ + uint8 fc_mask; /* Specifies the frame classifier mask */ + uint8 req_type; /* Indicates the MSCS Request type (add/remove/change) */ + uint8 status_flags; /* Status flags, see wl_qos_rav_mscs_status_flags_e; */ + uint16 status_code; /* IEEE status code */ +} wl_qos_rav_mscs_config_v1_t; + +typedef enum wl_qos_rav_scs_flags { + /* If bit0 is 1 which indicates to send the SCS action frame to the AP */ + WL_QOS_RAV_SCS_FLAGS_COMMIT = (1u << 0u) /* bit 0 */ +} wl_qos_rav_scs_flags_e; + +#define WL_QOS_RAV_SCS_DESCR_PARAMS_VERSION_1 1u /* rav_scs descr subcommand version */ +typedef struct wl_qos_rav_scs_descr_params_v1 { + uint16 version; /* version of this structure */ + uint16 length; /* length (bytes) of this structure */ + uint16 status_code; /* Status code from the AP */ + uint8 flags; /* various flags, see wl_qos_rav_scs_descr_flags_e */ + uint8 scsid; /* SCS descriptor id */ + uint8 req_type; /* Request type (0/1/2, add/change/delete) */ + uint8 intra_ac_prio; /* Intra AC (Access Category) priority */ + uint8 tc_processing; /* TCLAS processing */ + uint8 pad; /* Reserved */ +} wl_qos_rav_scs_descr_params_v1_t; + +/* SCS ct4 (classifier type 4) for IPv4/IPv6 */ +#define WL_QOS_RAV_SCS_CT4_SC_VERSION_1 1u /* rav_scs ct4 subcommand version */ +#define SCS_CT4_IPV6_FLOW_LABEL_SIZE 3u /* bytes */ +typedef struct wl_qos_rav_scs_ct4_v1 { + uint16 version; /* version of this structure */ + uint16 length; /* length (bytes) of this structure */ + uint16 src_port; /* Src port, network byte order */ + uint16 dst_port; /* Dst port, network byte order */ + uint8 src_ip[IPV6_ADDR_LEN]; /* Src IP v4/v6, network byte order */ + uint8 dst_ip[IPV6_ADDR_LEN]; /* Dest IP v4/v6, network byte order */ + uint8 scsid; /* Unique SCS descriptor id */ + uint8 up; /* Not used, specify 255 */ + uint8 classifier_mask; /* Each bit identifies the following */ + uint8 ip_version; /* IP version v4/v6 */ + uint8 dscp; /* DSCP in IP header */ + uint8 proto_or_nh; /* IPv4: protocol, IPv6: next header */ + uint8 flow_label[SCS_CT4_IPV6_FLOW_LABEL_SIZE]; /* IPv6 flow label */ + uint8 pad[3]; /* Reserved */ +} wl_qos_rav_scs_ct4_v1_t; + +/* SCS ct10 (classifier type 10) for IPv4/IPv6 */ +#define WL_QOS_RAV_SCS_CT10_SC_VERSION_1 1u /* rav_scs ct10 subcommand version */ +typedef struct wl_qos_rav_scsc_ct10_filter_data { + uint8 filter_value; + uint8 filter_mask; + uint8 pad[2]; +} wl_qos_rav_scsc_ct10_filter_data_t; + +typedef struct wl_qos_rav_scs_ct10_v1 { + uint16 version; /* version of this structure */ + uint16 length; /* length (bytes) of this structure */ + uint8 scsid; /* SCS descriptor id */ + uint8 up; /* Unused, specify 255 */ + uint8 proto_instance; /* protocol instance */ + uint8 proto_or_nh; /* protocol or next header */ + uint16 num_filter_items; /* Number of entries in filter_data */ + uint8 pad[2]; /* Reserved */ + wl_qos_rav_scsc_ct10_filter_data_t filter_data[]; +} wl_qos_rav_scs_ct10_v1_t; + +#define WL_ESP_IOV_MAJOR_VER_1 1 +#define WL_ESP_IOV_MINOR_VER_1 1 #define WL_ESP_IOV_MAJOR_VER_SHIFT 8 -#define WL_ESP_IOV_VERSION \ - ((WL_ESP_IOV_MAJOR_VER << WL_ESP_IOV_MAJOR_VER_SHIFT)| WL_ESP_IOV_MINOR_VER) +#define WL_ESP_IOV_VERSION_1_1 \ + ((WL_ESP_IOV_MAJOR_VER_1 << WL_ESP_IOV_MAJOR_VER_SHIFT)| WL_ESP_IOV_MINOR_VER_1) enum wl_esp_cmd_ids { WL_ESP_CMD_ENABLE = 1, @@ -21815,47 +25252,62 @@ enum wl_esp_xtlv_id { WL_ESP_XTLV_STATIC_VAL = 0x4 }; -#define WL_BCN_PROT_IOV_MAJOR_VER 1 -#define WL_BCN_PROT_IOV_MINOR_VER 1 -#define WL_BCN_PROT_IOV_MAJOR_VER_SHIFT 8 -#define WL_BCN_PROT_IOV_VERSION \ - ((WL_BCN_PROT_IOV_MAJOR_VER << WL_BCN_PROT_IOV_MAJOR_VER_SHIFT)| WL_BCN_PROT_IOV_MINOR_VER) +/* bcnprot commands */ + +/* Definitions for bcn_prot iovar */ +#define WL_BCN_PROT_VERSION_1 1u /* bcn_prot IOVAR/API version */ enum wl_bcn_prot_cmd_ids { - WL_BCN_PROT_CMD_ENABLE = 1, - WL_BCN_PROT_CMD_COUNTERS = 2, - /* Add before this !! */ - WL_BCN_PROT_CMD_LAST + WL_BCN_PROT_CMD_VERSION = 0u, + WL_BCN_PROT_CMD_ENABLE = 1u, + WL_BCN_PROT_CMD_COUNTERS = 2u, + WL_BCN_PROT_CMD_STATUS = 3u, + WL_BCN_PROT_CMD_CONFIG = 4u }; -enum wl_bcn_prot_xtlv_id { - WL_BCN_PROT_XTLV_ENABLE = 0x1, - WL_BCN_PROT_XTLV_COUNTERS = 0x2 +/* Optional XTLVs included in wlc_roam_start_event_t */ +enum wl_roam_start_xtlv_id { + /* XTLV for beacon protection counters if beacon protection + * is active and roam started due to beacon loss + */ + WL_ROAM_START_XTLV_BCNPROT_STATS = 0x1u }; -typedef struct wlc_bcn_prot_counters { +/* WL_ROAM_START_XTLV_BCNPROT_STATS */ +#define BCN_PROT_COUNTERS_VERSION_0 (0u) +typedef struct wlc_bcn_prot_counters_v0 { uint32 no_en_bit; /* counts beacons without bcn prot enable bit at ext cap */ uint32 no_mme_ie; /* counts beacons without mme ie */ uint32 mic_fails; /* counts beacons failed mic check */ uint32 replay_fails; /* counts beacons failed replay check */ -} wlc_bcn_prot_counters_t; -#define BCN_PROT_COUNTERS_SIZE sizeof(wlc_bcn_prot_counters_t) +} wlc_bcn_prot_counters_v0_t; -#define WL_DRR_IOV_MAJOR_VER 1 -#define WL_DRR_IOV_MINOR_VER 1 -#define WL_DRR_IOV_MAJOR_VER_SHIFT 8 -#define WL_DRR_IOV_VERSION \ - ((WL_DRR_IOV_MAJOR_VER << WL_DRR_IOV_MAJOR_VER_SHIFT)| WL_DRR_IOV_MINOR_VER) +#define BCN_PROT_COUNTERS_VERSION_1 (1u) +typedef struct wlc_bcn_prot_counters_v1 { + uint16 version; /* version of this structure */ + uint16 length; /* length (bytes) of this structure */ + uint32 no_en_bit; /* counts beacons without bcn prot enable bit at ext cap */ + uint32 no_mme_ie; /* counts beacons without mme ie */ + uint32 mic_fails; /* counts beacons that failed mic check */ + uint32 replay_fails; /* counts beacons that failed replay check */ + uint32 errors_since_good_bcn; /* counts failures since last good beacon */ +} wlc_bcn_prot_counters_v1_t; -enum wl_drr_cmd_ids { - WL_DRR_CMD_ENABLE = 1u, - /* Add before this !! */ - WL_DRR_CMD_LAST -}; +#ifndef BCN_PROT_COUNTERS_TEMP_VERSION_ENABLED +#define BCN_PROT_COUNTERS_VERSION (BCN_PROT_COUNTERS_VERSION_0) +typedef wlc_bcn_prot_counters_v0_t wlc_bcn_prot_counters_t; +#define BCN_PROT_COUNTERS_SIZE sizeof(wlc_bcn_prot_counters_v0_t) +#endif /* BCN_PROT_COUNTERS_TEMP_VERSION_ENABLED */ -enum wl_drr_xtlv_id { - WL_DRR_XTLV_ENABLE = 0x1u -}; +/* Enable bitmap */ +#define WL_BCN_PROT_ENABLE_FEATURE 0x1u +#define WL_BCN_PROT_ENABLE_AP 0x2u + +#define WL_BCN_PROT_STATUS_ACTIVE 1u + +#define WL_BCN_PROT_CONFIG_ALLOW_PROT_ONLY 0x00000001u /* Allow join/roam to only Beacon + * protection capable AP + */ /* otpread command */ #define WL_OTPREAD_VER 1 @@ -21918,39 +25370,23 @@ typedef struct { (bcm_bitcount((uint8 *)&(val), sizeof(uint8)) > 1) /* otp command details */ -#define WL_OTP_IOV_MAJOR_VER 1u -#define WL_OTP_IOV_MINOR_VER 1u +#define WL_OTP_IOV_MAJOR_VER_1 1u +#define WL_OTP_IOV_MINOR_VER_1 1u #define WL_OTP_IOV_MAJOR_VER_SHIFT 8u -#define WL_OTP_IOV_VERSION \ - ((WL_OTP_IOV_MAJOR_VER << WL_OTP_IOV_MAJOR_VER_SHIFT) | WL_OTP_IOV_MINOR_VER) +#define WL_OTP_IOV_VERSION_1_1 \ + ((WL_OTP_IOV_MAJOR_VER_1 << WL_OTP_IOV_MAJOR_VER_SHIFT) | WL_OTP_IOV_MINOR_VER_1) /* OTP Regions HW/SW */ #define OTP_RGN_NONE 0u #define OTP_RGN_HW 1u #define OTP_RGN_SW 2u - -/* OTP Lock Regions */ -#define OTP_LOCK_RGN_NONE 0u -#define OTP_LOCK_RGN_WAFER_SORT 1u -#define OTP_LOCK_RGN_HASH_DATA 2u -#define OTP_LOCK_RGN_FINAL_TEST 3u -#define OTP_LOCK_RGN_AUTOLOAD 4u -#define OTP_LOCK_RGN_UPPER_GU 5u -#define OTP_LOCK_RGN_LOWER_GU 6u -#define OTP_LOCK_RGN_HW_SW 7u -#define OTP_LOCK_RGN_BT 8u -#define OTP_LOCK_RGN_SECURE 9u -#define OTP_LOCK_RGN_SECURE_V 10u -#define OTP_LOCK_RGN_SECURE_VI_0 11u -#define OTP_LOCK_RGN_SECURE_VI_1 12u +#define OTP_RGN_BT 3u enum wl_otp_cmd_ids { + WL_OTP_CMD_ALL = 0u, WL_OTP_CMD_RGNSTATUS = 1u, WL_OTP_CMD_RGNDUMP = 2u, WL_OTP_CMD_RGNWRITE = 3u, - WL_OTP_CMD_SBOOT = 4u, - WL_OTP_CMD_RGNLOCK = 5u, - /* Add before this !!! */ WL_OTP_CMD_LAST }; @@ -21961,30 +25397,6 @@ enum wl_otp_xtlv_id { WL_OTP_XTLV_ADDR = 2u, /* OTP region start address */ WL_OTP_XTLV_SIZE = 3u, /* OTP region size */ WL_OTP_XTLV_DATA = 4u, /* OTP dump data */ - - /* SBOOT TAGs: */ - WL_OTP_XTLV_SBOOT_FW_SIG_ENABLE = 5u, /* FW signing enable bit */ - WL_OTP_XTLV_SBOOT_FW_SIG_DISABLE = 6u, /* FW signing disaable bit */ - WL_OTP_XTLV_SBOOT_ROM_PROTECT_ENABLE = 7u, /* ROM protect enable bit */ - WL_OTP_XTLV_SBOOT_ROM_PROTECT_PATCH = 8u, /* ROM protect from patch */ - WL_OTP_XTLV_SBOOT_HOST_READ_NONSEC_EN = 9u, /* Host read non secure enable bit */ - WL_OTP_XTLV_SBOOT_HOST_READ_NONSEC_DIS = 10u, /* Host read non secure disable bit */ - WL_OTP_XTLV_SBOOT_HOST_WRITE_NONSEC_EN = 11u, /* Host write non secure enable bit */ - WL_OTP_XTLV_SBOOT_HOST_WRITE_NONSEC_DIS = 12u, /* Host write non secure disable bit */ - WL_OTP_XTLV_SBOOT_DBGREGS_PROTECT_ENAB = 13u, /* ARM DBG regs protect enable bit */ - WL_OTP_XTLV_SBOOT_DBGREGS_PROTECT_DIS = 14u, /* ARM DBG regs protect disable bit */ - WL_OTP_XTLV_SBOOT_JTAG_PROTECT_ENAB = 15u, /* JTAG protect disable bit */ - WL_OTP_XTLV_SBOOT_JTAG_PROTECT_DIS = 16u, /* JTAG protect re-enable bit */ - WL_OTP_XTLV_SBOOT_TCAM_PROTECT_SIZE = 17u, /* TCAM protect enable size field 8 bits */ - WL_OTP_XTLV_SBOOT_ACTIVATE_SECURITY = 18u, /* Active security enable bit */ - WL_OTP_XTLV_SBOOT_KEY_REVOC_BITS = 19u, /* Key revocation Bits field 16 bits */ - WL_OTP_XTLV_SBOOT_CUSTOMER_PUBLIC_KEY_1 = 20u, /* Customer public key 1 field 257 bits */ - WL_OTP_XTLV_SBOOT_CUSTOMER_PUBLIC_KEY_2 = 21u, /* Customer public key 2 field 257 bits */ - WL_OTP_XTLV_SBOOT_LOT_NUM = 22u, /* Chip lot num 17 bits */ - WL_OTP_XTLV_SBOOT_WAFER_NUM = 23u, /* Chip wafer num 5 bits */ - WL_OTP_XTLV_SBOOT_WAFER_X = 24u, /* Chip wafer X 9 bits */ - WL_OTP_XTLV_SBOOT_WAFER_Y = 25u, /* Chip wafer Y 9 bits */ - WL_OTP_XTLV_SBOOT_UNLOCK_HASH_VAL = 26u, /* Unlock Hash Val 128 bits */ }; #define WL_LEAKY_AP_STATS_GT_TYPE 0 @@ -22015,11 +25427,6 @@ typedef struct wlc_leaked_infra_guard_marker { #define WL_LEAKED_GUARD_TIME_FRTS (0x01 << 0) /* Normal FRTS power save */ #define WL_LEAKED_GUARD_TIME_SCAN (0x01 << 1) /* Channel switch due to scanning */ -#ifdef WLAWDL -#define WL_LEAKED_GUARD_TIME_AWDL_PSF (0x01 << 2) /* Channel switch due to AWDL PSF */ -#define WL_LEAKED_GUARD_TIME_AWDL_AW (0x01 << 3) /* Channel switch due to AWDL AW */ -#endif /* WLAWDL */ - #define WL_LEAKED_GUARD_TIME_INFRA_STA (0x01 << 4) /* generic type infra sta channel switch */ #define WL_LEAKED_GUARD_TIME_TERMINATED (0x01 << 7) /* indicate a GT is terminated early */ @@ -22036,8 +25443,8 @@ typedef struct wlc_leaked_infra_packet_stat { } wlc_leaked_infra_packet_stat_t; /* Wake timer structure definition */ -#define WAKE_TIMER_VERSION 1 -#define WAKE_TIMER_NOLIMIT 0xFFFF +#define WAKE_TIMER_VERSION_1 1 +#define WAKE_TIMER_NOLIMIT 0xFFFF typedef struct wake_timer { uint16 ver; @@ -22060,7 +25467,6 @@ typedef struct wl_desense_restage_gain { #define MAX_UCM_CHAINS 5 #define MAX_UCM_PROFILES 10 -#define UCM_PROFILE_VERSION_1 1 /* UCM per chain attribute struct */ typedef struct wlc_btcx_chain_attr { @@ -22073,6 +25479,31 @@ typedef struct wlc_btcx_chain_attr { uint8 PAD[1]; /* additional bytes for alignment */ } wlc_btcx_chain_attr_t; +#define WL_UCM_PER_CHAIN_ATTR_VERSION_V1 1 +/* UCM per chain attribute struct v1 (same structure to wlc_btcx_chain_attr_t) */ +typedef struct wlc_btcx_per_chain_attr_v1 { + uint16 length; /* chain attr length, version is same as profile version */ + int8 desense_level; /* per chain desense level */ + int8 ack_pwr_strong_rssi; /* per chain ack power at strong rssi */ + int8 ack_pwr_weak_rssi; /* per chain ack power at weak rssi */ + int8 tx_pwr_strong_rssi; /* per chain tx power at strong rssi */ + int8 tx_pwr_weak_rssi; /* per chain tx power at weak rssi */ + uint8 PAD[1]; /* additional bytes for alignment */ +} wlc_btcx_per_chain_attr_v1_t; + +#define WL_UCM_PER_CHAIN_ATTR_VERSION_V2 2 +/* UCM per chain attribute struct v2 */ +typedef struct wlc_btcx_per_chain_attr_v2 { + uint16 length; /* chain attr length, version is same as profile version */ + uint8 desense_strong_rssi; /* per chain desense mode for strong rssi */ + uint8 desense_weak_rssi; /* per chain desense mode for weak rssi */ + int8 ack_pwr_strong_rssi; /* per chain ack power at strong rssi */ + int8 ack_pwr_weak_rssi; /* per chain ack power at weak rssi */ + int8 tx_pwr_strong_rssi; /* per chain tx power at strong rssi */ + int8 tx_pwr_weak_rssi; /* per chain tx power at weak rssi */ +} wlc_btcx_per_chain_attr_v2_t; + +#define UCM_PROFILE_VERSION_1 1 typedef struct wlc_btcx_profile_v1 { uint16 version; /* UCM profile version */ uint16 length; /* profile size */ @@ -22099,7 +25530,6 @@ typedef struct wlc_btcx_profile_v1 { } wlc_btcx_profile_v1_t; #define UCM_PROFILE_VERSION_2 2u - typedef struct wlc_btcx_profile_v2 { uint16 version; /* UCM profile version */ uint16 length; /* profile size */ @@ -22125,6 +25555,32 @@ typedef struct wlc_btcx_profile_v2 { wlc_btcx_chain_attr_t chain_attr[]; /* variable length array with chain attributes */ } wlc_btcx_profile_v2_t; +#define UCM_PROFILE_VERSION_3 3u +typedef struct wlc_btcx_profile_v3 { + uint16 version; /* UCM profile version */ + uint16 length; /* profile size */ + uint16 fixed_length; /* size of the fixed portion of the profile */ + uint8 init; /* profile initialized or not */ + uint8 chain_attr_count; /* Number of elements in chain_attr array */ + uint8 profile_index; /* profile index */ + uint8 mode_strong_wl_bt; /* Mode under strong WLAN and BT RSSI */ + uint8 mode_weak_wl; /* Mode under weak WLAN RSSI */ + uint8 mode_weak_bt; /* Mode under weak BT RSSI */ + uint8 mode_weak_wl_bt; /* Mode under weak BT and WLAN RSSI */ + int8 mode_wl_hi_lo_rssi_thresh; /* Strong to weak WLAN RSSI threshold for mode selection */ + int8 mode_wl_lo_hi_rssi_thresh; /* Weak to strong WLAN RSSI threshold for mode selection */ + int8 mode_bt_hi_lo_rssi_thresh; /* Strong to weak BT RSSI threshold for mode selection */ + int8 mode_bt_lo_hi_rssi_thresh; /* Weak to strong BT RSSI threshold for mode selection */ + int8 desense_wl_hi_lo_rssi_thresh; /* Strong to weak RSSI threshold for desense */ + int8 desense_wl_lo_hi_rssi_thresh; /* Weak to strong RSSI threshold for desense */ + int8 ack_pwr_wl_hi_lo_rssi_thresh; /* Strong to weak RSSI threshold for ACK power */ + int8 ack_pwr_wl_lo_hi_rssi_thresh; /* Weak to strong RSSI threshold for ACK power */ + int8 tx_pwr_wl_hi_lo_rssi_thresh; /* Strong to weak RSSI threshold for Tx power */ + int8 tx_pwr_wl_lo_hi_rssi_thresh; /* Weak to strong RSSI threshold for Tx power */ + uint8 hybrid_ant_core_config; /* Select antenna configuration for hybrid */ + wlc_btcx_per_chain_attr_v2_t chain_attr[]; /* variable length array with chain attributes */ +} wlc_btcx_profile_v3_t; + #define SSSR_D11_RESET_SEQ_STEPS 5u #define SSSR_HWA_RESET_SEQ_STEPS 8u @@ -22132,6 +25588,7 @@ typedef struct wlc_btcx_profile_v2 { #define SSSR_REG_INFO_VER_1 1u #define SSSR_REG_INFO_VER_2 2u #define SSSR_REG_INFO_VER_3 3u +#define SSSR_REG_INFO_VER_4 4u typedef struct sssr_reg_info_v0 { uint16 version; @@ -22405,10 +25862,103 @@ typedef struct sssr_reg_info_v3 { } hwa_regs; } sssr_reg_info_v3_t; -#ifndef SSSR_REG_INFO_HAS_ALIAS -typedef sssr_reg_info_v0_t sssr_reg_info_t; -#define SSSR_REG_INFO_VER SSSR_REG_INFO_VER_0 -#endif +typedef struct sssr_reg_info_v4 { + uint16 version; + uint16 length; /* length of the structure validated at host */ + struct { + struct { + uint32 pmuintmask0; + uint32 pmuintmask1; + uint32 resreqtimer; + uint32 macresreqtimer; + uint32 macresreqtimer1; + uint32 macresreqtimer2; + } base_regs; + } pmu_regs; + struct { + struct { + uint32 intmask; + uint32 powerctrl; + uint32 clockcontrolstatus; + uint32 powerctrl_mask; + } base_regs; + } chipcommon_regs; + struct { + struct { + uint32 clockcontrolstatus; + uint32 clockcontrolstatus_val; + } base_regs; + struct { + uint32 extrsrcreq; + } oobr_regs; + } arm_regs; + struct { + struct { + uint32 ltrstate; + uint32 clockcontrolstatus; + uint32 clockcontrolstatus_val; + } base_regs; + struct { + uint32 extrsrcreq; + } oobr_regs; + } pcie_regs; + struct { + struct { + uint32 xmtaddress; + uint32 xmtdata; + uint32 clockcontrolstatus; + uint32 clockcontrolstatus_val; + } base_regs; + struct { + uint32 extrsrcreq; + } oobr_regs; + uint32 sr_size; + } mac_regs[MAX_NUM_D11_CORES_WITH_SCAN]; + + struct { + struct { + uint32 clockcontrolstatus; + uint32 clockcontrolstatus_val; + } base_regs; + struct { + uint32 extrsrcreq; + } oobr_regs; + + uint32 saqm_sssr_addr; + uint32 saqm_sssr_size; + + struct { + uint32 digsr_srcontrol1_addr; /* DIGSR engine sr control1 register */ + uint32 digsr_srcontrol1_clrbit_val; /* clear these bits from srcontrol1 */ + + uint32 digsr_srcontrol2_addr; /* DIGSR engine sr control2 register */ + uint32 digsr_srcontrol2_setbit_val; /* Value to set in the above address */ + + uint32 pmuchip_ctl_addr_reg; + uint32 pmuchip_ctl_val; + uint32 pmuchip_ctl_data_reg; + uint32 pmuchip_ctl_setbit_val; + } sssr_config_regs; + } saqm_sssr_info; + + struct { + uint32 dig_sssr_addr; + uint32 dig_sssr_size; + } dig_mem_info; + + struct { + uint32 fis_addr; + uint32 fis_size; + } fis_mem_info; + + /* Start address and end address for SSSR collection by host. */ + struct { + uint32 sysmem_sssr_addr; + uint32 sysmem_sssr_size; + } sssr_all_mem_info; + + uint32 fis_enab; +} sssr_reg_info_v4_t; /* A wrapper structure for all versions of SSSR register information structures */ typedef union sssr_reg_info { @@ -22416,6 +25966,7 @@ typedef union sssr_reg_info { sssr_reg_info_v1_t rev1; sssr_reg_info_v2_t rev2; sssr_reg_info_v3_t rev3; + sssr_reg_info_v4_t rev4; } sssr_reg_info_cmn_t; /* ADaptive Power Save(ADPS) structure definition */ @@ -22506,14 +26057,14 @@ typedef struct wlc_adps_energy_gain_data { uint32 pm_dur_gain; /* gain of pm duration by ADPS */ uint32 step0_dur; /* duration of ADPS STEP0(PM MAX + PSPOLL PRD) */ uint32 wake_up_dur; /* duration of wake up state */ - uint32 pad; + uint32 PAD; uint64 tx_tot_bytes; /* Total Tx bytes */ } wlc_adps_energy_gain_data_t; typedef struct wl_adps_energy_gain_v1 { uint16 version; uint16 length; - uint32 pad; + uint32 PAD; wlc_adps_energy_gain_data_t gain_data[MAX_BANDS]; } wl_adps_energy_gain_v1_t; @@ -22598,11 +26149,66 @@ typedef struct wl_btc_ulmu_config_v1 { /* --- End BTCX ULMU config --- */ -#define RPSNOA_IOV_MAJOR_VER 1 -#define RPSNOA_IOV_MINOR_VER 1 -#define RPSNOA_IOV_MAJOR_VER_SHIFT 8 -#define RPSNOA_IOV_VERSION \ - ((RPSNOA_IOV_MAJOR_VER << RPSNOA_IOV_MAJOR_VER_SHIFT)| RPSNOA_IOV_MINOR_VER) +#define WL_BTC_LESCAN_TOTAL_MAX 15u + +/* --- BTC ACK Counters (btc_ack_counters legacy command) --- */ + +#define BTC_ACK_CNTS_VER_1 1u +#define BTC_ACK_CNTS_VER_2 2u + +typedef struct wl_btc_ack_cnts_v1 { + uint16 ver; + uint16 len; + uint8 slice_index; + uint8 PAD[3]; + uint32 cdd_ack_cnt; + uint32 siso_ack_cnt; + uint32 c0_ack_txpwr; + uint32 c1_ack_txpwr; +} wl_btc_ack_cnts_v1_t; + +typedef struct wl_btc_ack_cnts_v2 { + uint16 ver; + uint16 len; + uint8 slice_index; + uint8 PAD[3]; + uint32 cdd_ack_cnt; + uint32 siso_ack_cnt; + uint32 c0_ack_txpwr; + uint32 c1_ack_txpwr; + uint32 cdd_ack_bt_cnt; +} wl_btc_ack_cnts_v2_t; + +typedef enum wl_btc_ack_cnts_command_e { + ACK_CNTS_CMD_CLEAR = 0u, /* To clear BTC Ack counters */ +} wl_btc_ack_cnts_command_t; + +typedef struct wl_btc_ack_cnts_config_v1 { + uint16 ver; /* Command structure version */ + uint16 len; /* Command structure length */ + uint8 cmd; /**< 0 - clear */ + uint8 PAD[3]; +} wl_btc_ack_cnts_config_v1_t; + +/* --- End BTC ACK Counters --- */ + +/* --- BTC STATUS (coex status from both 2G and 5G slices) --- */ +#define BTC_STATUS_VER_1 1u + +typedef struct wlc_btc_status_v1 { + uint16 ver; + uint16 len; + uint32 btc_status_5g; + uint32 btc_status_2g; + uint8 PAD[4]; /* For future enhancements */ +} wlc_btc_status_v1_t; +/* --- End BTC STATUS --- */ + +#define RPSNOA_IOV_MAJOR_VER_1 1u +#define RPSNOA_IOV_MINOR_VER_1 1u +#define RPSNOA_IOV_MAJOR_VER_SHIFT 8u +#define RPSNOA_IOV_VERSION_1_1 \ + ((RPSNOA_IOV_MAJOR_VER_1 << RPSNOA_IOV_MAJOR_VER_SHIFT) | RPSNOA_IOV_MINOR_VER_1) enum wl_rpsnoa_cmd_ids { WL_RPSNOA_CMD_ENABLE = 1, @@ -22641,17 +26247,17 @@ typedef struct rpsnoa_param { typedef struct rpsnoa_iovar { rpsnoa_cmnhdr_t hdr; - rpsnoa_data_t data[1]; + rpsnoa_data_t data[BCM_FLEX_ARRAY]; } rpsnoa_iovar_t; typedef struct rpsnoa_iovar_status { rpsnoa_cmnhdr_t hdr; - rpsnoa_stats_t stats[1]; + rpsnoa_stats_t stats[BCM_FLEX_ARRAY]; } rpsnoa_iovar_status_t; typedef struct rpsnoa_iovar_params { rpsnoa_cmnhdr_t hdr; - rpsnoa_param_t param[1]; + rpsnoa_param_t param[BCM_FLEX_ARRAY]; } rpsnoa_iovar_params_t; /* Per-interface reportable stats types */ @@ -22691,6 +26297,12 @@ enum wl_ifstats_xtlv_id { WL_IFSTATS_XTLV_SC_PERIODIC_STATE = 0x109, WL_IFSTATS_XTLV_WBUS_PERIODIC_STATE = 0x10A, + /* PHY ecounters */ + WL_STATS_XTLV_PHY_ECOUNTER = 0x10B, + + /* PHYCAL ecounters */ + WL_STATS_XTLV_PHYCAL_ECOUNTER = 0x10C, + /* Per-slice information * Per-interface reporting could also include slice specific data */ @@ -22741,7 +26353,16 @@ enum wl_ifstats_xtlv_id { WL_IFSTATS_XTLV_SC_CHANIM_PERIODIC_STATS = 0x318, /* Per-slice RC2 COEX stats */ WL_IFSTATS_XTLV_WL_SLICE_RC2CX = 0x319, - + /* Rx MPDU lost counter per-slice */ + WL_STATS_XTLV_WL_SLICE_RX_LOST_CNT = 0x31A, + /* per slice tx mpdu cnt eCounters */ + WL_STATS_XTLV_WME_TX_CNT_WL_SLICE = 0x31B, + /* per slice rx mpdu cnt eCounters */ + WL_STATS_XTLV_WME_RX_CNT_WL_SLICE = 0x31C, + /* Per-slice UWBCX stats */ + WL_IFSTATS_XTLV_WL_SLICE_UWBCX = 0x31D, + /* Per-slice UWBCX stats */ + WL_IFSTATS_XTLV_WL_SLICE_PWRSTATS_SCAN_6E = 0x31E, /* Per-interface */ /* XTLV container for reporting */ WL_IFSTATS_XTLV_IF = 0x501, @@ -22755,10 +26376,6 @@ enum wl_ifstats_xtlv_id { WL_IFSTATS_XTLV_AMPDU_DUMP = 0x505, WL_IFSTATS_XTLV_IF_SPECIFIC = 0x506, -#ifdef WLAWDL - WL_IFSTATS_XTLV_WL_PWRSTATS_AWDL = 0x507, -#endif /* WLAWDL */ - WL_IFSTATS_XTLV_IF_LQM = 0x508, /* Interface specific state capture in periodic fashion */ WL_IFSTATS_XTLV_IF_PERIODIC_STATE = 0x509, @@ -22885,13 +26502,21 @@ typedef struct wl_infra_stats_he { uint64 ulofdma_mpdu_bytes; } wl_if_infra_stats_he_t; +#define WL_RX_MPDU_LOST_CNT_VERSION (1u) +typedef struct rx_mpdu_lost_cnt { + uint16 version; + uint16 length; + uint32 rx_mpdu_lost_ba[NUMPRIO]; + uint32 rx_mpdu_lost_nonba[NUMPRIO]; +} rx_mpdu_lost_cnt_t; + #define LTECOEX_STATS_VER 1 typedef struct wlc_ltecoex_stats { uint16 version; /**< WL_IFSTATS_XTLV_WL_SLICE_LTECOEX */ uint16 len; /* Length of wl_ltecx_stats structure */ uint8 slice_index; /* Slice unit of wl_ltecx_stats structure */ - uint8 pad[3]; /* Padding */ + uint8 PAD[3]; /* Padding */ /* LTE noise based eCounters Bins cumulative the wl_cnt_wlc_t and wl_ctl_mgt_cnt_t counter information based on LTE Coex interference level @@ -22952,7 +26577,7 @@ typedef struct csa_event_data { dot11_mesh_csp_ie_t mcsp; dot11_wide_bw_chan_switch_ie_t wbcs; uint8 flags; - uint8 pad[3]; + uint8 PAD[3]; } csa_event_data_t; /* ifdef (WL_ASSOC_BCN_RPT) */ @@ -22987,19 +26612,18 @@ enum wl_bcn_report_cmd_id { #define WL_BCN_RPT_ASSOC_SCAN_CACHE_COUNT_MAX (8) #define WL_BCN_RPT_ASSOC_SCAN_CACHE_COUNT_DEFAULT (WL_BCN_RPT_ASSOC_SCAN_CACHE_COUNT_MAX) -#define WL_BCN_REPORT_CMD_VERSION 1 -struct wl_bcn_report_cfg { +#define WL_BCN_REPORT_CMD_VERSION_V1 1 + +typedef struct wl_bcn_report_cfg_v1 { uint32 flags; /**< Flags that defines the operation/setting information */ uint32 scan_cache_timeout; /**< scan cache timeout value in millisec */ uint32 scan_cache_timer_pend; /**< Read only pending time for timer expiry in millisec */ uint8 scan_cache_cnt; /**< scan cache count */ -}; - -/* endif (WL_ASSOC_BCN_RPT) */ + uint8 pad[3]; +} wl_bcn_report_cfg_v1_t; /* Thermal, Voltage, and Power Mitigation */ -#define TVPM_REQ_VERSION_1 1 -#define TVPM_REQ_CURRENT_VERSION TVPM_REQ_VERSION_1 +#define TVPM_REQ_VERSION_1 1u /* tvpm iovar data */ typedef struct { @@ -23030,7 +26654,7 @@ typedef struct wl_tvpm_status { uint16 num_active_chains; /* 1...3 */ int16 temp; /* local temperature in degrees C */ uint8 vbat; /* local voltage in units of 0.1V */ - uint8 pad; + uint8 PAD; } wl_tvpm_status_t; /* TVPM ecounters */ @@ -23044,7 +26668,7 @@ typedef struct wl_tvpm_ecounters_t { uint8 vbat; /* local voltage */ uint8 cltm; /* CLTM index */ uint8 ppm; /* PPM index */ - uint8 pad; /* pad to align to uint16 */ + uint8 PAD; /* pad to align to uint16 */ } wl_tvpm_ecounters_t; #define TDMTX_ECOUNTERS_VERSION_V1 1 @@ -23100,6 +26724,7 @@ typedef struct wlc_scb_stats_v1 { uint32 rx_decrypt_succeeds; /* num of packets decrypted successfully */ uint32 rx_decrypt_failures; /* num of packets decrypted unsuccessfully */ uint32 tx_mcast_pkts; /* num of mcast pkts txed */ + uint32 PAD; uint64 tx_ucast_bytes; /* data bytes txed (ucast) */ uint64 tx_mcast_bytes; /* data bytes txed (mcast) */ uint64 rx_ucast_bytes; /* data bytes recvd ucast */ @@ -23129,7 +26754,7 @@ typedef struct wl_scb_ecounters_v1 { uint32 chanspec; /* current chanspec where scb is operating */ struct ether_addr ea; /* peer ndi or sta ea */ uint8 peer_type; /* peer type */ - uint8 pad; + uint8 PAD; /* scb tx and rx stats */ wlc_scb_stats_v1_t stats; @@ -23141,13 +26766,13 @@ typedef struct wl_scb_ecounters_v2 { uint32 chanspec; /* current chanspec where scb is operating */ struct ether_addr ea; /* peer ndi or sta ea */ uint8 peer_type; /* peer type */ - uint8 pad; + uint8 PAD; /* scb tx and rx stats */ uint16 tx_rate; /* Rate(in Mbps) of last successful tx frame */ uint16 rx_rate; /* Rate(in Mbps) of last successful rx frame */ uint16 tx_rate_fallback; /* last used lowest fallback TX rate(in Mbps) */ - uint16 pad1; + uint16 PAD; uint32 rx_decrypt_succeeds; /* num of packets decrypted successfully */ uint32 rx_decrypt_failures; /* num of packets decrypted unsuccessfully */ uint32 rx_pkts_retried; /* # rx with retry bit set */ @@ -23164,13 +26789,14 @@ typedef struct wl_scb_ecounters_v2 { #define WL_NAN_SLOT_ECOUNTERS_VERSION_1 1 #define WL_NAN_SLOT_ECOUNTERS_VERSION_2 2 #define WL_NAN_SLOT_ECOUNTERS_VERSION_3 3 +#define WL_NAN_SLOT_ECOUNTERS_VERSION_4 4 typedef struct wl_nan_slot_ecounters_v1 { uint16 version; /* version field */ uint16 length; /* struct length starting from version */ uint32 chan[NAN_MAX_BANDS]; /* cur nan slot chanspec of both bands */ uint16 cur_slot_idx; /* cur nan slot index */ - uint16 pad; + uint16 PAD; nan_sched_stats_t sched; /* sched stats */ wl_nan_mac_stats_t mac; /* mac stats */ } wl_nan_slot_ecounters_v1_t; @@ -23180,7 +26806,7 @@ typedef struct wl_nan_slot_ecounters_v2 { uint16 length; /* struct length starting from version */ uint32 chan[NAN_MAX_BANDS]; /* cur nan slot chanspec of both bands */ uint16 cur_slot_idx; /* cur nan slot index */ - uint16 pad; + uint16 PAD; nan_sched_stats_t sched; /* sched stats */ wl_nan_mac_stats_t mac; /* mac stats */ /* for v2 */ @@ -23199,7 +26825,7 @@ typedef struct wl_nan_slot_ecounters_v3 { uint16 length; /* struct length starting from version */ uint32 chan[NAN_MAX_BANDS]; /* cur nan slot chanspec of both bands */ uint16 cur_slot_idx; /* cur nan slot index */ - uint16 pad; + uint16 PAD; nan_sched_stats_t sched; /* sched stats */ /* for v3 */ wl_nan_mac_stats_v1_t mac; /* mac stats */ @@ -23213,6 +26839,25 @@ typedef struct wl_nan_slot_ecounters_v3 { uint16 bcn_txfail_5g; /* sending 5G beacon failure count */ } wl_nan_slot_ecounters_v3_t; +typedef struct wl_nan_slot_ecounters_v4 { + uint16 version; /* version field */ + uint16 length; /* struct length starting from version */ + uint32 chan[NAN_MAX_BANDS]; /* cur nan slot chanspec of both bands */ + uint16 cur_slot_idx; /* cur nan slot index */ + uint16 PAD; + nan_sched_stats_t sched; /* sched stats */ + /* for v4 */ + wl_nan_mac_stats_v2_t mac; /* mac stats */ + uint16 bcn_rx_drop_rssi; /* Beacon received but ignored due to weak rssi */ + uint16 bcn_rx_drop_rssi_5g; /* 5G Beacon received but ignored due to weak rssi */ + uint16 cnt_rssi_close; /* cnt of beacon rssi > rssi_close received */ + uint16 cnt_rssi_close_5g; /* cnt of 5G beacon rssi > rssi_close received */ + uint16 cnt_rssi_mid; /* cnt of beacon rssi > rssi_middle received */ + uint16 cnt_rssi_mid_5g; /* cnt of 5G beacon rssi > rssi_middle received */ + uint16 bcn_txfail; /* Beacon sending failure count */ + uint16 bcn_txfail_5g; /* sending 5G beacon failure count */ +} wl_nan_slot_ecounters_v4_t; + /* WL_STATS_XTLV_NDP_SESSION_STATUS for ecounters */ #define WL_NAN_SESSION_STATUS_EC_VERSION_1 1 typedef struct wl_nan_ndp_session_status_v1_s { @@ -23226,7 +26871,7 @@ typedef struct wl_nan_ndp_session_status_v1_s { struct ether_addr pnmi_addr; /* Peer NMI addr */ struct ether_addr pndi_addr; /* Peer NDI addr */ uint8 dpe_state; /* DPE state to know where timeout/dpend has come */ - uint8 pad; + uint8 PAD; } wl_nan_ndp_session_status_v1_t; /* WL_STATS_XTLV_NAN_DISC_FRM_STATUS for ecounters */ @@ -23239,10 +26884,32 @@ typedef struct wl_nan_disc_frame_status_v1_s { uint8 reason_code; /* to identify reason when status is failure */ uint8 inst_id; /* Publish or subscribe instance id */ uint8 req_id; /* Requestor instance id */ - uint8 pad; + uint8 PAD; uint16 token; /* seq num to keep track of pkts sent by host */ } wl_nan_disc_frame_status_v1_t; +/* keepalive oob ops */ +typedef enum { + NAN_KA_OOB_OPS_ADD, + NAN_KA_OOB_OPS_DEL, + NAN_KA_OOB_OPS_GET, + NAN_KA_OOB_OPS_MAX +} nan_ka_oob_ops_t; + +/* NAN KEEPALIVE(KA) oob flags */ +typedef enum { + NAN_KA_OOB_FLAG_LEGACY, + NAN_KA_OOB_FLAG_PER_PEER_TX, + NAN_KA_OOB_FLAG_PER_PEER_RX, + NAN_KA_OOB_FLAG_MAX +} nan_ka_oob_flag_t; + +/* NAN KEEPALIVE(KA) oob param */ +typedef struct wl_nan_ka_oob_af_param { + uint8 ops; /* add/del/get */ + uint8 flags; /* per peer tx/ rx keepalive oob or legacy oob */ +} wl_nan_ka_oob_af_param_t; + typedef struct wl_nan_oob_af { uint64 bitmap; /* 16 TU slots in 1024 TU window */ struct ether_addr sa; /* Optional SA. Default set to NMI */ @@ -23251,12 +26918,21 @@ typedef struct wl_nan_oob_af { bool secured; /* Optional. Default set to 0 (Open) */ uint8 map_id; /* Host selected map id. Default 0 */ uint16 timeout; /* OOB AF session timeout in milliseconds */ - uint16 pad[3]; /* Structure padding. Can be used in future */ + wl_nan_ka_oob_af_param_t koap; /* Keep alive oob af additional param */ + uint16 PAD[2]; /* Structure padding. Can be used in future */ uint16 token; /* host generated. Used by FW in TX status event */ uint16 payload_len; uint8 payload[]; /* AF hdr + NAN attrbutes in TLV format */ } wl_nan_oob_af_t; +typedef struct wl_nan_oob_rx_match_payload { + uint16 offset; /* the offset from the start of data field + * in nan_attr_type_t which is the part of RX pkt + */ + uint16 match_length; /* Length to be used for match */ + uint8 payload[]; /* Payload to be used for match */ +} wl_nan_oob_rx_match_payload_t; + /* * BT log definitions */ @@ -23275,7 +26951,7 @@ typedef struct wl_btl { /* WL_BTL_SUBCMD_ENABLE data */ typedef struct wl_blt_enable { uint8 enable; /* 1 - enable, 0 - disable */ - uint8 pad[3]; /* 4-byte struct alignment */ + uint8 PAD[3]; /* 4-byte struct alignment */ } wl_btl_enable_t; /* WL_BTL_SUBCMD_STATS data */ @@ -23303,7 +26979,7 @@ typedef struct wl_blt_stats { uint16 mem_dump_proc_no_bt_ready; /* num proceed if no BT ready */ uint16 mem_dump_proc_no_bt_response; /* num proceed if no BT response */ uint16 mem_dump_proc_no_bt_clock; /* num proceed if no BT clock */ - uint16 pad; /* alignment */ + uint16 PAD; /* alignment */ uint32 last_failed_region; /* start addr of last failed region */ uint32 min_mem_dump_duration; /* min mem dump duration in usec */ uint32 max_mem_dump_duration; /* max mem dump duration in usec */ @@ -23396,10 +27072,12 @@ enum wl_rmc_report_cmd_id { }; enum wl_rmc_report_xtlv_id { - WL_RMC_RPT_XTLV_VER = 0x0, - WL_RMC_RPT_XTLV_BSS_INFO = 0x1, - WL_RMC_RPT_XTLV_CANDIDATE_INFO = 0x2, - WL_RMC_RPT_XTLV_USER_CACHE_INFO = 0x3 + WL_RMC_RPT_XTLV_VER = 0x0, + WL_RMC_RPT_XTLV_BSS_INFO = 0x1, + WL_RMC_RPT_XTLV_CANDIDATE_INFO = 0x2, + WL_RMC_RPT_XTLV_USER_CACHE_INFO = 0x3, + WL_RMC_RPT_XTLV_CANDIDATE_INFO_V2 = 0x4, + WL_RMC_RPT_XTLV_USER_CACHE_INFO_V2 = 0x5 }; /* WL_RMC_RPT_XTLV_BSS_INFO */ @@ -23417,10 +27095,18 @@ typedef struct { uint16 ctl_channel; /* channel */ uint32 time_last_seen; /* delta time (in ms) between cur time and last seen timestamp */ uint16 bss_load; /* BSS load */ - uint8 bssid [6]; /* padding to get 32 bits alignment */ + uint8 bssid[6]; /* BSSID */ } rmc_candidate_info_v1_t; -#define WL_FILTER_IE_VERSION 1 /* deprecated */ +/* WL_RMC_RPT_XTLV_CANDIDATE_INFO_V2 */ +typedef struct { + int16 rssi; /* last seen rssi */ + chanspec_t ctl_channel; /* chanspec of primary channel */ + uint32 time_last_seen; /* delta time (in ms) between cur time and last seen timestamp */ + uint16 bss_load; /* BSS load */ + struct ether_addr bssid; /* BSSID */ +} rmc_candidate_info_v2_t; + enum wl_filter_ie_options { WL_FILTER_IE_CLEAR = 0, /* allow element id in packet.For suboption */ WL_FILTER_IE_SET = 1, /* filter element id in packet.For suboption */ @@ -23441,11 +27127,23 @@ typedef struct wl_filter_ie_iov_v1 { uint16 len; /* Total length of the structure */ uint16 fixed_length; /* Total length of fixed fields */ uint8 option; /* Filter action - check for suboption */ - uint8 pad[1]; /* Align to 4 bytes */ + uint8 PAD[1]; /* Align to 4 bytes */ uint32 pktflag; /* frame type - FC_XXXX */ uint8 tlvs[]; /* variable data (zero in for list ,clearall) */ } wl_filter_ie_iov_v1_t; +#define WL_ASSOC_RESP_PARAMS_V1 (1u) +typedef struct wl_assoc_resp_params_v1 { + uint16 version; /* Structure version */ + uint16 len; /* Total length of the structure */ + uint16 fixed_length; /* Total length of fixed fields */ + uint8 mac_addr[ETHER_ADDR_LEN]; /* peer MAC address */ + uint8 resp_ie_len; /* Assoc_resp IE's length */ + uint8 pad; /* Pad for alignment */ + uint16 status; /* AREQ status code from Host */ + uint8 ies[]; /* Variable data (resp_ies) */ +} wl_assoc_resp_params_v1_t; + /* Event aggregation config */ #define EVENT_AGGR_CFG_VERSION 1 #define EVENT_AGGR_DISABLED 0x0 @@ -23466,17 +27164,8 @@ typedef struct event_aggr_config { uint16 num_events_flush; /* Number of events aggregated before flush */ } event_aggr_config_t; -#ifndef WL_TDMTX_TYPEDEF_HAS_ALIAS -typedef tdmtx_cnt_v1_t tdmtx_cnt_t; -typedef tdmtx_cnt_shm_v1_t tdmtx_cnt_shm_t; -typedef wl_tdmtx_ecounters_v1_t wl_tdmtx_ecounters_t; -#define WL_CNT_TDMTX_STRUCT_SZ (sizeof(tdmtx_cnt_t)) -#define WL_CNT_TDMTX_SHM_SZ (sizeof(tdmtx_cnt_shm_t)) -#endif - /** chanctxt related statistics */ -#define CHANCTXT_STATS_VERSION_1 1 -#define CHANCTXT_STATS_CURRENT_VERSION CHANCTXT_STATS_VERSION_1 +#define CHANCTXT_STATS_VERSION_1 1u typedef struct wlc_chanctxt_stats { uint32 excursionq_end_miss; uint32 activeq_end_miss; @@ -23565,7 +27254,19 @@ enum wl_sae_status { /* SAE Crypto private data magic number mismatch */ WL_SAE_E_CRYPTO_PRIV_MAGIC_MISMATCH = -3091, /* Max retry exhausted */ - WL_SAE_E_MAX_RETRY_LIMIT_REACHED = -3092 + WL_SAE_E_MAX_RETRY_LIMIT_REACHED = -3092, + /* peer sent password ID mismatch to local */ + WL_SAE_E_AUTH_PEER_PWDID_MISMATCH = -3093, + /* user not configured password */ + WL_SAE_E_AUTH_PASSWORD_NOT_CONFIGURED = -3094, + /* user not configured password ID */ + WL_SAE_E_AUTH_PWDID_NOT_CONFIGURED = -3095, + /* Anti-clogging token mismatch */ + WL_SAE_E_AUTH_ANTI_CLOG_MISMATCH = -3096, + /* SAE PWE method mismatch */ + WL_SAE_E_AUTH_PWE_MISMATCH = -3097, + /* SAE-PK validation failed */ + WL_SAE_E_AUTH_PK_VALIDATION = -3098 }; /* PMK manager block. Event codes from -5120 to -6143 */ @@ -23598,7 +27299,7 @@ typedef struct dma_wl_addr_region { uint32 addr_high; } dma_wl_addr_region_t; -#define WL_ROAMSTATS_IOV_VERSION 1 +#define WL_ROAMSTATS_IOV_VERSION_1 1u #define MAX_PREV_ROAM_EVENTS 16u @@ -23640,6 +27341,7 @@ typedef struct { uint16 min_cached_ch_cnt; uint16 partial_roam_scan_cnt; uint16 full_roam_scan_cnt; + uint16 PAD; } roamstats_counter_info_v1_t; /* WL_ROAMSTATS_XTLV_PREV_ROAM_EVENTS */ @@ -23677,11 +27379,11 @@ typedef struct { /** receive signal reporting module interface */ -#define WL_RXSIG_IOV_MAJOR_VER (1u) -#define WL_RXSIG_IOV_MINOR_VER (1u) +#define WL_RXSIG_IOV_MAJOR_VER_1 (1u) +#define WL_RXSIG_IOV_MINOR_VER_1 (1u) #define WL_RXSIG_IOV_MAJOR_VER_SHIFT (8u) -#define WL_RXSIG_IOV_VERSION \ - ((WL_RXSIG_IOV_MAJOR_VER << WL_RXSIG_IOV_MAJOR_VER_SHIFT) | WL_RXSIG_IOV_MINOR_VER) +#define WL_RXSIG_IOV_VERSION_1_1 \ + ((WL_RXSIG_IOV_MAJOR_VER_1 << WL_RXSIG_IOV_MAJOR_VER_SHIFT) | WL_RXSIG_IOV_MINOR_VER_1) #define WL_RXSIG_IOV_GET_MAJOR(x) (x >> WL_RXSIG_IOV_MAJOR_VER_SHIFT) #define WL_RXSIG_IOV_GET_MINOR(x) (x & 0xFF) @@ -23693,17 +27395,20 @@ enum wl_rxsig_cmd_rssi_mode { /* structure defs for 'wl rxsig [cmd]' iovars */ enum wl_rxsig_iov_v1 { - WL_RXSIG_CMD_RSSI = 0x1, /**< combined rssi moving avg */ - WL_RXSIG_CMD_SNR = 0x2, /**< combined snr moving avg */ - WL_RXSIG_CMD_RSSIANT = 0x3, /**< rssi moving avg per-ant */ - WL_RXSIG_CMD_SNRANT = 0x4, /**< snr moving avg per-snr */ - WL_RXSIG_CMD_SMPLWIN = 0x5, /**< config for sampling window size */ - WL_RXSIG_CMD_SMPLGRP = 0x7, /**< config for grouping of pkt type */ - WL_RXSIG_CMD_STA_MA = 0x8, - WL_RXSIG_CMD_MAMODE = 0x9, - WL_RXSIG_CMD_MADIV = 0xa, - WL_RXSIG_CMD_DUMP = 0xb, - WL_RXSIG_CMD_DUMPWIN = 0xc, + WL_RXSIG_CMD_RSSI = 0x1, /**< combined rssi moving avg */ + WL_RXSIG_CMD_SNR = 0x2, /**< combined snr moving avg */ + WL_RXSIG_CMD_RSSIANT = 0x3, /**< rssi moving avg per-ant */ + WL_RXSIG_CMD_SNRANT = 0x4, /**< snr moving avg per-snr */ + WL_RXSIG_CMD_SMPLWIN = 0x5, /**< config for sampling window size */ + WL_RXSIG_CMD_SMPLGRP = 0x7, /**< config for grouping of pkt type */ + WL_RXSIG_CMD_STA_MA = 0x8, + WL_RXSIG_CMD_MAMODE = 0x9, + WL_RXSIG_CMD_MADIV = 0xa, + WL_RXSIG_CMD_DUMP = 0xb, + WL_RXSIG_CMD_DUMPWIN = 0xc, + WL_RXSIG_CMD_RSSI_EXP = 0xd, /**< config for expiry time in ms */ + WL_RXSIG_CMD_RSSI_COMP = 0xe, /**< config for rssi compensation threshold */ + WL_RXSIG_CMD_RSSI_COMP_TBL = 0xf, /**< config for rssi compensation table */ WL_RXSIG_CMD_TOTAL }; @@ -23716,12 +27421,12 @@ struct wl_rxsig_cfg_v1 { struct wl_rxsig_iov_rssi_v1 { int8 rssi; uint8 rssi_qdb; - uint8 pad[2]; + uint8 PAD[2]; }; struct wl_rxsig_iov_snr_v1 { int16 snr; - uint16 pad; + uint16 PAD; }; struct wl_rxsig_iov_rssi_ant_v1 { @@ -23729,7 +27434,18 @@ struct wl_rxsig_iov_rssi_ant_v1 { uint8 frac[WL_RSSI_ANT_MAX]; uint8 rssi_mode; /**< MODE_DB or MODE_QDB */ uint8 num_of_ant; /**< total number of ants */ - uint8 pad[2]; /**< padding for 32bit align */ + uint8 PAD[2]; /**< padding for 32bit align */ +}; + +#define WL_RXSIG_RSSI_COMP_TBL_V1 (1u) +struct wl_rxsig_rssi_comp_tbl_v1 { + uint16 version; /**< version */ + uint8 num_steps; /**< number of RSSI steps for gradual compensation per BW. + * The total length of tbl[] must be multiple of this value + * Example: 3xnum_steps is needed to support 40, 80 and 160MHz + */ + uint8 pad; + uint8 tbl[]; /**< compensation value tables - starting on 32-bit alignment */ }; #ifdef BCM_SDC @@ -23739,7 +27455,7 @@ typedef struct { uint16 version; uint16 type; uint8 activate; - uint8 pad; + uint8 PAD; } sdc_trigger_cfg_t; typedef enum sdc_trigger_types { @@ -23889,9 +27605,16 @@ typedef struct wl_avs_info_v1 { #define WL_CLM_HAS_OFDM_EIRP 0x2000u /**< Flag for HAS_OFDM_EIRP */ #define WL_CLM_NO_160MHZ 0x4000u /**< Flag for NO_160MHZ */ #define WL_CLM_NO_80_80MHZ 0x8000u /**< Flag for NO_80_80MHZ */ -#define WL_CLM_NO_240MHZ 0x10000u /**< Flag for NO_240MHZ */ #define WL_CLM_NO_320MHZ 0x200000u /**< Flag for NO_320MHZ */ #define WL_CLM_NO_160_160MHZ 0x400000u /**< Flag for NO_160_160MHZ */ +#define WL_CLM_CBP_FCC 0x800000u /**< Flag for CBP_FCC */ +#define WL_CLM_6G_P2P_FLAGS_MASK 0x7000000u /**< 3 bits to represent 6GHz p2p releated flags + * 0x3 ~ 0x6 are reserved for now + */ +#define WL_CLM_C2C_DISABLED 0x0u /**< No C2C related flags */ +#define WL_CLM_C2C_EU 0x1000000u /**< Flag for C2C_EU */ +#define WL_CLM_C2C_US 0x2000000u /**< Flag for C2C_US */ +#define WL_CLM_VLP_P2P_DISABLE 0x7000000u /**< Flag VLP_P2P_DISABLE */ #define WL_CLM_DFS_FCC WL_CLM_DFS_TPC /**< Flag for DFS FCC */ #define WL_CLM_DFS_EU (WL_CLM_DFS_TPC | WL_CLM_RADAR_TYPE_EU) /**< Flag for DFS EU */ @@ -23916,6 +27639,7 @@ enum wl_wbus_cmd { WL_WBUS_CMD_UNIT_TEST = 2, WL_WBUS_CMD_BT_TEST = 3, WL_WBUS_CMD_CAP = 4, + WL_WBUS_CMD_COEX_CFG = 5, WL_WBUS_CMD_LAST }; @@ -23978,7 +27702,7 @@ typedef struct wlc_btcec_stats_v1 { typedef struct wlc_btcec_sch_stats_v2 { uint8 sch_id; /* schedule id */ uint8 flags; /* flags. see BTCEC_SCHSTATS_FLAG_xxx */ - uint8 pad[2]; + uint8 PAD[2]; uint32 slcnt; /* num slots granted to bt */ uint32 skip; /* count of btsc le/page scan, skipped */ uint32 btdur; /* duration in millisec granted for bt corr to which wlsc slept */ @@ -23995,7 +27719,7 @@ typedef struct wlc_btcec_stats_v2 { uint32 add_msg_cnt; /* rx add messages counter */ uint32 del_msg_cnt; /* rx del messages counter */ uint32 stats_dur; /* dur in sec for which stats is accumulated */ - uint8 pad[3]; + uint8 PAD[3]; uint8 num_sstats; /* number of elements in sstats struct */ wlc_btcec_sch_stats_v2_t sstats[]; /* sch specific stats */ } wlc_btcec_stats_v2_t; @@ -24006,7 +27730,7 @@ typedef struct wlc_btcec_stats_v2 { typedef struct wlc_btcec_sch_stats_v3 { uint8 sch_id; /* schedule id */ uint8 flags; /* flags. see BTCEC_SCHSTATS_FLAG_xxx */ - uint8 pad[2]; + uint8 PAD[2]; uint32 slcnt; /* num slots granted to bt */ uint32 skip; /* count of btsc le/page scan, skipped */ uint32 btdur; /* duration in millisec granted for bt corr to which wlsc slept */ @@ -24018,7 +27742,7 @@ typedef struct wlc_btcec_sch_stats_v3 { uint16 req_duration; /* duration finally scheduled in msch, in ms */ uint16 req_interval; /* interval finally scheduled in msch, in ms */ uint16 min_duty_cycle; /* interval finally scheduled in msch, in ms */ - uint16 pad2; + uint16 PAD; } wlc_btcec_sch_stats_v3_t; /* btcec stats for general reporting */ @@ -24030,7 +27754,7 @@ typedef struct wlc_btcec_stats_v3 { uint32 add_msg_cnt; /* rx add messages counter */ uint32 del_msg_cnt; /* rx del messages counter */ uint32 stats_dur; /* dur in sec for which stats is accumulated */ - uint8 pad[3]; + uint8 PAD[3]; uint8 num_sstats; /* number of elements in sstats struct */ wlc_btcec_sch_stats_v3_t sstats[]; /* sch specific stats */ } wlc_btcec_stats_v3_t; @@ -24055,7 +27779,7 @@ typedef struct wlc_btcec_periodic_sch_stats_v1 { uint16 req_duration; /* duration finally scheduled in msch, in ms */ uint16 req_interval; /* interval finally scheduled in msch, in ms */ uint16 min_duty_cycle; /* interval finally scheduled in msch, in ms */ - uint16 pad2; + uint16 PAD; } wlc_btcec_periodic_sch_stats_v1_t; /* btcec stats for periodic ecounters reporting */ @@ -24066,11 +27790,29 @@ typedef struct { uint8 tx_msg_cnt; /* transmitted messages counter */ uint8 add_msg_cnt; /* rx add messages counter */ uint8 del_msg_cnt; /* rx del messages counter */ - uint8 pad[3]; + uint8 PAD[3]; uint8 num_sstats; /* number of elements in sstats struct */ wlc_btcec_periodic_sch_stats_v1_t sstats[BTCEC_SCHED_MAX_V1]; /* sch specific */ } wlc_btcec_periodic_stats_v1_t; +#define WLC_BTCEC_PERIODIC_CNTRS_V2 (2u) +typedef struct { + uint16 ver; + uint16 len; + uint8 rx_msg_cnt; /* received messages counter */ + uint8 tx_msg_cnt; /* transmitted messages counter */ + uint8 add_msg_cnt; /* rx add messages counter */ + uint8 del_msg_cnt; /* rx del messages counter */ + uint8 btmc_cnt; /* btmc state check count */ + uint8 fb_schupd_cnt; /* fixed bit:schedule update count */ + uint8 fb_btmc_cnt; /* fixed bit:btmc update count */ + uint8 num_sstats; /* number of elements in sstats struct */ + uint32 fixed_bits_lsb; /* state of gci fixed bits */ + uint32 btmc_active_ts; /* last btmc active timestamp in ms */ + uint32 btmc_idle_ts; /* last btmc idle timestamp in ms */ + wlc_btcec_periodic_sch_stats_v1_t sstats[BTCEC_SCHED_MAX_V1]; /* sch specific */ +} wlc_btcec_periodic_stats_v2_t; + #define WBUS_OFFLOAD_STATS_V1 1u #define WBUS_OFFLOAD_USER_STATS_V1 1u @@ -24078,7 +27820,7 @@ typedef struct wbus_offload_user_stats_v1 { uint16 version; /* version of this structure */ uint16 len; /* size of this structure */ uint8 type; /* Offload type */ - uint8 pad[3]; + uint8 PAD[3]; uint32 num_accepted; /* num of times user got accepted */ uint32 num_rejected; /* num of times user got rejected */ uint32 num_failed; /* num of times user accept failed */ @@ -24092,7 +27834,7 @@ typedef struct wbus_offload_stats_v1 { uint32 num_rejected; /* num of rejected users so far */ uint32 num_rejected_bt; /* num of rejected users so far for BT */ uint32 num_rejected_all; /* num times all offloads are rejected */ - uint8 pad[3]; + uint8 PAD[3]; uint8 num_user; /* num of users stats */ wbus_offload_user_stats_v1_t user_stats[]; /* per user stats */ } wbus_offload_stats_v1_t; @@ -24113,184 +27855,6 @@ typedef struct key_update_info_v1 /* Key update flag bit field */ #define KEY_UPD_FLAG_ADD_KEY 0x1 /* 0 - Removal, 1 - Add key */ -#ifdef WLLLW -/* LLW Session */ -#define LLW_VERSION 1 -#define LLW_STATS_VERSION 1 - -/* LLW roles */ -#define LLW_ROLE_SCHEDULER 0 -#define LLW_ROLE_CLIENT 1 - -/* LLW modes */ -#define LLW_MODE_GAPS 0 -#define LLW_MODE_BACK_TO_BACK 1 - -/* LLW session max values */ -#define LLW_MAX_SESSION_ID 10 -#define LLW_MAX_FLOW_ID 40 -#define LLW_MAX_CLIENT_NUM 15 -#define LLW_MAX_GAPS_PERIOD 20 -#define LLW_MAX_GAPS_VAR 3 -#define LLW_MAX_RETX_CNT 10 -#define LLW_MAX_AIFSN EDCF_AIFSN_MAX -#define LLW_MAX_CWMIN EDCF_ECW_MAX -#define LLW_MAX_CWMAX EDCF_ECW_MAX -#define LLW_MAX_PER_NUMERATOR 100 -#define LLW_MAX_PER_DENOM 10000 -#define LLW_MAX_CLIENT_ID 15 -#define LLW_MAX_PKT_SIZE 1500 -#define LLW_MAX_PKT_NUM 10 -#define LLW_MAX_MCS 9 -#define LLW_MAX_NUM_STREAMS 8 -#define LLW_MAX_IBS 32 - -/* Per LLW session config */ -/* WL_LLW_CMD_SESSION_CREATE, WL_LLW_CMD_SESSION_UPDATE */ -typedef struct wl_llw_session_cfg { - uint8 session_id; - uint8 role; - uint8 mode; - uint8 client_id; - uint8 gaps_period; - uint8 gaps_var; - uint8 aifsn; - uint8 ecwmin; /* exponent value for minimum contention window */ - uint8 ecwmax; /* exponent value for maximum contention window */ - uint8 mcs; - uint8 num_streams; - uint8 ibs; /* interblock spacing in usecs, for spacing between Transaction Blocks */ - uint16 ul_pkt_size; - uint16 dl_pkt_size; - uint16 per_denom; /* denominator for target PER */ - uint8 per_numerator; /* this value divided by per_denom gives the target PER */ - uint8 dl_pkt_num; - uint8 client_num; - uint8 retx_cnt; - uint8 pwr_save; - uint8 auto_ba; /* automatic RX/TX BA session setup (no negotiation needed) */ - uint8 if_index; - uint8 padding[3]; - struct ether_addr multicast_addr; - struct ether_addr scheduler_addr; -} wl_llw_session_cfg_t; - -/* WL_LLW_CMD_SESSION_DELETE, WL_LLW_CMD_SESSION_ENABLE, WL_LLW_CMD_SESSION_DISABLE, */ -/* WL_LLW_CMD_SESSION_GET */ -typedef struct wl_llw_session_cmd { - uint8 session_id; - uint8 padding[3]; -} wl_llw_session_cmd_t; - -/* LLW client config */ -/* WL_LLW_CMD_CLIENT_ADD, WL_LLW_CMD_CLIENT_DELETE, WL_LLW_CMD_CLIENT_GET */ -typedef struct wl_llw_client_cfg { - uint8 session_id; - uint8 client_id; - struct ether_addr mac; -} wl_llw_client_cfg_t; - -/* Get list of session IDs from FW */ -/* WL_LLW_CMD_SESSION_ID */ -typedef struct llw_session_id_list { - uint8 id_count; /* Number of session IDs */ - uint8 list[]; /* list of session IDs */ -} llw_session_id_list_t; - -/* LLW XTLV structures */ -typedef struct wl_llw_iov_cmd { - uint16 version; - uint8 cmd_cnt; - uint8 pad; - uint8 cmds[]; -} wl_llw_iov_cmd_t; - -typedef struct wl_llw_iov_sub_cmd { - uint16 type; - uint16 len; - union { - int32 status; /* Processed status - Set by FW */ - uint32 options; /* Command Process Options - Set by Host */ - } u; - uint8 data[]; -} wl_llw_iov_sub_cmd_t; - -/* to be used in type field of wl_llw_iov_sub_cmd_t structure while issuing LLW commands */ -typedef enum wl_llw_sub_cmd_xtlv_id { - WL_LLW_CMD_SESSION_ID, - WL_LLW_CMD_SESSION_CREATE, - WL_LLW_CMD_SESSION_DELETE, - WL_LLW_CMD_SESSION_UPDATE, - WL_LLW_CMD_SESSION_ENABLE, - WL_LLW_CMD_SESSION_DISABLE, - WL_LLW_CMD_SESSION_GET, - WL_LLW_CMD_CLIENT_ADD, - WL_LLW_CMD_CLIENT_DELETE, - WL_LLW_CMD_CLIENT_GET, - WL_LLW_CMD_FLOW_ADD, - WL_LLW_CMD_FLOW_DELETE, - WL_LLW_CMD_FLOW_GET, - WL_LLW_CMD_STATS -} wl_llw_sub_cmd_xtlv_id_t; - -/* LLW stats */ -typedef enum wl_llw_xtlv { - WL_LLW_XTLV_STATS -} wl_llw_xtlv_t; - -typedef struct wl_llw_stats { - uint32 txpackets; - uint32 txbytes; - uint32 txrts; - uint32 txnocts; - uint32 txnoack; - uint32 txfail; - uint32 txretry; - uint32 txdropped; - uint32 tx_avg_q_time; - uint32 tx_min_q_time; - uint32 tx_max_q_time; - uint32 tx_avg_rem_lifetime; - uint32 tx_min_rem_lifetime; - uint32 tx_max_rem_lifetime; - uint32 rxpackets; - uint32 rxbytes; - uint32 rxfail; - uint32 rxretry; - uint32 txschedfrm; - uint32 retxschedfrm; -} wl_llw_stats_t; - -typedef struct wl_llw_stats_hdr { - uint16 version; - uint16 stats_cnt; - uint32 tot_len; - uint8 stat_xtlvs[]; -} wl_llw_stats_hdr_t; - -/* WL_LLW_XTLV_STATS */ -typedef struct wl_llw_stats_xtlv { - uint16 type; - uint16 len; - uint8 stats[]; -} wl_llw_stats_xtlv_t; - -/* WL_LLW_CMD_STATS */ -typedef struct wl_llw_stats_cmd { - uint8 session_id; - uint8 client_id; - uint16 padding; -} wl_llw_stats_cmd_t; - -/* LLW flow ring ID config */ -/* WL_LLW_CMD_FLOW_ADD, WL_LLW_CMD_FLOW_DELETE, WL_LLW_CMD_FLOW_GET */ -typedef struct wl_llw_flow_cfg { - uint8 session_id; - uint8 flow_id; - uint16 padding; -} wl_llw_flow_cfg_t; -#endif /* End of LLW Session */ - #define WL_OMI_CONFIG_VERSION_1 1u /* values for valid_bm */ @@ -24301,9 +27865,15 @@ typedef struct wl_llw_flow_cfg { #define OMI_CONFIG_VALID_BMP_ERSU_DISABLE 0x0010u #define OMI_CONFIG_VALID_BMP_DLMU_RSD_RCM 0x0020u #define OMI_CONFIG_VALID_BMP_ULMU_DATA_DISABLE 0x0040u +#define OMI_CONFIG_VALID_BMP_BW_EXT 0x0080u +#define OMI_CONFIG_VALID_BMP_RXNSS_EXT 0x0100u +#define OMI_CONFIG_VALID_BMP_TXNSTS_EXT 0x0200u #define OMI_CONFIG_VALID_BMP_ALL 0x0FFFu -#define OMI_CONFIG_BW_MAX 3u +#define OMI_CONFIG_BW_MAX 3u +#define OMI_CONFIG_BW_EXT_MAX 1u +#define OMI_CONFIG_RXNSS_EXT_MAX 1u +#define OMI_CONFIG_TXNSTS_EXT_MAX 1u typedef struct wl_omi_config { uint16 valid_bm; /* validity bitmask for each config */ @@ -24314,7 +27884,9 @@ typedef struct wl_omi_config { uint8 ersu_disable; uint8 dlmu_resound_rec; uint8 ulmu_data_disable; - uint8 pad[3]; + uint8 bw_ext; + uint8 rxnss_ext; + uint8 txnsts_ext; } wl_omi_config_t; typedef struct wl_omi_req { @@ -24326,17 +27898,16 @@ typedef struct wl_omi_req { /* Bits for ULMU disable reason */ #define OMI_ULMU_DISABLED_HOST 0x01u /* Host has disabled through he omi */ -#ifdef WLAWDL -#define OMI_ULMU_DISABLED_AWDL 0x02u /* Disabled due to AWDL enabled */ -#endif /* WLAWDL */ - #define OMI_ULMU_DISABLED_NAN 0x04u /* Disabled due to NAN enabled */ #define OMI_ULMU_DISABLED_BTCOEX 0x08u /* Disabled while in BT Coex activity */ #define OMI_ULMU_DISABLED_LTECOEX 0x10u /* Disabled due to LTE Coex activity */ -#define OMI_ULMU_DISABLED_NON11AX_CONN 0x20u /* Disabled due to not associated to 11ax AP */ +#define OMI_ULMU_DISABLED_NON11AX_CONN 0x20u /* Disabled due to non-11ax connection */ #define OMI_ULMU_DISABLED_THROTTLE_ENABLE 0x40u /* Disabled due to throttle timer running */ -#define OMI_ULMU_DISABLED_TXCHAIN_DOWNGRADE 0x80u /* Disabled due to Txchain downgrade */ -#define OMI_ULMU_DISABLED_TX_DUTY_CYCLE 0x100u /* Disabled due to tx duty cycle */ +#define OMI_ULMU_DISABLED_TXCHAIN_DOWNGRADE 0x80u /* Disabled due to Txchain downgrade */ +#define OMI_ULMU_DISABLED_TX_DUTY_CYCLE 0x100u /* Disabled due to tx duty cycle */ +#define OMI_ULMU_DISABLED_VLP 0x200u /* Disabled due to VLP */ +#define OMI_ULMU_DISABLED_DUALSTA 0x400u /* Disabled due to dualsta */ +#define OMI_ULMU_DISABLED_UNSUPPORTED_TXPWR 0x800u /* Disabled due to unsupported tx power */ /* Bits for DLMU Resound Recommendation reason */ #define OMI_DLMU_RSD_RCM_HOST (0x1u << 0u) /* Host directly set the bit */ @@ -24365,6 +27936,21 @@ typedef struct wl_omi_status_v2 { uint16 dlmu_rsd_rcm_reason; /* DL MU-MIMO recommendation reasons bitmap */ } wl_omi_status_v2_t; +#define WL_OMI_STATUS_VERSION_3 3u +typedef struct wl_omi_status_v3 { + uint16 version; + uint16 len; + wl_omi_config_t omi_pending; /* OMI requests pending */ + uint16 omi_data; /* Current HE OM Control field for completed OMI req */ + uint16 ulmu_disable_reason; /* Bits representing UL OFDMA disable reasons */ + uint32 ulmu_disable_duration; /* Duration (ms) for which UL OFDMA is disabled */ + uint32 dlmu_rsd_rcm_duration; /* Dur (ms) for which ResoundRecommentation is set */ + uint16 dlmu_rsd_rcm_mpf_state; /* The MPF state value */ + uint16 dlmu_rsd_rcm_reason; /* DL MU-MIMO recommendation reasons bitmap */ + uint16 omi_data_ext; /* Current EHT OM Control field for completed OMI req */ + uint16 PAD; +} wl_omi_status_v3_t; + #define WL_ULMU_DISABLE_STATS_VERSION_1 1u typedef struct wl_ulmu_disable_stats { uint16 version; @@ -24379,6 +27965,27 @@ typedef struct wl_ulmu_disable_stats { uint16 avg_latency; /* Avg latency by AP to re-act for UL OFDMA disable request (ms) */ } wl_ulmu_disable_stats_v1_t; +/* Bits for configuring the feature for setting max Rx MPDU size to 4K for 160MHz + * association with BRCM AP + */ +#define WL_RXMPDU_MAXLEN_4K_EN 0x1u /* Enable/disable the feature */ +#define WL_RXMPDU_MAXLEN_4K_ACTIVE 0x2u /* Status to indicate if the feature is active */ + +#define WL_TPE_TXPWR_CONFIG_VERSION_1 1u +#define WL_TPE_TXPWR_MAX_LEN 8u + +typedef struct wl_tpe_txpwr_config { + uint16 version; + uint16 len; + uint8 idx; /* Index of profile */ + uint8 cat; /* Transmit Power Info category */ + uint8 intr; /* Transmit Power Info Interpretation */ + uint8 cnt; /* Transmit Power Info count */ + uint8 regcat; /* reg info power category */ + uint8 PAD[3]; + int8 txpwr[WL_TPE_TXPWR_MAX_LEN]; /* Maximum TX power */ +} wl_tpe_txpwr_config_v1_t; + /* sub-xtlv IDs within WL_STATS_XTLV_WL_SLICE_TX_HISTOGRAMS */ enum wl_tx_histogram_id { WL_TX_HIST_TXQ_ID = 1, @@ -24392,7 +27999,7 @@ enum wl_tx_histogram_id { typedef struct wl_tx_hist { uint16 hist_bmap; /* bit N indicates histogram follows for priority or fifo N */ uint16 hist_count; /* count of histograms in var len array */ - uint32 hist[1]; /* var len array of histograms each prefix by hist length */ + uint32 hist[BCM_FLEX_ARRAY]; /* var len array of histograms each prefix by hist length */ } wl_tx_hist_t; #define WL_TX_HIST_FIXED_LEN (OFFSETOF(wl_tx_hist_t, hist)) @@ -24469,7 +28076,7 @@ enum wl_tx_queue_depth_id { typedef struct wl_tx_queue_depth { uint16 queue_depth_bmap; /* bitmap of queue depth in var len array */ uint16 queue_depth_count; /* count of queue depth in var len array */ - uint16 queue_depth[1]; /* var len array of queue depth */ + uint16 queue_depth[BCM_FLEX_ARRAY]; /* var len array of queue depth */ } wl_tx_queue_depth_t; #define WL_TX_QUEUE_DEPTH_FIXED_LEN (OFFSETOF(wl_tx_queue_depth_t, queue_depth)) @@ -24521,7 +28128,7 @@ enum wl_pcie_tx_histogram_id { /* structure for PCIE_TX_HIST_ID */ typedef struct wl_pcie_tx_hist { uint16 ring_id; /* PCIe ring id */ - uint16 pad; /* 4-byte alignment */ + uint16 PAD; /* 4-byte alignment */ wl_tx_hist_t tx_hist; /* hist_bmap: * 0x1=tx histogram * 0x2=tx status pending histogram @@ -24544,7 +28151,7 @@ typedef struct wl_pcie_tx_queue_depth { uint16 ring_id; /* PCIe ring id */ uint16 queue_depth; /* queue depth of ring id */ uint16 tx_status_pend; /* tx status pending of ring id */ - uint16 pad; /* 4-byte alignment */ + uint16 PAD; /* 4-byte alignment */ } wl_pcie_tx_queue_depth_t; #define WL_PCIE_TX_QUEUE_DEPTH_FIXED_LEN sizeof(wl_pcie_tx_queue_depth_t) @@ -24562,15 +28169,14 @@ typedef struct wl_wsec_del_pmk { #define WL_WSEC_DEL_PMK_FIXED_LEN_V1 OFFSETOF(wl_wsec_del_pmk_t, xtlvs) /* WTC */ -#define WLC_WTC_ROAM_VER_1 1 - -#define WLC_WTC_ROAM_CUR_VER WLC_WTC_ROAM_VER_1 +#define WLC_WTC_ROAM_VER_1 1u #define WLC_WTC_ROAM_CONFIG_HDRLEN 4u typedef enum wtc_band_list { WTC_BAND_2G = 0, WTC_BAND_5G = 1, - WTC_MAX_BAND = 2 + WTC_BAND_6G = 2, + WTC_MAX_BAND = 3 } wtc_band_list_e; typedef struct wlc_wtcroam { @@ -24587,7 +28193,7 @@ typedef struct wlc_wtcconfig_info { } wlc_wtcconfig_info_v1_t; /* RCROAM */ -#define WLC_RC_ROAM_VER_1 1 +#define WLC_RC_ROAM_VER_1 1u typedef struct wlc_rcroam { uint16 ver; @@ -24603,7 +28209,6 @@ typedef struct wlc_rcroam_info_v1 { bool enab; } wlc_rcroam_info_v1_t; -#define WLC_RC_ROAM_CUR_VER WLC_RC_ROAM_VER_1 #define RCROAM_HDRLEN 4u #define MAX_RCSCAN_TIMER 300u @@ -24618,7 +28223,7 @@ typedef struct wlc_rcroam_info_v1 { #define WLC_RCROAM_RESET_WTCREQ 7 /* WTC request overriding rcroam */ #define WLC_RCROAM_RESET_RSN_ABORT 8 /* Reset RCROAM params due to roam abort */ -#define WLC_SILENT_ROAM_VER_1 1 +#define WLC_SILENT_ROAM_VER_1 1u /* silent roam information struct */ typedef struct wlc_sroam_info_v1 { /* Silent roam Set/Get value */ @@ -24635,7 +28240,7 @@ typedef struct wlc_sroam_info_v1 { * out from rssi range */ uint8 sroam_time_since; /* elapsed time since start monitoring */ - uint8 pad[3]; + uint8 PAD[3]; uint32 sroam_txfrm_prev; /* save current tx frame counts */ uint32 sroam_rxfrm_prev; /* save current rx frame counts */ } wlc_sroam_info_v1_t; @@ -24646,17 +28251,16 @@ typedef struct wlc_sroam { uint8 data[]; } wlc_sroam_t; -#define WLC_SILENT_ROAM_CUR_VER WLC_SILENT_ROAM_VER_1 #define SROAM_HDRLEN 4u #define DEF_SROAM_OFF 0 #define DEF_SROAM_MIN_RSSI -65 -#define DEF_SROAM_RSSI_RANGE 3u -#define DEF_SROAM_SCORE_DELTA 1u -#define DEF_SROAM_PERIOD_TIME 10u -#define DEF_SROAM_INACT_CNT 5u +#define DEF_SROAM_RSSI_RANGE 8u +#define DEF_SROAM_SCORE_DELTA 0 +#define DEF_SROAM_PERIOD_TIME 5u +#define DEF_SROAM_INACT_CNT 10u #define MAX_SROAM_RSSI -70 -#define MAX_SROAM_RSSI_RANGE 5u +#define MAX_SROAM_RSSI_RANGE 10u #define MAX_SROAM_SCORE_DELTA 10u #define MAX_SROAM_PERIOD_TIME 250u #define SROAM_BAND_AUTO 3u @@ -24682,7 +28286,7 @@ typedef enum wl_macdbg_macsmpl_status { typedef struct wl_macsmpl_start_param { uint32 trig_condition; /* trigger condition */ uint16 gpio_mux; /* MACControl1 GPIOSel field */ - uint8 pad[2]; /* 4-byte struct alignment */ + uint8 PAD[2]; /* 4-byte struct alignment */ } wl_macsmpl_param_start_t; /* MAC SC fragment request data */ @@ -24756,7 +28360,7 @@ typedef struct hp2p_counters_hdr { uint16 version; /* version of hp2p_counters_t structure */ uint16 len; uint16 slice_idx; - uint16 pad; + uint16 PAD; uint8 counters[]; } hp2p_counters_hdr_t; @@ -24766,7 +28370,7 @@ typedef struct hp2p_rllw_stats_hdr { uint16 version; /* version of hptp_rllw_stats structure */ uint16 len; /* length of the payload */ uint8 slice_idx; /* Slice idx BAND_2G_INDEX - 0 / BAND_5G_INDEX - 1 */ - uint8 pad[3]; + uint8 PAD[3]; uint8 stats[]; /* rllw_stats instance */ } hp2p_rllw_stats_hdr_t; @@ -24827,14 +28431,14 @@ typedef struct hp2p_tx_config { uint8 burst_interval; uint8 latency_target; uint8 max_retry; - uint8 pad; + uint8 PAD; } hp2p_tx_config_t; typedef struct hp2p_rx_config { struct ether_addr peer_addr; uint16 flags; /* flags to enable/disable AMPDU, AMSDU, RDG, AMPDU Reorder */ uint8 tid; - uint8 pad; + uint8 PAD; uint16 ba_wsize; /* AMPDU BA Window size */ } hp2p_rx_config_t; @@ -24847,6 +28451,7 @@ typedef struct hp2p_udbg_config { #define WLC_HP2P_RLLW_RETRY_LIMIT 7u #define WLC_HP2P_MAX_PKTLIFETIME_IN_MS 2000u /* 2 seconds */ +#define WLC_HP2P_MAX_CCA_THRESHOLD 100u /* 100 percent */ /* * nav_thresh: 13 : By default set to 13ms @@ -24868,7 +28473,8 @@ typedef struct hp2p_rllw_cfg { uint16 hof_wait_thr; /* HOF packet wait threshold in ms */ uint16 hof_switch_dur; /* How long to stay in the switched band in ms */ uint16 hof_pkt_life_thr; /* HOF remaining pkt lifetime threshold in ms */ - uint16 pad; + uint8 cca_thresh; /* CCA threshold in percentage for HOF switch */ + uint8 PAD; } hp2p_rllw_cfg_t; #define WL_HP2P_CAP_MPEER 0x01u /* Multipeer Hp2p */ @@ -24914,7 +28520,7 @@ typedef struct wl_hp2p_stats_hdr { /* Per Slice RLLW Stats */ typedef struct wlc_hp2p_rllw_slice_stats { uint8 slice; /* slice number */ - uint8 pad; + uint8 PAD; uint16 n_hnav_intrs; /* # of high nav interrupts on slice n */ uint16 n_overrides; /* # of overrides */ uint16 n_switches; /* # of switches */ @@ -24933,7 +28539,7 @@ typedef struct wlc_hp2p_rllw_slice_stats { /* Peer specific stats */ typedef struct { uint8 slice; /* slice number */ - uint8 pad[3]; + uint8 PAD[3]; uint16 n_overrides; /* # of overrides */ uint16 n_switches; /* # of switches */ uint32 n_switched_pkts; /* # of packets after switching to slice n */ @@ -25007,7 +28613,8 @@ enum tx_profile_param_id { WL_TX_PROFILE_PARAM_AGGRE = 4, WL_TX_PROFILE_PARAM_AMSDU = 5, WL_TX_PROFILE_PARAM_AMPDU = 6, - WL_TX_PROFILE_PARAM_LAST = 7 + WL_TX_PROFILE_PARAM_LIFETIME = 7, + WL_TX_PROFILE_PARAM_LAST = 8 }; typedef enum tx_profile_param_id tx_profile_param_id_t; @@ -25035,7 +28642,9 @@ typedef enum tx_profile_cmd_id { /* Show TX Profile stats */ WL_TX_PROFILE_STATS = 5, /* Show Tx Profile tagged packets log */ - WL_TX_PROFILE_PKT_LOGS = 6 + WL_TX_PROFILE_PKT_LOGS = 6, + /* Set the number of logs for the profile tagged packets */ + WL_TX_PROFILE_PKT_LOG_NUM = 7 } tx_profile_cmd_id_t; typedef struct tx_profile_index_params { @@ -25065,6 +28674,8 @@ typedef enum wl_rffe_cmd_type { WL_RFFE_CMD_ELNABYP_MODE = 1, WL_RFFE_CMD_REG = 2, WL_RFFE_CMD_ELNA_VDD_MODE = 3, + WL_RFFE_CMD_DRV_STRENGTH = 4, + WL_RFFE_CMD_RX_MODE = 5, WL_RFFE_CMD_LAST } wl_rffe_cmd_type_t; @@ -25076,6 +28687,32 @@ typedef struct { uint32 value; /**< read/write value */ } rffe_reg_t; +typedef struct { + uint32 slaveid; /**< rFEM SlaveID */ + uint32 ds_val; /**< drive strength code */ +} rffe_drv_strength_t; + +/* subcommand ids for srcb */ +enum wl_srcb_cmd_type { + WL_SRCB_CMD_REG = 0u, /* get/set registers */ + WL_SRCB_CMD_LAST +}; + +#define WL_SRCB_REG_VERSION_1 1u + +typedef struct wl_srcb_reg_v1 { + uint32 address; /* address */ + uint32 value; /* value */ +} wl_srcb_reg_v1_t; + +typedef struct wl_srcb_v1 { + uint16 subcmd_version; /* Version of the sub-command */ + uint16 length; /* Length of the particular struct being used in union */ + union { + wl_srcb_reg_v1_t reg_v1; /* reg data */ + } u; +} wl_srcb_v1_t; + #ifndef BCMUTILS_ERR_CODES /* @@ -25266,6 +28903,8 @@ typedef struct wlc_rc1cx_status_v2 { /* ifdef (WLC_OBSS_HW) */ /* OBSS HW specific Macros */ #define WLC_OBSS_HW_CMD_VERSION_1 1u +#define WLC_OBSS_HW_CMD_VERSION_2 2u +#define WLC_OBSS_HW_CMD_VERSION_3 3u /* OBSS HW config sub command identification flag */ #define OBSS_HW_CFG_SUB_CMD_ENABLE (1u << 0u) @@ -25297,10 +28936,12 @@ typedef struct wlc_rc1cx_status_v2 { #define WLC_OBSS_HW_TEST_MITI_TX_ONLY 2u /* Rx mitigation disabled, Tx mitigation */ #define WLC_OBSS_HW_TEST_MITI_TX_RX_FILT 3u /* Rx Tx mitigation enabled */ #define WLC_OBSS_HW_TEST_MITI_CHAN_CHANGE 4u /* Mitigation by chanspec change */ +#define WLC_OBSS_HW_TEST_MITI_RX_ONLY 5u /* Tx mitigation disabled, Rx mitigation */ +#define WLC_OBSS_HW_TEST_MITI_TX_RX_NO_FILT 6u /* Rx Tx mitigation enabled, no filter */ +#define WLC_OBSS_HW_TEST_MITI_LAST WLC_OBSS_HW_TEST_MITI_TX_RX_NO_FILT #define WL_OBSS_ANT_MAX 2u /* Max Antennas */ #define ACPHY_OBSS_STATS_BIN_CNT 8u /* min 1 for default */ -#define ACPHY_OBSS_SUBBAND_CNT 8u /* Max sub band counts i.e., 160Mhz = 8 * 20MHZ */ enum wlc_obss_hw_cmd_id { WLC_OBSS_HW_CMD_VER = 1u, @@ -25332,6 +28973,82 @@ typedef struct wlc_obss_hw_test_v1 { uint8 mitigation_mode; /* mitigation enabling/disabling options */ } wlc_obss_hw_test_v1_t; +#define OBSS_HW_CFG_FEATURE_DISABLED 0u +#define OBSS_HW_CFG_STATS_AND_MITIGATION_ENABLED 1u +#define OBSS_HW_CFG_STATS_ONLY_ENABLED 2u +#define OBSS_HW_CFG_INVALID 255u + +typedef struct wlc_obss_hw_cfg_v2 { + uint16 sub_cmd_flags; /* Flag bits to Identify configuring sub command */ + uint8 is_enable; /* Feature and mode enable flag */ + uint8 sw_cache_interval; /* SW cache interval to cache OBSS stats in sec */ + uint16 phy_sensing_duration; /* PHY OBSS sensing duration in msec */ +} wlc_obss_hw_cfg_v2_t; + +typedef struct wlc_obss_hw_stats_v2 { + uint16 avg_obss_stats[WL_OBSS_ANT_MAX][ACPHY_OBSS_SUBBAND_CNT][ACPHY_OBSS_STATS_BIN_CNT]; + uint16 obss_det_stats[ACPHY_OBSS_SUBBAND_CNT]; + uint16 stats_cnt; /* Stats count */ + uint8 obss_mit_status; /* OBSS mitigation status */ + uint8 mit_bw; /* Mitigation BW that got selected */ + uint32 lifetime_expiry_cnt; /* count of lifetime expired pkts */ + uint32 medium_access_delay; /* sum of medium access delay */ + uint32 pkt_cnt; /* number of pkts for which Tx status stats are logged */ + uint32 rts_pkts_cnt; /* number of packets sent with RTS */ +} wlc_obss_hw_stats_v2_t; + +typedef struct wlc_obss_hw_test_v2 { + uint16 sub_cmd_flags; /* Flag bits to Identify configuring sub command */ + uint8 test_mode; /* To stop/start respective test mode */ + uint8 mitigation_mode; /* mitigation enabling/disabling options */ +} wlc_obss_hw_test_v2_t; + +typedef wlc_obss_hw_test_v2_t wlc_obss_hw_test_v3_t; +typedef wlc_obss_hw_cfg_v2_t wlc_obss_hw_cfg_v3_t; + +/* obss_pwrest is normally a negative value in dBm, + * when it is not negative, the following enum is + * used to indicate exceptional cases as listed below. + * The below structures and onwards will follow this format + * - wlc_obss_hw_stats_v3_t.obss_pwrest[][] + * - phy_ecounter_v5.phy_ecounter_log_core_v4_t.obss_pwrest[] + * - phy_periodic_obss_stats_v4.obss_pwrest[] + */ +typedef enum obss_pwr_dbm_status { + OBSS_PWRSTS_UNDEFINED = 0, /* Undefined */ + OBSS_PWRSTS_PRIM_SB = 1, /* Primary sub-band */ + OBSS_PWRSTS_SATURATED = 2, /* Measurement Saturated */ + OBSS_PWRSTS_NO_VALID_CNT = 3, /* No valid measure count */ + OBSS_PWRSTS_MAX +} obss_pwr_dbm_status_t; + +typedef struct wlc_obss_hw_stats_v3 { + uint16 avg_obss_stats[WL_OBSS_ANT_MAX][ACPHY_OBSS_SUBBAND_CNT][ACPHY_OBSS_STATS_BIN_CNT]; + /* average bin counts collected per bin across + * multiple sensing durations + */ + uint16 obss_det_stats[ACPHY_OBSS_SUBBAND_CNT]; + /* OBSS detection count for each sub-band */ + uint16 stats_cnt; /* stats count */ + uint8 obss_mit_status; /* OBSS mitigation status */ + uint8 mit_bw; /* mitigation BW that got selected */ + uint32 lifetime_expiry_cnt; /* count of lifetime expired pkts */ + uint32 medium_access_delay; /* sum of medium access delay */ + uint32 pkt_cnt; /* number of pkts for which Tx status stats are + * logged + */ + uint32 rts_pkts_cnt; /* number of packets sent with RTS */ + int8 obss_pwrest[WL_OBSS_ANT_MAX][ACPHY_OBSS_SUBBAND_CNT]; + /* estimated OBSS signal power in dBm, + * please refer to obss_pwr_dbm_status_t + * for exceptional cases + */ + int8 soi_rssi; /* rssi of SOI */ + uint8 deferred_enable_config; /* Feature enable config if deferred */ + uint8 obss_last_rec_bw; /* Last stats block recommended BW */ + uint8 current_enable_config; /* Current active feature enable config */ +} wlc_obss_hw_stats_v3_t; + #define STA_PM_SC_OFLD_CFG_VER_V1 1u #define STA_PM_SC_OFLD_ENAB_FLAG (1u << 0u) @@ -25381,7 +29098,12 @@ typedef enum wlc_sta_pm_sc_ofld_fail_reason { STA_PM_SC_OFLD_FAIL_AP_ENAB = (1u << 13u), /* AP cfg is enabled */ STA_PM_SC_OFLD_FAIL_SLOTTED_BSS_ENAB = (1u << 14u), /* Slotted BSS is enabled */ STA_PM_SC_OFLD_FAIL_BTMC_ACTIVE = (1u << 15u), /* BT Main Core is active */ - STA_PM_SC_OFLD_FAIL_UNSUP_BASIC_RATE = (1u << 16u) /* SC Unsupported basic rate */ + STA_PM_SC_OFLD_FAIL_UNSUP_BASIC_RATE = (1u << 16u), /* SC Unsupported basic rate */ + STA_PM_SC_OFLD_FAIL_UNSUP_CHANSPEC = (1u << 17u), /* SC Unsupported chanspec */ + STA_PM_SC_OFLD_FAIL_MLO_LINK_ACTIVE_IN_SC = (1u << 18u), /* One of the MLO link is + * already offloaded to sc + */ + STA_PM_SC_OFLD_FAIL_UATBTT = (1u << 19u) /* UATBTT active */ } wlc_sta_pm_sc_ofld_fail_reason_t; typedef enum wlc_sta_pm_sc_ofld_exit_reason { @@ -25406,6 +29128,7 @@ typedef enum wlc_sta_pm_sc_ofld_exit_reason { STA_PM_SC_OFLD_EXIT_TWT = 19u, /* Exit due to TWT active */ STA_PM_SC_OFLD_EXIT_SLOTTED_BSS = 20u, /* Exit due to Slotted BSS active */ STA_PM_SC_OFLD_EXIT_AP_BSS = 21u, /* Exit due to AP BSS active */ + STA_PM_SC_OFLD_EXIT_MLO = 22u, /* Exit due to high priority MLO link */ STA_PM_SC_OFLD_EXIT_MAX = 255u /* Max, uint8 for now */ } wlc_sta_pm_sc_ofld_exit_reason_t; @@ -25436,14 +29159,23 @@ typedef struct wlc_sta_pm_sc_status_v1 { #define MAX_ATID_CORES 5u #define SDTC_ID_ALL 0xFFu -/* SDTC IOV ID's */ +/* SDTC IOV ID's. SW assigned IDs to each of the SDTC units. */ enum wl_sdtc_iov_id { - SDTC_ID_INVALID = 0x0, - SDTC_ID_CB = 0x1, - SDTC_ID_PCIE = 0x2, - SDTC_ID_SYSMEM = 0x3, - SDTC_ID_AUXMAC = 0x4, - SDTC_ID_MAINMAC = 0x5 + SDTC_ID_INVALID = 0x0, /* Invalid SDTC id. This is used for ETM internally */ + SDTC_ID_CB = 0x1, /* Common Bridge AXL SDTC */ + SDTC_ID_PCIE = 0x2, /* AXL SDTC between common bridge and PCIE core. */ + SDTC_ID_SYSMEM = 0x3, /* AXL between WLAN backplane and CA7 subsystem */ + SDTC_ID_AUXMAC = 0x4, /* HWL inside AUX MAC */ + SDTC_ID_MAINMAC = 0x5, /* HWL inside MAIN MAC */ + SDTC_ID_LP = 0x6, /* HWL connected to Async APB bridge */ + SDTC_ID_AUXMAC_AXL = 0x7, /* AXL between booker interconnect and AUX MAC */ + SDTC_ID_MAINMAC_AXL = 0x8, /* AXL between booker interconnect and MAIN MAC */ + SDTC_ID_SCANMAC_HWL = 0x9, /* HWL inside SCAN MAC */ + SDTC_ID_SCANMAC_AXL = 0xa, /* AXL between booker interconnect and SCAN MAC */ + SDTC_ID_SAQM_AXL = 0xb, /* AXL between booker interconnect and SAQM */ + SDTC_ID_SAQM_HWL = 0xc, /* HWL inside SAQM */ + SDTC_ID_WL_AXL = 0xd, /* AXL for WL_SDTC */ + SDTC_ID_LAST = 0xe }; /* SDTC Iovars */ @@ -25469,9 +29201,9 @@ typedef struct sdtc_config { uint16 len; uint8 sdtc_id; /* 0xFF indicates, all core id's enable */ - uint8 pad; /* 32 bit alignment */ + uint8 PAD; /* 32 bit alignment */ uint16 num_of_registers; /* if no of reg is "0",it will use default SDTC config */ - sdtc_regs_t regs[1]; /* Array of register list */ + sdtc_regs_t regs[BCM_FLEX_ARRAY]; /* Array of register list */ } sdtc_config_t; typedef struct sdtc_enab_atid_list { @@ -25493,7 +29225,7 @@ typedef struct etb_info { uint16 len; uint32 read_write_p; /* read write pointer address */ uint8 etb_full; /* status bit */ - uint8 pad[3]; /* 32bit alignment */ + uint8 PAD[3]; /* 32bit alignment */ uint32 addr; /* H/W Address */ uint32 read_bytes; /* Size of ETB(Embedded Trace Buffer) Memory */ } etb_info_t; @@ -25547,9 +29279,13 @@ typedef struct wlc_roam_min_delta { #define WLC_BCN_MUTE_MITI_CFG_CMD_ENABLE (1u << 0u) #define WLC_BCN_MUTE_MITI_CFG_CMD_PM0_PERIOD (1u << 1u) #define WLC_BCN_MUTE_MITI_CFG_CMD_MAX_MITI_TIMEOUT (1u << 2u) -#define WLC_BCN_MUTE_MITI_CFG_CMD_MASK (WLC_BCN_MUTE_MITI_CFG_CMD_ENABLE |\ - WLC_BCN_MUTE_MITI_CFG_CMD_PM0_PERIOD |\ - WLC_BCN_MUTE_MITI_CFG_CMD_MAX_MITI_TIMEOUT) +#define WLC_BCN_MUTE_MITI_CFG_CMD_LOW_RSSI_THRESH (1u << 3u) + +/* Define the config command mask */ +#define WLC_BCN_MUTE_MITI_CFG_CMD_MASK (WLC_BCN_MUTE_MITI_CFG_CMD_ENABLE |\ + WLC_BCN_MUTE_MITI_CFG_CMD_PM0_PERIOD |\ + WLC_BCN_MUTE_MITI_CFG_CMD_MAX_MITI_TIMEOUT |\ + WLC_BCN_MUTE_MITI_CFG_CMD_LOW_RSSI_THRESH) /* Configurable PM0 period range in sec */ #define WLC_BCN_MUTE_MITI_CFG_PM0_PERIOD_MIN (0u) /* Minimum PM0 periodicity */ @@ -25561,7 +29297,13 @@ typedef struct wlc_roam_min_delta { #define WLC_BCN_MUTE_MITI_CFG_TIMEOUT_DEFAULT (60u) /* Default Timeout in sec */ #define WLC_BCN_MUTE_MITI_CFG_TIMEOUT_MAX (120u) /* Maximum Timeout in sec */ +/* Configurable RSSI Threshold ranges */ +#define WLC_BCN_MUTE_MITI_CFG_RSSI_THRESH_MAX (0) /* Maximum RSSI threshold */ +#define WLC_BCN_MUTE_MITI_CFG_RSSI_THRESH_DEFAULT (WLC_BCN_MUTE_MITI_CFG_RSSI_THRESH_MAX) +#define WLC_BCN_MUTE_MITI_CFG_RSSI_THRESH_MIN (-127) /* Min RSSI threshold */ + #define WLC_BCN_MUTE_MITI_CMD_VER_1 1u /* Version number for wlc_bcn_mute_miti_cfg_v1 struct */ +#define WLC_BCN_MUTE_MITI_CMD_VER_2 2u /* Version number for wlc_bcn_mute_miti_cfg_v2 struct */ typedef struct wlc_bcn_mute_miti_cfg_v1 { uint16 version; /* Structure version */ uint16 length; /* Length of whole struct */ @@ -25575,6 +29317,21 @@ typedef struct wlc_bcn_mute_miti_cfg_v1 { */ } wlc_bcn_mute_miti_cfg_v1_t; +typedef struct wlc_bcn_mute_miti_cfg_v2 { + uint16 version; /* Structure version */ + uint16 length; /* Length of whole struct */ + uint32 cmd_flags; /* Flag bits to Identify configuring command */ + uint8 is_enabled; /* Feature is enabled or not */ + uint8 pm0_periodicity; /* Interval between consecutive PM0 during mitigation + * period (in sec) + */ + uint16 max_miti_timeout; /* Maximum mitigation timeout in sec to send + * Mitigation Timeout event. + */ + int8 low_rssi_threshold; /* Low RSSI threshold value */ + uint8 PAD[3]; /* Pad bytes */ +} wlc_bcn_mute_miti_cfg_v2_t; + #define WLC_BCN_TBTT_CMD_VER_1 (1u) /* Ver num for wlc_bcn_tbtt_cfg struct */ /* Configurable mitigation Timeout range */ #define WLC_BCN_TBTT_CFG_EVENT_PERIOD (3u) /* Send event after this value of drift */ @@ -25610,15 +29367,15 @@ typedef struct wlc_bcn_tbtt_cfg_v1 { /* SC scan retry config params */ #define SC_SCAN_RETRY_CFG_VERSION_1 1u #define SC_SCAN_RETRY_CFG_VERSION_2 2u +#define SC_SCAN_RETRY_CFG_VERSION_3 3u /* Bits indicating which are the valid params in the set command. */ #define SC_SCAN_RETRY_CFG_PARAMS_THRESHOLD (1u << 0u) #define SC_SCAN_RETRY_CFG_PARAMS_MODE (1u << 1u) #define SC_SCAN_RETRY_CFG_PARAMS_BTMCRX_WEIGHT (1u << 2u) - -#ifndef SC_SCAN_RETRY_CFG_HAS_ALIAS -#define SC_SCAN_RETRY_CFG_VERSION SC_SCAN_RETRY_CFG_VERSION_1 -#endif +#define SC_SCAN_RETRY_CFG_PARAMS_BCN_DUR_2G (1u << 3u) +#define SC_SCAN_RETRY_CFG_PARAMS_BCN_DUR_5G (1u << 4u) +#define SC_SCAN_RETRY_CFG_PARAMS_BCN_DUR_6G (1u << 5u) /* Input structure for sc_scan_retry_cfg IOVAR */ typedef struct sc_scan_retry_cfg_params_v1 { @@ -25648,6 +29405,35 @@ typedef struct sc_scan_retry_cfg_params_v2 { uint8 PAD; /* 32bit alignment */ } sc_scan_retry_cfg_params_v2_t; +#define SC_SCAN_RETRY_CFG_BCN_DUR_MAX 50u /* max dur is 5ms(50 * 0.1ms) */ +#define SC_SCAN_RETRY_CFG_BCN_DUR_MIN 1u /* max dur is 0.1ms(1 * 0.1ms) */ +#define SC_SCAN_RETRY_CFG_BANDS_MAX 3u /* max bands supported(2G, 5G and 6G) */ + +/* Input structure for sc_scan_retry_cfg v3 IOVAR */ +typedef struct sc_scan_retry_cfg_params_v3 { + uint16 version; /* config version. */ + uint16 len; /* Length of this struct. */ + uint32 set_flag; /* Flag bits to Identify valid param type to + * be set. + */ + uint8 threshold; /* Amount of Tx-Blanking + the weighted + * BTMC Rx overlap. + * in percentage considered as failed scan. + */ + uint8 scan_mode; /* Scan mode in which scan need to be + * re-scheduled.. + */ + uint8 btmc_rx_overlap_weightage; /* weightage for btmc_rx_overlap + * duration in % + */ + uint8 bcn_dur[SC_SCAN_RETRY_CFG_BANDS_MAX]; /* Beacon reception time in 0.1ms + * Byte 0:2G Beacon Duration + * Byte 1: 5G Beacon Duration + * Byte 2: 6G Beacon Duration + */ + uint8 PAD[2]; /* pad for 32 bit alignment */ +} sc_scan_retry_cfg_params_v3_t; + /* host queries RNG version from 'wl cap' iovar */ #define BCM_RNG_VERSION_1 1u /* for initial "reseed" version */ /* Supported entropy size, bytes */ @@ -25669,74 +29455,67 @@ typedef struct bcm_rng_reseed { typedef struct wl_rng_iovar { uint16 version; /* Version of this structure */ uint16 subcmd_id; /* RNG subcmd ID */ - uint16 pad; /* padding for 32-bit struct alignment */ + uint16 PAD; /* padding for 32-bit struct alignment */ uint16 length; /* Length of data following this length field */ union { bcm_rng_reseed_t reseed; /* RNG reseed data */ } u; } wl_rng_iovar_t; -#ifdef RC2CX -#define RC2CX_STATUS_VER_1 1 -/* RC2 coex status structures */ -typedef struct wlc_rc2cx_stats_v1 { - uint16 version; /* version info */ - uint8 len; /* status length */ - uint8 mode; /* RC2 coex mode */ - uint16 rc2_req_cnt; /* RC2 req number since last read. */ - uint16 rc2_grant_cnt; /* RC2 grant count since last read. */ - uint32 rc2_dur; /* RC2 duration since last read, us. */ - uint16 rc2_succ_pm_prot_cnt; /* RC2 number of successfully acked PM. */ - uint16 rc2_succ_cts_prot_cnt; /* RC2 number of successfully TXed CTS2A. */ - uint16 rc2_grant_delay_cnt; /* RC2 grant delay counter, delay > 4.5ms. */ - uint16 rc2_crit_phycal_cnt; /* RC2 WLAN/BT critical: PHY cal. counter. */ - uint16 rc2_crit_rate_cnt; /* RC2 WLAN/BT critical: rate recovery counter. */ - uint16 rc2_crit_bcnloss_cnt; /* RC2 WLAN/BT critical: beacon loss counter. */ - uint16 rc2_crit_hpp_cnt; /* RC2 WLAN/BT critical: HPP counter. */ - uint16 rc2_crit_bt_cnt; /* RC2 WLAN/BT critical: BT counter. */ - uint16 rc2_crit_slotbss_cnt; /* RC2 WLAN/BT critical: AWDL/NAN counter. */ - uint16 rsvd; - uint32 rc2_crit_cnt; /* RC2 WLAN/BT critical counter, aggregate. */ -} wlc_rc2cx_stats_v1_t; +#define WL_BTC_VER_V1 1u +#define BTCX_ROAM_PROF_VERSION_V1 1u +#define BTCX_ROAM_BW_VERSION_V1 1u -/* Definitions for RC2 coex iovar */ -#define WL_RC2CX_VERSION 1 +/* BT coex IOV sub command IDs */ +typedef enum btc_cmd_id { + WL_BTC_CMD_VER = 0, /* BTCX version sub command */ + WL_BTC_CMD_ROAM_PROFILE = 1, + WL_BTC_CMD_ROAM_BW = 2, + WL_BTC_CMD_ROAM_ON = 3, + WL_BTC_CMD_ROAM_BAND_FILTER = 4, + WL_BTC_CMD_ROAM_DELTA = 5, + WL_BTC_CMD_ROAM_RSSI = 6, + WL_BTC_CMD_ROAM_MODE = 7, + WL_BTC_CMD_ACK_CNTS = 8, + WL_BTC_CMD_RR_ENABLE = 9, + WL_BTC_CMD_HP_OVR_LESCAN = 10 +} btc_cmd_id_t; -/* RC2 coex IOV sub command IDs */ -typedef enum rc2cx_cmd_id { - WL_RC2CX_CMD_VER = 0, /* RC2CX version sub command */ - WL_RC2CX_CMD_MODE = 1, /* RC2CX Mode sub command */ - WL_RC2CX_CMD_PM_PROT = 2, /* RC2CX PM Protection sub command */ - WL_RC2CX_CMD_PER_CTS = 3 /* RC2CX Periodic CTS sub command */ -} rc2cx_cmd_id_t; +typedef struct btcx_roam_bandwidth { + uint16 version; /* version info */ + uint8 len; /* btc roam profile length */ + uint8 pad; + uint8 low_offset; + uint8 mid_offset; + uint8 high_offset; + uint8 pad1; +} btcx_roam_bw_v1_t; -/* first byte of bcm_iov_batch_subcmd.data for the WL_RC2CX_CMD_MODE command */ -#define RC2CX_MODE_TDD 0x01u -#define RC2CX_MODE_DISABLED 0x00u +typedef struct btcx_roam_profile { + uint16 version; /* version info */ + uint8 len; /* btc roam profile length */ + uint8 pad; + uint8 prof_id; + uint8 initialized; + uint16 offset; + uint32 task_bm; +} btcx_roam_profile_v1_t; -/* first byte of bcm_iov_batch_subcmd.data for the WL_RC2CX_CMD_PM_PROT command */ -#define RC2CX_PM_PROT_ENABLED 0x01u -#define RC2CX_PM_PROT_DISABLED 0x00u +/* WLAN Rate Recovery Configuration */ +/* Version 1 is the IOVAR itself. */ +#define BTC_RR_CONFIG_VER_1 1 -/* first byte of bcm_iov_batch_subcmd.data for the WL_RC2CX_CMD_PER_CTS command */ -#define RC2CX_PER_CTS_ENABLED 0x01u -#define RC2CX_PER_CTS_DISABLED 0x00u - -#define RC2CX_PER_CTS_DENY_BT 0x02u -#define RC2CX_PER_CTS_GRANT_BT 0x01u - -/* payload for the WL_RC2CX_CMD_PER_CTS command */ -typedef struct rc2cx_per_cts_config { - uint8 enable_flag; /* 0: feature disabled; - * 1: grant BT when granting RC2; - * 2: deny BT when granting RC2 - */ - uint8 duration_val; /* Must be valid with enable command */ - uint8 interval_val; /* Must be valid with enable command */ +#define BTC_RR_CONFIG_VER_2 2 +typedef struct wlc_btc_rr_config_v2 { + uint8 version; /* version */ + uint8 len; /* length */ + bool enable; /* enable/disable */ + uint8 nss; /* NSS and MCS from the host define the cutoff rate. */ + uint8 mcs; + uint8 cutoff_mcs_nss1_11n; /* Cutoff MCS when NSS=1. */ + uint8 cutoff_mcs_nss2_11n; /* Cutoff MCS when NSS=2. */ uint8 pad; -} rc2cx_per_cts_config_t; - -#endif /* RC2CX */ +} wlc_btc_rr_config_v2_t; enum phy_rxgcrs_ed_enhncd_cmd_id { PHY_RXGCRS_ED_ENHNCD_CMD_EN = 1u, @@ -25762,6 +29541,10 @@ typedef enum sae_cmd_id { * Data: * uint32 */ + WL_SAE_CMD_STATUS = 3, /* RSNXE Caps + * Data: + * uint32 + */ } sae_cmd_id_t; /* Frameburst COT IOVAR data */ @@ -25771,7 +29554,7 @@ typedef struct frameburst_cot { uint16 version; /* version of frameburst_cot_t structure */ uint16 length; chanspec_t chspec; - uint16 pad; /* padding */ + uint16 PAD; /* padding */ uint16 fbcot[WL_FRAMEBURST_MAX_AC]; /* per AC (BK, BE, VI, and VO) in us units */ } frameburst_cot_t; @@ -25781,29 +29564,38 @@ typedef enum { BCM_TRACE_EVENT_ENAB = 3 } bcm_trace_sub_cmds_t; -/* Trace events - * Max trace event allowed = 255 - */ -enum { - BCM_TRACE_E_INVALID = 0, - BCM_TRACE_E_WBUS = 1, - BCM_TRACE_E_MSCH = 2, - BCM_TRACE_E_SC = 3, - BCM_TRACE_E_SCAN = 4, - BCM_TRACE_E_LAST -}; - #define BCM_TRACE_VERSION_1 1u +#define BCM_TRACE_VERSION_2 2u typedef struct bcm_trace_event_enab_v1 { uint8 version; uint8 event; uint8 enab; - uint8 pad[1]; + uint8 PAD[1]; } bcm_trace_event_enab_v1_t; +/* BCMTRACE even log type bit definitions */ +#define BCM_TRACE_TYPE_NORMAL 0x1 +#define BCM_TRACE_TYPE_CHATTY 0x2 + +#define BCM_TRACE_TYPE_MASK 0x3 + +/* Enum value for BCMTRACE array index */ +enum bcmtrace_array_val { + BCM_TRACE_NORMAL = 0, + BCM_TRACE_CHATTY, + BCM_TRACE_LAST +}; + +typedef struct bcm_trace_event_enab_v2 { + uint8 version; + uint8 event; /* event operated */ + uint8 type; /* bit map of event type */ + uint8 val; /* values corresponding to event type */ +} bcm_trace_event_enab_v2_t; + /* rate_info command version */ -#define WL_RATE_INFO_VERSION 1 +#define WL_RATE_INFO_VERSION_1 1 typedef struct wl_rate_info { uint16 version; /**< structure version */ uint16 length; /**< length of this struct */ @@ -25830,13 +29622,6 @@ typedef enum { LATENCY_CRT_DATA_MODE_LAST } latency_crt_mode_t; -typedef struct wl_ext_auth_evt { - wlc_ssid_t ssid; - struct ether_addr bssid; - unsigned int key_mgmt_suite; - int status; -} wl_ext_auth_evt_t; - #define WL_AUTH_START_EVT_V1 1u typedef struct wl_auth_start_evt { uint16 version; @@ -25847,4 +29632,1565 @@ typedef struct wl_auth_start_evt { uint32 key_mgmt_suite; uint8 opt_tlvs[]; } wl_auth_start_evt_t; + +/* Additional header pushed to the logged mgmt frame in aml(assoc mgmt frame logger) */ +typedef struct wl_aml_header_v1 { + uint16 version; /* Header version, now 1 */ + uint16 length; /* frame length excluding this header */ + uint16 flags; /* flag to indicate tx/rx, acked/noack and others */ + uint8 PAD[2]; /* pad bytes for align */ +} wl_aml_header_v1_t; + +/* Version for aml header */ +#define WL_AML_HEADER_VERSION 1u + +/* Flags for aml header */ +#define WL_AML_F_DIRECTION 0x0001 /* This flag indicates this is Tx mgmt, otherwise Rx */ +#define WL_AML_F_ACKED 0x0002 /* This flag indicates the frame is acked */ +#define WL_AML_F_MGMT 0x0004 /* This flag indicates the frame is 80211 mgmt */ +#define SDIO_HLEN 12 /* Sdio Header Length */ + +/* Version for IOVAR 'aml' */ +#define WL_AML_IOV_MAJOR_VER_1 1u +#define WL_AML_IOV_MINOR_VER_0 0u +#define WL_AML_IOV_MAJOR_VER_SHIFT 8u +#define WL_AML_IOV_VERSION_1_0 \ + ((WL_AML_IOV_MAJOR_VER_1 << WL_AML_IOV_MAJOR_VER_SHIFT) | WL_AML_IOV_MINOR_VER_0) + +/* Common header for IOVAR 'aml' */ +typedef struct wl_aml_iov_cmnhdr { + uint16 ver; /* IOVAR cmd structure version */ + uint16 len; /* IOVAR cmd structure total len (cmnhdr + following subcmd) */ + uint16 subcmd; /* IOVAR subcmd */ + uint8 PAD[2]; +} wl_aml_iov_cmnhdr_t; + +/* IOVAR 'aml' data structure, cmn header is followed by subcmd structure */ +typedef struct wl_aml_iovar { + wl_aml_iov_cmnhdr_t hdr; + uint32 data[0]; +} wl_aml_iovar_t; + +/* IOVAR 'aml' subcmd list */ +enum wl_aml_subcmd_ids { + WL_AML_SUBCMD_ENABLE = 1, /* Enable/disable aml feature */ + WL_AML_SUBCMD_LAST +}; + +/* IOVAR 'aml' subcmd structure for uint32 data + * Subcmd 'enable' uses this structure + */ +typedef struct wl_aml_iov_uint_data { + uint32 val; +} wl_aml_iov_uint_data_t; + +/* IOVAR 'aml enable' subcmd bit numbers + * wl_aml_iov_uint_data.val is popluated with following bits + */ +enum wl_aml_cmd_enable_bitnums { + WL_AML_ASSOC_ENABLE = 0, /* Logging for association */ + WL_AML_ROAM_ENABLE = 1, /* Logging for roaming */ + WL_AML_ENABLE_LAST +}; + +/* Snapshot of various timestamps */ +#define WL_TIMESTAMP_VERSION_1 1 +typedef struct wl_timestamps_v1 { + uint16 version; /**< structure version */ + uint16 length; /**< length of this struct */ + uint32 PAD; + uint64 cpu_cycles; /**< CPU Cycle count */ + uint64 ptm; /**< Local PTM master timestamp in nano seconds */ + uint64 pmu_timer; /**< Legacy PMU timer in micsoseconds */ + uint32 tsf_main; /**< Main slice TSF */ + uint32 tsf_aux; /**< Aux slice TSF */ + uint32 tsf_scan; /**< Scan core TSF */ + uint32 PAD; +} wl_timestamps_v1_t; + +#define WL_TIMESTAMP_VERSION_2 2 +typedef struct wl_timestamps_v2 { + uint16 version; /**< structure version */ + uint16 length; /**< length of this struct */ + uint32 PAD; + uint64 cpu_cycles; /**< cpu cycle count */ + uint64 pgt; /**< local pgt master timestamp in nano seconds */ + uint64 pmu_timer; /**< legacy pmu timer in microseconds */ + uint32 tsf_main; /**< main slice tsf */ + uint32 tsf_aux; /**< aux slice tsf */ + uint32 tsf_scan; /**< scan core tsf */ + uint32 PAD; + uint64 sysuptime_ns; /**< sysup time in nanoseconds */ +} wl_timestamps_v2_t; + +#define WL_LOW_LATENCY_CONFIG_V1 1u +#define WL_LOW_LATENCY_V1 1u + +/* low latency config */ +typedef struct wl_low_latency_config_v1 { + uint16 version; + uint16 length; + uint8 periodicity; /* periodicity in sec of low latency PNO scan */ + uint8 PAD[3]; +} wl_low_latency_config_v1_t; + +/* Interface for low latency */ +typedef struct wl_low_latency_v1 { + uint16 version; + uint16 length; + uint8 mode; /* latency mode */ + uint8 PAD[3]; + wl_low_latency_config_v1_t config; /* config for latency mode */ +} wl_low_latency_v1_t; + +#define WL_PASN_VERSION_1 0x0001u + +/* PASN subcommands ID. */ +enum { + WL_PASN_CMD_NONE = 0, + /* get PASN IOVAR version. */ + WL_PASN_CMD_GET_VERSION = 1, + /* set, enable PASN. */ + WL_PASN_CMD_ENABLE = 2, + /* set, disable PASN. */ + WL_PASN_CMD_DISABLE = 3, + /* get/set, PASN finite cyclic group id. */ + WL_PASN_CMD_CONFIG_GROUP = 4, + /* get/set, PASN authentication policy. */ + WL_PASN_CMD_CONFIG_POLICY = 5, + /* get/set, The key lifetime in minutes. */ + WL_PASN_CMD_CONFIG_KEY_LIFETIME_MIN = 6, + /* get/set, peer mac address of PASN session. */ + WL_PASN_CMD_CONFIG_PEER_ADDR = 7, + /* get/set, local mac address of PASN session. */ + WL_PASN_CMD_CONFIG_LOCAL_ADDR = 8, + /* get/set, chanspec of PASN session. */ + WL_PASN_CMD_CONFIG_CHANSPEC = 9, + /* set, start PASN session. */ + WL_PASN_CMD_START = 10, + /* set, stop PASN session. */ + WL_PASN_CMD_STOP = 11, + /* set, delete PASN session. */ + WL_PASN_CMD_DELETE = 12, + /* get info for PASN session with given id - wl_pasn_session_info_t. */ + WL_PASN_CMD_GET_INFO = 13, + /* Note: for debug purpose or future event - wl_pasn_key_info_t. */ + WL_PASN_CMD_GET_KEY_INFO = 14, + /* get/set. uint32. PASN event mask. */ + WL_PASN_CMD_EVENT_MASK = 15, + /* get. List id of active sessions. */ + WL_PASN_CMD_LIST_SESSIONS = 16, + /* get/set, flags of PASN session. */ + WL_PASN_CMD_CONFIG_FLAGS = 17, + /* get/set. uint32. PASN key idle time. */ + WL_PASN_CMD_KEY_IDLE_TIME = 18, + /* get/set. for testing purpose. */ + WL_PASN_CMD_TEST = 0xfffe +}; +typedef uint16 wl_pasn_cmd_t; + +enum { + /* No test action */ + WL_PASN_CMD_TEST_NONE = 0, + /* DUT to send auth frame with invalid MIC */ + WL_PASN_CMD_TEST_INVALID_MIC = 1, + /* DUT to send deauth frame to peer */ + WL_PASN_CMD_TEST_DEAUTH = 2 +}; +typedef uint8 wl_pasn_cmd_test_id_t; + +typedef uint16 wl_pasn_session_id_t; +/* Session id ranges are allocated to various users of PASN - + * including internal use (e.g. automatically allocated IDs on an AP). + * Other ranges can be defined in the future. + */ +enum { + PASN_SID_TYPE_HOST = 0, + PASN_SID_TYPE_FTM = 1, + PASN_SID_TYPE_INTERNAL = 2 +}; + +#define PASN_SID_GLOBAL 0u + +#define PASN_SID_HOST_START 1u +#define PASN_SID_HOST_END 1023u + +#define PASN_SID_FTM_START 1024u +#define PASN_SID_FTM_END 2047u + +#define PASN_SID_NAN_START 2048u +#define PASN_SID_NAN_END 3071u + +#define PASN_SID_INTERNAL_START 3072u +#define PASN_SID_INTERNAL_END 32767u + +typedef struct wl_pasn_iov { + uint16 version; /* structure version will be incremented + * when header is changed. + */ + uint16 len; /* includes the id field and following data. */ + wl_pasn_cmd_t cmd; /* sub-command id. */ + wl_pasn_session_id_t id; /* session id is the input for session specific commands + * and a reserved value for global commands. + */ + uint8 data[]; /* variable */ +} wl_pasn_iov_t; + +/* The policy used in the PASN exchange. */ +/* + * ALLOW_NO_PMKSA may be set independent of USE_PMKSA or SETUP_PMKSA. + * SETUP_PMKSA implies USE_PMKSA i.e. attempt to use existing PMKSA before + * attempting setup. Ignore USE_PMKSA when SETUP_PMKSA is set. + * if USE_PMKSA or SETUP_PMKSA are not set, attempt w/o PMKSA - OWE like + * USE_PMKSA does not imply SETUP_PMKSA - i.e. we wont attempt setting up PASN via tunneling. + */ +enum { + WL_PASN_POLICY_NONE = 0, /* Not used. */ + WL_PASN_POLICY_ALLOW_NO_PMKSA = 1, /* allow no pmksa, fixed pmk */ + WL_PASN_POLICY_USE_PMKSA = 2, /* use existing pmksa for base akm */ + /* 3 is reserved for bit "OR" of ALLOW_NO_PMKSA and USE_PMKSA. */ + WL_PASN_POLICY_SETUP_PMKSA = 4, /* setup PMKSA using base akm */ + WL_PASN_POLICY_MAX = WL_PASN_POLICY_SETUP_PMKSA +}; + +enum { + /* Initial state of PASN state machine. + * Initialization is allowed if PASN is enabled via configuration. + */ + WL_PASN_STATE_IDLE = 0, + /* For STA, Initiate an instance requested by user, ex. FTM. + * For AP, Receive PASN authentication frame with sequence 1. + */ + WL_PASN_STATE_INIT = 1, + /* STA only. Auth frame is constructed and ready for + * transmission. STA request for channel scheduling. + * It is not necessary to AP because AP will not be off channel. + */ + WL_PASN_STATE_SCHED_WAIT = 2, + /* STA only. PASN is waiting for desired security + * methods(FILS/SAE/FBT) t obuild tunneled protocol data for authentication + * frame with sequence 1. + */ + WL_PASN_STATE_DATA_WAIT_1 = 3, + /* STA only. PASN authentication frame with sequence + * 1 is constructed and pushed to FIFO, waiting for ACK. + */ + WL_PASN_STATE_WAIT_ACK_1 = 4, + /* STA only. STA is waiting for authentication frame with sequence 2. */ + WL_PASN_STATE_WAIT_AUTH_2 = 5, + /* STA: PASN is waiting for desired security + * methods(FILS/SAE/FBT) to build tunneled protocol data for authentication + * frame with sequence 3. + * AP: PASN is waiting for desired security module to validate the tunneled + * protocol data in received authentication frame with sequence 3. + */ + WL_PASN_STATE_DATA_WAIT_3 = 6, + /* STA only. PASN authentication frame with sequence 3 + * is constructed and pushed to FIFO, waiting for ACK. + */ + WL_PASN_STATE_WAIT_ACK_3 = 7, + /* STA only. The received PASN authentication frame + * with sequence 2 has status code as REFUSED_TEMPORARILY, + * and the comeback info field in PASN parameters element indicates + * the time for STA to retry the authentication later. + */ + WL_PASN_STATE_COME_BACK = 8, + /* AP only. PASN is waiting for desired security + * methods(FILS/SAE/FBT) to build tunneled protocol data for + * authentication frame with sequence 2. + */ + WL_PASN_STATE_DATA_WAIT_2 = 9, + /* AP only. PASN authentication frame with + * sequence 2 is constructed and pushed to FIFO, waiting for ACK. + */ + WL_PASN_STATE_WAIT_ACK_2 = 10, + /* AP only. AP is waiting for authentication frame with sequence 3. */ + WL_PASN_STATE_WAIT_AUTH_3 = 11, + /* PASN exchange is done. */ + WL_PASN_STATE_DONE = 12 +}; + +typedef uint8 wl_pasn_session_state_t; +typedef int32 wl_pasn_status_t; + +/* Global and bsscfg flags */ +enum { + /* PASN is enabled on bsscfg */ + WL_PASN_FLAG_BSSCFG_ENABLED = 0x0001u +}; +typedef uint16 wl_pasn_flags_t; + +enum { + /* PASN exchange will use PMKSA to derive PTKSA */ + WL_PASN_SESSION_FLAG_CACHED_PMK = 0x0001u, + /* PASN exchange will setup PMKSA by tunneling protocol data */ + WL_PASN_SESSION_FLAG_TUNNELED_AKM = 0x0002u, + /* PASN session will be deleted if error occurs */ + WL_PASN_SESSION_FLAG_DELETE_ON_ERR = 0x0004u, + /* PASN session will issue scan with randmac */ + WL_PASN_SESSION_FLAG_RANDMAC = 0x0008u +}; +typedef uint16 wl_pasn_session_flags_t; + +/* PASN session state information. */ +typedef struct wl_pasn_session_info { + wl_pasn_session_id_t id; /* The id of pasn auth exchange. */ + wl_pasn_session_state_t state; /* The state of pasn auth exchange. */ + uint8 PAD[1]; + wl_pasn_status_t status; /* The status code of pasn auth exchange. bcmerror.h */ + struct ether_addr local_addr; /* The source mac address of pasn auth exchange. */ + struct ether_addr peer_addr; /* The peer mac address of pasn auth exchange. */ + uint8 akm; /* The AKM used in pasn auth exchange. + * see rsn_akm_t in bcmwpa.h + */ + uint8 pairwise_cipher; /* The pairwise cipher used in pasn auth exchange. */ + uint16 comeback_after_ms; /* time in miliseconds after which the non-AP STA is + * requested to retry the PASN authentication. + */ + uint16 cyclic_group_id; /* Finite cyclic group id, IANA id, see bcm_ec.h */ + wl_pasn_session_flags_t flags; /* session flags. */ + uint32 key_lifetime_ms; /* key lifetime negotiated in authentication. */ +} wl_pasn_session_info_t; + +#define WL_PASN_MAX_CC_GROUP 6 + +/* PASN global information. */ +typedef struct wl_pasn_info { + wl_pasn_flags_t flags; /* flags. */ + wl_pasn_policy_t policy; /* authentication policy supported. */ + uint8 auth_num_retries; /* authentication frame retry limit. */ + uint8 num_groups; /* number of cyclic groups. */ + uint8 max_auth_session; /* Maximum number of sessions. */ + uint8 active_auth_session; /* number of active sessions. */ + uint8 PAD[1]; + uint32 key_lifetime_min; /* key lifetime in minutes. */ + uint32 event_mask; + uint16 auth_timeout_ms; /* timeout waiting for auth frame. */ + uint16 group_offset; /* the offset of cyclic_group_id. */ + uint32 key_idle_sec; /* Idle time of PASN keys in seconds. */ + /* uint16 cyclic_group_id[]; + * Finite cyclic group id list, IANA id, see bcm_ec.h. + */ +} wl_pasn_info_t; + +/* Note: for debug/internal purpose or future event. + * PTKSA derived from PASN exchange. + */ +typedef struct wl_pasn_key_info { + wl_pasn_session_id_t id; /* The id of pasn auth exchange. */ + uint16 len; /* The length includes the structure and data. */ + struct ether_addr local; /* The source mac address of pasn auth exchange. */ + struct ether_addr peer; /* The peer mac address of pasn auth exchange. */ + bcm_xlo_t kdk; /* KDK length and data offset. */ + bcm_xlo_t kck; /* KCK length and data offset. */ + bcm_xlo_t tk; /* TK length and data offset. */ + /* data follows */ +} wl_pasn_key_info_t; + +/* WL_PASN_CMD_LIST_SESSIONS */ +typedef struct wl_pasn_active_session_list { + uint16 num_sids; + wl_pasn_session_id_t sids[]; +} wl_pasn_active_session_list_t; + +/* WL_PASN_CMD_CONFIG_GROUP */ +typedef struct wl_pasn_group_id_list { + uint16 num_groups; /* number of cyclic groups. */ + uint16 cyclic_group_id[]; /* Finite cyclic group id list, IANA id, see bcm_ec.h. */ +} wl_pasn_group_id_list_t; + +/* pasn sub-event type. */ +enum { + WL_PASN_EVENT_NONE = 0, /* reserved */ + WL_PASN_EVENT_CREATED = 1, /* create a new session */ + WL_PASN_EVENT_STARTED = 2, /* session is started */ + WL_PASN_EVENT_SCHED_WAIT = 3, /* wait for channel scheduling . */ + WL_PASN_EVENT_DATA_WAIT = 4, /* wait for wrapped data to be ready. */ + WL_PASN_EVENT_ACK_WAIT = 5, /* wait for ACK */ + WL_PASN_EVENT_AUTH_WAIT = 6, /* wait for next authentication frame from peer. */ + WL_PASN_EVENT_COME_BACK = 7, /* wait for certain time to start auth again */ + WL_PASN_EVENT_DESTROYED = 8, /* session is deleted. ie. PTKSA is deleted. */ + WL_PASN_EVENT_DONE = 9, /* session is done. */ + WL_PASN_EVENT_REQUEST = 10 /* Request PASN session setup. */ +}; +typedef uint16 wl_pasn_event_type_t; + +/* pasn event */ +typedef struct wl_pasn_event { + uint16 version; + uint16 len; /* includes the entire structure and following data. */ + wl_pasn_session_id_t sid; /* session id */ + wl_pasn_event_type_t type; /* sub event type */ + wl_pasn_session_state_t state; /* current pasn authentication state. */ + wl_pasn_session_state_t prev_state; /* previous pasn authentication state. */ + uint8 PAD[2]; + uint8 data[]; /* variable */ +} wl_pasn_event_t; + +/* amt command details */ +/* non-batched command version = major|minor w/ major <= 127 */ +#define WL_AMT_IOV_MAJOR_VER_1 1u +#define WL_AMT_IOV_MINOR_VER_2 2u +#define WL_AMT_IOV_MAJOR_VER_SHIFT 8u +#define WL_AMT_IOV_VERSION_1_2 \ + ((WL_AMT_IOV_MAJOR_VER_1 << WL_AMT_IOV_MAJOR_VER_SHIFT) | WL_AMT_IOV_MINOR_VER_2) + +enum wl_amt_cmd_ids { + WL_AMT_CMD_VER = 1u, /* Get AMT API VER */ + WL_AMT_CMD_HW_ENTRY = 2u, /* Get/Set HW AMT only */ + WL_AMT_CMD_HW_DUMP = 4u, /* Dump HW AMT only */ + WL_AMT_CMD_HW_ENTRY_EX = 5u, /* Get/Set HW AMT, AFT and FFT */ + WL_AMT_CMD_HW_DUMP_EX = 7u /* Dump HW AMT, AFT and FFT */ +}; + +enum wl_amt_xtlv_id { + WL_AMT_XTLV_NONE = 0u, /* Not valid AMT tag */ + WL_AMT_XTLV_VER = 1u, /* Version */ + WL_AMT_XTLV_IDX = 2u, /* AMT index */ + WL_AMT_XTLV_AMT = 3u, /* AMT table entry */ + WL_AMT_XTLV_AFT = 4u, /* AFT table entry */ + WL_AMT_XTLV_FFT = 5u, /* FFT table entry */ + WL_AMT_XTLV_AMTINFO_FLAGS = 6u /* M_AMT_INFO SHM flags */ +}; + +/* struct for WL_AMT_XTLV_AMT xtlv */ +typedef struct wlc_amt_entry_info_v1 { + uint16 attr; + struct ether_addr ea; +} wlc_amt_entry_info_v1_t; + +/* struct for WL_AMT_XTLV_AFT xtlv */ +typedef struct wlc_aft_entry_info_v1 { + uint8 ds_bits; + uint8 if_id; + uint16 fft_idx; +} wlc_aft_entry_info_v1_t; + +/* struct for WL_AMT_XTLV_FFT xtlv */ +typedef struct wlc_fft_entry_info_v1 { + uint16 fft_mask_mng; + uint16 fft_mask_ctl; + uint16 fft_mask_data; + uint16 fft_mask_ext; +} wlc_fft_entry_info_v1_t; + +/* struct for WL_AMT_XTLV_AFT xtlv version 2 */ +typedef struct wlc_aft_entry_info_v2 { + uint8 ds_bits; + uint8 fft_idx; + uint16 if_id; +} wlc_aft_entry_info_v2_t; + +/* subcommand ids for phy_tpc */ +#define WL_TPC_CMD_INFO_BUF_SZ 4 + +enum wl_tpc_subcmd_ids { + WL_TPC_SUBCMD_AV = 0u, /* AV */ + WL_TPC_SUBCMD_VMID = 1u, /* VMID */ + WL_TPC_SUBCMD_VER_CHECK = 2u, /* VER CHECK */ + WL_TPC_SUBCMD_PACAL = 3u, /* VER CHECK */ + WL_TPC_SUBCMD_TXPWRINDEX = 4u /* PHY TX BASEINDEX */ +}; + +typedef struct wl_tpc_avvmid_info_v1 { + uint16 version; /* structure version */ + uint16 length; /* structure length */ + uint8 core; /* core number */ + uint8 sub_band_idx; /* sub band index */ + uint8 pa_mode; /* PA mode */ + uint8 is_6g; /* 0: 2G/5G or 1: 6G */ + uint8 avvmid_val; /* AV or Vmid value */ + uint8 PAD[3]; /* explicit padding */ +} wl_tpc_avvmid_info_v1_t; + +typedef struct wl_tpc_cmd_v1 { + uint16 version; /* structure version */ + uint16 length; /* structure length */ + uint16 sub_cmd; /* sub_cmd type */ + uint8 PAD[2]; /* explicit padding */ + wl_tpc_avvmid_info_v1_t avvmid_info; /* avvmid info */ +} wl_tpc_cmd_v1_t; + +typedef struct wl_tpc_cmd_info_v2 { + uint16 version; /* structure version */ + uint16 length; /* structure length */ + uint8 core; /* core number */ + uint8 sub_band_idx; /* sub band index */ + uint8 pa_mode; /* PA mode */ + uint8 is_6g; /* 0: 2G/5G or 1: 6G */ + uint8 buf[WL_TPC_CMD_INFO_BUF_SZ]; /* value buffer */ +} wl_tpc_cmd_info_v2_t; + +typedef struct wl_tpc_cmd_v2 { + uint16 version; /* structure version */ + uint16 length; /* structure length */ + uint16 sub_cmd; /* sub_cmd type */ + uint8 PAD[2]; /* explicit padding */ + wl_tpc_cmd_info_v2_t info; +} wl_tpc_cmd_v2_t; + +#define WL_TPC_CMD_IOV_VER_1 1u +#define WL_TPC_CMD_IOV_VER_2 2u +#define WL_TPC_AVVMID_IOV_VER_1 1u +#define WL_TPC_PACAL_IOV_VER_1 1u +#define WL_TPC_TXPWRINDEX_IOV_VER_1 1u + +/* PTM */ +#define WL_PTM_IOV_MAJOR_VER_1 1u +#define WL_PTM_IOV_MINOR_VER_1 1u +#define WL_PTM_IOV_MAJOR_VER_SHIFT 8u +#define WL_PTM_IOV_VERSION_1_1 \ + ((WL_PTM_IOV_MAJOR_VER_1 << WL_PTM_IOV_MAJOR_VER_SHIFT)| WL_PTM_IOV_MINOR_VER_1) + +/* subcommand ids */ +enum wl_ptm_cmd_ids { + WL_PTM_SUBCMD_VER = 0u, /* PTM IOVAR version */ + WL_PTM_SUBCMD_ENABLE = 1u, /* PTM disable:0, interrupt:1, polling:2 */ + WL_PTM_SUBCMD_OFFSET_PERIOD = 2u, /* PTM offset period in ms */ + WL_PTM_SUBCMD_DRIFT_LIMIT = 3u, /* PTM drift limit in ns */ + WL_PTM_SUBCMD_LAST_DRIFT = 4u, /* PTM last drift in ns */ + WL_PTM_SUBCMD_LAST_OFFSET = 5u, /* PTM last offset in ns */ + WL_PTM_SUBCMD_CURRENT_TIME = 6u, /* PTM master and local time in ns */ + WL_PTM_SUBCMD_FAIL_LIMIT = 7u, /* PTM fail count limit */ + WL_PTM_SUBCMD_LAST +}; + +typedef struct wl_ptm_offset { + uint32 offset_high; + uint32 offset_low; + uint32 master_ahead; +} wl_ptm_offset_t; + +typedef struct wl_ptm_time { + uint32 offset_high; + uint32 offset_low; + uint32 local_high; + uint32 local_low; + uint32 master_high; + uint32 master_low; +} wl_ptm_time_t; + +typedef struct wl_ptm_master_time { + uint32 master_high; + uint32 master_low; +} wl_ptm_master_time_t; + +#define WL_TX_PER_TID_WME_ECNT_VER 1u +typedef struct tx_wme_eCounters +{ + uint16 version; + uint16 length; + uint32 tx[NUMPRIO]; +} tx_wme_eCounters_t; + +#define WL_RX_PER_TID_WME_ECNT_VER 1u +typedef struct rx_wme_eCounters +{ + uint16 version; + uint16 length; + uint32 rx[NUMPRIO]; +} rx_wme_eCounters_t; + +/* Interface for pm2 peek */ +#define WL_PM2_PEEK_VERSION_1 1u +typedef struct wl_pm2_peek_v1 { + uint16 version; /* structure version */ + uint16 length; /* length of this structure */ + uint16 enable; /* enable or disable the feature */ + uint16 offset; /* time since last tbtt when FW sends null data frame with PM0 */ + uint16 awake_time; /* After FW wake up, time to detect traffic */ +} wl_pm2_peek_v1_t; + +/* Triggered log events iovar structure */ +#define TRIG_LOG_EVENTS_CFG_REQ_VERSION_1 (1u) +enum trig_log_events_cmd { + TRIG_LOG_EVENTS_CMD_DISABLE_ALL = 0, /* Disable all active TLEs */ + TRIG_LOG_EVENTS_CMD_ENABLE = 1, /* Enable a list of TLEs */ + TRIG_LOG_EVENTS_CMD_DISABLE = 2, /* Disable a list of TLEs */ + TRIG_LOG_EVENTS_CMD_MAX +}; + +typedef struct trig_log_events_config_request_v1 { + uint16 version; /* config version */ + uint16 len; /* Length of this struct including variable len */ + uint8 cmd; /* Command to execute on list of TLEs sent in this struct */ + uint8 rsvd; + uint16 tles[]; /* List of triggered log event (TLE) ids */ +} trig_log_events_config_request_v1_t; + +/** Dynamic Tx Power Control common interfaces */ +#define WL_DTPC_IOV_VERSION_1 (1u) + +typedef enum wl_dtpc_iov { + WL_DTPC_CMD_EN = 0x0, /**< top control switch */ + WL_DTPC_CMD_TXS_THRES = 0x1, /**< txs PER threshold */ + WL_DTPC_CMD_PROBSTEP = 0x2, /**< step size */ + WL_DTPC_CMD_ALPHA = 0x3, /**< mv alpha */ + WL_DTPC_CMD_TRIGINT = 0x4, /**< pwr prob trigger interval */ + WL_DTPC_CMD_HEADROOM = 0x5, /**< power headroom */ + WL_DTPC_CMD_CAP = 0x6 /**< DTPC Tx/Rx capability */ +} wl_dtpc_iov_t; + +typedef struct rate_headroom { + ratespec_t rspec; + uint32 headroom; +} rate_headroom_t; + +typedef struct wl_dtpc_cfg_headroom { + uint8 max_bw; /* Max BW supported */ + uint8 max_nss; /* Max NSS supported */ + uint16 len; /* count of rspec/headroom entries that follow */ + rate_headroom_t headrooms[]; +} wl_dtpc_cfg_headroom_t; + +/* Version for IOVAR 'cellavoid' */ +#define WL_CELL_AVOID_IOV_VERSION_1 1u +/* Version for IOVAR 'cellavoid' subcmd */ +#define WL_CELL_AVOID_SUB_IOV_VERSION_1 1u +/* Max chanspec number for IOVAR 'cellavoid' */ +#define WL_CELL_AVOID_MAX_NUM_CHANSPEC 128u + +/* IOVAR 'cellavoid' subcmd list */ +enum wl_cell_avoid_subcmd_ids { + WL_CELL_AVOID_SUBCMD_VER = 0u, /* Get version */ + WL_CELL_AVOID_SUBCMD_CH_INFO = 1u, /* Set/Get/Remove cellular channel list */ +}; + +typedef struct wl_cell_pwrcap_chanspec_v1 { + int8 pwrcap; /* pwr cap applied to the cellular channel */ + int8 padding; /* padding */ + chanspec_t chanspec; /* chanspec for the clellular channel */ +} wl_cell_pwrcap_chanspec_v1_t; + +/* IOVAR 'cellavoid' subcmd structure + * Subcmd 'chinfo' uses this structure + */ +typedef struct wl_cell_avoid_ch_info_v1 { + uint16 version; /* version of this structure */ + uint16 length; /* length of this structure */ + uint16 flags; /* Mandatory flags */ + uint16 cnt; /* Count of pwrcap + chanspec info */ + wl_cell_pwrcap_chanspec_v1_t list[]; /* list for pwrcap+chanspec info */ +} wl_cell_avoid_ch_info_v1_t; + +/* flags in wl_cell_avoid_ch_info_v1_t is populated with following values + * If any of these are set, then the driver should completely avoid + * using any of cellular channels for any of these modes + */ +#define WL_CELL_AVOID_WIFI_DIRECT 0x0001u +#define WL_CELL_AVOID_SOFTAP 0x0002u +#define WL_CELL_AVOID_NAN 0x0004u +/* This flag is used to remove channel info list in chinfo subcmd */ +#define WL_CELL_AVOID_REMOVE_CH_INFO 0x8000u + +#ifdef COEX_CPU +enum wl_coex_cpu_sub_cmd_xtlv_id { + WL_COEX_CPU_CMD_FW_VERSION = 0u, /* Get firmware version string */ + WL_COEX_CPU_CMD_STATUS = 1u, /* Get current coex cpu status */ +}; +#endif /* COEX_CPU */ + +#define WLC_DYN_BW_CONFIG_VER_1 (1u) +typedef struct wlc_dyn_bw_cfg_v1 { + uint16 ver; /* Version */ + uint16 len; /* Length of the structure */ + uint8 is_enabled; /* Enable/disable dynamic BW */ + uint8 tx_dyn_bw; /* Tx dynamic BW active or not */ + uint8 backoff_sb; /* Dynamic BW Backoff sub-band */ + uint8 pad; /* Pad bytes */ + uint32 pricrs_mask; /* PRI_40_80_CRS_MASK in LSB + * IFS_CTL_SEL_PRICRS in MSB + */ +} wlc_dyn_bw_cfg_v1_t; + +enum wlc_dyn_bw_cmd_id { + WLC_DYN_BW_XTLV_VER_ID = 1u, + WLC_DYN_BW_XTLV_ENABLE_ID = 2u, + WLC_DYN_BW_XTLV_TX_ID = 3u, + WLC_DYN_BW_XTLV_BACKOFF_SB_ID = 4u, + WLC_DYN_BW_XTLV_PRICRS_MASK_ID = 5u, + WLC_DYN_BW_XTLV_SCRMBLR_WAR_ID = 6u, + WLC_DYN_BW_XTLV_LAST_ID +}; + +/* CAPEXT WL partition */ +/* The features listed in the enumeration below have subfeatures + * If a new feature is added and that feature has sub-features that need to be reported, + * add that feature here + */ +#define CAPEXT_WL_FEATURE_ID_BASE (2048u) +enum capext_wl_feature_id { + CAPEXT_WL_FEATURE_RSVD = (CAPEXT_WL_FEATURE_ID_BASE + 0), + /* WL top level feature id to hold and report bitmaps of features with and + * without sub-features. + */ + CAPEXT_WL_FEATURE_WL_FEATURES = (CAPEXT_WL_FEATURE_ID_BASE + 1), + /* other wl features with sub-features that need to be reported */ + CAPEXT_WL_FEATURE_AMPDU = (CAPEXT_WL_FEATURE_ID_BASE + 2), + CAPEXT_WL_FEATURE_AMSDU = (CAPEXT_WL_FEATURE_ID_BASE + 3), + CAPEXT_WL_FEATURE_STBC = (CAPEXT_WL_FEATURE_ID_BASE + 4), + CAPEXT_WL_FEATURE_NAN = (CAPEXT_WL_FEATURE_ID_BASE + 5), + CAPEXT_WL_FEATURE_COEX = (CAPEXT_WL_FEATURE_ID_BASE + 6), + CAPEXT_WL_FEATURE_FBT = (CAPEXT_WL_FEATURE_ID_BASE + 7), + CAPEXT_WL_FEATURE_MBSS = (CAPEXT_WL_FEATURE_ID_BASE + 8), + CAPEXT_WL_FEATURE_TXPWRCAP = (CAPEXT_WL_FEATURE_ID_BASE + 9), + CAPEXT_WL_FEATURE_PPR = (CAPEXT_WL_FEATURE_ID_BASE + 10), + CAPEXT_WL_FEATURE_PKT_FILTER = (CAPEXT_WL_FEATURE_ID_BASE + 11), + CAPEXT_WL_FEATURE_EHT = (CAPEXT_WL_FEATURE_ID_BASE + 12), + CAPEXT_WL_FEATURE_AP = (CAPEXT_WL_FEATURE_ID_BASE + 13), + CAPEXT_WL_FEATURE_MAX +}; + +/* MBSS cap sub-feature bit positions. These sub-features need to be reported */ +enum wlc_capext_mbss_subfeature_bitpos { + WLC_CAPEXT_MBSS_BITPOS_UCODE_BSS_0 = 0, + WLC_CAPEXT_MBSS_BITPOS_UCODE_BSS_1 = 1, + WLC_CAPEXT_MBSS_BITPOS_UCODE_BSS_2 = 2, + WLC_CAPEXT_MBSS_BITPOS_MAX +}; + +/* AMPDU cap sub-feature bit positions. These sub-features need to be reported */ +enum wlc_capext_ampdu_subfeature_bitpos { + WLC_CAPEXT_AMPDU_BITPOS_RX = 0, + WLC_CAPEXT_AMPDU_BITPOS_TX = 1, + WLC_CAPEXT_AMPDU_BITPOS_MAX +}; + +/* AMSDU cap sub-feature bit positions. These sub-features need to be reported */ +enum wlc_capext_amsdu_subfeature_bitpos { + WLC_CAPEXT_AMSDU_BITPOS_RX = 0, + WLC_CAPEXT_AMSDU_BITPOS_TX = 1, + WLC_CAPEXT_AMSDU_BITPOS_DYNLEN = 2, + WLC_CAPEXT_AMSDU_BITPOS_MAX +}; + +/* STBC cap sub-feature bit positions. These sub-features need to be reported */ +enum wlc_capext_stbc_subfeature_bitpos { + WLC_CAPEXT_STBC_BITPOS_TX = 0, + WLC_CAPEXT_STBC_BITPOS_RX_1SS = 1, + WLC_CAPEXT_STBC_BITPOS_MAX +}; + +/* TX power cap sub-feature bit positions. These sub-features need to be reported */ +enum wlc_capext_txpwrcap_subfeature_bitpos { + WLC_CAPEXT_TXPWRCAP_BITPOS_RSVD = 0, + WLC_CAPEXT_TXPWRCAP_BITPOS_TXPWRCAP_1 = 1, + WLC_CAPEXT_TXPWRCAP_BITPOS_TXPWRCAP_2 = 2, + WLC_CAPEXT_TXPWRCAP_BITPOS_TXPWRCAP_3 = 3, + WLC_CAPEXT_TXPWRCAP_BITPOS_TXPWRCAP_4 = 4, + WLC_CAPEXT_TXPWRCAP_BITPOS_MAX +}; + +/* PPR sub-feature bit positions. These sub-features need to be reported */ +enum wlc_capext_ppr_subfeature_bitpos { + WLC_CAPEXT_PPR_BITPOS_RSVD = 0, + WLC_CAPEXT_PPR_BITPOS_TLV_VER_1 = 1, + WLC_CAPEXT_PPR_BITPOS_TLV_VER_2 = 2, + WLC_CAPEXT_PPR_BITPOS_TLV_VER_3 = 3, + WLC_CAPEXT_PPR_BITPOS_TLV_VER_4 = 4, + WLC_CAPEXT_PPR_BITPOS_MAX +}; + +/* COEX sub-feature bit positions. These sub-features need to be reported */ +enum wlc_capext_coex_subfeature_bitpos { + WLC_CAPEXT_COEX_BITPOS_LTE = 0, + WLC_CAPEXT_COEX_BITPOS_LTECX_LBT = 1, + WLC_CAPEXT_COEX_BITPOS_BTC_WIFI_PROT = 2, + WLC_CAPEXT_COEX_BITPOS_RC1 = 3, + WLC_CAPEXT_COEX_BITPOS_SIB = 5, + WLC_CAPEXT_COEX_BITPOS_MAX +}; + +/* NAN sub-feature bit positions. These sub-features need to be reported */ +enum wlc_capext_nan_subfeature_bitpos { +#ifdef NAN_DAM_ANDROID + WLC_CAPEXT_NAN_BITPOS_AUTODAM = 0, + WLC_CAPEXT_NAN_BITPOS_P2P = 1, +#endif + WLC_CAPEXT_NAN_BITPOS_RANGE = 2, + WLC_CAPEXT_NAN_BITPOS_MESH = 3, + WLC_CAPEXT_NAN_BITPOS_MAX +}; + +/* FBT sub-feature bit positions. These sub-features need to be reported */ +enum wlc_capext_fbt_subfeature_bitpos { + WLC_CAPEXT_FBT_BITPOS_OVERDS = 0, + WLC_CAPEXT_FBT_BITPOS_ADPT = 1, + WLC_CAPEXT_FBT_BITPOS_MAX +}; + +/* Packet filter sub-feature bit positions. These sub-features need to be reported */ +enum wlc_capext_pkt_filter_subfeature_bitpos { + WLC_CAPEXT_PKT_FILTER_BITPOS_PKT_FILTER2 = 0, + WLC_CAPEXT_PKT_FILTER_BITPOS_PKT_FILTER6 = 1, + WLC_CAPEXT_PKT_FILTER_BITPOS_MAX +}; + +/* AP sub-feature bit positions. These sub-features need to be reported */ +enum wlc_capext_ap_subfeature_bitpos { + WLC_CAPEXT_AP_BITPOS_NONAX = 0, + WLC_CAPEXT_AP_BITPOS_AX_5G_ONLY = 1, + WLC_CAPEXT_AP_BITPOS_SAE = 2, + WLC_CAPEXT_AP_BITPOS_MAX +}; + +/* EHT sub-feature bit positions. These sub-features need to be reported */ +enum wlc_capext_eht_subfeature_bitpos { + WLC_CAPEXT_EHT_BITPOS_320MHZ = 0, + WLC_CAPEXT_EHT_BITPOS_MLO = 1, + WLC_CAPEXT_EHT_BITPOS_MAX +}; + +/* WLC features bit positions in top level WLC feature id. Features mentioned below are reported */ +enum wlc_capext_feature_bitpos { + WLC_CAPEXT_FEATURE_BITPOS_AP = 0, /* feature with sub-features */ + WLC_CAPEXT_FEATURE_BITPOS_STA = 1, + WLC_CAPEXT_FEATURE_BITPOS_TOE = 2, + WLC_CAPEXT_FEATURE_BITPOS_WME = 3, + WLC_CAPEXT_FEATURE_BITPOS_802_11d = 4, + + WLC_CAPEXT_FEATURE_BITPOS_802_11h = 5, + WLC_CAPEXT_FEATURE_BITPOS_RM = 6, + WLC_CAPEXT_FEATURE_BITPOS_CQA = 7, + WLC_CAPEXT_FEATURE_BITPOS_CAC = 8, + WLC_CAPEXT_FEATURE_BITPOS_MBSS = 9, /* feature with sub-features */ + + WLC_CAPEXT_FEATURE_BITPOS_DUALBAND = 10, + WLC_CAPEXT_FEATURE_BITPOS_AMPDU = 11, /* feature with sub-features */ + WLC_CAPEXT_FEATURE_BITPOS_AMSDU = 12, /* feature with sub-features */ + WLC_CAPEXT_FEATURE_BITPOS_TDLS = 13, + WLC_CAPEXT_FEATURE_BITPOS_WMF = 14, + + WLC_CAPEXT_FEATURE_BITPOS_RXCHAIN_PWRSAVE = 15, + WLC_CAPEXT_FEATURE_BITPOS_RADIO_PWRSAVE = 16, + WLC_CAPEXT_FEATURE_BITPOS_P2P = 17, + WLC_CAPEXT_FEATURE_BITPOS_BCMDCS = 18, + WLC_CAPEXT_FEATURE_BITPOS_PROP_TXSTATUS = 19, + + WLC_CAPEXT_FEATURE_BITPOS_MCHAN = 20, + WLC_CAPEXT_FEATURE_BITPOS_WDS = 21, + WLC_CAPEXT_FEATURE_BITPOS_DWDS = 22, + WLC_CAPEXT_FEATURE_BITPOS_CSO = 23, + WLC_CAPEXT_FEATURE_BITPOS_P2P0 = 24, + + WLC_CAPEXT_FEATURE_BITPOS_ANQPO = 25, + WLC_CAPEXT_FEATURE_BITPOS_PROXD = 26, + WLC_CAPEXT_FEATURE_BITPOS_VHT_PROP_RATES = 27, + WLC_CAPEXT_FEATURE_BITPOS_MU_BEAMFORMER = 28, + WLC_CAPEXT_FEATURE_BITPOS_SU_BEAMFORMER = 29, + + WLC_CAPEXT_FEATURE_BITPOS_MU_BEAMFORMEE = 30, + WLC_CAPEXT_FEATURE_BITPOS_SU_BEAMFORMEE = 31, + WLC_CAPEXT_FEATURE_BITPOS_160MHZ_SUPPORT = 32, + WLC_CAPEXT_FEATURE_BITPOS_HE = 33, + WLC_CAPEXT_FEATURE_BITPOS_EHT = 34, /* feature with sub-features */ + + WLC_CAPEXT_FEATURE_BITPOS_DFRTS = 35, + WLC_CAPEXT_FEATURE_BITPOS_LPAS = 36, + WLC_CAPEXT_FEATURE_BITPOS_TXPWRCACHE = 37, + WLC_CAPEXT_FEATURE_BITPOS_STBC = 38, /* feature with sub-features */ + WLC_CAPEXT_FEATURE_BITPOS_PS_PRETEND = 39, + + WLC_CAPEXT_FEATURE_BITPOS_MP2P = 40, + WLC_CAPEXT_FEATURE_BITPOS_RSDB = 41, + WLC_CAPEXT_FEATURE_BITPOS_PRBRESP_MAC_FLTR = 42, + WLC_CAPEXT_FEATURE_BITPOS_MFP = 43, + WLC_CAPEXT_FEATURE_BITPOS_NDOE = 44, + + WLC_CAPEXT_FEATURE_BITPOS_RSSI_MON = 45, + WLC_CAPEXT_FEATURE_BITPOS_WNM = 46, + WLC_CAPEXT_FEATURE_BITPOS_BSSTRANS = 47, + WLC_CAPEXT_FEATURE_BITPOS_EPNO = 48, + WLC_CAPEXT_FEATURE_BITPOS_PFNX = 49, + + WLC_CAPEXT_FEATURE_BITPOS_SCANMAC = 51, + WLC_CAPEXT_FEATURE_BITPOS_BDO = 52, + WLC_CAPEXT_FEATURE_BITPOS_PPR = 53, /* feature with sub-features */ + WLC_CAPEXT_FEATURE_BITPOS_VE = 54, + + WLC_CAPEXT_FEATURE_BITPOS_FBT = 55, /* feature with sub-features */ + WLC_CAPEXT_FEATURE_BITPOS_CDEF = 56, + WLC_CAPEXT_FEATURE_BITPOS_TXPWRCAP = 58, /* feature with sub-features */ + WLC_CAPEXT_FEATURE_BITPOS_MIMO_PS = 59, + + WLC_CAPEXT_FEATURE_BITPOS_ARB = 60, + WLC_CAPEXT_FEATURE_BITPOS_OCL = 61, + WLC_CAPEXT_FEATURE_BITPOS_D11STATUS = 62, + WLC_CAPEXT_FEATURE_BITPOS_SCANCACHE = 63, + WLC_CAPEXT_FEATURE_BITPOS_APF = 64, + + WLC_CAPEXT_FEATURE_BITPOS_ICMP = 65, + WLC_CAPEXT_FEATURE_BITPOS_IFVER = 66, + WLC_CAPEXT_FEATURE_BITPOS_TKO = 67, + WLC_CAPEXT_FEATURE_BITPOS_BGDFS = 68, + WLC_CAPEXT_FEATURE_BITPOS_IDAUTH = 69, + + WLC_CAPEXT_FEATURE_BITPOS_IFST = 70, + WLC_CAPEXT_FEATURE_BITPOS_NAP = 71, + WLC_CAPEXT_FEATURE_BITPOS_UCM = 72, + WLC_CAPEXT_FEATURE_BITPOS_FIE = 73, + WLC_CAPEXT_FEATURE_BITPOS_TVPM = 74, + + WLC_CAPEXT_FEATURE_BITPOS_TSYNC = 75, + WLC_CAPEXT_FEATURE_BITPOS_BCNTRIM = 76, + WLC_CAPEXT_FEATURE_BITPOS_LPR_SCAN = 77, + WLC_CAPEXT_FEATURE_BITPOS_BKOFF_EVT = 78, + WLC_CAPEXT_FEATURE_BITPOS_OPS = 79, + + WLC_CAPEXT_FEATURE_BITPOS_CLM_RESTRICT = 80, + WLC_CAPEXT_FEATURE_BITPOS_EVT_EXT = 81, + WLC_CAPEXT_FEATURE_BITPOS_TDMTX = 83, + WLC_CAPEXT_FEATURE_BITPOS_NATOE = 84, + + WLC_CAPEXT_FEATURE_BITPOS_MONITOR = 85, + WLC_CAPEXT_FEATURE_BITPOS_PSBW = 86, + WLC_CAPEXT_FEATURE_BITPOS_ROAMSTATS = 87, + WLC_CAPEXT_FEATURE_BITPOS_IDSUP = 88, + WLC_CAPEXT_FEATURE_BITPOS_GCMP = 89, + + WLC_CAPEXT_FEATURE_BITPOS_MBO = 90, + WLC_CAPEXT_FEATURE_BITPOS_ESTM = 91, + WLC_CAPEXT_FEATURE_BITPOS_SC = 92, + WLC_CAPEXT_FEATURE_BITPOS_6G = 93, + WLC_CAPEXT_FEATURE_BITPOS_TX_PROF = 94, + + WLC_CAPEXT_FEATURE_BITPOS_DSA = 95, + WLC_CAPEXT_FEATURE_BITPOS_ARPOE = 96, + WLC_CAPEXT_FEATURE_BITPOS_BCNPROT = 97, + WLC_CAPEXT_FEATURE_BITPOS_AVOID_BSSID = 98, + WLC_CAPEXT_FEATURE_BITPOS_IOT_BM = 99, + + WLC_CAPEXT_FEATURE_BITPOS_IOT_BD = 100, + WLC_CAPEXT_FEATURE_BITPOS_HOST_SFHLLC = 101, + WLC_CAPEXT_FEATURE_BITPOS_RCO = 102, + WLC_CAPEXT_FEATURE_BITPOS_PMR = 103, + WLC_CAPEXT_FEATURE_BITPOS_SCR = 104, + + WLC_CAPEXT_FEATURE_BITPOS_DTPC = 105, + WLC_CAPEXT_FEATURE_BITPOS_PASN = 106, + WLC_CAPEXT_FEATURE_BITPOS_QOS_MGMT = 107, + WLC_CAPEXT_FEATURE_BITPOS_LPC = 108, + WLC_CAPEXT_FEATURE_BITPOS_SAE = 109, + + WLC_CAPEXT_FEATURE_BITPOS_EXTSAE = 110, + WLC_CAPEXT_FEATURE_BITPOS_D3CBUF = 111, + WLC_CAPEXT_FEATURE_BITPOS_PKT_FILTER = 112, /* feature with sub-features */ + WLC_CAPEXT_FEATURE_BITPOS_COEX = 113, /* feature with sub-features */ + WLC_CAPEXT_FEATURE_BITPOS_NAN = 114, /* feature with sub-features */ + + WLC_CAPEXT_FEATURE_BITPOS_IGMPOE = 115, + WLC_CAPEXT_FEATURE_BITPOS_OWE = 116, + WLC_CAPEXT_FEATURE_BITPOS_CSI = 117, + WLC_CAPEXT_FEATURE_BITPOS_SAE_H2E = 118, + WLC_CAPEXT_FEATURE_BITPOS_SAE_PK = 119, + + WLC_CAPEXT_FEATURE_BITPOS_OBSS_HW = 120, + WLC_CAPEXT_FEATURE_BITPOS_DYN_BW = 121, + WLC_CAPEXT_FEATURE_BITPOS_OCT = 122, + WLC_CAPEXT_FEATURE_BITPOS_MBO_MIN = 123, + WLC_CAPEXT_FEATURE_BITPOS_OCV = 124, + WLC_CAPEXT_FEATURE_BITPOS_OCV_AP = 125, + + WLC_CAPEXT_FEATURE_BITPOS_MAX +}; + +#define WL_ROAM_PARAMS_IOV_MAJOR_VER_SHIFT 8u + +#define WL_ROAM_PARAMS_IOV_MAJOR_VER_1 1u +#define WL_ROAM_PARAMS_IOV_MINOR_VER_1 1u + +#define WL_ROAM_PARAMS_IOV_VERSION_1_1 \ + ((WL_ROAM_PARAMS_IOV_MAJOR_VER_1 << WL_ROAM_PARAMS_IOV_MAJOR_VER_SHIFT) | \ + WL_ROAM_PARAMS_IOV_MINOR_VER_1) + +/* roam_params sub-command types */ +typedef enum { + WL_ROAM_PARAMS_NONE = 0, + WL_ROAM_PARAMS_ALLOWED_BAND = 1, + WL_ROAM_PARAMS_MAX +} wl_roam_params_type_t; + +/* roam allowed band index */ +#define WLC_ROAM_ALLOW_BAND_AUTO WLC_BAND_AUTO /* auto-select */ +#define WLC_ROAM_ALLOW_BAND_2G (1<<0) /* 2.4 Ghz */ +#define WLC_ROAM_ALLOW_BAND_5G (1<<1) /* 5 Ghz */ +#if defined(WL_BAND6G) || defined(WL_6G_BAND) +#define WLC_ROAM_ALLOW_BAND_6G (1<<2) /* 6 Ghz */ +#define WLC_ROAM_ALLOW_BAND_MAX (WLC_ROAM_ALLOW_BAND_2G | WLC_ROAM_ALLOW_BAND_5G | \ + WLC_ROAM_ALLOW_BAND_6G) +#else +#define WLC_ROAM_ALLOW_BAND_MAX (WLC_ROAM_ALLOW_BAND_2G | WLC_ROAM_ALLOW_BAND_5G) +#endif /* WL_BAND6G || WL_6G_BAND */ + +/* + * Channel State Information (CSI) definitions + * + * IOVAR encoded in bcm_xtlv_t format with the subcommand as the TYPE field, + * length of subcommand data as the LENGTH field, followed by subcommand data + * structure as the DATA field. + */ + +/* subcommand enum */ +typedef enum wl_csi_subcommand { + WL_CSI_SUBCMD_VERSION = 0u, /* CSI version */ + WL_CSI_SUBCMD_DISABLE = 1u, /* disable CSI data */ + WL_CSI_SUBCMD_ENABLE = 2u, /* enable CSI data */ + WL_CSI_SUBCMD_DATA_INFO = 3u, /* get CSI data info */ + WL_CSI_SUBCMD_GET_DATA = 4u, /* get CSI data fragment */ +} wl_csi_subcommand_t; + +/* current version */ +#define WL_CSI_VERSION_V1 1u + +/* WL_CSI_SUBCMD_VERSION GET subcommand data */ +typedef struct wl_csi_version { + uint16 version; /* CSI version */ + uint8 pad[2u]; /* 4-byte struct alignment */ +} wl_csi_version_t; + +/* enable control bits */ +#define WL_CSI_ENABLE_CNTRL_TA (1u << 0u) /* match TA addr */ +#define WL_CSI_ENABLE_CNTRL_FRAME (1u << 1u) /* match frame type/subtype */ +#define WL_CSI_ENABLE_CNTRL_SUBCHANNEL (1u << 2u) /* enable subchannel index/width */ +#define WL_CSI_ENABLE_CNTRL_NSTREAM (1u << 3u) /* enable number of streams */ + +/* WL_CSI_SUBCMD_ENABLE SET subcommand data */ +typedef struct wl_csi_enable { + uint16 enable_control; /* control bits */ + uint8 subchannel_index; /* 0=1st, 1=2nd, etc */ + uint8 subchannel_width; /* 0=20mhz, 1=40mhz, 2=80mhz, etc */ + uint8 num_streams; /* 0=1 stream, 1=2 streams, etc */ + uint8 frame; /* frame type (bits=0x0c) and subtype (bits=0xf0) */ + chanspec_t chanspec; /* not currently used, reserved for future */ + struct ether_addr ta; /* transmit address to match */ + uint16 mode_timer; /* not currently used, reserved for future */ +} wl_csi_enable_t; + +/* WL_CSI_SUBCMD_DATA_INFO GET subcommand data info */ +typedef struct wl_csi_data_info { + struct ether_addr ta; /* transmit address */ + struct ether_addr ra; /* receive address */ + struct ether_addr bssid; /* bssid address */ + uint16 num_tones; /* number of tones in data */ + uint16 bw; /* bandwidth of frame */ + uint8 frame; /* frame type (bits=0x0c) and subtype (bits=0xf0) */ + uint8 nsts; /* num streams of frame */ + uint8 slice; /* 0=main, 1=aux */ + uint8 num_rx; /* number of rx cores in data */ + uint8 num_streams; /* number of streams in data */ + uint8 num_rssi; /* number of rssi in following array */ + int8 rssi[BCM_FLEX_ARRAY]; /* variable length array of rssi of each core */ +} wl_csi_data_info_t; + +/* WL_CSI_SUBCMD_GET_DATA GET subcommand data fragment request */ +typedef struct wl_csi_get_data_req { + uint32 offset; /* CSI data offset to read */ + uint32 length; /* request length */ +} wl_csi_get_data_req_t; + +/* WL_CSI_SUBCMD_GET_DATA GET subcommand data fragment response */ +typedef struct wl_csi_get_data_resp { + uint32 total_length; /* total length of CSI data */ + uint32 offset; /* CSI data offset read */ + uint32 length; /* length of CSI data in following array */ + uint32 csi_data[BCM_FLEX_ARRAY]; /* variable length array of CSI data */ +} wl_csi_get_data_resp_t; + +/* User roam cache size updated 10 so that + * 4 slots are provided for 6G. + */ +#define USER_ROAM_CACHE_MAX_COUNT 10u + +#define WL_OCT_IOV_VERSION_1 1u + +enum wl_oct_iov_sub_cmd_v1 { + IOV_OCT_SUB_CMD_NONE = 0u, + IOV_OCT_SUB_CMD_ENAB = 1u, + IOV_OCT_SUB_CMD_STALE_RESET_TIMEOUT = 2u, + IOV_OCT_SUB_CMD_NO_DECISION_TIMEOUT = 3u, + IOV_OCT_SUB_CMD_CUR_CORE_MIN_DWELL_TIME = 4u, + IOV_OCT_SUB_CMD_EMA_WEIGHT_FACTOR = 5u, + IOV_OCT_SUB_CMD_MIN_NUM_VALID_CNT = 6u, + IOV_OCT_SUB_CMD_RSSI_DELTA_THRESH = 7u, + IOV_OCT_SUB_CMD_MIN_SAMPLING_FREQ = 8u, + IOV_OCT_SUB_CMD_VERSION = 9u, + IOV_OCT_SUB_CMD_STATUS = 10u, + IOV_OCT_SUB_CMD_RESET_STATUS = 11u, + IOV_OCT_SUB_CMD_TOTAL +}; + +enum wl_oct_xtlv_id_v1 { + WL_OCT_XTLV_NONE = 0x0u, + WL_OCT_XTLV_ENABLE = 0x1u, + WL_OCT_XTLV_STALE_RESET_TIMEOUT = 0x2u, + WL_OCT_XTLV_NO_DECISION_TIMEOUT = 0x3u, + WL_OCT_XTLV_CUR_CORE_MIN_DWELL_TIME = 0x4u, + WL_OCT_XTLV_EMA_WEIGHT_FACTOR = 0x5u, + WL_OCT_XTLV_MIN_NUM_VALID_CNT = 0x6u, + WL_OCT_XTLV_RSSI_DELTA_THRESH = 0x7u, + WL_OCT_XTLV_MIN_SAMPLING_FREQ = 0x8u, + WL_OCT_XTLV_VERSION = 0x9u, + WL_OCT_XTLV_STATUS = 0xau, + WL_OCT_XTLV_RESET_STATUS = 0xbu, + WL_OCT_XTLV_TOTAL +}; + +typedef enum wl_oct_status_xtlv_id { + WL_OCT_STATUS_CMN_ID = 0u, + WL_OCT_STATUS_SLICE_ID = 1u, + WL_OCT_STATUS_XTLV_MAX = 2u +} wl_oct_status_xtlv_id_t; + +#define WL_OCT_STATUS_CMN_VER_1 1u /* status_cmn version */ +#define WL_OCT_STATUS_SLICE_VER_1 1u /* status_slice version */ + +/* WL_OCT_STATUS_CMN_ID */ +typedef struct wl_oct_status_cmn_v1 { + uint8 version; + uint8 infra_assoced; /* primary infra assoced */ + uint8 infra_assoc_slice; /* slice of primary infra assoced */ + uint8 selected_txcm; /* currently selected txcm */ +} wl_oct_status_cmn_v1_t; + +/* + * Definitions for disable bits in the per slice status + */ +#define OCT_DISABLED_HOST (1u << 0u) /* Host disabled */ +#define OCT_DISABLED_NOINFRA (1u << 1u) /* Disabled due to + * no-infra or AS not-idle + */ +#define OCT_DISABLED_SCAN (1u << 2u) /* Disable due to Scan active */ + +#define OCT_CORES_MAX 2u +/* WL_OCT_STATUS_SLICE_ID */ +typedef struct wl_oct_status_slice_v1 { + uint8 version; + uint8 slice_id; /* slice identifier */ + uint8 PAD[2]; /* 32-bit align */ + uint32 disable_bits; /* current disable bits */ + uint32 disable_dur; /* total disable duration (ms) */ + uint32 enable_dur; /* total enable duration (ms) */ + uint32 txcm_upd_cnt; /* total count of txcm decision updates + * due RSSI, TxPER, etc. blocks, + * currently RSSI block only + */ + uint32 txcm_upd_cnt_rssi; /* total count of txcore updates + * due to RSSI delta + */ + uint32 txcm_upd_cnt_rssi_aged; /* total count of txcore updates due to rssi aged */ + uint32 override_dur; /* total dur (ms) oct decision is overriden */ + uint32 txcm_dur[OCT_CORES_MAX]; /* per core txcm duration (ms) */ + uint32 txcm_cnt[OCT_CORES_MAX]; /* per core txcm count */ +} wl_oct_status_slice_v1_t; + +/* ====== C2C definitions ===== */ +/* subcommand IDs */ +enum wl_c2c_cmd_id { + WL_C2C_CMD_PRE_EXPIRY, + WL_C2C_CMD_REG_RULES, + WL_C2C_CMD_STATUS, + WL_C2C_CMD_STATS, + WL_C2C_CMD_AP_CACHE, + WL_C2C_CMD_CTRL, + WL_C2C_CMD_EVTMASK, + WL_C2C_CMD_LAST +}; + +/* xtlvs */ +enum wl_c2c_tlv_id { + WL_C2C_XTLV_AP_ENTRY, + WL_C2C_XTLV_AP_INFO, + WL_C2C_XTLV_LAST +}; + +/* WL_C2C_XTLV_AP_ENTRY */ +typedef struct wl_c2c_ap_entry { + struct ether_addr bssid; /* ap bssid */ + chanspec_t chanspec; /* ap chanspec */ + uint32 last_rx_time; /* last esig rx time (GET only) */ + uint32 num_esig_rx; /* esigs received from AP (GET only) */ + int8 rssi; /* rssi (GET only) */ + uint8 num_tlvs; /* number of tlvs included */ + uint8 pad[2]; + uint8 tlvs[]; +} wl_c2c_ap_entry_t; + +/* internal c2c states + * + * |----------ON----------|--ON(Pre-expiry)--| + * | | + * |<--------Enabling signal duration------->| + */ +#define C2C_STATE_OFF 1u /* c2c is inactive */ +#define C2C_STATE_ON 2u /* c2c active */ +#define C2C_STATE_ON_PRE_EXP 3u /* c2c active, in pre-expiry region */ + +#define C2C_SCAN_STATE_OFF 1u /* no c2c-initiated scan */ +#define C2C_SCAN_STATE_IN_PROG 2u /* c2c-initiated scan in progress */ + +#define C2C_SCAN_TYPE_DIRECT 1u /* direct scan to 6GHz AP */ +#define C2C_SCAN_TYPE_FULL 2u /* full scan */ + +/* WL_C2C_CMD_PRE_EXPIRY */ +typedef uint32 wl_c2c_pre_exp_t; /* pre expiry time */ + +/* WL_C2C_CMD_REG_RULES */ +#define WL_C2C_REG_RULES_VLP_ALLOWED 1u +#define WL_C2C_REG_RULES_INV_TIMEOUT 0xFFFFFFFFu + +typedef struct wl_c2c_reg_rules { + uint32 esig_timeout; /* enabling signal timeout(ms) */ + int8 min_rssi; /* enabling signal min rssi */ + uint8 pad[3]; /* available for use */ +} wl_c2c_reg_rules_t; + +/* WL_C2C_CMD_STATUS */ +typedef struct wl_c2c_status { + uint8 cur_state; /* c2c state */ + uint8 scan_state; /* scan state */ + struct ether_addr esig_bssid; /* current enabling signal bssid */ + chanspec_t esig_chanspec; /* current enabling signal chanspec */ + int8 esig_rssi; /* current enabling signal rssi */ + uint8 scan_type; /* scan type */ + uint32 last_dscan; /* last direct scan start (FW) time */ + uint32 last_fscan; /* last full scan start time */ +} wl_c2c_status_t; + +/* WL_C2C_CMD_CTRL */ +/* if set, enable scan requests from c2c module */ +#define WL_C2C_CTRL_C2C_SCAN 0x0001u +/* if set, enable c2c functionality + * if clear, c2c functionality - enabling signal processing, scanning, etc is disabled + */ +#define WL_C2C_CTRL_ENAB 0x0002u +#define WL_C2C_CTRL_ALLOWED_MASK (WL_C2C_CTRL_C2C_SCAN | WL_C2C_CTRL_ENAB) + +#define WL_C2C_CTRL_IS_C2C_SCAN(_ctrl) (((_ctrl) & WL_C2C_CTRL_C2C_SCAN) != 0) +#define WL_C2C_CTRL_IS_ENAB(_ctrl) (((_ctrl) & WL_C2C_CTRL_ENAB) != 0) + +typedef uint32 wl_c2c_ctrl_t; /* c2c control bit masks */ + +/* WL_C2C_CMD_AP_CACHE */ +/* WL_C2C_CMD_AP_CACHE operations */ +#define WL_C2C_CACHE_OP_GET 0u +#define WL_C2C_CACHE_OP_ADD 1u +#define WL_C2C_CACHE_OP_DEL 2u +#define WL_C2C_CACHE_OP_CLR 3u + +typedef struct wl_c2c_ap_cache { + uint8 op; /* WL_C2C_CACHE_OP */ + uint8 num_tlvs; /* number of tlvs */ + uint8 pad[2]; + uint8 tlvs[]; +} wl_c2c_ap_cache_t; + +/* WL_C2C_CMD_STATS */ +/* WL_C2C_CMD_STATS operations */ +#define WL_C2C_STATS_OP_CLEAR 0u + +typedef struct wl_c2c_stats { + uint32 esig_rx; /* total received enabling signals */ + uint32 c2c_on_off; /* count of c2c on to off */ + uint32 c2c_off_on; /* count of c2c off to on */ + uint32 c2c_extn; /* c2c extension (due to new esig) */ + uint32 dscan; /* number of directed scans */ + uint32 fscan; /* number of full scans */ + uint8 op; /* WL_C2C_STATS_OP */ + uint8 num_tlvs; /* number of tlvs included */ + uint8 pad[2]; /* available for use */ + uint8 tlvs[]; +} wl_c2c_stats_t; + +/* WL_C2C_CMD_EVTMASK */ +typedef uint32 wl_c2c_evt_mask_t; /* event mask */ + +/* events */ +#define WL_C2C_EVENT_AP_INFO_VER_1 1u +/* WL_C2C_XTLV_AP_INFO */ +typedef struct wl_c2c_event_ap_info { + uint16 version; /* version */ + uint16 len; /* total len */ + struct ether_addr bssid; /* AP bssid */ + chanspec_t chanspec; /* AP chanspec */ + uint32 time_ms; /* esig receive time (FW time in ms) */ + int8 rssi; /* rssi */ + uint8 num_tlvs; /* number of tlvs */ + uint8 pad[2]; + uint8 tlvs[]; /* optional TLVs */ +} wl_c2c_event_ap_info_t; + +#define WL_CH6GPROF_VER_1 1 +enum wl_ch6gprof_cmd_id { + WL_CH6GPROF_CMD_VER = 0u, + WL_CH6GPROF_CMD_EXPIRY_TO = 1u, + WL_CH6GPROF_CMD_RESET_CACHE = 2u +}; + +/* scbrate iovar: txminrate */ +#define WL_SCBRATE_TXMINRATE_VER_1 1u +typedef struct wl_scbrate_txminrate { + uint16 version; + uint16 len; + struct ether_addr peer_mac; /* mac addrss of peer */ + uint16 txminrate; /* Tx min rate in 0.5mbps */ +} wl_scbrate_txminrate_t; + +/* Test seeding top level command IDs */ +enum { + WL_SEED_TEST_CMD_ROAM_CONFIG = 0u, + WL_SEED_TEST_CMD_ROAM_CLEAR_TARGETS = 1u, + WL_SEED_TEST_CMD_ROAM_ADD_TARGETS = 2u, + WL_SEED_TEST_CMD_LAST +}; + +#define SEED_TEST_ROAM_CFG_VERSION_1 1u +/* set roam test seeding rule: + * replace(1) or append(0) host's target list to FW's scan results + */ +#define SEED_TEST_ROAM_CFGFLAG_REPLACE 0x1u + +struct wl_seed_test_roam_config_v1 { + uint16 version; + uint16 length; + uint16 flags; + uint8 pad[2]; +}; + +#define SEED_TEST_ROAM_MODE_CAP_N 0x1u +#define SEED_TEST_ROAM_MODE_CAP_VHT 0x2u +#define SEED_TEST_ROAM_MODE_CAP_EHT 0x4u +#define SEED_TEST_ROAM_MODE_CAP_HE 0x8u + +#define SEED_TEST_ROAM_ADD_TARGETS_VERSION_1 1u + +struct wl_seed_test_roam_add_targets_v1 { + uint16 version; /* version field */ + /* byte length of data in this data structure, + * starting at version and including IEs appended afterwards + */ + uint16 length; + struct ether_addr BSSID; + uint8 mode_cap; /* n_cap, he_cap, vht_cap, eht_cap */ + uint8 SSID_len; + /* values can be short ssid or ssid, indicated in flags */ + uint8 SSID[DOT11_MAX_SSID_LEN]; + chanspec_t chanspec; /* chanspec for bss */ + int16 RSSI; /* receive signal strength (in dBm) */ + uint16 capability; /* capability filed in beacon */ + uint16 flags; /* flags w.r.t. beacon: TBD */ + struct { + uint32 count; /* number of rates in this set */ + uint8 rates[WLC_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */ + } rateset; /* supported rates */ + uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ + uint16 vht_mcsmap; /* vhtmcsmap */ + uint16 vht_mcsmap_prop; /* prop vhtmcsmap */ + uint32 he_mcsmap; /* same as he_mcs_nss_set */ + wl_eht_mcsmap_t eht_mcsmap; /* EHT-MCS Map for the BSS operating chan width */ + uint8 pad1; + /* qbss load available admission capacity, from qbss_load_ie */ + uint16 qbss_load_aac; + /* indicates how free the channel is, (0xff - channel_utilization of qbss_load_ie) */ + uint8 qbss_load_chan_free; + /* last set max txpwr, from VHT TPE IE, for 6G AP */ + int8 max_tx_pwr_used; + /* from HE Operation IE with HE 6G Operation info, for 6G AP */ + uint8 reg_info_6g_bss; + uint8 pad2; + uint16 ie_length; /* length of following ie data, can be 0 */ + uint8 ie_data[]; /* ie data indicated by length above */ +}; + +/* subcommand ids for phy_dbg */ +enum wl_phy_dbg_cmd_type { + WL_PHY_DBG_CMD_GCI = 0u, /* GCI Dump */ + WL_PHY_DBG_CMD_LAST +}; + +#define WL_PHY_DBG_GCI_VERSION_1 1u + +typedef struct wl_phy_dbg_gci_data_v1 { + uint16 gci_lst_inv_ctr; + uint16 gci_lst_rst_ctr; + uint16 gci_lst_sem_fail; + uint16 gci_lst_rb_state; + uint16 gci_lst_state_mask; + uint16 gci_inv_tx; + uint16 gci_inv_rx; + uint16 gci_rst_tx; + uint16 gci_rst_rx; + uint16 gci_sem_fail; + uint16 gci_invstate; + uint16 gci_phyctl2; + uint16 gci_chan; + uint16 gci_cm; + uint16 gci_intr; + uint16 gci_rst_intr; + uint16 gci_rst_prdc_rx; + uint16 gci_rst_wk_rx; + uint16 gci_rst_rmac_rx; + uint16 gci_rst_tx_rx; + uint16 gci_dbg01; + uint16 gci_dbg02; + uint16 gci_dbg03; + uint16 gci_dbg04; + uint16 gci_dbg05; +} wl_phy_dbg_gci_data_v1_t; + +typedef struct wl_phy_dbg_v1 { + uint16 subcmd_version; /* Version of the sub-command */ + uint16 length; /* Length of the particular struct being used in union */ + union { + wl_phy_dbg_gci_data_v1_t gcivals_v1; /* GCI data */ + } u; +} wl_phy_dbg_v1_t; + +/* subcommand ids for phy_ed */ +enum wl_phy_ed_cmd_type { + WL_PHY_ED_CMD_MLED = 0u, /* get mled profile */ + WL_PHY_ED_CMD_LAST +}; + +#define WL_PHY_ED_MLED_VERSION_1 1u + +typedef struct wl_phy_ed_mled_v1 { + chanspec_t chanspec; /* chanspec */ + uint8 mled_profile; /* mled profile */ + uint8 region_group; /* region group - EU or other */ + int8 edthresh_val; /* ed threshold - primary */ + int8 edthresh_sec_val; /* ed threshold - secondary */ +} wl_phy_ed_mled_v1_t; + +#define WL_PHY_ED_MLED_VERSION_2 2u + +typedef struct wl_phy_ed_mled_v2 { + chanspec_t chanspec; /* chanspec */ + uint8 mled_profile; /* mled profile */ + uint8 eu_edcrs; /* EU or other */ + int8 edthresh_val; /* ed threshold - primary */ + int8 edthresh_sec_val; /* ed threshold - secondary */ +} wl_phy_ed_mled_v2_t; + +typedef struct wl_phy_ed_v1 { + uint16 subcmd_version; /* Version of the sub-command */ + uint16 length; /* Length of the particular struct being used in union */ + union { + wl_phy_ed_mled_v1_t mled_v1; /* mled profile data */ + wl_phy_ed_mled_v2_t mled_v2; /* mled profile data */ + } u; +} wl_phy_ed_v1_t; + +/* subcommand ids for phy_noise */ +enum wl_phy_noise_cmd_type { + WL_PHY_NOISE_CMD_LONG = 0u, /* get noise profile */ + WL_PHY_NOISE_CMD_LAST +}; + +#define WL_PHY_NOISE_LONG_VERSION_1 1u + +typedef struct wl_phy_noise_long_v1 { + uint8 long_accum; /* long accum */ + uint8 PAD[3]; +} wl_phy_noise_long_v1_t; + +typedef struct wl_phy_noise_v1 { + uint16 subcmd_version; /* Version of the sub-command */ + uint16 length; /* Length of the particular struct being used in union */ + union { + wl_phy_noise_long_v1_t long_v1; + } u; +} wl_phy_noise_v1_t; + +#ifndef CHSPEC2WLC_BAND +#ifdef WL_BAND6G +#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS2G(chspec) ? WLC_BAND_2G : \ + CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_6G) +#else +#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS2G(chspec) ? WLC_BAND_2G : WLC_BAND_5G) +#endif +#endif /* CHSPEC2WLC_BAND */ + +#define BUS_TX_RELEASE_LOG_VERSION_1 (1u) +typedef struct _bus_tx_release_log_entry_v1 { + uint32 ts; /* timestamp */ + uint32 flowid; /* flowing id */ + uint32 pkts_cnt; /* # of tx pkts released to wl layer */ + uint32 times; /* same flowid repeats how many times */ +} bus_tx_release_log_entry_v1_t; + +#define BUS_TX_RELEASE_LOG_FLAG_TRUNCATED (0x1u) +struct bus_tx_release_log_v1 { + uint16 version; /**< version field */ + uint16 flags; /**< flags */ + uint16 idx; /**< current index inside log */ + uint16 count; /**< total log count */ + bus_tx_release_log_entry_v1_t log[]; /**< count # of tx release log entries */ +}; + +/* Scancache command IDs */ +enum wl_scan_sub_cmd { + WL_SCAN_CACHE_EXT_CMD_CLEAR = 0u, + WL_SCAN_CACHE_EXT_CMD_GET = 1u, + WL_SCAN_CMD_LAST +}; + +#define SCAN_CACHE_VERSION_1 (1u) +typedef struct wlc_scan_cache_data_v1 { + wlc_ssid_t SSID; /* SSID of cached result */ + struct ether_addr BSSID; /* BSSID of cached result */ + bool valid; /* is cache entry valid */ + uint8 PAD[1]; + chanspec_t chanspec; /* chanspec of cached result */ + int16 RSSI; /* RSSI of cached result */ + uint32 timestamp; /* time when scancache is updated */ + uint32 capability; /* capability of cached entry */ + uint32 flags; /* Flags to indicate HT/VHT/HE/EHT etc */ + uint32 age_ms; /* Time difference of scan cache update + * and scan cache query + */ +} wlc_scan_cache_data_v1_t; + +typedef struct wlc_scan_cache_v1 { + uint16 version; + uint16 len; + wlc_scan_cache_data_v1_t scan_data[]; +} wlc_scan_cache_v1_t; + +#define SCAN_CACHE_FIXED_SIZE (OFFSETOF(wlc_scan_cache_v1_t, scan_data)) + +typedef struct wl_ext_auth_evt { + wlc_ssid_t ssid; + struct ether_addr bssid; + unsigned int key_mgmt_suite; + int status; +} wl_ext_auth_evt_t; + +/* SAR related parameter and structure */ +#define MAX_5G_SUBBAND 4 +#define MAX_6G_SUBBAND 6 +#define SAR_PARAM_V1_VSDB 1 +#define SAR_PARAM_V2_RSDB 2 +#define SAR_PARAM_6G_V3_VSDB 3 +#define SAR_PARAM_6G_V4_RSDB 4 + +typedef struct _sarctrl_single_set { + uint32 sarctrl_2g; + uint32 sarctrl_2g_2; + uint32 sarctrl_5gs[MAX_5G_SUBBAND]; + uint32 sarctrl_5gs_2[MAX_5G_SUBBAND]; +#if defined(WL_BAND6G) || defined(WL_6G_BAND) + uint32 sarctrl_6gs[MAX_6G_SUBBAND]; + uint32 sarctrl_6gs_2[MAX_6G_SUBBAND]; +#endif /* WL_BAND6G || WL_6G_BAND */ +} sarctrl_single_set; +#define CONST_SARCTRL_SINGLE_SET_QTY (sizeof(sarctrl_single_set)/sizeof(uint32)) + +typedef struct _sarctrl_set { + uint32 ver; + + sarctrl_single_set basic; + sarctrl_single_set rsdb; +} sarctrl_set; +#define CONST_SARCTRL_SET_QTY (sizeof(sarctrl_set)/sizeof(uint32) - 1) + #endif /* _wlioctl_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl_defs.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl_defs.h old mode 100755 new mode 100644 index 6ab03aadfc60..55ede5bc4f28 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl_defs.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl_defs.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -40,7 +40,9 @@ #undef D11AC_IOTYPES #define D11AC_IOTYPES -#ifndef USE_NEW_RSPEC_DEFS +#ifdef USE_LEGACY_RSPEC_DEFS +typedef uint32 ratespec_t; + /* Remove when no referencing branches exist. * These macros will be used only in older branches (prior to K branch). * Wl layer in newer branches and trunk use those defined in bcmwifi_rspec.h. @@ -89,7 +91,7 @@ #define GET_11N_MCS_NSS(mcs) ((mcs) < 32 ? (1 + ((mcs) / 8)) \ : ((mcs) == 32 ? 1 : GET_PROPRIETARY_11N_MCS_NSS(mcs))) #endif /* !OEM_ANDROID */ -#endif /* !USE_NEW_RSPEC_DEFS */ +#endif /* USE_LEGACY_RSPEC_DEFS */ /* Legacy defines for the nrate iovar */ #define OLD_NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ @@ -110,7 +112,6 @@ #define WLC_11N_FIRST_PROP_MCS 87 /* first Broadcom proprietary MCS */ #define WLC_11N_LAST_PROP_MCS 102 -#define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */ #define MAX_CCA_SECS 1 /* CCA keeps this many seconds history - trimmed for dongle */ #define IBSS_MED 15 /* Mediom in-bss congestion percentage */ @@ -230,10 +231,6 @@ #define WL_SCAN_THROTTLE_OTHER_FW_SCAN (1U << 2) /* for other scans like pno etc */ #define WL_SCAN_THROTTLE_HOSTSCAN (1U << 3) -/* Mask bit for Assoc scan, Roam scan, Other FW scan, Host scan bit defines */ -#define WL_SCANFLAGS_CLIENT_MASK 0xF00u -#define WL_SCANFLAGS_CLIENT_SHIFT 8 - /* Mask bit for LOW power scan, High accuracy scan, LOW span scan bit defines */ #define WL_SCANFLAGS_SCAN_MODE_MASK 0x7000u #define WL_SCANFLAGS_SCAN_MODE_SHIFT 12u @@ -246,22 +243,45 @@ * So, reserved flag definition removed. */ /* Use lower 16 bit for scan flags, the upper 16 bits are for internal use */ -#define WL_SCANFLAGS_PASSIVE 0x01U /* force passive scan */ -#define WL_SCANFLAGS_LOW_PRIO 0x02U /* Low priority scan */ -#define WL_SCANFLAGS_PROHIBITED 0x04U /* allow scanning prohibited channels */ -#define WL_SCANFLAGS_OFFCHAN 0x08U /* allow scanning/reporting off-channel APs */ -#define WL_SCANFLAGS_HOTSPOT 0x10U /* automatic ANQP to hotspot APs */ -#define WL_SCANFLAGS_SWTCHAN 0x20U /* Force channel switch for differerent bandwidth */ -#define WL_SCANFLAGS_FORCE_PARALLEL 0x40U /* Force parallel scan even when actcb_fn_t is on. - * by default parallel scan will be disabled if actcb_fn_t - * is provided. - */ -#define WL_SCANFLAGS_SISO 0x40U /* Use 1 RX chain for scanning */ -#define WL_SCANFLAGS_MIMO 0x80U /* Force MIMO scanning */ +#define WL_SCANFLAGS_PASSIVE 0x01U /* force passive scan */ +#define WL_SCANFLAGS_LOW_PRIO 0x02U /* Low priority scan */ +#define WL_SCANFLAGS_PROHIBITED 0x04U /* allow scanning prohibited channels */ +#define WL_SCANFLAGS_OFFCHAN 0x08U /* allow scanning/reporting off-channel + * APs. + */ +#define WL_SCANFLAGS_HOTSPOT 0x10U /* automatic ANQP to hotspot APs */ +#define WL_SCANFLAGS_SWTCHAN 0x20U /* Force channel switch for differerent + * bandwidth. + */ +#define WL_SCANFLAGS_FORCE_PARALLEL 0x40U /* Force parallel scan even when actcb_fn_t + * is on.By default parallel scan will be + * disabled if actcb_fn_t is provided. + */ +#define WL_SCANFLAGS_SISO 0x40U /* Use 1 RX chain for scanning */ +#define WL_SCANFLAGS_MIMO 0x80U /* Force MIMO scanning */ + +#define WL_SCANFLAGS_NO_6GHZ_FOLLOWUP 0x100U /* No 6G active scan due to RNR or FILS */ +#define WL_SCANFLAGS_INCL_FILS_DISC_FRAMES 0x200U /* Include Fils info as well in + * escan results. + */ +#define WL_SCANFLAGS_FORCE_SCAN_CORE_6G_SCAN 0x400U /* Force 6G scan on Scan core. */ +#define WL_SCANFLAGS_INCL_ORIG_RNR 0x800U /* Include scan results with + * matching RNR BSS + */ +/* This is to re purpose the definition to firmware internal use. + * By repurposing these bit values can be used for host. + * These are moved to higher bits and defined in firmware. + */ +#ifndef WL_SCANFLAGS_INT_SCANTYPE_HAS_ALIAS +/* Mask bit for Assoc scan, Roam scan, Other FW scan, Host scan bit defines */ +#define WL_SCANFLAGS_CLIENT_MASK 0xF00u +#define WL_SCANFLAGS_CLIENT_SHIFT 8 #define WL_SCANFLAGS_ASSOCSCAN 0x100U /* Assoc scan */ #define WL_SCANFLAGS_ROAMSCAN 0x200U /* Roam scan */ #define WL_SCANFLAGS_FWSCAN 0x400U /* Other FW scan */ #define WL_SCANFLAGS_HOSTSCAN 0x800U /* Host scan */ +#endif /* WL_SCANFLAGS_INT_SCANTYPE_HAS_ALIAS */ + #define WL_SCANFLAGS_LOW_POWER_SCAN 0x1000U /* LOW power scan, scheduled scan * only on scancore */ @@ -275,8 +295,11 @@ * enable LISTEN along with PASSIVE flag */ -/* BIT MASK for SSID TYPE */ -#define WL_SCAN_SSIDFLAGS_SHORT_SSID 0x01U /* Use as Regular SSID */ +/* BIT MASK for 6G_SCAN_TYPE */ +#define WL_SCAN_SSIDFLAGS_SHORT_SSID 0x01U /* include short ssid */ +#define WL_SCAN_INC_RNR 0x02U /* Include RNR channels for scan */ +#define WL_SCAN_SKIP_FILS_DISCOVERY_PERIOD 0x04U /* Skip FILS Discovery Period for 6G chans */ +#define WL_SCAN_ACTIVE_6GHZ 0x08U /* Force active scan for 6GHZ channel */ /* Value to decide scan type based on scqs */ #define WL_SC_RETRY_SCAN_MODE_NO_SCAN 0x0u /* Do not reschedule scan */ @@ -428,6 +451,15 @@ #define WL_BSS_FLAGS_SNR_INVALID 0x40 /* BSS contains invalid SNR */ #define WL_BSS_FLAGS_NF_INVALID 0x80 /* BSS contains invalid noise floor */ +/* bss_info_cap_t flags_2 */ +#define WL_BSS_FLAGS_THRU_LPSC 0x01 /* bss_info obtained thru' LPSC */ +#define WL_BSS_FLAGS_QBSS_LOAD 0x02 /* QBSS load value present */ +#define WL_BSS2_FLAGS_FROM_FILS 0x04 /* values are based on FILS frame */ +#define WL_BSS2_FLAGS_SHORT_SSID 0x08 /* values ssid is indicating as short ssid */ +#define WL_BSS2_FLAGS_RNR_MATCH 0x10 /* To report original BSS that has RNR match */ +#define WL_BSS2_FLAGS_HE_BCN_PRBRSP 0x20 /* BSS update to indiacte HE bcn or prb rsp. */ +#define WL_BSS2_FLAGS_HE_6G_DUP 0x40 /* non-HT dup'ed beacon indicator */ + /* bit definitions for bcnflags in wl_bss_info */ #define WL_BSS_BCNFLAGS_INTERWORK_PRESENT 0x01 /* beacon had IE, accessnet valid */ #define WL_BSS_BCNFLAGS_INTERWORK_PRESENT_VALID 0x02 /* on indicates support for this API */ @@ -435,10 +467,10 @@ #define WL_BSS_BCNFLAGS_NONTRANSMITTED_BSSID 0x8 /* this AP is the transmitted BSSID */ /* bssinfo flag for nbss_cap */ -#define VHT_BI_SGI_80MHZ 0x00000100 -#define VHT_BI_80MHZ 0x00000200 -#define VHT_BI_160MHZ 0x00000400 -#define VHT_BI_8080MHZ 0x00000800 +#define VHT_BI_SGI_80MHZ 0x00000100 +#define VHT_BI_80MHZ 0x00000200 +#define VHT_BI_160MHZ 0x00000400 +#define VHT_BI_8080MHZ 0x00000800 /* reference to wl_ioctl_t struct used by usermode driver */ #define ioctl_subtype set /* subtype param */ @@ -540,9 +572,9 @@ #define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED) #define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED) #else /* WLWSEC */ -#define WSEC_WEP_ENABLED(wsec) NULL -#define WSEC_TKIP_ENABLED(wsec) NULL -#define WSEC_AES_ENABLED(wsec) NULL +#define WSEC_WEP_ENABLED(wsec) (FALSE) +#define WSEC_TKIP_ENABLED(wsec) (FALSE) +#define WSEC_AES_ENABLED(wsec) (FALSE) #endif /* WLWSEC */ /* Macros to check if algorithm is enabled */ @@ -579,7 +611,7 @@ #endif /* BCMWAPI_WPI */ #endif /* BCMCCX */ #else /* WLWSEC */ -#define WSEC_ENABLED(wsec) 0 +#define WSEC_ENABLED(wsec) (FALSE) #endif /* WLWSEC */ #define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED) @@ -629,6 +661,7 @@ #define WPA3_AUTH_1X_SUITE_B_SHA384 0x400000 /* Suite B-192 SHA384 */ #define WPA3_AUTH_PSK_SHA384 0x800000 /* PSK with SHA384 key derivation */ #define WPA3_AUTH_SAE_AP_ONLY 0x1000000 /* SAE restriction to connect to pure SAE APs */ +#define WPA3_AUTH_SAE_EXT_PSK 0x2000000 /* SAE (variable length PMK) 4-way handshake */ /* WPA2_AUTH_SHA256 not used anymore. Just kept here to avoid build issue in DINGO */ #define WPA2_AUTH_SHA256 0x8000 #define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ @@ -637,24 +670,20 @@ #define MAXPMKID 16 /* max # PMKID cache entries NDIS */ #ifdef MACOSX -/* Macos limits ioctl maxlen to 2k */ -#define WLC_IOCTL_MAXLEN 2048 /* max length ioctl buffer required */ +/* Macos limits ioctl maxlen for TX to 1864 and for RX to 2004 */ +#define WLC_IOCTL_MAXLEN 2000 /* "max" length ioctl buffer */ #else -/* SROM12 changes */ -#define WLC_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ +#define WLC_IOCTL_MAXLEN 8192u /* "max" length ioctl buffer */ #endif /* MACOSX */ -#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ -#define WLC_IOCTL_MEDLEN 1896 /* "med" length ioctl buffer required */ -#if defined(LCNCONF) || defined(LCN40CONF) || defined(LCN20CONF) -#define WLC_SAMPLECOLLECT_MAXLEN 8192 /* Max Sample Collect buffer */ -#else -#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */ -#endif -#define WLC_SAMPLECOLLECT_MAXLEN_LCN40 8192 +#define WLC_IOCTL_MEDLEN 1936u /* "med" length ioctl buffer */ -#define WLC_IOCTL_NANRESP_MAXLEN 4096u /* "max" length nan ioctl resp buffer required */ -#define WLC_IOCTL_NANRESP_MEDLEN 800u /* "med" length nan ioctl resp buffer required */ +#define WLC_IOCTL_SMLEN 256u /* "small" length ioctl buffer */ + +#define WLC_SAMPLECOLLECT_MAXLEN 10240u /* Max Sample Collect buffer for two cores */ + +#define WLC_IOCTL_NANRESP_MAXLEN 4096u /* "max" length nan ioctl resp buffer */ +#define WLC_IOCTL_NANRESP_MEDLEN WLC_IOCTL_MEDLEN /* "med" length nan ioctl resp buffer */ /* common ioctl definitions */ #define WLC_GET_MAGIC 0 @@ -985,8 +1014,7 @@ #define WLC_GET_RSSI_QDB 321 /* qdB portion of the RSSI */ #define WLC_DUMP_RATESET 322 #define WLC_ECHO 323 -#define WLC_SCB_AUTHENTICATE 325 -#define WLC_LAST 326 /* The last ioctl. Also push this +#define WLC_LAST 324 /* The last ioctl. Also push this * number when adding new ioctls */ /* @@ -996,7 +1024,6 @@ * If this grows any more, it would be time to move these irelay-specific * definitions out of the epiioctl.h and into a separate driver common file. */ -#define WLC_SPEC_FLAG 0x80000000 /* For some special IOCTL */ #ifndef EPICTRL_COOKIE #define EPICTRL_COOKIE 0xABADCEDE #endif @@ -1222,8 +1249,7 @@ #define WLC_BW_40MHZ_BIT (1<<1) #define WLC_BW_80MHZ_BIT (1<<2) #define WLC_BW_160MHZ_BIT (1<<3) -#define WLC_BW_240MHZ_BIT (1<<4) -#define WLC_BW_320MHZ_BIT (1u<<5u) +#define WLC_BW_320MHZ_BIT (1u<<4u) /* Bandwidth capabilities */ #define WLC_BW_CAP_20MHZ (WLC_BW_20MHZ_BIT) @@ -1235,16 +1261,12 @@ #define WLC_BW_CAP_320MHZ (WLC_BW_320MHZ_BIT| \ WLC_BW_160MHZ_BIT|WLC_BW_80MHZ_BIT| \ WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) -#define WLC_BW_CAP_240MHZ (WLC_BW_240MHZ_BIT| \ - WLC_BW_160MHZ_BIT|WLC_BW_80MHZ_BIT| \ - WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) #define WLC_BW_CAP_UNRESTRICTED 0xFF #define WL_BW_CAP_20MHZ(bw_cap) (((bw_cap) & WLC_BW_20MHZ_BIT) ? TRUE : FALSE) #define WL_BW_CAP_40MHZ(bw_cap) (((bw_cap) & WLC_BW_40MHZ_BIT) ? TRUE : FALSE) #define WL_BW_CAP_80MHZ(bw_cap) (((bw_cap) & WLC_BW_80MHZ_BIT) ? TRUE : FALSE) #define WL_BW_CAP_160MHZ(bw_cap) (((bw_cap) & WLC_BW_160MHZ_BIT) ? TRUE : FALSE) -#define WL_BW_CAP_240MHZ(bw_cap) (((bw_cap) & WLC_BW_240MHZ_BIT) ? TRUE : FALSE) #define WL_BW_CAP_320MHZ(bw_cap) (((bw_cap) & WLC_BW_320MHZ_BIT) ? TRUE : FALSE) /* values to force tx/rx chain */ @@ -1286,21 +1308,6 @@ #define AP_ENV_SPARSE 2 /* "Home" or other sparse environment */ #define AP_ENV_INDETERMINATE 3 /* AP environment hasn't been identified */ -#define TRIGGER_NOW 0 -#define TRIGGER_CRS 0x01 -#define TRIGGER_CRSDEASSERT 0x02 -#define TRIGGER_GOODFCS 0x04 -#define TRIGGER_BADFCS 0x08 -#define TRIGGER_BADPLCP 0x10 -#define TRIGGER_CRSGLITCH 0x20 -#define TRIGGER_ASYNC 0x40 - -#define WL_SAMPLEDATA_HEADER_TYPE 1 -#define WL_SAMPLEDATA_HEADER_SIZE 80 /* sample collect header size (bytes) */ -#define WL_SAMPLEDATA_TYPE 2 -#define WL_SAMPLEDATA_SEQ 0xff /* sequence # */ -#define WL_SAMPLEDATA_MORE_DATA 0x100 /* more data mask */ - /* WL_OTA START */ #define WL_OTA_ARG_PARSE_BLK_SIZE 1200 #define WL_OTA_TEST_MAX_NUM_RATE 30 @@ -1371,6 +1378,8 @@ #define WL_TX_POWER_F_TXCAP 0x200 #define WL_TX_POWER_F_HE 0x400 #define WL_TX_POWER_F_RU_RATE 0x800 +#define WL_TX_POWER_TPE_PSD 0x1000 +#define WL_TX_POWER_TPE_LOC 0x2000 /* Message levels */ #define WL_ERROR_VAL 0x00000001 @@ -1446,23 +1455,15 @@ #define WL_FBT_VAL 0x00800000 #define WL_RRM_VAL 0x00800000 /* reuse */ #define WL_MQ_VAL 0x01000000 -/* This level is currently used in Phoenix2 only */ -#define WL_SRSCAN_VAL 0x02000000 +#define WL_RANDMAC_VAL 0x02000000 #define WL_WNM_VAL 0x04000000 /* re-using WL_WNM_VAL for MBO */ #define WL_MBO_VAL 0x04000000 -/* re-using WL_SRSCAN_VAL */ -#define WL_RANDMAC_VAL 0x02000000 -#ifdef WLAWDL -#define WL_AWDL_VAL 0x08000000 -#endif /* WLAWDL */ - -#define WL_UNUSED_VAL 0x10000000 /* Was a duplicate for WL_LPC_VAL. Removed */ #define WL_NET_DETECT_VAL 0x20000000 -#define WL_OCE_VAL 0x20000000 /* reuse */ +#define WL_OCE_VAL 0x20000000 /* reuse */ #define WL_PCIE_VAL 0x40000000 -#define WL_PMDUR_VAL 0x80000000 +#define WL_PMDUR_VAL 0x80000000 /* use top-bit for WL_TIME_STAMP_VAL because this is a modifier * rather than a message-type of its own */ @@ -1475,21 +1476,37 @@ #define WL_FILS_VAL 0x00000002 #define WL_LATENCY_VAL 0x00000004 #define WL_WBUS_VAL 0x00000008 +#define WL_DTPC_DBG_VAL 0x00000010 /* number of bytes needed to define a proper bit mask for MAC event reporting */ #define BCMIO_ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) #define BCMIO_NBBY 8 -#define WL_EVENTING_MASK_LEN (16+4) /* Don't increase this without wl review */ +#define WL_EVENTING_MASK_LEN 16 /* Don't increase this without wl review */ #define WL_EVENTING_MASK_EXT_LEN ROUNDUP(WLC_E_LAST, NBBY)/NBBY /* join preference types */ -#define WL_JOIN_PREF_RSSI 1u /* by RSSI */ -#define WL_JOIN_PREF_WPA 2u /* by akm and ciphers */ -#define WL_JOIN_PREF_BAND 3u /* by 802.11 band */ -#define WL_JOIN_PREF_RSSI_DELTA 4u /* by 802.11 band only if RSSI delta condition matches */ -#define WL_JOIN_PREF_TRANS_PREF 5u /* defined by requesting AP */ -#define WL_JOIN_PREF_RSN_PRIO 6u /* by RSNE/RSNXE related security priority */ +#define WL_JOIN_PREF_RSSI 1u /* by RSSI */ +#define WL_JOIN_PREF_WPA 2u /* by akm and ciphers */ +#define WL_JOIN_PREF_BAND 3u /* by 802.11 band */ +#define WL_JOIN_PREF_RSSI_DELTA 4u /* by 802.11 band only if RSSI + * delta condition matches + */ +#define WL_JOIN_PREF_TRANS_PREF 5u /* defined by requesting AP */ +#define WL_JOIN_PREF_RSN_PRIO 6u /* by RSNE/RSNXE related security priority */ +#define WL_JOIN_PREF_RSSI_PER_BAND 7u /* RSSI boost value per band */ +#define WL_JOIN_PREF_SKIP_PSC 8u /* Used to set flag to filter PSC channel scan */ +#define WL_JOIN_PREF_6G_DISABLE 9u /* Used to disable join/roam 6G BSS target */ + +/* Join preference 6G disable Flag definition */ +#define WL_JP_6G_DISABLE_ROAM (1u << 0u) /* Used to set flag to disable join/roam to + 6G BSS target + */ + +/* Join preference skip PSC Flag definition */ +#define WL_JP_SKIP_PSC_ROAM (1u << 0u) /* Used to set flag to filter PSC channel + during full band roam scan + */ /* Join preference RSN priority */ #define WL_JP_RSN_SAE_PK 1u /* SAE-PK higher priority over non SAE-PK APs */ @@ -1529,6 +1546,13 @@ */ #define WL_CHAN_CLM_RESTRICTED (1u << 8) /* channel restricted in CLM (i.e. by default) */ #define WL_CHAN_BAND_6G (1u << 9) /* 6GHz-band channel */ +#define WL_CHAN_BAND_6G_VLP (1u << 10u) /* 6GHz VLP channel */ +#define WL_CHAN_BAND_6G_PSC (1u << 11u) /* 6GHz PSC channel */ +#define WL_CHAN_BAND_6G_LPI (1u << 12u) /* 6GHz LPI channel */ +#define WL_CHAN_BAND_6G_SP (1u << 13u) /* 6GHz SP channel */ +#define WL_CHAN_INDOOR_ONLY (1u << 14u) /* indoor only channel */ +#define WL_CHAN_P2P_PROHIBITED (1u << 15u) /* p2p restricted channel */ + #define WL_CHAN_OOS_SHIFT 24u /* shift for OOS field */ #define WL_CHAN_OOS_MASK 0xFF000000u /* field specifying minutes remaining for this * channel's out-of-service period due to radar @@ -1537,17 +1561,22 @@ /* BTC mode used by "btc_mode" iovar */ #define WL_BTC_DISABLE 0 /* disable BT coexistence */ -#define WL_BTC_FULLTDM 1 /* full TDM COEX */ -#define WL_BTC_ENABLE 1 /* full TDM COEX to maintain backward compatiblity */ -#define WL_BTC_PREMPT 2 /* full TDM COEX with preemption */ -#define WL_BTC_LITE 3 /* light weight coex for large isolation platform */ -#define WL_BTC_PARALLEL 4 /* BT and WLAN run in parallel with separate antenna */ -#define WL_BTC_HYBRID 5 /* hybrid coex, only ack is allowed to transmit in BT slot */ +#define WL_BTC_FULLTDM 1 /* full TDM COEX */ +#define WL_BTC_ENABLE 1 /* full TDM COEX to maintain backward compatiblity */ +#define WL_BTC_PREMPT 2 /* full TDM COEX with preemption */ +#define WL_BTC_LITE 3 /* light weight coex for large isolation platform */ +#define WL_BTC_PARALLEL 4 /* BT and WLAN run in parallel with separate antenna */ +#define WL_BTC_HYBRID 5 /* hybrid coex, only ack allowed to transmit in BT slot */ +#define WL_BTC_HYBRID_WLTX 6 /* hybrid coex HPP mode w WL data Tx during BT grant */ #define WL_BTC_DEFAULT 8 /* set the default mode for the device */ #define WL_INF_BTC_DISABLE 0 #define WL_INF_BTC_ENABLE 1 #define WL_INF_BTC_AUTO 3 +#define WL_BTC_MODE_IOV_2G_MASK 0xFFu +#define WL_BTC_MODE_IOV_5G_MASK 0xFF00u +#define WL_BTC_MODE_IOV_5G_SHIFT 0x8u + /* BTC wire used by "btc_wire" iovar */ #define WL_BTC_DEFWIRE 0 /* use default wire setting */ #define WL_BTC_2WIRE 2 /* use 2-wire BTC */ @@ -1572,16 +1601,22 @@ * It is preserved only for compatibility with older branches that use it */ #ifdef WL_BAND6G +#ifdef WL_BAND5P9G +#ifdef WL11AC_80P80 +#define WL_NUMCHANSPECS 466 +#else +#define WL_NUMCHANSPECS 370 +#endif +#else #ifdef WL11AC_80P80 #define WL_NUMCHANSPECS 446 #else #define WL_NUMCHANSPECS 350 #endif +#endif /* WL_BAND5P9G */ #else #if defined(WL11AC_80P80) #define WL_NUMCHANSPECS 206 -#elif defined(WL_BW160MHZ) -#define WL_NUMCHANSPECS 140 #else #define WL_NUMCHANSPECS 110 #endif @@ -1741,9 +1776,6 @@ #define MAX_RSSI_LEVELS 8 -/* **** EXTLOG **** */ -#define EXTLOG_CUR_VER 0x0100 - #define MAX_ARGSTR_LEN 18 /* At least big enough for storing ETHER_ADDR_STR_LEN */ /* log modules (bitmap) */ @@ -1843,6 +1875,14 @@ #define WL_CHANIM_COUNT_ALL 0xff #define WL_CHANIM_COUNT_ONE 0x1 +/* flags used in scandb, indicates bss attributes of interest */ +#define WLC_SCANDB_CACHE_FLAG_NONE (0u) /* None */ +#define WLC_SCANDB_CACHE_FLAG_HT_CAP (1u << 0u) /* HT capable */ +#define WLC_SCANDB_CACHE_FLAG_VHT_CAP (1u << 1u) /* VHT capable */ +#define WLC_SCANDB_CACHE_FLAG_HE_CAP (1u << 2u) /* HE capable */ +#define WLC_SCANDB_CACHE_FLAG_EHT_CAP (1u << 3u) /* EHT capable */ +#define WLC_SCANDB_CACHE_FLAG_FTM_RESP (1u << 4u) /* FTM responder */ + /* Module id: to know which module has sent the stats */ #define SC_CHANIM_ID_NULL 0u #define SC_CHANIM_ID_SCAN 1u /* Module Id of scan, used to report scqs */ @@ -2129,7 +2169,8 @@ #define SUPPRESS_SSID_MASK 0x0200 #define ENABLE_NET_OFFLOAD_MASK 0x0400 /* report found/lost events for SSID and BSSID networks seperately */ -#define REPORT_SEPERATELY_MASK 0x0800 +#define REPORT_SEPARATELY_MASK 0x0800 +#define REPORT_SEPERATELY_MASK REPORT_SEPARATELY_MASK // Legacy typo #define BESTN_BSSID_ONLY_MASK 0x1000 #ifdef PFN_SCANRESULT_2 @@ -2138,7 +2179,7 @@ #define PFN_SCANRESULT_VERSION 1 #endif /* PFN_SCANRESULT_2 */ #ifndef MAX_PFN_LIST_COUNT -#define MAX_PFN_LIST_COUNT 16 +#define MAX_PFN_LIST_COUNT 64 #endif /* MAX_PFN_LIST_COUNT */ #define PFN_COMPLETE 1 @@ -2169,6 +2210,8 @@ #define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ #define WL_PFN_CFG_FLAGS_HISTORY_OFF 0x00000002 /* Scan history suppressed */ +/* Set to avoid sending direct probe in 6G channels */ +#define WL_PFN_CFG_FLAGS_NO_6GHZ_FOLLOWUP 0x00000004 #define WL_PFN_HIDDEN_BIT 2 #define PNO_SCAN_MAX_FW 508*1000 /* max time scan time in msec */ @@ -2194,11 +2237,11 @@ #define TOE_ERRTEST_RX_CSUM2 0x00000004 /* ARP Offload feature flags for arp_ol iovar */ -#define ARP_OL_AGENT 0x00000001 -#define ARP_OL_SNOOP 0x00000002 -#define ARP_OL_HOST_AUTO_REPLY 0x00000004 -#define ARP_OL_PEER_AUTO_REPLY 0x00000008 -#define ARP_OL_UPDATE_HOST_CACHE 0x00000010 +#define ARP_OL_AGENT 0x00000001 /* enable processing of rx ARP packets */ +#define ARP_OL_SNOOP 0x00000002 /* populate using ARP pkts from host */ +#define ARP_OL_HOST_AUTO_REPLY 0x00000004 /* reply to ARP request from host */ +#define ARP_OL_PEER_AUTO_REPLY 0x00000008 /* reply to ARP request from peer */ +#define ARP_OL_UPDATE_HOST_CACHE 0x00000010 /* forward new ARP request to host */ /* ARP Offload error injection */ #define ARP_ERRTEST_REPLY_PEER 0x1 @@ -2212,30 +2255,6 @@ #endif /* WL_PKT_FLTR_EXT && !WL_PKT_FLTR_EXT_DISABLED */ #define ND_REQUEST_MAX 5 /* Max set of offload params */ -#ifdef WLAWDL -/* AWDL AF flags for awdl_oob_af iovar */ -#define AWDL_OOB_AF_FILL_TSF_PARAMS 0x00000001 -#define AWDL_OOB_AF_FILL_SYNC_PARAMS 0x00000002 -#define AWDL_OOB_AF_FILL_ELECT_PARAMS 0x00000004 -#define AWDL_OOB_AF_PARAMS_SIZE 38 - -#define AWDL_OPMODE_AUTO 0 -#define AWDL_OPMODE_FIXED 1 - -#define AWDL_PEER_STATE_OPEN 0 -#define AWDL_PEER_STATE_CLOSE 1 - -#define SYNC_ROLE_SLAVE 0 -#define SYNC_ROLE_NE_MASTER 1 /* Non-election master */ -#define SYNC_ROLE_MASTER 2 - -/* peer opcode */ -#define AWDL_PEER_OP_ADD 0 -#define AWDL_PEER_OP_DEL 1 -#define AWDL_PEER_OP_INFO 2 -#define AWDL_PEER_OP_UPD 3 -#endif /* WLAWDL */ - /* AOAC wake event flag */ #define WAKE_EVENT_NLO_DISCOVERY_BIT 1 #define WAKE_EVENT_AP_ASSOCIATION_LOST_BIT 2 @@ -2453,10 +2472,6 @@ #define WL_PWRSTATS_TYPE_PM_AWAKE1 3 /**< struct wl_pwr_pm_awake_stats_v1 */ #define WL_PWRSTATS_TYPE_CONNECTION 4 /* struct wl_pwr_connect_stats; assoc and key-exch time */ -#ifdef WLAWDL -#define WL_PWRSTATS_TYPE_AWDL 5 /**< struct wl_pwr_awdl_stats; */ -#endif /* WLAWDL */ - #define WL_PWRSTATS_TYPE_PCIE 6 /**< struct wl_pwr_pcie_stats */ #define WL_PWRSTATS_TYPE_PM_AWAKE2 7 /**< struct wl_pwr_pm_awake_stats_v2 */ #define WL_PWRSTATS_TYPE_SDIO 8 /* struct wl_pwr_sdio_stats */ @@ -2468,6 +2483,8 @@ #define WL_PWRSTATS_TYPE_SLICE_INDEX_BAND_INFO 14 /* wl_pwr_slice_index_band_t */ #define WL_PWRSTATS_TYPE_PSBW_STATS 15 /* struct wl_pwr_psbw_stats_t */ #define WL_PWRSTATS_TYPE_PM_ACCUMUL 16 /* struct wl_pwr_pm_accum_stats_v1_t */ +#define WL_PWRSTATS_TYPE_SCAN_6E 17 /* struct wl_pwr_scan_6E_stats_v1 */ +#define WL_PWRSTATS_TYPE_SCAN_EXT 18 /**< struct wl_pwr_scan_stats_v1 */ /* IOV AWD DATA */ #define AWD_DATA_JOIN_INFO 0 @@ -2511,4 +2528,29 @@ /* Add get and set macros for each of the configs? */ /* === Place holder for cnx and nan cfgs === */ + +/* Timeout checks to disable. Bits in mask, returned by hnd_get_dbg_disable_to_mask() */ +/* Disables H2D DMA stall health check */ +#define DBG_DISABLE_PCIE_H2D_DMA_TO_MASK 0x00000001 +/* Disables D2H DMA stall health check */ +#define DBG_DISABLE_PCIE_D2H_DMA_TO_MASK 0x00000002 +/* Disables IOCTL timeout health check */ +#define DBG_DISABLE_PCIE_IOCTL_TO_MASK 0x00000004 +/* Disables flowring timeout health check */ +#define DBG_DISABLE_PCIE_FLOWRING_TO_MASK 0x00000008 +/* Disables rxpost timeout health check */ +#define DBG_DISABLE_PCIE_RXPOST_TO_MASK 0x00000010 +/* Disables D3ACK timeout health check */ +#define DBG_DISABLE_PCIE_D3ACK_TO_MASK 0x00000020 +/* Disables DS ACK timeout health check */ +#define DBG_DISABLE_PCIE_DSACK_TO_MASK 0x00000040 +/* Disables host wake assert timeout health check */ +#define DBG_DISABLE_PCIE_HOST_WAKE_TO_MASK 0x00000080 +/* Disables deep sleep wake timeout health check */ +#define DBG_DISABLE_DS_NO_SLEEP_TO_MASK 0x00000100 +/* Disables RX DMA stall health check */ +#define DBG_DISABLE_RX_STALL_TO_MASK 0x00000200 +/* Disables TX DMA stall health check */ +#define DBG_DISABLE_TX_STALL_TO_MASK 0x00000400 + #endif /* wlioctl_defs_h */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl_utils.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl_utils.h old mode 100755 new mode 100644 index b419d170917c..9558938684bd --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl_utils.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl_utils.h @@ -1,7 +1,7 @@ /* * Custom OID/ioctl related helper functions. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wpa.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wpa.h old mode 100755 new mode 100644 index 331cbbbe7bf5..da403ee53db8 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wpa.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wpa.h @@ -1,7 +1,7 @@ /* * Fundamental types and constants relating to WPA * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -96,7 +96,7 @@ typedef BWL_PRE_PACKED_STRUCT struct uint8 low; uint8 high; } BWL_POST_PACKED_STRUCT count; - wpa_suite_t list[1]; + wpa_suite_t list[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; #define WPA_IE_SUITE_COUNT_LEN 2 typedef BWL_PRE_PACKED_STRUCT struct @@ -105,7 +105,7 @@ typedef BWL_PRE_PACKED_STRUCT struct uint8 low; uint8 high; } BWL_POST_PACKED_STRUCT count; - wpa_pmkid_t list[1]; + wpa_pmkid_t list[BCM_FLEX_ARRAY]; } BWL_POST_PACKED_STRUCT wpa_pmkid_list_t; /* WPA cipher suites */ @@ -134,13 +134,6 @@ typedef BWL_PRE_PACKED_STRUCT struct #define WPA_CIPHER_BIP_GMAC_256 12 /* BIP_GMAC_256 */ #define WPA_CIPHER_BIP_CMAC_256 13 /* BIP_CMAC_256 */ -#ifdef BCMWAPI_WAI -#define WAPI_CIPHER_NONE WPA_CIPHER_NONE -#define WAPI_CIPHER_SMS4 11 - -#define WAPI_CSE_WPI_SMS4 1 -#endif /* BCMWAPI_WAI */ - #define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ (cipher) == WPA_CIPHER_WEP_40 || \ (cipher) == WPA_CIPHER_WEP_104 || \ @@ -157,18 +150,6 @@ typedef BWL_PRE_PACKED_STRUCT struct (cipher) == WPA_CIPHER_BIP_GMAC_256 || \ (cipher) == WPA_CIPHER_BIP_CMAC_256) -#ifdef BCMWAPI_WAI -#define IS_WAPI_CIPHER(cipher) ((cipher) == WAPI_CIPHER_NONE || \ - (cipher) == WAPI_CSE_WPI_SMS4) - -/* convert WAPI_CSE_WPI_XXX to WAPI_CIPHER_XXX */ -#define WAPI_CSE_WPI_2_CIPHER(cse) ((cse) == WAPI_CSE_WPI_SMS4 ? \ - WAPI_CIPHER_SMS4 : WAPI_CIPHER_NONE) - -#define WAPI_CIPHER_2_CSE_WPI(cipher) ((cipher) == WAPI_CIPHER_SMS4 ? \ - WAPI_CSE_WPI_SMS4 : WAPI_CIPHER_NONE) -#endif /* BCMWAPI_WAI */ - #define IS_VALID_AKM(akm) ((akm) == RSN_AKM_NONE || \ (akm) == RSN_AKM_UNSPECIFIED || \ (akm) == RSN_AKM_PSK || \ @@ -185,12 +166,14 @@ typedef BWL_PRE_PACKED_STRUCT struct (akm) == RSN_AKM_FILS_SHA384 || \ (akm) == RSN_AKM_OWE || \ (akm) == RSN_AKM_SUITEB_SHA256_1X || \ - (akm) == RSN_AKM_SUITEB_SHA384_1X) + (akm) == RSN_AKM_SUITEB_SHA384_1X || \ + (akm) == RSN_AKM_PASN) #define IS_VALID_BIP_CIPHER(cipher) ((cipher) == WPA_CIPHER_BIP || \ (cipher) == WPA_CIPHER_BIP_GMAC_128 || \ (cipher) == WPA_CIPHER_BIP_GMAC_256 || \ - (cipher) == WPA_CIPHER_BIP_CMAC_256) + (cipher) == WPA_CIPHER_BIP_CMAC_256 || \ + (cipher) == WPA_CIPHER_TPK) #define WPA_IS_FT_AKM(akm) ((akm) == RSN_AKM_FBT_SHA256 || \ (akm) == RSN_AKM_FBT_SHA384) @@ -283,23 +266,14 @@ typedef struct rsn_ie_info { uint8 ptk_len; /* EAPOL PTK */ uint8 kck2_len; /* EAPOL KCK2 */ uint8 kek2_len; /* EAPOL KEK2 */ + uint8 rsnxe_len; /* RSNXE IE from assoc request */ + uint8 *rsnxe; /* RSNXE IE length */ + uint8 kdk_len; /* EAPOL KDK */ + uint8 pad[3]; + uint32 rsnxe_cap; /* RSNXE IE cap flag, refer to 802.11.h */ } rsn_ie_info_t; #endif /* RSN_IE_INFO_STRUCT_RELOCATED */ -#ifdef BCMWAPI_WAI -#define WAPI_CAP_PREAUTH RSN_CAP_PREAUTH - -/* Other WAI definition */ -#define WAPI_WAI_REQUEST 0x00F1 -#define WAPI_UNICAST_REKEY 0x00F2 -#define WAPI_STA_AGING 0x00F3 -#define WAPI_MUTIL_REKEY 0x00F4 -#define WAPI_STA_STATS 0x00F5 - -#define WAPI_USK_REKEY_COUNT 0x4000000 /* 0xA00000 */ -#define WAPI_MSK_REKEY_COUNT 0x4000000 /* 0xA00000 */ -#endif /* BCMWAPI_WAI */ - /* This marks the end of a packed structure section. */ #include diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wps.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wps.h deleted file mode 100755 index 81009bac301b..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wps.h +++ /dev/null @@ -1,379 +0,0 @@ -/* - * WPS IE definitions - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ - -#ifndef _WPS_ -#define _WPS_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Data Element Definitions */ -#define WPS_ID_AP_CHANNEL 0x1001 -#define WPS_ID_ASSOC_STATE 0x1002 -#define WPS_ID_AUTH_TYPE 0x1003 -#define WPS_ID_AUTH_TYPE_FLAGS 0x1004 -#define WPS_ID_AUTHENTICATOR 0x1005 -#define WPS_ID_CONFIG_METHODS 0x1008 -#define WPS_ID_CONFIG_ERROR 0x1009 -#define WPS_ID_CONF_URL4 0x100A -#define WPS_ID_CONF_URL6 0x100B -#define WPS_ID_CONN_TYPE 0x100C -#define WPS_ID_CONN_TYPE_FLAGS 0x100D -#define WPS_ID_CREDENTIAL 0x100E -#define WPS_ID_DEVICE_NAME 0x1011 -#define WPS_ID_DEVICE_PWD_ID 0x1012 -#define WPS_ID_E_HASH1 0x1014 -#define WPS_ID_E_HASH2 0x1015 -#define WPS_ID_E_SNONCE1 0x1016 -#define WPS_ID_E_SNONCE2 0x1017 -#define WPS_ID_ENCR_SETTINGS 0x1018 -#define WPS_ID_ENCR_TYPE 0x100F -#define WPS_ID_ENCR_TYPE_FLAGS 0x1010 -#define WPS_ID_ENROLLEE_NONCE 0x101A -#define WPS_ID_FEATURE_ID 0x101B -#define WPS_ID_IDENTITY 0x101C -#define WPS_ID_IDENTITY_PROOF 0x101D -#define WPS_ID_KEY_WRAP_AUTH 0x101E -#define WPS_ID_KEY_IDENTIFIER 0x101F -#define WPS_ID_MAC_ADDR 0x1020 -#define WPS_ID_MANUFACTURER 0x1021 -#define WPS_ID_MSG_TYPE 0x1022 -#define WPS_ID_MODEL_NAME 0x1023 -#define WPS_ID_MODEL_NUMBER 0x1024 -#define WPS_ID_NW_INDEX 0x1026 -#define WPS_ID_NW_KEY 0x1027 -#define WPS_ID_NW_KEY_INDEX 0x1028 -#define WPS_ID_NEW_DEVICE_NAME 0x1029 -#define WPS_ID_NEW_PWD 0x102A -#define WPS_ID_OOB_DEV_PWD 0x102C -#define WPS_ID_OS_VERSION 0x102D -#define WPS_ID_POWER_LEVEL 0x102F -#define WPS_ID_PSK_CURRENT 0x1030 -#define WPS_ID_PSK_MAX 0x1031 -#define WPS_ID_PUBLIC_KEY 0x1032 -#define WPS_ID_RADIO_ENABLED 0x1033 -#define WPS_ID_REBOOT 0x1034 -#define WPS_ID_REGISTRAR_CURRENT 0x1035 -#define WPS_ID_REGISTRAR_ESTBLSHD 0x1036 -#define WPS_ID_REGISTRAR_LIST 0x1037 -#define WPS_ID_REGISTRAR_MAX 0x1038 -#define WPS_ID_REGISTRAR_NONCE 0x1039 -#define WPS_ID_REQ_TYPE 0x103A -#define WPS_ID_RESP_TYPE 0x103B -#define WPS_ID_RF_BAND 0x103C -#define WPS_ID_R_HASH1 0x103D -#define WPS_ID_R_HASH2 0x103E -#define WPS_ID_R_SNONCE1 0x103F -#define WPS_ID_R_SNONCE2 0x1040 -#define WPS_ID_SEL_REGISTRAR 0x1041 -#define WPS_ID_SERIAL_NUM 0x1042 -#define WPS_ID_SC_STATE 0x1044 -#define WPS_ID_SSID 0x1045 -#define WPS_ID_TOT_NETWORKS 0x1046 -#define WPS_ID_UUID_E 0x1047 -#define WPS_ID_UUID_R 0x1048 -#define WPS_ID_VENDOR_EXT 0x1049 -#define WPS_ID_VERSION 0x104A -#define WPS_ID_X509_CERT_REQ 0x104B -#define WPS_ID_X509_CERT 0x104C -#define WPS_ID_EAP_IDENTITY 0x104D -#define WPS_ID_MSG_COUNTER 0x104E -#define WPS_ID_PUBKEY_HASH 0x104F -#define WPS_ID_REKEY_KEY 0x1050 -#define WPS_ID_KEY_LIFETIME 0x1051 -#define WPS_ID_PERM_CFG_METHODS 0x1052 -#define WPS_ID_SEL_REG_CFG_METHODS 0x1053 -#define WPS_ID_PRIM_DEV_TYPE 0x1054 -#define WPS_ID_SEC_DEV_TYPE_LIST 0x1055 -#define WPS_ID_PORTABLE_DEVICE 0x1056 -#define WPS_ID_AP_SETUP_LOCKED 0x1057 -#define WPS_ID_APP_LIST 0x1058 -#define WPS_ID_EAP_TYPE 0x1059 -#define WPS_ID_INIT_VECTOR 0x1060 -#define WPS_ID_KEY_PROVIDED_AUTO 0x1061 -#define WPS_ID_8021X_ENABLED 0x1062 -#define WPS_ID_WEP_TRANSMIT_KEY 0x1064 -#define WPS_ID_REQ_DEV_TYPE 0x106A - -/* WSC 2.0, WFA Vendor Extension Subelements */ -#define WFA_VENDOR_EXT_ID "\x00\x37\x2A" -#define WPS_WFA_SUBID_VERSION2 0x00 -#define WPS_WFA_SUBID_AUTHORIZED_MACS 0x01 -#define WPS_WFA_SUBID_NW_KEY_SHAREABLE 0x02 -#define WPS_WFA_SUBID_REQ_TO_ENROLL 0x03 -#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME 0x04 -#define WPS_WFA_SUBID_REG_CFG_METHODS 0x05 - -/* WCN-NET Windows Rally Vertical Pairing Vendor Extensions */ -#define MS_VENDOR_EXT_ID "\x00\x01\x37" -#define WPS_MS_ID_VPI 0x1001 /* Vertical Pairing Identifier TLV */ -#define WPS_MS_ID_TRANSPORT_UUID 0x1002 /* Transport UUID TLV */ - -/* Vertical Pairing Identifier TLV Definitions */ -#define WPS_MS_VPI_TRANSPORT_NONE 0x00 /* None */ -#define WPS_MS_VPI_TRANSPORT_DPWS 0x01 /* Devices Profile for Web Services */ -#define WPS_MS_VPI_TRANSPORT_UPNP 0x02 /* uPnP */ -#define WPS_MS_VPI_TRANSPORT_SDNWS 0x03 /* Secure Devices Profile for Web Services */ -#define WPS_MS_VPI_NO_PROFILE_REQ 0x00 /* Wi-Fi profile not requested. - * Not supported in Windows 7 - */ -#define WPS_MS_VPI_PROFILE_REQ 0x01 /* Wi-Fi profile requested. */ - -/* sizes of the fixed size elements */ -#define WPS_ID_AP_CHANNEL_S 2 -#define WPS_ID_ASSOC_STATE_S 2 -#define WPS_ID_AUTH_TYPE_S 2 -#define WPS_ID_AUTH_TYPE_FLAGS_S 2 -#define WPS_ID_AUTHENTICATOR_S 8 -#define WPS_ID_CONFIG_METHODS_S 2 -#define WPS_ID_CONFIG_ERROR_S 2 -#define WPS_ID_CONN_TYPE_S 1 -#define WPS_ID_CONN_TYPE_FLAGS_S 1 -#define WPS_ID_DEVICE_PWD_ID_S 2 -#define WPS_ID_ENCR_TYPE_S 2 -#define WPS_ID_ENCR_TYPE_FLAGS_S 2 -#define WPS_ID_FEATURE_ID_S 4 -#define WPS_ID_MAC_ADDR_S 6 -#define WPS_ID_MSG_TYPE_S 1 -#define WPS_ID_SC_STATE_S 1 -#define WPS_ID_RF_BAND_S 1 -#define WPS_ID_OS_VERSION_S 4 -#define WPS_ID_VERSION_S 1 -#define WPS_ID_SEL_REGISTRAR_S 1 -#define WPS_ID_SEL_REG_CFG_METHODS_S 2 -#define WPS_ID_REQ_TYPE_S 1 -#define WPS_ID_RESP_TYPE_S 1 -#define WPS_ID_AP_SETUP_LOCKED_S 1 - -/* WSC 2.0, WFA Vendor Extension Subelements */ -#define WPS_WFA_SUBID_VERSION2_S 1 -#define WPS_WFA_SUBID_NW_KEY_SHAREABLE_S 1 -#define WPS_WFA_SUBID_REQ_TO_ENROLL_S 1 -#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME_S 1 -#define WPS_WFA_SUBID_REG_CFG_METHODS_S 2 - -/* Association states */ -#define WPS_ASSOC_NOT_ASSOCIATED 0 -#define WPS_ASSOC_CONN_SUCCESS 1 -#define WPS_ASSOC_CONFIG_FAIL 2 -#define WPS_ASSOC_ASSOC_FAIL 3 -#define WPS_ASSOC_IP_FAIL 4 - -/* Authentication types */ -#define WPS_AUTHTYPE_OPEN 0x0001 -#define WPS_AUTHTYPE_WPAPSK 0x0002 /* Deprecated in WSC 2.0 */ -#define WPS_AUTHTYPE_SHARED 0x0004 /* Deprecated in WSC 2.0 */ -#define WPS_AUTHTYPE_WPA 0x0008 /* Deprecated in WSC 2.0 */ -#define WPS_AUTHTYPE_WPA2 0x0010 -#define WPS_AUTHTYPE_WPA2PSK 0x0020 - -/* Config methods */ -#define WPS_CONFMET_USBA 0x0001 /* Deprecated in WSC 2.0 */ -#define WPS_CONFMET_ETHERNET 0x0002 /* Deprecated in WSC 2.0 */ -#define WPS_CONFMET_LABEL 0x0004 -#define WPS_CONFMET_DISPLAY 0x0008 -#define WPS_CONFMET_EXT_NFC_TOK 0x0010 -#define WPS_CONFMET_INT_NFC_TOK 0x0020 -#define WPS_CONFMET_NFC_INTF 0x0040 -#define WPS_CONFMET_PBC 0x0080 -#define WPS_CONFMET_KEYPAD 0x0100 -/* WSC 2.0 */ -#define WPS_CONFMET_VIRT_PBC 0x0280 -#define WPS_CONFMET_PHY_PBC 0x0480 -#define WPS_CONFMET_VIRT_DISPLAY 0x2008 -#define WPS_CONFMET_PHY_DISPLAY 0x4008 - -/* WPS error messages */ -#define WPS_ERROR_NO_ERROR 0 -#define WPS_ERROR_OOB_INT_READ_ERR 1 -#define WPS_ERROR_DECRYPT_CRC_FAIL 2 -#define WPS_ERROR_CHAN24_NOT_SUPP 3 -#define WPS_ERROR_CHAN50_NOT_SUPP 4 -#define WPS_ERROR_SIGNAL_WEAK 5 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_NW_AUTH_FAIL 6 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_NW_ASSOC_FAIL 7 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_NO_DHCP_RESP 8 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_FAILED_DHCP_CONF 9 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_IP_ADDR_CONFLICT 10 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_FAIL_CONN_REGISTRAR 11 -#define WPS_ERROR_MULTI_PBC_DETECTED 12 -#define WPS_ERROR_ROGUE_SUSPECTED 13 -#define WPS_ERROR_DEVICE_BUSY 14 -#define WPS_ERROR_SETUP_LOCKED 15 -#define WPS_ERROR_MSG_TIMEOUT 16 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_REG_SESSION_TIMEOUT 17 /* Deprecated in WSC 2.0 */ -#define WPS_ERROR_DEV_PWD_AUTH_FAIL 18 -#define WPS_ERROR_60GHZ_NOT_SUPPORT 19 -#define WPS_ERROR_PKH_MISMATCH 20 /* Public Key Hash Mismatch */ - -/* Connection types */ -#define WPS_CONNTYPE_ESS 0x01 -#define WPS_CONNTYPE_IBSS 0x02 - -/* Device password ID */ -#define WPS_DEVICEPWDID_DEFAULT 0x0000 -#define WPS_DEVICEPWDID_USER_SPEC 0x0001 -#define WPS_DEVICEPWDID_MACHINE_SPEC 0x0002 -#define WPS_DEVICEPWDID_REKEY 0x0003 -#define WPS_DEVICEPWDID_PUSH_BTN 0x0004 -#define WPS_DEVICEPWDID_REG_SPEC 0x0005 -#define WPS_DEVICEPWDID_IBSS 0x0006 -#define WPS_DEVICEPWDID_NFC_CHO 0x0007 /* NFC-Connection-Handover */ -#define WPS_DEVICEPWDID_WFDS 0x0008 /* Wi-Fi Direct Services Specification */ - -/* Encryption type */ -#define WPS_ENCRTYPE_NONE 0x0001 -#define WPS_ENCRTYPE_WEP 0x0002 /* Deprecated in WSC 2.0 */ -#define WPS_ENCRTYPE_TKIP 0x0004 /* Deprecated in version 2.0. TKIP can only - * be advertised on the AP when Mixed Mode - * is enabled (Encryption Type is 0x000c). - */ -#define WPS_ENCRTYPE_AES 0x0008 - -/* WPS Message Types */ -#define WPS_ID_BEACON 0x01 -#define WPS_ID_PROBE_REQ 0x02 -#define WPS_ID_PROBE_RESP 0x03 -#define WPS_ID_MESSAGE_M1 0x04 -#define WPS_ID_MESSAGE_M2 0x05 -#define WPS_ID_MESSAGE_M2D 0x06 -#define WPS_ID_MESSAGE_M3 0x07 -#define WPS_ID_MESSAGE_M4 0x08 -#define WPS_ID_MESSAGE_M5 0x09 -#define WPS_ID_MESSAGE_M6 0x0A -#define WPS_ID_MESSAGE_M7 0x0B -#define WPS_ID_MESSAGE_M8 0x0C -#define WPS_ID_MESSAGE_ACK 0x0D -#define WPS_ID_MESSAGE_NACK 0x0E -#define WPS_ID_MESSAGE_DONE 0x0F - -/* WSP private ID for local use */ -#define WPS_PRIVATE_ID_IDENTITY (WPS_ID_MESSAGE_DONE + 1) -#define WPS_PRIVATE_ID_WPS_START (WPS_ID_MESSAGE_DONE + 2) -#define WPS_PRIVATE_ID_FAILURE (WPS_ID_MESSAGE_DONE + 3) -#define WPS_PRIVATE_ID_FRAG (WPS_ID_MESSAGE_DONE + 4) -#define WPS_PRIVATE_ID_FRAG_ACK (WPS_ID_MESSAGE_DONE + 5) -#define WPS_PRIVATE_ID_EAPOL_START (WPS_ID_MESSAGE_DONE + 6) - -/* Device Type categories for primary and secondary device types */ -#define WPS_DEVICE_TYPE_CAT_COMPUTER 1 -#define WPS_DEVICE_TYPE_CAT_INPUT_DEVICE 2 -#define WPS_DEVICE_TYPE_CAT_PRINTER 3 -#define WPS_DEVICE_TYPE_CAT_CAMERA 4 -#define WPS_DEVICE_TYPE_CAT_STORAGE 5 -#define WPS_DEVICE_TYPE_CAT_NW_INFRA 6 -#define WPS_DEVICE_TYPE_CAT_DISPLAYS 7 -#define WPS_DEVICE_TYPE_CAT_MM_DEVICES 8 -#define WPS_DEVICE_TYPE_CAT_GAME_DEVICES 9 -#define WPS_DEVICE_TYPE_CAT_TELEPHONE 10 -#define WPS_DEVICE_TYPE_CAT_AUDIO_DEVICES 11 /* WSC 2.0 */ - -/* Device Type sub categories for primary and secondary device types */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_PC 1 -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_SERVER 2 -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MEDIA_CTR 3 -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_UM_PC 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NOTEBOOK 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_DESKTOP 6 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MID 7 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NETBOOK 8 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_Keyboard 1 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_MOUSE 2 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_JOYSTICK 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_TRACKBALL 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_GAM_CTRL 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_REMOTE 6 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_TOUCHSCREEN 7 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_BIO_READER 8 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_INP_BAR_READER 9 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_PRINTER 1 -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_SCANNER 2 -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_FAX 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_COPIER 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_ALLINONE 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_CAM_DGTL_STILL 1 -#define WPS_DEVICE_TYPE_SUB_CAT_CAM_VIDEO_CAM 2 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_CAM_WEB_CAM 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_CAM_SECU_CAM 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_STOR_NAS 1 -#define WPS_DEVICE_TYPE_SUB_CAT_NW_AP 1 -#define WPS_DEVICE_TYPE_SUB_CAT_NW_ROUTER 2 -#define WPS_DEVICE_TYPE_SUB_CAT_NW_SWITCH 3 -#define WPS_DEVICE_TYPE_SUB_CAT_NW_GATEWAY 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_NW_BRIDGE 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_DISP_TV 1 -#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PIC_FRAME 2 -#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PROJECTOR 3 -#define WPS_DEVICE_TYPE_SUB_CAT_DISP_MONITOR 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_MM_DAR 1 -#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVR 2 -#define WPS_DEVICE_TYPE_SUB_CAT_MM_MCX 3 -#define WPS_DEVICE_TYPE_SUB_CAT_MM_STB 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_MM_MS_ME 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVP 6 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX 1 -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX_360 2 -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PS 3 -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_GC 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PGD 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_WM 1 -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PSM 2 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PDM 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SSM 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SDM 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_TUNER 1 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_SPEAKERS 2 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_PMP 3 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HEADSET 4 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HPHONE 5 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_MPHONE 6 /* WSC 2.0 */ -#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HTS 7 /* WSC 2.0 */ - -/* Device request/response type */ -#define WPS_MSGTYPE_ENROLLEE_INFO_ONLY 0x00 -#define WPS_MSGTYPE_ENROLLEE_OPEN_8021X 0x01 -#define WPS_MSGTYPE_REGISTRAR 0x02 -#define WPS_MSGTYPE_AP_WLAN_MGR 0x03 - -/* RF Band */ -#define WPS_RFBAND_24GHZ 0x01 -#define WPS_RFBAND_50GHZ 0x02 - -/* Simple Config state */ -#define WPS_SCSTATE_UNCONFIGURED 0x01 -#define WPS_SCSTATE_CONFIGURED 0x02 -#define WPS_SCSTATE_OFF 11 - -/* WPS Vendor extension key */ -#define WPS_OUI_HEADER_LEN 2 -#define WPS_OUI_HEADER_SIZE 4 -#define WPS_OUI_FIXED_HEADER_OFF 16 -#define WPS_WFA_SUBID_V2_OFF 3 -#define WPS_WFA_V2_OFF 5 - -#ifdef __cplusplus -} -#endif - -#endif /* _WPS_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c old mode 100755 new mode 100644 index 621d3dae5dbc..fe9b9511cc65 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -33,6 +33,9 @@ #endif /* __ARM_ARCH_7A__ && !DHD_USE_COHERENT_MEM_FOR_RING */ #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) +#include +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) */ #include #include @@ -43,10 +46,6 @@ #include #endif -#if defined(BCMASSERT_LOG) && !defined(OEM_ANDROID) -#include -#endif - #include #ifdef BCM_OBJECT_TRACE @@ -58,11 +57,11 @@ #define DUMPBUFSZ 1024 -#ifdef CUSTOMER_HW4_DEBUG +#if defined(CUSTOMER_HW7_DEBUG) uint32 g_assert_type = 1; /* By Default not cause Kernel Panic */ #else uint32 g_assert_type = 0; /* By Default Kernel Panic */ -#endif /* CUSTOMER_HW4_DEBUG */ +#endif module_param(g_assert_type, int, 0); @@ -85,92 +84,6 @@ static void osl_dma_lock_init(osl_t *osh); #define DMA_LOCK_INIT(osh) do { /* noop */ } while(0) #endif /* USE_DMA_LOCK */ -static int16 linuxbcmerrormap[] = -{ 0, /* 0 */ - -EINVAL, /* BCME_ERROR */ - -EINVAL, /* BCME_BADARG */ - -EINVAL, /* BCME_BADOPTION */ - -EINVAL, /* BCME_NOTUP */ - -EINVAL, /* BCME_NOTDOWN */ - -EINVAL, /* BCME_NOTAP */ - -EINVAL, /* BCME_NOTSTA */ - -EINVAL, /* BCME_BADKEYIDX */ - -EINVAL, /* BCME_RADIOOFF */ - -EINVAL, /* BCME_NOTBANDLOCKED */ - -EINVAL, /* BCME_NOCLK */ - -EINVAL, /* BCME_BADRATESET */ - -EINVAL, /* BCME_BADBAND */ - -E2BIG, /* BCME_BUFTOOSHORT */ - -E2BIG, /* BCME_BUFTOOLONG */ - -EBUSY, /* BCME_BUSY */ - -EINVAL, /* BCME_NOTASSOCIATED */ - -EINVAL, /* BCME_BADSSIDLEN */ - -EINVAL, /* BCME_OUTOFRANGECHAN */ - -EINVAL, /* BCME_BADCHAN */ - -EFAULT, /* BCME_BADADDR */ - -ENOMEM, /* BCME_NORESOURCE */ - -EOPNOTSUPP, /* BCME_UNSUPPORTED */ - -EMSGSIZE, /* BCME_BADLENGTH */ - -EINVAL, /* BCME_NOTREADY */ - -EPERM, /* BCME_EPERM */ - -ENOMEM, /* BCME_NOMEM */ - -EINVAL, /* BCME_ASSOCIATED */ - -ERANGE, /* BCME_RANGE */ - -EINVAL, /* BCME_NOTFOUND */ - -EINVAL, /* BCME_WME_NOT_ENABLED */ - -EINVAL, /* BCME_TSPEC_NOTFOUND */ - -EINVAL, /* BCME_ACM_NOTSUPPORTED */ - -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ - -EIO, /* BCME_SDIO_ERROR */ - -ENODEV, /* BCME_DONGLE_DOWN */ - -EINVAL, /* BCME_VERSION */ - -EIO, /* BCME_TXFAIL */ - -EIO, /* BCME_RXFAIL */ - -ENODEV, /* BCME_NODEVICE */ - -EINVAL, /* BCME_NMODE_DISABLED */ - -ENODATA, /* BCME_NONRESIDENT */ - -EINVAL, /* BCME_SCANREJECT */ - -EINVAL, /* BCME_USAGE_ERROR */ - -EIO, /* BCME_IOCTL_ERROR */ - -EIO, /* BCME_SERIAL_PORT_ERR */ - -EOPNOTSUPP, /* BCME_DISABLED, BCME_NOTENABLED */ - -EIO, /* BCME_DECERR */ - -EIO, /* BCME_ENCERR */ - -EIO, /* BCME_MICERR */ - -ERANGE, /* BCME_REPLAY */ - -EINVAL, /* BCME_IE_NOTFOUND */ - -EINVAL, /* BCME_DATA_NOTFOUND */ - -EINVAL, /* BCME_NOT_GC */ - -EINVAL, /* BCME_PRS_REQ_FAILED */ - -EINVAL, /* BCME_NO_P2P_SE */ - -EINVAL, /* BCME_NOA_PND */ - -EINVAL, /* BCME_FRAG_Q_FAILED */ - -EINVAL, /* BCME_GET_AF_FAILED */ - -EINVAL, /* BCME_MSCH_NOTREADY */ - -EINVAL, /* BCME_IOV_LAST_CMD */ - -EINVAL, /* BCME_MINIPMU_CAL_FAIL */ - -EINVAL, /* BCME_RCAL_FAIL */ - -EINVAL, /* BCME_LPF_RCCAL_FAIL */ - -EINVAL, /* BCME_DACBUF_RCCAL_FAIL */ - -EINVAL, /* BCME_VCOCAL_FAIL */ - -EINVAL, /* BCME_BANDLOCKED */ - -EINVAL, /* BCME_BAD_IE_DATA */ - -EINVAL, /* BCME_REG_FAILED */ - -EINVAL, /* BCME_NOCHAN */ - -EINVAL, /* BCME_PKTTOSS */ - -EINVAL, /* BCME_DNGL_DEVRESET */ - -EINVAL, /* BCME_ROAM */ - -EOPNOTSUPP, /* BCME_NO_SIG_FILE */ - -/* When an new error code is added to bcmutils.h, add os - * specific error translation here as well - */ -/* check if BCME_LAST changed since the last time this function was updated */ -#if BCME_LAST != BCME_NO_SIG_FILE -#error "You need to add a OS error translation in the linuxbcmerrormap \ - for new error code defined in bcmutils.h" -#endif -}; uint lmtest = FALSE; #ifdef DHD_MAP_LOGGING @@ -200,16 +113,16 @@ osl_dma_map_dump(osl_t *osh) osl_get_localtime(&ts_sec, &ts_usec); if (map_log && unmap_log) { - printf("%s: map_idx=%d unmap_idx=%d " + OSL_PRINT(("%s: map_idx=%d unmap_idx=%d " "current time=[%5lu.%06lu]\n", __FUNCTION__, map_log->idx, unmap_log->idx, (unsigned long)ts_sec, - (unsigned long)ts_usec); - printf("%s: dhd_map_log(pa)=0x%llx size=%d," + (unsigned long)ts_usec)); + OSL_PRINT(("%s: dhd_map_log(pa)=0x%llx size=%d," " dma_unmap_log(pa)=0x%llx size=%d\n", __FUNCTION__, (uint64)__virt_to_phys((ulong)(map_log->map)), (uint32)(sizeof(dhd_map_item_t) * map_log->items), (uint64)__virt_to_phys((ulong)(unmap_log->map)), - (uint32)(sizeof(dhd_map_item_t) * unmap_log->items)); + (uint32)(sizeof(dhd_map_item_t) * unmap_log->items))); } } @@ -253,7 +166,7 @@ osl_dma_map_logging(osl_t *osh, void *handle, dmaaddr_t pa, uint32 len) uint32 idx; if (log == NULL) { - printf("%s: log is NULL\n", __FUNCTION__); + OSL_PRINT(("%s: log is NULL\n", __FUNCTION__)); return; } @@ -275,7 +188,7 @@ osl_error(int bcmerror) bcmerror = BCME_ERROR; /* Array bounds covered by ASSERT in osl_attach */ - return linuxbcmerrormap[-bcmerror]; + return linux_get_errmap(bcmerror); } osl_t * @@ -295,7 +208,7 @@ osl_attach(void *pdev, uint bustype, bool pkttag if (!(osh = kmalloc(sizeof(osl_t), flags))) return osh; - ASSERT(osh); + ASSERT_NULL(osh); bzero(osh, sizeof(osl_t)); @@ -322,8 +235,7 @@ osl_attach(void *pdev, uint bustype, bool pkttag atomic_add(1, &osh->cmn->refcount); bcm_object_trace_init(); - /* Check that error map has the right number of entries in it */ - ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1)); + osh->failed = 0; osh->pdev = pdev; osh->pub.pkttag = pkttag; @@ -365,12 +277,12 @@ osl_attach(void *pdev, uint bustype, bool pkttag #ifdef DHD_MAP_LOGGING osh->dhd_map_log = osl_dma_map_log_init(DHD_MAP_LOG_SIZE); if (osh->dhd_map_log == NULL) { - printf("%s: Failed to alloc dhd_map_log\n", __FUNCTION__); + OSL_PRINT(("%s: Failed to alloc dhd_map_log\n", __FUNCTION__)); } osh->dhd_unmap_log = osl_dma_map_log_init(DHD_MAP_LOG_SIZE); if (osh->dhd_unmap_log == NULL) { - printf("%s: Failed to alloc dhd_unmap_log\n", __FUNCTION__); + OSL_PRINT(("%s: Failed to alloc dhd_unmap_log\n", __FUNCTION__)); } #endif /* DHD_MAP_LOGGING */ @@ -387,16 +299,6 @@ void* osl_get_bus_handle(osl_t *osh) return osh->bus_handle; } -#if defined(AXI_TIMEOUTS_NIC) -void osl_set_bpt_cb(osl_t *osh, void *bpt_cb, void *bpt_ctx) -{ - if (osh) { - osh->bpt_cb = (bpt_cb_fn)bpt_cb; - osh->sih = bpt_ctx; - } -} -#endif /* AXI_TIMEOUTS_NIC */ - void osl_detach(osl_t *osh) { @@ -408,10 +310,10 @@ osl_detach(osl_t *osh) static char dumpbuf[DUMPBUFSZ]; struct bcmstrbuf b; - printf("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)); + OSL_PRINT(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh))); bcm_binit(&b, dumpbuf, DUMPBUFSZ); MALLOC_DUMP(osh, &b); - printf("%s", b.origbuf); + OSL_PRINT(("%s", b.origbuf)); } #endif @@ -478,7 +380,8 @@ osl_pci_read_config(osl_t *osh, uint offset, uint size) uint val = 0; uint retry = PCI_CFG_RETRY; /* PR15065: faulty cardbus controller bug */ - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); /* only 4byte access supported */ ASSERT(size == 4); @@ -491,8 +394,8 @@ osl_pci_read_config(osl_t *osh, uint offset, uint size) #ifdef BCMDBG if (retry < PCI_CFG_RETRY) - printf("PCI CONFIG READ access to %d required %d retries\n", offset, - (PCI_CFG_RETRY - retry)); + OSL_PRINT(("PCI CONFIG READ access to %d required %d retries\n", offset, + (PCI_CFG_RETRY - retry))); #endif /* BCMDBG */ return (val); @@ -503,17 +406,20 @@ osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) { uint retry = PCI_CFG_RETRY; /* PR15065: faulty cardbus controller bug */ - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); /* only 4byte access supported */ ASSERT(size == 4); - +#ifdef DHD_DEBUG_REG_DUMP + OSL_PRINT(("###### W_CFG : 0x%x 0x%x #######\n", offset, val)); +#endif /* DHD_DEBUG_REG_DUMP */ do { pci_write_config_dword(osh->pdev, offset, val); /* PR15065: PCI_BAR0_WIN is believed to be the only pci cfg write that can occur * when dma activity is possible */ - if (offset != PCI_BAR0_WIN) + if (offset != PCI_BAR0_WIN && offset != PCI_BAR1_WIN) break; if (osl_pci_read_config(osh, offset, size) == val) break; @@ -521,8 +427,8 @@ osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) #ifdef BCMDBG if (retry < PCI_CFG_RETRY) - printf("PCI CONFIG WRITE access to %d required %d retries\n", offset, - (PCI_CFG_RETRY - retry)); + OSL_PRINT(("PCI CONFIG WRITE access to %d required %d retries\n", offset, + (PCI_CFG_RETRY - retry))); #endif /* BCMDBG */ } @@ -531,7 +437,9 @@ osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) uint osl_pci_bus(osl_t *osh) { - ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC) + ASSERT_NULL(osh->pdev); #if defined(__ARM_ARCH_7A__) return pci_domain_nr(((struct pci_dev *)osh->pdev)->bus); @@ -544,7 +452,9 @@ osl_pci_bus(osl_t *osh) uint osl_pci_slot(osl_t *osh) { - ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); + ASSERT_NULL(osh->pdev); #if defined(__ARM_ARCH_7A__) return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn) + 1; @@ -557,7 +467,9 @@ osl_pci_slot(osl_t *osh) uint osl_pcie_domain(osl_t *osh) { - ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); + ASSERT_NULL(osh->pdev); return pci_domain_nr(((struct pci_dev *)osh->pdev)->bus); } @@ -566,7 +478,9 @@ osl_pcie_domain(osl_t *osh) uint osl_pcie_bus(osl_t *osh) { - ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); + ASSERT_NULL(osh->pdev); return ((struct pci_dev *)osh->pdev)->bus->number; } @@ -575,21 +489,14 @@ osl_pcie_bus(osl_t *osh) struct pci_dev * osl_pci_device(osl_t *osh) { - ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); + ASSERT_NULL(osh->pdev); return osh->pdev; } #endif -#ifdef BCMDBG_MEM -/* In BCMDBG_MEM configurations osl_malloc is only used internally in - * the implementation of osl_debug_malloc. Because we are using the GCC - * -Wstrict-prototypes compile option, we must always have a prototype - * for a global/external function. So make osl_malloc static in - * the BCMDBG_MEM case. - */ -static -#endif void * osl_malloc(osl_t *osh, uint size) { @@ -617,7 +524,7 @@ osl_malloc(osl_t *osh, uint size) if (i == STATIC_BUF_MAX_NUM) { OSL_STATIC_BUF_UNLOCK(&bcm_static_buf->static_lock, irq_flags); - printf("all static buff in use!\n"); + OSL_PRINT(("all static buff in use!\n")); goto original; } @@ -646,7 +553,6 @@ original: return (addr); } -#ifndef BCMDBG_MEM void * osl_mallocz(osl_t *osh, uint size) { @@ -660,17 +566,47 @@ osl_mallocz(osl_t *osh, uint size) return ptr; } -#endif -#ifdef BCMDBG_MEM -/* In BCMDBG_MEM configurations osl_mfree is only used internally in - * the implementation of osl_debug_mfree. Because we are using the GCC - * -Wstrict-prototypes compile option, we must always have a prototype - * for a global/external function. So make osl_mfree static in - * the BCMDBG_MEM case. - */ -static +#if defined(L1_CACHE_BYTES) +#define DMA_PAD (L1_CACHE_BYTES) +#else +#define DMA_PAD (128u) #endif +void * +osl_dma_mallocz(osl_t *osh, uint size, uint *dmable_size) +{ + void *addr = NULL; + gfp_t flags = 0; + uint16 align = 0; + uint32 dmapad = 0; + + if (osh) + ASSERT(osh->magic == OS_HANDLE_MAGIC); + if (!size || !dmable_size) + return NULL; + + *dmable_size = size; + align = *dmable_size % DMA_PAD; + dmapad = align ? (DMA_PAD - align) : 0; + *dmable_size += dmapad; + + flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; + flags |= GFP_DMA; + addr = kmalloc(*dmable_size, flags); + if (addr != NULL) { + bzero(addr, *dmable_size); + if (osh && osh->cmn) { + atomic_add(*dmable_size, &osh->cmn->malloced); + } + } else { + if (osh) { + osh->failed++; + } + } + + return addr; +} + void osl_mfree(osl_t *osh, void *addr, uint size) { @@ -712,6 +648,23 @@ osl_mfree(osl_t *osh, void *addr, uint size) kfree(addr); } +void +osl_dma_mfree(osl_t *osh, void *addr, uint size) +{ + if (addr == NULL) { + return; + } + + if (osh && osh->cmn) { + ASSERT(osh->magic == OS_HANDLE_MAGIC); + ASSERT(size <= osl_malloced(osh)); + atomic_sub(size, &osh->cmn->malloced); + } + + kfree(addr); + addr = NULL; +} + #ifdef BCMDBG_MEM /* In BCMDBG_MEM configurations osl_vmalloc is only used internally in * the implementation of osl_debug_vmalloc. Because we are using the GCC @@ -778,10 +731,88 @@ osl_vmfree(osl_t *osh, void *addr, uint size) vfree(addr); } +#ifdef BCMDBG_MEM +/* In BCMDBG_MEM configurations osl_kvmalloc is only used internally in + * the implementation of osl_debug_kvmalloc. Because we are using the GCC + * -Wstrict-prototypes compile option, we must always have a prototype + * for a global/external function. So make osl_kvmalloc static in + * the BCMDBG_MEM case. + */ +static +#endif +void * +osl_kvmalloc(osl_t *osh, uint size) +{ + void *addr; + gfp_t flags; + + /* only ASSERT if osh is defined */ + if (osh) + ASSERT(osh->magic == OS_HANDLE_MAGIC); + + flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) + if ((addr = kmalloc(size, flags)) == NULL) { +#else + if ((addr = kvmalloc(size, flags)) == NULL) { +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */ + if (osh) + osh->failed++; + return (NULL); + } + if (osh && osh->cmn) + atomic_add(size, &osh->cmn->malloced); + + return (addr); +} + +#ifndef BCMDBG_MEM +void * +osl_kvmallocz(osl_t *osh, uint size) +{ + void *ptr; + + ptr = osl_kvmalloc(osh, size); + + if (ptr != NULL) { + bzero(ptr, size); + } + + return ptr; +} +#endif + +#ifdef BCMDBG_MEM +/* In BCMDBG_MEM configurations osl_kvmfree is only used internally in + * the implementation of osl_debug_kvmfree. Because we are using the GCC + * -Wstrict-prototypes compile option, we must always have a prototype + * for a global/external function. So make osl_kvmfree static in + * the BCMDBG_MEM case. + */ +static +#endif +void +osl_kvmfree(osl_t *osh, void *addr, uint size) +{ + if (osh && osh->cmn) { + ASSERT(osh->magic == OS_HANDLE_MAGIC); + + ASSERT(size <= osl_malloced(osh)); + + atomic_sub(size, &osh->cmn->malloced); + } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) + kfree(addr); +#else + kvfree(addr); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */ +} + uint osl_check_memleak(osl_t *osh) { - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); if (atomic_read(&osh->cmn->refcount) == 1) return (atomic_read(&osh->cmn->malloced)); else @@ -791,14 +822,16 @@ osl_check_memleak(osl_t *osh) uint osl_malloced(osl_t *osh) { - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); return (atomic_read(&osh->cmn->malloced)); } uint osl_malloc_failed(osl_t *osh) { - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); return (osh->failed); } @@ -810,7 +843,8 @@ osl_debug_malloc(osl_t *osh, uint size, int line, const char* file) const char* basename; unsigned long flags = 0; if (!size) { - printf("%s: allocating zero sized mem at %s line %d\n", __FUNCTION__, file, line); + OSL_PRINT(("%s: allocating zero sized mem at %s line %d\n", + __FUNCTION__, file, line)); ASSERT(0); } @@ -877,27 +911,27 @@ osl_debug_mfree(osl_t *osh, void *addr, uint size, int line, const char* file) p = (bcm_mem_link_t *)((int8*)addr - sizeof(bcm_mem_link_t)); if (p->size == 0) { - printf("osl_debug_mfree: double free on addr %p size %d at line %d file %s\n", - addr, size, line, file); + OSL_PRINT(("osl_debug_mfree: double free on addr %p size %d at line %d file %s\n", + addr, size, line, file)); prhex("bcm_mem_link_t", (void *)p, sizeof(*p)); ASSERT(p->size); return; } if (p->size != size) { - printf("%s: dealloca size does not match alloc size\n", __FUNCTION__); - printf("Dealloc addr %p size %d at line %d file %s\n", addr, size, line, file); - printf("Alloc size %d line %d file %s\n", p->size, p->line, p->file); + OSL_PRINT(("%s: dealloca size does not match alloc size\n", __FUNCTION__)); + OSL_PRINT(("Dealloc addr %p size %d at line %d file %s\n", addr, size, line, file)); + OSL_PRINT(("Alloc size %d line %d file %s\n", p->size, p->line, p->file)); prhex("bcm_mem_link_t", (void *)p, sizeof(*p)); ASSERT(p->size == size); return; } if (osh && ((osl_t*)p->osh)->cmn != osh->cmn) { - printf("osl_debug_mfree: alloc osh %p does not match dealloc osh %p\n", - ((osl_t*)p->osh)->cmn, osh->cmn); - printf("Dealloc addr %p size %d at line %d file %s\n", addr, size, line, file); - printf("Alloc size %d line %d file %s\n", p->size, p->line, p->file); + OSL_PRINT(("osl_debug_mfree: alloc osh %p does not match dealloc osh %p\n", + ((osl_t*)p->osh)->cmn, osh->cmn)); + OSL_PRINT(("Dealloc addr %p size %d at line %d file %s\n", addr, size, line, file)); + OSL_PRINT(("Alloc size %d line %d file %s\n", p->size, p->line, p->file)); prhex("bcm_mem_link_t", (void *)p, sizeof(*p)); ASSERT(((osl_t*)p->osh)->cmn == osh->cmn); return; @@ -929,7 +963,8 @@ osl_debug_vmalloc(osl_t *osh, uint size, int line, const char* file) const char* basename; unsigned long flags = 0; if (!size) { - printf("%s: allocating zero sized mem at %s line %d\n", __FUNCTION__, file, line); + OSL_PRINT(("%s: allocating zero sized mem at %s line %d\n", + __FUNCTION__, file, line)); ASSERT(0); } @@ -991,25 +1026,25 @@ osl_debug_vmfree(osl_t *osh, void *addr, uint size, int line, const char* file) ASSERT(osh == NULL || osh->magic == OS_HANDLE_MAGIC); if (p->size == 0) { - printf("osl_debug_mfree: double free on addr %p size %d at line %d file %s\n", - addr, size, line, file); + OSL_PRINT(("osl_debug_mfree: double free on addr %p size %d at line %d file %s\n", + addr, size, line, file)); ASSERT(p->size); return; } if (p->size != size) { - printf("%s: dealloca size does not match alloc size\n", __FUNCTION__); - printf("Dealloc addr %p size %d at line %d file %s\n", addr, size, line, file); - printf("Alloc size %d line %d file %s\n", p->size, p->line, p->file); + OSL_PRINT(("%s: dealloca size does not match alloc size\n", __FUNCTION__)); + OSL_PRINT(("Dealloc addr %p size %d at line %d file %s\n", addr, size, line, file)); + OSL_PRINT(("Alloc size %d line %d file %s\n", p->size, p->line, p->file)); ASSERT(p->size == size); return; } if (osh && ((osl_t*)p->osh)->cmn != osh->cmn) { - printf("osl_debug_mfree: alloc osh %p does not match dealloc osh %p\n", - ((osl_t*)p->osh)->cmn, osh->cmn); - printf("Dealloc addr %p size %d at line %d file %s\n", addr, size, line, file); - printf("Alloc size %d line %d file %s\n", p->size, p->line, p->file); + OSL_PRINT(("osl_debug_mfree: alloc osh %p does not match dealloc osh %p\n", + ((osl_t*)p->osh)->cmn, osh->cmn)); + OSL_PRINT(("Dealloc addr %p size %d at line %d file %s\n", addr, size, line, file)); + OSL_PRINT(("Alloc size %d line %d file %s\n", p->size, p->line, p->file)); ASSERT(((osl_t*)p->osh)->cmn == osh->cmn); return; } @@ -1033,13 +1068,126 @@ osl_debug_vmfree(osl_t *osh, void *addr, uint size, int line, const char* file) osl_vmfree(osh, p, size + sizeof(bcm_mem_link_t)); } +void * +osl_debug_kvmalloc(osl_t *osh, uint size, int line, const char* file) +{ + bcm_mem_link_t *p; + const char* basename; + unsigned long flags = 0; + if (!size) { + OSL_PRINT(("%s: allocating zero sized mem at %s line %d\n", + __FUNCTION__, file, line)); + ASSERT(0); + } + + if ((p = (bcm_mem_link_t*)osl_kvmalloc(osh, sizeof(bcm_mem_link_t) + size)) == NULL) { + return (NULL); + } + + if (osh) { + OSL_MEMLIST_LOCK(&osh->cmn->dbgmem_lock, flags); + } + + p->size = size; + p->line = line; + p->osh = (void *)osh; + + basename = strrchr(file, '/'); + /* skip the '/' */ + if (basename) + basename++; + + if (!basename) + basename = file; + + strlcpy(p->file, basename, sizeof(p->file)); + + /* link this block */ + if (osh) { + p->prev = NULL; + p->next = osh->cmn->dbgvmem_list; + if (p->next) + p->next->prev = p; + osh->cmn->dbgvmem_list = p; + OSL_MEMLIST_UNLOCK(&osh->cmn->dbgmem_lock, flags); + } + + return p + 1; +} + +void * +osl_debug_kvmallocz(osl_t *osh, uint size, int line, const char* file) +{ + void *ptr; + + ptr = osl_debug_kvmalloc(osh, size, line, file); + + if (ptr != NULL) { + bzero(ptr, size); + } + + return ptr; +} + +void +osl_debug_kvmfree(osl_t *osh, void *addr, uint size, int line, const char* file) +{ + bcm_mem_link_t *p = (bcm_mem_link_t *)((int8*)addr - sizeof(bcm_mem_link_t)); + unsigned long flags = 0; + + ASSERT(osh == NULL || osh->magic == OS_HANDLE_MAGIC); + + if (p->size == 0) { + OSL_PRINT(("osl_debug_mfree: double free on addr %p size %d at line %d file %s\n", + addr, size, line, file)); + ASSERT(p->size); + return; + } + + if (p->size != size) { + OSL_PRINT(("%s: dealloca size does not match alloc size\n", __FUNCTION__)); + OSL_PRINT(("Dealloc addr %p size %d at line %d file %s\n", addr, size, line, file)); + OSL_PRINT(("Alloc size %d line %d file %s\n", p->size, p->line, p->file)); + ASSERT(p->size == size); + return; + } + + if (osh && ((osl_t*)p->osh)->cmn != osh->cmn) { + OSL_PRINT(("osl_debug_mfree: alloc osh %p does not match dealloc osh %p\n", + ((osl_t*)p->osh)->cmn, osh->cmn)); + OSL_PRINT(("Dealloc addr %p size %d at line %d file %s\n", addr, size, line, file)); + OSL_PRINT(("Alloc size %d line %d file %s\n", p->size, p->line, p->file)); + ASSERT(((osl_t*)p->osh)->cmn == osh->cmn); + return; + } + + /* unlink this block */ + if (osh && osh->cmn) { + OSL_MEMLIST_LOCK(&osh->cmn->dbgmem_lock, flags); + if (p->prev) + p->prev->next = p->next; + if (p->next) + p->next->prev = p->prev; + if (osh->cmn->dbgvmem_list == p) + osh->cmn->dbgvmem_list = p->next; + p->next = p->prev = NULL; + } + p->size = 0; + + if (osh && osh->cmn) { + OSL_MEMLIST_UNLOCK(&osh->cmn->dbgmem_lock, flags); + } + osl_kvmfree(osh, p, size + sizeof(bcm_mem_link_t)); +} + int osl_debug_memdump(osl_t *osh, struct bcmstrbuf *b) { bcm_mem_link_t *p; unsigned long flags = 0; - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); OSL_MEMLIST_LOCK(&osh->cmn->dbgmem_lock, flags); @@ -1047,15 +1195,15 @@ osl_debug_memdump(osl_t *osh, struct bcmstrbuf *b) if (b != NULL) bcm_bprintf(b, " Address Size File:line\n"); else - printf(" Address Size File:line\n"); + OSL_PRINT((" Address Size File:line\n")); for (p = osh->cmn->dbgmem_list; p; p = p->next) { if (b != NULL) bcm_bprintf(b, "%p %6d %s:%d\n", (char*)p + sizeof(bcm_mem_link_t), p->size, p->file, p->line); else - printk("%p %6d %s:%d\n", (char*)p + sizeof(bcm_mem_link_t), - p->size, p->file, p->line); + OSL_PRINT(("%p %6d %s:%d\n", (char*)p + sizeof(bcm_mem_link_t), + p->size, p->file, p->line)); /* Detects loop-to-self so we don't enter infinite loop */ if (p == p->next) { @@ -1063,8 +1211,8 @@ osl_debug_memdump(osl_t *osh, struct bcmstrbuf *b) bcm_bprintf(b, "WARNING: loop-to-self " "p %p p->next %p\n", p, p->next); else - printk("WARNING: loop-to-self " - "p %p p->next %p\n", p, p->next); + OSL_PRINT(("WARNING: loop-to-self " + "p %p p->next %p\n", p, p->next)); break; } @@ -1074,15 +1222,15 @@ osl_debug_memdump(osl_t *osh, struct bcmstrbuf *b) if (b != NULL) bcm_bprintf(b, "Vmem\n Address Size File:line\n"); else - printf("Vmem\n Address Size File:line\n"); + OSL_PRINT(("Vmem\n Address Size File:line\n")); for (p = osh->cmn->dbgvmem_list; p; p = p->next) { if (b != NULL) bcm_bprintf(b, "%p %6d %s:%d\n", (char*)p + sizeof(bcm_mem_link_t), p->size, p->file, p->line); else - printk("%p %6d %s:%d\n", (char*)p + sizeof(bcm_mem_link_t), - p->size, p->file, p->line); + OSL_PRINT(("%p %6d %s:%d\n", (char*)p + sizeof(bcm_mem_link_t), + p->size, p->file, p->line)); /* Detects loop-to-self so we don't enter infinite loop */ if (p == p->next) { @@ -1090,8 +1238,8 @@ osl_debug_memdump(osl_t *osh, struct bcmstrbuf *b) bcm_bprintf(b, "WARNING: loop-to-self " "p %p p->next %p\n", p, p->next); else - printk("WARNING: loop-to-self " - "p %p p->next %p\n", p, p->next); + OSL_PRINT(("WARNING: loop-to-self " + "p %p p->next %p\n", p, p->next)); break; } @@ -1116,7 +1264,8 @@ osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced { void *va; uint16 align = (1 << align_bits); - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align)) size += align; @@ -1155,19 +1304,23 @@ osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced void osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa) { + struct pci_dev *hwdev = NULL; #ifdef BCMDMA64OSL dma_addr_t paddr; #endif /* BCMDMA64OSL */ - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); + UNUSED_PARAMETER(hwdev); #if (defined(__ARM_ARCH_7A__) && !defined(DHD_USE_COHERENT_MEM_FOR_RING)) - kfree(va); -#else + KVFREE(osh, va); +#else /* (defined(__ARM_ARCH_7A__) && !defined(DHD_USE_COHERENT_MEM_FOR_RING)) */ + hwdev = osh->pdev; #ifdef BCMDMA64OSL PHYSADDRTOULONG(pa, paddr); - pci_free_consistent(osh->pdev, size, va, paddr); -#else - pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); + dma_free_coherent(&hwdev->dev, size, va, paddr); +#else /* BCMDMA64OSL */ + dma_free_coherent(&hwdev->dev, size, va, (dma_addr_t)pa); #endif /* BCMDMA64OSL */ #endif /* __ARM_ARCH_7A__ && !DHD_USE_COHERENT_MEM_FOR_RING */ } @@ -1190,6 +1343,7 @@ dmaaddr_t BCMFASTPATH(osl_dma_map)(osl_t *osh, void *va, uint size, int direction, void *p, hnddma_seg_map_t *dmah) { + struct pci_dev *hwdev = osh->pdev; int dir; dmaaddr_t ret_addr; dma_addr_t map_addr; @@ -1197,15 +1351,18 @@ BCMFASTPATH(osl_dma_map)(osl_t *osh, void *va, uint size, int direction, void *p DMA_LOCK(osh); - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); - map_addr = pci_map_single(osh->pdev, va, size, dir); + /* For Rx buffers, keep direction as bidirectional to handle packet fetch cases */ + dir = (direction == DMA_RX)? DMA_RXTX: direction; - ret = pci_dma_mapping_error(osh->pdev, map_addr); + map_addr = dma_map_single(&hwdev->dev, va, size, dir); + + ret = dma_mapping_error(&hwdev->dev, map_addr); if (ret) { - printf("%s: Failed to map memory\n", __FUNCTION__); + OSL_PRINT(("%s: Failed to map memory\n", __FUNCTION__)); PHYSADDRLOSET(ret_addr, 0); PHYSADDRHISET(ret_addr, 0); } else { @@ -1229,22 +1386,25 @@ BCMFASTPATH(osl_dma_unmap)(osl_t *osh, dmaaddr_t pa, uint size, int direction) #ifdef BCMDMA64OSL dma_addr_t paddr; #endif /* BCMDMA64OSL */ + struct pci_dev *hwdev = osh->pdev; - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + ASSERT_NULL(osh); + ASSERT(osh->magic == OS_HANDLE_MAGIC); DMA_LOCK(osh); - dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; - #ifdef DHD_MAP_LOGGING osl_dma_map_logging(osh, osh->dhd_unmap_log, pa, size); #endif /* DHD_MAP_LOGGING */ + /* For Rx buffers, keep direction as bidirectional to handle packet fetch cases */ + dir = (direction == DMA_RX)? DMA_RXTX: direction; + #ifdef BCMDMA64OSL PHYSADDRTOULONG(pa, paddr); - pci_unmap_single(osh->pdev, paddr, size, dir); + dma_unmap_single(&hwdev->dev, paddr, size, dir); #else /* BCMDMA64OSL */ - pci_unmap_single(osh->pdev, (uint32)pa, size, dir); + dma_unmap_single(&hwdev->dev, (uint32)pa, size, dir); #endif /* BCMDMA64OSL */ DMA_UNLOCK(osh); @@ -1285,9 +1445,6 @@ osl_assert(const char *exp, const char *file, int line) #ifdef BCMASSERT_LOG snprintf(tempbuf, 64, "\"%s\": file \"%s\", line %d\n", exp, basename, line); -#ifndef OEM_ANDROID - bcm_assert_log(tempbuf); -#endif /* OEM_ANDROID */ #endif /* BCMASSERT_LOG */ #ifdef BCMDBG_ASSERT @@ -1297,8 +1454,8 @@ osl_assert(const char *exp, const char *file, int line) /* Print assert message and give it time to be written to /var/log/messages */ if (!in_interrupt() && g_assert_type != 1 && g_assert_type != 3) { const int delay = 3; - printf("%s", tempbuf); - printf("panic in %d seconds\n", delay); + printk("%s", tempbuf); + printk("panic in %d seconds\n", delay); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(delay * HZ); } @@ -1306,16 +1463,16 @@ osl_assert(const char *exp, const char *file, int line) switch (g_assert_type) { case 0: - printf("%s", tempbuf); + printk("%s", tempbuf); BUG(); break; case 1: /* fall through */ case 3: - printf("%s", tempbuf); + printk("%s", tempbuf); break; case 2: - printf("%s", tempbuf); + printk("%s", tempbuf); BUG(); break; default: @@ -1358,12 +1515,12 @@ osl_sleep(uint ms) uint64 osl_sysuptime_us(void) { - struct osl_timespec tv; + struct osl_timespec ts; uint64 usec; - osl_do_gettimeofday(&tv); - /* tv_usec content is fraction of a second */ - usec = (uint64)tv.tv_sec * 1000000ul + tv.tv_usec; + osl_do_gettimeofday(&ts); + /* tv_nsec content is fraction of a second */ + usec = (uint64)ts.tv_sec * USEC_PER_SEC + (ts.tv_nsec / NSEC_PER_USEC); #ifdef BCMSLTGT /* scale down the time to match the slow target roughly */ usec /= htclkratio; @@ -1371,6 +1528,14 @@ osl_sysuptime_us(void) return usec; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) +uint64 +osl_sysuptime_ns(void) +{ + return ktime_get_real_ns(); +} +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) */ + uint64 osl_localtime_ns(void) { @@ -1417,18 +1582,33 @@ osl_get_localtime(uint64 *sec, uint64 *usec) uint64 osl_systztime_us(void) { - struct osl_timespec tv; + struct osl_timespec ts; uint64 tzusec; - osl_do_gettimeofday(&tv); + osl_do_gettimeofday(&ts); /* apply timezone */ - tzusec = (uint64)((tv.tv_sec - (sys_tz.tz_minuteswest * 60)) * - USEC_PER_SEC); - tzusec += tv.tv_usec; + tzusec = (uint64)((ts.tv_sec - (sys_tz.tz_minuteswest * 60L)) * USEC_PER_SEC); + tzusec += ts.tv_nsec / NSEC_PER_USEC; return tzusec; } +char * +osl_get_rtctime(void) +{ + static char timebuf[RTC_TIME_BUF_LEN]; + struct timespec64 ts; + struct rtc_time tm; + + memset_s(timebuf, RTC_TIME_BUF_LEN, 0, RTC_TIME_BUF_LEN); + ktime_get_real_ts64(&ts); + rtc_time_to_tm(ts.tv_sec - (sys_tz.tz_minuteswest * 60L), &tm); + scnprintf(timebuf, RTC_TIME_BUF_LEN, + "%02d:%02d:%02d.%06lu", + tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec/NSEC_PER_USEC); + return timebuf; +} + /* * OSLREGOPS specifies the use of osl_XXX routines to be used for register access */ @@ -1517,11 +1697,11 @@ osl_printf(const char *format, ...) va_end(args); if (len > sizeof(printbuf)) { - printf("osl_printf: buffer overrun\n"); + printk("osl_printf: buffer overrun\n"); return (0); } - return (printf("%s", printbuf)); + return (printk("%s", printbuf)); } int @@ -1718,110 +1898,8 @@ osl_rand(void) return rand; } -/* Linux Kernel: File Operations: start */ -void * -osl_os_open_image(char *filename) -{ - struct file *fp; - - fp = filp_open(filename, O_RDONLY, 0); - /* - * 2.6.11 (FC4) supports filp_open() but later revs don't? - * Alternative: - * fp = open_namei(AT_FDCWD, filename, O_RD, 0); - * ??? - */ - if (IS_ERR(fp)) { - printf("ERROR %ld: Unable to open file %s\n", PTR_ERR(fp), filename); - fp = NULL; - } - - return fp; -} - -int -osl_os_get_image_block(char *buf, int len, void *image) -{ - struct file *fp = (struct file *)image; - int rdlen; - - if (fp == NULL) { - return 0; - } - - rdlen = kernel_read_compat(fp, fp->f_pos, buf, len); - if (rdlen > 0) { - fp->f_pos += rdlen; - } - - return rdlen; -} - -void -osl_os_close_image(void *image) -{ - struct file *fp = (struct file *)image; - - if (fp != NULL) { - filp_close(fp, NULL); - } -} - -int -osl_os_image_size(void *image) -{ - int len = 0, curroffset; - - if (image) { - /* store the current offset */ - curroffset = generic_file_llseek(image, 0, 1); - /* goto end of file to get length */ - len = generic_file_llseek(image, 0, 2); - /* restore back the offset */ - generic_file_llseek(image, curroffset, 0); - } - return len; -} - /* Linux Kernel: File Operations: end */ -#if defined(AXI_TIMEOUTS_NIC) -inline void osl_bpt_rreg(osl_t *osh, ulong addr, volatile void *v, uint size) -{ - bool poll_timeout = FALSE; - static int in_si_clear = FALSE; - - switch (size) { - case sizeof(uint8): - *(volatile uint8*)v = readb((volatile uint8*)(addr)); - if (*(volatile uint8*)v == 0xff) - poll_timeout = TRUE; - break; - case sizeof(uint16): - *(volatile uint16*)v = readw((volatile uint16*)(addr)); - if (*(volatile uint16*)v == 0xffff) - poll_timeout = TRUE; - break; - case sizeof(uint32): - *(volatile uint32*)v = readl((volatile uint32*)(addr)); - if (*(volatile uint32*)v == 0xffffffff) - poll_timeout = TRUE; - break; - case sizeof(uint64): - *(volatile uint64*)v = *((volatile uint64*)(addr)); - if (*(volatile uint64*)v == 0xffffffffffffffff) - poll_timeout = TRUE; - break; - } - - if (osh && osh->sih && (in_si_clear == FALSE) && poll_timeout && osh->bpt_cb) { - in_si_clear = TRUE; - osh->bpt_cb((void *)osh->sih, (void *)addr); - in_si_clear = FALSE; - } -} -#endif /* AXI_TIMEOUTS_NIC */ - #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) void timer_cb_compat(struct timer_list *tl) @@ -1835,18 +1913,18 @@ timer_cb_compat(struct timer_list *tl) /* Note: All timer api's are thread unsafe and should be protected with locks by caller */ osl_timer_t * -osl_timer_init(osl_t *osh, const char *name, void (*fn)(void *arg), void *arg) +osl_timer_init(osl_t *osh, const char *name, void (*fn)(ulong arg), void *arg) { osl_timer_t *t; BCM_REFERENCE(fn); if ((t = MALLOCZ(NULL, sizeof(osl_timer_t))) == NULL) { - printf(KERN_ERR "osl_timer_init: out of memory, malloced %d bytes\n", - (int)sizeof(osl_timer_t)); + OSL_PRINT(("osl_timer_init: out of memory, malloced %d bytes\n", + (int)sizeof(osl_timer_t))); return (NULL); } bzero(t, sizeof(osl_timer_t)); if ((t->timer = MALLOCZ(NULL, sizeof(timer_list_compat_t))) == NULL) { - printf("osl_timer_init: malloc failed\n"); + OSL_PRINT(("osl_timer_init: malloc failed\n")); MFREE(NULL, t, sizeof(osl_timer_t)); return (NULL); } @@ -1867,14 +1945,14 @@ void osl_timer_add(osl_t *osh, osl_timer_t *t, uint32 ms, bool periodic) { if (t == NULL) { - printf("%s: Timer handle is NULL\n", __FUNCTION__); + OSL_PRINT(("%s: Timer handle is NULL\n", __FUNCTION__)); return; } ASSERT(!t->set); t->set = TRUE; if (periodic) { - printf("Periodic timers are not supported by Linux timer apis\n"); + OSL_PRINT(("Periodic timers are not supported by Linux timer apis\n")); } #if defined(BCMSLTGT) timer_expires(t->timer) = jiffies + ms*HZ/1000*htclkratio; @@ -1891,11 +1969,11 @@ void osl_timer_update(osl_t *osh, osl_timer_t *t, uint32 ms, bool periodic) { if (t == NULL) { - printf("%s: Timer handle is NULL\n", __FUNCTION__); + OSL_PRINT(("%s: Timer handle is NULL\n", __FUNCTION__)); return; } if (periodic) { - printf("Periodic timers are not supported by Linux timer apis\n"); + OSL_PRINT(("Periodic timers are not supported by Linux timer apis\n")); } t->set = TRUE; #if defined(BCMSLTGT) @@ -1916,14 +1994,14 @@ bool osl_timer_del(osl_t *osh, osl_timer_t *t) { if (t == NULL) { - printf("%s: Timer handle is NULL\n", __FUNCTION__); + OSL_PRINT(("%s: Timer handle is NULL\n", __FUNCTION__)); return (FALSE); } if (t->set) { t->set = FALSE; if (t->timer) { del_timer(t->timer); - MFREE(NULL, t->timer, sizeof(struct timer_list)); + MFREE(NULL, t->timer, sizeof(timer_list_compat_t)); } #ifdef BCMDBG if (t->name) { @@ -1939,9 +2017,11 @@ osl_timer_del(osl_t *osh, osl_timer_t *t) int kernel_read_compat(struct file *file, loff_t offset, char *addr, unsigned long count) { - if (!IS_ENABLED(CONFIG_NO_GKI)) - return -EPERM; +#ifdef DHD_SUPPORT_VFS_CALL return (int)kernel_read(file, addr, (size_t)count, &offset); +#else + return 0; +#endif /* DHD_SUPPORT_VFS_CALL */ } #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) */ @@ -1957,6 +2037,7 @@ osl_spin_lock_init(osl_t *osh) spin_lock_init(lock); return ((void *)lock); } + void osl_spin_lock_deinit(osl_t *osh, void *lock) { @@ -2051,10 +2132,8 @@ osl_mutex_lock_init(osl_t *osh) } void -osl_mutex_lock_deinit(osl_t *osh, void *mutex) +osl_mutex_lock_deinit(osl_t *osh, void *mtx) { - struct mutex *mtx = mutex; - if (mtx) { mutex_destroy(mtx); MFREE(osh, mtx, sizeof(struct mutex)); @@ -2121,6 +2200,49 @@ osl_dma_lock_init(osl_t *osh) } #endif /* USE_DMA_LOCK */ +#if defined(NIC_REG_ACCESS_LEGACY) || defined(NIC_REG_ACCESS_LEGACY_DBG) +osl_pcie_window_t osl_reg_access_pcie_window; +/** + * Initialize osl_reg_access_pcie_window. + * @param[in] osh OS handle. + * @param[in] bp_access_lock Lock for restricting backplane access. + * @param[in] window_offset Config space window base register offset. + * @param[in] bar_addr ioremap address of this window. + */ +void +osl_reg_access_pcie_window_init(osl_t *osh, void *bp_access_lock, unsigned long window_offset, + volatile void *bar_addr) +{ + osl_reg_access_pcie_window.bp_access_lock = bp_access_lock; + osl_reg_access_pcie_window.window_offset = window_offset; + osl_reg_access_pcie_window.bar_addr = bar_addr; + osl_reg_access_pcie_window.bp_addr = OSL_PCI_READ_CONFIG(osh, + osl_reg_access_pcie_window.window_offset, sizeof(uint32)); +} + +/** + * Check that the osl_reg_access_pcie_window is configured to access the reg_addr and return the + * window address. If the window is not properly configured, then it will be reconfigured. + * @param[in] osh OS handle. + * @param[in] reg_addr Address that the window should be able to access after this function call. + * @return Address of the pcie bar window that is configured to access the provided + * address. + */ +volatile void * +osl_update_pcie_win(osl_t *osh, volatile void *reg_addr) +{ + unsigned long r_addr = (unsigned long)reg_addr; + unsigned long base_addr = (r_addr & BAR0_WINDOW_ADDRESS_MASK); + if (base_addr != osl_reg_access_pcie_window.bp_addr) { + osl_reg_access_pcie_window.bp_addr = base_addr; + OSL_PCI_WRITE_CONFIG(osh, osl_reg_access_pcie_window.window_offset, sizeof(uint32), + osl_reg_access_pcie_window.bp_addr); + } + return (volatile void *)(((volatile uint8 *)osl_reg_access_pcie_window.bar_addr) + + (r_addr & BAR0_WINDOW_OFFSET_MASK)); +} +#endif /* defined(NIC_REG_ACCESS_LEGACY) || defined(NIC_REG_ACCESS_LEGACY_DBG) */ + void osl_do_gettimeofday(struct osl_timespec *ts) { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl_priv.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl_priv.h old mode 100755 new mode 100644 index de06b9944521..51530815e935 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl_priv.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl_priv.h @@ -1,7 +1,7 @@ /* * Private header file for Linux OS Independent Layer * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -145,10 +145,6 @@ struct osl_cmn_info { }; typedef struct osl_cmn_info osl_cmn_t; -#if defined(AXI_TIMEOUTS_NIC) -typedef uint32 (*bpt_cb_fn)(void *ctx, void *addr); -#endif /* AXI_TIMEOUTS_NIC */ - struct osl_info { osl_pubinfo_t pub; uint32 flags; /* If specific cases to be handled in the OSL */ @@ -168,10 +164,6 @@ struct osl_info { struct list_head ctrace_list; int ctrace_num; #endif /* BCMDBG_CTRACE */ -#if defined(AXI_TIMEOUTS_NIC) - bpt_cb_fn bpt_cb; - void *sih; -#endif /* AXI_TIMEOUTS_NIC */ #ifdef USE_DMA_LOCK spinlock_t dma_lock; bool dma_lock_bh; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_pkt.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_pkt.c old mode 100755 new mode 100644 index f32f8e450795..22e05a4d0cb1 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_pkt.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_pkt.c @@ -1,7 +1,7 @@ /* * Linux Packet (skb) interface * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -34,9 +34,6 @@ #include #include -#if defined(BCMASSERT_LOG) && !defined(OEM_ANDROID) -#include -#endif #include #include "linux_osl_priv.h" @@ -48,6 +45,20 @@ bcm_static_pkt_t *bcm_static_skb = 0; void* wifi_platform_prealloc(void *adapter, int section, unsigned long size); #endif /* CONFIG_DHD_USE_STATIC_BUF */ +#ifndef CUSTOM_PREFIX +#define BCM_PRINT(args) \ + do { \ + printf args; \ + } while (0) +#else +#define BCM_PRINT_PREFIX "[%s]"CUSTOM_PREFIX, OSL_GET_RTCTIME() +#define BCM_PRINT(args) \ + do { \ + pr_cont(OSL_PRINT_PREFIX); \ + pr_cont args; \ + } while (0) +#endif /* CUSTOM_PREFIX */ + #ifdef BCM_OBJECT_TRACE /* don't clear the first 4 byte that is the pkt sn */ #define OSL_PKTTAG_CLEAR(p) \ @@ -73,12 +84,12 @@ int osl_static_mem_init(osl_t *osh, void *adapter) if (!bcm_static_buf && adapter) { if (!(bcm_static_buf = (bcm_static_buf_t *)wifi_platform_prealloc(adapter, DHD_PREALLOC_OSL_BUF, STATIC_BUF_SIZE + STATIC_BUF_TOTAL_LEN))) { - printf("can not alloc static buf!\n"); + BCM_PRINT(("can not alloc static buf!\n")); bcm_static_skb = NULL; ASSERT(osh->magic == OS_HANDLE_MAGIC); return -ENOMEM; } else { - printf("succeed to alloc static buf\n"); + BCM_PRINT(("succeed to alloc static buf\n")); } spin_lock_init(&bcm_static_buf->static_lock); @@ -93,7 +104,7 @@ int osl_static_mem_init(osl_t *osh, void *adapter) bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); skb_buff_ptr = wifi_platform_prealloc(adapter, DHD_PREALLOC_SKB_BUF, 0); if (!skb_buff_ptr) { - printf("cannot alloc static buf!\n"); + BCM_PRINT(("cannot alloc static buf!\n")); bcm_static_buf = NULL; bcm_static_skb = NULL; ASSERT(osh->magic == OS_HANDLE_MAGIC); @@ -125,11 +136,11 @@ int osl_static_mem_deinit(osl_t *osh, void *adapter) if (bcm_static_buf) { bcm_static_buf = 0; } -#ifdef BCMSDIO +#if defined(BCMSDIO) || defined(DHD_USE_STATIC_CTRLBUF) if (bcm_static_skb) { bcm_static_skb = 0; } -#endif /* BCMSDIO */ +#endif /* BCMSDIO || DHD_USE_STATIC_CTRLBUF */ #endif /* CONFIG_DHD_USE_STATIC_BUF */ return 0; } @@ -139,7 +150,7 @@ BCMFASTPATH(osl_alloc_skb)(osl_t *osh, unsigned int len) { struct sk_buff *skb; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) - gfp_t flags = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; + gfp_t flags = CAN_SLEEP() ? GFP_KERNEL : GFP_ATOMIC; #ifdef DHD_USE_ATOMIC_PKTGET flags = GFP_ATOMIC; @@ -282,10 +293,11 @@ BCMFASTPATH(linux_pktget)(osl_t *osh, uint len) #ifdef BCMDBG_PKT unsigned long flags; #endif - uchar num = 0; + uint num = 0u; if (lmtest != FALSE) { + /* get a byte length random number */ get_random_bytes(&num, sizeof(uchar)); - if ((num + 1) <= (256 * lmtest / 100)) + if ((num + 1u) <= (256u * lmtest / 100u)) return NULL; } @@ -347,15 +359,15 @@ BCMFASTPATH(linux_pktfree)(osl_t *osh, void *p, bool send) #if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_CTRLBUF) if (skb && (skb->mac_len == PREALLOC_USED_MAGIC)) { - printf("%s: pkt %p is from static pool\n", - __FUNCTION__, p); + BCM_PRINT(("%s: pkt %p is from static pool\n", + __FUNCTION__, p)); dump_stack(); return; } if (skb && (skb->mac_len == PREALLOC_FREE_MAGIC)) { - printf("%s: pkt %p is from static pool and not in used\n", - __FUNCTION__, p); + BCM_PRINT(("%s: pkt %p is from static pool and not in used\n", + __FUNCTION__, p)); dump_stack(); return; } @@ -409,7 +421,7 @@ osl_pktget_static(osl_t *osh, uint len) return linux_pktget(osh, len); if (len > DHD_SKB_MAX_BUFSIZE) { - printf("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len); + BCM_PRINT(("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len)); return linux_pktget(osh, len); } @@ -452,7 +464,7 @@ osl_pktget_static(osl_t *osh, uint len) } OSL_STATIC_PKT_UNLOCK(&bcm_static_skb->osl_pkt_lock, flags); - printf("%s: all static pkt in use!\n", __FUNCTION__); + BCM_PRINT(("%s: all static pkt in use!\n", __FUNCTION__)); return NULL; #else down(&bcm_static_skb->osl_pkt_sem); @@ -504,7 +516,7 @@ osl_pktget_static(osl_t *osh, uint len) } } -#if defined (ENHANCED_STATIC_BUF) +#if defined(ENHANCED_STATIC_BUF) if (bcm_static_skb->skb_16k && bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM - 1] == 0) { bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM - 1] = 1; @@ -523,7 +535,7 @@ osl_pktget_static(osl_t *osh, uint len) #endif /* ENHANCED_STATIC_BUF */ up(&bcm_static_skb->osl_pkt_sem); - printf("%s: all static pkt in use!\n", __FUNCTION__); + BCM_PRINT(("%s: all static pkt in use!\n", __FUNCTION__)); return linux_pktget(osh, len); #endif /* DHD_USE_STATIC_CTRLBUF */ } @@ -552,15 +564,15 @@ osl_pktfree_static(osl_t *osh, void *p, bool send) for (i = 0; i < STATIC_PKT_2PAGE_NUM; i++) { if (p == bcm_static_skb->skb_8k[i]) { if (bcm_static_skb->pkt_use[i] == 0) { - printf("%s: static pkt idx %d(%p) is double free\n", - __FUNCTION__, i, p); + BCM_PRINT(("%s: static pkt idx %d(%p) is double free\n", + __FUNCTION__, i, p)); } else { bcm_static_skb->pkt_use[i] = 0; } if (skb->mac_len != PREALLOC_USED_MAGIC) { - printf("%s: static pkt idx %d(%p) is not in used\n", - __FUNCTION__, i, p); + BCM_PRINT(("%s: static pkt idx %d(%p) is not in used\n", + __FUNCTION__, i, p)); } skb->mac_len = PREALLOC_FREE_MAGIC; @@ -570,7 +582,7 @@ osl_pktfree_static(osl_t *osh, void *p, bool send) } OSL_STATIC_PKT_UNLOCK(&bcm_static_skb->osl_pkt_lock, flags); - printf("%s: packet %p does not exist in the pool\n", __FUNCTION__, p); + BCM_PRINT(("%s: packet %p does not exist in the pool\n", __FUNCTION__, p)); #else down(&bcm_static_skb->osl_pkt_sem); for (i = 0; i < STATIC_PKT_1PAGE_NUM; i++) { @@ -685,25 +697,25 @@ void osl_ctrace_dump(osl_t *osh, struct bcmstrbuf *b) if (b != NULL) bcm_bprintf(b, " Total %d sbk not free\n", osh->ctrace_num); else - printf(" Total %d sbk not free\n", osh->ctrace_num); + BCM_PRINT((" Total %d sbk not free\n", osh->ctrace_num)); list_for_each_entry(skb, &osh->ctrace_list, ctrace_list) { if (b != NULL) bcm_bprintf(b, "[%d] skb %p:\n", ++idx, skb); else - printk("[%d] skb %p:\n", ++idx, skb); + BCM_PRINT(("[%d] skb %p:\n", ++idx, skb)); for (i = 0; i < skb->ctrace_count; i++) { j = (skb->ctrace_start + i) % CTRACE_NUM; if (b != NULL) bcm_bprintf(b, " [%s(%d)]\n", skb->func[j], skb->line[j]); else - printk(" [%s(%d)]\n", skb->func[j], skb->line[j]); + BCM_PRINT((" [%s(%d)]\n", skb->func[j], skb->line[j])); } if (b != NULL) bcm_bprintf(b, "\n"); else - printk("\n"); + BCM_PRINT(("\n")); } OSL_CTRACE_UNLOCK(&osh->ctrace_lock, flags); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linuxerrmap.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linuxerrmap.c new file mode 100644 index 000000000000..a182d4f8dd27 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linuxerrmap.c @@ -0,0 +1,128 @@ +/* + * Linux Error codes + * + * Copyright (C) 2022, Broadcom. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * + * <> + */ +#include +#include +#include +#include + +#include + +static int16 linuxbcmerrormap[] = { + 0, /* 0 */ + -EINVAL, /* BCME_ERROR */ + -EINVAL, /* BCME_BADARG */ + -EINVAL, /* BCME_BADOPTION */ + -EINVAL, /* BCME_NOTUP */ + -EINVAL, /* BCME_NOTDOWN */ + -EINVAL, /* BCME_NOTAP */ + -EINVAL, /* BCME_NOTSTA */ + -EINVAL, /* BCME_BADKEYIDX */ + -EINVAL, /* BCME_RADIOOFF */ + -EINVAL, /* BCME_NOTBANDLOCKED */ + -EINVAL, /* BCME_NOCLK */ + -EINVAL, /* BCME_BADRATESET */ + -EINVAL, /* BCME_BADBAND */ + -E2BIG, /* BCME_BUFTOOSHORT */ + -E2BIG, /* BCME_BUFTOOLONG */ + -EBUSY, /* BCME_BUSY */ + -EINVAL, /* BCME_NOTASSOCIATED */ + -EINVAL, /* BCME_BADSSIDLEN */ + -EINVAL, /* BCME_OUTOFRANGECHAN */ + -EINVAL, /* BCME_BADCHAN */ + -EFAULT, /* BCME_BADADDR */ + -ENOMEM, /* BCME_NORESOURCE */ + -EOPNOTSUPP, /* BCME_UNSUPPORTED */ + -EMSGSIZE, /* BCME_BADLENGTH */ + -EINVAL, /* BCME_NOTREADY */ + -EPERM, /* BCME_EPERM */ + -ENOMEM, /* BCME_NOMEM */ + -EINVAL, /* BCME_ASSOCIATED */ + -ERANGE, /* BCME_RANGE */ + -EINVAL, /* BCME_NOTFOUND */ + -EINVAL, /* BCME_WME_NOT_ENABLED */ + -EINVAL, /* BCME_TSPEC_NOTFOUND */ + -EINVAL, /* BCME_ACM_NOTSUPPORTED */ + -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ + -EIO, /* BCME_SDIO_ERROR */ + -ENODEV, /* BCME_DONGLE_DOWN */ + -EINVAL, /* BCME_VERSION */ + -EIO, /* BCME_TXFAIL */ + -EIO, /* BCME_RXFAIL */ + -ENODEV, /* BCME_NODEVICE */ + -EINVAL, /* BCME_NMODE_DISABLED */ + -ENODATA, /* BCME_NONRESIDENT */ + -EINVAL, /* BCME_SCANREJECT */ + -EINVAL, /* BCME_USAGE_ERROR */ + -EIO, /* BCME_IOCTL_ERROR */ + -EIO, /* BCME_SERIAL_PORT_ERR */ + -EOPNOTSUPP, /* BCME_DISABLED, BCME_NOTENABLED */ + -EIO, /* BCME_DECERR */ + -EIO, /* BCME_ENCERR */ + -EIO, /* BCME_MICERR */ + -ERANGE, /* BCME_REPLAY */ + -EINVAL, /* BCME_IE_NOTFOUND */ + -EINVAL, /* BCME_DATA_NOTFOUND */ + -EINVAL, /* BCME_NOT_GC */ + -EINVAL, /* BCME_PRS_REQ_FAILED */ + -EINVAL, /* BCME_NO_P2P_SE */ + -EINVAL, /* BCME_NOA_PND */ + -EINVAL, /* BCME_FRAG_Q_FAILED */ + -EINVAL, /* BCME_GET_AF_FAILED */ + -EINVAL, /* BCME_MSCH_NOTREADY */ + -EINVAL, /* BCME_IOV_LAST_CMD */ + -EINVAL, /* BCME_MINIPMU_CAL_FAIL */ + -EINVAL, /* BCME_RCAL_FAIL */ + -EINVAL, /* BCME_LPF_RCCAL_FAIL */ + -EINVAL, /* BCME_DACBUF_RCCAL_FAIL */ + -EINVAL, /* BCME_VCOCAL_FAIL */ + -EINVAL, /* BCME_BANDLOCKED */ + -EINVAL, /* BCME_BAD_IE_DATA */ + -EINVAL, /* BCME_REG_FAILED */ + -EINVAL, /* BCME_NOCHAN */ + -EINVAL, /* BCME_PKTTOSS */ + -EINVAL, /* BCME_DNGL_DEVRESET */ + -EINVAL, /* BCME_ROAM */ + -EOPNOTSUPP, /* BCME_NO_SIG_FILE */ + -EOPNOTSUPP, /* BCME_RESP_PENDING */ + -EINVAL, /* BCME_ACTIVE */ + -EINVAL, /* BCME_IN_PROGRESS */ + -EINVAL, /* BCME_NOP */ + -EINVAL, /* BCME_6GCH_EPERM */ + -EINVAL, /* BCME_6G_NO_TPE */ + +/* When an new error code is added to bcmutils.h, add os + * specific error translation here as well + */ +/* check if BCME_LAST changed since the last time this function was updated */ +#if BCME_LAST != BCME_6G_NO_TPE +#error "You need to add a OS error translation in the linuxbcmerrormap \ + for new error code defined in bcmutils.h" +#endif +}; + +/* translate bcmerrors into linux errors */ +int +linux_get_errmap(int bcmerror) +{ + return linuxbcmerrormap[-bcmerror]; +} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/nciutils.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/nciutils.c deleted file mode 100755 index 9ae0f3cfe2c7..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/nciutils.c +++ /dev/null @@ -1,3095 +0,0 @@ -/* - * Misc utility routines for accessing chip-specific features - * of the BOOKER NCI (non coherent interconnect) based Broadcom chips. - * - * Broadcom Proprietary and Confidential. Copyright (C) 2020, - * All Rights Reserved. - * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom; - * the contents of this file may not be disclosed to third parties, - * copied or duplicated in any form, in whole or in part, without - * the prior written permission of Broadcom. - * - * - * <> - */ - -#include -#include -#include -#include -#include -#include "siutils_priv.h" -#include -#include -#include - -#define NCI_BAD_REG 0xbbadd000u /* Bad Register Address */ -#define NCI_BAD_INDEX -1 /* Bad Index */ - -#define OOBR_BASE_MASK 0x00001FFFu /* Mask to get Base address of OOBR */ -#define EROM1_BASE_MASK 0x00000FFFu /* Mask to get Base address of EROM1 */ - -/* Core Info */ -#define COREINFO_COREID_MASK 0x00000FFFu /* Bit-11 to 0 */ -#define COREINFO_REV_MASK 0x000FF000u /* Core Rev Mask */ -#define COREINFO_REV_SHIFT 12u /* Bit-12 */ -#define COREINFO_MFG_MASK 0x00F00000u /* Core Mfg Mask */ -#define COREINFO_MFG_SHIFT 20u /* Bit-20 */ -#define COREINFO_BPID_MASK 0x07000000u /* 26-24 Gives Backplane ID */ -#define COREINFO_BPID_SHIFT 24u /* Bit:26-24 */ -#define COREINFO_ISBP_MASK 0x08000000u /* Is Backplane or Bridge */ -#define COREINFO_ISBP_SHIFT 27u /* Bit:27 */ - -/* Interface Config */ -#define IC_IFACECNT_MASK 0x0000F000u /* No of Interface Descriptor Mask */ -#define IC_IFACECNT_SHIFT 12u /* Bit-12 */ -#define IC_IFACEOFFSET_MASK 0x00000FFFu /* OFFSET for 1st Interface Descriptor */ - -/* DMP Reg Offset */ -#define DMP_DMPCTRL_REG_OFFSET 8u - -/* Interface Descriptor Masks */ -#define ID_NODEPTR_MASK 0xFFFFFFF8u /* Master/Slave Network Interface Addr */ -#define ID_NODETYPE_MASK 0x00000007u /* 0:Booker 1:IDM 1-0xf:Reserved */ -#define ID_WORDOFFSET_MASK 0xF0000000u /* WordOffset to next Iface Desc in EROM2 */ -#define ID_WORDOFFSET_SHIFT 28u /* WordOffset bits 31-28 */ -#define ID_CORETYPE_MASK 0x08000000u /* CORE belongs to OOBR(0) or EROM(1) */ -#define ID_CORETYPE_SHIFT 27u /* Bit-27 */ -#define ID_MI_MASK 0x04000000u /* 0: Slave Interface, 1:Master Interface */ -#define ID_MI_SHIFT 26u /* Bit-26 */ -#define ID_NADDR_MASK 0x03000000u /* No of Slave Address Regions */ -#define ID_NADDR_SHIFT 24u /* Bit:25-24 */ -#define ID_BPID_MASK 0x00F00000u /* Give Backplane ID */ -#define ID_BPID_SHIFT 20u /* Bit:20-23 */ -#define ID_COREINFOPTR_MASK 0x00001FFFu /* OOBR or EROM Offset */ -#define ID_ENDMARKER 0xFFFFFFFFu /* End of EROM Part 2 */ - -/* Slave Port Address Descriptor Masks */ -#define SLAVEPORT_BASE_ADDR_MASK 0xFFFFFF00u /* Bits 31:8 is the base address */ -#define SLAVEPORT_BOUND_ADDR_MASK 0x00000040u /* Addr is not 2^n and with bound addr */ -#define SLAVEPORT_BOUND_ADDR_SHIFT 6u /* Bit-6 */ -#define SLAVEPORT_64BIT_ADDR_MASK 0x00000020u /* 64-bit base and bound fields */ -#define SLAVEPORT_64BIT_ADDR_SHIFT 5u /* Bit-5 */ -#define SLAVEPORT_ADDR_SIZE_MASK 0x0000001Fu /* Address Size mask */ -#define SLAVEPORT_ADDR_TYPE_BOUND 0x1u /* Bound Addr */ -#define SLAVEPORT_ADDR_TYPE_64 0x2u /* 64-Bit Addr */ -#define SLAVEPORT_ADDR_MIN_SHIFT 0x8u -/* Address space Size of the slave port */ -#define SLAVEPORT_ADDR_SIZE(adesc) (1u << ((adesc & SLAVEPORT_ADDR_SIZE_MASK) + \ - SLAVEPORT_ADDR_MIN_SHIFT)) - -#define GET_NEXT_EROM_ADDR(addr) ((uint32*)((uintptr)(addr) + 4u)) - -#define NCI_DEFAULT_CORE_UNIT (0u) - -/* Error Codes */ -enum { - NCI_OK = 0, - NCI_BACKPLANE_ID_MISMATCH = -1, - NCI_INVALID_EROM2PTR = -2, - NCI_WORDOFFSET_MISMATCH = -3, - NCI_NOMEM = -4, - NCI_MASTER_INVALID_ADDR = -5 -}; - -#define GET_OOBR_BASE(erom2base) ((erom2base) & ~OOBR_BASE_MASK) -#define GET_EROM1_BASE(erom2base) ((erom2base) & ~EROM1_BASE_MASK) -#define CORE_ID(core_info) ((core_info) & COREINFO_COREID_MASK) -#define GET_INFACECNT(iface_cfg) (((iface_cfg) & IC_IFACECNT_MASK) >> IC_IFACECNT_SHIFT) -#define GET_NODEPTR(iface_desc_0) ((iface_desc_0) & ID_NODEPTR_MASK) -#define GET_NODETYPE(iface_desc_0) ((iface_desc_0) & ID_NODETYPE_MASK) -#define GET_WORDOFFSET(iface_desc_1) (((iface_desc_1) & ID_WORDOFFSET_MASK) \ - >> ID_WORDOFFSET_SHIFT) -#define IS_MASTER(iface_desc_1) (((iface_desc_1) & ID_MI_MASK) >> ID_MI_SHIFT) -#define GET_CORETYPE(iface_desc_1) (((iface_desc_1) & ID_CORETYPE_MASK) >> ID_CORETYPE_SHIFT) -#define GET_NUM_ADDR_REG(iface_desc_1) (((iface_desc_1) & ID_NADDR_MASK) >> ID_NADDR_SHIFT) -#define GET_COREOFFSET(iface_desc_1) ((iface_desc_1) & ID_COREINFOPTR_MASK) -#define ADDR_SIZE(sz) ((1u << ((sz) + 8u)) - 1u) - -#define CORE_REV(core_info) ((core_info) & COREINFO_REV_MASK) >> COREINFO_REV_SHIFT -#define CORE_MFG(core_info) ((core_info) & COREINFO_MFG_MASK) >> COREINFO_MFG_SHIFT -#define COREINFO_BPID(core_info) (((core_info) & COREINFO_BPID_MASK) >> COREINFO_BPID_SHIFT) -#define IS_BACKPLANE(core_info) (((core_info) & COREINFO_ISBP_MASK) >> COREINFO_ISBP_SHIFT) -#define ID_BPID(iface_desc_1) (((iface_desc_1) & ID_BPID_MASK) >> ID_BPID_SHIFT) -#define IS_BACKPLANE_ID_SAME(core_info, iface_desc_1) \ - (COREINFO_BPID((core_info)) == ID_BPID((iface_desc_1))) - -#define NCI_WORD_SIZE (4u) -#define PCI_ACCESS_SIZE (4u) - -#define NCI_ADDR2NUM(addr) ((uintptr)(addr)) -#define NCI_ADD_NUM(addr, size) (NCI_ADDR2NUM(addr) + (size)) -#ifdef DONGLEBUILD -#define NCI_ADD_ADDR(addr, size) ((uint32*)REG_MAP(NCI_ADD_NUM((addr), (size)), 0u)) -#else /* !DONGLEBUILD */ -#define NCI_ADD_ADDR(addr, size) ((uint32*)(NCI_ADD_NUM((addr), (size)))) -#endif /* DONGLEBUILD */ -#define NCI_INC_ADDR(addr, size) ((addr) = NCI_ADD_ADDR((addr), (size))) - -#define NODE_TYPE_BOOKER 0x0u -#define NODE_TYPE_NIC400 0x1u - -#define BP_BOOKER 0x0u -#define BP_NIC400 0x1u -#define BP_APB1 0x2u -#define BP_APB2 0x3u -#define BP_CCI400 0x4u - -#define PCIE_WRITE_SIZE 4u - -static const char BACKPLANE_ID_NAME[][11] = { - "BOOKER", - "NIC400", - "APB1", - "APB2", - "CCI400", - "\0" -}; - -#define APB_INF(ifd) ((ID_BPID((ifd).iface_desc_1) == BP_APB1) || \ - (ID_BPID((ifd).iface_desc_1) == BP_APB2)) -#define BOOKER_INF(ifd) (ID_BPID((ifd).iface_desc_1) == BP_BOOKER) -#define NIC_INF(ifd) (ID_BPID((ifd).iface_desc_1) == BP_NIC400) - -/* BOOKER NCI LOG LEVEL */ -#define NCI_LOG_LEVEL_ERROR 0x1u -#define NCI_LOG_LEVEL_TRACE 0x2u -#define NCI_LOG_LEVEL_INFO 0x4u -#define NCI_LOG_LEVEL_PRINT 0x8u - -#ifndef NCI_DEFAULT_LOG_LEVEL -#define NCI_DEFAULT_LOG_LEVEL (NCI_LOG_LEVEL_ERROR) -#endif /* NCI_DEFAULT_LOG_LEVEL */ - -uint32 nci_log_level = NCI_DEFAULT_LOG_LEVEL; - -#ifdef DONGLEBUILD -#define NCI_ERROR(args) do { if (nci_log_level & NCI_LOG_LEVEL_ERROR) { printf args; } } while (0u) -#define NCI_TRACE(args) do { if (nci_log_level & NCI_LOG_LEVEL_TRACE) { printf args; } } while (0u) -#define NCI_INFO(args) do { if (nci_log_level & NCI_LOG_LEVEL_INFO) { printf args; } } while (0u) -#define NCI_PRINT(args) do { if (nci_log_level & NCI_LOG_LEVEL_PRINT) { printf args; } } while (0u) -#else /* !DONGLEBUILD */ -#define NCI_KERN_PRINT(...) printk(KERN_ERR __VA_ARGS__) -#define NCI_ERROR(args) do { if (nci_log_level & NCI_LOG_LEVEL_ERROR) \ - { NCI_KERN_PRINT args; } } while (0u) -#define NCI_TRACE(args) do { if (nci_log_level & NCI_LOG_LEVEL_TRACE) \ - { NCI_KERN_PRINT args; } } while (0u) -#define NCI_INFO(args) do { if (nci_log_level & NCI_LOG_LEVEL_INFO) \ - { NCI_KERN_PRINT args; } } while (0u) -#define NCI_PRINT(args) do { if (nci_log_level & NCI_LOG_LEVEL_PRINT) \ - { NCI_KERN_PRINT args; } } while (0u) -#endif /* DONGLEBUILD */ - -#define NCI_EROM_WORD_SIZEOF 4u -#define NCI_REGS_PER_CORE 2u - -#define NCI_EROM1_LEN(erom2base) (erom2base - GET_EROM1_BASE(erom2base)) -#define NCI_NONOOBR_CORES(erom2base) NCI_EROM1_LEN(erom2base) \ - /(NCI_REGS_PER_CORE * NCI_EROM_WORD_SIZEOF) - -/* AXI ID to CoreID + unit mappings */ -typedef struct nci_axi_to_coreidx { - uint coreid; - uint coreunit; -} nci_axi_to_coreidx_t; - -static const nci_axi_to_coreidx_t axi2coreidx_4397[] = { - {CC_CORE_ID, 0}, /* 00 Chipcommon */ - {PCIE2_CORE_ID, 0}, /* 01 PCIe */ - {D11_CORE_ID, 0}, /* 02 D11 Main */ - {ARMCR4_CORE_ID, 0}, /* 03 ARM */ - {BT_CORE_ID, 0}, /* 04 BT AHB */ - {D11_CORE_ID, 1}, /* 05 D11 Aux */ - {D11_CORE_ID, 0}, /* 06 D11 Main l1 */ - {D11_CORE_ID, 1}, /* 07 D11 Aux l1 */ - {D11_CORE_ID, 0}, /* 08 D11 Main l2 */ - {D11_CORE_ID, 1}, /* 09 D11 Aux l2 */ - {NODEV_CORE_ID, 0}, /* 10 M2M DMA */ - {NODEV_CORE_ID, 0}, /* 11 unused */ - {NODEV_CORE_ID, 0}, /* 12 unused */ - {NODEV_CORE_ID, 0}, /* 13 unused */ - {NODEV_CORE_ID, 0}, /* 14 unused */ - {NODEV_CORE_ID, 0} /* 15 unused */ -}; - -typedef struct slave_port { - uint32 adesc; /**< Address Descriptor 0 */ - uint32 addrl; /**< Lower Base */ - uint32 addrh; /**< Upper Base */ - uint32 extaddrl; /**< Lower Bound */ - uint32 extaddrh; /**< Ubber Bound */ -} slave_port_t; - -typedef struct interface_desc { - slave_port_t *sp; /**< Slave Port Addr 0-3 */ - - uint32 iface_desc_0; /**< Interface-0 Descriptor Word0 */ - /* If Node Type 0-Booker xMNI/xSNI address. If Node Type 1-DMP wrapper Address */ - uint32 node_ptr; /**< Core's Node pointer */ - - uint32 iface_desc_1; /**< Interface Descriptor Word1 */ - uint8 num_addr_reg; /**< Number of Slave Port Addr (Valid only if master=0) */ - uint8 coretype; /**< Core Belongs to 0:OOBR 1:Without OOBR */ - uint8 master; /**< 1:Master 0:Slave */ - - uint8 node_type; /**< 0:Booker , 1:IDM Wrapper, 2-0xf: Reserved */ -} interface_desc_t; - -typedef struct nci_cores { - void *regs; - /* 2:0-Node type (0-booker,1-IDM Wrapper) 31:3-Interconnect registyer space */ - interface_desc_t *desc; /**< Interface & Address Descriptors */ - /* - * 11:0-CoreID, 19:12-RevID 23:20-MFG 26:24-Backplane ID if - * bit 27 is 1 (Core is Backplane or Bridge ) - */ - uint32 coreinfo; /**< CoreInfo of each core */ - /* - * 11:0 - Offosewt of 1st Interface desc in EROM 15:12 - No. - * of interfaces attachedto this core - */ - uint32 iface_cfg; /**< Interface config Reg */ - uint32 dmp_regs_off; /**< DMP control & DMP status @ 0x48 from coreinfo */ - uint32 coreid; /**< id of each core */ - uint8 coreunit; /**< Unit differentiate same coreids */ - uint8 iface_cnt; /**< no of Interface connected to each core */ - uint8 PAD[2u]; -} nci_cores_t; - -typedef struct nci_info { - void *osh; /**< osl os handle */ - nci_cores_t *cores; /**< Cores Parsed */ - void *pci_bar_addr; /**< PCI BAR0 Window */ - uint32 cc_erom2base; /**< Base of EROM2 from ChipCommon */ - uint32 *erom1base; /**< Base of EROM1 */ - uint32 *erom2base; /**< Base of EROM2 */ - uint32 *oobr_base; /**< Base of OOBR */ - uint16 bustype; /**< SI_BUS, PCI_BUS */ - uint8 max_cores; /**< # Max cores indicated by Register */ - uint8 num_cores; /**< # discovered cores */ - uint8 refcnt; /**< Allocation reference count */ - uint8 scan_done; /**< Set to TRUE when erom scan is done. */ - uint8 PAD[2]; -} nci_info_t; - -#define NI_IDM_RESET_ENTRY 0x1 -#define NI_IDM_RESET_EXIT 0x0 - -/* AXI Slave Network Interface registers */ -typedef volatile struct asni_regs { - uint32 node_type; /* 0x000 */ - uint32 node_info; /* 0x004 */ - uint32 secr_acc; /* 0x008 */ - uint32 pmusela; /* 0x00c */ - uint32 pmuselb; /* 0x010 */ - uint32 PAD[11]; - uint32 node_feat; /* 0x040 */ - uint32 bursplt; /* 0x044 */ - uint32 addr_remap; /* 0x048 */ - uint32 PAD[13]; - uint32 sildbg; /* 0x080 */ - uint32 qosctl; /* 0x084 */ - uint32 wdatthrs; /* 0x088 */ - uint32 arqosovr; /* 0x08c */ - uint32 awqosovr; /* 0x090 */ - uint32 atqosot; /* 0x094 */ - uint32 arqosot; /* 0x098 */ - uint32 awqosot; /* 0x09c */ - uint32 axqosot; /* 0x0a0 */ - uint32 qosrdpk; /* 0x0a4 */ - uint32 qosrdbur; /* 0x0a8 */ - uint32 qosrdavg; /* 0x0ac */ - uint32 qoswrpk; /* 0x0b0 */ - uint32 qoswrbur; /* 0x0b4 */ - uint32 qoswravg; /* 0x0b8 */ - uint32 qoscompk; /* 0x0bc */ - uint32 qoscombur; /* 0x0c0 */ - uint32 qoscomavg; /* 0x0c4 */ - uint32 qosrbbqv; /* 0x0c8 */ - uint32 qoswrbqv; /* 0x0cc */ - uint32 qoscombqv; /* 0x0d0 */ - uint32 PAD[11]; - uint32 idm_device_id; /* 0x100 */ - uint32 PAD[15]; - uint32 idm_reset_ctrl; /* 0x140 */ -} asni_regs_t; - -/* AXI Master Network Interface registers */ -typedef volatile struct amni_regs { - uint32 node_type; /* 0x000 */ - uint32 node_info; /* 0x004 */ - uint32 secr_acc; /* 0x008 */ - uint32 pmusela; /* 0x00c */ - uint32 pmuselb; /* 0x010 */ - uint32 PAD[11]; - uint32 node_feat; /* 0x040 */ - uint32 PAD[15]; - uint32 sildbg; /* 0x080 */ - uint32 qosacc; /* 0x084 */ - uint32 PAD[26]; - uint32 interrupt_status; /* 0x0f0 */ - uint32 interrupt_mask; /* 0x0f4 */ - uint32 interrupt_status_ns; /* 0x0f8 */ - uint32 interrupt_mask_ns; /* 0x0FC */ - uint32 idm_device_id; /* 0x100 */ - uint32 PAD[15]; - uint32 idm_reset_ctrl; /* 0x140 */ -} amni_regs_t; - -#define NCI_SPINWAIT_TIMEOUT (300u) - -/* DMP/io control and DMP/io status */ -typedef struct dmp_regs { - uint32 dmpctrl; - uint32 dmpstatus; -} dmp_regs_t; - -#ifdef _RTE_ -static nci_info_t *knci_info = NULL; -#endif /* _RTE_ */ - -static void nci_save_iface1_reg(interface_desc_t *desc, uint32 iface_desc_1); -static uint32* nci_save_slaveport_addr(nci_info_t *nci, - interface_desc_t *desc, uint32 *erom2ptr); -static int nci_get_coreunit(nci_cores_t *cores, uint32 numcores, uint cid, - uint32 iface_desc_1); -static nci_cores_t* nci_initial_parse(nci_info_t *nci, uint32 *erom2ptr, uint32 *core_idx); -static void _nci_setcoreidx_pcie_bus(si_t *sih, volatile void **regs, uint32 curmap, - uint32 curwrap); -static volatile void *_nci_setcoreidx(si_t *sih, uint coreidx); -static uint32 _nci_get_curwrap(nci_info_t *nci, uint coreidx, uint wrapper_idx); -static uint32 nci_get_curwrap(nci_info_t *nci, uint coreidx); -static uint32 _nci_get_curmap(nci_info_t *nci, uint coreidx, uint slave_port_idx, uint base_idx); -static uint32 nci_get_curmap(nci_info_t *nci, uint coreidx); -static void _nci_core_reset(const si_t *sih, uint32 bits, uint32 resetbits); -#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) -static void nci_reset_APB(const si_info_t *sii, aidmp_t *ai, int *ret, - uint32 errlog_status, uint32 errlog_id); -static void nci_reset_axi_to(const si_info_t *sii, aidmp_t *ai); -#endif /* (AXI_TIMEOUTS) || (AXI_TIMEOUTS_NIC) */ -static uint32 nci_find_numcores(si_t *sih); -#ifdef BOOKER_NIC400_INF -static int32 nci_find_first_wrapper_idx(nci_info_t *nci, uint32 coreidx); -#endif /* BOOKER_NIC400_INF */ - -/* - * Description : This function will search for a CORE with matching 'core_id' and mismatching - * 'wordoffset', if found then increments 'coreunit' by 1. - */ -/* TODO: Need to understand this. */ -static int -BCMATTACHFN(nci_get_coreunit)(nci_cores_t *cores, uint32 numcores, - uint core_id, uint32 iface_desc_1) -{ - uint32 core_idx; - uint32 coreunit = NCI_DEFAULT_CORE_UNIT; - - for (core_idx = 0u; core_idx < numcores; core_idx++) { - if ((cores[core_idx].coreid == core_id) && - (GET_COREOFFSET(cores[core_idx].desc->iface_desc_1) != - GET_COREOFFSET(iface_desc_1))) { - coreunit = cores[core_idx].coreunit + 1; - } - } - - return coreunit; -} - -/* - * OOBR Region - +-------------------------------+ - + + - + OOBR with EROM Data + - + + - +-------------------------------+ - + + - + EROM1 + - + + - +-------------------------------+ --> ChipCommon.EROMBASE - + + - + EROM2 + - + + - +-------------------------------+ -*/ - -/** - * Function : nci_init - * Description : Malloc's memory related to 'nci_info_t' and its internal elements. - * - * @paramter[in] - * @regs : This is a ChipCommon Regster - * @bustype : Bus Connect Type - * - * Return : On Succes 'nci_info_t' data structure is returned as void, - * where all EROM parsed Cores are saved, - * using this all EROM Cores are Freed. - * On Failure 'NULL' is returned by printing ERROR messages - */ -void* -BCMATTACHFN(nci_init)(si_t *sih, chipcregs_t *cc, uint bustype) -{ - si_info_t *sii = SI_INFO(sih); - nci_cores_t *cores; - nci_info_t *nci = NULL; - uint8 err_at = 0u; - -#ifdef _RTE_ - if (knci_info) { - knci_info->refcnt++; - nci = knci_info; - - goto end; - } -#endif /* _RTE_ */ - - /* It is used only when NCI_ERROR is used */ - BCM_REFERENCE(err_at); - - if ((nci = MALLOCZ(sii->osh, sizeof(*nci))) == NULL) { - err_at = 1u; - goto end; - } - sii->nci_info = nci; - - nci->osh = sii->osh; - nci->refcnt++; - - nci->cc_erom2base = R_REG(nci->osh, &cc->eromptr); - nci->bustype = bustype; - switch (nci->bustype) { - case SI_BUS: - nci->erom2base = (uint32*)REG_MAP(nci->cc_erom2base, 0u); - nci->oobr_base = (uint32*)REG_MAP(GET_OOBR_BASE(nci->cc_erom2base), 0u); - nci->erom1base = (uint32*)REG_MAP(GET_EROM1_BASE(nci->cc_erom2base), 0u); - - break; - - case PCI_BUS: - /* Set wrappers address */ - sii->curwrap = (void *)((uintptr)cc + SI_CORE_SIZE); - /* Set access window to Erom Base(For NCI, EROM starts with OOBR) */ - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE, - GET_EROM1_BASE(nci->cc_erom2base)); - nci->erom1base = (uint32*)((uintptr)cc); - nci->erom2base = (uint32*)((uintptr)cc + NCI_EROM1_LEN(nci->cc_erom2base)); - - break; - - default: - err_at = 2u; - ASSERT(0u); - goto end; - } - - nci->max_cores = nci_find_numcores(sih); - if (!nci->max_cores) { - err_at = 3u; - goto end; - } - - if ((cores = MALLOCZ(nci->osh, sizeof(*cores) * nci->max_cores)) == NULL) { - err_at = 4u; - goto end; - } - nci->cores = cores; - -#ifdef _RTE_ - knci_info = nci; -#endif /* _RTE_ */ - -end: - if (err_at) { - NCI_ERROR(("nci_init: Failed err_at=%#x\n", err_at)); - nci_uninit(nci); - nci = NULL; - } - - return nci; -} - -/** - * Function : nci_uninit - * Description : Free's memory related to 'nci_info_t' and its internal malloc'd elements. - * - * @paramter[in] - * @nci : This is 'nci_info_t' data structure, where all EROM parsed Cores are saved, using this - * all EROM Cores are Freed. - * - * Return : void - */ -void -BCMATTACHFN(nci_uninit)(void *ctx) -{ - nci_info_t *nci = (nci_info_t *)ctx; - uint8 core_idx, desc_idx; - interface_desc_t *desc; - nci_cores_t *cores; - slave_port_t *sp; - - if (nci == NULL) { - return; - } - - nci->refcnt--; - -#ifdef _RTE_ - if (nci->refcnt != 0) { - return; - } -#endif /* _RTE_ */ - - cores = nci->cores; - if (cores == NULL) { - goto end; - } - - for (core_idx = 0u; core_idx < nci->num_cores; core_idx++) { - desc = cores[core_idx].desc; - if (desc == NULL) { - break; - } - - for (desc_idx = 0u; desc_idx < cores[core_idx].iface_cnt; desc_idx++) { - sp = desc[desc_idx].sp; - if (sp) { - MFREE(nci->osh, sp, (sizeof(*sp) * desc[desc_idx].num_addr_reg)); - } - } - MFREE(nci->osh, desc, (sizeof(*desc) * cores[core_idx].iface_cnt)); - } - MFREE(nci->osh, cores, sizeof(*cores) * nci->max_cores); - -end: - -#ifdef _RTE_ - knci_info = NULL; -#endif /* _RTE_ */ - - MFREE(nci->osh, nci, sizeof(*nci)); -} - -/** - * Function : nci_save_iface1_reg - * Description : Interface1 Descriptor is obtained from the Reg and saved in - * Internal data structures 'nci->cores'. - * - * @paramter[in] - * @desc : Descriptor of Core which needs to be updated with obatained Interface1 Descritpor. - * @iface_desc_1 : Obatained Interface1 Descritpor. - * - * Return : void - */ -static void -BCMATTACHFN(nci_save_iface1_reg)(interface_desc_t *desc, uint32 iface_desc_1) -{ - BCM_REFERENCE(BACKPLANE_ID_NAME); - - desc->coretype = GET_CORETYPE(iface_desc_1); - desc->master = IS_MASTER(iface_desc_1); - - desc->iface_desc_1 = iface_desc_1; - desc->num_addr_reg = GET_NUM_ADDR_REG(iface_desc_1); - if (desc->master) { - if (desc->num_addr_reg) { - NCI_ERROR(("nci_save_iface1_reg: Master NODEPTR Addresses is not zero " - "i.e. %d\n", GET_NUM_ADDR_REG(iface_desc_1))); - ASSERT(0u); - } - } else { - /* SLAVE 'NumAddressRegion' one less than actual slave ports, so increment by 1 */ - desc->num_addr_reg++; - } - - NCI_INFO(("\tnci_save_iface1_reg: %s InterfaceDesc:%#x WordOffset=%#x " - "NoAddrReg=%#x %s_Offset=%#x BackplaneID=%s\n", - desc->master?"Master":"Slave", desc->iface_desc_1, - GET_WORDOFFSET(desc->iface_desc_1), - desc->num_addr_reg, desc->coretype?"EROM1":"OOBR", - GET_COREOFFSET(desc->iface_desc_1), - BACKPLANE_ID_NAME[ID_BPID(desc->iface_desc_1)])); -} - -/** - * Function : nci_save_slaveport_addr - * Description : All Slave Port Addr of Interface Descriptor are saved. - * - * @paramter[in] - * @nci : This is 'nci_info_t' data structure, where all EROM parsed Cores are saved - * @desc : Current Interface Descriptor. - * @erom2ptr : Pointer to Address Descriptor0. - * - * Return : On Success, this function returns Erom2 Ptr to Next Interface Descriptor, - * On Failure, NULL is returned. - */ -static uint32* -BCMATTACHFN(nci_save_slaveport_addr)(nci_info_t *nci, - interface_desc_t *desc, uint32 *erom2ptr) -{ - slave_port_t *sp; - uint32 adesc; - uint32 sz; - uint32 addr_idx; - - /* Allocate 'NumAddressRegion' of Slave Port */ - if ((desc->sp = (slave_port_t *)MALLOCZ( - nci->osh, (sizeof(*sp) * desc->num_addr_reg))) == NULL) { - NCI_ERROR(("\tnci_save_slaveport_addr: Memory Allocation failed for Slave Port\n")); - return NULL; - } - - sp = desc->sp; - /* Slave Port Addrs Desc */ - for (addr_idx = 0u; addr_idx < desc->num_addr_reg; addr_idx++) { - adesc = R_REG(nci->osh, erom2ptr); - NCI_INC_ADDR(erom2ptr, NCI_WORD_SIZE); - sp[addr_idx].adesc = adesc; - - sp[addr_idx].addrl = adesc & SLAVEPORT_BASE_ADDR_MASK; - if (adesc & SLAVEPORT_64BIT_ADDR_MASK) { - sp[addr_idx].addrh = R_REG(nci->osh, erom2ptr); - NCI_INC_ADDR(erom2ptr, NCI_WORD_SIZE); - sp[addr_idx].extaddrl = R_REG(nci->osh, erom2ptr); - NCI_INC_ADDR(erom2ptr, NCI_WORD_SIZE); - sp[addr_idx].extaddrh = R_REG(nci->osh, erom2ptr); - NCI_INC_ADDR(erom2ptr, NCI_WORD_SIZE); - NCI_INFO(("\tnci_save_slaveport_addr: SlavePortAddr[%#x]:0x%08x al=0x%08x " - "ah=0x%08x extal=0x%08x extah=0x%08x\n", addr_idx, adesc, - sp[addr_idx].addrl, sp[addr_idx].addrh, sp[addr_idx].extaddrl, - sp[addr_idx].extaddrh)); - } - else if (adesc & SLAVEPORT_BOUND_ADDR_MASK) { - sp[addr_idx].addrh = R_REG(nci->osh, erom2ptr); - NCI_INC_ADDR(erom2ptr, NCI_WORD_SIZE); - NCI_INFO(("\tnci_save_slaveport_addr: SlavePortAddr[%#x]:0x%08x al=0x%08x " - "ah=0x%08x\n", addr_idx, adesc, sp[addr_idx].addrl, - sp[addr_idx].addrh)); - } else { - sz = adesc & SLAVEPORT_ADDR_SIZE_MASK; - sp[addr_idx].addrh = sp[addr_idx].addrl + ADDR_SIZE(sz); - NCI_INFO(("\tnci_save_slaveport_addr: SlavePortAddr[%#x]:0x%08x al=0x%08x " - "ah=0x%08x sz=0x%08x\n", addr_idx, adesc, sp[addr_idx].addrl, - sp[addr_idx].addrh, sz)); - } - } - - return erom2ptr; -} - -/** - * Function : nci_initial_parse - * Description : This function does - * 1. Obtains OOBR/EROM1 pointer based on CoreType - * 2. Analysis right CoreUnit for this 'core' - * 3. Saves CoreInfo & Interface Config in Coresponding 'core' - * - * @paramter[in] - * @nci : This is 'nci_info_t' data structure, where all EROM parsed Cores are saved. - * @erom2ptr : Pointer to Interface Descriptor0. - * @core_idx : New core index needs to be populated in this pointer. - * - * Return : On Success, this function returns 'core' where CoreInfo & Interface Config are saved. - */ -static nci_cores_t* -BCMATTACHFN(nci_initial_parse)(nci_info_t *nci, uint32 *erom2ptr, uint32 *core_idx) -{ - uint32 iface_desc_1; - nci_cores_t *core; - uint32 dmp_regs_off = 0u; - uint32 iface_cfg = 0u; - uint32 core_info; - uint32 *ptr; - uint coreid; - - iface_desc_1 = R_REG(nci->osh, erom2ptr); - - /* Get EROM1/OOBR Pointer based on CoreType */ - if (!GET_CORETYPE(iface_desc_1)) { - if (nci->bustype == PCI_BUS) { - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE, - GET_OOBR_BASE(nci->cc_erom2base)); - nci->oobr_base = (uint32*)((uintptr)nci->erom1base); - } - - ptr = NCI_ADD_ADDR(nci->oobr_base, GET_COREOFFSET(iface_desc_1)); - } else { - ptr = NCI_ADD_ADDR(nci->erom1base, GET_COREOFFSET(iface_desc_1)); - } - dmp_regs_off = GET_COREOFFSET(iface_desc_1) + DMP_DMPCTRL_REG_OFFSET; - - core_info = R_REG(nci->osh, ptr); - NCI_INC_ADDR(ptr, NCI_WORD_SIZE); - iface_cfg = R_REG(nci->osh, ptr); - - *core_idx = nci->num_cores; - core = &nci->cores[*core_idx]; - - if (CORE_ID(core_info) < 0xFFu) { - coreid = CORE_ID(core_info) | 0x800u; - } else { - coreid = CORE_ID(core_info); - } - - /* Get coreunit from previous cores i.e. num_cores */ - core->coreunit = nci_get_coreunit(nci->cores, nci->num_cores, - coreid, iface_desc_1); - - core->coreid = coreid; - - /* Increment the num_cores once proper coreunit is known */ - nci->num_cores++; - - NCI_INFO(("\n\nnci_initial_parse: core_idx:%d %s=%p \n", - *core_idx, GET_CORETYPE(iface_desc_1)?"EROM1":"OOBR", ptr)); - - /* Core Info Register */ - core->coreinfo = core_info; - - /* Save DMP register base address. */ - core->dmp_regs_off = dmp_regs_off; - - NCI_INFO(("\tnci_initial_parse: COREINFO:%#x CId:%#x CUnit=%#x CRev=%#x CMfg=%#x\n", - core->coreinfo, core->coreid, core->coreunit, CORE_REV(core->coreinfo), - CORE_MFG(core->coreinfo))); - - /* Interface Config Register */ - core->iface_cfg = iface_cfg; - core->iface_cnt = GET_INFACECNT(iface_cfg); - - NCI_INFO(("\tnci_initial_parse: INTERFACE_CFG:%#x IfaceCnt=%#x IfaceOffset=%#x \n", - iface_cfg, core->iface_cnt, iface_cfg & IC_IFACEOFFSET_MASK)); - - /* For PCI_BUS case set back BAR0 Window to EROM1 Base */ - if (nci->bustype == PCI_BUS) { - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE, - GET_EROM1_BASE(nci->cc_erom2base)); - } - - return core; -} - -static uint32 -BCMATTACHFN(nci_find_numcores)(si_t *sih) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - volatile hndoobr_reg_t *oobr_reg = NULL; - uint32 orig_bar0_win1 = 0u; - uint32 num_oobr_cores = 0u; - uint32 num_nonoobr_cores = 0u; - - /* No of Non-OOBR Cores */ - num_nonoobr_cores = NCI_NONOOBR_CORES(nci->cc_erom2base); - if (num_nonoobr_cores <= 0u) { - NCI_ERROR(("nci_find_numcores: Invalid Number of non-OOBR cores %d\n", - num_nonoobr_cores)); - goto fail; - } - - /* No of OOBR Cores */ - switch (BUSTYPE(sih->bustype)) { - case SI_BUS: - oobr_reg = (volatile hndoobr_reg_t*)REG_MAP(GET_OOBR_BASE(nci->cc_erom2base), - SI_CORE_SIZE); - break; - - case PCI_BUS: - /* Save Original Bar0 Win1 */ - orig_bar0_win1 = OSL_PCI_READ_CONFIG(nci->osh, PCI_BAR0_WIN, - PCI_ACCESS_SIZE); - - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE, - GET_OOBR_BASE(nci->cc_erom2base)); - oobr_reg = (volatile hndoobr_reg_t*)sii->curmap; - break; - - default: - NCI_ERROR(("nci_find_numcores: Invalid bustype %d\n", BUSTYPE(sih->bustype))); - ASSERT(0); - goto fail; - } - - num_oobr_cores = R_REG(nci->osh, &oobr_reg->capability) & OOBR_CAP_CORECNT_MASK; - if (num_oobr_cores <= 0u) { - NCI_ERROR(("nci_find_numcores: Invalid Number of OOBR cores %d\n", num_oobr_cores)); - goto fail; - } - - /* Point back to original base */ - if (BUSTYPE(sih->bustype) == PCI_BUS) { - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE, orig_bar0_win1); - } - - NCI_PRINT(("nci_find_numcores: Total Cores found %d\n", - (num_oobr_cores + num_nonoobr_cores))); - /* Total No of Cores */ - return (num_oobr_cores + num_nonoobr_cores); - -fail: - return 0u; -} - -/** - * Function : nci_scan - * Description : Function parses EROM in BOOKER NCI Architecture and saves all inforamtion about - * Cores in 'nci_info_t' data structure. - * - * @paramter[in] - * @nci : This is 'nci_info_t' data structure, where all EROM parsed Cores are saved. - * - * Return : On Success No of parsed Cores in EROM is returned, - * On Failure '0' is returned by printing ERROR messages - * in Console(If NCI_LOG_LEVEL is enabled). - */ -uint32 -BCMATTACHFN(nci_scan)(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = (nci_info_t *)sii->nci_info; - axi_wrapper_t * axi_wrapper = sii->axi_wrapper; - uint32 *cur_iface_desc_1_ptr; - nci_cores_t *core; - interface_desc_t *desc; - uint32 wordoffset = 0u; - uint32 iface_desc_0; - uint32 iface_desc_1; - uint32 *erom2ptr; - uint8 iface_idx; - uint32 core_idx; - int err = 0; - - /* If scan was finished already */ - if (nci->scan_done) { - goto end; - } - - erom2ptr = nci->erom2base; - sii->axi_num_wrappers = 0; - - while (TRUE) { - iface_desc_0 = R_REG(nci->osh, erom2ptr); - if (iface_desc_0 == ID_ENDMARKER) { - NCI_INFO(("\nnci_scan: Reached end of EROM2 with total cores=%d \n", - nci->num_cores)); - break; - } - - /* Save current Iface1 Addr for comparision */ - cur_iface_desc_1_ptr = GET_NEXT_EROM_ADDR(erom2ptr); - - /* Get CoreInfo, InterfaceCfg, CoreIdx */ - core = nci_initial_parse(nci, cur_iface_desc_1_ptr, &core_idx); - - core->desc = (interface_desc_t *)MALLOCZ( - nci->osh, (sizeof(*(core->desc)) * core->iface_cnt)); - if (core->desc == NULL) { - NCI_ERROR(("nci_scan: Mem Alloc failed for Iface and Addr " - "Descriptor\n")); - err = NCI_NOMEM; - break; - } - - for (iface_idx = 0u; iface_idx < core->iface_cnt; iface_idx++) { - desc = &core->desc[iface_idx]; - - iface_desc_0 = R_REG(nci->osh, erom2ptr); - NCI_INC_ADDR(erom2ptr, NCI_WORD_SIZE); - iface_desc_1 = R_REG(nci->osh, erom2ptr); - NCI_INC_ADDR(erom2ptr, NCI_WORD_SIZE); - - /* Interface Descriptor Register */ - nci_save_iface1_reg(desc, iface_desc_1); - if (desc->master && desc->num_addr_reg) { - err = NCI_MASTER_INVALID_ADDR; - goto end; - } - - wordoffset = GET_WORDOFFSET(iface_desc_1); - - /* NodePointer Register */ - desc->iface_desc_0 = iface_desc_0; - desc->node_ptr = GET_NODEPTR(iface_desc_0); - desc->node_type = GET_NODETYPE(iface_desc_0); - - if (axi_wrapper && (sii->axi_num_wrappers < SI_MAX_AXI_WRAPPERS)) { - axi_wrapper[sii->axi_num_wrappers].mfg = CORE_MFG(core->coreinfo); - axi_wrapper[sii->axi_num_wrappers].cid = CORE_ID(core->coreinfo); - axi_wrapper[sii->axi_num_wrappers].rev = CORE_REV(core->coreinfo); - axi_wrapper[sii->axi_num_wrappers].wrapper_type = desc->master; - axi_wrapper[sii->axi_num_wrappers].wrapper_addr = desc->node_ptr; - sii->axi_num_wrappers++; - } - - NCI_INFO(("nci_scan: %s NodePointer:%#x Type=%s NODEPTR=%#x \n", - desc->master?"Master":"Slave", desc->iface_desc_0, - desc->node_type?"NIC-400":"BOOKER", desc->node_ptr)); - - /* Slave Port Addresses */ - if (!desc->master) { - erom2ptr = nci_save_slaveport_addr(nci, desc, erom2ptr); - if (erom2ptr == NULL) { - NCI_ERROR(("nci_scan: Invalid EROM2PTR\n")); - err = NCI_INVALID_EROM2PTR; - goto end; - } - } - - /* Current loop ends with next iface_desc_0 */ - } - - if (wordoffset == 0u) { - NCI_INFO(("\nnci_scan: EROM PARSING found END 'wordoffset=%#x' " - "with total cores=%d \n", wordoffset, nci->num_cores)); - break; - } - } - nci->scan_done = TRUE; - -end: - if (err) { - NCI_ERROR(("nci_scan: Failed with Code %d\n", err)); - nci->num_cores = 0; - ASSERT(0u); - } - - return nci->num_cores; -} - -/** - * Function : nci_dump_erom - * Description : Function dumps EROM from inforamtion cores in 'nci_info_t' data structure. - * - * @paramter[in] - * @nci : This is 'nci_info_t' data structure, where all EROM parsed Cores are saved. - * - * Return : void - */ -void -BCMATTACHFN(nci_dump_erom)(void *ctx) -{ - nci_info_t *nci = (nci_info_t *)ctx; - nci_cores_t *core; - interface_desc_t *desc; - slave_port_t *sp; - uint32 core_idx, addr_idx, iface_idx; - uint32 core_info; - - BCM_REFERENCE(core_info); - - NCI_INFO(("\nnci_dump_erom: -- EROM Dump --\n")); - for (core_idx = 0u; core_idx < nci->num_cores; core_idx++) { - core = &nci->cores[core_idx]; - - /* Core Info Register */ - core_info = core->coreinfo; - NCI_INFO(("\nnci_dump_erom: core_idx=%d COREINFO:%#x CId:%#x CUnit:%#x CRev=%#x " - "CMfg=%#x\n", core_idx, core_info, CORE_ID(core_info), core->coreunit, - CORE_REV(core_info), CORE_MFG(core_info))); - - /* Interface Config Register */ - NCI_INFO(("nci_dump_erom: IfaceCfg=%#x IfaceCnt=%#x \n", - core->iface_cfg, core->iface_cnt)); - - for (iface_idx = 0u; iface_idx < core->iface_cnt; iface_idx++) { - desc = &core->desc[iface_idx]; - /* NodePointer Register */ - NCI_INFO(("nci_dump_erom: %s iface_desc_0 Master=%#x MASTER_WRAP=%#x " - "Type=%s \n", desc->master?"Master":"Slave", desc->iface_desc_0, - desc->node_ptr, - (desc->node_type)?"NIC-400":"BOOKER")); - - /* Interface Descriptor Register */ - NCI_INFO(("nci_dump_erom: %s InterfaceDesc:%#x WOffset=%#x NoAddrReg=%#x " - "%s_Offset=%#x\n", desc->master?"Master":"Slave", - desc->iface_desc_1, GET_WORDOFFSET(desc->iface_desc_1), - desc->num_addr_reg, - desc->coretype?"EROM1":"OOBR", GET_COREOFFSET(desc->iface_desc_1))); - - /* Slave Port Addresses */ - sp = desc->sp; - if (!sp) { - continue; - } - for (addr_idx = 0u; addr_idx < desc->num_addr_reg; addr_idx++) { - if (sp[addr_idx].extaddrl) { - NCI_INFO(("nci_dump_erom: SlavePortAddr[%#x]: AddrDesc=%#x" - " al=%#x ah=%#x extal=%#x extah=%#x\n", addr_idx, - sp[addr_idx].adesc, sp[addr_idx].addrl, - sp[addr_idx].addrh, sp[addr_idx].extaddrl, - sp[addr_idx].extaddrh)); - } else { - NCI_INFO(("nci_dump_erom: SlavePortAddr[%#x]: AddrDesc=%#x" - " al=%#x ah=%#x\n", addr_idx, sp[addr_idx].adesc, - sp[addr_idx].addrl, sp[addr_idx].addrh)); - } - } - } - } - - return; -} - -/* - * Switch to 'coreidx', issue a single arbitrary 32bit register mask & set operation, - * switch back to the original core, and return the new value. - */ -uint -BCMPOSTTRAPFN(nci_corereg)(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) -{ - uint origidx = 0; - volatile uint32 *r = NULL; - uint w; - bcm_int_bitmask_t intr_val; - bool fast = FALSE; - si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - nci_cores_t *cores_info = &nci->cores[coreidx]; - - NCI_TRACE(("nci_corereg coreidx %u regoff %u mask %u val %u\n", - coreidx, regoff, mask, val)); - ASSERT(GOODIDX(coreidx, nci->num_cores)); - ASSERT(regoff < SI_CORE_SIZE); - ASSERT((val & ~mask) == 0); - - if (coreidx >= SI_MAXCORES) { - return 0; - } - - if (BUSTYPE(sih->bustype) == SI_BUS) { - /* If internal bus, we can always get at everything */ - uint32 curmap = nci_get_curmap(nci, coreidx); - BCM_REFERENCE(curmap); - - fast = TRUE; - /* map if does not exist */ - if (!cores_info->regs) { - cores_info->regs = REG_MAP(curmap, SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs)); - } - r = (volatile uint32 *)((volatile uchar *)cores_info->regs + regoff); - } else if (BUSTYPE(sih->bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - - if ((cores_info->coreid == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - - fast = TRUE; - r = (volatile uint32 *)((volatile char *)sii->curmap + - PCI_16KB0_CCREGS_OFFSET + regoff); - } else if (sii->pub.buscoreidx == coreidx) { - /* pci registers are at either in the last 2KB of an 8KB window - * or, in pcie and pci rev 13 at 8KB - */ - fast = TRUE; - if (SI_FAST(sii)) { - r = (volatile uint32 *)((volatile char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - } else { - r = (volatile uint32 *)((volatile char *)sii->curmap + - ((regoff >= SBCONFIGOFF) ? - PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + regoff); - } - } - } - - if (!fast) { - INTR_OFF(sii, &intr_val); - - /* save current core index */ - origidx = si_coreidx(&sii->pub); - - /* switch core */ - r = (volatile uint32*)((volatile uchar*)nci_setcoreidx(&sii->pub, coreidx) + - regoff); - } - ASSERT(r != NULL); - - /* mask and set */ - if (mask || val) { - w = (R_REG(sii->osh, r) & ~mask) | val; - W_REG(sii->osh, r, w); - } - - /* readback */ - w = R_REG(sii->osh, r); - - if (!fast) { - /* restore core index */ - if (origidx != coreidx) { - nci_setcoreidx(&sii->pub, origidx); - } - INTR_RESTORE(sii, &intr_val); - } - - return (w); -} - -uint -nci_corereg_writeonly(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) -{ - uint origidx = 0; - volatile uint32 *r = NULL; - uint w = 0; - bcm_int_bitmask_t intr_val; - bool fast = FALSE; - si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - nci_cores_t *cores_info = &nci->cores[coreidx]; - - NCI_TRACE(("nci_corereg_writeonly() coreidx %u regoff %u mask %u val %u\n", - coreidx, regoff, mask, val)); - - ASSERT(GOODIDX(coreidx, nci->num_cores)); - ASSERT(regoff < SI_CORE_SIZE); - ASSERT((val & ~mask) == 0); - - if (coreidx >= SI_MAXCORES) { - return 0; - } - - if (BUSTYPE(sih->bustype) == SI_BUS) { - /* If internal bus, we can always get at everything */ - uint32 curmap = nci_get_curmap(nci, coreidx); - BCM_REFERENCE(curmap); - fast = TRUE; - /* map if does not exist */ - if (!cores_info->regs) { - cores_info->regs = REG_MAP(curmap, SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs)); - } - r = (volatile uint32 *)((volatile uchar *)cores_info->regs + regoff); - } else if (BUSTYPE(sih->bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - - if ((cores_info->coreid == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - - fast = TRUE; - r = (volatile uint32 *)((volatile char *)sii->curmap + - PCI_16KB0_CCREGS_OFFSET + regoff); - } else if (sii->pub.buscoreidx == coreidx) { - /* pci registers are at either in the last 2KB of an 8KB window - * or, in pcie and pci rev 13 at 8KB - */ - fast = TRUE; - if (SI_FAST(sii)) { - r = (volatile uint32 *)((volatile char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - } else { - r = (volatile uint32 *)((volatile char *)sii->curmap + - ((regoff >= SBCONFIGOFF) ? - PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + regoff); - } - } - } - - if (!fast) { - INTR_OFF(sii, &intr_val); - - /* save current core index */ - origidx = si_coreidx(&sii->pub); - - /* switch core */ - r = (volatile uint32*) ((volatile uchar*) nci_setcoreidx(&sii->pub, coreidx) + - regoff); - } - ASSERT(r != NULL); - - /* mask and set */ - if (mask || val) { - w = (R_REG(sii->osh, r) & ~mask) | val; - W_REG(sii->osh, r, w); - } - - if (!fast) { - /* restore core index */ - if (origidx != coreidx) { - nci_setcoreidx(&sii->pub, origidx); - } - - INTR_RESTORE(sii, &intr_val); - } - - return (w); -} - -/* - * If there is no need for fiddling with interrupts or core switches (typically silicon - * back plane registers, pci registers and chipcommon registers), this function - * returns the register offset on this core to a mapped address. This address can - * be used for W_REG/R_REG directly. - * - * For accessing registers that would need a core switch, this function will return - * NULL. - */ -volatile uint32 * -nci_corereg_addr(si_t *sih, uint coreidx, uint regoff) -{ - volatile uint32 *r = NULL; - bool fast = FALSE; - si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - nci_cores_t *cores_info = &nci->cores[coreidx]; - - NCI_TRACE(("nci_corereg_addr() coreidx %u regoff %u\n", coreidx, regoff)); - - ASSERT(GOODIDX(coreidx, nci->num_cores)); - ASSERT(regoff < SI_CORE_SIZE); - - if (coreidx >= SI_MAXCORES) { - return 0; - } - - if (BUSTYPE(sih->bustype) == SI_BUS) { - uint32 curmap = nci_get_curmap(nci, coreidx); - BCM_REFERENCE(curmap); - - /* If internal bus, we can always get at everything */ - fast = TRUE; - /* map if does not exist */ - if (!cores_info->regs) { - cores_info->regs = REG_MAP(curmap, SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs)); - } - r = (volatile uint32 *)((volatile uchar *)cores_info->regs + regoff); - - } else if (BUSTYPE(sih->bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - - if ((cores_info->coreid == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - - fast = TRUE; - r = (volatile uint32 *)((volatile char *)sii->curmap + - PCI_16KB0_CCREGS_OFFSET + regoff); - } else if (sii->pub.buscoreidx == coreidx) { - /* pci registers are at either in the last 2KB of an 8KB window - * or, in pcie and pci rev 13 at 8KB - */ - fast = TRUE; - if (SI_FAST(sii)) { - r = (volatile uint32 *)((volatile char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - } else { - r = (volatile uint32 *)((volatile char *)sii->curmap + - ((regoff >= SBCONFIGOFF) ? - PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + regoff); - } - } - } - - if (!fast) { - ASSERT(sii->curidx == coreidx); - r = (volatile uint32*) ((volatile uchar*)sii->curmap + regoff); - } - - return (r); -} - -uint -BCMPOSTTRAPFN(nci_findcoreidx)(const si_t *sih, uint coreid, uint coreunit) -{ - si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - uint core_idx; - - NCI_TRACE(("nci_findcoreidx() coreid %u coreunit %u\n", coreid, coreunit)); - - for (core_idx = 0; core_idx < nci->num_cores; core_idx++) { - if ((nci->cores[core_idx].coreid == coreid) && - (nci->cores[core_idx].coreunit == coreunit)) { - return core_idx; - } - } - return BADIDX; -} - -static uint32 -_nci_get_slave_addr_size(nci_info_t *nci, uint coreidx, uint32 slave_port_idx, uint base_idx) -{ - uint32 size; - uint32 add_desc; - - NCI_TRACE(("_nci_get_slave_addr_size() coreidx %u slave_port_idx %u base_idx %u\n", - coreidx, slave_port_idx, base_idx)); - - add_desc = nci->cores[coreidx].desc[slave_port_idx].sp[base_idx].adesc; - - size = add_desc & SLAVEPORT_ADDR_SIZE_MASK; - return ADDR_SIZE(size); -} - -static uint32 -BCMPOSTTRAPFN(_nci_get_curmap)(nci_info_t *nci, uint coreidx, uint slave_port_idx, uint base_idx) -{ - /* TODO: Is handling of 64 bit addressing required */ - NCI_TRACE(("_nci_get_curmap coreidx %u slave_port_idx %u base_idx %u\n", - coreidx, slave_port_idx, base_idx)); - return nci->cores[coreidx].desc[slave_port_idx].sp[base_idx].addrl; -} - -/* Get the interface descriptor which is connected to APB and return its address */ -static uint32 -BCMPOSTTRAPFN(nci_get_curmap)(nci_info_t *nci, uint coreidx) -{ - nci_cores_t *core_info = &nci->cores[coreidx]; - uint32 iface_idx; - - NCI_TRACE(("nci_get_curmap coreidx %u\n", coreidx)); - for (iface_idx = 0; iface_idx < core_info->iface_cnt; iface_idx++) { - NCI_TRACE(("nci_get_curmap iface_idx %u BP_ID %u master %u\n", - iface_idx, ID_BPID(core_info->desc[iface_idx].iface_desc_1), - IS_MASTER(core_info->desc[iface_idx].iface_desc_1))); - - /* If core is a Backplane or Bridge, then its slave port - * will give the pointer to access registers. - */ - if (!IS_MASTER(core_info->desc[iface_idx].iface_desc_1) && - (IS_BACKPLANE(core_info->coreinfo) || - APB_INF(core_info->desc[iface_idx]))) { - return _nci_get_curmap(nci, coreidx, iface_idx, 0); - } - } - - /* no valid slave port address is found */ - return NCI_BAD_REG; -} - -static uint32 -BCMPOSTTRAPFN(_nci_get_curwrap)(nci_info_t *nci, uint coreidx, uint wrapper_idx) -{ - return nci->cores[coreidx].desc[wrapper_idx].node_ptr; -} - -static uint32 -BCMPOSTTRAPFN(nci_get_curwrap)(nci_info_t *nci, uint coreidx) -{ - nci_cores_t *core_info = &nci->cores[coreidx]; - uint32 iface_idx; - NCI_TRACE(("nci_get_curwrap coreidx %u\n", coreidx)); - for (iface_idx = 0; iface_idx < core_info->iface_cnt; iface_idx++) { - NCI_TRACE(("nci_get_curwrap iface_idx %u BP_ID %u master %u\n", - iface_idx, ID_BPID(core_info->desc[iface_idx].iface_desc_1), - IS_MASTER(core_info->desc[iface_idx].iface_desc_1))); - if ((ID_BPID(core_info->desc[iface_idx].iface_desc_1) == BP_BOOKER) || - (ID_BPID(core_info->desc[iface_idx].iface_desc_1) == BP_NIC400)) { - return _nci_get_curwrap(nci, coreidx, iface_idx); - } - } - - /* no valid master wrapper found */ - return NCI_BAD_REG; -} - -static void -_nci_setcoreidx_pcie_bus(si_t *sih, volatile void **regs, uint32 curmap, - uint32 curwrap) -{ - si_info_t *sii = SI_INFO(sih); - - *regs = sii->curmap; - switch (sii->slice) { - case 0: /* main/first slice */ - /* point bar0 window */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, PCIE_WRITE_SIZE, curmap); - // TODO: why curwrap is zero i.e no master wrapper - if (curwrap != 0) { - if (PCIE_GEN2(sii)) { - OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_WIN2, - PCIE_WRITE_SIZE, curwrap); - } else { - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, - PCIE_WRITE_SIZE, curwrap); - } - } - break; - case 1: /* aux/second slice */ - /* PCIE GEN2 only for other slices */ - if (!PCIE_GEN2(sii)) { - /* other slices not supported */ - NCI_ERROR(("pci gen not supported for slice 1\n")); - ASSERT(0); - break; - } - - /* 0x4000 - 0x4fff: enum space 0x5000 - 0x5fff: wrapper space */ - - *regs = (volatile uint8 *)*regs + PCI_SEC_BAR0_WIN_OFFSET; - sii->curwrap = (void *)((uintptr)*regs + SI_CORE_SIZE); - - /* point bar0 window */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_CORE2_WIN, PCIE_WRITE_SIZE, curmap); - OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_CORE2_WIN2, PCIE_WRITE_SIZE, curwrap); - break; - - case 2: /* scan/third slice */ - /* PCIE GEN2 only for other slices */ - if (!PCIE_GEN2(sii)) { - /* other slices not supported */ - NCI_ERROR(("pci gen not supported for slice 1\n")); - ASSERT(0); - break; - } - /* 0x9000 - 0x9fff: enum space 0xa000 - 0xafff: wrapper space */ - *regs = (volatile uint8 *)*regs + PCI_SEC_BAR0_WIN_OFFSET; - sii->curwrap = (void *)((uintptr)*regs + SI_CORE_SIZE); - - /* point bar0 window */ - nci_corereg(sih, sih->buscoreidx, PCIE_TER_BAR0_WIN, ~0, curmap); - nci_corereg(sih, sih->buscoreidx, PCIE_TER_BAR0_WRAPPER, ~0, curwrap); - break; - default: - ASSERT(0); - break; - } -} - -static volatile void * -BCMPOSTTRAPFN(_nci_setcoreidx)(si_t *sih, uint coreidx) -{ - si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - nci_cores_t *cores_info = &nci->cores[coreidx]; - uint32 curmap, curwrap; - volatile void *regs = NULL; - - NCI_TRACE(("_nci_setcoreidx coreidx %u\n", coreidx)); - if (!GOODIDX(coreidx, nci->num_cores)) { - return (NULL); - } - /* - * If the user has provided an interrupt mask enabled function, - * then assert interrupts are disabled before switching the core. - */ - ASSERT((sii->intrsenabled_fn == NULL) || - !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); - - curmap = nci_get_curmap(nci, coreidx); - curwrap = nci_get_curwrap(nci, coreidx); - - switch (BUSTYPE(sih->bustype)) { - case SI_BUS: - /* map if does not exist */ - if (!cores_info->regs) { - cores_info->regs = REG_MAP(curmap, SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs)); - } - sii->curmap = regs = cores_info->regs; - sii->curwrap = REG_MAP(curwrap, SI_CORE_SIZE); - break; - - case PCI_BUS: - _nci_setcoreidx_pcie_bus(sih, ®s, curmap, curwrap); - break; - - default: - NCI_ERROR(("_nci_stcoreidx Invalid bustype %d\n", BUSTYPE(sih->bustype))); - break; - } - sii->curidx = coreidx; - return regs; -} - -volatile void * -BCMPOSTTRAPFN(nci_setcoreidx)(si_t *sih, uint coreidx) -{ - return _nci_setcoreidx(sih, coreidx); -} - -volatile void * -BCMPOSTTRAPFN(nci_setcore)(si_t *sih, uint coreid, uint coreunit) -{ - si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - uint core_idx; - - NCI_TRACE(("nci_setcore coreidx %u coreunit %u\n", coreid, coreunit)); - core_idx = nci_findcoreidx(sih, coreid, coreunit); - - if (!GOODIDX(core_idx, nci->num_cores)) { - return (NULL); - } - return nci_setcoreidx(sih, core_idx); -} - -/* Get the value of the register at offset "offset" of currently configured core */ -uint -BCMPOSTTRAPFN(nci_get_wrap_reg)(const si_t *sih, uint32 offset, uint32 mask, uint32 val) -{ - const si_info_t *sii = SI_INFO(sih); - uint32 *addr = (uint32 *) ((uchar *)(sii->curwrap) + offset); - NCI_TRACE(("nci_wrap_reg offset %u mask %u val %u\n", offset, mask, val)); - - if (mask || val) { - uint32 w = R_REG(sii->osh, addr); - w &= ~mask; - w |= val; - W_REG(sii->osh, addr, w); - } - return (R_REG(sii->osh, addr)); -} - -uint -nci_corevendor(const si_t *sih) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - - NCI_TRACE(("nci_corevendor coreidx %u\n", sii->curidx)); - return (nci->cores[sii->curidx].coreinfo & COREINFO_MFG_MASK) >> COREINFO_MFG_SHIFT; -} - -uint -BCMPOSTTRAPFN(nci_corerev)(const si_t *sih) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - uint coreidx = sii->curidx; - - NCI_TRACE(("nci_corerev coreidx %u\n", coreidx)); - - return (nci->cores[coreidx].coreinfo & COREINFO_REV_MASK) >> COREINFO_REV_SHIFT; -} - -uint -nci_corerev_minor(const si_t *sih) -{ - return (nci_core_sflags(sih, 0, 0) >> SISF_MINORREV_D11_SHIFT) & - SISF_MINORREV_D11_MASK; -} - -uint -BCMPOSTTRAPFN(nci_coreid)(const si_t *sih, uint coreidx) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - - NCI_TRACE(("nci_coreid coreidx %u\n", coreidx)); - return nci->cores[coreidx].coreid; -} - -/** return total coreunit of coreid or zero if not found */ -uint -BCMPOSTTRAPFN(nci_numcoreunits)(const si_t *sih, uint coreid) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - uint found = 0; - uint i; - - NCI_TRACE(("nci_numcoreunits coreidx %u\n", coreid)); - - for (i = 0; i < nci->num_cores; i++) { - if (nci->cores[i].coreid == coreid) { - found++; - } - } - - return found; -} - -/* Return the address of the nth address space in the current core - * Arguments: - * sih : Pointer to struct si_t - * spidx : slave port index - * baidx : base address index - */ -uint32 -nci_addr_space(const si_t *sih, uint spidx, uint baidx) -{ - const si_info_t *sii = SI_INFO(sih); - uint cidx; - - NCI_TRACE(("nci_addr_space spidx %u baidx %u\n", spidx, baidx)); - cidx = sii->curidx; - return _nci_get_curmap(sii->nci_info, cidx, spidx, baidx); -} - -/* Return the size of the nth address space in the current core -* Arguments: -* sih : Pointer to struct si_t -* spidx : slave port index -* baidx : base address index -*/ -uint32 -nci_addr_space_size(const si_t *sih, uint spidx, uint baidx) -{ - const si_info_t *sii = SI_INFO(sih); - uint cidx; - - NCI_TRACE(("nci_addr_space_size spidx %u baidx %u\n", spidx, baidx)); - - cidx = sii->curidx; - return _nci_get_slave_addr_size(sii->nci_info, cidx, spidx, baidx); -} - -/* - * Performs soft reset of attached device. - * Writes have the following effect: - * 0b1 Request attached device to enter reset. - * Write is ignored if it occurs before soft reset exit has occurred. - * - * 0b0 Request attached device to exit reset. - * Write is ignored if it occurs before soft reset entry has occurred. - * - * Software can poll this register to determine whether soft reset entry or exit has occurred, - * using the following values: - * 0b1 Indicates that the device is in reset. - * 0b0 Indicates that the device is not in reset. - * - * - * Note - * The register value updates to reflect a request for reset entry or reset exit, - * but the update can only occur after required internal conditions are met. - * Until these conditions are met, a read to the register returns the old value. - * For example, outstanding transactions currently being handled must complete before - * the register value updates. - * - * To ensure reset propagation within the device, - * it is the responsibility of software to allow enough cycles after - * soft reset assertion is reflected in the reset control register - * before exiting soft reset by triggering a write of 0b0. - * If this responsibility is not met, the behavior is undefined or unpredictable. - * - * When the register value is 0b1, - * the external soft reset pin that connects to the attached AXI master or slave - * device is asserted, using the correct polarity of the reset pin. - * When the register value is 0b0, the external softreset - * pin that connects to the attached AXI master or slave device is deasserted, - * using the correct polarity of the reset pin. - */ -static void -BCMPOSTTRAPFN(_nci_core_reset)(const si_t *sih, uint32 bits, uint32 resetbits) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - amni_regs_t *amni = (amni_regs_t *)(uintptr)sii->curwrap; - volatile dmp_regs_t *io; - volatile uint32* erom_base = 0u; - uint32 orig_bar0_win1 = 0u; - volatile uint32 dummy; - volatile uint32 reg_read; - uint32 dmp_write_value; - - /* Point to OOBR base */ - switch (BUSTYPE(sih->bustype)) { - case SI_BUS: - erom_base = (volatile uint32*)REG_MAP(GET_OOBR_BASE(nci->cc_erom2base), - SI_CORE_SIZE); - break; - - case PCI_BUS: - /* - * Save Original Bar0 Win1. In nci, the io registers dmpctrl & dmpstatus - * registers are implemented in the EROM section. REF - - * https://docs.google.com/document/d/1HE7hAmvdoNFSnMI7MKQV1qVrFBZVsgLdNcILNOA2C8c - * This requires addition BAR0 windows mapping to erom section in chipcommon. - */ - orig_bar0_win1 = OSL_PCI_READ_CONFIG(nci->osh, PCI_BAR0_WIN, - PCI_ACCESS_SIZE); - - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE, - GET_OOBR_BASE(nci->cc_erom2base)); - erom_base = (volatile uint32*)sii->curmap; - break; - - default: - NCI_ERROR(("_nci_core_reset Invalid bustype %d\n", BUSTYPE(sih->bustype))); - break; - } - - /* Point to DMP Control */ - io = (dmp_regs_t*)(NCI_ADD_ADDR(erom_base, nci->cores[sii->curidx].dmp_regs_off)); - - NCI_TRACE(("_nci_core_reset reg 0x%p io %p\n", amni, io)); - - /* Put core into reset */ - W_REG(nci->osh, &amni->idm_reset_ctrl, NI_IDM_RESET_ENTRY); - - /* poll for the reset to happen */ - while (TRUE) { - /* Wait until reset is effective */ - SPINWAIT(((reg_read = R_REG(nci->osh, &amni->idm_reset_ctrl)) != - NI_IDM_RESET_ENTRY), NCI_SPINWAIT_TIMEOUT); - - if (reg_read == NI_IDM_RESET_ENTRY) { - break; - } - } - - dmp_write_value = (bits | resetbits | SICF_FGC | SICF_CLOCK_EN); - - W_REG(nci->osh, &io->dmpctrl, dmp_write_value); - - /* poll for the dmp_reg write to happen */ - while (TRUE) { - /* Wait until reset is effective */ - SPINWAIT(((reg_read = R_REG(nci->osh, &io->dmpctrl)) != - dmp_write_value), NCI_SPINWAIT_TIMEOUT); - if (reg_read == dmp_write_value) { - break; - } - } - - /* take core out of reset */ - W_REG(nci->osh, &amni->idm_reset_ctrl, 0u); - - /* poll for the core to come out of reset */ - while (TRUE) { - /* Wait until reset is effected */ - SPINWAIT(((reg_read = R_REG(nci->osh, &amni->idm_reset_ctrl)) != - NI_IDM_RESET_EXIT), NCI_SPINWAIT_TIMEOUT); - if (reg_read == NI_IDM_RESET_EXIT) { - break; - } - } - - dmp_write_value = (bits | SICF_CLOCK_EN); - W_REG(nci->osh, &io->dmpctrl, (bits | SICF_CLOCK_EN)); - /* poll for the core to come out of reset */ - while (TRUE) { - SPINWAIT(((reg_read = R_REG(nci->osh, &io->dmpctrl)) != - dmp_write_value), NCI_SPINWAIT_TIMEOUT); - if (reg_read == dmp_write_value) { - break; - } - } - - dummy = R_REG(nci->osh, &io->dmpctrl); - BCM_REFERENCE(dummy); - - /* Point back to original base */ - if (BUSTYPE(sih->bustype) == PCI_BUS) { - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE, orig_bar0_win1); - } -} - -/* reset and re-enable a core - */ -void -BCMPOSTTRAPFN(nci_core_reset)(const si_t *sih, uint32 bits, uint32 resetbits) -{ - const si_info_t *sii = SI_INFO(sih); - int32 iface_idx = 0u; - nci_info_t *nci = sii->nci_info; - nci_cores_t *core = &nci->cores[sii->curidx]; - - /* If Wrapper is of NIC400, then call AI functionality */ - for (iface_idx = core->iface_cnt-1; iface_idx >= 0; iface_idx--) { - if (!(BOOKER_INF(core->desc[iface_idx]) || NIC_INF(core->desc[iface_idx]))) { - continue; - } -#ifdef BOOKER_NIC400_INF - if (core->desc[iface_idx].node_type == NODE_TYPE_NIC400) { - ai_core_reset_ext(sih, bits, resetbits); - } else -#endif /* BOOKER_NIC400_INF */ - { - _nci_core_reset(sih, bits, resetbits); - } - } -} - -#ifdef BOOKER_NIC400_INF -static int32 -BCMPOSTTRAPFN(nci_find_first_wrapper_idx)(nci_info_t *nci, uint32 coreidx) -{ - nci_cores_t *core_info = &nci->cores[coreidx]; - uint32 iface_idx; - - NCI_TRACE(("nci_find_first_wrapper_idx %u\n", coreidx)); - - for (iface_idx = 0; iface_idx < core_info->iface_cnt; iface_idx++) { - NCI_INFO(("nci_find_first_wrapper_idx: %u BP_ID %u master %u\n", - iface_idx, ID_BPID(core_info->desc[iface_idx].iface_desc_1), - IS_MASTER(core_info->desc[iface_idx].iface_desc_1))); - - if ((ID_BPID(core_info->desc[iface_idx].iface_desc_1) == BP_BOOKER) || - (ID_BPID(core_info->desc[iface_idx].iface_desc_1) == BP_NIC400)) { - return iface_idx; - } - } - - /* no valid master wrapper found */ - return NCI_BAD_INDEX; -} -#endif /* BOOKER_NIC400_INF */ - -void -nci_core_disable(const si_t *sih, uint32 bits) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - uint32 reg_read; - volatile dmp_regs_t *io = NULL; - uint32 orig_bar0_win1 = 0u; - uint32 dmp_write_value; - amni_regs_t *amni = (amni_regs_t *)(uintptr)sii->curwrap; - nci_cores_t *core = &nci->cores[sii->curidx]; - int32 iface_idx; - - NCI_TRACE(("nci_core_disable\n")); - - BCM_REFERENCE(core); - BCM_REFERENCE(iface_idx); - -#ifdef BOOKER_NIC400_INF - iface_idx = nci_find_first_wrapper_idx(nci, sii->curidx); - - if (iface_idx < 0) { - NCI_ERROR(("nci_core_disable: First Wrapper is not found\n")); - ASSERT(0u); - return; - } - - /* If Wrapper is of NIC400, then call AI functionality */ - if (core->desc[iface_idx].master && (core->desc[iface_idx].node_type == NODE_TYPE_NIC400)) { - return ai_core_disable(sih, bits); - } -#endif /* BOOKER_NIC400_INF */ - - ASSERT(GOODREGS(sii->curwrap)); - reg_read = R_REG(nci->osh, &amni->idm_reset_ctrl); - - /* if core is already in reset, just return */ - if (reg_read == NI_IDM_RESET_ENTRY) { - return; - } - - /* Put core into reset */ - W_REG(nci->osh, &amni->idm_reset_ctrl, NI_IDM_RESET_ENTRY); - while (TRUE) { - /* Wait until reset is effected */ - SPINWAIT(((reg_read = R_REG(nci->osh, &amni->idm_reset_ctrl)) != - NI_IDM_RESET_ENTRY), NCI_SPINWAIT_TIMEOUT); - if (reg_read == NI_IDM_RESET_ENTRY) { - break; - } - } - - /* Point to OOBR base */ - switch (BUSTYPE(sih->bustype)) { - case SI_BUS: - io = (volatile dmp_regs_t*) - REG_MAP(GET_OOBR_BASE(nci->cc_erom2base), SI_CORE_SIZE); - break; - - case PCI_BUS: - /* Save Original Bar0 Win1 */ - orig_bar0_win1 = - OSL_PCI_READ_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE); - - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE, - GET_OOBR_BASE(nci->cc_erom2base)); - io = (volatile dmp_regs_t*)sii->curmap; - break; - - default: - NCI_ERROR(("nci_core_disable Invalid bustype %d\n", BUSTYPE(sih->bustype))); - break; - - } - - /* Point to DMP Control */ - io = (dmp_regs_t*)(NCI_ADD_ADDR(io, nci->cores[sii->curidx].dmp_regs_off)); - - dmp_write_value = (bits | SICF_FGC | SICF_CLOCK_EN); - W_REG(nci->osh, &io->dmpctrl, dmp_write_value); - - /* poll for the dmp_reg write to happen */ - while (TRUE) { - /* Wait until reset is effected */ - SPINWAIT(((reg_read = R_REG(nci->osh, &io->dmpctrl)) != dmp_write_value), - NCI_SPINWAIT_TIMEOUT); - if (reg_read == dmp_write_value) { - break; - } - } - - /* Point back to original base */ - if (BUSTYPE(sih->bustype) == PCI_BUS) { - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE, orig_bar0_win1); - } -} - -bool -BCMPOSTTRAPFN(nci_iscoreup)(const si_t *sih) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - amni_regs_t *ni = (amni_regs_t *)(uintptr)sii->curwrap; - uint32 reset_ctrl; - -#ifdef BOOKER_NIC400_INF - nci_cores_t *core = &nci->cores[sii->curidx]; - int32 iface_idx = nci_find_first_wrapper_idx(nci, sii->curidx); - - if (iface_idx < 0) { - NCI_ERROR(("nci_iscoreup: First Wrapper is not found\n")); - ASSERT(0u); - return FALSE; - } - - /* If Wrapper is of NIC400, then call AI functionality */ - if (core->desc[iface_idx].master && (core->desc[iface_idx].node_type == NODE_TYPE_NIC400)) { - return ai_iscoreup(sih); - } -#endif /* BOOKER_NIC400_INF */ - - NCI_TRACE(("nci_iscoreup\n")); - reset_ctrl = R_REG(nci->osh, &ni->idm_reset_ctrl); - - return (reset_ctrl == NI_IDM_RESET_ENTRY) ? FALSE : TRUE; -} - -/* TODO: OOB Router core is not available. Can be removed. */ -uint -nci_intflag(si_t *sih) -{ - return 0; -} - -uint -nci_flag(si_t *sih) -{ - /* TODO: will be implemented if required for NCI */ - return 0; -} - -uint -nci_flag_alt(const si_t *sih) -{ - /* TODO: will be implemented if required for NCI */ - return 0; -} - -void -BCMATTACHFN(nci_setint)(const si_t *sih, int siflag) -{ - BCM_REFERENCE(sih); - BCM_REFERENCE(siflag); - - /* TODO: Figure out how to set interrupt mask in nci */ -} - -/* TODO: OOB Router core is not available. Can we remove or need an alternate implementation. */ -uint32 -nci_oobr_baseaddr(const si_t *sih, bool second) -{ - return 0; -} - -uint -nci_coreunit(const si_t *sih) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - nci_cores_t *cores = nci->cores; - uint idx; - uint coreid; - uint coreunit; - uint i; - - coreunit = 0; - - idx = sii->curidx; - - ASSERT(GOODREGS(sii->curmap)); - coreid = nci_coreid(sih, sii->curidx); - - /* count the cores of our type */ - for (i = 0; i < idx; i++) { - if (cores[i].coreid == coreid) { - coreunit++; - } - } - - return (coreunit); -} - -uint -nci_corelist(const si_t *sih, uint coreid[]) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - nci_cores_t *cores = nci->cores; - uint32 i; - - for (i = 0; i < sii->numcores; i++) { - coreid[i] = cores[i].coreid; - } - - return (sii->numcores); -} - -/* Return the number of address spaces in current core */ -int -BCMATTACHFN(nci_numaddrspaces)(const si_t *sih) -{ - /* TODO: Either save it or parse the EROM on demand, currently hardcode 2 */ - BCM_REFERENCE(sih); - - return 2; -} - -/* The value of wrap_pos should be greater than 0 */ -/* wrapba, wrapba2 and wrapba3 */ -uint32 -nci_get_nth_wrapper(const si_t *sih, int32 wrap_pos) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - const nci_cores_t *core_info = &nci->cores[sii->curidx]; - uint32 iface_idx; - uint32 addr = 0; - - ASSERT(wrap_pos >= 0); - if (wrap_pos < 0) { - return addr; - } - - NCI_TRACE(("nci_get_curmap coreidx %u\n", sii->curidx)); - for (iface_idx = 0; iface_idx < core_info->iface_cnt; iface_idx++) { - NCI_TRACE(("nci_get_curmap iface_idx %u BP_ID %u master %u\n", - iface_idx, ID_BPID(core_info->desc[iface_idx].iface_desc_1), - IS_MASTER(core_info->desc[iface_idx].iface_desc_1))); - /* hack for core idx 8, coreidx without APB Backplane ID */ - if (!IS_MASTER(core_info->desc[iface_idx].iface_desc_1)) { - continue; - } - /* TODO: Should the interface be only BOOKER or NIC is also fine. */ - if (GET_NODETYPE(core_info->desc[iface_idx].iface_desc_0) != NODE_TYPE_BOOKER) { - continue; - } - /* Iterate till we do not get a wrapper at nth (wrap_pos) position */ - if (wrap_pos == 0) { - break; - } - wrap_pos--; - } - if (iface_idx < core_info->iface_cnt) { - addr = GET_NODEPTR(core_info->desc[iface_idx].iface_desc_0); - } - return addr; -} - -/* Get slave port address of the 0th slave (csp2ba) */ -uint32 -nci_get_axi_addr(const si_t *sih, uint32 *size) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - const nci_cores_t *core_info = (const nci_cores_t *)&nci->cores[sii->curidx]; - uint32 iface_idx; - uint32 addr = 0; - - NCI_TRACE(("nci_get_curmap coreidx %u\n", sii->curidx)); - for (iface_idx = 0; iface_idx < core_info->iface_cnt; iface_idx++) { - NCI_TRACE(("nci_get_curmap iface_idx %u BP_ID %u master %u\n", - iface_idx, ID_BPID(core_info->desc[iface_idx].iface_desc_1), - IS_MASTER(core_info->desc[iface_idx].iface_desc_1))); - if (IS_MASTER(core_info->desc[iface_idx].iface_desc_1)) { - continue; - } - if ((ID_BPID(core_info->desc[iface_idx].iface_desc_1) == BP_BOOKER) || - (ID_BPID(core_info->desc[iface_idx].iface_desc_1) == BP_NIC400)) { - break; - } - } - if (iface_idx < core_info->iface_cnt) { - /* - * TODO: Is there any case where we need to return the slave port address - * corresponding to index other than 0. - */ - if (&core_info->desc[iface_idx].sp[0] != NULL) { - addr = core_info->desc[iface_idx].sp[0].addrl; - if (size) { - uint32 adesc = core_info->desc[iface_idx].sp[0].adesc; - *size = SLAVEPORT_ADDR_SIZE(adesc); - } - } - } - return addr; -} - -/* spidx shouldbe the index of the slave port which we are expecting. - * The value will vary from 0 to num_addr_reg. - */ -/* coresba and coresba2 */ -uint32 -nci_get_core_baaddr(const si_t *sih, uint32 *size, int32 baidx) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - const nci_cores_t *core_info = (const nci_cores_t *)&nci->cores[sii->curidx]; - uint32 iface_idx; - uint32 addr = 0; - - NCI_TRACE(("nci_get_curmap coreidx %u\n", sii->curidx)); - for (iface_idx = 0; iface_idx < core_info->iface_cnt; iface_idx++) { - NCI_TRACE(("nci_get_curmap iface_idx %u BP_ID %u master %u\n", - iface_idx, ID_BPID(core_info->desc[iface_idx].iface_desc_1), - IS_MASTER(core_info->desc[iface_idx].iface_desc_1))); - /* hack for core idx 8, coreidx without APB Backplane ID */ - if (IS_MASTER(core_info->desc[iface_idx].iface_desc_1)) { - continue; - } - if ((ID_BPID(core_info->desc[iface_idx].iface_desc_1) == BP_APB1) || - (ID_BPID(core_info->desc[iface_idx].iface_desc_1) == BP_APB2)) { - break; - } - } - if (iface_idx < core_info->iface_cnt) { - /* - * TODO: Is there any case where we need to return the slave port address - * corresponding to index other than 0. - */ - if ((core_info->desc[iface_idx].num_addr_reg > baidx) && - (&core_info->desc[iface_idx].sp[baidx] != NULL)) { - addr = core_info->desc[iface_idx].sp[baidx].addrl; - if (size) { - uint32 adesc = core_info->desc[iface_idx].sp[0].adesc; - *size = SLAVEPORT_ADDR_SIZE(adesc); - } - } - } - return addr; -} - -uint32 -nci_addrspace(const si_t *sih, uint spidx, uint baidx) -{ - if (spidx == CORE_SLAVE_PORT_0) { - if (baidx == CORE_BASE_ADDR_0) { - return nci_get_core_baaddr(sih, NULL, CORE_BASE_ADDR_0); - } else if (baidx == CORE_BASE_ADDR_1) { - return nci_get_core_baaddr(sih, NULL, CORE_BASE_ADDR_1); - } - } else if (spidx == CORE_SLAVE_PORT_1) { - if (baidx == CORE_BASE_ADDR_0) { - return nci_get_axi_addr(sih, NULL); - } - } - - SI_ERROR(("nci_addrspace: Need to parse the erom again to find %d base addr" - " in %d slave port\n", baidx, spidx)); - - return 0; -} - -uint32 -BCMATTACHFN(nci_addrspacesize)(const si_t *sih, uint spidx, uint baidx) -{ - uint32 size = 0; - - if (spidx == CORE_SLAVE_PORT_0) { - if (baidx == CORE_BASE_ADDR_0) { - nci_get_core_baaddr(sih, &size, CORE_BASE_ADDR_0); - goto done; - } else if (baidx == CORE_BASE_ADDR_1) { - nci_get_core_baaddr(sih, &size, CORE_BASE_ADDR_1); - goto done; - } - } else if (spidx == CORE_SLAVE_PORT_1) { - if (baidx == CORE_BASE_ADDR_0) { - nci_get_axi_addr(sih, &size); - goto done; - } - } - - SI_ERROR(("nci_addrspacesize: Need to parse the erom again to find %d" - " base addr in %d slave port\n", baidx, spidx)); -done: - return size; -} - -uint32 -BCMPOSTTRAPFN(nci_core_cflags)(const si_t *sih, uint32 mask, uint32 val) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - nci_cores_t *core = &nci->cores[sii->curidx]; - uint32 orig_bar0_win1 = 0; - int32 iface_idx; - uint32 w; - - BCM_REFERENCE(iface_idx); - - if ((core[sii->curidx].coreid) == PMU_CORE_ID) { - NCI_ERROR(("nci_core_cflags: Accessing PMU DMP register (ioctrl)\n")); - return 0; - } - - ASSERT(GOODREGS(sii->curwrap)); - ASSERT((val & ~mask) == 0); - -#ifdef BOOKER_NIC400_INF - iface_idx = nci_find_first_wrapper_idx(nci, sii->curidx); - if (iface_idx < 0) { - NCI_ERROR(("nci_core_cflags: First Wrapper is not found\n")); - ASSERT(0u); - return 0u; - } - - /* If Wrapper is of NIC400, then call AI functionality */ - if (core->desc[iface_idx].master && (core->desc[iface_idx].node_type == NODE_TYPE_NIC400)) { - aidmp_t *ai = sii->curwrap; - - if (mask || val) { - w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); - W_REG(sii->osh, &ai->ioctrl, w); - } - return R_REG(sii->osh, &ai->ioctrl); - } else -#endif /* BOOKER_NIC400_INF */ - { - volatile dmp_regs_t *io = sii->curwrap; - volatile uint32 reg_read; - - /* BOOKER */ - /* Point to OOBR base */ - switch (BUSTYPE(sih->bustype)) { - case SI_BUS: - io = (volatile dmp_regs_t*) - REG_MAP(GET_OOBR_BASE(nci->cc_erom2base), SI_CORE_SIZE); - break; - - case PCI_BUS: - /* Save Original Bar0 Win1 */ - orig_bar0_win1 = - OSL_PCI_READ_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE); - - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE, - GET_OOBR_BASE(nci->cc_erom2base)); - io = (volatile dmp_regs_t*)sii->curmap; - break; - - default: - NCI_ERROR(("nci_core_cflags Invalid bustype %d\n", BUSTYPE(sih->bustype))); - break; - - } - - /* Point to DMP Control */ - io = (dmp_regs_t*)(NCI_ADD_ADDR(io, nci->cores[sii->curidx].dmp_regs_off)); - - if (mask || val) { - w = ((R_REG(sii->osh, &io->dmpctrl) & ~mask) | val); - W_REG(sii->osh, &io->dmpctrl, w); - } - - reg_read = R_REG(sii->osh, &io->dmpctrl); - - /* Point back to original base */ - if (BUSTYPE(sih->bustype) == PCI_BUS) { - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, - PCI_ACCESS_SIZE, orig_bar0_win1); - } - - return reg_read; - } -} - -void -BCMPOSTTRAPFN(nci_core_cflags_wo)(const si_t *sih, uint32 mask, uint32 val) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - nci_cores_t *core = &nci->cores[sii->curidx]; - volatile dmp_regs_t *io = sii->curwrap; - uint32 orig_bar0_win1 = 0; - int32 iface_idx; - uint32 w; - - BCM_REFERENCE(iface_idx); - - if ((core[sii->curidx].coreid) == PMU_CORE_ID) { - NCI_ERROR(("nci_core_cflags: Accessing PMU DMP register (ioctrl)\n")); - return; - } - - ASSERT(GOODREGS(sii->curwrap)); - ASSERT((val & ~mask) == 0); - -#ifdef BOOKER_NIC400_INF - iface_idx = nci_find_first_wrapper_idx(nci, sii->curidx); - if (iface_idx < 0) { - NCI_ERROR(("nci_core_cflags_wo: First Wrapper is not found\n")); - ASSERT(0u); - return; - } - - /* If Wrapper is of NIC400, then call AI functionality */ - if (core->desc[iface_idx].master && (core->desc[iface_idx].node_type == NODE_TYPE_NIC400)) { - aidmp_t *ai = sii->curwrap; - if (mask || val) { - w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); - W_REG(sii->osh, &ai->ioctrl, w); - } - } else -#endif /* BOOKER_NIC400_INF */ - { - /* BOOKER */ - /* Point to OOBR base */ - switch (BUSTYPE(sih->bustype)) { - case SI_BUS: - io = (volatile dmp_regs_t*) - REG_MAP(GET_OOBR_BASE(nci->cc_erom2base), SI_CORE_SIZE); - break; - - case PCI_BUS: - /* Save Original Bar0 Win1 */ - orig_bar0_win1 = - OSL_PCI_READ_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE); - - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE, - GET_OOBR_BASE(nci->cc_erom2base)); - io = (volatile dmp_regs_t*)sii->curmap; - break; - - default: - NCI_ERROR(("nci_core_cflags_wo Invalid bustype %d\n", - BUSTYPE(sih->bustype))); - break; - } - - /* Point to DMP Control */ - io = (dmp_regs_t*)(NCI_ADD_ADDR(io, nci->cores[sii->curidx].dmp_regs_off)); - - if (mask || val) { - w = ((R_REG(sii->osh, &io->dmpctrl) & ~mask) | val); - W_REG(sii->osh, &io->dmpctrl, w); - } - - /* Point back to original base */ - if (BUSTYPE(sih->bustype) == PCI_BUS) { - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, - PCI_ACCESS_SIZE, orig_bar0_win1); - } - } -} - -uint32 -nci_core_sflags(const si_t *sih, uint32 mask, uint32 val) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - nci_cores_t *core = &nci->cores[sii->curidx]; - uint32 orig_bar0_win1 = 0; - int32 iface_idx; - uint32 w; - - BCM_REFERENCE(iface_idx); - - if ((core[sii->curidx].coreid) == PMU_CORE_ID) { - NCI_ERROR(("nci_core_sflags: Accessing PMU DMP register (ioctrl)\n")); - return 0; - } - - ASSERT(GOODREGS(sii->curwrap)); - - ASSERT((val & ~mask) == 0); - ASSERT((mask & ~SISF_CORE_BITS) == 0); - -#ifdef BOOKER_NIC400_INF - iface_idx = nci_find_first_wrapper_idx(nci, sii->curidx); - if (iface_idx < 0) { - NCI_ERROR(("nci_core_sflags: First Wrapper is not found\n")); - ASSERT(0u); - return 0u; - } - - /* If Wrapper is of NIC400, then call AI functionality */ - if (core->desc[iface_idx].master && (core->desc[iface_idx].node_type == NODE_TYPE_NIC400)) { - aidmp_t *ai = sii->curwrap; - if (mask || val) { - w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val); - W_REG(sii->osh, &ai->iostatus, w); - } - - return R_REG(sii->osh, &ai->iostatus); - } else -#endif /* BOOKER_NIC400_INF */ - { - volatile dmp_regs_t *io = sii->curwrap; - volatile uint32 reg_read; - - /* BOOKER */ - /* Point to OOBR base */ - switch (BUSTYPE(sih->bustype)) { - case SI_BUS: - io = (volatile dmp_regs_t*) - REG_MAP(GET_OOBR_BASE(nci->cc_erom2base), SI_CORE_SIZE); - break; - - case PCI_BUS: - /* Save Original Bar0 Win1 */ - orig_bar0_win1 = - OSL_PCI_READ_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE); - - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, PCI_ACCESS_SIZE, - GET_OOBR_BASE(nci->cc_erom2base)); - io = (volatile dmp_regs_t*)sii->curmap; - break; - - default: - NCI_ERROR(("nci_core_sflags Invalid bustype %d\n", BUSTYPE(sih->bustype))); - return 0u; - } - - /* Point to DMP Control */ - io = (dmp_regs_t*)(NCI_ADD_ADDR(io, nci->cores[sii->curidx].dmp_regs_off)); - - if (mask || val) { - w = ((R_REG(sii->osh, &io->dmpstatus) & ~mask) | val); - W_REG(sii->osh, &io->dmpstatus, w); - } - - reg_read = R_REG(sii->osh, &io->dmpstatus); - - /* Point back to original base */ - if (BUSTYPE(sih->bustype) == PCI_BUS) { - OSL_PCI_WRITE_CONFIG(nci->osh, PCI_BAR0_WIN, - PCI_ACCESS_SIZE, orig_bar0_win1); - } - - return reg_read; - } -} - -/* TODO: Used only by host */ -int -nci_backplane_access(si_t *sih, uint addr, uint size, uint *val, bool read) -{ - return 0; -} - -int -nci_backplane_access_64(si_t *sih, uint addr, uint size, uint64 *val, bool read) -{ - return 0; -} - -uint -nci_num_slaveports(const si_t *sih, uint coreidx) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - const nci_cores_t *core_info = (const nci_cores_t *)&nci->cores[coreidx]; - uint32 iface_idx; - uint32 numports = 0; - - NCI_TRACE(("nci_get_curmap coreidx %u\n", coreidx)); - for (iface_idx = 0; iface_idx < core_info->iface_cnt; iface_idx++) { - NCI_TRACE(("nci_get_curmap iface_idx %u BP_ID %u master %u\n", - iface_idx, ID_BPID(core_info->desc[iface_idx].iface_desc_1), - IS_MASTER(core_info->desc[iface_idx].iface_desc_1))); - /* hack for core idx 8, coreidx without APB Backplane ID */ - if (IS_MASTER(core_info->desc[iface_idx].iface_desc_1)) { - continue; - } - if ((ID_BPID(core_info->desc[iface_idx].iface_desc_1) == BP_APB1) || - (ID_BPID(core_info->desc[iface_idx].iface_desc_1) == BP_APB2)) { - break; - } - } - if (iface_idx < core_info->iface_cnt) { - numports = core_info->desc[iface_idx].num_addr_reg; - } - return numports; -} - -#if defined(BCMDBG) || defined(BCMDBG_DUMP) || defined(BCMDBG_PHYDUMP) -void -nci_dumpregs(const si_t *sih, struct bcmstrbuf *b) -{ - const si_info_t *sii = SI_INFO(sih); - - bcm_bprintf(b, "ChipNum:%x, ChipRev;%x, BusType:%x, BoardType:%x, BoardVendor:%x\n\n", - sih->chip, sih->chiprev, sih->bustype, sih->boardtype, sih->boardvendor); - BCM_REFERENCE(sii); - /* TODO: Implement dump regs for nci. */ -} -#endif /* BCMDBG || BCMDBG_DUMP || BCMDBG_PHYDUMP */ - -#ifdef BCMDBG -static void -_nci_view(osl_t *osh, aidmp_t *ai, uint32 cid, uint32 addr, bool verbose) -{ - /* TODO: This is WIP and will be developed once the - * implementation is done based on the NCI. - */ -} - -void -nci_view(si_t *sih, bool verbose) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - const nci_cores_t *core_info = (const nci_cores_t *)nci->cores; - osl_t *osh; - /* TODO: We need to do the structure mapping correctly based on the BOOKER/NIC type */ - aidmp_t *ai; - uint32 cid, addr; - - ai = sii->curwrap; - osh = sii->osh; - - if ((core_info[sii->curidx].coreid) == PMU_CORE_ID) { - SI_ERROR(("Cannot access pmu DMP\n")); - return; - } - cid = core_info[sii->curidx].coreid; - addr = nci_get_nth_wrapper(sih, 0u); - _nci_view(osh, ai, cid, addr, verbose); -} - -void -nci_viewall(si_t *sih, bool verbose) -{ - const si_info_t *sii = SI_INFO(sih); - nci_info_t *nci = sii->nci_info; - const nci_cores_t *core_info = (const nci_cores_t *)nci->cores; - osl_t *osh; - aidmp_t *ai; - uint32 cid, addr; - uint i; - - osh = sii->osh; - for (i = 0; i < sii->numcores; i++) { - nci_setcoreidx(sih, i); - - if ((core_info[i].coreid) == PMU_CORE_ID) { - SI_ERROR(("Skipping pmu DMP\n")); - continue; - } - ai = sii->curwrap; - cid = core_info[i].coreid; - addr = nci_get_nth_wrapper(sih, 0u); - _nci_view(osh, ai, cid, addr, verbose); - } -} -#endif /* BCMDBG */ - -uint32 -nci_clear_backplane_to(si_t *sih) -{ - /* TODO: This is WIP and will be developed once the - * implementation is done based on the NCI. - */ - return 0; -} - -#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) -static bool g_disable_backplane_logs = FALSE; - -static uint32 last_axi_error = AXI_WRAP_STS_NONE; -static uint32 last_axi_error_log_status = 0; -static uint32 last_axi_error_core = 0; -static uint32 last_axi_error_wrap = 0; -static uint32 last_axi_errlog_lo = 0; -static uint32 last_axi_errlog_hi = 0; -static uint32 last_axi_errlog_id = 0; - -/* slave error is ignored, so account for those cases */ -static uint32 si_ignore_errlog_cnt = 0; - -static void -nci_reset_APB(const si_info_t *sii, aidmp_t *ai, int *ret, - uint32 errlog_status, uint32 errlog_id) -{ - /* only reset APB Bridge on timeout (not slave error, or dec error) */ - switch (errlog_status & AIELS_ERROR_MASK) { - case AIELS_SLAVE_ERR: - NCI_PRINT(("AXI slave error\n")); - *ret |= AXI_WRAP_STS_SLAVE_ERR; - break; - - case AIELS_TIMEOUT: - nci_reset_axi_to(sii, ai); - *ret |= AXI_WRAP_STS_TIMEOUT; - break; - - case AIELS_DECODE: - NCI_PRINT(("AXI decode error\n")); -#ifdef USE_HOSTMEM - /* Ignore known cases of CR4 prefetch abort bugs */ - if ((errlog_id & (BCM_AXI_ID_MASK | BCM_AXI_ACCESS_TYPE_MASK)) != - (BCM43xx_AXI_ACCESS_TYPE_PREFETCH | BCM43xx_CR4_AXI_ID)) -#endif /* USE_HOSTMEM */ - { - *ret |= AXI_WRAP_STS_DECODE_ERR; - } - break; - default: - ASSERT(0); /* should be impossible */ - } - if (errlog_status & AIELS_MULTIPLE_ERRORS) { - NCI_PRINT(("Multiple AXI Errors\n")); - /* Set multiple errors bit only if actual error is not ignored */ - if (*ret) { - *ret |= AXI_WRAP_STS_MULTIPLE_ERRORS; - } - } - return; -} -/* - * API to clear the back plane timeout per core. - * Caller may passs optional wrapper address. If present this will be used as - * the wrapper base address. If wrapper base address is provided then caller - * must provide the coreid also. - * If both coreid and wrapper is zero, then err status of current bridge - * will be verified. - */ - -uint32 -nci_clear_backplane_to_per_core(si_t *sih, uint coreid, uint coreunit, void *wrap) -{ - int ret = AXI_WRAP_STS_NONE; - aidmp_t *ai = NULL; - uint32 errlog_status = 0; - const si_info_t *sii = SI_INFO(sih); - uint32 errlog_lo = 0, errlog_hi = 0, errlog_id = 0, errlog_flags = 0; - uint32 current_coreidx = si_coreidx(sih); - uint32 target_coreidx = nci_findcoreidx(sih, coreid, coreunit); - -#if defined(AXI_TIMEOUTS_NIC) - si_axi_error_t * axi_error = sih->err_info ? - &sih->err_info->axi_error[sih->err_info->count] : NULL; -#endif /* AXI_TIMEOUTS_NIC */ - bool restore_core = FALSE; - - if ((sii->axi_num_wrappers == 0) || -#ifdef AXI_TIMEOUTS_NIC - (!PCIE(sii)) || -#endif /* AXI_TIMEOUTS_NIC */ - FALSE) { - SI_VMSG(("nci_clear_backplane_to_per_core, axi_num_wrappers:%d, Is_PCIE:%d," - " BUS_TYPE:%d, ID:%x\n", - sii->axi_num_wrappers, PCIE(sii), - BUSTYPE(sii->pub.bustype), sii->pub.buscoretype)); - return AXI_WRAP_STS_NONE; - } - - if (wrap != NULL) { - ai = (aidmp_t *)wrap; - } else if (coreid && (target_coreidx != current_coreidx)) { - if (nci_setcoreidx(sih, target_coreidx) == NULL) { - /* Unable to set the core */ - NCI_PRINT(("Set Code Failed: coreid:%x, unit:%d, target_coreidx:%d\n", - coreid, coreunit, target_coreidx)); - errlog_lo = target_coreidx; - ret = AXI_WRAP_STS_SET_CORE_FAIL; - goto end; - } - restore_core = TRUE; - ai = (aidmp_t *)si_wrapperregs(sih); - } else { - /* Read error status of current wrapper */ - ai = (aidmp_t *)si_wrapperregs(sih); - - /* Update CoreID to current Code ID */ - coreid = nci_coreid(sih, sii->curidx); - } - - /* read error log status */ - errlog_status = R_REG(sii->osh, &ai->errlogstatus); - - if (errlog_status == ID32_INVALID) { - /* Do not try to peek further */ - NCI_PRINT(("nci_clear_backplane_to_per_core, errlogstatus:%x - " - "Slave Wrapper:%x\n", errlog_status, coreid)); - ret = AXI_WRAP_STS_WRAP_RD_ERR; - errlog_lo = (uint32)(uintptr)&ai->errlogstatus; - goto end; - } - - if ((errlog_status & AIELS_ERROR_MASK) != 0) { - uint32 tmp; - uint32 count = 0; - /* set ErrDone to clear the condition */ - W_REG(sii->osh, &ai->errlogdone, AIELD_ERRDONE_MASK); - - /* SPINWAIT on errlogstatus timeout status bits */ - while ((tmp = R_REG(sii->osh, &ai->errlogstatus)) & AIELS_ERROR_MASK) { - - if (tmp == ID32_INVALID) { - NCI_PRINT(("nci_clear_backplane_to_per_core: prev errlogstatus:%x," - " errlogstatus:%x\n", - errlog_status, tmp)); - ret = AXI_WRAP_STS_WRAP_RD_ERR; - - errlog_lo = (uint32)(uintptr)&ai->errlogstatus; - goto end; - } - /* - * Clear again, to avoid getting stuck in the loop, if a new error - * is logged after we cleared the first timeout - */ - W_REG(sii->osh, &ai->errlogdone, AIELD_ERRDONE_MASK); - - count++; - OSL_DELAY(10); - if ((10 * count) > AI_REG_READ_TIMEOUT) { - errlog_status = tmp; - break; - } - } - - errlog_lo = R_REG(sii->osh, &ai->errlogaddrlo); - errlog_hi = R_REG(sii->osh, &ai->errlogaddrhi); - errlog_id = R_REG(sii->osh, &ai->errlogid); - errlog_flags = R_REG(sii->osh, &ai->errlogflags); - - /* we are already in the error path, so OK to check for the slave error */ - if (nci_ignore_errlog(sii, ai, errlog_lo, errlog_hi, errlog_id, errlog_status)) { - si_ignore_errlog_cnt++; - goto end; - } - - nci_reset_APB(sii, ai, &ret, errlog_status, errlog_id); - - NCI_PRINT(("\tCoreID: %x\n", coreid)); - NCI_PRINT(("\t errlog: lo 0x%08x, hi 0x%08x, id 0x%08x, flags 0x%08x" - ", status 0x%08x\n", - errlog_lo, errlog_hi, errlog_id, errlog_flags, - errlog_status)); - } - -end: - if (ret != AXI_WRAP_STS_NONE) { - last_axi_error = ret; - last_axi_error_log_status = errlog_status; - last_axi_error_core = coreid; - last_axi_error_wrap = (uint32)ai; - last_axi_errlog_lo = errlog_lo; - last_axi_errlog_hi = errlog_hi; - last_axi_errlog_id = errlog_id; - } - -#if defined(AXI_TIMEOUTS_NIC) - if (axi_error && (ret != AXI_WRAP_STS_NONE)) { - axi_error->error = ret; - axi_error->coreid = coreid; - axi_error->errlog_lo = errlog_lo; - axi_error->errlog_hi = errlog_hi; - axi_error->errlog_id = errlog_id; - axi_error->errlog_flags = errlog_flags; - axi_error->errlog_status = errlog_status; - sih->err_info->count++; - - if (sih->err_info->count == SI_MAX_ERRLOG_SIZE) { - sih->err_info->count = SI_MAX_ERRLOG_SIZE - 1; - NCI_PRINT(("AXI Error log overflow\n")); - } - } -#endif /* AXI_TIMEOUTS_NIC */ - - if (restore_core) { - if (nci_setcoreidx(sih, current_coreidx) == NULL) { - /* Unable to set the core */ - return ID32_INVALID; - } - } - return ret; -} - -/* TODO: It needs to be handled based on BOOKER/NCI DMP. */ -/* reset AXI timeout */ -static void -nci_reset_axi_to(const si_info_t *sii, aidmp_t *ai) -{ - /* reset APB Bridge */ - OR_REG(sii->osh, &ai->resetctrl, AIRC_RESET); - /* sync write */ - (void)R_REG(sii->osh, &ai->resetctrl); - /* clear Reset bit */ - AND_REG(sii->osh, &ai->resetctrl, ~(AIRC_RESET)); - /* sync write */ - (void)R_REG(sii->osh, &ai->resetctrl); - NCI_PRINT(("AXI timeout\n")); - if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) { - NCI_PRINT(("reset failed on wrapper %p\n", ai)); - g_disable_backplane_logs = TRUE; - } -} - -void -nci_wrapper_get_last_error(const si_t *sih, uint32 *error_status, uint32 *core, uint32 *lo, - uint32 *hi, uint32 *id) -{ - *error_status = last_axi_error_log_status; - *core = last_axi_error_core; - *lo = last_axi_errlog_lo; - *hi = last_axi_errlog_hi; - *id = last_axi_errlog_id; -} - -uint32 -nci_get_axi_timeout_reg(void) -{ - return (GOODREGS(last_axi_errlog_lo) ? last_axi_errlog_lo : 0); -} -#endif /* AXI_TIMEOUTS || AXI_TIMEOUTS_NIC */ - -/* TODO: This function should be able to handle NIC as well as BOOKER */ -bool -nci_ignore_errlog(const si_info_t *sii, const aidmp_t *ai, - uint32 lo_addr, uint32 hi_addr, uint32 err_axi_id, uint32 errsts) -{ - uint32 ignore_errsts = AIELS_SLAVE_ERR; - uint32 ignore_errsts_2 = 0; - uint32 ignore_hi = BT_CC_SPROM_BADREG_HI; - uint32 ignore_lo = BT_CC_SPROM_BADREG_LO; - uint32 ignore_size = BT_CC_SPROM_BADREG_SIZE; - bool address_check = TRUE; - uint32 axi_id = 0; - uint32 axi_id2 = 0; - bool extd_axi_id_mask = FALSE; - uint32 axi_id_mask; - - NCI_PRINT(("err check: core %p, error %d, axi id 0x%04x, addr(0x%08x:%08x)\n", - ai, errsts, err_axi_id, hi_addr, lo_addr)); - - /* ignore the BT slave errors if the errlog is to chipcommon addr 0x190 */ - switch (CHIPID(sii->pub.chip)) { - case BCM4397_CHIP_GRPID: /* TODO: Are these IDs same for 4397 as well? */ -#ifdef BTOVERPCIE - axi_id = BCM4378_BT_AXI_ID; - /* For BT over PCIE, ignore any slave error from BT. */ - /* No need to check any address range */ - address_check = FALSE; -#endif /* BTOVERPCIE */ - axi_id2 = BCM4378_ARM_PREFETCH_AXI_ID; - extd_axi_id_mask = TRUE; - ignore_errsts_2 = AIELS_DECODE; - break; - default: - return FALSE; - } - - axi_id_mask = extd_axi_id_mask ? AI_ERRLOGID_AXI_ID_MASK_EXTD : AI_ERRLOGID_AXI_ID_MASK; - - /* AXI ID check */ - err_axi_id &= axi_id_mask; - errsts &= AIELS_ERROR_MASK; - - /* check the ignore error cases. 2 checks */ - if (!(((err_axi_id == axi_id) && (errsts == ignore_errsts)) || - ((err_axi_id == axi_id2) && (errsts == ignore_errsts_2)))) { - /* not the error ignore cases */ - return FALSE; - - } - - /* check the specific address checks now, if specified */ - if (address_check) { - /* address range check */ - if ((hi_addr != ignore_hi) || - (lo_addr < ignore_lo) || (lo_addr >= (ignore_lo + ignore_size))) { - return FALSE; - } - } - - NCI_PRINT(("err check: ignored\n")); - return TRUE; -} - -/* TODO: Check the CORE to AXI ID mapping for 4397 */ -uint32 -nci_findcoreidx_by_axiid(const si_t *sih, uint32 axiid) -{ - uint coreid = 0; - uint coreunit = 0; - const nci_axi_to_coreidx_t *axi2coreidx = NULL; - switch (CHIPID(sih->chip)) { - case BCM4397_CHIP_GRPID: - axi2coreidx = axi2coreidx_4397; - break; - default: - NCI_PRINT(("Chipid mapping not found\n")); - break; - } - - if (!axi2coreidx) { - return (BADIDX); - } - - coreid = axi2coreidx[axiid].coreid; - coreunit = axi2coreidx[axiid].coreunit; - - return nci_findcoreidx(sih, coreid, coreunit); -} - -void nci_coreaddrspaceX(const si_t *sih, uint asidx, uint32 *addr, uint32 *size) -{ - /* Adding just a wrapper. Will implement when required. */ -} - -/* - * this is not declared as static const, although that is the right thing to do - * reason being if declared as static const, compile/link process would that in - * read only section... - * currently this code/array is used to identify the registers which are dumped - * during trap processing - * and usually for the trap buffer, .rodata buffer is reused, so for now just static -*/ -/* TODO: Should we do another mapping for BOOKER and used correct one based on type of DMP. */ -#ifdef DONGLEBUILD -static uint32 BCMPOST_TRAP_RODATA(wrapper_offsets_to_dump)[] = { - OFFSETOF(aidmp_t, ioctrl), - OFFSETOF(aidmp_t, iostatus), - OFFSETOF(aidmp_t, resetctrl), - OFFSETOF(aidmp_t, resetstatus), - OFFSETOF(aidmp_t, resetreadid), - OFFSETOF(aidmp_t, resetwriteid), - OFFSETOF(aidmp_t, errlogctrl), - OFFSETOF(aidmp_t, errlogdone), - OFFSETOF(aidmp_t, errlogstatus), - OFFSETOF(aidmp_t, errlogaddrlo), - OFFSETOF(aidmp_t, errlogaddrhi), - OFFSETOF(aidmp_t, errlogid), - OFFSETOF(aidmp_t, errloguser), - OFFSETOF(aidmp_t, errlogflags), - OFFSETOF(aidmp_t, itipoobaout), - OFFSETOF(aidmp_t, itipoobbout), - OFFSETOF(aidmp_t, itipoobcout), - OFFSETOF(aidmp_t, itipoobdout) -}; - -static uint32 -BCMRAMFN(nci_get_sizeof_wrapper_offsets_to_dump)(void) -{ - return (sizeof(wrapper_offsets_to_dump)); -} - -static uint32 -BCMRAMFN(nci_get_wrapper_base_addr)(uint32 **offset) -{ - uint32 arr_size = ARRAYSIZE(wrapper_offsets_to_dump); - - *offset = &wrapper_offsets_to_dump[0]; - return arr_size; -} - -#ifdef UART_TRAP_DBG -/* TODO: Is br_wrapba populated for 4397 NCI? */ -void -nci_dump_APB_Bridge_registers(const si_t *sih) -{ - aidmp_t *ai; - const si_info_t *sii = SI_INFO(sih); - - ai = (aidmp_t *)sii->br_wrapba[0]; - printf("APB Bridge 0\n"); - printf("lo 0x%08x, hi 0x%08x, id 0x%08x, flags 0x%08x", - R_REG(sii->osh, &ai->errlogaddrlo), - R_REG(sii->osh, &ai->errlogaddrhi), - R_REG(sii->osh, &ai->errlogid), - R_REG(sii->osh, &ai->errlogflags)); - printf("\n status 0x%08x\n", R_REG(sii->osh, &ai->errlogstatus)); -} -#endif /* UART_TRAP_DBG */ - -uint32 -BCMATTACHFN(nci_wrapper_dump_buf_size)(const si_t *sih) -{ - uint32 buf_size = 0; - uint32 wrapper_count = 0; - const si_info_t *sii = SI_INFO(sih); - - wrapper_count = sii->axi_num_wrappers; - if (wrapper_count == 0) { - return 0; - } - - /* cnt indicates how many registers, tag_id 0 will say these are address/value */ - /* address/value pairs */ - buf_size += 2 * (nci_get_sizeof_wrapper_offsets_to_dump() * wrapper_count); - - return buf_size; -} - -uint32* -nci_wrapper_dump_binary_one(const si_info_t *sii, uint32 *p32, uint32 wrap_ba) -{ - uint i; - uint32 *addr; - uint32 arr_size; - uint32 *offset_base; - - arr_size = nci_get_wrapper_base_addr(&offset_base); - - for (i = 0; i < arr_size; i++) { - addr = (uint32 *)(wrap_ba + *(offset_base + i)); - *p32++ = (uint32)addr; - *p32++ = R_REG(sii->osh, addr); - } - return p32; -} - -uint32 -nci_wrapper_dump_binary(const si_t *sih, uchar *p) -{ - uint32 *p32 = (uint32 *)p; - uint32 i; - const si_info_t *sii = SI_INFO(sih); - - for (i = 0; i < sii->axi_num_wrappers; i++) { - p32 = nci_wrapper_dump_binary_one(sii, p32, sii->axi_wrapper[i].wrapper_addr); - } - return 0; -} - -#if defined(ETD) -uint32 -nci_wrapper_dump_last_timeout(const si_t *sih, uint32 *error, uint32 *core, uint32 *ba, uchar *p) -{ -#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) - uint32 *p32; - uint32 wrap_ba = last_axi_error_wrap; - uint i; - uint32 *addr; - - const si_info_t *sii = SI_INFO(sih); - - if (last_axi_error != AXI_WRAP_STS_NONE) { - if (wrap_ba) { - p32 = (uint32 *)p; - uint32 arr_size; - uint32 *offset_base; - - arr_size = nci_get_wrapper_base_addr(&offset_base); - for (i = 0; i < arr_size; i++) { - addr = (uint32 *)(wrap_ba + *(offset_base + i)); - *p32++ = R_REG(sii->osh, addr); - } - } - *error = last_axi_error; - *core = last_axi_error_core; - *ba = wrap_ba; - } -#else - *error = 0; - *core = 0; - *ba = 0; -#endif /* AXI_TIMEOUTS || AXI_TIMEOUTS_NIC */ - return 0; -} -#endif /* ETD */ - -bool -nci_check_enable_backplane_log(const si_t *sih) -{ -#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) - if (g_disable_backplane_logs) { - return FALSE; - } - else { - return TRUE; - } -#else /* (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) */ - return FALSE; -#endif /* (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) */ -} -#endif /* DONGLEBUILD */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/pcie_core.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/pcie_core.c old mode 100755 new mode 100644 index 1dfc3d6542f8..bc3e4bebfc38 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/pcie_core.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/pcie_core.c @@ -3,7 +3,7 @@ * Contains PCIe related functions that are shared between different driver models (e.g. firmware * builds, DHD builds, BMAC builds), in order to avoid code duplication. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -44,7 +44,8 @@ /* function definitions */ -#ifdef BCMDRIVER /* this workaround can only be run on the host side since it resets the chip */ +#ifdef BCMDRIVER /* this workaround can only be run on the host side since it resets \ + the chip */ #if !defined(DONGLEBUILD) || defined(BCMSTANDALONE_TEST) /* To avoid build error for dongle standalone test, define CAN_SLEEP if not defined */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/pom.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/pom.h deleted file mode 100755 index 32d056b3a2ad..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/pom.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), common DHD core. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id: $ - */ - -/* - * NOTE:- - * This file is a exact copy of trunk/components/opensource/pom/pom.h. - * Any changes needed to this file should reflect in trunk too. - * Otherwise POM(power on off manager) and dhd will go out of sync - */ - -/* - * Donot change the order of func ids below. - * Order of invoking the power off and power on handlers is importent during - * power toggle through API: pom_toggle_reg_on. - * WLAN FW should be loaded first after REG-ON. Otherwise SR doesnot work. - * - */ -enum pom_func_id { - WLAN_FUNC_ID = 0, - BT_FUNC_ID = 1, - MAX_COEX_FUNC = 2 -}; - -enum pom_toggle_reason { - BY_WLAN_DUE_TO_WLAN = 0, - BY_WLAN_DUE_TO_BT = 1, - BY_BT_DUE_TO_BT = 2, - BY_BT_DUE_TO_WLAN = 3, - BY_USER_PROCESS = 4, - BY_UNKNOWN_REASON = 5 -}; - -/* Common structure to be used to register and de-register from BT/WLAN */ -typedef struct pom_func_handler { - unsigned char func_id; - void *handler; - int (*power_off)(void *handler, unsigned char reason); - int (*power_on)(void *handler, unsigned char reason); -} pom_func_handler_t; - -/* Register call back during attach of each function */ -extern int pom_func_register(struct pom_func_handler *func); - -/* De-Register call back during detach of each function */ -extern int pom_func_deregister(struct pom_func_handler *func); - -/* Toggle Reg ON, called to recover from bad state */ -extern int pom_toggle_reg_on(unsigned char func_id, unsigned char reason); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/rk_dhd_pcie_linux.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/rk_dhd_pcie_linux.h index c6fedf9fb78b..80501a3cfd41 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/rk_dhd_pcie_linux.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/rk_dhd_pcie_linux.h @@ -24,6 +24,7 @@ rk_dhd_bus_l1ss_enable_rc_ep(dhd_bus_t *bus, bool enable) } /* Disable ASPM of RC and EP */ + printf("%s: %s L1ss\n", __FUNCTION__, enable?"enable":"disable"); pcie_aspm_ext_l1ss_enable(bus->dev, bus->rc_dev, enable); } diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/sbutils.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/sbutils.c old mode 100755 new mode 100644 index 1722d88241ab..bb8b6a12fb1c --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/sbutils.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/sbutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -127,7 +127,7 @@ sb_setint(const si_t *sih, int siflag) /* return core index of the core with address 'sba' */ static uint -BCMATTACHFN(_sb_coreidx)(const si_info_t *sii, uint32 sba) +_sb_coreidx(const si_info_t *sii, uint32 sba) { uint i; const si_cores_info_t *cores_info = (const si_cores_info_t *)sii->cores_info; @@ -140,7 +140,7 @@ BCMATTACHFN(_sb_coreidx)(const si_info_t *sii, uint32 sba) /* return core address of the current core */ static uint32 -BCMATTACHFN(_sb_coresba)(const si_info_t *sii) +_sb_coresba(const si_info_t *sii) { uint32 sbaddr; @@ -444,7 +444,7 @@ sb_corereg_addr(const si_t *sih, uint coreidx, uint regoff) */ #define SB_MAXBUSES 2 static uint -BCMATTACHFN(_sb_scan)(si_info_t *sii, uint32 sba, volatile void *regs, uint bus, +_sb_scan(si_info_t *sii, uint32 sba, volatile void *regs, uint bus, uint32 sbba, uint numcores, uint devid) { uint next; @@ -518,7 +518,7 @@ BCMATTACHFN(_sb_scan)(si_info_t *sii, uint32 sba, volatile void *regs, uint bus, /* scan the sb enumerated space to identify all cores */ void -BCMATTACHFN(sb_scan)(si_t *sih, volatile void *regs, uint devid) +sb_scan(si_t *sih, volatile void *regs, uint devid) { uint32 origsba; sbconfig_t *sb; @@ -673,8 +673,7 @@ sb_addrspacesize(const si_t *sih, uint asidx) return (sb_size(R_SBREG(sii, sb_admatch(sii, asidx)))); } -#if defined(BCMDBG_ERR) || defined(BCMASSERT_SUPPORT) || \ - defined(BCMDBG_DUMP) +#if defined(BCMDBG_ERR) || defined(BCMASSERT_SUPPORT) || defined(BCMDBG_DUMP) /* traverse all cores to find and clear source of serror */ static void sb_serr_clear(si_info_t *sii) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c old mode 100755 new mode 100644 index dab58438c32f..1819a6c0cb9f --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -93,9 +93,6 @@ #include "siutils_priv.h" #include "sbhndarm.h" #include -#ifdef SOCI_NCI_BUS -#include -#endif /* SOCI_NCI_BUS */ #ifdef SECI_UART /* Defines the set of GPIOs to be used for SECI UART if not specified in NVRAM */ @@ -146,7 +143,7 @@ static bool force_seci_clk = 0; #if !defined(BCMDONGLEHOST) static void si_43012_lp_enable(si_t *sih); #endif /* !defined(BCMDONGLEHOST) */ -static int32 BCMATTACHFN(si_alloc_wrapper)(si_info_t *sii); +static int32 si_alloc_wrapper(si_info_t *sii); static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, volatile void *regs, uint bustype, void *sdh, char **vars, uint *varsz); static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh); @@ -163,7 +160,6 @@ static bool _si_clkctl_cc(si_info_t *sii, uint mode); static bool si_ispcie(const si_info_t *sii); static uint sysmem_banksize(const si_info_t *sii, sysmemregs_t *r, uint8 idx); static uint socram_banksize(const si_info_t *sii, sbsocramregs_t *r, uint8 idx, uint8 mtype); -static void si_gci_get_chipctrlreg_ringidx_base4(uint32 pin, uint32 *regidx, uint32 *pos); static uint8 si_gci_get_chipctrlreg_ringidx_base8(uint32 pin, uint32 *regidx, uint32 *pos); static void si_gci_gpio_chipcontrol(si_t *si, uint8 gpoi, uint8 opt); static void si_gci_enable_gpioint(si_t *sih, bool enable); @@ -172,14 +168,15 @@ static chipcregs_t * seci_set_core(si_t *sih, uint32 *origidx, bool *fast); #endif #endif /* !defined(BCMDONGLEHOST) */ +static void si_gci_get_chipctrlreg_ringidx_base4(uint32 pin, uint32 *regidx, uint32 *pos); static bool si_pmu_is_ilp_sensitive(uint32 idx, uint regoff); static void si_oob_war_BT_F1(si_t *sih); #if defined(DONGLEBUILD) #if !defined(NVSRCX) -static char * BCMATTACHFN(si_getkvars)(void); -static int BCMATTACHFN(si_getkvarsz)(void); +static char * si_getkvars(void); +static int si_getkvarsz(void); #endif #endif /* DONGLEBUILD */ @@ -213,13 +210,13 @@ static si_info_t ksii; static si_cores_info_t ksii_cores_info; #ifndef BCMDONGLEHOST -static const char BCMATTACHDATA(rstr_rmin)[] = "rmin"; -static const char BCMATTACHDATA(rstr_rmax)[] = "rmax"; +static const char rstr_rmin[] = "rmin"; +static const char rstr_rmax[] = "rmax"; -static const char BCMATTACHDATA(rstr_lhl_ps_mode)[] = "lhl_ps_mode"; -static const char BCMATTACHDATA(rstr_ext_wakeup_dis)[] = "ext_wakeup_dis"; +static const char rstr_lhl_ps_mode[] = "lhl_ps_mode"; +static const char rstr_ext_wakeup_dis[] = "ext_wakeup_dis"; #if defined(BCMSRTOPOFF) && !defined(BCMSRTOPOFF_DISABLED) -static const char BCMATTACHDATA(rstr_srtopoff_enab)[] = "srtopoff_enab"; +static const char rstr_srtopoff_enab[] = "srtopoff_enab"; #endif #endif /* BCMDONGLEHOST */ @@ -232,20 +229,14 @@ static uint32 wd_msticks; /**< watchdog timer ticks normalized to ms */ */ #if !defined(NVSRCX) static char * -BCMATTACHFN(si_getkvars)(void) +si_getkvars(void) { - if (FWSIGN_ENAB()) { - return NULL; - } return (ksii.vars); } static int -BCMATTACHFN(si_getkvarsz)(void) +si_getkvarsz(void) { - if (FWSIGN_ENAB()) { - return NULL; - } return (ksii.varsz); } #endif /* !defined(NVSRCX) */ @@ -253,7 +244,7 @@ BCMATTACHFN(si_getkvarsz)(void) /** Returns the backplane address of the chipcommon core for a particular chip */ uint32 -BCMATTACHFN(si_enum_base)(uint devid) +si_enum_base(uint devid) { return SI_ENUM_BASE_DEFAULT; } @@ -270,11 +261,12 @@ BCMATTACHFN(si_enum_base)(uint devid) * varsz - pointer to int to return the size of the vars */ si_t * -BCMATTACHFN(si_attach)(uint devid, osl_t *osh, volatile void *regs, +si_attach(uint devid, osl_t *osh, volatile void *regs, uint bustype, void *sdh, char **vars, uint *varsz) { si_info_t *sii; + SI_MSG_DBG_REG(("%s: Enter\n", __FUNCTION__)); /* alloc si_info_t */ /* freed after ucode download for firmware builds */ if ((sii = MALLOCZ_NOPERSIST(osh, sizeof(si_info_t))) == NULL) { @@ -299,12 +291,13 @@ BCMATTACHFN(si_attach)(uint devid, osl_t *osh, volatile void *regs, #if defined(BCM_SH_SFLASH) && !defined(BCM_SH_SFLASH_DISABLED) sh_sflash_attach(osh, (si_t *)sii); #endif + SI_MSG_DBG_REG(("%s: Exit\n", __FUNCTION__)); return (si_t *)sii; } /** generic kernel variant of si_attach(). Is not called for Linux WLAN NIC builds. */ si_t * -BCMATTACHFN(si_kattach)(osl_t *osh) +si_kattach(osl_t *osh) { static bool ksii_attached = FALSE; si_cores_info_t *cores_info; @@ -359,7 +352,7 @@ BCMATTACHFN(si_kattach)(osl_t *osh) } static bool -BCMATTACHFN(si_buscore_prep)(si_info_t *sii, uint bustype, uint devid, void *sdh) +si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh) { BCM_REFERENCE(sdh); BCM_REFERENCE(devid); @@ -472,7 +465,7 @@ done: } static bool -BCMATTACHFN(si_buscore_setup)(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, +si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, uint *origidx, volatile const void *regs) { const si_cores_info_t *cores_info = sii->cores_info; @@ -523,13 +516,14 @@ BCMATTACHFN(si_buscore_setup)(si_info_t *sii, chipcregs_t *cc, uint bustype, uin GCI_OFFSETOF(&sii->pub, gci_corecaps0), 0, 0) & GCI_CAP0_REV_MASK; if (GCIREV(sii->pub.gcirev) >= 9) { +#if !defined(BCMQT) && !defined(BCMFPGA) sii->pub.lhlrev = si_corereg(&sii->pub, GCI_CORE_IDX(&sii->pub), OFFSETOF(gciregs_t, lhl_core_capab_adr), 0, 0) & LHL_CAP_REV_MASK; +#endif /* !defined(BCMQT && !defined(BCMFPGA */ } else { sii->pub.lhlrev = NOREV; } - } else sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); @@ -660,7 +654,7 @@ BCMATTACHFN(si_buscore_setup)(si_info_t *sii, chipcregs_t *cc, uint bustype, uin #if !defined(BCMDONGLEHOST) /* fixup necessary chip/core configurations */ - if (!FWSIGN_ENAB() && BUSTYPE(sii->pub.bustype) == PCI_BUS) { + if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { if (SI_FAST(sii)) { if (!sii->pch && ((sii->pch = (void *)(uintptr)pcicore_init(&sii->pub, sii->osh, @@ -693,36 +687,36 @@ BCMATTACHFN(si_buscore_setup)(si_info_t *sii, chipcregs_t *cc, uint bustype, uin #if !defined(BCMDONGLEHOST) /* if not a DHD build */ -static const char BCMATTACHDATA(rstr_boardvendor)[] = "boardvendor"; -static const char BCMATTACHDATA(rstr_boardtype)[] = "boardtype"; +static const char rstr_boardvendor[] = "boardvendor"; +static const char rstr_boardtype[] = "boardtype"; #if defined(BCMPCIEDEV_SROM_FORMAT) -static const char BCMATTACHDATA(rstr_subvid)[] = "subvid"; +static const char rstr_subvid[] = "subvid"; #endif /* defined(BCMPCIEDEV_SROM_FORMAT) */ #ifdef BCMSDIO -static const char BCMATTACHDATA(rstr_manfid)[] = "manfid"; +static const char rstr_manfid[] = "manfid"; #endif -static const char BCMATTACHDATA(rstr_prodid)[] = "prodid"; -static const char BCMATTACHDATA(rstr_boardrev)[] = "boardrev"; -static const char BCMATTACHDATA(rstr_boardflags)[] = "boardflags"; -static const char BCMATTACHDATA(rstr_boardflags4)[] = "boardflags4"; -static const char BCMATTACHDATA(rstr_xtalfreq)[] = "xtalfreq"; -static const char BCMATTACHDATA(rstr_muxenab)[] = "muxenab"; -static const char BCMATTACHDATA(rstr_gpiopulldown)[] = "gpdn"; -static const char BCMATTACHDATA(rstr_devid)[] = "devid"; -static const char BCMATTACHDATA(rstr_wl0id)[] = "wl0id"; -static const char BCMATTACHDATA(rstr_devpathD)[] = "devpath%d"; -static const char BCMATTACHDATA(rstr_D_S)[] = "%d:%s"; -static const char BCMATTACHDATA(rstr_swdenab)[] = "swdenable"; -static const char BCMATTACHDATA(rstr_spurconfig)[] = "spurconfig"; -static const char BCMATTACHDATA(rstr_lpflags)[] = "lpflags"; -static const char BCMATTACHDATA(rstr_armclk)[] = "armclk"; -static const char BCMATTACHDATA(rstr_rfldo3p3_cap_war)[] = "rfldo3p3_cap_war"; +static const char rstr_prodid[] = "prodid"; +static const char rstr_boardrev[] = "boardrev"; +static const char rstr_boardflags[] = "boardflags"; +static const char rstr_boardflags4[] = "boardflags4"; +static const char rstr_xtalfreq[] = "xtalfreq"; +static const char rstr_muxenab[] = "muxenab"; +static const char rstr_gpiopulldown[] = "gpdn"; +static const char rstr_devid[] = "devid"; +static const char rstr_wl0id[] = "wl0id"; +static const char rstr_devpathD[] = "devpath%d"; +static const char rstr_D_S[] = "%d:%s"; +static const char rstr_swdenab[] = "swdenable"; +static const char rstr_spurconfig[] = "spurconfig"; +static const char rstr_lpflags[] = "lpflags"; +static const char rstr_armclk[] = "armclk"; +static const char rstr_rfldo3p3_cap_war[] = "rfldo3p3_cap_war"; #if defined(SECI_UART) -static const char BCMATTACHDATA(rstr_fuart_pup_rx_cts)[] = "fuart_pup_rx_cts"; +static const char rstr_fuart_pup_rx_cts[] = "fuart_pup_rx_cts"; #endif /* defined(SECI_UART) */ static uint32 -BCMATTACHFN(si_fixup_vid_overrides)(si_info_t *sii, char *pvars, uint32 conf_vid) +si_fixup_vid_overrides(si_info_t *sii, char *pvars, uint32 conf_vid) { BCM_REFERENCE(pvars); @@ -752,14 +746,10 @@ BCMATTACHFN(si_fixup_vid_overrides)(si_info_t *sii, char *pvars, uint32 conf_vid } static void -BCMATTACHFN(si_nvram_process)(si_info_t *sii, char *pvars) +si_nvram_process(si_info_t *sii, char *pvars) { uint w = 0; - if (FWSIGN_ENAB()) { - return; - } - /* get boardtype and boardrev */ switch (BUSTYPE(sii->pub.bustype)) { case PCI_BUS: @@ -790,9 +780,7 @@ BCMATTACHFN(si_nvram_process)(si_info_t *sii, char *pvars) } /* Override high priority fixups */ - if (!FWSIGN_ENAB()) { - si_fixup_vid_overrides(sii, pvars, w); - } + si_fixup_vid_overrides(sii, pvars, w); break; #ifdef BCMSDIO @@ -862,18 +850,18 @@ typedef struct { } si_mux_uartopt_t; /* note: each index corr to MUXENAB43012_HOSTWAKE_MASK > shift - 1 */ -static const uint8 BCMATTACHDATA(mux43012_hostwakeopt)[] = { +static const uint8 mux43012_hostwakeopt[] = { CC_PIN_GPIO_00 }; -static const si_mux_uartopt_t BCMATTACHDATA(mux_uartopt)[] = { +static const si_mux_uartopt_t mux_uartopt[] = { {CC_PIN_GPIO_00, CC_PIN_GPIO_01}, {CC_PIN_GPIO_05, CC_PIN_GPIO_04}, {CC_PIN_GPIO_15, CC_PIN_GPIO_14}, }; /* note: each index corr to MUXENAB_DEF_HOSTWAKE mask >> shift - 1 */ -static const uint8 BCMATTACHDATA(mux_hostwakeopt)[] = { +static const uint8 mux_hostwakeopt[] = { CC_PIN_GPIO_00, }; @@ -889,7 +877,7 @@ static uint32 fast_uart_cts_in; #endif /* SECI_UART */ void -BCMATTACHFN(si_swdenable)(si_t *sih, uint32 swdflag) +si_swdenable(si_t *sih, uint32 swdflag) { /* FIXME Need a more generic test for SWD instead of check on specific chipid */ switch (CHIPID(sih->chip)) { @@ -923,7 +911,7 @@ BCMATTACHFN(si_swdenable)(si_t *sih, uint32 swdflag) /** want to have this available all the time to switch mux for debugging */ void -BCMATTACHFN(si_muxenab)(si_t *sih, uint32 w) +si_muxenab(si_t *sih, uint32 w) { uint32 chipcontrol, pmu_chipcontrol; @@ -964,7 +952,9 @@ BCMATTACHFN(si_muxenab)(si_t *sih, uint32 w) } break; -case BCM4385_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: + case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: if (w & MUXENAB_DEF_UART_MASK) { uint32 uart_rx = 0, uart_tx = 0; @@ -1238,7 +1228,10 @@ si_gpio_enable(si_t *sih, uint32 mask) case BCM4369_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4387_CHIP_GRPID: + case BCM4389_CHIP_GRPID: fnsel = CC_FNSEL_SAMEASPIN; default: ; @@ -1258,9 +1251,9 @@ si_gpio_enable(si_t *sih, uint32 mask) return BCME_OK; } -static const char BCMATTACHDATA(rstr_host_wake_opt)[] = "host_wake_opt"; +static const char rstr_host_wake_opt[] = "host_wake_opt"; uint8 -BCMATTACHFN(si_gci_host_wake_gpio_init)(si_t *sih) +si_gci_host_wake_gpio_init(si_t *sih) { uint8 host_wake_gpio = CC_GCI_GPIO_INVALID; uint32 host_wake_opt; @@ -1284,6 +1277,8 @@ BCMPOSTTRAPFN(si_gci_host_wake_gpio_enable)(si_t *sih, uint8 gpio, bool state) case BCM4369_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -1307,8 +1302,11 @@ si_gci_time_sync_gpio_enable(si_t *sih, uint8 gpio, bool state) case BCM4362_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: + case BCM4389_CHIP_GRPID: si_gci_enable_gpio(sih, gpio, 1 << gpio, state ? 1 << gpio : 0x00); break; @@ -1319,9 +1317,9 @@ si_gci_time_sync_gpio_enable(si_t *sih, uint8 gpio, bool state) } #define TIMESYNC_GPIO_NUM 12 /* Hardcoded for now. Will be removed later */ -static const char BCMATTACHDATA(rstr_time_sync_opt)[] = "time_sync_opt"; +static const char rstr_time_sync_opt[] = "time_sync_opt"; uint8 -BCMATTACHFN(si_gci_time_sync_gpio_init)(si_t *sih) +si_gci_time_sync_gpio_init(si_t *sih) { uint8 time_sync_gpio = TIMESYNC_GPIO_NUM; uint32 time_sync_opt; @@ -1338,8 +1336,11 @@ BCMATTACHFN(si_gci_time_sync_gpio_init)(si_t *sih) case BCM4362_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: + case BCM4389_CHIP_GRPID: time_sync_gpio = time_sync_opt & 0xff; si_gci_enable_gpio(sih, time_sync_gpio, 1 << time_sync_gpio, 0x00); @@ -1385,7 +1386,7 @@ si_gci_enable_gpioint(si_t *sih, bool enable) /* assumes function select is performed separately */ void -BCMINITFN(si_enable_gpio_wake)(si_t *sih, uint8 *wake_mask, uint8 *cur_status, uint8 gci_gpio, +si_enable_gpio_wake(si_t *sih, uint8 *wake_mask, uint8 *cur_status, uint8 gci_gpio, uint32 pmu_cc2_mask, uint32 pmu_cc2_value) { si_gci_gpio_chipcontrol(sih, gci_gpio, @@ -1458,14 +1459,14 @@ si_gci_free_wake_pin(si_t *sih, uint8 gpio_n) } #if defined(BCMPCIEDEV) -static const char BCMINITDATA(rstr_device_wake_opt)[] = "device_wake_opt"; +static const char rstr_device_wake_opt[] = "device_wake_opt"; #else -static const char BCMINITDATA(rstr_device_wake_opt)[] = "sd_devwake"; +static const char rstr_device_wake_opt[] = "sd_devwake"; #endif #define DEVICE_WAKE_GPIO3 3 uint8 -BCMATTACHFN(si_enable_perst_wake)(si_t *sih, uint8 *perst_wake_mask, uint8 *perst_cur_status) +si_enable_perst_wake(si_t *sih, uint8 *perst_wake_mask, uint8 *perst_cur_status) { uint8 gci_perst = CC_GCI_GPIO_15; switch (CHIPID(sih->chip)) { @@ -1478,7 +1479,7 @@ BCMATTACHFN(si_enable_perst_wake)(si_t *sih, uint8 *perst_wake_mask, uint8 *pers } uint8 -BCMINITFN(si_get_device_wake_opt)(si_t *sih) +si_get_device_wake_opt(si_t *sih) { si_info_t *sii = SI_INFO(sih); @@ -1513,8 +1514,11 @@ si_enable_device_wake(si_t *sih, uint8 *wake_mask, uint8 *cur_status) case BCM4369_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: + case BCM4389_CHIP_GRPID: case BCM4362_CHIP_GRPID: /* device_wake op 1: * gpio 1, func sel 4, @@ -2442,6 +2446,24 @@ si_gci_uart_init(si_t *sih, osl_t *osh, uint8 seci_mode) #endif /* HNDGCI */ } +/* input: pin number +* output: chipcontrol reg(ring_index base) and +* bits to shift for pin first regbit. +* eg: gpio9 will give regidx: 2 and pos 16 +*/ +static uint8 +BCMPOSTTRAPFN(si_gci_get_chipctrlreg_ringidx_base8)(uint32 pin, uint32 *regidx, uint32 *pos) +{ + *regidx = (pin / 4); + *pos = (pin % 4)*8; + + SI_MSG(("si_gci_get_chipctrlreg_ringidx_base8:%d:%d:%d\n", pin, *regidx, *pos)); + + return 0; +} + +#endif /* !defined(BCMDONGLEHOST) */ + /** * A given GCI pin needs to be converted to a GCI FunctionSel register offset and the bit position * in this register. @@ -2460,22 +2482,6 @@ BCMPOSTTRAPFN(si_gci_get_chipctrlreg_ringidx_base4)(uint32 pin, uint32 *regidx, SI_MSG(("si_gci_get_chipctrlreg_ringidx_base4:%d:%d:%d\n", pin, *regidx, *pos)); } -/* input: pin number -* output: chipcontrol reg(ring_index base) and -* bits to shift for pin first regbit. -* eg: gpio9 will give regidx: 2 and pos 16 -*/ -static uint8 -BCMPOSTTRAPFN(si_gci_get_chipctrlreg_ringidx_base8)(uint32 pin, uint32 *regidx, uint32 *pos) -{ - *regidx = (pin / 4); - *pos = (pin % 4)*8; - - SI_MSG(("si_gci_get_chipctrlreg_ringidx_base8:%d:%d:%d\n", pin, *regidx, *pos)); - - return 0; -} - /** setup a given pin for fnsel function */ void BCMPOSTTRAPFN(si_gci_set_functionsel)(si_t *sih, uint32 pin, uint8 fnsel) @@ -2543,10 +2549,33 @@ BCMPOSTTRAPFN(si_gci_chipstatus)(si_t *sih, uint reg) /* setting mask and value to '0' to use si_corereg for read only purpose */ return si_corereg(sih, GCI_CORE_IDX(sih), GCI_OFFSETOF(sih, gci_chipsts), 0, 0); } -#endif /* !defined(BCMDONGLEHOST) */ + +void +sflash_gpio_config(si_t *sih) +{ + ASSERT(sih); + + if (!si_is_sflash_available(sih)) { + return; + } + + switch (CHIPID((sih)->chip)) { + case BCM4387_CHIP_GRPID: + /* config 4387 sflash gpio lines 12,15,18,19 */ + si_gci_set_functionsel(sih, CC_PIN_GPIO_12, CC4387_FNSEL_SFLASH); + si_gci_set_functionsel(sih, CC_PIN_GPIO_15, CC4387_FNSEL_SFLASH); + si_gci_set_functionsel(sih, CC_PIN_GPIO_18, CC4387_FNSEL_SFLASH); + si_gci_set_functionsel(sih, CC_PIN_GPIO_19, CC4387_FNSEL_SFLASH); + break; + default: + break; + } + + return; +} uint16 -BCMINITFN(si_chipid)(const si_t *sih) +si_chipid(const si_t *sih) { const si_info_t *sii = SI_INFO(sih); @@ -2555,7 +2584,7 @@ BCMINITFN(si_chipid)(const si_t *sih) /* CHIP_ID's being mapped here should not be used anywhere else in the code */ static void -BCMATTACHFN(si_chipid_fixup)(si_t *sih) +si_chipid_fixup(si_t *sih) { si_info_t *sii = SI_INFO(sih); @@ -2617,7 +2646,7 @@ si_reset_axi_errlog_info(const si_t *sih) /* TODO: Can we allocate only one instance? */ static int32 -BCMATTACHFN(si_alloc_wrapper)(si_info_t *sii) +si_alloc_wrapper(si_info_t *sii) { if (sii->osh) { sii->axi_wrapper = (axi_wrapper_t *)MALLOCZ(sii->osh, @@ -2634,7 +2663,7 @@ BCMATTACHFN(si_alloc_wrapper)(si_info_t *sii) } static void -BCMATTACHFN(si_free_wrapper)(si_info_t *sii) +si_free_wrapper(si_info_t *sii) { if (sii->axi_wrapper) { @@ -2643,7 +2672,7 @@ BCMATTACHFN(si_free_wrapper)(si_info_t *sii) } static void * -BCMATTACHFN(si_alloc_coresinfo)(si_info_t *sii, osl_t *osh, chipcregs_t *cc) +si_alloc_coresinfo(si_info_t *sii, osl_t *osh, chipcregs_t *cc) { if (CHIPTYPE(sii->pub.socitype) == SOCI_NCI) { sii->nci_info = nci_init(&sii->pub, (void*)(uintptr)cc, sii->pub.bustype); @@ -2674,7 +2703,7 @@ BCMATTACHFN(si_alloc_coresinfo)(si_info_t *sii, osl_t *osh, chipcregs_t *cc) } static void -BCMATTACHFN(si_free_coresinfo)(si_info_t *sii, osl_t *osh) +si_free_coresinfo(si_info_t *sii, osl_t *osh) { if (CHIPTYPE(sii->pub.socitype) == SOCI_NCI) { @@ -2697,7 +2726,7 @@ BCMATTACHFN(si_free_coresinfo)(si_info_t *sii, osl_t *osh) * function set 'vars' to NULL. */ static si_info_t * -BCMATTACHFN(si_doattach)(si_info_t *sii, uint devid, osl_t *osh, volatile void *regs, +si_doattach(si_info_t *sii, uint devid, osl_t *osh, volatile void *regs, uint bustype, void *sdh, char **vars, uint *varsz) { struct si_pub *sih = &sii->pub; @@ -2821,21 +2850,27 @@ BCMATTACHFN(si_doattach)(si_info_t *sii, uint devid, osl_t *osh, volatile void * } ASSERT(sii->nci_info); - if (!FWSIGN_ENAB()) { - if ((si_alloc_wrapper(sii)) != BCME_OK) { - err_at = 5; - goto exit; - } +#ifndef BCM_BOOTLOADER + if ((si_alloc_wrapper(sii)) != BCME_OK) { + err_at = 5; + goto exit; } +#endif /* BCM_BOOTLOADER */ +#ifndef SOCI_NCI_BUS + /* If !SOCI_NCI_BUS, nci_scan(sih) is always 0. */ + err_at = 6; + goto exit; +#else if ((sii->numcores = nci_scan(sih)) == 0u) { err_at = 6; goto exit; } else { - if (!FWSIGN_ENAB()) { - nci_dump_erom(sii->nci_info); - } +#ifndef BCM_BOOTLOADER + nci_dump_erom(sii->nci_info); +#endif /* BCM_BOOTLOADER */ } +#endif /* !SOCI_NCI_BUS */ } else { if (si_alloc_coresinfo(sii, osh, cc) == NULL) { @@ -2948,12 +2983,10 @@ BCMATTACHFN(si_doattach)(si_info_t *sii, uint devid, osl_t *osh, volatile void * #endif /* SI_SPROM_PROBE */ #if !defined(BCMDONGLEHOST) - if (!FWSIGN_ENAB()) { - /* Init nvram from flash if it exists */ - if (nvram_init(&(sii->pub)) != BCME_OK) { - SI_ERROR(("si_doattach: nvram_init failed \n")); - goto exit; - } + /* Init nvram from flash if it exists */ + if (nvram_init(&(sii->pub)) != BCME_OK) { + SI_ERROR(("si_doattach: nvram_init failed \n")); + goto exit; } /* Init nvram from sprom/otp if they exist */ @@ -2962,7 +2995,7 @@ BCMATTACHFN(si_doattach)(si_info_t *sii, uint devid, osl_t *osh, volatile void * #ifdef DONGLEBUILD #if !defined(NVSRCX) /* Init nvram from sprom/otp if they exist and not inited */ - if (!FWSIGN_ENAB() && si_getkvars()) { + if (si_getkvars()) { *vars = si_getkvars(); *varsz = si_getkvarsz(); } @@ -2980,12 +3013,10 @@ BCMATTACHFN(si_doattach)(si_info_t *sii, uint devid, osl_t *osh, volatile void * } } #else - if (!FWSIGN_ENAB()) { - if (srom_var_init(&sii->pub, BUSTYPE(bustype), (void *)regs, - sii->osh, vars, varsz)) { - err_at = 13; - goto exit; - } + if (srom_var_init(&sii->pub, BUSTYPE(bustype), (void *)regs, + sii->osh, vars, varsz)) { + err_at = 13; + goto exit; } #endif /* NVSRCX */ } @@ -3008,24 +3039,22 @@ BCMATTACHFN(si_doattach)(si_info_t *sii, uint devid, osl_t *osh, volatile void * _srtopoff_enab = (bool)getintvar(NULL, rstr_srtopoff_enab); #endif - if (!FWSIGN_ENAB()) { - if (HIB_EXT_WAKEUP_CAP(sih)) { - sii->lhl_ps_mode = (uint8)getintvar(NULL, rstr_lhl_ps_mode); + if (HIB_EXT_WAKEUP_CAP(sih)) { + sii->lhl_ps_mode = (uint8)getintvar(NULL, rstr_lhl_ps_mode); - if (getintvar(NULL, rstr_ext_wakeup_dis)) { - sii->hib_ext_wakeup_enab = FALSE; - } else if (BCMSRTOPOFF_ENAB()) { - /* Has GPIO false wakeup issue on 4387, needs resolve */ - sii->hib_ext_wakeup_enab = TRUE; - } else if (LHL_IS_PSMODE_1(sih)) { - sii->hib_ext_wakeup_enab = TRUE; - } else { - sii->hib_ext_wakeup_enab = FALSE; - } + if (getintvar(NULL, rstr_ext_wakeup_dis)) { + sii->hib_ext_wakeup_enab = FALSE; + } else if (BCMSRTOPOFF_ENAB()) { + /* Has GPIO false wakeup issue on 4387, needs resolve */ + sii->hib_ext_wakeup_enab = TRUE; + } else if (LHL_IS_PSMODE_1(sih)) { + sii->hib_ext_wakeup_enab = TRUE; + } else { + sii->hib_ext_wakeup_enab = FALSE; } - - sii->rfldo3p3_war = (bool)getintvar(NULL, rstr_rfldo3p3_cap_war); } + + sii->rfldo3p3_war = (bool)getintvar(NULL, rstr_rfldo3p3_cap_war); #endif /* !defined(BCMDONGLEHOST) */ if (!si_onetimeinit) { @@ -3033,37 +3062,36 @@ BCMATTACHFN(si_doattach)(si_info_t *sii, uint devid, osl_t *osh, volatile void * char *val; (void) val; - if (!FWSIGN_ENAB()) { - /* Cache nvram override to min mask */ - if ((val = getvar(NULL, rstr_rmin)) != NULL) { - sii->min_mask_valid = TRUE; - sii->nvram_min_mask = (uint32)bcm_strtoul(val, NULL, 0); - } else { - sii->min_mask_valid = FALSE; - } - /* Cache nvram override to max mask */ - if ((val = getvar(NULL, rstr_rmax)) != NULL) { - sii->max_mask_valid = TRUE; - sii->nvram_max_mask = (uint32)bcm_strtoul(val, NULL, 0); - } else { - sii->max_mask_valid = FALSE; - } + + /* Cache nvram override to min mask */ + if ((val = getvar(NULL, rstr_rmin)) != NULL) { + sii->min_mask_valid = TRUE; + sii->nvram_min_mask = (uint32)bcm_strtoul(val, NULL, 0); + } else { + sii->min_mask_valid = FALSE; + } + /* Cache nvram override to max mask */ + if ((val = getvar(NULL, rstr_rmax)) != NULL) { + sii->max_mask_valid = TRUE; + sii->nvram_max_mask = (uint32)bcm_strtoul(val, NULL, 0); + } else { + sii->max_mask_valid = FALSE; + } #ifdef DONGLEBUILD - /* Handle armclk frequency setting from NVRAM file */ - if (BCM4369_CHIP(sih->chip) || BCM4362_CHIP(sih->chip) || - BCM4389_CHIP(sih->chip) || - BCM4388_CHIP(sih->chip) || BCM4397_CHIP(sih->chip) || FALSE) { - if ((val = getvar(NULL, rstr_armclk)) != NULL) { - sii->armpllclkfreq = (uint32)bcm_strtoul(val, NULL, 0); - ASSERT(sii->armpllclkfreq > 0); - } else { - sii->armpllclkfreq = 0; - } + /* Handle armclk frequency setting from NVRAM file */ + if (BCM4369_CHIP(sih->chip) || BCM4362_CHIP(sih->chip) || + BCM4389_CHIP(sih->chip) || + BCM4388_CHIP(sih->chip) || BCM4397_CHIP(sih->chip) || FALSE) { + if ((val = getvar(NULL, rstr_armclk)) != NULL) { + sii->armpllclkfreq = (uint32)bcm_strtoul(val, NULL, 0); + ASSERT(sii->armpllclkfreq > 0); + } else { + sii->armpllclkfreq = 0; } + } #endif /* DONGLEBUILD */ - } #endif /* !BCMDONGLEHOST */ @@ -3148,11 +3176,6 @@ BCMATTACHFN(si_doattach)(si_info_t *sii, uint devid, osl_t *osh, volatile void * si_pmu_init(sih, sii->osh); si_pmu_chip_init(sih, sii->osh); xtalfreq = getintvar(pvars, rstr_xtalfreq); -#if defined(WL_FWSIGN) - if (FWSIGN_ENAB()) { - xtalfreq = XTALFREQ_KHZ; - } -#endif /* WL_FWSIGN */ /* * workaround for chips that don't support external LPO, thus ALP clock @@ -3177,37 +3200,35 @@ BCMATTACHFN(si_doattach)(si_info_t *sii, uint devid, osl_t *osh, volatile void * sii->xtalfreq = xtalfreq; si_pmu_pll_init(sih, sii->osh, xtalfreq); - if (!FWSIGN_ENAB()) { - /* configure default spurmode */ - sii->spurmode = getintvar(pvars, rstr_spurconfig) & 0xf; + /* configure default spurmode */ + sii->spurmode = getintvar(pvars, rstr_spurconfig) & 0xf; #if defined(SAVERESTORE) - /* Only needs to be done once. - * Needs this before si_pmu_res_init() to use sr_isenab() - */ - if (SR_ENAB()) { - sr_save_restore_init(sih); - } + /* Only needs to be done once. + * Needs this before si_pmu_res_init() to use sr_isenab() + */ + if (SR_ENAB()) { + sr_save_restore_init(sih); + } #endif - /* TODO: should move the per core srpwr out of - * si_doattach() to a function where it knows - * which core it should enable the power domain - * request for... - */ - if (SRPWR_CAP(sih) && !SRPWR_ENAB()) { - uint32 domain = SRPWR_DMN3_MACMAIN_MASK; + /* TODO: should move the per core srpwr out of + * si_doattach() to a function where it knows + * which core it should enable the power domain + * request for... + */ + if (SRPWR_CAP(sih) && !SRPWR_ENAB()) { + uint32 domain = SRPWR_DMN3_MACMAIN_MASK; #if defined(WLRSDB) && !defined(WLRSDB_DISABLED) - domain |= SRPWR_DMN2_MACAUX_MASK; + domain |= SRPWR_DMN2_MACAUX_MASK; #endif /* WLRSDB && !WLRSDB_DISABLED */ - if (si_scan_core_present(sih)) { - domain |= SRPWR_DMN4_MACSCAN_MASK; - } - - si_srpwr_request(sih, domain, domain); + if (si_scan_core_present(sih)) { + domain |= SRPWR_DMN4_MACSCAN_MASK; } + + si_srpwr_request(sih, domain, domain); } si_pmu_res_init(sih, sii->osh); @@ -3226,11 +3247,9 @@ BCMATTACHFN(si_doattach)(si_info_t *sii, uint devid, osl_t *osh, volatile void * si_lowpwr_opt(sih); - if (!FWSIGN_ENAB()) { - if (PCIE(sii)) { - ASSERT(sii->pch != NULL); - pcicore_attach(sii->pch, pvars, SI_DOATTACH); - } + if (PCIE(sii)) { + ASSERT(sii->pch != NULL); + pcicore_attach(sii->pch, pvars, SI_DOATTACH); } if ((CHIPID(sih->chip) == BCM43012_CHIP_ID) || @@ -3308,7 +3327,7 @@ exit: /** may be called with core in reset */ void -BCMATTACHFN(si_detach)(si_t *sih) +si_detach(si_t *sih) { si_info_t *sii = SI_INFO(sih); si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; @@ -3401,7 +3420,7 @@ si_setosh(si_t *sih, osl_t *osh) /** register driver interrupt disabling and restoring callback functions */ void -BCMATTACHFN(si_register_intr_callback)(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, +si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, void *intrsenabled_fn, void *intr_arg) { si_info_t *sii = SI_INFO(sih); @@ -3481,7 +3500,7 @@ si_flag_alt(const si_t *sih) } void -BCMATTACHFN(si_setint)(const si_t *sih, int siflag) +si_setint(const si_t *sih, int siflag) { if (CHIPTYPE(sih->socitype) == SOCI_SB) sb_setint(sih, siflag); @@ -3582,7 +3601,7 @@ si_coreunit(const si_t *sih) } uint -BCMATTACHFN(si_corevendor)(const si_t *sih) +si_corevendor(const si_t *sih) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_corevendor(sih); @@ -3601,7 +3620,7 @@ BCMATTACHFN(si_corevendor)(const si_t *sih) } bool -BCMINITFN(si_backplane64)(const si_t *sih) +si_backplane64(const si_t *sih) { return ((sih->cccaps & CC_CAP_BKPLN64) != 0); } @@ -3886,7 +3905,7 @@ uint si_get_corerev(si_t *sih, uint core_id) #endif /* !USE_NEW_COREREV_API */ int -BCMATTACHFN(si_numaddrspaces)(const si_t *sih) +si_numaddrspaces(const si_t *sih) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_numaddrspaces(sih); @@ -3937,7 +3956,7 @@ si_addrspace(const si_t *sih, uint spidx, uint baidx) * baidx : base address index */ uint32 -BCMATTACHFN(si_addrspacesize)(const si_t *sih, uint spidx, uint baidx) +si_addrspacesize(const si_t *sih, uint spidx, uint baidx) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_addrspacesize(sih, baidx); @@ -4179,69 +4198,6 @@ si_backplane_access(si_t *sih, uint addr, uint size, uint *val, bool read) return (BCME_OK); } -/* precommit failed when this is removed */ -/* BLAZAR_BRANCH_101_10_DHD_002/build/dhd/linux-fc30/brix-brcm */ -/* TBD: Revisit later */ -#ifdef BCMINTERNAL -int -si_backplane_access_64(si_t *sih, uint addr, uint size, uint64 *val, bool read) -{ -#if defined(NDIS) || defined(EFI) - SI_ERROR(("NDIS/EFI won't support 64 bit access\n")); - return (BCME_ERROR); -#else - volatile uint64 *r = NULL; - uint32 region = 0; - si_info_t *sii = SI_INFO(sih); - - /* Valid only for pcie bus */ - if (BUSTYPE(sih->bustype) != PCI_BUS) { - SI_ERROR(("Valid only for pcie bus \n")); - return BCME_ERROR; - } - - /* Split adrr into region and address offset */ - region = (addr & (0xFFFFF << 12)); - addr = addr & 0xFFF; - - /* check for address and size sanity */ - if (si_backplane_addr_sane(addr, size) != BCME_OK) { - SI_ERROR(("Address is not aligned\n")); - return BCME_ERROR; - } - - /* Update window if required */ - if (sii->second_bar0win != region) { - OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_CORE2_WIN, 4, region); - sii->second_bar0win = region; - } - - /* Estimate effective address - * sii->curmap : bar-0 virtual address - * PCI_SECOND_BAR0_OFFSET : secondar bar-0 offset - * regoff : actual reg offset - */ - r = (volatile uint64 *)((volatile char *)sii->curmap + PCI_SECOND_BAR0_OFFSET + addr); - - switch (size) { - case sizeof(uint64) : - if (read) { - *val = R_REG(sii->osh, (volatile uint64*)r); - } else { - W_REG(sii->osh, (volatile uint64*)r, *val); - } - break; - default : - SI_ERROR(("Invalid size %d \n", size)); - return (BCME_ERROR); - break; - } - - return (BCME_OK); -#endif /* NDIS */ -} -#endif /* BCMINTERNAL */ - uint BCMPOSTTRAPFN(si_corereg)(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) { @@ -4451,7 +4407,7 @@ done: } static uint32 -BCMINITFN(factor6)(uint32 x) +factor6(uint32 x) { switch (x) { case CC_F6_2: return 2; @@ -4476,7 +4432,7 @@ divide_clock(uint32 clock, uint32 div) /** calculate the speed the SI would run at given a set of clockcontrol values */ uint32 -BCMINITFN(si_clock_rate)(uint32 pll_type, uint32 n, uint32 m) +si_clock_rate(uint32 pll_type, uint32 n, uint32 m) { uint32 n1, n2, clock, m1, m2, m3, mc; @@ -4610,7 +4566,16 @@ si_chip_hostif(const si_t *sih) hosti = CHIP_HOSTIF_PCIEMODE; } break; - + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: + if (CST4381_CHIPMODE_PCIE(sih->chipst)) { + hosti = CHIP_HOSTIF_PCIEMODE; + } else if (CST4381_CHIPMODE_SDIO(sih->chipst)) { + hosti = CHIP_HOSTIF_SDIOMODE; + } else if (CST4381_CHIPMODE_USB(sih->chipst)) { + hosti = CHIP_HOSTIF_USBMODE; + } + break; default: break; } @@ -4620,7 +4585,7 @@ si_chip_hostif(const si_t *sih) #if !defined(BCMDONGLEHOST) uint32 -BCMINITFN(si_clock)(si_t *sih) +si_clock(si_t *sih) { const si_info_t *sii = SI_INFO(sih); chipcregs_t *cc; @@ -4664,7 +4629,7 @@ exit: /** returns value in [Hz] units */ uint32 -BCMINITFN(si_alp_clock)(si_t *sih) +si_alp_clock(si_t *sih) { if (PMUCTL_ENAB(sih)) { return si_pmu_alp_clock(sih, si_osh(sih)); @@ -4675,7 +4640,7 @@ BCMINITFN(si_alp_clock)(si_t *sih) /** returns value in [Hz] units */ uint32 -BCMINITFN(si_ilp_clock)(si_t *sih) +si_ilp_clock(si_t *sih) { if (PMUCTL_ENAB(sih)) return si_pmu_ilp_clock(sih, si_osh(sih)); @@ -4691,6 +4656,14 @@ si_watchdog(si_t *sih, uint ticks) uint nb, maxt; uint pmu_wdt = 1; + if ((CHIPID(sih->chip) == BCM4381_CHIP_GRPID) || + (CHIPID(sih->chip) == BCM4382_CHIP_GRPID)) { + /* For chips in which PMU is shared, cc watchdog reset + * * should be done insted of PMU + * */ + pmu_wdt = 0; + } + if (PMUCTL_ENAB(sih) && pmu_wdt) { nb = (CCREV(sih->ccrev) < 26) ? 16 : ((CCREV(sih->ccrev) >= 37) ? 32 : 24); /* The mips compiler uses the sllv instruction, @@ -4753,8 +4726,7 @@ uint32 si_watchdog_msticks(void) bool si_taclear(si_t *sih, bool details) { -#if defined(BCMDBG_ERR) || defined(BCMASSERT_SUPPORT) || \ - defined(BCMDBG_DUMP) +#if defined(BCMDBG_ERR) || defined(BCMASSERT_SUPPORT) || defined(BCMDBG_DUMP) if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_taclear(sih, details); else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || @@ -4778,15 +4750,12 @@ si_taclear(si_t *sih, bool details) * Map sb core id to pci device id. */ uint16 -BCMATTACHFN(si_d11_devid)(si_t *sih) +si_d11_devid(si_t *sih) { const si_info_t *sii = SI_INFO(sih); uint16 device; (void) sii; - if (FWSIGN_ENAB()) { - return 0xffff; - } /* normal case: nvram variable with devpath->devid->wl0id */ if ((device = (uint16)si_getdevpathintvar(sih, rstr_devid)) != 0) @@ -4807,7 +4776,7 @@ BCMATTACHFN(si_d11_devid)(si_t *sih) } int -BCMATTACHFN(si_corepciid)(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice, +si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice, uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, uint8 *pciheader) { @@ -5091,7 +5060,7 @@ si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc) } static void -BCMINITFN(si_clkctl_setdelay)(si_info_t *sii, void *chipcregs) +si_clkctl_setdelay(si_info_t *sii, void *chipcregs) { chipcregs_t *cc = (chipcregs_t *)chipcregs; uint slowmaxfreq, pll_delay, slowclk; @@ -5119,7 +5088,7 @@ BCMINITFN(si_clkctl_setdelay)(si_info_t *sii, void *chipcregs) /** initialize power control delay registers */ void -BCMINITFN(si_clkctl_init)(si_t *sih) +si_clkctl_init(si_t *sih) { si_info_t *sii; uint origidx = 0; @@ -5156,7 +5125,7 @@ BCMINITFN(si_clkctl_init)(si_t *sih) #if !defined(BCMDONGLEHOST) /** return the value suitable for writing to the dot11 core FAST_PWRUP_DELAY register */ uint16 -BCMINITFN(si_clkctl_fast_pwrup_delay)(si_t *sih) +si_clkctl_fast_pwrup_delay(si_t *sih) { si_info_t *sii = SI_INFO(sih); uint origidx = 0; @@ -5453,7 +5422,7 @@ BCMNMIATTACHFN(si_devpath_pcie)(const si_t *sih, char *path, int size) } char * -BCMATTACHFN(si_coded_devpathvar)(const si_t *sih, char *varname, int var_len, const char *name) +si_coded_devpathvar(const si_t *sih, char *varname, int var_len, const char *name) { char pathname[SI_DEVPATH_BUFSZ + 32]; char devpath[SI_DEVPATH_BUFSZ + 32]; @@ -5464,9 +5433,6 @@ BCMATTACHFN(si_coded_devpathvar)(const si_t *sih, char *varname, int var_len, co int len2; int len3 = 0; - if (FWSIGN_ENAB()) { - return NULL; - } if (BUSTYPE(sih->bustype) == PCI_BUS) { snprintf(devpath_pcie, SI_DEVPATH_BUFSZ, "pcie/%u/%u", OSL_PCIE_DOMAIN((SI_INFO(sih))->osh), @@ -5512,7 +5478,7 @@ BCMATTACHFN(si_coded_devpathvar)(const si_t *sih, char *varname, int var_len, co /** Get a variable, but only if it has a devpath prefix */ char * -BCMATTACHFN(si_getdevpathvar)(const si_t *sih, const char *name) +si_getdevpathvar(const si_t *sih, const char *name) { char varname[SI_DEVPATH_BUFSZ + 32]; char *val; @@ -5537,7 +5503,7 @@ BCMATTACHFN(si_getdevpathvar)(const si_t *sih, const char *name) /** Get a variable, but only if it has a devpath prefix */ int -BCMATTACHFN(si_getdevpathintvar)(const si_t *sih, const char *name) +si_getdevpathintvar(const si_t *sih, const char *name) { #if defined(BCMBUSTYPE) && (BCMBUSTYPE == SI_BUS) BCM_REFERENCE(sih); @@ -5572,7 +5538,7 @@ BCMATTACHFN(si_getdevpathintvar)(const si_t *sih, const char *name) * On overflow, the first char will be set to '\0'. */ static char * -BCMATTACHFN(si_devpathvar)(const si_t *sih, char *var, int len, const char *name) +si_devpathvar(const si_t *sih, char *var, int len, const char *name) { uint path_len; @@ -5592,7 +5558,7 @@ BCMATTACHFN(si_devpathvar)(const si_t *sih, char *var, int len, const char *name } static char * -BCMATTACHFN(si_pcie_devpathvar)(const si_t *sih, char *var, int len, const char *name) +si_pcie_devpathvar(const si_t *sih, char *var, int len, const char *name) { uint path_len; @@ -5825,7 +5791,7 @@ si_pcieserdesreg(const si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, /** return TRUE if PCIE capability exists in the pci config space */ static bool -BCMATTACHFN(si_ispcie)(const si_info_t *sii) +si_ispcie(const si_info_t *sii) { uint8 cap_ptr; @@ -5969,7 +5935,7 @@ si_pcie_set_request_size(const si_t *sih, uint16 size) } uint16 -BCMATTACHFN(si_pcie_get_request_size)(const si_t *sih) +si_pcie_get_request_size(const si_t *sih) { const si_info_t *sii = SI_INFO(sih); @@ -6047,7 +6013,7 @@ si_pcie_hw_L1SS_war(const si_t *sih) } void -BCMINITFN(si_pci_up)(const si_t *sih) +si_pci_up(const si_t *sih) { const si_info_t *sii; @@ -6064,7 +6030,7 @@ BCMINITFN(si_pci_up)(const si_t *sih) /** Unconfigure and/or apply various WARs when system is going to sleep mode */ void -BCMUNINITFN(si_pci_sleep)(const si_t *sih) +si_pci_sleep(const si_t *sih) { /* 4360 pcie2 WAR */ do_4360_pcie2_war = 0; @@ -6074,7 +6040,7 @@ BCMUNINITFN(si_pci_sleep)(const si_t *sih) /** Unconfigure and/or apply various WARs when the wireless interface is going down */ void -BCMINITFN(si_pci_down)(const si_t *sih) +si_pci_down(const si_t *sih) { const si_info_t *sii = SI_INFO(sih); BCM_REFERENCE(sii); @@ -6091,7 +6057,7 @@ BCMINITFN(si_pci_down)(const si_t *sih) * coremask is the bitvec of cores by index to be enabled. */ void -BCMATTACHFN(si_pci_setup)(si_t *sih, uint coremask) +si_pci_setup(si_t *sih, uint coremask) { const si_info_t *sii = SI_INFO(sih); sbpciregs_t *pciregs = NULL; @@ -6157,7 +6123,7 @@ BCMATTACHFN(si_pci_setup)(si_t *sih, uint coremask) /* In NIC mode is there any better way to find out what ARM core is there? */ static uint -BCMATTACHFN(si_get_armcoreidx)(si_t *sih) +si_get_armcoreidx(si_t *sih) { uint saveidx = si_coreidx(sih); uint coreidx = BADIDX; @@ -6177,7 +6143,7 @@ BCMATTACHFN(si_get_armcoreidx)(si_t *sih) * coreidx is the index of the core to be enabled. */ int -BCMATTACHFN(si_pcie_setup)(si_t *sih, uint coreidx) +si_pcie_setup(si_t *sih, uint coreidx) { si_info_t *sii = SI_INFO(sih); int main_intr, alt_intr; @@ -6302,7 +6268,7 @@ si_pcieltrenable(const si_t *sih, uint32 mask, uint32 val) } uint8 -BCMATTACHFN(si_pcieobffenable)(const si_t *sih, uint32 mask, uint32 val) +si_pcieobffenable(const si_t *sih, uint32 mask, uint32 val) { const si_info_t *sii = SI_INFO(sih); @@ -6914,7 +6880,7 @@ si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val) } uint32 -BCMATTACHFN(si_gpio_int_enable)(si_t *sih, bool enable) +si_gpio_int_enable(si_t *sih, bool enable) { uint offs; @@ -6969,6 +6935,7 @@ si_gci_shif_config_wake_pin(si_t *sih, uint8 gpio_n, uint8 wake_events, } case BCM4385_CHIP_GRPID : case BCM4387_CHIP_GRPID : + case BCM4389_CHIP_GRPID : { if (!gci_gpio) { chipcontrol = (1 << GCI_GPIO_CHIPCTRL_ENAB_EXT_GPIO_BIT); @@ -7017,6 +6984,8 @@ si_shif_int_enable(si_t *sih, uint8 gpio_n, uint8 wake_events, bool enable) } #endif /* !defined(BCMDONGLEHOST) */ +#define SI_BANKINFO_DELAY_USEC 10u + /** Return the size of the specified SYSMEM bank */ static uint sysmem_banksize(const si_info_t *sii, sysmemregs_t *regs, uint8 idx) @@ -7025,11 +6994,20 @@ sysmem_banksize(const si_info_t *sii, sysmemregs_t *regs, uint8 idx) uint bankidx = idx; W_REG(sii->osh, ®s->bankidx, bankidx); + /* Add some delay before reading back bankinfo */ + OSL_DELAY(SI_BANKINFO_DELAY_USEC); bankinfo = R_REG(sii->osh, ®s->bankinfo); banksize = SYSMEM_BANKINFO_SZBASE * ((bankinfo & SYSMEM_BANKINFO_SZMASK) + 1); + + SI_PRINT(("%s: bankidx:%d bankinfo:0x%x banksize:%d(0x%x)\n", + __FUNCTION__, bankidx, bankinfo, banksize, banksize)); + return banksize; } +#define SI_CORE_RESET_DELAY_USEC 10u +#define SI_CORE_RESET_RETRY 5u + /** Return the RAM size of the SYSMEM core */ uint32 si_sysmem_size(si_t *sih) @@ -7044,19 +7022,42 @@ si_sysmem_size(si_t *sih) uint memsize = 0; uint8 i; uint nb, nrb; + uint32 retry = SI_CORE_RESET_RETRY; + SI_MSG_DBG_REG(("%s: Enter\n", __FUNCTION__)); /* Block ints and save current core */ INTR_OFF(sii, &intr_val); origidx = si_coreidx(sih); /* Switch to SYSMEM core */ - if (!(regs = si_setcore(sih, SYSMEM_CORE_ID, 0))) + if (!(regs = si_setcore(sih, SYSMEM_CORE_ID, 0))) { + SI_ERROR(("%s: si_setcore SYSMEM_CORE_ID failed\n", __FUNCTION__)); goto done; + } + + while (retry--) { + /* retry if core is not up */ + if (!(wasup = si_iscoreup(sih))) { + SI_PRINT(("%s: core not up, do si_core_reset, retry:%d\n", + __FUNCTION__, retry)); + si_core_reset(sih, 0, 0); + /* Add some delay after reset */ + OSL_DELAY(SI_CORE_RESET_DELAY_USEC); + } else { + break; + } + } + + if (retry == 0) { + SI_ERROR(("%s: failed\n", __FUNCTION__)); + goto restore_core; + } - /* Get info for determining size */ - if (!(wasup = si_iscoreup(sih))) - si_core_reset(sih, 0, 0); coreinfo = R_REG(sii->osh, ®s->coreinfo); + if (coreinfo == (uint32)-1) { + SI_ERROR(("%s: invalid coreinfo:0x%x\n", __FUNCTION__, coreinfo)); + goto restore_core; + } /* Number of ROM banks, SW need to skip the ROM banks. */ if (si_corerev(sih) < 12) { @@ -7066,14 +7067,20 @@ si_sysmem_size(si_t *sih) nrb = (coreinfo & SYSMEM_SRCI_NEW_ROMNB_MASK) >> SYSMEM_SRCI_NEW_ROMNB_SHIFT; nb = (coreinfo & SYSMEM_SRCI_NEW_SRNB_MASK) >> SYSMEM_SRCI_NEW_SRNB_SHIFT; } + + SI_PRINT(("%s: coreinfo:0x%x num_rom_banks:%d num_ram_baks:%d\n", + __FUNCTION__, coreinfo, nrb, nb)); + for (i = 0; i < nb; i++) memsize += sysmem_banksize(sii, regs, i + nrb); +restore_core: si_setcoreidx(sih, origidx); done: INTR_RESTORE(sii, &intr_val); + SI_MSG_DBG_REG(("%s: Exit memsize=%d\n", __FUNCTION__, memsize)); return memsize; } @@ -7264,6 +7271,7 @@ si_tcm_size(si_t *sih) volatile uint32 *arm_bidx; volatile uint32 *arm_binfo; + SI_MSG_DBG_REG(("%s: Enter\n", __FUNCTION__)); /* Block ints and save current core */ INTR_OFF(sii, &intr_val); origidx = si_coreidx(sih); @@ -7306,7 +7314,7 @@ si_tcm_size(si_t *sih) done: INTR_RESTORE(sii, &intr_val); - + SI_MSG_DBG_REG(("%s: Exit memsize=%d\n", __FUNCTION__, memsize)); return memsize; } @@ -7614,7 +7622,7 @@ bool si_seci_clk_force_status(si_t *sih) /** SECI Init routine, pass in seci_mode */ volatile void * -BCMINITFN(si_seci_init)(si_t *sih, uint8 seci_mode) +si_seci_init(si_t *sih, uint8 seci_mode) { uint32 origidx = 0; uint32 offset; @@ -7760,7 +7768,7 @@ BCMINITFN(si_seci_init)(si_t *sih, uint8 seci_mode) /** Query OTP to see if FM is disabled */ static int -BCMINITFN(si_query_FMDisabled_from_OTP)(si_t *sih, uint16 *FMDisabled) +si_query_FMDisabled_from_OTP(si_t *sih, uint16 *FMDisabled) { int error = BCME_OK; uint bitoff = 0; @@ -7813,7 +7821,7 @@ si_sraon(const si_t *sih) /** ECI Init routine */ int -BCMINITFN(si_eci_init)(si_t *sih) +si_eci_init(si_t *sih) { uint32 origidx = 0; const si_info_t *sii; @@ -8023,7 +8031,7 @@ exit: } void * -BCMINITFN(si_gci_init)(si_t *sih) +si_gci_init(si_t *sih) { #ifdef HNDGCI const si_info_t *sii = SI_INFO(sih); @@ -8295,6 +8303,8 @@ si_is_sprom_available(si_t *sih) case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: return (sih->chipst & CST4387_SPROM_PRESENT) != 0; + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4388_CHIP_GRPID: case BCM4389_CHIP_GRPID: case BCM4397_CHIP_GRPID: @@ -8308,12 +8318,7 @@ si_is_sprom_available(si_t *sih) bool si_is_sflash_available(const si_t *sih) { - switch (CHIPID(sih->chip)) { - case BCM4387_CHIP_ID: - return (sih->chipst & CST4387_SFLASH_PRESENT) != 0; - default: - return FALSE; - } + return (sih->chipst & CST_SFLASH_PRESENT) != 0; } #if !defined(BCMDONGLEHOST) @@ -8336,6 +8341,8 @@ si_is_otp_disabled(const si_t *sih) case BCM4362_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -8410,6 +8417,8 @@ si_cis_source(const si_t *sih) if (sih->chipst & CST4387_SPROM_PRESENT) return CIS_SROM; return CIS_OTP; + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4388_CHIP_GRPID: case BCM4389_CHIP_GRPID: case BCM4397_CHIP_GRPID: @@ -8420,7 +8429,7 @@ si_cis_source(const si_t *sih) } } -uint16 BCMATTACHFN(si_fabid)(si_t *sih) +uint16 si_fabid(si_t *sih) { uint32 data; uint16 fabid = 0; @@ -8434,6 +8443,8 @@ uint16 BCMATTACHFN(si_fabid)(si_t *sih) case BCM4362_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -8451,7 +8462,7 @@ uint16 BCMATTACHFN(si_fabid)(si_t *sih) } #endif /* !defined(BCMDONGLEHOST) */ -uint32 BCMATTACHFN(si_get_sromctl)(si_t *sih) +uint32 si_get_sromctl(si_t *sih) { chipcregs_t *cc; uint origidx = si_coreidx(sih); @@ -8468,7 +8479,7 @@ uint32 BCMATTACHFN(si_get_sromctl)(si_t *sih) return sromctl; } -int BCMATTACHFN(si_set_sromctl)(si_t *sih, uint32 value) +int si_set_sromctl(si_t *sih, uint32 value) { chipcregs_t *cc; uint origidx = si_coreidx(sih); @@ -8551,6 +8562,8 @@ si_update_masks(si_t *sih) case BCM4362_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -8929,7 +8942,7 @@ BCMPOSTTRAPFN(si_clear_backplane_to)(si_t *sih) } void -BCMATTACHFN(si_update_backplane_timeouts)(const si_t *sih, bool enable, uint32 timeout_exp, +si_update_backplane_timeouts(const si_t *sih, bool enable, uint32 timeout_exp, uint32 cid) { #if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC) @@ -9077,7 +9090,7 @@ si_pll_sr_reinit(si_t *sih) } void -BCMATTACHFN(si_pll_closeloop)(si_t *sih) +si_pll_closeloop(si_t *sih) { #if !defined(BCMDONGLEHOST) && !defined(DONGLEBUILD) || defined(SAVERESTORE) uint32 data; @@ -9107,6 +9120,8 @@ BCMATTACHFN(si_pll_closeloop)(si_t *sih) case BCM4362_CHIP_GRPID: case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -9229,7 +9244,7 @@ BCMPOSTTRAPFN(si_get_ccidiv)(const si_t *sih) } #ifdef DONGLEBUILD uint32 -BCMATTACHFN(si_wrapper_dump_buf_size)(const si_t *sih) +si_wrapper_dump_buf_size(const si_t *sih) { if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_wrapper_dump_buf_size(sih); @@ -9334,10 +9349,6 @@ BCMPOSTTRAPFN(si_srpwr_request)(const si_t *sih, uint32 mask, uint32 val) volatile uint32 *fast_srpwr_addr = (volatile uint32 *)((uintptr)SI_ENUM_BASE(sih) + (uintptr)offset); - if (FWSIGN_ENAB()) { - return 0; - } - if (mask || val) { mask <<= SRPWR_REQON_SHIFT; val <<= SRPWR_REQON_SHIFT; @@ -9463,9 +9474,6 @@ BCMPOSTTRAPFN(si_srpwr_stat_spinwait)(const si_t *sih, uint32 mask, uint32 val) volatile uint32 *fast_srpwr_addr = (volatile uint32 *)((uintptr)SI_ENUM_BASE(sih) + (uintptr)offset); - if (FWSIGN_ENAB()) { - return 0; - } ASSERT(mask); ASSERT(val); @@ -9515,10 +9523,6 @@ si_srpwr_domain(si_t *sih) OFFSETOF(chipcregs_t, powerctl) : PWRREQ_OFFSET(sih); uint cidx = (BUSTYPE(sih->bustype) == SI_BUS) ? SI_CC_IDX : sih->buscoreidx; - if (FWSIGN_ENAB()) { - return 0; - } - if (BUSTYPE(sih->bustype) == SI_BUS) { r = si_corereg(sih, cidx, offset, 0, 0); } else { @@ -9539,10 +9543,6 @@ si_srpwr_domain_wl(si_t *sih) bool si_srpwr_cap(si_t *sih) { - if (FWSIGN_ENAB()) { - return FALSE; - } - /* If domain ID is non-zero, chip supports power domain control */ return si_srpwr_domain(sih) != 0 ? TRUE : FALSE; } @@ -9675,14 +9675,11 @@ si_hib_ext_wakeup_isenab(const si_t *sih) } static void -BCMATTACHFN(si_oob_war_BT_F1)(si_t *sih) +si_oob_war_BT_F1(si_t *sih) { uint origidx = si_coreidx(sih); volatile void *regs; - if (FWSIGN_ENAB()) { - return; - } regs = si_setcore(sih, AXI2AHB_BRIDGE_ID, 0); ASSERT(regs); BCM_REFERENCE(regs); @@ -9986,6 +9983,8 @@ si_chipcap_sdio_ate_only(const si_t *sih) break; case BCM4376_CHIP_GRPID: case BCM4378_CHIP_GRPID: + case BCM4381_CHIP_GRPID: + case BCM4383_CHIP_GRPID: case BCM4385_CHIP_GRPID: case BCM4387_CHIP_GRPID: case BCM4388_CHIP_GRPID: @@ -10110,7 +10109,7 @@ si_btc_bt_pds_wakeup_force(si_t *sih, bool force) #ifndef BCMDONGLEHOST /* query d11 core type */ uint -BCMATTACHFN(si_core_d11_type)(si_t *sih, uint coreunit) +si_core_d11_type(si_t *sih, uint coreunit) { #ifdef WL_SCAN_CORE_SIM /* use the core unit WL_SCAN_CORE_SIM as the scan core */ @@ -10136,7 +10135,7 @@ BCMATTACHFN(si_core_d11_type)(si_t *sih, uint coreunit) /* decide if this core is allowed by the package option or not... */ bool -BCMATTACHFN(si_pkgopt_d11_allowed)(si_t *sih, uint coreunit) +si_pkgopt_d11_allowed(si_t *sih, uint coreunit) { uint coreidx; volatile void *regs; @@ -10202,7 +10201,7 @@ si_jtag_udr_pwrsw_main_toggle(si_t *sih, bool on) /* return the backplane address where the sssr dumps are stored per D11 core */ uint32 -BCMATTACHFN(si_d11_core_sssr_addr)(si_t *sih, uint unit, uint32 *sssr_size) +si_d11_core_sssr_addr(si_t *sih, uint unit, uint32 *sssr_size) { uint32 sssr_dmp_src = 0; *sssr_size = 0; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils_priv.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils_priv.h old mode 100755 new mode 100644 index 39350391b9f1..f57c41c4a993 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils_priv.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils_priv.h @@ -1,7 +1,7 @@ /* * Include file private to the SOC Interconnect support files. * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -52,6 +52,12 @@ #define SI_MSG(args) #endif /* BCMDBG */ +#ifdef DHD_DEBUG_REG_DUMP +#define SI_MSG_DBG_REG(args) printf args +#else +#define SI_MSG_DBG_REG(args) +#endif /* DHD_DEBUG_REG_DUMP */ + #ifdef BCMDBG_SI #define SI_VMSG(args) printf args #else @@ -509,5 +515,5 @@ void ai_force_clocks(const si_t *sih, uint clock_state); #define nci_wrapper_dump_last_timeout(a, b, c, d, e) (0) #define nci_check_enable_backplane_log(a) (FALSE) #define nci_wrapper_dump_buf_size(a) (0) -#endif /* SOCI_NCI_BUS */ +#endif /* !SOCI_NCI_BUS */ #endif /* _siutils_priv_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wb_regon_coordinator.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wb_regon_coordinator.c old mode 100755 new mode 100644 index bd3aa84210d0..571d9728bcdb --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wb_regon_coordinator.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wb_regon_coordinator.c @@ -1,7 +1,7 @@ /* * DHD BT WiFi Coex RegON Coordinator * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -94,6 +94,8 @@ struct wbrc_pvt_data { unsigned int bt_reset_ack; /* condition variable to be check for bt reset */ wait_queue_head_t wlan_reset_waitq; /* waitq to wait till wlan reset is done */ unsigned int wlan_reset_ack; /* condition variable to be check for wlan reset */ + wait_queue_head_t wlan_on_waitq; /* waitq to wait till wlan on is done */ + unsigned int wlan_on_ack; /* condition variable to be check for wlan on */ wait_queue_head_t outmsg_waitq; /* wait queue for poll */ char wl2bt_message[WBRC_MSG_LEN]; /* message to communicate with Bt stack */ bool read_data_available; /* condition to check if read data is present */ @@ -107,8 +109,8 @@ static struct wbrc_pvt_data *g_wbrc_data; int wbrc_wl2bt_reset(void); int wbrc_bt_reset_ack(struct wbrc_pvt_data *wbrc_data); -int wbrc_bt2wl_reset(void); -int wbrc_wl_reset_ack(struct wbrc_pvt_data *wbrc_data); +static int wbrc_bt2wl_reset(void); +static int wbrc_wl_reset_ack(struct wbrc_pvt_data *wbrc_data); static int wbrc_bt_dev_open(struct inode *, struct file *); static int wbrc_bt_dev_release(struct inode *, struct file *); @@ -169,7 +171,7 @@ static ssize_t wbrc_bt_dev_write(struct file *filep, const char *buffer, WBRC_LOCK(wbrc_data); pr_info("%s Received %zu bytes\n", __func__, len); - if (len < WBRC_MSG_LEN) { + if (len != WBRC_MSG_LEN) { pr_err("%s: Received malformed packet:%d\n", __func__, (int)len); ret = -EFAULT; goto exit; @@ -191,10 +193,11 @@ static ssize_t wbrc_bt_dev_write(struct file *filep, const char *buffer, if (message[2] == TYPE_BT_CMD) { switch (message[3]) { case CMD_RESET_WIFI: - pr_info("RCVD CMD_RESET_WIFI\n"); + pr_info("RCVD TYPE_BT_CMD: CMD_RESET_WIFI\n"); break; case CMD_RESET_WIFI_WITH_ACK: - pr_info("RCVD CMD_RESET_WIFI_WITH_ACK\n"); + pr_info("RCVD TYPE_BT_CMD: CMD_RESET_WIFI_WITH_ACK\n"); + wbrc_bt2wl_reset(); break; } } @@ -225,6 +228,8 @@ static __poll_t wbrc_bt_dev_poll(struct file *filep, poll_table *wait) return mask; } +int wbrc_reset_wait_on_condition(wait_queue_head_t *reset_waitq, uint *var, uint condition); + static int wbrc_bt_dev_open(struct inode *inodep, struct file *filep) { struct wbrc_pvt_data *wbrc_data = g_wbrc_data; @@ -232,16 +237,35 @@ static int wbrc_bt_dev_open(struct inode *inodep, struct file *filep) WBRC_LOCK(wbrc_data); if (wbrc_data->bt_dev_opened) { pr_err("%s already opened\n", __func__); - ret = -EFAULT; - goto exit; + WBRC_UNLOCK(wbrc_data); + return -EFAULT; } wbrc_data->bt_dev_opened = TRUE; pr_info("%s Device opened %d time(s)\n", __func__, wbrc_data->bt_dev_opened); filep->private_data = wbrc_data; -exit: - WBRC_UNLOCK(wbrc_data); + /* If wlan_on_ack is false means, the dev_open is called during WLAN ON */ + if (wbrc_data->wlan_on_ack == FALSE) { + /* unlock mutex before wait as wbrc_wlan_on_ack also holds same mutex */ + WBRC_UNLOCK(wbrc_data); + + pr_info("%s: wait for wlan_on_ack\n", __func__); + /* Wait till wlan is ON */ + wbrc_reset_wait_on_condition(&wbrc_data->wlan_on_waitq, + &wbrc_data->wlan_on_ack, TRUE); + if (wbrc_data->wlan_on_ack == FALSE) { + pr_err("%s: WLAN ON timeout\n", __func__); + } else { + pr_info("%s: got wlan_on_ack\n", __func__); + } + } else { + pr_info("%s: wlan_on_ack is TRUE\n", __func__); + WBRC_UNLOCK(wbrc_data); + } + + pr_info("%s Done\n", __func__); + return ret; } @@ -283,7 +307,12 @@ int wbrc_init(void) mutex_init(&wbrc_data->wbrc_mutex); init_waitqueue_head(&wbrc_data->bt_reset_waitq); init_waitqueue_head(&wbrc_data->wlan_reset_waitq); + init_waitqueue_head(&wbrc_data->wlan_on_waitq); init_waitqueue_head(&wbrc_data->outmsg_waitq); + + /* Set wlan_on_ack in bootup so that 1st BT ON without WLAN does not wait */ + wbrc_data->wlan_on_ack = TRUE; + g_wbrc_data = wbrc_data; wbrc_data->wbrc_bt_dev_major_number = register_chrdev(0, DEVICE_NAME, &wbrc_bt_dev_fops); @@ -363,6 +392,34 @@ wbrc_reset_wait_on_condition(wait_queue_head_t *reset_waitq, uint *var, uint con return timeout; } +int wbrc_wlan_on_ack(void) +{ + struct wbrc_pvt_data *wbrc_data = g_wbrc_data; + + WBRC_LOCK(wbrc_data); + if (wbrc_data->wlan_on_ack == FALSE) { + pr_info("%s: set wlan_on_ack\n", __func__); + wbrc_data->wlan_on_ack = TRUE; + smp_wmb(); + wake_up(&wbrc_data->wlan_on_waitq); + } + WBRC_UNLOCK(wbrc_data); + + return 0; +} + +int wbrc_wlan_on_started(void) +{ + struct wbrc_pvt_data *wbrc_data = g_wbrc_data; + + WBRC_LOCK(wbrc_data); + pr_info("%s: reset wlan_on_ack\n", __func__); + wbrc_data->wlan_on_ack = FALSE; + WBRC_UNLOCK(wbrc_data); + + return 0; +} + /* WBRC_LOCK should be held from caller */ int wbrc_bt_reset_ack(struct wbrc_pvt_data *wbrc_data) { @@ -375,18 +432,19 @@ int wbrc_bt_reset_ack(struct wbrc_pvt_data *wbrc_data) int wbrc_wl2bt_reset(void) { - int ret = 0; struct wbrc_pvt_data *wbrc_data = g_wbrc_data; pr_info("%s\n", __func__); WBRC_LOCK(wbrc_data); + if (!wbrc_data->bt_dev_opened) { pr_info("%s: no BT\n", __func__); WBRC_UNLOCK(wbrc_data); - return ret; + return -1; } + /* bt_reset_ack will be set after BT acks for reset */ wbrc_data->bt_reset_ack = FALSE; wbrc_signal_bt_reset(wbrc_data); @@ -397,38 +455,60 @@ int wbrc_wl2bt_reset(void) &wbrc_data->bt_reset_ack, TRUE); if (wbrc_data->bt_reset_ack == FALSE) { pr_err("%s: BT reset timeout\n", __func__); - ret = -1; + } else { + pr_info("%s: got bt_reset_ack\n", __func__); } - return ret; + return 0; } EXPORT_SYMBOL(wbrc_wl2bt_reset); -int wbrc_signal_wlan_reset(struct wbrc_pvt_data *wbrc_data) +#ifdef WBRC_BT2WL_RESET +extern void dhd_wbrc_wl_trap(void); +#endif /* WBRC_BT2WL_RESET */ + +/* WBRC_LOCK should be held from caller */ +static int +wbrc_signal_wlan_reset(struct wbrc_pvt_data *wbrc_data) { - /* TODO call dhd reset, right now just send ack from here */ +#ifdef WBRC_BT2WL_RESET + /* Force trap wl */ + dhd_wbrc_wl_trap(); +#endif /* WBRC_BT2WL_RESET */ wbrc_wl_reset_ack(wbrc_data); return 0; } -/* WBRC_LOCK should be held from caller, this will be called from DHD */ -int wbrc_wl_reset_ack(struct wbrc_pvt_data *wbrc_data) +/* WBRC_LOCK should be held from caller */ +static int +wbrc_wl_reset_ack(struct wbrc_pvt_data *wbrc_data) { pr_info("%s\n", __func__); wbrc_data->wlan_reset_ack = TRUE; + + /* Below message will be read by userspace using .read */ + wbrc_data->wl2bt_message[0] = HEADER_DIR_WL2BT; // Minimal Header + wbrc_data->wl2bt_message[1] = 2; // Length + wbrc_data->wl2bt_message[2] = TYPE_WIFI_ACK; // Type + wbrc_data->wl2bt_message[3] = ACK_RESET_WIFI_COMPLETE; // Value + wbrc_data->read_data_available = TRUE; + + smp_wmb(); + wake_up_interruptible(&wbrc_data->outmsg_waitq); + smp_wmb(); wake_up(&wbrc_data->wlan_reset_waitq); return 0; } -EXPORT_SYMBOL(wbrc_wl_reset_ack); -int wbrc_bt2wl_reset(void) +/* WBRC_LOCK should be held from caller */ +static int +wbrc_bt2wl_reset(void) { int ret = 0; struct wbrc_pvt_data *wbrc_data = g_wbrc_data; pr_info("%s\n", __func__); - WBRC_LOCK(wbrc_data); wbrc_data->wlan_reset_ack = FALSE; wbrc_signal_wlan_reset(wbrc_data); /* Wait till WLAN reset is done */ @@ -438,7 +518,5 @@ int wbrc_bt2wl_reset(void) pr_err("%s: WLAN reset timeout\n", __func__); ret = -1; } - WBRC_UNLOCK(wbrc_data); return ret; } -EXPORT_SYMBOL(wbrc_bt2wl_reset); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wifi_stats.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wifi_stats.h old mode 100755 new mode 100644 index a4d2e7393c9a..94a2136324c2 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wifi_stats.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wifi_stats.h @@ -2,7 +2,7 @@ * Common stats definitions for clients of dongle * ports * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -31,6 +31,10 @@ #include #include <802.11.h> +#ifdef CONFIG_COMPAT +#include +#endif /* CONFIG_COMPAT */ + typedef int32 wifi_radio; typedef int32 wifi_channel; typedef int32 wifi_rssi; @@ -68,9 +72,26 @@ typedef enum { WIFI_INTERFACE_P2P_CLIENT = 3, WIFI_INTERFACE_P2P_GO = 4, WIFI_INTERFACE_NAN = 5, - WIFI_INTERFACE_MESH = 6 + WIFI_INTERFACE_MESH = 6, + WIFI_INTERFACE_TDLS = 7 } wifi_interface_mode; +typedef enum { + /* Filter channels that are unsafe due to cellular coexistence */ + WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE = 1 << 0, + /* Filter channels due to concurrency state */ + WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY = 1 << 1, + /* Filter the channels out for non nan and non instant mode usable */ + /* This Filter queries Wifi channels and bands that are supported for + * NAN3.1 Instant communication mode. This filter should only be applied to NAN interface. + * If 5G is supported default discovery channel 149/44 is considered, + * If 5G is not supported then channel 6 has to be considered. + * Based on regulatory domain if channel 149 and 44 are restricted, channel 6 should + * be considered for instant communication channel + */ + WIFI_USABLE_CHANNEL_FILTER_NAN_INSTANT_MODE = 1 << 2 +} wifi_usable_channel_filter; + #define WIFI_CAPABILITY_QOS 0x00000001 /* set for QOS association */ #define WIFI_CAPABILITY_PROTECTED 0x00000002 /* set for protected association (802.11 * beacon frame control protected bit set) @@ -83,6 +104,9 @@ typedef enum { * element UTF-8 SSID bit is set */ #define WIFI_CAPABILITY_COUNTRY 0x00000020 /* set is 802.11 Country Element is present */ +#define WIFI_RSDB_TIMESLICE_DUTY_CYCLE 100 +#define WIFI_VSDB_TIMESLICE_DUTY_CYCLE 50 + #if defined(__linux__) #define PACK_ATTRIBUTE __attribute__ ((packed)) #else @@ -103,7 +127,27 @@ typedef struct { uint8 PAD[2]; } wifi_interface_info; +typedef struct { + wifi_interface_mode mode; /* interface mode */ + uint8 mac_addr[6]; /* interface mac address (self) */ + uint8 PAD[2]; + wifi_connection_state state; /* connection state (valid for STA, CLI only) */ + wifi_roam_state roaming; /* roaming state */ + uint32 capabilities; /* WIFI_CAPABILITY_XXX (self) */ + uint8 ssid[DOT11_MAX_SSID_LEN+1]; /* null terminated SSID */ + uint8 bssid[ETHER_ADDR_LEN]; /* bssid */ + uint8 ap_country_str[3]; /* country string advertised by AP */ + uint8 country_str[3]; /* country string for this association */ + uint8 time_slicing_duty_cycle_percent; /* if this iface is being served using time slicing + * on a radio with one or more ifaces (i.e MCC), + * then the duty cycle assigned to this iface in %. + * If not using time slicing (i.e SCC or DBS), + * set to 100. + */ +} wifi_interface_info_v1; + typedef wifi_interface_info *wifi_interface_handle; +typedef wifi_interface_info_v1 *wifi_interface_handle_v1; /* channel information */ typedef struct { @@ -149,44 +193,6 @@ typedef struct { */ } wifi_channel_stat; -/* radio statistics */ -typedef struct { - struct { - uint16 version; - uint16 length; - }; - wifi_radio radio; /* wifi radio (if multiple radio supported) */ - uint32 on_time; /* msecs the radio is awake (32 bits number - * accruing over time) - */ - uint32 tx_time; /* msecs the radio is transmitting (32 bits - * number accruing over time) - */ - uint32 rx_time; /* msecs the radio is in active receive (32 bits - * number accruing over time) - */ - uint32 on_time_scan; /* msecs the radio is awake due to all scan (32 bits - * number accruing over time) - */ - uint32 on_time_nbd; /* msecs the radio is awake due to NAN (32 bits - * number accruing over time) - */ - uint32 on_time_gscan; /* msecs the radio is awake due to G?scan (32 bits - * number accruing over time) - */ - uint32 on_time_roam_scan; /* msecs the radio is awake due to roam?scan (32 bits - * number accruing over time) - */ - uint32 on_time_pno_scan; /* msecs the radio is awake due to PNO scan (32 bits - * number accruing over time) - */ - uint32 on_time_hs20; /* msecs the radio is awake due to HS2.0 scans and - * GAS exchange (32 bits number accruing over time) - */ - uint32 num_channels; /* number of channels */ - wifi_channel_stat channels[1]; /* channel statistics */ -} wifi_radio_stat; - typedef struct { wifi_radio radio; uint32 on_time; @@ -201,6 +207,28 @@ typedef struct { uint32 num_channels; } wifi_radio_stat_h; +typedef struct { + wifi_radio radio; + uint32 on_time; + uint32 tx_time; + uint32 num_tx_levels; + uint32 *tx_time_per_levels; + uint32 rx_time; + uint32 on_time_scan; + uint32 on_time_nbd; + uint32 on_time_gscan; + uint32 on_time_roam_scan; + uint32 on_time_pno_scan; + uint32 on_time_hs20; + uint32 num_channels; +} wifi_radio_stat_h_v2; + +/* radio statistics */ +typedef struct { + wifi_radio_stat_h_v2 radio_stats; + wifi_channel_stat channels[]; // channel statistics +} wifi_radio_stat; + /* per rate statistics */ typedef struct { wifi_rate_v1 rate; /* rate information */ @@ -246,6 +274,21 @@ typedef enum } wifi_peer_type; /* per peer statistics */ +typedef struct bssload_info { + uint16 sta_count; /* station count */ + uint16 chan_util; /* channel utilization */ + uint8 PAD[4]; +} bssload_info_t; + +typedef struct { + wifi_peer_type type; /* peer type (AP, TDLS, GO etc.) */ + uint8 peer_mac_address[6]; /* mac address */ + uint32 capabilities; /* peer WIFI_CAPABILITY_XXX */ + bssload_info_t bssload; /* STA count and CU */ + uint32 num_rate; /* number of rates */ + wifi_rate_stat rate_stats[1]; /* per rate statistics, number of entries = num_rate */ +} wifi_peer_info_v1; + typedef struct { wifi_peer_type type; /* peer type (AP, TDLS, GO etc.) */ uint8 peer_mac_address[6]; /* mac address */ @@ -282,8 +325,13 @@ typedef struct { /* interface statistics */ typedef struct { +#ifdef LINKSTAT_EXT_SUPPORT + wifi_interface_handle_v1 iface; /* wifi interface */ + wifi_interface_info_v1 info; /* current state of the interface */ +#else wifi_interface_handle iface; /* wifi interface */ wifi_interface_info info; /* current state of the interface */ +#endif /* LINKSTAT_EXT_SUPPORT */ uint32 beacon_rx; /* access point beacon received count from * connected AP */ @@ -322,14 +370,22 @@ typedef struct { */ wifi_wmm_ac_stat ac[WIFI_AC_MAX]; /* per ac data packet statistics */ uint32 num_peers; /* number of peers */ +#if defined(LINKSTAT_EXT_SUPPORT) || (ANDROID_VERSION >= 12) + wifi_peer_info_v1 peer_info[1]; /* per peer statistics */ +#else wifi_peer_info peer_info[1]; /* per peer statistics */ +#endif /* LINKSTAT_EXT_SUPPORT */ } wifi_iface_stat; #ifdef CONFIG_COMPAT /* interface statistics */ typedef struct { compat_uptr_t iface; /* wifi interface */ +#ifdef LINKSTAT_EXT_SUPPORT + wifi_interface_info_v1 info; /* current state of the interface */ +#else wifi_interface_info info; /* current state of the interface */ +#endif /* LINKSTAT_EXT_SUPPORT */ uint32 beacon_rx; /* access point beacon received count from * connected AP */ @@ -368,7 +424,11 @@ typedef struct { */ wifi_wmm_ac_stat ac[WIFI_AC_MAX]; /* per ac data packet statistics */ uint32 num_peers; /* number of peers */ +#if defined(LINKSTAT_EXT_SUPPORT) || (ANDROID_VERSION >= 12) + wifi_peer_info_v1 peer_info[1]; /* per peer statistics */ +#else wifi_peer_info peer_info[1]; /* per peer statistics */ +#endif /* LINKSTAT_EXT_SUPPORT */ } compat_wifi_iface_stat; #endif /* CONFIG_COMPAT */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c old mode 100755 new mode 100644 index ae863e1f653c..f07c6cce0069 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Android related functions * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,6 +21,8 @@ * <> */ +#define CLEANED_UP_IOCTL 1 + #include #include #include @@ -38,7 +40,6 @@ #include #include #include -#include #include #ifdef PNO_SUPPORT #include @@ -50,6 +51,7 @@ #include #include #include +#include #endif #ifdef WL_NAN #include @@ -57,16 +59,16 @@ #ifdef DHDTCPACK_SUPPRESS #include #endif /* DHDTCPACK_SUPPRESS */ +#ifdef USE_NEW_RSPEC_DEFS #include +#endif /* USE_NEW_RSPEC_DEFS */ #include #include #ifdef DHD_PKT_LOGGING #include #endif /* DHD_PKT_LOGGING */ -#ifdef WL_BCNRECV #include #include -#endif /* WL_BCNRECV */ #ifdef WL_MBO #include #endif /* WL_MBO */ @@ -76,42 +78,10 @@ #ifdef DHD_EVENT_LOG_FILTER #include #endif /* DHD_EVENT_LOG_FILTER */ -#ifdef WL_ESCAN -#include -#endif #ifdef WL_TWT #include <802.11ah.h> #endif /* WL_TWT */ - -#ifdef WL_STATIC_IF -#define WL_BSSIDX_MAX 16 -#endif /* WL_STATIC_IF */ - -uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL; - -#define ANDROID_ERROR_MSG(x, args...) \ - do { \ - if (android_msg_level & ANDROID_ERROR_LEVEL) { \ - printf("ANDROID-ERROR) " x, ## args); \ - } \ - } while (0) -#define ANDROID_TRACE_MSG(x, args...) \ - do { \ - if (android_msg_level & ANDROID_TRACE_LEVEL) { \ - printf("ANDROID-TRACE) " x, ## args); \ - } \ - } while (0) -#define ANDROID_INFO_MSG(x, args...) \ - do { \ - if (android_msg_level & ANDROID_INFO_LEVEL) { \ - printf("ANDROID-INFO) " x, ## args); \ - } \ - } while (0) -#define ANDROID_ERROR(x) ANDROID_ERROR_MSG x -#define ANDROID_TRACE(x) ANDROID_TRACE_MSG x -#define ANDROID_INFO(x) ANDROID_INFO_MSG x - /* * Android private command strings, PLEASE define new private commands here * so they can be updated easily in the future (if needed) @@ -141,9 +111,7 @@ uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL; #define CMD_GETBAND "GETBAND" #define CMD_COUNTRY "COUNTRY" #define CMD_P2P_SET_NOA "P2P_SET_NOA" -#if !defined WL_ENABLE_P2P_IF #define CMD_P2P_GET_NOA "P2P_GET_NOA" -#endif /* WL_ENABLE_P2P_IF */ #define CMD_P2P_SD_OFFLOAD "P2P_SD_" #define CMD_P2P_LISTEN_OFFLOAD "P2P_LO_" #define CMD_P2P_SET_PS "P2P_SET_PS" @@ -158,7 +126,7 @@ uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL; #endif /* WL_NAN */ #define CMD_COUNTRY_DELIMITER "/" -#if defined (WL_SUPPORT_AUTO_CHANNEL) +#if defined(WL_SUPPORT_AUTO_CHANNEL) #define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS" #endif /* WL_SUPPORT_AUTO_CHANNEL */ @@ -170,42 +138,6 @@ uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL; #ifdef WL_SUPPORT_AUTO_CHANNEL #define CMD_SET_HAPD_AUTO_CHANNEL "HAPD_AUTO_CHANNEL" #endif /* WL_SUPPORT_AUTO_CHANNEL */ -#ifdef CUSTOMER_HW4_PRIVATE_CMD -#ifdef WL_WTC -#define CMD_WTC_CONFIG "SETWTCMODE" -#endif /* WL_WTC */ -#ifdef SUPPORT_HIDDEN_AP -/* Hostapd private command */ -#define CMD_SET_HAPD_MAX_NUM_STA "HAPD_MAX_NUM_STA" -#define CMD_SET_HAPD_SSID "HAPD_SSID" -#define CMD_SET_HAPD_HIDE_SSID "HAPD_HIDE_SSID" -#endif /* SUPPORT_HIDDEN_AP */ -#ifdef SUPPORT_SOFTAP_SINGL_DISASSOC -#define CMD_HAPD_STA_DISASSOC "HAPD_STA_DISASSOC" -#endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */ -#ifdef SUPPORT_SET_LPC -#define CMD_HAPD_LPC_ENABLED "HAPD_LPC_ENABLED" -#endif /* SUPPORT_SET_LPC */ -#ifdef SUPPORT_TRIGGER_HANG_EVENT -#define CMD_TEST_FORCE_HANG "TEST_FORCE_HANG" -#endif /* SUPPORT_TRIGGER_HANG_EVENT */ -#ifdef SUPPORT_LTECX -#define CMD_LTECX_SET "LTECOEX" -#endif /* SUPPORT_LTECX */ -#ifdef TEST_TX_POWER_CONTROL -#define CMD_TEST_SET_TX_POWER "TEST_SET_TX_POWER" -#define CMD_TEST_GET_TX_POWER "TEST_GET_TX_POWER" -#endif /* TEST_TX_POWER_CONTROL */ -#define CMD_SARLIMIT_TX_CONTROL "SET_TX_POWER_CALLING" -#ifdef SUPPORT_SET_TID -#define CMD_SET_TID "SET_TID" -#define CMD_GET_TID "GET_TID" -#endif /* SUPPORT_SET_TID */ -#define CMD_ROAM_VSIE_ENAB_SET "SET_ROAMING_REASON_ENABLED" -#define CMD_ROAM_VSIE_ENAB_GET "GET_ROAMING_REASON_ENABLED" -#define CMD_BR_VSIE_ENAB_SET "SET_BR_ERR_REASON_ENABLED" -#define CMD_BR_VSIE_ENAB_GET "GET_BR_ERR_REASON_ENABLED" -#endif /* CUSTOMER_HW4_PRIVATE_CMD */ #define CMD_KEEP_ALIVE "KEEPALIVE" #ifdef PNO_SUPPORT @@ -217,6 +149,8 @@ uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL; #endif /* PNO_SUPPORT */ #define CMD_HAPD_SET_AX_MODE "HAPD_SET_AX_MODE" +#define CMD_SET_HOTSPOT_ANTENNA_MODE "SET_HOTSPOT_ANTENNA_MODE" +#define CMD_GET_HOTSPOT_ANTENNA_MODE "GET_HOTSPOT_ANTENNA_MODE" #define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER" @@ -225,169 +159,16 @@ uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL; #define DISABLE_RANDOM_MAC "DISABLE_RANDOM_MAC" #endif /* SUPPORT_RANDOM_MAC_SCAN */ #define CMD_GET_FACTORY_MAC "FACTORY_MAC" -#ifdef CUSTOMER_HW4_PRIVATE_CMD - -#ifdef ROAM_API -#define CMD_ROAMTRIGGER_SET "SETROAMTRIGGER" -#define CMD_ROAMTRIGGER_GET "GETROAMTRIGGER" -#define CMD_ROAMDELTA_SET "SETROAMDELTA" -#define CMD_ROAMDELTA_GET "GETROAMDELTA" -#define CMD_ROAMSCANPERIOD_SET "SETROAMSCANPERIOD" -#define CMD_ROAMSCANPERIOD_GET "GETROAMSCANPERIOD" -#define CMD_FULLROAMSCANPERIOD_SET "SETFULLROAMSCANPERIOD" -#define CMD_FULLROAMSCANPERIOD_GET "GETFULLROAMSCANPERIOD" -#define CMD_COUNTRYREV_SET "SETCOUNTRYREV" -#define CMD_COUNTRYREV_GET "GETCOUNTRYREV" -#endif /* ROAM_API */ - -#if defined(SUPPORT_NAN_RANGING_TEST_BW) -#define CMD_NAN_RANGING_SET_BW "NAN_RANGING_SET_BW" -#endif /* SUPPORT_NAN_RANGING_TEST_BW */ - -#ifdef WES_SUPPORT -#define CMD_GETSCANCHANNELTIMELEGACY "GETSCANCHANNELTIME_LEGACY" -#define CMD_SETSCANCHANNELTIMELEGACY "SETSCANCHANNELTIME_LEGACY" -#define CMD_GETSCANUNASSOCTIMELEGACY "GETSCANUNASSOCTIME_LEGACY" -#define CMD_SETSCANUNASSOCTIMELEGACY "SETSCANUNASSOCTIME_LEGACY" -#define CMD_GETSCANPASSIVETIMELEGACY "GETSCANPASSIVETIME_LEGACY" -#define CMD_SETSCANPASSIVETIMELEGACY "SETSCANPASSIVETIME_LEGACY" -#define CMD_GETSCANHOMETIMELEGACY "GETSCANHOMETIME_LEGACY" -#define CMD_SETSCANHOMETIMELEGACY "SETSCANHOMETIME_LEGACY" -#define CMD_GETSCANHOMEAWAYTIMELEGACY "GETSCANHOMEAWAYTIME_LEGACY" -#define CMD_SETSCANHOMEAWAYTIMELEGACY "SETSCANHOMEAWAYTIME_LEGACY" -#define CMD_GETROAMSCANCHLEGACY "GETROAMSCANCHANNELS_LEGACY" -#define CMD_ADDROAMSCANCHLEGACY "ADDROAMSCANCHANNELS_LEGACY" -#define CMD_GETROAMSCANFQLEGACY "GETROAMSCANFREQUENCIES_LEGACY" -#define CMD_ADDROAMSCANFQLEGACY "ADDROAMSCANFREQUENCIES_LEGACY" -#define CMD_GETROAMTRIGLEGACY "GETROAMTRIGGER_LEGACY" -#define CMD_SETROAMTRIGLEGACY "SETROAMTRIGGER_LEGACY" -#define CMD_REASSOCLEGACY "REASSOC_LEGACY" - -#define CMD_GETROAMSCANCONTROL "GETROAMSCANCONTROL" -#define CMD_SETROAMSCANCONTROL "SETROAMSCANCONTROL" -#define CMD_GETROAMSCANCHANNELS "GETROAMSCANCHANNELS" -#define CMD_SETROAMSCANCHANNELS "SETROAMSCANCHANNELS" -#define CMD_ADDROAMSCANCHANNELS "ADDROAMSCANCHANNELS" -#define CMD_GETROAMSCANFREQS "GETROAMSCANFREQUENCIES" -#define CMD_SETROAMSCANFREQS "SETROAMSCANFREQUENCIES" -#define CMD_ADDROAMSCANFREQS "ADDROAMSCANFREQUENCIES" -#define CMD_GETSCANCHANNELTIME "GETSCANCHANNELTIME" -#define CMD_SETSCANCHANNELTIME "SETSCANCHANNELTIME" -#define CMD_GETSCANUNASSOCTIME "GETSCANUNASSOCTIME" -#define CMD_SETSCANUNASSOCTIME "SETSCANUNASSOCTIME" -#define CMD_GETSCANPASSIVETIME "GETSCANPASSIVETIME" -#define CMD_SETSCANPASSIVETIME "SETSCANPASSIVETIME" -#define CMD_GETSCANHOMETIME "GETSCANHOMETIME" -#define CMD_SETSCANHOMETIME "SETSCANHOMETIME" -#define CMD_GETSCANHOMEAWAYTIME "GETSCANHOMEAWAYTIME" -#define CMD_SETSCANHOMEAWAYTIME "SETSCANHOMEAWAYTIME" -#define CMD_GETSCANNPROBES "GETSCANNPROBES" -#define CMD_SETSCANNPROBES "SETSCANNPROBES" -#define CMD_GETDFSSCANMODE "GETDFSSCANMODE" -#define CMD_SETDFSSCANMODE "SETDFSSCANMODE" -#define CMD_SETJOINPREFER "SETJOINPREFER" - -#define CMD_SENDACTIONFRAME "SENDACTIONFRAME" -#define CMD_REASSOC "REASSOC" - -#define CMD_GETWESMODE "GETWESMODE" -#define CMD_SETWESMODE "SETWESMODE" -#define CMD_GETNCHOMODE "GETNCHOMODE" -#define CMD_SETNCHOMODE "SETNCHOMODE" - -/* Customer requested to Remove OKCMODE command */ -#define CMD_GETOKCMODE "GETOKCMODE" -#define CMD_SETOKCMODE "SETOKCMODE" - -#define CMD_OKC_SET_PMK "SET_PMK" -#define CMD_OKC_ENABLE "OKC_ENABLE" - -typedef struct android_wifi_reassoc_params { - unsigned char bssid[18]; - int channel; -} android_wifi_reassoc_params_t; - -#define ANDROID_WIFI_REASSOC_PARAMS_SIZE sizeof(struct android_wifi_reassoc_params) - -#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040 - -typedef struct android_wifi_af_params { - unsigned char bssid[18]; - int channel; - int dwell_time; - int len; - unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE]; -} android_wifi_af_params_t; - -#define ANDROID_WIFI_AF_PARAMS_SIZE sizeof(struct android_wifi_af_params) -#endif /* WES_SUPPORT */ -#ifdef SUPPORT_AMPDU_MPDU_CMD -#define CMD_AMPDU_MPDU "AMPDU_MPDU" -#endif /* SUPPORT_AMPDU_MPDU_CMD */ - -#define CMD_CHANGE_RL "CHANGE_RL" -#define CMD_RESTORE_RL "RESTORE_RL" - -#define CMD_SET_RMC_ENABLE "SETRMCENABLE" -#define CMD_SET_RMC_TXRATE "SETRMCTXRATE" -#define CMD_SET_RMC_ACTPERIOD "SETRMCACTIONPERIOD" -#define CMD_SET_RMC_IDLEPERIOD "SETRMCIDLEPERIOD" -#define CMD_SET_RMC_LEADER "SETRMCLEADER" -#define CMD_SET_RMC_EVENT "SETRMCEVENT" - -#define CMD_SET_SCSCAN "SETSINGLEANT" -#define CMD_GET_SCSCAN "GETSINGLEANT" -#ifdef WLTDLS -#define CMD_TDLS_RESET "TDLS_RESET" -#endif /* WLTDLS */ - -#ifdef CONFIG_SILENT_ROAM -#define CMD_SROAM_TURN_ON "SROAMTURNON" -#define CMD_SROAM_SET_INFO "SROAMSETINFO" -#define CMD_SROAM_GET_INFO "SROAMGETINFO" -#endif /* CONFIG_SILENT_ROAM */ - -#ifdef CONFIG_ROAM_RSSI_LIMIT -#define CMD_ROAM_RSSI_LMT "ROAMRSSILIMIT" -#endif /* CONFIG_ROAM_RSSI_LIMIT */ -#ifdef CONFIG_ROAM_MIN_DELTA -#define CMD_ROAM_MIN_DELTA "ROAMMINSCOREDELTA" -#endif /* CONFIG_ROAM_MIN_DELTA */ - -#define CMD_SET_DISCONNECT_IES "SET_DISCONNECT_IES" - -#ifdef FCC_PWR_LIMIT_2G -#define CMD_GET_FCC_PWR_LIMIT_2G "GET_FCC_CHANNEL" -#define CMD_SET_FCC_PWR_LIMIT_2G "SET_FCC_CHANNEL" -/* CUSTOMER_HW4's value differs from BRCM FW value for enable/disable */ -#define CUSTOMER_HW4_ENABLE 0 -#define CUSTOMER_HW4_DISABLE -1 -#endif /* FCC_PWR_LIMIT_2G */ -#define CUSTOMER_HW4_EN_CONVERT(i) (i += 1) -#endif /* CUSTOMER_HW4_PRIVATE_CMD */ #ifdef WLFBT #define CMD_GET_FTKEY "GET_FTKEY" #endif -#ifdef WLAIBSS -#define CMD_SETIBSSTXFAILEVENT "SETIBSSTXFAILEVENT" -#define CMD_GET_IBSS_PEER_INFO "GETIBSSPEERINFO" -#define CMD_GET_IBSS_PEER_INFO_ALL "GETIBSSPEERINFOALL" -#define CMD_SETIBSSROUTETABLE "SETIBSSROUTETABLE" -#define CMD_SETIBSSAMPDU "SETIBSSAMPDU" -#define CMD_SETIBSSANTENNAMODE "SETIBSSANTENNAMODE" -#endif /* WLAIBSS */ - #define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD" #define CMD_INTERFACE_CREATE "INTERFACE_CREATE" #define CMD_INTERFACE_DELETE "INTERFACE_DELETE" #define CMD_GET_LINK_STATUS "GETLINKSTATUS" -#if defined(DHD_ENABLE_BIGDATA_LOGGING) -#define CMD_GET_BSS_INFO "GETBSSINFO" -#define CMD_GET_ASSOC_REJECT_INFO "GETASSOCREJECTINFO" -#endif /* DHD_ENABLE_BIGDATA_LOGGING */ #define CMD_GET_STA_INFO "GETSTAINFO" /* related with CMD_GET_LINK_STATUS */ @@ -452,9 +233,6 @@ typedef struct android_wifi_af_params { #define BUFSZ 8 #define BUFSZN BUFSZ + 1 -#define _S(x) #x -#define S(x) _S(x) - #define MAXBANDS 2 /**< Maximum #of bands */ #define BAND_2G_INDEX 1 #define BAND_5G_INDEX 0 @@ -471,10 +249,6 @@ typedef union { #define CMD_DEL_WFDS_HASH "DEL_WFDS_HASH" #endif /* WLWFDS */ -#ifdef BT_WIFI_HANDOVER -#define CMD_TBOW_TEARDOWN "TBOW_TEARDOWN" -#endif /* BT_WIFI_HANDOVER */ - #define CMD_MURX_BFE_CAP "MURX_BFE_CAP" #ifdef SUPPORT_RSSI_SUM_REPORT @@ -536,9 +310,7 @@ struct connection_stats { #endif static LIST_HEAD(miracast_resume_list); -#ifdef WL_CFG80211 static u8 miracast_cur_mode; -#endif /* WL_CFG80211 */ #ifdef DHD_LOG_DUMP #define CMD_NEW_DEBUG_PRINT_DUMP "DEBUG_DUMP" @@ -560,7 +332,7 @@ extern bool dhd_debug_uart_is_running(struct net_device *dev); #endif /* DHD_DEBUG_UART */ #ifdef RTT_GEOFENCE_INTERVAL -#if defined (RTT_SUPPORT) && defined(WL_NAN) +#if defined(RTT_SUPPORT) && defined(WL_NAN) #define CMD_GEOFENCE_INTERVAL "GEOFENCE_INT" #endif /* RTT_SUPPORT && WL_NAN */ #endif /* RTT_GEOFENCE_INTERVAL */ @@ -580,12 +352,6 @@ struct io_cfg { #define MAX_NUM_SUITES 10 #define WIDTH_AKM_SUITE 8 #define JOIN_PREF_RSSI_LEN 0x02 -#define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */ -#define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */ -#define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */ -#define JOIN_PREF_MAX_WPA_TUPLES 16 -#define MAX_BUF_SIZE (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \ - (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES)) #endif /* BCMFW_ROAM_ENABLE */ #if defined(CONFIG_TIZEN) @@ -598,92 +364,11 @@ struct io_cfg { #endif /* CONFIG_TIZEN */ #define CMD_DEBUG_VERBOSE "DEBUG_VERBOSE" -#ifdef WL_NATOE - -#define CMD_NATOE "NATOE" - -#define NATOE_MAX_PORT_NUM 65535 - -/* natoe command info structure */ -typedef struct wl_natoe_cmd_info { - uint8 *command; /* pointer to the actual command */ - uint16 tot_len; /* total length of the command */ - uint16 bytes_written; /* Bytes written for get response */ -} wl_natoe_cmd_info_t; - -typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t; -typedef int (natoe_cmd_handler_t)(struct net_device *dev, - const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info); - -struct wl_natoe_sub_cmd { - char *name; - uint8 version; /* cmd version */ - uint16 id; /* id for the dongle f/w switch/case */ - uint16 type; /* base type of argument */ - natoe_cmd_handler_t *handler; /* cmd handler */ -}; - -#define WL_ANDROID_NATOE_FUNC(suffix) wl_android_natoe_subcmd_ ##suffix -static int wl_android_process_natoe_cmd(struct net_device *dev, - char *command, int total_len); -static int wl_android_natoe_subcmd_enable(struct net_device *dev, - const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info); -static int wl_android_natoe_subcmd_config_ips(struct net_device *dev, - const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info); -static int wl_android_natoe_subcmd_config_ports(struct net_device *dev, - const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info); -static int wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, - const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info); -static int wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, - const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info); - -static const wl_natoe_sub_cmd_t natoe_cmd_list[] = { - /* wl natoe enable [0/1] or new: "wl natoe [0/1]" */ - {"enable", 0x01, WL_NATOE_CMD_ENABLE, - IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(enable) - }, - {"config_ips", 0x01, WL_NATOE_CMD_CONFIG_IPS, - IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ips) - }, - {"config_ports", 0x01, WL_NATOE_CMD_CONFIG_PORTS, - IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ports) - }, - {"stats", 0x01, WL_NATOE_CMD_DBG_STATS, - IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(dbg_stats) - }, - {"tbl_cnt", 0x01, WL_NATOE_CMD_TBL_CNT, - IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(tbl_cnt) - }, - {NULL, 0, 0, 0, NULL} -}; - -#endif /* WL_NATOE */ #ifdef SET_PCIE_IRQ_CPU_CORE #define CMD_PCIE_IRQ_CORE "PCIE_IRQ_CORE" #endif /* SET_PCIE_IRQ_CPU_CORE */ -#ifdef WLADPS_PRIVATE_CMD -#define CMD_SET_ADPS "SET_ADPS" -#define CMD_GET_ADPS "GET_ADPS" -#ifdef WLADPS_ENERGY_GAIN -#define CMD_GET_GAIN_ADPS "GET_GAIN_ADPS" -#define CMD_RESET_GAIN_ADPS "RESET_GAIN_ADPS" -#ifndef ADPS_GAIN_2G_PM0_IDLE -#define ADPS_GAIN_2G_PM0_IDLE 0 -#endif -#ifndef ADPS_GAIN_5G_PM0_IDLE -#define ADPS_GAIN_5G_PM0_IDLE 0 -#endif -#ifndef ADPS_GAIN_2G_TX_PSPOLL -#define ADPS_GAIN_2G_TX_PSPOLL 0 -#endif -#ifndef ADPS_GAIN_5G_TX_PSPOLL -#define ADPS_GAIN_5G_TX_PSPOLL 0 -#endif -#endif /* WLADPS_ENERGY_GAIN */ -#endif /* WLADPS_PRIVATE_CMD */ - #ifdef DHD_PKT_LOGGING #define CMD_PKTLOG_FILTER_ENABLE "PKTLOG_FILTER_ENABLE" #define CMD_PKTLOG_FILTER_DISABLE "PKTLOG_FILTER_DISABLE" @@ -701,6 +386,11 @@ static const wl_natoe_sub_cmd_t natoe_cmd_list[] = { #define CMD_PKTLOG_DEBUG_DUMP "PKTLOG_DEBUG_DUMP" #endif /* DHD_PKT_LOGGING */ +#ifdef TPUT_DEBUG_DUMP +#define CMD_TPUT_DEBUG_MODE_ENABLE "TPUT_DEBUG_MODE_ENABLE" +#define CMD_TPUT_DEBUG_MODE_DISABLE "TPUT_DEBUG_MODE_DISABLE" +#endif /* TPUT_DEBUG_DUMP */ + #ifdef DHD_EVENT_LOG_FILTER #define CMD_EWP_FILTER "EWP_FILTER" #endif /* DHD_EVENT_LOG_FILTER */ @@ -728,10 +418,15 @@ static const wl_natoe_sub_cmd_t natoe_cmd_list[] = { #define CMD_TWT_SETUP "TWT_SETUP" #define CMD_TWT_TEARDOWN "TWT_TEARDOWN" #define CMD_TWT_INFO "TWT_INFO_FRM" -#define CMD_TWT_STATUS_QUERY "TWT_STATUS" -#define CMD_TWT_CAPABILITY "TWT_CAP" +#define CMD_TWT_STATUS_QUERY "GET_TWT_STATUS" +#define CMD_TWT_CAPABILITY "GET_TWT_CAP" +#define CMD_TWT_GET_STATS "GET_TWT_STATISTICS" +#define CMD_TWT_CLR_STATS "CLEAR_TWT_STATISTICS" +#define CMD_TWT_SOFTAP_ENABLE "TWT_SOFTAP_ENABLE" #endif /* WL_TWT */ +#define CMD_GET_6G_SOFTAP_FREQ_LIST "GET_6G_SOFTAP_FREQ_LIST" + /* drv command info structure */ typedef struct wl_drv_cmd_info { uint8 *command; /* pointer to the actual command */ @@ -796,7 +491,9 @@ static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = { #define WL_GENL_VER 1 /* family definition */ static struct genl_family wl_genl_family = { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */ +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */ .hdrsize = 0, .name = "bcm-genl", /* Netlink I/F for Android */ .version = WL_GENL_VER, /* Version Number */ @@ -825,16 +522,16 @@ struct genl_ops wl_genl_ops = { }; #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) -static struct genl_multicast_group wl_genl_mcast[] = { - { .name = "bcm-genl-mcast", }, -}; -#else +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) static struct genl_multicast_group wl_genl_mcast = { .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */ .name = "bcm-genl-mcast", }; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */ +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) +static struct genl_multicast_group wl_genl_mcast[] = { + { .name = "bcm-genl-mcast", }, +}; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */ #endif /* WL_GENL */ #ifdef SUPPORT_LQCM @@ -851,10 +548,6 @@ static struct genl_multicast_group wl_genl_mcast = { static int priv_cmd_errors = 0; #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */ -#ifdef WL_P2P_6G -#define CMD_ENABLE_6G_P2P "ENABLE_6G_P2P" -#endif /* WL_P2P_6G */ - /** * Extern function declarations (TODO: move them to dhd_linux.h) */ @@ -882,10 +575,7 @@ int wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len) { return 0; } int wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len) { return 0; } -#endif /* WL_CFG80211 */ -#if defined(WL_WTC) && defined(CUSTOMER_HW4_PRIVATE_CMD) -static int wl_android_wtc_config(struct net_device *dev, char *command, int total_len); -#endif /* WL_WTC && CUSTOMER_HW4_PRIVATE_CMD */ +#endif /* WK_CFG80211 */ #ifdef WBTEXT static int wl_android_wbtext(struct net_device *dev, char *command, int total_len); static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev, @@ -896,9 +586,11 @@ static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev, char *command, int total_len); static int wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp, uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size); -static int wl_android_wbtext_enable(struct net_device *dev, int mode); #endif /* WBTEXT */ #ifdef WES_SUPPORT +#ifdef WBTEXT +static int wl_android_wbtext_enable(struct net_device *dev, int mode); +#endif /* WBTEXT */ /* wl_roam.c */ extern int get_roamscan_mode(struct net_device *dev, int *mode); extern int set_roamscan_mode(struct net_device *dev, int mode); @@ -911,7 +603,7 @@ static char* legacy_cmdlist[] = CMD_GETROAMSCANCHLEGACY, CMD_ADDROAMSCANCHLEGACY, CMD_GETROAMSCANFQLEGACY, CMD_ADDROAMSCANFQLEGACY, CMD_GETROAMTRIGLEGACY, CMD_SETROAMTRIGLEGACY, - CMD_REASSOCLEGACY, + CMD_REASSOCLEGACY, CMD_REASSOCFREQLEGACY, CMD_GETSCANCHANNELTIMELEGACY, CMD_SETSCANCHANNELTIMELEGACY, CMD_GETSCANUNASSOCTIMELEGACY, CMD_SETSCANUNASSOCTIMELEGACY, CMD_GETSCANPASSIVETIMELEGACY, CMD_SETSCANPASSIVETIMELEGACY, @@ -931,16 +623,17 @@ static char* ncho_cmdlist[] = CMD_GETROAMSCANCHANNELS, CMD_SETROAMSCANCHANNELS, CMD_ADDROAMSCANCHANNELS, CMD_GETROAMSCANFREQS, CMD_SETROAMSCANFREQS, CMD_ADDROAMSCANFREQS, CMD_SENDACTIONFRAME, - CMD_REASSOC, + CMD_REASSOC, CMD_REASSOCFREQ, CMD_GETSCANCHANNELTIME, CMD_SETSCANCHANNELTIME, CMD_GETSCANUNASSOCTIME, CMD_SETSCANUNASSOCTIME, CMD_GETSCANPASSIVETIME, CMD_SETSCANPASSIVETIME, CMD_GETSCANHOMETIME, CMD_SETSCANHOMETIME, CMD_GETSCANHOMEAWAYTIME, CMD_SETSCANHOMEAWAYTIME, CMD_GETSCANNPROBES, CMD_SETSCANNPROBES, - CMD_GETDFSSCANMODE, CMD_SETDFSSCANMODE, + CMD_GETDFSSCANMODE, CMD_SETJOINPREFER, CMD_GETWESMODE, CMD_SETWESMODE, + CMD_GETROAMALLOWBAND, CMD_SETROAMALLOWBAND, "\0" }; #endif /* WES_SUPPORT */ @@ -952,7 +645,6 @@ int wl_android_priority_roam_enable(struct net_device *dev, int mode); #ifdef CONFIG_SILENT_ROAM int wl_android_sroam_turn_on(struct net_device *dev, int mode); #endif /* CONFIG_SILENT_ROAM */ -int wl_android_rcroam_turn_on(struct net_device *dev, int mode); #ifdef ENABLE_4335BT_WAR extern int bcm_bt_lock(int cookie); @@ -990,7 +682,7 @@ typedef struct android_restore_scan_params { } android_restore_scan_params_t; /* function prototypes of private command handler */ -static int wl_android_default_set_scan_params(struct net_device *dev, char *command, int total_len); +int wl_android_default_set_scan_params(struct net_device *dev, char *command, int total_len); static int wl_android_set_roam_trigger(struct net_device *dev, char* command); int wl_android_set_roam_delta(struct net_device *dev, char* command); int wl_android_set_roam_scan_period(struct net_device *dev, char* command); @@ -1001,9 +693,10 @@ int wl_android_set_scan_home_time(struct net_device *dev, char *command); int wl_android_set_scan_home_away_time(struct net_device *dev, char *command); int wl_android_set_scan_nprobes(struct net_device *dev, char *command); static int wl_android_set_band(struct net_device *dev, char *command); -int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command); int wl_android_set_wes_mode(struct net_device *dev, char *command); int wl_android_set_okc_mode(struct net_device *dev, char *command); +int wl_android_set_scan_passive_time(struct net_device *dev, char *command); +int wl_android_set_roam_allowed_band(struct net_device *dev, char *command); /* default values */ #ifdef ROAM_API @@ -1020,11 +713,10 @@ int wl_android_set_okc_mode(struct net_device *dev, char *command); #else #define DEFAULT_SCANHOMETIME 45 #endif /* BCM4361_CHIP */ -#define DEFAULT_SCANHOMEAWAYTIME 100 -#define DEFAULT_SCANPROBES 2 -#define DEFAULT_DFSSCANMODE 1 -#define DEFAULT_WESMODE 0 -#define DEFAULT_OKCMODE 1 +#define DEFAULT_SCANPROBES 2 +#define DEFAULT_DFSSCANMODE 1 +#define DEFAULT_WESMODE 0 +#define DEFAULT_OKCMODE 1 #endif /* WES_SUPPORT */ #define DEFAULT_BAND 0 #ifdef WBTEXT @@ -1056,14 +748,16 @@ static android_restore_scan_params_t restore_params[] = RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_channel_time}, { CMD_SETSCANHOMETIME, DEFAULT_SCANHOMETIME, RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_time}, - { CMD_GETSCANHOMEAWAYTIME, DEFAULT_SCANHOMEAWAYTIME, + { CMD_GETSCANHOMEAWAYTIME, DHD_SCAN_HOME_AWAY_TIME, RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_away_time}, { CMD_SETSCANNPROBES, DEFAULT_SCANPROBES, RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_nprobes}, - { CMD_SETDFSSCANMODE, DEFAULT_DFSSCANMODE, - RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_dfs_channel_mode}, { CMD_SETWESMODE, DEFAULT_WESMODE, RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_wes_mode}, + { CMD_SETSCANPASSIVETIME, DHD_SCAN_PASSIVE_TIME, + RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_passive_time}, + { CMD_SETROAMALLOWBAND, WLC_ROAM_ALLOW_BAND_AUTO, + RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_allowed_band}, #endif /* WES_SUPPORT */ { CMD_SETBAND, DEFAULT_BAND, RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_band}, @@ -1078,8 +772,14 @@ static android_restore_scan_params_t restore_params[] = #ifdef SUPPORT_LATENCY_CRITICAL_DATA #define CMD_GET_LATENCY_CRITICAL_DATA "GET_LATENCY_CRT_DATA" #define CMD_SET_LATENCY_CRITICAL_DATA "SET_LATENCY_CRT_DATA" +int wl_android_set_latency_crt_data(struct net_device *dev, int mode); #endif /* SUPPORT_LATENCY_CRITICAL_DATA */ +#ifdef WL_LATENCY_CONFIG +#define CMD_SET_LOW_LATENCY "LOW_LATENCY" +#define DEF_LOW_LATENCY_PERIOD 30u +#endif /* WL_LATENCY_CONFIG */ + typedef struct android_priv_cmd_log_cfg_table { char command[64]; int enable; @@ -1096,6 +796,33 @@ static android_priv_cmd_log_cfg_table_t loging_params[] = { {"\0", FALSE} }; +#ifdef WL_UWB_COEX +#define CMD_SET_UWB_COEX_ENABLE "SET_UWBCX_ENABLE" +#define CMD_GET_UWB_COEX_ENABLE "GET_UWBCX_ENABLE" + +#define CMD_SET_UWB_COEX_PREPARE_TIME "SET_UWBCX_PREPARE_TIME" +#define CMD_GET_UWB_COEX_PREPARE_TIME "GET_UWBCX_PREPARE_TIME" + +static int wl_android_uwbcx_set_enable(struct net_device *dev, const char *command); +static int wl_android_uwbcx_get_enable(struct net_device *dev, char *command, int tot_len); + +static int wl_android_uwbcx_set_prepare_time(struct net_device *dev, const char *command); +static int wl_android_uwbcx_get_prepare_time(struct net_device *dev, char *command, int tot_len); +#endif /* WL_UWB_COEX */ + +#ifdef WL_DUAL_STA +#define CMD_SET_PRIMARY_INET "SET_PRIMARY_INET" +#endif /* WL_DUAL_STA */ + +#define CMD_SETWSECINFO "SETWSECINFO" + +#if defined(LIMIT_AP_BW) +#define CMD_SET_SOFTAP_BW "CMD_SET_SOFTAP_BW" +#define CMD_GET_SOFTAP_BW "CMD_GET_SOFTAP_BW" +static int wl_android_set_softap_bw(struct net_device *ndev, char *command); +static int wl_android_get_softap_bw(struct net_device *ndev, char *command, int total_len); +#endif /* LIMIT_AP_BW */ + /** * Local (static) functions and variables */ @@ -1122,7 +849,7 @@ static char* wl_android_get_band_str(u16 band) case WLC_BAND_2G: return "2G"; default: - ANDROID_ERROR(("Unkown band: %d \n", band)); + WL_ERR(("Unkown band: %d \n", band)); return "Unknown band"; } } @@ -1161,7 +888,7 @@ static int wl_android_set_wfds_hash( smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN); if (smbuf == NULL) { - ANDROID_ERROR(("wl_android_set_wfds_hash: failed to allocated memory %d bytes\n", + DHD_ERROR(("wl_android_set_wfds_hash: failed to allocated memory %d bytes\n", WLC_IOCTL_MAXLEN)); return -ENOMEM; } @@ -1178,7 +905,7 @@ static int wl_android_set_wfds_hash( } if (error) { - ANDROID_ERROR(("wl_android_set_wfds_hash: failed to %s, error=%d\n", command, error)); + DHD_ERROR(("wl_android_set_wfds_hash: failed to %s, error=%d\n", command, error)); } if (smbuf) { @@ -1196,14 +923,14 @@ static int wl_android_get_link_speed(struct net_device *net, char *command, int error = wldev_get_link_speed(net, &link_speed); if (error) { - ANDROID_ERROR(("Get linkspeed failed \n")); + DHD_ERROR(("Get linkspeed failed \n")); return -1; } /* Convert Kbps to Android Mbps */ link_speed = link_speed / 1000; bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed); - ANDROID_INFO(("wl_android_get_link_speed: command result is %s\n", command)); + DHD_INFO(("wl_android_get_link_speed: command result is %s\n", command)); return bytes_written; } @@ -1230,15 +957,15 @@ static int wl_android_get_rssi(struct net_device *net, char *command, int total_ /* Ap/GO mode * driver rssi */ - ANDROID_TRACE(("wl_android_get_rssi: cmd:%s\n", delim)); + DHD_TRACE(("wl_android_get_rssi: cmd:%s\n", delim)); /* skip space from delim after finding char */ delim++; if (!(bcm_ether_atoe((delim), &scbval.ea))) { - ANDROID_ERROR(("wl_android_get_rssi: address err\n")); + DHD_ERROR(("wl_android_get_rssi: address err\n")); return -1; } scbval.val = htod32(0); - ANDROID_TRACE(("wl_android_get_rssi: address:"MACDBG, MAC2STRDBG(scbval.ea.octet))); + DHD_TRACE(("wl_android_get_rssi: address:"MACDBG, MAC2STRDBG(scbval.ea.octet))); #ifdef WL_VIRTUAL_APSTA /* RSDB AP may have another virtual interface * In this case, format of private command is as following, @@ -1268,15 +995,12 @@ static int wl_android_get_rssi(struct net_device *net, char *command, int total_ error = wldev_get_rssi(target_ndev, &scbval); if (error) return -1; -#if defined(RSSIOFFSET) - scbval.val = wl_update_rssi_offset(net, scbval.val); -#endif error = wldev_get_ssid(target_ndev, &ssid); if (error) return -1; if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) { - ANDROID_ERROR(("wl_android_get_rssi: wldev_get_ssid failed\n")); + DHD_ERROR(("wl_android_get_rssi: wldev_get_ssid failed\n")); } else if (total_len <= ssid.SSID_len) { return -ENOMEM; } else { @@ -1290,7 +1014,7 @@ static int wl_android_get_rssi(struct net_device *net, char *command, int total_ " rssi %d", scbval.val); command[bytes_written] = '\0'; - ANDROID_TRACE(("wl_android_get_rssi: command result is %s (%d)\n", command, bytes_written)); + DHD_TRACE(("wl_android_get_rssi: command result is %s (%d)\n", command, bytes_written)); return bytes_written; } @@ -1309,10 +1033,10 @@ static int wl_android_set_suspendopt(struct net_device *dev, char *command) if (ret_now != suspend_flag) { if (!(ret = net_os_set_suspend(dev, ret_now, 1))) { - ANDROID_INFO(("wl_android_set_suspendopt: Suspend Flag %d -> %d\n", + DHD_INFO(("wl_android_set_suspendopt: Suspend Flag %d -> %d\n", ret_now, suspend_flag)); } else { - ANDROID_ERROR(("wl_android_set_suspendopt: failed %d\n", ret)); + DHD_ERROR(("wl_android_set_suspendopt: failed %d\n", ret)); } } @@ -1323,23 +1047,30 @@ static int wl_android_set_suspendmode(struct net_device *dev, char *command) { int ret = 0; -#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND) +#if (!defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)) || \ + defined(DHD_USE_PM_SLEEP) int suspend_flag; suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0'; - if (suspend_flag != 0) + if (suspend_flag != 0) { suspend_flag = 1; +#if defined(DHD_USE_PM_SLEEP) + /* The suspend setting is handled in linux pm_nofi callback. */ + DHD_INFO(("wl_android_set_suspendmode: Suspend Mode %d doesn't set\n", + suspend_flag)); + return ret; +#endif /* DHD_USE_PM_SLEEP */ + } if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) - ANDROID_INFO(("wl_android_set_suspendmode: Suspend Mode %d\n", suspend_flag)); + DHD_INFO(("wl_android_set_suspendmode: Suspend Mode %d\n", suspend_flag)); else - ANDROID_ERROR(("wl_android_set_suspendmode: failed %d\n", ret)); -#endif + DHD_ERROR(("wl_android_set_suspendmode: failed %d\n", ret)); +#endif /* (!CONFIG_HAS_EARLYSUSPEND || !DHD_USE_EARLYSUSPEND) || DHD_USE_PM_SLEEP */ return ret; } -#ifdef WL_CFG80211 int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len) { uint8 mode[5]; @@ -1350,9 +1081,9 @@ int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_l if (error) return -1; - ANDROID_INFO(("wl_android_get_80211_mode: mode:%s\n", mode)); + DHD_INFO(("wl_android_get_80211_mode: mode:%s\n", mode)); bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode); - ANDROID_INFO(("wl_android_get_80211_mode: command:%s EXIT\n", command)); + DHD_INFO(("wl_android_get_80211_mode: command:%s EXIT\n", command)); return bytes_written; } @@ -1378,13 +1109,14 @@ int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len return -1; chanspec = wl_chspec_driver_to_host(chsp); - ANDROID_INFO(("wl_android_get_80211_mode: return value of chanspec:%x\n", chanspec)); + DHD_INFO(("wl_android_get_80211_mode: return value of chanspec:%x\n", chanspec)); channel = chanspec & WL_CHANSPEC_CHAN_MASK; band = chanspec & WL_CHANSPEC_BAND_MASK; bw = chanspec & WL_CHANSPEC_BW_MASK; + UNUSED_PARAMETER(band); - ANDROID_INFO(("wl_android_get_80211_mode: channel:%d band:%d bandwidth:%d\n", + DHD_INFO(("wl_android_get_80211_mode: channel:%d band:%d bandwidth:%d\n", channel, band, bw)); if (bw == WL_CHANSPEC_BW_160) { @@ -1424,11 +1156,10 @@ int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d", CMD_CHANSPEC, channel, wl_android_get_band_str(CHSPEC2WLC_BAND(chanspec)), bw); - ANDROID_INFO(("wl_android_get_chanspec: command:%s EXIT\n", command)); + DHD_INFO(("wl_android_get_chanspec: command:%s EXIT\n", command)); return bytes_written; } -#endif /* WL_CFG80211 */ /* returns current datarate datarate returned from firmware are in 500kbps */ int wl_android_get_datarate(struct net_device *dev, char *command, int total_len) @@ -1441,11 +1172,12 @@ int wl_android_get_datarate(struct net_device *dev, char *command, int total_len if (error) return -1; - ANDROID_INFO(("wl_android_get_datarate: datarate:%d\n", datarate)); + DHD_INFO(("wl_android_get_datarate: datarate:%d\n", datarate)); bytes_written = snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate/2)); return bytes_written; } + int wl_android_get_assoclist(struct net_device *dev, char *command, int total_len) { int error = 0; @@ -1456,7 +1188,7 @@ int wl_android_get_assoclist(struct net_device *dev, char *command, int total_le sizeof(struct ether_addr) + sizeof(uint)] = {0}; struct maclist *assoc_maclist = (struct maclist *)mac_buf; - ANDROID_TRACE(("wl_android_get_assoclist: ENTER\n")); + DHD_TRACE(("wl_android_get_assoclist: ENTER\n")); assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST); @@ -1477,7 +1209,7 @@ int wl_android_get_assoclist(struct net_device *dev, char *command, int total_le if ((len > 0) && (len < (total_len - bytes_written))) { bytes_written += len; } else { - ANDROID_ERROR(("wl_android_get_assoclist: Insufficient buffer %d," + DHD_ERROR(("wl_android_get_assoclist: Insufficient buffer %d," " bytes_written %d\n", total_len, bytes_written)); bytes_written = -1; @@ -1487,34 +1219,33 @@ int wl_android_get_assoclist(struct net_device *dev, char *command, int total_le return bytes_written; } -#ifdef WL_CFG80211 extern chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec); static int wl_android_set_csa(struct net_device *dev, char *command) { int error = 0; char smbuf[WLC_IOCTL_SMLEN]; - wl_chan_switch_t csa_arg; + wl_chan_switch_t csa_arg = {0, }; u32 chnsp = 0; int err = 0; - ANDROID_INFO(("wl_android_set_csa: command:%s\n", command)); + DHD_INFO(("wl_android_set_csa: command:%s\n", command)); command = (command + strlen(CMD_SET_CSA)); /* Order is mode, count channel */ if (!*++command) { - ANDROID_ERROR(("wl_android_set_csa:error missing arguments\n")); + DHD_ERROR(("wl_android_set_csa:error missing arguments\n")); return -1; } csa_arg.mode = bcm_atoi(command); if (csa_arg.mode != 0 && csa_arg.mode != 1) { - ANDROID_ERROR(("Invalid mode\n")); + DHD_ERROR(("Invalid mode\n")); return -1; } if (!*++command) { - ANDROID_ERROR(("wl_android_set_csa: error missing count\n")); + DHD_ERROR(("wl_android_set_csa: error missing count\n")); return -1; } command++; @@ -1524,13 +1255,13 @@ static int wl_android_set_csa(struct net_device *dev, char *command) csa_arg.chspec = 0; command += 2; if (!*command) { - ANDROID_ERROR(("wl_android_set_csa: error missing channel\n")); + DHD_ERROR(("wl_android_set_csa: error missing channel\n")); return -1; } chnsp = wf_chspec_aton(command); if (chnsp == 0) { - ANDROID_ERROR(("wl_android_set_csa:chsp is not correct\n")); + DHD_ERROR(("wl_android_set_csa:chsp is not correct\n")); return -1; } chnsp = wl_chspec_host_to_driver(chnsp); @@ -1541,49 +1272,49 @@ static int wl_android_set_csa(struct net_device *dev, char *command) err = wldev_iovar_getint(dev, "per_chan_info", &chanspec); if (!err) { if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) { - ANDROID_ERROR(("Channel is radar sensitive\n")); + DHD_ERROR(("Channel is radar sensitive\n")); return -1; } if (chanspec == 0) { - ANDROID_ERROR(("Invalid hw channel\n")); + DHD_ERROR(("Invalid hw channel\n")); return -1; } } else { - ANDROID_ERROR(("does not support per_chan_info\n")); + DHD_ERROR(("does not support per_chan_info\n")); return -1; } - ANDROID_INFO(("non radar sensitivity\n")); + DHD_INFO(("non radar sensitivity\n")); } error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg), smbuf, sizeof(smbuf), NULL); if (error) { - ANDROID_ERROR(("wl_android_set_csa:set csa failed:%d\n", error)); + DHD_ERROR(("wl_android_set_csa:set csa failed:%d\n", error)); return -1; } return 0; } -#endif /* WL_CFG80211 */ static int wl_android_set_bcn_li_dtim(struct net_device *dev, char *command) { int ret = 0; int dtim; + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); dtim = *(command + strlen(CMD_SETDTIM_IN_SUSPEND) + 1) - '0'; if (dtim > (MAX_DTIM_ALLOWED_INTERVAL / MAX_DTIM_SKIP_BEACON_INTERVAL)) { - ANDROID_ERROR(("%s: failed, invalid dtim %d\n", + DHD_ERROR(("%s: failed, invalid dtim %d\n", __FUNCTION__, dtim)); return BCME_ERROR; } - if (!(ret = net_os_set_suspend_bcn_li_dtim(dev, dtim))) { - ANDROID_TRACE(("%s: SET bcn_li_dtim in suspend %d\n", - __FUNCTION__, dtim)); - } else { - ANDROID_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); + cfg->suspend_bcn_li_dtim = dtim; +#ifdef OEM_ANDROID + if (cfg->soft_suspend) { + wl_cfg80211_set_suspend_bcn_li_dtim(cfg, dev, TRUE); } +#endif /* OEM_ANDROID */ return ret; } @@ -1593,15 +1324,19 @@ wl_android_set_max_dtim(struct net_device *dev, char *command) { int ret = 0; int dtim_flag; + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); dtim_flag = *(command + strlen(CMD_MAXDTIM_IN_SUSPEND) + 1) - '0'; - - if (!(ret = net_os_set_max_dtim_enable(dev, dtim_flag))) { - ANDROID_TRACE(("wl_android_set_max_dtim: use Max bcn_li_dtim in suspend %s\n", + WL_INFORM(("use MAX bcn_li_dtim in suspend %s\n", (dtim_flag ? "Enable" : "Disable"))); - } else { - ANDROID_ERROR(("wl_android_set_max_dtim: failed %d\n", ret)); + + cfg->max_dtim_enable = dtim_flag ? TRUE : FALSE; + +#ifdef OEM_ANDROID + if (cfg->soft_suspend) { + wl_cfg80211_set_suspend_bcn_li_dtim(cfg, dev, TRUE); } +#endif /* OEM_ANDROID */ return ret; } @@ -1612,56 +1347,133 @@ wl_android_set_disable_dtim_in_suspend(struct net_device *dev, char *command) { int ret = 0; int dtim_flag; + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); dtim_flag = *(command + strlen(CMD_DISDTIM_IN_SUSPEND) + 1) - '0'; - if (!(ret = net_os_set_disable_dtim_in_suspend(dev, dtim_flag))) { - ANDROID_TRACE(("wl_android_set_disable_dtim_in_suspend: " + cfg->disable_dtim_in_suspend = dtim_flag ? TRUE : FALSE; +#ifdef OEM_ANDROID + if (cfg->soft_suspend) { + wl_cfg80211_set_suspend_bcn_li_dtim(cfg, dev, TRUE); + } +#endif /* OEM_ANDROID */ + + WL_INFORM_MEM(("wl_android_set_disable_dtim_in_suspend: " "use Disable bcn_li_dtim in suspend %s\n", (dtim_flag ? "Enable" : "Disable"))); - } else { - ANDROID_ERROR(("wl_android_set_disable_dtim_in_suspend: failed %d\n", ret)); - } return ret; } #endif /* DISABLE_DTIM_IN_SUSPEND */ -static int wl_android_get_band(struct net_device *dev, char *command, int total_len) +typedef enum band_define { + BAND_DEF_2G5G = 0, /* 0: Auto (2.4GHz + 5GHz) */ + BAND_DEF_5G, /* 1: 5GHz */ + BAND_DEF_2G, /* 2: 2.4GHz */ + BAND_DEF_2G5G6G, /* 3, Auto (2.4GHz + 5GHz + 6GHz) */ + BAND_DEF_6G, /* 4: 6GHz */ + BAND_DEF_5G6G, /* 5: 5GHz + 6GHz */ + BAND_DEF_2G6G, /* 6: 2.4GHz + 6GHz */ + BAMD_DEF_MAX +} band_define_t; + +static int +wl_android_get_band(struct net_device *dev, char *command, int total_len) { - uint band; + uint band, band_def = 0; int bytes_written; int error = BCME_OK; +#ifdef WL_6G_BAND + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); +#endif /* WL_6G_BAND */ error = wldev_iovar_getint(dev, "if_band", &band); if (error == BCME_UNSUPPORTED) { error = wldev_get_band(dev, &band); if (error) { - return error; + return BCME_ERROR; } } - bytes_written = snprintf(command, total_len, "Band %d", band); + + /* Changed Band types to Band Definition */ + switch (band) { + case WLC_BAND_AUTO: +#ifdef WL_6G_BAND + if (cfg->band_6g_supported) { + band_def = BAND_DEF_2G5G6G; + break; + } +#endif /* WL_6G_BAND */ + band_def = BAND_DEF_2G5G; + break; + case WLC_BAND_2G: + band_def = BAND_DEF_2G; + break; + case WLC_BAND_5G: +#ifdef WL_6G_BAND + case WLC_BAND_6G: + if (cfg->band_6g_supported) { + band_def = BAND_DEF_5G6G; + break; + } +#endif /* WL_6G_BAND */ + band_def = BAND_DEF_5G; + break; + default: + WL_ERR(("Unkown band: %d\n", band)); + return BCME_ERROR; + } + + bytes_written = snprintf(command, total_len, "Band %d", band_def); return bytes_written; } -#ifdef WL_CFG80211 static int wl_android_set_band(struct net_device *dev, char *command) { - int error = 0; - uint band = *(command + strlen(CMD_SETBAND) + 1) - '0'; + int error = BCME_OK; + uint band_def, band = 0; + band_def = *(command + strlen(CMD_SETBAND) + 1) - '0'; + + /* Changed Band Definition to Band types */ + switch (band_def) { + case BAND_DEF_2G: + band = WLC_BAND_2G; + break; +#ifndef WL_6G_BAND + case BAND_DEF_2G5G: + band = WLC_BAND_AUTO; + break; + case BAND_DEF_5G: + band = WLC_BAND_5G; + break; +#else + case BAND_DEF_2G5G6G: + band = WLC_BAND_AUTO; + break; + case BAND_DEF_5G6G: + band = WLC_BAND_5G; + break; + /* Can't set only 5GHz or 6GHz band on 6GHz supported device. */ + case BAND_DEF_6G: + case BAND_DEF_2G6G: +#endif /* !WL_6G_BAND */ + default: + WL_ERR(("Unsupported band definition: %d\n", band_def)); + return BCME_ERROR; + } + #ifdef WL_HOST_BAND_MGMT - int ret = 0; - if ((ret = wl_cfg80211_set_band(dev, band)) < 0) { - if (ret == BCME_UNSUPPORTED) { + if ((error = wl_cfg80211_set_band(dev, band)) < 0) { + if (error == BCME_UNSUPPORTED) { /* If roam_var is unsupported, fallback to the original method */ - ANDROID_ERROR(("WL_HOST_BAND_MGMT defined, " + WL_ERR(("WL_HOST_BAND_MGMT defined, " "but roam_band iovar unsupported in the firmware\n")); } else { - error = -1; + error = BCME_ERROR; } } - if (((ret == 0) && (band == WLC_BAND_AUTO)) || (ret == BCME_UNSUPPORTED)) { + if (((error == BCME_OK) && (band == WLC_BAND_AUTO)) || (error == BCME_UNSUPPORTED)) { /* Apply if roam_band iovar is not supported or band setting is AUTO */ error = wldev_set_band(dev, band); } @@ -1673,1698 +1485,14 @@ wl_android_set_band(struct net_device *dev, char *command) #endif /* ROAM_CHANNEL_CACHE */ return error; } -#endif /* WL_CFG80211 */ -#ifdef CUSTOMER_HW4_PRIVATE_CMD -#ifdef ROAM_API -#ifdef WBTEXT +#if defined(WES_SUPPORT) && defined(WBTEXT) static bool wl_android_check_wbtext_support(struct net_device *dev) { dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); return dhdp->wbtext_support; } -#endif /* WBTEXT */ - -static bool -wl_android_check_wbtext_policy(struct net_device *dev) -{ - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); - if (dhdp->wbtext_policy == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT) { - return TRUE; - } - - return FALSE; -} - -static int -wl_android_set_roam_trigger(struct net_device *dev, char* command) -{ - int roam_trigger[2] = {0, 0}; - int error; - -#ifdef WBTEXT - if (wl_android_check_wbtext_policy(dev)) { - ANDROID_ERROR(("blocked to set roam trigger. try with setting roam profile\n")); - return BCME_ERROR; - } -#endif /* WBTEXT */ - - sscanf(command, "%*s %10d", &roam_trigger[0]); - if (roam_trigger[0] >= 0) { - ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0])); - return BCME_ERROR; - } - - roam_trigger[1] = WLC_BAND_ALL; - error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, - sizeof(roam_trigger)); - if (error != BCME_OK) { - ANDROID_ERROR(("failed to set roam trigger (%d)\n", error)); - return BCME_ERROR; - } - - return BCME_OK; -} - -static int -wl_android_get_roam_trigger(struct net_device *dev, char *command, int total_len) -{ - int bytes_written, error; - int roam_trigger[2] = {0, 0}; - uint16 band = 0; - int chsp = {0}; - chanspec_t chanspec; -#ifdef WBTEXT - int i; - wl_roamprof_band_t rp; - uint8 roam_prof_ver = 0, roam_prof_size = 0; -#endif /* WBTEXT */ - - error = wldev_iovar_getint(dev, "chanspec", &chsp); - if (error != BCME_OK) { - ANDROID_ERROR(("failed to get chanspec (%d)\n", error)); - return BCME_ERROR; - } - - chanspec = wl_chspec_driver_to_host(chsp); - band = CHSPEC2WLC_BAND(chanspec); - - if (wl_android_check_wbtext_policy(dev)) { -#ifdef WBTEXT - memset_s(&rp, sizeof(rp), 0, sizeof(rp)); - if ((error = wlc_wbtext_get_roam_prof(dev, &rp, band, &roam_prof_ver, - &roam_prof_size))) { - ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", error)); - return -EINVAL; - } - switch (roam_prof_ver) { - case WL_ROAM_PROF_VER_1: - { - for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) { - if (rp.v2.roam_prof[i].channel_usage == 0) { - roam_trigger[0] = rp.v2.roam_prof[i].roam_trigger; - break; - } - } - } - break; - case WL_ROAM_PROF_VER_2: - { - for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) { - if (rp.v3.roam_prof[i].channel_usage == 0) { - roam_trigger[0] = rp.v3.roam_prof[i].roam_trigger; - break; - } - } - } - break; - case WL_ROAM_PROF_VER_3: - { - for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) { - if (rp.v4.roam_prof[i].channel_usage == 0) { - roam_trigger[0] = rp.v4.roam_prof[i].roam_trigger; - break; - } - } - } - break; - default: - ANDROID_ERROR(("bad version = %d \n", roam_prof_ver)); - return BCME_VERSION; - } -#endif /* WBTEXT */ - if (roam_trigger[0] == 0) { - ANDROID_ERROR(("roam trigger was not set properly\n")); - return BCME_ERROR; - } - } else { - roam_trigger[1] = band; - error = wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, - sizeof(roam_trigger)); - if (error != BCME_OK) { - ANDROID_ERROR(("failed to get roam trigger (%d)\n", error)); - return BCME_ERROR; - } - } - - bytes_written = snprintf(command, total_len, "%s %d", - CMD_ROAMTRIGGER_GET, roam_trigger[0]); - - return bytes_written; -} - -#ifdef WBTEXT -s32 -wl_cfg80211_wbtext_roam_trigger_config(struct net_device *ndev, int roam_trigger) -{ - char *commandp = NULL; - s32 ret = BCME_OK; - char *data; - struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); - uint8 bandidx = 0; - - commandp = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN); - if (unlikely(!commandp)) { - ANDROID_ERROR(("%s: failed to allocate memory\n", __func__)); - ret = -ENOMEM; - goto exit; - } - - ANDROID_INFO(("roam trigger %d\n", roam_trigger)); - if (roam_trigger > 0) { - ANDROID_ERROR(("Invalid roam trigger value %d\n", roam_trigger)); - goto exit; - } - - for (bandidx = 0; bandidx < MAXBANDS; bandidx++) { - char *band; - int tri0, tri1, low0, low1, cu0, cu1, dur0, dur1; - int tri0_dflt; - if (bandidx == BAND_5G_INDEX) { - band = "a"; - tri0_dflt = DEFAULT_WBTEXT_CU_RSSI_TRIG_A; - } else { - band = "b"; - tri0_dflt = DEFAULT_WBTEXT_CU_RSSI_TRIG_B; - } - - /* Get ROAM Profile - * WBTEXT_PROFILE_CONFIG band - */ - bzero(commandp, WLC_IOCTL_SMLEN); - snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s", - CMD_WBTEXT_PROFILE_CONFIG, band); - data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1); - wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN); - - /* Set ROAM Profile - * WBTEXT_PROFILE_CONFIG band -70 roam_trigger 70 10 roam_trigger -128 0 10 - */ - sscanf(commandp, "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)" - "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)", - &tri0, &low0, &cu0, &dur0, &tri1, &low1, &cu1, &dur1); - - if (tri0_dflt <= roam_trigger) { - tri0 = roam_trigger + 1; - } else { - tri0 = tri0_dflt; - } - - memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN); - snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s %d %d %d %d %d %d %d %d", - CMD_WBTEXT_PROFILE_CONFIG, band, - tri0, roam_trigger, cu0, dur0, roam_trigger, low1, cu1, dur1); - - ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN); - if (ret != BCME_OK) { - ANDROID_ERROR(("Failed to set roam_prof %s error = %d\n", data, ret)); - goto exit; - } - } - -exit: - if (commandp) { - MFREE(cfg->osh, commandp, WLC_IOCTL_SMLEN); - } - return ret; -} -#endif /* WBTEXT */ - -static int -wl_android_set_roam_trigger_legacy(struct net_device *dev, char* command) -{ - int roam_trigger[2] = {0, 0}; - int error; - - sscanf(command, "%*s %10d", &roam_trigger[0]); - if (roam_trigger[0] >= 0) { - ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0])); - return BCME_ERROR; - } - - if (wl_android_check_wbtext_policy(dev)) { -#ifdef WBTEXT - error = wl_cfg80211_wbtext_roam_trigger_config(dev, roam_trigger[0]); - if (error != BCME_OK) { - ANDROID_ERROR(("failed to set roam prof trigger (%d)\n", error)); - return BCME_ERROR; - } -#endif /* WBTEXT */ - } else { - if (roam_trigger[0] >= 0) { - ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0])); - return BCME_ERROR; - } - - roam_trigger[1] = WLC_BAND_ALL; - error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, - sizeof(roam_trigger)); - if (error != BCME_OK) { - ANDROID_ERROR(("failed to set roam trigger (%d)\n", error)); - return BCME_ERROR; - } - } - - return BCME_OK; -} - -int wl_android_set_roam_delta( - struct net_device *dev, char* command) -{ - int roam_delta[2]; - - sscanf(command, "%*s %10d", &roam_delta[0]); - roam_delta[1] = WLC_BAND_ALL; - - return wldev_ioctl_set(dev, WLC_SET_ROAM_DELTA, roam_delta, - sizeof(roam_delta)); -} - -static int wl_android_get_roam_delta( - struct net_device *dev, char *command, int total_len) -{ - int bytes_written; - int roam_delta[2] = {0, 0}; - - roam_delta[1] = WLC_BAND_2G; - if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta, - sizeof(roam_delta))) { - roam_delta[1] = WLC_BAND_5G; -#ifdef WL_6G_BAND - if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta, - sizeof(roam_delta))) { - roam_delta[1] = WLC_BAND_6G; -#endif /* WL_6G_BAND */ - if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta, - sizeof(roam_delta))) { - return -1; - } -#ifdef WL_6G_BAND - } -#endif /* WL_6G_BAND */ - } - - bytes_written = snprintf(command, total_len, "%s %d", - CMD_ROAMDELTA_GET, roam_delta[0]); - - return bytes_written; -} - -int wl_android_set_roam_scan_period( - struct net_device *dev, char* command) -{ - int roam_scan_period = 0; - - sscanf(command, "%*s %10d", &roam_scan_period); - return wldev_ioctl_set(dev, WLC_SET_ROAM_SCAN_PERIOD, &roam_scan_period, - sizeof(roam_scan_period)); -} - -static int wl_android_get_roam_scan_period( - struct net_device *dev, char *command, int total_len) -{ - int bytes_written; - int roam_scan_period = 0; - - if (wldev_ioctl_get(dev, WLC_GET_ROAM_SCAN_PERIOD, &roam_scan_period, - sizeof(roam_scan_period))) - return -1; - - bytes_written = snprintf(command, total_len, "%s %d", - CMD_ROAMSCANPERIOD_GET, roam_scan_period); - - return bytes_written; -} - -int wl_android_set_full_roam_scan_period( - struct net_device *dev, char* command) -{ - int error = 0; - int full_roam_scan_period = 0; - char smbuf[WLC_IOCTL_SMLEN]; - - sscanf(command+sizeof("SETFULLROAMSCANPERIOD"), "%d", &full_roam_scan_period); - WL_TRACE(("fullroamperiod = %d\n", full_roam_scan_period)); - - error = wldev_iovar_setbuf(dev, "fullroamperiod", &full_roam_scan_period, - sizeof(full_roam_scan_period), smbuf, sizeof(smbuf), NULL); - if (error) { - ANDROID_ERROR(("Failed to set full roam scan period, error = %d\n", error)); - } - - return error; -} - -static int wl_android_get_full_roam_scan_period( - struct net_device *dev, char *command, int total_len) -{ - int error; - int bytes_written; - int full_roam_scan_period = 0; - - error = wldev_iovar_getint(dev, "fullroamperiod", &full_roam_scan_period); - - if (error) { - ANDROID_ERROR(("%s: get full roam scan period failed code %d\n", - __func__, error)); - return -1; - } else { - ANDROID_INFO(("%s: get full roam scan period %d\n", __func__, full_roam_scan_period)); - } - - bytes_written = snprintf(command, total_len, "%s %d", - CMD_FULLROAMSCANPERIOD_GET, full_roam_scan_period); - - return bytes_written; -} - -int wl_android_set_country_rev( - struct net_device *dev, char* command) -{ - int error = 0; - wl_country_t cspec = {{0}, 0, {0} }; - char country_code[WLC_CNTRY_BUF_SZ]; - char smbuf[WLC_IOCTL_SMLEN]; - int rev = 0; - - bzero(country_code, sizeof(country_code)); - sscanf(command+sizeof("SETCOUNTRYREV"), "%3s %10d", country_code, &rev); - WL_TRACE(("country_code = %s, rev = %d\n", country_code, rev)); - - memcpy(cspec.country_abbrev, country_code, sizeof(country_code)); - memcpy(cspec.ccode, country_code, sizeof(country_code)); - cspec.rev = rev; - - error = wldev_iovar_setbuf(dev, "country", (char *)&cspec, - sizeof(cspec), smbuf, sizeof(smbuf), NULL); - - if (error) { - ANDROID_ERROR(("wl_android_set_country_rev: set country '%s/%d' failed code %d\n", - cspec.ccode, cspec.rev, error)); - } else { - dhd_bus_country_set(dev, &cspec, true); - ANDROID_INFO(("wl_android_set_country_rev: set country '%s/%d'\n", - cspec.ccode, cspec.rev)); - } - - return error; -} - -static int wl_android_get_country_rev( - struct net_device *dev, char *command, int total_len) -{ - int error; - int bytes_written; - char smbuf[WLC_IOCTL_SMLEN]; - wl_country_t cspec; - - error = wldev_iovar_getbuf(dev, "country", NULL, 0, smbuf, - sizeof(smbuf), NULL); - - if (error) { - ANDROID_ERROR(("wl_android_get_country_rev: get country failed code %d\n", - error)); - return -1; - } else { - memcpy(&cspec, smbuf, sizeof(cspec)); - ANDROID_INFO(("wl_android_get_country_rev: get country '%c%c %d'\n", - cspec.ccode[0], cspec.ccode[1], cspec.rev)); - } - - bytes_written = snprintf(command, total_len, "%s %c%c %d", - CMD_COUNTRYREV_GET, cspec.ccode[0], cspec.ccode[1], cspec.rev); - - return bytes_written; -} -#endif /* ROAM_API */ - -#ifdef WES_SUPPORT -int wl_android_get_roam_scan_control(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - int bytes_written = 0; - int mode = 0; - - error = get_roamscan_mode(dev, &mode); - if (error) { - ANDROID_ERROR(("wl_android_get_roam_scan_control: Failed to get Scan Control," - " error = %d\n", error)); - return -1; - } - - bytes_written = snprintf(command, total_len, "%s %d", CMD_GETROAMSCANCONTROL, mode); - - return bytes_written; -} - -int wl_android_set_roam_scan_control(struct net_device *dev, char *command) -{ - int error = 0; - int mode = 0; - - if (sscanf(command, "%*s %d", &mode) != 1) { - ANDROID_ERROR(("wl_android_set_roam_scan_control: Failed to get Parameter\n")); - return -1; - } - - error = set_roamscan_mode(dev, mode); - if (error) { - ANDROID_ERROR(("wl_android_set_roam_scan_control: Failed to set Scan Control %d," - " error = %d\n", - mode, error)); - return -1; - } - - return 0; -} - -int -wl_android_get_roam_scan_channels(struct net_device *dev, char *command, int total_len, char *cmd) -{ - int bytes_written = 0; - chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0}; - int nchan = 0, i = 0; - int buf_avail, len; - - nchan = get_roamscan_chanspec_list(dev, chanspecs); - if (nchan < 0) { - ANDROID_ERROR(("Failed to Set roamscan channels, n_chan = %d\n", nchan)); - return BCME_ERROR; - } - - bytes_written = snprintf(command, total_len, "%s %d", cmd, nchan); - - buf_avail = total_len - bytes_written; - for (i = 0; i < nchan; i++) { - /* A return value of 'buf_avail' or more means that the output was truncated */ - len = snprintf(command + bytes_written, buf_avail, " %d", - CHSPEC_CHANNEL(chanspecs[i])); - if (len >= buf_avail) { - ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len)); - ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len)); - bytes_written = -1; - break; - } - /* 'buf_avail' decremented by number of bytes written */ - buf_avail -= len; - bytes_written += len; - } - ANDROID_INFO(("%s\n", command)); - return bytes_written; -} - -#define CHANNEL_IDX 1 -int -wl_android_set_roam_scan_channels(struct net_device *dev, char *command) -{ - int error = BCME_OK, i; - unsigned char *p = (unsigned char *)(command + strlen(CMD_SETROAMSCANCHANNELS) + 1); - uint16 nchan = 0, channel = 0; - chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0}; - - nchan = p[0]; - if (nchan > MAX_ROAM_CHANNEL) { - ANDROID_ERROR(("Failed to Set roamscan channnels, n_chan = %d\n", nchan)); - return BCME_BADARG; - } - - for (i = 0; i < nchan; i++) { - channel = p[i + CHANNEL_IDX]; - /* Convert chanspec from channel */ - chanspecs[i] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20); - } - - error = set_roamscan_chanspec_list(dev, nchan, chanspecs); - if (error) { - ANDROID_ERROR(("Failed to Set Scan Channels %d, error = %d\n", p[0], error)); - return error; - } - - return error; -} - -int -wl_android_add_roam_scan_channels(struct net_device *dev, char *command, uint cmdlen) -{ - int i, error = BCME_OK; - char *pcmd, *token; - uint16 nchan = 0, channel = 0; - chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0}; - - pcmd = (command + cmdlen + 1); - /* Parse roam channel count */ - token = bcmstrtok(&pcmd, " ", NULL); - if (!token) { - ANDROID_ERROR(("Bad argument!\n")); - return BCME_BADARG; - } - nchan = bcm_atoi(token); - if (nchan > MAX_ROAM_CHANNEL) { - ANDROID_ERROR(("Failed to Add roamscan channnels, n_chan = %d\n", nchan)); - return BCME_BADARG; - } - - for (i = 0; i < nchan; i++) { - /* Parse roam channel list */ - token = bcmstrtok(&pcmd, " ", NULL); - if (!token) { - ANDROID_ERROR(("Bad argument!\n")); - return BCME_BADARG; - } - channel = bcm_atoi(token); - /* Convert chanspec from channel */ - if (channel > 0) { - chanspecs[i] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20); - } - } - - error = add_roamscan_chanspec_list(dev, nchan, chanspecs); - if (error) { - ANDROID_ERROR(("Failed to add Scan Channels %s, error = %d\n", pcmd, error)); - } - - return error; -} - -int -wl_android_get_roam_scan_freqs(struct net_device *dev, char *command, int total_len, char *cmd) -{ - int bytes_written = 0; - chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0}; - int nchan = 0, i = 0; - int buf_avail, len; - u32 freq = 0; - uint start_factor = 0; - - nchan = get_roamscan_chanspec_list(dev, chanspecs); - if (nchan < 0) { - ANDROID_ERROR(("Failed to Get roamscan frequencies, n_chan = %d\n", nchan)); - return BCME_ERROR; - } - - bytes_written = snprintf(command, total_len, "%s %d", cmd, nchan); - - buf_avail = total_len - bytes_written; - for (i = 0; i < nchan; i++) { - start_factor = WF_CHAN_FACTOR_2_4_G; - if (CHSPEC_BAND(chanspecs[i]) == WL_CHANSPEC_BAND_5G) { - start_factor = WF_CHAN_FACTOR_5_G; - } else if (CHSPEC_BAND(chanspecs[i]) == WL_CHANSPEC_BAND_6G) { - start_factor = WF_CHAN_FACTOR_6_G; - } - freq = wf_channel2mhz(CHSPEC_CHANNEL(chanspecs[i]), start_factor); - /* A return value of 'buf_avail' or more means that the output was truncated */ - len = snprintf(command + bytes_written, buf_avail, " %d", freq); - if (len >= buf_avail) { - ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len)); - bytes_written = -1; - break; - } - /* 'buf_avail' decremented by number of bytes written */ - buf_avail -= len; - bytes_written += len; - } - ANDROID_INFO(("%s\n", command)); - return bytes_written; -} - -int -wl_android_set_roam_scan_freqs(struct net_device *dev, char *command) -{ - int error = BCME_OK, i; - char *pcmd, *token; - uint16 nchan = 0, freq = 0; - chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0}; - - pcmd = (command + strlen(CMD_SETROAMSCANFREQS) + 1); - /* Parse roam channel count */ - token = bcmstrtok(&pcmd, " ", NULL); - if (!token) { - ANDROID_ERROR(("Bad argument!\n")); - return BCME_BADARG; - } - nchan = bcm_atoi(token); - if (nchan > MAX_ROAM_CHANNEL) { - ANDROID_ERROR(("Failed to Set roamscan frequencies, n_chan = %d\n", nchan)); - return BCME_BADARG; - } - - for (i = 0; i < nchan; i++) { - /* Parse roam channel list */ - token = bcmstrtok(&pcmd, " ", NULL); - if (!token) { - ANDROID_ERROR(("Bad argument!\n")); - return BCME_BADARG; - } - freq = bcm_atoi(token); - /* Convert chanspec from frequency */ - chanspecs[i] = wl_freq_to_chanspec(freq); - } - - error = set_roamscan_chanspec_list(dev, nchan, chanspecs); - if (error) { - ANDROID_ERROR(("Failed to set Scan Channels %d, error = %d\n", nchan, error)); - return error; - } - - return error; -} - -int -wl_android_add_roam_scan_freqs(struct net_device *dev, char *command, uint cmdlen) -{ - int i, error = BCME_OK; - char *pcmd, *token; - uint16 nchan = 0, freq = 0; - chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0}; - - pcmd = (command + cmdlen + 1); - /* Parse roam channel count */ - token = bcmstrtok(&pcmd, " ", NULL); - if (!token) { - ANDROID_ERROR(("Bad argument!\n")); - return BCME_BADARG; - } - nchan = bcm_atoi(token); - if (nchan > MAX_ROAM_CHANNEL) { - ANDROID_ERROR(("Failed to Add roamscan frequencies, n_chan = %d\n", nchan)); - return BCME_BADARG; - } - - for (i = 0; i < nchan; i++) { - /* Parse roam channel list */ - token = bcmstrtok(&pcmd, " ", NULL); - if (!token) { - ANDROID_ERROR(("Bad argument!\n")); - return BCME_BADARG; - } - freq = bcm_atoi(token); - /* Convert chanspec from channel */ - if (freq > 0) { - chanspecs[i] = wl_freq_to_chanspec(freq); - } - } - - error = add_roamscan_chanspec_list(dev, nchan, chanspecs); - if (error) { - ANDROID_ERROR(("Failed to add Scan Channels %s, error = %d\n", pcmd, error)); - } - - return error; -} - -int -wl_android_get_scan_channel_time(struct net_device *dev, char *command, int total_len) -{ - int error = BCME_OK; - int bytes_written = 0; - int time = 0; - - error = wldev_ioctl_get(dev, WLC_GET_SCAN_CHANNEL_TIME, &time, sizeof(time)); - if (error) { - ANDROID_ERROR(("Failed to get Scan Channel Time, error = %d\n", error)); - return BCME_ERROR; - } - - bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANCHANNELTIME, time); - - return bytes_written; -} - -int -wl_android_set_scan_channel_time(struct net_device *dev, char *command) -{ - int error = BCME_OK; - int time = 0; - - if (sscanf(command, "%*s %d", &time) != 1) { - ANDROID_ERROR(("Failed to get Parameter\n")); - return BCME_ERROR; - } - - if (time == 0) { - /* Set default value when Private param is 0. */ - time = DHD_SCAN_ASSOC_ACTIVE_TIME; - } -#ifdef CUSTOMER_SCAN_TIMEOUT_SETTING - wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_CHANNEL_TIME, time); - error = wldev_ioctl_set(dev, WLC_SET_SCAN_CHANNEL_TIME, &time, sizeof(time)); -#endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */ - if (error) { - ANDROID_ERROR(("Failed to set Scan Channel Time %d, error = %d\n", time, error)); - return BCME_ERROR; - } - - return error; -} - -int -wl_android_get_scan_unassoc_time(struct net_device *dev, char *command, int total_len) -{ - int error = BCME_OK; - int bytes_written = 0; - int time = 0; - - error = wldev_ioctl_get(dev, WLC_GET_SCAN_UNASSOC_TIME, &time, sizeof(time)); - if (error) { - ANDROID_ERROR(("Failed to get Scan Unassoc Time, error = %d\n", error)); - return BCME_ERROR; - } - - bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANUNASSOCTIME, time); - - return bytes_written; -} - -int -wl_android_set_scan_unassoc_time(struct net_device *dev, char *command) -{ - int error = BCME_OK; - int time = 0; - - if (sscanf(command, "%*s %d", &time) != 1) { - ANDROID_ERROR(("Failed to get Parameter\n")); - return BCME_ERROR; - } - if (time == 0) { - /* Set default value when Private param is 0. */ - time = DHD_SCAN_UNASSOC_ACTIVE_TIME; - } -#ifdef CUSTOMER_SCAN_TIMEOUT_SETTING - wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_UNASSOC_TIME, time); - error = wldev_ioctl_set(dev, WLC_SET_SCAN_UNASSOC_TIME, &time, sizeof(time)); -#endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */ - if (error) { - ANDROID_ERROR(("Failed to set Scan Unassoc Time %d, error = %d\n", time, error)); - return BCME_ERROR; - } - - return error; -} - -int -wl_android_get_scan_passive_time(struct net_device *dev, char *command, int total_len) -{ - int error = BCME_OK; - int bytes_written = 0; - int time = 0; - - error = wldev_ioctl_get(dev, WLC_GET_SCAN_PASSIVE_TIME, &time, sizeof(time)); - if (error) { - ANDROID_ERROR(("Failed to get Scan Passive Time, error = %d\n", error)); - return BCME_ERROR; - } - - bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANPASSIVETIME, time); - - return bytes_written; -} - -int -wl_android_set_scan_passive_time(struct net_device *dev, char *command) -{ - int error = BCME_OK; - int time = 0; - - if (sscanf(command, "%*s %d", &time) != 1) { - ANDROID_ERROR(("Failed to get Parameter\n")); - return BCME_ERROR; - } - if (time == 0) { - /* Set default value when Private param is 0. */ - time = DHD_SCAN_PASSIVE_TIME; - } -#ifdef CUSTOMER_SCAN_TIMEOUT_SETTING - wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_PASSIVE_TIME, time); - error = wldev_ioctl_set(dev, WLC_SET_SCAN_PASSIVE_TIME, &time, sizeof(time)); -#endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */ - if (error) { - ANDROID_ERROR(("Failed to set Scan Passive Time %d, error = %d\n", time, error)); - return BCME_ERROR; - } - - return error; -} - -int -wl_android_get_scan_home_time(struct net_device *dev, char *command, int total_len) -{ - int error = BCME_OK; - int bytes_written = 0; - int time = 0; - - error = wldev_ioctl_get(dev, WLC_GET_SCAN_HOME_TIME, &time, sizeof(time)); - if (error) { - ANDROID_ERROR(("Failed to get Scan Home Time, error = %d\n", error)); - return BCME_ERROR; - } - - bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMETIME, time); - - return bytes_written; -} - -int wl_android_set_scan_home_time(struct net_device *dev, char *command) -{ - int error = BCME_OK; - int time = 0; - - if (sscanf(command, "%*s %d", &time) != 1) { - ANDROID_ERROR(("Failed to get Parameter\n")); - return BCME_ERROR; - } - if (time == 0) { - /* Set default value when Private param is 0. */ - time = DHD_SCAN_HOME_TIME; - } -#ifdef CUSTOMER_SCAN_TIMEOUT_SETTING - wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_TIME, time); - error = wldev_ioctl_set(dev, WLC_SET_SCAN_HOME_TIME, &time, sizeof(time)); -#endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */ - if (error) { - ANDROID_ERROR(("Failed to set Scan Home Time %d, error = %d\n", time, error)); - return BCME_ERROR; - } - - return error; -} - -int -wl_android_get_scan_home_away_time(struct net_device *dev, char *command, int total_len) -{ - int error = BCME_OK; - int bytes_written = 0; - int time = 0; - - error = wldev_iovar_getint(dev, "scan_home_away_time", &time); - if (error) { - ANDROID_ERROR(("Failed to get Scan Home Away Time, error = %d\n", error)); - return BCME_ERROR; - } - - bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMEAWAYTIME, time); - - return bytes_written; -} - -int -wl_android_set_scan_home_away_time(struct net_device *dev, char *command) -{ - int error = BCME_OK; - int time = 0; - - if (sscanf(command, "%*s %d", &time) != 1) { - ANDROID_ERROR(("Failed to get Parameter\n")); - return BCME_ERROR; - } - if (time == 0) { - /* Set default value when Private param is 0. */ - time = DHD_SCAN_HOME_AWAY_TIME; - } -#ifdef CUSTOMER_SCAN_TIMEOUT_SETTING - wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_AWAY_TIME, time); - error = wldev_iovar_setint(dev, "scan_home_away_time", time); -#endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */ - if (error) { - ANDROID_ERROR(("Failed to set Scan Home Away Time %d, error = %d\n", time, error)); - return BCME_ERROR; - } - - return error; -} - -int -wl_android_get_scan_nprobes(struct net_device *dev, char *command, int total_len) -{ - int error = BCME_OK; - int bytes_written = 0; - int num = 0; - - error = wldev_ioctl_get(dev, WLC_GET_SCAN_NPROBES, &num, sizeof(num)); - if (error) { - ANDROID_ERROR(("Failed to get Scan NProbes, error = %d\n", error)); - return BCME_ERROR; - } - - bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANNPROBES, num); - - return bytes_written; -} - -int -wl_android_set_scan_nprobes(struct net_device *dev, char *command) -{ - int error = BCME_OK; - int num = 0; - - if (sscanf(command, "%*s %d", &num) != 1) { - ANDROID_ERROR(("Failed to get Parameter\n")); - return BCME_ERROR; - } - - error = wldev_ioctl_set(dev, WLC_SET_SCAN_NPROBES, &num, sizeof(num)); - if (error) { - ANDROID_ERROR(("Failed to set Scan NProbes %d, error = %d\n", num, error)); - return BCME_ERROR; - } - - return error; -} - -int -wl_android_get_scan_dfs_channel_mode(struct net_device *dev, char *command, int total_len) -{ - int error = BCME_OK; - int bytes_written = 0; - int mode = 0; - int scan_passive_time = 0; - - error = wldev_iovar_getint(dev, "scan_passive_time", &scan_passive_time); - if (error) { - ANDROID_ERROR(("Failed to get Passive Time, error = %d\n", error)); - return BCME_ERROR; - } - - if (scan_passive_time == 0) { - mode = 0; - } else { - mode = 1; - } - - bytes_written = snprintf(command, total_len, "%s %d", CMD_GETDFSSCANMODE, mode); - - return bytes_written; -} - -int -wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command) -{ - int error = BCME_OK; - int mode = 0; - int scan_passive_time = 0; - - if (sscanf(command, "%*s %d", &mode) != 1) { - ANDROID_ERROR(("Failed to get Parameter\n")); - return BCME_ERROR; - } - - if (mode == 1) { - scan_passive_time = DHD_SCAN_PASSIVE_TIME; - } else if (mode == 0) { - scan_passive_time = 0; - } else { - ANDROID_ERROR(("Failed to set Scan DFS channel mode %d\n", mode)); - return BCME_ERROR; - } - error = wldev_iovar_setint(dev, "scan_passive_time", scan_passive_time); - if (error) { - ANDROID_ERROR(("Failed to set Scan Passive Time %d, error = %d\n", - scan_passive_time, error)); - return BCME_ERROR; - } - - return error; -} - -#define JOINPREFFER_BUF_SIZE 12 - -static int -wl_android_set_join_prefer(struct net_device *dev, char *command) -{ - int error = BCME_OK; - char smbuf[WLC_IOCTL_SMLEN]; - uint8 buf[JOINPREFFER_BUF_SIZE]; - char *pcmd; - int total_len_left; - int i; - char hex[] = "XX"; -#ifdef WBTEXT - int turn_on = OFF; - char clear[] = { 0x01, 0x02, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 }; -#endif /* WBTEXT */ - - pcmd = command + strlen(CMD_SETJOINPREFER) + 1; - total_len_left = strlen(pcmd); - - bzero(buf, sizeof(buf)); - - if (total_len_left != JOINPREFFER_BUF_SIZE << 1) { - ANDROID_ERROR(("wl_android_set_join_prefer: Failed to get Parameter\n")); - return BCME_ERROR; - } - - /* Store the MSB first, as required by join_pref */ - for (i = 0; i < JOINPREFFER_BUF_SIZE; i++) { - hex[0] = *pcmd++; - hex[1] = *pcmd++; - buf[i] = (uint8)simple_strtoul(hex, NULL, 16); - } - -#ifdef WBTEXT - /* Set WBTEXT mode */ - turn_on = memcmp(buf, clear, sizeof(buf)) == 0 ? TRUE : FALSE; - error = wl_android_wbtext_enable(dev, turn_on); - if (error) { - ANDROID_ERROR(("Failed to set WBTEXT(%d) = %s\n", - error, (turn_on ? "Enable" : "Disable"))); - } -#endif /* WBTEXT */ - - prhex("join pref", (uint8 *)buf, JOINPREFFER_BUF_SIZE); - error = wldev_iovar_setbuf(dev, "join_pref", buf, JOINPREFFER_BUF_SIZE, - smbuf, sizeof(smbuf), NULL); - if (error) { - ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error)); - } - - return error; -} - -int wl_android_send_action_frame(struct net_device *dev, char *command, int total_len) -{ - int error = -1; - android_wifi_af_params_t *params = NULL; - wl_action_frame_t *action_frame = NULL; - wl_af_params_t *af_params = NULL; - char *smbuf = NULL; - struct ether_addr tmp_bssid; - int tmp_channel = 0; - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - - if (total_len < - (strlen(CMD_SENDACTIONFRAME) + 1 + sizeof(android_wifi_af_params_t))) { - ANDROID_ERROR(("wl_android_send_action_frame: Invalid parameters \n")); - goto send_action_frame_out; - } - - params = (android_wifi_af_params_t *)(command + strlen(CMD_SENDACTIONFRAME) + 1); - - if ((uint16)params->len > ANDROID_WIFI_ACTION_FRAME_SIZE) { - ANDROID_ERROR(("wl_android_send_action_frame: Requested action frame len" - " was out of range(%d)\n", - params->len)); - goto send_action_frame_out; - } - - smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN); - if (smbuf == NULL) { - ANDROID_ERROR(("wl_android_send_action_frame: failed to allocated memory %d bytes\n", - WLC_IOCTL_MAXLEN)); - goto send_action_frame_out; - } - - af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE); - if (af_params == NULL) { - ANDROID_ERROR(("wl_android_send_action_frame: unable to allocate frame\n")); - goto send_action_frame_out; - } - - bzero(&tmp_bssid, ETHER_ADDR_LEN); - if (bcm_ether_atoe((const char *)params->bssid, (struct ether_addr *)&tmp_bssid) == 0) { - bzero(&tmp_bssid, ETHER_ADDR_LEN); - - error = wldev_ioctl_get(dev, WLC_GET_BSSID, &tmp_bssid, ETHER_ADDR_LEN); - if (error) { - bzero(&tmp_bssid, ETHER_ADDR_LEN); - ANDROID_ERROR(("wl_android_send_action_frame: failed to get bssid," - " error=%d\n", error)); - goto send_action_frame_out; - } - } - - if (params->channel < 0) { - struct channel_info ci; - bzero(&ci, sizeof(ci)); - error = wldev_ioctl_get(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)); - if (error) { - ANDROID_ERROR(("wl_android_send_action_frame: failed to get channel," - " error=%d\n", error)); - goto send_action_frame_out; - } - - tmp_channel = ci.hw_channel; - } - else { - tmp_channel = params->channel; - } - - af_params->channel = tmp_channel; - af_params->dwell_time = params->dwell_time; - memcpy(&af_params->BSSID, &tmp_bssid, ETHER_ADDR_LEN); - action_frame = &af_params->action_frame; - - action_frame->packetId = 0; - memcpy(&action_frame->da, &tmp_bssid, ETHER_ADDR_LEN); - action_frame->len = (uint16)params->len; - memcpy(action_frame->data, params->data, action_frame->len); - - error = wldev_iovar_setbuf(dev, "actframe", af_params, - sizeof(wl_af_params_t), smbuf, WLC_IOCTL_MAXLEN, NULL); - if (error) { - ANDROID_ERROR(("wl_android_send_action_frame: failed to set action frame," - " error=%d\n", error)); - } - -send_action_frame_out: - if (af_params) { - MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE); - } - - if (smbuf) { - MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN); - } - - if (error) - return -1; - else - return 0; -} - -int -wl_android_reassoc(struct net_device *dev, char *command, int total_len) -{ - int error = BCME_OK; - android_wifi_reassoc_params_t *params = NULL; - chanspec_t channel; - u32 params_size; - wl_reassoc_params_t reassoc_params; - char pcmd[WL_PRIV_CMD_LEN + 1]; - - sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s *", pcmd); - if (total_len < (strlen(pcmd) + 1 + sizeof(android_wifi_reassoc_params_t))) { - ANDROID_ERROR(("Invalid parameters %s\n", command)); - return BCME_ERROR; - } - params = (android_wifi_reassoc_params_t *)(command + strlen(pcmd) + 1); - - bzero(&reassoc_params, WL_REASSOC_PARAMS_FIXED_SIZE); - - if (bcm_ether_atoe((const char *)params->bssid, - (struct ether_addr *)&reassoc_params.bssid) == 0) { - ANDROID_ERROR(("Invalid bssid \n")); - return BCME_BADARG; - } - - if (params->channel < 0) { - ANDROID_ERROR(("Invalid Channel %d\n", params->channel)); - return BCME_BADARG; - } - - reassoc_params.chanspec_num = 1; - - channel = params->channel; - if (CHANNEL_IS_2G(channel) || CHANNEL_IS_5G(channel)) { - /* If reassoc Param is BSSID and Channel */ - reassoc_params.chanspec_list[0] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20); - } else { - /* If reassoc Param is BSSID and Frequency */ - reassoc_params.chanspec_list[0] = wl_freq_to_chanspec(channel); - } - params_size = WL_REASSOC_PARAMS_FIXED_SIZE + sizeof(chanspec_t); - - error = wldev_ioctl_set(dev, WLC_REASSOC, &reassoc_params, params_size); - if (error) { - ANDROID_ERROR(("failed to reassoc, error=%d\n", error)); - return error; - } - return error; -} - -int wl_android_get_wes_mode(struct net_device *dev, char *command, int total_len) -{ - int bytes_written = 0; - int mode = 0; - - mode = wl_cfg80211_get_wes_mode(dev); - - bytes_written = snprintf(command, total_len, "%s %d", CMD_GETWESMODE, mode); - - return bytes_written; -} - -int wl_android_set_wes_mode(struct net_device *dev, char *command) -{ - int error = 0; - int mode = 0; - - if (sscanf(command, "%*s %d", &mode) != 1) { - ANDROID_ERROR(("wl_android_set_wes_mode: Failed to get Parameter\n")); - return -1; - } - - error = wl_cfg80211_set_wes_mode(dev, mode); - if (error) { - ANDROID_ERROR(("wl_android_set_wes_mode: Failed to set WES Mode %d, error = %d\n", - mode, error)); - return -1; - } - - return 0; -} - -int -wl_android_get_ncho_mode(struct net_device *dev, char *command, int total_len) -{ - int bytes_written = 0; - int mode = 0; - - mode = wl_cfg80211_get_ncho_mode(dev); - - bytes_written = snprintf(command, total_len, "%s %d", CMD_GETNCHOMODE, mode); - - return bytes_written; -} - -int -wl_android_set_ncho_mode(struct net_device *dev, int mode) -{ - char cmd[WLC_IOCTL_SMLEN]; - int error = BCME_OK; - -#ifdef WBTEXT - /* Set WBTEXT mode */ - error = wl_android_wbtext_enable(dev, !mode); - if (error) { - ANDROID_ERROR(("Failed to set WBTEXT(%d) = %s\n", - error, (mode ? "Disable" : "Enable"))); - } -#endif /* WBTEXT */ - /* Set Piority roam mode */ - error = wl_android_priority_roam_enable(dev, !mode); - if (error) { - ANDROID_ERROR(("Failed to set Priority Roam(%d) = %s\n", - error, (mode ? "Disable" : "Enable"))); - } -#ifdef CONFIG_SILENT_ROAM - /* Set Silent roam mode */ - error = wl_android_sroam_turn_on(dev, !mode); - if (error) { - ANDROID_ERROR(("Failed to set SROAM(%d) = %s\n", - error, (mode ? "Disable" : "Enable"))); - } -#endif /* CONFIG_SILENT_ROAM */ - /* Set RCROAM(ROAMEXT) mode */ - error = wl_android_rcroam_turn_on(dev, !mode); - if (error) { - ANDROID_ERROR(("Failed to set RCROAM(%d) = %s\n", - error, (mode ? "Disable" : "Enable"))); - } - - if (mode == OFF) { - /* restore NCHO set parameters */ - bzero(cmd, WLC_IOCTL_SMLEN); - snprintf(cmd, WLC_IOCTL_SMLEN, "%s", CMD_RESTORE_SCAN_PARAMS); - error = wl_android_default_set_scan_params(dev, cmd, WLC_IOCTL_SMLEN); - if (error) { - ANDROID_ERROR(("Failed to set RESTORE_SCAN_PARAMS(%d)\n", error)); - } - - wl_cfg80211_set_wes_mode(dev, OFF); - set_roamscan_mode(dev, ROAMSCAN_MODE_NORMAL); - } - - error = wl_cfg80211_set_ncho_mode(dev, mode); - if (error) { - ANDROID_ERROR(("Failed to set NCHO Mode %d, error = %d\n", mode, error)); - } - - return error; -} - -static int -wl_android_set_pmk(struct net_device *dev, char *command, int total_len) -{ - uchar pmk[33]; - int error = 0; - char smbuf[WLC_IOCTL_SMLEN]; - dhd_pub_t *dhdp; -#ifdef OKC_DEBUG - int i = 0; -#endif - - if (total_len < (strlen("SET_PMK ") + 32)) { - ANDROID_ERROR(("wl_android_set_pmk: Invalid argument\n")); - return -1; - } - - dhdp = wl_cfg80211_get_dhdp(dev); - if (!dhdp) { - ANDROID_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); - return -1; - } - - bzero(pmk, sizeof(pmk)); - DHD_STATLOG_CTRL(dhdp, ST(INSTALL_OKC_PMK), dhd_net2idx(dhdp->info, dev), 0); - memcpy((char *)pmk, command + strlen("SET_PMK "), 32); - error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL); - if (error) { - ANDROID_ERROR(("Failed to set PMK for OKC, error = %d\n", error)); - } -#ifdef OKC_DEBUG - ANDROID_ERROR(("PMK is ")); - for (i = 0; i < 32; i++) - ANDROID_ERROR(("%02X ", pmk[i])); - - ANDROID_ERROR(("\n")); -#endif - return error; -} - -static int -wl_android_okc_enable(struct net_device *dev, char *command) -{ - int error = 0; - char okc_enable = 0; - - okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0'; - error = wldev_iovar_setint(dev, "okc_enable", okc_enable); - if (error) { - ANDROID_ERROR(("Failed to %s OKC, error = %d\n", - okc_enable ? "enable" : "disable", error)); - } - - return error; -} - -static int -wl_android_legacy_check_command(struct net_device *dev, char *command) -{ - int cnt = 0; - - while (strlen(legacy_cmdlist[cnt]) > 0) { - if (strnicmp(command, legacy_cmdlist[cnt], strlen(legacy_cmdlist[cnt])) == 0) { - char cmd[WL_PRIV_CMD_LEN + 1]; - sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s ", cmd); - if (strlen(legacy_cmdlist[cnt]) == strlen(cmd)) { - return TRUE; - } - } - cnt++; - } - return FALSE; -} - -static int -wl_android_legacy_private_command(struct net_device *net, char *command, int total_len) -{ - int bytes_written = 0; - struct bcm_cfg80211 *cfg = wl_get_cfg(net); - - if (cfg->ncho_mode == ON) { - ANDROID_ERROR(("Enabled NCHO mode\n")); - /* In order to avoid Sequential error HANG event. */ - return BCME_UNSUPPORTED; - } - - /* ROAMSCAN CHANNELS Add, Get Command */ - if (strnicmp(command, CMD_ADDROAMSCANCHLEGACY, strlen(CMD_ADDROAMSCANCHLEGACY)) == 0) { - bytes_written = wl_android_add_roam_scan_channels(net, command, - strlen(CMD_ADDROAMSCANCHLEGACY)); - } - else if (strnicmp(command, CMD_GETROAMSCANCHLEGACY, strlen(CMD_GETROAMSCANCHLEGACY)) == 0) { - bytes_written = wl_android_get_roam_scan_channels(net, command, total_len, - CMD_GETROAMSCANCHLEGACY); - } - /* ROAMSCAN FREQUENCIES Add, Get Command */ - else if (strnicmp(command, CMD_ADDROAMSCANFQLEGACY, strlen(CMD_ADDROAMSCANFQLEGACY)) == 0) { - bytes_written = wl_android_add_roam_scan_freqs(net, command, - strlen(CMD_ADDROAMSCANFQLEGACY)); - } - else if (strnicmp(command, CMD_GETROAMSCANFQLEGACY, strlen(CMD_GETROAMSCANFQLEGACY)) == 0) { - bytes_written = wl_android_get_roam_scan_freqs(net, command, total_len, - CMD_GETROAMSCANFQLEGACY); - } - else if (strnicmp(command, CMD_GETROAMTRIGLEGACY, strlen(CMD_GETROAMTRIGLEGACY)) == 0) { - bytes_written = wl_android_get_roam_trigger(net, command, total_len); - } - else if (strnicmp(command, CMD_SETROAMTRIGLEGACY, strlen(CMD_SETROAMTRIGLEGACY)) == 0) { - bytes_written = wl_android_set_roam_trigger_legacy(net, command); - } - else if (strnicmp(command, CMD_REASSOCLEGACY, strlen(CMD_REASSOCLEGACY)) == 0) { - bytes_written = wl_android_reassoc(net, command, total_len); - } - else if (strnicmp(command, CMD_GETSCANCHANNELTIMELEGACY, - strlen(CMD_GETSCANCHANNELTIMELEGACY)) == 0) { - bytes_written = wl_android_get_scan_channel_time(net, command, total_len); - } - else if (strnicmp(command, CMD_SETSCANCHANNELTIMELEGACY, - strlen(CMD_SETSCANCHANNELTIMELEGACY)) == 0) { - bytes_written = wl_android_set_scan_channel_time(net, command); - } - else if (strnicmp(command, CMD_GETSCANUNASSOCTIMELEGACY, - strlen(CMD_GETSCANUNASSOCTIMELEGACY)) == 0) { - bytes_written = wl_android_get_scan_unassoc_time(net, command, total_len); - } - else if (strnicmp(command, CMD_SETSCANUNASSOCTIMELEGACY, - strlen(CMD_SETSCANUNASSOCTIMELEGACY)) == 0) { - bytes_written = wl_android_set_scan_unassoc_time(net, command); - } - else if (strnicmp(command, CMD_GETSCANPASSIVETIMELEGACY, - strlen(CMD_GETSCANPASSIVETIMELEGACY)) == 0) { - bytes_written = wl_android_get_scan_passive_time(net, command, total_len); - } - else if (strnicmp(command, CMD_SETSCANPASSIVETIMELEGACY, - strlen(CMD_SETSCANPASSIVETIMELEGACY)) == 0) { - bytes_written = wl_android_set_scan_passive_time(net, command); - } - else if (strnicmp(command, CMD_GETSCANHOMETIMELEGACY, - strlen(CMD_GETSCANHOMETIMELEGACY)) == 0) { - bytes_written = wl_android_get_scan_home_time(net, command, total_len); - } - else if (strnicmp(command, CMD_SETSCANHOMETIMELEGACY, - strlen(CMD_SETSCANHOMETIMELEGACY)) == 0) { - bytes_written = wl_android_set_scan_home_time(net, command); - } - else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIMELEGACY, - strlen(CMD_GETSCANHOMEAWAYTIMELEGACY)) == 0) { - bytes_written = wl_android_get_scan_home_away_time(net, command, total_len); - } - else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIMELEGACY, - strlen(CMD_SETSCANHOMEAWAYTIMELEGACY)) == 0) { - bytes_written = wl_android_set_scan_home_away_time(net, command); - } - else { - ANDROID_ERROR(("Unknown NCHO PRIVATE command %s - ignored\n", command)); - bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL"); - } - - return bytes_written; -} - -static int -wl_android_ncho_check_command(struct net_device *dev, char *command) -{ - int cnt = 0; - - while (strlen(ncho_cmdlist[cnt]) > 0) { - if (strnicmp(command, ncho_cmdlist[cnt], strlen(ncho_cmdlist[cnt])) == 0) { - char cmd[WL_PRIV_CMD_LEN + 1]; - sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s ", cmd); - if (strlen(ncho_cmdlist[cnt]) == strlen(cmd)) { - return TRUE; - } - } - cnt++; - } - return FALSE; -} - -static int -wl_android_ncho_private_command(struct net_device *net, char *command, int total_len) -{ - int bytes_written = 0; - struct bcm_cfg80211 *cfg = wl_get_cfg(net); - - if (cfg->ncho_mode == OFF) { - ANDROID_ERROR(("Disable NCHO mode\n")); - /* In order to avoid Sequential error HANG event. */ - return BCME_UNSUPPORTED; - } - -#ifdef ROAM_API - if (strnicmp(command, CMD_ROAMTRIGGER_SET, strlen(CMD_ROAMTRIGGER_SET)) == 0) { - bytes_written = wl_android_set_roam_trigger(net, command); - } else if (strnicmp(command, CMD_ROAMTRIGGER_GET, strlen(CMD_ROAMTRIGGER_GET)) == 0) { - bytes_written = wl_android_get_roam_trigger(net, command, total_len); - } else if (strnicmp(command, CMD_ROAMDELTA_SET, strlen(CMD_ROAMDELTA_SET)) == 0) { - bytes_written = wl_android_set_roam_delta(net, command); - } else if (strnicmp(command, CMD_ROAMDELTA_GET, strlen(CMD_ROAMDELTA_GET)) == 0) { - bytes_written = wl_android_get_roam_delta(net, command, total_len); - } else if (strnicmp(command, CMD_ROAMSCANPERIOD_SET, - strlen(CMD_ROAMSCANPERIOD_SET)) == 0) { - bytes_written = wl_android_set_roam_scan_period(net, command); - } else if (strnicmp(command, CMD_ROAMSCANPERIOD_GET, - strlen(CMD_ROAMSCANPERIOD_GET)) == 0) { - bytes_written = wl_android_get_roam_scan_period(net, command, total_len); - } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_SET, - strlen(CMD_FULLROAMSCANPERIOD_SET)) == 0) { - bytes_written = wl_android_set_full_roam_scan_period(net, command); - } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_GET, - strlen(CMD_FULLROAMSCANPERIOD_GET)) == 0) { - bytes_written = wl_android_get_full_roam_scan_period(net, command, total_len); - } else if (strnicmp(command, CMD_COUNTRYREV_SET, strlen(CMD_COUNTRYREV_SET)) == 0) { - bytes_written = wl_android_set_country_rev(net, command); -#ifdef FCC_PWR_LIMIT_2G - if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) { - ANDROID_ERROR(("fccpwrlimit2g deactivation is failed\n")); - } else { - ANDROID_ERROR(("fccpwrlimit2g is deactivated\n")); - } -#endif /* FCC_PWR_LIMIT_2G */ - } else if (strnicmp(command, CMD_COUNTRYREV_GET, strlen(CMD_COUNTRYREV_GET)) == 0) { - bytes_written = wl_android_get_country_rev(net, command, total_len); - } else -#endif /* ROAM_API */ - if (strnicmp(command, CMD_GETROAMSCANCONTROL, strlen(CMD_GETROAMSCANCONTROL)) == 0) { - bytes_written = wl_android_get_roam_scan_control(net, command, total_len); - } - else if (strnicmp(command, CMD_SETROAMSCANCONTROL, strlen(CMD_SETROAMSCANCONTROL)) == 0) { - bytes_written = wl_android_set_roam_scan_control(net, command); - } - /* ROAMSCAN CHANNELS Add, Get, Set Command */ - else if (strnicmp(command, CMD_ADDROAMSCANCHANNELS, strlen(CMD_ADDROAMSCANCHANNELS)) == 0) { - bytes_written = wl_android_add_roam_scan_channels(net, command, - strlen(CMD_ADDROAMSCANCHANNELS)); - } - else if (strnicmp(command, CMD_GETROAMSCANCHANNELS, strlen(CMD_GETROAMSCANCHANNELS)) == 0) { - bytes_written = wl_android_get_roam_scan_channels(net, command, total_len, - CMD_GETROAMSCANCHANNELS); - } - else if (strnicmp(command, CMD_SETROAMSCANCHANNELS, strlen(CMD_SETROAMSCANCHANNELS)) == 0) { - bytes_written = wl_android_set_roam_scan_channels(net, command); - } - /* ROAMSCAN FREQUENCIES Add, Get, Set Command */ - else if (strnicmp(command, CMD_ADDROAMSCANFREQS, strlen(CMD_ADDROAMSCANFREQS)) == 0) { - bytes_written = wl_android_add_roam_scan_freqs(net, command, - strlen(CMD_ADDROAMSCANFREQS)); - } - else if (strnicmp(command, CMD_GETROAMSCANFREQS, strlen(CMD_GETROAMSCANFREQS)) == 0) { - bytes_written = wl_android_get_roam_scan_freqs(net, command, total_len, - CMD_GETROAMSCANFREQS); - } - else if (strnicmp(command, CMD_SETROAMSCANFREQS, strlen(CMD_SETROAMSCANFREQS)) == 0) { - bytes_written = wl_android_set_roam_scan_freqs(net, command); - } - else if (strnicmp(command, CMD_SENDACTIONFRAME, strlen(CMD_SENDACTIONFRAME)) == 0) { - bytes_written = wl_android_send_action_frame(net, command, total_len); - } - else if (strnicmp(command, CMD_REASSOC, strlen(CMD_REASSOC)) == 0) { - bytes_written = wl_android_reassoc(net, command, total_len); - } - else if (strnicmp(command, CMD_GETSCANCHANNELTIME, strlen(CMD_GETSCANCHANNELTIME)) == 0) { - bytes_written = wl_android_get_scan_channel_time(net, command, total_len); - } - else if (strnicmp(command, CMD_SETSCANCHANNELTIME, strlen(CMD_SETSCANCHANNELTIME)) == 0) { - bytes_written = wl_android_set_scan_channel_time(net, command); - } - else if (strnicmp(command, CMD_GETSCANUNASSOCTIME, strlen(CMD_GETSCANUNASSOCTIME)) == 0) { - bytes_written = wl_android_get_scan_unassoc_time(net, command, total_len); - } - else if (strnicmp(command, CMD_SETSCANUNASSOCTIME, strlen(CMD_SETSCANUNASSOCTIME)) == 0) { - bytes_written = wl_android_set_scan_unassoc_time(net, command); - } - else if (strnicmp(command, CMD_GETSCANPASSIVETIME, strlen(CMD_GETSCANPASSIVETIME)) == 0) { - bytes_written = wl_android_get_scan_passive_time(net, command, total_len); - } - else if (strnicmp(command, CMD_SETSCANPASSIVETIME, strlen(CMD_SETSCANPASSIVETIME)) == 0) { - bytes_written = wl_android_set_scan_passive_time(net, command); - } - else if (strnicmp(command, CMD_GETSCANHOMETIME, strlen(CMD_GETSCANHOMETIME)) == 0) { - bytes_written = wl_android_get_scan_home_time(net, command, total_len); - } - else if (strnicmp(command, CMD_SETSCANHOMETIME, strlen(CMD_SETSCANHOMETIME)) == 0) { - bytes_written = wl_android_set_scan_home_time(net, command); - } - else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIME, strlen(CMD_GETSCANHOMEAWAYTIME)) == 0) { - bytes_written = wl_android_get_scan_home_away_time(net, command, total_len); - } - else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIME, strlen(CMD_SETSCANHOMEAWAYTIME)) == 0) { - bytes_written = wl_android_set_scan_home_away_time(net, command); - } - else if (strnicmp(command, CMD_GETSCANNPROBES, strlen(CMD_GETSCANNPROBES)) == 0) { - bytes_written = wl_android_get_scan_nprobes(net, command, total_len); - } - else if (strnicmp(command, CMD_SETSCANNPROBES, strlen(CMD_SETSCANNPROBES)) == 0) { - bytes_written = wl_android_set_scan_nprobes(net, command); - } - else if (strnicmp(command, CMD_GETDFSSCANMODE, strlen(CMD_GETDFSSCANMODE)) == 0) { - bytes_written = wl_android_get_scan_dfs_channel_mode(net, command, total_len); - } - else if (strnicmp(command, CMD_SETDFSSCANMODE, strlen(CMD_SETDFSSCANMODE)) == 0) { - bytes_written = wl_android_set_scan_dfs_channel_mode(net, command); - } - else if (strnicmp(command, CMD_SETJOINPREFER, strlen(CMD_SETJOINPREFER)) == 0) { - bytes_written = wl_android_set_join_prefer(net, command); - } - else if (strnicmp(command, CMD_GETWESMODE, strlen(CMD_GETWESMODE)) == 0) { - bytes_written = wl_android_get_wes_mode(net, command, total_len); - } - else if (strnicmp(command, CMD_SETWESMODE, strlen(CMD_SETWESMODE)) == 0) { - bytes_written = wl_android_set_wes_mode(net, command); - } - else { - ANDROID_ERROR(("Unknown NCHO PRIVATE command %s - ignored\n", command)); - bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL"); - } - - return bytes_written; -} -#endif /* WES_SUPPORT */ - -#if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT) -static int -wl_android_default_set_scan_params(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - uint error_cnt = 0; - int cnt = 0; - char restore_command[WLC_IOCTL_SMLEN]; - - while (strlen(restore_params[cnt].command) > 0 && restore_params[cnt].cmd_handler) { - snprintf(restore_command, WLC_IOCTL_SMLEN, "%s %d", - restore_params[cnt].command, restore_params[cnt].parameter); - if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD) { - error = restore_params[cnt].cmd_handler(dev, restore_command); - } else if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD_WITH_LEN) { - error = restore_params[cnt].cmd_handler_w_len(dev, - restore_command, total_len); - } else { - ANDROID_ERROR(("Unknown restore command handler\n")); - error = -1; - } - if (error) { - ANDROID_ERROR(("Failed to restore scan parameters %s, error : %d\n", - restore_command, error)); - error_cnt++; - } - cnt++; - } - if (error_cnt > 0) { - ANDROID_ERROR(("Got %d error(s) while restoring scan parameters\n", - error_cnt)); - error = -1; - } - return error; -} -#endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT */ - -#ifdef WLTDLS -int wl_android_tdls_reset(struct net_device *dev) -{ - int ret = 0; - ret = dhd_tdls_enable(dev, false, false, NULL); - if (ret < 0) { - ANDROID_ERROR(("Disable tdls failed. %d\n", ret)); - return ret; - } - ret = dhd_tdls_enable(dev, true, true, NULL); - if (ret < 0) { - ANDROID_ERROR(("enable tdls failed. %d\n", ret)); - return ret; - } - return 0; -} -#endif /* WLTDLS */ +#endif /* WES_SUPPORT && WBTEXT */ int wl_android_rcroam_turn_on(struct net_device *dev, int rcroam_enab) @@ -3376,38 +1504,38 @@ wl_android_rcroam_turn_on(struct net_device *dev, int rcroam_enab) wlc_rcroam_info_v1_t *rcroam; uint rcroamlen = sizeof(*rcroam) + RCROAM_HDRLEN; - ANDROID_INFO(("RCROAM mode %s\n", rcroam_enab ? "enable" : "disable")); + WL_INFORM(("RCROAM mode %s\n", rcroam_enab ? "enable" : "disable")); prcroam = (wlc_rcroam_t *)MALLOCZ(dhdp->osh, rcroamlen); if (!prcroam) { - ANDROID_ERROR(("Fail to malloc buffer\n")); + WL_ERR(("Fail to malloc buffer\n")); return BCME_NOMEM; } /* Get RCROAM param */ ret = wldev_iovar_getbuf(dev, "rcroam", NULL, 0, prcroam, rcroamlen, NULL); if (ret) { - ANDROID_ERROR(("Failed to get RCROAM info(%d)\n", ret)); + WL_ERR(("Failed to get RCROAM info(%d)\n", ret)); goto done; } - if (prcroam->ver != WLC_RC_ROAM_CUR_VER) { + if (prcroam->ver != WLC_RC_ROAM_VER_1) { ret = BCME_VERSION; - ANDROID_ERROR(("Ver(%d:%d). mismatch RCROAM info(%d)\n", - prcroam->ver, WLC_RC_ROAM_CUR_VER, ret)); + WL_ERR(("Ver(%d:%d). mismatch RCROAM info(%d)\n", + prcroam->ver, WLC_RC_ROAM_VER_1, ret)); goto done; } /* Set RCROAM param */ rcroam = (wlc_rcroam_info_v1_t *)prcroam->data; - prcroam->ver = WLC_RC_ROAM_CUR_VER; + prcroam->ver = WLC_RC_ROAM_VER_1; prcroam->len = sizeof(*rcroam); rcroam->enab = rcroam_enab; ret = wldev_iovar_setbuf(dev, "rcroam", prcroam, rcroamlen, ioctl_buf, sizeof(ioctl_buf), NULL); if (ret) { - ANDROID_ERROR(("Failed to set RCROAM %s(%d)\n", + WL_ERR(("Failed to set RCROAM %s(%d)\n", rcroam_enab ? "Enable" : "Disable", ret)); goto done; } @@ -3419,825 +1547,6 @@ done: return ret; } -#ifdef CONFIG_SILENT_ROAM -int -wl_android_sroam_turn_on(struct net_device *dev, int sroam_mode) -{ - int ret = BCME_OK; - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); - - dhdp->sroam_turn_on = sroam_mode; - ANDROID_INFO(("%s Silent mode %s\n", __FUNCTION__, - sroam_mode ? "enable" : "disable")); - - if (!sroam_mode) { - ret = dhd_sroam_set_mon(dhdp, FALSE); - if (ret) { - ANDROID_ERROR(("%s Failed to Set sroam %d\n", - __FUNCTION__, ret)); - } - } - - return ret; -} - -int -wl_android_sroam_set_info(struct net_device *dev, char *data, - char *command, int total_len) -{ - int ret = BCME_OK; - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); - size_t slen = strlen(data); - u8 ioctl_buf[WLC_IOCTL_SMLEN]; - wlc_sroam_t *psroam; - wlc_sroam_info_t *sroam; - uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN; - - data[slen] = '\0'; - psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen); - if (!psroam) { - ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__)); - ret = BCME_NOMEM; - goto done; - } - - psroam->ver = WLC_SILENT_ROAM_CUR_VER; - psroam->len = sizeof(*sroam); - sroam = (wlc_sroam_info_t *)psroam->data; - - sroam->sroam_on = FALSE; - if (*data && *data != '\0') { - sroam->sroam_min_rssi = simple_strtol(data, &data, 10); - ANDROID_INFO(("1.Minimum RSSI %d\n", sroam->sroam_min_rssi)); - data++; - } - if (*data && *data != '\0') { - sroam->sroam_rssi_range = simple_strtol(data, &data, 10); - ANDROID_INFO(("2.RSSI Range %d\n", sroam->sroam_rssi_range)); - data++; - } - if (*data && *data != '\0') { - sroam->sroam_score_delta = simple_strtol(data, &data, 10); - ANDROID_INFO(("3.Score Delta %d\n", sroam->sroam_score_delta)); - data++; - } - if (*data && *data != '\0') { - sroam->sroam_period_time = simple_strtol(data, &data, 10); - ANDROID_INFO(("4.Sroam period %d\n", sroam->sroam_period_time)); - data++; - } - if (*data && *data != '\0') { - sroam->sroam_band = simple_strtol(data, &data, 10); - ANDROID_INFO(("5.Sroam Band %d\n", sroam->sroam_band)); - data++; - } - if (*data && *data != '\0') { - sroam->sroam_inact_cnt = simple_strtol(data, &data, 10); - ANDROID_INFO(("6.Inactivity Count %d\n", sroam->sroam_inact_cnt)); - data++; - } - - if (*data != '\0') { - ret = BCME_BADARG; - goto done; - } - - ret = wldev_iovar_setbuf(dev, "sroam", psroam, sroamlen, ioctl_buf, - sizeof(ioctl_buf), NULL); - if (ret) { - ANDROID_ERROR(("Failed to set silent roam info(%d)\n", ret)); - goto done; - } -done: - if (psroam) { - MFREE(dhdp->osh, psroam, sroamlen); - } - - return ret; -} - -int -wl_android_sroam_get_info(struct net_device *dev, char *command, int total_len) -{ - int ret = BCME_OK; - int bytes_written = 0; - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); - wlc_sroam_t *psroam; - wlc_sroam_info_t *sroam; - uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN; - - psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen); - if (!psroam) { - ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__)); - ret = BCME_NOMEM; - goto done; - } - - ret = wldev_iovar_getbuf(dev, "sroam", NULL, 0, psroam, sroamlen, NULL); - if (ret) { - ANDROID_ERROR(("Failed to get silent roam info(%d)\n", ret)); - goto done; - } - - if (psroam->ver != WLC_SILENT_ROAM_CUR_VER) { - ret = BCME_VERSION; - ANDROID_ERROR(("Ver(%d:%d). mismatch silent roam info(%d)\n", - psroam->ver, WLC_SILENT_ROAM_CUR_VER, ret)); - goto done; - } - - sroam = (wlc_sroam_info_t *)psroam->data; - bytes_written = snprintf(command, total_len, - "%s %d %d %d %d %d %d %d\n", - CMD_SROAM_GET_INFO, sroam->sroam_on, sroam->sroam_min_rssi, sroam->sroam_rssi_range, - sroam->sroam_score_delta, sroam->sroam_period_time, sroam->sroam_band, - sroam->sroam_inact_cnt); - ret = bytes_written; - - ANDROID_INFO(("%s", command)); -done: - if (psroam) { - MFREE(dhdp->osh, psroam, sroamlen); - } - - return ret; -} -#endif /* CONFIG_SILENT_ROAM */ - -int -wl_android_priority_roam_enable(struct net_device *dev, int mode) -{ - int error = BCME_OK; - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); - u8 ioctl_buf[WLC_IOCTL_SMLEN]; - wl_prio_roam_prof_v1_t *prio_roam; - uint buf_len = sizeof(wl_prio_roam_prof_v1_t) + (uint)strlen("priority_roam") + 1; - - prio_roam = (wl_prio_roam_prof_v1_t *)MALLOCZ(dhdp->osh, buf_len); - if (!prio_roam) { - ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__)); - error = BCME_NOMEM; - goto done; - } - - error = wldev_iovar_getbuf(dev, "priority_roam", NULL, 0, prio_roam, buf_len, NULL); - if (error == BCME_UNSUPPORTED) { - ANDROID_ERROR(("Priority Roam Unsupport\n")); - error = BCME_OK; - goto done; - } else if (prio_roam->version != WL_PRIO_ROAM_PROF_V1) { - ANDROID_ERROR(("Priority Roam Version mismatch\n")); - goto done; - } else if (prio_roam->prio_roam_mode == mode) { - ANDROID_INFO(("Priority Roam already set(mode:%d)\n", mode)); - goto done; - } - - prio_roam->version = WL_PRIO_ROAM_PROF_V1; - prio_roam->length = sizeof(wl_prio_roam_prof_v1_t); - prio_roam->prio_roam_mode = mode; - - error = wldev_iovar_setbuf(dev, "priority_roam", prio_roam, - sizeof(wl_prio_roam_prof_v1_t), ioctl_buf, sizeof(ioctl_buf), NULL); - if (error) { - ANDROID_ERROR(("Failed to set Priority Roam %s(%d)\n", - mode ? "Enable" : "Disable", error)); - goto done; - } -done: - if (prio_roam) { - MFREE(dhdp->osh, prio_roam, sizeof(wl_prio_roam_prof_v1_t)); - } - - return error; -} - -#ifdef CONFIG_ROAM_RSSI_LIMIT -int -wl_android_roam_rssi_limit(struct net_device *dev, char *command, int total_len) -{ - int ret = BCME_OK; - int argc, bytes_written = 0; - int lmt2g, lmt5g; - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); - - argc = sscanf(command, CMD_ROAM_RSSI_LMT " %d %d\n", &lmt2g, &lmt5g); - - if (!argc) { - ret = dhd_roam_rssi_limit_get(dhdp, &lmt2g, &lmt5g); - if (ret) { - ANDROID_ERROR(("Failed to Get roam_rssi_limit (%d)\n", ret)); - return ret; - } - bytes_written = snprintf(command, total_len, "%d, %d\n", lmt2g, lmt5g); - /* Get roam rssi limit */ - return bytes_written; - } else { - /* Set roam rssi limit */ - ret = dhd_roam_rssi_limit_set(dhdp, lmt2g, lmt5g); - if (ret) { - ANDROID_ERROR(("Failed to Set roam_rssi_limit (%d)\n", ret)); - return ret; - } - } - - return ret; -} -#endif /* CONFIG_ROAM_RSSI_LIMIT */ - -#ifdef CONFIG_ROAM_MIN_DELTA -int -wl_android_roam_min_delta(struct net_device *dev, char *command, int total_len) -{ - int ret = BCME_OK; - int argc, bytes_written = 0; - uint32 delta2g = 0, delta5g = 0, delta = 0; - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); - - argc = sscanf(command, CMD_ROAM_MIN_DELTA " %d\n", &delta); - - if (!argc) { - /* Get Minimum ROAM score delta */ - ret = dhd_roam_min_delta_get(dhdp, &delta2g, &delta5g); - if (ret) { - ANDROID_ERROR(("Failed to Get roam_min_delta (%d)\n", ret)); - return ret; - } - bytes_written = snprintf(command, total_len, "%d, %d\n", delta2g, delta5g); - return bytes_written; - } else { - /* Set Minimum ROAM score delta - * Framework set one parameter # wpa_cli driver ROAMMINSCOREDELTA - */ - ret = dhd_roam_min_delta_set(dhdp, delta, delta); - if (ret) { - ANDROID_ERROR(("Failed to Set roam_min_delta (%d)\n", ret)); - return ret; - } - } - - return ret; -} -#endif /* CONFIG_ROAM_MIN_DELTA */ - -static int -get_int_bytes(uchar *oui_str, uchar *oui, int len) -{ - int idx; - uchar val; - uchar *src, *dest; - char hexstr[3]; - - if ((oui_str == NULL) || (oui == NULL) || (len == 0)) { - return BCME_BADARG; - } - src = oui_str; - dest = oui; - - for (idx = 0; idx < len; idx++) { - if (*src == '\0') { - *dest = '\0'; - break; - } - hexstr[0] = src[0]; - hexstr[1] = src[1]; - hexstr[2] = '\0'; - - val = (uchar)bcm_strtoul(hexstr, NULL, 16); - if (val == (uchar)-1) { - return BCME_ERROR; - } - *dest++ = val; - src += 2; - } - return BCME_OK; -} - -#define TAG_BYTE 0 -static int -wl_android_set_disconnect_ies(struct net_device *dev, char *command) -{ - int cmd_prefix_len = 0; - char ie_len = 0; - int hex_ie_len = 0; - int total_len = 0; - int max_len = 0; - int cmd_len = 0; - uchar disassoc_ie[VNDR_IE_MAX_LEN] = {0}; - s32 bssidx = 0; - struct bcm_cfg80211 *cfg = NULL; - s32 ret = 0; - cfg = wl_get_cfg(dev); - - cmd_prefix_len = strlen("SET_DISCONNECT_IES "); - cmd_len = strlen(command); - /* - * + - * IES in hex format has to be in following format - * First byte = Tag, Second Byte = len and rest of - * bytes will be value. For ex: SET_DISCONNECT_IES dd0411223344 - * tag = dd, len =04. Total IEs len = len + 2 - */ - ANDROID_INFO(("cmd recv = %s\n", command)); - max_len = MIN(cmd_len, VNDR_IE_MAX_LEN); - /* Validate IEs len */ - get_int_bytes(&command[cmd_prefix_len + 2], &ie_len, 1); - ANDROID_INFO(("ie_len = %d \n", ie_len)); - if (ie_len <= 0 || ie_len > max_len) { - ret = BCME_BADLEN; - return ret; - } - - /* Total len in hex is sum of double binary len, tag and len byte */ - hex_ie_len = (ie_len * 2) + 4; - total_len = cmd_prefix_len + hex_ie_len; - if (command[total_len] != '\0' || (cmd_len != total_len)) { - ANDROID_ERROR(("command recv not matching with len, command = %s" - "total_len = %d, cmd_len = %d\n", command, total_len, cmd_len)); - ret = BCME_BADARG; - return ret; - } - - if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { - ANDROID_ERROR(("Find index failed\n")); - ret = -EINVAL; - return ret; - } - - /* Tag and len bytes are also part of total len of ies in binary */ - ie_len = ie_len + 2; - /* Convert IEs in binary */ - get_int_bytes(&command[cmd_prefix_len], disassoc_ie, ie_len); - if (disassoc_ie[TAG_BYTE] != 0xdd) { - ANDROID_ERROR(("Wrong tag recv, tag = 0x%02x\n", disassoc_ie[TAG_BYTE])); - ret = BCME_UNSUPPORTED; - return ret; - } - - ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, - ndev_to_cfgdev(dev), bssidx, VNDR_IE_DISASSOC_FLAG, disassoc_ie, ie_len); - - return ret; -} - -#ifdef FCC_PWR_LIMIT_2G -int -wl_android_set_fcc_pwr_limit_2g(struct net_device *dev, char *command) -{ - int error = 0; - int enable = 0; - - sscanf(command+sizeof("SET_FCC_CHANNEL"), "%d", &enable); - - if ((enable != CUSTOMER_HW4_ENABLE) && (enable != CUSTOMER_HW4_DISABLE)) { - ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: Invalid data\n")); - return BCME_ERROR; - } - - CUSTOMER_HW4_EN_CONVERT(enable); - - ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g set (%d)\n", enable)); - error = wldev_iovar_setint(dev, "fccpwrlimit2g", enable); - if (error) { - ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g" - " set returned (%d)\n", error)); - return BCME_ERROR; - } - - return error; -} - -int -wl_android_get_fcc_pwr_limit_2g(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - int enable = 0; - int bytes_written = 0; - - error = wldev_iovar_getint(dev, "fccpwrlimit2g", &enable); - if (error) { - ANDROID_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get" - " error (%d)\n", error)); - return BCME_ERROR; - } - ANDROID_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get (%d)\n", enable)); - - bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_FCC_PWR_LIMIT_2G, enable); - - return bytes_written; -} -#endif /* FCC_PWR_LIMIT_2G */ - -/* Additional format of sta_info - * tx_pkts, tx_failures, tx_rate(kbps), rssi(main), rssi(aux), tx_pkts_retried, - * tx_pkts_retry_exhausted, rx_lastpkt_rssi(main), rx_lastpkt_rssi(aux), - * tx_pkts_total, tx_pkts_retries, tx_pkts_fw_total, tx_pkts_fw_retries, - * tx_pkts_fw_retry_exhausted - */ -#define STA_INFO_ADD_FMT "%d %d %d %d %d %d %d %d %d %d %d %d %d %d" - -#ifdef BIGDATA_SOFTAP -#define BIGDATA_SOFTAP_FMT MACOUI " %d %s %d %d %d %d %d %d" -#endif /* BIGDATA_SOFTAP */ - -#define STAINFO_BAND_2G 0x0001 -#define STAINFO_BAND_5G 0x0002 -#define STAINFO_BAND_6G 0x0004 -#define STAINFO_BAND_60G 0x0008 -s32 -wl_cfg80211_get_sta_info(struct net_device *dev, char* command, int total_len) -{ - int bytes_written = -1, ret = 0; - char *pos, *token, *cmdstr; - bool is_macaddr = FALSE; - sta_info_v4_t *sta = NULL; - struct ether_addr mac; - char *iovar_buf = NULL; - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - struct net_device *apdev = NULL; -#ifdef BCMDONGLEHOST - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); -#endif /* BCMDONGLEHOST */ - -#ifdef BIGDATA_SOFTAP - void *data = NULL; - wl_ap_sta_data_t *sta_data = NULL; -#endif /* BIGDATA_SOFTAP */ - - /* Client information */ - uint16 cap = 0; - uint32 rxrtry = 0, rxmulti = 0; - uint32 tx_pkts = 0, tx_failures = 0, tx_rate = 0; - uint32 tx_pkts_retried = 0, tx_pkts_retry_exhausted = 0; - uint32 tx_pkts_total = 0, tx_pkts_retries = 0; - uint32 tx_pkts_fw_total = 0, tx_pkts_fw_retries = 0; - uint32 tx_pkts_fw_retry_exhausted = 0; - int8 rssi[WL_STA_ANT_MAX] = {0}; - int8 rx_lastpkt_rssi[WL_STA_ANT_MAX] = {0}; - wl_if_stats_t *if_stats = NULL; - u16 bands = 0; - u32 sta_flags = 0; - char mac_buf[MAX_NUM_OF_ASSOCLIST * - sizeof(struct ether_addr) + sizeof(uint)] = {0}; - struct maclist *assoc_maclist = (struct maclist *)mac_buf; - - BCM_REFERENCE(if_stats); - /* This Command used during only SoftAP mode. */ - ANDROID_INFO(("%s\n", command)); - - /* Check the current op_mode */ - if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) { - ANDROID_ERROR(("unsupported op mode: %d\n", dhdp->op_mode)); - return BCME_NOTAP; - } - - /* - * DRIVER GETSTAINFO [client MAC or ALL] [ifname] - */ - pos = command; - - /* drop command */ - token = bcmstrtok(&pos, " ", NULL); - - /* Client MAC or ALL */ - token = bcmstrtok(&pos, " ", NULL); - if (!token) { - ANDROID_ERROR(("GETSTAINFO subcmd not provided wl_cfg80211_get_sta_info\n")); - return -EINVAL; - } - cmdstr = token; - - bzero(&mac, ETHER_ADDR_LEN); - if ((!strncmp(token, "all", 3)) || (!strncmp(token, "ALL", 3))) { - is_macaddr = FALSE; - } else if ((bcm_ether_atoe(token, &mac))) { - is_macaddr = TRUE; - } else { - ANDROID_ERROR(("Failed to get address\n")); - return -EINVAL; - } - - /* get the interface name */ - token = bcmstrtok(&pos, " ", NULL); - if (!token) { - /* assign requested dev for compatibility */ - apdev = dev; - } else { - /* Find a net_device for SoftAP by interface name */ - apdev = wl_get_ap_netdev(cfg, token); - if (!apdev) { - ANDROID_ERROR(("cannot find a net_device for SoftAP\n")); - return -EINVAL; - } - } - - iovar_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN); - if (!iovar_buf) { - ANDROID_ERROR(("Failed to allocated memory %d bytes\n", - WLC_IOCTL_MAXLEN)); - return BCME_NOMEM; - } - - if (is_macaddr) { - int cnt; - - /* get the sta info */ - ret = wldev_iovar_getbuf(apdev, "sta_info", - (struct ether_addr *)mac.octet, ETHER_ADDR_LEN, - iovar_buf, WLC_IOCTL_MAXLEN, NULL); - if (ret < 0) { - ANDROID_ERROR(("Get sta_info ERR %d\n", ret)); - -#ifdef BIGDATA_SOFTAP - /* Customer wants to send basic client information - * to the framework even if DHD cannot get the sta_info. - */ - goto get_bigdata; -#endif /* BIGDATA_SOFTAP */ - -#ifndef BIGDATA_SOFTAP - goto error; -#endif /* BIGDATA_SOFTAP */ - } - - sta = (sta_info_v4_t *)iovar_buf; - if (dtoh16(sta->ver) != WL_STA_VER_4) { - ANDROID_ERROR(("sta_info struct version mismatch, " - "host ver : %d, fw ver : %d\n", WL_STA_VER_4, - dtoh16(sta->ver))); - -#ifdef BIGDATA_SOFTAP - /* Customer wants to send basic client information - * to the framework even if DHD cannot get the sta_info. - */ - goto get_bigdata; -#endif /* BIGDATA_SOFTAP */ - -#ifndef BIGDATA_SOFTAP - goto error; -#endif /* BIGDATA_SOFTAP */ - } - cap = dtoh16(sta->cap); - rxrtry = dtoh32(sta->rx_pkts_retried); - rxmulti = dtoh32(sta->rx_mcast_pkts); - tx_pkts = dtoh32(sta->tx_pkts); - tx_failures = dtoh32(sta->tx_failures); - tx_rate = dtoh32(sta->tx_rate); - tx_pkts_retried = dtoh32(sta->tx_pkts_retried); - tx_pkts_retry_exhausted = dtoh32(sta->tx_pkts_retry_exhausted); - tx_pkts_total = dtoh32(sta->tx_pkts_total); - tx_pkts_retries = dtoh32(sta->tx_pkts_retries); - tx_pkts_fw_total = dtoh32(sta->tx_pkts_fw_total); - tx_pkts_fw_retries = dtoh32(sta->tx_pkts_fw_retries); - tx_pkts_fw_retry_exhausted = dtoh32(sta->tx_pkts_fw_retry_exhausted); - sta_flags = dtoh32(sta->flags); - if (sta_flags & WL_STA_IS_2G) { - bands |= STAINFO_BAND_2G; - } - if (sta_flags & WL_STA_IS_5G) { - bands |= STAINFO_BAND_5G; - } - if (sta_flags & WL_STA_IS_6G) { - bands |= STAINFO_BAND_6G; - } - for (cnt = WL_ANT_IDX_1; cnt < WL_RSSI_ANT_MAX; cnt++) { - rssi[cnt] = sta->rssi[cnt]; - rx_lastpkt_rssi[cnt] = sta->rx_lastpkt_rssi[cnt]; - } - } else { - int i; - - /* Check if there is an associated STA or not */ - assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST); - ret = wldev_ioctl_get(apdev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf)); - - if (ret < 0) { - ANDROID_ERROR(("Fail to get assoc list: %d\n", ret)); - goto error; - } - - assoc_maclist->count = dtoh32(assoc_maclist->count); - ANDROID_INFO(("Assoc count : %d\n", assoc_maclist->count)); - - for (i = 0; i < assoc_maclist->count; i++) { - /* get the sta info */ - ret = wldev_iovar_getbuf(apdev, "sta_info", - (struct ether_addr *)assoc_maclist->ea[i].octet, ETHER_ADDR_LEN, - iovar_buf, WLC_IOCTL_MAXLEN, NULL); - - if (ret < 0) { - ANDROID_ERROR(("sta_info err : %d", ret)); - continue; - } - sta = (sta_info_v4_t *)iovar_buf; - if (dtoh16(sta->ver) == WL_STA_VER_4) { - rxrtry += dtoh32(sta->rx_pkts_retried); - rxmulti += dtoh32(sta->rx_mcast_pkts); - tx_pkts += dtoh32(sta->tx_pkts); - tx_failures += dtoh32(sta->tx_failures); - tx_pkts_total += dtoh32(sta->tx_pkts_total); - tx_pkts_retries += dtoh32(sta->tx_pkts_retries); - tx_pkts_fw_total += dtoh32(sta->tx_pkts_fw_total); - tx_pkts_fw_retries += dtoh32(sta->tx_pkts_fw_retries); - tx_pkts_fw_retry_exhausted += - dtoh32(sta->tx_pkts_fw_retry_exhausted); - } - } - } - -#ifdef BIGDATA_SOFTAP -get_bigdata: - - if (is_macaddr && wl_get_ap_stadata(cfg, &mac, &data) == BCME_OK) { - ANDROID_ERROR(("mac " MACDBG" \n", MAC2STRDBG((char*)&mac))); - sta_data = (wl_ap_sta_data_t *)data; -#ifdef STAINFO_LEGACY - bytes_written = snprintf(command, total_len, - "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d " - "CAP=%04x " BIGDATA_SOFTAP_FMT " " STA_INFO_ADD_FMT - "\n", CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap, - MACOUI2STR((char*)&sta_data->mac), - sta_data->channel, wf_chspec_to_bw_str(sta_data->chanspec), - sta_data->rssi, sta_data->rate, sta_data->mode_80211, - sta_data->nss, sta_data->mimo, sta_data->reason_code, - tx_pkts, tx_failures, tx_rate, - (int32)rssi[WL_ANT_IDX_1], (int32)rssi[WL_ANT_IDX_2], - tx_pkts_retried, tx_pkts_retry_exhausted, - (int32)rx_lastpkt_rssi[WL_ANT_IDX_1], - (int32)rx_lastpkt_rssi[WL_ANT_IDX_2], - tx_pkts_total, tx_pkts_retries, tx_pkts_fw_total, - tx_pkts_fw_retries, tx_pkts_fw_retry_exhausted); -#else - bytes_written = snprintf(command, total_len, - "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d " - "CAP=%04x " BIGDATA_SOFTAP_FMT " %d\n", - CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap, - MACOUI2STR((char*)&sta_data->mac), - sta_data->channel, wf_chspec_to_bw_str(sta_data->chanspec), - sta_data->rssi, sta_data->rate, sta_data->mode_80211, - sta_data->nss, sta_data->mimo, sta_data->reason_code, bands); -#endif /* STAINFO_LEGACY */ - } else -#endif /* BIGDATA_SOFTAP */ - { - ANDROID_ERROR(("ALL\n")); - bytes_written = snprintf(command, total_len, - "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d CAP=%04x " - STA_INFO_ADD_FMT "\n", CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap, - tx_pkts, tx_failures, tx_rate, (int32)rssi[WL_ANT_IDX_1], - (int32)rssi[WL_ANT_IDX_2], tx_pkts_retried, - tx_pkts_retry_exhausted, (int32)rx_lastpkt_rssi[WL_ANT_IDX_1], - (int32)rx_lastpkt_rssi[WL_ANT_IDX_2], tx_pkts_total, - tx_pkts_retries, tx_pkts_fw_total, tx_pkts_fw_retries, - tx_pkts_fw_retry_exhausted); - } - WL_ERR_KERN(("Command: %s", command)); - -error: - if (iovar_buf) { - MFREE(cfg->osh, iovar_buf, WLC_IOCTL_MAXLEN); - } - if (if_stats) { - MFREE(cfg->osh, if_stats, sizeof(*if_stats)); - } - - return bytes_written; -} - -#ifdef WL_WTC -/* - * CMD Format - * Enable format for 3 band and 2 band respectively: - * DRIVER SETWTCMODE - * DRIVER SETWTCMODE 0 1 -80 -70 -65 -60 - * DRIVER SETWTCMODE - * DRIVER SETWTCMODE 0 1 -80 -70 -65 - * Disable format for 3 band and 2 band respectively: - * DRIVER SETWTCMODE 1 0 0 0 0 0 - * DRIVER SETWTCMODE 1 0 0 0 0 - */ -#define WL_TRIBAND 3 -#define WL_DUALBAND 2 - -/* For WTC disable, any value >= 1 */ -#define WL_WTC_ENABLE 0 -static int -wl_android_wtc_config(struct net_device *dev, char *command, int total_len) -{ - s32 bw; - char *token, *pos; - wlc_wtc_args_t *wtc_params; - wlc_wtcconfig_info_v1_t *wtc_config; - u32 i, wtc_paramslen, maxbands = WL_DUALBAND; - u8 buf[WLC_IOCTL_SMLEN] = {0}; - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - - WL_DBG_MEM(("Enter. cmd:%s\n", command)); -#ifdef WL_6G_BAND - if (cfg->band_6g_supported) { - maxbands = WL_TRIBAND; - } -#endif /* WL_6G_BAND */ - wtc_paramslen = sizeof(wlc_wtcconfig_info_v1_t) + WLC_WTC_ROAM_CONFIG_HDRLEN; - wtc_params = (wlc_wtc_args_t*)MALLOCZ(cfg->osh, wtc_paramslen); - if (!wtc_params) { - ANDROID_ERROR(("Error allocating wtc_params\n")); - return -ENOMEM; - } - - wtc_config = (wlc_wtcconfig_info_v1_t *)wtc_params->data; - /* Get wtc config information and check version compatibility */ - bw = wldev_iovar_getbuf(dev, "wnm_wbtext_wtc_config", - (char*)&wtc_params, wtc_paramslen, buf, WLC_IOCTL_SMLEN, 0); - if (bw) { - ANDROID_ERROR(("Error querying wnm_wbtext_wtc_config: %d\n", bw)); - goto exit; - } - - (void)memcpy_s(wtc_params, wtc_paramslen, buf, wtc_paramslen); - if (wtc_params->ver != WLC_WTC_ROAM_VER_1) { - ANDROID_ERROR(("Wrong version:%d\n", wtc_params->ver)); - bw = -EINVAL; - goto exit; - } - - if (wtc_params->len != sizeof(wlc_wtcconfig_info_v1_t)) { - ANDROID_ERROR(("Bad len\n")); - bw = -EINVAL; - goto exit; - } - - if (strlen(command) == strlen(CMD_WTC_CONFIG)) { - /* No additional arguments given. GET case */ - bw += scnprintf(command, (total_len - bw), "%u %u", - wtc_config->mode, wtc_config->scantype); - bw += scnprintf(command + bw, (total_len - bw), " %d", - wtc_config->rssithresh[0]); - for (i = 0; i < maxbands; i++) { - bw += scnprintf(command + bw, (total_len - bw), " %d", - wtc_config->ap_rssithresh[i]); - } - bw += scnprintf(command + bw, (total_len - bw), "\n"); - } else { - /* SET */ - pos = command + sizeof(CMD_WTC_CONFIG); - - /* mode */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("No mode present\n")); - bw = -EINVAL; - goto exit; - } - wtc_config->mode = (u8)bcm_atoi(token); - - /* scantype */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("No scantype present\n")); - bw = -EINVAL; - goto exit; - } - wtc_config->scantype = (u8)bcm_atoi(token); - - /* rssithreshold */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("Invalid arg for rssi threshold\n")); - bw = -EINVAL; - goto exit; - } - for (i = 0; i < maxbands; i++) { - wtc_config->rssithresh[i] = (s8)bcm_atoi(token); - } - - /* AP rssithreshold */ - for (i = 0; i < maxbands; i++) { - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("Invalid arg for ap threshold\n")); - bw = -EINVAL; - goto exit; - } - wtc_config->ap_rssithresh[i] = (s8)bcm_atoi(token); - } - - bw = wldev_iovar_setbuf(dev, "wnm_wbtext_wtc_config", - (char*)wtc_params, wtc_paramslen, buf, WLC_IOCTL_SMLEN, NULL); - if (bw) { - ANDROID_ERROR(("wtc config set failed. ret:%d\n", bw)); - } - } - -exit: - if (wtc_params) { - MFREE(cfg->osh, wtc_params, wtc_paramslen); - } - return bw; -} -#endif /* WL_WTC */ -#endif /* CUSTOMER_HW4_PRIVATE_CMD */ - #ifdef WBTEXT static int wl_android_wbtext(struct net_device *dev, char *command, int total_len) { @@ -4250,7 +1559,7 @@ static int wl_android_wbtext(struct net_device *dev, char *command, int total_le if (!argc) { error = wldev_iovar_getint(dev, "wnm_bsstrans_resp", &data); if (error) { - ANDROID_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n", + DHD_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n", error)); return error; } @@ -4264,7 +1573,7 @@ static int wl_android_wbtext(struct net_device *dev, char *command, int total_le } if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_resp", data)) != BCME_OK) { - ANDROID_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n", + DHD_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n", error)); return error; } @@ -4280,7 +1589,7 @@ static int wl_android_wbtext(struct net_device *dev, char *command, int total_le roam_trigger[1] = WLC_BAND_ALL; if ((error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger))) != BCME_OK) { - ANDROID_ERROR(("wl_android_wbtext: Failed to reset roam trigger = %d\n", + DHD_ERROR(("wl_android_wbtext: Failed to reset roam trigger = %d\n", error)); return error; } @@ -4290,6 +1599,7 @@ static int wl_android_wbtext(struct net_device *dev, char *command, int total_le return error; } +#ifdef WES_SUPPORT static int wl_android_wbtext_enable(struct net_device *dev, int mode) { @@ -4301,13 +1611,14 @@ wl_android_wbtext_enable(struct net_device *dev, int mode) snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE %d", mode); error = wl_android_wbtext(dev, commandp, WLC_IOCTL_SMLEN); if (error) { - ANDROID_ERROR(("Failed to set WBTEXT = %d\n", error)); + WL_ERR(("Failed to set WBTEXT = %d\n", error)); return error; } } return error; } +#endif /* WES_SUPPORT */ static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev, char *command, int total_len) @@ -4319,7 +1630,7 @@ static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev, if (!argc) { error = wldev_iovar_getint(dev, "wnm_bsstrans_timer_threshold", &data); if (error) { - ANDROID_ERROR(("Failed to get wnm_bsstrans_timer_threshold (%d)\n", error)); + WL_ERR(("Failed to get wnm_bsstrans_timer_threshold (%d)\n", error)); return error; } bytes_written = snprintf(command, total_len, "%d\n", data); @@ -4327,7 +1638,7 @@ static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev, } else { if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_timer_threshold", data)) != BCME_OK) { - ANDROID_ERROR(("Failed to set wnm_bsstrans_timer_threshold (%d)\n", error)); + WL_ERR(("Failed to set wnm_bsstrans_timer_threshold (%d)\n", error)); return error; } } @@ -4344,7 +1655,7 @@ static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev, if (!argc) { error = wldev_iovar_getint(dev, "wnm_btmdelta", &data); if (error) { - ANDROID_ERROR(("Failed to get wnm_btmdelta (%d)\n", error)); + WL_ERR(("Failed to get wnm_btmdelta (%d)\n", error)); return error; } bytes_written = snprintf(command, total_len, "%d\n", data); @@ -4352,7 +1663,7 @@ static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev, } else { if ((error = wldev_iovar_setint(dev, "wnm_btmdelta", data)) != BCME_OK) { - ANDROID_ERROR(("Failed to set wnm_btmdelta (%d)\n", error)); + WL_ERR(("Failed to set wnm_btmdelta (%d)\n", error)); return error; } } @@ -4371,10 +1682,10 @@ static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev, error = wldev_iovar_getint(dev, "wnm", &wnmmask); if (error) { - ANDROID_ERROR(("Failed to get wnm_btmdelta (%d)\n", error)); + WL_ERR(("Failed to get wnm_btmdelta (%d)\n", error)); return error; } - ANDROID_INFO(("wnmmask %x\n", wnmmask)); + WL_DBG(("wnmmask %x\n", wnmmask)); if (*pcmd == WL_IOCTL_ACTION_GET) { bytes_written = snprintf(command, total_len, "wbtext_estm_enable %d\n", (wnmmask & WL_WNM_ESTM) ? 1:0); @@ -4386,9 +1697,9 @@ static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev, } else { wnmmask |= WL_WNM_ESTM; } - ANDROID_INFO(("wnmmask %x\n", wnmmask)); + WL_DBG(("wnmmask %x\n", wnmmask)); if ((error = wldev_iovar_setint(dev, "wnm", wnmmask)) != BCME_OK) { - ANDROID_ERROR(("Failed to set wnm mask (%d)\n", error)); + WL_ERR(("Failed to set wnm mask (%d)\n", error)); return error; } } @@ -4409,13 +1720,13 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1]; struct dhd_pno_batch_params batch_params; - ANDROID_INFO(("wls_parse_batching_cmd: command=%s, len=%d\n", command, total_len)); + DHD_PNO(("wls_parse_batching_cmd: command=%s, len=%d\n", command, total_len)); len_remain = total_len; if (len_remain > (strlen(CMD_WLS_BATCHING) + 1)) { pos = command + strlen(CMD_WLS_BATCHING) + 1; len_remain -= strlen(CMD_WLS_BATCHING) + 1; } else { - ANDROID_ERROR(("wls_parse_batching_cmd: No arguments, total_len %d\n", total_len)); + WL_ERR(("wls_parse_batching_cmd: No arguments, total_len %d\n", total_len)); err = BCME_ERROR; goto exit; } @@ -4424,7 +1735,7 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) if (len_remain > (strlen(PNO_BATCHING_SET) + 1)) { pos += strlen(PNO_BATCHING_SET) + 1; } else { - ANDROID_ERROR(("wls_parse_batching_cmd: %s missing arguments, total_len %d\n", + WL_ERR(("wls_parse_batching_cmd: %s missing arguments, total_len %d\n", PNO_BATCHING_SET, total_len)); err = BCME_ERROR; goto exit; @@ -4443,20 +1754,20 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) tokens = sscanf(token, LIMIT_STR_FMT, param, value); if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) { batch_params.scan_fr = simple_strtol(value, NULL, 0); - ANDROID_INFO(("scan_freq : %d\n", batch_params.scan_fr)); + DHD_PNO(("scan_freq : %d\n", batch_params.scan_fr)); } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) { batch_params.bestn = simple_strtol(value, NULL, 0); - ANDROID_INFO(("bestn : %d\n", batch_params.bestn)); + DHD_PNO(("bestn : %d\n", batch_params.bestn)); } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) { batch_params.mscan = simple_strtol(value, NULL, 0); - ANDROID_INFO(("mscan : %d\n", batch_params.mscan)); + DHD_PNO(("mscan : %d\n", batch_params.mscan)); } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) { i = 0; pos2 = value; tokens = sscanf(value, "<%s>", value); if (tokens != 1) { err = BCME_ERROR; - ANDROID_ERROR(("wls_parse_batching_cmd: invalid format" + DHD_ERROR(("wls_parse_batching_cmd: invalid format" " for channel" " <> params\n")); goto exit; @@ -4470,12 +1781,12 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) if (*token2 == 'A' || *token2 == 'B') { batch_params.band = (*token2 == 'A')? WLC_BAND_5G : WLC_BAND_2G; - ANDROID_INFO(("band : %s\n", + DHD_PNO(("band : %s\n", (*token2 == 'A')? "A" : "B")); } else { if ((batch_params.nchan >= WL_NUMCHANNELS) || (i >= WL_NUMCHANNELS)) { - ANDROID_ERROR(("Too many nchan %d\n", + DHD_ERROR(("Too many nchan %d\n", batch_params.nchan)); err = BCME_BUFTOOSHORT; goto exit; @@ -4483,22 +1794,22 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) batch_params.chan_list[i++] = simple_strtol(token2, NULL, 0); batch_params.nchan++; - ANDROID_INFO(("channel :%d\n", + DHD_PNO(("channel :%d\n", batch_params.chan_list[i-1])); } } } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) { batch_params.rtt = simple_strtol(value, NULL, 0); - ANDROID_INFO(("rtt : %d\n", batch_params.rtt)); + DHD_PNO(("rtt : %d\n", batch_params.rtt)); } else { - ANDROID_ERROR(("wls_parse_batching_cmd : unknown param: %s\n", param)); + DHD_ERROR(("wls_parse_batching_cmd : unknown param: %s\n", param)); err = BCME_ERROR; goto exit; } } err = dhd_dev_pno_set_for_batch(dev, &batch_params); if (err < 0) { - ANDROID_ERROR(("failed to configure batch scan\n")); + DHD_ERROR(("failed to configure batch scan\n")); } else { bzero(command, total_len); err = snprintf(command, total_len, "%d", err); @@ -4506,20 +1817,20 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) { err = dhd_dev_pno_get_for_batch(dev, command, total_len); if (err < 0) { - ANDROID_ERROR(("failed to getting batching results\n")); + DHD_ERROR(("failed to getting batching results\n")); } else { err = strlen(command); } } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) { err = dhd_dev_pno_stop_for_batch(dev); if (err < 0) { - ANDROID_ERROR(("failed to stop batching scan\n")); + DHD_ERROR(("failed to stop batching scan\n")); } else { bzero(command, total_len); err = snprintf(command, total_len, "OK"); } } else { - ANDROID_ERROR(("wls_parse_batching_cmd : unknown command\n")); + DHD_ERROR(("wls_parse_batching_cmd : unknown command\n")); err = BCME_ERROR; goto exit; } @@ -4530,7 +1841,7 @@ exit: #ifndef WL_SCHED_SCAN static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) { - wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT]; + wlc_ssid_ext_t *ssids_local = NULL; int res = -1; int nssid = 0; cmd_tlv_t *cmd_tlv_temp; @@ -4539,6 +1850,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t int pno_time = 0; int pno_repeat = 0; int pno_freq_expo_max = 0; + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); #ifdef PNO_SET_DEBUG int i; @@ -4560,10 +1872,10 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t 0x00 }; #endif /* PNO_SET_DEBUG */ - ANDROID_INFO(("wl_android_set_pno_setup: command=%s, len=%d\n", command, total_len)); + DHD_PNO(("wl_android_set_pno_setup: command=%s, len=%d\n", command, total_len)); if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) { - ANDROID_ERROR(("wl_android_set_pno_setup: argument=%d less min size\n", total_len)); + DHD_ERROR(("wl_android_set_pno_setup: argument=%d less min size\n", total_len)); goto exit_proc; } #ifdef PNO_SET_DEBUG @@ -4574,7 +1886,12 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET); cmd_tlv_temp = (cmd_tlv_t *)str_ptr; - bzero(ssids_local, sizeof(ssids_local)); + ssids_local = (wlc_ssid_ext_t *)MALLOCZ(cfg->osh, + sizeof(wlc_ssid_ext_t) * MAX_PFN_LIST_COUNT); + if (!ssids_local) { + DHD_ERROR(("wl_android_set_pno_setup: No memory\n")); + return -ENOMEM; + } if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && (cmd_tlv_temp->version == PNO_TLV_VERSION) && @@ -4585,48 +1902,52 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local, MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) { - ANDROID_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); + DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); goto exit_proc; } else { if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) { - ANDROID_ERROR(("wl_android_set_pno_setup: scan duration corrupted" + DHD_ERROR(("wl_android_set_pno_setup: scan duration corrupted" " field size %d\n", tlv_size_left)); goto exit_proc; } str_ptr++; pno_time = simple_strtoul(str_ptr, &str_ptr, 16); - ANDROID_INFO(("wl_android_set_pno_setup: pno_time=%d\n", pno_time)); + DHD_PNO(("wl_android_set_pno_setup: pno_time=%d\n", pno_time)); if (str_ptr[0] != 0) { if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { - ANDROID_ERROR(("wl_android_set_pno_setup: pno repeat:" + DHD_ERROR(("wl_android_set_pno_setup: pno repeat:" " corrupted field\n")); goto exit_proc; } str_ptr++; pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); - ANDROID_INFO(("wl_android_set_pno_setup: got pno_repeat=%d\n", + DHD_PNO(("wl_android_set_pno_setup: got pno_repeat=%d\n", pno_repeat)); if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { - ANDROID_ERROR(("wl_android_set_pno_setup: FREQ_EXPO_MAX" + DHD_ERROR(("wl_android_set_pno_setup: FREQ_EXPO_MAX" " corrupted field size\n")); goto exit_proc; } str_ptr++; pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); - ANDROID_INFO(("wl_android_set_pno_setup: pno_freq_expo_max=%d\n", + DHD_PNO(("wl_android_set_pno_setup: pno_freq_expo_max=%d\n", pno_freq_expo_max)); } } } else { - ANDROID_ERROR(("wl_android_set_pno_setup: get wrong TLV command\n")); + DHD_ERROR(("wl_android_set_pno_setup: get wrong TLV command\n")); goto exit_proc; } res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max, NULL, 0); exit_proc: + if (ssids_local) { + MFREE(cfg->osh, ssids_local, + sizeof(wlc_ssid_ext_t) * MAX_PFN_LIST_COUNT); + } return res; } #endif /* !WL_SCHED_SCAN */ @@ -4639,14 +1960,14 @@ static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, i #define MAC_ADDR_STR_LEN 18 if (total_len < MAC_ADDR_STR_LEN) { - ANDROID_ERROR(("wl_android_get_p2p_dev_addr: buflen %d is less than p2p dev addr\n", + DHD_ERROR(("wl_android_get_p2p_dev_addr: buflen %d is less than p2p dev addr\n", total_len)); return -1; } ret = wl_cfg80211_get_p2p_dev_addr(ndev, &p2pdev_addr); if (ret) { - ANDROID_ERROR(("wl_android_get_p2p_dev_addr: Failed to get p2p dev addr\n")); + DHD_ERROR(("wl_android_get_p2p_dev_addr: Failed to get p2p dev addr\n")); return -1; } return (snprintf(command, total_len, MACF, ETHERP_TO_MACF(&p2pdev_addr))); @@ -4663,21 +1984,21 @@ wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist * /* set filtering mode */ if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode)) != 0)) { - ANDROID_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACMODE error=%d\n", ret)); + DHD_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACMODE error=%d\n", ret)); return ret; } if (macmode != MACLIST_MODE_DISABLED) { /* set the MAC filter list */ if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist, sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) { - ANDROID_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACLIST error=%d\n", ret)); + DHD_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACLIST error=%d\n", ret)); return ret; } /* get the current list of associated STAs */ assoc_maclist->count = MAX_NUM_OF_ASSOCLIST; if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf))) != 0) { - ANDROID_ERROR(("wl_android_set_ap_mac_list: WLC_GET_ASSOCLIST error=%d\n", + DHD_ERROR(("wl_android_set_ap_mac_list: WLC_GET_ASSOCLIST error=%d\n", ret)); return ret; } @@ -4688,7 +2009,7 @@ wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist * match = 0; /* compare with each entry */ for (j = 0; j < maclist->count; j++) { - ANDROID_INFO(("wl_android_set_ap_mac_list: associated="MACDBG + DHD_INFO(("wl_android_set_ap_mac_list: associated="MACDBG "list = "MACDBG "\n", MAC2STRDBG(assoc_maclist->ea[i].octet), MAC2STRDBG(maclist->ea[j].octet))); @@ -4710,7 +2031,7 @@ wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist * if ((ret = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, sizeof(scb_val_t))) != 0) - ANDROID_ERROR(("wl_android_set_ap_mac_list:" + DHD_ERROR(("wl_android_set_ap_mac_list:" " WLC_SCB_DEAUTHENTICATE" " error=%d\n", ret)); @@ -4748,7 +2069,7 @@ wl_android_set_mac_address_filter(struct net_device *dev, char* str) macmode = bcm_atoi(token); if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) { - ANDROID_ERROR(("wl_android_set_mac_address_filter: invalid macmode %d\n", macmode)); + DHD_ERROR(("wl_android_set_mac_address_filter: invalid macmode %d\n", macmode)); return -1; } @@ -4758,7 +2079,7 @@ wl_android_set_mac_address_filter(struct net_device *dev, char* str) } macnum = bcm_atoi(token); if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) { - ANDROID_ERROR(("wl_android_set_mac_address_filter: invalid number of MAC" + DHD_ERROR(("wl_android_set_mac_address_filter: invalid number of MAC" " address entries %d\n", macnum)); return -1; @@ -4767,7 +2088,7 @@ wl_android_set_mac_address_filter(struct net_device *dev, char* str) list = (struct maclist*) MALLOCZ(cfg->osh, sizeof(int) + sizeof(struct ether_addr) * macnum); if (!list) { - ANDROID_ERROR(("wl_android_set_mac_address_filter : failed to allocate memory\n")); + DHD_ERROR(("wl_android_set_mac_address_filter : failed to allocate memory\n")); return -1; } /* prepare the MAC list */ @@ -4776,19 +2097,19 @@ wl_android_set_mac_address_filter(struct net_device *dev, char* str) for (i = 0; i < list->count; i++) { token = strsep((char**)&str, " "); if (token == NULL) { - ANDROID_ERROR(("wl_android_set_mac_address_filter : No mac address present\n")); + DHD_ERROR(("wl_android_set_mac_address_filter : No mac address present\n")); ret = -EINVAL; goto exit; } strlcpy(eabuf, token, sizeof(eabuf)); if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) { - ANDROID_ERROR(("wl_android_set_mac_address_filter : mac parsing err index=%d," + DHD_ERROR(("wl_android_set_mac_address_filter : mac parsing err index=%d," " addr=%s\n", i, eabuf)); list->count = i; break; } - ANDROID_INFO(("wl_android_set_mac_address_filter : %d/%d MACADDR=%s", + DHD_INFO(("wl_android_set_mac_address_filter : %d/%d MACADDR=%s", i, list->count, eabuf)); } if (i == 0) @@ -4796,7 +2117,7 @@ wl_android_set_mac_address_filter(struct net_device *dev, char* str) /* set the list */ if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0) - ANDROID_ERROR(("wl_android_set_mac_address_filter: Setting MAC list failed error=%d\n", + DHD_ERROR(("wl_android_set_mac_address_filter: Setting MAC list failed error=%d\n", ret)); exit: @@ -4811,7 +2132,7 @@ static int wl_android_get_factory_mac_addr(struct net_device *ndev, char *comman struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); if (total_len < ETHER_ADDR_STR_LEN) { - ANDROID_ERROR(("wl_android_get_factory_mac_addr buflen %d" + DHD_ERROR(("wl_android_get_factory_mac_addr buflen %d" "is less than factory mac addr\n", total_len)); return BCME_ERROR; } @@ -4821,31 +2142,36 @@ static int wl_android_get_factory_mac_addr(struct net_device *ndev, char *comman } #if defined(WLAN_ACCEL_BOOT) +bool g_wifi_accel_on = FALSE; int wl_android_wifi_accel_on(struct net_device *dev, bool force_reg_on) { int ret = 0; - ANDROID_ERROR(("%s: force_reg_on = %d\n", __FUNCTION__, force_reg_on)); + DHD_ERROR(("%s: force_reg_on:%d g_wifi_accel_on:%d\n", + __FUNCTION__, force_reg_on, g_wifi_accel_on)); if (!dev) { - ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__)); + DHD_ERROR(("%s: dev is null\n", __FUNCTION__)); return -EINVAL; } if (force_reg_on) { - /* First resume the bus if it is in suspended state */ - ret = dhd_net_bus_resume(dev, 0); - if (ret) { - ANDROID_ERROR(("%s: dhd_net_bus_resume failed\n", __FUNCTION__)); - } - /* Toggle wl_reg_on */ - ret = wl_android_wifi_off(dev, TRUE); - if (ret) { - ANDROID_ERROR(("%s: wl_android_wifi_off failed\n", __FUNCTION__)); + if (g_wifi_accel_on) { + /* First resume the bus if it is in suspended state */ + ret = dhd_net_bus_resume(dev, 0); + if (ret) { + DHD_ERROR(("%s: dhd_net_bus_resume failed\n", __FUNCTION__)); + } + /* Toggle wl_reg_on */ + ret = wl_android_wifi_off(dev, TRUE); + if (ret) { + DHD_ERROR(("%s: wl_android_wifi_off failed\n", __FUNCTION__)); + } } ret = wl_android_wifi_on(dev); if (ret) { - ANDROID_ERROR(("%s: wl_android_wifi_on failed\n", __FUNCTION__)); + DHD_ERROR(("%s: wl_android_wifi_on failed\n", __FUNCTION__)); } + g_wifi_accel_on = TRUE; } else { ret = dhd_net_bus_resume(dev, 0); } @@ -4857,15 +2183,16 @@ int wl_android_wifi_accel_off(struct net_device *dev, bool force_reg_on) { int ret = 0; - ANDROID_ERROR(("%s: force_reg_on = %d\n", __FUNCTION__, force_reg_on)); + DHD_ERROR(("%s: force_reg_on:%d g_wifi_accel_on:%d\n", + __FUNCTION__, force_reg_on, g_wifi_accel_on)); if (!dev) { - ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__)); + DHD_ERROR(("%s: dev is null\n", __FUNCTION__)); return -EINVAL; } if (force_reg_on) { - ANDROID_ERROR(("%s: do nothing as wl_reg_on will be toggled in UP\n", - __FUNCTION__)); + ret = wl_android_wifi_off(dev, TRUE); + g_wifi_accel_on = FALSE; } else { ret = dhd_net_bus_suspend(dev); } @@ -4876,6 +2203,8 @@ int wl_android_wifi_accel_off(struct net_device *dev, bool force_reg_on) #ifdef WBRC extern int wbrc_wl2bt_reset(void); +extern int wbrc_wlan_on_ack(void); +extern int wbrc_wlan_on_started(void); #endif /* WBRC */ /** @@ -4886,18 +2215,38 @@ int wl_android_wifi_on(struct net_device *dev) { int ret = 0; int retry = POWERUP_MAX_RETRY; - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); + dhd_pub_t *dhdp; BCM_REFERENCE(dhdp); if (!dev) { - ANDROID_ERROR(("wl_android_wifi_on: dev is null\n")); + DHD_ERROR(("wl_android_wifi_on: dev is null\n")); return -EINVAL; } + dhdp = wl_cfg80211_get_dhdp(dev); dhd_net_if_lock(dev); WL_MSG(dev->name, "in g_wifi_on=%d\n", g_wifi_on); if (!g_wifi_on) { do { +#ifdef WBRC + /* + * Inform wbrc that wlan is started to reset wlan_on_ack and + * wlan_on_ack will be set back after successful WLAN ON + * by calling wbrc_wlan_on_ack(). + * This is to ensure BT dev_open waits till WLAN ON is finished. + */ + (void)wbrc_wlan_on_started(); + + if (dhdp->do_chip_bighammer) { + dhdp->do_chip_bighammer = FALSE; + /* Inform BT to reset which wait till BT OFF is done */ + if (wbrc_wl2bt_reset()) { + DHD_ERROR(("%s:no BT\n", __FUNCTION__)); + } else { + dhdp->chip_bighammer_count++; + } + } +#endif /* WBRC */ dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY); #ifdef BCMSDIO ret = dhd_net_bus_resume(dev, 0); @@ -4907,7 +2256,7 @@ int wl_android_wifi_on(struct net_device *dev) ret = dhd_net_bus_devreset(dev, FALSE); #ifdef WBRC if (dhdp->dhd_induce_bh_error == DHD_INDUCE_BH_ON_FAIL_ONCE) { - ANDROID_ERROR(("%s: dhd_induce_bh_error = %d\n", + DHD_ERROR(("%s: dhd_induce_bh_error = %d\n", __FUNCTION__, dhdp->dhd_induce_bh_error)); /* Forcefully set error */ ret = BCME_ERROR; @@ -4915,7 +2264,7 @@ int wl_android_wifi_on(struct net_device *dev) dhdp->dhd_induce_bh_error = DHD_INDUCE_ERROR_CLEAR; } if (dhdp->dhd_induce_bh_error == DHD_INDUCE_BH_ON_FAIL_ALWAYS) { - ANDROID_ERROR(("%s: dhd_induce_bh_error = %d\n", + DHD_ERROR(("%s: dhd_induce_bh_error = %d\n", __FUNCTION__, dhdp->dhd_induce_bh_error)); /* Forcefully set error */ ret = BCME_ERROR; @@ -4929,32 +2278,30 @@ int wl_android_wifi_on(struct net_device *dev) #endif /* BCMSDIO */ ret = dhd_dev_init_ioctl(dev); if (ret < 0) { - goto retry_bus; + goto retry_power; } #endif /* BCMSDIO || BCMDBUS */ if (ret == 0) { +#ifdef WBRC + /* Ack wbrc driver on wlan ON succeed */ + (void)wbrc_wlan_on_ack(); +#endif /* WBRC */ break; } -#if defined(BCMSDIO) || defined(BCMDBUS) -retry_bus: +retry_power: + DHD_ERROR(("%s: failed to power up wifi chip, retry again (%d left) **\n", + __FUNCTION__, retry)); + /* Set big hammer flag */ + dhdp->do_chip_bighammer = TRUE; + dhd_net_bus_devreset(dev, TRUE); #ifdef BCMSDIO dhd_net_bus_suspend(dev); #endif /* BCMSDIO */ -#endif /* BCMSDIO || BCMDBUS */ -retry_power: - ANDROID_ERROR(("failed to power up wifi chip, retry again (%d left) **\n\n", - retry)); - dhd_net_bus_devreset(dev, TRUE); dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); -#ifdef WBRC - /* Inform BT reset which will internally wait till BT reset is done */ - if (wbrc_wl2bt_reset()) { - ANDROID_ERROR(("Failed to reset BT, nothing to be done!!!!\n")); - } -#endif /* WBRC */ + } while (retry-- > 0); if (ret != 0) { - ANDROID_ERROR(("failed to power up wifi chip, max retry reached **\n\n")); + DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n")); #ifdef BCM_DETECT_TURN_ON_FAILURE BUG_ON(1); #endif /* BCM_DETECT_TURN_ON_FAILURE */ @@ -4969,28 +2316,29 @@ exit: else WL_MSG(dev->name, "Success\n"); dhd_net_if_unlock(dev); + return ret; } -int wl_android_wifi_off(struct net_device *dev, bool on_failure) +int wl_android_wifi_off(struct net_device *dev, bool force_off) { int ret = 0; if (!dev) { - ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__)); + DHD_TRACE(("wl_android_wifi_off: dev is null\n")); return -EINVAL; } #if defined(BCMPCIE) && defined(DHD_DEBUG_UART) ret = dhd_debug_uart_is_running(dev); if (ret) { - ANDROID_ERROR(("wl_android_wifi_off: - Debug UART App is running\n")); + DHD_ERROR(("wl_android_wifi_off: - Debug UART App is running\n")); return -EBUSY; } #endif /* BCMPCIE && DHD_DEBUG_UART */ dhd_net_if_lock(dev); - WL_MSG(dev->name, "in g_wifi_on=%d, on_failure=%d\n", g_wifi_on, on_failure); - if (g_wifi_on || on_failure) { + WL_MSG(dev->name, " g_wifi_on=%d force_off=%d\n", g_wifi_on, force_off); + if (g_wifi_on || force_off) { #if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS) ret = dhd_net_bus_devreset(dev, TRUE); #ifdef BCMSDIO @@ -5031,7 +2379,7 @@ wl_chanim_stats(struct net_device *dev, u8 *chan_idle) if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)¶m, sizeof(wl_chanim_stats_t), (char*)result, sizeof(result), 0)) < 0) { - ANDROID_ERROR(("Failed to get chanim results %d \n", err)); + WL_ERR(("Failed to get chanim results %d \n", err)); return err; } @@ -5045,7 +2393,7 @@ wl_chanim_stats(struct net_device *dev, u8 *chan_idle) list->version = 0; list->count = 0; } else if (list->version != WL_CHANIM_STATS_VERSION) { - ANDROID_ERROR(("Sorry, firmware has wl_chanim_stats version %d " + WL_ERR(("Sorry, firmware has wl_chanim_stats version %d " "but driver supports only version %d.\n", list->version, WL_CHANIM_STATS_VERSION)); list->buflen = 0; @@ -5059,7 +2407,7 @@ wl_chanim_stats(struct net_device *dev, u8 *chan_idle) stats->timestamp = dtoh32(stats->timestamp); stats->chan_idle = dtoh32(stats->chan_idle); - ANDROID_INFO(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n", + WL_INFORM(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n", stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle, stats->timestamp)); @@ -5087,16 +2435,16 @@ wl_android_get_connection_stats(struct net_device *dev, char *command, int total int bytes_written = -1; int ret = 0; - ANDROID_INFO(("wl_android_get_connection_stats: enter Get Connection Stats\n")); + WL_INFORM(("wl_android_get_connection_stats: enter Get Connection Stats\n")); if (total_len <= 0) { - ANDROID_ERROR(("wl_android_get_connection_stats: invalid buffer size %d\n", total_len)); + WL_ERR(("wl_android_get_connection_stats: invalid buffer size %d\n", total_len)); goto error; } bufsize = total_len; if (bufsize < sizeof(struct connection_stats)) { - ANDROID_ERROR(("wl_android_get_connection_stats: not enough buffer size, provided=%u," + WL_ERR(("wl_android_get_connection_stats: not enough buffer size, provided=%u," " requires=%zu\n", bufsize, sizeof(struct connection_stats))); @@ -5108,7 +2456,7 @@ wl_android_get_connection_stats(struct net_device *dev, char *command, int total #ifndef DISABLE_IF_COUNTERS if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(*if_stats)); if (if_stats == NULL) { - ANDROID_ERROR(("wl_android_get_connection_stats: MALLOCZ failed\n")); + WL_ERR(("wl_android_get_connection_stats: MALLOCZ failed\n")); goto error; } bzero(if_stats, sizeof(*if_stats)); @@ -5126,7 +2474,7 @@ wl_android_get_connection_stats(struct net_device *dev, char *command, int total ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0, (char *)if_stats, sizeof(*if_stats), NULL); if (ret) { - ANDROID_ERROR(("wl_android_get_connection_stats: if_counters not supported ret=%d\n", + WL_ERR(("wl_android_get_connection_stats: if_counters not supported ret=%d\n", ret)); /* In case if_stats IOVAR is not supported, get information from counters. */ @@ -5134,19 +2482,19 @@ wl_android_get_connection_stats(struct net_device *dev, char *command, int total ret = wldev_iovar_getbuf(dev, "counters", NULL, 0, iovar_buf, WLC_IOCTL_MAXLEN, NULL); if (unlikely(ret)) { - ANDROID_ERROR(("counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t))); + WL_ERR(("counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t))); goto error; } ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0); if (ret != BCME_OK) { - ANDROID_ERROR(("wl_android_get_connection_stats:" + WL_ERR(("wl_android_get_connection_stats:" " wl_cntbuf_to_xtlv_format ERR %d\n", ret)); goto error; } if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) { - ANDROID_ERROR(("wl_android_get_connection_stats: wlc_cnt NULL!\n")); + WL_ERR(("wl_android_get_connection_stats: wlc_cnt NULL!\n")); goto error; } @@ -5165,7 +2513,7 @@ wl_android_get_connection_stats(struct net_device *dev, char *command, int total } else { /* Populate from if_stats. */ if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) { - ANDROID_ERROR(("wl_android_get_connection_stats: incorrect version of" + WL_ERR(("wl_android_get_connection_stats: incorrect version of" " wl_if_stats_t," " expected=%u got=%u\n", WL_IF_STATS_T_VERSION, if_stats->version)); @@ -5195,7 +2543,7 @@ wl_android_get_connection_stats(struct net_device *dev, char *command, int total /* link_speed is in kbps */ ret = wldev_get_link_speed(dev, &link_speed); if (ret || link_speed < 0) { - ANDROID_ERROR(("wl_android_get_connection_stats: wldev_get_link_speed()" + WL_ERR(("wl_android_get_connection_stats: wldev_get_link_speed()" " failed, ret=%d, speed=%d\n", ret, link_speed)); goto error; @@ -5221,616 +2569,6 @@ error: } #endif /* CONNECTION_STATISTICS */ -#ifdef WL_NATOE -static int -wl_android_process_natoe_cmd(struct net_device *dev, char *command, int total_len) -{ - int ret = BCME_ERROR; - char *pcmd = command; - char *str = NULL; - wl_natoe_cmd_info_t cmd_info; - const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0]; - - /* skip to cmd name after "natoe" */ - str = bcmstrtok(&pcmd, " ", NULL); - - /* If natoe subcmd name is not provided, return error */ - if (*pcmd == '\0') { - ANDROID_ERROR(("natoe subcmd not provided wl_android_process_natoe_cmd\n")); - ret = -EINVAL; - return ret; - } - - /* get the natoe command name to str */ - str = bcmstrtok(&pcmd, " ", NULL); - - while (natoe_cmd->name != NULL) { - if (strcmp(natoe_cmd->name, str) == 0) { - /* dispacth cmd to appropriate handler */ - if (natoe_cmd->handler) { - cmd_info.command = command; - cmd_info.tot_len = total_len; - ret = natoe_cmd->handler(dev, natoe_cmd, pcmd, &cmd_info); - } - return ret; - } - natoe_cmd++; - } - return ret; -} - -static int -wlu_natoe_set_vars_cbfn(void *ctx, uint8 *data, uint16 type, uint16 len) -{ - int res = BCME_OK; - wl_natoe_cmd_info_t *cmd_info = (wl_natoe_cmd_info_t *)ctx; - uint8 *command = cmd_info->command; - uint16 total_len = cmd_info->tot_len; - uint16 bytes_written = 0; - - UNUSED_PARAMETER(len); - - switch (type) { - - case WL_NATOE_XTLV_ENABLE: - { - bytes_written = snprintf(command, total_len, "natoe: %s\n", - *data?"enabled":"disabled"); - cmd_info->bytes_written = bytes_written; - break; - } - - case WL_NATOE_XTLV_CONFIG_IPS: - { - wl_natoe_config_ips_t *config_ips; - uint8 buf[16]; - - config_ips = (wl_natoe_config_ips_t *)data; - bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_ip, buf); - bytes_written = snprintf(command, total_len, "sta ip: %s\n", buf); - bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_netmask, buf); - bytes_written += snprintf(command + bytes_written, total_len, - "sta netmask: %s\n", buf); - bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_router_ip, buf); - bytes_written += snprintf(command + bytes_written, total_len, - "sta router ip: %s\n", buf); - bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_dnsip, buf); - bytes_written += snprintf(command + bytes_written, total_len, - "sta dns ip: %s\n", buf); - bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_ip, buf); - bytes_written += snprintf(command + bytes_written, total_len, - "ap ip: %s\n", buf); - bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_netmask, buf); - bytes_written += snprintf(command + bytes_written, total_len, - "ap netmask: %s\n", buf); - cmd_info->bytes_written = bytes_written; - break; - } - - case WL_NATOE_XTLV_CONFIG_PORTS: - { - wl_natoe_ports_config_t *ports_config; - - ports_config = (wl_natoe_ports_config_t *)data; - bytes_written = snprintf(command, total_len, "starting port num: %d\n", - dtoh16(ports_config->start_port_num)); - bytes_written += snprintf(command + bytes_written, total_len, - "number of ports: %d\n", dtoh16(ports_config->no_of_ports)); - cmd_info->bytes_written = bytes_written; - break; - } - - case WL_NATOE_XTLV_DBG_STATS: - { - char *stats_dump = (char *)data; - - bytes_written = snprintf(command, total_len, "%s\n", stats_dump); - cmd_info->bytes_written = bytes_written; - break; - } - - case WL_NATOE_XTLV_TBL_CNT: - { - bytes_written = snprintf(command, total_len, "natoe max tbl entries: %d\n", - dtoh32(*(uint32 *)data)); - cmd_info->bytes_written = bytes_written; - break; - } - - default: - /* ignore */ - break; - } - - return res; -} - -/* - * --- common for all natoe get commands ---- - */ -static int -wl_natoe_get_ioctl(struct net_device *dev, wl_natoe_ioc_t *natoe_ioc, - uint16 iocsz, uint8 *buf, uint16 buflen, wl_natoe_cmd_info_t *cmd_info) -{ - /* for gets we only need to pass ioc header */ - wl_natoe_ioc_t *iocresp = (wl_natoe_ioc_t *)buf; - int res; - - /* send getbuf natoe iovar */ - res = wldev_iovar_getbuf(dev, "natoe", natoe_ioc, iocsz, buf, - buflen, NULL); - - /* check the response buff */ - if ((res == BCME_OK)) { - /* scans ioctl tlvbuf f& invokes the cbfn for processing */ - res = bcm_unpack_xtlv_buf(cmd_info, iocresp->data, iocresp->len, - BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn); - - if (res == BCME_OK) { - res = cmd_info->bytes_written; - } - } - else - { - ANDROID_ERROR(("wl_natoe_get_ioctl: get command failed code %d\n", res)); - res = BCME_ERROR; - } - - return res; -} - -static int -wl_android_natoe_subcmd_enable(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd, - char *command, wl_natoe_cmd_info_t *cmd_info) -{ - int ret = BCME_OK; - wl_natoe_ioc_t *natoe_ioc; - char *pcmd = command; - uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ; - uint16 buflen = WL_NATOE_IOC_BUFSZ; - bcm_xtlv_t *pxtlv = NULL; - char *ioctl_buf = NULL; - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - - ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); - if (!ioctl_buf) { - ANDROID_ERROR(("ioctl memory alloc failed\n")); - return -ENOMEM; - } - - /* alloc mem for ioctl headr + tlv data */ - natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz); - if (!natoe_ioc) { - ANDROID_ERROR(("ioctl header memory alloc failed\n")); - MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); - return -ENOMEM; - } - - /* make up natoe cmd ioctl header */ - natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION); - natoe_ioc->id = htod16(cmd->id); - natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ); - pxtlv = (bcm_xtlv_t *)natoe_ioc->data; - - if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */ - iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv); - ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf, - WLC_IOCTL_MEDLEN, cmd_info); - if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_enable\n")); - ret = -EINVAL; - } - } else { /* set */ - uint8 val = bcm_atoi(pcmd); - - /* buflen is max tlv data we can write, it will be decremented as we pack */ - /* save buflen at start */ - uint16 buflen_at_start = buflen; - - /* we'll adjust final ioc size at the end */ - ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE, - sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32); - - if (ret != BCME_OK) { - ret = -EINVAL; - goto exit; - } - - /* adjust iocsz to the end of last data record */ - natoe_ioc->len = (buflen_at_start - buflen); - iocsz = sizeof(*natoe_ioc) + natoe_ioc->len; - - ret = wldev_iovar_setbuf(dev, "natoe", - natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to set iovar %d\n", ret)); - ret = -EINVAL; - } - } - -exit: - MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); - MFREE(cfg->osh, natoe_ioc, iocsz); - - return ret; -} - -static int -wl_android_natoe_subcmd_config_ips(struct net_device *dev, - const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info) -{ - int ret = BCME_OK; - wl_natoe_config_ips_t config_ips; - wl_natoe_ioc_t *natoe_ioc; - char *pcmd = command; - char *str; - uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ; - uint16 buflen = WL_NATOE_IOC_BUFSZ; - bcm_xtlv_t *pxtlv = NULL; - char *ioctl_buf = NULL; - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - - ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); - if (!ioctl_buf) { - ANDROID_ERROR(("ioctl memory alloc failed\n")); - return -ENOMEM; - } - - /* alloc mem for ioctl headr + tlv data */ - natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz); - if (!natoe_ioc) { - ANDROID_ERROR(("ioctl header memory alloc failed\n")); - MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); - return -ENOMEM; - } - - /* make up natoe cmd ioctl header */ - natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION); - natoe_ioc->id = htod16(cmd->id); - natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ); - pxtlv = (bcm_xtlv_t *)natoe_ioc->data; - - if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */ - iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv); - ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf, - WLC_IOCTL_MEDLEN, cmd_info); - if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_config_ips\n")); - ret = -EINVAL; - } - } else { /* set */ - /* buflen is max tlv data we can write, it will be decremented as we pack */ - /* save buflen at start */ - uint16 buflen_at_start = buflen; - - bzero(&config_ips, sizeof(config_ips)); - - str = bcmstrtok(&pcmd, " ", NULL); - if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_ip)) { - ANDROID_ERROR(("Invalid STA IP addr %s\n", str)); - ret = -EINVAL; - goto exit; - } - - str = bcmstrtok(&pcmd, " ", NULL); - if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_netmask)) { - ANDROID_ERROR(("Invalid STA netmask %s\n", str)); - ret = -EINVAL; - goto exit; - } - - str = bcmstrtok(&pcmd, " ", NULL); - if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_router_ip)) { - ANDROID_ERROR(("Invalid STA router IP addr %s\n", str)); - ret = -EINVAL; - goto exit; - } - - str = bcmstrtok(&pcmd, " ", NULL); - if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_dnsip)) { - ANDROID_ERROR(("Invalid STA DNS IP addr %s\n", str)); - ret = -EINVAL; - goto exit; - } - - str = bcmstrtok(&pcmd, " ", NULL); - if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_ip)) { - ANDROID_ERROR(("Invalid AP IP addr %s\n", str)); - ret = -EINVAL; - goto exit; - } - - str = bcmstrtok(&pcmd, " ", NULL); - if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_netmask)) { - ANDROID_ERROR(("Invalid AP netmask %s\n", str)); - ret = -EINVAL; - goto exit; - } - - ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, - &buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips), - &config_ips, BCM_XTLV_OPTION_ALIGN32); - - if (ret != BCME_OK) { - ret = -EINVAL; - goto exit; - } - - /* adjust iocsz to the end of last data record */ - natoe_ioc->len = (buflen_at_start - buflen); - iocsz = sizeof(*natoe_ioc) + natoe_ioc->len; - - ret = wldev_iovar_setbuf(dev, "natoe", - natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to set iovar %d\n", ret)); - ret = -EINVAL; - } - } - -exit: - MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); - MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ); - - return ret; -} - -static int -wl_android_natoe_subcmd_config_ports(struct net_device *dev, - const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info) -{ - int ret = BCME_OK; - wl_natoe_ports_config_t ports_config; - wl_natoe_ioc_t *natoe_ioc; - char *pcmd = command; - char *str; - uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ; - uint16 buflen = WL_NATOE_IOC_BUFSZ; - bcm_xtlv_t *pxtlv = NULL; - char *ioctl_buf = NULL; - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - - ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); - if (!ioctl_buf) { - ANDROID_ERROR(("ioctl memory alloc failed\n")); - return -ENOMEM; - } - - /* alloc mem for ioctl headr + tlv data */ - natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz); - if (!natoe_ioc) { - ANDROID_ERROR(("ioctl header memory alloc failed\n")); - MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); - return -ENOMEM; - } - - /* make up natoe cmd ioctl header */ - natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION); - natoe_ioc->id = htod16(cmd->id); - natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ); - pxtlv = (bcm_xtlv_t *)natoe_ioc->data; - - if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */ - iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv); - ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf, - WLC_IOCTL_MEDLEN, cmd_info); - if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_config_ports\n")); - ret = -EINVAL; - } - } else { /* set */ - /* buflen is max tlv data we can write, it will be decremented as we pack */ - /* save buflen at start */ - uint16 buflen_at_start = buflen; - - bzero(&ports_config, sizeof(ports_config)); - - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - ANDROID_ERROR(("Invalid port string %s\n", str)); - ret = -EINVAL; - goto exit; - } - ports_config.start_port_num = htod16(bcm_atoi(str)); - - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - ANDROID_ERROR(("Invalid port string %s\n", str)); - ret = -EINVAL; - goto exit; - } - ports_config.no_of_ports = htod16(bcm_atoi(str)); - - if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) > - NATOE_MAX_PORT_NUM) { - ANDROID_ERROR(("Invalid port configuration\n")); - ret = -EINVAL; - goto exit; - } - ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, - &buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config), - &ports_config, BCM_XTLV_OPTION_ALIGN32); - - if (ret != BCME_OK) { - ret = -EINVAL; - goto exit; - } - - /* adjust iocsz to the end of last data record */ - natoe_ioc->len = (buflen_at_start - buflen); - iocsz = sizeof(*natoe_ioc) + natoe_ioc->len; - - ret = wldev_iovar_setbuf(dev, "natoe", - natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to set iovar %d\n", ret)); - ret = -EINVAL; - } - } - -exit: - MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); - MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ); - - return ret; -} - -static int -wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd, - char *command, wl_natoe_cmd_info_t *cmd_info) -{ - int ret = BCME_OK; - wl_natoe_ioc_t *natoe_ioc; - char *pcmd = command; - uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ; - uint16 buflen = WL_NATOE_DBG_STATS_BUFSZ; - bcm_xtlv_t *pxtlv = NULL; - char *ioctl_buf = NULL; - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - - ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN); - if (!ioctl_buf) { - ANDROID_ERROR(("ioctl memory alloc failed\n")); - return -ENOMEM; - } - - /* alloc mem for ioctl headr + tlv data */ - natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz); - if (!natoe_ioc) { - ANDROID_ERROR(("ioctl header memory alloc failed\n")); - MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN); - return -ENOMEM; - } - - /* make up natoe cmd ioctl header */ - natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION); - natoe_ioc->id = htod16(cmd->id); - natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ); - pxtlv = (bcm_xtlv_t *)natoe_ioc->data; - - if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */ - iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv); - ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf, - WLC_IOCTL_MAXLEN, cmd_info); - if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_dbg_stats\n")); - ret = -EINVAL; - } - } else { /* set */ - uint8 val = bcm_atoi(pcmd); - - /* buflen is max tlv data we can write, it will be decremented as we pack */ - /* save buflen at start */ - uint16 buflen_at_start = buflen; - - /* we'll adjust final ioc size at the end */ - ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE, - sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32); - - if (ret != BCME_OK) { - ret = -EINVAL; - goto exit; - } - - /* adjust iocsz to the end of last data record */ - natoe_ioc->len = (buflen_at_start - buflen); - iocsz = sizeof(*natoe_ioc) + natoe_ioc->len; - - ret = wldev_iovar_setbuf(dev, "natoe", - natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MAXLEN, NULL); - if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to set iovar %d\n", ret)); - ret = -EINVAL; - } - } - -exit: - MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN); - MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ); - - return ret; -} - -static int -wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd, - char *command, wl_natoe_cmd_info_t *cmd_info) -{ - int ret = BCME_OK; - wl_natoe_ioc_t *natoe_ioc; - char *pcmd = command; - uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ; - uint16 buflen = WL_NATOE_IOC_BUFSZ; - bcm_xtlv_t *pxtlv = NULL; - char *ioctl_buf = NULL; - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - - ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); - if (!ioctl_buf) { - ANDROID_ERROR(("ioctl memory alloc failed\n")); - return -ENOMEM; - } - - /* alloc mem for ioctl headr + tlv data */ - natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz); - if (!natoe_ioc) { - ANDROID_ERROR(("ioctl header memory alloc failed\n")); - MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); - return -ENOMEM; - } - - /* make up natoe cmd ioctl header */ - natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION); - natoe_ioc->id = htod16(cmd->id); - natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ); - pxtlv = (bcm_xtlv_t *)natoe_ioc->data; - - if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */ - iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv); - ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf, - WLC_IOCTL_MEDLEN, cmd_info); - if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_tbl_cnt\n")); - ret = -EINVAL; - } - } else { /* set */ - uint32 val = bcm_atoi(pcmd); - - /* buflen is max tlv data we can write, it will be decremented as we pack */ - /* save buflen at start */ - uint16 buflen_at_start = buflen; - - /* we'll adjust final ioc size at the end */ - ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT, - sizeof(uint32), &val, BCM_XTLV_OPTION_ALIGN32); - - if (ret != BCME_OK) { - ret = -EINVAL; - goto exit; - } - - /* adjust iocsz to the end of last data record */ - natoe_ioc->len = (buflen_at_start - buflen); - iocsz = sizeof(*natoe_ioc) + natoe_ioc->len; - - ret = wldev_iovar_setbuf(dev, "natoe", - natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to set iovar %d\n", ret)); - ret = -EINVAL; - } - } - -exit: - MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); - MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ); - - return ret; -} - -#endif /* WL_NATOE */ - #ifdef WL_MBO static int wl_android_process_mbo_cmd(struct net_device *dev, char *command, int total_len) @@ -5846,7 +2584,7 @@ wl_android_process_mbo_cmd(struct net_device *dev, char *command, int total_len) /* If mbo subcmd name is not provided, return error */ if (*pcmd == '\0') { - ANDROID_ERROR(("mbo subcmd not provided %s\n", __FUNCTION__)); + WL_ERR(("mbo subcmd not provided %s\n", __FUNCTION__)); ret = -EINVAL; return ret; } @@ -5854,6 +2592,7 @@ wl_android_process_mbo_cmd(struct net_device *dev, char *command, int total_len) /* get the mbo command name to str */ str = bcmstrtok(&pcmd, " ", NULL); + cmd_info.bytes_written = 0; while (mbo_cmd->name != NULL) { if (strnicmp(mbo_cmd->name, str, strlen(mbo_cmd->name)) == 0) { /* dispatch cmd to appropriate handler */ @@ -5879,7 +2618,7 @@ wl_android_send_wnm_notif(struct net_device *dev, bcm_iov_buf_t *iov_buf, uint16 buflen = 0, buflen_start = 0; memset_s(iov_buf, iov_buf_len, 0, iov_buf_len); - iov_buf->version = WL_MBO_IOV_VERSION; + iov_buf->version = WL_MBO_IOV_VERSION_1_1; iov_buf->id = WL_MBO_CMD_SEND_NOTIF; buflen = buflen_start = iov_buf_len - sizeof(bcm_iov_buf_t); pxtlv = (uint8 *)&iov_buf->data[0]; @@ -5893,7 +2632,7 @@ wl_android_send_wnm_notif(struct net_device *dev, bcm_iov_buf_t *iov_buf, ret = wldev_iovar_setbuf(dev, "mbo", iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL); if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to sent wnm notif %d\n", ret)); + WL_ERR(("Fail to sent wnm notif %d\n", ret)); } return ret; } @@ -5909,7 +2648,7 @@ wl_android_mbo_resp_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 UNUSED_PARAMETER(len); /* TODO: validate data value */ if (data == NULL) { - ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__)); + WL_ERR(("%s: Bad argument !!\n", __FUNCTION__)); return -EINVAL; } switch (type) { @@ -5920,7 +2659,7 @@ wl_android_mbo_resp_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 } break; default: - ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type)); + WL_ERR(("%s: Unknown tlv %u\n", __FUNCTION__, type)); } return BCME_OK; } @@ -5944,18 +2683,18 @@ wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev, const wl_drv_sub_cmd iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); if (iov_buf == NULL) { ret = -ENOMEM; - ANDROID_ERROR(("iov buf memory alloc exited\n")); + WL_ERR(("iov buf memory alloc exited\n")); goto exit; } iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN); if (iov_resp == NULL) { ret = -ENOMEM; - ANDROID_ERROR(("iov resp memory alloc exited\n")); + WL_ERR(("iov resp memory alloc exited\n")); goto exit; } /* fill header */ - iov_buf->version = WL_MBO_IOV_VERSION; + iov_buf->version = WL_MBO_IOV_VERSION_1_1; iov_buf->id = WL_MBO_CMD_CELLULAR_DATA_CAP; ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp, @@ -5970,7 +2709,7 @@ wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev, const wl_drv_sub_cmd if (*pcmd == WL_IOCTL_ACTION_GET) { /* Check for version */ version = dtoh16(*(uint16 *)iov_resp); - if (version != WL_MBO_IOV_VERSION) { + if (version != WL_MBO_IOV_VERSION_1_1) { ret = -EINVAL; } if (p_resp->id == WL_MBO_CMD_CELLULAR_DATA_CAP) { @@ -5982,7 +2721,7 @@ wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev, const wl_drv_sub_cmd } } else { ret = -EINVAL; - ANDROID_ERROR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id)); + WL_ERR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id)); goto exit; } } else { @@ -5993,7 +2732,7 @@ wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev, const wl_drv_sub_cmd old_cell_cap = bcm_get_data_from_xtlv_buf((uint8 *)p_resp->data, p_resp->len, WL_MBO_XTLV_CELL_DATA_CAP, &len, BCM_XTLV_OPTION_ALIGN32); if (old_cell_cap && *old_cell_cap == cell_cap) { - ANDROID_ERROR(("No change is cellular data capability\n")); + WL_ERR(("No change is cellular data capability\n")); /* No change in value */ goto exit; } @@ -6002,7 +2741,7 @@ wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev, const wl_drv_sub_cmd if (cell_cap < MBO_CELL_DATA_CONN_AVAILABLE || cell_cap > MBO_CELL_DATA_CONN_NOT_CAPABLE) { - ANDROID_ERROR(("wrong value %u\n", cell_cap)); + WL_ERR(("wrong value %u\n", cell_cap)); ret = -EINVAL; goto exit; } @@ -6017,25 +2756,23 @@ wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev, const wl_drv_sub_cmd ret = wldev_iovar_setbuf(dev, "mbo", iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL); if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to set iovar %d\n", ret)); + WL_ERR(("Fail to set iovar %d\n", ret)); ret = -EINVAL; goto exit; } /* Skip for CUSTOMER_HW4 - WNM notification * for cellular data capability is handled by host */ -#if !defined(CUSTOMER_HW4) /* send a WNM notification request to associated AP */ if (wl_get_drv_status(cfg, CONNECTED, dev)) { - ANDROID_INFO(("Sending WNM Notif\n")); + WL_INFORM(("Sending WNM Notif\n")); ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN, iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_CELL_DATA_CAP); if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to send WNM notification %d\n", ret)); + WL_ERR(("Fail to send WNM notification %d\n", ret)); ret = -EINVAL; } } -#endif /* CUSTOMER_HW4 */ } exit: if (iov_buf) { @@ -6055,17 +2792,17 @@ wl_android_mbo_non_pref_chan_parse_cbfn(void *ctx, const uint8 *data, uint16 typ uint16 total_len = cmd_info->tot_len; uint16 bytes_written = 0; - ANDROID_INFO(("Total bytes written at begining %u\n", cmd_info->bytes_written)); + WL_DBG(("Total bytes written at begining %u\n", cmd_info->bytes_written)); UNUSED_PARAMETER(len); if (data == NULL) { - ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__)); + WL_ERR(("%s: Bad argument !!\n", __FUNCTION__)); return -EINVAL; } switch (type) { case WL_MBO_XTLV_OPCLASS: { bytes_written = snprintf(command, total_len, "%u:", *data); - ANDROID_ERROR(("wr %u %u\n", bytes_written, *data)); + WL_ERR(("wr %u %u\n", bytes_written, *data)); command += bytes_written; cmd_info->bytes_written += bytes_written; } @@ -6073,7 +2810,7 @@ wl_android_mbo_non_pref_chan_parse_cbfn(void *ctx, const uint8 *data, uint16 typ case WL_MBO_XTLV_CHAN: { bytes_written = snprintf(command, total_len, "%u:", *data); - ANDROID_ERROR(("wr %u\n", bytes_written)); + WL_ERR(("wr %u\n", bytes_written)); command += bytes_written; cmd_info->bytes_written += bytes_written; } @@ -6081,7 +2818,7 @@ wl_android_mbo_non_pref_chan_parse_cbfn(void *ctx, const uint8 *data, uint16 typ case WL_MBO_XTLV_PREFERENCE: { bytes_written = snprintf(command, total_len, "%u:", *data); - ANDROID_ERROR(("wr %u\n", bytes_written)); + WL_ERR(("wr %u\n", bytes_written)); command += bytes_written; cmd_info->bytes_written += bytes_written; } @@ -6089,15 +2826,15 @@ wl_android_mbo_non_pref_chan_parse_cbfn(void *ctx, const uint8 *data, uint16 typ case WL_MBO_XTLV_REASON_CODE: { bytes_written = snprintf(command, total_len, "%u ", *data); - ANDROID_ERROR(("wr %u\n", bytes_written)); + WL_ERR(("wr %u\n", bytes_written)); command += bytes_written; cmd_info->bytes_written += bytes_written; } break; default: - ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type)); + WL_ERR(("%s: Unknown tlv %u\n", __FUNCTION__, type)); } - ANDROID_INFO(("Total bytes written %u\n", cmd_info->bytes_written)); + WL_DBG(("Total bytes written %u\n", cmd_info->bytes_written)); return BCME_OK; } @@ -6117,23 +2854,23 @@ wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev, struct bcm_cfg80211 *cfg = wl_get_cfg(dev); uint16 version; - ANDROID_ERROR(("%s:%d\n", __FUNCTION__, __LINE__)); + WL_ERR(("%s:%d\n", __FUNCTION__, __LINE__)); iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); if (iov_buf == NULL) { ret = -ENOMEM; - ANDROID_ERROR(("iov buf memory alloc exited\n")); + WL_ERR(("iov buf memory alloc exited\n")); goto exit; } iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN); if (iov_resp == NULL) { ret = -ENOMEM; - ANDROID_ERROR(("iov resp memory alloc exited\n")); + WL_ERR(("iov resp memory alloc exited\n")); goto exit; } /* get */ if (*pcmd == WL_IOCTL_ACTION_GET) { /* fill header */ - iov_buf->version = WL_MBO_IOV_VERSION; + iov_buf->version = WL_MBO_IOV_VERSION_1_1; iov_buf->id = WL_MBO_CMD_LIST_CHAN_PREF; ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp, @@ -6144,9 +2881,9 @@ wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev, p_resp = (bcm_iov_buf_t *)iov_resp; /* Check for version */ version = dtoh16(*(uint16 *)iov_resp); - if (version != WL_MBO_IOV_VERSION) { - ANDROID_ERROR(("Version mismatch. returned ver %u expected %u\n", - version, WL_MBO_IOV_VERSION)); + if (version != WL_MBO_IOV_VERSION_1_1) { + WL_ERR(("Version mismatch. returned ver %u expected %u\n", + version, WL_MBO_IOV_VERSION_1_1)); ret = -EINVAL; } if (p_resp->id == WL_MBO_CMD_LIST_CHAN_PREF) { @@ -6158,7 +2895,7 @@ wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev, } } else { ret = -EINVAL; - ANDROID_ERROR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id)); + WL_ERR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id)); goto exit; } } else { @@ -6168,19 +2905,19 @@ wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev, str = bcmstrtok(&pcmd, " ", NULL); if (!(strnicmp(str, "set", 3)) || (!strnicmp(str, "clear", 5))) { /* delete all configurations */ - iov_buf->version = WL_MBO_IOV_VERSION; + iov_buf->version = WL_MBO_IOV_VERSION_1_1; iov_buf->id = WL_MBO_CMD_DEL_CHAN_PREF; iov_buf->len = 0; iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len; ret = wldev_iovar_setbuf(dev, "mbo", iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL); if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to set iovar %d\n", ret)); + WL_ERR(("Fail to set iovar %d\n", ret)); ret = -EINVAL; goto exit; } } else { - ANDROID_ERROR(("Unknown command %s\n", str)); + WL_ERR(("Unknown command %s\n", str)); goto exit; } /* parse non pref channel list */ @@ -6189,10 +2926,10 @@ wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev, str = bcmstrtok(&pcmd, " ", NULL); while (str != NULL) { ret = sscanf(str, "%u:%u:%u:%u", &opcl, &ch, &pref, &rc); - ANDROID_ERROR(("buflen %u op %u, ch %u, pref %u rc %u\n", + WL_ERR(("buflen %u op %u, ch %u, pref %u rc %u\n", buflen, opcl, ch, pref, rc)); if (ret != 4) { - ANDROID_ERROR(("Not all parameter presents\n")); + WL_ERR(("Not all parameter presents\n")); ret = -EINVAL; } /* TODO: add a validation check here */ @@ -6223,16 +2960,16 @@ wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev, if (ret != BCME_OK) { goto exit; } - ANDROID_ERROR(("len %u\n", (buflen_start - buflen))); + WL_ERR(("len %u\n", (buflen_start - buflen))); /* Now set the new non pref channels */ - iov_buf->version = WL_MBO_IOV_VERSION; + iov_buf->version = WL_MBO_IOV_VERSION_1_1; iov_buf->id = WL_MBO_CMD_ADD_CHAN_PREF; iov_buf->len = buflen_start - buflen; iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len; ret = wldev_iovar_setbuf(dev, "mbo", iov_buf, iovlen, iov_resp, WLC_IOCTL_MEDLEN, NULL); if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to set iovar %d\n", ret)); + WL_ERR(("Fail to set iovar %d\n", ret)); ret = -EINVAL; goto exit; } @@ -6240,17 +2977,17 @@ wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev, if (cnt >= MBO_MAX_CHAN_PREF_ENTRIES) { break; } - ANDROID_ERROR(("%d cnt %u\n", __LINE__, cnt)); + WL_ERR(("%d cnt %u\n", __LINE__, cnt)); str = bcmstrtok(&pcmd, " ", NULL); } } /* send a WNM notification request to associated AP */ if (wl_get_drv_status(cfg, CONNECTED, dev)) { - ANDROID_INFO(("Sending WNM Notif\n")); + WL_INFORM(("Sending WNM Notif\n")); ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN, iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_NON_PREF_CHAN_REPORT); if (ret != BCME_OK) { - ANDROID_ERROR(("Fail to send WNM notification %d\n", ret)); + WL_ERR(("Fail to send WNM notification %d\n", ret)); ret = -EINVAL; } } @@ -6266,42 +3003,14 @@ exit: } #endif /* WL_MBO */ -#ifdef CUSTOMER_HW4_PRIVATE_CMD -#ifdef SUPPORT_AMPDU_MPDU_CMD -/* CMD_AMPDU_MPDU */ -static int -wl_android_set_ampdu_mpdu(struct net_device *dev, const char* string_num) -{ - int err = 0; - int ampdu_mpdu; - - ampdu_mpdu = bcm_atoi(string_num); - - if (ampdu_mpdu > 32) { - ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu MAX value is 32.\n")); - return -1; - } - - ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu = %d\n", ampdu_mpdu)); - err = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu); - if (err < 0) { - ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu set error. %d\n", err)); - return -1; - } - - return 0; -} -#endif /* SUPPORT_AMPDU_MPDU_CMD */ -#endif /* CUSTOMER_HW4_PRIVATE_CMD */ - -#if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL) +#ifdef WL_CP_COEX extern int wl_cfg80211_send_msg_to_ril(void); extern void wl_cfg80211_register_dev_ril_bridge_event_notifier(void); extern void wl_cfg80211_unregister_dev_ril_bridge_event_notifier(void); -extern int g_mhs_chan_for_cpcoex; -#endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */ +extern struct wl_cp_coex g_cx; +#endif /* WL_CP_COEX */ -#if defined (WL_SUPPORT_AUTO_CHANNEL) +#if defined(WL_SUPPORT_AUTO_CHANNEL) static s32 wl_android_set_auto_channel_scan_state(struct net_device *ndev) { @@ -6313,7 +3022,7 @@ wl_android_set_auto_channel_scan_state(struct net_device *ndev) ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val)); if (ret < 0) { - ANDROID_ERROR(("set interface up failed, error = %d\n", ret)); + WL_ERR(("set interface up failed, error = %d\n", ret)); goto done; } @@ -6340,6 +3049,10 @@ wl_android_get_freq_list_chanspecs(struct net_device *ndev, wl_uint32_list_t *li int i = 0; char *pcmd, *token; int len = buflen; + u32 freq_bands = 0; +#ifdef WL_6G_BAND + struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); +#endif /* WL_6G_BAND */ pcmd = bcmstrstr(cmd_str, FREQ_STR); pcmd += strlen(FREQ_STR); @@ -6354,29 +3067,36 @@ wl_android_get_freq_list_chanspecs(struct net_device *ndev, wl_uint32_list_t *li break; freq = bcm_atoi(token); + chanspec = wl_freq_to_chanspec(freq); /* Convert chanspec from frequency */ - if ((freq > 0) && - ((chanspec = wl_freq_to_chanspec(freq)) != INVCHANSPEC)) { - ANDROID_INFO(("Adding chanspec in list : 0x%x at the index %d\n", chanspec, i)); + if ((freq > 0) && (chanspec != INVCHANSPEC)) { +#ifdef WL_UNII4_CHAN + /* Skip UNII-4 frequencies */ + if (CHSPEC_IS5G(chanspec) && + IS_UNII4_CHANNEL(wf_chspec_primary20_chan(chanspec))) { + WL_DBG(("Skipped UNII-4 chanspec 0x%x\n", chanspec)); + continue; + } +#endif /* WL_UNII4_CHAN */ +#ifdef WL_5G_SOFTAP_ONLY_ON_DEF_CHAN + if (CHSPEC_IS5G(chanspec) && + !(IS_5G_APCS_CHANNEL(wf_chspec_primary20_chan(chanspec)))) { + WL_DBG(("Skipped unsupported 5G chanspec 0x%x\n", chanspec)); + continue; + } +#endif /* WL_5G_SOFTAP_ONLY_ON_DEF_CHAN */ + WL_DBG(("%s:Adding chanspec in list : 0x%x at the index %d\n", + __FUNCTION__, chanspec, i)); + /* mark all the bands found */ + freq_bands |= CHSPEC_TO_WLC_BAND(CHSPEC_BAND(chanspec)); list->element[i] = chanspec; len -= sizeof(list->element[i]); i++; -#ifdef WL_5G_SOFTAP_ONLY_ON_DEF_CHAN - /* Android includes 2g channels even for 5g band configuration. For - * customers using only single channel 5G AP, set the channel and - * return without doing ACS - */ - if (CHSPEC_BAND(chanspec) == WL_CHANSPEC_BAND_5G) { - ANDROID_INFO(("Pick default channnel from 5g\n")); - if (!sta_channel) { - list->element[0] = chanspec; - list->count = 1; - return ret; - } - break; - } -#endif /* WL_5G_SOFTAP_ONLY_ON_DEF_CHAN */ + + WL_DBG(("chspec[%d]: 0x%x (band=0x%x)\n", + i, chanspec, CHSPEC_BAND(chanspec))); } + WL_DBG(("** freq_bands=0x%x\n", freq_bands)); } list->count = i; @@ -6386,23 +3106,60 @@ wl_android_get_freq_list_chanspecs(struct net_device *ndev, wl_uint32_list_t *li * Frequency list is order of lower to higher band. * check with the highest band entry. */ - chanspec = list->element[i-1]; - if (CHSPEC_BAND(chanspec) == sta_acs_band) { - /* softap request is for same band. Use SCC - * Convert sta channel to freq - */ - freq = wl_channel_to_frequency(sta_channel, sta_acs_band); - list->element[0] = - wl_freq_to_chanspec(freq); - ANDROID_INFO(("Softap on same band as STA." - "Use SCC. chanspec:0x%x\n", chanspec)); - } else { - list->element[0] = chanspec; - ANDROID_INFO(("RSDB case chanspec:0x%x\n", chanspec)); - } list->count = 1; - return ret; + chanspec = list->element[i-1]; + if (sta_acs_band == WL_CHANSPEC_BAND_2G) { +#ifdef WL_6G_BAND + if ((freq_bands & WLC_BAND_6G) && cfg->band_6g_supported) { + list->element[0] = wl_freq_to_chanspec(APCS_DEFAULT_6G_FREQ); + } else +#endif /* WL_6G_BAND */ + if (freq_bands & WLC_BAND_5G) { + list->element[0] = wl_freq_to_chanspec(APCS_DEFAULT_5G_FREQ); + } else { + freq = wl_channel_to_frequency(sta_channel, sta_acs_band); + list->element[0] = wl_freq_to_chanspec(freq); + WL_INFORM_MEM(("Softap on same band as STA." + "Use SCC chanspec:0x%x\n", + list->element[0])); + } + } else if (sta_acs_band == WL_CHANSPEC_BAND_5G) { + if (freq_bands & WLC_BAND_5G) { + if (IS_5G_APCS_CHANNEL(sta_channel)) { + freq = wl_channel_to_frequency(sta_channel, sta_acs_band); + list->element[0] = wl_freq_to_chanspec(freq); + } else { + list->element[0] = + wl_freq_to_chanspec(APCS_DEFAULT_2G_FREQ); + } + } else { + list->element[0] = wl_freq_to_chanspec(APCS_DEFAULT_2G_FREQ); + } + } else +#ifdef WL_6G_BAND + if (sta_acs_band == WL_CHANSPEC_BAND_6G) { + if ((freq_bands & WLC_BAND_6G) && cfg->band_6g_supported) { + freq = wl_channel_to_frequency(sta_channel, sta_acs_band); + list->element[0] = wl_freq_to_chanspec(freq); + WL_INFORM_MEM(("Softap on same band as STA." + "Use SCC chanspec:0x%x\n", + list->element[0])); + } else + { + list->element[0] = wl_freq_to_chanspec(APCS_DEFAULT_2G_FREQ); + } + } else +#endif /* WL_6G_BAND */ + { + WL_ERR(("ACS: Invalid sta acs band: sta_acs_band = 0x%x\n", sta_acs_band)); + list->count = 0; + return BCME_ERROR; + } } + + if (!list->count) + return BCME_ERROR; + return ret; } @@ -6427,7 +3184,7 @@ wl_android_get_band_chanspecs(struct net_device *ndev, void *buf, s32 buflen, ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec, sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync); if (ret < 0) { - ANDROID_ERROR(("get 'chanspecs' failed, error = %d\n", ret)); + WL_ERR(("get 'chanspecs' failed, error = %d\n", ret)); goto done; } @@ -6443,23 +3200,32 @@ wl_android_get_band_chanspecs(struct net_device *ndev, void *buf, s32 buflen, ret = wldev_iovar_getint(ndev, "per_chan_info", &channel); if (ret < 0) { - ANDROID_ERROR(("get 'per_chan_info' failed, error = %d\n", ret)); + WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret)); goto done; } if (CHSPEC_IS5G(chanspec) && (CHANNEL_IS_RADAR(channel) || #ifndef ALLOW_5G_ACS - ((acs_req == true) && (CHSPEC_CHANNEL(chanspec) != APCS_DEFAULT_5G_CH)) || + ((acs_req == true) && + !(IS_5G_APCS_CHANNEL(wf_chspec_primary20_chan(chanspec)))) || #endif /* !ALLOW_5G_ACS */ (0))) { continue; } else if (!(CHSPEC_IS2G(chanspec) || CHSPEC_IS5G(chanspec)) && !(CHSPEC_IS_6G_PSC(chanspec))) { continue; +#ifdef WL_UNII4_CHAN + } else if (CHSPEC_IS5G(chanspec) && + IS_UNII4_CHANNEL(wf_chspec_primary20_chan(chanspec))) { + /* Skip UNII-4 channels */ + WL_INFORM_MEM(("Skip UNII-4 chanspec from list : %x\n", + chanspec)); + continue; +#endif /* WL_UNII4_CHAN */ } else { list->element[j] = list->element[i]; - ANDROID_INFO(("Adding chanspec in list : %x\n", list->element[j])); + WL_DBG(("Adding chanspec in list : %x\n", list->element[j])); } j++; @@ -6482,7 +3248,7 @@ wl_android_get_best_channel(struct net_device *ndev, void *buf, int buflen, /* Start auto channel selection scan. */ ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, NULL, 0); if (ret < 0) { - ANDROID_ERROR(("can't start auto channel scan, error = %d\n", ret)); + WL_ERR(("can't start auto channel scan, error = %d\n", ret)); *channel = 0; goto done; } @@ -6496,15 +3262,15 @@ wl_android_get_best_channel(struct net_device *ndev, void *buf, int buflen, ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen)); if ((ret == 0) && (dtoh32(chosen) != 0)) { *channel = (u16)(chosen & 0x00FF); - ANDROID_INFO(("selected channel = %d\n", *channel)); + WL_INFORM_MEM(("selected channel = %d\n", *channel)); break; } - ANDROID_INFO(("attempt = %d, ret = %d, chosen = %d\n", + WL_DBG(("attempt = %d, ret = %d, chosen = %d\n", (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen))); } if (retry <= 0) { - ANDROID_ERROR(("failure, auto channel selection timed out\n")); + WL_ERR(("failure, auto channel selection timed out\n")); *channel = 0; ret = BCME_ERROR; } @@ -6538,7 +3304,7 @@ wl_android_get_best_channels(struct net_device *dev, char* cmd, int total_len) buf = (u8 *)MALLOC(cfg->osh, CHANSPEC_BUF_SIZE); if (buf == NULL) { - ANDROID_ERROR(("failed to allocate chanspec buffer\n")); + WL_ERR(("failed to allocate chanspec buffer\n")); return -ENOMEM; } @@ -6554,7 +3320,7 @@ wl_android_get_best_channels(struct net_device *dev, char* cmd, int total_len) */ ret = wl_android_set_auto_channel_scan_state(ndev); if (ret < 0) { - ANDROID_ERROR(("can't set auto channel scan state, error = %d\n", ret)); + WL_ERR(("can't set auto channel scan state, error = %d\n", ret)); goto done; } @@ -6562,21 +3328,21 @@ wl_android_get_best_channels(struct net_device *dev, char* cmd, int total_len) ret = wl_android_get_band_chanspecs(ndev, (void *)buf, CHANSPEC_BUF_SIZE, WL_CHANSPEC_BAND_2G, false); if (ret < 0) { - ANDROID_ERROR(("can't get chanspecs in 2.4GHz, error = %d\n", ret)); + WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret)); goto done; } ret = wl_android_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE, &channel); if (ret < 0) { - ANDROID_ERROR(("can't select best channel scan in 2.4GHz, error = %d\n", ret)); + WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret)); goto done; } if (CHANNEL_IS_2G(channel)) { channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); } else { - ANDROID_ERROR(("invalid 2.4GHz channel, channel = %d\n", channel)); + WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel)); channel = 0; } @@ -6586,21 +3352,21 @@ wl_android_get_best_channels(struct net_device *dev, char* cmd, int total_len) ret = wl_android_get_band_chanspecs(ndev, (void *)buf, CHANSPEC_BUF_SIZE, WL_CHANSPEC_BAND_5G, false); if (ret < 0) { - ANDROID_ERROR(("can't get chanspecs in 5GHz, error = %d\n", ret)); + WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret)); goto done; } ret = wl_android_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE, &channel); if (ret < 0) { - ANDROID_ERROR(("can't select best channel scan in 5GHz, error = %d\n", ret)); + WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret)); goto done; } if (CHANNEL_IS_5G(channel)) { channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); } else { - ANDROID_ERROR(("invalid 5GHz channel, channel = %d\n", channel)); + WL_ERR(("invalid 5GHz channel, channel = %d\n", channel)); channel = 0; } @@ -6617,7 +3383,7 @@ done: /* Restore FW and driver back to normal state. */ ret = wl_android_restore_auto_channel_scan_state(ndev); if (ret < 0) { - ANDROID_ERROR(("can't restore auto channel scan state, error = %d\n", ret)); + WL_ERR(("can't restore auto channel scan state, error = %d\n", ret)); } return (pos - cmd); @@ -6634,37 +3400,59 @@ wl_android_set_spect(struct net_device *dev, int spect) if (!wl_get_drv_status_all(cfg, CONNECTED)) { err = wldev_ioctl_set(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down)); if (err) { - ANDROID_ERROR(("%s: WLC_DOWN failed: code: %d\n", __func__, err)); + WL_ERR(("%s: WLC_DOWN failed: code: %d\n", __func__, err)); return err; } err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect)); if (err) { - ANDROID_ERROR(("%s: error setting spect: code: %d\n", __func__, err)); + WL_ERR(("%s: error setting spect: code: %d\n", __func__, err)); return err; } err = wldev_ioctl_set(dev, WLC_UP, &wlc_up, sizeof(wlc_up)); if (err) { - ANDROID_ERROR(("%s: WLC_UP failed: code: %d\n", __func__, err)); + WL_ERR(("%s: WLC_UP failed: code: %d\n", __func__, err)); return err; } } return err; } -static int +int wl_android_get_sta_channel(struct bcm_cfg80211 *cfg) { chanspec_t *sta_chanspec = NULL; u32 channel = 0; +#ifdef WL_DUAL_APSTA + if (wl_get_drv_status_all(cfg, CONNECTED) >= 2) { + /* If both STA interfaces are connected return failure */ + return 0; + } else { + struct net_info *iter, *next; + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + for_each_ndev(cfg, iter, next) { + GCC_DIAGNOSTIC_POP(); + if ((iter->ndev) && (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) && + (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION)) { + if ((sta_chanspec = (chanspec_t *)wl_read_prof(cfg, + iter->ndev, WL_PROF_CHAN))) { + channel = wf_chspec_ctlchan(*sta_chanspec); + } + } + } + } +#else if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) { if ((sta_chanspec = (chanspec_t *)wl_read_prof(cfg, bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN))) { channel = wf_chspec_ctlchan(*sta_chanspec); } } +#endif /* WL_DUAL_APSTA */ + return channel; } @@ -6674,18 +3462,18 @@ wl_cfg80211_get_acs_band(int band) chanspec_band_t acs_band = WLC_ACS_BAND_INVALID; switch (band) { case WLC_BAND_AUTO: - ANDROID_INFO(("ACS full channel scan \n")); + WL_DBG(("ACS full channel scan \n")); /* Restricting band to 2G in case of hw_mode any */ acs_band = WL_CHANSPEC_BAND_2G; break; #ifdef WL_6G_BAND case WLC_BAND_6G: - ANDROID_INFO(("ACS 6G band scan \n")); + WL_DBG(("ACS 6G band scan \n")); acs_band = WL_CHANSPEC_BAND_6G; break; #endif /* WL_6G_BAND */ case WLC_BAND_5G: - ANDROID_INFO(("ACS 5G band scan \n")); + WL_DBG(("ACS 5G band scan \n")); acs_band = WL_CHANSPEC_BAND_5G; break; case WLC_BAND_2G: @@ -6693,14 +3481,14 @@ wl_cfg80211_get_acs_band(int band) * If channel argument is not provided/ argument 20 is provided, * Restrict channel to 2GHz, 20MHz BW, No SB */ - ANDROID_INFO(("ACS 2G band scan \n")); + WL_DBG(("ACS 2G band scan \n")); acs_band = WL_CHANSPEC_BAND_2G; break; default: - ANDROID_ERROR(("ACS: No band chosen\n")); + WL_ERR(("ACS: No band chosen\n")); break; } - ANDROID_INFO(("%s: ACS: band = %d, acs_band = 0x%x\n", __FUNCTION__, band, acs_band)); + WL_DBG(("%s: ACS: band = %d, acs_band = 0x%x\n", __FUNCTION__, band, acs_band)); return acs_band; } @@ -6710,24 +3498,28 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, char* command, int total_len) { int channel = 0, sta_channel = 0; + chanspec_t sta_chanspec = 0; int chosen = 0; int retry = 0; int ret = 0; int spect = 0; u8 *reqbuf = NULL; - uint32 band = WLC_BAND_INVALID, sta_band = WLC_BAND_INVALID; + uint32 band = WLC_BAND_INVALID; chanspec_band_t acs_band = WLC_ACS_BAND_INVALID; + chanspec_band_t sta_band = WLC_ACS_BAND_INVALID; uint32 buf_size; struct bcm_cfg80211 *cfg = wl_get_cfg(dev); bool acs_freq_list_present = false; char *pcmd; + int freq = 0; + wl_ap_oper_data_t ap_oper_data = {0}; if (cmd_str) { - ANDROID_INFO(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str))); + WL_INFORM(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str))); pcmd = bcmstrstr(cmd_str, FREQ_STR); if (pcmd) { acs_freq_list_present = true; - ANDROID_INFO(("ACS has freq list\n")); + WL_INFORM_MEM(("ACS has freq list\n")); } else if (strnicmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) { band = WLC_BAND_AUTO; #ifdef WL_6G_BAND @@ -6748,106 +3540,177 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, (channel == APCS_BAND_2G_LEGACY2)) { band = WLC_BAND_2G; } else { - ANDROID_ERROR(("Invalid argument\n")); + WL_ERR(("Invalid argument\n")); return -EINVAL; } } } else { /* If no argument is provided, default to 2G */ - ANDROID_ERROR(("No argument given default to 2.4G scan\n")); + WL_ERR(("No argument given default to 2.4G scan\n")); band = WLC_BAND_2G; } - ANDROID_INFO(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band)); + WL_INFORM(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band)); -#if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL) - wl_cfg80211_register_dev_ril_bridge_event_notifier(); +#ifdef WL_CP_COEX if (band == WLC_BAND_2G) { + (void)memset_s(&g_cx, sizeof(g_cx), 0, sizeof(g_cx)); + wl_cfg80211_register_dev_ril_bridge_event_notifier(); + /* wait 500ms for receiving packet from CP */ wl_cfg80211_send_msg_to_ril(); + wl_cfg80211_unregister_dev_ril_bridge_event_notifier(); - if (g_mhs_chan_for_cpcoex) { - channel = g_mhs_chan_for_cpcoex; - g_mhs_chan_for_cpcoex = 0; + WL_ERR(("[CP_COEX] - Channel:%u\n", g_cx.ch_cpcoex)); + if (g_cx.ch_cpcoex) { + channel = g_cx.ch_cpcoex; + acs_band = WL_CHANSPEC_BAND_2G; goto done2; } } - wl_cfg80211_unregister_dev_ril_bridge_event_notifier(); -#endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */ +#endif /* WL_CP_COEX */ - /* If STA is connected, return is STA channel, else ACS can be issued, + /* Check whether AP is already operational */ + wl_get_ap_chanspecs(cfg, &ap_oper_data); + if (ap_oper_data.count >= MAX_AP_IFACES) { + WL_ERR(("ACS request in multi AP case!! count:%d\n", + ap_oper_data.count)); + return -EINVAL; + } + + if (ap_oper_data.count == 1) { + chanspec_t ch = ap_oper_data.iface[0].chspec; + u16 ap_band; + + /* Single AP case. Bring up the AP in the other band */ + ap_band = CHSPEC_TO_WLC_BAND(ch); + WL_INFORM_MEM(("AP operational in band:%d and incoming band:%d\n", + ap_band, band)); + /* if incoming and operational AP band is same, it is invalid case */ + if (ap_band == band) { + WL_ERR(("DUAL AP not allowed on same band\n")); + goto done2; + } + } + + /* If STA is connected, return is STA chanspec, else ACS can be issued, * set spect to 0 and proceed with ACS */ - sta_channel = wl_android_get_sta_channel(cfg); - sta_band = WL_GET_BAND(sta_channel); - if (sta_channel && (band != WLC_BAND_INVALID)) { + sta_chanspec = wl_cfg80211_get_sta_chanspec(cfg); + if (sta_chanspec) { + if (wf_chspec_valid(sta_chanspec)) { + sta_channel = wf_chspec_ctlchan((chanspec_t)sta_chanspec); + sta_band = CHSPEC_BAND((chanspec_t)sta_chanspec); + WL_DBG(("sta_chanspec = 0x%x, sta_channel = %d, sta_band = 0x%x, " + "sap band = %d\n", sta_chanspec, sta_channel, sta_band, band)); + } else { + WL_ERR(("Invalid sta chanspec 0x%x\n", sta_chanspec)); + return -EINVAL; + } + } + + if ((sta_band != WLC_ACS_BAND_INVALID) && sta_chanspec && (band != WLC_BAND_INVALID)) { switch (sta_band) { - case (WLC_BAND_5G): -#ifdef WL_6G_BAND - case (WLC_BAND_6G): -#endif /* WL_6G_BAND */ - { - if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) { - channel = APCS_DEFAULT_2G_CH; - } else if (band == WLC_BAND_5G) { + case (WL_CHANSPEC_BAND_5G): { + if ((IS_5G_APCS_CHANNEL(sta_channel)) && + (band == WLC_BAND_5G || band == WLC_BAND_AUTO)) { + /* SCC is allowed only for DEF_5G Channel */ channel = sta_channel; + acs_band = sta_band; + } else { + channel = APCS_DEFAULT_2G_CH; + acs_band = wl_cfg80211_get_acs_band(WLC_BAND_2G); } break; } - case (WLC_BAND_2G): { +#ifdef WL_6G_BAND + case (WL_CHANSPEC_BAND_6G): + { + if ((CHSPEC_IS_6G_PSC((chanspec_t)sta_chanspec)) && + (band == WLC_BAND_6G || band == WLC_BAND_AUTO)) { + /* scc */ + channel = sta_channel; + acs_band = sta_band; + } else { + WL_INFORM_MEM(("Fall back to 2g default\n")); + channel = APCS_DEFAULT_2G_CH; + acs_band = wl_cfg80211_get_acs_band(WLC_BAND_2G); + } + break; + } +#endif /* WL_6G_BAND */ + case (WL_CHANSPEC_BAND_2G): { +#ifdef WL_6G_BAND + if (band == WLC_BAND_6G) { + channel = APCS_DEFAULT_6G_CH; + acs_band = wl_cfg80211_get_acs_band(WLC_BAND_6G); + } else +#endif /* WL_6G_BAND */ if (band == WLC_BAND_5G) { channel = APCS_DEFAULT_5G_CH; - } else if (band == WLC_BAND_2G) { - channel = sta_channel; - } + acs_band = wl_cfg80211_get_acs_band(WLC_BAND_5G); + } else if (band == WLC_BAND_AUTO) { #ifdef WL_6G_BAND - else if (band == WLC_BAND_6G) { - channel = APCS_DEFAULT_6G_CH; + if (cfg->band_6g_supported) { + channel = APCS_DEFAULT_6G_CH; + acs_band = wl_cfg80211_get_acs_band(WLC_BAND_6G); + } else { + channel = APCS_DEFAULT_5G_CH; + acs_band = wl_cfg80211_get_acs_band(WLC_BAND_5G); + } +#else + channel = APCS_DEFAULT_5G_CH; + acs_band = wl_cfg80211_get_acs_band(WLC_BAND_5G); +#endif /* WL_6G_BAND */ + } else { + /* scc */ + channel = sta_channel; + acs_band = sta_band; } -#endif /* WL_6G_BAND */ break; } default: /* Intentional fall through to use same sta channel for softap */ channel = sta_channel; + acs_band = sta_band; break; } - WL_MSG(dev->name, "band=%d, sta_band=%d, channel=%d\n", band, sta_band, channel); goto done2; } - /* If AP is started on wlan0 iface, - * do not issue any iovar to fw and choose default ACS channel for softap - */ - if (dev == bcmcfg_to_prmry_ndev(cfg)) { - if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { - ANDROID_INFO(("Softap started on primary iface\n")); - goto done; - } - } - - channel = wl_ext_autochannel(dev, ACS_DRV_BIT, band); + chosen = wl_ext_autochannel(dev, ACS_DRV_BIT, band, NULL); + channel = wf_chspec_ctlchan(chosen); if (channel) { acs_band = CHSPEC_BAND(channel); goto done2; } else goto done; + /* If AP is started on wlan0 iface, + * do not issue any iovar to fw and choose default ACS channel for softap + */ + if (dev == bcmcfg_to_prmry_ndev(cfg)) { + if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { + WL_INFORM_MEM(("Softap started on primary iface\n")); + goto done; + } + } + ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect)); if (ret) { - ANDROID_ERROR(("ACS: error getting the spect, ret=%d\n", ret)); + WL_ERR(("ACS: error getting the spect, ret=%d\n", ret)); goto done; } if (spect > 0) { ret = wl_android_set_spect(dev, 0); if (ret < 0) { - ANDROID_ERROR(("ACS: error while setting spect, ret=%d\n", ret)); + WL_ERR(("ACS: error while setting spect, ret=%d\n", ret)); goto done; } } reqbuf = (u8 *)MALLOCZ(cfg->osh, CHANSPEC_BUF_SIZE); if (reqbuf == NULL) { - ANDROID_ERROR(("failed to allocate chanspec buffer\n")); + WL_ERR(("failed to allocate chanspec buffer\n")); return -ENOMEM; } @@ -6857,29 +3720,32 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, list = (wl_uint32_list_t *)reqbuf; ret = wl_android_get_freq_list_chanspecs(dev, list, CHANSPEC_BUF_SIZE, - cmd_str, sta_channel, wl_cfg80211_get_acs_band(sta_band)); + cmd_str, sta_channel, sta_band); if (ret < 0) { - ANDROID_ERROR(("ACS chanspec set failed!\n")); + WL_ERR(("ACS chanspec set failed!\n")); goto done; } /* skip ACS for single channel case */ if (list->count == 1) { - cfg->acs_chspec = (chanspec_t)list->element[0]; channel = wf_chspec_ctlchan((chanspec_t)list->element[0]); acs_band = CHSPEC_BAND((chanspec_t)list->element[0]); + WL_INFORM_MEM(("chosen acs_chspec = 0x%x, channel =%d, acs_band =0x%x, " + "sta_channel =%d, sta_acs_band = 0x%x\n", + (chanspec_t)list->element[0], channel, acs_band, + sta_channel, sta_band)); goto done2; } } else { acs_band = wl_cfg80211_get_acs_band(band); if (acs_band == WLC_ACS_BAND_INVALID) { - ANDROID_ERROR(("ACS: No band chosen\n")); + WL_ERR(("ACS: No band chosen\n")); goto done2; } if ((ret = wl_android_get_band_chanspecs(dev, reqbuf, CHANSPEC_BUF_SIZE, acs_band, true)) < 0) { - ANDROID_ERROR(("ACS chanspec retrieval failed! \n")); + WL_ERR(("ACS chanspec retrieval failed! \n")); goto done; } } @@ -6888,7 +3754,7 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf, buf_size); if (ret < 0) { - ANDROID_ERROR(("can't start auto channel scan, err = %d\n", ret)); + WL_ERR(("can't start auto channel scan, err = %d\n", ret)); channel = 0; goto done; } @@ -6914,14 +3780,24 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, chosen = dtoh32(chosen); } - if (chosen) { - /* Update chanspec which can be used during softAP bringup with right BW */ - cfg->acs_chspec = chosen; - channel = wf_chspec_ctlchan(chosen); - acs_band = CHSPEC_BAND(chosen); + if (wf_chspec_valid((chanspec_t)chosen)) { +#ifdef WL_6G_BAND + if (CHSPEC_BAND((chanspec_t)chosen) == WL_CHANSPEC_BAND_6G && + cfg->band_6g_supported) { + /* Cache the chanspec for 6g, as fw will choose the BW */ +#if defined(LIMIT_AP_BW) + chosen = (int) wl_cfg80211_get_ap_bw_limited_chspec(cfg, + WL_CHANSPEC_BAND_6G, (chanspec_t) chosen); + +#endif /* LIMIT_AP_BW */ + cfg->acs_chspec = (chanspec_t)chosen; + } +#endif /* WL_6G_BAND */ + channel = wf_chspec_ctlchan((chanspec_t)chosen); + acs_band = CHSPEC_BAND((chanspec_t)chosen); break; } - ANDROID_INFO(("%d tried, ret = %d, chosen = 0x%x, acs_band = 0x%x\n", + WL_DBG(("%d tried, ret = %d, chosen = 0x%x, acs_band = 0x%x\n", (APCS_MAX_RETRY - retry), ret, chosen, acs_band)); OSL_SLEEP(250); } @@ -6938,12 +3814,12 @@ done: } else { channel = APCS_DEFAULT_2G_CH; } - ANDROID_ERROR(("ACS failed. Fall back to default channel (%d) \n", channel)); + WL_ERR(("ACS failed. Fall back to default channel (%d) \n", channel)); } done2: if (spect > 0) { if ((ret = wl_android_set_spect(dev, spect) < 0)) { - ANDROID_ERROR(("ACS: error while setting spect\n")); + WL_ERR(("ACS: error while setting spect\n")); } } @@ -6951,675 +3827,45 @@ done2: MFREE(cfg->osh, reqbuf, CHANSPEC_BUF_SIZE); } - if (channel) { - ret = snprintf(command, total_len, "%d", channel); - ANDROID_INFO(("command result is %s \n", command)); + WL_MSG(dev->name, "band = %d, sta_band=0x%x acs_channel = %d, acs_band = 0x%x\n", + band, sta_band, channel, acs_band); + if (channel && (acs_band != WLC_ACS_BAND_INVALID)) { + freq = wl_channel_to_frequency(channel, wl_cfg80211_get_acs_band(band)); + if (!freq) { + WL_ERR(("ACS: Invalid freq\n")); + return BCME_ERROR; + } + ret = snprintf(command, total_len, "%d freq=%d", channel, freq); + WL_INFORM_MEM(("command result is %s \n", command)); } return ret; } #endif /* WL_SUPPORT_AUTO_CHANNEL */ -#ifdef CUSTOMER_HW4_PRIVATE_CMD -static int -wl_android_set_roam_vsie_enab(struct net_device *dev, const char *cmd, u32 cmd_len) -{ - s32 err = BCME_OK; - u32 roam_vsie_enable = 0; - u32 cmd_str_len = (u32)strlen(CMD_ROAM_VSIE_ENAB_SET); - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - - /* */ - if (!cmd || (cmd_len < (cmd_str_len + 1))) { - ANDROID_ERROR(("wrong arg\n")); - err = -EINVAL; - goto exit; - } - - if (dev != bcmcfg_to_prmry_ndev(cfg)) { - ANDROID_ERROR(("config not supported on non primary i/f\n")); - err = -ENODEV; - goto exit; - } - - roam_vsie_enable = cmd[(cmd_str_len + 1)] - '0'; - if (roam_vsie_enable > 1) { - roam_vsie_enable = 1; - } - - WL_DBG_MEM(("set roam vsie %d\n", roam_vsie_enable)); - err = wldev_iovar_setint(dev, "roam_vsie", roam_vsie_enable); - if (unlikely(err)) { - ANDROID_ERROR(("set roam vsie enable failed. ret:%d\n", err)); - } - -exit: - return err; -} - -static int -wl_android_get_roam_vsie_enab(struct net_device *dev, char *cmd, u32 cmd_len) -{ - s32 err = BCME_OK; - u32 roam_vsie_enable = 0; - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - int bytes_written; - - /* */ - if (!cmd) { - ANDROID_ERROR(("wrong arg\n")); - return -1; - } - - if (dev != bcmcfg_to_prmry_ndev(cfg)) { - ANDROID_ERROR(("config not supported on non primary i/f\n")); - return -1; - } - - err = wldev_iovar_getint(dev, "roam_vsie", &roam_vsie_enable); - if (unlikely(err)) { - ANDROID_ERROR(("get roam vsie enable failed. ret:%d\n", err)); - return -1; - } - ANDROID_INFO(("get roam vsie %d\n", roam_vsie_enable)); - - bytes_written = snprintf(cmd, cmd_len, "%s %d", - CMD_ROAM_VSIE_ENAB_GET, roam_vsie_enable); - - return bytes_written; -} - -static int -wl_android_set_bcn_rpt_vsie_enab(struct net_device *dev, const char *cmd, u32 cmd_len) -{ - s32 err; - u32 bcn_vsie_enable = 0; - u32 cmd_str_len = (u32)strlen(CMD_BR_VSIE_ENAB_SET); - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - - /* */ - if (!cmd || (cmd_len < (cmd_str_len + 1))) { - ANDROID_ERROR(("invalid arg\n")); - err = -EINVAL; - goto exit; - } - - if (dev != bcmcfg_to_prmry_ndev(cfg)) { - ANDROID_ERROR(("config not supported on non primary i/f\n")); - err = -ENODEV; - goto exit; - } - - bcn_vsie_enable = cmd[cmd_str_len + 1] - '0'; - if (bcn_vsie_enable > 1) { - bcn_vsie_enable = 1; - } - - WL_DBG_MEM(("set bcn report vsie %d\n", bcn_vsie_enable)); - err = wldev_iovar_setint(dev, "bcnrpt_vsie_en", bcn_vsie_enable); - if (unlikely(err)) { - ANDROID_ERROR(("set bcn vsie failed. ret:%d\n", err)); - } - -exit: - return err; -} - -static int -wl_android_get_bcn_rpt_vsie_enab(struct net_device *dev, char *cmd, u32 cmd_len) -{ - s32 err = BCME_OK; - u32 bcn_vsie_enable = 0; - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - int bytes_written; - - /* */ - if (!cmd) { - ANDROID_ERROR(("wrong arg\n")); - return -1; - } - - if (dev != bcmcfg_to_prmry_ndev(cfg)) { - ANDROID_ERROR(("config not supported on non primary i/f\n")); - return -1; - } - - err = wldev_iovar_getint(dev, "bcnrpt_vsie_en", &bcn_vsie_enable); - if (unlikely(err)) { - ANDROID_ERROR(("get bcn vsie failed. ret:%d\n", err)); - return -1; - } - ANDROID_INFO(("get bcn report vsie %d\n", bcn_vsie_enable)); - - bytes_written = snprintf(cmd, cmd_len, "%s %d", - CMD_BR_VSIE_ENAB_GET, bcn_vsie_enable); - - return bytes_written; -} - -#ifdef SUPPORT_HIDDEN_AP -static int -wl_android_set_max_num_sta(struct net_device *dev, const char* string_num) -{ - int err = BCME_ERROR; - int max_assoc; - - max_assoc = bcm_atoi(string_num); - ANDROID_INFO(("wl_android_set_max_num_sta : HAPD_MAX_NUM_STA = %d\n", max_assoc)); - - err = wldev_iovar_setint(dev, "maxassoc", max_assoc); - if (err < 0) { - ANDROID_ERROR(("failed to set maxassoc, error:%d\n", err)); - } - - return err; -} - -static int -wl_android_set_ssid(struct net_device *dev, const char* hapd_ssid) -{ - wlc_ssid_t ssid; - s32 ret; - - ssid.SSID_len = strlen(hapd_ssid); - if (ssid.SSID_len == 0) { - ANDROID_ERROR(("wl_android_set_ssids : No SSID\n")); - return -1; - } - if (ssid.SSID_len > DOT11_MAX_SSID_LEN) { - ssid.SSID_len = DOT11_MAX_SSID_LEN; - ANDROID_ERROR(("wl_android_set_ssid : Too long SSID Length %zu\n", strlen(hapd_ssid))); - } - bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len); - ANDROID_INFO(("wl_android_set_ssid: HAPD_SSID = %s\n", ssid.SSID)); - ret = wldev_ioctl_set(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t)); - if (ret < 0) { - ANDROID_ERROR(("wl_android_set_ssid : WLC_SET_SSID Error:%d\n", ret)); - } - return 1; - -} - -static int -wl_android_set_hide_ssid(struct net_device *dev, const char* string_num) -{ - int hide_ssid; - int enable = 0; - int err = BCME_ERROR; - - hide_ssid = bcm_atoi(string_num); - ANDROID_INFO(("wl_android_set_hide_ssid: HAPD_HIDE_SSID = %d\n", hide_ssid)); - if (hide_ssid) { - enable = 1; - } - - err = wldev_iovar_setint(dev, "closednet", enable); - if (err < 0) { - ANDROID_ERROR(("failed to set closednet, error:%d\n", err)); - } - - return err; -} -#endif /* SUPPORT_HIDDEN_AP */ - -#ifdef SUPPORT_SOFTAP_SINGL_DISASSOC -static int -wl_android_sta_diassoc(struct net_device *dev, const char* straddr) -{ - scb_val_t scbval; - int error = 0; - - ANDROID_INFO(("wl_android_sta_diassoc: deauth STA %s\n", straddr)); - - /* Unspecified reason */ - scbval.val = htod32(1); - - if (bcm_ether_atoe(straddr, &scbval.ea) == 0) { - ANDROID_ERROR(("wl_android_sta_diassoc: Invalid station MAC Address!!!\n")); - return -1; - } - - ANDROID_ERROR(("wl_android_sta_diassoc: deauth STA: "MACDBG " scb_val.val %d\n", - MAC2STRDBG(scbval.ea.octet), scbval.val)); - - error = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, - sizeof(scb_val_t)); - if (error) { - ANDROID_ERROR(("Fail to DEAUTH station, error = %d\n", error)); - } - - return 1; -} -#endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */ - -#ifdef SUPPORT_SET_LPC -static int -wl_android_set_lpc(struct net_device *dev, const char* string_num) -{ - int lpc_enabled, ret; - s32 val = 1; - - lpc_enabled = bcm_atoi(string_num); - ANDROID_INFO(("wl_android_set_lpc: HAPD_LPC_ENABLED = %d\n", lpc_enabled)); - - ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32)); - if (ret < 0) - ANDROID_ERROR(("WLC_DOWN error %d\n", ret)); - - wldev_iovar_setint(dev, "lpc", lpc_enabled); - - ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32)); - if (ret < 0) - ANDROID_ERROR(("WLC_UP error %d\n", ret)); - - return 1; -} -#endif /* SUPPORT_SET_LPC */ - -static int -wl_android_ch_res_rl(struct net_device *dev, bool change) -{ - int error = 0; - s32 srl = 7; - s32 lrl = 4; - ANDROID_ERROR(("wl_android_ch_res_rl: enter\n")); - if (change) { - srl = 4; - lrl = 2; - } - - BCM_REFERENCE(lrl); - - error = wldev_ioctl_set(dev, WLC_SET_SRL, &srl, sizeof(s32)); - if (error) { - ANDROID_ERROR(("Failed to set SRL, error = %d\n", error)); - } -#ifndef CUSTOM_LONG_RETRY_LIMIT - error = wldev_ioctl_set(dev, WLC_SET_LRL, &lrl, sizeof(s32)); - if (error) { - ANDROID_ERROR(("Failed to set LRL, error = %d\n", error)); - } -#endif /* CUSTOM_LONG_RETRY_LIMIT */ - return error; -} - -#ifdef SUPPORT_LTECX -#define DEFAULT_WLANRX_PROT 1 -#define DEFAULT_LTERX_PROT 0 -#define DEFAULT_LTETX_ADV 1200 - -static int -wl_android_set_ltecx(struct net_device *dev, const char* string_num) -{ - uint16 chan_bitmap; - int ret; - - chan_bitmap = bcm_strtoul(string_num, NULL, 16); - - ANDROID_INFO(("wl_android_set_ltecx: LTECOEX 0x%x\n", chan_bitmap)); - - if (chan_bitmap) { - ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap); - if (ret < 0) { - ANDROID_ERROR(("mws_coex_bitmap error %d\n", ret)); - } - - ret = wldev_iovar_setint(dev, "mws_wlanrx_prot", DEFAULT_WLANRX_PROT); - if (ret < 0) { - ANDROID_ERROR(("mws_wlanrx_prot error %d\n", ret)); - } - - ret = wldev_iovar_setint(dev, "mws_lterx_prot", DEFAULT_LTERX_PROT); - if (ret < 0) { - ANDROID_ERROR(("mws_lterx_prot error %d\n", ret)); - } - - ret = wldev_iovar_setint(dev, "mws_ltetx_adv", DEFAULT_LTETX_ADV); - if (ret < 0) { - ANDROID_ERROR(("mws_ltetx_adv error %d\n", ret)); - } - } else { - ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap); - if (ret < 0) { - if (ret == BCME_UNSUPPORTED) { - ANDROID_ERROR(("LTECX_CHAN_BITMAP is UNSUPPORTED\n")); - } else { - ANDROID_ERROR(("LTECX_CHAN_BITMAP error %d\n", ret)); - } - } - } - return 1; -} -#endif /* SUPPORT_LTECX */ - -#ifdef WL_RELMCAST -static int -wl_android_rmc_enable(struct net_device *net, int rmc_enable) -{ - int err; - - err = wldev_iovar_setint(net, "rmc_ackreq", rmc_enable); - if (err != BCME_OK) { - ANDROID_ERROR(("wl_android_rmc_enable: rmc_ackreq, error = %d\n", err)); - } - return err; -} - -static int -wl_android_rmc_set_leader(struct net_device *dev, const char* straddr) -{ - int error = BCME_OK; - char smbuf[WLC_IOCTL_SMLEN]; - wl_rmc_entry_t rmc_entry; - ANDROID_INFO(("wl_android_rmc_set_leader: Set new RMC leader %s\n", straddr)); - - bzero(&rmc_entry, sizeof(wl_rmc_entry_t)); - if (!bcm_ether_atoe(straddr, &rmc_entry.addr)) { - if (strlen(straddr) == 1 && bcm_atoi(straddr) == 0) { - ANDROID_INFO(("wl_android_rmc_set_leader: Set auto leader selection mode\n")); - bzero(&rmc_entry, sizeof(wl_rmc_entry_t)); - } else { - ANDROID_ERROR(("wl_android_rmc_set_leader: No valid mac address provided\n")); - return BCME_ERROR; - } - } - - error = wldev_iovar_setbuf(dev, "rmc_ar", &rmc_entry, sizeof(wl_rmc_entry_t), - smbuf, sizeof(smbuf), NULL); - - if (error != BCME_OK) { - ANDROID_ERROR(("wl_android_rmc_set_leader: Unable to set RMC leader, error = %d\n", - error)); - } - - return error; -} - -static int wl_android_set_rmc_event(struct net_device *dev, char *command) -{ - int err = 0; - int pid = 0; - - if (sscanf(command, CMD_SET_RMC_EVENT " %d", &pid) <= 0) { - ANDROID_ERROR(("Failed to get Parameter from : %s\n", command)); - return -1; - } - - /* set pid, and if the event was happened, let's send a notification through netlink */ - wl_cfg80211_set_rmc_pid(dev, pid); - - ANDROID_INFO(("RMC pid=%d\n", pid)); - - return err; -} -#endif /* WL_RELMCAST */ - -int wl_android_get_singlecore_scan(struct net_device *dev, char *command, int total_len) -{ - int error = 0; - int bytes_written = 0; - int mode = 0; - - error = wldev_iovar_getint(dev, "scan_ps", &mode); - if (error) { - ANDROID_ERROR(("wl_android_get_singlecore_scan: Failed to get single core scan Mode," - " error = %d\n", - error)); - return -1; - } - - bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_SCSCAN, mode); - - return bytes_written; -} - -int wl_android_set_singlecore_scan(struct net_device *dev, char *command) -{ - int error = 0; - int mode = 0; - - if (sscanf(command, "%*s %d", &mode) != 1) { - ANDROID_ERROR(("wl_android_set_singlecore_scan: Failed to get Parameter\n")); - return -1; - } - - error = wldev_iovar_setint(dev, "scan_ps", mode); - if (error) { - ANDROID_ERROR(("wl_android_set_singlecore_scan[1]: Failed to set Mode %d, error = %d\n", - mode, error)); - return -1; - } - - return error; -} -#ifdef TEST_TX_POWER_CONTROL -static int -wl_android_set_tx_power(struct net_device *dev, const char* string_num) -{ - int err = 0; - s32 dbm; - enum nl80211_tx_power_setting type; - - dbm = bcm_atoi(string_num); - - if (dbm < -1) { - ANDROID_ERROR(("wl_android_set_tx_power: dbm is negative...\n")); - return -EINVAL; - } - - if (dbm == -1) - type = NL80211_TX_POWER_AUTOMATIC; - else - type = NL80211_TX_POWER_FIXED; - - err = wl_set_tx_power(dev, type, dbm); - if (unlikely(err)) { - ANDROID_ERROR(("wl_android_set_tx_power: error (%d)\n", err)); - return err; - } - - return 1; -} - -static int -wl_android_get_tx_power(struct net_device *dev, char *command, int total_len) -{ - int err; - int bytes_written; - s32 dbm = 0; - - err = wl_get_tx_power(dev, &dbm); - if (unlikely(err)) { - ANDROID_ERROR(("wl_android_get_tx_power: error (%d)\n", err)); - return err; - } - - bytes_written = snprintf(command, total_len, "%s %d", - CMD_TEST_GET_TX_POWER, dbm); - - ANDROID_ERROR(("wl_android_get_tx_power: GET_TX_POWER: dBm=%d\n", dbm)); - - return bytes_written; -} -#endif /* TEST_TX_POWER_CONTROL */ - -static int -wl_android_set_sarlimit_txctrl(struct net_device *dev, const char* string_num) -{ - int err = BCME_ERROR; - int setval = 0; - s32 mode = bcm_atoi(string_num); - s32 mode_bit = 0; - int enab = 0; - - /* As Samsung specific and their requirement, - * the mode set as the following form. - * -1 : HEAD SAR disabled - * 0 : HEAD SAR enabled - * 1 : GRIP SAR disabled - * 2 : GRIP SAR enabled - * 3 : NR mmWave SAR disabled - * 4 : NR mmWave SAR enabled - * 5 : NR Sub6 SAR disabled - * 6 : NR Sub6 SAR enabled - * 7 : SAR BACKOFF disabled all - * The 'SAR BACKOFF disabled all' index should be the end of the mode. - */ - if ((mode < HEAD_SAR_BACKOFF_DISABLE) || (mode > SAR_BACKOFF_DISABLE_ALL)) { - ANDROID_ERROR(("%s: Request for Unsupported:%d\n", __FUNCTION__, bcm_atoi(string_num))); - err = BCME_RANGE; - goto error; - } - - mode_bit = mode + 1; - enab = mode_bit % 2; - mode_bit = mode_bit / 2; - - err = wldev_iovar_getint(dev, "sar_enable", &setval); - if (unlikely(err)) { - ANDROID_ERROR(("%s: Failed to get sar_enable - error (%d)\n", __FUNCTION__, err)); - goto error; - } - - if (mode == SAR_BACKOFF_DISABLE_ALL) { - ANDROID_ERROR(("%s: SAR limit control all mode disable!\n", __FUNCTION__)); - setval = 0; - } else { - ANDROID_ERROR(("%s: SAR limit control mode %d enab %d\n", - __FUNCTION__, mode_bit, enab)); - if (enab) { - setval |= (1 << mode_bit); - } else { - setval &= ~(1 << mode_bit); - } - } - - err = wldev_iovar_setint(dev, "sar_enable", setval); - if (unlikely(err)) { - ANDROID_ERROR(("%s: Failed to set sar_enable - error (%d)\n", __FUNCTION__, err)); - goto error; - } - err = BCME_OK; -error: - return err; -} - -#ifdef SUPPORT_SET_TID -static int -wl_android_set_tid(struct net_device *dev, char* command) -{ - int err = BCME_ERROR; - char *pos = command; - char *token = NULL; - uint8 mode = 0; - uint32 uid = 0; - uint8 prio = 0; - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); - - if (!dhdp) { - ANDROID_ERROR(("dhd is NULL\n")); - return err; - } - - ANDROID_INFO(("%s: command[%s]\n", __FUNCTION__, command)); - - /* drop command */ - token = bcmstrtok(&pos, " ", NULL); - - token = bcmstrtok(&pos, " ", NULL); - if (!token) { - ANDROID_ERROR(("Invalid arguments\n")); - return err; - } - - mode = bcm_atoi(token); - - if (mode < SET_TID_OFF || mode > SET_TID_BASED_ON_UID) { - ANDROID_ERROR(("Invalid arguments, mode %d\n", mode)); - return err; - } - - if (mode) { - token = bcmstrtok(&pos, " ", NULL); - if (!token) { - ANDROID_ERROR(("Invalid arguments for target uid\n")); - return err; - } - - uid = bcm_atoi(token); - - token = bcmstrtok(&pos, " ", NULL); - if (!token) { - ANDROID_ERROR(("Invalid arguments for target tid\n")); - return err; - } - - prio = bcm_atoi(token); - if (prio >= 0 && prio <= MAXPRIO) { - dhdp->tid_mode = mode; - dhdp->target_uid = uid; - dhdp->target_tid = prio; - } else { - ANDROID_ERROR(("Invalid arguments, prio %d\n", prio)); - return err; - } - } else { - dhdp->tid_mode = SET_TID_OFF; - dhdp->target_uid = 0; - dhdp->target_tid = 0; - } - - ANDROID_INFO(("%s mode [%d], uid [%d], tid [%d]\n", __FUNCTION__, - dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid)); - - err = BCME_OK; - return err; -} - -static int -wl_android_get_tid(struct net_device *dev, char* command, int total_len) -{ - int bytes_written = BCME_ERROR; - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); - - if (!dhdp) { - ANDROID_ERROR(("dhd is NULL\n")); - return bytes_written; - } - - bytes_written = snprintf(command, total_len, "mode %d uid %d tid %d", - dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid); - - ANDROID_INFO(("%s: command results %s\n", __FUNCTION__, command)); - - return bytes_written; -} -#endif /* SUPPORT_SET_TID */ -#endif /* CUSTOMER_HW4_PRIVATE_CMD */ - int wl_android_set_roam_mode(struct net_device *dev, char *command) { - int error = 0; + int error = BCME_OK; int mode = 0; if (sscanf(command, "%*s %d", &mode) != 1) { - ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); - return -1; + DHD_ERROR(("wl_android_set_roam_mode: Failed to get Parameter\n")); + return BCME_ERROR; } error = wldev_iovar_setint(dev, "roam_off", mode); if (error) { - ANDROID_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n", - __FUNCTION__, mode, error)); - return -1; + WL_ERR(("Failed to set roaming Mode %d, error = %d\n", + mode, error)); + } else { + WL_ERR(("succeeded to set roaming Mode %d,error = %d\n", + mode, error)); + ROAMOFF_DBG_SAVE(dev, SET_ROAM_ROAMMODE, mode); } - else - ANDROID_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n", - __FUNCTION__, mode, error)); - return 0; + + return error; } -#ifdef WL_CFG80211 int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len) { char ie_buf[VNDR_IE_MAX_LEN]; @@ -7641,14 +3887,14 @@ int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, in } if (total_len < (strlen(CMD_SETIBSSBEACONOUIDATA) + 1)) { - ANDROID_ERROR(("error. total_len:%d\n", total_len)); + WL_ERR(("error. total_len:%d\n", total_len)); return -EINVAL; } pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1; for (idx = 0; idx < DOT11_OUI_LEN; idx++) { if (*pcmd == '\0') { - ANDROID_ERROR(("error while parsing OUI.\n")); + WL_ERR(("error while parsing OUI.\n")); return -EINVAL; } hex[0] = *pcmd++; @@ -7664,14 +3910,14 @@ int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, in } if (datalen <= 0) { - ANDROID_ERROR(("error. vndr ie len:%d\n", datalen)); + WL_ERR(("error. vndr ie len:%d\n", datalen)); return -EINVAL; } tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (datalen - 1)); vndr_ie = (vndr_ie_setbuf_t *)MALLOCZ(cfg->osh, tot_len); if (!vndr_ie) { - ANDROID_ERROR(("IE memory alloc failed\n")); + WL_ERR(("IE memory alloc failed\n")); return -ENOMEM; } /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ @@ -7698,7 +3944,7 @@ int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, in ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN); if (!ioctl_buf) { - ANDROID_ERROR(("ioctl memory alloc failed\n")); + WL_ERR(("ioctl memory alloc failed\n")); if (vndr_ie) { MFREE(cfg->osh, vndr_ie, tot_len); } @@ -7706,7 +3952,7 @@ int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, in } bzero(ioctl_buf, WLC_IOCTL_MEDLEN); /* init the buffer */ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { - ANDROID_ERROR(("Find index failed\n")); + WL_ERR(("Find index failed\n")); err = BCME_ERROR; goto end; } @@ -7730,7 +3976,6 @@ end: return err; } -#endif /* WL_CFG80211 */ #if defined(BCMFW_ROAM_ENABLE) static int @@ -7738,7 +3983,7 @@ wl_android_set_roampref(struct net_device *dev, char *command, int total_len) { int error = 0; char smbuf[WLC_IOCTL_SMLEN]; - uint8 buf[MAX_BUF_SIZE]; + uint8 buf[JOIN_PREF_MAX_BUF_SIZE]; uint8 *pref = buf; char *pcmd; int num_ucipher_suites = 0; @@ -7756,7 +4001,7 @@ wl_android_set_roampref(struct net_device *dev, char *command, int total_len) num_akm_suites = simple_strtoul(pcmd, NULL, 16); if (num_akm_suites > MAX_NUM_SUITES) { - ANDROID_ERROR(("too many AKM suites = %d\n", num_akm_suites)); + DHD_ERROR(("too many AKM suites = %d\n", num_akm_suites)); return -1; } @@ -7836,7 +4081,8 @@ wl_android_set_roampref(struct net_device *dev, char *command, int total_len) total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples); } else { - ANDROID_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__)); + DHD_ERROR(("wl_android_set_roampref: Too many wpa configs" + " for join_pref \n")); return -1; } } else { @@ -7860,13 +4106,12 @@ wl_android_set_roampref(struct net_device *dev, char *command, int total_len) prhex("join pref", (uint8 *)buf, total_bytes); error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL); if (error) { - ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error)); + DHD_ERROR(("Failed to set join_pref, error = %d\n", error)); } return error; } #endif /* defined(BCMFW_ROAM_ENABLE */ -#ifdef WL_CFG80211 static int wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config) { @@ -7881,19 +4126,23 @@ wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_ if (config->iovar) { ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param); if (ret) { - ANDROID_ERROR(("%s: Failed to get current %s value\n", - __FUNCTION__, config->iovar)); + DHD_ERROR(("wl_android_iolist_add: Failed to get current %s value\n", + config->iovar)); goto error; } ret = wldev_iovar_setint(dev, config->iovar, config->param); if (ret) { - ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, + DHD_ERROR(("wl_android_iolist_add: Failed to set %s to %d\n", config->iovar, config->param)); goto error; } - resume_cfg->iovar = config->iovar; +#ifdef DEBUG_SETROAMMODE + if (strnicmp(config->iovar, CMD_ROAMOFF, strlen(CMD_ROAMOFF)) == 0) { + ROAMOFF_DBG_SAVE(dev, SET_ROAM_IOLIST_ADD, config->param); + } +#endif /* DEBUG_SETROAMMODE */ } else { resume_cfg->arg = MALLOCZ(cfg->osh, config->len); if (!resume_cfg->arg) { @@ -7902,13 +4151,13 @@ wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_ } ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len); if (ret) { - ANDROID_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__, + DHD_ERROR(("wl_android_iolist_add: Failed to get ioctl %d\n", config->ioctl)); goto error; } ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len); if (ret) { - ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, + DHD_ERROR(("wl_android_iolist_add: Failed to set %s to %d\n", config->iovar, config->param)); goto error; } @@ -7940,9 +4189,17 @@ wl_android_iolist_resume(struct net_device *dev, struct list_head *head) config = list_entry(cur, struct io_cfg, list); GCC_DIAGNOSTIC_POP(); if (config->iovar) { - if (!ret) + if (!ret) { ret = wldev_iovar_setint(dev, config->iovar, config->param); +#ifdef DEBUG_SETROAMMODE + if (strnicmp(config->iovar, CMD_ROAMOFF, + strlen(CMD_ROAMOFF)) == 0) { + ROAMOFF_DBG_SAVE(dev, SET_ROAM_IOLIST_RESUME, + config->param); + } +#endif /* DEBUG_SETROAMMODE */ + } } else { if (!ret) ret = wldev_ioctl_set(dev, config->ioctl + 1, @@ -7964,11 +4221,11 @@ wl_android_set_miracast(struct net_device *dev, char *command) struct io_cfg config; if (sscanf(command, "%*s %d", &mode) != 1) { - ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + DHD_ERROR(("wl_android_set_miracasts: Failed to get Parameter\n")); return -1; } - ANDROID_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode)); + DHD_INFO(("wl_android_set_miracast: enter miracast mode %d\n", mode)); if (miracast_cur_mode == mode) { return 0; @@ -7990,9 +4247,9 @@ wl_android_set_miracast(struct net_device *dev, char *command) ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int)); if (!ret && val > 100) { config.param = 0; - ANDROID_ERROR(("%s: Connected station's beacon interval: " + DHD_ERROR(("wl_android_set_miracast: Connected station's beacon interval: " "%d and set mchan_algo to %d \n", - __FUNCTION__, val, config.param)); + val, config.param)); } else { config.param = MIRACAST_MCHAN_ALGO; } @@ -8025,6 +4282,8 @@ wl_android_set_miracast(struct net_device *dev, char *command) /* Source mode shares most configurations with sink mode. * Fall through here to avoid code duplication */ + fallthrough; + case MIRACAST_MODE_SINK: /* disable internal roaming */ config.iovar = "roam_off"; @@ -8036,39 +4295,6 @@ wl_android_set_miracast(struct net_device *dev, char *command) goto resume; } -#ifdef CUSTOMER_HW10 - /* [CSP#812738] Change scan engine parameters to reduce scan time - * and guarantee more times to mirroring. - */ - val = 10; - config.iovar = NULL; - config.ioctl = WLC_GET_SCAN_CHANNEL_TIME; - config.arg = &val; - config.len = sizeof(int); - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) - goto resume; - - val = 180; - config.iovar = NULL; - config.ioctl = WLC_GET_SCAN_HOME_TIME; - config.arg = &val; - config.len = sizeof(int); - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - if (ret) - goto resume; - -#if defined(BCM4339_CHIP) - config.iovar = "phy_watchdog"; - config.param = 0; - ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); - ANDROID_INFO(("%s: do iovar cmd=%s (ret=%d)\n", - __FUNCTION__, config.iovar, ret)); -#endif -#endif /* CUSTOMER_HW10 */ - -#ifndef CUSTOMER_HW10 - /* tunr off pm */ ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val)); if (ret) { @@ -8086,7 +4312,6 @@ wl_android_set_miracast(struct net_device *dev, char *command) goto resume; } } -#endif /* CUSTOMER_HW10 */ break; case MIRACAST_MODE_OFF: default: @@ -8097,13 +4322,11 @@ wl_android_set_miracast(struct net_device *dev, char *command) return 0; resume: - ANDROID_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret)); + DHD_ERROR(("wl_android_set_miracast: turnoff miracast mode because of err%d\n", ret)); wl_android_iolist_resume(dev, &miracast_resume_list); return ret; } -#endif /* WL_CFG80211 */ -#ifdef WL_RELMCAST #define NETLINK_OXYGEN 30 #define AIBSS_BEACON_TIMEOUT 10 @@ -8111,7 +4334,7 @@ static struct sock *nl_sk = NULL; static void wl_netlink_recv(struct sk_buff *skb) { - ANDROID_ERROR(("netlink_recv called\n")); + WL_ERR(("netlink_recv called\n")); } static int wl_netlink_init(void) @@ -8123,7 +4346,7 @@ static int wl_netlink_init(void) #endif if (nl_sk != NULL) { - ANDROID_ERROR(("nl_sk already exist\n")); + WL_ERR(("nl_sk already exist\n")); return BCME_ERROR; } @@ -8137,7 +4360,7 @@ static int wl_netlink_init(void) #endif if (nl_sk == NULL) { - ANDROID_ERROR(("nl_sk is not ready\n")); + WL_ERR(("nl_sk is not ready\n")); return BCME_ERROR; } @@ -8160,19 +4383,19 @@ wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size) int ret = -1; if (nl_sk == NULL) { - ANDROID_ERROR(("nl_sk was not initialized\n")); + WL_ERR(("nl_sk was not initialized\n")); goto nlmsg_failure; } skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC); if (skb == NULL) { - ANDROID_ERROR(("failed to allocate memory\n")); + WL_ERR(("failed to allocate memory\n")); goto nlmsg_failure; } nlh = nlmsg_put(skb, 0, 0, 0, size, 0); if (nlh == NULL) { - ANDROID_ERROR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n", + WL_ERR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n", skb_tailroom(skb), nlmsg_total_size(size))); dev_kfree_skb(skb); goto nlmsg_failure; @@ -8184,368 +4407,52 @@ wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size) /* netlink_unicast() takes ownership of the skb and frees it itself. */ ret = netlink_unicast(nl_sk, skb, pid, 0); - ANDROID_INFO(("netlink_unicast() pid=%d, ret=%d\n", pid, ret)); + WL_DBG(("netlink_unicast() pid=%d, ret=%d\n", pid, ret)); nlmsg_failure: return ret; } -#endif /* WL_RELMCAST */ - -#ifdef WLAIBSS -static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len) -{ - int err = 0; - int retry = 0; - int pid = 0; - aibss_txfail_config_t txfail_config = {0, 0, 0, 0, 0}; - char smbuf[WLC_IOCTL_SMLEN]; - - if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) { - ANDROID_ERROR(("Failed to get Parameter from : %s\n", command)); - return -1; - } - - /* set pid, and if the event was happened, let's send a notification through netlink */ - wl_cfg80211_set_txfail_pid(dev, pid); - -#ifdef WL_RELMCAST - /* using same pid for RMC, AIBSS shares same pid with RMC and it is set once */ - wl_cfg80211_set_rmc_pid(dev, pid); -#endif /* WL_RELMCAST */ - - /* If retry value is 0, it disables the functionality for TX Fail. */ - if (retry > 0) { - txfail_config.max_tx_retry = retry; - txfail_config.bcn_timeout = 0; /* 0 : disable tx fail from beacon */ - } - txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0; - txfail_config.len = sizeof(txfail_config); - - err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config, - sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL); - ANDROID_INFO(("retry=%d, pid=%d, err=%d\n", retry, pid, err)); - - return ((err == 0)?total_len:err); -} - -static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command, - int total_len, bool bAll) -{ - int error; - int bytes_written = 0; - void *buf = NULL; - bss_peer_list_info_t peer_list_info; - bss_peer_info_t *peer_info; - int i; - bool found = false; - struct ether_addr mac_ea; - char *str = command; - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - - ANDROID_INFO(("get ibss peer info(%s)\n", bAll?"true":"false")); - - if (!bAll) { - if (bcmstrtok(&str, " ", NULL) == NULL) { - ANDROID_ERROR(("invalid command\n")); - return -1; - } - - if (!str || !bcm_ether_atoe(str, &mac_ea)) { - ANDROID_ERROR(("invalid MAC address\n")); - return -1; - } - } - - if ((buf = MALLOC(cfg->osh, WLC_IOCTL_MAXLEN)) == NULL) { - ANDROID_ERROR(("kmalloc failed\n")); - return -1; - } - - error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL); - if (unlikely(error)) { - ANDROID_ERROR(("could not get ibss peer info (%d)\n", error)); - MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN); - return -1; - } - - memcpy(&peer_list_info, buf, sizeof(peer_list_info)); - peer_list_info.version = htod16(peer_list_info.version); - peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len); - peer_list_info.count = htod32(peer_list_info.count); - - ANDROID_INFO(("ver:%d, len:%d, count:%d\n", peer_list_info.version, - peer_list_info.bss_peer_info_len, peer_list_info.count)); - - if (peer_list_info.count > 0) { - if (bAll) - bytes_written += snprintf(&command[bytes_written], total_len, "%u ", - peer_list_info.count); - - peer_info = (bss_peer_info_t *) ((char *)buf + BSS_PEER_LIST_INFO_FIXED_LEN); - - for (i = 0; i < peer_list_info.count; i++) { - - ANDROID_INFO(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi, - peer_info->tx_rate, peer_info->rx_rate)); - - if (!bAll && - memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) { - found = true; - } - - if (bAll || found) { - bytes_written += snprintf(&command[bytes_written], - total_len - bytes_written, - MACF" %u %d ", ETHER_TO_MACF(peer_info->ea), - peer_info->tx_rate/1000, peer_info->rssi); - if (bytes_written >= total_len) { - ANDROID_ERROR(("wl_android_get_ibss_peer_info: Insufficient" - " memory, %d bytes\n", - total_len)); - bytes_written = -1; - break; - } - } - - if (found) - break; - - peer_info = (bss_peer_info_t *)((char *)peer_info+sizeof(bss_peer_info_t)); - } - } - else { - ANDROID_ERROR(("could not get ibss peer info : no item\n")); - } - ANDROID_INFO(("command(%u):%s\n", total_len, command)); - ANDROID_INFO(("bytes_written:%d\n", bytes_written)); - - MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN); - return bytes_written; -} - -int wl_android_set_ibss_routetable(struct net_device *dev, char *command) -{ - - char *pcmd = command; - char *str = NULL; - ibss_route_tbl_t *route_tbl = NULL; - char *ioctl_buf = NULL; - s32 err = BCME_OK; - uint32 route_tbl_len; - uint32 entries; - char *endptr; - uint32 i = 0; - struct ipv4_addr dipaddr; - struct ether_addr ea; - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - - route_tbl_len = sizeof(ibss_route_tbl_t) + - (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t); - route_tbl = (ibss_route_tbl_t *)MALLOCZ(cfg->osh, route_tbl_len); - if (!route_tbl) { - ANDROID_ERROR(("Route TBL alloc failed\n")); - return -ENOMEM; - } - ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); - if (!ioctl_buf) { - ANDROID_ERROR(("ioctl memory alloc failed\n")); - if (route_tbl) { - MFREE(cfg->osh, route_tbl, route_tbl_len); - } - return -ENOMEM; - } - bzero(ioctl_buf, WLC_IOCTL_MEDLEN); - - /* drop command */ - str = bcmstrtok(&pcmd, " ", NULL); - - /* get count */ - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - ANDROID_ERROR(("Invalid number parameter %s\n", str)); - err = -EINVAL; - goto exit; - } - entries = bcm_strtoul(str, &endptr, 0); - if (*endptr != '\0') { - ANDROID_ERROR(("Invalid number parameter %s\n", str)); - err = -EINVAL; - goto exit; - } - if (entries > MAX_IBSS_ROUTE_TBL_ENTRY) { - ANDROID_ERROR(("Invalid entries number %u\n", entries)); - err = -EINVAL; - goto exit; - } - - ANDROID_INFO(("Routing table count:%u\n", entries)); - route_tbl->num_entry = entries; - - for (i = 0; i < entries; i++) { - str = bcmstrtok(&pcmd, " ", NULL); - if (!str || !bcm_atoipv4(str, &dipaddr)) { - ANDROID_ERROR(("Invalid ip string %s\n", str)); - err = -EINVAL; - goto exit; - } - - str = bcmstrtok(&pcmd, " ", NULL); - if (!str || !bcm_ether_atoe(str, &ea)) { - ANDROID_ERROR(("Invalid ethernet string %s\n", str)); - err = -EINVAL; - goto exit; - } - bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN); - bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN); - } - - route_tbl_len = sizeof(ibss_route_tbl_t) + - ((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t)); - err = wldev_iovar_setbuf(dev, "ibss_route_tbl", - route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - if (err != BCME_OK) { - ANDROID_ERROR(("Fail to set iovar %d\n", err)); - err = -EINVAL; - } - -exit: - if (route_tbl) { - MFREE(cfg->osh, route_tbl, sizeof(ibss_route_tbl_t) + - (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t)); - } - if (ioctl_buf) { - MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); - } - return err; - -} - -int -wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len) -{ - char *pcmd = command; - char *str = NULL, *endptr = NULL; - struct ampdu_aggr aggr; - char smbuf[WLC_IOCTL_SMLEN]; - int idx; - int err = 0; - int wme_AC2PRIO[AC_COUNT][2] = { - {PRIO_8021D_VO, PRIO_8021D_NC}, /* AC_VO - 3 */ - {PRIO_8021D_CL, PRIO_8021D_VI}, /* AC_VI - 2 */ - {PRIO_8021D_BK, PRIO_8021D_NONE}, /* AC_BK - 1 */ - {PRIO_8021D_BE, PRIO_8021D_EE}}; /* AC_BE - 0 */ - - ANDROID_INFO(("set ibss ampdu:%s\n", command)); - - bzero(&aggr, sizeof(aggr)); - /* Cofigure all priorities */ - aggr.conf_TID_bmap = NBITMASK(NUMPRIO); - - /* acquire parameters */ - /* drop command */ - str = bcmstrtok(&pcmd, " ", NULL); - - for (idx = 0; idx < AC_COUNT; idx++) { - bool on; - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - ANDROID_ERROR(("Invalid parameter : %s\n", pcmd)); - return -EINVAL; - } - on = bcm_strtoul(str, &endptr, 0) ? TRUE : FALSE; - if (*endptr != '\0') { - ANDROID_ERROR(("Invalid number format %s\n", str)); - return -EINVAL; - } - if (on) { - setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][0]); - setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][1]); - } - } - - err = wldev_iovar_setbuf(dev, "ampdu_txaggr", (void *)&aggr, - sizeof(aggr), smbuf, WLC_IOCTL_SMLEN, NULL); - - return ((err == 0) ? total_len : err); -} - -int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len) -{ - char *pcmd = command; - char *str = NULL; - int txchain, rxchain; - int err = 0; - - ANDROID_INFO(("set ibss antenna:%s\n", command)); - - /* acquire parameters */ - /* drop command */ - str = bcmstrtok(&pcmd, " ", NULL); - - /* TX chain */ - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - ANDROID_ERROR(("Invalid parameter : %s\n", pcmd)); - return -EINVAL; - } - txchain = bcm_atoi(str); - - /* RX chain */ - str = bcmstrtok(&pcmd, " ", NULL); - if (!str) { - ANDROID_ERROR(("Invalid parameter : %s\n", pcmd)); - return -EINVAL; - } - rxchain = bcm_atoi(str); - - err = wldev_iovar_setint(dev, "txchain", txchain); - if (err != 0) - return err; - err = wldev_iovar_setint(dev, "rxchain", rxchain); - return ((err == 0)?total_len:err); -} -#endif /* WLAIBSS */ int wl_keep_alive_set(struct net_device *dev, char* extra) { - wl_mkeep_alive_pkt_t mkeep_alive_pkt; + wl_mkeep_alive_pkt_v1_t mkeep_alive_pkt; int ret; uint period_msec = 0; char *buf; - dhd_pub_t *dhd = dhd_get_pub(dev); + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); if (extra == NULL) { - ANDROID_ERROR(("%s: extra is NULL\n", __FUNCTION__)); + DHD_ERROR(("wl_keep_alive_set: extra is NULL\n")); return -1; } if (sscanf(extra, "%d", &period_msec) != 1) { - ANDROID_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__)); + DHD_ERROR(("wl_keep_alive_set: sscanf error. check period_msec value\n")); return -EINVAL; } - ANDROID_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec)); + DHD_ERROR(("wl_keep_alive_set: period_msec is %d\n", period_msec)); - bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t)); + bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_v1_t)); mkeep_alive_pkt.period_msec = period_msec; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION_1); mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); /* Setup keep alive zero for null packet generation */ mkeep_alive_pkt.keep_alive_id = 0; mkeep_alive_pkt.len_bytes = 0; - buf = (char *)MALLOC(dhd->osh, WLC_IOCTL_SMLEN); + buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_SMLEN); if (!buf) { - ANDROID_ERROR(("%s: buffer alloc failed\n", __FUNCTION__)); + DHD_ERROR(("wl_keep_alive_set: buffer alloc failed\n")); return BCME_NOMEM; } ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL); if (ret < 0) - ANDROID_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret)); + DHD_ERROR(("wl_keep_alive_set:keep_alive set failed:%d\n", ret)); else - ANDROID_TRACE(("%s:keep_alive set ok\n", __FUNCTION__)); - MFREE(dhd->osh, buf, WLC_IOCTL_SMLEN); + DHD_TRACE(("wl_keep_alive_set: keep_alive set ok\n")); + MFREE(cfg->osh, buf, WLC_IOCTL_SMLEN); return ret; } @@ -8558,8 +4465,9 @@ static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc); if (error) { - ANDROID_ERROR(("%s: Failed to get the mode for only_resp_wfdsrc, error = %d\n", - __FUNCTION__, error)); + DHD_ERROR(("wl_android_get_wfdie_resp: Failed to get the mode" + " for only_resp_wfdsrc, error = %d\n", + error)); return -1; } @@ -8575,8 +4483,9 @@ static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsr error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc); if (error) { - ANDROID_ERROR(("%s: Failed to set only_resp_wfdsrc %d, error = %d\n", - __FUNCTION__, only_resp_wfdsrc, error)); + DHD_ERROR(("wl_android_set_wfdie_resp: Failed to set only_resp_wfdsrc %d," + " error = %d\n", + only_resp_wfdsrc, error)); return -1; } @@ -8584,38 +4493,18 @@ static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsr } #endif /* P2PRESP_WFDIE_SRC */ -#ifdef BT_WIFI_HANDOVER -static int -wl_tbow_teardown(struct net_device *dev) -{ - int err = BCME_OK; - char buf[WLC_IOCTL_SMLEN]; - tbow_setup_netinfo_t netinfo; - bzero(&netinfo, sizeof(netinfo)); - netinfo.opmode = TBOW_HO_MODE_TEARDOWN; - - err = wldev_iovar_setbuf_bsscfg(dev, "tbow_doho", &netinfo, - sizeof(tbow_setup_netinfo_t), buf, WLC_IOCTL_SMLEN, 0, NULL); - if (err < 0) { - ANDROID_ERROR(("tbow_doho iovar error %d\n", err)); - return err; - } - return err; -} -#endif /* BT_WIFI_HANOVER */ - static int wl_android_get_link_status(struct net_device *dev, char *command, int total_len) { int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map; uint32 rspec; uint encode, txexp; - wl_bss_info_t *bi; - int datalen = sizeof(uint32) + sizeof(wl_bss_info_t); + wl_bss_info_v109_t *bi; + int datalen = sizeof(uint32) + sizeof(wl_bss_info_v109_t); char buf[WLC_IOCTL_SMLEN]; if (datalen > WLC_IOCTL_SMLEN) { - ANDROID_ERROR(("data too big\n")); + WL_ERR(("data too big\n")); return -1; } @@ -8624,11 +4513,11 @@ static int wl_android_get_link_status(struct net_device *dev, char *command, *(u32 *) buf = htod32(datalen); error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen); if (unlikely(error)) { - ANDROID_ERROR(("Could not get bss info %d\n", error)); + WL_ERR(("Could not get bss info %d\n", error)); return -1; } - bi = (wl_bss_info_t*) (buf + sizeof(uint32)); + bi = (wl_bss_info_v109_t*) (buf + sizeof(uint32)); for (i = 0; i < ETHER_ADDR_LEN; i++) { if (bi->BSSID.octet[i] > 0) { @@ -8637,7 +4526,7 @@ static int wl_android_get_link_status(struct net_device *dev, char *command, } if (i == ETHER_ADDR_LEN) { - ANDROID_INFO(("No BSSID\n")); + WL_DBG(("No BSSID\n")); return -1; } @@ -8651,7 +4540,7 @@ static int wl_android_get_link_status(struct net_device *dev, char *command, /* get a rspec (radio spectrum) rate */ error = wldev_iovar_getint(dev, "nrate", &rspec); if (unlikely(error) || rspec == 0) { - ANDROID_ERROR(("get link status error (%d)\n", error)); + WL_ERR(("get link status error (%d)\n", error)); return -1; } @@ -8731,7 +4620,7 @@ static int wl_android_get_link_status(struct net_device *dev, char *command, } } - ANDROID_INFO(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n", + WL_DBG(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n", __FUNCTION__, result, stf, single_stream, nss)); bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_LINK_STATUS, result); @@ -8749,14 +4638,14 @@ wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg) int p2plo_pause = 0; dhd_pub_t *dhd = NULL; if (!cfg || !cfg->p2p) { - ANDROID_ERROR(("Wl %p or cfg->p2p %p is null\n", + WL_ERR(("Wl %p or cfg->p2p %p is null\n", cfg, cfg ? cfg->p2p : 0)); return 0; } dhd = (dhd_pub_t *)(cfg->pub); if (!dhd->up) { - ANDROID_ERROR(("bus is already down\n")); + WL_ERR(("bus is already down\n")); return ret; } @@ -8765,11 +4654,12 @@ wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg) "p2po_stop", (void*)&p2plo_pause, sizeof(p2plo_pause), cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync); if (ret < 0) { - ANDROID_ERROR(("p2po_stop Failed :%d\n", ret)); + WL_ERR(("p2po_stop Failed :%d\n", ret)); } return ret; } + s32 wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len) { @@ -8782,28 +4672,28 @@ wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len) int interval = 0; int count = 0; if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) { - ANDROID_ERROR(("Sending Action Frames. Try it again.\n")); + WL_ERR(("Sending Action Frames. Try it again.\n")); goto exit; } if (wl_get_drv_status_all(cfg, SCANNING)) { - ANDROID_ERROR(("Scanning already\n")); + WL_ERR(("Scanning already\n")); goto exit; } if (wl_get_drv_status(cfg, SCAN_ABORTING, dev)) { - ANDROID_ERROR(("Scanning being aborted\n")); + WL_ERR(("Scanning being aborted\n")); goto exit; } if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) { - ANDROID_ERROR(("p2p listen offloading already running\n")); + WL_ERR(("p2p listen offloading already running\n")); goto exit; } /* Just in case if it is not enabled */ if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) { - ANDROID_ERROR(("cfgp2p_enable discovery failed")); + WL_ERR(("cfgp2p_enable discovery failed")); goto exit; } @@ -8813,7 +4703,7 @@ wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len) sscanf(buf, " %10d %10d %10d %10d", &channel, &period, &interval, &count); if ((channel == 0) || (period == 0) || (interval == 0) || (count == 0)) { - ANDROID_ERROR(("Wrong argument %d/%d/%d/%d \n", + WL_ERR(("Wrong argument %d/%d/%d/%d \n", channel, period, interval, count)); ret = -EAGAIN; goto exit; @@ -8822,10 +4712,10 @@ wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len) p2plo_listen.interval = interval; p2plo_listen.count = count; - ANDROID_ERROR(("channel:%d period:%d, interval:%d count:%d\n", + WL_ERR(("channel:%d period:%d, interval:%d count:%d\n", channel, period, interval, count)); } else { - ANDROID_ERROR(("Argument len is wrong.\n")); + WL_ERR(("Argument len is wrong.\n")); ret = -EAGAIN; goto exit; } @@ -8833,14 +4723,14 @@ wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len) if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel, sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync)) < 0) { - ANDROID_ERROR(("p2po_listen_channel Failed :%d\n", ret)); + WL_ERR(("p2po_listen_channel Failed :%d\n", ret)); goto exit; } if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&p2plo_listen, sizeof(wl_p2plo_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync)) < 0) { - ANDROID_ERROR(("p2po_listen Failed :%d\n", ret)); + WL_ERR(("p2po_listen Failed :%d\n", ret)); goto exit; } @@ -8848,6 +4738,7 @@ wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len) exit : return ret; } + s32 wl_cfg80211_p2plo_listen_stop(struct net_device *dev) { @@ -8858,7 +4749,7 @@ wl_cfg80211_p2plo_listen_stop(struct net_device *dev) if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync)) < 0) { - ANDROID_ERROR(("p2po_stop Failed :%d\n", ret)); + WL_ERR(("p2po_stop Failed :%d\n", ret)); goto exit; } @@ -8871,18 +4762,19 @@ wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len) { int ret = 0; - ANDROID_ERROR(("Entry cmd:%s arg_len:%d \n", cmd, len)); + WL_ERR(("Entry cmd:%s arg_len:%d \n", cmd, len)); if (strncmp(cmd, "P2P_LO_START", strlen("P2P_LO_START")) == 0) { ret = wl_cfg80211_p2plo_listen_start(dev, buf, len); } else if (strncmp(cmd, "P2P_LO_STOP", strlen("P2P_LO_STOP")) == 0) { ret = wl_cfg80211_p2plo_listen_stop(dev); } else { - ANDROID_ERROR(("Request for Unsupported CMD:%s \n", buf)); + WL_ERR(("Request for Unsupported CMD:%s \n", buf)); ret = -EINVAL; } return ret; } + void wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg) { @@ -8894,7 +4786,7 @@ wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg) wdev = bcmcfg_to_p2p_wdev(cfg); if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) { - ANDROID_INFO(("P2P_FIND: Discovery offload is already in progress." + WL_INFORM_MEM(("P2P_FIND: Discovery offload is already in progress." "it aborted\n")); wl_clr_p2p_status(cfg, DISC_IN_PROGRESS); if (wdev != NULL) { @@ -8924,14 +4816,14 @@ wl_android_murx_bfe_cap(struct net_device *dev, int val) wl_reassoc_params_t params; if (iface_count > 1) { - ANDROID_ERROR(("murx_bfe_cap change is not allowed when " + WL_ERR(("murx_bfe_cap change is not allowed when " "there are multiple interfaces\n")); return -EINVAL; } /* Now there is only single interface */ err = wldev_iovar_setint(dev, "murx_bfe_cap", val); if (unlikely(err)) { - ANDROID_ERROR(("Failed to set murx_bfe_cap IOVAR to %d," + WL_ERR(("Failed to set murx_bfe_cap IOVAR to %d," "error %d\n", val, err)); return err; } @@ -8939,7 +4831,7 @@ wl_android_murx_bfe_cap(struct net_device *dev, int val) /* If successful intiate a reassoc */ bzero(&bssid, ETHER_ADDR_LEN); if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) < 0) { - ANDROID_ERROR(("Failed to get bssid, error=%d\n", err)); + WL_ERR(("Failed to get bssid, error=%d\n", err)); return err; } @@ -8948,9 +4840,9 @@ wl_android_murx_bfe_cap(struct net_device *dev, int val) if ((err = wldev_ioctl_set(dev, WLC_REASSOC, ¶ms, sizeof(wl_reassoc_params_t))) < 0) { - ANDROID_ERROR(("reassoc failed err:%d \n", err)); + WL_ERR(("reassoc failed err:%d \n", err)); } else { - ANDROID_INFO(("reassoc issued successfully\n")); + WL_DBG(("reassoc issued successfully\n")); } return err; @@ -8983,7 +4875,7 @@ wl_android_get_rssi_per_ant(struct net_device *dev, char *command, int total_len /* get the interface name */ token = bcmstrtok(&pos, " ", NULL); if (!token) { - ANDROID_ERROR(("Invalid arguments\n")); + WL_ERR(("Invalid arguments\n")); return -EINVAL; } ifname = token; @@ -9007,22 +4899,22 @@ wl_android_get_rssi_per_ant(struct net_device *dev, char *command, int total_len err = wl_get_rssi_per_ant(dev, ifname, peer_mac, &rssi_ant_mimo); if (unlikely(err)) { - ANDROID_ERROR(("Failed to get RSSI info, err=%d\n", err)); + WL_ERR(("Failed to get RSSI info, err=%d\n", err)); return err; } /* Parse the results */ - ANDROID_INFO(("ifname %s, version %d, count %d, mimo rssi %d\n", + WL_DBG(("ifname %s, version %d, count %d, mimo rssi %d\n", ifname, rssi_ant_mimo.version, rssi_ant_mimo.count, mimo_rssi)); if (mimo_rssi) { - ANDROID_INFO(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum)); + WL_DBG(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum)); bytes_written = snprintf(command, total_len, "%s MIMO %d", CMD_GET_RSSI_PER_ANT, rssi_ant_mimo.rssi_sum); } else { int cnt; bytes_written = snprintf(command, total_len, "%s PER_ANT ", CMD_GET_RSSI_PER_ANT); for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) { - ANDROID_INFO(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt])); + WL_DBG(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt])); bytes_written = snprintf(command, total_len, "%d ", rssi_ant_mimo.rssi_ant[cnt]); } @@ -9050,7 +4942,7 @@ wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len /* enable/disable */ token = bcmstrtok(&pos, " ", NULL); if (!token) { - ANDROID_ERROR(("Invalid arguments\n")); + WL_ERR(("Invalid arguments\n")); return -EINVAL; } set_param.enable = bcm_atoi(token); @@ -9058,7 +4950,7 @@ wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len /* RSSI Threshold */ token = bcmstrtok(&pos, " ", NULL); if (!token) { - ANDROID_ERROR(("Invalid arguments\n")); + WL_ERR(("Invalid arguments\n")); return -EINVAL; } set_param.rssi_threshold = bcm_atoi(token); @@ -9066,17 +4958,17 @@ wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len /* Time Threshold */ token = bcmstrtok(&pos, " ", NULL); if (!token) { - ANDROID_ERROR(("Invalid arguments\n")); + WL_ERR(("Invalid arguments\n")); return -EINVAL; } set_param.time_threshold = bcm_atoi(token); - ANDROID_INFO(("enable %d, RSSI threshold %d, Time threshold %d\n", set_param.enable, + WL_DBG(("enable %d, RSSI threshold %d, Time threshold %d\n", set_param.enable, set_param.rssi_threshold, set_param.time_threshold)); err = wl_set_rssi_logging(dev, (void *)&set_param); if (unlikely(err)) { - ANDROID_ERROR(("Failed to configure RSSI logging: enable %d, RSSI Threshold %d," + WL_ERR(("Failed to configure RSSI logging: enable %d, RSSI Threshold %d," " Time Threshold %d\n", set_param.enable, set_param.rssi_threshold, set_param.time_threshold)); } @@ -9093,33 +4985,33 @@ wl_android_get_rssi_logging(struct net_device *dev, char *command, int total_len err = wl_get_rssi_logging(dev, (void *)&get_param); if (unlikely(err)) { - ANDROID_ERROR(("Failed to get RSSI logging info\n")); + WL_ERR(("Failed to get RSSI logging info\n")); return BCME_ERROR; } - ANDROID_INFO(("report_count %d, enable %d, rssi_threshold %d, time_threshold %d\n", + WL_DBG(("report_count %d, enable %d, rssi_threshold %d, time_threshold %d\n", get_param.report_count, get_param.enable, get_param.rssi_threshold, get_param.time_threshold)); /* Parse the parameter */ if (!get_param.enable) { - ANDROID_INFO(("RSSI LOGGING: Feature is disables\n")); + WL_DBG(("RSSI LOGGING: Feature is disables\n")); bytes_written = snprintf(command, total_len, "%s FEATURE DISABLED\n", CMD_GET_RSSI_LOGGING); } else if (get_param.enable & (RSSILOG_FLAG_FEATURE_SW | RSSILOG_FLAG_REPORT_READY)) { if (!get_param.report_count) { - ANDROID_INFO(("[PASS] RSSI difference across antennas is within" + WL_DBG(("[PASS] RSSI difference across antennas is within" " threshold limits\n")); bytes_written = snprintf(command, total_len, "%s PASS\n", CMD_GET_RSSI_LOGGING); } else { - ANDROID_INFO(("[FAIL] RSSI difference across antennas found " + WL_DBG(("[FAIL] RSSI difference across antennas found " "to be greater than %3d dB\n", get_param.rssi_threshold)); - ANDROID_INFO(("[FAIL] RSSI difference check have failed for " + WL_DBG(("[FAIL] RSSI difference check have failed for " "%d out of %d times\n", get_param.report_count, get_param.time_threshold)); - ANDROID_INFO(("[FAIL] RSSI difference is being monitored once " + WL_DBG(("[FAIL] RSSI difference is being monitored once " "per second, for a %d secs window\n", get_param.time_threshold)); bytes_written = snprintf(command, total_len, "%s FAIL - RSSI Threshold " "%d dBm for %d out of %d times\n", CMD_GET_RSSI_LOGGING, @@ -9127,7 +5019,7 @@ wl_android_get_rssi_logging(struct net_device *dev, char *command, int total_len get_param.time_threshold); } } else { - ANDROID_INFO(("[BUSY] Reprot is not ready\n")); + WL_DBG(("[BUSY] Reprot is not ready\n")); bytes_written = snprintf(command, total_len, "%s BUSY - NOT READY\n", CMD_GET_RSSI_LOGGING); } @@ -9142,7 +5034,7 @@ wl_android_set_irq_cpucore(struct net_device *net, int affinity_cmd) { dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net); if (!dhdp) { - ANDROID_ERROR(("dhd is NULL\n")); + WL_ERR(("dhd is NULL\n")); return; } @@ -9158,7 +5050,7 @@ wl_android_lqcm_enable(struct net_device *net, int lqcm_enable) err = wldev_iovar_setint(net, "lqcm", lqcm_enable); if (err != BCME_OK) { - ANDROID_ERROR(("failed to set lqcm enable %d, error = %d\n", lqcm_enable, err)); + WL_ERR(("failed to set lqcm enable %d, error = %d\n", lqcm_enable, err)); return -EIO; } return err; @@ -9173,18 +5065,23 @@ wl_android_get_lqcm_report(struct net_device *dev, char *command, int total_len) err = wldev_iovar_getint(dev, "lqcm", &lqcm_report); if (err != BCME_OK) { - ANDROID_ERROR(("failed to get lqcm report, error = %d\n", err)); + WL_ERR(("failed to get lqcm report, error = %d\n", err)); return -EIO; } lqcm_enable = lqcm_report & LQCM_ENAB_MASK; tx_lqcm_idx = (lqcm_report & LQCM_TX_INDEX_MASK) >> LQCM_TX_INDEX_SHIFT; rx_lqcm_idx = (lqcm_report & LQCM_RX_INDEX_MASK) >> LQCM_RX_INDEX_SHIFT; - ANDROID_INFO(("lqcm report EN:%d, TX:%d, RX:%d\n", lqcm_enable, tx_lqcm_idx, rx_lqcm_idx)); + WL_DBG(("lqcm report EN:%d, TX:%d, RX:%d\n", lqcm_enable, tx_lqcm_idx, rx_lqcm_idx)); bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_LQCM_REPORT, lqcm_report); +#ifdef RPM_FAST_TRIGGER + WL_INFORM(("Trgger RPM Fast\n")); + dhd_trigger_rpm_fast(wl_get_cfg(dev)); +#endif /* RPM_FAST_TRIGGER */ + return bytes_written; } #endif /* SUPPORT_LQCM */ @@ -9197,13 +5094,13 @@ wl_android_get_snr(struct net_device *dev, char *command, int total_len) error = wldev_iovar_getint(dev, "snr", &snr); if (error) { - ANDROID_ERROR(("%s: Failed to get SNR %d, error = %d\n", - __FUNCTION__, snr, error)); + DHD_ERROR(("wl_android_get_snr: Failed to get SNR %d, error = %d\n", + snr, error)); return -EIO; } bytes_written = snprintf(command, total_len, "snr %d", snr); - ANDROID_INFO(("%s: command result is %s\n", __FUNCTION__, command)); + DHD_INFO(("wl_android_get_snr: command result is %s\n", command)); return bytes_written; } @@ -9236,11 +5133,11 @@ wl_android_set_ap_beaconrate(struct net_device *dev, char *command) return -EINVAL; ifname = token; - ANDROID_INFO(("rate %d, ifacename %s\n", rate, ifname)); + WL_DBG(("rate %d, ifacename %s\n", rate, ifname)); err = wl_set_ap_beacon_rate(dev, rate, ifname); if (unlikely(err)) { - ANDROID_ERROR(("Failed to set ap beacon rate to %d, error = %d\n", rate, err)); + WL_ERR(("Failed to set ap beacon rate to %d, error = %d\n", rate, err)); } return err; @@ -9265,11 +5162,11 @@ int wl_android_get_ap_basicrate(struct net_device *dev, char *command, int total return -EINVAL; ifname = token; - ANDROID_INFO(("ifacename %s\n", ifname)); + WL_DBG(("ifacename %s\n", ifname)); bytes_written = wl_get_ap_basic_rate(dev, command, ifname, total_len); if (bytes_written < 1) { - ANDROID_ERROR(("Failed to get ap basic rate, error = %d\n", bytes_written)); + WL_ERR(("Failed to get ap basic rate, error = %d\n", bytes_written)); return -EPROTO; } @@ -9300,11 +5197,11 @@ wl_android_get_ap_rps(struct net_device *dev, char *command, int total_len) ifname = token; strlcpy(name, ifname, sizeof(name)); - ANDROID_INFO(("ifacename %s\n", name)); + WL_DBG(("ifacename %s\n", name)); bytes_written = wl_get_ap_rps(dev, command, name, total_len); if (bytes_written < 1) { - ANDROID_ERROR(("Failed to get rps, error = %d\n", bytes_written)); + WL_ERR(("Failed to get rps, error = %d\n", bytes_written)); return -EPROTO; } @@ -9342,11 +5239,11 @@ wl_android_set_ap_rps(struct net_device *dev, char *command, int total_len) ifname = token; strlcpy(name, ifname, sizeof(name)); - ANDROID_INFO(("enable %d, ifacename %s\n", enable, name)); + WL_DBG(("enable %d, ifacename %s\n", enable, name)); err = wl_set_ap_rps(dev, enable? TRUE: FALSE, name); if (unlikely(err)) { - ANDROID_ERROR(("Failed to set rps, enable %d, error = %d\n", enable, err)); + WL_ERR(("Failed to set rps, enable %d, error = %d\n", enable, err)); } return err; @@ -9401,13 +5298,13 @@ wl_android_set_ap_rps_params(struct net_device *dev, char *command, int total_le ifname = token; strlcpy(name, ifname, sizeof(name)); - ANDROID_INFO(("pps %d, level %d, quiettime %d, sta_assoc_check %d, " + WL_DBG(("pps %d, level %d, quiettime %d, sta_assoc_check %d, " "ifacename %s\n", rps.pps, rps.level, rps.quiet_time, rps.sta_assoc_check, name)); err = wl_update_ap_rps_params(dev, &rps, name); if (unlikely(err)) { - ANDROID_ERROR(("Failed to update rps, pps %d, level %d, quiettime %d, " + WL_ERR(("Failed to update rps, pps %d, level %d, quiettime %d, " "sta_assoc_check %d, err = %d\n", rps.pps, rps.level, rps.quiet_time, rps.sta_assoc_check, err)); } @@ -9432,13 +5329,13 @@ wl_android_check_priv_cmd_errors(struct net_device *dev) int memdump_mode; if (!dev) { - ANDROID_ERROR(("dev is NULL\n")); + WL_ERR(("dev is NULL\n")); return; } dhdp = wl_cfg80211_get_dhdp(dev); if (!dhdp) { - ANDROID_ERROR(("dhdp is NULL\n")); + WL_ERR(("dhdp is NULL\n")); return; } @@ -9460,7 +5357,7 @@ wl_android_check_priv_cmd_errors(struct net_device *dev) */ if (memdump_mode == DUMP_MEMFILE_BUGON && (priv_cmd_errors > NUMBER_SEQUENTIAL_PRIVCMD_ERRORS)) { - ANDROID_ERROR(("Send HANG event due to sequential private cmd errors\n")); + WL_ERR(("Send HANG event due to sequential private cmd errors\n")); priv_cmd_errors = 0; #ifdef DHD_FW_COREDUMP /* Take a SOCRAM dump */ @@ -9497,9 +5394,9 @@ wl_android_pktlog_filter_enable(struct net_device *dev, char *command, int total if (err == BCME_OK) { bytes_written = snprintf(command, total_len, "OK"); - ANDROID_ERROR(("%s: pktlog filter enable success\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter enable success\n", __FUNCTION__)); } else { - ANDROID_ERROR(("%s: pktlog filter enable fail\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter enable fail\n", __FUNCTION__)); return BCME_ERROR; } @@ -9528,9 +5425,9 @@ wl_android_pktlog_filter_disable(struct net_device *dev, char *command, int tota if (err == BCME_OK) { bytes_written = snprintf(command, total_len, "OK"); - ANDROID_ERROR(("%s: pktlog filter disable success\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter disable success\n", __FUNCTION__)); } else { - ANDROID_ERROR(("%s: pktlog filter disable fail\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter disable fail\n", __FUNCTION__)); return BCME_ERROR; } @@ -9562,9 +5459,9 @@ wl_android_pktlog_filter_pattern_enable(struct net_device *dev, char *command, i if (err == BCME_OK) { bytes_written = snprintf(command, total_len, "OK"); - ANDROID_ERROR(("%s: pktlog filter pattern enable success\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter pattern enable success\n", __FUNCTION__)); } else { - ANDROID_ERROR(("%s: pktlog filter pattern enable fail\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter pattern enable fail\n", __FUNCTION__)); return BCME_ERROR; } @@ -9596,9 +5493,9 @@ wl_android_pktlog_filter_pattern_disable(struct net_device *dev, char *command, if (err == BCME_OK) { bytes_written = snprintf(command, total_len, "OK"); - ANDROID_ERROR(("%s: pktlog filter pattern disable success\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter pattern disable success\n", __FUNCTION__)); } else { - ANDROID_ERROR(("%s: pktlog filter pattern disable fail\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter pattern disable fail\n", __FUNCTION__)); return BCME_ERROR; } @@ -9629,9 +5526,9 @@ wl_android_pktlog_filter_add(struct net_device *dev, char *command, int total_le if (err == BCME_OK) { bytes_written = snprintf(command, total_len, "OK"); - ANDROID_ERROR(("%s: pktlog filter add success\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter add success\n", __FUNCTION__)); } else { - ANDROID_ERROR(("%s: pktlog filter add fail\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter add fail\n", __FUNCTION__)); return BCME_ERROR; } @@ -9647,7 +5544,7 @@ wl_android_pktlog_filter_del(struct net_device *dev, char *command, int total_le int err = BCME_OK; if (!dhdp || !dhdp->pktlog) { - ANDROID_ERROR(("%s(): dhdp=%p pktlog=%p\n", + DHD_ERROR(("%s(): dhdp=%p pktlog=%p\n", __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL))); return -EINVAL; } @@ -9663,9 +5560,9 @@ wl_android_pktlog_filter_del(struct net_device *dev, char *command, int total_le err = dhd_pktlog_filter_del(filter, command + strlen(CMD_PKTLOG_FILTER_DEL) + 1); if (err == BCME_OK) { bytes_written = snprintf(command, total_len, "OK"); - ANDROID_ERROR(("%s: pktlog filter del success\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter del success\n", __FUNCTION__)); } else { - ANDROID_ERROR(("%s: pktlog filter del fail\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter del fail\n", __FUNCTION__)); return BCME_ERROR; } @@ -9692,9 +5589,9 @@ wl_android_pktlog_filter_info(struct net_device *dev, char *command, int total_l if (err == BCME_OK) { bytes_written = snprintf(command, total_len, "OK"); - ANDROID_ERROR(("%s: pktlog filter info success\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter info success\n", __FUNCTION__)); } else { - ANDROID_ERROR(("%s: pktlog filter info fail\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog filter info fail\n", __FUNCTION__)); return BCME_ERROR; } @@ -9723,7 +5620,7 @@ wl_android_pktlog_start(struct net_device *dev, char *command, int total_len) bytes_written = snprintf(command, total_len, "OK"); - ANDROID_ERROR(("%s: pktlog start success\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog start success\n", __FUNCTION__)); return bytes_written; } @@ -9750,7 +5647,7 @@ wl_android_pktlog_stop(struct net_device *dev, char *command, int total_len) bytes_written = snprintf(command, total_len, "OK"); - ANDROID_ERROR(("%s: pktlog stop success\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog stop success\n", __FUNCTION__)); return bytes_written; } @@ -9781,10 +5678,10 @@ wl_android_pktlog_filter_exist(struct net_device *dev, char *command, int total_ if (exist) { bytes_written = snprintf(command, total_len, "TRUE"); - ANDROID_ERROR(("%s: pktlog filter pattern id: %d is existed\n", __FUNCTION__, id)); + DHD_ERROR(("%s: pktlog filter pattern id: %d is existed\n", __FUNCTION__, id)); } else { bytes_written = snprintf(command, total_len, "FALSE"); - ANDROID_ERROR(("%s: pktlog filter pattern id: %d is not existed\n", __FUNCTION__, id)); + DHD_ERROR(("%s: pktlog filter pattern id: %d is not existed\n", __FUNCTION__, id)); } return bytes_written; @@ -9812,7 +5709,7 @@ wl_android_pktlog_minmize_enable(struct net_device *dev, char *command, int tota bytes_written = snprintf(command, total_len, "OK"); - ANDROID_ERROR(("%s: pktlog pktlog_minmize enable\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog pktlog_minmize enable\n", __FUNCTION__)); return bytes_written; } @@ -9839,7 +5736,7 @@ wl_android_pktlog_minmize_disable(struct net_device *dev, char *command, int tot bytes_written = snprintf(command, total_len, "OK"); - ANDROID_ERROR(("%s: pktlog pktlog_minmize disable\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog pktlog_minmize disable\n", __FUNCTION__)); return bytes_written; } @@ -9872,9 +5769,9 @@ wl_android_pktlog_change_size(struct net_device *dev, char *command, int total_l if (err == BCME_OK) { bytes_written = snprintf(command, total_len, "OK"); - ANDROID_ERROR(("%s: pktlog change size success\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog change size success\n", __FUNCTION__)); } else { - ANDROID_ERROR(("%s: pktlog change size fail\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog change size fail\n", __FUNCTION__)); return BCME_ERROR; } @@ -9901,9 +5798,9 @@ wl_android_pktlog_dbg_dump(struct net_device *dev, char *command, int total_len) err = dhd_pktlog_debug_dump(dhdp); if (err == BCME_OK) { bytes_written = snprintf(command, total_len, "OK"); - ANDROID_INFO(("%s: pktlog dbg dump success\n", __FUNCTION__)); + DHD_INFO(("%s: pktlog dbg dump success\n", __FUNCTION__)); } else { - ANDROID_ERROR(("%s: pktlog dbg dump fail\n", __FUNCTION__)); + DHD_ERROR(("%s: pktlog dbg dump fail\n", __FUNCTION__)); return BCME_ERROR; } @@ -9923,7 +5820,7 @@ static int wl_android_set_powersave_mode( #endif /* DHD_PM_OVERRIDE */ sscanf(command, "%*s %10d", &pm); if (pm < PM_OFF || pm > PM_FAST) { - ANDROID_ERROR(("check pm=%d\n", pm)); + WL_ERR(("check pm=%d\n", pm)); return BCME_ERROR; } @@ -9940,7 +5837,7 @@ static int wl_android_set_powersave_mode( g_pm_override = TRUE; } - ANDROID_ERROR(("%s: PM:%d, pm_override=%d\n", __FUNCTION__, pm, g_pm_override)); + WL_ERR(("%s: PM:%d, pm_override=%d\n", __FUNCTION__, pm, g_pm_override)); #endif /* DHD_PM_OVERRIDE */ return err; } @@ -9953,7 +5850,7 @@ static int wl_android_get_powersave_mode( err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm)); if (err != BCME_OK) { - ANDROID_ERROR(("failed to get pm (%d)", err)); + WL_ERR(("failed to get pm (%d)", err)); return err; } @@ -9986,19 +5883,19 @@ wl_android_ewp_filter(struct net_device *dev, char *command, uint32 tot_len) #endif if (!dhdp || !command) { - ANDROID_ERROR(("%s(): dhdp=%p \n", __FUNCTION__, dhdp)); + DHD_ERROR(("%s(): dhdp=%p \n", __FUNCTION__, dhdp)); return -EINVAL; } if (!FW_SUPPORTED(dhdp, ecounters)) { - ANDROID_ERROR(("does not support ecounters!\n")); + DHD_ERROR(("does not support ecounters!\n")); return BCME_UNSUPPORTED; } #ifdef DHD_EWPR_VER2 if (strlen(command) > strlen(CMD_EWP_FILTER) + 1) { sscanf(index_str, "%10d %10d %10d", &index1, &index2, &index3); - ANDROID_TRACE(("%s(): get index request: %d %d %d\n", __FUNCTION__, + DHD_TRACE(("%s(): get index request: %d %d %d\n", __FUNCTION__, index1, index2, index3)); } bytes_written += dhd_event_log_filter_serialize_bit(dhdp, @@ -10048,11 +5945,11 @@ wl_android_set_ap_suspend(struct net_device *dev, char *command, int total_len) ifname = token; strlcpy(name, ifname, sizeof(name)); - ANDROID_INFO(("suspend %d, ifacename %s\n", suspend, name)); + WL_DBG(("suspend %d, ifacename %s\n", suspend, name)); err = wl_set_ap_suspend(dev, suspend? TRUE: FALSE, name); if (unlikely(err)) { - ANDROID_ERROR(("Failed to set suspend, suspend %d, error = %d\n", suspend, err)); + WL_ERR(("Failed to set suspend, suspend %d, error = %d\n", suspend, err)); } return err; @@ -10095,11 +5992,11 @@ wl_android_set_ap_bw(struct net_device *dev, char *command, int total_len) ifname = token; strlcpy(name, ifname, sizeof(name)); - ANDROID_INFO(("bw %d, ifacename %s\n", bw, name)); + WL_DBG(("bw %d, ifacename %s\n", bw, name)); err = wl_set_ap_bw(dev, bw, name); if (unlikely(err)) { - ANDROID_ERROR(("Failed to set bw, bw %d, error = %d\n", bw, err)); + WL_ERR(("Failed to set bw, bw %d, error = %d\n", bw, err)); } return err; @@ -10132,11 +6029,11 @@ wl_android_get_ap_bw(struct net_device *dev, char *command, int total_len) ifname = token; strlcpy(name, ifname, sizeof(name)); - ANDROID_INFO(("ifacename %s\n", name)); + WL_DBG(("ifacename %s\n", name)); bytes_written = wl_get_ap_bw(dev, command, name, total_len); if (bytes_written < 1) { - ANDROID_ERROR(("Failed to get bw, error = %d\n", bytes_written)); + WL_ERR(("Failed to get bw, error = %d\n", bytes_written)); return -EPROTO; } @@ -10159,7 +6056,7 @@ wl_android_priv_cmd_log_enable_check(char* cmd) cnt++; } - return FALSE; + return TRUE; } int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr) @@ -10171,7 +6068,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr) int bytes_written = 0; android_wifi_priv_cmd priv_cmd; int buf_size = 0; - dhd_pub_t *dhd = dhd_get_pub(net); + struct bcm_cfg80211 *cfg = wl_get_cfg(net); net_os_wake_lock(net); @@ -10190,7 +6087,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr) if (in_compat_syscall()) #else if (is_compat_task()) -#endif +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) */ { compat_android_wifi_priv_cmd compat_priv_cmd; if (copy_from_user(&compat_priv_cmd, ifr->ifr_data, @@ -10211,16 +6108,16 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr) } } if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) { - ANDROID_ERROR(("%s: buf length invalid:%d\n", __FUNCTION__, + DHD_ERROR(("wl_android_priv_cmd: buf length invalid:%d\n", priv_cmd.total_len)); ret = -EINVAL; goto exit; } buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN); - command = (char *)MALLOC(dhd->osh, (buf_size + 1)); + command = (char *)MALLOC(cfg->osh, (buf_size + 1)); if (!command) { - ANDROID_ERROR(("%s: failed to allocate memory\n", __FUNCTION__)); + DHD_ERROR(("wl_android_priv_cmd: failed to allocate memory\n")); ret = -ENOMEM; goto exit; } @@ -10231,11 +6128,12 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr) command[priv_cmd.total_len] = '\0'; if (wl_android_priv_cmd_log_enable_check(command)) { - ANDROID_ERROR(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, + DHD_ERROR(("wl_android_priv_cmd: Android private cmd \"%s\" on %s\n", command, ifr->ifr_name)); } else { - ANDROID_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name)); + DHD_INFO(("wl_android_priv_cmd: Android private cmd \"%s\" on %s\n", + command, ifr->ifr_name)); } @@ -10245,16 +6143,15 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr) command[0] = '\0'; } if (bytes_written >= priv_cmd.total_len) { - ANDROID_ERROR(("%s: err. bytes_written:%d >= total_len:%d, buf_size:%d\n", - __FUNCTION__, bytes_written, priv_cmd.total_len, buf_size)); - + DHD_ERROR(("wl_android_priv_cmd: err. bytes_written:%d >= total_len:%d," + " buf_size:%d \n", bytes_written, priv_cmd.total_len, buf_size)); ret = BCME_BUFTOOSHORT; goto exit; } bytes_written++; priv_cmd.used_len = bytes_written; if (copy_to_user(priv_cmd.buf, command, bytes_written)) { - ANDROID_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__)); + DHD_ERROR(("wl_android_priv_cmd: failed to copy data to user buffer\n")); ret = -EFAULT; } } @@ -10266,8 +6163,17 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr) exit: #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS if (ret) { - /* Avoid incrementing priv_cmd_errors in case of unsupported feature */ - if (ret != BCME_UNSUPPORTED) { + /* Avoid incrementing priv_cmd_errors in case of unsupported feature + * or BUSY state specific to TWT commands + */ + if ( +#ifdef WL_TWT + !(((ret == -EBUSY) || (ret == -EOPNOTSUPP)) && + ((strnicmp(command, CMD_TWT_SETUP, strlen(CMD_TWT_SETUP)) == 0) || + (strnicmp(command, CMD_TWT_TEARDOWN, strlen(CMD_TWT_TEARDOWN)) == 0) || + (strnicmp(command, CMD_TWT_INFO, strlen(CMD_TWT_INFO)) == 0))) && +#endif /* WL_TWT */ + (ret != BCME_UNSUPPORTED)) { wl_android_check_priv_cmd_errors(net); } } else { @@ -10275,130 +6181,10 @@ exit: } #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */ net_os_wake_unlock(net); - MFREE(dhd->osh, command, (buf_size + 1)); + MFREE(cfg->osh, command, (buf_size + 1)); return ret; } -#ifdef WLADPS_PRIVATE_CMD -static int -wl_android_set_adps_mode(struct net_device *dev, const char* string_num) -{ - int err = 0, adps_mode; - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); -#ifdef DHD_PM_CONTROL_FROM_FILE - if (g_pm_control) { - return -EPERM; - } -#endif /* DHD_PM_CONTROL_FROM_FILE */ - - adps_mode = bcm_atoi(string_num); - ANDROID_ERROR(("%s: SET_ADPS %d\n", __FUNCTION__, adps_mode)); - - if (!(adps_mode == 0 || adps_mode == 1)) { - ANDROID_ERROR(("wl_android_set_adps_mode: Invalid value %d.\n", adps_mode)); - return -EINVAL; - } - - err = dhd_enable_adps(dhdp, adps_mode); - if (err != BCME_OK) { - ANDROID_ERROR(("failed to set adps mode %d, error = %d\n", adps_mode, err)); - return -EIO; - } - return err; -} -static int -wl_android_get_adps_mode( - struct net_device *dev, char *command, int total_len) -{ - int bytes_written, err = 0; - uint len; - char buf[WLC_IOCTL_SMLEN]; - - bcm_iov_buf_t iov_buf; - bcm_iov_buf_t *ptr = NULL; - wl_adps_params_v1_t *data = NULL; - - uint8 *pdata = NULL; - uint8 band, mode = 0; - - bzero(&iov_buf, sizeof(iov_buf)); - - len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(band); - - iov_buf.version = WL_ADPS_IOV_VER; - iov_buf.len = sizeof(band); - iov_buf.id = WL_ADPS_IOV_MODE; - - pdata = (uint8 *)&iov_buf.data; - - for (band = 1; band <= MAX_BANDS; band++) { - pdata[0] = band; - err = wldev_iovar_getbuf(dev, "adps", &iov_buf, len, - buf, WLC_IOCTL_SMLEN, NULL); - if (err != BCME_OK) { - ANDROID_ERROR(("wl_android_get_adps_mode fail to get adps band %d(%d).\n", - band, err)); - return -EIO; - } - ptr = (bcm_iov_buf_t *) buf; - data = (wl_adps_params_v1_t *) ptr->data; - mode = data->mode; - if (mode != OFF) { - break; - } - } - - bytes_written = snprintf(command, total_len, "%s %d", - CMD_GET_ADPS, mode); - return bytes_written; -} - -#ifdef WLADPS_ENERGY_GAIN -static int -wl_android_get_gain_adps( - struct net_device *dev, char *command, int total_len) -{ - int bytes_written; - - int ret = 0; - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); - - ret = dhd_event_log_filter_adps_energy_gain(dhdp); - if (ret < 0) { - return ret; - } - - ANDROID_INFO(("%s ADPS Energy Gain: %d uAh\n", __FUNCTION__, ret)); - - bytes_written = snprintf(command, total_len, "%s %d uAm", - CMD_GET_GAIN_ADPS, ret); - - return bytes_written; -} - -static int -wl_android_reset_gain_adps( - struct net_device *dev, char *command) -{ - int ret = BCME_OK; - - bcm_iov_buf_t iov_buf; - char buf[WLC_IOCTL_SMLEN] = {0, }; - - iov_buf.version = WL_ADPS_IOV_VER; - iov_buf.id = WL_ADPS_IOV_RESET_GAIN; - iov_buf.len = 0; - - if ((ret = wldev_iovar_setbuf(dev, "adps", &iov_buf, sizeof(iov_buf), - buf, sizeof(buf), NULL)) < 0) { - ANDROID_ERROR(("%s fail to reset adps gain (%d)\n", __FUNCTION__, ret)); - } - - return ret; -} -#endif /* WLADPS_ENERGY_GAIN */ -#endif /* WLADPS_PRIVATE_CMD */ - #ifdef WL_BCNRECV #define BCNRECV_ATTR_HDR_LEN 30 int @@ -10418,7 +6204,7 @@ wl_android_bcnrecv_event(struct net_device *ndev, uint attr_type, skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), len, BRCM_VENDOR_EVENT_BEACON_RECV, kflags); if (!skb) { - ANDROID_ERROR(("skb alloc failed")); + WL_ERR(("skb alloc failed")); return -ENOMEM; } if ((attr_type == BCNRECV_ATTR_BCNINFO) && (data)) { @@ -10430,7 +6216,7 @@ wl_android_bcnrecv_event(struct net_device *ndev, uint attr_type, nla_put_u32(skb, BCNRECV_ATTR_REASON, reason); } } else { - ANDROID_ERROR(("UNKNOWN ATTR_TYPE. attr_type:%d\n", attr_type)); + WL_ERR(("UNKNOWN ATTR_TYPE. attr_type:%d\n", attr_type)); kfree_skb(skb); return -EINVAL; } @@ -10443,25 +6229,26 @@ _wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev, boo { s32 err = BCME_OK; struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg); + dhd_pub_t *dhd = cfg->pub; /* check any scan is in progress before beacon recv scan trigger IOVAR */ if (wl_get_drv_status_all(cfg, SCANNING)) { err = BCME_UNSUPPORTED; - ANDROID_ERROR(("Scan in progress, Aborting beacon recv start, " + WL_ERR(("Scan in progress, Aborting beacon recv start, " "error:%d\n", err)); goto exit; } if (wl_get_p2p_status(cfg, SCANNING)) { err = BCME_UNSUPPORTED; - ANDROID_ERROR(("P2P Scan in progress, Aborting beacon recv start, " + WL_ERR(("P2P Scan in progress, Aborting beacon recv start, " "error:%d\n", err)); goto exit; } if (wl_get_drv_status(cfg, REMAINING_ON_CHANNEL, ndev)) { err = BCME_UNSUPPORTED; - ANDROID_ERROR(("P2P remain on channel, Aborting beacon recv start, " + WL_ERR(("P2P remain on channel, Aborting beacon recv start, " "error:%d\n", err)); goto exit; } @@ -10471,7 +6258,7 @@ _wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev, boo */ if (!wl_get_drv_status(cfg, CONNECTED, ndev)) { err = BCME_UNSUPPORTED; - ANDROID_ERROR(("STA is in not associated state error:%d\n", err)); + WL_ERR(("STA is in not associated state error:%d\n", err)); goto exit; } @@ -10479,23 +6266,34 @@ _wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev, boo /* Check NAN is enabled, if enabled exit else continue */ if (wl_cfgnan_is_enabled(cfg)) { err = BCME_UNSUPPORTED; - ANDROID_ERROR(("Nan is enabled, NAN+STA+FAKEAP concurrency is not supported\n")); + WL_ERR(("Nan is enabled, NAN+STA+FAKEAP concurrency is not supported\n")); goto exit; } #endif /* WL_NAN */ + if (dhd->early_suspended) { + /* Set BEACON_RECV in suspend mode */ + WL_INFORM_MEM(("Already suspend mode, Aborting beacon recv start\n")); + cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_SUSPENDED; + if ((err = wl_android_bcnrecv_event(pdev, BCNRECV_ATTR_STATUS, + WL_BCNRECV_SUSPENDED, WL_BCNRECV_SUSPEND, NULL, 0)) != BCME_OK) { + WL_ERR(("failed to send bcnrecv event, error:%d\n", err)); + } + goto exit; + } + /* Triggering an sendup_bcn iovar */ - err = wldev_iovar_setint(pdev, "sendup_bcn", 1); + err = wldev_iovar_setint_no_wl(pdev, "sendup_bcn", 1); if (unlikely(err)) { - ANDROID_ERROR(("sendup_bcn failed to set, error:%d\n", err)); + WL_ERR(("sendup_bcn failed to set, error:%d\n", err)); } else { cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STARTED; - ANDROID_INFO(("bcnrecv started. user_trigger:%d ifindex:%d\n", + WL_INFORM_MEM(("bcnrecv started. user_trigger:%d ifindex:%d\n", user_trigger, ndev->ifindex)); if (user_trigger) { if ((err = wl_android_bcnrecv_event(pdev, BCNRECV_ATTR_STATUS, WL_BCNRECV_STARTED, 0, NULL, 0)) != BCME_OK) { - ANDROID_ERROR(("failed to send bcnrecv event, error:%d\n", err)); + WL_ERR(("failed to send bcnrecv event, error:%d\n", err)); } } } @@ -10522,9 +6320,9 @@ _wl_android_bcnrecv_stop(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint /* Stop bcnrx except for fw abort event case */ if (reason != WL_BCNRECV_ROAMABORT) { - err = wldev_iovar_setint(pdev, "sendup_bcn", 0); + err = wldev_iovar_setint_no_wl(pdev, "sendup_bcn", 0); if (unlikely(err)) { - ANDROID_ERROR(("sendup_bcn failed to set error:%d\n", err)); + WL_ERR(("sendup_bcn failed to set error:%d\n", err)); goto exit; } } @@ -10535,7 +6333,7 @@ _wl_android_bcnrecv_stop(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint status = WL_BCNRECV_SUSPENDED; } else { cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STOPPED; - ANDROID_INFO(("bcnrecv stopped. reason:%d ifindex:%d\n", + WL_INFORM_MEM(("bcnrecv stopped. reason:%d ifindex:%d\n", reason, ndev->ifindex)); if (reason == WL_BCNRECV_USER_TRIGGER) { status = WL_BCNRECV_STOPPED; @@ -10545,7 +6343,7 @@ _wl_android_bcnrecv_stop(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint } if ((err = wl_android_bcnrecv_event(pdev, BCNRECV_ATTR_STATUS, status, reason, NULL, 0)) != BCME_OK) { - ANDROID_ERROR(("failed to send bcnrecv event, error:%d\n", err)); + WL_ERR(("failed to send bcnrecv event, error:%d\n", err)); } exit: return err; @@ -10588,7 +6386,7 @@ wl_android_bcnrecv_suspend(struct net_device *ndev) mutex_lock(&cfg->bcn_sync); if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) { - ANDROID_INFO(("bcnrecv suspend\n")); + WL_INFORM_MEM(("bcnrecv suspend\n")); ret = _wl_android_bcnrecv_stop(cfg, ndev, WL_BCNRECV_SUSPEND); } mutex_unlock(&cfg->bcn_sync); @@ -10605,7 +6403,7 @@ wl_android_bcnrecv_resume(struct net_device *ndev) mutex_lock(&cfg->scan_sync); mutex_lock(&cfg->bcn_sync); if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED) { - ANDROID_INFO(("bcnrecv resume\n")); + WL_INFORM_MEM(("bcnrecv resume\n")); ret = _wl_android_bcnrecv_start(cfg, ndev, false); } mutex_unlock(&cfg->bcn_sync); @@ -10621,30 +6419,30 @@ wl_android_bcnrecv_config(struct net_device *ndev, char *cmd_argv, int total_len uint err = BCME_OK; if (!ndev) { - ANDROID_ERROR(("ndev is NULL\n")); + WL_ERR(("ndev is NULL\n")); return -EINVAL; } cfg = wl_get_cfg(ndev); if (!cfg) { - ANDROID_ERROR(("cfg is NULL\n")); + WL_ERR(("cfg is NULL\n")); return -EINVAL; } /* sync commands from user space */ mutex_lock(&cfg->usr_sync); if (strncmp(cmd_argv, "start", strlen("start")) == 0) { - ANDROID_INFO(("BCNRECV start\n")); + WL_INFORM(("BCNRECV start\n")); err = wl_android_bcnrecv_start(cfg, ndev); if (err != BCME_OK) { - ANDROID_ERROR(("Failed to process the start command, error:%d\n", err)); + WL_ERR(("Failed to process the start command, error:%d\n", err)); goto exit; } } else if (strncmp(cmd_argv, "stop", strlen("stop")) == 0) { - ANDROID_INFO(("BCNRECV stop\n")); + WL_INFORM(("BCNRECV stop\n")); err = wl_android_bcnrecv_stop(ndev, WL_BCNRECV_USER_TRIGGER); if (err != BCME_OK) { - ANDROID_ERROR(("Failed to stop the bcn recv, error:%d\n", err)); + WL_ERR(("Failed to stop the bcn recv, error:%d\n", err)); goto exit; } } else { @@ -10657,33 +6455,88 @@ exit: #endif /* WL_BCNRECV */ #ifdef SUPPORT_LATENCY_CRITICAL_DATA -static int +int wl_android_set_latency_crt_data(struct net_device *dev, int mode) { int ret; +#ifdef WL_LATENCY_CONFIG + char iovreq[WLC_IOCTL_SMLEN] = {0}; + wl_low_latency_v1_t low_latency; +#endif /* WL_LATENCY_CONFIG */ + struct bcm_cfg80211 *cfg = NULL; #ifdef DHD_GRO_ENABLE_HOST_CTRL dhd_pub_t *dhdp = NULL; #endif /* DHD_GRO_ENABLE_HOST_CTRL */ + if (mode >= LATENCY_CRT_DATA_MODE_LAST) { - return BCME_BADARG; + ret = BCME_BADARG; + goto exit; } + + if (!dev) { + WL_ERR(("ndev is NULL\n")); + ret = -EINVAL; + goto exit; + } + + cfg = wl_get_cfg(dev); + if (!cfg) { + WL_ERR(("cfg is NULL\n")); + ret = -EINVAL; + goto exit; + } + + if (mode == cfg->latency_mode) { + WL_INFORM_MEM(("Mode value: %d is already configured!!\n", cfg->latency_mode)); + ret = BCME_OK; + goto exit; + } + #ifdef DHD_GRO_ENABLE_HOST_CTRL dhdp = wl_cfg80211_get_dhdp(dev); if (mode != LATENCY_CRT_DATA_MODE_OFF) { - ANDROID_ERROR(("Not permitted GRO by framework\n")); + WL_ERR(("Not permitted GRO by framework\n")); dhdp->permitted_gro = FALSE; } else { - ANDROID_ERROR(("Permitted GRO by framework\n")); + WL_ERR(("Permitted GRO by framework\n")); dhdp->permitted_gro = TRUE; } #endif /* DHD_GRO_ENABLE_HOST_CTRL */ + +#ifdef WL_LATENCY_CONFIG + bzero(&low_latency, sizeof(wl_low_latency_v1_t)); + + /* set the version and length of wl_low_latency_v1_t */ + low_latency.version = WL_LOW_LATENCY_V1; + low_latency.length = sizeof(wl_low_latency_v1_t); + low_latency.config.version = WL_LOW_LATENCY_CONFIG_V1; + low_latency.config.length = sizeof(low_latency.config); + low_latency.config.periodicity = DEF_LOW_LATENCY_PERIOD; + low_latency.mode = mode; + + WL_DBG(("low_latency: mode is %d, periodicity is %d\n", + low_latency.mode, low_latency.config.periodicity)); + + ret = wldev_iovar_setbuf(dev, "low_latency", (char *)&low_latency, + sizeof(wl_low_latency_v1_t), iovreq, WLC_IOCTL_SMLEN, NULL); + if (ret < 0) { + WL_ERR(("low_latency set failed:%d\n", ret)); + goto exit; + } else { + WL_INFORM_MEM(("low_latency set ok\n")); + } +#endif /* WL_LATENCY_CONFIG */ + ret = wldev_iovar_setint(dev, "latency_critical_data", mode); if (ret != BCME_OK) { - ANDROID_ERROR(("failed to set latency_critical_data mode %d, error = %d\n", + WL_ERR(("failed to set latency_critical_data mode %d, error = %d\n", mode, ret)); - return ret; + goto exit; } + /* Cache mode value */ + cfg->latency_mode = mode; +exit: return ret; } @@ -10696,7 +6549,7 @@ wl_android_get_latency_crt_data(struct net_device *dev, char *command, int total ret = wldev_iovar_getint(dev, "latency_critical_data", &mode); if (ret != BCME_OK) { - ANDROID_ERROR(("failed to get latency_critical_data error = %d\n", ret)); + WL_ERR(("failed to get latency_critical_data error = %d\n", ret)); return ret; } @@ -10707,6 +6560,77 @@ wl_android_get_latency_crt_data(struct net_device *dev, char *command, int total } #endif /* SUPPORT_LATENCY_CRITICAL_DATA */ +#ifdef WL_LATENCY_CONFIG +static int +wl_android_set_low_latency(struct net_device *dev, char* cmd_str) +{ + int ret; + u8 mode = 0, period = 0; + char iovreq[WLC_IOCTL_SMLEN] = {0}; + wl_low_latency_v1_t low_latency; + char *param = NULL, *val_p = NULL; + + bzero(&low_latency, sizeof(wl_low_latency_v1_t)); + + /* set the version and length of wl_low_latency_v1_t */ + low_latency.version = WL_LOW_LATENCY_V1; + low_latency.length = sizeof(wl_low_latency_v1_t); + low_latency.config.version = WL_LOW_LATENCY_CONFIG_V1; + low_latency.config.length = sizeof(low_latency.config); + + param = cmd_str; + + /* parsing string options */ + while ((val_p = bcmstrtok(¶m, " ", NULL)) != NULL) { + if (!strnicmp(val_p, "mode", strlen(val_p))) { + val_p = bcmstrtok(¶m, " ", NULL); + if (val_p) { + /* get mode */ + mode = bcm_atoi(val_p); + if (mode >= LATENCY_CRT_DATA_MODE_LAST) { + ret = BCME_BADARG; + goto exit; + } + } else { + WL_ERR(("%s : no mode value\n", __FUNCTION__)); + ret = BCME_BADARG; + goto exit; + } + } else if (!strnicmp(val_p, "period", strlen(val_p))) { + val_p = bcmstrtok(¶m, " ", NULL); + if (val_p) { + /* get period */ + period = bcm_atoi(val_p); + } else { + WL_ERR(("%s : no period value\n", __FUNCTION__)); + ret = BCME_BADARG; + goto exit; + } + } else { + WL_ERR(("%s : unsupported parameter: %s\n", __FUNCTION__, param)); + ret = BCME_BADARG; + goto exit; + } + } + + low_latency.config.periodicity = period; + low_latency.mode = mode; + + WL_DBG(("low_latency: mode is %d, periodicity is %d\n", + low_latency.mode, low_latency.config.periodicity)); + + ret = wldev_iovar_setbuf(dev, "low_latency", (char *)&low_latency, + sizeof(wl_low_latency_v1_t), iovreq, WLC_IOCTL_SMLEN, NULL); + if (ret < 0) { + WL_ERR(("low_latency set failed:%d\n", ret)); + } else { + WL_INFORM_MEM(("low_latency set ok\n")); + } +exit: + return ret; +} +#endif /* WL_LATENCY_CONFIG */ + #ifdef WL_CAC_TS /* CAC TSPEC functionality code implementation */ static void @@ -10751,7 +6675,7 @@ wl_android_handle_cac_action(struct bcm_cfg80211 * cfg, struct net_device * ndev ((tspec_arg.surplus_bw < TSPEC_MIN_SURPLUS_BW) || (tspec_arg.surplus_bw > TSPEC_MAX_SURPLUS_BW)) || (tspec_arg.nom_msdu_size > TSPEC_MAX_MSDU_SIZE)) { - ANDROID_ERROR(("Invalid params access_category %hhu nom_msdu_size %hu" + WL_ERR(("Invalid params access_category %hhu nom_msdu_size %hu" " surplus BW %hu\n", access_category, tspec_arg.nom_msdu_size, tspec_arg.surplus_bw)); return BCME_USAGE_ERROR; @@ -10771,7 +6695,7 @@ wl_android_handle_cac_action(struct bcm_cfg80211 * cfg, struct net_device * ndev sscanf(argv, "%*s %hhu", &access_category); if (access_category > TSPEC_MAX_ACCESS_CATEGORY) { - ANDROID_INFO(("Invalide param, access_category %hhu\n", access_category)); + WL_INFORM_MEM(("Invalide param, access_category %hhu\n", access_category)); return BCME_USAGE_ERROR; } /* Update tsinfo */ @@ -10779,14 +6703,14 @@ wl_android_handle_cac_action(struct bcm_cfg80211 * cfg, struct net_device * ndev } if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) { - ANDROID_ERROR(("Find index failed\n")); + WL_ERR(("Find index failed\n")); err = BCME_ERROR; return err; } err = wldev_iovar_setbuf_bsscfg(ndev, ts_cmd, &tspec_arg, sizeof(tspec_arg), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); if (unlikely(err)) { - ANDROID_ERROR(("%s error (%d)\n", ts_cmd, err)); + WL_ERR(("%s error (%d)\n", ts_cmd, err)); } return err; @@ -10799,19 +6723,19 @@ wl_android_cac_ts_config(struct net_device *ndev, char *cmd_argv, int total_len) s32 err = BCME_OK; if (!ndev) { - ANDROID_ERROR(("ndev is NULL\n")); + WL_ERR(("ndev is NULL\n")); return -EINVAL; } cfg = wl_get_cfg(ndev); if (!cfg) { - ANDROID_ERROR(("cfg is NULL\n")); + WL_ERR(("cfg is NULL\n")); return -EINVAL; } /* Request supported only for primary interface */ if (ndev != bcmcfg_to_prmry_ndev(cfg)) { - ANDROID_ERROR(("Request on non-primary interface\n")); + WL_ERR(("Request on non-primary interface\n")); return -1; } @@ -10832,28 +6756,23 @@ wl_android_get_channel_util(struct net_device *ndev, char *command, int total_le s32 bytes_written, err = 0; wl_bssload_t bssload; u8 smbuf[WLC_IOCTL_SMLEN]; - u8 chan_use_percentage = 0; if ((err = wldev_iovar_getbuf(ndev, "bssload_report", NULL, 0, smbuf, WLC_IOCTL_SMLEN, NULL))) { - ANDROID_ERROR(("Getting bssload report failed with err=%d \n", err)); + WL_ERR(("Getting bssload report failed with err=%d \n", err)); return err; } (void)memcpy_s(&bssload, sizeof(wl_bssload_t), smbuf, sizeof(wl_bssload_t)); - /* Convert channel usage to percentage value */ - chan_use_percentage = (bssload.chan_util * 100) / 255; - - bytes_written = snprintf(command, total_len, "CU %hhu", - chan_use_percentage); - ANDROID_INFO(("Channel Utilization %u %u\n", bssload.chan_util, chan_use_percentage)); + WL_DBG(("Channel Utilization %u\n", bssload.chan_util)); + bytes_written = snprintf(command, total_len, "%hhu", bssload.chan_util); return bytes_written; } #endif /* WL_GET_CU */ #ifdef RTT_GEOFENCE_INTERVAL -#if defined (RTT_SUPPORT) && defined(WL_NAN) +#if defined(RTT_SUPPORT) && defined(WL_NAN) static void wl_android_set_rtt_geofence_interval(struct net_device *ndev, char *command) { @@ -10890,7 +6809,7 @@ wl_android_set_softap_elna_bypass(struct net_device *dev, char *command, int tot /* get the interface name */ token = bcmstrtok(&pos, " ", NULL); if (!token) { - ANDROID_ERROR(("%s: Invalid arguments about interface name\n", __FUNCTION__)); + WL_ERR(("%s: Invalid arguments about interface name\n", __FUNCTION__)); return -EINVAL; } ifname = token; @@ -10898,7 +6817,7 @@ wl_android_set_softap_elna_bypass(struct net_device *dev, char *command, int tot /* get enable/disable flag */ token = bcmstrtok(&pos, " ", NULL); if (!token) { - ANDROID_ERROR(("%s: Invalid arguments about Enable/Disable\n", __FUNCTION__)); + WL_ERR(("%s: Invalid arguments about Enable/Disable\n", __FUNCTION__)); return -EINVAL; } enable = bcm_atoi(token); @@ -10906,7 +6825,7 @@ wl_android_set_softap_elna_bypass(struct net_device *dev, char *command, int tot CUSTOMER_HW4_EN_CONVERT(enable); err = wl_set_softap_elna_bypass(dev, ifname, enable); if (unlikely(err)) { - ANDROID_ERROR(("%s: Failed to set ELNA Bypass of SoftAP mode, err=%d\n", + WL_ERR(("%s: Failed to set ELNA Bypass of SoftAP mode, err=%d\n", __FUNCTION__, err)); return err; } @@ -10934,19 +6853,19 @@ wl_android_get_softap_elna_bypass(struct net_device *dev, char *command, int tot /* get the interface name */ token = bcmstrtok(&pos, " ", NULL); if (!token) { - ANDROID_ERROR(("%s: Invalid arguments about interface name\n", __FUNCTION__)); + WL_ERR(("%s: Invalid arguments about interface name\n", __FUNCTION__)); return -EINVAL; } ifname = token; err = wl_get_softap_elna_bypass(dev, ifname, &softap_elnabypass); if (unlikely(err)) { - ANDROID_ERROR(("%s: Failed to get ELNA Bypass of SoftAP mode, err=%d\n", + WL_ERR(("%s: Failed to get ELNA Bypass of SoftAP mode, err=%d\n", __FUNCTION__, err)); return err; } else { softap_elnabypass--; //Convert format to Customer HW4 - ANDROID_INFO(("%s: eLNA Bypass feature enable status is %d\n", + WL_DBG(("%s: eLNA Bypass feature enable status is %d\n", __FUNCTION__, softap_elnabypass)); bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_SOFTAP_ELNA_BYPASS, softap_elnabypass); @@ -10956,6 +6875,110 @@ wl_android_get_softap_elna_bypass(struct net_device *dev, char *command, int tot } #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */ +#ifdef CUSTOM_SOFTAP_SET_ANT +#define HOTSPOT_ANTENNA_MODE_MIMO 1 +#define HOTSPOT_ANTENNA_MODE_SISO 2 + +static int +wl_android_set_softap_antenna(struct net_device *dev, char *command) +{ + char *ifname = NULL; + char *pos, *token; + int err = BCME_OK; + int mimo_siso = 0; + int set_chain = 0; + + /* + * DRIVER SET_HOTSPOT_ANTENNA_MODE + * MIMO:1, SISO:2 + */ + pos = command; + + /* drop command */ + token = bcmstrtok(&pos, " ", NULL); + + /* get the interface name */ + token = bcmstrtok(&pos, " ", NULL); + if (!token) { + WL_ERR(("%s: Invalid arguments about interface name\n", __FUNCTION__)); + return -EINVAL; + } + ifname = token; + + /* get mimo_siso value */ + token = bcmstrtok(&pos, " ", NULL); + if (!token) { + WL_ERR(("%s: Invalid arguments about MIMO/SISO\n", __FUNCTION__)); + return -EINVAL; + } + mimo_siso = bcm_atoi(token); + + if (mimo_siso == HOTSPOT_ANTENNA_MODE_SISO) { + /* Set SISO mode */ + set_chain = 1; + } else { + /* Set MIMO mode for other cases */ + set_chain = 3; + } + + WL_ERR(("[Test Mode] %s: Set Antenna for SoftAP [%d]\n", __FUNCTION__, set_chain)); + err = wl_set_softap_antenna(dev, ifname, set_chain); + if (unlikely(err)) { + WL_ERR(("%s: Failed to set Antenna of SoftAP mode[%d], err=%d\n", + __FUNCTION__, mimo_siso, err)); + return -EIO; + } + + return err; +} + +static int +wl_android_get_softap_antenna(struct net_device *dev, char *command, int total_len) +{ + char *ifname = NULL; + char *pos, *token; + int err = BCME_OK; + int bytes_written = 0; + int mimo_siso = 0; + uint32 cur_rxchain; + + /* + * DRIVER GET_HOTSPOT_ANTENNA_MODE + */ + pos = command; + + /* drop command */ + token = bcmstrtok(&pos, " ", NULL); + + /* get the interface name */ + token = bcmstrtok(&pos, " ", NULL); + if (!token) { + WL_ERR(("%s: Invalid arguments about interface name\n", __FUNCTION__)); + return -EINVAL; + } + ifname = token; + + err = wl_get_softap_antenna(dev, ifname, &cur_rxchain); + if (unlikely(err)) { + WL_ERR(("%s: Failed to get MIMO/SISO info of SoftAP mode, err=%d\n", + __FUNCTION__, err)); + return -EIO; + } else { + if (cur_rxchain == 3) { + mimo_siso = HOTSPOT_ANTENNA_MODE_MIMO; + } else { + mimo_siso = HOTSPOT_ANTENNA_MODE_SISO; + } + WL_DBG(("[Test Mode] %s: SoftAP antenna status is %d\n", + __FUNCTION__, mimo_siso)); + bytes_written = snprintf(command, total_len, "%s %d", + CMD_GET_HOTSPOT_ANTENNA_MODE, mimo_siso); + } + + return bytes_written; +} +#endif /* CUSTOM_SOFTAP_SET_ANT */ + #ifdef WL_NAN int wl_android_get_nan_status(struct net_device *dev, char *command, int total_len) @@ -10966,7 +6989,7 @@ wl_android_get_nan_status(struct net_device *dev, char *command, int total_len) error = wl_cfgnan_get_status(dev, &nstatus); if (error) { - ANDROID_ERROR(("Failed to get nan status (%d)\n", error)); + WL_ERR(("Failed to get nan status (%d)\n", error)); return error; } @@ -11011,24 +7034,24 @@ wl_nan_ranging_bw(struct net_device *net, int bw, char *command) } param = {0, 0}; if (bw < NAN_RANGING_5G_BW20 || bw > NAN_RANGING_5G_BW80) { - ANDROID_ERROR(("Wrong BW cmd:%d, %s\n", bw, __FUNCTION__)); + WL_ERR(("Wrong BW cmd:%d, %s\n", bw, __FUNCTION__)); bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL"); return bytes_written; } switch (bw) { case NAN_RANGING_5G_BW20: - ANDROID_ERROR(("NAN_RANGING 5G/BW20\n")); + WL_ERR(("NAN_RANGING 5G/BW20\n")); param.band = WLC_BAND_5G; param.bw_cap = 0x1; break; case NAN_RANGING_5G_BW40: - ANDROID_ERROR(("NAN_RANGING 5G/BW40\n")); + WL_ERR(("NAN_RANGING 5G/BW40\n")); param.band = WLC_BAND_5G; param.bw_cap = 0x3; break; case NAN_RANGING_5G_BW80: - ANDROID_ERROR(("NAN_RANGING 5G/BW80\n")); + WL_ERR(("NAN_RANGING 5G/BW80\n")); param.band = WLC_BAND_5G; param.bw_cap = 0x7; break; @@ -11036,23 +7059,23 @@ wl_nan_ranging_bw(struct net_device *net, int bw, char *command) err = wldev_ioctl_set(net, WLC_DOWN, &val, sizeof(s32)); if (err) { - ANDROID_ERROR(("WLC_DOWN error %d\n", err)); + WL_ERR(("WLC_DOWN error %d\n", err)); bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL"); } else { err = wldev_iovar_setbuf(net, "bw_cap", ¶m, sizeof(param), ioctl_buf, sizeof(ioctl_buf), NULL); if (err) { - ANDROID_ERROR(("BW set failed\n")); + WL_ERR(("BW set failed\n")); bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL"); } else { - ANDROID_ERROR(("BW set done\n")); + WL_ERR(("BW set done\n")); bytes_written = scnprintf(command, sizeof("OK"), "OK"); } err = wldev_ioctl_set(net, WLC_UP, &val, sizeof(s32)); if (err < 0) { - ANDROID_ERROR(("WLC_UP error %d\n", err)); + WL_ERR(("WLC_UP error %d\n", err)); bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL"); } } @@ -11082,70 +7105,92 @@ wl_android_set_softap_ax_mode(struct net_device *dev, const char* cmd_str) if (cmd_str) { enable = bcm_atoi(cmd_str); } else { - ANDROID_ERROR(("failed due to wrong received parameter\n")); + WL_ERR(("failed due to wrong received parameter\n")); err = -EINVAL; goto exit; } if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { - ANDROID_ERROR(("find softap index from wdev failed\n")); + WL_ERR(("find softap index from wdev failed\n")); err = -EINVAL; goto exit; } - ANDROID_INFO(("HAPD_SET_AX_MODE = %d\n", enable)); - err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_HE_FEATURES_HE_AP, (bool)enable); + WL_INFORM(("HAPD_SET_AX_MODE = %d\n", enable)); + err = wl_cfg80211_change_he_features(dev, cfg, bssidx, WL_HE_FEATURES_HE_AP, (bool)enable); if (err) { - ANDROID_ERROR(("failed to set softap ax mode(%d)\n", enable)); + WL_ERR(("failed to set softap ax mode(%d)\n", enable)); } exit : return err; } -#ifdef WL_P2P_6G -#define WL_HE_FEATURES_P2P_6G 0x0200u -static int -wl_android_enable_p2p_6g(struct net_device *dev, int enable) -{ - s32 err = 0; - s32 bssidx = 0; - struct bcm_cfg80211 *cfg = NULL; - - if (!dev) { - err = -EINVAL; - return err; - } - - cfg = wl_get_cfg(dev); - if (!cfg) { - err = -EINVAL; - return err; - } - - if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { - ANDROID_ERROR(("find softap index from wdev failed\n")); - err = -EINVAL; - return err; - } - - /* Enable/disable for P2P 6G, both P2P and P2P_6G needs to be handled together */ - err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, (WL_HE_FEATURES_HE_P2P | - WL_HE_FEATURES_P2P_6G), (bool)enable); - if (err == BCME_OK) { - /* Set P2P 6G support flag */ - if (enable) { - cfg->p2p_6g_enabled = TRUE; - } else { - cfg->p2p_6g_enabled = FALSE; - } - } - - return err; -} -#endif /* WL_P2P_6G */ - #ifdef WL_TWT +static int +wl_android_twt_bcmerr_to_kernel_err(int bcm_err) +{ + int ret = 0; + + switch (bcm_err) { + case BCME_OK: + ret = 0; + break; + case BCME_ERROR: + ret = -EAGAIN; + break; + case BCME_BADARG: /* Bad Argument */ + ret = -EINVAL; + break; + case BCME_RANGE: /* TWT parameter value provided is not in allowed range */ + ret = -ERANGE; + break; + case BCME_BUSY: + /* Busy + * 1. STA is in off-channel/Scan in progress + * 2. STA is in allTWT Suspend mode + * 3. Other TWT Action frame transmission is not completed yet + */ + ret = -EBUSY; + break; + case BCME_NOTASSOCIATED: /* STA Not Associated */ + ret = -ENOTCONN; + break; + case BCME_EPERM: /* Not Permitted because of + * 1. More than one TWT + * 2. More than one concurrent connection is active. + * 3. BT is active + */ + ret = -EPERM; + break; + case BCME_NOTFOUND: /* Not Found. Peer not found for given mac address */ + case BCME_NORESOURCE: /* Not Enough resources to establish new TWT session */ + ret = -ENODEV; + break; + case BCME_NOMEM: + ret = -ENOMEM; + break; + case BCME_UNSUPPORTED: /* Unsupported. + * 1. No TWT support + * 2. TWT capabilities is not set by device or peer device + */ + ret = -EOPNOTSUPP; + break; + case BCME_VERSION: + ret = -ENOEXEC; + break; + case BCME_BUFTOOSHORT: + ret = -ENOBUFS; + break; + default: + ret = -EAGAIN; + break; + } + + WL_DBG(("twt wifi_error ret:%d\n", ret)); + + return ret; +} static int wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) @@ -11163,7 +7208,7 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) WL_DBG_MEM(("Enter. cmd:%s\n", command)); if (strlen(command) == strlen(CMD_TWT_SETUP)) { - ANDROID_ERROR(("Error, twt_setup cmd missing params\n")); + WL_ERR(("Error, twt_setup cmd missing params\n")); bw = -EINVAL; goto exit; } @@ -11173,6 +7218,7 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) val.length = sizeof(val.version) + sizeof(val.length); /* Default values, Overide Below */ + val.desc.flow_flags = 0; val.desc.wake_time_h = 0xFFFFFFFF; val.desc.wake_time_l = 0xFFFFFFFF; val.desc.wake_int_min = 0xFFFFFFFF; @@ -11180,22 +7226,54 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) val.desc.wake_dur_min = 0xFFFFFFFF; val.desc.wake_dur_max = 0xFFFFFFFF; val.desc.avg_pkt_num = 0xFFFFFFFF; + val.desc.avg_pkt_size = 0xFFFFFFFF; pos = command + sizeof(CMD_TWT_SETUP); + /* Config ID */ + token = strsep((char**)&pos, " "); + if (!token) { + WL_ERR(("Mandatory param ConfigID not present\n")); + bw = -EINVAL; + goto exit; + } + val.desc.configID = (u8)bcm_atoi(token); + /* negotiation_type */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("Mandatory param negotiation type not present\n")); + WL_ERR(("Mandatory param negotiation type not present\n")); bw = -EINVAL; goto exit; } - val.desc.negotiation_type = htod32((u32)bcm_atoi(token)); + val.desc.negotiation_type = (u8)bcm_atoi(token); + + /* Flow Type */ + token = strsep((char**)&pos, " "); + if (!token) { + WL_ERR(("Mandatory param Flow Type not present\n")); + bw = -EINVAL; + goto exit; + } + if (htod32((u32)bcm_atoi(token)) == 1) { + val.desc.flow_flags |= WL_TWT_FLOW_FLAG_UNANNOUNCED; + } + + /* Trigger Type */ + token = strsep((char**)&pos, " "); + if (!token) { + WL_ERR(("Mandatory param Trigger Type not present\n")); + bw = -EINVAL; + goto exit; + } + if (htod32((u32)bcm_atoi(token)) == 1) { + val.desc.flow_flags |= WL_TWT_FLOW_FLAG_TRIGGER; + } /* Wake Duration */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("Mandatory param wake Duration not present\n")); + WL_ERR(("Mandatory param wake Duration not present\n")); bw = -EINVAL; goto exit; } @@ -11204,7 +7282,7 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) /* Wake interval */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("Mandaory param Wake Interval not present\n")); + WL_ERR(("Mandaory param Wake Interval not present\n")); bw = -EINVAL; goto exit; } @@ -11213,7 +7291,7 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) /* Wake Time parameter */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("No Wake Time parameter provided, using default\n")); + WL_ERR(("No Wake Time parameter provided, using default\n")); } else { twt = (u64)bcm_atoi(token); val32 = htod32((u32)(twt >> 32)); @@ -11226,7 +7304,7 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) /* Minimum allowed Wake interval */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("No Minimum allowed Wake interval provided, using default\n")); + WL_ERR(("No Minimum allowed Wake interval provided, using default\n")); } else { val32 = htod32((u32)bcm_atoi(token)); if (val32 != -1) { @@ -11237,7 +7315,7 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) /* Max Allowed Wake interval */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("Maximum allowed Wake interval not provided, using default\n")); + WL_ERR(("Maximum allowed Wake interval not provided, using default\n")); } else { val32 = htod32((u32)bcm_atoi(token)); if (val32 != -1) { @@ -11248,7 +7326,7 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) /* Minimum allowed Wake duration */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("Maximum allowed Wake duration not provided, using default\n")); + WL_ERR(("Maximum allowed Wake duration not provided, using default\n")); } else { val32 = htod32((u32)bcm_atoi(token)); if (val32 != -1) { @@ -11259,7 +7337,7 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) /* Maximum allowed Wake duration */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("Maximum allowed Wake duration not provided, using default\n")); + WL_ERR(("Maximum allowed Wake duration not provided, using default\n")); } else { val32 = htod32((u32)bcm_atoi(token)); if (val32 != -1) { @@ -11270,7 +7348,7 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) /* Average number of packets */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("Average number of packets not provided, using default\n")); + WL_ERR(("Average number of packets not provided, using default\n")); } else { val32 = htod32((u32)bcm_atoi(token)); if (val32 != -1) { @@ -11278,16 +7356,14 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) } } - /* a peer_address */ + /* Average packets size */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("Average number of packets not provided, using default\n")); + WL_ERR(("Average packets size not provided, using default\n")); } else { - /* get peer mac */ - if (!bcm_ether_atoe(token, &val.peer)) { - ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__)); - bw = BCME_ERROR; - goto exit; + val32 = htod32((u32)bcm_atoi(token)); + if (val32 != -1) { + val.desc.avg_pkt_size = htod32((u32)bcm_atoi(token)); } } @@ -11300,10 +7376,10 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) bw = wldev_iovar_setbuf(ndev, "twt", mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL); if (bw < 0) { - ANDROID_ERROR(("twt config set failed. ret:%d\n", bw)); + WL_ERR(("twt config set failed. ret:%d\n", bw)); } exit: - return bw; + return wl_android_twt_bcmerr_to_kernel_err(bw); } static int @@ -11312,93 +7388,37 @@ wl_android_twt_display_cap(wl_twt_cap_t *result, char *command, int total_len) int rem_len = 0, bytes_written = 0; rem_len = total_len; - bytes_written = scnprintf(command, rem_len, "Device TWT Capabilities:\n"); + + bytes_written = scnprintf(command, rem_len, "0x%04x%04x\n", + result->device_cap, result->peer_cap); + CHECK_SCNPRINTF_RET_VAL(bytes_written); command += bytes_written; rem_len -= bytes_written; - bytes_written = scnprintf(command, rem_len, "Requester Support %d, \t", - !!(result->device_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT)); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, "Responder Support %d, \t", - !!(result->device_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT)); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, "Broadcast TWT Support %d, \t", - !!(result->device_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT)); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, "Flexible TWT Support %d, \t", - !!(result->device_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT)); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, "TWT Required by peer %d, \n", - !!(result->device_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED)); - command += bytes_written; - rem_len -= bytes_written; - - /* Peer capabilities */ - bytes_written = scnprintf(command, rem_len, "\nPeer TWT Capabilities:\n"); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, "Requester Support %d, \t", - !!(result->peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT)); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, "Responder Support %d, \t", - !!(result->peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT)); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, "Broadcast TWT Support %d, \t", - !!(result->peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT)); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, "Flexible TWT Support %d, \t", - !!(result->peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT)); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, "TWT Required by peer %d, \n", - !!(result->peer_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED)); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, "\t------------" - "---------------------------------------------------\n\n"); - command += bytes_written; - rem_len -= bytes_written; - ANDROID_INFO(("Device TWT Capabilities:\n")); - ANDROID_INFO(("Requester Support %d, \t", + WL_DBG(("Device TWT Capabilities:\n")); + WL_DBG(("Requester Support %d, \t", !!(result->device_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT))); - ANDROID_INFO(("Responder Support %d, \t", + WL_DBG(("Responder Support %d, \t", !!(result->device_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT))); - ANDROID_INFO(("Broadcast TWT Support %d, \t", + WL_DBG(("Broadcast TWT Support %d, \t", !!(result->device_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT))); - ANDROID_INFO(("Flexible TWT Support %d, \t", + WL_DBG(("Flexible TWT Support %d, \t", !!(result->device_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT))); - ANDROID_INFO(("TWT Required by peer %d, \n", + WL_DBG(("TWT Required by peer %d, \n", !!(result->device_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED))); /* Peer capabilities */ - ANDROID_INFO(("\nPeer TWT Capabilities:\n")); - ANDROID_INFO(("Requester Support %d, \t", + WL_DBG(("\nPeer TWT Capabilities:\n")); + WL_DBG(("Requester Support %d, \t", !!(result->peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT))); - ANDROID_INFO(("Responder Support %d, \t", + WL_DBG(("Responder Support %d, \t", !!(result->peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT))); - ANDROID_INFO(("Broadcast TWT Support %d, \t", + WL_DBG(("Broadcast TWT Support %d, \t", !!(result->peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT))); - ANDROID_INFO(("Flexible TWT Support %d, \t", + WL_DBG(("Flexible TWT Support %d, \t", !!(result->peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT))); - ANDROID_INFO(("TWT Required by peer %d, \n", + WL_DBG(("TWT Required by peer %d, \n", !!(result->peer_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED))); - ANDROID_INFO(("\t-----------------------------------------------------------------\n\n")); + WL_DBG(("\t-----------------------------------------------------------------\n\n")); if ((total_len - rem_len) > 0) { return (total_len - rem_len); @@ -11427,7 +7447,7 @@ wl_android_twt_cap(struct net_device *dev, char *command, int total_len) iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); if (iovresp == NULL) { - ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); + DHD_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); goto exit; } @@ -11437,28 +7457,28 @@ wl_android_twt_cap(struct net_device *dev, char *command, int total_len) ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_CAP, sizeof(cmd_cap), (uint8 *)&cmd_cap, BCM_XTLV_OPTION_ALIGN32); if (ret != BCME_OK) { - ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); + DHD_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); goto exit; } if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen, iovresp, WLC_IOCTL_MEDLEN, NULL))) { - ANDROID_ERROR(("Getting twt status failed with err=%d \n", ret)); + DHD_ERROR(("Getting twt status failed with err=%d \n", ret)); goto exit; } if (ret) { - ANDROID_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret)); + DHD_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret)); } (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result)); if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) { - ANDROID_ERROR(("capability ver %d, \n", dtoh16(result.version))); + DHD_ERROR(("capability ver %d, \n", dtoh16(result.version))); ret = wl_android_twt_display_cap(&result, command, total_len); return ret; } else { ret = BCME_UNSUPPORTED; - ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version))); + DHD_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version))); goto exit; } @@ -11474,181 +7494,93 @@ static int wl_android_twt_status_display_v1(wl_twt_status_v1_t *status, char *command, int total_len) { uint i; - wl_twt_sdesc_t *desc = NULL; + wl_twt_sdesc_v0_t *desc = NULL; + u64 wake_time = 0; int rem_len = 0, bytes_written = 0; rem_len = total_len; - ANDROID_ERROR(("\nNumber of Individual TWTs: %d\n", status->num_fid)); - bytes_written = scnprintf(command, rem_len, - "\nNumber of Individual TWTs: %d\n", status->num_fid); - command += bytes_written; - rem_len -= bytes_written; - bytes_written = scnprintf(command, rem_len, - "Number of Broadcast TWTs: %d\n", status->num_bid); - command += bytes_written; - rem_len -= bytes_written; - bytes_written = scnprintf(command, rem_len, - "TWT SPPS Enabled %d \t STA Wake Status %d \t Wake Override %d\n", - !!(status->status_flags & WL_TWT_STATUS_FLAG_SPPS_ENAB), - !!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_STATE), - !!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_OVERRIDE)); - command += bytes_written; - rem_len -= bytes_written; - ANDROID_INFO(("Number of Broadcast TWTs: %d\n", status->num_bid)); - ANDROID_INFO(("TWT SPPS Enabled %d \t STA Wake Status %d \t Wake Override %d\n", + WL_DBG(("\nNumber of Individual TWTs: %d\n", status->num_fid)); + WL_DBG(("Number of Broadcast TWTs: %d\n", status->num_bid)); + WL_DBG(("TWT SPPS Enabled %d \t STA Wake Status %d \t Wake Override %d\n", !!(status->status_flags & WL_TWT_STATUS_FLAG_SPPS_ENAB), !!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_STATE), !!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_OVERRIDE))); - ANDROID_INFO(("\t---------------- Individual TWT list-------------------\n")); - bytes_written = scnprintf(command, rem_len, - "\t---------------- Individual TWT list-------------------\n"); - command += bytes_written; - rem_len -= bytes_written; + WL_DBG(("\t---------------- Individual TWT list-------------------\n")); for (i = 0; i < WL_TWT_MAX_ITWT; i ++) { - if ((status->itwt_status[i].state == WL_TWT_ACTIVE) || - (status->itwt_status[i].state == WL_TWT_SUSPEND)) { + WL_DBG(("Config ID %d\n", status->itwt_status[i].configID)); + if (status->itwt_status[i].configID != WL_TWT_INV_CONFIG_ID) { desc = &status->itwt_status[i].desc; - bytes_written = scnprintf(command, rem_len, "\tFlow ID %d \tState %d\t", - desc->flow_id, - status->itwt_status[i].state); + bytes_written = scnprintf(command, rem_len, + "%d %d %u %u\n", status->itwt_status[i].configID, + status->itwt_status[i].state, desc->wake_dur, + desc->wake_int); + CHECK_SCNPRINTF_RET_VAL(bytes_written); command += bytes_written; rem_len -= bytes_written; - bytes_written = scnprintf(command, rem_len, - "peer: "MACF"\n", - ETHER_TO_MACF(status->itwt_status[i].peer)); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, - "Unannounced %d\tTriggered %d\tProtection %d\t" - "Info Frame Disabled %d\n", - !!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED), - !!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER), - !!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT), - !!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED)); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, - "target wake time: 0x%08x%08x\t", - desc->wake_time_h, desc->wake_time_l); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, - "wake duration: %u\t", desc->wake_dur); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, - "wake interval: %u\t", desc->wake_int); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, - "TWT channel: %u\n", desc->channel); - command += bytes_written; - rem_len -= bytes_written; - ANDROID_INFO(("\tFlow ID %d \tState %d\t", + WL_DBG(("Config ID %d \tFlow ID %d \tState %d\t", + status->itwt_status[i].configID, desc->flow_id, status->itwt_status[i].state)); - ANDROID_INFO(("peer: "MACF"\n", ETHER_TO_MACF(status->itwt_status[i].peer))); - ANDROID_INFO(("Unannounced %d\tTriggered %d\tProtection %d\t" + WL_DBG(("peer: "MACF"\n", + ETHER_TO_MACF(status->itwt_status[i].peer))); + WL_DBG(("Unannounced %d\tTriggered %d\tProtection %d\t" "Info Frame Disabled %d\n", !!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED), !!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER), !!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT), !!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED))); - ANDROID_INFO(("target wake time: 0x%08x%08x\t", - desc->wake_time_h, desc->wake_time_l)); - ANDROID_INFO(("wake duration: %u\t", desc->wake_dur)); - ANDROID_INFO(("wake interval: %u\t", desc->wake_int)); - ANDROID_INFO(("TWT channel: %u\n", desc->channel)); + WL_DBG(("target wake time: %llu\t", wake_time)); + WL_DBG(("wake duration: %u\t", desc->wake_dur)); + WL_DBG(("wake interval: %u\t", desc->wake_int)); + WL_DBG(("TWT channel: %u\n", desc->channel)); + WL_DBG(("AvgPktNum: %u\tAvgPktSize: %u\n", + status->itwt_status[i].avg_pkt_num, + status->itwt_status[i].avg_pkt_size)); } } - ANDROID_INFO(("\t---------------- Broadcast TWT list-------------------\n")); - bytes_written = scnprintf(command, rem_len, - "\t---------------- Broadcast TWT list-------------------\n"); - command += bytes_written; - rem_len -= bytes_written; + WL_DBG(("\t---------------- Broadcast TWT list-------------------\n")); for (i = 0; i < WL_TWT_MAX_BTWT; i ++) { - if ((status->btwt_status[i].state == WL_TWT_ACTIVE) || - (status->btwt_status[i].state == WL_TWT_SUSPEND)) { + if (status->btwt_status[i].configID != WL_TWT_INV_CONFIG_ID) { desc = &status->btwt_status[i].desc; bytes_written = scnprintf(command, rem_len, - "Broadcast ID %d \tState %d\t", - desc->bid, status->btwt_status[i].state); + "%d %d %u %u\n", status->btwt_status[i].configID, + status->btwt_status[i].state, desc->wake_dur, + desc->wake_int); + CHECK_SCNPRINTF_RET_VAL(bytes_written); command += bytes_written; rem_len -= bytes_written; - bytes_written = scnprintf(command, rem_len, - "peer: "MACF"\n", - ETHER_TO_MACF(status->btwt_status[i].peer)); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, - "Unannounced %d\tTriggered %d\tProtection %d\t" - "Info Frame Disabled %d\t", - !!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED), - !!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER), - !!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT), - !!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED)); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, - "Frame Recommendation %d\tBTWT Persistence %d\n", - desc->frame_recomm, desc->btwt_persistence); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, - "target wake time: 0x%08x%08x\t", - desc->wake_time_h, desc->wake_time_l); - command += bytes_written; - rem_len -= bytes_written; - bytes_written = scnprintf(command, rem_len, - "wake duration: %u\t", desc->wake_dur); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, - "wake interval: %u\t", desc->wake_int); - command += bytes_written; - rem_len -= bytes_written; - - bytes_written = scnprintf(command, rem_len, - "TWT channel: %u\n", desc->channel); - command += bytes_written; - rem_len -= bytes_written; - ANDROID_INFO(("Broadcast ID %d \tState %d\t", + WL_DBG(("Config ID %d \tBroadcast ID %d \tState %d\t", + status->btwt_status[i].configID, desc->bid, status->btwt_status[i].state)); - ANDROID_INFO(("peer: "MACF"\n", ETHER_TO_MACF(status->btwt_status[i].peer))); - ANDROID_INFO(("Unannounced %d\tTriggered %d\tProtection %d\t" + WL_DBG(("peer: "MACF"\n", + ETHER_TO_MACF(status->btwt_status[i].peer))); + WL_DBG(("Unannounced %d\tTriggered %d\tProtection %d\t" "Info Frame Disabled %d\t", !!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED), !!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER), !!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT), !!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED))); - ANDROID_INFO(("Frame Recommendation %d\tBTWT Persistence %d\n", + WL_DBG(("Frame Recommendation %d\tBTWT Persistence %d\n", desc->frame_recomm, desc->btwt_persistence)); - ANDROID_INFO(("target wake time: 0x%08x%08x\t", - desc->wake_time_h, desc->wake_time_l)); - ANDROID_INFO(("wake duration: %u\t", desc->wake_dur)); - ANDROID_INFO(("wake interval: %u\t", desc->wake_int)); - ANDROID_INFO(("TWT channel: %u\n", desc->channel)); + WL_DBG(("target wake time: %llu\t", wake_time)); + WL_DBG(("wake duration: %u\t", desc->wake_dur)); + WL_DBG(("wake interval: %u\t", desc->wake_int)); + WL_DBG(("TWT channel: %u\n", desc->channel)); + WL_DBG(("AvgPktNum: %u\tAvgPktSize: %u\n", + status->btwt_status[i].avg_pkt_num, + status->btwt_status[i].avg_pkt_size)); } } if ((total_len - rem_len) > 0) { return (total_len - rem_len); } else { - return BCME_ERROR; + return BCME_OK; } } @@ -11661,6 +7593,7 @@ wl_android_twt_status_query(struct net_device *dev, char *command, int total_len uint8 *iovresp = NULL; wl_twt_status_cmd_v1_t status_cmd; wl_twt_status_v1_t result; + char *token, *pos; uint16 buflen = 0, bufstart = 0; struct bcm_cfg80211 *cfg = wl_get_cfg(dev); @@ -11670,9 +7603,19 @@ wl_android_twt_status_query(struct net_device *dev, char *command, int total_len status_cmd.version = WL_TWT_CMD_STATUS_VERSION_1; status_cmd.length = sizeof(status_cmd) - OFFSETOF(wl_twt_status_cmd_v1_t, peer); + pos = command + sizeof(CMD_TWT_STATUS_QUERY); + /* Config ID */ + token = strsep((char**)&pos, " "); + if (!token) { + WL_ERR(("Mandatory param config ID not present\n")); + ret = -EINVAL; + goto exit; + } + status_cmd.configID = (u8)bcm_atoi(token); + iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); if (iovresp == NULL) { - ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); + DHD_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); goto exit; } @@ -11682,28 +7625,28 @@ wl_android_twt_status_query(struct net_device *dev, char *command, int total_len ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATUS, sizeof(status_cmd), (uint8 *)&status_cmd, BCM_XTLV_OPTION_ALIGN32); if (ret != BCME_OK) { - ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); + DHD_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); goto exit; } if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen, iovresp, WLC_IOCTL_MEDLEN, NULL))) { - ANDROID_ERROR(("Getting twt status failed with err=%d \n", ret)); + DHD_ERROR(("Getting twt status failed with err=%d \n", ret)); goto exit; } if (ret) { - ANDROID_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret)); + DHD_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret)); } (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result)); if (dtoh16(result.version) == WL_TWT_CMD_STATUS_VERSION_1) { - ANDROID_ERROR(("status query ver %d, \n", dtoh16(result.version))); + DHD_ERROR(("status query ver %d, \n", dtoh16(result.version))); ret = wl_android_twt_status_display_v1(&result, command, total_len); return ret; } else { ret = BCME_UNSUPPORTED; - ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version))); + DHD_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version))); goto exit; } @@ -11731,7 +7674,7 @@ wl_android_twt_info(struct net_device *ndev, char *command, int total_len) WL_DBG_MEM(("Enter. cmd:%s\n", command)); if (strlen(command) == strlen(CMD_TWT_INFO)) { - ANDROID_ERROR(("Error, twt teardown cmd missing params\n")); + WL_ERR(("Error, twt teardown cmd missing params\n")); bw = -EINVAL; goto exit; } @@ -11747,55 +7690,30 @@ wl_android_twt_info(struct net_device *ndev, char *command, int total_len) pos = command + sizeof(CMD_TWT_TEARDOWN); - /* (all TWT) */ + /* Config ID */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("Mandatory all TWT type not present\n")); + WL_ERR(("Mandatory param config ID not present\n")); bw = -EINVAL; goto exit; } - if (htod32((u32)bcm_atoi(token)) == 1) { - val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_ALL_TWT; - } - - /* Flow ID */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("flow ID not provided, using default\n")); - } else { - val32 = htod32((u32)bcm_atoi(token)); - if (val32 != -1) { - val.infodesc.flow_id = htod32((u32)bcm_atoi(token)); - } - } + val.configID = (u8)bcm_atoi(token); /* resume offset */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("resume offset not provided, using default\n")); + WL_ERR(("resume offset not provided, using default\n")); } else { twt = (u64)bcm_atoi(token); val32 = htod32((u32)(twt >> 32)); - if ((val32 != -1) && ((int32)(htod32((u32)twt)) != -1)) { + if (!(((val32 == -1) && ((int32)(htod32((u32)twt)) == -1)) || + ((val32 == 0) && ((int32)(htod32((u32)twt)) == 0)))) { val.infodesc.next_twt_h = htod32((u32)(twt >> 32)); val.infodesc.next_twt_l = htod32((u32)twt); val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_RESUME; } } - /* peer_address */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("Peer Addr not provided, using default\n")); - } else { - /* get peer mac */ - if (!bcm_ether_atoe(token, &val.peer)) { - ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__)); - bw = BCME_ERROR; - goto exit; - } - } - bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_INFO, sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32); if (bw != BCME_OK) { @@ -11805,10 +7723,10 @@ wl_android_twt_info(struct net_device *ndev, char *command, int total_len) bw = wldev_iovar_setbuf(ndev, "twt", mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL); if (bw < 0) { - ANDROID_ERROR(("twt teardown failed. ret:%d\n", bw)); + WL_ERR(("twt info failed. ret:%d\n", bw)); } exit: - return bw; + return wl_android_twt_bcmerr_to_kernel_err(bw); } @@ -11822,12 +7740,11 @@ wl_android_twt_teardown(struct net_device *ndev, char *command, int total_len) u8 res_buf[WLC_IOCTL_SMLEN] = {0}; uint8 *rem = mybuf; uint16 rem_len = sizeof(mybuf); - int32 val32; WL_DBG_MEM(("Enter. cmd:%s\n", command)); if (strlen(command) == strlen(CMD_TWT_TEARDOWN)) { - ANDROID_ERROR(("Error, twt teardown cmd missing params\n")); + WL_ERR(("Error, twt teardown cmd missing params\n")); bw = -EINVAL; goto exit; } @@ -11842,59 +7759,24 @@ wl_android_twt_teardown(struct net_device *ndev, char *command, int total_len) pos = command + sizeof(CMD_TWT_TEARDOWN); + /* Config ID */ + token = strsep((char**)&pos, " "); + if (!token) { + WL_ERR(("Mandatory param config ID not present\n")); + bw = -EINVAL; + goto exit; + } + val.configID = (u8)bcm_atoi(token); + /* negotiation_type */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("Mandatory param negotiation type not present\n")); + WL_ERR(("Mandatory param negotiation type not present\n")); bw = -EINVAL; goto exit; } val.teardesc.negotiation_type = htod32((u32)bcm_atoi(token)); - /* (all TWT) */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("Mandatory all TWT type not present\n")); - bw = -EINVAL; - goto exit; - } - val.teardesc.alltwt = htod32((u32)bcm_atoi(token)); - - /* Flow ID */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("flow ID not provided, using default\n")); - } else { - val32 = htod32((u32)bcm_atoi(token)); - if (val32 != -1) { - val.teardesc.flow_id = htod32((u32)bcm_atoi(token)); - } - } - - /* Broadcas ID */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("flow ID not provided, using default\n")); - } else { - val32 = htod32((u32)bcm_atoi(token)); - if (val32 != -1) { - val.teardesc.bid = htod32((u32)bcm_atoi(token)); - } - } - - /* peer_address */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("Peer Addr not provided, using default\n")); - } else { - /* get peer mac */ - if (!bcm_ether_atoe(token, &val.peer)) { - ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__)); - bw = BCME_ERROR; - goto exit; - } - } - bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_TEARDOWN, sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32); if (bw != BCME_OK) { @@ -11904,13 +7786,277 @@ wl_android_twt_teardown(struct net_device *ndev, char *command, int total_len) bw = wldev_iovar_setbuf(ndev, "twt", mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL); if (bw < 0) { - ANDROID_ERROR(("twt teardown failed. ret:%d\n", bw)); + WL_ERR(("twt teardown failed. ret:%d\n", bw)); } exit: - return bw; + return wl_android_twt_bcmerr_to_kernel_err(bw); +} + +/* wl twt stats result display version 2 */ +static int +wl_android_twt_stats_display_v2(wl_twt_stats_v2_t *stats, char *command, int total_len) +{ + u32 i; + wl_twt_peer_stats_v2_t *peer_stats; + int rem_len = 0, bytes_written = 0; + + rem_len = total_len; + for (i = 0; i < stats->num_stats; i++) { + peer_stats = &stats->peer_stats_list[i]; + + bytes_written = scnprintf(command, rem_len, + "%u %u %u %u %u", + peer_stats->eosp_dur_avg, peer_stats->tx_pkts_avg, peer_stats->rx_pkts_avg, + peer_stats->tx_pkt_sz_avg, peer_stats->rx_pkt_sz_avg); + CHECK_SCNPRINTF_RET_VAL(bytes_written); + command += bytes_written; + rem_len -= bytes_written; + } + + if ((total_len - rem_len) > 0) { + return (total_len - rem_len); + } else { + return BCME_ERROR; + } +} + +static int +wl_android_twt_stats(struct net_device *ndev, char *command, int total_len) +{ + wl_twt_stats_cmd_v1_t query; + wl_twt_stats_v2_t stats_v2; + int ret = BCME_OK; + char iovbuf[WLC_IOCTL_SMLEN] = {0, }; + uint8 *pxtlv = NULL; + uint8 *iovresp = NULL; + char *token, *pos; + uint16 buflen = 0, bufstart = 0; + struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); + + WL_DBG_MEM(("Enter. cmd:%s\n", command)); + + bzero(&query, sizeof(query)); + query.version = WL_TWT_STATS_CMD_VERSION_1; + query.length = sizeof(query) - OFFSETOF(wl_twt_stats_cmd_v1_t, peer); + + /* Default values, Overide Below */ + query.num_bid = 0xFF; + query.num_fid = 0xFF; + + if (!(strnicmp(command, CMD_TWT_CLR_STATS, strlen(CMD_TWT_CLR_STATS)))) { + query.flags |= WL_TWT_STATS_CMD_FLAGS_RESET; + pos = command + sizeof(CMD_TWT_CLR_STATS); + } else if (!(strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)))) { + pos = command + sizeof(CMD_TWT_GET_STATS); + } + + /* Config ID */ + token = strsep((char**)&pos, " "); + if (!token) { + WL_ERR(("Mandatory param config ID not present\n")); + ret = -EINVAL; + goto exit; + } + query.configID = (u8)bcm_atoi(token); + + iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (iovresp == NULL) { + DHD_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); + goto exit; + } + + buflen = bufstart = WLC_IOCTL_SMLEN; + pxtlv = (uint8 *)iovbuf; + ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATS, + sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + DHD_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); + goto exit; + } + + if ((ret = wldev_iovar_getbuf(ndev, "twt", iovbuf, bufstart-buflen, + iovresp, WLC_IOCTL_MEDLEN, NULL))) { + DHD_ERROR(("twt status failed with err=%d \n", ret)); + goto exit; + } + + (void)memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2)); + + if (dtoh16(stats_v2.version) == WL_TWT_STATS_VERSION_2) { + if (!(strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)))) { + DHD_ERROR(("stats query ver %d, \n", dtoh16(stats_v2.version))); + ret = wl_android_twt_stats_display_v2((wl_twt_stats_v2_t*)iovresp, + command, total_len); + } + } else { + ret = BCME_UNSUPPORTED; + DHD_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(stats_v2.version))); + goto exit; + } + +exit: + if (iovresp) { + MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN); + } + + return ret; +} + +static int +wl_android_twt_softap_enable(struct net_device *ndev, int twt_softap_enable) +{ + s32 err = 0; + struct bcm_cfg80211 *cfg = NULL; + u8 mybuf[WLC_IOCTL_SMLEN] = {0}; + u8 res_buf[WLC_IOCTL_SMLEN] = {0}; + u8 *rem = mybuf; + u16 rem_len = sizeof(mybuf); + wl_twt_resp_cfg_t val; + + if (!ndev) { + err = -EINVAL; + return err; + } + + cfg = wl_get_cfg(ndev); + if (!cfg) { + err = -EINVAL; + return err; + } + + /* Enable/disable SoftAP for TWT */ + bzero(&val, sizeof(val)); + val.version = WL_TWT_RESP_CFG_VER; + val.length = sizeof(val.version) + sizeof(val.length); + + if (twt_softap_enable == 1) { + val.twt_resp_enab = 1; + } + + err = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_RESP_CONFIG, + sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32); + if (err != BCME_OK) { + goto exit; + } + + err = wldev_iovar_setbuf(ndev, "twt", + mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL); + if (err < 0) { + WL_ERR(("twt softAP enable/disable failed. ret:%d\n", err)); + } + +exit: + return wl_android_twt_bcmerr_to_kernel_err(err); } #endif /* WL_TWT */ +static int +wl_android_get_6g_softap_freq_list(struct net_device *ndev, char *command, int total_len) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); + int err = BCME_OK; + uint16 *chan_list = NULL; + uint32 i, freq, list_count; + uint32 chspec, chaninfo; + char *input_command = NULL; + int rem_len = 0, bytes_written = 0; + + rem_len = total_len; + input_command = command; + + chan_list = MALLOCZ(cfg->osh, CHANINFO_LIST_BUF_SIZE); + if (chan_list == NULL) { + WL_ERR(("failed to allocate chanspec buffer\n")); + return -ENOMEM; + } + err = wldev_iovar_getbuf_bsscfg(ndev, "chan_info_list", NULL, + 0, chan_list, CHANINFO_LIST_BUF_SIZE, 0, NULL); + if (err == BCME_UNSUPPORTED) { + WL_INFORM(("get chan_info_list, UNSUPPORTED\n")); + goto exit; + } else if (err != BCME_OK) { + WL_ERR(("get chan_info_list err(%d)\n", err)); + goto exit; + } + + list_count = ((wl_chanspec_list_v1_t *)chan_list)->count; + for (i = 0; i < list_count; i++) { + chspec = dtoh32(((wl_chanspec_list_v1_t *)chan_list)->chspecs[i].chanspec); + + /* Check if the chanspec is 6G, PSC and VLP */ + if (CHSPEC_IS6G(chspec) && CHSPEC_IS20(chspec)) { + chaninfo = + dtoh32(((wl_chanspec_list_v1_t *)chan_list)->chspecs[i].chaninfo); + if ((chaninfo & WL_CHAN_BAND_6G_PSC) && (chaninfo & WL_CHAN_BAND_6G_VLP)) { + freq = wl_channel_to_frequency(wf_chspec_ctlchan(chspec), + CHSPEC_BAND(chspec)); + bytes_written = scnprintf(command, rem_len, "%d ", freq); + CHECK_SCNPRINTF_RET_VAL(bytes_written); + command += bytes_written; + rem_len -= bytes_written; + } + } + } + + if ((total_len - rem_len) >= 0) { + err = total_len - rem_len; + WL_INFORM_MEM(("6G SoftAP FreqList: %s \n", input_command)); + } else { + err = BCME_ERROR; + } +exit: + if (chan_list) { + MFREE(cfg->osh, chan_list, CHANINFO_LIST_BUF_SIZE); + } + return err; +} + +#ifdef WL_DUAL_STA +static int +wl_android_set_primary_inet(struct net_device *ndev, char *command, int total_len) +{ + int err = BCME_OK; + + err = wl_cfgvendor_multista_set_primary_connection(ndev->ieee80211_ptr->wiphy, + ndev_to_wdev(ndev), NULL, 0); + + return err; +} +#endif /* WL_DUAL_STA */ + +int +wl_android_set_wsec_info(struct net_device *dev, char *command) +{ + int error = BCME_OK; + uint32 wsec_info; +#ifdef DHD_PM_CONTROL_FROM_FILE + if (g_pm_control) { + WL_ERR(("Ignored Set wsec_info\n")); + return BCME_UNSUPPORTED; + } +#endif /* DHD_PM_CONTROL_FROM_FILE */ + + if (sscanf(command, "%*s %d", &wsec_info) != 1) { + WL_ERR(("Failed to get Parameter\n")); + return BCME_ERROR; + } + + if ((wsec_info != 0) && (wsec_info != 1)) { + WL_ERR(("Invalid wsec info value %d\n", wsec_info)); + return BCME_ERROR; + } + + error = wl_cfg80211_set_wsec_info(dev, &wsec_info, sizeof(wsec_info), + WL_WSEC_INFO_6G_LEGACY_SEC); + if (error) { + WL_ERR(("Failed to set wsec info %d, error = %d\n", wsec_info, error)); + } else { + WL_ERR(("Succeeded to set wsec info %d,error = %d\n", wsec_info, error)); + } + + return error; +} + int wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) { @@ -11921,7 +8067,7 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) priv_cmd.total_len = cmd_len; if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) { - ANDROID_INFO(("%s, Received regular START command\n", __FUNCTION__)); + DHD_INFO(("wl_handle_private_cmd, Received regular START command\n")); #ifdef SUPPORT_DEEP_SLEEP trigger_deep_sleep = 1; #else @@ -11937,8 +8083,8 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) } if (!g_wifi_on) { - ANDROID_ERROR(("%s: Ignore private cmd \"%s\" - iface is down\n", - __FUNCTION__, command)); + DHD_ERROR(("wl_handle_private_cmd: Ignore private cmd \"%s\" - iface is down\n", + command)); return 0; } @@ -11953,14 +8099,12 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) #endif /* BT_OVER_SDIO */ #endif /* SUPPORT_DEEP_SLEEP */ } -#ifdef WL_CFG80211 else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) { wl_cfg80211_set_passive_scan(net, command); } else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) { wl_cfg80211_set_passive_scan(net, command); } -#endif /* WL_CFG80211 */ else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) { bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len); } @@ -11991,8 +8135,10 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) } else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) { #ifdef WL_CFG80211 +#ifdef OEM_ANDROID void *dhdp = wl_cfg80211_get_dhdp(net); bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command); +#endif // OEM_ANDROID #else #ifdef PKT_FILTER_SUPPORT uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0'; @@ -12021,23 +8167,13 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) bytes_written = wl_android_set_disable_dtim_in_suspend(net, command); } #endif /* DISABLE_DTIM_IN_SUSPEND */ -#ifdef WL_CFG80211 else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { bytes_written = wl_android_set_band(net, command); } -#endif /* WL_CFG80211 */ else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { bytes_written = wl_android_get_band(net, command, priv_cmd.total_len); } #ifdef WL_CFG80211 - else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) { - bytes_written = wl_android_set_csa(net, command); - } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) { - bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len); - } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) { - bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len); - } -#endif /* WL_CFG80211 */ #ifndef CUSTOMER_SET_COUNTRY /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */ else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { @@ -12056,15 +8192,14 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) #endif /* DHD_BLOB_EXISTENCE_CHECK */ if ((rev_info_delim) && (strnicmp(rev_info_delim, CMD_COUNTRY_DELIMITER, - strlen(CMD_COUNTRY_DELIMITER)) == 0) && - (rev_info_delim + 1)) { + strlen(CMD_COUNTRY_DELIMITER)) == 0)) { revinfo = bcm_atoi(rev_info_delim + 1); } else { revinfo = 0; } if (revinfo < 0) { - ANDROID_ERROR(("%s:failed due to wrong revinfo %d\n", __FUNCTION__, revinfo)); + DHD_ERROR(("%s:failed due to wrong revinfo %d\n", __FUNCTION__, revinfo)); return BCME_BADARG; } @@ -12074,100 +8209,23 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) } #endif /* DHD_BLOB_EXISTENCE_CHECK */ -#ifdef WL_CFG80211 bytes_written = wl_cfg80211_set_country_code(net, country_code, - true, true, revinfo); -#ifdef CUSTOMER_HW4_PRIVATE_CMD -#ifdef FCC_PWR_LIMIT_2G - if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) { - ANDROID_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__)); - } else { - ANDROID_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__)); - } -#endif /* FCC_PWR_LIMIT_2G */ -#endif /* CUSTOMER_HW4_PRIVATE_CMD */ -#else - bytes_written = wldev_set_country(net, country_code, true, true, revinfo); -#endif /* WL_CFG80211 */ + true, true, revinfo); } #endif /* CUSTOMER_SET_COUNTRY */ - else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) { +#endif /* WL_CFG80211 */ + else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) { + bytes_written = wl_android_set_csa(net, command); + } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) { + bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len); + } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) { + bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len); + } else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) { bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len); } else if (strnicmp(command, CMD_ASSOC_CLIENTS, strlen(CMD_ASSOC_CLIENTS)) == 0) { bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len); } -#ifdef CUSTOMER_HW4_PRIVATE_CMD - else if (strnicmp(command, CMD_ROAM_VSIE_ENAB_SET, strlen(CMD_ROAM_VSIE_ENAB_SET)) == 0) { - bytes_written = wl_android_set_roam_vsie_enab(net, command, priv_cmd.total_len); - } else if (strnicmp(command, CMD_ROAM_VSIE_ENAB_GET, strlen(CMD_ROAM_VSIE_ENAB_GET)) == 0) { - bytes_written = wl_android_get_roam_vsie_enab(net, command, priv_cmd.total_len); - } else if (strnicmp(command, CMD_BR_VSIE_ENAB_SET, strlen(CMD_BR_VSIE_ENAB_SET)) == 0) { - bytes_written = wl_android_set_bcn_rpt_vsie_enab(net, command, priv_cmd.total_len); - } else if (strnicmp(command, CMD_BR_VSIE_ENAB_GET, strlen(CMD_BR_VSIE_ENAB_GET)) == 0) { - bytes_written = wl_android_get_bcn_rpt_vsie_enab(net, command, priv_cmd.total_len); - } -#ifdef WES_SUPPORT - else if (strnicmp(command, CMD_GETNCHOMODE, strlen(CMD_GETNCHOMODE)) == 0) { - bytes_written = wl_android_get_ncho_mode(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_SETNCHOMODE, strlen(CMD_SETNCHOMODE)) == 0) { - int mode; - sscanf(command, "%*s %d", &mode); - bytes_written = wl_android_set_ncho_mode(net, mode); - } - else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) { - bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) { - bytes_written = wl_android_okc_enable(net, command); - } - else if (wl_android_legacy_check_command(net, command)) { - bytes_written = wl_android_legacy_private_command(net, command, priv_cmd.total_len); - } - else if (wl_android_ncho_check_command(net, command)) { - bytes_written = wl_android_ncho_private_command(net, command, priv_cmd.total_len); - } -#endif /* WES_SUPPORT */ -#if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT) - else if (strnicmp(command, CMD_RESTORE_SCAN_PARAMS, strlen(CMD_RESTORE_SCAN_PARAMS)) == 0) { - bytes_written = wl_android_default_set_scan_params(net, command, - priv_cmd.total_len); - } -#endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT */ -#ifdef WLTDLS - else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) { - bytes_written = wl_android_tdls_reset(net); - } -#endif /* WLTDLS */ -#ifdef CONFIG_SILENT_ROAM - else if (strnicmp(command, CMD_SROAM_TURN_ON, strlen(CMD_SROAM_TURN_ON)) == 0) { - int mode = *(command + strlen(CMD_SROAM_TURN_ON) + 1) - '0'; - bytes_written = wl_android_sroam_turn_on(net, mode); - } - else if (strnicmp(command, CMD_SROAM_SET_INFO, strlen(CMD_SROAM_SET_INFO)) == 0) { - char *data = (command + strlen(CMD_SROAM_SET_INFO) + 1); - bytes_written = wl_android_sroam_set_info(net, data, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_SROAM_GET_INFO, strlen(CMD_SROAM_GET_INFO)) == 0) { - bytes_written = wl_android_sroam_get_info(net, command, priv_cmd.total_len); - } -#endif /* CONFIG_SILENT_ROAM */ -#ifdef CONFIG_ROAM_RSSI_LIMIT - else if (strnicmp(command, CMD_ROAM_RSSI_LMT, strlen(CMD_ROAM_RSSI_LMT)) == 0) { - bytes_written = wl_android_roam_rssi_limit(net, command, priv_cmd.total_len); - } -#endif /* CONFIG_ROAM_RSSI_LIMIT */ -#ifdef CONFIG_ROAM_MIN_DELTA - else if (strnicmp(command, CMD_ROAM_MIN_DELTA, strlen(CMD_ROAM_MIN_DELTA)) == 0) { - bytes_written = wl_android_roam_min_delta(net, command, priv_cmd.total_len); - } -#endif /* CONFIG_ROAM_MIN_DELTA */ - else if (strnicmp(command, CMD_SET_DISCONNECT_IES, strlen(CMD_SET_DISCONNECT_IES)) == 0) { - bytes_written = wl_android_set_disconnect_ies(net, command); - } -#endif /* CUSTOMER_HW4_PRIVATE_CMD */ - #ifdef PNO_SUPPORT else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { bytes_written = dhd_dev_pno_stop_for_ssid(net); @@ -12221,11 +8279,9 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) sub_command ? strlen(sub_command) : 0); } #endif /* P2P_LISTEN_OFFLOADING */ -#if !defined WL_ENABLE_P2P_IF else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) { bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); } -#endif /* WL_ENABLE_P2P_IF */ else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) { int skip = strlen(CMD_P2P_SET_PS) + 1; bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, @@ -12257,14 +8313,14 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) } #endif /* WLFBT */ #endif /* WL_CFG80211 */ -#if defined (WL_SUPPORT_AUTO_CHANNEL) +#if defined(WL_SUPPORT_AUTO_CHANNEL) else if (strnicmp(command, CMD_GET_BEST_CHANNELS, strlen(CMD_GET_BEST_CHANNELS)) == 0) { bytes_written = wl_android_get_best_channels(net, command, priv_cmd.total_len); } #endif /* WL_SUPPORT_AUTO_CHANNEL */ -#if defined (WL_SUPPORT_AUTO_CHANNEL) +#if defined(WL_SUPPORT_AUTO_CHANNEL) else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL, strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) { int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 1; @@ -12272,128 +8328,6 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) priv_cmd.total_len); } #endif /* WL_SUPPORT_AUTO_CHANNEL */ -#ifdef CUSTOMER_HW4_PRIVATE_CMD -#ifdef SUPPORT_AMPDU_MPDU_CMD - /* CMD_AMPDU_MPDU */ - else if (strnicmp(command, CMD_AMPDU_MPDU, strlen(CMD_AMPDU_MPDU)) == 0) { - int skip = strlen(CMD_AMPDU_MPDU) + 1; - bytes_written = wl_android_set_ampdu_mpdu(net, (const char*)command+skip); - } -#endif /* SUPPORT_AMPDU_MPDU_CMD */ -#if defined (SUPPORT_HIDDEN_AP) - else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA, - strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) { - int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3; - wl_android_set_max_num_sta(net, (const char*)command+skip); - } - else if (strnicmp(command, CMD_SET_HAPD_SSID, - strlen(CMD_SET_HAPD_SSID)) == 0) { - int skip = strlen(CMD_SET_HAPD_SSID) + 3; - wl_android_set_ssid(net, (const char*)command+skip); - } - else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID, - strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) { - int skip = strlen(CMD_SET_HAPD_HIDE_SSID) + 3; - wl_android_set_hide_ssid(net, (const char*)command+skip); - } -#endif /* SUPPORT_HIDDEN_AP */ -#ifdef SUPPORT_SOFTAP_SINGL_DISASSOC - else if (strnicmp(command, CMD_HAPD_STA_DISASSOC, - strlen(CMD_HAPD_STA_DISASSOC)) == 0) { - int skip = strlen(CMD_HAPD_STA_DISASSOC) + 1; - wl_android_sta_diassoc(net, (const char*)command+skip); - } -#endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */ -#ifdef SUPPORT_SET_LPC - else if (strnicmp(command, CMD_HAPD_LPC_ENABLED, - strlen(CMD_HAPD_LPC_ENABLED)) == 0) { - int skip = strlen(CMD_HAPD_LPC_ENABLED) + 3; - wl_android_set_lpc(net, (const char*)command+skip); - } -#endif /* SUPPORT_SET_LPC */ -#ifdef SUPPORT_TRIGGER_HANG_EVENT - else if (strnicmp(command, CMD_TEST_FORCE_HANG, - strlen(CMD_TEST_FORCE_HANG)) == 0) { - int skip = strlen(CMD_TEST_FORCE_HANG) + 1; - net_os_send_hang_message_reason(net, (const char*)command+skip); - } -#endif /* SUPPORT_TRIGGER_HANG_EVENT */ - else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0) - bytes_written = wl_android_ch_res_rl(net, true); - else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0) - bytes_written = wl_android_ch_res_rl(net, false); -#ifdef SUPPORT_LTECX - else if (strnicmp(command, CMD_LTECX_SET, strlen(CMD_LTECX_SET)) == 0) { - int skip = strlen(CMD_LTECX_SET) + 1; - bytes_written = wl_android_set_ltecx(net, (const char*)command+skip); - } -#endif /* SUPPORT_LTECX */ -#ifdef WL_RELMCAST - else if (strnicmp(command, CMD_SET_RMC_ENABLE, strlen(CMD_SET_RMC_ENABLE)) == 0) { - int rmc_enable = *(command + strlen(CMD_SET_RMC_ENABLE) + 1) - '0'; - bytes_written = wl_android_rmc_enable(net, rmc_enable); - } - else if (strnicmp(command, CMD_SET_RMC_TXRATE, strlen(CMD_SET_RMC_TXRATE)) == 0) { - int rmc_txrate; - sscanf(command, "%*s %10d", &rmc_txrate); - bytes_written = wldev_iovar_setint(net, "rmc_txrate", rmc_txrate * 2); - } - else if (strnicmp(command, CMD_SET_RMC_ACTPERIOD, strlen(CMD_SET_RMC_ACTPERIOD)) == 0) { - int actperiod; - sscanf(command, "%*s %10d", &actperiod); - bytes_written = wldev_iovar_setint(net, "rmc_actf_time", actperiod); - } - else if (strnicmp(command, CMD_SET_RMC_IDLEPERIOD, strlen(CMD_SET_RMC_IDLEPERIOD)) == 0) { - int acktimeout; - sscanf(command, "%*s %10d", &acktimeout); - acktimeout *= 1000; - bytes_written = wldev_iovar_setint(net, "rmc_acktmo", acktimeout); - } - else if (strnicmp(command, CMD_SET_RMC_LEADER, strlen(CMD_SET_RMC_LEADER)) == 0) { - int skip = strlen(CMD_SET_RMC_LEADER) + 1; - bytes_written = wl_android_rmc_set_leader(net, (const char*)command+skip); - } - else if (strnicmp(command, CMD_SET_RMC_EVENT, - strlen(CMD_SET_RMC_EVENT)) == 0) { - bytes_written = wl_android_set_rmc_event(net, command); - } -#endif /* WL_RELMCAST */ - else if (strnicmp(command, CMD_GET_SCSCAN, strlen(CMD_GET_SCSCAN)) == 0) { - bytes_written = wl_android_get_singlecore_scan(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_SET_SCSCAN, strlen(CMD_SET_SCSCAN)) == 0) { - bytes_written = wl_android_set_singlecore_scan(net, command); - } -#ifdef TEST_TX_POWER_CONTROL - else if (strnicmp(command, CMD_TEST_SET_TX_POWER, - strlen(CMD_TEST_SET_TX_POWER)) == 0) { - int skip = strlen(CMD_TEST_SET_TX_POWER) + 1; - wl_android_set_tx_power(net, (const char*)command+skip); - } - else if (strnicmp(command, CMD_TEST_GET_TX_POWER, - strlen(CMD_TEST_GET_TX_POWER)) == 0) { - wl_android_get_tx_power(net, command, priv_cmd.total_len); - } -#endif /* TEST_TX_POWER_CONTROL */ - else if (strnicmp(command, CMD_SARLIMIT_TX_CONTROL, - strlen(CMD_SARLIMIT_TX_CONTROL)) == 0) { - int skip = strlen(CMD_SARLIMIT_TX_CONTROL) + 1; - bytes_written = wl_android_set_sarlimit_txctrl(net, (const char*)command+skip); - } -#ifdef SUPPORT_SET_TID - else if (strnicmp(command, CMD_SET_TID, strlen(CMD_SET_TID)) == 0) { - bytes_written = wl_android_set_tid(net, command); - } - else if (strnicmp(command, CMD_GET_TID, strlen(CMD_GET_TID)) == 0) { - bytes_written = wl_android_get_tid(net, command, priv_cmd.total_len); - } -#endif /* SUPPORT_SET_TID */ -#ifdef WL_WTC - else if (strnicmp(command, CMD_WTC_CONFIG, strlen(CMD_WTC_CONFIG)) == 0) { - bytes_written = wl_android_wtc_config(net, command, priv_cmd.total_len); - } -#endif /* WL_WTC */ -#endif /* CUSTOMER_HW4_PRIVATE_CMD */ else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) { int skip = strlen(CMD_HAPD_MAC_FILTER) + 1; wl_android_set_mac_address_filter(net, command+skip); @@ -12405,45 +8339,22 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len); } #endif /* BCMFW_ROAM_ENABLE */ -#ifdef WL_CFG80211 else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0) bytes_written = wl_android_set_miracast(net, command); else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0) bytes_written = wl_android_set_ibss_beacon_ouidata(net, command, priv_cmd.total_len); -#endif /* WL_CFG80211 */ -#ifdef WLAIBSS - else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT, - strlen(CMD_SETIBSSTXFAILEVENT)) == 0) - bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len); - else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL, - strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0) - bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len, - TRUE); - else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO, - strlen(CMD_GET_IBSS_PEER_INFO)) == 0) - bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len, - FALSE); - else if (strnicmp(command, CMD_SETIBSSROUTETABLE, - strlen(CMD_SETIBSSROUTETABLE)) == 0) - bytes_written = wl_android_set_ibss_routetable(net, command); - else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0) - bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len); - else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0) - bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len); -#endif /* WLAIBSS */ else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) { int skip = strlen(CMD_KEEP_ALIVE) + 1; bytes_written = wl_keep_alive_set(net, command + skip); } -#ifdef WL_CFG80211 else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) { int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0'; bytes_written = wl_cfg80211_enable_roam_offload(net, enable); } else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) { char *name = (command + strlen(CMD_INTERFACE_CREATE) +1); - ANDROID_INFO(("Creating %s interface\n", name)); + WL_INFORM(("Creating %s interface\n", name)); if (wl_cfg80211_add_if(wl_get_cfg(net), net, WL_IF_TYPE_STA, name, NULL) == NULL) { bytes_written = -ENODEV; @@ -12454,10 +8365,9 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) } else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) { char *name = (command + strlen(CMD_INTERFACE_DELETE) +1); - ANDROID_INFO(("Deleteing %s interface\n", name)); + WL_INFORM(("Deleteing %s interface\n", name)); bytes_written = wl_cfg80211_del_if(wl_get_cfg(net), net, NULL, name); } -#endif /* WL_CFG80211 */ else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) { bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len); } @@ -12471,12 +8381,10 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len); } #endif /* P2PRESP_WFDIE_SRC */ -#ifdef WL_CFG80211 else if (strnicmp(command, CMD_DFS_AP_MOVE, strlen(CMD_DFS_AP_MOVE)) == 0) { char *data = (command + strlen(CMD_DFS_AP_MOVE) +1); bytes_written = wl_cfg80211_dfs_ap_move(net, data, command, priv_cmd.total_len); } -#endif /* WL_CFG80211 */ #ifdef WBTEXT else if (strnicmp(command, CMD_WBTEXT_ENABLE, strlen(CMD_WBTEXT_ENABLE)) == 0) { bytes_written = wl_android_wbtext(net, command, priv_cmd.total_len); @@ -12528,26 +8436,6 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) bytes_written = wl_android_set_wfds_hash(net, command, 0); } #endif /* WLWFDS */ -#ifdef BT_WIFI_HANDOVER - else if (strnicmp(command, CMD_TBOW_TEARDOWN, strlen(CMD_TBOW_TEARDOWN)) == 0) { - bytes_written = wl_tbow_teardown(net); - } -#endif /* BT_WIFI_HANDOVER */ -#ifdef CUSTOMER_HW4_PRIVATE_CMD -#ifdef FCC_PWR_LIMIT_2G - else if (strnicmp(command, CMD_GET_FCC_PWR_LIMIT_2G, - strlen(CMD_GET_FCC_PWR_LIMIT_2G)) == 0) { - bytes_written = wl_android_get_fcc_pwr_limit_2g(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_SET_FCC_PWR_LIMIT_2G, - strlen(CMD_SET_FCC_PWR_LIMIT_2G)) == 0) { - bytes_written = wl_android_set_fcc_pwr_limit_2g(net, command); - } -#endif /* FCC_PWR_LIMIT_2G */ - else if (strnicmp(command, CMD_GET_STA_INFO, strlen(CMD_GET_STA_INFO)) == 0) { - bytes_written = wl_cfg80211_get_sta_info(net, command, priv_cmd.total_len); - } -#endif /* CUSTOMER_HW4_PRIVATE_CMD */ else if (strnicmp(command, CMD_MURX_BFE_CAP, strlen(CMD_MURX_BFE_CAP)) == 0) { #ifdef WL_MURX @@ -12600,16 +8488,6 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) bytes_written = wl_android_get_rssi_per_ant(net, command, priv_cmd.total_len); } #endif /* SUPPORT_RSSI_SUM_REPORT */ -#if defined(DHD_ENABLE_BIGDATA_LOGGING) - else if (strnicmp(command, CMD_GET_BSS_INFO, strlen(CMD_GET_BSS_INFO)) == 0) { - bytes_written = wl_cfg80211_get_bss_info(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_GET_ASSOC_REJECT_INFO, strlen(CMD_GET_ASSOC_REJECT_INFO)) - == 0) { - bytes_written = wl_cfg80211_get_connect_failed_status(net, command, - priv_cmd.total_len); - } -#endif /* DHD_ENABLE_BIGDATA_LOGGING */ #if defined(SUPPORT_RANDOM_MAC_SCAN) else if (strnicmp(command, ENABLE_RANDOM_MAC, strlen(ENABLE_RANDOM_MAC)) == 0) { bytes_written = wl_cfg80211_set_random_mac(net, TRUE); @@ -12617,12 +8495,6 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) bytes_written = wl_cfg80211_set_random_mac(net, FALSE); } #endif /* SUPPORT_RANDOM_MAC_SCAN */ -#ifdef WL_NATOE - else if (strnicmp(command, CMD_NATOE, strlen(CMD_NATOE)) == 0) { - bytes_written = wl_android_process_natoe_cmd(net, command, - priv_cmd.total_len); - } -#endif /* WL_NATOE */ #ifdef CONNECTION_STATISTICS else if (strnicmp(command, CMD_GET_CONNECTION_STATS, strlen(CMD_GET_CONNECTION_STATS)) == 0) { @@ -12651,6 +8523,16 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) } } #endif /* DHD_LOG_DUMP */ +#ifdef TPUT_DEBUG_DUMP + else if (strnicmp(command, CMD_TPUT_DEBUG_MODE_ENABLE, + strlen(CMD_TPUT_DEBUG_MODE_ENABLE)) == 0) { + wl_cfgdbg_tput_debug_mode(net, true); + } + else if (strnicmp(command, CMD_TPUT_DEBUG_MODE_DISABLE, + strlen(CMD_TPUT_DEBUG_MODE_DISABLE)) == 0) { + wl_cfgdbg_tput_debug_mode(net, false); + } +#endif /* WL_TPUT_DEBUG_DUMP */ #ifdef DHD_STATUS_LOGGING else if (strnicmp(command, CMD_DUMP_STATUS_LOG, strlen(CMD_DUMP_STATUS_LOG)) == 0) { dhd_statlog_dump_scr(wl_cfg80211_get_dhdp(net)); @@ -12698,23 +8580,6 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) else if (strnicmp(command, CMD_GET_SNR, strlen(CMD_GET_SNR)) == 0) { bytes_written = wl_android_get_snr(net, command, priv_cmd.total_len); } -#ifdef WLADPS_PRIVATE_CMD - else if (strnicmp(command, CMD_SET_ADPS, strlen(CMD_SET_ADPS)) == 0) { - int skip = strlen(CMD_SET_ADPS) + 1; - bytes_written = wl_android_set_adps_mode(net, (const char*)command+skip); - } - else if (strnicmp(command, CMD_GET_ADPS, strlen(CMD_GET_ADPS)) == 0) { - bytes_written = wl_android_get_adps_mode(net, command, priv_cmd.total_len); - } -#ifdef WLADPS_ENERGY_GAIN - else if (strnicmp(command, CMD_GET_GAIN_ADPS, strlen(CMD_GET_GAIN_ADPS)) == 0) { - bytes_written = wl_android_get_gain_adps(net, command, priv_cmd.total_len); - } - else if (strnicmp(command, CMD_RESET_GAIN_ADPS, strlen(CMD_RESET_GAIN_ADPS)) == 0) { - bytes_written = wl_android_reset_gain_adps(net, command); - } -#endif /* WLADPS_ENERGY_GAIN */ -#endif /* WLADPS_PRIVATE_CMD */ #ifdef DHD_PKT_LOGGING else if (strnicmp(command, CMD_PKTLOG_FILTER_ENABLE, strlen(CMD_PKTLOG_FILTER_ENABLE)) == 0) { @@ -12768,12 +8633,10 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) bytes_written = wl_android_pktlog_dbg_dump(net, command, priv_cmd.total_len); } #endif /* DHD_PKT_LOGGING */ -#ifdef WL_CFG80211 else if (strnicmp(command, CMD_DEBUG_VERBOSE, strlen(CMD_DEBUG_VERBOSE)) == 0) { int verbose_level = *(command + strlen(CMD_DEBUG_VERBOSE) + 1) - '0'; bytes_written = wl_cfg80211_set_dbg_verbose(net, verbose_level); } -#endif /* WL_CFG80211 */ #ifdef DHD_EVENT_LOG_FILTER else if (strnicmp(command, CMD_EWP_FILTER, strlen(CMD_EWP_FILTER)) == 0) { @@ -12810,7 +8673,7 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) } #endif /* WL_GET_CU */ #ifdef RTT_GEOFENCE_INTERVAL -#if defined (RTT_SUPPORT) && defined(WL_NAN) +#if defined(RTT_SUPPORT) && defined(WL_NAN) else if (strnicmp(command, CMD_GEOFENCE_INTERVAL, strlen(CMD_GEOFENCE_INTERVAL)) == 0) { (void)wl_android_set_rtt_geofence_interval(net, command); @@ -12829,6 +8692,16 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) wl_android_get_softap_elna_bypass(net, command, priv_cmd.total_len); } #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */ +#ifdef CUSTOM_SOFTAP_SET_ANT + else if (strnicmp(command, CMD_SET_HOTSPOT_ANTENNA_MODE, + strlen(CMD_SET_HOTSPOT_ANTENNA_MODE)) == 0) { + bytes_written = wl_android_set_softap_antenna(net, command); + } + else if (strnicmp(command, CMD_GET_HOTSPOT_ANTENNA_MODE, + strlen(CMD_GET_HOTSPOT_ANTENNA_MODE)) == 0) { + bytes_written = wl_android_get_softap_antenna(net, command, priv_cmd.total_len); + } +#endif /* CUSTOM_SOFTAP_SET_ANT */ #ifdef WL_NAN else if (strnicmp(command, CMD_GET_NAN_STATUS, strlen(CMD_GET_NAN_STATUS)) == 0) { @@ -12860,6 +8733,13 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) bytes_written = wl_android_get_latency_crt_data(net, command, priv_cmd.total_len); } #endif /* SUPPORT_LATENCY_CRITICAL_DATA */ +#if defined(WL_LATENCY_CONFIG) + else if (strnicmp(command, CMD_SET_LOW_LATENCY, + strlen(CMD_SET_LOW_LATENCY)) == 0) { + int skip = strlen(CMD_SET_LOW_LATENCY) + 1; + bytes_written = wl_android_set_low_latency(net, command + skip); + } +#endif /* WL_LATENCY_CONFIG */ #ifdef WL_TWT else if (strnicmp(command, CMD_TWT_SETUP, strlen(CMD_TWT_SETUP)) == 0) { bytes_written = wl_android_twt_setup(net, command, priv_cmd.total_len); @@ -12876,17 +8756,66 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) else if (strnicmp(command, CMD_TWT_CAPABILITY, strlen(CMD_TWT_CAPABILITY)) == 0) { bytes_written = wl_android_twt_cap(net, command, priv_cmd.total_len); } -#endif /* WL_TWT */ -#ifdef WL_P2P_6G - else if (strnicmp(command, CMD_ENABLE_6G_P2P, strlen(CMD_ENABLE_6G_P2P)) == 0) { - int enable = *(command + strlen(CMD_ENABLE_6G_P2P) + 1) - '0'; - bytes_written = wl_android_enable_p2p_6g(net, enable); + else if ((strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)) == 0) || + (strnicmp(command, CMD_TWT_CLR_STATS, strlen(CMD_TWT_CLR_STATS)) == 0)) { + bytes_written = wl_android_twt_stats(net, command, priv_cmd.total_len); } -#endif /* WL_P2P_6G */ + else if (strnicmp(command, CMD_TWT_SOFTAP_ENABLE, strlen(CMD_TWT_SOFTAP_ENABLE)) == 0) { + int twt_softap_enable = *(command + strlen(CMD_TWT_SOFTAP_ENABLE) + 1) - '0'; + bytes_written = wl_android_twt_softap_enable(net, twt_softap_enable); + } +#endif /* WL_TWT */ + else if (strnicmp(command, CMD_GET_6G_SOFTAP_FREQ_LIST, + strlen(CMD_GET_6G_SOFTAP_FREQ_LIST)) == 0) { + bytes_written = wl_android_get_6g_softap_freq_list(net, command, + priv_cmd.total_len); + } +#ifdef WL_UWB_COEX + else if (strnicmp(command, CMD_SET_UWB_COEX_ENABLE, + strlen(CMD_SET_UWB_COEX_ENABLE)) == 0) { + int skip = strlen(CMD_SET_UWB_COEX_ENABLE) + 1; + bytes_written = wl_android_uwbcx_set_enable(net, (const char *)(command + skip)); + } + else if (strnicmp(command, CMD_GET_UWB_COEX_ENABLE, + strlen(CMD_GET_UWB_COEX_ENABLE)) == 0) { + bytes_written = wl_android_uwbcx_get_enable(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SET_UWB_COEX_PREPARE_TIME, + strlen(CMD_SET_UWB_COEX_PREPARE_TIME)) == 0) { + int skip = strlen(CMD_SET_UWB_COEX_PREPARE_TIME) + 1; + bytes_written = wl_android_uwbcx_set_prepare_time(net, + (const char *)(command + skip)); + } + else if (strnicmp(command, CMD_GET_UWB_COEX_PREPARE_TIME, + strlen(CMD_GET_UWB_COEX_PREPARE_TIME)) == 0) { + bytes_written = wl_android_uwbcx_get_prepare_time(net, + command, priv_cmd.total_len); + } +#endif /* WL_UWB_COEX */ +#ifdef WL_DUAL_STA + else if (strnicmp(command, CMD_SET_PRIMARY_INET, + strlen(CMD_SET_PRIMARY_INET)) == 0) { + bytes_written = wl_android_set_primary_inet(net, + command, priv_cmd.total_len); + } +#endif /* WL_DUAL_STA */ + else if (strnicmp(command, CMD_SETWSECINFO, strlen(CMD_SETWSECINFO)) == 0) { + bytes_written = wl_android_set_wsec_info(net, command); + } +#if defined(LIMIT_AP_BW) + else if (strnicmp(command, CMD_SET_SOFTAP_BW, + strlen(CMD_SET_SOFTAP_BW)) == 0) { + bytes_written = wl_android_set_softap_bw(net, command); + } else if (strnicmp(command, CMD_GET_SOFTAP_BW, + strlen(CMD_GET_SOFTAP_BW)) == 0) { + bytes_written = wl_android_get_softap_bw(net, command, + priv_cmd.total_len); + } +#endif /* LIMIT_AP_BW */ else if (wl_android_ext_priv_cmd(net, command, priv_cmd.total_len, &bytes_written) == 0) { } else { - ANDROID_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); + DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL"); } @@ -12908,7 +8837,7 @@ int wl_android_init(void) #ifdef ENABLE_INSMOD_NO_POWER_OFF dhd_download_fw_on_driverload = TRUE; -#elif defined(ENABLE_INSMOD_NO_FW_LOAD) || defined(BUS_POWER_RESTORE) +#elif defined(ENABLE_INSMOD_NO_FW_LOAD) dhd_download_fw_on_driverload = FALSE; #endif /* ENABLE_INSMOD_NO_FW_LOAD */ if (!iface_name[0]) { @@ -12916,17 +8845,10 @@ int wl_android_init(void) bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ); } -#ifdef CUSTOMER_HW4_DEBUG - /* No Kernel Panic from ASSERT() on customer platform. */ - g_assert_type = 1; -#endif /* CUSTOMER_HW4_DEBUG */ - #ifdef WL_GENL wl_genl_init(); #endif -#ifdef WL_RELMCAST wl_netlink_init(); -#endif /* WL_RELMCAST */ return ret; } @@ -12939,9 +8861,7 @@ int wl_android_exit(void) #ifdef WL_GENL wl_genl_deinit(); #endif /* WL_GENL */ -#ifdef WL_RELMCAST wl_netlink_deinit(); -#endif /* WL_RELMCAST */ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(cur, q, &miracast_resume_list, list) { @@ -12958,11 +8878,12 @@ void wl_android_post_init(void) #ifdef ENABLE_4335BT_WAR bcm_bt_unlock(lock_cookie_wifi); - ANDROID_ERROR(("%s: btlock released\n", __FUNCTION__)); + DHD_ERROR(("wl_android_post_init: btlock released\n")); #endif /* ENABLE_4335BT_WAR */ if (!dhd_download_fw_on_driverload) { g_wifi_on = FALSE; + DHD_ERROR(("%s: %d\n", __FUNCTION__, g_wifi_on)); } } @@ -12972,7 +8893,7 @@ static int wl_genl_init(void) { int ret; - ANDROID_INFO(("GEN Netlink Init\n\n")); + WL_DBG(("GEN Netlink Init\n\n")); #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) /* register new family */ @@ -12983,17 +8904,19 @@ static int wl_genl_init(void) /* register functions (commands) of the new family */ ret = genl_register_ops(&wl_genl_family, &wl_genl_ops); if (ret != 0) { - ANDROID_ERROR(("register ops failed: %i\n", ret)); + WL_ERR(("register ops failed: %i\n", ret)); genl_unregister_family(&wl_genl_family); goto failure; } ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast); -#else +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops, wl_genl_mcast); +#else + ret = genl_register_family(&wl_genl_family); #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */ if (ret != 0) { - ANDROID_ERROR(("register mc_group failed: %i\n", ret)); + WL_ERR(("register mc_group failed: %i\n", ret)); #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) genl_unregister_ops(&wl_genl_family, &wl_genl_ops); #endif @@ -13004,7 +8927,7 @@ static int wl_genl_init(void) return 0; failure: - ANDROID_ERROR(("Registering Netlink failed!!\n")); + WL_ERR(("Registering Netlink failed!!\n")); return -1; } @@ -13014,10 +8937,10 @@ static int wl_genl_deinit(void) #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0) - ANDROID_ERROR(("Unregister wl_genl_ops failed\n")); + WL_ERR(("Unregister wl_genl_ops failed\n")); #endif if (genl_unregister_family(&wl_genl_family) < 0) - ANDROID_ERROR(("Unregister wl_genl_ops failed\n")); + WL_ERR(("Unregister wl_genl_ops failed\n")); return 0; } @@ -13040,14 +8963,9 @@ s32 wl_event_to_bcm_event(u16 event_type) event = BCM_E_DEV_LOST; break; /* Above events are supported from BCM Supp ver 47 Onwards */ -#ifdef BT_WIFI_HANDOVER - case WLC_E_BT_WIFI_HANDOVER_REQ: - event = BCM_E_DEV_BT_WIFI_HO_REQ; - break; -#endif /* BT_WIFI_HANDOVER */ default: - ANDROID_ERROR(("Event not supported\n")); + WL_ERR(("Event not supported\n")); } return event; @@ -13074,7 +8992,7 @@ wl_genl_send_msg( u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); - ANDROID_INFO(("Enter \n")); + WL_DBG(("Enter \n")); /* Decide between STRING event and Data event */ if (event_type == 0) @@ -13099,14 +9017,14 @@ wl_genl_send_msg( * make sure it is null terminated */ if (subhdr || subhdr_len) { - ANDROID_ERROR(("No sub hdr support for the ATTR STRING type \n")); + WL_ERR(("No sub hdr support for the ATTR STRING type \n")); ret = -EINVAL; goto out; } ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf); if (ret != 0) { - ANDROID_ERROR(("nla_put_string failed\n")); + WL_ERR(("nla_put_string failed\n")); goto out; } } else { @@ -13116,7 +9034,7 @@ wl_genl_send_msg( p = ptr = (u8 *)MALLOCZ(cfg->osh, tot_len); if (!ptr) { ret = -ENOMEM; - ANDROID_ERROR(("ENOMEM!!\n")); + WL_ERR(("ENOMEM!!\n")); goto out; } @@ -13139,7 +9057,7 @@ wl_genl_send_msg( ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p); if (ret != 0) { - ANDROID_ERROR(("nla_put_string failed\n")); + WL_ERR(("nla_put_string failed\n")); goto out; } } @@ -13155,10 +9073,10 @@ wl_genl_send_msg( #else if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) < 0) #endif - ANDROID_ERROR(("genlmsg_multicast for attr(%d) failed. Error:%d \n", + WL_ERR(("genlmsg_multicast for attr(%d) failed. Error:%d \n", attr_type, err)); else - ANDROID_INFO(("Multicast msg sent successfully. attr_type:%d len:%d \n", + WL_DBG(("Multicast msg sent successfully. attr_type:%d len:%d \n", attr_type, tot_len)); } else { NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */ @@ -13168,7 +9086,7 @@ wl_genl_send_msg( /* send the message back */ if (genlmsg_unicast(&init_net, skb, pid) < 0) - ANDROID_ERROR(("genlmsg_unicast failed\n")); + WL_ERR(("genlmsg_unicast failed\n")); } out: @@ -13189,7 +9107,7 @@ wl_genl_handle_msg( struct nlattr *na; u8 *data = NULL; - ANDROID_INFO(("Enter \n")); + WL_DBG(("Enter \n")); if (info == NULL) { return -EINVAL; @@ -13197,22 +9115,21 @@ wl_genl_handle_msg( na = info->attrs[BCM_GENL_ATTR_MSG]; if (!na) { - ANDROID_ERROR(("nlattribute NULL\n")); + WL_ERR(("nlattribute NULL\n")); return -EINVAL; } data = (char *)nla_data(na); if (!data) { - ANDROID_ERROR(("Invalid data\n")); + WL_ERR(("Invalid data\n")); return -EINVAL; } else { /* Handle the data */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || \ - defined(WL_COMPAT_WIRELESS) - ANDROID_INFO(("%s: Data received from pid (%d) \n", __func__, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || defined(WL_COMPAT_WIRELESS) + WL_DBG(("%s: Data received from pid (%d) \n", __func__, info->snd_pid)); #else - ANDROID_INFO(("%s: Data received from pid (%d) \n", __func__, + WL_DBG(("%s: Data received from pid (%d) \n", __func__, info->snd_portid)); #endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */ } @@ -13229,217 +9146,10 @@ int wl_fatal_error(void * wl, int rc) void wl_android_set_wifi_on_flag(bool enable) { - ANDROID_ERROR(("%s: %d\n", __FUNCTION__, enable)); + DHD_ERROR(("%s: %d\n", __FUNCTION__, enable)); g_wifi_on = enable; } -#ifdef WL_STATIC_IF -#include -struct net_device * -wl_cfg80211_register_static_if(struct bcm_cfg80211 *cfg, u16 iftype, char *ifname, - int static_ifidx) -{ -#if defined(CUSTOM_MULTI_MAC) || defined(WL_EXT_IAPSTA) - dhd_pub_t *dhd = cfg->pub; -#endif - struct net_device *ndev; - struct wireless_dev *wdev = NULL; - int ifidx = WL_STATIC_IFIDX; /* Register ndev with a reserved ifidx */ - u8 mac_addr[ETH_ALEN]; - struct net_device *primary_ndev; -#ifdef DHD_USE_RANDMAC - struct ether_addr ea_addr; -#endif /* DHD_USE_RANDMAC */ -#ifdef CUSTOM_MULTI_MAC - char hw_ether[62]; -#endif - - ANDROID_INFO(("[STATIC_IF] Enter (%s) iftype:%d\n", ifname, iftype)); - - if (!cfg) { - ANDROID_ERROR(("cfg null\n")); - return NULL; - } - primary_ndev = bcmcfg_to_prmry_ndev(cfg); - - ifidx += static_ifidx; -#ifdef DHD_USE_RANDMAC - wl_cfg80211_generate_mac_addr(&ea_addr); - (void)memcpy_s(mac_addr, ETH_ALEN, ea_addr.octet, ETH_ALEN); -#else -#if defined(CUSTOM_MULTI_MAC) - if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, static_ifidx+1)) { - (void)memcpy_s(mac_addr, ETH_ALEN, hw_ether, ETH_ALEN); - } else -#endif - { - /* Use primary mac with locally admin bit set */ - (void)memcpy_s(mac_addr, ETH_ALEN, primary_ndev->dev_addr, ETH_ALEN); - mac_addr[0] |= 0x02; -#ifdef WL_EXT_IAPSTA - wl_ext_iapsta_get_vif_macaddr(dhd, static_ifidx+1, mac_addr); -#endif - } -#endif /* DHD_USE_RANDMAC */ - - ndev = wl_cfg80211_allocate_if(cfg, ifidx, ifname, mac_addr, - WL_BSSIDX_MAX, NULL); - if (unlikely(!ndev)) { - ANDROID_ERROR(("Failed to allocate static_if\n")); - goto fail; - } - wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev)); - if (unlikely(!wdev)) { - ANDROID_ERROR(("Failed to allocate wdev for static_if\n")); - goto fail; - } - - wdev->wiphy = cfg->wdev->wiphy; - wdev->iftype = iftype; - - ndev->ieee80211_ptr = wdev; - SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); - wdev->netdev = ndev; - - if (wl_cfg80211_register_if(cfg, ifidx, - ndev, TRUE) != BCME_OK) { - ANDROID_ERROR(("ndev registration failed!\n")); - goto fail; - } - - cfg->static_ndev[static_ifidx] = ndev; - cfg->static_ndev_state[static_ifidx] = NDEV_STATE_OS_IF_CREATED; - wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, WL_BSSIDX_MAX, - ifname, NDEV_STATE_OS_IF_CREATED); - ANDROID_INFO(("Static I/F (%s) Registered\n", ndev->name)); - return ndev; - -fail: - wl_cfg80211_remove_if(cfg, ifidx, ndev, false); - return NULL; -} - -void -wl_cfg80211_unregister_static_if(struct bcm_cfg80211 *cfg) -{ - int i; - - ANDROID_INFO(("[STATIC_IF] Enter\n")); - if (!cfg) { - ANDROID_ERROR(("invalid input\n")); - return; - } - - /* wdev free will happen from notifier context */ - /* free_netdev(cfg->static_ndev); - */ - for (i=0; istatic_ndev[i]) - unregister_netdev(cfg->static_ndev[i]); - } -} - -s32 -wl_cfg80211_static_if_open(struct net_device *net) -{ - struct wireless_dev *wdev = NULL; - struct bcm_cfg80211 *cfg = wl_get_cfg(net); - struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg); - u16 iftype = net->ieee80211_ptr ? net->ieee80211_ptr->iftype : 0; - u16 wl_iftype, wl_mode; -#ifdef CUSTOM_MULTI_MAC - dhd_pub_t *dhd = dhd_get_pub(net); - char hw_ether[62]; -#endif - int static_ifidx; - - ANDROID_INFO(("[STATIC_IF] dev_open ndev %p and wdev %p\n", net, net->ieee80211_ptr)); - static_ifidx = wl_cfg80211_static_ifidx(cfg, net); - ASSERT(static_ifidx >= 0); - - if (cfg80211_to_wl_iftype(iftype, &wl_iftype, &wl_mode) < 0) { - return BCME_ERROR; - } - if (cfg->static_ndev_state[static_ifidx] != NDEV_STATE_FW_IF_CREATED) { -#ifdef CUSTOM_MULTI_MAC - if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, static_ifidx+1)) - dev_addr_set(net, hw_ether); -#endif - wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name, net->dev_addr); - if (!wdev) { - ANDROID_ERROR(("[STATIC_IF] wdev is NULL, can't proceed\n")); - return BCME_ERROR; - } - } else { - ANDROID_INFO(("Fw IF for static netdev already created\n")); - } - - return BCME_OK; -} - -s32 -wl_cfg80211_static_if_close(struct net_device *net) -{ - int ret = BCME_OK; - struct bcm_cfg80211 *cfg = wl_get_cfg(net); - struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg); - int static_ifidx; - - static_ifidx = wl_cfg80211_static_ifidx(cfg, net); - - if (cfg->static_ndev_state[static_ifidx] == NDEV_STATE_FW_IF_CREATED) { - if (mutex_is_locked(&cfg->if_sync) == TRUE) { - ret = _wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name); - } else { - ret = wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name); - } - - if (unlikely(ret)) { - ANDROID_ERROR(("Del iface failed for static_if %d\n", ret)); - } - } - - return ret; -} -struct net_device * -wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg, - wl_if_event_info *event, u8 *addr, s32 iface_type, int static_ifidx) -{ - struct net_device *new_ndev = NULL; - struct wireless_dev *wdev = NULL; - - ANDROID_INFO(("Updating static iface after Fw IF create \n")); - new_ndev = cfg->static_ndev[static_ifidx]; - - if (new_ndev) { - wdev = new_ndev->ieee80211_ptr; - ASSERT(wdev); - wdev->iftype = iface_type; - dev_addr_set(new_ndev, addr); - } - - cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_CREATED; - wl_cfg80211_update_iflist_info(cfg, new_ndev, event->ifidx, addr, event->bssidx, - event->name, NDEV_STATE_FW_IF_CREATED); - return new_ndev; -} -s32 -wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 *cfg, struct net_device *ndev) -{ - int static_ifidx; - int ifidx = WL_STATIC_IFIDX; - - static_ifidx = wl_cfg80211_static_ifidx(cfg, ndev); - ifidx += static_ifidx; - cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_DELETED; - wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, - WL_BSSIDX_MAX, NULL, NDEV_STATE_FW_IF_DELETED); - wl_cfg80211_clear_per_bss_ies(cfg, ndev->ieee80211_ptr); - wl_dealloc_netinfo_by_wdev(cfg, ndev->ieee80211_ptr); - return BCME_OK; -} -#endif /* WL_STATIC_IF */ - #ifdef WBTEXT static int wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp, @@ -13451,7 +9161,7 @@ wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp, ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); if (unlikely(!ioctl_buf)) { - ANDROID_ERROR(("%s: failed to allocate memory\n", __func__)); + WL_ERR(("%s: failed to allocate memory\n", __func__)); err = -ENOMEM; goto exit; } @@ -13460,13 +9170,13 @@ wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp, /* Getting roam profile from fw */ if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp), ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) { - ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err)); + WL_ERR(("Getting roam_profile failed with err=%d \n", err)); goto exit; } memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp)); /* roam_prof version get */ if (rp->v1.ver > WL_ROAM_PROF_VER_3) { - ANDROID_ERROR(("bad version (=%d) in return data\n", rp->v1.ver)); + WL_ERR(("bad version (=%d) in return data\n", rp->v1.ver)); err = BCME_VERSION; goto exit; } @@ -13496,13 +9206,13 @@ wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp, } break; default: - ANDROID_ERROR(("bad version = %d \n", rp->v1.ver)); + WL_ERR(("bad version = %d \n", rp->v1.ver)); err = BCME_VERSION; goto exit; } - ANDROID_INFO(("roam prof ver %u size %u\n", *roam_prof_ver, *roam_prof_size)); + WL_DBG(("roam prof ver %u size %u\n", *roam_prof_ver, *roam_prof_size)); if ((rp->v1.len % *roam_prof_size) != 0) { - ANDROID_ERROR(("bad length (=%d) in return data\n", rp->v1.len)); + WL_ERR(("bad length (=%d) in return data\n", rp->v1.len)); err = BCME_BADLEN; } exit: @@ -13524,17 +9234,17 @@ wl_cfg80211_wbtext_set_default(struct net_device *ndev) int wnmmask = 0; struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); - ANDROID_INFO(("set wbtext to default\n")); + WL_DBG(("set wbtext to default\n")); commandp = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN); if (unlikely(!commandp)) { - ANDROID_ERROR(("%s: failed to allocate memory\n", __func__)); + WL_ERR(("%s: failed to allocate memory\n", __func__)); ret = -ENOMEM; goto exit; } ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN); if (unlikely(!ioctl_buf)) { - ANDROID_ERROR(("%s: failed to allocate memory\n", __func__)); + WL_ERR(("%s: failed to allocate memory\n", __func__)); ret = -ENOMEM; goto exit; } @@ -13544,7 +9254,7 @@ wl_cfg80211_wbtext_set_default(struct net_device *ndev) /* Getting roam profile from fw */ if ((ret = wldev_iovar_getbuf(ndev, "roam_prof", &rp, sizeof(rp), ioctl_buf, WLC_IOCTL_SMLEN, NULL))) { - ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", ret)); + WL_ERR(("Getting roam_profile failed with err=%d \n", ret)); goto exit; } memcpy_s(&rp, sizeof(rp), ioctl_buf, sizeof(rp)); @@ -13584,14 +9294,14 @@ wl_cfg80211_wbtext_set_default(struct net_device *ndev) } break; default: - ANDROID_ERROR(("No Support for roam prof ver = %d \n", rp.v1.ver)); + WL_ERR(("No Support for roam prof ver = %d \n", rp.v1.ver)); ret = -EINVAL; goto exit; } /* set roam profile */ ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN); if (ret != BCME_OK) { - ANDROID_ERROR(("%s: Failed to set roam_prof %s error = %d\n", + WL_ERR(("%s: Failed to set roam_prof %s error = %d\n", __FUNCTION__, data, ret)); goto exit; } @@ -13607,7 +9317,7 @@ wl_cfg80211_wbtext_set_default(struct net_device *ndev) data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1); ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN); if (ret != BCME_OK) { - ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n", + WL_ERR(("%s: Failed to set weight config %s error = %d\n", __FUNCTION__, data, ret)); goto exit; } @@ -13618,7 +9328,7 @@ wl_cfg80211_wbtext_set_default(struct net_device *ndev) data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1); ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN); if (ret != BCME_OK) { - ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n", + WL_ERR(("%s: Failed to set weight config %s error = %d\n", __FUNCTION__, data, ret)); goto exit; } @@ -13630,7 +9340,7 @@ wl_cfg80211_wbtext_set_default(struct net_device *ndev) data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1); ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN); if (ret != BCME_OK) { - ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n", + WL_ERR(("%s: Failed to set weight config %s error = %d\n", __FUNCTION__, data, ret)); goto exit; } @@ -13641,26 +9351,26 @@ wl_cfg80211_wbtext_set_default(struct net_device *ndev) data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1); ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN); if (ret != BCME_OK) { - ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n", + WL_ERR(("%s: Failed to set weight config %s error = %d\n", __FUNCTION__, data, ret)); goto exit; } ret = wldev_iovar_getint(ndev, "wnm", &wnmmask); if (ret != BCME_OK) { - ANDROID_ERROR(("%s: Failed to get wnmmask error = %d\n", __func__, ret)); + WL_ERR(("%s: Failed to get wnmmask error = %d\n", __func__, ret)); goto exit; } /* set ESTM DL weight. */ if (wnmmask & WL_WNM_ESTM) { - ANDROID_ERROR(("Setting ESTM wt\n")); + WL_ERR(("Setting ESTM wt\n")); memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN); snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s", CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A); data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1); ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN); if (ret != BCME_OK) { - ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n", + WL_ERR(("%s: Failed to set weight config %s error = %d\n", __FUNCTION__, data, ret)); goto exit; } @@ -13671,7 +9381,7 @@ wl_cfg80211_wbtext_set_default(struct net_device *ndev) data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1); ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN); if (ret != BCME_OK) { - ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n", + WL_ERR(("%s: Failed to set weight config %s error = %d\n", __FUNCTION__, data, ret)); goto exit; } @@ -13684,7 +9394,7 @@ wl_cfg80211_wbtext_set_default(struct net_device *ndev) data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1); ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN); if (ret != BCME_OK) { - ANDROID_ERROR(("%s: Failed to set RSSI table %s error = %d\n", + WL_ERR(("%s: Failed to set RSSI table %s error = %d\n", __FUNCTION__, data, ret)); goto exit; } @@ -13695,7 +9405,7 @@ wl_cfg80211_wbtext_set_default(struct net_device *ndev) data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1); ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN); if (ret != BCME_OK) { - ANDROID_ERROR(("%s: Failed to set RSSI table %s error = %d\n", + WL_ERR(("%s: Failed to set RSSI table %s error = %d\n", __FUNCTION__, data, ret)); goto exit; } @@ -13707,7 +9417,7 @@ wl_cfg80211_wbtext_set_default(struct net_device *ndev) data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1); ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN); if (ret != BCME_OK) { - ANDROID_ERROR(("%s: Failed to set CU table %s error = %d\n", + WL_ERR(("%s: Failed to set CU table %s error = %d\n", __FUNCTION__, data, ret)); goto exit; } @@ -13718,7 +9428,7 @@ wl_cfg80211_wbtext_set_default(struct net_device *ndev) data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1); ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN); if (ret != BCME_OK) { - ANDROID_ERROR(("%s: Failed to set CU table %s error = %d\n", + WL_ERR(("%s: Failed to set CU table %s error = %d\n", __FUNCTION__, data, ret)); goto exit; } @@ -13749,13 +9459,13 @@ wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, in data[len] = '\0'; ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); if (unlikely(!ioctl_buf)) { - ANDROID_ERROR(("%s: failed to allocate memory\n", __func__)); + WL_ERR(("%s: failed to allocate memory\n", __func__)); err = -ENOMEM; goto exit; } rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp)); if (unlikely(!rp)) { - ANDROID_ERROR(("%s: failed to allocate memory\n", __func__)); + WL_ERR(("%s: failed to allocate memory\n", __func__)); err = -ENOMEM; goto exit; } @@ -13772,13 +9482,13 @@ wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, in /* Getting roam profile from fw */ if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp), ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) { - ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err)); + WL_ERR(("Getting roam_profile failed with err=%d \n", err)); goto exit; } memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp)); /* roam_prof version get */ if (rp->v1.ver > WL_ROAM_PROF_VER_3) { - ANDROID_ERROR(("bad version (=%d) in return data\n", rp->v1.ver)); + WL_ERR(("bad version (=%d) in return data\n", rp->v1.ver)); err = -EINVAL; goto exit; } @@ -13808,12 +9518,12 @@ wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, in } break; default: - ANDROID_ERROR(("bad version = %d \n", rp->v1.ver)); + WL_ERR(("bad version = %d \n", rp->v1.ver)); goto exit; } - ANDROID_INFO(("roam prof ver %u size %u\n", roam_prof_ver, roam_prof_size)); + WL_DBG(("roam prof ver %u size %u\n", roam_prof_ver, roam_prof_size)); if ((rp->v1.len % roam_prof_size) != 0) { - ANDROID_ERROR(("bad length (=%d) in return data\n", rp->v1.len)); + WL_ERR(("bad length (=%d) in return data\n", rp->v1.len)); err = -EINVAL; goto exit; } @@ -13875,7 +9585,7 @@ wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, in } else { /* Do not set roam_prof from upper layer if fw doesn't have 2 rows */ if (prof_cnt != 2) { - ANDROID_ERROR(("FW must have 2 rows to fill roam_prof\n")); + WL_ERR(("FW must have 2 rows to fill roam_prof\n")); err = -EINVAL; goto exit; } @@ -13884,14 +9594,14 @@ wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, in for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) { roam_trigger = simple_strtol(data, &data, 10); if (roam_trigger >= 0) { - ANDROID_ERROR(("roam trigger[%d] value must be negative\n", i)); + WL_ERR(("roam trigger[%d] value must be negative\n", i)); err = -EINVAL; goto exit; } data++; rssi_lower = simple_strtol(data, &data, 10); if (rssi_lower >= 0) { - ANDROID_ERROR(("rssi lower[%d] value must be negative\n", i)); + WL_ERR(("rssi lower[%d] value must be negative\n", i)); err = -EINVAL; goto exit; } @@ -13931,7 +9641,7 @@ wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, in data++; } if (i != 1) { - ANDROID_ERROR(("Only two roam_prof rows supported.\n")); + WL_ERR(("Only two roam_prof rows supported.\n")); err = -EINVAL; goto exit; } @@ -13939,7 +9649,7 @@ wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, in if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp, sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync)) < 0) { - ANDROID_ERROR(("seting roam_profile failed with err %d\n", err)); + WL_ERR(("seting roam_profile failed with err %d\n", err)); } } exit: @@ -13964,15 +9674,17 @@ int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data, bwcfg = (wnm_bss_select_weight_cfg_t *)MALLOCZ(cfg->osh, sizeof(*bwcfg)); if (unlikely(!bwcfg)) { - ANDROID_ERROR(("%s: failed to allocate memory\n", __func__)); + WL_ERR(("%s: failed to allocate memory\n", __func__)); err = -ENOMEM; goto exit; } - bwcfg->version = WNM_BSSLOAD_MONITOR_VERSION; + bwcfg->version = WNM_BSSLOAD_MONITOR_VERSION_1; bwcfg->type = 0; bwcfg->weight = 0; - argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band, weight); + argc = sscanf(data, + "%"SIZE_CONST_STRING(BUFSZ)"s %"SIZE_CONST_STRING(BUFSZ)"s " + "%"SIZE_CONST_STRING(BUFSZ)"s", rssi, band, weight); if (!strcasecmp(rssi, "rssi")) bwcfg->type = WNM_BSS_SELECT_TYPE_RSSI; @@ -13982,25 +9694,25 @@ int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data, bwcfg->type = WNM_BSS_SELECT_TYPE_ESTM_DL; else { /* Usage DRIVER WBTEXT_WEIGHT_CONFIG */ - ANDROID_ERROR(("%s: Command usage error\n", __func__)); + WL_ERR(("%s: Command usage error\n", __func__)); goto exit; } if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &bwcfg->band)) { - ANDROID_ERROR(("%s: Command usage error\n", __func__)); + WL_ERR(("%s: Command usage error\n", __func__)); goto exit; } if (argc == 2) { /* If there is no data after band, getting wnm_bss_select_weight from fw */ if (bwcfg->band == WLC_BAND_ALL) { - ANDROID_ERROR(("band option \"all\" is for set only, not get\n")); + WL_ERR(("band option \"all\" is for set only, not get\n")); goto exit; } if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_weight", bwcfg, sizeof(*bwcfg), ioctl_buf, sizeof(ioctl_buf), NULL))) { - ANDROID_ERROR(("Getting wnm_bss_select_weight failed with err=%d \n", err)); + WL_ERR(("Getting wnm_bss_select_weight failed with err=%d \n", err)); goto exit; } memcpy(bwcfg, ioctl_buf, sizeof(*bwcfg)); @@ -14014,14 +9726,14 @@ int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data, /* if weight is non integer returns command usage error */ bwcfg->weight = simple_strtol(weight, &endptr, 0); if (*endptr != '\0') { - ANDROID_ERROR(("%s: Command usage error", __func__)); + WL_ERR(("%s: Command usage error", __func__)); goto exit; } /* setting weight for iovar wnm_bss_select_weight to fw */ if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_weight", bwcfg, sizeof(*bwcfg), ioctl_buf, sizeof(ioctl_buf), NULL))) { - ANDROID_ERROR(("setting wnm_bss_select_weight failed with err=%d\n", err)); + WL_ERR(("setting wnm_bss_select_weight failed with err=%d\n", err)); } } exit: @@ -14050,17 +9762,17 @@ int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data, btcfg = (wnm_bss_select_factor_cfg_t *)MALLOCZ(cfg->osh, (sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT)); if (unlikely(!btcfg)) { - ANDROID_ERROR(("%s: failed to allocate memory\n", __func__)); + WL_ERR(("%s: failed to allocate memory\n", __func__)); err = -ENOMEM; goto exit; } - btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION; + btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION_1; btcfg->band = WLC_BAND_AUTO; btcfg->type = 0; btcfg->count = 0; - sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band); + sscanf(data, "%"SIZE_CONST_STRING(BUFSZ)"s %"SIZE_CONST_STRING(BUFSZ)"s", rssi, band); if (!strcasecmp(rssi, "rssi")) { btcfg->type = WNM_BSS_SELECT_TYPE_RSSI; @@ -14069,12 +9781,12 @@ int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data, btcfg->type = WNM_BSS_SELECT_TYPE_CU; } else { - ANDROID_ERROR(("%s: Command usage error\n", __func__)); + WL_ERR(("%s: Command usage error\n", __func__)); goto exit; } if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &btcfg->band)) { - ANDROID_ERROR(("%s: Command usage, Wrong band\n", __func__)); + WL_ERR(("%s: Command usage, Wrong band\n", __func__)); goto exit; } @@ -14083,7 +9795,7 @@ int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data, if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_table", btcfg, sizeof(*btcfg), ioctl_buf, sizeof(ioctl_buf), NULL))) { - ANDROID_ERROR(("Getting wnm_bss_select_table failed with err=%d \n", err)); + WL_ERR(("Getting wnm_bss_select_table failed with err=%d \n", err)); goto exit; } memcpy(btcfg, ioctl_buf, sizeof(*btcfg)); @@ -14123,14 +9835,14 @@ int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data, data++; parsed_len = data - start_addr; } else { - ANDROID_ERROR(("%s:Command usage:less no of args\n", __func__)); + WL_ERR(("%s:Command usage:less no of args\n", __func__)); goto exit; } } btcfg_len = sizeof(*btcfg) + ((btcfg->count) * sizeof(*btcfg)); if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_table", btcfg, btcfg_len, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync)) < 0) { - ANDROID_ERROR(("seting wnm_bss_select_table failed with err %d\n", err)); + WL_ERR(("seting wnm_bss_select_table failed with err %d\n", err)); goto exit; } } @@ -14154,19 +9866,20 @@ wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *comma rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp)); if (unlikely(!rp)) { - ANDROID_ERROR(("%s: failed to allocate memory\n", __func__)); + WL_ERR(("%s: failed to allocate memory\n", __func__)); err = -ENOMEM; goto exit; } - argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", band, delta); + argc = sscanf(data, "%"SIZE_CONST_STRING(BUFSZ)"s %"SIZE_CONST_STRING(BUFSZ)"s", + band, delta); if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &band_val)) { - ANDROID_ERROR(("%s: Missing band\n", __func__)); + WL_ERR(("%s: Missing band\n", __func__)); goto exit; } if ((err = wlc_wbtext_get_roam_prof(ndev, rp, band_val, &roam_prof_ver, &roam_prof_size))) { - ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err)); + WL_ERR(("Getting roam_profile failed with err=%d \n", err)); err = -EINVAL; goto exit; } @@ -14174,7 +9887,7 @@ wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *comma /* if delta is non integer returns command usage error */ val = simple_strtol(delta, &endptr, 0); if (*endptr != '\0') { - ANDROID_ERROR(("%s: Command usage error", __func__)); + WL_ERR(("%s: Command usage error", __func__)); goto exit; } for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) { @@ -14224,7 +9937,7 @@ wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *comma if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp, sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync)) < 0) { - ANDROID_ERROR(("seting roam_profile failed with err %d\n", err)); + WL_ERR(("seting roam_profile failed with err %d\n", err)); } exit : if (rp) { @@ -14233,3 +9946,318 @@ exit : return err; } #endif /* WBTEXT */ + +#ifdef WL_UWB_COEX +static int +wl_android_uwbcx_set_enable(struct net_device *dev, const char *command) +{ + int enable; + int start_ch; + int end_ch; + + sscanf(command, "%d %d %d", &enable, &start_ch, &end_ch); + + return wl_cfg_uwb_coex_enable(dev, enable, start_ch, end_ch); +} + +static int +wl_android_uwbcx_get_enable(struct net_device *dev, char *command, int tot_len) +{ + int i; + int bytes_written = 0; + + int ret = BCME_OK; + uint8 *resp_buf = NULL; + + bool enable = FALSE; + uint16 start_ch = 0; + uint16 end_ch = 0; + bool is_bit_set = FALSE; + + bcm_iov_batch_subcmd_t *sub_cmd_ret; + uwbcx_coex_bitmap_v2_t *coex_bitmap_cfg; + uwbcx_coex_bitmap_t *coex_bitmap; + + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + + resp_buf = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN); + if (unlikely(!resp_buf)) { + WL_ERR(("%s - Failed to alloc mem\n", __FUNCTION__)); + ret = BCME_NOMEM; + goto exit; + } + + ret = wl_cfg_uwb_coex_execute_ioctl(dev, cfg, FALSE, + WL_UWBCX_CMD_COEX_BITMAP, NULL, 0, resp_buf, WLC_IOCTL_SMLEN); + if (!ret) { + sub_cmd_ret = (bcm_iov_batch_subcmd_t *)(resp_buf + + OFFSETOF(bcm_iov_batch_buf_t, cmds[0])); + coex_bitmap_cfg = (uwbcx_coex_bitmap_v2_t *)(sub_cmd_ret->data); + coex_bitmap = (uwbcx_coex_bitmap_t *)(&coex_bitmap_cfg->coex_bitmap); + + if (coex_bitmap_cfg->version != UWBCX_COEX_BITMAP_VERSION_V2) { + WL_ERR(("%s - Failed due to UWB coex bitmap ver mismatch\n", __FUNCTION__)); + ret = BCME_VERSION; + goto exit; + } + + for (i = 0; i < UWB_COEX_CH_MAP_NUM; i++) { + is_bit_set = FALSE; + if (i < 16u) { + is_bit_set = coex_bitmap->low_bitmap & (1 << i); + } else if (i >= 16u && i < 32u) { + is_bit_set = coex_bitmap->mid_low_bitmap & (1 << (i - 16u)); + } else if (i >= 32u && i < 48u) { + is_bit_set = coex_bitmap->mid_high_bitmap & (1 << (i - 32u)); + } else if (i >= 48u) { + is_bit_set = coex_bitmap->high_bitmap & (1 << (i - 48u)); + } + + if (is_bit_set) { + if (!start_ch) { + start_ch = wl_cfg_uwb_coex_get_ch_val(i); + } + end_ch = wl_cfg_uwb_coex_get_ch_val(i); + } + } + + enable = (start_ch > 0 && end_ch > 0) ? TRUE : FALSE; + + WL_ERR(("UWB Coex State: %s Ch.[%d/%d]\n", + enable ? "Enable" : "Disable", start_ch, end_ch)); + bytes_written = snprintf(command, tot_len, "%s %d %d %d", + CMD_GET_UWB_COEX_ENABLE, enable, start_ch, end_ch); + } + else { + WL_ERR(("%s - Failed to get uwbcx enable\n", __FUNCTION__)); + bytes_written = ret; + } +exit: + if (resp_buf) { + MFREE(cfg->osh, resp_buf, WLC_IOCTL_SMLEN); + } + + return bytes_written; +} + +static int +wl_android_uwbcx_set_prepare_time(struct net_device *dev, const char *command) +{ + int ret = BCME_OK; + + int param; + uint8 adv_req_timer; + uint8 *resp_buf = NULL; + + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + + resp_buf = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN); + if (unlikely(!resp_buf)) { + WL_ERR(("%s - Failed to alloc mem\n", __FUNCTION__)); + ret = BCME_NOMEM; + goto exit; + } + + sscanf(command, "%d", ¶m); + if (param < 0 || param > 255) { + ret = BCME_RANGE; + goto exit; + } + adv_req_timer = (uint8)param; + + ret = wl_cfg_uwb_coex_execute_ioctl(dev, cfg, TRUE, + WL_UWBCX_CMD_ADV_REQ_TIMER, &adv_req_timer, sizeof(adv_req_timer), + resp_buf, WLC_IOCTL_SMLEN); + if (!ret) { + WL_ERR(("Set UWB Coex prepare time: %d\n", adv_req_timer)); + } + else { + WL_ERR(("%s - Failed to set UWB Coex prepare time %d\n", + __FUNCTION__, adv_req_timer)); + } + +exit: + if (resp_buf) { + MFREE(cfg->osh, resp_buf, WLC_IOCTL_SMLEN); + } + + return ret; +} + +static int +wl_android_uwbcx_get_prepare_time(struct net_device *dev, char *command, int tot_len) +{ + int ret = BCME_OK; + int bytes_written = 0; + + uint8 adv_req_timer = 0; + + uint8 *resp_buf = NULL; + bcm_iov_batch_subcmd_t *sub_cmd_ret; + + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + + resp_buf = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN); + if (unlikely(!resp_buf)) { + WL_ERR(("%s - Failed to alloc mem\n", __FUNCTION__)); + ret = BCME_NOMEM; + goto exit; + } + + ret = wl_cfg_uwb_coex_execute_ioctl(dev, cfg, FALSE, + WL_UWBCX_CMD_ADV_REQ_TIMER, NULL, 0, + resp_buf, WLC_IOCTL_SMLEN); + if (!ret) { + sub_cmd_ret = (bcm_iov_batch_subcmd_t *)(resp_buf + + OFFSETOF(bcm_iov_batch_buf_t, cmds[0])); + adv_req_timer = *(uint8 *)sub_cmd_ret->data; + + WL_ERR(("UWB Coex prepare time: %d\n", adv_req_timer)); + bytes_written = snprintf(command, tot_len, "%s %d", + CMD_GET_UWB_COEX_PREPARE_TIME, adv_req_timer); + } + else { + WL_ERR(("%s - Failed to get UWB Coex prepare time (%d)\n", + __FUNCTION__, ret)); + bytes_written = ret; + } + +exit: + if (resp_buf) { + MFREE(cfg->osh, resp_buf, WLC_IOCTL_SMLEN); + } + + return bytes_written; +} +#endif /* WL_UWB_COEX */ + +#if defined(CUSTOM_CONTROL_HE_6G_FEATURES) +int +wl_android_set_he_6g_band(struct net_device *dev, bool enable) +{ + s32 err = BCME_OK; + s32 bssidx = 0; + struct bcm_cfg80211 *cfg = NULL; + + if (!dev) { + err = BCME_NOTFOUND; + return err; + } + + cfg = wl_get_cfg(dev); + if (!cfg) { + err = BCME_NOTFOUND; + return err; + } + + if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { + WL_ERR(("find bss index from wdev failed\n")); + err = BCME_NOTFOUND; + return err; + } +#ifdef DHD_PM_CONTROL_FROM_FILE + if (g_pm_control) { + enable = TRUE; + } +#endif /* DHD_PM_CONTROL_FROM_FILE */ + + WL_ERR(("%s: Set he mode 6G band to %s\n", __FUNCTION__, enable ? "Enable" : "Disable")); + /* Enable/disable for 6G */ + err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_HE_FEATURES_6G, enable); + if (err != BCME_OK) { + WL_ERR(("%s: failed to set he mode 6G band - err(%d)\n", + __FUNCTION__, err)); + } + + return err; +} +#endif /* CUSTOM_CONTROL_HE_6G_FEATURES */ + +#if defined(LIMIT_AP_BW) +static int +wl_android_set_softap_bw(struct net_device *ndev, char *command) +{ + struct bcm_cfg80211 *cfg = NULL; + uint32 bw; + char *token, *pos; + int err = BCME_OK; + + if (!ndev || (!(cfg = wl_get_cfg(ndev)))) { + err = BCME_NOTFOUND; + return err; + } + pos = command; + + /* drop command */ + token = bcmstrtok(&pos, " ", NULL); + + /* get band */ + token = bcmstrtok(&pos, " ", NULL); + if (!token) { + WL_ERR((CMD_SET_SOFTAP_BW ": band is not specified\n")); + return -EINVAL; + } + if (strncmp(token, "6g", strlen("6g"))) { + WL_ERR((CMD_SET_SOFTAP_BW " support 6G only\n")); + return -EINVAL; + } + + /* get bandwidth */ + token = bcmstrtok(&pos, " ", NULL); + if (!token) { + WL_ERR((CMD_SET_SOFTAP_BW ": bandwidth is not specified\n")); + return -EINVAL; + } + bw = (uint32)bcm_atoi(token); + err = wl_cfg80211_set_softap_bw(cfg, WL_CHANSPEC_BAND_6G, bw); + if (err != BCME_OK) { + return -EINVAL; + } + + WL_INFORM(("SOFTAP BANDWITH LIMIT: %d\n", bw)); + return BCME_OK; +} + +static int +wl_android_get_softap_bw(struct net_device *ndev, char *command, int total_len) +{ + struct bcm_cfg80211 *cfg = NULL; + int err = BCME_OK; + char *token, *pos; + uint32 bw = 0; + int rem_len = 0, bytes_written = 0; + + if (!ndev || (!(cfg = wl_get_cfg(ndev)))) { + err = BCME_NOTFOUND; + goto exit; + return err; + } + + pos = command; + + /* drop command */ + token = bcmstrtok(&pos, " ", NULL); + + /* get band */ + token = bcmstrtok(&pos, " ", NULL); + if (!token) { + WL_ERR((CMD_GET_SOFTAP_BW ": band is not specified\n")); + err = -EINVAL; + goto exit; + } + if (strncmp(token, "6g", strlen("6g"))) { + WL_ERR((CMD_GET_SOFTAP_BW " support 6G only\n")); + err = -EINVAL; + goto exit; + } + + bw = wl_cfg80211_get_ap_bw_limit_bit(cfg, WL_CHANSPEC_BAND_6G); + bytes_written = scnprintf(command, rem_len, "%s = %d ", + CMD_GET_SOFTAP_BW, bw); + CHECK_SCNPRINTF_RET_VAL(bytes_written); + +exit: + WL_INFORM_MEM(("%s ret:%d bw:%d\n", CMD_GET_SOFTAP_BW, err, bw)); + return bytes_written; +} +#endif /* SUPPORT_AP_INIT_BWCONF */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h old mode 100755 new mode 100644 index cdd34b9164cc..d9b61ba02fcc --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Android related functions * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -31,11 +31,11 @@ #include #include #ifdef WL_EXT_IAPSTA +#include +#endif /* WL_IAPSTA */ #ifdef WL_ESCAN #include #endif /* WL_ESCAN */ -#include -#endif /* WL_IAPSTA */ #if defined(WL_EXT_IAPSTA) || defined(USE_IW) || defined(WL_ESCAN) || \ (defined(WL_EXT_GENL) && defined(SENDPROB)) #ifndef WL_EVENT @@ -43,11 +43,12 @@ #endif #include #endif +#include /* If any feature uses the Generic Netlink Interface, put it here to enable WL_GENL * automatically */ -#if defined(WL_SDO) || defined(BT_WIFI_HANDOVER) +#if defined(WL_SDO) #define WL_GENL #endif @@ -55,6 +56,11 @@ #include #endif +#if !defined(WL_MBO_IOV_VERSION) +/* MBO IOV API version */ +#define WL_MBO_IOV_VERSION WL_MBO_IOV_VERSION_1_1 +#endif + typedef struct _android_wifi_priv_cmd { char *buf; int used_len; @@ -82,6 +88,9 @@ typedef struct _compat_android_wifi_priv_cmd { #define ANDROID_SCAN_LEVEL (1 << 3) #define ANDROID_DBG_LEVEL (1 << 4) #define ANDROID_TPUT_LEVEL (1 << 8) +#define ANDROID_AMPDU_LEVEL (1 << 9) +#define ANDROID_TVPM_LEVEL (1 << 10) +#define ANDROID_BTC_LEVEL (1 << 11) #define ANDROID_MSG_LEVEL (1 << 0) #define WL_MSG(name, arg1, args...) \ @@ -170,9 +179,6 @@ enum { BCM_E_SVC_FOUND, BCM_E_DEV_FOUND, BCM_E_DEV_LOST, -#ifdef BT_WIFI_HANDOVER - BCM_E_DEV_BT_WIFI_HO_REQ, -#endif BCM_E_MAX }; @@ -249,4 +255,16 @@ extern int wl_android_bcnrecv_event(struct net_device *ndev, #define WLC_ACS_BAND_INVALID 0xffffu #endif /* WL_SUPPORT_AUTO_CHANNEL */ #define WL_PRIV_CMD_LEN 64 +#define CHECK_SCNPRINTF_RET_VAL(ret) \ + { \ + if (ret < 0) { \ + WL_ERR(("scnprintf failed %d\n", ret)); \ + return BCME_ERROR; \ + } \ + } + +#if defined(CUSTOM_CONTROL_HE_6G_FEATURES) +extern int wl_android_set_he_6g_band(struct net_device *dev, bool enable); +#endif /* CUSTOM_CONTROL_HE_6G_FEATURES */ +extern int wl_android_rcroam_turn_on(struct net_device *dev, int rcroam_enab); #endif /* _wl_android_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c old mode 100755 new mode 100644 index 4b884dfc5427..9b0d4b4c279a --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ + #include #include #include @@ -32,6 +32,8 @@ #include #endif /* WL_ESCAN */ +uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL; + #define AEXT_ERROR(name, arg1, args...) \ do { \ if (android_msg_level & ANDROID_ERROR_LEVEL) { \ @@ -80,6 +82,9 @@ #define CMD_ROAM_TRIGGER "ROAM_TRIGGER" #define CMD_PM "PM" #define CMD_MONITOR "MONITOR" +#ifdef BTC_WAR +#define CMD_BTC_WAR "BTC_WAR" +#endif /* BTC_WAR */ #define CMD_SET_SUSPEND_BCN_LI_DTIM "SET_SUSPEND_BCN_LI_DTIM" #define CMD_WLMSGLEVEL "WLMSGLEVEL" #ifdef WL_EXT_IAPSTA @@ -180,6 +185,7 @@ const auth_name_map_t auth_name_map[] = { {WL_AUTH_OPEN_SYSTEM, 0x20|WPA2_AUTH_PSK_SHA256|WPA2_AUTH_PSK, "wpa3/psk/sha256"}, {WL_AUTH_SAE_KEY, 0x20|WPA2_AUTH_PSK_SHA256|WPA2_AUTH_PSK, "wpa3sae/psk/sha256"}, {WL_AUTH_OPEN_SYSTEM, WPA3_AUTH_OWE, "owe"}, + {WL_AUTH_OPEN_SYSTEM, BRCM_AUTH_DPT, "owe"}, }; typedef struct wsec_name_map_t { @@ -317,9 +323,9 @@ wl_ext_chspec_to_legacy(chanspec_t chspec) } chanspec_t -wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec) +wl_ext_chspec_host_to_driver(struct dhd_pub *dhd, chanspec_t chanspec) { - if (ioctl_ver == 1) { + if (dhd->conf->ioctl_ver == 1) { chanspec = wl_ext_chspec_to_legacy(chanspec); if (chanspec == INVCHANSPEC) { return chanspec; @@ -331,7 +337,7 @@ wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec) } static void -wl_ext_ch_to_chanspec(int ioctl_ver, int ch, +wl_ext_ch_to_chanspec(struct dhd_pub *dhd, int ch, struct wl_join_params *join_params, size_t *join_params_size) { chanspec_t chanspec = 0; @@ -354,7 +360,7 @@ wl_ext_ch_to_chanspec(int ioctl_ver, int ch, join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; join_params->params.chanspec_list[0] |= chanspec; join_params->params.chanspec_list[0] = - wl_ext_chspec_host_to_driver(ioctl_ver, + wl_ext_chspec_host_to_driver(dhd, join_params->params.chanspec_list[0]); join_params->params.chanspec_num = @@ -399,10 +405,10 @@ wl_ext_chspec_from_legacy(chanspec_t legacy_chspec) } chanspec_t -wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec) +wl_ext_chspec_driver_to_host(struct dhd_pub *dhd, chanspec_t chanspec) { chanspec = dtohchanspec(chanspec); - if (ioctl_ver == 1) { + if (dhd->conf->ioctl_ver == 1) { chanspec = wl_ext_chspec_from_legacy(chanspec); } @@ -413,7 +419,7 @@ wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec) chanspec_band_t wl_ext_wlcband_to_chanspec_band(int band) { - chanspec_band_t chanspec_band = WLC_BAND_INVALID; + chanspec_band_t chanspec_band = INVCHANSPEC; switch (band) { #ifdef WL_6G_BAND @@ -428,6 +434,7 @@ wl_ext_wlcband_to_chanspec_band(int band) chanspec_band = WL_CHANSPEC_BAND_2G; break; default: + AEXT_ERROR("wlan", "Invalid Frequency Band\n"); break; } return chanspec_band; @@ -549,28 +556,6 @@ wl_ext_wait_event_complete(struct dhd_pub *dhd, int ifidx) } } -int -wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver) -{ - int ret = 0; - s32 val = 0; - - val = 1; - ret = wl_ext_ioctl(dev, WLC_GET_VERSION, &val, sizeof(val), 0); - if (ret) { - return ret; - } - val = dtoh32(val); - if (val != WLC_IOCTL_VERSION && val != 1) { - AEXT_ERROR(dev->name, "Version mismatch, please upgrade. Got %d, expected %d or 1\n", - val, WLC_IOCTL_VERSION); - return BCME_VERSION; - } - *ioctl_ver = val; - - return ret; -} - void wl_ext_bss_iovar_war(struct net_device *ndev, s32 *val) { @@ -611,6 +596,7 @@ int wl_ext_set_chanspec(struct net_device *dev, struct wl_chan_info *chan_info, chanspec_t *ret_chspec) { + struct dhd_pub *dhd = dhd_get_pub(dev); s32 _chan = chan_info->chan; chanspec_t chspec = 0; chanspec_t fw_chspec = 0; @@ -623,7 +609,6 @@ wl_ext_set_chanspec(struct net_device *dev, struct wl_chan_info *chan_info, u32 bw_cap; } param = {0, 0}; chanspec_band_t chanspec_band = 0; - int ioctl_ver; if ((chan_info->band != WLC_BAND_2G) && (chan_info->band != WLC_BAND_5G) && (chan_info->band != WLC_BAND_6G)) { @@ -632,11 +617,11 @@ wl_ext_set_chanspec(struct net_device *dev, struct wl_chan_info *chan_info, } param.band = chan_info->band; - err = wl_ext_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), + err = wldev_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), iovar_buf, WLC_IOCTL_SMLEN, NULL); if (err) { if (err != BCME_UNSUPPORTED) { - AEXT_ERROR(dev->name, "bw_cap failed, %d\n", err); + AEXT_TRACE(dev->name, "bw_cap failed, %d\n", err); return err; } else { err = wl_ext_iovar_getint(dev, "mimo_bw_cap", &bw_cap); @@ -656,8 +641,7 @@ set_channel: chanspec_band = wl_ext_wlcband_to_chanspec_band(chan_info->band); chspec = wf_create_chspec_from_primary(chan_info->chan, bw, chanspec_band); if (wf_chspec_valid(chspec)) { - wl_ext_get_ioctl_ver(dev, &ioctl_ver); - fw_chspec = wl_ext_chspec_host_to_driver(ioctl_ver, chspec); + fw_chspec = wl_ext_chspec_host_to_driver(dhd, chspec); if (fw_chspec != INVCHANSPEC) { if ((err = wl_ext_iovar_setint(dev, "chanspec", fw_chspec)) == BCME_BADCHAN) { if (bw == WL_CHANSPEC_BW_80) @@ -667,8 +651,11 @@ set_channel: } else if (err) { AEXT_ERROR(dev->name, "failed to set chanspec error %d\n", err); } else - WL_MSG(dev->name, "channel %s-%d(0x%x)\n", - CHSPEC2BANDSTR(chspec), chan_info->chan, chspec); + WL_MSG(dev->name, "channel %s-%d(0x%x %sMHz)\n", + CHSPEC2BANDSTR(chspec), chan_info->chan, chspec, + CHSPEC_IS20(chspec)?"20": + CHSPEC_IS40(chspec)?"40": + CHSPEC_IS80(chspec)?"80":"160"); } else { AEXT_ERROR(dev->name, "failed to convert host chanspec to fw chanspec\n"); err = BCME_ERROR; @@ -694,44 +681,59 @@ change_bw: static int wl_ext_channel(struct net_device *dev, char* command, int total_len) { + struct dhd_pub *dhd = dhd_get_pub(dev); struct wl_chan_info chan_info; - int ret; - char band[16]=""; - int channel = 0; - channel_info_t ci; - int bytes_written = 0; - chanspec_t fw_chspec; + char chan[16]=""; + int ret, bytes_written = 0; + chanspec_t chanspec; + u32 fw_chanspec = 0; + + /* get: dhd_priv channel + * set: dhd_priv channel [6|36|2g6|5g36|6g5] + */ AEXT_TRACE(dev->name, "cmd %s", command); - sscanf(command, "%*s %d %s", &channel, band); - if (strnicmp(band, "band=auto", strlen("band=auto")) == 0) { - chan_info.band = WLC_BAND_AUTO; + sscanf(command, "%*s %s", chan); + memset(&chan_info, 0, sizeof(struct wl_chan_info)); + if (strnicmp(chan, "2g", strlen("2g")) == 0) { + chan_info.band = WLC_BAND_2G; + chan_info.chan = (int)simple_strtol(chan+2, NULL, 10); + } + else if (strnicmp(chan, "5g", strlen("5g")) == 0) { + chan_info.band = WLC_BAND_5G; + chan_info.chan = (int)simple_strtol(chan+2, NULL, 10); } #ifdef WL_6G_BAND - else if (strnicmp(band, "band=6g", strlen("band=6g")) == 0) { + else if (strnicmp(chan, "6g", strlen("6g")) == 0) { chan_info.band = WLC_BAND_6G; + chan_info.chan = (int)simple_strtol(chan+2, NULL, 10); } #endif /* WL_6G_BAND */ - else if (strnicmp(band, "band=5g", strlen("band=5g")) == 0) { - chan_info.band = WLC_BAND_5G; - } - else if (strnicmp(band, "band=2g", strlen("band=2g")) == 0) { - chan_info.band = WLC_BAND_2G; + else if (strlen(chan)) { + chan_info.chan = (int)simple_strtol(chan, NULL, 10); + if (chan_info.chan <= CH_MAX_2G_CHANNEL) + chan_info.band = WLC_BAND_2G; + else + chan_info.band = WLC_BAND_5G; } - if (channel > 0) { - chan_info.chan = channel; - ret = wl_ext_set_chanspec(dev, &chan_info, &fw_chspec); + if (chan_info.chan > 0) { + ret = wl_ext_set_chanspec(dev, &chan_info, &chanspec); } else { - if (!(ret = wl_ext_ioctl(dev, WLC_GET_CHANNEL, &ci, - sizeof(channel_info_t), FALSE))) { - AEXT_TRACE(dev->name, "hw_channel %d\n", ci.hw_channel); - AEXT_TRACE(dev->name, "target_channel %d\n", ci.target_channel); - AEXT_TRACE(dev->name, "scan_channel %d\n", ci.scan_channel); - bytes_written = snprintf(command, sizeof(channel_info_t)+2, - "channel %d", ci.hw_channel); - AEXT_TRACE(dev->name, "command result is %s\n", command); + ret = wl_ext_iovar_getint(dev, "chanspec", (s32 *)&fw_chanspec); + if (ret == BCME_OK) { + chanspec = fw_chanspec; + chanspec = wl_ext_chspec_driver_to_host(dhd, chanspec); + chan_info.band = CHSPEC2WLC_BAND(chanspec); + chan_info.chan = wf_chspec_ctlchan(chanspec); + if (chan_info.band == WLC_BAND_6G) { + bytes_written = snprintf(command, total_len, + "channel 6g%d", chan_info.chan); + } else { + bytes_written = snprintf(command, total_len, + "channel %d", chan_info.chan); + } ret = bytes_written; } } @@ -744,28 +746,47 @@ wl_ext_channels(struct net_device *dev, char* command, int total_len) { int ret, i; int bytes_written = -1; - u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; - wl_uint32_list_t *list; + wl_uint32_list_t *list = NULL; + chanspec_t chspec; + u32 channel; AEXT_TRACE(dev->name, "cmd %s", command); - memset(valid_chan_list, 0, sizeof(valid_chan_list)); - list = (wl_uint32_list_t *)(void *) valid_chan_list; - list->count = htod32(WL_NUMCHANNELS); - ret = wl_ext_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list, - sizeof(valid_chan_list), 0); - if (ret<0) { + list = kzalloc(sizeof(u32)*(MAX_CTRL_CHANSPECS + 1), GFP_KERNEL); + if (list == NULL) { + AEXT_ERROR(dev->name, "kzalloc failed\n"); + ret = -ENOMEM; + goto exit; + } + + ret = wl_construct_ctl_chanspec_list(dev, list, FALSE); + if (ret < 0) { AEXT_ERROR(dev->name, "get channels failed with %d\n", ret); + goto exit; } else { - bytes_written = snprintf(command, total_len, "channels"); - for (i = 0; i < dtoh32(list->count); i++) { - bytes_written += snprintf(command+bytes_written, total_len, " %d", - dtoh32(list->element[i])); + bytes_written = 0; + for (i = 0; i < list->count; i++) { + chspec = list->element[i]; + channel = wf_chspec_ctlchan(chspec); +#ifdef WL_6G_BAND + if (CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) && + (channel <= CH_MAX_6G_CHANNEL)) { + bytes_written += snprintf(command+bytes_written, total_len, "6g%d ", + channel); + } else +#endif + { + bytes_written += snprintf(command+bytes_written, total_len, "%d ", + channel); + } } AEXT_TRACE(dev->name, "command result is %s\n", command); ret = bytes_written; } +exit: + if (list) + kfree(list); return ret; } @@ -863,6 +884,30 @@ wl_ext_monitor(struct net_device *dev, char *command, int total_len) return ret; } +#ifdef BTC_WAR +extern int btc_war; +static int +wl_ext_btc_war(struct net_device *dev, char *command, int total_len) +{ + int user_btc_war = 0; + bool enable = FALSE; + + sscanf(command, "%*s %d", &user_btc_war); + + AEXT_TRACE(dev->name, "btc_war=%d, user_btc_war=%d\n", + btc_war, user_btc_war); + + if (btc_war >= 0) { + btc_war = user_btc_war; + if (btc_war > 0) + enable = TRUE; + wl_ext_btc_config(dev, enable); + } + + return 0; +} +#endif /* BTC_WAR */ + s32 wl_ext_connect(struct net_device *dev, struct wl_conn_info *conn_info) { @@ -873,11 +918,8 @@ wl_ext_connect(struct net_device *dev, struct wl_conn_info *conn_info) s32 err = 0; u32 chan_cnt = 0; s8 *iovar_buf = NULL; - int ioctl_ver = 0; char sec[64]; - wl_ext_get_ioctl_ver(dev, &ioctl_ver); - if (dhd->conf->chip == BCM43362_CHIP_ID) goto set_ssid; @@ -933,7 +975,7 @@ wl_ext_connect(struct net_device *dev, struct wl_conn_info *conn_info) ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; ext_join_params->assoc.chanspec_list[0] |= chspec; ext_join_params->assoc.chanspec_list[0] = - wl_ext_chspec_host_to_driver(ioctl_ver, + wl_ext_chspec_host_to_driver(dhd, ext_join_params->assoc.chanspec_list[0]); } ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num); @@ -970,7 +1012,7 @@ set_ssid: else memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); - wl_ext_ch_to_chanspec(ioctl_ver, conn_info->channel, &join_params, &join_params_size); + wl_ext_ch_to_chanspec(dhd, conn_info->channel, &join_params, &join_params_size); AEXT_TRACE(dev->name, "join_param_size %zu\n", join_params_size); if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { @@ -1087,16 +1129,39 @@ wl_ext_dfs_chan(struct wl_chan_info *chan_info) return FALSE; } +bool +wl_ext_passive_chan(struct net_device *dev, u32 chanspec) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); + struct wl_chan_info chan_info; + s32 ret = BCME_OK; + + chan_info.band = CHSPEC2WLC_BAND(chanspec); + chan_info.chan = wf_chspec_ctlchan(chanspec); + + chanspec = wl_ext_chspec_host_to_driver(dhd, chanspec); + ret = wldev_iovar_getint(dev, "per_chan_info", &chanspec); + if (!ret) { + if (chanspec & WL_CHAN_PASSIVE) + return TRUE; + } else { + if (chan_info.band == WLC_BAND_5G && chan_info.chan >= 52 && chan_info.chan <= 144) + return TRUE; + } + + return FALSE; +} + uint16 wl_ext_get_default_chan(struct net_device *dev, uint16 *chan_2g, uint16 *chan_5g, bool nodfs) { - struct dhd_pub *dhd = dhd_get_pub(dev); struct wl_chan_info chan_info; uint16 chan_tmp = 0, chan = 0; wl_uint32_list_t *list; u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; s32 ret = BCME_OK; + u32 chanspec; int i; *chan_2g = 0; @@ -1109,15 +1174,17 @@ wl_ext_get_default_chan(struct net_device *dev, if (ret == 0) { for (i=0; icount); i++) { chan_tmp = dtoh32(list->element[i]); - if (!dhd_conf_match_channel(dhd, chan_tmp)) - continue; if (chan_tmp <= 13 && !*chan_2g) { *chan_2g = chan_tmp; } else if (chan_tmp >= 36 && chan_tmp <= 161 && !*chan_5g) { chan_info.band = WLC_BAND_5G; chan_info.chan = chan_tmp; + chanspec = wf_create_chspec_from_primary(chan_info.chan, + WL_CHANSPEC_BW_20, wl_ext_wlcband_to_chanspec_band(chan_info.band)); if (wl_ext_dfs_chan(&chan_info) && nodfs) continue; + else if (wl_ext_passive_chan(dev, chanspec)) + continue; else *chan_5g = chan_tmp; } @@ -1198,69 +1265,6 @@ wl_ext_wlmsglevel(struct net_device *dev, char *command, int total_len) return ret; } -#ifdef WL_CFG80211 -bool -wl_legacy_chip_check(struct net_device *net) -{ - struct dhd_pub *dhd = dhd_get_pub(net); - uint chip; - - chip = dhd_conf_get_chip(dhd); - - if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || - chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || - chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || - chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || - chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || - chip == BCM4371_CHIP_ID || - chip == BCM43430_CHIP_ID || - chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID || - chip == BCM4359_CHIP_ID || - chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID || - chip == BCM43569_CHIP_ID) { - return true; - } - - return false; -} - -bool -wl_new_chip_check(struct net_device *net) -{ - struct dhd_pub *dhd = dhd_get_pub(net); - uint chip; - - chip = dhd_conf_get_chip(dhd); - - if (chip == BCM4359_CHIP_ID || chip == BCM43012_CHIP_ID || - chip == BCM43751_CHIP_ID || chip == BCM43752_CHIP_ID) { - return true; - } - - return false; -} - -bool -wl_extsae_chip(struct dhd_pub *dhd) -{ - uint chip; - - chip = dhd_conf_get_chip(dhd); - - if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || - chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || - chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || - chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || - chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || - chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID || - chip == BCM43569_CHIP_ID) { - return false; - } - - return true; -} -#endif - #ifdef WLEASYMESH #define CMD_EASYMESH "EASYMESH" //Set map 4 and dwds 1 on wlan0 interface @@ -1475,7 +1479,7 @@ wl_ext_mkeep_alive(struct net_device *dev, char *data, char *command, int total_len) { struct dhd_pub *dhd = dhd_get_pub(dev); - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; + wl_mkeep_alive_pkt_v1_t *mkeep_alive_pktp; int ret = -1, i, ifidx, id, period=-1; char *packet = NULL, *buf = NULL; int bytes_written = 0; @@ -1503,7 +1507,7 @@ wl_ext_mkeep_alive(struct net_device *dev, char *data, char *command, ret = wl_ext_iovar_getbuf(dev, "mkeep_alive", &id, sizeof(id), buf, total_len, NULL); if (!ret) { - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) buf; + mkeep_alive_pktp = (wl_mkeep_alive_pkt_v1_t *) buf; bytes_written += snprintf(command+bytes_written, total_len, "Id :%d\n" "Period (msec) :%d\n" @@ -1711,25 +1715,24 @@ static int wl_ext_recal(struct net_device *dev, char *data, char *command, int total_len) { + struct dhd_pub *dhd = dhd_get_pub(dev); int ret = 0, i, nchan, nssid = 0; - int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16); - wl_scan_params_t *params = NULL; - int ioctl_ver; + int params_size = WL_SCAN_PARAMS_V1_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16); + wl_scan_params_v1_t *params = NULL; + uint16 *chan_list = NULL; char *p; AEXT_TRACE(dev->name, "Enter\n"); if (data) { params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); - params = (wl_scan_params_t *) kzalloc(params_size, GFP_KERNEL); + params = (wl_scan_params_v1_t *) kzalloc(params_size, GFP_KERNEL); if (params == NULL) { ret = -ENOMEM; goto exit; } memset(params, 0, params_size); - wl_ext_get_ioctl_ver(dev, &ioctl_ver); - memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); params->bss_type = DOT11_BSSTYPE_ANY; params->scan_type = 0; @@ -1741,8 +1744,9 @@ wl_ext_recal(struct net_device *dev, char *data, char *command, params->scan_type |= WL_SCANFLAGS_PASSIVE; nchan = 2; - params->channel_list[0] = wf_channel2chspec(1, WL_CHANSPEC_BW_20); - params->channel_list[1] = wf_channel2chspec(2, WL_CHANSPEC_BW_20); + chan_list = params->channel_list; + chan_list[0] = wf_channel2chspec(1, WL_CHANSPEC_BW_20); + chan_list[1] = wf_channel2chspec(2, WL_CHANSPEC_BW_20); params->nprobes = htod32(params->nprobes); params->active_time = htod32(params->active_time); @@ -1750,7 +1754,7 @@ wl_ext_recal(struct net_device *dev, char *data, char *command, params->home_time = htod32(params->home_time); for (i = 0; i < nchan; i++) { - wl_ext_chspec_host_to_driver(ioctl_ver, params->channel_list[i]); + wl_ext_chspec_host_to_driver(dhd, params->channel_list[i]); } p = (char*)params->channel_list + nchan * sizeof(uint16); @@ -2141,7 +2145,7 @@ wl_ext_recv_probresp(struct net_device *dev, char *data, char *command, /* enable: 1. dhd_priv wl pkt_filter_add 150 0 0 0 0xFF 0x50 - 2. dhd_priv wl pkt_filter_enable 150 1 + 2. dhd_priv wl pkt_filter_enable 150 1 3. dhd_priv wl mpc 0 4. dhd_priv wl 108 1 disable: @@ -2452,27 +2456,43 @@ wl_ext_wowl_wakeind(struct net_device *dev, char *data, char *command, typedef struct notify_payload { int index; int len; - char payload[128]; + char payload[256]; } notify_payload_t; static int wl_ext_gpio_notify(struct net_device *dev, char *data, char *command, int total_len) { - s8 iovar_buf[WLC_IOCTL_SMLEN]; + s8 *iovar_buf = NULL; notify_payload_t notify, *pnotify = NULL; - int i, ret = 0, bytes_written = 0; - char frame_str[WLC_IOCTL_SMLEN+3]; + int i, ret = 0, bytes_written = 0, len; + char *frame_str = NULL; if (data) { + iovar_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); + if (iovar_buf == NULL) { + AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_MEDLEN); + goto exit; + } + memset(iovar_buf, 0, WLC_IOCTL_MEDLEN); + frame_str = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); + if (frame_str == NULL) { + AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_MEDLEN); + goto exit; + } + memset(frame_str, 0, WLC_IOCTL_MEDLEN); memset(¬ify, 0, sizeof(notify)); - memset(frame_str, 0, sizeof(frame_str)); sscanf(data, "%d %s", ¬ify.index, frame_str); if (notify.index < 0) notify.index = 0; - if (strlen(frame_str)) { + len = strlen(frame_str); + if (len > sizeof(notify.payload)) { + AEXT_ERROR(dev->name, "playload size %d > %d\n", len, sizeof(notify.payload)); + goto exit; + } + if (len) { notify.len = wl_pattern_atoh(frame_str, notify.payload); if (notify.len == -1) { AEXT_ERROR(dev->name, "rejecting pattern=%s\n", frame_str); @@ -2504,6 +2524,10 @@ wl_ext_gpio_notify(struct net_device *dev, char *data, char *command, } exit: + if (iovar_buf) + kfree(iovar_buf); + if (frame_str) + kfree(frame_str); return ret; } #endif /* WL_GPIO_NOTIFY */ @@ -2526,22 +2550,6 @@ typedef struct csi_list { csi_config_t configs[1]; } csi_list_t; -static int -wl_ether_atoe(const char *a, struct ether_addr *n) -{ - char *c = NULL; - int i = 0; - - memset(n, 0, ETHER_ADDR_LEN); - for (;;) { - n->octet[i++] = (uint8)strtoul(a, &c, 16); - if (!*c++ || i == ETHER_ADDR_LEN) - break; - a = c; - } - return (i == ETHER_ADDR_LEN); -} - static int wl_ext_csi(struct net_device *dev, char *data, char *command, int total_len) { @@ -2561,7 +2569,7 @@ wl_ext_csi(struct net_device *dev, char *data, char *command, int total_len) if (data) { sscanf(data, "%s %d", mac, &period); - ret = wl_ether_atoe(mac, &ea); + ret = bcm_ether_atoe(mac, &ea); if (!ret) { AEXT_ERROR(dev->name, "rejecting mac=%s, ret=%d\n", mac, ret); goto exit; @@ -2659,6 +2667,34 @@ wl_ext_get_country(struct net_device *dev, char *data, char *command, return bytes_written; } +static int +wl_ext_disable_5g_band(struct net_device *dev, char *data, char *command, + int total_len) +{ +#ifdef WL_CFG80211 + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); +#endif + int ret = -1; + int val; + + if (data) { + val = (int)simple_strtol(data, NULL, 0); + ret = wl_ext_iovar_setint(dev, "disable_5g_band", val); +#ifdef WL_CFG80211 + if (!ret) + wl_update_wiphybands(cfg, true); +#endif + } else { + ret = wl_ext_iovar_getint(dev, "disable_5g_band", &val); + if (!ret) { + ret = snprintf(command, total_len, "%d", val); + AEXT_TRACE(dev->name, "command result is %s\n", command); + } + } + + return ret; +} + typedef int (wl_ext_tpl_parse_t)(struct net_device *dev, char *data, char *command, int total_len); @@ -2711,6 +2747,7 @@ const wl_ext_iovar_tpl_t wl_ext_iovar_tpl_list[] = { {WLC_GET_VAR, WLC_SET_VAR, "csi", wl_ext_csi}, #endif /* CSI_SUPPORT */ {WLC_GET_VAR, WLC_SET_VAR, "country", wl_ext_get_country}, + {WLC_GET_VAR, WLC_SET_VAR, "disable_5g_band", wl_ext_disable_5g_band}, }; /* @@ -2812,7 +2849,7 @@ wl_ext_conf_iovar(struct net_device *dev, char *command, int total_len) goto exit; strncpy(name, pch, sizeof(name)); - + data = bcmstrtok(&pick_tmp, "", 0); // pick data if (!strcmp(name, "pm")) { @@ -2852,11 +2889,17 @@ wl_android_ext_priv_cmd(struct net_device *net, char *command, else if (strnicmp(command, CMD_MONITOR, strlen(CMD_MONITOR)) == 0) { *bytes_written = wl_ext_monitor(net, command, total_len); } - else if (strnicmp(command, CMD_SET_SUSPEND_BCN_LI_DTIM, strlen(CMD_SET_SUSPEND_BCN_LI_DTIM)) == 0) { - int bcn_li_dtim; - bcn_li_dtim = (int)simple_strtol((command + strlen(CMD_SET_SUSPEND_BCN_LI_DTIM) + 1), NULL, 10); - *bytes_written = net_os_set_suspend_bcn_li_dtim(net, bcn_li_dtim); +#ifdef BTC_WAR + else if (strnicmp(command, CMD_BTC_WAR, strlen(CMD_BTC_WAR)) == 0) { + *bytes_written = wl_ext_btc_war(net, command, total_len); } +#endif /* BTC_WAR */ +#ifdef WL_CFG80211 + else if (strnicmp(command, CMD_SET_SUSPEND_BCN_LI_DTIM, strlen(CMD_SET_SUSPEND_BCN_LI_DTIM)) == 0) { + struct bcm_cfg80211 *cfg = wl_get_cfg(net); + cfg->suspend_bcn_li_dtim = (int)simple_strtol((command + strlen(CMD_SET_SUSPEND_BCN_LI_DTIM) + 1), NULL, 10); + } +#endif /* WL_CFG80211 */ #ifdef WL_EXT_IAPSTA else if (strnicmp(command, CMD_IAPSTA_INIT, strlen(CMD_IAPSTA_INIT)) == 0 || strnicmp(command, CMD_ISAM_INIT, strlen(CMD_ISAM_INIT)) == 0) { @@ -2927,9 +2970,9 @@ wl_android_ext_priv_cmd(struct net_device *net, char *command, return ret; } -#define CH_MIN_5G_CHANNEL 34 int -wl_construct_ctl_chanspec_list(struct net_device *dev, wl_uint32_list_t *chan_list) +wl_construct_ctl_chanspec_list(struct net_device *dev, + wl_uint32_list_t *chan_list, bool nodfs) { void *list; u32 i, channel; @@ -2945,7 +2988,7 @@ wl_construct_ctl_chanspec_list(struct net_device *dev, wl_uint32_list_t *chan_li return -ENOMEM; } - err = wl_ext_iovar_getbuf(dev, "chan_info_list", NULL, + err = wldev_iovar_getbuf(dev, "chan_info_list", NULL, 0, list, LOCAL_BUF_LEN, NULL); if (err == BCME_UNSUPPORTED) { err = wl_ext_iovar_getbuf(dev, "chanspecs", NULL, @@ -2973,6 +3016,8 @@ wl_construct_ctl_chanspec_list(struct net_device *dev, wl_uint32_list_t *chan_li (((wl_chanspec_list_v1_t *)list)->chspecs[i].chanspec); } chspec = wl_chspec_driver_to_host(chspec); + if (nodfs && wl_ext_passive_chan(dev, chspec)) + continue; channel = wf_chspec_ctlchan(chspec); if (!CHSPEC_IS20(chspec)) { @@ -3020,11 +3065,11 @@ wl_ext_get_distance(struct net_device *net, u32 band) s32 err = BCME_OK; param.band = band; - err = wl_ext_iovar_getbuf(net, "bw_cap", ¶m, sizeof(param), buf, + err = wldev_iovar_getbuf(net, "bw_cap", ¶m, sizeof(param), buf, sizeof(buf), NULL); if (err) { if (err != BCME_UNSUPPORTED) { - AEXT_ERROR(net->name, "bw_cap failed, %d\n", err); + AEXT_TRACE(net->name, "bw_cap failed, %d\n", err); return err; } else { err = wl_ext_iovar_getint(net, "mimo_bw_cap", &bw_cap); @@ -3058,11 +3103,13 @@ wl_ext_get_best_channel(struct net_device *net, #if defined(BSSCACHE) wl_bss_cache_ctrl_t *bss_cache_ctrl, #else - wl_scan_results_t *bss_list, + wl_scan_results_v109_t *bss_list, #endif /* BSSCACHE */ - int ioctl_ver, int *best_2g_ch, int *best_5g_ch, int *best_6g_ch) + int *best_2g_ch, int *best_5g_ch, int *best_6g_ch) { + struct dhd_pub *dhd = dhd_get_pub(net); struct wl_bss_info *bi = NULL; /* must be initialized */ + struct wl_chan_info chan_info; s32 i, j; #if defined(BSSCACHE) wl_bss_cache_t *node; @@ -3073,8 +3120,7 @@ wl_ext_get_best_channel(struct net_device *net, s32 distance_6g; #endif /* WL_6G_BAND */ s32 cen_ch, distance, distance_2g, distance_5g, chanspec, min_ap=999; - u8 valid_chan_list[sizeof(u32)*(MAX_CTRL_CHANSPECS + 1)]; - wl_uint32_list_t *list; + wl_uint32_list_t *list = NULL; int ret; chanspec_t chspec; u32 channel; @@ -3089,24 +3135,31 @@ wl_ext_get_best_channel(struct net_device *net, memset(six_g_band8, -1, sizeof(six_g_band8)); #endif /* WL_6G_BAND */ - memset(valid_chan_list, 0, sizeof(valid_chan_list)); - list = (wl_uint32_list_t *)(void *) valid_chan_list; + list = kzalloc(sizeof(u32)*(MAX_CTRL_CHANSPECS + 1), GFP_KERNEL); + if (list == NULL) { + AEXT_ERROR(net->name, "kzalloc failed\n"); + ret = -ENOMEM; + goto exit; + } - ret = wl_construct_ctl_chanspec_list(net, list); + ret = wl_construct_ctl_chanspec_list(net, list, TRUE); if (ret < 0) { - AEXT_ERROR(net->name, "get channels failed with %d\n", ret); - return 0; + AEXT_ERROR(net->name, "construct chsnspec failed with %d\n", ret); + goto exit; } else { for (i = 0; i < list->count; i++) { chspec = list->element[i]; channel = wf_chspec_ctlchan(chspec); + chan_info.band = CHSPEC2WLC_BAND(chspec); + chan_info.chan = channel; if (CHSPEC_IS2G(chspec) && (channel >= CH_MIN_2G_CHANNEL) && - (channel <= CH_MAX_2G_CHANNEL)) { + (channel <= CH_MAX_2G_CHANNEL)) { b_band[channel-1] = 0; } #ifdef WL_6G_BAND - else if (CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) && - (channel <= CH_MAX_6G_CHANNEL)) { + else if (CHSPEC_IS6G(chspec) && CHSPEC_IS_6G_PSC(chspec) && + (channel >= CH_MIN_6G_CHANNEL) && + (channel <= CH_MAX_6G_CHANNEL)) { if (channel <= 93) six_g_band5[(channel-1)/4] = 0; else if (channel >= 97 && channel <= 109) @@ -3142,9 +3195,9 @@ wl_ext_get_best_channel(struct net_device *net, #if defined(BSSCACHE) bi = node->results.bss_info; #else - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : bss_list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : bss_list->bss_info; #endif /* BSSCACHE */ - chanspec = wl_ext_chspec_driver_to_host(ioctl_ver, bi->chanspec); + chanspec = wl_ext_chspec_driver_to_host(dhd, bi->chanspec); cen_ch = CHSPEC_CHANNEL(bi->chanspec); distance = 0; if (CHSPEC_IS20(chanspec)) @@ -3153,8 +3206,16 @@ wl_ext_get_best_channel(struct net_device *net, distance += 4; else if (CHSPEC_IS80(chanspec)) distance += 8; - else +#ifdef WL_6G_BAND + else if (CHSPEC_IS160(chanspec)) distance += 16; + else if (CHSPEC_IS320(chanspec)) + distance += 32; +#endif /* WL_6G_BAND */ + else { + AEXT_INFO(net->name, "unknown bw chanspec 0x%x\n", chanspec); + distance += 0; + } if (CHSPEC_IS2G(chanspec)) { distance += distance_2g; @@ -3166,26 +3227,26 @@ wl_ext_get_best_channel(struct net_device *net, #ifdef WL_6G_BAND else if (CHSPEC_IS6G(chanspec)) { distance += distance_6g; - if (cen_ch <= 93) { - for (j=0; j= 0 && abs(cen_ch-(93+j*4)) <= distance) + if (cen_ch <= 93 && cen_ch != 2) { + for (j=0; j= 0 && abs(cen_ch-(1+j*4)) <= distance) six_g_band5[j] += 1; } } else if (channel >= 97 && channel <= 109) { - for (j=0; j= 0 && abs(cen_ch-(97+j*4)) <= distance) six_g_band6[j] += 1; } } else if (channel >= 117 && channel <= 181) { - for (j=0; j= 0 && abs(cen_ch-(117+j*4)) <= distance) six_g_band7[j] += 1; } } else if (channel >= 189 && channel <= 221) { - for (j=0; j= 0 && abs(cen_ch-(189+j*4)) <= distance) six_g_band8[j] += 1; } @@ -3315,14 +3376,16 @@ wl_ext_get_best_channel(struct net_device *net, } exit: - return 0; + if (list) + kfree(list); + return ret; } #endif /* WL_CFG80211 || WL_ESCAN */ #ifdef WL_CFG80211 #define APCS_MAX_RETRY 10 -static int -wl_ext_fw_apcs(struct net_device *dev, uint32 band) +int +wl_ext_fw_apcs(struct net_device *dev, uint32 band, wl_scan_info_t *scan_info) { int channel = 0, chosen = 0, retry = 0, ret = 0, spect = 0; u8 *reqbuf = NULL; @@ -3351,19 +3414,27 @@ wl_ext_fw_apcs(struct net_device *dev, uint32 band) memset(reqbuf, 0, CHANSPEC_BUF_SIZE); acs_band = wl_ext_wlcband_to_chanspec_band(band); - if ((uint32)acs_band == WLC_BAND_INVALID) { + if (acs_band == INVCHANSPEC) { acs_band = WL_CHANSPEC_BAND_2G; } - if ((ret = wl_android_get_band_chanspecs(dev, reqbuf, CHANSPEC_BUF_SIZE, - acs_band, true)) < 0) { - WL_ERR(("ACS chanspec retrieval failed!\n")); - goto done; + if (scan_info) { + buf_size = sizeof(wl_channel_list_t); + memcpy(reqbuf, &scan_info->channels, sizeof(wl_channel_list_t)); + } else { + if ((ret = wl_android_get_band_chanspecs(dev, reqbuf, CHANSPEC_BUF_SIZE, + acs_band, true)) < 0) { + WL_ERR(("ACS chanspec retrieval failed!\n")); + goto done; + } + buf_size = CHANSPEC_BUF_SIZE; } - AEXT_INFO(dev->name, "ACS chanspec band 0x%x\n", acs_band); + AEXT_INFO(dev->name, "ACS band %d (chanspec band 0x%x)\n", band, acs_band); + if (android_msg_level & ANDROID_INFO_LEVEL) { + prhex("acs reqbuf", reqbuf, buf_size); + } - buf_size = CHANSPEC_BUF_SIZE; ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf, buf_size); if (ret < 0) { @@ -3416,150 +3487,52 @@ done: kfree(reqbuf); } - return channel; + return chosen; } #endif /* WL_CFG80211 */ -#ifdef WL_ESCAN int -wl_ext_drv_scan(struct net_device *dev, uint32 band, bool fast_scan) +wl_ext_autochannel(struct net_device *dev, uint acs, uint32 band, + wl_scan_info_t *scan_info) { - int ret = -1, i, cnt = 0; - int retry = 0, retry_max, retry_interval = 250, up = 1; - wl_scan_info_t scan_info; + int chosen = 0; + uint16 chan_2g, chan_5g, channel; - retry_max = WL_ESCAN_TIMER_INTERVAL_MS/retry_interval; - ret = wldev_ioctl_get(dev, WLC_GET_UP, &up, sizeof(s32)); - if (ret < 0 || up == 0) { - ret = wldev_ioctl_set(dev, WLC_UP, &up, sizeof(s32)); - } - memset(&scan_info, 0, sizeof(wl_scan_info_t)); - if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) { - for (i=0; i<13; i++) { - scan_info.channels.channel[i+cnt] = wf_create_chspec_from_primary(i+1, - WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G); - } - cnt += 13; - } - if (band == WLC_BAND_5G || band == WLC_BAND_AUTO) { - for (i=0; i<4; i++) { - scan_info.channels.channel[i+cnt] = wf_create_chspec_from_primary(36+i*4, - WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G); - } - cnt += 4; - for (i=0; i<4; i++) { - scan_info.channels.channel[i+cnt] = wf_create_chspec_from_primary(149+i*4, - WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G); - } - cnt += 4; - } -#ifdef WL_6G_BAND - if (band == WLC_BAND_6G || band == WLC_BAND_AUTO) { - for (i=0; i<59; i++) { - scan_info.channels.channel[i+cnt] = wf_create_chspec_from_primary(1+i*4, - WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_6G); - } - cnt += 59; - } -#endif /* WL_6G_BAND */ - if (band == WLC_BAND_2G) - fast_scan = FALSE; - scan_info.channels.count = cnt; - if (fast_scan) - scan_info.scan_time = 40; - scan_info.bcast_ssid = TRUE; - retry = retry_max; - while (retry--) { - ret = wl_escan_set_scan(dev, &scan_info); - if (!ret) - break; - OSL_SLEEP(retry_interval); - } - if (retry == 0) { - AEXT_ERROR(dev->name, "scan retry failed %d\n", retry_max); - ret = -1; - } - - return ret; -} - -int -wl_ext_drv_apcs(struct net_device *dev, uint32 band) -{ - int ret = 0, channel = 0; - struct dhd_pub *dhd = dhd_get_pub(dev); - struct wl_escan_info *escan = NULL; - int retry = 0, retry_max, retry_interval = 250; - - escan = dhd->escan; - WL_MSG(dev->name, "ACS_SCAN\n"); - escan->autochannel = 1; - ret = wl_ext_drv_scan(dev, band, TRUE); - if (ret < 0) - goto done; - retry_max = WL_ESCAN_TIMER_INTERVAL_MS/retry_interval; - retry = retry_max; - while (retry--) { - if (escan->escan_state == ESCAN_STATE_IDLE) { - if (band == WLC_BAND_5G) - channel = escan->best_5g_ch; -#ifdef WL_6G_BAND - else if (band == WLC_BAND_6G) - channel = escan->best_6g_ch; -#endif /* WL_6G_BAND */ - else - channel = escan->best_2g_ch; - WL_MSG(dev->name, "selected channel = %d\n", channel); - goto done; - } - AEXT_INFO(dev->name, "escan_state=%d, %d tried, ret = %d\n", - escan->escan_state, (retry_max - retry), ret); - OSL_SLEEP(retry_interval); - } - -done: - escan->autochannel = 0; - - return channel; -} -#endif /* WL_ESCAN */ - -int -wl_ext_autochannel(struct net_device *dev, uint acs, uint32 band) -{ - int channel = 0; - uint16 chan_2g, chan_5g; - - AEXT_INFO(dev->name, "acs=0x%x, band=%d \n", acs, band); + AEXT_INFO(dev->name, "acs=0x%x, band=%s\n", acs, WLCBAND2STR(band)); #ifdef WL_CFG80211 if (acs & ACS_FW_BIT) { int ret = 0; ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &channel, sizeof(channel)); - channel = 0; + chosen = 0; if (ret != BCME_UNSUPPORTED) - channel = wl_ext_fw_apcs(dev, band); - if (channel) - return channel; + chosen = wl_ext_fw_apcs(dev, band, scan_info); + if (chosen) + return chosen; } #endif #ifdef WL_ESCAN if (acs & ACS_DRV_BIT) - channel = wl_ext_drv_apcs(dev, band); -#endif /* WL_ESCAN */ + chosen = wl_escan_drv_apcs(dev, band, scan_info); +#endif - if (channel == 0) { + if (chosen == 0) { wl_ext_get_default_chan(dev, &chan_2g, &chan_5g, TRUE); if (band == WLC_BAND_5G) { + chosen = wf_create_chspec_from_primary(wf_chspec_primary20_chan(chan_5g), + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G); channel = chan_5g; } else { + chosen = wf_create_chspec_from_primary(wf_chspec_primary20_chan(chan_2g), + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G); channel = chan_2g; } - AEXT_ERROR(dev->name, "ACS failed. Fall back to default channel (%d) \n", channel); + AEXT_ERROR(dev->name, "ACS failed. Fall back to default channel (%s-%d) \n", + CHSPEC2BANDSTR(chosen), channel); } - return channel; + return chosen; } #if defined(RSSIAVG) @@ -3757,10 +3730,10 @@ exit: void wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, - wl_scan_results_t *ss_list) + wl_scan_results_v109_t *ss_list) { wl_rssi_cache_t *node, *prev, *leaf, **rssi_head; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; int i, j, k; struct osl_timespec now, timeout; @@ -3786,7 +3759,7 @@ wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, node = *rssi_head; prev = NULL; k = 0; - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; for (;node;) { if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) { AEXT_INFO("wlan", "Update %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n", @@ -4112,11 +4085,11 @@ wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, #if defined(RSSIAVG) wl_rssi_cache_ctrl_t *rssi_cache_ctrl, #endif /* RSSIAVG */ - wl_scan_results_t *ss_list) + wl_scan_results_v109_t *ss_list) { wl_bss_cache_t *node, *node_target = NULL, *prev, *leaf, **bss_head; wl_bss_cache_t *node_rssi_prev = NULL, *node_rssi = NULL; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; int i, k=0, bss_num = 0; struct osl_timespec now, timeout; int16 rssi_min; @@ -4151,7 +4124,7 @@ wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, prev = NULL; node_target = NULL; node_rssi_prev = NULL; - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; // find the bss with same BSSID for (;node;) { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.h old mode 100755 new mode 100644 index a8f88626d6f8..da605828db5a --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.h @@ -7,6 +7,19 @@ typedef struct wl_chan_info { uint16 chan; } wl_chan_info_t; +#define MAX_CTRL_CHANSPECS 256 +typedef struct wl_channel_list { + uint32 count; + uint32 chanspec[MAX_CTRL_CHANSPECS]; +} wl_channel_list_t; + +typedef struct wl_scan_info { + bool bcast_ssid; + wlc_ssid_t ssid; + wl_channel_list_t channels; + int scan_time; +} wl_scan_info_t; + typedef struct bcol_gtk_para { int enable; int ptk_len; @@ -15,7 +28,8 @@ typedef struct bcol_gtk_para { } bcol_gtk_para_t; #define ACS_FW_BIT (1<<0) #define ACS_DRV_BIT (1<<1) -int wl_ext_autochannel(struct net_device *dev, uint acs, uint32 band); +int wl_ext_autochannel(struct net_device *dev, uint acs, uint32 band, + wl_scan_info_t *scan_info); chanspec_band_t wl_ext_wlcband_to_chanspec_band(int band); int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len, int *bytes_written); @@ -24,11 +38,10 @@ bool wl_ext_check_scan(struct net_device *dev, dhd_pub_t *dhdp); int wl_ext_set_scan_time(struct net_device *dev, int scan_time, uint32 scan_get, uint32 scan_set); void wl_ext_wait_event_complete(struct dhd_pub *dhd, int ifidx); -int wl_ext_add_del_ie(struct net_device *dev, uint pktflag, char *ie_data, const char* add_del_cmd); -#ifdef WL_ESCAN -int wl_construct_ctl_chanspec_list(struct net_device *dev, wl_uint32_list_t *chan_list); -int wl_ext_drv_scan(struct net_device *dev, uint band, bool fast_scan); -#endif +int wl_ext_add_del_ie(struct net_device *dev, uint pktflag, char *ie_data, + const char* add_del_cmd); +int wl_construct_ctl_chanspec_list(struct net_device *dev, + wl_uint32_list_t *chan_list, bool nodfs); #ifdef WL_EXT_GENL int wl_ext_genl_init(struct net_device *net); void wl_ext_genl_deinit(struct net_device *net); @@ -47,9 +60,10 @@ int wl_ext_iovar_setbuf(struct net_device *dev, s8 *iovar_name, int wl_ext_iovar_setbuf_bsscfg(struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); -chanspec_t wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec); -chanspec_t wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec); +chanspec_t wl_ext_chspec_driver_to_host(struct dhd_pub *dhd, chanspec_t chanspec); +chanspec_t wl_ext_chspec_host_to_driver(struct dhd_pub *dhd, chanspec_t chanspec); bool wl_ext_dfs_chan(struct wl_chan_info *chan_info); +bool wl_ext_passive_chan(struct net_device *dev, u32 chanspec); uint16 wl_ext_get_default_chan(struct net_device *dev, uint16 *chan_2g, uint16 *chan_5g, bool nodfs); int wl_ext_set_chanspec(struct net_device *dev, struct wl_chan_info *chan_info, @@ -59,11 +73,6 @@ int wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver); #if defined(WL_CFG80211) || defined(WL_ESCAN) void wl_ext_user_sync(struct dhd_pub *dhd, int ifidx, bool lock); #endif -#if defined(WL_CFG80211) -bool wl_legacy_chip_check(struct net_device *net); -bool wl_new_chip_check(struct net_device *net); -bool wl_extsae_chip(struct dhd_pub *dhd); -#endif #if defined(WL_EXT_IAPSTA) || defined(WL_CFG80211) void wl_ext_bss_iovar_war(struct net_device *dev, s32 *val); #endif /* WL_EXT_IAPSTA ||WL_CFG80211 */ @@ -178,18 +187,31 @@ int wl_ext_get_best_channel(struct net_device *net, #else wl_scan_results_v109_t *bss_list, #endif - int ioctl_ver, int *best_2g_ch, int *best_5g_ch, int *best_6g_ch + int *best_2g_ch, int *best_5g_ch, int *best_6g_ch ); #ifdef WL_6G_BAND -#define CHSPEC2BANDSTR(chspec) (CHSPEC_IS2G(chspec) ? "2g" : CHSPEC_IS5G(chspec) ? \ - "5g" : CHSPEC_IS6G(chspec) ? "6g" : "0g") -#define WLCBAND2STR(band) ((band == WLC_BAND_2G) ? "2g" : (band == WLC_BAND_5G) ? \ - "5g" : (band == WLC_BAND_6G) ? "6g" : "0g") +#define CHSPEC2BANDSTR(chspec) ((chspec && CHSPEC_IS2G(chspec)) ? \ + "2g" : CHSPEC_IS5G(chspec) ? \ + "5g" : CHSPEC_IS6G(chspec) ? \ + "6g" : "0g") +#define WLCBAND2STR(band) ((band == WLC_BAND_2G) ? \ + "2g" : (band == WLC_BAND_5G) ? \ + "5g" : (band == WLC_BAND_6G) ? \ + "6g" : (band == WLC_BAND_AUTO) ? \ + "auto" : "0g") #else -#define CHSPEC2BANDSTR(chspec) (CHSPEC_IS2G(chspec) ? "2g" : CHSPEC_IS5G(chspec) ? \ - "5g" : "0g") -#define WLCBAND2STR(band) ((band == WLC_BAND_2G) ? "2g" : (band == WLC_BAND_5G) ? \ +#define CHSPEC2BANDSTR(chspec) ((chspec && CHSPEC_IS2G(chspec)) ? \ + "2g" : CHSPEC_IS5G(chspec) ? \ "5g" : "0g") +#define WLCBAND2STR(band) ((band == WLC_BAND_2G) ? \ + "2g" : (band == WLC_BAND_5G) ? \ + "5g" : (band == WLC_BAND_AUTO) ? \ + "auto" : "0g") #endif /* WL_6G_BAND */ +#define WLCWIDTH2STR(width) ((width == WL_CHANSPEC_BW_20) ? \ + "20" : (width == WL_CHANSPEC_BW_40) ? \ + "40" : (width == WL_CHANSPEC_BW_80) ? \ + "80" : (width == WL_CHANSPEC_BW_160) ? \ + "160" : "0") #endif diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_bam.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_bam.c old mode 100755 new mode 100644 index ec9e91ca3383..c568b04ab6d2 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_bam.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_bam.c @@ -1,7 +1,7 @@ /* * Bad AP Manager for ADPS * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -51,289 +51,7 @@ wl_bad_ap_mngr_add_entry(wl_bad_ap_mngr_t *bad_ap_mngr, wl_bad_ap_info_t *bad_ap return BCME_OK; } -#if !defined(DHD_ADPS_BAM_EXPORT) -#define WL_BAD_AP_INFO_FILE_PATH PLATFORM_PATH".bad_ap_list.info" -#define WL_BAD_AP_MAX_BUF_SIZE 1024u - -/* Bad AP information data format - * - * Status and Reason: come from event - * Connection count: Increase connecting Bad AP - * - * BSSID,year-month-day hour:min:sec,Status,Reason,Connection count - * ex) XX:XX:XX:XX:XX:XX,1970-01-01 00:00:00,1,2,1 - * - */ -#define WL_BAD_AP_INFO_FMT \ - "%02x:%02x:%02x:%02x:%02x:%02x,%04ld-%02d-%02d %02d:%02d:%02d,%u,%u,%u\n" -#define WL_BAD_AP_INFO_FMT_ITEM_CNT 15u - -static inline void -wl_bad_ap_mngr_tm2ts(struct timespec *ts, const struct tm tm) -{ - ts->tv_sec = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); - ts->tv_nsec = 0; -} - -/* Ignore compiler warnings due to -Werror=cast-qual */ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif -static int -wl_bad_ap_mngr_timecmp(void *priv, struct list_head *a, struct list_head *b) -{ - int ret; - - struct timespec ts1; - struct timespec ts2; - - wl_bad_ap_info_entry_t *e1 = CONTAINEROF(a, wl_bad_ap_info_entry_t, list); - wl_bad_ap_info_entry_t *e2 = CONTAINEROF(b, wl_bad_ap_info_entry_t, list); - - wl_bad_ap_mngr_tm2ts(&ts1, e1->bad_ap.tm); - wl_bad_ap_mngr_tm2ts(&ts2, e2->bad_ap.tm); - - ret = timespec_compare((const struct timespec *)&ts1, (const struct timespec *)&ts2); - - return ret; -} - -static void -wl_bad_ap_mngr_update(struct bcm_cfg80211 *cfg, wl_bad_ap_info_t *bad_ap_info) -{ - wl_bad_ap_info_entry_t *entry; - unsigned long flags; - - if (list_empty(&cfg->bad_ap_mngr.list)) { - return; - } - - WL_CFG_BAM_LOCK(&cfg->bad_ap_mngr.lock, flags); - /* sort by timestamp */ - list_sort(NULL, &cfg->bad_ap_mngr.list, wl_bad_ap_mngr_timecmp); - - /* update entry with the latest bad ap information */ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - entry = list_first_entry(&cfg->bad_ap_mngr.list, wl_bad_ap_info_entry_t, list); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - if (entry != NULL) { - memcpy(&entry->bad_ap, bad_ap_info, sizeof(entry->bad_ap)); - } - WL_CFG_BAM_UNLOCK(&cfg->bad_ap_mngr.lock, flags); -} -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - -static inline int -wl_bad_ap_mngr_fread_bad_ap_info(char *buf, int buf_len, wl_bad_ap_info_t *bad_ap) -{ - return snprintf(buf, buf_len, WL_BAD_AP_INFO_FMT, - bad_ap->bssid.octet[0], bad_ap->bssid.octet[1], - bad_ap->bssid.octet[2], bad_ap->bssid.octet[3], - bad_ap->bssid.octet[4], bad_ap->bssid.octet[5], - bad_ap->tm.tm_year + 1900, bad_ap->tm.tm_mon + 1, bad_ap->tm.tm_mday, - bad_ap->tm.tm_hour, bad_ap->tm.tm_min, bad_ap->tm.tm_sec, - bad_ap->status, bad_ap->reason, bad_ap->connect_count); -} - -static int -wl_bad_ap_mngr_fparse(struct bcm_cfg80211 *cfg, struct file *fp) -{ - int len; - int pos = 0; - char tmp[128]; - int ret = BCME_ERROR; - - wl_bad_ap_info_t bad_ap; - char *buf = NULL; - - buf = MALLOCZ(cfg->osh, WL_BAD_AP_MAX_BUF_SIZE); - if (buf == NULL) { - WL_ERR(("%s: allocation for buf failed\n", __FUNCTION__)); - return BCME_NOMEM; - } - - ret = vfs_read(fp, buf, WL_BAD_AP_MAX_BUF_SIZE, &fp->f_pos); - if (ret < 0) { - WL_ERR(("%s: file read failed (%d)\n", __FUNCTION__, ret)); - goto fail; - } - - len = ret; - do { - ret = sscanf(&buf[pos], WL_BAD_AP_INFO_FMT, - (uint32 *)&bad_ap.bssid.octet[0], (uint32 *)&bad_ap.bssid.octet[1], - (uint32 *)&bad_ap.bssid.octet[2], (uint32 *)&bad_ap.bssid.octet[3], - (uint32 *)&bad_ap.bssid.octet[4], (uint32 *)&bad_ap.bssid.octet[5], - (long int *)&bad_ap.tm.tm_year, (uint32 *)&bad_ap.tm.tm_mon, - (uint32 *)&bad_ap.tm.tm_mday, (uint32 *)&bad_ap.tm.tm_hour, - (uint32 *)&bad_ap.tm.tm_min, (uint32 *)&bad_ap.tm.tm_sec, - (uint32 *)&bad_ap.status, (uint32 *)&bad_ap.reason, - (uint32 *)&bad_ap.connect_count); - if (ret != WL_BAD_AP_INFO_FMT_ITEM_CNT) { - WL_ERR(("%s: file parse failed(expected: %d actual: %d)\n", - __FUNCTION__, WL_BAD_AP_INFO_FMT_ITEM_CNT, ret)); - ret = BCME_ERROR; - goto fail; - } - - /* convert struct tm format */ - bad_ap.tm.tm_year -= 1900; - bad_ap.tm.tm_mon -= 1; - - ret = wl_bad_ap_mngr_add(&cfg->bad_ap_mngr, &bad_ap); - if (ret < 0) { - WL_ERR(("%s: bad ap add failed\n", __FUNCTION__)); - goto fail; - } - - ret = wl_bad_ap_mngr_fread_bad_ap_info(tmp, sizeof(tmp), &bad_ap); - if (ret < 0) { - WL_ERR(("%s: wl_bad_ap_mngr_fread_bad_ap_info failed (%d)\n", - __FUNCTION__, ret)); - goto fail; - } - - if (cfg->bad_ap_mngr.num >= WL_BAD_AP_MAX_ENTRY_NUM) { - break; - } - - len -= ret; - pos += ret; - } while (len > 0); - - ret = BCME_OK; - -fail: - if (buf) { - MFREE(cfg->osh, buf, WL_BAD_AP_MAX_BUF_SIZE); - } - - return ret; -} - -static int -wl_bad_ap_mngr_fread(struct bcm_cfg80211 *cfg, const char *fname) -{ - int ret = BCME_ERROR; - - mm_segment_t fs; - struct file *fp = NULL; - - if (fname == NULL) { - WL_ERR(("%s: fname is NULL\n", __FUNCTION__)); - return ret; - } - mutex_lock(&cfg->bad_ap_mngr.fs_lock); - - fs = get_fs(); - set_fs(KERNEL_DS); - - fp = filp_open(fname, O_RDONLY, 0); - if (IS_ERR(fp)) { - fp = NULL; - WL_ERR(("%s: file open failed(%d)\n", __FUNCTION__, ret)); - goto fail; - } - - if ((ret = wl_bad_ap_mngr_fparse(cfg, fp)) < 0) { - goto fail; - } -fail: - if (fp) { - filp_close(fp, NULL); - } - set_fs(fs); - - mutex_unlock(&cfg->bad_ap_mngr.fs_lock); - - return ret; -} - -static int -wl_bad_ap_mngr_fwrite(struct bcm_cfg80211 *cfg, const char *fname) -{ - int ret = BCME_ERROR; - - mm_segment_t fs; - struct file *fp = NULL; - - int len = 0; - char tmp[WL_BAD_AP_MAX_BUF_SIZE]; - wl_bad_ap_info_t *bad_ap; - wl_bad_ap_info_entry_t *entry; - - if (list_empty(&cfg->bad_ap_mngr.list)) { - return BCME_ERROR; - } - - if (fname == NULL) { - return BCME_NOTFOUND; - } - - mutex_lock(&cfg->bad_ap_mngr.fs_lock); - - fs = get_fs(); - set_fs(KERNEL_DS); - - fp = filp_open(fname, O_CREAT | O_RDWR | O_TRUNC, 0666); - if (IS_ERR(fp)) { - ret = PTR_ERR(fp); - WL_ERR(("%s: file open failed(%d)\n", __FUNCTION__, ret)); - fp = NULL; - goto fail; - } - - memset(tmp, 0, sizeof(tmp)); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - list_for_each_entry(entry, &cfg->bad_ap_mngr.list, list) { - bad_ap = &entry->bad_ap; - ret = wl_bad_ap_mngr_fread_bad_ap_info(&tmp[len], sizeof(tmp) - len, bad_ap); - if (ret < 0) { - WL_ERR(("%s: snprintf failed(%d)\n", __FUNCTION__, ret)); - goto fail; - } - - len += ret; - } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - - ret = vfs_write(fp, tmp, len, &fp->f_pos); - if (ret < 0) { - WL_ERR(("%s: file write failed(%d)\n", __FUNCTION__, ret)); - goto fail; - } - /* Sync file from filesystem to physical media */ - ret = vfs_fsync(fp, 0); - if (ret < 0) { - WL_ERR(("%s: sync file failed(%d)\n", __FUNCTION__, ret)); - goto fail; - } - ret = BCME_OK; -fail: - if (fp) { - filp_close(fp, NULL); - } - set_fs(fs); - mutex_unlock(&cfg->bad_ap_mngr.fs_lock); - - return ret; -} -#else extern wl_bad_ap_mngr_t *g_bad_ap_mngr; -#endif /* DHD_ADPS_BAM_EXPORT */ wl_bad_ap_info_entry_t* wl_bad_ap_mngr_find(wl_bad_ap_mngr_t *bad_ap_mngr, const struct ether_addr *bssid) @@ -369,14 +87,15 @@ wl_bad_ap_mngr_add(wl_bad_ap_mngr_t *bad_ap_mngr, wl_bad_ap_info_t *bad_ap_info) BCM_REFERENCE(entry); BCM_REFERENCE(flags); -#if !defined(DHD_ADPS_BAM_EXPORT) - ret = wl_bad_ap_mngr_add_entry(bad_ap_mngr, bad_ap_info); -#else if (bad_ap_mngr->num == WL_BAD_AP_MAX_ENTRY_NUM) { /* Remove the oldest entry if entry list is full */ spin_lock_irqsave(&bad_ap_mngr->lock, flags); - list_del(bad_ap_mngr->list.next); - bad_ap_mngr->num--; + entry = list_entry(bad_ap_mngr->list.next, wl_bad_ap_info_entry_t, list); + if (entry) { + list_del(&entry->list); + MFREE(bad_ap_mngr->osh, entry, sizeof(*entry)); + bad_ap_mngr->num--; + } spin_unlock_irqrestore(&bad_ap_mngr->lock, flags); } @@ -385,6 +104,7 @@ wl_bad_ap_mngr_add(wl_bad_ap_mngr_t *bad_ap_mngr, wl_bad_ap_info_t *bad_ap_info) if (entry != NULL) { spin_lock_irqsave(&bad_ap_mngr->lock, flags); list_del(&entry->list); + MFREE(bad_ap_mngr->osh, entry, sizeof(*entry)); bad_ap_mngr->num--; spin_unlock_irqrestore(&bad_ap_mngr->lock, flags); } @@ -394,7 +114,7 @@ wl_bad_ap_mngr_add(wl_bad_ap_mngr_t *bad_ap_mngr, wl_bad_ap_info_t *bad_ap_info) WL_ERR(("%s - fail to add bad ap data(%d)\n", __FUNCTION__, ret)); return ret; } -#endif /* DHD_ADPS_BAM_EXPORT */ + return ret; } @@ -412,7 +132,7 @@ wl_bad_ap_mngr_deinit(struct bcm_cfg80211 *cfg) while (!list_empty(&cfg->bad_ap_mngr.list)) { entry = list_entry(cfg->bad_ap_mngr.list.next, wl_bad_ap_info_entry_t, list); if (entry) { - list_del(&cfg->bad_ap_mngr.list); + list_del(&entry->list); MFREE(cfg->osh, entry, sizeof(*entry)); } } @@ -420,9 +140,6 @@ wl_bad_ap_mngr_deinit(struct bcm_cfg80211 *cfg) #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) #pragma GCC diagnostic pop #endif -#if !defined(DHD_ADPS_BAM_EXPORT) - mutex_destroy(&cfg->bad_ap_mngr.fs_lock); -#endif /* !DHD_ADPS_BAM_EXPORT */ } void @@ -434,11 +151,7 @@ wl_bad_ap_mngr_init(struct bcm_cfg80211 *cfg) spin_lock_init(&cfg->bad_ap_mngr.lock); INIT_LIST_HEAD(&cfg->bad_ap_mngr.list); -#if !defined(DHD_ADPS_BAM_EXPORT) - mutex_init(&cfg->bad_ap_mngr.fs_lock); -#else g_bad_ap_mngr = &cfg->bad_ap_mngr; -#endif /* !DHD_ADPS_BAM_EXPORT */ } static int @@ -451,9 +164,6 @@ wl_event_adps_bad_ap_mngr(struct bcm_cfg80211 *cfg, void *data) wl_bad_ap_info_entry_t *entry; wl_bad_ap_info_t temp; -#if !defined(DHD_ADPS_BAM_EXPORT) - struct timespec ts; -#endif /* !DHD_ADPS_BAM_EXPORT */ if (event_data->version != WL_EVENT_ADPS_VER_1) { return BCME_VERSION; @@ -467,40 +177,8 @@ wl_event_adps_bad_ap_mngr(struct bcm_cfg80211 *cfg, void *data) BCM_REFERENCE(entry); bad_ap_data = (wl_event_adps_bad_ap_t *)event_data->data; -#if !defined(DHD_ADPS_BAM_EXPORT) - /* Update Bad AP list */ - if (list_empty(&cfg->bad_ap_mngr.list)) { - wl_bad_ap_mngr_fread(cfg, WL_BAD_AP_INFO_FILE_PATH); - } - - getnstimeofday(&ts); - entry = wl_bad_ap_mngr_find(&cfg->bad_ap_mngr, &bad_ap_data->ea); - if (entry != NULL) { - time_to_tm((ts.tv_sec - (sys_tz.tz_minuteswest * 60)), 0, &entry->bad_ap.tm); - entry->bad_ap.status = bad_ap_data->status; - entry->bad_ap.reason = bad_ap_data->reason; - entry->bad_ap.connect_count++; - } - else { - time_to_tm((ts.tv_sec - (sys_tz.tz_minuteswest * 60)), 0, &temp.tm); - temp.status = bad_ap_data->status; - temp.reason = bad_ap_data->reason; - temp.connect_count = 1; - memcpy(temp.bssid.octet, &bad_ap_data->ea.octet, ETHER_ADDR_LEN); - - if (cfg->bad_ap_mngr.num < WL_BAD_AP_MAX_ENTRY_NUM) { - wl_bad_ap_mngr_add(&cfg->bad_ap_mngr, &temp); - } - else { - wl_bad_ap_mngr_update(cfg, &temp); - } - } - - wl_bad_ap_mngr_fwrite(cfg, WL_BAD_AP_INFO_FILE_PATH); -#else memcpy(temp.bssid.octet, &bad_ap_data->ea.octet, ETHER_ADDR_LEN); ret = wl_bad_ap_mngr_add(&cfg->bad_ap_mngr, &temp); -#endif /* !DHD_ADPS_BAM_EXPORT */ return ret; } @@ -611,13 +289,6 @@ exit: bool wl_adps_bad_ap_check(struct bcm_cfg80211 *cfg, const struct ether_addr *bssid) { -#if !defined(DHD_ADPS_BAM_EXPORT) - /* Update Bad AP list */ - if (list_empty(&cfg->bad_ap_mngr.list)) { - wl_bad_ap_mngr_fread(cfg, WL_BAD_AP_INFO_FILE_PATH); - } -#endif /* DHD_ADPS_BAM_EXPORT */ - if (wl_bad_ap_mngr_find(&cfg->bad_ap_mngr, bssid) != NULL) return TRUE; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_bigdata.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_bigdata.c deleted file mode 100755 index fc7798304bf7..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_bigdata.c +++ /dev/null @@ -1,575 +0,0 @@ -/* - * Bigdata logging and report. None EWP and Hang event. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define WL_AP_BIGDATA_LOG(args) WL_DBG(args) - -#define WLC_E_IS_ASSOC(e, r) \ - (((e == WLC_E_ASSOC_IND) || (e == WLC_E_REASSOC_IND)) && r == DOT11_SC_SUCCESS) -#define WLC_E_IS_DEAUTH(e) \ - (e == WLC_E_DISASSOC_IND || e == WLC_E_DEAUTH_IND || e == WLC_E_DEAUTH) - -static void dump_ap_stadata(wl_ap_sta_data_t *ap_sta_data); -static inline void copy_ap_stadata(wl_ap_sta_data_t *dest, wl_ap_sta_data_t *src); -static void wg_rate_dot11mode(uint32 *rate, uint8 *channel, uint32 *mode_80211); -static void wg_ht_mimo_ant(uint32 *nss, wl_rateset_args_t *rateset); -static void wg_vht_mimo_ant(uint32 *nss, wl_rateset_args_t *rateset); -#if defined(WL11AX) -static void wg_he_mimo_ant(uint32 *nss, uint16 *mcsset); -#endif /* WL11AX */ -static int wg_parse_ap_stadata(struct net_device *dev, struct ether_addr *sta_mac, - wl_ap_sta_data_t *ap_sta_data); - -static void -dump_ap_stadata(wl_ap_sta_data_t *ap_sta_data) -{ - int i; - - if (!ap_sta_data) { - WL_AP_BIGDATA_LOG(("ap_sta_data is NULL\n")); - return; - } - - for (i = 0; i < MAX_STA_INFO_AP_CNT; i++) { - if (!ap_sta_data[i].is_empty) { - WL_AP_BIGDATA_LOG(("idx %d "MACDBG" dis %d empty %d\n", - i, MAC2STRDBG((char *)&ap_sta_data[i].mac), - ap_sta_data[i].disconnected, ap_sta_data[i].is_empty)); - WL_AP_BIGDATA_LOG(("mode %d nss %d chanspec %d rssi %d " - "rate %d reason_code %d\n\n", - ap_sta_data[i].mode_80211, - ap_sta_data[i].nss, ap_sta_data[i].chanspec, - ap_sta_data[i].rssi, ap_sta_data[i].rate, - ap_sta_data[i].reason_code)); - } - } -} - -static inline void -copy_ap_stadata(wl_ap_sta_data_t *dest, wl_ap_sta_data_t *src) -{ - memcpy(dest, src, sizeof(wl_ap_sta_data_t)); - dest->is_empty = FALSE; - dest->disconnected = FALSE; - dest->reason_code = 0; -} - -static void -get_copy_ptr_stadata(struct ether_addr *sta_mac, wl_ap_sta_data_t *sta_data, - uint32 *sta_list_cnt, void **data) -{ - int i; - int discon_idx = -1; - int empty_idx = -1; - - if (!sta_mac || !sta_data || !sta_list_cnt ||!data) { - WL_ERR(("sta_mac=%p sta_data=%p sta_lit_cnt=%p data=%p\n", - sta_mac, sta_data, sta_list_cnt, data)); - return; - } - - /* Find already existed sta */ - for (i = 0; i < MAX_STA_INFO_AP_CNT; i++) { - if (!memcmp((char*)sta_mac, (char*)&sta_data[i].mac, ETHER_ADDR_LEN)) { - WL_AP_BIGDATA_LOG(("found existed " - "STA idx %d "MACDBG"\n", - i, MAC2STRDBG((char *)sta_mac))); - *data = (wl_ap_sta_data_t *)&sta_data[i]; - return; - } - - if (sta_data[i].disconnected && (discon_idx == -1)) { - discon_idx = i; - } - - if (sta_data[i].is_empty && (empty_idx == -1)) { - empty_idx = i; - } - } - - /* Buf is max */ - if (*sta_list_cnt >= MAX_STA_INFO_AP_CNT) { - if (discon_idx != -1) { - WL_AP_BIGDATA_LOG(("delete disconnected " - "idx %d "MACDBG"\n", - discon_idx, MAC2STRDBG((char *)sta_mac))); - *data = (wl_ap_sta_data_t *)&sta_data[discon_idx]; - return; - } - } - - /* Buf is not max */ - if (empty_idx != -1) { - (*sta_list_cnt)++; - WL_AP_BIGDATA_LOG(("empty idx %d \n", empty_idx)); - *data = (wl_ap_sta_data_t *)&sta_data[empty_idx]; - return; - } -} - -static void -wg_rate_dot11mode(uint32 *rate, uint8 *channel, uint32 *mode_80211) -{ - if (*rate <= DOT11_11B_MAX_RATE) { - /* 11b maximum rate is 11Mbps. 11b mode */ - *mode_80211 = BIGDATA_DOT11_11B_MODE; - } else { - /* It's not HT Capable case. */ - if (*channel > DOT11_2GHZ_MAX_CH_NUM) { - *mode_80211 = BIGDATA_DOT11_11A_MODE; /* 11a mode */ - } else { - *mode_80211 = BIGDATA_DOT11_11G_MODE; /* 11g mode */ - } - } -} - -static void -wg_ht_mimo_ant(uint32 *nss, wl_rateset_args_t *rateset) -{ - int i; - - *nss = 0; - for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) { - int8 bitmap = DOT11_HT_MCS_RATE_MASK; - if (i == MAX_STREAMS_SUPPORTED-1) { - bitmap = DOT11_RATE_MASK; - } - if (rateset->mcs[i] & bitmap) { - (*nss)++; - } - } -} - -static void -wg_vht_mimo_ant(uint32 *nss, wl_rateset_args_t *rateset) -{ - int i; - uint32 mcs_code; - - *nss = 0; - - for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) { - mcs_code = VHT_MCS_MAP_TO_MCS_CODE(rateset->vht_mcs[i - 1]); - if (mcs_code != VHT_CAP_MCS_MAP_NONE) { - (*nss)++; - } - } -} - -#if defined(WL11AX) -static void -wg_he_mimo_ant(uint32 *nss, uint16 *mcsset) -{ - int i; - - *nss = 0; - - for (i = 0; i <= HE_MCS_MAP_NSS_MAX; i++) { - if (mcsset[i]) { - (*nss)++; - } - } -} -#endif /* WL11AX */ - -static int -wg_parse_ap_stadata(struct net_device *dev, struct ether_addr *sta_mac, - wl_ap_sta_data_t *ap_sta_data) -{ - sta_info_v4_t *sta_v4 = NULL; - sta_info_v5_t *sta_v5 = NULL; - wl_rateset_args_t *rateset_adv; - int ret = BCME_OK; - char* ioctl_buf = NULL; -#if defined(WL11AX) - struct wl_rateset_args_v2 *rateset_adv_v2; -#endif - - ioctl_buf = (char*)kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); - if (ioctl_buf == NULL) { - WL_ERR(("failed to allocated ioctl_buf \n")); - return BCME_ERROR; - } - - ret = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)sta_mac, - ETHER_ADDR_LEN, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - - if (ret < 0) { - WL_ERR(("sta_info err value :%d\n", ret)); - ret = BCME_ERROR; - goto done; - } - - sta_v4 = (sta_info_v4_t *)ioctl_buf; - ap_sta_data->mac = *sta_mac; - ap_sta_data->rssi = 0; - ap_sta_data->mimo = 0; - - rateset_adv = &sta_v4->rateset_adv; - ap_sta_data->chanspec = sta_v4->chanspec; - - WL_AP_BIGDATA_LOG(("sta_info ver %d\n", sta_v4->ver)); - - if (sta_v4->ver == WL_STA_VER_5) { - sta_v5 = (sta_info_v5_t *)ioctl_buf; - ap_sta_data->chanspec = sta_v5->chanspec; - rateset_adv = &sta_v5->rateset_adv; - } - - ap_sta_data->channel = wf_chspec_ctlchan(ap_sta_data->chanspec); - ap_sta_data->rate = - (sta_v4->rateset.rates[sta_v4->rateset.count - 1] & DOT11_RATE_MASK) / 2; - - if (sta_v4->vht_flags) { - ap_sta_data->mode_80211 = BIGDATA_DOT11_11AC_MODE; - wg_vht_mimo_ant(&ap_sta_data->nss, rateset_adv); - } else if (sta_v4->ht_capabilities) { - ap_sta_data->mode_80211 = BIGDATA_DOT11_11N_MODE; - wg_ht_mimo_ant(&ap_sta_data->nss, rateset_adv); - } else { - wg_rate_dot11mode(&ap_sta_data->rate, &ap_sta_data->channel, - &ap_sta_data->mode_80211); - } - -#if defined(WL11AX) - ret = wldev_iovar_getbuf(dev, "rateset", NULL, 0, ioctl_buf, - sizeof(wl_rateset_args_v2_t), NULL); - if (ret < 0) { - WL_ERR(("get rateset failed = %d\n", ret)); - } else { - rateset_adv_v2 = (wl_rateset_args_v2_t *)ioctl_buf; - WL_AP_BIGDATA_LOG(("rateset ver %d\n", rateset_adv_v2->version)); - - if (rateset_adv_v2->version == RATESET_ARGS_V2) { - rateset_adv_v2 = (wl_rateset_args_v2_t *)&sta_v4->rateset_adv; - if (sta_v4->ver == WL_STA_VER_5) { - rateset_adv_v2 = (wl_rateset_args_v2_t *)&sta_v5->rateset_adv; - } - - if (rateset_adv_v2->he_mcs[0]) { - WL_AP_BIGDATA_LOG(("there is he mcs rate\n")); - ap_sta_data->mode_80211 = BIGDATA_DOT11_11AX_MODE; - wg_he_mimo_ant(&ap_sta_data->nss, &rateset_adv_v2->he_mcs[0]); - } - } - } -#endif /* WL11AX */ - - if (ap_sta_data->nss) { - ap_sta_data->nss = ap_sta_data->nss - 1; - } - -done: - if (ioctl_buf) { - kfree(ioctl_buf); - } - - return ret; -} - -void -wl_gather_ap_stadata(void *handle, void *event_info, u8 event) -{ - u32 event_type = 0; - u32 reason = 0; - u32 status = 0; - struct ether_addr sta_mac; - dhd_pub_t *dhdp; - - struct net_device *dev = NULL; - struct bcm_cfg80211 *cfg = NULL; - wl_event_msg_t *e; - - wl_ap_sta_data_t *sta_data; - wl_ap_sta_data_t temp_sta_data; - void *data = NULL; - int i; - int ret; - - ap_sta_wq_data_t *wq_event_data = event_info; - if (!wq_event_data) { - WL_ERR(("wq_event_data is NULL\n")); - return; - } - - cfg = (struct bcm_cfg80211 *)wq_event_data->bcm_cfg; - if (!cfg || !cfg->ap_sta_info) { - WL_ERR(("cfg=%p ap_sta_info=%p\n", cfg, (cfg ? cfg->ap_sta_info : NULL))); - if (wq_event_data) { - kfree(wq_event_data); - } - return; - } - - mutex_lock(&cfg->ap_sta_info->wq_data_sync); - - dhdp = (dhd_pub_t *)cfg->pub; - e = &wq_event_data->e; - dev = (struct net_device *)wq_event_data->ndev; - - if (!e || !dev) { - WL_ERR(("e=%p dev=%p\n", e, dev)); - goto done; - } - - if (!wl_get_drv_status(cfg, AP_CREATED, dev)) { - WL_ERR(("skip to gather data becasue interface is not available\n")); - goto done; - } - - sta_data = cfg->ap_sta_info->ap_sta_data; - - event_type = ntoh32(e->event_type); - reason = ntoh32(e->reason); - status = ntoh32(e->status); - sta_mac = e->addr; - - if (!sta_data) { - WL_ERR(("sta_data is NULL\n")); - goto done; - } - - WL_AP_BIGDATA_LOG((""MACDBG" event %d status %d reason %d\n", - MAC2STRDBG((char*)&sta_mac), event_type, status, reason)); - - if (WLC_E_IS_ASSOC(event_type, reason)) { - ret = wg_parse_ap_stadata(dev, &sta_mac, &temp_sta_data); - if (ret < 0) { - WL_AP_BIGDATA_LOG(("sta_info err value :%d\n", ret)); - goto done; - } - - if (cfg->ap_sta_info->sta_list_cnt == 0) { - copy_ap_stadata(&sta_data[0], &temp_sta_data); - cfg->ap_sta_info->sta_list_cnt++; - dump_ap_stadata(sta_data); - } else { - get_copy_ptr_stadata(&sta_mac, sta_data, - &cfg->ap_sta_info->sta_list_cnt, &data); - if (data != NULL) { - copy_ap_stadata((wl_ap_sta_data_t *)data, &temp_sta_data); - dump_ap_stadata(sta_data); - } - } - } - - if (WLC_E_IS_DEAUTH(event_type)) { - /* Find already existed sta */ - for (i = 0; i < MAX_STA_INFO_AP_CNT; i++) { - if (!sta_data[i].is_empty && - !memcmp((char*)&sta_mac, (char*)&sta_data[i].mac, ETHER_ADDR_LEN)) { - WL_AP_BIGDATA_LOG(("found disconnected " - "STA idx %d "MACDBG"\n", - i, MAC2STRDBG((char *)&sta_mac))); - sta_data[i].is_empty = FALSE; - sta_data[i].disconnected = TRUE; - sta_data[i].reason_code = reason; - dump_ap_stadata(sta_data); - goto done; - } - } - } - -done: - if (wq_event_data) { - ASSERT(dhdp->osh); - MFREE(dhdp->osh, wq_event_data, sizeof(ap_sta_wq_data_t)); - } - mutex_unlock(&cfg->ap_sta_info->wq_data_sync); -} - -int -wl_attach_ap_stainfo(void *bcm_cfg) -{ - gfp_t kflags; - uint32 alloc_len; - wl_ap_sta_info_t *sta_info; - wl_ap_sta_data_t *sta_data = NULL; - int i; - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)bcm_cfg; - - if (!cfg) { - WL_ERR(("cfg is NULL\n")); - return -EINVAL; - } - - kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - alloc_len = sizeof(wl_ap_sta_info_t); - sta_info = (wl_ap_sta_info_t *)kzalloc(alloc_len, kflags); - - if (unlikely(!sta_info)) { - WL_ERR(("could not allocate memory for - " - "wl_ap_sta_info_t\n")); - goto fail; - } - cfg->ap_sta_info = sta_info; - - alloc_len = sizeof(wl_ap_sta_data_t) * MAX_STA_INFO_AP_CNT; - sta_data = (wl_ap_sta_data_t *)kzalloc(alloc_len, kflags); - - if (unlikely(!sta_data)) { - WL_ERR(("could not allocate memory for - " - "wl_ap_sta_data_t\n")); - goto fail; - } - - cfg->ap_sta_info->sta_list_cnt = 0; - - for (i = 0; i < MAX_STA_INFO_AP_CNT; i++) { - sta_data[i].is_empty = TRUE; - memset(&sta_data[i].mac, 0, ETHER_ADDR_LEN); - } - - cfg->ap_sta_info->ap_sta_data = sta_data; - - mutex_init(&cfg->ap_sta_info->wq_data_sync); - - WL_ERR(("attach success\n")); - - return BCME_OK; - -fail: - if (sta_data) { - kfree(sta_data); - cfg->ap_sta_info->ap_sta_data = NULL; - } - - if (sta_info) { - kfree(sta_info); - cfg->ap_sta_info = NULL; - } - - return BCME_ERROR; -} - -int -wl_detach_ap_stainfo(void *bcm_cfg) -{ - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)bcm_cfg; - - if (!cfg || !cfg->ap_sta_info) { - WL_ERR(("cfg=%p ap_sta_info=%p\n", - cfg, (cfg ? cfg->ap_sta_info : NULL))); - return -EINVAL; - } - - if (cfg->ap_sta_info->ap_sta_data) { - kfree(cfg->ap_sta_info->ap_sta_data); - cfg->ap_sta_info->ap_sta_data = NULL; - } - - mutex_destroy(&cfg->ap_sta_info->wq_data_sync); - - kfree(cfg->ap_sta_info); - cfg->ap_sta_info = NULL; - - WL_ERR(("detach success\n")); - - return BCME_OK; -} - -int -wl_ap_stainfo_init(void *bcm_cfg) -{ - int i; - wl_ap_sta_data_t *sta_data; - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)bcm_cfg; - - if (!cfg || !cfg->ap_sta_info) { - WL_ERR(("cfg=%p ap_sta_info=%p\n", - cfg, (cfg ? cfg->ap_sta_info : NULL))); - return -EINVAL; - } - - sta_data = cfg->ap_sta_info->ap_sta_data; - cfg->ap_sta_info->sta_list_cnt = 0; - - if (!sta_data) { - WL_ERR(("ap_sta_data is NULL\n")); - return -EINVAL; - } - - for (i = 0; i < MAX_STA_INFO_AP_CNT; i++) { - sta_data[i].is_empty = TRUE; - memset(&sta_data[i].mac, 0, ETHER_ADDR_LEN); - } - - return BCME_OK; -} - -int -wl_get_ap_stadata(void *bcm_cfg, struct ether_addr *sta_mac, void **data) -{ - int i; - wl_ap_sta_data_t *sta_data; - struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)bcm_cfg; - - if (!cfg || !cfg->ap_sta_info) { - WL_ERR(("cfg=%p ap_sta_info=%p\n", - cfg, (cfg ? cfg->ap_sta_info : NULL))); - return -EINVAL; - } - - if (!sta_mac || !data) { - WL_ERR(("sta_mac=%p data=%p\n", sta_mac, data)); - return -EINVAL; - } - - sta_data = cfg->ap_sta_info->ap_sta_data; - - if (!sta_data) { - WL_ERR(("ap_sta_data is NULL\n")); - return -EINVAL; - } - - /* Find already existed sta */ - for (i = 0; i < MAX_STA_INFO_AP_CNT; i++) { - if (!sta_data[i].is_empty) { - WL_AP_BIGDATA_LOG(("%d " MACDBG " " MACDBG "\n", i, - MAC2STRDBG((char *)sta_mac), - MAC2STRDBG((char*)&sta_data[i].mac))); - - if (!memcmp(sta_mac, (char*)&sta_data[i].mac, ETHER_ADDR_LEN)) { - WL_AP_BIGDATA_LOG(("Found STA idx %d " MACDBG "\n", - i, MAC2STRDBG((char *)&sta_mac))); - - *data = (wl_ap_sta_data_t*)&sta_data[i]; - return BCME_OK; - } - } - } - - return BCME_ERROR; -} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c old mode 100755 new mode 100644 index 3cfb4ec5e308..f35565ec8dbb --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -34,6 +34,8 @@ #include #endif /* WL_WPS_SYNC */ #include <802.11.h> +#include <802.11wfa.h> +#include <802.11cust.h> #include #include #include @@ -76,6 +78,7 @@ #include #include #include +#include #include #include #include @@ -111,23 +114,35 @@ #include #endif /* RTT_SUPPORT */ -#if defined(BIGDATA_SOFTAP) || defined(DHD_ENABLE_BIGDATA_LOGGING) -#include -#endif /* BIGDATA_SOFTAP || DHD_ENABLE_BIGDATA_LOGGING */ - #ifdef DHD_EVENT_LOG_FILTER #include #endif /* DHD_EVENT_LOG_FILTER */ #define BRCM_SAE_VENDOR_EVENT_BUF_LEN 500 -#ifdef DNGL_AXI_ERROR_LOGGING +#if defined(DNGL_AXI_ERROR_LOGGING) && defined(REPORT_AXI_ERROR) #include -#endif /* DNGL_AXI_ERROR_LOGGING */ +#endif /* DNGL_AXI_ERROR_LOGGING && REPORT_AXI_ERROR */ -#if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL) +#ifdef WL_CP_COEX #include #include -#endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */ +#endif /* WL_CP_COEX */ + +#ifdef WL_CELLULAR_CHAN_AVOID +#include +#endif /* WL_CELLULAR_CHAN_AVOID */ + +/* DSCP Policy for the network-centric QoS */ +#if defined(DHD_DSCP_POLICY) +#include +#include +#endif /* DHD_DSCP_POLICY */ + +#include + +#ifdef CSI_SUPPORT +#include +#endif /* CSI_SUPPORT */ #if (defined(WL_FW_OCE_AP_SELECT) || defined(BCMFW_ROAM_ENABLE)) && \ ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)) @@ -144,9 +159,27 @@ uint wl_reassoc_support = false; #endif /* WL_REASSOC */ module_param(wl_reassoc_support, uint, 0660); +#ifdef WL_RAV_MSCS_NEG_IN_ASSOC +/* Call IOVs to enable MSCS OFFLOAD + * and set default MSCS configuration. + */ +uint mscs_offload = true; +#else +uint mscs_offload = false; +#endif /* WL_REASSOC */ +module_param(mscs_offload, uint, 0660); + static struct device *cfg80211_parent_dev = NULL; static struct bcm_cfg80211 *g_bcmcfg = NULL; +/* + * wl_dbg_level : a default level to print to dmesg buffer + * wl_log_level : a default level to log to DLD or Ring + * To keep one level operation(dhd_msg_level) in HW4, + * dhd_msg_level and dhd_log_level have the same level + * IOVAR(loglevel) can adjust logging level dynamically + */ u32 wl_dbg_level = WL_DBG_ERR; +u32 wl_log_level = WL_DBG_ERR; #define MAX_WAIT_TIME 1500 #ifdef WLAIBSS_MCHAN @@ -192,17 +225,10 @@ u32 wl_dbg_level = WL_DBG_ERR; #define DNGL_FUNC(func, parameters) #else #define DNGL_FUNC(func, parameters) func parameters -#define COEX_DHCP #endif /* defined(BCMDONGLEHOST) */ #define WLAN_EID_SSID 0 -#define CH_MIN_5G_CHANNEL 34 -#ifdef WLAIBSS -enum abiss_event_type { - AIBSS_EVENT_TXFAIL -}; -#endif #ifdef WL_RELMCAST enum rmc_event_type { @@ -220,19 +246,21 @@ enum rmc_event_type { * this definition reuires disabling missing-field-initializer warning * as the ieee80211_regdomain definition differs in plain linux and in Android */ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \ -(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ + 4 && __GNUC_MINOR__ >= 6)) _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") #endif -static const struct ieee80211_regdomain brcm_regdom = { +static const struct ieee80211_regdomain const_regdom_default = { #ifdef WL_6G_BAND .n_reg_rules = 8, #else .n_reg_rules = 4, #endif .alpha2 = "99", + .dfs_region = NL80211_DFS_UNSET, .reg_rules = { + /* REG_RULE(start, end, bw, gain, eirp, reg_flags) */ /* IEEE 802.11b/g, channels 1..11 */ REG_RULE(2412-10, 2472+10, 40, 6, 20, 0), /* If any */ @@ -241,9 +269,14 @@ static const struct ieee80211_regdomain brcm_regdom = { */ REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), /* IEEE 802.11a, channel 36..64 */ - REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), + REG_RULE(5150-10, 5350+10, 80, 6, 20, 0), +#ifdef WL_5P9G + /* IEEE 802.11a, channel 100..181 */ + REG_RULE(5470-10, 5910+10, 80, 6, 20, 0), +#else /* IEEE 802.11a, channel 100..165 */ - REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), + REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), +#endif /* WL_5P9G */ #ifdef WL_6G_BAND REG_RULE(6025-80, 6985+80, 160, 6, 20, 0), REG_RULE(5935-10, 7115+10, 20, 6, 20, 0), @@ -252,14 +285,67 @@ static const struct ieee80211_regdomain brcm_regdom = { #endif /* WL_6G_BAND */ } }; -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \ -(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ + 4 && __GNUC_MINOR__ >= 6)) _Pragma("GCC diagnostic pop") #endif +#ifdef EXT_REG_INFO +static struct ieee80211_regdomain *global_regd_self = NULL; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM) + +/* it's better reserved enough items here for some + * channels were split into too many piecs case + */ +#define CONST_SYNA_REG_RULES_MAX_QTY NL80211_MAX_SUPP_REG_RULES /* 64 */ +#define CONST_SYNA_REGD_SELF_SIZE \ +(sizeof(struct ieee80211_regdomain) + \ + (CONST_SYNA_REG_RULES_MAX_QTY * \ + sizeof(struct ieee80211_reg_rule))) +#define CONST_SYNA_REG_ANTENNA_GAIN_DEFAULT 6 /* dbi */ +#define CONST_SYNA_REG_EIRP_DEFAULT 20 /* dbm */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) +#define CONST_SYNA_REG_FLAG_FILTER_MASK (IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_RADAR) +#else +#define CONST_SYNA_REG_FLAG_FILTER_MASK (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR) +#endif +#define CONST_SYNA_REG_FLAG_FILTER_EXTRA_MASK \ +(IEEE80211_CHAN_NO_HT40MINUS \ + | IEEE80211_CHAN_NO_HT40PLUS) +/* Consider pick up suitable flags mask to avoid quantity + * exceeds the NL80211_MAX_SUPP_REG_RULES(64): + * A. adding 'IEEE80211_CHAN_NO_20MHZ' will make those + * 80MHz center channels like 42/58 split the regdomain + * into a lot of pieces + * B. adding 'IEEE80211_CHAN_NO_HT40(IEEE80211_CHAN_NO_HT40MINUS + * and IEEE80211_CHAN_NO_HT40PLUS)' will make those + * 40MHz center channels like (38/46/54) split the + * regdomain into a lot of pieces + * C. adding 'CONST_SYNA_REG_FLAG_FILTER_MASK' will make those + * 40MHz center channels like 60/62 split the regdomain + * into a lot of pieces + * D. adding ' | IEEE80211_CHAN_NO_80MHZ \' will make those + * 80MHz center channels like 42/58 split the regdomain + * into a lot of pieces + */ +#define CONST_SYNA_REG_FLAG_COMPARE_FOR_SPLIT_MASK \ +( \ + IEEE80211_CHAN_DISABLED | \ + IEEE80211_CHAN_NO_160MHZ \ +) + +#define CONST_SYNA_REG_FLAG_SAVE_MASK \ +( \ + CONST_SYNA_REG_FLAG_COMPARE_FOR_SPLIT_MASK | \ + CONST_SYNA_REG_FLAG_FILTER_EXTRA_MASK \ +) + +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM) */ +#endif /* EXT_REG_INFO */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ - (defined(WL_IFACE_COMB_NUM_CHANNELS) || \ - defined(WL_CFG80211_P2P_DEV_IF)) + (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) static const struct ieee80211_iface_limit common_if_limits[] = { { /* @@ -318,6 +404,61 @@ common_iface_combinations[] = { }; #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ +#if defined(WL_CFG80211_AKM_TYPES_BKPORT) || (LINUX_VERSION_CODE >= KERNEL_VERSION(5, \ + 7, 0)) +static const uint32 +akm_suites_station[] = { + WLAN_AKM_SUITE_8021X, + WLAN_AKM_SUITE_PSK, + WLAN_AKM_SUITE_SAE, + WLAN_AKM_SUITE_FT_OVER_SAE, + WLAN_AKM_SUITE_8021X_SHA256, + WLAN_AKM_SUITE_PSK_SHA256, + WLAN_AKM_SUITE_FT_PSK, + WLAN_AKM_SUITE_FT_8021X, + WLAN_AKM_SUITE_8021X_SUITE_B, + WLAN_AKM_SUITE_8021X_SUITE_B_192, + WLAN_AKM_SUITE_FILS_SHA256, + WLAN_AKM_SUITE_FILS_SHA384, + WLAN_AKM_SUITE_FT_FILS_SHA256, + WLAN_AKM_SUITE_FT_FILS_SHA384, + WLAN_AKM_SUITE_OWE, + WLAN_AKM_SUITE_DPP +}; + +static const uint32 +akm_suites_ap[] = { + WLAN_AKM_SUITE_PSK, + WLAN_AKM_SUITE_SAE, + WL_AKM_SUITE_SHA256_PSK, +}; + +static const uint32 +akm_suites_p2p[] = { + WLAN_AKM_SUITE_PSK, + WL_AKM_SUITE_SHA256_PSK, +}; + +static const struct wiphy_iftype_akm_suites +iftype_akm_suites[] = { + { + .iftypes_mask = BIT(NL80211_IFTYPE_STATION), + .akm_suites = akm_suites_station, + .n_akm_suites = ARRAY_SIZE(akm_suites_station), + }, + { + .iftypes_mask = BIT(NL80211_IFTYPE_AP), + .akm_suites = akm_suites_ap, + .n_akm_suites = ARRAY_SIZE(akm_suites_ap), + }, + { + .iftypes_mask = BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO), + .akm_suites = akm_suites_p2p, + .n_akm_suites = ARRAY_SIZE(akm_suites_p2p), + }, +}; +#endif /* (WL_CFG80211_AKM_TYPES_BKPORT ) || (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) */ + static const char *wl_if_state_strs[WL_IF_STATE_MAX + 1] = { "WL_IF_CREATE_REQ", "WL_IF_CREATE_DONE", @@ -356,11 +497,16 @@ static s32 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); static s32 wl_cfg80211_start_bssload_report(struct net_device *ndev); #endif /* WL_CHAN_UTIL */ +#ifdef OEM_ANDROID +static s32 wl_apply_per_sta_conn_suspend_settings(struct bcm_cfg80211 *cfg, + struct net_device *dev, bool set); +#endif /* OEM_ANDROID */ +s32 wl_cfg80211_wsec_info_pmk(struct bcm_cfg80211 *cfg, struct net_device *ndev, + wl_wsec_info_pmk_info_t *pmk_info, uint16 pmk_info_len, uint8 action); + +static int wl_get_p2p_disc_ies(struct bcm_cfg80211 *cfg, + struct wireless_dev *wdev, u8 **p2p_ie, u16 *p2p_ie_len); -/* SoftAP related parameters */ -#define DEFAULT_2G_SOFTAP_CHANNEL 1 -#define DEFAULT_2G_SOFTAP_CHANSPEC 0x1006 -#define DEFAULT_5G_SOFTAP_CHANNEL 149 #define WL_MAX_NUM_CSA_COUNTERS 255 #define MAX_VNDR_OUI_STR_LEN 256u @@ -391,6 +537,11 @@ static const uchar disco_bcnloss_vsie[] = { }; #endif /* WL_ANALYTICS */ +#ifdef WL_RAV_MSCS_NEG_IN_ASSOC +static s32 wl_cfg80211_enable_rav_mscs_params(struct bcm_cfg80211 *cfg, + struct net_device *ndev, bool mscs_offload); +#endif /* WL_RAV_MSCS_NEG_IN_ASSOC */ +static void wl_cfg80211_recovery_handler(struct work_struct *work); static int wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg, struct net_device *ndev, char *vndr_oui, u32 vndr_oui_len); static void wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg); @@ -426,6 +577,11 @@ wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u3 } #endif /* WL_FW_OCE_AP_SELECT */ +#if defined(DHD_DSCP_POLICY) +static int wl_cfg80211_is_wfa_cap_ie(wlcfg_assoc_info_t *info, struct bcm_cfg80211 *cfg, + const u8 *bssid_hint); +#endif /* defined(DHD_DSCP_POLICY) */ + /* * cfg80211_ops api/callback list */ @@ -475,19 +631,36 @@ static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); #endif /* WL_CFG80211_P2P_DEV_IF */ static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) + int link_id, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) */ u8 key_idx, bool unicast, bool multicast); static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) + int link_id, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) */ u8 key_idx, bool pairwise, const u8 *mac_addr, struct key_params *params); static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) + int link_id, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) */ u8 key_idx, bool pairwise, const u8 *mac_addr); static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) + int link_id, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) */ u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *params)); -static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, - struct net_device *dev, u8 key_idx); -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) +static int wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, + struct net_device *dev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) + int link_id, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) */ + u8 key_idx); +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 2, 0)) static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, u64 cookie); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) @@ -534,6 +707,10 @@ s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, wl_iftype_t brcm_iftype, s32 del, u8 *addr); +#ifdef WL_CFG80211_MONITOR +int wl_cfg80211_set_monitor_channel(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef); +#endif /* WL_CFG80211_MONITOR */ #ifdef GTK_OFFLOAD_SUPPORT #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) static s32 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev, @@ -556,6 +733,10 @@ static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev, static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev, const u8 *aa); #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) +static int wl_cfg80211_update_owe_info(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_update_owe_info *oweinfo); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) */ /* * event & event Q handlers for cfg80211 interfaces @@ -577,18 +758,17 @@ static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +#ifdef CSI_SUPPORT +static s32 wl_notify_csi_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +#endif /* CSI_SUPPORT */ + static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, const wl_event_msg_t *e, void *data, bool completed); -#ifdef DHD_LOSSLESS_ROAMING static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, const wl_event_msg_t *e, void *data); -#endif /* DHD_LOSSLESS_ROAMING */ static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); -#ifdef BT_WIFI_HANDOVER -static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, - bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); -#endif /* BT_WIFI_HANDOVER */ #ifdef GSCAN_SUPPORT static s32 wl_handle_roam_exp_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); @@ -603,7 +783,7 @@ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_ static s32 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); #endif /* CUSTOM_EVENT_PM_WAKE */ -#if defined(DHD_LOSSLESS_ROAMING) || defined (DBG_PKT_MON) +#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON) static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */ @@ -621,6 +801,11 @@ static s32 wl_notify_device_discovery(struct bcm_cfg80211 *cfg, bcm_struct_cfgde static s32 wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +#ifdef WL_MBO_HOST +static s32 +wl_mbo_btm_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +#endif /* WL_MBO_HOST */ #endif /* WL_MBO */ #ifdef WL_TWT @@ -631,15 +816,21 @@ wl_notify_twt_event(struct bcm_cfg80211 *cfg, #ifdef WL_CLIENT_SAE static bool wl_is_pmkid_available(struct net_device *dev, const u8 *bssid); -static s32 wl_notify_start_auth(struct bcm_cfg80211 *cfg, +static s32 +wl_notify_start_auth(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); -static s32 wl_cfg80211_external_auth(struct wiphy *wiphy, +static s32 +wl_cfg80211_external_auth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_external_auth_params *ext_auth); static s32 wl_cfg80211_mgmt_auth_tx(struct net_device *dev, bcm_struct_cfgdev *cfgdev, struct bcm_cfg80211 *cfg, const u8 *buf, size_t len, s32 bssidx, u64 *cookie); #endif /* WL_CLIENT_SAE */ +#if defined(WL_SAR_TX_POWER) && defined(WL_SAR_TX_POWER_CONFIG) +static void wl_get_sar_config_info(struct bcm_cfg80211 *cfg); +#endif /* WL_SAR_TX_POWER && WL_SAR_TX_POWER_CONFIG */ + /* * register/deregister parent device */ @@ -670,7 +861,7 @@ static s32 wl_set_auth_type(struct net_device *dev, static s32 wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme); static s32 wl_set_key_mgmt(struct net_device *dev, - struct cfg80211_connect_params *sme); + struct cfg80211_connect_params *sme, wlcfg_assoc_info_t *assoc_info); static s32 wl_set_set_sharedkey(struct net_device *dev, struct cfg80211_connect_params *sme); #ifdef WL_FILS @@ -709,7 +900,8 @@ static void wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); #endif /* CONFIG_CFG80211_INTERNAL_REGDB */ -static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool update_ssid); +static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, + bool update_ssid, u8 *mac); static void wl_cfg80211_work_handler(struct work_struct *work); static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, const u8 *mac_addr, @@ -775,9 +967,6 @@ int init_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver); s32 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg); #endif /* P2P_LISTEN_OFFLOADING */ -#ifdef CUSTOMER_HW4_DEBUG -extern bool wl_scan_timeout_dbg_enabled; -#endif /* CUSTOMER_HW4_DEBUG */ #ifdef PKT_FILTER_SUPPORT extern uint dhd_pkt_filter_enable; extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); @@ -803,7 +992,7 @@ wl_sdo_proto_t wl_sdo_protos [] = { #ifdef WL_WPS_SYNC static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg); static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg); -static void wl_wps_reauth_timeout(unsigned long data); +static void wl_wps_reauth_timeout(void *data); static s32 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg); static s32 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev); static s32 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *peer_mac); @@ -821,18 +1010,37 @@ static s32 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct const wl_event_msg_t *e, void *data); #endif /* WL_BCNRECV */ +#if defined(KEEP_ALIVE) && defined(DHD_CLEANUP_KEEP_ALIVE) +#define KEEP_ALIVE_ID_MAX 8 +void wl_cleanup_keep_alive(struct net_device *ndev, struct bcm_cfg80211 *cfg); +#endif /* defined(KEEP_ALIVE) && defined(DHD_CLEANUP_KEEP_ALIVE) */ + #ifdef WL_CAC_TS static s32 wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); #endif /* WL_CAC_TS */ -#if defined(WL_MBO) || defined(WL_OCE) static s32 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); -#endif /* WL_MBO || WL_OCE */ static void wl_cfg80211_handle_set_ssid_complete(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as, const wl_event_msg_t *event, wl_assoc_state_t assoc_state); +#ifdef WL_CFGVENDOR_CUST_ADVLOG +static void wl_cfgvendor_custom_advlog_conn(struct bcm_cfg80211 *cfg, struct net_device *dev, + struct cfg80211_connect_params *sme); +static void wl_cfgvendor_custom_advlog_disconn(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as); +static void wl_cfgvendor_custom_advlog_connfail(struct bcm_cfg80211 *cfg, + const wl_event_msg_t *event, wl_assoc_status_t *as); +void wl_cfgvendor_advlog_disassoc_tx(struct bcm_cfg80211 *cfg, struct net_device *ndev, + uint32 reason, int rssi); +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ + +#ifdef WL_NAN_INSTANT_MODE +static int wl_cfg80211_get_nan_instant_chan(struct bcm_cfg80211 *cfg, + wl_chanspec_list_v1_t *chan_list, uint32 band_mask, + chanspec_t *nan_inst_mode_chspec); +#endif /* WL_NAN_INSTANT_MODE */ + #if !defined(BCMDONGLEHOST) /* Wake lock are used in Android only, which is dongle based as of now */ #define DHD_OS_WAKE_LOCK(pub) @@ -842,8 +1050,8 @@ static void wl_cfg80211_handle_set_ssid_complete(struct bcm_cfg80211 *cfg, wl_as #define DHD_OS_WAKE_LOCK_TIMEOUT(pub) #endif /* defined(BCMDONGLEHOST) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || \ - (defined(CONFIG_ARCH_MSM) && defined(CFG80211_DISCONNECTED_V2)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || (defined(CONFIG_ARCH_MSM) && \ + defined(CFG80211_DISCONNECTED_V2)) #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \ cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \ IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); @@ -855,8 +1063,8 @@ static void wl_cfg80211_handle_set_ssid_complete(struct bcm_cfg80211 *cfg, wl_as #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || \ - defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE) || \ - defined(WL_FILS) || defined(CONFIG_CFG80211_FILS_BKPORT) + defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE) || defined(WL_FILS) || \ + defined(CONFIG_CFG80211_FILS_BKPORT) #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \ resp_ie_len, status, gfp) \ cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \ @@ -909,7 +1117,8 @@ extern int disable_proptx; extern void dhd_force_disable_singlcore_scan(dhd_pub_t *dhd); #endif /* FORCE_DISABLE_SINGLECORE_SCAN */ -#if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, 0))) +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, \ + 0))) struct chan_info { int freq; int chan_type; @@ -977,6 +1186,10 @@ static struct ieee80211_channel __wl_5ghz_a_channels[] = { CHAN5G(149, 0), CHAN5G(153, 0), CHAN5G(157, 0), CHAN5G(161, 0), CHAN5G(165, 0), +#ifdef WL_5P9G + CHAN5G(169, 0), CHAN5G(173, 0), + CHAN5G(177, 0), CHAN5G(181, 0), +#endif /* WL_5P9G */ #if defined(WL_6G_BAND) && !defined(CFG80211_6G_SUPPORT) /* 6GHz frequency starting 5935 */ @@ -1075,12 +1288,83 @@ static struct ieee80211_channel __wl_6ghz_channels[] = { }; #endif /* CFG80211_6G_SUPPORT */ +#ifdef WL_CAP_HE +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) || defined(CONFIG_6GHZ_BKPORT) +static struct ieee80211_sband_iftype_data __wl_he_cap = { + .types_mask = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP), + .he_cap = { + .has_he = true, + .he_cap_elem = { + .mac_cap_info[0] = (IEEE80211_HE_MAC_CAP0_HTC_HE | + IEEE80211_HE_MAC_CAP0_TWT_REQ), + .mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US, + .mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_BSR, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) + .mac_cap_info[5] = IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) */ + + .phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G, + .phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, + .phy_cap_info[2] = + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US, + .phy_cap_info[3] = + IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER, + .phy_cap_info[4] = + IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4, + .phy_cap_info[5] = + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2, + .phy_cap_info[6] = + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)) + IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB | + IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB | +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)) */ + IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | + IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB | +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)) */ + IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, + .phy_cap_info[7] = + IEEE80211_HE_PHY_CAP7_MAX_NC_1, + .phy_cap_info[8] = + IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) + .phy_cap_info[9] = + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) */ + }, + .he_mcs_nss_supp = { + .rx_mcs_80 = cpu_to_le16(0xfffa), + .tx_mcs_80 = cpu_to_le16(0xfffa), + } + }, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + .he_6ghz_capa = {.capa = cpu_to_le16(0x3038)}, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) */ +}; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) */ +#endif /* WL_CAP_HE */ + static struct ieee80211_supported_band __wl_band_2ghz = { .band = IEEE80211_BAND_2GHZ, .channels = __wl_2ghz_channels, .n_channels = ARRAY_SIZE(__wl_2ghz_channels), .bitrates = wl_g_rates, - .n_bitrates = wl_g_rates_size + .n_bitrates = wl_g_rates_size, +#ifdef WL_CAP_HE +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) || defined(CONFIG_6GHZ_BKPORT) + .iftype_data = &__wl_he_cap, + .n_iftype_data = 1 +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) */ +#endif /* WL_CAP_HE */ }; static struct ieee80211_supported_band __wl_band_5ghz_a = { @@ -1088,7 +1372,13 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = { .channels = __wl_5ghz_a_channels, .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), .bitrates = wl_a_rates, - .n_bitrates = wl_a_rates_size + .n_bitrates = wl_a_rates_size, +#ifdef WL_CAP_HE +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) || defined(CONFIG_6GHZ_BKPORT) + .iftype_data = &__wl_he_cap, + .n_iftype_data = 1 +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) */ +#endif /* WL_CAP_HE */ }; #ifdef CFG80211_6G_SUPPORT @@ -1097,7 +1387,13 @@ static struct ieee80211_supported_band __wl_band_6ghz = { .channels = __wl_6ghz_channels, .n_channels = ARRAY_SIZE(__wl_6ghz_channels), .bitrates = wl_a_rates, - .n_bitrates = wl_a_rates_size + .n_bitrates = wl_a_rates_size, +#ifdef WL_CAP_HE +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) || defined(CONFIG_6GHZ_BKPORT) + .iftype_data = &__wl_he_cap, + .n_iftype_data = 1 +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) */ +#endif /* WL_CAP_HE */ }; #endif /* CFG80211_6G_SUPPORT */ @@ -1227,9 +1523,6 @@ static const rsn_akm_wpa_auth_entry_t rsn_akm_wpa_auth_lookup_tbl[] = { #define BUFSZ 8 #define BUFSZN BUFSZ + 1 -#define _S(x) #x -#define S(x) _S(x) - #define SOFT_AP_IF_NAME "swlan0" /* watchdog timer for disconnecting when fw is not associated for FW_ASSOC_WATCHDOG_TIME ms */ @@ -1270,6 +1563,95 @@ int wl_channel_to_frequency(u32 chan, chanspec_band_t band) return 0; /* not supported */ } +int +wl_get_sideband_num(chanspec_bw_t bw) +{ + int sb_cnt; + + switch (bw) { + case WL_CHANSPEC_BW_20: + sb_cnt = 1; + break; + case WL_CHANSPEC_BW_40: + sb_cnt = WF_NUM_SIDEBANDS_40MHZ; + break; + case WL_CHANSPEC_BW_80: + sb_cnt = WF_NUM_SIDEBANDS_80MHZ; + break; + case WL_CHANSPEC_BW_160: + sb_cnt = WF_NUM_SIDEBANDS_160MHZ; + break; + default: + sb_cnt = 0; + break; + } + + return sb_cnt; +} + +int +wl_get_all_sideband_chanspecs(uint center_channel, chanspec_band_t band, + chanspec_bw_t bw, chanspec_t *chspecs, int *cnt) +{ + wf_chanspec_iter_t iter; + chanspec_t chanspec; + int sb_cnt, ret = -EINVAL; + + if (chspecs == NULL || cnt == NULL) { + WL_ERR(("Invalid input params\n")); + return ret; + } + + if (band != WL_CHANSPEC_BAND_2G && + band != WL_CHANSPEC_BAND_5G) { + WL_ERR(("band is not supported %x\n", band)); + return ret; + } + + sb_cnt = wl_get_sideband_num(bw); + if (sb_cnt == 0) { + WL_ERR(("invalid band %x\n", band)); + goto exit; + } + + *cnt = 0; + + wf_chanspec_iter_init(&iter, band, bw); + while (wf_chanspec_iter_next(&iter, &chanspec)) { + if (CHSPEC_CHANNEL(chanspec) == center_channel) { + chspecs[(*cnt)++] = chanspec; + } + if (*cnt == sb_cnt) { + break; + } + } + + if (*cnt == sb_cnt) { + ret = BCME_OK; + } + +exit: + return ret; +} + +u8 wl_chanspec_to_host_bw_map(chanspec_t cur_chanspec) +{ + u8 host_bw = WIFI_CHAN_WIDTH_INVALID; + + if (CHSPEC_IS20(cur_chanspec)) { + host_bw = WIFI_CHAN_WIDTH_20; + } else if (CHSPEC_IS40(cur_chanspec)) { + host_bw = WIFI_CHAN_WIDTH_40; + } else if (CHSPEC_IS80(cur_chanspec)) { + host_bw = WIFI_CHAN_WIDTH_80; + } else if (CHSPEC_IS160(cur_chanspec)) { + host_bw = WIFI_CHAN_WIDTH_160; + } else if (CHSPEC_IS8080(cur_chanspec)) { + host_bw = WIFI_CHAN_WIDTH_80P80; + } + return host_bw; +} + static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg, enum wl_pm_workq_act_type type) { @@ -1743,11 +2125,11 @@ s32 wl_set_tx_power(struct net_device *dev, err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm, sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync); - if (unlikely(err)) + if (unlikely(err)) { WL_ERR(("qtxpower error (%d)\n", err)); - else - WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm)); - + } else { + WL_TRACE(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm)); + } return err; } @@ -1768,7 +2150,7 @@ s32 wl_get_tx_power(struct net_device *dev, s32 *dbm) txpwrdbm = dtoh32(txpwrdbm); *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4; - WL_DBG(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm)); + WL_TRACE(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm)); return err; } @@ -1780,7 +2162,7 @@ chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); struct ether_addr bssid; - wl_bss_info_t *bss = NULL; + wl_bss_info_v109_t *bss = NULL; u16 channel = WL_P2P_TEMP_CHAN; char *buf; @@ -1814,7 +2196,7 @@ chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) chspec = wl_ch_host_to_driver(channel); } else { - bss = (wl_bss_info_t *) (buf + 4); + bss = (wl_bss_info_v109_t *) (buf + 4); chspec = bss->chanspec; #ifdef WL_6G_BAND /* Avoid p2p bring up in 6G based on bssinfo */ @@ -1987,6 +2369,64 @@ fail: return NULL; } +static int +wl_iovar_fn(struct bcm_cfg80211 *cfg, struct net_device *ndev, struct preinit_iov *data) +{ + preinit_iov_t *vi = (preinit_iov_t *)data; + + return wldev_iovar_setint(ndev, vi->cmd_name, vi->value); +} + +static int +wl_ioctl_fn(struct bcm_cfg80211 *cfg, struct net_device *ndev, struct preinit_iov *data) +{ + preinit_iov_t *vi = (preinit_iov_t *)data; + + return wldev_ioctl_set(ndev, vi->cmd_id, &(vi->value), sizeof(int)); +} + +static preinit_iov_t init_sta_role_iovars[] = { + {wl_iovar_fn, WLC_SET_VAR, DEFAULT_ASSOC_LISTEN, "assoc_listen"}, + {wl_iovar_fn, WLC_SET_VAR, 0, "roam_off"}, + {wl_ioctl_fn, WLC_SET_ROAM_SCAN_PERIOD, DEFAULT_ROAM_SCAN_PRD, ""}, + {wl_iovar_fn, WLC_SET_VAR, DEFAULT_FULL_ROAM_PRD, "fullroamperiod"}, + {wl_iovar_fn, WLC_SET_VAR, AP_ENV_INDETERMINATE, "roam_env_detection"}, + {wl_iovar_fn, WLC_SET_PM, 0x2, ""}, + {wl_iovar_fn, WLC_SET_VAR, DEFAULT_BCN_TIMEOUT, "bcn_timeout"}, + {wl_iovar_fn, WLC_SET_VAR, DEFAULT_ASSOC_RETRY, "assoc_retry_max"}, + {wl_ioctl_fn, WLC_SET_FAKEFRAG, 0x1, ""}, + {wl_iovar_fn, WLC_SET_VAR, 0x1, "buf_key_b4_m4"}, + {wl_iovar_fn, WLC_SET_VAR, 0x1, "interworking"}, + {wl_iovar_fn, WLC_SET_VAR, DEFAULT_WNM_CONF, "wnm"}, + {wl_iovar_fn, WLC_SET_VAR, DEFAULT_RECREATE_BI_TIMEOUT, "recreate_bi_timeout"}, + {wl_iovar_fn, WLC_SET_VAR, 0, "wnm_btmdelta"}, + {NULL, 0, 0, NULL} +}; + +static void +wl_apply_vif_sta_config(struct bcm_cfg80211 *cfg, + struct net_device *ndev) +{ + s32 ret; + preinit_iov_t *vi; + +#ifdef WL_RAV_MSCS_NEG_IN_ASSOC + ret = wl_cfg80211_enable_rav_mscs_params(cfg, ndev, mscs_offload); + if (ret) { + WL_INFORM(("enable rav_mscs failed ,err(%d)\n", ret)); + } +#endif /* WL_RAV_MSCS_NEG_IN_ASSOC */ + + for (vi = init_sta_role_iovars; vi->fn != NULL; vi++) { + ret = vi->fn(cfg, ndev, vi); + if ((ret != BCME_OK) && (ret != BCME_UNSUPPORTED)) { + WL_ERR(("dualsta_exec_initiovars: iov %s status %d\n", + vi->cmd_name, ret)); + } + WL_DBG(("iov: %s ret: %d\n", vi->cmd_name, ret)); + } +} + void wl_cfg80211_iface_state_ops(struct wireless_dev *wdev, wl_interface_state_t state, @@ -1996,6 +2436,7 @@ wl_cfg80211_iface_state_ops(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg; dhd_pub_t *dhd; s32 bssidx; + struct net_info *netinfo = NULL; WL_DBG(("state:%s wl_iftype:%d mode:%d\n", wl_if_state_strs[state], wl_iftype, wl_mode)); @@ -2016,6 +2457,7 @@ wl_cfg80211_iface_state_ops(struct wireless_dev *wdev, cfg = wiphy_priv(wdev->wiphy); ndev = wdev->netdev; + netinfo = wl_get_netinfo_by_wdev(cfg, wdev); dhd = (dhd_pub_t *)(cfg->pub); bssidx = wl_get_bssidx_by_wdev(cfg, wdev); @@ -2038,6 +2480,11 @@ wl_cfg80211_iface_state_ops(struct wireless_dev *wdev, #endif /* WLTDLS */ break; case WL_IF_DELETE_REQ: + if (netinfo && netinfo->passphrase_cfg) { + wl_cfg80211_wsec_info_pmk(cfg, wdev->netdev, + (wl_wsec_info_pmk_info_t *)netinfo->passphrase_cfg, + netinfo->passphrase_cfg_len, WL_WSEC_PMK_INFO_DEL); + } #ifdef WL_WPS_SYNC wl_wps_handle_ifdel(ndev); #endif /* WPS_SYNC */ @@ -2053,6 +2500,13 @@ wl_cfg80211_iface_state_ops(struct wireless_dev *wdev, } #endif /* CUSTOM_SET_CPUCORE */ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL); + +#if defined(KEEP_ALIVE) && defined(DHD_CLEANUP_KEEP_ALIVE) + if ((ndev == cfg->inet_ndev) && cfg->mkeep_alive_avail) { + wl_cleanup_keep_alive(ndev, cfg); + } +#endif /* defined(KEEP_ALIVE) && defined(DHD_CLEANUP_KEEP_ALIVE) */ + break; case WL_IF_CREATE_DONE: if (wl_mode == WL_MODE_BSS) { @@ -2060,10 +2514,14 @@ wl_cfg80211_iface_state_ops(struct wireless_dev *wdev, /* Enable firmware key buffering before sent 4-way M4 */ wldev_iovar_setint(ndev, "buf_key_b4_m4", 1); } + if (wl_iftype == WL_IF_TYPE_STA) { + wl_apply_vif_sta_config(cfg, ndev); + } if (wl_iftype == WL_IF_TYPE_P2P_GC) { /* Disable firmware roaming for P2P interface */ wldev_iovar_setint(ndev, "roam_off", 1); wldev_iovar_setint(ndev, "bcn_timeout", dhd->conf->bcn_timeout); + ROAMOFF_DBG_SAVE(ndev, SET_ROAM_P2P_GC, 1); { int assoc_retry = 3; #if defined(CUSTOM_ASSOC_RETRY_MAX) @@ -2143,8 +2601,7 @@ wl_cfg80211_p2p_if_del(struct wiphy *wiphy, struct wireless_dev *wdev) } ndev = wdev->netdev; - (void)memcpy_s(p2p_dev_addr.octet, ETHER_ADDR_LEN, - ndev->dev_addr, ETHER_ADDR_LEN); + DEV_ADDR_GET(ndev, p2p_dev_addr.octet); wl_clr_p2p_status(cfg, GO_NEG_PHASE); wl_clr_p2p_status(cfg, IF_ADDING); @@ -2156,7 +2613,7 @@ wl_cfg80211_p2p_if_del(struct wiphy *wiphy, struct wireless_dev *wdev) /* disable interface before bsscfg free */ err = wl_cfgp2p_ifdisable(cfg, &p2p_dev_addr); /* if fw doesn't support "ifdis", - do not wait for link down of ap mode + * do not wait for link down of ap mode */ if (err == 0) { WL_ERR(("Wait for Link Down event for GO !!!\n")); @@ -2258,7 +2715,7 @@ wl_cfg80211_add_monitor_if(struct wiphy *wiphy, const char *name) return ndev->ieee80211_ptr; fail: return ERR_PTR(-EOPNOTSUPP); -#endif // endif +#endif /* WL_CFG80211_P2P_DEV_IF */ } static struct wireless_dev * @@ -2274,7 +2731,7 @@ wl_cfg80211_add_ibss(struct wiphy *wiphy, u16 wl_iftype, char const *name) #endif } -#ifdef DNGL_AXI_ERROR_LOGGING +#if defined(DNGL_AXI_ERROR_LOGGING) && defined(REPORT_AXI_ERROR) static s32 _wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg) { @@ -2291,7 +2748,7 @@ _wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg) WL_ERR(("%s: starts to read %s. Axi error \n", __FUNCTION__, filename)); - fp = filp_open(filename, O_RDONLY, 0); + fp = dhd_filp_open(filename, O_RDONLY, 0); if (IS_ERR(fp) || (fp == NULL)) { WL_ERR(("%s: Couldn't read the file, err %ld,File [%s] No previous axi error \n", @@ -2299,8 +2756,8 @@ _wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg) return ret; } - kernel_read_compat(fp, fp->f_pos, (char *)dhd->axi_err_dump, sizeof(dhd_axi_error_dump_t)); - filp_close(fp, NULL); + dhd_kernel_read_compat(fp, fp->f_pos, (char *)dhd->axi_err_dump, sizeof(dhd_axi_error_dump_t)); + dhd_filp_close(fp, NULL); /* Delete axi error info file */ if (dhd_file_delete(filename) < 0) { @@ -2346,15 +2803,15 @@ _wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg) ret = BCME_ERROR; return ret; } -#endif /* DNGL_AXI_ERROR_LOGGING */ +#endif /* DNGL_AXI_ERROR_LOGGING && REPORT_AXI_ERROR */ /* All Android/Linux private/Vendor Interface calls should make * use of below API for interface creation. */ -struct wireless_dev * -wl_cfg80211_add_if(struct bcm_cfg80211 *cfg, +static struct wireless_dev * +_wl_cfg80211_add_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev, - wl_iftype_t wl_iftype, const char *name, u8 *mac) + wl_iftype_t wl_iftype, const char *name, const u8 *mac) { u8 mac_addr[ETH_ALEN]; s32 err = -ENODEV; @@ -2383,6 +2840,10 @@ wl_cfg80211_add_if(struct bcm_cfg80211 *cfg, if (!dhd) { return NULL; } + + if (wl_iftype == WL_IF_TYPE_P2P_DISC) { + dhd->p2p_disc_busy_cnt = 0; + } #endif /* BCMDONGLEHOST */ if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) { @@ -2393,7 +2854,6 @@ wl_cfg80211_add_if(struct bcm_cfg80211 *cfg, if ((wl_mode = wl_iftype_to_mode(wl_iftype)) < 0) { return NULL; } - mutex_lock(&cfg->if_sync); #ifdef WL_NAN if (wl_iftype == WL_IF_TYPE_NAN) { /* @@ -2410,17 +2870,15 @@ wl_cfg80211_add_if(struct bcm_cfg80211 *cfg, */ if ((wl_iftype != WL_IF_TYPE_P2P_DISC) && (err = wl_cfg80211_handle_if_role_conflict(cfg, wl_iftype)) < 0) { - mutex_unlock(&cfg->if_sync); return NULL; } #endif /* WL_IFACE_MGMT */ -#ifdef DNGL_AXI_ERROR_LOGGING +#if defined(DNGL_AXI_ERROR_LOGGING) && defined(REPORT_AXI_ERROR) /* Check the previous smmu fault error */ if ((err = _wl_cfg80211_check_axi_error(cfg)) < 0) { - mutex_unlock(&cfg->if_sync); return NULL; } -#endif /* DNGL_AXI_ERROR_LOGGING */ +#endif /* DNGL_AXI_ERROR_LOGGING && REPORT_AXI_ERROR */ /* Protect the interace op context */ /* Do pre-create ops */ wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr, WL_IF_CREATE_REQ, @@ -2460,7 +2918,7 @@ wl_cfg80211_add_if(struct bcm_cfg80211 *cfg, break; case WL_IF_TYPE_P2P_DISC: case WL_IF_TYPE_P2P_GO: - /* Intentional fall through */ + /* falls through */ case WL_IF_TYPE_P2P_GC: if (cfg->p2p_supported) { wdev = wl_cfg80211_p2p_if_add(cfg, wl_iftype, @@ -2470,6 +2928,8 @@ wl_cfg80211_add_if(struct bcm_cfg80211 *cfg, /* Intentionally fall through for unsupported interface * handling when firmware doesn't support p2p */ + /* falls through */ + fallthrough; default: WL_ERR(("Unsupported interface type\n")); err = -ENOTSUPP; @@ -2494,7 +2954,6 @@ wl_cfg80211_add_if(struct bcm_cfg80211 *cfg, " cfg_iftype:%d, vif_count:%d\n", (wdev->netdev ? wdev->netdev->ifindex : 0xff), wdev->iftype, cfg->vif_count)); - mutex_unlock(&cfg->if_sync); return wdev; fail: @@ -2534,10 +2993,23 @@ fail: } exit: - mutex_unlock(&cfg->if_sync); return NULL; } +struct wireless_dev * +wl_cfg80211_add_if(struct bcm_cfg80211 *cfg, + struct net_device *primary_ndev, + wl_iftype_t wl_iftype, const char *name, const u8 *mac) +{ + struct wireless_dev *wdev = NULL; + mutex_lock(&cfg->if_sync); + DHD_OS_WAKE_LOCK((dhd_pub_t *)(cfg->pub)); + wdev = _wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, name, mac); + DHD_OS_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub)); + mutex_unlock(&cfg->if_sync); + return wdev; +} + static s32 wl_cfg80211_del_ibss(struct wiphy *wiphy, struct wireless_dev *wdev) { @@ -2559,6 +3031,22 @@ wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev, mutex_lock(&cfg->if_sync); ret = _wl_cfg80211_del_if(cfg, primary_ndev, wdev, ifname); mutex_unlock(&cfg->if_sync); + + if ((ret == BCME_OK) && (cfg->vif_count == 0) && !(primary_ndev->flags & IFF_UP) && +#ifdef WL_STATIC_IF + !(wl_cfg80211_static_if_active(cfg)) && +#endif + (wl_cfgvif_get_iftype_count(cfg, WL_IF_TYPE_AP) == 0) && + (wl_cfgvif_get_iftype_count(cfg, WL_IF_TYPE_STA) == 0)) { + /* DHD cleanup in case wlan0 down was already called but was not + * done due to a virtual interface still running + */ + if (!dhd_net_if_locked(primary_ndev)) { + WL_INFORM(("Calling dhd_stop for DHD cleanup as all interfaces are down\n")); + dhd_stop(primary_ndev); + } + } + return ret; } @@ -2577,8 +3065,11 @@ _wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev, BCM_REFERENCE(dhd); #endif /* BCMDONGLEHOST */ + DHD_OS_WAKE_LOCK((dhd_pub_t *)(cfg->pub)); + if (!cfg) { - return -EINVAL; + ret = -EINVAL; + goto end; } #if defined(BCMDONGLEHOST) @@ -2595,11 +3086,19 @@ _wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev, /* Check whether we have a valid wdev ptr */ if (unlikely(!wdev)) { WL_ERR(("wdev not found. '%s' does not exists\n", ifname)); - return -ENODEV; + ret = -ENODEV; + goto end; } WL_INFORM_MEM(("del vif. wdev cfg_iftype:%d\n", wdev->iftype)); + /* If dhd_stop is called virtual interface cleanup will be done + * from wl_cfg80211_cleanup_virtual_ifaces + */ + if (dhd->stop_in_progress) { + WL_INFORM_MEM(("Avoid _wl_cfg80211_del_if path, as dhd_stop is called\n")); + goto end; + } wiphy = wdev->wiphy; #ifdef WL_CFG80211_P2P_DEV_IF if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { @@ -2616,7 +3115,8 @@ _wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev, if (cfg->vif_count) { cfg->vif_count--; } - return BCME_OK; + ret = BCME_OK; + goto end; } } #endif /* WL_CFG80211_P2P_DEV_IF */ @@ -2648,6 +3148,13 @@ _wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev, dhd_net_del_flowrings_sta(dhd, wdev->netdev); #endif /* PCIE_FULL_DONGLE */ +#ifdef WL_CELLULAR_CHAN_AVOID + if (wl_iftype == WL_IF_TYPE_AP) { + wl_cellavoid_clear_requested_freq_bands(wdev->netdev, + cfg->cellavoid_info); + } +#endif /* WL_CELLULAR_CHAN_AVOID */ + switch (wl_iftype) { case WL_IF_TYPE_P2P_GO: case WL_IF_TYPE_P2P_GC: @@ -2673,9 +3180,15 @@ exit: } wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr, WL_IF_DELETE_DONE, wl_iftype, wl_mode); + if ( #ifdef WL_NAN - if (!((cfg->nancfg->mac_rand) && (wl_iftype == WL_IF_TYPE_NAN))) + (!((cfg->nancfg->mac_rand) && (wl_iftype == WL_IF_TYPE_NAN))) && #endif /* WL_NAN */ +#if defined(WL_STATIC_IF) && (defined(DHD_USE_RANDMAC) || defined(WL_SOFTAP_RAND)) + /* interface delete is invalid for static interface */ + (!IS_CFG80211_STATIC_IF(cfg, wdev_to_ndev(wdev))) && +#endif /* WL_STATIC_IF && (DHD_USE_RANDMAC || WL_SOFTAP_RAND) */ + (TRUE)) { wl_release_vif_macaddr(cfg, wdev->netdev->dev_addr, wl_iftype); } @@ -2723,6 +3236,7 @@ exit: } } end: + DHD_OS_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub)); return ret; } @@ -3126,12 +3640,6 @@ wl_cfg80211_to_fw_iftype(wl_iftype_t iftype) ret = WL_INTERFACE_TYPE_P2P_GC; break; -#ifdef WLAWDL - case WL_IF_TYPE_AWDL: - ret = WL_INTERFACE_TYPE_AWDL; - break; -#endif /* WLAWDL */ - default: WL_ERR(("Unsupported type:%d \n", iftype)); ret = -EINVAL; @@ -3182,7 +3690,7 @@ wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, if (addr) { ifflags |= WL_INTERFACE_MAC_USE; - if (wl_legacy_chip_check(ndev)) { + if (dhd_conf_legacy_chip_check(cfg->pub)) { iface.flags = ifflags; memcpy(&iface.mac_addr.octet, addr, ETH_ALEN); } @@ -3195,7 +3703,7 @@ wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, #endif /* WLEASYMESH */ /* Pass ver = 0 for fetching the interface_create iovar version */ - if (wl_legacy_chip_check(ndev)) { + if (dhd_conf_legacy_chip_check(cfg->pub)) { bzero(&iface_v0, sizeof(iface_v0)); iface_v0.ver = WL_INTERFACE_CREATE_VER_0; iface_v0.flags = iftype | ifflags; @@ -3231,12 +3739,8 @@ wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, ret = wldev_iovar_getbuf(ndev, "interface_create", &iface_v3, sizeof(wl_interface_create_v3_t), ioctl_buf, sizeof(ioctl_buf), NULL); - } else if ((ret == 0) && - ((*((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_2) || - (*((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_1))) { - /* Legacy firmware could invoke iovar and reply data - * directly. Do not try if return ver is not expected. - * On any other error, attempt with iovar version 2 */ + } else { + /* On any other error, attempt with iovar version 2 */ WL_DBG(("interface_create version 2. get_ver:%d ifflags:0x%x\n", ret, ifflags)); iface.ver = WL_INTERFACE_CREATE_VER_2; iface.iftype = iftype; @@ -3247,10 +3751,6 @@ wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, ret = wldev_iovar_getbuf(ndev, "interface_create", &iface, sizeof(struct wl_interface_create_v2), ioctl_buf, sizeof(ioctl_buf), NULL); - } else { - /* inteface_create version 0, need to add chipnum in bcmdevs_legacy.h - * and add new chip check at wl_legacy_chip_check function */ - WL_DBG(("interface_create version 0. get_ver:%d ifflags:0x%x\n", ret, ifflags)); } if (unlikely(ret)) { @@ -3279,49 +3779,6 @@ exit: return ret; } -#ifdef CUSTOMER_HW6 -#define BCM4355_REV_C1 0x0c -bool -wl_customer6_legacy_chip_check(struct bcm_cfg80211 *cfg, - struct net_device *ndev) -{ - u32 chipnum; - wlc_rev_info_t revinfo; - int ret; - - /* Get the device rev info */ - bzero(&revinfo, sizeof(revinfo)); - ret = wldev_ioctl_get(ndev, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)); - if (ret < 0) { - WL_ERR(("wl_customer6_legacy_chip_check: GET revinfo FAILED. ret:%d\n", ret)); - ASSERT(0); - return false; - } - - chipnum = revinfo.chipnum; - WL_DBG(("wl_customer6_legacy_chip_check: GET_REVINFO device 0x%x, vendor 0x%x," - " chipnum 0x%x\n", - dtoh32(revinfo.deviceid), dtoh32(revinfo.vendorid), dtoh32(chipnum))); - if ( -#ifdef BCM4350_CHIP_ID - (chipnum == BCM4350_CHIP_ID) || -#endif /* BCM4350_CHIP_ID */ -#ifdef BCM4355_CHIP_ID - ((chipnum == BCM4355_CHIP_ID) && (revinfo.chiprev < BCM4355_REV_C1)) || -#endif /* BCM4355_CHIP_ID */ -#ifdef BCM4345_CHIP_ID - (chipnum == BCM4345_CHIP_ID) || -#endif /* BCM4345_CHIP_ID */ - false) { - /* WAR required */ - WL_DBG(("%s: Customer6 legacy chip identified\n", __FUNCTION__)); - return true; - } - - return false; -} -#endif /* CUSTOMER_HW6 */ - s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, @@ -3444,12 +3901,6 @@ wl_iftype_to_mode(wl_iftype_t iftype) mode = WL_MODE_NAN; break; -#ifdef WLAWDL - case WL_IF_TYPE_AWDL: - mode = WL_MODE_AWDL; - break; -#endif /* WLAWDL */ - case WL_IF_TYPE_AIBSS: /* Intentional fall through */ case WL_IF_TYPE_IBSS: @@ -3494,8 +3945,14 @@ cfg80211_to_wl_iftype(uint16 type, uint16 *role, uint16 *mode) *mode = WL_MODE_BSS; break; case NL80211_IFTYPE_MONITOR: +#ifdef WL_CFG80211_MONITOR + *role = WL_IF_TYPE_STA; + *mode = WL_MODE_BSS; + break; +#else WL_ERR(("Unsupported mode \n")); return BCME_UNSUPPORTED; +#endif case NL80211_IFTYPE_ADHOC: *role = WL_IF_TYPE_IBSS; *mode = WL_MODE_IBSS; @@ -3524,17 +3981,6 @@ wl_role_to_cfg80211_type(uint16 role, uint16 *wl_iftype, uint16 *mode) { switch (role) { -#ifdef WLAWDL - case WLC_E_IF_ROLE_AWDL: - /* Intentional fall through - Since there is no - * corresponding iftype in cfg80211 stack, map - * iftype to station. - */ - *wl_iftype = WL_IF_TYPE_AWDL; - *mode = WL_MODE_AWDL; - return NL80211_IFTYPE_STATION; -#endif /* WLAWDL */ - case WLC_E_IF_ROLE_STA: *wl_iftype = WL_IF_TYPE_STA; *mode = WL_MODE_BSS; @@ -3650,11 +4096,9 @@ wl_cfg80211_post_ifcreate(struct net_device *ndev, * bit set. */ primary_ndev = bcmcfg_to_prmry_ndev(cfg); - memcpy(mac_addr, primary_ndev->dev_addr, ETH_ALEN); -#ifndef CUSTOMER_HW6 + DEV_ADDR_GET(primary_ndev, mac_addr); /* For customer6 builds, use primary mac address for virtual interface */ mac_addr[0] |= 0x02; -#endif /* CUSTOMER_HW6 */ addr = mac_addr; } @@ -3727,7 +4171,7 @@ wl_cfg80211_post_ifcreate(struct net_device *ndev, #endif /* WLDWDS */ SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy)); - dev_addr_set(new_ndev, addr); + DEV_ADDR_SET(new_ndev, addr); #ifdef WL_EXT_IAPSTA if (event->role != WLC_E_IF_ROLE_WDS) { wl_ext_iapsta_ifadding(new_ndev, event->ifidx); @@ -3806,11 +4250,6 @@ wl_cfg80211_delete_iface(struct bcm_cfg80211 *cfg, BCM_REFERENCE(i); BCM_REFERENCE(ret); - /* Note: This function will clean up only the network interface and host - * data structures. The firmware interface clean up will happen in the - * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod - * context for the module case). - */ primary_ndev = bcmcfg_to_prmry_ndev(cfg); WL_DBG(("Enter, deleting iftype %s\n", wl_iftype_to_str(sec_data_if_type))); @@ -3966,6 +4405,8 @@ wl_cfg80211_create_iface(struct wiphy *wiphy, s32 ret = BCME_OK; s32 bsscfg_idx = 0; long timeout; + long time_to_wait = MAX_WAIT_TIME; + unsigned long start_wait_time; wl_if_event_info *event = NULL; u8 addr[ETH_ALEN]; struct net_info *iter, *next; @@ -4006,13 +4447,6 @@ wl_cfg80211_create_iface(struct wiphy *wiphy, * Intialize the firmware I/F. */ -#ifdef CUSTOMER_HW6 - if (wl_customer6_legacy_chip_check(cfg, primary_ndev)) { - /* Use bss iovar instead of interface_create iovar */ - ret = BCME_UNSUPPORTED; - } else -#endif /* CUSTOMER_HW6 */ - { ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx, wl_iftype, 0, addr); @@ -4037,15 +4471,29 @@ wl_cfg80211_create_iface(struct wiphy *wiphy, * Wait till the firmware send a confirmation event back. */ WL_DBG(("Wait for the FW I/F Event\n")); - timeout = wait_event_interruptible_timeout(cfg->netif_change_event, - !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME)); - if (timeout <= 0 || cfg->bss_pending_op) { - WL_ERR(("ADD_IF event, didn't come. Return. timeout:%lu bss_pending_op:%d\n", - timeout, cfg->bss_pending_op)); + + while (TRUE) { + start_wait_time = get_jiffies_64(); + timeout = wait_event_interruptible_timeout(cfg->netif_change_event, + !cfg->bss_pending_op, msecs_to_jiffies(time_to_wait)); if (timeout == -ERESTARTSYS) { - WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n")); + WL_ERR(("waitqueue was interrupted by a signal\n")); + time_to_wait -= jiffies_to_msecs(get_jiffies_64() - start_wait_time); + + if (time_to_wait <= 0) { + WL_ERR(("Timed out. time_to_wait:%ld, timeout:%ld\n", + time_to_wait, timeout)); + goto exit; + } + + } else if (timeout <= 0 || cfg->bss_pending_op) { + WL_ERR(("ADD_IF event, didn't come. " + "Return. timeout:%ld bss_pending_op:%d\n", + timeout, cfg->bss_pending_op)); + goto exit; + } else { + break; } - goto exit; } event = &cfg->if_event_info; @@ -4288,8 +4736,13 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("Failed to get bandwidth capability (%d)\n", err)); return err; } +#ifdef WL_6G_320_SUPPORT + chanspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(cfg->channel), + bw_cap, CHSPEC_BAND(cfg->channel), 0); +#else chanspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(cfg->channel), bw_cap, CHSPEC_BAND(cfg->channel)); +#endif /* WL_6G_320_SUPPORT */ } /* @@ -4354,9 +4807,6 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, } wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID); wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN); -#ifdef WLAIBSS - cfg->aibss_txfail_seq = 0; /* initialize the sequence */ -#endif /* WLAIBSS */ #ifdef WL_RELMCAST cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */ #endif /* WL_RELMCAST */ @@ -4533,7 +4983,12 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) WL_DBG(("shared key\n")); break; case NL80211_AUTHTYPE_AUTOMATIC: - val = WL_AUTH_OPEN_SHARED; + if ((sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_WEP40) || + (sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_WEP104)) { + val = WL_AUTH_OPEN_SHARED; + } else { + val = WL_AUTH_OPEN_SYSTEM; + } WL_DBG(("automatic\n")); break; #ifdef WL_FILS @@ -4660,12 +5115,10 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) #ifdef BCMWAPI_WPI case WLAN_CIPHER_SUITE_SMS4: -#ifndef CUSTOMER_HW6 if (!IS_WAPI_VER(sme->crypto.wpa_versions)) { WL_ERR(("Invalid WAPI version %d\n", sme->crypto.wpa_versions)); return BCME_BADARG; } -#endif /* !CUSTOMER_HW6 */ val = pval; err = wl_set_set_wapi_ie(dev, sme); if (unlikely(err)) { @@ -4783,6 +5236,7 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) sec->fw_wsec = wsec_val; return err; } + #ifdef WL_GCMP static s32 wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask) @@ -4812,7 +5266,7 @@ wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask) return BCME_NOMEM; } wsec_info = (wl_wsec_info_t *)buf; - wsec_info->version = WL_WSEC_INFO_VERSION; + wsec_info->version = WL_WSEC_INFO_VERSION_1; wsec_info_tlv = (bcm_xtlv_t *)(buf + OFFSETOF(wl_wsec_info_t, tlvs)); wsec_info->num_tlvs++; @@ -4832,7 +5286,6 @@ wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask) } #endif /* WL_GCMP */ -#ifdef WL_SAE s32 wl_cfg80211_set_wsec_info(struct net_device *dev, uint32 *data, uint16 data_len, int tag) @@ -4849,7 +5302,7 @@ wl_cfg80211_set_wsec_info(struct net_device *dev, uint32 *data, return BCME_ERROR; } - if (data_len > WLC_IOCTL_SMLEN) { + if (data_len > WLC_IOCTL_MEDLEN) { err = BCME_BADLEN; goto exit; } @@ -4869,7 +5322,7 @@ wl_cfg80211_set_wsec_info(struct net_device *dev, uint32 *data, wsec_info = (wl_wsec_info_t *)buf; bzero(wsec_info, sizeof(wl_wsec_info_t) + data_len); - wsec_info->version = WL_WSEC_INFO_VERSION; + wsec_info->version = WL_WSEC_INFO_VERSION_1; bcm_info_tlv = (bcm_xtlv_t *)(buf + OFFSETOF(wl_wsec_info_t, tlvs)); wsec_info->num_tlvs++; @@ -4888,7 +5341,6 @@ exit: MFREE(cfg->osh, buf, sizeof(wl_wsec_info_t) + data_len); return err; } -#endif /* SAE */ #ifdef MFP static s32 @@ -4920,19 +5372,14 @@ wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg, /* Parse the wpa2ie to decode the MFP capablity */ if (((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len, - DOT11_MNG_RSN_ID)) != NULL) && - (wl_cfg80211_get_rsn_capa(wpa2_ie, &rsn_cap) == 0) && rsn_cap) { + DOT11_MNG_RSN_ID)) != NULL) && + (wl_cfg80211_get_rsn_capa(wpa2_ie, &rsn_cap) == 0) && rsn_cap) { WL_DBG(("rsn_cap 0x%x%x\n", rsn_cap[0], rsn_cap[1])); /* Check for MFP cap in the RSN capability field */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) - if (sme->mfp) -#endif - { - if (rsn_cap[0] & RSN_CAP_MFPR) { - mfp = WL_MFP_REQUIRED; - } else if (rsn_cap[0] & RSN_CAP_MFPC) { - mfp = WL_MFP_CAPABLE; - } + if (rsn_cap[0] & RSN_CAP_MFPR) { + mfp = WL_MFP_REQUIRED; + } else if (rsn_cap[0] & RSN_CAP_MFPC) { + mfp = WL_MFP_CAPABLE; } /* * eptr --> end/last byte addr of wpa2_ie @@ -4941,13 +5388,18 @@ wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg, eptr = (const u8*)wpa2_ie + (wpa2_ie->len + TLV_HDR_LEN); /* pointing ptr to the next byte after rns_cap */ ptr = (const u8*)rsn_cap + RSN_CAP_LEN; - if (mfp && (eptr - ptr) >= WPA2_PMKID_COUNT_LEN) { + /* If sme->mfp is not set, the bip iovar will not be fired. */ + if (mfp && +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) + (sme->mfp) && +#endif + (eptr - ptr) >= WPA2_PMKID_COUNT_LEN) { /* pmkid now to point to 1st byte addr of pmkid in wpa2_ie */ pmkid = (const wpa_pmkid_list_t*)ptr; count = pmkid->count.low | (pmkid->count.high << 8); /* ptr now to point to last byte addr of pmkid */ ptr = (const u8*)pmkid + (count * WPA2_PMKID_LEN - + WPA2_PMKID_COUNT_LEN); + + WPA2_PMKID_COUNT_LEN); if ((eptr - ptr) >= WPA_SUITE_LEN) { /* group_mgmt_cs now to point to first byte addr of bip */ group_mgmt_cs = ptr; @@ -5006,20 +5458,6 @@ wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg, if (err != BCME_UNSUPPORTED && err < 0) { WL_ERR(("bip set error (%d)\n", err)); -#ifdef CUSTOMER_HW6 - if (wl_customer6_legacy_chip_check(cfg, - bcmcfg_to_prmry_ndev(cfg))) { - /* Ignore bip error: Some older firmwares doesn't - * support bip iovar/ return BCME_NOTUP while trying - * to set bip from connect context. These firmares - * include bip in RSNIE by default. So its okay to - * ignore the error. - */ - err = BCME_OK; - goto exit; - } else -#endif /* CUSTOMER_HW6 */ - { goto exit; } @@ -5047,7 +5485,7 @@ wl_is_fils_supported(struct net_device *ndev) u8 ioctl_buf[WLC_IOCTL_SMLEN] = {0}; bcm_iov_buf_t *iov_buf = (bcm_iov_buf_t *)ioctl_buf; - iov_buf->version = WL_FILS_IOV_VERSION; + iov_buf->version = WL_FILS_IOV_VERSION_1_1; err = wldev_iovar_getbuf(ndev, "fils", (uint8*)iov_buf, sizeof(bcm_iov_buf_t), iov_buf, WLC_IOCTL_SMLEN, NULL); if (err == BCME_UNSUPPORTED) { @@ -5096,7 +5534,7 @@ wl_set_fils_params(struct net_device *dev, struct cfg80211_connect_params *sme) err = BCME_NOMEM; goto exit; } - iov_buf->version = WL_FILS_IOV_VERSION; + iov_buf->version = WL_FILS_IOV_VERSION_1_1; iov_buf->id = WL_FILS_CMD_ADD_CONNECT_PARAMS; /* check if this should be len w/o headers */ err = bcm_xtlv_buf_init(&tbuf, (uint8*)&iov_buf->data[0], @@ -5130,11 +5568,15 @@ wl_set_fils_params(struct net_device *dev, struct cfg80211_connect_params *sme) goto exit; } } - err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_NEXT_SEQ_NUM, + + if (sme->fils_erp_username_len && sme->fils_erp_realm_len && + sme->fils_erp_rrk_len) { + err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_NEXT_SEQ_NUM, (u8 *)&sme->fils_erp_next_seq_num, sizeof(sme->fils_erp_next_seq_num)); - if (err != BCME_OK) { - WL_ERR(("%s: write xtlv failed\n", __FUNCTION__)); - goto exit; + if (err != BCME_OK) { + WL_ERR(("%s: write xtlv failed\n", __FUNCTION__)); + goto exit; + } } iov_buf->len = bcm_xtlv_buf_len(&tbuf); err = wldev_iovar_setbuf(dev, "fils", iov_buf, iov_buf->len + sizeof(bcm_iov_buf_t) - @@ -5200,8 +5642,178 @@ wl_fils_toggle_roaming(struct net_device *dev, u32 auth_type) #endif /* !WL_FILS_ROAM_OFFLD && WL_FILS */ #endif /* WL_FILS */ +/* Set Passphrase w.r.t SSID */ static s32 -wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) +wl_set_passphrase(struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct net_info *_net_info; + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + wl_config_passphrase_t pp_config; + int err = BCME_OK; + + bzero(&pp_config, sizeof(wl_config_passphrase_t)); + _net_info = wl_get_netinfo_by_netdev(cfg, dev); + + if (_net_info == NULL) { + WL_ERR(("net_info not found for iface %s", dev->name)); + err = BCME_BADARG; + goto done; + } + + /* Backward compat code till wpa_supp RB: 208505 is given to SS */ + if (_net_info->passphrase_len == 0) { + WL_INFORM(("Passphrase not set ..Skip config\n")); + goto done; + } + + if ((sme->ssid_len == 0) || (_net_info->passphrase_len == 0)) { + WL_ERR(("Invalid config ssid_len %zu passphrase_len %d", + sme->ssid_len, _net_info->passphrase_len)); + err = BCME_BADARG; + goto done; + } + + WL_INFORM(("Passphrase config: ssid len %zu passphrase len %d\n", + sme->ssid_len, _net_info->passphrase_len)); + pp_config.ssid = sme->ssid; + pp_config.ssid_len = sme->ssid_len; + pp_config.passphrase = _net_info->passphrase; + pp_config.passphrase_len = _net_info->passphrase_len; + + err = wl_cfg80211_config_passphrase(cfg, dev, &pp_config); + +done: + return err; +} + +static void +wl_prepare_joinpref_tuples(uint8 **pref_buf, u32 akm, u32 pairwise_cipher, u32 mcast_cipher) +{ + u32 val = 0; + + /* Update AKM in tuple */ + val = bcmswap32(akm); + /* memcpy_s return is typecast to void since we have JOIN_PREF_MAX_WPA_TUPLES check */ + (void)memcpy_s(*pref_buf, sizeof(u32), (uint8 *)&val, sizeof(u32)); + *pref_buf += WPA_SUITE_LEN; + /* Set unicast cipher in tuple */ + val = bcmswap32(pairwise_cipher); + (void)memcpy_s(*pref_buf, sizeof(u32), (uint8 *)&val, sizeof(u32)); + *pref_buf += WPA_SUITE_LEN; + /* Set multicast cipher tuple */ + val = bcmswap32(mcast_cipher); + (void)memcpy_s(*pref_buf, sizeof(u32), (uint8 *)&val, sizeof(u32)); + *pref_buf += WPA_SUITE_LEN; + +} + +static s32 +wl_set_multi_akm(struct net_device *dev, struct bcm_cfg80211 *cfg, + struct cfg80211_connect_params *sme, wlcfg_assoc_info_t *assoc_info) +{ + int num_tuples = 0; + char smbuf[WLC_IOCTL_SMLEN]; + uint8 buf[JOIN_PREF_MAX_BUF_SIZE]; + uint8 *pref = buf; + int j; + int total_bytes = 0; + u32 multi_akm = 0; + s32 err = 0; + u32 sae_default_cipher_pairwise = WLAN_CIPHER_SUITE_CCMP; + u32 sae_default_cipher_group = WLAN_CIPHER_SUITE_CCMP; + + /* Check for valid set AKM combinations */ + for (j = 0; j < sme->crypto.n_akm_suites; j++) { + multi_akm |= wl_rsn_akm_wpa_auth_lookup(sme->crypto.akm_suites[j]); + } + + WL_DBG(("SYNA: MultiAKM combination 0x%x\n", multi_akm)); + /* Currently supplicant layer multi-AKM is support is restricted to + * SAE and WPA2PSK for seamless roaming + */ + if (multi_akm == (WPA3_AUTH_SAE_PSK | WPA2_AUTH_PSK) || + multi_akm == (WPA3_AUTH_SAE_PSK | WPA2_AUTH_PSK_SHA256)) { + bool matched = false; + + /* Set auto_wpa_enabled to avoid wpa ie plumb */ + assoc_info->auto_wpa_enabled = TRUE; + /* Update seamless_psk for AKMs needing psk plumb */ + assoc_info->seamless_psk = TRUE; + + if (sme->crypto.cipher_group != sae_default_cipher_group) { + sae_default_cipher_group = sme->crypto.cipher_group; + } + + for (j = 0; j < sme->crypto.n_ciphers_pairwise; j++) { + if (sme->crypto.ciphers_pairwise[j] == + sae_default_cipher_pairwise) { + matched = true; + break; + } + } + + if (!matched) { + sae_default_cipher_pairwise = sme->crypto.ciphers_pairwise[0]; + } + } else { + WL_ERR(("Invalid MultiAKM combination 0x%x\n", multi_akm)); + return -EINVAL; + } + + bzero(buf, sizeof(buf)); + /* Increment the num_tuples value whenever new joinpref tuple is added */ + num_tuples = 4; + + if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) { + *pref++ = WL_JOIN_PREF_WPA; + *pref++ = (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples) + 2; + *pref++ = 0; + *pref++ = (uint8)num_tuples; + total_bytes = JOIN_PREF_WPA_HDR_SIZE + + (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples); + } else { + WL_ERR(("Too many wpa configs for join_pref\n")); + return -EINVAL; + } + + /* Update tuples in akm-ucipher-mcipher format required for join_pref, the order of + * tuple defines the AKM preference, the first addition being the highest preference + */ + WL_DBG(("SYNA: add %d types of key mgmt for SAE/WPA2 roamming\n", num_tuples)); + WL_DBG(("SYNA: MultiAKM SAE: cipher pairwise/group=%08x/%08x\n", + sae_default_cipher_pairwise, sae_default_cipher_group)); + + wl_prepare_joinpref_tuples(&pref, WLAN_AKM_SUITE_SAE, + sae_default_cipher_pairwise, sae_default_cipher_group); + wl_prepare_joinpref_tuples(&pref, WLAN_AKM_SUITE_PSK, + WLAN_CIPHER_SUITE_CCMP, WLAN_CIPHER_SUITE_CCMP); + wl_prepare_joinpref_tuples(&pref, WLAN_AKM_SUITE_PSK_SHA256, + WLAN_CIPHER_SUITE_CCMP, WLAN_CIPHER_SUITE_CCMP); + wl_prepare_joinpref_tuples(&pref, WLAN_AKM_SUITE_PSK, + WLAN_CIPHER_SUITE_CCMP, WLAN_CIPHER_SUITE_TKIP); + +#ifdef MFP + if ((err = wl_cfg80211_set_mfp(cfg, dev, sme)) < 0) { + WL_ERR(("MFP set failed err:%d\n", err)); + return -EINVAL; + } +#endif /* MFP */ + + err = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, + smbuf, sizeof(smbuf), NULL); + if (err) { + WL_ERR(("Failed to set join_pref, error = %d\n", err)); + } else { + WL_MSG(dev->name, "multi_akm=0x%x\n", multi_akm); + } + + return err; +} + +static s32 +wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme, + wlcfg_assoc_info_t *assoc_info) { struct bcm_cfg80211 *cfg = wl_get_cfg(dev); struct wl_security *sec; @@ -5215,137 +5827,136 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) } if (sme->crypto.n_akm_suites) { - err = wldev_iovar_getint(dev, "wpa_auth", &val); - if (unlikely(err)) { - WL_ERR(("could not get wpa_auth (%d)\n", err)); - return err; - } - if (val & (WPA_AUTH_PSK | - WPA_AUTH_UNSPECIFIED)) { - switch (sme->crypto.akm_suites[0]) { - case WLAN_AKM_SUITE_8021X: - val = WPA_AUTH_UNSPECIFIED; - break; - case WLAN_AKM_SUITE_PSK: - val = WPA_AUTH_PSK; - break; - default: - WL_ERR(("invalid akm suite (0x%x)\n", - sme->crypto.akm_suites[0])); - return -EINVAL; + WL_DBG(("No of akms %d 0x%x 0x%x\n", sme->crypto.n_akm_suites, + sme->crypto.akm_suites[0], sme->crypto.akm_suites[1])); + if (sme->crypto.n_akm_suites > 1 && + wl_set_multi_akm(dev, cfg, sme, assoc_info) == 0) { + WL_DBG(("multi-akm\n")); + } else { + err = wl_set_set_cipher(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid ciper\n")); + return err; } - } else if (val & (WPA2_AUTH_PSK | - WPA2_AUTH_UNSPECIFIED)) { - switch (sme->crypto.akm_suites[0]) { + err = wldev_iovar_getint(dev, "wpa_auth", &val); + if (unlikely(err)) { + WL_ERR(("could not get wpa_auth (%d)\n", err)); + return err; + } + if (val & (WPA_AUTH_PSK | + WPA_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + val = WPA_AUTH_UNSPECIFIED; + break; + case WLAN_AKM_SUITE_PSK: + val = WPA_AUTH_PSK; + break; + default: + WL_ERR(("invalid akm suite (0x%x)\n", + sme->crypto.akm_suites[0])); + return -EINVAL; + } + } else if (val & (WPA2_AUTH_PSK | + WPA2_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { #ifdef MFP -#ifdef CUSTOMER_HW6 - case WL_AKM_SUITE_SHA256_1X: - if (wl_customer6_legacy_chip_check(cfg, dev)) { - val = WPA2_AUTH_UNSPECIFIED; - } else { + case WL_AKM_SUITE_SHA256_1X: val = WPA2_AUTH_1X_SHA256; - } - break; - case WL_AKM_SUITE_SHA256_PSK: - if (wl_customer6_legacy_chip_check(cfg, dev)) { - val = WPA2_AUTH_PSK; - } else { + break; + case WL_AKM_SUITE_SHA256_PSK: val = WPA2_AUTH_PSK_SHA256; - } - break; -#endif /* CUSTOMER_HW6 */ - -#ifndef CUSTOMER_HW6 - case WL_AKM_SUITE_SHA256_1X: - val = WPA2_AUTH_1X_SHA256; - break; - case WL_AKM_SUITE_SHA256_PSK: - val = WPA2_AUTH_PSK_SHA256; - break; -#endif /* CUSTOMER_HW6 */ + break; #endif /* MFP */ - case WLAN_AKM_SUITE_8021X: - case WLAN_AKM_SUITE_PSK: + case WLAN_AKM_SUITE_8021X: + case WLAN_AKM_SUITE_PSK: #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X) - case WLAN_AKM_SUITE_FT_8021X: + case WLAN_AKM_SUITE_FT_8021X: #endif #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK) - case WLAN_AKM_SUITE_FT_PSK: + case WLAN_AKM_SUITE_FT_PSK: #endif - case WLAN_AKM_SUITE_FILS_SHA256: - case WLAN_AKM_SUITE_FILS_SHA384: - case WLAN_AKM_SUITE_8021X_SUITE_B: - case WLAN_AKM_SUITE_8021X_SUITE_B_192: + case WLAN_AKM_SUITE_FILS_SHA256: + case WLAN_AKM_SUITE_FILS_SHA384: + case WLAN_AKM_SUITE_8021X_SUITE_B: + case WLAN_AKM_SUITE_8021X_SUITE_B_192: #ifdef WL_OWE - case WLAN_AKM_SUITE_OWE: + case WLAN_AKM_SUITE_OWE: #endif /* WL_OWE */ #if defined(WL_SAE) || defined(WL_CLIENT_SAE) - case WLAN_AKM_SUITE_SAE: + case WLAN_AKM_SUITE_SAE: #endif /* WL_SAE || WL_CLIENT_SAE */ #ifdef WL_SAE_FT - case WLAN_AKM_SUITE_FT_OVER_SAE: + case WLAN_AKM_SUITE_FT_OVER_SAE: #endif /* WL_SAE_FT */ - case WLAN_AKM_SUITE_DPP: - case WLAN_AKM_SUITE_FT_8021X_SHA384: - val = wl_rsn_akm_wpa_auth_lookup(sme->crypto.akm_suites[0]); - break; - case WLAN_AKM_SUITE_FT_FILS_SHA256: - val = WPA2_AUTH_FILS_SHA256 | WPA2_AUTH_FT; - break; - case WLAN_AKM_SUITE_FT_FILS_SHA384: - val = WPA2_AUTH_FILS_SHA384 | WPA2_AUTH_FT; - break; - default: - WL_ERR(("invalid akm suite (0x%x)\n", - sme->crypto.akm_suites[0])); - return -EINVAL; + case WLAN_AKM_SUITE_DPP: + case WLAN_AKM_SUITE_FT_8021X_SHA384: + val = wl_rsn_akm_wpa_auth_lookup(sme->crypto.akm_suites[0]); + break; + case WLAN_AKM_SUITE_FT_FILS_SHA256: + val = WPA2_AUTH_FILS_SHA256 | WPA2_AUTH_FT; + break; + case WLAN_AKM_SUITE_FT_FILS_SHA384: + val = WPA2_AUTH_FILS_SHA384 | WPA2_AUTH_FT; + break; + default: + WL_ERR(("invalid akm suite (0x%x)\n", + sme->crypto.akm_suites[0])); + return -EINVAL; + } } - } #ifdef BCMWAPI_WPI - else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) { - switch (sme->crypto.akm_suites[0]) { - case WLAN_AKM_SUITE_WAPI_CERT: - val = WAPI_AUTH_UNSPECIFIED; - break; - case WLAN_AKM_SUITE_WAPI_PSK: - val = WAPI_AUTH_PSK; - break; - default: - WL_ERR(("invalid akm suite (0x%x)\n", - sme->crypto.akm_suites[0])); - return -EINVAL; + else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_WAPI_CERT: + val = WAPI_AUTH_UNSPECIFIED; + break; + case WLAN_AKM_SUITE_WAPI_PSK: + val = WAPI_AUTH_PSK; + break; + default: + WL_ERR(("invalid akm suite (0x%x)\n", + sme->crypto.akm_suites[0])); + return -EINVAL; + } } - } #endif #ifdef WL_FILS #if !defined(WL_FILS_ROAM_OFFLD) - err = wl_fils_toggle_roaming(dev, val); - if (unlikely(err)) { - return err; - } + err = wl_fils_toggle_roaming(dev, val); + if (unlikely(err)) { + return err; + } #endif /* !WL_FILS_ROAM_OFFLD */ #endif /* !WL_FILS */ #ifdef MFP - if ((err = wl_cfg80211_set_mfp(cfg, dev, sme)) < 0) { - WL_ERR(("MFP set failed err:%d\n", err)); - return -EINVAL; - } + if ((err = wl_cfg80211_set_mfp(cfg, dev, sme)) < 0) { + WL_ERR(("MFP set failed err:%d\n", err)); + return -EINVAL; + } #endif /* MFP */ - WL_DBG_MEM(("[%s] wl wpa_auth to 0x%x\n", dev->name, val)); - err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); - if (unlikely(err)) { - WL_ERR(("could not set wpa_auth (0x%x)\n", err)); - return err; + WL_DBG_MEM(("[%s] wl wpa_auth to 0x%x\n", dev->name, val)); + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); + if (unlikely(err)) { + WL_ERR(("could not set wpa_auth (0x%x)\n", err)); + return err; + } } } sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - sec->wpa_auth = sme->crypto.akm_suites[0]; - sec->fw_wpa_auth = val; + if (assoc_info->auto_wpa_enabled == TRUE) { + /* Set to value 0 indicating multi-akm configuration */ + sec->wpa_auth = 0; + sec->fw_wpa_auth = 0; + } else { + sec->wpa_auth = sme->crypto.akm_suites[0]; + sec->fw_wpa_auth = val; + } return err; } @@ -5356,10 +5967,11 @@ wl_set_set_sharedkey(struct net_device *dev, { struct bcm_cfg80211 *cfg = wl_get_cfg(dev); struct wl_security *sec; - struct wl_wsec_key key; + struct wl_wsec_key key = {0}; s32 val; s32 err = 0; s32 bssidx; + uint8 iov_buf[WLC_IOCTL_SMLEN] = {0}; if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr)); @@ -5386,17 +5998,22 @@ wl_set_set_sharedkey(struct net_device *dev, key.index = (u32) sme->key_idx; if (unlikely(key.len > sizeof(key.data))) { WL_ERR(("Too long key length (%u)\n", key.len)); - return -EINVAL; + err = -EINVAL; + goto exit; + } + if (memcpy_s(key.data, sizeof(key.data), sme->key, + key.len) != BCME_OK) { + err = -EINVAL; + goto exit; } - memcpy(key.data, sme->key, key.len); - key.flags = WL_PRIMARY_KEY; if ((sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP40) || (sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP104)) { key.algo = wl_rsn_cipher_wsec_key_algo_lookup(sec->cipher_pairwise); } else { WL_ERR(("Invalid algorithm (%d)\n", sme->crypto.ciphers_pairwise[0])); - return -EINVAL; + err = -EINVAL; + goto exit; } /* Set the new key/index */ WL_DBG(("key length (%d) key index (%d) algo (%d)\n", @@ -5404,10 +6021,11 @@ wl_set_set_sharedkey(struct net_device *dev, WL_DBG(("key \"%s\"\n", key.data)); swap_key_from_BE(&key); err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + iov_buf, WLC_IOCTL_SMLEN, bssidx, NULL); if (unlikely(err)) { WL_ERR(("WLC_SET_KEY error (%d)\n", err)); - return err; + err = -EINVAL; + goto exit; } WL_INFORM_MEM(("key applied to fw\n")); if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { @@ -5416,15 +6034,20 @@ wl_set_set_sharedkey(struct net_device *dev, err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); if (unlikely(err)) { WL_ERR(("set auth failed (%d)\n", err)); - return err; + err = -EINVAL; + goto exit; } } } } +exit: + bzero(&key, sizeof(key)); + bzero(iov_buf, sizeof(iov_buf)); + return err; } -#if defined (CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX) +#if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX) static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd) { u32 chanspec = 0; @@ -5446,6 +6069,9 @@ int wl_cfg80211_cleanup_mismatch_status(struct net_device *dev, struct bcm_cfg80 scb_val_t scbval; int err = TRUE; int wait_cnt; +#ifdef WL_CFGVENDOR_CUST_ADVLOG + scb_val_t scb_rssi; +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ if (disassociate) { #ifdef BCMDONGLEHOST @@ -5459,6 +6085,16 @@ int wl_cfg80211_cleanup_mismatch_status(struct net_device *dev, struct bcm_cfg80 scbval.val = DOT11_RC_DISASSOC_LEAVING; scbval.val = htod32(scbval.val); +#ifdef WL_CFGVENDOR_CUST_ADVLOG + /* get rssi before sending DISASSOC to avoid getting zero */ + bzero(&scb_rssi, sizeof(scb_val_t)); + err = wldev_get_rssi(dev, &scb_rssi); + if (unlikely(err)) { + WL_ERR(("get_rssi error (%d)\n", err)); + scb_rssi.val = WLC_RSSI_INVALID; + } +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ + err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); if (unlikely(err)) { @@ -5467,6 +6103,11 @@ int wl_cfg80211_cleanup_mismatch_status(struct net_device *dev, struct bcm_cfg80 return err; } wait_cnt = 500/10; + +#ifdef WL_CFGVENDOR_CUST_ADVLOG + wl_cfgvendor_advlog_disassoc_tx(cfg, dev, DOT11_RC_DISASSOC_LEAVING, + scb_rssi.val); +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ } else { wait_cnt = 200/10; WL_ERR(("Waiting for previous DISCONNECTING status!\n")); @@ -5533,7 +6174,7 @@ wl_fils_add_hlp_container(struct bcm_cfg80211 *cfg, struct net_device *dev, memcpy(((bcm_xtlv_t*)pxtlv)->data, hlp_ie, ((bcm_xtlv_t*)pxtlv)->len); - iov_buf->version = WL_FILS_IOV_VERSION; + iov_buf->version = WL_FILS_IOV_VERSION_1_1; iov_buf->id = WL_FILS_CMD_ADD_HLP_IE; iov_buf->len = ((sizeof(bcm_xtlv_t)-1) + ((bcm_xtlv_t*)pxtlv)->len); @@ -5609,7 +6250,7 @@ wl_config_roam_env_detection(struct bcm_cfg80211 *cfg, struct net_device *dev) s32 roam_trigger[2] = {0, 0}; s32 err = BCME_OK; - if (dhdp->roam_env_detection && (dev == bcmcfg_to_prmry_ndev(cfg))) { + if (dhdp->roam_env_detection && (IS_STA_IFACE(ndev_to_wdev(dev)))) { bool is_roamtrig_reset = TRUE; bool is_roam_env_ok = (wldev_iovar_setint(dev, "roam_env_detection", AP_ENV_DETECT_NOT_USED) == BCME_OK); @@ -5620,7 +6261,8 @@ wl_config_roam_env_detection(struct bcm_cfg80211 *cfg, struct net_device *dev) sizeof(roam_trigger)) == BCME_OK) && (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER-10); #endif /* SKIP_ROAM_TRIGGER_RESET */ - if (is_roamtrig_reset && is_roam_env_ok) { + if (is_roamtrig_reset && is_roam_env_ok && + (dhdp->wbtext_policy != WL_BSSTRANS_POLICY_PRODUCT_WBTEXT)) { roam_trigger[0] = WL_AUTO_ROAM_TRIGGER; roam_trigger[1] = WLC_BAND_ALL; err = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, @@ -5680,7 +6322,7 @@ wl_do_preassoc_ops(struct bcm_cfg80211 *cfg, maxrxpktglom = 0; #endif -#if defined (ROAM_ENABLE) && defined (ROAM_AP_ENV_DETECTION) +#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) if (wl_config_roam_env_detection(cfg, dev) != BCME_OK) { return BCME_ERROR; } @@ -5711,16 +6353,23 @@ wl_do_preassoc_ops(struct bcm_cfg80211 *cfg, if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) { prhex(NULL, sme->ie, sme->ie_len); } +#ifdef WL_DUAL_APSTA + wl_cfgvif_roam_config(cfg, dev, ROAM_CONF_ASSOC_REQ); +#endif /* WL_DUAL_APSTA */ + /* Connection attempted via linux-wireless */ wl_set_drv_status(cfg, CFG80211_CONNECT, dev); return BCME_OK; } static s32 -wl_config_assoc_security(struct bcm_cfg80211 *cfg, - struct net_device *dev, struct cfg80211_connect_params *sme) +wl_config_assoc_security(struct bcm_cfg80211 *cfg, struct net_device *dev, + struct cfg80211_connect_params *sme, wlcfg_assoc_info_t *assoc_info) { s32 err = BCME_OK; + struct wl_security *sec; + + BCM_REFERENCE(sec); err = wl_set_wpa_version(dev, sme); if (unlikely(err)) { @@ -5743,19 +6392,34 @@ wl_config_assoc_security(struct bcm_cfg80211 *cfg, } } #endif /* WL_FILS */ - - err = wl_set_set_cipher(dev, sme); - if (unlikely(err)) { - WL_ERR(("Invalid ciper\n")); - goto exit; + /* Avoid cipher setting for multi-AKM, cipher combinations for multi-AKM predefined */ + if (!(sme->crypto.n_akm_suites > 1)) { + err = wl_set_set_cipher(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid ciper\n")); + goto exit; + } } - err = wl_set_key_mgmt(dev, sme); + err = wl_set_key_mgmt(dev, sme, assoc_info); if (unlikely(err)) { WL_ERR(("Invalid key mgmt\n")); goto exit; } + BCM_REFERENCE(wl_set_passphrase); +#ifdef WL_SAE + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + if ((sec->fw_wpa_auth & WPA3_AUTH_SAE_PSK) || + (assoc_info->seamless_psk == TRUE)) { + err = wl_set_passphrase(dev, sme); + if (unlikely(err)) { + WL_ERR(("Unable to set passphrase\n")); + goto exit; + } + } +#endif /* WL_SAE */ + err = wl_set_set_sharedkey(dev, sme); if (unlikely(err)) { WL_ERR(("Invalid shared key\n")); @@ -5770,6 +6434,33 @@ wl_config_assoc_security(struct bcm_cfg80211 *cfg, } #endif /* WL_FILS */ +#ifdef WL_PSK_OFFLOAD + /* Add pmk for psk in connect path */ + if (sme->crypto.psk) { + wsec_pmk_t pmk = {0}; + + pmk.key_len = WL_SUPP_PMK_LEN; + if (pmk.key_len > sizeof(pmk.key)) { + err = -EINVAL; + goto exit; + } + pmk.flags = 0; + err = memcpy_s(&pmk.key, sizeof(pmk.key), sme->crypto.psk, pmk.key_len); + if (err) { + err = -EINVAL; + goto exit; + } + + err = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk)); + if (err) { + WL_ERR(("pmk set with WLC_SET_WSEC_PMK failed, error:%d\n", err)); + goto exit; + } else { + WL_INFORM(("pmk added succesfully\n")); + } + } +#endif /* WL_PSK_OFFLOAD */ + exit: return err; } @@ -5784,11 +6475,56 @@ wl_config_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *dev, u32 wpaie_len; s32 err; s32 bssidx = info->bssidx; + u8 *p2p_ie = NULL; + u16 p2p_ie_len = 0; + bcm_tlv_t *ie = NULL; + +#if defined(DHD_DSCP_POLICY) + /* Add WFA capabilities vendor-specific IE in the assoc request */ + if ((err = dhd_dscp_policy_set_vndr_ie(cfg, dev, bssidx)) != BCME_OK) { + WL_ERR(("Failed to set vendor-specific WFA Cap IE in assoc request: %d\n", err)); + /* continue */ + } +#endif /* DHD_DSCP_POLICY */ /* configure all vendor and extended vendor IEs */ wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx, VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); + /* supplicant sometimes reuses scan from another interface and triggers p2p_connect + * and that can cause regular scans to be skipped on actual connect interface. + * Because of this, the vendor IEs may not be applied for Probe request that are + * to be sent in the join scan. Invoke API for applying vendor IEs for probe req. + */ + if (IS_P2P_GC(dev->ieee80211_ptr)) { + wl_get_p2p_disc_ies(cfg, dev->ieee80211_ptr, &p2p_ie, &p2p_ie_len); + if (!p2p_ie_len && cfg->p2p_wdev) { + WL_DBG_MEM(("No IEs present in GC I/F. Fetch from P2P Disc.\n")); + wl_get_p2p_disc_ies(cfg, cfg->p2p_wdev, &p2p_ie, &p2p_ie_len); + } + + /* If IEs are not found from discovery I/F, look for p2p IE in the assoc req */ + if (p2p_ie_len == 0) { + WL_DBG_MEM(("no p2p IEs. fetch from assoc req\n")); + ie = (bcm_tlv_t *)wl_cfgp2p_find_p2pie((const u8 *)sme->ie, sme->ie_len); + if (ie) { + p2p_ie = (u8 *)ie; + p2p_ie_len = ie->len + BCM_TLV_HDR_SIZE; + } else { + WL_ERR(("no p2p IE found in assoc req\n")); + } + } + + /* Apply P2P IEs if found */ + if (p2p_ie && !wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), + bssidx, VNDR_IE_PRBREQ_FLAG, + p2p_ie, p2p_ie_len)) { + WL_DBG_MEM(("P2P IE config done for connect. len:%d\n", p2p_ie_len)); + } else { + WL_ERR(("P2P IE set failed for GC I/F. p2p_ie_len=%d\n", p2p_ie_len)); + } + } + /* Find the RSNXE_IE and plumb */ if ((err = wl_cfg80211_config_rsnxe_ie(cfg, dev, (const u8*)sme->ie, sme->ie_len)) < 0) { @@ -5817,10 +6553,13 @@ wl_config_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *dev, wpaie_len = 0; } - err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("wpaie set error (%d)\n", err)); + /* In case of auto_wpa FW prepares the wpaie */ + if (info->auto_wpa_enabled == FALSE) { + err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (unlikely(err)) { + WL_ERR(("wpaie set error (%d)\n", err)); + } } return err; @@ -5845,7 +6584,7 @@ wl_cfg80211_config_rsnxe_ie(struct bcm_cfg80211 *cfg, struct net_device *dev, err = wldev_iovar_setbuf(dev, "rsnxe", ie, ie_len, smbuf, sizeof(smbuf), NULL); if (!err) { - WL_DBG(("Configured RSNXE IE\n")); + WL_DBG(("Configured RSNXE IE len %d\n", ie_len)); } else if (err == BCME_UNSUPPORTED) { WL_DBG(("FW does not support rsnxe iovar\n")); err = BCME_OK; @@ -5892,8 +6631,8 @@ wl_fillup_assoc_params_v1(struct bcm_cfg80211 *cfg, struct net_device *dev, ext_join_params->ssid.SSID_len = htod32(info->ssid_len); /* Use increased dwell for targeted join case to take care of noisy env */ - join_scan_active_time = info->targeted_join ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : - WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS; + join_scan_active_time = (info->targeted_join && !info->bssid_hint) ? + WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS; ext_join_params->scan.active_time = chan_cnt ? join_scan_active_time : -1; ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1; /* Set up join scan parameters */ @@ -5906,6 +6645,9 @@ wl_fillup_assoc_params_v1(struct bcm_cfg80211 *cfg, struct net_device *dev, (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1; ext_join_params->scan.home_time = -1; + WL_DBG(("active_time:%d nprobes:%d\n", join_scan_active_time, + ext_join_params->scan.nprobes)); + (void)memcpy_s(&ext_join_params->assoc.bssid, ETH_ALEN, info->bssid, ETH_ALEN); ext_join_params->assoc.chanspec_num = chan_cnt; @@ -5948,8 +6690,8 @@ wl_fillup_assoc_params_v0(struct bcm_cfg80211 *cfg, struct net_device *dev, ext_join_params->ssid.SSID_len = htod32(info->ssid_len); /* Use increased dwell for targeted join case to take care of noisy env */ - join_scan_active_time = info->targeted_join ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : - WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS; + join_scan_active_time = (info->targeted_join && !info->bssid_hint) ? + WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS; ext_join_params->scan.active_time = chan_cnt ? join_scan_active_time : -1; ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1; /* Set up join scan parameters */ @@ -5987,14 +6729,63 @@ wl_config_assoc_params(struct bcm_cfg80211 *cfg, struct net_device *dev, return ret; } +static s32 +wl_ext_get_scan_rssi(struct bcm_cfg80211 *cfg, u8 *bssid) +{ + wl_scan_results_v109_t *bss_list; + wl_bss_info_v109_t *bi = NULL; + s32 i, rssi = 0; + + mutex_lock(&cfg->scan_sync); + bss_list = cfg->bss_list; + bi = next_bss(bss_list, bi); + for_each_bss(bss_list, bi, i) { + if (!memcmp(&bi->BSSID, bssid, ETHER_ADDR_LEN)) + rssi = dtoh32(bi->RSSI); + } + mutex_unlock(&cfg->scan_sync); + + return rssi; +} + +#ifdef CONNECT_INFO_WAR +static chanspec_t +wl_ext_get_scan_chanspec(struct bcm_cfg80211 *cfg, u8 *bssid) +{ + wl_scan_results_v109_t *bss_list; + wl_bss_info_v109_t *bi = NULL; + chanspec_t chanspec = 0; + s32 i; + + mutex_lock(&cfg->scan_sync); + bss_list = cfg->bss_list; + bi = next_bss(bss_list, bi); + for_each_bss(bss_list, bi, i) { + if (!memcmp(&bi->BSSID, bssid, ETHER_ADDR_LEN)) + chanspec = wl_chspec_driver_to_host(bi->chanspec); + } + mutex_unlock(&cfg->scan_sync); + + return chanspec; +} +#endif /* CONNECT_INFO_WAR */ + static s32 wl_handle_assoc_hints(struct bcm_cfg80211 *cfg, struct net_device *dev, struct cfg80211_connect_params *sme, wlcfg_assoc_info_t *info) { + +#if defined(DHD_DSCP_POLICY) + int ret_val; +#endif /* defeind(DHD_DSCP_POLICY) */ + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) bool skip_hints = false; #endif /* KERNEL >= 3.15 */ - chanspec_t chspec; +#ifdef CONNECT_INFO_WAR + chanspec_t scan_chspec; +#endif /* CONNECT_INFO_WAR */ + chanspec_t chspec = 0; if (!sme || !info) { WL_ERR(("wrong args\n")); @@ -6019,14 +6810,24 @@ wl_handle_assoc_hints(struct bcm_cfg80211 *cfg, struct net_device *dev, /* Use user space requested BSSID and channel */ info->targeted_join = true; (void)memcpy_s(info->bssid, ETH_ALEN, sme->bssid, ETH_ALEN); - if (sme->channel && ((chspec = - wl_freq_to_chanspec(sme->channel->center_freq)) != INVCHANSPEC)) { + if (sme->channel) { + chspec = wl_freq_to_chanspec(sme->channel->center_freq); + } +#ifdef CONNECT_INFO_WAR + scan_chspec = wl_ext_get_scan_chanspec(cfg, info->bssid); + if (scan_chspec && (scan_chspec != chspec)) { + WL_MSG(dev->name, "replace chspec 0x%x to previous scan chanspec 0x%x\n", + chspec, scan_chspec); + chspec = scan_chspec; + } +#endif /* CONNECT_INFO_WAR */ + if (chspec && (chspec != INVCHANSPEC)) { info->chan_cnt = 1; info->chanspecs[0] = chspec; - /* Skip p2p connection on 6G */ #ifdef WL_P2P_6G if (!(cfg->p2p_6g_enabled)) { #endif /* WL_P2P_6G */ + /* Skip p2p connection on 6G */ if (IS_P2P_GC(dev->ieee80211_ptr) && (CHSPEC_IS6G(chspec))) { WL_ERR(("P2P connection not allowed on 6G\n")); return -ENOTSUPP; @@ -6052,27 +6853,29 @@ wl_handle_assoc_hints(struct bcm_cfg80211 *cfg, struct net_device *dev, WL_DBG(("fw_ap_select:%d skip_hints:%d\n", fw_ap_select, skip_hints)); #endif /* WL_SKIP_CONNECT_HINTS */ + if (IS_P2P_GC(dev->ieee80211_ptr)) { + skip_hints = false; + } + /* Use bssid_hint if hints are allowed and if its unicast addr */ if (!skip_hints && sme->bssid_hint && !ETHER_ISBCAST(sme->bssid_hint)) { WL_INFORM_MEM(("bssid_hint "MACDBG" \n", MAC2STRDBG(sme->bssid_hint))); info->targeted_join = true; - if (cfg->join_iovar_ver) { + if (cfg->join_iovar_ver && IS_STA_IFACE(ndev_to_wdev(dev))) { /* Firmware supports bssid_hint feature */ info->bssid_hint = true; } (void)memcpy_s(info->bssid, ETH_ALEN, sme->bssid_hint, ETH_ALEN); -#ifndef WL_FORCE_RCC_LIST - /* Use channel hint only for target bssid join case. In other - * cases, use RCC or full scan to find better APs. - */ - if (sme->channel_hint && ((chspec = wl_freq_to_chanspec( - sme->channel_hint->center_freq)) != INVCHANSPEC)) { - info->chan_cnt = 1; - info->chanspecs[0] = chspec; - WL_INFORM_MEM(("channel_hint: chspec(%x)\n", chspec)); - } -#endif /* !WL_FORCE_RCC_LIST */ } +#ifndef WL_FORCE_RCC_LIST + /* Store channel hint. If RCC is used, it will append this list */ + if (sme->channel_hint && ((chspec = wl_freq_to_chanspec( + sme->channel_hint->center_freq)) != INVCHANSPEC)) { + info->chan_cnt = 1; + info->chanspecs[0] = chspec; + WL_INFORM_MEM(("channel_hint: chspec(%x)\n", chspec)); + } +#endif /* !WL_FORCE_RCC_LIST */ } #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */ @@ -6082,9 +6885,86 @@ wl_handle_assoc_hints(struct bcm_cfg80211 *cfg, struct net_device *dev, } WL_DBG(("targeted_join:%d chan_cnt:%d\n", info->targeted_join, info->chan_cnt)); + +#if defined(DHD_DSCP_POLICY) + ret_val = wl_cfg80211_is_wfa_cap_ie(info, cfg, sme->bssid_hint); + if (ret_val != BCME_OK) { + WL_ERR(("Unable to find the WFA Capabilities IE in the " + "beacon/proberesp, ret_val = %d\n", ret_val)); + } +#endif /* defined(DHD_DSCP_POLICY) */ + return 0; } +#if defined(DHD_DSCP_POLICY) + +/* + * Based on the bssid_hint, gets the bss and its ies. These ies are further searched for + * WFA capabilities vendor-specific IE. Returns BCME_OK on success (i.e., WFA cap ie is found) + * or appropriate error code on failures. + */ +static int +wl_cfg80211_is_wfa_cap_ie(wlcfg_assoc_info_t *assoc_info, struct bcm_cfg80211 *cfg, + const u8 *bssid_hint) +{ + const u8 *parse = NULL; + const struct cfg80211_bss_ies *ies; + u32 len; + struct cfg80211_bss *bss; + int ret_val = BCME_ERROR; + struct wiphy *wiphy; + + /* Look for WFA capabilities IE in the cached IEs. + * + * TODO: The best way to include the WFA capabilities IE in the assoc request is to do + * in the firmware. In most cases, FW decides which AP to join and its capabilities. + * Based on that, FW can include the vendor-specific WFA capabilities IE only if the AP + * supports the DSCP policy feature. + * + * For now, use the bssid_hint. + * The bssid_hint is interpreted differently beween different vendors. + * For example, bssid_hint is preferred for Samsung where as it is ignored in the case of + * Google and FW selects the AP. + */ + + if (assoc_info->targeted_join == false) { + goto done; + } + + wiphy = bcmcfg_to_wiphy(cfg); + + if (wiphy == NULL || bssid_hint == NULL) { + WL_ERR(("*** bssid_hint is NULL")); + goto done; + } + + bss = CFG80211_GET_BSS(wiphy, NULL, bssid_hint, 0, 0); + if (!bss) { + WL_ERR(("Unable to find AP in the cache")); + goto done; + } + + if (rcu_access_pointer(bss->ies)) { + ies = rcu_access_pointer(bss->ies); + parse = ies->data; + len = ies->len; + } else { + WL_ERR(("ies is NULL")); + goto done; + } + + if (wl_dbg_level & WL_DBG_DBG) { + WL_INFORM_MEM(("*** bssid_hint "MACDBG" \n", MAC2STRDBG(bssid_hint))); + } + + /* Check to see if the WFA Capabilities IE is present and handles it accordingly */ + ret_val = dhd_dscp_process_wfa_cap_ie(cfg, parse, len); +done: + return ret_val; +} +#endif /* defined(DHD_DSCP_POLICY) */ + static s32 wl_sync_fw_assoc_states(struct bcm_cfg80211 *cfg, struct net_device *dev, wlcfg_assoc_info_t *info) @@ -6092,7 +6972,11 @@ wl_sync_fw_assoc_states(struct bcm_cfg80211 *cfg, s32 err = BCME_OK; u8 bssid[ETH_ALEN]; - if (wl_get_drv_status(cfg, CONNECTED, dev) && wl_reassoc_support) { + if (wl_get_drv_status(cfg, CONNECTED, dev) && wl_reassoc_support +#ifdef WL_EXT_IAPSTA + && wl_ext_sta_connected(dev) +#endif /* WL_EXT_IAPSTA */ + ) { /* ROAM case */ info->reassoc = true; } else { @@ -6169,25 +7053,6 @@ wl_pkt_mon_start(struct bcm_cfg80211 *cfg, struct net_device *dev) } #endif /* DBG_PKT_MON && BCMDONGLEHOST */ -static s32 -wl_ext_get_rssi(struct bcm_cfg80211 *cfg, u8 *bssid) -{ - wl_scan_results_t *bss_list; - wl_bss_info_t *bi = NULL; - s32 i, rssi = 0; - - mutex_lock(&cfg->scan_sync); - bss_list = cfg->bss_list; - bi = next_bss(bss_list, bi); - for_each_bss(bss_list, bi, i) { - if (!memcmp(&bi->BSSID, bssid, ETHER_ADDR_LEN)) - rssi = dtoh32(bi->RSSI); - } - mutex_unlock(&cfg->scan_sync); - - return rssi; -} - void wl_conn_debug_info(struct bcm_cfg80211 *cfg, struct net_device *dev, wlcfg_assoc_info_t *info) { @@ -6204,7 +7069,7 @@ wl_conn_debug_info(struct bcm_cfg80211 *cfg, struct net_device *dev, wlcfg_assoc return; } - target_rssi = wl_ext_get_rssi(cfg, info->bssid); + target_rssi = wl_ext_get_scan_rssi(cfg, info->bssid); wl_ext_get_sec(dev, 0, sec_info, sizeof(sec_info), TRUE); if (info->reassoc) { memset(&scb_val, 0, sizeof(scb_val_t)); @@ -6300,7 +7165,9 @@ wl_handle_reassoc(struct bcm_cfg80211 *cfg, struct net_device *dev, size_t reassoc_params_size; u32 chan_cnt = info->chan_cnt; chanspec_t *chanspecs = info->chanspecs; +#ifdef WL_EXT_IAPSTA u32 chanspec = info->chanspecs[0]; +#endif if (!cfg->join_iovar_ver) { reassoc_params_size = WL_ASSOC_PARAMS_FIXED_SIZE + @@ -6344,6 +7211,30 @@ fail: return err; } +#ifdef WL_DUAL_STA +static bool +wl_is_macaddr_in_use(struct bcm_cfg80211 *cfg, struct net_device *dev) +{ + struct net_info *iter, *next; + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + for_each_ndev(cfg, iter, next) { + GCC_DIAGNOSTIC_POP(); + /* Check against wl_iftype_t type */ + if ((iter->wdev) && (iter->iftype == WL_IF_TYPE_STA)) { + struct net_device *ndev = iter->wdev->netdev; + if (ndev && wl_get_drv_status(cfg, CONNECTED, ndev) && (ndev != dev)) { + if (memcmp(dev->dev_addr, ndev->dev_addr, ETHER_ADDR_LEN) == 0) { + return true; + } + } + } + } + + return false; +} +#endif /* WL_DUAL_STA */ + static s32 wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) @@ -6351,6 +7242,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, s32 err = BCME_OK; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); wlcfg_assoc_info_t assoc_info; + chanspec_t scan_chspec = 1; WL_DBG(("Enter len=%zu\n", sme->ie_len)); RETURN_EIO_IF_NOT_UP(cfg); @@ -6358,6 +7250,14 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, /* syncronize the connect states */ mutex_lock(&cfg->connect_sync); +#ifdef WL_DUAL_STA + if (wl_is_macaddr_in_use(cfg, dev)) { + WL_ERR(("Blocking connect request as another STA interface" + " with same MAC address already connected\n")); + err = -EINVAL; + goto fail; + } +#endif /* WL_DUAL_STA */ bzero(&assoc_info, sizeof(wlcfg_assoc_info_t)); if ((assoc_info.bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { WL_ERR(("Find wlan index from wdev(%p) failed\n", dev->ieee80211_ptr)); @@ -6381,22 +7281,41 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("fw assoc sync failed\n")); } +#ifdef DBG_PKT_MON + /* Start pkt monitor here to avoid probe auth and assoc lost */ + if (dev == bcmcfg_to_prmry_ndev(cfg)) { + wl_pkt_mon_start(cfg, dev); + } +#endif /* DBG_PKT_MON */ if (assoc_info.reassoc) { /* Handle roam to same ESS */ +#ifdef DHD_LOSSLESS_ROAMING + wl_ext_send_event_msg(dev, WLC_E_ROAM_PREP, WLC_E_STATUS_SUCCESS, WLC_E_REASON_LOW_RSSI); +#endif if ((err = wl_handle_reassoc(cfg, dev, &assoc_info)) != BCME_OK) { goto fail; } } else { - err = wl_config_assoc_security(cfg, dev, sme); + err = wl_config_assoc_security(cfg, dev, sme, &assoc_info); if (unlikely(err)) { WL_ERR(("config assoc security failed\n")); goto fail; } - err = wl_get_assoc_channels(cfg, dev, &assoc_info); - if (unlikely(err)) { - WL_ERR(("get assoc channels failed\n")); - goto fail; +#ifdef CONNECT_INFO_WAR + if (!ETHER_ISBCAST(assoc_info.bssid)) { + scan_chspec = wl_ext_get_scan_chanspec(cfg, assoc_info.bssid); + } + if(!scan_chspec) + WL_MSG(dev->name, "BSSID %pM not in previous scan results\n", + assoc_info.bssid); +#endif /* CONNECT_INFO_WAR */ + if (scan_chspec) { + err = wl_get_assoc_channels(cfg, dev, &assoc_info); + if (unlikely(err)) { + WL_ERR(("get assoc channels failed\n")); + goto fail; + } } err = wl_config_assoc_ies(cfg, dev, sme, &assoc_info); @@ -6408,6 +7327,9 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, if ((err = wl_handle_join(cfg, dev, &assoc_info)) != BCME_OK) { goto fail; } +#ifdef WL_CFGVENDOR_CUST_ADVLOG + wl_cfgvendor_custom_advlog_conn(cfg, dev, sme); +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ } /* Store the minium idx expected */ cfg->eidx.min_connect_idx = cfg->eidx.enqd; @@ -6415,6 +7337,10 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, fail: if (unlikely(err)) { WL_ERR(("connect error (%d)\n", err)); + if (err == BCME_NOTUP) { + WL_ERR(("FW not up, change to linux error code\n")); + err = -EAGAIN; + } wl_clr_drv_status(cfg, CONNECTING, dev); CLR_TS(cfg, conn_start); /* Flush fw logs */ @@ -6424,10 +7350,7 @@ fail: wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false); #endif /* WLTDLS */ } else { -#ifdef DBG_PKT_MON - /* start packet log in adv to ensure that EAPOL msgs aren't missed */ - wl_pkt_mon_start(cfg, dev); -#endif /* DBG_PKT_MON */ + } #ifdef WL_EXT_IAPSTA if (!err) @@ -6490,7 +7413,9 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, #ifdef BCMDONGLEHOST dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); #endif /* BCMDONGLEHOST */ - +#ifdef WL_CFGVENDOR_CUST_ADVLOG + scb_val_t scb_rssi; +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ RETURN_EIO_IF_NOT_UP(cfg); #ifdef BCMDONGLEHOST @@ -6537,7 +7462,11 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, WL_TRACE_HW4(("Aborting the scan! \n")); wl_cfgscan_cancel_scan(cfg); } - if (conn_in_progress || connected || wdev->ssid_len) { + if (conn_in_progress || connected || + WDEV_CLIENT(wdev, ssid_len)) { +#ifdef WL_EXT_IAPSTA + wl_ext_in4way_sync(dev, 0, WL_EXT_STATUS_PRE_DISCONNECTING, NULL); +#endif scbval.val = reason_code; memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); scbval.val = htod32(scbval.val); @@ -6546,6 +7475,18 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, in all exit paths */ wl_set_drv_status(cfg, DISCONNECTING, dev); + /* clear connecting state */ + wl_clr_drv_status(cfg, CONNECTING, dev); + +#ifdef WL_CFGVENDOR_CUST_ADVLOG + /* get rssi before sending DISASSOC to avoid getting zero */ + bzero(&scb_rssi, sizeof(scb_val_t)); + err = wldev_get_rssi(dev, &scb_rssi); + if (unlikely(err)) { + WL_ERR(("get_rssi error (%d)\n", err)); + scb_rssi.val = WLC_RSSI_INVALID; + } +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); if (unlikely(err)) { @@ -6553,10 +7494,15 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("error (%d)\n", err)); goto exit; } +#ifdef WL_CFGVENDOR_CUST_ADVLOG + wl_cfgvendor_advlog_disassoc_tx(cfg, dev, + reason_code, scb_rssi.val); +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ #ifdef WL_EXT_IAPSTA wl_ext_in4way_sync(dev, STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED, WL_EXT_STATUS_DISCONNECTING, NULL); #endif + } #ifdef WL_WPS_SYNC /* If are in WPS reauth state, then we would be @@ -6581,12 +7527,21 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, * disassoc indicates state mismatch with upper layer. Check for state * and issue disconnect indication if required. */ - - if (wdev->current_bss || wdev->ssid_len) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + if (wdev->connected || +#else + if (wdev->current_bss || +#endif /* LINUX_VER >= 5.19 || CFG80211_BKPORT_MLO */ + WDEV_CLIENT(wdev, ssid_len)) + { WL_INFORM_MEM(("report disconnect event\n")); CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL); } } +#if defined(OEM_ANDROID) + /* Kill CMD_BTCOEXMODE timer/handler if those are enabled */ + wl_cfg80211_btcoex_kill_handler(); +#endif /* defined(OEM_ANDROID) */ #ifdef CUSTOM_SET_CPUCORE /* set default cpucore */ @@ -6687,6 +7642,9 @@ wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) + int link_id, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) */ u8 key_idx, bool unicast, bool multicast) { struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); @@ -6730,8 +7688,9 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, s32 err = 0; s32 bssidx; s32 mode = wl_get_mode_by_netdev(cfg, dev); + uint8 iov_buf[WLC_IOCTL_SMLEN] = {0}; - WL_MSG(dev->name, "key index (%d)\n", key_idx); + WL_MSG(dev->name, "key index (%d) for %pM\n", key_idx, mac_addr); if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr)); return BCME_ERROR; @@ -6748,15 +7707,17 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, /* key delete */ swap_key_from_BE(&key); err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + iov_buf, WLC_IOCTL_SMLEN, bssidx, NULL); if (unlikely(err)) { WL_ERR(("key delete error (%d)\n", err)); - return err; + err = -EINVAL; + goto exit; } } else { if (key.len > sizeof(key.data)) { WL_ERR(("Invalid key length (%d)\n", key.len)); - return -EINVAL; + err = -EINVAL; + goto exit; } WL_DBG(("Setting the key index %d\n", key.index)); memcpy(key.data, params->key, key.len); @@ -6767,10 +7728,11 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, memcpy(keybuf, &key.data[24], sizeof(keybuf)); memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); memcpy(&key.data[16], keybuf, sizeof(keybuf)); + bzero(keybuf, sizeof(keybuf)); } /* if IW_ENCODE_EXT_RX_SEQ_VALID set */ - if (params->seq && params->seq_len == 6) { + if (params->seq && params->seq_len == CRYPTO_PARAMS_PN_IV_LEN) { /* rx iv */ const u8 *ivptr; ivptr = (const u8 *) params->seq; @@ -6782,21 +7744,30 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher); if (key.algo == CRYPTO_ALGO_OFF) { //not found. WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); - return -EINVAL; + err = -EINVAL; + goto exit; } swap_key_from_BE(&key); -#if defined(BCMDONGLEHOST) && !defined(CUSTOMER_HW4) +#if defined(BCMDONGLEHOST) /* need to guarantee EAPOL 4/4 send out before set key */ dhd_wait_pend8021x(dev); -#endif /* BCMDONGLEHOST && !CUSTOMER_HW4 */ +#endif err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + iov_buf, WLC_IOCTL_SMLEN, bssidx, NULL); if (unlikely(err)) { WL_ERR(("WLC_SET_KEY error (%d)\n", err)); - return err; + err = -EINVAL; + goto exit; } - WL_INFORM_MEM(("[%s] wsec key set\n", dev->name)); + + WL_INFORM_MEM(("[%s] wsec key set. key_idx:%d cipher:0x%x, key.iv_initialized %d\n", + dev->name, key_idx, params->cipher, key.iv_initialized)); } +exit: + /* clear buffers that held the keys */ + bzero(&key, sizeof(key)); + bzero(iov_buf, sizeof(iov_buf)); + return err; } @@ -6898,10 +7869,13 @@ wl_cfg80211_block_arp(struct net_device *dev, int enable) static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) + int link_id, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) */ u8 key_idx, bool pairwise, const u8 *mac_addr, struct key_params *params) { - struct wl_wsec_key key; + struct wl_wsec_key key = {0}; s32 val = 0; s32 wsec = 0; s32 err = 0; @@ -6909,6 +7883,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, s32 bssidx = 0; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); s32 mode = wl_get_mode_by_netdev(cfg, dev); + uint8 iov_buf[WLC_IOCTL_SMLEN] = {0}; #ifdef WL_GCMP uint32 algos = 0, mask = 0; #endif /* WL_GCMP */ @@ -6920,7 +7895,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); #endif /* BCMDONGLEHOST */ -#if defined (BCMDONGLEHOST) +#if defined(BCMDONGLEHOST) if (dhd_query_bus_erros(dhdp)) { /* If we are hit with bus error, return success so that * don't repeatedly call del station till we recover. @@ -6929,7 +7904,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, } #endif /* BCMDONGLEHOST */ - WL_INFORM_MEM(("key index (%d) (0x%x)\n", key_idx, params->cipher)); + WL_DBG(("key index (%d) (0x%x)\n", key_idx, params->cipher)); RETURN_EIO_IF_NOT_UP(cfg); if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { @@ -6958,16 +7933,14 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, if (unlikely(key.len > sizeof(key.data))) { WL_ERR(("Too long key length (%u)\n", key.len)); - return -EINVAL; + err = -EINVAL; + goto exit; } memcpy(key.data, params->key, key.len); - key.flags = WL_PRIMARY_KEY; - key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher); val = wl_rsn_cipher_wsec_algo_lookup(params->cipher); if (val == WSEC_NONE) { - WL_ERR(("Invalid cipher (0x%x), key.len = %d\n", params->cipher, key.len)); #if defined(WLAN_CIPHER_SUITE_PMK) /* WLAN_CIPHER_SUITE_PMK is not NL80211 standard ,but BRCM proprietary cipher suite. * so it doesn't have right algo type. Just for now, bypass this check for @@ -6976,19 +7949,25 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, */ if (params->cipher != WLAN_CIPHER_SUITE_PMK) #endif /* defined(WLAN_CIPHER_SUITE_PMK) */ - return -EINVAL; + { + WL_ERR(("Invalid cipher (0x%x), key.len = %d\n", params->cipher, key.len)); + err = -EINVAL; + goto exit; + } } switch (params->cipher) { case WLAN_CIPHER_SUITE_TKIP: if (params->key_len != TKIP_KEY_SIZE) { WL_ERR(("wrong TKIP Key length:%d", params->key_len)); - return -EINVAL; + err = -EINVAL; + goto exit; } /* wpa_supplicant switches the third and fourth quarters of the TKIP key */ if (mode == WL_MODE_BSS) { bcopy(&key.data[24], keybuf, sizeof(keybuf)); bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); bcopy(keybuf, &key.data[16], sizeof(keybuf)); + bzero(keybuf, sizeof(keybuf)); } WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); break; @@ -6996,7 +7975,6 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, case WLAN_CIPHER_SUITE_PMK: sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - WL_MEM(("set_pmk: wpa_auth:%x akm:%x\n", sec->wpa_auth, params->cipher)); /* Avoid pmk set for SAE and OWE for external supplicant case. */ if (IS_AKM_SAE(sec->wpa_auth) || IS_AKM_OWE(sec->wpa_auth)) { WL_INFORM_MEM(("skip pmk set for akm:%x\n", sec->wpa_auth)); @@ -7004,30 +7982,30 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, } if (params->key_len > sizeof(pmk.key)) { - WL_ERR(("Worng PMK key length:%d", params->key_len)); - return -EINVAL; + WL_ERR(("Wrong PMK key length:%d", params->key_len)); + err = -EINVAL; + goto exit; } bzero(&pmk, sizeof(pmk)); bcopy(params->key, &pmk.key, params->key_len); pmk.key_len = params->key_len; pmk.flags = 0; /* 0:PMK, WSEC_PASSPHRASE:PSK, WSEC_SAE_PASSPHRASE:SAE_PSK */ - if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) || - (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) { - err = wldev_iovar_setbuf_bsscfg(dev, "okc_info_pmk", pmk.key, pmk.key_len, - cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync); - if (err) { - /* could fail in case that 'okc' is not supported */ - WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", err)); - } - } + wl_cfg80211_set_okc_pmkinfo(cfg, dev, pmk, TRUE); err = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk)); if (err) { - WL_ERR(("pmk failed, err=%d (ignore)\n", err)); - return err; + bzero(&pmk, sizeof(pmk)); + WL_ERR(("pmk set failed. wpa_auth:0x%x, err=%d\n", sec->wpa_auth, err)); + /* PMK failure is not fatal, the connection could still go through + * by handling EAPOL at supplicant level. so print error reason and + * make an attempt to proceed. + */ + err = BCME_OK; + goto exit; } else { - WL_DBG(("pmk set. flags:0x%x\n", pmk.flags)); + WL_INFORM_MEM(("pmk set. len:%d flags:0x%x wpa_auth:0x%x akm:0x%x\n", + pmk.key_len, pmk.flags, sec->wpa_auth, params->cipher)); } /* Clear key length to delete key */ key.len = 0; @@ -7066,14 +8044,38 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("Buffering WEP Keys \n")); memcpy(&cfg->wep_key, &key, sizeof(struct wl_wsec_key)); } - err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf, - WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + + if (params->seq && params->seq_len == CRYPTO_PARAMS_PN_IV_LEN) { + /* rx iv */ + const u8 *ivptr; + ivptr = (const u8 *) params->seq; + key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | + (ivptr[3] << 8) | ivptr[2]; + key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; + key.iv_initialized = true; + } + + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), iov_buf, + WLC_IOCTL_SMLEN, bssidx, NULL); if (unlikely(err)) { WL_ERR(("WLC_SET_KEY error (%d)\n", err)); - return err; + } else { + WL_INFORM_MEM(("wsec_key applied. key_idx:%d cipher:0x%x, key.iv_initialized %d\n", + key_idx, params->cipher, key.iv_initialized)); } exit: + /* clear buffer used for setting pmk/keys */ + bzero(&key, sizeof(key)); + bzero(iov_buf, sizeof(iov_buf)); + bzero(&pmk, sizeof(pmk)); + + if (err) { + WL_ERR(("add_key failed. err:%d key_idx:%d cipher:0x%x\n", + err, key_idx, params->cipher)); + return err; + } + err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); if (unlikely(err)) { WL_ERR(("get wsec error (%d)\n", err)); @@ -7097,17 +8099,21 @@ exit: static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) + int link_id, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) */ u8 key_idx, bool pairwise, const u8 *mac_addr) { - struct wl_wsec_key key; + struct wl_wsec_key key = {0}; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); s32 err = 0; s32 bssidx; #ifdef BCMDONGLEHOST dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); #endif /* BCMDONGLEHOST */ + uint8 iov_buf[WLC_IOCTL_SMLEN] = {0}; -#if defined (BCMDONGLEHOST) +#if defined(BCMDONGLEHOST) if (dhd_query_bus_erros(dhdp)) { /* If we are hit with bus error, return success so that * don't repeatedly call del station till we recover. @@ -7134,15 +8140,16 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, #endif /* BCMDONGLEHOST */ bzero(&key, sizeof(key)); - key.flags = WL_PRIMARY_KEY; key.algo = CRYPTO_ALGO_OFF; key.index = (u32) key_idx; WL_DBG(("key index (%d)\n", key_idx)); /* Set the new key/index */ swap_key_from_BE(&key); - err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf, - WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), iov_buf, + WLC_IOCTL_SMLEN, bssidx, NULL); + bzero(iov_buf, sizeof(iov_buf)); + bzero(&key, sizeof(key)); if (unlikely(err)) { if (err == -EINVAL) { if (key.index >= DOT11_MAX_DEFAULT_KEYS) { @@ -7160,6 +8167,9 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, /* NOTE : this function cannot work as is and is never called */ static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) + int link_id, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) */ u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params * params)) { @@ -7232,9 +8242,13 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, return err; } -static s32 +static int wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, - struct net_device *dev, u8 key_idx) + struct net_device *dev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) + int link_id, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) || defined(CFG80211_BKPORT_MLO) */ + u8 key_idx) { #ifdef MFP /* Firmware seems to use hard coded index for Group Mgmt Key. @@ -7289,7 +8303,7 @@ wl_cfg80211_get_rssi(struct net_device *dev, struct bcm_cfg80211 *cfg, s32 *rssi /* Query RSSI sum across antennas */ bzero(&rssi_ant_mimo, sizeof(rssi_ant_mimo)); err = wl_get_rssi_per_ant(dev, dev->name, NULL, &rssi_ant_mimo); - if (err) { + if (err && err != BCME_UNSUPPORTED) { WL_ERR(("Could not get rssi sum (%d)\n", err)); /* set rssi to zero and do not return error, * because iovar phy_rssi_ant could return BCME_UNSUPPORTED @@ -7297,9 +8311,10 @@ wl_cfg80211_get_rssi(struct net_device *dev, struct bcm_cfg80211 *cfg, s32 *rssi */ err = BCME_OK; } else { - cfg->rssi_sum_report = TRUE; if ((*rssi = rssi_ant_mimo.rssi_sum) >= 0) { *rssi = 0; + } else { + cfg->rssi_sum_report = TRUE; } } #endif /* SUPPORT_RSSI_SUM_REPORT */ @@ -7354,6 +8369,14 @@ wl_cfg80211_ifstats_counters_cb(void *ctx, const uint8 *data, uint16 type, uint1 memcpy(ctx, data, sizeof(wl_if_stats_t)); break; } + case WL_IFSTATS_XTLV_INFRA_SPECIFIC: { + if (len > sizeof(wl_if_infra_enh_stats_v2_t)) { + WL_INFORM(("type 0x%x: cntbuf length too long! %d > %d\n", + type, len, (int)sizeof(wl_if_infra_enh_stats_v2_t))); + } + (void)memcpy_s(ctx, len, data, sizeof(wl_if_infra_enh_stats_v2_t)); + break; + } default: WL_DBG(("Unsupported counter type 0x%x\n", type)); break; @@ -7362,11 +8385,157 @@ wl_cfg80211_ifstats_counters_cb(void *ctx, const uint8 *data, uint16 type, uint1 return BCME_OK; } +#define IF_COUNTERS_PARAM_CONTAINER_LEN_MAX 228 /* Parameters to if_counters iovar need to be converted to XTLV format * before sending to FW. The length of the top level XTLV container * containing parameters should not exceed 228 bytes */ -#define IF_COUNTERS_PARAM_CONTAINER_LEN_MAX 228 +int +wl_cfg80211_if_infra_enh_ifstats_counters(struct net_device *dev, + wl_if_infra_enh_stats_v2_t *if_infra_enh_stats) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + uint8 *pbuf = NULL; + bcm_xtlvbuf_t xtlvbuf, local_xtlvbuf; + bcm_xtlv_t *xtlv; + uint16 expected_resp_len; + wl_stats_report_t *request = NULL, *response = NULL; + int bsscfg_idx; + int ret = BCME_OK; + + pbuf = (uint8 *)MALLOCZ(dhdp->osh, WLC_IOCTL_MEDLEN); + if (!pbuf) { + WL_ERR(("Failed to allocate local pbuf\n")); + return BCME_NOMEM; + } + + /* top level container length cannot exceed 228 bytes. + * This is because the output buffer is 1535 bytes long. + * Allow 1300 bytes for reporting stats coming in XTLV format + */ + request = (wl_stats_report_t *) + MALLOCZ(dhdp->osh, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX); + if (!request) { + WL_ERR(("Failed to allocate wl_stats_report_t with length (%d)\n", + IF_COUNTERS_PARAM_CONTAINER_LEN_MAX)); + ret = BCME_NOMEM; + goto fail; + } + + request->version = WL_STATS_REPORT_REQUEST_VERSION_V2; + + /* Top level container... we will create it ourselves */ + /* Leave space for report version, length, and top level XTLV + * WL_IFSTATS_XTLV_IF. + */ + ret = bcm_xtlv_buf_init(&local_xtlvbuf, + (uint8*)(request->data) + BCM_XTLV_HDR_SIZE, + IF_COUNTERS_PARAM_CONTAINER_LEN_MAX - + offsetof(wl_stats_report_t, data) - BCM_XTLV_HDR_SIZE, + BCM_XTLV_OPTION_ALIGN32); + + if (ret) { + goto fail; + } + + /* Populate requests using this the local_xtlvbuf context. The xtlvbuf + * is used to fill the container containing the XTLVs populated using + * local_xtlvbuf. + */ + ret = bcm_xtlv_buf_init(&xtlvbuf, + (uint8*)(request->data), + IF_COUNTERS_PARAM_CONTAINER_LEN_MAX - + offsetof(wl_stats_report_t, data), + BCM_XTLV_OPTION_ALIGN32); + + if (ret) { + goto fail; + } + + ret = bcm_xtlv_put_data(&local_xtlvbuf, + WL_IFSTATS_XTLV_INFRA_SPECIFIC, NULL, 0); + if (ret) { + goto fail; + } + + /* Complete the outer container with type and length + * only. + */ + ret = bcm_xtlv_put_data(&xtlvbuf, + WL_IFSTATS_XTLV_IF, + NULL, bcm_xtlv_buf_len(&local_xtlvbuf)); + if (ret) { + goto fail; + } + + request->length = bcm_xtlv_buf_len(&xtlvbuf) + + offsetof(wl_stats_report_t, data); + bsscfg_idx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr); + + /* send the command over to the device and get the output */ + ret = wldev_iovar_getbuf_bsscfg(dev, "if_counters", (void *)request, + request->length, pbuf, WLC_IOCTL_MEDLEN, bsscfg_idx, + &cfg->ioctl_buf_sync); + if (ret < 0) { + WL_ERR(("if_counters not supported ret=%d\n", ret)); + goto fail; + } + + /* Reuse request to process response */ + response = (wl_stats_report_t *)pbuf; + + /* version check */ + if (response->version != WL_STATS_REPORT_REQUEST_VERSION_V2) { + ret = BCME_VERSION; + goto fail; + } + + xtlv = (bcm_xtlv_t *)(response->data); + + expected_resp_len = + (BCM_XTLV_LEN(xtlv) + OFFSETOF(wl_stats_report_t, data)); + + /* Check if the received length is as expected */ + if ((response->length > WLC_IOCTL_MEDLEN) || + (response->length < expected_resp_len)) { + ret = BCME_ERROR; + WL_ERR(("Illegal response length received. Got: %d" + " Expected: %d. Expected len must be <= %u\n", + response->length, expected_resp_len, WLC_IOCTL_MEDLEN)); + goto fail; + } + + /* check the type. The return data will be in + * WL_IFSTATS_XTLV_IF container. So check if that container is + * present + */ + if (BCM_XTLV_ID(xtlv) != WL_IFSTATS_XTLV_IF) { + ret = BCME_ERROR; + WL_ERR(("unexpected type received: %d Expected: %d\n", + BCM_XTLV_ID(xtlv), WL_IFSTATS_XTLV_IF)); + goto fail; + } + + /* Process XTLVs within WL_IFSTATS_XTLV_INFRA_SPECIFIC container */ + ret = bcm_unpack_xtlv_buf(if_infra_enh_stats, + (uint8*)response->data + BCM_XTLV_HDR_SIZE, + BCM_XTLV_LEN(xtlv), /* total length of all TLVs in container */ + BCM_XTLV_OPTION_ALIGN32, wl_cfg80211_ifstats_counters_cb); + if (ret) { + WL_ERR(("Error unpacking XTLVs in wl_if_infra_enh_stats_v2_t counters: %d\n", ret)); + } + +fail: + if (pbuf) { + MFREE(dhdp->osh, pbuf, WLC_IOCTL_MEDLEN); + } + + if (request) { + MFREE(dhdp->osh, request, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX); + } + return ret; +} int wl_cfg80211_ifstats_counters(struct net_device *dev, wl_if_stats_t *if_stats) @@ -7452,7 +8621,7 @@ wl_cfg80211_ifstats_counters(struct net_device *dev, wl_if_stats_t *if_stats) offsetof(wl_stats_report_t, data); bsscfg_idx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr); - /* send the command over to the device and get teh output */ + /* send the command over to the device and get the output */ ret = wldev_iovar_getbuf_bsscfg(dev, "if_counters", (void *)request, request->length, pbuf, WLC_IOCTL_MEDLEN, bsscfg_idx, &cfg->ioctl_buf_sync); @@ -7515,8 +8684,8 @@ fail: } return ret; } -#undef IF_COUNTERS_PARAM_CONTAINER_LEN_MAX +#undef IF_COUNTERS_PARAM_CONTAINER_LEN_MAX static s32 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, @@ -7528,7 +8697,8 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, { struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); s32 rssi = 0; -#if defined(SUPPORT_RSSI_SUM_REPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +#if defined(SUPPORT_RSSI_SUM_REPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, \ + 0)) wl_rssi_ant_mimo_t rssi_ant_mimo; int cnt, chains; #endif /* SUPPORT_RSSI_SUM_REPORT && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */ @@ -7538,7 +8708,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, u16 wl_mode = 0; get_pktcnt_t pktcnt; wl_if_stats_t *if_stats = NULL; - sta_info_v4_t *sta = NULL; + wlcfg_sta_info_t *sta = NULL; #ifdef WL_RATE_INFO wl_rate_info_t *rates = NULL; #endif /* WL_RATE_INFO */ @@ -7550,6 +8720,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, u32 dhd_assoc_state = 0; #endif void *buf; + s32 ifidx = DHD_BAD_IF; RETURN_EIO_IF_NOT_UP(cfg); @@ -7585,8 +8756,9 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, } #if defined(BCMDONGLEHOST) dhd_assoc_state = wl_get_drv_status(cfg, CONNECTED, dev); + ifidx = dhd_net2idx(dhd->info, dev); DHD_OS_WAKE_LOCK(dhd); - fw_assoc_state = dhd_is_associated(dhd, 0, &err); + fw_assoc_state = dhd_is_associated(dhd, ifidx, &err); if (dhd_assoc_state && !fw_assoc_state) { /* check roam (join) status */ if (wl_check_assoc_state(cfg, dev)) { @@ -7595,8 +8767,6 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, } } DHD_OS_WAKE_UNLOCK(dhd); -#endif -#if defined(BCMDONGLEHOST) if (!dhd_assoc_state || !fw_assoc_state) #else if (!wl_get_drv_status(cfg, CONNECTED, dev)) @@ -7636,7 +8806,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, goto error; } #if defined(BCMDONGLEHOST) - if (dhd_is_associated(dhd, 0, NULL)) { + if (dhd_is_associated(dhd, ifidx, NULL)) { fw_assoc_watchdog_started = FALSE; } #endif /* defined(BCMDONGLEHOST) */ @@ -7645,7 +8815,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n", MAC2STRDBG(mac), MAC2STRDBG(curmacp))); } - sta = (sta_info_v4_t *)buf; + sta = (wlcfg_sta_info_t *)buf; bzero(sta, WLC_IOCTL_MEDLEN); err = wldev_iovar_getbuf(dev, "sta_info", (const void*)curmacp, ETHER_ADDR_LEN, buf, WLC_IOCTL_MEDLEN, NULL); @@ -7653,8 +8823,9 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("GET STA INFO failed, %d\n", err)); goto error; } - if (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5) { - WL_ERR(("GET STA INFO version mismatch, %d\n", err)); + if (!IS_STA_INFO_VER(sta)) { + WL_ERR(("STA INFO ver mismatch, %d! = %d\n", + sta->ver, WL_STAINFO_VER)); return BCME_VERSION; } sta->rx_rate = dtoh32(sta->rx_rate); @@ -7664,6 +8835,8 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("RX Rate %d Mbps\n", (sta->rx_rate / 1000))); } /* go through to get another information */ + /* fall through */ + fallthrough; case WL_IF_TYPE_P2P_GC: case WL_IF_TYPE_P2P_DISC: if ((err = wl_cfg80211_get_rssi(dev, cfg, &rssi)) != BCME_OK) { @@ -7688,14 +8861,15 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, sinfo->filled |= STA_INFO_BIT(INFO_SIGNAL); sinfo->signal = rssi; WL_DBG(("RSSI %d dBm\n", rssi)); -#if defined(SUPPORT_RSSI_SUM_REPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +#if defined(SUPPORT_RSSI_SUM_REPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, \ + 0)) /* Query RSSI sum across antennas */ (void)memset_s(&rssi_ant_mimo, sizeof(rssi_ant_mimo), 0, sizeof(rssi_ant_mimo)); err = wl_get_rssi_per_ant(dev, dev->name, NULL, &rssi_ant_mimo); - if (err) { + if (err && err != BCME_UNSUPPORTED) { WL_ERR(("Could not get rssi sum (%d)\n", err)); - } else { + } else if (!err) { chains = 0; for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) { sinfo->chain_signal[cnt] = rssi_ant_mimo.rssi_ant[cnt]; @@ -7708,6 +8882,8 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, } #endif /* SUPPORT_RSSI_SUM_REPORT && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */ /* go through to get another information */ + /* fall through */ + fallthrough; case WL_IF_TYPE_P2P_GO: #ifdef WL_RATE_INFO /* Get the current tx/rx rate */ @@ -7728,7 +8904,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, rates = (wl_rate_info_t *)buf; rates->version = dtoh32(rates->version); rates->length = dtoh32(rates->length); - if (rates->version != WL_RATE_INFO_VERSION) { + if (rates->version != WL_RATE_INFO_VERSION_1) { WL_ERR(("RATE_INFO version mismatch\n")); err = BCME_VERSION; goto error; @@ -7843,7 +9019,7 @@ get_station_err: #endif break; case WL_IF_TYPE_AP: - sta = (sta_info_v4_t *)buf; + sta = (wlcfg_sta_info_t *)buf; bzero(sta, WLC_IOCTL_MEDLEN); err = wldev_iovar_getbuf(dev, "sta_info", (const void*)mac, ETHER_ADDR_LEN, buf, WLC_IOCTL_MEDLEN, NULL); @@ -7851,8 +9027,9 @@ get_station_err: WL_ERR(("GET STA INFO failed, %d\n", err)); goto error; } - if (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5) { - WL_ERR(("GET STA INFO version mismatch, %d\n", err)); + if (!IS_STA_INFO_VER(sta)) { + WL_ERR(("STA INFO ver mismatch, %d! = %d\n", + sta->ver, WL_STAINFO_VER)); return BCME_VERSION; } sta->len = dtoh16(sta->len); @@ -7862,8 +9039,7 @@ get_station_err: sta->in = dtoh32(sta->in); sinfo->filled |= STA_INFO_BIT(INFO_INACTIVE_TIME); sinfo->inactive_time = sta->idle * 1000; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS) if (sta->flags & WL_STA_ASSOC) { sinfo->filled |= STA_INFO_BIT(INFO_CONNECTED_TIME); sinfo->connected_time = sta->in; @@ -7881,6 +9057,11 @@ error: MFREE(cfg->osh, buf, WLC_IOCTL_MEDLEN); } +#ifdef RPM_FAST_TRIGGER + WL_INFORM(("Trgger RPM Fast\n")); + dhd_trigger_rpm_fast(cfg); +#endif /* RPM_FAST_TRIGGER */ + return err; } @@ -7922,10 +9103,12 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev); s32 mode; +#if defined(OEM_ANDROID) || defined(RTT_SUPPORT) + dhd_pub_t *dhd = cfg->pub; +#endif /* OEM_ANDROID || RTT_SUPPORT */ #ifdef RTT_SUPPORT rtt_status_info_t *rtt_status; #endif /* RTT_SUPPORT */ - dhd_pub_t *dhd = cfg->pub; RETURN_EIO_IF_NOT_UP(cfg); WL_DBG(("Enter\n")); @@ -7937,8 +9120,15 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, return err; } - /* Enlarge pm_enable_work */ - wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_LONG); + mutex_lock(&cfg->pm_sync); + /* Remove the workqueue from enabling back PM when + * PM is explicitly disabled by the power mgmt API + */ + cancel_delayed_work(&cfg->pm_enable_work); +#if defined(BCMDONGLEHOST) && defined(OEM_ANDROID) + DHD_PM_WAKE_UNLOCK(cfg->pub); +#endif /* BCMDONGLEHOST && OEM_ANDROID */ + mutex_unlock(&cfg->pm_sync); pm = enabled ? PM_FAST : PM_OFF; if (_net_info->pm_block) { @@ -7952,6 +9142,10 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled"))); #ifdef RTT_SUPPORT rtt_status = GET_RTTSTATE(dhd); + /* Update rtt status's pm - save restored PM value after RTT process - + * to sync up with framework's WiFi PM state + */ + rtt_status->pm = pm; if (rtt_status->status != RTT_ENABLED) { #endif /* RTT_SUPPORT */ err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm)); @@ -7966,6 +9160,20 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, } #endif /* RTT_SUPPORT */ wl_cfg80211_update_power_mode(dev); + + /* Track host turning off the PM */ + _net_info->ps_managed = !enabled; + if (_net_info->ps_managed) { + _net_info->ps_managed_start_ts = OSL_SYSUPTIME(); + } + +#ifdef OEM_ANDROID + if (dhd->in_suspend) { + /* Enable/Disable bcn_li_dtim if suspend mode */ + wl_cfg80211_set_suspend_bcn_li_dtim(cfg, dev, TRUE); + } +#endif /* OEM_ANDROID */ + return err; } @@ -8166,6 +9374,360 @@ exit: #endif /* CONFIG_PM */ #endif /* !OEM_ANDROID */ +#ifdef OEM_ANDROID +void +wl_apply_per_sta_static_settings(struct bcm_cfg80211 *cfg, + struct net_device *dev, bool suspend) +{ + /* + * The below iovar values hold through the connection. It can + * be applied irrespective of STA connection status. + */ + +#ifdef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND + { + s32 err; + u32 roam_thresh = suspend ? CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND : 2000; + WL_DBG(("configure roam_threshold to %d iface:%s\n", + roam_thresh, dev->name)); + err = wldev_iovar_setint_no_wl(dev, "roam_time_thresh", roam_thresh); + if (err < 0) { + WL_ERR(("roam_time_thresh failed %d\n", err)); + } + } +#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */ + +#ifndef ENABLE_FW_ROAM_SUSPEND + { + s32 err; + /* Disable firmware roaming during suspend */ + u32 roamvar = suspend ? TRUE : FALSE; + err = wldev_iovar_setint_no_wl(dev, "roam_off", roamvar); + if (err < 0) { + WL_ERR(("roam_off failed %d\n", err)); + } + ROAMOFF_DBG_SAVE(dhd_linux_get_primary_netdev(dhd), + SET_ROAM_DHD_SUSPEND, roamvar); + } +#endif /* ENABLE_FW_ROAM_SUSPEND */ +} + +static int +wl_get_suspend_bcn_li_dtim(struct bcm_cfg80211 *cfg, + struct net_device *dev, int *dtim_period, int *bcn_interval) +{ + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + int bcn_li_dtim = 1; /* default no dtim skip setting */ + int ret = -1; + int allowed_skip_dtim_cnt = 0; + + if (cfg->disable_dtim_in_suspend) { + WL_ERR(("Disable bcn_li_dtim in suspend\n")); + bcn_li_dtim = 0; + return bcn_li_dtim; + } + + if (!wl_get_drv_status(cfg, CONNECTED, dev)) { + WL_ERR(("not associated\n")); + return bcn_li_dtim; + } + + if ((dtim_period == NULL) || (bcn_interval == NULL)) { + return bcn_li_dtim; + } + + if ((ret = wldev_ioctl_no_wl(dev, WLC_GET_BCNPRD, (u8 *)bcn_interval, + sizeof(*bcn_interval), FALSE))) { + WL_ERR(("GET BCNPRD failed:%d\n", ret)); + return bcn_li_dtim; + } + + if ((ret = wldev_ioctl_no_wl(dev, WLC_GET_DTIMPRD, (u8 *)dtim_period, + sizeof(*dtim_period), FALSE))) { + WL_ERR(("GET DTIM PERIOD failed:%d\n", ret)); + return bcn_li_dtim; + } + + if (*dtim_period == 0) { + return bcn_li_dtim; + } + + if (cfg->max_dtim_enable) { + bcn_li_dtim = + (int) (MAX_DTIM_ALLOWED_INTERVAL / ((*dtim_period) * (*bcn_interval))); + if (bcn_li_dtim == 0) { + bcn_li_dtim = 1; + } + } else { + /* attemp to use platform defined dtim skip interval */ + bcn_li_dtim = cfg->suspend_bcn_li_dtim; + + /* check if sta listen interval fits into AP dtim */ + if (*dtim_period > CUSTOM_LISTEN_INTERVAL) { + /* AP DTIM to big for our Listen Interval : no dtim skiping */ + bcn_li_dtim = NO_DTIM_SKIP; + WL_ERR(("DTIM=%d > Listen=%d : too big ...\n", + *dtim_period, CUSTOM_LISTEN_INTERVAL)); + return bcn_li_dtim; + } + + if (((*dtim_period) * (*bcn_interval) * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) { + allowed_skip_dtim_cnt = + MAX_DTIM_ALLOWED_INTERVAL / ((*dtim_period) * (*bcn_interval)); + bcn_li_dtim = + (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP; + } + + if ((bcn_li_dtim * (*dtim_period)) > CUSTOM_LISTEN_INTERVAL) { + /* Round up dtim_skip to fit into STAs Listen Interval */ + bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / *dtim_period); + WL_DBG(("agjust dtim_skip as %d\n", bcn_li_dtim)); + } + } + + if (dhd->conf->suspend_bcn_li_dtim >= 0) + bcn_li_dtim = dhd->conf->suspend_bcn_li_dtim; + WL_MSG(dev->name, "beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", + *bcn_interval, bcn_li_dtim, *dtim_period, CUSTOM_LISTEN_INTERVAL); + return bcn_li_dtim; +} + +static void +wl_get_dtim_settings(struct bcm_cfg80211 *cfg, struct net_device *dev, bool suspend, + u32 *bcn_li_dtim, u32 *lpas, u32 *bcn_to_dly) +{ + int dtim_period = 0; + int bcn_interval = 0; + + /* If DTIM skip is set up as default, force it to wake up each + * third DTIM for better power savings. Note that there is a + * side effect of a chance to miss BC/MC packet + */ + /* bi_li_dtim */ + *bcn_li_dtim = wl_get_suspend_bcn_li_dtim(cfg, dev, &dtim_period, &bcn_interval); + if ((*bcn_li_dtim * dtim_period * bcn_interval) >= MIN_DTIM_FOR_ROAM_THRES_EXTEND) { + + /* + * Increase max roaming threshold from 2 secs to 8 secs + * the real roam threshold is MIN(max_roam_threshold, + * bcn_timeout/2) + */ + *lpas = 1; + *bcn_to_dly = 1; + /* + * if bcn_to_dly is 1, the real roam threshold is + * MIN(max_roam_threshold, bcn_timeout -1); + * notify link down event after roaming procedure complete + * if we hit bcn_timeout while we are in roaming progress. + */ + } +} + +void +wl_cfg80211_set_suspend_bcn_li_dtim(struct bcm_cfg80211 *cfg, + struct net_device *dev, bool suspend) +{ + int err; + int lpas = 0; + int bcn_to_dly = 0; + int bcn_li_dtim = 0; + + if (suspend) { + wl_get_dtim_settings(cfg, dev, suspend, &bcn_li_dtim, &lpas, &bcn_to_dly); + } + + err = wldev_iovar_setint_no_wl(dev, "bcn_li_dtim", bcn_li_dtim); + if (err < 0) { + WL_ERR(("set bcn_li_ditm failed %d\n", err)); + } + + err = wldev_iovar_setint_no_wl(dev, "lpas", lpas); + if ((err < 0) && (err != BCME_UNSUPPORTED)) { + WL_ERR(("set lpas failed %d\n", err)); + } + + err = wldev_iovar_setint_no_wl(dev, "bcn_to_dly", bcn_to_dly); + if (err < 0) { + WL_ERR(("set bcn_to_dly failed %d\n", err)); + } + WL_MSG(dev->name, "bcn_li_dtim:%d lpas:%d bcn_to_dly:%d\n", bcn_li_dtim, lpas, bcn_to_dly); + +#ifdef ENABLE_BCN_LI_BCN_WAKEUP + { + int bcn_li_bcn = bcn_li_dtim ? 0 : 1; + + if (bcn_li_bcn) { + /* This can be true only in non-suspend state as bcn_li_dtim be + * non-zero in suspend state + */ + if ((cfg->stas_associated > 1) && (dev != cfg->inet_ndev)) { + /* For interfaces other than primary, clear the value */ + bcn_li_bcn = 0; + } + } + + err = wldev_iovar_setint_no_wl(dev, "bcn_li_bcn", bcn_li_bcn); + if (err < 0) { + WL_ERR(("%s set bcn_li_bcn failed %d\n", __FUNCTION__, err)); + } + } +#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ +} + +#if defined(WL_BCNRECV) +static void +wl_apply_bcn_recv(struct bcm_cfg80211 *cfg, + struct net_device *ndev, bool suspend) +{ + s32 ret; + + /* Applicable only for single STA I/F case. Disable for secondary I/F */ + if (cfg->stas_associated > 1) { + wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY); + } else { + /* single STA case */ + if (suspend) { + ret = wl_android_bcnrecv_suspend(ndev); + } else { + ret = wl_android_bcnrecv_resume(ndev); + } + + if (ret != BCME_OK) { + WL_ERR(("failed to stop beacon recv event on" + " suspend state (%d)\n", ret)); + } + } +} +#endif /* WL_BCNRECV */ + +static s32 +wl_apply_per_sta_conn_suspend_settings(struct bcm_cfg80211 *cfg, + struct net_device *dev, bool suspend) +{ + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + s32 err; + + BCM_REFERENCE(err); + + WL_INFORM_MEM(("apply sta settings for suspend:%d\n", suspend)); +#ifdef WLTDLS + if (suspend && dhd->tdls_mode) { + WL_DBG_MEM(("skip dtim settings in tdls mode\n")); + return 0; + } +#endif /* WLTDLS */ + + wl_cfg80211_set_suspend_bcn_li_dtim(cfg, dev, suspend); + +#ifdef ENABLE_IPMCAST_FILTER + { + int l2_filter = suspend ? TRUE : FALSE; + err = wldev_iovar_setint_no_wl(dev, "ipmcast_l2filter", l2_filter); + if (err < 0) { + WL_ERR(("failed to set ipmcast_l2filter (%d)\n", err)); + } + } +#endif /* ENABLE_IPMCAST_FILTER */ + +#ifndef SUPPORT_PM2_ONLY + { + u32 power_mode = suspend ? PM_MAX : PM_FAST; + wldev_ioctl_no_wl(dev, WLC_SET_PM, (u8 *)&power_mode, sizeof(u32), TRUE); + } +#endif /* SUPPORT_PM2_ONLY */ + +#ifdef DHD_BCN_TIMEOUT_IN_SUSPEND + { + u32 bcn_timeout = suspend ? + CUSTOM_BCN_TIMEOUT_IN_SUSPEND : CUSTOM_BCN_TIMEOUT; + err = wldev_iovar_setint_no_wl(dev, "bcn_timeout", bcn_timeout); + if (err < 0) { + WL_ERR(("bcn_timeout failed %d\n", err)); + } + } +#endif /* DHD_BCN_TIMEOUT_IN_SUSPEND */ + +#ifdef WL_BCNRECV + wl_apply_bcn_recv(cfg, dev, suspend); +#endif /* WL_BCNRECV */ + +#ifdef CONFIG_SILENT_ROAM + { + if (suspend) { + if (!cfg->sroamed && IS_INET_LINK_NDEV(cfg, dev)) { + /* sroam enable applicable only for primary interface. + * roam_off will be 1 for non-primary interfaces + */ + cfg->sroamed = TRUE; + wl_cfg80211_sroam_config(cfg, dev, TRUE); + } + } else { + cfg->sroamed = FALSE; + wl_cfg80211_sroam_config(cfg, dev, FALSE); + } + } +#endif /* CONFIG_SILENT_ROAM */ + return BCME_OK; +} + +void +wl_apply_sta_role_settings(struct bcm_cfg80211 *cfg, bool suspend) +{ + struct net_info *iter, *next; + + for_each_ndev(cfg, iter, next) { + if (iter->ndev && (iter->wdev->iftype == NL80211_IFTYPE_STATION)) { + + WL_DBG_MEM(("apply sta %s settings for %s\n", + (suspend ? "suspend" : "resume"), iter->ndev->name)); + + /* settings that needs to be applied per connection */ + if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) { + wl_apply_per_sta_conn_suspend_settings(cfg, iter->ndev, suspend); + } + + /* settings that hold with/without conneciton */ + wl_apply_per_sta_static_settings(cfg, iter->ndev, suspend); + } + } +} +#endif /* OEM_ANDROID */ + +/* + * This API is invoked from the screen OFF/ON context + * screen OFF: soft_supend ON + * screen ON: soft_supend OFF + */ +void +wl_cfg80211_soft_suspend(struct net_device *dev, bool suspend) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + + WL_INFORM_MEM(("enter %s\n", (suspend ? "suspend" : "resume"))); + + /* cache the state for internal reference */ + cfg->soft_suspend = suspend; + +#ifdef OEM_ANDROID + /* Apply cfg80211 settings for display on/off transition */ + wl_apply_sta_role_settings(cfg, suspend); +#endif /* OEM_ANDROID */ +} + +/* + * This API is invoked when there is a change in primary iface + */ +void +wl_cfg80211_handle_primary_ifchange(struct bcm_cfg80211 *cfg, + struct net_device *ndev) +{ + wl_cfgvif_roam_config(cfg, ndev, ROAM_CONF_PRIMARY_STA); +#ifdef OEM_ANDROID + /* re-apply cfg80211 suspend/resume settings */ + wl_apply_sta_role_settings(cfg, cfg->soft_suspend); +#endif /* OEM_ANDROID */ +} + #ifndef OEM_ANDROID /* * API invoked from driver .suspend context @@ -8255,7 +9817,12 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].pmkid[j])); } } - if (cfg->wlc_ver.wlc_ver_major >= MIN_PMKID_LIST_V3_FW_MAJOR) { + + WL_INFORM_MEM(("wlc_ver_major %x(%x) minor %x\n", cfg->wlc_ver.wlc_ver_major, + MIN_PMKID_LIST_V3_FW_MAJOR, cfg->wlc_ver.wlc_ver_minor)); + + if (WLC_PMKLIST_V3_SUPPORT(cfg->wlc_ver)) { + WL_INFORM_MEM(("PMKID_LIST_V3\n")); pmk_list->pmkids.version = PMKID_LIST_VER_3; err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list, sizeof(*pmk_list), cfg->ioctl_buf, @@ -8366,6 +9933,40 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, return err; } +void +wl_cfg80211_set_okc_pmkinfo(struct bcm_cfg80211 *cfg, struct net_device *dev, + wsec_pmk_t pmk, bool validate_sec) +{ + struct wl_security *sec; + uint8 iov_buf[WLC_IOCTL_SMLEN] = {0}; + s32 err = 0; + + if (!validate_sec) { + /* Update OKC only for legacy EAP connection */ + return; + } + + sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + if (!(sec->wpa_auth == WLAN_AKM_SUITE_8021X) && + !(sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) { + return; + } + + err = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk.key, pmk.key_len, iov_buf, + WLC_IOCTL_SMLEN, NULL); + if (err) { + /* could fail in case that 'okc' is not supported */ + if (err == BCME_UNSUPPORTED) { + WL_DBG_MEM(("okc_info_pmk not supported. Ignore.\n")); + } else { + WL_INFORM_MEM(("okc_info_pmk failed (%d). Ignore.\n", err)); + } + } else { + WL_DBG_MEM(("set okc_info_pmk complete\n")); + } + return; +} + /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single * entry operation. */ @@ -8381,7 +9982,7 @@ wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); #endif /* BCMDONGLEHOST */ - if (cfg->wlc_ver.wlc_ver_major >= PMKDB_WLC_VER) { + if (WLC_PMKDB_SUPPORT(cfg->wlc_ver)) { err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, TRUE); if (err != BCME_OK) { WL_ERR(("wl_cfg80211_set_pmksa err:%d\n", err)); @@ -8423,8 +10024,7 @@ wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, FILS_CACHE_ID_LEN); } #endif /* WL_FILS */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || \ - defined(WL_FILS)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS)) if (pmksa->pmk_len) { if (memcpy_s(&cfg->pmk_list->pmkids.pmkid[i].pmk, PMK_LEN_MAX, pmksa->pmk, pmksa->pmk_len)) { @@ -8483,10 +10083,14 @@ static s32 wl_cfg80211_update_pmksa(struct wiphy *wiphy, struct net_device *dev, s32 err = 0; pmkid_list_v3_t *pmk_list; uint32 alloc_len; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) + wsec_pmk_t pmk = {0}; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */ RETURN_EIO_IF_NOT_UP(cfg); - if (cfg->wlc_ver.wlc_ver_major < MIN_PMKID_LIST_V3_FW_MAJOR) { + if (!WLC_PMKLIST_V3_SUPPORT(cfg->wlc_ver)) { + WL_INFORM_MEM(("wlc_ver_major not supported:%d\n", cfg->wlc_ver.wlc_ver_major)); WL_DBG(("wlc_ver_major not supported:%d\n", cfg->wlc_ver.wlc_ver_major)); return BCME_VERSION; } @@ -8528,6 +10132,18 @@ static s32 wl_cfg80211_update_pmksa(struct wiphy *wiphy, struct net_device *dev, goto exit; } pmk_list->pmkid->pmk_len = pmksa->pmk_len; + pmk.key_len = pmksa->pmk_len; + err = memcpy_s(&pmk.key, sizeof(pmk.key), pmksa->pmk, pmksa->pmk_len); + if (err) { + goto exit; + } +#ifdef OEM_ANDROID + /* Call wl_cfg80211_set_okc_pmkinfo() with validate_sec + * as false, since sec->wpa_auth is not available in the + * Wi-Fi toggle context. + */ + wl_cfg80211_set_okc_pmkinfo(cfg, dev, pmk, TRUE); +#endif /* OEM_ANDROID */ } if (pmksa->ssid) { err = memcpy_s(&pmk_list->pmkid->ssid, sizeof(pmk_list->pmkid->ssid), @@ -8581,7 +10197,7 @@ wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("pmksa is not initialized\n")); return BCME_ERROR; } - if (cfg->wlc_ver.wlc_ver_major >= PMKDB_WLC_VER) { + if (WLC_PMKDB_SUPPORT(cfg->wlc_ver)) { err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, FALSE); if (err != BCME_OK) { WL_ERR(("wl_cfg80211_del_pmksa err:%d\n", err)); @@ -8675,7 +10291,7 @@ wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); s32 err = 0; RETURN_EIO_IF_NOT_UP(cfg); - if (cfg->wlc_ver.wlc_ver_major >= PMKDB_WLC_VER) { + if (WLC_PMKDB_SUPPORT(cfg->wlc_ver)) { /* NULL pmksa means delete whole PMKSA list */ err = wl_cfg80211_update_pmksa(wiphy, dev, NULL, FALSE); if (err != BCME_OK) { @@ -8734,7 +10350,7 @@ wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *de cfg->afx_hdl->is_active = TRUE; if (cfg->afx_hdl->pending_tx_act_frm) { - wl_action_frame_t *action_frame; + wl_action_frame_v1_t *action_frame; action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame); if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) is_p2p_gas = true; @@ -8804,7 +10420,7 @@ struct p2p_config_af_params { static s32 wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, - wl_action_frame_t *action_frame, wl_af_params_t *af_params, + wl_action_frame_v1_t *action_frame, wl_af_params_v1_t *af_params, struct p2p_config_af_params *config_af_params) { s32 err = BCME_OK; @@ -8930,11 +10546,11 @@ wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, #if defined(WL11U) && defined(WL_HOST_AF_DFS_CHECK) static bool -wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params, +wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_v1_t *af_params, void *frame, u16 frame_len) { wl_scan_results *bss_list; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; bool result = false; s32 i; chanspec_t chanspec; @@ -8964,6 +10580,7 @@ wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_param return result; } #endif /* WL11U && WL_HOST_AF_DFS_CHECK */ + static bool wl_cfg80211_check_dwell_overflow(int32 requested_dwell, ulong dwell_jiffies) { @@ -8978,8 +10595,8 @@ wl_cfg80211_check_dwell_overflow(int32 requested_dwell, ulong dwell_jiffies) static bool wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, - bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params, - wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx) + bcm_struct_cfgdev *cfgdev, wl_af_params_v1_t *af_params, + wl_action_frame_v1_t *action_frame, u16 action_frame_len, s32 bssidx, const u8 *sa) { #ifdef WL11U struct net_device *ndev = NULL; @@ -9237,13 +10854,14 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, off_chan_started_jiffies = jiffies; #endif /* VSDB */ - wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel); + wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, + CHSPEC_CHANNEL(af_params->channel)); wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true); dwell_jiffies = jiffies; /* Now send a tx action frame */ - ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true; + ack = wl_cfgp2p_tx_action_frame(cfg, cfgdev, dev, af_params, bssidx, sa) ? false : true; dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies); /* if failed, retry it. tx_retry_max value is configure by .... */ @@ -9259,7 +10877,7 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, OSL_SLEEP(AF_RETRY_DELAY_TIME); } #endif /* VSDB */ - ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? + ack = wl_cfgp2p_tx_action_frame(cfg, cfgdev, dev, af_params, bssidx, sa) ? false : true; dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies); } @@ -9339,19 +10957,17 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, bool channel_type_valid, #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */ unsigned int wait, const u8* buf, size_t len, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) bool no_cck, #endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS) bool dont_wait_for_ack, #endif u64 *cookie) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ { - wl_action_frame_t *action_frame; - wl_af_params_t *af_params; + wl_action_frame_v1_t *action_frame; + wl_af_params_v1_t *af_params; scb_val_t scb_val; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) struct ieee80211_channel *channel = params->chan; @@ -9500,14 +11116,12 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, goto exit; } #endif /* WL_CLIENT_SAE */ - } else { WL_ERR(("Driver only allows MGMT packet type\n")); goto exit; } - af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE); - + af_params = (wl_af_params_v1_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE_V1); if (af_params == NULL) { WL_ERR(("unable to allocate frame\n")); @@ -9522,7 +11136,6 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, /* Add BSSID */ memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN); memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN); - /* Add the length exepted for 802.11 header */ action_frame->len = len - DOT11_MGMT_HDR_LEN; WL_DBG(("action_frame->len: %d\n", action_frame->len)); @@ -9548,11 +11161,11 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params, - action_frame, action_frame->len, bssidx); + action_frame, action_frame->len, bssidx, mgmt->sa); cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL); WL_DBG(("txstatus notified for cookie:%llu. ack:%d\n", *cookie, ack)); - MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE); + MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE_V1); exit: return err; } @@ -9704,7 +11317,14 @@ wl_cfg80211_change_bss(struct wiphy *wiphy, return err; } -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +void +wl_init_listen_timer(struct bcm_cfg80211 *cfg) +{ + if (cfg->p2p) { + init_timer_compat(&cfg->p2p->listen_timer, wl_cfgp2p_listen_expired, cfg); + } +} + struct net_device * wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg) { @@ -9719,7 +11339,6 @@ wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg) return NULL; } -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ bool wl_cfg80211_macaddr_sync_reqd(struct net_device *dev) @@ -9769,7 +11388,8 @@ wl_cfg80211_macaddr_sync_reqd(struct net_device *dev) return false; } -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 2, 0)) static s32 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) wl_cfg80211_del_station( @@ -9912,6 +11532,11 @@ wl_cfg80211_post_scb_auth(struct bcm_cfg80211 *cfg, struct net_device *dev) wl_cfg80211_wbtext_update_rcc(cfg, dev); } #endif /* WBTEXT */ + +#ifdef OEM_ANDROID + /* Apply per sta connection settings based on current suspend state */ + wl_apply_per_sta_conn_suspend_settings(cfg, dev, cfg->soft_suspend); +#endif /* OEM_ANDROID */ } /* Currently adding support only for authorize/de-authorize flag @@ -10102,7 +11727,7 @@ exit: return err; } -static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev, +static int wl_cfg80211_dump_survey_ap(struct wiphy *wiphy, struct net_device *ndev, int idx, struct survey_info *info) { struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); @@ -10135,7 +11760,7 @@ static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev, chan = &band->channels[idx]; /* Setting current channel to the requested channel */ if ((err = wl_cfg80211_set_channel(wiphy, ndev, chan, - NL80211_CHAN_HT20) < 0)) { + NL80211_CHAN_WIDTH_20) < 0)) { /* * FIXME: * @@ -10218,6 +11843,109 @@ exit: } #endif /* WL_SUPPORT_ACS */ +/** + * A connected STA typically cannot afford to go off-channel to collect + * all form of stats like an AP sounding the air before going up, hence + * a dedicated interface. And NL only uses that for the noise field of + * wpa_cli's signal_poll. + */ +static int wl_cfg80211_dump_survey_sta(struct wiphy *wiphy, struct net_device *ndev, + int idx, struct survey_info *info) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + u16 wl_iftype = 0; + u16 wl_mode = 0; + chanspec_t *chanspec = NULL; + s32 freq = 0; + struct ieee80211_channel *channel = NULL; + int err, noise, retry; + + if (cfg80211_to_wl_iftype(ndev->ieee80211_ptr->iftype, &wl_iftype, &wl_mode) < 0) { + return -ENOENT; + } + + if (wl_iftype != WL_IF_TYPE_STA || + !wl_get_drv_status(cfg, CONNECTED, ndev) || + idx != 0) { + return -ENOENT; + } + chanspec = (chanspec_t *)wl_read_prof(cfg, ndev, WL_PROF_CHAN); + if (chanspec && (*chanspec) && (*chanspec != INVCHANNEL)) { + freq = wl_channel_to_frequency(wf_chspec_ctlchan(*chanspec), CHSPEC_BAND(*chanspec)); + channel = ieee80211_get_channel(wiphy, freq); + } else { + return -ENOENT; + } + + /* Get noise value */ + retry = IOCTL_RETRY_COUNT; + while (retry--) { + noise = 0; + err = wldev_ioctl_get(ndev, WLC_GET_PHY_NOISE, &noise, + sizeof(noise)); + if (err >= 0) { + break; + } + WL_DBG(("attempt = %d, err = %d, \n", + (IOCTL_RETRY_COUNT - retry), err)); + } + + if (retry <= 0) { + WL_ERR(("Get Phy Noise failed, error = %d\n", err)); + noise = CHAN_NOISE_DUMMY; + } + + memset_s(info, sizeof(struct survey_info), 0, sizeof(struct survey_info)); + info->channel = channel; + info->noise = noise; + info->filled = SURVEY_INFO_NOISE_DBM ; + + return 0; +} + +static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev, + int idx, struct survey_info *info) +{ +#ifdef WL_SUPPORT_ACS + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + if ((dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { + return wl_cfg80211_dump_survey_ap(wiphy, ndev, idx, info); + } else +#endif /* WL_SUPPORT_ACS */ + { + return wl_cfg80211_dump_survey_sta(wiphy, ndev, idx, info); + } +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) +static int +wl_cfg80211_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + unsigned int link_id, +#endif /* LINUX_VER >= 5.19.2 || CFG80211_BKPORT_MLO */ + struct cfg80211_chan_def *chandef) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + u32 chanspec = 0; + int ret = 0; + + RETURN_EIO_IF_NOT_UP(cfg); + if (wdev->netdev == NULL) { + /* the P2P interface may temporary use wdev without ndev */ + return -EINVAL; + } + + if ((ret = wldev_iovar_getint(wdev->netdev, "chanspec", (s32 *)&chanspec) != BCME_OK)) { + return ret; + } + if (!chandef || (wl_chspec_chandef(chanspec, chandef, wiphy) != BCME_OK)) { + return BCME_ERROR; + } + return 0; +} +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION (3, 6, 0) */ + static struct cfg80211_ops wl_cfg80211_ops = { .add_virtual_intf = wl_cfg80211_add_virtual_iface, .del_virtual_intf = wl_cfg80211_del_virtual_iface, @@ -10255,14 +11983,12 @@ static struct cfg80211_ops wl_cfg80211_ops = { .mgmt_frame_register = wl_cfg80211_mgmt_frame_register, #else .update_mgmt_frame_registrations = wl_cfg80211_mgmt_frame_register, -#endif +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0) */ .change_bss = wl_cfg80211_change_bss, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || defined(WL_COMPAT_WIRELESS) .set_channel = wl_cfg80211_set_channel, #endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && \ - !defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(WL_COMPAT_WIRELESS) .set_beacon = wl_cfg80211_add_set_beacon, .add_beacon = wl_cfg80211_add_set_beacon, .del_beacon = wl_cfg80211_del_beacon, @@ -10275,22 +12001,23 @@ static struct cfg80211_ops wl_cfg80211_ops = { .sched_scan_start = wl_cfg80211_sched_scan_start, .sched_scan_stop = wl_cfg80211_sched_scan_stop, #endif /* WL_SCHED_SCAN */ -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 2, 0)) .del_station = wl_cfg80211_del_station, .change_station = wl_cfg80211_change_station, .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait, #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) .tdls_mgmt = wl_cfg80211_tdls_mgmt, .tdls_oper = wl_cfg80211_tdls_oper, #endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */ -#ifdef WL_SUPPORT_ACS .dump_survey = wl_cfg80211_dump_survey, -#endif /* WL_SUPPORT_ACS */ #ifdef WL_CFG80211_ACL .set_mac_acl = wl_cfg80211_set_mac_acl, #endif /* WL_CFG80211_ACL */ +#ifdef WL_CFG80211_MONITOR + .set_monitor_channel = wl_cfg80211_set_monitor_channel, +#endif /* WL_CFG80211_MONITOR */ #ifdef GTK_OFFLOAD_SUPPORT #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) .set_rekey_data = wl_cfg80211_set_rekey_data, @@ -10315,6 +12042,12 @@ static struct cfg80211_ops wl_cfg80211_ops = { .update_ft_ies = wl_cfg80211_update_ft_ies, #endif /* WLFBT */ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) + .update_owe_info = wl_cfg80211_update_owe_info, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0) + .get_channel = wl_cfg80211_get_channel, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION (3, 6, 0) */ }; s32 wl_mode_to_nl80211_iftype(s32 mode) @@ -10375,6 +12108,11 @@ wl_is_ccode_change_required(struct net_device *net, s32 ret = BCME_OK; wl_country_t cspec = {{0}, 0, {0}}; wl_country_t cur_cspec = {{0}, 0, {0}}; + struct dhd_pub *dhd = dhd_get_pub(net); + + if (dhd_conf_same_country(dhd, country_code)) { + return false; + } ret = wldev_iovar_getbuf(net, "country", NULL, 0, &cur_cspec, sizeof(cur_cspec), NULL); @@ -10405,22 +12143,13 @@ wl_cfg80211_cleanup_connection(struct net_device *net, bool user_enforced) struct wiphy *wiphy = wdev->wiphy; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); struct net_info *iter, *next; - scb_val_t scbval; + BCM_REFERENCE(ret); GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); for_each_ndev(cfg, iter, next) { GCC_DIAGNOSTIC_POP(); if (iter->ndev) { - if (wl_get_drv_status(cfg, AP_CREATED, iter->ndev)) { - memset(scbval.ea.octet, 0xff, ETHER_ADDR_LEN); - scbval.val = DOT11_RC_DEAUTH_LEAVING; - if ((ret = wldev_ioctl_set(iter->ndev, - WLC_SCB_DEAUTHENTICATE_FOR_REASON, - &scbval, sizeof(scb_val_t))) != 0) { - WL_ERR(("Failed to disconnect STAs %d\n", ret)); - } - - } else if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) { + if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) { if ((iter->ndev == net) && !user_enforced) continue; wl_cfg80211_disassoc(iter->ndev, WLAN_REASON_DEAUTH_LEAVING); @@ -10437,6 +12166,7 @@ wl_cfg80211_cleanup_connection(struct net_device *net, bool user_enforced) #ifdef WL_NAN if (wl_cfgnan_is_enabled(cfg)) { mutex_lock(&cfg->if_sync); + cfg->nancfg->notify_user = true; ret = wl_cfgnan_check_nan_disable_pending(cfg, true, true); mutex_unlock(&cfg->if_sync); if (ret != BCME_OK) { @@ -10446,8 +12176,9 @@ wl_cfg80211_cleanup_connection(struct net_device *net, bool user_enforced) #endif /* WL_NAN */ } -static int wl_copy_regd(const struct ieee80211_regdomain *regd_orig, - struct ieee80211_regdomain *regd_copy) +#if defined(WL_SELF_MANAGED_REGDOM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) +static int wl_cfg80211_regd_duplicate(struct ieee80211_regdomain *regd_copy, + const struct ieee80211_regdomain *regd_orig) { int i; @@ -10462,14 +12193,121 @@ static int wl_copy_regd(const struct ieee80211_regdomain *regd_orig, } return BCME_OK; } +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM) */ +#ifdef EXT_REG_INFO +static void wl_cfg80211_regd_check_special_country_code(char *country_code) +{ + /* If a country code is Brcm specific change the domain to world domain */ + if ((!strcmp("AA", country_code)) /* AA */ + || (!strcmp("ZZ", country_code)) /* ZZ */ + || (country_code[0] == 'X') /* XA - XZ */ + || ( /* QM - QZ */ + (country_code[0] == 'Q') + && ((country_code[1] >= 'M') + && (country_code[1] <= 'Z')))) { + country_code[0] = '0'; + country_code[1] = '0'; + } +} + +static int wl_cfg80211_regd_update(struct bcm_cfg80211 *cfg, char *ccode) +{ + int err = BCME_OK; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM) + + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + int regd_len = 0; + struct ieee80211_regdomain *regd_copy = NULL; + s32 clm_flags = WLC_BAND_5G; + + wl_cfg80211_regd_check_special_country_code(ccode); + + WL_DBG(("Updating new country %s\n", ccode)); + + if (!IS_REGDOM_SELF_MANAGED(wiphy)) { + err = regulatory_hint(wiphy, ccode); + if (err) { + WL_ERR(("%s: update country to upper layers failed\n", __FUNCTION__)); + } + } + else if (global_regd_self) { + regd_len = sizeof(struct ieee80211_regdomain) + + (global_regd_self->n_reg_rules * sizeof(struct ieee80211_reg_rule)); + regd_copy = kzalloc(regd_len, GFP_ATOMIC); + + if (!regd_copy) { + WL_ERR(("*Faile to get %d memory for regd\n", regd_len)); + return BCME_NOMEM; + } + wl_cfg80211_regd_duplicate(regd_copy, global_regd_self); + + /* Set country code for REGDOM_SELF_MANAGED */ + regd_copy->alpha2[0] = ccode[0]; + regd_copy->alpha2[1] = ccode[1]; + err = wldev_iovar_getint(dev, "clm_flags", &clm_flags); + if (unlikely(err)) { + WL_ERR(("*Error reading clm_flags(%d)\n", err)); + } else { + WL_TRACE(("clm_flags(%d)\n", clm_flags)); + if (memcmp(regd_copy->alpha2, "JP", 2) == 0) { + regd_copy->dfs_region = NL80211_DFS_JP; + } else if (clm_flags & WL_CLM_DFS_TPC) { + if (clm_flags & WL_CLM_RADAR_TYPE_EU) { + regd_copy->dfs_region = NL80211_DFS_ETSI; + } else { + regd_copy->dfs_region = NL80211_DFS_FCC; + } + } else { + regd_copy->dfs_region = NL80211_DFS_UNSET; + } + } + if (wiphy) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) + if (rtnl_is_locked()) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + wiphy_lock(wiphy); + regulatory_set_wiphy_regd_sync(wiphy, regd_copy); + wiphy_unlock(wiphy); +#else + regulatory_set_wiphy_regd_sync_rtnl(wiphy, regd_copy); +#endif /* LINUX_VERSION >= 5.12.0 */ + } else { + regulatory_set_wiphy_regd(wiphy, regd_copy); + } +#else + /* for 3.10 */ + wiphy_apply_custom_regulatory(wiphy, regd_copy); +#endif /* LINUX_VERSION >= 4.0.0 */ + } + + kfree(regd_copy); + } else { + err = BCME_BADARG; + WL_ERR((" *global_regd_self is NULL!\n")); + WARN_ON(1); + } + +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM) */ + + /* just for reference */ + UNUSED_PARAMETER(global_regd_self); + wl_cfg80211_regd_check_special_country_code(ccode); + +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM) */ + + return err; +} +#else /* EXT_REG_INFO */ static void wl_notify_regd(struct wiphy *wiphy, char *country_code) { struct ieee80211_regdomain *regd_copy = NULL; int regd_len; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - regd_len = sizeof(brcm_regdom) + (brcm_regdom.n_reg_rules * + regd_len = sizeof(const_regdom_default) + (const_regdom_default.n_reg_rules * sizeof(struct ieee80211_reg_rule)); regd_copy = (struct ieee80211_regdomain *)MALLOCZ(cfg->osh, regd_len); @@ -10478,8 +12316,7 @@ static void wl_notify_regd(struct wiphy *wiphy, char *country_code) return; } - /* the upper layer function below requires non-const type */ - if (wl_copy_regd(&brcm_regdom, regd_copy)) { + if (wl_cfg80211_regd_duplicate(regd_copy, &const_regdom_default) != BCME_OK) { WL_ERR(("failed to copy new regd\n")); goto exit; } @@ -10500,18 +12337,48 @@ static void wl_notify_regd(struct wiphy *wiphy, char *country_code) wiphy_unlock(wiphy); #else regulatory_set_wiphy_regd_sync_rtnl(wiphy, regd_copy); -#endif /* LINUX_VERSION > 5.12.0 */ +#endif /* LINUX_VERSION >= 5.12.0 */ } else { regulatory_set_wiphy_regd(wiphy, regd_copy); } #else + /* for 3.10 OEM_HW40 build */ wiphy_apply_custom_regulatory(wiphy, regd_copy); -#endif /* LINUX_VERSION > 4.0.0 */ +#endif /* LINUX_VERSION >= 4.0.0 */ exit: MFREE(cfg->osh, regd_copy, regd_len); return; } +#endif /* EXT_REG_INFO */ + +#ifdef WL_AUTO_COUNTRY +static int +wl_config_autocountry(struct bcm_cfg80211 *cfg, + struct net_device *ndev, char *country_code) +{ + bool val = FALSE; + s32 err; + + if (!country_code) { + return -EINVAL; + } + + if ((country_code[0] == '0') && (country_code[1] == '0')) { + /* Enable auto country for world domain (00) */ + val = TRUE; + } + + WL_INFORM_MEM(("SYNA: autocountry %d\n", val)); + err = wldev_iovar_setint(ndev, "autocountry", val); + if (err) { + WL_ERR(("Failed to config auto country (%d) ret:%d\n", val, err)); + return err; + } + + return err; +} +#endif /* WL_AUTO_COUNTRY */ s32 wl_cfg80211_set_country_code(struct net_device *net, char *country_code, @@ -10523,6 +12390,13 @@ wl_cfg80211_set_country_code(struct net_device *net, char *country_code, struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); BCM_REFERENCE(cfg); +#ifdef WL_AUTO_COUNTRY + ret = wl_config_autocountry(cfg, net, country_code); + if (ret) { + return ret; + } +#endif /* WL_AUTO_COUNTRY */ + if (revinfo < 0) { WL_ERR(("country revinfo wrong : %d\n", revinfo)); ret = BCME_BADARG; @@ -10543,10 +12417,11 @@ wl_cfg80211_set_country_code(struct net_device *net, char *country_code, wl_cfg80211_cleanup_connection(net, user_enforced); /* Store before applying - so that if event comes earlier that is handled properly */ - if (strlcpy(cfg->country, country_code, WL_CCODE_LEN) >= WLC_CNTRY_BUF_SZ) { + if (strlcpy(cfg->country, country_code, WL_CCODE_LEN+1) >= WLC_CNTRY_BUF_SZ) { WL_ERR(("country code copy failed :%d\n", ret)); goto exit; } + WL_INFORM_MEM(("SYNA: cfg->country: %c%c\n", cfg->country[0], cfg->country[1])); ret = wldev_set_country(net, country_code, notify, revinfo); @@ -10560,11 +12435,15 @@ wl_cfg80211_set_country_code(struct net_device *net, char *country_code, * can refresh the channel * list */ +#ifdef EXT_REG_INFO + ret = wl_cfg80211_regd_update(cfg, country_code); +#else if (!IS_REGDOM_SELF_MANAGED(wiphy)) { regulatory_hint(wiphy, country_code); } else { wl_notify_regd(wiphy, country_code); } +#endif /* EXT_REG_INFO */ exit: return OSL_ERROR(ret); @@ -10583,7 +12462,7 @@ WL_CFG80211_REG_NOTIFIER() { struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy); int ret = 0; - int revinfo = -1; + int revinfo = 0; if (!request || !cfg) { WL_ERR(("Invalid arg\n")); @@ -10651,16 +12530,292 @@ int wl_features_set(u8 *array, uint8 len, u32 ftidx) return BCME_OK; } +#ifdef EXT_REG_INFO +#if defined(WL_SELF_MANAGED_REGDOM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) + +static int wl_cfg80211_regd_ieee_flag_to_bandwidth(int ieee_flag) +{ + int ret = -1; + + if (ieee_flag & IEEE80211_CHAN_DISABLED) { + ret = 0; + } else if ((ieee_flag & IEEE80211_CHAN_NO_HT40) == IEEE80211_CHAN_NO_HT40) { + /* make sure no HT40MINUS and HT40PLUS */ + ret = 20; + } else if (ieee_flag & IEEE80211_CHAN_NO_80MHZ) { + ret = 40; + } else if (ieee_flag & IEEE80211_CHAN_NO_160MHZ) { + ret = 80; + } else { + ret = 160; + } + + return ret; +} + +static uint32 wl_cfg80211_regd_ieee_flag_to_reg_flag(int ieee_flag) +{ + uint32 reg_flags = 0; + + if (ieee_flag & IEEE80211_CHAN_NO_OFDM) + reg_flags |= NL80211_RRF_NO_OFDM; + + if (ieee_flag & 0x0) + reg_flags |= NL80211_RRF_NO_CCK; + + if (ieee_flag & 0x0) + reg_flags |= NL80211_RRF_NO_INDOOR; + + if (ieee_flag & 0x0) + reg_flags |= NL80211_RRF_NO_OUTDOOR; + + if (ieee_flag & IEEE80211_CHAN_RADAR) + reg_flags |= NL80211_RRF_DFS; + + if (ieee_flag & 0x0) + reg_flags |= NL80211_RRF_PTP_ONLY; + + if (ieee_flag & 0x0) + reg_flags |= NL80211_RRF_PTMP_ONLY; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) + if (ieee_flag & IEEE80211_CHAN_PASSIVE_SCAN) + reg_flags |= NL80211_RRF_PASSIVE_SCAN; +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) */ + if (ieee_flag & IEEE80211_CHAN_NO_IR) + reg_flags |= NL80211_RRF_NO_IR; +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) */ + + if (20 < wl_cfg80211_regd_ieee_flag_to_bandwidth(ieee_flag)) + reg_flags |= NL80211_RRF_AUTO_BW; + + if (ieee_flag & 0x0) + reg_flags |= NL80211_RRF_IR_CONCURRENT; + + if (ieee_flag & IEEE80211_CHAN_NO_HT40MINUS) + reg_flags |= NL80211_RRF_NO_HT40MINUS; + + if (ieee_flag & IEEE80211_CHAN_NO_HT40PLUS) + reg_flags |= NL80211_RRF_NO_HT40PLUS; + + if (ieee_flag & IEEE80211_CHAN_NO_80MHZ) + reg_flags |= NL80211_RRF_NO_80MHZ; + + if (ieee_flag & IEEE80211_CHAN_NO_160MHZ) + reg_flags |= NL80211_RRF_NO_160MHZ; + + return reg_flags; +} + +static int wl_cfg80211_regd_update_rule(struct ieee80211_regdomain *regd, + int freq_start, int freq_end, uint32 ieee_flags, + int gain, int eirp) +{ + int band_width = 0; + uint32 interest_flag = 0x0; + uint32 reg_flags = 0x0; + + if (!regd) { + return -1; + } else if (freq_start > freq_end) { + return -2; + } else if ((band_width = wl_cfg80211_regd_ieee_flag_to_bandwidth(ieee_flags)) <= 0) { + return -3; + } else { + int index = -1; + int32 freq_diff = 0; + + /* adjust the parameters */ + interest_flag = CONST_SYNA_REG_FLAG_SAVE_MASK & ieee_flags; + if (2500 < freq_start) { + /* Non-2.4G ignore the BW40 flag */ + interest_flag &= ~CONST_SYNA_REG_FLAG_FILTER_EXTRA_MASK; + } + freq_start -= 10; + freq_end += 10; + reg_flags = wl_cfg80211_regd_ieee_flag_to_reg_flag(interest_flag); + + freq_diff = freq_end - freq_start; + if (freq_diff < band_width) { + if (band_width) { + WL_ERR(("freq_range=%d-%d=%d < max_bw=%d, force minimial\n", + freq_end, freq_start, freq_diff, band_width)); + } + band_width = freq_diff; + } + index = regd->n_reg_rules; + if (index >= (CONST_SYNA_REG_RULES_MAX_QTY - 1)) { + WL_ERR(("*Error, index=%d exceeds MAX=%d\n", + index, CONST_SYNA_REG_RULES_MAX_QTY - 1)); + return -5; + } + + memset(®d->reg_rules[index], 0, sizeof(regd->reg_rules[index])); + + regd->reg_rules[index].freq_range.start_freq_khz = MHZ_TO_KHZ(freq_start); + regd->reg_rules[index].freq_range.end_freq_khz = MHZ_TO_KHZ(freq_end); + regd->reg_rules[index].freq_range.max_bandwidth_khz = MHZ_TO_KHZ(band_width); + + regd->reg_rules[index].power_rule.max_antenna_gain = DBI_TO_MBI(gain); + regd->reg_rules[index].power_rule.max_eirp = DBM_TO_MBM(eirp); + + regd->reg_rules[index].flags = reg_flags; + WL_DBG(("rule[%d]: start_freq_khz=%d, end_freq_khz=%d, " + "max_banddwidth_khz=%d, flags=0x%X %s%s%s%s%s%s%s%s%s%s%s%s\n", + index, + regd->reg_rules[index].freq_range.start_freq_khz, + regd->reg_rules[index].freq_range.end_freq_khz, + regd->reg_rules[index].freq_range.max_bandwidth_khz, + reg_flags, + (IEEE80211_CHAN_DISABLED & reg_flags)?"DISABLED ":"", +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + (IEEE80211_CHAN_NO_IR & reg_flags)?"PASSIVE ":"", +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */ + "", +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */ + (IEEE80211_CHAN_RADAR & reg_flags)?"RADAR ":"", + (IEEE80211_CHAN_NO_HT40PLUS & reg_flags)?"NO_HT40PLUS ":"", + (IEEE80211_CHAN_NO_HT40MINUS & reg_flags)?"NO_HT40MINUS ":"", + (IEEE80211_CHAN_NO_OFDM & reg_flags)?"NO_OFDM ":"", + (IEEE80211_CHAN_NO_80MHZ & reg_flags)?"NO_80MHz ":"", + (IEEE80211_CHAN_NO_160MHZ & reg_flags)?"NO_160MHz ":"", +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + (IEEE80211_CHAN_INDOOR_ONLY & reg_flags)?"INDOOR ":"", +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */ + "", +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) + (IEEE80211_CHAN_IR_CONCURRENT & reg_flags)?"IR_CON ":"", +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + (IEEE80211_CHAN_GO_CONCURRENT & reg_flags)?"GO_CON ":"", +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) */ + "", +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + (IEEE80211_CHAN_NO_20MHZ & reg_flags)?"NO_20MHz ":"", + (IEEE80211_CHAN_NO_10MHZ & reg_flags)?"NO_10MHz ":"" +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */ + "", + "" +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */ + )); + regd->n_reg_rules++; + } + + return 0; +} + +static int wl_cfg80211_regd_parse_channels(struct ieee80211_regdomain * regd, + struct ieee80211_channel * channels, int qty) +{ + int i, ret = 0; + int range_start = 0, range_end = 0; + uint32 flags = ~0; + /* use for compare include the disable flag */ + uint32 mask_compare = CONST_SYNA_REG_FLAG_COMPARE_FOR_SPLIT_MASK; + + if ((!channels) || (qty <= 0)) { + ret = -1; + } else for (i = 0, range_start = -1; i < qty; i++) { + if (range_start == -1) { + flags = mask_compare & channels[i].flags; + if (IEEE80211_CHAN_DISABLED & flags) { + WL_TRACE(("*skip start=CH[%d]=%d, flags=0x%X => 0x%X\n", + i, channels[i].hw_value, channels[i].flags, flags)); + continue; + } else { + range_start = range_end = i; + WL_DBG(("prepare CH[%d]=%d ~ CH[%d]=%d, flags=0x%X => 0x%X\n", + range_start, channels[range_start].hw_value, + range_end, channels[range_end].hw_value, + channels[range_end].flags, flags)); + } + } else { + /* continue accumulate since already compare by last round */ + range_end = i; + } + if ((i + 1) >= qty) { + /* last fragment */ + WL_DBG(("=> confirm last(i=%d), CH[%d]=%d(freq=%d) ~ CH[%d]=%d(freq=%d)," + " flags=0x%X => 0x%X\n", + i, range_start, channels[range_start].hw_value, + channels[range_start].center_freq, + range_end, channels[range_end].hw_value, + channels[range_end].center_freq, + channels[range_end].flags, flags)); + wl_cfg80211_regd_update_rule(regd, channels[range_start].center_freq, + channels[range_end].center_freq, + channels[range_end].flags, + CONST_SYNA_REG_ANTENNA_GAIN_DEFAULT, + CONST_SYNA_REG_EIRP_DEFAULT); + } else { + WL_DBG(("accumulate %d, CH[%d]=%d ~ CH[%d]=%d, flags=0x%X => 0x%X\n", + i, range_start, channels[range_start].hw_value, + range_end, channels[range_end].hw_value, + channels[range_end].flags, flags)); + /* cut section when flags different */ + if (flags != (mask_compare & channels[i+1].flags)) { + WL_DBG(("=> confirm slice, CH[%d]=%d(freq=%d) ~ " + "CH[%d]=%d(freq=%d), flags=0x%X => 0x%X\n", + range_start, channels[range_start].hw_value, + channels[range_start].center_freq, + range_end, channels[range_end].hw_value, + channels[range_end].center_freq, + channels[range_end].flags, flags)); + wl_cfg80211_regd_update_rule(regd, + channels[range_start].center_freq, + channels[range_end].center_freq, + channels[range_end].flags, + CONST_SYNA_REG_ANTENNA_GAIN_DEFAULT, + CONST_SYNA_REG_EIRP_DEFAULT); + /* make flag to retry current mismatch one */ + range_start = -1; + } + } + } + + return ret; +} +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM) */ +#endif /* EXT_REG_INFO */ + static void wl_config_custom_regulatory(struct wiphy *wiphy) { #if defined(WL_SELF_MANAGED_REGDOM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) + +#ifdef EXT_REG_INFO + int regd_len = 0; + struct ieee80211_regdomain *regd_copy = NULL; +#endif /* EXT_REG_INFO */ + /* Use self managed regulatory domain */ - wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED | - REGULATORY_IGNORE_STALE_KICKOFF; + wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED + /* From kernel 6.4.4, this bit is removed and will be reused later */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 4)) + | REGULATORY_IGNORE_STALE_KICKOFF +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 4) */ + ; +#ifdef EXT_REG_INFO + regd_len = sizeof(struct ieee80211_regdomain) + + (CONST_SYNA_REG_RULES_MAX_QTY * sizeof(struct ieee80211_reg_rule)); + /* it will be released in function reg_process_self_managed_hints */ + regd_copy = kzalloc(regd_len, GFP_ATOMIC); + if (NULL != wiphy->regd) { + /* just give a warning and let it continue with overwrite */ + WL_ERR(("*Warning, original regd=0x%p is not NULL!\n", wiphy->regd)); + } + if (regd_copy) { + if (global_regd_self) { + wl_cfg80211_regd_duplicate(regd_copy, global_regd_self); + } else { + wl_cfg80211_regd_duplicate(regd_copy, &const_regdom_default); + } + wiphy->regd = regd_copy; + } +#endif /* EXT_REG_INFO */ WL_DBG(("Self managed regdom\n")); - return; #else /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) @@ -10672,7 +12827,11 @@ void wl_config_custom_regulatory(struct wiphy *wiphy) #else /* KERNEL VER >= 3.14 */ wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ +#ifdef EXT_REG_INFO + wiphy_apply_custom_regulatory(wiphy, &const_regdom_default); +#else wl_notify_regd(wiphy, NULL); +#endif /* EXT_REG_INFO */ WL_DBG(("apply custom regulatory\n")); #endif /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */ } @@ -10725,7 +12884,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) -#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF) +#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF) || defined(WL_CFG80211_MONITOR) /* * This monitor mode support creates an issue in registering * Action frame for P2P-GO, this was leading an error in receiving @@ -10734,9 +12893,8 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev * though we are not supporting this mode. */ | BIT(NL80211_IFTYPE_MONITOR) -#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */ -#if defined(WL_IFACE_COMB_NUM_CHANNELS) || \ - defined(WL_CFG80211_P2P_DEV_IF) +#endif +#if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) #endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */ @@ -10749,13 +12907,18 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev | BIT(NL80211_IFTYPE_AP); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ - (defined(WL_IFACE_COMB_NUM_CHANNELS) || \ - defined(WL_CFG80211_P2P_DEV_IF)) + (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) WL_DBG(("Setting interface combinations for common mode\n")); wdev->wiphy->iface_combinations = common_iface_combinations; wdev->wiphy->n_iface_combinations = ARRAY_SIZE(common_iface_combinations); #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ +#if defined(WL_CFG80211_AKM_TYPES_BKPORT) || (LINUX_VERSION_CODE >= KERNEL_VERSION(5, \ + 7, 0)) + wdev->wiphy->iftype_akm_suites = iftype_akm_suites; + wdev->wiphy->num_iftype_akm_suites = + ARRAY_SIZE(iftype_akm_suites); +#endif /* (WL_CFG80211_AKM_TYPES_BKPORT ) || (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) */ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; @@ -10771,8 +12934,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #endif /* !WL_POWERSAVE_DISABLED */ wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK | WIPHY_FLAG_4ADDR_AP | -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && \ - !defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && !defined(WL_COMPAT_WIRELESS) WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS | #endif WIPHY_FLAG_4ADDR_STATION; @@ -10786,13 +12948,13 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev */ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS) /* this flag should be added to support wpa_supplicant 1.0+ */ wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_OFFCHAN_TX; #endif -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 4, 0)) /* From 3.4 kernel ownards AP_SME flag can be advertised * to remove the patch from supplicant */ @@ -10819,8 +12981,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #endif /* defined(BCMDONGLEHOST) && KERNEL >= 3, 4, 0 || defined(WL_COMPAT_WIRELESS)) */ #endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; #endif @@ -10879,33 +13040,37 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #ifdef WL_FILS wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD); #endif /* WL_FILS */ - +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || \ + defined(WL_SUPPORT_BACKPORTED_ANQP_RMAC)) && defined(WL_ACT_FRAME_MAC_RAND) + wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) && defined(WL_ACT_FRAME_MAC_RAND) */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) wdev->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; - wdev->wiphy->max_num_csa_counters = WL_MAX_NUM_CSA_COUNTERS; #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 12, 0) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + wdev->wiphy->max_num_csa_counters = WL_MAX_NUM_CSA_COUNTERS; +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 16, 0) */ -#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ - (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS) +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \ + KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS) /* Workaround for a cfg80211 bug */ wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS; #endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) - wdev->wiphy->features |= (NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | - NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR); - wdev->wiphy->max_sched_scan_plans = 1; /* multiple plans not supported */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && \ + defined(SUPPORT_RANDOM_MAC_SCAN) + wdev->wiphy->features |= (NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | + NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR); + wdev->wiphy->max_sched_scan_plans = 1; /* multiple plans not supported */ #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) */ #if defined(WL_SAE) || defined(WL_CLIENT_SAE) - if (wl_extsae_chip(dhd)) + if (dhd_conf_extsae_chip(dhd)) wdev->wiphy->features |= NL80211_FEATURE_SAE; #endif /* WL_SAE || WL_CLIENT_SAE */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) && defined(BCMSUP_4WAY_HANDSHAKE) - if (FW_SUPPORTED(dhd, idsup)) { - wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK); - wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X); - } + wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK); + wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X); #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) && defined(BCMSUP_4WAY_HANDSHAKE) */ #ifdef WL_SCAN_TYPE /* These scan types will be mapped to default scan on non-supported chipset */ @@ -10915,10 +13080,14 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN); wdev->wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN; #endif /* WL_SCAN_TYPE */ - -#ifdef DHD_PNO_FLAG - wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI); -#endif +#if defined(WL_OCE) && defined(WL_CAP_OCE_STA) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) + wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME); + wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP); + wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE); + wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) */ +#endif /* WL_OCE && WL_CAP_OCE_STA */ /* Now we can register wiphy with cfg80211 module */ err = wiphy_register(wdev->wiphy); @@ -10927,7 +13096,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev wiphy_free(wdev->wiphy); return err; } - +#ifndef EXT_REG_INFO /* set wiphy->regd through reg_process_self_managed_hints * need to call it after wiphy_register * since wiphy_register adds rdev to cfg80211_rdev_list @@ -10937,6 +13106,8 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev wl_notify_regd(wdev->wiphy, NULL); rtnl_unlock(); } +#endif /* EXT_REG_INFO */ + return err; } @@ -11000,7 +13171,7 @@ wl_post_linkup_ops(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as) wl_wps_session_update(ndev, WPS_STATE_LINKUP, as->addr); #endif /** WL_WPS_SYNC */ - if (IS_PRIMARY_NDEV(cfg, ndev)) { + if (IS_STA_IFACE(ndev_to_wdev(ndev))) { vndr_oui_num = wl_vndr_ies_get_vendor_oui(cfg, ndev, vndr_oui, ARRAY_SIZE(vndr_oui)); if (vndr_oui_num > 0) { @@ -11065,7 +13236,7 @@ wl_post_linkup_ops(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as) } #endif /* CUSTOM_SET_ANTNPM */ -#if defined (ROAM_ENABLE) && defined (ROAM_AP_ENV_DETECTION) +#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) if (dhdp->roam_env_detection) { wldev_iovar_setint(ndev, "roam_env_detection", AP_ENV_INDETERMINATE); @@ -11119,6 +13290,11 @@ wl_post_linkup_ops(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as) else wldev_iovar_setint(ndev, "tcpack_fast_tx", 1); #endif /* CONFIG_TCPACK_FASTTX */ + +#ifdef WL_DUAL_APSTA + wl_cfgvif_roam_config(cfg, ndev, ROAM_CONF_LINKUP); +#endif /* WL_DUAL_APSTA */ + return ret; } @@ -11135,7 +13311,7 @@ wl_cfg80211_event_sae_key(struct bcm_cfg80211 *cfg, struct net_device *ndev, kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \ - LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), BRCM_SAE_VENDOR_EVENT_BUF_LEN, BRCM_VENDOR_EVENT_SAE_KEY, kflags); #else @@ -11149,7 +13325,7 @@ wl_cfg80211_event_sae_key(struct bcm_cfg80211 *cfg, struct net_device *ndev, goto done; } - WL_INFORM_MEM(("Received Sae Key event for "MACDBG" key length %x %x", + WL_INFORM_MEM(("Received Sae Key event for "MACDBG" key length %x %x\n", MAC2STRDBG(sae_key->peer_mac), sae_key->pmk_len, sae_key->pmkid_len)); nla_put(skb, BRCM_SAE_KEY_ATTR_PEER_MAC, ETHER_ADDR_LEN, sae_key->peer_mac); nla_put(skb, BRCM_SAE_KEY_ATTR_PMK, sae_key->pmk_len, sae_key->pmk); @@ -11160,7 +13336,7 @@ wl_cfg80211_event_sae_key(struct bcm_cfg80211 *cfg, struct net_device *ndev, * else ignore. * MIN_PMKID_LIST_V3_FW_MAJOR has two IOVAR's(pmklist_info and PMKDB). */ - if (cfg->wlc_ver.wlc_ver_major == MIN_PMKID_LIST_V3_FW_MAJOR) { + if (WLC_PMKLIST_V3_SUPPORT(cfg->wlc_ver)) { WL_INFORM_MEM(("Deleting the SAE PMK cache Info from firmware \n")); memset_s(&pmksa, sizeof(pmksa), 0, sizeof(pmksa)); pmksa.bssid = sae_key->peer_mac; @@ -11227,6 +13403,10 @@ wl_bss_handle_sae_auth_v2(struct bcm_cfg80211 *cfg, struct net_device *ndev, pmkid_v3_t *t_pmkid = NULL; auth_data = (wl_auth_event_t *)data; + if (!auth_data) { + WL_ERR(("Invalid param")); + return BCME_ERROR; + } tlv_buf_len = auth_data->length - WL_AUTH_EVENT_FIXED_LEN_V2; @@ -11251,7 +13431,7 @@ wl_bss_handle_sae_auth_v2(struct bcm_cfg80211 *cfg, struct net_device *ndev, tmp_buf = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len, WL_AUTH_PMKID_TYPE_TLV_ID, &type_len, BCM_XTLV_OPTION_ALIGN32); - memcpy(&type, tmp_buf, MIN(type_len, sizeof(type))); + memcpy_s(&type, sizeof(type), tmp_buf, MIN(type_len, sizeof(type))); if (type == WL_AUTH_PMKID_TYPE_SSID) { int idx; int idx2; @@ -11288,17 +13468,35 @@ wl_bss_handle_sae_auth_v2(struct bcm_cfg80211 *cfg, struct net_device *ndev, return BCME_NOTFOUND; } bzero(t_pmkid, sizeof(pmkid_v3_t)); - memcpy(&t_pmkid->bssid, event->addr.octet, 6); + memcpy_s(&t_pmkid->bssid, sizeof(t_pmkid->bssid), event->addr.octet, + ETHER_ADDR_LEN); + + if (ssid_len > (uint8)sizeof(t_pmkid->ssid)) { + WL_ERR(("insufficient ssid buffer\n")); + err = BCME_BUFTOOSHORT; + goto done; + } t_pmkid->ssid_len = ssid_len; err = memcpy_s(t_pmkid->ssid, sizeof(t_pmkid->ssid), ssid, ssid_len); if (err != BCME_OK) { goto done; } /* COPY but not used */ - t_pmkid->pmkid_len = sae_key.pmkid_len; - memcpy(t_pmkid->pmkid, sae_key.pmkid, sae_key.pmkid_len); + if (sae_key.pmkid_len > (uint16)sizeof(t_pmkid->pmkid)) { + WL_ERR(("insufficient pmkid buffer\n")); + err = BCME_BUFTOOSHORT; + goto done; + } + t_pmkid->pmkid_len = MIN(sizeof(t_pmkid->pmkid), sae_key.pmkid_len); + memcpy_s(t_pmkid->pmkid, sizeof(t_pmkid->pmkid), sae_key.pmkid, sae_key.pmkid_len); + + if (sae_key.pmk_len > (uint16)sizeof(t_pmkid->pmk)) { + WL_ERR(("insufficient pmk buffer\n")); + err = BCME_BUFTOOSHORT; + goto done; + } t_pmkid->pmk_len = sae_key.pmk_len; - memcpy(t_pmkid->pmk, sae_key.pmk, sae_key.pmk_len); + memcpy_s(t_pmkid->pmk, sizeof(t_pmkid->pmk), sae_key.pmk, sae_key.pmk_len); } err = wl_cfg80211_event_sae_key(cfg, ndev, &sae_key); @@ -11334,83 +13532,6 @@ wl_bss_handle_sae_auth(struct bcm_cfg80211 *cfg, struct net_device *ndev, } #endif /* WL_SAE */ -#if defined(DHD_ENABLE_BIGDATA_LOGGING) -enum { - BIGDATA_ASSOC_REJECT_NO_ACK = 1, - BIGDATA_ASSOC_REJECT_FAIL = 2, - BIGDATA_ASSOC_REJECT_UNSOLICITED = 3, - BIGDATA_ASSOC_REJECT_TIMEOUT = 4, - BIGDATA_ASSOC_REJECT_ABORT = 5, - BIGDATA_ASSOC_REJECT_NO_NETWWORKS = 6, - BIGDATA_ASSOC_REJECT_MAX = 50 -}; - -int wl_get_connect_failed_status(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e) -{ - u32 status = ntoh32(e->status); - - cfg->assoc_reject_status = 0; - - if (status != WLC_E_STATUS_SUCCESS) { - WL_INFORM(("auth assoc status event=%d e->status %d e->reason %d \n", - ntoh32(cfg->event_auth_assoc.event_type), - (int)ntoh32(cfg->event_auth_assoc.status), - (int)ntoh32(cfg->event_auth_assoc.reason))); - - /* Populate status based on cached auth/assoc status value */ - switch ((int)ntoh32(cfg->event_auth_assoc.status)) { - case WLC_E_STATUS_NO_ACK: - cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_NO_ACK; - break; - case WLC_E_STATUS_FAIL: - cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_FAIL; - break; - case WLC_E_STATUS_UNSOLICITED: - cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_UNSOLICITED; - break; - case WLC_E_STATUS_TIMEOUT: - cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_TIMEOUT; - break; - case WLC_E_STATUS_ABORT: - cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_ABORT; - break; - case WLC_E_STATUS_SUCCESS: - if (status == WLC_E_STATUS_NO_NETWORKS) { - cfg->assoc_reject_status = - BIGDATA_ASSOC_REJECT_NO_NETWWORKS; - break; - } - default: - cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_MAX; - break; - } - if (cfg->assoc_reject_status) { - if (ntoh32(cfg->event_auth_assoc.event_type) == WLC_E_ASSOC) { - cfg->assoc_reject_status += BIGDATA_ASSOC_REJECT_MAX; - } - } - } - - WL_INFORM_MEM(("assoc_reject_status %d \n", cfg->assoc_reject_status)); - - return 0; -} - -s32 wl_cfg80211_get_connect_failed_status(struct net_device *dev, char* cmd, int total_len) -{ - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - int bytes_written = 0; - - if (cfg == NULL) { - return -1; - } - bytes_written = snprintf(cmd, total_len, "assoc_reject.status %d", - cfg->assoc_reject_status); - WL_ERR(("cmd: %s \n", cmd)); - return bytes_written; -} -#endif /* DHD_ENABLE_BIGDATA_LOGGING */ - static s32 wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev, const wl_event_msg_t *e, void *data) @@ -11457,7 +13578,7 @@ wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev, MAC2STRDBG(cur_bssid), MAC2STRDBG((const u8 *)&e->addr)); wl_get_assoc_ies(cfg, ndev); wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID); - wl_update_bss_info(cfg, ndev, false); + wl_update_bss_info(cfg, ndev, false, NULL); #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL); #else @@ -11471,7 +13592,7 @@ wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev, wl_link_up(cfg); wl_get_assoc_ies(cfg, ndev); wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID); - wl_update_bss_info(cfg, ndev, false); + wl_update_bss_info(cfg, ndev, false, NULL); #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL); #else @@ -11492,407 +13613,18 @@ wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev, } else { WL_DBG(("no action (IBSS mode)\n")); -} + } return err; } -#if defined(DHD_ENABLE_BIGDATA_LOGGING) -#define WiFiALL_OUI "\x50\x6F\x9A" /* Wi-FiAll OUI */ -#define WiFiALL_OUI_LEN 3 -#define WiFiALL_OUI_TYPE 16 - -/* 11kv feature flag for big data */ -#define WL_BIGDATA_11KV_QBSSLOAD 0x00000001 -#define WL_BIGDATA_11KV_PROXYARP 0x00000002 -#define WL_BIGDATA_11KV_TFS 0x00000004 -#define WL_BIGDATA_11KV_SLEEP 0x00000008 -#define WL_BIGDATA_11KV_TIMBC 0x00000010 -#define WL_BIGDATA_11KV_BSSTRANS 0x00000020 -#define WL_BIGDATA_11KV_DMS 0x00000040 -#define WL_BIGDATA_11KV_LINK_MEA 0x00000080 -#define WL_BIGDATA_11KV_NBRREP 0x00000100 -#define WL_BIGDATA_11KV_BCNPASSIVE 0x00000200 -#define WL_BIGDATA_11KV_BCNACTIVE 0x00000400 -#define WL_BIGDATA_11KV_BCNTABLE 0x00000800 -#define WL_BIGDATA_11KV_BSSAAD 0x00001000 -#define WL_BIGDATA_11KV_MAX 0x00002000 - -#define WL_BIGDATA_SUPPORT_11K 0x00000001 -#define WL_BIGDATA_SUPPORT_11V 0x00000002 - -typedef struct { - uint8 bitmap; - uint8 octet_len; - uint32 flag; -} bigdata_11kv_t; - -bigdata_11kv_t bigdata_11k_info[] = { - {DOT11_RRM_CAP_LINK, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_LINK_MEA}, - {DOT11_RRM_CAP_NEIGHBOR_REPORT, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_NBRREP}, - {DOT11_RRM_CAP_BCN_PASSIVE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNPASSIVE}, - {DOT11_RRM_CAP_BCN_ACTIVE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNACTIVE}, - {DOT11_RRM_CAP_BCN_TABLE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNTABLE}, - {DOT11_RRM_CAP_BSSAAD, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BSSAAD}, -}; - -bigdata_11kv_t bigdata_11v_info[] = { - {DOT11_EXT_CAP_PROXY_ARP, DOT11_EXTCAP_LEN_PROXY_ARP, WL_BIGDATA_11KV_PROXYARP}, - {DOT11_EXT_CAP_TFS, DOT11_EXTCAP_LEN_TFS, WL_BIGDATA_11KV_TFS}, - {DOT11_EXT_CAP_WNM_SLEEP, DOT11_EXTCAP_LEN_WNM_SLEEP, WL_BIGDATA_11KV_SLEEP}, - {DOT11_EXT_CAP_TIMBC, DOT11_EXTCAP_LEN_TIMBC, WL_BIGDATA_11KV_TIMBC}, - {DOT11_EXT_CAP_BSSTRANS_MGMT, DOT11_EXTCAP_LEN_BSSTRANS, WL_BIGDATA_11KV_BSSTRANS}, - {DOT11_EXT_CAP_DMS, DOT11_EXTCAP_LEN_DMS, WL_BIGDATA_11KV_DMS} -}; - -static void -wl_get_11kv_info(u8 *ie, u32 ie_len, uint8 *support_11kv, uint32 *flag_11kv) -{ - bcm_tlv_t *ie_11kv = NULL; - uint32 flag_11k = 0, flag_11v = 0; - int i; - - /* parsing QBSS load ie */ - if ((bcm_parse_tlvs(ie, (u32)ie_len, - DOT11_MNG_QBSS_LOAD_ID)) != NULL) { - flag_11k |= WL_BIGDATA_11KV_QBSSLOAD; - } - - /* parsing RM IE for 11k */ - if ((ie_11kv = bcm_parse_tlvs(ie, (u32)ie_len, - DOT11_MNG_RRM_CAP_ID)) != NULL) { - for (i = 0; i < ARRAYSIZE(bigdata_11k_info); i++) { - if ((ie_11kv->len >= bigdata_11k_info[i].octet_len) && - isset(ie_11kv->data, bigdata_11k_info[i].bitmap)) { - flag_11k |= bigdata_11k_info[i].flag; - } - } - } - - /* parsing extended cap. IE for 11v */ - if ((ie_11kv = bcm_parse_tlvs(ie, (u32)ie_len, - DOT11_MNG_EXT_CAP_ID)) != NULL) { - for (i = 0; i < ARRAYSIZE(bigdata_11v_info); i++) { - if ((ie_11kv->len >= bigdata_11v_info[i].octet_len) && - isset(ie_11kv->data, bigdata_11v_info[i].bitmap)) { - flag_11v |= bigdata_11v_info[i].flag; - } - } - } - - if (flag_11k > 0) { - *support_11kv |= WL_BIGDATA_SUPPORT_11K; - } - - if (flag_11v > 0) { - *support_11kv |= WL_BIGDATA_SUPPORT_11V; - } - - *flag_11kv = flag_11k | flag_11v; -} - -int wl_get_bss_info(struct bcm_cfg80211 *cfg, struct net_device *dev, const u8 *mac) -{ - s32 err = 0; - wl_bss_info_v109_1_t *bi; - uint8 eabuf[ETHER_ADDR_LEN]; - u32 rate, channel, freq, supported_rate, nss = 0, mcs_map, mode_80211 = 0; - char rate_str[4]; - u8 *ie = NULL; - u32 ie_len; - struct wiphy *wiphy; - struct cfg80211_bss *bss; - bcm_tlv_t *interworking_ie = NULL; - bcm_tlv_t *tlv_ie = NULL; - bcm_tlv_t *vht_ie = NULL; - vndr_ie_t *vndrie; - int16 ie_11u_rel_num = -1, ie_mu_mimo_cap = -1; - u32 i, remained_len, count = 0; - char roam_count_str[4], akm_str[4]; - s32 val = 0; - uint8 support_11kv = 0; - uint32 flag_11kv = 0; /* bit flags of 11kv big data */ - int cfg_bss_info_len = 0; - - /* get BSS information */ - - strlcpy(cfg->bss_info, "x x x x x x x x x x x x x x x x x", sizeof(cfg->bss_info)); - - *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX); - - err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, cfg->extra_buf, WL_EXTRA_BUF_MAX); - if (unlikely(err)) { - WL_ERR(("Could not get bss info %d\n", err)); - cfg->roam_count = 0; - return -1; - } - - if (!mac) { - WL_ERR(("mac is null \n")); - cfg->roam_count = 0; - return -1; - } - - memcpy(eabuf, mac, ETHER_ADDR_LEN); - - bi = (wl_bss_info_v109_1_t *)(cfg->extra_buf + 4); - channel = wf_chspec_ctlchan(bi->chanspec); - freq = wl_channel_to_frequency(channel, CHSPEC_BAND(bi->chanspec)); - rate = 0; - err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate)); - if (err) { - WL_ERR(("Could not get rate (%d)\n", err)); - snprintf(rate_str, sizeof(rate_str), "x"); /* Unknown */ - - } else { - rate = dtoh32(rate); - snprintf(rate_str, sizeof(rate_str), "%d", (rate/2)); - } - - /* supported maximum rate */ - supported_rate = (bi->rateset.rates[bi->rateset.count - 1] & 0x7f) / 2; - - if (supported_rate < 12) { - mode_80211 = BIGDATA_DOT11_11B_MODE; /* 11b maximum rate is 11Mbps. 11b mode */ - } else { - /* It's not HT Capable case. */ - if (channel > 14) { - mode_80211 = BIGDATA_DOT11_11A_MODE; /* 11a mode */ - } else { - mode_80211 = BIGDATA_DOT11_11G_MODE; /* 11g mode */ - } - } - - if (bi->n_cap) { - /* check Rx MCS Map for HT */ - nss = 0; - mode_80211 = BIGDATA_DOT11_11N_MODE; - for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) { - int8 bitmap = DOT11_HT_MCS_RATE_MASK; - if (i == MAX_STREAMS_SUPPORTED-1) { - bitmap = DOT11_RATE_MASK; - } - if (bi->basic_mcs[i] & bitmap) { - nss++; - } - } - } - - if (bi->vht_cap) { - nss = 0; - mode_80211 = BIGDATA_DOT11_11AC_MODE; - for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) { - mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap)); - if (mcs_map != VHT_CAP_MCS_MAP_NONE) { - nss++; - } - } - } - -#if defined(WL11AX) - if (bi->he_cap) { - nss = 0; - mode_80211 = BIGDATA_DOT11_11AX_MODE; - for (i = 1; i <= HE_MCS_MAP_NSS_MAX; i++) { - mcs_map = HE_MCS_NSS_GET_MCS(i, dtoh32(bi->he_rxmcsmap)); - if (mcs_map != HE_MCS_CODE_NONE) { - nss++; - } - } - } -#endif /* WL11AX */ - - if (nss) { - nss = nss - 1; - } - - wiphy = bcmcfg_to_wiphy(cfg); - bss = CFG80211_GET_BSS(wiphy, NULL, eabuf, bi->SSID, bi->SSID_len); - if (!bss) { - WL_ERR(("Could not find the AP\n")); - } else { - GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); -#if defined(WL_CFG80211_P2P_DEV_IF) - ie = (u8 *)bss->ies->data; - ie_len = bss->ies->len; -#else - ie = bss->information_elements; - ie_len = bss->len_information_elements; -#endif /* WL_CFG80211_P2P_DEV_IF */ - GCC_DIAGNOSTIC_POP(); - } - - if (ie) { - ie_mu_mimo_cap = 0; - ie_11u_rel_num = 0; - - if (bi->vht_cap) { - if ((vht_ie = bcm_parse_tlvs(ie, ie_len, - DOT11_MNG_VHT_CAP_ID)) != NULL) { - if (vht_ie->len >= VHT_CAP_IE_LEN) { - ie_mu_mimo_cap = (vht_ie->data[2] & 0x08) >> 3; - } - } - } - - if ((interworking_ie = bcm_parse_tlvs(ie, ie_len, - DOT11_MNG_INTERWORKING_ID)) != NULL) { - if ((tlv_ie = bcm_parse_tlvs(ie, ie_len, DOT11_MNG_VS_ID)) != NULL) { - remained_len = ie_len; - - while (tlv_ie) { - if (count > MAX_VNDR_IE_NUMBER) - break; - - if (tlv_ie->id == DOT11_MNG_VS_ID) { - vndrie = (vndr_ie_t *) tlv_ie; - - if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) { - WL_ERR(("wl_get_bss_info: invalid vndr ie." - "length is too small %d\n", - vndrie->len)); - break; - } - - if (!bcmp(vndrie->oui, - (u8*)WiFiALL_OUI, WiFiALL_OUI_LEN) && - (vndrie->data[0] == WiFiALL_OUI_TYPE)) - { - WL_ERR(("Found Wi-FiAll OUI oui.\n")); - ie_11u_rel_num = vndrie->data[1]; - ie_11u_rel_num = (ie_11u_rel_num & 0xf0)>>4; - ie_11u_rel_num += 1; - - break; - } - } - count++; - tlv_ie = bcm_next_tlv(tlv_ie, &remained_len); - } - } - } - - /* get 11kv information from ie of current bss */ - wl_get_11kv_info(ie, ie_len, &support_11kv, &flag_11kv); - } - - for (i = 0; i < bi->SSID_len; i++) { - if (bi->SSID[i] == ' ') { - bi->SSID[i] = '_'; - } - } - - /* 0 : None, 1 : OKC, 2 : FT, 3 : CCKM */ - err = wldev_iovar_getint(dev, "wpa_auth", &val); - if (unlikely(err)) { - WL_ERR(("could not get wpa_auth (%d)\n", err)); - snprintf(akm_str, sizeof(akm_str), "x"); /* Unknown */ - } else { - WL_ERR(("wpa_auth val %d \n", val)); - if (val & WPA2_AUTH_FT) { - snprintf(akm_str, sizeof(akm_str), "2"); - } else if (val & (WPA_AUTH_UNSPECIFIED | WPA2_AUTH_UNSPECIFIED)) { - snprintf(akm_str, sizeof(akm_str), "1"); - } else { - snprintf(akm_str, sizeof(akm_str), "0"); - } - } - - if (cfg->roam_offload) { - snprintf(roam_count_str, sizeof(roam_count_str), "x"); /* Unknown */ - } else { - snprintf(roam_count_str, sizeof(roam_count_str), "%d", cfg->roam_count); - } - cfg->roam_count = 0; - - WL_ERR(("BSSID:" MACDBG " SSID %s \n", MAC2STRDBG(eabuf), "*****")); - WL_ERR(("freq:%d, BW:%s, RSSI:%d dBm, Rate:%d Mbps, 11mode:%d, stream:%d," - "MU-MIMO:%d, Passpoint:%d, SNR:%d, Noise:%d, \n" - "akm:%s, roam:%s, 11kv:%d/%d \n", - freq, wf_chspec_to_bw_str(bi->chanspec), - dtoh32(bi->RSSI), (rate / 2), mode_80211, nss, - ie_mu_mimo_cap, ie_11u_rel_num, bi->SNR, bi->phy_noise, - akm_str, roam_count_str, support_11kv, flag_11kv)); - - if (ie) { - snprintf(cfg->bss_info, GET_BSS_INFO_LEN, - MACOUI" %d %s %d %s %d %d %d %d %d %d %s %s %d %d", - MACOUI2STR(eabuf), freq, wf_chspec_to_bw_str(bi->chanspec), - dtoh32(bi->RSSI), rate_str, mode_80211, nss, ie_mu_mimo_cap, - ie_11u_rel_num, bi->SNR, bi->phy_noise, akm_str, roam_count_str, - support_11kv, flag_11kv); - } else { - /* ie_mu_mimo_cap and ie_11u_rel_num is unknow. */ - snprintf(cfg->bss_info, GET_BSS_INFO_LEN, - MACOUI" %d %s %d %s %d %d x x %d %d %s %s x x", - MACOUI2STR(eabuf), freq, wf_chspec_to_bw_str(bi->chanspec), - dtoh32(bi->RSSI), rate_str, mode_80211, nss, bi->SNR, - bi->phy_noise, akm_str, roam_count_str); - } - - cfg_bss_info_len = strlen(cfg->bss_info); - if (GET_BSS_INFO_LEN > cfg_bss_info_len) { - uint16 full_cnt = 0, partial_cnt = 0; - bool cnt_valid = FALSE; - -#if defined(DHD_PUB_ROAM_EVT) - wl_roam_stats_v1_t *roam_elem = - (wl_roam_stats_v1_t *)dhd_get_roam_evt((dhd_pub_t *)cfg->pub); - - if (roam_elem && roam_elem->version == WL_ROAM_STATS_VER_1) { - wl_roam_stats_v1_t *roam_elem_v1; - roam_elem_v1 = (wl_roam_stats_v1_t *)(uintptr_t)roam_elem; - - cnt_valid = TRUE; - full_cnt = roam_elem_v1->full_roam_scan_cnt; - partial_cnt = roam_elem_v1->partial_roam_scan_cnt; - } -#endif /* DHD_PUB_ROAM_EVT */ - if (cnt_valid) { - WL_ERR(("GET_BSS: full roam scan count:%d partial roam scan count:%d\n", - full_cnt, partial_cnt)); - snprintf(&cfg->bss_info[cfg_bss_info_len], - GET_BSS_INFO_LEN - cfg_bss_info_len, " %d %d", - full_cnt, partial_cnt); - } else { - WL_ERR(("GET_BSS: roam scan count invalid\n")); - snprintf(&cfg->bss_info[cfg_bss_info_len], - GET_BSS_INFO_LEN - cfg_bss_info_len, " x x"); - } - } else { - WL_ERR(("Buffer to short to save roam info\n")); - } - - CFG80211_PUT_BSS(wiphy, bss); - - return 0; -} - -s32 wl_cfg80211_get_bss_info(struct net_device *dev, char* cmd, int total_len) -{ - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - - if (cfg == NULL) { - return -1; - } - - if (total_len < GET_BSS_INFO_LEN) { - WL_ERR(("wl_cfg80211_get_bss_info: Buffer insuffient %d\n", total_len)); - return -1; - } - - bzero(cmd, total_len); - memcpy(cmd, cfg->bss_info, GET_BSS_INFO_LEN); - - WL_ERR_KERN(("cmd: %s \n", cmd)); - - return GET_BSS_INFO_LEN; -} -#endif /* DHD_ENABLE_BIGDATA_LOGGING */ - void wl_cfg80211_disassoc(struct net_device *ndev, uint32 reason) { scb_val_t scbval; s32 err; +#ifdef WL_CFGVENDOR_CUST_ADVLOG + scb_val_t scb_rssi; +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ + #ifdef BCMDONGLEHOST struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); @@ -11903,6 +13635,16 @@ void wl_cfg80211_disassoc(struct net_device *ndev, uint32 reason) dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING); #endif /* BCMDONGLEHOST */ +#ifdef WL_CFGVENDOR_CUST_ADVLOG + /* get rssi before sending DISASSOC to avoid getting zero */ + bzero(&scb_rssi, sizeof(scb_val_t)); + err = wldev_get_rssi(ndev, &scb_rssi); + if (unlikely(err)) { + WL_ERR(("get_rssi error (%d)\n", err)); + scb_rssi.val = WLC_RSSI_INVALID; + } +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ + memset_s(&scbval, sizeof(scb_val_t), 0x0, sizeof(scb_val_t)); scbval.val = htod32(reason); err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); @@ -11910,8 +13652,12 @@ void wl_cfg80211_disassoc(struct net_device *ndev, uint32 reason) WL_ERR(("WLC_DISASSOC error %d\n", err)); } else { WL_INFORM_MEM(("wl disassoc. reason:%d\n", reason)); +#ifdef WL_CFGVENDOR_CUST_ADVLOG + wl_cfgvendor_advlog_disassoc_tx(cfg, ndev, reason, scb_rssi.val); +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ } } + void wl_cfg80211_del_all_sta(struct net_device *ndev, uint32 reason) { struct net_device *dev; @@ -11967,6 +13713,7 @@ void wl_cfg80211_del_all_sta(struct net_device *ndev, uint32 reason) return; } + /* API to handle the Deauth from the AP. * For now we are deleting the PMKID cache in DHD/FW * in case of current connection is using SAE authnetication @@ -12113,14 +13860,12 @@ wl_set_link_action(wl_assoc_state_t assoc_state, bool link_up) } break; case WL_STATE_ASSOC_IDLE: - if (link_up) { - /* link up while cfg80211 state is not in - * 'ASSOCIATING/ASSOCIATED. Sync up the fw - * by disconnecting. - */ - WL_ERR(("Unexpected link up\n")); - action = WL_LINK_FORCE_DEAUTH; - } + /* link up/down while cfg80211 state is not in + * 'ASSOCIATING/ASSOCIATED. Do nothing, + */ + WL_ERR(("Unexpected link %s in assoc idle state, do nothing\n", + link_up ? "UP" : "DOWN")); + action = WL_LINK_NONE; break; default: WL_ERR(("unknown state:%d\n", assoc_state)); @@ -12143,20 +13888,33 @@ wl_cfg8021_unlink_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 *bss if (bss) { cfg80211_unlink_bss(wdev->wiphy, bss); CFG80211_PUT_BSS(wdev->wiphy, bss); - WL_INFORM_MEM(("bss unlinked")); + WL_INFORM_MEM(("bss unlinked\n")); } } } +#if defined(SUPPORT_RESTORE_SCAN_PARAMS) && defined(WES_SUPPORT) +extern int wl_android_default_set_scan_params(struct net_device *dev, char *command, int total_len); +#endif /* SUPPORT_RESTORE_SCAN_PARAMS && WES_SUPPORT */ + +#ifdef SUPPORT_LATENCY_CRITICAL_DATA +extern int wl_android_set_latency_crt_data(struct net_device *dev, int mode); +#endif /* SUPPORT_LATENCY_CRITICAL_DATA */ + +#ifdef SUPPORT_SET_TID +extern int wl_android_set_tid(struct net_device *ndev, char* command); +#endif /* SUPPORT_SET_TID */ static s32 wl_post_linkdown_ops(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as, struct net_device *ndev) { s32 ret = BCME_OK; dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + char cmd[WLC_IOCTL_SMLEN]; /* Common Code for connect failure & link down */ BCM_REFERENCE(dhdp); + BCM_REFERENCE(cmd); WL_INFORM_MEM(("link down. connection state bit status: [%u:%u:%u:%u]\n", wl_get_drv_status(cfg, CONNECTING, ndev), @@ -12186,25 +13944,34 @@ wl_post_linkdown_ops(struct bcm_cfg80211 *cfg, wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg), FW_LOGSET_MASK_ALL); -#ifdef WL_GET_RCC - wl_android_get_roam_scan_chanlist(cfg); -#endif /* WL_GET_RCC */ - #ifdef WES_SUPPORT if (cfg->ncho_mode) { /* Turn off NCHO mode */ wl_android_set_ncho_mode(ndev, FALSE); } +#ifdef SUPPORT_RESTORE_SCAN_PARAMS + else { + + bzero(cmd, WLC_IOCTL_SMLEN); + snprintf(cmd, WLC_IOCTL_SMLEN, "%s", "RESTORE_SCAN_PARAMS"); + wl_android_default_set_scan_params(ndev, cmd, WLC_IOCTL_SMLEN); + } +#endif /* SUPPORT_RESTORE_SCAN_PARAMS */ #endif /* WES_SUPPORT */ #ifdef WLTDLS wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false); #endif /* WLTDLS */ +#ifdef WL_DUAL_APSTA + wl_cfgvif_roam_config(cfg, ndev, ROAM_CONF_LINKDOWN); +#endif /* WL_DUAL_APSTA */ + /* clear RSSI monitor, framework will set new cfg */ #ifdef RSSI_MONITOR_SUPPORT - dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg), - FALSE, 0, 0); + if (ndev == cfg->inet_ndev) { + dhd_dev_set_rssi_monitor_cfg(ndev, FALSE, 0, 0); + } #endif /* RSSI_MONITOR_SUPPORT */ #ifdef WBTEXT @@ -12219,11 +13986,26 @@ wl_post_linkdown_ops(struct bcm_cfg80211 *cfg, } #endif /* P2PLISTEN_AP_SAMECHN */ -#ifdef WL_NAN - if (wl_cfgnan_is_enabled(cfg)) { - wl_cfgnan_get_stats(cfg); +#if defined(KEEP_ALIVE) && defined(DHD_CLEANUP_KEEP_ALIVE) + if ((ndev == cfg->inet_ndev) && cfg->mkeep_alive_avail) { + wl_cleanup_keep_alive(ndev, cfg); } -#endif /* WL_NAN */ +#endif /* defined(KEEP_ALIVE) && defined(DHD_CLEANUP_KEEP_ALIVE) */ + +#ifdef SUPPORT_LATENCY_CRITICAL_DATA + if (cfg->latency_mode) { + wl_android_set_latency_crt_data(ndev, LATENCY_CRT_DATA_MODE_OFF); + } +#endif /* SUPPORT_LATENCY_CRITICAL_DATA */ + +#ifdef SUPPORT_SET_TID + if (dhdp->tid_mode) { + bzero(cmd, WLC_IOCTL_SMLEN); + snprintf(cmd, WLC_IOCTL_SMLEN, "%d %d %d", SET_TID_OFF, + DEFAULT_SET_TID_TARGET_UID, DEFAULT_SET_TID_TARGET_PRIO); + wl_android_set_tid(ndev, cmd); + } +#endif /* SUPPORT_SET_TID */ return ret; } @@ -12255,7 +14037,7 @@ wl_handle_assoc_fail(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as, bool compl memcpy(&emsg, as->event_msg, sizeof(wl_event_msg_t)); ret = wl_ext_in4way_sync(ndev, STA_REASSOC_RETRY, WL_EXT_STATUS_RECONNECT, &emsg); - if (ret) + if (ret == BCME_ERROR) return 0; } wl_ext_iapsta_enable_master_if(ndev, FALSE); @@ -12411,7 +14193,13 @@ wl_handle_link_down(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as) memcpy(&emsg, as->event_msg, sizeof(wl_event_msg_t)); ret = wl_ext_in4way_sync(ndev, STA_REASSOC_RETRY, WL_EXT_STATUS_RECONNECT, &emsg); - if (ret) + if (ret == BCME_BADADDR) { + u8 *curbssid = NULL; + curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + if (curbssid) + (void)memcpy_s(as->addr, ETH_ALEN, curbssid, ETH_ALEN); + } + else if (ret == BCME_ERROR) return 0; } #endif @@ -12488,19 +14276,27 @@ wl_handle_link_down(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as) ie_len = datalen - DOT11_DISCONNECT_RC; } } -#ifdef WL_ANALYTICS - else if ((event == WLC_E_LINK) && - (reason == WLC_E_LINK_BCN_LOSS)) { + else if ((event == WLC_E_LINK) && (reason == WLC_E_LINK_BCN_LOSS)) { if (ndev == bcmcfg_to_prmry_ndev(cfg)) { +#ifdef WL_ANALYTICS if (wl_vndr_ies_find_vendor_oui(cfg, ndev, CISCO_AIRONET_OUI)) { WL_INFORM_MEM(("Analytics Beacon loss\n")); ie_ptr = (uchar*)disco_bcnloss_vsie; ie_len = sizeof(disco_bcnloss_vsie); } - } - } #endif /* WL_ANALYTICS */ +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT + dhdp->alert_reason = ALERT_BCN_LOST; + dhd_os_send_alert_message(dhdp); +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ +#ifdef WL_CFGVENDOR_CUST_ADVLOG + wl_cfgvendor_custom_advlog_disconn(cfg, as); +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ + } + /* force reset reason code to prevent autoreconnect in bcnloss case */ + reason = 0; + } #ifdef BCMDONGLEHOST #if defined(DHDTCPSYNC_FLOOD_BLK) && defined(CUSTOMER_TCPSYNC_FLOOD_DIS_RC) @@ -12514,13 +14310,15 @@ wl_handle_link_down(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as) #endif /* DHDTCPSYNC_FLOOD_BLK && CUSTOMER_TCPSYNC_FLOOD_DIS_RC */ #endif /* BCMDONGLEHOST */ -#ifdef DHD_ENABLE_BIGDATA_LOGGING - wl_get_bss_info(cfg, ndev, as->addr); -#endif /* DHD_ENABLE_BIGDATA_LOGGING */ - /* unlink from bss list - to force fresh add from next scan/connect */ wl_cfg8021_unlink_bss(cfg, ndev, as->addr); +#ifdef WL_GET_RCC + wl_android_get_roam_scan_chanlist(cfg); + wl_android_get_roam_scan_freqlist(cfg); +#endif /* WL_GET_RCC */ + ROAMOFF_DBG_DUMP(cfg); + /* clear profile before reporting link down */ wl_init_prof(cfg, ndev); #if defined(BSSCACHE) @@ -12536,13 +14334,18 @@ wl_handle_link_down(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as) } #endif + if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) { + /* If DISCONNECTING bit is set, mark locally generated */ + loc_gen = 1; + } + CFG80211_DISCONNECTED(ndev, reason, ie_ptr, ie_len, loc_gen, GFP_KERNEL); WL_MSG(ndev->name, "Disconnect event sent to upper layer" - "event:%d e->reason=%d reason=%d ie_len=%d " + "event:%d e->reason=%d reason=%d ie_len=%d loc_gen=%d " "from " MACDBG "\n", event, ntoh32(as->reason), reason, ie_len, - MAC2STRDBG((const u8*)(&as->addr))); + loc_gen, MAC2STRDBG((const u8*)(&as->addr))); /* clear connected state */ wl_clr_drv_status(cfg, CONNECTED, ndev); @@ -12618,7 +14421,10 @@ wl_handle_roam_done(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as) { struct wl_security *sec = wl_read_prof(cfg, as->ndev, WL_PROF_SEC); - if (!IS_AKM_SUITE_FT(sec)) { + /* For FT cases roaming done will be called in ROAM/BSSID + * event context and we should avoid here in LINK_UP context + */ + if (!IS_AKM_SUITE_FT(sec) && !IS_AKM_SUITE_SAE_FT(sec)) { wl_bss_roaming_done(cfg, as->ndev, as->event_msg, as->data); } } @@ -12667,6 +14473,216 @@ wl_handle_sta_link_action(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as) return ret; } +#ifdef WL_CFGVENDOR_CUST_ADVLOG +extern const char* get_advlog_val(dhd_advlog_map_entry_t *arr, uint32 arr_len, int tag); + +static dhd_advlog_map_entry_t wl_advlog_auth_assoc_req[] = { + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + {WLC_E_AUTH, "[CONN] AUTH REQ bssid="MACDBG_FULL" rssi=%d auth_algo=%u tx_status=%s"}, + {WLC_E_ASSOC, "[CONN] ASSOC REQ bssid="MACDBG_FULL" rssi=%d auth_algo=%u tx_status=%s"}, +}; + +static dhd_advlog_map_entry_t wl_advlog_auth_assoc_resp[] = { + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + {WLC_E_AUTH, "[CONN] AUTH RESP bssid="MACDBG_FULL" auth_algo=%u status=%u"}, + {WLC_E_ASSOC, "[CONN] ASSOC RESP bssid="MACDBG_FULL" auth_algo=%u status=%u"}, +}; + +static dhd_advlog_map_entry_t wl_advlog_tx_status[] = { + {WLC_E_STATUS_SUCCESS, "ACK"}, + {WLC_E_STATUS_TIMEOUT, "ACK"}, + {WLC_E_STATUS_FAIL, "ACK"}, + {WLC_E_STATUS_NO_ACK, "NO_ACK"}, + {WLC_E_STATUS_SUPPRESS, "TX_FAIL"}, +}; + +static dhd_advlog_map_entry_t wl_advlog_deauth_disassoc[] = { + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + {WLC_E_DEAUTH_IND, "[CONN] DEAUTH RX bssid="MACDBG_FULL" rssi=%d reason=%u"}, + {WLC_E_DEAUTH, "[CONN] DEAUTH TX bssid="MACDBG_FULL" rssi=%d reason=%u"}, + {WLC_E_DISASSOC_IND, "[CONN] DISASSOC RX bssid="MACDBG_FULL" rssi=%d reason=%u"}, + {WLC_E_DISASSOC, "[CONN] DISASSOC TX bssid="MACDBG_FULL" rssi=%d reason=%u"}, +}; + +static void +wl_cfgvendor_advlog_deauth_disassoc(wl_assoc_status_t *as, int rssi) +{ + const char *fmt_str = NULL; + + fmt_str = get_advlog_val(wl_advlog_deauth_disassoc, + ARRAY_SIZE(wl_advlog_deauth_disassoc), as->event_type); + if (fmt_str) { + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + SUPP_ADVLOG((fmt_str, MAC2STRDBG_FULL((const u8*)(&as->addr)), + rssi, as->reason)); + } +} + +static void +wl_cfgvendor_advlog_auth_assoc(wl_assoc_status_t *as, uint32 rssi) +{ + const char *req_str = NULL; + const char *resp_str = NULL; + const char *status_str = NULL; + const wl_event_msg_t *e; + + e = as->event_msg; + + if (as->status == WLC_E_STATUS_ABORT || + as->status == WLC_E_STATUS_UNSOLICITED) { + WL_DBG(("This event was aborted or unsolicited for Auth/Assoc.\n")); + return; + } + + req_str = get_advlog_val(wl_advlog_auth_assoc_req, + ARRAY_SIZE(wl_advlog_auth_assoc_req), as->event_type); + + status_str = get_advlog_val(wl_advlog_tx_status, + ARRAY_SIZE(wl_advlog_tx_status), as->status); + if (!req_str || !status_str) { + WL_ERR(("map arr not found type:%d status:%d\n", as->event_type, as->status)); + return; + } + + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + SUPP_ADVLOG((req_str, MAC2STRDBG_FULL((const u8*)(&e->addr)), + rssi, ntoh32(e->auth_type), status_str)); + + if (as->status == WLC_E_STATUS_SUCCESS || + as->status == WLC_E_STATUS_FAIL) { + resp_str = get_advlog_val(wl_advlog_auth_assoc_resp, + ARRAY_SIZE(wl_advlog_auth_assoc_resp), as->event_type); + if (!resp_str) { + WL_ERR(("resp map arr not found type:%d\n", as->event_type)); + return; + } + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + SUPP_ADVLOG((resp_str, MAC2STRDBG_FULL((const u8*)(&e->addr)), + ntoh32(e->auth_type), as->reason)); + } + + return; +} + +void +wl_cfgvendor_advlog_connect_event(wl_assoc_status_t *as, bool query_rssi, int pre_rssi) +{ + s32 err = BCME_OK; + scb_val_t scbval; + + if (!as->ndev) { + WL_ERR(("ndev is null\n")); + return; + } + + if (query_rssi == TRUE && pre_rssi == WLC_RSSI_INVALID) { + /* get rssi value */ + bzero(&scbval, sizeof(scb_val_t)); + err = wldev_get_rssi(as->ndev, &scbval); + if (unlikely(err)) { + WL_ERR(("get_rssi error (%d)\n", err)); + scbval.val = WLC_RSSI_INVALID; + } + } else { + scbval.val = pre_rssi; + } + + /* Handle FW events */ + switch (as->event_type) { + case WLC_E_AUTH: + case WLC_E_ASSOC: + wl_cfgvendor_advlog_auth_assoc(as, scbval.val); + break; + case WLC_E_DISASSOC: + case WLC_E_DISASSOC_IND: + case WLC_E_DEAUTH: + case WLC_E_DEAUTH_IND: + wl_cfgvendor_advlog_deauth_disassoc(as, scbval.val); + break; + default: + WL_DBG(("Ignore event:%d\n", as->event_type)); + } +} + +void +wl_cfgvendor_advlog_disassoc_tx(struct bcm_cfg80211 *cfg, struct net_device *ndev, + uint32 reason, int rssi) +{ + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + wl_assoc_status_t as; + s32 ifidx = DHD_BAD_IF; + u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + struct ether_addr fw_bssid; + int err; + + /* In DEAUTH_IND or Beacon loss cases, we already lost contact */ + bzero(&fw_bssid, sizeof(fw_bssid)); + err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &fw_bssid, ETHER_ADDR_LEN); + if (err) { + WL_ERR(("not inform disassoc for already disconnected\n")); + return; + } + + if (!curbssid) { + WL_ERR(("No bssid found\n")); + return; + } + + ifidx = dhd_net2idx(dhdp->info, ndev); + /* Advanced Logging supports only STA mode */ + if (!DHD_IF_ROLE_STA(dhdp, ifidx)) { + return; + } + + bzero(&as, sizeof(wl_assoc_status_t)); + as.ndev = ndev; + if (memcpy_s(as.addr, ETH_ALEN, curbssid, ETH_ALEN)) { + WL_ERR(("failed to memcpy bssid\n")); + return; + } + + /* Nomally, FW sends WLC_E_DISASSOC event twice + * to avoid printing twice, move it in WLC_DISASSOC sending path + * Set WLC_E_DISASSOC forcely instead of WLC_DISASSOC + */ + as.event_type = WLC_E_DISASSOC; + as.reason = reason; + wl_cfgvendor_advlog_connect_event(&as, FALSE, rssi); +} + +static s32 +wl_cfgvendor_advlog_get_target_rssi(struct bcm_cfg80211 *cfg, struct net_device *ndev, + int *rssi) +{ + s32 err = BCME_OK; + wl_bss_info_v109_t *bi; + char *buf = NULL; + + buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX); + if (!buf) { + WL_ERR(("buffer alloc failed.\n")); + return BCME_NOMEM; + } + + *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX); + err = wldev_iovar_getbuf(ndev, "target_bss_info", NULL, 0, + buf, WL_EXTRA_BUF_MAX, NULL); + if (unlikely(err)) { + WL_ERR(("Could not get bss info %d\n", err)); + err = BCME_ERROR; + goto exit; + } + + bi = (wl_bss_info_v109_t *)(buf + sizeof(uint32)); + *rssi = bi->RSSI; + +exit: + MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX); + return err; +} + +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ + static s32 wl_handle_assoc_events(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev, const wl_event_msg_t *e, @@ -12674,6 +14690,13 @@ wl_handle_assoc_events(struct bcm_cfg80211 *cfg, { s32 err = BCME_OK; wl_assoc_status_t as; + s32 advlog_err = BCME_OK; + int target_rssi = WLC_RSSI_INVALID; + bool query_rssi = TRUE; + + BCM_REFERENCE(advlog_err); + BCM_REFERENCE(target_rssi); + BCM_REFERENCE(query_rssi); if (!wdev || !e) { WL_ERR(("wrong input\n")); @@ -12689,6 +14712,7 @@ wl_handle_assoc_events(struct bcm_cfg80211 *cfg, as.data = data; as.data_len = ntoh32(e->datalen); as.event_msg = e; + as.assoc_state = assoc_state; (void)memcpy_s(as.addr, ETH_ALEN, e->addr.octet, ETH_ALEN); WL_INFORM_MEM(("[%s] Mode BSS. assoc_state:%d event:%d " @@ -12696,6 +14720,22 @@ wl_handle_assoc_events(struct bcm_cfg80211 *cfg, as.ndev->name, as.assoc_state, as.event_type, as.status, as.reason, cfg->eidx.in_progress, MAC2STRDBG((const u8*)(&e->addr)))); +#ifdef WL_CFGVENDOR_CUST_ADVLOG + if (as.event_type == WLC_E_AUTH || as.event_type == WLC_E_ASSOC) { + /* In AUTH/ASSOC REQ, FW doesn't have rssi in moving average windows + * so, WLC_GET_RSSI(IOVAR) result will return zero + * Try to get rssi from target_bss when state is not ASSOCIATED + * If it failed, allow to get rssi from WLC_GET_RSSI + */ + advlog_err = wl_cfgvendor_advlog_get_target_rssi(cfg, wdev->netdev, + &target_rssi); + if (advlog_err == BCME_OK) { + query_rssi = FALSE; + } + } + wl_cfgvendor_advlog_connect_event(&as, query_rssi, target_rssi); +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ + /* Handle FW events */ switch (as.event_type) { case WLC_E_AUTH: @@ -12709,9 +14749,19 @@ wl_handle_assoc_events(struct bcm_cfg80211 *cfg, #endif /* WL_CLIENT_SAE */ } + /* Update latest bssid */ + wl_update_prof(cfg, as.ndev, NULL, + (const void *)&e->addr, WL_PROF_LATEST_BSSID); /* Intentional fall through */ + /* fall through */ + fallthrough; case WLC_E_ASSOC: wl_get_auth_assoc_status(cfg, as.ndev, e, data); +#ifdef AUTH_ASSOC_STATUS_EXT + if ((as.reason == 0) && (as.status != WLC_E_STATUS_SUCCESS)) { + wl_get_auth_assoc_status_ext(cfg, as.ndev, e); + } +#endif /* AUTH_ASSOC_STATUS_EXT */ break; case WLC_E_ASSOC_RESP_IE: if (as.status != WLC_E_STATUS_SUCCESS) { @@ -12725,7 +14775,7 @@ wl_handle_assoc_events(struct bcm_cfg80211 *cfg, case WLC_E_DISASSOC_IND: wl_cfg80211_handle_deauth_ind(cfg, &as); /* intentional fall through */ - case WLC_E_DISASSOC: + fallthrough; case WLC_E_DEAUTH: as.link_action = wl_set_link_action(assoc_state, false); break; @@ -12749,6 +14799,26 @@ wl_handle_assoc_events(struct bcm_cfg80211 *cfg, return err; } +void +wl_handle_unexpected_assoc_states(struct bcm_cfg80211 *cfg, + struct wireless_dev *wdev, const wl_event_msg_t *e, + void *data, wl_assoc_state_t assoc_state) +{ + struct net_device *ndev = wdev->netdev; + u32 event = ntoh32(e->event_type); + u16 flags = ntoh16(e->flags); + + if ((assoc_state == WL_STATE_ASSOC_IDLE) && + (((event == WLC_E_LINK) && (flags & WLC_EVENT_MSG_LINK)) || + (event == WLC_E_ROAM) || (event == WLC_E_BSSID))) { + /* If link up/roam events are received, issue disassoc to + * firwmware to sync up the states. + */ + WL_ERR(("event_type:%d in assoc idle state. force sync fw state\n", event)); + wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING); + } +} + #define IS_OBSOLETE_EVENT(cur_idx, marker_idx) ((s32)(cur_idx - marker_idx) < 0) static s32 wl_notify_connect_status_sta(struct bcm_cfg80211 *cfg, @@ -12758,19 +14828,21 @@ wl_notify_connect_status_sta(struct bcm_cfg80211 *cfg, wl_assoc_state_t assoc_state; struct net_device *ndev; s32 ret = BCME_OK; - wl_event_idx_t *idx = &cfg->eidx; + wl_event_idx_t *idx; if (!wdev || !e) { WL_ERR(("wrong input\n")); return -EINVAL; } + mutex_lock(&cfg->connect_sync); + idx = &cfg->eidx; event_type = ntoh32(e->event_type); if (IS_OBSOLETE_EVENT(idx->in_progress, idx->min_connect_idx)) { /* If this event is enqd before the connect req, discard */ WL_ERR(("discard obsolete event:%d. cur_idx:%d min_idx:%d\n", event_type, idx->in_progress, idx->min_connect_idx)); - return -EINVAL; + goto exit; } ndev = wdev->netdev; @@ -12778,11 +14850,27 @@ wl_notify_connect_status_sta(struct bcm_cfg80211 *cfg, /* Join attempt via non-cfg80211 interface. * Don't send events to cfg80211 layer */ - WL_INFORM_MEM(("Event received in non-cfg80211" - " connect state. Ignore\n")); + WL_INFORM_MEM(("Event (%u) received in non-cfg80211" + " connect state. Ignore\n", event_type)); goto exit; } +#ifdef WL_ROAM_WAR + if (event_type == WLC_E_JOIN) + bzero((u8*)&cfg->roaming_bssid, ETHER_ADDR_LEN); + else if (wl_get_drv_status(cfg, CONNECTED, ndev)) { + if (event_type == WLC_E_AUTH && ntoh32(e->status) == WLC_E_STATUS_SUCCESS) + bcopy(&e->addr, &cfg->roaming_bssid, ETHER_ADDR_LEN); + else if (event_type == WLC_E_DEAUTH && + !ETHER_ISNULLADDR(&cfg->roaming_bssid.octet) && + memcmp(&e->addr, &cfg->roaming_bssid, ETHER_ADDR_LEN)) { + WL_MSG(ndev->name, "skip WLC_E_DEAUTH(%pM), roaming_bssid %pM\n", + &e->addr, &cfg->roaming_bssid); + goto exit; + } + } +#endif /* WL_ROAM_WAR */ + if (wl_get_drv_status(cfg, CONNECTING, ndev)) { assoc_state = WL_STATE_ASSOCIATING; } else if (wl_get_drv_status(cfg, CONNECTED, ndev)) { @@ -12790,10 +14878,18 @@ wl_notify_connect_status_sta(struct bcm_cfg80211 *cfg, } else { WL_ERR(("Unexpected event:%d in assoc idle state\n", event_type)); assoc_state = WL_STATE_ASSOC_IDLE; + wl_handle_unexpected_assoc_states(cfg, wdev, e, data, assoc_state); + ret = -EINVAL; + goto exit; } - ret = wl_handle_assoc_events(cfg, wdev, e, data, assoc_state); + /* Free up lock so that there is no conflict with post processing */ + mutex_unlock(&cfg->connect_sync); + + return wl_handle_assoc_events(cfg, wdev, e, data, assoc_state); + exit: + mutex_unlock(&cfg->connect_sync); return ret; } @@ -12845,50 +14941,6 @@ void wl_cfg80211_set_rmc_pid(struct net_device *dev, int pid) } #endif /* WL_RELMCAST */ -#ifdef WLAIBSS -void wl_cfg80211_set_txfail_pid(struct net_device *dev, int pid) -{ - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - if (pid > 0) - cfg->aibss_txfail_pid = pid; - WL_DBG(("set pid for aibss fail event : pid=%d\n", pid)); -} - -static s32 -wl_notify_aibss_txfail(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - u32 evt = ntoh32(e->event_type); - int ret = -1; -#ifdef PCIE_FULL_DONGLE - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - u32 reason = ntoh32(e->reason); -#endif - if (cfg->aibss_txfail_pid != 0) { -#ifdef PCIE_FULL_DONGLE - if (reason == AIBSS_PEER_FREE) { - uint8 ifindex; - wl_event_msg_t event; - - bzero(&event, sizeof(wl_event_msg_t)); - memcpy(&event, e, sizeof(wl_event_msg_t)); - - ifindex = (uint8)dhd_ifname2idx(dhd->info, event.ifname); - WL_INFORM_MEM(("Peer freed. Flow rings delete for peer.\n")); - dhd_flow_rings_delete_for_peer(dhd, ifindex, - (void *)&event.addr.octet[0]); - return 0; - } -#endif - ret = wl_netlink_send_msg(cfg->aibss_txfail_pid, AIBSS_EVENT_TXFAIL, - cfg->aibss_txfail_seq++, &e->addr, ETHER_ADDR_LEN); - } - - WL_DBG(("txfail : evt=%d, pid=%d, ret=%d, mac=" MACF "\n", - evt, cfg->aibss_txfail_pid, ret, CONST_ETHERP_TO_MACF(&e->addr))); - return ret; -} -#endif /* WLAIBSS */ #ifdef WL_RELMCAST static s32 wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, @@ -12902,9 +14954,11 @@ wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, case WLC_E_REASON_RMC_AR_LOST: case WLC_E_REASON_RMC_AR_NO_ACK: if (cfg->rmc_event_pid != 0) { +#ifdef OEM_ANDROID ret = wl_netlink_send_msg(cfg->rmc_event_pid, RMC_EVENT_LEADER_CHECK_FAIL, cfg->rmc_event_seq++, NULL, 0); +#endif // OEM_ANDROID } break; default: @@ -12925,14 +14979,16 @@ wl_handle_roam_exp_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, if (datalen) { wl_roam_exp_event_t *evt_data = (wl_roam_exp_event_t *)data; - if (evt_data->version == ROAM_EXP_EVENT_VERSION) { + if (evt_data->version == ROAM_EXP_EVENT_VERSION_1) { wlc_ssid_t *ssid = &evt_data->cur_ssid; struct wireless_dev *wdev; ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); if (ndev) { wdev = ndev->ieee80211_ptr; - wdev->ssid_len = min(ssid->SSID_len, (uint32)DOT11_MAX_SSID_LEN); - memcpy(wdev->ssid, ssid->SSID, wdev->ssid_len); + WDEV_CLIENT(wdev, ssid_len) = min(ssid->SSID_len, + (uint32)DOT11_MAX_SSID_LEN); + memcpy(WDEV_CLIENT(wdev, ssid), ssid->SSID, + WDEV_CLIENT(wdev, ssid_len)); WL_ERR(("SSID is %s\n", ssid->SSID)); wl_update_prof(cfg, ndev, NULL, ssid, WL_PROF_SSID); } else { @@ -12940,7 +14996,7 @@ wl_handle_roam_exp_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } } else { WL_ERR(("Version mismatch %d, expected %d", evt_data->version, - ROAM_EXP_EVENT_VERSION)); + ROAM_EXP_EVENT_VERSION_1)); } } return BCME_OK; @@ -12959,7 +15015,7 @@ static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfg if (datalen) { wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data; - if (evt_data->version == RSSI_MONITOR_VERSION) { + if (evt_data->version == RSSI_MONITOR_VERSION_1) { dhd_rssi_monitor_evt_t monitor_data; monitor_data.version = DHD_RSSI_MONITOR_EVT_VERSION; monitor_data.cur_rssi = evt_data->cur_rssi; @@ -12969,7 +15025,7 @@ static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfg &monitor_data, sizeof(monitor_data)); } else { WL_ERR(("Version mismatch %d, expected %d", evt_data->version, - RSSI_MONITOR_VERSION)); + RSSI_MONITOR_VERSION_1)); } } #endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */ @@ -12977,6 +15033,20 @@ static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfg } #endif /* RSSI_MONITOR_SUPPORT */ +#ifdef CSI_SUPPORT +static s32 +wl_notify_csi_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + int ret = BCME_OK; + + ret = dhd_csi_event_handler(dhdp, e, data); + + return ret; +} +#endif /* CSI_SUPPORT */ + static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) @@ -13020,7 +15090,7 @@ wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, * here only if WLC_E_LINK event is blocked for specific * security type. */ - if (IS_AKM_SUITE_FT(sec)) { + if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_SAE_FT(sec)) { wl_bss_roaming_done(cfg, ndev, e, data); #ifdef BCMDONGLEHOST /* Arm pkt logging timer */ @@ -13080,9 +15150,199 @@ wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } #ifdef CUSTOM_EVENT_PM_WAKE -uint32 last_dpm_upd_time = 0; /* ms */ -#define DPM_UPD_LMT_TIME ((CUSTOM_EVENT_PM_WAKE + (5)) * (1000) * (4)) /* ms */ -#define DPM_UPD_LMT_RSSI -85 /* dbm */ +#ifdef DHD_LOG_DUMP +static int +wl_return_from_ndev_to_coreidx(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + int err = 0, cur_chansp = 0; + chanspec_t cur_chanspec; + uint32 cur_band; + + if (!wl_get_drv_status(cfg, CONNECTED, ndev)) { + WL_ERR(("wl_return_from_ndev_to_coreidx: Not connected.\n")); + err = BCME_ERROR; + goto exit; + } + + err = wldev_iovar_getint(ndev, "chanspec", (int*)&cur_chansp); + if (err != BCME_OK) { + WL_ERR(("wl_return_from_ndev_to_coreidx: chanspec error (%d) \n", + err)); + goto exit; + } + + cur_chanspec = wl_chspec_driver_to_host(cur_chansp); + if (!wf_chspec_valid(cur_chanspec)) { + WL_ERR(("wl_return_from_ndev_to_coreidx: Invalid chanspec : %x\n", + cur_chanspec)); + err = BCME_ERROR; + goto exit; + } + + cur_band = CHSPEC_TO_WLC_BAND(CHSPEC_BAND(cur_chansp)); + if (cur_band == WLC_BAND_2G) { + return SOC_SLICE_AUX; + } else if (cur_band == WLC_BAND_5G || cur_band == WLC_BAND_6G) { + return SOC_SLICE_MAIN; + } else { + WL_ERR(("wl_return_from_ndev_to_coreidx: Invalid band : %x\n", + cur_band)); + err = BCME_ERROR; + goto exit; + } + +exit: + return err; +} +#endif /* DHD_LOG_DUMP */ +#endif /* CUSTOM_EVENT_PM_WAKE */ + +#ifdef CUSTOM_EVENT_PM_WAKE +char wl_check_pmstatus_time_str[DEBUG_DUMP_TIME_BUF_LEN]; +#define DPM_MAX_CONT_EVT_CNT (5u) /* 120sec * 5times = 10min */ +#define DPM_MIN_CONT_EVT_INTV (1000u) /* 1000ms */ +#define DPM_MAX_INACT_CNT (CUSTOM_EVENT_PM_WAKE * 4 * 6) /* 6 pkts/sec */ +#define DPM_LMT_RSSI -80 /* dbm */ + +#ifdef DHD_LOG_DUMP +static void +wl_check_pmstatus_memdump(struct bcm_cfg80211 *cfg, struct net_device *ndev, + uint32 cur_pm_dur, uint32 cur_total_pkts) +{ + dpm_info_t *dpm_info = NULL; + int val = 0, core_idx = -1; + dhd_pub_t *dhd = NULL; + + BCM_REFERENCE(dhd); + + val = wl_return_from_ndev_to_coreidx(cfg, ndev); + if (val < BCME_OK) { + return; + } + core_idx = val; + + if (core_idx >= SOC_MAX_SLICE) { + WL_ERR(("core_idx is wrong\n")); + return; + } + dpm_info = &cfg->dpm_info[core_idx]; + + dhd = (dhd_pub_t *)(cfg->pub); + if ((cur_total_pkts - dpm_info->dpm_total_pkts) > DPM_MAX_INACT_CNT) { + WL_INFORM(("Updated DPM event due to tx/rx packets(count: %d)\n", + (cur_total_pkts - dpm_info->dpm_total_pkts))); + goto exit; + } + + if (cur_pm_dur - dpm_info->dpm_prev_pmdur < DPM_MIN_CONT_EVT_INTV) { + dpm_info->dpm_cont_evt_cnt++; + WL_INFORM(("Updated DPM event counter for %s(%d).\n", + ndev->name, dpm_info->dpm_cont_evt_cnt)); + + if (dpm_info->dpm_cont_evt_cnt == DPM_MAX_CONT_EVT_CNT) { + scb_val_t scb_val; + s32 rssi = DPM_LMT_RSSI; + + val = wldev_ioctl_get(ndev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)); + if (val) { + WL_ERR(("Could not get rssi(%d)\n", val)); + } else { + rssi = wl_rssi_offset(dtoh32(scb_val.val)); + } + + WL_INFORM(("DPM event RSSI (%d)\n", rssi)); +#if defined(DHD_FW_COREDUMP) && !defined(CUSTOM_EVENT_PM_WAKE_MEMDUMP_DISABLED) + if (dhd->memdump_enabled && (rssi > DPM_LMT_RSSI)) { + dhd->memdump_type = DUMP_TYPE_CONT_EXCESS_PM_AWAKE; + dhd_bus_mem_dump(dhd); + } +#endif /* DHD_FW_COREDUMP && !CUSTOM_EVENT_PM_WAKE_MEMDUMP_DISABLED */ + } + if (dpm_info->dpm_cont_evt_cnt > DPM_MAX_CONT_EVT_CNT) { + WL_ERR(("[%s] Force Disassoc due to updated DPM event.\n", + ndev->name)); + wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING); + dpm_info->dpm_cont_evt_cnt = 0; + } + } else { + dpm_info->dpm_cont_evt_cnt = 0; + } + +exit: + dpm_info->dpm_prev_pmdur = cur_pm_dur; + dpm_info->dpm_total_pkts = cur_total_pkts; +} + +static s32 +wl_check_pmstatus_dump(struct bcm_cfg80211 *cfg, struct net_device *ndev, dhd_pub_t *dhd) +{ + s32 err = BCME_OK; + uint32 pm_dur = 0, total_pkts = 0; + const wl_cnt_wlc_t *wlc_cnt; + char *iovar_buf = NULL; + wlc_rev_info_t revinfo; + + /* Dump PM duration */ + err = wldev_iovar_getint(ndev, "pm_dur", &pm_dur); + if (unlikely(err)) { + WL_ERR(("error Get pm_dur (%d)\n", err)); + } else { + clear_debug_dump_time(wl_check_pmstatus_time_str); + get_debug_dump_time(wl_check_pmstatus_time_str); + WL_ERR(("PM duration : %d, TS(%s)\n", pm_dur, wl_check_pmstatus_time_str)); + } + + /* Get the device rev info */ + bzero(&revinfo, sizeof(revinfo)); + err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_REVINFO, + &revinfo, sizeof(revinfo)); + if (err != BCME_OK) { + return err; + } + + /* Dump counters */ + iovar_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (!iovar_buf) { + WL_ERR(("iovar_buf MALLOCZ failed\n")); + return -ENOMEM; + } + + err = wldev_iovar_getbuf(ndev, "counters", NULL, 0, + iovar_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(err)) { + WL_ERR(("counters error (%d) - size = %zu\n", err, sizeof(wl_cnt_wlc_t))); + goto exit; + } + + err = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WLC_IOCTL_MEDLEN, + revinfo.corerev); + if (err != BCME_OK) { + WL_ERR(("wl_check_pmstatus_dump: wl_cntbuf_to_xtlv_format ERR %d\n", + err)); + goto exit; + } + + if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) { + WL_ERR(("wl_check_pmstatus_dump: wlc_cnt NULL!\n")); + goto exit; + } + + WL_ERR(("PM counters(Tx/Rx/RxMul : %d/%d/%d \n", + dtoh32(wlc_cnt->txfrmsnt), + dtoh32(wlc_cnt->rxframe), dtoh32(wlc_cnt->rxmulti))); + total_pkts = dtoh32(wlc_cnt->txfrmsnt) + + dtoh32(wlc_cnt->rxframe) + dtoh32(wlc_cnt->rxmulti); + + wl_check_pmstatus_memdump(cfg, ndev, pm_dur, total_pkts); + +exit: + if (iovar_buf) { + MFREE(cfg->osh, iovar_buf, WLC_IOCTL_MEDLEN); + } + + return err; +} +#endif /* DHD_LOG_DUMP */ static s32 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, @@ -13090,114 +15350,165 @@ wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, { s32 err = BCME_OK; struct net_device *ndev = NULL; + struct wireless_dev *wdev = NULL; u8 *pbuf = NULL; - uint32 cur_dpm_upd_time = 0; dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - s32 rssi; -#ifdef SUPPORT_RSSI_SUM_REPORT - wl_rssi_ant_mimo_t rssi_ant_mimo; -#endif /* SUPPORT_RSSI_SUM_REPORT */ - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + u32 status = ntoh32(e->status); + u32 reason = ntoh32(e->reason); + wl_pmalert_t *pm_alert = (wl_pmalert_t *) data; + UNUSED_PARAMETER(dhd); + wdev = wl_get_wdev_by_fw_idx(cfg, e->bsscfgidx, e->ifidx); + WL_INFORM_MEM(("wl_check_pmstatus: wdev found! bssidx: %d, ifidx: %d", + e->bsscfgidx, e->ifidx)); + if (wdev == NULL || wdev->netdev == NULL) { + WL_ERR(("No wdev/ndev corresponding to bssidx: 0x%x found!", + e->bsscfgidx)); + return -EINVAL; + } + ndev = wdev->netdev; + + WL_ERR(("[%s] wl_check_pmstatus: status %d reason %d pm_alert->reasons %d\n", + ndev->name, status, reason, pm_alert->reasons)); + if (pm_alert->reasons == MPC_DUR_EXCEEDED) { + wl_pmalert_fixed_t *fixed; + fixed = (wl_pmalert_fixed_t *)pm_alert->data; + WL_ERR(("wl_check_pmstatus: pm_alert reason = MPC_DUR_EXCEEDED\n")); + WL_ERR(("wl_check_pmstatus: prev_pm_dur %d pm_dur %d curr_time %d " + "prev_stats_time %d cal_dur %d prev_cal_dur %d prev_frts_dur %d " + "prev_mpc_dur %d mpc_dur %d hw_macc 0x%04x sw_macc 0x%04x\n", + fixed->prev_pm_dur, fixed->pm_dur, fixed->curr_time, + fixed->prev_stats_time, fixed->cal_dur, fixed->prev_cal_dur, + fixed->prev_frts_dur, fixed->prev_mpc_dur, fixed->mpc_dur, + fixed->hw_macc, fixed->sw_macc)); + +#if defined(CUSTOM_EVENT_PM_WAKE_MEMDUMP_DISABLED) + WL_ERR(("[%s] Force Disassoc due to updated DPM event (MPC)\n", + ndev->name)); + wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING); +#else /* CUSTOM_EVENT_PM_WAKE_MEMDUMP_DISABLED */ +#if defined(DHD_FW_COREDUMP) + if (dhd->memdump_enabled) { + dhd->memdump_type = DUMP_TYPE_CONT_EXCESS_PM_AWAKE; + dhd_bus_mem_dump(dhd); + } +#endif /* DHD_FW_COREDUMP */ + + wl_cfg80211_handle_hang_event(ndev, + HANG_REASON_SLEEP_FAILURE, DUMP_TYPE_DONGLE_HOST_EVENT); +#endif /* CUSTOM_EVENT_PM_WAKE_MEMDUMP_DISABLED */ + } + + /* Dump PM status */ pbuf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); if (pbuf == NULL) { WL_ERR(("failed to allocate local pbuf\n")); return -ENOMEM; } - - err = wldev_iovar_getbuf_bsscfg(ndev, "dump", - "pm", strlen("pm"), pbuf, WLC_IOCTL_MEDLEN, + err = wldev_iovar_getbuf_bsscfg(ndev, "dump", "pm", strlen("pm"), pbuf, WLC_IOCTL_MEDLEN, 0, &cfg->ioctl_buf_sync); - if (err) { WL_ERR(("dump ioctl err = %d", err)); } else { WL_ERR(("PM status : %s\n", pbuf)); } - if (pbuf) { MFREE(cfg->osh, pbuf, WLC_IOCTL_MEDLEN); } - if (dhd->early_suspended) { - /* LCD off */ -#ifdef SUPPORT_RSSI_SUM_REPORT - /* Query RSSI sum across antennas */ - memset(&rssi_ant_mimo, 0, sizeof(rssi_ant_mimo)); - err = wl_get_rssi_per_ant(ndev, ndev->name, NULL, &rssi_ant_mimo); - if (err) { - WL_ERR(("Could not get rssi sum (%d)\n", err)); - } - rssi = rssi_ant_mimo.rssi_sum; - if (rssi == 0) -#endif /* SUPPORT_RSSI_SUM_REPORT */ - { - scb_val_t scb_val; - memset(&scb_val, 0, sizeof(scb_val_t)); - scb_val.val = 0; - err = wldev_ioctl_get(ndev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)); - if (err) { - WL_ERR(("Could not get rssi (%d)\n", err)); - } - rssi = wl_rssi_offset(dtoh32(scb_val.val)); - } - WL_ERR(("RSSI %d dBm\n", rssi)); - if (rssi > DPM_UPD_LMT_RSSI) { - return err; - } - } else { - /* LCD on */ - return err; - } - - if (last_dpm_upd_time == 0) { - last_dpm_upd_time = OSL_SYSUPTIME(); - } else { - cur_dpm_upd_time = OSL_SYSUPTIME(); - if (cur_dpm_upd_time - last_dpm_upd_time < DPM_UPD_LMT_TIME) { - scb_val_t scbval; - DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START), - dhd_net2idx(dhd->info, ndev), 0); - bzero(&scbval, sizeof(scb_val_t)); - - err = wldev_ioctl_set(ndev, WLC_DISASSOC, - &scbval, sizeof(scb_val_t)); - if (err < 0) { - WL_ERR(("Disassoc error %d\n", err)); - return err; - } - WL_ERR(("Force Disassoc due to updated DPM event.\n")); - - last_dpm_upd_time = 0; - } else { - last_dpm_upd_time = cur_dpm_upd_time; - } - } - +#ifdef DHD_LOG_DUMP + wl_check_pmstatus_dump(cfg, ndev, dhd); +#endif /* DHD_LOG_DUMP */ return err; } #endif /* CUSTOM_EVENT_PM_WAKE */ -#ifdef QOS_MAP_SET +#if defined(QOS_MAP_SET) || defined(WL_CUSTOM_MAPPING_OF_DSCP) +void +wl_store_up_table_netinfo(struct bcm_cfg80211 *cfg, + struct net_device *ndev, u8 *uptable) +{ + unsigned long flags; + struct net_info *netinfo; + + WL_CFG_NET_LIST_SYNC_LOCK(&cfg->net_list_sync, flags); + netinfo = _wl_get_netinfo_by_wdev(cfg, ndev->ieee80211_ptr); + if (netinfo) { + netinfo->qos_up_table = uptable; + } else { + WL_ERR(("netinfo not found for %s\n", ndev->name)); + } + WL_CFG_NET_LIST_SYNC_UNLOCK(&cfg->net_list_sync, flags); +} + +u8 * +wl_get_up_table_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + u8 *uptable = NULL; + unsigned long flags; + struct net_info *netinfo; + + WL_CFG_NET_LIST_SYNC_LOCK(&cfg->net_list_sync, flags); + netinfo = _wl_get_netinfo_by_wdev(cfg, ndev->ieee80211_ptr); + if (netinfo) { + uptable = netinfo->qos_up_table; + } + WL_CFG_NET_LIST_SYNC_UNLOCK(&cfg->net_list_sync, flags); + + return uptable; +} + /* get user priority table */ -uint8 * +u8 * wl_get_up_table(dhd_pub_t * dhdp, int idx) { - struct net_device *ndev; struct bcm_cfg80211 *cfg; + struct net_device *ndev; ndev = dhd_idx2net(dhdp, idx); if (ndev) { cfg = wl_get_cfg(ndev); if (cfg) - return (uint8 *)(cfg->up_table); + return wl_get_up_table_netinfo(cfg, ndev); } return NULL; } +#endif /* defined(QOS_MAP_SET) || defined(WL_CUSTOM_MAPPING_OF_DSCP) */ +#ifdef QOS_MAP_SET +static s32 +wl_config_up_table(struct bcm_cfg80211 *cfg, + struct net_device *ndev, bcm_tlv_t *qos_map_ie) +{ + u8 *up_table = wl_get_up_table_netinfo(cfg, ndev); + + /* Add/update table */ + if (qos_map_ie) { + WL_INFORM_MEM(("[%s] qos map add\n", ndev->name)); + if (!up_table) { + up_table = (uint8 *)MALLOCZ(cfg->osh, UP_TABLE_MAX); + if (up_table == NULL) { + WL_ERR(("** malloc failure for up_table\n")); + return -ENOMEM; + } + } + wl_set_up_table(up_table, qos_map_ie); + wl_store_up_table_netinfo(cfg, ndev, up_table); + if (wl_dbg_level & WL_DBG_DBG) { + prhex("*** UP Table", up_table, UP_TABLE_MAX); + } + } else if (up_table) { + /* No qos_map_ie. Delete old entry if present */ + wl_store_up_table_netinfo(cfg, ndev, NULL); + MFREE(cfg->osh, up_table, UP_TABLE_MAX); + WL_INFORM_MEM(("[%s] qos map del\n", ndev->name)); + } + + return BCME_OK; +} #endif /* QOS_MAP_SET */ -#if defined(DHD_LOSSLESS_ROAMING) || defined (DBG_PKT_MON) +#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON) /* * start packet logging in advance to make sure that EAPOL * messages are not missed during roaming @@ -13215,12 +15526,17 @@ wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, BCM_REFERENCE(sec); if (status == WLC_E_STATUS_SUCCESS && reason != WLC_E_REASON_INITIAL_ASSOC) { +#ifndef WES_SUPPORT WL_ERR(("Attempting roam with reason code : %d\n", reason)); +#else + WL_ERR(("Attempting roam with reason code : %d, Current %s mode\n", + reason, (cfg->ncho_mode ? "NCHO" : "Legacy Roam"))); +#endif /* WES_SUPPORT */ } #ifdef CONFIG_SILENT_ROAM if (dhdp->in_suspend && reason == WLC_E_REASON_SILENT_ROAM) { - dhdp->sroamed = TRUE; + cfg->sroamed = TRUE; } #endif /* CONFIG_SILENT_ROAM */ @@ -13246,7 +15562,9 @@ wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, dhdp->dequeue_prec_map = 1 << dhdp->flow_prio_map[PRIO_8021D_NC]; /* Restore flow control */ dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF); - +#if defined(BCMDONGLEHOST) && defined(OEM_ANDROID) + DHD_DISABLE_RUNTIME_PM(dhdp); +#endif /* BCMDONGLEHOST && OEM_ANDROID */ mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS)); #endif /* DHD_LOSSLESS_ROAMING */ @@ -13276,8 +15594,10 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) wl_assoc_info_t assoc_info; struct wl_connect_info *conn_info = wl_to_conn(cfg); s32 err = 0; + struct wl_security *sec; #ifdef QOS_MAP_SET bcm_tlv_t * qos_map_ie = NULL; + bcm_tlv_t * ext_cap_ie = NULL; #endif /* QOS_MAP_SET */ WL_DBG(("Enter \n")); @@ -13326,6 +15646,12 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) conn_info->req_ie_len, MAX_REQ_LINE)); return err; } + sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); + /* Update security wpa_auth for seamless roam, wpa_auth was earlier set to 0 */ + if (sec->wpa_auth == 0) { + wl_update_akm_from_assoc_ie(cfg, ndev, conn_info->req_ie, + conn_info->req_ie_len); + } } else { conn_info->req_ie_len = 0; } @@ -13352,17 +15678,27 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) return err; } +#if defined(DHD_DSCP_POLICY) + /* Look for vendor-specific WFA Capabilities IE in the assoc response */ + if (dhd_dscp_process_wfa_cap_ie(cfg, conn_info->resp_ie, conn_info->resp_ie_len) + != BCME_OK) { + WL_ERR(("dhd_dscp_process_wfa_cap_ie has failed \n")); + /* continue processing */ + } +#endif /* defined(DHD_DSCP_POLICY) */ + #ifdef QOS_MAP_SET + if (wl_dbg_level & WL_DBG_DBG) { + /* find extended cap IE */ + ext_cap_ie = bcm_parse_tlvs(conn_info->req_ie, conn_info->req_ie_len, + DOT11_MNG_EXT_CAP_ID); + prhex("ext_cap_ie", (u8 *)ext_cap_ie->data, ext_cap_ie->len); + } /* find qos map set ie */ - if ((qos_map_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len, - DOT11_MNG_QOS_MAP_ID)) != NULL) { - WL_DBG((" QoS map set IE found in assoc response\n")); - if (!cfg->up_table) { - cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX); - } - wl_set_up_table(cfg->up_table, qos_map_ie); - } else { - MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX); + qos_map_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len, + DOT11_MNG_QOS_MAP_ID); + if (wl_config_up_table(cfg, ndev, qos_map_ie) != BCME_OK) { + WL_ERR(("qos map config failed\n")); } #endif /* QOS_MAP_SET */ } else { @@ -13375,10 +15711,10 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) } static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, - bool update_ssid) + bool update_ssid, u8 *target_bssid) { struct cfg80211_bss *bss; - wl_bss_info_t *bi; + wl_bss_info_v109_t *bi; struct wlc_ssid *ssid; const struct bcm_tlv *tim; s32 beacon_interval; @@ -13395,9 +15731,15 @@ static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, wiphy = bcmcfg_to_wiphy(cfg); ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID); - curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + if (target_bssid) { + WL_INFORM_MEM(("Update bssinfo for target bssid\n")); + curbssid = target_bssid; + } else { + WL_INFORM_MEM(("Update bssinfo for ASSOCIATED bssid\n")); + curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + } bss = CFG80211_GET_BSS(wiphy, NULL, curbssid, - ssid->SSID, ssid->SSID_len); + ssid->SSID, ssid->SSID_len); buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX); if (!buf) { WL_ERR(("buffer alloc failed.\n")); @@ -13405,13 +15747,24 @@ static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, } mutex_lock(&cfg->usr_sync); *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX); - err = wldev_ioctl_get(ndev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX); + if (target_bssid) { + err = wldev_iovar_getbuf(ndev, "target_bss_info", NULL, 0, + buf, WL_EXTRA_BUF_MAX, NULL); + } else { + err = wldev_ioctl_get(ndev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX); + } if (unlikely(err)) { WL_ERR(("Could not get bss info %d\n", err)); goto update_bss_info_out; } - bi = (wl_bss_info_t *)(buf + 4); + bi = (wl_bss_info_v109_t *)(buf + 4); chspec = wl_chspec_driver_to_host(bi->chanspec); + /* chanspec queried for ASSOCIATED BSSID needs to be valid */ + if (!(target_bssid) && !wf_chspec_valid(chspec)) { + WL_ERR(("Invalid chanspec from get bss info %x\n", chspec)); + err = BCME_BADCHAN; + goto update_bss_info_out; + } wl_update_prof(cfg, ndev, NULL, &chspec, WL_PROF_CHAN); if (!bss) { @@ -13426,13 +15779,15 @@ static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, goto update_bss_info_out; } - WL_INFORM_MEM(("Updated the AP %pM detail in cache\n", curbssid)); + WL_INFORM_MEM(("Updated the AP " MACDBG " detail in cache\n", + MAC2STRDBG(curbssid))); ie = ((u8 *)bi) + bi->ie_offset; ie_len = bi->ie_length; beacon_interval = cpu_to_le16(bi->beacon_period); } else { u16 channel; - WL_INFORM_MEM(("Found AP in the cache - BSSID %pM\n", bss->bssid)); + WL_INFORM_MEM(("Found AP in the cache - BSSID " MACDBG "\n", + MAC2STRDBG(bss->bssid))); channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec)); freq = wl_channel_to_frequency(channel, CHSPEC_BAND(bi->chanspec)); bss->channel = ieee80211_get_channel(wiphy, freq); @@ -13450,7 +15805,7 @@ static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM); if (tim) { - dtim_period = tim->data[1]; + dtim_period = *(tim->data + 1); } else { /* * active scan was done so we could not get dtim @@ -13479,7 +15834,6 @@ update_bss_info_out: return err; } -#ifdef DHD_LOSSLESS_ROAMING static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, const wl_event_msg_t *e, void *data) @@ -13487,18 +15841,17 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, struct wl_connect_info *conn_info = wl_to_conn(cfg); s32 err = 0; u8 *curbssid; - chanspec_t *chanspec; + chanspec_t *chanspec, cur_chanspec; scb_val_t scbval; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); struct ieee80211_channel *notify_channel = NULL; u32 freq; - u32 cur_channel, cur_chanspec, orig_channel; + u32 cur_channel, orig_channel; #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */ #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || \ - defined(WL_FILS_ROAM_OFFLD) || defined(CFG80211_ROAM_API_GE_4_12) + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || defined(WL_FILS_ROAM_OFFLD) || \ + defined(CFG80211_ROAM_API_GE_4_12) struct cfg80211_roam_info roam_info; #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */ #if defined(WL_FILS_ROAM_OFFLD) @@ -13521,8 +15874,7 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, BCM_REFERENCE(dhdp); curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); chanspec = (chanspec_t *)wl_read_prof(cfg, ndev, WL_PROF_CHAN); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) /* Skip calling cfg80211_roamed If the channels are same and * the current bssid & the new bssid are same * Also clear timer roam_timeout. @@ -13535,15 +15887,19 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, cur_channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(cur_chanspec)); orig_channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(*chanspec)); if (dhdp->conf->chip != BCM43569_CHIP_ID) { - if ((orig_channel == cur_channel) && + if (((orig_channel == cur_channel) && memcmp(ðer_null, &cfg->last_roamed_addr, ETHER_ADDR_LEN)) && ((memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) || (memcmp(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN) == 0))) { - WL_DBG(("BSS already present, Skipping roamed event to upper layer\n")); + WL_INFORM_MEM(("BSS already present, Skipping roamed event to upper layer\n")); + WL_INFORM_MEM(("orig_chan/cur_chan=%d/%d, addr/curbssid/last_roamed_addr=%pM/%pM/%pM\n", + orig_channel, cur_channel, + (const u8*)(&e->addr), curbssid, (const u8*)(&cfg->last_roamed_addr))); goto fail; } } #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */ + wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet), WL_PROF_BSSID); if ((err = wl_get_assoc_ies(cfg, ndev)) != BCME_OK) { #ifdef BCMDONGLEHOST DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START), @@ -13551,17 +15907,6 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, #endif /* BCMDONGLEHOST */ WL_ERR(("Fetching Assoc IEs failed, Skipping roamed event to" " upper layer\n")); - /* To make sure disconnect, and fw sync, explictly send dissassoc - * for BSSID 00:00:00:00:00:00 issue - */ - bzero(&scbval, sizeof(scb_val_t)); - scbval.val = WLAN_REASON_DEAUTH_LEAVING; - memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); - scbval.val = htod32(scbval.val); - if (wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t)) < 0) { - WL_ERR(("WLC_DISASSOC error\n")); - } goto fail; } @@ -13572,35 +15917,45 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, } rssi = dtoh32(scbval.val); - WL_MSG(ndev->name, "%pM(ch:%3d/%sMHz) => %pM(ch:%3d/%sMHz, rssi: %3d)\n", - curbssid, orig_channel, + WL_MSG(ndev->name, "%pM(chan=%s-%d/%sMHz) => %pM(chan=%s-%d/%sMHz, rssi: %3d)\n", + curbssid, + CHSPEC2BANDSTR(*chanspec), wf_chspec_ctlchan(*chanspec), CHSPEC_IS20(*chanspec)?"20": CHSPEC_IS40(*chanspec)?"40": CHSPEC_IS80(*chanspec)?"80": CHSPEC_IS160(*chanspec)?"160":"??", - (const u8*)(&e->addr), cur_channel, + (const u8*)(&e->addr), + CHSPEC2BANDSTR(cur_chanspec), wf_chspec_ctlchan(cur_chanspec), CHSPEC_IS20(cur_chanspec)?"20": CHSPEC_IS40(cur_chanspec)?"40": CHSPEC_IS80(cur_chanspec)?"80": CHSPEC_IS160(cur_chanspec)?"160":"??", rssi); - wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet), WL_PROF_BSSID); curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); - if ((err = wl_update_bss_info(cfg, ndev, true)) != BCME_OK) { + if ((err = wl_update_bss_info(cfg, ndev, true, NULL)) != BCME_OK) { WL_ERR(("failed to update bss info, err=%d\n", err)); goto fail; } - if (cfg->wlc_ver.wlc_ver_major < PMKDB_WLC_VER) { + if (!WLC_PMKDB_SUPPORT(cfg->wlc_ver)) { wl_update_pmklist(ndev, cfg->pmk_list, err); } chanspec = (chanspec_t *)wl_read_prof(cfg, ndev, WL_PROF_CHAN); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */ + if (!wf_chspec_valid(*chanspec)) { + WL_ERR(("Invalid chanspec (%x) for roam, triggering a disassoc\n", *chanspec)); + err = BCME_BADCHAN; + goto fail; + } freq = wl_channel_to_frequency(wf_chspec_ctlchan(*chanspec), CHSPEC_BAND(*chanspec)); notify_channel = ieee80211_get_channel(wiphy, freq); + if (notify_channel == NULL) { + WL_ERR(("Invalid roam notify channel\n")); + err = BCME_BADCHAN; + goto fail; + } #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */ #ifdef WLFBT /* back up the given FBT key for the further supplicant request, @@ -13619,15 +15974,20 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, DHD_STATLOG_CTRL(dhdp, ST(REASSOC_INFORM), dhd_net2idx(dhdp->info, ndev), 0); #ifdef WL_EXT_IAPSTA - wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL); + wl_ext_in4way_sync(ndev, STA_REASSOC_RETRY, WL_EXT_STATUS_ROAMED, NULL); #endif #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || \ - defined(WL_FILS_ROAM_OFFLD) || defined(CFG80211_ROAM_API_GE_4_12) + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || defined(WL_FILS_ROAM_OFFLD) || \ + defined(CFG80211_ROAM_API_GE_4_12) memset(&roam_info, 0, sizeof(struct cfg80211_roam_info)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) || defined(CFG80211_BKPORT_MLO) + roam_info.links[0].channel = notify_channel; + roam_info.links[0].bssid = curbssid; +#else roam_info.channel = notify_channel; roam_info.bssid = curbssid; +#endif /* LINUX_VER >= 6.0 || CFG80211_BKPORT_MLO */ roam_info.req_ie = conn_info->req_ie; roam_info.req_ie_len = conn_info->req_ie_len; roam_info.resp_ie = conn_info->resp_ie; @@ -13647,8 +16007,7 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, cfg80211_roamed(ndev, &roam_info, GFP_KERNEL); #else cfg80211_roamed(ndev, -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS) notify_channel, #endif curbssid, @@ -13659,9 +16018,6 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, memcpy(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN); wl_set_drv_status(cfg, CONNECTED, ndev); -#if defined(DHD_ENABLE_BIGDATA_LOGGING) - cfg->roam_count++; -#endif /* DHD_ENABLE_BIGDATA_LOGGING */ #ifdef WL_BAM if (wl_adps_bad_ap_check(cfg, &e->addr)) { if (wl_adps_enabled(cfg, ndev)) { @@ -13680,12 +16036,19 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, return err; fail: + /* Trigger a disassoc to avoid state mismatch between driver and upper + * layers, since we skip roam indication to upper layers in fail: handling + */ + wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING); +#ifdef WL_EXT_IAPSTA + if (err) + wl_ext_in4way_sync(ndev, STA_NO_BTC_IN4WAY, WL_EXT_STATUS_DISCONNECTED, NULL); +#endif #ifdef DHD_LOSSLESS_ROAMING wl_del_roam_timeout(cfg); #endif /* DHD_LOSSLESS_ROAMING */ return err; } -#endif /* DHD_LOSSLESS_ROAMING */ static bool wl_cfg80211_verify_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, @@ -13740,7 +16103,7 @@ wl_get_fils_connect_params(struct bcm_cfg80211 *cfg, struct net_device *ndev) err = BCME_NOMEM; goto exit; } - iov_buf_out.version = WL_FILS_IOV_VERSION; + iov_buf_out.version = WL_FILS_IOV_VERSION_1_1; iov_buf_out.id = WL_FILS_CMD_GET_CONNECT_PARAMS; err = wldev_iovar_getbuf(ndev, "fils", (uint8*)&iov_buf_out, sizeof(bcm_iov_buf_t), iov_buf_in, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); @@ -13821,10 +16184,21 @@ wl_fillup_resp_params(struct bcm_cfg80211 *cfg, struct net_device *ndev, resp_params = (struct cfg80211_connect_resp_params *)params; resp_params->status = status; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) || defined(CFG80211_BKPORT_MLO) + resp_params->links[0].bssid = curbssid; + resp_params->links[0].bss = CFG80211_GET_BSS(wiphy, NULL, curbssid, + ssid->SSID, ssid->SSID_len); +#else resp_params->bssid = curbssid; resp_params->bss = CFG80211_GET_BSS(wiphy, NULL, curbssid, ssid->SSID, ssid->SSID_len); - if (!resp_params->bss) { +#endif /* LINUX_VER >= 6.0 || CFG80211_BKPORT_MLO */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) || defined(CFG80211_BKPORT_MLO) + if (!resp_params->links[0].bss) +#else + if (!resp_params->bss) +#endif /* LINUX_VER >= 6.0 || CFG80211_BKPORT_MLO */ + { WL_ERR(("null bss\n")); return BCME_ERROR; } @@ -13919,8 +16293,11 @@ wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, * For cases, there is no match available, * need to update the cache based on bss info from fw. */ - wl_update_bss_info(cfg, ndev, true); - if (cfg->wlc_ver.wlc_ver_major < PMKDB_WLC_VER) { + if ((err = wl_update_bss_info(cfg, ndev, true, NULL)) != BCME_OK) { + WL_ERR(("failed to update bss info, err=%d\n", err)); + goto exit; + } + if (!WLC_PMKDB_SUPPORT(cfg->wlc_ver)) { wl_update_pmklist(ndev, cfg->pmk_list, err); } wl_set_drv_status(cfg, CONNECTED, ndev); @@ -13934,7 +16311,7 @@ wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, completed = false; sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE; } - if (!ndev->ieee80211_ptr->ssid_len) { + if (!WDEV_CLIENT(ndev->ieee80211_ptr, ssid_len)) { /* In certain cases, the delayed cfg80211 work from * disconnect context will induce race conditions in * which the ssid_len will be cleared, but dhd is in @@ -13962,17 +16339,12 @@ wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, if (completed) { WL_MSG(ndev->name, "Report connect result - connection succeeded\n"); -#ifdef WL_EXT_IAPSTA - wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL); - wl_ext_iapsta_enable_master_if(ndev, TRUE); -#endif } else { WL_MSG(ndev->name, "Report connect result - connection failed\n"); #ifdef WL_EXT_IAPSTA wl_ext_in4way_sync(ndev, STA_NO_BTC_IN4WAY, WL_EXT_STATUS_DISCONNECTED, NULL); #endif } - #ifdef WL_FILS if ((sec->auth_type == NL80211_AUTHTYPE_FILS_SK_PFS) || (sec->auth_type == NL80211_AUTHTYPE_FILS_SK)) { @@ -14015,6 +16387,13 @@ wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, #endif /* WAPI */ } +#ifdef WL_EXT_IAPSTA + if (completed) { + wl_ext_in4way_sync(ndev, STA_REASSOC_RETRY, WL_EXT_STATUS_CONNECTED, NULL); + wl_ext_iapsta_enable_master_if(ndev, TRUE); + } +#endif + exit: CLR_TS(cfg, conn_start); return err; @@ -14046,27 +16425,9 @@ wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, return 0; } -#ifdef BT_WIFI_HANDOVER -static s32 -wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, - const wl_event_msg_t *e, void *data) -{ - struct net_device *ndev = NULL; - u32 event = ntoh32(e->event_type); - u32 datalen = ntoh32(e->datalen); - s32 err; - - WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n", event, datalen)); - ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); - err = wl_genl_send_msg(ndev, event, data, (u16)datalen, 0, 0); - - return err; -} -#endif /* BT_WIFI_HANDOVER */ - #ifdef WL_CFG80211_GON_COLLISION static void -wl_gon_req_collision(struct bcm_cfg80211 *cfg, wl_action_frame_t *tx_act_frm, +wl_gon_req_collision(struct bcm_cfg80211 *cfg, wl_action_frame_v1_t *tx_act_frm, wifi_p2p_pub_act_frame_t *rx_act_frm, struct net_device *ndev, struct ether_addr sa, struct ether_addr da) { @@ -14225,6 +16586,33 @@ int wl_cfg80211_get_ioctl_version(void) return ioctl_version; } +#if defined(DHD_DSCP_POLICY) + +/* + * Returns true if the incoming frame is the vendor-specific QoS Mgmt action frame, + * otherwise false. + */ +static bool +wl_is_qos_mgmt_vsaf(uint8 *body, uint body_len) +{ + dot11_action_vs_frmhdr_t *vsafh; + + if (body_len < DOT11_ACTION_VS_HDR_LEN) { + return false; + } + + vsafh = (dot11_action_vs_frmhdr_t *) body; + if ((vsafh->type == DSCP_POLICY_AF_OUI_TYPE) && + ((vsafh->subtype == DSCP_POLICY_REQ_FRAME) || + (vsafh->subtype == DSCP_POLICY_RESP_FRAME)) && + (bcmp(vsafh->OUI, WFA_OUI, WFA_OUI_LEN) == 0)) { + return (true); + } + + return false; +} +#endif /* DHD_DSCP_POLICY */ + static s32 wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) @@ -14240,7 +16628,7 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; wl_event_rx_frame_data_t *rxframe; u32 event; - u8 *mgmt_frame; + u8 *mgmt_frame, *rx_event_data; u8 bsscfgidx; u32 mgmt_frame_len; chanspec_t chspec; @@ -14251,17 +16639,32 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen))); return -EINVAL; } - mgmt_frame_len = ntoh32(e->datalen) - (uint32)sizeof(wl_event_rx_frame_data_t); - event = ntoh32(e->event_type); - bsscfgidx = e->bsscfgidx; + rxframe = (wl_event_rx_frame_data_t *)data; if (!rxframe) { WL_ERR(("rxframe: NULL\n")); return -EINVAL; } + + /* Handle different versions of Rx frame data */ + if (ntoh16(rxframe->version) == BCM_RX_FRAME_DATA_VERSION_1) { + mgmt_frame_len = ntoh32(e->datalen) - (uint32)sizeof(wl_event_rx_frame_data_v1_t); + rx_event_data = (u8 *) ((wl_event_rx_frame_data_v1_t *)rxframe + 1); + } else if (ntoh16(rxframe->version) == BCM_RX_FRAME_DATA_VERSION_2) { + mgmt_frame_len = ntoh32(e->datalen) - (uint32)sizeof(wl_event_rx_frame_data_v2_t); + rx_event_data = (u8 *) ((wl_event_rx_frame_data_v2_t *)rxframe + 1); + } else { + WL_ERR(("version mismatch for rx_frame_data, received = %d \n", + ntoh16(rxframe->version))); + return -EINVAL; + } + + event = ntoh32(e->event_type); + bsscfgidx = e->bsscfgidx; chspec = ntoh16(rxframe->channel); bzero(&bssid, ETHER_ADDR_LEN); ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + if ((ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) && (event == WLC_E_PROBREQ_MSG)) { /* Probe req event comes on wlan0 interface even though @@ -14290,21 +16693,30 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, freq = wl_channel_to_frequency(wf_chspec_ctlchan(chspec), CHSPEC_BAND(chspec)); #endif if (event == WLC_E_ACTION_FRAME_RX) { - u8 ioctl_buf[WLC_IOCTL_SMLEN]; - if ((err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", - NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx, - NULL)) != BCME_OK) { - WL_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err)); - goto exit; + { + u8 ioctl_buf[WLC_IOCTL_SMLEN]; + if ((err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", + NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx, + NULL)) != BCME_OK) { + WL_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err)); + goto exit; + } + eacopy(ioctl_buf, da.octet); + } + { + err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN); + if ((err < 0) && (err != BCME_NOTASSOCIATED)) { + WL_ERR(("WLC_GET_BSSID error %d\n", err)); + } + } + + if ((ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) && + cfg->randomized_gas_tx) { + da = cfg->af_randmac; } - err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN); - if (err < 0) - WL_ERR(("WLC_GET_BSSID error %d\n", err)); - memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN); err = wl_frame_get_mgmt(cfg, FC_ACTION, &da, &e->addr, &bssid, - &mgmt_frame, &mgmt_frame_len, - (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1)); + &mgmt_frame, &mgmt_frame_len, rx_event_data); if (err < 0) { WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n", mgmt_frame_len, CHSPEC_CHANNEL(chspec), freq)); @@ -14377,22 +16789,64 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } #endif /* TDLS_MSG_ONLY_WFD */ #endif /* WLTDLS */ + #ifdef QOS_MAP_SET } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_QOS) { /* update QoS map set table */ bcm_tlv_t * qos_map_ie = NULL; uint8 offset = DOT11_MGMT_HDR_LEN + DOT11_ACTION_FRMHDR_LEN; - if ((qos_map_ie = bcm_parse_tlvs(&mgmt_frame[offset], - mgmt_frame_len - offset, DOT11_MNG_QOS_MAP_ID)) != NULL) { - WL_DBG((" QoS map set IE found in QoS action frame\n")); - if (!cfg->up_table) { - cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX); - } - wl_set_up_table(cfg->up_table, qos_map_ie); - } else { - MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX); + + if (wl_dbg_level & WL_DBG_DBG) { + prhex("*** QoS Map Configure frame in DHD", + &mgmt_frame[offset], mgmt_frame_len - offset); + } + + qos_map_ie = bcm_parse_tlvs(&mgmt_frame[offset], mgmt_frame_len - offset, + DOT11_MNG_QOS_MAP_ID); + if (wl_config_up_table(cfg, ndev, qos_map_ie) != BCME_OK) { + WL_ERR(("qos map config failed\n")); } #endif /* QOS_MAP_SET */ + +#ifdef DHD_DSCP_POLICY + } else if ((mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_VS) || + (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_VSP)) { + + uint8 offset = DOT11_MGMT_HDR_LEN; + bool qos_mgmt_vsaf; + + /* Check if the frame is the vendor-specific QoS Mgmt AF */ + qos_mgmt_vsaf = wl_is_qos_mgmt_vsaf(&mgmt_frame[offset], + mgmt_frame_len - offset); + + if (qos_mgmt_vsaf == true) { + + struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); + + /* sec has the information about the security parameters + * for the current ongoing association. + */ + if (sec != NULL) { + int ret_val; + + if (wl_dbg_level & WL_DBG_DBG) { + prhex("QoS Mgmt VS frame in DHD", + &mgmt_frame[offset], + mgmt_frame_len - offset); + } + + /* process the DSCP Policy frame */ + ret_val = dhd_dscp_policy_process_vsaf( + cfg, ndev, &mgmt_frame[offset], + mgmt_frame_len - offset); + if (ret_val != BCME_OK) { + WL_ERR(("DSCP Policy frame processing " + "has failed = %d \n", ret_val)); + } + } + } +#endif /* DHD_DSCP_POLICY */ + #ifdef WBTEXT } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_RRM) { /* radio measurement category */ @@ -14436,6 +16890,7 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_DBG(("Recived action is the waiting action(%d)\n", action)); wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); + cfg->randomized_gas_tx = FALSE; /* Stop waiting for next AF. */ wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx); @@ -14625,37 +17080,24 @@ wl_cfg80211_ccode_evt_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgde const wl_event_msg_t *event, void *data) { s32 err = 0; +#ifndef EXT_REG_INFO struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); +#endif /* EXT_REG_INFO */ char country_str[WLC_CNTRY_BUF_SZ] = { 0 }; - struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); - wl_country_t cspec = {{0}, 0, {0}}; - if (strlcpy(country_str, data, WL_CCODE_LEN + 1) >= WLC_CNTRY_BUF_SZ) { + if (strlcpy(country_str, data, WL_CCODE_LEN+1) >= WLC_CNTRY_BUF_SZ) { return -EINVAL; } - if (strncmp(cfg->country, country_str, WL_CCODE_LEN) == 0) { + if (!strncmp(cfg->country, country_str, WL_CCODE_LEN)) { /* If country code is updated from command context, skip wiphy update */ - WL_MSG(dev->name, "No change in country (%s)\n", country_str); + WL_DBG_MEM(("No change in country (%s)\n", country_str)); return BCME_OK; } - WL_MSG(dev->name, "Updating new country %s\n", country_str); + WL_INFORM_MEM(("Updating new country %s\n", country_str)); - strlcpy(cspec.country_abbrev, country_str, WL_CCODE_LEN + 1); - strlcpy(cspec.ccode, country_str, WL_CCODE_LEN + 1); - err = dhd_conf_map_country_list(dhd_get_pub(dev), &cspec); - if (err) - dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec); - err = dhd_conf_set_country(dhd_get_pub(dev), &cspec); - if (err < 0) { - WL_ERR(("set country for %s as %s rev %d failed\n", - country_str, cspec.ccode, cspec.rev)); - } - dhd_conf_fix_country(dhd_get_pub(dev)); - - /* Indicate to upper layer for regdom change */ - err = wl_update_wiphybands(cfg, true); + err = wl_update_wiphybands(cfg, false); if (err != BCME_OK) { WL_ERR(("update wiphy bands failed\n")); return err; @@ -14663,6 +17105,12 @@ wl_cfg80211_ccode_evt_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgde wl_map_brcm_specifc_country_code(country_str); + /* update the country with new value */ +#ifdef EXT_REG_INFO + strlcpy(cfg->country, country_str, WLC_CNTRY_BUF_SZ); + + wl_cfg80211_regd_update(cfg, country_str); +#else if (!IS_REGDOM_SELF_MANAGED(wiphy)) { err = regulatory_hint(wiphy, country_str); if (err) { @@ -14670,7 +17118,10 @@ wl_cfg80211_ccode_evt_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgde return err; } WL_DBG_MEM(("regulatory hint notified for ccode change\n")); + } else { + wl_notify_regd(wiphy, country_str); } +#endif /* EXT_REG_INFO */ return err; } @@ -14712,6 +17163,7 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg) cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status; cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status; + cfg->evt_handler[WLC_E_OWE_INFO] = wl_notify_connect_status; cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status; cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status; cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; @@ -14729,9 +17181,14 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg) #ifdef PNO_SUPPORT cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; #endif /* PNO_SUPPORT */ +#ifdef WL_SCHED_SCAN + cfg->evt_handler[WLC_E_PFN_PARTIAL_RESULT] = wl_cfgscan_pfn_scanresult_handler; +#endif /* WL_SCHED_SCAN */ +#if defined(GSCAN_SUPPORT) || defined(WL_SCHED_SCAN) + cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_cfgscan_notify_pfn_complete; +#endif /* GSCAN_SUPPORT || WL_SCHED_SCAN */ #ifdef GSCAN_SUPPORT cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event; @@ -14751,15 +17208,9 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg) cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler; #endif /* WLTDLS */ cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status; -#ifdef WLAIBSS - cfg->evt_handler[WLC_E_AIBSS_TXFAIL] = wl_notify_aibss_txfail; -#endif /* WLAIBSS */ #ifdef WL_RELMCAST cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status; #endif /* WL_RELMCAST */ -#ifdef BT_WIFI_HANDOVER - cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req; -#endif #ifdef WL_NAN cfg->evt_handler[WLC_E_NAN_CRITICAL] = wl_cfgnan_notify_nan_status; cfg->evt_handler[WLC_E_NAN_NON_CRITICAL] = wl_cfgnan_notify_nan_status; @@ -14769,7 +17220,7 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg) #ifdef CUSTOM_EVENT_PM_WAKE cfg->evt_handler[WLC_E_EXCESS_PM_WAKE_EVENT] = wl_check_pmstatus; #endif /* CUSTOM_EVENT_PM_WAKE */ -#if defined(DHD_LOSSLESS_ROAMING) || defined (DBG_PKT_MON) +#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON) cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status; #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */ cfg->evt_handler[WLC_E_ROAM_START] = wl_notify_roam_start_status; @@ -14783,14 +17234,15 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg) #endif /* WL_BCNRECV */ #ifdef WL_MBO cfg->evt_handler[WLC_E_MBO] = wl_mbo_event_handler; +#ifdef WL_MBO_HOST + cfg->evt_handler[WLC_E_BSSTRANS] = wl_mbo_btm_event_handler; +#endif /* WL_MBO_HOST */ #endif /* WL_MBO */ #ifdef WL_CAC_TS cfg->evt_handler[WLC_E_ADDTS_IND] = wl_cfg80211_cac_event_handler; cfg->evt_handler[WLC_E_DELTS_IND] = wl_cfg80211_cac_event_handler; #endif /* WL_CAC_TS */ -#if defined(WL_MBO) || defined(WL_OCE) cfg->evt_handler[WLC_E_PRUNE] = wl_bssid_prune_event_handler; -#endif /* WL_MBO || WL_OCE */ #ifdef RTT_SUPPORT cfg->evt_handler[WLC_E_PROXD] = wl_cfg80211_rtt_event_handler; #endif @@ -14798,13 +17250,18 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg) cfg->evt_handler[WLC_E_BSS_LOAD] = wl_cfg80211_bssload_report_event_handler; #endif /* WL_CHAN_UTIL */ #ifdef WL_TWT - cfg->evt_handler[WLC_E_TWT_SETUP] = wl_notify_twt_event; - cfg->evt_handler[WLC_E_TWT_TEARDOWN] = wl_notify_twt_event; - cfg->evt_handler[WLC_E_TWT_INFO_FRM] = wl_notify_twt_event; + cfg->evt_handler[WLC_E_TWT] = wl_notify_twt_event; +#else +#ifdef WL_TWT_HAL_IF + cfg->evt_handler[WLC_E_TWT] = wl_cfgvendor_notify_twt_event; +#endif /* WL_TWT_HAL_IF */ #endif /* WL_TWT */ #ifdef WL_CLIENT_SAE cfg->evt_handler[WLC_E_JOIN_START] = wl_notify_start_auth; #endif /* WL_CLIENT_SAE */ +#ifdef CSI_SUPPORT + cfg->evt_handler[WLC_E_CSI] = wl_notify_csi_status; +#endif /* CSI_SUPPORT */ } #if defined(STATIC_WL_PRIV_STRUCT) @@ -14868,7 +17325,7 @@ static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg) { WL_DBG(("Enter \n")); - cfg->scan_results = (wl_scan_results_t *)MALLOCZ(cfg->osh, + cfg->scan_results = (wl_scan_results_v109_t *)MALLOCZ(cfg->osh, WL_SCAN_BUF_MAX); if (unlikely(!cfg->scan_results)) { WL_ERR(("Scan results alloc failed\n")); @@ -14943,6 +17400,13 @@ static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg) WL_ERR(("Single PMK info list allocation falure\n")); goto init_priv_mem_out; } +#ifdef DEBUG_SETROAMMODE + cfg->roamoff_info = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->roamoff_info)); + if (unlikely(!cfg->roamoff_info)) { + WL_ERR(("Debug roamoff info allocation falure\n")); + goto init_priv_mem_out; + } +#endif /* DEBUG_SETROAMMODE */ return 0; @@ -14973,6 +17437,9 @@ static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg) MFREE(cfg->osh, cfg->afx_hdl, sizeof(*cfg->afx_hdl)); } MFREE(cfg->osh, cfg->spmk_info_list, sizeof(*cfg->spmk_info_list)); +#ifdef DEBUG_SETROAMMODE + MFREE(cfg->osh, cfg->roamoff_info, sizeof(*cfg->roamoff_info)); +#endif /* DEBUG_SETROAMMODE */ } @@ -15046,6 +17513,9 @@ static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg) /* restore prec_map to ALLPRIO */ dhdp->dequeue_prec_map = ALLPRIO; del_timer_sync(&cfg->roam_timeout); +#if defined(BCMDONGLEHOST) && defined(OEM_ANDROID) + DHD_ENABLE_RUNTIME_PM(dhdp); +#endif /* BCMDONGLEHOST && OEM_ANDROID */ } static void wl_roam_timeout(unsigned long data) @@ -15057,14 +17527,27 @@ static void wl_roam_timeout(unsigned long data) /* restore prec_map to ALLPRIO */ dhdp->dequeue_prec_map = ALLPRIO; +#if defined(BCMDONGLEHOST) && defined(OEM_ANDROID) + DHD_ENABLE_RUNTIME_PM(dhdp); +#endif /* BCMDONGLEHOST && OEM_ANDROID */ } #endif /* DHD_LOSSLESS_ROAMING */ -#if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL) +#ifdef WL_CP_COEX #define CP_CHAN_INFO_RAT_MODE_LTE 3 #define CP_CHAN_INFO_RAT_MODE_NR5G 7 -int g_mhs_chan_for_cpcoex = 0; +struct wl_cp_coex g_cx; + +#define CP_N40_FREQ_STR 460000u +#define CP_N40_FREQ_END 480000u +#define CP_N41_FREQ_STR 499200u +#define CP_N41_FREQ_END 537999u + +#define CP_B40_FREQ_STR 38650u +#define CP_B40_FREQ_END 39649u +#define CP_B41_FREQ_STR 39650u +#define CP_B41_FREQ_END 41589u struct __packed cam_cp_noti_info { u8 rat; @@ -15073,13 +17556,13 @@ struct __packed cam_cp_noti_info { }; int -wl_cfg80211_send_msg_to_ril() +wl_cfg80211_send_msg_to_ril(void) { int id, buf = 1; id = IPC_SYSTEM_CP_CHANNEL_INFO; dev_ril_bridge_send_msg(id, sizeof(int), &buf); - WL_ERR(("[BeyondX] send message to ril.\n")); + WL_ERR(("[CP_COEX] send message to ril.\n")); OSL_SLEEP(500); return 0; @@ -15091,10 +17574,8 @@ wl_cfg80211_ril_bridge_notifier_call(struct notifier_block *nb, { struct dev_ril_bridge_msg *msg; struct cam_cp_noti_info *cp_noti_info; - static int mhs_channel_for_4g, mhs_channel_for_5g; - static int recv_msg_4g, recv_msg_5g; - WL_ERR(("[BeyondX] receive message from ril.\n")); + WL_ERR(("[CP_COEX] receive message from ril.\n")); msg = (struct dev_ril_bridge_msg *)buf; if (msg->dev_id == IPC_SYSTEM_CP_CHANNEL_INFO && @@ -15111,42 +17592,45 @@ wl_cfg80211_ril_bridge_notifier_call(struct notifier_block *nb, /* LTE/5G Band/Freq information => Mobile Hotspot channel mapping. * LTE/B40: 38650~39649 => Ch.11 * LTE/B41: 39650~41589 => Ch.1 + * 5G/N40: 460000~480000 => Ch.11 * 5G/N41: 499200~537999 => Ch.1 */ if (rat == CP_CHAN_INFO_RAT_MODE_LTE) { - recv_msg_4g = 1; - if (channel >= 38650 && channel <= 39649) { - mhs_channel_for_4g = 11; - } else if (channel >= 39650 && channel <= 41589) { - mhs_channel_for_4g = 1; + if (channel >= CP_B40_FREQ_STR && channel <= CP_B40_FREQ_END) { + g_cx.ch_4g = 11; + } else if (channel >= CP_B41_FREQ_STR && channel <= CP_B41_FREQ_END) { + g_cx.ch_4g = 1; } - } - if (rat == CP_CHAN_INFO_RAT_MODE_NR5G) { - recv_msg_5g = 1; - if (channel >= 499200 && channel <= 537999) { - mhs_channel_for_5g = 1; + } else if (rat == CP_CHAN_INFO_RAT_MODE_NR5G) { + if (channel >= CP_N40_FREQ_STR && channel <= CP_N40_FREQ_END) { + g_cx.ch_5g = 11; + } else if (channel >= CP_N41_FREQ_STR && channel <= CP_N41_FREQ_END) { + g_cx.ch_5g = 1; } + } else { + WL_ERR(("[CP_COEX] Not interested packet. rat:%u, band:%u, channel:%u\n", + rat, band, channel)); + return 0; } - WL_DBG(("[BeyondX] rat: %u, band: %u, channel: %u, mhs_channel_for_4g: %u, " - "mhs_channel_for_5g: %u\n", rat, band, channel, - mhs_channel_for_4g, mhs_channel_for_5g)); + WL_ERR(("[CP_COEX] rat:%u, band:%u, channel:%u, ch_4g:%d, ch_5g:%d\n", + rat, band, channel, g_cx.ch_4g, g_cx.ch_5g)); - if (recv_msg_4g && recv_msg_5g) { - if (mhs_channel_for_4g && mhs_channel_for_5g) { - /* if 4G/B40 + 5G/N41, select channel 6 for MHS */ - if (mhs_channel_for_4g == 11 && mhs_channel_for_5g == 1) { - g_mhs_chan_for_cpcoex = 6; - /* if 4G(except for B40) + 5G/N41, select channel 1 for MHS */ - } else { - g_mhs_chan_for_cpcoex = 1; - } + /* only consider 4G or 5G */ + if (g_cx.ch_4g && g_cx.ch_5g) { + /* if 4G/B40 + 5G/N41 or 4G/B41 + 5GN40, select channel 6 for MHS + * if ch_4g != ch_5g then select Ch.6 else then Ch.1 + */ + if ((g_cx.ch_4g == 11 && g_cx.ch_5g == 1) || + (g_cx.ch_4g == 1 && g_cx.ch_5g == 11)) { + g_cx.ch_cpcoex = 6; + /* select channel 1 for other case */ } else { - g_mhs_chan_for_cpcoex = mhs_channel_for_4g ? mhs_channel_for_4g : - mhs_channel_for_5g ? mhs_channel_for_5g : 0; + g_cx.ch_cpcoex = 1; } - mhs_channel_for_4g = mhs_channel_for_5g = 0; - recv_msg_4g = recv_msg_5g = 0; + } else { + g_cx.ch_cpcoex = g_cx.ch_4g ? g_cx.ch_4g : + g_cx.ch_5g ? g_cx.ch_5g : 0; } } @@ -15158,7 +17642,7 @@ static struct notifier_block wl_cfg80211_ril_bridge_notifier = { }; static bool wl_cfg80211_ril_bridge_notifier_registered = FALSE; -#endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */ +#endif /* WL_CP_COEX */ static s32 wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, @@ -15180,7 +17664,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, wdev = ndev_to_wdev(dev); if (!wdev) { - WL_DBG(("wdev null. Do nothing\n")); + WL_DBG(("wdev(%s) null. Do nothing\n", dev->name)); return NOTIFY_DONE; } @@ -15291,8 +17775,9 @@ void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable) if (iter->ndev && iter->wdev && iter->wdev->iftype == NL80211_IFTYPE_STATION) { if (wldev_iovar_setint(iter->ndev, "roam_off", TRUE) - == BCME_OK) { + == BCME_OK) { iter->roam_off = TRUE; + ROAMOFF_DBG_SAVE(iter->ndev, SET_ROAM_CONCRT_MODE, TRUE); } else { WL_ERR(("error to enable roam_off\n")); @@ -15309,8 +17794,10 @@ void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable) iter->wdev->iftype == NL80211_IFTYPE_STATION) { if (iter->roam_off != WL_INVALID) { if (wldev_iovar_setint(iter->ndev, "roam_off", FALSE) - == BCME_OK) { + == BCME_OK) { iter->roam_off = FALSE; + ROAMOFF_DBG_SAVE(iter->ndev, + SET_ROAM_CONCRT_MODE, FALSE); } else { WL_ERR(("error to disable roam_off\n")); @@ -15353,7 +17840,7 @@ static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg) (s32 *)&chanspec) == BCME_OK) { chanspec = wl_chspec_driver_to_host(chanspec); ctl_chan = wf_chspec_ctlchan(chanspec); - band = CHSPEC_BAND(chanspec); + band = CHSPEC_TO_WLC_BAND(CHSPEC_BAND(chanspec)); wl_update_prof(cfg, iter->ndev, NULL, &chanspec, WL_PROF_CHAN); } @@ -15386,7 +17873,7 @@ static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg) } int -wl_cfg80211_determine_p2p_rsdb_scc_mode(struct bcm_cfg80211 *cfg) +wl_cfg80211_determine_rsdb_scc_mode(struct bcm_cfg80211 *cfg) { struct net_info *iter, *next; u32 chanspec = 0; @@ -15394,7 +17881,7 @@ wl_cfg80211_determine_p2p_rsdb_scc_mode(struct bcm_cfg80211 *cfg) u32 band = 0; u32 pre_band = INVCHANSPEC; bool is_rsdb_supported = FALSE; - bool rsdb_or_scc_mode = FALSE; + bool rsdb_or_scc_mode = TRUE; #ifdef BCMDONGLEHOST is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE); @@ -15415,7 +17902,7 @@ wl_cfg80211_determine_p2p_rsdb_scc_mode(struct bcm_cfg80211 *cfg) if (wldev_iovar_getint(iter->ndev, "chanspec", (s32 *)&chanspec) == BCME_OK) { chanspec = wl_chspec_driver_to_host(chanspec); - band = CHSPEC_BAND(chanspec); + band = CHSPEC_TO_WLC_BAND(CHSPEC_BAND(chanspec)); } if (pre_band == INVCHANSPEC && chanspec) { @@ -15425,9 +17912,6 @@ wl_cfg80211_determine_p2p_rsdb_scc_mode(struct bcm_cfg80211 *cfg) if ((pre_band == band) && (pre_chanspec != chanspec)) { /* VSDB case */ rsdb_or_scc_mode = FALSE; - } else { - /* RSDB/SCC case */ - rsdb_or_scc_mode = TRUE; } } } @@ -15497,7 +17981,7 @@ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_ #ifdef DISABLE_FRAMEBURST_VSDB if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) && wl_cfg80211_is_concurrent_mode(primary_dev)) { - rsdb_scc_flag = wl_cfg80211_determine_p2p_rsdb_scc_mode(cfg); + rsdb_scc_flag = wl_cfg80211_determine_rsdb_scc_mode(cfg); wl_cfg80211_set_frameburst(cfg, rsdb_scc_flag); } #endif /* DISABLE_FRAMEBURST_VSDB */ @@ -15674,6 +18158,10 @@ static s32 wl_init_priv(struct bcm_cfg80211 *cfg) cfg->pmk_list->pmkids.count = 0; cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3; +#ifdef WL_CELLULAR_CHAN_AVOID + wl_cellavoid_init(cfg); +#endif /* WL_CELLULAR_CHAN_AVOID */ + #ifdef CONFIG_SLEEP_MONITOR sleep_monitor_register_ops(cfg, &wlan_sleep_monitor_ops, SLEEP_MONITOR_WIFI); @@ -15687,13 +18175,16 @@ static void wl_deinit_priv(struct bcm_cfg80211 *cfg) wl_destroy_event_handler(cfg); wl_flush_eq(cfg); wl_link_down(cfg); -#if defined (WL_SCHED_SCAN) && defined (SCHED_SCAN_DELAYED_WORK) +#ifdef WL_SCHED_SCAN cancel_delayed_work_sync(&cfg->sched_scan_stop_work); #endif /* WL_SCHED_SCAN */ del_timer_sync(&cfg->scan_timeout); #ifdef DHD_LOSSLESS_ROAMING del_timer_sync(&cfg->roam_timeout); #endif +#ifdef WL_CELLULAR_CHAN_AVOID + wl_cellavoid_deinit(cfg); +#endif /* WL_CELLULAR_CHAN_AVOID */ wl_deinit_priv_mem(cfg); if (wl_cfg80211_netdev_notifier_registered) { wl_cfg80211_netdev_notifier_registered = FALSE; @@ -15750,7 +18241,7 @@ static s32 wl_cfg80211_detach_p2p(struct bcm_cfg80211 *cfg) return 0; } -#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */ +#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ #if defined(BCMDONGLEHOST) static s32 wl_cfg80211_attach_post(struct net_device *ndev) @@ -15795,8 +18286,10 @@ static s32 wl_cfg80211_attach_post(struct net_device *ndev) #endif /* WL_ENABLE_P2P_IF */ cfg->p2p_supported = true; } else if (ret == 0) { - if ((err = wl_cfgp2p_init_priv(cfg)) != 0) + if ((err = wl_cfgp2p_init_priv(cfg)) != 0) { goto fail; + } + cfg->p2p_supported = true; } else { /* SDIO bus timeout */ err = -ENODEV; @@ -15804,7 +18297,6 @@ static s32 wl_cfg80211_attach_post(struct net_device *ndev) } } } - wl_set_drv_status(cfg, READY, ndev); fail: return err; } @@ -15930,11 +18422,11 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *context) } } -#if defined(OEM_ANDROID) && defined(COEX_DHCP) +#if defined(OEM_ANDROID) cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev); if (!cfg->btcoex_info) goto cfg80211_attach_out; -#endif /* defined(OEM_ANDROID) && defined(COEX_DHCP) */ +#endif /* defined(OEM_ANDROID) */ #if defined(SUPPORT_RANDOM_MAC_SCAN) cfg->random_mac_enabled = FALSE; @@ -15948,7 +18440,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *context) err = wl_cfg80211_attach_p2p(cfg); if (err) goto cfg80211_attach_out; -#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */ +#endif #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS) /* wlan scan_supp timer and work thread info */ @@ -15956,13 +18448,19 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *context) INIT_WORK(&cfg->wlan_work, wl_cfg80211_work_handler); #endif /* DHCP_SCAN_SUPPRESS */ -#if defined (WL_SCHED_SCAN) && defined (SCHED_SCAN_DELAYED_WORK) +#ifdef WL_SCHED_SCAN INIT_DELAYED_WORK(&cfg->sched_scan_stop_work, wl_cfgscan_sched_scan_stop_work); #endif /* WL_SCHED_SCAN */ INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler); + INIT_DELAYED_WORK(&cfg->recovery_work, wl_cfg80211_recovery_handler); INIT_DELAYED_WORK(&cfg->loc.work, wl_cfgscan_listen_complete_work); INIT_DELAYED_WORK(&cfg->ap_work, wl_cfg80211_ap_timeout_work); mutex_init(&cfg->pm_sync); + +#ifdef TPUT_DEBUG_DUMP + INIT_DELAYED_WORK(&cfg->tput_debug_work, wl_cfgdbg_tput_debug_work); +#endif /* TPUT_DEBUG_DUMP */ + #ifdef WL_NAN err = wl_cfgnan_attach(cfg); if (err) { @@ -15975,9 +18473,13 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *context) wl_bad_ap_mngr_init(cfg); #endif /* WL_BAM */ -#ifdef BIGDATA_SOFTAP - wl_attach_ap_stainfo(cfg); -#endif /* BIGDATA_SOFTAP */ +#if defined(DHD_DSCP_POLICY) + err = dhd_dscp_policy_attach(cfg); + if (err != BCME_OK) { + WL_ERR(("Failed to attach DSCP module %d\n", err)); + goto cfg80211_attach_out; + } +#endif /* defined(DHD_DSCP_POLICY) */ return err; @@ -15997,10 +18499,10 @@ void wl_cfg80211_detach(struct bcm_cfg80211 *cfg) */ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL); -#if defined(OEM_ANDROID) && defined(COEX_DHCP) +#if defined(OEM_ANDROID) wl_cfg80211_btcoex_deinit(); cfg->btcoex_info = NULL; -#endif /* defined(OEM_ANDROID) && defined(COEX_DHCP) */ +#endif /* defined(OEM_ANDROID) */ wl_setup_rfkill(cfg, FALSE); @@ -16016,20 +18518,25 @@ void wl_cfg80211_detach(struct bcm_cfg80211 *cfg) #ifdef WL_STATIC_IF wl_cfg80211_unregister_static_if(cfg); #endif /* WL_STATIC_IF */ +#if defined(WL_CFG80211_P2P_DEV_IF) + if (cfg->p2p_wdev) + wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg); +#endif /* WL_CFG80211_P2P_DEV_IF */ #if defined(WL_ENABLE_P2P_IF) || defined (WL_NEWCFG_PRIVCMD_SUPPORT) wl_cfg80211_detach_p2p(cfg); -#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */ +#endif #ifdef WL_BAM wl_bad_ap_mngr_deinit(cfg); #endif /* WL_BAM */ -#ifdef BIGDATA_SOFTAP - wl_detach_ap_stainfo(cfg); -#endif /* BIGDATA_SOFTAP */ - #ifdef WL_NAN wl_cfgnan_detach(cfg); #endif /* WL_NAN */ + +#if defined(DHD_DSCP_POLICY) + dhd_dscp_policy_detach(cfg); +#endif /* defined(DHD_DSCP_POLICY) */ + wl_cfg80211_ibss_vsie_free(cfg); wl_dealloc_netinfo_by_wdev(cfg, cfg->wdev); wl_cfg80211_set_bcmcfg(NULL); @@ -16050,8 +18557,8 @@ void wl_cfg80211_detach(struct bcm_cfg80211 *cfg) WL_DBG(("Exit\n")); } -#if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL) -void wl_cfg80211_register_dev_ril_bridge_event_notifier() +#ifdef WL_CP_COEX +void wl_cfg80211_register_dev_ril_bridge_event_notifier(void) { WL_DBG(("Enter\n")); if (!wl_cfg80211_ril_bridge_notifier_registered) { @@ -16065,7 +18572,7 @@ void wl_cfg80211_register_dev_ril_bridge_event_notifier() } } -void wl_cfg80211_unregister_dev_ril_bridge_event_notifier() +void wl_cfg80211_unregister_dev_ril_bridge_event_notifier(void) { WL_DBG(("Enter\n")); if (wl_cfg80211_ril_bridge_notifier_registered) { @@ -16073,15 +18580,15 @@ void wl_cfg80211_unregister_dev_ril_bridge_event_notifier() unregister_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier); } } -#endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */ +#endif /* WL_CP_COEX */ static void wl_print_event_data(struct bcm_cfg80211 *cfg, uint32 event_type, const wl_event_msg_t *e) { s32 status = ntoh32(e->status); s32 reason = ntoh32(e->reason); - s32 ifidx = ntoh32(e->ifidx); - s32 bssidx = ntoh32(e->bsscfgidx); + u8 ifidx = e->ifidx; + u8 bssidx = e->bsscfgidx; switch (event_type) { case WLC_E_ESCAN_RESULT: @@ -16184,7 +18691,7 @@ fail: */ s32 wl_cfg80211_handle_critical_events(struct bcm_cfg80211 *cfg, - struct wireless_dev *wdev, const wl_event_msg_t * e) + struct wireless_dev *wdev, const wl_event_msg_t * e, void *data) { s32 ret = BCME_ERROR; u32 event_type = ntoh32(e->event_type); @@ -16225,7 +18732,7 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) #ifdef OEM_ANDROID if (cfg->event_workq == NULL) { - WL_ERR(("Event handler is not created\n")); + WL_ERR(("Event handler is not created (%s)\n", bcmevent_get_name(event_type))); return; } #endif /* OEM_ANDROID */ @@ -16253,7 +18760,8 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) } /* Handle wl_cfg80211_critical_events */ - if (wl_cfg80211_handle_critical_events(cfg, netinfo->wdev, e) == BCME_OK) { + if (wl_cfg80211_handle_critical_events(cfg, + netinfo->wdev, e, data) == BCME_OK) { return; } @@ -16389,10 +18897,6 @@ static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u1 #endif /* WLMESH_CFG80211 */ case WL_IF_TYPE_MONITOR: -#ifdef WLAWDL - case WL_IF_TYPE_AWDL: -#endif /* WLAWDL */ - case WL_IF_TYPE_NAN: /* Intentionall fall through */ default: @@ -16570,11 +19074,12 @@ wl_cfg80211_generate_mac_addr(struct ether_addr *ea_addr) /* restore mcast and local admin bits to 0 and 1 */ ETHER_SET_UNICAST(ea_addr->octet); ETHER_SET_LOCALADDR(ea_addr->octet); - WL_ERR(("%s:generated new MAC="MACDBG" \n", + WL_DBG_MEM(("%s:generated new MAC="MACDBG" \n", __FUNCTION__, MAC2STRDBG(ea_addr->octet))); return; } +#ifndef EXT_REG_INFO static s32 wl_update_chan_param(struct net_device *dev, u32 cur_chan, struct ieee80211_channel *band_chan, bool *dfs_radar_disabled, bool legacy_chan_info) { @@ -16596,7 +19101,8 @@ static s32 wl_update_chan_param(struct net_device *dev, u32 cur_chan, band_chan->flags |= IEEE80211_CHAN_RADAR; #endif } - if (channel & WL_CHAN_PASSIVE) { + if ((channel & WL_CHAN_PASSIVE) || + (channel & WL_CHAN_CLM_RESTRICTED)) { #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) band_chan->flags |= IEEE80211_CHAN_PASSIVE_SCAN; #else @@ -16611,8 +19117,10 @@ static s32 wl_update_chan_param(struct net_device *dev, u32 cur_chan, return err; } +#endif /* EXT_REG_INFO */ -static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) +static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap_2g, + s32 bw_cap_5g, s32 bw_cap_6g) { struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); struct ieee80211_channel *band_chan_arr = NULL; @@ -16620,7 +19128,12 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) u32 i, j, index, channel, array_size = 0; chanspec_t chspec = 0; s32 err = BCME_OK; - bool ht40_allowed; + bool ht40_allowed = 0; +#ifdef EXT_REG_INFO + bool ht80_allowed = 0, ht160_allowed = 0; + int min_ch = 0, max_ch = 0; + int32 mask = ~0x0, value = 0x0; +#endif /* EXT_REG_INFO */ bool dfs_radar_disabled = FALSE; bool legacy_chan_info = FALSE; u16 list_count; @@ -16662,6 +19175,10 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) for (i = 0; i < dtoh32(list_count); i++) { index = 0; ht40_allowed = false; +#ifdef EXT_REG_INFO + ht80_allowed = false; + ht160_allowed = false; +#endif /* EXT_REG_INFO */ if (legacy_chan_info) { chspec = (chanspec_t)dtoh32(((wl_uint32_list_t *)list)->element[i]); } else { @@ -16671,23 +19188,49 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) chspec = wl_chspec_driver_to_host(chspec); channel = wf_chspec_ctlchan(chspec); +#ifdef EXT_REG_INFO + if (CHSPEC_IS2G(chspec) && (channel >= CH_MIN_2G_CHANNEL) && + (channel <= CH_MAX_2G_CHANNEL) && + (channel > __wl_band_2ghz.n_channels)) { + /* 40M channels would appear later with a lower + * control channel than the last 20MHz bandwidth channel, + * also makes this robust to out-of-order chanspecs + */ + __wl_band_2ghz.n_channels = channel; + } + + if (!CHSPEC_IS160(chspec) && + !CHSPEC_IS80(chspec) && + !CHSPEC_IS40(chspec) && + !CHSPEC_IS20(chspec)) { + WL_DBG(("skip invalid chanspec 0x%X(%d)\n", chspec, channel)); + continue; + } +#else if (!CHSPEC_IS40(chspec) && !CHSPEC_IS20(chspec)) { WL_DBG(("HT80/160/80p80 center channel : %d\n", channel)); continue; } +#endif /* EXT_REG_INFO */ if (CHSPEC_IS2G(chspec) && (channel >= CH_MIN_2G_CHANNEL) && (channel <= CH_MAX_2G_CHANNEL)) { band_chan_arr = __wl_2ghz_channels; array_size = ARRAYSIZE(__wl_2ghz_channels); - ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false; +#ifdef EXT_REG_INFO + ht40_allowed = WL_BW_CAP_40MHZ(bw_cap_2g); +#endif /* EXT_REG_INFO */ } #ifdef CFG80211_6G_SUPPORT else if (CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) && (channel <= CH_MAX_6G_CHANNEL)) { band_chan_arr = __wl_6ghz_channels; array_size = ARRAYSIZE(__wl_6ghz_channels); - ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true; + ht40_allowed = WL_BW_CAP_40MHZ(bw_cap_6g); +#ifdef EXT_REG_INFO + ht80_allowed = WL_BW_CAP_80MHZ(bw_cap_6g); + ht160_allowed = WL_BW_CAP_160MHZ(bw_cap_6g); +#endif /* EXT_REG_INFO */ } #endif /* CFG80211_6G_SUPPORT */ else if ( @@ -16701,22 +19244,49 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) (CHSPEC_IS5G(chspec) && channel >= CH_MIN_5G_CHANNEL)) { band_chan_arr = __wl_5ghz_a_channels; array_size = ARRAYSIZE(__wl_5ghz_a_channels); - ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true; + ht40_allowed = WL_BW_CAP_40MHZ(bw_cap_5g); +#ifdef EXT_REG_INFO + ht80_allowed = WL_BW_CAP_80MHZ(bw_cap_5g); + ht160_allowed = WL_BW_CAP_160MHZ(bw_cap_5g); +#endif /* EXT_REG_INFO */ } else { WL_ERR(("Invalid channel Sepc. 0x%x.\n", chspec)); continue; } - if (!ht40_allowed && CHSPEC_IS40(chspec)) - continue; + +#ifdef EXT_REG_INFO + /* adjust the 'channel' for comparing 'hw_value' */ + if (CHSPEC_IS6G(chspec)) { + channel += CH_MAX_5G_CHANNEL; + } + for (j = 0; j < array_size; j++) { - if (band_chan_arr[j].hw_value == chspec) { + if (band_chan_arr[j].hw_value == channel) { break; } } - index = j; - if (!dhd_conf_match_channel(cfg->pub, channel)) +#else + if (!ht40_allowed && CHSPEC_IS40(chspec)) continue; + for (j = 0; j < array_size; j++) { + if (band_chan_arr[j].hw_value == wf_chspec_primary20_chspec(chspec)) { + break; + } + } +#endif /* EXT_REG_INFO */ + index = j; if (index < array_size) { +#ifdef EXT_REG_INFO + uint32 flags = band_chan_arr[index].flags; +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) + band_chan_arr[index].center_freq = + ieee80211_channel_to_frequency(wf_chspec_ctlchan(chspec)); +#else + band_chan_arr[index].center_freq = + wl_channel_to_frequency(wf_chspec_ctlchan(chspec), + CHSPEC_BAND(chspec)); +#endif +#else /* EXT_REG_INFO */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS) band_chan_arr[index].center_freq = ieee80211_channel_to_frequency(channel); @@ -16724,20 +19294,194 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) band_chan_arr[index].center_freq = wl_channel_to_frequency(channel, CHSPEC_BAND(chspec)); #endif - band_chan_arr[index].hw_value = chspec; +#endif /* EXT_REG_INFO */ band_chan_arr[index].beacon_found = false; - band_chan_arr[index].flags &= ~IEEE80211_CHAN_DISABLED; +#ifdef EXT_REG_INFO + if (CHSPEC_IS20(chspec)) { + min_ch = channel; + max_ch = channel; + mask = ~(CH_DEFAULT_FLAGS); + if (!ht40_allowed) { + value |= IEEE80211_CHAN_NO_HT40MINUS | + IEEE80211_CHAN_NO_HT40PLUS; + } + if (!ht80_allowed) { + value |= IEEE80211_CHAN_NO_80MHZ; + } + /* Update channel for radar/passive support */ + if (!dfs_radar_disabled) { + uint32 iov_value = wf_chspec_primary20_chspec(chspec); + err = wldev_iovar_getint(dev, "per_chan_info", &iov_value); + if (err == BCME_UNSUPPORTED) { + dfs_radar_disabled = TRUE; + WL_ERR(("does not support per_chan_info\n")); + } else { + if (iov_value & WL_CHAN_RADAR) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) + value |= IEEE80211_CHAN_RADAR + | IEEE80211_CHAN_NO_IBSS; +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) */ + value |= IEEE80211_CHAN_RADAR; +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) */ + } + if (iov_value & WL_CHAN_PASSIVE) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) + value |= IEEE80211_CHAN_PASSIVE_SCAN; +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) */ + value |= IEEE80211_CHAN_NO_IR; +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) */ + } + } + } + } else if (CHSPEC_IS40(chspec)) { + if (!ht40_allowed) { + if (WL_CHANSPEC_CTL_SB_L == CHSPEC_CTL_SB(chspec)) { + min_ch = channel + 1; + max_ch = channel + CH_20MHZ_APART + 1; + mask = ~0x0; + value = IEEE80211_CHAN_NO_HT40MINUS; + WL_DBG(("SB_L, add the NO_HT40-," + "CH[%d]=%d, flags=0x%X\n", + index, channel, flags)); + } else { + min_ch = channel - CH_20MHZ_APART - 1; + max_ch = channel - 1; + mask = ~0x0; + value = IEEE80211_CHAN_NO_HT40PLUS; + WL_DBG(("SB_U, add the NO_HT40+," + "CH[%d]=%d, flags=0x%X\n", + index, channel, flags)); + } + } else { + if (WL_CHANSPEC_CTL_SB_L == CHSPEC_CTL_SB(chspec)) { + min_ch = channel + 1; + max_ch = channel + CH_20MHZ_APART + 1; + mask = ~(IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_NO_HT40MINUS | + IEEE80211_CHAN_NO_HT40PLUS); + value = 0x0; + WL_DBG(("SB_L, clean the NO_HT40-," + "CH[%d]=%d, flags=0x%X\n", + index, channel, flags)); + } else { + min_ch = channel - CH_20MHZ_APART - 1; + max_ch = channel - 1; + mask = ~(IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_NO_HT40MINUS | + IEEE80211_CHAN_NO_HT40PLUS); + value = 0x0; + WL_DBG(("SB_U, clean the NO_HT40+," + "CH[%d]=%d, flags=0x%X\n", + index, channel, flags)); + } + } + } else { + min_ch = CH_FIRST_20_SB(chspec); + max_ch = CH_LAST_20_SB(chspec); + if (CHSPEC_IS6G(chspec)) { + min_ch += CH_MAX_5G_CHANNEL; + max_ch += CH_MAX_5G_CHANNEL; + } + + if (CHSPEC_IS80(chspec)) { + if (!ht80_allowed) { + mask = ~0x0; + value = IEEE80211_CHAN_NO_80MHZ; + } else { + mask = ~(IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_NO_80MHZ); + value = 0x0; + } + } else if (CHSPEC_IS160(chspec)) { + if (!ht160_allowed) { + mask = ~0x0; + value = IEEE80211_CHAN_NO_160MHZ; + } else { + mask = ~(IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_NO_160MHZ); + value = 0x0; + } + } else { + min_ch = max_ch = 0; + } + } + + if (min_ch) { + /* side band channel processing */ + for (j = 0; j < array_size; j++) { + if ((min_ch <= band_chan_arr[j].hw_value) + && (max_ch >= band_chan_arr[j].hw_value)) { + band_chan_arr[j].flags &= mask; + band_chan_arr[j].flags |= value; + flags = band_chan_arr[j].flags; + WL_DBG(("side_band, CH[%d]=%d, mask=0x%X," + "value=0x%X, chspec=0x%X, channel=%d," + "flags=0x%X %s%s%s%s%s%s%s%s%s%s%s%s\n", + j, band_chan_arr[j].hw_value, mask, value, + chspec, channel, flags, + (IEEE80211_CHAN_DISABLED & flags)? + "DISABLED ":"", +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + (IEEE80211_CHAN_NO_IR & flags)? + "PASSIVE ":"", +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */ + "", +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */ + (IEEE80211_CHAN_RADAR & flags)?"RADAR ":"", + (IEEE80211_CHAN_NO_HT40PLUS & flags)? + "NO_HT40PLUS ":"", + (IEEE80211_CHAN_NO_HT40MINUS & flags)? + "NO_HT40MINUS ":"", + (IEEE80211_CHAN_NO_OFDM & flags)? + "NO_OFDM ":"", + (IEEE80211_CHAN_NO_80MHZ & flags)? + "NO_80MHz ":"", + (IEEE80211_CHAN_NO_160MHZ & flags)? + "NO_160MHz ":"", +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + (IEEE80211_CHAN_INDOOR_ONLY & flags) ? + "INDOOR ":"", +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */ + "", +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) + (IEEE80211_CHAN_IR_CONCURRENT & flags) ? + "IR_CON ":"", +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + (IEEE80211_CHAN_GO_CONCURRENT & flags) ? + "GO_CON ":"", +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) */ + "", +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + (IEEE80211_CHAN_NO_20MHZ & flags) ? + "NO_20MHz ":"", + (IEEE80211_CHAN_NO_10MHZ & flags) ? + "NO_10MHz ":"" +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */ + "", + "" +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */ + )); + } + } + } +#else /* EXT_REG_INFO */ + band_chan_arr[index].hw_value = wf_chspec_primary20_chspec(chspec); + band_chan_arr[index].flags &= ~IEEE80211_CHAN_DISABLED; if (CHSPEC_IS40(chspec) && ht40_allowed) { /* assuming the order is HT20, HT40 Upper, * HT40 lower from chanspecs */ - u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40; + u32 ht40_flag = + band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40; if (CHSPEC_SB_UPPER(chspec)) { if (ht40_flag == IEEE80211_CHAN_NO_HT40) band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40; - band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS; + band_chan_arr[index].flags |= + IEEE80211_CHAN_NO_HT40PLUS; } else { /* It should be one of * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS @@ -16748,7 +19492,10 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) IEEE80211_CHAN_NO_HT40MINUS; } } else { - band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40; +#ifdef WL_CFG80211_MONITOR + if (!ht40_allowed) +#endif /* WL_CFG80211_MONITOR */ + band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40; if (!legacy_chan_info) { channel = dtoh32 (((wl_chanspec_list_v1_t *)list)->chspecs[i].chaninfo); @@ -16759,15 +19506,40 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) err = wl_update_chan_param(dev, channel, &band_chan_arr[index], &dfs_radar_disabled, legacy_chan_info); } +#endif /* EXT_REG_INFO */ } - } +#ifdef EXT_REG_INFO +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM) + if (global_regd_self) { + global_regd_self->n_reg_rules = 0; + wl_cfg80211_regd_parse_channels(global_regd_self, + __wl_band_2ghz.channels, + __wl_band_2ghz.n_channels); + wl_cfg80211_regd_parse_channels(global_regd_self, + __wl_band_5ghz_a.channels, + __wl_band_5ghz_a.n_channels); +#ifdef CFG80211_6G_SUPPORT + wl_cfg80211_regd_parse_channels(global_regd_self, + __wl_band_6ghz.channels, + __wl_band_6ghz.n_channels); +#endif /* CFG80211_6G_SUPPORT */ + } +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM) */ +#else /* EXT_REG_INFO */ + WL_CHANNEL_COPY_FLAG(__wl_2ghz_channels); + WL_CHANNEL_COPY_FLAG(__wl_5ghz_a_channels); +#ifdef CFG80211_6G_SUPPORT + WL_CHANNEL_COPY_FLAG(__wl_6ghz_channels); +#endif /* CFG80211_6G_SUPPORT */ + __wl_band_2ghz.n_channels = ARRAYSIZE(__wl_2ghz_channels); __wl_band_5ghz_a.n_channels = ARRAYSIZE(__wl_5ghz_a_channels); #ifdef CFG80211_6G_SUPPORT __wl_band_6ghz.n_channels = ARRAYSIZE(__wl_6ghz_channels); #endif /* CFG80211_6G_SUPPORT */ +#endif /* EXT_REG_INFO */ MFREE(cfg->osh, list, LOCAL_BUF_LEN); #undef LOCAL_BUF_LEN @@ -16801,8 +19573,10 @@ static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) s32 err = 0; s32 index = 0; s32 nmode = 0; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) + s32 txchain = 0; + s32 rxchain = 0; u32 j = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) s32 vhtmode = 0; s32 txstreams = 0; s32 rxstreams = 0; @@ -16812,10 +19586,18 @@ static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) s32 txbf_bfe_cap = 0; s32 txbf_bfr_cap = 0; #endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ - s32 bw_cap = 0; +#ifdef EXT_REG_INFO +#ifdef WL_CAP_HE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) + s32 hemode = 0; +#endif /* KERNEL >= 4.19 */ +#endif /* WL_CAP_HE */ +#endif /* EXT_REG_INFO */ + s32 bw_cap_2g = 0, bw_cap_5g = 0, bw_cap_6g = 0; s32 cur_band = -1; struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, }; + WL_INFORM(("%s: Enter\n", __FUNCTION__)); bzero(bandlist, sizeof(bandlist)); err = wldev_ioctl_get(dev, WLC_GET_BANDLIST, bandlist, sizeof(bandlist)); @@ -16823,6 +19605,11 @@ static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) WL_ERR(("error read bandlist (%d)\n", err)); return err; } + +#ifdef WL_6G_BAND + wl_is_6g_supported(cfg, bandlist, bandlist[0]); +#endif /* WL_6G_BAND */ + err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band, sizeof(s32)); if (unlikely(err)) { @@ -16835,6 +19622,24 @@ static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) WL_ERR(("error reading nmode (%d)\n", err)); } + err = wldev_iovar_getint(dev, "txchain", &txchain); + if (unlikely(err)) { + WL_ERR(("error reading txchain (%d)\n", err)); + } else if (txchain == 0x03) { + txchain = 2; + } else { + txchain = 1; + } + + err = wldev_iovar_getint(dev, "rxchain", &rxchain); + if (unlikely(err)) { + WL_ERR(("error reading rxchain (%d)\n", err)); + } else if (rxchain == 0x03) { + rxchain = 2; + } else { + rxchain = 1; + } + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) err = wldev_iovar_getint(dev, "vhtmode", &vhtmode); if (unlikely(err)) { @@ -16852,6 +19657,61 @@ static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) WL_ERR(("error reading rxstreams (%d)\n", err)); } + err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap); + if (unlikely(err)) { + WL_ERR(("error reading txbf_bfe_cap (%d)\n", err)); + } + + err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap); + if (unlikely(err)) { + WL_ERR(("error reading txbf_bfr_cap (%d)\n", err)); + } + } +#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ +#ifdef EXT_REG_INFO +#ifdef WL_CAP_HE +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) + err = wldev_iovar_getint(dev, "he", &hemode); + if (unlikely(err)) { + WL_ERR(("error reading hemode (%d)\n", err)); + } +#endif /* KERNEL >= 4.19 */ +#endif /* WL_CAP_HE */ +#endif /* EXT_REG_INFO */ + + /* For nmode and vhtmode check bw cap */ + if (nmode || +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + vhtmode || +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */ + 0) { + uint32 value; + + value = WLC_BAND_2G; + err = wldev_iovar_getint(dev, "bw_cap", &value); + if (unlikely(err)) { + WL_ERR(("error get bw_cap 2g (%d)\n", err)); + } else { + bw_cap_2g = dtoh32(value); + } + value = WLC_BAND_5G; + err = wldev_iovar_getint(dev, "bw_cap", &value); + if (unlikely(err)) { + WL_ERR(("error get bw_cap 5g (%d)\n", err)); + } else { + bw_cap_5g = dtoh32(value); + } +#ifdef WL_6G_BAND + if (cfg->band_6g_supported) { + value = WLC_BAND_6G; + err = wldev_iovar_getint(dev, "bw_cap", &value); + if (unlikely(err)) { + WL_ERR(("error get bw_cap 6g (%d)\n", err)); + } else { + bw_cap_6g = dtoh32(value); + } + } +#endif /* WL_6G_BAND */ err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap); if (unlikely(err)) { WL_ERR(("error reading ldpc_cap (%d)\n", err)); @@ -16866,36 +19726,9 @@ static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) if (unlikely(err)) { WL_ERR(("error reading stbc_tx (%d)\n", err)); } - - err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap); - if (unlikely(err)) { - WL_ERR(("error reading txbf_bfe_cap (%d)\n", err)); - } - - err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap); - if (unlikely(err)) { - WL_ERR(("error reading txbf_bfr_cap (%d)\n", err)); - } - } -#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ - - /* For nmode and vhtmode check bw cap */ - if (nmode || -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) - vhtmode || -#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ - 0) { - err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); - if (unlikely(err)) { - WL_ERR(("error get mimo_bw_cap (%d)\n", err)); - } } -#ifdef WL_6G_BAND - wl_is_6g_supported(cfg, bandlist, bandlist[0]); -#endif /* WL_6G_BAND */ - - err = wl_construct_reginfo(cfg, bw_cap); + err = wl_construct_reginfo(cfg, bw_cap_2g, bw_cap_5g, bw_cap_6g); if (err) { WL_ERR(("wl_construct_reginfo() fails err=%d\n", err)); if (err != BCME_UNSUPPORTED) @@ -16905,134 +19738,381 @@ static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) wiphy = bcmcfg_to_wiphy(cfg); nband = bandlist[0]; + wiphy->available_antennas_tx = txchain; + wiphy->available_antennas_rx = rxchain; + for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) { + s32 bw_cap = 0; index = -1; if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) { - bands[IEEE80211_BAND_2GHZ] = - &__wl_band_2ghz; index = IEEE80211_BAND_2GHZ; - if (bw_cap == WLC_N_BW_40ALL) - bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; - } else { - if (bandlist[i] == WLC_BAND_6G) { -#ifdef CFG80211_6G_SUPPORT - if (__wl_band_6ghz.n_channels > 0) { - bands[IEEE80211_BAND_6GHZ] = &__wl_band_6ghz; - index = IEEE80211_BAND_6GHZ; - } else { - WL_ERR(("6GHz channels not listed\n")); - continue; - } -#else /* CFG80211_6G_SUPPORT */ - /* Both 6G/5G channels will be under 5G band list */ - if (__wl_band_5ghz_a.n_channels > 0) - { - bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; - index = IEEE80211_BAND_5GHZ; - } else { - WL_ERR(("5GHz channels not listed\n")); - continue; - } -#endif /* CFG80211_6G_SUPPORT */ - } else if ((bandlist[i] == WLC_BAND_5G) && - (__wl_band_5ghz_a.n_channels > 0)) { - bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; - index = IEEE80211_BAND_5GHZ; + bands[index] = &__wl_band_2ghz; + bw_cap = bw_cap_2g; + (void)memset_s(bands[index]->ht_cap.mcs.rx_mask, IEEE80211_HT_MCS_MASK_LEN, + 0, IEEE80211_HT_MCS_MASK_LEN); + if (nmode && (WL_BW_CAP_40MHZ(bw_cap_2g))) { + bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SGI_40; + bands[index]->ht_cap.mcs.rx_mask[4] = 0x01; + bands[index]->ht_cap.mcs.rx_highest = + cpu_to_le16(150 * rxchain); /* Mbps */ } else { - WL_ERR(("Invalid band\n")); + bands[index]->ht_cap.mcs.rx_highest = + cpu_to_le16(72 * rxchain); /* Mbps */ + } + } else if (bandlist[i] == WLC_BAND_6G) { +#ifdef CFG80211_6G_SUPPORT + if (__wl_band_6ghz.n_channels > 0) { + index = IEEE80211_BAND_6GHZ; + bands[index] = &__wl_band_6ghz; + bw_cap = bw_cap_6g; + } else { + WL_ERR(("6GHz channels not listed\n")); + continue; + } +#else /* CFG80211_6G_SUPPORT */ + /* Both 6G/5G channels will be under 5G band list */ + if (__wl_band_5ghz_a.n_channels > 0) { + index = IEEE80211_BAND_5GHZ; + bands[index] = &__wl_band_5ghz_a; +#ifdef EXT_REG_INFO + bw_cap = bw_cap_6g; +#endif /* EXT_REG_INFO */ + } else { + WL_ERR(("5GHz channels not listed\n")); + continue; + } +#endif /* CFG80211_6G_SUPPORT */ + } else if ((bandlist[i] == WLC_BAND_5G) && + (__wl_band_5ghz_a.n_channels > 0)) { + index = IEEE80211_BAND_5GHZ; + bands[index] = &__wl_band_5ghz_a; + bw_cap = bw_cap_5g; + } else { + WL_ERR(("Invalid band\n")); + continue; + } + +#ifdef EXT_REG_INFO + /* HT capabilityes */ + memset(&(bands[index]->ht_cap), 0, sizeof(struct ieee80211_sta_ht_cap)); + if (nmode) { + bands[index]->ht_cap.ht_supported = TRUE; + + bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_DSSSCCK40; + if (ldpc_cap) { + bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; + } + if (stbc_rx) { + bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_RX_STBC; + } + if (stbc_tx) { + bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; + } + if (WL_BW_CAP_40MHZ(bw_cap)) { + bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + bands[index]->ht_cap.mcs.rx_highest = + cpu_to_le16(150 * rxchain); /* Mbps */ + } else { + bands[index]->ht_cap.mcs.rx_highest = + cpu_to_le16(72 * rxchain); /* Mbps */ + } + + bands[index]->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + /* An HT shall support all EQM rates for one spatial stream */ + for (j = 0; j < rxchain; j++) { + bands[index]->ht_cap.mcs.rx_mask[j] = 0xff; + } + bands[index]->ht_cap.mcs.rx_mask[4] = 0x01; + bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; + } +#else /* EXT_REG_INFO */ + (void)memset_s(bands[index]->ht_cap.mcs.rx_mask, IEEE80211_HT_MCS_MASK_LEN, + 0, IEEE80211_HT_MCS_MASK_LEN); + if (nmode && (WL_BW_CAP_40MHZ(bw_cap))) { + bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SGI_40; + bands[index]->ht_cap.mcs.rx_mask[4] = 0x01; + bands[index]->ht_cap.mcs.rx_highest = cpu_to_le16(150 * rxchain); + } else { + bands[index]->ht_cap.mcs.rx_highest = cpu_to_le16(72 * rxchain); + } +#endif /* EXT_REG_INFO */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + /* VHT capabilities. */ + memset(&(bands[index]->vht_cap), 0, sizeof(struct ieee80211_sta_vht_cap)); + if (vhtmode) { + /* Supported */ + bands[index]->vht_cap.vht_supported = TRUE; + + /* Capabilities */ + bands[index]->vht_cap.cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | + IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; + /* 80 MHz is mandatory */ + bands[index]->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80; + if (WL_BW_CAP_160MHZ(bw_cap)) { + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + bands[index]->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160; + } + bands[index]->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; + if (ldpc_cap) { + bands[index]->vht_cap.cap |= IEEE80211_VHT_CAP_RXLDPC; + } + if (stbc_tx) { + bands[index]->vht_cap.cap |= IEEE80211_VHT_CAP_TXSTBC; + } + if (stbc_rx) { + bands[index]->vht_cap.cap |= + (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT); + } + + if (txbf_bfe_cap) { + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + } + if (txbf_bfr_cap) { + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; + } + if (txbf_bfe_cap || txbf_bfr_cap) { + bands[index]->vht_cap.cap |= + (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT); + bands[index]->vht_cap.cap |= + ((txstreams - 1) << VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT); + bands[index]->vht_cap.cap |= + IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB; + } + + /* MCS related */ + for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) { + /* TX stream rates. */ + if (j <= txstreams) { +#ifdef EXT_REG_INFO + if (IEEE80211_BAND_2GHZ == index) { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_8, + bands[index]->vht_cap.vht_mcs.tx_mcs_map); + } else { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, + bands[index]->vht_cap.vht_mcs.tx_mcs_map); + } +#else + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, + bands[index]->vht_cap.vht_mcs.tx_mcs_map); +#endif /* EXT_REG_INFO */ + } else { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE, + bands[index]->vht_cap.vht_mcs.tx_mcs_map); + } + + /* RX stream rates. */ + if (j <= rxstreams) { +#ifdef EXT_REG_INFO + if (IEEE80211_BAND_2GHZ == index) { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_8, + bands[index]->vht_cap.vht_mcs.rx_mcs_map); + } else { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, + bands[index]->vht_cap.vht_mcs.rx_mcs_map); + } +#else + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, + bands[index]->vht_cap.vht_mcs.rx_mcs_map); +#endif /* EXT_REG_INFO */ + } else { + VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE, + bands[index]->vht_cap.vht_mcs.rx_mcs_map); + } + } + if (WL_BW_CAP_160MHZ(bw_cap)) { + bands[index]->vht_cap.vht_mcs.tx_highest = + cpu_to_le16(866 * txstreams); /* Mbps */ + bands[index]->vht_cap.vht_mcs.rx_highest = + cpu_to_le16(867 * txstreams); /* Mbps */ + } else if (WL_BW_CAP_80MHZ(bw_cap)) { + bands[index]->vht_cap.vht_mcs.tx_highest = + cpu_to_le16(433 * txstreams); /* Mbps */ + bands[index]->vht_cap.vht_mcs.rx_highest = + cpu_to_le16(433 * txstreams); /* Mbps */ + } else if (WL_BW_CAP_40MHZ(bw_cap)) { + bands[index]->vht_cap.vht_mcs.tx_highest = + cpu_to_le16(200 * txstreams); /* Mbps */ + bands[index]->vht_cap.vht_mcs.rx_highest = + cpu_to_le16(200 * txstreams); /* Mbps */ + } else { + bands[index]->vht_cap.vht_mcs.tx_highest = + cpu_to_le16(86 * txstreams); /* Mbps */ + bands[index]->vht_cap.vht_mcs.rx_highest = + cpu_to_le16(86 * txstreams); /* Mbps */ + } + + /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */ + bands[index]->vht_cap.cap |= + (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT); + WL_DBG(("__wl_update_wiphybands band[%d] vht_enab=%d vht_cap=%08x " + "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n", + index, + bands[index]->vht_cap.vht_supported, + bands[index]->vht_cap.cap, + bands[index]->vht_cap.vht_mcs.rx_mcs_map, + bands[index]->vht_cap.vht_mcs.tx_mcs_map)); + } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */ + +#ifdef EXT_REG_INFO +#ifdef WL_CAP_HE +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) + /* HE capabilities. */ + if (bands[index]->iftype_data) { + struct ieee80211_sband_iftype_data *pItf_data = NULL; + struct ieee80211_sta_he_cap *pHE_cap = NULL; + struct ieee80211_he_cap_elem *pHE_elem = NULL; + struct ieee80211_he_mcs_nss_supp *pHE_mcs = NULL; + + bands[index]->n_iftype_data = 1; + /* Ignore compiler warnings due to -Werror=cast-qual */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + pItf_data = (struct ieee80211_sband_iftype_data *)(&bands[index]->iftype_data[0]); + GCC_DIAGNOSTIC_POP(); + memset(pItf_data, 0, sizeof(struct ieee80211_sband_iftype_data)); + + pHE_cap = &(pItf_data->he_cap); + pHE_elem = &(pHE_cap->he_cap_elem); + pHE_mcs = &(pHE_cap->he_mcs_nss_supp); + + if (!hemode) { continue; } - if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G)) - bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + pItf_data->types_mask = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP); + pHE_cap->has_he = TRUE; + pHE_elem->mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_HTC_HE | + IEEE80211_HE_MAC_CAP0_TWT_REQ | + IEEE80211_HE_MAC_CAP0_TWT_RES | + IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_64; + pHE_elem->mac_cap_info[1] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; + pHE_elem->mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_BSR | + IEEE80211_HE_MAC_CAP2_ACK_EN; + pHE_elem->mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_OFDMA_RA; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) + pHE_elem->mac_cap_info[4] |= IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU; +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) */ + /* Kernel has spell bug between [4.19.0, 5.13.0) */ + pHE_elem->mac_cap_info[4] |= IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) + pHE_elem->mac_cap_info[5] |= IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5) - /* VHT capabilities. */ - if (vhtmode) { - /* Supported */ - bands[index]->vht_cap.vht_supported = TRUE; - - for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) { - /* TX stream rates. */ - if (j <= txstreams) { - VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, - bands[index]->vht_cap.vht_mcs.tx_mcs_map); - } else { - VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE, - bands[index]->vht_cap.vht_mcs.tx_mcs_map); + if (WL_BW_CAP_40MHZ(bw_cap)) { + if (IEEE80211_BAND_2GHZ == index) { + pHE_elem->phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; + } else if (IEEE80211_BAND_5GHZ == index) { + if (WL_BW_CAP_80MHZ(bw_cap)) { + pHE_elem->phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; } - - /* RX stream rates. */ - if (j <= rxstreams) { - VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9, - bands[index]->vht_cap.vht_mcs.rx_mcs_map); - } else { - VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE, - bands[index]->vht_cap.vht_mcs.rx_mcs_map); + if (WL_BW_CAP_160MHZ(bw_cap)) { + pHE_elem->phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; } } - - /* Capabilities */ - /* 80 MHz is mandatory */ - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SHORT_GI_80; - - if (WL_BW_CAP_160MHZ(bw_cap)) { - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SHORT_GI_160; - } - - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; - - if (ldpc_cap) - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_RXLDPC; - - if (stbc_tx) - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_TXSTBC; - - if (stbc_rx) - bands[index]->vht_cap.cap |= - (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT); - - if (txbf_bfe_cap) - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; - - if (txbf_bfr_cap) { - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; - } - - if (txbf_bfe_cap || txbf_bfr_cap) { - bands[index]->vht_cap.cap |= - (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT); - bands[index]->vht_cap.cap |= - ((txstreams - 1) << - VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT); - bands[index]->vht_cap.cap |= - IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB; - } - - /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */ - bands[index]->vht_cap.cap |= - (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT); - WL_DBG(("__wl_update_wiphybands band[%d] vht_enab=%d vht_cap=%08x " - "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n", - index, - bands[index]->vht_cap.vht_supported, - bands[index]->vht_cap.cap, - bands[index]->vht_cap.vht_mcs.rx_mcs_map, - bands[index]->vht_cap.vht_mcs.tx_mcs_map)); } -#endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */ - } + pHE_elem->phy_cap_info[1] |= IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; + pHE_elem->phy_cap_info[2] |= IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US; + pHE_elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; + if (txstreams > 1) { + pHE_elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2; + } + if (rxstreams > 1) { + pHE_elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_2; + } + pHE_elem->phy_cap_info[4] = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE; + if (WL_BW_CAP_80MHZ(bw_cap)) { + pHE_elem->phy_cap_info[4] |= + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8 | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8; + pHE_elem->phy_cap_info[5] |= + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2; + } + pHE_elem->phy_cap_info[6] |= + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)) + IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB | + IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB | +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)) */ + IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | + IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB | +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)) */ + IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; + pHE_elem->phy_cap_info[7] |= IEEE80211_HE_PHY_CAP7_MAX_NC_7 | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)) + IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)) */ + IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)) */ + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI; + pHE_elem->phy_cap_info[8] |= + IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI; + if (WL_BW_CAP_40MHZ(bw_cap)) { + if (IEEE80211_BAND_2GHZ == index) { + pHE_elem->phy_cap_info[8] |= + IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G; + } + } + if (WL_BW_CAP_160MHZ(bw_cap)) { + pHE_elem->phy_cap_info[8] |= + IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) + pHE_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) */ + memset(pHE_mcs, 0xff, sizeof(struct ieee80211_he_mcs_nss_supp)); + if (WL_BW_CAP_160MHZ(bw_cap)) { + pHE_mcs->rx_mcs_160 = 0xfffe; + pHE_mcs->tx_mcs_160 = 0xfffe; + if (1 < rxstreams) { + pHE_mcs->rx_mcs_160 = 0xfffa; + } + if (1 < txstreams) { + pHE_mcs->tx_mcs_160 = 0xfffa; + } + } + if (WL_BW_CAP_80MHZ(bw_cap)) { + pHE_mcs->rx_mcs_80 = 0xfffe; + pHE_mcs->tx_mcs_80 = 0xfffe; + if (1 < rxstreams) { + pHE_mcs->rx_mcs_80 = 0xfffa; + } + if (1 < txstreams) { + pHE_mcs->tx_mcs_80 = 0xfffa; + } + } + + WL_DBG(("band[%d] he_cap=%d " + "he_80_tx_mcs=0x%04x he_80_rx_mcs_map=0x%04x\n", + index, hemode, + pHE_mcs->tx_mcs_80, pHE_mcs->rx_mcs_80)); + } +#endif /* KERNEL >= 4.19 */ +#endif /* WL_CAP_HE */ +#else if ((index >= 0) && nmode) { bands[index]->ht_cap.cap |= (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40); @@ -17040,8 +20120,12 @@ static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; /* An HT shall support all EQM rates for one spatial stream */ - bands[index]->ht_cap.mcs.rx_mask[0] = 0xff; + for (j = 0; j < rxchain; j++) { + bands[index]->ht_cap.mcs.rx_mask[j] = 0xff; + } + bands[index]->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; } +#endif /* EXT_REG_INFO */ } @@ -17062,13 +20146,40 @@ static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) } if (notify) { +#if defined(WL_SELF_MANAGED_REGDOM) if (!IS_REGDOM_SELF_MANAGED(wiphy)) { WL_UPDATE_CUSTOM_REGULATORY(wiphy); +#ifdef EXT_REG_INFO + if (!global_regd_self) { + return BCME_ERROR; + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) + if (rtnl_is_locked()) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + wiphy_lock(wiphy); + regulatory_set_wiphy_regd_sync(wiphy, global_regd_self); + wiphy_unlock(wiphy); +#else + regulatory_set_wiphy_regd_sync_rtnl(wiphy, global_regd_self); +#endif /* LINUX_VERSION >= 5.12.0 */ + } else { + regulatory_set_wiphy_regd(wiphy, global_regd_self); + } +#else + wiphy_apply_custom_regulatory(wiphy, global_regd_self); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */ +#else wl_notify_regd(wiphy, NULL); +#endif /* EXT_REG_INFO */ } +#endif /* WL_SELF_MANAGED_REGDOM */ } - return 0; +#ifdef WL_CELLULAR_CHAN_AVOID + err = wl_cellavoid_reinit(cfg); +#endif /* WL_CELLULAR_CHAN_AVOID */ + + return err; } s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) @@ -17082,6 +20193,151 @@ s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) return err; } +#ifdef WL_RAV_MSCS_NEG_IN_ASSOC +static s32 wl_cfg80211_config_rav_mscs_params(struct bcm_cfg80211 *cfg, + struct net_device *ndev) +{ + int err = BCME_OK; + bcm_iov_buf_t *iov_buf = NULL; + uint16 buflen = 0, buflen_start = 0; + char *ioctl_buf = NULL; + uint16 iovlen; + wl_qos_rav_mscs_config_v1_t rav_mscs_cfg; + uint8 *data; + + ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (!ioctl_buf) { + WL_ERR(("ioctl memory alloc failed\n")); + err = BCME_NOMEM; + goto fail; + } + + bzero(&rav_mscs_cfg, sizeof(rav_mscs_cfg)); + rav_mscs_cfg.version = WL_QOS_RAV_MSCS_SC_VERSION_1; + rav_mscs_cfg.length = (uint16) sizeof(wl_qos_rav_mscs_config_v1_t); + + iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (!iov_buf) { + WL_ERR(("No memory")); + err = BCME_NOMEM; + goto fail; + } + + /* Fill the bcm_iov_buf_t, IOVAR header */ + iov_buf->version = WL_QOS_VERSION_1; + iov_buf->id = WL_QOS_CMD_RAV_MSCS; + + data = (uint8 *)&iov_buf->data[0]; + buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t); + + rav_mscs_cfg.up_bitmap = MSCS_CFG_DEF_FC_MASK; + rav_mscs_cfg.up_limit = MSCS_CFG_DEF_UP_LIMIT; + rav_mscs_cfg.stream_timeout = MSCS_CFG_DEF_STREAM_TIMEOUT; + rav_mscs_cfg.fc_type = DOT11_TCLAS_FC_4_IP_HIGHER; + rav_mscs_cfg.fc_mask = MSCS_CFG_DEF_TCLAS_MASK; + rav_mscs_cfg.req_type = DOT11_MSCS_REQ_TYPE_ADD; + + *(wl_qos_rav_mscs_config_v1_t *) data = rav_mscs_cfg; + buflen -= sizeof(wl_qos_rav_mscs_config_v1_t); + + iov_buf->len = buflen_start - buflen; + iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len; + + err = wldev_iovar_setbuf(ndev, "qos_mgmt", iov_buf, iovlen, + ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(err)) { + WL_ERR(("set qos_mgmt failed ,err(%d)\n", err)); + } else { + if (wl_dbg_level & WL_DBG_DBG) { + prhex("mscs config", (u8 *)iov_buf, iovlen); + WL_DBG(("UP bit map: %0x\n", + ((wl_qos_rav_mscs_config_v1_t *)(&iov_buf->data[0]))->up_bitmap)); + } + } +fail: + if (ioctl_buf) { + MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); + } + + if (iov_buf) { + MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN); + } + + return err; +} + +static s32 wl_cfg80211_enable_rav_mscs_params(struct bcm_cfg80211 *cfg, + struct net_device *ndev, bool mscs_offload) +{ + s32 err = BCME_OK; + bcm_iov_buf_t *iov_buf = NULL; + char *ioctl_buf = NULL; + uint16 buflen = 0, buflen_start = 0; + uint16 iovlen = 0; + uint8 *data; + + if (!cfg) { + return BCME_ERROR; + } + + if (mscs_offload) { + err = wl_cfg80211_config_rav_mscs_params(cfg, ndev); + if (err) { + WL_INFORM(("config rav_mscs failed ,err(%d)\n", err)); + return err; + } + } + + ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (!ioctl_buf) { + WL_ERR(("ioctl memory alloc failed\n")); + err = BCME_NOMEM; + goto exit; + } + + iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (!iov_buf) { + WL_ERR(("No memory")); + err = BCME_NOMEM; + goto exit; + } + + /* fill header */ + iov_buf->version = WL_QOS_VERSION_1; + iov_buf->id = WL_QOS_CMD_ENABLE; + + data = (uint8 *)&iov_buf->data[0]; + buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t); + *((uint16 *)data) = WL_QOS_CMD_ENABLE_FLAG_RAV_MSCS; + + if (mscs_offload) { + *((uint16 *)data) |= WL_QOS_CMD_ENABLE_FLAG_RAV_MSCS_NEG_IN_ASSOC; + } + + buflen -= sizeof(uint16); + + iov_buf->len = buflen_start - buflen; + iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len; + + err = wldev_iovar_setbuf(ndev, "qos_mgmt", iov_buf, iovlen, + ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(err)) { + WL_ERR(("set qos_mgmt failed ,err(%d)\n", err)); + } + +exit: + if (ioctl_buf) { + MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); + } + + if (iov_buf) { + MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN); + } + + return err; +} +#endif /* WL_RAV_MSCS_NEG_IN_ASSOC */ + static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) { s32 err = 0; @@ -17097,10 +20353,11 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) u16 wl_iftype = 0; u16 wl_mode = 0; u8 ioctl_buf[WLC_IOCTL_SMLEN]; + wl_actframe_version_v1_t *af_ver_p; WL_DBG(("In\n")); -#if defined(__linux__) +#if defined(BCMDONGLEHOST) && defined(__linux__) if (!dhd_download_fw_on_driverload) { #endif err = wl_create_event_handler(cfg); @@ -17109,7 +20366,7 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) return err; } wl_init_event_handler(cfg); -#if defined(__linux__) +#if defined(BCMDONGLEHOST) && defined(__linux__) } #endif /* Reserve 0x8000 toggle bit for P2P GO/GC */ @@ -17125,6 +20382,10 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) /* Start the event logging */ wl_add_remove_eventmsg(ndev, WLC_E_TRACE, TRUE); #endif /* SHOW_LOGTRACE */ +#if defined(BCMDBUS) + if (!dhd->dhd_console_ms) + wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE); +#endif (void)memcpy_s(wdev->wiphy->perm_addr, ETHER_ADDR_LEN, bcmcfg_to_prmry_ndev(cfg)->perm_addr, ETHER_ADDR_LEN); @@ -17146,7 +20407,10 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) */ netinfo->iftype = WL_IF_TYPE_AP; } else { - ndev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; +#ifdef WL_CFG80211_MONITOR + if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_MONITOR) +#endif /* WL_CFG80211_MONITOR */ + ndev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; netinfo->iftype = WL_IF_TYPE_STA; } @@ -17164,6 +20428,24 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) } } +#ifdef EXT_REG_INFO +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM) + if (!global_regd_self) { + int regd_len = 0; + + regd_len = sizeof(struct ieee80211_regdomain) + + (CONST_SYNA_REG_RULES_MAX_QTY * sizeof(struct ieee80211_reg_rule)); + + global_regd_self = kzalloc(regd_len, GFP_ATOMIC); + if (global_regd_self) { + wl_cfg80211_regd_duplicate(global_regd_self, &const_regdom_default); + } + } else { + WL_ERR(("*Warning, use the existed global_regd_self=0x%p\n", global_regd_self)); + } +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM) */ +#endif /* EXT_REG_INFO */ + err = wl_init_scan(cfg); if (err) { WL_ERR(("wl_init_scan failed\n")); @@ -17178,15 +20460,28 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) } } + wl_init_listen_timer(cfg); + /* Update wlc version in cfg struct already queried as part of DHD initialization */ cfg->wlc_ver.wlc_ver_major = dhd->wlc_ver_major; cfg->wlc_ver.wlc_ver_minor = dhd->wlc_ver_minor; - if ((ret = wldev_iovar_getbuf(ndev, "scan_ver", NULL, 0, - ioctl_buf, sizeof(ioctl_buf), NULL)) == BCME_OK) { - WL_INFORM_MEM(("scan_params v2\n")); - /* use scan_params ver2 */ - cfg->scan_params_v2 = true; + ret = wldev_iovar_getbuf(ndev, "scan_ver", NULL, 0, ioctl_buf, sizeof(ioctl_buf), NULL); + if (ret == BCME_OK) { + wl_scan_version_t *ver = (wl_scan_version_t *)ioctl_buf; + if ((ver->scan_ver_major == SCAN_PARAMS_VER_3) || + (ver->scan_ver_major == SCAN_PARAMS_VER_2)) { + /* v2 and v3 structs are of same size just that a pad variable + * has been changed to ssid type for 6G use. That will variable + * get ignored when used with branches supporting V2 struct + */ + cfg->scan_params_ver = ver->scan_ver_major; + WL_INFORM_MEM(("scan_params version:%d\n", cfg->scan_params_ver)); + } else { + WL_INFORM(("scan_ver (%d), UNSUPPORTED\n", ver->scan_ver_major)); + err = -EINVAL; + return err; + } } else { if (ret == BCME_UNSUPPORTED) { WL_INFORM(("scan_ver, UNSUPPORTED\n")); @@ -17197,7 +20492,8 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) } if (((cfg->wlc_ver.wlc_ver_major == MIN_JOINEXT_V1_BR1_FW_MAJOR) && - (cfg->wlc_ver.wlc_ver_minor == MIN_JOINEXT_V1_BR1_FW_MINOR)) || + ((cfg->wlc_ver.wlc_ver_minor == MIN_JOINEXT_V1_BR1_FW_MINOR_2) || + (cfg->wlc_ver.wlc_ver_minor == MIN_JOINEXT_V1_BR1_FW_MINOR_4))) || ((cfg->wlc_ver.wlc_ver_major == MIN_JOINEXT_V1_BR2_FW_MAJOR) && (cfg->wlc_ver.wlc_ver_minor >= MIN_JOINEXT_V1_BR2_FW_MINOR)) || (cfg->wlc_ver.wlc_ver_major >= MIN_JOINEXT_V1_FW_MAJOR)) { @@ -17205,6 +20501,41 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) WL_INFORM_MEM(("join_ver:%d\n", cfg->join_iovar_ver)); } + ret = wldev_iovar_getbuf(ndev, "actframe_ver", NULL, 0, ioctl_buf, sizeof(ioctl_buf), NULL); + if (ret == BCME_OK) { + if (((wl_actframe_version_v1_t *)ioctl_buf)->version == WL_ACTFRAME_VERSION_V1) { + af_ver_p = (wl_actframe_version_v1_t *)ioctl_buf; + } else { + WL_INFORM_MEM(("unsupported -actframe_ver-, add support for ver %d\n", + ((wl_actframe_version_v1_t *)ioctl_buf)->version)); + return BCME_VERSION; + } + + if (af_ver_p->actframe_ver_major == WL_ACTFRAME_VERSION_MAJOR_2) { + /* use actframe_params ver2 */ + WL_INFORM_MEM(("actframe_params v2\n")); + cfg->actframe_params_ver = WL_ACTFRAME_VERSION_MAJOR_2; + } else { + WL_INFORM_MEM(("unsupported actframe_ver, add support" + "for ver %d\n", af_ver_p->actframe_ver_major)); + return BCME_VERSION; + } + } else { + if (ret == BCME_UNSUPPORTED) { + /* Use default version (1) */ + } else { + WL_ERR(("get actframe_ver failed ,err(%d)\n", ret)); + return BCME_ERROR; + } + } + +#ifdef WL_RAV_MSCS_NEG_IN_ASSOC + ret = wl_cfg80211_enable_rav_mscs_params(cfg, ndev, mscs_offload); + if (ret) { + WL_INFORM(("enable rav_mscs failed ,err(%d)\n", ret)); + } +#endif /* WL_RAV_MSCS_NEG_IN_ASSOC */ + #ifdef DHD_LOSSLESS_ROAMING del_timer_sync(&cfg->roam_timeout); #endif /* DHD_LOSSLESS_ROAMING */ @@ -17230,6 +20561,7 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) cfg->wes_mode = OFF; cfg->ncho_mode = OFF; cfg->ncho_band = WLC_BAND_AUTO; + ROAMOFF_DBG_CLR(cfg); #ifdef WBTEXT /* when wifi up, set roam_prof to default value */ if (dhd->wbtext_support) { @@ -17267,8 +20599,13 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) #ifdef WL_SAR_TX_POWER cfg->wifi_tx_power_mode = WIFI_POWER_SCENARIO_INVALID; +#if defined(WL_SAR_TX_POWER_CONFIG) + wl_get_sar_config_info(cfg); +#endif /* WL_SAR_TX_POWER_CONFIG */ #endif /* WL_SAR_TX_POWER */ + cfg->scan_request = NULL; + #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS) /* wlan scan_supp timer and work thread info */ init_timer_compat(&cfg->scan_supp_timer, wl_cfg80211_scan_supp_timerfunc, cfg); @@ -17276,11 +20613,109 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) #endif /* DHCP_SCAN_SUPPRESS */ INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler); - wl_set_drv_status(cfg, READY, ndev); +#ifdef WL_MBO_HOST + cfg->btmreq = NULL; + cfg->btmreq_len = 0; + cfg->btmreq_token = 0; +#endif /* WL_MBO_HOST */ + + /* Initialze dtim configs */ + cfg->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; + cfg->disable_dtim_in_suspend = FALSE; +#ifdef ENABLE_MAX_DTIM_IN_SUSPEND + cfg->max_dtim_enable = TRUE; +#else + cfg->max_dtim_enable = FALSE; +#endif /* ENABLE_MAX_DTIM_IN_SUSPEND */ + +#ifdef CONFIG_SILENT_ROAM + cfg->sroam_turn_on = TRUE; + cfg->sroamed = FALSE; +#endif /* CONFIG_SILTENT_ROAM */ + cfg->roam_allowed_band = WLC_ROAM_ALLOW_BAND_AUTO; + if (FW_SUPPORTED(dhd, rsdb)) { + cfg->num_radios = 2; + } else { + cfg->num_radios = 1; + } + if (FW_SUPPORTED(dhd, sc)) { + cfg->num_radios += 1; + } return err; } +#ifdef BCMDBUS +s32 +__wl_cfg80211_up_resume(dhd_pub_t *dhd) +{ + struct net_device *ndev = dhd_linux_get_primary_netdev(dhd); + struct bcm_cfg80211 *cfg; + struct wireless_dev *wdev; + s32 err = 0; +#ifdef WL_HOST_BAND_MGMT + s32 ret = 0; +#endif /* WL_HOST_BAND_MGMT */ + u16 wl_iftype = 0; + u16 wl_mode = 0; + + WL_DBG(("In\n")); + + if (!ndev) + return -EINVAL; + cfg = wl_get_cfg(ndev); + wdev = ndev->ieee80211_ptr; + if (!cfg || !wdev) + return -EINVAL; + +#if defined(BCMDONGLEHOST) + err = dhd_config_dongle(cfg); + if (unlikely(err)) + return err; +#endif /* defined(BCMDONGLEHOST) */ + +#ifdef SHOW_LOGTRACE + /* Start the event logging */ + wl_add_remove_eventmsg(ndev, WLC_E_TRACE, TRUE); +#endif /* SHOW_LOGTRACE */ +#if defined(BCMDBUS) + if (!dhd->dhd_console_ms) + wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE); +#endif + + if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) { + return -EINVAL; + } + if (!dhd->fw_preinit) { + err = wl_config_infra(cfg, ndev, wl_iftype); + if (unlikely(err && err != -EINPROGRESS)) { + WL_ERR(("wl_config_infra failed\n")); + if (err == -1) { + WL_ERR(("return error %d\n", err)); + return err; + } + } + } + +#ifdef WL_HOST_BAND_MGMT + /* By default the curr_band is initialized to BAND_AUTO */ + if ((ret = wl_cfg80211_set_band(ndev, WLC_BAND_AUTO)) < 0) { + if (ret == BCME_UNSUPPORTED) { + /* Don't fail the initialization, lets just + * fall back to the original method + */ + WL_ERR(("WL_HOST_BAND_MGMT defined, " + "but roam_band iovar not supported \n")); + } else { + WL_ERR(("roam_band failed. ret=%d", ret)); + err = -1; + } + } +#endif /* WL_HOST_BAND_MGMT */ + return err; +} +#endif /* BCMDBUS */ + static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) { s32 err = 0; @@ -17290,7 +20725,7 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) (defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && \ !defined(PLATFORM_SLP) struct net_device *p2p_net = cfg->p2p_net; -#endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT) && !PLATFORM_SLP */ +#endif #ifdef BCMDONGLEHOST dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); #endif /* BCMDONGLEHOST */ @@ -17333,6 +20768,8 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) cancel_delayed_work_sync(&cfg->ap_work); } + cancel_delayed_work_sync(&cfg->recovery_work); + if (cfg->p2p_supported) { wl_clr_p2p_status(cfg, GO_NEG_PHASE); #ifdef PROP_TXSTATUS_VSDB @@ -17361,8 +20798,27 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) cancel_work_sync(&cfg->wlan_work); #endif /* DHCP_SCAN_SUPPRESS */ +#ifdef WL_SCHED_SCAN + if (cfg->sched_scan_req) { + struct wireless_dev *wdev = ndev->ieee80211_ptr; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) + wl_cfg80211_sched_scan_stop(wdev->wiphy, ndev, + cfg->sched_scan_req->reqid); +#else + wl_cfg80211_sched_scan_stop(wdev->wiphy, ndev); +#endif /* KERNEL >= 4.11 */ + } +#endif /* WL_SCHED_SCAN */ + #ifdef WL_SAR_TX_POWER cfg->wifi_tx_power_mode = WIFI_POWER_SCENARIO_INVALID; +#if defined(WL_SAR_TX_POWER_CONFIG) + if (cfg->sar_config_info != NULL) { + MFREE(cfg->osh, cfg->sar_config_info, + sizeof(wl_sar_config_info_t) * cfg->sar_config_info_cnt); + cfg->sar_config_info_cnt = 0; + } +#endif /* WL_SAR_TX_POWER_CONFIG */ #endif /* WL_SAR_TX_POWER */ if (!dhd_download_fw_on_driverload) { /* For built-in drivers/other drivers that do reset on @@ -17374,6 +20830,8 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) /* Clear used mac addr mask */ cfg->vif_macaddr_mask = 0; + /* Clear the latency mode value */ + cfg->latency_mode = LATENCY_CRT_DATA_MODE_OFF; #ifdef BCMDONGLEHOST if (dhd->up) #endif /* BCMDONGLEHOST */ @@ -17429,7 +20887,7 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); struct wireless_dev *wdev = ndev->ieee80211_ptr; struct cfg80211_bss *bss = CFG80211_GET_BSS(wiphy, NULL, latest_bssid, - wdev->ssid, wdev->ssid_len); + WDEV_CLIENT(wdev, ssid), WDEV_CLIENT(wdev, ssid_len)); BCM_REFERENCE(bss); @@ -17450,8 +20908,10 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) wl_clr_drv_status(cfg, NESTED_CONNECT, iter->ndev); wl_clr_drv_status(cfg, CFG80211_CONNECT, iter->ndev); } - bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype = - NL80211_IFTYPE_STATION; +#ifdef WL_CFG80211_MONITOR + if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_MONITOR) +#endif /* WL_CFG80211_MONITOR */ + ndev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; #if defined(WL_CFG80211) && \ (defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && \ !defined(PLATFORM_SLP) @@ -17460,8 +20920,15 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) #endif /* SUPPORT_DEEP_SLEEP */ if (p2p_net) dev_close(p2p_net); -#endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT)&& !PLATFORM_SLP */ +#endif /* WL_CFG80211 && WL_NEWCFG_PRIVCMD_SUPPORT */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM) \ + && defined(EXT_REG_INFO) + if (global_regd_self) { + kfree(global_regd_self); + global_regd_self = NULL; + } +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && WL_SELF_MANAGED_REGDOM && EXT_REG_INFO */ /* Avoid deadlock from wl_cfg80211_down */ #if defined(BCMDONGLEHOST) && defined(__linux__) if (!dhd_download_fw_on_driverload) { @@ -17501,14 +20968,7 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) } #endif /* WL11U */ -#ifdef CUSTOMER_HW4_DEBUG - if (wl_scan_timeout_dbg_enabled) { - wl_scan_timeout_dbg_clear(); - } -#endif /* CUSTOMER_HW4_DEBUG */ - cfg->disable_roam_event = false; - cfg->scan_params_v2 = false; DNGL_FUNC(dhd_cfg80211_down, (cfg)); @@ -17516,6 +20976,11 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) /* Printout all netinfo entries */ wl_probe_wdev_all(cfg); #endif /* DHD_IFDEBUG */ +#ifdef WL_MBO_HOST + if (cfg->btmreq) { + MFREE(dhd->osh, cfg->btmreq, cfg->btmreq_len); + } +#endif /* WL_MBO_HOST */ return err; } @@ -17536,9 +21001,15 @@ s32 wl_cfg80211_up(struct net_device *net) #ifdef WL_USE_RANDOMIZED_SCAN uint8 random_addr[ETHER_ADDR_LEN] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00}; #endif /* WL_USE_RANDOMIZED_SCAN */ +#ifdef EXT_REG_INFO + wl_country_t cur_cspec = {{0}, 0, {0}}; +#endif /* EXT_REG_INFO */ WL_DBG(("In\n")); cfg = wl_get_cfg(net); +#ifdef WL_DUAL_STA + cfg->inet_ndev = net; +#endif /* WL_DUAL_STA */ if ((err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val, sizeof(int)) < 0)) { WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err)); @@ -17588,7 +21059,7 @@ s32 wl_cfg80211_up(struct net_device *net) if (init_roam_cache(cfg, ioctl_version) == 0) { /* Enable support for Roam cache */ cfg->rcc_enabled = true; - WL_ERR(("Roam channel cache enabled\n")); + WL_MSG(net->name, "Roam channel cache enabled\n"); } else { WL_ERR(("Failed to enable RCC.\n")); } @@ -17606,9 +21077,7 @@ s32 wl_cfg80211_up(struct net_device *net) } } #endif /* WL_USE_RANDOMIZED_SCAN */ -/* WAR: disable pm_bcnrx , scan_ps for BCM4354 WISOL module. - * WISOL module have ANT_1 Rx sensitivity issue. - */ + #if defined(FORCE_DISABLE_SINGLECORE_SCAN) dhd_force_disable_singlcore_scan(dhd); #endif /* FORCE_DISABLE_SINGLECORE_SCAN */ @@ -17636,6 +21105,33 @@ s32 wl_cfg80211_up(struct net_device *net) bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME); #endif /* WLAIBSS_MCHAN */ cfg->spmk_info_list->pmkids.count = 0; + +#ifdef EXT_REG_INFO + err = wldev_iovar_getbuf(net, "country", NULL, 0, &cur_cspec, + sizeof(cur_cspec), NULL); + if (err < 0) { + WL_ERR(("get country code failed = %d\n", err)); + return err; + } + if (strncmp(cfg->country, cur_cspec.ccode, WL_CCODE_LEN)) { + strncpy(cfg->country, cur_cspec.ccode, WLC_CNTRY_BUF_SZ); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) + cfg->wdev->wiphy->regulatory_flags &= ~REGULATORY_WIPHY_SELF_MANAGED; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + cfg->wdev->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */ + err = wl_update_wiphybands(cfg, true); + wl_cfg80211_regd_update(cfg, cur_cspec.ccode); + } +#endif /* EXT_REG_INFO */ + + if (err == BCME_OK) { + wl_set_drv_status(cfg, READY, net); + } +#ifdef WL_P2P_6G + cfg->p2p_6g_enabled = TRUE; +#endif /* WL_P2P_6G */ return err; } @@ -17756,6 +21252,13 @@ s32 wl_cfg80211_down(struct net_device *dev) err = __wl_cfg80211_down(cfg); mutex_unlock(&cfg->usr_sync); } +#ifdef TPUT_DEBUG_DUMP + wl_cfgdbg_tput_debug_mode(dev, FALSE); +#endif /* TPUT_DEBUG_DUMP */ +#if defined(OEM_ANDROID) + /* Kill CMD_BTCOEXMODE timer/handler if those are enabled */ + wl_cfg80211_btcoex_kill_handler(); +#endif /* defined(OEM_ANDROID) */ return err; } @@ -17961,7 +21464,7 @@ s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pd return -1; if (!p2p_is_on(cfg)) { get_primary_mac(cfg, &primary_mac); - memcpy((void *)&p2pdev_addr, (void *)&primary_mac, ETHER_ADDR_LEN); + memcpy((void *)p2pdev_addr, (void *)&primary_mac, ETHER_ADDR_LEN); } else { memcpy(p2pdev_addr->octet, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE).octet, ETHER_ADDR_LEN); @@ -17969,6 +21472,7 @@ s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pd return 0; } + s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) { struct bcm_cfg80211 *cfg = wl_get_cfg(net); @@ -18038,12 +21542,12 @@ wl_notify_device_discovery(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, int err = 0; u32 event = ntoh32(e->event_type); wl_cfg80211_dev_info_t info; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; struct net_device *ndev = NULL; u8 *buf = NULL; u32 buflen = 0; u16 channel = 0; - wl_escan_result_t *escan_result; + wl_escan_result_v109_t *escan_result; chanspec_t chspec = INVCHANSPEC; WL_SD(("Enter. type:%d \n", event)); @@ -18061,7 +21565,7 @@ wl_notify_device_discovery(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, err = wl_genl_send_msg(ndev, event, (const u8 *)e->addr.octet, ETH_ALEN, 0, 0); } else { - escan_result = (wl_escan_result_t *) data; + escan_result = (wl_escan_result_v109_t *) data; if (dtoh16(escan_result->bss_count) != 1) { WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count)); @@ -19025,13 +22529,33 @@ int wl_cfg80211_do_driver_init(struct net_device *net) return 0; } +void wl_cfg80211_enable_log_trace(bool set, u32 level) +{ + if (set) { + wl_log_level = level & WL_DBG_LEVEL; + } else { + wl_log_level |= (WL_DBG_LEVEL & level); + } +} + void wl_cfg80211_enable_trace(u32 level) { wl_dbg_level = level; WL_MSG("wlan", "wl_dbg_level = 0x%x\n", wl_dbg_level); } -#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) +uint32 wl_cfg80211_get_print_level(void) +{ + return wl_dbg_level; +} + +uint32 wl_cfg80211_get_log_level(void) +{ + return wl_log_level; +} + +#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ + 2, 0)) static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, u64 cookie) @@ -19315,6 +22839,21 @@ wl_cfg80211_filter_vndr_ext_id(const vndr_ie_t *vndrie) WL_DBG(("%s:SKIP ADDING FILS HLP EXTN ID\n", __func__)); return true; } +#ifdef WL_CAP_OCE_STA + if (vndrie->oui[0] == FILS_EXTID_MNG_REQ_PARAMS) { + /* Skip adding fils FILS_MAX_CHANNEL_TIME, its already done in FW */ + WL_DBG(("%s:SKIP ADDING FILS MNG REQ PARAMS \n", __func__)); + return true; + } +#endif /* WL_CAP_OCE_STA */ + if ((vndrie->oui[0] == EXT_MNG_HE_CAP_ID) || + (vndrie->oui[0] == EXT_MNG_HE_OP_ID)) { + /* Skip adding HE Capabilities ie and HE operation IE + */ + WL_DBG(("%s:SKIP ADDING HE EXTN ID\n", __func__)); + return true; + } + return false; } @@ -19678,6 +23217,40 @@ wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg) return 0; } +#ifdef GET_FW_IE_DATA +static void +wl_dump_ie_buf(vndr_ie_buf_t *ie_getbuf) +{ + uchar *iebuf; + uchar *data; + int tot_ie, pktflag, iecount, datalen; + vndr_ie_info_t *ie_info; + vndr_ie_t *ie; + + memcpy(&tot_ie, (void *)&ie_getbuf->iecount, sizeof(int)); + tot_ie = dtoh32(tot_ie); + iebuf = (uchar *)&ie_getbuf->vndr_ie_list[0]; + + printf("-----------------\n"); + printf("Total IEs %d\n", tot_ie); + for (iecount = 0; iecount < tot_ie; iecount++) { + ie_info = (vndr_ie_info_t *) iebuf; + memcpy(&pktflag, (void *)&ie_info->pktflag, sizeof(uint32)); + pktflag = dtoh32(pktflag); + iebuf += sizeof(uint32); + ie = &ie_info->vndr_ie_data; + data = &ie->data[0]; + datalen = ie->len - VNDR_IE_MIN_LEN; + printf("index=%d, pktflag=0x%x\n", iecount, pktflag); + prhex("IE", (u8 *)ie, ie->len+VNDR_IE_HDR_LEN); + + iebuf += ie->len + VNDR_IE_HDR_LEN; + } + printf("-----------------\n"); + printf("\n"); +} +#endif /* GET_FW_IE_DATA */ + static void wl_print_fw_ie_data(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx) { @@ -19689,18 +23262,10 @@ wl_print_fw_ie_data(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssid bssidx, &cfg->ioctl_buf_sync); if (ret == BCME_OK) { ies = (vndr_ie_buf_t *)cfg->ioctl_buf; - WL_INFORM_MEM(("FW IE count:%d ", ies->iecount)); #ifdef GET_FW_IE_DATA - if (wl_dbg_level & WL_DBG_DBG) { - int i = 0; - /* If debug enabled, print each IE */ - for (i = 0; i < ies->iecount; i++) { - vndr_ie_info_t *info = &ies->vndr_ie_list[i]; - WL_DBG_MEM(("pktflag:0x%x\n", info->pktflag)); - prhex("IE:", (u8 *)&info->vndr_ie_data, - info->vndr_ie_data.len + TLV_HDR_LEN); - } - } + wl_dump_ie_buf((vndr_ie_buf_t *)cfg->ioctl_buf); +#else + WL_MSG(ndev->name, "FW IE count:%d\n", ies->iecount); #endif /* GET_FW_IE_DATA */ } else { WL_ERR(("IE retrieval failed! ret:%d\n", ret)); @@ -19709,6 +23274,27 @@ wl_print_fw_ie_data(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssid #define WL_VNDR_IE_MAXLEN 2048 static s8 g_mgmt_ie_buf[WL_VNDR_IE_MAXLEN]; +static int +wl_get_p2p_disc_ies(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev, + u8 **p2p_ie, u16 *p2p_ie_len) +{ + wl_bss_vndr_ies_t *ies = NULL; + struct net_info *netinfo; + + netinfo = wl_get_netinfo_by_wdev(cfg, wdev); + if (!netinfo) { + WL_ERR(("net_info ptr is NULL \n")); + return -EINVAL; + } + + ies = &netinfo->bss.ies; + *p2p_ie = ies->probe_req_ie; + *p2p_ie_len = ies->probe_req_ie_len; + WL_DBG(("probe_req_len:%d bssidx:%d\n", ies->probe_req_ie_len, netinfo->bssidx)); + + return BCME_OK; +} + int wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, s32 bssidx, s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len) @@ -19724,6 +23310,7 @@ wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgde u32 parsed_ie_buf_len = 0; struct parsed_vndr_ies old_vndr_ies; struct parsed_vndr_ies new_vndr_ies; + int del_add_cnt = 0; s32 i; u8 *ptr; s32 remained_buf_len; @@ -19867,6 +23454,7 @@ wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgde curr_ie_buf += del_add_ie_buf_len; total_ie_buf_len += del_add_ie_buf_len; + del_add_cnt++; } } @@ -19916,13 +23504,32 @@ wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgde *mgmt_ie_len += vndrie_info->ie_len; curr_ie_buf += del_add_ie_buf_len; total_ie_buf_len += del_add_ie_buf_len; + del_add_cnt++; } } if (total_ie_buf_len && cfg->ioctl_buf != NULL) { - ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf, +#ifdef VNDR_IE_WAR + curr_ie_buf = g_mgmt_ie_buf; + for (i=0; ivndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0] - + (u8*)vndr_ie_setbuf; + curr_ie_buf_len += vndr_ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len; + ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", curr_ie_buf, + curr_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, + bssidx, &cfg->ioctl_buf_sync); + if (ret) + break; + curr_ie_buf += curr_ie_buf_len; + } +#else + ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf, total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); +#endif if (ret) { WL_ERR(("vndr_ie set error :%d\n", ret)); if (ret == BCME_NOTFOUND) { @@ -20034,9 +23641,8 @@ static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev, const struct cfg80211_pmk_conf *conf) { int ret = 0; - wsec_pmk_t pmk; + wsec_pmk_t pmk = {0}; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct wl_security *sec; s32 bssidx; pmk.key_len = conf->pmk_len; @@ -20057,16 +23663,7 @@ static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev, return ret; } - sec = wl_read_prof(cfg, dev, WL_PROF_SEC); - if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) || - (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) { - ret = wldev_iovar_setbuf_bsscfg(dev, "okc_info_pmk", pmk.key, pmk.key_len, - cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync); - if (ret) { - /* could fail in case that 'okc' is not supported */ - WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", ret)); - } - } + wl_cfg80211_set_okc_pmkinfo(cfg, dev, pmk, TRUE); ret = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk)); if (ret) { @@ -20074,7 +23671,7 @@ static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev, ret = -EINVAL; return ret; } else { - WL_DBG(("pmk added for mac:"MACDBG"\n", MAC2STRDBG(conf->aa))); + WL_INFORM_MEM(("pmk added for mac:"MACDBG"\n", MAC2STRDBG(conf->aa))); } return 0; } @@ -20101,6 +23698,75 @@ static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev, } #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) +static int wl_cfg80211_update_owe_info(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_update_owe_info *oweinfo) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + wl_assoc_resp_params_v1_t *assoc_resp_params = NULL; + uint8 *resp_buf = NULL; + uint8 *p_resp_ies_tlv = NULL; + uint16 assoc_params_iovsize; + + WL_DBG(("%s: Enter\n", __func__)); + + resp_buf = MALLOCZ(dhdp->osh, AP_OWE_IOCTL_BUF_SIZE); + if (resp_buf == NULL) { + WL_ERR(("error: failed to allocate %d bytes of memory\n", AP_OWE_IOCTL_BUF_SIZE)); + err = BCME_NOMEM; + goto exit; + } + + assoc_params_iovsize = AP_OWE_ASSOC_RESP_PARAMS_BUFSZ + + OFFSETOF(wl_assoc_resp_params_v1_t, ies); + assoc_resp_params = (wl_assoc_resp_params_v1_t *)MALLOCZ(dhdp->osh, assoc_params_iovsize); + + if (assoc_resp_params == NULL) { + WL_ERR(("error: failed to allocate %d bytes of memory\n", assoc_params_iovsize)); + err = BCME_NOMEM; + goto exit; + } + /* setup assoc_resp_params iovar */ + assoc_resp_params->version = WL_ASSOC_RESP_PARAMS_V1; + assoc_resp_params->len = assoc_params_iovsize; + assoc_resp_params->fixed_length = OFFSETOF(wl_assoc_resp_params_v1_t, ies); + /* setup TLVs */ + p_resp_ies_tlv = (uint8 *)&assoc_resp_params->ies[0]; + + if (wl_dbg_level & WL_DBG_DBG) { + if (oweinfo) { + prhex("supplicant MAC", oweinfo->peer, ETHER_ADDR_LEN); + prhex("supplicant generated OWE IE", oweinfo->ie, oweinfo->ie_len); + } + } + + if (oweinfo->ie_len > AP_OWE_ASSOC_RESP_PARAMS_BUFSZ) { + WL_ERR(("no resp ies buffer left\n")); + err = -EINVAL; + goto exit; + } + (void)memcpy_s(assoc_resp_params->mac_addr, ETHER_ADDR_LEN, + oweinfo->peer, ETHER_ADDR_LEN); + (void)memcpy_s(p_resp_ies_tlv, AP_OWE_ASSOC_RESP_PARAMS_BUFSZ, + oweinfo->ie, oweinfo->ie_len); + assoc_resp_params->resp_ie_len = oweinfo->ie_len; + assoc_resp_params->status = oweinfo->status; + err = wldev_iovar_setbuf(dev, "assoc_resp_params", assoc_resp_params, + assoc_params_iovsize, resp_buf, AP_OWE_IOCTL_BUF_SIZE, NULL); + if (err) { + WL_DBG(("ap_assoc_resp_params failed, err=%d\n", err)); + } +exit: + if (resp_buf) + MFREE(dhdp->osh, resp_buf, AP_OWE_IOCTL_BUF_SIZE); + if (assoc_resp_params) + MFREE(dhdp->osh, assoc_resp_params, assoc_params_iovsize); + return err; +} +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) */ + u64 wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 *cfg) { @@ -20424,6 +24090,7 @@ wl_cfg80211_recv_nbr_resp(struct net_device *dev, uint8 *body, uint body_len) return BCME_OK; } #endif /* WBTEXT */ + #ifdef SUPPORT_SET_CAC void wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable) @@ -20492,8 +24159,8 @@ wl_get_rssi_per_ant(struct net_device *dev, char *ifname, char *peer_mac, void * WL_ERR(("Failed to get rssi info, err=%d\n", err)); } else { memcpy(get_param, iobuf, sizeof(wl_rssi_ant_mimo_t)); - if (get_param->count == 0) { - WL_ERR(("Not supported on this chip\n")); + if (get_param->count == 0 || get_param->rssi_sum >= 0) { + WL_INFORM(("Not supported on this chip\n")); err = BCME_UNSUPPORTED; } } @@ -20543,6 +24210,7 @@ wl_set_rssi_logging(struct net_device *dev, void *param) return err; } #endif /* SUPPORT_RSSI_SUM_REPORT */ + /* Function to flush the FW preserve buffer content * The buffer content is sent to host in form of events. */ @@ -20573,6 +24241,7 @@ wl_flush_fw_log_buffer(struct net_device *dev, uint32 logset_mask) } } } + #ifdef USE_WFA_CERT_CONF extern int g_frameburst; #endif /* USE_WFA_CERT_CONF */ @@ -20596,6 +24265,8 @@ wl_cfg80211_set_frameburst(struct bcm_cfg80211 *cfg, bool enable) WL_ERR(("Failed set frameburst, ret=%d\n", ret)); } else { WL_INFORM_MEM(("frameburst is %s\n", enable ? "enabled" : "disabled")); + /* Track disabled state */ + cfg->frameburst_disabled = (enable ? FALSE : TRUE); } return ret; @@ -20608,9 +24279,11 @@ wl_cfg80211_set_dbg_verbose(struct net_device *ndev, u32 level) if (level) { /* Enable increased verbose */ wl_dbg_level |= WL_DBG_DBG; + wl_log_level |= WL_DBG_DBG; } else { /* Disable */ wl_dbg_level &= ~WL_DBG_DBG; + wl_log_level &= ~WL_DBG_DBG; } WL_INFORM(("debug verbose set to %d\n", level)); @@ -20911,17 +24584,6 @@ wl_wps_handle_peersta_linkdown(struct net_device *ndev, u16 inst, const u8 *peer WL_INFORM_MEM(("[%s][WPS] REAUTH link down." " Peer: " MACDBG "\n", ndev->name, MAC2STRDBG(peer_mac))); -#ifdef NOT_YET - /* Link down during REAUTH state is expected. However, - * if this is send up, hostapd statemachine issues a - * deauth down and that may pre-empt WPS reauth state - * at GC. - */ - WL_INFORM_MEM(("[%s][WPS] REAUTH link down. Ignore." - " for client:" MACDBG "\n", - ndev->name, MAC2STRDBG(peer_mac))); - ret = BCME_UNSUPPORTED; -#endif } else if (cur_state == WPS_STATE_STARTED) { /* Link down before reaching REAUTH_WAIT state. WPS * session ended. @@ -21478,6 +25140,9 @@ wl_cfg80211_sup_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgde u32 status = ntoh32(event->status); struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); u32 reason = ntoh32(event->reason); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) + const u8 *curbssid = (const u8 *)event->addr.octet; +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(4, 15, 0) */ if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) { /* Join attempt via non-cfg80211 interface. @@ -21489,20 +25154,29 @@ wl_cfg80211_sup_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgde return BCME_OK; } + WL_INFORM_MEM(("idsup status:%d reason:%d\n", status, reason)); if ((status == WLC_SUP_KEYED || status == WLC_SUP_KEYXCHANGE_WAIT_G1) && reason == WLC_E_SUP_OTHER) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) - /* NL80211_CMD_PORT_AUTHORIZED supported above >= 4.15 */ - cfg80211_port_authorized(ndev, (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID), - GFP_KERNEL); - WL_INFORM_MEM(("4way HS finished. port authorized event sent\n")); -#elif ((LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)) + if (!ETHER_ISNULLADDR(curbssid)) { + WL_DBG(("Authorizing Port with BSSID from FW event " MACDBG" \n", + MAC2STRDBG(curbssid))); + } else { + curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + WL_DBG(("Authorizing Port with BSSID from DHD profile " MACDBG" \n", + MAC2STRDBG(curbssid))); + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 2, 0)) || \ + ((ANDROID_VERSION >= 13) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 94))) + cfg80211_port_authorized(ndev, (const u8 *)curbssid, NULL, 0, GFP_KERNEL); +#else + cfg80211_port_authorized(ndev, (const u8 *)curbssid, GFP_KERNEL); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 2, 0) */ +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) err = wl_cfgvendor_send_async_event(bcmcfg_to_wiphy(cfg), ndev, BRCM_VENDOR_EVENT_PORT_AUTHORIZED, NULL, 0); +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0) || WL_VENDOR_EXT_SUPPORT */ WL_INFORM_MEM(("4way HS finished. port authorized event sent\n")); -#else - /* not supported in kernel <= 3,14,0 */ -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) */ /* Post SCB authorize actions */ wl_cfg80211_post_scb_auth(cfg, ndev); } else if (status < WLC_SUP_KEYXCHANGE_WAIT_G1 && (reason != WLC_E_SUP_OTHER && @@ -21564,6 +25238,128 @@ wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } return err; } + +#ifdef WL_MBO_HOST +static s32 +wl_mbo_btm_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + struct net_device *ndev = NULL; + u8 *mgmt_frame = NULL; + s32 chan; + chanspec_t chanspec; + s32 freq; + struct ether_addr da; + struct ether_addr bssid; + u32 len = ntoh32(e->datalen); + int err = BCME_OK; + dot11_bsstrans_req_t *req; + dot11_bsstrans_resp_t *res; + uchar action_cat = ((uchar *)data)[DOT11_ACTION_CAT_OFF]; + uchar action_type = ((uchar *)data)[DOT11_ACTION_ACT_OFF]; + uchar token; + uchar status; + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + + if (action_type == DOT11_WNM_ACTION_BSSTRANS_REQ && + len >= DOT11_BSSTRANS_REQ_LEN) { + + req = (dot11_bsstrans_req_t*)data; + action_cat = req->category; + action_type = req->action; + token = req->token; + + if (action_cat != DOT11_ACTION_CAT_WNM) { + return BCME_BADARG; + } + + if (cfg->btmreq) { + MFREE(cfg->osh, cfg->btmreq, cfg->btmreq_len); + cfg->btmreq = NULL; + cfg->btmreq_len = 0; + cfg->btmreq_token = 0; + } + + (void)memcpy_s(da.octet, ETHER_ADDR_LEN, ndev->dev_addr, ETHER_ADDR_LEN); + + bzero(&bssid, sizeof(bssid)); + err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN); + /* Use e->addr as bssid for Sta case , before association completed */ + if (err == BCME_NOTASSOCIATED) { + (void)memcpy_s(&bssid, ETHER_ADDR_LEN, &e->addr, ETHER_ADDR_LEN); + err = BCME_OK; + } + if (unlikely(err)) { + WL_ERR(("%s: Could not get bssid %d\n", __FUNCTION__, err)); + return err; + } + + err = wl_frame_get_mgmt(cfg, FC_ACTION, &da, &e->addr, &bssid, + &mgmt_frame, &len, data); + if (!err) { + cfg->btmreq = mgmt_frame; + cfg->btmreq_len = len; + cfg->btmreq_token = token; + } + } else if (action_type == DOT11_WNM_ACTION_BSSTRANS_RESP && + len >= DOT11_BSSTRANS_RESP_LEN) { + res = (dot11_bsstrans_resp_t*)data; + action_cat = res->category; + action_type = res->action; + token = res->token; + status = res->status; + + if (action_cat != DOT11_ACTION_CAT_WNM) { + return BCME_BADARG; + } + + if (!cfg->btmreq || !cfg->btmreq_len) { + WL_ERR(("%s: No saved BSSTRANS Req frame. btmreq_len:%d\n", + __FUNCTION__, cfg->btmreq_len)); + return err; + } + + if (cfg->btmreq_token == token) { + err = wldev_iovar_getint(ndev, "chanspec", &chan); + if (unlikely(err)) { + WL_ERR(("%s: Could not get chanspec %d\n", __FUNCTION__, err)); + return err; + } + + chanspec = wl_chspec_driver_to_host(chan); + freq = wl_channel_to_frequency(wf_chspec_ctlchan(chanspec), + CHSPEC_BAND(chanspec)); + + WL_INFORM_MEM(("Send btmreq action frame token:%u len:%u\n", + token, cfg->btmreq_len)); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) + cfg80211_rx_mgmt(cfgdev, freq, 0, cfg->btmreq, cfg->btmreq_len, GFP_KERNEL); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) + cfg80211_rx_mgmt(ndev, freq, 0, cfg->btmreq, cfg->btmreq_len, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(ndev, freq, cfg->btmreq, cfg->btmreq_len, GFP_KERNEL); +#endif + } else { + WL_ERR(("%s: BSSTRANS Res status:%u ReqToken:%u ResToken:%u\n", + __FUNCTION__, status, cfg->btmreq_token, token)); + } + + /* When the wrong frame comes up, initialize the saved Req */ + if (cfg->btmreq) { + MFREE(cfg->osh, cfg->btmreq, cfg->btmreq_len); + cfg->btmreq = NULL; + cfg->btmreq_len = 0; + cfg->btmreq_token = 0; + } + } else { + WL_ERR(("%s: Wrong case act type:%u len:%u\n", __FUNCTION__, action_type, len)); + err = BCME_ERROR; + } + + return err; +} +#endif /* WL_MBO_HOST */ #endif /* WL_MBO */ #ifdef WL_CAC_TS @@ -21596,7 +25392,6 @@ wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgde } #endif /* WL_CAC_TS */ -#if defined(WL_MBO) || defined(WL_OCE) static s32 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) @@ -21604,6 +25399,10 @@ wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev s32 err = 0; uint reason = 0; wl_bssid_pruned_evt_info_t *evt_info = (wl_bssid_pruned_evt_info_t *)data; +#ifdef AUTH_ASSOC_STATUS_EXT + struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); +#endif /* AUTH_ASSOC_STATUS_EXT */ if (evt_info->version == WL_BSSID_PRUNE_EVT_VER_1) { if (evt_info->reason == WLC_E_PRUNE_ASSOC_RETRY_DELAY) { @@ -21619,6 +25418,22 @@ wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev " reason=%u timeout_val=%u(ms) rssi_threshold=%d(dBm)\n", evt_info->SSID, ETHER_TO_MACF(evt_info->BSSID), reason, evt_info->time_remaining, evt_info->rssi_threshold)); + } else if (evt_info->reason == WLC_E_PRUNE_CHANNEL_NOT_IN_VLP) { + /* AP Channel not in VLP */ + reason = WIFI_PRUNE_CHANNEL_NOT_IN_VLP; + SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF + " reason=%u\n", + evt_info->SSID, ETHER_TO_MACF(evt_info->BSSID), reason)); +#ifdef AUTH_ASSOC_STATUS_EXT + sec->auth_assoc_res_status = AUTH_ASSOC_STATUS_CHAN_NOVLP; + WL_ERR(("event %d: AP Channel not in VLP\n", ntoh32(e->event_type))); +#endif /* AUTH_ASSOC_STATUS_EXT */ + } else if (evt_info->reason == WLC_E_PRUNE_WRONG_COUNTRY_CODE) { + /* STA-AP country mismatch */ + reason = WIFI_PRUNE_WRONG_CCODE; + SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF + " reason=%u\n", + evt_info->SSID, ETHER_TO_MACF(evt_info->BSSID), reason)); } else { /* Invalid other than the assoc retry delay/RSSI assoc rejection * in the current handler @@ -21632,7 +25447,7 @@ wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev } return err; } -#endif /* WL_MBO || WL_OCE */ + #ifdef RTT_SUPPORT static s32 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, @@ -21643,6 +25458,7 @@ wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgde (void)memcpy_s(&event, sizeof(wl_event_msg_t), e, sizeof(wl_event_msg_t)); + return dhd_rtt_event_handler(dhdp, &event, data); } #endif /* RTT_SUPPORT */ @@ -21721,13 +25537,14 @@ int wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 *cfg) } } } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \ -(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ + 4 && __GNUC_MINOR__ >= 6)) _Pragma("GCC diagnostic pop") #endif exit: return cmode; } + #ifdef WL_CHAN_UTIL static s32 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, @@ -21738,7 +25555,7 @@ wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cf s32 status = ntoh32(e->status); u8 chan_use_percentage = 0; #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \ - LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */ /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */ @@ -21999,6 +25816,35 @@ wl_cfg80211_wips_event(uint16 misdeauth, char* bssid) } #endif /* WL_WIPSEVT */ +static void +wl_attempt_recovery(struct bcm_cfg80211 *cfg, u32 reason) +{ + if ((reason == WL_STATE_SCANNING) && + (wl_get_drv_status_all(cfg, SCANNING))) { + wl_cfgscan_cancel_scan(cfg); + WL_ERR(("force clear scanning state\n")); + wl_clr_drv_status_all(cfg, SCANNING); + } +} + +static void +wl_cfg80211_recovery_handler(struct work_struct *work) +{ + struct bcm_cfg80211 *cfg = NULL; + u32 cfg_hang_reason = HANG_REASON_UNKNOWN; + + BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, recovery_work.work); + + if (cfg->recovery_state) { + wl_attempt_recovery(cfg, cfg->recovery_state); + cfg_hang_reason = HANG_REASON_DS_SKIP_TIMEOUT; + } + + WL_ERR(("**trigger hang event for recovery state:%d\n", cfg->recovery_state)); + wl_cfg80211_handle_hang_event(bcmcfg_to_prmry_ndev(cfg), + cfg_hang_reason, DUMP_TYPE_CFG_VENDOR_TRIGGERED); +} + #ifdef PCIE_INB_DW #define WL_DS(x) /* @@ -22054,7 +25900,14 @@ bool wl_cfg80211_check_in_progress(struct net_device *dev) WL_ERR(("DS skip threshold hit. reason:%d start_time:" SEC_USEC_FMT" cur_time:"SEC_USEC_FMT"\n", reason, GET_SEC_USEC(start_time), GET_SEC_USEC(curtime))); - ASSERT((0)); + /* Force clear states and send a hang event */ + cfg->recovery_state = reason; + if (!schedule_delayed_work(&cfg->recovery_work, + msecs_to_jiffies((const unsigned int)10))) { + /* Unexpected. If it happens, don't block suspend */ + WL_ERR(("recovery work schedule failed!!\n")); + return false; + } } /* return true to skip suspend */ return true; @@ -22104,18 +25957,25 @@ get_dpp_pa_ftype(enum wl_dpp_ftype ftype) #define GAS_RESP_LEN 2 #define DOUBLE_TLV_BODY_OFF 4 -bool wl_cfg80211_find_gas_subtype(u8 subtype, u16 adv_id, u8* data, u32 len) +bool wl_cfg80211_find_gas_subtype(u8 subtype, u16 adv_id, u8* data, s32 len) { const bcm_tlv_t *ie = (bcm_tlv_t *)data; const u8 *frame = NULL; u16 id, flen; + if (len <= 0) { + return false; + } /* Skipped first ANQP Element, if frame has anqp elemnt */ ie = bcm_parse_tlvs(ie, len, DOT11_MNG_ADVERTISEMENT_ID); if (ie == NULL) return false; + if (len < (ie->len + TLV_HDR_LEN + GAS_RESP_LEN + DOUBLE_TLV_BODY_OFF)) { + return false; + } + frame = (const uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN; id = ((u16) (((frame)[1] << 8) | (frame)[0])); flen = ((u16) (((frame)[3] << 8) | (frame)[2])); @@ -22156,8 +26016,8 @@ bool wl_cfg80211_is_dpp_gas_action(void *frame, u32 frame_len) } if (ie && (ie->len >= WL_GAS_MIN_LEN) && - (memcmp(&ie->data[WL_GAS_WFA_OFFSET], WFA_OUI, 3) == 0) && - (ie->data[WL_GAS_STYPE_OFFSET] == WL_GAS_WFA_STYPE_DPP)) { + (memcmp(ie->data + WL_GAS_WFA_OFFSET, WFA_OUI, 3) == 0) && + (*(ie->data + WL_GAS_STYPE_OFFSET) == WL_GAS_WFA_STYPE_DPP)) { WL_DBG(("DPP GAS FRAME. type:%d\n", act_frm->action)); return true; } @@ -22170,15 +26030,15 @@ bool wl_cfg80211_is_dpp_gas_action(void *frame, u32 frame_len) #define KA_TEMP_BUF_SIZE 512 #define KA_FRAME_SIZE 300 int -wl_cfg80211_start_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id, - uint16 ether_type, uint8 *ip_pkt, uint16 ip_pkt_len, +wl_cfg80211_start_mkeep_alive(struct net_device *ndev, struct bcm_cfg80211 *cfg, + uint8 mkeep_alive_id, uint16 ether_type, uint8 *ip_pkt, uint16 ip_pkt_len, uint8* src_mac, uint8* dst_mac, uint32 period_msec) { const int ETHERTYPE_LEN = 2; char *pbuf = NULL; const char *str; - wl_mkeep_alive_pkt_t mkeep_alive_pkt; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp = NULL; + wl_mkeep_alive_pkt_v1_t mkeep_alive_pkt; + wl_mkeep_alive_pkt_v1_t *mkeep_alive_pktp = NULL; uint16 buf_len = 0; u8 str_len = 0; int res = BCME_ERROR; @@ -22191,8 +26051,6 @@ wl_cfg80211_start_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id, char *pmac_frame = NULL; char *pmac_frame_begin = NULL; dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - struct net_device *primary_ndev = NULL; - primary_ndev = bcmcfg_to_prmry_ndev(cfg); /* * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, @@ -22219,14 +26077,14 @@ wl_cfg80211_start_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id, /* * Get current mkeep-alive status. */ - res = wldev_iovar_getbuf(primary_ndev, "mkeep_alive", &mkeep_alive_id, + res = wldev_iovar_getbuf(ndev, "mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), pbuf, KA_TEMP_BUF_SIZE, &cfg->ioctl_buf_sync); if (res < 0) { WL_ERR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); goto exit; } else { /* Check available ID whether it is occupied */ - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; + mkeep_alive_pktp = (wl_mkeep_alive_pkt_v1_t *) pbuf; if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { WL_ERR(("%s: Get mkeep_alive failed, ID %u is in use.\n", __FUNCTION__, mkeep_alive_id)); @@ -22252,7 +26110,7 @@ wl_cfg80211_start_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id, } /* Request the specified ID */ - bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t)); + bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_v1_t)); bzero(pbuf, KA_TEMP_BUF_SIZE); str = "mkeep_alive"; str_len = strlen(str); @@ -22260,9 +26118,9 @@ wl_cfg80211_start_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id, buf_len = str_len + 1; pbuf_len -= buf_len; - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + buf_len); + mkeep_alive_pktp = (wl_mkeep_alive_pkt_v1_t *) (pbuf + buf_len); mkeep_alive_pkt.period_msec = htod32(period_msec); - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION_1); mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); len_bytes = (ETHER_ADDR_LEN*2) + ETHERTYPE_LEN + ip_pkt_len; mkeep_alive_pkt.len_bytes = htod16(len_bytes); @@ -22332,7 +26190,7 @@ wl_cfg80211_start_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id, } buf_len += len_bytes; - res = wldev_ioctl_set(primary_ndev, WLC_SET_VAR, pbuf, buf_len); + res = wldev_ioctl_set(ndev, WLC_SET_VAR, pbuf, buf_len); exit: if (pmac_frame_begin) { MFREE(cfg->osh, pmac_frame_begin, KA_FRAME_SIZE); @@ -22344,16 +26202,15 @@ exit: } int -wl_cfg80211_stop_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id) +wl_cfg80211_stop_mkeep_alive(struct net_device *ndev, struct bcm_cfg80211 *cfg, + uint8 mkeep_alive_id) { char *pbuf = NULL; - wl_mkeep_alive_pkt_t mkeep_alive_pkt; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp = NULL; + wl_mkeep_alive_pkt_v1_t mkeep_alive_pkt; + wl_mkeep_alive_pkt_v1_t *mkeep_alive_pktp = NULL; int res = BCME_ERROR; int i = 0; - struct net_device *primary_ndev = NULL; dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - primary_ndev = bcmcfg_to_prmry_ndev(cfg); /* * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, @@ -22373,14 +26230,15 @@ wl_cfg80211_stop_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id) return res; } - res = wldev_iovar_getbuf(primary_ndev, "mkeep_alive", &mkeep_alive_id, + res = wldev_iovar_getbuf(ndev, "mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), pbuf, KA_TEMP_BUF_SIZE, &cfg->ioctl_buf_sync); if (res < 0) { - WL_ERR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); + WL_ERR(("%s: Get mkeep_alive failed id:%d (error=%d)\n", __FUNCTION__, + mkeep_alive_id, res)); goto exit; } else { /* Check occupied ID */ - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; + mkeep_alive_pktp = (wl_mkeep_alive_pkt_v1_t *) pbuf; WL_DBG(("%s: mkeep_alive\n", __FUNCTION__)); WL_DBG((" Id : %d\n" " Period: %d msec\n" @@ -22399,14 +26257,14 @@ wl_cfg80211_stop_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id) /* Make it stop if available */ if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { WL_INFORM_MEM(("stop mkeep_alive on ID %d\n", mkeep_alive_id)); - bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t)); + bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_v1_t)); mkeep_alive_pkt.period_msec = 0; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION_1); mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; - res = wldev_iovar_setbuf(primary_ndev, "mkeep_alive", + res = wldev_iovar_setbuf(ndev, "mkeep_alive", (char *)&mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN, pbuf, KA_TEMP_BUF_SIZE, &cfg->ioctl_buf_sync); } else { @@ -22487,6 +26345,27 @@ wl_cfg80211_handle_hang_event(struct net_device *ndev, uint16 hang_reason, uint3 return BCME_OK; } +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT +int wl_cfg80211_alert(struct net_device *dev) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + dhd_pub_t *dhd; + + if (!cfg) { + return BCME_ERROR; + } + + RETURN_EIO_IF_NOT_UP(cfg); + + dhd = (dhd_pub_t *)(cfg->pub); + + WL_ERR(("In : error alert eventing, reason=0x%x\n", (uint32)(dhd->alert_reason))); + wl_cfgvendor_send_alert_event(dev, dhd->alert_reason); + + return 0; +} +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ + static void wl_cfg80211_spmk_pmkdb_change_pmk_type(struct bcm_cfg80211 *cfg, pmkid_list_v3_t *pmk_list) { @@ -22549,54 +26428,278 @@ wl_cfg80211_handle_set_ssid_complete(struct bcm_cfg80211 *cfg, wl_assoc_status_t const wl_event_msg_t *event, wl_assoc_state_t assoc_state) { if (as->status != WLC_E_STATUS_SUCCESS) { -#ifdef CUSTOMER_HW6 - /* Some older chips sends SET_SSID with fail status and it - * still proceeds with join. Excempt it for the sake of - * compatibility - */ - return; -#endif /* CUSTOMER_HW6 */ -#ifdef DHD_ENABLE_BIGDATA_LOGGING - wl_get_connect_failed_status(cfg, event); -#endif /* DHD_ENABLE_BIGDATA_LOGGING */ + struct wl_security *sec = wl_read_prof(cfg, as->ndev, WL_PROF_SEC); + if (sec && sec->auth_assoc_res_status) { + WL_INFORM_MEM(("Assoc fail status %d\n", + sec->auth_assoc_res_status)); + } #ifdef SET_SSID_FAIL_CUSTOM_RC - if (as->status == WLC_E_STATUS_TIMEOUT) { + else if (as->status == WLC_E_STATUS_TIMEOUT) { WL_INFORM_MEM(("overriding reason code %d to %d\n", - as->reason, SET_SSID_FAIL_CUSTOM_RC)); + as->reason, SET_SSID_FAIL_CUSTOM_RC)); as->reason = SET_SSID_FAIL_CUSTOM_RC; } #endif /* SET_SSID_FAIL_CUSTOM_RC */ +#ifdef AUTH_ASSOC_STATUS_EXT + else if (sec && as->status == WLC_E_STATUS_NO_NETWORKS) { + WL_INFORM_MEM(("overriding status code %d to %d\n", + sec->auth_assoc_res_status, AUTH_ASSOC_STATUS_NO_NETWORKS)); + sec->auth_assoc_res_status = AUTH_ASSOC_STATUS_NO_NETWORKS; + } +#endif /* AUTH_ASSOC_STATUS_EXT */ +#ifdef WL_CFGVENDOR_CUST_ADVLOG + wl_cfgvendor_custom_advlog_connfail(cfg, event, as); +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ /* Report connect failure */ as->link_action = wl_set_link_action(assoc_state, false); } -#ifdef WL_NAN - else if ((as->status == WLC_E_STATUS_SUCCESS) && - wl_cfgnan_is_enabled(cfg) && - wl_get_drv_status(cfg, CONNECTED, as->ndev)) { - u8 *curbssid = wl_read_prof(cfg, as->ndev, WL_PROF_BSSID); - u8 *conn_req_bssid = - wl_read_prof(cfg, as->ndev, WL_PROF_LATEST_BSSID); - - if (memcmp(curbssid, conn_req_bssid, ETHER_ADDR_LEN) == 0) { - wl_cfgnan_get_stats(cfg); - } - } -#endif /* WL_NAN */ - return; } #ifdef WL_TWT +#define BRCM_TWT_VENDOR_EVENT_BUF_LEN 500 +static int +wl_update_twt_setup_evt_info(struct sk_buff *skb, void *event_data) +{ + s32 err = BCME_OK; + const wl_twt_setup_cplt_t *setup_cplt = (wl_twt_setup_cplt_t *)event_data; + const wl_twt_sdesc_v0_t *sdesc = (const wl_twt_sdesc_v0_t *)&setup_cplt[1]; + + WL_DBG(("TWT_SETUP: status %d, reason %d, configID %d, setup_cmd %d, flow_flags 0x%x," + " flow_id %d, channel %d, negotiation_type %d, wake_time_h %u, wake_time_l %u," + " wake_dur %u, wake_int %u\n", + (int)setup_cplt->status, (int)setup_cplt->reason_code, (int)setup_cplt->configID, + (int)sdesc->setup_cmd, sdesc->flow_flags, (int)sdesc->flow_id, (int)sdesc->channel, + (int)sdesc->negotiation_type, sdesc->wake_time_h, sdesc->wake_time_l, + sdesc->wake_dur, sdesc->wake_int)); + + err = nla_put_u8(skb, WIFI_TWT_ATTR_SUB_EVENT, WIFI_TWT_EVENT_SETUP); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n")); + goto fail; + } + err = nla_put_u8(skb, WIFI_TWT_ATTR_REASON_CODE, setup_cplt->reason_code); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_REASON_CODE failed\n")); + goto fail; + } + err = nla_put_u8(skb, WIFI_TWT_ATTR_STATUS, !!(setup_cplt->status)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_STATUS failed\n")); + goto fail; + } + err = nla_put_u8(skb, WIFI_TWT_ATTR_CONFIG_ID, setup_cplt->configID); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_CONFIG_ID failed\n")); + goto fail; + } + err = nla_put_u8(skb, WIFI_TWT_ATTR_NEGOTIATION_TYPE, sdesc->negotiation_type); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_NEGOTIATION_TYPE failed\n")); + goto fail; + } + err = nla_put_u32(skb, WIFI_TWT_ATTR_WAKETIME_H, sdesc->wake_time_h); + if (unlikely(err)) { + WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKETIME_H failed\n")); + goto fail; + } + err = nla_put_u32(skb, WIFI_TWT_ATTR_WAKETIME_L, sdesc->wake_time_l); + if (unlikely(err)) { + WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKETIME_L failed\n")); + goto fail; + } + err = nla_put_u32(skb, WIFI_TWT_ATTR_WAKE_DURATION, sdesc->wake_dur); + if (unlikely(err)) { + WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKE_DURATION failed\n")); + goto fail; + } + err = nla_put_u32(skb, WIFI_TWT_ATTR_WAKE_INTERVAL, sdesc->wake_int); + if (unlikely(err)) { + WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKE_INTERVAL failed\n")); + goto fail; + } + err = nla_put_u8(skb, WIFI_TWT_ATTR_FLOW_TYPE, + !!(sdesc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_FLOW_TYPE failed\n")); + goto fail; + } + err = nla_put_u8(skb, WIFI_TWT_ATTR_TRIGGER_TYPE, + !!(sdesc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_TRIGGER_TYPE failed\n")); + goto fail; + } + +fail: + return err; +} + +static int +wl_update_twt_teardown_evt_info(struct sk_buff *skb, void *event_data) +{ + s32 err = BCME_OK; + const wl_twt_teardown_cplt_t *td_cplt = (wl_twt_teardown_cplt_t *)event_data; + const wl_twt_teardesc_t *teardesc = (const wl_twt_teardesc_t *)&td_cplt[1]; + + WL_DBG(("TWT_TEARDOWN: status %d, reason %d, configID %d, flow_id %d, negotiation_type %d," + " bid %d, alltwt %d\n", (int)td_cplt->status, (int)td_cplt->reason_code, + (int)td_cplt->configID, (int)teardesc->flow_id, (int)teardesc->negotiation_type, + (int)teardesc->bid, (int)teardesc->alltwt)); + + err = nla_put_u8(skb, WIFI_TWT_ATTR_SUB_EVENT, WIFI_TWT_EVENT_TEARDOWN); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n")); + goto fail; + } + err = nla_put_u8(skb, WIFI_TWT_ATTR_REASON_CODE, td_cplt->reason_code); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_REASON_CODE failed\n")); + goto fail; + } + err = nla_put_u8(skb, WIFI_TWT_ATTR_STATUS, !!(td_cplt->status)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_STATUS failed\n")); + goto fail; + } + err = nla_put_u8(skb, WIFI_TWT_ATTR_CONFIG_ID, td_cplt->configID); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_CONFIG_ID failed\n")); + goto fail; + } + +fail: + return err; +} + +static int +wl_update_twt_info_frm_evt_info(struct sk_buff *skb, void *event_data) +{ + s32 err = BCME_OK; + const wl_twt_info_cplt_t *info_cplt = (wl_twt_info_cplt_t *)event_data; + const wl_twt_infodesc_t *infodesc = (const wl_twt_infodesc_t *)&info_cplt[1]; + + WL_DBG(("TWT_INFOFRM: status %d, reason %d, configID %d, flow_flags 0x%x, flow_id %d," + " next_twt_h %u, next_twt_l %u\n", (int)info_cplt->status, + (int)info_cplt->reason_code, (int)info_cplt->configID, infodesc->flow_flags, + (int)infodesc->flow_id, infodesc->next_twt_h, infodesc->next_twt_l)); + + err = nla_put_u8(skb, WIFI_TWT_ATTR_SUB_EVENT, WIFI_TWT_EVENT_INFO_FRM); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n")); + goto fail; + } + err = nla_put_u8(skb, WIFI_TWT_ATTR_REASON_CODE, info_cplt->reason_code); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_REASON_CODE failed\n")); + goto fail; + } + err = nla_put_u8(skb, WIFI_TWT_ATTR_STATUS, !!(info_cplt->status)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_STATUS failed\n")); + goto fail; + } + err = nla_put_u8(skb, WIFI_TWT_ATTR_CONFIG_ID, info_cplt->configID); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_CONFIG_ID failed\n")); + goto fail; + } + err = nla_put_u32(skb, WIFI_TWT_ATTR_NEXT_TWT_H, infodesc->next_twt_h); + if (unlikely(err)) { + WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_NEXT_TWT_H failed\n")); + goto fail; + } + err = nla_put_u32(skb, WIFI_TWT_ATTR_NEXT_TWT_L, infodesc->next_twt_l); + if (unlikely(err)) { + WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_NEXT_TWT_L failed\n")); + goto fail; + } + +fail: + return err; +} + +static int +wl_update_twt_notify_evt_info(struct sk_buff *skb, void *event_data) +{ + s32 err = BCME_OK; + const wl_twt_notify_t *notif_cplt = (wl_twt_notify_t *)event_data; + + WL_DBG(("TWT_NOTIFY: notification %d\n", (int)notif_cplt->notification)); + + err = nla_put_u8(skb, WIFI_TWT_ATTR_SUB_EVENT, WIFI_TWT_EVENT_NOTIFY); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n")); + goto fail; + } + + err = nla_put_u8(skb, WIFI_TWT_ATTR_NOTIFICATION, notif_cplt->notification); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_NOTIFICATION failed\n")); + goto fail; + } + +fail: + return err; +} + static s32 wl_notify_twt_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) { - uint32 type; - type = ntoh32(e->event_type); - WL_DBG(("TWT event type %d\n", type)); + struct sk_buff *skb = NULL; + gfp_t kflags; + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + int err = BCME_OK; + struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + const wl_twt_event_t *twt_event = (wl_twt_event_t *)data; + + kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), BRCM_TWT_VENDOR_EVENT_BUF_LEN, + BRCM_VENDOR_EVENT_TWT, kflags); + if (!skb) { + WL_ERR(("skb alloc failed")); + err = BCME_NOMEM; + goto fail; + } + + switch (twt_event->event_type) { + case WL_TWT_EVENT_SETUP: + err = wl_update_twt_setup_evt_info(skb, (void*)twt_event->event_info); + break; + case WL_TWT_EVENT_TEARDOWN: + err = wl_update_twt_teardown_evt_info(skb, (void*)twt_event->event_info); + break; + case WL_TWT_EVENT_INFOFRM: + err = wl_update_twt_info_frm_evt_info(skb, (void*)twt_event->event_info); + break; + case WL_TWT_EVENT_NOTIFY: + err = wl_update_twt_notify_evt_info(skb, (void*)twt_event->event_info); + break; + default: + WL_ERR(("Invalid TWT sub event type %d", twt_event->event_type)); + err = BCME_UNSUPPORTED; + break; + } + + if (err) { + goto fail; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + cfg80211_vendor_event(skb, kflags); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ return BCME_OK; + +fail: + /* Free skb for failure cases */ + if (skb) { + kfree_skb(skb); + } + + return err; } #endif /* WL_TWT */ @@ -22680,6 +26783,78 @@ wl_cfg80211_debug_data_dump(struct net_device *dev, u8 *buf, u32 buf_len) return len; } +void +wl_cfg80211_wdev_lock(struct wireless_dev *wdev) +{ + mutex_lock(&wdev->mtx); + __acquire(wdev->mtx); +} + +void +wl_cfg80211_wdev_unlock(struct wireless_dev *wdev) +{ + __release(wdev->mtx); + mutex_unlock(&wdev->mtx); +} + +#ifdef AUTH_ASSOC_STATUS_EXT +s32 +wl_get_auth_assoc_status_ext(struct bcm_cfg80211 *cfg, struct net_device *ndev, + const wl_event_msg_t *e) +{ + u32 event = ntoh32(e->event_type); + s32 status = ntoh32(e->status); + struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); + u32 reason = 0; + + if (!sec) { + WL_ERR(("sec is NULL\n")); + return 0; + } + switch (event) { + case WLC_E_AUTH: + if (ntoh32(e->auth_type) == DOT11_SAE) { + /* SAE Authentication */ + if (status == WLC_E_STATUS_NO_ACK) { + reason = AUTH_ASSOC_STATUS_SAE_AUTH_NOACK; + } else if (status == WLC_E_STATUS_TIMEOUT) { + reason = AUTH_ASSOC_STATUS_SAE_AUTH_NORESP; + } else { + reason = AUTH_ASSOC_STATUS_SAE_AUTH_FAIL; + } + } else { + /* Open Authentication */ + if (status == WLC_E_STATUS_NO_ACK) { + reason = AUTH_ASSOC_STATUS_OPEN_AUTH_NOACK; + } else if (status == WLC_E_STATUS_TIMEOUT) { + reason = AUTH_ASSOC_STATUS_OPEN_AUTH_NORESP; + } else { + reason = AUTH_ASSOC_STATUS_OPEN_AUTH_FAIL; + } + } + break; + case WLC_E_ASSOC: + if (status == WLC_E_STATUS_NO_ACK) { + reason = AUTH_ASSOC_STATUS_ASSOC_NOACK; + } else if (status == WLC_E_STATUS_TIMEOUT) { + reason = AUTH_ASSOC_STATUS_ASSOC_NORESP; + } else { + reason = AUTH_ASSOC_STATUS_ASSOC_FAIL; + } + break; + default: + break; + } + + if (reason) { + WL_DBG(("event %d status %d reason %d\n", + event, status, reason)); + sec->auth_assoc_res_status = reason; + } + return 0; +} +#endif /* AUTH_ASSOC_STATUS_EXT */ + #ifdef WL_CLIENT_SAE static bool wl_is_pmkid_available(struct net_device *dev, const u8 *bssid) @@ -22699,6 +26874,43 @@ wl_is_pmkid_available(struct net_device *dev, const u8 *bssid) return FALSE; } +static void +wl_inform_sae_target_bss(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) +{ + u8 bsscfgidx = e->bsscfgidx; + struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + wl_ext_auth_evt_t *evt_data = (wl_ext_auth_evt_t *)data; + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + struct cfg80211_bss *bss; + wl_bss_info_v109_t *bi = NULL; + char *buf; + int err; + buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN); + if (buf == NULL) { + WL_ERR(("failed to allocate memory\n")); + goto out; + } + err = wldev_iovar_getbuf_bsscfg(ndev, "target_bss_info", + NULL, 0, buf, WLC_IOCTL_MAXLEN, bsscfgidx, &cfg->ioctl_buf_sync); + if (err != BCME_OK) { + WL_ERR(("Could not get target_bss_info %d\n", err)); + goto out; + } + bi = (wl_bss_info_v109_t *)(buf); + bss = CFG80211_GET_BSS(wiphy, NULL, (u8 *)evt_data->bssid.octet, + evt_data->ssid.SSID, MIN(evt_data->ssid.SSID_len, DOT11_MAX_SSID_LEN)); + if (!bss) { + err = wl_inform_single_bss(cfg, bi, false); + if (unlikely(err)) { + WL_ERR(("Could not add the AP info into cache\n")); + goto out; + } + } +out: + MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN); +} + #define WL_AUTH_START_EVT_V0 0 static s32 wl_notify_start_auth(struct bcm_cfg80211 *cfg, @@ -22744,6 +26956,7 @@ wl_notify_start_auth(struct bcm_cfg80211 *cfg, MAC2STRDBG(&evt_v1_data->bssid), evt_v1_data->version); #endif + wl_inform_sae_target_bss(cfg, cfgdev, e, data); /* Wait for conn_owner_nlportid been assigned in nl80211_connect */ for (retry = 3; retry > 0; retry--) { if (wdev->conn_owner_nlportid) { @@ -22889,6 +27102,15 @@ wl_cfg80211_external_auth(struct wiphy *wiphy, return -EINVAL; } + WL_INFORM_MEM(("wl_cfg80211_external_auth: BSSID:"MACDBG", status:%d\n", + MAC2STRDBG(&ext_auth_param->bssid), ext_auth_param->status)); + + /* Issue disassoc on Auth failure */ + if (unlikely(ext_auth_param->status)) { + wl_cfg80211_disassoc(ndev, WLAN_REASON_UNSPECIFIED); + goto done; + } + cmd.version = WL_ASSOC_MGR_CURRENT_VERSION; cmd.length = sizeof(cmd); cmd.cmd = WL_ASSOC_MGR_CMD_PAUSE_ON_EVT; @@ -22899,6 +27121,7 @@ wl_cfg80211_external_auth(struct wiphy *wiphy, WL_ERR(("Failed to pause assoc(%d)\n", err)); } +done: return err; } @@ -22921,7 +27144,7 @@ wl_cfg80211_mgmt_auth_tx(struct net_device *dev, bcm_struct_cfgdev *cfgdev, cmd = (wl_assoc_mgr_cmd_t*)ambuf; cmd->version = WL_ASSOC_MGR_CURRENT_VERSION; - cmd->length = len; + cmd->length = htod16((uint16)len); cmd->cmd = WL_ASSOC_MGR_CMD_SEND_AUTH; err = memcpy_s(&cmd->params, len, buf, len); if (err) { @@ -22949,6 +27172,1232 @@ wl_cfg80211_mgmt_auth_tx(struct net_device *dev, bcm_struct_cfgdev *cfgdev, } #endif /* WL_CLIENT_SAE */ +#if defined(WL_SAR_TX_POWER) && defined(WL_SAR_TX_POWER_CONFIG) +#ifdef DHD_LINUX_STD_FW_API +#define CONFIG_SAR_CONFIG_INFO_PATH "sarconfig.info" +#else +#define CONFIG_SAR_CONFIG_INFO_PATH PLATFORM_PATH"sarconfig.info" +#endif /* DHD_LINUX_STD_FW_API */ +static void wl_get_sar_config_info(struct bcm_cfg80211 *cfg) +{ +#ifdef DHD_LINUX_STD_FW_API + const struct firmware *fw = NULL; +#else + struct file *fp = NULL; +#endif /* DHD_LINUX_STD_FW_API */ + char *filepath = CONFIG_SAR_CONFIG_INFO_PATH; + int ret = BCME_OK; + char *buf = NULL, *ptr = NULL, *cptr = NULL; + int filelen = 0, buflen = 0, offset = 0, num, len, i; + int8 scenario, airplanemode; + uint8 sarmode; + + if (cfg == NULL) { + WL_ERR(("cfg is null\n")); + return; + } + + if (cfg->sar_config_info) { + MFREE(cfg->osh, cfg->sar_config_info, + sizeof(wl_sar_config_info_t) * cfg->sar_config_info_cnt); + cfg->sar_config_info_cnt = 0; + } + +#ifdef DHD_LINUX_STD_FW_API + ret = dhd_os_get_img_fwreq(&fw, filepath); + if (ret < 0 || fw == NULL) { + WL_DBG(("file [%s] doesn't exist\n", filepath)); + return; + } else { + filelen = fw->size; + buflen = filelen + 1; + if ((buf = (char *)MALLOCZ(cfg->osh, buflen)) == NULL) { + WL_ERR(("fail to malloc buffer\n")); + goto exit; + } + } + + if ((ret = memcpy_s(buf, buflen, fw->data, fw->size)) < 0) { + WL_ERR((" memcpy error, err %d\n", ret)); + goto exit; + } +#else + fp = dhd_filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { + WL_DBG(("file [%s] doesn't exist\n", filepath)); + return; + } + + if ((filelen = dhd_i_size_read(file_inode(fp))) <= 0) { + WL_ERR(("abnormal file size\n")); + goto exit; + } else { + buflen = filelen + 1; + if ((buf = (char *)MALLOCZ(cfg->osh, buflen)) == NULL) { + WL_ERR(("fail to malloc buffer\n")); + goto exit; + } + } + + /* read file to check line count */ + if ((ret = dhd_kernel_read_compat(fp, 0, (char *)buf, filelen)) < 0) { + WL_ERR((" file read error, err %d\n", ret)); + goto exit; + } +#endif /* DHD_LINUX_STD_FW_API */ + + /* get the line count */ + for (cfg->sar_config_info_cnt = 0, ptr = buf; offset < filelen; offset += (len + 1)) { + if ((cptr = bcmstrtok(&ptr, "\n", NULL)) == NULL) { + break; + } + len = strlen(cptr); + cfg->sar_config_info_cnt++; + } + if (cfg->sar_config_info_cnt <= 0) { + WL_ERR(("no data in the config file\n")); + goto exit; + } + + /* make buffer again becuase bcmstrtok removes the delimiter in it */ +#ifdef DHD_LINUX_STD_FW_API + if ((ret = memcpy_s(buf, buflen, fw->data, fw->size)) < 0) { + WL_ERR((" memcpy error, err %d\n", ret)); + goto exit; + } +#else + if ((ret = dhd_kernel_read_compat(fp, 0, (char *)buf, filelen)) < 0) { + WL_ERR((" file read error, err %d\n", ret)); + goto exit; + } +#endif /* DHD_LINUX_STD_FW_API */ + + /* allocate the buffer */ + if ((cfg->sar_config_info = (wl_sar_config_info_t *)MALLOCZ(cfg->osh, + sizeof(wl_sar_config_info_t) * cfg->sar_config_info_cnt)) == NULL) { + WL_ERR(("malloc failure\n")); + goto exit; + } + + for (i = 0, ptr = buf; i < cfg->sar_config_info_cnt; i++) { + cptr = bcmstrtok(&ptr, "\n", NULL); + if (cptr) { + num = sscanf(cptr, "%hhd,%hhd,%hhd", + &scenario, &sarmode, &airplanemode); + if ((num != 3) || (scenario < WIFI_POWER_SCENARIO_DEFAULT) || + (scenario >= SAR_CONFIG_SCENARIO_COUNT)) { + cfg->sar_config_info[i].scenario = WIFI_POWER_SCENARIO_INVALID; + WL_ERR(("format should be [scenario (-1 to %d)]," + " [sar], [airplane]\n", + (SAR_CONFIG_SCENARIO_COUNT-1))); + } else { + WL_DBG(("scenario=%d, sar=%d, airplane=%d\n", + scenario, sarmode, airplanemode)); + cfg->sar_config_info[i].scenario = scenario; + cfg->sar_config_info[i].sar_tx_power_val = sarmode; + cfg->sar_config_info[i].airplane_mode = airplanemode; + } + } else { + cfg->sar_config_info[i].scenario = WIFI_POWER_SCENARIO_INVALID; + } + } + +exit: +#ifdef DHD_LINUX_STD_FW_API + if (fw) { + dhd_os_close_img_fwreq(fw); + } +#else + if (fp) { + dhd_filp_close(fp, NULL); + } +#endif /* DHD_LINUX_STD_FW_API */ + if (buf) { + MFREE(cfg->osh, buf, buflen); + } + return; +} +#endif /* WL_SAR_TX_POWER && WL_SAR_TX_POWER_CONFIG */ + +s32 +wl_cfg80211_set_netinfo_passphrase(struct bcm_cfg80211 *cfg, + struct net_device *ndev, const u8* passphrase, u8 len) +{ + struct net_info * _net_info = NULL; + int err = BCME_OK; + + _net_info = wl_get_netinfo_by_netdev(cfg, ndev); + if (_net_info == NULL) { + WL_ERR(("net_info not found for iface %s", ndev->name)); + err = BCME_ERROR; + goto done; + } + + _net_info->passphrase_len = len; + err = memcpy_s(_net_info->passphrase, sizeof(_net_info->passphrase), + passphrase, len); + if (err != BCME_OK) { + WL_ERR(("Failed to copy passphrase err %d\n", err)); + goto done; + } + +done: + return err; +} + +/* Configure "wsec_info 0x108" IOVAR */ +s32 +wl_cfg80211_wsec_info_pmk(struct bcm_cfg80211 *cfg, struct net_device *ndev, + wl_wsec_info_pmk_info_t *pmk_info, uint16 pmk_info_len, uint8 action) +{ + int err = BCME_OK; + + pmk_info->action = action; + err = wl_cfg80211_set_wsec_info(ndev, (uint32 *)pmk_info, + pmk_info_len, WL_WSEC_INFO_BSS_PMK_PASSPHRASE); + + if (unlikely(err)) { + WL_ERR(("couldn't set[%d] passphrase (wsec_info %d)\n", action, err)); + } + + return err; +} + +s32 +wl_cfg80211_config_passphrase(struct bcm_cfg80211 *cfg, + struct net_device *ndev, wl_config_passphrase_t *pp_config) +{ + wl_wsec_info_pmk_info_t *pmk_info = NULL; + uint16 buf_size = 0; + uint8 *data = NULL; + int err = BCME_OK; + uint16 avail_size = 0; + struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, ndev); + + buf_size = sizeof(wl_wsec_info_pmk_info_t) + + pp_config->passphrase_len + pp_config->ssid_len; + buf_size = ALIGN_SIZE(buf_size, 4); + + pmk_info = (wl_wsec_info_pmk_info_t *)MALLOCZ(cfg->osh, buf_size); + if (pmk_info == NULL) { + WL_ERR(("Failed to alloc memory for pmk_info\n")); + err = BCME_NOMEM; + goto done; + } + + avail_size = buf_size - sizeof(wl_wsec_info_pmk_info_t); + bzero(pmk_info, buf_size); + pmk_info->version = WL_WSEC_PMK_INFO_VERSION; + + /* Set data start ..after pmk_info struct */ + data = (uint8*)(pmk_info + 1); + + /* Copy SSID */ + pmk_info->ssid.len = pp_config->ssid_len; + pmk_info->ssid.off = sizeof(wl_wsec_info_pmk_info_t); + err = memcpy_s(data, avail_size, pp_config->ssid, + pp_config->ssid_len); + if (err != BCME_OK) { + WL_ERR(("Failed to copy ssid err %d\n", err)); + goto done; + } + data = data + pp_config->ssid_len; + avail_size -= pp_config->ssid_len; + + /* Copy passphrase */ + pmk_info->passphrase.len = pp_config->passphrase_len; + pmk_info->passphrase.off = sizeof(wl_wsec_info_pmk_info_t) + pp_config->ssid_len; + err = memcpy_s(data, avail_size, + pp_config->passphrase, pp_config->passphrase_len); + if (err != BCME_OK) { + WL_ERR(("Failed to copy passphrase err %d\n", err)); + goto done; + } + data = data + pp_config->passphrase_len; + avail_size -= pp_config->passphrase_len; + + /* Compare with earlier config and delete passphrase entry from firmware + * if not matching and then add the new entry + */ + if (_net_info->passphrase_cfg_len && _net_info->passphrase_cfg && + (buf_size != _net_info->passphrase_cfg_len || + memcmp((uint8*)pmk_info, _net_info->passphrase_cfg, buf_size))) { + wl_wsec_info_pmk_info_t *pmk_del_info = + (wl_wsec_info_pmk_info_t *)_net_info->passphrase_cfg; + WL_INFORM_MEM(("New passphrase config received for iface %s." + "Delete earlier config before adding new one\n", ndev->name)); + err = wl_cfg80211_wsec_info_pmk(cfg, ndev, pmk_del_info, + _net_info->passphrase_cfg_len, WL_WSEC_PMK_INFO_DEL); + if (unlikely(err)) { + WL_ERR(("couldn't delete passphrase err %d..continue and try to add new\n", + err)); + } + } + + err = wl_cfg80211_wsec_info_pmk(cfg, ndev, pmk_info, buf_size, WL_WSEC_PMK_INFO_ADD); + + if (unlikely(err)) { + WL_ERR(("couldn't set passphrase (wsec_info %d)\n", err)); + if (err == BCME_UNSUPPORTED) { + /* try legacy iovar */ + wsec_pmk_t pmk; + (void)memset_s(&pmk, sizeof(wsec_pmk_t), 0x0, + sizeof(wsec_pmk_t)); + pmk.key_len = htod16(pp_config->passphrase_len); + bcopy((const u8*)pp_config->passphrase, pmk.key, + pp_config->passphrase_len); + pmk.flags = htod16(WSEC_PASSPHRASE); + + err = wldev_ioctl_set(ndev, WLC_SET_WSEC_PMK, &pmk, + sizeof(pmk)); + if (unlikely(err)) { + WL_ERR(("couldn't set passphrase (wsec_pmk %d)\n", err)); + } else { + WL_INFORM_MEM(("Passphrase set(wsec_pmk) for iface %s\n", + ndev->name)); + } + } + } else { + WL_INFORM_MEM(("Passphrase set(wsec_info) for iface %s\n", ndev->name)); + /* update the config */ + if (_net_info->passphrase_cfg) { + MFREE(cfg->osh, _net_info->passphrase_cfg, + _net_info->passphrase_cfg_len); + _net_info->passphrase_cfg = NULL; + } + _net_info->passphrase_cfg = (uint8*)pmk_info; + _net_info->passphrase_cfg_len = buf_size; + _net_info->passphrase_len = 0; + return err; + } + +done: + if (pmk_info) { + MFREE(cfg->osh, pmk_info, buf_size); + } + return err; +} + +#ifdef DEBUG_SETROAMMODE +void +wl_android_roamoff_dbg_clr(struct bcm_cfg80211 *cfg) +{ + bzero(cfg->roamoff_info, sizeof(wl_roamoff_info_t)); +} + +void +wl_android_roamoff_dbg_save(struct net_device *dev, uint rsn, uint roamvar) +{ + struct bcm_cfg80211 *cfg; + struct wl_roamoff_info *roamoff_info; + + if (!dev) { + WL_ERR(("net_device is NULL\n")); + return; + } + cfg = wl_get_cfg(dev); + if (!cfg) { + WL_ERR(("bcm_cfg80211 is NULL\n")); + return; + } + roamoff_info = cfg->roamoff_info; + if (!roamoff_info) { + WL_ERR(("roamoff_info is NULL\n")); + return; + } + + WL_INFORM_MEM(("Set roam_off %d, reason %d\n", roamvar, rsn)); + if (roamvar) { + /* ROAM Disable (roam_off 1) */ + roamoff_info->roam_disable_time = OSL_LOCALTIME_NS(); + roamoff_info->roam_disable_rsn = rsn; + } else { + /* ROAM Enable (roam_off 0) */ + roamoff_info->roam_enable_time = OSL_LOCALTIME_NS(); + roamoff_info->roam_enable_rsn = rsn; + } + + return; +} + +void +wl_android_roamoff_dbg_dump(struct bcm_cfg80211 *cfg) +{ + s32 err = BCME_OK; + uint roamoff = DISABLE; + struct net_device *ndev; + struct wl_roamoff_info *roamoff_info = cfg->roamoff_info; + + if (!roamoff_info) { + WL_ERR(("roamoff_info is NULL\n")); + return; + } + +#ifdef DHD_PM_CONTROL_FROM_FILE + { + extern bool g_pm_control; + if (g_pm_control == TRUE) { + WL_ERR(("Enabled RF test mode\n")); + return; + } + } +#endif /* DHD_PM_CONTROL_FROM_FILE */ + + /* Dump roaminfo */ + WL_INFORM_MEM(("Last ROAM Disable(%02d) "SEC_USEC_FMT"\n", + roamoff_info->roam_disable_rsn, + GET_SEC_USEC(roamoff_info->roam_disable_time))); + WL_INFORM_MEM(("Last ROAM Enable(%02d) "SEC_USEC_FMT"\n", + roamoff_info->roam_enable_rsn, + GET_SEC_USEC(roamoff_info->roam_enable_time))); + + ROAMOFF_DBG_CLR(cfg); + ndev = bcmcfg_to_prmry_ndev(cfg); + if (!ndev) { + WL_ERR(("net_device is NULL\n")); + return; + } + /* Get Current roam_off value */ + err = wldev_iovar_getint(ndev, "roam_off", &roamoff); + if (err) { + WL_ERR(("Failed Get roam_off, err = %d\n", err)); + } + /* Reset roamoff */ + if (roamoff == ENABLE) { + err = wldev_iovar_setint(ndev, "roam_off", DISABLE); + if (err) { + WL_ERR(("Failed Get roam_off, err = %d\n", err)); + } + } + + return; +} +#endif /* DEBUG_SETROAMMODE */ + +#if defined(KEEP_ALIVE) && defined(DHD_CLEANUP_KEEP_ALIVE) +void +wl_cleanup_keep_alive(struct net_device *ndev, struct bcm_cfg80211 *cfg) +{ + int mkeep_alive_id; + + WL_MEM(("mkeep_alive_avail:%x\n", cfg->mkeep_alive_avail)); + for (mkeep_alive_id = 1; mkeep_alive_id < KEEP_ALIVE_ID_MAX; mkeep_alive_id++) { + if (isset(&cfg->mkeep_alive_avail, mkeep_alive_id)) { + if (wl_cfg80211_stop_mkeep_alive(ndev, cfg, mkeep_alive_id) == BCME_OK) { + clrbit(&cfg->mkeep_alive_avail, mkeep_alive_id); + } + } + if (!cfg->mkeep_alive_avail) { + WL_INFORM(("Stopped for all keep alive id.\n")); + break; + } + } + + return; +} +#endif /* defined(KEEP_ALIVE) && defined(DHD_CLEANUP_KEEP_ALIVE) */ + +chanspec_t +wl_cfg80211_get_sta_chanspec(struct bcm_cfg80211 *cfg) +{ + chanspec_t *sta_chanspec = NULL; + +#ifdef WL_DUAL_APSTA + if (wl_cfgvif_get_iftype_count(cfg, WL_IF_TYPE_STA) >= 2) { + /* If both STA interfaces are connected return failure */ + return 0; + } else { + struct net_info *iter, *next; + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + for_each_ndev(cfg, iter, next) { + GCC_DIAGNOSTIC_POP(); + if ((iter->ndev) && (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) && + (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION)) { + if ((sta_chanspec = (chanspec_t *)wl_read_prof(cfg, + iter->ndev, WL_PROF_CHAN))) { + return *sta_chanspec; + } + } + } + } +#else + if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) { + if ((sta_chanspec = (chanspec_t *)wl_read_prof(cfg, + bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN))) { + return *sta_chanspec; + } + } +#endif /* WL_DUAL_APSTA */ + + return 0; +} + +int +wl_cfg80211_reassoc(struct net_device *dev, struct ether_addr *bssid, chanspec_t chanspec) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + int error = BCME_OK; + u32 params_size; + + void *iovar_params; + wl_reassoc_params_t *reassoc_params_info; + wl_reassoc_params_t reassoc_params_v0; + wl_reassoc_params_cvt_v1_t reassoc_params_v1; + wl_ext_reassoc_params_cvt_v1_t reassoc_params_v2; + + switch (cfg->join_iovar_ver) { + case WL_REASSOC_VERSION_V0 : + /* wl_reassoc_params */ + params_size = WL_REASSOC_PARAMS_FIXED_SIZE + sizeof(chanspec_t); + iovar_params = &reassoc_params_v0; + reassoc_params_info = &reassoc_params_v0; + break; + case WL_REASSOC_VERSION_V1 : + /* wl_reassoc_params_v1 */ + params_size = WL_REASSOC_PARAMS_FIXED_SIZE_V1 + sizeof(chanspec_t); + iovar_params = &reassoc_params_v1; + reassoc_params_v1.version = WL_REASSOC_VERSION_V1; + reassoc_params_v1.flags = WL_SCAN_MODE_HIGH_ACC; + reassoc_params_info = &reassoc_params_v1.params; + break; + case WL_REASSOC_VERSION_V2 : + /* wl_ext_reassoc_params */ + params_size = WL_EXTREASSOC_PARAMS_FIXED_SIZE_V1 + sizeof(chanspec_t); + iovar_params = &reassoc_params_v2; + reassoc_params_v2.version = WL_REASSOC_VERSION_V2; + reassoc_params_v2.length = params_size; + reassoc_params_v2.flags = WL_SCAN_MODE_HIGH_ACC; + reassoc_params_v2.params.version = WL_REASSOC_VERSION_V2; + reassoc_params_v2.params.flags = WL_SCAN_MODE_HIGH_ACC; + reassoc_params_info = &reassoc_params_v2.params.params; + break; + default : + error = BCME_VERSION; + goto exit; + } + + bzero(reassoc_params_info, WL_REASSOC_PARAMS_FIXED_SIZE); + bcopy(bssid, (void *)&reassoc_params_info->bssid, ETHER_ADDR_LEN); + + reassoc_params_info->chanspec_num = 1; + reassoc_params_info->chanspec_list[0] = chanspec; + + error = wldev_ioctl_set(dev, WLC_REASSOC, iovar_params, params_size); + if (error) { + WL_ERR(("failed to reassoc, error=%d\n", error)); + } + +exit: + return error; +} + +#ifdef WL_USABLE_CHAN +int wl_check_exist_freq_in_list(usable_channel_t *channels, int cur_idx, u32 freq) +{ + int i; + for (i = 0; i < cur_idx; i++) { + if (channels[i].freq == freq) { + return i; + } + } + return BCME_NOTFOUND; +} + +void wl_usable_channels_filter(struct bcm_cfg80211 *cfg, uint32 cur_chspec, uint32 *mask, + usable_channel_info_t *u_info, uint32 *conn, + chanspec_t sta_chspec, uint32 sta_chaninfo) +{ +#ifdef WL_CELLULAR_CHAN_AVOID + wifi_interface_mode mode; +#endif /* WL_CELLULAR_CHAN_AVOID */ + drv_acs_params_t param = { 0 }; + int ret; + uint32 cur_band, sta_band; + uint32 filter = 0; + bool restrict_chan = false; + + /* If there is STA connection on 5GHz DFS channel, + * none of the 5GHz channels are usable for SoftAP + */ + if (u_info->filter_mask & WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY) { + sta_band = CHSPEC_TO_WLC_BAND(CHSPEC_BAND(sta_chspec)); + cur_band = CHSPEC_TO_WLC_BAND(CHSPEC_BAND(cur_chspec)); + restrict_chan = ((sta_chaninfo & WL_CHAN_RADAR) || + (sta_chaninfo & WL_CHAN_PASSIVE)|| + (sta_chaninfo & WL_CHAN_CLM_RESTRICTED)); + + /* Filter out SOFTAP when STA connected DFS channel */ + if (sta_band == WLC_BAND_5G && restrict_chan) { + if (cur_band == WLC_BAND_5G) { + filter |= (1U << WIFI_INTERFACE_SOFTAP); + } + } + + /* Filter out P2P_GO, P2P_CLIENT and NAN under condition */ + if (conn[WL_IF_TYPE_STA] && conn[WL_IF_TYPE_AP]) { + /* STA + SOFTAP */ + filter |= ((1U << WIFI_INTERFACE_P2P_GO) | + (1U << WIFI_INTERFACE_P2P_CLIENT) | + (1U << WIFI_INTERFACE_NAN)); + } else if (conn[WL_IF_TYPE_STA] && conn[WL_IF_TYPE_P2P_GO]) { + /* STA + GO */ + filter |= ((1U << WIFI_INTERFACE_P2P_CLIENT) | + (1U << WIFI_INTERFACE_NAN) | + (1U << WIFI_INTERFACE_P2P_GO) | + (1U << WIFI_INTERFACE_SOFTAP)); + } else if (conn[WL_IF_TYPE_STA] && conn[WL_IF_TYPE_P2P_GC]) { + /* STA + GC */ + filter |= ((1U << WIFI_INTERFACE_P2P_GO) | + (1U << WIFI_INTERFACE_NAN) | + (1U << WIFI_INTERFACE_P2P_CLIENT) | + (1U << WIFI_INTERFACE_SOFTAP)); + } else if (conn[WL_IF_TYPE_STA] && conn[WL_IF_TYPE_NAN]) { + /* STA + NAN */ + filter |= ((1U << WIFI_INTERFACE_P2P_GO) | + (1U << WIFI_INTERFACE_P2P_CLIENT) | + (1U << WIFI_INTERFACE_NAN) | + (1U << WIFI_INTERFACE_SOFTAP)); + } + + /* Filter out SOFTAP under condition */ + /* Check whether the cur_chspec is available for SOFTAP (include scc case) */ + if (!(filter & (1U << WIFI_INTERFACE_SOFTAP))) { + param.freq_bands |= cur_band; + + ret = wl_handle_acs_concurrency_cases(cfg, ¶m, 1, &cur_chspec); + if (ret != BCME_OK) { + WL_DBG(("Clear SOFAP bit chspec:%x ret:%d freq_bands(%d)\n", + cur_chspec, ret, param.freq_bands)); + filter |= (1U << WIFI_INTERFACE_SOFTAP); + } else { + /* the function could returns TRUE even if the requested chspec + * is not unavailable due to DHD_ACS_CHECK_SCC_2G_ACTIVE_CH + * feature. scc_chspec can be zero when STA doesn't exist or + * band is not matched. + * here, we just interested in requested chspec. + * so, should check the requested chspec and selected chspec + * are the same + */ + if (param.scc_chspec != 0 && + (wf_chspec_primary20_chan(cur_chspec) != + wf_chspec_primary20_chan(param.scc_chspec))) { + WL_DBG(("Clear SOFTAP bit chspec:%x " + "p_chspec:%x p_band:%x\n", + cur_chspec, param.scc_chspec, param.freq_bands)); + filter |= (1U << WIFI_INTERFACE_SOFTAP); + } + } + } + + /* Filter out STA under condition */ + /* If Dual STA is enabled cannot add another STA iface on any channel + * and TDLS are not supported. + */ + if (conn[WL_IF_TYPE_STA] == 2U) { + filter |= ((1U << WIFI_INTERFACE_TDLS) | + (1U << WIFI_INTERFACE_STA)); + WL_DBG(("DualSTA filter:%u chspec:%x cur_band:%d\n", + filter, cur_chspec, cur_band)); + } else if (conn[WL_IF_TYPE_STA] == 1U && sta_chspec) { + if (CHSPEC_CHANNEL(cur_chspec) != CHSPEC_CHANNEL(sta_chspec)) { + filter |= (1U << WIFI_INTERFACE_TDLS); + } + } + + /* Only interfaces queried from upper layer are left. */ + *mask &= ~(filter); + } + +#ifdef WL_CELLULAR_CHAN_AVOID + if (u_info->filter_mask & WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE) { + /* Filter chanspecs that must be avoided (hard unsafe) due to cell coex */ + mode = wl_cellavoid_mandatory_to_usable_channel_filter(cfg->cellavoid_info); + WL_DBG(("Filter coexistence chspec:%x mode:%d\n", cur_chspec, mode)); + *mask &= (~mode); + } +#endif /* WL_CELLULAR_CHAN_AVOID */ + +} + +#ifdef WL_NAN_INSTANT_MODE +static int wl_cfg80211_get_nan_instant_chan(struct bcm_cfg80211 *cfg, + wl_chanspec_list_v1_t *chan_list, uint32 band_mask, + chanspec_t *nan_inst_mode_chspec) +{ + int err = BCME_OK; + int band = 0; + uint32 channel; + uint8 nan_2g = 0, nan_pri_5g = 0, nan_sec_5g = 0; + + wl_cfgnan_inst_chan_support(cfg, chan_list, + band_mask, &nan_2g, &nan_pri_5g, &nan_sec_5g); + if (!nan_2g && !nan_pri_5g && !nan_sec_5g) { + WL_ERR(("Failed to retrieve the soc channels for nan:" + "nan_2g: %d, nan_pri_5g: %d, nan_sec_5g: %d\n", + nan_2g, nan_pri_5g, nan_sec_5g)); + err = BCME_NOTFOUND; + goto exit; + } + /* Skip if chanspec does not match the interested band_mask */ + if (!((band_mask & WLAN_MAC_2_4_BAND) || + (band_mask & WLAN_MAC_5_0_BAND))) { + WL_ERR(("Unsupported band mask in unsupported for nan\n")); + err = BCME_UNSUPPORTED; + goto exit; + } + + if ((band_mask & WLAN_MAC_5_0_BAND) && (nan_pri_5g)) { + channel = nan_pri_5g; + band = WL_CHANSPEC_BAND_5G; + } else if ((band_mask & WLAN_MAC_5_0_BAND) && (nan_sec_5g)) { + channel = nan_sec_5g; + band = WL_CHANSPEC_BAND_5G; + } else if ((band_mask & WLAN_MAC_2_4_BAND) && (nan_2g)) { + channel = nan_2g; + band = WL_CHANSPEC_BAND_2G; + } else { + WL_ERR(("No usable channels for nan\n")); + err = BCME_NOTFOUND; + goto exit; + } + if ((*nan_inst_mode_chspec = + wl_freq_to_chanspec(wl_channel_to_frequency(channel, band))) == INVCHANSPEC) { + WL_ERR(("Invalid instant mode usable channel: %d, band: %d\n", channel, band)); + err = BCME_ERROR; + goto exit; + } + WL_INFORM_MEM(("Instant mode usable channel for nan: %d\n", channel)); +exit: + return err; +} +#endif /* WL_NAN_INSTANT_MODE */ + +int wl_get_usable_channels(struct bcm_cfg80211 *cfg, usable_channel_info_t *u_info) +{ + usable_channel_t *cur_ch = NULL; + void *chan_list = NULL; + int i, err, idx = 0, band = 0; + u32 mask = 0; + uint32 channel; + uint32 freq, width; + uint32 chspec, chaninfo, sta_chaninfo = 0; + u16 list_count; + int found_idx = BCME_NOTFOUND; + bool ch_160mhz_5g; + u32 restrict_chan; +#ifdef WL_SOFTAP_6G + u32 vlp_psc_include; +#endif /* WL_SOFTAP_6G */ + uint32 conn[WL_IF_TYPE_MAX] = {0}; + struct net_device *p2p_ndev = NULL; + chanspec_t sta_chanspec = 0; + uint32 sta_assoc_freq = 0; + bool is_unii4 = false; +#ifdef WL_NAN_INSTANT_MODE + chanspec_t nan_inst_mode_chspec = INVCHANSPEC; +#endif /* WL_NAN_INSTANT_MODE */ + + bzero(u_info->channels, sizeof(*u_info->channels) * u_info->max_size); + /* Get chan_info_list or chanspec from FW */ + + chan_list = MALLOCZ(cfg->osh, CHANINFO_LIST_BUF_SIZE); + if (chan_list == NULL) { + WL_ERR(("failed to allocate local buf\n")); + err = -ENOMEM; + goto exit; + } + + err = wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "chan_info_list", NULL, + 0, chan_list, CHANINFO_LIST_BUF_SIZE, 0, NULL); + if (err == BCME_UNSUPPORTED) { + WL_INFORM(("get chan_info_list, UNSUPPORTED\n")); + goto exit; + } else if (err != BCME_OK) { + WL_ERR(("get chan_info_list err(%d)\n", err)); + goto exit; + } + +#ifdef WL_NAN_INSTANT_MODE + if ((u_info->iface_mode_mask & (1 << WIFI_INTERFACE_NAN)) && + (u_info->filter_mask & WIFI_USABLE_CHANNEL_FILTER_NAN_INSTANT_MODE)) { + if (wl_cfg80211_get_nan_instant_chan(cfg, (wl_chanspec_list_v1_t *)chan_list, + u_info->band_mask, &nan_inst_mode_chspec) != BCME_OK) { + WL_ERR(("Failed to get the instant nan mode chanspec!!\n")); + } + } +#endif /* WL_NAN_INSTANT_MODE */ + + /* TDLS is supported only for single STA associated case */ + if (cfg->stas_associated == 1) { + sta_chanspec = wl_cfg80211_get_sta_chanspec(cfg); + band = CHSPEC_TO_WLC_BAND(CHSPEC_BAND(sta_chanspec)); + channel = CHSPEC_CHANNEL(sta_chanspec); + sta_assoc_freq = wl_channel_to_frequency(channel, band); + } + + list_count = ((wl_chanspec_list_v1_t *)chan_list)->count; + for (i = 0; i < list_count; i++) { + if (u_info->max_size <= idx) { + WL_ERR(("No more space to add usable channel info idx:%d max_size:%u\n", + idx, u_info->max_size)); + break; + } + chspec = dtoh32(((wl_chanspec_list_v1_t *)chan_list)->chspecs[i].chanspec); + chspec = wl_chspec_driver_to_host(chspec); + chaninfo = dtoh32(((wl_chanspec_list_v1_t *)chan_list)->chspecs[i].chaninfo); + band = CHSPEC_BAND(chspec); + channel = wf_chspec_primary20_chan(chspec); + freq = wl_channel_to_frequency(channel, band); + width = wl_chanspec_to_host_bw_map(chspec); + + if (sta_chanspec == chspec) { + sta_chaninfo = chaninfo; + WL_DBG(("Found STA chspec in chan_list sta_chanspec:%x\n", sta_chanspec)); + } + + WL_DBG(("chspec:%x channel:%u chaninfo:%x freq:%u band:%u " + "req_band:%u req_iface_mode:%u filter:%u\n", + chspec, channel, chaninfo, freq, CHSPEC_TO_WLC_BAND(band), + u_info->band_mask, u_info->iface_mode_mask, u_info->filter_mask)); + + /* Skip if it is not interested */ + if (!((u_info->band_mask & WLAN_MAC_2_4_BAND) && CHSPEC_IS2G(chspec)) && + !((u_info->band_mask & WLAN_MAC_5_0_BAND) && CHSPEC_IS5G(chspec)) && + !((u_info->band_mask & WLAN_MAC_6_0_BAND) && CHSPEC_IS6G(chspec))) { + continue; + } + + restrict_chan = ((chaninfo & WL_CHAN_RADAR) || + (chaninfo & WL_CHAN_PASSIVE)|| + (chaninfo & WL_CHAN_CLM_RESTRICTED)); +#ifdef WL_SOFTAP_6G + vlp_psc_include = ((chaninfo & WL_CHAN_BAND_6G_PSC) && + (chaninfo & WL_CHAN_BAND_6G_VLP)); +#endif /* WL_SOFTAP_6G */ +#ifdef WL_UNII4_CHAN + is_unii4 = (CHSPEC_IS5G(chspec) && + IS_UNII4_CHANNEL(wf_chspec_primary20_chan(chspec))); +#endif /* WL_UNII4_CHAN */ + + /* STA set all chanspec but can be filtered out in filter function */ + mask = (1 << WIFI_INTERFACE_STA); + + if (sta_assoc_freq && (sta_assoc_freq == freq) && + (!CHSPEC_IS6G(chspec) && !is_unii4)) { + if (CHSPEC_IS5G(chspec) && (chaninfo & WL_CHAN_CLM_RESTRICTED)) { + /* if restricted channel, specifically allow only DFS channel + * (radar+passive). TDLS operates on STA channel and + * allowed in DFS channel + */ + if ((chaninfo & WL_CHAN_RADAR) && (chaninfo & WL_CHAN_PASSIVE)) { + mask |= (1 << WIFI_INTERFACE_TDLS); + } + } else { + /* 2g channels || 5G non restricted channels */ + mask |= (1 << WIFI_INTERFACE_TDLS); + } + } + + /* Only STA supported 160Mhz in 5G */ + if (CHSPEC_IS5G(chspec) && CHSPEC_IS160(chspec)) { + ch_160mhz_5g = true; + } else { + ch_160mhz_5g = false; + } + + if (!restrict_chan && !ch_160mhz_5g) { + if (!is_unii4) + { + if (CHSPEC_IS6G(chspec)) { +#ifdef WL_NAN_6G + mask |= (1 << WIFI_INTERFACE_NAN); +#endif /* WL_NAN_6G */ +#ifdef WL_SOFTAP_6G + /* consider only VLP and PSC channel in 6g for softap */ + if (vlp_psc_include) { + mask |= (1 << WIFI_INTERFACE_SOFTAP); + } +#endif /* WL_SOFTAP_6G */ + } else { + /* handle 2G and 5G channels */ + mask |= ((1 << WIFI_INTERFACE_P2P_GO) | + (1 << WIFI_INTERFACE_SOFTAP)); +#ifdef WL_NAN_INSTANT_MODE + /* handle nan instant mode filter mask case separately */ + if ((u_info->iface_mode_mask & (1 << WIFI_INTERFACE_NAN)) && + (u_info->filter_mask & + WIFI_USABLE_CHANNEL_FILTER_NAN_INSTANT_MODE)) { + if (chspec == nan_inst_mode_chspec) { + mask |= (1 << WIFI_INTERFACE_NAN); + } + } else +#endif /* WL_NAN_INSTANT_MODE */ + { + mask |= (1 << WIFI_INTERFACE_NAN); + } + } + } + } + + /* Supplicant does scan passive channel but not for DFS channel */ + if (!(chaninfo & WL_CHAN_RADAR) && !ch_160mhz_5g && + !CHSPEC_IS6G(chspec) && (!is_unii4)) { + mask |= (1 << WIFI_INTERFACE_P2P_CLIENT); + } + + /* only channel entries matched at least a bit in iface_mode_mask are returned */ + if ((mask & u_info->iface_mode_mask) == 0) { + continue; + } + + /* Return only primary channel and max bandwidth. + * If freq is already added and found bigger bandwidth + * replace bandwidth with found one + */ + found_idx = wl_check_exist_freq_in_list(u_info->channels, idx, freq); + if (found_idx != BCME_NOTFOUND) { + if (width > u_info->channels[found_idx].width) { + u_info->channels[found_idx].width = width; + u_info->channels[found_idx].chspec = chspec; + } + continue; + } + + /* Add current channel to list */ + cur_ch = &u_info->channels[idx]; + cur_ch->freq = freq; + cur_ch->width = width; + cur_ch->iface_mode_mask = mask & u_info->iface_mode_mask; + cur_ch->chspec = chspec; + WL_INFORM_MEM(("idx:%d chanspec:%x freq:%u width:%u iface_mode_mask:%u\n", + idx, cur_ch->chspec, cur_ch->freq, cur_ch->width, cur_ch->iface_mode_mask)); + idx++; + } + u_info->size = idx; + + /* Driver should clear unusable interface based on concurrency and coex restriction */ + if (u_info->filter_mask) { + /* Get conneceted bands to clear STA bit when Dual STA is connected */ + sta_chanspec = wl_cfg80211_get_sta_chanspec(cfg); + + /* Get connected STA, AP, P2P and NAN interface count */ + conn[WL_IF_TYPE_STA] = wl_cfgvif_get_iftype_count(cfg, WL_IF_TYPE_STA); + conn[WL_IF_TYPE_AP] = wl_cfgvif_get_iftype_count(cfg, WL_IF_TYPE_AP); + if (wl_cfgp2p_vif_created(cfg)) { + p2p_ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1); + if (!p2p_ndev) { + WL_ERR(("No p2p net device")); + goto exit; + } + if (p2p_ndev->ieee80211_ptr) { + if (p2p_ndev->ieee80211_ptr->iftype == + NL80211_IFTYPE_P2P_GO) { + conn[WL_IF_TYPE_P2P_GO] = 1; + } else if (p2p_ndev->ieee80211_ptr->iftype == + NL80211_IFTYPE_P2P_CLIENT) { + conn[WL_IF_TYPE_P2P_GC] = 1; + } + } + } +#ifdef WL_NAN + conn[WL_IF_TYPE_NAN] = wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg)); + WL_INFORM_MEM(("Cur interface STA:%d(chspec:%x) " + "AP:%d P2P GO:%d GC:%d NAN:%d\n", + conn[WL_IF_TYPE_STA], sta_chanspec, + conn[WL_IF_TYPE_AP], conn[WL_IF_TYPE_P2P_GO], + conn[WL_IF_TYPE_P2P_GC], conn[WL_IF_TYPE_NAN])); +#endif /* WL_NAN */ + + for (i = 0; i < u_info->size; i++) { + cur_ch = &u_info->channels[i]; + wl_usable_channels_filter(cfg, cur_ch->chspec, &cur_ch->iface_mode_mask, + u_info, conn, sta_chanspec, sta_chaninfo); + } + } + +exit: + if (chan_list) { + MFREE(cfg->osh, chan_list, CHANINFO_LIST_BUF_SIZE); + } + return err; +} +#endif /* WL_USABLE_CHAN */ + +#ifdef CONFIG_SILENT_ROAM +int +wl_cfg80211_sroam_config(struct bcm_cfg80211 *cfg, struct net_device *dev, bool set) +{ + int ret = BCME_OK; + wlc_sroam_t *psroam; + wlc_sroam_info_t *sroam; + uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN; +#ifdef BCMDONGLEHOST + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); +#endif /* BCMDONGLEHOST */ + + /* Check if associated */ + if (!wl_get_drv_status(cfg, CONNECTED, dev)) { + WL_ERR(("NOT associated\n")); + return ret; + } + +#ifdef BCMDONGLEHOST + if (set && (dhd->op_mode & + (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) { + WL_ERR((" Failed to set sroam %d, op_mode 0x%04x\n", set, dhd->op_mode)); + return ret; + } +#endif /* BCMDONGLEHOST */ + + if (!cfg->sroam_turn_on) { + WL_ERR((" sroam %d failed. sroam not enabled (%d)\n", set, cfg->sroam_turn_on)); + return ret; + } + + psroam = (wlc_sroam_t *)MALLOCZ(cfg->osh, sroamlen); + if (!psroam) { + WL_ERR(("Fail to malloc buffer\n")); + return BCME_NOMEM; + } + + ret = wldev_iovar_no_wl(dev, "sroam", + NULL, 0, (char *)psroam, sroamlen, FALSE); + if (ret < 0) { + WL_ERR(("Failed to Get sroam %d\n", ret)); + goto done; + } + + if (psroam->ver != WLC_SILENT_ROAM_VER_1) { + ret = BCME_VERSION; + goto done; + } + + sroam = (wlc_sroam_info_t *)psroam->data; + sroam->sroam_on = set; + WL_INFORM((" Silent roam monitor mode %s\n", set ? "On" : "Off")); + + ret = wldev_iovar_no_wl(dev, "sroam", (char *)psroam, sroamlen, NULL, 0, TRUE); + if (ret < 0) { + WL_ERR(("Failed to Set sroam %d\n", ret)); + } + +done: + if (psroam) { + MFREE(cfg->osh, psroam, sroamlen); + } + + return ret; +} +#endif /* CONFIG_SILENT_ROAM */ + +#ifdef WL_CFGVENDOR_CUST_ADVLOG +static void +wl_cfgvendor_custom_advlog_conn(struct bcm_cfg80211 *cfg, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC); + char advlog[SUPP_LOG_LEN] = {'\0'}; + int buf_pos = 0; + char ssid_str[DOT11_MAX_SSID_LEN + 1]; + + if (!sec) { + WL_ERR(("sec is NULL")); + return; + } + + bzero(advlog, SUPP_LOG_LEN); + + if (memcpy_s(ssid_str, DOT11_MAX_SSID_LEN, + sme->ssid, sme->ssid_len) != BCME_OK) { + WL_ERR(("ssid cpy failed\n")); + return; + } + ssid_str[sme->ssid_len] = '\0'; + + buf_pos = snprintf(advlog, SUPP_LOG_LEN, "[CONN] CONNECTING ssid=\"%s\" ", + ssid_str); + + if (sme->bssid && !ETHER_ISBCAST(sme->bssid)) { + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + buf_pos += snprintf(&advlog[buf_pos], SUPP_LOG_LEN - buf_pos, + "bssid="MACDBG_FULL" ", MAC2STRDBG_FULL(sme->bssid)); + } + if (sme->bssid_hint && !ETHER_ISBCAST(sme->bssid_hint)) { + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + buf_pos += snprintf(&advlog[buf_pos], SUPP_LOG_LEN - buf_pos, + "bssid_hint="MACDBG_FULL" ", MAC2STRDBG_FULL(sme->bssid_hint)); + } + if (sme->channel) { + buf_pos += snprintf(&advlog[buf_pos], SUPP_LOG_LEN - buf_pos, + "freq=%d ", sme->channel->center_freq); + } + if (sme->channel_hint) { + buf_pos += snprintf(&advlog[buf_pos], SUPP_LOG_LEN - buf_pos, + "freq_hint=%d ", sme->channel_hint->center_freq); + } + buf_pos += snprintf(&advlog[buf_pos], SUPP_LOG_LEN - buf_pos, + "pairwise=0x%x group=0x%x akm=0x%x auth_type=%d ", + sec->cipher_pairwise, sec->cipher_group, sec->wpa_auth, sec->auth_type); + if (sec->fw_mfp == WL_MFP_REQUIRED) { + buf_pos += snprintf(&advlog[buf_pos], SUPP_LOG_LEN - buf_pos, + "group_mgmt=0x%x", sme->crypto.akm_suites[0]); + } + + SUPP_ADVLOG(("%s", advlog)); + + return; +} + +static void +wl_cfgvendor_custom_advlog_connfail(struct bcm_cfg80211 *cfg, const wl_event_msg_t *event, + wl_assoc_status_t *as) +{ + BCM_REFERENCE(cfg); + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + SUPP_ADVLOG(("[CONN] CONNECTING FAIL bssid=" MACDBG_FULL " [status=%d]\n", + MAC2STRDBG_FULL((const u8*)(&event->addr)), as->status)); + + return; +} + +static void +wl_cfgvendor_custom_advlog_disconn(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as) +{ + int err = 0; + scb_val_t scbval; + + bzero(&scbval, sizeof(scb_val_t)); + err = wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg), &scbval); + if (unlikely(err)) { + WL_ERR(("get_rssi error (%d)\n", err)); + scbval.val = 0; + } + /* Beacon loss link down */ + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + SUPP_ADVLOG(("[CONN] DISCONN bssid=" MACDBG_FULL " rssi=%d reason=0\n", + MAC2STRDBG_FULL((const u8*)(&as->addr)), scbval.val)); + + return; +} +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ + +int +wl_cfg80211_get_roam_params(struct net_device *dev, uint32 *data, uint16 data_len, uint16 id) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + s32 err = BCME_OK; + bcm_iov_buf_t *iov_buf = NULL; + bcm_iov_buf_t *ioctl_buf = NULL; + const uint8 *pxtlv = NULL; + + ioctl_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (!ioctl_buf) { + WL_ERR(("ioctl memory alloc failed\n")); + err = BCME_NOMEM; + goto exit; + } + + iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (!iov_buf) { + WL_ERR(("No memory")); + err = BCME_NOMEM; + goto exit; + } + + /* fill header */ + iov_buf->version = WL_ROAM_PARAMS_IOV_VERSION_1_1; + iov_buf->id = id; + + err = wldev_iovar_getbuf(dev, "roam_params", iov_buf, sizeof(bcm_iov_buf_t), + ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(err)) { + WL_ERR(("get roam_params id %d error %d\n", id, err)); + } + + pxtlv = (const uint8 *)&ioctl_buf->data[0]; + err = bcm_unpack_xtlv_entry(&pxtlv, id, + data_len, (uint8 *)data, BCM_XTLV_OPTION_ALIGN32); + +exit: + if (ioctl_buf) { + MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); + } + + if (iov_buf) { + MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN); + } + + return err; +} + +int +wl_cfg80211_set_roam_params(struct net_device *dev, uint32 *data, uint16 data_len, uint16 id) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + s32 err = BCME_OK; + bcm_iov_buf_t *iov_buf = NULL; + char *ioctl_buf = NULL; + uint8 *pxtlv = NULL; + uint16 iovlen = 0; + uint16 buflen = 0, buflen_start = 0; + + if (!cfg) { + return BCME_ERROR; + } + + if (data_len > WLC_IOCTL_MEDLEN) { + err = BCME_BADLEN; + goto exit; + } + + ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (!ioctl_buf) { + WL_ERR(("ioctl memory alloc failed\n")); + err = BCME_NOMEM; + goto exit; + } + + iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (!iov_buf) { + WL_ERR(("No memory")); + err = BCME_NOMEM; + goto exit; + } + + /* fill header */ + iov_buf->version = WL_ROAM_PARAMS_IOV_VERSION_1_1; + iov_buf->id = id; + pxtlv = (uint8 *)&iov_buf->data[0]; + buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t); + + err = bcm_pack_xtlv_entry(&pxtlv, &buflen, id, + data_len, (uint8 *)data, BCM_XTLV_OPTION_ALIGN32); + + if (err != BCME_OK) { + WL_ERR(("failed to pack roam_params id %d, err %d\n", id, err)); + goto exit; + } + iov_buf->len = buflen_start - buflen; + iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len; + + err = wldev_iovar_setbuf(dev, "roam_params", iov_buf, iovlen, + ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(err)) { + WL_ERR(("set roam_params id %d error %d\n", id, err)); + } + +exit: + if (ioctl_buf) { + MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); + } + + if (iov_buf) { + MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN); + } + return err; +} + s32 wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len) { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h old mode 100755 new mode 100644 index d5e7315518f9..65783e72b234 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -29,6 +29,9 @@ #define _wl_cfg80211_h_ #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) +#include +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) */ #include #include #include @@ -39,8 +42,17 @@ #if defined(BCMDONGLEHOST) #include #include +#ifdef DHD_LOG_DUMP +#include +#include +#endif #endif /* BCMDONGLEHOST */ +#if !defined(WL_FILS_IOV_VERSION) +/* WL FILS IOV API version */ +#define WL_FILS_IOV_VERSION WL_FILS_IOV_VERSION_1_1 +#endif /* WL_FILS_IOV_VERSION */ + #define WL_CFG_DRV_LOCK(lock, flags) (flags) = osl_spin_lock(lock) #define WL_CFG_DRV_UNLOCK(lock, flags) osl_spin_unlock((lock), (flags)) @@ -59,6 +71,7 @@ #define WL_CFG_VNDR_OUI_SYNC_LOCK(lock, flags) (flags) = osl_spin_lock(lock) #define WL_CFG_VNDR_OUI_SYNC_UNLOCK(lock, flags) osl_spin_unlock((lock), (flags)) +#include #include #include #ifdef WL_NAN @@ -67,10 +80,6 @@ #ifdef WL_BAM #include #endif /* WL_BAM */ - -#ifdef BIGDATA_SOFTAP -#include -#endif /* BIGDATA_SOFTAP */ #include struct wl_conf; @@ -82,12 +91,6 @@ struct wl_ibss; /* Enable by default */ #define WL_WTC -/* - * Common feature. If this becomes customer specific, - * move it to customer specific makefile when required - */ -#define WL_5G_SOFTAP_ONLY_ON_DEF_CHAN - #if !defined(WL_CLIENT_SAE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)) #define WL_CLIENT_SAE #endif @@ -101,7 +104,45 @@ struct wl_ibss; #error "WL_SAE is for dongle-offload and WL_CLIENT_SAE is for wpa_supplicant. Please choose one." #endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) && !defined(WL_SCAN_TYPE)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)) +#ifndef WL_CLIENT_SAE +#define WL_CLIENT_SAE +#endif /* WL_CLIENT_SAE */ + +/* OWE */ +#ifndef WL_OWE +#define WL_OWE +#endif /* WL_OWE */ + +/* WPA3 Enterprise Suite-B 192 */ +#ifndef WL_GCMP_SUPPORT +#define WL_GCMP_SUPPORT +#endif /* WL_GCMP_SUPPORT */ + +#ifdef OEM_ANDROID +/* mandatory for Android 11 */ +#define WL_ACT_FRAME_MAC_RAND +#endif + +/* WPA3 R2 */ +#ifndef WL_SAE_FT +#define WL_SAE_FT +#endif // WL_SAE_FT +#endif /* KERNEL >= 4.17 */ + +#ifdef WL_CLIENT_SAE +#ifdef WL_SAE +#error "WL_SAE is for dongle-offload and WL_CLIENT_SAE is for wpa_supplicant. \ + Please modify DHD to choose one." +#endif /* WL_SAE */ +#endif /* WL_CLIENT_SAE */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) && !defined(WL_SAE)) +#define WL_SAE +#endif /* LINUX_VERSION_CODE >= (4, 17, 0) && !(WL_SAE) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)) && !defined(WL_DISABLE_SCAN_TYPE) \ + && !defined(WL_SCAN_TYPE) #define WL_SCAN_TYPE #endif /* WL_SCAN_TYPE */ @@ -115,15 +156,75 @@ struct wl_ibss; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) /* Use driver managed regd */ +#define WL_AUTO_COUNTRY 1 #define WL_SELF_MANAGED_REGDOM #endif /* KERNEL >= 4.0 */ +#ifdef OEM_ANDROID +/* mandatory for Android 11 */ +#define WL_ACT_FRAME_MAC_RAND +#endif + +#if defined(WL_6G_BAND) && !defined(WL_DISABLE_SOFTAP_6G) +/* Unless exlicitly disabled, enable softap 6G when 6G band support is present */ +#define WL_SOFTAP_6G +#endif /* WL_6G_BAND && !WL_DISABLE_SOFTAP_6G */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) && !defined(WL_NMI_IF)) +#define WL_NMI_IF +#endif /* LINUX_VERSION_CODE >= (4, 17, 0) && !(WL_NMI_IF) */ + +/* Define to default v6 */ +#define USE_STA_INFO_V6 +#ifdef USE_STA_INFO_V6 +typedef sta_info_v6_t wlcfg_sta_info_t; +/* Support ver >= 6 */ +#define IS_STA_INFO_VER(sta) (dtoh16(sta->ver) >= WL_STA_VER_6 || (dtoh16(sta->ver) == WL_STA_VER_4)) +#define WL_STAINFO_VER WL_STA_VER_6 +#elif defined(USE_STA_INFO_V5) +typedef sta_info_v5_t wlcfg_sta_info_t; +#define IS_STA_INFO_VER(sta) (dtoh16(sta->ver) == WL_STA_VER_5) +#define WL_STAINFO_VER WL_STA_VER_5 +#else +typedef sta_info_v4_t wlcfg_sta_info_t; +#define IS_STA_INFO_VER(sta) (dtoh16(sta->ver) == WL_STA_VER_4) +#define WL_STAINFO_VER WL_STA_VER_4 +#endif /* USE_STA_INFO_V6 */ + +/* MSCS default configuration values */ +#ifndef MSCS_CFG_DEF_STREAM_TIMEOUT +#define MSCS_CFG_DEF_STREAM_TIMEOUT 60000u /* TUs */ +#endif /* MSCS_CFG_DEF_STREAM_TIMEOUT */ + +#ifndef MSCS_CFG_DEF_UP_LIMIT +#define MSCS_CFG_DEF_UP_LIMIT 7u /* up limit */ +#endif /* MSCS_CFG_DEF_UP_LIMIT */ + +#ifndef MSCS_CFG_DEF_FC_MASK +#define MSCS_CFG_DEF_FC_MASK 0xF0u /* frame classifier mask */ +#endif /* MSCS_CFG_DEF_FC_MASK */ + +#ifndef MSCS_CFG_DEF_TCLAS_MASK +#define MSCS_CFG_DEF_TCLAS_MASK 0x5Fu /* TCLAS mask */ +#endif /* MSCS_CFG_DEF_TCLAS_MASK */ + #define CH_TO_CHSPC(band, _channel) \ ((_channel | band) | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE) +#ifdef EXT_REG_INFO +#define HW_VALUE_CHANNEL_2G(_channel) _channel +#define HW_VALUE_CHANNEL_5G(_channel) _channel +#define HW_VALUE_CHANNEL_6G(_channel) (CH_MAX_5G_CHANNEL + _channel) +#define HW_VALUE_CHANNEL_6G_2(_channel) (CH_MAX_5G_CHANNEL + 2) +#else +#define HW_VALUE_CHANNEL_2G(_channel) CH_TO_CHSPC(WL_CHANSPEC_BAND_2G, _channel) +#define HW_VALUE_CHANNEL_5G(_channel) CH_TO_CHSPC(WL_CHANSPEC_BAND_5G, _channel) +#define HW_VALUE_CHANNEL_6G(_channel) CH_TO_CHSPC(WL_CHANSPEC_BAND_6G, _channel) +#define HW_VALUE_CHANNEL_6G_2(_channel) 0x5002 +#endif /* EXT_REG_INFO */ #define CHAN2G(_channel, _freq, _flags) { \ .band = IEEE80211_BAND_2GHZ, \ .center_freq = (_freq), \ - .hw_value = CH_TO_CHSPC(WL_CHANSPEC_BAND_2G, _channel), \ + .hw_value = HW_VALUE_CHANNEL_2G(_channel),\ .flags = (_flags), \ .max_antenna_gain = 0, \ .max_power = 30, \ @@ -132,7 +233,7 @@ struct wl_ibss; #define CHAN5G(_channel, _flags) { \ .band = IEEE80211_BAND_5GHZ, \ .center_freq = 5000 + (5 * (_channel)), \ - .hw_value = CH_TO_CHSPC(WL_CHANSPEC_BAND_5G, _channel), \ + .hw_value = HW_VALUE_CHANNEL_5G(_channel),\ .flags = (_flags), \ .max_antenna_gain = 0, \ .max_power = 30, \ @@ -142,7 +243,7 @@ struct wl_ibss; #define CHAN6G(_channel, _flags) { \ .band = IEEE80211_BAND_6GHZ, \ .center_freq = 5950 + (5 * (_channel)), \ - .hw_value = CH_TO_CHSPC(WL_CHANSPEC_BAND_6G, _channel), \ + .hw_value = HW_VALUE_CHANNEL_6G(_channel),\ .flags = (_flags), \ .max_antenna_gain = 0, \ .max_power = 30, \ @@ -151,7 +252,7 @@ struct wl_ibss; #define CHAN6G_CHAN2(_flags) { \ .band = IEEE80211_BAND_6GHZ, \ .center_freq = 5935, \ - .hw_value = 0x5002, \ + .hw_value = HW_VALUE_CHANNEL_6G_2(_channel),\ .flags = (_flags), \ .max_antenna_gain = 0, \ .max_power = 30, \ @@ -160,7 +261,7 @@ struct wl_ibss; #define CHAN6G(_channel, _flags) { \ .band = IEEE80211_BAND_5GHZ, \ .center_freq = 5950 + (5 * (_channel)), \ - .hw_value = CH_TO_CHSPC(WL_CHANSPEC_BAND_6G, _channel), \ + .hw_value = HW_VALUE_CHANNEL_6G(_channel),\ .flags = (_flags), \ .max_antenna_gain = 0, \ .max_power = 30, \ @@ -169,7 +270,7 @@ struct wl_ibss; #define CHAN6G_CHAN2(_flags) { \ .band = IEEE80211_BAND_5GHZ, \ .center_freq = 5935, \ - .hw_value = 0x5002, \ + .hw_value = HW_VALUE_CHANNEL_6G_2(_channel),\ .flags = (_flags), \ .max_antenna_gain = 0, \ .max_power = 30, \ @@ -207,6 +308,7 @@ struct wl_ibss; #endif /* IL_BIGENDIAN */ #define WL_DBG_NONE 0 +#define WL_DBG_PNO (1 << 6) #define WL_DBG_P2P_ACTION (1 << 5) #define WL_DBG_TRACE (1 << 4) #define WL_DBG_SCAN (1 << 3) @@ -247,7 +349,6 @@ struct wl_ibss; extern void dhd_log_dump_write(int type, char *binary_data, int binary_len, const char *fmt, ...); extern char *dhd_log_dump_get_timestamp(void); -extern char *dhd_dbg_get_system_timestamp(void); #ifndef _DHD_LOG_DUMP_DEFINITIONS_ #define DHD_LOG_DUMP_WRITE(fmt, ...) \ dhd_log_dump_write(DLD_BUF_TYPE_GENERAL, NULL, 0, fmt, ##__VA_ARGS__) @@ -332,6 +433,7 @@ extern char *dhd_dbg_get_system_timestamp(void); #endif /* SUPPORT_AP_RADIO_PWRSAVE */ #ifdef BCMWAPI_WPI +#ifdef OEM_ANDROID #ifdef CFG80211_WAPI_BKPORT #define IS_WAPI_VER(version) (version == NL80211_WAPI_VERSION_1) #undef WLAN_AKM_SUITE_WAPI_PSK @@ -339,7 +441,6 @@ extern char *dhd_dbg_get_system_timestamp(void); #undef WLAN_AKM_SUITE_WAPI_CERT #define WLAN_AKM_SUITE_WAPI_CERT 0x000FAC14 #else -#ifdef OEM_ANDROID #undef NL80211_WAPI_VERSION_1 #define NL80211_WAPI_VERSION_1 0 @@ -350,18 +451,18 @@ extern char *dhd_dbg_get_system_timestamp(void); #define WLAN_AKM_SUITE_WAPI_CERT 0x000FACFF /* WAPI */ #define IS_WAPI_VER(version) (version == NL80211_WAPI_VERSION_1) +#endif /* CFG80211_WAPI_BKPORT */ #else #undef WLAN_AKM_SUITE_WAPI_PSK -#define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC04 +#define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC13 #undef WLAN_AKM_SUITE_WAPI_CERT -#define WLAN_AKM_SUITE_WAPI_CERT 0x000FAC12 +#define WLAN_AKM_SUITE_WAPI_CERT 0x000FAC14 #undef NL80211_WAPI_VERSION_1 -#define NL80211_WAPI_VERSION_1 1 << 2 +#define NL80211_WAPI_VERSION_1 1 << 3 #define IS_WAPI_VER(version) (version & NL80211_WAPI_VERSION_1) #endif /* OEM_ANDROID */ -#endif /* CFG80211_WAPI_BKPORT */ #endif /* BCMWAPI_WPI */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) @@ -371,8 +472,7 @@ extern char *dhd_dbg_get_system_timestamp(void); #define IS_REGDOM_SELF_MANAGED(wiphy) (false) #endif /* KERNEL >= 4.0 */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && \ - defined(WL_SELF_MANAGED_REGDOM) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM) #define WL_UPDATE_CUSTOM_REGULATORY(wiphy) \ wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) @@ -400,13 +500,16 @@ extern char *dhd_dbg_get_system_timestamp(void); #define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */ +/* regdomain country code len */ +#define WL_CCODE_LEN 2u + /* On some MSM platform, it uses different version * of linux kernel and cfg code as not synced. * MSM defined CFG80211_DISCONNECTED_V2 as the flag * when they uses different kernel/cfg version. */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) || \ - (defined(CONFIG_ARCH_MSM) && defined(CFG80211_DISCONNECTED_V2)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) || (defined(CONFIG_ARCH_MSM) && \ + defined(CFG80211_DISCONNECTED_V2)) #define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \ cfg80211_disconnected(dev, reason, ie, len, loc_gen, gfp); #elif (LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)) @@ -420,58 +523,77 @@ extern char *dhd_dbg_get_system_timestamp(void); #if defined(CUSTOMER_DBG_SYSTEM_TIME) && defined(DHD_DEBUGABILITY_LOG_DUMP_RING) #define WL_DBG_PRINT_SYSTEM_TIME \ - pr_cont("[%s]", dhd_dbg_get_system_timestamp()) + pr_cont("[%s]", OSL_GET_RTCTIME()) #else #define WL_DBG_PRINT_SYSTEM_TIME #endif /* defined(CUSTOMER_DBG_SYSTEM_TIME) && defined(DHD_DEBUGABILITY_LOG_DUMP_RING) */ #if defined(CUSTOMER_DBG_PREFIX_ENABLE) +#ifdef CUSTOM_PREFIX_NORTCTIME +#define USER_PREFIX_CFG80211 CUSTOM_PREFIX_NORTCTIME +#else #define USER_PREFIX_CFG80211 "[cfg80211][wlan] " +#endif /* CUSTOM_PREFIX_NORTCTIME */ #define CFG80211_INFO_TEXT USER_PREFIX_CFG80211 #define CFG80211_ERROR_TEXT USER_PREFIX_CFG80211 #define CFG80211_SCAN_TEXT USER_PREFIX_CFG80211 #define CFG80211_TRACE_TEXT USER_PREFIX_CFG80211 #define CFG80211_DEBUG_TEXT USER_PREFIX_CFG80211 + +#define WL_CONS_ONLY_MSG(x, args...) \ +do { \ + printf(USER_PREFIX_CFG80211 "%s : " x, __func__, ## args); \ +} while (0) +#define WL_CONS_ONLY(x) WL_CONS_ONLY_MSG x #else #define CFG80211_INFO_TEXT "CFG80211-INFO) " /* Samsung want to print INFO2 instead of ERROR * because most of case, ERROR message is not a real ERROR. * but it can be regarded as real error case for Tester */ -#ifdef CUSTOMER_HW4_DEBUG -#define CFG80211_ERROR_TEXT "CFG80211-INFO2) " -#else #define CFG80211_ERROR_TEXT "CFG80211-ERROR) " -#endif /* CUSTOMER_HW4_DEBUG */ #define CFG80211_SCAN_TEXT "CFG80211-SCAN) " #define CFG80211_TRACE_TEXT "CFG80211-TRACE) " #define CFG80211_DEBUG_TEXT "CFG80211-DEBUG) " +#define WL_CONS_ONLY(args) do { printf args; } while (0) #endif /* defined(CUSTOMER_DBG_PREFIX_ENABLE) */ +#ifdef DBG_PRINT_SSID +#define SSID_DBG(_ssid_) _ssid_ +#else /* DBG_PNO_SSID */ +#define SSID_DBG(_ssid_) "*****" +#endif /* DBG_PRINT_SSID */ + #ifdef DHD_DEBUG #ifdef DHD_LOG_DUMP #define WL_ERR_MSG(x, args...) \ do { \ if (wl_dbg_level & WL_DBG_ERR) { \ printf(CFG80211_ERROR_TEXT "%s : " x, __func__, ## args); \ + } \ + if (wl_log_level & WL_DBG_ERR) { \ DHD_LOG_DUMP_WRITE_TS_FN; \ - DHD_LOG_DUMP_WRITE(x, ## args); \ - } \ + DHD_LOG_DUMP_WRITE (x, ## args); \ + } \ } while (0) #define WL_ERR(x) WL_ERR_MSG x #define WL_ERR_KERN_MSG(x, args...) \ do { \ if (wl_dbg_level & WL_DBG_ERR) { \ printf(CFG80211_ERROR_TEXT "%s : " x, __func__, ## args); \ - } \ + } \ + if (wl_log_level & WL_DBG_ERR) { \ + DHD_LOG_DUMP_WRITE_TS_FN; \ + DHD_LOG_DUMP_WRITE(x, ## args); \ + } \ } while (0) #define WL_ERR_KERN(x) WL_ERR_KERN_MSG x #define WL_ERR_MEM_MSG(x, args...) \ do { \ - if (wl_dbg_level & WL_DBG_ERR) { \ + if (wl_log_level & WL_DBG_ERR) { \ DHD_LOG_DUMP_WRITE_TS_FN; \ DHD_LOG_DUMP_WRITE(x, ## args); \ - } \ + } \ } while (0) /* Prints to debug ring by default. If dbg level is enabled, prints on to * console as well @@ -490,25 +612,32 @@ do { \ do { \ if (wl_dbg_level & WL_DBG_INFO) { \ printf(CFG80211_INFO_TEXT "%s : " x, __func__, ## args); \ + } \ + if (wl_log_level & WL_DBG_INFO) { \ DHD_LOG_DUMP_WRITE_TS_FN; \ DHD_LOG_DUMP_WRITE(x, ## args); \ - } \ + } \ } while (0) #define WL_INFORM_MEM(x) WL_INFORM_MEM_MSG x #define WL_ERR_EX_MSG(x, args...) \ do { \ if (wl_dbg_level & WL_DBG_ERR) { \ printf(CFG80211_ERROR_TEXT "%s : " x, __func__, ## args); \ + } \ + if (wl_log_level & WL_DBG_ERR) { \ DHD_LOG_DUMP_WRITE_EX_TS_FN; \ DHD_LOG_DUMP_WRITE_EX(x, ## args); \ - } \ + } \ } while (0) #define WL_ERR_EX(x) WL_ERR_EX_MSG x -#define WL_MEM(args) \ +#define WL_MEM_MSG(x, args...) \ do { \ - DHD_LOG_DUMP_WRITE_TS_FN; \ - DHD_LOG_DUMP_WRITE args; \ + if (wl_log_level & WL_DBG_ERR) { \ + DHD_LOG_DUMP_WRITE_TS_FN; \ + DHD_LOG_DUMP_WRITE(x, ## args); \ + } \ } while (0) +#define WL_MEM(x) WL_MEM_MSG x #else #define WL_ERR_MSG(x, args...) \ do { \ @@ -540,10 +669,10 @@ do { \ #define WL_MEM(args) WL_DBG(args) #endif /* defined(DHD_DEBUG) */ -#if defined(__linux__) && !defined(DHD_EFI) +#if defined(__linux__) #define WL_PRINT_RATE_LIMIT_PERIOD 4000000000u /* 4s in units of ns */ #endif -#if defined(__linux__) && !defined(DHD_EFI) +#if defined(__linux__) #define WL_ERR_RLMT(args) \ do { \ if (wl_dbg_level & WL_DBG_ERR) { \ @@ -564,7 +693,7 @@ do { \ } while (0) #else /* defined(__linux__) && !defined(DHD_EFI) */ #define WL_ERR_RLMT(args) WL_ERR(args) -#endif /* defined(__linux__) && !defined(DHD_EFI) */ +#endif /* __linux__ */ #ifdef WL_INFORM #undef WL_INFORM @@ -601,17 +730,7 @@ do { \ #ifdef WL_TRACE_HW4 #undef WL_TRACE_HW4 #endif -#ifdef CUSTOMER_HW4_DEBUG -#define WL_TRACE_HW4_MSG(x, args...) \ -do { \ - if (wl_dbg_level & WL_DBG_ERR) { \ - printf(CFG80211_TRACE_TEXT "%s : " x, __func__, ## args); \ - } \ -} while (0) -#define WL_TRACE_HW4(x) WL_TRACE_HW4_MSG x -#else #define WL_TRACE_HW4 WL_TRACE -#endif /* CUSTOMER_HW4_DEBUG */ #if (WL_DBG_LEVEL > 0) #define WL_DBG_MSG(x, args...) \ do { \ @@ -623,7 +742,14 @@ do { \ #else /* !(WL_DBG_LEVEL > 0) */ #define WL_DBG(args) #endif /* (WL_DBG_LEVEL > 0) */ -#define WL_PNO(x) +#define WL_PNO_MSG(x, args...) \ +do { \ + if (wl_dbg_level & WL_DBG_PNO) { \ + printf(CFG80211_SCAN_TEXT "%s :" x, __func__, ## args); \ + } \ +} while (0) +#define WL_PNO(x) WL_PNO_MSG x + #define WL_SD(x) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) @@ -653,8 +779,12 @@ do { \ #define WL_MED_DWELL_TIME 400 #define WL_MIN_DWELL_TIME 100 #define WL_LONG_DWELL_TIME 1000 +#ifdef WL_MLO +#define IFACE_MAX_CNT 7 +#else #define IFACE_MAX_CNT 5 -#define WL_SCAN_CONNECT_DWELL_TIME_MS 200 +#endif /* WL_MLO */ +#define WL_SCAN_CONNECT_DWELL_TIME_MS 100 #define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 #define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 #define WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 80 @@ -672,14 +802,21 @@ do { \ #ifdef WL_6G_BAND /* additional scan timeout for 6GHz, 6000msec */ #define WL_SCAN_TIMER_INTERVAL_MS_6G 6000 +#define CHSPEC_TO_WLC_BAND(chspec) (CHSPEC_IS2G(chspec) ? WLC_BAND_2G : CHSPEC_IS5G(chspec) ? \ + WLC_BAND_5G : WLC_BAND_6G) +#else +#define CHSPEC_TO_WLC_BAND(chspec) (CHSPEC_IS2G(chspec) ? WLC_BAND_2G : WLC_BAND_5G) #endif /* WL_6G_BAND */ -#define CHSPEC_IS_6G_PSC(chspec) (CHSPEC_IS6G(chspec) && ((CHSPEC_CHANNEL(chspec) % 16) == 5)) +#define CHSPEC_IS_6G_PSC(chspec) (CHSPEC_IS6G(chspec) && ((wf_chspec_ctlchan(chspec) % 16) == 5)) #define WL_CHANNEL_SYNC_RETRY 5 #define WL_INVALID -1 #ifdef DHD_LOSSLESS_ROAMING +#ifndef WL_ROAM_TIMEOUT_MS #define WL_ROAM_TIMEOUT_MS 1000 /* Roam timeout */ -#endif +#endif /* WL_ROAM_TIMEOUT_MS */ +#endif /* DHD_LOSSLESS_ROAMING */ + /* Bring down SCB Timeout to 20secs from 60secs default */ #ifndef WL_SCB_TIMEOUT #define WL_SCB_TIMEOUT 20 @@ -723,9 +860,6 @@ do { \ #define WLAN_AKM_SUITE_8021X_SUITE_B_192 0x000FAC0C #endif /* WLAN_AKM_SUITE_8021X_SUITE_B */ -/* TODO: even in upstream linux(v5.0), FT-1X-SHA384 isn't defined and supported yet. - * need to revisit here to sync correct name later. - */ #ifndef WLAN_AKM_SUITE_FT_8021X_SHA384 #define WLAN_AKM_SUITE_FT_8021X_SHA384 0x000FAC0D #endif /* WLAN_AKM_SUITE_FT_8021X_SHA384 */ @@ -743,12 +877,18 @@ do { \ #endif /* WLAN_AKM_SUITE_FILS_SHA256 */ #define MIN_VENDOR_EXTN_IE_LEN 2 + #ifdef WL_OWE #ifndef WLAN_AKM_SUITE_OWE #define WLAN_AKM_SUITE_OWE 0X000FAC12 #endif /* WPA_KEY_MGMT_OWE */ #endif /* WL_OWE */ + +#ifndef WLAN_AKM_SUITE_DPP #define WLAN_AKM_SUITE_DPP 0X506F9A02 +#endif /* WLAN_AKM_SUITE_DPP */ + +#define CRYPTO_PARAMS_PN_IV_LEN 6 /* * BRCM local. @@ -770,13 +910,8 @@ do { \ #define WL_WOWLAN_PKT_FILTER_ID_FIRST 201 #define WL_WOWLAN_PKT_FILTER_ID_LAST (WL_WOWLAN_PKT_FILTER_ID_FIRST + \ WL_WOWLAN_MAX_PATTERNS - 1) -#ifdef WLAIBSS -#define IBSS_COALESCE_DEFAULT 0 -#define IBSS_INITIAL_SCAN_ALLOWED_DEFAULT 0 -#else /* WLAIBSS */ #define IBSS_COALESCE_DEFAULT 1 #define IBSS_INITIAL_SCAN_ALLOWED_DEFAULT 1 -#endif /* WLAIBSS */ #ifdef WLTDLS #define TDLS_TUNNELED_PRB_REQ "\x7f\x50\x6f\x9a\04" @@ -784,20 +919,26 @@ do { \ #define TDLS_MAX_IFACE_FOR_ENABLE 1 #endif /* WLTDLS */ -#ifdef WLAIBSS -/* Custom AIBSS beacon parameters */ -#define AIBSS_INITIAL_MIN_BCN_DUR 500 -#define AIBSS_MIN_BCN_DUR 5000 -#define AIBSS_BCN_FLOOD_DUR 5000 -#define AIBSS_PEER_FREE 3 -#endif /* WLAIBSS */ - #ifndef FILS_INDICATION_IE_TAG_FIXED_LEN #define FILS_INDICATION_IE_TAG_FIXED_LEN 2 #endif -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) &&\ -(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) +#define IS_RADAR_CHAN(flags) (flags & (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN)) +#else +#define IS_RADAR_CHAN(flags) (flags & (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR)) +#endif + +/* Join pref defines */ +#define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */ +#define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */ +#define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */ +#define JOIN_PREF_MAX_WPA_TUPLES 16 /* Max no of tuples */ +#define JOIN_PREF_MAX_BUF_SIZE (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \ + (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES)) + +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ + 4 && __GNUC_MINOR__ >= 6)) #define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); \ (entry) = list_first_entry((ptr), type, member); \ @@ -867,6 +1008,25 @@ typedef struct wl_dpp_pub_act_frame wl_dpp_pa_frame_t; typedef wifi_p2psd_gas_pub_act_frame_t wl_dpp_gas_af_t; +#define DEFAULT_ASSOC_LISTEN 0xau +#define DEFAULT_ROAM_SCAN_PRD 10u +#define DEFAULT_FULL_ROAM_PRD 0x78u +#define DEFAULT_ASSOC_RETRY 0x3u +#define DEFAULT_WNM_CONF 0x505u +#ifndef DEFAULT_RECREATE_BI_TIMEOUT +#define DEFAULT_RECREATE_BI_TIMEOUT 20u +#endif + +struct preinit_iov; +typedef int (*wl_iov_fn) (struct bcm_cfg80211 *cfg, struct net_device *dev, struct preinit_iov *v); + +typedef struct preinit_iov { + wl_iov_fn fn; + uint16 cmd_id; /* preinit iovar/ioctl cmd id */ + int32 value; /* preinit iovar input value */ + s8 *cmd_name; /* preinit ioctl cmd name */ +} preinit_iov_t; + /* driver status */ enum wl_status { WL_STATUS_READY = 0, @@ -876,6 +1036,7 @@ enum wl_status { WL_STATUS_CONNECTED, WL_STATUS_DISCONNECTING, WL_STATUS_AP_CREATING, + WL_STATUS_AP_ROLE_UPGRADED, WL_STATUS_AP_CREATED, /* whole sending action frame procedure: * includes a) 'finding common channel' for public action request frame @@ -907,6 +1068,7 @@ enum wl_status { WL_STATUS_NESTED_CONNECT, WL_STATUS_CFG80211_CONNECT, WL_STATUS_AUTHORIZED + }; typedef enum wl_iftype { @@ -916,10 +1078,6 @@ typedef enum wl_iftype { WL_IF_TYPE_MESH = 2, #endif /* WLMESH_CFG80211 */ -#ifdef WLAWDL - WL_IF_TYPE_AWDL = 2, -#endif /* WLAWDL */ - WL_IF_TYPE_NAN_NMI = 3, WL_IF_TYPE_NAN = 4, WL_IF_TYPE_P2P_GO = 5, @@ -928,6 +1086,8 @@ typedef enum wl_iftype { WL_IF_TYPE_IBSS = 8, WL_IF_TYPE_MONITOR = 9, WL_IF_TYPE_AIBSS = 10, + WL_IF_TYPE_MLO_STA_LINK = 11, + WL_IF_TYPE_MLO_AP_LINK = 12, WL_IF_TYPE_MAX } wl_iftype_t; @@ -947,10 +1107,6 @@ enum wl_mode { WL_MODE_IBSS = 1, WL_MODE_AP = 2, -#ifdef WLAWDL - WL_MODE_AWDL = 3, -#endif /* WLAWDL */ - WL_MODE_NAN = 4, #ifdef WLMESH_CFG80211 WL_MODE_MESH = 5, @@ -1011,9 +1167,20 @@ enum wl_tdls_config { typedef enum wl_assoc_state { WL_STATE_ASSOC_IDLE, WL_STATE_ASSOCIATING, - WL_STATE_ASSOCIATED + WL_STATE_ASSOCIATED, + WL_STATE_LINKDOWN } wl_assoc_state_t; +typedef enum wl_roam_conf { + ROAM_CONF_INVALID, + ROAM_CONF_ASSOC_REQ, + ROAM_CONF_LINKUP, + ROAM_CONF_LINKDOWN, + ROAM_CONF_PRIMARY_STA, + ROAM_CONF_ROAM_ENAB_REQ, + ROAM_CONF_ROAM_DISAB_REQ +} wl_roam_conf_t; + typedef enum wl_link_action { WL_LINK_NONE, WL_LINK_ASSOC_FAIL, @@ -1031,6 +1198,7 @@ typedef struct wl_assoc_status { u32 reason; wl_link_action_t link_action; u8 curbssid[ETH_ALEN]; + u8 ml_event; u8 addr[ETH_ALEN]; u16 data_len; void *data; @@ -1189,7 +1357,19 @@ struct net_info { s32 bssidx; wl_cfgbss_t bss; u8 ifidx; + u8 passphrase[WSEC_MAX_PASSPHRASE_LEN]; + u16 passphrase_len; struct list_head list; /* list of all net_info structure */ + + bool ps_managed; + uint32 ps_managed_start_ts; + /* used to comapre with incoming config + * Delete config from firmware if both are not matching + * If matching, skip configuring iovar again + */ + u8* passphrase_cfg; + u16 passphrase_cfg_len; + u8 *qos_up_table; }; #ifdef WL_BCNRECV @@ -1290,7 +1470,8 @@ struct wl_assoc_ielen { #define MIN_JOINEXT_V1_BR2_FW_MINOR 1u #define MIN_JOINEXT_V1_BR1_FW_MAJOR 14u -#define MIN_JOINEXT_V1_BR1_FW_MINOR 2u +#define MIN_JOINEXT_V1_BR1_FW_MINOR_2 2u +#define MIN_JOINEXT_V1_BR1_FW_MINOR_4 4u #define PMKDB_WLC_VER 14 #define MIN_PMKID_LIST_V3_FW_MAJOR 13 @@ -1299,6 +1480,17 @@ struct wl_assoc_ielen { #define MIN_PMKID_LIST_V2_FW_MAJOR 12 #define MIN_PMKID_LIST_V2_FW_MINOR 0 +#define NEW_PMK_MGR_API_BACK_PORTED(ver) \ + ((ver.wlc_ver_major == 12) && (ver.wlc_ver_minor == 2)) + +#define WLC_PMKDB_SUPPORT(ver) \ + ((ver.wlc_ver_major >= PMKDB_WLC_VER) || \ + NEW_PMK_MGR_API_BACK_PORTED(ver)) + +#define WLC_PMKLIST_V3_SUPPORT(ver) \ + ((ver.wlc_ver_major >= MIN_PMKID_LIST_V3_FW_MAJOR) || \ + NEW_PMK_MGR_API_BACK_PORTED(ver)) + /* wpa2 pmk list */ struct wl_pmk_list { pmkid_list_v3_t pmkids; @@ -1355,7 +1547,7 @@ typedef struct { #endif /* ESCAN_BUF_OVERFLOW_MGMT */ struct afx_hdl { - wl_af_params_t *pending_tx_act_frm; + wl_af_params_v1_t *pending_tx_act_frm; struct ether_addr tx_dst_addr; struct net_device *dev; struct work_struct work; @@ -1378,6 +1570,10 @@ struct parsed_ies { u32 wpa2_ie_len; const bcm_tlv_t *fils_ind_ie; u32 fils_ind_ie_len; + const bcm_tlv_t *rate_ie; + u32 rate_ie_len; + const bcm_tlv_t *ext_rate_ie; + u32 ext_rate_ie_len; }; #ifdef WL_SDO @@ -1500,18 +1696,14 @@ typedef struct wl_rssi_ant_mimo { } wl_rssi_ant_mimo_t; #endif /* SUPPORT_RSSI_SUM_REPORT */ -/* MBO-OCE prune event reason codes */ -#if defined(WL_MBO) || defined(WL_OCE) +/* prune event reason codes */ typedef enum wl_prune_evt_reason { - WIFI_PRUNE_UNSPECIFIED = 0, /* Unspecified event reason code */ - WIFI_PRUNE_ASSOC_RETRY_DELAY = 1, /* MBO assoc retry delay */ - WIFI_PRUNE_RSSI_ASSOC_REJ = 2 /* OCE RSSI-based assoc rejection */ + WIFI_PRUNE_UNSPECIFIED = 0, /* Unspecified event reason code */ + WIFI_PRUNE_ASSOC_RETRY_DELAY = 1, /* MBO assoc retry delay */ + WIFI_PRUNE_RSSI_ASSOC_REJ = 2, /* OCE RSSI-based assoc rejection */ + WIFI_PRUNE_CHANNEL_NOT_IN_VLP = 3, /* Prune AP due to Chanspec not in VLP cat */ + WIFI_PRUNE_WRONG_CCODE = 4, /* wrong country code */ } wl_prune_evt_reason_t; -#endif /* WL_MBO || WL_OCE */ - -#if defined(DHD_ENABLE_BIGDATA_LOGGING) -#define GET_BSS_INFO_LEN 90 -#endif /* DHD_ENABLE_BIGDATA_LOGGING */ #ifdef WL_MBO typedef struct wl_event_mbo wl_event_mbo_t; @@ -1519,11 +1711,7 @@ typedef struct wl_event_mbo_cell_nw_switch wl_event_mbo_cell_nw_switch_t; typedef struct wl_btm_event_type_data wl_btm_event_type_data_t; #endif /* WL_MBO */ -#if defined(WL_MBO) || defined(WL_OCE) typedef struct wl_bssid_prune_evt_info wl_bssid_pruned_evt_info_t; -#endif /* WL_MBO || WL_OCE */ - -#define WL_CCODE_LEN 2 #ifdef WL_NAN #ifdef WL_NANP2P @@ -1533,9 +1721,8 @@ typedef struct wl_bssid_prune_evt_info wl_bssid_pruned_evt_info_t; #endif /* WL_NAN2P */ #endif /* WL_NAN */ -#ifdef WL_IFACE_MGMT #define WL_IFACE_NOT_PRESENT -1 - +#ifdef WL_IFACE_MGMT typedef enum iface_conc_policy { WL_IF_POLICY_DEFAULT = 0, WL_IF_POLICY_FCFS = 1, @@ -1626,7 +1813,7 @@ typedef struct wl_loc_info { struct wireless_dev *wdev; /* interface on which listen is requested */ } wl_loc_info_t; -typedef enum wl_sar_modes { +typedef enum wl_sar_events { HEAD_SAR_BACKOFF_DISABLE = -1, HEAD_SAR_BACKOFF_ENABLE = 0, GRIP_SAR_BACKOFF_DISABLE, @@ -1635,8 +1822,63 @@ typedef enum wl_sar_modes { NR_mmWave_SAR_BACKOFF_ENABLE, NR_Sub6_SAR_BACKOFF_DISABLE, NR_Sub6_SAR_BACKOFF_ENABLE, - SAR_BACKOFF_DISABLE_ALL -} wl_sar_modes_t; + NR_MMWAVE_NR_SUB6_SAR_BACKOFF_DISABLE, + NR_MMWAVE_NR_SUB6_SAR_BACKOFF_ENABLE, + MHS_SAR_BACKOFF_DISABLE, + MHS_SAR_BACKOFF_ENABLE, + SAR_BACKOFF_DISABLE_ALL, + SAR_BACKOFF_EVENT_MAX +} wl_sar_events_t; + +#define SAR_MODE_DIS_ALL 0xff +#define SAR_MODE_BIT_HEAD 0x01 /* bit 0 */ +#define SAR_MODE_BIT_GRIP 0x02 /* bit 1 */ +#define SAR_MODE_BIT_NR_MW 0x04 /* bit 2 */ +#define SAR_MODE_BIT_NR_S6 0x08 /* bit 3 */ +#define SAR_MODE_BIT_NR_MWS6 0x0C /* bits 3:2 */ +#define SAR_MODE_BIT_MHS 0x40 /* bit 6 */ + +#define MAX_NUM_CONTROL 2 +typedef struct wl_sar_ctl_tbl { + wl_sar_events_t sar_evt_id; + int num_ctls; + struct { + bool enab; + uint8 setval; + } sar_mode[MAX_NUM_CONTROL]; +} wl_sar_ctl_tbl_t; + +typedef enum +{ + SAR_DISABLE = 0, + SAR_HEAD, /* bit 0 */ + SAR_GRIP, /* bit 1 */ + SAR_HEAD_GRIP, + SAR_NR_mW_ONLY, + SAR_NR_mW_HEAD, + SAR_NR_mW_GRIP, + SAR_NR_mW_HEAD_GRIP, + SAR_NR_SUB6_ONLY, + SAR_NR_SUB6_HEAD, + SAR_NR_SUB6_GRIP, + SAR_NR_SUB6_HEAD_GRIP, + SAR_NR_SUB6_mW_INVALID1, + SAR_NR_SUB6_mW_INVALID2, + SAR_NR_SUB6_mW_INVALID3, + SAR_NR_SUB6_mW_INVALID4, + SAR_BT = 16, /* bit 4 */ + SAR_HOTSPOT = 32 /* bit 5 */ +} sar_advance_modes; + +typedef enum wl_sar_sub6_bandinfo { + SAR_NR_SUB6_BANDINFO_DISABLE = -1, + SAR_NR_SUB6_BANDINFO_BAND2 = 2, + SAR_NR_SUB6_BANDINFO_BAND25 = 25, + SAR_NR_SUB6_BANDINFO_BAND41 = 41, + SAR_NR_SUB6_BANDINFO_BAND48 = 48, + SAR_NR_SUB6_BANDINFO_BAND66 = 66, + SAR_NR_SUB6_BANDINFO_BAND77 = 77 +} wl_sar_sub6_bandinfo_t; /* Pre selected Power scenarios to be applied from BDF file */ typedef enum { @@ -1650,6 +1892,15 @@ typedef enum { WIFI_POWER_SCENARIO_ON_BODY_BT = 5 } wifi_power_scenario; +#if defined(WL_SAR_TX_POWER) && defined(WL_SAR_TX_POWER_CONFIG) +#define SAR_CONFIG_SCENARIO_COUNT 100 +typedef struct wl_sar_config_info { + int8 scenario; + uint8 sar_tx_power_val; + int8 airplane_mode; +} wl_sar_config_info_t; +#endif /* WL_SAR_TX_POWER && WL_SAR_TX_POWER_CONFIG */ + /* Log timestamp */ #define LOG_TS(cfg, ts) cfg->tsinfo.ts = OSL_LOCALTIME_NS(); #define CLR_TS(cfg, ts) cfg->tsinfo.ts = 0; @@ -1679,6 +1930,8 @@ typedef struct wlcfg_assoc_info { s32 bssidx; u32 chan_cnt; chanspec_t chanspecs[MAX_ROAM_CHANNEL]; + bool auto_wpa_enabled; /* auto_wpa enabled for multi AKM */ + bool seamless_psk; /* Multi-AKMs needing seamless PSK */ } wlcfg_assoc_info_t; #define MAX_NUM_OF_ASSOCIATED_DEV 64 @@ -1694,6 +1947,80 @@ typedef struct wl_event_idx { u32 min_connect_idx; } wl_event_idx_t; +typedef struct { + u32 band; + u32 bw_cap; +} wl_bw_cap_t; + +#ifdef WL_USABLE_CHAN +#define USABLE_CHAN_MAX_SIZE 400 +typedef struct usable_channel { + wifi_channel freq; + wifi_channel_width_t width; + u32 iface_mode_mask; + chanspec_t chspec; /* used only for inter processing */ +} usable_channel_t; + +typedef struct usable_channel_info { + u32 band_mask; + u32 iface_mode_mask; + u32 filter_mask; + u32 max_size; + u32 size; + usable_channel_t *channels; +} usable_channel_info_t; +#endif /* WL_USABLE_CHAN */ + +#ifdef TPUT_DEBUG_DUMP +struct tput_debug_cmd_config { + char cmd[WLC_IOCTL_SMLEN]; + char sub_cmd[WLC_IOCTL_SMLEN]; +}; +#define TPUT_DBG_CMD_CONFIG_MAX 2 +#endif /* TPUT_DEBUG_DUMP */ + +#ifdef DEBUG_SETROAMMODE +typedef struct wl_roamoff_info { + uint64 roam_disable_time; + uint64 roam_enable_time; + uint roam_disable_rsn; + uint roam_enable_rsn; +} wl_roamoff_info_t; +#endif /* DEBUG_SETROAMMODE */ + +#ifdef CONFIG_COMPAT +typedef struct compat_buf_data { + u32 ver; /* version of struct */ + u32 len; /* Total len */ + /* size of each buffer in case of split buffers (0 - single buffer). */ + u32 buf_threshold; + u32 data_buf; /* array of user space buffer pointers. */ +} compat_buf_data_t; +#endif /* CONFIG_COMPAT */ + +#ifdef CUSTOM_EVENT_PM_WAKE +#define SOC_SLICE_MAIN 0 /* SLICE ID for 5GHz, 6GHz */ +#define SOC_SLICE_AUX 1 /* SLICE ID for 2GHz */ +#define SOC_MAX_SLICE 2 /* MAX slice in dongle */ + +typedef struct dpm_info { + uint32 dpm_prev_pmdur; /* pm_dur value at previous dpm event */ + uint32 dpm_cont_evt_cnt; /* continuous repeated dpm count */ + uint32 dpm_total_pkts; /* total tx/rx packet count */ +} dpm_info_t; +#endif /* CUSTOM_EVENT_PM_WAKE */ + +#ifdef LINKSTAT_EXT_SUPPORT +typedef struct scan_stat_cache_cores { + uint32 on_time_scan_aux; + uint32 on_time_roam_scan_aux; + uint32 on_time_pno_scan_aux; + uint32 on_time_scan_main; + uint32 on_time_roam_scan_main; + uint32 on_time_pno_scan_main; +} scan_stat_cache_cores_t; +#endif /* LINKSTAT_EXT_SUPPORT */ + /* private data of cfg80211 interface */ struct bcm_cfg80211 { struct wireless_dev *wdev; /* representing cfg cfg80211 device */ @@ -1715,8 +2042,8 @@ struct bcm_cfg80211 { struct mutex usr_sync; /* maily for up/down synchronization */ struct mutex if_sync; /* maily for iface op synchronization */ struct mutex scan_sync; /* scan sync from different scan contexts */ - wl_scan_results_t *bss_list; - wl_scan_results_t *scan_results; + wl_scan_results_v109_t *bss_list; + wl_scan_results_v109_t *scan_results; /* scan request object for internal purpose */ struct wl_scan_req *scan_req_int; @@ -1811,6 +2138,8 @@ struct bcm_cfg80211 { struct mutex event_sync; /* maily for up/down synchronization */ bool disable_roam_event; struct delayed_work pm_enable_work; + struct delayed_work recovery_work; + u32 recovery_state; #ifdef OEM_ANDROID struct workqueue_struct *event_workq; /* workqueue for event */ @@ -1824,10 +2153,6 @@ struct bcm_cfg80211 { vndr_ie_setbuf_t *ibss_vsie; /* keep the VSIE for IBSS */ int ibss_vsie_len; -#ifdef WLAIBSS - u32 aibss_txfail_pid; - u32 aibss_txfail_seq; -#endif /* WLAIBSS */ #ifdef WL_RELMCAST u32 rmc_event_pid; u32 rmc_event_seq; @@ -1861,17 +2186,11 @@ struct bcm_cfg80211 { s32 tdls_mgmt_freq; #endif /* WLTDLS */ bool need_wait_afrx; -#ifdef QOS_MAP_SET +#if defined(QOS_MAP_SET) || defined(WL_CUSTOM_MAPPING_OF_DSCP) uint8 *up_table; /* user priority table, size is UP_TABLE_MAX */ -#endif /* QOS_MAP_SET */ +#endif /* QOS_MAP_SET || WL_CUSTOM_MAPPING_OF_DSCP */ struct ether_addr last_roamed_addr; bool rcc_enabled; /* flag for Roam channel cache feature */ -#if defined(DHD_ENABLE_BIGDATA_LOGGING) - char bss_info[GET_BSS_INFO_LEN]; - wl_event_msg_t event_auth_assoc; - u32 assoc_reject_status; - u32 roam_count; -#endif /* DHD_ENABLE_BIGDATA_LOGGING */ u16 ap_oper_channel; #if defined(SUPPORT_RANDOM_MAC_SCAN) bool random_mac_enabled; @@ -1921,10 +2240,6 @@ struct bcm_cfg80211 { wl_bad_ap_mngr_t bad_ap_mngr; #endif /* WL_BAM */ -#ifdef BIGDATA_SOFTAP - struct wl_ap_sta_info *ap_sta_info; -#endif /* BIGDATA_SOFTAP */ - uint8 scanmac_enabled; bool scanmac_config; #ifdef WL_BCNRECV @@ -1936,7 +2251,7 @@ struct bcm_cfg80211 { uint8 static_ndev_state[DHD_MAX_STATIC_IFS]; bool hal_started; wl_wlc_version_t wlc_ver; - bool scan_params_v2; + u8 scan_params_ver; #ifdef SUPPORT_AP_BWCTRL u32 bw_cap_5g; #endif /* SUPPORT_AP_BWCTRL */ @@ -1949,7 +2264,11 @@ struct bcm_cfg80211 { int ncho_mode; int ncho_band; #ifdef WL_SAR_TX_POWER - wifi_power_scenario wifi_tx_power_mode; + int8 wifi_tx_power_mode; +#if defined(WL_SAR_TX_POWER_CONFIG) + wl_sar_config_info_t *sar_config_info; + int sar_config_info_cnt; +#endif /* WL_SAR_TX_POWER_CONFIG */ #endif /* WL_SAR_TX_POWER */ struct mutex connect_sync; /* For assoc/resssoc state sync */ wl_ctx_tsinfo_t tsinfo; @@ -1959,14 +2278,77 @@ struct bcm_cfg80211 { u32 join_iovar_ver; struct delayed_work ap_work; /* AP linkup timeout handler */ wl_event_idx_t eidx; /* event state tracker */ -#if defined (WL_SCHED_SCAN) && defined (SCHED_SCAN_DELAYED_WORK) + u32 halpid; +#ifdef WL_THERMAL_MITIGATION + u32 thermal_mode; +#endif /* WL_THERMAL_MITIGATION */ + uint16 actframe_params_ver; + struct ether_addr af_randmac; + bool randomized_gas_tx; + u8 country[WLC_CNTRY_BUF_SZ]; + u8 latency_mode; +#ifdef WL_MBO_HOST + void *btmreq; + uint16 btmreq_len; + uint8 btmreq_token; +#endif /* WL_MBO_HOST */ +#ifdef WL_CELLULAR_CHAN_AVOID + void *cellavoid_info; + struct delayed_work csa_delayed_work; +#endif /* WL_CELLULAR_CHAN_AVOID */ +#ifdef TPUT_DEBUG_DUMP + struct tput_debug_cmd_config tput_dbg_cmds[TPUT_DBG_CMD_CONFIG_MAX]; + struct delayed_work tput_debug_work; + bool tput_dbg_mode_enable; + bool tput_dbg_cmd_config; + uint8 tput_dbg_ifindex; +#endif /* TPUT_DEBUG_DUMP */ +#ifdef DEBUG_SETROAMMODE + wl_roamoff_info_t *roamoff_info; +#endif /* DEBUG_SETROAMMODE */ +#ifdef DHD_CLEANUP_KEEP_ALIVE + uint8 mkeep_alive_avail; +#endif /* DHD_CLEANUP_KEEP_ALIVE */ +#ifdef WL_SCHED_SCAN struct delayed_work sched_scan_stop_work; -#endif +#endif /* WL_SCHED_SCAN */ + struct net_device *inet_ndev; + struct wireless_dev *nmi_wdev; /* representing cfg cfg80211 device for NAN NMI */ + struct net_device *nmi_ndev; /* reference to NAN NMI interface */ +#if defined(DHD_DSCP_POLICY) + void *dscp_policy_info; +#endif /* defined(DHD_DSCP_POLICY) */ + bool disable_fw_roam; + bool soft_suspend; + bool disable_dtim_in_suspend; + uint8 suspend_bcn_li_dtim; + bool max_dtim_enable; +#ifdef LINKSTAT_EXT_SUPPORT + scan_stat_cache_cores_t scan_stat_cores; +#endif /* LINKSTAT_EXT_SUPPORT */ +#ifdef CUSTOM_EVENT_PM_WAKE + dpm_info_t dpm_info[SOC_MAX_SLICE]; +#endif /* CUSTOM_EVENT_PM_WAKE */ + u8 stas_associated; + u8 ap_cnt; +#ifdef CONFIG_SILENT_ROAM + bool sroam_turn_on; + bool sroamed; +#endif /* CONFIG_SILTENT_ROAM */ + uint32 roam_allowed_band; /* roam allow band in order to purne roam candidate */ + uint8 num_radios; /* number of active radios */ + uint32 ap_bw_limit; + uint32 ap_bw_chspec; + bool frameburst_disabled; #ifdef WL_P2P_6G bool p2p_6g_enabled; /* P2P 6G support enabled */ #endif /* WL_P2P_6G */ - u32 halpid; - u8 country[WLC_CNTRY_BUF_SZ]; +#ifdef BCMDBUS + bool bus_resuming; +#endif /* BCMDBUS */ +#ifdef WL_ROAM_WAR + struct ether_addr roaming_bssid; +#endif /* WL_ROAM_WAR */ #if defined(RSSIAVG) wl_rssi_cache_ctrl_t g_rssi_cache_ctrl; wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl; @@ -2034,17 +2416,104 @@ typedef struct wl_wips_event_info { int16 deauth_RSSI; } wl_wips_event_info_t; +/* defined for hw_mode in hostapd.conf */ +enum hostapd_hw_mode { + HOSTAPD_MODE_IEEE80211B, + HOSTAPD_MODE_IEEE80211G, + HOSTAPD_MODE_IEEE80211A, + HOSTAPD_MODE_IEEE80211AD, + HOSTAPD_MODE_IEEE80211ANY, + NUM_HOSTAPD_MODES +}; + +typedef struct drv_acs_params { + enum hostapd_hw_mode hw_mode; + u32 band; /* band derived from hw_mode */ + u32 ht_enabled; + u32 ht40_enabled; + u32 vht_enabled; + u32 he_enabled; + u16 ch_width; + unsigned int ch_list_len; + const u8 *ch_list; + const u32 *freq_list; + u32 freq_bands; /* band derived from freq list */ + chanspec_t scc_chspec; +} drv_acs_params_t; + +#define IS_5G_APCS_CHANNEL(channel) ((channel == 149) || \ + (channel == 153) || \ + (channel == 157) || \ + (channel == 161)) + +#ifdef WL_SOFTAP_ACS +/* Added for HOSTAPD required ACS action */ +#define APCS_MAX_RETRY 10 +#define APCS_DEFAULT_2G_CH 1 +#define APCS_DEFAULT_5G_CH 149 + +enum wl_vendor_attr_acs_offload { + BRCM_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0, + BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ, + BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ, + BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL, + BRCM_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL, + BRCM_VENDOR_ATTR_ACS_HW_MODE, + BRCM_VENDOR_ATTR_ACS_HT_ENABLED, + BRCM_VENDOR_ATTR_ACS_HT40_ENABLED, + BRCM_VENDOR_ATTR_ACS_VHT_ENABLED, + BRCM_VENDOR_ATTR_ACS_CHWIDTH, + BRCM_VENDOR_ATTR_ACS_CH_LIST, + BRCM_VENDOR_ATTR_ACS_FREQ_LIST, + + BRCM_VENDOR_ATTR_ACS_LAST +}; + +typedef struct acs_selected_channels { + u32 pri_freq; /* save slelcted primary frequency */ + u32 sec_freq; /* save slelcted secondary frequency */ + u8 vht_seg0_center_ch; + u8 vht_seg1_center_ch; + u16 ch_width; + enum hostapd_hw_mode hw_mode; +} acs_selected_channels_t; + +typedef struct acs_delay_work { + struct delayed_work acs_delay_work; + u32 init_flag; + struct net_device *ndev; + chanspec_t ch_chosen; + drv_acs_params_t parameter; +} acs_delay_work_t; +#endif /* WL_SOFTAP_ACS */ + +/* Struct used to populate fields needed for +* wsec_info passphrase iovar config.. +* Passphrase can be configured per +* 1. SSID +* 2. SSID + AKM +* 3. BSSID +*/ +typedef struct wl_config_passphrase { + u8* passphrase; + u16 passphrase_len; + const u8 *ssid; + u8 ssid_len; + u8 *bssid; + u32 akm; +} wl_config_passphrase_t; + s32 wl_iftype_to_mode(wl_iftype_t iftype); #define BCM_LIST_FOR_EACH_ENTRY_SAFE(pos, next, head, member) \ list_for_each_entry_safe((pos), (next), (head), member) extern int ioctl_version; -static inline wl_bss_info_t -*next_bss(wl_scan_results_t *list, wl_bss_info_t *bss) +static inline wl_bss_info_v109_t +*next_bss(wl_scan_results_v109_t *list, wl_bss_info_v109_t *bss) { return bss = bss ? - (wl_bss_info_t *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info; + (wl_bss_info_v109_t *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info; } static inline void @@ -2066,12 +2535,10 @@ wl_probe_wdev_all(struct bcm_cfg80211 *cfg) } static inline struct net_info * -wl_get_netinfo_by_fw_idx(struct bcm_cfg80211 *cfg, s32 bssidx, u8 ifidx) +_wl_get_netinfo_by_fw_idx(struct bcm_cfg80211 *cfg, s32 bssidx, u8 ifidx) { struct net_info *_net_info, *next, *info = NULL; - unsigned long int flags; - WL_CFG_NET_LIST_SYNC_LOCK(&cfg->net_list_sync, flags); GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) { GCC_DIAGNOSTIC_POP(); @@ -2081,7 +2548,19 @@ wl_get_netinfo_by_fw_idx(struct bcm_cfg80211 *cfg, s32 bssidx, u8 ifidx) break; } } + return info; +} + +static inline struct net_info * +wl_get_netinfo_by_fw_idx(struct bcm_cfg80211 *cfg, s32 bssidx, u8 ifidx) +{ + unsigned long int flags; + struct net_info *info = NULL; + + WL_CFG_NET_LIST_SYNC_LOCK(&cfg->net_list_sync, flags); + info = _wl_get_netinfo_by_fw_idx(cfg, bssidx, ifidx); WL_CFG_NET_LIST_SYNC_UNLOCK(&cfg->net_list_sync, flags); + return info; } @@ -2117,6 +2596,17 @@ wl_dealloc_netinfo_by_wdev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev) MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2); bss->wps_ie = NULL; } + + if (_net_info->passphrase_cfg) { + MFREE(cfg->osh, _net_info->passphrase_cfg, + _net_info->passphrase_cfg_len); + _net_info->passphrase_cfg = NULL; + } + + if (_net_info->qos_up_table) { + MFREE(cfg->osh, _net_info->qos_up_table, UP_TABLE_MAX); + _net_info->qos_up_table = NULL; + } list_del(&_net_info->list); cfg->iface_cnt--; MFREE(cfg->osh, _net_info, sizeof(struct net_info)); @@ -2147,13 +2637,15 @@ wl_alloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev, * already present which shouldn't have been the case. * Attempt recovery. */ - WL_ERR(("Duplicate entry for bssidx=%d ifidx=%d present." - " Can't add new entry\n", bssidx, ifidx)); - wl_probe_wdev_all(cfg); + if (bssidx != (u8)WL_INVALID) { + WL_ERR(("**Duplicate entry for bssidx=%d ifidx=%d present." + " Can't add new entry\n", bssidx, ifidx)); + wl_probe_wdev_all(cfg); #ifdef DHD_DEBUG - ASSERT(0); + ASSERT(0); #endif /* DHD_DEBUG */ - return -EINVAL; + return -EINVAL; + } } if (cfg->iface_cnt == IFACE_MAX_CNT) return -ENOMEM; @@ -2170,6 +2662,8 @@ wl_alloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev, _net_info->roam_off = WL_INVALID; _net_info->bssidx = bssidx; _net_info->ifidx = ifidx; + _net_info->ps_managed = FALSE; + _net_info->ps_managed_start_ts = 0; WL_CFG_NET_LIST_SYNC_LOCK(&cfg->net_list_sync, flags); cfg->iface_cnt++; list_add(&_net_info->list, &cfg->net_list); @@ -2224,6 +2718,7 @@ wl_delete_all_netinfo(struct bcm_cfg80211 *cfg) cfg->iface_cnt = 0; WL_CFG_NET_LIST_SYNC_UNLOCK(&cfg->net_list_sync, flags); } + static inline u32 wl_get_status_all(struct bcm_cfg80211 *cfg, s32 status) @@ -2243,6 +2738,7 @@ wl_get_status_all(struct bcm_cfg80211 *cfg, s32 status) WL_CFG_NET_LIST_SYNC_UNLOCK(&cfg->net_list_sync, flags); return cnt; } + static inline void wl_set_status_all(struct bcm_cfg80211 *cfg, s32 status, u32 op) { @@ -2275,6 +2771,55 @@ wl_set_status_all(struct bcm_cfg80211 *cfg, s32 status, u32 op) } WL_CFG_NET_LIST_SYNC_UNLOCK(&cfg->net_list_sync, flags); } + +static inline void +wl_track_if_states(struct bcm_cfg80211 *cfg, struct net_info *_net_info, + s32 status, bool set) +{ + struct net_device *ndev = _net_info->ndev; + enum nl80211_iftype iftype = ndev->ieee80211_ptr->iftype; + + switch (iftype) { + case NL80211_IFTYPE_STATION: + if (status == WL_STATUS_CONNECTED) { + if (set) { + if (test_bit(status, &_net_info->sme_state)) { + /* bit already set. ROAM case. don't incr */ + return; + } + cfg->stas_associated++; + } else { + /* clearing of states may happen from multiple places + * count only once + */ + if (!test_bit(status, &_net_info->sme_state)) { + /* bit not set. nothing to clear */ + return; + } + + if (cfg->stas_associated) { + cfg->stas_associated--; + } + } + WL_DBG_MEM(("stas_associated:%d\n", cfg->stas_associated)); + } + break; + case NL80211_IFTYPE_AP: + if (status == WL_STATUS_AP_CREATED) { + if (set) { + cfg->ap_cnt++; + } else { + cfg->ap_cnt--; + } + WL_DBG(("ap_cnt:%d\n", cfg->ap_cnt)); + } + break; + default: + /* Do nothing for other roles. Add cases as and when reqd */ + break; + } +} + static inline void wl_set_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status, struct net_device *ndev, u32 op) @@ -2305,6 +2850,7 @@ wl_set_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status, * will be nested calls */ WL_CFG_NET_LIST_SYNC_UNLOCK(&cfg->net_list_sync, flags); + wl_track_if_states(cfg, _net_info, status, TRUE); set_bit(status, &_net_info->sme_state); if (cfg->state_notifier && test_bit(status, &(cfg->interrested_state))) @@ -2316,6 +2862,7 @@ wl_set_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status, * will be nested calls */ WL_CFG_NET_LIST_SYNC_UNLOCK(&cfg->net_list_sync, flags); + wl_track_if_states(cfg, _net_info, status, FALSE); clear_bit(status, &_net_info->sme_state); if (cfg->state_notifier && test_bit(status, &(cfg->interrested_state))) @@ -2456,6 +3003,7 @@ wl_get_profile_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) WL_CFG_NET_LIST_SYNC_UNLOCK(&cfg->net_list_sync, flags); return prof; } + static inline struct net_info * wl_get_netinfo_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) { @@ -2476,12 +3024,10 @@ wl_get_netinfo_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) } static inline struct net_info * -wl_get_netinfo_by_wdev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev) +_wl_get_netinfo_by_wdev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev) { struct net_info *_net_info, *next, *info = NULL; - unsigned long int flags; - WL_CFG_NET_LIST_SYNC_LOCK(&cfg->net_list_sync, flags); GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) { GCC_DIAGNOSTIC_POP(); @@ -2490,6 +3036,17 @@ wl_get_netinfo_by_wdev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev) break; } } + return info; +} + +static inline struct net_info * +wl_get_netinfo_by_wdev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev) +{ + struct net_info *info = NULL; + unsigned long int flags; + + WL_CFG_NET_LIST_SYNC_LOCK(&cfg->net_list_sync, flags); + info = _wl_get_netinfo_by_wdev(cfg, wdev); WL_CFG_NET_LIST_SYNC_UNLOCK(&cfg->net_list_sync, flags); return info; } @@ -2503,11 +3060,6 @@ wl_iftype_to_str(int wl_iftype) case (WL_IF_TYPE_AP): return "WL_IF_TYPE_AP"; -#ifdef WLAWDL - case (WL_IF_TYPE_AWDL): - return "WL_IF_TYPE_AWDL"; -#endif /* WLAWDL */ - case (WL_IF_TYPE_NAN_NMI): return "WL_IF_TYPE_NAN_NMI"; case (WL_IF_TYPE_NAN): @@ -2545,14 +3097,39 @@ wl_iftype_to_str(int wl_iftype) #define ndev_to_wdev(ndev) (ndev->ieee80211_ptr) #define wdev_to_ndev(wdev) (wdev->netdev) -#ifdef WL_BLOCK_P2P_SCAN_ON_STA -#define IS_P2P_IFACE(wdev) (wdev && \ - ((wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) || \ - (wdev->iftype == NL80211_IFTYPE_P2P_GO) || \ - (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT))) -#endif /* WL_BLOCK_P2P_SCAN_ON_STA */ +#ifdef WL_NMI_IF +#define bcmcfg_to_nmi_ndev(cfg) (cfg->nmi_ndev) +#define bcmcfg_to_nmi_wdev(cfg) (cfg->nmi_wdev) +#else +#define bcmcfg_to_nmi_ndev(cfg) bcmcfg_to_prmry_ndev(cfg) +#define bcmcfg_to_nmi_wdev(cfg) bcmcfg_to_prmry_wdev(cfg) +#endif /* WL_NMI_IF */ +#if defined(WL_CFG80211_P2P_DEV_IF) +#define IS_P2P_IFACE(wdev) (wdev && \ + ((wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) || \ + (wdev->iftype == NL80211_IFTYPE_P2P_GO) || \ + (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT))) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) +#define IS_P2P_IFACE(ieee80211_ptr) (ieee80211_ptr && \ + ((ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_DEVICE) || \ + (ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) || \ + (ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT))) +#else +#define IS_P2P_IFACE(ieee80211_ptr) (ieee80211_ptr && \ + ((ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) || \ + (ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT))) +#endif /* WL_CFG80211_P2P_DEV_IF */ + +/* Initial registered ndev on driver load */ #define IS_PRIMARY_NDEV(cfg, ndev) (ndev == bcmcfg_to_prmry_ndev(cfg)) + +/* Primary link interface: used for internet traffic */ +#ifdef WL_DUAL_STA +#define IS_INET_LINK_NDEV(cfg, ndev) (ndev == cfg->inet_ndev) +#else +#define IS_INET_LINK_NDEV(cfg, ndev) (ndev == bcmcfg_to_prmry_ndev(cfg)) +#endif /* WL_DUAL_STA */ #define IS_STA_IFACE(wdev) (wdev && \ (wdev->iftype == NL80211_IFTYPE_STATION)) @@ -2673,6 +3250,7 @@ wl_iftype_to_str(int wl_iftype) #define IS_AKM_SUITE_FT(sec) ({BCM_REFERENCE(sec); FALSE;}) #endif /* WLFBT */ +#define IS_AKM_SUITE_SAE_FT(sec) (sec->wpa_auth == WLAN_AKM_SUITE_FT_OVER_SAE) #define IS_AKM_SUITE_CCKM(sec) ({BCM_REFERENCE(sec); FALSE;}) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) @@ -2685,13 +3263,19 @@ wl_iftype_to_str(int wl_iftype) #define STA_INFO_BIT(info) (STATION_ ## info) #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) && defined(BCMSUP_4WAY_HANDSHAKE) +/* Enable PSK key mgmt offload */ +#define WL_PSK_OFFLOAD +#define WL_SUPP_PMK_LEN 32u +#endif /* LINUX_VERSION_CODE >= 4, 13, 0 && BCMSUP_4WAY_HANDSHAKE */ + extern s32 wl_cfg80211_attach(struct net_device *ndev, void *context); extern void wl_cfg80211_detach(struct bcm_cfg80211 *cfg); extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, void *data); extern s32 wl_cfg80211_handle_critical_events(struct bcm_cfg80211 *cfg, - struct wireless_dev *wdev, const wl_event_msg_t * e); + struct wireless_dev *wdev, const wl_event_msg_t * e, void *data); void wl_cfg80211_set_parent_dev(void *dev); struct device *wl_cfg80211_get_parent_dev(void); @@ -2743,9 +3327,12 @@ extern s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int le extern s32 wl_cfg80211_set_p2p_resp_ap_chn(struct net_device *net, s32 enable); #endif /* P2PLISTEN_AP_SAMECHN */ +#if defined(OEM_ANDROID) /* btcoex functions */ void* wl_cfg80211_btcoex_init(struct net_device *ndev); void wl_cfg80211_btcoex_deinit(void); +void wl_cfg80211_btcoex_kill_handler(void); +#endif /* defined(OEM_ANDROID) */ extern chanspec_t wl_chspec_from_legacy(chanspec_t legacy_chspec); extern chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec); @@ -2758,9 +3345,11 @@ extern s32 wl_cfg80211_pause_sdo(struct net_device *dev, struct bcm_cfg80211 *cf extern s32 wl_cfg80211_resume_sdo(struct net_device *dev, struct bcm_cfg80211 *cfg); #endif + +#define CHANINFO_LIST_BUF_SIZE (1024 * 4) + #ifdef WL_SUPPORT_AUTO_CHANNEL #define CHANSPEC_BUF_SIZE 2048 -#define CHANINFO_LIST_BUF_SIZE (1024 * 4) #define CHAN_SEL_IOCTL_DELAY 300 #define CHAN_SEL_RETRY_COUNT 15 #define CHANNEL_IS_RADAR(channel) (((channel & WL_CHAN_RADAR) || \ @@ -2779,6 +3368,9 @@ void wl_cfg80211_generate_mac_addr(struct ether_addr *ea_addr); extern s32 wl_mode_to_nl80211_iftype(s32 mode); int wl_cfg80211_do_driver_init(struct net_device *net); void wl_cfg80211_enable_trace(u32 level); +void wl_cfg80211_enable_log_trace(bool set, u32 level); +extern uint32 wl_cfg80211_get_print_level(void); +extern uint32 wl_cfg80211_get_log_level(void); extern s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify); extern s32 wl_cfg80211_if_is_group_owner(void); extern chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec); @@ -2803,10 +3395,6 @@ extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev, extern void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac); extern void wl_cfg80211_update_power_mode(struct net_device *dev); extern void wl_terminate_event_handler(struct net_device *dev); -#if defined(DHD_ENABLE_BIGDATA_LOGGING) -extern s32 wl_cfg80211_get_bss_info(struct net_device *dev, char* cmd, int total_len); -extern s32 wl_cfg80211_get_connect_failed_status(struct net_device *dev, char* cmd, int total_len); -#endif /* DHD_ENABLE_BIGDATA_LOGGING */ extern struct bcm_cfg80211 *wl_get_cfg(struct net_device *ndev); extern s32 wl_cfg80211_set_if_band(struct net_device *ndev, int band); extern s32 wl_cfg80211_set_country_code(struct net_device *dev, char *country_code, @@ -2824,9 +3412,6 @@ extern int wl_cfg80211_wips_event_ext(wl_wips_event_info_t *wips_event); extern void wl_cfg80211_ibss_vsie_set_buffer(struct net_device *dev, vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len); extern s32 wl_cfg80211_ibss_vsie_delete(struct net_device *dev); -#ifdef WLAIBSS -extern void wl_cfg80211_set_txfail_pid(struct net_device *dev, int pid); -#endif /* WLAIBSS */ #ifdef WL_RELMCAST extern void wl_cfg80211_set_rmc_pid(struct net_device *dev, int pid); #endif /* WL_RELMCAST */ @@ -2842,14 +3427,13 @@ extern int wl_cfg80211_get_fbt_key(struct net_device *dev, uint8 *key, int total extern u8 wl_get_action_category(void *frame, u32 frame_len); extern int wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action); -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST struct net_device *wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg); -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + +#define IOCTL_RETRY_COUNT 5 +#define CHAN_NOISE_DUMMY -80 #ifdef WL_SUPPORT_ACS #define ACS_MSRMNT_DELAY 1000 /* dump_obss delay in ms */ -#define IOCTL_RETRY_COUNT 5 -#define CHAN_NOISE_DUMMY -80 #define OBSS_TOKEN_IDX 15 #define IBSS_TOKEN_IDX 15 #define TX_TOKEN_IDX 14 @@ -2858,6 +3442,17 @@ struct net_device *wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *c #define IDLE_TOKEN_IDX 12 #endif /* WL_SUPPORT_ACS */ +#ifdef WL_UNII4_CHAN +#define IS_5G_UNII4_165_CHANNEL(chspec) (CHSPEC_IS5G(chspec) && \ + (wf_chspec_primary20_chan(chspec) == 165)) +#define UINII4_169 169 +#define UINII4_173 173 +#define UINII4_177 177 +#define IS_UNII4_CHANNEL(channel) ((channel == UINII4_169) || \ + (channel == UINII4_173) || \ + (channel == UINII4_177)) +#endif /* WL_UNII4_CHAN */ + #ifdef BCMWAPI_WPI #define is_wapi(cipher) (cipher == WLAN_CIPHER_SUITE_SMS4) ? 1 : 0 #endif /* BCMWAPI_WPI */ @@ -2939,9 +3534,9 @@ do { \ } \ } while (0) -#ifdef QOS_MAP_SET +#if defined(QOS_MAP_SET) || defined(WL_CUSTOM_MAPPING_OF_DSCP) extern uint8 *wl_get_up_table(dhd_pub_t * dhdp, int idx); -#endif /* QOS_MAP_SET */ +#endif /* QOS_MAP_SET || WL_CUSTOM_MAPPING_OF_DSCP */ #define P2PO_COOKIE 65535 u64 wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 *cfg); @@ -2955,7 +3550,7 @@ int wl_set_rssi_logging(struct net_device *dev, void *param); int wl_get_rssi_per_ant(struct net_device *dev, char *ifname, char *peer_mac, void *param); #endif /* SUPPORT_RSSI_SUM_REPORT */ struct wireless_dev * wl_cfg80211_add_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev, - wl_iftype_t wl_iftype, const char *name, u8 *mac); + wl_iftype_t wl_iftype, const char *name, const u8 *mac); extern s32 wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev, struct wireless_dev *wdev, char *name); s32 _wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev, @@ -2976,10 +3571,12 @@ extern struct wireless_dev *wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 const char *name); struct net_device* wl_get_netdev_by_name(struct bcm_cfg80211 *cfg, char *ifname); extern int wl_cfg80211_ifstats_counters(struct net_device *dev, wl_if_stats_t *if_stats); +extern int wl_cfg80211_if_infra_enh_ifstats_counters(struct net_device *dev, + wl_if_infra_enh_stats_v2_t *if_infra_enh_stats); extern s32 wl_cfg80211_set_dbg_verbose(struct net_device *ndev, u32 level); extern int wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 * cfg); extern int wl_cfg80211_set_frameburst(struct bcm_cfg80211 *cfg, bool enable); -extern int wl_cfg80211_determine_p2p_rsdb_scc_mode(struct bcm_cfg80211 *cfg); +extern int wl_cfg80211_determine_rsdb_scc_mode(struct bcm_cfg80211 *cfg); extern uint8 wl_cfg80211_get_bus_state(struct bcm_cfg80211 *cfg); #ifdef WL_WPS_SYNC void wl_handle_wps_states(struct net_device *ndev, u8 *dump_data, u16 len, bool direction); @@ -2988,9 +3585,6 @@ extern int wl_features_set(u8 *array, uint8 len, u32 ftidx); extern void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item); extern s32 wl_cfg80211_sup_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *event, void *data); -#ifdef CUSTOMER_HW4_DEBUG -extern void wl_scan_timeout_dbg_clear(void); -#endif /* CUSTOMER_HW4_DEBUG */ extern s32 cfg80211_to_wl_iftype(uint16 type, uint16 *role, uint16 *mode); extern s32 wl_cfg80211_net_attach(struct net_device *primary_ndev); extern void wl_print_verinfo(struct bcm_cfg80211 *cfg); @@ -3004,10 +3598,11 @@ bool wl_cfg80211_check_in_progress(struct net_device *dev); extern int wl_android_set_ncho_mode(struct net_device *dev, int mode); #endif /* WES_SUPPORT */ #ifdef KEEP_ALIVE -extern int wl_cfg80211_start_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id, - uint16 ether_type, uint8 *ip_pkt, uint16 ip_pkt_len, uint8* src_mac_addr, - uint8* dst_mac_addr, uint32 period_msec); -extern int wl_cfg80211_stop_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id); +extern int wl_cfg80211_start_mkeep_alive(struct net_device *ndev, struct bcm_cfg80211 *cfg, + uint8 mkeep_alive_id, uint16 ether_type, uint8 *ip_pkt, uint16 ip_pkt_len, + uint8* src_mac_addr, uint8* dst_mac_addr, uint32 period_msec); +extern int wl_cfg80211_stop_mkeep_alive(struct net_device *ndev, struct bcm_cfg80211 *cfg, + uint8 mkeep_alive_id); #endif /* KEEP_ALIVE */ extern s32 wl_cfg80211_handle_macaddr_change(struct net_device *dev, u8 *macaddr); @@ -3020,7 +3615,7 @@ extern s32 wl_cfg80211_suspend(struct bcm_cfg80211 *cfg); bool wl_cfg80211_is_dpp_frame(void *frame, u32 frame_len); const char *get_dpp_pa_ftype(enum wl_dpp_ftype ftype); bool wl_cfg80211_is_dpp_gas_action(void *frame, u32 frame_len); -extern bool wl_cfg80211_find_gas_subtype(u8 subtype, u16 adv_id, u8* data, u32 len); +extern bool wl_cfg80211_find_gas_subtype(u8 subtype, u16 adv_id, u8* data, s32 len); #ifdef ESCAN_CHANNEL_CACHE extern void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver); #endif /* ESCAN_CHANNEL_CACHE */ @@ -3029,10 +3624,14 @@ extern void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver); extern int wl_cfgnan_get_stats(struct bcm_cfg80211 *cfg); #endif /* WL_NAN */ -#ifdef WL_SAE extern s32 wl_cfg80211_set_wsec_info(struct net_device *dev, uint32 *data, uint16 data_len, int tag); -#endif /* WL_SAE */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +#define CH_DEFAULT_FLAGS IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_NO_20MHZ +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */ +#define CH_DEFAULT_FLAGS IEEE80211_CHAN_DISABLED +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) */ + #define WL_CHANNEL_ARRAY_INIT(band_chan_arr) \ do { \ u32 arr_size, k; \ @@ -3042,6 +3641,15 @@ do { \ } \ } while (0) +#define WL_CHANNEL_COPY_FLAG(band_chan_arr) \ +do { \ + u32 arr_size, k; \ + arr_size = ARRAYSIZE(band_chan_arr); \ + for (k = 0; k < arr_size; k++) { \ + band_chan_arr[k].orig_flags = band_chan_arr[k].flags; \ + } \ +} while (0) + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) #define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(wiphy, bss); #else @@ -3059,11 +3667,13 @@ static inline s32 wl_rssi_offset(s32 rssi) #else #define wl_rssi_offset(x) x #endif +extern u8 wl_chanspec_to_host_bw_map(chanspec_t cur_chanspec); extern int wl_channel_to_frequency(u32 chan, chanspec_band_t band); extern int wl_cfg80211_config_rsnxe_ie(struct bcm_cfg80211 *cfg, struct net_device *dev, const u8 *parse, u32 len); extern bool dhd_force_country_change(struct net_device *dev); extern u32 wl_dbg_level; +extern u32 wl_log_level; extern u32 wl_cfg80211_debug_data_dump(struct net_device *dev, u8 *buf, u32 buf_len); extern void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable); @@ -3087,10 +3697,145 @@ extern s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, extern s32 wl_handle_auth_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, const wl_event_msg_t *e, void *data); #endif /* WL_CLIENT_SAE */ -#ifdef CUSTOMER_HW6 -extern bool wl_customer6_legacy_chip_check(struct bcm_cfg80211 *cfg, - struct net_device *ndev); -#endif /* CUSTOMER_HW6 */ +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT +extern int wl_cfg80211_alert(struct net_device *dev); +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ +extern void +wl_cfg80211_set_okc_pmkinfo(struct bcm_cfg80211 *cfg, struct net_device *dev, + wsec_pmk_t pmk, bool validate_sec); + +#ifdef AUTH_ASSOC_STATUS_EXT +typedef enum auth_assoc_status_ext { + /* WLC_E_SET_SSID */ + AUTH_ASSOC_STATUS_NO_NETWORKS = 1025, + /* WLC_E_AUTH */ + AUTH_ASSOC_STATUS_OPEN_AUTH_NOACK, + AUTH_ASSOC_STATUS_OPEN_AUTH_NORESP, + AUTH_ASSOC_STATUS_OPEN_AUTH_FAIL, + AUTH_ASSOC_STATUS_SAE_AUTH_NOACK, + AUTH_ASSOC_STATUS_SAE_AUTH_NORESP, + AUTH_ASSOC_STATUS_SAE_AUTH_FAIL, + /* WLC_E_ASSOC */ + AUTH_ASSOC_STATUS_ASSOC_NOACK, + AUTH_ASSOC_STATUS_ASSOC_NORESP, + AUTH_ASSOC_STATUS_ASSOC_FAIL, + AUTH_ASSOC_STATUS_CHAN_NOVLP = 2049, + AUTH_ASSOC_STATUE_MAX /* MAX Status Code */ +} auth_assoc_status_ext_t; +extern s32 wl_get_auth_assoc_status_ext(struct bcm_cfg80211 *cfg, + struct net_device *ndev, const wl_event_msg_t *e); +#endif /* AUTH_ASSOC_STATUS_EXT */ + +s32 wl_cfg80211_set_netinfo_passphrase(struct bcm_cfg80211 *cfg, + struct net_device *ndev, const u8* passphrase, u8 len); +s32 wl_cfg80211_config_passphrase(struct bcm_cfg80211 *cfg, + struct net_device *ndev, wl_config_passphrase_t *pp_config); +chanspec_t wl_cfg80211_get_sta_chanspec(struct bcm_cfg80211 *cfg); + +#ifdef WL_UWB_COEX +#define UWB_COEX_CH_MAP_NUM 64 + +uint16 wl_cfg_uwb_coex_get_ch_val(const int idx); +int wl_cfg_uwb_coex_enable(struct net_device *dev, int enable, int start_ch, int end_ch); +int wl_cfg_uwb_coex_execute_ioctl(struct net_device *dev, struct bcm_cfg80211 *cfg, + const uint8 is_set, uint16 id, void *data, uint16 data_len, + uint8 *resp_buf, uint16 resp_buf_xz); +#endif /* WL_UWB_COEX */ + +#ifdef DEBUG_SETROAMMODE +#define CMD_ROAMOFF "roam_off" +typedef enum wl_roamoff_dbg_reason { + SET_ROAM_RF_TEST = 0, + SET_ROAM_DHD_SUSPEND, + SET_ROAM_PREINIT, + SET_ROAM_FILS_TOGGLE, + SET_ROAM_ROAMMODE, + SET_ROAM_IOLIST_ADD, + SET_ROAM_IOLIST_RESUME, + SET_ROAM_P2P_GC, + SET_ROAM_CONCRT_MODE, + SET_ROAM_VNDR_POLICY, + SET_ROAM_MAX /* Max set roam_off reason */ +} wl_roamoff_dbg_reason_t; + +extern void wl_android_roamoff_dbg_clr(struct bcm_cfg80211 *cfg); +extern void wl_android_roamoff_dbg_save(struct net_device *dev, uint rsn, uint roamvar); +extern void wl_android_roamoff_dbg_dump(struct bcm_cfg80211 *cfg); + +#define ROAMOFF_DBG_CLR(cfg) \ + wl_android_roamoff_dbg_clr((cfg)); +#define ROAMOFF_DBG_SAVE(dev, rsn, var) \ + wl_android_roamoff_dbg_save((dev), (rsn), (var)); +#define ROAMOFF_DBG_DUMP(cfg) \ + wl_android_roamoff_dbg_dump((cfg)); +#else +#define ROAMOFF_DBG_CLR(cfg) +#define ROAMOFF_DBG_SAVE(dev, rsn, var) +#define ROAMOFF_DBG_DUMP(cfg) +#endif /* DEBUG_SETROAMMODE */ +#if !defined(WL_TWT) && defined(WL_TWT_HAL_IF) +extern s32 wl_cfgvendor_notify_twt_event(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +#endif /* !WL_TWT && WL_TWT_HAL_IF */ +extern int wl_get_all_sideband_chanspecs(uint center_channel, chanspec_band_t band, + chanspec_bw_t bw, chanspec_t *chspecs, int *cnt); + +#ifdef WL_USABLE_CHAN +int wl_get_usable_channels(struct bcm_cfg80211 *cfg, usable_channel_info_t *u_info); +#endif /* WL_USABLE_CHAN */ + +extern int wl_cfg80211_reassoc(struct net_device *dev, struct ether_addr *bssid, + chanspec_t chanspec); +extern void wl_cfg80211_set_suspend_bcn_li_dtim(struct bcm_cfg80211 *cfg, + struct net_device *dev, bool suspend); +extern void wl_cfg80211_soft_suspend(struct net_device *dev, bool supsend); +extern void wl_cfg80211_handle_primary_ifchange(struct bcm_cfg80211 *cfg, + struct net_device *dev); +#ifdef CONFIG_SILENT_ROAM +int wl_cfg80211_sroam_config(struct bcm_cfg80211 *cfg, struct net_device *dev, bool set); +#endif /* CONFIG_SILENT_ROAM */ + +int wl_cfg80211_get_roam_params(struct net_device *dev, uint32 *data, uint16 data_len, uint16 id); +int wl_cfg80211_set_roam_params(struct net_device *dev, uint32 *data, uint16 data_len, uint16 id); + +extern void wl_cfg80211_wdev_lock(struct wireless_dev *wdev); +extern void wl_cfg80211_wdev_unlock(struct wireless_dev *wdev); + +extern u8 *wl_get_up_table_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev); +extern void wl_store_up_table_netinfo(struct bcm_cfg80211 *cfg, + struct net_device *ndev, u8 *uptable); + +/* Added wl_reassoc_params_cvt_v1 due to mis-sync between DHD and FW + * Because Dongle use wl_reassoc_params_v1_t for WLC_REASSOC + * Legacy FW use wl_reassoc_params_t + */ +typedef struct wl_reassoc_params_cvt_v1 { + uint16 version; + uint16 flags; + wl_reassoc_params_t params; +} wl_reassoc_params_cvt_v1_t; + +typedef struct wl_ext_reassoc_params_cvt_v1 { + uint16 version; + uint16 length; + uint32 flags; + wl_reassoc_params_cvt_v1_t params; +} wl_ext_reassoc_params_cvt_v1_t; + +#define WL_REASSOC_VERSION_V0 0u +#define WL_REASSOC_VERSION_V1 WL_EXTJOIN_VERSION_V1 +#define WL_REASSOC_VERSION_V2 WL_EXT_REASSOC_VER_1 +#ifdef WL_CP_COEX +struct wl_cp_coex { + int ch_cpcoex; + int ch_4g; + int ch_5g; +}; +#endif /* WL_CP_COEX */ +#ifdef BCMDBUS +s32 +__wl_cfg80211_up_resume(dhd_pub_t *dhd); +#endif /* BCMDBUS */ void wl_wlfc_enable(struct bcm_cfg80211 *cfg, bool enable); s32 wl_handle_join(struct bcm_cfg80211 *cfg, struct net_device *dev, wlcfg_assoc_info_t *assoc_info); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c old mode 100755 new mode 100644 index 3f334744bac6..49a51285ce8a --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -24,11 +24,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include @@ -38,16 +40,30 @@ extern uint dhd_master_mode; extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); #endif +typedef enum wl_cfg_btcx_timer_trig_type { + BT_DHCP_TIMER_IDLE, + BT_DHCP_TIMER_TRIGGER_NORMAL, + BT_DHCP_TIMER_TRIGGER_SCO +} wl_cfg_btcx_timer_trig_type_t; + +typedef enum wl_cfg_btcx_dhcp_state { + BT_DHCP_IDLE, + BT_DHCP_START, + BT_DHCP_OPPR_WIN, + BT_DHCP_FLAG_FORCE_TIMEOUT +} wl_cfg_btcx_dhcp_state_t; + struct btcoex_info { timer_list_compat_t timer; u32 timer_ms; u32 timer_on; - u32 ts_dhcp_start; /* ms ts ecord time stats */ - u32 ts_dhcp_ok; /* ms ts ecord time stats */ - bool dhcp_done; /* flag, indicates that host done with - * dhcp before t1/t2 expiration - */ - s32 bt_state; + u32 ts_dhcp_start; /* ms ts ecord time stats */ + u32 ts_dhcp_ok; /* ms ts ecord time stats */ + bool dhcp_done; /* flag, indicates that host done with + * dhcp before t1/t2 expiration + */ + wl_cfg_btcx_dhcp_state_t bt_state; + wl_cfg_btcx_timer_trig_type_t timer_trig_type; /* timer trigger type */ struct work_struct work; struct net_device *dev; }; @@ -69,13 +85,6 @@ static struct btcoex_info *btcoex_info_loc = NULL; #define BTCOEXMODE "BTCOEXMODE" #define POWERMODE "POWERMODE" -enum wl_cfg80211_btcoex_status { - BT_DHCP_IDLE, - BT_DHCP_START, - BT_DHCP_OPPR_WIN, - BT_DHCP_FLAG_FORCE_TIMEOUT -}; - /* * get named driver variable to uint register value and return error indication * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value) @@ -271,6 +280,16 @@ static int set_btc_esco_params(struct net_device *dev, bool trump_sco) } #endif /* BT_DHCP_eSCO_FIX */ +static void +wl_cfg80211_btcoex_init_handler_status(void) +{ + if (!btcoex_info_loc) + return; + + btcoex_info_loc->timer_trig_type = BT_DHCP_TIMER_IDLE; + btcoex_info_loc->bt_state = BT_DHCP_IDLE; +} + static void wl_cfg80211_bt_setflag(struct net_device *dev, bool set) { @@ -341,16 +360,23 @@ static void wl_cfg80211_bt_handler(struct work_struct *work) goto btc_coex_idle; } - /* DHCP is not over yet, start lowering BT priority - * enforce btc_params + flags if necessary - */ - WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME)); - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); - btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; - mod_timer(&btcx_inf->timer, - jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME)); - btcx_inf->timer_on = 1; + if (btcx_inf->timer_trig_type == BT_DHCP_TIMER_TRIGGER_SCO) { + /* DHCP is not over yet, start lowering BT priority + * enforce btc_params + flags if necessary + */ + WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME)); + if (btcx_inf->dev) + wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); + + btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; + mod_timer(&btcx_inf->timer, + jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME)); + btcx_inf->timer_on = 1; + } + else { + goto btc_coex_idle; + } + break; case BT_DHCP_FLAG_FORCE_TIMEOUT: @@ -361,20 +387,25 @@ static void wl_cfg80211_bt_handler(struct work_struct *work) WL_TRACE(("DHCP wait interval T2:%d msec expired\n", BT_DHCP_FLAG_FORCE_TIME)); } - - /* Restoring default bt priority */ - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); -btc_coex_idle: - btcx_inf->bt_state = BT_DHCP_IDLE; - btcx_inf->timer_on = 0; - break; + /* Pass through */ + fallthrough; default: - WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state)); - if (btcx_inf->dev) + if (btcx_inf->bt_state != BT_DHCP_FLAG_FORCE_TIMEOUT) { + WL_ERR(("Error BT DHCP status=%d!!!\n", btcx_inf->bt_state)); + } + + /* Restoring default bt priority */ + if (btcx_inf->dev && + btcx_inf->timer_trig_type == BT_DHCP_TIMER_TRIGGER_SCO) { wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); - btcx_inf->bt_state = BT_DHCP_IDLE; + } +btc_coex_idle: + /* Restore BLE Scan Grant */ + if (btcx_inf->dev) { + wldev_iovar_setint(btcx_inf->dev, "btc_ble_grants", 1); + } + wl_cfg80211_btcoex_init_handler_status(); btcx_inf->timer_on = 0; break; } @@ -391,12 +422,12 @@ void* wl_cfg80211_btcoex_init(struct net_device *ndev) if (!btco_inf) return NULL; - btco_inf->bt_state = BT_DHCP_IDLE; btco_inf->ts_dhcp_start = 0; btco_inf->ts_dhcp_ok = 0; /* Set up timer for BT */ btco_inf->timer_ms = 10; init_timer_compat(&btco_inf->timer, wl_cfg80211_bt_timerfunc, btco_inf); + wl_cfg80211_btcoex_init_handler_status(); btco_inf->dev = ndev; @@ -406,7 +437,7 @@ void* wl_cfg80211_btcoex_init(struct net_device *ndev) return btco_inf; } -void wl_cfg80211_btcoex_deinit(void) +void wl_cfg80211_btcoex_kill_handler(void) { if (!btcoex_info_loc) return; @@ -415,9 +446,16 @@ void wl_cfg80211_btcoex_deinit(void) btcoex_info_loc->timer_on = 0; del_timer_sync(&btcoex_info_loc->timer); } - cancel_work_sync(&btcoex_info_loc->work); + wl_cfg80211_btcoex_init_handler_status(); +} +void wl_cfg80211_btcoex_deinit(void) +{ + if (!btcoex_info_loc) + return; + + wl_cfg80211_btcoex_kill_handler(); kfree(btcoex_info_loc); } @@ -493,6 +531,9 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *co #ifndef OEM_ANDROID dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local)); #endif + /* Disable BLE Scan Grant during DHCP session */ + wldev_iovar_setint(dev, "btc_ble_grants", 0); + btco_inf->timer_trig_type = BT_DHCP_TIMER_TRIGGER_NORMAL; /* Disable PM mode during dhpc session */ /* Start BT timer only for SCO connection */ @@ -509,25 +550,26 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *co dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg68va_dhcp_on[0], sizeof(buf_reg68va_dhcp_on)); - saved_status = TRUE; - btco_inf->bt_state = BT_DHCP_START; - btco_inf->timer_on = 1; - mod_timer(&btco_inf->timer, - timer_expires(&btco_inf->timer)); - WL_TRACE(("enable BT DHCP Timer\n")); + btco_inf->timer_trig_type = BT_DHCP_TIMER_TRIGGER_SCO; } + + btco_inf->bt_state = BT_DHCP_START; + btco_inf->timer_on = 1; + mod_timer(&btco_inf->timer, timer_expires(&btco_inf->timer)); + + WL_TRACE(("enable BT DHCP Timer\n")); } else if (saved_status == TRUE) { WL_ERR(("was called w/o DHCP OFF. Continue\n")); } } #ifdef OEM_ANDROID - else if (powermode_val == '2') + else if (powermode_val == '2') { #else - else if (powermode_val == '0') + else if (powermode_val == '0') { #endif - { + #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS) /* Since DHCP is complete, enable the scan back */ wl_cfg80211_scan_suppress(dev, 0); @@ -570,13 +612,12 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *co } } - /* Restoring btc_flag paramter anyway */ - if (saved_status == TRUE) + if (saved_status == TRUE) { + /* Restoring btc_flag paramter anyway */ dev_wlc_bufvar_set(dev, "btc_flags", (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); - /* Restore original values */ - if (saved_status == TRUE) { + /* Restore original values */ regaddr = 66; dev_wlc_intvar_set_reg(dev, "btc_params", (char *)®addr, (char *)&saved_reg66); @@ -589,13 +630,305 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *co WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", saved_reg66, saved_reg41, saved_reg68)); - } - saved_status = FALSE; + /* Enable BLE Scan Grant */ + wldev_iovar_setint(dev, "btc_ble_grants", 1); + wl_cfg80211_btcoex_init_handler_status(); + } + + saved_status = FALSE; } else { WL_ERR(("Unknown yet power setting, ignored\n")); } return 0; } + +#ifdef WL_UWB_COEX +const uint16 uwb_6g_chmap[UWB_COEX_CH_MAP_NUM] = { + 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, + 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, + 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, 181, 185, 189, + 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233, 0, 0, 0, 0, 0 +}; + +static int +wl_cfg_uwb_coex_get_iovar_status_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len) +{ + bcm_iov_batch_buf_t *b_resp = (bcm_iov_batch_buf_t *)ctx; + uint32 status; + uint16 resp_len; + + /* if all tlvs are parsed, we should not be here */ + if (b_resp->count == 0) { + return BCME_BADLEN; + } + + /* cbfn params may be used in f/w */ + if (len < sizeof(status)) { + return BCME_BUFTOOSHORT; + } + + /* first 4 bytes consists status */ + status = dtoh32(*(uint32 *)data); + resp_len = len - sizeof(status); + + if (status != BCME_OK) { + WL_ERR(("%s - cmd type %d failed, status: %04x\n", + __FUNCTION__, type, status)); + return status; + } + if (!resp_len) { + if (b_resp->is_set) { + /* Set cmd resp may have only status, so len might be zero. + * just decrement batch resp count + */ + goto counter; + } + /* Every response for get command expects some data, + * return error if there is no data + */ + return BCME_ERROR; + } +counter: + if (b_resp->count > 0) { + b_resp->count--; + } + + if (!b_resp->count) { + status = BCME_IOV_LAST_CMD; + } + + return status; +} + +static int +wl_cfg_uwb_coex_proc_resp_buf(bcm_iov_batch_buf_t *resp, uint16 max_len, uint8 is_set) +{ + int ret = BCME_UNSUPPORTED; + uint16 version; + uint16 tlvs_len; + + version = dtoh16(*(uint16 *)resp); + if (version & (BCM_IOV_XTLV_VERSION_0 | BCM_IOV_BATCH_MASK)) { + if (!resp->count) { + return BCME_RANGE; + } else { + resp->is_set = is_set; + /* number of tlvs count */ + tlvs_len = max_len - OFFSETOF(bcm_iov_batch_buf_t, cmds[0]); + /* Extract the tlvs and print their resp in cb fn */ + ret = bcm_unpack_xtlv_buf((void *)resp, (const uint8 *)&resp->cmds[0], + tlvs_len, BCM_IOV_CMD_OPT_ALIGN32, + wl_cfg_uwb_coex_get_iovar_status_cbfn); + + if (ret == BCME_IOV_LAST_CMD) { + ret = BCME_OK; + } + } + } + + return ret; +} + +static int +wl_cfg_uwb_coex_execute_cmd(struct net_device *dev, struct bcm_cfg80211 *cfg, + bcm_iov_batch_buf_t *buf, uint16 buf_sz, + uint8 *resp_buf, uint16 resp_buf_sz) +{ + int ret = BCME_ERROR; + + char *iov = "uwbcx"; + bcm_iov_batch_buf_t *p_resp = NULL; + + if (buf->is_set) { + ret = wldev_iovar_setbuf(dev, iov, buf, buf_sz, + resp_buf, resp_buf_sz, NULL); + p_resp = (bcm_iov_batch_buf_t *)(resp_buf + strlen(iov) + 1); + resp_buf_sz -= (strlen(iov) + 1); + } else { + ret = wldev_iovar_getbuf(dev, iov, buf, buf_sz, + resp_buf, resp_buf_sz, NULL); + p_resp = (bcm_iov_batch_buf_t *)resp_buf; + } + if (unlikely(ret)) { + WL_ERR(("%s - failed to execute uwbcx cmd, err = %d\n", __FUNCTION__, ret)); + goto fail; + } + + if (ret == BCME_OK && p_resp != NULL) { + ret = wl_cfg_uwb_coex_proc_resp_buf(p_resp, resp_buf_sz, buf->is_set); + } +fail: + return ret; +} + +static int +wl_cfg_uwb_coex_fill_ioctl_data(bcm_iov_batch_buf_t *b_buf, const uint8 is_set, + const uint16 id, void *data, uint16 data_len) +{ + uint16 len; + + bcm_iov_batch_subcmd_t *sub_cmd; + + /* Fill the header */ + b_buf->version = htol16(BCM_IOV_XTLV_VERSION_0 | BCM_IOV_BATCH_MASK); + b_buf->count = 1; + b_buf->is_set = is_set; + len = OFFSETOF(bcm_iov_batch_buf_t, cmds[0]); + + /* Fill the sub command */ + sub_cmd = (bcm_iov_batch_subcmd_t *)(uint8 *)(&b_buf->cmds[0]); + sub_cmd->id = htod16(id); + sub_cmd->len = sizeof(sub_cmd->u.options) + data_len; + sub_cmd->u.options = htol32(BCM_XTLV_OPTION_ALIGN32); + len += OFFSETOF(bcm_iov_batch_subcmd_t, data); + + if (data) { + (void)memcpy_s(sub_cmd->data, data_len, (uint8 *)data, data_len); + len += ALIGN_SIZE(data_len, 4); + } + + return len; +} + +static int +wl_cfg_uwb_coex_get_ch_idx(const int ch) +{ + int i; + bool found = FALSE; + + if (ch < UWB_COEX_CH_MIN || ch > UWB_COEX_CH_MAX) { + return BCME_UNSUPPORTED; + } + + for (i = 0; i < UWB_COEX_CH_MAP_NUM; i++) { + if (uwb_6g_chmap[i] == ch) { + found = TRUE; + break; + } + } + + return found ? i : BCME_UNSUPPORTED; +} + +static void +wl_cfg_uwb_coex_make_coex_bitmap(int start_ch_idx, int end_ch_idx, + uwbcx_coex_bitmap_v2_t *coex_bitmap_cfg) +{ + int i; + uwbcx_coex_bitmap_t *coex_bitmap = (uwbcx_coex_bitmap_t *) (&coex_bitmap_cfg->coex_bitmap); + + for (i = start_ch_idx; i <= end_ch_idx; i++) { + if (i < 16u) { + coex_bitmap->low_bitmap |= (1 << i); + } else if (i >= 16u && i < 32u) { + coex_bitmap->mid_low_bitmap |= (1 << (i - 16u)); + } else if (i >= 32u && i < 48u) { + coex_bitmap->mid_high_bitmap |= (1 << (i - 32u)); + } else if (i >= 48u) { + coex_bitmap->high_bitmap |= (1 << (i - 48u)); + } + } +} + +uint16 +wl_cfg_uwb_coex_get_ch_val(const int idx) +{ + return uwb_6g_chmap[idx]; +} + +int +wl_cfg_uwb_coex_execute_ioctl(struct net_device *dev, struct bcm_cfg80211 *cfg, + const uint8 is_set, uint16 id, void *data, uint16 data_len, + uint8 *resp_buf, uint16 resp_buf_sz) +{ + int ret; + + uint8 *buf = NULL; + bcm_iov_batch_buf_t *b_buf; + + uint16 iov_len; + + buf = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN); + if (unlikely(!buf)) { + WL_ERR(("%s - Failed to alloc mem\n", __FUNCTION__)); + ret = BCME_NOMEM; + goto exit; + } + b_buf = (bcm_iov_batch_buf_t *)buf; + + if (is_set) { + iov_len = wl_cfg_uwb_coex_fill_ioctl_data(b_buf, TRUE, + id, data, data_len); + } else { + iov_len = wl_cfg_uwb_coex_fill_ioctl_data(b_buf, FALSE, + id, NULL, 0); + } + + ret = wl_cfg_uwb_coex_execute_cmd(dev, cfg, b_buf, iov_len, + (void *)resp_buf, resp_buf_sz); + if (unlikely(ret)) { + WL_ERR(("%s - Failed to execute uwb coex ioctl, ret = %d\n", + __FUNCTION__, ret)); + } +exit: + if (buf) { + MFREE(cfg->osh, buf, WLC_IOCTL_SMLEN); + } + + return ret; +} + +int +wl_cfg_uwb_coex_enable(struct net_device *dev, int enable, int start_ch, int end_ch) +{ + int ret = BCME_OK; + + int start_ch_idx; + int end_ch_idx; + + uint8 *resp_buf = NULL; + + uwbcx_coex_bitmap_v2_t coex_bitmap_cfg; + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + + resp_buf = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN); + if (unlikely(!resp_buf)) { + WL_ERR(("%s - Failed to alloc mem\n", __FUNCTION__)); + ret = BCME_NOMEM; + goto exit; + } + + bzero(&coex_bitmap_cfg, sizeof(uwbcx_coex_bitmap_v2_t)); + coex_bitmap_cfg.version = UWBCX_COEX_BITMAP_VERSION_V2; + coex_bitmap_cfg.len = sizeof(coex_bitmap_cfg); + coex_bitmap_cfg.band = UWBCX_BAND_6G; + + /* Validate UWB Coex channel in case of turnning on */ + if (enable && (((start_ch_idx = wl_cfg_uwb_coex_get_ch_idx(start_ch)) < 0) || + ((end_ch_idx = wl_cfg_uwb_coex_get_ch_idx(end_ch)) < 0))) { + WL_ERR(("%s - Unsupported ch.%d, ch.%d\n", __FUNCTION__, start_ch, end_ch)); + ret = BCME_UNSUPPORTED; + goto exit; + } + + if (enable) { + wl_cfg_uwb_coex_make_coex_bitmap(start_ch_idx, end_ch_idx, &coex_bitmap_cfg); + } + + ret = wl_cfg_uwb_coex_execute_ioctl(dev, cfg, TRUE, WL_UWBCX_CMD_COEX_BITMAP, + &coex_bitmap_cfg, (uint16)sizeof(coex_bitmap_cfg), + resp_buf, WLC_IOCTL_SMLEN); + WL_ERR(("%s - UWB Coex %s %s - Ch. [%d/%d] (ret = %d)\n", __FUNCTION__, + enable ? "On" : "Off", !ret ? "Success" : "Fail", + start_ch, end_ch, ret)); +exit: + if (resp_buf) { + MFREE(cfg->osh, resp_buf, WLC_IOCTL_SMLEN); + } + + return ret; +} +#endif /* WL_UWB_COEX */ #endif /* defined(OEM_ANDROID) */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgnan.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgnan.c old mode 100755 new mode 100644 index 878495e41df8..415f845b3892 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgnan.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgnan.c @@ -1,7 +1,7 @@ /* * Neighbor Awareness Networking * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -57,6 +57,8 @@ static int wl_cfgnan_cache_disc_result(struct bcm_cfg80211 *cfg, void * data, u16 *disc_cache_update_flags); static int wl_cfgnan_remove_disc_result(struct bcm_cfg80211 * cfg, uint8 local_subid); +static int wl_cfgnan_reset_disc_result(struct bcm_cfg80211 *cfg, + nan_disc_result_cache *disc_res); static nan_disc_result_cache * wl_cfgnan_get_disc_result(struct bcm_cfg80211 *cfg, uint8 remote_pubid, struct ether_addr *peer); #endif /* WL_NAN_DISC_CACHE */ @@ -82,6 +84,7 @@ static nan_ndp_peer_t* wl_cfgnan_data_get_peer(struct bcm_cfg80211 *cfg, static int wl_cfgnan_disable(struct bcm_cfg80211 *cfg); static s32 wl_cfgnan_del_ndi_data(struct bcm_cfg80211 *cfg, char *name); static s32 wl_cfgnan_add_ndi_data(struct bcm_cfg80211 *cfg, s32 idx, char *name); +static int wl_nan_print_stats_tlvs(void *ctx, const uint8 *data, uint16 type, uint16 len); #ifdef RTT_SUPPORT static int wl_cfgnan_clear_disc_cache(struct bcm_cfg80211 *cfg, wl_nan_instance_id_t sub_id); @@ -103,6 +106,22 @@ static void wl_cfgnan_reset_remove_ranging_instance(struct bcm_cfg80211 *cfg, static void wl_cfgnan_remove_ranging_instance(struct bcm_cfg80211 *cfg, nan_ranging_inst_t *ranging_inst); #endif /* RTT_SUPPORT */ +static void wl_cfgnan_periodic_nmi_rand_addr(struct work_struct *work); +static uint8 wl_cfgnan_map_nan_prot_csid_to_host_csid(uint8 prot_csid); +static uint8 wl_cfgnan_map_host_csid_to_nan_prot_csid(uint8 host_csid); + +typedef struct nan_csid_map { + uint16 fw_csid; + uint16 host_csid; +} nan_csid_map_t; + +nan_csid_map_t nan_csid_map_table[] = { + {NAN_SEC_ALGO_NONE, 0}, + {NAN_SEC_ALGO_NCS_SK_CCM_128, WL_NAN_CIPHER_SUITE_SHARED_KEY_128_MASK}, + {NAN_SEC_ALGO_NCS_SK_GCM_256, WL_NAN_CIPHER_SUITE_SHARED_KEY_256_MASK}, + {NAN_SEC_ALGO_NCS_PK_CCM_128, WL_NAN_CIPHER_SUITE_PUBLIC_KEY_128_MASK}, + {NAN_SEC_ALGO_NCS_PK_GCM_256, WL_NAN_CIPHER_SUITE_PUBLIC_KEY_256_MASK} +}; static const char * nan_role_to_str(u8 role) @@ -229,6 +248,8 @@ nan_event_to_str(u16 cmd) break; C2S(WL_NAN_EVENT_OOB_AF_RX); break; + C2S(WL_NAN_EVENT_SCHED_CHANGE); + break; C2S(WL_NAN_EVENT_INVALID); break; @@ -367,6 +388,7 @@ wl_cfgnan_remove_inst_id(struct bcm_cfg80211 *cfg, uint8 inst_id) clrbit(cfg->nancfg->svc_inst_id_mask, inst_id-1); return ret; } + s32 wl_cfgnan_parse_sdea_data(osl_t *osh, const uint8 *p_attr, uint16 len, nan_event_data_t *tlv_data) { @@ -708,9 +730,125 @@ fail: return ret; } +static s32 +wl_cfgnan_parse_scid_info(osl_t *osh, const uint8 *p_attr, + uint16 len, nan_event_data_t *tlv_data) +{ + s32 ret = BCME_OK; + s8 buf_end = 0; + const wifi_nan_sec_ctx_id_info_attr_t *scid_info_attr; + wifi_nan_sec_ctx_id_field_t *p = NULL; + uint16 scid_len; + + /* security context id attribute */ + scid_info_attr = (const wifi_nan_sec_ctx_id_info_attr_t *)p_attr; + /* attribute ID */ + WL_TRACE(("> attr id: 0x%02x\n", scid_info_attr->attr_id)); + + /* attribute length */ + WL_TRACE(("> attr len: 0x%x\n", scid_info_attr->len)); + + scid_len = scid_info_attr->len; + + if (scid_len > NAN_MAX_SCID_BUF_LEN) { + WL_ERR(("Invalid scid len\n")); + ret = BCME_BADLEN; + goto fail; + } + buf_end = sizeof(*scid_info_attr) + scid_len; + if (buf_end > len) { + WL_ERR(("Invalid event buffer len\n")); + ret = BCME_BUFTOOSHORT; + goto fail; + } + + p = (wifi_nan_sec_ctx_id_field_t *)(scid_info_attr->var); + scid_len = p->sec_ctx_id_type_len; + + tlv_data->scid.dlen = scid_len; + tlv_data->scid.data = MALLOCZ(osh, scid_len); + if (!tlv_data->scid.data) { + WL_ERR(("%s: memory allocation failed\n", __FUNCTION__)); + tlv_data->scid.dlen = 0; + ret = BCME_NOMEM; + goto fail; + } + + (void)memcpy_s(tlv_data->scid.data, tlv_data->scid.dlen, p->var, scid_len); + return ret; +fail: + if (tlv_data->scid.data) { + MFREE(osh, tlv_data->scid.data, tlv_data->scid.dlen); + tlv_data->scid.data = NULL; + } + + WL_DBG(("Parse SCID event data, status = %d\n", ret)); + return ret; +} + +static s32 +wl_cfgnan_parse_csid_data(osl_t *osh, const uint8 *p_attr, + uint16 len, nan_event_data_t *tlv_data, uint16 type) +{ + s32 ret = BCME_OK; + const wifi_nan_sec_cipher_suite_info_attr_t *csid_info_attr; + const wifi_nan_sec_cipher_suite_field_t *csid_field = NULL; + uint8 csid_len, csid_offset; + + /* security context id attribute */ + csid_info_attr = (const wifi_nan_sec_cipher_suite_info_attr_t *)p_attr; + /* attribute ID */ + WL_TRACE(("> attr id: 0x%02x\n", csid_info_attr->attr_id)); + + /* attribute length */ + WL_TRACE(("> attr len: 0x%x\n", csid_info_attr->len)); + + csid_len = csid_info_attr->len; + + if (csid_len > len) { + WL_ERR(("Invalid event buffer len\n")); + ret = BCME_BUFTOOSHORT; + goto fail; + } + + csid_offset = (OFFSETOF(wifi_nan_sec_cipher_suite_info_attr_t, var) - + NAN_ATTR_HDR_LEN); + + csid_field = (wifi_nan_sec_cipher_suite_field_t *)(csid_info_attr->var); + csid_len -= csid_offset; + + if (type == WL_NAN_XTLV_SD_DISC_RESULTS) { + while (csid_len >= sizeof(*csid_field)) { + if (csid_field->inst_id == tlv_data->pub_id) { + tlv_data->peer_cipher_suite = csid_field->cipher_suite_id; + break; + } else { + csid_field++; + csid_len -= sizeof(*csid_field); + } + } + } else { + if (csid_len != sizeof(*csid_field)) { + ret = BCME_BADLEN; + goto fail; + } + tlv_data->peer_cipher_suite = csid_field->cipher_suite_id; + } + + /* Default csid is zero, if peer_cipher_suite is not updated */ + tlv_data->peer_cipher_suite = + wl_cfgnan_map_nan_prot_csid_to_host_csid(tlv_data->peer_cipher_suite); + + return ret; +fail: + WL_DBG(("Parse CSID event data, status = %d\n", ret)); + return ret; +} + static s32 wl_cfgnan_parse_sd_attr_data(osl_t *osh, uint16 len, const uint8 *data, - nan_event_data_t *tlv_data, uint16 type) { + nan_event_data_t *tlv_data, uint16 type) +{ const uint8 *p_attr = data; uint16 offset = 0; s32 ret = BCME_OK; @@ -776,6 +914,26 @@ wl_cfgnan_parse_sd_attr_data(osl_t *osh, uint16 len, const uint8 *data, goto fail; } } + + if ((uint8)*p_attr == NAN_ATTR_SEC_CTX_ID_INFO) { + WL_TRACE(("> attr id: 0x%02x\n", (uint8)*p_attr)); + ret = wl_cfgnan_parse_scid_info(osh, p_attr, len, tlv_data); + if (unlikely(ret)) { + WL_ERR(("wl_cfgnan_parse_scid_info failed," + "error = %d \n", ret)); + goto fail; + } + } + + if ((uint8)*p_attr == NAN_ATTR_CIPHER_SUITE_INFO) { + WL_TRACE(("> attr id: 0x%02x\n", (uint8)*p_attr)); + ret = wl_cfgnan_parse_csid_data(osh, p_attr, len, tlv_data, type); + if (unlikely(ret)) { + WL_ERR(("wl_cfgnan_parse_csid_data failed," + "error = %d \n", ret)); + goto fail; + } + } offset = (sizeof(*p_attr) + sizeof(ev_disc->attr_list_len) + (p_attr[1] | (p_attr[2] << 8))); @@ -931,8 +1089,8 @@ wl_cfgnan_set_vars_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len) nan_parse_event_ctx_t *ctx_tlv_data = ((nan_parse_event_ctx_t *)(ctx)); nan_event_data_t *tlv_data = ((nan_event_data_t *)(ctx_tlv_data->nan_evt_data)); int ret = BCME_OK; + uint8 csid; - NAN_DBG_ENTER(); if (!data || !len) { WL_ERR(("data length is invalid\n")); ret = BCME_ERROR; @@ -972,17 +1130,93 @@ wl_cfgnan_set_vars_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len) } break; } + case WL_NAN_XTLV_NDL_SCHED_INFO: { + wl_nan_ndl_sched_info_t *sched_info = (wl_nan_ndl_sched_info_t *)data; + uint32 expected_len = 0; + uint16 slot_idx = 0; + nan_channel_info_t channel_info; + nan_channel_info_t *ch_info; + uint8 ch_info_idx; + chanspec_t chspec; + nan_ndl_sched_info_t *nan_sched_info = &tlv_data->ndl_sched_info; + + expected_len = sizeof(wl_nan_ndl_sched_info_t) + (sched_info->num_slot * + sizeof(wl_nan_ndl_slot_info_t)); + if (len != expected_len) { + WL_ERR(("NDL sched info Bad Length:%d, Expected length:%d\n", + len, expected_len)); + ret = BCME_BADLEN; + goto fail; + } + + (void)memset_s(nan_sched_info, sizeof(nan_ndl_sched_info_t), + 0, sizeof(nan_ndl_sched_info_t)); + WL_DBG(("NDL sched info num slot:%d\n", sched_info->num_slot)); + while (slot_idx < sched_info->num_slot) { + if (!sched_info->slot[slot_idx].chanspec) { + slot_idx++; + continue; + } + chspec = wl_chspec_driver_to_host(sched_info->slot[slot_idx].chanspec); + channel_info.channel = wl_channel_to_frequency(wf_chspec_ctlchan(chspec), + CHSPEC_BAND(chspec)); + channel_info.bandwidth = wl_chanspec_to_host_bw_map(chspec); + channel_info.nss = sched_info->slot[slot_idx].nss; + + if (nan_sched_info->num_channels < NAN_MAX_CHANNEL_INFO_SUPPORTED) { + for (ch_info_idx = 0; ch_info_idx < NAN_MAX_CHANNEL_INFO_SUPPORTED; + ch_info_idx++) { + ch_info = &nan_sched_info->channel_info[ch_info_idx]; + if (ch_info->channel == 0) { + WL_DBG(("channel:%d, bw:%d, nss:%d\n", + channel_info.channel, + channel_info.bandwidth, + channel_info.nss)); + (void)memcpy_s(ch_info, sizeof(nan_channel_info_t), + &channel_info, sizeof(nan_channel_info_t)); + nan_sched_info->num_channels++; + break; + } else if (!memcmp((uint8 *)ch_info, (uint8 *)&channel_info, + sizeof(nan_channel_info_t))) { + break; + } + } + } else { + break; + } + slot_idx++; + } + + break; + } case WL_NAN_XTLV_SD_NAN_AF: case WL_NAN_XTLV_DAM_NA_ATTR: /* No action -intentionally added to avoid prints when these events are rcvd */ break; + case WL_NAN_XTLV_CFG_SEC_PMKID: + tlv_data->scid.data = MALLOCZ(ctx_tlv_data->cfg->osh, len); + if (!tlv_data->scid.data) { + WL_ERR(("%s: memory allocation failed\n", __FUNCTION__)); + tlv_data->scid.dlen = 0; + ret = BCME_NOMEM; + goto fail; + } + tlv_data->scid.dlen = len; + (void)memcpy_s(tlv_data->scid.data, tlv_data->scid.dlen, data, len); + break; + case WL_NAN_XTLV_CFG_SEC_CSID: + csid = *(uint8 *)data; + tlv_data->peer_cipher_suite = wl_cfgnan_map_nan_prot_csid_to_host_csid(csid); + break; + case WL_NAN_XTLV_GEN_AVAIL_STATS_SCHED: + ret = wl_nan_print_stats_tlvs(ctx, data, type, len); + break; default: WL_ERR(("Not available for tlv type = 0x%x\n", type)); ret = BCME_ERROR; break; } fail: - NAN_DBG_EXIT(); return ret; } @@ -1064,8 +1298,9 @@ wl_cfgnan_config_eventmask(struct net_device *ndev, struct bcm_cfg80211 *cfg, nan_buf->count = 1; if (disable_events) { - WL_DBG(("Disabling all nan events..except stop event\n")); + WL_DBG(("Disabling all nan events..except start/stop events\n")); setbit(event_mask, NAN_EVENT_MAP(WL_NAN_EVENT_STOP)); + setbit(event_mask, NAN_EVENT_MAP(WL_NAN_EVENT_START)); } else { /* * Android framework event mask configuration. @@ -1102,6 +1337,7 @@ wl_cfgnan_config_eventmask(struct net_device *ndev, struct bcm_cfg80211 *cfg, setbit(event_mask, NAN_EVENT_MAP(WL_NAN_EVENT_RECEIVE)); setbit(event_mask, NAN_EVENT_MAP(WL_NAN_EVENT_TERMINATED)); setbit(event_mask, NAN_EVENT_MAP(WL_NAN_EVENT_STOP)); + setbit(event_mask, NAN_EVENT_MAP(WL_NAN_EVENT_START)); setbit(event_mask, NAN_EVENT_MAP(WL_NAN_EVENT_TXS)); setbit(event_mask, NAN_EVENT_MAP(WL_NAN_EVENT_PEER_DATAPATH_IND)); setbit(event_mask, NAN_EVENT_MAP(WL_NAN_EVENT_DATAPATH_ESTB)); @@ -1113,6 +1349,7 @@ wl_cfgnan_config_eventmask(struct net_device *ndev, struct bcm_cfg80211 *cfg, clrbit(event_mask, NAN_EVENT_MAP(WL_NAN_EVENT_PEER_SCHED_UPD_NOTIF)); clrbit(event_mask, NAN_EVENT_MAP(WL_NAN_EVENT_RNG_RPT_IND)); clrbit(event_mask, NAN_EVENT_MAP(WL_NAN_EVENT_DW_END)); + clrbit(event_mask, NAN_EVENT_MAP(WL_NAN_EVENT_REPLIED)); } nan_buf->is_set = true; @@ -1536,7 +1773,7 @@ wl_cfgnan_get_iovars_status(void *ctx, const uint8 *data, uint16 type, uint16 le /* If status is non zero */ if (status != BCME_OK) { - printf("cmd type %d failed, status: %04x\n", type, status); + WL_ERR(("cmd type %d failed, status: %04x\n", type, status)); goto exit; } @@ -1766,6 +2003,10 @@ wl_cfgnan_set_if_addr(struct bcm_cfg80211 *cfg) WL_ERR(("Failed to copy nmi addr\n")); goto fail; } +#ifdef WL_NMI_IF + /* copy new nmi addr to dedicated NMI interface */ + eacopy(if_addr.octet, cfg->nmi_ndev->dev_addr); +#endif /* WL_NMI_IF */ return ret; fail: if (!rand_mac) { @@ -1853,6 +2094,43 @@ wl_cfgnan_enable_handler(wl_nan_iov_t *nan_iov_data, bool val) return ret; } +static int +wl_cfgnan_set_instant_chanspec(nan_config_cmd_data_t *cmd_data, wl_nan_iov_t *nan_iov_data) +{ + s32 ret = BCME_OK; + bcm_iov_batch_subcmd_t *sub_cmd = NULL; + chanspec_t chspec; + uint16 subcmd_len; + NAN_DBG_ENTER(); + + sub_cmd = (bcm_iov_batch_subcmd_t*)(nan_iov_data->nan_iov_buf); + + ret = wl_cfg_nan_check_cmd_len(nan_iov_data->nan_iov_len, + sizeof(chanspec_t), &subcmd_len); + if (unlikely(ret)) { + WL_ERR(("nan_sub_cmd check failed\n")); + return ret; + } + /* Fill the sub_command block */ + sub_cmd->id = htod16(WL_NAN_CMD_CFG_INSTANT_CHAN); + sub_cmd->len = sizeof(sub_cmd->u.options) + sizeof(chspec); + sub_cmd->u.options = htol32(BCM_XTLV_OPTION_ALIGN32); + chspec = cmd_data->instant_chspec; + + ret = memcpy_s(sub_cmd->data, sizeof(chanspec_t), + (uint8*)&chspec, sizeof(chanspec_t)); + if (ret != BCME_OK) { + WL_ERR(("Failed to copy enab instant chspec\n")); + return ret; + } + + nan_iov_data->nan_iov_len -= subcmd_len; + nan_iov_data->nan_iov_buf += subcmd_len; + + NAN_DBG_EXIT(); + return ret; +} + static int wl_cfgnan_warmup_time_handler(nan_config_cmd_data_t *cmd_data, wl_nan_iov_t *nan_iov_data) @@ -2043,8 +2321,8 @@ wl_cfgnan_set_rssi_mid_or_close(nan_config_cmd_data_t *cmd_data, return ret; } -static int -check_for_valid_5gchan(struct net_device *ndev, uint8 chan) +int +wl_cfgnan_check_for_valid_5gchan(struct net_device *ndev, uint8 chan) { s32 ret = BCME_OK; uint bitmap; @@ -2075,6 +2353,30 @@ check_for_valid_5gchan(struct net_device *ndev, uint8 chan) ret = BCME_BADCHAN; goto exit; } + + if (bitmap & WL_CHAN_RADAR) { + WL_ERR(("Radar channel, NAN can not operate\n")); + ret = BCME_BADCHAN; + goto exit; + } + + if (bitmap & WL_CHAN_PASSIVE) { + WL_ERR(("Passive channel, NAN can not operate\n")); + ret = BCME_BADCHAN; + goto exit; + } + + if (bitmap & WL_CHAN_RESTRICTED) { + WL_ERR(("Use restricted channel, NAN can not operate\n")); + ret = BCME_BADCHAN; + goto exit; + } + + if (bitmap & WL_CHAN_CLM_RESTRICTED) { + WL_ERR(("CLM restricted channel, NAN can not operate\n")); + ret = BCME_BADCHAN; + goto exit; + } exit: NAN_DBG_EXIT(); return ret; @@ -2118,9 +2420,9 @@ wl_cfgnan_set_nan_soc_chans(struct net_device *ndev, nan_config_cmd_data_t *cmd_ } else { soc_chans->soc_chan_5g = NAN_DEF_SOCIAL_CHAN_5G; } - ret = check_for_valid_5gchan(ndev, soc_chans->soc_chan_5g); + ret = wl_cfgnan_check_for_valid_5gchan(ndev, soc_chans->soc_chan_5g); if (ret != BCME_OK) { - ret = check_for_valid_5gchan(ndev, NAN_DEF_SEC_SOCIAL_CHAN_5G); + ret = wl_cfgnan_check_for_valid_5gchan(ndev, NAN_DEF_SEC_SOCIAL_CHAN_5G); if (ret == BCME_OK) { soc_chans->soc_chan_5g = NAN_DEF_SEC_SOCIAL_CHAN_5G; } else { @@ -2707,6 +3009,77 @@ wl_cfgnan_check_nan_disable_pending(struct bcm_cfg80211 *cfg, return ret; } +static int +wl_cfgnan_config_nmi_rand_mac(struct net_device *ndev, + struct bcm_cfg80211 *cfg, nan_config_cmd_data_t *cmd_data) +{ + s32 ret = BCME_OK; + +#ifdef WL_NAN_ENABLE_MERGE + /* Cluster merge enable/disable are being set using nmi random interval config param + * If MSB(31st bit) is set that indicates cluster merge enable/disable config is set + * MSB 30th bit indicates cluser merge enable/disable value to set in firmware + */ + if (cmd_data->nmi_rand_intvl & NAN_NMI_RAND_PVT_CMD_VENDOR) { + uint8 merge_enable; + uint8 lwt_mode_enable; + int status = BCME_OK; + + merge_enable = !!(cmd_data->nmi_rand_intvl & + NAN_NMI_RAND_CLUSTER_MERGE_ENAB); + ret = wl_cfgnan_set_enable_merge(bcmcfg_to_prmry_ndev(cfg), cfg, + merge_enable, &status); + if (unlikely(ret) || unlikely(status)) { + WL_ERR(("Enable merge: failed to set config request [%d]\n", ret)); + /* As there is no cmd_reply, check if error is in status or ret */ + if (status) { + ret = status; + } + return ret; + } + + WL_INFORM_MEM(("Cluster merge : %s\n", merge_enable ? "Enabled" : "Disabled")); + + lwt_mode_enable = !!(cmd_data->nmi_rand_intvl & + NAN_NMI_RAND_AUTODAM_LWT_MODE_ENAB); + + /* set CFG CTRL2 flags1 and flags2 */ + ret = wl_cfgnan_config_control_flag(ndev, cfg, + WL_NAN_CTRL2_FLAG1_AUTODAM_LWT_MODE, + 0, WL_NAN_CMD_CFG_NAN_CONFIG2, + &status, lwt_mode_enable); + if (unlikely(ret) || unlikely(status)) { + WL_ERR(("Enable dam lwt mode: " + "failed to set config request [%d]\n", ret)); + /* As there is no cmd_reply, check if error is in status or ret */ + if (status) { + ret = status; + } + return ret; + } + + WL_INFORM_MEM(("LWT mode : %s\n", lwt_mode_enable ? "Enabled" : "Disabled")); + + /* reset pvt merge enable bits */ + cmd_data->nmi_rand_intvl &= ~(NAN_NMI_RAND_PVT_CMD_VENDOR | + NAN_NMI_RAND_CLUSTER_MERGE_ENAB | + NAN_NMI_RAND_AUTODAM_LWT_MODE_ENAB); + } +#endif /* WL_NAN_ENABLE_MERGE */ + + if (cmd_data->nmi_rand_intvl) { + WL_INFORM_MEM((" NMI randomization mac interval %d \n", cmd_data->nmi_rand_intvl)); + cfg->nancfg->nmi_rand_intvl = + (cmd_data->nmi_rand_intvl & NAN_NMI_RAND_INTVL_MASK); + if (delayed_work_pending(&cfg->nancfg->nan_nmi_rand)) { + cancel_delayed_work(&cfg->nancfg->nan_nmi_rand); + } + schedule_delayed_work(&cfg->nancfg->nan_nmi_rand, + msecs_to_jiffies(cfg->nancfg->nmi_rand_intvl * 1000)); + } + return ret; +} + int wl_cfgnan_start_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, nan_config_cmd_data_t *cmd_data, uint32 nan_attr_mask) @@ -2722,6 +3095,7 @@ wl_cfgnan_start_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, nan_hal_capabilities_t capabilities; uint32 cfg_ctrl1_flags = 0; uint32 cfg_ctrl2_flags1 = 0; + uint32 cfg_ctrl2_reset_flags1 = 0; wl_nancfg_t *nancfg = cfg->nancfg; NAN_DBG_ENTER(); @@ -2862,6 +3236,13 @@ wl_cfgnan_start_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, } } + if (cmd_data->nmi_rand_intvl > 0) { + ret = wl_cfgnan_config_nmi_rand_mac(ndev, cfg, cmd_data); + if (unlikely(ret)) { + WL_ERR(("Failed to config nmi random interval\n")); + goto fail; + } + } /* * A cluster_low value matching cluster_high indicates a request * to join a cluster with that value. @@ -2941,7 +3322,8 @@ wl_cfgnan_start_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, } /* enable events */ - ret = wl_cfgnan_config_eventmask(ndev, cfg, cmd_data->disc_ind_cfg, false); + ret = wl_cfgnan_config_eventmask(ndev, cfg, cmd_data->disc_ind_cfg, + cmd_data->chre_req ? true : false); if (unlikely(ret)) { WL_ERR(("Failed to config disc ind flag in event_mask, ret = %d\n", ret)); goto fail; @@ -2954,6 +3336,15 @@ wl_cfgnan_start_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, goto fail; } nan_buf->count++; + + if (cmd_data->instant_chspec) { + ret = wl_cfgnan_set_instant_chanspec(cmd_data, nan_iov_data); + if (unlikely(ret)) { + WL_ERR(("NAN 3.1 Instant disc channel sub_cmd set failed\n")); + goto fail; + } + nan_buf->count++; + } nan_buf->is_set = true; nan_buf_size -= nan_iov_data->nan_iov_len; @@ -2962,7 +3353,7 @@ wl_cfgnan_start_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, ret = wl_cfgnan_execute_ioctl(ndev, cfg, nan_buf, nan_buf_size, &(cmd_data->status), (void*)resp_buf, NAN_IOCTL_BUF_SIZE); if (unlikely(ret) || unlikely(cmd_data->status)) { - WL_ERR((" nan start handler, enable failed, ret = %d status = %d \n", + WL_ERR(("nan start handler, enable failed, ret = %d status = %d \n", ret, cmd_data->status)); goto fail; } @@ -3013,7 +3404,7 @@ wl_cfgnan_start_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, } } } else { - WL_ERR(("wl_cfgnan_get_capablities_handler failed, ret = %d\n", ret)); + WL_ERR(("wl_cfgnan_get_capabilities_handler failed, ret = %d\n", ret)); goto fail; } @@ -3046,15 +3437,28 @@ wl_cfgnan_start_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, nancfg->ndpe_enabled = true; } else { /* reset NDPE capability in FW */ - ret = wl_cfgnan_config_control_flag(ndev, cfg, WL_NAN_CTRL2_FLAG1_NDPE_CAP, + cfg_ctrl2_reset_flags1 |= WL_NAN_CTRL2_FLAG1_NDPE_CAP; + nancfg->ndpe_enabled = false; + } + + /* NAN 3.1 Instant communication config mode */ + if (cmd_data->instant_mode_en) { + cfg_ctrl2_flags1 |= WL_NAN_CTRL2_FLAG1_INSTANT_MODE; + } else { + /* reset NAN 3.1 Instant communication mode in FW */ + cfg_ctrl2_reset_flags1 |= WL_NAN_CTRL2_FLAG1_INSTANT_MODE; + } + + /* Reset ctrl2 flags */ + if (cfg_ctrl2_reset_flags1) { + ret = wl_cfgnan_config_control_flag(ndev, cfg, cfg_ctrl2_reset_flags1, 0, WL_NAN_CMD_CFG_NAN_CONFIG2, &(cmd_data->status), false); if (unlikely(ret) || unlikely(cmd_data->status)) { - WL_ERR((" nan ctrl2 config flags resetting failed, ret = %d status = %d \n", + WL_ERR(("nan ctrl2 config flags resetting failed, ret = %d status = %d \n", ret, cmd_data->status)); goto fail; } - nancfg->ndpe_enabled = false; } /* set CFG CTRL2 flags1 and flags2 */ @@ -3062,7 +3466,7 @@ wl_cfgnan_start_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, 0, WL_NAN_CMD_CFG_NAN_CONFIG2, &(cmd_data->status), true); if (unlikely(ret) || unlikely(cmd_data->status)) { - WL_ERR((" nan ctrl2 config flags setting failed, ret = %d status = %d \n", + WL_ERR(("nan ctrl2 config flags setting failed, ret = %d status = %d \n", ret, cmd_data->status)); goto fail; } @@ -3087,21 +3491,19 @@ wl_cfgnan_start_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, nancfg->nan_enable = true; WL_INFORM_MEM(("[NAN] Enable successfull \n")); + goto done; fail: - /* Enable back TDLS if connected interface is <= 1 */ - wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_DELETE, false); - - /* reset conditon variable */ - nancfg->nan_event_recvd = false; if (unlikely(ret) || unlikely(cmd_data->status)) { - nancfg->nan_enable = false; mutex_lock(&cfg->if_sync); ret = wl_cfg80211_delete_iface(cfg, WL_IF_TYPE_NAN); if (ret != BCME_OK) { WL_ERR(("failed to delete NDI[%d]\n", ret)); } mutex_unlock(&cfg->if_sync); + if (delayed_work_pending(&cfg->nancfg->nan_nmi_rand)) { + cancel_delayed_work_sync(&cfg->nancfg->nan_nmi_rand); + } if (nancfg->nan_ndp_peer_info) { MFREE(cfg->osh, nancfg->nan_ndp_peer_info, nancfg->max_ndp_count * sizeof(nan_ndp_peer_t)); @@ -3112,7 +3514,24 @@ fail: nancfg->max_ndi_supported * sizeof(*nancfg->ndi)); nancfg->ndi = NULL; } + + ret = wl_cfgnan_stop_handler(ndev, cfg); + if (ret != BCME_OK) { + WL_ERR(("failed to stop nan[%d]\n", ret)); + } + ret = wl_cfgnan_deinit(cfg, dhdp->up); + if (ret != BCME_OK) { + WL_ERR(("failed to de-initialize NAN[%d]\n", ret)); + } + } +done: + /* Enable back TDLS if connected interface is <= 1 */ + wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_DELETE, false); + + /* reset conditon variable */ + nancfg->nan_event_recvd = false; + if (nan_buf) { MFREE(cfg->osh, nan_buf, NAN_IOCTL_BUF_SIZE); } @@ -3144,16 +3563,15 @@ wl_cfgnan_disable(struct bcm_cfg80211 *cfg) ret = wl_cfgnan_stop_handler(ndev, cfg); if (ret == -ENODEV) { - WL_ERR(("Bus is down, no need to proceed\n")); + WL_ERR(("Bus is down, proceed to cleanup\n")); } else if (ret != BCME_OK) { WL_ERR(("failed to stop nan, error[%d]\n", ret)); } ret = wl_cfgnan_deinit(cfg, dhdp->up); - if (ret != BCME_OK) { + if (ret == -ENODEV) { + WL_ERR(("Bus is down, proceed to cleanup\n")); + } else if (ret != BCME_OK) { WL_ERR(("failed to de-initialize NAN[%d]\n", ret)); - if (!dhd_query_bus_erros(dhdp)) { - ASSERT(0); - } } wl_cfgnan_disable_cleanup(cfg); } @@ -3227,6 +3645,9 @@ wl_cfgnan_disable_cleanup(struct bcm_cfg80211 *cfg) /* Delete if any directed nan rtt session */ dhd_rtt_delete_nan_session(dhdp); #endif /* RTT_SUPPORT */ + if (delayed_work_pending(&nancfg->nan_nmi_rand)) { + cancel_delayed_work_sync(&nancfg->nan_nmi_rand); + } /* Clear the NDP ID array and dp count */ for (i = 0; i < NAN_MAX_NDP_PEER; i++) { nancfg->ndp_id[i] = 0; @@ -3270,9 +3691,8 @@ wl_cfgnan_delayed_disable(struct work_struct *work) } else { WL_INFORM_MEM(("nan is in disabled state\n")); } - rtnl_unlock(); - DHD_NAN_WAKE_UNLOCK(cfg->pub); + rtnl_unlock(); return; } @@ -3293,12 +3713,6 @@ wl_cfgnan_stop_handler(struct net_device *ndev, NAN_DBG_ENTER(); NAN_MUTEX_LOCK(); - if (!nancfg->nan_enable) { - WL_INFORM(("Nan is not enabled\n")); - ret = BCME_OK; - goto fail; - } - if (dhdp->up != DHD_BUS_DOWN) { /* * Framework doing cleanup(iface remove) on disable command, @@ -3498,6 +3912,17 @@ wl_cfgnan_config_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, goto fail; } } + + /* Set NAN 3.1 Instant channel */ + if (cmd_data->instant_chspec) { + ret = wl_cfgnan_set_instant_chanspec(cmd_data, nan_iov_data); + if (unlikely(ret)) { + WL_ERR(("NAN 3.1 Instant communication channel sub_cmd set failed\n")); + goto fail; + } + nan_buf->count++; + } + nan_buf->is_set = true; nan_buf_size -= nan_iov_data->nan_iov_len; @@ -3515,6 +3940,27 @@ wl_cfgnan_config_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, WL_DBG(("No commands to send\n")); } + /* NAN 3.1 Instant communication config mode */ + if (nan_attr_mask & NAN_ATTR_INSTANT_MODE_CONFIG) { + uint8 set; + uint32 flags1 = WL_NAN_CTRL2_FLAG1_INSTANT_MODE; + + if (cmd_data->instant_mode_en) { + set = TRUE; + } else { + set = FALSE; + } + /* trigger nan ctrl2 iovar to config NAN 3.1 instant mode */ + ret = wl_cfgnan_config_control_flag(ndev, cfg, flags1, + 0, WL_NAN_CMD_CFG_NAN_CONFIG2, + &(cmd_data->status), set); + if (unlikely(ret) || unlikely(cmd_data->status)) { + WL_ERR(("nan ctrl2 config flags setting failed, ret = %d status = %d \n", + ret, cmd_data->status)); + goto fail; + } + } + if ((!cmd_data->bmap) || (cmd_data->avail_params.duration == NAN_BAND_INVALID) || (!cmd_data->chanspec[0])) { WL_TRACE(("mandatory arguments are not present to set avail\n")); @@ -3539,59 +3985,10 @@ wl_cfgnan_config_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, } if (cmd_data->nmi_rand_intvl > 0) { -#ifdef WL_NAN_ENABLE_MERGE - /* Cluster merge enable/disable are being set using nmi random interval config param - * If MSB(31st bit) is set that indicates cluster merge enable/disable config is set - * MSB 30th bit indicates cluser merge enable/disable value to set in firmware - */ - if (cmd_data->nmi_rand_intvl & NAN_NMI_RAND_PVT_CMD_VENDOR) { - uint8 merge_enable; - uint8 lwt_mode_enable; - int status = BCME_OK; - - merge_enable = !!(cmd_data->nmi_rand_intvl & - NAN_NMI_RAND_CLUSTER_MERGE_ENAB); - ret = wl_cfgnan_set_enable_merge(bcmcfg_to_prmry_ndev(cfg), cfg, - merge_enable, &status); - if (unlikely(ret) || unlikely(status)) { - WL_ERR(("Enable merge: failed to set config request [%d]\n", ret)); - /* As there is no cmd_reply, check if error is in status or ret */ - if (status) { - ret = status; - } - goto fail; - } - - lwt_mode_enable = !!(cmd_data->nmi_rand_intvl & - NAN_NMI_RAND_AUTODAM_LWT_MODE_ENAB); - - /* set CFG CTRL2 flags1 and flags2 */ - ret = wl_cfgnan_config_control_flag(ndev, cfg, - WL_NAN_CTRL2_FLAG1_AUTODAM_LWT_MODE, - 0, WL_NAN_CMD_CFG_NAN_CONFIG2, - &status, lwt_mode_enable); - if (unlikely(ret) || unlikely(status)) { - WL_ERR(("Enable dam lwt mode: " - "failed to set config request [%d]\n", ret)); - /* As there is no cmd_reply, check if error is in status or ret */ - if (status) { - ret = status; - } - goto fail; - } - - /* reset pvt merge enable bits */ - cmd_data->nmi_rand_intvl &= ~(NAN_NMI_RAND_PVT_CMD_VENDOR | - NAN_NMI_RAND_CLUSTER_MERGE_ENAB | - NAN_NMI_RAND_AUTODAM_LWT_MODE_ENAB); - } -#endif /* WL_NAN_ENABLE_MERGE */ - - if (cmd_data->nmi_rand_intvl) { - /* run time nmi rand not supported as of now. - * Only during nan enable/iface-create rand mac is used - */ - WL_ERR(("run time nmi rand not supported, ignoring for now\n")); + ret = wl_cfgnan_config_nmi_rand_mac(ndev, cfg, cmd_data); + if (unlikely(ret)) { + WL_ERR(("Failed to config nmi random interval\n")); + goto fail; } } @@ -4038,6 +4435,8 @@ wl_cfgnan_reset_remove_ranging_instance(struct bcm_cfg80211 *cfg, bzero(ranging_inst, sizeof(*ranging_inst)); } else { ranging_inst->range_status = NAN_RANGING_REQUIRED; + /* Reset back to Init role for pending geof target */ + ranging_inst->range_role = NAN_RANGING_ROLE_INITIATOR; /* resolve range role concurrency */ WL_INFORM_MEM(("Resolving Role Concurrency constraint, peer : " MACDBG "\n", MAC2STRDBG(&ranging_inst->peer_addr))); @@ -4294,10 +4693,9 @@ wl_cfgnan_suspend_all_geofence_rng_sessions(struct net_device *ndev, struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub); - WL_INFORM_MEM(("Suspending all geofence sessions: " + WL_MEM(("Suspending all geofence sessions: " "suspend_reason = %d\n", suspend_reason)); - cancel_flags |= NAN_RNG_TERM_FLAG_IMMEDIATE; for (i = 0; i < NAN_MAX_RANGING_INST; i++) { ranging_inst = &cfg->nancfg->nan_ranging_info[i]; /* Cancel Ranging if in progress for rang_inst */ @@ -4345,20 +4743,29 @@ wl_cfgnan_terminate_ranging_session(struct bcm_cfg80211 *cfg, /* Cancel Ranging if in progress for rang_inst */ if (NAN_RANGING_IS_IN_PROG(ranging_inst->range_status)) { ret = wl_cfgnan_cancel_ranging(bcmcfg_to_prmry_ndev(cfg), - cfg, &ranging_inst->range_id, - NAN_RNG_TERM_FLAG_IMMEDIATE, &status); + cfg, &ranging_inst->range_id, + NAN_RNG_TERM_FLAG_IMMEDIATE, &status); if (unlikely(ret) || unlikely(status)) { WL_ERR(("%s:nan range cancel failed ret = %d status = %d\n", __FUNCTION__, ret, status)); + if (ret == BCME_NOTFOUND) { + dhd_rtt_update_geofence_sessions_cnt(dhd, FALSE, + &ranging_inst->peer_addr); + /* Remove ranging instance and clean any corresponding target */ + wl_cfgnan_remove_ranging_instance(cfg, ranging_inst); + } } else { WL_DBG(("Range cancelled \n")); dhd_rtt_update_geofence_sessions_cnt(dhd, FALSE, - &ranging_inst->peer_addr); + &ranging_inst->peer_addr); + /* Remove ranging instance and clean any corresponding target */ + wl_cfgnan_remove_ranging_instance(cfg, ranging_inst); } - } + } else { + /* Remove ranging instance and clean any corresponding target */ + wl_cfgnan_remove_ranging_instance(cfg, ranging_inst); - /* Remove ranging instance and clean any corresponding target */ - wl_cfgnan_remove_ranging_instance(cfg, ranging_inst); + } } /* @@ -4375,7 +4782,8 @@ wl_cfgnan_terminate_all_obsolete_ranging_sessions( for (i = 0; i < NAN_MAX_RANGING_INST; i++) { ranging_inst = &cfg->nancfg->nan_ranging_info[i]; - if (ranging_inst->in_use) { + if (ranging_inst->in_use && + ranging_inst->range_role == NAN_RANGING_ROLE_INITIATOR) { wl_cfgnan_terminate_ranging_session(cfg, ranging_inst); } } @@ -4473,6 +4881,13 @@ wl_cfgnan_trigger_geofencing_ranging(struct net_device *dev, /* TODO: Attempt again over a timer */ err_at = 2; } else { + /* + * Report disc result + * without ranging result, + * on ranging failure + */ + wl_cfgnan_disc_result_on_geofence_cancel(cfg, + ranging_inst); /* Remove target and clean ranging inst */ wl_cfgnan_remove_ranging_instance(cfg, ranging_inst); err_at = 3; @@ -4495,8 +4910,7 @@ wl_cfgnan_trigger_geofencing_ranging(struct net_device *dev, exit: if (ret) { - WL_ERR(("wl_cfgnan_trigger_geofencing_ranging: Failed to " - "trigger ranging, peer: " MACDBG " ret" + WL_ERR(("Failed to trigger ranging, peer: " MACDBG " ret" " = (%d), err_at = %d\n", MAC2STRDBG(peer_addr), ret, err_at)); } @@ -4515,8 +4929,15 @@ wl_cfgnan_check_disc_result_for_ranging(struct bcm_cfg80211 *cfg, bool add_target; *send_disc_result = TRUE; - svc = wl_cfgnan_get_svc_inst(cfg, nan_event_data->sub_id, 0); + if (cfg->nancfg->ranging_enable == FALSE) { + WL_INFORM_MEM(("Nan Ranging not enabled, skip geofence ranging\n")); + *send_disc_result = TRUE; + ret = BCME_NOTENABLED; + goto exit; + } + + svc = wl_cfgnan_get_svc_inst(cfg, nan_event_data->sub_id, 0); if (svc && svc->ranging_required) { nan_ranging_inst_t *ranging_inst; ranging_inst = wl_cfgnan_get_ranging_inst(cfg, @@ -4670,16 +5091,27 @@ wl_cfgnan_handle_ranging_ind(struct bcm_cfg80211 *cfg, uint8 rtt_invalid_state; dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub); rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd); + rtt_geofence_cfg_t* geofence_cfg = &rtt_status->geofence_cfg; int err_at = 0; WL_DBG(("Trigger range response\n")); + WL_INFORM_MEM(("Geofence Session: Ssn Cnt %d, Target Cnt %d, Cur Idx %d\n", + geofence_cfg->geofence_sessions_cnt, geofence_cfg->geofence_target_cnt, + geofence_cfg->cur_target_idx)); + + if (cfg->nancfg->ranging_enable == FALSE) { + WL_ERR(("Nan Ranging not enabled..reject request\n")); + ret = BCME_NOTENABLED; + err_at = 1; + goto done; + } /* Check if ranging is allowed */ rtt_invalid_state = dhd_rtt_invalid_states(ndev, peer_addr); if (rtt_invalid_state != RTT_STATE_VALID) { WL_INFORM_MEM(("Cannot allow ranging due to reason %d \n", rtt_invalid_state)); ret = BCME_NORESOURCE; - err_at = 1; + err_at = 2; goto done; } @@ -4688,7 +5120,7 @@ wl_cfgnan_handle_ranging_ind(struct bcm_cfg80211 *cfg, if (rtt_status && !RTT_IS_STOPPED(rtt_status)) { WL_INFORM_MEM(("Direcetd RTT in progress..reject RNG_REQ\n")); ret = BCME_NORESOURCE; - err_at = 2; + err_at = 3; goto done; } @@ -4696,7 +5128,7 @@ wl_cfgnan_handle_ranging_ind(struct bcm_cfg80211 *cfg, if (dhd_rtt_is_geofence_setup_inprog(dhd)) { WL_INFORM_MEM(("Ranging set up already in progress, " "RNG IND event dropped\n")); - err_at = 3; + err_at = 4; ret = BCME_NOTREADY; goto done; } @@ -4723,7 +5155,7 @@ wl_cfgnan_handle_ranging_ind(struct bcm_cfg80211 *cfg, RTT_GEO_SUSPN_PEER_RTT_TRIGGER, cancel_flags); } else { WL_ERR(("Reject the RNG_REQ_IND in direct rtt initiator role\n")); - err_at = 4; + err_at = 5; ret = BCME_BUSY; goto done; } @@ -4731,7 +5163,7 @@ wl_cfgnan_handle_ranging_ind(struct bcm_cfg80211 *cfg, /* Check if new Ranging session is allowed */ if (dhd_rtt_geofence_sessions_maxed_out(dhd)) { WL_ERR(("Cannot allow more ranging sessions\n")); - err_at = 5; + err_at = 6; ret = BCME_NORESOURCE; goto done; } @@ -4744,7 +5176,7 @@ wl_cfgnan_handle_ranging_ind(struct bcm_cfg80211 *cfg, /* Check if new Ranging session is allowed */ if (dhd_rtt_geofence_sessions_maxed_out(dhd)) { WL_ERR(("Cannot allow more ranging sessions\n")); - err_at = 6; + err_at = 7; ret = BCME_NORESOURCE; goto done; } @@ -4754,7 +5186,7 @@ wl_cfgnan_handle_ranging_ind(struct bcm_cfg80211 *cfg, ASSERT(ranging_inst); if (!ranging_inst) { WL_ERR(("Failed to create ranging instance \n")); - err_at = 7; + err_at = 8; ret = BCME_NORESOURCE; goto done; } @@ -5301,6 +5733,7 @@ wl_cfgnan_sd_params_handler(struct net_device *ndev, /* Security elements */ if (cmd_data->csid) { WL_TRACE(("Cipher suite type is present, pack it\n")); + cmd_data->csid = wl_cfgnan_map_host_csid_to_nan_prot_csid(cmd_data->csid); ret = bcm_pack_xtlv_entry(&pxtlv, nan_buf_size, WL_NAN_XTLV_CFG_SEC_CSID, sizeof(nan_sec_csid_e), (uint8*)&cmd_data->csid, BCM_XTLV_OPTION_ALIGN32); @@ -5310,17 +5743,17 @@ wl_cfgnan_sd_params_handler(struct net_device *ndev, } } - if (cmd_data->ndp_cfg.security_cfg) { + if (cmd_data->sde_control_flag & NAN_SDE_CF_SECURITY_REQUIRED) { if ((cmd_data->key_type == NAN_SECURITY_KEY_INPUT_PMK) || - (cmd_data->key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE)) { + (cmd_data->key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE)) { if (cmd_data->key.data && cmd_data->key.dlen) { WL_TRACE(("optional pmk present, pack it\n")); ret = bcm_pack_xtlv_entry(&pxtlv, nan_buf_size, - WL_NAN_XTLV_CFG_SEC_PMK, cmd_data->key.dlen, - cmd_data->key.data, BCM_XTLV_OPTION_ALIGN32); + WL_NAN_XTLV_CFG_SEC_PMK, cmd_data->key.dlen, + cmd_data->key.data, BCM_XTLV_OPTION_ALIGN32); if (unlikely(ret)) { WL_ERR(("%s: fail to pack WL_NAN_XTLV_CFG_SEC_PMK\n", - __FUNCTION__)); + __FUNCTION__)); goto fail; } } @@ -5333,10 +5766,13 @@ wl_cfgnan_sd_params_handler(struct net_device *ndev, if (cmd_data->scid.data && cmd_data->scid.dlen) { WL_TRACE(("optional scid present, pack it\n")); - ret = bcm_pack_xtlv_entry(&pxtlv, nan_buf_size, WL_NAN_XTLV_CFG_SEC_SCID, +#ifdef WL_NAN_DEBUG + prhex("SCID: ", cmd_data->scid.data, cmd_data->scid.dlen); +#endif /* WL_NAN_DEBUG */ + ret = bcm_pack_xtlv_entry(&pxtlv, nan_buf_size, WL_NAN_XTLV_CFG_SEC_PMKID, cmd_data->scid.dlen, cmd_data->scid.data, BCM_XTLV_OPTION_ALIGN32); if (unlikely(ret)) { - WL_ERR(("%s: fail to pack WL_NAN_XTLV_CFG_SEC_SCID\n", __FUNCTION__)); + WL_ERR(("%s: fail to pack WL_NAN_XTLV_CFG_SEC_PMKID\n", __FUNCTION__)); goto fail; } } @@ -5415,14 +5851,20 @@ wl_cfgnan_aligned_data_size_of_opt_dp_params(struct bcm_cfg80211 *cfg, uint16 *d *data_size += ALIGN_SIZE(cmd_data->svc_info.dlen + NAN_XTLV_ID_LEN_SIZE, 4); } } - if (cmd_data->key.dlen) + if (cmd_data->key.dlen) { *data_size += ALIGN_SIZE(cmd_data->key.dlen + NAN_XTLV_ID_LEN_SIZE, 4); - if (cmd_data->csid) + } + if (cmd_data->csid) { *data_size += ALIGN_SIZE(sizeof(nan_sec_csid_e) + NAN_XTLV_ID_LEN_SIZE, 4); + } + if (cmd_data->scid.dlen) { + *data_size += ALIGN_SIZE(cmd_data->scid.dlen + NAN_XTLV_ID_LEN_SIZE, 4); + } *data_size += ALIGN_SIZE(WL_NAN_SVC_HASH_LEN + NAN_XTLV_ID_LEN_SIZE, 4); return ret; } + int wl_cfgnan_svc_get_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, uint16 cmd_id, nan_discover_cmd_data_t *cmd_data) @@ -6178,6 +6620,11 @@ wl_cfgnan_get_capability(struct net_device *ndev, capabilities->is_ndp_security_supported = fw_cap->is_ndp_security_supported; capabilities->ndp_supported_bands = fw_cap->ndp_supported_bands; capabilities->cipher_suites_supported = fw_cap->cipher_suites_supported_mask; +#ifdef WL_NAN_INSTANT_MODE + if (fw_cap->flags1 & WL_NAN_FW_CAP_FLAG1_INSTANT_MODE) { + capabilities->is_instant_mode_supported = true; + } +#endif /* WL_NAN_INSTANT_MODE */ if (fw_cap->flags1 & WL_NAN_FW_CAP_FLAG1_NDPE) { capabilities->ndpe_attr_supported = true; } @@ -6199,10 +6646,13 @@ wl_cfgnan_get_capablities_handler(struct net_device *ndev, NAN_DBG_ENTER(); + RETURN_EIO_IF_NOT_UP(cfg); + /* Do not query fw about nan if feature is not supported */ if (!FW_SUPPORTED(dhdp, nan)) { WL_DBG(("NAN is not supported\n")); - return ret; + ret = BCME_NOTUP; + goto fail; } if (cfg->nancfg->nan_init_state) { @@ -6225,7 +6675,6 @@ wl_cfgnan_get_capablities_handler(struct net_device *ndev, if (ret != BCME_OK) { WL_ERR(("NAN init state: %d, failed to get capability from FW[%d]\n", cfg->nancfg->nan_init_state, ret)); - goto exit; } WL_ERR(("De-Initializing NAN\n")); ret = wl_cfgnan_deinit(cfg, dhdp->up); @@ -6253,7 +6702,10 @@ exit: capabilities->max_sdea_service_specific_info_len = MAX_SDEA_SVC_INFO_LEN; capabilities->max_subscribe_address = MAX_SUBSCRIBE_ADDRESS; capabilities->cipher_suites_supported = WL_NAN_CIPHER_SUITE_SHARED_KEY_128_MASK; - capabilities->max_scid_len = MAX_SCID_LEN; +#ifdef WL_NAN_INSTANT_MODE + capabilities->cipher_suites_supported |= (WL_NAN_CIPHER_SUITE_PUBLIC_KEY_128_MASK); +#endif /* WL_NAN_INSTANT_MODE */ + capabilities->max_scid_len = NAN_MAX_SCID_BUF_LEN; capabilities->is_ndp_security_supported = true; capabilities->ndp_supported_bands = NDP_SUPPORTED_BANDS; capabilities->ndpe_attr_supported = false; @@ -6268,6 +6720,8 @@ bool wl_cfgnan_is_enabled(struct bcm_cfg80211 *cfg) if (nancfg) { if (nancfg->nan_init_state && nancfg->nan_enable) { return TRUE; + } else if (nancfg->nan_init_state && !nancfg->nan_enable) { + WL_ERR(("Not expected state: init state is set but enable is not set\n")); } } @@ -6645,6 +7099,38 @@ end: return; } +/* Converts NAN Andrid host Cipher Suite type to NAN protocol Cipher type format */ +static uint8 +wl_cfgnan_map_host_csid_to_nan_prot_csid(uint8 host_csid) +{ + uint8 idx = 0; + uint8 prot_csid = NAN_SEC_ALGO_NONE; + + for (idx = 0; idx < ARRAYSIZE(nan_csid_map_table); idx++) { + if (nan_csid_map_table[idx].host_csid == host_csid) { + prot_csid = nan_csid_map_table[idx].fw_csid; + break; + } + } + return prot_csid; +} + +/* Converts NAN protocol Cipher type to NAN Andrid host Cipher Suite format */ +static uint8 +wl_cfgnan_map_nan_prot_csid_to_host_csid(uint8 prot_csid) +{ + uint8 idx = 0; + uint8 host_csid = NAN_SEC_ALGO_NONE; + + for (idx = 0; idx < ARRAYSIZE(nan_csid_map_table); idx++) { + if (nan_csid_map_table[idx].fw_csid == prot_csid) { + host_csid = nan_csid_map_table[idx].host_csid; + break; + } + } + return host_csid; +} + int wl_cfgnan_data_path_request_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, nan_datapath_cmd_data_t *cmd_data, @@ -6687,8 +7173,14 @@ wl_cfgnan_data_path_request_handler(struct net_device *ndev, /* cancel any ongoing RTT session with peer * as we donot support DP and RNG to same peer */ - wl_cfgnan_handle_dp_ranging_concurrency(cfg, &cmd_data->mac_addr, + ret = wl_cfgnan_handle_dp_ranging_concurrency(cfg, &cmd_data->mac_addr, RTT_GEO_SUSPN_HOST_NDP_TRIGGER); + if (ret != BCME_OK) { + WL_ERR(("%s: failed to handler dp ranging concurrency, " + "peer_addr: " MACDBG ", err = %d\n", __func__, + ret, MAC2STRDBG(&cmd_data->mac_addr))); + goto fail; + } #endif /* RTT_SUPPORT */ nan_buf = MALLOCZ(cfg->osh, data_size); @@ -6817,6 +7309,7 @@ wl_cfgnan_data_path_request_handler(struct net_device *ndev, if (cmd_data->csid) { WL_TRACE(("Cipher suite type is present, pack it\n")); + cmd_data->csid = wl_cfgnan_map_host_csid_to_nan_prot_csid(cmd_data->csid); ret = bcm_pack_xtlv_entry(&pxtlv, &nan_buf_size, WL_NAN_XTLV_CFG_SEC_CSID, sizeof(nan_sec_csid_e), (uint8*)&cmd_data->csid, BCM_XTLV_OPTION_ALIGN32); @@ -6825,6 +7318,20 @@ wl_cfgnan_data_path_request_handler(struct net_device *ndev, goto fail; } } + if (cmd_data->scid.dlen && cmd_data->scid.data) { + WL_TRACE(("SCID present, pack it\n")); +#ifdef WL_NAN_DEBUG + prhex("SCID: ", cmd_data->scid.data, cmd_data->scid.dlen); +#endif /* WL_NAN_DEBUG */ + ret = bcm_pack_xtlv_entry(&pxtlv, &nan_buf_size, + WL_NAN_XTLV_CFG_SEC_PMKID, cmd_data->scid.dlen, + cmd_data->scid.data, + BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + WL_ERR(("unable to process scid info: %d\n", ret)); + goto fail; + } + } if (cmd_data->ndp_cfg.security_cfg) { if ((cmd_data->key_type == NAN_SECURITY_KEY_INPUT_PMK) || @@ -7034,8 +7541,14 @@ wl_cfgnan_data_path_response_handler(struct net_device *ndev, /* cancel any ongoing RTT session with peer * as we donot support DP and RNG to same peer */ - wl_cfgnan_handle_dp_ranging_concurrency(cfg, &cmd_data->mac_addr, + ret = wl_cfgnan_handle_dp_ranging_concurrency(cfg, &cmd_data->mac_addr, RTT_GEO_SUSPN_HOST_NDP_TRIGGER); + if (ret != BCME_OK) { + WL_ERR(("%s: failed to handler dp ranging concurrency, " + "peer_addr: " MACDBG ", err = %d\n", __func__, + ret, MAC2STRDBG(&cmd_data->mac_addr))); + goto fail; + } #endif /* RTT_SUPPORT */ /* Retrieve mac from given iface name */ wdev = wl_cfg80211_get_wdev_from_ifname(cfg, @@ -7108,6 +7621,7 @@ wl_cfgnan_data_path_response_handler(struct net_device *ndev, /* Security elements */ if (cmd_data->csid) { WL_TRACE(("Cipher suite type is present, pack it\n")); + cmd_data->csid = wl_cfgnan_map_host_csid_to_nan_prot_csid(cmd_data->csid); ret = bcm_pack_xtlv_entry(&pxtlv, &nan_buf_size, WL_NAN_XTLV_CFG_SEC_CSID, sizeof(nan_sec_csid_e), (uint8*)&cmd_data->csid, BCM_XTLV_OPTION_ALIGN32); @@ -7116,6 +7630,17 @@ wl_cfgnan_data_path_response_handler(struct net_device *ndev, goto fail; } } + if (cmd_data->scid.dlen && cmd_data->scid.data) { + WL_ERR(("SCID present, pack it\n")); + ret = bcm_pack_xtlv_entry(&pxtlv, &nan_buf_size, + WL_NAN_XTLV_CFG_SEC_PMKID, cmd_data->scid.dlen, + cmd_data->scid.data, + BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + WL_ERR(("unable to process scid info: %d\n", ret)); + goto fail; + } + } if (cmd_data->ndp_cfg.security_cfg) { if ((cmd_data->key_type == NAN_SECURITY_KEY_INPUT_PMK) || @@ -7423,7 +7948,28 @@ wl_cfgnan_clear_peer_ranging(struct bcm_cfg80211 *cfg, err = wl_cfgnan_cancel_ranging(ndev, cfg, &rng_inst->range_id, NAN_RNG_TERM_FLAG_IMMEDIATE, &status); - wl_cfgnan_reset_remove_ranging_instance(cfg, rng_inst); + if (unlikely(err) || unlikely(status)) { + WL_ERR(("%s:nan range cancel failed, rng_id = %d ret = %d status = %d\n", + __FUNCTION__, rng_inst->range_id, err, status)); + WL_ERR(("%s:nan range cancel failed, rng_id = %d " + "ret = %d status = %d, peer addr: " MACDBG "\n", + __FUNCTION__, rng_inst->range_id, err, status, + MAC2STRDBG(&rng_inst->peer_addr))); + if (err == BCME_NOTFOUND) { + dhd_rtt_update_geofence_sessions_cnt(dhdp, FALSE, + &rng_inst->peer_addr); + /* Remove ranging instance and clean any corresponding target */ + wl_cfgnan_remove_ranging_instance(cfg, rng_inst); + err = BCME_OK; + } + } else { + WL_DBG(("%s: Range cancelled, range_id = %d\n", + __func__, rng_inst->range_id)); + dhd_rtt_update_geofence_sessions_cnt(dhdp, FALSE, + &rng_inst->peer_addr); + /* Remove ranging instance and clean any corresponding target */ + wl_cfgnan_remove_ranging_instance(cfg, rng_inst); + } } if (err) { @@ -7521,6 +8067,7 @@ wl_nan_dp_cmn_event_data(struct bcm_cfg80211 *cfg, void *event_data, nan_event_data->pub_id = ev_dp->pub_id; WL_TRACE(("security: %d\n", ev_dp->security)); nan_event_data->security = ev_dp->security; + WL_INFORM_MEM(("dp status: %d\n", ev_dp->status)); /* Store initiator_ndi, required for data_path_response_request */ ret = memcpy_s(&cfg->nancfg->initiator_ndi, ETHER_ADDR_LEN, @@ -7546,7 +8093,7 @@ wl_nan_dp_cmn_event_data(struct bcm_cfg80211 *cfg, void *event_data, } } else { /* type is multicast */ - WL_INFORM_MEM(("NDP ID: %d\n", ev_dp->mc_id)); + WL_INFORM_MEM(("MC ID: %d\n", ev_dp->mc_id)); nan_event_data->ndp_id = ev_dp->mc_id; WL_TRACE(("PEER NMI: " MACDBG "\n", MAC2STRDBG(ev_dp->peer_nmi.octet))); @@ -7570,15 +8117,21 @@ wl_nan_dp_cmn_event_data(struct bcm_cfg80211 *cfg, void *event_data, goto fail; } #endif /* WL_NAN_DISC_CACHE */ - /* Add peer to data ndp peer list */ - wl_cfgnan_data_add_peer(cfg, &ev_dp->peer_nmi); #ifdef RTT_SUPPORT /* cancel any ongoing RTT session with peer * as we donot support DP and RNG to same peer */ - wl_cfgnan_handle_dp_ranging_concurrency(cfg, &ev_dp->peer_nmi, - RTT_GEO_SUSPN_PEER_NDP_TRIGGER); + ret = wl_cfgnan_handle_dp_ranging_concurrency(cfg, &ev_dp->peer_nmi, + RTT_GEO_SUSPN_PEER_NDP_TRIGGER); + if (ret != BCME_OK) { + WL_ERR(("%s: failed to handler dp ranging concurrency," + " peer addr: " MACDBG ", err = %d\n", __func__, + MAC2STRDBG(&ev_dp->peer_nmi), ret)); + goto fail; + } #endif /* RTT_SUPPORT */ + /* Add peer to data ndp peer list */ + wl_cfgnan_data_add_peer(cfg, &ev_dp->peer_nmi); } else if (event_num == WL_NAN_EVENT_DATAPATH_ESTB) { *hal_event_id = GOOGLE_NAN_EVENT_DATA_CONFIRMATION; if (ev_dp->role == NAN_DP_ROLE_INITIATOR) { @@ -7608,7 +8161,6 @@ wl_nan_dp_cmn_event_data(struct bcm_cfg80211 *cfg, void *event_data, wl_cfgnan_data_set_peer_dp_state(cfg, &ev_dp->peer_nmi, NAN_PEER_DP_CONNECTED); wl_cfgnan_update_dp_info(cfg, true, nan_event_data->ndp_id); - wl_cfgnan_get_stats(cfg); } else if (ev_dp->status == NAN_NDP_STATUS_REJECT) { nan_event_data->status = NAN_DP_REQUEST_REJECT; #ifdef WL_NAN_DISC_CACHE @@ -7660,11 +8212,11 @@ wl_nan_dp_cmn_event_data(struct bcm_cfg80211 *cfg, void *event_data, } #endif /* WL_NAN_DISC_CACHE */ /* Remove peer from data ndp peer list */ + WL_INFORM_MEM(("DP_END for NDP ID %d REMOTE_NMI: " MACDBG " with %s\n", + nan_event_data->ndp_id, MAC2STRDBG(&ev_dp->peer_nmi), + nan_event_cause_to_str(ev_dp->event_cause))); wl_cfgnan_data_remove_peer(cfg, &ev_dp->peer_nmi); wl_cfgnan_update_dp_info(cfg, false, nan_event_data->ndp_id); - WL_INFORM_MEM(("DP_END for REMOTE_NMI: " MACDBG " with %s\n", - MAC2STRDBG(&ev_dp->peer_nmi), - nan_event_cause_to_str(ev_dp->event_cause))); #ifdef RTT_SUPPORT rng_inst = wl_cfgnan_check_for_ranging(cfg, &ev_dp->peer_nmi); if (rng_inst) { @@ -7685,6 +8237,21 @@ fail: return ret; } +static void +wl_cfgnan_event_disc_cache_timeout(struct bcm_cfg80211 *cfg, + nan_event_data_t *nan_event_data) +{ + int ret = BCME_OK; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) + ret = wl_cfgvendor_send_nan_event(cfg->wdev->wiphy, bcmcfg_to_prmry_ndev(cfg), + GOOGLE_NAN_EVENT_MATCH_EXPIRY, nan_event_data); + if (ret != BCME_OK) { + WL_ERR(("Failed to send event to nan hal\n")); + } +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ + return; +} + #ifdef RTT_SUPPORT static int wl_cfgnan_event_disc_result(struct bcm_cfg80211 *cfg, @@ -7921,11 +8488,13 @@ wl_cfgnan_process_range_report(struct bcm_cfg80211 *cfg, rng_inst->geof_retry_count = 0; /* * Suspend and trigger other targets, + * if setup not in prog and, * if running sessions maxed out and more * pending targets waiting for trigger */ - if (dhd_rtt_geofence_sessions_maxed_out(dhd) && - (dhd_rtt_get_geofence_target_cnt(dhd) >= + if ((!dhd_rtt_is_geofence_setup_inprog(dhd)) && + dhd_rtt_geofence_sessions_maxed_out(dhd) && + (dhd_rtt_get_geofence_target_cnt(dhd) > dhd_rtt_get_geofence_max_sessions(dhd))) { /* * Update the target idx first, before suspending current target @@ -7952,21 +8521,21 @@ exit: static void wl_nan_print_status(wl_nan_conf_status_t *nstatus) { - WL_INFORM_MEM(("> NMI: " MACDBG " Cluster_ID: " MACDBG "\n", + WL_DBG(("> NMI: " MACDBG " Cluster_ID: " MACDBG "\n", MAC2STRDBG(nstatus->nmi.octet), MAC2STRDBG(nstatus->cid.octet))); - WL_INFORM_MEM(("> NAN Device Role %s\n", nan_role_to_str(nstatus->role))); - WL_INFORM_MEM(("> Social channels: %d, %d\n", + WL_DBG(("> NAN Device Role %s\n", nan_role_to_str(nstatus->role))); + WL_DBG(("> Social channels: %d, %d\n", nstatus->social_chans[0], nstatus->social_chans[1])); - WL_INFORM_MEM(("> Master_rank: " NMRSTR " AMR : " NMRSTR " Hop Count : %d, AMBTT : %d\n", + WL_DBG(("> Master_rank: " NMRSTR " AMR : " NMRSTR " Hop Count : %d, AMBTT : %d\n", NMR2STR(nstatus->mr), NMR2STR(nstatus->amr), nstatus->hop_count, nstatus->ambtt)); - WL_INFORM_MEM(("> Cluster TSF_H: %x , Cluster TSF_L: %x\n", + WL_DBG(("> Cluster TSF_H: %x , Cluster TSF_L: %x\n", nstatus->cluster_tsf_h, nstatus->cluster_tsf_l)); } @@ -7995,6 +8564,11 @@ wl_cfgnan_clear_nan_event_data(struct bcm_cfg80211 *cfg, nan_event_data->sde_svc_info.dlen); nan_event_data->sde_svc_info.data = NULL; } + if (nan_event_data->scid.data) { + MFREE(cfg->osh, nan_event_data->scid.data, + nan_event_data->scid.dlen); + nan_event_data->scid.data = NULL; + } MFREE(cfg->osh, nan_event_data, sizeof(*nan_event_data)); } @@ -8087,7 +8661,7 @@ wl_cfgnan_reset_geofence_ranging(struct bcm_cfg80211 *cfg, mutex_lock(&rtt_status->rtt_mutex); } - WL_INFORM_MEM(("wl_cfgnan_reset_geofence_ranging: " + WL_MEM(("wl_cfgnan_reset_geofence_ranging: " "sched_reason = %d, cur_idx = %d, target_cnt = %d\n", sched_reason, rtt_status->geofence_cfg.cur_target_idx, rtt_status->geofence_cfg.geofence_target_cnt)); @@ -8106,7 +8680,7 @@ wl_cfgnan_reset_geofence_ranging(struct bcm_cfg80211 *cfg, * Remove all valid ranging inst */ if (rng_inst) { - WL_INFORM_MEM(("Removing Ranging Instance " MACDBG "\n", + WL_MEM(("Removing Ranging Instance " MACDBG "\n", MAC2STRDBG(&(rng_inst->peer_addr)))); bzero(rng_inst, sizeof(*rng_inst)); } @@ -8162,7 +8736,7 @@ wl_cfgnan_reset_geofence_ranging(struct bcm_cfg80211 *cfg, exit: if (reset_req_drop) { - WL_INFORM_MEM(("reset geofence req dropped, reason = %d\n", + WL_MEM(("reset geofence req dropped, reason = %d\n", reset_req_drop)); } if (need_rtt_mutex == TRUE) { @@ -8262,8 +8836,8 @@ wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, UNUSED_PARAMETER(status); NAN_DBG_ENTER(); - if (!event || !event_data) { - WL_ERR(("event data is NULL\n")); + if (!event) { + WL_ERR(("event is NULL\n")); return -EINVAL; } @@ -8271,6 +8845,15 @@ wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, event_num = ntoh32(event->reason); data_len = ntoh32(event->datalen); + if (!event_data) { + WL_ERR(("event data is NULL for event: %d\n", event_num)); + return -EINVAL; + } + if (!data_len) { + WL_ERR(("Invalid event data len for event: %d\n", event_num)); + return -EINVAL; + } + #ifdef RTT_SUPPORT if (event_num == WL_NAN_EVENT_RNG_REQ_IND) { @@ -8301,7 +8884,8 @@ wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, #endif /* WL_NAN_DEBUG */ if (!cfg->nancfg->nan_init_state) { - WL_ERR(("nan is not in initialized state, dropping nan related events\n")); + WL_ERR(("nan is not in initialized state, dropping nan related event num: %d, " + "type: %d\n", event_num, event_type)); ret = BCME_OK; goto exit; } @@ -8325,9 +8909,9 @@ wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, /* get nan status info as-is */ bcm_xtlv_t *xtlv = (bcm_xtlv_t *)event_data; wl_nan_conf_status_t *nstatus = (wl_nan_conf_status_t *)xtlv->data; - WL_INFORM_MEM((">> Nan Mac Event Received: %s (num=%d, len=%d)\n", + WL_DBG((">> Nan Mac Event Received: %s (num=%d, len=%d)\n", nan_event_to_str(event_num), event_num, data_len)); - WL_INFORM_MEM(("Nan Device Role %s\n", nan_role_to_str(nstatus->role))); + WL_DBG(("Nan Device Role %s\n", nan_role_to_str(nstatus->role))); /* Mapping to common struct between DHD and HAL */ nan_event_data->enabled = nstatus->enabled; ret = memcpy_s(&nan_event_data->local_nmi, ETHER_ADDR_LEN, @@ -8470,29 +9054,39 @@ wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, goto exit; } #ifdef RTT_SUPPORT - } else if (txs->type == WL_NAN_FRM_TYPE_RNG_RESP) { + } else if ((txs->type == WL_NAN_FRM_TYPE_RNG_RESP) || + (txs->type == WL_NAN_FRM_TYPE_RNG_REQ) || + (txs->type == WL_NAN_FRM_TYPE_RNG_TERM)) { xtlv = (bcm_xtlv_t *)(txs->opt_tlvs); if (txs->opt_tlvs_len && xtlv->id == WL_NAN_XTLV_RNG_TXS) { - wl_nan_range_txs_t* txs_rng_resp = (wl_nan_range_txs_t*)xtlv->data; - nan_ranging_inst_t *rng_inst = - wl_cfgnan_get_rng_inst_by_id(cfg, txs_rng_resp->range_id); - if (rng_inst && - NAN_RANGING_SETUP_IS_IN_PROG(rng_inst->range_status)) { - /* Unset ranging set up in progress */ - dhd_rtt_update_geofence_sessions_cnt(dhd, FALSE, - &rng_inst->peer_addr); - if (txs->status == WL_NAN_TXS_SUCCESS) { - /* range set up is over, move range in progress */ - rng_inst->range_status = - NAN_RANGING_SESSION_IN_PROGRESS; - /* Increment geofence session count */ - dhd_rtt_update_geofence_sessions_cnt(dhd, - TRUE, NULL); - WL_DBG(("Txs for range resp, rng_id = %d\n", - rng_inst->range_id)); - } else { - wl_cfgnan_reset_remove_ranging_instance(cfg, - rng_inst); + wl_nan_range_txs_t* txs_rng = (wl_nan_range_txs_t*)xtlv->data; + WL_INFORM_MEM(("TXS for type %s(%d), status %d rng_id %d\n", + nan_frm_type_to_str(txs->type), txs->type, + txs->status, txs_rng->range_id)); + if (txs->type == WL_NAN_FRM_TYPE_RNG_RESP) { + nan_ranging_inst_t *rng_inst = + wl_cfgnan_get_rng_inst_by_id + (cfg, txs_rng->range_id); + if (rng_inst && + NAN_RANGING_SETUP_IS_IN_PROG + (rng_inst->range_status)) { + /* Unset ranging set up in progress */ + dhd_rtt_update_geofence_sessions_cnt(dhd, FALSE, + &rng_inst->peer_addr); + if (txs->status == WL_NAN_TXS_SUCCESS) { + /* + * range set up is over, + * move range in progress + */ + rng_inst->range_status = + NAN_RANGING_SESSION_IN_PROGRESS; + /* Increment geofence session count */ + dhd_rtt_update_geofence_sessions_cnt(dhd, + TRUE, NULL); + } else { + wl_cfgnan_reset_remove_ranging_instance(cfg, + rng_inst); + } } } } else { @@ -8533,6 +9127,9 @@ wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, WL_INFORM_MEM(("WL_NAN_EVENT_DISC_CACHE_TIMEOUT peer: " MACDBG " l_id:%d r_id:%d\n", MAC2STRDBG(&cache_entry->r_nmi_addr), cache_entry->l_sub_id, cache_entry->r_pub_id)); + nan_event_data->sub_id = cache_entry->l_sub_id; + nan_event_data->pub_id = cache_entry->r_pub_id; + wl_cfgnan_event_disc_cache_timeout(cfg, nan_event_data); #ifdef RTT_SUPPORT wl_cfgnan_ranging_clear_publish(cfg, &cache_entry->r_nmi_addr, cache_entry->l_sub_id); @@ -8543,7 +9140,7 @@ wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, entry_idx++; } } - break; + goto exit; } #ifdef RTT_SUPPORT case WL_NAN_EVENT_RNG_REQ_IND: { @@ -8601,9 +9198,18 @@ wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, &rng_inst->peer_addr); if (!wl_cfgnan_geofence_retry_check(rng_inst, range_term->reason_code)) { - /* Report on ranging failure */ - wl_cfgnan_disc_result_on_geofence_cancel(cfg, - rng_inst); + if ((range_term->reason_code != + NAN_RNG_TERM_USER_REQ) && + range_term->reason_code != + NAN_RNG_TERM_PEER_REQ) { + /* + * Report on ranging failure + * Dont report for self or peer + * termination reason codes + */ + wl_cfgnan_disc_result_on_geofence_cancel + (cfg, rng_inst); + } WL_TRACE(("Reset the state on terminate\n")); geofence_target = dhd_rtt_get_geofence_target(dhd, &rng_inst->peer_addr, &index); @@ -8664,8 +9270,9 @@ wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, * and max sessions, not running already, * schedule next target for RTT */ - if ((!dhd_rtt_nan_all_directed_sessions_triggered(dhd)) && - dhd_rtt_nan_directed_sessions_allowed(dhd)) { + if (dhd_rtt_is_taget_list_mode_nan(dhd) && + !dhd_rtt_nan_all_directed_sessions_triggered(dhd) && + dhd_rtt_nan_directed_sessions_allowed(dhd)) { /* Find and set next directed target */ dhd_rtt_set_next_target_idx(dhd, (dhd_rtt_get_cur_target_idx(dhd) + 1)); @@ -8720,6 +9327,14 @@ wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, /* No action -intentionally added to avoid prints when this event is rcvd */ break; } + case WL_NAN_EVENT_SCHED_CHANGE: + { + tlvs_offset = OFFSETOF(wl_nan_ev_sched_info_t, opt_tlvs) + + OFFSETOF(bcm_xtlv_t, data); + nan_opts_len = data_len - tlvs_offset; + xtlv_opt = BCM_IOV_CMD_OPT_ALIGN_NONE; + break; + } default: WL_ERR_RLMT(("WARNING: unimplemented NAN APP EVENT = %d\n", event_num)); ret = BCME_ERROR; @@ -8736,6 +9351,11 @@ wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, } } + if (event_num == WL_NAN_EVENT_SCHED_CHANGE) { + /* no need to send this event to HAL */ + goto exit; + } + #ifdef WL_NAN_DISC_CACHE if (hal_event_id == GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH) { #ifdef RTT_SUPPORT @@ -8804,16 +9424,15 @@ wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg, #endif /* WL_NAN_DISC_CACHE */ WL_TRACE(("Send up %s (%d) data to HAL, hal_event_id=%d\n", - nan_event_to_str(event_num), event_num, hal_event_id)); + nan_event_to_str(event_num), event_num, hal_event_id)); #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) ret = wl_cfgvendor_send_nan_event(cfg->wdev->wiphy, bcmcfg_to_prmry_ndev(cfg), hal_event_id, nan_event_data); if (ret != BCME_OK) { WL_ERR(("Failed to send event to nan hal, %s (%d)\n", - nan_event_to_str(event_num), event_num)); + nan_event_to_str(event_num), event_num)); } #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ - exit: wl_cfgnan_clear_nan_event_data(cfg, nan_event_data); @@ -8828,21 +9447,17 @@ wl_cfgnan_cache_disc_result(struct bcm_cfg80211 *cfg, void * data, u16 *disc_cache_update_flags) { nan_event_data_t* disc = (nan_event_data_t*)data; - int i, add_index = 0; + int i, add_index = NAN_MAX_CACHE_DISC_RESULT; int ret = BCME_OK; wl_nancfg_t *nancfg = cfg->nancfg; nan_disc_result_cache *disc_res = nancfg->nan_disc_cache; - *disc_cache_update_flags = 0; + bool new_entry = TRUE; + *disc_cache_update_flags = 0; if (!nancfg->nan_enable) { WL_DBG(("nan not enabled")); return BCME_NOTENABLED; } - if (nancfg->nan_disc_count == NAN_MAX_CACHE_DISC_RESULT) { - WL_DBG(("cache full")); - ret = BCME_NORESOURCE; - goto done; - } for (i = 0; i < NAN_MAX_CACHE_DISC_RESULT; i++) { if (!disc_res[i].valid) { @@ -8850,77 +9465,104 @@ wl_cfgnan_cache_disc_result(struct bcm_cfg80211 *cfg, void * data, continue; } if (!memcmp(&disc_res[i].peer, &disc->remote_nmi, ETHER_ADDR_LEN) && - !memcmp(disc_res[i].svc_hash, disc->svc_name, WL_NAN_SVC_HASH_LEN)) { + !memcmp(disc_res[i].svc_hash, disc->svc_name, WL_NAN_SVC_HASH_LEN) && + (disc_res[i].pub_id == disc->pub_id) && + (disc_res[i].sub_id == disc->sub_id)) { WL_DBG(("cache entry already present, i = %d", i)); /* Update needed parameters here */ if (disc_res[i].sde_control_flag != disc->sde_control_flag) { - disc_res[i].sde_control_flag = disc->sde_control_flag; *disc_cache_update_flags |= NAN_DISC_CACHE_PARAM_SDE_CONTROL; } - ret = BCME_OK; /* entry already present */ - goto done; + add_index = i; + new_entry = FALSE; + break; } } - WL_DBG(("adding cache entry: add_index = %d\n", add_index)); - disc_res[add_index].valid = 1; - disc_res[add_index].pub_id = disc->pub_id; - disc_res[add_index].sub_id = disc->sub_id; - disc_res[add_index].publish_rssi = disc->publish_rssi; - disc_res[add_index].peer_cipher_suite = disc->peer_cipher_suite; - disc_res[add_index].sde_control_flag = disc->sde_control_flag; - ret = memcpy_s(&disc_res[add_index].peer, ETHER_ADDR_LEN, - &disc->remote_nmi, ETHER_ADDR_LEN); - if (ret != BCME_OK) { - WL_ERR(("Failed to copy remote nmi\n")); - goto done; - } - ret = memcpy_s(disc_res[add_index].svc_hash, WL_NAN_SVC_HASH_LEN, - disc->svc_name, WL_NAN_SVC_HASH_LEN); - if (ret != BCME_OK) { - WL_ERR(("Failed to copy svc hash\n")); + + if (add_index == NAN_MAX_CACHE_DISC_RESULT) { + WL_DBG(("cache full")); + ret = BCME_NORESOURCE; goto done; } + if (new_entry) { + WL_DBG(("adding cache entry: add_index = %d\n", add_index)); + disc_res[add_index].valid = 1; + disc_res[add_index].pub_id = disc->pub_id; + disc_res[add_index].sub_id = disc->sub_id; + + eacopy(&disc->remote_nmi, &disc_res[add_index].peer); + eacopy(disc->svc_name, disc_res[add_index].svc_hash); + } + + disc_res[add_index].publish_rssi = disc->publish_rssi; + disc_res[add_index].peer_cipher_suite = disc->peer_cipher_suite; + disc_res[add_index].sde_control_flag = disc->sde_control_flag; if (disc->svc_info.dlen && disc->svc_info.data) { - disc_res[add_index].svc_info.dlen = disc->svc_info.dlen; - disc_res[add_index].svc_info.data = - MALLOCZ(cfg->osh, disc_res[add_index].svc_info.dlen); + if (disc_res[add_index].svc_info.dlen != disc->svc_info.dlen) { + if (disc_res[add_index].svc_info.data) { + MFREE(cfg->osh, disc_res[add_index].svc_info.data, + disc_res[add_index].svc_info.dlen); + } + disc_res[add_index].svc_info.dlen = disc->svc_info.dlen; + disc_res[add_index].svc_info.data = + MALLOCZ(cfg->osh, disc_res[add_index].svc_info.dlen); + } if (!disc_res[add_index].svc_info.data) { WL_ERR(("%s: memory allocation failed\n", __FUNCTION__)); disc_res[add_index].svc_info.dlen = 0; ret = BCME_NOMEM; - goto done; + goto reset_entry; } ret = memcpy_s(disc_res[add_index].svc_info.data, disc_res[add_index].svc_info.dlen, disc->svc_info.data, disc->svc_info.dlen); if (ret != BCME_OK) { WL_ERR(("Failed to copy svc info\n")); - goto done; + goto reset_entry; } } if (disc->tx_match_filter.dlen && disc->tx_match_filter.data) { - disc_res[add_index].tx_match_filter.dlen = disc->tx_match_filter.dlen; - disc_res[add_index].tx_match_filter.data = - MALLOCZ(cfg->osh, disc_res[add_index].tx_match_filter.dlen); + if (disc_res[add_index].tx_match_filter.dlen != disc->tx_match_filter.dlen) { + if (disc_res[add_index].tx_match_filter.data) { + MFREE(cfg->osh, disc_res[add_index].tx_match_filter.data, + disc_res[add_index].tx_match_filter.dlen); + } + disc_res[add_index].tx_match_filter.dlen = disc->tx_match_filter.dlen; + disc_res[add_index].tx_match_filter.data = + MALLOCZ(cfg->osh, disc_res[add_index].tx_match_filter.dlen); + } if (!disc_res[add_index].tx_match_filter.data) { WL_ERR(("%s: memory allocation failed\n", __FUNCTION__)); disc_res[add_index].tx_match_filter.dlen = 0; ret = BCME_NOMEM; - goto done; + goto reset_entry; } ret = memcpy_s(disc_res[add_index].tx_match_filter.data, disc_res[add_index].tx_match_filter.dlen, disc->tx_match_filter.data, disc->tx_match_filter.dlen); if (ret != BCME_OK) { WL_ERR(("Failed to copy tx match filter\n")); - goto done; + goto reset_entry; } } - nancfg->nan_disc_count++; + if (new_entry) { + nancfg->nan_disc_count++; + } WL_DBG(("cfg->nan_disc_count = %d\n", nancfg->nan_disc_count)); done: return ret; + +reset_entry: + if (!new_entry) { + nancfg->nan_disc_count--; + *disc_cache_update_flags = 0; + } + WL_ERR(("resetting cache entry: %d, cfg->nan_disc_count = %d\n", add_index, + nancfg->nan_disc_count)); + wl_cfgnan_reset_disc_result(cfg, &disc_res[add_index]); + + return ret; } #ifdef RTT_SUPPORT @@ -9015,6 +9657,31 @@ done: return ret; } +static int wl_cfgnan_reset_disc_result(struct bcm_cfg80211 *cfg, + nan_disc_result_cache *disc_res) +{ + int ret = BCME_OK; + + if (!cfg->nancfg->nan_enable) { + WL_DBG(("nan not enabled\n")); + ret = BCME_NOTENABLED; + goto done; + } + + if (disc_res->tx_match_filter.data) { + MFREE(cfg->osh, disc_res->tx_match_filter.data, + disc_res->tx_match_filter.dlen); + } + if (disc_res->svc_info.data) { + MFREE(cfg->osh, disc_res->svc_info.data, + disc_res->svc_info.dlen); + } + bzero(disc_res, sizeof(*disc_res)); + +done: + return ret; +} + static nan_disc_result_cache * wl_cfgnan_get_disc_result(struct bcm_cfg80211 *cfg, uint8 remote_pubid, struct ether_addr *peer) @@ -9106,6 +9773,20 @@ wl_cfgnan_update_dp_info(struct bcm_cfg80211 *cfg, bool add, WL_INFORM_MEM(("NAN_DP_COUNT: %d\n", nancfg->nan_dp_count)); } +bool +wl_cfgnan_is_nan_active(struct net_device *ndev) +{ + struct bcm_cfg80211 *cfg; + + if (!ndev || !ndev->ieee80211_ptr) { + WL_ERR(("ndev/wdev null\n")); + return false; + } + + cfg = wiphy_priv(ndev->ieee80211_ptr->wiphy); + return cfg->nancfg->nan_enable; +} + bool wl_cfgnan_is_dp_active(struct net_device *ndev) { @@ -9292,7 +9973,7 @@ wl_nan_print_avail_stats(const uint8 *data) int s_chan = 0; char pbuf[NAN_IOCTL_BUF_SIZE_MED]; const wl_nan_stats_sched_t *sched = (const wl_nan_stats_sched_t *)data; -#define SLOT_PRINT_SIZE 4 +#define SLOT_PRINT_SIZE 6 char *buf = pbuf; int remained_len = 0, bytes_written = 0; @@ -9320,8 +10001,10 @@ wl_nan_print_avail_stats(const uint8 *data) buf += bytes_written; remained_len -= bytes_written; - bytes_written = snprintf(buf, remained_len, "%03d|", s_chan); - + bytes_written = snprintf(buf, remained_len, "%3u%c|", + s_chan, ((s_chan) && + (slot->info & WL_NAN_SCHED_STAT_SLOT_COMM)) ? 'C' : + ' '); /* Committed */ } WL_INFORM_MEM(("%s\n", pbuf)); exit: @@ -9426,6 +10109,152 @@ fail: return ret; } +#ifdef WL_NMI_IF + +/* AWARE NMI interface name */ +#ifndef CUSTOM_NMI_IFNAME +#define NMI_IFNAME "aware_nmi0" +#else +#define NMI_IFNAME CUSTOM_NMI_IFNAME +#endif /* !CUSTOM_NMI_IFNAME */ + +static int +wl_cfgnan_nmi_if_dummy_open(struct net_device *net) +{ + WL_DBG(("(%s) NMI aware iface open \n", __FUNCTION__)); + return 0; +} + +static int +wl_cfgnan_nmi_if_dummy_close(struct net_device *net) +{ + WL_DBG(("(%s) NMI aware iface close \n", __FUNCTION__)); + return 0; +} + +static netdev_tx_t +wl_cfgnan_nmi_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + + if (skb) + { + WL_DBG(("(%s) is not used for data operations.Droping the packet.\n", + ndev->name)); + dev_kfree_skb_any(skb); + } + + return 0; +} + +static int +wl_cfgnan_nmi_if_dummy_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd) +{ + WL_DBG(("(%s) NMI aware iface do_ioctl cmd %d \n", __FUNCTION__, cmd)); + return 0; +} + +static const struct net_device_ops wl_cfgnan_nmi_if_ops = { + .ndo_open = wl_cfgnan_nmi_if_dummy_open, + .ndo_stop = wl_cfgnan_nmi_if_dummy_close, + .ndo_do_ioctl = wl_cfgnan_nmi_if_dummy_do_ioctl, + .ndo_start_xmit = wl_cfgnan_nmi_start_xmit, +}; + +s32 +wl_cfgnan_register_nmi_ndev(struct bcm_cfg80211 *cfg) +{ + int ret = 0; + struct net_device* ndev = NULL; + struct wireless_dev *wdev = NULL; + uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 }; + struct bcm_cfg80211 **priv; + + if (cfg->nmi_ndev) { + WL_ERR(("nmi_ndev defined already.\n")); + return -EINVAL; + } + + /* Allocate etherdev, including space for private structure */ + if (!(ndev = alloc_etherdev(sizeof(struct bcm_cfg80211 *)))) { + WL_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); + return -ENODEV; + } + + wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev)); + if (unlikely(!wdev)) { + WL_ERR(("Could not allocate wireless device\n")); + free_netdev(ndev); + return -ENOMEM; + } + + strlcpy(ndev->name, NMI_IFNAME, sizeof(ndev->name)); + + /* Copy the reference to bcm_cfg80211 */ + priv = (struct bcm_cfg80211 **)netdev_priv(ndev); + *priv = cfg; + + ASSERT(!ndev->netdev_ops); + ndev->netdev_ops = &wl_cfgnan_nmi_if_ops; + + /* Register with a dummy MAC addr */ + eacopy(temp_addr, ndev->dev_addr); + + ndev->ieee80211_ptr = wdev; + wdev->netdev = ndev; + wdev->wiphy = bcmcfg_to_wiphy(cfg); + wdev->iftype = NL80211_IFTYPE_STATION; + + ret = register_netdev(ndev); + if (ret) { + WL_ERR((" NMI register_netdevice failed (%d)\n", ret)); + goto fail; + } + + /* store nmi ndev ptr for further reference. Note that iflist won't have this + * entry as there corresponding firmware interface is a "Hidden" interface. + */ + cfg->nmi_wdev = wdev; + cfg->nmi_ndev = ndev; + + WL_MSG(ndev->name, "NMI Interface Registered\n"); + return ret; +fail: + free_netdev(ndev); + MFREE(cfg->osh, wdev, sizeof(*wdev)); + return -ENODEV; +} + +static s32 +wl_cfgnan_unregister_nmi_ndev(struct bcm_cfg80211 *cfg) +{ + struct wireless_dev *wdev; + + if (!cfg) { + WL_ERR(("NMI IF unreg, invalid cfg \n")); + return -EINVAL; + } + if (!cfg->nmi_ndev) { + WL_ERR(("NMI IF unreg, invalid nmi_ndev \n")); + goto free_wdev; + } + + unregister_netdev(cfg->nmi_ndev); + free_netdev(cfg->nmi_ndev); + + cfg->nmi_ndev = NULL; + +free_wdev: + wdev = cfg->nmi_wdev; + if (!wdev) { + WL_ERR(("NMI IF unreg, invalid NMI Iface wdev ptr \n")); + return -EINVAL; + } + MFREE(cfg->osh, wdev, sizeof(*wdev)); + cfg->nmi_wdev = NULL; + return BCME_OK; +} +#endif /* WL_NMI_IF */ + int wl_cfgnan_attach(struct bcm_cfg80211 *cfg) { @@ -9445,9 +10274,16 @@ wl_cfgnan_attach(struct bcm_cfg80211 *cfg) } nancfg = cfg->nancfg; +#ifdef WL_NMI_IF + if (wl_cfgnan_register_nmi_ndev(cfg) < 0) { + WL_ERR(("NAN NMI ndev reg failed in attach \n")); + return -ENODEV; + } +#endif /* WL_NMI_IF */ mutex_init(&nancfg->nan_sync); init_waitqueue_head(&nancfg->nan_event_wait); INIT_DELAYED_WORK(&nancfg->nan_disable, wl_cfgnan_delayed_disable); + INIT_DELAYED_WORK(&nancfg->nan_nmi_rand, wl_cfgnan_periodic_nmi_rand_addr); nancfg->nan_dp_state = NAN_DP_STATE_DISABLED; init_waitqueue_head(&nancfg->ndp_if_change_event); @@ -9465,9 +10301,159 @@ wl_cfgnan_detach(struct bcm_cfg80211 *cfg) DHD_NAN_WAKE_UNLOCK(cfg->pub); cancel_delayed_work_sync(&cfg->nancfg->nan_disable); } + if (delayed_work_pending(&cfg->nancfg->nan_nmi_rand)) { + WL_DBG(("Cancel nan_nmi_rand workq\n")); + cancel_delayed_work_sync(&cfg->nancfg->nan_nmi_rand); + } + +#ifdef WL_NMI_IF + /* Unregister NMI ndev */ + wl_cfgnan_unregister_nmi_ndev(cfg); +#endif /* WL_NMI_IF */ + MFREE(cfg->osh, cfg->nancfg, sizeof(wl_nancfg_t)); cfg->nancfg = NULL; } } + +static s32 +wl_cfgnan_send_nmi_change_event(struct bcm_cfg80211 *cfg) +{ + nan_event_data_t *nan_event_data = NULL; + s32 ret = BCME_OK; + + NAN_DBG_ENTER(); + NAN_MUTEX_LOCK(); + if (!cfg->nancfg->nan_init_state) { + WL_ERR(("nan is not in initialized state, dropping nan NMI change event\n")); + ret = BCME_OK; + goto exit; + } + + nan_event_data = MALLOCZ(cfg->osh, sizeof(*nan_event_data)); + if (!nan_event_data) { + WL_ERR(("%s: memory allocation failed\n", __func__)); + goto exit; + } + + nan_event_data->nan_de_evt_type = WL_NAN_EVENT_NMI_ADDR; + ret = memcpy_s(&nan_event_data->local_nmi, ETHER_ADDR_LEN, + cfg->nancfg->nan_nmi_mac, ETHER_ADDR_LEN); + if (ret != BCME_OK) { + WL_ERR(("Failed to copy nmi\n")); + goto exit; + } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) + ret = wl_cfgvendor_send_nan_event(cfg->wdev->wiphy, bcmcfg_to_prmry_ndev(cfg), + GOOGLE_NAN_EVENT_DE_EVENT, nan_event_data); + if (ret != BCME_OK) { + WL_ERR(("Failed to send event to nan hal, %s (%d)\n", + nan_event_to_str(WL_NAN_EVENT_NMI_ADDR), WL_NAN_EVENT_NMI_ADDR)); + } +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ + +exit: + wl_cfgnan_clear_nan_event_data(cfg, nan_event_data); + + NAN_MUTEX_UNLOCK(); + NAN_DBG_EXIT(); + return ret; +} + +/* workqueue to program NMI random address to FW */ +void +wl_cfgnan_periodic_nmi_rand_addr(struct work_struct *work) +{ + struct bcm_cfg80211 *cfg = NULL; + wl_nancfg_t *nancfg = NULL; + s32 ret = BCME_OK; + + BCM_SET_CONTAINER_OF(nancfg, work, wl_nancfg_t, nan_nmi_rand.work); + + cfg = nancfg->cfg; + if (!cfg->nancfg->nan_enable || !cfg->nancfg->mac_rand) { + return; + } + + /* check if NDP or ranging are in progress are already present */ + if (!cfg->nancfg->nan_dp_count && wl_cfgnan_ranging_allowed(cfg)) { + ret = wl_cfgnan_set_if_addr(cfg); + if (ret != BCME_OK) { + WL_INFORM_MEM((" FW could not change NMI \n")); + goto sched; + } + } else { + WL_INFORM_MEM((" NDP is already present, cannot change NMI \n")); + goto sched; + } + + schedule_delayed_work(&cfg->nancfg->nan_nmi_rand, + msecs_to_jiffies(nancfg->nmi_rand_intvl * 1000)); + /* Send NMI change event to hal */ + wl_cfgnan_send_nmi_change_event(cfg); + return; + +sched: + /* As FW is busy, retry NMI change after 60sec */ + schedule_delayed_work(&cfg->nancfg->nan_nmi_rand, msecs_to_jiffies(60 * 1000)); +} +#ifdef WL_NAN_INSTANT_MODE +void wl_cfgnan_inst_chan_support(struct bcm_cfg80211 *cfg, + wl_chanspec_list_v1_t *chan_list, u32 band_mask, + uint8 *nan_2g, uint8 *nan_pri_5g, uint8 *nan_sec_5g) +{ + int ret = BCME_OK; + uint16 list_count = 0, i = 0; + uint8 channel = 0; + chanspec_t chanspec = INVCHANSPEC; + + list_count = chan_list->count; + for (i = 0; i < list_count; i++) { + chanspec = dtoh32(((wl_chanspec_list_v1_t *)chan_list)->chspecs[i].chanspec); + chanspec = wl_chspec_driver_to_host(chanspec); + + if (!wf_chspec_malformed(chanspec)) { + channel = CHSPEC_CHANNEL(chanspec); + + if ((band_mask & WLAN_MAC_5_0_BAND) && + (channel == NAN_DEF_SOCIAL_CHAN_5G)) { + /* Check nan operatability in the current locale */ + ret = wl_cfgnan_check_for_valid_5gchan(bcmcfg_to_prmry_ndev(cfg), + channel); + if (ret != BCME_OK) { + WL_DBG_MEM(("Current locale doesn't support 5G op" + "continuing with 2G only operation\n")); + *nan_pri_5g = 0; + } else { + WL_DBG_MEM(("Found prim inst mode 5g chan!!\n")); + *nan_pri_5g = channel; + } + } + + if ((band_mask & WLAN_MAC_5_0_BAND) && + (channel == NAN_DEF_SEC_SOCIAL_CHAN_5G)) { + /* Check nan operatability in the current locale */ + ret = wl_cfgnan_check_for_valid_5gchan(bcmcfg_to_prmry_ndev(cfg), + channel); + if (ret != BCME_OK) { + WL_DBG_MEM(("Current locale doesn't support 5G op" + "continuing with 2G only operation\n")); + *nan_sec_5g = 0; + } else { + WL_DBG_MEM(("Found sec inst mode 5g chan!!\n")); + *nan_sec_5g = channel; + } + } + + if ((band_mask & WLAN_MAC_2_4_BAND) && + (channel == NAN_DEF_SOCIAL_CHAN_2G)) { + WL_DBG_MEM(("Found instant mode 2g channel!!\n")); + *nan_2g = channel; + } + } + } + return; +} +#endif /* WL_NAN_INSTANT_MODE */ #endif /* WL_NAN */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgnan.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgnan.h old mode 100755 new mode 100644 index 703e64571433..23d4f3d7c47e --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgnan.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgnan.h @@ -1,7 +1,7 @@ /* * Neighbor Awareness Networking * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -90,7 +90,9 @@ #define NAME_TO_STR(name) #name #define NAN_ID_CTRL_SIZE ((NAN_MAXIMUM_ID_NUMBER/8) + 1) +#ifndef tolower #define tolower(c) bcm_tolower(c) +#endif /* tolower */ #define NMR2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6], (a)[7] #define NMRSTR "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x" @@ -134,6 +136,7 @@ #define NAN_SRF_MAX_MAC (NAN_BLOOM_LENGTH_DEFAULT / ETHER_ADDR_LEN) #define NAN_MAX_PMK_LEN 32u #define NAN_ERROR_STR_LEN 255u +#define NAN_MAX_SCID_BUF_LEN 1024u /* NAN related Capabilities */ #define MAX_CONCURRENT_NAN_CLUSTERS 1u @@ -165,6 +168,9 @@ #define NAN_NMI_RAND_PVT_CMD_VENDOR (1 << 31) #define NAN_NMI_RAND_CLUSTER_MERGE_ENAB (1 << 30) #define NAN_NMI_RAND_AUTODAM_LWT_MODE_ENAB (1 << 29) +#define NAN_NMI_RAND_INTVL_MASK ~(NAN_NMI_RAND_PVT_CMD_VENDOR | \ + NAN_NMI_RAND_CLUSTER_MERGE_ENAB | \ + NAN_NMI_RAND_AUTODAM_LWT_MODE_ENAB) #ifdef WL_NAN_DEBUG #define NAN_MUTEX_LOCK() {WL_DBG(("Mutex Lock: Enter: %s\n", __FUNCTION__)); \ @@ -205,6 +211,8 @@ #define NAN_ATTR_OUI_CONFIG (1<<27) #define NAN_ATTR_SUB_SID_BEACON_CONFIG (1<<28) #define NAN_ATTR_DISC_BEACON_INTERVAL (1<<29) +#define NAN_ATTR_INSTANT_MODE_CONFIG (1<<30) + #define NAN_IOVAR_NAME_SIZE 4u #define NAN_XTLV_ID_LEN_SIZE OFFSETOF(bcm_xtlv_t, data) #define NAN_RANGING_INDICATE_CONTINUOUS_MASK 0x01 @@ -306,17 +314,17 @@ typedef struct nan_ranging_inst { bool role_concurrency_status; } nan_ranging_inst_t; -#define DUMP_NAN_RTT_INST(inst) { printf("svc instance ID %d", (inst)->svc_inst_id); \ - printf("Range ID %d", (inst)->range_id); \ - printf("range_status %d", (inst)->range_status); \ - printf("Range Type %d", (inst)->range_type); \ - printf("Peer MAC "MACDBG"\n", MAC2STRDBG((inst)->peer_addr.octet)); \ +#define DUMP_NAN_RTT_INST(inst) { WL_CONS_ONLY(("svc instance ID %d", (inst)->svc_inst_id)); \ + WL_CONS_ONLY(("Range ID %d", (inst)->range_id)); \ + WL_CONS_ONLY(("range_status %d", (inst)->range_status)); \ + WL_CONS_ONLY(("Range Type %d", (inst)->range_type)); \ + WL_CONS_ONLY(("Peer MAC "MACDBG"\n", MAC2STRDBG((inst)->peer_addr.octet))); \ } -#define DUMP_NAN_RTT_RPT(rpt) { printf("Range ID %d", (rpt)->rng_id); \ - printf("Distance in MM %d", (rpt)->dist_mm); \ - printf("range_indication %d", (rpt)->indication); \ - printf("Peer MAC "MACDBG"\n", MAC2STRDBG((rpt)->peer_m_addr.octet)); \ +#define DUMP_NAN_RTT_RPT(rpt) { WL_CONS_ONLY("Range ID %d", (rpt)->rng_id); \ + WL_CONS_ONLY(("Distance in MM %d", (rpt)->dist_mm)); \ + WL_CONS_ONLY(("range_indication %d", (rpt)->indication)); \ + WL_CONS_ONLY(("Peer MAC "MACDBG"\n", MAC2STRDBG((rpt)->peer_m_addr.octet))); \ } /* * Data request Initiator/Responder @@ -476,6 +484,7 @@ typedef struct nan_datapath_cmd_data { uint8 num_ndp_instances; uint8 duration; char ndp_iface[IFNAMSIZ+1]; + nan_str_data_t scid; /* security context information */ } nan_datapath_cmd_data_t; typedef struct nan_rssi_cmd_data { @@ -533,6 +542,9 @@ typedef struct nan_config_cmd_data { uint16 cluster_high; wl_nan_disc_bcn_interval_t disc_bcn_interval; uint32 dw_early_termination; + uint32 instant_mode_en; + chanspec_t instant_chspec; + uint8 chre_req; } nan_config_cmd_data_t; typedef struct nan_event_hdr { @@ -577,6 +589,7 @@ typedef struct nan_event_data { uint32 range_measurement_cm; uint32 ranging_ind; uint8 rng_id; + nan_ndl_sched_info_t ndl_sched_info; } nan_event_data_t; /* @@ -643,6 +656,7 @@ typedef struct nan_hal_capabilities { uint32 max_sdea_service_specific_info_len; uint32 max_subscribe_address; uint32 ndpe_attr_supported; + bool is_instant_mode_supported; } nan_hal_capabilities_t; typedef struct _nan_hal_resp { @@ -668,7 +682,12 @@ typedef struct wl_nan_iov { #ifdef WL_NAN_DISC_CACHE -#define NAN_MAX_CACHE_DISC_RESULT 16 +#ifndef CUSTOM_NAN_MAX_CACHE_DISC_RESULT +#define NAN_MAX_CACHE_DISC_RESULT 40 +#else +#define NAN_MAX_CACHE_DISC_RESULT CUSTOM_NAN_MAX_CACHE_DISC_RESULT +#endif /* CUSTOM_NAN_MAX_CACHE_DISC_RESULT */ + typedef struct { bool valid; wl_nan_instance_id_t pub_id; @@ -705,10 +724,21 @@ typedef struct wl_ndi_data struct net_device *nan_ndev; } wl_ndi_data_t; +/* Google mobile platforms have 2 processors which can request NAN + * APP - main application processor + * CHRE - Low power processor + * We need to differentiate the request for handling (non)concurrency + */ +typedef enum { + ENABLE_FOR_APP = 0, + ENABLE_FOR_CHRE = 1 +} nan_enab_reason; + typedef struct wl_nancfg { struct bcm_cfg80211 *cfg; bool nan_enable; + nan_enab_reason enab_reason; nan_svc_inst_t nan_inst_ctrl[NAN_ID_CTRL_SIZE]; struct ether_addr initiator_ndi; uint8 nan_dp_state; @@ -738,8 +768,13 @@ typedef struct wl_nancfg uint8 max_ndi_supported; wl_ndi_data_t *ndi; bool ranging_enable; + struct delayed_work nan_nmi_rand; /* WQ for periodic nmi randomization */ + uint32 nmi_rand_intvl; /* nmi randomization interval */ } wl_nancfg_t; +#define NAN_RTT_ENABLED(cfg) (wl_cfgnan_is_enabled(cfg) && \ + (cfg->nancfg->ranging_enable == TRUE)) + bool wl_cfgnan_is_enabled(struct bcm_cfg80211 *cfg); int wl_cfgnan_check_nan_disable_pending(struct bcm_cfg80211 *cfg, bool force_disable, bool is_sync_reqd); @@ -787,6 +822,7 @@ int wl_cfgnan_sec_info_handler(struct bcm_cfg80211 *cfg, /* ranging quest and response iovar handler */ #endif /* WL_NAN_DISC_CACHE */ bool wl_cfgnan_is_dp_active(struct net_device *ndev); +bool wl_cfgnan_is_nan_active(struct net_device *ndev); bool wl_cfgnan_data_dp_exists_with_peer(struct bcm_cfg80211 *cfg, struct ether_addr *peer_addr); s32 wl_cfgnan_delete_ndp(struct bcm_cfg80211 *cfg, struct net_device *nan_ndev); @@ -795,6 +831,13 @@ int wl_cfgnan_set_enable_merge(struct net_device *ndev, int wl_cfgnan_attach(struct bcm_cfg80211 *cfg); void wl_cfgnan_detach(struct bcm_cfg80211 *cfg); int wl_cfgnan_get_status(struct net_device *ndev, wl_nan_conf_status_t *nan_status); +#ifdef WL_NAN_INSTANT_MODE +extern void wl_cfgnan_inst_chan_support(struct bcm_cfg80211 *cfg, + wl_chanspec_list_v1_t *chan_list, uint32 band_mask, + uint8 *nan_2g, uint8 *nan_pri_5g, uint8* nan_sec_5g); +#endif /* WL_NAN_INSTANT_MODE */ +int +wl_cfgnan_check_for_valid_5gchan(struct net_device *ndev, uint8 chan); #ifdef RTT_SUPPORT int wl_cfgnan_trigger_ranging(struct net_device *ndev, @@ -825,9 +868,12 @@ bool wl_cfgnan_check_role_concurrency(struct bcm_cfg80211 *cfg, bool wl_cfgnan_update_geofence_target_idx(struct bcm_cfg80211 *cfg); bool wl_cfgnan_ranging_is_in_prog_for_peer(struct bcm_cfg80211 *cfg, struct ether_addr *peer_addr); +#else +static INLINE bool wl_cfgnan_ranging_allowed(struct bcm_cfg80211 *cfg) { return FALSE; } #endif /* RTT_SUPPORT */ typedef enum { + NAN_ATTRIBUTE_INVALID = 0, NAN_ATTRIBUTE_HEADER = 100, NAN_ATTRIBUTE_HANDLE = 101, NAN_ATTRIBUTE_TRANSAC_ID = 102, @@ -963,7 +1009,8 @@ typedef enum { NAN_ATTRIBUTE_NUM_CHANNELS = 229, NAN_ATTRIBUTE_INSTANT_MODE_ENABLE = 230, NAN_ATTRIBUTE_INSTANT_COMM_CHAN = 231, - NAN_ATTRIBUTE_MAX = 232 + NAN_ATTRIBUTE_CHRE_REQUEST = 232, + NAN_ATTRIBUTE_MAX = 233 } NAN_ATTRIBUTE; enum geofence_suspend_reason { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c old mode 100755 new mode 100644 index 05a7edffdd4e..7cdd8f7cddfc --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c @@ -1,7 +1,7 @@ /* * Linux cfgp2p driver * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -39,6 +39,7 @@ #include #include #include <802.11.h> +#include <802.11wfa.h> #include #include @@ -146,6 +147,11 @@ bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len) */ #define GAS_RESP_OFFSET 4 #define GAS_CRESP_OFFSET 5 +/* +* structure elements of wifi_p2psd_gas_pub_act_frame +* category + action + dialog_token +*/ +#define P2P_GAS_ACT_FRAME_FIXED_SIZE 3 bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) { wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; @@ -163,27 +169,6 @@ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) return true; } -#ifdef WL11U - /* Hotspot2.0 STA mode can receive only response - * SoftAP mode cannot run Hotspot2.0 compliant Ap because - * Hotspot2.0 support only Enterprise mode - */ - if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP) { - return wl_cfg80211_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, P2PSD_GAS_NQP_INFOID, - (u8 *)sd_act_frm->query_data + GAS_RESP_OFFSET, - frame_len); - - } else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) { - return wl_cfg80211_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, P2PSD_GAS_NQP_INFOID, - (u8 *)sd_act_frm->query_data + GAS_CRESP_OFFSET, - frame_len); - } else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || - sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ) { - return true; - } else { - return false; - } -#else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || @@ -191,7 +176,6 @@ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) return true; else return false; -#endif /* WL11U */ } bool wl_cfgp2p_is_p2p_gas_action(void *frame, u32 frame_len) @@ -211,7 +195,7 @@ bool wl_cfgp2p_is_p2p_gas_action(void *frame, u32 frame_len) if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ) return wl_cfg80211_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, P2PSD_GAS_NQP_INFOID, (u8 *)sd_act_frm->query_data, - frame_len); + frame_len - P2P_GAS_ACT_FRAME_FIXED_SIZE); else return false; } @@ -224,7 +208,6 @@ void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel) if (!frame || frame_len <= 2) return; - channel = CHSPEC_CHANNEL(channel); if (wl_cfgp2p_is_pub_action(frame, frame_len)) { pact_frm = (wifi_p2p_pub_act_frame_t *)frame; switch (pact_frm->subtype) { @@ -330,15 +313,13 @@ void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel) s32 wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg) { - struct ether_addr primary_mac; cfg->p2p = MALLOCZ(cfg->osh, sizeof(struct p2p_info)); if (cfg->p2p == NULL) { CFGP2P_ERR(("struct p2p_info allocation failed\n")); return -ENOMEM; } - get_primary_mac(cfg, &primary_mac); - wl_cfgp2p_generate_bss_mac(cfg, &primary_mac); + wl_cfgp2p_generate_bss_mac(cfg); wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY) = bcmcfg_to_prmry_ndev(cfg); wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY) = 0; @@ -351,6 +332,7 @@ wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg) return BCME_OK; } + /* * Deinitialize variables related to P2P * @@ -365,6 +347,7 @@ wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg) } cfg->p2p_supported = 0; } + /* * Set P2P functions into firmware */ @@ -413,8 +396,10 @@ wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg) * After Initializing firmware, we have to set current mac address to * firmware for P2P device address */ + CFGP2P_INFO(("p2p dev addr : "MACDBG"\n", MAC2STRDBG(p2p_dev_addr->octet))); ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", p2p_dev_addr, - sizeof(*p2p_dev_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &cfg->ioctl_buf_sync); + sizeof(*p2p_dev_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, 0, + &cfg->ioctl_buf_sync); if (ret && ret != BCME_UNSUPPORTED) { CFGP2P_ERR(("failed to update device address ret %d\n", ret)); } @@ -572,11 +557,64 @@ wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index) return ret; } +#ifdef BCMDONGLEHOST +#define DISCOVERY_EBUSY_RETRY_LIMIT 5u +static void +wl_cfgp2p_handle_discovery_busy(struct bcm_cfg80211 *cfg) +{ + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + struct ether_addr *p2p_dev_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE); + + if (dhdp->dhd_induce_error == DHD_INDUCE_P2P_DISC_BUSY) { + /* force hang for p2p disc busy to be triggered */ + dhdp->p2p_disc_busy_cnt = DISCOVERY_EBUSY_RETRY_LIMIT; + CFGP2P_ERR(("P2P disc busy hang forcily\n")); + } + + if (++dhdp->p2p_disc_busy_cnt < DISCOVERY_EBUSY_RETRY_LIMIT) { + goto done; + } + + CFGP2P_ERR(("p2p disc busy!!!\n")); + + if (ETHER_ISNULLADDR(p2p_dev_addr)) { + CFGP2P_ERR(("NULL p2p_dev_addr\n")); + } else { + CFGP2P_ERR(("p2p disc mac : "MACDBG"\n", MAC2STRDBG(p2p_dev_addr->octet))); + } + + if (dhd_query_bus_erros(dhdp)) { + CFGP2P_ERR(("bus error\n")); + goto done; + } + + dhdp->p2p_disc_busy_occurred = TRUE; + +#if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP) + if (dhdp->memdump_enabled) { + dhdp->memdump_type = DUMP_TYPE_P2P_DISC_BUSY; + dhd_bus_mem_dump(dhdp); + } +#endif /* DHD_DEBUG && DHD_FW_COREDUMP */ + +#ifdef OEM_ANDROID + dhdp->hang_reason = HANG_REASON_P2P_DISC_BUSY; + dhd_os_send_hang_message(dhdp); +#endif /* OEM_ANDROID */ + +done: + return; +} +#endif /* BCMDONGLEHOST */ + static s32 wl_cfgp2p_set_discovery(struct bcm_cfg80211 *cfg, s32 on) { s32 ret = BCME_OK; struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); +#ifdef BCMDONGLEHOST + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); +#endif /* BCMDONGLEHOST */ CFGP2P_DBG(("enter\n")); ret = wldev_iovar_setint(ndev, "p2p_disc", on); @@ -585,6 +623,17 @@ wl_cfgp2p_set_discovery(struct bcm_cfg80211 *cfg, s32 on) CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret)); } +#ifdef BCMDONGLEHOST + if (on) { + if (ret == BCME_BUSY || + dhdp->dhd_induce_error == DHD_INDUCE_P2P_DISC_BUSY) { + wl_cfgp2p_handle_discovery_busy(cfg); + } else { + dhdp->p2p_disc_busy_cnt = 0; + } + } +#endif /* BCMDONGLEHOST */ + return ret; } @@ -697,7 +746,6 @@ int wl_cfgp2p_get_conn_idx(struct bcm_cfg80211 *cfg) s32 wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg) { - s32 bssidx = 0; s32 ret = BCME_OK; struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); @@ -705,7 +753,12 @@ wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg) BCM_REFERENCE(ndev); CFGP2P_DBG(("enter\n")); - if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) > 0) { +#ifdef BCMDBUS + if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) > 0 && !cfg->bus_resuming) +#else + if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) > 0) +#endif /* BCMDBUS */ + { CFGP2P_ERR(("do nothing, already initialized\n")); goto exit; } @@ -732,6 +785,9 @@ wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg) * so that time, the ifidx returned in WLC_E_IF should be used for populating * the netinfo */ +#ifdef BCMDBUS + if (!cfg->bus_resuming) +#endif /* BCMDBUS */ ret = wl_alloc_netinfo(cfg, NULL, cfg->p2p_wdev, WL_IF_TYPE_STA, 0, bssidx, 0); if (unlikely(ret)) { goto exit; @@ -798,6 +854,7 @@ wl_cfgp2p_deinit_discovery(struct bcm_cfg80211 *cfg) return ret; } + /* Enable P2P Discovery * Parameters: * @cfg : wl_private data @@ -822,7 +879,12 @@ wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev, } #endif /* WL_IFACE_MGMT */ - if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { +#ifdef BCMDBUS + if (!cfg->bus_resuming && (wl_get_p2p_status(cfg, DISCOVERY_ON))) +#else + if (wl_get_p2p_status(cfg, DISCOVERY_ON)) +#endif /* BCMDBUS */ + { CFGP2P_DBG((" DISCOVERY is already initialized, we have nothing to do\n")); goto set_ie; } @@ -921,11 +983,6 @@ wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg) /* Do a scan abort to stop the driver's scan engine in case it is still * waiting out an action frame tx dwell time. */ -#ifdef NOT_YET - if (wl_get_p2p_status(cfg, SCANNING)) { - p2pwlu_scan_abort(hdl, FALSE); - } -#endif wl_clr_p2p_status(cfg, DISCOVERY_ON); ret = wl_cfgp2p_deinit_discovery(cfg); @@ -952,8 +1009,8 @@ wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active_sca u32 i; s8 *memblk; wl_p2p_scan_t *p2p_params; - wl_escan_params_t *eparams; - wl_escan_params_v2_t *eparams_v2; + wl_escan_params_v1_t *eparams; + wl_escan_params_v3_t *eparams_v3; wlc_ssid_t ssid; u32 sync_id = 0; s32 nprobes = 0; @@ -964,13 +1021,13 @@ wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active_sca pri_dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); /* Allocate scan params which need space for 3 channels and 0 ssids */ - if (cfg->scan_params_v2) { - eparams_size = (WL_SCAN_PARAMS_V2_FIXED_SIZE + - OFFSETOF(wl_escan_params_v2_t, params)) + + if (IS_SCAN_PARAMS_V3_V2(cfg)) { + eparams_size = (WL_SCAN_PARAMS_V3_FIXED_SIZE + + OFFSETOF(wl_escan_params_v3_t, params)) + num_chans * sizeof(eparams->params.channel_list[0]); } else { - eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE + - OFFSETOF(wl_escan_params_t, params)) + + eparams_size = (WL_SCAN_PARAMS_V1_FIXED_SIZE + + OFFSETOF(wl_escan_params_v1_t, params)) + num_chans * sizeof(eparams->params.channel_list[0]); } @@ -1054,33 +1111,33 @@ wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active_sca wl_escan_set_sync_id(sync_id, cfg); /* Fill in the Scan structure that follows the P2P scan structure */ - if (cfg->scan_params_v2) { - eparams_v2 = (wl_escan_params_v2_t*) (p2p_params + 1); - eparams_v2->version = htod16(ESCAN_REQ_VERSION_V2); - eparams_v2->action = htod16(action); - eparams_v2->params.version = htod16(WL_SCAN_PARAMS_VERSION_V2); - eparams_v2->params.length = htod16(sizeof(wl_scan_params_v2_t)); - eparams_v2->params.bss_type = DOT11_BSSTYPE_ANY; - eparams_v2->params.scan_type = htod32(scan_type); - (void)memcpy_s(&eparams_v2->params.bssid, ETHER_ADDR_LEN, mac_addr, ETHER_ADDR_LEN); - eparams_v2->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); - eparams_v2->params.active_time = htod32(active_time); - eparams_v2->params.nprobes = htod32(nprobes); - eparams_v2->params.passive_time = htod32(-1); - eparams_v2->sync_id = sync_id; + if (IS_SCAN_PARAMS_V3_V2(cfg)) { + eparams_v3 = (wl_escan_params_v3_t*) (p2p_params + 1); + eparams_v3->version = htod16(cfg->scan_params_ver); + eparams_v3->action = htod16(action); + eparams_v3->params.version = htod16(cfg->scan_params_ver); + eparams_v3->params.length = htod16(sizeof(wl_scan_params_v3_t)); + eparams_v3->params.bss_type = DOT11_BSSTYPE_ANY; + eparams_v3->params.scan_type = htod32(scan_type); + (void)memcpy_s(&eparams_v3->params.bssid, ETHER_ADDR_LEN, mac_addr, ETHER_ADDR_LEN); + eparams_v3->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); + eparams_v3->params.active_time = htod32(active_time); + eparams_v3->params.nprobes = htod32(nprobes); + eparams_v3->params.passive_time = htod32(-1); + eparams_v3->sync_id = sync_id; for (i = 0; i < num_chans; i++) { - eparams_v2->params.channel_list[i] = + eparams_v3->params.channel_list[i] = wl_chspec_host_to_driver(channels[i]); } - eparams_v2->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | + eparams_v3->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); if (ssid.SSID_len) - (void)memcpy_s(&eparams_v2->params.ssid, + (void)memcpy_s(&eparams_v3->params.ssid, sizeof(wlc_ssid_t), &ssid, sizeof(wlc_ssid_t)); - sync_id = eparams_v2->sync_id; + sync_id = eparams_v3->sync_id; } else { - eparams = (wl_escan_params_t*) (p2p_params + 1); - eparams->version = htod32(ESCAN_REQ_VERSION); + eparams = (wl_escan_params_v1_t*) (p2p_params + 1); + eparams->version = htod32(ESCAN_REQ_VERSION_V1); eparams->action = htod16(action); eparams->params.bss_type = DOT11_BSSTYPE_ANY; eparams->params.scan_type = htod32(scan_type); @@ -1147,7 +1204,7 @@ wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev, chan_cnt = SOCIAL_CHAN_CNT; if (cfg->afx_hdl->pending_tx_act_frm && cfg->afx_hdl->is_active) { - wl_action_frame_t *action_frame; + wl_action_frame_v1_t *action_frame; action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame); if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) { chan_cnt = 1; @@ -1168,12 +1225,21 @@ wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev, default_chan_list[i] = channel; } } else { +#ifdef WL_6G_320_SUPPORT + default_chan_list[0] = wf_create_chspec_from_primary(SOCIAL_CHAN_1, + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G, 0); + default_chan_list[1] = wf_create_chspec_from_primary(SOCIAL_CHAN_2, + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G, 0); + default_chan_list[2] = wf_create_chspec_from_primary(SOCIAL_CHAN_3, + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G, 0); +#else default_chan_list[0] = wf_create_chspec_from_primary(SOCIAL_CHAN_1, WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G); default_chan_list[1] = wf_create_chspec_from_primary(SOCIAL_CHAN_2, WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G); default_chan_list[2] = wf_create_chspec_from_primary(SOCIAL_CHAN_3, WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G); +#endif /* WL_6G_320_SUPPORT */ } ret = wl_cfgp2p_escan(cfg, ndev, true, chan_cnt, default_chan_list, WL_P2P_DISC_ST_SEARCH, @@ -1351,6 +1417,7 @@ wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx) exit: return ndev; } + /* * Search the driver array idx based on bssidx argument * Parameters: Note that this idx is applicable only @@ -1527,6 +1594,7 @@ wl_cfgp2p_listen_expired(unsigned long data) } wl_cfg80211_event(ndev, &msg, NULL); } + /* * Routine for cancelling the P2P LISTEN */ @@ -1538,11 +1606,6 @@ wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev, /* Irrespective of whether timer is running or not, reset * the LISTEN state. */ -#ifdef NOT_YET -/* WAR : it is temporal workaround before resolving the root cause of kernel panic */ - wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, - wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); -#endif /* NOT_YET */ if (timer_pending(&cfg->p2p->listen_timer)) { del_timer_sync(&cfg->p2p->listen_timer); if (notify) { @@ -1559,6 +1622,7 @@ wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev, } return 0; } + /* * Do a P2P Listen on the given channel for the given duration. * A listen consists of sitting idle and responding to P2P probe requests @@ -1575,7 +1639,6 @@ wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms { #define EXTRA_DELAY_TIME 100 s32 ret = BCME_OK; - timer_list_compat_t *_timer; s32 extra_delay; struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg); @@ -1600,7 +1663,6 @@ wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms, wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); - _timer = &cfg->p2p->listen_timer; /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle , * otherwise we will wait up to duration_ms + 100ms + duration / 10 @@ -1613,7 +1675,7 @@ wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms extra_delay = 0; } - INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, extra_delay); + mod_timer(&cfg->p2p->listen_timer, jiffies + msecs_to_jiffies(duration_ms + extra_delay)); #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST wl_clr_p2p_status(cfg, LISTEN_EXPIRED); #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ @@ -1686,6 +1748,7 @@ wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev } else { CFGP2P_ACTION(("TX actfrm : NO ACK\n")); } + cfg->randomized_gas_tx = FALSE; /* if there is no ack, we don't need to wait for * WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event for ucast */ @@ -1697,12 +1760,80 @@ wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev CFGP2P_ACTION((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," "status : %d\n", status)); + cfg->randomized_gas_tx = FALSE; if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) complete(&cfg->send_af_done); } } return ret; } + +#define ETHER_LOCAL_ADDR 0x02 +static s32 +wl_actframe_fillup_v2(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + struct net_device *dev, wl_af_params_v2_t *af_params_v2_p, + wl_af_params_v1_t *af_params, const u8 *sa, uint16 wl_af_params_size) +{ + s32 err = 0; + wl_action_frame_v2_t *action_frame_v2_p; + struct ether_addr rand_mac_mask = {{0}}; + WL_DBG(("Enter \n")); + + af_params_v2_p->version = WL_ACTFRAME_VERSION_MAJOR_2; + af_params_v2_p->length = wl_af_params_size; + af_params_v2_p->channel = af_params->channel; + af_params_v2_p->dwell_time = af_params->dwell_time; + af_params_v2_p->BSSID = af_params->BSSID; + action_frame_v2_p = &af_params_v2_p->action_frame; + action_frame_v2_p->len_total = OFFSETOF(wl_action_frame_v2_t, data) + + af_params->action_frame.len; + action_frame_v2_p->data_offset = OFFSETOF(wl_action_frame_v2_t, data); + action_frame_v2_p->da = af_params->action_frame.da; + action_frame_v2_p->len_data = af_params->action_frame.len; + action_frame_v2_p->packetId = af_params->action_frame.packetId; + err = memcpy_s(action_frame_v2_p->data, action_frame_v2_p->len_data, + af_params->action_frame.data, af_params->action_frame.len); + if (err) { + WL_ERR(("actframe :memcpy failed\n")); + return -ENOMEM; + } + /* check if local admin bit is set and addr is different from ndev addr */ + if ((sa[0] & ETHER_LOCAL_ADDR) && +#if defined(WL_CFG80211_P2P_DEV_IF) + (cfgdev->iftype == NL80211_IFTYPE_STATION) && +#else + (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) && +#endif + memcmp(sa, dev->dev_addr, ETH_ALEN)) { + /* Use mask to avoid randomization, as the address from supplicant + * is already randomized. + */ + eacopy(sa, &action_frame_v2_p->rand_mac_addr); + action_frame_v2_p->rand_mac_mask = rand_mac_mask; + action_frame_v2_p->flags |= WL_RAND_GAS_MAC; + eacopy(sa, &cfg->af_randmac); + cfg->randomized_gas_tx = TRUE; + } + return err; +} + +s32 +wl_cfg80211_abort_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, s32 bssidx) +{ + s32 ret = BCME_OK; + + ret = wldev_iovar_setint_bsscfg(dev, "actframe_abort", 1, bssidx); + if (ret < 0) { + if (ret == BCME_UNSUPPORTED) { + WL_ERR(("actframe_abort unsupported. ret:%d\n", ret)); + wl_cfgscan_cancel_scan(cfg); + } else { + WL_ERR(("actframe_abort failed. ret:%d\n", ret)); + } + } + return ret; +} + /* Send an action frame immediately without doing channel synchronization. * * This function does not wait for a completion event before returning. @@ -1712,17 +1843,22 @@ wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev * 802.11 ack has been received for the sent action frame. */ s32 -wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, - wl_af_params_t *af_params, s32 bssidx) +wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + struct net_device *dev, wl_af_params_v1_t *af_params, s32 bssidx, const u8 *sa) { s32 ret = BCME_OK; s32 evt_ret = BCME_OK; s32 timeout = 0; wl_eventmsg_buf_t buf; + wl_af_params_v2_t *af_params_v2_p = NULL; + u8 *af_params_iov_p = NULL; + s32 af_params_iov_len = 0; + uint16 wl_af_params_size = 0; CFGP2P_DBG(("\n")); - CFGP2P_ACTION(("channel : %u , dwell time : %u wait_afrx:%d\n", - CHSPEC_CHANNEL(af_params->channel), af_params->dwell_time, cfg->need_wait_afrx)); + CFGP2P_ACTION(("channel : %u(0x%04x) , dwell time : %u wait_afrx:%d\n", + CHSPEC_CHANNEL(af_params->channel), af_params->channel, af_params->dwell_time, + cfg->need_wait_afrx)); wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED); wl_clr_p2p_status(cfg, ACTION_TX_NOACK); @@ -1741,8 +1877,35 @@ wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, #ifdef WL_CFG80211_SYNC_GON cfg->af_tx_sent_jiffies = jiffies; #endif /* WL_CFG80211_SYNC_GON */ + if (cfg->actframe_params_ver) { + if (cfg->actframe_params_ver == WL_ACTFRAME_VERSION_MAJOR_2) { + wl_af_params_size = OFFSETOF(wl_af_params_v2_t, action_frame) + + OFFSETOF(wl_action_frame_v2_t, data) + + af_params->action_frame.len; + af_params_v2_p = MALLOCZ(cfg->osh, wl_af_params_size); + if (af_params_v2_p == NULL) { + WL_ERR(("unable to allocate frame\n")); + ret = -ENOMEM; + goto exit; + } + ret = wl_actframe_fillup_v2(cfg, cfgdev, dev, af_params_v2_p, af_params, sa, + wl_af_params_size); + if (ret != BCME_OK) { + WL_ERR(("unable to fill actframe_params, ret %d\n", ret)); + goto exit; + } + af_params_iov_p = (u8 *)af_params_v2_p; + af_params_iov_len = wl_af_params_size; + } else { + ret = BCME_VERSION; + goto exit; + } + } else { + af_params_iov_p = (u8 *)af_params; + af_params_iov_len = sizeof(*af_params); + } - ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params), + ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params_iov_p, af_params_iov_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); if (ret < 0) { @@ -1752,8 +1915,13 @@ wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, timeout = wait_for_completion_timeout(&cfg->send_af_done, msecs_to_jiffies(af_params->dwell_time + WL_AF_TX_EXTRA_TIME_MAX)); - - if (timeout >= 0 && wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) { + if (timeout == 0) { + CFGP2P_DBG(("action frame dwell timeout completed\n")); + /* Call actframe_abort to cleanup FW state, when + * dwell timeout occurs. + */ + ret = wl_cfg80211_abort_action_frame(cfg, dev, bssidx); + } else if (timeout > 0 && wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) { CFGP2P_DBG(("tx action frame operation is completed\n")); ret = BCME_OK; } else if (ETHER_ISBCAST(&cfg->afx_hdl->tx_dst_addr)) { @@ -1768,8 +1936,11 @@ wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, wl_clr_p2p_status(cfg, ACTION_TX_NOACK); exit: - CFGP2P_DBG((" via act frame iovar : status = %d\n", ret)); + if (af_params_v2_p) { + MFREE(cfg->osh, af_params_v2_p, wl_af_params_size); + } + CFGP2P_DBG((" via act frame iovar : status = %d\n", ret)); bzero(&buf, sizeof(wl_eventmsg_buf_t)); wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, false); wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, false); @@ -1777,7 +1948,6 @@ exit: WL_ERR(("TX frame events revert back failed \n")); return evt_ret; } - return ret; } @@ -1785,36 +1955,39 @@ exit: * MAC address. */ void -wl_cfgp2p_generate_bss_mac(struct bcm_cfg80211 *cfg, struct ether_addr *primary_addr) +wl_cfgp2p_generate_bss_mac(struct bcm_cfg80211 *cfg) { struct ether_addr *mac_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE); - struct ether_addr *int_addr; + struct ether_addr *int_addr = NULL; #ifdef P2P_AP_CONCURRENT dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); #endif - - if (ETHER_IS_LOCALADDR(primary_addr)) { - /* STA is using locally administered MAC. Use randomized mac - * for p2p disc to avoid collision with sta mac add. - */ - wl_cfg80211_generate_mac_addr(mac_addr); - } else { - (void)memcpy_s(mac_addr, ETH_ALEN, bcmcfg_to_prmry_ndev(cfg)->perm_addr, ETH_ALEN); - mac_addr->octet[0] |= 0x02; -#ifdef P2P_AP_CONCURRENT - if (dhd->conf->war & P2P_AP_MAC_CONFLICT) - wl_ext_iapsta_get_vif_macaddr(dhd, 2, (u8 *)mac_addr); -#endif - WL_DBG(("P2P Discovery address:"MACDBG "\n", MAC2STRDBG(mac_addr->octet))); + if (!cfg->p2p) { + WL_ERR(("p2p not initialized\n")); + return; } +#ifdef WL_P2P_RAND + /* When p2p rand is enabled, use randomized mac by default */ + wl_cfg80211_generate_mac_addr(mac_addr); +#else + (void)memcpy_s(mac_addr->octet, ETHER_ADDR_LEN, + bcmcfg_to_prmry_ndev(cfg)->perm_addr, ETHER_ADDR_LEN); + mac_addr->octet[0] |= 0x02; +#ifdef P2P_AP_CONCURRENT + if (dhd->conf->war & P2P_AP_MAC_CONFLICT) + wl_ext_iapsta_get_vif_macaddr(dhd, 2, (u8 *)mac_addr); +#endif +#endif /* WL_P2P_RAND */ + WL_INFORM_MEM(("P2P Discovery address:"MACDBG "\n", MAC2STRDBG(mac_addr->octet))); + int_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_CONNECTION1); - memcpy(int_addr, mac_addr, sizeof(struct ether_addr)); + (void)memcpy_s(int_addr, sizeof(struct ether_addr), mac_addr, sizeof(struct ether_addr)); int_addr->octet[4] ^= 0x80; WL_DBG(("Primary P2P Interface address:"MACDBG "\n", MAC2STRDBG(int_addr->octet))); int_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_CONNECTION2); - memcpy(int_addr, mac_addr, sizeof(struct ether_addr)); + (void)memcpy_s(int_addr, sizeof(struct ether_addr), mac_addr, sizeof(struct ether_addr)); int_addr->octet[4] ^= 0x90; } @@ -2032,6 +2205,7 @@ wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* b } return ret; } + s32 wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int buf_len) { @@ -2075,6 +2249,7 @@ wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* b } return len * 2; } + s32 wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len) { @@ -2301,7 +2476,7 @@ wl_cfgp2p_find_attrib_in_all_p2p_Ies(const u8 *parse, u32 len, u32 attrib) } const u8 * -wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length) +wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_v109_t *bi, u32 bi_length) { const u8 *capability = NULL; bool p2p_go = 0; @@ -2403,7 +2578,7 @@ wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg) #endif /* Register with a dummy MAC addr */ - dev_addr_set(net, temp_addr); + DEV_ADDR_SET(net, temp_addr); #ifndef WL_NEWCFG_PRIVCMD_SUPPORT wdev->wiphy = cfg->wdev->wiphy; @@ -2465,6 +2640,7 @@ wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg) return 0; } + static netdev_tx_t wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev) { @@ -2621,8 +2797,9 @@ wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg) memcpy(wdev->address, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE), ETHER_ADDR_LEN); #if defined(WL_NEWCFG_PRIVCMD_SUPPORT) - if (cfg->p2p_net) - dev_addr_set(cfg->p2p_net, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE)); + if (cfg->p2p_net) { + DEV_ADDR_SET(cfg->p2p_net, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE)); + } #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ /* store p2p wdev ptr for further reference. */ @@ -2670,7 +2847,7 @@ wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) cfg->p2p_prb_noti = false; #endif - CFGP2P_DBG(("P2P interface started\n")); + printf("P2P interface started\n"); exit: return ret; @@ -2718,7 +2895,7 @@ wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) p2p_on(cfg) = false; - CFGP2P_DBG(("Exit. P2P interface stopped\n")); + printf("Exit. P2P interface stopped\n"); return; } @@ -2740,13 +2917,15 @@ wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg) return -EINVAL; } - /* Ensure discovery i/f is deinitialized */ - if (wl_cfgp2p_disable_discovery(cfg) != BCME_OK) { - /* discard error in the deinit part. Fw state - * recovery would happen from wl down/reset - * context. - */ - CFGP2P_ERR(("p2p disable disc failed\n")); + if (cfg->p2p != NULL) { + /* Ensure discovery i/f is deinitialized */ + if (wl_cfgp2p_disable_discovery(cfg) != BCME_OK) { + /* discard error in the deinit part. Fw state + * recovery would happen from wl down/reset + * context. + */ + CFGP2P_ERR(("p2p disable disc failed\n")); + } } if (!rtnl_is_locked()) { @@ -2785,7 +2964,7 @@ wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_le pact_frm = (wifi_p2p_pub_act_frame_t *)frame; if (pact_frm->subtype == P2P_PAF_GON_RSP && tx) { CFGP2P_ACTION(("Check TX P2P Group Owner Negotiation Rsp Frame status\n")); - status = pact_frm->elts[WL_P2P_AF_STATUS_OFFSET]; + status = *(pact_frm->elts + WL_P2P_AF_STATUS_OFFSET); if (status) { cfg->need_wait_afrx = false; return; @@ -2808,3 +2987,36 @@ wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request) } return false; } + +#ifdef BCMDBUS +int +wl_cfgp2p_start_p2p_device_resume(dhd_pub_t *dhd) +{ + int ret = 0; +#ifdef WL_CFG80211_P2P_DEV_IF + struct net_device *primary_ndev = dhd_linux_get_primary_netdev(dhd); + struct bcm_cfg80211 *cfg; + struct wiphy *wiphy; + + if (!primary_ndev) + return -EINVAL; + cfg = wl_get_cfg(primary_ndev); + if (!cfg) + return -EINVAL; + + RETURN_EIO_IF_NOT_UP(cfg); + if (!p2p_on(cfg)) + return -EINVAL; + + rtnl_lock(); + wiphy = bcmcfg_to_wiphy(cfg); + cfg->bus_resuming = TRUE; + ret = wl_cfgp2p_start_p2p_device(wiphy, cfg->wdev); + cfg->bus_resuming = FALSE; + printf("P2P interface resumed\n"); + rtnl_unlock(); +#endif + + return ret; +} +#endif /* BCMDBUS */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h old mode 100755 new mode 100644 index 58a161a254b5..d1ecbba5c837 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h @@ -1,7 +1,7 @@ /* * Linux cfgp2p driver * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -27,6 +27,7 @@ struct bcm_cfg80211; extern u32 wl_dbg_level; +extern u32 wl_log_level; typedef struct wifi_p2p_ie wifi_wfd_ie_t; /* Enumeration of the usages of the BSSCFGs used by the P2P Library. Do not @@ -125,9 +126,6 @@ enum wl_cfgp2p_status { #define p2p_scan(cfg) ((cfg)->p2p->scan) #define p2p_is_on(cfg) ((cfg)->p2p && (cfg)->p2p->on) -/* dword align allocation */ -#define WLC_IOCTL_MAXLEN 8192 - #if defined(CUSTOMER_DBG_PREFIX_ENABLE) #define USER_PREFIX_CFGP2P "[cfgp2p][wlan] " #define CFGP2P_ERROR_TEXT USER_PREFIX_CFGP2P @@ -135,46 +133,44 @@ enum wl_cfgp2p_status { #define CFGP2P_ACTION_TEXT USER_PREFIX_CFGP2P #define CFGP2P_DEBUG_TEXT USER_PREFIX_CFGP2P #else -/* Samsung want to print INFO2 instead of ERROR - * because most of case, ERROR message is not a real ERROR. - * but it can be regarded as real error case for Tester - */ -#ifdef CUSTOMER_HW4_DEBUG -#define CFGP2P_ERROR_TEXT "CFGP2P-INFO2) " -#else #define CFGP2P_ERROR_TEXT "CFGP2P-ERROR) " -#endif /* CUSTOMER_HW4_DEBUG */ #define CFGP2P_INFO_TEXT "CFGP2P-INFO) " #define CFGP2P_ACTION_TEXT "CFGP2P-ACTION) " #define CFGP2P_DEBUG_TEXT "CFGP2P-DEBUG) " #endif /* defined(CUSTOMER_DBG_PREFIX_ENABLE) */ #ifdef DHD_LOG_DUMP -#define CFGP2P_ERR_MSG(x, args...) \ - do { \ - if (wl_dbg_level & WL_DBG_ERR) { \ +#define CFGP2P_ERR_MSG(x, args...) \ + do { \ + if (wl_dbg_level & WL_DBG_ERR) { \ printf(CFGP2P_ERROR_TEXT "%s : " x, __func__, ## args); \ - DHD_LOG_DUMP_WRITE_TS_FN; \ - DHD_LOG_DUMP_WRITE(x, ## args); \ - } \ + } \ + if (wl_log_level & WL_DBG_ERR) { \ + DHD_LOG_DUMP_WRITE_TS_FN; \ + DHD_LOG_DUMP_WRITE(x, ## args); \ + } \ } while (0) #define CFGP2P_ERR(x) CFGP2P_ERR_MSG x -#define CFGP2P_INFO_MSG(x, args...) \ - do { \ - if (wl_dbg_level & WL_DBG_INFO) { \ +#define CFGP2P_INFO_MSG(x, args...) \ + do { \ + if (wl_dbg_level & WL_DBG_INFO) { \ printf(CFGP2P_INFO_TEXT "%s : " x, __func__, ## args); \ - DHD_LOG_DUMP_WRITE_TS_FN; \ - DHD_LOG_DUMP_WRITE(x, ## args); \ - } \ + } \ + if (wl_log_level & WL_DBG_INFO) { \ + DHD_LOG_DUMP_WRITE_TS_FN; \ + DHD_LOG_DUMP_WRITE(x, ## args); \ + } \ } while (0) #define CFGP2P_INFO(x) CFGP2P_INFO_MSG x -#define CFGP2P_ACTION_MSG(x, args...) \ - do { \ +#define CFGP2P_ACTION_MSG(x, args...) \ + do { \ if (wl_dbg_level & WL_DBG_P2P_ACTION) { \ printf(CFGP2P_ACTION_TEXT "%s : " x, __func__, ## args); \ - DHD_LOG_DUMP_WRITE_TS_FN; \ - DHD_LOG_DUMP_WRITE(x, ## args); \ - } \ + } \ + if (wl_log_level & WL_DBG_P2P_ACTION) { \ + DHD_LOG_DUMP_WRITE_TS_FN; \ + DHD_LOG_DUMP_WRITE(x, ## args); \ + } \ } while (0) #define CFGP2P_ACTION(x) CFGP2P_ACTION_MSG x #else @@ -209,27 +205,19 @@ enum wl_cfgp2p_status { } while (0) #define CFGP2P_DBG(x) CFGP2P_DBG_MSG x -#define INIT_TIMER(timer, func, duration, extra_delay) \ - do { \ - init_timer_compat(timer, func, cfg); \ - timer_expires(timer) = jiffies + msecs_to_jiffies(duration + extra_delay); \ - add_timer(timer); \ - } while (0); - #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 8)) #ifdef WL_SUPPORT_BACKPORTED_KPATCHES #undef WL_SUPPORT_BACKPORTED_KPATCHES #endif #endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)) #ifdef WL_CFG80211_STA_EVENT #undef WL_CFG80211_STA_EVENT #endif #endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) && \ - !defined(WL_CFG80211_P2P_DEV_IF) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) && !defined(WL_CFG80211_P2P_DEV_IF) #define WL_CFG80211_P2P_DEV_IF #ifdef WL_ENABLE_P2P_IF @@ -365,11 +353,11 @@ wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev const wl_event_msg_t *e, void *data); extern s32 -wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, - wl_af_params_t *af_params, s32 bssidx); +wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + struct net_device *dev, wl_af_params_v1_t *af_params, s32 bssidx, const u8 *sa); extern void -wl_cfgp2p_generate_bss_mac(struct bcm_cfg80211 *cfg, struct ether_addr *primary_addr); +wl_cfgp2p_generate_bss_mac(struct bcm_cfg80211 *cfg); extern void wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id); @@ -402,7 +390,7 @@ extern const u8* wl_cfgp2p_find_attrib_in_all_p2p_Ies(const u8 *parse, u32 len, u32 attrib); extern const u8 * -wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length); +wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_v109_t *bi, u32 bi_length); extern s32 wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg); @@ -446,6 +434,9 @@ wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_le extern int wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request); +extern s32 +wl_cfg80211_abort_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev, s32 bssidx); + /* WiFi Direct */ #define SOCIAL_CHAN_1 1 #define SOCIAL_CHAN_2 6 @@ -485,4 +476,9 @@ wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request); * instead of channel in actframe iovar. */ #define FW_MAJOR_VER_ACTFRAME_CHSPEC 14 + +#ifdef BCMDBUS +int +wl_cfgp2p_start_p2p_device_resume(dhd_pub_t *dhd); +#endif /* BCMDBUS */ #endif /* _wl_cfgp2p_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgscan.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgscan.c old mode 100755 new mode 100644 index d2a2bf1cb454..006be856a7d7 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgscan.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgscan.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver scan related code * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -84,6 +84,9 @@ #ifdef RTT_SUPPORT #include "dhd_rtt.h" #endif /* RTT_SUPPORT */ +#ifdef WL_CELLULAR_CHAN_AVOID +#include +#endif /* WL_CELLULAR_CHAN_AVOID */ #include #define ACTIVE_SCAN 1 @@ -114,18 +117,13 @@ cfg80211_sched_scan_stopped(wiphy); #endif /* KERNEL > 4.11.0 */ -#ifdef DHD_GET_VALID_CHANNELS #define IS_DFS(chaninfo) ((chaninfo & WL_CHAN_RADAR) || \ (chaninfo & WL_CHAN_PASSIVE)) -#endif /* DHD_GET_VALID_CHANNELS */ #if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME) #define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40 bool g_first_broadcast_scan = TRUE; #endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */ -#ifdef CUSTOMER_HW4_DEBUG -bool wl_scan_timeout_dbg_enabled = 0; -#endif /* CUSTOMER_HW4_DEBUG */ #ifdef P2P_LISTEN_OFFLOADING void wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg); #endif /* P2P_LISTEN_OFFLOADING */ @@ -135,18 +133,10 @@ static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg, void wl_cfgscan_scan_abort(struct bcm_cfg80211 *cfg); static void _wl_cfgscan_cancel_scan(struct bcm_cfg80211 *cfg); -#if defined (WL_SCHED_SCAN) && defined (SCHED_SCAN_DELAYED_WORK) +#ifdef PNO_SUPPORT void wl_cfg80211_stop_pno(struct bcm_cfg80211 *cfg, struct net_device *dev); #endif /* WL_SCHED_SCAN */ -#ifdef ESCAN_CHANNEL_CACHE -void reset_roam_cache(struct bcm_cfg80211 *cfg); -void add_roam_cache(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi); -int get_roam_channel_list(struct bcm_cfg80211 *cfg, chanspec_t target_chan, chanspec_t *channels, - int n_channels, const wlc_ssid_t *ssid, int ioctl_ver); -void set_roam_band(int band); -#endif /* ESCAN_CHANNEL_CACHE */ - #ifdef ROAM_CHANNEL_CACHE void print_roam_cache(struct bcm_cfg80211 *cfg); #endif /* ROAM_CHANNEL_CACHE */ @@ -154,7 +144,7 @@ void print_roam_cache(struct bcm_cfg80211 *cfg); extern int passive_channel_skip; #ifdef DUAL_ESCAN_RESULT_BUFFER -static wl_scan_results_t * +static wl_scan_results_v109_t * wl_escan_get_buf(struct bcm_cfg80211 *cfg, bool aborted) { u8 index; @@ -168,8 +158,9 @@ wl_escan_get_buf(struct bcm_cfg80211 *cfg, bool aborted) index = (cfg->escan_info.cur_sync_id)%SCAN_BUF_CNT; } - return (wl_scan_results_t *)cfg->escan_info.escan_buf[index]; + return (wl_scan_results_v109_t *)cfg->escan_info.escan_buf[index]; } + static int wl_escan_check_sync_id(struct bcm_cfg80211 *cfg, s32 status, u16 result_id, u16 wl_id) { @@ -188,10 +179,18 @@ wl_escan_check_sync_id(struct bcm_cfg80211 *cfg, s32 status, u16 result_id, u16 return 0; } } + +#ifdef SYNCID_MISMATCH_DEBUG +#define wl_escan_increment_sync_id(a, b) \ + ((u8)((a)->escan_info.cur_sync_id + b) == 0 ? \ + ((a)->escan_info.cur_sync_id = 1) : ((a)->escan_info.cur_sync_id += b)) +#define wl_escan_init_sync_id(a) ((a)->escan_info.cur_sync_id = 1) +#else #define wl_escan_increment_sync_id(a, b) ((a)->escan_info.cur_sync_id += b) #define wl_escan_init_sync_id(a) ((a)->escan_info.cur_sync_id = 0) +#endif /* SYNCID_MISMATCH_DEBUG */ #else -#define wl_escan_get_buf(a, b) ((wl_scan_results_t *) (a)->escan_info.escan_buf) +#define wl_escan_get_buf(a, b) ((wl_scan_results_v109_t *) (a)->escan_info.escan_buf) #define wl_escan_check_sync_id(a, b, c, d) 0 #define wl_escan_increment_sync_id(a, b) #define wl_escan_init_sync_id(a) @@ -208,13 +207,14 @@ static void wl_rst_ie(struct bcm_cfg80211 *cfg) bzero(ie->buf, sizeof(ie->buf)); } -static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 *ie_size, - bool update_ssid) +static void wl_update_hidden_ap_ie(wl_bss_info_v109_t *bi, const u8 *ie_stream, u32 *ie_size, + bool update_ssid, u32 *ssid_len_from_ie) { u8 *ssidie; int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN); int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len; /* cfg80211_find_ie defined in kernel returning const u8 */ + int ret = 0; GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size); @@ -230,6 +230,8 @@ static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 * if (!ssidie) { return; } + *ssid_len_from_ie = (u32)ssidie[1]; + available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream); remaining_ie_buf_len = available_buffer_len - (int)ssidie[1]; unused_buf_len = WL_EXTRA_BUF_MAX - (4 + bi->length + *ie_size); @@ -256,10 +258,19 @@ static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 * */ if ((update_ssid && (ssid_len > ssidie[1])) && (unused_buf_len > ssid_len)) { WL_INFORM_MEM(("Changing the SSID Info.\n")); - memmove(ssidie + ssid_len + 2, - (ssidie + 2) + ssidie[1], - remaining_ie_buf_len); - memcpy(ssidie + 2, bi->SSID, ssid_len); + ret = memmove_s(ssidie + ssid_len + 2, available_buffer_len, + (ssidie + 2) + ssidie[1], remaining_ie_buf_len); + if (ret) { + WL_ERR(("SSID Info memmove failed:%d, destsz:%d, n:%d\n", + ret, available_buffer_len, remaining_ie_buf_len)); + return; + } + ret = memcpy_s(ssidie + 2, DOT11_MAX_SSID_LEN, bi->SSID, ssid_len); + if (ret) { + WL_ERR(("SSID Info memcpy failed:%d, destsz:%d, n:%d\n", + ret, DOT11_MAX_SSID_LEN, ssid_len)); + return; + } *ie_size = *ie_size + ssid_len - ssidie[1]; ssidie[1] = ssid_len; } else if (ssid_len < ssidie[1]) { @@ -268,8 +279,14 @@ static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 * } return; } - if (*(ssidie + 2) == '\0') - memcpy(ssidie + 2, bi->SSID, ssid_len); + if (*(ssidie + 2) == '\0') { + ret = memcpy_s(ssidie + 2, DOT11_MAX_SSID_LEN, bi->SSID, ssid_len); + if (ret) { + WL_ERR(("memcopy failed:%d, destsz:%d, n:%d\n", + ret, DOT11_MAX_SSID_LEN, ssid_len)); + return; + } + } return; } @@ -277,12 +294,19 @@ static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size) { struct wl_ie *ie = wl_to_ie(cfg); s32 err = 0; + int ret = 0; if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) { WL_ERR(("ei_stream crosses buffer boundary\n")); return -ENOSPC; } - memcpy(&ie->buf[ie->offset], ie_stream, ie_size); + ret = memcpy_s(&ie->buf[ie->offset], (sizeof(ie->buf) - ie->offset), + ie_stream, ie_size); + if (ret) { + WL_ERR(("memcpy failed:%d, destsz: %zu, n: %d\n", + ret, (sizeof(ie->buf) - ie->offset), ie_size)); + return BCME_ERROR; + } ie->offset += ie_size; return err; @@ -309,7 +333,7 @@ static u32 wl_get_ielen(struct bcm_cfg80211 *cfg) return ie->offset; } -s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool update_ssid) +s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_v109_t *bi, bool update_ssid) { struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); struct ieee80211_mgmt *mgmt; @@ -329,6 +353,7 @@ s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool updat s32 err = 0; gfp_t aflags; u8 tmp_buf[IEEE80211_MAX_SSID_LEN + 1]; + u32 ssid_len_from_ie = 0; chanspec_t chanspec; if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { @@ -336,6 +361,12 @@ s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool updat return err; } + if (bi->length < (bi->ie_offset + bi->ie_length)) { + WL_ERR(("IE length is not Valid. IE offse:%d, len:%d\n", + bi->ie_offset, bi->ie_length)); + return -EINVAL; + } + if (bi->SSID_len > IEEE80211_MAX_SSID_LEN) { WL_ERR(("wrong SSID len:%d\n", bi->SSID_len)); return -EINVAL; @@ -390,7 +421,13 @@ s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool updat beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); beacon_proberesp->capab_info = cpu_to_le16(bi->capability); wl_rst_ie(cfg); - wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, update_ssid); + wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, + update_ssid, &ssid_len_from_ie); + if (ssid_len_from_ie > IEEE80211_MAX_SSID_LEN) { + WL_ERR(("wrong SSID len from ie: %d\n", ssid_len_from_ie)); + err = -EINVAL; + goto out_err; + } wl_mrg_ie(cfg, ((u8 *) bi) + bi->ie_offset, bi->ie_length); wl_cp_ie(cfg, beacon_proberesp->variable, WL_BSS_INFO_MAX - offsetof(struct wl_cfg80211_bss_info, frame_buf)); @@ -406,9 +443,9 @@ s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool updat channel = ieee80211_get_channel(wiphy, freq); memcpy(tmp_buf, bi->SSID, bi->SSID_len); tmp_buf[bi->SSID_len] = '\0'; - WL_SCAN(("BSSID %pM, channel %3d(%3d %3sMHz), rssi %3d, capa 0x%-4x, mgmt_type %d, " + WL_SCAN(("BSSID %pM, channel %s-%-3d(%3d %3sMHz), rssi %3d, capa 0x%-4x, mgmt_type %d, " "frame_len %3d, SSID \"%s\"\n", - &bi->BSSID, notif_bss_info->channel, CHSPEC_CHANNEL(chanspec), + &bi->BSSID, CHSPEC2BANDSTR(chanspec), notif_bss_info->channel, CHSPEC_CHANNEL(chanspec), CHSPEC_IS20(chanspec)?"20": CHSPEC_IS40(chanspec)?"40": CHSPEC_IS80(chanspec)?"80": @@ -427,8 +464,8 @@ s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool updat #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) struct osl_timespec ts; osl_get_monotonic_boottime(&ts); - mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000) - + ts.tv_nsec / 1000; + mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*USEC_PER_SEC) + + (ts.tv_nsec / NSEC_PER_USEC); #else struct osl_timespec tv; osl_do_gettimeofday(&tv); @@ -524,7 +561,7 @@ void wl_cfg80211_update_bss_cache(struct bcm_cfg80211 *cfg) struct net_device *ndev = wl_get_scan_ndev(cfg); int rssi; #endif - wl_scan_results_t *bss_list = cfg->bss_list; + wl_scan_results_v109_t *bss_list = cfg->bss_list; /* Free cache in p2p scanning*/ if (p2p_is_on(cfg) && p2p_scan(cfg)) { @@ -567,8 +604,8 @@ void wl_cfg80211_update_bss_cache(struct bcm_cfg80211 *cfg) #if defined(BSSCACHE) s32 wl_inform_bss_cache(struct bcm_cfg80211 *cfg) { - wl_scan_results_t *bss_list = cfg->bss_list; - wl_bss_info_t *bi = NULL; /* must be initialized */ + wl_scan_results_v109_t *bss_list = cfg->bss_list; + wl_bss_info_v109_t *bi = NULL; /* must be initialized */ s32 err = 0; s32 i, cnt; wl_bss_cache_t *node; @@ -584,7 +621,7 @@ s32 wl_inform_bss_cache(struct bcm_cfg80211 *cfg) } } - cnt = i; + cnt = i; node = cfg->g_bss_cache_ctrl.m_cache_head; WL_SCAN(("cached AP count (%d)\n", wl_bss_cache_size(&cfg->g_bss_cache_ctrl))); for (i=cnt; node && iautochannel && ndev) { #if defined(BSSCACHE) - wl_ext_get_best_channel(ndev, &cfg->g_bss_cache_ctrl, ioctl_version, + wl_ext_get_best_channel(ndev, &cfg->g_bss_cache_ctrl, &cfg->best_2g_ch, &cfg->best_5g_ch, &cfg->best_6g_ch); #else - wl_ext_get_best_channel(ndev, bss_list, ioctl_version, + wl_ext_get_best_channel(ndev, bss_list, &cfg->best_2g_ch, &cfg->best_5g_ch, &cfg->best_6g_ch); #endif } @@ -701,7 +738,7 @@ wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bss s32 err = BCME_OK; s32 buf_len; ie_setbuf_t *ie_setbuf; - ie_getbuf_t ie_getbufp; + ie_getbuf_t ie_getbufp = {0, 0}; char getbuf[WLC_IOCTL_SMLEN]; if (ie_id != DOT11_MNG_INTERWORKING_ID) { @@ -785,6 +822,7 @@ wl_bcnrecv_result_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, struct wiphy *wiphy = NULL; wl_bcnrecv_result_t *bcn_recv = NULL; struct osl_timespec ts; + int ret = 0; if (!bi) { WL_ERR(("%s: bi is NULL\n", __func__)); err = BCME_NORESOURCE; @@ -807,19 +845,23 @@ wl_bcnrecv_result_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_ERR(("Failed to allocate memory\n")); return -ENOMEM; } - /* Returning void here as copy size does not exceed dest size of SSID */ - (void)memcpy_s((char *)bcn_recv->SSID, DOT11_MAX_SSID_LEN, - (char *)bi->SSID, DOT11_MAX_SSID_LEN); - /* Returning void here as copy size does not exceed dest size of ETH_LEN */ - (void)memcpy_s(&bcn_recv->BSSID, ETHER_ADDR_LEN, &bi->BSSID, ETH_ALEN); + ret = memcpy_s((char *)bcn_recv->SSID, sizeof(bcn_recv->SSID), + (char *)bi->SSID, bi->SSID_len); + if (ret) { + WL_ERR(("memcpy failed:%d, destsz:%lu, n:%d\n", + ret, sizeof(bcn_recv->SSID), bi->SSID_len)); + err = BCME_ERROR; + goto exit; + } + eacopy(&bi->BSSID, &bcn_recv->BSSID); bcn_recv->channel = wf_chspec_ctlchan( wl_chspec_driver_to_host(bi->chanspec)); bcn_recv->beacon_interval = bi->beacon_period; /* kernal timestamp */ osl_get_monotonic_boottime(&ts); - bcn_recv->system_time = ((u64)ts.tv_sec*1000000) - + ts.tv_nsec / 1000; + bcn_recv->system_time = ((u64)ts.tv_sec*USEC_PER_SEC) + + ts.tv_nsec / NSEC_PER_USEC; bcn_recv->timestamp[0] = bi->timestamp[0]; bcn_recv->timestamp[1] = bi->timestamp[1]; if ((err = wl_android_bcnrecv_event(cfgdev_to_wlc_ndev(cfgdev, cfg), @@ -841,13 +883,21 @@ exit: #ifdef ESCAN_BUF_OVERFLOW_MGMT #ifndef WL_DRV_AVOID_SCANCACHE +#ifdef WL_6G_BAND +#define WL_6G_CMP 30 /* (dBm) 6G Band RSSI compensation */ +#define BSSRSSI(b) \ + (CHSPEC_IS6G((b)->chanspec) ? (((b)->RSSI) + (WL_6G_CMP)) : ((b)->RSSI)) +#else +#define BSSRSSI(b) ((b)->RSSI) +#endif /* WL_6G_BAND */ + static void -wl_cfg80211_find_removal_candidate(wl_bss_info_t *bss, removal_element_t *candidate) +wl_cfg80211_find_removal_candidate(wl_bss_info_v109_t *bss, removal_element_t *candidate) { int idx; for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) { int len = BUF_OVERFLOW_MGMT_COUNT - idx - 1; - if (bss->RSSI < candidate[idx].RSSI) { + if (BSSRSSI(bss) < candidate[idx].RSSI) { if (len) { /* In the below memcpy operation the candidate array always has the * buffer space available to max 'len' calculated in the for loop. @@ -856,7 +906,7 @@ wl_cfg80211_find_removal_candidate(wl_bss_info_t *bss, removal_element_t *candid (sizeof(removal_element_t) * len), &candidate[idx], sizeof(removal_element_t) * len); } - candidate[idx].RSSI = bss->RSSI; + candidate[idx].RSSI = BSSRSSI(bss); candidate[idx].length = bss->length; (void)memcpy_s(&candidate[idx].BSSID, ETHER_ADDR_LEN, &bss->BSSID, ETHER_ADDR_LEN); @@ -866,24 +916,24 @@ wl_cfg80211_find_removal_candidate(wl_bss_info_t *bss, removal_element_t *candid } static void -wl_cfg80211_remove_lowRSSI_info(wl_scan_results_t *list, removal_element_t *candidate, - wl_bss_info_t *bi) +wl_cfg80211_remove_lowRSSI_info(wl_scan_results_v109_t *list, removal_element_t *candidate, + wl_bss_info_v109_t *bi) { int idx1, idx2; int total_delete_len = 0; for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) { - int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; - wl_bss_info_t *bss = NULL; - if (candidate[idx1].RSSI >= bi->RSSI) + int cur_len = WL_SCAN_RESULTS_V109_FIXED_SIZE; + wl_bss_info_v109_t *bss = NULL; + if (candidate[idx1].RSSI >= BSSRSSI(bi)) continue; for (idx2 = 0; idx2 < list->count; idx2++) { - bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) : + bss = bss ? (wl_bss_info_v109_t *)((uintptr)bss + dtoh32(bss->length)) : list->bss_info; if (!bss) { continue; } if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) && - candidate[idx1].RSSI == bss->RSSI && + candidate[idx1].RSSI == BSSRSSI(bss) && candidate[idx1].length == dtoh32(bss->length)) { u32 delete_len = dtoh32(bss->length); WL_DBG(("delete scan info of " MACDBG " to add new AP\n", @@ -914,15 +964,15 @@ wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, { s32 err = BCME_OK; s32 status = ntoh32(e->status); - wl_escan_result_t *escan_result; + wl_escan_result_v109_t *escan_result; struct net_device *ndev = NULL; #ifndef WL_DRV_AVOID_SCANCACHE - wl_bss_info_t *bi; + wl_bss_info_v109_t *bi; u32 bi_length; const wifi_p2p_ie_t * p2p_ie; const u8 *p2p_dev_addr = NULL; - wl_scan_results_t *list; - wl_bss_info_t *bss = NULL; + wl_scan_results_v109_t *list; + wl_bss_info_v109_t *bss = NULL; u32 i; #endif /* WL_DRV_AVOID_SCANCACHE */ u16 channel; @@ -955,7 +1005,7 @@ wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, else ndev = cfg->escan_info.ndev; } - escan_result = (wl_escan_result_t *)data; + escan_result = (wl_escan_result_v109_t *)data; if (!escan_result) { WL_ERR(("Invalid escan result (NULL data)\n")); goto exit; @@ -992,7 +1042,7 @@ wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_DBG(("WLC_E_STATUS_PARTIAL \n")); DBG_EVENT_LOG((dhd_pub_t *)cfg->pub, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND); if ((dtoh32(escan_result->buflen) > (int)ESCAN_BUF_SIZE) || - (dtoh32(escan_result->buflen) < sizeof(wl_escan_result_t))) { + (dtoh32(escan_result->buflen) < sizeof(wl_escan_result_v109_t))) { WL_ERR(("Invalid escan buffer len:%d\n", dtoh32(escan_result->buflen))); goto exit; } @@ -1006,7 +1056,8 @@ wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, goto exit; } bi_length = dtoh32(bi->length); - if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { + if (bi_length != (dtoh32(escan_result->buflen) + - WL_ESCAN_RESULTS_V109_FIXED_SIZE)) { WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length)); goto exit; } @@ -1022,8 +1073,6 @@ wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_ERR(("No valid band\n")); goto exit; } - if (!dhd_conf_match_channel(cfg->pub, channel)) - goto exit; /* ----- terence 20130524: skip invalid bss */ if (!(bcmcfg_to_wiphy(cfg)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) { @@ -1055,7 +1104,7 @@ wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } } else { - int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; + int cur_len = WL_SCAN_RESULTS_V109_FIXED_SIZE; #ifdef ESCAN_BUF_OVERFLOW_MGMT removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT]; int remove_lower_rssi = FALSE; @@ -1102,8 +1151,8 @@ wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, #endif /* ESCAN_BUF_OVERFLOW_MGMT */ for (i = 0; i < list->count; i++) { - bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) - : list->bss_info; + bss = bss ? (wl_bss_info_v109_t *) + ((uintptr)bss + dtoh32(bss->length)): list->bss_info; if (!bss) { WL_ERR(("bss is NULL\n")); goto exit; @@ -1246,6 +1295,13 @@ wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } } else if (status == WLC_E_STATUS_SUCCESS) { + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + if ((dhdp->dhd_induce_error == DHD_INDUCE_SCAN_TIMEOUT) || + (dhdp->dhd_induce_error == DHD_INDUCE_SCAN_TIMEOUT_SCHED_ERROR)) { + WL_ERR(("Skip escan complete to induce scantimeout\n")); + err = BCME_ERROR; + goto exit; + } cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; #ifdef DHD_SEND_HANG_ESCAN_SYNCID_MISMATCH cfg->escan_info.prev_escan_aborted = FALSE; @@ -1268,10 +1324,6 @@ wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, wl_notify_escan_complete(cfg, ndev, false); } wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT); -#ifdef CUSTOMER_HW4_DEBUG - if (wl_scan_timeout_dbg_enabled) - wl_scan_timeout_dbg_clear(); -#endif /* CUSTOMER_HW4_DEBUG */ } else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN) || (status == WLC_E_STATUS_11HQUIET) || (status == WLC_E_STATUS_CS_ABORT) || (status == WLC_E_STATUS_NEWASSOC)) { @@ -1289,8 +1341,14 @@ wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, if (cfg->afx_hdl->peer_chan == WL_INVALID) complete(&cfg->act_frm_scan); } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) { - WL_INFORM_MEM(("ESCAN ABORTED\n")); + WL_INFORM_MEM(("ESCAN ABORTED - reason:%d\n", status)); + if (cfg->escan_info.ndev != ndev) { + /* Ignore events coming for older scan reqs */ + WL_INFORM_MEM(("abort event doesn't match on going scan req\n")); + err = BCME_ERROR; + goto exit; + } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) if (p2p_scan(cfg) && cfg->scan_request && (cfg->scan_request->flags & NL80211_SCAN_FLAG_FLUSH)) { @@ -1336,7 +1394,7 @@ wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg->scan_request)); WL_ERR(("reason[0x%x]\n", e->reason)); if (e->reason == 0xFFFFFFFF) { - wl_scan_results_t *bss_list; + wl_scan_results_v109_t *bss_list; bss_list = wl_escan_get_buf(cfg, FALSE); if (!bss_list) { WL_ERR(("bss_list is null. Didn't receive any partial scan results\n")); @@ -1381,7 +1439,119 @@ exit: return err; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) +#ifdef WL_SCHED_SCAN +s32 wl_cfgscan_pfn_handler(struct bcm_cfg80211 *cfg, wl_pfn_scanresult_v3_1_t *pfn_scanresult) +{ + s32 err = BCME_OK; + wl_bss_info_v109_t *bi = NULL; + + bi = (wl_bss_info_v109_t *)pfn_scanresult->bss_info; + if (!bi) { + WL_ERR(("Invalid pfn bss info (NULL pointer)" + "or invalid bss_info length\n")); + goto exit; + } + preempt_disable(); +#ifdef ESCAN_CHANNEL_CACHE + add_roam_cache(cfg, bi); +#endif /* ESCAN_CHANNEL_CACHE */ + err = wl_inform_single_bss(cfg, bi, false); + if (unlikely(err)) { + WL_ERR(("bss inform failed\n")); + } + preempt_enable(); + WL_MEM(("cfg80211 scan cache updated\n")); +exit: + return err; +} + +s32 +wl_cfgscan_pfn_scanresult_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + s32 err = BCME_OK; + wl_pfn_scanresult_v3_1_t *pfn_scanresult; + + WL_DBG_MEM(("event type : %d, status : %d \n", + ntoh32(e->event_type), ntoh32(e->status))); + + mutex_lock(&cfg->scan_sync); + + pfn_scanresult = (wl_pfn_scanresult_v3_1_t *)data; + if (!pfn_scanresult) { + WL_ERR(("Invalid pfn scan result (NULL data)\n")); + goto exit; + } + + if (cfg->sched_scan_req) { + err = wl_cfgscan_pfn_handler(cfg, pfn_scanresult); + } +exit: + mutex_unlock(&cfg->scan_sync); + return err; +} +#endif /* WL_SCHED_SCAN */ + +#if defined(GSCAN_SUPPORT) || defined(WL_SCHED_SCAN) +/* sched scan done and stop pno upon receiving the pfn scan complete event */ +s32 +wl_cfgscan_notify_pfn_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + s32 err = BCME_OK; + struct net_device *dev; + s32 status = ntoh32(e->status); + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + struct wiphy *wiphy = NULL; + + dev = cfgdev_to_wlc_ndev(cfgdev, cfg); + WL_DBG_MEM(("Enter \n")); + BCM_REFERENCE(dhdp); + +#ifdef GSCAN_SUPPORT + err = wl_notify_gscan_event(cfg, cfgdev, e, data); + return err; +#endif + mutex_lock(&cfg->scan_sync); + + if (!cfg->sched_scan_req) { + WL_INFORM_MEM(("No sched scan req is in progress.\n")); + goto exit; + } + + wiphy = cfg->sched_scan_req->wiphy; + /* If new sched scan triggered, wiphy set as NULL. + * In this case, drop this event to avoid kernel state schew up + */ + if (!wiphy) { + WL_INFORM_MEM(("wiphy of sched_scan_req is NULL.\n")); + goto exit; + } + + if (status == WLC_E_STATUS_SUCCESS) { + WL_INFORM_MEM(("[%s] Report sched scan done.\n", dev->name)); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) + cfg80211_sched_scan_results(wiphy, + cfg->sched_scan_req->reqid); +#else + cfg80211_sched_scan_results(wiphy); +#endif /* LINUX_VER > 4.11 */ + } else if (status != WLC_E_STATUS_SUCCESS) { + WL_INFORM_MEM(("bss list empty. report sched_scan_stop\n")); + wl_cfg80211_stop_pno(cfg, bcmcfg_to_prmry_ndev(cfg)); +#ifdef WL_SCHED_SCAN + /* schedule the work to indicate sched scan stop to cfg layer */ + schedule_delayed_work(&cfg->sched_scan_stop_work, 0); +#endif /* WL_SCHED_SCAN */ + } +exit: + mutex_unlock(&cfg->scan_sync); + return err; +} +#endif /* GSCAN_SUPPORT || WL_SCHED_SCAN */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && \ + defined(SUPPORT_RANDOM_MAC_SCAN) static const u8 * wl_retrieve_wps_attribute(const u8 *buf, u16 element_id) { @@ -1506,6 +1676,13 @@ wl_cfgscan_map_nl80211_scan_type(struct bcm_cfg80211 *cfg, struct cfg80211_scan_ return scan_flags; } + if (cfg->latency_mode && + wl_is_sta_connected(cfg)) { + WL_DBG_MEM(("latency mode on. force LP scan\n")); + scan_flags |= WL_SCANFLAGS_LOW_POWER_SCAN; + goto exit; + } + if (request->flags & NL80211_SCAN_FLAG_LOW_SPAN) { scan_flags |= WL_SCANFLAGS_LOW_SPAN; } @@ -1519,6 +1696,7 @@ wl_cfgscan_map_nl80211_scan_type(struct bcm_cfg80211 *cfg, struct cfg80211_scan_ scan_flags |= WL_SCANFLAGS_LOW_PRIO; } +exit: WL_INFORM(("scan flags. wl:%x cfg80211:%x\n", scan_flags, request->flags)); return scan_flags; } @@ -1601,11 +1779,6 @@ wl_cfgscan_populate_scan_channel(struct bcm_cfg80211 *cfg, } #endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) -#define IS_RADAR_CHAN(flags) (flags & (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN)) -#else -#define IS_RADAR_CHAN(flags) (flags & (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR)) -#endif static void wl_cfgscan_populate_scan_channels(struct bcm_cfg80211 *cfg, struct ieee80211_channel **channels, u32 n_channels, @@ -1613,7 +1786,6 @@ wl_cfgscan_populate_scan_channels(struct bcm_cfg80211 *cfg, { u32 i = 0, j = 0; u32 chanspec = 0; - struct wireless_dev *wdev; bool is_p2p_scan = false; #ifdef P2P_SKIP_DFS int is_printed = false; @@ -1625,13 +1797,6 @@ wl_cfgscan_populate_scan_channels(struct bcm_cfg80211 *cfg, return; } - wdev = GET_SCAN_WDEV(cfg->scan_request); - if (!skip_dfs && wdev && wdev->netdev && - (wdev->netdev != bcmcfg_to_prmry_ndev(cfg))) { - /* SKIP DFS channels for Secondary interface */ - skip_dfs = true; - } - /* Check if request is for p2p scans */ is_p2p_scan = p2p_is_on(cfg) && p2p_scan(cfg); @@ -1642,8 +1807,6 @@ wl_cfgscan_populate_scan_channels(struct bcm_cfg80211 *cfg, (channels[i]->center_freq))); continue; } - if (!dhd_conf_match_channel(cfg->pub, channel)) - continue; chanspec = wl_freq_to_chanspec(channels[i]->center_freq); if (chanspec == INVCHANSPEC) { @@ -1697,6 +1860,14 @@ wl_cfgscan_populate_scan_channels(struct bcm_cfg80211 *cfg, continue; } #endif /* P2P_SKIP_DFS */ +#ifdef WL_UNII4_CHAN + /* Skip UNII-4 frequencies */ + if (CHSPEC_IS5G(chanspec) && + IS_UNII4_CHANNEL(wf_chspec_primary20_chan(chanspec))) { + WL_DBG(("Skip UNII-4 chanspec 0x%x\n", chanspec)); + continue; + } +#endif /* WL_UNII4_CHAN */ } if (use_chanspecs) { @@ -1704,7 +1875,8 @@ wl_cfgscan_populate_scan_channels(struct bcm_cfg80211 *cfg, } else { channel_list[j] = CHSPEC_CHANNEL(chanspec); } - WL_SCAN(("chan: %d, chanspec: %x\n", channel, channel_list[j])); + WL_SCAN(("chan: %s-%d, chanspec: %x\n", + CHSPEC2BANDSTR(chanspec), wf_chspec_ctlchan(chanspec), channel_list[j])); j++; if (j == WL_NUMCHANSPECS) { /* max limit */ @@ -1770,8 +1942,8 @@ wl_scan_prep(struct bcm_cfg80211 *cfg, struct net_device *ndev, void *scan_param struct wl_chan_info chan_info; u32 channel; #endif - wl_scan_params_t *params = NULL; - wl_scan_params_v2_t *params_v2 = NULL; + wl_scan_params_v1_t *params = NULL; + wl_scan_params_v3_t *params_v3 = NULL; u32 scan_type = 0; u32 scan_param_size = 0; u32 n_channels = 0; @@ -1790,34 +1962,41 @@ wl_scan_prep(struct bcm_cfg80211 *cfg, struct net_device *ndev, void *scan_param } WL_DBG(("Preparing Scan request\n")); - if (cfg->scan_params_v2) { - params_v2 = (wl_scan_params_v2_t *)scan_params; - scan_param_size = sizeof(wl_scan_params_v2_t); - channel_offset = offsetof(wl_scan_params_v2_t, channel_list); + if (IS_SCAN_PARAMS_V3_V2(cfg)) { + params_v3 = (wl_scan_params_v3_t *)scan_params; + scan_param_size = sizeof(wl_scan_params_v3_t); + channel_offset = offsetof(wl_scan_params_v3_t, channel_list); } else { - params = (wl_scan_params_t *)scan_params; - scan_param_size = sizeof(wl_scan_params_t); - channel_offset = offsetof(wl_scan_params_t, channel_list); + params = (wl_scan_params_v1_t *)scan_params; + scan_param_size = sizeof(wl_scan_params_v1_t); + channel_offset = offsetof(wl_scan_params_v1_t, channel_list); } - if (params_v2) { - /* scan params ver2 */ + if (params_v3) { + /* scan params ver3 */ #if defined(WL_SCAN_TYPE) scan_type += wl_cfgscan_map_nl80211_scan_type(cfg, request); #endif /* WL_SCAN_TYPE */ + (void)memcpy_s(¶ms_v3->bssid, ETHER_ADDR_LEN, ðer_bcast, ETHER_ADDR_LEN); + params_v3->version = htod16(cfg->scan_params_ver); + params_v3->length = htod16(sizeof(wl_scan_params_v3_t)); + params_v3->bss_type = DOT11_BSSTYPE_ANY; + params_v3->scan_type = htod32(scan_type); + params_v3->nprobes = htod32(-1); + params_v3->active_time = htod32(-1); + params_v3->passive_time = htod32(-1); + params_v3->home_time = htod32(-1); + params_v3->channel_num = 0; + bzero(¶ms_v3->ssid, sizeof(wlc_ssid_t)); + chan_list = params_v3->channel_list; - (void)memcpy_s(¶ms_v2->bssid, ETHER_ADDR_LEN, ðer_bcast, ETHER_ADDR_LEN); - params_v2->version = htod16(WL_SCAN_PARAMS_VERSION_V2); - params_v2->length = htod16(sizeof(wl_scan_params_v2_t)); - params_v2->bss_type = DOT11_BSSTYPE_ANY; - params_v2->scan_type = htod32(scan_type); - params_v2->nprobes = htod32(-1); - params_v2->active_time = htod32(-1); - params_v2->passive_time = htod32(-1); - params_v2->home_time = htod32(-1); - params_v2->channel_num = 0; - bzero(¶ms_v2->ssid, sizeof(wlc_ssid_t)); - chan_list = params_v2->channel_list; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) && defined(DHD_SCAN_INC_RNR) + /* scan for colocated APs reported by 2.4/5 GHz APs */ + if (request->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ) +#endif + { + params_v3->ssid_type |= WL_SCAN_INC_RNR; + } } else { /* scan params ver 1 */ if (!params) { @@ -1842,12 +2021,13 @@ wl_scan_prep(struct bcm_cfg80211 *cfg, struct net_device *ndev, void *scan_param return BCME_OK; } - WL_INFORM(("n_channels:%d n_ssids:%d\n", request->n_channels, request->n_ssids)); + WL_INFORM(("n_channels:%d n_ssids:%d ver:%d\n", + request->n_channels, request->n_ssids, cfg->scan_params_ver)); cur_offset = channel_offset; /* Copy channel array if applicable */ #ifdef SCAN_SUPPRESS - channel = wl_ext_scan_suppress(ndev, scan_params, cfg->scan_params_v2, &chan_info); + channel = wl_ext_scan_suppress(ndev, scan_params, cfg->scan_params_ver, &chan_info); if (channel) { n_channels = 1; if ((n_channels > 0) && chan_list) { @@ -1883,12 +2063,12 @@ wl_scan_prep(struct bcm_cfg80211 *cfg, struct net_device *ndev, void *scan_param u32 channel_num = htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) | (n_channels & WL_SCAN_PARAMS_COUNT_MASK)); - if (params_v2) { - params_v2->channel_num = channel_num; + if (params_v3) { + params_v3->channel_num = channel_num; if (n_channels == 1) { - params_v2->active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); - params_v2->nprobes = htod32( - params_v2->active_time / WL_SCAN_JOIN_PROBE_INTERVAL_MS); + params_v3->active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); + params_v3->nprobes = htod32( + params_v3->active_time / WL_SCAN_JOIN_PROBE_INTERVAL_MS); } } else { params->channel_num = channel_num; @@ -1904,7 +2084,8 @@ wl_scan_prep(struct bcm_cfg80211 *cfg, struct net_device *ndev, void *scan_param return BCME_OK; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && \ + defined(SUPPORT_RANDOM_MAC_SCAN) static s32 wl_config_scan_macaddr(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool randmac_enable, u8 *mac_addr, u8 *mac_addr_mask) @@ -1951,8 +2132,7 @@ exit: err = BCME_OK; } else { /* For errors other than unsupported fail the scan */ - WL_ERR(("%s : failed to configure random mac for host scan, %d\n", - __FUNCTION__, err)); + WL_ERR(("failed to configure random mac for host scan, %d\n", err)); err = -EAGAIN; } } @@ -1970,8 +2150,8 @@ wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 n_channels = 0; u32 n_ssids; s32 params_size; - wl_escan_params_t *eparams = NULL; - wl_escan_params_v2_t *eparams_v2 = NULL; + wl_escan_params_v1_t *eparams = NULL; + wl_escan_params_v3_t *eparams_v3 = NULL; u8 *scan_params = NULL; u8 *params = NULL; s32 search_state = WL_P2P_DISC_ST_SCAN; @@ -1989,21 +2169,24 @@ wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev, if (!cfg || !request) { err = -EINVAL; + WL_ERR(("invalid escan parameter\n")); goto exit; } - if (cfg->scan_params_v2) { - params_size = (WL_SCAN_PARAMS_V2_FIXED_SIZE + - OFFSETOF(wl_escan_params_v2_t, params)); + if (IS_SCAN_PARAMS_V3_V2(cfg)) { + params_size = (WL_SCAN_PARAMS_V3_FIXED_SIZE + + OFFSETOF(wl_escan_params_v3_t, params)); } else { - params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); + params_size = (WL_SCAN_PARAMS_V1_FIXED_SIZE + + OFFSETOF(wl_escan_params_v1_t, params)); } if (!cfg->p2p_supported || !p2p_scan(cfg)) { /* LEGACY SCAN TRIGGER */ WL_SCAN((" LEGACY E-SCAN START\n")); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && \ + defined(SUPPORT_RANDOM_MAC_SCAN) if (request) { bool randmac_enable = (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR); if (wl_is_wps_enrollee_active(ndev, request->ie, request->ie_len)) { @@ -2072,25 +2255,26 @@ wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev, else params_size += sizeof(u16) * n_channels; - /* Allocate space for populating ssids in wl_escan_params_t struct */ + /* Allocate space for populating ssids in wl_escan_params_v1_t struct */ params_size += sizeof(struct wlc_ssid) * n_ssids; params = MALLOCZ(cfg->osh, params_size); if (params == NULL) { err = -ENOMEM; + WL_ERR(("malloc failure for escan params\n")); goto exit; } wl_escan_set_sync_id(sync_id, cfg); - if (cfg->scan_params_v2) { - eparams_v2 = (wl_escan_params_v2_t *)params; - scan_params = (u8 *)&eparams_v2->params; - eparams_v2->version = htod32(ESCAN_REQ_VERSION_V2); - eparams_v2->action = htod16(action); - eparams_v2->sync_id = sync_id; + if (IS_SCAN_PARAMS_V3_V2(cfg)) { + eparams_v3 = (wl_escan_params_v3_t *)params; + scan_params = (u8 *)&eparams_v3->params; + eparams_v3->version = htod32(cfg->scan_params_ver); + eparams_v3->action = htod16(action); + eparams_v3->sync_id = sync_id; } else { - eparams = (wl_escan_params_t *)params; + eparams = (wl_escan_params_v1_t *)params; scan_params = (u8 *)&eparams->params; - eparams->version = htod32(ESCAN_REQ_VERSION); + eparams->version = htod32(ESCAN_REQ_VERSION_V1); eparams->action = htod16(action); eparams->sync_id = sync_id; } @@ -2104,8 +2288,8 @@ wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev, #if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME) /* Override active_time to reduce scan time if it's first bradcast scan. */ if (is_first_init_2g_scan) { - if (eparams_v2) { - eparams_v2->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS; + if (eparams_v3) { + eparams_v3->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS; } else { eparams->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS; } @@ -2197,6 +2381,11 @@ wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev, cfg->p2p->search_state = search_state; MFREE(cfg->osh, default_chan_list, chan_mem); + } else { + WL_ERR(("escan not triggered - p2p_supported=%d, p2p_scan=%d, p2p_is_on=%d\n", + cfg->p2p_supported, p2p_scan(cfg), p2p_is_on(cfg))); + err = -EINVAL; + goto exit; } exit: if (unlikely(err)) { @@ -2217,13 +2406,13 @@ wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *nd s32 passive_scan; s32 passive_scan_time; s32 passive_scan_time_org; - wl_scan_results_t *results; + wl_scan_results_v109_t *results; WL_SCAN(("Enter \n")); results = wl_escan_get_buf(cfg, FALSE); results->version = 0; results->count = 0; - results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; + results->buflen = WL_SCAN_RESULTS_V109_FIXED_SIZE; cfg->escan_info.ndev = ndev; cfg->escan_info.wiphy = wiphy; @@ -2260,6 +2449,10 @@ wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *nd } err = wl_run_escan(cfg, ndev, request, WL_SCAN_ACTION_START); + if (unlikely(err)) { + WL_ERR(("escan failed (%d)\n", err)); + goto exit; + } if (passive_channel_skip) { err = wldev_ioctl_set(ndev, WLC_SET_SCAN_PASSIVE_TIME, @@ -2321,6 +2514,12 @@ wl_cfgscan_handle_scanbusy(struct bcm_cfg80211 *cfg, struct net_device *ndev, s3 busy_count = 0; return scanbusy_err; } + + if (!p2p_scan(cfg) && wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL)) { + WL_ERR(("Scan err = (%d) due to p2p scan, nothing to do\n", err)); + busy_count = 0; + } + if (err == BCME_BUSY || err == BCME_NOTREADY) { WL_ERR(("Scan err = (%d), busy?%d\n", err, -EBUSY)); scanbusy_err = -EBUSY; @@ -2375,9 +2574,8 @@ wl_cfgscan_handle_scanbusy(struct bcm_cfg80211 *cfg, struct net_device *ndev, s3 dhd_os_send_hang_message(dhdp); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(OEM_ANDROID) */ -#if !((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && \ - defined(OEM_ANDROID)) - WL_ERR(("%s: HANG event is unsupported\n", __FUNCTION__)); +#if !((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(OEM_ANDROID)) + WL_ERR(("HANG event is unsupported\n")); #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */ #endif /* BCMDONGLEHOST */ @@ -2410,27 +2608,159 @@ wl_cfgscan_handle_scanbusy(struct bcm_cfg80211 *cfg, struct net_device *ndev, s3 return scanbusy_err; } +static bool +is_p2p_ssid_present(struct cfg80211_scan_request *request) +{ + struct cfg80211_ssid *ssids; + int i; + + ssids = request->ssids; + for (i = 0; i < request->n_ssids; i++) { + if (ssids[i].ssid_len && + IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) { + /* P2P Scan */ + return TRUE; + } + } + return FALSE; +} + +static void +wl_set_p2p_scan_states(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + if (cfg->p2p_supported) { + /* p2p scan trigger */ + if (p2p_on(cfg) == false) { + /* p2p on at the first time */ + p2p_on(cfg) = true; +#if defined(P2P_IE_MISSING_FIX) + cfg->p2p_prb_noti = false; +#endif + } + wl_clr_p2p_status(cfg, GO_NEG_PHASE); + WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); + p2p_scan(cfg) = true; + } +} + +static void +wl_set_legacy_scan_states(struct bcm_cfg80211 *cfg, + struct cfg80211_scan_request *request, struct net_device *ndev, s32 bssidx) +{ + s32 err = BCME_OK; +#ifdef WL11U + bcm_tlv_t *interworking_ie; +#endif + + /* legacy scan trigger + * So, we have to disable p2p discovery if p2p discovery is on + */ + if (cfg->p2p_supported) { + p2p_scan(cfg) = false; + if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { + err = wl_cfgp2p_discover_enable_search(cfg, false); + if (unlikely(err)) { + WL_ERR(("disable discovery failed\n")); + /* non-fatal error. fall through */ + } + } + } + +#ifdef WL11U + if (request && (interworking_ie = wl_cfg80211_find_interworking_ie(request->ie, + request->ie_len)) != NULL) { + if ((err = wl_cfg80211_add_iw_ie(cfg, ndev, bssidx, + VNDR_IE_CUSTOM_FLAG, interworking_ie->id, interworking_ie->data, + interworking_ie->len)) != BCME_OK) { + WL_ERR(("Failed to add interworking IE")); + } + } else if (cfg->wl11u) { + /* we have to clear IW IE and disable gratuitous APR */ + wl_cfg80211_clear_iw_ie(cfg, ndev, bssidx); + err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0, bssidx); + /* we don't care about error here + * because the only failure case is unsupported, + * which is fine + */ + if (unlikely(err)) { + WL_ERR(("Set grat_arp failed:(%d) Ignore!\n", err)); + } + cfg->wl11u = FALSE; + } +#endif /* WL11U */ +} + +static bool +is_scan_allowed(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + struct net_device *remain_on_channel_ndev = NULL; +#endif + +#ifdef WL_SCHED_SCAN + if (cfg->sched_scan_running) { + WL_ERR(("PNO SCAN in progress\n")); + return FALSE; + } +#endif /* WL_SCHED_SCAN */ + + if (wl_get_drv_status_all(cfg, SCANNING)) { + if (cfg->scan_request == NULL) { + /* SCANNING bit is set, but scan_request NULL!! */ + wl_clr_drv_status_all(cfg, SCANNING); + WL_DBG(("<<<<<<<<<<>>>>>>>>>>\n")); + } else { + WL_ERR(("Scanning already\n")); + return FALSE; + } + } + + if (wl_get_drv_status(cfg, CONNECTING, ndev)) { + WL_ERR(("Association is in progress, skip new scan\n")); + return FALSE; + } + + if (wl_get_drv_status(cfg, SCAN_ABORTING, ndev)) { + WL_ERR(("Scanning being aborted. skip new scan\n")); + return FALSE; + } + + if (cfg->loc.in_progress) { + WL_ERR(("loc in progress. skip new scan\n")); + /* Listen in progress, avoid new scan trigger */ + return FALSE; + } + + if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) { + WL_ERR(("Sending Action Frames. Try it again.\n")); + return FALSE; + } + +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + remain_on_channel_ndev = wl_cfg80211_get_remain_on_channel_ndev(cfg); + if (remain_on_channel_ndev) { + /* scan listen and proceed */ + WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n")); + _wl_cfgscan_cancel_scan(cfg); + } +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ + + return TRUE; +} + s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request, struct cfg80211_ssid *this_ssid) { struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct cfg80211_ssid *ssids; - bool p2p_ssid; -#ifdef WL11U - bcm_tlv_t *interworking_ie; -#endif + bool p2p_ssid = FALSE; s32 err = 0; - s32 bssidx = -1; - s32 i; bool escan_req_failed = false; s32 scanbusy_err = 0; - unsigned long flags; -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - struct net_device *remain_on_channel_ndev = NULL; -#endif + s32 bssidx = 0; + /* * Hostapd triggers scan before starting automatic channel selection * to collect channel characteristics. However firmware scan engine @@ -2440,7 +2770,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, if (request && (scan_req_iftype(request) == NL80211_IFTYPE_AP)) { WL_DBG(("Scan Command on SoftAP Interface. Ignoring...\n")); // terence 20161023: let it scan in SoftAP mode -// return 0; +// return -EOPNOTSUPP; } if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) { @@ -2450,51 +2780,13 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ndev = ndev_to_wlc_ndev(ndev, cfg); - if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) { - WL_ERR(("Sending Action Frames. Try it again.\n")); - return -EAGAIN; - } - - WL_DBG(("Enter wiphy (%p)\n", wiphy)); - mutex_lock(&cfg->scan_sync); - if (wl_get_drv_status_all(cfg, SCANNING)) { - if (cfg->scan_request == NULL) { - wl_clr_drv_status_all(cfg, SCANNING); - WL_DBG(("<<<<<<<<<<>>>>>>>>>>\n")); - } else { - WL_ERR(("Scanning already\n")); - mutex_unlock(&cfg->scan_sync); - return -EAGAIN; - } - } - if (wl_get_drv_status(cfg, SCAN_ABORTING, ndev)) { - WL_ERR(("Scanning being aborted\n")); - mutex_unlock(&cfg->scan_sync); - return -EAGAIN; - } - - if (cfg->loc.in_progress) { - /* Listen in progress, avoid new scan trigger */ - mutex_unlock(&cfg->scan_sync); - return -EBUSY; - } - mutex_unlock(&cfg->scan_sync); + WL_DBG(("[%s] Enter\n", ndev->name)); #ifdef WL_BCNRECV /* check fakeapscan in progress then abort */ wl_android_bcnrecv_stop(ndev, WL_BCNRECV_SCANBUSY); #endif /* WL_BCNRECV */ -#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - mutex_lock(&cfg->scan_sync); - remain_on_channel_ndev = wl_cfg80211_get_remain_on_channel_ndev(cfg); - if (remain_on_channel_ndev) { - WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n")); - _wl_cfgscan_cancel_scan(cfg); - } - mutex_unlock(&cfg->scan_sync); -#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - #ifdef P2P_LISTEN_OFFLOADING wl_cfg80211_cancel_p2plo(cfg); #endif /* P2P_LISTEN_OFFLOADING */ @@ -2505,107 +2797,33 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } #endif - if (request) { /* scan bss */ - ssids = request->ssids; - p2p_ssid = false; - for (i = 0; i < request->n_ssids; i++) { - if (ssids[i].ssid_len && - IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) { - /* P2P Scan */ -#ifdef WL_BLOCK_P2P_SCAN_ON_STA - if (!(IS_P2P_IFACE(request->wdev))) { - /* P2P scan on non-p2p iface. Fail scan */ - WL_ERR(("p2p_search on non p2p iface\n")); - goto scan_out; - } -#endif /* WL_BLOCK_P2P_SCAN_ON_STA */ - p2p_ssid = true; - break; - } - } + if (request) { + /* scan bss */ + p2p_ssid = is_p2p_ssid_present(request); if (p2p_ssid) { - if (cfg->p2p_supported) { - /* p2p scan trigger */ - if (p2p_on(cfg) == false) { - /* p2p on at the first time */ - p2p_on(cfg) = true; - wl_cfgp2p_set_firm_p2p(cfg); -#if defined(P2P_IE_MISSING_FIX) - cfg->p2p_prb_noti = false; +#if defined(WL_CFG80211_P2P_DEV_IF) + if (!(IS_P2P_IFACE(request->wdev))) +#else + if (!(IS_P2P_IFACE(ndev->ieee80211_ptr))) #endif - } - wl_clr_p2p_status(cfg, GO_NEG_PHASE); - WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); - p2p_scan(cfg) = true; - } - } else { - /* legacy scan trigger - * So, we have to disable p2p discovery if p2p discovery is on - */ - if (cfg->p2p_supported) { - p2p_scan(cfg) = false; - /* If Netdevice is not equals to primary and p2p is on - * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE. - */ - - if (p2p_scan(cfg) == false) { - if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { - err = wl_cfgp2p_discover_enable_search(cfg, - false); - if (unlikely(err)) { - goto scan_out; - } - - } - } - } - if (!cfg->p2p_supported || !p2p_scan(cfg)) { - if ((bssidx = wl_get_bssidx_by_wdev(cfg, - ndev->ieee80211_ptr)) < 0) { - WL_ERR(("Find p2p index from ndev(%p) failed\n", - ndev)); - err = BCME_ERROR; - goto scan_out; - } -#ifdef WL11U - if (request && (interworking_ie = wl_cfg80211_find_interworking_ie( - request->ie, request->ie_len)) != NULL) { - if ((err = wl_cfg80211_add_iw_ie(cfg, ndev, bssidx, - VNDR_IE_CUSTOM_FLAG, interworking_ie->id, - interworking_ie->data, - interworking_ie->len)) != BCME_OK) { - WL_ERR(("Failed to add interworking IE")); - } - } else if (cfg->wl11u) { - /* we have to clear IW IE and disable gratuitous APR */ - wl_cfg80211_clear_iw_ie(cfg, ndev, bssidx); - err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", - 0, bssidx); - /* we don't care about error here - * because the only failure case is unsupported, - * which is fine - */ - if (unlikely(err)) { - WL_ERR(("Set grat_arp failed:(%d) Ignore!\n", err)); - } - cfg->wl11u = FALSE; - } -#endif /* WL11U */ - if (request) { - err = wl_cfg80211_set_mgmt_vndr_ies(cfg, - ndev_to_cfgdev(ndev), bssidx, VNDR_IE_PRBREQ_FLAG, - request->ie, request->ie_len); - } - - if (unlikely(err)) { -// terence 20161023: let it scan in SoftAP mode -// goto scan_out; - } - + { + /* P2P SSID in legacy scan */ + WL_DBG(("p2p_search on non p2p iface %d\n", +#if defined(WL_CFG80211_P2P_DEV_IF) + request->wdev->iftype +#else + ndev->ieee80211_ptr->iftype +#endif + )); + p2p_ssid = FALSE; } } - } else { /* scan in ibss */ - ssids = this_ssid; + } + + if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) { + WL_ERR(("Find bssidx from wdev failed!\n")); + err = -EINVAL; + goto scan_out; } WL_TRACE_HW4(("START SCAN\n")); @@ -2616,36 +2834,62 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)(cfg->pub)); #endif - if (cfg->p2p_supported) { - if (request && p2p_on(cfg) && p2p_scan(cfg)) { - + if (cfg->p2p_supported && p2p_ssid) { #ifdef WL_SDO - if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) { - /* We shouldn't be getting p2p_find while discovery - * offload is in progress - */ - WL_SD(("P2P_FIND: Discovery offload is in progress." - " Do nothing\n")); - err = -EINVAL; - goto scan_out; - } + if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) { + /* We shouldn't be getting p2p_find while discovery + * offload is in progress + */ + WL_SD(("P2P_FIND: Discovery offload is in progress." + " Do nothing\n")); + err = -EINVAL; + goto scan_out; + } #endif - /* find my listen channel */ - cfg->afx_hdl->my_listen_chan = - wl_find_listen_channel(cfg, request->ie, - request->ie_len); - err = wl_cfgp2p_enable_discovery(cfg, ndev, - request->ie, request->ie_len); + /* find my listen channel */ + cfg->afx_hdl->my_listen_chan = + wl_find_listen_channel(cfg, request->ie, request->ie_len); + err = wl_cfgp2p_enable_discovery(cfg, ndev, request->ie, request->ie_len); + if (unlikely(err)) { + goto scan_out; + } + } - if (unlikely(err)) { - goto scan_out; - } + mutex_lock(&cfg->scan_sync); + + if (is_scan_allowed(cfg, ndev) == FALSE) { + err = -EAGAIN; + WL_ERR(("scan not permitted!\n")); + escan_req_failed = true; + goto scan_out; + } + + if (request) { + /* set scan related states that need mutex protection */ + if (p2p_ssid) { + wl_set_p2p_scan_states(cfg, ndev); + } else { + wl_set_legacy_scan_states(cfg, request, ndev, bssidx); + } + + /* configure upper app provided IEs to the firmware */ + err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(ndev), bssidx, + VNDR_IE_PRBREQ_FLAG, request->ie, request->ie_len); + if (unlikely(err)) { + WL_ERR(("vndr_ie set for probereq failed for bssidx:%d!\n", bssidx)); } } #ifdef WL_EXT_IAPSTA - if (wl_ext_in4way_sync(ndev, STA_FAKE_SCAN_IN_CONNECT, WL_EXT_STATUS_SCANNING, NULL)) { + mutex_unlock(&cfg->scan_sync); + err = wl_ext_in4way_sync(ndev, STA_FAKE_SCAN_IN_CONNECT, WL_EXT_STATUS_SCANNING, NULL); + if (err) { + wl_event_msg_t msg; mutex_lock(&cfg->scan_sync); + bzero(&msg, sizeof(wl_event_msg_t)); + msg.event_type = hton32(WLC_E_ESCAN_RESULT); + msg.status = hton32(WLC_E_STATUS_SUCCESS); + wl_cfg80211_event(ndev, &msg, NULL); goto scan_success; } #endif @@ -2716,6 +2960,9 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, #if defined(WL_CFG80211_P2P_DEV_IF) struct net_device *ndev = wdev_to_wlc_ndev(request->wdev, cfg); #endif /* WL_CFG80211_P2P_DEV_IF */ +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ WL_DBG(("Enter\n")); RETURN_EIO_IF_NOT_UP(cfg); @@ -2746,6 +2993,14 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); if (unlikely(err)) { WL_ERR(("scan error (%d)\n", err)); +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT + if (err == -EBUSY) { + dhdp->alert_reason = ALERT_SCAN_BUSY; + } else { + dhdp->alert_reason = ALERT_SCAN_ERR; + } + dhd_os_send_alert_message(dhdp); +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ } #ifdef WL_DRV_AVOID_SCANCACHE /* Reset roam cache after successful scan request */ @@ -2796,6 +3051,15 @@ static void _wl_cfgscan_cancel_scan(struct bcm_cfg80211 *cfg) struct wireless_dev *wdev = NULL; struct net_device *ndev = NULL; + ndev = wl_cfg80211_get_remain_on_channel_ndev(cfg); + if (wl_get_drv_status(cfg, REMAINING_ON_CHANNEL, ndev)) { + /* Cancel P2P listen */ + if (cfg->p2p_supported && cfg->p2p) { + wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); + } + } + if (!cfg->scan_request && !cfg->sched_scan_req) { /* No scans in progress */ WL_INFORM_MEM(("No scan in progress\n")); @@ -2812,6 +3076,7 @@ static void _wl_cfgscan_cancel_scan(struct bcm_cfg80211 *cfg) /* Check if any scan in progress only then abort */ if (wl_get_drv_status_all(cfg, SCANNING)) { + WL_MEM(("Called by %pS\n", CALL_SITE)); wl_cfgscan_scan_abort(cfg); /* Indicate escan completion to upper layer */ @@ -2823,6 +3088,7 @@ static void _wl_cfgscan_cancel_scan(struct bcm_cfg80211 *cfg) /* Wrapper function for cancel_scan with scan_sync mutex */ void wl_cfgscan_cancel_scan(struct bcm_cfg80211 *cfg) { + WL_MEM(("Called by %pS\n", CALL_SITE)); mutex_lock(&cfg->scan_sync); _wl_cfgscan_cancel_scan(cfg); mutex_unlock(&cfg->scan_sync); @@ -2841,10 +3107,10 @@ void wl_cfgscan_scan_abort(struct bcm_cfg80211 *cfg) u32 channel, channel_num; /* Abort scan params only need space for 1 channel and 0 ssids */ - if (cfg->scan_params_v2) { - params_size = WL_SCAN_PARAMS_V2_FIXED_SIZE + (1 * sizeof(uint16)); + if (IS_SCAN_PARAMS_V3_V2(cfg)) { + params_size = WL_SCAN_PARAMS_V3_FIXED_SIZE + (1 * sizeof(uint16)); } else { - params_size = WL_SCAN_PARAMS_FIXED_SIZE + (1 * sizeof(uint16)); + params_size = WL_SCAN_PARAMS_V1_FIXED_SIZE + (1 * sizeof(uint16)); } params = MALLOCZ(cfg->osh, params_size); @@ -2857,13 +3123,13 @@ void wl_cfgscan_scan_abort(struct bcm_cfg80211 *cfg) channel = htodchanspec(-1); channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | (1 & WL_SCAN_PARAMS_COUNT_MASK)); - if (cfg->scan_params_v2) { - wl_scan_params_v2_t *params_v2 = (wl_scan_params_v2_t *)params; - params_v2->channel_list[0] = channel; - params_v2->channel_num = channel_num; - params_v2->length = htod16(sizeof(wl_scan_params_v2_t)); + if (IS_SCAN_PARAMS_V3_V2(cfg)) { + wl_scan_params_v3_t *params_v3 = (wl_scan_params_v3_t *)params; + params_v3->channel_list[0] = channel; + params_v3->channel_num = channel_num; + params_v3->length = htod16(sizeof(wl_scan_params_v3_t)); } else { - wl_scan_params_t *params_v1 = (wl_scan_params_t *)params; + wl_scan_params_v1_t *params_v1 = (wl_scan_params_v1_t *)params; params_v1->channel_list[0] = channel; params_v1->channel_num = channel_num; } @@ -2910,8 +3176,9 @@ wl_notify_escan_complete(struct bcm_cfg80211 *cfg, err = BCME_ERROR; goto out; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) && \ - (!defined(WL_USE_RANDOMIZED_SCAN)) + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && \ + defined(SUPPORT_RANDOM_MAC_SCAN) && !defined(WL_USE_RANDOMIZED_SCAN) /* Disable scanmac if enabled */ if (cfg->scanmac_enabled) { wl_cfg80211_scan_mac_disable(ndev); @@ -2925,7 +3192,7 @@ wl_notify_escan_complete(struct bcm_cfg80211 *cfg, #elif defined(WL_CFG80211_P2P_DEV_IF) if (cfg->scan_request->wdev->iftype != NL80211_IFTYPE_P2P_DEVICE) dev = cfg->scan_request->wdev->netdev; -#endif /* WL_ENABLE_P2P_IF */ +#endif } else { WL_DBG(("cfg->scan_request is NULL. Internal scan scenario." @@ -2938,7 +3205,7 @@ wl_notify_escan_complete(struct bcm_cfg80211 *cfg, /* clear scan enq time on complete */ CLR_TS(cfg, scan_enq); CLR_TS(cfg, scan_start); -#if defined (ESCAN_RESULT_PATCH) +#if defined(ESCAN_RESULT_PATCH) if (likely(cfg->scan_request)) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) if (aborted && cfg->p2p && p2p_scan(cfg) && @@ -2985,19 +3252,9 @@ wl_notify_escan_complete(struct bcm_cfg80211 *cfg, if (cfg->bss_list && (cfg->bss_list->count == 0)) { WL_INFORM_MEM(("bss list empty. report sched_scan_stop\n")); - -#if defined (WL_SCHED_SCAN) && defined (SCHED_SCAN_DELAYED_WORK) wl_cfg80211_stop_pno(cfg, bcmcfg_to_prmry_ndev(cfg)); /* schedule the work to indicate sched scan stop to cfg layer */ schedule_delayed_work(&cfg->sched_scan_stop_work, 0); -#else - /* Indicated sched scan stopped so that user space - * can do a full scan incase found match is empty. - */ - CFG80211_SCHED_SCAN_STOPPED(wiphy, cfg->sched_scan_req); - cfg->sched_scan_req = NULL; -#endif - } } #endif /* WL_SCHED_SCAN */ @@ -3146,7 +3403,7 @@ _wl_notify_scan_done(struct bcm_cfg80211 *cfg, bool aborted) } #ifdef WL_DRV_AVOID_SCANCACHE -static u32 wl_p2p_find_peer_channel(struct bcm_cfg80211 *cfg, s32 status, wl_bss_info_t *bi, +static u32 wl_p2p_find_peer_channel(struct bcm_cfg80211 *cfg, s32 status, wl_bss_info_v109_t *bi, u32 bi_length) { u32 ret; @@ -3186,11 +3443,13 @@ static u32 wl_p2p_find_peer_channel(struct bcm_cfg80211 *cfg, s32 status, wl_bss return ret; } -static s32 wl_escan_without_scan_cache(struct bcm_cfg80211 *cfg, wl_escan_result_t *escan_result, - struct net_device *ndev, const wl_event_msg_t *e, s32 status) +static s32 wl_escan_without_scan_cache(struct bcm_cfg80211 *cfg, + wl_escan_result_v109_t *escan_result, + struct net_device *ndev, + const wl_event_msg_t *e, s32 status) { s32 err = BCME_OK; - wl_bss_info_t *bi; + wl_bss_info_v109_t *bi; u32 bi_length; bool aborted = false; bool fw_abort = false; @@ -3220,7 +3479,7 @@ static s32 wl_escan_without_scan_cache(struct bcm_cfg80211 *cfg, wl_escan_result bi = escan_result->bss_info; bi_length = dtoh32(bi->length); if ((!bi) || - (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE))) { + (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_V109_FIXED_SIZE))) { WL_ERR(("Invalid escan bss info (NULL pointer)" "or invalid bss_info length\n")); goto exit; @@ -3276,20 +3535,15 @@ static s32 wl_escan_without_scan_cache(struct bcm_cfg80211 *cfg, wl_escan_result aborted = false; fw_abort = false; -#ifdef CUSTOMER_HW4_DEBUG - if (wl_scan_timeout_dbg_enabled) - wl_scan_timeout_dbg_clear(); -#endif /* CUSTOMER_HW4_DEBUG */ } else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN) || (status == WLC_E_STATUS_11HQUIET) || (status == WLC_E_STATUS_CS_ABORT) || (status == WLC_E_STATUS_NEWASSOC)) { /* Handle all cases of scan abort */ - WL_DBG(("ESCAN ABORT reason: %d\n", status)); + WL_INFORM_MEM(("ESCAN ABORT reason: %d\n", status)); if (wl_p2p_find_peer_channel(cfg, status, NULL, 0)) { goto exit; } - WL_INFORM_MEM(("ESCAN ABORTED\n")); /* Update escan complete status */ aborted = true; @@ -3334,7 +3588,7 @@ wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) { struct channel_info channel_inform; - wl_scan_results_t *bss_list; + wl_scan_results_v109_t *bss_list; struct net_device *ndev = NULL; u32 len = WL_SCAN_BUF_MAX; s32 err = 0; @@ -3643,6 +3897,7 @@ int wl_cfg80211_scan_mac_enable(struct net_device *dev) return err; } + /* * This is new interface for mac randomization. It takes randmac and randmask * as arg and it uses scanmac iovar to offload the mac randomization to firmware. @@ -3744,10 +3999,11 @@ wl_cfg80211_scan_mac_disable(struct net_device *dev) #endif /* SUPPORT_RANDOM_MAC_SCAN */ #ifdef WL_SCHED_SCAN -#define PNO_TIME 30 -#define PNO_REPEAT 4 -#define PNO_FREQ_EXPO_MAX 2 -#define PNO_ADAPTIVE_SCAN_LIMIT 60 +#define PNO_TIME 30u +#define PNO_REPEAT_MAX 100u +#define PNO_FREQ_EXPO_MAX 2u +#define PNO_ADAPTIVE_SCAN_LIMIT 80u +#define ADP_PNO_REPEAT_DEFAULT 2u static bool is_ssid_in_list(struct cfg80211_ssid *ssid, struct cfg80211_ssid *ssid_list, int count) { @@ -3772,10 +4028,10 @@ wl_cfg80211_sched_scan_start(struct wiphy *wiphy, { u16 chan_list[WL_NUMCHANNELS] = {0}; u32 num_channels = 0; - ushort pno_time; - int pno_repeat = PNO_REPEAT; - int pno_freq_expo_max = PNO_FREQ_EXPO_MAX; - wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT]; + ushort pno_time = 0; + int pno_repeat = 0; + int pno_freq_expo_max = 0; + wlc_ssid_ext_t *ssids_local = NULL; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); struct cfg80211_ssid *ssid = NULL; @@ -3788,36 +4044,75 @@ wl_cfg80211_sched_scan_start(struct wiphy *wiphy, int i; int ret = 0; unsigned long flags; + bool adaptive_pno = false; +#ifdef WL_DUAL_STA + if (!IS_INET_LINK_NDEV(cfg, dev)) { + WL_ERR(("Sched scan not supported on non-INET link\n")); + return -EOPNOTSUPP; + } + if ((wl_cfgvif_get_iftype_count(cfg, WL_IF_TYPE_STA) >= 2) || cfg->latency_mode) { + WL_ERR(("Sched scan not supported in multi sta connected state" + " or latency mode %d\n", cfg->latency_mode)); + return -EOPNOTSUPP; + } +#endif /* WL_DUAL_STA */ if (!request) { WL_ERR(("Sched scan request was NULL\n")); return -EINVAL; } - if ((request->n_scan_plans == 1) && request->scan_plans && - (request->scan_plans->interval > PNO_ADAPTIVE_SCAN_LIMIT)) { - /* If the host gives a high value for scan interval, then - * doing adaptive scan doesn't make sense. Better stick to the - * scan interval that host gives. - */ - pno_time = request->scan_plans->interval; - pno_repeat = 0; - pno_freq_expo_max = 0; - } else { - /* Run adaptive PNO */ - pno_time = PNO_TIME; - } - - WL_DBG(("Enter. ssids:%d match_sets:%d pno_time:%d pno_repeat:%d channels:%d\n", - request->n_ssids, request->n_match_sets, - pno_time, pno_repeat, request->n_channels)); - - if (!request->n_ssids || !request->n_match_sets) { - WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids)); + if (!(request->n_scan_plans == 1) || !request->scan_plans) { + WL_ERR(("wrong input. plans:%d\n", request->n_scan_plans)); return -EINVAL; } - bzero(&ssids_local, sizeof(ssids_local)); +#ifndef DISABLE_ADAPTIVE_PNO + if (request->scan_plans->interval <= PNO_ADAPTIVE_SCAN_LIMIT) { + /* If the host gives a high value for scan interval, then + * doing adaptive scan doesn't make sense. For smaller + * values attempt adaptive scan. + */ + adaptive_pno = true; + } +#endif /* DISABLE_ADAPTIVE_PNO */ + + /* Use host provided iterations */ + pno_repeat = request->scan_plans->iterations; + if (!pno_repeat || pno_repeat > PNO_REPEAT_MAX) { + /* (scan_plan->iterations == zero) means infinite */ + pno_repeat = PNO_REPEAT_MAX; + } + + if (adaptive_pno) { + /* Run adaptive PNO */ + pno_time = request->scan_plans->interval; + pno_freq_expo_max = PNO_FREQ_EXPO_MAX; + pno_repeat = ADP_PNO_REPEAT_DEFAULT; + } else { + /* use host provided values */ + pno_time = request->scan_plans->interval; + } + + if (!request->n_ssids || !request->n_match_sets) { + WL_ERR(("Invalid sched scan req!! n_ssids:%d, request->n_match_sets:%d \n", + request->n_ssids, request->n_match_sets)); + return -EINVAL; + } + + mutex_lock(&cfg->scan_sync); + + WL_INFORM_MEM(("[%s] Enter. ssids:%d match_sets:%d pno_time:%d pno_repeat:%d " + "channels:%d adaptive:%d\n", dev->name, request->n_ssids, request->n_match_sets, + pno_time, pno_repeat, request->n_channels, adaptive_pno)); + + ssids_local = (wlc_ssid_ext_t *)MALLOCZ(cfg->osh, + sizeof(wlc_ssid_ext_t) * MAX_PFN_LIST_COUNT); + if (!ssids_local) { + WL_ERR(("No memory")); + ret = -ENOMEM; + goto exit; + } if (request->n_ssids > 0) { hidden_ssid_list = request->ssids; @@ -3827,7 +4122,7 @@ wl_cfg80211_sched_scan_start(struct wiphy *wiphy, /* get channel list. Note PNO uses channels and not chanspecs */ wl_cfgscan_populate_scan_channels(cfg, request->channels, request->n_channels, - chan_list, &num_channels, false, false); + chan_list, &num_channels, true, false); } if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) { @@ -3836,7 +4131,8 @@ wl_cfg80211_sched_scan_start(struct wiphy *wiphy, if (!event_data) { WL_ERR(("%s: failed to allocate log_conn_event_t with " "length(%d)\n", __func__, alloc_len)); - return -ENOMEM; + ret = -ENOMEM; + goto exit; } } for (i = 0; i < request->n_match_sets && ssid_cnt < MAX_PFN_LIST_COUNT; i++) { @@ -3906,7 +4202,8 @@ wl_cfg80211_sched_scan_start(struct wiphy *wiphy, ret = -EINVAL; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && \ + defined(SUPPORT_RANDOM_MAC_SCAN) if ((ret = wl_config_scan_macaddr(cfg, dev, (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR), request->mac_addr, request->mac_addr_mask)) != BCME_OK) { @@ -3924,109 +4221,17 @@ wl_cfg80211_sched_scan_start(struct wiphy *wiphy, #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && (defined(SUPPORT_RANDOM_MAC_SCAN)) */ exit: + if (ssids_local) { + MFREE(cfg->osh, ssids_local, + sizeof(wlc_ssid_ext_t) * MAX_PFN_LIST_COUNT); + } if (event_data) { MFREE(cfg->osh, event_data, alloc_len); } + mutex_unlock(&cfg->scan_sync); return ret; } -int -#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 11, 0)) -wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev, u64 reqid) -#else -wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) -#endif /* LINUX_VER > 4.11 */ -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); -#if defined (WL_SCHED_SCAN) && !defined (SCHED_SCAN_DELAYED_WORK) - dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); -#endif - -#if defined (WL_SCHED_SCAN) && defined (SCHED_SCAN_DELAYED_WORK) - struct net_device *pri_ndev; -#endif - - WL_DBG(("Enter \n")); - WL_PNO((">>> SCHED SCAN STOP\n")); - -#if defined (WL_SCHED_SCAN) && defined (SCHED_SCAN_DELAYED_WORK) - pri_ndev = bcmcfg_to_prmry_ndev(cfg); - wl_cfg80211_stop_pno(cfg, dev); - - cancel_delayed_work(&cfg->sched_scan_stop_work); -#else - -#if defined(BCMDONGLEHOST) - if (dhd_dev_pno_stop_for_ssid(dev) < 0) { - WL_ERR(("PNO Stop for SSID failed")); - } else { - /* - * purposefully logging here to make sure that - * firmware configuration was successful - */ - DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_PNO_REMOVE); - } -#endif /* BCMDONGLEHOST */ - -#endif - - mutex_lock(&cfg->scan_sync); - if (cfg->sched_scan_req) { -#if defined (WL_SCHED_SCAN) && defined (SCHED_SCAN_DELAYED_WORK) - if (cfg->sched_scan_running && wl_get_drv_status(cfg, SCANNING, pri_ndev)) { - /* If targetted escan for PNO is running, abort it */ - WL_INFORM_MEM(("abort targetted escan\n")); - _wl_cfgscan_cancel_scan(cfg); - wl_clr_drv_status(cfg, SCANNING, pri_ndev); - } else { - WL_INFORM_MEM(("pno escan state:%d\n", - cfg->sched_scan_running)); - } -#else - WL_PNO((">>> Sched scan running. Aborting it..\n")); - _wl_cfgscan_cancel_scan(cfg); -#endif - } - cfg->sched_scan_req = NULL; - cfg->sched_scan_running = FALSE; - mutex_unlock(&cfg->scan_sync); - - return 0; -} -#if defined (WL_SCHED_SCAN) && defined (SCHED_SCAN_DELAYED_WORK) -void -wl_cfgscan_sched_scan_stop_work(struct work_struct *work) -{ - struct bcm_cfg80211 *cfg = NULL; - struct wiphy *wiphy = NULL; - struct delayed_work *dw = to_delayed_work(work); - - GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); - cfg = container_of(dw, struct bcm_cfg80211, sched_scan_stop_work); - GCC_DIAGNOSTIC_POP(); - - /* Hold rtnl_lock -> scan_sync lock to be in sync with cfg80211_ops path */ - rtnl_lock(); - mutex_lock(&cfg->scan_sync); - if (cfg->sched_scan_req) { - wiphy = cfg->sched_scan_req->wiphy; - /* Indicate sched scan stopped so that user space - * can do a full scan incase found match is empty. - */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) - cfg80211_sched_scan_stopped_rtnl(wiphy, cfg->sched_scan_req->reqid); -#else - cfg80211_sched_scan_stopped_rtnl(wiphy); -#endif /* KERNEL > 4.12.0 */ - cfg->sched_scan_req = NULL; - } - mutex_unlock(&cfg->scan_sync); - rtnl_unlock(); -} -#endif -#endif /* WL_SCHED_SCAN */ - -#if defined (WL_SCHED_SCAN) && defined (SCHED_SCAN_DELAYED_WORK) void wl_cfg80211_stop_pno(struct bcm_cfg80211 *cfg, struct net_device *dev) { @@ -4040,10 +4245,87 @@ wl_cfg80211_stop_pno(struct bcm_cfg80211 *cfg, struct net_device *dev) * purposefully logging here to make sure that * firmware configuration was successful */ + UNUSED_PARAMETER(dhdp); DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_PNO_REMOVE); } #endif /* BCMDONGLEHOST */ } + +int +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 11, 0)) +wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev, u64 reqid) +#else +wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) +#endif /* LINUX_VER > 4.11 */ +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *pri_ndev; + + WL_INFORM_MEM(("[%s] Enter\n", dev->name)); + pri_ndev = bcmcfg_to_prmry_ndev(cfg); + wl_cfg80211_stop_pno(cfg, dev); + + cancel_delayed_work(&cfg->sched_scan_stop_work); + + mutex_lock(&cfg->scan_sync); + if (cfg->sched_scan_req) { + if (cfg->sched_scan_running && wl_get_drv_status(cfg, SCANNING, pri_ndev)) { + /* If targetted escan for PNO is running, abort it */ + WL_INFORM_MEM(("abort targetted escan\n")); + _wl_cfgscan_cancel_scan(cfg); + wl_clr_drv_status(cfg, SCANNING, pri_ndev); + } else { + WL_INFORM_MEM(("pno escan state:%d\n", + cfg->sched_scan_running)); + } + } + cfg->sched_scan_req = NULL; + cfg->sched_scan_running = FALSE; + mutex_unlock(&cfg->scan_sync); + + return 0; +} + +void +wl_cfgscan_sched_scan_stop_work(struct work_struct *work) +{ + struct bcm_cfg80211 *cfg = NULL; + struct wiphy *wiphy = NULL; + struct delayed_work *dw = to_delayed_work(work); + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + cfg = container_of(dw, struct bcm_cfg80211, sched_scan_stop_work); + GCC_DIAGNOSTIC_POP(); + + if (cfg->sched_scan_req) { + /* Hold rtnl_lock -> scan_sync lock to be in sync with cfg80211_ops path */ + wiphy = cfg->sched_scan_req->wiphy; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + wiphy_lock(wiphy); +#else + rtnl_lock(); +#endif /* KERNEL > 5.12.0 */ + mutex_lock(&cfg->scan_sync); + + /* Indicate sched scan stopped so that user space + * can do a full scan incase found match is empty. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + cfg80211_sched_scan_stopped_locked(wiphy, cfg->sched_scan_req->reqid); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) + cfg80211_sched_scan_stopped_rtnl(wiphy, cfg->sched_scan_req->reqid); +#else + cfg80211_sched_scan_stopped_rtnl(wiphy); +#endif /* KERNEL > 5.12.0 */ + cfg->sched_scan_req = NULL; + mutex_unlock(&cfg->scan_sync); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + wiphy_unlock(wiphy); +#else + rtnl_unlock(); +#endif /* KERNEL > 5.12.0 */ + } +} #endif /* WL_SCHED_SCAN */ #ifdef WES_SUPPORT @@ -4086,32 +4368,6 @@ s32 wl_cfg80211_custom_scan_time(struct net_device *dev, #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */ #endif /* WES_SUPPORT */ -#ifdef CUSTOMER_HW4_DEBUG -uint prev_dhd_console_ms = 0; -u32 prev_wl_dbg_level = 0; -static void wl_scan_timeout_dbg_set(void); - -static void wl_scan_timeout_dbg_set(void) -{ - WL_ERR(("Enter \n")); - prev_dhd_console_ms = dhd_console_ms; - prev_wl_dbg_level = wl_dbg_level; - - dhd_console_ms = 1; - wl_dbg_level |= (WL_DBG_ERR | WL_DBG_P2P_ACTION | WL_DBG_SCAN); - - wl_scan_timeout_dbg_enabled = 1; -} -void wl_scan_timeout_dbg_clear(void) -{ - WL_ERR(("Enter \n")); - dhd_console_ms = prev_dhd_console_ms; - wl_dbg_level = prev_wl_dbg_level; - - wl_scan_timeout_dbg_enabled = 0; -} -#endif /* CUSTOMER_HW4_DEBUG */ - static void wl_scan_timeout(unsigned long data) { wl_event_msg_t msg; @@ -4119,8 +4375,8 @@ static void wl_scan_timeout(unsigned long data) struct wireless_dev *wdev = NULL; struct net_device *ndev = NULL; #if 0 - wl_scan_results_t *bss_list; - wl_bss_info_t *bi = NULL; + wl_scan_results_v109_t *bss_list; + wl_bss_info_v109_t *bi = NULL; s32 i; u32 channel; #endif @@ -4154,7 +4410,11 @@ static void wl_scan_timeout(unsigned long data) if (dhd_query_bus_erros(dhdp)) { return; } + #if defined(DHD_KERNEL_SCHED_DEBUG) && defined(DHD_FW_COREDUMP) + if (dhdp->memdump_enabled) { + dhdp->hang_reason = HANG_REASON_SCAN_TIMEOUT; + } /* DHD triggers Kernel panic if the SCAN timeout occurrs * due to tasklet or workqueue scheduling problems in the Linux Kernel. * Customer informs that it is hard to find any clue from the @@ -4164,12 +4424,10 @@ static void wl_scan_timeout(unsigned long data) * For this reason, customer requestes us to trigger Kernel Panic rather than * taking a SOCRAM dump. */ - if (dhdp->memdump_enabled == DUMP_MEMFILE_BUGON && - ((cfg->tsinfo.scan_deq < cfg->tsinfo.scan_enq) || - dhd_bus_query_dpc_sched_errors(dhdp))) { + if ((cfg->tsinfo.scan_deq < cfg->tsinfo.scan_enq) || + dhd_bus_query_dpc_sched_errors(dhdp) || + (dhdp->dhd_induce_error == DHD_INDUCE_SCAN_TIMEOUT_SCHED_ERROR)) { WL_ERR(("****SCAN event timeout due to scheduling problem\n")); - /* change g_assert_type to trigger Kernel panic */ - g_assert_type = 2; #ifdef RTT_SUPPORT rtt_status = GET_RTTSTATE(dhdp); #endif /* RTT_SUPPORT */ @@ -4204,9 +4462,15 @@ static void wl_scan_timeout(unsigned long data) mutex_is_locked(&(rtt_status)->geofence_mutex))); #endif /* WL_NAN */ #endif /* RTT_SUPPORT */ - - /* use ASSERT() to trigger panic */ - ASSERT(0); + if (dhdp->memdump_enabled == DUMP_MEMFILE_BUGON) { + /* change g_assert_type to trigger Kernel panic */ + g_assert_type = 2; + /* use ASSERT() to trigger panic */ + ASSERT(0); + } + if (dhdp->memdump_enabled) { + dhdp->hang_reason = HANG_REASON_SCAN_TIMEOUT_SCHED_ERROR; + } } #endif /* DHD_KERNEL_SCHED_DEBUG && DHD_FW_COREDUMP */ dhd_bus_intr_count_dump(dhdp); @@ -4227,8 +4491,13 @@ static void wl_scan_timeout(unsigned long data) bi = next_bss(bss_list, bi); for_each_bss(bss_list, bi, i) { - channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec)); - WL_ERR(("SSID :%s Channel :%d\n", bi->SSID, channel)); + if (wf_chspec_valid(bi->chanspec)) { + channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec)); + WL_ERR(("SSID :%s Channel :%d\n", bi->SSID, channel)); + } else { + WL_ERR(("SSID :%s Invalid chanspec :0x%x\n", + bi->SSID, bi->chanspec)); + } } } #endif @@ -4240,13 +4509,13 @@ static void wl_scan_timeout(unsigned long data) dhdp->scan_timeout_occurred = TRUE; #ifdef BCMPCIE if (!dhd_pcie_dump_int_regs(dhdp)) { - WL_ERR(("%s : PCIe link might be down\n", __FUNCTION__)); + WL_ERR(("PCIe link might be down\n")); dhd_bus_set_linkdown(dhdp, TRUE); dhdp->hang_reason = HANG_REASON_PCIE_LINK_DOWN_EP_DETECT; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(OEM_ANDROID) dhd_os_send_hang_message(dhdp); #else - WL_ERR(("%s: HANG event is unsupported\n", __FUNCTION__)); + WL_ERR(("HANG event is unsupported\n")); #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */ } @@ -4255,28 +4524,48 @@ static void wl_scan_timeout(unsigned long data) #if 0 if (!dhd_bus_get_linkdown(dhdp) && dhdp->memdump_enabled) { dhdp->memdump_type = DUMP_TYPE_SCAN_TIMEOUT; +#ifdef BCMPCIE dhd_bus_mem_dump(dhdp); +#else + if (dhd_schedule_socram_dump(dhdp)) { + WL_ERR(("socram dump failed\n")); + } +#endif /* BCMPCIE */ } -#endif /* DHD_FW_COREDUMP */ /* * For the memdump sanity, blocking bus transactions for a while * Keeping it TRUE causes the sequential private cmd error */ - dhdp->scan_timeout_occurred = FALSE; + if (!dhdp->memdump_enabled) { + dhdp->scan_timeout_occurred = FALSE; + } +#endif /* DHD_FW_COREDUMP */ #endif /* BCMDONGLEHOST */ + msg.event_type = hton32(WLC_E_ESCAN_RESULT); msg.status = hton32(WLC_E_STATUS_TIMEOUT); msg.reason = 0xFFFFFFFF; wl_cfg80211_event(ndev, &msg, NULL); -#ifdef CUSTOMER_HW4_DEBUG - if (!wl_scan_timeout_dbg_enabled) - wl_scan_timeout_dbg_set(); -#endif /* CUSTOMER_HW4_DEBUG */ + +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT + dhdp->alert_reason = ALERT_SCAN_ERR; + dhd_os_send_alert_message(dhdp); +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID) DHD_ENABLE_RUNTIME_PM(dhdp); #endif /* BCMDONGLEHOST && OEM_ANDROID */ +#if defined(BCMDONGLEHOST) && defined(DHD_FW_COREDUMP) + if (dhdp->memdump_enabled) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(OEM_ANDROID) + dhd_os_send_hang_message(dhdp); +#else + WL_ERR(("HANG event is unsupported\n")); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */ + } +#endif /* BCMDONGLEHOST && DHD_FW_COREDUMP */ + } s32 wl_init_scan(struct bcm_cfg80211 *cfg) @@ -4303,30 +4592,50 @@ wl_cfgscan_init_pno_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev, struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); int err = 0; - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && \ + defined(SUPPORT_RANDOM_MAC_SCAN) + uint8 random_addr[ETHER_ADDR_LEN] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8 random_mask_46_bits[ETHER_ADDR_LEN] = {0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +#endif /* KERNEL_VER >= 3.19 && SUPPORT_RANDOM_MAC_SCAN */ mutex_lock(&cfg->scan_sync); - LOG_TS(cfg, scan_start); + + /* No scans in progress */ + if (!cfg->sched_scan_req) { + err = BCME_ERROR; + WL_ERR(("No sched scan is in progress, err:%d\n", err)); + goto exit; + } if (wl_get_drv_status_all(cfg, SCANNING)) { + WL_INFORM_MEM(("scan in progress. cancel and trigger PNO targetted scan\n")); _wl_cfgscan_cancel_scan(cfg); } wl_set_drv_status(cfg, SCANNING, ndev); WL_PNO((">>> Doing targeted ESCAN on PNO event\n")); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && \ + defined(SUPPORT_RANDOM_MAC_SCAN) + request->flags |= NL80211_SCAN_FLAG_RANDOM_ADDR; + memcpy_s(&request->mac_addr, ETH_ALEN, random_addr, ETH_ALEN); + memcpy_s(&request->mac_addr_mask, ETH_ALEN, random_mask_46_bits, ETH_ALEN); +#endif /* KERNEL_VER >= 3.19 && SUPPORT_RANDOM_MAC_SCAN */ + LOG_TS(cfg, scan_start); err = wl_do_escan(cfg, wiphy, ndev, request); if (err) { wl_clr_drv_status(cfg, SCANNING, ndev); - mutex_unlock(&cfg->scan_sync); WL_ERR(("targeted escan failed. err:%d\n", err)); - return err; + CLR_TS(cfg, scan_start); + goto exit; } + UNUSED_PARAMETER(dhdp); DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED); cfg->sched_scan_running = TRUE; - mutex_unlock(&cfg->scan_sync); +exit: + mutex_unlock(&cfg->scan_sync); return err; } @@ -4337,7 +4646,7 @@ wl_cfgscan_update_v3_schedscan_results(struct bcm_cfg80211 *cfg, struct net_devi int err = 0; wl_pfn_net_info_v3_t *netinfo, *pnetinfo; struct cfg80211_scan_request *request = NULL; - struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT]; + struct cfg80211_ssid *ssid = NULL; struct ieee80211_channel *channel = NULL; struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); @@ -4362,13 +4671,13 @@ wl_cfgscan_update_v3_schedscan_results(struct bcm_cfg80211 *cfg, struct net_devi pfn_result->count = MAX_PFN_LIST_COUNT; } - bzero(&ssid, sizeof(ssid)); - + ssid = (struct cfg80211_ssid *)MALLOCZ(cfg->osh, + sizeof(struct cfg80211_ssid) * MAX_PFN_LIST_COUNT); request = (struct cfg80211_scan_request *)MALLOCZ(cfg->osh, sizeof(*request) + sizeof(*request->channels) * pfn_result->count); channel = (struct ieee80211_channel *)MALLOCZ(cfg->osh, (sizeof(struct ieee80211_channel) * pfn_result->count)); - if (!request || !channel) { + if (!request || !channel || !ssid) { WL_ERR(("No memory")); err = -ENOMEM; goto out_err; @@ -4422,8 +4731,9 @@ wl_cfgscan_update_v3_schedscan_results(struct bcm_cfg80211 *cfg, struct net_devi (void)memcpy_s(ssid_buf, IEEE80211_MAX_SSID_LEN, ssid[i].ssid, ssid_len); ssid_buf[ssid_len] = '\0'; - WL_INFORM_MEM(("[PNO] SSID:%s chanspec:0x%x freq:%d band:%d\n", - ssid_buf, netinfo->pfnsubnet.chanspec, + WL_INFORM_MEM(("[PNO] SSID:%s SSID length:%d" + " chanspec:0x%x freq:%d band:%d\n", + SSID_DBG(ssid_buf), ssid_len, netinfo->pfnsubnet.chanspec, channel[i].center_freq, channel[i].band)); if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) { payload_len = sizeof(log_conn_event_t); @@ -4468,7 +4778,7 @@ wl_cfgscan_update_v3_schedscan_results(struct bcm_cfg80211 *cfg, struct net_devi err = wl_cfgp2p_discover_enable_search(cfg, false); if (unlikely(err)) { wl_clr_drv_status(cfg, SCANNING, ndev); - return err; + goto out_err; } p2p_scan(cfg) = false; } @@ -4483,6 +4793,10 @@ wl_cfgscan_update_v3_schedscan_results(struct bcm_cfg80211 *cfg, struct net_devi } out_err: + if (ssid) { + MFREE(cfg->osh, ssid, + sizeof(struct cfg80211_ssid) * MAX_PFN_LIST_COUNT); + } if (request) { MFREE(cfg->osh, request, sizeof(*request) + sizeof(*request->channels) * pfn_result->count); @@ -4498,6 +4812,7 @@ out_err: return err; } + /* If target scan is not reliable, set the below define to "1" to do a * full escan */ @@ -4511,7 +4826,7 @@ wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev, dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); int err = 0; struct cfg80211_scan_request *request = NULL; - struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT]; + struct cfg80211_ssid *ssid = NULL; struct ieee80211_channel *channel = NULL; int channel_req = 0; int band = 0; @@ -4527,6 +4842,11 @@ wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev, WL_DBG(("Enter\n")); + if (cfg->sched_scan_running) { + WL_INFORM_MEM(("sched_scan is already running. return\n")); + return BCME_OK; + } + /* These static asserts guarantee v1/v2 net_info and subnet_info are compatible * in size and SSID offset, allowing v1 to be used below except for the results * fields themselves (status, count, offset to netinfo). @@ -4534,8 +4854,6 @@ wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev, STATIC_ASSERT(sizeof(wl_pfn_net_info_v1_t) == sizeof(wl_pfn_net_info_v2_t)); STATIC_ASSERT(sizeof(wl_pfn_lnet_info_v1_t) == sizeof(wl_pfn_lnet_info_v2_t)); STATIC_ASSERT(sizeof(wl_pfn_subnet_info_v1_t) == sizeof(wl_pfn_subnet_info_v2_t)); - STATIC_ASSERT(OFFSETOF(wl_pfn_subnet_info_v1_t, SSID) == - OFFSETOF(wl_pfn_subnet_info_v2_t, u.SSID)); /* Extract the version-specific items */ if (pfn_result_v1->version == PFN_SCANRESULT_VERSION_V1) { @@ -4549,13 +4867,13 @@ wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev, if (n_pfn_results > MAX_PFN_LIST_COUNT) n_pfn_results = MAX_PFN_LIST_COUNT; - bzero(&ssid, sizeof(ssid)); - + ssid = (struct cfg80211_ssid *)MALLOCZ(cfg->osh, + sizeof(struct cfg80211_ssid) * MAX_PFN_LIST_COUNT); request = (struct cfg80211_scan_request *)MALLOCZ(cfg->osh, sizeof(*request) + sizeof(*request->channels) * n_pfn_results); channel = (struct ieee80211_channel *)MALLOCZ(cfg->osh, (sizeof(struct ieee80211_channel) * n_pfn_results)); - if (!request || !channel) { + if (!request || !channel || !ssid) { WL_ERR(("No memory")); err = -ENOMEM; goto out_err; @@ -4695,13 +5013,13 @@ wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev, if (n_pfn_results > MAX_PFN_LIST_COUNT) n_pfn_results = MAX_PFN_LIST_COUNT; - bzero(&ssid, sizeof(ssid)); - + ssid = (struct cfg80211_ssid *)MALLOCZ(cfg->osh, + sizeof(struct cfg80211_ssid) * MAX_PFN_LIST_COUNT); request = (struct cfg80211_scan_request *)MALLOCZ(cfg->osh, sizeof(*request) + sizeof(*request->channels) * n_pfn_results); channel = (struct ieee80211_channel *)MALLOCZ(cfg->osh, (sizeof(struct ieee80211_channel) * n_pfn_results)); - if (!request || !channel) { + if (!request || !channel || !ssid) { WL_ERR(("No memory")); err = -ENOMEM; goto out_err; @@ -4834,18 +5152,9 @@ out_err: */ if (cfg->sched_scan_req) { WL_ERR(("sched_scan stopped\n")); -#if defined (WL_SCHED_SCAN) && defined (SCHED_SCAN_DELAYED_WORK) wl_cfg80211_stop_pno(cfg, bcmcfg_to_prmry_ndev(cfg)); /* schedule the work to indicate sched scan stop to cfg layer */ schedule_delayed_work(&cfg->sched_scan_stop_work, 0); -#else -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) - cfg80211_sched_scan_stopped(wiphy, cfg->sched_scan_req->reqid); -#else - cfg80211_sched_scan_stopped(wiphy); -#endif /* KERNEL > 4.11.0 */ - cfg->sched_scan_req = NULL; -#endif } else { WL_ERR(("sched scan req null!\n")); } @@ -4854,6 +5163,10 @@ out_err: } mutex_unlock(&cfg->scan_sync); + if (ssid) { + MFREE(cfg->osh, ssid, + sizeof(struct cfg80211_ssid) * MAX_PFN_LIST_COUNT); + } if (request) { MFREE(cfg->osh, request, sizeof(*request) + sizeof(*request->channels) * n_pfn_results); @@ -4913,7 +5226,11 @@ wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, /* If cfg80211 scheduled scan is supported, report the pno results via sched * scan results */ - wl_notify_sched_scan_results(cfg, ndev, e, data); + if (cfg->sched_scan_req) { + wl_notify_sched_scan_results(cfg, ndev, e, data); + } else { + WL_ERR(("No sched scan running. ignore.\n")); + } #endif /* WL_SCHED_SCAN */ return 0; } @@ -5065,34 +5382,34 @@ wl_init_scan_params(struct bcm_cfg80211 *cfg, u8 *params, u16 params_size, u32 scan_type, u32 action, u32 passive_time) { u32 sync_id = 0; - wl_escan_params_t *eparams = NULL; - wl_escan_params_v2_t *eparams_v2 = NULL; - wl_scan_params_t *scanparams = NULL; - wl_scan_params_v2_t *scanparams_v2 = NULL; + wl_escan_params_v1_t *eparams = NULL; + wl_escan_params_v3_t *eparams_v3 = NULL; + wl_scan_params_v1_t *scanparams = NULL; + wl_scan_params_v3_t *scanparams_v3 = NULL; wl_escan_set_sync_id(sync_id, cfg); - if (cfg->scan_params_v2) { - eparams_v2 = (wl_escan_params_v2_t *)params; - eparams_v2->version = htod32(ESCAN_REQ_VERSION_V2); - eparams_v2->action = htod16(action); - eparams_v2->sync_id = sync_id; - scanparams_v2 = (wl_scan_params_v2_t *)&eparams_v2->params; - (void)memcpy_s(&scanparams_v2->bssid, ETHER_ADDR_LEN, ðer_bcast, ETHER_ADDR_LEN); - scanparams_v2->version = htod16(WL_SCAN_PARAMS_VERSION_V2); - scanparams_v2->length = htod16(sizeof(wl_scan_params_v2_t)); - scanparams_v2->bss_type = DOT11_BSSTYPE_ANY; - scanparams_v2->scan_type = htod32(scan_type); - scanparams_v2->nprobes = htod32(-1); - scanparams_v2->active_time = htod32(-1); - scanparams_v2->passive_time = htod32(passive_time); - scanparams_v2->home_time = htod32(-1); - bzero(&scanparams_v2->ssid, sizeof(wlc_ssid_t)); + if (IS_SCAN_PARAMS_V3_V2(cfg)) { + eparams_v3 = (wl_escan_params_v3_t *)params; + eparams_v3->version = htod32(cfg->scan_params_ver); + eparams_v3->action = htod16(action); + eparams_v3->sync_id = sync_id; + scanparams_v3 = (wl_scan_params_v3_t *)&eparams_v3->params; + (void)memcpy_s(&scanparams_v3->bssid, ETHER_ADDR_LEN, ðer_bcast, ETHER_ADDR_LEN); + scanparams_v3->version = htod16(WL_SCAN_PARAMS_VERSION_V3); + scanparams_v3->length = htod16(sizeof(wl_scan_params_v3_t)); + scanparams_v3->bss_type = DOT11_BSSTYPE_ANY; + scanparams_v3->scan_type = htod32(scan_type); + scanparams_v3->nprobes = htod32(-1); + scanparams_v3->active_time = htod32(-1); + scanparams_v3->passive_time = htod32(passive_time); + scanparams_v3->home_time = htod32(-1); + bzero(&scanparams_v3->ssid, sizeof(wlc_ssid_t)); } else { - eparams = (wl_escan_params_t *)params; - eparams->version = htod32(ESCAN_REQ_VERSION); + eparams = (wl_escan_params_v1_t *)params; + eparams->version = htod32(ESCAN_REQ_VERSION_V1); eparams->action = htod16(action); eparams->sync_id = sync_id; - scanparams = (wl_scan_params_t *)&eparams->params; + scanparams = (wl_scan_params_v1_t *)&eparams->params; (void)memcpy_s(&scanparams->bssid, ETHER_ADDR_LEN, ðer_bcast, ETHER_ADDR_LEN); scanparams->bss_type = DOT11_BSSTYPE_ANY; scanparams->scan_type = 0; @@ -5146,10 +5463,10 @@ wl_cfgscan_listen_on_channel(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev s32 err = 0; struct net_device *ndev = NULL; u8 *params = NULL; - wl_escan_params_t *eparams = NULL; - wl_escan_params_v2_t *eparams_v2 = NULL; - wl_scan_params_t *scanparams = NULL; - wl_scan_params_v2_t *scanparams_v2 = NULL; + wl_escan_params_v1_t *eparams = NULL; + wl_escan_params_v3_t *eparams_v3 = NULL; + wl_scan_params_v1_t *scanparams = NULL; + wl_scan_params_v3_t *scanparams_v3 = NULL; u16 *chanspec_list = NULL; u32 channel_num = 0, scan_type = 0; @@ -5180,18 +5497,19 @@ wl_cfgscan_listen_on_channel(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev /* Use primary ndev for netless dev. BSSIDX will point to right I/F */ ndev = wdev->netdev ? wdev->netdev : bcmcfg_to_prmry_ndev(cfg); - if (cfg->scan_params_v2) { - params_size = (WL_SCAN_PARAMS_V2_FIXED_SIZE + - OFFSETOF(wl_escan_params_v2_t, params)); + if (IS_SCAN_PARAMS_V3_V2(cfg)) { + params_size = (WL_SCAN_PARAMS_V3_FIXED_SIZE + + OFFSETOF(wl_escan_params_v3_t, params)); } else { - params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); + params_size = (WL_SCAN_PARAMS_V1_FIXED_SIZE + + OFFSETOF(wl_escan_params_v1_t, params)); } /* Single channel for listen case. Add a padd of u16 for alignment */ chanspec_num = 1; params_size += (chanspec_num + 1); - /* Allocate space for populating single ssid in wl_escan_params_t struct */ + /* Allocate space for populating single ssid in wl_escan_params_v1_t struct */ params_size += ((u32) sizeof(struct wlc_ssid)); params = MALLOCZ(cfg->osh, params_size); @@ -5207,14 +5525,14 @@ wl_cfgscan_listen_on_channel(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev scan_type, WL_SCAN_ACTION_START, dwell); channel_num = (chanspec_num & WL_SCAN_PARAMS_COUNT_MASK); - if (cfg->scan_params_v2) { - eparams_v2 = (wl_escan_params_v2_t *)params; - scanparams_v2 = (wl_scan_params_v2_t *)&eparams_v2->params; - chanspec_list = scanparams_v2->channel_list; - scanparams_v2->channel_num = channel_num; + if (IS_SCAN_PARAMS_V3_V2(cfg)) { + eparams_v3 = (wl_escan_params_v3_t *)params; + scanparams_v3 = (wl_scan_params_v3_t *)&eparams_v3->params; + chanspec_list = scanparams_v3->channel_list; + scanparams_v3->channel_num = channel_num; } else { - eparams = (wl_escan_params_t *)params; - scanparams = (wl_scan_params_t *)&eparams->params; + eparams = (wl_escan_params_v1_t *)params; + scanparams = (wl_scan_params_v1_t *)&eparams->params; chanspec_list = scanparams->channel_list; scanparams->channel_num = channel_num; } @@ -5273,8 +5591,7 @@ wl_priortize_scan_over_listen(struct bcm_cfg80211 *cfg, wl_clr_p2p_status(cfg, LISTEN_EXPIRED); - INIT_TIMER(&cfg->p2p->listen_timer, - wl_cfgp2p_listen_expired, duration, 0); + mod_timer(&cfg->p2p->listen_timer, jiffies + msecs_to_jiffies(duration)); } #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ @@ -5283,12 +5600,15 @@ wl_priortize_scan_over_listen(struct bcm_cfg80211 *cfg, (wdev->netdev ? (strncmp(wdev->netdev->name, "p2p0", strlen("p2p0")) == 0) : false) s32 +#if defined(WL_CFG80211_P2P_DEV_IF) +wl_cfgscan_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + struct ieee80211_channel *channel, unsigned int duration, u64 *cookie) +#else wl_cfgscan_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, struct ieee80211_channel *channel, -#if !defined(WL_CFG80211_P2P_DEV_IF) enum nl80211_channel_type channel_type, -#endif /* WL_CFG80211_P2P_DEV_IF */ unsigned int duration, u64 *cookie) +#endif /* WL_CFG80211_P2P_DEV_IF */ { s32 target_channel; u32 id; @@ -5299,7 +5619,6 @@ wl_cfgscan_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, RETURN_EIO_IF_NOT_UP(cfg); - mutex_lock(&cfg->usr_sync); ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); #if defined(WL_CFG80211_P2P_DEV_IF) wdev = cfgdev; @@ -5312,6 +5631,11 @@ wl_cfgscan_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, goto exit; } + if (wl_get_drv_status(cfg, AP_CREATING, ndev)) { + err = BCME_BADARG; + goto exit; + } + target_channel = ieee80211_frequency_to_channel(channel->center_freq); WL_DBG(("Enter, channel: %d, duration ms (%d) scan_state:%d\n", @@ -5384,6 +5708,8 @@ wl_cfgscan_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, if (unlikely(err)) { goto exit; } + + mutex_lock(&cfg->usr_sync); err = wl_cfgp2p_discover_listen(cfg, target_channel, duration); if (err == BCME_OK) { wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev); @@ -5401,6 +5727,7 @@ wl_cfgscan_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, } #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ } + mutex_unlock(&cfg->usr_sync); } else if (wdev->iftype == NL80211_IFTYPE_STATION || wdev->iftype == NL80211_IFTYPE_AP) { WL_DBG(("LISTEN ON CHANNEL\n")); @@ -5429,7 +5756,6 @@ exit: WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie)); wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL); } - mutex_unlock(&cfg->usr_sync); return err; } @@ -5501,7 +5827,8 @@ wl_android_get_roam_scan_chanlist(struct bcm_cfg80211 *cfg) wlc_ssid_t *ssid = NULL; wl_roam_channel_list_t channel_list; uint16 channels[MAX_ROAM_CHANNEL] = {0}; - int i = 0; + char chanspec_buf[CHANSPEC_STR_LEN]; + int i = 0, nchan = 0; ndev = bcmcfg_to_prmry_ndev(cfg); wiphy = bcmcfg_to_wiphy(cfg); @@ -5537,9 +5864,15 @@ wl_android_get_roam_scan_chanlist(struct bcm_cfg80211 *cfg) WL_DBG(("SSID %s(%d), RCC(%d)\n", ssid->SSID, ssid->SSID_len, channel_list.n)); for (i = 0; i < channel_list.n; i++) { - channels[i] = CHSPEC_CHANNEL(channel_list.channels[i]); - WL_DBG(("Chanspec[%d] CH:%03d(0x%04x)\n", - i, channels[i], channel_list.channels[i])); + WL_DBG(("Chanspec[%d] CH: %s (0x%04x)\n", + i, wf_chspec_ntoa_ex(channel_list.channels[i], chanspec_buf), + channel_list.channels[i])); + if (CHSPEC_IS6G(channel_list.channels[i])) { + WL_DBG(("Skip 6G channel\n")); + continue; + } + channels[nchan] = CHSPEC_CHANNEL(channel_list.channels[i]); + nchan++; } err = nla_put_string(skb, RCC_ATTRIBUTE_SSID, ssid->SSID); @@ -5554,7 +5887,7 @@ wl_android_get_roam_scan_chanlist(struct bcm_cfg80211 *cfg) goto fail; } - err = nla_put_u32(skb, RCC_ATTRIBUTE_NUM_CHANNELS, channel_list.n); + err = nla_put_u32(skb, RCC_ATTRIBUTE_NUM_CHANNELS, nchan); if (unlikely(err)) { WL_ERR(("nla_put_u32 RCC_ATTRIBUTE_NUM_CHANNELS failed\n")); goto fail; @@ -5578,6 +5911,98 @@ fail: #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ return err; } + +int +wl_android_get_roam_scan_freqlist(struct bcm_cfg80211 *cfg) +{ + s32 err = BCME_OK; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + struct sk_buff *skb; + gfp_t kflags; + struct net_device *ndev; + struct wiphy *wiphy; + wlc_ssid_t *ssid = NULL; + wl_roam_channel_list_t channel_list; + uint16 frequencies[MAX_ROAM_CHANNEL] = {0}; + int i = 0; + + ndev = bcmcfg_to_prmry_ndev(cfg); + wiphy = bcmcfg_to_wiphy(cfg); + + kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), + BRCM_VENDOR_GET_RCC_EVENT_BUF_LEN, BRCM_VENDOR_EVENT_RCC_FREQ_INFO, kflags); + + if (!skb) { + WL_ERR(("skb alloc failed")); + return BCME_NOMEM; + } + + /* Get Current SSID */ + ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID); + if (!ssid) { + WL_ERR(("No SSID found in the saved profile\n")); + err = BCME_ERROR; + goto fail; + } + + /* Get Current RCC List */ + err = wldev_iovar_getbuf(ndev, "roamscan_channels", 0, 0, + (void *)&channel_list, sizeof(channel_list), NULL); + if (err) { + WL_ERR(("Failed to get roamscan channels, err = %d\n", err)); + goto fail; + } + if (channel_list.n > MAX_ROAM_CHANNEL) { + WL_ERR(("Invalid roamscan channels count(%d)\n", channel_list.n)); + goto fail; + } + + WL_DBG(("SSID %s(%d), RCC(%d)\n", ssid->SSID, ssid->SSID_len, channel_list.n)); + for (i = 0; i < channel_list.n; i++) { + chanspec_t chsp = channel_list.channels[i]; + u32 freq = wl_channel_to_frequency(wf_chspec_ctlchan(chsp), CHSPEC_BAND(chsp)); + WL_DBG((" [%d] Freq: %d (0x%04x)\n", i, freq, channel_list.channels[i])); + frequencies[i] = (uint16)freq; + } + + err = nla_put_string(skb, RCC_ATTRIBUTE_SSID, ssid->SSID); + if (unlikely(err)) { + WL_ERR(("nla_put_string RCC_ATTRIBUTE_SSID failed\n")); + goto fail; + } + + err = nla_put_u32(skb, RCC_ATTRIBUTE_SSID_LEN, ssid->SSID_len); + if (unlikely(err)) { + WL_ERR(("nla_put_u32 RCC_ATTRIBUTE_SSID_LEN failed\n")); + goto fail; + } + + err = nla_put_u32(skb, RCC_ATTRIBUTE_NUM_CHANNELS, channel_list.n); + if (unlikely(err)) { + WL_ERR(("nla_put_u32 RCC_ATTRIBUTE_NUM_CHANNELS failed\n")); + goto fail; + } + + err = nla_put(skb, RCC_ATTRIBUTE_CHANNEL_LIST, + sizeof(uint16) * MAX_ROAM_CHANNEL, frequencies); + if (unlikely(err)) { + WL_ERR(("nla_put RCC_ATTRIBUTE_CHANNEL_LIST failed\n")); + goto fail; + } + + cfg80211_vendor_event(skb, kflags); + + return err; + +fail: + if (skb) { + nlmsg_free(skb); + } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ + return err; +} + #endif /* WL_GET_RCC */ /* @@ -5617,8 +6042,10 @@ wl_get_assoc_channels(struct bcm_cfg80211 *cfg, } ssid.SSID_len = (uint32)info->ssid_len; - if (info->targeted_join && info->chanspecs[0]) { + /* Utilize channel hint if availble */ + if ((info->chan_cnt == 1) && info->chanspecs[0]) { target_chspec = info->chanspecs[0]; + WL_DBG(("channel_hint chanspec:%x\n", info->chanspecs[0])); } else { target_chspec = INVCHANSPEC; } @@ -5637,6 +6064,7 @@ wl_get_assoc_channels(struct bcm_cfg80211 *cfg, WL_INFORM_MEM(("6G channel in rcc. use fw nw sel\n")); /* skip bssid hint inclusion and provide bcast bssid */ info->bssid_hint = false; + info->targeted_join = false; (void)memcpy_s(&info->bssid, ETH_ALEN, ðer_bcast, ETH_ALEN); break; @@ -5654,11 +6082,10 @@ wl_get_assoc_channels(struct bcm_cfg80211 *cfg, } #endif /* ESCAN_CHANNEL_CACHE */ - WL_DBG_MEM(("channel cnt:%d\n", info->chan_cnt)); + WL_SCAN(("channel cnt:%d\n", info->chan_cnt)); return BCME_OK; } -#ifdef DHD_GET_VALID_CHANNELS bool wl_cfgscan_is_dfs_set(wifi_band band) { @@ -5675,14 +6102,31 @@ wl_cfgscan_is_dfs_set(wifi_band band) } s32 -wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, int band, - uint16 *list, uint32 *num_channels) +wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev, int band, + uint32 *list, uint32 *num_channels) { s32 err = BCME_OK; uint32 i, freq, list_count, count = 0; struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); uint32 chspec, chaninfo; bool dfs_set = false; + bool ap_iface; + + if (!wdev) { + WL_ERR(("wdev null\n")); + return -EINVAL; + } + + ap_iface = IS_AP_IFACE(wdev); +#ifndef WL_DUAL_APSTA + if (!ap_iface && (wdev->netdev != bcmcfg_to_prmry_ndev(cfg))) { + /* The GETCHANNEL API could come before role conversion. so + * for now consider the requests coming on non primary I/F + * too as request for AP. + */ + ap_iface = TRUE; + } +#endif /* WL_DUAL_APSTA */ dfs_set = wl_cfgscan_is_dfs_set(band); err = wldev_iovar_getbuf_bsscfg(dev, "chan_info_list", NULL, @@ -5701,14 +6145,25 @@ wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, int band, chaninfo = dtoh32(((wl_chanspec_list_v1_t *)list)->chspecs[i].chaninfo); freq = wl_channel_to_frequency(wf_chspec_ctlchan(chspec), CHSPEC_BAND(chspec)); - if (((band & WIFI_BAND_BG) && CHSPEC_IS2G(chspec)) || - ((band & WIFI_BAND_6GHZ) && CHSPEC_IS6G(chspec))) { - /* add 2g/6g channels */ - list[i] = freq; - count++; + + if ((band & WIFI_BAND_BG) && CHSPEC_IS2G(chspec)) { + /* add 2g channels */ + list[count++] = freq; } + + if ((band & WIFI_BAND_6GHZ) && CHSPEC_IS6G(chspec) && CHSPEC_IS20(chspec)) { + /* For AP interface and 6G band, use only VLP, PSC channels */ + if (ap_iface && (!(chaninfo & WL_CHAN_BAND_6G_PSC) || + !(chaninfo & WL_CHAN_BAND_6G_VLP))) { + WL_DBG(("skipping chspec:%x freq:%d for ap_iface\n", chspec, freq)); + continue; + } + /* add 6g channels */ + list[count++] = freq; + } + /* handle 5g separately */ - if (CHSPEC_IS5G(chspec)) { + if (CHSPEC_IS5G(chspec) && CHSPEC_IS20(chspec)) { if (!((band == WIFI_BAND_A_DFS) && IS_DFS(chaninfo)) && !(band & WIFI_BAND_A)) { /* Not DFS only case nor 5G case */ @@ -5718,12 +6173,1289 @@ wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, int band, if ((band & WIFI_BAND_A) && !dfs_set && IS_DFS(chaninfo)) { continue; } - - list[i] = freq; - count++; + list[count++] = freq; } } + + WL_INFORM_MEM(("get_freqlist_cnt:%d band:%d\n", count, band)); *num_channels = count; return err; } -#endif /* DHD_GET_VALID_CHANNELS */ + +#if defined(WL_SOFTAP_ACS) +#define SEC_FREQ_HT40_OFFSET 20 +static acs_delay_work_t delay_work_acs = { .init_flag = 0 }; + +static int wl_cfgscan_acs_parse_result(acs_selected_channels_t *pResult, + chanspec_t ch_chosen, drv_acs_params_t *pParameter) +{ + unsigned int chspec_band, chspec_ctl_freq, chspec_center_ch, chspec_bw, chspec_sb; + + if ((!pResult) || (!pParameter)) { + WL_ERR(("parameter invalid\n")); + return BCME_BADARG; + } else if (!wf_chspec_valid(ch_chosen)) { + WL_ERR(("ch_chosen=0x%X invalid\n", ch_chosen)); + return BCME_BADARG; + } + + chspec_ctl_freq = wl_channel_to_frequency(wf_chspec_ctlchan((chanspec_t)ch_chosen), + CHSPEC_BAND((chanspec_t)ch_chosen)); + chspec_center_ch = wf_chspec_ctlchan((chanspec_t)ch_chosen); + chspec_band = CHSPEC_BAND((chanspec_t)ch_chosen); + chspec_bw = CHSPEC_BW(ch_chosen); + chspec_sb = CHSPEC_CTL_SB(ch_chosen); + WL_TRACE(("ctl_freq=%d, center_ch=%d, band=0x%X, bw=0x%X, sb=0x%X\n", + chspec_ctl_freq, chspec_center_ch, chspec_band, chspec_bw, chspec_sb)); + + (void)memset_s(pResult, sizeof(acs_selected_channels_t), + 0, sizeof(acs_selected_channels_t)); + + /* hw_mode */ + switch (chspec_band) { + case WL_CHANSPEC_BAND_2G: + pResult->hw_mode = HOSTAPD_MODE_IEEE80211G; + break; + case WL_CHANSPEC_BAND_5G: + case WL_CHANSPEC_BAND_6G: + default: + pResult->hw_mode = HOSTAPD_MODE_IEEE80211A; + break; + } + WL_TRACE(("hw_mode=%d\n", pResult->hw_mode)); + + /* ch_width and others */ + switch (chspec_bw) { + case WL_CHANSPEC_BW_40: + if (pParameter->ht40_enabled) { + pResult->ch_width = 40; + switch (chspec_sb) { + case WL_CHANSPEC_CTL_SB_U: + pResult->pri_freq = chspec_ctl_freq; + pResult->sec_freq = chspec_ctl_freq - SEC_FREQ_HT40_OFFSET; + break; + case WL_CHANSPEC_CTL_SB_L: + default: + pResult->pri_freq = chspec_ctl_freq; + pResult->sec_freq = chspec_ctl_freq + SEC_FREQ_HT40_OFFSET; + break; + } + WL_TRACE(("HT40 ok\n")); + } else { + pResult->ch_width = 20; + pResult->pri_freq = chspec_ctl_freq; + pResult->sec_freq = 0; + WL_TRACE(("HT40 to HT20\n")); + } + break; + case WL_CHANSPEC_BW_80: + if ((pParameter->vht_enabled) || (pParameter->he_enabled)) { + pResult->ch_width = 80; + chspec_center_ch = wf_chspec_primary80_channel((chanspec_t)ch_chosen); + pResult->vht_seg0_center_ch = chspec_center_ch; + pResult->vht_seg1_center_ch = 0; + switch (chspec_sb) { + case WL_CHANSPEC_CTL_SB_LL: + case WL_CHANSPEC_CTL_SB_LU: + pResult->pri_freq = chspec_ctl_freq; + pResult->sec_freq = chspec_ctl_freq + SEC_FREQ_HT40_OFFSET; + break; + case WL_CHANSPEC_CTL_SB_UL: + case WL_CHANSPEC_CTL_SB_UU: + default: + pResult->pri_freq = chspec_ctl_freq; + pResult->sec_freq = chspec_ctl_freq - SEC_FREQ_HT40_OFFSET; + break; + } + WL_TRACE(("HT80 ok\n")); + } else if (pParameter->ht40_enabled) { + pResult->ch_width = 40; + switch (chspec_sb) { + case WL_CHANSPEC_CTL_SB_LL: + case WL_CHANSPEC_CTL_SB_UL: + pResult->pri_freq = chspec_ctl_freq; + pResult->sec_freq = chspec_ctl_freq + SEC_FREQ_HT40_OFFSET; + break; + case WL_CHANSPEC_CTL_SB_LU: + case WL_CHANSPEC_CTL_SB_UU: + default: + pResult->pri_freq = chspec_ctl_freq; + pResult->sec_freq = chspec_ctl_freq - SEC_FREQ_HT40_OFFSET; + break; + } + WL_TRACE(("HT80 to HT40\n")); + } else { + pResult->ch_width = 20; + pResult->pri_freq = chspec_ctl_freq; + pResult->sec_freq = 0; + WL_TRACE(("HT80 to HT20\n")); + } + break; + case WL_CHANSPEC_BW_160: + case WL_CHANSPEC_BW_8080: + if ((pParameter->vht_enabled) || (pParameter->he_enabled)) { + pResult->ch_width = 160; + switch (chspec_sb) { + case WL_CHANSPEC_CTL_SB_LLL: + case WL_CHANSPEC_CTL_SB_LLU: + case WL_CHANSPEC_CTL_SB_LUL: + case WL_CHANSPEC_CTL_SB_LUU: + pResult->pri_freq = chspec_ctl_freq; + pResult->sec_freq = chspec_ctl_freq + SEC_FREQ_HT40_OFFSET; + pResult->vht_seg0_center_ch = chspec_center_ch; + pResult->vht_seg1_center_ch = chspec_center_ch + CH_80MHZ_APART; + break; + case WL_CHANSPEC_CTL_SB_ULL: + case WL_CHANSPEC_CTL_SB_ULU: + case WL_CHANSPEC_CTL_SB_UUL: + case WL_CHANSPEC_CTL_SB_UUU: + default: + pResult->pri_freq = chspec_ctl_freq; + pResult->sec_freq = chspec_ctl_freq - SEC_FREQ_HT40_OFFSET; + pResult->vht_seg0_center_ch = chspec_center_ch; + pResult->vht_seg1_center_ch = chspec_center_ch - CH_80MHZ_APART; + break; + } + WL_TRACE(("HT160 ok\n")); + } else if (pParameter->ht40_enabled) { + pResult->ch_width = 40; + switch (chspec_sb) { + case WL_CHANSPEC_CTL_SB_LLL: + case WL_CHANSPEC_CTL_SB_LUL: + case WL_CHANSPEC_CTL_SB_ULL: + case WL_CHANSPEC_CTL_SB_UUL: + pResult->pri_freq = chspec_ctl_freq; + pResult->sec_freq = chspec_ctl_freq + SEC_FREQ_HT40_OFFSET; + break; + case WL_CHANSPEC_CTL_SB_LLU: + case WL_CHANSPEC_CTL_SB_LUU: + case WL_CHANSPEC_CTL_SB_ULU: + case WL_CHANSPEC_CTL_SB_UUU: + default: + pResult->pri_freq = chspec_ctl_freq; + pResult->sec_freq = chspec_ctl_freq - SEC_FREQ_HT40_OFFSET; + break; + } + WL_TRACE(("HT160 to HT40\n")); + } else { + pResult->ch_width = 20; + pResult->pri_freq = chspec_ctl_freq; + pResult->sec_freq = 0; + WL_TRACE(("HT160 to HT20\n")); + } + break; + case WL_CHANSPEC_BW_20: + default: + if ((pParameter->ht_enabled) || (TRUE)) { + pResult->ch_width = 20; + pResult->pri_freq = chspec_ctl_freq; + } + WL_TRACE(("HT20 ok\n")); + break; + } + + WL_TRACE(("result: pri_freq=%d, sec_freq=%d, vht_seg0=%d, vht_seg1=%d," + " ch_width=%d, hw_mode=%d\n", + pResult->pri_freq, pResult->sec_freq, + pResult->vht_seg0_center_ch, pResult->vht_seg1_center_ch, + pResult->ch_width, pResult->hw_mode)); + + return 0; +} + +static int wl_cfgscan_acs_parse_parameter_save(int *pLen, uint32 *pList, chanspec_t chspec) +{ + int ret = 0; + int qty = 0; + int i; + + do { + if ((!pLen) || (!pList)) { + WL_ERR(("parameter invalid\n")); + ret = BCME_BADARG; + break; + } else { + qty = *pLen; + } + + if (!wf_chspec_valid(chspec)) { + WL_TRACE(("chanspec=0x%X invalid\n", chspec)); + ret = BCME_BADARG; + break; + } + + for (i = 0; i < qty; i++) { + if (pList[i] == chspec) { + break; + } + } + + if (i == qty) { + pList[qty++] = chspec; + *pLen = qty; + WL_TRACE(("fill list[%d] = 0x%X\n", qty, chspec)); + } else { + WL_TRACE(("duplicate with [idx]=[%d]=0x%X\n", i, chspec)); + break; + } + } while (0); + + return ret; +} + +static int wl_cfgscan_acs_parse_parameter(struct bcm_cfg80211 *cfg, + int *pLen, uint32 *pList, unsigned int chanspec, + drv_acs_params_t *pParameter) +{ + unsigned int chspec = 0, chspec_ctl_ch = 0, chspec_band = 0, chspec_bw = 0, chspec_sb = 0; + uint32 qty = 0, channel = 0, bw = 0; + s32 ret = 0; + + do { + if ((!pLen) || (!pList) || (!pParameter)) { + WL_ERR(("parameter invalid\n")); + ret = BCME_BADARG; + break; + } + + chspec_band = CHSPEC_BAND((chanspec_t)chanspec); + channel = wf_chspec_ctlchan((chanspec_t)chanspec); + if (channel != 165) { + bw = pParameter->ch_width; + } else { + bw = 20; /* ch165 supports bw20 only */ + } + qty = *pLen; + + /* Handle 20MHz case for 2G and 6G (PSC) */ + if (chspec_band == WL_CHANSPEC_BAND_2G || + chspec_band == WL_CHANSPEC_BAND_6G) { + /* Firmware expects 20Mhz PSC channels. */ + chspec_bw = WL_CHANSPEC_BW_20; + chspec_ctl_ch = channel; + chspec_sb = WL_CHANSPEC_CTL_SB_NONE; + chspec = (chanspec_t)(chspec_ctl_ch | chspec_band | + chspec_bw | chspec_sb); + wl_cfgscan_acs_parse_parameter_save(&qty, pList, chspec); + *pLen = qty; + return 0; + } + + /* Handle 5G band (from bw20 to bw80) */ + /* bw80 */ + if ((bw == 80) && + (pParameter->vht_enabled || pParameter->he_enabled)) { + chspec = wf_create_chspec_from_primary(channel, + WL_CHANSPEC_BW_80, chspec_band); +#ifdef WL_CELLULAR_CHAN_AVOID + if (!wl_cellavoid_is_safe_overlap(cfg->cellavoid_info, chspec)) { + chspec = INVCHANSPEC; + } +#endif /* WL_CELLULAR_CHAN_AVOID */ + if (chspec != INVCHANSPEC) { + WL_INFORM_MEM(("set %d/80 (0x%x)\n", channel, chspec)); + wl_cfgscan_acs_parse_parameter_save(&qty, pList, chspec); + } else { + bw = 40; /* downgrade if not found proper chanspec */ + } + } + + /* bw40 */ + if ((bw == 40) && + ((pParameter->ht40_enabled) || (pParameter->vht_enabled) || + (pParameter->he_enabled))) { + chspec = wf_create_chspec_from_primary(channel, + WL_CHANSPEC_BW_40, chspec_band); +#ifdef WL_CELLULAR_CHAN_AVOID + if (!wl_cellavoid_is_safe_overlap(cfg->cellavoid_info, chspec)) { + chspec = INVCHANSPEC; + } +#endif /* WL_CELLULAR_CHAN_AVOID */ + if (chspec != INVCHANSPEC) { + WL_INFORM_MEM(("set %d/40 (0x%x)\n", channel, chspec)); + wl_cfgscan_acs_parse_parameter_save(&qty, pList, chspec); + } else { + bw = 20; /* downgrade if not found proper chanspec */ + } + } + + /* bw20 */ + if ((bw == 20) && + ((pParameter->ht_enabled) || (pParameter->ht40_enabled) || + (pParameter->vht_enabled) || (pParameter->he_enabled))) { + chspec = wf_create_chspec_from_primary(channel, + WL_CHANSPEC_BW_20, chspec_band); +#ifdef WL_CELLULAR_CHAN_AVOID + if (!wl_cellavoid_is_safe_overlap(cfg->cellavoid_info, chspec)) { + chspec = INVCHANSPEC; + } +#endif /* WL_CELLULAR_CHAN_AVOID */ + if (chspec != INVCHANSPEC) { + WL_INFORM_MEM(("set %d/20 (0x%x)\n", channel, chspec)); + wl_cfgscan_acs_parse_parameter_save(&qty, pList, chspec); + } + } + + *pLen = qty; + WL_TRACE(("current quantity=%d\n", qty)); + } while (0); + + return ret; +} + +static void wl_cfgscan_acs_result_event(struct work_struct *work) +{ + acs_delay_work_t *delay_work = (acs_delay_work_t *)work; + struct net_device *ndev = NULL; + struct wiphy *wiphy = NULL; + chanspec_t ch_chosen; + drv_acs_params_t *pParameter; + gfp_t kflags; + struct sk_buff *skb = NULL; + acs_selected_channels_t result; + int len = 0; + int ret = 0; + + do { + if (!delay_work) { + WL_ERR(("work parameter invalid\n")); + ret = BCME_BADARG; + break; + } else { + ndev = delay_work->ndev; + ch_chosen = delay_work->ch_chosen; + pParameter = &delay_work->parameter; + } + + if ((!ndev) || (!(ndev->ieee80211_ptr)) || (!(ndev->ieee80211_ptr->wiphy))) { + WL_ERR(("parameter invalid\n")); + ret = BCME_BADARG; + break; + } + wiphy = ndev->ieee80211_ptr->wiphy; + + /* construct result */ + if (wl_cfgscan_acs_parse_result(&result, ch_chosen, pParameter) < 0) { + WL_ERR(("fail to convert the result\n")); + ret = BCME_BADARG; + break; + } + + len = 200; + kflags = in_atomic()? GFP_ATOMIC : GFP_KERNEL; + WL_TRACE(("idx=%d, wiphy->n_vendor_events=%d\n", + BRCM_VENDOR_EVENT_ACS, wiphy->n_vendor_events)); + /* Alloc the SKB for vendor_event */ +#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \ + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) || defined(USE_BACKPORT_4) + skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), len, + BRCM_VENDOR_EVENT_ACS, kflags); +#else + skb = cfg80211_vendor_event_alloc(wiphy, len, BRCM_VENDOR_EVENT_ACS, kflags); +#endif /* CONFIG_ARCH_MSM SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC */ + if (!skb) { + WL_ERR(("Error, no memory for event\n")); + ret = BCME_NOMEM; + break; + } + + if ((nla_put_u32(skb, BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ, result.pri_freq) < 0) || + (nla_put_u32(skb, BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ, result.sec_freq) < 0) || + (nla_put_u8(skb, BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL, + result.vht_seg0_center_ch) < 0) || + (nla_put_u8(skb, BRCM_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL, + result.vht_seg1_center_ch) < 0) || + (nla_put_u16(skb, BRCM_VENDOR_ATTR_ACS_CHWIDTH, result.ch_width) < 0) || + (nla_put_u8(skb, BRCM_VENDOR_ATTR_ACS_HW_MODE, result.hw_mode) < 0)) { + WL_ERR(("Error, fail to fill the result\n")); + ret = BCME_BADARG; + break; + } + + WL_INFORM_MEM(("ACS event notified. freq:%d:%d\n", + result.pri_freq, result.sec_freq)); + cfg80211_vendor_event(skb, kflags); + } while (0); + + if (ret < 0) { + if (skb) { + WL_ERR(("free the event since fail with ret=%d\n", ret)); + dev_kfree_skb_any(skb); + } + } +} + +static chanspec_t +wl_cfgscan_acs_find_default_chanspec(struct bcm_cfg80211 *cfg, u32 band, + uint32 *pList, int qty) +{ + chanspec_t chosen; +#ifndef WL_CELLULAR_CHAN_AVOID + uint16 channel; + BCM_REFERENCE(cfg); +#endif + + if (pList != NULL && qty != 0) { + chosen = pList[qty - 1]; + } else { +#ifdef WL_CELLULAR_CHAN_AVOID + wl_cellavoid_sync_lock(cfg); + chosen = wl_cellavoid_find_chspec_fromband(cfg->cellavoid_info, band); + wl_cellavoid_sync_unlock(cfg); +#else + switch (band) { +#ifdef WL_6G_BAND + case WLC_BAND_6G: + channel = APCS_DEFAULT_6G_CH; + break; +#endif /* WL_6G_BAND */ + case WLC_BAND_5G: + channel = APCS_DEFAULT_5G_CH; + break; + default: + channel = APCS_DEFAULT_2G_CH; + break; + } + chosen = CH20MHZ_CHSPEC(channel); +#endif /* WL_CELLULAR_CHAN_AVOID */ + } + + return chosen; +} + +static int wl_cfgscan_acs_do_apcs(struct net_device *dev, + drv_acs_params_t *parameter, chanspec_t *pCH, + int len, unsigned char *pBuffer, int qty, uint32 *pList) +{ + int channel = 0; + int chosen = 0; + int retry = 0; + int ret = 0; + u32 band = parameter->band; + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); +#ifdef WL_ESCAN + wl_scan_info_t *scan_info = NULL; +#endif /* WL_ESCAN */ + + if (parameter->scc_chspec) { + chosen = parameter->scc_chspec; + WL_INFORM_MEM(("sta connected case. chosen:0x%x\n", chosen)); + goto done2; + } + + if ((pBuffer) && (0 < len)) { + /* The buffer has count followed by chanspecs */ + u32 buf_len = (qty + 1) * sizeof(uint32); + if (wl_dbg_level & WL_DBG_DBG) { + prhex("acs iovar_buf:", pBuffer, buf_len); + } + + /* Skip ACS for single channel case */ + if ((qty == 1) && pList) { + /* For single chanspec, ACS not required */ + chosen = pList[0]; + WL_INFORM_MEM(("single channel case. Skip ACS. chosen:0x%x\n", chosen)); + goto done2; + } + + /* Make sure any scan is not running before ACS trigged. */ + wl_cfgscan_cancel_scan(cfg); + +#ifdef WL_ESCAN + scan_info = kzalloc(sizeof(wl_scan_info_t), GFP_KERNEL); + if (scan_info == NULL) { + WL_ERR(("scan_info kzalloc failed\n")); + ret = -ENOMEM; + goto done; + } + memcpy(&scan_info->channels, pBuffer, buf_len); + chosen = wl_ext_autochannel(dev, ACS_DRV_BIT, band, scan_info); + if (chosen) { + goto done2; + } else + goto done; +#endif /* WL_ESCAN */ + ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)pBuffer, buf_len); + if (ret) { + WL_ERR(("autochannel trigger failed. ret=%d\n", ret)); + } else { + WL_INFORM_MEM(("acs triggered for %d chanspecs. ret=%d\n", qty, ret)); + } + } else { + ret = BCME_BADARG; + WL_ERR(("Error, no parameter to go, ret=%d\n", ret)); + } + + if (ret < 0) { + channel = 0; + ret = BCME_BADARG; + goto done; + } + + /* Wait for auto channel selection, max 3000 ms */ + if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G) || (band == WLC_BAND_6G)) { + OSL_SLEEP(500); + } else { + /* Full channel scan at the minimum takes 1.2secs + * even with parallel scan. max wait time: 3500ms + */ + OSL_SLEEP(1000); + } + + retry = APCS_MAX_RETRY; + while (retry--) { + ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen)); + if (ret < 0) { + chosen = 0; + } else { + chosen = dtoh32(chosen); + } + WL_DBG(("round=%d, ret=%d, chosen=0x%X\n", + APCS_MAX_RETRY-retry, ret, chosen)); + + if (chosen) { + int freq; + + channel = wf_chspec_ctlchan((chanspec_t)chosen); + freq = wl_channel_to_frequency( + wf_chspec_ctlchan((chanspec_t)chosen), + CHSPEC_BAND((chanspec_t)chosen)); + + WL_INFORM_MEM(("* good, selected chosen=0x%X, freq:%d channel = %d\n", + chosen, freq, channel)); + break; + } + OSL_SLEEP(300); + } + +done: + + if (!chosen) { + WL_ERR(("retry=%d, ret=%d, chosen=0x%X. Attempt default chan\n", + retry, ret, chosen)); + + /* On failure, fallback to a default channel */ + chosen = wl_cfgscan_acs_find_default_chanspec(cfg, band, pList, qty); + + /* Cellavoid might return INVCHANSPEC */ + if (ret < 0 && chosen != INVCHANSPEC) { + /* set it 0 when use default channel */ + ret = 0; + } + WL_ERR(("ACS failed. Fall back to default chanspec (0x%x)\n", chosen)); + } + +done2: + *pCH = chosen; + +#ifdef WL_ESCAN + if (scan_info) + kfree(scan_info); +#endif /* WL_ESCAN */ + return ret; +} + +#ifdef DHD_ACS_CHECK_SCC_2G_ACTIVE_CH +bool wl_check_active_2g_chan(struct bcm_cfg80211 *cfg, drv_acs_params_t *parameter, + chanspec_t sta_chanspec) +{ + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + bool scc = FALSE; + s32 ret = BCME_OK; + uint bitmap = 0; + u8 ioctl_buf[WLC_IOCTL_SMLEN]; + + bzero(ioctl_buf, WLC_IOCTL_SMLEN); + ret = wldev_iovar_getbuf(dev, "per_chan_info", + (void *)&sta_chanspec, sizeof(sta_chanspec), + ioctl_buf, WLC_IOCTL_SMLEN, NULL); + if (ret != BCME_OK) { + WL_ERR(("Failed to get per_chan_info chspec:0x%x, error:%d\n", + sta_chanspec, ret)); + goto exit; + } + + bitmap = dtoh32(*(uint *)ioctl_buf); + if (bitmap & (WL_CHAN_PASSIVE | WL_CHAN_RESTRICTED | WL_CHAN_CLM_RESTRICTED)) { + WL_INFORM_MEM(("chspec is not active chanspec:0x%x bitmap:%d\n", + sta_chanspec, bitmap)); + goto exit; + } + +#ifdef WL_CELLULAR_CHAN_AVOID + if (wl_cellavoid_mandatory_isset(cfg->cellavoid_info, NL80211_IFTYPE_AP) && + !wl_cellavoid_is_safe(cfg->cellavoid_info, sta_chanspec)) { + WL_INFORM_MEM(("Not allow unsafe channel and mandatory chspec:0x%x\n", + sta_chanspec)); + goto exit; + } +#endif /* WL_CELLULAR_CHAN_AVOID */ + + scc = TRUE; + +exit: + WL_INFORM_MEM(("STA chanspec:0x%x per_chan_info:0x%x scc:%d\n", + sta_chanspec, bitmap, scc)); + return scc; +} +#endif /* DHD_ACS_CHECK_SCC_2G_ACTIVE_CH */ + +#define MAX_ACS_FREQS 256u +static int +wl_convert_freqlist_to_chspeclist(struct bcm_cfg80211 *cfg, + u32 *pElem_freq, u32 freq_list_len, u32 *req_len, + u32 *pList, drv_acs_params_t *parameter, int qty) +{ + int i, j; + u32 list_size; + s32 ret = -EINVAL; + u32 *chspeclist = NULL; + u32 *p_chspec_list = NULL; + char chanspec_str[CHANSPEC_STR_LEN]; +#ifdef WL_CELLULAR_CHAN_AVOID + int safe_chspec_cnt = 0; + u32 *safe_chspeclist = NULL; + drv_acs_params_t safe_param = { 0 }; + bool safe_success = FALSE; +#endif /* WL_CELLULAR_CHAN_AVOID */ + + if (freq_list_len > MAX_ACS_FREQS) { + WL_ERR(("invalid len:%d\n", freq_list_len)); + return -EINVAL; + } + + list_size = sizeof(u32) * freq_list_len; + chspeclist = MALLOCZ(cfg->osh, list_size); + if (!chspeclist) { + WL_ERR(("chspec list alloc failed\n")); + return -ENOMEM; + } + +#ifdef WL_CELLULAR_CHAN_AVOID + safe_chspeclist = MALLOCZ(cfg->osh, list_size); + if (!safe_chspeclist) { + WL_ERR(("safe chspec list alloc failed\n")); + MFREE(cfg->osh, chspeclist, list_size); + return -ENOMEM; + } + + wl_cellavoid_sync_lock(cfg); +#endif /* WL_CELLULAR_CHAN_AVOID */ + + for (i = 0, j = 0; i < freq_list_len; i++) { + chspeclist[j] = wl_freq_to_chanspec(pElem_freq[i]); + if (CHSPEC_IS6G(chspeclist[j]) && !CHSPEC_IS_6G_PSC(chspeclist[j])) { + /* Skip non PSC channels */ + WL_DBG(("Skipping 6G non PSC channel\n")); + continue; + } + +#ifdef WL_UNII4_CHAN + /* Skip UNII-4 frequencies */ + if (CHSPEC_IS5G(chspeclist[j]) && + IS_UNII4_CHANNEL(CHSPEC_CHANNEL(chspeclist[j]))) { + WL_DBG(("Skipped UNII-4 chanspec 0x%x\n", chspeclist[j])); + continue; + } +#endif /* WL_UNII4_CHAN */ + +#ifdef WL_CELLULAR_CHAN_AVOID + if (wl_cellavoid_is_safe(cfg->cellavoid_info, chspeclist[j])) { + safe_chspeclist[safe_chspec_cnt++] = chspeclist[j]; + safe_param.freq_bands |= CHSPEC_TO_WLC_BAND(CHSPEC_BAND(chspeclist[j])); + wf_chspec_ntoa(chspeclist[j], chanspec_str); + WL_INFORM_MEM(("Adding %s (0x%x) to the safe list\n", + chanspec_str, chspeclist[j])); + } +#endif /* WL_CELLULAR_CHAN_AVOID */ + + /* mark all the bands found */ + parameter->freq_bands |= CHSPEC_TO_WLC_BAND(CHSPEC_BAND(chspeclist[j])); + WL_DBG(("list[%d]=%d => chspec=0x%x\n", i, pElem_freq[i], chspeclist[j])); + j++; + } + +#ifdef WL_CELLULAR_CHAN_AVOID + wl_cellavoid_sync_unlock(cfg); +#endif /* WL_CELLULAR_CHAN_AVOID */ + + /* Overried freq list len with the new value */ + freq_list_len = j; + + WL_DBG(("** freq_bands=0x%x\n", parameter->freq_bands)); +#ifdef WL_5G_SOFTAP_ONLY_ON_DEF_CHAN + if ((parameter->freq_bands & WLC_BAND_5G) && + !(parameter->freq_bands & WLC_BAND_6G)) { + + /* Use default 5G channel for cases where 6G is not provided */ + for (i = 0; i < freq_list_len; i++) { + if (CHSPEC_CHANNEL(chspeclist[i]) == APCS_DEFAULT_5G_CH) { + WL_INFORM_MEM(("Def ACS chanspec:0x%x\n", chspeclist[i])); + wl_cfgscan_acs_parse_parameter(cfg, req_len, pList, + chspeclist[i], parameter); + goto exit; + } + } + + if (i == freq_list_len) { + WL_ERR(("Default 5g channel not found in the list\n")); + ret = -EINVAL; + goto exit; + } + } +#endif /* WL_5G_SOFTAP_ONLY_ON_DEF_CHAN */ + +#ifdef WL_CELLULAR_CHAN_AVOID + if (safe_chspec_cnt) { + WL_INFORM_MEM(("Try with safe channel, freq_band %x, chanspec cnt %d\n", + safe_param.freq_bands, safe_chspec_cnt)); + ret = wl_handle_acs_concurrency_cases(cfg, &safe_param, + safe_chspec_cnt, safe_chspeclist); + if (ret == BCME_OK) { + WL_INFORM_MEM(("Succeded to handle the acs concurrency case " + "with safe channels!\n")); + safe_success = TRUE; + goto success; + } + } + + if (wl_cellavoid_mandatory_isset(cfg->cellavoid_info, NL80211_IFTYPE_AP)) { + WL_INFORM_MEM(("Mandatory flag for AP is set, skip the ACS, safe_chspec_cnt %d\n", + safe_chspec_cnt)); + goto exit; + } + + if (safe_chspec_cnt != freq_list_len) { + WL_INFORM_MEM(("Try with all channels, freq_band %x, chanspec cnt %d\n", + parameter->freq_bands, freq_list_len)); + ret = wl_handle_acs_concurrency_cases(cfg, parameter, freq_list_len, chspeclist); + if (ret) { + WL_ERR(("Failed to handle the acs concurrency cases!\n")); + goto exit; + } + } +#else + ret = wl_handle_acs_concurrency_cases(cfg, parameter, freq_list_len, chspeclist); +#endif /* WL_CELLULAR_CHAN_AVOID */ + + if (ret) { + WL_ERR(("Failed to handle the acs concurrency cases!\n")); + goto exit; + } + +#ifdef WL_CELLULAR_CHAN_AVOID +success: + if (safe_success) { + p_chspec_list = safe_chspeclist; + parameter->freq_bands = safe_param.freq_bands; + parameter->scc_chspec = safe_param.scc_chspec; + freq_list_len = safe_chspec_cnt; + } else +#endif /* WL_CELLULAR_CHAN_AVOID */ + { + p_chspec_list = chspeclist; + } + + for (i = 0; i < freq_list_len; i++) { + if ((parameter->freq_bands & CHSPEC_TO_WLC_BAND(p_chspec_list[i])) == 0) { + WL_DBG(("Skipping no matched band channel(0x%x).\n", p_chspec_list[i])); + continue; + } + + wf_chspec_ntoa(p_chspec_list[i], chanspec_str); + WL_INFORM_MEM(("ACS : %s (0x%x)\n", chanspec_str, p_chspec_list[i])); + wl_cfgscan_acs_parse_parameter(cfg, req_len, pList, + p_chspec_list[i], parameter); + } + +exit: + MFREE(cfg->osh, chspeclist, list_size); +#ifdef WL_CELLULAR_CHAN_AVOID + MFREE(cfg->osh, safe_chspeclist, list_size); +#endif /* WL_CELLULAR_CHAN_AVOID */ + return ret; +} + +#define ACS_WORK_DELAY_US (100 * 1000) +#define ACS_WORK_CNT 5 +int +wl_cfgscan_acs(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int ret = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *net = wdev_to_ndev(wdev); + + int qty = 0, total = 0; + unsigned int *pElem_freq = NULL; + /* original HOSTAPD parameters */ + struct nlattr *tb[BRCM_VENDOR_ATTR_ACS_LAST + 1]; + drv_acs_params_t *parameter = NULL; +#ifdef WL_ACS_CHANLIST + int i = 0; + unsigned char *pElem_chan = NULL; + const struct nlattr *pChanList = NULL; +#endif /* WL_ACS_CHANLIST */ + const struct nlattr *pFreqList = NULL; + uint32 chan_list_len = 0, freq_list_len = 0; + /* converted list */ + wl_uint32_list_t *pReq = NULL; + uint32 *pList = NULL; + int req_len = 0; + chanspec_t ch_chosen = 0x0; + + if (!delay_work_acs.init_flag) { + delay_work_acs.ndev = net; + delay_work_acs.ch_chosen = 0; + INIT_DELAYED_WORK(&delay_work_acs.acs_delay_work, wl_cfgscan_acs_result_event); + delay_work_acs.init_flag = 1; + } + + do { + /* get orignal HOSTAPD paramters */ + if ( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) + nla_parse(tb, BRCM_VENDOR_ATTR_ACS_LAST, (struct nlattr *)data, + len, NULL, NULL) || +#else + nla_parse(tb, BRCM_VENDOR_ATTR_ACS_LAST, (struct nlattr *)data, + len, NULL) || +#endif + (!tb[BRCM_VENDOR_ATTR_ACS_HW_MODE])) { + WL_ERR(("***Error, parse fail\n")); + ret = BCME_BADARG; + break; + } + + parameter = &delay_work_acs.parameter; + (void)memset_s(parameter, sizeof(drv_acs_params_t), 0, sizeof(drv_acs_params_t)); + if (tb[BRCM_VENDOR_ATTR_ACS_HW_MODE]) { + parameter->hw_mode = nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_HW_MODE]); + WL_TRACE(("hw_mode=%d\n", parameter->hw_mode)); + } + if (tb[BRCM_VENDOR_ATTR_ACS_HT_ENABLED]) { + parameter->ht_enabled = nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_HT_ENABLED]); + WL_TRACE(("ht_enabled=%d\n", parameter->ht_enabled)); + } + if (tb[BRCM_VENDOR_ATTR_ACS_HT40_ENABLED]) { + parameter->ht40_enabled = nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_HT40_ENABLED]); + WL_TRACE(("ht40_enabled=%d\n", parameter->ht40_enabled)); + } + if (tb[BRCM_VENDOR_ATTR_ACS_VHT_ENABLED]) { + parameter->vht_enabled = nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_VHT_ENABLED]); + WL_TRACE(("vht_enabled=%d\n", parameter->vht_enabled)); + } + parameter->he_enabled = parameter->vht_enabled; + if (tb[BRCM_VENDOR_ATTR_ACS_CHWIDTH]) { + parameter->ch_width = nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_CHWIDTH]); + WL_TRACE(("ch_width=%d\n", parameter->ch_width)); + } + + if (tb[BRCM_VENDOR_ATTR_ACS_CH_LIST]) { +#ifdef WL_ACS_CHANLIST + pChanList = tb[BRCM_VENDOR_ATTR_ACS_CH_LIST]; + chan_list_len = nla_len(tb[BRCM_VENDOR_ATTR_ACS_CH_LIST]); + WL_TRACE(("chan_list_len=%d\n", chan_list_len)); +#else + WL_ERR(("chan_list attribute not supported\n")); +#endif /* WL_ACS_CHANLIST */ + } + if (tb[BRCM_VENDOR_ATTR_ACS_FREQ_LIST]) { + pFreqList = tb[BRCM_VENDOR_ATTR_ACS_FREQ_LIST]; + freq_list_len = nla_len(tb[BRCM_VENDOR_ATTR_ACS_FREQ_LIST]) / sizeof(int); + WL_TRACE(("freq_list_len=%d\n", freq_list_len)); + } + + switch (parameter->hw_mode) { + case HOSTAPD_MODE_IEEE80211B: + parameter->band = WLC_BAND_2G; + break; + case HOSTAPD_MODE_IEEE80211G: + parameter->band = WLC_BAND_2G; + break; + case HOSTAPD_MODE_IEEE80211A: + parameter->band = WLC_BAND_5G; + break; + case HOSTAPD_MODE_IEEE80211ANY: + parameter->band = WLC_BAND_AUTO; + break; + case HOSTAPD_MODE_IEEE80211AD: + /* 802.11ad 60G is 'dead' and not supported */ + default: + parameter->band = WLC_BAND_INVALID; + break; + } + WL_INFORM_MEM(("hw_mode=%d, band=%d ht_enabled:%d vht_enabled:%d ch_width:%d " + "parameter->he_enabled = %d\n", + parameter->hw_mode, parameter->band, parameter->ht_enabled, + parameter->vht_enabled, parameter->ch_width, parameter->he_enabled)); + if (WLC_BAND_INVALID == parameter->band) { + ret = BCME_BADARG; + WL_ERR(("*Error, hw_mode=%d based band invalid\n", + parameter->hw_mode)); + break; + } + + /* count memory requirement */ + qty = chan_list_len + freq_list_len; + total = sizeof(uint32) * qty * + (/* extra structure 'count' item */ + 1 + + /* maximum expand quantity of each channel: 20MHZ * 1, 40MHz * 2, + * 80MHz * 4, 160MHz * 8 + */ + (1 + 2 + 4 + 8)); + WL_TRACE(("qty=%d+%d=%d, total=%d\n", + chan_list_len, freq_list_len, qty, total)); + + if (total <= 0) { + ret = BCME_BADARG; + WL_ERR(("*Error, total number (%d) is invalid\n", total)); + break; + } + pReq = MALLOCZ(cfg->osh, total); + if (!pReq) { + WL_ERR(("*Error, no memory for %d bytes\n", total)); + ret = BCME_NOMEM; + break; + } else { + memset_s(pReq, total, 0, total); + pReq->count = req_len = 0; + pList = pReq->element; + } + +#ifdef WL_ACS_CHANLIST + /* process 'ch_list' for select list */ + pElem_chan = (unsigned char *)nla_data(pChanList); + if (pElem_chan) { + /* Applicable only for 2g or 5g band */ + if ((parameter->band == WLC_BAND_AUTO) || + (parameter->band == WLC_BAND_INVALID)) { + WL_ERR(("chanlist not applicable for band:%d\n", + parameter->band)); + break; + } + for (i = 0; i < chan_list_len; i++) { + /* TODO chanspec needs to be created */ + chanspec = pElem_chan[i]; + wl_cfgscan_acs_parse_parameter(cfg, &req_len, pList, + chanspec, parameter); + } + } + WL_TRACE(("list_len=%d after ch_list\n", req_len)); +#endif /* WL_ACS_CHANLIST */ + + /* process 'freq_list' */ + pElem_freq = (unsigned int *)nla_data(pFreqList); + if (pElem_freq) { +#ifdef WL_CELLULAR_CHAN_AVOID + ret = wl_cellavoid_set_requested_freq_bands(net, cfg->cellavoid_info, + pElem_freq, freq_list_len); + if (ret) { + WL_ERR(("Setting requested freq band failed, ret %d\n", ret)); + break; + } +#endif /* WL_CELLULAR_CHAN_AVOID */ + ret = wl_convert_freqlist_to_chspeclist(cfg, pElem_freq, freq_list_len, + &req_len, pList, parameter, qty); + if (ret) { + WL_ERR(("Freq conversion failed!\n")); + break; + } + } + WL_TRACE(("list_len=%d after freq_list\n", req_len)); + + pReq->count = req_len; + req_len = pReq->count * (sizeof(pReq->element[0])); + + WL_DBG(("set pReq->count=%d, with req_len=%d\n", + pReq->count, req_len)); + ret = wl_cfgscan_acs_do_apcs(net, parameter, &ch_chosen, total, + (unsigned char *)pReq, pReq->count, pList); + WL_DBG(("do acs ret=%d, ch_chosen=(0x%X)\n", + ret, ch_chosen)); + if (ret >= 0) { + u8 acs_work_cnt = ACS_WORK_CNT; + while (delayed_work_pending(&delay_work_acs.acs_delay_work)) { + if (acs_work_cnt) { + WL_INFORM(("acs_delay_work: wait_cnt:%d\n", acs_work_cnt)); + acs_work_cnt--; + OSL_DELAY(ACS_WORK_DELAY_US); + } else { + WL_INFORM_MEM(("ACS work time out. Force cancel.\n")); + break; + } + } + cancel_delayed_work_sync(&delay_work_acs.acs_delay_work); + delay_work_acs.ndev = net; + delay_work_acs.ch_chosen = ch_chosen; + schedule_delayed_work(&delay_work_acs.acs_delay_work, + msecs_to_jiffies((const unsigned int)50)); + WL_INFORM_MEM(("scheduled work for acs event (chspec:0x%X)\n", + ch_chosen)); + ret = 0; + } + + } while (0); + + /* free and clean up */ + if (NULL != pReq) { + WL_TRACE(("free the pReq=0x%p with total=%d\n", pReq, total)); + MFREE(cfg->osh, pReq, total); + } + +#ifdef WL_CELLULAR_CHAN_AVOID + /* This needs to be cleared in case of ACS failure */ + if (ret < 0) { + wl_cellavoid_clear_requested_freq_bands(net, cfg->cellavoid_info); + } +#endif /* WL_CELLULAR_CHAN_AVOID */ + + return ret; +} +#endif /* WL_SOFTAP_ACS */ + +void +wl_get_ap_chanspecs(struct bcm_cfg80211 *cfg, wl_ap_oper_data_t *ap_data) +{ + struct net_info *iter, *next; + u32 ch; + + bzero(ap_data, sizeof(wl_ap_oper_data_t)); + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + for_each_ndev(cfg, iter, next) { + GCC_DIAGNOSTIC_POP(); + if ((iter->ndev) && + (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) && + wl_get_drv_status(cfg, CONNECTED, iter->ndev)) { + if (wldev_iovar_getint(iter->ndev, "chanspec", (&ch)) == BCME_OK) { + ap_data->iface[ap_data->count].ndev = iter->ndev; + ap_data->iface[ap_data->count].chspec = (chanspec_t)ch; + ap_data->count++; + } + } + } +} + +bool wl_is_chanspec_restricted(struct bcm_cfg80211 *cfg, chanspec_t sta_chanspec) +{ + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + s32 ret = BCME_OK; + uint bitmap = 0; + u8 ioctl_buf[WLC_IOCTL_SMLEN]; + + bzero(ioctl_buf, WLC_IOCTL_SMLEN); + ret = wldev_iovar_getbuf(dev, "per_chan_info", + (void *)&sta_chanspec, sizeof(sta_chanspec), + ioctl_buf, WLC_IOCTL_SMLEN, NULL); + if (ret != BCME_OK) { + WL_ERR(("Failed to get per_chan_info chspec:0x%x, error:%d\n", + sta_chanspec, ret)); + return FALSE; + } + + bitmap = dtoh32(*(uint *)ioctl_buf); + if (bitmap & (WL_CHAN_PASSIVE | WL_CHAN_RADAR | + WL_CHAN_RESTRICTED | WL_CHAN_CLM_RESTRICTED)) { + WL_INFORM_MEM(("chanspec:0x%x is restricted by per_chan_info:0x%x\n", + sta_chanspec, bitmap)); + return TRUE; + } + + WL_INFORM_MEM(("STA chanspec:0x%x per_chan_info:0x%x\n", sta_chanspec, bitmap)); + return FALSE; +} + +static bool wl_find_matching_chanspec(chanspec_t sta_chanspec, + int qty, uint32 *pList) +{ + uint32 i = qty; + + if (!qty) { + WL_ERR(("Invalid qty\n")); + return false; + } + + while (i--) { + if (pList[i]) { + if (wf_chspec_ctlchspec((pList[i])) == wf_chspec_ctlchspec(sta_chanspec)) { + WL_INFORM_MEM(("Found sta chanspec in the list:0x%x\n", + sta_chanspec)); + return true; + } + WL_INFORM_MEM(("skipped chanspec:0x%x\n", pList[i])); + } + } + + return false; +} + +static bool +wl_acs_check_scc(struct bcm_cfg80211 *cfg, drv_acs_params_t *parameter, + chanspec_t sta_chanspec, int qty, uint32 *pList) +{ + bool scc = FALSE; + + if (!(parameter->freq_bands & CHSPEC_TO_WLC_BAND(sta_chanspec))) { + return scc; + } + + if (wl_find_matching_chanspec(sta_chanspec, qty, pList)) { + scc = TRUE; + } + +#ifdef DHD_ACS_CHECK_SCC_2G_ACTIVE_CH + /* + * For the corner case when STA is running in Ch12 or Ch13 + * and Framework may give the Ch [1-11] to ACS algorithm. + * In this case, SoftAP will be failed to run. + * To allow SoftAP to run in that channel as SCC mode, + * get active channels and check it + */ + if (scc == FALSE && CHSPEC_IS2G(sta_chanspec)) { +#ifdef WL_CELLULAR_CHAN_AVOID + scc = wl_cellavoid_operation_allowed(cfg->cellavoid_info, + sta_chanspec, NL80211_IFTYPE_AP); + if (scc == FALSE) { + WL_INFORM_MEM(("Not allow unsafe channel and mandatory chspec:0x%x\n", + sta_chanspec)); + } +#endif /* WL_CELLULAR_CHAN_AVOID */ + } +#endif /* DHD_ACS_CHECK_SCC_2G_ACTIVE_CH */ + + if (scc == TRUE) { + parameter->scc_chspec = sta_chanspec; + parameter->freq_bands = CHSPEC_TO_WLC_BAND(sta_chanspec); + WL_INFORM_MEM(("SCC case, ACS pick up STA chanspec:0x%x\n", sta_chanspec)); + } + return scc; +} + +int +wl_handle_acs_concurrency_cases(struct bcm_cfg80211 *cfg, drv_acs_params_t *parameter, + int qty, uint32 *pList) +{ + chanspec_t chspec = 0; + wl_ap_oper_data_t ap_oper_data = {0}; + + /* If STA is connected, figure out the STA connected band and applly + * following rules: + * If STA is in DFS channel or there is an AP already in that band, check + * whether the AP can be started in the other band + * If STA band and incoming Band matches, attempt SCC + */ + + /* Check whether AP is already operational */ + wl_get_ap_chanspecs(cfg, &ap_oper_data); + + if (ap_oper_data.count >= MAX_AP_IFACES) { + WL_ERR(("ACS request in multi AP case!! count:%d\n", + ap_oper_data.count)); + return -EINVAL; + } + + if (ap_oper_data.count == 1) { + chanspec_t ch = ap_oper_data.iface[0].chspec; + u16 ap_band; + + /* Single AP case. Bring up the AP in the other band */ + ap_band = CHSPEC_TO_WLC_BAND(ch); + if ((ap_band == WLC_BAND_5G) || (ap_band == WLC_BAND_6G)) { + WL_INFORM_MEM(("AP operational in band:%d\n", ap_band)); + if (!(parameter->freq_bands & WLC_BAND_2G)) { + WL_ERR(("2G band not present in ACS list. fail ACS\n")); + return -EINVAL; + } else { + /* Force set 2g and clear other bands for ACS */ + parameter->freq_bands = WLC_BAND_2G; + } + } else if (ap_band == WLC_BAND_2G) { + WL_INFORM_MEM(("AP operational in 2G band\n")); + if (!(parameter->freq_bands & WLC_BAND_5G) && + !(parameter->freq_bands & WLC_BAND_6G)) { + WL_ERR(("5G/6G freqs not available in the ACS list. FAIL ACS\n")); + return -EINVAL; + } else { + /* 6g/5g freqlist available. Clear 2g */ + parameter->freq_bands &= ~WLC_BAND_2G; + } + } + WL_INFORM_MEM(("AP band:0x%x Trimmed ACS band:0x%x\n", + ap_band, parameter->freq_bands)); + } + + /* Check STA concurrency cases */ + if (wl_cfgvif_get_iftype_count(cfg, WL_IF_TYPE_STA) >= 2) { + /* Dual sta operational. Invalid use case */ + WL_ERR(("Dual sta operational. ACS request not expected.\n")); + return -EINVAL; + } + + chspec = wl_cfg80211_get_sta_chanspec(cfg); + + if (chspec) { + bool scc_case = false; + u32 sta_band = CHSPEC_TO_WLC_BAND(chspec); + if (sta_band == WLC_BAND_2G) { + if (wl_is_chanspec_restricted(cfg, chspec) || + (parameter->freq_bands & (WLC_BAND_5G | WLC_BAND_6G))) { + /* Remove the 2g band from incoming ACS bands */ + parameter->freq_bands &= ~WLC_BAND_2G; + } else if (wl_acs_check_scc(cfg, parameter, chspec, qty, pList)) { + scc_case = TRUE; + } else { + WL_ERR(("STA connected in 2G," + " but no 2G channel available. Fail ACS\n")); + return -EINVAL; + } + } else if (sta_band == WLC_BAND_5G) { + if (wl_is_chanspec_restricted(cfg, chspec) || +#ifdef WL_UNII4_CHAN + IS_UNII4_CHANNEL(wf_chspec_primary20_chan(chspec)) || +#endif /* WL_UNII4_CHAN */ + FALSE) { + /* + * If STA is in DFS/Restricted/UNII4 channel, + * check for 2G availability in ACS list + */ + if (!(parameter->freq_bands & WLC_BAND_2G)) { + WL_ERR(("STA connected in 5G DFS." + " but no 2G channel available. Fail ACS\n")); + return -EINVAL; + } + /* Remove the 5g/6g band from incoming ACS bands */ + parameter->freq_bands &= ~(WLC_BAND_5G | WLC_BAND_6G); + } else if (wl_acs_check_scc(cfg, parameter, chspec, qty, pList)) { + scc_case = TRUE; + } else if (parameter->freq_bands & WLC_BAND_2G) { + parameter->freq_bands = WLC_BAND_2G; + } else { + WL_ERR(("STA connected in 5G %x, but no channel available " + "for ACS %x\n", chspec, parameter->freq_bands)); + return -EINVAL; + } + } else if (sta_band == WLC_BAND_6G) { + if (wl_acs_check_scc(cfg, parameter, chspec, qty, pList)) { + scc_case = TRUE; + } else if (parameter->freq_bands & WLC_BAND_2G) { + parameter->freq_bands = WLC_BAND_2G; + } else { + WL_ERR(("STA connected in 6G %x, but no channel available " + "for ACS %x\n", chspec, parameter->freq_bands)); + return -EINVAL; + } + } else { + WL_ERR(("Invalid sta band. Fail ACS\n")); + return -EINVAL; + } + + if (!scc_case) { + WL_INFORM_MEM(("sta_band:%d chanspec:0x%x." + " Attempt rsdb ACS for band/s:0x%x\n", + sta_band, chspec, parameter->freq_bands)); + } + } + return BCME_OK; +} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgscan.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgscan.h old mode 100755 new mode 100644 index d08f06b61c6e..2c6429f0c4da --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgscan.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgscan.h @@ -1,7 +1,7 @@ /* * Header for Linux cfg80211 scan * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -53,6 +53,15 @@ #define wl_escan_set_sync_id(a, b) ((a) = htod16((b)->escan_sync_id_cntr++)) #define wl_escan_set_type(a, b) #endif /* DUAL_ESCAN_RESULT_BUFFER */ + +#define SCAN_PARAMS_VER_2 2u +#define SCAN_PARAMS_VER_3 3u +/* SCAN_PARAMS V3 and V2 have same size. so use V3 with appriate version param */ +#define IS_SCAN_PARAMS_V3_V2(cfg) (((cfg->scan_params_ver == SCAN_PARAMS_VER_3) || \ + (cfg->scan_params_ver == SCAN_PARAMS_VER_2)) ? TRUE : FALSE) +#define IS_SCAN_PARAMS_V3(cfg) ((cfg->scan_params_ver == SCAN_PARAMS_VER_3) ? \ + TRUE : FALSE) + extern s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); extern s32 wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, @@ -89,6 +98,17 @@ extern s32 wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cf const wl_event_msg_t *e, void *data); #endif /* GSCAN_SUPPORT */ +#ifdef WL_SCHED_SCAN +extern s32 wl_cfgscan_pfn_scanresult_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +extern s32 wl_cfgscan_pfn_handler(struct bcm_cfg80211 *cfg, + wl_pfn_scanresult_v3_1_t *pfn_scanresult); +#endif /* WL_SCHED_SCAN */ + +#if defined(GSCAN_SUPPORT) || defined(WL_SCHED_SCAN) +extern s32 wl_cfgscan_notify_pfn_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +#endif /* GSCAN_SUPPORT || WL_SCHED_SCAN */ #ifdef WES_SUPPORT #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING #define CUSTOMER_WL_SCAN_TIMER_INTERVAL_MS 25000 /* Scan timeout */ @@ -138,15 +158,20 @@ extern s32 wl_cfgscan_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev * extern s32 wl_cfgscan_cancel_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, u64 cookie); extern chanspec_t wl_freq_to_chanspec(int freq); -extern s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool update_ssid); +extern s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_v109_t *bi, bool update_ssid); #ifdef WL_GET_RCC extern int wl_android_get_roam_scan_chanlist(struct bcm_cfg80211 *cfg); +extern int wl_android_get_roam_scan_freqlist(struct bcm_cfg80211 *cfg); #endif /* WL_GET_RCC */ extern s32 wl_get_assoc_channels(struct bcm_cfg80211 *cfg, struct net_device *dev, wlcfg_assoc_info_t *info); extern void wl_cfgscan_cancel_scan(struct bcm_cfg80211 *cfg); extern void wl_cfgscan_scan_abort(struct bcm_cfg80211 *cfg); -#ifdef DHD_GET_VALID_CHANNELS + +#define APCS_DEFAULT_2G_FREQ 2437u +#define APCS_DEFAULT_5G_FREQ 5745u +#define APCS_DEFAULT_6G_FREQ 5975u + typedef enum { WIFI_BAND_UNSPECIFIED, /* 2.4 GHz */ @@ -172,10 +197,35 @@ typedef enum { } wifi_band; extern bool wl_cfgscan_is_dfs_set(wifi_band band); -extern s32 wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, int band, - uint16 *list, uint32 *num_channels); -#endif /* DHD_GET_VALID_CHANNELS */ -#if defined (WL_SCHED_SCAN) && defined (SCHED_SCAN_DELAYED_WORK) +extern s32 wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, + struct wireless_dev *wdev, int band, uint32 *list, uint32 *num_channels); +#define MAX_AP_IFACES 2 +typedef struct ap_iface_data { + chanspec_t chspec; + struct net_device *ndev; +} wl_ap_iface_data_t; + +typedef struct ap_oper_data { + u8 count; + wl_ap_iface_data_t iface[MAX_AP_IFACES]; +} wl_ap_oper_data_t; + +extern void wl_get_ap_chanspecs(struct bcm_cfg80211 *cfg, wl_ap_oper_data_t *ap_data); + +extern int wl_android_get_sta_channel(struct bcm_cfg80211 *cfg); +extern int wl_handle_acs_concurrency_cases(struct bcm_cfg80211 *cfg, + drv_acs_params_t *parameter, int qty, uint32 *pList); +#ifdef WL_SCHED_SCAN extern void wl_cfgscan_sched_scan_stop_work(struct work_struct *work); #endif /* WL_SCHED_SCAN */ +#ifdef WL_SOFTAP_ACS +extern bool wl_is_chanspec_restricted(struct bcm_cfg80211 *cfg, chanspec_t chspec); +#endif /* WL_SOFTAP_ACS */ +#ifdef ESCAN_CHANNEL_CACHE +void reset_roam_cache(struct bcm_cfg80211 *cfg); +void add_roam_cache(struct bcm_cfg80211 *cfg, wl_bss_info_v109_t *bi); +int get_roam_channel_list(struct bcm_cfg80211 *cfg, chanspec_t target_chan, chanspec_t *channels, + int n_channels, const wlc_ssid_t *ssid, int ioctl_ver); +void set_roam_band(int band); +#endif /* ESCAN_CHANNEL_CACHE */ #endif /* _wl_cfgscan_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c old mode 100755 new mode 100644 index fa08b8f44e18..9b19314c4e1f --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 Vendor Extension Code * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -69,6 +69,7 @@ #include #include #include +#include #include #include @@ -77,6 +78,7 @@ #include #include #include +#include #ifdef WL_NAN #include #endif /* WL_NAN */ @@ -91,6 +93,73 @@ #endif #include +#ifdef WL_CELLULAR_CHAN_AVOID +#include +#endif /* WL_CELLULAR_CHAN_AVOID */ + +#ifdef WL_CFGVENDOR_CUST_ADVLOG +static void wl_cfgvendor_custom_advlog_scan_start(void *plog, uint32 armcycle); +static void wl_cfgvendor_custom_advlog_scan_cmpl(void *plog, uint32 armcycle); +static void wl_cfgvendor_custom_advlog_roam_cmpl(void *plog, uint32 armcycle); +static void wl_cfgvendor_custom_advlog_btm_req(void *plog, uint32 armcycle); +static void wl_cfgvendor_custom_advlog_btm_resp(void *plog, uint32 armcycle); +static void wl_cfgvendor_custom_advlog_btm_wtc(void *plog, uint32 armcycle); +static void wl_cfgvendor_custom_advlog_btm_query(void *plog, uint32 armcycle); + +typedef void (*print_advlog_func)(void *log, uint32 armcycle); +typedef struct _pr_advlog_tbl { + uint8 id; + print_advlog_func advlog_func; +} pr_advlog_tbl_t; + +typedef struct dhd_covt_roam_rsn { + uint roam_rsn; + uint cust_roam_rsn; +} dhd_covt_roam_rsn_t; + +typedef enum { + WL_CUST_ROAM_REASON_UNKNOWN = 0, + WL_CUST_ROAM_REASON_LOW_RSSI, + WL_CUST_ROAM_REASON_LOW_RSSI_CU, + WL_CUST_ROAM_REASON_BCNS_LOST, + WL_CUST_ROAM_REASON_EMERG_ROAM, + WL_CUST_ROAM_REASON_BTM_REQ, + WL_CUST_ROAM_REASON_IDLE_ROAM, + WL_CUST_ROAM_REASON_WTC, + WL_CUST_ROAM_REASON_INACTIVITY, + WL_CUST_ROAM_REASON_SCAN_TIMEOUT, + WL_CUST_ROAM_REASON_BTCOEX, + WL_CUST_ROAM_REASON_MAX +} cust_roam_reason_t; + +static dhd_covt_roam_rsn_t dhd_covt_roam_rsn_list[] = +{ + {WLC_E_REASON_INITIAL_ASSOC, WL_CUST_ROAM_REASON_UNKNOWN}, + {WLC_E_REASON_LOW_RSSI, WL_CUST_ROAM_REASON_LOW_RSSI}, + {WLC_E_REASON_DEAUTH, WL_CUST_ROAM_REASON_EMERG_ROAM}, + {WLC_E_REASON_DISASSOC, WL_CUST_ROAM_REASON_EMERG_ROAM}, + {WLC_E_REASON_BCNS_LOST, WL_CUST_ROAM_REASON_BCNS_LOST}, + {WLC_E_REASON_BSSTRANS_REQ, WL_CUST_ROAM_REASON_BTM_REQ}, + {WLC_E_REASON_LOW_RSSI_CU, WL_CUST_ROAM_REASON_LOW_RSSI_CU}, + {WLC_E_REASON_SILENT_ROAM, WL_CUST_ROAM_REASON_IDLE_ROAM}, + {WLC_E_REASON_INACTIVITY, WL_CUST_ROAM_REASON_INACTIVITY}, + {WLC_E_REASON_ROAM_SCAN_TIMEOUT, WL_CUST_ROAM_REASON_SCAN_TIMEOUT}, + {WLC_E_REASON_BTCX_ROAM, WL_CUST_ROAM_REASON_BTCOEX} +}; + +static const pr_advlog_tbl_t advlog_print_tbl[] = +{ + {ROAM_LOG_SCANSTART, wl_cfgvendor_custom_advlog_scan_start}, + {ROAM_LOG_SCAN_CMPLT, wl_cfgvendor_custom_advlog_scan_cmpl}, + {ROAM_LOG_ROAM_CMPLT, wl_cfgvendor_custom_advlog_roam_cmpl}, + {ROAM_LOG_BTM_REP, wl_cfgvendor_custom_advlog_btm_resp}, + {ROAM_LOG_WTC_BTM_REP, wl_cfgvendor_custom_advlog_btm_wtc}, + {ROAM_LOG_BTM_QUERY, wl_cfgvendor_custom_advlog_btm_query}, + {ROAM_LOG_BTM_REQ, wl_cfgvendor_custom_advlog_btm_req}, + {PRSV_PERIODIC_ID_MAX, NULL} +}; +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ + char* wl_get_kernel_timestamp(void) { @@ -197,6 +266,55 @@ wl_cfgvendor_notify_supp_event_str(const char *evt_name, const char *fmt, ...) return wl_cfgvendor_send_async_event(wiphy, bcmcfg_to_prmry_ndev(cfg), BRCM_VENDOR_EVENT_PRIV_STR, buf, len); } + +#ifdef WL_CFGVENDOR_CUST_ADVLOG +int +wl_cfgvendor_send_supp_advlog(const char *fmt, ...) +{ + char buf[SUPP_LOG_LEN] = {0}; + struct bcm_cfg80211 *cfg; + struct wiphy *wiphy; + va_list args; + int len; + int prefix_len; + int rem_len; + + cfg = wl_cfg80211_get_bcmcfg(); + if (!cfg || !cfg->wdev) { + WL_DBG(("supp evt invalid arg\n")); + return BCME_OK; + } + + wiphy = cfg->wdev->wiphy; + prefix_len = snprintf(buf, SUPP_LOG_LEN, "[%s]", + wl_get_kernel_timestamp()); + /* Remaining buffer len */ + rem_len = SUPP_LOG_LEN - (prefix_len + 1); + /* Print the arg list on to the remaining part of the buffer */ + va_start(args, fmt); + len = vsnprintf((buf + prefix_len), rem_len, fmt, args); + va_end(args); + if (len < 0) { + return -EINVAL; + } + + if (len > rem_len) { + /* If return length is greater than buffer len, + * then its truncated buffer case. + */ + len = rem_len; + } + + /* Ensure the buffer is null terminated */ + len += prefix_len; + buf[len] = '\0'; + len++; + + return wl_cfgvendor_send_async_event(wiphy, + bcmcfg_to_prmry_ndev(cfg), BRCM_VENDOR_EVENT_CONNECTIVITY_LOG, + buf, len); +} +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ #endif /* WL_SUPP_EVENT */ /* @@ -215,7 +333,7 @@ int wl_cfgvendor_send_async_event(struct wiphy *wiphy, /* Alloc the SKB for vendor_event */ #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \ - LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(dev), len, event_id, kflags); #else skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags); @@ -355,6 +473,7 @@ wl_cfgvendor_set_rand_mac_oui(struct wiphy *wiphy, exit: return err; } + #ifdef CUSTOM_FORCE_NODFS_FLAG static int wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy, @@ -411,12 +530,25 @@ wl_cfgvendor_set_country(struct wiphy *wiphy, return err; } } + /* country code is unique for dongle..hence using primary interface. */ err = wl_cfg80211_set_country_code(primary_ndev, country_code, true, true, 0); if (err < 0) { WL_ERR(("Set country failed ret:%d\n", err)); + goto exit; } - +#ifdef OEM_ANDROID +#ifdef FCC_PWR_LIMIT_2G + err = wldev_iovar_setint(primary_ndev, "fccpwrlimit2g", FALSE); + if (err < 0) { + WL_ERR(("fccpwrlimit2g deactivation is failed\n")); + goto exit; + } else { + WL_ERR(("fccpwrlimit2g is deactivated\n")); + } +#endif /* FCC_PWR_LIMIT_2G */ +#endif /* OEM_ANDROID */ +exit: return err; } @@ -445,7 +577,7 @@ wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, /* Alloc the SKB for vendor_event */ #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \ - LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(dev), malloc_len, event, kflags); #else @@ -469,7 +601,11 @@ wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, iter_cnt_to_send -= cnt; cache->tot_consumed += cnt; /* Push the data to the skb */ +#ifdef ANDROID13_KERNEL515_BKPORT + nla_put_nohdr(skb, cnt * sizeof(wifi_gscan_result_t), ptr); +#else nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr); +#endif if (cache->tot_consumed == cache->tot_count) { cache = cache->next; } @@ -1203,14 +1339,14 @@ wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy, } #endif /* GSCAN_SUPPORT */ -#if defined (GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) +#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) static int wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { int err = 0, type, band; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - uint16 *reply = NULL; + uint32 *reply = NULL; uint32 reply_len = 0, num_channels, mem_needed; struct sk_buff *skb; dhd_pub_t *dhdp; @@ -1249,7 +1385,8 @@ wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy, WL_ERR(("failed to allocate chanspec buffer\n")); return -ENOMEM; } - err = wl_cfgscan_get_band_freq_list(cfg, band, reply, &num_channels); + + err = wl_cfgscan_get_band_freq_list(cfg, wdev, band, reply, &num_channels); if (err != BCME_OK && err != BCME_UNSUPPORTED) { WL_ERR(("%s: failed to get valid channel list\n", __FUNCTION__)); @@ -1258,6 +1395,7 @@ wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy, } else if (err == BCME_OK) { reply_len = (num_channels * sizeof(uint32)); } else if (err == BCME_UNSUPPORTED) { + MFREE(cfg->osh, reply, CHANINFO_LIST_BUF_SIZE); reply = dhd_pno_get_gscan(dhdp, DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len); if (!reply) { @@ -1289,7 +1427,7 @@ exit: MFREE(cfg->osh, reply, CHANINFO_LIST_BUF_SIZE); return err; } -#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ +#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ #ifdef RSSI_MONITOR_SUPPORT static int wl_cfgvendor_set_rssi_monitor(struct wiphy *wiphy, @@ -1299,8 +1437,15 @@ static int wl_cfgvendor_set_rssi_monitor(struct wiphy *wiphy, struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); int8 max_rssi = 0, min_rssi = 0; const struct nlattr *iter; + struct net_device *ndev = wdev_to_ndev(wdev); - if (!wl_get_drv_status(cfg, CONNECTED, wdev_to_ndev(wdev))) { + /* Limit rssi monitoring only on primary interface */ + if (!IS_INET_LINK_NDEV(cfg, ndev)) { + WL_ERR(("rssi monitor query requested on non primary interface\n")); + return BCME_UNSUPPORTED; + } + + if (!wl_get_drv_status(cfg, CONNECTED, ndev)) { WL_ERR(("Sta is not connected to an AP, rssi monitoring is not allowed\n")); return -EINVAL; } @@ -1319,8 +1464,7 @@ static int wl_cfgvendor_set_rssi_monitor(struct wiphy *wiphy, } } - if (dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg), - start, max_rssi, min_rssi) < 0) { + if (dhd_dev_set_rssi_monitor_cfg(ndev, start, max_rssi, min_rssi) < 0) { WL_ERR(("Could not set rssi monitor cfg\n")); err = -EINVAL; } @@ -1336,9 +1480,14 @@ wl_cfgvendor_get_wake_reason_stats(struct wiphy *wiphy, struct net_device *ndev = wdev_to_ndev(wdev); wake_counts_t *pwake_count_info; int ret, mem_needed; -#if defined(DHD_DEBUG) && defined(DHD_WAKE_EVENT_STATUS) +#if defined(DHD_WAKE_EVENT_STATUS) int flowid; -#endif /* DHD_DEBUG && DHD_WAKE_EVENT_STATUS */ +#ifdef CUSTOM_WAKE_REASON_STATS + int tmp_rc_event[MAX_WAKE_REASON_STATS]; + int rc_event_used_cnt = 0; + int front = 0; +#endif /* CUSTOM_WAKE_REASON_STATS */ +#endif /* DHD_WAKE_EVENT_STATUS */ struct sk_buff *skb = NULL; dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev); @@ -1356,29 +1505,66 @@ wl_cfgvendor_get_wake_reason_stats(struct wiphy *wiphy, } #ifdef DHD_WAKE_EVENT_STATUS WL_ERR(("pwake_count_info->rcwake %d\n", pwake_count_info->rcwake)); +#ifdef CUSTOM_WAKE_REASON_STATS + ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW, 0); + if (unlikely(ret)) { + WL_ERR(("Failed to put total count of driver fw\n")); + goto exit; + } +#endif /* CUSTOM_WAKE_REASON_STATS */ ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT, pwake_count_info->rcwake); if (unlikely(ret)) { WL_ERR(("Failed to put Total count of CMD event, ret=%d\n", ret)); goto exit; } - ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT_USED, WLC_E_LAST); +#ifdef CUSTOM_WAKE_REASON_STATS + front = pwake_count_info->rc_event_idx - 1; + for (flowid = 0; flowid < MAX_WAKE_REASON_STATS; flowid++) { + /* Reorder the rc_event, the latest event in the header index */ + if (front < 0) { + front = MAX_WAKE_REASON_STATS - 1; + } + if (pwake_count_info->rc_event[front] != -1) { + rc_event_used_cnt++; + } + tmp_rc_event[flowid] = pwake_count_info->rc_event[front]; + front--; + } + + ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT_USED, rc_event_used_cnt); +#endif /* CUSTOM_WAKE_REASON_STATS */ if (unlikely(ret)) { WL_ERR(("Failed to put Max count of event used, ret=%d\n", ret)); goto exit; } +#ifdef CUSTOM_WAKE_REASON_STATS + ret = nla_put(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE, + (MAX_WAKE_REASON_STATS * sizeof(int)), tmp_rc_event); +#else ret = nla_put(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE, (WLC_E_LAST * sizeof(uint)), pwake_count_info->rc_event); +#endif /* CUSTOM_WAKE_REASON_STATS */ if (unlikely(ret)) { WL_ERR(("Failed to put Event wake data, ret=%d\n", ret)); goto exit; } + #ifdef DHD_DEBUG +#ifdef CUSTOM_WAKE_REASON_STATS + for (flowid = 0; flowid < MAX_WAKE_REASON_STATS; flowid++) { + if (pwake_count_info->rc_event[flowid] != -1) { + WL_INFORM(("Event ID %u = %s\n", pwake_count_info->rc_event[flowid], + bcmevent_get_name(pwake_count_info->rc_event[flowid]))); + } + } +#else for (flowid = 0; flowid < WLC_E_LAST; flowid++) { if (pwake_count_info->rc_event[flowid] != 0) { WL_ERR((" %s = %u\n", bcmevent_get_name(flowid), pwake_count_info->rc_event[flowid])); } } +#endif /* CUSTOM_WAKE_REASON_STATS */ #endif /* DHD_DEBUG */ #endif /* DHD_WAKE_EVENT_STATUS */ #ifdef DHD_WAKE_RX_STATUS @@ -1403,7 +1589,7 @@ wl_cfgvendor_get_wake_reason_stats(struct wiphy *wiphy, WL_ERR(("Failed to put Total wake due to RX broadcast, ret=%d\n", ret)); goto exit; } - ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT, pwake_count_info->rx_arp); + ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT, pwake_count_info->rx_icmp); if (unlikely(ret)) { WL_ERR(("Failed to put Total wake due to ICMP pkt, ret=%d\n", ret)); goto exit; @@ -1516,6 +1702,7 @@ wl_cfgvendor_notify_dump_completion(struct wiphy *wiphy, /* call wmb() to synchronize with the previous memory operations */ OSL_SMP_WMB(); DHD_BUS_BUSY_CLEAR_IN_HALDUMP(dhd_pub); + dhd_set_dump_status(dhd_pub, DUMP_READY); /* Call another wmb() to make sure wait_for_dump_completion value * gets updated before waking up waiting context. */ @@ -1561,8 +1748,10 @@ wl_cfgvendor_set_hal_started(struct wiphy *wiphy, struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); #ifdef WL_STA_ASSOC_RAND struct ether_addr primary_mac; - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); #endif /* WL_STA_ASSOC_RAND */ +#if defined(WL_STA_ASSOC_RAND) || defined(DHD_FILE_DUMP_EVENT) + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); +#endif /* WL_STA_ASSOC_RAND || DHD_FILE_DUMP_EVENT */ int ret = BCME_OK; #if defined(WIFI_TURNON_USE_HALINIT) struct net_device *ndev = wdev_to_wlc_ndev(wdev, cfg); @@ -1598,6 +1787,9 @@ wl_cfgvendor_set_hal_started(struct wiphy *wiphy, WL_INFORM(("%s,[DUMP] HAL STARTED\n", __FUNCTION__)); cfg->hal_started = true; +#ifdef DHD_FILE_DUMP_EVENT + dhd_set_dump_status(dhd, DUMP_READY); +#endif /* DHD_FILE_DUMP_EVENT */ #ifdef WL_STA_ASSOC_RAND /* If mac randomization is enabled and primary macaddress is not * randomized, randomize it from HAL init context @@ -1621,9 +1813,16 @@ wl_cfgvendor_stop_hal(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); +#ifdef DHD_FILE_DUMP_EVENT + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); +#endif /* DHD_FILE_DUMP_EVENT */ + WL_INFORM(("%s,[DUMP] HAL STOPPED\n", __FUNCTION__)); cfg->hal_started = false; +#ifdef DHD_FILE_DUMP_EVENT + dhd_set_dump_status(dhd, DUMP_NOT_READY); +#endif /* DHD_FILE_DUMP_EVENT */ return BCME_OK; } #endif /* WL_CFG80211 */ @@ -1639,9 +1838,6 @@ wl_cfgvendor_set_latency_mode(struct wiphy *wiphy, #ifdef SUPPORT_LATENCY_CRITICAL_DATA bool enable; #endif /* SUPPORT_LATENCY_CRITICAL_DATA */ -#ifdef WL_AUTO_QOS - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev); -#endif /* WL_AUTO_QOS */ nla_for_each_attr(iter, data, len, rem) { type = nla_type(iter); @@ -1650,10 +1846,6 @@ wl_cfgvendor_set_latency_mode(struct wiphy *wiphy, latency_mode = nla_get_u32(iter); WL_DBG(("%s,Setting latency mode %u\n", __FUNCTION__, latency_mode)); -#ifdef WL_AUTO_QOS - /* Enable/Disable qos monitoring */ - dhd_wl_sock_qos_set_status(dhdp, latency_mode); -#endif /* WL_AUTO_QOS */ #ifdef SUPPORT_LATENCY_CRITICAL_DATA enable = latency_mode ? true : false; err = wldev_iovar_setint(wdev->netdev, @@ -1677,6 +1869,43 @@ wl_cfgvendor_set_latency_mode(struct wiphy *wiphy, #endif /* WL_LATENCY_MODE */ #ifdef RTT_SUPPORT +bool wl_check_wdev(struct wireless_dev *wdev) +{ + struct bcm_cfg80211 *cfg = NULL; + cfg = wl_cfg80211_get_bcmcfg(); + + if (!wdev) { + WL_ERR(("wdev is null\n")); + return BCME_ERROR; + } + + /* g_bcmcfg is set when the primary interface up + * compare the wdev as parameter with g_bcmcfg->wdev + * to detect whether the wdev is corrupted or not + */ + if (!cfg) { + WL_ERR(("cfg is null\n")); + return BCME_ERROR; + } + + if (!cfg->wdev) { + WL_ERR(("cfg->wdev is null\n")); + return BCME_ERROR; + } + + /* if the wdev param is valid address it will print and hexdump */ + if (cfg->wdev->wiphy != wdev->wiphy) { + WL_ERR(("wiphy is not the same with wiphy " + "cfg->wdev:%px wdev:%px " + "cfg->wdev->wiphy:%px wdev->wiphy:%px\n", + cfg->wdev, wdev, cfg->wdev->wiphy, wdev->wiphy)); + prhex("wdev hexdump", (const u8 *)wdev, sizeof(struct wireless_dev)); + return BCME_ERROR; + } + + return BCME_OK; +} + void wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data) { @@ -1693,16 +1922,27 @@ wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data) wiphy = wdev->wiphy; WL_DBG(("In\n")); + if (wl_check_wdev(wdev)) { + WL_ERR(("Invalid wdev\n")); + return; + } + /* Push the data to the skb */ if (!rtt_data) { WL_ERR(("rtt_data is NULL\n")); return; } rtt_cache_list = (struct list_head *)rtt_data; + + if (!wiphy) { + WL_ERR(("wiphy is NULL\n")); + return; + } + kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; if (list_empty(rtt_cache_list)) { #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \ - LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) skb = cfg80211_vendor_event_alloc(wiphy, NULL, 100, GOOGLE_RTT_COMPLETE_EVENT, kflags); #else @@ -1726,7 +1966,7 @@ wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data) list_for_each_entry(rtt_header, rtt_cache_list, list) { /* Alloc the SKB for vendor_event */ #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \ - LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) skb = cfg80211_vendor_event_alloc(wiphy, NULL, rtt_header->result_tot_len + 100, GOOGLE_RTT_COMPLETE_EVENT, kflags); #else @@ -1764,8 +2004,62 @@ wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data) goto free_mem; } list_for_each_entry(rtt_result, &rtt_header->result_list, list) { - ret = nla_put(skb, RTT_ATTRIBUTE_RESULT, - rtt_result->report_len, &rtt_result->report); +#ifdef WL_RTT_LCI + WL_DBG(("rtt_result report len=%d(%lu)\n", + rtt_result->report_len, RTT_REPORT_SIZE)); + if (rtt_result->report_len > RTT_REPORT_SIZE) { + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int msize = rtt_result->report_len; + char *mbuf; + int plen; + char *pdata; + + mbuf = (char *)MALLOCZ(cfg->osh, msize); + if (!mbuf) { + WL_ERR(("Failed to malloc buf for LCI/LCR, len(%d)\n", + msize)); + goto free_mem; + } + pdata = mbuf; + plen = msize; + (void) memcpy_s(pdata, plen, &rtt_result->report, RTT_REPORT_SIZE); + pdata += RTT_REPORT_SIZE; + plen -= RTT_REPORT_SIZE; + if (rtt_result->report.LCI) { + bcm_tlv_t *tlv = rtt_result->report.LCI; + int tlv_size = BCM_TLV_SIZE(tlv); + if (tlv_size > plen) { + WL_ERR(("LCI IE size error, len %d(%d)\n", + tlv_size, plen)); + } else { + (void) memcpy_s(pdata, plen, (char*)tlv, tlv_size); + pdata += tlv_size; + plen -= tlv_size; + WL_INFORM_MEM(("copy LCI, len=%d\n", tlv_size)); + } + } + if (rtt_result->report.LCR) { + bcm_tlv_t *tlv = rtt_result->report.LCR; + int tlv_size = BCM_TLV_SIZE(tlv); + if (tlv_size > plen) { + WL_ERR(("LCR IE size error, len %d(%d)\n", + tlv_size, plen)); + } else { + (void) memcpy_s(pdata, plen, (char*)tlv, tlv_size); + pdata += tlv_size; + plen -= tlv_size; + WL_INFORM_MEM(("copy LCR, len=%d\n", tlv_size)); + } + } + ret = nla_put(skb, RTT_ATTRIBUTE_RESULT, msize - plen, mbuf); + MFREE(cfg->osh, mbuf, msize); + } else +#endif /* WL_RTT_LCI */ + { + ret = nla_put(skb, RTT_ATTRIBUTE_RESULT, + rtt_result->report_len, &rtt_result->report); + } + if (ret < 0) { WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT, ret:%d\n", ret)); goto free_mem; @@ -1792,6 +2086,31 @@ free_mem: } } +static void +wl_cfgvendor_rtt_sort_targets(rtt_config_params_t *rtt_param) +{ + uint8 target_count = rtt_param->rtt_target_cnt; + rtt_target_info_t *rtt_target = rtt_param->target_info; + uint8 i, j; + uint8 min_index; + rtt_target_info_t rtt_tmp_target; + + for (i = 0; i < (target_count - 1); i++) { + min_index = i; + for (j = i+1; j < target_count; j++) { + if (rtt_target[min_index].chanspec > rtt_target[j].chanspec) { + min_index = j; + } + } + if (i != min_index) { + /* swap */ + rtt_tmp_target = rtt_target[i]; + rtt_target[i] = rtt_target[min_index]; + rtt_target[min_index] = rtt_tmp_target; + } + } +} + static int wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { @@ -1808,6 +2127,11 @@ wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, bzero(&rtt_param, sizeof(rtt_param)); WL_DBG(("In\n")); + if (wl_check_wdev(wdev)) { + WL_ERR(("Invalid wdev\n")); + goto exit; + } + err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt); if (err < 0) { WL_ERR(("failed to register rtt_noti_callback\n")); @@ -1942,7 +2266,7 @@ wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, rtt_target->LCI_request = nla_get_u8(iter2); break; case RTT_ATTRIBUTE_TARGET_LCR: - rtt_target->LCI_request = nla_get_u8(iter2); + rtt_target->LCR_request = nla_get_u8(iter2); break; case RTT_ATTRIBUTE_TARGET_BURST_DURATION: if ((nla_get_u32(iter2) > 1 && @@ -1971,12 +2295,12 @@ wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, /* convert to chanspec value */ rtt_target->chanspec = dhd_rtt_convert_to_chspec(rtt_target->channel); - if (rtt_target->chanspec == 0) { + if (rtt_target->chanspec == INVCHANSPEC) { WL_ERR(("Channel is not valid \n")); err = -EINVAL; goto exit; } - WL_INFORM_MEM(("Target addr %s, Channel : %s for RTT \n", + WL_MEM(("Target addr %s, Channel : %s for RTT \n", bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr, eabuf), wf_chspec_ntoa(rtt_target->chanspec, chanbuf))); @@ -1986,6 +2310,8 @@ wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, } } WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt)); + /* sort targets */ + wl_cfgvendor_rtt_sort_targets(&rtt_param); if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) { WL_ERR(("Could not set RTT configuration\n")); err = -EINVAL; @@ -2103,6 +2429,7 @@ wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev, exit: return err; } + static int get_responder_info(struct bcm_cfg80211 *cfg, struct wifi_rtt_responder *responder_info) @@ -2128,6 +2455,7 @@ get_responder_info(struct bcm_cfg80211 *cfg, } return err; } + static int wl_cfgvendor_rtt_get_responder_info(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) @@ -2315,7 +2643,7 @@ wl_cfgvendor_set_bssid_pref(struct wiphy *wiphy, switch (type) { case GSCAN_ATTRIBUTE_NUM_BSSID: if (num) { - WL_ERR(("attempt overide bssid num.\n")); + WL_ERR(("attempt override bssid num.\n")); err = -EINVAL; goto exit; } @@ -2432,6 +2760,7 @@ exit: return err; } #endif /* GSCAN_SUPPORT */ + #if defined(GSCAN_SUPPORT) || defined(ROAMEXP_SUPPORT) static int wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy, @@ -2676,10 +3005,8 @@ exit: #ifdef ROAMEXP_SUPPORT typedef enum { - FW_ROAMING_ENABLE = 1, FW_ROAMING_DISABLE, - FW_ROAMING_PAUSE, - FW_ROAMING_RESUME + FW_ROAMING_ENABLE } fw_roaming_state_t; static int @@ -2689,6 +3016,8 @@ wl_cfgvendor_set_fw_roaming_state(struct wiphy *wiphy, fw_roaming_state_t requested_roaming_state; int type; int err = 0; + wl_roam_conf_t roam_req; + struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev)); if (!data) { WL_ERR(("data is not available\n")); @@ -2710,16 +3039,19 @@ wl_cfgvendor_set_fw_roaming_state(struct wiphy *wiphy, requested_roaming_state = nla_get_u32(data); WL_INFORM(("setting FW roaming state to %d\n", requested_roaming_state)); - if ((requested_roaming_state == FW_ROAMING_ENABLE) || - (requested_roaming_state == FW_ROAMING_RESUME)) { - err = wldev_iovar_setint(wdev_to_ndev(wdev), "roam_off", FALSE); - } else if ((requested_roaming_state == FW_ROAMING_DISABLE) || - (requested_roaming_state == FW_ROAMING_PAUSE)) { - err = wldev_iovar_setint(wdev_to_ndev(wdev), "roam_off", TRUE); + if (requested_roaming_state == FW_ROAMING_ENABLE) { + roam_req = ROAM_CONF_ROAM_ENAB_REQ; + } else if (requested_roaming_state == FW_ROAMING_DISABLE) { + roam_req = ROAM_CONF_ROAM_DISAB_REQ; } else { - err = -EINVAL; + WL_ERR(("unexpected roam_state_request:%d\n", requested_roaming_state)); + return -EINVAL; } + wl_cfgvif_roam_config(cfg, wdev->netdev, roam_req); + + ROAMOFF_DBG_SAVE(wdev_to_ndev(wdev), SET_ROAM_VNDR_POLICY, !cfg->disable_fw_roam); + return err; } @@ -2808,7 +3140,7 @@ wl_cfgvendor_priv_string_handler(struct wiphy *wiphy, ret = dhd_cfgvendor_priv_string_handler(cfg, wdev, nlioc, buf); if (ret) { - WL_ERR(("dhd_cfgvendor returned error %d", ret)); + WL_ERR(("dhd_cfgvendor returned error %d\n", ret)); vfree(buf); return ret; } @@ -3009,7 +3341,7 @@ wl_cfgvendor_start_ap_params_handler(struct wiphy *wiphy, return ret; } -#if defined(WL_SAE) || defined(WL_CLIENT_SAE) +#if defined(WL_SAE) static int wl_cfgvendor_set_sae_password(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) @@ -3020,11 +3352,7 @@ wl_cfgvendor_set_sae_password(struct wiphy *wiphy, wsec_pmk_t pmk; s32 bssidx; -/* This api not needed for wpa_supplicant based sae authentication */ -#ifdef WL_CLIENT_SAE - WL_INFORM_MEM(("Ignore for external sae auth\n")); - return BCME_OK; -#endif /* WL_CLIENT_SAE */ + BCM_REFERENCE(pmk); /* clear the content of pmk structure before usage */ (void)memset_s(&pmk, sizeof(wsec_pmk_t), 0x0, sizeof(wsec_pmk_t)); @@ -3034,8 +3362,8 @@ wl_cfgvendor_set_sae_password(struct wiphy *wiphy, return BCME_ERROR; } - if ((len < WSEC_MIN_PSK_LEN) || (len >= WSEC_MAX_PASSPHRASE_LEN)) { - WL_ERR(("Invalid passphrase length %d..should be >= 8 and < 256\n", + if ((len < 1) || (len > WSEC_MAX_PASSPHRASE_LEN)) { + WL_ERR(("Invalid passphrase length %d..should be >= 1 and <= 256\n", len)); err = BCME_BADLEN; goto done; @@ -3046,21 +3374,63 @@ wl_cfgvendor_set_sae_password(struct wiphy *wiphy, WL_ERR(("could not set wpa_auth (0x%x)\n", err)); goto done; } - pmk.key_len = htod16(len); - bcopy((const u8*)data, pmk.key, len); - pmk.flags = htod16(WSEC_PASSPHRASE); - err = wldev_ioctl_set(net, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk)); + /* Update passphrase in net_info and will be used + * in connect/start_ap context + */ + err = wl_cfg80211_set_netinfo_passphrase(cfg, net, data, len); + if (err) { - WL_ERR(("\n failed to set pmk %d\n", err)); + WL_ERR(("\n failed to cache sae passphrase %d\n", err)); goto done; } else { WL_INFORM_MEM(("sae passphrase set successfully\n")); } + done: return err; } -#endif /* WL_SAE || WL_CLIENT_SAE */ +#endif /* WL_SAE */ + +static int +wl_cfgvendor_set_td_policy(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + struct net_device *net = wdev->netdev; + int ret = BCME_OK; + int attr_type; + int rem = len; + const struct nlattr *iter; + + BCM_REFERENCE(net); + nla_for_each_attr(iter, data, len, rem) { + attr_type = nla_type(iter); + WL_DBG(("attr type: (%u)\n", attr_type)); + + switch (attr_type) { + case BRCM_ATTR_TD_POLICY: { + u32 td_policy = nla_get_u32(iter); + + WL_INFORM_MEM(("Setting TD policy %d\n", td_policy)); + ret = wl_cfg80211_set_wsec_info(net, &td_policy, + sizeof(td_policy), WL_WSEC_INFO_BSS_TD_POLICY); + if (unlikely(ret)) { + WL_ERR(("set wsec_info for td_policy failed, error %d\n", ret)); + /* Trigger disassoc, going ahead with connection is + * violation of TD policy + */ + wl_cfg80211_disassoc(net, WLAN_REASON_UNSPECIFIED); + } + break; + } + /* Add new attributes here */ + default: + WL_ERR(("%s: Unknown type, %d\n", __FUNCTION__, attr_type)); + } + } + + return ret; +} #ifdef BCM_PRIV_CMD_SUPPORT /* strlen("ifname=") + IFNAMESIZE + strlen(" ") + '\0' */ @@ -3084,13 +3454,14 @@ wl_cfgvendor_priv_bcm_handler(struct wiphy *wiphy, struct net_device *net = NULL; unsigned long int cmd_out = 0; -#if defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID) +#if (defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID)) || \ + defined(WL_PRIV_CMD_OVER_NL80211) u32 cmd_buf_len = WL_DRIVER_PRIV_CMD_LEN; char cmd_prefix[ANDROID_PRIV_CMD_IF_PREFIX_LEN + 1] = {0}; char *cmd_buf = NULL; char *current_pos; u32 cmd_offset; -#endif /* WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID */ +#endif /* (WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID) || defined(WL_PRIV_CMD_OVER_NL80211) */ WL_DBG(("%s: Enter \n", __func__)); @@ -3109,7 +3480,8 @@ wl_cfgvendor_priv_bcm_handler(struct wiphy *wiphy, goto exit; } -#if defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID) +#if (defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID)) || \ + defined(WL_PRIV_CMD_OVER_NL80211) if (type == BRCM_ATTR_DRIVER_CMD) { if ((cmd_len >= WL_DRIVER_PRIV_CMD_LEN) || (cmd_len < ANDROID_PRIV_CMD_IF_PREFIX_LEN)) { @@ -3165,6 +3537,7 @@ wl_cfgvendor_priv_bcm_handler(struct wiphy *wiphy, cmd_buf[WL_DRIVER_PRIV_CMD_LEN - 1] = '\0'; WL_DBG(("vendor_command: %s len: %u \n", cmd_buf, cmd_buf_len)); +#ifdef OEM_ANDROID bytes_written = wl_handle_private_cmd(net, cmd_buf, cmd_buf_len); WL_DBG(("bytes_written: %d \n", bytes_written)); if (bytes_written == 0) { @@ -3183,6 +3556,10 @@ wl_cfgvendor_priv_bcm_handler(struct wiphy *wiphy, err = bytes_written; goto exit; } +#else // OEM_ANDROID + err = bytes_written = -ENODEV; + goto exit; +#endif // OEM_ANDROID if ((data_len > 0) && (data_len < (cmd_buf_len - 1)) && cmd_buf) { err = wl_cfgvendor_send_cmd_reply(wiphy, cmd_buf, data_len); if (unlikely(err)) { @@ -3197,18 +3574,18 @@ wl_cfgvendor_priv_bcm_handler(struct wiphy *wiphy, } break; } -#endif /* WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID */ +#endif /* (WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID) || defined(WL_PRIV_CMD_OVER_NL80211) */ } exit: -#if defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID) +#if (defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID)) || \ + defined(WL_PRIV_CMD_OVER_NL80211) if (cmd_buf) { MFREE(cfg->osh, cmd_buf, cmd_buf_len); } -#endif /* WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID */ - +#endif /* (WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID) || defined(WL_PRIV_CMD_OVER_NL80211) */ net_os_wake_unlock(ndev); return err; } @@ -3455,6 +3832,14 @@ nan_attr_to_str(u16 cmd) break; C2S(NAN_ATTRIBUTE_DW_EARLY_TERM); break; + C2S(NAN_ATTRIBUTE_CHANNEL_INFO); + break; + C2S(NAN_ATTRIBUTE_NUM_CHANNELS); + break; + C2S(NAN_ATTRIBUTE_INSTANT_MODE_ENABLE); + break; + C2S(NAN_ATTRIBUTE_INSTANT_COMM_CHAN); + break; default: id2str = "NAN_ATTRIBUTE_UNKNOWN"; } @@ -3548,7 +3933,8 @@ wl_cfgvendor_nan_cmd_reply(struct wiphy *wiphy, int nan_cmd, nan_req_resp->value = ret; err = wl_cfgvendor_send_cmd_reply(wiphy, nan_req_resp, sizeof(*nan_req_resp)); - return err; + /* giving more prio to ret than err */ + return (ret == 0) ? err : ret; } static void @@ -3578,6 +3964,9 @@ wl_cfgvendor_free_disc_cmd_data(struct bcm_cfg80211 *cfg, if (cmd_data->key.data) { MFREE(cfg->osh, cmd_data->key.data, NAN_MAX_PMK_LEN); } + if (cmd_data->scid.data) { + MFREE(cfg->osh, cmd_data->scid.data, cmd_data->scid.dlen); + } if (cmd_data->sde_svc_info.data) { MFREE(cfg->osh, cmd_data->sde_svc_info.data, cmd_data->sde_svc_info.dlen); } @@ -3601,6 +3990,9 @@ wl_cfgvendor_free_dp_cmd_data(struct bcm_cfg80211 *cfg, if (cmd_data->key.data) { MFREE(cfg->osh, cmd_data->key.data, NAN_MAX_PMK_LEN); } + if (cmd_data->scid.data) { + MFREE(cfg->osh, cmd_data->scid.data, cmd_data->scid.dlen); + } MFREE(cfg->osh, cmd_data, sizeof(*cmd_data)); } @@ -3631,7 +4023,7 @@ wl_cfgvendor_nan_parse_dp_sec_info_args(struct wiphy *wiphy, } break; case NAN_ATTRIBUTE_PUBLISH_ID: - cmd_data->pub_id = nla_get_u16(iter); + cmd_data->pub_id = nla_get_u32(iter); break; case NAN_ATTRIBUTE_NDP_ID: cmd_data->ndp_instance_id = nla_get_u32(iter); @@ -3648,6 +4040,65 @@ wl_cfgvendor_nan_parse_dp_sec_info_args(struct wiphy *wiphy, } #endif /* WL_NAN_DISC_CACHE */ +static int +wl_cfgvendor_nan_parse_scid_params(struct bcm_cfg80211 *cfg, nan_str_data_t *scid, + const struct nlattr *iter, int attr_type) +{ + int ret = BCME_OK; + + switch (attr_type) { + case NAN_ATTRIBUTE_SCID_LEN: + if (nla_len(iter) != sizeof(uint32)) { + ret = -EINVAL; + goto exit; + } + if (scid->dlen) { + WL_ERR(("trying to overwrite:%d\n", attr_type)); + ret = -EINVAL; + goto exit; + } + scid->dlen = nla_get_u32(iter); + if ((!scid->dlen) || scid->dlen >= NAN_MAX_SCID_BUF_LEN) { + ret = -EINVAL; + WL_ERR(("scid len %d invalid\n", scid->dlen)); + goto exit; + } + WL_TRACE(("valid scid length = %u\n", scid->dlen)); + break; + case NAN_ATTRIBUTE_SCID: + if (!scid->dlen || (nla_len(iter) != scid->dlen)) { + WL_ERR(("wrong scid len:%d,%d\n", scid->dlen, nla_len(iter))); + ret = -EINVAL; + goto exit; + } + if (scid->data) { + WL_ERR(("trying to overwrite:%d\n", attr_type)); + ret = -EINVAL; + goto exit; + } + + scid->data = MALLOCZ(cfg->osh, scid->dlen); + if (scid->data == NULL) { + WL_ERR(("failed to allocate scid, len=%d\n", scid->dlen)); + ret = -ENOMEM; + goto exit; + } + ret = memcpy_s(scid->data, scid->dlen, + nla_data(iter), nla_len(iter)); + if (ret != BCME_OK) { + WL_ERR(("Failed to copy scid data\n")); + return ret; + } + break; + default: + WL_ERR(("Unknown type, %d\n", attr_type)); + ret = -EINVAL; + break; + } +exit: + return ret; +} + int8 chanbuf[CHANSPEC_STR_LEN]; static int wl_cfgvendor_nan_parse_datapath_args(struct wiphy *wiphy, @@ -3780,13 +4231,9 @@ wl_cfgvendor_nan_parse_datapath_args(struct wiphy *wiphy, } /* take the default channel start_factor frequency */ chan = wf_mhz2channel((uint)nla_get_u32(iter), 0); - if (chan <= CH_MAX_2G_CHANNEL) { - cmd_data->avail_params.chanspec[0] = - wf_channel2chspec(chan, WL_CHANSPEC_BW_20); - } else { - cmd_data->avail_params.chanspec[0] = - wf_channel2chspec(chan, WL_CHANSPEC_BW_80); - } + /* 20MHz as BW */ + cmd_data->avail_params.chanspec[0] = + wf_channel2chspec(chan, WL_CHANSPEC_BW_20); if (cmd_data->avail_params.chanspec[0] == 0) { WL_ERR(("Channel is not valid \n")); ret = -EINVAL; @@ -3962,7 +4409,16 @@ wl_cfgvendor_nan_parse_datapath_args(struct wiphy *wiphy, goto exit; } break; - + case NAN_ATTRIBUTE_SCID_LEN: + /* Fall through */ + case NAN_ATTRIBUTE_SCID: + ret = wl_cfgvendor_nan_parse_scid_params(cfg, &cmd_data->scid, + iter, attr_type); + if (ret != BCME_OK) { + WL_ERR(("Failed to scid data\n")); + return ret; + } + break; default: WL_ERR(("Unknown type, %d\n", attr_type)); ret = -EINVAL; @@ -4007,11 +4463,11 @@ wl_cfgvendor_nan_parse_discover_args(struct wiphy *wiphy, /* Nan Publish/Subscribe request Attributes */ case NAN_ATTRIBUTE_PUBLISH_ID: - if (nla_len(iter) != sizeof(uint16)) { + if (nla_len(iter) != sizeof(uint32)) { ret = -EINVAL; goto exit; } - cmd_data->pub_id = nla_get_u16(iter); + cmd_data->pub_id = nla_get_u32(iter); cmd_data->local_id = cmd_data->pub_id; break; case NAN_ATTRIBUTE_MAC_ADDR: @@ -4522,6 +4978,16 @@ wl_cfgvendor_nan_parse_discover_args(struct wiphy *wiphy, return ret; } break; + case NAN_ATTRIBUTE_SCID_LEN: + /* Fall through */ + case NAN_ATTRIBUTE_SCID: + ret = wl_cfgvendor_nan_parse_scid_params(cfg, &cmd_data->scid, + iter, attr_type); + if (ret != BCME_OK) { + WL_ERR(("Failed to scid data\n")); + return ret; + } + break; case NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG: if (nla_len(iter) != sizeof(uint8)) { ret = -EINVAL; @@ -4825,11 +5291,8 @@ wl_cfgvendor_nan_parse_args(struct wiphy *wiphy, const void *buf, } /* take the default channel start_factor frequency */ chan = wf_mhz2channel((uint)nla_get_u32(iter), 0); - if (chan <= CH_MAX_2G_CHANNEL) { - cmd_data->chanspec[0] = wf_channel2chspec(chan, WL_CHANSPEC_BW_20); - } else { - cmd_data->chanspec[0] = wf_channel2chspec(chan, WL_CHANSPEC_BW_80); - } + /* 20MHz as BW */ + cmd_data->chanspec[0] = wf_channel2chspec(chan, WL_CHANSPEC_BW_20); if (cmd_data->chanspec[0] == 0) { WL_ERR(("Channel is not valid \n")); ret = -EINVAL; @@ -5051,45 +5514,10 @@ wl_cfgvendor_nan_parse_args(struct wiphy *wiphy, const void *buf, WL_TRACE(("CSID = %u\n", cmd_data->csid)); break; case NAN_ATTRIBUTE_SCID_LEN: - if (nla_len(iter) != sizeof(uint32)) { - ret = -EINVAL; - goto exit; - } - if (cmd_data->scid.dlen) { - WL_ERR(("trying to overwrite:%d\n", attr_type)); - ret = -EINVAL; - goto exit; - } - cmd_data->scid.dlen = nla_get_u32(iter); - if (cmd_data->scid.dlen > MAX_SCID_LEN) { - ret = -EINVAL; - WL_ERR_RLMT(("Not allowed beyond %d\n", MAX_SCID_LEN)); - goto exit; - } - WL_TRACE(("valid scid length = %u\n", cmd_data->scid.dlen)); - break; + /* Fall through */ case NAN_ATTRIBUTE_SCID: - if (!cmd_data->scid.dlen || (nla_len(iter) != cmd_data->scid.dlen)) { - WL_ERR(("wrong scid len:%d,%d\n", cmd_data->scid.dlen, - nla_len(iter))); - ret = -EINVAL; - goto exit; - } - if (cmd_data->scid.data) { - WL_ERR(("trying to overwrite:%d\n", attr_type)); - ret = -EINVAL; - goto exit; - } - - cmd_data->scid.data = MALLOCZ(cfg->osh, cmd_data->scid.dlen); - if (cmd_data->scid.data == NULL) { - WL_ERR(("failed to allocate scid, len=%d\n", - cmd_data->scid.dlen)); - ret = -ENOMEM; - goto exit; - } - ret = memcpy_s(cmd_data->scid.data, cmd_data->scid.dlen, - nla_data(iter), nla_len(iter)); + ret = wl_cfgvendor_nan_parse_scid_params(cfg, &cmd_data->scid, + iter, attr_type); if (ret != BCME_OK) { WL_ERR(("Failed to scid data\n")); return ret; @@ -5170,6 +5598,28 @@ wl_cfgvendor_nan_parse_args(struct wiphy *wiphy, const void *buf, } cmd_data->use_ndpe_attr = nla_get_u32(iter); break; + case NAN_ATTRIBUTE_INSTANT_MODE_ENABLE: + if (nla_len(iter) != sizeof(uint32)) { + ret = -EINVAL; + goto exit; + } + cmd_data->instant_mode_en = nla_get_u32(iter); + *nan_attr_mask |= NAN_ATTR_INSTANT_MODE_CONFIG; + break; + case NAN_ATTRIBUTE_INSTANT_COMM_CHAN: + if (nla_len(iter) != sizeof(uint32)) { + ret = -EINVAL; + goto exit; + } + cmd_data->instant_chspec = wl_freq_to_chanspec((int)nla_get_u32(iter)); + if (cmd_data->instant_chspec <= 0) { + WL_ERR((" Instant mode Channel is not valid \n")); + ret = -EINVAL; + break; + } + WL_INFORM_MEM(("[NAN Instant mode] Freq %d chanspec %x \n", + nla_get_u32(iter), cmd_data->instant_chspec)); + break; case NAN_ATTRIBUTE_ENABLE_MERGE: if (nla_len(iter) != sizeof(uint8)) { ret = -EINVAL; @@ -5199,12 +5649,7 @@ wl_cfgvendor_nan_parse_args(struct wiphy *wiphy, const void *buf, ret = -EINVAL; goto exit; } - cfg->nancfg->ranging_enable = nla_get_u32(iter); - if (cfg->nancfg->ranging_enable == 0) { - WL_ERR((" ranging enable is not set \n")); - cmd_data->status = BCME_BADARG; - goto exit; - } + cfg->nancfg->ranging_enable = nla_get_u32(iter) != 0 ? TRUE : FALSE; break; case NAN_ATTRIBUTE_DW_EARLY_TERM: if (nla_len(iter) != sizeof(uint32)) { @@ -5213,6 +5658,13 @@ wl_cfgvendor_nan_parse_args(struct wiphy *wiphy, const void *buf, } cmd_data->dw_early_termination = nla_get_u32(iter); break; + case NAN_ATTRIBUTE_CHRE_REQUEST: + if (nla_len(iter) != sizeof(uint8)) { + ret = -EINVAL; + goto exit; + } + cmd_data->chre_req = nla_get_u8(iter); + break; default: WL_ERR(("%s: Unknown type, %d\n", __FUNCTION__, attr_type)); ret = -EINVAL; @@ -5235,6 +5687,8 @@ static int wl_cfgvendor_nan_dp_estb_event_data_filler(struct sk_buff *msg, nan_event_data_t *event_data) { int ret = BCME_OK; + nan_ndl_sched_info_t *nan_sched_info = &event_data->ndl_sched_info; + ret = nla_put_u32(msg, NAN_ATTRIBUTE_NDP_ID, event_data->ndp_id); if (unlikely(ret)) { WL_ERR(("Failed to put NDP ID, ret=%d\n", ret)); @@ -5270,15 +5724,37 @@ wl_cfgvendor_nan_dp_estb_event_data_filler(struct sk_buff *msg, } } + if (nan_sched_info->num_channels > 0) { + if (nan_sched_info->num_channels > NAN_MAX_CHANNEL_INFO_SUPPORTED) { + WL_ERR(("Failed to put more num channels: %d than supported\n", + nan_sched_info->num_channels)); + ret = BCME_BADLEN; + goto fail; + } + ret = nla_put_u32(msg, NAN_ATTRIBUTE_NUM_CHANNELS, nan_sched_info->num_channels); + if (unlikely(ret)) { + WL_ERR(("Failed to put num channels, ret=%d\n", ret)); + goto fail; + } + + ret = nla_put(msg, NAN_ATTRIBUTE_CHANNEL_INFO, + (nan_sched_info->num_channels * sizeof(nan_channel_info_t)), + &nan_sched_info->channel_info[0]); + if (unlikely(ret)) { + WL_ERR(("Failed to put nan channel info, ret=%d\n", ret)); + goto fail; + } + } fail: return ret; } static int wl_cfgvendor_nan_dp_ind_event_data_filler(struct sk_buff *msg, - nan_event_data_t *event_data) { + nan_event_data_t *event_data) +{ int ret = BCME_OK; - ret = nla_put_u16(msg, NAN_ATTRIBUTE_PUBLISH_ID, + ret = nla_put_u32(msg, NAN_ATTRIBUTE_PUBLISH_ID, event_data->pub_id); if (unlikely(ret)) { WL_ERR(("Failed to put pub ID, ret=%d\n", ret)); @@ -5315,6 +5791,23 @@ wl_cfgvendor_nan_dp_ind_event_data_filler(struct sk_buff *msg, goto fail; } } +#ifdef WL_NAN_INSTANT_MODE + /* PMKID(scid) info */ + if (event_data->scid.dlen && event_data->scid.data) { + ret = nla_put_u32(msg, NAN_ATTRIBUTE_SCID_LEN, event_data->scid.dlen); + if (unlikely(ret)) { + WL_ERR(("Failed to put scid info len, ret=%d\n", ret)); + goto fail; + } + ret = nla_put(msg, NAN_ATTRIBUTE_SCID, + event_data->scid.dlen, event_data->scid.data); + if (unlikely(ret)) { + WL_ERR(("Failed to put scid info, ret=%d\n", ret)); + goto fail; + } + WL_TRACE(("scid info len = %d\n", event_data->scid.dlen)); + } +#endif /* WL_NAN_INSTANT_MODE */ fail: return ret; @@ -5376,7 +5869,7 @@ wl_cfgvendor_nan_svc_terminate_event_filler(struct sk_buff *msg, goto fail; } } else { - ret = nla_put_u16(msg, NAN_ATTRIBUTE_PUBLISH_ID, + ret = nla_put_u32(msg, NAN_ATTRIBUTE_PUBLISH_ID, event_data->local_inst_id); if (unlikely(ret)) { WL_ERR(("Failed to put local inst id, ret=%d\n", ret)); @@ -5461,6 +5954,27 @@ fail: return ret; } +static int +wl_cfgvendor_nan_match_expiry_event_filler(struct sk_buff *msg, + nan_event_data_t *event_data) { + int ret = BCME_OK; + + WL_DBG(("sub id (local id)=%d, pub id (remote id)=%d\n", + event_data->sub_id, event_data->pub_id)); + ret = nla_put_u16(msg, NAN_ATTRIBUTE_SUBSCRIBE_ID, event_data->sub_id); + if (unlikely(ret)) { + WL_ERR(("Failed to put Sub Id, ret=%d\n", ret)); + goto fail; + } + ret = nla_put_u32(msg, NAN_ATTRIBUTE_PUBLISH_ID, event_data->pub_id); + if (unlikely(ret)) { + WL_ERR(("Failed to put pub id, ret=%d\n", ret)); + goto fail; + } +fail: + return ret; +} + static int wl_cfgvendor_nan_tx_followup_event_filler(struct sk_buff *msg, nan_event_data_t *event_data) { @@ -5527,7 +6041,7 @@ wl_cfgvendor_nan_sub_match_event_filler(struct sk_buff *msg, WL_ERR(("Failed to put handle, ret=%d\n", ret)); goto fail; } - ret = nla_put_u16(msg, NAN_ATTRIBUTE_PUBLISH_ID, event_data->pub_id); + ret = nla_put_u32(msg, NAN_ATTRIBUTE_PUBLISH_ID, event_data->pub_id); if (unlikely(ret)) { WL_ERR(("Failed to put pub id, ret=%d\n", ret)); goto fail; @@ -5543,6 +6057,13 @@ wl_cfgvendor_nan_sub_match_event_filler(struct sk_buff *msg, WL_ERR(("Failed to put remote NMI, ret=%d\n", ret)); goto fail; } +#ifdef WL_NAN_INSTANT_MODE + ret = nla_put_u8(msg, NAN_ATTRIBUTE_CIPHER_SUITE_TYPE, event_data->peer_cipher_suite); + if (unlikely(ret)) { + WL_ERR(("Failed to put CSID, ret=%d\n", ret)); + goto fail; + } +#endif /* WL_NAN_INSTANT_MODE */ if (event_data->publish_rssi) { event_data->publish_rssi = -event_data->publish_rssi; ret = nla_put_u8(msg, NAN_ATTRIBUTE_RSSI_PROXIMITY, @@ -5590,6 +6111,24 @@ wl_cfgvendor_nan_sub_match_event_filler(struct sk_buff *msg, event_data->tx_match_filter.dlen)); } +#ifdef WL_NAN_INSTANT_MODE + /* PMKID(scid) info */ + if (event_data->scid.dlen && event_data->scid.data) { + ret = nla_put_u32(msg, NAN_ATTRIBUTE_SCID_LEN, event_data->scid.dlen); + if (unlikely(ret)) { + WL_ERR(("Failed to put scid info len, ret=%d\n", ret)); + goto fail; + } + ret = nla_put(msg, NAN_ATTRIBUTE_SCID, + event_data->scid.dlen, event_data->scid.data); + if (unlikely(ret)) { + WL_ERR(("Failed to put scid info, ret=%d\n", ret)); + goto fail; + } + WL_TRACE(("scid info len = %d\n", event_data->scid.dlen)); + } +#endif /* WL_NAN_INSTANT_MODE */ + fail: return ret; } @@ -5725,11 +6264,13 @@ wl_cfgvendor_send_nan_async_resp(struct wiphy *wiphy, struct wireless_dev *wdev, int ret = BCME_OK; int buf_len = NAN_EVENT_BUFFER_SIZE_LARGE; gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy); struct sk_buff *msg; NAN_DBG_ENTER(); + wdev = bcmcfg_to_nmi_wdev(cfg); /* Allocate the skb for vendor event */ msg = CFG80211_VENDOR_EVENT_ALLOC(wiphy, wdev, buf_len, event_id, kflags); @@ -5753,8 +6294,8 @@ wl_cfgvendor_send_nan_async_resp(struct wiphy *wiphy, struct wireless_dev *wdev, fail: dev_kfree_skb_any(msg); - WL_ERR(("Event not implemented or unknown -- Free skb, event_id = %d, ret = %d\n", - event_id, ret)); + WL_ERR(("%s: Event not implemented or unknown -- Free skb, event_id = %d, ret = %d\n", + __func__, event_id, ret)); NAN_DBG_EXIT(); return ret; } @@ -5790,6 +6331,7 @@ wl_cfgvendor_send_nan_event(struct wiphy *wiphy, struct net_device *dev, NAN_DBG_ENTER(); + dev = bcmcfg_to_nmi_ndev(cfg); /* Allocate the skb for vendor event */ msg = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(dev), buf_len, event_id, kflags); @@ -5800,17 +6342,29 @@ wl_cfgvendor_send_nan_event(struct wiphy *wiphy, struct net_device *dev, switch (event_id) { case GOOGLE_NAN_EVENT_DE_EVENT: { - WL_INFORM_MEM(("[NAN] GOOGLE_NAN_DE_EVENT cluster id=" MACDBG "nmi= " MACDBG "\n", - MAC2STRDBG(event_data->clus_id.octet), - MAC2STRDBG(event_data->local_nmi.octet))); - ret = wl_cfgvendor_nan_de_event_filler(msg, event_data); - if (unlikely(ret)) { - WL_ERR(("Failed to fill de event data, ret=%d\n", ret)); - goto fail; + if (event_data->nan_de_evt_type == WL_NAN_EVENT_NMI_ADDR) { + WL_INFORM_MEM(("[NAN] GOOGLE_NAN_DE_EVENT nmi= " MACDBG "\n", + MAC2STRDBG(event_data->local_nmi.octet))); + ret = nla_put(msg, NAN_ATTRIBUTE_MAC_ADDR, ETH_ALEN, + event_data->local_nmi.octet); + if (unlikely(ret)) { + WL_ERR(("Failed to put NMI, ret=%d\n", ret)); + goto fail; + } + } else { + WL_DBG(("[NAN] GOOGLE_NAN_DE_EVENT cluster id=" MACDBG "nmi= " MACDBG "\n", + MAC2STRDBG(event_data->clus_id.octet), + MAC2STRDBG(event_data->local_nmi.octet))); + ret = wl_cfgvendor_nan_de_event_filler(msg, event_data); + if (unlikely(ret)) { + WL_ERR(("Failed to fill de event data, ret=%d\n", ret)); + goto fail; + } } break; } case GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH: + case GOOGLE_NAN_EVENT_MATCH_EXPIRY: case GOOGLE_NAN_EVENT_FOLLOWUP: { if (event_id == GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH) { WL_DBG(("GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH\n")); @@ -5823,10 +6377,18 @@ wl_cfgvendor_send_nan_event(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("GOOGLE_NAN_EVENT_FOLLOWUP\n")); ret = wl_cfgvendor_nan_tx_followup_event_filler(msg, event_data); if (unlikely(ret)) { - WL_ERR(("Failed to fill sub match event data, ret=%d\n", ret)); + WL_ERR(("Failed to fill tx follow up event data, ret=%d\n", ret)); + goto fail; + } + } else if (event_id == GOOGLE_NAN_EVENT_MATCH_EXPIRY) { + WL_DBG(("GOOGLE_NAN_EVENT_MATCH_EXPIRY\n")); + ret = wl_cfgvendor_nan_match_expiry_event_filler(msg, event_data); + if (unlikely(ret)) { + WL_ERR(("Failed to fill match expiry event data, ret=%d\n", ret)); goto fail; } } + ret = wl_cfgvendor_nan_opt_params_filler(msg, event_data); if (unlikely(ret)) { WL_ERR(("Failed to fill sub match event data, ret=%d\n", ret)); @@ -5925,8 +6487,8 @@ wl_cfgvendor_send_nan_event(struct wiphy *wiphy, struct net_device *dev, fail: dev_kfree_skb_any(msg); - WL_ERR(("Event not implemented or unknown -- Free skb, event_id = %d, ret = %d\n", - event_id, ret)); + WL_ERR(("%s: Event not implemented or unknown -- Free skb, event_id = %d, ret = %d\n", + __func__, event_id, ret)); NAN_DBG_EXIT(); return ret; } @@ -5941,6 +6503,7 @@ wl_cfgvendor_nan_req_subscribe(struct wiphy *wiphy, nan_hal_resp_t nan_req_resp; NAN_DBG_ENTER(); + wdev = bcmcfg_to_prmry_wdev(cfg); /* Blocking Subscribe if NAN is not enable */ if (!cfg->nancfg->nan_enable) { WL_ERR(("nan is not enabled, subscribe blocked\n")); @@ -6004,6 +6567,7 @@ wl_cfgvendor_nan_req_publish(struct wiphy *wiphy, nan_hal_resp_t nan_req_resp; NAN_DBG_ENTER(); + wdev = bcmcfg_to_prmry_wdev(cfg); /* Blocking Publish if NAN is not enable */ if (!cfg->nancfg->nan_enable) { WL_ERR(("nan is not enabled publish blocked\n")); @@ -6066,7 +6630,9 @@ wl_cfgvendor_nan_start_handler(struct wiphy *wiphy, struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); nan_hal_resp_t nan_req_resp; uint32 nan_attr_mask = 0; + wl_nancfg_t *nancfg = cfg->nancfg; + wdev = bcmcfg_to_prmry_wdev(cfg); cmd_data = (nan_config_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data)); if (!cmd_data) { WL_ERR(("%s: memory allocation failed\n", __func__)); @@ -6081,15 +6647,11 @@ wl_cfgvendor_nan_start_handler(struct wiphy *wiphy, goto exit; } - if (cfg->nancfg->nan_enable) { - WL_ERR(("nan is already enabled\n")); - ret = BCME_OK; - goto exit; - } bzero(&nan_req_resp, sizeof(nan_req_resp)); cmd_data->sid_beacon.sid_enable = NAN_SID_ENABLE_FLAG_INVALID; /* Setting to some default */ cmd_data->sid_beacon.sid_count = NAN_SID_BEACON_COUNT_INVALID; /* Setting to some default */ + cfg->nancfg->ranging_enable = TRUE; /* by default enable ranging */ ret = wl_cfgvendor_nan_parse_args(wiphy, data, len, cmd_data, &nan_attr_mask); if (ret) { @@ -6101,6 +6663,32 @@ wl_cfgvendor_nan_start_handler(struct wiphy *wiphy, goto exit; } + if (nancfg->nan_enable) { + if (cmd_data->chre_req) { + if (cfg->nancfg->enab_reason == ENABLE_FOR_CHRE) { + /* Already enabled for CHRE */ + ret = BCME_OK; + goto exit; + } else { + /* enabled for APP .. return busy for CHRE req */ + ret = BCME_BUSY; + goto exit; + } + } else { + if (cfg->nancfg->enab_reason == ENABLE_FOR_CHRE) { + /* TODO : Disable Nan and enable again for APP + * For now return busy + */ + ret = BCME_BUSY; + goto exit; + } else { + /* already enabled for APP */ + ret = BCME_OK; + goto exit; + } + } + } + ret = wl_cfgnan_start_handler(wdev->netdev, cfg, cmd_data, nan_attr_mask); if (ret) { WL_ERR(("failed to start nan error[%d]\n", ret)); @@ -6108,7 +6696,14 @@ wl_cfgvendor_nan_start_handler(struct wiphy *wiphy, } /* Initializing Instance Id List */ bzero(cfg->nancfg->nan_inst_ctrl, NAN_ID_CTRL_SIZE * sizeof(nan_svc_inst_t)); + exit: + if (ret == BCME_OK) { + nancfg->enab_reason = cmd_data->chre_req ? + ENABLE_FOR_CHRE : ENABLE_FOR_APP; + WL_INFORM_MEM(("Enabled successful for reason %d\n", nancfg->enab_reason)); + } + ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_ENABLE, &nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK); if (cmd_data) { @@ -6119,6 +6714,7 @@ exit: MFREE(cfg->osh, cmd_data, sizeof(*cmd_data)); } NAN_DBG_EXIT(); + return ret; } @@ -6135,6 +6731,7 @@ wl_cfgvendor_terminate_dp_rng_sessions(struct bcm_cfg80211 *cfg, nan_ranging_inst_t *ranging_inst = NULL; #endif /* RTT_SUPPORT */ + wdev = bcmcfg_to_prmry_wdev(cfg); *ssn_exists = false; dhdp = wl_cfg80211_get_dhdp(wdev->netdev); /* Cleanup active Data Paths If any */ @@ -6159,7 +6756,7 @@ wl_cfgvendor_terminate_dp_rng_sessions(struct bcm_cfg80211 *cfg, (NAN_RANGING_IS_IN_PROG(ranging_inst->range_status))) { ret = wl_cfgnan_cancel_ranging(bcmcfg_to_prmry_ndev(cfg), cfg, &ranging_inst->range_id, - NAN_RNG_TERM_FLAG_NONE, &status); + NAN_RNG_TERM_FLAG_IMMEDIATE, &status); if (unlikely(ret) || unlikely(status)) { WL_ERR(("nan range cancel failed ret = %d status = %d\n", ret, status)); @@ -6181,10 +6778,31 @@ wl_cfgvendor_nan_stop_handler(struct wiphy *wiphy, bool ssn_exists = false; uint32 delay_ms = 0; wl_nancfg_t *nancfg = cfg->nancfg; + nan_config_cmd_data_t *cmd_data; + uint32 nan_attr_mask = 0; NAN_DBG_ENTER(); mutex_lock(&cfg->if_sync); + wdev = bcmcfg_to_prmry_wdev(cfg); + + cmd_data = (nan_config_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data)); + if (!cmd_data) { + WL_ERR(("%s: memory allocation failed\n", __func__)); + ret = BCME_NOMEM; + goto exit; + } + + ret = wl_cfgvendor_nan_parse_args(wiphy, data, len, cmd_data, &nan_attr_mask); + if (ret) { + WL_ERR(("failed to parse nan vendor args, ret %d\n", ret)); + goto exit; + } + if (cmd_data->status == BCME_BADARG) { + WL_ERR(("nan vendor args is invalid\n")); + goto exit; + } + if (nancfg->nan_init_state == false) { WL_INFORM_MEM(("nan is not initialized/nmi doesnt exists\n")); goto exit; @@ -6192,6 +6810,19 @@ wl_cfgvendor_nan_stop_handler(struct wiphy *wiphy, if (nancfg->nan_enable == false) { WL_INFORM_MEM(("nan is in disabled state\n")); } else { + if (cmd_data->chre_req) { + if (nancfg->enab_reason != ENABLE_FOR_CHRE) { + /* Not enabled for CHRE.. ignore disable req */ + WL_INFORM_MEM(("nan not enabled for CHRE..ignore disab\n")); + goto exit; + } + } else { + if (nancfg->enab_reason != ENABLE_FOR_APP) { + /* Not enabled for APP.. ignore disable req */ + WL_INFORM_MEM(("nan not enabled for APP..ignore disab\n")); + goto exit; + } + } nancfg->notify_user = true; wl_cfgvendor_terminate_dp_rng_sessions(cfg, wdev, &ssn_exists); if (ssn_exists == true) { @@ -6234,6 +6865,7 @@ wl_cfgvendor_nan_config_handler(struct wiphy *wiphy, } NAN_DBG_ENTER(); + wdev = bcmcfg_to_prmry_wdev(cfg); bzero(&nan_req_resp, sizeof(nan_req_resp)); cmd_data->avail_params.duration = NAN_BAND_INVALID; /* Setting to some default */ @@ -6278,6 +6910,7 @@ wl_cfgvendor_nan_cancel_publish(struct wiphy *wiphy, struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); nan_hal_resp_t nan_req_resp; + wdev = bcmcfg_to_prmry_wdev(cfg); /* Blocking Cancel_Publish if NAN is not enable */ if (!cfg->nancfg->nan_enable) { WL_ERR(("nan is not enabled, cancel publish blocked\n")); @@ -6325,6 +6958,7 @@ wl_cfgvendor_nan_cancel_subscribe(struct wiphy *wiphy, struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); nan_hal_resp_t nan_req_resp; + wdev = bcmcfg_to_prmry_wdev(cfg); /* Blocking Cancel_Subscribe if NAN is not enableb */ if (!cfg->nancfg->nan_enable) { WL_ERR(("nan is not enabled, cancel subscribe blocked\n")); @@ -6372,6 +7006,7 @@ wl_cfgvendor_nan_transmit(struct wiphy *wiphy, struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); nan_hal_resp_t nan_req_resp; + wdev = bcmcfg_to_prmry_wdev(cfg); /* Blocking Transmit if NAN is not enable */ if (!cfg->nancfg->nan_enable) { WL_ERR(("nan is not enabled, transmit blocked\n")); @@ -6417,6 +7052,7 @@ wl_cfgvendor_nan_get_capablities(struct wiphy *wiphy, NAN_DBG_ENTER(); + wdev = bcmcfg_to_prmry_wdev(cfg); bzero(&nan_req_resp, sizeof(nan_req_resp)); ret = wl_cfgnan_get_capablities_handler(wdev->netdev, cfg, &nan_req_resp.capabilities); if (ret) { @@ -6441,6 +7077,7 @@ wl_cfgvendor_nan_data_path_iface_create(struct wiphy *wiphy, nan_hal_resp_t nan_req_resp; dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev); + wdev = bcmcfg_to_prmry_wdev(cfg); if (!cfg->nancfg->nan_init_state) { WL_ERR(("%s: NAN is not inited or Device doesn't support NAN \n", __func__)); ret = -ENODEV; @@ -6498,6 +7135,7 @@ wl_cfgvendor_nan_data_path_iface_delete(struct wiphy *wiphy, } NAN_DBG_ENTER(); + wdev = bcmcfg_to_prmry_wdev(cfg); cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data)); if (!cmd_data) { WL_ERR(("%s: memory allocation failed\n", __func__)); @@ -6542,6 +7180,7 @@ wl_cfgvendor_nan_data_path_request(struct wiphy *wiphy, goto exit; } + wdev = bcmcfg_to_prmry_wdev(cfg); NAN_DBG_ENTER(); cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data)); if (!cmd_data) { @@ -6592,6 +7231,7 @@ wl_cfgvendor_nan_data_path_response(struct wiphy *wiphy, goto exit; } NAN_DBG_ENTER(); + wdev = bcmcfg_to_prmry_wdev(cfg); cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data)); if (!cmd_data) { WL_ERR(("%s: memory allocation failed\n", __func__)); @@ -6629,6 +7269,7 @@ wl_cfgvendor_nan_data_path_end(struct wiphy *wiphy, int status = BCME_ERROR; NAN_DBG_ENTER(); + wdev = bcmcfg_to_prmry_wdev(cfg); if (!cfg->nancfg->nan_enable) { WL_ERR(("nan is not enabled, nan data path end blocked\n")); ret = BCME_OK; @@ -6673,6 +7314,7 @@ wl_cfgvendor_nan_data_path_sec_info(struct wiphy *wiphy, dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev); NAN_DBG_ENTER(); + wdev = bcmcfg_to_prmry_wdev(cfg); if (!cfg->nancfg->nan_enable) { WL_ERR(("nan is not enabled\n")); ret = BCME_UNSUPPORTED; @@ -6741,6 +7383,7 @@ wl_cfgvendor_nan_enable_merge(struct wiphy *wiphy, goto exit; } + wdev = bcmcfg_to_prmry_wdev(cfg); ret = wl_cfgvendor_nan_parse_args(wiphy, data, len, cmd_data, &nan_attr_mask); if (ret) { WL_ERR((" Enable merge: failed to parse nan config vendor args, ret = %d\n", ret)); @@ -6769,8 +7412,11 @@ exit: #endif /* WL_NAN */ #ifdef LINKSTAT_SUPPORT - -#define NUM_RATE 32 +/* 11n/HT: OFDM(12) + HT(16) rates = 28 (MCS0 ~ MCS15) + * 11ac/VHT: OFDM(12) + VHT(12) x 2 nss = 36 (MCS0 ~ MCS11) + * 11ax/HE: OFDM(12) + HE(12) x 2 nss = 36 (MCS0 ~ MCS11) + */ +#define NUM_RATE 36 #define NUM_PEER 1 #define NUM_CHAN 11 #define HEADER_SIZE sizeof(ver_len) @@ -6778,30 +7424,51 @@ exit: #define NUM_PNO_SCANS 8 #define NUM_CCA_SAMPLING_SECS 1 -static int wl_cfgvendor_lstats_get_bcn_mbss(char *buf, uint32 *rxbeaconmbss) +#if ANDROID_VERSION >= 13 +static int wl_cfgvendor_send_stats_info(struct wiphy *wiphy, + const void *data, int len) { - wl_cnt_info_t *cbuf = (wl_cnt_info_t *)buf; - const void *cnt; + int ret = 0; + struct sk_buff *skb; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int mem_needed; - if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen, - WL_CNT_XTLV_CNTV_LE10_UCODE, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) { - *rxbeaconmbss = ((const wl_cnt_v_le10_mcst_t *)cnt)->rxbeaconmbss; - } else if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen, - WL_CNT_XTLV_LT40_UCODE_V1, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) { - *rxbeaconmbss = ((const wl_cnt_lt40mcst_v1_t *)cnt)->rxbeaconmbss; - } else if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen, - WL_CNT_XTLV_GE40_UCODE_V1, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) { - *rxbeaconmbss = ((const wl_cnt_ge40mcst_v1_t *)cnt)->rxbeaconmbss; - } else if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen, - WL_CNT_XTLV_GE80_UCODE_V1, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) { - *rxbeaconmbss = ((const wl_cnt_ge80mcst_v1_t *)cnt)->rxbeaconmbss; - } else { - *rxbeaconmbss = 0; - return BCME_NOTFOUND; + mem_needed = VENDOR_REPLY_OVERHEAD + len + ATTRIBUTE_U32_LEN; + + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("skb alloc failed")); + return -ENOMEM; } - return BCME_OK; + ret = nla_put_u32(skb, ANDR_LSTAT_ATTRIBUTE_NUM_RADIO, cfg->num_radios); + if (unlikely(ret)) { + WL_ERR(("Failed to put number of radios, ret=%d\n", ret)); + goto fail; + } + + ret = nla_put(skb, ANDR_LSTAT_ATTRIBUTE_STATS_INFO, len, data); + if (unlikely(ret)) { + WL_ERR(("Failed to put stats info , ret=%d\n", ret)); + goto fail; + } + + ret = cfg80211_vendor_cmd_reply(skb); + if (unlikely(ret)) { + WL_ERR(("Vendor Command reply failed ret:%d \n", ret)); + } + + return ret; +fail: + /* Free skb memory */ + if (skb) { + kfree_skb(skb); + } + return ret; + } +#endif /* ANDROID_VERSION >= 13 */ static void fill_chanspec_to_channel_info(chanspec_t cur_chanspec, wifi_channel_info *channel, int *cur_band) @@ -6841,27 +7508,221 @@ static void fill_chanspec_to_channel_info(chanspec_t cur_chanspec, } } +static s32 +wl_cfgvendor_get_radio_stats(struct bcm_cfg80211 *cfg, struct net_device *ndev, + wifi_channel_stat *chan_stats, int num_channels, char **output, uint *total_len) +{ + s32 err = 0; + uint radio_stats_size = 0, chan_stats_size = 0, avail_radio_stat_len = 0; + char *radio_stat_ptr = NULL, *out_radio_stat = NULL; + wifi_radio_stat_h_v2 radio_h_v2[WL_RADIOSTAT_SLICE_INDEX_MAX]; + wifi_radio_stat_h radio_h; + wifi_radio_stat_v1_t *radio_v1; + wifi_radio_stat_v2_t radio_req_v2; + wifi_radio_stat_v2_t *radio_v2; + static char iovar_buf[WLC_IOCTL_MAXLEN]; + int i = 0; + + chan_stats_size = sizeof(wifi_channel_stat) * num_channels; + /* Radio stat field */ + radio_stats_size = cfg->num_radios*(offsetof(wifi_radio_stat, channels)) + + chan_stats_size; + radio_stat_ptr = (char*)MALLOCZ(cfg->osh, radio_stats_size); + if (radio_stat_ptr == NULL) { + WL_ERR(("radio_stat_ptr alloc failed\n")); + err = BCME_NOMEM; + goto exit; + } + bzero(radio_stat_ptr, radio_stats_size); + avail_radio_stat_len = radio_stats_size; + + bzero(&radio_h, sizeof(radio_h)); + bzero(&radio_h_v2, sizeof(radio_h_v2)); + + out_radio_stat = radio_stat_ptr; + + for (i = 0; i < cfg->num_radios; i++) { + /* Try the VERSION_2 first */ + radio_req_v2.version = WIFI_RADIO_STAT_VERSION_2; + radio_req_v2.length = sizeof(radio_req_v2); + radio_req_v2.radio = i; + + err = wldev_iovar_getbuf(ndev, "radiostat", &radio_req_v2, + sizeof(radio_req_v2), iovar_buf, sizeof(iovar_buf), NULL); + if (err != BCME_OK && err != BCME_UNSUPPORTED && err != BCME_VERSION) { + WL_ERR(("error (%d) - size = %zu\n", + err, sizeof(wifi_radio_stat_v2_t))); + goto exit; + } + + radio_v2 = (wifi_radio_stat_v2_t *)iovar_buf; + if ((err == BCME_OK) && + (dtoh16(radio_v2->version) == WIFI_RADIO_STAT_VERSION_2)) { + if (i != radio_v2->radio) { + WL_ERR(("Fw version is unsupported\n")); + err = BCME_UNSUPPORTED; + goto exit; + } + radio_h_v2[i].radio = radio_v2->radio; + if (radio_v2->radio != WL_RADIOSTAT_SLICE_INDEX_SCAN) { + radio_h_v2[i].on_time = radio_v2->on_time; + } else { + radio_h_v2[i].on_time = 0; + } + radio_h_v2[i].tx_time = radio_v2->tx_time; + radio_h_v2[i].num_tx_levels = 0; + radio_h_v2[i].tx_time_per_levels = NULL; +#ifdef LINKSTAT_EXT_SUPPORT + radio_h_v2[i].rx_time = radio_v2->myrx_time; +#else + radio_h_v2[i].rx_time = radio_v2->rx_time; +#endif /* LINKSTAT_EXT_SUPPORT */ + if (radio_v2->radio != WL_RADIOSTAT_SLICE_INDEX_SCAN) { + radio_h_v2[i].on_time_scan = + (uint32)(radio_v2->on_time_scan / 1000); + } else { + radio_h_v2[i].on_time_scan = 0; + } + radio_h_v2[i].on_time_nbd = (uint32)(radio_v2->on_time_nbd / 1000); + radio_h_v2[i].on_time_gscan = (uint32)(radio_v2->on_time_gscan / 1000); + radio_h_v2[i].on_time_roam_scan = radio_v2->on_time_roam_scan; + radio_h_v2[i].on_time_pno_scan = + (uint32)(radio_v2->on_time_pno_scan / 1000); + radio_h_v2[i].on_time_hs20 = radio_v2->on_time_hs20; + if (i == WL_RADIOSTAT_SLICE_INDEX_MAIN) { + radio_h_v2[i].num_channels = 0; + } else if (i == WL_RADIOSTAT_SLICE_INDEX_AUX) { + radio_h_v2[i].num_channels = 0; + } else { + radio_h_v2[i].num_channels = num_channels; + } + + err = memcpy_s(out_radio_stat, avail_radio_stat_len, + &radio_h_v2[i], offsetof(wifi_radio_stat, channels)); + if (err) { + WL_ERR(("failed to copy radio_stat_h : %d\n", err)); + goto exit; + } + out_radio_stat += offsetof(wifi_radio_stat, channels); + avail_radio_stat_len -= offsetof(wifi_radio_stat, channels); + } else { + /* Retry the VERSION_1 */ + err = wldev_iovar_getbuf(ndev, "radiostat", NULL, 0, + iovar_buf, sizeof(iovar_buf), NULL); + + if (err != BCME_OK && err != BCME_UNSUPPORTED) { + WL_ERR(("error (%d) - size = %zu\n", + err, sizeof(wifi_radio_stat_v1_t))); + goto exit; + } + radio_v1 = (wifi_radio_stat_v1_t *)iovar_buf; +#if ANDROID_VERSION >= 13 + radio_h_v2[i].radio = radio_v1->radio; + if (radio_v1->radio != WL_RADIOSTAT_SLICE_INDEX_SCAN) { + radio_h_v2[i].on_time = radio_v1->on_time; + } else { + radio_h_v2[i].on_time = 0; + } + radio_h_v2[i].tx_time = radio_v1->tx_time; + radio_h_v2[i].num_tx_levels = 0; + radio_h_v2[i].tx_time_per_levels = NULL; + radio_h_v2[i].rx_time = radio_v1->rx_time; + radio_h_v2[i].on_time_scan = 0; + radio_h_v2[i].on_time_nbd = radio_v1->on_time_nbd; + radio_h_v2[i].on_time_gscan = radio_v1->on_time_gscan; + radio_h_v2[i].on_time_roam_scan = radio_v1->on_time_roam_scan; + radio_h_v2[i].on_time_pno_scan = radio_v1->on_time_pno_scan; + radio_h_v2[i].on_time_hs20 = radio_v1->on_time_hs20; + if (i == WL_RADIOSTAT_SLICE_INDEX_MAIN) { + radio_h_v2[i].num_channels = 0; + } else if (i == WL_RADIOSTAT_SLICE_INDEX_AUX) { + radio_h_v2[i].num_channels = 0; + } else { + radio_h_v2[i].num_channels = num_channels; + } + + err = memcpy_s(out_radio_stat, avail_radio_stat_len, + &radio_h_v2[i], offsetof(wifi_radio_stat, channels)); + if (err) { + WL_ERR(("failed to copy radio_stat_h : %d\n", err)); + goto exit; + } + out_radio_stat += offsetof(wifi_radio_stat, channels); + avail_radio_stat_len -= offsetof(wifi_radio_stat, channels); +#else + radio_h.rx_time = radio_v1->rx_time; + if (radio_v1->radio != WL_RADIOSTAT_SLICE_INDEX_SCAN) { + radio_h.on_time = radio_v1->on_time; + } else { + radio_h.on_time = 0; + } + radio_h.tx_time = radio_v1->tx_time; + radio_h.on_time_nbd = radio_v1->on_time_nbd; + radio_h.on_time_gscan = radio_v1->on_time_gscan; + radio_h.on_time_hs20 = radio_v1->on_time_hs20; + err = memcpy_s(out_radio_stat, avail_radio_stat_len, + &radio_h, sizeof(wifi_radio_stat_h)); + if (err) { + WL_ERR(("failed to copy VERSION_1 radio_stat_h : %d\n", err)); + goto exit; + } + out_radio_stat += sizeof(wifi_radio_stat_h); + avail_radio_stat_len -= sizeof(wifi_radio_stat_h); +#endif + } + } + /* Update all channels */ + err = memcpy_s(out_radio_stat, avail_radio_stat_len, + chan_stats, chan_stats_size); + if (err) { + WL_ERR(("failed to copy all channel_stat: %d\n", err)); + goto exit; + } + out_radio_stat += chan_stats_size; + avail_radio_stat_len -= chan_stats_size; + + err = memcpy_s(*output, WLC_IOCTL_MAXLEN, radio_stat_ptr, radio_stats_size); + if (err) { + WL_ERR(("Failed to copy wifi_radio_stat_h: %d\n", err)); + goto exit; + } + *output += radio_stats_size; + *total_len += radio_stats_size; +exit: + if (radio_stat_ptr) { + MFREE(cfg->osh, radio_stat_ptr, radio_stats_size); + } + return err; +} + static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { - static char iovar_buf[WLC_IOCTL_MAXLEN]; + char *iovar_buf; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int err = 0, ret = 0, i; - wifi_radio_stat *radio; + struct net_device *inet_ndev = wdev_to_ndev(wdev); + int err = 0, i; wifi_radio_stat_h radio_h; wifi_channel_stat *chan_stats = NULL; + int num_channels = 0; uint chan_stats_size = 0; -#ifdef CHAN_STATS_SUPPORT - wifi_channel_stat *p_chan_stats = NULL; +#ifdef LINKSTAT_EXT_SUPPORT + wifi_channel_stat *all_chan_stats = NULL; cca_congest_ext_channel_req_v2_t *per_chspec_stats = NULL; uint per_chspec_stats_size = 0; cca_congest_ext_channel_req_v3_t *all_chan_results; - cca_congest_ext_channel_req_v3_t all_chan_req; + cca_congest_ext_channel_req_v3_t *all_chan_req = NULL; + uint all_chan_req_size = sizeof(cca_congest_ext_channel_req_v3_t); + wl_bssload_t *bssload; #else /* cca_get_stats_ext iovar for Wifi channel statics */ - struct cca_congest_ext_channel_req_v2 *cca_v2_results; - struct cca_congest_ext_channel_req_v2 cca_v2_req; -#endif /* CHAN_STATS_SUPPORT */ + cca_congest_ext_channel_req_v2_t *cca_v2_results = NULL; + cca_congest_ext_channel_req_v3_t *cca_v3_req = NULL; + cca_congest_ext_channel_req_v2_t *cca_v2_req = NULL; + uint cca_v3_req_size = sizeof(cca_congest_ext_channel_req_v3_t); + uint cca_v2_req_size = sizeof(cca_congest_ext_channel_req_v2_t); + uint16 cca_ver; +#endif /* LINKSTAT_EXT_SUPPORT */ const wl_cnt_wlc_t *wlc_cnt; scb_val_t scbval; char *output = NULL; @@ -6869,18 +7730,15 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, wifi_rate_stat_v1 *p_wifi_rate_stat_v1 = NULL; wifi_rate_stat *p_wifi_rate_stat = NULL; uint total_len = 0; - uint32 rxbeaconmbss; + uint32 rxbeaconmbss = 0; wlc_rev_info_t revinfo; wl_if_stats_t *if_stats = NULL; + wl_if_infra_enh_stats_v2_t *if_infra_enh_stats = NULL; dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); - wl_pwrstats_query_t scan_query; - wl_pwrstats_t *pwrstats; - wl_pwr_scan_stats_t scan_stats; - int scan_time_len; - uint32 tot_pno_dur = 0; wifi_channel_stat cur_channel_stat; cca_congest_channel_req_t *cca_result; - cca_congest_channel_req_t cca_req; + cca_congest_channel_req_t *cca_req = NULL; + uint cca_req_size = sizeof(cca_congest_channel_req_t); uint32 cca_busy_time = 0; int cur_chansp, cur_band; chanspec_t cur_chanspec; @@ -6891,7 +7749,15 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, RETURN_EIO_IF_NOT_UP(cfg); BCM_REFERENCE(if_stats); + BCM_REFERENCE(if_infra_enh_stats); BCM_REFERENCE(dhdp); + BCM_REFERENCE(chan_stats_size); + + /* Limit link stats query only on primary interface */ + if (!IS_INET_LINK_NDEV(cfg, inet_ndev)) { + WL_ERR(("link stats query requested on non primary interface\n")); + return BCME_UNSUPPORTED; + } /* Get the device rev info */ bzero(&revinfo, sizeof(revinfo)); err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_REVINFO, &revinfo, @@ -6900,6 +7766,7 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, goto exit; } + iovar_buf = cfg->ioctl_buf; outdata = (void *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN); if (outdata == NULL) { WL_ERR(("outdata alloc failed\n")); @@ -6910,90 +7777,8 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, bzero(outdata, WLC_IOCTL_MAXLEN); output = outdata; - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "radiostat", NULL, 0, - iovar_buf, WLC_IOCTL_MAXLEN, NULL); - if (err != BCME_OK && err != BCME_UNSUPPORTED) { - WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wifi_radio_stat))); - goto exit; - } - radio = (wifi_radio_stat *)iovar_buf; - bzero(&radio_h, sizeof(wifi_radio_stat_h)); - radio_h.on_time = radio->on_time; - radio_h.tx_time = radio->tx_time; - radio_h.rx_time = radio->rx_time; - radio_h.on_time_scan = radio->on_time_scan; - radio_h.on_time_nbd = radio->on_time_nbd; - radio_h.on_time_gscan = radio->on_time_gscan; - radio_h.on_time_roam_scan = radio->on_time_roam_scan; - radio_h.on_time_pno_scan = radio->on_time_pno_scan; - radio_h.on_time_hs20 = radio->on_time_hs20; - radio_h.num_channels = NUM_PEER; - - scan_query.length = 1; - scan_query.type[0] = WL_PWRSTATS_TYPE_SCAN; - - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "pwrstats", &scan_query, - sizeof(scan_query), iovar_buf, WLC_IOCTL_MAXLEN, NULL); - if (err != BCME_OK && err != BCME_UNSUPPORTED) { - WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wl_pwrstats_t))); - goto exit; - } - - pwrstats = (wl_pwrstats_t *) iovar_buf; - - if (dtoh16(pwrstats->version) != WL_PWRSTATS_VERSION) { - WL_ERR(("PWRSTATS Version mismatch\n")); - err = BCME_ERROR; - goto exit; - } - - scan_time_len = dtoh16(((uint16 *)pwrstats->data)[1]); - - if (scan_time_len < sizeof(wl_pwr_scan_stats_t)) { - WL_ERR(("WL_PWRSTATS_TYPE_SCAN IOVAR info short len : %d < %d\n", - scan_time_len, (int)sizeof(wl_pwr_scan_stats_t))); - err = BCME_ERROR; - goto exit; - } - - (void) memcpy_s(&scan_stats, sizeof(wl_pwr_scan_stats_t), pwrstats->data, scan_time_len); - - /* wl_pwr_scan_stats structure has the array of pno_scans. - * scan_data_t pno_scans[8]; - * The number of array is 8 : For future PNO bucketing (BSSID, SSID, etc) - * FW sets the number as harcoded. - * If the hardcoded number (8) is changed, - * the loop condition or NUM_PNO_SCANS has to be changed - */ - - for (i = 0; i < NUM_PNO_SCANS; i++) { - tot_pno_dur += dtoh32(scan_stats.pno_scans[i].dur); - } - - /* Android Framework defines the total scan time in ms. - * But FW sends each scan time in us except for roam scan time. - * So we need to scale the times in ms. - */ - - radio_h.on_time_scan = (uint32)((tot_pno_dur + - dtoh32(scan_stats.user_scans.dur) + - dtoh32(scan_stats.assoc_scans.dur) + - dtoh32(scan_stats.other_scans.dur)) / 1000); - - radio_h.on_time_scan += dtoh32(scan_stats.roam_scans.dur); - radio_h.on_time_roam_scan = dtoh32(scan_stats.roam_scans.dur); - radio_h.on_time_pno_scan = (uint32)(tot_pno_dur / 1000); - - WL_TRACE(("pwr_scan_stats : %u %u %u %u %u %u\n", - radio_h.on_time_scan, - dtoh32(scan_stats.user_scans.dur), - dtoh32(scan_stats.assoc_scans.dur), - dtoh32(scan_stats.roam_scans.dur), - tot_pno_dur, - dtoh32(scan_stats.other_scans.dur))); - - err = wldev_iovar_getint(bcmcfg_to_prmry_ndev(cfg), "chanspec", (int*)&cur_chansp); + err = wldev_iovar_getint(inet_ndev, "chanspec", (int*)&cur_chansp); if (err != BCME_OK) { WL_ERR(("error (%d) \n", err)); goto exit; @@ -7016,15 +7801,18 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, cur_channel_stat.channel.center_freq0, cur_channel_stat.channel.center_freq1)); - chan_stats_size = sizeof(wifi_channel_stat); - chan_stats = &cur_channel_stat; - -#ifdef CHAN_STATS_SUPPORT +#ifdef LINKSTAT_EXT_SUPPORT /* Option to get all channel statistics */ - all_chan_req.num_of_entries = 0; - all_chan_req.ver = WL_CCA_EXT_REQ_VER_V3; - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cca_get_stats_ext", - &all_chan_req, sizeof(all_chan_req), iovar_buf, WLC_IOCTL_MAXLEN, NULL); + all_chan_req = (void *)MALLOCZ(cfg->osh, all_chan_req_size); + if (all_chan_req == NULL) { + err = BCME_NOMEM; + WL_ERR(("all_chan_req alloc failed\n")); + goto exit; + } + all_chan_req->num_of_entries = 0; + all_chan_req->ver = WL_CCA_EXT_REQ_VER_V3; + err = wldev_iovar_getbuf(inet_ndev, "cca_get_stats_ext", + all_chan_req, all_chan_req_size, iovar_buf, WLC_IOCTL_MAXLEN, NULL); if (err != BCME_OK && err != BCME_UNSUPPORTED) { WL_ERR(("cca_get_stats_ext iovar err = %d\n", err)); @@ -7034,28 +7822,25 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, all_chan_results = (cca_congest_ext_channel_req_v3_t *) iovar_buf; if ((err == BCME_OK) && (dtoh16(all_chan_results->ver) == WL_CCA_EXT_REQ_VER_V3)) { - wifi_channel_stat *all_chan_stats = NULL; - int i = 0, num_channels; + int i = 0; num_channels = dtoh16(all_chan_results->num_of_entries); - radio_h.num_channels = num_channels; - chan_stats_size = sizeof(wifi_channel_stat) * num_channels; chan_stats = (wifi_channel_stat*)MALLOCZ(cfg->osh, chan_stats_size); - p_chan_stats = chan_stats; if (chan_stats == NULL) { WL_ERR(("chan_stats alloc failed\n")); + err = BCME_NOMEM; goto exit; } bzero(chan_stats, chan_stats_size); all_chan_stats = chan_stats; - per_chspec_stats_size = sizeof(cca_congest_ext_channel_req_v2_t) * num_channels; per_chspec_stats = (cca_congest_ext_channel_req_v2_t *) MALLOCZ(cfg->osh, per_chspec_stats_size); if (per_chspec_stats == NULL) { WL_ERR(("per_chspec_stats alloc failed\n")); + err = BCME_NOMEM; goto exit; } (void) memcpy_s(per_chspec_stats, per_chspec_stats_size, @@ -7083,33 +7868,76 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, per_chspec_stats[i].secs[0].radio_on_time, per_chspec_stats[i].secs[0].cca_busy_time)); } + all_chan_stats = chan_stats; } #else - cca_v2_req.ver = WL_CCA_EXT_REQ_VER_V2; - cca_v2_req.chanspec = + chan_stats_size = sizeof(wifi_channel_stat); + chan_stats = &cur_channel_stat; + + cca_v3_req = (void *)MALLOCZ(cfg->osh, cca_v3_req_size); + if (cca_v3_req == NULL) { + err = BCME_NOMEM; + WL_ERR(("cca_v3_req alloc failed\n")); + goto exit; + } + cca_v3_req->num_of_entries = 1; + cca_v3_req->ver = WL_CCA_EXT_REQ_VER_V3; + cca_v3_req->per_chan_stats->chanspec = wl_chspec_host_to_driver(wf_chspec_primary20_chspec(cur_chanspec)); - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cca_get_stats_ext", &cca_v2_req, - sizeof(cca_v2_req), iovar_buf, WLC_IOCTL_MAXLEN, NULL); + err = wldev_iovar_getbuf(inet_ndev, "cca_get_stats_ext", cca_v3_req, + cca_v3_req_size, iovar_buf, WLC_IOCTL_MAXLEN, NULL); if (err != BCME_OK && err != BCME_UNSUPPORTED) { WL_ERR(("cca_get_stats_ext iovar err = %d\n", err)); goto exit; } - cca_v2_results = (struct cca_congest_ext_channel_req_v2 *) iovar_buf; + cca_ver = ((cca_congest_ext_channel_req_v3_t *)iovar_buf)->ver; /* Check the verison for cca_get_stats_ext iovar */ if ((err == BCME_OK) && - (dtoh16(cca_v2_results->ver) == WL_CCA_EXT_REQ_VER_V2)) { + (dtoh16(cca_ver) == WL_CCA_EXT_REQ_VER_V3)) { + + cca_v2_results = + ((cca_congest_ext_channel_req_v3_t *)iovar_buf)->per_chan_stats; + /* the accumulated time for the current channel */ cur_channel_stat.on_time = dtoh32(cca_v2_results->secs[0].radio_on_time); cur_channel_stat.cca_busy_time = dtoh32(cca_v2_results->secs[0].cca_busy_time); - WL_TRACE(("wifi chan statics - on_time : %u, cca_busy_time : %u\n", + WL_TRACE(("wifi chan statics ver.3 - on_time : %u, cca_busy_time : %u\n", + cur_channel_stat.on_time, cur_channel_stat.cca_busy_time)); + } else if ((err == BCME_OK) && + (dtoh16(cca_ver) == WL_CCA_EXT_REQ_VER_V2)) { + + cca_v2_req = (void *)MALLOCZ(cfg->osh, cca_v2_req_size); + if (cca_v2_req == NULL) { + err = BCME_NOMEM; + WL_ERR(("cca_v2_req alloc failed\n")); + goto exit; + } + cca_v2_req->chanspec = + wl_chspec_host_to_driver(wf_chspec_primary20_chspec(cur_chanspec)); + + err = wldev_iovar_getbuf(inet_ndev, "cca_get_stats_ext", + cca_v2_req, cca_v2_req_size, iovar_buf, WLC_IOCTL_MAXLEN, NULL); + + if (err != BCME_OK) { + WL_ERR(("cca_get_stats_ext iovar err = %d\n", err)); + goto exit; + } + + cca_v2_results = (cca_congest_ext_channel_req_v2_t *) iovar_buf; + + /* the accumulated time for the current channel */ + cur_channel_stat.on_time = dtoh32(cca_v2_results->secs[0].radio_on_time); + cur_channel_stat.cca_busy_time = dtoh32(cca_v2_results->secs[0].cca_busy_time); + + WL_TRACE(("wifi chan statics ver.2 - on_time : %u, cca_busy_time : %u\n", cur_channel_stat.on_time, cur_channel_stat.cca_busy_time)); } -#endif /* CHAN_STATS_SUPPORT */ +#endif /* LINKSTAT_EXT_SUPPORT */ else { /* To get fine-grained cca result, * you can increase num_secs because num_secs is the time to get samples. @@ -7119,10 +7947,16 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, */ WL_TRACE(("cca_get_stats_ext unsupported or version mismatch\n")); - cca_req.num_secs = NUM_CCA_SAMPLING_SECS; - cca_req.chanspec = wl_chspec_host_to_driver(cur_chanspec); + cca_req = (void *)MALLOCZ(cfg->osh, cca_req_size); + if (cca_req == NULL) { + err = BCME_NOMEM; + WL_ERR(("cca_req alloc failed\n")); + goto exit; + } + cca_req->num_secs = NUM_CCA_SAMPLING_SECS; + cca_req->chanspec = wl_chspec_host_to_driver(cur_chanspec); - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cca_get_stats", &cca_req, + err = wldev_iovar_getbuf(inet_ndev, "cca_get_stats", cca_req, sizeof(cca_req), iovar_buf, WLC_IOCTL_MAXLEN, NULL); if (err != BCME_OK && err != BCME_UNSUPPORTED) { @@ -7145,35 +7979,37 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, dtoh32(cca_result->secs[0].congest_obss), dtoh32(cca_result->secs[0].interference))); } else { - WL_ERR(("cca_get_stats is unsupported \n")); + WL_INFORM(("cca_get_stats is unsupported \n")); } /* If cca_get_stats is unsupported, cca_busy_time has zero value as initial value */ cur_channel_stat.cca_busy_time = cca_busy_time; } - ret = memcpy_s(output, WLC_IOCTL_MAXLEN, &radio_h, sizeof(wifi_radio_stat_h)); - if (ret) { - WL_ERR(("Failed to copy wifi_radio_stat_h: %d\n", ret)); + err = wl_cfgvendor_get_radio_stats(cfg, inet_ndev, chan_stats, + num_channels, &output, &total_len); + if (unlikely(err)) { + WL_ERR(("Failed to get radio_stat (%d)\n", err)); goto exit; } - output += sizeof(wifi_radio_stat_h); - - ret = memcpy_s(output, (WLC_IOCTL_MAXLEN - sizeof(wifi_radio_stat_h)), - chan_stats, chan_stats_size); - if (ret) { - WL_ERR(("Failed to copy wifi_channel_stat: %d\n", ret)); - goto exit; - } - output += chan_stats_size; COMPAT_BZERO_IFACE(wifi_iface_stat, iface); +#ifdef LINKSTAT_EXT_SUPPORT + /* Update duty cycle info based on RSDB/VSDB */ + if (wl_cfg80211_determine_rsdb_scc_mode(cfg)) { + COMPAT_ASSIGN_VALUE(iface, info.time_slicing_duty_cycle_percent, + WIFI_RSDB_TIMESLICE_DUTY_CYCLE); + } else { + COMPAT_ASSIGN_VALUE(iface, info.time_slicing_duty_cycle_percent, + WIFI_VSDB_TIMESLICE_DUTY_CYCLE); + } +#endif /* LINKSTAT_EXT_SUPPORT */ COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].ac, WIFI_AC_VO); COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].ac, WIFI_AC_VI); COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].ac, WIFI_AC_BE); COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].ac, WIFI_AC_BK); - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "counters", NULL, 0, + err = wldev_iovar_getbuf(inet_ndev, "counters", NULL, 0, iovar_buf, WLC_IOCTL_MAXLEN, NULL); if (unlikely(err)) { WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wl_cnt_wlc_t))); @@ -7200,30 +8036,47 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, #ifndef DISABLE_IF_COUNTERS if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(wl_if_stats_t)); if (!if_stats) { + WL_ERR(("%s: memory allocation for if_stats failed\n", __func__)); + err = BCME_NOMEM; + goto exit; + } + + if_infra_enh_stats = (wl_if_infra_enh_stats_v2_t *)MALLOCZ(cfg->osh, + sizeof(wl_if_infra_enh_stats_v2_t)); + if (!if_infra_enh_stats) { WL_ERR(("MALLOCZ failed\n")); err = BCME_NOMEM; goto exit; } if (FW_SUPPORTED(dhdp, ifst)) { - err = wl_cfg80211_ifstats_counters(bcmcfg_to_prmry_ndev(cfg), if_stats); + err = wl_cfg80211_if_infra_enh_ifstats_counters(inet_ndev, + if_infra_enh_stats); + if (!err) { + rxbeaconmbss = if_infra_enh_stats->rxbeaconmbss; + } + } + + if (FW_SUPPORTED(dhdp, ifst)) { + err = wl_cfg80211_ifstats_counters(inet_ndev, if_stats); } else { - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "if_counters", + err = wldev_iovar_getbuf(inet_ndev, "if_counters", NULL, 0, (char *)if_stats, sizeof(*if_stats), NULL); } if (!err) { /* Populate from if_stats */ - if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) { + if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION_1) { WL_ERR(("incorrect version of wl_if_stats_t," - " expected=%u got=%u\n", WL_IF_STATS_T_VERSION, + " expected=%u got=%u\n", WL_IF_STATS_T_VERSION_1, if_stats->version)); goto exit; } COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].tx_mpdu, (uint32)if_stats->txframe); COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].rx_mpdu, (uint32)(if_stats->rxframe - if_stats->rxmulti)); - COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].mpdu_lost, (uint32)if_stats->txfail); + COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].mpdu_lost, + (uint32)if_stats->txfail + wlc_cnt->tx_toss_cnt); COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].retries, (uint32)if_stats->txretrans); } else #endif /* !DISABLE_IF_COUNTERS */ @@ -7231,17 +8084,12 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].tx_mpdu, (wlc_cnt->txfrmsnt - wlc_cnt->txmulti)); COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].rx_mpdu, wlc_cnt->rxframe); - COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].mpdu_lost, wlc_cnt->txfail); + COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].mpdu_lost, + wlc_cnt->txfail + wlc_cnt->tx_toss_cnt); COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].retries, wlc_cnt->txretrans); } - err = wl_cfgvendor_lstats_get_bcn_mbss(iovar_buf, &rxbeaconmbss); - if (unlikely(err)) { - WL_ERR(("get_bcn_mbss error (%d)\n", err)); - goto exit; - } - - err = wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg), &scbval); + err = wldev_get_rssi(inet_ndev, &scbval); if (unlikely(err)) { WL_ERR(("get_rssi error (%d)\n", err)); goto exit; @@ -7252,9 +8100,26 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, COMPAT_ASSIGN_VALUE(iface, num_peers, NUM_PEER); COMPAT_ASSIGN_VALUE(iface, peer_info->num_rate, NUM_RATE); +#ifdef LINKSTAT_EXT_SUPPORT + err = wldev_iovar_getbuf(inet_ndev, "bssload_report", NULL, + 0, iovar_buf, WLC_IOCTL_MAXLEN, NULL); + + if (err == BCME_OK) { + bssload = (wl_bssload_t *)iovar_buf; + COMPAT_ASSIGN_VALUE(iface, peer_info->bssload.sta_count, bssload->sta_count); + COMPAT_ASSIGN_VALUE(iface, peer_info->bssload.chan_util, bssload->chan_util); + } else if (err == BCME_UNSUPPORTED) { + WL_ERR(("bssload_report is unsupported \n")); + } else if (err == BCME_NOTASSOCIATED) { + WL_ERR(("bssload_report IOVAR failed. STA is not associated.\n")); + } else { + WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wl_bssload_t))); + goto exit; + } +#endif /* LINKSTAT_EXT_SUPPORT */ COMPAT_MEMCOPY_IFACE(output, total_len, wifi_iface_stat, iface, wifi_rate_stat); - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "ratestat", NULL, 0, + err = wldev_iovar_getbuf(inet_ndev, "ratestat", NULL, 0, iovar_buf, WLC_IOCTL_MAXLEN, NULL); if (err != BCME_OK && err != BCME_UNSUPPORTED) { WL_ERR(("error (%d) - size = %zu\n", err, NUM_RATE*sizeof(wifi_rate_stat))); @@ -7280,56 +8145,129 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, output += sizeof(p_wifi_rate_stat_v1->retries_long); } - total_len = sizeof(wifi_radio_stat_h) + chan_stats_size; - total_len = total_len - sizeof(wifi_peer_info) + - NUM_PEER * (sizeof(wifi_peer_info) - sizeof(wifi_rate_stat_v1) + - NUM_RATE * sizeof(wifi_rate_stat_v1)); + /* Due to flexible array member, '-' operation is required. + * Remove redundant wifi_peer_info[1] size from 'wifi_iface_stat' + * Remove redundant wifi_rate_stat[1] size from 'wifi_peer_info' + */ +#if defined(LINKSTAT_EXT_SUPPORT) || (ANDROID_VERSION >= 12) + total_len = total_len - + sizeof(wifi_peer_info) + + NUM_PEER * (sizeof(wifi_peer_info_v1) - + sizeof(wifi_rate_stat) + + NUM_RATE * sizeof(wifi_rate_stat_v1)); +#else + total_len = total_len - + sizeof(wifi_peer_info) + + NUM_PEER * (sizeof(wifi_peer_info) - + sizeof(wifi_rate_stat) + + NUM_RATE * sizeof(wifi_rate_stat_v1)); +#endif if (total_len > WLC_IOCTL_MAXLEN) { WL_ERR(("Error! total_len:%d is unexpected value\n", total_len)); err = BCME_BADLEN; goto exit; } - err = wl_cfgvendor_send_cmd_reply(wiphy, outdata, total_len); - - if (unlikely(err)) +#if ANDROID_VERSION >= 13 + err = wl_cfgvendor_send_stats_info(wiphy, outdata, total_len); + if (unlikely(err)) { WL_ERR(("Vendor Command reply failed ret:%d \n", err)); + } +#else + err = wl_cfgvendor_send_cmd_reply(wiphy, outdata, total_len); +#endif /* ANDROID_VERSION >= 13 */ exit: + if (cca_req) { + MFREE(cfg->osh, cca_req, cca_req_size); + } +#ifdef LINKSTAT_EXT_SUPPORT + if (all_chan_req) { + MFREE(cfg->osh, all_chan_req, all_chan_req_size); + } +#else + if (cca_v2_req) { + MFREE(cfg->osh, cca_v2_req, cca_v2_req_size); + } + if (cca_v3_req) { + MFREE(cfg->osh, cca_v3_req, cca_v3_req_size); + } +#endif /* LINKSTAT_EXT_SUPPORT */ if (outdata) { MFREE(cfg->osh, outdata, WLC_IOCTL_MAXLEN); } +#ifndef DISABLE_IF_COUNTERS if (if_stats) { MFREE(cfg->osh, if_stats, sizeof(wl_if_stats_t)); } -#ifdef CHAN_STATS_SUPPORT - if (p_chan_stats) { - MFREE(cfg->osh, p_chan_stats, chan_stats_size); + + if (if_infra_enh_stats) { + MFREE(cfg->osh, if_infra_enh_stats, sizeof(wl_if_infra_enh_stats_v2_t)); + } +#endif /* !DISABLE_IF_COUNTERS */ + +#ifdef LINKSTAT_EXT_SUPPORT + if (chan_stats) { + MFREE(cfg->osh, chan_stats, chan_stats_size); } if (per_chspec_stats) { MFREE(cfg->osh, per_chspec_stats, per_chspec_stats_size); } -#endif /* CHAN_STATS_SUPPORT */ +#endif /* LINKSTAT_EXT_SUPPORT */ + +#ifdef RPM_FAST_TRIGGER + WL_INFORM(("Trgger RPM Fast\n")); + dhd_trigger_rpm_fast(cfg); +#endif /* RPM_FAST_TRIGGER */ return err; } #endif /* LINKSTAT_SUPPORT */ #ifdef DHD_LOG_DUMP static int -wl_cfgvendor_get_buf_data(const struct nlattr *iter, struct buf_data **buf) +wl_cfgvendor_get_buf_data(const struct nlattr *iter, struct buf_data *buf) { int ret = BCME_OK; +#ifdef CONFIG_COMPAT +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) + if (in_compat_syscall()) +#else + if (is_compat_task()) +#endif /* LINUX_VER >= 4.6 */ + { + struct compat_buf_data *compat_buf = (struct compat_buf_data *)nla_data(iter); - if (nla_len(iter) != sizeof(struct buf_data)) { - WL_ERR(("Invalid len : %d\n", nla_len(iter))); - ret = BCME_BADLEN; + if (nla_len(iter) != sizeof(struct compat_buf_data)) { + WL_ERR(("Invalid len : %d\n", nla_len(iter))); + ret = BCME_BADLEN; + } + + buf->ver = compat_buf->ver; + buf->len = compat_buf->len; + buf->buf_threshold = compat_buf->buf_threshold; + buf->data_buf[0] = (const void *)compat_ptr(compat_buf->data_buf); } - (*buf) = (struct buf_data *)nla_data(iter); - if (!(*buf) || (((*buf)->len) <= 0) || !((*buf)->data_buf[0])) { + else +#endif /* CONFIG_COMPAT */ + { + if (nla_len(iter) != sizeof(struct buf_data)) { + WL_ERR(("Invalid len : %d\n", nla_len(iter))); + ret = BCME_BADLEN; + } + ret = memcpy_s(buf, sizeof(struct buf_data), (void *)nla_data(iter), nla_len(iter)); + if (ret) { + WL_ERR(("Can't get buf data\n")); + goto exit; + } + } + + if ((buf->len <= 0) || !buf->data_buf[0]) { WL_ERR(("Invalid buffer\n")); ret = BCME_ERROR; } +exit: return ret; + } static int @@ -7342,8 +8280,10 @@ wl_cfgvendor_dbg_file_dump(struct wiphy *wiphy, struct sk_buff *skb = NULL; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); struct buf_data *buf; + struct buf_data data_from_hal; int pos = 0; + RETURN_EIO_IF_NOT_UP(cfg); /* Alloc the SKB for vendor_event */ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, CFG80211_VENDOR_CMD_REPLY_SKB_SZ); if (!skb) { @@ -7351,12 +8291,16 @@ wl_cfgvendor_dbg_file_dump(struct wiphy *wiphy, ret = BCME_NOMEM; goto exit; } - WL_ERR(("%s\n", __FUNCTION__)); + + memset_s(&data_from_hal, sizeof(data_from_hal), 0, sizeof(data_from_hal)); + buf = &data_from_hal; nla_for_each_attr(iter, data, len, rem) { type = nla_type(iter); - ret = wl_cfgvendor_get_buf_data(iter, &buf); + ret = wl_cfgvendor_get_buf_data(iter, buf); if (ret) goto exit; + + WL_DBG_MEM(("%s: type %d\n", __FUNCTION__, type)); switch (type) { case DUMP_BUF_ATTR_MEMDUMP: ret = dhd_os_get_socram_dump(bcmcfg_to_prmry_ndev(cfg), &mem_buf, @@ -7379,6 +8323,25 @@ wl_cfgvendor_dbg_file_dump(struct wiphy *wiphy, buf->data_buf[0], NULL, (uint32)buf->len, &pos); break; #endif /* EWP_ECNTRS_LOGGING */ + +#ifdef EWP_DACS + case DUMP_BUF_ATTR_EWP_HW_INIT_LOG: + ret = dhd_print_init_dump_data(bcmcfg_to_prmry_ndev(cfg), NULL, + buf->data_buf[0], NULL, (uint32)buf->len, &pos, + LOG_DUMP_SECTION_EWP_HW_INIT_LOG); + break; + case DUMP_BUF_ATTR_EWP_HW_MOD_DUMP: + ret = dhd_print_init_dump_data(bcmcfg_to_prmry_ndev(cfg), NULL, + buf->data_buf[0], NULL, (uint32)buf->len, &pos, + LOG_DUMP_SECTION_EWP_HW_MOD_DUMP); + break; + case DUMP_BUF_ATTR_EWP_HW_REG_DUMP: + ret = dhd_print_init_dump_data(bcmcfg_to_prmry_ndev(cfg), NULL, + buf->data_buf[0], NULL, (uint32)buf->len, &pos, + LOG_DUMP_SECTION_EWP_HW_REG_DUMP); + break; +#endif /* EWP_DACS */ + #ifdef DHD_STATUS_LOGGING case DUMP_BUF_ATTR_STATUS_LOG : ret = dhd_print_status_log_data(bcmcfg_to_prmry_ndev(cfg), NULL, @@ -7434,6 +8397,24 @@ wl_cfgvendor_dbg_file_dump(struct wiphy *wiphy, buf->data_buf[0], NULL, (uint32)buf->len, DLD_BUF_TYPE_SPECIAL, &pos); break; +#ifdef DHD_SDTC_ETB_DUMP + case DUMP_BUF_ATTR_SDTC_ETB_DUMP: + ret = dhd_sdtc_etb_hal_file_dump(bcmcfg_to_prmry_ndev(cfg), + buf->data_buf[0], (uint32)buf->len); + break; +#endif /* DHD_SDTC_ETB_DUMP */ +#ifdef DHD_MAP_PKTID_LOGGING + case DUMP_BUF_ATTR_PKTID_MAP_LOG: + ret = dhd_print_pktid_map_log_data(bcmcfg_to_prmry_ndev(cfg), NULL, + buf->data_buf[0], NULL, (uint32)buf->len, &pos, TRUE); + break; + + case DUMP_BUF_ATTR_PKTID_UNMAP_LOG: + ret = dhd_print_pktid_map_log_data(bcmcfg_to_prmry_ndev(cfg), NULL, + buf->data_buf[0], NULL, (uint32)buf->len, &pos, FALSE); + break; +#endif /* DHD_MAP_PKTID_LOGGIN */ + #ifdef DHD_SSSR_DUMP #ifdef DHD_SSSR_DUMP_BEFORE_SR case DUMP_BUF_ATTR_SSSR_C0_D11_BEFORE : @@ -7494,12 +8475,12 @@ wl_cfgvendor_dbg_file_dump(struct wiphy *wiphy, buf->data_buf[0], (uint32)buf->len); break; #endif /* DHD_PKT_LOGGING */ -#ifdef DNGL_AXI_ERROR_LOGGING +#if defined(DNGL_AXI_ERROR_LOGGING) && defined(REPORT_AXI_ERROR) case DUMP_BUF_ATTR_AXI_ERROR: ret = dhd_os_get_axi_error_dump(bcmcfg_to_prmry_ndev(cfg), buf->data_buf[0], (uint32)buf->len); break; -#endif /* DNGL_AXI_ERROR_LOGGING */ +#endif /* DNGL_AXI_ERROR_LOGGING && REPORT_AXI_ERROR */ default: WL_ERR(("Unknown type: %d\n", type)); ret = BCME_ERROR; @@ -7708,14 +8689,14 @@ static int wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { - return WIFI_ERROR_NOT_SUPPORTED; + return -EOPNOTSUPP; } static int wl_cfgvendor_dbg_get_mem_dump(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { - return WIFI_ERROR_NOT_SUPPORTED; + return -EOPNOTSUPP; } #endif /* !DEBUGABILITY_DISABLE_MEMDUMP */ @@ -7829,6 +8810,7 @@ static int wl_cfgvendor_dbg_get_ring_data(struct wiphy *wiphy, { int ret = BCME_OK, rem, type; char ring_name[DBGRING_NAME_MAX] = {0}; + int ring_id; const struct nlattr *iter; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); dhd_pub_t *dhd_pub = cfg->pub; @@ -7845,6 +8827,21 @@ static int wl_cfgvendor_dbg_get_ring_data(struct wiphy *wiphy, } } + /* Moved the dump_start op */ + ring_id = dhd_dbg_find_ring_id(dhd_pub, ring_name); + /* Using first ring get context to trigger ring dump event. */ + if (ring_id == DEBUG_DUMP_RING1_ID) { + /* + * The ring buffer data context timeout at framework is 100ms and + * hence skipping memdump invocation in this path. + */ + dhd_pub->skip_memdump_map_read = true; + WL_MEM(("Doing dump_start op for ring_id %d ring:%s\n", + ring_id, ring_name)); + dhd_log_dump_vendor_trigger(dhd_pub); + } + + WL_DBG_MEM(("Received GET_RING_DATA ring:%s\n", ring_name)); ret = dhd_os_trigger_get_ring_data(dhd_pub, ring_name); if (ret < 0) { WL_ERR(("trigger_get_data failed ret:%d\n", ret)); @@ -7852,6 +8849,54 @@ static int wl_cfgvendor_dbg_get_ring_data(struct wiphy *wiphy, return ret; } + +#ifdef DHD_HAL_RING_DUMP +static int wl_cfgvendor_dbg_get_buf_ring_map(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int ret = BCME_OK; + struct sk_buff *skb = NULL; + int map_cnt = ARRAYSIZE(dhd_buf_ring_map); + int entry_size = sizeof(dhd_buf_ring_map_entry_t); + int i; + + WL_MEM(("map_cnt:%d\n", map_cnt)); + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + nla_total_size(sizeof(dhd_buf_ring_map)) + nla_total_size(sizeof(map_cnt))); + if (!skb) { + WL_ERR(("skb allocation is failed\n")); + ret = BCME_NOMEM; + goto fail; + } + + ret = nla_put_u32(skb, DEBUG_ATTRIBUTE_BUF_RING_NUM, map_cnt); + if (unlikely(ret)) { + goto fail; + } + + for (i = 0; i < map_cnt; i++) { + ret = nla_put(skb, DEBUG_ATTRIBUTE_BUF_RING_MAP, entry_size, + &dhd_buf_ring_map[i]); + if (unlikely(ret)) { + goto fail; + } + } + + ret = cfg80211_vendor_cmd_reply(skb); + if (ret) { + /* kfree_skb is called if it is failed */ + WL_ERR(("Vendor Command reply failed ret:%d \n", ret)); + } + return ret; + +fail: + if (skb) { + kfree_skb(skb); + } + return ret; +} +#endif /* DHD_HAL_RING_DUMP */ #endif /* DEBUGABILITY */ static int wl_cfgvendor_dbg_get_feature(struct wiphy *wiphy, @@ -7884,8 +8929,8 @@ static void wl_cfgvendor_dbg_ring_send_evt(void *ctx, struct sk_buff *skb; struct nlmsghdr *nlh; struct bcm_cfg80211 *cfg; - if (!ndev) { - WL_ERR(("ndev is NULL\n")); + if (ndev == NULL || ndev->ieee80211_ptr == NULL) { + WL_CONS_ONLY(("no device for debug ring id:%d\n", ring_id)); return; } kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; @@ -7894,12 +8939,12 @@ static void wl_cfgvendor_dbg_ring_send_evt(void *ctx, /* If wifi hal is not start, don't send event to wifi hal */ if (!cfg->hal_started) { - WL_ERR(("Hal is not started\n")); + WL_CONS_ONLY(("Hal is not started id:%d\n", ring_id)); return; } /* Alloc the SKB for vendor_event */ #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \ - LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + CFG80211_VENDOR_EVT_SKB_SZ, GOOGLE_DEBUG_RING_EVENT, kflags); #else @@ -7908,7 +8953,7 @@ static void wl_cfgvendor_dbg_ring_send_evt(void *ctx, #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */ /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */ if (!skb) { - WL_ERR(("skb alloc failed")); + WL_CONS_ONLY(("skb alloc failed id:%d\n", ring_id)); return; } /* Set halpid for sending unicast event to wifi hal */ @@ -7921,6 +8966,7 @@ static void wl_cfgvendor_dbg_ring_send_evt(void *ctx, #endif /* DEBUGABILITY */ #ifdef DHD_LOG_DUMP +#ifndef DHD_HAL_RING_DUMP #ifdef DHD_SSSR_DUMP #define DUMP_SSSR_DUMP_MAX_COUNT 8 static int wl_cfgvendor_nla_put_sssr_dump_data(struct sk_buff *skb, @@ -8040,14 +9086,19 @@ static int wl_cfgvendor_nla_put_sssr_dump_data(struct sk_buff *skb, return BCME_OK; } #endif /* DHD_SSSR_DUMP */ +#endif /* DHD_HAL_RING_DUMP */ static int wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff *skb, struct net_device *ndev) { int ret = BCME_OK; uint32 len = 0; - char dump_path[128]; +#ifdef EWP_DACS + int i = 0, j = 0; +#endif +#ifndef DHD_HAL_RING_DUMP + char dump_path[128]; ret = dhd_get_debug_dump_file_name(ndev, NULL, dump_path, sizeof(dump_path)); if (ret < 0) { WL_ERR(("%s: Failed to get debug dump filename\n", __FUNCTION__)); @@ -8060,6 +9111,7 @@ static int wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff *skb, } WL_ERR(("debug_dump path = %s%s\n", dump_path, FILE_NAME_HAL_TAG)); wl_print_verinfo(wl_get_cfg(ndev)); +#endif /* DHD_HAL_RING_DUMP */ len = dhd_get_time_str_len(); if (len) { @@ -8070,6 +9122,7 @@ static int wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff *skb, } } +#ifndef DHD_HAL_RING_DUMP len = dhd_get_dld_len(DLD_BUF_TYPE_GENERAL); if (len) { ret = nla_put_u32(skb, DUMP_LEN_ATTR_GENERAL_LOG, len); @@ -8078,6 +9131,7 @@ static int wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff *skb, goto exit; } } +#endif /* DHD_HAL_RING_DUMP */ #ifdef EWP_ECNTRS_LOGGING len = dhd_get_ecntrs_len(ndev, NULL); if (len) { @@ -8088,6 +9142,22 @@ static int wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff *skb, } } #endif /* EWP_ECNTRS_LOGGING */ + +#ifdef EWP_DACS + j = DUMP_LEN_ATTR_EWP_HW_INIT_LOG; + for (i = LOG_DUMP_SECTION_EWP_HW_INIT_LOG; i <= LOG_DUMP_SECTION_EWP_HW_REG_DUMP; ++i) { + len = dhd_get_init_dump_len(ndev, NULL, i); + if (len) { + ret = nla_put_u32(skb, j, len); + if (unlikely(ret)) { + WL_ERR(("Failed to nla put init dump length, ret=%d\n", ret)); + goto exit; + } + } + ++j; + } +#endif /* EWP_DACS */ +#ifndef DHD_HAL_RING_DUMP len = dhd_get_dld_len(DLD_BUF_TYPE_SPECIAL); if (len) { ret = nla_put_u32(skb, DUMP_LEN_ATTR_SPECIAL_LOG, len); @@ -8096,6 +9166,7 @@ static int wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff *skb, goto exit; } } +#endif /* DHD_HAL_RING_DUMP */ len = dhd_get_dhd_dump_len(ndev, NULL); if (len) { ret = nla_put_u32(skb, DUMP_LEN_ATTR_DHD_DUMP, len); @@ -8126,7 +9197,7 @@ static int wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff *skb, } } #endif - +#ifndef DHD_HAL_RING_DUMP len = dhd_get_dld_len(DLD_BUF_TYPE_PRESERVE); if (len) { ret = nla_put_u32(skb, DUMP_LEN_ATTR_PRESERVE_LOG, len); @@ -8135,7 +9206,7 @@ static int wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff *skb, goto exit; } } - +#endif /* DHD_HAL_RING_DUMP */ len = dhd_get_cookie_log_len(ndev, NULL); if (len) { ret = nla_put_u32(skb, DUMP_LEN_ATTR_COOKIE, len); @@ -8174,10 +9245,30 @@ static int wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff *skb, } } #endif /* EWP_RTT_LOGGING */ +#ifdef DHD_MAP_PKTID_LOGGING + len = dhd_get_pktid_map_logging_len(ndev, NULL, TRUE); + if (len) { + ret = nla_put_u32(skb, DUMP_LEN_ATTR_PKTID_MAP_LOG, len); + if (unlikely(ret)) { + WL_ERR(("Failed to nla put pktid log length, ret=%d", ret)); + goto exit; + } + } + + len = dhd_get_pktid_map_logging_len(ndev, NULL, FALSE); + if (len) { + ret = nla_put_u32(skb, DUMP_LEN_ATTR_PKTID_UNMAP_LOG, len); + if (unlikely(ret)) { + WL_ERR(("Failed to nla put pktid log length, ret=%d", ret)); + goto exit; + } + } +#endif /* DHD_MAP_PKTID_LOGGING */ exit: return ret; } -#ifdef DNGL_AXI_ERROR_LOGGING + +#if defined(DNGL_AXI_ERROR_LOGGING) && defined(REPORT_AXI_ERROR) static void wl_cfgvendor_nla_put_axi_error_data(struct sk_buff *skb, struct net_device *ndev) { @@ -8200,7 +9291,8 @@ static void wl_cfgvendor_nla_put_axi_error_data(struct sk_buff *skb, return; } } -#endif /* DNGL_AXI_ERROR_LOGGING */ +#endif /* DNGL_AXI_ERROR_LOGGING && REPORT_AXI_ERROR */ + #ifdef DHD_PKT_LOGGING static int wl_cfgvendor_nla_put_pktlogdump_data(struct sk_buff *skb, struct net_device *ndev, bool pktlogdbg) @@ -8209,8 +9301,13 @@ static int wl_cfgvendor_nla_put_pktlogdump_data(struct sk_buff *skb, char pktlogdump_path[MEMDUMP_PATH_LEN]; uint32 pktlog_dumpsize = dhd_os_get_pktlog_dump_size(ndev); if (pktlog_dumpsize == 0) { +#ifdef DHD_PKT_LOGGING_DBGRING + /* dump size can be zero. do not fail dump process */ + return BCME_OK; +#else WL_ERR(("Failed to calcuate pktlog len\n")); return BCME_ERROR; +#endif /* DHD_PKT_LOGGING_DBGRING */ } dhd_os_get_pktlogdump_filename(ndev, pktlogdump_path, MEMDUMP_PATH_LEN); @@ -8242,18 +9339,62 @@ static int wl_cfgvendor_nla_put_pktlogdump_data(struct sk_buff *skb, } #endif /* DHD_PKT_LOGGING */ -static int wl_cfgvendor_nla_put_memdump_data(struct sk_buff *skb, - struct net_device *ndev, const uint32 fw_len) +#ifndef DHD_HAL_RING_DUMP +/* There is no appropriate ringbuffer to push etbdump data in google build. + * Disable it until negotiated with Google and the etb data is required. + */ +#ifdef DHD_SDTC_ETB_DUMP +static int wl_cfgvendor_nla_put_sdtc_etb_dump_data(struct sk_buff *skb, struct net_device *ndev) { + dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev); char memdump_path[MEMDUMP_PATH_LEN]; int ret = BCME_OK; + if (!dhdp->sdtc_etb_inited) { + WL_ERR(("sdtc not inited, hence donot collect SDTC dump through HAL\n")); + goto exit; + } + if (dhdp->sdtc_etb_dump_len <= sizeof(etb_info_t)) { + WL_ERR(("ETB is of zero size. Hence donot collect SDTC ETB\n")); + goto exit; + } + dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN, "sdtc_etb_dump"); + ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SDTC_ETB_DUMP, memdump_path); + if (unlikely(ret)) { + WL_ERR(("Failed to nla put stdc etb dump path, ret=%d\n", ret)); + goto exit; + } + + ret = nla_put_u32(skb, DUMP_LEN_ATTR_SDTC_ETB_DUMP, DHD_SDTC_ETB_MEMPOOL_SIZE); + if (unlikely(ret)) { + WL_ERR(("Failed to nla put stdc etb length, ret=%d\n", ret)); + goto exit; + } + +exit: + return ret; +} +#else +static int wl_cfgvendor_nla_put_sdtc_etb_dump_data(struct sk_buff *skb, struct net_device *ndev) +{ + return BCME_OK; +} +#endif /* DHD_SDTC_ETB_DUMP */ +#endif /* DHD_HAL_RING_DUMP */ + +static int wl_cfgvendor_nla_put_memdump_data(struct sk_buff *skb, + struct net_device *ndev, const uint32 fw_len) +{ + int ret = BCME_OK; +#ifndef DHD_HAL_RING_DUMP + char memdump_path[MEMDUMP_PATH_LEN]; dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN, "mem_dump"); ret = nla_put_string(skb, DUMP_FILENAME_ATTR_MEM_DUMP, memdump_path); if (unlikely(ret)) { WL_ERR(("Failed to nla put mem dump path, ret=%d\n", ret)); goto exit; } +#endif /* DHD_HAL_RING_DUMP */ ret = nla_put_u32(skb, DUMP_LEN_ATTR_MEMDUMP, fw_len); if (unlikely(ret)) { WL_ERR(("Failed to nla put mem dump length, ret=%d\n", ret)); @@ -8269,15 +9410,23 @@ static int wl_cfgvendor_nla_put_dump_data(dhd_pub_t *dhd_pub, struct sk_buff *sk { int ret = BCME_OK; -#ifdef DNGL_AXI_ERROR_LOGGING +#if defined(DNGL_AXI_ERROR_LOGGING) && defined(REPORT_AXI_ERROR) if (dhd_pub->smmu_fault_occurred) { wl_cfgvendor_nla_put_axi_error_data(skb, ndev); } -#endif /* DNGL_AXI_ERROR_LOGGING */ +#endif /* DNGL_AXI_ERROR_LOGGING && REPORT_AXI_ERROR */ +#if defined(DHD_FW_COREDUMP) if (dhd_pub->memdump_enabled || (dhd_pub->memdump_type == DUMP_TYPE_BY_SYSDUMP)) { +#endif /* DHD_FW_COREDUMP */ if (((ret = wl_cfgvendor_nla_put_debug_dump_data(skb, ndev)) < 0) || - ((ret = wl_cfgvendor_nla_put_memdump_data(skb, ndev, fw_len)) < 0) || - ((ret = wl_cfgvendor_nla_put_sssr_dump_data(skb, ndev)) < 0)) { + ((ret = wl_cfgvendor_nla_put_memdump_data(skb, ndev, fw_len)) < 0)) { + goto done; + } +#ifndef DHD_HAL_RING_DUMP + if ((ret = wl_cfgvendor_nla_put_sssr_dump_data(skb, ndev)) < 0) { + goto done; + } + if ((ret = wl_cfgvendor_nla_put_sdtc_etb_dump_data(skb, ndev)) < 0) { goto done; } #ifdef DHD_PKT_LOGGING @@ -8285,7 +9434,10 @@ static int wl_cfgvendor_nla_put_dump_data(dhd_pub_t *dhd_pub, struct sk_buff *sk goto done; } #endif /* DHD_PKT_LOGGING */ +#endif /* DHD_HAL_RING_DUMP */ +#if defined(DHD_FW_COREDUMP) } +#endif /* DHD_FW_COREDUMP */ done: return ret; } @@ -8310,7 +9462,7 @@ static void wl_cfgvendor_dbg_send_file_dump_evt(void *ctx, const void *data, wiphy = ndev->ieee80211_ptr->wiphy; /* Alloc the SKB for vendor_event */ #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \ - LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + CFG80211_VENDOR_EVT_SKB_SZ, GOOGLE_FILE_DUMP_EVENT, kflags); #else @@ -8443,15 +9595,15 @@ static int __wl_cfgvendor_dbg_get_pkt_fates(struct wiphy *wiphy, user_buf = (void __user *)(unsigned long) nla_get_u64(iter); break; default: - WL_ERR(("%s: no such attribute %d\n", __FUNCTION__, type)); + WL_ERR(("no such attribute %d\n", type)); ret = -EINVAL; goto exit; } } if (!req_count || !user_buf) { - WL_ERR(("%s: invalid request, user_buf=%p, req_count=%u\n", - __FUNCTION__, user_buf, req_count)); + WL_ERR(("invalid request, user_buf=%p, req_count=%u\n", + user_buf, req_count)); ret = -EINVAL; goto exit; } @@ -8536,6 +9688,13 @@ static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_d uint32 period_msec = 0; const struct nlattr *iter; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = wdev_to_ndev(wdev); + + /* Limit keep alive only on primary interface */ + if (!IS_INET_LINK_NDEV(cfg, ndev)) { + WL_ERR(("keep alive query requested on non primary interface\n")); + return BCME_UNSUPPORTED; + } nla_for_each_attr(iter, data, len, rem) { type = nla_type(iter); @@ -8600,11 +9759,16 @@ static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_d goto exit; } - ret = wl_cfg80211_start_mkeep_alive(cfg, mkeep_alive_id, + ret = wl_cfg80211_start_mkeep_alive(ndev, cfg, mkeep_alive_id, ether_type, ip_pkt, ip_pkt_len, src_mac, dst_mac, period_msec); if (ret < 0) { WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret)); } +#ifdef DHD_CLEANUP_KEEP_ALIVE + else if (ret == BCME_OK) { + setbit(&cfg->mkeep_alive_avail, mkeep_alive_id); + } +#endif /* DHD_CLEANUP_KEEP_ALIVE */ exit: if (ip_pkt) { @@ -8621,6 +9785,13 @@ static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_de uint8 mkeep_alive_id = 0; const struct nlattr *iter; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = wdev_to_ndev(wdev); + + /* Limit keep alive only on primary interface */ + if (!IS_INET_LINK_NDEV(cfg, ndev)) { + WL_ERR(("keep alive query requested on non primary interface\n")); + return BCME_UNSUPPORTED; + } nla_for_each_attr(iter, data, len, rem) { type = nla_type(iter); @@ -8635,16 +9806,21 @@ static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_de } } - ret = wl_cfg80211_stop_mkeep_alive(cfg, mkeep_alive_id); + ret = wl_cfg80211_stop_mkeep_alive(ndev, cfg, mkeep_alive_id); if (ret < 0) { WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret)); } +#ifdef DHD_CLEANUP_KEEP_ALIVE + else if (ret == BCME_OK) { + clrbit(&cfg->mkeep_alive_avail, mkeep_alive_id); + } +#endif /* DHD_CLEANUP_KEEP_ALIVE */ return ret; } #endif /* KEEP_ALIVE */ -#if defined(PKT_FILTER_SUPPORT) && defined(APF) +#if defined(APF) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) const struct nla_policy apf_atrribute_policy[APF_ATTRIBUTE_MAX] = { [APF_ATTRIBUTE_VERSION] = { .type = NLA_U32 }, @@ -8667,7 +9843,7 @@ wl_cfgvendor_apf_get_capabilities(struct wiphy *wiphy, ret = dhd_dev_apf_get_version(ndev, &ver); if (unlikely(ret)) { WL_ERR(("APF get version failed, ret=%d\n", ret)); - return ret; + goto fail; } /* APF memory size limit */ @@ -8675,7 +9851,7 @@ wl_cfgvendor_apf_get_capabilities(struct wiphy *wiphy, ret = dhd_dev_apf_get_max_len(ndev, &max_len); if (unlikely(ret)) { WL_ERR(("APF get maximum length failed, ret=%d\n", ret)); - return ret; + goto fail; } mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2); @@ -8683,28 +9859,34 @@ wl_cfgvendor_apf_get_capabilities(struct wiphy *wiphy, skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); if (unlikely(!skb)) { WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed)); - return -ENOMEM; + ret = -ENOMEM; + goto fail; } ret = nla_put_u32(skb, APF_ATTRIBUTE_VERSION, ver); if (ret < 0) { WL_ERR(("Failed to put APF_ATTRIBUTE_VERSION, ret:%d\n", ret)); - goto exit; + goto fail; } ret = nla_put_u32(skb, APF_ATTRIBUTE_MAX_LEN, max_len); if (ret < 0) { WL_ERR(("Failed to put APF_ATTRIBUTE_MAX_LEN, ret:%d\n", ret)); - goto exit; + goto fail; } ret = cfg80211_vendor_cmd_reply(skb); if (unlikely(ret)) { WL_ERR(("vendor command reply failed, ret=%d\n", ret)); } + return ret; -exit: - /* Free skb memory */ - kfree_skb(skb); + +fail: + if (skb) { + /* Free skb memory */ + kfree_skb(skb); + } + return ret; } @@ -8716,7 +9898,7 @@ wl_cfgvendor_apf_set_filter(struct wiphy *wiphy, const struct nlattr *iter; u8 *program = NULL; u32 program_len = 0; - int ret, tmp, type; + int ret, tmp, type, max_len; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); if (len <= 0) { @@ -8724,6 +9906,15 @@ wl_cfgvendor_apf_set_filter(struct wiphy *wiphy, ret = -EINVAL; goto exit; } + + /* APF memory size limit */ + max_len = 0; + ret = dhd_dev_apf_get_max_len(ndev, &max_len); + if (unlikely(ret)) { + WL_ERR(("APF get maximum length failed, ret=%d\n", ret)); + return ret; + } + nla_for_each_attr(iter, data, len, tmp) { type = nla_type(iter); switch (type) { @@ -8738,7 +9929,7 @@ wl_cfgvendor_apf_set_filter(struct wiphy *wiphy, goto exit; } - if (program_len > WL_APF_PROGRAM_MAX_SIZE) { + if (program_len > max_len) { WL_ERR(("program len is more than expected len\n")); ret = -EINVAL; goto exit; @@ -8790,7 +9981,89 @@ exit: } return ret; } -#endif /* PKT_FILTER_SUPPORT && APF */ + +static int +wl_cfgvendor_apf_read_filter_data(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + struct net_device *ndev = wdev_to_ndev(wdev); + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct sk_buff *skb = NULL; + uint8 *buf = NULL; + int ret, buf_len, max_len, mem_needed; + + /* Get APF memory size limit */ + max_len = 0; + ret = dhd_dev_apf_get_max_len(ndev, &max_len); + if (unlikely(ret)) { + WL_ERR(("APF get maximum length failed, ret=%d\n", ret)); + goto fail; + } + + /* As the IOVar returns the data in 'wl_apf_program_t' structure format, account for this + * also along with the queried APF buffer size for the IOvar buffer. + */ + buf_len = WL_APF_PROGRAM_FIXED_LEN + max_len; + + /* Get APF filter data */ + buf = MALLOCZ(cfg->osh, buf_len); + if (unlikely(!buf)) { + WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, buf_len)); + ret = -ENOMEM; + goto fail; + } + ret = dhd_dev_apf_read_filter_data(ndev, buf, buf_len); + if (unlikely(ret)) { + WL_ERR(("APF get filter data failed, ret=%d\n", ret)); + goto fail; + } + + mem_needed = VENDOR_REPLY_OVERHEAD + ATTRIBUTE_U32_LEN + max_len; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed)); + ret = -ENOMEM; + goto fail; + } + + ret = nla_put_u32(skb, APF_ATTRIBUTE_PROGRAM_LEN, max_len); + if (ret < 0) { + WL_ERR(("Failed to put APF_ATTRIBUTE_MAX_LEN, ret=%d\n", ret)); + goto fail; + } + + /* Skip the initial fixed portion of 'wl_apf_program_t' and copy only the data portion */ + ret = nla_put(skb, APF_ATTRIBUTE_PROGRAM, max_len, (buf + WL_APF_PROGRAM_FIXED_LEN)); + if (ret < 0) { + WL_ERR(("Failed to put APF_ATTRIBUTE_MAX_LEN, ret=%d\n", ret)); + goto fail; + } + + ret = cfg80211_vendor_cmd_reply(skb); + if (unlikely(ret)) { + WL_ERR(("vendor command reply failed, ret=%d\n", ret)); + } + + if (buf) { + MFREE(cfg->osh, buf, buf_len); + } + + return ret; + +fail: + if (buf) { + MFREE(cfg->osh, buf, buf_len); + } + + if (skb) { + /* Free skb memory */ + kfree_skb(skb); + } + + return ret; +} +#endif /* APF */ #ifdef NDO_CONFIG_SUPPORT static int wl_cfgvendor_configure_nd_offload(struct wiphy *wiphy, @@ -8834,7 +10107,6 @@ static int wl_cfgvendor_set_pmk(struct wiphy *wiphy, int rem, type; struct net_device *ndev = wdev_to_ndev(wdev); struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - struct wl_security *sec; bzero(&pmk, sizeof(pmk)); nla_for_each_attr(iter, data, len, rem) { @@ -8857,17 +10129,7 @@ static int wl_cfgvendor_set_pmk(struct wiphy *wiphy, goto exit; } } - - sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); - if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) || - (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) { - ret = wldev_iovar_setbuf(ndev, "okc_info_pmk", pmk.key, pmk.key_len, cfg->ioctl_buf, - WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); - if (ret) { - /* could fail in case that 'okc' is not supported */ - WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", ret)); - } - } + wl_cfg80211_set_okc_pmkinfo(cfg, ndev, pmk, TRUE); ret = wldev_ioctl_set(ndev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk)); WL_INFORM_MEM(("IOVAR set_pmk ret:%d", ret)); @@ -8972,76 +10234,1895 @@ exit: } #endif /* WL_P2P_RAND */ -#ifdef WL_SAR_TX_POWER +#ifdef WL_THERMAL_MITIGATION static int -wl_cfgvendor_tx_power_scenario(struct wiphy *wiphy, +wl_cfgvendor_thermal_mitigation(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { int err = BCME_ERROR, rem, type; + wifi_thermal_mode set_thermal_mode = WIFI_MITIGATION_NONE; struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev)); const struct nlattr *iter; - wifi_power_scenario sar_tx_power_val = WIFI_POWER_SCENARIO_INVALID; - wl_sar_modes_t wifi_tx_power_mode = 0; + u32 duty_cycle = 100; + /* delay_win + * Deadline (in milliseconds) to complete this request, value 0 implies apply + * immediately. Deadline is basically a relaxed limit and allows + * vendors to apply the mitigation within the window (if it cannot + * apply immediately) + * current chip can apply immediately, so will not use this value currently + */ + u32 delay_win = 0; nla_for_each_attr(iter, data, len, rem) { type = nla_type(iter); - if (type == ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO) { - sar_tx_power_val = nla_get_s8(iter); + if (type == ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION) { + set_thermal_mode = nla_get_u32(iter); + WL_INFORM_MEM(("got thermal mode = %d\n", set_thermal_mode)); + } else if (type == ANDR_WIFI_ATTRIBUTE_THERMAL_COMPLETION_WINDOW) { + delay_win = nla_get_u32(iter); + WL_INFORM_MEM(("got delay_win = %d\n", delay_win)); } else { WL_ERR(("Unknown attr type: %d\n", type)); err = -EINVAL; goto exit; } } - /* If sar tx power is already configured, no need to set it again */ - if (cfg->wifi_tx_power_mode == sar_tx_power_val) { - WL_INFORM_MEM(("%s, tx_power_mode %d is already set\n", - __FUNCTION__, sar_tx_power_val)); + /* If thermal mode is already configured, no need to set it again */ + if (cfg->thermal_mode == set_thermal_mode) { + WL_INFORM_MEM(("%s, thermal_mode %d is already set\n", + __FUNCTION__, set_thermal_mode)); err = BCME_OK; goto exit; } - /* Map Android TX power modes to Brcm power mode */ - switch (sar_tx_power_val) { - case WIFI_POWER_SCENARIO_VOICE_CALL: - case WIFI_POWER_SCENARIO_DEFAULT: - wifi_tx_power_mode = HEAD_SAR_BACKOFF_ENABLE; + /* Map Android TX power modes to internal power mode */ + switch (set_thermal_mode) { + case WIFI_MITIGATION_LIGHT: + duty_cycle = DUTY_CYCLE_LIGHT; break; - case WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF: - wifi_tx_power_mode = GRIP_SAR_BACKOFF_DISABLE; + case WIFI_MITIGATION_MODERATE: + duty_cycle = DUTY_CYCLE_MODERATE; break; - case WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF: - wifi_tx_power_mode = GRIP_SAR_BACKOFF_ENABLE; + case WIFI_MITIGATION_SEVERE: + duty_cycle = DUTY_CYCLE_SEVERE; break; - case WIFI_POWER_SCENARIO_ON_BODY_BT: - wifi_tx_power_mode = NR_mmWave_SAR_BACKOFF_ENABLE; + case WIFI_MITIGATION_CRITICAL: + duty_cycle = DUTY_CYCLE_CRITICAL; break; - case WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON: - wifi_tx_power_mode = NR_Sub6_SAR_BACKOFF_DISABLE; - break; - case WIFI_POWER_SCENARIO_ON_BODY_CELL_ON: - wifi_tx_power_mode = NR_Sub6_SAR_BACKOFF_ENABLE; + case WIFI_MITIGATION_EMERGENCY: + duty_cycle = DUTY_CYCLE_EMERGENCY; break; + case WIFI_MITIGATION_NONE: + /* intentional fall-through */ default: - WL_ERR(("invalid wifi tx power scenario = %d\n", - sar_tx_power_val)); + duty_cycle = DUTY_CYCLE_NONE; + break; + } + WL_DBG(("%s, duty_cycle %d thermal_mode %d\n", __FUNCTION__, + duty_cycle, set_thermal_mode)); + err = wldev_iovar_setint(wdev_to_ndev(wdev), "dutycycle_thermal", duty_cycle); + if (unlikely(err)) { + WL_ERR(("%s: Failed to set dutycycle - error (%d)\n", __FUNCTION__, err)); + goto exit; + } + /* Cache the thermal mode sent by the hal */ + cfg->thermal_mode = set_thermal_mode; +exit: + return err; +} +#endif /* WL_THERMAL_MITIGATION */ + +#ifdef WL_SAR_TX_POWER +static int +wl_cfgvendor_tx_power_scenario(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = BCME_ERROR, rem, type; + int8 wifi_tx_power_mode = WIFI_POWER_SCENARIO_INVALID; + struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev)); + const struct nlattr *iter; + sar_advance_modes sar_tx_power_val = SAR_DISABLE; + int airplane_mode = 0; +#if defined(WL_SAR_TX_POWER_CONFIG) + int i = 0; + bool found = FALSE; +#endif /* WL_SAR_TX_POWER_CONFIG */ + + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + if (type == ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO) { + wifi_tx_power_mode = nla_get_s8(iter); + } else { + WL_ERR(("SAR: Unknown attr type: %d\n", type)); err = -EINVAL; goto exit; + } + } + /* If sar tx power is already configured, no need to set it again */ + if (cfg->wifi_tx_power_mode == wifi_tx_power_mode) { + WL_INFORM_MEM(("SAR: tx_power_mode %d is already set\n", + wifi_tx_power_mode)); + err = BCME_OK; + goto exit; } - WL_DBG(("%s, tx_power_mode %d\n", __FUNCTION__, wifi_tx_power_mode)); - err = wldev_iovar_setint(wdev_to_ndev(wdev), "sar_enable", wifi_tx_power_mode); +#if defined(WL_SAR_TX_POWER_CONFIG) + for (i = 0; i < cfg->sar_config_info_cnt; i++) { + if ((wifi_tx_power_mode != WIFI_POWER_SCENARIO_INVALID) && + (cfg->sar_config_info[i].scenario == wifi_tx_power_mode)) { + found = TRUE; + sar_tx_power_val = cfg->sar_config_info[i].sar_tx_power_val; + airplane_mode = cfg->sar_config_info[i].airplane_mode; + WL_DBG(("found scenario with new config\n")); + break; + } + } + + if (!found) +#endif /* WL_SAR_TX_POWER_CONFIG */ + { + /* Map Android TX power modes to Brcm power mode */ + switch (wifi_tx_power_mode) { + case WIFI_POWER_SCENARIO_VOICE_CALL: + case WIFI_POWER_SCENARIO_DEFAULT: + /* SAR disabled */ + sar_tx_power_val = SAR_DISABLE; + airplane_mode = 0; + break; + case WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF: + /* HEAD mode, Airplane */ + sar_tx_power_val = SAR_HEAD; + airplane_mode = 1; + break; + case WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF: + /* GRIP mode, Airplane */ + sar_tx_power_val = SAR_GRIP; + airplane_mode = 1; + break; + case WIFI_POWER_SCENARIO_ON_BODY_BT: + /* BT mode, Airplane */ + sar_tx_power_val = SAR_BT; + airplane_mode = 1; + break; + case WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON: + /* HEAD mode, Normal */ + sar_tx_power_val = SAR_HEAD; + airplane_mode = 0; + break; + case WIFI_POWER_SCENARIO_ON_BODY_CELL_ON: + /* GRIP mode, Normal */ + sar_tx_power_val = SAR_GRIP; + airplane_mode = 0; + break; + default: + WL_ERR(("SAR: invalid wifi tx power scenario = %d\n", + sar_tx_power_val)); + err = -EINVAL; + goto exit; + } + } + WL_DBG_MEM(("SAR: sar_mode %d airplane_mode %d\n", sar_tx_power_val, airplane_mode)); +#ifdef SYNA_SAR_CUSTOMER_PARAMETER + if (sar_tx_power_val) { + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + err = dhd_sar_set_parameter(dhd, sar_tx_power_val); + if (unlikely(err)) { + WL_ERR(("SAR: Failed to set sar_params - error (%d)\n", err)); + goto exit; + } + /* as already set sar_params for sar_enable 1 */ + sar_tx_power_val = 1; + } +#endif /* SYNA_SAR_CUSTOMER_PARAMETER */ + err = wldev_iovar_setint(wdev_to_ndev(wdev), "fccpwrlimit2g", airplane_mode); if (unlikely(err)) { - WL_ERR(("%s: Failed to set sar_enable - error (%d)\n", __FUNCTION__, err)); + WL_ERR(("SAR: Failed to set airplane_mode - error (%d)\n", err)); + goto exit; + } + err = wldev_iovar_setint(wdev_to_ndev(wdev), "sar_enable", sar_tx_power_val); + if (unlikely(err)) { + WL_ERR(("SAR: Failed to set sar_enable - error (%d)\n", err)); goto exit; } /* Cache the tx power mode sent by the hal */ - cfg->wifi_tx_power_mode = sar_tx_power_val; + cfg->wifi_tx_power_mode = wifi_tx_power_mode; + WL_INFORM_MEM(("SAR: tx_power_mode %d SUCCESS\n", wifi_tx_power_mode)); exit: return err; } #endif /* WL_SAR_TX_POWER */ +#ifdef WL_CUSTOM_MAPPING_OF_DSCP +#define UNUSED_PRIO 0xffu +enum andr_user_ac { + BEST_EFFORT = 0, + BACKGROUND = 1, + VIDEO = 2, + VOICE = 3 +}; +const uint8 default_dscp_mapping_table[UP_TABLE_MAX] = +{ + PRIO_8021D_BE, UNUSED_PRIO, UNUSED_PRIO, UNUSED_PRIO, /* 00 ~ 03 */ + UNUSED_PRIO, UNUSED_PRIO, UNUSED_PRIO, UNUSED_PRIO, /* 04 ~ 07 */ + PRIO_8021D_BK, UNUSED_PRIO, PRIO_8021D_BE, UNUSED_PRIO, /* 08 ~ 11 */ + PRIO_8021D_BE, UNUSED_PRIO, PRIO_8021D_BE, UNUSED_PRIO, /* 12 ~ 15 */ + PRIO_8021D_BE, UNUSED_PRIO, PRIO_8021D_EE, UNUSED_PRIO, /* 16 ~ 19 */ + PRIO_8021D_EE, UNUSED_PRIO, PRIO_8021D_EE, UNUSED_PRIO, /* 20 ~ 23 */ + PRIO_8021D_CL, UNUSED_PRIO, PRIO_8021D_CL, UNUSED_PRIO, /* 24 ~ 27 */ + PRIO_8021D_CL, UNUSED_PRIO, PRIO_8021D_CL, UNUSED_PRIO, /* 28 ~ 31 */ + PRIO_8021D_CL, UNUSED_PRIO, PRIO_8021D_CL, UNUSED_PRIO, /* 32 ~ 35 */ + PRIO_8021D_CL, UNUSED_PRIO, PRIO_8021D_CL, UNUSED_PRIO, /* 36 ~ 39 */ + PRIO_8021D_VI, UNUSED_PRIO, UNUSED_PRIO, UNUSED_PRIO, /* 40 ~ 43 */ + PRIO_8021D_VO, UNUSED_PRIO, PRIO_8021D_VO, UNUSED_PRIO, /* 44 ~ 47 */ + PRIO_8021D_NC, UNUSED_PRIO, UNUSED_PRIO, UNUSED_PRIO, /* 48 ~ 51 */ + UNUSED_PRIO, UNUSED_PRIO, UNUSED_PRIO, UNUSED_PRIO, /* 52 ~ 55 */ + PRIO_8021D_NC, UNUSED_PRIO, UNUSED_PRIO, UNUSED_PRIO, /* 56 ~ 59 */ + UNUSED_PRIO, UNUSED_PRIO, UNUSED_PRIO, UNUSED_PRIO /* 60 ~ 63 */ +}; + +static int +wl_set_dscp_default_priority(uint8* table) +{ + int err = BCME_ERROR; + + err = memcpy_s(table, UP_TABLE_MAX, default_dscp_mapping_table, + sizeof(default_dscp_mapping_table)); + if (unlikely(err)) { + WL_ERR(("Fail to set the defalut dscp.\n")); + } + return err; +} + +static int +wl_cfgvendor_custom_mapping_of_dscp(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = BCME_OK, rem, type; + const struct nlattr *iter; + uint32 dscp_start = 0; + uint32 dscp_end = 0; + uint32 access_category = 0; + uint32 priority = 0; + uint32 dscp; + int32 def_dscp_pri; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = wdev_to_ndev(wdev); + u8 *up_table; + + if (ndev == NULL) { + WL_ERR(("Invalid net device, NULL\n")); + err = BCME_ERROR; + goto exit; + } + + up_table = wl_get_up_table_netinfo(cfg, ndev); + if (!up_table) { + up_table = (uint8 *)MALLOCZ(cfg->osh, UP_TABLE_MAX); + if (up_table == NULL) { + WL_ERR(("malloc failure for up_table\n")); + err = BCME_NOMEM; + goto exit; + } + wl_set_dscp_default_priority(up_table); + wl_store_up_table_netinfo(cfg, ndev, up_table); + WL_INFORM(("allocate dscp up_table\n")); + } + + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + if (type == CUSTOM_SETTING_ATTRIBUTE_DSCP_START) { + dscp_start = nla_get_u32(iter); + WL_INFORM(("got to dscp_stat value [%d]\n", dscp_start)); + if (dscp_start >= UP_TABLE_MAX) { + err = -EINVAL; + goto exit; + } + } else if (type == CUSTOM_SETTING_ATTRIBUTE_DSCP_END) { + dscp_end = nla_get_u32(iter); + WL_INFORM(("got to dscp_end value [%d]\n", dscp_end)); + if (dscp_end >= UP_TABLE_MAX) { + err = -EINVAL; + goto exit; + } + } else if (type == CUSTOM_SETTING_ATTRIBUTE_ACCESS_CATEGORY) { + access_category = nla_get_u32(iter); + WL_INFORM(("got to access_category value [%d]\n", access_category)); + switch (access_category) { + case BEST_EFFORT: + priority = PRIO_8021D_BE; + break; + case BACKGROUND: + priority = PRIO_8021D_BK; + break; + case VIDEO: + priority = PRIO_8021D_VI; + break; + case VOICE: + priority = PRIO_8021D_VO; + break; + default: + err = -EINVAL; + goto exit; + break; + } + } else { + WL_ERR(("Unknown attr type: %d\n", type)); + err = -EINVAL; + goto exit; + } + } + + if (dscp_end < dscp_start) { + WL_ERR(("dscp_end is lower than dscp_start.\n")); + return -EINVAL; + } + + /* Verify to set DSCP of user priority. */ + for (dscp = dscp_start; dscp <= dscp_end; dscp++) { + def_dscp_pri = default_dscp_mapping_table[dscp]; + if ((def_dscp_pri != 0xff) && (def_dscp_pri != priority)) { + err = -EINVAL; + WL_ERR(("Request priority is %d from %d to %d.\n", + priority, dscp_start, dscp_end)); + WL_ERR(("But conflict with defalut priority of DSCP %d and priority %d.\n", + dscp, def_dscp_pri)); + goto exit; + } + } + + /* Set the custom DSCP of user priority. */ + err = memset_s(up_table + dscp_start, UP_TABLE_MAX - dscp_start, priority, + dscp_end - dscp_start + 1); + + if (unlikely(err)) { + WL_ERR(("Fail to set table. free table\n")); + MFREE(cfg->osh, up_table, UP_TABLE_MAX); + wl_store_up_table_netinfo(cfg, ndev, NULL); + } + +exit: + return err; + +} + +static int +wl_cfgvendor_custom_mapping_of_dscp_reset(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = wdev_to_ndev(wdev); + u8 *up_table; + + if (ndev == NULL) { + WL_ERR(("Invalid net device, NULL\n")); + return BCME_ERROR; + } + + up_table = wl_get_up_table_netinfo(cfg, ndev); + if (!up_table) { + WL_ERR(("up_table is not ready\n")); + return BCME_ERROR; + } + + wl_set_dscp_default_priority(up_table); + + return BCME_OK; +} +#endif /* WL_CUSTOM_MAPPING_OF_DSCP */ + +int +wl_cfgvendor_multista_set_primary_connection(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = BCME_OK; + struct bcm_cfg80211 *cfg = NULL; + struct net_device *dev = NULL; + + if (wdev == NULL) { + WL_ERR(("Invalid wireless device, NULL\n")); + return -EINVAL; + } + + dev = wdev_to_ndev(wdev); + if (dev == NULL) { + WL_ERR(("Invalid net device, NULL\n")); + return -EINVAL; + } + + cfg = wl_get_cfg(dev); + if (cfg == NULL) { + WL_ERR(("Invalid cfg, NULL\n")); + return -EINVAL; + } + + if (dev != cfg->inet_ndev) { + WL_INFORM_MEM(("primary iface changed from (%s) to %s\n", + cfg->inet_ndev->name, dev->name)); + cfg->inet_ndev = dev; + wl_cfg80211_handle_primary_ifchange(cfg, cfg->inet_ndev); + } else { + WL_INFORM_MEM(("primary iface:%s\n", cfg->inet_ndev->name)); + } + + return err; +} + +static int +wl_cfgvendor_multista_set_use_case(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = BCME_OK; + int rem, type; + const struct nlattr *iter; + wifi_multi_sta_use_case sta_use_case; + + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + if (type == MULTISTA_ATTRIBUTE_USE_CASE) { + sta_use_case = nla_get_u32(iter); + WL_INFORM_MEM(("Multista requested usecase = %d\n", sta_use_case)); + } else { + WL_ERR(("Unknown attr type: %d\n", type)); + err = -EINVAL; + return err; + } + } + + return err; +} + +#if !defined(WL_TWT) && defined(WL_TWT_HAL_IF) +static int +wl_cfgvendor_twt_setup(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + wl_twt_config_t val; + s32 bw; + s32 type, rem_attr; + u8 mybuf[WLC_IOCTL_SMLEN] = {0}; + u8 resp_buf[WLC_IOCTL_SMLEN] = {0}; + const struct nlattr *iter; + uint8 *rem = mybuf; + uint16 rem_len = sizeof(mybuf); + + bzero(&val, sizeof(val)); + val.version = WL_TWT_SETUP_VER; + val.length = sizeof(val.version) + sizeof(val.length); + + /* Default values, Override Below */ + val.desc.flow_flags = 0; + val.desc.wake_time_h = 0xFFFFFFFF; + val.desc.wake_time_l = 0xFFFFFFFF; + val.desc.wake_int_min = 0xFFFFFFFF; + val.desc.wake_int_max = 0xFFFFFFFF; + val.desc.wake_dur_min = 0xFFFFFFFF; + val.desc.wake_dur_max = 0xFFFFFFFF; + val.desc.avg_pkt_num = 0xFFFFFFFF; + val.desc.avg_pkt_size = 0xFFFFFFFF; + + nla_for_each_attr(iter, data, len, rem_attr) { + type = nla_type(iter); + switch (type) { + case ANDR_TWT_ATTR_CONFIG_ID: + /* Config ID */ + val.desc.configID = nla_get_u8(iter); + break; + case ANDR_TWT_ATTR_NEGOTIATION_TYPE: + /* negotiation_type */ + val.desc.negotiation_type = nla_get_u8(iter); + break; + case ANDR_TWT_ATTR_TRIGGER_TYPE: + /* Trigger Type */ + if (nla_get_u8(iter) == 1) { + val.desc.flow_flags |= WL_TWT_FLOW_FLAG_TRIGGER; + } + break; + case ANDR_TWT_ATTR_WAKE_DURATION: + /* Wake Duration */ + val.desc.wake_dur = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_WAKE_INTERVAL: + /* Wake interval */ + val.desc.wake_int = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_WAKETIME_OFFSET: + /* Wake Time parameter */ + val.desc.wake_time_h = 0; + val.desc.wake_time_l = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_WAKE_INTERVAL_MIN: + /* Minimum allowed Wake interval */ + val.desc.wake_int_min = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_WAKE_INTERVAL_MAX: + /* Max Allowed Wake interval */ + val.desc.wake_int_max = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_WAKE_DURATION_MIN: + /* Minimum allowed Wake duration */ + val.desc.wake_dur_min = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_WAKE_DURATION_MAX: + /* Maximum allowed Wake duration */ + val.desc.wake_dur_max = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_AVG_PKT_NUM: + /* Average number of packets */ + val.desc.avg_pkt_num = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_AVG_PKT_SIZE: + /* Average packets size */ + val.desc.avg_pkt_size = nla_get_u32(iter); + break; + default: + WL_ERR(("Invalid setup attribute type %d\n", type)); + break; + } + } + + bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_CONFIG, + sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32); + if (bw != BCME_OK) { + goto exit; + } + + bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt", + mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL); + if (bw < 0) { + WL_ERR(("twt config set failed. ret:%d\n", bw)); + } else { + WL_INFORM(("twt config setup succeeded, config ID %d " + "Negotiation type %d flow flags %d\n", val.desc.configID, + val.desc.negotiation_type, val.desc.flow_flags)); + } + +exit: + return bw; +} + +static int +wl_cfgvendor_twt_teardown(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + wl_twt_teardown_t val; + s32 bw; + s32 type, rem_attr; + u8 mybuf[WLC_IOCTL_SMLEN] = {0}; + u8 res_buf[WLC_IOCTL_SMLEN] = {0}; + const struct nlattr *iter; + uint8 *rem = mybuf; + uint16 rem_len = sizeof(mybuf); + + bzero(&val, sizeof(val)); + val.version = WL_TWT_TEARDOWN_VER; + val.length = sizeof(val.version) + sizeof(val.length); + + /* Default values, Override Below */ + val.teardesc.flow_id = 0xFF; + val.teardesc.bid = 0xFF; + + nla_for_each_attr(iter, data, len, rem_attr) { + type = nla_type(iter); + switch (type) { + case ANDR_TWT_ATTR_CONFIG_ID: + /* Config ID */ + val.configID = nla_get_u8(iter); + break; + case ANDR_TWT_ATTR_NEGOTIATION_TYPE: + /* negotiation_type */ + val.teardesc.negotiation_type = nla_get_u8(iter); + break; + case ANDR_TWT_ATTR_ALL_TWT: + /* all twt */ + val.teardesc.alltwt = nla_get_u8(iter); + break; + default: + WL_ERR(("Invalid teardown attribute type %d\n", type)); + break; + } + } + + bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_TEARDOWN, + sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32); + if (bw != BCME_OK) { + goto exit; + } + + bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt", + mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL); + if (bw < 0) { + WL_ERR(("twt teardown failed. ret:%d\n", bw)); + } else { + WL_INFORM(("twt teardown succeeded, config ID %d " + "Negotiation type %d alltwt %d\n", val.configID, + val.teardesc.negotiation_type, val.teardesc.alltwt)); + } + +exit: + return bw; +} + +static int +wl_cfgvendor_twt_info_frame(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + wl_twt_info_t val; + int bw; + s32 type, rem_attr; + const struct nlattr *iter; + u8 mybuf[WLC_IOCTL_SMLEN] = {0}; + u8 res_buf[WLC_IOCTL_SMLEN] = {0}; + uint8 *rem = mybuf; + uint16 rem_len = sizeof(mybuf); + uint32 val32 = 0; + + bzero(&val, sizeof(val)); + val.version = WL_TWT_INFO_VER; + val.length = sizeof(val.version) + sizeof(val.length); + + /* Default values, Override Below */ + val.infodesc.flow_id = 0xFF; + val.desc.next_twt_h = 0xFFFFFFFF; + val.desc.next_twt_l = 0xFFFFFFFF; + + nla_for_each_attr(iter, data, len, rem_attr) { + type = nla_type(iter); + if (type == ANDR_TWT_ATTR_CONFIG_ID) { + /* Config ID */ + val.configID = nla_get_u8(iter); + } else if (type == ANDR_TWT_ATTR_RESUME_TIME) { + /* Resume offset */ + val32 = nla_get_u32(iter); + if (!((val32 == 0) || (val32 == -1))) { + val.infodesc.next_twt_h = 0; + val.infodesc.next_twt_l = val32; + val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_RESUME; + } + } else if (type == ANDR_TWT_ATTR_ALL_TWT) { + /* all twt */ + val32 = (uint32)nla_get_u8(iter); + if (val32) { + val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_ALL_TWT; + } + } else { + WL_ERR(("Invalid info frame attribute type %d\n", type)); + } + } + + bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_INFO, + sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32); + if (bw != BCME_OK) { + goto exit; + } + + bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt", + mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL); + if (bw < 0) { + WL_ERR(("twt info frame failed. ret:%d\n", bw)); + } else { + WL_INFORM(("twt info frame succeeded, config ID %d\n", val.configID)); + } + +exit: + return bw; +} + +static int +wl_cfgvendor_twt_stats_update_v2(struct wiphy *wiphy, wl_twt_stats_v2_t *stats) +{ + u32 i; + wl_twt_peer_stats_v2_t *peer_stats; + struct sk_buff *skb; + int32 mem_needed; + int ret = BCME_OK; + + mem_needed = BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed)); + ret = -ENOMEM; + goto fail; + } + + ret = nla_put_u32(skb, ANDR_TWT_ATTR_NUM_PEER_STATS, stats->num_stats); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_DEVICE_CAP, ret:%d\n", ret)); + goto fail; + } + + for (i = 0; i < stats->num_stats; i++) { + peer_stats = &stats->peer_stats_list[i]; + + WL_INFORM_MEM(("%u %u %u %u %u", + peer_stats->eosp_dur_avg, peer_stats->tx_pkts_avg, peer_stats->rx_pkts_avg, + peer_stats->tx_pkt_sz_avg, peer_stats->rx_pkt_sz_avg)); + ret = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, peer_stats->configID); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_CONFIG_ID, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_NUM_TX, peer_stats->tx_pkts_avg); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_NUM_TX, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_SIZE_TX, peer_stats->tx_pkt_sz_avg); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_SIZE_TX, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_NUM_RX, peer_stats->rx_pkts_avg); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_NUM_RX, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_SIZE_RX, peer_stats->rx_pkt_sz_avg); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_SIZE_RX, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_EOSP_DUR, peer_stats->eosp_dur_avg); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_EOSP_DUR, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_EOSP_CNT, peer_stats->eosp_count); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_EOSP_CNT, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_NUM_SP, peer_stats->sp_seq); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_NUM_SP, ret:%d\n", ret)); + goto fail; + } + } + + ret = cfg80211_vendor_cmd_reply(skb); + if (unlikely(ret)) { + WL_ERR(("vendor command reply failed, ret=%d\n", ret)); + } + return ret; + +fail: + /* Free skb for failure cases */ + if (skb) { + kfree_skb(skb); + } + return ret; +} + +static int +wl_cfgvendor_send_twt_status_map_v1(struct wiphy *wiphy, uint8 config_id, + wl_twt_status_v1_t *status) +{ + uint i; + int ret = BCME_OK; + wl_twt_sdesc_v0_t *sdesc = NULL; + struct sk_buff *skb; + int32 mem_needed; + + mem_needed = BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed)); + ret = -ENOMEM; + goto fail; + } + + for (i = 0; i < WL_TWT_MAX_ITWT; i ++) { + if ((status->itwt_status[i].configID != WL_TWT_INV_CONFIG_ID) && + (status->itwt_status[i].configID == config_id)) { + sdesc = &status->itwt_status[i].desc; + if (!sdesc) { + WL_ERR(("Failed to fetch the descriptions for the config id %d\n", + config_id)); + goto fail; + } + WL_DBG_MEM(("response o/p for config_id %u: setup_cmd: %d, flow_flags: %u," + " flow_id: %u, channel: %u, wake_dur: %u," + " wake_int: %u, neg_type: %d", + status->itwt_status[i].configID, + (int)sdesc->setup_cmd, sdesc->flow_flags, (int)sdesc->flow_id, + (int)sdesc->channel, sdesc->wake_dur, sdesc->wake_int, + sdesc->negotiation_type)); + + ret = nla_put_u8(skb, ANDR_TWT_ATTRIBUTE_SETUP_CMD, (int)sdesc->setup_cmd); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTRIBUTE_SETUP_CMD, ret:%d\n", + ret)); + goto fail; + } + ret = nla_put_u8(skb, ANDR_TWT_ATTRIBUTE_FLOW_FLAGS, + (int)sdesc->flow_flags); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTRIBUTE_FLOW_FLAGS, ret:%d\n", + ret)); + goto fail; + } + ret = nla_put_u8(skb, ANDR_TWT_ATTRIBUTE_FLOW_ID, (int)sdesc->flow_id); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTRIBUTE_FLOW_ID, ret:%d\n", + ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTRIBUTE_CHANNEL, (int)sdesc->channel); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTRIBUTE_CHANNEL, ret:%d\n", + ret)); + goto fail; + } + ret = nla_put_u8(skb, ANDR_TWT_ATTR_NEGOTIATION_TYPE, + (int)sdesc->negotiation_type); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_NEGOTIATION_TYPE, ret:%d\n", + ret)); + goto fail; + } + + /* Convert to us from ms, as fw expects it in us */ + ret = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_DURATION, + (1000u*sdesc->wake_dur)); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_WAKE_DURATION, ret:%d\n", + ret)); + goto fail; + } + + /* Convert to us from ms, as fw expects it in us */ + ret = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_INTERVAL, + (1000u*sdesc->wake_int)); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_WAKE_INTERVAL, ret:%d\n", + ret)); + goto fail; + } + } + } + + ret = cfg80211_vendor_cmd_reply(skb); + if (unlikely(ret)) { + WL_ERR(("vendor command reply failed, ret=%d\n", ret)); + } + return ret; +fail: + /* Free skb for failure cases */ + if (skb) { + kfree_skb(skb); + } + + return ret; +} + +static int +wl_cfgvendor_twt_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len, bool clear_stats) +{ + wl_twt_stats_cmd_v1_t query; + wl_twt_stats_v2_t stats_v2; + s32 type, rem_attr; + const struct nlattr *iter; + int ret = BCME_OK; + char iovbuf[WLC_IOCTL_SMLEN] = {0, }; + uint8 *pxtlv = NULL; + uint8 *iovresp = NULL; + uint16 buflen = 0, bufstart = 0; + struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev)); + + bzero(&query, sizeof(query)); + query.version = WL_TWT_STATS_CMD_VERSION_1; + query.length = sizeof(query) - OFFSETOF(wl_twt_stats_cmd_v1_t, peer); + + /* Default values, Override Below */ + query.num_bid = 0xFF; + query.num_fid = 0xFF; + + if (clear_stats) { + query.flags |= WL_TWT_STATS_CMD_FLAGS_RESET; + } + nla_for_each_attr(iter, data, len, rem_attr) { + type = nla_type(iter); + if (type == ANDR_TWT_ATTR_CONFIG_ID) { + /* Config ID */ + query.configID = nla_get_u8(iter); + } else { + WL_ERR(("Invalid TWT stats attribute type %d\n", type)); + } + } + + iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (iovresp == NULL) { + WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); + goto exit; + } + + buflen = bufstart = WLC_IOCTL_SMLEN; + pxtlv = (uint8 *)iovbuf; + ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATS, + sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); + goto exit; + } + + if ((ret = wldev_iovar_getbuf(wdev_to_ndev(wdev), "twt", iovbuf, bufstart-buflen, + iovresp, WLC_IOCTL_MEDLEN, NULL))) { + WL_ERR(("twt status failed with err=%d \n", ret)); + goto exit; + } + + if (sizeof(stats_v2) > sizeof(iovresp)) { + WL_ERR(("Invalid len : %ld\n", sizeof(stats_v2))); + ret = BCME_BADLEN; + goto exit; + } + + ret = memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2)); + if (ret) { + WL_ERR(("Failed to copy result: %d\n", ret)); + goto exit; + } + + if (dtoh16(stats_v2.version) == WL_TWT_STATS_VERSION_2) { + if (!clear_stats) { + WL_ERR(("stats query ver %d, \n", dtoh16(stats_v2.version))); + ret = wl_cfgvendor_twt_stats_update_v2(wiphy, (wl_twt_stats_v2_t*)iovresp); + } + } else { + ret = BCME_UNSUPPORTED; + WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(stats_v2.version))); + goto exit; + } + +exit: + if (iovresp) { + MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN); + } + + return ret; +} + +static int +wl_cfgvendor_twt_get_response(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int ret = BCME_OK; + char iovbuf[WLC_IOCTL_SMLEN] = {0, }; + uint8 *pxtlv = NULL; + uint8 *iovresp = NULL; + wl_twt_status_cmd_v1_t status_cmd; + wl_twt_status_v1_t result; + uint16 buflen = 0, bufstart = 0; + s32 type, rem_attr; + const struct nlattr *iter; + struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev)); + + bzero(&status_cmd, sizeof(status_cmd)); + bzero(&result, sizeof(result)); + + status_cmd.version = WL_TWT_CMD_STATUS_VERSION_1; + status_cmd.length = sizeof(status_cmd) - OFFSETOF(wl_twt_status_cmd_v1_t, peer); + + nla_for_each_attr(iter, data, len, rem_attr) { + type = nla_type(iter); + if (type == ANDR_TWT_ATTR_CONFIG_ID) { + /* Config ID */ + status_cmd.configID = nla_get_u8(iter); + } else { + WL_ERR(("Invalid TWT get status attribute type %d\n", type)); + goto exit; + } + } + + iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (iovresp == NULL) { + WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); + goto exit; + } + + buflen = bufstart = WLC_IOCTL_SMLEN; + pxtlv = (uint8 *)iovbuf; + ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATUS, + sizeof(status_cmd), (uint8 *)&status_cmd, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); + goto exit; + } + + if ((ret = wldev_iovar_getbuf(wdev_to_ndev(wdev), "twt", iovbuf, bufstart-buflen, + iovresp, WLC_IOCTL_MEDLEN, NULL))) { + WL_ERR(("Getting twt status failed with err=%d \n", ret)); + goto exit; + } + + if (sizeof(result) > sizeof(iovresp)) { + WL_ERR(("Invalid len : %ld\n", sizeof(result))); + ret = BCME_BADLEN; + goto exit; + } + + ret = memcpy_s(&result, sizeof(result), iovresp, sizeof(result)); + if (ret) { + WL_ERR(("Failed to copy result: %d\n", ret)); + goto exit; + } + + if (dtoh16(result.version) == WL_TWT_CMD_STATUS_VERSION_1) { + ret = wl_cfgvendor_send_twt_status_map_v1(wiphy, status_cmd.configID, &result); + if (ret != BCME_OK) { + WL_ERR(("Failed to send twt response for config_id %d\n", + status_cmd.configID)); + goto exit; + } + } else { + ret = BCME_UNSUPPORTED; + WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version))); + } + +exit: + if (iovresp) { + MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN); + } + return ret; +} + +static int +wl_cfgvendor_twt_get_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + return wl_cfgvendor_twt_stats(wiphy, wdev, data, len, false); +} + +static int +wl_cfgvendor_twt_clear_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + return wl_cfgvendor_twt_stats(wiphy, wdev, data, len, true); +} + +static int +wl_cfgvendor_twt_update_cap(struct wiphy *wiphy, wl_twt_cap_t *result) +{ + struct sk_buff *skb; + int32 mem_needed; + int ret = BCME_OK; + + WL_INFORM_MEM(("TWT Capabilites Device,Peer 0x%04x 0x%04x\n", + result->device_cap, result->peer_cap)); + + mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed)); + ret = -ENOMEM; + goto fail; + } + + ret = nla_put_u32(skb, ANDR_TWT_ATTR_DEVICE_CAP, result->device_cap); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_DEVICE_CAP, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_PEER_CAP, result->peer_cap); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_PEER_CAP, ret:%d\n", ret)); + goto fail; + } + + ret = cfg80211_vendor_cmd_reply(skb); + if (unlikely(ret)) { + WL_ERR(("vendor command reply failed, ret=%d\n", ret)); + } + return ret; + +fail: + /* Free skb for failure cases */ + if (skb) { + kfree_skb(skb); + } + return ret; +} + +static int +wl_cfgvendor_twt_cap(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int ret = BCME_OK; + char iovbuf[WLC_IOCTL_SMLEN] = {0, }; + uint8 *pxtlv = NULL; + uint8 *iovresp = NULL; + wl_twt_cap_cmd_t cmd_cap; + wl_twt_cap_t result; + + uint16 buflen = 0, bufstart = 0; + struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev)); + + bzero(&cmd_cap, sizeof(cmd_cap)); + + cmd_cap.version = WL_TWT_CAP_CMD_VERSION_1; + cmd_cap.length = sizeof(cmd_cap) - OFFSETOF(wl_twt_cap_cmd_t, peer); + + iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (iovresp == NULL) { + WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); + goto exit; + } + + buflen = bufstart = WLC_IOCTL_SMLEN; + pxtlv = (uint8 *)iovbuf; + + ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_CAP, + sizeof(cmd_cap), (uint8 *)&cmd_cap, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); + goto exit; + } + + if ((ret = wldev_iovar_getbuf(wdev_to_ndev(wdev), "twt", iovbuf, bufstart-buflen, + iovresp, WLC_IOCTL_MEDLEN, NULL))) { + WL_ERR(("Getting twt status failed with err=%d \n", ret)); + goto exit; + } + + if (sizeof(result) > sizeof(iovresp)) { + WL_ERR(("Invalid len : %ld\n", sizeof(result))); + ret = BCME_BADLEN; + goto exit; + } + + ret = memcpy_s(&result, sizeof(result), iovresp, sizeof(result)); + if (ret) { + WL_ERR(("Failed to copy result: %d\n", ret)); + goto exit; + } + + if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) { + WL_ERR(("capability ver %d, \n", dtoh16(result.version))); + ret = wl_cfgvendor_twt_update_cap(wiphy, &result); + return ret; + } else { + ret = BCME_UNSUPPORTED; + WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version))); + goto exit; + } + +exit: + if (iovresp) { + MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN); + } + + return ret; +} + +static int +wl_cfgvendor_twt_update_setup_response(struct sk_buff *skb, void *event_data) +{ + s32 err = BCME_OK; + const wl_twt_setup_cplt_t *setup_cplt = (wl_twt_setup_cplt_t *)event_data; + const wl_twt_sdesc_v0_t *sdesc = (const wl_twt_sdesc_v0_t *)&setup_cplt[1]; + + WL_DBG(("TWT_SETUP: status %d, reason %d, configID %d, setup_cmd %d, flow_flags 0x%x," + " flow_id %d, channel %d, negotiation_type %d, wake_time_h %u, wake_time_l %u," + " wake_dur %u, wake_int %u\n", + (int)setup_cplt->status, (int)setup_cplt->reason_code, (int)setup_cplt->configID, + (int)sdesc->setup_cmd, sdesc->flow_flags, (int)sdesc->flow_id, (int)sdesc->channel, + (int)sdesc->negotiation_type, sdesc->wake_time_h, sdesc->wake_time_l, + sdesc->wake_dur, sdesc->wake_int)); + + err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_SETUP); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, setup_cplt->configID); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_CONFIG_ID failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, setup_cplt->reason_code); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_REASON_CODE failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(setup_cplt->status)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_STATUS failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_NEGOTIATION_TYPE, sdesc->negotiation_type); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_NEGOTIATION_TYPE failed\n")); + goto fail; + } + err = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_DURATION, sdesc->wake_dur); + if (unlikely(err)) { + WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKE_DURATION failed\n")); + goto fail; + } + err = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_INTERVAL, sdesc->wake_int); + if (unlikely(err)) { + WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKE_INTERVAL failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_TRIGGER_TYPE, + !!(sdesc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_TRIGGER_TYPE failed\n")); + goto fail; + } + +fail: + return err; +} + +static int +wl_cfgvendor_twt_update_teardown_response(struct sk_buff *skb, void *event_data) +{ + s32 err = BCME_OK; + const wl_twt_teardown_cplt_t *td_cplt = (wl_twt_teardown_cplt_t *)event_data; + const wl_twt_teardesc_t *teardesc = (const wl_twt_teardesc_t *)&td_cplt[1]; + + WL_DBG(("TWT_TEARDOWN: status %d, reason %d, configID %d, flow_id %d, negotiation_type %d," + " bid %d, alltwt %d\n", (int)td_cplt->status, (int)td_cplt->reason_code, + (int)td_cplt->configID, (int)teardesc->flow_id, (int)teardesc->negotiation_type, + (int)teardesc->bid, (int)teardesc->alltwt)); + + err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_TEARDOWN); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, td_cplt->reason_code); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_REASON_CODE failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(td_cplt->status)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_STATUS failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, td_cplt->configID); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_CONFIG_ID failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_ALL_TWT, teardesc->alltwt); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_ALL_TWT failed\n")); + goto fail; + } + +fail: + return err; +} + +static int +wl_cfgvendor_twt_update_infoframe_response(struct sk_buff *skb, void *event_data) +{ + s32 err = BCME_OK; + const wl_twt_info_cplt_t *info_cplt = (wl_twt_info_cplt_t *)event_data; + const wl_twt_infodesc_t *infodesc = (const wl_twt_infodesc_t *)&info_cplt[1]; + + WL_DBG(("TWT_INFOFRM: status %d, reason %d, configID %d, flow_flags 0x%x, flow_id %d," + " next_twt_h %u, next_twt_l %u\n", (int)info_cplt->status, + (int)info_cplt->reason_code, (int)info_cplt->configID, infodesc->flow_flags, + (int)infodesc->flow_id, infodesc->next_twt_h, infodesc->next_twt_l)); + + err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_INFO_FRM); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, info_cplt->reason_code); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_REASON_CODE failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(info_cplt->status)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_STATUS failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, info_cplt->configID); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_CONFIG_ID failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_ALL_TWT, + !!(infodesc->flow_flags & WL_TWT_INFO_FLAG_ALL_TWT)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_TWT_RESUMED failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_TWT_RESUMED, + !!(infodesc->flow_flags & WL_TWT_INFO_FLAG_RESUME)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_TWT_RESUMED failed\n")); + goto fail; + } + +fail: + return err; +} + +static int +wl_cfgvendor_twt_update_notify_response(struct sk_buff *skb, void *event_data) +{ + s32 err = BCME_OK; + const wl_twt_notify_t *notif_cplt = (wl_twt_notify_t *)event_data; + + WL_DBG(("TWT_NOTIFY: notification %d\n", (int)notif_cplt->notification)); + + err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_NOTIFY); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n")); + goto fail; + } + + err = nla_put_u8(skb, ANDR_TWT_ATTR_TWT_NOTIFICATION, notif_cplt->notification); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_NOTIFICATION failed\n")); + goto fail; + } + +fail: + return err; +} + +s32 +wl_cfgvendor_notify_twt_event(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) +{ + struct sk_buff *skb = NULL; + gfp_t kflags; + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + int err = BCME_OK; + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + const wl_twt_event_t *twt_event = (wl_twt_event_t *)data; + + kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), + BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN, BRCM_VENDOR_EVENT_TWT, kflags); + if (!skb) { + WL_ERR(("skb alloc failed")); + err = BCME_NOMEM; + goto fail; + } + + switch (twt_event->event_type) { + case WL_TWT_EVENT_SETUP: + err = wl_cfgvendor_twt_update_setup_response(skb, + (void*)twt_event->event_info); + break; + case WL_TWT_EVENT_TEARDOWN: + err = wl_cfgvendor_twt_update_teardown_response(skb, + (void*)twt_event->event_info); + break; + case WL_TWT_EVENT_INFOFRM: + err = wl_cfgvendor_twt_update_infoframe_response(skb, + (void*)twt_event->event_info); + break; + case WL_TWT_EVENT_NOTIFY: + err = wl_cfgvendor_twt_update_notify_response(skb, + (void*)twt_event->event_info); + break; + default: + WL_ERR(("Invalid TWT sub event type %d", twt_event->event_type)); + err = BCME_UNSUPPORTED; + break; + } + + if (err) { + goto fail; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + cfg80211_vendor_event(skb, kflags); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ + WL_INFORM(("Successfully sent TWT vendor event type %d\n", twt_event->event_type)); + return BCME_OK; + +fail: + /* Free skb for failure cases */ + if (skb) { + kfree_skb(skb); + } + + return err; +} +#endif /* !WL_TWT && WL_TWT_HAL_IF */ + +#ifdef SUPPORT_OTA_UPDATE +static void +wl_set_ota_nvram_ext(dhd_pub_t *dhd) +{ +#if defined(USE_CID_CHECK) + naming_info_t *info = NULL; + bool is_murata_fem = FALSE; + ota_update_info_t *ota_info = &dhd->ota_update_info; + + info = dhd_find_naming_info_by_chip_rev(dhd, &is_murata_fem); + if (info) { + WL_INFORM(("Nvram extension prefix is [%s].\n", info->nvram_ext)); + strlcpy(ota_info->nvram_ext, info->nvram_ext, MAX_EXT_INFO_LEN); + } + else { + WL_ERR(("info is null\n")); + } +#endif /* USE_CID_CHECK */ + return; +} + +static int +wl_cfgvendor_get_ota_current_info(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int ret, mem_needed; + struct sk_buff *skb = NULL; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_pub_t *dhd_pub = cfg->pub; + ota_update_info_t *ota_info = &dhd_pub->ota_update_info; + + WL_DBG(("Recv get ota current info cmd.\n")); + + mem_needed = VENDOR_REPLY_OVERHEAD + MAX_EXT_INFO_LEN; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed)); + ret = -ENOMEM; + goto exit; + } + + ret = nla_put_string(skb, OTA_CUR_NVRAM_EXT_ATTR, ota_info->nvram_ext); + if (unlikely(ret)) { + WL_ERR(("Failed to put ota_nvram_ext string, ret=%d\n", ret)); + goto exit; + } + + ret = cfg80211_vendor_cmd_reply(skb); + if (unlikely(ret)) { + WL_ERR(("Vendor cmd reply for -get wake status failed:%d \n", ret)); + } + /* On cfg80211_vendor_cmd_reply() skb is consumed and freed in case of success or failure */ + return ret; + +exit: + /* Free skb memory */ + if (skb) { + kfree_skb(skb); + } + return ret; + +} + +static int +wl_cfgvendor_ota_download(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = BCME_OK; + int rem, type; + const struct nlattr *iter; + char* buf[1]; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + dhd_pub_t *dhdp = cfg->pub; +#if defined(WLAN_ACCEL_BOOT) + struct net_device *net = wdev->netdev; +#endif /* WLAN_ACCEL_BOOT */ + ota_update_info_t *ota_info = &dhdp->ota_update_info; + + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + switch (type) { + case OTA_DOWNLOAD_CLM_LENGTH_ATTR: + ota_info->clm_len = nla_get_u32(iter); + WL_INFORM_MEM(("Set to OTA clm length to [%d].\n", + ota_info->clm_len)); + break; + case OTA_DOWNLOAD_CLM_ATTR: + if (!ota_info->clm_len) { + err = -EINVAL; + WL_ERR(("clm length is invalid\n")); + goto exit; + } + memcpy_s(buf, sizeof(*buf), + (void *)nla_data(iter), nla_len(iter)); + ota_info->clm_buf = MALLOCZ(cfg->osh, ota_info->clm_len); + if (ota_info->clm_buf == NULL) { + err = -ENOMEM; + WL_ERR(("Allocte fail size [%d]\n", ota_info->clm_len)); + goto exit; + } + err = copy_from_user(ota_info->clm_buf, buf[0], + ota_info->clm_len); + if (err) { + WL_ERR(("Failed copy_from_user for ota_clm_buf.\n")); + goto exit; + } + break; + case OTA_DOWNLOAD_NVRAM_LENGTH_ATTR: + ota_info->nvram_len = nla_get_u32(iter); + WL_INFORM_MEM(("Set the OTA nvram length to [%d]\n", + ota_info->nvram_len)); + break; + case OTA_DOWNLOAD_NVRAM_ATTR: + if (!ota_info->nvram_len) { + err = -EINVAL; + WL_ERR(("clm length is invalid\n")); + goto exit; + } + memcpy_s(buf, sizeof(*buf), + (void *)nla_data(iter), nla_len(iter)); + ota_info->nvram_buf = MALLOCZ(cfg->osh, ota_info->nvram_len); + if (ota_info->nvram_buf == NULL) { + err = -ENOMEM; + WL_ERR(("Allocte fail size [%d]\n", ota_info->nvram_len)); + goto exit; + } + err = copy_from_user(ota_info->nvram_buf, buf[0], + ota_info->nvram_len); + if (err) { + WL_ERR(("Failed copy_from_user for ota_nvram_buf.\n")); + goto exit; + } + break; + case OTA_SET_FORCE_REG_ON: + { +#if defined(WLAN_ACCEL_BOOT) + uint force_reg_on = nla_get_u32(iter); + if (force_reg_on == TRUE) { + dhd_dev_set_accel_force_reg_on(net); + } +#endif /* WLAN_ACCEL_BOOT */ + } + break; + default: + WL_ERR(("Unknown attr type: %d\n", type)); + err = -EINVAL; + goto exit; + break; + } + } + return err; +exit: + if (ota_info->clm_buf) { + MFREE(cfg->osh, ota_info->clm_buf, ota_info->clm_len); + } + if (ota_info->nvram_buf) { + MFREE(cfg->osh, ota_info->nvram_buf, ota_info->nvram_len); + } + ota_info->clm_len = 0; + ota_info->nvram_len = 0; + return err; +} +#endif /* SUPPORT_OTA_UPDATE */ + +#ifdef OEM_ANDROID +static int +wl_cfgvendor_set_dtim_config(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = BCME_OK, rem, type; + const struct nlattr *iter; + uint32 dtim_multiplier; + int set = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *net = wdev->netdev; + + nla_for_each_attr(iter, data, len, rem) { + type = nla_type(iter); + switch (type) { + case ANDR_WIFI_ATTRIBUTE_DTIM_MULTIPLIER: + dtim_multiplier = nla_get_u32(iter); + WL_INFORM_MEM(("dtim multiplier %d\n", dtim_multiplier)); + set = (dtim_multiplier > 0) ? FALSE : TRUE; + cfg->suspend_bcn_li_dtim = dtim_multiplier; + cfg->max_dtim_enable = set ? TRUE : FALSE; + if (cfg->soft_suspend) { + wl_cfg80211_set_suspend_bcn_li_dtim(cfg, net, TRUE); + } + break; + default: + WL_ERR(("Unknown type: %d\n", type)); + return err; + } + } + + return err; + +} +#endif /* OEM_ANDROID */ + +#ifdef WL_USABLE_CHAN +static int wl_cfgvendor_get_usable_channels(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + usable_channel_info_t u_info; + usable_channel_t u_chan; + struct sk_buff *skb; + int ret = BCME_OK; + s32 type, rem_attr; + const struct nlattr *iter; + int i = 0; + uint32 uchan_item_size = 0, uchan_data_len = 0; + int off = 0; + char *uchan_data = NULL; + + nla_for_each_attr(iter, data, len, rem_attr) { + type = nla_type(iter); + switch (type) { + case USABLECHAN_ATTRIBUTE_BAND: + u_info.band_mask = nla_get_u32(iter); + break; + case USABLECHAN_ATTRIBUTE_IFACE: + u_info.iface_mode_mask = nla_get_u32(iter); + break; + case USABLECHAN_ATTRIBUTE_FILTER: + u_info.filter_mask = nla_get_u32(iter); + break; + case USABLECHAN_ATTRIBUTE_MAX_SIZE: + u_info.max_size = nla_get_u32(iter); + break; + default: + WL_ERR(("Invalid usable_chan attribute type %d\n", type)); + break; + } + } + WL_INFORM_MEM(("usable channel param band:%u iface:%u filter:%u max_size:%u\n", + u_info.band_mask, u_info.iface_mode_mask, u_info.filter_mask, u_info.max_size)); + + if (u_info.max_size == 0 || u_info.band_mask == 0 || u_info.iface_mode_mask == 0) { + WL_ERR(("Invalid param band:%u iface:%u filter:%u max_size:%u\n", + u_info.band_mask, u_info.iface_mode_mask, + u_info.filter_mask, u_info.max_size)); + return -EINVAL; + } + + if (u_info.max_size > USABLE_CHAN_MAX_SIZE) { + WL_ERR(("Too big max_size band:%u iface:%u filter:%u max_size:%u limit:%u\n", + u_info.band_mask, u_info.iface_mode_mask, + u_info.filter_mask, u_info.max_size, USABLE_CHAN_MAX_SIZE)); + return -EINVAL; + } + + u_info.channels = MALLOCZ(cfg->osh, sizeof(*u_info.channels) * u_info.max_size); + if (!u_info.channels) { + WL_ERR(("failed to allocate channels buffer\n")); + return -ENOMEM; + } + + ret = wl_get_usable_channels(cfg, &u_info); + if (ret) { + WL_ERR(("can not get channel list from FW err:%d\n", ret)); + goto exit; + } + + uchan_item_size = sizeof(u_chan.freq) + sizeof(u_chan.width) + + sizeof(u_chan.iface_mode_mask); + uchan_data_len = uchan_item_size * u_info.size; + /* Only freq, width and iface_mode_mask in usable_channel_t send to HAL */ + uchan_data = MALLOC(cfg->osh, uchan_data_len); + if (!uchan_data) { + WL_ERR(("failed to allocate sending buffer\n")); + ret = -ENOMEM; + goto exit; + } + + for (i = 0; i < u_info.size; i++) { + memcpy_s(uchan_data + off, uchan_data_len, &u_info.channels[i], uchan_item_size); + off += uchan_item_size; + } + + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + nla_total_size(uchan_data_len) + + nla_total_size(sizeof(u_info.size))); + if (!skb) { + WL_ERR(("skb allocation is failed\n")); + ret = -ENOMEM; + goto exit; + } + + (void)nla_put_u32(skb, USABLECHAN_ATTRIBUTE_SIZE, u_info.size); + (void)nla_put(skb, USABLECHAN_ATTRIBUTE_CHANNELS, uchan_data_len, uchan_data); + + ret = cfg80211_vendor_cmd_reply(skb); + + if (ret) { + WL_ERR(("Vendor Command reply failed ret:%d \n", ret)); + } +exit: + if (uchan_data) { + MFREE(cfg->osh, uchan_data, uchan_data_len); + } + + if (u_info.channels) { + MFREE(cfg->osh, u_info.channels, sizeof(*u_info.channels) * u_info.max_size); + } + + return ret; +} +#endif /* WL_USABLE_CHAN */ + +#if defined(WLAN_ACCEL_BOOT) +static int +wl_cfgvendor_trigger_ssr(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + WL_INFORM_MEM(("trigger subsystem recovery\n")); + dhd_dev_set_accel_force_reg_on(wdev->netdev); + + return BCME_OK; +} +#endif /* WLAN_ACCEL_BOOT */ + +const struct nla_policy wifi_tx_power_limits_attr_policy[TX_POWER_ATTRIBUTE_MAX] = { + [TX_POWER_CAP_ENABLE_ATTRIBUTE] = { .type = NLA_U8 }, +}; + +int +wl_cfgvendor_set_tx_power_policy_handler(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int ret = BCME_OK; + int attr_type; + int rem = len; + const struct nlattr *iter; + bool pwr_lmt_enab = false; + + nla_for_each_attr(iter, data, len, rem) { + attr_type = nla_type(iter); + + switch (attr_type) { + case TX_POWER_CAP_ENABLE_ATTRIBUTE: { + if (nla_len(iter) != sizeof(uint8)) { + WL_ERR(("Invalid value of tx_power cap\n")); + ret = -EINVAL; + break; + } + pwr_lmt_enab = nla_get_u8(iter); + break; + } + /* Add new attributes here */ + default: + WL_ERR(("Unknown type %d\n", attr_type)); + ret = -EINVAL; + goto exit; + } + } + + WL_DBG_MEM(("wl phy_peak_curr_txpwrcap (%d)\n", pwr_lmt_enab)); + ret = wldev_iovar_setint(wdev_to_ndev(wdev), "phy_peak_curr_txpwrcap", pwr_lmt_enab); + if (unlikely(ret)) { + WL_ERR(("txpwrcap set failed with error %d\n", ret)); + goto exit; + } +exit: + return ret; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) +const struct nla_policy wifi_radio_combo_attr_policy[ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MAX] = { + [ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MATRIX] = { .type = NLA_BINARY }, +}; +#endif /* LINUX_VERSION >= 5.3 */ + +wifi_radio_configuration radio6_2x2[] = {{WLAN_MAC_6_0_BAND, WIFI_ANTENNA_2X2}}; +wifi_radio_configuration radio5_2x2[] = {{WLAN_MAC_5_0_BAND, WIFI_ANTENNA_2X2}}; +wifi_radio_configuration radio2_2x2[] = {{WLAN_MAC_2_4_BAND, WIFI_ANTENNA_2X2}}; +wifi_radio_configuration radio25_2x2[] = {{WLAN_MAC_2_4_BAND, WIFI_ANTENNA_2X2}, + {WLAN_MAC_5_0_BAND, WIFI_ANTENNA_2X2}}; +wifi_radio_configuration radio26_2x2[] = {{WLAN_MAC_2_4_BAND, WIFI_ANTENNA_2X2}, + {WLAN_MAC_6_0_BAND, WIFI_ANTENNA_2X2}}; + +static int +wl_cfgvendor_get_radio_combo_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + struct net_device *ndev = wdev_to_ndev(wdev); + struct sk_buff *skb = NULL; + int err, mem_needed; + struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + u8 buf[WLC_IOCTL_SMLEN] = {0}; + u32 total_len = 0, size = 0; + wifi_radio_combination *radio_combinations = NULL; + wifi_radio_combination_matrix *rc = NULL; + + if (sizeof(buf) < MAX_RADIO_MATRIX_SIZE) { + WL_ERR(("Buff too short: %zd, exp max_radio matrix size: %zd\n", + sizeof(buf), MAX_RADIO_MATRIX_SIZE)); + err = BCME_BUFTOOSHORT; + goto fail; + } + + rc = (wifi_radio_combination_matrix *)buf; + (void)memset_s(&buf, sizeof(buf), 0x0, sizeof(buf)); + radio_combinations = rc->radio_combinations; + total_len = sizeof(u32); + + /* Fill up stand alone cases first and conditionally include rsdb & 6G */ + radio_combinations->num_radio_combinations = 1; + (void)(memcpy_s(radio_combinations->radio_configurations, + sizeof(radio2_2x2), (void *)radio2_2x2, sizeof(radio2_2x2))); + total_len += size = sizeof(u32) + sizeof(radio2_2x2); + rc->num_combinations++; + + radio_combinations = (wifi_radio_combination *)((u8 *)radio_combinations + size); + radio_combinations->num_radio_combinations = 1; + (void)(memcpy_s(radio_combinations->radio_configurations, + sizeof(radio5_2x2), (void *)radio5_2x2, sizeof(radio5_2x2))); + total_len += size = sizeof(u32) + sizeof(radio5_2x2); + rc->num_combinations++; + +#ifdef WL_6G_BAND + if (cfg->band_6g_supported) { + radio_combinations = (wifi_radio_combination *)((u8 *)radio_combinations + size); + radio_combinations->num_radio_combinations = 1; + (void)(memcpy_s(radio_combinations->radio_configurations, + sizeof(radio6_2x2), radio6_2x2, sizeof(radio6_2x2))); + total_len += size = sizeof(u32) + sizeof(radio6_2x2); + rc->num_combinations++; + } +#endif /* WL_6G_BAND */ + + if (FW_SUPPORTED(dhdp, rsdb)) { + radio_combinations = (wifi_radio_combination *)((u8 *)radio_combinations + size); + radio_combinations->num_radio_combinations = 2; + (void)memcpy_s(radio_combinations->radio_configurations, + sizeof(radio25_2x2), radio25_2x2, sizeof(radio25_2x2)); + total_len += size = sizeof(u32) + sizeof(radio25_2x2); + rc->num_combinations++; + +#ifdef WL_6G_BAND + if (cfg->band_6g_supported) { + radio_combinations = + (wifi_radio_combination *)((u8 *)radio_combinations + size); + radio_combinations->num_radio_combinations = 2; + (void)memcpy_s(radio_combinations->radio_configurations, + sizeof(radio26_2x2), radio26_2x2, sizeof(radio26_2x2)); + total_len += size = sizeof(u32) + sizeof(radio26_2x2); + rc->num_combinations++; + } +#endif /* WL_6G_BAND */ + } + + mem_needed = VENDOR_REPLY_OVERHEAD + total_len; + /* Alloc the SKB for vendor_event */ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("skb alloc failed")); + err = -ENOMEM; + goto fail; + } + + err = nla_put(skb, ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MATRIX, total_len, rc); + if (unlikely(err)) { + WL_ERR(("nla_put ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MATRIX failed\n")); + goto fail; + } + + err = cfg80211_vendor_cmd_reply(skb); + if (unlikely(err)) { + WL_ERR(("Vendor Command reply failed err:%d \n", err)); + } + return err; + +fail: + if (skb) { + /* Free skb memory */ + kfree_skb(skb); + } + + return err; +} + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) const struct nla_policy andr_wifi_attr_policy[ANDR_WIFI_ATTRIBUTE_MAX] = { [ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET] = { .type = NLA_U32 }, @@ -9052,6 +12133,7 @@ const struct nla_policy andr_wifi_attr_policy[ANDR_WIFI_ATTRIBUTE_MAX] = { [ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE] = { .type = NLA_U8 }, [ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE] = { .type = NLA_U32 }, [ANDR_WIFI_ATTRIBUTE_LATENCY_MODE] = { .type = NLA_U32, .len = sizeof(uint32) }, + /* Dont see ANDR_WIFI_ATTRIBUTE_RANDOM_MAC being used currently */ [ANDR_WIFI_ATTRIBUTE_RANDOM_MAC] = { .type = NLA_U32 }, [ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO] = { .type = NLA_S8 }, [ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION] = { .type = NLA_S8 }, @@ -9088,6 +12170,33 @@ const struct nla_policy dump_buf_policy[DUMP_BUF_ATTR_MAX] = { [DUMP_BUF_ATTR_SDTC_ETB_DUMP] = { .type = NLA_BINARY }, [DUMP_BUF_ATTR_PKTID_MAP_LOG] = { .type = NLA_BINARY }, [DUMP_BUF_ATTR_PKTID_UNMAP_LOG] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_EWP_HW_INIT_LOG] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_EWP_HW_MOD_DUMP] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_EWP_HW_REG_DUMP] = { .type = NLA_BINARY }, +}; + +const struct nla_policy andr_dbg_policy[DEBUG_ATTRIBUTE_MAX] = { + [DEBUG_ATTRIBUTE_GET_DRIVER] = { .type = NLA_BINARY }, + [DEBUG_ATTRIBUTE_GET_FW] = { .type = NLA_BINARY }, + [DEBUG_ATTRIBUTE_RING_ID] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_RING_NAME] = { .type = NLA_NUL_STRING }, + [DEBUG_ATTRIBUTE_RING_FLAGS] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_LOG_LEVEL] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_LOG_TIME_INTVAL] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_FW_DUMP_LEN] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_FW_DUMP_DATA] = { .type = NLA_U64 }, +#if (ANDROID_VERSION >= 11) + [DEBUG_ATTRIBUTE_FW_ERR_CODE] = { .type = NLA_U32 }, +#endif + [DEBUG_ATTRIBUTE_RING_DATA] = { .type = NLA_BINARY }, + [DEBUG_ATTRIBUTE_RING_STATUS] = { .type = NLA_BINARY }, + [DEBUG_ATTRIBUTE_RING_NUM] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_DRIVER_DUMP_LEN] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_DRIVER_DUMP_DATA] = { .type = NLA_BINARY }, + [DEBUG_ATTRIBUTE_PKT_FATE_NUM] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_PKT_FATE_DATA] = { .type = NLA_U64 }, + [DEBUG_ATTRIBUTE_HANG_REASON] = { .type = NLA_BINARY }, }; const struct nla_policy brcm_drv_attr_policy[BRCM_ATTR_DRIVER_MAX] = { @@ -9097,6 +12206,7 @@ const struct nla_policy brcm_drv_attr_policy[BRCM_ATTR_DRIVER_MAX] = { ((BRCM_WLAN_VENDOR_FEATURES_MAX / 8) + 1) }, [BRCM_ATTR_DRIVER_RAND_MAC] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN }, [BRCM_ATTR_SAE_PWE] = { .type = NLA_U32 }, + [BRCM_ATTR_TD_POLICY] = { .type = NLA_U32 }, }; #ifdef RTT_SUPPORT @@ -9126,6 +12236,14 @@ const struct nla_policy rtt_attr_policy[RTT_ATTRIBUTE_MAX] = { }; #endif /* RTT_SUPPORT */ +#ifdef RSSI_MONITOR_SUPPORT +const struct nla_policy rssi_monitor_attr_policy[RSSI_MONITOR_ATTRIBUTE_MAX] = { + [RSSI_MONITOR_ATTRIBUTE_MAX_RSSI] = { .type = NLA_U32 }, + [RSSI_MONITOR_ATTRIBUTE_MIN_RSSI] = { .type = NLA_U32 }, + [RSSI_MONITOR_ATTRIBUTE_START] = { .type = NLA_U32 } +}; +#endif /* RSSI_MONITOR_SUPPORT */ + #ifdef KEEP_ALIVE const struct nla_policy mkeep_alive_attr_policy[MKEEP_ALIVE_ATTRIBUTE_MAX] = { [MKEEP_ALIVE_ATTRIBUTE_ID] = { .type = NLA_U8 }, @@ -9173,7 +12291,7 @@ const struct nla_policy nan_attr_policy[NAN_ATTRIBUTE_MAX] = { [NAN_ATTRIBUTE_RSSI_WINDOW_SIZE] = { .type = NLA_U8, .len = sizeof(uint8) }, [NAN_ATTRIBUTE_CIPHER_SUITE_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) }, [NAN_ATTRIBUTE_SCID_LEN] = { .type = NLA_U32, .len = sizeof(uint32) }, - [NAN_ATTRIBUTE_SCID] = { .type = NLA_BINARY, .len = MAX_SCID_LEN }, + [NAN_ATTRIBUTE_SCID] = { .type = NLA_BINARY, .len = NAN_MAX_SCID_BUF_LEN }, [NAN_ATTRIBUTE_2G_AWAKE_DW] = { .type = NLA_U32, .len = sizeof(uint32) }, [NAN_ATTRIBUTE_5G_AWAKE_DW] = { .type = NLA_U32, .len = sizeof(uint32) }, [NAN_ATTRIBUTE_DISC_IND_CFG] = { .type = NLA_U8, .len = sizeof(uint8) }, @@ -9248,6 +12366,7 @@ const struct nla_policy nan_attr_policy[NAN_ATTRIBUTE_MAX] = { [NAN_ATTRIBUTE_NUM_CHANNELS] = { .type = NLA_U32, .len = sizeof(uint32) }, [NAN_ATTRIBUTE_INSTANT_MODE_ENABLE] = { .type = NLA_U32, .len = sizeof(uint32) }, [NAN_ATTRIBUTE_INSTANT_COMM_CHAN] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_CHRE_REQUEST] = { .type = NLA_U8, .len = sizeof(uint8) }, }; #endif /* WL_NAN */ @@ -9303,14 +12422,22 @@ const struct nla_policy wake_stat_attr_policy[WAKE_STAT_ATTRIBUTE_MAX] = { }; #endif /* DHD_WAKE_STATUS */ -#ifdef RSSI_MONITOR_SUPPORT -const struct nla_policy rssi_monitor_attr_policy[RSSI_MONITOR_ATTRIBUTE_MAX] = { - [RSSI_MONITOR_ATTRIBUTE_MAX_RSSI] = { .type = NLA_U32 }, - [RSSI_MONITOR_ATTRIBUTE_MIN_RSSI] = { .type = NLA_U32 }, - [RSSI_MONITOR_ATTRIBUTE_START] = { .type = NLA_U32 } +#ifdef WL_SOFTAP_ACS +const struct nla_policy acs_attr_policy[BRCM_VENDOR_ATTR_ACS_LAST] = { + [BRCM_VENDOR_ATTR_ACS_CHANNEL_INVALID] = { .type = NLA_U8 }, + [BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ] = { .type = NLA_U32 }, + [BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ] = { .type = NLA_U32 }, + [BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL] = { .type = NLA_U8 }, + [BRCM_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL] = { .type = NLA_U8 }, + [BRCM_VENDOR_ATTR_ACS_HW_MODE] = { .type = NLA_U8 }, + [BRCM_VENDOR_ATTR_ACS_HT_ENABLED] = { .type = NLA_U8 }, + [BRCM_VENDOR_ATTR_ACS_HT40_ENABLED] = { .type = NLA_U8 }, + [BRCM_VENDOR_ATTR_ACS_VHT_ENABLED] = { .type = NLA_U8 }, + [BRCM_VENDOR_ATTR_ACS_CHWIDTH] = { .type = NLA_U16 }, + [BRCM_VENDOR_ATTR_ACS_CH_LIST] = { .type = NLA_BINARY }, + [BRCM_VENDOR_ATTR_ACS_FREQ_LIST] = { .type = NLA_BINARY }, }; -#endif /* RSSI_MONITOR_SUPPORT */ - +#endif /* WL_SOFTAP_ACS */ const struct nla_policy hal_start_attr_policy[SET_HAL_START_ATTRIBUTE_MAX] = { [0] = { .strict_start_type = 0 }, @@ -9319,27 +12446,96 @@ const struct nla_policy hal_start_attr_policy[SET_HAL_START_ATTRIBUTE_MAX] = { [SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID] = { .type = NLA_U32 }, }; -const struct nla_policy andr_dbg_policy[DEBUG_ATTRIBUTE_MAX] = { - [DEBUG_ATTRIBUTE_GET_DRIVER] = { .type = NLA_BINARY }, - [DEBUG_ATTRIBUTE_GET_FW] = { .type = NLA_BINARY }, - [DEBUG_ATTRIBUTE_RING_ID] = { .type = NLA_U32 }, - [DEBUG_ATTRIBUTE_RING_NAME] = { .type = NLA_NUL_STRING }, - [DEBUG_ATTRIBUTE_RING_FLAGS] = { .type = NLA_U32 }, - [DEBUG_ATTRIBUTE_LOG_LEVEL] = { .type = NLA_U32 }, - [DEBUG_ATTRIBUTE_LOG_TIME_INTVAL] = { .type = NLA_U32 }, - [DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE] = { .type = NLA_U32 }, - [DEBUG_ATTRIBUTE_FW_DUMP_LEN] = { .type = NLA_U32 }, - [DEBUG_ATTRIBUTE_FW_DUMP_DATA] = { .type = NLA_U64 }, - [DEBUG_ATTRIBUTE_FW_ERR_CODE] = { .type = NLA_U32 }, - [DEBUG_ATTRIBUTE_RING_DATA] = { .type = NLA_BINARY }, - [DEBUG_ATTRIBUTE_RING_STATUS] = { .type = NLA_BINARY }, - [DEBUG_ATTRIBUTE_RING_NUM] = { .type = NLA_U32 }, - [DEBUG_ATTRIBUTE_DRIVER_DUMP_LEN] = { .type = NLA_U32 }, - [DEBUG_ATTRIBUTE_DRIVER_DUMP_DATA] = { .type = NLA_BINARY }, - [DEBUG_ATTRIBUTE_PKT_FATE_NUM] = { .type = NLA_U32 }, - [DEBUG_ATTRIBUTE_PKT_FATE_DATA] = { .type = NLA_U64 }, - [DEBUG_ATTRIBUTE_HANG_REASON] = { .type = NLA_BINARY }, +#ifdef WL_CUSTOM_MAPPING_OF_DSCP +const struct nla_policy custom_setting_attr_policy[CUSTOM_SETTING_ATTRIBUTE_MAX] = { + [CUSTOM_SETTING_ATTRIBUTE_DSCP_START] = { .type = NLA_U32 }, + [CUSTOM_SETTING_ATTRIBUTE_DSCP_END] = { .type = NLA_U32 }, + [CUSTOM_SETTING_ATTRIBUTE_ACCESS_CATEGORY] = { .type = NLA_U32 }, }; +#endif /* WL_CUSTOM_MAPPING_OF_DSCP */ + +#ifdef WL_CELLULAR_CHAN_AVOID +const struct nla_policy cellavoid_attr_policy[CELLAVOID_ATTRIBUTE_MAX] = { + [CELLAVOID_ATTRIBUTE_CNT] = { .type = NLA_U32 }, + [CELLAVOID_ATTRIBUTE_CONFIG] = { .type = NLA_NESTED }, + [CELLAVOID_ATTRIBUTE_BAND] = { .type = NLA_U32 }, + [CELLAVOID_ATTRIBUTE_CHANNEL] = { .type = NLA_U32 }, + [CELLAVOID_ATTRIBUTE_PWRCAP] = { .type = NLA_U32 }, + [CELLAVOID_ATTRIBUTE_MANDATORY] = { .type = NLA_U32 }, +}; +#endif /* WL_CELLULAR_CHAN_AVOID */ + +#ifdef WL_USABLE_CHAN +const struct nla_policy usable_chan_attr_policy[USABLECHAN_ATTRIBUTE_MAX] = { + [USABLECHAN_ATTRIBUTE_BAND] = { .type = NLA_U32 }, + [USABLECHAN_ATTRIBUTE_IFACE] = { .type = NLA_U32 }, + [USABLECHAN_ATTRIBUTE_FILTER] = { .type = NLA_U32 }, + [USABLECHAN_ATTRIBUTE_MAX_SIZE] = { .type = NLA_U32 }, + [USABLECHAN_ATTRIBUTE_SIZE] = { .type = NLA_U32 }, + [USABLECHAN_ATTRIBUTE_CHANNELS] = { .type = NLA_BINARY }, +}; +#endif /* WL_USABLE_CHAN */ + +#ifdef TPUT_DEBUG_DUMP +const struct nla_policy tput_debug_dump_attr_policy[TPUT_DEBUG_ATTRIBUTE_MAX] = { + [0] = { .strict_start_type = 0 }, + [TPUT_DEBUG_ATTRIBUTE_CMD_STR ] = { .type = NLA_NUL_STRING }, + [TPUT_DEBUG_ATTRIBUTE_SUB_CMD_STR_AMPDU] = { .type = NLA_NUL_STRING }, + [TPUT_DEBUG_ATTRIBUTE_SUB_CMD_STR_CLEAR] = { .type = NLA_NUL_STRING }, +}; +#endif /* TPUT_DEBUG_DUMP */ + +#ifdef SUPPORT_OTA_UPDATE +const struct nla_policy ota_update_attr_policy[OTA_UPDATE_ATTRIBUTE_MAX] = { + [OTA_DOWNLOAD_CLM_LENGTH_ATTR ] = { .type = NLA_U32 }, + [OTA_DOWNLOAD_CLM_ATTR ] = { .type = NLA_BINARY }, + [OTA_DOWNLOAD_NVRAM_LENGTH_ATTR ] = { .type = NLA_U32 }, + [OTA_DOWNLOAD_NVRAM_ATTR ] = { .type = NLA_BINARY }, + [OTA_SET_FORCE_REG_ON ] = { .type = NLA_U32 }, + [OTA_CUR_NVRAM_EXT_ATTR] = { .type = NLA_NUL_STRING }, +}; +#endif /* SUPPORT_OTA_UPDATE */ + +const struct nla_policy multista_attr_policy[MULTISTA_ATTRIBUTE_MAX] = { + [MULTISTA_ATTRIBUTE_PRIM_CONN_IFACE] = { .type = NLA_NUL_STRING }, + [MULTISTA_ATTRIBUTE_USE_CASE] = { .type = NLA_U32 }, +}; + +#if !defined(WL_TWT) && defined(WL_TWT_HAL_IF) +const struct nla_policy andr_twt_attr_policy[ANDR_TWT_ATTR_MAX] = { + [ANDR_TWT_ATTR_NONE] = { .strict_start_type = 0 }, + [ANDR_TWT_ATTR_CONFIG_ID] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_NEGOTIATION_TYPE] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_TRIGGER_TYPE] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_WAKE_DURATION] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_WAKE_INTERVAL] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_WAKE_INTERVAL_MIN] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_WAKE_INTERVAL_MAX] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_WAKE_DURATION_MIN] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_WAKE_DURATION_MAX] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_AVG_PKT_SIZE] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_AVG_PKT_NUM] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_WAKETIME_OFFSET] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_ALL_TWT] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_RESUME_TIME] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_AVG_EOSP_DUR] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_EOSP_CNT] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_NUM_SP] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_DEVICE_CAP] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_PEER_CAP] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_STATUS] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_REASON_CODE] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_TWT_RESUMED] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_TWT_NOTIFICATION] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_SUB_EVENT] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_NUM_PEER_STATS] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_AVG_PKT_NUM_TX] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_AVG_PKT_SIZE_TX] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_AVG_PKT_NUM_RX] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_AVG_PKT_SIZE_RX] = { .type = NLA_U32 }, +}; +#endif /* !WL_TWT && WL_TWT_HAL_IF */ + #endif /* LINUX_VERSION >= 5.3 */ static struct wiphy_vendor_command wl_vendor_cmds [] = { @@ -9369,7 +12565,7 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { #endif /* LINUX_VERSION >= 5.3 */ }, #endif /* BCM_PRIV_CMD_SUPPORT */ -#if defined(WL_SAE) || defined(WL_CLIENT_SAE) +#if defined(WL_SAE) { { .vendor_id = OUI_BRCM, @@ -9378,7 +12574,7 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, .doit = wl_cfgvendor_set_sae_password }, -#endif /* WL_SAE || WL_CLIENT_SAE */ +#endif /* WL_SAE */ { { .vendor_id = OUI_BRCM, @@ -9401,6 +12597,18 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) .policy = brcm_drv_attr_policy, .maxattr = BRCM_ATTR_DRIVER_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_BRCM, + .subcmd = BRCM_VENDOR_SCMD_SET_TD_POLICY + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_td_policy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = brcm_drv_attr_policy, + .maxattr = BRCM_ATTR_DRIVER_MAX #endif /* LINUX_VERSION >= 5.3 */ }, #ifdef GSCAN_SUPPORT @@ -9597,6 +12805,7 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .policy = andr_wifi_attr_policy, .maxattr = ANDR_WIFI_ATTRIBUTE_MAX #endif /* LINUX_VERSION >= 5.3 */ + }, #endif /* CUSTOM_FORCE_NODFS_FLAG */ { @@ -9800,7 +13009,22 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .policy = andr_dbg_policy, .maxattr = DEBUG_ATTRIBUTE_MAX #endif /* LINUX_VERSION >= 5.3 */ + }, +#ifdef DHD_HAL_RING_DUMP + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = DEBUG_GET_BUF_RING_MAP + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_dbg_get_buf_ring_map, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_dbg_policy, + .maxattr = DEBUG_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* DHD_HAL_RING_DUMP */ #endif /* DEBUGABILITY */ { { @@ -10071,7 +13295,7 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { #endif /* LINUX_VERSION >= 5.3 */ }, #endif /* WL_NAN */ -#if defined(PKT_FILTER_SUPPORT) && defined(APF) +#if defined(APF) { { .vendor_id = OUI_GOOGLE, @@ -10084,7 +13308,6 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .maxattr = APF_ATTRIBUTE_MAX #endif /* LINUX_VERSION >= 5.3 */ }, - { { .vendor_id = OUI_GOOGLE, @@ -10097,7 +13320,19 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .maxattr = APF_ATTRIBUTE_MAX #endif /* LINUX_VERSION >= 5.3 */ }, -#endif /* PKT_FILTER_SUPPORT && APF */ + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = APF_SUBCMD_READ_FILTER_DATA + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_apf_read_filter_data, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = apf_atrribute_policy, + .maxattr = APF_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* APF */ #ifdef NDO_CONFIG_SUPPORT { { @@ -10166,6 +13401,7 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .policy = brcm_drv_attr_policy, .maxattr = BRCM_ATTR_DRIVER_MAX #endif /* LINUX_VERSION >= 5.3 */ + }, #endif /* !BCMSUP_4WAY_HANDSHAKE || LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */ { @@ -10179,6 +13415,7 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .policy = brcm_drv_attr_policy, .maxattr = BRCM_ATTR_DRIVER_MAX #endif /* LINUX_VERSION >= 5.3 */ + }, #if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT) { @@ -10238,6 +13475,7 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { #endif /* LINUX_VERSION >= 5.3 */ }, #endif /* WL_LATENCY_MODE */ + #ifdef WL_P2P_RAND { { @@ -10252,6 +13490,20 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { #endif /* LINUX_VERSION >= 5.3 */ }, #endif /* WL_P2P_RAND */ +#ifdef WL_THERMAL_MITIGATION + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_THERMAL_MITIGATION + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_thermal_mitigation, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_wifi_attr_policy, + .maxattr = ANDR_WIFI_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* WL_THERMAL_MITIGATION */ #ifdef WL_SAR_TX_POWER { { @@ -10264,8 +13516,274 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .policy = andr_wifi_attr_policy, .maxattr = ANDR_WIFI_ATTRIBUTE_MAX #endif /* LINUX_VERSION >= 5.3 */ - } + }, #endif /* WL_SAR_TX_POWER */ +#ifdef WL_SOFTAP_ACS + { + { + .vendor_id = OUI_BRCM, + .subcmd = BRCM_VENDOR_SCMD_ACS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgscan_acs, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = acs_attr_policy, + .maxattr = BRCM_VENDOR_ATTR_ACS_LAST +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* WL_SOFTAP_ACS */ +#ifdef WL_CUSTOM_MAPPING_OF_DSCP + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_CUSTOM_MAPPING_OF_DSCP + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV, + .doit = wl_cfgvendor_custom_mapping_of_dscp, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = custom_setting_attr_policy, + .maxattr = CUSTOM_SETTING_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_CUSTOM_MAPPING_OF_DSCP_RESET + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV, + .doit = wl_cfgvendor_custom_mapping_of_dscp_reset, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = custom_setting_attr_policy, + .maxattr = CUSTOM_SETTING_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* WL_CUSTOM_MAPPING_OF_DSCP */ +#ifdef WL_CELLULAR_CHAN_AVOID + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_CELL_AVOID_SUBCMD_SET_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV, + .doit = wl_cfgvendor_cellavoid_set_cell_channels, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = cellavoid_attr_policy, + .maxattr = CELLAVOID_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* WL_CELLULAR_CHAN_AVOID */ +#ifdef TPUT_DEBUG_DUMP + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = DEBUG_SET_TPUT_DEBUG_DUMP_CMD + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgdbg_tput_debug_get_cmd, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = tput_debug_dump_attr_policy, + .maxattr = TPUT_DEBUG_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* TPUT_DEBUG_DUMP */ + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_MULTISTA_PRIMARY_CONNECTION + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_multista_set_primary_connection, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = multista_attr_policy, + .maxattr = MULTISTA_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_MULTISTA_USE_CASE + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_multista_set_use_case, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = multista_attr_policy, + .maxattr = MULTISTA_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#if !defined(WL_TWT) && defined(WL_TWT_HAL_IF) + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_SETUP + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_setup, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_TEARDOWN + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_teardown, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_INFO_FRAME + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_info_frame, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_GET_CAP + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_cap, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_GET_STATS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_get_stats, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_CLR_STATS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_clear_stats, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_GET_RESPONSE + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_get_response, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* !WL_TWT && WL_TWT_HAL_IF */ +#ifdef SUPPORT_OTA_UPDATE + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_GET_OTA_CURRUNT_INFO + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_get_ota_current_info, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = ota_update_attr_policy, + .maxattr = OTA_UPDATE_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_OTA_UPDATE + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_ota_download, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = ota_update_attr_policy, + .maxattr = OTA_UPDATE_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* SUPPORT_OTA_UPDATE */ +#ifdef OEM_ANDROID + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_DTIM_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_dtim_config, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_wifi_attr_policy, + .maxattr = ANDR_WIFI_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* OEM_ANDROID */ +#ifdef WL_USABLE_CHAN + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_USABLE_CHAN + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV, + .doit = wl_cfgvendor_get_usable_channels, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = usable_chan_attr_policy, + .maxattr = USABLECHAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* WL_USABLE_CHAN */ +#ifdef WLAN_ACCEL_BOOT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_TRIGGER_SSR + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_trigger_ssr + }, +#endif /* WLAN_ACCEL_BOOT */ + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_GET_RADIO_COMBO_MATRIX + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_get_radio_combo_matrix, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = wifi_radio_combo_attr_policy, + .maxattr = ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_TX_POWER_LIMITS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_tx_power_policy_handler, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = wifi_tx_power_limits_attr_policy, + .maxattr = TX_POWER_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, }; @@ -10311,7 +13829,13 @@ static const struct nl80211_vendor_cmd_info wl_vendor_events [] = { { OUI_BRCM, BRCM_VENDOR_EVENT_CU}, { OUI_BRCM, BRCM_VENDOR_EVENT_WIPS}, { OUI_GOOGLE, NAN_ASYNC_RESPONSE_DISABLED}, - { OUI_BRCM, BRCM_VENDOR_EVENT_RCC_INFO} + { OUI_BRCM, BRCM_VENDOR_EVENT_RCC_INFO}, + { OUI_BRCM, BRCM_VENDOR_EVENT_ACS}, + { OUI_BRCM, BRCM_VENDOR_EVENT_TWT}, + { OUI_GOOGLE, BRCM_VENDOR_EVENT_TPUT_DUMP}, + { OUI_GOOGLE, GOOGLE_NAN_EVENT_MATCH_EXPIRY}, + { OUI_BRCM, BRCM_VENDOR_EVENT_RCC_FREQ_INFO}, + { OUI_BRCM, BRCM_VENDOR_EVENT_CONNECTIVITY_LOG}, }; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) @@ -10348,16 +13872,27 @@ int wl_cfgvendor_attach(struct wiphy *wiphy, dhd_pub_t *dhd) #ifdef DEBUGABILITY dhd_os_dbg_register_callback(FW_VERBOSE_RING_ID, wl_cfgvendor_dbg_ring_send_evt); +#ifdef DHD_DEBUGABILITY_EVENT_RING dhd_os_dbg_register_callback(DHD_EVENT_RING_ID, wl_cfgvendor_dbg_ring_send_evt); +#endif /* DHD_DEBUGABILITY_EVENT_RING */ #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING dhd_os_dbg_register_callback(DRIVER_LOG_RING_ID, wl_cfgvendor_dbg_ring_send_evt); dhd_os_dbg_register_callback(ROAM_STATS_RING_ID, wl_cfgvendor_dbg_ring_send_evt); +#ifdef DHD_DEBUGABILITY_DEBUG_DUMP + dhd_os_dbg_register_callback(DEBUG_DUMP_RING1_ID, wl_cfgvendor_dbg_ring_send_evt); + dhd_os_dbg_register_callback(DEBUG_DUMP_RING2_ID, wl_cfgvendor_dbg_ring_send_evt); +#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */ #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ +#ifdef DHD_PKT_LOGGING_DBGRING + dhd_os_dbg_register_callback(PACKET_LOG_RING_ID, wl_cfgvendor_dbg_ring_send_evt); +#endif /* DHD_PKT_LOGGING_DBGRING */ #endif /* DEBUGABILITY */ #ifdef DHD_LOG_DUMP dhd_os_dbg_register_urgent_notifier(dhd, wl_cfgvendor_dbg_send_file_dump_evt); #endif /* DHD_LOG_DUMP */ - +#ifdef SUPPORT_OTA_UPDATE + (void)wl_set_ota_nvram_ext(dhd); +#endif /* SUPPORT_OTA_UPDATE */ return 0; } @@ -10524,7 +14059,7 @@ wl_cfgvendor_simple_hang_event(struct net_device *dev, u16 reason) nla_put(msg, DEBUG_ATTRIBUTE_HANG_REASON, DHD_MEMDUMP_LONGSTR_LEN, dhd->memdump_str); #endif - cfg80211_vendor_event(msg, kflags); + CFG80211_VENDOR_EVENT(msg, kflags); return; } @@ -10540,7 +14075,7 @@ wl_copy_hang_info_if_falure(struct net_device *dev, u16 reason, s32 ret) int remain_len = 0; if (!dev) { - WL_ERR(("dev is null")); + WL_ERR(("dev is null\n")); return; } @@ -10598,3 +14133,258 @@ wl_copy_hang_info_if_falure(struct net_device *dev, u16 reason, s32 ret) return; } #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */ + +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT +void +wl_cfgvendor_send_alert_event(struct net_device *dev, uint32 reason) +{ +#if (ANDROID_VERSION >= 11) + struct bcm_cfg80211 *cfg; + struct wiphy *wiphy; + struct sk_buff *msg; + gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + + WL_DBG(("wl_cfgvendor_send_fw_dump_event %d\n", reason)); + + cfg = wl_cfg80211_get_bcmcfg(); + if (!cfg || !cfg->wdev) { + WL_ERR(("fw dump evt invalid arg\n")); + return; + } + + wiphy = bcmcfg_to_wiphy(cfg); + if (!wiphy) { + WL_ERR(("wiphy is NULL\n")); + return; + } + + /* Allocate the skb for vendor event */ + msg = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(dev), sizeof(uint32), + GOOGLE_FW_DUMP_EVENT, kflags); + if (!msg) { + WL_ERR(("%s: fail to allocate skb for vendor event\n", __FUNCTION__)); + return; + } + + nla_put_u32(msg, DEBUG_ATTRIBUTE_FW_ERR_CODE, reason); + + cfg80211_vendor_event(msg, kflags); +#endif + return; +} +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ + +#ifdef WL_CFGVENDOR_CUST_ADVLOG +void +wl_cfgvendor_custom_advlog_roam_log(void *plog, uint32 armcycle) +{ + prsv_periodic_log_hdr_t *hdr = (prsv_periodic_log_hdr_t *)plog; + const pr_advlog_tbl_t *cur_advlog_elem = &advlog_print_tbl[0]; + + if (hdr->version < ROAM_LOG_VER_3) { + WL_ERR(("%s: Version mis-match(%d)\n", __FUNCTION__, hdr->version)); + return; + } + + while (cur_advlog_elem && cur_advlog_elem->advlog_func) { + if (hdr->id == cur_advlog_elem->id) { + cur_advlog_elem->advlog_func(plog, armcycle); + break; + } + cur_advlog_elem++; + } +} + +static void +wl_cfgvendor_custom_advlog_scan_start(void *plog, uint32 armcycle) +{ + roam_log_trig_v2_t *log = (roam_log_trig_v2_t *)plog; + uint cust_roam_rsn = WLC_E_REASON_INITIAL_ASSOC; + int i; + bool rssi_thresh = FALSE; + + if (log->result != BCME_OK) { + /* Not required logging if ROAM scan is failed. */ + return; + } + + for (i = 0; i < WL_CUST_ROAM_REASON_MAX; i++) { + if (dhd_covt_roam_rsn_list[i].roam_rsn == log->reason) { + cust_roam_rsn = dhd_covt_roam_rsn_list[i].cust_roam_rsn; + break; + } + } + + if ((log->reason == WLC_E_REASON_LOW_RSSI) || + (log->reason == WLC_E_REASON_LOW_RSSI_CU) || + (log->reason == WLC_E_REASON_INACTIVITY) || + (log->reason == WLC_E_REASON_ROAM_SCAN_TIMEOUT)) { + rssi_thresh = TRUE; + } + SUPP_ADVLOG(("[ROAM] SCAN_START reason=%d rssi=%d cu=%d full_scan=%d " + "rssi_thresh=%d [%d]\n", + cust_roam_rsn, log->rssi, log->current_cu, log->full_scan, + (rssi_thresh ? log->low_rssi.rssi_threshold : (0)), armcycle)); +} + +static int +wl_cfgvendor_custom_advlog_get_rcc(chanspec_t *chanspecs) +{ + struct bcm_cfg80211 *cfg; + struct net_device *ndev; + int rcc_chan_cnt = 0; + wlc_ssid_t *ssid = NULL; + + cfg = wl_cfg80211_get_bcmcfg(); + ndev = bcmcfg_to_prmry_ndev(cfg); + + /* Get Current SSID */ + ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID); + if (!ssid) { + WL_ERR(("No SSID found in the saved profile\n")); + goto exit; + } + + rcc_chan_cnt = get_roam_channel_list(cfg, 0, chanspecs, MAX_ROAM_CHANNEL, + ssid, ioctl_version); + +exit: + return rcc_chan_cnt; +} + +#define CH_LIST_LEN (SUPP_LOG_LEN / 2) +static void +wl_cfgvendor_custom_advlog_scan_cmpl(void *plog, uint32 armcycle) +{ + int i; + roam_log_scan_cmplt_v2_t *log = (roam_log_scan_cmplt_v2_t *)plog; + int freq; +#ifdef ESCAN_CHANNEL_CACHE + chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0}; + uint ch_cnt = 0; + char ch_list[CH_LIST_LEN] = {'\0'}; + uint buf_pos = 0; + + ch_cnt = wl_cfgvendor_custom_advlog_get_rcc(chanspecs); + + bzero(ch_list, CH_LIST_LEN); + for (i = 0; i < ch_cnt; i++) { + freq = wl_channel_to_frequency(wf_chspec_ctlchan(chanspecs[i]), + CHSPEC_BAND(chanspecs[i])); + if (CH_LIST_LEN < buf_pos) { + break; + } + buf_pos += snprintf(&ch_list[buf_pos], CH_LIST_LEN - buf_pos, + "%d ", freq); + } + + SUPP_ADVLOG(("[ROAM] SCAN_DONE ap_count=%d freq[%d]=%s [%d]\n", + log->scan_count, ch_cnt, ch_list, armcycle)); +#else + SUPP_ADVLOG(("[ROAM] SCAN_DONE ap_count=%d freq[%d] [%d]\n", + log->scan_count, log->chan_num, armcycle)); +#endif /* ESCAN_CHANNEL_CACHE */ + + freq = wl_channel_to_frequency(wf_chspec_ctlchan(log->cur_info.chanspec), + CHSPEC_BAND(log->cur_info.chanspec)); + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + SUPP_ADVLOG(("[ROAM] SCORE_CUR_AP bssid=" MACDBG_FULL " freq=%d rssi=%d cu=%d " + "score=%d.%02d\n", + MAC2STRDBG_FULL((uint8 *)&log->cur_info.addr), + freq, log->cur_info.rssi, + log->cur_info.cu_avail ? + (log->cur_info.cu * 100 / WL_MAX_CHANNEL_USAGE) : WL_CU_NOT_AVAIL, + log->cur_info.score / 100, log->cur_info.score % 100)); + + for (i = 0; i < log->scan_list_size; i++) { + freq = wl_channel_to_frequency(wf_chspec_ctlchan(log->scan_list[i].chanspec), + CHSPEC_BAND(log->scan_list[i].chanspec)); + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + SUPP_ADVLOG(("[ROAM] SCORE_CANDI[%d], bssid=" MACDBG_FULL " freq=%d " + "rssi=%d cu=%d score=%d.%02d tp=%dkbps\n", + i, MAC2STRDBG_FULL((uint8 *)&log->scan_list[i].addr), freq, + log->scan_list[i].rssi, + log->scan_list[i].cu_avail ? + (log->scan_list[i].cu * 100 / WL_MAX_CHANNEL_USAGE) : WL_CU_NOT_AVAIL, + log->scan_list[i].score / 100, log->scan_list[i].score % 100, + log->scan_list[i].estm_tput != ROAM_LOG_INVALID_TPUT? + log->scan_list[i].estm_tput:0)); + } +} + +static void +wl_cfgvendor_custom_advlog_roam_cmpl(void *plog, uint32 armcycle) +{ + roam_log_cmplt_v1_t *log = (roam_log_cmplt_v1_t *)plog; + + if (log->status == WLC_E_STATUS_ABORT) { + /* Roaming Abort(Cancel) */ + SUPP_ADVLOG(("[ROAM] CANCELLED [%d]\n", armcycle)); + } else if (log->status == WLC_E_STATUS_NO_NETWORKS || log->status == WLC_E_STATUS_TIMEOUT) { + /* Roaming No Networks */ + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + SUPP_ADVLOG(("[ROAM] RESULT NO_ROAM bssid=" MACDBG_FULL " [%d]\n", + MAC2STRDBG_FULL((uint8 *)&log->addr), armcycle)); + } else { + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + SUPP_ADVLOG(("[ROAM] RESULT ROAM bssid=" MACDBG_FULL " [%d status=%d]\n", + MAC2STRDBG_FULL((uint8 *)&log->addr), armcycle, log->status)); + } +} + +static void +wl_cfgvendor_custom_advlog_btm_req(void *plog, uint32 armcycle) +{ + roam_log_btm_req_v4_t *log = (roam_log_btm_req_v4_t *)plog; + int i; + + SUPP_ADVLOG(("[BTM] REQ token=%d mode=%d disassoc=%d validity=%d " + "candidate_list_cnt=%d [%d]\n", + log->token, log->req_mode, log->disassoc_dur, log->validity_dur, + log->nbrlist_size, armcycle)); + if (log->nbrlist_size) { + int max_idx = MIN(log->nbrlist_size, ROAM_NBR_RPT_LIST_SIZE); + for (i = 0; i < max_idx; i++) { + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + SUPP_ADVLOG(("[BTM] REQ_CANDI[%d] bssid=" MACDBG_FULL " preference=%d\n", + i, MAC2STRDBG_FULL((uint8 *)&log->nbr_list[i].bssid), + log->nbr_list[i].preference)); + } + } +} + +static void +wl_cfgvendor_custom_advlog_btm_resp(void *plog, uint32 armcycle) +{ + roam_log_btm_resp_v4_t *log = (roam_log_btm_resp_v4_t *)plog; + + /* do not print to the kernel, only for framework (MACDBG_FULL) */ + SUPP_ADVLOG(("[BTM] RESP token=%d status=%d delay=%d target=" MACDBG_FULL " [%d]\n", + log->token, log->status, log->term_delay, + MAC2STRDBG_FULL((uint8 *)&log->target_addr), armcycle)); +} + +static void +wl_cfgvendor_custom_advlog_btm_wtc(void *plog, uint32 armcycle) +{ + roam_log_wtc_btmrep_v3_t *log = (roam_log_wtc_btmrep_v3_t *)plog; + + if (log->wtc_type == WTC_BTMREQ) { + SUPP_ADVLOG(("[BTM] WTC reason=%d sub_code=%d duration=%d [%d]\n", + log->wtcreq.rsn_code, log->wtcreq.subcode, log->wtcreq.duration, + armcycle)); + } else if (log->wtc_type == WTC_BTMRESP) { + SUPP_ADVLOG(("[BTM] WTC reason_code=%d [%d]\n", + log->wtcresp.rsn_code, armcycle)); + } +} + +static void +wl_cfgvendor_custom_advlog_btm_query(void *plog, uint32 armcycle) +{ + roam_log_btm_query_v3_t *log = (roam_log_btm_query_v3_t *)plog; + + SUPP_ADVLOG(("[BTM] QUERY token=%d reason=%d [%d]\n", + log->token, log->reason, armcycle)); +} +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.h old mode 100755 new mode 100644 index 231163d229c5..b1fe71729f4e --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 Vendor Extension Code * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -45,7 +45,8 @@ enum brcm_vendor_attr { BRCM_ATTR_DRIVER_FEATURE_FLAGS = 2, BRCM_ATTR_DRIVER_RAND_MAC = 3, BRCM_ATTR_SAE_PWE = 4, - BRCM_ATTR_DRIVER_MAX = 5 + BRCM_ATTR_TD_POLICY = 5, + BRCM_ATTR_DRIVER_MAX = 6 }; enum brcm_wlan_vendor_features { @@ -108,6 +109,9 @@ typedef enum wifi_error { #define CFG80211_VENDOR_CMD_REPLY_SKB_SZ 100 #define CFG80211_VENDOR_EVT_SKB_SZ 2048 +#define AP_OWE_IOCTL_BUF_SIZE 1024u +#define AP_OWE_ASSOC_RESP_PARAMS_BUFSZ 512u + #define SUPP_SAE_PWE_LOOP 0x00 #define SUPP_SAE_PWE_H2E 0x01 #define SUPP_SAE_PWE_TRANS 0x02 @@ -157,6 +161,38 @@ typedef enum { ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START = 0x1900, ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_END = 0x19FF, + /* define all tx power related commands between 0x1920 and 0x192F */ + ANDROID_NL80211_SUBCMD_MITIGATION_RANGE_START = 0x1920, + ANDROID_NL80211_SUBCMD_MITIGATION_RANGE_END = 0x192F, + + /* define all customer related setting command between 0x2000 and 0x20FF */ + ANDROID_NL80211_SUBCMD_CUSTOM_SETTING_START = 0x2000, + ANDROID_NL80211_SUBCMD_CUSTOM_SETTING_END = 0x20FF, + + /* define all Channel Avoidance related commands between 0x2100 and 0x211F */ + ANDROID_NL80211_SUBCMD_CELL_AVOID_RANGE_START = 0x2100, + ANDROID_NL80211_SUBCMD_CELL_AVOID_RANGE_END = 0x211F, + + /* define all OTA Download related commands between 0x2120 and 0x212F */ + ANDROID_NL80211_SUBCMD_OTA_DOWNLOAD_START = 0x2120, + ANDROID_NL80211_SUBCMD_OTA_DOWNLOAD_END = 0x212F, + + /* define all VOIP mode config related commands between 0x2130 and 0x213F */ + ANDROID_NL80211_SUBCMD_VIOP_MODE_START = 0x2130, + ANDROID_NL80211_SUBCMD_VIOP_MODE_END = 0x213F, + + /* define all TWT related commands between 0x2140 and 0x214F */ + ANDROID_NL80211_SUBCMD_TWT_START = 0x2140, + ANDROID_NL80211_SUBCMD_TWT_END = 0x214F, + + /* define all Usable Channel related commands between 0x2150 and 0x215F */ + ANDROID_NL80211_SUBCMD_USABLE_CHAN_RANGE_START = 0x2150, + ANDROID_NL80211_SUBCMD_USABLE_CHAN_RANGE_END = 0x215F, + + /* define all init/deinit related commands between 0x2160 and 0x216F */ + ANDROID_NL80211_SUBCMD_INIT_DEINIT_RANGE_START = 0x2160, + ANDROID_NL80211_SUBCMD_INIT_DEINIT_RANGE_END = 0x216F, + /* This is reserved for future usage */ } ANDROID_VENDOR_SUB_COMMAND; @@ -191,6 +227,16 @@ enum andr_vendor_subcmd { WIFI_SUBCMD_FW_ROAM_POLICY, WIFI_SUBCMD_ROAM_CAPABILITY, WIFI_SUBCMD_SET_LATENCY_MODE, + WIFI_SUBCMD_SET_MULTISTA_PRIMARY_CONNECTION, + WIFI_SUBCMD_SET_MULTISTA_USE_CASE, + WIFI_SUBCMD_SET_DTIM_CONFIG, + ANDR_TWT_SUBCMD_GET_CAP = ANDROID_NL80211_SUBCMD_TWT_START, + ANDR_TWT_SUBCMD_SETUP, + ANDR_TWT_SUBCMD_TEARDOWN, + ANDR_TWT_SUBCMD_INFO_FRAME, + ANDR_TWT_SUBCMD_GET_STATS, + ANDR_TWT_SUBCMD_CLR_STATS, + ANDR_TWT_SUBCMD_GET_RESPONSE, RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START, RTT_SUBCMD_CANCEL_CONFIG, RTT_SUBCMD_GETCAPABILITY, @@ -219,6 +265,8 @@ enum andr_vendor_subcmd { DEBUG_SET_HAL_START, DEBUG_SET_HAL_STOP, DEBUG_SET_HAL_PID, + DEBUG_SET_TPUT_DEBUG_DUMP_CMD, + DEBUG_GET_BUF_RING_MAP, WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START, WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE, @@ -244,7 +292,19 @@ enum andr_vendor_subcmd { NAN_WIFI_SUBCMD_ENABLE_MERGE, /* 0x1712 */ APF_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START, APF_SUBCMD_SET_FILTER, + APF_SUBCMD_READ_FILTER_DATA, WIFI_SUBCMD_TX_POWER_SCENARIO = ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START, + WIFI_SUBCMD_THERMAL_MITIGATION = ANDROID_NL80211_SUBCMD_MITIGATION_RANGE_START, + WIFI_SUBCMD_CUSTOM_MAPPING_OF_DSCP = ANDROID_NL80211_SUBCMD_CUSTOM_SETTING_START, + WIFI_SUBCMD_CUSTOM_MAPPING_OF_DSCP_RESET, + WIFI_SUBCMD_CELL_AVOID_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_CELL_AVOID_RANGE_START, + WIFI_SUBCMD_CONFIG_VOIP_MODE = ANDROID_NL80211_SUBCMD_VIOP_MODE_START, + WIFI_SUBCMD_GET_OTA_CURRUNT_INFO = ANDROID_NL80211_SUBCMD_OTA_DOWNLOAD_START, + WIFI_SUBCMD_OTA_UPDATE, + WIFI_SUBCMD_USABLE_CHAN = ANDROID_NL80211_SUBCMD_USABLE_CHAN_RANGE_START, + WIFI_SUBCMD_TRIGGER_SSR = ANDROID_NL80211_SUBCMD_INIT_DEINIT_RANGE_START, + WIFI_SUBCMD_GET_RADIO_COMBO_MATRIX, + WIFI_SUBCMD_SET_TX_POWER_LIMITS, /* Add more sub commands here */ VENDOR_SUBCMD_MAX }; @@ -387,7 +447,7 @@ enum gscan_ch_attributes { }; enum rtt_attributes { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || (ANDROID_VERSION >= 12) +#if ANDROID_VERSION >= 12 RTT_ATTRIBUTE_INVALID, #endif RTT_ATTRIBUTE_TARGET_CNT, @@ -416,7 +476,7 @@ enum rtt_attributes { }; enum wifi_rssi_monitor_attr { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || (ANDROID_VERSION >= 12) +#if ANDROID_VERSION >= 12 RSSI_MONITOR_ATTRIBUTE_INVALID, #endif RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, @@ -432,7 +492,7 @@ enum wifi_sae_key_attr { }; enum debug_attributes { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || (ANDROID_VERSION >= 12) +#if ANDROID_VERSION >= 12 DEBUG_ATTRIBUTE_INVALID, #endif DEBUG_ATTRIBUTE_GET_DRIVER, @@ -445,7 +505,9 @@ enum debug_attributes { DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE, DEBUG_ATTRIBUTE_FW_DUMP_LEN, DEBUG_ATTRIBUTE_FW_DUMP_DATA, +#if (ANDROID_VERSION >= 11) DEBUG_ATTRIBUTE_FW_ERR_CODE, +#endif DEBUG_ATTRIBUTE_RING_DATA, DEBUG_ATTRIBUTE_RING_STATUS, DEBUG_ATTRIBUTE_RING_NUM, @@ -454,7 +516,9 @@ enum debug_attributes { DEBUG_ATTRIBUTE_PKT_FATE_NUM, DEBUG_ATTRIBUTE_PKT_FATE_DATA, DEBUG_ATTRIBUTE_HANG_REASON, - /* Please add new attributes from here to sync up old HAL */ + DEBUG_ATTRIBUTE_BUF_RING_NUM, + DEBUG_ATTRIBUTE_BUF_RING_MAP, + /* Add new attributes just above this */ DEBUG_ATTRIBUTE_MAX }; @@ -496,8 +560,16 @@ typedef enum { DUMP_LEN_ATTR_STATUS_LOG = 34, DUMP_LEN_ATTR_AXI_ERROR = 35, DUMP_FILENAME_ATTR_AXI_ERROR_DUMP = 36, - DUMP_LEN_ATTR_RTT_LOG = 37 + DUMP_LEN_ATTR_RTT_LOG = 37, + DUMP_LEN_ATTR_SDTC_ETB_DUMP = 38, + DUMP_FILENAME_ATTR_SDTC_ETB_DUMP = 39, + DUMP_LEN_ATTR_PKTID_MAP_LOG = 40, + DUMP_LEN_ATTR_PKTID_UNMAP_LOG = 41, + DUMP_LEN_ATTR_EWP_HW_INIT_LOG = 42, + DUMP_LEN_ATTR_EWP_HW_MOD_DUMP = 43, + DUMP_LEN_ATTR_EWP_HW_REG_DUMP = 44, /* Please add new attributes from here to sync up old HAL */ + DUMP_TYPE_ATTR_MAX } EWP_DUMP_EVENT_ATTRIBUTE; /* Attributes associated with DEBUG_GET_DUMP_BUF */ @@ -530,12 +602,40 @@ typedef enum { DUMP_BUF_ATTR_SDTC_ETB_DUMP = 25, DUMP_BUF_ATTR_PKTID_MAP_LOG = 26, DUMP_BUF_ATTR_PKTID_UNMAP_LOG = 27, + DUMP_BUF_ATTR_EWP_HW_INIT_LOG = 28, + DUMP_BUF_ATTR_EWP_HW_MOD_DUMP = 29, + DUMP_BUF_ATTR_EWP_HW_REG_DUMP = 30, /* Please add new attributes from here to sync up old HAL */ DUMP_BUF_ATTR_MAX } EWP_DUMP_CMD_ATTRIBUTE; +#ifdef DHD_HAL_RING_DUMP +typedef struct dhd_buf_ring_map_entry { + uint32 type; + uint32 ring_id; + char ring_name[DBGRING_NAME_MAX]; +} dhd_buf_ring_map_entry_t; + +static dhd_buf_ring_map_entry_t dhd_buf_ring_map[] = { + {DUMP_BUF_ATTR_TIMESTAMP, DEBUG_DUMP_RING1_ID, DEBUG_DUMP_RING1_NAME}, + {DUMP_BUF_ATTR_ECNTRS, DEBUG_DUMP_RING2_ID, DEBUG_DUMP_RING2_NAME}, + {DUMP_BUF_ATTR_STATUS_LOG, DEBUG_DUMP_RING1_ID, DEBUG_DUMP_RING1_NAME}, + {DUMP_BUF_ATTR_RTT_LOG, DEBUG_DUMP_RING2_ID, DEBUG_DUMP_RING2_NAME}, + {DUMP_BUF_ATTR_PKTID_MAP_LOG, DEBUG_DUMP_RING2_ID, DEBUG_DUMP_RING2_NAME}, + {DUMP_BUF_ATTR_PKTID_UNMAP_LOG, DEBUG_DUMP_RING2_ID, DEBUG_DUMP_RING2_NAME}, + {DUMP_BUF_ATTR_DHD_DUMP, DEBUG_DUMP_RING1_ID, DEBUG_DUMP_RING1_NAME}, + {DUMP_BUF_ATTR_EXT_TRAP, DEBUG_DUMP_RING1_ID, DEBUG_DUMP_RING1_NAME}, + {DUMP_BUF_ATTR_HEALTH_CHK, DEBUG_DUMP_RING1_ID, DEBUG_DUMP_RING1_NAME}, + {DUMP_BUF_ATTR_COOKIE, DEBUG_DUMP_RING1_ID, DEBUG_DUMP_RING1_NAME}, + {DUMP_BUF_ATTR_FLOWRING_DUMP, DEBUG_DUMP_RING1_ID, DEBUG_DUMP_RING1_NAME}, +#ifdef DHD_HAL_RING_DUMP_MEMDUMP + {DUMP_BUF_ATTR_MEMDUMP, MEM_DUMP_RING_ID, MEM_DUMP_RING_NAME}, +#endif /* DHD_HAL_RING_DUMP_MEMDUMP */ +}; +#endif /* DHD_HAL_RING_DUMP */ + enum mkeep_alive_attributes { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || (ANDROID_VERSION >= 12) +#if ANDROID_VERSION >= 12 MKEEP_ALIVE_ATTRIBUTE_INVALID, #endif MKEEP_ALIVE_ATTRIBUTE_ID, @@ -548,6 +648,50 @@ enum mkeep_alive_attributes { MKEEP_ALIVE_ATTRIBUTE_MAX }; +enum custom_setting_attributes { + CUSTOM_SETTING_ATTRIBUTE_INVALID = 0, + CUSTOM_SETTING_ATTRIBUTE_DSCP_START = 1, + CUSTOM_SETTING_ATTRIBUTE_DSCP_END = 2, + CUSTOM_SETTING_ATTRIBUTE_ACCESS_CATEGORY = 3, + CUSTOM_SETTING_ATTRIBUTE_MAX +}; + +#ifdef WL_CELLULAR_CHAN_AVOID +enum wifi_cellavoid_attributes { + CELLAVOID_ATTRIBUTE_INVALID = 0, + CELLAVOID_ATTRIBUTE_CNT = 1, + CELLAVOID_ATTRIBUTE_CONFIG = 2, + CELLAVOID_ATTRIBUTE_BAND = 3, + CELLAVOID_ATTRIBUTE_CHANNEL = 4, + CELLAVOID_ATTRIBUTE_PWRCAP = 5, + CELLAVOID_ATTRIBUTE_MANDATORY = 6, + /* Add more attributes here */ + CELLAVOID_ATTRIBUTE_MAX +}; +#endif /* WL_CELLULAR_CHAN_AVOID */ + +#ifdef WL_USABLE_CHAN +enum wifi_usable_channel_attributes { + USABLECHAN_ATTRIBUTE_INVALID = 0, + USABLECHAN_ATTRIBUTE_BAND = 1, + USABLECHAN_ATTRIBUTE_IFACE = 2, + USABLECHAN_ATTRIBUTE_FILTER = 3, + USABLECHAN_ATTRIBUTE_MAX_SIZE = 4, + USABLECHAN_ATTRIBUTE_SIZE = 5, + USABLECHAN_ATTRIBUTE_CHANNELS = 6, + USABLECHAN_ATTRIBUTE_MAX +}; +#endif /* WL_USABLE_CHAN */ + +#ifdef TPUT_DEBUG_DUMP +enum tput_debug_attributes { + DUMP_TPUT_DEBUG_ATTR_INVALID = 0, + DUMP_TPUT_DEBUG_ATTR_FILE_NAME = 1, + DUMP_TPUT_DEBUG_ATTR_CMD = 2, + DUMP_TPUT_DEBUG_ATTR_BUF = 3 +}; +#endif /* TPUT_DEBUG_DUMP */ + typedef enum wl_vendor_event { BRCM_VENDOR_EVENT_UNSPEC = 0, BRCM_VENDOR_EVENT_PRIV_STR = 1, @@ -596,11 +740,18 @@ typedef enum wl_vendor_event { BRCM_VENDOR_EVENT_CU = 38, BRCM_VENDOR_EVENT_WIPS = 39, NAN_ASYNC_RESPONSE_DISABLED = 40, - BRCM_VENDOR_EVENT_RCC_INFO = 41 + BRCM_VENDOR_EVENT_RCC_INFO = 41, + BRCM_VENDOR_EVENT_ACS = 42, + BRCM_VENDOR_EVENT_TWT = 43, + BRCM_VENDOR_EVENT_TPUT_DUMP = 44, + GOOGLE_NAN_EVENT_MATCH_EXPIRY = 45, + BRCM_VENDOR_EVENT_RCC_FREQ_INFO = 46, + BRCM_VENDOR_EVENT_CONNECTIVITY_LOG = 47, + BRCM_VENDOR_EVENT_LAST } wl_vendor_event_t; enum andr_wifi_attr { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || (ANDROID_VERSION >= 12) +#if ANDROID_VERSION >= 12 ANDR_WIFI_ATTRIBUTE_INVALID, #endif ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, @@ -659,7 +810,7 @@ typedef enum gscan_complete_event { #ifdef DHD_WAKE_STATUS enum wake_stat_attributes { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || (ANDROID_VERSION >= 12) +#if ANDROID_VERSION >= 12 WAKE_STAT_ATTRIBUTE_INVALID, #endif WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT, @@ -683,7 +834,6 @@ enum wake_stat_attributes { WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT, WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT, WAKE_STAT_ATTRIBUTE_RX_MULTICAST_PKT_INFO, - /* Please add new attributes from here to sync up old HAL */ WAKE_STAT_ATTRIBUTE_MAX }; @@ -756,6 +906,239 @@ typedef enum { SET_HAL_START_ATTRIBUTE_MAX } SET_HAL_START_ATTRIBUTE; +#ifdef WL_THERMAL_MITIGATION +/* Wifi Thermal mitigation modes */ +typedef enum { + WIFI_MITIGATION_NONE = 0, + WIFI_MITIGATION_LIGHT = 1, + WIFI_MITIGATION_MODERATE = 2, + WIFI_MITIGATION_SEVERE = 3, + WIFI_MITIGATION_CRITICAL = 4, + WIFI_MITIGATION_EMERGENCY = 5 +} wifi_thermal_mode; + +#define DUTY_CYCLE_NONE 100u +#define DUTY_CYCLE_LIGHT 90u +#define DUTY_CYCLE_MODERATE 70u +#define DUTY_CYCLE_SEVERE 50u +#define DUTY_CYCLE_CRITICAL 30u +#define DUTY_CYCLE_EMERGENCY 10u +#endif /* WL_THERMAL_MITIGATION */ + +#ifdef WL_TWT +typedef enum { + WIFI_TWT_EVENT_SETUP = 1, + WIFI_TWT_EVENT_TEARDOWN = 2, + WIFI_TWT_EVENT_INFO_FRM = 3, + WIFI_TWT_EVENT_NOTIFY = 4 +} wifi_twt_sub_event; + +typedef enum { + WIFI_TWT_ATTR_NONE = 0, + WIFI_TWT_ATTR_SUB_EVENT = 1, + WIFI_TWT_ATTR_REASON_CODE = 2, + WIFI_TWT_ATTR_STATUS = 3, + WIFI_TWT_ATTR_SETUP_CMD = 4, + WIFI_TWT_ATTR_FLOW_FLAGS = 5, + WIFI_TWT_ATTR_FLOW_ID = 6, + WIFI_TWT_ATTR_CHANNEL = 7, + WIFI_TWT_ATTR_NEGOTIATION_TYPE = 8, + WIFI_TWT_ATTR_WAKETIME_H = 9, + WIFI_TWT_ATTR_WAKETIME_L = 10, + WIFI_TWT_ATTR_WAKE_DURATION = 11, + WIFI_TWT_ATTR_WAKE_INTERVAL = 12, + WIFI_TWT_ATTR_BID = 13, + WIFI_TWT_ATTR_ALLTWT = 14, + WIFI_TWT_ATTR_NEXT_TWT_H = 15, + WIFI_TWT_ATTR_NEXT_TWT_L = 16, + WIFI_TWT_ATTR_CONFIG_ID = 17, + WIFI_TWT_ATTR_NOTIFICATION = 18, + WIFI_TWT_ATTR_FLOW_TYPE = 19, + WIFI_TWT_ATTR_TRIGGER_TYPE = 20, + + WIFI_TWT_ATTR_MAX +} wifi_twt_attribute; +#endif /* WL_TWT */ + +typedef enum { + /** + * Usage: + * - This will be sent down for make before break use-case. + * - Platform is trying to speculatively connect to a second network and evaluate it without + * disrupting the primary connection. + * + * Requirements for Firmware: + * - Do not reduce the number of tx/rx chains of primary connection. + * - If using MCC, should set the MCC duty cycle of the primary connection to be higher than + * the secondary connection (maybe 70/30 split). + * - Should pick the best BSSID for the secondary STA (disregard the chip mode) + * independent of the primary STA: + * - Don't optimize for DBS vs MCC/SCC + * - Should not impact the primary connections bssid selection: + * - Don't downgrade chains of the existing primary connection. + * - Don't optimize for DBS vs MCC/SCC. + */ + WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY = 0, + /** + * Usage: + * - This will be sent down for any app requested peer to peer connections. + * - In this case, both the connections needs to be allocated equal resources. + * - For the peer to peer use case, BSSID for the secondary connection will be chosen by the + * framework. + * + * Requirements for Firmware: + * - Can choose MCC or DBS mode depending on the MCC efficiency and HW capability. + * - If using MCC, set the MCC duty cycle of the primary connection to be equal to the + * secondary connection. + * - Prefer BSSID candidates which will help provide the best "overall" performance for + * both the connections. + */ + WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED = 1 +} wifi_multi_sta_use_case; + +enum wifi_multista_attr { + MULTISTA_ATTRIBUTE_PRIM_CONN_IFACE, + MULTISTA_ATTRIBUTE_USE_CASE, + /* Add more attributes here */ + MULTISTA_ATTRIBUTE_MAX +}; + +#ifdef TPUT_DEBUG_DUMP +typedef enum { + TPUT_DEBUG_ATTRIBUTE_CMD_STR = 0x0001, + TPUT_DEBUG_ATTRIBUTE_SUB_CMD_STR_AMPDU = 0x0002, + TPUT_DEBUG_ATTRIBUTE_SUB_CMD_STR_CLEAR = 0x0003, + TPUT_DEBUG_ATTRIBUTE_MAX +} TPUT_DEBUG_ATTRIBUTE; +#endif /* TPUT_DEBUG_DUMP */ + +#ifdef SUPPORT_OTA_UPDATE +typedef enum { + OTA_DOWNLOAD_CLM_LENGTH_ATTR = 0x0001, + OTA_DOWNLOAD_CLM_ATTR = 0x0002, + OTA_DOWNLOAD_NVRAM_LENGTH_ATTR = 0x0003, + OTA_DOWNLOAD_NVRAM_ATTR = 0x0004, + OTA_SET_FORCE_REG_ON = 0x0005, + OTA_CUR_NVRAM_EXT_ATTR = 0x0006, + OTA_UPDATE_ATTRIBUTE_MAX +} OTA_UPDATE_ATTRIBUTE; +#endif /* SUPPORT_OTA_UPDATE */ + +#ifdef WL_TWT_HAL_IF +#define BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN 500 + +typedef enum { + ANDR_TWT_ATTR_NONE = 0, + ANDR_TWT_ATTR_CONFIG_ID = 1, + ANDR_TWT_ATTR_NEGOTIATION_TYPE = 2, + ANDR_TWT_ATTR_TRIGGER_TYPE = 3, + ANDR_TWT_ATTR_WAKE_DURATION = 4, + ANDR_TWT_ATTR_WAKE_INTERVAL = 5, + ANDR_TWT_ATTR_WAKE_INTERVAL_MIN = 6, + ANDR_TWT_ATTR_WAKE_INTERVAL_MAX = 7, + ANDR_TWT_ATTR_WAKE_DURATION_MIN = 8, + ANDR_TWT_ATTR_WAKE_DURATION_MAX = 9, + ANDR_TWT_ATTR_AVG_PKT_SIZE = 10, + ANDR_TWT_ATTR_AVG_PKT_NUM = 11, + ANDR_TWT_ATTR_WAKETIME_OFFSET = 12, + ANDR_TWT_ATTR_ALL_TWT = 13, + ANDR_TWT_ATTR_RESUME_TIME = 14, + ANDR_TWT_ATTR_AVG_EOSP_DUR = 15, + ANDR_TWT_ATTR_EOSP_CNT = 16, + ANDR_TWT_ATTR_NUM_SP = 17, + ANDR_TWT_ATTR_DEVICE_CAP = 18, + ANDR_TWT_ATTR_PEER_CAP = 19, + ANDR_TWT_ATTR_STATUS = 20, + ANDR_TWT_ATTR_REASON_CODE = 21, + ANDR_TWT_ATTR_TWT_RESUMED = 22, + ANDR_TWT_ATTR_TWT_NOTIFICATION = 23, + ANDR_TWT_ATTR_SUB_EVENT = 24, + ANDR_TWT_ATTR_NUM_PEER_STATS = 25, + ANDR_TWT_ATTR_AVG_PKT_NUM_TX = 26, + ANDR_TWT_ATTR_AVG_PKT_SIZE_TX = 27, + ANDR_TWT_ATTR_AVG_PKT_NUM_RX = 28, + ANDR_TWT_ATTR_AVG_PKT_SIZE_RX = 29, + ANDR_TWT_ATTRIBUTE_SETUP_CMD = 30, + ANDR_TWT_ATTRIBUTE_FLOW_FLAGS = 31, + ANDR_TWT_ATTRIBUTE_FLOW_ID = 32, + ANDR_TWT_ATTRIBUTE_CHANNEL = 33, + ANDR_TWT_ATTR_MAX +} andr_twt_attribute; + +typedef enum { + ANDR_TWT_EVENT_SETUP = 1, + ANDR_TWT_EVENT_TEARDOWN = 2, + ANDR_TWT_EVENT_INFO_FRM = 3, + ANDR_TWT_EVENT_NOTIFY = 4 +} andr_twt_sub_event; +#endif /* WL_TWT_HAL_IF */ + +typedef enum { + ANDR_LSTAT_ATTRIBUTE_INVALID = 0, + ANDR_LSTAT_ATTRIBUTE_NUM_RADIO = 1, + ANDR_LSTAT_ATTRIBUTE_STATS_INFO = 2, + ANDR_LSTAT_ATTRIBUTE_STATS_MAX = 3 +} LINK_STAT_ATTRIBUTE; + +typedef enum { + /* WLAN MAC Operates in 2.4 GHz Band */ + WLAN_MAC_2_4_BAND = 1 << 0, + /* WLAN MAC Operates in 5 GHz Band */ + WLAN_MAC_5_0_BAND = 1 << 1, + /* WLAN MAC Operates in 6 GHz Band */ + WLAN_MAC_6_0_BAND = 1 << 2, + /* WLAN MAC Operates in 60 GHz Band */ + WLAN_MAC_60_0_BAND = 1 << 3 +} wlan_mac_band; + +typedef enum { + TX_POWER_CAP_ATTRIBUTE_INVALID = 0, + TX_POWER_CAP_ENABLE_ATTRIBUTE = 1, + /* Add more attributes here */ + TX_POWER_ATTRIBUTE_MAX +} wifi_tx_power_limits; + +typedef enum { + ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_INVALID = 0, + ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MATRIX = 1, + ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MAX +} wifi_radio_combo_attributes; + +/* Antenna configuration */ +typedef enum { + WIFI_ANTENNA_INVALID = 0, + WIFI_ANTENNA_1X1 = 1, + WIFI_ANTENNA_2X2 = 2, + WIFI_ANTENNA_3X3 = 3, + WIFI_ANTENNA_4X4 = 4 +} wifi_antenna_configuration; + +/* Wifi Radio configuration */ +typedef struct { + /* Operating band */ + wlan_mac_band band; + /* Antenna configuration */ + wifi_antenna_configuration antenna_cfg; +} wifi_radio_configuration; + +/* WiFi Radio Combination */ +typedef struct { + uint32 num_radio_combinations; + wifi_radio_configuration radio_configurations[]; +} wifi_radio_combination; + +/* WiFi Radio combinations matrix */ +typedef struct { + uint32 num_combinations; + /* Each row represents possible radio combinations */ + wifi_radio_combination radio_combinations[]; +} wifi_radio_combination_matrix; + +#define MAX_RADIO_COMBO 5u +#define MAX_RADIO_CONFIGS 2u +#define MAX_RADIO_MATRIX_SIZE (MAX_RADIO_COMBO * (sizeof(wifi_radio_combination) +\ + (MAX_RADIO_CONFIGS * sizeof(wifi_radio_configuration)))) + /* Capture the BRCM_VENDOR_SUBCMD_PRIV_STRINGS* here */ #define BRCM_VENDOR_SCMD_CAPA "cap" #define MEMDUMP_PATH_LEN 128 @@ -779,8 +1162,8 @@ static INLINE int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, { return 0; } #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */ -#if defined(WL_SUPP_EVENT) && \ - ((LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)) +#if defined(WL_SUPP_EVENT) && ((LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || \ + defined(WL_VENDOR_EXT_SUPPORT)) extern int wl_cfgvendor_send_supp_eventstring(const char *func, const char *fmt, ...); int wl_cfgvendor_notify_supp_event_str(const char *evt_name, const char *fmt, ...); #define SUPP_LOG_LEN 256 @@ -790,6 +1173,15 @@ int wl_cfgvendor_notify_supp_event_str(const char *evt_name, const char *fmt, .. #define SUPP_EVT_LOG(evt_name, fmt, ...) \ wl_cfgvendor_notify_supp_event_str(evt_name, fmt, ##__VA_ARGS__); #define SUPP_EVENT(args) SUPP_EVT_LOG args + +#ifdef WL_CFGVENDOR_CUST_ADVLOG +extern int wl_cfgvendor_send_supp_advlog(const char *fmt, ...); +#define PRINT_SUPP_ADVLOG(fmt, ...) \ + wl_cfgvendor_send_supp_advlog(fmt, ##__VA_ARGS__); +#define SUPP_ADVLOG(args) PRINT_SUPP_ADVLOG args; +#else +#define SUPP_ADVLOG(x) +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ #else #define SUPP_LOG(x) #define SUPP_EVENT(x) @@ -806,7 +1198,7 @@ int wl_cfgvendor_notify_supp_event_str(const char *evt_name, const char *fmt, .. compat_ ## normal_structure compat_ ## iface; \ int compat_task_state = is_compat_task(); \ normal_structure value; -#endif +#endif /* LINUX_VER >= 4.6 */ #define COMPAT_BZERO_IFACE(normal_structure, value) \ do { \ @@ -851,14 +1243,34 @@ int wl_cfgvendor_notify_supp_event_str(const char *evt_name, const char *fmt, .. #endif /* CONFIG_COMPAT */ #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \ - LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) #define CFG80211_VENDOR_EVENT_ALLOC(wiphy, wdev, len, type, kflags) \ - cfg80211_vendor_event_alloc(wiphy, wdev, len, type, kflags); + cfg80211_vendor_event_alloc(wiphy, wdev, len, type, kflags) +#define CFG80211_VENDOR_EVENT(msg, kflags) cfg80211_vendor_event(msg, kflags) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) +#define CFG80211_VENDOR_EVENT_ALLOC(wiphy, wdev, len, type, kflags) \ +({ \ + UNUSED_PARAMETER(wdev); \ + cfg80211_vendor_event_alloc(wiphy, len, type, kflags); \ +}) #else -#define CFG80211_VENDOR_EVENT_ALLOC(wiphy, wdev, len, type, kflags) \ - cfg80211_vendor_event_alloc(wiphy, len, type, kflags); -#endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */ - /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */ +/* kernel < 3.14 doesn't provide vendor event alloc */ +#define CFG80211_VENDOR_EVENT_ALLOC(wiphy, wdev, len, type, kflags) \ +({ \ + UNUSED_PARAMETER(wiphy); \ + UNUSED_PARAMETER(wdev); \ + UNUSED_PARAMETER(len); \ + UNUSED_PARAMETER(type); \ + UNUSED_PARAMETER(kflags); \ + NULL; \ +}) +#define CFG80211_VENDOR_EVENT(msg, kflags) \ +({ \ + UNUSED_PARAMETER(msg); \ + UNUSED_PARAMETER(kflags); \ +}) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ + int wl_cfgvendor_nan_send_async_disable_resp(struct wireless_dev *wdev); #ifdef WL_CFGVENDOR_SEND_HANG_EVENT @@ -874,4 +1286,23 @@ int wl_cfgvendor_connect_params_handler(struct wiphy *wiphy, struct wireless_dev const void *data, int len); int wl_cfgvendor_start_ap_params_handler(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len); +#ifdef WL_SOFTAP_ACS +int wl_cfgscan_acs(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, + int len); +#endif /* WL_SOFTAP_ACS */ +#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT +void wl_cfgvendor_send_alert_event(struct net_device *dev, uint32 reason); +#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ +#ifdef TPUT_DEBUG_DUMP +void wl_cfgdbg_tput_debug_mode(struct net_device *ndev, bool enable); +void wl_cfgdbg_tput_debug_work(struct work_struct *work); +int wl_cfgdbg_tput_debug_get_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len); +#endif /* TPUT_DEBUG_DUMP */ +extern int wl_cfgvendor_multista_set_primary_connection(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len); + +#ifdef WL_CFGVENDOR_CUST_ADVLOG +void wl_cfgvendor_custom_advlog_roam_log(void *plog, uint32 armcycle); +#endif /* WL_CFGVENDOR_CUST_ADVLOG */ #endif /* _wl_cfgvendor_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvif.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvif.c old mode 100755 new mode 100644 index e3b60013b640..ea08abf76aec --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvif.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvif.c @@ -1,7 +1,7 @@ /* * Wifi Virtual Interface implementaion * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -35,6 +35,10 @@ #include #endif /* WL_WPS_SYNC */ #include <802.11.h> +#ifdef BCMWAPI_WPI +#include <802.11wapi.h> +#endif +#include <802.11wfa.h> #include #include #include @@ -89,9 +93,10 @@ #ifdef BCMPCIE #include #endif -#if defined(BIGDATA_SOFTAP) || defined(DHD_ENABLE_BIGDATA_LOGGING) -#include -#endif /* BIGDATA_SOFTAP || DHD_ENABLE_BIGDATA_LOGGING */ + +#ifdef WL_CELLULAR_CHAN_AVOID +#include +#endif /* WL_CELLULAR_CHAN_AVOID */ #include #define MAX_VIF_OFFSET 15 @@ -117,18 +122,17 @@ #define DNGL_FUNC(func, parameters) #else #define DNGL_FUNC(func, parameters) func parameters -#define COEX_DHCP #endif /* defined(BCMDONGLEHOST) */ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \ -(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ + 4 && __GNUC_MINOR__ >= 6)) _Pragma("GCC diagnostic pop") #endif /* SoftAP related parameters */ #define DEFAULT_2G_SOFTAP_CHANNEL 1 -#define DEFAULT_2G_SOFTAP_CHANSPEC 0x1006 +#define DEFAULT_2G_SOFTAP_CHANSPEC 0x1001 #define DEFAULT_5G_SOFTAP_CHANNEL 149 #define MAX_VNDR_OUI_STR_LEN 256u @@ -185,13 +189,18 @@ static void wl_update_apchan_bwcap(struct bcm_cfg80211 *cfg, struct net_device *ndev, chanspec_t chanspec); #endif /* SUPPORT_AP_BWCTRL */ -#if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, 0))) +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, \ + 0))) struct chan_info { int freq; int chan_type; }; #endif +#ifdef WL_STATIC_IF +#define WL_BSSIDX_MAX 16 +#endif /* WL_STATIC_IF */ + #if defined(WL_FW_OCE_AP_SELECT) bool wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint) { @@ -360,8 +369,8 @@ wl_cfg80211_is_policy_config_allowed(struct bcm_cfg80211 *cfg) mutex_lock(&cfg->if_sync); - sta_assoc_state = (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || - wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))); + sta_assoc_state = (wl_get_drv_status_all(cfg, CONNECTED) || + wl_get_drv_status_all(cfg, CONNECTING)); active_sec_iface = wl_cfg80211_get_sec_iface(cfg); p2p_disc_on = wl_get_p2p_status(cfg, SCANNING); @@ -384,6 +393,7 @@ wl_cfg80211_is_policy_config_allowed(struct bcm_cfg80211 *cfg) return ret; } #endif /* WL_IFACE_MGMT */ + #ifdef WL_NANP2P int wl_cfg80211_set_iface_conc_disc(struct net_device *ndev, @@ -419,6 +429,7 @@ wl_cfg80211_get_iface_conc_disc(struct net_device *ndev) return cfg->conc_disc; } #endif /* WL_NANP2P */ + #ifdef WL_IFACE_MGMT int wl_cfg80211_set_iface_policy(struct net_device *ndev, @@ -482,33 +493,19 @@ wl_cfg80211_get_iface_policy(struct net_device *ndev) #endif /* WL_IFACE_MGMT */ #endif /* WL_IFACE_MGMT_CONF */ -#ifdef WL_IFACE_MGMT /* Get active secondary data iface type */ wl_iftype_t wl_cfg80211_get_sec_iface(struct bcm_cfg80211 *cfg) { -#ifdef WL_STATIC_IF - struct net_device *static_if_ndev; -#else dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); -#endif /* WL_STATIC_IF */ struct net_device *p2p_ndev = NULL; p2p_ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1); -#ifdef WL_STATIC_IF - static_if_ndev = wl_cfg80211_static_if_active(cfg); - if (static_if_ndev) { - if (IS_AP_IFACE(static_if_ndev->ieee80211_ptr)) { - return WL_IF_TYPE_AP; - } - } -#else if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { return WL_IF_TYPE_AP; } -#endif /* WL_STATIC_IF */ if (p2p_ndev && p2p_ndev->ieee80211_ptr) { if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) { @@ -519,7 +516,7 @@ wl_cfg80211_get_sec_iface(struct bcm_cfg80211 *cfg) * role to station type while bringing down the interface */ if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) { - WL_DBG_MEM(("%s, Change to GC base role\n", __FUNCTION__)); + WL_DBG_MEM(("%s, Change to GC base role\n", p2p_ndev->name)); return WL_IF_TYPE_P2P_GC; } @@ -529,13 +526,15 @@ wl_cfg80211_get_sec_iface(struct bcm_cfg80211 *cfg) } #ifdef WL_NAN - if (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg))) { + if (wl_cfgnan_is_nan_active(bcmcfg_to_prmry_ndev(cfg)) || + wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg))) { return WL_IF_TYPE_NAN; } #endif /* WL_NAN */ return WL_IFACE_NOT_PRESENT; } +#ifdef WL_IFACE_MGMT /* * Handle incoming data interface request based on policy. * If there is any conflicting interface, that will be @@ -563,6 +562,26 @@ wl_cfg80211_data_if_mgmt(struct bcm_cfg80211 *cfg, return BCME_OK; } +#ifdef WL_DUAL_APSTA + if (sec_wl_if_type == WL_IF_TYPE_AP && + (new_wl_iftype == WL_IF_TYPE_AP || new_wl_iftype == WL_IF_TYPE_STA)) { + /* For Dual APSTA configuration allow starting new AP/STA even though + * secondary interface is AP + */ + return BCME_OK; + } +#else +#ifdef BCMDONGLEHOST + if (DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE)) { + if (sec_wl_if_type == WL_IF_TYPE_AP && + (new_wl_iftype == WL_IF_TYPE_AP || new_wl_iftype == WL_IF_TYPE_STA)) { + /* RSDB chip can allow dual apsta */ + return BCME_OK; + } + } +#endif /* BCMDONGLEHOST */ +#endif /* WL_DUAL_APSTA */ + /* Handle secondary data link case */ switch (cfg->iface_data.policy) { case WL_IF_POLICY_CUSTOM: @@ -647,6 +666,8 @@ wl_cfg80211_disc_if_mgmt(struct bcm_cfg80211 *cfg, * as for AP and associated ifaces, both are same */ } + /* fall through */ + fallthrough; case WL_IF_POLICY_DEFAULT: { if (sec_wl_if_type == WL_IF_TYPE_AP) { WL_INFORM_MEM(("AP is active, cant support new iface\n")); @@ -659,10 +680,11 @@ wl_cfg80211_disc_if_mgmt(struct bcm_cfg80211 *cfg, * Fall through */ } else { - /* Active iface is present, returning error */ - WL_INFORM_MEM(("P2P group is active," - " cant support new iface\n")); - ret = BCME_ERROR; + /* clear associated group interfaces */ + WL_INFORM_MEM(("remove P2P group," + " to support new iface\n")); + ret = wl_cfg80211_delete_iface(cfg, + sec_wl_if_type); } } else if (sec_wl_if_type == WL_IF_TYPE_NAN) { ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type); @@ -845,7 +867,7 @@ wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 *cfg, dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); #endif - WL_INFORM_MEM(("Incoming iface = %s\n", wl_iftype_to_str(new_wl_iftype))); + WL_DBG_MEM(("Incoming iface = %s\n", wl_iftype_to_str(new_wl_iftype))); #ifdef P2P_AP_CONCURRENT if (dhd->conf->war & P2P_AP_MAC_CONFLICT) { @@ -861,6 +883,7 @@ wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 *cfg, /* Incoming data interface request */ if (wl_cfg80211_get_sec_iface(cfg) != WL_IFACE_NOT_PRESENT) { /* active interface present - Apply interface data policy */ + WL_INFORM_MEM(("apply iface policy for %d\n", new_wl_iftype)); ret = wl_cfg80211_data_if_mgmt(cfg, new_wl_iftype); if (ret != BCME_OK) { WL_ERR(("if_mgmt fail:%d\n", ret)); @@ -875,7 +898,7 @@ wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 *cfg, #endif /* WL_IFACE_MGMT */ s32 -wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, u8 *mac_addr, u16 wl_iftype) +wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, const u8 *mac_addr, u16 wl_iftype) { struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); u16 org_toggle_bytes; @@ -888,6 +911,7 @@ wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, u8 *mac_addr, u16 wl_iftype) WL_DBG(("%s:Mac addr" MACDBG "\n", __FUNCTION__, MAC2STRDBG(mac_addr))); +#if defined(SPECIFIC_MAC_GEN_SCHEME) if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_AP) || (wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) { /* Avoid invoking release mac addr code for interfaces using @@ -895,10 +919,15 @@ wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, u8 *mac_addr, u16 wl_iftype) */ return BCME_OK; } +#else + if (wl_iftype == WL_IF_TYPE_P2P_DISC) { + return BCME_OK; + } +#endif /* SPECIFIC_MAC_GEN_SCHEME */ /* Fetch last two bytes of mac address */ org_toggle_bytes = ntoh16(*((u16 *)&ndev->dev_addr[4])); - cur_toggle_bytes = ntoh16(*((u16 *)&mac_addr[4])); + cur_toggle_bytes = ntoh16(*((const u16 *)&mac_addr[4])); toggled_bit = (org_toggle_bytes ^ cur_toggle_bytes); WL_DBG(("org_toggle_bytes:%04X cur_toggle_bytes:%04X\n", @@ -951,7 +980,7 @@ wl_get_vif_macaddr(struct bcm_cfg80211 *cfg, u16 wl_iftype, u8 *mac_addr) * released. Ensure to call wl_release_vif_macaddress to free up * the mac address. */ -#if defined (SPECIFIC_MAC_GEN_SCHEME) +#if defined(SPECIFIC_MAC_GEN_SCHEME) if (wl_iftype == WL_IF_TYPE_P2P_DISC || wl_iftype == WL_IF_TYPE_AP) { mac_addr[0] |= 0x02; } else if ((wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) { @@ -962,7 +991,7 @@ wl_get_vif_macaddr(struct bcm_cfg80211 *cfg, u16 wl_iftype, u8 *mac_addr) if (wl_iftype == WL_IF_TYPE_P2P_DISC) { mac_addr[0] |= 0x02; } -#endif /* SEPCIFIC_MAC_GEN_SCHEME */ +#endif /* SPECIFIC_MAC_GEN_SCHEME */ else { /* For locally administered mac addresses, we keep the * OUI part constant and just work on the last two bytes. @@ -1071,6 +1100,14 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) return -ENODEV; } +#ifdef WL_STATIC_IF + /* interface delete is invalid for static interface */ + if (wl_cfg80211_static_if(cfg, wdev_to_ndev(wdev))) { + WL_ERR(("Invalid request to delete static interface %s\n", wdev->netdev->name)); + return -EINVAL; + } +#endif /* WL_STATIC_IF */ + WL_DBG(("Enter wdev:%p iftype: %d\n", wdev, wdev->iftype)); if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) { WL_ERR(("Wrong iftype: %d\n", wdev->iftype)); @@ -1224,8 +1261,9 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, } mutex_lock(&cfg->if_sync); + netinfo = wl_get_netinfo_by_wdev(cfg, ndev->ieee80211_ptr); - if (unlikely(!netinfo)) { + if (!netinfo) { #ifdef WL_STATIC_IF if (wl_cfg80211_static_if(cfg, ndev)) { /* Incase of static interfaces, the netinfo will be @@ -1235,12 +1273,11 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, WL_INFORM_MEM(("skip change vif for static if\n")); ndev->ieee80211_ptr->iftype = type; err = BCME_OK; - } else -#endif /* WL_STATIC_IF */ - { - WL_ERR(("netinfo not found \n")); - err = -ENODEV; + goto fail; } +#endif /* WL_STATIC_IF */ + WL_ERR(("netinfo not found \n")); + err = -ENODEV; goto fail; } @@ -1273,11 +1310,20 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, WL_ERR(("P2P downgrade failed \n")); } } else if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) { - /* Downgrade role from AP to STA */ - if ((err = wl_cfg80211_add_del_bss(cfg, ndev, - netinfo->bssidx, wl_iftype, 0, NULL)) < 0) { - WL_ERR(("AP-STA Downgrade failed \n")); - goto fail; +#ifdef WL_SKIP_AP_ROLE_DOWNGRADE + if (!wl_get_drv_status(cfg, AP_ROLE_UPGRADED, ndev)) { + /* Interface created with AP type. Downgrade not required */ + WL_DBG(("Skip AP downgrade\n")); + } else +#endif /* WL_SKIP_AP_ROLE_DOWNGRADE */ + { + wl_clr_drv_status(cfg, AP_ROLE_UPGRADED, ndev); + /* Downgrade role from AP to STA */ + if ((err = wl_cfg80211_add_del_bss(cfg, ndev, + netinfo->bssidx, wl_iftype, 0, NULL)) < 0) { + WL_ERR(("AP-STA Downgrade failed \n")); + goto fail; + } } } break; @@ -1295,6 +1341,8 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, WL_ERR(("set ap role failed!\n")); goto fail; } + /* Mark AP role upgrade */ + wl_set_drv_status(cfg, AP_ROLE_UPGRADED, ndev); } else { WL_INFORM_MEM(("AP_CREATED bit set. Skip role change\n")); } @@ -1307,6 +1355,11 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, err = wl_cfg80211_change_p2prole(wiphy, ndev, type); break; case NL80211_IFTYPE_MONITOR: +#ifdef WL_CFG80211_MONITOR + if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) { + break; + } +#endif /* WL_CFG80211_MONITOR */ case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_MESH_POINT: /* Intentional fall through */ @@ -1331,9 +1384,9 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, if (is_p2p_group_iface(ndev->ieee80211_ptr) && (type == NL80211_IFTYPE_STATION)) { /* For role downgrade cases, we keep interface role as GC */ netinfo->iftype = WL_IF_TYPE_P2P_GC; - WL_DBG_MEM(("[%s] Set base role to GC, current role" + WL_DBG_MEM(("[%s] Set base role to GC, current role" "ndev->ieee80211_ptr->iftype = %d\n", - __FUNCTION__, ndev->ieee80211_ptr->iftype)); + ndev->name, ndev->ieee80211_ptr->iftype)); } else { netinfo->iftype = wl_iftype; } @@ -1439,6 +1492,15 @@ wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211 *cfg, bool rtnl_lock_reqd { dev_close(iter->ndev); WL_DBG(("Cleaning up iface:%s \n", iter->ndev->name)); +#if defined(WLAN_ACCEL_BOOT) + /* Trigger force reg_on to ensure clean up of virtual interface + * states in FW for any residual interface states, casued due to + * framework crashes + */ + WL_ERR(("Setting forced reg_on to enusre clearing" + " interface states in FW\n")); + dhd_dev_set_accel_force_reg_on(iter->ndev); +#endif /* WLAN_ACCEL_BOOT */ wl_cfg80211_post_ifdel(iter->ndev, rtnl_lock_reqd, 0); } } @@ -1505,6 +1567,16 @@ wl_get_bandwidth_cap(struct net_device *ndev, uint32 band, uint32 *bandwidth) bw = WL_CHANSPEC_BW_20; } +#if defined(LIMIT_AP_BW) + if (band == WL_CHANSPEC_BAND_6G) { + struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); + if (cfg->ap_bw_chspec != INVCHANSPEC && + (wf_bw_chspec_to_mhz(cfg->ap_bw_chspec) < wf_bw_chspec_to_mhz(bw))) { + bw = cfg->ap_bw_chspec; + } + } +#endif /* LIMIT_AP_BW */ + *bandwidth = bw; return err; @@ -1520,14 +1592,18 @@ wl_get_nl80211_band(u32 wl_band) return IEEE80211_BAND_2GHZ; case WL_CHANSPEC_BAND_5G: return IEEE80211_BAND_5GHZ; -#ifdef WL_BAND_6G +#ifdef WL_6G_BAND case WL_CHANSPEC_BAND_6G: +#ifdef CFG80211_6G_SUPPORT + return IEEE80211_BAND_6GHZ; +#else /* CFG80211_6G_SUPPORT */ /* current kernels doesn't support seperate * band for 6GHz. so till patch is available * map it under 5GHz */ return IEEE80211_BAND_5GHZ; -#endif /* WL_BAND_6G */ +#endif /* CFG80211_6G_SUPPORT */ +#endif /* WL_6G_BAND */ default: WL_ERR(("unsupported Band. %d\n", wl_band)); } @@ -1535,22 +1611,121 @@ wl_get_nl80211_band(u32 wl_band) return err; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) +#ifdef SUPPORT_2G_VHT +static struct ieee80211_channel * +wl_cfg80211_get_ieee80211_chan(struct net_device *dev, + struct cfg80211_ap_settings *info) +{ + struct ieee80211_channel * ptr = NULL; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) + if (info) { + ptr = info->chandef.chan; + } +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + if (info) { + ptr = info->channel; + } +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) */ + if ((dev) && (dev->ieee80211_ptr)) { + ptr = dev->ieee80211_ptr->channel; + } +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) */ + + return ptr; +} +#endif /* SUPPORT_2G_VHT */ +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) */ + +bool +wl_is_sta_connected(struct bcm_cfg80211 *cfg) +{ + bool sta_connected = false; + +#ifdef WL_DUAL_APSTA + if (wl_get_drv_status_all(cfg, CONNECTED) >= 2) { + /* If both STA interfaces are connected return failure */ + return false; + } else { + struct net_info *iter, *next; + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + for_each_ndev(cfg, iter, next) { + GCC_DIAGNOSTIC_POP(); + if ((iter->ndev) && (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) && + (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION)) { + return true; + } + } + } +#else + if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) { + return true; + } +#endif /* WL_DUAL_APSTA */ + + return sta_connected; +} + s32 wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + enum nl80211_channel_type channel_type +#else + enum nl80211_chan_width width +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) */ +) { chanspec_t chspec = INVCHANSPEC; chanspec_t cur_chspec = INVCHANSPEC; - u32 bw = WL_CHANSPEC_BW_20; + u32 band_width = WL_CHANSPEC_BW_20, bw = WL_CHANSPEC_BW_20; s32 err = BCME_OK; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); -#if defined(CUSTOM_SET_CPUCORE) || defined(APSTA_RESTRICTED_CHANNEL) + wl_ap_oper_data_t ap_oper_data = {0}; dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); -#endif /* CUSTOM_SET_CPUCORE || APSTA_RESTRICTED_CHANNEL */ +#if defined(SUPPORT_AP_INIT_BWCONF) + u32 configured_bw; +#endif /* SUPPORT_AP_INIT_BWCONF */ u16 center_freq = chan->center_freq; + BCM_REFERENCE(dhd); + dev = ndev_to_wlc_ndev(dev, cfg); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + switch (channel_type) { + case NL80211_CHAN_HT40MINUS: + /* secondary channel is below the control channel */ + band_width = WL_CHANSPEC_BW_40; + break; + case NL80211_CHAN_HT40PLUS: + /* secondary channel is above the control channel */ + band_width = WL_CHANSPEC_BW_40; + break; + default: + band_width = WL_CHANSPEC_BW_20; + } +#else + switch (width) + { + case NL80211_CHAN_WIDTH_160: + band_width = WL_CHANSPEC_BW_160; + break; + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_80: + band_width = WL_CHANSPEC_BW_80; + break; + case NL80211_CHAN_WIDTH_40: + band_width = WL_CHANSPEC_BW_40; + break; + default: + band_width = WL_CHANSPEC_BW_20; + break; + } +#endif + #ifdef WL_EXT_IAPSTA if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP || dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) { @@ -1571,9 +1746,17 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, #endif chspec = wl_freq_to_chanspec(center_freq); - WL_MSG(dev->name, "netdev_ifidx(%d), chan_type(%d) target channel(%s-%d) \n", - dev->ifindex, channel_type, CHSPEC2BANDSTR(chspec), CHSPEC_CHANNEL(chspec)); + WL_MSG(dev->name, "netdev_ifidx(%d) target channel(%s-%d %sMHz)\n", + dev->ifindex, CHSPEC2BANDSTR(chspec), + CHSPEC_CHANNEL(chspec), WLCWIDTH2STR(band_width)); +#ifdef WL_DUAL_STA + /* In case of Dual STA if both STAs are connected, do not allow softAP bringup */ + if (wl_cfgvif_get_iftype_count(cfg, WL_IF_TYPE_STA) >= 2) { + WL_ERR(("Dual STA case, softAP bringup not supported\n")); + return -ENOTSUPP; + } +#endif /* WL_DUAL_STA */ #ifdef WL_P2P_6G if (!(cfg->p2p_6g_enabled)) { #endif /* WL_P2P_6G */ @@ -1584,34 +1767,72 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, #ifdef WL_P2P_6G } #endif /* WL_P2P_6G */ - -#ifdef NOT_YET - switch (channel_type) { - case NL80211_CHAN_HT40MINUS: - /* secondary channel is below the control channel */ - chspec = CH40MHZ_CHSPEC(CHSPEC_CHANNEL(chspec), WL_CHANSPEC_CTL_SB_UPPER); - break; - case NL80211_CHAN_HT40PLUS: - /* secondary channel is above the control channel */ - chspec = CH40MHZ_CHSPEC(CHSPEC_CHANNEL(chspec), WL_CHANSPEC_CTL_SB_LOWER); - break; - default: - chspec = CH20MHZ_CHSPEC(CHSPEC_CHANNEL(chspec)); - +#ifndef WL_SOFTAP_6G + if (IS_AP_IFACE(dev->ieee80211_ptr) && (CHSPEC_IS6G(chspec))) { + WL_ERR(("AP not allowed on 6G\n")); + return -ENOTSUPP; + } +#endif /* WL_SOFTAP_6G */ + +#ifdef WL_UNII4_CHAN + if (CHSPEC_IS5G(chspec) && + IS_UNII4_CHANNEL(wf_chspec_primary20_chan(chspec))) { + WL_ERR(("AP not allowed on UNII-4 chanspec 0x%x\n", chspec)); + return -ENOTSUPP; + } +#endif /* WL_UNII4_CHAN */ + /* Check whether AP is already operational */ + wl_get_ap_chanspecs(cfg, &ap_oper_data); + if (ap_oper_data.count >= MAX_AP_IFACES) { + WL_ERR(("ACS request in multi AP case!! count:%d\n", + ap_oper_data.count)); + return -EINVAL; + } + + if (ap_oper_data.count == 1) { + chanspec_t sta_chspec; + chanspec_t ch = ap_oper_data.iface[0].chspec; + u16 ap_band, incoming_band; + + /* Single AP case. Bring up the AP in the other band */ + ap_band = CHSPEC_TO_WLC_BAND(ch); + incoming_band = CHSPEC_TO_WLC_BAND(chspec); + WL_INFORM_MEM(("AP operational in band:%d and incoming band:%d\n", + ap_band, incoming_band)); + /* if incoming and operational AP band is same, it is invalid case */ + if (ap_band == incoming_band) { + WL_ERR(("DUAL AP not allowed on same band\n")); + return -ENOTSUPP; + } + sta_chspec = wl_cfg80211_get_sta_chanspec(cfg); + if (sta_chspec && wf_chspec_valid(sta_chspec)) { + /* 5G cant be upgraded to 6G since dual band clients + * wont be able able to scan 6G + */ + if (CHSPEC_IS6G(sta_chspec) && (incoming_band == WLC_BAND_5G)) { + WL_ERR(("DUAL AP not allowed for" + " 5G band as sta in 6G chspec 0x%x\n", + chspec)); + return -ENOTSUPP; + } + if (incoming_band == CHSPEC_TO_WLC_BAND(sta_chspec)) { + /* use sta chanspec for SCC */ + chspec = sta_chspec; + } + } } -#endif /* NOT_YET */ #if defined(APSTA_RESTRICTED_CHANNEL) /* Some customer platform used limited number of channels * for SoftAP interface on STA/SoftAP concurrent mode. * - 2.4GHz Channel: CH1 - CH13 - * - 5GHz Channel: CH149 (it depends on the country code) + * - 5GHz Channel: CH 149, 153, 157, 161 (it depends on the country code) * If the Android framework sent invaild channel configuration - * to DHD, driver should change the channel which is sutible for + * to DHD, driver should change the channel which is suitable for * STA/SoftAP concurrent mode. * - Set operating channel to CH1 (default 2.4GHz channel for * restricted APSTA mode) if STA interface was associated to - * 5GHz APs except for CH149. + * 5GHz APs except for CH149, 153, 157, 161. * - Otherwise, set the channel to the same channel as existing AP. */ if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP && @@ -1623,11 +1844,13 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, /* Do not try SCC in 5GHz if channel is not CH149 */ chspec = ( #ifdef WL_6G_BAND - CHSPEC_IS6G(*sta_chanspec) || + (CHSPEC_IS6G(*sta_chanspec) && + (!CHSPEC_IS_6G_PSC(*sta_chanspec) || + (wf_chspec_primary20_chspec(*sta_chanspec) != + wf_chspec_primary20_chspec(chspec)))) || #endif /* WL_6G_BAND */ (CHSPEC_IS5G(*sta_chanspec) && - wf_chspec_primary20_chan(*sta_chanspec) != - DEFAULT_5G_SOFTAP_CHANNEL)) ? + !IS_5G_APCS_CHANNEL(wf_chspec_primary20_chan(*sta_chanspec)))) ? DEFAULT_2G_SOFTAP_CHANSPEC: *sta_chanspec; WL_ERR(("target chanspec will be changed to %x\n", chspec)); if (CHSPEC_IS2G(chspec)) { @@ -1642,24 +1865,76 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, if (err < 0) { WL_ERR(("Failed to get bandwidth information, err=%d\n", err)); return err; + } else if (bw < band_width) { + WL_ERR(("capability force band_width=0x%X to be 0x%X\n", band_width, bw)); + band_width = bw; } +#ifdef HOSTAPD_BW_SUPPORT + WL_MSG(dev->name, "hostapd bw(%sMHz) <= chip bw(%sMHz)\n", + wf_chspec_to_bw_str(band_width), wf_chspec_to_bw_str(bw)); +#else + WL_MSG(dev->name, "hostapd bw(%sMHz) => chip bw(%sMHz)\n", + wf_chspec_to_bw_str(band_width), wf_chspec_to_bw_str(bw)); + band_width = bw; +#endif + +#if defined(SUPPORT_AP_INIT_BWCONF) + /* Update BW for 5G and 6G SoftAP if BW is configured */ + configured_bw = wl_update_configured_bw(wl_get_configured_ap_bw(dhd)); + if (configured_bw != INVCHANSPEC) { + bw = configured_bw; + } +#endif /* SUPPORT_AP_INIT_BWCONF */ /* In case of 5G downgrade BW to 80MHz as 160MHz channels falls in DFS */ if (CHSPEC_IS5G(chspec) && (bw == WL_CHANSPEC_BW_160)) { bw = WL_CHANSPEC_BW_80; } + +#ifdef WL_UNII4_CHAN + /* Handle 165/20 channel as special case to not upgrade the bw */ + if (IS_5G_UNII4_165_CHANNEL(chspec)) { + bw = WL_CHANSPEC_BW_20; + } +#endif /* WL_UNII4_CHAN */ + +#ifdef WL_CELLULAR_CHAN_AVOID + if (!CHSPEC_IS6G(chspec)) { + wl_cellavoid_sanity_check_chan_info_list(cfg->cellavoid_info); + wl_cellavoid_sync_lock(cfg); + cur_chspec = wl_cellavoid_find_widechspec_fromchspec(cfg->cellavoid_info, chspec); + if (cur_chspec == INVCHANSPEC) { + wl_cellavoid_sync_unlock(cfg); + return BCME_ERROR; + } + /* Limit the configured bw to the bw from the safe channel list */ + if (bw > CHSPEC_BW(cur_chspec)) { + WL_INFORM_MEM(("cellular avoidance update org_bw %x to bw %x\n", + bw, CHSPEC_BW(cur_chspec))); + bw = CHSPEC_BW(cur_chspec); + } + + wl_cellavoid_sync_unlock(cfg); + } +#endif /* WL_CELLULAR_CHAN_AVOID */ set_channel: + WL_DBG(("bw = %x, chspec =%x, chspec band = %x\n", bw, chspec, CHSPEC_BAND(chspec))); +#ifdef WL_6G_320_SUPPORT cur_chspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(chspec), - bw, CHSPEC_BAND(chspec)); + band_width, CHSPEC_BAND(chspec), 0); +#else + cur_chspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(chspec), + band_width, CHSPEC_BAND(chspec)); +#endif /* WL_6G_320_SUPPORT */ #ifdef WL_6G_BAND if (cfg->acs_chspec && CHSPEC_IS6G(cfg->acs_chspec) && (wf_chspec_ctlchspec(cfg->acs_chspec) == wf_chspec_ctlchspec(cur_chspec))) { WL_DBG(("using acs_chanspec %x\n", cfg->acs_chspec)); cur_chspec = cfg->acs_chspec; - cfg->acs_chspec = 0; } #endif /* WL_6G_BAND */ + cfg->acs_chspec = 0; if (wf_chspec_valid(cur_chspec)) { /* convert 802.11 ac chanspec to current fw chanspec type */ cur_chspec = wl_chspec_host_to_driver(cur_chspec); @@ -1682,14 +1957,17 @@ set_channel: #ifdef DISABLE_WL_FRAMEBURST_SOFTAP else { /* Disable Frameburst only for stand-alone 2GHz SoftAP */ - if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP && - DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) && - (CHSPEC_IS2G(chspec)) && - !wl_get_drv_status(cfg, CONNECTED, - bcmcfg_to_prmry_ndev(cfg))) { - WL_DBG(("Disabling frameburst on " - "stand-alone 2GHz SoftAP\n")); - wl_cfg80211_set_frameburst(cfg, FALSE); + if ((wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) && + DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE)) { + if (CHSPEC_IS2G(chspec) && !wl_is_sta_connected(cfg)) { + WL_DBG(("Disabling frameburst on " + "stand-alone 2GHz SoftAP\n")); + wl_cfg80211_set_frameburst(cfg, FALSE); + } else if (!CHSPEC_IS2G(chspec) && + cfg->frameburst_disabled) { + WL_INFORM(("Enable back frameburst\n")); + wl_cfg80211_set_frameburst(cfg, TRUE); + } } } #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */ @@ -1813,7 +2091,7 @@ wl_validate_fils_ind_ie(struct net_device *dev, const bcm_tlv_t *filsindie, s32 err = BCME_NOMEM; goto exit; } - iov_buf->version = WL_FILS_IOV_VERSION; + iov_buf->version = WL_FILS_IOV_VERSION_1_1; iov_buf->id = WL_FILS_CMD_ADD_IND_IE; iov_buf->len = sizeof(bcm_xtlv_t) + filsindie->len - 1; pxtlv = (bcm_xtlv_t*)&iov_buf->data[0]; @@ -2013,6 +2291,11 @@ wl_validate_wpa2ie(struct net_device *dev, const bcm_tlv_t *wpa2ie, s32 bssidx) break; #endif /* WL_SAE || WL_CLIENT_SAE */ #endif /* MFP */ +#if defined(WL_OWE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) + case RSN_AKM_OWE: + wpa_auth |= WPA3_AUTH_OWE; + break; +#endif /* WL_OWE && LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) */ default: WL_ERR(("No Key Mgmt Info\n")); } @@ -2262,38 +2545,8 @@ exit: return 0; } -#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED) -static u32 wl_get_cipher_type(uint8 type) -{ - u32 ret = 0; - switch (type) { - case WPA_CIPHER_NONE: - ret = 0; - break; - case WPA_CIPHER_WEP_40: - case WPA_CIPHER_WEP_104: - ret = WEP_ENABLED; - break; - case WPA_CIPHER_TKIP: - ret = TKIP_ENABLED; - break; - case WPA_CIPHER_AES_CCM: - ret = AES_ENABLED; - break; - -#ifdef BCMWAPI_WPI - case WAPI_CIPHER_SMS4: - ret = SMS4_ENABLED; - break; -#endif - - default: - WL_ERR(("No Security Info\n")); - } - return ret; -} - -static u32 wl_get_suite_auth_key_mgmt_type(uint8 type, const wpa_suite_mcast_t *mcast) +static u32 +wl_get_suite_auth_key_mgmt_type(uint8 type, const wpa_suite_mcast_t *mcast) { u32 ret = 0; u32 is_wpa2 = 0; @@ -2343,6 +2596,82 @@ static u32 wl_get_suite_auth_key_mgmt_type(uint8 type, const wpa_suite_mcast_t * return ret; } +s32 +wl_update_akm_from_assoc_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, + u8 *assoc_ies, u32 assoc_ie_len) +{ + const wpa_suite_mcast_t *mcast; + const wpa_suite_ucast_t *ucast; + const wpa_suite_auth_key_mgmt_t *mgmt; + struct parsed_ies parsed_assoc_ies; + const bcm_tlv_t *wpa2ie; + u16 suite_count; + struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); + + WL_DBG(("Enter \n")); + + /* Parse assoc IEs */ + if (wl_cfg80211_parse_ies(assoc_ies, assoc_ie_len, &parsed_assoc_ies) < 0) { + WL_ERR(("Get Assoc IEs failed\n")); + return 0; + } + + if (parsed_assoc_ies.wpa2_ie == NULL) { + WL_DBG(("wpa2_ie\n")); + return -EINVAL; + } else { + wpa2ie = parsed_assoc_ies.wpa2_ie; + } + + /* Get the mcast cipher */ + mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; + + /* Get the unicast cipher */ + ucast = (const wpa_suite_ucast_t *)&mcast[1]; + suite_count = ltoh16_ua(&ucast->count); + + /* check and update the AKM and FW auth in DHD security profile */ + mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; + sec->wpa_auth = ntoh32_ua(&mgmt->list[0]); + sec->fw_wpa_auth = wl_get_suite_auth_key_mgmt_type(mgmt->list[0].type, mcast); + + WL_INFORM(("AKM updated from assoc ie in DHD Security profile = 0x%X 0x%X\n", + sec->wpa_auth, sec->fw_wpa_auth)); + + return 0; +} + +#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED) +static u32 wl_get_cipher_type(uint8 type) +{ + u32 ret = 0; + switch (type) { + case WPA_CIPHER_NONE: + ret = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + ret = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + ret = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + ret = AES_ENABLED; + break; + +#ifdef BCMWAPI_WPI + case WAPI_CIPHER_SMS4: + ret = SMS4_ENABLED; + break; +#endif + + default: + WL_ERR(("No Security Info\n")); + } + return ret; +} + static s32 wl_validate_wpaie_wpa2ie(struct net_device *dev, const wpa_ie_fixed_t *wpaie, const bcm_tlv_t *wpa2ie, s32 bssidx) @@ -2538,6 +2867,42 @@ exit: } #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */ +static s32 +wl_set_ap_passphrase(struct net_device *dev) +{ + struct net_info *_net_info; + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + wl_config_passphrase_t pp_config; + int err = BCME_OK; + bzero(&pp_config, sizeof(wl_config_passphrase_t)); + + _net_info = wl_get_netinfo_by_netdev(cfg, dev); + + if (_net_info == NULL) { + WL_ERR(("net_info not found for iface %s", dev->name)); + err = BCME_BADARG; + goto done; + } + + if ((cfg->hostapd_ssid.SSID_len == 0) || + (_net_info->passphrase_len == 0)) { + WL_ERR(("Invalid config ssid_len %d passphrase_len %d", + cfg->hostapd_ssid.SSID_len, _net_info->passphrase_len)); + err = BCME_BADARG; + goto done; + } + + pp_config.ssid = cfg->hostapd_ssid.SSID; + pp_config.ssid_len = cfg->hostapd_ssid.SSID_len; + pp_config.passphrase = _net_info->passphrase; + pp_config.passphrase_len = _net_info->passphrase_len; + + err = wl_cfg80211_config_passphrase(cfg, dev, &pp_config); + +done: + return err; +} + static s32 wl_cfg80211_bcn_validate_sec( struct net_device *dev, @@ -2582,6 +2947,14 @@ wl_cfg80211_bcn_validate_sec( return BCME_ERROR; } + BCM_REFERENCE(wl_set_ap_passphrase); +#ifdef WL_SAE + /* Set SAE passphrase */ + if (sec->fw_wpa_auth & WPA3_AUTH_SAE_PSK) { + wl_set_ap_passphrase(dev); + } +#endif /* WL_SAE */ + if (ies->fils_ind_ie && (wl_validate_fils_ind_ie(dev, ies->fils_ind_ie, bssidx) < 0)) { bss->security_mode = false; @@ -2665,8 +3038,7 @@ wl_cfg80211_bcn_validate_sec( } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) static s32 wl_cfg80211_bcn_set_params( struct cfg80211_ap_settings *info, struct net_device *dev, @@ -2728,6 +3100,16 @@ wl_cfg80211_parse_ies(const u8 *ptr, u32 len, struct parsed_ies *ies) } else { WL_DBG(("No WPSIE in beacon \n")); } + /* find rates IEs */ + if ((ies->rate_ie = bcm_parse_tlvs(ptr, len, + DOT11_MNG_RATES_ID)) != NULL) { + ies->rate_ie_len = ies->rate_ie->len; + } + + if ((ies->ext_rate_ie = bcm_parse_tlvs(ptr, len, + DOT11_MNG_EXT_RATES_ID)) != NULL) { + ies->ext_rate_ie_len = ies->ext_rate_ie->len; + } /* find the RSN_IE */ if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len, @@ -2769,7 +3151,7 @@ wl_cfg80211_set_ap_role( dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); #endif /* WLEASYMESH */ - new_chip = wl_new_chip_check(dev); + new_chip = dhd_conf_new_chip_check(cfg->pub); if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr)); @@ -2927,7 +3309,7 @@ wl_cfg80211_set_ap_role( void wl_cfg80211_ap_timeout_work(struct work_struct *work) { -#if defined (BCMDONGLEHOST) +#if defined(BCMDONGLEHOST) struct bcm_cfg80211 *cfg = NULL; dhd_pub_t *dhdp = NULL; BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, ap_work.work); @@ -2937,9 +3319,6 @@ wl_cfg80211_ap_timeout_work(struct work_struct *work) if (dhd_query_bus_erros(dhdp)) { return; } -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(dhdp, CAN_SLEEP(), __builtin_return_address(0)); -#endif /* DHD_PCIE_RUNTIMEPM */ dhdp->iface_op_failed = TRUE; #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP) @@ -2979,11 +3358,14 @@ wl_cfg80211_bcn_bringup_ap( uint32 wme_apsd = 0; #endif /* SOFTAP_UAPSD_OFF */ s32 err = BCME_OK; +#ifdef BCM4343X_WAR dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - s32 is_rsdb_supported = BCME_ERROR; +#endif char sec[64]; + s32 is_rsdb_supported = BCME_ERROR; + u8 buf[WLC_IOCTL_SMLEN] = {0}; -#if defined (BCMDONGLEHOST) +#if defined(BCMDONGLEHOST) is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE); if (is_rsdb_supported < 0) return (-ENODEV); @@ -3026,6 +3408,16 @@ wl_cfg80211_bcn_bringup_ap( WL_ERR(("GO SSID setting error %d\n", err)); goto exit; } +#ifdef MFP + err = wldev_iovar_setint_bsscfg(dev, "mfp", cfg->mfp_mode, bssidx); + if (err < 0) { + WL_ERR(("MFP Setting failed. ret = %d \n", err)); + /* If fw doesn't support mfp, Ignore the error */ + if (err != BCME_UNSUPPORTED) { + goto exit; + } + } +#endif /* MFP */ if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) { WL_ERR(("GO Bring up error %d\n", err)); @@ -3072,7 +3464,7 @@ wl_cfg80211_bcn_bringup_ap( #endif /* DISABLE_11H_SOFTAP */ #ifdef WL_DISABLE_HE_SOFTAP - err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_HE_FEATURES_HE_AP, FALSE); + err = wl_cfg80211_change_he_features(dev, cfg, bssidx, WL_HE_FEATURES_HE_AP, FALSE); if (err < 0) { WL_ERR(("failed to set he features, error=%d\n", err)); } @@ -3108,19 +3500,6 @@ wl_cfg80211_bcn_bringup_ap( if (err < 0) { WL_ERR(("bip set error %d\n", err)); -#ifdef CUSTOMER_HW6 - if (wl_customer6_legacy_chip_check(cfg, - bcmcfg_to_prmry_ndev(cfg))) { - /* Ignore bip error: Some older firmwares doesn't - * support bip iovar/ return BCME_NOTUP while trying - * to set bip from AP bring up context. These firmares - * include bip in RSNIE by default. So its okay to ignore - * the error. - */ - err = BCME_OK; - } else -#endif /* CUSTOMER_HW6 */ - { goto exit; } @@ -3133,6 +3512,7 @@ wl_cfg80211_bcn_bringup_ap( WL_ERR(("Could not get wsec %d\n", err)); goto exit; } +#ifdef BCM4343X_WAR if (dhd->conf->chip == BCM43430_CHIP_ID && bssidx > 0 && (wsec & (TKIP_ENABLED|AES_ENABLED))) { struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg); @@ -3153,13 +3533,14 @@ wl_cfg80211_bcn_bringup_ap( wldev_ioctl_set(primary_ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); } } +#endif if ((wsec == WEP_ENABLED) && cfg->wep_key.len) { WL_DBG(("Applying buffered WEP KEY \n")); err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &cfg->wep_key, - sizeof(struct wl_wsec_key), cfg->ioctl_buf, - WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + sizeof(struct wl_wsec_key), buf, WLC_IOCTL_SMLEN, bssidx, NULL); /* clear the key after use */ bzero(&cfg->wep_key, sizeof(struct wl_wsec_key)); + bzero(buf, sizeof(buf)); if (unlikely(err)) { WL_ERR(("WLC_SET_KEY error (%d)\n", err)); goto exit; @@ -3167,21 +3548,28 @@ wl_cfg80211_bcn_bringup_ap( } #ifdef MFP - if (cfg->mfp_mode) { - /* This needs to go after wsec otherwise the wsec command will - * overwrite the values set by MFP - */ - err = wldev_iovar_setint_bsscfg(dev, "mfp", cfg->mfp_mode, bssidx); - if (err < 0) { - WL_ERR(("MFP Setting failed. ret = %d \n", err)); - /* If fw doesn't support mfp, Ignore the error */ - if (err != BCME_UNSUPPORTED) { - goto exit; - } + /* This needs to go after wsec otherwise the wsec command will + * overwrite the values set by MFP + */ + err = wldev_iovar_setint_bsscfg(dev, "mfp", cfg->mfp_mode, bssidx); + if (err < 0) { + WL_ERR(("MFP Setting failed. ret = %d \n", err)); + /* If fw doesn't support mfp, Ignore the error */ + if (err != BCME_UNSUPPORTED) { + goto exit; } } #endif /* MFP */ + /* sync up host macaddr */ + err = wldev_iovar_setbuf(dev, "cur_etheraddr", + dev->dev_addr, ETH_ALEN, cfg->ioctl_buf, WLC_IOCTL_SMLEN, + &cfg->ioctl_buf_sync); + if (err) { + WL_ERR(("sync macaddr for softap error\n")); + goto exit; + } + bzero(&join_params, sizeof(join_params)); /* join parameters starts with ssid */ join_params_size = sizeof(join_params.ssid); @@ -3223,9 +3611,7 @@ exit: } #ifdef MFP - if (cfg->mfp_mode) { - cfg->mfp_mode = 0; - } + cfg->mfp_mode = 0; if (cfg->bip_pos) { cfg->bip_pos = NULL; @@ -3243,8 +3629,44 @@ exit: return err; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ - defined(WL_COMPAT_WIRELESS) +static s32 +wl_cfg80211_config_bss_selector( + struct net_device *dev, + struct parsed_ies *ies, + u32 dev_role, s32 bssidx) +{ + int err = BCME_OK; + bool sae_h2e_required = FALSE; + int i, j; + const bcm_tlv_t *rates[2] = {ies->rate_ie, ies->ext_rate_ie}; + + /* check and config h2e config */ + for (i = 0; i < 2; i++) { + if (rates[i]) { + for (j = 0; j < rates[i]->len; j++) { + if (rates[i]->data[j] == DOT11_BSS_SAE_HASH_TO_ELEMENT) { + sae_h2e_required = TRUE; + } + } + } + } + + if (sae_h2e_required) { + u32 sae_pwe = SAE_PWE_H2E; + err = wl_cfg80211_set_wsec_info(dev, &sae_pwe, + sizeof(sae_pwe), WL_WSEC_INFO_BSS_SAE_PWE); + if (unlikely(err)) { + WL_ERR(("set wsec_info_sae_pwe failed \n")); + } + } + + WL_INFORM_MEM(("Config BSS Selector Done err %d, h2e_req %d\n", + err, sae_h2e_required)); + + return err; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) s32 wl_cfg80211_parse_ap_ies( struct net_device *dev, @@ -3591,8 +4013,7 @@ wl_cfg80211_set_scb_timings( return 0; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) s32 wl_cfg80211_start_ap( struct wiphy *wiphy, @@ -3604,6 +4025,7 @@ wl_cfg80211_start_ap( struct parsed_ies ies; s32 bssidx = 0; u32 dev_role = 0; + u32 hidden_ssid = 0; #ifdef BCMDONGLEHOST dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); #endif /* BCMDONGLEHOST */ @@ -3626,6 +4048,7 @@ wl_cfg80211_start_ap( WL_ERR(("set ap role failed!\n")); return BCME_ERROR; } + } dev_role = NL80211_IFTYPE_AP; #ifdef BCMDONGLEHOST @@ -3639,16 +4062,6 @@ wl_cfg80211_start_ap( #ifdef WL_EXT_IAPSTA wl_ext_iapsta_update_iftype(dev, WL_IF_TYPE_AP); #endif /* WL_EXT_IAPSTA */ -#ifdef PKT_FILTER_SUPPORT - /* Disable packet filter */ - if (dhd->early_suspended) { - WL_ERR(("Disable pkt_filter\n")); - dhd_enable_packet_filter(0, dhd); -#ifdef APF - dhd_dev_apf_disable_filter(dhd_linux_get_primary_netdev(dhd)); -#endif /* APF */ - } -#endif /* PKT_FILTER_SUPPORT */ #endif /* BCMDONGLEHOST */ } else { /* only AP or GO role need to be handled here. */ @@ -3656,6 +4069,19 @@ wl_cfg80211_start_ap( goto fail; } +#ifdef BCMDONGLEHOST + /* Disable packet filter */ + if (dhd->early_suspended) { + WL_ERR(("Disable pkt_filter\n")); +#ifdef PKT_FILTER_SUPPORT + dhd_enable_packet_filter(0, dhd); +#endif /* PKT_FILTER_SUPPORT */ +#ifdef APF + dhd_dev_apf_disable_filter(dhd_linux_get_primary_netdev(dhd)); +#endif /* APF */ + } +#endif /* BCMDONGLEHOST */ + /* disable TDLS */ #ifdef WLTDLS if (bssidx == 0) { @@ -3678,14 +4104,23 @@ wl_cfg80211_start_ap( * hardcoded values in 'wl_cfg80211_set_channel()'. */ #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS)) - if (!dev->ieee80211_ptr->preset_chandef.chan) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + if (!dev->ieee80211_ptr->u.ap.preset_chandef.chan) +#else + if (!dev->ieee80211_ptr->preset_chandef.chan) +#endif /* LINUX_VER >= 5.19.2 || CFG80211_BKPORT_MLO */ + { WL_ERR(("chan is NULL\n")); err = -EINVAL; goto fail; } if ((err = wl_cfg80211_set_channel(wiphy, dev, - dev->ieee80211_ptr->preset_chandef.chan, - NL80211_CHAN_HT20) < 0)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + dev->ieee80211_ptr->u.ap.preset_chandef.chan, +#else + dev->ieee80211_ptr->preset_chandef.chan, +#endif /* LINUX_VER >= 5.19.2 || CFG80211_BKPORT_MLO */ + info->chandef.width) < 0)) { WL_ERR(("Set channel failed \n")); goto fail; } @@ -3716,6 +4151,11 @@ wl_cfg80211_start_ap( goto fail; } + if ((err = wl_cfg80211_config_bss_selector(dev, &ies, + dev_role, bssidx)) < 0) { + WL_ERR(("Config BSS selector failed \n")); + } + /* Set GC/STA SCB expiry timings. */ if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) { WL_ERR(("scb setting failed \n")); @@ -3757,10 +4197,10 @@ wl_cfg80211_start_ap( } /* Configure hidden SSID */ - if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) { - if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0) - WL_ERR(("failed to set hidden : %d\n", err)); - WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid)); + hidden_ssid = (info->hidden_ssid == NL80211_HIDDEN_SSID_NOT_IN_USE) ? 0 : 1; + WL_DBG(("hidden_ssid: %d \n", hidden_ssid)); + if ((err = wldev_iovar_setint(dev, "closednet", hidden_ssid)) < 0) { + WL_ERR(("failed to set hidden : %d\n", err)); } #ifdef SUPPORT_AP_RADIO_PWRSAVE @@ -3779,23 +4219,20 @@ fail: if (err) { WL_ERR(("ADD/SET beacon failed\n")); wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + wl_cfg80211_stop_ap(wiphy, dev, 0); +#else wl_cfg80211_stop_ap(wiphy, dev); +#endif /* LINUX_VER >= 5.19.2 || defined(CFG80211_BKPORT_MLO) */ if (dev_role == NL80211_IFTYPE_AP) { #ifdef WL_EXT_IAPSTA if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) { #endif /* WL_EXT_IAPSTA */ #ifdef BCMDONGLEHOST - dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE; -#ifdef PKT_FILTER_SUPPORT - /* Enable packet filter */ - if (dhd->early_suspended) { - WL_ERR(("Enable pkt_filter\n")); - dhd_enable_packet_filter(1, dhd); -#ifdef APF - dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd)); -#endif /* APF */ + /* If there are no other APs active, clear the AP mode */ + if (wl_cfgvif_get_iftype_count(cfg, WL_IF_TYPE_AP) == 0) { + dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE; } -#endif /* PKT_FILTER_SUPPORT */ #ifdef DISABLE_WL_FRAMEBURST_SOFTAP wl_cfg80211_set_frameburst(cfg, TRUE); #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */ @@ -3805,6 +4242,19 @@ fail: } #endif /* WL_EXT_IAPSTA */ } +#ifdef BCMDONGLEHOST + /* Enable packet filter */ + if (dhd->early_suspended) { + WL_ERR(("Enable pkt_filter\n")); +#ifdef PKT_FILTER_SUPPORT + dhd_enable_packet_filter(1, dhd); +#endif /* PKT_FILTER_SUPPORT */ +#ifdef APF + dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd)); +#endif /* APF */ + } +#endif /* BCMDONGLEHOST */ + #ifdef WLTDLS if (bssidx == 0) { /* Since AP creation failed, re-enable TDLS */ @@ -3820,7 +4270,11 @@ fail: s32 wl_cfg80211_stop_ap( struct wiphy *wiphy, - struct net_device *dev) + struct net_device *dev +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + , unsigned int link_id +#endif /* LINUX_VER >= 5.19.2 || CFG80211_BKPORT_MLO */ +) { int err = 0; u32 dev_role = 0; @@ -3831,15 +4285,19 @@ wl_cfg80211_stop_ap( #ifdef BCMDONGLEHOST dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); #endif /* BCMDONGLEHOST */ + u8 null_mac[ETH_ALEN]; WL_DBG(("Enter \n")); - if (wl_cfg80211_get_bus_state(cfg)) { - /* since bus is down, iovar will fail. recovery path will bringup the bus. */ - WL_ERR(("bus is not ready\n")); - return BCME_OK; - } -#if defined (BCMDONGLEHOST) + /* wl_cfg80211_start_ap() schedules cfg->ap_work + * and then cancels it if a link up event is recevied. + * Somtimes an android framework calls wl_cfg80211_stop() + * immediately after wl_cfg80211_start_ap(). + * In this case we should cancel the work. + */ + cancel_delayed_work_sync(&cfg->ap_work); + +#if defined(BCMDONGLEHOST) is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE); if (is_rsdb_supported < 0) return (-ENODEV); @@ -3852,6 +4310,17 @@ wl_cfg80211_stop_ap( if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) { dev_role = NL80211_IFTYPE_AP; WL_MSG(dev->name, "stopping AP operation\n"); + + /* Clear macaddress to prevent any macaddress conflict with interface + * like p2p discovery which can run as soon as softap is brought down + */ + (void)memset_s(null_mac, sizeof(null_mac), 0, sizeof(null_mac)); + err = wldev_iovar_setbuf(dev, "cur_etheraddr", + null_mac, ETH_ALEN, cfg->ioctl_buf, WLC_IOCTL_SMLEN, + &cfg->ioctl_buf_sync); + if (err) { + WL_ERR(("softap mac_addr set failed\n")); + } } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) { dev_role = NL80211_IFTYPE_P2P_GO; WL_MSG(dev->name, "stopping P2P GO operation\n"); @@ -3879,26 +4348,50 @@ wl_cfg80211_stop_ap( /* Clear AP/GO connected status */ wl_clr_drv_status(cfg, CONNECTED, dev); + + if (wl_cfg80211_get_bus_state(cfg)) { + /* since bus is down, iovar will fail. recovery path will bringup the bus. */ + WL_ERR(("bus is not ready\n")); + return BCME_OK; + } + if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) { WL_ERR(("bss down error %d\n", err)); } +#ifdef BCMDONGLEHOST + /* Enable packet filter */ + if (dhd->early_suspended) { + WL_ERR(("Enable pkt_filter\n")); +#ifdef PKT_FILTER_SUPPORT + dhd_enable_packet_filter(1, dhd); +#endif /* PKT_FILTER_SUPPORT */ +#ifdef APF + dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd)); +#endif /* APF */ + } +#endif /* BCMDONGLEHOST */ + if (dev_role == NL80211_IFTYPE_AP) { + /* Clear the security settings on the Interface */ + err = wldev_iovar_setint(dev, "wsec", 0); + if (unlikely(err)) { + WL_ERR(("wsec clear failed (%d)\n", err)); + } + err = wldev_iovar_setint(dev, "auth", 0); + if (unlikely(err)) { + WL_ERR(("auth clear failed (%d)\n", err)); + } + err = wldev_iovar_setint(dev, "wpa_auth", 0); + if (unlikely(err)) { + WL_ERR(("set wpa_auth failed (%d)\n", err)); + } + #ifdef BCMDONGLEHOST #ifdef DISABLE_WL_FRAMEBURST_SOFTAP wl_cfg80211_set_frameburst(cfg, TRUE); #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */ #endif /* BCMDONGLEHOST */ -#ifdef PKT_FILTER_SUPPORT - /* Enable packet filter */ - if (dhd->early_suspended) { - WL_ERR(("Enable pkt_filter\n")); - dhd_enable_packet_filter(1, dhd); -#ifdef APF - dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd)); -#endif /* APF */ - } -#endif /* PKT_FILTER_SUPPORT */ if (is_rsdb_supported == 0) { /* For non-rsdb chips, we use stand alone AP. Do wl down on stop AP */ @@ -3911,7 +4404,7 @@ wl_cfg80211_stop_ap( } #ifdef WL_DISABLE_HE_SOFTAP - if (wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_HE_FEATURES_HE_AP, + if (wl_cfg80211_change_he_features(dev, cfg, bssidx, WL_HE_FEATURES_HE_AP, TRUE) != BCME_OK) { WL_ERR(("failed to set he features\n")); } @@ -3925,6 +4418,11 @@ wl_cfg80211_stop_ap( WL_ERR(("Set rpsnoa failed \n")); } #endif /* SUPPORT_AP_RADIO_PWRSAVE */ +#ifdef WL_CELLULAR_CHAN_AVOID + wl_cellavoid_sync_lock(cfg); + wl_cellavoid_free_csa_info(cfg->cellavoid_info, dev); + wl_cellavoid_sync_unlock(cfg); +#endif /* WL_CELLULAR_CHAN_AVOID */ } else { /* Do we need to do something here */ WL_DBG(("Stopping P2P GO \n")); @@ -3956,8 +4454,10 @@ exit: #ifdef WL_EXT_IAPSTA if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) { #endif /* WL_EXT_IAPSTA */ - /* clear the AP mode */ - dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE; + /* If there are no other APs active, clear the AP mode */ + if (wl_cfgvif_get_iftype_count(cfg, WL_IF_TYPE_AP) == 0) { + dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE; + } wl_wlfc_enable(cfg, FALSE); #ifdef WL_EXT_IAPSTA } @@ -4306,14 +4806,6 @@ wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event = ntoh32(e->event_type); struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); -#if defined(DHD_ENABLE_BIGDATA_LOGGING) - (void)memcpy_s(&cfg->event_auth_assoc, sizeof(wl_event_msg_t), - e, sizeof(wl_event_msg_t)); - WL_DBG(("event=%d status %d reason %d \n", - ntoh32(cfg->event_auth_assoc.event_type), - ntoh32(cfg->event_auth_assoc.status), - ntoh32(cfg->event_auth_assoc.reason))); -#endif /* DHD_ENABLE_BIGDATA_LOGGING */ if (sec) { switch (event) { case WLC_E_ASSOC: @@ -4449,6 +4941,54 @@ exit: } #endif /* WL_CFG80211_STA_EVENT || KERNEL_VER < 3.2 */ +static void +wl_update_sta_chanspec_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, const u8 *addr) +{ + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + u8 *iovar_buf = NULL; + u16 iovar_buf_len = WLC_IOCTL_MEDLEN; + wlcfg_sta_info_t *sta; + chanspec_t chanspec = 0; + s32 ifidx; + s32 ret; + + ifidx = dhd_net2idx(dhdp->info, ndev); + if (ifidx < 0) { + WL_ERR(("invalid ifidx\n")); + return; + } + + iovar_buf = MALLOCZ(cfg->osh, iovar_buf_len); + if (!iovar_buf) { + WL_ERR(("no memory\n")); + return; + } + + /* get the sta info */ + ret = wldev_iovar_getbuf(ndev, "sta_info", + addr, ETHER_ADDR_LEN, iovar_buf, iovar_buf_len, NULL); + if (ret < 0) { + WL_ERR(("get sta_info error %d\n", ret)); + goto exit; + } + + sta = (wlcfg_sta_info_t *)iovar_buf; + if (!IS_STA_INFO_VER(sta)) { + WL_ERR(("Unsupported sta info ver:%d\n", dtoh16(sta->ver))); + goto exit; + } + + chanspec = dtoh16(sta->chanspec); + dhd_update_sta_chanspec_info(dhdp, ifidx, addr, chanspec); + + WL_INFORM_MEM(("[%s] updated client sta info. chanspec:0x%x\n", + ndev->name, chanspec)); +exit: + if (iovar_buf) { + MFREE(cfg->osh, iovar_buf, iovar_buf_len); + } +} + s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, const wl_event_msg_t *e, void *data) @@ -4461,9 +5001,9 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, #if defined(WL_CFG80211_STA_EVENT) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) struct station_info sinfo; #endif /* (LINUX_VERSION >= VERSION(3,2,0)) || !WL_CFG80211_STA_EVENT */ -#ifdef BIGDATA_SOFTAP - dhd_pub_t *dhdp; -#endif /* BIGDATA_SOFTAP */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) + struct cfg80211_update_owe_info owe_info; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) */ WL_INFORM_MEM(("[%s] Mode AP/GO. Event:%d status:%d reason:%d\n", ndev->name, event, ntoh32(e->status), reason)); @@ -4504,16 +5044,15 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, (reason == WLC_E_REASON_INITIAL_ASSOC) && (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP)) { if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) { + char chan_str[64]; /* AP/GO brought up successfull in firmware */ - WL_MSG(ndev->name, "AP/GO Link up\n"); + wl_ext_get_chan_str(ndev, chan_str, sizeof(chan_str)); + WL_MSG(ndev->name, "AP/GO Link up (%s)\n", chan_str); wl_set_drv_status(cfg, AP_CREATED, ndev); if (delayed_work_pending(&cfg->ap_work)) { cancel_delayed_work_sync(&cfg->ap_work); WL_DBG(("cancelled ap_work\n")); } -#ifdef BIGDATA_SOFTAP - wl_ap_stainfo_init(cfg); -#endif /* BIGDATA_SOFTAP */ #ifdef WL_EXT_IAPSTA wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_AP_ENABLED, NULL); #endif @@ -4527,17 +5066,6 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, bcmevent_get_name(event), event, ntoh32(e->status), reason); } -#ifdef BIGDATA_SOFTAP - if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) { - WL_ERR(("AP link down - skip get sta data\n")); - } else { - dhdp = (dhd_pub_t *)(cfg->pub); - if (dhdp && dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) { - dhd_schedule_gather_ap_stadata(cfg, ndev, e); - } - } -#endif /* BIGDATA_SOFTAP */ - #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \ (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) err = wl_notify_connect_status_ap_legacy(cfg, ndev, e, data); @@ -4555,6 +5083,9 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, WL_ERR(("No IEs present in ASSOC/REASSOC_IND")); return -EINVAL; } + + wl_update_sta_chanspec_info(cfg, ndev, e->addr.octet); + sinfo.assoc_req_ies = data; sinfo.assoc_req_ies_len = len; WL_MSG(ndev->name, "new sta event for "MACDBG "\n", @@ -4600,8 +5131,24 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, wl_wps_session_update(ndev, WPS_STATE_LINKDOWN, e->addr.octet); #endif /* WL_WPS_SYNC */ } - #endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) + else if (event == WLC_E_OWE_INFO) { + if (!data) { + WL_ERR(("No DH-IEs present in ASSOC/REASSOC_IND")); + return -EINVAL; + } + if (wl_dbg_level & WL_DBG_DBG) { + prhex("FW-OWEIE ", (uint8 *)data, len); + } + eacopy(e->addr.octet, owe_info.peer); + owe_info.ie = data; + owe_info.ie_len = len; + WL_INFORM_MEM(("Recieved owe_info. Mac addr" MACDBG "\n", + MAC2STRDBG((const u8*)(&e->addr)))); + cfg80211_update_owe_info_event(ndev, &owe_info, GFP_ATOMIC); + } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) */ return err; } @@ -4737,40 +5284,12 @@ wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } -#if defined(CUSTOMER_HW10) -static void wl_tdls_enable(struct bcm_cfg80211 *cfg) -{ - int enable = true; - int err = 0; - struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg); - dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); - -/* #define IS_P2P_OPERATING (p2p_is_on(cfg) && cfg->p2p->vif_created ) */ -#define IS_P2P_OPERATING (dhd->op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE)) -#if !defined(DISABLE_TDLS_IN_P2P) - if (cfg->vsdb_mode) -#else - if (cfg->vsdb_mode || IS_P2P_OPERATING) -#endif - { - enable = false; - } - - err = wldev_iovar_setint(primary_dev, "tdls_enable", enable); - if (err) { - WL_ERR(("tdls_enable failed!!: %d\n", enable)); - } -#undef IS_P2P_OPERATING -} -#endif /* defined(CUSTOMER_HW10) */ - #endif /* WLTDLS */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) s32 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || \ - ((LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))) + (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capability, const u8 *buf, size_t len) @@ -5026,7 +5545,7 @@ wl_cfg80211_dfs_ap_move(struct net_device *ndev, char *data, char *command, int } #ifdef WL_CFG80211_ACL -static int +int wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev, const struct cfg80211_acl_data *acl) { @@ -5085,44 +5604,145 @@ wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev, } #endif /* WL_CFG80211_ACL */ +#ifdef WL_CFG80211_MONITOR +int +wl_cfg80211_set_monitor_channel(struct wiphy *wiphy, struct cfg80211_chan_def *chandef) +{ + int err = BCME_OK; + struct bcm_cfg80211 *cfg; + struct net_device *ndev; + dhd_pub_t *dhdp; + u32 bw = WL_CHANSPEC_BW_20; + chanspec_t chspec = 0; + + WL_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (!wiphy) { + WL_ERR(("%s: wiphy is null\n", __FUNCTION__)); + return BCME_ERROR; + } + + cfg = wiphy_priv(wiphy); + if (!cfg) { + WL_ERR(("%s: cfg is null\n", __FUNCTION__)); + return BCME_ERROR; + } + + dhdp = (dhd_pub_t *)(cfg->pub); + if (!dhdp->monitor_enable) { + WL_ERR(("%s: Monitor mode is not enabled\n", __FUNCTION__)); + return BCME_UNSUPPORTED; + } + + ndev = bcmcfg_to_prmry_ndev(cfg); + /* Convert from struct cfg80211_chan_def to chanspec_t */ + chspec = wl_freq_to_chanspec(chandef->chan->center_freq); + WL_ERR(("%s: target_channel(%d), target bandwidth(%d)\n", + __FUNCTION__, CHSPEC_CHANNEL(chspec), chandef->width)); + + if ( +#ifdef WL_6G_BAND + CHSPEC_IS6G(chspec) || +#endif /* WL_6G_BAND */ + CHSPEC_IS5G(chspec)) { + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20: + bw = WL_CHANSPEC_BW_20; + break; + case NL80211_CHAN_WIDTH_40: + bw = WL_CHANSPEC_BW_40; + break; + case NL80211_CHAN_WIDTH_80: + bw = WL_CHANSPEC_BW_80; + break; + case NL80211_CHAN_WIDTH_160: + bw = WL_CHANSPEC_BW_160; + break; + default: + err = wl_get_bandwidth_cap(ndev, CHSPEC_BAND(chspec), &bw); + if (err < 0) { + WL_ERR(("Failed to get bandwidth information, err=%d\n", + err)); + return err; + } + + /* In case of 5G downgrade BW to 80MHz + * as 160MHz channels falls in DFS + */ + if (CHSPEC_IS5G(chspec) && (bw == WL_CHANSPEC_BW_160)) { + bw = WL_CHANSPEC_BW_80; + } + break; + } + } else if (CHSPEC_IS2G(chspec)) { + bw = WL_CHANSPEC_BW_20; + } else { + WL_ERR(("invalid band (%d)\n", CHSPEC_BAND(chspec))); + return -EINVAL; + } + + WL_DBG(("%s: chandef->width(%u), bw(%u)\n", + __FUNCTION__, chandef->width, bw)); +#ifdef WL_6G_320_SUPPORT + chspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(chspec), + bw, CHSPEC_BAND(chspec), 0); +#else + chspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(chspec), + bw, CHSPEC_BAND(chspec)); +#endif /* WL_6G_320_SUPPORT */ + + if (!wf_chspec_valid(chspec)) { + WL_ERR(("Invalid chanspec 0x%x\n", chspec)); + return -EINVAL; + } + + /* Set chanspec for monitor channel */ + err = wldev_iovar_setint(ndev, "chanspec", chspec); + if (unlikely(err)) { + WL_ERR(("%s: Could not set chanspec %d\n", __FUNCTION__, err)); + } + + return err; +} +#endif /* WL_CFG80211_MONITOR */ + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) int wl_chspec_chandef(chanspec_t chanspec, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) - struct cfg80211_chan_def *chandef, -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0))) - struct chan_info *chaninfo, -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */ - struct wiphy *wiphy) + struct cfg80211_chan_def *chandef, struct wiphy *wiphy) { uint16 freq = 0; - int chan_type = 0; - int channel = 0; struct ieee80211_channel *chan; if (!chandef) { return -1; + } else { + memset(chandef, 0, sizeof(*chandef)); } - channel = CHSPEC_CHANNEL(chanspec); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) + chandef->center_freq1 = wl_channel_to_frequency(CHSPEC_CHANNEL(chanspec), CHSPEC_BAND(chanspec)); + freq = wl_channel_to_frequency(wf_chspec_primary20_chan(chanspec), CHSPEC_BAND(chanspec)); + chandef->chan = ieee80211_get_channel(wiphy, freq); + chandef->center_freq2 = 0; switch (CHSPEC_BW(chanspec)) { case WL_CHANSPEC_BW_20: - chan_type = NL80211_CHAN_HT20; - break; - case WL_CHANSPEC_BW_40: - { - if (CHSPEC_SB_UPPER(chanspec)) { - channel += CH_10MHZ_APART; - } else { - channel -= CH_10MHZ_APART; - } - } - chan_type = NL80211_CHAN_HT40PLUS; + chandef->width = NL80211_CHAN_WIDTH_20; + break; + + case WL_CHANSPEC_BW_40: + chandef->width = NL80211_CHAN_WIDTH_40; break; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) case WL_CHANSPEC_BW_80: + chandef->width = NL80211_CHAN_WIDTH_80; + break; + case WL_CHANSPEC_BW_8080: { + /* XXX Left as is but need proper calculation for center_freq2 is used */ + int chan_type = 0; + int channel = 0; uint16 sb = CHSPEC_CTL_SB(chanspec); if (sb == WL_CHANSPEC_CTL_SB_LL) { @@ -5140,19 +5760,45 @@ int wl_chspec_chandef(chanspec_t chanspec, chan_type = NL80211_CHAN_HT40MINUS; else if (sb == WL_CHANSPEC_CTL_SB_UL || sb == WL_CHANSPEC_CTL_SB_UU) chan_type = NL80211_CHAN_HT40PLUS; - } + freq = wl_channel_to_frequency(channel, CHSPEC_BAND(chanspec)); + chan = ieee80211_get_channel(wiphy, freq); + cfg80211_chandef_create(chandef, chan, chan_type); + return 0; break; + } + case WL_CHANSPEC_BW_160: - channel = wf_chspec_primary20_chan(chanspec); - /* Using base chan_type as kernel does not define chan_type for 160 MHz */ + chandef->width = NL80211_CHAN_WIDTH_160; + break; + default: + chandef->width = NL80211_CHAN_WIDTH_20; + break; + } + +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && \ + (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 7, 0))) + + int chan_type = 0; + int channel = 0; + channel = CHSPEC_CHANNEL(chanspec); + switch (CHSPEC_BW(chanspec)) { + case WL_CHANSPEC_BW_20: chan_type = NL80211_CHAN_HT20; break; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ + case WL_CHANSPEC_BW_40: + if (CHSPEC_SB_UPPER(chanspec)) { + channel += CH_10MHZ_APART; + } else { + channel -= CH_10MHZ_APART; + } + chan_type = NL80211_CHAN_HT40PLUS; + break; + default: chan_type = NL80211_CHAN_HT20; break; - } + freq = wl_channel_to_frequency(channel, CHSPEC_BAND(chanspec)); chan = ieee80211_get_channel(wiphy, freq); WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n", @@ -5164,12 +5810,10 @@ int wl_chspec_chandef(chanspec_t chanspec, return -EINVAL; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) - cfg80211_chandef_create(chandef, chan, chan_type); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0))) - chaninfo->freq = freq; - chaninfo->chan_type = chan_type; + chandef->freq = freq; + chandef->chan_type = chan_type; #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ + return 0; } @@ -5177,11 +5821,7 @@ void wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wiphy *wiphy) { u32 freq; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) struct cfg80211_chan_def chandef; -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0))) - struct chan_info chaninfo; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ if (!wiphy) { WL_ERR(("wiphy is null\n")); @@ -5196,21 +5836,24 @@ wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wip } #endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0)) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) - if (wl_chspec_chandef(chanspec, &chandef, wiphy)) -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0))) - if (wl_chspec_chandef(chanspec, &chaninfo, wiphy)) -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ - { + if (wl_chspec_chandef(chanspec, &chandef, wiphy)) { WL_ERR(("chspec_chandef failed\n")); return; } + #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) freq = chandef.chan ? chandef.chan->center_freq : chandef.center_freq1; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) || \ + ((ANDROID_VERSION >= 13) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 94))) + cfg80211_ch_switch_notify(dev, &chandef, 0, 0); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + cfg80211_ch_switch_notify(dev, &chandef, 0); +#else cfg80211_ch_switch_notify(dev, &chandef); +#endif /* LINUX_VER >= 5.19.2 || defined(CFG80211_BKPORT_MLO) */ #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0))) - freq = chan_info.freq; - cfg80211_ch_switch_notify(dev, freq, chan_info.chan_type); + freq = chandef.freq; + cfg80211_ch_switch_notify(dev, freq, chandef.chan_type); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ WL_MSG(dev->name, "Channel switch notification for freq: %d chanspec: 0x%x\n", @@ -5245,6 +5888,11 @@ wl_ap_channel_ind(struct bcm_cfg80211 *cfg, wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg)); #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */ cfg->ap_oper_channel = chanspec; + +#ifdef WL_CELLULAR_CHAN_AVOID + wl_cellavoid_set_csa_done(cfg->cellavoid_info); +#endif /* WL_CELLULAR_CHAN_AVOID */ + } } @@ -5488,7 +6136,7 @@ int wl_set_ap_beacon_rate(struct net_device *dev, int val, char *ifname) { struct bcm_cfg80211 *cfg = wl_get_cfg(dev); dhd_pub_t *dhdp; - wl_rateset_args_t rs; + wl_rateset_args_v1_t rs; int error = BCME_ERROR, i; struct net_device *ndev = NULL; @@ -5506,9 +6154,9 @@ int wl_set_ap_beacon_rate(struct net_device *dev, int val, char *ifname) return BCME_NOTAP; } - bzero(&rs, sizeof(wl_rateset_args_t)); + bzero(&rs, sizeof(wl_rateset_args_v1_t)); error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0, - &rs, sizeof(wl_rateset_args_t), NULL); + &rs, sizeof(wl_rateset_args_v1_t), NULL); if (error < 0) { WL_ERR(("get rateset failed = %d\n", error)); return error; @@ -5546,7 +6194,7 @@ wl_get_ap_basic_rate(struct net_device *dev, char* command, char *ifname, int to { struct bcm_cfg80211 *cfg = wl_get_cfg(dev); dhd_pub_t *dhdp; - wl_rateset_args_t rs; + wl_rateset_args_v1_t rs; int error = BCME_ERROR; int i, bytes_written = 0; struct net_device *ndev = NULL; @@ -5565,9 +6213,9 @@ wl_get_ap_basic_rate(struct net_device *dev, char* command, char *ifname, int to return BCME_NOTAP; } - bzero(&rs, sizeof(wl_rateset_args_t)); + bzero(&rs, sizeof(wl_rateset_args_v1_t)); error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0, - &rs, sizeof(wl_rateset_args_t), NULL); + &rs, sizeof(wl_rateset_args_v1_t), NULL); if (error < 0) { WL_ERR(("get rateset failed = %d\n", error)); return error; @@ -5913,7 +6561,7 @@ wl_he_pack_uint_cb(void *ctx, uint16 id, uint16 len, uint8 *buf) } } -int wl_cfg80211_set_he_mode(struct net_device *dev, struct bcm_cfg80211 *cfg, +int wl_cfg80211_change_he_features(struct net_device *dev, struct bcm_cfg80211 *cfg, s32 bssidx, u32 he_flag, bool set) { bcm_xtlv_t read_he_xtlv; @@ -5922,16 +6570,17 @@ int wl_cfg80211_set_he_mode(struct net_device *dev, struct bcm_cfg80211 *cfg, he_xtlv_v32 v32; u32 he_feature = 0; s32 err = 0; + uint8 iovar_buf[WLC_IOCTL_SMLEN]; read_he_xtlv.id = WL_HE_CMD_FEATURES; read_he_xtlv.len = 0; err = wldev_iovar_getbuf_bsscfg(dev, "he", &read_he_xtlv, sizeof(read_he_xtlv), - cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, NULL); + iovar_buf, WLC_IOCTL_SMLEN, bssidx, NULL); if (err < 0) { WL_ERR(("HE get failed. error=%d\n", err)); return err; } else { - he_feature = *(int*)cfg->ioctl_buf; + he_feature = *(int*)iovar_buf; he_feature = dtoh32(he_feature); } @@ -5961,6 +6610,35 @@ int wl_cfg80211_set_he_mode(struct net_device *dev, struct bcm_cfg80211 *cfg, return err; } +int wl_cfg80211_set_he_features(struct net_device *dev, struct bcm_cfg80211 *cfg, + s32 bssidx, u32 interface_type, uint features) +{ + uint8 se_he_xtlv[32]; + int se_he_xtlv_len = sizeof(se_he_xtlv); + he_xtlv_v32 v32; + s32 err = 0; + + v32.id = WL_HE_CMD_FEATURES; + v32.len = sizeof(s32); + v32.val = features; + + err = bcm_pack_xtlv_buf((void *)&v32, se_he_xtlv, sizeof(se_he_xtlv), + BCM_XTLV_OPTION_ALIGN32, wl_he_get_uint_cb, wl_he_pack_uint_cb, + &se_he_xtlv_len); + if (err != BCME_OK) { + WL_ERR(("failed to pack he settvl=%d\n", err)); + } + + err = wldev_iovar_setbuf_bsscfg(dev, "he", &se_he_xtlv, sizeof(se_he_xtlv), + cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync); + if (err < 0) { + WL_ERR(("failed to set he features, error=%d\n", err)); + } + WL_INFORM(("Set he features[%d] done\n", features)); + + return err; +} + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) int wl_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, @@ -5996,7 +6674,7 @@ wl_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, if (chspec == cfg->ap_oper_channel) { WL_ERR(("Channel %d is same as current operating channel," " so skip\n", CHSPEC_CHANNEL(chspec))); - return BCME_OK; + return -EINVAL; } if ( @@ -6238,6 +6916,7 @@ int wl_set_softap_elna_bypass(struct net_device *dev, char *ifname, int enable) fail: return err; } + int wl_get_softap_elna_bypass(struct net_device *dev, char *ifname, void *param) { struct bcm_cfg80211 *cfg = wl_get_cfg(dev); @@ -6452,8 +7131,7 @@ wl_set_ap_bw(struct net_device *dev, u32 bw, char *ifname) } if ((DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp) && - wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) || - wl_cfgnan_is_enabled(cfg)) { + wl_is_sta_connected(cfg)) || wl_cfgnan_is_enabled(cfg)) { WL_ERR(("BW control in concurrent mode is not supported\n")); return BCME_BUSY; } @@ -6628,3 +7306,658 @@ wl_restore_ap_bw(struct bcm_cfg80211 *cfg) } } #endif /* SUPPORT_AP_BWCTRL */ + +static s32 +wl_roam_off_config(struct net_device *dev, bool val) +{ + s32 err; + + err = wldev_iovar_setint(dev, "roam_off", val); + if (err) { + WL_ERR(("roam config (%d) failed for (%s) err=%d\n", + val, dev->name, err)); + } else { + WL_INFORM_MEM(("roam %s for %s\n", + (val ? "disabled" : "enabled"), dev->name)); + } + + return err; +} + +#ifdef WL_DUAL_APSTA +static void +wl_roam_enable_on_connected(struct bcm_cfg80211 *cfg, + bool enable) +{ + struct net_info *iter, *next; + bool roam_val = false; + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + for_each_ndev(cfg, iter, next) { + GCC_DIAGNOSTIC_POP(); + if ((iter->ndev) && + (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION)) { + + if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) { + roam_val = enable ? FALSE : TRUE; + wl_roam_off_config(iter->ndev, roam_val); + } + } + } +} + +/* + * Roam config API for dual STA + * Disable: Disable for all interfaces + * Enable: Enable roam only for primary STA + */ +static void +wl_dualsta_enable_roam(struct bcm_cfg80211 *cfg, + struct net_device *dev, bool enable) +{ + struct net_info *iter, *next; + bool roam_val = false; + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + for_each_ndev(cfg, iter, next) { + GCC_DIAGNOSTIC_POP(); + if ((iter->ndev) && + (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION)) { + + roam_val = enable ? FALSE : TRUE; + if (enable && iter->ndev != cfg->inet_ndev) { + /* For enable case, the roam is supposed to enabled only + * on primary. For other interfaces, disable it + */ + wl_roam_off_config(iter->ndev, TRUE); + WL_DBG_MEM(("non-primary ndev. skip roam enable\n")); + continue; + } + wl_roam_off_config(iter->ndev, roam_val); + } + } +} +#endif /* WL_DUAL_APSTA */ + +void +wl_cfgvif_roam_config(struct bcm_cfg80211 *cfg, struct net_device *dev, + wl_roam_conf_t state) +{ + if (!cfg || !dev) { + WL_ERR(("invalid args\n")); + return; + } + + WL_DBG_MEM(("Enter. state:%d stas:%d\n", state, cfg->stas_associated)); + + if (!IS_STA_IFACE(dev->ieee80211_ptr)) { + WL_ERR(("non-sta iface. ignore.\n")); + return; + } + + /* + * We support roam only on one STA interface at a time (meant for internet + * traffic. For ROAM enable cases, if more than one STA interface is in + * connected state, the primary interface is expected to be set (inet_ndev) + */ + + if (state == ROAM_CONF_ROAM_DISAB_REQ) { + cfg->disable_fw_roam = TRUE; +#ifdef WL_DUAL_APSTA + wl_android_rcroam_turn_on(dev, FALSE); +#endif /* WL_DUAL_APSTA */ + /* roam off for incoming ndev interface */ + wl_roam_off_config(dev, TRUE); + return; + } else if (state == ROAM_CONF_ROAM_ENAB_REQ) { + cfg->disable_fw_roam = FALSE; +#ifdef WL_DUAL_APSTA + if ((cfg->stas_associated >= 1)) { + WL_DBG_MEM(("Roam enable with more than one interface connected.\n")); + /* If roam enable comes with > 1 iface connected, enable it on primary */ + if (!cfg->inet_ndev) { + WL_ERR(("primary_sta (inet_ndev) not set! skip roam enable\n")); + return; + } + /* Enable roam on primary, disable on others */ + wl_dualsta_enable_roam(cfg, cfg->inet_ndev, TRUE); + wl_android_rcroam_turn_on(cfg->inet_ndev, TRUE); + return; + } +#endif /* WL_DUAL_APSTA */ + + /* ROAM enable */ + wl_roam_off_config(dev, FALSE); + /* Single Interface. Enable back rcroam */ +#ifdef WL_DUAL_APSTA + wl_android_rcroam_turn_on(dev, TRUE); +#endif /* WL_DUAL_APSTA */ + return; + } + + if (cfg->disable_fw_roam) { + /* Framework has disabled roam, don't change roam states within the DHD */ + WL_INFORM_MEM(("fwk roam disable active. don't handle state:%d\n", state)); + return; + } + +#ifdef WL_DUAL_APSTA + if (state == ROAM_CONF_LINKUP) { + if (cfg->stas_associated == 2) { + /* Apply ROAM_CONF_PRIMARY_STA configuration */ + state = ROAM_CONF_PRIMARY_STA; + } else if (cfg->stas_associated == 1) { + /* Single sta case. Enable ROAM */ + wl_roam_off_config(dev, FALSE); + wl_android_rcroam_turn_on(dev, TRUE); + } else { + WL_ERR(("roam_config unexpected state. stas:%d\n", + cfg->stas_associated)); + return; + } + + } + + if (state == ROAM_CONF_PRIMARY_STA) { + /* Enable roam on primary STA */ + if (!cfg->inet_ndev) { + WL_ERR(("primary_sta (inet_ndev) not configured! skip roam enable\n")); + return; + } + + /* Enable roam on primary, disable on others */ + wl_dualsta_enable_roam(cfg, cfg->inet_ndev, TRUE); + wl_android_rcroam_turn_on(dev, TRUE); + return; + } + + if ((state == ROAM_CONF_ASSOC_REQ) && + (cfg->stas_associated >= 1)) { + /* If we already have another STA connected, disable ROAM + * on both STA interfaces. Enable it back from linkdown or + * setPrimarySta context. + */ + wl_android_rcroam_turn_on(dev, FALSE); + wl_dualsta_enable_roam(cfg, dev, FALSE); + + } else if (state == ROAM_CONF_LINKDOWN) { + /* If link down came for STA interface and there are no two active STA + * connections, enable back the roam + */ + if (cfg->stas_associated == 1) { + wl_roam_enable_on_connected(cfg, TRUE); + wl_android_rcroam_turn_on(dev, TRUE); + } + } +#endif /* WL_DUAL_APSTA */ +} + +#ifdef SUPPORT_AP_INIT_BWCONF +uint32 +wl_get_configured_ap_bw(dhd_pub_t *dhdp) +{ + WL_DBG(("%s: Confitured SoftAP BW is %d\n", __FUNCTION__, dhdp->wl_softap_bw)); + + return dhdp->wl_softap_bw; +} + +uint32 +wl_update_configured_bw(uint32 bw) +{ + uint32 configured_bw = INVCHANSPEC; + + switch (bw) + { + case 20: + configured_bw = WL_CHANSPEC_BW_20; + break; + case 40: + configured_bw = WL_CHANSPEC_BW_40; + break; + case 80: + configured_bw = WL_CHANSPEC_BW_80; + break; + case 160: + configured_bw = WL_CHANSPEC_BW_160; + break; + default: + /* wl_softap_bw have invalid BW, use default BW for each band */ + WL_ERR(("BW %d is not allowed, Use default BW \n", bw)); + } + + return configured_bw; +} +#endif /* SUPPORT_AP_INIT_BWCONF */ + +uint32 +wl_cfgvif_get_iftype_count(struct bcm_cfg80211 *cfg, wl_iftype_t iftype) +{ + struct net_info *iter, *next; + u32 count = 0; + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + for_each_ndev(cfg, iter, next) { + GCC_DIAGNOSTIC_POP(); + /* Check against wl_iftype_t type */ + if ((iter->wdev) && (iter->iftype == iftype)) { + struct net_device *ndev = iter->wdev->netdev; + + switch (iftype) { + case WL_IF_TYPE_STA: + case WL_IF_TYPE_AP: + if (ndev && wl_get_drv_status(cfg, CONNECTED, ndev)) { + /* If interface is in connected state, mark it */ + count++; + } + break; + /* P2P, NAN interfaces are dynamically created when required + * and removed after use. so presence of interface indicates + * that role is active. + */ + case WL_IF_TYPE_P2P_GO: + case WL_IF_TYPE_P2P_GC: + case WL_IF_TYPE_P2P_DISC: + case WL_IF_TYPE_NAN: + case WL_IF_TYPE_NAN_NMI: + case WL_IF_TYPE_MONITOR: + case WL_IF_TYPE_IBSS: + count++; + break; + default: + WL_DBG(("Ignore iftype:%d\n", iftype)); + } + } + } + return count; +} + +#ifdef CUSTOM_SOFTAP_SET_ANT +int +wl_set_softap_antenna(struct net_device *dev, char *ifname, int set_chain) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + struct net_device *ifdev = NULL; + char iobuf[WLC_IOCTL_SMLEN]; + int err = BCME_OK; + int iftype = 0; + s32 val = 1; + + memset(iobuf, 0, WLC_IOCTL_SMLEN); + + /* Check the interface type */ + ifdev = wl_get_netdev_by_name(cfg, ifname); + if (ifdev == NULL) { + WL_ERR(("%s: Could not find net_device for ifname:%s\n", + __FUNCTION__, ifname)); + err = BCME_BADARG; + goto fail; + } + + iftype = ifdev->ieee80211_ptr->iftype; + if (iftype == NL80211_IFTYPE_AP) { + err = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32)); + if (err) { + WL_ERR(("WLC_DOWN error %d\n", err)); + goto fail; + } else { + err = wldev_iovar_setint(ifdev, "txchain", set_chain); + if (unlikely(err)) { + WL_ERR(("%s: Failed to set txchain[%d], err=%d\n", + __FUNCTION__, set_chain, err)); + } + err = wldev_iovar_setint(ifdev, "rxchain", set_chain); + if (unlikely(err)) { + WL_ERR(("%s: Failed to set rxchain[%d], err=%d\n", + __FUNCTION__, set_chain, err)); + } + err = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32)); + if (err < 0) { + WL_ERR(("WLC_UP error %d\n", err)); + } + } + } else { + WL_ERR(("%s: Chain set should control in SoftAP mode only\n", + __FUNCTION__)); + err = BCME_BADARG; + } +fail: + return err; +} + +int +wl_get_softap_antenna(struct net_device *dev, char *ifname, void *param) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + uint32 *cur_rxchain = (uint32*)param; + struct net_device *ifdev = NULL; + char iobuf[WLC_IOCTL_SMLEN]; + int err = BCME_OK; + int iftype = 0; + + memset(iobuf, 0, WLC_IOCTL_SMLEN); + + /* Check the interface type */ + ifdev = wl_get_netdev_by_name(cfg, ifname); + if (ifdev == NULL) { + WL_ERR(("%s: Could not find net_device for ifname:%s\n", __FUNCTION__, ifname)); + err = BCME_BADARG; + goto fail; + } + + iftype = ifdev->ieee80211_ptr->iftype; + if (iftype == NL80211_IFTYPE_AP) { + err = wldev_iovar_getint(ifdev, "rxchain", cur_rxchain); + if (unlikely(err)) { + WL_ERR(("%s: Failed to get rxchain, err=%d\n", + __FUNCTION__, err)); + } + } else { + WL_ERR(("%s: rxchain should control in SoftAP mode only\n", + __FUNCTION__)); + err = BCME_BADARG; + } +fail: + return err; +} +#endif /* CUSTOM_SOFTAP_SET_ANT */ + +#if defined(LIMIT_AP_BW) +uint32 +wl_cfg80211_get_ap_bw_limit_bit(struct bcm_cfg80211 *cfg, uint32 band) +{ + + if (band != WL_CHANSPEC_BAND_6G) { + WL_ERR(("AP BW LIMIT supportted for 6G band only requested = %d\n", band)); + return 0; + } + + return cfg->ap_bw_limit; +} + +#ifdef WL_6G_320_SUPPORT +#define BAND_PARAM(a) a, 0 +#else +#define BAND_PARAM(a) a +#endif /* WL_6G_320_SUPPORT */ + +chanspec_t +wl_cfg80211_get_ap_bw_limited_chspec(struct bcm_cfg80211 *cfg, uint32 band, chanspec_t candidate) +{ + + chanspec_t updated_chspec; + if (band != WL_CHANSPEC_BAND_6G) { + WL_ERR(("AP BW LIMIT supported for 6G band only requested = %d\n", band)); + return candidate; + } + + if (!cfg->ap_bw_limit || + (wf_bw_chspec_to_mhz(candidate) <= wf_bw_chspec_to_mhz(cfg->ap_bw_chspec))) { + /* LIMIT is not set or narrower bandwidth is required */ + return candidate; + } + updated_chspec = wf_create_chspec_from_primary( + wf_chspec_primary20_chan(candidate), + cfg->ap_bw_chspec, + BAND_PARAM(WL_CHANSPEC_BAND_6G)); + + return updated_chspec; +} + +/* configure BW limit for AP + * support 6G band only + */ +int +wl_cfg80211_set_softap_bw(struct bcm_cfg80211 *cfg, uint32 band, uint32 limit) +{ + int i, found = FALSE, f_idx = 0; + uint32 support_bw[][2] = { + {WLC_BW_20MHZ_BIT, WL_CHANSPEC_BW_20}, + {WLC_BW_40MHZ_BIT, WL_CHANSPEC_BW_40}, + {WLC_BW_80MHZ_BIT, WL_CHANSPEC_BW_80}, +#if defined(CHSPEC_IS160) + {WLC_BW_160MHZ_BIT, WL_CHANSPEC_BW_160}, +#endif /* CHSPEC_IS160 */ + }; + + if (band != WL_CHANSPEC_BAND_6G) { + WL_ERR(("AP BW LIMIT supportted for 6G band only requested = %d\n", band)); + return FALSE; + } + + for (i = 0; i < ARRAYSIZE(support_bw); i++) { + if (support_bw[i][0] == limit) { + found = TRUE; + f_idx = i; + break; + } + } + + if (limit && !found) { + WL_ERR(("AP BW LIMIT not supported bandwidth :%d\n", limit)); + return BCME_ERROR; + } + + cfg->ap_bw_limit = limit; + if (found) { + cfg->ap_bw_chspec = support_bw[f_idx][1]; + } else { + cfg->ap_bw_chspec = INVCHANSPEC; + } + + return BCME_OK; +} +#endif /* LIMIT_AP_BW */ + +#ifdef WL_STATIC_IF +struct net_device * +wl_cfg80211_register_static_if(struct bcm_cfg80211 *cfg, u16 iftype, char *ifname, + int static_ifidx) +{ +#if defined(CUSTOM_MULTI_MAC) || defined(WL_EXT_IAPSTA) + dhd_pub_t *dhd = cfg->pub; +#endif + struct net_device *ndev; + struct wireless_dev *wdev = NULL; + int ifidx = WL_STATIC_IFIDX; /* Register ndev with a reserved ifidx */ + u8 mac_addr[ETH_ALEN]; + struct net_device *primary_ndev; +#ifdef DHD_USE_RANDMAC + struct ether_addr ea_addr; +#endif /* DHD_USE_RANDMAC */ +#ifdef CUSTOM_MULTI_MAC + char hw_ether[62]; +#endif + + BCM_REFERENCE(primary_ndev); + + WL_INFORM_MEM(("[STATIC_IF] Enter (%s) iftype:%d\n", ifname, iftype)); + + if (!cfg) { + WL_ERR(("cfg null\n")); + return NULL; + } + primary_ndev = bcmcfg_to_prmry_ndev(cfg); + UNUSED_PARAMETER(primary_ndev); + + ifidx += static_ifidx; +#ifdef DHD_USE_RANDMAC + wl_cfg80211_generate_mac_addr(&ea_addr); + (void)memcpy_s(mac_addr, ETH_ALEN, ea_addr.octet, ETH_ALEN); +#else +#if defined(CUSTOM_MULTI_MAC) + if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, static_ifidx+1)) { + (void)memcpy_s(mac_addr, ETH_ALEN, hw_ether, ETH_ALEN); + DEV_ADDR_GET(hw_ether, mac_addr); + } else +#endif + { + /* Use primary mac with locally admin bit set */ + DEV_ADDR_GET(primary_ndev, mac_addr); + mac_addr[0] |= 0x02; +#ifdef WL_EXT_IAPSTA + wl_ext_iapsta_get_vif_macaddr(dhd, static_ifidx+1, mac_addr); +#endif + } +#endif /* DHD_USE_RANDMAC */ + + ndev = wl_cfg80211_allocate_if(cfg, ifidx, ifname, mac_addr, + WL_BSSIDX_MAX, NULL); + if (unlikely(!ndev)) { + WL_ERR(("Failed to allocate static_if\n")); + goto fail; + } + wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev)); + if (unlikely(!wdev)) { + WL_ERR(("Failed to allocate wdev for static_if\n")); + goto fail; + } + + wdev->wiphy = cfg->wdev->wiphy; + wdev->iftype = iftype; + + ndev->ieee80211_ptr = wdev; + SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); + wdev->netdev = ndev; + + if (wl_cfg80211_register_if(cfg, ifidx, + ndev, TRUE) != BCME_OK) { + WL_ERR(("ndev registration failed!\n")); + goto fail; + } + + cfg->static_ndev[static_ifidx] = ndev; + cfg->static_ndev_state[static_ifidx] = NDEV_STATE_OS_IF_CREATED; + wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, WL_BSSIDX_MAX, + ifname, NDEV_STATE_OS_IF_CREATED); + WL_INFORM_MEM(("Static I/F (%s) Registered\n", ndev->name)); + return ndev; + +fail: + wl_cfg80211_remove_if(cfg, ifidx, ndev, false); + return NULL; +} + +void +wl_cfg80211_unregister_static_if(struct bcm_cfg80211 *cfg) +{ + int i; + + WL_INFORM_MEM(("[STATIC_IF] Enter\n")); + if (!cfg) { + WL_ERR(("invalid input\n")); + return; + } + + /* wdev free will happen from notifier context */ + /* free_netdev(cfg->static_ndev); + */ + for (i=0; istatic_ndev[i]) + unregister_netdev(cfg->static_ndev[i]); + } +} + +s32 +wl_cfg80211_static_if_open(struct net_device *net) +{ + struct wireless_dev *wdev = NULL; + struct bcm_cfg80211 *cfg = wl_get_cfg(net); + struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg); + u16 iftype = net->ieee80211_ptr ? net->ieee80211_ptr->iftype : 0; + u16 wl_iftype, wl_mode; +#ifdef CUSTOM_MULTI_MAC + dhd_pub_t *dhd = dhd_get_pub(net); + char hw_ether[62]; +#endif + int static_ifidx; + + WL_INFORM_MEM(("[STATIC_IF] dev_open ndev %p and wdev %p\n", net, net->ieee80211_ptr)); + static_ifidx = wl_cfg80211_static_ifidx(cfg, net); + ASSERT(static_ifidx >= 0); + + if (cfg80211_to_wl_iftype(iftype, &wl_iftype, &wl_mode) < 0) { + return BCME_ERROR; + } + if (cfg->static_ndev_state[static_ifidx] != NDEV_STATE_FW_IF_CREATED) { +#ifdef CUSTOM_MULTI_MAC + if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, static_ifidx+1)) + dev_addr_set(net, hw_ether); +#endif + wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name, net->dev_addr); + if (!wdev) { + WL_ERR(("[STATIC_IF] wdev is NULL, can't proceed")); + return BCME_ERROR; + } + } else { + WL_INFORM_MEM(("Fw IF for static netdev already created\n")); + } + + return BCME_OK; +} + +s32 +wl_cfg80211_static_if_close(struct net_device *net) +{ + int ret = BCME_OK; + struct bcm_cfg80211 *cfg = wl_get_cfg(net); + struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg); + int static_ifidx; + + /* clear flags */ + wl_clr_drv_status(cfg, AP_ROLE_UPGRADED, net); + static_ifidx = wl_cfg80211_static_ifidx(cfg, net); + + if (cfg->static_ndev_state[static_ifidx] == NDEV_STATE_FW_IF_CREATED) { + if (mutex_is_locked(&cfg->if_sync) == TRUE) { + ret = _wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name); + } else { + ret = wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name); + } + + if (unlikely(ret)) { + WL_ERR(("Del iface failed for static_if %d\n", ret)); + } + } + + return ret; +} + +struct net_device * +wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg, + wl_if_event_info *event, u8 *addr, s32 iface_type, int static_ifidx) +{ + struct net_device *new_ndev = NULL; + struct wireless_dev *wdev = NULL; + + WL_INFORM_MEM(("Updating static iface after Fw IF create \n")); + new_ndev = cfg->static_ndev[static_ifidx]; + + if (new_ndev) { + wdev = new_ndev->ieee80211_ptr; + ASSERT(wdev); + wdev->iftype = iface_type; + DEV_ADDR_SET(new_ndev, addr); + } + + cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_CREATED; + wl_cfg80211_update_iflist_info(cfg, new_ndev, event->ifidx, addr, event->bssidx, + event->name, NDEV_STATE_FW_IF_CREATED); + return new_ndev; +} + +s32 +wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + int static_ifidx; + int ifidx = WL_STATIC_IFIDX; + + static_ifidx = wl_cfg80211_static_ifidx(cfg, ndev); + ifidx += static_ifidx; + cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_DELETED; + wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, + WL_BSSIDX_MAX, NULL, NDEV_STATE_FW_IF_DELETED); + wl_cfg80211_clear_per_bss_ies(cfg, ndev->ieee80211_ptr); + wl_dealloc_netinfo_by_wdev(cfg, ndev->ieee80211_ptr); + return BCME_OK; +} +#endif /* WL_STATIC_IF */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvif.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvif.h old mode 100755 new mode 100644 index 09f63fb36235..76c78cabbe7a --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvif.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvif.h @@ -1,7 +1,7 @@ /* * Wifi Virtual Interface implementaion * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -118,18 +118,21 @@ void wl_cfg80211_init_ap_rps(struct bcm_cfg80211 *cfg); int wl_cfg80211_iface_count(struct net_device *dev); struct net_device* wl_get_ap_netdev(struct bcm_cfg80211 *cfg, char *ifname); void wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211 *cfg, bool rtnl_lock_reqd); +extern wl_iftype_t wl_cfg80211_get_sec_iface(struct bcm_cfg80211 *cfg); #ifdef WL_IFACE_MGMT extern int wl_cfg80211_set_iface_policy(struct net_device *ndev, char *arg, int len); extern uint8 wl_cfg80211_get_iface_policy(struct net_device *ndev); extern s32 wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 *cfg, wl_iftype_t new_wl_iftype); -extern wl_iftype_t wl_cfg80211_get_sec_iface(struct bcm_cfg80211 *cfg); #endif /* WL_IFACE_MGMT */ extern s32 wl_get_vif_macaddr(struct bcm_cfg80211 *cfg, u16 wl_iftype, u8 *mac_addr); -extern s32 wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, u8 *mac_addr, u16 wl_iftype); +extern s32 wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, const u8 *mac_addr, u16 wl_iftype); -int wl_cfg80211_set_he_mode(struct net_device *dev, struct bcm_cfg80211 *cfg, +int wl_cfg80211_change_he_features(struct net_device *dev, struct bcm_cfg80211 *cfg, s32 bssidx, u32 interface_type, bool set); +extern int wl_cfg80211_set_he_features(struct net_device *dev, struct bcm_cfg80211 *cfg, + s32 bssidx, u32 interface_type, uint features); + #ifdef SUPPORT_AP_SUSPEND extern int wl_set_ap_suspend(struct net_device *dev, bool enable, char *ifname); #endif /* SUPPORT_AP_SUSPEND */ @@ -137,6 +140,10 @@ extern int wl_set_ap_suspend(struct net_device *dev, bool enable, char *ifname); int wl_set_softap_elna_bypass(struct net_device *dev, char *ifname, int enable); int wl_get_softap_elna_bypass(struct net_device *dev, char *ifname, void *param); #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */ +#ifdef CUSTOM_SOFTAP_SET_ANT +int wl_set_softap_antenna(struct net_device *dev, char *ifname, int set_chain); +int wl_get_softap_antenna(struct net_device *dev, char *ifname, void *param); +#endif /* CUSTOM_SOFTAP_SET_ANT */ #ifdef SUPPORT_AP_BWCTRL extern int wl_set_ap_bw(struct net_device *dev, u32 bw, char *ifname); extern int wl_get_ap_bw(struct net_device *dev, char* command, char *ifname, int total_len); @@ -144,11 +151,9 @@ extern int wl_get_ap_bw(struct net_device *dev, char* command, char *ifname, int extern s32 wl_get_nl80211_band(u32 wl_band); extern int wl_get_bandwidth_cap(struct net_device *ndev, uint32 band, uint32 *bandwidth); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || \ - defined(WL_COMPAT_WIRELESS) -#if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || \ - ((LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) && \ - LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) +#if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \ + KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) extern s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capability, const u8 *buf, size_t len); @@ -189,13 +194,22 @@ extern s32 wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_devi s32 wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + enum nl80211_channel_type channel_type +#else + enum nl80211_chan_width width +#endif +); #endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ - defined(WL_COMPAT_WIRELESS) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) extern s32 wl_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *info); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) +extern s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id); +#else extern s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev); +#endif /* LINUX_VER >= 5.19.2 || CFG80211_BKPORT_MLO */ extern s32 wl_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_beacon_data *info); #else @@ -203,6 +217,10 @@ extern s32 wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *de struct beacon_parameters *info); extern s32 wl_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev); #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || WL_COMPAT_WIRELESS */ +#ifdef WL_CFG80211_ACL +extern int wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev, + const struct cfg80211_acl_data *acl); +#endif /* WL_CFG80211_ACL */ extern s32 wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); @@ -248,4 +266,28 @@ extern bool wl_cfg80211_is_tdls_tunneled_frame(void *frame, u32 frame_len); #ifdef SUPPORT_AP_BWCTRL extern void wl_restore_ap_bw(struct bcm_cfg80211 *cfg); #endif /* SUPPORT_AP_BWCTRL */ +extern bool wl_is_sta_connected(struct bcm_cfg80211 *cfg); +extern void wl_cfgvif_roam_config(struct bcm_cfg80211 *cfg, struct net_device *dev, + wl_roam_conf_t state); +#ifdef SUPPORT_AP_INIT_BWCONF +extern uint32 +wl_get_configured_ap_bw(dhd_pub_t *dhdp); +extern uint32 +wl_update_configured_bw(uint32 bw); +#endif /* SUPPORT_AP_INIT_BWCONF */ +extern uint32 wl_cfgvif_get_iftype_count(struct bcm_cfg80211 *cfg, wl_iftype_t iftype); +extern s32 wl_update_akm_from_assoc_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, + u8 *assoc_ies, u32 assoc_ie_len); + +#if defined(LIMIT_AP_BW) +uint32 wl_cfg80211_get_ap_bw_limit_bit(struct bcm_cfg80211 *cfg, uint32 band); +chanspec_t wl_cfg80211_get_ap_bw_limited_chspec(struct bcm_cfg80211 *cfg, + uint32 band, chanspec_t candidate); +int wl_cfg80211_set_softap_bw(struct bcm_cfg80211 *cfg, uint32 band, uint32 limit); +#endif /* LIMIT_AP_BW */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) +extern int wl_chspec_chandef(chanspec_t chanspec, + struct cfg80211_chan_def *chandef, struct wiphy *wiphy); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))) */ #endif /* _wl_cfgvif_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_dbg.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_dbg.h deleted file mode 100755 index cbdce44bc39b..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_dbg.h +++ /dev/null @@ -1,1544 +0,0 @@ -/* - * Minimal debug/trace/assert driver definitions for - * Broadcom 802.11 Networking Adapter. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - */ - -/* XXX, some old "wl msglevel" for PHY module has been moved to phy on 6/10/2009 "wl phymsglevel" - * They are spare in TOT and can be reused if needed. see src/wl/phy/wlc_phy_int.h - */ - -#ifndef _wl_dbg_h_ -#define _wl_dbg_h_ - -#include - -/* wl_msg_level is a bit vector with defs in wlioctl.h */ -extern uint32 wl_msg_level; -extern uint32 wl_msg_level2; -extern uint32 wl_msg_level3; - -#if defined (BCMDBG) && \ -!defined(BCMDONGLEHOST) && !defined(BCMDBG_EXCLUDE_HW_TIMESTAMP) -extern char* wlc_dbg_get_hw_timestamp(void); - -#define WL_TIMESTAMP() do { if (wl_msg_level2 & WL_TIMESTAMP_VAL) {\ - printf(wlc_dbg_get_hw_timestamp()); }\ - } while (0) -#else -#define WL_TIMESTAMP() -#endif /* BCMDBG && !BCMDONGLEHOST && !BCMDBG_EXCLUDE_HW_TIMESTAMP */ - -#ifdef ENABLE_CORECAPTURE -#define MAX_BACKTRACE_DEPTH 32 -extern int wl_print_backtrace(const char * prefix, void * i_backtrace, int i_backtrace_depth); -#else -#define wl_print_backtrace(a, b, c) -#endif /* ENABLE_CORECAPTURE */ - -#define WIFICC_CAPTURE(_reason) -#define WIFICC_LOGDEBUGIF(_flags, _args) -#define WIFICC_LOGDEBUG(_args) - -#define WL_PRINT(args) do { WL_TIMESTAMP(); printf args; } while (0) - -#ifdef BCM_UPTIME_PROFILE -#define WL_PROF(args) WL_PRINT(args) -#else -#define WL_PROF(args) -#endif /* BCM_UPTIME_PROFILE */ - -#if defined(ERR_USE_EVENT_LOG) && defined(EVENT_LOG_COMPILE) -#define EVENT_LOG_PRSRV_DUMP() EVENT_LOG_PRSRV_FLUSH() -#else -#define EVENT_LOG_PRSRV_DUMP() -#endif /* ERR_USE_EVENT_LOG && EVENT_LOG_COMPILE */ - -#if defined(BCMDBG) - -/* DBGONLY() macro to reduce ifdefs in code for statements that are only needed when - * BCMDBG is defined. - * Ex. - * myfn() { - * int i; - * DBGONLY(int dbg; ) - */ -#define DBGONLY(x) x - -#define WL_WARN(x) WL_ERROR(x) - -/* To disable a message completely ... until you need it again */ -#define WL_NONE(args) do {if (wl_msg_level & 0) WL_PRINT(args);} while (0) - -#define WL_ERROR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args);} while (0) - -#define WL_IE_ERROR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args); } while (0) - -#define WL_AMSDU_ERROR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args); } while (0) - -#define WL_ASSOC_ERROR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args); } while (0) - -#define WL_SCAN_ERROR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args); } while (0) -#define KM_ERR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args); } while (0) - -#define WL_WBTEXT_ERROR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args); } while (0) - -#define WL_MBO_ERR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args); } while (0) - -#define WL_RANDMAC_ERR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args); } while (0) - -#define WL_TRACE(args) do {if (wl_msg_level & WL_TRACE_VAL) WL_PRINT(args);} while (0) - -#define WL_PFN_ERROR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args); } while (0) - -#define WL_PRHDRS_MSG(args) do {if (wl_msg_level & WL_PRHDRS_VAL) WL_PRINT(args);} while (0) -#define WL_PRHDRS(i, p, f, t, r, l) do { \ - if (wl_msg_level & WL_PRHDRS_VAL) \ - wlc_print_hdrs(i, p, f, t, r, l); \ - } while (0) -#define WL_PRPKT(m, b, n) do {if (wl_msg_level & WL_PRPKT_VAL) prhex(m, b, n);} while (0) -#define WL_INFORM(args) do {if (wl_msg_level & WL_INFORM_VAL) WL_PRINT(args);} while (0) -#define WL_TMP(args) do {if (wl_msg_level & WL_TMP_VAL) WL_PRINT(args);} while (0) -#define WL_OID(args) do {if (wl_msg_level & WL_OID_VAL) WL_PRINT(args);} while (0) -#define WL_RATE(args) do {if (wl_msg_level & WL_RATE_VAL) WL_PRINT(args);} while (0) -#define WL_ASSOC(args) do {if (wl_msg_level & WL_ASSOC_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args);} while (0) -#define WL_PRUSR(m, b, n) do {if (wl_msg_level & WL_PRUSR_VAL) prhex(m, b, n);} while (0) -#define WL_PS(args) do {if (wl_msg_level & WL_PS_VAL) WL_PRINT(args);} while (0) -#define WL_SPARE1(args) do {if (wl_msg_level & WL_TXPWR_VAL) WL_PRINT(args);} while (0) -#define WL_PORT(args) do {if (wl_msg_level & WL_PORT_VAL) WL_PRINT(args);} while (0) -#define WL_DUAL(args) do {if (wl_msg_level & WL_DUAL_VAL) WL_PRINT(args);} while (0) -#define WL_WSEC(args) do {if (wl_msg_level & WL_WSEC_VAL) WL_PRINT(args);} while (0) -#define WL_WSEC_DUMP(args) do {if (wl_msg_level & WL_WSEC_DUMP_VAL) WL_PRINT(args);} while (0) -#define WL_SPARE2(args) do {if (wl_msg_level & WL_NRSSI_VAL) WL_PRINT(args);} while (0) -#define WL_SPARE3(args) do {if (wl_msg_level & WL_LOFT_VAL) WL_PRINT(args);} while (0) -#define WL_REGULATORY(args) do {if (wl_msg_level & WL_REGULATORY_VAL) WL_PRINT(args);} while (0) -#define WL_SPARE4(args) do {if (wl_msg_level & WL_PHYCAL_VAL) WL_PRINT(args);} while (0) -#define WL_WDI(args) do {if (wl_msg_level & WL_WDI_VAL) WL_PRINT(args);} while (0) -#define WL_MPC(args) do {if (wl_msg_level & WL_MPC_VAL) WL_PRINT(args);} while (0) -#define WL_APSTA(args) do {if (wl_msg_level & WL_APSTA_VAL) WL_PRINT(args);} while (0) -#define WL_DFS(args) do {if (wl_msg_level & WL_DFS_VAL) WL_PRINT(args);} while (0) -#define WL_MUMIMO(args) do {if (wl_msg_level & WL_MUMIMO_VAL) WL_PRINT(args);} while (0) -#define WL_MODE_SWITCH(args) do {if (wl_msg_level & WL_MODE_SWITCH_VAL) WL_PRINT(args);} while (0) -#define WL_BCNTRIM_DBG(args) do {if (wl_msg_level & WL_BCNTRIM_VAL) WL_PRINT(args);} while (0) -#define WL_MBSS(args) do {if (wl_msg_level & WL_MBSS_VAL) WL_PRINT(args);} while (0) -#define WL_CAC(args) do {if (wl_msg_level & WL_CAC_VAL) WL_PRINT(args);} while (0) -#define WL_AMSDU(args) do {if (wl_msg_level & WL_AMSDU_VAL) WL_PRINT(args);} while (0) -#define WL_AMPDU(args) do {if (wl_msg_level & WL_AMPDU_VAL) WL_PRINT(args);} while (0) -#define WL_FFPLD(args) do {if (wl_msg_level & WL_FFPLD_VAL) WL_PRINT(args);} while (0) -#define WL_PFN(args) do {if (wl_msg_level & WL_PFN_VAL) WL_PRINT(args);} while (0) -/* wl_msg_level is full. Use wl_msg_level_2 now */ -#define WL_WOWL(args) do {if (wl_msg_level2 & WL_WOWL_VAL) WL_PRINT(args);} while (0) -#define WL_SCAN(args) do {if (wl_msg_level2 & WL_SCAN_VAL) WL_PRINT(args);} while (0) -#define WL_SCAN_WARN(args) do {if (wl_msg_level2 & WL_SCAN_VAL) WL_PRINT(args);} while (0) -#define WL_COEX(args) do {if (wl_msg_level2 & WL_COEX_VAL) WL_PRINT(args);} while (0) -#define WL_RTDC(w,s,i,j) do {if (wl_msg_level2 & WL_RTDC_VAL) wlc_log(w,s,i,j);} while (0) -#define WL_PROTO(args) do {if (wl_msg_level2 & WL_PROTO_VAL) WL_PRINT(args);} while (0) -#define WL_RTDC2(w,s,i,j) do {if (wl_msg_level2 & 0) wlc_log(w,s,i,j);} while (0) -#define WL_CHANINT(args) do {if (wl_msg_level2 & WL_CHANINT_VAL) WL_PRINT(args);} while (0) -#define WL_WMF(args) do {if (wl_msg_level2 & WL_WMF_VAL) WL_PRINT(args);} while (0) -#define WL_P2P(args) do {if (wl_msg_level2 & WL_P2P_VAL) WL_PRINT(args);} while (0) -#define WL_ITFR(args) do {if (wl_msg_level2 & WL_ITFR_VAL) WL_PRINT(args);} while (0) -#define WL_MCHAN(args) do {if (wl_msg_level2 & WL_MCHAN_VAL) WL_PRINT(args);} while (0) -#define WL_TDLS(args) do {if (wl_msg_level2 & WL_TDLS_VAL) WL_PRINT(args);} while (0) -#define WL_MCNX(args) do {if (wl_msg_level2 & WL_MCNX_VAL) WL_PRINT(args);} while (0) -#define WL_PROT(args) do {if (wl_msg_level2 & WL_PROT_VAL) WL_PRINT(args);} while (0) -#define WL_PSTA(args) do {if (wl_msg_level2 & WL_PSTA_VAL) WL_PRINT(args);} while (0) -#define WL_TBTT(args) do {if (wl_msg_level2 & WL_TBTT_VAL) WL_PRINT(args);} while (0) -#define WL_TRF_MGMT(args) do {if (wl_msg_level2 & WL_TRF_MGMT_VAL) WL_PRINT(args);} while (0) -#define WL_L2FILTER(args) do {if (wl_msg_level2 & WL_L2FILTER_VAL) WL_PRINT(args);} while (0) -#define WL_TSO(args) do {if (wl_msg_level2 & WL_TSO_VAL) WL_PRINT(args);} while (0) -#define WL_MQ(args) do {if (wl_msg_level2 & WL_MQ_VAL) WL_PRINT(args);} while (0) -#define WL_P2PO(args) do {if (wl_msg_level2 & WL_P2PO_VAL) WL_PRINT(args);} while (0) -#ifdef WLAWDL -#define WL_AWDL(args) do {if (wl_msg_level2 & WL_AWDL_VAL) WL_PRINT(args);} while (0) -#endif /* WLAWDL */ -#define WL_WNM(args) do {if (wl_msg_level2 & WL_WNM_VAL) WL_PRINT(args);} while (0) -#define WL_TXBF(args) do {if (wl_msg_level2 & WL_TXBF_VAL) WL_PRINT(args);} while (0) -#define WL_PCIE(args) do {if (wl_msg_level2 & WL_PCIE_VAL) WL_PRINT(args);} while (0) -#define WL_PMDUR(args) do {if (wl_msg_level2 & WL_PMDUR_VAL) WL_PRINT(args);} while (0) -#ifdef BCMTSTAMPEDLOGS -void wlc_bmac_tslog(struct wlc_hw_info *hw, const char *str, uint32 p1, uint32 p2); -#else -#define wlc_bmac_tslog(hw, str, p1, p2) do {} while (0) -#endif -#define WL_TSLOG(w, s, i, j) \ - do { \ - if (wl_msg_level2 & WL_TIMESTAMP_VAL) { \ - wlc_bmac_tslog(w, s, i, j); \ - } \ - } while (0) -/* not using WL_ROAM for BCMDBG at the moment */ -#define WL_ROAM(args) -#define WL_PRMAC(args) do {if (wl_msg_level & WL_PRMAC_VAL) WL_PRINT(args);} while (0) -#define WL_FBT(args) do {if (wl_msg_level2 & WL_FBT_VAL) WL_PRINT(args);} while (0) -#define WL_MESH(args) do {if (wl_msg_level2 & WL_MESH_VAL) WL_PRINT(args);} while (0) -#define WL_SWDIV(args) do {if (wl_msg_level2 & WL_SWDIV_VAL) WL_PRINT(args);} while (0) -#define WL_MBO_DBG(args) do {if (wl_msg_level2 & WL_MBO_VAL) WL_PRINT(args);} while (0) -#define WL_RANDMAC_INFO(args) do {if (wl_msg_level2 & WL_RANDMAC_VAL) WL_PRINT(args);} while (0) -#define WL_BAM_ERR(args) do {if (wl_msg_level2 & WL_ERROR_VAL) WL_PRINT(args);} while (0) -#define WL_ADPS(args) do {if (wl_msg_level2 & WL_ADPS_VAL) WL_PRINT(args);} while (0) -#define WL_OCE_DBG(args) do {if (wl_msg_level2 & WL_OCE_VAL) WL_PRINT(args);} while (0) -#define WL_WBTEXT_INFO(args) do {if (wl_msg_level2 & WL_WNM_VAL) WL_PRINT(args);} while (0) -#define WL_ASSOC_AP(args) \ - do { \ - if (wl_msg_level3 & WL_ASSOC_AP_VAL) { \ - WL_PRINT(args); \ - } else { \ - WIFICC_LOGDEBUG(args); \ - } \ - } while (0) -#define WL_TPA_ERR(args) do {if (wl_msg_level2 & WL_ERROR_VAL) WL_PRINT(args);} while (0) -#define WL_TPA_INFO(args) do {if (wl_msg_level2 & WL_INFORM_VAL) WL_PRINT(args);} while (0) -#define WL_LATENCY_INFO(args) do {if (wl_msg_level3 & WL_LATENCY_VAL) WL_PRINT(args);} while (0) - -#define WL_ERROR_ON() (wl_msg_level & WL_ERROR_VAL) -#define WL_TRACE_ON() (wl_msg_level & WL_TRACE_VAL) -#define WL_PRHDRS_ON() (wl_msg_level & WL_PRHDRS_VAL) -#define WL_PRPKT_ON() (wl_msg_level & WL_PRPKT_VAL) -#define WL_INFORM_ON() (wl_msg_level & WL_INFORM_VAL) -#define WL_TMP_ON() (wl_msg_level & WL_TMP_VAL) -#define WL_OID_ON() (wl_msg_level & WL_OID_VAL) -#define WL_RATE_ON() (wl_msg_level & WL_RATE_VAL) -#define WL_ASSOC_ON() (wl_msg_level & WL_ASSOC_VAL) -#define WL_PORT_ON() (wl_msg_level & WL_PORT_VAL) -#define WL_WSEC_ON() (wl_msg_level & WL_WSEC_VAL) -#define WL_WSEC_DUMP_ON() (wl_msg_level & WL_WSEC_DUMP_VAL) -#define WL_MPC_ON() (wl_msg_level & WL_MPC_VAL) -#define WL_REGULATORY_ON() (wl_msg_level & WL_REGULATORY_VAL) -#define WL_APSTA_ON() (wl_msg_level & WL_APSTA_VAL) -#define WL_DFS_ON() (wl_msg_level & WL_DFS_VAL) -#define WL_MUMIMO_ON() (wl_msg_level & WL_MUMIMO_VAL) -#define WL_MODE_SWITCH_ON() (wl_msg_level & WL_MODE_SWITCH_VAL) -#define WL_MBSS_ON() (wl_msg_level & WL_MBSS_VAL) -#define WL_AMPDU_ON() (wl_msg_level & WL_AMPDU_VAL) -#define WL_PFN_ON() (wl_msg_level & WL_PFN_VAL) -#define WL_WOWL_ON() (wl_msg_level2 & WL_WOWL_VAL) -#define WL_SCAN_ON() (wl_msg_level2 & WL_SCAN_VAL) -#define WL_WMF_ON() (wl_msg_level2 & WL_WMF_VAL) -#define WL_P2P_ON() (wl_msg_level2 & WL_P2P_VAL) -#define WL_ITFR_ON() (wl_msg_level2 & WL_ITFR_VAL) -#define WL_MCHAN_ON() (wl_msg_level2 & WL_MCHAN_VAL) -#define WL_TDLS_ON() (wl_msg_level2 & WL_TDLS_VAL) -#define WL_MCNX_ON() (wl_msg_level2 & WL_MCNX_VAL) -#define WL_PROT_ON() (wl_msg_level2 & WL_PROT_VAL) -#define WL_PSTA_ON() (wl_msg_level2 & WL_PSTA_VAL) -#define WL_TBTT_ON() (wl_msg_level2 & WL_TBTT_VAL) -#define WL_TRF_MGMT_ON() (wl_msg_level2 & WL_TRF_MGMT) -#define WL_LPC_ON() (wl_msg_level2 & WL_LPC_VAL) -#define WL_L2FILTER_ON() (wl_msg_level2 & WL_L2FILTER_VAL) -#define WL_MQ_ON() (wl_msg_level2 & WL_MQ_VAL) -#define WL_P2PO_ON() (wl_msg_level2 & WL_P2PO_VAL) -#ifdef WLAWDL -#define WL_AWDL_ON() (wl_msg_level2 & WL_AWDL_VAL) -#endif /* WLAWDL */ -#define WL_WNM_ON() (wl_msg_level2 & WL_WNM_VAL) -#define WL_TXBF_ON() (wl_msg_level2 & WL_TXBF_VAL) -#define WL_PCIE_ON() (wl_msg_level2 & WL_PCIE_VAL) -#define WL_TSLOG_ON() (wl_msg_level2 & WL_TIMESTAMP_VAL) -#define WL_MESH_ON() (wl_msg_level2 & WL_MESH_VAL) -#define WL_SWDIV_ON() (wl_msg_level2 & WL_SWDIV_VAL) -#define WL_MBO_DBG_ON() (wl_msg_level2 & WL_MBO_VAL) -#define WL_RANDMAC_DBG_ON() (wl_msg_level2 & WL_RANDMAC_VAL) -#define WL_ADPS_ON() (wl_msg_level2 & WL_ADPS_VAL) -#define WL_OCE_DBG_ON() (wl_msg_level2 & WL_OCE_VAL) -#define WL_ASSOC_AP_ON() (wl_msg_level3 & WL_ASSOC_AP_VAL) -#define WL_FILS_DBG_ON() (wl_msg_level3 & WL_FILS_DBG_VAL) - -/* Extra message control for APSTA debugging */ -#define WL_APSTA_UPDN_VAL 0x00000001 /* Config up/down related */ -#define WL_APSTA_BCN_VAL 0x00000002 /* Calls to beacon update */ -#define WL_APSTA_TX_VAL 0x00000004 /* Transmit data path */ -#define WL_APSTA_RX_VAL 0x00000008 /* Receive data path */ -#define WL_APSTA_TSF_VAL 0x00000010 /* TSF-related items */ -#define WL_APSTA_BSSID_VAL 0x00000020 /* Calls to set bssid */ - -extern uint32 wl_apsta_dbg; - -#define WL_APSTA_UPDN(args) do {if (wl_apsta_dbg & WL_APSTA_UPDN_VAL) {WL_APSTA(args);}} while (0) -#define WL_APSTA_BCN(args) do {if (wl_apsta_dbg & WL_APSTA_BCN_VAL) {WL_APSTA(args);}} while (0) -#define WL_APSTA_TX(args) do {if (wl_apsta_dbg & WL_APSTA_TX_VAL) {WL_APSTA(args);}} while (0) -#define WL_APSTA_RX(args) do {if (wl_apsta_dbg & WL_APSTA_RX_VAL) {WL_APSTA(args);}} while (0) -#define WL_APSTA_TSF(args) do {if (wl_apsta_dbg & WL_APSTA_TSF_VAL) {WL_APSTA(args);}} while (0) -#define WL_APSTA_BSSID(args) do {if (wl_apsta_dbg & WL_APSTA_BSSID_VAL) {WL_APSTA(args);}} while (0) - -/* Extra message control for AMPDU debugging */ -#define WL_AMPDU_UPDN_VAL 0x00000001 /* Config up/down related */ -#define WL_AMPDU_ERR_VAL 0x00000002 /* Calls to beaocn update */ -#define WL_AMPDU_TX_VAL 0x00000004 /* Transmit data path */ -#define WL_AMPDU_RX_VAL 0x00000008 /* Receive data path */ -#define WL_AMPDU_CTL_VAL 0x00000010 /* TSF-related items */ -#define WL_AMPDU_HW_VAL 0x00000020 /* AMPDU_HW */ -#define WL_AMPDU_HWTXS_VAL 0x00000040 /* AMPDU_HWTXS */ -#define WL_AMPDU_HWDBG_VAL 0x00000080 /* AMPDU_DBG */ -#define WL_AMPDU_STAT_VAL 0x00000100 /* statistics */ - -extern uint32 wl_ampdu_dbg; - -#define WL_AMPDU_UPDN(args) do {if (wl_ampdu_dbg & WL_AMPDU_UPDN_VAL) {WL_AMPDU(args);}} while (0) -#define WL_AMPDU_RX(args) do {if (wl_ampdu_dbg & WL_AMPDU_RX_VAL) {WL_AMPDU(args);}} while (0) -#define WL_AMPDU_ERR(args) do {if (wl_ampdu_dbg & WL_AMPDU_ERR_VAL) {WL_AMPDU(args);}} while (0) -#define WL_AMPDU_TX(args) do {if (wl_ampdu_dbg & WL_AMPDU_TX_VAL) {WL_AMPDU(args);}} while (0) -#define WL_AMPDU_CTL(args) do {if (wl_ampdu_dbg & WL_AMPDU_CTL_VAL) {WL_AMPDU(args);}} while (0) -#define WL_AMPDU_HW(args) do {if (wl_ampdu_dbg & WL_AMPDU_HW_VAL) {WL_AMPDU(args);}} while (0) -#define WL_AMPDU_HWTXS(args) do {if (wl_ampdu_dbg & WL_AMPDU_HWTXS_VAL) {WL_AMPDU(args);}} while (0) -#define WL_AMPDU_HWDBG(args) do {if (wl_ampdu_dbg & WL_AMPDU_HWDBG_VAL) {WL_AMPDU(args);}} while (0) -#define WL_AMPDU_STAT(args) do {if (wl_ampdu_dbg & WL_AMPDU_STAT_VAL) {WL_AMPDU(args);}} while (0) -#define WL_AMPDU_ERR_ON() (wl_ampdu_dbg & WL_AMPDU_ERR_VAL) -#define WL_AMPDU_HW_ON() (wl_ampdu_dbg & WL_AMPDU_HW_VAL) -#define WL_AMPDU_HWTXS_ON() (wl_ampdu_dbg & WL_AMPDU_HWTXS_VAL) - -/* Extra Message control for Mesh debugging */ -extern uint32 wl_mesh_dbg; -#define WL_MESH_AMPE_VAL 0x00000001 -#define WL_MESH_ROUTE_VAL 0x00000002 -#define WL_MESH_BCN_VAL 0x00000004 - -#define WL_MESH_AMPE(args) do {if (wl_mesh_dbg & WL_MESH_AMPE_VAL) {WL_MESH(args);}} while (0) -#define WL_MESH_ROUTE(args) do {if (wl_mesh_dbg & WL_MESH_ROUTE_VAL) {WL_MESH(args);}} while (0) -#define WL_MESH_BCN(args) do {if (wl_mesh_dbg & WL_MESH_BCN_VAL) {WL_MESH(args);}} while (0) - -/* BCMDBG */ -#elif defined(BCMCONDITIONAL_LOGGING) - -/* Ideally this should be some include file that vendors can include to conditionalize logging */ - -/* DBGONLY() macro to reduce ifdefs in code for statements that are only needed when - * BCMDBG is defined. - */ -#define DBGONLY(x) x - -/* To disable a message completely ... until you need it again */ -#define WL_NONE(args) -#define WL_WARN(x) WL_ERROR(x) -#define WL_ERROR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args); } while (0) -#define WL_SCAN_ERROR(args) -#define WL_IE_ERROR(args) -#define WL_AMSDU_ERROR(args) -#define WL_ASSOC_ERROR(args) -#define WL_WNM_PDT_ERROR(args) -#define KM_ERR(args) -#define WL_WBTEXT_ERROR(args) -#define WL_WBTEXT_INFO(args) -#define WL_LATENCY_INFO(args) - -#define WL_TRACE(args) -#define WL_PRHDRS_MSG(args) -#define WL_PRHDRS(i, p, f, t, r, l) -#define WL_PRPKT(m, b, n) -#define WL_INFORM(args) -#define WL_TMP(args) -#define WL_OID(args) -#define WL_RATE(args) do {if (wl_msg_level & WL_RATE_VAL) WL_PRINT(args);} while (0) -#define WL_ASSOC(args) do {if (wl_msg_level & WL_ASSOC_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args);} while (0) -#define WL_PRUSR(m, b, n) -#define WL_PS(args) do {if (wl_msg_level & WL_PS_VAL) WL_PRINT(args);} while (0) - -#define WL_PORT(args) -#define WL_DUAL(args) -#define WL_REGULATORY(args) do {if (wl_msg_level & WL_REGULATORY_VAL) WL_PRINT(args); \ - else WIFICC_LOGDEBUG(args);} while (0) - -#define WL_MPC(args) -#define WL_APSTA(args) -#define WL_APSTA_BCN(args) -#define WL_APSTA_TX(args) -#define WL_APSTA_TSF(args) -#define WL_APSTA_BSSID(args) -#define WL_BA(args) -#define WL_MBSS(args) -#define WL_MODE_SWITCH(args) -#define WL_PROTO(args) - -#define WL_CAC(args) do {if (wl_msg_level & WL_CAC_VAL) WL_PRINT(args);} while (0) -#define WL_AMSDU(args) -#define WL_AMPDU(args) -#define WL_FFPLD(args) -#define WL_MCHAN(args) - -#define WL_DFS(args) -#define WL_WOWL(args) -#define WL_DPT(args) -#define WL_ASSOC_OR_DPT(args) -#define WL_SCAN(args) do {if (wl_msg_level2 & WL_SCAN_VAL) WL_PRINT(args);} while (0) -#define WL_SCAN_WARN(args) do {if (wl_msg_level2 & WL_SCAN_VAL) WL_PRINT(args);} while (0) -#define WL_COEX(args) -#define WL_RTDC(w, s, i, j) -#define WL_RTDC2(w, s, i, j) -#define WL_CHANINT(args) -#define WL_BTA(args) -#define WL_P2P(args) -#define WL_ITFR(args) -#define WL_TDLS(args) -#define WL_MCNX(args) -#define WL_PROT(args) -#define WL_PSTA(args) -#define WL_WFDS(m, b, n) -#define WL_TRF_MGMT(args) -#define WL_L2FILTER(args) -#define WL_MQ(args) -#define WL_TXBF(args) -#define WL_MUMIMO(args) -#define WL_P2PO(args) -#ifdef WLAWDL -#define WL_AWDL(args) -#endif /* WLAWDL */ -#define WL_ROAM(args) -#define WL_WNM(args) - -#ifdef WLMSG_MESH -#define WL_MESH(args) WL_PRINT(args) -#define WL_MESH_AMPE(args) WL_PRINT(args) -#define WL_MESH_ROUTE(args) WL_PRINT(args) -#define WL_MESH_BCN(args) -#else -#define WL_MESH(args) -#define WL_MESH_AMPE(args) -#define WL_MESH_ROUTE(args) -#define WL_MESH_BCN(args) -#endif -#define WL_ASSOC_AP(args) \ - do { \ - if (wl_msg_level3 & WL_ASSOC_AP_VAL) { \ - WL_PRINT(args); \ - } else { \ - WIFICC_LOGDEBUG(args); \ - } \ - } while (0) -#ifdef BCMDBG_ERR -#if defined(EVENT_LOG_COMPILE) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_PFN_ERROR(args) EVENT_LOG_RA(EVENT_LOG_TAG_SCAN_ERR, args) -#else -#define WL_PFN_ERROR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_SCAN_ERR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_PFN_ERROR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define WL_PFN_ERROR(args) -#endif /* BCMDBG_ERR */ - -#define WL_AMPDU_UPDN(args) -#define WL_AMPDU_RX(args) -#define WL_AMPDU_ERR(args) -#define WL_AMPDU_TX(args) -#define WL_AMPDU_CTL(args) -#define WL_AMPDU_HW(args) -#define WL_AMPDU_HWTXS(args) -#define WL_AMPDU_HWDBG(args) -#define WL_AMPDU_STAT(args) -#define WL_AMPDU_ERR_ON() 0 -#define WL_AMPDU_HW_ON() 0 -#define WL_AMPDU_HWTXS_ON() 0 - -#define WL_APSTA_UPDN(args) -#define WL_APSTA_RX(args) -#define WL_WSEC(args) -#define WL_WSEC_DUMP(args) -#define WL_PCIE(args) -#define WL_PMDUR(args) -#define WL_TSLOG(w, s, i, j) -#define WL_FBT(args) -#define WL_MBO_DBG(args) -#define WL_RANDMAC_DBG(args) -#define WL_BAM_ERR(args) -#define WL_ADPS(args) -#define WL_OCE_DBG(args) -#define WL_TPA_ERR(args) -#define WL_TPA_INFO(args) - -#define WL_ERROR_ON() (wl_msg_level & WL_ERROR_VAL) -#define WL_TRACE_ON() 0 -#define WL_PRHDRS_ON() 0 -#define WL_PRPKT_ON() 0 -#define WL_INFORM_ON() 0 -#define WL_TMP_ON() 0 -#define WL_OID_ON() 0 -#define WL_RATE_ON() (wl_msg_level & WL_RATE_VAL) -#define WL_ASSOC_ON() (wl_msg_level & WL_ASSOC_VAL) -#define WL_PRUSR_ON() 0 -#define WL_PS_ON() (wl_msg_level & WL_PS_VAL) -#define WL_PORT_ON() 0 -#define WL_WSEC_ON() 0 -#define WL_WSEC_DUMP_ON() 0 -#define WL_MPC_ON() 0 -#define WL_REGULATORY_ON() (wl_msg_level & WL_REGULATORY_VAL) -#define WL_APSTA_ON() 0 -#define WL_DFS_ON() 0 -#define WL_MBSS_ON() 0 -#define WL_CAC_ON() (wl_msg_level & WL_CAC_VAL) -#define WL_AMPDU_ON() 0 -#define WL_DPT_ON() 0 -#define WL_WOWL_ON() 0 -#define WL_SCAN_ON() (wl_msg_level2 & WL_SCAN_VAL) -#define WL_BTA_ON() 0 -#define WL_P2P_ON() 0 -#define WL_ITFR_ON() 0 -#define WL_MCHAN_ON() 0 -#define WL_TDLS_ON() 0 -#define WL_MCNX_ON() 0 -#define WL_PROT_ON() 0 -#define WL_PSTA_ON() 0 -#define WL_TRF_MGMT_ON() 0 -#define WL_LPC_ON() 0 -#define WL_L2FILTER_ON() 0 -#define WL_TXBF_ON() 0 -#define WL_P2PO_ON() 0 -#ifdef WLAWDL -#define WL_AWDL_ON() 0 -#endif /* WLAWDL */ -#define WL_TSLOG_ON() 0 -#define WL_WNM_ON() 0 -#define WL_PCIE_ON() 0 -#define WL_MUMIMO_ON() 0 -#define WL_MESH_ON() 0 -#define WL_MBO_DBG_ON() 0 -#define WL_RANDMAC_DBG_ON() 0 -#define WL_ADPS_ON() 0 -#define WL_OCE_DBG_ON() 0 -#define WL_FILS_DBG_ON() 0 -#define WL_ASSOC_AP_ON() (wl_msg_level3 & WL_ASSOC_AP_VAL) - -#else /* !BCMDBG */ - -/* DBGONLY() macro to reduce ifdefs in code for statements that are only needed when - * BCMDBG is defined. - */ -#define DBGONLY(x) - -/* To disable a message completely ... until you need it again */ -#define WL_NONE(args) - -#ifdef BCMDBG_ERR -/* ROM and ROML optimized builds */ -#if defined(EVENT_LOG_COMPILE) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_ERROR(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_ERROR, args) -#define WL_WARN(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_WARN, args) -#else -#define WL_ERROR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_ERROR, args) -#define WL_WARN(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_WARN, args) -#endif /* ERR_USE_EVENT_LOG_RA */ - -#else -#define WL_ERROR(args) WL_PRINT(args) -#define WL_WARN(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define WL_ERROR(args) -#define WL_WARN(args) -#endif /* BCMDBG_ERR */ - -#ifdef TS_PLOT -#define TS_LOG_DBG(x) x -#define TS_LOG(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_TSLOG, args) -#else -#define TS_LOG_DBG(x) -#define TS_LOG(args) -#endif - -#ifdef BCMDBG_ERR -/* ROM and ROML optimized builds */ -#if defined(EVENT_LOG_COMPILE)&& defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define KM_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_KM_ERROR, args) -#else -#define KM_ERR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_KM_ERROR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define KM_ERR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define KM_ERR(args) -#endif /* BCMDBG_ERR */ - -#ifdef BCMDBG_ERR -/* ROM and ROML optimized builds */ -#if defined(EVENT_LOG_COMPILE) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_AMPDU_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_AMPDU_ERROR, args) -#else -#define WL_AMPDU_ERR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_AMPDU_ERROR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_AMPDU_ERR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define WL_AMPDU_ERR(args) -#endif /* BCMDBG_ERR */ - -#define WL_TRACE(args) -#ifdef WLMSG_PRHDRS -#define WL_PRHDRS_MSG(args) WL_PRINT(args) -#define WL_PRHDRS(i, p, f, t, r, l) wlc_print_hdrs(i, p, f, t, r, l) -#else -#define WL_PRHDRS_MSG(args) -#define WL_PRHDRS(i, p, f, t, r, l) -#endif -#ifdef WLMSG_PRPKT -#define WL_PRPKT(m, b, n) prhex(m, b, n) -#else -#define WL_PRPKT(m, b, n) -#endif -#ifdef WLMSG_INFORM -#define WL_INFORM(args) WL_PRINT(args) -#else -#define WL_INFORM(args) -#endif -#define WL_TMP(args) -#ifdef WLMSG_OID -#define WL_OID(args) WL_PRINT(args) -#else -#define WL_OID(args) -#endif -#define WL_RATE(args) - -#ifdef BCMDBG_ERR -#if defined(EVENT_LOG_COMPILE) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_IE_ERROR(args) EVENT_LOG_RA(EVENT_LOG_TAG_IE_ERROR, args) -#else -#define WL_IE_ERROR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_IE_ERROR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_IE_ERROR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define WL_IE_ERROR(args) -#endif /* BCMDBG_ERR */ - -#ifdef WLMSG_WNM_BSSTRANS -#if defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_WBTEXT_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_WNM_BSSTRANS_INFO, args) -#else -#define WL_WBTEXT_INFO(args) \ - EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_WNM_BSSTRANS_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_WBTEXT_INFO(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_WBTEXT_INFO(args) -#endif /* WLMSG_WNM_BSSTRANS */ - -#if defined(BCMPCIE_LATENCY) && defined(BCMPCIE_LATENCY_DEBUG) -#if defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_LATENCY_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_LATENCY_INFO, args) -#else -#define WL_LATENCY_INFO(args) \ - EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_LATENCY_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_LATENCY_INFO(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_LATENCY_INFO(args) -#endif /* BCMPCIE_LATENCY && BCMPCIE_LATENCY_DEBUG */ - -#ifdef BCMDBG_ERR -#if defined(ERR_USE_EVENT_LOG) && defined(EVENT_LOG_COMPILE) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_WBTEXT_ERROR(args) EVENT_LOG_RA(EVENT_LOG_TAG_WNM_BSSTRANS_ERR, args) -#else -#define WL_WBTEXT_ERROR(args) \ - EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_WNM_BSSTRANS_ERR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_WBTEXT_ERROR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG && EVENT_LOG_COMPILE */ -#else -#define WL_WBTEXT_ERROR(args) -#endif /* BCMDBG_ERR */ - -#ifdef WLMSG_WNM_BSSTRANS -#if defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_WNM_PDT_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_WNM_BSSTRANS_INFO, args) -#else -#define WL_WNM_PDT_INFO(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WNM_BSSTRANS_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_WNM_PDT_INFO(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_WNM_PDT_INFO(args) -#endif /* WLMSG_WNM_BSSTRANS */ - -#ifdef BCMDBG_ERR -#if defined(ERR_USE_EVENT_LOG) && defined(EVENT_LOG_COMPILE) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_WNM_PDT_ERROR(args) EVENT_LOG_RA(EVENT_LOG_TAG_WNM_BSSTRANS_ERR, args) -#else -#define WL_WNM_PDT_ERROR(args) \ - EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_WNM_BSSTRANS_ERR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_WNM_PDT_ERROR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG && EVENT_LOG_COMPILE */ -#else -#define WL_WNM_PDT_ERROR(args) -#endif /* BCMDBG_ERR */ - -#ifdef WLMSG_ASSOC -#if defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_ASSOC(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_ASSOC_LOG, args) -#else -#define WL_ASSOC(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_ASSOC_LOG, args) -#define WL_ASSOC_DP(args) EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_ASSOC_LOG, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_ASSOC(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#define WL_ASSOC_AP(args) WL_PRINT(args) -#else -#define WL_ASSOC(args) -#define WL_ASSOC_AP(args) -#endif /* WLMSG_ASSOC */ - -#ifdef BCMDBG_ERR -/* ROM and ROML optimized builds */ -#if defined(EVENT_LOG_COMPILE) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_ASSOC_ERROR(args) EVENT_LOG_RA(EVENT_LOG_TAG_ASSOC_ERROR, args) -#else -#define WL_ASSOC_ERROR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_ASSOC_ERROR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_ASSOC_ERROR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define WL_ASSOC_ERROR(args) -#endif /* BCMDBG_ERR */ - -#ifdef BCMDBG_ERR -/* ROM and ROML optimized builds */ -#if defined(EVENT_LOG_COMPILE) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_SCAN_ERROR(args) EVENT_LOG_RA(EVENT_LOG_TAG_SCAN_ERR, args) -#else -#define WL_SCAN_ERROR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_SCAN_ERR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_SCAN_ERROR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define WL_SCAN_ERROR(args) -#endif /* BCMDBG_ERR */ - -#define WL_PRUSR(m, b, n) - -#ifdef WLMSG_PS -#if defined(EVENT_LOG_COMPILE) && defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_PS(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_PS_LOG, args) -#else -#define WL_PS(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_PS_LOG, args) -#define WL_PS_DP(args) EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_PS_LOG, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_PS(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_PS(args) -#endif /* WLMSG_PS */ - -#ifdef BCMDBG_ERR -/* ROM and ROML optimized builds */ -#if defined(EVENT_LOG_COMPILE) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_AMSDU_ERROR(args) EVENT_LOG_RA(EVENT_LOG_TAG_AMSDU_ERROR, args) -#else -#define WL_AMSDU_ERROR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_AMSDU_ERROR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_AMSDU_ERROR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define WL_AMSDU_ERROR(args) -#endif /* BCMDBG_ERR */ - -#ifdef BCMDBG_PRINT_EAP_PKT_INFO -#if defined(EVENT_LOG_COMPILE) && defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_8021X_ERR(args) do {printf args; \ - EVENT_LOG_RA(EVENT_LOG_TAG_4WAYHANDSHAKE, args);} while (0) -#else -#define WL_8021X_ERR(args) do {printf args; \ - EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_4WAYHANDSHAKE, args);} while (0) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_8021X_ERR(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_8021X_ERR(args) -#endif /* BCMDBG_PRINT_EAP_PKT_INFO */ - -#ifdef WLMSG_ROAM -#if defined(EVENT_LOG_COMPILE) && defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_ROAM(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_ROAM_LOG, args) -#else -#define WL_ROAM(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_ROAM_LOG, args) -#define WL_ROAM_DP(args) EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_ROAM_LOG, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_ROAM(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_ROAM(args) -#endif /* WLMSG_ROAM */ - -#define WL_PORT(args) -#define WL_DUAL(args) -#define WL_REGULATORY(args) - -#ifdef WLMSG_MPC -#if defined(EVENT_LOG_COMPILE) && defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_MPC(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_MPC_LOG, args) -#else -#define WL_MPC(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_MPC_LOG, args) -#define WL_MPC_DP(args) EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_MPC_LOG, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_MPC(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_MPC(args) -#endif /* WLMSG_MPC */ - -#define WL_APSTA(args) -#define WL_APSTA_BCN(args) -#define WL_APSTA_TX(args) -#define WL_APSTA_TSF(args) -#define WL_APSTA_BSSID(args) -#define WL_BA(args) -#define WL_MBSS(args) -#define WL_MODE_SWITCH(args) -#define WL_PROTO(args) - -#define WL_CAC(args) -#define WL_AMSDU(args) -#define WL_AMPDU(args) -#define WL_FFPLD(args) -#define WL_MCHAN(args) -#define WL_BCNTRIM_DBG(args) - -/* Define WLMSG_DFS automatically for WLTEST builds */ -#if defined(WLTEST) && !defined(WLTEST_DISABLED) -#ifndef WLMSG_DFS -#define WLMSG_DFS -#endif -#endif /* WLTEST */ - -#ifdef WLMSG_DFS -#define WL_DFS(args) do {if (wl_msg_level & WL_DFS_VAL) WL_PRINT(args);} while (0) -#else /* WLMSG_DFS */ -#define WL_DFS(args) -#endif /* WLMSG_DFS */ -#define WL_WOWL(args) - -#ifdef WLMSG_SCAN -#if defined(EVENT_LOG_COMPILE) && defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_SCAN(args) EVENT_LOG_RA(EVENT_LOG_TAG_SCAN_TRACE_LOW, args) -#define WL_SCAN_WARN(args) EVENT_LOG_RA(EVENT_LOG_TAG_SCAN_WARN, args) -#else -#define WL_SCAN(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_SCAN_TRACE_LOW, args) -#define WL_SCAN_DP(args) \ - EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_SCAN_TRACE_LOW, args) -#define WL_SCAN_WARN(args) EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_SCAN_WARN, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_SCAN(args) WL_PRINT(args) -#define WL_SCAN_WARN(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_SCAN(args) -#define WL_SCAN_WARN(args) -#endif /* WLMSG_SCAN */ - -#define WL_COEX(args) -#define WL_RTDC(w, s, i, j) -#define WL_RTDC2(w, s, i, j) -#define WL_CHANINT(args) -#ifdef WLMSG_BTA -#define WL_BTA(args) WL_PRINT(args) -#else -#define WL_BTA(args) -#endif -#define WL_WMF(args) -#define WL_P2P(args) -#define WL_ITFR(args) -#define WL_TDLS(args) - -#ifdef WLMSG_MCNX -#if defined(EVENT_LOG_COMPILE) && defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_MCNX(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_MCNX_LOG, args) -#else -#define WL_MCNX(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_MCNX_LOG, args) -#define WL_MCNX_DP(args) EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_MCNX_LOG, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_MCNX(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_MCNX(args) -#endif /* WLMSG_MCNX */ - -#define WL_PROT(args) -#define WL_PSTA(args) -#define WL_TBTT(args) -#define WL_TRF_MGMT(args) -#define WL_L2FILTER(args) -#define WL_MQ(args) -#define WL_P2PO(args) -#ifdef WLAWDL -#define WL_AWDL(args) -#endif /* WLAWDL */ -#define WL_WNM(args) -#define WL_TXBF(args) -#define WL_TSLOG(w, s, i, j) -#define WL_FBT(args) -#define WL_MUMIMO(args) -#ifdef WLMSG_MESH -#define WL_MESH(args) WL_PRINT(args) -#define WL_MESH_AMPE(args) WL_PRINT(args) -#define WL_MESH_ROUTE(args) WL_PRINT(args) -#define WL_MESH_BCN(args) -#else -#define WL_MESH(args) -#define WL_MESH_AMPE(args) -#define WL_MESH_ROUTE(args) -#define WL_MESH_BCN(args) -#endif -#define WL_SWDIV(args) -#define WL_ADPS(args) - -#ifdef BCMDBG_ERR -#define WL_ERROR_ON() 1 -#else -#define WL_ERROR_ON() 0 -#endif -#define WL_TRACE_ON() 0 -#ifdef WLMSG_PRHDRS -#define WL_PRHDRS_ON() 1 -#else -#define WL_PRHDRS_ON() 0 -#endif -#ifdef WLMSG_PRPKT -#define WL_PRPKT_ON() 1 -#else -#define WL_PRPKT_ON() 0 -#endif -#ifdef WLMSG_INFORM -#define WL_INFORM_ON() 1 -#else -#define WL_INFORM_ON() 0 -#endif -#ifdef WLMSG_OID -#define WL_OID_ON() 1 -#else -#define WL_OID_ON() 0 -#endif -#define WL_TMP_ON() 0 -#define WL_RATE_ON() 0 -#ifdef WLMSG_ASSOC -#define WL_ASSOC_ON() 1 -#define WL_ASSOC_AP_ON() 1 -#else -#define WL_ASSOC_ON() 0 -#define WL_ASSOC_AP_ON() 0 -#endif -#define WL_PORT_ON() 0 -#ifdef WLMSG_WSEC -#define WL_WSEC_ON() 1 -#define WL_WSEC_DUMP_ON() 1 -#else -#define WL_WSEC_ON() 0 -#define WL_WSEC_DUMP_ON() 0 -#endif -#ifdef WLMSG_MPC -#define WL_MPC_ON() 1 -#else -#define WL_MPC_ON() 0 -#endif -#define WL_REGULATORY_ON() 0 - -#define WL_APSTA_ON() 0 -#define WL_BA_ON() 0 -#define WL_MBSS_ON() 0 -#define WL_MODE_SWITCH_ON() 0 -#ifdef WLMSG_DFS -#define WL_DFS_ON() 1 -#else /* WLMSG_DFS */ -#define WL_DFS_ON() 0 -#endif /* WLMSG_DFS */ -#ifdef WLMSG_SCAN -#define WL_SCAN_ON() 1 -#else -#define WL_SCAN_ON() 0 -#endif -#ifdef WLMSG_BTA -#define WL_BTA_ON() 1 -#else -#define WL_BTA_ON() 0 -#endif -#define WL_WMF_ON() 0 -#define WL_P2P_ON() 0 -#define WL_MCHAN_ON() 0 -#define WL_TDLS_ON() 0 -#define WL_MCNX_ON() 0 -#define WL_PROT_ON() 0 -#define WL_TBTT_ON() 0 -#define WL_LPC_ON() 0 -#define WL_L2FILTER_ON() 0 -#define WL_MQ_ON() 0 -#define WL_P2PO_ON() 0 -#ifdef WLAWDL -#define WL_AWDL_ON() 0 -#endif /* WLAWDL */ -#define WL_TXBF_ON() 0 -#define WL_TSLOG_ON() 0 -#define WL_MUMIMO_ON() 0 -#define WL_SWDIV_ON() 0 - -#define WL_AMPDU_UPDN(args) -#define WL_AMPDU_RX(args) -#define WL_AMPDU_TX(args) -#define WL_AMPDU_CTL(args) -#define WL_AMPDU_HW(args) -#define WL_AMPDU_HWTXS(args) -#define WL_AMPDU_HWDBG(args) -#define WL_AMPDU_STAT(args) -#define WL_AMPDU_ERR_ON() 0 -#define WL_AMPDU_HW_ON() 0 -#define WL_AMPDU_HWTXS_ON() 0 - -#define WL_WNM_ON() 0 -#ifdef WLMSG_MBO -#define WL_MBO_DBG_ON() 1 -#else -#define WL_MBO_DBG_ON() 0 -#endif /* WLMSG_MBO */ -#ifdef WLMSG_RANDMAC -#define WL_RANDMAC_DBG_ON() 1 -#else -#define WL_RANDMAC_DBG_ON() 0 -#endif /* WLMSG_RANDMAC */ -#define WL_ADPS_ON() 0 -#ifdef WLMSG_OCE -#define WL_OCE_DBG_ON() 1 -#else -#define WL_OCE_DBG_ON() 0 -#endif /* WLMSG_OCE */ -#ifdef WLMSG_FILS -#define WL_FILS_DBG_ON() 1 -#else -#define WL_FILS_DBG_ON() 0 -#endif /* WLMSG_FILS */ - -#define WL_APSTA_UPDN(args) -#define WL_APSTA_RX(args) - -#ifdef WLMSG_WSEC -#if defined(EVENT_LOG_COMPILE) && defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_WSEC(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_WSEC_LOG, args) -#define WL_WSEC_DUMP(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_WSEC_DUMP, args) -#else -#define WL_WSEC(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_WSEC_LOG, args) -#define WL_WSEC_DUMP(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_WSEC_DUMP, args) -#define WL_WSEC_DP(args) EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_WSEC_LOG, args) -#define WL_WSEC_DUMP_DP(args) EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_WSEC_DUMP, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_WSEC(args) WL_PRINT(args) -#define WL_WSEC_DUMP(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_WSEC(args) -#define WL_WSEC_DUMP(args) -#endif /* WLMSG_WSEC */ - -#ifdef WLMSG_MBO -#if defined(EVENT_LOG_COMPILE) && defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_MBO_DBG(args) EVENT_LOG_RA(EVENT_LOG_TAG_MBO_DBG, args) -#define WL_MBO_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_MBO_INFO, args) -#else -#define WL_MBO_DBG(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_MBO_DBG, args) -#define WL_MBO_INFO(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_MBO_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_MBO_DBG(args) WL_PRINT(args) -#define WL_MBO_INFO(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_MBO_DBG(args) -#define WL_MBO_INFO(args) -#endif /* WLMSG_MBO */ - -#ifdef BCMDBG_ERR -#if defined(EVENT_LOG_COMPILE) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_MBO_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_MBO_ERR, args) -#else -#define WL_MBO_ERR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_MBO_ERR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_MBO_ERR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define WL_MBO_ERR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ - -#ifdef WLMSG_RANDMAC -#if defined(EVENT_LOG_COMPILE) && defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_RANDMAC_DBG(args) EVENT_LOG_RA(EVENT_LOG_TAG_RANDMAC_DBG, args) -#define WL_RANDMAC_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_RANDMAC_INFO, args) -#else -#define WL_RANDMAC_DBG(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_RANDMAC_DBG, args) -#define WL_RANDMAC_INFO(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_RANDMAC_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_RANDMAC_DBG(args) WL_PRINT(args) -#define WL_RANDMAC_INFO(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_RANDMAC_DBG(args) -#define WL_RANDMAC_INFO(args) -#endif /* WLMSG_RANDMAC */ - -#ifdef BCMDBG_ERR -#if defined(EVENT_LOG_COMPILE) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_RANDMAC_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_RANDMAC_ERR, args) -#else -#define WL_RANDMAC_ERR(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_RANDMAC_ERR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_RANDMAC_ERR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define WL_RANDMAC_ERR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ - -#ifdef WLMSG_OCE -#if defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_OCE_DBG(args) EVENT_LOG_RA(EVENT_LOG_TAG_OCE_DBG, args) -#define WL_OCE_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_OCE_INFO, args) -#else -#define WL_OCE_DBG(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_OCE_DBG, args) -#define WL_OCE_INFO(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_OCE_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_OCE_DBG(args) WL_PRINT(args) -#define WL_OCE_INFO(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_OCE_DBG(args) -#define WL_OCE_INFO(args) -#endif /* WLMSG_OCE */ - -#ifdef WLMSG_FILS -#if defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_FILS_DBG(args) EVENT_LOG_RA(EVENT_LOG_TAG_FILS_DBG, args) -#define WL_FILS_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_FILS_INFO, args) -#else -#define WL_FILS_DBG(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_FILS_DBG, args) -#define WL_FILS_INFO(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_FILS_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_FILS_DBG(args) WL_PRINT(args) -#define WL_FILS_INFO(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_FILS_DBG(args) -#define WL_FILS_INFO(args) -#endif /* WLMSG_FILS */ -#ifdef BCMDBG_ERR -#if defined(ERR_USE_EVENT_LOG) && defined(EVENT_LOG_COMPILE) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_OCE_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_OCE_ERR, args) -#define WL_FILS_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_FILS_ERROR, args) - -#else -#define WL_OCE_ERR(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_OCE_ERR, args) -#define WL_FILS_ERR(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_FILS_ERROR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_OCE_ERR(args) WL_PRINT(args) -#define WL_FILS_ERR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG && EVENT_LOG_COMPILE */ -#else -#define WL_OCE_ERR(args) WL_PRINT(args) -#define WL_FILS_ERR(args) WL_PRINT(args) -#endif /* BCMDBG_ERR */ - -#define WL_PCIE(args) do {if (wl_msg_level2 & WL_PCIE_VAL) WL_PRINT(args);} while (0) -#define WL_PCIE_ON() (wl_msg_level2 & WL_PCIE_VAL) -#define WL_PFN(args) do {if (wl_msg_level & WL_PFN_VAL) WL_PRINT(args);} while (0) -#define WL_PFN_ON() (wl_msg_level & WL_PFN_VAL) -#define WL_PMDUR(args) - -#ifdef WLMSG_BAM -#if defined(EVENT_LOG_COMPILE) -#ifdef USE_EVENT_LOG_RA -#define WL_BAM_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_BAM, args) -#else -#define WL_BAM_ERR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_BAM, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_BAM_ERR(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_BAM_ERR(args) -#endif /* WLMSG_BAM */ -#endif /* BCMDBG */ - -#ifdef BCMDBG_ERR -/* ROM and ROML optimized builds */ -#if defined(EVENT_LOG_COMPILE) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_HE_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_HE_INFO, args) -#define WL_HE_TRACE(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_HE_TRACE, args) -#define WL_HE_WARN(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_HE_WARN, args) -#define WL_HE_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_HE_ERROR, args) -#define WL_TWT_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_TWT_INFO, args) -#define WL_TWT_TRACE(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_TWT_TRACE, args) -#define WL_TWT_WARN(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_TWT_WARN, args) -#define WL_TWT_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_TWT_ERROR, args) -#define WL_HEB_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_HEB_ERROR, args) -#define WL_HEB_TRACE(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_HEB_TRACE, args) -#else -#define WL_HE_INFO(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_HE_INFO, args) -#define WL_HE_TRACE(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_HE_TRACE, args) -#define WL_HE_WARN(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_HE_WARN, args) -#define WL_HE_ERR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_HE_ERROR, args) -#define WL_TWT_INFO(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_TWT_INFO, args) -#define WL_TWT_TRACE(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_TWT_TRACE, args) -#define WL_TWT_WARN(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_TWT_WARN, args) -#define WL_TWT_ERR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_TWT_ERROR, args) -#define WL_HEB_ERR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_HEB_ERROR, args) -#define WL_HEB_TRACE(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_HEB_TRACE, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_HE_INFO(args) WL_PRINT(args) -#define WL_HE_TRACE(args) WL_PRINT(args) -#define WL_HE_WARN(args) WL_PRINT(args) -#define WL_HE_ERR(args) WL_PRINT(args) -#define WL_TWT_INFO(args) WL_PRINT(args) -#define WL_TWT_TRACE(args) WL_PRINT(args) -#define WL_TWT_WARN(args) WL_PRINT(args) -#define WL_TWT_ERR(args) WL_PRINT(args) -#define WL_HEB_ERR(args) WL_PRINT(args) -#define WL_HEB_TRACE(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define WL_HE_INFO(args) -#define WL_HE_TRACE(args) -#define WL_HE_WARN(args) -#define WL_HE_ERR(args) -#define WL_TWT_INFO(args) -#define WL_TWT_TRACE(args) -#define WL_TWT_WARN(args) -#define WL_TWT_ERR(args) -#define WL_HEB_ERR(args) -#define WL_HEB_TRACE(args) -#endif /* BCMDBG_ERR */ - -#ifdef WLMSG_TPA -#ifdef EVENT_LOG_COMPILE -#ifdef USE_EVENT_LOG_RA -#define WL_TPA_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_TPA_ERR, args) -#define WL_TPA_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_TPA_INFO, args) -#else -#define WL_TPA_ERR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_TPA_ERR, args) -#define WL_TPA_INFO(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_TPA_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_TPA_ERR(args) WL_PRINT(args) -#define WL_TPA_INFO(args) WL_INFORM(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#ifndef WL_TPA_ERR -#define WL_TPA_ERR(args) -#endif /* WL_TPA_ERR */ -#ifndef WL_TPA_INFO -#define WL_TPA_INFO(args) -#endif /* WL_TPA_INFO */ -#endif /* WLMSG_TPA */ - -#ifdef WLMSG_WNM_BSSTRANS -#if defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_BSSTRANS_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_WNM_BSSTRANS_INFO, args) -#else -#define WL_BSSTRANS_INFO(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WNM_BSSTRANS_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_BSSTRANS_INFO(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_BSSTRANS_INFO(args) -#endif /* WLMSG_WNM_BSSTRANS */ - -#ifdef BCMDBG_ERR -#if defined(EVENT_LOG_COMPILE) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_BSSTRANS_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_WNM_BSSTRANS_ERR, args) -#else -#define WL_BSSTRANS_ERR(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WNM_BSSTRANS_ERR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_BSSTRANS_ERR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define WL_BSSTRANS_ERR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ - -#if defined(BCMDBG) || defined(BCMDBG_ERR) -#define DBGERRONLY(x) x -#else -#define DBGERRONLY(x) -#endif - -#ifdef EVENT_LOG_COMPILE -#ifdef USE_EVENT_LOG_RA -#define WL_ADPS_ELOG(args) EVENT_LOG_RA(EVENT_LOG_TAG_ADPS, args) -#define WL_ADPS_ELOG_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_ADPS_INFO, args) -#else -#define WL_ADPS_ELOG(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_ADPS, args) -#define WL_ADPS_ELOG_INFO(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_ADPS_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_ADPS_ELOG(args) WL_ADPS(args) -#define WL_ADPS_ELOG_INFO(args) WL_ADPS(args) -#endif /* EVENT_LOG_COMPILE */ - -#ifdef WLMSG_RRM -#if defined(EVENT_LOG_COMPILE) && defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_RRM_DBG(args) EVENT_LOG_RA(EVENT_LOG_TAG_RRM_DBG, args) -#define WL_RRM_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_RRM_INFO, args) -#else -#define WL_RRM_DBG(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_RRM_DBG, args) -#define WL_RRM_INFO(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_RRM_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_RRM_DBG(args) WL_PRINT(args) -#define WL_RRM_INFO(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_RRM_DBG(args) -#define WL_RRM_INFO(args) -#endif /* WLMSG_RRM */ - -#ifdef BCMDBG_ERR -#if defined(EVENT_LOG_COMPILE) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_RRM_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_RRM_ERR, args) -#else -#define WL_RRM_ERR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_RRM_ERR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_RRM_ERR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define WL_RRM_ERR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ - -#ifdef WLMSG_ESP -#if defined(EVENT_LOG_COMPILE) && defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_ESP_DBG(args) EVENT_LOG_RA(EVENT_LOG_TAG_ESP_DBG, args) -#define WL_ESP_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_ESP_INFO, args) -#else -#define WL_ESP_DBG(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_ESP_DBG, args) -#define WL_ESP_INFO(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_ESP_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_ESP_DBG(args) WL_PRINT(args) -#define WL_ESP_INFO(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_ESP_DBG(args) -#define WL_ESP_INFO(args) -#endif /* WLMSG_ESP */ - -#ifdef BCMDBG_ERR -#if defined(EVENT_LOG_COMPILE) && defined(ERR_USE_EVENT_LOG) -#if defined(ERR_USE_EVENT_LOG_RA) -#define WL_ESP_ERR(args) EVENT_LOG_RA(EVENT_LOG_TAG_ESP_ERR, args) -#else -#define WL_ESP_ERR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_ESP_ERR, args) -#endif /* ERR_USE_EVENT_LOG_RA */ -#else -#define WL_ESP_ERR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ -#else -#define WL_ESP_ERR(args) WL_PRINT(args) -#endif /* ERR_USE_EVENT_LOG */ - -#ifndef WL_ASSOC_DP -#define WL_ASSOC_DP(args) WL_ASSOC(args) -#endif - -#ifndef WL_ROAM_DP -#define WL_ROAM_DP(args) WL_ROAM(args) -#endif - -#ifndef WL_PS_DP -#define WL_PS_DP(args) WL_PS(args) -#endif - -#ifndef WL_WSEC_DP -#define WL_WSEC_DP(args) WL_WSEC(args) -#endif - -#ifdef EVENT_LOG_COMPILE -#ifdef USE_EVENT_LOG_RA -#define WL_EVT_NOTIF_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_EVT_NOTIF_INFO, args) -#else -#define WL_EVT_NOTIF_INFO(args) \ - EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_EVT_NOTIF_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_EVT_NOTIF_INFO(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ - -#ifdef BCMDBG_ERR -#if defined(EVENT_LOG_COMPILE) -#if defined(USE_EVENT_LOG_RA) -#define WL_PKTFLTR_CNT(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_PS_LOG, args) -#else -#define WL_PKTFLTR_CNT(args) EVENT_LOG_FAST_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_PS_LOG, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_PKTFLTR_CNT(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ -#else -#define WL_PKTFLTR_CNT(args) -#endif /* BCMDBG_ERR */ -#ifdef EVENT_LOG_COMPILE - -#ifdef USE_EVENT_LOG_RA -#define WL_TDLS_INFO(args) EVENT_LOG_RA(EVENT_LOG_TAG_WL_TDLS_INFO, args) -#else -#define WL_TDLS_INFO(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_TDLS_INFO, args) -#endif /* USE_EVENT_LOG_RA */ -#else -#define WL_TDLS_INFO(args) WL_PRINT(args) -#endif /* EVENT_LOG_COMPILE */ - -#ifndef WL_OCE_INFO -#define WL_OCE_INFO(args) -#endif - -#ifndef WL_OCE_ERR -#define WL_OCE_ERR(args) -#endif - -#ifndef WL_MBO_INFO -#define WL_MBO_INFO(args) -#endif - -#ifndef WL_FILS_ERR -#define WL_FILS_ERR(args) -#endif - -#ifndef WL_FILS_DBG -#define WL_FILS_DBG(args) -#endif - -#ifndef WL_FILS_INFO -#define WL_FILS_INFO(args) -#endif - -/* =============================================================== - * ====define BCMDBG_RATESET/WL_RATESET_ON()/WL_RATESET_PRT(x)==== - * =============================================================== - */ -/* 1. #define BCMDBG_RATESET explicitly turns on WL_RATESET_ON() */ -#ifdef BCMDBG_RATESET -#define WL_RATESET_ON() 1 -#define WL_RATESET_PRT(x) WL_PRINT(x) -#endif -/* 2. #define BCMDBG implicitly turns on BCMDBG_RATESET but not WL_RATESET_ON() */ -#ifdef BCMDBG -#ifndef BCMDBG_RATESET -#define BCMDBG_RATESET -#endif -#endif /* BCMDBG */ -/* 3. default WL_RATESET_ON() is 0 */ -#ifndef WL_RATESET_ON -#define WL_RATESET_ON() 0 -#endif -/* 4. default WL_RATESET_PRT(x) is WL_RATE(x) */ -#ifndef WL_RATESET_PRT -#define WL_RATESET_PRT(x) WL_RATE(x) -#endif - -#endif /* _wl_dbg_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c old mode 100755 new mode 100644 index 3311f4c9b1ae..0a7aea9148ba --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ + #if defined(WL_ESCAN) #include #include @@ -19,6 +19,12 @@ printf("[%s] ESCAN-TRACE) %s : " arg1, name, __func__, ## args); \ } \ } while (0) +#define ESCAN_INFO(name, arg1, args...) \ + do { \ + if (android_msg_level & ANDROID_INFO_LEVEL) { \ + printf("[%s] ESCAN-INFO) %s : " arg1, name, __func__, ## args); \ + } \ + } while (0) #define ESCAN_SCAN(name, arg1, args...) \ do { \ if (android_msg_level & ANDROID_SCAN_LEVEL) { \ @@ -41,11 +47,15 @@ #define dtohchanspec(i) (i) #define WL_EXTRA_BUF_MAX 2048 -#define wl_escan_get_buf(a) ((wl_scan_results_t *) (a)->escan_buf) +#ifdef WL_6G_BAND +#define CHSPEC_IS_6G_PSC(chspec) (CHSPEC_IS6G(chspec) && ((wf_chspec_ctlchan(chspec) % 16) == 5)) +#endif /* WL_6G_BAND */ + +#define wl_escan_get_buf(a) ((wl_scan_results_v109_t *) (a)->escan_buf) #if defined(WL_WIRELESS_EXT) extern int wl_iw_handle_scanresults_ies(char **event_p, char *end, - struct iw_request_info *info, wl_bss_info_t *bi); + struct iw_request_info *info, wl_bss_info_v109_t *bi); #define for_each_bss_wext(list, bss, __i) \ for (__i = 0; __i < list->count && __i < IW_MAX_AP; __i++, bss = next_bss(list, bss)) #endif @@ -205,7 +215,7 @@ wl_ch_host_to_driver(int ioctl_ver, u16 channel) return wl_chspec_host_to_driver(ioctl_ver, chanspec); } -static inline struct wl_bss_info *next_bss(wl_scan_results_t *list, +static inline struct wl_bss_info *next_bss(wl_scan_results_v109_t *list, struct wl_bss_info *bss) { return bss = bss ? @@ -216,7 +226,7 @@ static inline struct wl_bss_info *next_bss(wl_scan_results_t *list, #ifndef BSSCACHE static void wl_escan_dump_bss(struct net_device *dev, struct wl_escan_info *escan, - wl_bss_info_t *bi) + wl_bss_info_v109_t *bi) { int16 rssi; int channel; @@ -232,8 +242,8 @@ wl_escan_dump_bss(struct net_device *dev, struct wl_escan_info *escan, #endif chanspec = wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec); channel = wf_chspec_ctlchan(chanspec); - ESCAN_SCAN(dev->name, "BSSID %pM, channel %3d(%3d %sMHz), rssi %3d, SSID \"%s\"\n", - &bi->BSSID, channel, CHSPEC_CHANNEL(chanspec), + ESCAN_SCAN(dev->name, "BSSID %pM, channel %s-%-3d(%3d %sMHz), rssi %3d, SSID \"%s\"\n", + &bi->BSSID, CHSPEC2BANDSTR(chanspec), channel, CHSPEC_CHANNEL(chanspec), CHSPEC_IS20(chanspec)?"20": CHSPEC_IS40(chanspec)?"40": CHSPEC_IS80(chanspec)?"80":"160", @@ -244,9 +254,9 @@ wl_escan_dump_bss(struct net_device *dev, struct wl_escan_info *escan, static s32 wl_escan_inform_bss(struct net_device *dev, struct wl_escan_info *escan) { - wl_scan_results_t *bss_list; + wl_scan_results_v109_t *bss_list; #ifndef BSSCACHE - wl_bss_info_t *bi = NULL; /* must be initialized */ + wl_bss_info_v109_t *bi = NULL; /* must be initialized */ s32 i; #endif s32 err = 0; @@ -283,14 +293,14 @@ wl_escan_inform_bss(struct net_device *dev, struct wl_escan_info *escan) wl_reset_bss_cache(&escan->g_bss_cache_ctrl); if (escan->autochannel) wl_ext_get_best_channel(dev, &escan->g_bss_cache_ctrl, - escan->ioctl_ver, &escan->best_2g_ch, &escan->best_5g_ch, &escan->best_6g_ch); + &escan->best_2g_ch, &escan->best_5g_ch, &escan->best_6g_ch); #else bi = next_bss(bss_list, bi); for_each_bss(bss_list, bi, i) { wl_escan_dump_bss(dev, escan, bi); } if (escan->autochannel) - wl_ext_get_best_channel(dev, bss_list, escan->ioctl_ver, + wl_ext_get_best_channel(dev, bss_list, &escan->best_2g_ch, &escan->best_5g_ch, &escan->best_6g_ch); #endif @@ -298,19 +308,19 @@ wl_escan_inform_bss(struct net_device *dev, struct wl_escan_info *escan) } #endif /* ESCAN_RESULT_PATCH */ -static wl_scan_params_t * +static wl_scan_params_v1_t * wl_escan_alloc_params(struct net_device *dev, struct wl_escan_info *escan, int channel, int nprobes, int *out_params_size) { - wl_scan_params_t *params; + wl_scan_params_v1_t *params; int params_size; int num_chans; *out_params_size = 0; /* Our scan params only need space for 1 channel and 0 ssids */ - params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16); - params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL); + params_size = WL_SCAN_PARAMS_V1_FIXED_SIZE + 1 * sizeof(uint16); + params = (wl_scan_params_v1_t*) kzalloc(params_size, GFP_KERNEL); if (params == NULL) { ESCAN_ERROR(dev->name, "mem alloc failed (%d bytes)\n", params_size); return params; @@ -343,7 +353,7 @@ wl_escan_alloc_params(struct net_device *dev, struct wl_escan_info *escan, static void wl_escan_abort(struct net_device *dev, struct wl_escan_info *escan) { - wl_scan_params_t *params = NULL; + wl_scan_params_v1_t *params = NULL; s32 params_size = 0; s32 err = BCME_OK; if (!in_atomic()) { @@ -416,7 +426,7 @@ wl_escan_notify_complete(struct net_device *dev, #ifdef ESCAN_BUF_OVERFLOW_MGMT static void wl_escan_find_removal_candidate(struct wl_escan_info *escan, - wl_bss_info_t *bss, removal_element_t *candidate) + wl_bss_info_v109_t *bss, removal_element_t *candidate) { int idx; for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) { @@ -435,17 +445,17 @@ wl_escan_find_removal_candidate(struct wl_escan_info *escan, static void wl_escan_remove_lowRSSI_info(struct net_device *dev, struct wl_escan_info *escan, - wl_scan_results_t *list, removal_element_t *candidate, wl_bss_info_t *bi) + wl_scan_results_v109_t *list, removal_element_t *candidate, wl_bss_info_v109_t *bi) { int idx1, idx2; int total_delete_len = 0; for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) { - int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; - wl_bss_info_t *bss = NULL; + int cur_len = WL_SCAN_RESULTS_V109_FIXED_SIZE; + wl_bss_info_v109_t *bss = NULL; if (candidate[idx1].RSSI >= bi->RSSI) continue; for (idx2 = 0; idx2 < list->count; idx2++) { - bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) : + bss = bss ? (wl_bss_info_v109_t *)((uintptr)bss + dtoh32(bss->length)) : list->bss_info; if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) && candidate[idx1].RSSI == bss->RSSI && @@ -478,16 +488,16 @@ wl_escan_ext_handler(struct net_device *dev, void *argu, { struct wl_escan_info *escan = (struct wl_escan_info *)argu; s32 status = ntoh32(e->status); - wl_bss_info_t *bi; - wl_escan_result_t *escan_result; - wl_bss_info_t *bss = NULL; - wl_scan_results_t *list; + wl_bss_info_v109_t *bi; + wl_escan_result_v109_t *escan_result; + wl_bss_info_v109_t *bss = NULL; + wl_scan_results_v109_t *list; u32 bi_length; u32 i; u16 channel; mutex_lock(&escan->usr_sync); - escan_result = (wl_escan_result_t *)data; + escan_result = (wl_escan_result_v109_t *)data; if (escan->escan_state != ESCAN_STATE_SCANING) { ESCAN_DBG(dev->name, "Not my scan\n"); @@ -514,7 +524,7 @@ wl_escan_ext_handler(struct net_device *dev, void *argu, goto exit; } bi_length = dtoh32(bi->length); - if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { + if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_V109_FIXED_SIZE)) { ESCAN_ERROR(dev->name, "Invalid bss_info length %d: ignoring\n", bi_length); goto exit; @@ -524,12 +534,10 @@ wl_escan_ext_handler(struct net_device *dev, void *argu, channel = bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec)); - if (!dhd_conf_match_channel(escan->pub, channel)) - goto exit; /* ----- terence 20130524: skip invalid bss */ { - int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; + int cur_len = WL_SCAN_RESULTS_V109_FIXED_SIZE; #ifdef ESCAN_BUF_OVERFLOW_MGMT removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT]; int remove_lower_rssi = FALSE; @@ -546,7 +554,7 @@ wl_escan_ext_handler(struct net_device *dev, void *argu, ESCAN_DBG(dev->name, "%s(%pM) RSSI %d flags 0x%x length %d\n", bi->SSID, &bi->BSSID, bi->RSSI, bi->flags, bi->length); for (i = 0; i < list->count; i++) { - bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) + bss = bss ? (wl_bss_info_v109_t *)((uintptr)bss + dtoh32(bss->length)) : list->bss_info; #ifdef ESCAN_BUF_OVERFLOW_MGMT ESCAN_DBG(dev->name, @@ -690,16 +698,15 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan, wl_uint32_list_t *list, void *scan_params, wl_scan_info_t *scan_info) { int err = 0; - wl_scan_results_t *results; + wl_scan_results_v109_t *results; char *ptr; int i = 0, j = 0; wlc_ssid_t ssid_tmp; u32 n_channels = 0; chanspec_t chanspec; u32 n_ssids = 0; - wl_scan_params_t *params = NULL; + wl_scan_params_v1_t *params = NULL; wl_scan_params_v2_t *params_v2 = NULL; - u32 scan_param_size = 0; u32 channel_offset = 0; u32 cur_offset; uint16 *chan_list = NULL; @@ -707,7 +714,7 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan, results = wl_escan_get_buf(escan); results->version = 0; results->count = 0; - results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; + results->buflen = WL_SCAN_RESULTS_V109_FIXED_SIZE; escan->escan_state = ESCAN_STATE_SCANING; /* Arm scan timeout timer */ @@ -715,12 +722,10 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan, if (escan->scan_params_v2) { params_v2 = (wl_scan_params_v2_t *)scan_params; - scan_param_size = sizeof(wl_scan_params_v2_t); channel_offset = offsetof(wl_scan_params_v2_t, channel_list); } else { - params = (wl_scan_params_t *)scan_params; - scan_param_size = sizeof(wl_scan_params_t); - channel_offset = offsetof(wl_scan_params_t, channel_list); + params = (wl_scan_params_v1_t *)scan_params; + channel_offset = offsetof(wl_scan_params_v1_t, channel_list); } if (params_v2) { @@ -770,8 +775,8 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan, continue; } chan_list[j] = chanspec; - ESCAN_SCAN(dev->name, "Chan : %d, Channel spec: %x\n", - CHSPEC_CHANNEL(chanspec), chanspec); + ESCAN_SCAN(dev->name, "chan : %s-%d, chanspec: %x\n", + CHSPEC2BANDSTR(chanspec), wf_chspec_ctlchan(chanspec), chanspec); chan_list[j] = wl_chspec_host_to_driver(escan->ioctl_ver, chan_list[j]); j++; @@ -843,7 +848,7 @@ wl_escan_timeout(unsigned long data) { wl_event_msg_t msg; struct wl_escan_info *escan = (struct wl_escan_info *)data; - wl_scan_results_t *bss_list; + wl_scan_results_v109_t *bss_list; struct wl_bss_info *bi = NULL; s32 i; u32 channel; @@ -883,14 +888,12 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info) struct dhd_pub *dhdp = dhd_get_pub(dev); struct wl_escan_info *escan = dhdp->escan; s32 err = BCME_OK; - wl_escan_params_t *eparams = NULL; + wl_escan_params_v1_t *eparams = NULL; wl_escan_params_v2_t *eparams_v2 = NULL; - u8 *scan_params = NULL; + u8 *scan_params = NULL, *params = NULL; s32 params_size; - wl_escan_params_t *params = NULL; u32 n_channels = 0; - wl_uint32_list_t *list; - u8 valid_chan_list[sizeof(u32)*(MAX_CTRL_CHANSPECS + 1)]; + wl_uint32_list_t *list = NULL; mutex_lock(&escan->usr_sync); if (escan->escan_state == ESCAN_STATE_DOWN) { @@ -918,18 +921,22 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info) params_size = (WL_SCAN_PARAMS_V2_FIXED_SIZE + OFFSETOF(wl_escan_params_v2_t, params)); } else { - params_size = (WL_SCAN_PARAMS_FIXED_SIZE + - OFFSETOF(wl_escan_params_t, params)); + params_size = (WL_SCAN_PARAMS_V1_FIXED_SIZE + + OFFSETOF(wl_escan_params_v1_t, params)); } /* if scan request is not empty parse scan request paramters */ - memset(valid_chan_list, 0, sizeof(valid_chan_list)); - list = (wl_uint32_list_t *)(void *) valid_chan_list; + list = kzalloc(sizeof(u32)*(MAX_CTRL_CHANSPECS + 1), GFP_KERNEL); + if (list == NULL) { + ESCAN_ERROR(dev->name, "kzalloc failed\n"); + err = -ENOMEM; + goto exit; + } if (scan_info->channels.count) { memcpy(list, &scan_info->channels, sizeof(wl_channel_list_t)); } else { - err = wl_construct_ctl_chanspec_list(dev, list); + err = wl_construct_ctl_chanspec_list(dev, list, FALSE); if (err != 0) { ESCAN_ERROR(dev->name, "get channels failed with %d\n", err); goto exit; @@ -937,7 +944,7 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info) } n_channels = list->count; - /* Allocate space for populating ssids in wl_escan_params_t struct */ + /* Allocate space for populating ssids in wl_escan_params_v1_t struct */ if (list->count % 2) /* If n_channels is odd, add a padd of u16 */ params_size += sizeof(u16) * (n_channels + 1); @@ -947,7 +954,7 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info) params_size += sizeof(struct wlc_ssid) * 2; } - params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL); + params = kzalloc(params_size, GFP_KERNEL); if (params == NULL) { ESCAN_ERROR(dev->name, "kzalloc failed\n"); err = -ENOMEM; @@ -959,13 +966,14 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info) scan_params = (u8 *)&eparams_v2->params; eparams_v2->version = htod32(ESCAN_REQ_VERSION_V2); eparams_v2->action = htod16(WL_SCAN_ACTION_START); + wl_escan_set_sync_id(eparams_v2->sync_id); } else { - eparams = (wl_escan_params_t *)params; + eparams = (wl_escan_params_v1_t *)params; scan_params = (u8 *)&eparams->params; - eparams->version = htod32(ESCAN_REQ_VERSION); + eparams->version = htod32(ESCAN_REQ_VERSION_V1); eparams->action = htod16(WL_SCAN_ACTION_START); + wl_escan_set_sync_id(eparams->sync_id); } - wl_escan_set_sync_id(params->sync_id); wl_escan_prep(dev, escan, list, scan_params, scan_info); @@ -986,6 +994,8 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info) } kfree(params); exit: + if (list) + kfree(list); if (unlikely(err)) { wl_escan_reset(escan); } @@ -994,6 +1004,156 @@ exit2: return err; } +#ifdef WL_SOFTAP_ACS +static void +wl_construct_acs_list(struct net_device *net, uint32 band, wl_scan_info_t *scan_info) +{ + int i, cnt = 0; +#ifdef WL_6G_BAND + chanspec_t chanspec; +#endif /* WL_6G_BAND */ + + if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) { + for (i=0; i<13; i++) { + scan_info->channels.chanspec[i+cnt] = wf_create_chspec_from_primary(i+1, + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G); + } + cnt += 13; + } + if (band == WLC_BAND_5G || band == WLC_BAND_AUTO) { + for (i=0; i<4; i++) { + scan_info->channels.chanspec[i+cnt] = wf_create_chspec_from_primary(36+i*4, + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G); + } + cnt += 4; + for (i=0; i<4; i++) { + scan_info->channels.chanspec[i+cnt] = wf_create_chspec_from_primary(149+i*4, + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G); + } + cnt += 4; + } +#ifdef WL_6G_BAND + if (band == WLC_BAND_6G) { + for (i=0; i<59; i++) { + chanspec = wf_create_chspec_from_primary(1+i*4, + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_6G); + if (CHSPEC_IS_6G_PSC(chanspec)) { + scan_info->channels.chanspec[i+cnt] = chanspec; + cnt++; + } + } + } +#endif /* WL_6G_BAND */ + scan_info->channels.count = cnt; + + return; +} + +int +wl_escan_drv_acs_scan(struct net_device *dev, uint32 band, + wl_scan_info_t *scan_info) +{ + int retry = 0, retry_max, retry_interval = 250, up = 1, ret = -1; + bool free_scan_info = FALSE; + + if (!scan_info) { + scan_info = kzalloc(sizeof(wl_scan_info_t), GFP_KERNEL); + if (scan_info == NULL) { + ESCAN_ERROR(dev->name, "kzalloc failed\n"); + ret = -ENOMEM; + goto exit; + } + free_scan_info = TRUE; + wl_construct_acs_list(dev, band, scan_info); + } + + retry_max = WL_ESCAN_TIMER_INTERVAL_MS/retry_interval; + ret = wldev_ioctl_get(dev, WLC_GET_UP, &up, sizeof(s32)); + if (ret < 0 || up == 0) { + ret = wldev_ioctl_set(dev, WLC_UP, &up, sizeof(s32)); + } + scan_info->bcast_ssid = TRUE; + retry = retry_max; + while (retry--) { + ret = wl_escan_set_scan(dev, scan_info); + if (!ret) + break; + OSL_SLEEP(retry_interval); + } + if (retry == 0) { + ESCAN_ERROR(dev->name, "scan retry failed %d\n", retry_max); + ret = -1; + } + +exit: + if (free_scan_info && scan_info) + kfree(scan_info); + + return ret; +} + +static int +wl_escan_get_drv_apcs(struct net_device *dev, uint32 band) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); + struct wl_escan_info *escan = dhd->escan; + int retry = 0, retry_max, retry_interval = 250, chanspec = 0; + + retry_max = WL_ESCAN_TIMER_INTERVAL_MS/retry_interval; + retry = retry_max; + while (retry--) { + if (escan->escan_state == ESCAN_STATE_IDLE) { + if (band == WLC_BAND_5G || band == WLC_BAND_AUTO) { + chanspec = wf_create_chspec_from_primary( + wf_chspec_primary20_chan(escan->best_5g_ch), + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G); + } +#ifdef WL_6G_BAND + else if (band == WLC_BAND_6G) { + chanspec = wf_create_chspec_from_primary( + wf_chspec_primary20_chan(escan->best_6g_ch), + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_6G); + } +#endif /* WL_6G_BAND */ + else { + chanspec = wf_create_chspec_from_primary( + wf_chspec_primary20_chan(escan->best_2g_ch), + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G); + } + WL_MSG(dev->name, "selected channel = %d(0x%x)\n", + wf_chspec_ctlchan(chanspec), chanspec); + goto exit; + } + ESCAN_INFO(dev->name, "escan_state=%d, %d tried\n", + escan->escan_state, (retry_max - retry)); + OSL_SLEEP(retry_interval); + } + +exit: + return chanspec; +} + +int +wl_escan_drv_apcs(struct net_device *dev, uint32 band, wl_scan_info_t *scan_info) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); + struct wl_escan_info *escan = dhd->escan; + int ret = 0, chanspec = 0; + + WL_MSG(dev->name, "ACS_SCAN\n"); + escan->autochannel = 1; + + ret = wl_escan_drv_acs_scan(dev, band, scan_info); + if (ret < 0) + goto exit; + chanspec = wl_escan_get_drv_apcs(dev, band); + +exit: + escan->autochannel = 0; + return chanspec; +} +#endif /* WL_SOFTAP_ACS */ + #if defined(WL_WIRELESS_EXT) static int rssi_to_qual(int rssi) @@ -1014,7 +1174,7 @@ rssi_to_qual(int rssi) static int wl_escan_merge_scan_results(struct net_device *dev, struct wl_escan_info *escan, - struct iw_request_info *info, char *extra, wl_bss_info_t *bi, int *len, int max_size) + struct iw_request_info *info, char *extra, wl_bss_info_v109_t *bi, int *len, int max_size) { s32 err = BCME_OK; struct iw_event iwe; @@ -1137,8 +1297,8 @@ wl_escan_merge_scan_list(struct net_device *dev, u8 *cur_bssid, s32 err = BCME_OK; int i = 0, cnt = 0; int len_prep = 0; - wl_bss_info_t *bi = NULL; - wl_scan_results_t *bss_list; + wl_bss_info_v109_t *bi = NULL; + wl_scan_results_v109_t *bss_list; __u16 buflen_from_user = dwrq->length; bss_list = escan->bss_list; @@ -1174,8 +1334,8 @@ wl_escan_merge_cache_list(struct net_device *dev, u8 *cur_bssid, s32 err = BCME_OK; int i = 0, cnt = 0; int len_prep = 0; - wl_bss_info_t *bi = NULL; - wl_scan_results_t *bss_list; + wl_bss_info_v109_t *bi = NULL; + wl_scan_results_v109_t *bss_list; __u16 buflen_from_user = dwrq->length; wl_bss_cache_t *node; @@ -1219,7 +1379,7 @@ wl_escan_get_scan(struct net_device *dev, int cache_cnt = 0; #endif int len_prep = 0, len_ret = 0; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; __u16 buflen_from_user = dwrq->length; char *buf = NULL; struct ether_addr cur_bssid; @@ -1376,8 +1536,8 @@ wl_escan_mesh_info(struct net_device *dev, struct wl_escan_info *escan, struct ether_addr *peer_bssid, struct wl_mesh_params *mesh_info) { int i = 0; - wl_bss_info_t *bi = NULL; - wl_scan_results_t *bss_list; + wl_bss_info_v109_t *bi = NULL; + wl_scan_results_v109_t *bss_list; int16 bi_rssi, bi_chan; wlc_ssid_t bi_meshid; bool is_mesh_peer = FALSE, found = FALSE; @@ -1448,8 +1608,8 @@ wl_escan_mesh_peer(struct net_device *dev, struct wl_escan_info *escan, struct wl_mesh_params *mesh_info) { int i = 0; - wl_bss_info_t *bi = NULL; - wl_scan_results_t *bss_list; + wl_bss_info_v109_t *bi = NULL; + wl_scan_results_v109_t *bss_list; int16 bi_rssi, bi_chan, max_rssi = -100; uint min_hop_cnt = 255; wlc_ssid_t bi_meshid; @@ -1630,7 +1790,7 @@ wl_escan_up(struct net_device *dev) } if ((ret = wldev_iovar_getbuf(dev, "scan_ver", NULL, 0, - ioctl_buf, sizeof(ioctl_buf), NULL)) == BCME_OK) { + ioctl_buf, sizeof(ioctl_buf), NULL)) == BCME_OK) { ESCAN_TRACE(dev->name, "scan_params v2\n"); /* use scan_params ver2 */ escan->scan_params_v2 = true; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h old mode 100755 new mode 100644 index c77660d06f3e..5670681106bc --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h @@ -1,90 +1,86 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _wl_escan_ -#define _wl_escan_ -#include -#if defined(WL_WIRELESS_EXT) -#include + +#ifndef _wl_escan_ +#define _wl_escan_ +#include +#if defined(WL_WIRELESS_EXT) +#include #endif /* WL_WIRELESS_EXT */ #include -#include +#include #include - -#define ESCAN_BUF_SIZE (64 * 1024) - -#define WL_ESCAN_TIMER_INTERVAL_MS 10000 /* Scan timeout */ - -/* donlge escan state */ -enum escan_state { - ESCAN_STATE_DOWN, - ESCAN_STATE_IDLE, - ESCAN_STATE_SCANING -}; - -typedef struct wl_scan_info { - bool bcast_ssid; - wlc_ssid_t ssid; - wl_channel_list_t channels; - int scan_time; -} wl_scan_info_t; -typedef struct wl_escan_info { - struct net_device *dev; +#define ESCAN_BUF_SIZE (64 * 1024) + +#define WL_ESCAN_TIMER_INTERVAL_MS 10000 /* Scan timeout */ + +/* donlge escan state */ +enum escan_state { + ESCAN_STATE_DOWN, + ESCAN_STATE_IDLE, + ESCAN_STATE_SCANING +}; + +typedef struct wl_escan_info { + struct net_device *dev; bool scan_params_v2; - dhd_pub_t *pub; + dhd_pub_t *pub; timer_list_compat_t scan_timeout; /* Timer for catch scan event timeout */ - int escan_state; - int ioctl_ver; - u8 escan_buf[ESCAN_BUF_SIZE]; - wl_scan_results_t *bss_list; - u8 *escan_ioctl_buf; + int escan_state; + int ioctl_ver; + u8 escan_buf[ESCAN_BUF_SIZE]; + wl_scan_results_v109_t *bss_list; + u8 *escan_ioctl_buf; struct mutex usr_sync; /* maily for up/down synchronization */ - int autochannel; - int best_2g_ch; - int best_5g_ch; - int best_6g_ch; -#if defined(RSSIAVG) - wl_rssi_cache_ctrl_t g_rssi_cache_ctrl; - wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl; -#endif -#if defined(BSSCACHE) - wl_bss_cache_ctrl_t g_bss_cache_ctrl; -#endif -} wl_escan_info_t; - -#if defined(WLMESH) -enum mesh_info_id { - MESH_INFO_MASTER_BSSID = 1, - MESH_INFO_MASTER_CHANNEL, - MESH_INFO_HOP_CNT, - MESH_INFO_PEER_BSSID -}; - + int autochannel; + int best_2g_ch; + int best_5g_ch; + int best_6g_ch; +#if defined(RSSIAVG) + wl_rssi_cache_ctrl_t g_rssi_cache_ctrl; + wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl; +#endif +#if defined(BSSCACHE) + wl_bss_cache_ctrl_t g_bss_cache_ctrl; +#endif +} wl_escan_info_t; + +#if defined(WLMESH) +enum mesh_info_id { + MESH_INFO_MASTER_BSSID = 1, + MESH_INFO_MASTER_CHANNEL, + MESH_INFO_HOP_CNT, + MESH_INFO_PEER_BSSID +}; + #define MAX_HOP_LIST 10 -typedef struct wl_mesh_params { - struct ether_addr master_bssid; - uint16 master_channel; - uint hop_cnt; +typedef struct wl_mesh_params { + struct ether_addr master_bssid; + uint16 master_channel; + uint hop_cnt; struct ether_addr peer_bssid[MAX_HOP_LIST]; - uint32 scan_channel; -} wl_mesh_params_t; + uint32 scan_channel; +} wl_mesh_params_t; bool wl_escan_mesh_info(struct net_device *dev, - struct wl_escan_info *escan, struct ether_addr *peer_bssid, - struct wl_mesh_params *mesh_info); + struct wl_escan_info *escan, struct ether_addr *peer_bssid, + struct wl_mesh_params *mesh_info); bool wl_escan_mesh_peer(struct net_device *dev, - struct wl_escan_info *escan, wlc_ssid_t *cur_ssid, uint16 cur_chan, bool sae, - struct wl_mesh_params *mesh_info); -#endif /* WLMESH */ - + struct wl_escan_info *escan, wlc_ssid_t *cur_ssid, uint16 cur_chan, bool sae, + struct wl_mesh_params *mesh_info); +#endif /* WLMESH */ +int wl_escan_drv_acs_scan(struct net_device *dev, uint32 band, + wl_scan_info_t *scan_info); +int wl_escan_drv_apcs(struct net_device *dev, uint32 band, wl_scan_info_t *scan_info); int wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info); -#if defined(WL_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) int wl_escan_get_scan(struct net_device *dev, - struct iw_request_info *info, struct iw_point *dwrq, char *extra); -#endif + struct iw_request_info *info, struct iw_point *dwrq, char *extra); +#endif +int wl_ext_drv_scan(struct net_device *dev, uint32 band, wl_scan_info_t *scan_info); int wl_escan_attach(struct net_device *dev); void wl_escan_detach(struct net_device *dev); int wl_escan_event_attach(struct net_device *dev, int ifidx); int wl_escan_event_dettach(struct net_device *dev, int ifidx); int wl_escan_up(struct net_device *dev); void wl_escan_down(struct net_device *dev); - -#endif /* _wl_escan_ */ + +#endif /* _wl_escan_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_event.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_event.c old mode 100755 new mode 100644 index a89f3cdba775..2d2a999d84af --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_event.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_event.c @@ -2,6 +2,7 @@ #include #ifdef WL_EVENT #include +#include #define EVENT_ERROR(name, arg1, args...) \ do { \ @@ -311,7 +312,8 @@ wl_ext_event_create_handler(struct wl_event_params *event_params) #else /* Allocate workqueue for event */ if (!event_params->event_workq) { - event_params->event_workq = alloc_workqueue("ext_eventd", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + event_params->event_workq = alloc_workqueue("ext_eventd", + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 0); } if (!event_params->event_workq) { @@ -385,6 +387,7 @@ wl_ext_event_register(struct net_device *dev, dhd_pub_t *dhd, uint32 event, mutex_unlock(&event_params->event_sync); return -ENOMEM; } + memset(leaf, 0, sizeof(event_handler_list_t)); leaf->next = NULL; leaf->dev = dev; leaf->etype = event; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_event.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_event.h old mode 100755 new mode 100644 diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_export.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_export.h deleted file mode 100755 index 1575d88b17d5..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_export.h +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Required functions exported by the port-specific (os-dependent) driver - * to common (os-independent) driver code. - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - */ - -#ifndef _wl_export_h_ -#define _wl_export_h_ - -/* misc callbacks */ -struct wl_info; -struct wl_if; -struct wlc_if; -struct wlc_event; -struct wlc_info; -struct wl_timer; -struct wl_rxsts; -struct wl_txsts; -struct reorder_rxcpl_id_list; - -/** wl_init() is called upon fault ('big hammer') conditions and as part of a 'wlc up' */ -extern void wl_init(struct wl_info *wl); -extern uint wl_reset(struct wl_info *wl); -extern void wl_intrson(struct wl_info *wl); -extern void wl_intrsoff(struct wl_info *wl, bcm_int_bitmask_t *curr_mask); -extern void wl_intrsrestore(struct wl_info *wl, bcm_int_bitmask_t *macintmask); -extern int wl_up(struct wl_info *wl); -extern void wl_down(struct wl_info *wl); -extern void wl_dump_ver(struct wl_info *wl, struct bcmstrbuf *b); -extern void wl_txflowcontrol(struct wl_info *wl, struct wl_if *wlif, bool state, int prio); -extern void wl_set_copycount_bytes(struct wl_info *wl, uint16 copycount, - uint16 d11rxoffset); -extern int wl_bus_pcie_config_access(struct wl_info *wl, uint32 configaddr, uint32 *configdata, - bool read); - -extern bool wl_alloc_dma_resources(struct wl_info *wl, uint dmaddrwidth); - -#ifdef TKO -extern void * wl_get_tko(struct wl_info *wl, struct wl_if *wlif); -#endif /* TKO */ -#ifdef ICMP -extern void * wl_get_icmp(struct wl_info *wl, struct wl_if *wlif); -#endif /* ICMP */ -/* timer functions */ -extern struct wl_timer *wl_init_timer(struct wl_info *wl, void (*fn)(void* arg), void *arg, - const char *name); -extern void wl_free_timer(struct wl_info *wl, struct wl_timer *timer); -/* Add timer guarantees the callback fn will not be called until AT LEAST ms later. In the - * case of a periodic timer, this guarantee is true of consecutive callback fn invocations. - * As a result, the period may not average ms duration and the callbacks may "drift". - * - * A periodic timer must have a non-zero ms delay. - */ -extern void wl_add_timer(struct wl_info *wl, struct wl_timer *timer, uint ms, int periodic); -extern void wl_add_timer_us(struct wl_info *wl, struct wl_timer *timer, uint us, int periodic); -extern bool wl_del_timer(struct wl_info *wl, struct wl_timer *timer); - -#ifdef WLATF_DONGLE -int wlfc_upd_flr_weight(struct wl_info *wl, uint8 mac_handle, uint8 tid, void* params); -int wlfc_enab_fair_fetch_scheduling(struct wl_info *wl, uint32 enab); -int wlfc_get_fair_fetch_scheduling(struct wl_info *wl, uint32 *status); -#endif /* WLATF_DONGLE */ - -#ifdef MONITOR_DNGL_CONV -extern void wl_sendup_monitor(struct wl_info *wl, void *p); -#endif - -/* data receive and interface management functions */ -extern void wl_sendup_fp(struct wl_info *wl, struct wl_if *wlif, void *p); -extern void wl_sendup(struct wl_info *wl, struct wl_if *wlif, void *p, int numpkt); -extern void wl_sendup_event(struct wl_info *wl, struct wl_if *wlif, void *pkt); -extern void wl_event(struct wl_info *wl, char *ifname, struct wlc_event *e); -extern void wl_event_sync(struct wl_info *wl, char *ifname, struct wlc_event *e); -extern void wl_event_sendup(struct wl_info *wl, const struct wlc_event *e, uint8 *data, uint32 len); - -/* interface manipulation functions */ -extern char *wl_ifname(struct wl_info *wl, struct wl_if *wlif); -void wl_set_ifname(struct wl_if *wlif, char *name); -extern struct wl_if *wl_add_if(struct wl_info *wl, struct wlc_if* wlcif, uint unit, - struct ether_addr *remote); -extern void wl_del_if(struct wl_info *wl, struct wl_if *wlif); -/* RSDB specific interface update function */ -void wl_update_wlcif(struct wlc_if *wlcif); -extern void wl_update_if(struct wl_info *from_wl, struct wl_info *to_wl, struct wl_if *from_wlif, - struct wlc_if *to_wlcif); -int wl_find_if(struct wl_if *wlif); -extern int wl_rebind_if(struct wl_if *wlif, int idx, bool rebind); - -/* contexts in wlif structure. Currently following are valid */ -#define IFCTX_ARPI (1) -#define IFCTX_NDI (2) -#define IFCTX_NETDEV (3) -extern void *wl_get_ifctx(struct wl_info *wl, int ctx_id, struct wl_if *wlif); - -/* pcie root complex operations - op == 0: get link capability in configuration space - op == 1: hot reset -*/ -extern int wl_osl_pcie_rc(struct wl_info *wl, uint op, int param); - -/* monitor mode functions */ -#ifndef MONITOR_DNGL_CONV -extern void wl_monitor(struct wl_info *wl, struct wl_rxsts *rxsts, void *p); -#endif -extern void wl_set_monitor(struct wl_info *wl, int val); - -#define wl_sort_bsslist(a, b, c) FALSE - -#if defined(D0_COALESCING) || defined(WLAWDL) -extern void wl_sendup_no_filter(struct wl_info *wl, struct wl_if *wlif, void *p, int numpkt); -#endif - -#ifdef LINUX_CRYPTO -struct wlc_key_info; -extern int wl_tkip_miccheck(struct wl_info *wl, void *p, int hdr_len, bool group_key, int id); -extern int wl_tkip_micadd(struct wl_info *wl, void *p, int hdr_len); -extern int wl_tkip_encrypt(struct wl_info *wl, void *p, int hdr_len); -extern int wl_tkip_decrypt(struct wl_info *wl, void *p, int hdr_len, bool group_key); -extern void wl_tkip_printstats(struct wl_info *wl, bool group_key); -#ifdef BCMINTERNAL -extern int wl_tkip_keydump(struct wl_info *wl, bool group); -#endif /* BCMINTERNAL */ -extern int wl_tkip_keyset(struct wl_info *wl, const struct wlc_key_info *key_info, - const uint8 *key_data, size_t key_len, const uint8 *rx_seq, size_t rx_seq_len); -#endif /* LINUX_CRYPTO */ - -#ifdef DONGLEBUILD -/* XXX 156-byte dongle size savings hack (rte version of routine doesn't use names) */ -#define wl_init_timer(wl, fn, arg, name) wl_init_timer(wl, fn, arg, NULL) -extern int wl_busioctl(struct wl_info *wl, uint32 cmd, void *buf, int len, int *used, - int *needed, int set); -extern void wl_isucodereclaimed(uint8 *value); -extern void wl_reclaim(void); -extern void wl_reclaim_postattach(void); -extern bool wl_dngl_is_ss(struct wl_info *wl); -extern void wl_sendctl_tx(struct wl_info *wl, uint8 type, uint32 op, void *opdata); -extern void wl_flowring_ctl(struct wl_info *wl, uint32 op, void *opdata); -extern void wl_indicate_maccore_state(struct wl_info *wl, uint8 state); -extern void wl_indicate_macwake_state(struct wl_info *wl, uint8 state); -extern void wl_flush_rxreorderqeue_flow(struct wl_info *wl, struct reorder_rxcpl_id_list *list); -extern uint32 wl_chain_rxcomplete_id(struct reorder_rxcpl_id_list *list, uint16 id, bool head); -extern void wl_chain_rxcompletions_amsdu(osl_t *osh, void *p, bool norxcpl); -extern void wl_timesync_add_rx_timestamp(struct wl_info *wl, void *p, - uint32 ts_low, uint32 ts_high); -extern void wl_timesync_add_tx_timestamp(struct wl_info *wl, void *p, - uint32 ts_low, uint32 ts_high); -extern void wl_timesync_get_tx_timestamp(struct wl_info *wl, void *p, - uint32 *ts_low, uint32 *ts_high); - -#define wl_chain_rxcomplete_id_tail(a, b) wl_chain_rxcomplete_id(a, b, FALSE) -#define wl_chain_rxcomplete_id_head(a, b) wl_chain_rxcomplete_id(a, b, TRUE) -extern void wl_inform_additional_buffers(struct wl_info *wl, uint16 buf_cnts); -extern void wl_health_check_notify(struct wl_info *wl, mbool notification, bool state); -extern void wl_health_check_notify_clear_all(struct wl_info *wl); -extern void wl_health_check_log(struct wl_info *wl, uint32 hc_log_type, - uint32 val, uint32 caller); -#ifdef BCMPCIEDEV -extern bool wl_get_hcapistimesync(void); -extern bool wl_get_hcapispkttxs(void); -#endif /* BCMPCIEDEV */ -#else -#define wl_indicate_maccore_state(a, b) do { } while (0) -#define wl_indicate_macwake_state(a, b) do { } while (0) -#define wl_flush_rxreorderqeue_flow(a, b) do { } while (0) -#define wl_chain_rxcomplete_id_tail(a, b) 0 -#define wl_chain_rxcomplete_id_head(a, b) 0 -#define wl_chain_rxcompletions_amsdu(a, b, c) do {} while (0) -#define wl_inform_additional_buffers(a, b) do { } while (0) -#define wl_health_check_notify(a, b, c) do { } while (0) -#define wl_health_check_notify_clear_all(a) do { } while (0) -#define wl_health_check_log(a, b, c, d) do { } while (0) -#define wl_get_hcapistimesync() do { } while (0) -#define wl_get_hcapispkttxs() do { } while (0) -#endif /* DONGLEBUILD */ - -extern int wl_fatal_error(void * wl, int rc); - -#ifdef NEED_HARD_RESET -extern int wl_powercycle(void * wl); -extern bool wl_powercycle_inprogress(void * wl); -#else -#define wl_powercycle(a) -#define wl_powercycle_inprogress(a) (0) -#endif /* NEED_HARD_RESET */ - -void *wl_create_fwdpkt(struct wl_info *wl, void *p, struct wl_if *wlif); - -#ifdef BCMFRWDPOOLREORG -void wl_upd_frwd_resrv_bufcnt(struct wl_info *wl); -#endif /* BCMFRWDPOOLREORG */ -#ifdef BCMFRWDPKT -void wl_prepare_frwd_pkt_rxcmplt(struct wl_info *wl, void *p); -#endif /* BCMFRWDPKT */ - -#ifdef WL_NATOE -void wl_natoe_notify_pktc(struct wl_info *wl, uint8 action); -int wl_natoe_ampdu_config_upd(struct wl_info *wl); -#endif /* WL_NATOE */ - -#ifdef ENABLE_CORECAPTURE -extern int wl_log_system_state(void * wl, const char * reason, bool capture); -#else -#define wl_log_system_state(a, b, c) -#endif - -#define WL_DUMP_MEM_SOCRAM 1 -#define WL_DUMP_MEM_UCM 2 - -extern void wl_dump_mem(char *addr, int len, int type); - -#ifdef HEALTH_CHECK -typedef int (*wl_health_check_fn)(uint8 *buffer, uint16 length, void *context, - int16 *bytes_written); -typedef int (*health_check_event_mask_fn)(void *context, bool get, uint32 *evt_bits); -extern int wl_health_check_evtmask_upd(struct wl_info *wl, int module_id, bool get, - uint32 *evt_mask); - -typedef struct health_check_info health_check_info_t; -typedef struct health_check_client_info health_check_client_info_t; - -/* WL wrapper to health check APIs. */ -extern health_check_client_info_t* wl_health_check_module_register(struct wl_info *wl, - const char* name, wl_health_check_fn fn, health_check_event_mask_fn evt_fn, - void *context, int module_id); - -extern void wl_health_check_execute(void *wl); - -extern int wl_health_check_execute_clients(struct wl_info *wl, - health_check_client_info_t** modules, uint16 num_modules); - -/* Following are not implemented in dongle health check */ -extern int wl_health_check_deinit(struct wl_info *wl); -extern int wl_health_check_module_unregister(struct wl_info *wl, - health_check_client_info_t *client); -#endif /* HEALTH_CHECK */ - -#ifdef ECOUNTERS -#define WL_ECOUNTERS_CALLBACK_V2 -typedef int (*wl_ecounters_stats_get)(uint16 stats_type, struct wlc_info *wlc, - const ecounters_stats_types_report_req_t * req, struct bcm_xtlvbuf *xtlvbuf, - uint32 *cookie, const bcm_xtlv_t* tlv, uint16 *attempted_write_len); - -extern int wl_ecounters_register_source(struct wl_info *wl, uint16 stats_type, - wl_ecounters_stats_get some_fn); -extern int wl_ecounters_register_source_periodic(struct wl_info *wl, uint16 stats_type, - wl_ecounters_stats_get periodic_fn, wl_ecounters_stats_get some_fn); - -extern int wl_ecounters_trigger(void *trigger_context, uint16 reason); -#endif -extern bool wl_health_check_enabled(struct wl_info *wl); -typedef void (*wl_send_if_event_cb_fn_t)(void *ctx); -extern int wl_if_event_send_cb_fn_register(struct wl_info *wl, wl_send_if_event_cb_fn_t fn, - void *arg); -extern int wl_if_event_send_cb_fn_unregister(struct wl_info *wl, - wl_send_if_event_cb_fn_t fn, void *arg); -extern uint32 wl_get_ramsize(void); -#ifdef PACKET_FILTER -extern void wl_periodic_pktfltr_cntrs_state_upd(wlc_info_t *wlc); -#endif /* PACKET_FILTER */ - -#ifdef BCMPCIE_LATENCY -int wl_bus_pcie_latency_enab(struct wl_info *wl, bool val); -#endif /* BCMPCIE_LATENCY */ -void wl_hp2p_update_prio(struct wl_info *wl, void *p); -#endif /* _wl_export_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_ext_genl.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_ext_genl.c old mode 100755 new mode 100644 index e9bf46d4c7c7..815eb6de4d4e --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_ext_genl.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_ext_genl.c @@ -566,4 +566,3 @@ wl_ext_genl_deinit(struct net_device *net) } #endif - diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iapsta.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iapsta.c old mode 100755 new mode 100644 index bd23fde26ea5..06e67c5eac62 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iapsta.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iapsta.c @@ -8,11 +8,22 @@ #include #ifdef WL_CFG80211 #include +#include #endif /* WL_CFG80211 */ #ifdef WL_ESCAN #include #endif /* WL_ESCAN */ +#ifdef BTC_WAR +/* btc_war: + * -1(don't apply btc) + * 0(disable btc war): btc_mode=1; txchain=3; rxchain=3 + * 1(enable btc war): txchain=2; rxchain=2; btc_mode=5 + */ +int btc_war = -1; +module_param(btc_war, int, 0644); +#endif /* BTC_WAR */ + #define IAPSTA_ERROR(name, arg1, args...) \ do { \ if (android_msg_level & ANDROID_ERROR_LEVEL) { \ @@ -57,18 +68,31 @@ extern int disable_proptx; #define CSA_FW_BIT (1<<0) #define CSA_DRV_BIT (1<<1) +#define WL_DUMP_BUF_LEN (127 * 1024) + #define MAX_AP_LINK_WAIT_TIME 3000 #define MAX_STA_LINK_WAIT_TIME 15000 #define STA_LINKDOWN_TIMEOUT 10000 #define STA_CONNECT_TIMEOUT 10500 +#define STA_CONNECT_FULL_CHAN_TIMEOUT 3000 #define STA_CONNECT_RETRY_TIMEOUT 600 #define STA_RECONNECT_RETRY_TIMEOUT 300 +#define STA_DISCONNECT_RECONNECT_TIMEOUT 30000 +#define STA_DISCONNECT_RECONNECT_MAX 3 +#define STA_4WAY_TIMEOUT 1000 +#ifdef EAPOL_RESEND_M4 +#define STA_KEY_INSTALL_INTERVAL 50 +#define STA_KEY_INSTALL_MAX (STA_4WAY_TIMEOUT/STA_KEY_INSTALL_INTERVAL) +#else +#define STA_KEY_INSTALL_INTERVAL 50 +#define STA_KEY_INSTALL_MAX 3 +#endif #define STA_EAPOL_TIMEOUT 100 #define STA_EMPTY_SCAN_MAX 6 -#define AP_RESTART_TIMEOUT 1 -#define AP_TXBCNFRM_TIMEOUT 10 +#define AP_RESTART_TIMEOUT 1000 +#define AP_TXBCNFRM_TIMEOUT 10000 #ifdef RXF0OVFL_REINIT_WAR -#define RXF0OVFL_POLLING_TIMEOUT 1 +#define RXF0OVFL_POLLING_TIMEOUT 1000 #define RXF0OVFL_THRESHOLD 100 #endif /* RXF0OVFL_REINIT_WAR */ @@ -129,6 +153,12 @@ typedef enum ENCMODE { ENC_TKIPAES } encmode_t; +typedef enum MAPSTA_MODE { + MCHAN_APSTA_NOT_ALLOW = 0, + MCHAN_APSTA_SBSC, + MCHAN_APSTA_NO_RESTRICT +} mapsta_mode_t; + #ifdef STA_MGMT typedef struct wl_sta_info { int ifidx; @@ -196,8 +226,14 @@ typedef struct wl_if_info { int transit_maxcount; #endif /* PROPTX_MAXCOUNT */ uint conn_state; - uint16 prev_channel; - uint16 post_channel; + struct wl_chan_info prev_chan_info; + struct wl_chan_info post_chan_info; + struct osl_timespec sta_disc_ts; + struct osl_timespec sta_conn_ts; + bool ap_recon_sta; + wait_queue_head_t ap_recon_sta_event; + struct ether_addr ap_disc_sta_bssid; + struct osl_timespec ap_disc_sta_ts; #ifdef TPUT_MONITOR struct wl_tput_info tput_info; #endif /* TPUT_MONITOR */ @@ -219,6 +255,10 @@ typedef struct wl_if_info { int eapol_resend_intvl; #endif /* EAPOL_DYNAMATIC_RESEND */ #endif /* EAPOL_RESEND */ +#ifdef KEY_INSTALL_CHECK + timer_list_compat_t key_install_timer; + int key_install_cnt; +#endif /* KEY_INSTALL_CHECK */ int empty_scan; #ifdef RESTART_AP_WAR timer_list_compat_t restart_ap_timer; @@ -227,15 +267,21 @@ typedef struct wl_if_info { timer_list_compat_t reset_ap_timer; uint32 txbcnfrm; #endif /* RESET_AP_WAR */ +#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) +#ifdef WL_EXT_DISCONNECT_RECONNECT + struct osl_timespec sta_disc_conn_ts; + int sta_disc_recon_cnt; +#endif /* WL_EXT_DISCONNECT_RECONNECT */ +#endif /* WL_EXT_RECONNECT && WL_CFG80211 */ } wl_if_info_t; +u8 *g_ioctl_buf = NULL; + typedef struct wl_apsta_params { struct wl_if_info if_info[MAX_IF_NUM]; #ifdef WLDWDS struct wl_dwds_info dwds_info[MAX_DWDS_IF_NUM]; #endif /* WLDWDS */ - struct dhd_pub *dhd; - int ioctl_ver; bool init; int rsdb; bool vsdb; @@ -254,12 +300,6 @@ typedef struct wl_apsta_params { #endif /* WLMESH && WL_ESCAN */ struct mutex in4way_sync; int sta_btc_mode; - struct osl_timespec sta_disc_ts; - struct osl_timespec sta_conn_ts; - bool ap_recon_sta; - wait_queue_head_t ap_recon_sta_event; - struct ether_addr ap_disc_sta_bssid; - struct osl_timespec ap_disc_sta_ts; #ifdef TPUT_MONITOR timer_list_compat_t monitor_timer; int32 tput_sum; @@ -300,7 +340,8 @@ enum wifi_isam_reason { ISAM_RC_AP_RESTART = 4, ISAM_RC_AP_RESET = 5, ISAM_RC_EAPOL_RESEND = 6, - ISAM_RC_RXF0OVFL_REINIT = 7 + ISAM_RC_KEY_INSTALL = 7, + ISAM_RC_RXF0OVFL_REINIT = 8 }; #define wl_get_isam_status(cur_if, stat) \ @@ -315,9 +356,6 @@ enum wifi_isam_reason { static int wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock); static int wl_ext_disable_iface(struct net_device *dev, char *ifname); -#if defined(WLMESH) && defined(WL_ESCAN) -static int wl_mesh_escan_attach(dhd_pub_t *dhd, struct wl_if_info *cur_if); -#endif /* WLMESH && WL_ESCAN */ static struct wl_if_info * wl_get_cur_if(struct net_device *dev) @@ -460,6 +498,7 @@ wl_ext_parse_wep(char *key, struct wl_wsec_key *wsec_key) else return -1; /* fall through */ + fallthrough; case 10: case 26: case 32: @@ -604,17 +643,19 @@ wl_ext_set_amode(struct wl_if_info *cur_if) } static int -wl_ext_set_emode(struct wl_apsta_params *apsta_params, - struct wl_if_info *cur_if) +wl_ext_set_emode(struct wl_if_info *cur_if) { struct net_device *dev = cur_if->dev; - int wsec=0; +#ifdef BCM4343X_WAR + struct dhd_pub *dhd = dhd_get_pub(dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; +#endif struct wl_wsec_key wsec_key; wsec_pmk_t psk; authmode_t amode = cur_if->amode; encmode_t emode = cur_if->emode; + int wsec=0; char *key = cur_if->key; - struct dhd_pub *dhd = apsta_params->dhd; memset(&wsec_key, 0, sizeof(wsec_key)); memset(&psk, 0, sizeof(psk)); @@ -654,10 +695,12 @@ wl_ext_set_emode(struct wl_apsta_params *apsta_params, memcpy(psk.key, key, strlen(key)); IAPSTA_INFO(dev->name, "TKIP/AES key \"%s\"\n", psk.key); } +#ifdef BCM4343X_WAR if (dhd->conf->chip == BCM43430_CHIP_ID && cur_if->ifidx > 0 && wsec >= 2 && apsta_params->apstamode == ISTAAP_MODE) { wsec |= WSEC_SWFLAG; // terence 20180628: fix me, this is a workaround } +#endif wl_ext_iovar_setint(dev, "wsec", wsec); @@ -710,14 +753,14 @@ wl_ext_associated(struct net_device *dev) } static u32 -wl_ext_get_chanspec(struct wl_apsta_params *apsta_params, - struct net_device *dev, struct wl_chan_info *chan_info) +wl_ext_get_chanspec(struct net_device *dev, struct wl_chan_info *chan_info) { + struct dhd_pub *dhd = dhd_get_pub(dev); u32 chanspec = 0; if (wl_ext_associated(dev)) { if (wl_ext_iovar_getint(dev, "chanspec", (s32 *)&chanspec) == BCME_OK) { - chanspec = wl_ext_chspec_driver_to_host(apsta_params->ioctl_ver, chanspec); + chanspec = wl_ext_chspec_driver_to_host(dhd, chanspec); if (chan_info) { chan_info->band = CHSPEC2WLC_BAND(chanspec); chan_info->chan = wf_chspec_ctlchan(chanspec); @@ -730,13 +773,12 @@ wl_ext_get_chanspec(struct wl_apsta_params *apsta_params, } static uint16 -wl_ext_get_chan(struct wl_apsta_params *apsta_params, - struct net_device *dev, struct wl_chan_info *chan_info) +wl_ext_get_chan(struct net_device *dev, struct wl_chan_info *chan_info) { uint16 chan = 0, ctl_chan; u32 chanspec = 0; - - chanspec = wl_ext_get_chanspec(apsta_params, dev, chan_info); + + chanspec = wl_ext_get_chanspec(dev, chan_info); if (chanspec) { ctl_chan = wf_chspec_ctlchan(chanspec); chan = (u16)(ctl_chan & 0x00FF); @@ -745,10 +787,26 @@ wl_ext_get_chan(struct wl_apsta_params *apsta_params, return chan; } -static chanspec_t -wl_ext_chan_to_chanspec(struct wl_apsta_params *apsta_params, - struct net_device *dev, struct wl_chan_info *chan_info) +void +wl_ext_get_chan_str(struct net_device *dev, char *chan_str, int total_len) { + struct wl_chan_info chan_info; + int bytes_written=0; + u32 chanspec = 0; + + memset(chan_str, 0, total_len); + chanspec = wl_ext_get_chanspec(dev, &chan_info); + if (chanspec) { + bytes_written += snprintf(chan_str+bytes_written, total_len, "%s-%d %sMHz", + WLCBAND2STR(chan_info.band), chan_info.chan, + wf_chspec_to_bw_str(chanspec)); + } +} + +static chanspec_t +wl_ext_chan_to_chanspec(struct net_device *dev, struct wl_chan_info *chan_info) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); chanspec_band_t chanspec_band; chanspec_t chspec = 0, fw_chspec = 0; u32 bw = WL_CHANSPEC_BW_20; @@ -790,7 +848,7 @@ set_channel: chanspec_band = wl_ext_wlcband_to_chanspec_band(chan_info->band); chspec = wf_create_chspec_from_primary(chan_info->chan, bw, chanspec_band); if (wf_chspec_valid(chspec)) { - fw_chspec = wl_ext_chspec_host_to_driver(apsta_params->ioctl_ver, chspec); + fw_chspec = wl_ext_chspec_host_to_driver(dhd, chspec); if (fw_chspec == INVCHANSPEC) { IAPSTA_ERROR(dev->name, "failed to convert host chanspec to fw chanspec\n"); fw_chspec = 0; @@ -847,53 +905,98 @@ wl_ext_assoclist(struct net_device *dev, char *data, char *command, return bytes_written; } -static void -wl_ext_mod_timer(timer_list_compat_t *timer, uint sec, uint msec) -{ - uint timeout = sec * 1000 + msec; - - IAPSTA_TRACE("wlan", "timeout=%d\n", timeout); - - if (timer_pending(timer)) - del_timer_sync(timer); - - if (timeout) - mod_timer(timer, jiffies + msecs_to_jiffies(timeout)); -} - -static void -wl_ext_send_event_msg(struct net_device *dev, int event, int status) +void +wl_ext_send_event_msg(struct net_device *dev, int event, int status, + int reason) { struct dhd_pub *dhd = dhd_get_pub(dev); struct wl_if_info *cur_if; wl_event_msg_t msg; - cur_if = wl_get_cur_if(dev); - if (!cur_if) - return; - - bzero(&msg, sizeof(wl_event_msg_t)); - - msg.ifidx = dhd_net2idx(dhd->info, dev); - msg.event_type = hton32(event); - msg.status = hton32(status); - memcpy(&msg.addr, &cur_if->bssid, ETHER_ADDR_LEN); - + if (dhd && dhd->up) { + cur_if = wl_get_cur_if(dev); + if (!cur_if) + return; + bzero(&msg, sizeof(wl_event_msg_t)); + msg.ifidx = dhd_net2idx(dhd->info, dev); + msg.event_type = hton32(event); + msg.status = hton32(status); + msg.reason = hton32(reason); + memcpy(&msg.addr, &cur_if->bssid, ETHER_ADDR_LEN); #ifdef WL_EVENT - wl_ext_event_send(dhd->event_params, &msg, NULL); -#endif + wl_ext_event_send(dhd->event_params, &msg, NULL); +#endif /* WL_EVENT */ #ifdef WL_CFG80211 - if (dhd->up) { wl_cfg80211_event(dev, &msg, NULL); +#endif /* WL_CFG80211 */ } -#endif /* defined(WL_CFG80211) */ } +#ifdef BTC_WAR +bool +wl_ext_iapsta_if_2g_enabled(struct net_device *net) +{ + struct dhd_pub *dhd = dhd_get_pub(net); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + struct wl_if_info *tmp_if; + struct wl_chan_info chan_info; + bool enabled = FALSE; + uint16 cur_chan; + int i; + + for (i=0; iif_info[i]; + if (tmp_if && wl_get_isam_status(tmp_if, IF_READY)) { + cur_chan = wl_ext_get_chan(tmp_if->dev, &chan_info); + if (cur_chan && chan_info.band == WLC_BAND_2G) { + enabled = TRUE; + break; + } + } + } + + return enabled; +} + +void +wl_ext_btc_config(struct net_device *dev, bool enable) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); + bool enab = FALSE; + + if (dhd->conf->chip == BCM4354_CHIP_ID || dhd->conf->chip == BCM4356_CHIP_ID || + dhd->conf->chip == BCM43752_CHIP_ID) { + IAPSTA_INFO(dev->name, "btc_war=%d, enable=%d\n", btc_war, enable); + if (btc_war >= 0) { + if (enable && btc_war > 0) { + if (wl_ext_iapsta_if_2g_enabled(dev)) + enab = TRUE; + } + if (enab) { + IAPSTA_INFO(dev->name, "enable\n"); + wl_ext_iovar_setint(dev, "txchain", 2); + wl_ext_iovar_setint(dev, "rxchain", 2); + wl_ext_iovar_setint(dev, "btc_mode", 5); + } else { + IAPSTA_INFO(dev->name, "disable\n"); + wl_ext_iovar_setint(dev, "btc_mode", 1); + wl_ext_iovar_setint(dev, "txchain", 3); + wl_ext_iovar_setint(dev, "rxchain", 3); + } + } + } +} +#endif /* BTC_WAR */ + static void wl_ext_connect_timeout(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct wl_if_info *cur_if; +#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + u8 *curbssid = NULL; +#endif /* WL_CFG80211 */ if (!dev) { IAPSTA_ERROR("wlan", "dev is not ready\n"); @@ -906,9 +1009,12 @@ wl_ext_connect_timeout(unsigned long data) #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) cur_if->assoc_info.reassoc = 0; + curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID); + if (curbssid) + (void)memcpy_s(&cur_if->bssid, ETH_ALEN, curbssid, ETH_ALEN); #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ IAPSTA_ERROR(dev->name, "timer expired\n"); - wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS); + wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WLC_E_STATUS_SUCCESS); } #if defined(WL_CFG80211) || (defined(WLMESH) && defined(WL_ESCAN)) @@ -1036,7 +1142,7 @@ wl_ext_mesh_peer_status(struct net_device *dev, char *data, char *command, } #ifdef WL_ESCAN -#define WL_MESH_DELAY_SCAN_TMO 3 +#define WL_MESH_DELAY_SCAN_TMO 3000 static void wl_mesh_timer(unsigned long data) { @@ -1128,9 +1234,10 @@ exit: } static int -wl_mesh_clear_mesh_info(struct wl_apsta_params *apsta_params, - struct wl_if_info *mesh_if, bool scan) +wl_mesh_clear_mesh_info(struct wl_if_info *mesh_if, bool scan) { + struct dhd_pub *dhd = dhd_get_pub(mesh_if->dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct wl_mesh_params *mesh_info = &apsta_params->mesh_info; uchar mesh_oui[]={0x00, 0x22, 0xf4}; int ret; @@ -1140,9 +1247,9 @@ wl_mesh_clear_mesh_info(struct wl_apsta_params *apsta_params, ret = wl_mesh_clear_vndr_ie(mesh_if->dev, mesh_oui); memset(mesh_info, 0, sizeof(struct wl_mesh_params)); if (scan) { - mesh_info->scan_channel = wl_ext_get_chan(apsta_params, mesh_if->dev, + mesh_info->scan_channel = wl_ext_get_chan(mesh_if->dev, &mesh_if->chan_info); - wl_ext_mod_timer(&mesh_if->delay_scan, 0, 100); + wl_timer_mod(dhd, &mesh_if->delay_scan, 100); } return ret; @@ -1221,8 +1328,7 @@ wl_mesh_update_master_info(struct wl_apsta_params *apsta_params, if (sta_if) { wldev_ioctl(mesh_if->dev, WLC_GET_BSSID, &mesh_info->master_bssid, ETHER_ADDR_LEN, 0); - mesh_info->master_channel = wl_ext_get_chan(apsta_params, mesh_if->dev, - &mesh_if->chan_info); + mesh_info->master_channel = wl_ext_get_chan(mesh_if->dev, &mesh_if->chan_info); mesh_info->hop_cnt = 0; memset(mesh_info->peer_bssid, 0, MAX_HOP_LIST*ETHER_ADDR_LEN); if (!wl_mesh_update_vndr_ie(apsta_params, mesh_if)) @@ -1298,8 +1404,7 @@ wl_mesh_update_mesh_info(struct wl_apsta_params *apsta_params, wl_ext_get_sec(mesh_if->dev, mesh_if->ifmode, sec, sizeof(sec), FALSE); if (strnicmp(sec, "sae/sae", strlen("sae/sae")) == 0) sae = TRUE; - cur_chan = wl_ext_get_chan(apsta_params, mesh_if->dev, - &mesh_if->chan_info); + cur_chan = wl_ext_get_chan(mesh_if->dev, &mesh_if->chan_info); bss_found = wl_escan_mesh_peer(mesh_if->dev, mesh_if->escan, &cur_ssid, cur_chan, sae, &peer_mesh_info); @@ -1308,7 +1413,7 @@ wl_mesh_update_mesh_info(struct wl_apsta_params *apsta_params, WL_MSG(mesh_if->ifname, "moving channel %d -> %d\n", cur_chan, peer_mesh_info.master_channel); wl_ext_disable_iface(mesh_if->dev, mesh_if->ifname); - mesh_if->channel = peer_mesh_info.master_channel; + mesh_if->chan_info.chan = peer_mesh_info.master_channel; wl_ext_enable_iface(mesh_if->dev, mesh_if->ifname, 500, TRUE); } } @@ -1320,67 +1425,106 @@ exit: } static void -wl_mesh_event_handler(struct wl_apsta_params *apsta_params, - struct wl_if_info *mesh_if, const wl_event_msg_t *e, void *data) +wl_mesh_event_handler(struct wl_if_info *cur_if, + const wl_event_msg_t *e, void *data) { + struct dhd_pub *dhd = dhd_get_pub(cur_if->dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct wl_mesh_params *mesh_info = &apsta_params->mesh_info; uint32 event_type = ntoh32(e->event_type); uint32 status = ntoh32(e->status); uint32 reason = ntoh32(e->reason); - int ret; + uint16 flags = ntoh16(e->flags); + struct wl_if_info *mesh_if = NULL, *tmp_if = NULL; + int ret, i; - if (wl_get_isam_status(mesh_if, AP_CREATED) && - ((event_type == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) || - (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && - reason == WLC_E_REASON_INITIAL_ASSOC))) { - if (!wl_mesh_update_master_info(apsta_params, mesh_if)) { - mesh_info->scan_channel = wl_ext_get_chan(apsta_params, &mesh_if->dev, - mesh_if->chan_info); - wl_ext_mod_timer(&mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO, 0); - } - } - else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) || - (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && - reason == WLC_E_REASON_DEAUTH)) { - wl_mesh_clear_mesh_info(apsta_params, mesh_if, FALSE); - } - else if (wl_get_isam_status(mesh_if, AP_CREATED) && - (event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) && - reason == DOT11_SC_SUCCESS) { - mesh_info->scan_channel = wl_ext_get_chan(apsta_params, mesh_if->dev, - &mesh_if->chan_info); - wl_ext_mod_timer(&mesh_if->delay_scan, 0, 100); - } - else if (event_type == WLC_E_DISASSOC_IND || event_type == WLC_E_DEAUTH_IND || - (event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) { - if (!memcmp(&mesh_info->peer_bssid, &e->addr, ETHER_ADDR_LEN)) - wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE); - } - else if (wl_get_isam_status(mesh_if, AP_CREATED) && - event_type == WLC_E_RESERVED && reason == ISAM_RC_MESH_ACS) { - if (!wl_mesh_update_master_info(apsta_params, mesh_if)) { - wl_scan_info_t scan_info; - memset(&scan_info, 0, sizeof(wl_scan_info_t)); - wl_ext_ioctl(mesh_if->dev, WLC_GET_SSID, &scan_info.ssid, sizeof(wlc_ssid_t), 0); - if (mesh_info->scan_channel) { - scan_info.channels.count = 1; - scan_info.channels.channel[0] = mesh_info->scan_channel; + if (cur_if->ifmode == IMESH_MODE) + mesh_if = cur_if; + else { + for (i=0; iif_info[i]; + if (tmp_if->dev && tmp_if->ifmode == IMESH_MODE) { + mesh_if = tmp_if; + break; } - ret = wl_escan_set_scan(mesh_if->dev, &scan_info); - if (ret) - wl_ext_mod_timer(&mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO, 0); } } - else if (wl_get_isam_status(mesh_if, AP_CREATED) && - ((event_type == WLC_E_ESCAN_RESULT && status == WLC_E_STATUS_SUCCESS) || - (event_type == WLC_E_ESCAN_RESULT && - (status == WLC_E_STATUS_ABORT || status == WLC_E_STATUS_NEWSCAN || - status == WLC_E_STATUS_11HQUIET || status == WLC_E_STATUS_CS_ABORT || - status == WLC_E_STATUS_NEWASSOC || status == WLC_E_STATUS_TIMEOUT)))) { - if (!wl_mesh_update_master_info(apsta_params, mesh_if)) { - if (!wl_mesh_update_mesh_info(apsta_params, mesh_if)) { - mesh_info->scan_channel = 0; - wl_ext_mod_timer(&mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO, 0); + + if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) { + if (event_type == WLC_E_LINK) { + if (!(flags & WLC_EVENT_MSG_LINK)) { + if (mesh_if && apsta_params->macs) + wl_mesh_clear_mesh_info(mesh_if, TRUE); + } else { + if (mesh_if && apsta_params->macs) + wl_mesh_update_master_info(apsta_params, mesh_if); + } + } + else if (event_type == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) { + if (mesh_if && apsta_params->macs) + wl_mesh_clear_mesh_info(mesh_if, TRUE); + } + else if (event_type == WLC_E_DEAUTH || event_type == WLC_E_DEAUTH_IND || + event_type == WLC_E_DISASSOC || event_type == WLC_E_DISASSOC_IND) { + if (mesh_if && apsta_params->macs) + wl_mesh_clear_mesh_info(mesh_if, TRUE); + } + } + else if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) { + if (wl_get_isam_status(mesh_if, AP_CREATED) && + ((event_type == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) || + (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && + reason == WLC_E_REASON_INITIAL_ASSOC))) { + if (!wl_mesh_update_master_info(apsta_params, mesh_if)) { + mesh_info->scan_channel = wl_ext_get_chan(mesh_if->dev, + &mesh_if->chan_info); + wl_timer_mod(dhd, &mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO); + } + } + else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) || + (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && + reason == WLC_E_REASON_DEAUTH)) { + wl_mesh_clear_mesh_info(mesh_if, FALSE); + } + else if (wl_get_isam_status(mesh_if, AP_CREATED) && + (event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) && + reason == DOT11_SC_SUCCESS) { + mesh_info->scan_channel = wl_ext_get_chan(mesh_if->dev, + &mesh_if->chan_info); + wl_timer_mod(dhd, &mesh_if->delay_scan, 100); + } + else if (event_type == WLC_E_DISASSOC_IND || event_type == WLC_E_DEAUTH_IND || + (event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) { + if (!memcmp(&mesh_info->peer_bssid, &e->addr, ETHER_ADDR_LEN)) + wl_mesh_clear_mesh_info(mesh_if, TRUE); + } + else if (wl_get_isam_status(mesh_if, AP_CREATED) && + event_type == WLC_E_RESERVED && reason == ISAM_RC_MESH_ACS) { + if (!wl_mesh_update_master_info(apsta_params, mesh_if)) { + wl_scan_info_t scan_info; + memset(&scan_info, 0, sizeof(wl_scan_info_t)); + wl_ext_ioctl(mesh_if->dev, WLC_GET_SSID, &scan_info.ssid, sizeof(wlc_ssid_t), 0); + if (mesh_info->scan_channel) { + scan_info.channels.count = 1; + // fix me: need to convert channel to host chanspec + scan_info.channels.chanspec[0] = mesh_info->scan_channel; + } + ret = wl_escan_set_scan(mesh_if->dev, &scan_info); + if (ret) + wl_timer_mod(dhd, &mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO); + } + } + else if (wl_get_isam_status(mesh_if, AP_CREATED) && + ((event_type == WLC_E_ESCAN_RESULT && status == WLC_E_STATUS_SUCCESS) || + (event_type == WLC_E_ESCAN_RESULT && + (status == WLC_E_STATUS_ABORT || status == WLC_E_STATUS_NEWSCAN || + status == WLC_E_STATUS_11HQUIET || status == WLC_E_STATUS_CS_ABORT || + status == WLC_E_STATUS_NEWASSOC || status == WLC_E_STATUS_TIMEOUT)))) { + if (!wl_mesh_update_master_info(apsta_params, mesh_if)) { + if (!wl_mesh_update_mesh_info(apsta_params, mesh_if)) { + mesh_info->scan_channel = 0; + wl_timer_mod(dhd, &mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO); + } } } } @@ -1390,9 +1534,7 @@ static void wl_mesh_escan_detach(dhd_pub_t *dhd, struct wl_if_info *mesh_if) { IAPSTA_TRACE(mesh_if->dev->name, "Enter\n"); - - del_timer_sync(&mesh_if->delay_scan); - + wl_timer_deregister(mesh_if->dev, &mesh_if->delay_scan); if (mesh_if->escan) { mesh_if->escan = NULL; } @@ -1404,7 +1546,7 @@ wl_mesh_escan_attach(dhd_pub_t *dhd, struct wl_if_info *mesh_if) IAPSTA_TRACE(mesh_if->dev->name, "Enter\n"); mesh_if->escan = dhd->escan; - init_timer_compat(&mesh_if->delay_scan, wl_mesh_timer, mesh_if->dev); + wl_timer_register(mesh_if->dev, &mesh_if->delay_scan, wl_mesh_timer); return 0; } @@ -1558,6 +1700,7 @@ static int wl_ext_if_up(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if, bool force_enable, int wait_up) { + dhd_pub_t *dhd = NULL; struct wl_chan_info *chan_info = &cur_if->chan_info; s8 iovar_buf[WLC_IOCTL_SMLEN]; struct { @@ -1575,10 +1718,18 @@ wl_ext_if_up(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if, return 0; } + dhd = dhd_get_pub(cur_if->dev); + chanspec = wf_create_chspec_from_primary(chan_info->chan, + WL_CHANSPEC_BW_20, wl_ext_wlcband_to_chanspec_band(chan_info->band)); + if (wl_ext_dfs_chan(chan_info) && !apsta_params->radar && !force_enable) { WL_MSG(cur_if->ifname, "[%c] skip DFS channel %d\n", cur_if->prefix, chan_info->chan); return 0; + } else if (wl_ext_passive_chan(cur_if->dev, chanspec)) { + WL_MSG(cur_if->ifname, "[%c] skip PASSIVE channel %d\n", + cur_if->prefix, chan_info->chan); + return 0; } else if (!chan_info->chan) { WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix); return 0; @@ -1613,7 +1764,7 @@ wl_ext_if_up(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if, } wl_ext_ioctl(cur_if->dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0); - chanspec = wl_ext_get_chanspec(apsta_params, cur_if->dev, chan_info); + chanspec = wl_ext_get_chanspec(cur_if->dev, chan_info); WL_MSG(cur_if->ifname, "[%c] enabled with SSID: \"%s\" on channel %s-%d(0x%x)\n", cur_if->prefix, ssid.SSID, CHSPEC2BANDSTR(chanspec), chan_info->chan, chanspec); @@ -1663,7 +1814,7 @@ wl_ext_get_same_band_chan(struct wl_apsta_params *apsta_params, if (cur_if != tmp_if && wl_get_isam_status(tmp_if, IF_READY) && tmp_if->prio > max_prio) { memset(&chan_info, 0, sizeof(struct wl_chan_info)); - wl_ext_get_chan(apsta_params, tmp_if->dev, &chan_info); + wl_ext_get_chan(tmp_if->dev, &chan_info); if (wl_ext_dfs_chan(&chan_info) && nodfs) continue; if (chan_info.chan && (cur_if->chan_info.band == chan_info.band)) { @@ -1690,7 +1841,7 @@ wl_ext_get_vsdb_chan(struct wl_apsta_params *apsta_params, return 0; memset(&chan_info, 0, sizeof(struct wl_chan_info)); - target_chan = wl_ext_get_chan(apsta_params, target_if->dev, &chan_info); + target_chan = wl_ext_get_chan(target_if->dev, &chan_info); if (target_chan) { target_band = chan_info.band; IAPSTA_INFO(cur_if->ifname, "cur_chan=%s-%d, target_chan=%s-%d\n", @@ -1718,13 +1869,13 @@ wl_ext_rsdb_core_conflict(struct wl_apsta_params *apsta_params, if (apsta_params->rsdb) { memset(&cur_chan_info, 0, sizeof(struct wl_chan_info)); - wl_ext_get_chan(apsta_params, cur_if->dev, &cur_chan_info); + wl_ext_get_chan(cur_if->dev, &cur_chan_info); for (i=0; iif_info[i]; if (tmp_if != cur_if && wl_get_isam_status(tmp_if, IF_READY) && tmp_if->prio > cur_if->prio) { memset(&tmp_chan_info, 0, sizeof(struct wl_chan_info)); - wl_ext_get_chan(apsta_params, tmp_if->dev, &tmp_chan_info); + wl_ext_get_chan(tmp_if->dev, &tmp_chan_info); if (!tmp_chan_info.chan) continue; if (wl_ext_rsdb_band(cur_chan_info.band, tmp_chan_info.band) && @@ -1757,8 +1908,7 @@ wl_ext_trigger_csa(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_ memset(&csa_arg, 0, sizeof(csa_arg)); csa_arg.mode = 1; csa_arg.count = 3; - csa_arg.chspec = wl_ext_chan_to_chanspec(apsta_params, cur_if->dev, - &cur_if->chan_info); + csa_arg.chspec = wl_ext_chan_to_chanspec(cur_if->dev, &cur_if->chan_info); core_conflict = wl_ext_rsdb_core_conflict(apsta_params, cur_if); if (core_conflict) { WL_MSG(cur_if->ifname, "[%c] Skip CSA due to rsdb core conflict\n", @@ -1806,7 +1956,8 @@ wl_ext_move_cur_dfs_channel(struct wl_apsta_params *apsta_params, auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, TRUE); if (!auto_chan) { auto_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT, - cur_chan_info->band); + cur_chan_info->band, NULL); + auto_chan = wf_chspec_ctlchan(auto_chan); } if (auto_chan) cur_chan_info->chan = auto_chan; @@ -1827,7 +1978,8 @@ wl_ext_move_cur_dfs_channel(struct wl_apsta_params *apsta_params, } if (!auto_chan) { auto_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT, - cur_chan_info->band); + cur_chan_info->band, NULL); + auto_chan = wf_chspec_ctlchan(auto_chan); } if (auto_chan) { cur_chan_info->chan = auto_chan; @@ -1840,7 +1992,8 @@ wl_ext_move_cur_dfs_channel(struct wl_apsta_params *apsta_params, cur_chan_info->chan = auto_chan; } else { auto_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT, - cur_chan_info->band); + cur_chan_info->band, NULL); + auto_chan = wf_chspec_ctlchan(auto_chan); if (auto_chan) { cur_chan_info->chan = auto_chan; } @@ -1878,7 +2031,8 @@ wl_ext_move_other_dfs_channel(struct wl_apsta_params *apsta_params, auto_chan = wl_ext_get_same_band_chan(apsta_params, tgt_if, TRUE); if (!auto_chan) { auto_chan = wl_ext_autochannel(tgt_if->dev, ACS_FW_BIT|ACS_DRV_BIT, - tgt_chan_info->band); + tgt_chan_info->band, NULL); + auto_chan = wf_chspec_ctlchan(auto_chan); } if (auto_chan) { tgt_chan_info->chan = auto_chan; @@ -1890,7 +2044,8 @@ wl_ext_move_other_dfs_channel(struct wl_apsta_params *apsta_params, auto_chan = wl_ext_get_same_band_chan(apsta_params, tgt_if, TRUE); if (!auto_chan) { auto_chan = wl_ext_autochannel(tgt_if->dev, ACS_FW_BIT|ACS_DRV_BIT, - tgt_chan_info->band); + tgt_chan_info->band, NULL); + auto_chan = wf_chspec_ctlchan(auto_chan); } } else { tgt_chan_info->chan = 0; @@ -1938,8 +2093,8 @@ wl_ext_move_cur_channel(struct wl_apsta_params *apsta_params, if (target_if) { memset(&cur_chan_info, 0, sizeof(struct wl_chan_info)); memset(&tgt_chan_info, 0, sizeof(struct wl_chan_info)); - wl_ext_get_chan(apsta_params, cur_if->dev, &cur_chan_info); - wl_ext_get_chan(apsta_params, target_if->dev, &tgt_chan_info); + wl_ext_get_chan(cur_if->dev, &cur_chan_info); + wl_ext_get_chan(target_if->dev, &tgt_chan_info); if (apsta_params->rsdb && cur_chan_info.chan && wl_ext_rsdb_band(cur_chan_info.band, tgt_chan_info.band)) { WL_MSG(cur_if->ifname, "[%c] keep on current channel %s-%d\n", @@ -1989,6 +2144,21 @@ wl_ext_move_other_channel(struct wl_apsta_params *apsta_params, } } + if (target_if) { + // skip move target_if while there is other interface's prio is higher than cur_if + max_prio = cur_if->prio; + for (i=0; iif_info[i]; + if (target_if != tmp_if && wl_get_isam_status(tmp_if, IF_READY) && + tmp_if->prio > max_prio) { + if (wl_ext_same_chan(&target_if->chan_info, &tmp_if->chan_info)) { + target_if = NULL; + break; + } + } + } + } + if (target_if) { WL_MSG(target_if->ifname, "channel=%s-%d => %s channel=%s-%d\n", WLCBAND2STR(target_if->chan_info.band), target_chan, @@ -2101,6 +2271,73 @@ wl_ext_sta_connecting(struct net_device *dev) return connecting; } +bool +wl_ext_sta_handshaking(struct net_device *dev) +{ + struct wl_if_info *cur_if = NULL; + bool connecting = FALSE; + int state; + + cur_if = wl_get_cur_if(dev); + if (!cur_if) + return FALSE; + + if (cur_if->ifmode != ISTA_MODE && cur_if->ifmode != IGC_MODE) + return FALSE; + + state = cur_if->conn_state; + if (state >= CONN_STATE_4WAY_M1 && state < CONN_STATE_CONNECTED) { + connecting = TRUE; + IAPSTA_TRACE(dev->name, "conn_state %d\n", state); + } + + return connecting; +} + +bool +wl_ext_sta_connected(struct net_device *dev) +{ + struct wl_if_info *cur_if = NULL; + bool connected = FALSE; + int state; + + cur_if = wl_get_cur_if(dev); + if (!cur_if) + return FALSE; + + if (cur_if->ifmode != ISTA_MODE && cur_if->ifmode != IGC_MODE) + return FALSE; + + state = cur_if->conn_state; + if (state >= CONN_STATE_CONNECTED) { + connected = TRUE; + IAPSTA_TRACE(dev->name, "conn_state %d\n", state); + } + + return connected; +} + +#ifdef DHD_LOSSLESS_ROAMING +int +wl_ext_any_sta_handshaking(struct dhd_pub *dhd) +{ + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + struct wl_if_info *cur_if; + int state = 0, i; + + for (i=0; iif_info[i]; + if (cur_if->dev && cur_if->ifmode == ISTA_MODE) { + state = cur_if->conn_state; + if (state >= CONN_STATE_4WAY_M1 && state < CONN_STATE_CONNECTED) { + return state; + } + } + } + return 0; +} +#endif /* DHD_LOSSLESS_ROAMING */ + #ifdef PROPTX_MAXCOUNT int wl_ext_get_wlfc_maxcount(struct dhd_pub *dhd, int ifidx) @@ -2143,7 +2380,7 @@ wl_ext_update_wlfc_maxcount(struct dhd_pub *dhd) tmp_if = &apsta_params->if_info[i]; if (tmp_if->dev) { memset(&chan_info, 0, sizeof(struct wl_chan_info)); - wl_ext_get_chan(apsta_params, tmp_if->dev, &chan_info); + wl_ext_get_chan(tmp_if->dev, &chan_info); if (chan_info.band == WLC_BAND_5G || chan_info.band == WLC_BAND_6G) { tmp_if->transit_maxcount = dhd->conf->proptx_maxcnt_5g; ret = dhd_wlfc_update_maxcount(dhd, tmp_if->ifidx, @@ -2159,7 +2396,7 @@ wl_ext_update_wlfc_maxcount(struct dhd_pub *dhd) for (i=0; iif_info[i]; if (tmp_if->dev) { - wl_ext_get_chan(apsta_params, tmp_if->dev, &chan_info); + wl_ext_get_chan(tmp_if->dev, &chan_info); if ((chan_info.chan == 0) || (chan_info.band == WLC_BAND_2G)) { if (chan_info.chan == 0) { tmp_if->transit_maxcount = WL_TXSTATUS_FREERUNCTR_MASK; @@ -2192,7 +2429,7 @@ wl_ext_get_dfs_master_if(struct wl_apsta_params *apsta_params) if (!cur_if->dev || !wl_ext_master_if(cur_if)) continue; memset(&chan_info, 0, sizeof(struct wl_chan_info)); - wl_ext_get_chan(apsta_params, cur_if->dev, &chan_info); + wl_ext_get_chan(cur_if->dev, &chan_info); if (chan_info.chan && wl_ext_dfs_chan(&chan_info)) { return cur_if; } @@ -2202,7 +2439,7 @@ wl_ext_get_dfs_master_if(struct wl_apsta_params *apsta_params) static void wl_ext_save_master_channel(struct wl_apsta_params *apsta_params, - uint16 post_channel) + struct wl_chan_info *post_chan_info) { struct wl_if_info *cur_if = NULL; struct wl_chan_info chan_info; @@ -2216,10 +2453,10 @@ wl_ext_save_master_channel(struct wl_apsta_params *apsta_params, if (!cur_if->dev || !wl_ext_master_if(cur_if)) continue; memset(&chan_info, 0, sizeof(struct wl_chan_info)); - wl_ext_get_chan(apsta_params, cur_if->dev, &chan_info); + wl_ext_get_chan(cur_if->dev, &chan_info); if (chan_info.chan) { - cur_if->prev_channel = chan_info.chan; - cur_if->post_channel = post_channel; + memcpy(&cur_if->prev_chan_info, &chan_info, sizeof(struct wl_chan_info)); + memcpy(&cur_if->post_chan_info, post_chan_info, sizeof(struct wl_chan_info)); } } } @@ -2234,14 +2471,17 @@ wl_ext_iapsta_enable_master_if(struct net_device *dev, bool post) for (i=0; iif_info[i]; - if (cur_if && cur_if->post_channel) { + if (cur_if && cur_if->post_chan_info.chan) { if (post) - cur_if->chan_info.chan = cur_if->post_channel; + memcpy(&cur_if->chan_info, &cur_if->post_chan_info, sizeof(struct wl_chan_info)); else - cur_if->chan_info.chan = cur_if->prev_channel; + memcpy(&cur_if->chan_info, &cur_if->prev_chan_info, sizeof(struct wl_chan_info)); + if (wl_ext_associated(cur_if->dev)) + wl_ext_if_down(apsta_params, cur_if); + OSL_SLEEP(100); wl_ext_if_up(apsta_params, cur_if, TRUE, 0); - cur_if->prev_channel = 0; - cur_if->post_channel = 0; + memset(&cur_if->prev_chan_info, 0, sizeof(struct wl_chan_info)); + memset(&cur_if->post_chan_info, 0, sizeof(struct wl_chan_info)); } } } @@ -2251,14 +2491,31 @@ wl_ext_iapsta_restart_master(struct net_device *dev) { dhd_pub_t *dhd = dhd_get_pub(dev); struct wl_apsta_params *apsta_params = dhd->iapsta_params; - struct wl_if_info *ap_if = NULL; + struct wl_if_info *ap_if = NULL, *tmp_if = NULL; + struct wl_chan_info chan_info; + int i; if (apsta_params->radar) return; ap_if = wl_ext_get_dfs_master_if(apsta_params); + if (!ap_if) + return; + + for (i=0; iif_info[i]; + if (tmp_if && tmp_if->ifmode == ISTA_MODE && + wl_get_isam_status(tmp_if, IF_READY)) { + memset(&chan_info, 0, sizeof(struct wl_chan_info)); + wl_ext_get_chan(tmp_if->dev, &chan_info); + if (wl_ext_same_chan(&chan_info, &tmp_if->chan_info)) { + return; + } + } + } if (ap_if) { uint16 chan_2g, chan_5g; + WL_MSG(tmp_if->ifname, "move DFS channel interface\n"); wl_ext_if_down(apsta_params, ap_if); wl_ext_iapsta_restart_master(dev); wl_ext_get_default_chan(ap_if->dev, &chan_2g, &chan_5g, TRUE); @@ -2271,6 +2528,8 @@ wl_ext_iapsta_restart_master(struct net_device *dev) if (ap_if->chan_info.chan) { wl_ext_move_cur_channel(apsta_params, ap_if); wl_ext_if_up(apsta_params, ap_if, FALSE, 0); + } else { + WL_MSG(tmp_if->ifname, "no preferred channel\n"); } } } @@ -2285,8 +2544,8 @@ wl_ext_if_reenabled(struct wl_apsta_params *apsta_params, ifmode_t ifmode, u32 c tmp_if = &apsta_params->if_info[i]; if (tmp_if && tmp_if->ifmode == ifmode && wl_get_isam_status(tmp_if, IF_READY)) { - if (wl_ext_get_chan(apsta_params, tmp_if->dev, &tmp_if->chan_info) == channel) { - WL_MSG(tmp_if->ifname, "re-enable channel %d\n", channel); + if (wl_ext_get_chan(tmp_if->dev, &tmp_if->chan_info) == channel) { + WL_MSG(tmp_if->ifname, "re-enable channel %d\n", channel); if (ifmode == IAP_MODE) { wl_ext_if_down(apsta_params, tmp_if); wl_ext_if_up(apsta_params, tmp_if, FALSE, 0); @@ -2315,12 +2574,13 @@ wl_ext_iapsta_update_channel(struct net_device *dev, u32 chanspec) wf_chspec_ctlchan(chanspec)); if (wl_ext_master_if(cur_if) && apsta_params->acs) { chan_info->chan = wl_ext_autochannel(cur_if->dev, apsta_params->acs, - chan_info->band); + chan_info->band, NULL); + chan_info->chan = wf_chspec_ctlchan(chan_info->chan); } chan_info->chan = wl_ext_move_cur_channel(apsta_params, cur_if); if (chan_info->chan) { if (cur_if->ifmode == ISTA_MODE && wl_ext_dfs_chan(chan_info)) - wl_ext_save_master_channel(apsta_params, chan_info->chan); + wl_ext_save_master_channel(apsta_params, chan_info); target_if = wl_ext_move_other_channel(apsta_params, cur_if); if (dhd->conf->chip == BCM4359_CHIP_ID && cur_if->ifmode == ISTA_MODE && !target_if) { @@ -2333,10 +2593,10 @@ wl_ext_iapsta_update_channel(struct net_device *dev, u32 chanspec) } } if (cur_if->ifmode == ISTA_MODE) { - if (conf->war & SET_CHAN_INCONN) { + if (conf->war & SET_CHAN_INCONN && chan_info->chan) { chanspec_t fw_chspec; - IAPSTA_INFO(dev->name, "set channel %d\n", chan_info->chan); - wl_ext_set_chanspec(cur_if->dev, chan_info, &fw_chspec); + IAPSTA_INFO(dev->name, "set channel %d\n", chan_info->chan); + wl_ext_set_chanspec(cur_if->dev, chan_info, &fw_chspec); } wl_set_isam_status(cur_if, STA_CONNECTING); } @@ -2391,6 +2651,9 @@ wl_ext_iapsta_update_iftype(struct net_device *net, int wl_iftype) cur_if->prio = PRIO_STA; cur_if->vsdb = TRUE; cur_if->prefix = 'S'; +#ifdef WL_STATIC_IF + dhd_conf_preinit_ioctls_sta(dhd, ifidx); +#endif /* WL_STATIC_IF */ } else if (wl_iftype == WL_IF_TYPE_AP && cur_if->ifmode != IMESH_MODE) { cur_if->ifmode = IAP_MODE; cur_if->prio = PRIO_AP; @@ -2495,7 +2758,84 @@ wl_ext_reconnect_timeout(unsigned long data) return; } IAPSTA_ERROR(dev->name, "timer expired\n"); - wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS); + wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WLC_E_STATUS_SUCCESS); +} + +#ifdef WL_EXT_DISCONNECT_RECONNECT +static bool +wl_ext_disc_recon_retry(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) +{ + int sta_disc_recon_cnt = cur_if->sta_disc_recon_cnt; + struct osl_timespec *sta_disc_conn_ts = &cur_if->sta_disc_conn_ts; + struct osl_timespec cur_ts; + uint32 diff_ms = 0; + bool retry = FALSE; + + if (sta_disc_recon_cnt == 0) + osl_do_gettimeofday(sta_disc_conn_ts); + + osl_do_gettimeofday(&cur_ts); + diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_conn_ts)/1000; + + IAPSTA_INFO(cur_if->ifname, "sta_disc_recon_cnt=%d, diff_ms = %dms\n", + sta_disc_recon_cnt, diff_ms); + if (sta_disc_recon_cnt >= STA_DISCONNECT_RECONNECT_MAX) { + if (diff_ms >= STA_DISCONNECT_RECONNECT_TIMEOUT) { + osl_do_gettimeofday(sta_disc_conn_ts); + cur_if->sta_disc_recon_cnt = 0; + retry = TRUE; + } else { + retry = FALSE; + } + } else { + retry = TRUE; + } + + if (retry) + cur_if->sta_disc_recon_cnt++; + + return retry; +} +#endif /* WL_EXT_DISCONNECT_RECONNECT */ + +static void +wl_ext_update_assoc_info(struct net_device *dev, bool reassoc) +{ +#ifndef WL_REASSOC_BCAST + dhd_pub_t *dhd = dhd_get_pub(dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + struct wl_chan_info chan_info; +#endif + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + wlcfg_assoc_info_t *assoc_info; + struct wl_if_info *cur_if; + + cur_if = wl_get_cur_if(dev); + if (cur_if) { + assoc_info = &cur_if->assoc_info; + assoc_info->reassoc = reassoc; + assoc_info->bssid_hint = false; +#ifdef WL_REASSOC_BCAST + assoc_info->chan_cnt = 0; + assoc_info->chanspecs[0] = 0; + memcpy(&assoc_info->bssid, ðer_bcast, ETHER_ADDR_LEN); +#else + assoc_info->chanspecs[0] = wl_ext_get_chanspec(dev, &chan_info); + if (assoc_info->chanspecs[0] && reassoc) { + assoc_info->chan_cnt = 1; + wldev_ioctl(dev, WLC_GET_BSSID, &cur_if->bssid, ETHER_ADDR_LEN, 0); + memcpy(&assoc_info->bssid, &cur_if->bssid, ETHER_ADDR_LEN); + } else { + assoc_info->chan_cnt = 0; + memcpy(&assoc_info->bssid, ðer_bcast, ETHER_ADDR_LEN); + } +#endif /* WL_REASSOC_BCAST */ + if (!ETHER_ISBCAST(assoc_info->bssid)) + assoc_info->targeted_join = true; + else + assoc_info->targeted_join = false; + wl_get_assoc_channels(cfg, dev, assoc_info); + } } static int @@ -2505,45 +2845,129 @@ wl_ext_connect_retry(struct net_device *dev, wl_event_msg_t *e) struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct wl_if_info *cur_if; struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - struct osl_timespec cur_ts, *sta_conn_ts = &apsta_params->sta_conn_ts; + struct osl_timespec cur_ts, *sta_conn_ts; + wlcfg_assoc_info_t *assoc_info; uint32 diff_ms = 0; int max_wait_time = 0, ret = 0; - bool connecting = FALSE; + bool connecting, handshaking, associated; + uint32 etype = ntoh32(e->event_type); + uint32 status = ntoh32(e->status); + + if (wl_get_drv_status(cfg, DISCONNECTING, dev)) { + WL_MSG(dev->name, "skip connect retry due to disconnecting\n"); + return BCME_BADADDR; + } cur_if = wl_get_cur_if(dev); if (!cur_if) return ret; + sta_conn_ts = &cur_if->sta_conn_ts; + connecting = wl_ext_sta_connecting(dev); + handshaking = wl_ext_sta_handshaking(dev); + + if (cur_if->conn_state == CONN_STATE_ASSOCIATED) { + WL_MSG(dev->name, "skip connect retry due to no 4-way M1 received\n"); + return BCME_BADADDR; + } mutex_unlock(&apsta_params->in4way_sync); mutex_lock(&cfg->connect_sync); - connecting = wl_ext_sta_connecting(dev); osl_do_gettimeofday(&cur_ts); diff_ms = osl_do_gettimediff(&cur_ts, sta_conn_ts)/1000; + associated = wl_ext_associated(dev); + assoc_info = &cur_if->assoc_info; if (connecting && diff_ms < STA_CONNECT_TIMEOUT && !wl_get_drv_status(cfg, DISCONNECTING, dev)) { - uint32 etype = ntoh32(e->event_type); - uint32 status = ntoh32(e->status); if (etype == WLC_E_SET_SSID && (status == WLC_E_STATUS_NO_NETWORKS || status == WLC_E_STATUS_NO_ACK)) { - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); - if (cur_if->assoc_info.reassoc) { + wl_timer_mod(dhd, &cur_if->reconnect_timer, 0); + if (assoc_info->reassoc && associated && !handshaking) { + /* There are two cases will come in to retry reassoc: + * 1) reconnect from wpa_supplicant + * 2) fw roam + */ + if (associated) + bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN); WL_MSG(dev->name, "retry reassoc\n"); - wl_handle_reassoc(cfg, dev, &cur_if->assoc_info); - max_wait_time = STA_RECONNECT_RETRY_TIMEOUT; - } else { - if (!wl_ext_associated(dev)) { - WL_MSG(dev->name, "retry join\n"); - wl_cfg80211_disassoc(dev, WLAN_REASON_DEAUTH_LEAVING); - wl_handle_join(cfg, dev, &cur_if->assoc_info); - max_wait_time = STA_CONNECT_RETRY_TIMEOUT; - } + if (wl_handle_reassoc(cfg, dev, assoc_info)) + goto exit; + if (assoc_info->chan_cnt == 0) + max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT; + else + max_wait_time = STA_RECONNECT_RETRY_TIMEOUT + + (WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS * assoc_info->chan_cnt); + max_wait_time = min(max_wait_time, STA_CONNECT_FULL_CHAN_TIMEOUT); } - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, max_wait_time); + else { + /* There is one case will come in to retry join: + * 1) connect from wpa_supplicant + */ + WL_MSG(dev->name, "retry join\n"); + if (associated) { + bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN); + wl_cfg80211_disassoc(dev, WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT); + OSL_SLEEP(50); // wait WLC_E_DISASSOC + } + if (wl_handle_join(cfg, dev, assoc_info)) + goto exit; + wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTING); + if (assoc_info->chan_cnt == 0) + max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT; + else + max_wait_time = STA_CONNECT_RETRY_TIMEOUT + + (WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS * assoc_info->chan_cnt); + max_wait_time = min(max_wait_time, STA_CONNECT_FULL_CHAN_TIMEOUT); + } + IAPSTA_INFO(dev->name, "reconnect %dms later\n", max_wait_time); + wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time); } - ret = -EAGAIN; + ret = BCME_ERROR; } +#ifdef WL_EXT_DISCONNECT_RECONNECT + else if (cur_if->conn_state >= CONN_STATE_CONNECTED && + !wl_get_drv_status(cfg, DISCONNECTING, dev) && + wl_get_drv_status(cfg, CONNECTED, dev)) { + if (etype == WLC_E_DISASSOC_IND || etype == WLC_E_DEAUTH_IND) { + /* There is one case will come in to retry join: + * 1) receive disconnect from AP after connected + */ + if (wl_ext_disc_recon_retry(apsta_params, cur_if)) { + int wpa_auth = 0; + WL_MSG(dev->name, "retry join cnt %d\n", cur_if->sta_disc_recon_cnt); + bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN); + wl_ext_update_assoc_info(dev, FALSE); +#ifdef DHD_LOSSLESS_ROAMING + wl_ext_send_event_msg(dev, WLC_E_ROAM_PREP, WLC_E_STATUS_SUCCESS, WLC_E_REASON_DEAUTH); +#endif + if (wl_handle_join(cfg, dev, assoc_info)) + goto exit; + wl_timer_mod(dhd, &cur_if->connect_timer, STA_CONNECT_TIMEOUT); + osl_do_gettimeofday(sta_conn_ts); + wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTING); + wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth); + if (!(wpa_auth & (WPA3_AUTH_SAE_PSK|0x20))) { + if (assoc_info->chan_cnt == 0) + max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT; + else + max_wait_time = STA_CONNECT_RETRY_TIMEOUT + + (WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS * assoc_info->chan_cnt); + max_wait_time = min(max_wait_time, STA_CONNECT_FULL_CHAN_TIMEOUT); + IAPSTA_INFO(dev->name, "reconnect %dms later\n", max_wait_time); + wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time); + } + ret = BCME_ERROR; + } + else { + WL_MSG(dev->name, "out of retry cnt %d within %dms\n", + cur_if->sta_disc_recon_cnt, STA_DISCONNECT_RECONNECT_TIMEOUT); + } + } + } +#endif /* WL_EXT_DISCONNECT_RECONNECT */ + +exit: mutex_unlock(&cfg->connect_sync); mutex_lock(&apsta_params->in4way_sync); @@ -2553,6 +2977,7 @@ wl_ext_connect_retry(struct net_device *dev, wl_event_msg_t *e) static void wl_ext_set_connect_retry(struct net_device *dev, void *context) { + struct dhd_pub *dhd = dhd_get_pub(dev); wlcfg_assoc_info_t *assoc_info = (wlcfg_assoc_info_t *)context; struct wl_if_info *cur_if; int max_wait_time; @@ -2562,18 +2987,20 @@ wl_ext_set_connect_retry(struct net_device *dev, void *context) if (!cur_if) return; - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->reconnect_timer, 0); memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t)); wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth); if (!(wpa_auth & (WPA3_AUTH_SAE_PSK|0x20) && assoc_info)) { memcpy(&cur_if->bssid, assoc_info->bssid, ETHER_ADDR_LEN); memcpy(&cur_if->assoc_info, assoc_info, sizeof(wlcfg_assoc_info_t)); - if (assoc_info->reassoc) + if (assoc_info->chan_cnt == 0) + max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT; + else if (assoc_info->reassoc) max_wait_time = STA_RECONNECT_RETRY_TIMEOUT; else max_wait_time = STA_CONNECT_RETRY_TIMEOUT; IAPSTA_INFO(dev->name, "reconnect %dms later\n", max_wait_time); - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, max_wait_time); + wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time); } } #endif /* WL_EXT_RECONNECT */ @@ -2951,7 +3378,7 @@ wl_ext_free_eapol_txpkt(struct wl_if_info *cur_if, bool rx) #ifdef BCMDBUS if (!rx) #endif /* BCMDBUS */ - wl_ext_mod_timer(&cur_if->eapol_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->eapol_timer, 0); if (cur_if->pend_eapol_pkt) { PKTCFREE(dhd->osh, cur_if->pend_eapol_pkt, TRUE); @@ -3010,7 +3437,7 @@ wl_ext_backup_eapol_txpkt(dhd_pub_t *dhd, int ifidx, void *pkt) #else interval = STA_EAPOL_TIMEOUT; #endif /* EAPOL_DYNAMATIC_RESEND */ - wl_ext_mod_timer(&cur_if->eapol_timer, 0, interval); + wl_timer_mod(dhd, &cur_if->eapol_timer, interval); IAPSTA_TRACE(cur_if->dev->name, "backup eapol pkt\n"); } spin_unlock_irqrestore(&apsta_params->eapol_lock, flags); @@ -3044,7 +3471,7 @@ wl_resend_eapol_handler(struct wl_if_info *cur_if, cur_if->eapol_max_intvl, STA_EAPOL_TIMEOUT, cur_if->eapol_cnt); #else - IAPSTA_INFO(dev->name, "resend eapol pkt %d\n", STA_EAPOL_TIMEOUT); + IAPSTA_INFO(dev->name, "resend eapol pkt %dms\n", STA_EAPOL_TIMEOUT); #endif /* EAPOL_DYNAMATIC_RESEND */ pending = TRUE; } @@ -3080,11 +3507,106 @@ wl_eapol_timer(unsigned long data) } #endif /* EAPOL_RESEND */ +#ifdef KEY_INSTALL_CHECK +static void +wl_ext_key_install_timeout(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct dhd_pub *dhd; + wl_event_msg_t msg; + + if (!dev) { + IAPSTA_ERROR("wlan", "dev is not ready\n"); + return; + } + + dhd = dhd_get_pub(dev); + + bzero(&msg, sizeof(wl_event_msg_t)); + IAPSTA_TRACE(dev->name, "timer expired\n"); + + msg.ifidx = dhd_net2idx(dhd->info, dev); + msg.event_type = hton32(WLC_E_RESERVED); + msg.reason = hton32(ISAM_RC_KEY_INSTALL); + wl_ext_event_send(dhd->event_params, &msg, NULL); +} + +static void +wl_ext_key_install_handler(struct wl_if_info *cur_if, + const wl_event_msg_t *e, void *data) +{ + struct net_device *dev = cur_if->dev; + struct dhd_pub *dhd = dhd_get_pub(dev); + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + uint32 etype = ntoh32(e->event_type); + uint32 reason = ntoh32(e->reason); + int err, key_installed = 0; + + if (etype == WLC_E_RESERVED && reason == ISAM_RC_KEY_INSTALL) { + if (cur_if->conn_state >= CONN_STATE_4WAY_M4 && + !wl_get_drv_status(cfg, DISCONNECTING, dev) && + wl_get_drv_status(cfg, CONNECTED, dev)) { + err = wldev_iovar_getint(dev, "buf_key_b4_m4_installed", &key_installed); + if (!err && !key_installed) { + cur_if->key_install_cnt++; + if (cur_if->key_install_cnt > STA_KEY_INSTALL_MAX) { + IAPSTA_ERROR(dev->name, "key not installed, send disconnect\n"); +#ifdef EAPOL_RESEND + wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); +#endif /* EAPOL_RESEND */ + wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED); + wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1); + wl_timer_mod(dhd, &cur_if->key_install_timer, 0); + cur_if->key_install_cnt = 0; + } else { + IAPSTA_INFO(dev->name, "check key installed %dms later, cnt=%d\n", + STA_KEY_INSTALL_INTERVAL, cur_if->key_install_cnt); + wl_timer_mod(dhd, &cur_if->key_install_timer, STA_KEY_INSTALL_INTERVAL); + } + } else { +#ifdef EAPOL_RESEND + wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); +#endif /* EAPOL_RESEND */ + IAPSTA_INFO(dev->name, "key installed\n"); + wl_timer_mod(dhd, &cur_if->connect_timer, 0); + wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED); + cur_if->key_install_cnt = 0; + } + } + } + return; +} + +static int +wl_key_installed(struct wl_if_info *cur_if) +{ + struct net_device *dev = cur_if->dev; + dhd_pub_t *dhd = dhd_get_pub(dev); + int err, key_installed = 0; + + err = wldev_iovar_getint(dev, "buf_key_b4_m4_installed", &key_installed); + if (err) { + IAPSTA_INFO(dev->name, "not supported %d\n", err); + key_installed = 1; + } else if (key_installed) + IAPSTA_INFO(dev->name, "key installed\n"); + + if (key_installed) + wl_timer_mod(dhd, &cur_if->key_install_timer, 0); + else { + IAPSTA_INFO(dev->name, "check key installed %dms later\n", STA_KEY_INSTALL_INTERVAL); + wl_timer_mod(dhd, &cur_if->key_install_timer, STA_KEY_INSTALL_INTERVAL); + } + + return key_installed; +} +#endif /* KEY_INSTALL_CHECK */ + #if defined(WL_CFG80211) && defined(SCAN_SUPPRESS) static void wl_ext_light_scan_prep(struct net_device *dev, void *scan_params, bool scan_v2) { - wl_scan_params_t *params = NULL; + wl_scan_params_v1_t *params = NULL; wl_scan_params_v2_t *params_v2 = NULL; if (!scan_params) { @@ -3096,7 +3618,7 @@ wl_ext_light_scan_prep(struct net_device *dev, void *scan_params, bool scan_v2) if (scan_v2) { params_v2 = (wl_scan_params_v2_t *)scan_params; } else { - params = (wl_scan_params_t *)scan_params; + params = (wl_scan_params_v1_t *)scan_params; } if (params_v2) { @@ -3130,7 +3652,7 @@ wl_ext_max_tput_chan(struct wl_apsta_params *apsta_params, tmp_if = &apsta_params->if_info[i]; if (tmp_if->dev && (tmp_if->tput_info.tput_tx + tmp_if->tput_info.tput_rx) > tput_sum) { memset(chan_info, 0, sizeof(struct wl_chan_info)); - wl_ext_get_chan(apsta_params, tmp_if->dev, chan_info); + wl_ext_get_chan(tmp_if->dev, chan_info); if (chan_info->chan) { max_tput_if = tmp_if; tput_sum = tmp_if->tput_info.tput_tx + tmp_if->tput_info.tput_rx; @@ -3269,7 +3791,6 @@ wl_set_btc_in4way(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_i } } } - } static void @@ -3277,7 +3798,7 @@ wl_wait_disconnect(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_ enum wl_ext_status status) { struct net_device *dev = cur_if->dev; - struct osl_timespec cur_ts, *sta_disc_ts = &apsta_params->sta_disc_ts; + struct osl_timespec cur_ts, *sta_disc_ts = &cur_if->sta_disc_ts; int max_wait_time = 200, max_wait_cnt = 20; int cur_conn_state = cur_if->conn_state; uint32 diff_ms = 0; @@ -3327,8 +3848,7 @@ wl_iapsta_suspend_resume_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, if (suspend) { if (insuspend & AP_DOWN_IN_SUSPEND) { - cur_if->chan_info.chan = wl_ext_get_chan(apsta_params, cur_if->dev, - &cur_if->chan_info); + cur_if->chan_info.chan = wl_ext_get_chan(cur_if->dev, &cur_if->chan_info); if (cur_if->chan_info.chan) wl_ext_if_down(apsta_params, cur_if); } @@ -3351,7 +3871,7 @@ wl_iapsta_suspend_resume(dhd_pub_t *dhd, int suspend) #ifdef TPUT_MONITOR if (suspend) - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, 0); + wl_timer_mod(dhd, &apsta_params->monitor_timer, 0); #endif /* TPUT_MONITOR */ for (i=0; imonitor_timer, 0, dhd->conf->tput_monitor_ms); + wl_timer_mod(dhd, &apsta_params->monitor_timer, dhd->conf->tput_monitor_ms); #endif /* TPUT_MONITOR */ return 0; @@ -3383,11 +3903,11 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct dhd_conf *conf = dhd->conf; struct net_device *dev = cur_if->dev; - struct osl_timespec cur_ts, *sta_disc_ts = &apsta_params->sta_disc_ts; - struct osl_timespec *sta_conn_ts = &apsta_params->sta_conn_ts; + struct osl_timespec cur_ts, *sta_disc_ts = &cur_if->sta_disc_ts; + struct osl_timespec *sta_conn_ts = &cur_if->sta_conn_ts; uint32 diff_ms = 0; - int ret = 0, cur_conn_state; - int suppressed = 0, wpa_auth = 0; + int ret = 0, suppressed = 0, wpa_auth = 0, max_wait_time = 0, key_installed = 1; + uint cur_conn_state, conn_state; bool connecting = FALSE; wl_event_msg_t *e = (wl_event_msg_t *)context; #ifdef WL_CFG80211 @@ -3438,7 +3958,8 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, osl_do_gettimeofday(&cur_ts); diff_ms = osl_do_gettimediff(&cur_ts, sta_conn_ts)/1000; if (connecting && diff_ms <= STA_CONNECT_TIMEOUT) { - IAPSTA_ERROR(dev->name, "connecting... %d\n", cur_conn_state); + IAPSTA_ERROR(dev->name, "scan during connecting... %d\n", + cur_conn_state); ret = -EBUSY; break; } @@ -3452,24 +3973,15 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, if (wl_get_drv_status(cfg, CONNECTING, dev) || (connecting && diff_ms <= STA_CONNECT_TIMEOUT) || (cur_if->empty_scan >= STA_EMPTY_SCAN_MAX)) { - unsigned long flags = 0; cur_if->empty_scan = 0; - spin_lock_irqsave(&dhd->up_lock, flags); - if (dhd->up) { - wl_event_msg_t msg; - bzero(&msg, sizeof(wl_event_msg_t)); - msg.event_type = hton32(WLC_E_ESCAN_RESULT); - msg.status = hton32(WLC_E_STATUS_SUCCESS); - WL_MSG(dev->name, "FAKE SCAN\n"); - wl_cfg80211_event(dev, &msg, NULL); - ret = -EBUSY; - } - spin_unlock_irqrestore(&dhd->up_lock, flags); + WL_MSG(dev->name, "FAKE SCAN\n"); + ret = -EBUSY; } } break; case WL_EXT_STATUS_SCAN_COMPLETE: - if ((conf->war & FW_REINIT_EMPTY_SCAN) && cfg->bss_list->count == 0) { + if ((conf->war & FW_REINIT_EMPTY_SCAN) && + cfg->bss_list->count == 0 && !p2p_scan(cfg)) { bool assoc; osl_do_gettimeofday(&cur_ts); diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_ts)/1000; @@ -3494,18 +4006,26 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, } break; #endif /* WL_CFG80211 */ - case WL_EXT_STATUS_DISCONNECTING: + case WL_EXT_STATUS_PRE_DISCONNECTING: #ifdef EAPOL_RESEND wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); #endif /* EAPOL_RESEND */ - wl_ext_mod_timer(&cur_if->connect_timer, 0, 0); +#ifdef KEY_INSTALL_CHECK + wl_timer_mod(dhd, &cur_if->key_install_timer, 0); +#endif /* KEY_INSTALL_CHECK */ + wl_timer_mod(dhd, &cur_if->connect_timer, 0); #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->reconnect_timer, 0); memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t)); +#ifdef WL_EXT_DISCONNECT_RECONNECT + cur_if->sta_disc_recon_cnt = 0; +#endif /* WL_EXT_DISCONNECT_RECONNECT */ #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ #ifdef SCAN_SUPPRESS apsta_params->scan_busy_cnt = 0; #endif /* SCAN_SUPPRESS */ + break; + case WL_EXT_STATUS_DISCONNECTING: if (connecting) { IAPSTA_ERROR(dev->name, "connect failed at %d\n", cur_conn_state); wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_IDLE); @@ -3513,6 +4033,9 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, if (action & STA_NO_BTC_IN4WAY) { wl_set_btc_in4way(apsta_params, cur_if, status, FALSE); } +#ifdef BTC_WAR + wl_ext_btc_config(cur_if->dev, FALSE); +#endif /* BTC_WAR */ if (action & STA_WAIT_DISCONNECTED) { wl_wait_disconnect(apsta_params, cur_if, status); wake_up_interruptible(&conf->event_complete); @@ -3523,8 +4046,11 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, if (action & STA_REASSOC_RETRY) { wl_ext_set_connect_retry(dev, context); } +#ifdef WL_EXT_DISCONNECT_RECONNECT + cur_if->sta_disc_recon_cnt = 0; +#endif /* WL_EXT_DISCONNECT_RECONNECT */ #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ - wl_ext_mod_timer(&cur_if->connect_timer, 0, STA_CONNECT_TIMEOUT); + wl_timer_mod(dhd, &cur_if->connect_timer, STA_CONNECT_TIMEOUT); osl_do_gettimeofday(sta_conn_ts); wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTING); if (action & STA_NO_BTC_IN4WAY) { @@ -3534,12 +4060,21 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, case WL_EXT_STATUS_CONNECTED: wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth); if ((wpa_auth < WPA_AUTH_UNSPECIFIED) || (wpa_auth & WPA2_AUTH_FT)) { - wl_ext_mod_timer(&cur_if->connect_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->connect_timer, 0); wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED); +#ifdef BTC_WAR + wl_ext_btc_config(cur_if->dev, TRUE); +#endif /* BTC_WAR */ + max_wait_time = 0; + } else { + wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_ASSOCIATED); + max_wait_time = STA_4WAY_TIMEOUT; } #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); - memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t)); + if (action & STA_REASSOC_RETRY) { + wl_ext_update_assoc_info(dev, TRUE); + wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time); + } #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ if (cur_if->ifmode == ISTA_MODE) { dhd_conf_set_wme(dhd, cur_if->ifidx, 0); @@ -3549,6 +4084,35 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, dhd_conf_set_mchan_bw(dhd, WL_P2P_IF_CLIENT, -1); } break; + case WL_EXT_STATUS_ROAMED: + wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth); + if ((wpa_auth >= WPA_AUTH_UNSPECIFIED) && !(wpa_auth & WPA2_AUTH_FT)) { + if (cur_if->conn_state >= CONN_STATE_CONNECTED) { + wl_timer_mod(dhd, &cur_if->connect_timer, STA_CONNECT_TIMEOUT); + osl_do_gettimeofday(sta_conn_ts); + } + wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTING); +#ifdef BTC_WAR + wl_ext_btc_config(cur_if->dev, TRUE); +#endif /* BTC_WAR */ + max_wait_time = STA_4WAY_TIMEOUT; + } else { + max_wait_time = 0; + } +#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) + if (action & STA_REASSOC_RETRY) { + wl_ext_update_assoc_info(dev, TRUE); + wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time); + } +#endif /* WL_EXT_RECONNECT && WL_CFG80211 */ +#ifdef KEY_INSTALL_CHECK + wl_timer_mod(dhd, &cur_if->key_install_timer, 0); +#endif /* KEY_INSTALL_CHECK */ + if (cur_if->ifmode == ISTA_MODE) { + dhd_conf_set_wme(dhd, cur_if->ifidx, 0); + wake_up_interruptible(&conf->event_complete); + } + break; case WL_EXT_STATUS_RECONNECT: #ifdef EAPOL_RESEND wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); @@ -3563,9 +4127,15 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, #ifdef EAPOL_RESEND wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); #endif /* EAPOL_RESEND */ +#ifdef KEY_INSTALL_CHECK + wl_timer_mod(dhd, &cur_if->key_install_timer, 0); +#endif /* KEY_INSTALL_CHECK */ #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->reconnect_timer, 0); memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t)); +#ifdef WL_EXT_DISCONNECT_RECONNECT + cur_if->sta_disc_recon_cnt = 0; +#endif /* WL_EXT_DISCONNECT_RECONNECT */ #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ #ifdef SCAN_SUPPRESS apsta_params->scan_busy_cnt = 0; @@ -3574,7 +4144,7 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, !(ntoh16(e->flags) & WLC_EVENT_MSG_LINK)) { apsta_params->linkdown_reason = ntoh32(e->reason); } - wl_ext_mod_timer(&cur_if->connect_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->connect_timer, 0); if (connecting) { IAPSTA_ERROR(dev->name, "connect failed at %d\n", cur_conn_state); } @@ -3582,23 +4152,39 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, if (action & STA_NO_BTC_IN4WAY) { wl_set_btc_in4way(apsta_params, cur_if, status, FALSE); } +#ifdef BTC_WAR + wl_ext_btc_config(cur_if->dev, FALSE); +#endif /* BTC_WAR */ osl_do_gettimeofday(sta_disc_ts); wake_up_interruptible(&conf->event_complete); break; case WL_EXT_STATUS_ADD_KEY: - wl_ext_mod_timer(&cur_if->connect_timer, 0, 0); - wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED); -#ifdef EAPOL_RESEND - wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); -#endif /* EAPOL_RESEND */ + conn_state = CONN_STATE_ADD_KEY; + wl_timer_mod(dhd, &cur_if->connect_timer, 0); #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->reconnect_timer, 0); #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ +#ifdef KEY_INSTALL_CHECK + if (wpa_auth != WPA_AUTH_DISABLED && wpa_auth != WPA_AUTH_PSK) { + key_installed = wl_key_installed(cur_if); + } +#endif /* KEY_INSTALL_CHECK */ + if (key_installed) + conn_state = CONN_STATE_CONNECTED; + IAPSTA_INFO(dev->name, "WPA 4-WAY complete %d => %d\n", + cur_conn_state, conn_state); + wl_ext_update_conn_state(dhd, cur_if->ifidx, conn_state); +#ifdef EAPOL_RESEND + if (key_installed) + wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); +#endif /* EAPOL_RESEND */ if (action & STA_NO_BTC_IN4WAY) { wl_set_btc_in4way(apsta_params, cur_if, status, FALSE); } +#ifdef BTC_WAR + wl_ext_btc_config(cur_if->dev, TRUE); +#endif /* BTC_WAR */ wake_up_interruptible(&conf->event_complete); - IAPSTA_INFO(dev->name, "WPA 4-WAY complete %d\n", cur_conn_state); break; default: IAPSTA_INFO(dev->name, "Unknown action=0x%x, status=%d\n", action, status); @@ -3614,8 +4200,8 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, { struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct net_device *dev = cur_if->dev; - struct osl_timespec cur_ts, *ap_disc_sta_ts = &apsta_params->ap_disc_sta_ts; - u8 *ap_disc_sta_bssid = (u8*)&apsta_params->ap_disc_sta_bssid; + struct osl_timespec cur_ts, *ap_disc_sta_ts = &cur_if->ap_disc_sta_ts; + u8 *ap_disc_sta_bssid = (u8*)&cur_if->ap_disc_sta_bssid; uint32 diff_ms = 0, timeout, max_wait_time = 300; int ret = 0, suppressed = 0; u8* mac_addr = context; @@ -3636,12 +4222,12 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, break; case WL_EXT_STATUS_AP_ENABLING: #ifdef RESTART_AP_WAR - wl_ext_mod_timer(&cur_if->restart_ap_timer, AP_RESTART_TIMEOUT, 0); + wl_timer_mod(dhd, &cur_if->restart_ap_timer, AP_RESTART_TIMEOUT); #endif /* RESTART_AP_WAR */ break; case WL_EXT_STATUS_AP_ENABLED: #ifdef RESTART_AP_WAR - wl_ext_mod_timer(&cur_if->restart_ap_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->restart_ap_timer, 0); #endif /* RESTART_AP_WAR */ if (cur_if->ifmode == IAP_MODE) dhd_conf_set_wme(dhd, cur_if->ifidx, 1); @@ -3650,7 +4236,7 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, break; case WL_EXT_STATUS_AP_DISABLING: #ifdef RESTART_AP_WAR - wl_ext_mod_timer(&cur_if->restart_ap_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->restart_ap_timer, 0); #endif /* RESTART_AP_WAR */ break; case WL_EXT_STATUS_DELETE_STA: @@ -3668,13 +4254,13 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, } if (wait) { IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d, waiting %dms ...\n", - status, apsta_params->ap_recon_sta, max_wait_time); + status, cur_if->ap_recon_sta, max_wait_time); mutex_unlock(&apsta_params->in4way_sync); - timeout = wait_event_interruptible_timeout(apsta_params->ap_recon_sta_event, - apsta_params->ap_recon_sta, msecs_to_jiffies(max_wait_time)); + timeout = wait_event_interruptible_timeout(cur_if->ap_recon_sta_event, + cur_if->ap_recon_sta, msecs_to_jiffies(max_wait_time)); mutex_lock(&apsta_params->in4way_sync); IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d, timeout=%d\n", - status, apsta_params->ap_recon_sta, timeout); + status, cur_if->ap_recon_sta, timeout); if (timeout > 0) { IAPSTA_INFO(dev->name, "skip delete STA %pM\n", mac_addr); ret = -1; @@ -3682,8 +4268,8 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, } } else { IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d => 0\n", - status, apsta_params->ap_recon_sta); - apsta_params->ap_recon_sta = FALSE; + status, cur_if->ap_recon_sta); + cur_if->ap_recon_sta = FALSE; if (cur_if->ifmode == IGO_MODE) wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_IDLE); } @@ -3692,10 +4278,10 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, case WL_EXT_STATUS_STA_DISCONNECTED: if (action & AP_WAIT_STA_RECONNECT) { IAPSTA_INFO(dev->name, "latest disc STA %pM ap_recon_sta=%d\n", - ap_disc_sta_bssid, apsta_params->ap_recon_sta); + ap_disc_sta_bssid, cur_if->ap_recon_sta); osl_do_gettimeofday(ap_disc_sta_ts); memcpy(ap_disc_sta_bssid, mac_addr, ETHER_ADDR_LEN); - apsta_params->ap_recon_sta = FALSE; + cur_if->ap_recon_sta = FALSE; } break; case WL_EXT_STATUS_STA_CONNECTED: @@ -3705,11 +4291,11 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, if (diff_ms < max_wait_time && !memcmp(ap_disc_sta_bssid, mac_addr, ETHER_ADDR_LEN)) { IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d => 1\n", - status, apsta_params->ap_recon_sta); - apsta_params->ap_recon_sta = TRUE; - wake_up_interruptible(&apsta_params->ap_recon_sta_event); + status, cur_if->ap_recon_sta); + cur_if->ap_recon_sta = TRUE; + wake_up_interruptible(&cur_if->ap_recon_sta_event); } else { - apsta_params->ap_recon_sta = FALSE; + cur_if->ap_recon_sta = FALSE; } } break; @@ -3781,7 +4367,7 @@ wl_ext_update_extsae_4way(struct net_device *dev, else conn_state = CONN_STATE_AUTH_SAE_M1; } else if (auth_seq == 2) { - if (tx) + if (tx) conn_state = CONN_STATE_AUTH_SAE_M4; else conn_state = CONN_STATE_AUTH_SAE_M3; @@ -3807,7 +4393,8 @@ wl_ext_update_extsae_4way(struct net_device *dev, } } } else { - WL_ERR(("Unknown auth_alg=%d or auth_seq=%d\n", auth_alg, auth_seq)); + IAPSTA_ERROR(dev->name, "Unknown auth_alg=%d or auth_seq=%d\n", + auth_alg, auth_seq); } return; @@ -3887,6 +4474,150 @@ wl_ext_assoclist_num(struct net_device *dev) return maxassoc; } +static int +dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); + dhd_ioctl_t ioc; + int8 index; + int ret; + + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; + + index = dhd_net2idx(dhd->info, dev); + if (index == DHD_BAD_IF) { + IAPSTA_ERROR(dev->name, "Bad ifidx from dev\n"); + return -ENODEV; + } + ret = dhd_ioctl_process(dhd, index, &ioc, arg); + + return ret; +} + +static void +wl_ampdu_dump(struct net_device *dev) +{ + char *ioctl_buf = g_ioctl_buf, *buf = NULL; + char *tx_pch_start, *tx_pch_end, *rx_pch_start, *rx_pch_end; + int ret = 0, max_len, tx_len, rx_len; + + if (!(android_msg_level & ANDROID_AMPDU_LEVEL)) + return; + + memset(ioctl_buf, 0, WL_DUMP_BUF_LEN); + ret = bcm_mkiovar("dump", "ampdu", strlen("ampdu"), ioctl_buf, WL_DUMP_BUF_LEN); + if (ret == 0) { + goto exit; + } + ret = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctl_buf, WL_DUMP_BUF_LEN); + if (ret) { + goto exit; + } + + buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); + if (buf == NULL) { + IAPSTA_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_MEDLEN); + goto exit; + } + memset(buf, 0, WLC_IOCTL_MEDLEN); + ret = bcm_mkiovar("dump_clear", "ampdu", strlen("ampdu"), buf, WLC_IOCTL_MEDLEN); + if (ret == 0) { + goto exit; + } + ret = dev_wlc_ioctl(dev, WLC_SET_VAR, (void *)buf, WLC_IOCTL_MEDLEN); + if (ret) { + goto exit; + } + + tx_pch_start = strstr(ioctl_buf, "TX MCS"); + tx_pch_end = strstr(ioctl_buf, "HEMU"); + rx_pch_start = strstr(ioctl_buf, "RX MCS"); + rx_pch_end = strstr(ioctl_buf, "RX MCS SGI"); + max_len = (tx_pch_end-tx_pch_start) + (rx_pch_end-rx_pch_start); + if (max_len > (WLC_IOCTL_MEDLEN-1)) + goto exit; + + tx_len = tx_pch_end - tx_pch_start; + rx_len = rx_pch_end - rx_pch_start; + + memset(buf, 0, WLC_IOCTL_MEDLEN); + memcpy(buf, tx_pch_start, tx_len); + memcpy(buf+tx_len, rx_pch_start, rx_len); + WL_MSG(dev->name,"\n%s\n", buf); + +exit: + if (buf) + kfree(buf); +} + +static void +wl_btc_dump(struct net_device *dev) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); + int ret, val; + + if (!(android_msg_level & ANDROID_BTC_LEVEL)) + return; + + ret = dhd_conf_reg2args(dhd, "btc_params", FALSE, 15, &val); + if (!ret) + WL_MSG(dev->name,"btc_params15=%d\n", val); +} + +static void +wl_tvpm_dump(struct net_device *dev) +{ + wl_tvpm_req_t* tvpm_req = NULL; + size_t reqlen = sizeof(wl_tvpm_req_t) + sizeof(wl_tvpm_status_t); + uint8 *outbuf = g_ioctl_buf; + size_t outlen = WLC_IOCTL_MEDLEN; + wl_tvpm_status_t* status; + int ret, phy_temp = 0; + bool tvpm = FALSE, sense = FALSE; + + if (!(android_msg_level & ANDROID_TVPM_LEVEL)) + return; + + tvpm_req = kmalloc(reqlen, GFP_KERNEL); + if (tvpm_req == NULL) { + IAPSTA_ERROR(dev->name, "MALLOC failed\n"); + goto exit; + } + memset(tvpm_req, 0, reqlen); + + tvpm_req->version = TVPM_REQ_VERSION_1; + tvpm_req->length = reqlen; + tvpm_req->req_type = WL_TVPM_REQ_STATUS; + ret = wldev_iovar_getbuf(dev, "tvpm", tvpm_req, reqlen, outbuf, outlen, NULL); + status = (wl_tvpm_status_t*)outbuf; + if (!ret && status->enable) { + tvpm = TRUE; + } else { + ret = wldev_iovar_getbuf(dev, "phy_tempsense", &phy_temp, sizeof(phy_temp), + outbuf, outlen, NULL); + if (!ret) { + phy_temp = dtoh32(*(int*)outbuf); + sense = TRUE; + } + } + + if (tvpm) { + WL_MSG(dev->name,"temp=%3d, duty=%3d, pwrbko=%d, chains=%d\n", + status->temp, status->tx_dutycycle, status->tx_power_backoff, + status->num_active_chains); + } + else if (sense) { + WL_MSG(dev->name,"phy_temp=%3d\n", phy_temp); + } + +exit: + if (tvpm_req) + kfree(tvpm_req); +} + static void wl_phy_rssi_ant(struct net_device *dev, struct ether_addr *mac, char *rssi_buf, int len) @@ -3912,6 +4643,8 @@ wl_phy_rssi_ant(struct net_device *dev, struct ether_addr *mac, wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0); rssi_ant_p->count = 1; rssi_ant_p->rssi_ant[0] = dtoh32(scb_val.val); + } else { + rssi_ant_p->count = 0; } } for (i=0; icount && rssi_ant_p->rssi_ant[i]; i++) { @@ -3937,17 +4670,12 @@ wl_tput_dump(struct wl_apsta_params *apsta_params, static void wl_sta_info_dump(struct net_device *dev, struct ether_addr *mac) { - void *buf = NULL; + void *buf = g_ioctl_buf; sta_info_v4_t *sta = NULL; char rssi_buf[16]; int ret; s32 rate = 0; - buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); - if (buf == NULL) { - IAPSTA_ERROR(dev->name, "MALLOC failed\n"); - goto exit; - } memset(rssi_buf, 0, sizeof(rssi_buf)); wl_phy_rssi_ant(dev, mac, rssi_buf, sizeof(rssi_buf)); ret = wldev_iovar_getbuf(dev, "sta_info", (const void*)mac, @@ -3955,22 +4683,27 @@ wl_sta_info_dump(struct net_device *dev, struct ether_addr *mac) if (ret == 0) { sta = (sta_info_v4_t *)buf; } - if (sta == NULL || (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5)) { + if (sta == NULL || (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5 && + sta->ver != WL_STA_VER_6)) { wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate)); rate = dtoh32(rate); WL_MSG(dev->name, "mac=%pM, rssi=%s, tx_rate:%4d%2s\n", mac, rssi_buf, rate/2, (rate & 1) ? ".5" : ""); } else { - WL_MSG(dev->name, - "mac=%pM, rssi=%s, tx_rate:%4d.%d, rx_rate:%4d.%d\n", mac, rssi_buf, - dtoh32(sta->tx_rate)/1000, ((dtoh32(sta->tx_rate)/100)%10), - dtoh32(sta->rx_rate)/1000, ((dtoh32(sta->rx_rate)/100)%10)); - } - -exit: - if (buf) { - kfree(buf); + if (dtoh32(sta->rx_rate) != -1) { + WL_MSG(dev->name, + "mac=%pM, rssi=%s, tx_rate:%4d.%d, rx_rate:%4d.%d\n", + mac, rssi_buf, + dtoh32(sta->tx_rate)/1000, ((dtoh32(sta->tx_rate)/100)%10), + dtoh32(sta->rx_rate)/1000, ((dtoh32(sta->rx_rate)/100)%10)); + } else { + WL_MSG(dev->name, + "mac=%pM, rssi=%s, tx_rate:%4d.%d, rx_rate:%4d\n", + mac, rssi_buf, + dtoh32(sta->tx_rate)/1000, ((dtoh32(sta->tx_rate)/100)%10), + dtoh32(sta->rx_rate)); + } } } @@ -3979,7 +4712,6 @@ wl_cur_if_tput_dump(struct wl_apsta_params *apsta_params, struct wl_if_info *cur { #ifdef WLDWDS struct wl_dwds_info *dwds_if; - int i; #endif /* WLDWDS */ struct ether_addr bssid; int ret = 0; @@ -4063,10 +4795,11 @@ wl_tput_monitor(struct dhd_pub *dhd, int ifidx, struct wl_tput_info *tput_info) } static void -wl_tput_monitor_handler(struct wl_apsta_params *apsta_params, - struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data) +wl_tput_monitor_handler(struct wl_if_info *cur_if, + const wl_event_msg_t *e, void *data) { - struct dhd_pub *dhd = apsta_params->dhd; + struct dhd_pub *dhd = dhd_get_pub(cur_if->dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; wl_tput_info_t *tput_info; struct wl_if_info *tmp_if; #ifdef WLDWDS @@ -4087,7 +4820,7 @@ wl_tput_monitor_handler(struct wl_apsta_params *apsta_params, tmp_if = &apsta_params->if_info[i]; if (tmp_if->dev && (tmp_if->ifmode == ISTA_MODE || tmp_if->ifmode == IGC_MODE) && - wl_ext_associated(tmp_if->dev)) { + wl_get_isam_status(tmp_if, STA_CONNECTED)) { wl_tput_monitor(dhd, tmp_if->ifidx, &tmp_if->tput_info); monitor_if[i] = TRUE; } @@ -4123,8 +4856,12 @@ wl_tput_monitor_handler(struct wl_apsta_params *apsta_params, monitor = TRUE; } } - if (monitor) - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, timeout); + if (monitor) { + wl_btc_dump(cur_if->dev); + wl_tvpm_dump(cur_if->dev); + wl_ampdu_dump(cur_if->dev); + wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout); + } #ifdef BCMSDIO if (apsta_params->tput_sum >= dhd->conf->doflow_tput_thresh && dhd_doflow) { dhd_doflow = FALSE; @@ -4140,9 +4877,9 @@ wl_tput_monitor_handler(struct wl_apsta_params *apsta_params, else if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) { if (etype == WLC_E_LINK) { if (flags & WLC_EVENT_MSG_LINK) { - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, timeout); + wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout); } else if (!wl_ext_iapsta_other_if_enabled(cur_if->dev)) { - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, 0); + wl_timer_mod(dhd, &apsta_params->monitor_timer, 0); } } } @@ -4150,33 +4887,22 @@ wl_tput_monitor_handler(struct wl_apsta_params *apsta_params, if ((etype == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) || (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && reason == WLC_E_REASON_INITIAL_ASSOC)) { - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, timeout); + wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout); } else if ((etype == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) || (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && reason == WLC_E_REASON_DEAUTH)) { if (!wl_ext_iapsta_other_if_enabled(cur_if->dev)) { - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, 0); + wl_timer_mod(dhd, &apsta_params->monitor_timer, 0); } } else if ((etype == WLC_E_ASSOC_IND || etype == WLC_E_REASSOC_IND) && reason == DOT11_SC_SUCCESS) { - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, timeout); + wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout); } } } #endif /* TPUT_MONITOR */ #ifdef ACS_MONITOR -static void -wl_ext_mod_timer_pending(timer_list_compat_t *timer, uint sec, uint msec) -{ - uint timeout = sec * 1000 + msec; - - if (timeout && !timer_pending(timer)) { - IAPSTA_TRACE("wlan", "timeout=%d\n", timeout); - mod_timer(timer, jiffies + msecs_to_jiffies(timeout)); - } -} - static bool wl_ext_max_prio_if(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) @@ -4214,7 +4940,7 @@ wl_ext_acs_scan(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) cur_scan_time = wl_ext_set_scan_time(cur_if->dev, 80, WLC_GET_SCAN_CHANNEL_TIME, WLC_SET_SCAN_CHANNEL_TIME); WL_MSG(cur_if->dev->name, "ACS_SCAN\n"); - wl_ext_drv_scan(cur_if->dev, WLC_BAND_AUTO, FALSE); + wl_escan_drv_acs_scan(cur_if->dev, WLC_BAND_2G|WLC_BAND_5G, NULL); if (cur_scan_time) { ret = wl_ext_ioctl(cur_if->dev, WLC_SET_SCAN_CHANNEL_TIME, &cur_scan_time, sizeof(cur_scan_time), 1); @@ -4231,7 +4957,7 @@ wl_ext_acs(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) if (apsta_params->acs & ACS_DRV_BIT) { mutex_lock(&apsta_params->usr_sync); memset(&chan_info, 0, sizeof(struct wl_chan_info)); - wl_ext_get_chan(apsta_params, cur_if->dev, &chan_info); + wl_ext_get_chan(cur_if->dev, &chan_info); if (chan_info.chan) { if (chan_info.band == WLC_BAND_5G) cur_if->chan_info.chan = cur_if->escan->best_5g_ch; @@ -4240,7 +4966,7 @@ wl_ext_acs(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) wl_ext_move_cur_channel(apsta_params, cur_if); if (!wl_ext_same_chan(&cur_if->chan_info, &chan_info)) { WL_MSG(cur_if->dev->name, "move channel %s-%d => %s-%d\n", - WLCBAND2STR(chan_info->band), chan_info.chan, + WLCBAND2STR(chan_info.band), chan_info.chan, WLCBAND2STR(cur_if->chan_info.band), cur_if->chan_info.chan); wl_ext_if_down(apsta_params, cur_if); wl_ext_move_other_channel(apsta_params, cur_if); @@ -4289,34 +5015,34 @@ wl_acs_handler(struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data) (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && reason == WLC_E_REASON_INITIAL_ASSOC)) { // Link up - wl_ext_mod_timer_pending(&cur_if->acs_timer, acs_tmo, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, acs_tmo*1000); } else if ((etype == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) || (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && reason == WLC_E_REASON_DEAUTH)) { // Link down - wl_ext_mod_timer(&cur_if->acs_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, 0); cur_if->escan->autochannel = 0; } else if ((etype == WLC_E_ASSOC_IND || etype == WLC_E_REASSOC_IND) && reason == DOT11_SC_SUCCESS) { // external STA connected - wl_ext_mod_timer(&cur_if->acs_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, 0); } else if (etype == WLC_E_DISASSOC_IND || etype == WLC_E_DEAUTH_IND || (etype == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) { // external STA disconnected - wl_ext_mod_timer_pending(&cur_if->acs_timer, acs_tmo, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, acs_tmo*1000); } else if (etype == WLC_E_RESERVED && reason == ISAM_RC_AP_ACS) { // acs_tmo expired if (!wl_ext_assoclist_num(cur_if->dev) && !wl_ext_max_prio_if(apsta_params, cur_if)) { wl_ext_acs_scan(apsta_params, cur_if); - wl_ext_mod_timer(&cur_if->acs_timer, acs_tmo, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, acs_tmo*1000); } else { - wl_ext_mod_timer(&cur_if->acs_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, 0); } } else if (((etype == WLC_E_ESCAN_RESULT && status == WLC_E_STATUS_SUCCESS) || @@ -4330,7 +5056,7 @@ wl_acs_handler(struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data) !wl_ext_max_prio_if(apsta_params, cur_if)) { wl_ext_acs(apsta_params, cur_if); } else { - wl_ext_mod_timer(&cur_if->acs_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, 0); } } } @@ -4340,7 +5066,7 @@ static void wl_acs_detach(struct wl_if_info *cur_if) { IAPSTA_TRACE(cur_if->dev->name, "Enter\n"); - del_timer_sync(&cur_if->acs_timer); + wl_timer_deregister(cur_if->dev, &cur_if->acs_timer); if (cur_if->escan) { cur_if->escan = NULL; } @@ -4351,7 +5077,7 @@ wl_acs_attach(dhd_pub_t *dhd, struct wl_if_info *cur_if) { IAPSTA_TRACE(cur_if->dev->name, "Enter\n"); cur_if->escan = dhd->escan; - init_timer_compat(&cur_if->acs_timer, wl_acs_timer, cur_if->dev); + wl_timer_register(cur_if->dev, &cur_if->acs_timer, wl_acs_timer); } #endif /* ACS_MONITOR */ @@ -4394,7 +5120,7 @@ wl_ext_restart_ap_handler(struct wl_if_info *cur_if, WL_MSG(cur_if->ifname, "restart AP\n"); wl_ext_if_down(apsta_params, cur_if); wl_ext_if_up(apsta_params, cur_if, FALSE, 1); - wl_ext_mod_timer(&cur_if->restart_ap_timer, AP_RESTART_TIMEOUT, 0); + wl_timer_mod(dhd, &cur_if->restart_ap_timer, AP_RESTART_TIMEOUT); } else { WL_MSG(cur_if->ifname, "skip restart AP\n"); } @@ -4483,20 +5209,12 @@ wl_ext_counters_update(struct wl_if_info *cur_if, int war_reason) { struct dhd_pub *dhd = dhd_get_pub(cur_if->dev); struct wl_apsta_params *apsta_params = dhd->iapsta_params; - char *iovar_buf = NULL; + char *iovar_buf = g_ioctl_buf; uint32 corerev = 0; wl_cnt_info_t *cntinfo; uint16 ver; int ret = 0; - iovar_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); - if (!iovar_buf) { - IAPSTA_ERROR(cur_if->ifname, "no memory\n"); - ret = BCME_NOMEM; - goto exit; - } - - memset(iovar_buf, 0, WLC_IOCTL_MEDLEN); ret = wldev_iovar_getbuf(cur_if->dev, "counters", NULL, 0, iovar_buf, WLC_IOCTL_MEDLEN, NULL); if (unlikely(ret)) { @@ -4509,10 +5227,10 @@ wl_ext_counters_update(struct wl_if_info *cur_if, int war_reason) cntinfo->datalen = dtoh16(cntinfo->datalen); ver = cntinfo->version; CHK_CNTBUF_DATALEN(iovar_buf, WLC_IOCTL_MEDLEN); - if (ver > WL_CNT_T_VERSION) { + if (ver > WL_CNT_VERSION_XTLV) { IAPSTA_ERROR(cur_if->ifname, "Incorrect version of counters struct: expected %d; got %d\n", - WL_CNT_T_VERSION, ver); + WL_CNT_VERSION_XTLV, ver); goto exit; } @@ -4540,9 +5258,6 @@ wl_ext_counters_update(struct wl_if_info *cur_if, int war_reason) } exit: - if (iovar_buf) - kfree(iovar_buf); - return ret; } #endif /* RESET_AP_WAR | RXF0OVFL_REINIT_WAR */ @@ -4589,7 +5304,7 @@ wl_ext_reset_ap_handler(struct wl_if_info *cur_if, reason == WLC_E_REASON_INITIAL_ASSOC)) { // Link up wl_ext_counters_update(cur_if, ISAM_RC_AP_RESET); - wl_ext_mod_timer(&cur_if->reset_ap_timer, AP_TXBCNFRM_TIMEOUT, 0); + wl_timer_mod(dhd, &cur_if->reset_ap_timer, AP_TXBCNFRM_TIMEOUT); } else if (etype == WLC_E_RESERVED && reason == ISAM_RC_AP_RESET) { txbcnfrm = cur_if->txbcnfrm; @@ -4602,7 +5317,7 @@ wl_ext_reset_ap_handler(struct wl_if_info *cur_if, wl_ext_if_up(apsta_params, cur_if, FALSE, 500); } done: - wl_ext_mod_timer(&cur_if->reset_ap_timer, AP_TXBCNFRM_TIMEOUT, 0); + wl_timer_mod(dhd, &cur_if->reset_ap_timer, AP_TXBCNFRM_TIMEOUT); } } return; @@ -4646,11 +5361,15 @@ wl_ext_rxf0ovfl_reinit_handler(struct wl_if_info *cur_if, const wl_event_msg_t * int ret = 0; bool reinit = FALSE; + if (!(dhd->conf->war & FW_REINIT_RXF0OVFL)) { + return; + } + if ((cur_if->ifmode == ISTA_MODE) && (etype == WLC_E_LINK) && (flags & WLC_EVENT_MSG_LINK)) { // Link up wl_ext_counters_update(cur_if, ISAM_RC_RXF0OVFL_REINIT); - wl_ext_mod_timer(&apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT, 0); + wl_timer_mod(dhd, &apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT); } else if ((cur_if->ifmode == IAP_MODE) && ((etype == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) || @@ -4658,7 +5377,7 @@ wl_ext_rxf0ovfl_reinit_handler(struct wl_if_info *cur_if, const wl_event_msg_t * reason == WLC_E_REASON_INITIAL_ASSOC))) { // Link up wl_ext_counters_update(cur_if, ISAM_RC_RXF0OVFL_REINIT); - wl_ext_mod_timer(&apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT, 0); + wl_timer_mod(dhd, &apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT); } else if ((etype == WLC_E_RESERVED) && (reason == ISAM_RC_RXF0OVFL_REINIT) && (wl_ext_iapsta_other_if_enabled(cur_if->dev))) { @@ -4678,16 +5397,18 @@ wl_ext_rxf0ovfl_reinit_handler(struct wl_if_info *cur_if, const wl_event_msg_t * if (rxbeaconmbss_diff < 5 && rxf0ovfl_diff > RXF0OVFL_THRESHOLD) reinit = TRUE; } +#if 0 else if (wl_ext_if_enabled(apsta_params, IAP_MODE)) { if (rxf0ovfl_diff > RXF0OVFL_THRESHOLD) reinit = TRUE; } +#endif if (reinit) { WL_MSG(cur_if->ifname, "wl reinit\n"); wl_ext_ioctl(cur_if->dev, WLC_INIT, NULL, 0, 1); } done: - wl_ext_mod_timer(&apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT, 0); + wl_timer_mod(dhd, &apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT); } return; @@ -4695,37 +5416,16 @@ done: #endif /* RXF0OVFL_REINIT_WAR */ void -wl_ext_iapsta_event(struct net_device *dev, void *argu, +wl_ext_iapsta_link(struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data) { - struct wl_apsta_params *apsta_params = (struct wl_apsta_params *)argu; - struct wl_if_info *cur_if = NULL; -#if defined(WLMESH) && defined(WL_ESCAN) - struct wl_if_info *tmp_if = NULL; - struct wl_if_info *mesh_if = NULL; - int i; -#endif /* WLMESH && WL_ESCAN */ + struct dhd_pub *dhd = dhd_get_pub(cur_if->dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; uint32 event_type = ntoh32(e->event_type); uint32 status = ntoh32(e->status); uint32 reason = ntoh32(e->reason); uint16 flags = ntoh16(e->flags); - cur_if = wl_get_cur_if(dev); - -#if defined(WLMESH) && defined(WL_ESCAN) - for (i=0; iif_info[i]; - if (tmp_if->dev && tmp_if->ifmode == IMESH_MODE) { - mesh_if = tmp_if; - break; - } - } -#endif /* WLMESH && WL_ESCAN */ - if (!cur_if || !cur_if->dev) { - IAPSTA_DBG(dev->name, "ifidx %d is not ready\n", e->ifidx); - return; - } - if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) { if (event_type == WLC_E_LINK) { if (!(flags & WLC_EVENT_MSG_LINK)) { @@ -4737,26 +5437,19 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, wl_ext_net_setcarrier(cur_if, FALSE, FALSE); #endif /* SET_CARRIER */ wl_clr_isam_status(cur_if, STA_CONNECTED); -#if defined(WLMESH) && defined(WL_ESCAN) - if (mesh_if && apsta_params->macs) - wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE); -#endif /* WLMESH && WL_ESCAN */ } else { WL_MSG(cur_if->ifname, "[%c] Link UP with %pM\n", cur_if->prefix, &e->addr); + wl_ext_isam_status(cur_if->dev, NULL, 0); #ifdef SET_CARRIER wl_ext_net_setcarrier(cur_if, TRUE, FALSE); #endif /* SET_CARRIER */ wl_set_isam_status(cur_if, STA_CONNECTED); -#if defined(WLMESH) && defined(WL_ESCAN) - if (mesh_if && apsta_params->macs) - wl_mesh_update_master_info(apsta_params, mesh_if); -#endif /* WLMESH && WL_ESCAN */ } wl_clr_isam_status(cur_if, STA_CONNECTING); wake_up_interruptible(&apsta_params->netif_change_event); #ifdef PROPTX_MAXCOUNT - wl_ext_update_wlfc_maxcount(apsta_params->dhd); + wl_ext_update_wlfc_maxcount(dhd); #endif /* PROPTX_MAXCOUNT */ } else if (event_type == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) { @@ -4765,12 +5458,8 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, event_type, reason, status); wl_clr_isam_status(cur_if, STA_CONNECTING); wake_up_interruptible(&apsta_params->netif_change_event); -#if defined(WLMESH) && defined(WL_ESCAN) - if (mesh_if && apsta_params->macs) - wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE); -#endif /* WLMESH && WL_ESCAN */ #ifdef PROPTX_MAXCOUNT - wl_ext_update_wlfc_maxcount(apsta_params->dhd); + wl_ext_update_wlfc_maxcount(dhd); #endif /* PROPTX_MAXCOUNT */ } else if (event_type == WLC_E_DEAUTH || event_type == WLC_E_DEAUTH_IND || @@ -4781,10 +5470,6 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, #ifdef SET_CARRIER wl_ext_net_setcarrier(cur_if, FALSE, FALSE); #endif /* SET_CARRIER */ -#if defined(WLMESH) && defined(WL_ESCAN) - if (mesh_if && apsta_params->macs) - wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE); -#endif /* WLMESH && WL_ESCAN */ } } else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IGO_MODE || @@ -4796,17 +5481,19 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, WL_MSG(cur_if->ifname, "[%c] Link up (etype=%d)\n", cur_if->prefix, event_type); wl_set_isam_status(cur_if, AP_CREATED); + wl_ext_isam_status(cur_if->dev, NULL, 0); wake_up_interruptible(&apsta_params->netif_change_event); } else { wl_set_isam_status(cur_if, AP_CREATED); WL_MSG(cur_if->ifname, "[%c] Link up w/o creating? (etype=%d)\n", cur_if->prefix, event_type); + wl_ext_isam_status(cur_if->dev, NULL, 0); } #ifdef SET_CARRIER wl_ext_net_setcarrier(cur_if, TRUE, FALSE); #endif /* SET_CARRIER */ #ifdef PROPTX_MAXCOUNT - wl_ext_update_wlfc_maxcount(apsta_params->dhd); + wl_ext_update_wlfc_maxcount(dhd); #endif /* PROPTX_MAXCOUNT */ } else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) || @@ -4819,7 +5506,7 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, wl_ext_net_setcarrier(cur_if, FALSE, FALSE); #endif /* SET_CARRIER */ #ifdef PROPTX_MAXCOUNT - wl_ext_update_wlfc_maxcount(apsta_params->dhd); + wl_ext_update_wlfc_maxcount(dhd); #endif /* PROPTX_MAXCOUNT */ } else if ((event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) && @@ -4837,17 +5524,52 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, event_type, reason); wl_ext_isam_status(cur_if->dev, NULL, 0); } -#if defined(WLMESH) && defined(WL_ESCAN) - if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) - wl_mesh_event_handler(apsta_params, cur_if, e, data); -#endif /* WLMESH && WL_ESCAN */ + } +} + +static void +wl_ext_iapsta_ccode(struct wl_if_info *cur_if, + const wl_event_msg_t *e, void *data) +{ + struct dhd_pub *dhd = dhd_get_pub(cur_if->dev); + uint32 event_type = ntoh32(e->event_type); + char country_str[WLC_CNTRY_BUF_SZ] = { 0 }; + + if (event_type == WLC_E_COUNTRY_CODE_CHANGED) { + if (strlcpy(country_str, data, WL_CCODE_LEN + 1) >= WLC_CNTRY_BUF_SZ) { + return; + } + WL_MSG(cur_if->ifname, "Updating new country %s\n", country_str); + dhd_conf_country(dhd, "country", country_str); + } +} + +void +wl_ext_iapsta_event(struct net_device *dev, void *argu, + const wl_event_msg_t *e, void *data) +{ +#ifdef ACS_MONITOR + struct wl_apsta_params *apsta_params = (struct wl_apsta_params *)argu; +#endif /* ACS_MONITOR */ + struct dhd_pub *dhd = dhd_get_pub(dev); + struct wl_if_info *cur_if = NULL; + + cur_if = wl_get_cur_if(dev); + if (!cur_if || !cur_if->dev) { + IAPSTA_DBG(dev->name, "ifidx %d is not ready\n", e->ifidx); + return; } + wl_ext_iapsta_link(cur_if, e, data); + wl_ext_iapsta_ccode(cur_if, e, data); #ifdef TPUT_MONITOR - if (apsta_params->dhd->conf->tput_monitor_ms) - wl_tput_monitor_handler(apsta_params, cur_if, e, data); + if (dhd->conf->tput_monitor_ms) + wl_tput_monitor_handler(cur_if, e, data); #endif /* TPUT_MONITOR */ +#if defined(WLMESH) && defined(WL_ESCAN) + wl_mesh_event_handler(cur_if, e, data); +#endif /* WLMESH && WL_ESCAN */ #ifdef ACS_MONITOR if ((apsta_params->acs & ACS_DRV_BIT) && apsta_params->acs_tmo) wl_acs_handler(cur_if, e, data); @@ -4855,6 +5577,9 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, #ifdef EAPOL_RESEND wl_resend_eapol_handler(cur_if, e, data); #endif /* EAPOL_RESEND */ +#ifdef KEY_INSTALL_CHECK + wl_ext_key_install_handler(cur_if, e, data); +#endif /* KEY_INSTALL_CHECK */ #ifdef RESTART_AP_WAR wl_ext_restart_ap_handler(cur_if, e, data); #endif /* RESTART_AP_WAR */ @@ -5019,8 +5744,7 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next) } } else if (!strcmp(row->name, " chan ")) { cur_if->chan_info.chan = (int)simple_strtol(pick_tmp, NULL, 10); - if (!cur_if->chan_info.band) - cur_if->chan_info.band = WL_GET_BAND(cur_if->chan_info.chan); + cur_if->chan_info.band = WL_GET_BAND(cur_if->chan_info.chan); } else if (!strcmp(row->name, " amode ")) { if (!strcmp(pick_tmp, "open")) cur_if->amode = AUTH_OPEN; @@ -5106,17 +5830,13 @@ wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_para cur_if->vsdb = FALSE; cur_if->prefix = 'M'; snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh"); -#ifdef WL_ESCAN - if (i == 0 && apsta_params->macs) - wl_mesh_escan_attach(dhd, cur_if); -#endif /* WL_ESCAN */ #endif /* WLMESH */ } } if (FW_SUPPORTED(dhd, rsdb)) { if (apstamode == IDUALAP_MODE) - apsta_params->rsdb = -1; + apsta_params->rsdb = 1; else if (apstamode == ISTAAPAP_MODE) apsta_params->rsdb = 0; if (apstamode == ISTAAPAP_MODE || apstamode == IDUALAP_MODE || @@ -5217,7 +5937,6 @@ wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_para } #endif /* WLMESH */ - wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver); apsta_params->init = TRUE; WL_MSG(dev->name, "apstamode=%d\n", apstamode); @@ -5374,7 +6093,8 @@ wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock if ((chan_2g && cur_if->chan_info.band == WLC_BAND_2G) || (chan_5g && cur_if->chan_info.band == WLC_BAND_5G)) { cur_if->chan_info.chan = wl_ext_autochannel(cur_if->dev, apsta_params->acs, - cur_if->chan_info.band); + cur_if->chan_info.band, NULL); + cur_if->chan_info.chan = wf_chspec_ctlchan(cur_if->chan_info.chan); } else { IAPSTA_ERROR(ifname, "invalid channel\n"); ret = -1; @@ -5391,7 +6111,7 @@ wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock } memset(&chan_info, 0, sizeof(struct wl_chan_info)); - wl_ext_get_chan(apsta_params, cur_if->dev, &chan_info); + wl_ext_get_chan(cur_if->dev, &chan_info); if (chan_info.chan) { IAPSTA_INFO(cur_if->ifname, "Associated\n"); if (!wl_ext_same_chan(&cur_if->chan_info, &chan_info)) { @@ -5436,7 +6156,7 @@ wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock } wl_ext_set_amode(cur_if); - wl_ext_set_emode(apsta_params, cur_if); + wl_ext_set_emode(cur_if); if (cur_if->ifmode == ISTA_MODE) { conn_info.bssidx = cur_if->bssidx; @@ -5567,8 +6287,6 @@ int wl_ext_isam_dev_status(struct net_device *dev, ifmode_t ifmode, char prefix, char *dump_buf, int dump_len) { - struct dhd_pub *dhd = dhd_get_pub(dev); - struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct wl_chan_info chan_info; wlc_ssid_t ssid = { 0, {0} }; struct ether_addr bssid; @@ -5585,9 +6303,8 @@ wl_ext_isam_dev_status(struct net_device *dev, ifmode_t ifmode, char prefix, if (wl_ext_associated(dev)) { wl_ext_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0); wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0); - wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, - sizeof(scb_val_t), 0); - chanspec = wl_ext_get_chanspec(apsta_params, dev, &chan_info); + wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0); + chanspec = wl_ext_get_chanspec(dev, &chan_info); wl_ext_get_sec(dev, ifmode, sec, sizeof(sec), FALSE); dump_written += snprintf(dump_buf+dump_written, dump_len, "\n" DHD_LOG_PREFIXS "[%s-%c]: bssid=%pM, chan=%s-%-3d(0x%x %sMHz), " @@ -5708,7 +6425,7 @@ wl_ext_isam_param(struct net_device *dev, char *command, int total_len) if (apsta_params->acs_tmo != acs_tmo) { apsta_params->acs_tmo = acs_tmo; WL_MSG(dev->name, "acs_timer reset to %d\n", acs_tmo); - wl_ext_mod_timer(&cur_if->acs_timer, acs_tmo, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, 0); } ret = 0; } else { @@ -6025,7 +6742,6 @@ wl_ext_iapsta_alive_postinit(struct net_device *dev) } // fix me: how to check it's ISTAAP_MODE or IDUALAP_MODE? - wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver); WL_MSG(dev->name, "apstamode=%d\n", apsta_params->apstamode); for (i=0; iiapsta_params; + int ret, mapsta_mode; + + ret = wldev_iovar_getint(net, "mapsta_mode", &mapsta_mode); + if (ret) { + IAPSTA_INFO(net->name, "not supported %d\n", ret); + mapsta_mode = MCHAN_APSTA_NOT_ALLOW; + } + + if (mapsta_mode == MCHAN_APSTA_SBSC) + apsta_params->rsdb = 1; + else if (mapsta_mode == MCHAN_APSTA_NO_RESTRICT) + apsta_params->vsdb = TRUE; + + IAPSTA_INFO(net->name, "mapsta_mode=%d(rsdb=%d, vsdb=%d)\n", + mapsta_mode, apsta_params->rsdb, apsta_params->vsdb); +} + static void wl_ext_iapsta_postinit(struct net_device *net, struct wl_if_info *cur_if) { struct dhd_pub *dhd = dhd_get_pub(net); struct wl_apsta_params *apsta_params = dhd->iapsta_params; - int pm; IAPSTA_TRACE(cur_if->ifname, "ifidx=%d\n", cur_if->ifidx); if (cur_if->ifidx == 0) { apsta_params->rsdb = wl_ext_iapsta_get_rsdb(net, dhd); apsta_params->vsdb = FALSE; + wl_ext_iapsta_get_mapsta_mode(net); apsta_params->csa = 0; apsta_params->acs = 0; apsta_params->radar = wl_ext_radar_detect(net); if (dhd->conf->fw_type == FW_TYPE_MESH) { apsta_params->csa |= (CSA_FW_BIT | CSA_DRV_BIT); } + cur_if->ifmode = ISTA_MODE; + cur_if->prio = PRIO_STA; + cur_if->vsdb = TRUE; + cur_if->prefix = 'S'; if (dhd->conf->vndr_ie_assocreq && strlen(dhd->conf->vndr_ie_assocreq)) wl_ext_add_del_ie(net, VNDR_IE_ASSOCREQ_FLAG, dhd->conf->vndr_ie_assocreq, "add"); } else { if (cur_if->ifmode == ISTA_MODE) { - wl_ext_iovar_setint(cur_if->dev, "roam_off", dhd->conf->roam_off); - wl_ext_iovar_setint(cur_if->dev, "bcn_timeout", dhd->conf->bcn_timeout); - if (dhd->conf->pm >= 0) - pm = dhd->conf->pm; - else - pm = PM_FAST; - wl_ext_ioctl(cur_if->dev, WLC_SET_PM, &pm, sizeof(pm), 1); - wl_ext_iovar_setint(cur_if->dev, "assoc_retry_max", 10); + dhd_conf_preinit_ioctls_sta(dhd, cur_if->ifidx); } #ifdef WLMESH else if (cur_if->ifmode == IMESH_MODE) { - pm = 0; + int pm = 0; wl_ext_ioctl(cur_if->dev, WLC_SET_PM, &pm, sizeof(pm), 1); } #endif /* WLMESH */ @@ -6204,7 +6939,7 @@ wl_ext_iapsta_update_net_device(struct net_device *net, int ifidx) memcpy(mac_addr, primary_if->dev->dev_addr, ETHER_ADDR_LEN); mac_addr[0] |= 0x02; wl_ext_iapsta_get_vif_macaddr(dhd, ifidx, mac_addr); - dev_addr_set(net, mac_addr); + DEV_ADDR_SET(net, mac_addr); } #endif /* WL_STATIC_IF */ } @@ -6271,6 +7006,32 @@ wl_ext_iapsta_dettach_dwds_netdev(struct net_device *net, int ifidx, uint8 bssid } #endif /* WLDWDS */ +static void +wl_ext_iapsta_init_priv(struct net_device *net) +{ + struct dhd_pub *dhd = dhd_get_pub(net); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + + init_waitqueue_head(&apsta_params->netif_change_event); + mutex_init(&apsta_params->usr_sync); + mutex_init(&apsta_params->in4way_sync); +#ifdef STA_MGMT + INIT_LIST_HEAD(&apsta_params->sta_list); +#endif /* STA_MGMT */ +#ifdef EAPOL_RESEND + spin_lock_init(&apsta_params->eapol_lock); +#endif /* EAPOL_RESEND */ +} + +static void +wl_ext_iapsta_deinit_priv(struct net_device *net) +{ + struct dhd_pub *dhd = dhd_get_pub(net); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + + memset(apsta_params, 0, sizeof(struct wl_apsta_params)); +} + int wl_ext_iapsta_attach_netdev(struct net_device *net, int ifidx, uint8 bssidx) { @@ -6282,87 +7043,52 @@ wl_ext_iapsta_attach_netdev(struct net_device *net, int ifidx, uint8 bssidx) IAPSTA_TRACE(net->name, "ifidx=%d, bssidx=%d\n", ifidx, bssidx); cur_if = &apsta_params->if_info[ifidx]; } + if (ifidx == 0) { - memset(apsta_params, 0, sizeof(struct wl_apsta_params)); - apsta_params->dhd = dhd; - cur_if->dev = net; - cur_if->ifidx = ifidx; - cur_if->bssidx = bssidx; - cur_if->ifmode = ISTA_MODE; - cur_if->prio = PRIO_STA; - cur_if->vsdb = TRUE; - cur_if->prefix = 'S'; - wl_ext_event_register(net, dhd, WLC_E_LAST, wl_ext_iapsta_event, - apsta_params, PRIO_EVENT_IAPSTA); + wl_ext_iapsta_init_priv(net); strcpy(cur_if->ifname, net->name); - init_waitqueue_head(&apsta_params->netif_change_event); - init_waitqueue_head(&apsta_params->ap_recon_sta_event); - mutex_init(&apsta_params->usr_sync); - mutex_init(&apsta_params->in4way_sync); - mutex_init(&cur_if->pm_sync); -#ifdef STA_MGMT - INIT_LIST_HEAD(&apsta_params->sta_list); -#endif /* STA_MGMT */ #ifdef TPUT_MONITOR - init_timer_compat(&apsta_params->monitor_timer, wl_tput_monitor_timer, net); + wl_timer_register(net, &apsta_params->monitor_timer, wl_tput_monitor_timer); #endif /* TPUT_MONITOR */ -#ifdef ACS_MONITOR - wl_acs_attach(dhd, cur_if); -#endif /* ACS_MONITOR */ - INIT_DELAYED_WORK(&cur_if->pm_enable_work, wl_ext_pm_work_handler); -#ifdef SET_CARRIER - wl_ext_net_setcarrier(cur_if, FALSE, TRUE); -#endif /* SET_CARRIER */ - init_timer_compat(&cur_if->connect_timer, wl_ext_connect_timeout, net); -#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - init_timer_compat(&cur_if->reconnect_timer, wl_ext_reconnect_timeout, net); -#endif /* WL_EXT_RECONNECT && WL_CFG80211 */ -#ifdef RESTART_AP_WAR - init_timer_compat(&cur_if->restart_ap_timer, wl_ext_restart_ap_timeout, net); -#endif /* RESTART_AP_WAR */ -#ifdef RESET_AP_WAR - init_timer_compat(&cur_if->reset_ap_timer, wl_ext_reset_ap_timeout, net); -#endif /* RESET_AP_WAR */ #ifdef RXF0OVFL_REINIT_WAR - init_timer_compat(&apsta_params->rxf0ovfl_timer, wl_ext_rxf0ovfl_reinit_timeout, net); + wl_timer_register(net, &apsta_params->rxf0ovfl_timer, wl_ext_rxf0ovfl_reinit_timeout); #endif /* RXF0OVFL_REINIT_WAR */ -#ifdef EAPOL_RESEND - spin_lock_init(&apsta_params->eapol_lock); - init_timer_compat(&cur_if->eapol_timer, wl_eapol_timer, net); -#endif /* EAPOL_RESEND */ } - else if (cur_if && wl_get_isam_status(cur_if, IF_ADDING)) { + + if (ifidx == 0 || (cur_if && wl_get_isam_status(cur_if, IF_ADDING))) { cur_if->dev = net; cur_if->ifidx = ifidx; cur_if->bssidx = bssidx; + mutex_init(&cur_if->pm_sync); + INIT_DELAYED_WORK(&cur_if->pm_enable_work, wl_ext_pm_work_handler); + init_waitqueue_head(&cur_if->ap_recon_sta_event); wl_ext_event_register(net, dhd, WLC_E_LAST, wl_ext_iapsta_event, apsta_params, PRIO_EVENT_IAPSTA); #if defined(WLMESH) && defined(WL_ESCAN) - if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) { - wl_mesh_escan_attach(dhd, cur_if); - } + wl_mesh_escan_attach(dhd, cur_if); #endif /* WLMESH && WL_ESCAN */ #ifdef ACS_MONITOR wl_acs_attach(dhd, cur_if); #endif /* ACS_MONITOR */ - mutex_init(&cur_if->pm_sync); - INIT_DELAYED_WORK(&cur_if->pm_enable_work, wl_ext_pm_work_handler); #ifdef SET_CARRIER wl_ext_net_setcarrier(cur_if, FALSE, TRUE); #endif /* SET_CARRIER */ - init_timer_compat(&cur_if->connect_timer, wl_ext_connect_timeout, net); + wl_timer_register(net, &cur_if->connect_timer, wl_ext_connect_timeout); +#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) + wl_timer_register(net, &cur_if->reconnect_timer, wl_ext_reconnect_timeout); +#endif /* WL_EXT_RECONNECT && WL_CFG80211 */ #ifdef RESTART_AP_WAR - init_timer_compat(&cur_if->restart_ap_timer, wl_ext_restart_ap_timeout, net); + wl_timer_register(net, &cur_if->restart_ap_timer, wl_ext_restart_ap_timeout); #endif /* RESTART_AP_WAR */ #ifdef RESET_AP_WAR - init_timer_compat(&cur_if->reset_ap_timer, wl_ext_reset_ap_timeout, net); + wl_timer_register(net, &cur_if->reset_ap_timer, wl_ext_reset_ap_timeout); #endif /* RESET_AP_WAR */ -#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - init_timer_compat(&cur_if->reconnect_timer, wl_ext_reconnect_timeout, net); -#endif /* WL_EXT_RECONNECT && WL_CFG80211 */ #ifdef EAPOL_RESEND - init_timer_compat(&cur_if->eapol_timer, wl_eapol_timer, net); + wl_timer_register(net, &cur_if->eapol_timer, wl_eapol_timer); #endif /* EAPOL_RESEND */ +#ifdef KEY_INSTALL_CHECK + wl_timer_register(net, &cur_if->key_install_timer, wl_ext_key_install_timeout); +#endif /* KEY_INSTALL_CHECK */ } return 0; @@ -6383,58 +7109,23 @@ wl_ext_iapsta_dettach_netdev(struct net_device *net, int ifidx) cur_if = &apsta_params->if_info[ifidx]; } - if (ifidx == 0) { + if (ifidx == 0 || (cur_if && (wl_get_isam_status(cur_if, IF_READY) || + wl_get_isam_status(cur_if, IF_ADDING)))) { #ifdef EAPOL_RESEND wl_ext_release_eapol_txpkt(dhd, ifidx, FALSE); #endif /* EAPOL_RESEND */ - wl_ext_mod_timer(&cur_if->connect_timer, 0, 0); +#ifdef KEY_INSTALL_CHECK + wl_timer_deregister(net, &cur_if->key_install_timer); +#endif /* KEY_INSTALL_CHECK */ + wl_timer_deregister(net, &cur_if->connect_timer); #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); + wl_timer_deregister(net, &cur_if->reconnect_timer); #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ #ifdef RESTART_AP_WAR - wl_ext_mod_timer(&cur_if->restart_ap_timer, 0, 0); + wl_timer_deregister(net, &cur_if->restart_ap_timer); #endif /* RESTART_AP_WAR */ #ifdef RESET_AP_WAR - wl_ext_mod_timer(&cur_if->reset_ap_timer, 0, 0); -#endif /* RESET_AP_WAR */ -#ifdef RXF0OVFL_REINIT_WAR - wl_ext_mod_timer(&apsta_params->rxf0ovfl_timer, 0, 0); -#endif /* RXF0OVFL_REINIT_WAR */ -#ifdef SET_CARRIER - wl_ext_net_setcarrier(cur_if, FALSE, FALSE); -#endif /* SET_CARRIER */ - wl_ext_add_remove_pm_enable_work(net, FALSE); -#ifdef ACS_MONITOR - wl_acs_detach(cur_if); -#endif /* ACS_MONITOR */ -#ifdef TPUT_MONITOR - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, 0); -#endif /* TPUT_MONITOR */ -#if defined(WLMESH) && defined(WL_ESCAN) - if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) { - wl_mesh_escan_detach(dhd, cur_if); - } -#endif /* WLMESH && WL_ESCAN */ - wl_ext_event_deregister(net, dhd, WLC_E_LAST, wl_ext_iapsta_event); -#ifdef STA_MGMT - wl_ext_flush_sta_list(net, ifidx); -#endif /* STA_MGMT */ - memset(apsta_params, 0, sizeof(struct wl_apsta_params)); - } - else if (cur_if && (wl_get_isam_status(cur_if, IF_READY) || - wl_get_isam_status(cur_if, IF_ADDING))) { -#ifdef EAPOL_RESEND - wl_ext_release_eapol_txpkt(dhd, ifidx, FALSE); -#endif /* EAPOL_RESEND */ - wl_ext_mod_timer(&cur_if->connect_timer, 0, 0); -#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); -#endif /* WL_EXT_RECONNECT && WL_CFG80211 */ -#ifdef RESTART_AP_WAR - wl_ext_mod_timer(&cur_if->restart_ap_timer, 0, 0); -#endif /* RESTART_AP_WAR */ -#ifdef RESET_AP_WAR - wl_ext_mod_timer(&cur_if->reset_ap_timer, 0, 0); + wl_timer_deregister(net, &cur_if->reset_ap_timer); #endif /* RESET_AP_WAR */ #ifdef SET_CARRIER wl_ext_net_setcarrier(cur_if, FALSE, FALSE); @@ -6444,9 +7135,7 @@ wl_ext_iapsta_dettach_netdev(struct net_device *net, int ifidx) wl_acs_detach(cur_if); #endif /* ACS_MONITOR */ #if defined(WLMESH) && defined(WL_ESCAN) - if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) { - wl_mesh_escan_detach(dhd, cur_if); - } + wl_mesh_escan_detach(dhd, cur_if); #endif /* WLMESH && WL_ESCAN */ wl_ext_event_deregister(net, dhd, WLC_E_LAST, wl_ext_iapsta_event); #ifdef STA_MGMT @@ -6455,23 +7144,15 @@ wl_ext_iapsta_dettach_netdev(struct net_device *net, int ifidx) memset(cur_if, 0, sizeof(struct wl_if_info)); } - return 0; -} - -int -wl_ext_iapsta_attach(struct net_device *net) -{ - struct dhd_pub *dhd = dhd_get_pub(net); - struct wl_apsta_params *iapsta_params; - - IAPSTA_TRACE(net->name, "Enter\n"); - - iapsta_params = kzalloc(sizeof(struct wl_apsta_params), GFP_KERNEL); - if (unlikely(!iapsta_params)) { - IAPSTA_ERROR("wlan", "Could not allocate apsta_params\n"); - return -ENOMEM; + if (ifidx == 0) { +#ifdef RXF0OVFL_REINIT_WAR + wl_timer_deregister(net, &apsta_params->rxf0ovfl_timer); +#endif /* RXF0OVFL_REINIT_WAR */ +#ifdef TPUT_MONITOR + wl_timer_deregister(net, &apsta_params->monitor_timer); +#endif /* TPUT_MONITOR */ + wl_ext_iapsta_deinit_priv(net); } - dhd->iapsta_params = (void *)iapsta_params; return 0; } @@ -6483,9 +7164,47 @@ wl_ext_iapsta_dettach(struct net_device *net) IAPSTA_TRACE(net->name, "Enter\n"); + if (g_ioctl_buf) { + kfree(g_ioctl_buf); + g_ioctl_buf = NULL; + } + if (dhd->iapsta_params) { + wl_ext_iapsta_deinit_priv(net); kfree(dhd->iapsta_params); dhd->iapsta_params = NULL; } } + +int +wl_ext_iapsta_attach(struct net_device *net) +{ + struct dhd_pub *dhd = dhd_get_pub(net); + struct wl_apsta_params *iapsta_params; + int ret = 0; + + IAPSTA_TRACE(net->name, "Enter\n"); + + iapsta_params = kzalloc(sizeof(struct wl_apsta_params), GFP_KERNEL); + if (unlikely(!iapsta_params)) { + IAPSTA_ERROR(net->name, "Can not allocate apsta_params\n"); + ret = -ENOMEM; + goto exit; + } + dhd->iapsta_params = (void *)iapsta_params; + + if (!g_ioctl_buf) { + g_ioctl_buf = kmalloc(WL_DUMP_BUF_LEN, GFP_KERNEL); + if (unlikely(!g_ioctl_buf)) { + IAPSTA_ERROR(net->name, "Can not allocate g_ioctl_buf\n"); + ret = -ENOMEM; + goto exit; + } + } + +exit: + if (ret) + wl_ext_iapsta_dettach(net); + return ret; +} #endif /* WL_EXT_IAPSTA */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iapsta.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iapsta.h old mode 100755 new mode 100644 index 75f016138cdb..26eb7e7d0da8 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iapsta.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iapsta.h @@ -10,7 +10,8 @@ typedef enum IFMODE { } ifmode_t; enum wl_ext_status { - WL_EXT_STATUS_DISCONNECTING = 0, + WL_EXT_STATUS_PRE_DISCONNECTING = 0, + WL_EXT_STATUS_DISCONNECTING, WL_EXT_STATUS_DISCONNECTED, WL_EXT_STATUS_SCAN, WL_EXT_STATUS_SCANNING, @@ -18,6 +19,7 @@ enum wl_ext_status { WL_EXT_STATUS_CONNECTING, WL_EXT_STATUS_RECONNECT, WL_EXT_STATUS_CONNECTED, + WL_EXT_STATUS_ROAMED, WL_EXT_STATUS_ADD_KEY, WL_EXT_STATUS_AP_ENABLING, WL_EXT_STATUS_AP_ENABLED, @@ -56,6 +58,11 @@ int wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len); void wl_ext_add_remove_pm_enable_work(struct net_device *dev, bool add); bool wl_ext_iapsta_other_if_enabled(struct net_device *net); bool wl_ext_sta_connecting(struct net_device *dev); +bool wl_ext_sta_connected(struct net_device *dev); +void wl_ext_get_chan_str(struct net_device *dev, char *chan_str, int total_len); +#ifdef DHD_LOSSLESS_ROAMING +int wl_ext_any_sta_handshaking(struct dhd_pub *dhd); +#endif /* DHD_LOSSLESS_ROAMING */ void wl_iapsta_wait_event_complete(struct dhd_pub *dhd); int wl_iapsta_suspend_resume(dhd_pub_t *dhd, int suspend); #ifdef USE_IW @@ -80,6 +87,11 @@ void wl_ext_iapsta_restart_master(struct net_device *dev); void wl_ext_iapsta_ifadding(struct net_device *net, int ifidx); bool wl_ext_iapsta_mesh_creating(struct net_device *net); void wl_ext_fw_reinit_incsa(struct net_device *dev); +void wl_ext_send_event_msg(struct net_device *dev, int event, int status, + int reason); +#ifdef BTC_WAR +void wl_ext_btc_config(struct net_device *dev, bool enable); +#endif /* BTC_WAR */ #ifdef STA_MGMT bool wl_ext_del_sta_info(struct net_device *net, u8 *bssid); bool wl_ext_add_sta_info(struct net_device *net, u8 *bssid); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c old mode 100755 new mode 100644 index ddec5e572394..96d63cdf207f --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c @@ -216,8 +216,8 @@ static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action); #endif /* !WL_ESCAN */ struct pmk_list { - pmkid_list_t pmkids; - pmkid_t foo[MAXPMKID - 1]; + pmkid_list_v1_t pmkids; + pmkid_v1_t foo[MAXPMKID - 1]; }; typedef struct wl_wext_info { @@ -293,7 +293,7 @@ dev_wlc_ioctl( index = dhd_net2idx(dhd->info, dev); if (index == DHD_BAD_IF) { - WL_ERROR(("Bad ifidx from dev:%p\n", dev)); + WL_ERROR(("Bad ifidx from %s\n", dev->name)); return -ENODEV; } ret = dhd_ioctl_process(dhd, index, &ioc, arg); @@ -456,6 +456,7 @@ typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, #endif /* WIRELESS_EXT < 13 */ #if WIRELESS_EXT > 12 +#ifdef CONFIG_WEXT_PRIV static int wl_iw_set_leddc( struct net_device *dev, @@ -502,6 +503,7 @@ wl_iw_set_pm( error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); return error; } +#endif /* CONFIG_WEXT_PRIV */ #endif /* WIRELESS_EXT > 12 */ int @@ -532,7 +534,7 @@ static int wl_iw_config_commit( struct net_device *dev, struct iw_request_info *info, - void *zwrq, + union iwreq_data *zwrq, char *extra ) { @@ -616,10 +618,11 @@ static int wl_iw_set_freq( struct net_device *dev, struct iw_request_info *info, - struct iw_freq *fwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_freq *fwrq = &wrqu->freq; int error, chan; uint sf = 0; struct dhd_pub *dhd = dhd_get_pub(dev); @@ -668,18 +671,24 @@ static int wl_iw_get_freq( struct net_device *dev, struct iw_request_info *info, - struct iw_freq *fwrq, + union iwreq_data *wrqu, char *extra ) { + struct dhd_pub *dhd = dhd_get_pub(dev); + struct iw_freq *fwrq = &wrqu->freq; int error; - u32 chanspec = 0; + u32 val; + chanspec_t chanspec = 0; int ctl_chan; WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name)); - if ((error = dev_wlc_intvar_get(dev, "chanspec", &chanspec))) + DHD_CHECK(dhd, dev); + if ((error = dev_wlc_intvar_get(dev, "chanspec", &val))) return error; + chanspec = val; + chanspec = wl_ext_chspec_driver_to_host(dhd, chanspec); ctl_chan = wf_chspec_ctlchan(chanspec); /* Return radio channel in channel form */ @@ -692,7 +701,7 @@ static int wl_iw_set_mode( struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, + union iwreq_data *wrqu, char *extra ) { @@ -709,7 +718,7 @@ wl_iw_set_mode( wext_info->conn_info.channel = 0; } - switch (*uwrq) { + switch (wrqu->mode) { case IW_MODE_MASTER: infra = ap = 1; break; @@ -737,7 +746,7 @@ static int wl_iw_get_mode( struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, + union iwreq_data *wrqu, char *extra ) { @@ -751,7 +760,7 @@ wl_iw_get_mode( infra = dtoh32(infra); ap = dtoh32(ap); - *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC; + wrqu->mode = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC; return 0; } @@ -760,10 +769,11 @@ static int wl_iw_get_range( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; struct iw_range *range = (struct iw_range *) extra; static int channels[MAXCHANNEL+1]; wl_uint32_list_t *list = (wl_uint32_list_t *) channels; @@ -992,10 +1002,11 @@ static int wl_iw_set_spy( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_iw_t *iw = IW_DEV_IF(dev); struct sockaddr *addr = (struct sockaddr *) extra; int i; @@ -1017,10 +1028,11 @@ static int wl_iw_get_spy( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_iw_t *iw = IW_DEV_IF(dev); struct sockaddr *addr = (struct sockaddr *) extra; struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num]; @@ -1046,7 +1058,7 @@ static int wl_iw_set_wap( struct net_device *dev, struct iw_request_info *info, - struct sockaddr *awrq, + union iwreq_data *wrqu, char *extra ) { @@ -1057,13 +1069,13 @@ wl_iw_set_wap( WL_TRACE(("%s: SIOCSIWAP\n", dev->name)); DHD_CHECK(dhd, dev); wext_info = dhd->wext_info; - if (awrq->sa_family != ARPHRD_ETHER) { + if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) { WL_ERROR(("Invalid Header...sa_family\n")); return -EINVAL; } /* Ignore "auto" or "off" */ - if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) { + if (ETHER_ISBCAST(wrqu->ap_addr.sa_data) || ETHER_ISNULLADDR(wrqu->ap_addr.sa_data)) { scb_val_t scbval; bzero(&scbval, sizeof(scb_val_t)); WL_MSG(dev->name, "WLC_DISASSOC\n"); @@ -1076,21 +1088,21 @@ wl_iw_set_wap( #endif return 0; } - /* WL_ASSOC(("Assoc to %s\n", bcm_ether_ntoa((struct ether_addr *)&(awrq->sa_data), + /* WL_ASSOC(("Assoc to %s\n", bcm_ether_ntoa((struct ether_addr *)&(wrqu->ap_addr.sa_data), * eabuf))); */ /* Reassociate to the specified AP */ if (wext_info) - memcpy(&wext_info->conn_info.bssid, awrq->sa_data, ETHER_ADDR_LEN); + memcpy(&wext_info->conn_info.bssid, wrqu->ap_addr.sa_data, ETHER_ADDR_LEN); if (wext_info && wext_info->conn_info.ssid.SSID_len) { if ((error = wl_ext_connect(dev, &wext_info->conn_info))) return error; } else { - if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, awrq->sa_data, ETHER_ADDR_LEN))) { + if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, wrqu->ap_addr.sa_data, ETHER_ADDR_LEN))) { WL_ERROR(("WLC_REASSOC failed (%d).\n", error)); return error; } - WL_MSG(dev->name, "join BSSID="MACSTR"\n", MAC2STR((u8 *)awrq->sa_data)); + WL_MSG(dev->name, "join BSSID="MACSTR"\n", MAC2STR((u8 *)wrqu->ap_addr.sa_data)); } #ifdef WL_EXT_IAPSTA wl_ext_in4way_sync_wext(dev, STA_NO_BTC_IN4WAY, WL_EXT_STATUS_CONNECTING, NULL); @@ -1103,17 +1115,17 @@ static int wl_iw_get_wap( struct net_device *dev, struct iw_request_info *info, - struct sockaddr *awrq, + union iwreq_data *wrqu, char *extra ) { WL_TRACE(("%s: SIOCGIWAP\n", dev->name)); - awrq->sa_family = ARPHRD_ETHER; - memset(awrq->sa_data, 0, ETHER_ADDR_LEN); + wrqu->ap_addr.sa_family = ARPHRD_ETHER; + memset(wrqu->ap_addr.sa_data, 0, ETHER_ADDR_LEN); /* Ignore error (may be down or disassociated) */ - (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN); + (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, wrqu->ap_addr.sa_data, ETHER_ADDR_LEN); return 0; } @@ -1123,7 +1135,7 @@ static int wl_iw_mlme( struct net_device *dev, struct iw_request_info *info, - struct sockaddr *awrq, + union iwreq_data *wrqu, char *extra ) { @@ -1171,14 +1183,15 @@ static int wl_iw_get_aplist( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + struct iw_point *wrqu, char *extra ) { - wl_scan_results_t *list; + struct iw_point *dwrq = (struct iw_point *)wrqu; + wl_scan_results_v109_t *list; struct sockaddr *addr = (struct sockaddr *) extra; struct iw_quality qual[IW_MAX_AP]; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; int error, i; uint buflen = dwrq->length; int16 rssi; @@ -1202,10 +1215,10 @@ wl_iw_get_aplist( list->buflen = dtoh32(list->buflen); list->version = dtoh32(list->version); list->count = dtoh32(list->count); - ASSERT(list->version == WL_BSS_INFO_VERSION); + ASSERT(list->version == WL_BSS_INFO_VER_109); for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + buflen)); @@ -1247,17 +1260,18 @@ static int wl_iw_iscan_get_aplist( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { - wl_scan_results_t *list; + struct iw_point *dwrq = (struct iw_point *)wrqu; + wl_scan_results_v109_t *list; iscan_buf_t * buf; iscan_info_t *iscan; struct sockaddr *addr = (struct sockaddr *) extra; struct iw_quality qual[IW_MAX_AP]; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; int i; int16 rssi; struct dhd_pub *dhd = dhd_get_pub(dev); @@ -1278,12 +1292,12 @@ wl_iw_iscan_get_aplist( buf = iscan->list_hdr; /* Get scan results (too large to put on the stack) */ while (buf) { - list = &((wl_iscan_results_t*)buf->iscan_buf)->results; - ASSERT(list->version == WL_BSS_INFO_VERSION); + list = &((wl_iscan_results_v109_t*)buf->iscan_buf)->results; + ASSERT(list->version == WL_BSS_INFO_VER_109); bi = NULL; for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + WLC_IW_ISCAN_MAXLEN)); @@ -1365,11 +1379,12 @@ wl_iw_iscan_set_scan( ) { struct dhd_pub *dhd = dhd_get_pub(dev); - wl_wext_info_t *wext_info = NULL; wlc_ssid_t ssid; #ifdef WL_ESCAN - wl_scan_info_t scan_info; + wl_scan_info_t *scan_info = NULL; + int err; #else + wl_wext_info_t *wext_info = NULL; iscan_info_t *iscan; #ifdef WL_EXT_IAPSTA int err; @@ -1377,7 +1392,6 @@ wl_iw_iscan_set_scan( #endif DHD_CHECK(dhd, dev); - wext_info = dhd->wext_info; #ifdef WL_ESCAN /* default Broadcast scan */ memset(&ssid, 0, sizeof(ssid)); @@ -1392,12 +1406,20 @@ wl_iw_iscan_set_scan( } } #endif - memset(&scan_info, 0, sizeof(wl_scan_info_t)); - scan_info.bcast_ssid = TRUE; - memcpy(scan_info.ssid.SSID, ssid.SSID, ssid.SSID_len); - scan_info.ssid.SSID_len = ssid.SSID_len; - return wl_escan_set_scan(dev, &scan_info); + scan_info = kmalloc(sizeof(wl_scan_info_t), GFP_KERNEL); + if (scan_info == NULL) { + WL_ERROR(("kzalloc failed\n")); + return -ENOMEM; + } + memset(scan_info, 0, sizeof(wl_scan_info_t)); + scan_info->bcast_ssid = TRUE; + memcpy(scan_info->ssid.SSID, ssid.SSID, ssid.SSID_len); + scan_info->ssid.SSID_len = ssid.SSID_len; + err = wl_escan_set_scan(dev, scan_info); + kfree(scan_info); + return err; #else + wext_info = dhd->wext_info; iscan = &wext_info->iscan; WL_TRACE(("%s: SIOCSIWSCAN iscan=%p\n", dev->name, iscan)); #ifdef WL_EXT_IAPSTA @@ -1532,7 +1554,7 @@ static #endif int wl_iw_handle_scanresults_ies(char **event_p, char *end, - struct iw_request_info *info, wl_bss_info_t *bi) + struct iw_request_info *info, wl_bss_info_v109_t *bi) { #if WIRELESS_EXT > 17 struct iw_event iwe; @@ -1546,17 +1568,20 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, if (bi->ie_length) { /* look for wpa/rsn ies in the ie list... */ bcm_tlv_t *ie; - uint8 *ptr = ((uint8 *)bi) + bi->ie_offset; + uint8 *ptr = ((uint8 *)bi) + bi->ie_offset, *ie_data; int ptr_len = bi->ie_length; /* OSEN IE */ - if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_VS_ID)) && - ie->len > WFA_OUI_LEN + 1 && - !bcmp((const void *)&ie->data[0], (const void *)WFA_OUI, WFA_OUI_LEN) && - ie->data[WFA_OUI_LEN] == WFA_OUI_TYPE_OSEN) { - iwe.cmd = IWEVGENIE; - iwe.u.data.length = ie->len + 2; - event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); + ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_VS_ID); + if (ie) { + ie_data = ie->data; + if (ie->len > WFA_OUI_LEN + 1 && + !bcmp((const void *)&ie->data[0], (const void *)WFA_OUI, WFA_OUI_LEN) && + ie_data[WFA_OUI_LEN] == WFA_OUI_TYPE_OSEN) { + iwe.cmd = IWEVGENIE; + iwe.u.data.length = ie->len + 2; + event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); + } } ptr = ((uint8 *)bi) + bi->ie_offset; @@ -1596,7 +1621,7 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, } #ifdef BCMWAPI_WPI - ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); + ptr = ((uint8 *)bi) + sizeof(wl_bss_info_v109_t); ptr_len = bi->ie_length; while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WAPI_ID))) { @@ -1639,14 +1664,15 @@ static int wl_iw_get_scan( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + struct iw_point *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; channel_info_t ci; - wl_scan_results_t *list; + wl_scan_results_v109_t *list; struct iw_event iwe; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; int error, i, j; char *event = extra, *end = extra + dwrq->length, *value; uint buflen = dwrq->length; @@ -1679,10 +1705,10 @@ wl_iw_get_scan( list->version = dtoh32(list->version); list->count = dtoh32(list->count); - ASSERT(list->version == WL_BSS_INFO_VERSION); + ASSERT(list->version == WL_BSS_INFO_VER_109); for (i = 0; i < list->count && i < IW_MAX_AP; i++) { - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + buflen)); @@ -1769,16 +1795,17 @@ static int wl_iw_iscan_get_scan( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; struct dhd_pub *dhd = dhd_get_pub(dev); - wl_wext_info_t *wext_info = NULL; #ifndef WL_ESCAN - wl_scan_results_t *list; + wl_wext_info_t *wext_info = NULL; + wl_scan_results_v109_t *list; struct iw_event iwe; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; int ii, j; int apcnt; char *event = extra, *end = extra + dwrq->length, *value; @@ -1789,7 +1816,6 @@ wl_iw_iscan_get_scan( #endif DHD_CHECK(dhd, dev); - wext_info = dhd->wext_info; #ifdef WL_ESCAN return wl_escan_get_scan(dev, info, dwrq, extra); #else @@ -1798,6 +1824,7 @@ wl_iw_iscan_get_scan( if (!extra) return -EINVAL; + wext_info = dhd->wext_info; /* use backup if our thread is not successful */ iscan = &wext_info->iscan; if ((!iscan) || (iscan->sysioc_pid < 0)) { @@ -1814,15 +1841,15 @@ wl_iw_iscan_get_scan( p_buf = iscan->list_hdr; /* Get scan results */ while (p_buf != iscan->list_cur) { - list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results; + list = &((wl_iscan_results_v109_t*)p_buf->iscan_buf)->results; - if (list->version != WL_BSS_INFO_VERSION) { - WL_ERROR(("list->version %d != WL_BSS_INFO_VERSION\n", list->version)); + if (list->version != WL_BSS_INFO_VER_109) { + WL_ERROR(("list->version %d != WL_BSS_INFO_VER_109\n", list->version)); } bi = NULL; for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) { - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + WLC_IW_ISCAN_MAXLEN)); @@ -1919,10 +1946,11 @@ static int wl_iw_set_essid( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wlc_ssid_t ssid; int error; struct dhd_pub *dhd = dhd_get_pub(dev); @@ -1982,10 +2010,11 @@ static int wl_iw_get_essid( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wlc_ssid_t ssid; int error; @@ -2004,14 +2033,15 @@ wl_iw_get_essid( /* Max SSID length check */ if (ssid.SSID_len > IW_ESSID_MAX_SIZE) { ssid.SSID_len = IW_ESSID_MAX_SIZE; + /* Get the current SSID */ + memcpy(extra, ssid.SSID, ssid.SSID_len); + /* NULL terminating as length of extra buffer is IW_ESSID_MAX_SIZE ie 32 */ + extra[IW_ESSID_MAX_SIZE-1] = '\0'; + } else { + /* Get the current SSID */ + memcpy(extra, ssid.SSID, ssid.SSID_len); } - /* Get the current SSID */ - memcpy(extra, ssid.SSID, ssid.SSID_len); - - /* NULL terminating as length of extra buffer is IW_ESSID_MAX_SIZE ie 32 */ - extra[IW_ESSID_MAX_SIZE] = '\0'; - dwrq->length = ssid.SSID_len; dwrq->flags = 1; /* active */ @@ -2023,10 +2053,11 @@ static int wl_iw_set_nick( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_iw_t *iw = IW_DEV_IF(dev); WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name)); @@ -2047,10 +2078,11 @@ static int wl_iw_get_nick( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_iw_t *iw = IW_DEV_IF(dev); WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name)); @@ -2066,10 +2098,11 @@ wl_iw_get_nick( static int wl_iw_set_rate( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->bitrate; wl_rateset_t rateset; int error, rate, i, error_bg, error_a; @@ -2132,10 +2165,11 @@ static int wl_iw_set_rate( static int wl_iw_get_rate( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->bitrate; int error, rate; WL_TRACE(("%s: SIOCGIWRATE\n", dev->name)); @@ -2153,10 +2187,11 @@ static int wl_iw_set_rts( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->rts; int error, rts; WL_TRACE(("%s: SIOCSIWRTS\n", dev->name)); @@ -2178,10 +2213,11 @@ static int wl_iw_get_rts( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->rts; int error, rts; WL_TRACE(("%s: SIOCGIWRTS\n", dev->name)); @@ -2200,10 +2236,11 @@ static int wl_iw_set_frag( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->frag; int error, frag; WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name)); @@ -2225,10 +2262,11 @@ static int wl_iw_get_frag( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->frag; int error, fragthreshold; WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name)); @@ -2247,10 +2285,11 @@ static int wl_iw_set_txpow( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->txpower; int error, disable; uint16 txpwrmw; WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name)); @@ -2287,10 +2326,11 @@ static int wl_iw_get_txpow( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->txpower; int error, disable, txpwrdbm; uint8 result; @@ -2315,10 +2355,11 @@ static int wl_iw_set_retry( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->retry; int error, lrl, srl; WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name)); @@ -2362,10 +2403,11 @@ static int wl_iw_get_retry( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->retry; int error, lrl, srl; WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name)); @@ -2403,10 +2445,11 @@ static int wl_iw_set_encode( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_wsec_key_t key; int error, val, wsec; @@ -2492,10 +2535,11 @@ static int wl_iw_get_encode( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_wsec_key_t key; int error, val, wsec, auth; @@ -2555,10 +2599,11 @@ static int wl_iw_set_power( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->power; int error, pm; WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name)); @@ -2576,10 +2621,11 @@ static int wl_iw_get_power( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->power; int error, pm; WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name)); @@ -2599,10 +2645,11 @@ static int wl_iw_set_wpaie( struct net_device *dev, struct iw_request_info *info, - struct iw_point *iwp, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *iwp = (struct iw_point *)wrqu; #if defined(BCMWAPI_WPI) uchar buf[WLC_IOCTL_SMLEN] = {0}; uchar *p = buf; @@ -2627,10 +2674,11 @@ static int wl_iw_get_wpaie( struct net_device *dev, struct iw_request_info *info, - struct iw_point *iwp, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *iwp = (struct iw_point *)wrqu; WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name)); iwp->length = 64; dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length); @@ -2641,10 +2689,11 @@ static int wl_iw_set_encodeext( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_wsec_key_t key; int error; struct iw_encode_ext *iwe; @@ -2793,7 +2842,7 @@ static int wl_iw_set_pmksa( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { @@ -2801,7 +2850,7 @@ wl_iw_set_pmksa( struct iw_pmksa *iwpmksa; uint i; char eabuf[ETHER_ADDR_STR_LEN]; - pmkid_t *pmkid_array = NULL; + pmkid_v1_t *pmkid_array = NULL; struct dhd_pub *dhd = dhd_get_pub(dev); wl_wext_info_t *wext_info = NULL; @@ -2818,7 +2867,7 @@ wl_iw_set_pmksa( bzero((char *)pmk_list, sizeof(struct pmk_list)); } if (iwpmksa->cmd == IW_PMKSA_REMOVE) { - pmkid_list_t pmkid, *pmkidptr; + pmkid_list_v1_t pmkid, *pmkidptr; pmkidptr = &pmkid; bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN); bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN); @@ -2883,7 +2932,7 @@ static int wl_iw_get_encodeext( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { @@ -2895,10 +2944,11 @@ static int wl_iw_set_wpaauth( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->param; int error = 0; int paramid; int paramval; @@ -3153,10 +3203,11 @@ static int wl_iw_get_wpaauth( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->param; int error; int paramid; int paramval = 0; @@ -3323,6 +3374,7 @@ static const iw_handler wl_iw_handler[] = }; #if WIRELESS_EXT > 12 +#ifdef CONFIG_WEXT_PRIV enum { WL_IW_SET_LEDDC = SIOCIWFIRSTPRIV, WL_IW_SET_VLANMODE, @@ -3358,15 +3410,18 @@ static struct iw_priv_args wl_iw_priv_args[] = { }, { 0, 0, 0, { 0 } } }; +#endif /* CONFIG_WEXT_PRIV */ const struct iw_handler_def wl_iw_handler_def = { .num_standard = ARRAYSIZE(wl_iw_handler), + .standard = (const iw_handler *) wl_iw_handler, +#ifdef CONFIG_WEXT_PRIV .num_private = ARRAY_SIZE(wl_iw_priv_handler), .num_private_args = ARRAY_SIZE(wl_iw_priv_args), - .standard = (const iw_handler *) wl_iw_handler, .private = wl_iw_priv_handler, .private_args = wl_iw_priv_args, +#endif /* CONFIG_WEXT_PRIV */ #if WIRELESS_EXT >= 19 get_wireless_stats: dhd_get_wireless_stats, #endif /* WIRELESS_EXT >= 19 */ @@ -3851,10 +3906,12 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat int rssi; scb_val_t scb_val; #if WIRELESS_EXT > 11 +#ifdef WL_NAN char *cntbuf = NULL; wl_cnt_info_t *cntinfo; uint16 ver; uint32 corerev = 0; +#endif #endif /* WIRELESS_EXT > 11 */ phy_noise = 0; @@ -3898,6 +3955,7 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat #endif /* WIRELESS_EXT > 18 */ #if WIRELESS_EXT > 11 +#ifdef WL_NAN WL_TRACE(("wl_iw_get_wireless_stats counters\n *****")); cntbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL); @@ -3918,12 +3976,10 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat cntinfo->version = dtoh16(cntinfo->version); cntinfo->datalen = dtoh16(cntinfo->datalen); ver = cntinfo->version; -#ifdef WL_NAN CHK_CNTBUF_DATALEN(cntbuf, MAX_WLIW_IOCTL_LEN); -#endif - if (ver > WL_CNT_T_VERSION) { + if (ver > WL_CNT_VERSION_XTLV) { WL_TRACE(("\tIncorrect version of counters struct: expected %d; got %d\n", - WL_CNT_T_VERSION, ver)); + WL_CNT_VERSION_XTLV, ver)); res = BCME_VERSION; goto done; } @@ -3939,7 +3995,6 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat corerev = dtoh32(revinfo.corerev); } -#ifdef WL_NAN res = wl_cntbuf_to_xtlv_format(NULL, cntinfo, MAX_WLIW_IOCTL_LEN, corerev); if (res) { WL_ERROR(("wl_cntbuf_to_xtlv_format failed %d\n", res)); @@ -3955,9 +4010,11 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat done: #if WIRELESS_EXT > 11 +#ifdef WL_NAN if (cntbuf) { kfree(cntbuf); } +#endif #endif /* WIRELESS_EXT > 11 */ return res; } @@ -3989,7 +4046,7 @@ wl_iw_set_event_mask(struct net_device *dev) } static int -wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid) +wl_iw_iscan_prep(wl_scan_params_v1_t *params, wlc_ssid_t *ssid) { int err = 0; @@ -4015,14 +4072,14 @@ wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid) static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) { - int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)); - wl_iscan_params_t *params; + int params_size = (WL_SCAN_PARAMS_V1_FIXED_SIZE + OFFSETOF(wl_iscan_params_v1_t, params)); + wl_iscan_params_v1_t *params; int err = 0; if (ssid && ssid->SSID_len) { params_size += sizeof(wlc_ssid_t); } - params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); + params = (wl_iscan_params_v1_t*)kmalloc(params_size, GFP_KERNEL); if (params == NULL) { return -ENOMEM; } @@ -4032,11 +4089,11 @@ wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) err = wl_iw_iscan_prep(¶ms->params, ssid); if (!err) { - params->version = htod32(ISCAN_REQ_VERSION); + params->version = htod32(ISCAN_REQ_VERSION_V1); params->action = htod16(action); params->scan_duration = htod16(0); - /* params_size += OFFSETOF(wl_iscan_params_t, params); */ + /* params_size += OFFSETOF(wl_iscan_params_v1_t, params); */ (void) dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size, iscan->ioctlbuf, WLC_IOCTL_SMLEN); } @@ -4050,9 +4107,9 @@ wl_iw_iscan_get(iscan_info_t *iscan) { iscan_buf_t * buf; iscan_buf_t * ptr; - wl_iscan_results_t * list_buf; - wl_iscan_results_t list; - wl_scan_results_t *results; + wl_iscan_results_v109_t * list_buf; + wl_iscan_results_v109_t list; + wl_scan_results_v109_t *results; uint32 status; /* buffers are allocated on demand */ @@ -4076,9 +4133,9 @@ wl_iw_iscan_get(iscan_info_t *iscan) } } memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN); - list_buf = (wl_iscan_results_t*)buf->iscan_buf; + list_buf = (wl_iscan_results_v109_t*)buf->iscan_buf; results = &list_buf->results; - results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE; + results->buflen = WL_ISCAN_RESULTS_V109_FIXED_SIZE; results->version = 0; results->count = 0; @@ -4088,7 +4145,7 @@ wl_iw_iscan_get(iscan_info_t *iscan) iscan->dev, "iscanresults", &list, - WL_ISCAN_RESULTS_FIXED_SIZE, + WL_ISCAN_RESULTS_V109_FIXED_SIZE, buf->iscan_buf, WLC_IW_ISCAN_MAXLEN); results->buflen = dtoh32(results->buflen); @@ -4277,14 +4334,12 @@ s32 wl_iw_autochannel(struct net_device *dev, char* command, int total_len) { struct dhd_pub *dhd = dhd_get_pub(dev); - wl_wext_info_t *wext_info = NULL; int ret = 0; #ifdef WL_ESCAN int bytes_written = -1; #endif DHD_CHECK(dhd, dev); - wext_info = dhd->wext_info; #ifdef WL_ESCAN sscanf(command, "%*s %d", &dhd->escan->autochannel); if (dhd->escan->autochannel == 0) { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.h old mode 100755 new mode 100644 index e161006a2bd6..a16265501e25 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.h @@ -83,7 +83,6 @@ typedef struct wl_iw_extra_params { #define WL_IW_RSSI_INVALID 0 /* invalid RSSI value */ #define MAX_WX_STRING 80 #define SSID_FMT_BUF_LEN ((4 * 32) + 1) -#define isprint(c) bcm_isprint(c) #define WL_IW_SET_ACTIVE_SCAN (SIOCIWFIRSTPRIV+1) #define WL_IW_GET_RSSI (SIOCIWFIRSTPRIV+3) #define WL_IW_SET_PASSIVE_SCAN (SIOCIWFIRSTPRIV+5) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_linux_mon.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_linux_mon.c old mode 100755 new mode 100644 index d8b69aaba857..42445271d581 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_linux_mon.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_linux_mon.c @@ -1,7 +1,7 @@ /* * Broadcom Dongle Host Driver (DHD), Linux monitor network interface * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_roam.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_roam.c old mode 100755 new mode 100644 index c6254da1655b..e061b342c51d --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_roam.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_roam.c @@ -1,7 +1,7 @@ /* * Linux roam cache * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -75,6 +75,9 @@ void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver) char iobuf[WLC_IOCTL_SMLEN]; struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); wlc_ssid_t ssid; +#ifdef WL_DUAL_STA + struct net_info *iter, *next; +#endif /* WL_DUAL_STA */ if (!cfg->rcc_enabled) { return; @@ -87,6 +90,22 @@ void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver) } #endif /* WES_SUPPORT */ +#ifdef WL_DUAL_STA + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + for_each_ndev(cfg, iter, next) { + GCC_DIAGNOSTIC_POP(); + if ((iter->wdev) && (iter->iftype == WL_IF_TYPE_STA)) { + struct net_device *ndev = iter->wdev->netdev; + if (IS_INET_LINK_NDEV(cfg, ndev)) { + /* Update the net device with primary interface */ + dev = ndev; + WL_DBG(("ndev considered for RCC %s\n", dev->name)); + break; + } + } + } +#endif /* WL_DUAL_STA */ + if (!wl_get_drv_status(cfg, CONNECTED, dev)) { WL_DBG(("Not associated\n")); return; @@ -159,7 +178,7 @@ void reset_roam_cache(struct bcm_cfg80211 *cfg) static void add_roam_cache_list(uint8 *SSID, uint32 SSID_len, chanspec_t chanspec) { - int i; + int i, ret = 0; uint8 channel; char chanbuf[CHANSPEC_STR_LEN]; @@ -167,6 +186,11 @@ add_roam_cache_list(uint8 *SSID, uint32 SSID_len, chanspec_t chanspec) return; } + if (SSID_len > DOT11_MAX_SSID_LEN) { + WL_ERR(("SSID len %u out of bounds [0-32]\n", SSID_len)); + return; + } + for (i = 0; i < n_roam_cache; i++) { if ((roam_cache[i].ssid_len == SSID_len) && (roam_cache[i].chanspec == chanspec) && @@ -178,16 +202,22 @@ add_roam_cache_list(uint8 *SSID, uint32 SSID_len, chanspec_t chanspec) roam_cache[n_roam_cache].ssid_len = SSID_len; channel = wf_chspec_ctlchan(chanspec); - WL_DBG(("CHSPEC = %s, CTL %d SSID %s\n", + WL_DBG(("CHSPEC = %s, CTL %d SSID %.32s\n", wf_chspec_ntoa_ex(chanspec, chanbuf), channel, SSID)); roam_cache[n_roam_cache].chanspec = CHSPEC_BAND(chanspec) | band_bw | channel; - (void)memcpy_s(roam_cache[n_roam_cache].ssid, SSID_len, SSID, SSID_len); + ret = memcpy_s(roam_cache[n_roam_cache].ssid, + sizeof(roam_cache[n_roam_cache].ssid), SSID, SSID_len); + if (ret) { + WL_ERR(("memcpy failed:%d, destsz:%zu, n:%d\n", + ret, sizeof(roam_cache[n_roam_cache].ssid), SSID_len)); + return; + } n_roam_cache++; } void -add_roam_cache(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi) +add_roam_cache(struct bcm_cfg80211 *cfg, wl_bss_info_v109_t *bi) { if (!cfg->rcc_enabled) { return; @@ -226,7 +256,7 @@ int get_roam_channel_list(struct bcm_cfg80211 *cfg, chanspec_t target_chan, n++; } - WL_DBG((" %s: 0x%04X\n", __FUNCTION__, channels[0])); + WL_SCAN(("0x%04X\n", channels[0])); #ifdef WES_SUPPORT if (cfg->roamscan_mode == ROAMSCAN_MODE_WES) { @@ -242,7 +272,7 @@ int get_roam_channel_list(struct bcm_cfg80211 *cfg, chanspec_t target_chan, ch = wf_chspec_ctlchan(ch) | CHSPEC_BAND(ch) | band_bw; if (band_match && !is_duplicated_channel(channels, n, ch)) { - WL_DBG(("%s: Chanspec = %s\n", __FUNCTION__, + WL_SCAN(("Chanspec = %s\n", wf_chspec_ntoa_ex(ch, chanbuf))); channels[n++] = ch; if (n >= n_channels) { @@ -270,7 +300,7 @@ int get_roam_channel_list(struct bcm_cfg80211 *cfg, chanspec_t target_chan, band_match && !is_duplicated_channel(channels, n, ch) && (memcmp(roam_cache[i].ssid, ssid->SSID, ssid->SSID_len) == 0)) { /* match found, add it */ - WL_DBG(("%s: Chanspec = %s\n", __FUNCTION__, + WL_SCAN(("Chanspec = %s\n", wf_chspec_ntoa_ex(ch, chanbuf))); channels[n++] = ch; if (n >= n_channels) { @@ -334,29 +364,59 @@ get_roamscan_chanspec_list(struct net_device *dev, chanspec_t *chanspecs) return i; } +bool +check_prune_roam_band(uint8 allowed_band, chanspec_t chanspec) +{ + int ret = FALSE; + + if ((allowed_band == WLC_ROAM_ALLOW_BAND_AUTO) || + (allowed_band == WLC_ROAM_ALLOW_BAND_MAX)) { + return ret; + } + + /* Pruned BSS via ROAM Band mode */ + if ((CHSPEC_IS2G(chanspec) && !(allowed_band & WLC_ROAM_ALLOW_BAND_2G))) { + ret = TRUE; + } else if (CHSPEC_IS5G(chanspec) && !(allowed_band & WLC_ROAM_ALLOW_BAND_5G)) { + ret = TRUE; +#ifdef WL_6G_BAND + } else if (CHSPEC_IS6G(chanspec) && !(allowed_band & WLC_ROAM_ALLOW_BAND_6G)) { + ret = TRUE; +#endif /* WL_6G_BAND */ + } + + return ret; +} + int set_roamscan_chanspec_list(struct net_device *dev, uint nchan, chanspec_t *chanspecs) { - int i; + int i, j; int error; wl_roam_channel_list_t channel_list; - char iobuf[WLC_IOCTL_SMLEN]; struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - cfg->roamscan_mode = ROAMSCAN_MODE_WES; + char iobuf[WLC_IOCTL_SMLEN]; if (nchan > MAX_ROAM_CHANNEL) { nchan = MAX_ROAM_CHANNEL; } - for (i = 0; i < nchan; i++) { - roam_cache[i].chanspec = chanspecs[i]; - channel_list.channels[i] = chanspecs[i]; - + for (i = 0, j = 0; i < nchan; i++) { + if (!wf_chspec_valid(chanspecs[i])) { + WL_ERR(("%02d/%d: invalid chan: 0x%04x\n", i, nchan, chanspecs[i])); + continue; + } + if (check_prune_roam_band(cfg->roam_allowed_band, chanspecs[i])) { + WL_ERR(("%02d/%d: Pruned ROAM band(%d) 0x%04x\n", i, nchan, + cfg->roam_allowed_band, chanspecs[i])); + continue; + } + channel_list.channels[j] = roam_cache[j].chanspec = chanspecs[i]; WL_DBG(("%02d/%d: chan: 0x%04x\n", i, nchan, chanspecs[i])); + j++; } - n_roam_cache = nchan; - channel_list.n = nchan; + channel_list.n = n_roam_cache = j; /* need to set ROAMSCAN_MODE_NORMAL to update roamscan_channels, * otherwise, it won't be updated @@ -373,11 +433,6 @@ set_roamscan_chanspec_list(struct net_device *dev, uint nchan, chanspec_t *chans WL_ERR(("Failed to set roamscan channels, error = %d\n", error)); return error; } - error = wldev_iovar_setint(dev, "roamscan_mode", ROAMSCAN_MODE_WES); - if (error) { - WL_ERR(("Failed to set roamscan mode to %d, error = %d\n", - ROAMSCAN_MODE_WES, error)); - } return error; } @@ -413,7 +468,12 @@ add_roamscan_chanspec_list(struct net_device *dev, uint nchan, chanspec_t *chans WL_DBG(("Add Roam scan channel count %d\n", nchan)); for (i = 0; i < nchan; i++) { - if (chanspecs[i] == 0) { + if (!wf_chspec_valid(chanspecs[i])) { + continue; + } + if (check_prune_roam_band(cfg->roam_allowed_band, chanspecs[i])) { + WL_ERR(("%02d/%d: Pruned ROAM band(%d) 0x%04x\n", i, nchan, + cfg->roam_allowed_band, chanspecs[i])); continue; } add_roam_cache_list(ssid.SSID, ssid.SSID_len, chanspecs[i]); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_timer.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_timer.c new file mode 100644 index 000000000000..0255acd55fbd --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_timer.c @@ -0,0 +1,611 @@ +#include +#ifdef WL_TIMER + +#define TIMER_ERROR(name, arg1, args...) \ + do { \ + if (android_msg_level & ANDROID_ERROR_LEVEL) { \ + printf("[%s] TIMER-ERROR) %s : " arg1, name, __func__, ## args); \ + } \ + } while (0) +#define TIMER_TRACE(name, arg1, args...) \ + do { \ + if (android_msg_level & ANDROID_TRACE_LEVEL) { \ + printf("[%s] TIMER-TRACE) %s : " arg1, name, __func__, ## args); \ + } \ + } while (0) + +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ + 4 && __GNUC_MINOR__ >= 6)) +#define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \ +_Pragma("GCC diagnostic push") \ +_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \ +(entry) = list_first_entry((ptr), type, member); \ +_Pragma("GCC diagnostic pop") \ + +#define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \ +_Pragma("GCC diagnostic push") \ +_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \ +entry = container_of((ptr), type, member); \ +_Pragma("GCC diagnostic pop") \ + +#else +#define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \ +(entry) = list_first_entry((ptr), type, member); \ + +#define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \ +entry = container_of((ptr), type, member); \ + +#endif /* STRICT_GCC_WARNINGS */ + +typedef void(*FUNC_HANDLER) (void *cb_argu); + +struct wl_func_q { + struct list_head eq_list; + FUNC_HANDLER cb_func; + void *cb_argu; +}; + +typedef void(*TIMER_HANDLER) (void *cb_argu); + +typedef struct timer_handler_list { + struct list_head list; + struct net_device *net; + timer_list_compat_t *timer; + TIMER_HANDLER cb_func; + void *cb_argu; + uint tmo_ms; + ulong tmo_jiffies; +} timer_handler_list_t; + +typedef struct wl_timer_params { + dhd_pub_t *pub; + struct list_head timer_list; + struct list_head eq_list; + timer_list_compat_t timer; + spinlock_t eq_lock; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + struct workqueue_struct *timer_workq; + struct work_struct timer_work; + struct workqueue_struct *func_workq; + struct work_struct func_work; +#else + tsk_ctl_t thr_timer_ctl; + tsk_ctl_t thr_func_ctl; +#endif +} wl_timer_params_t; + +static unsigned long +wl_func_lock_eq(struct wl_timer_params *timer_params) +{ + unsigned long flags; + + spin_lock_irqsave(&timer_params->eq_lock, flags); + return flags; +} + +static void +wl_func_unlock_eq(struct wl_timer_params *timer_params, unsigned long flags) +{ + spin_unlock_irqrestore(&timer_params->eq_lock, flags); +} + +static void +wl_func_init_eq_lock(struct wl_timer_params *timer_params) +{ + spin_lock_init(&timer_params->eq_lock); +} + +static void +wl_func_init_eq(struct wl_timer_params *timer_params) +{ + wl_func_init_eq_lock(timer_params); + INIT_LIST_HEAD(&timer_params->eq_list); +} + +static void +wl_func_flush_eq(struct wl_timer_params *timer_params) +{ + struct wl_func_q *e; + unsigned long flags; + + flags = wl_func_lock_eq(timer_params); + while (!list_empty_careful(&timer_params->eq_list)) { + BCM_SET_LIST_FIRST_ENTRY(e, &timer_params->eq_list, struct wl_func_q, eq_list); + list_del(&e->eq_list); + kfree(e); + } + wl_func_unlock_eq(timer_params, flags); +} + +static struct wl_func_q * +wl_func_deq(struct wl_timer_params *timer_params) +{ + struct wl_func_q *e = NULL; + unsigned long flags; + + flags = wl_func_lock_eq(timer_params); + if (likely(!list_empty(&timer_params->eq_list))) { + BCM_SET_LIST_FIRST_ENTRY(e, &timer_params->eq_list, struct wl_func_q, eq_list); + list_del(&e->eq_list); + } + wl_func_unlock_eq(timer_params, flags); + + return e; +} + +static s32 +wl_func_enq(struct wl_timer_params *timer_params, + void *cb_func, void *cb_argu) +{ + struct wl_func_q *e; + s32 err = 0; + uint32 funcq_size; + unsigned long flags; + gfp_t aflags; + + funcq_size = sizeof(struct wl_func_q); + aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; + e = kzalloc(funcq_size, aflags); + if (unlikely(!e)) { + TIMER_ERROR("wlan", "funcq_size alloc failed %d\n", funcq_size); + return -ENOMEM; + } + e->cb_func = cb_func; + e->cb_argu = cb_argu; + flags = wl_func_lock_eq(timer_params); + list_add_tail(&e->eq_list, &timer_params->eq_list); + wl_func_unlock_eq(timer_params, flags); + + return err; +} + +static void +wl_func_put(struct wl_func_q *e) +{ + kfree(e); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) +static void wl_func_handler(struct work_struct *data); +#define WL_FUNC_HANDLER() static void wl_func_handler(struct work_struct *data) +#else +static int wl_func_handler(void *data); +#define WL_FUNC_HANDLER() static int wl_func_handler(void *data) +#endif + +WL_FUNC_HANDLER() +{ + struct wl_timer_params *timer_params = NULL; + struct wl_func_q *e; + struct net_device *net = NULL; + dhd_pub_t *dhd; + unsigned long flags = 0; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)) + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + timer_params = (struct wl_timer_params *)tsk->parent; +#else + BCM_SET_CONTAINER_OF(timer_params, data, struct wl_timer_params, func_work); +#endif + + dhd = timer_params->pub; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)) + while (1) { + if (down_interruptible(&tsk->sema) == 0) { + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + break; + } +#endif + DHD_EVENT_WAKE_LOCK(dhd); + while ((e = wl_func_deq(timer_params))) { + DHD_GENERAL_LOCK(dhd, flags); + if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd)) { + TIMER_ERROR(net->name, "BUS is DOWN.\n"); + DHD_GENERAL_UNLOCK(dhd, flags); + goto fail; + } + DHD_GENERAL_UNLOCK(dhd, flags); + e->cb_func(e->cb_argu); +fail: + wl_func_put(e); + } + DHD_EVENT_WAKE_UNLOCK(dhd); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)) + } else { + break; + } + } + complete_and_exit(&tsk->completed, 0); +#endif +} + +void +wl_func_send(void *params, void *cb_func, void *cb_argu) +{ + struct wl_timer_params *timer_params = params; + + if (timer_params == NULL) { + TIMER_ERROR("wlan", "Stale ignored\n"); + return; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (timer_params->func_workq == NULL) { + TIMER_ERROR("wlan", "Event handler is not created\n"); + return; + } +#endif + + if (likely(!wl_func_enq(timer_params, cb_func, cb_argu))) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + queue_work(timer_params->func_workq, &timer_params->func_work); +#else + if (timer_params->thr_func_ctl.thr_pid >= 0) { + up(&timer_params->thr_func_ctl.sema); + } +#endif + } +} + +static s32 +wl_func_create_handler(struct wl_timer_params *timer_params) +{ + int ret = 0; + TIMER_TRACE("wlan", "Enter\n"); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (!timer_params->func_workq) { + timer_params->func_workq = alloc_workqueue("timer_funcd", + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 0); + } + if (!timer_params->func_workq) { + TIMER_ERROR("wlan", "func_workq alloc_workqueue failed\n"); + ret = -ENOMEM; + } else { + INIT_WORK(&timer_params->func_work, wl_func_handler); + } +#else + PROC_START(wl_func_handler, timer_params, &timer_params->thr_func_ctl, 0, "timer_funcd"); + if (timer_params->thr_func_ctl.thr_pid < 0) { + ret = -ENOMEM; + } +#endif + + return ret; +} + +static void +wl_func_destroy_handler(struct wl_timer_params *timer_params) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (timer_params && timer_params->func_workq) { + cancel_work_sync(&timer_params->func_work); + destroy_workqueue(timer_params->func_workq); + timer_params->func_workq = NULL; + } +#else + if (timer_params->thr_func_ctl.thr_pid >= 0) { + PROC_STOP(&timer_params->thr_func_ctl); + } +#endif +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) +static void wl_timer_handler(struct work_struct *data); +#define WL_TIMER_HANDLER() static void wl_timer_handler(struct work_struct *data) +#else +static int wl_timer_handler(void *data); +#define WL_TIMER_HANDLER() static int wl_timer_handler(void *data) +#endif + +WL_TIMER_HANDLER() +{ + struct wl_timer_params *timer_params = NULL; + struct timer_handler_list *node, *next; + dhd_pub_t *dhd; + unsigned long flags = 0; + unsigned long cur_jiffies, diff_jiffies, min_jiffies = 0; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)) + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + timer_params = (struct wl_timer_params *)tsk->parent; +#else + BCM_SET_CONTAINER_OF(timer_params, data, struct wl_timer_params, timer_work); +#endif + + dhd = timer_params->pub; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)) + while (1) { + if (down_interruptible(&tsk->sema) == 0) { + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + break; + } +#endif + DHD_EVENT_WAKE_LOCK(dhd); + DHD_GENERAL_LOCK(dhd, flags); + if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd)) { + TIMER_ERROR("wlan", "BUS is DOWN.\n"); + DHD_GENERAL_UNLOCK(dhd, flags); + goto exit; + } + DHD_GENERAL_UNLOCK(dhd, flags); + cur_jiffies = jiffies; + list_for_each_entry_safe(node, next, &timer_params->timer_list, list) { + if (node->tmo_ms) { + if (time_after(cur_jiffies, node->tmo_jiffies)) { + wl_func_send(timer_params, node->cb_func, node->cb_argu); + node->tmo_ms = 0; + } else { + diff_jiffies = node->tmo_jiffies - cur_jiffies; + if (min_jiffies == 0) + min_jiffies = diff_jiffies; + else if (diff_jiffies < min_jiffies) + min_jiffies = diff_jiffies; + } + } + } + if (min_jiffies) + mod_timer(&timer_params->timer, jiffies + min_jiffies); +exit: + DHD_EVENT_WAKE_UNLOCK(dhd); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)) + } else { + break; + } + } + complete_and_exit(&tsk->completed, 0); +#endif +} + +void +wl_timer_kick_handler(wl_timer_params_t *timer_params) +{ + if (timer_params == NULL) { + TIMER_ERROR("wlan", "timer_params not ready\n"); + return; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (timer_params->timer_workq == NULL) { + TIMER_ERROR("wlan", "timer handler is not created\n"); + return; + } + queue_work(timer_params->timer_workq, &timer_params->timer_work); +#else + if (timer_params->thr_timer_ctl.thr_pid >= 0) { + up(&timer_params->thr_timer_ctl.sema); + } +#endif +} + +static void +wl_timer_timeout(unsigned long data) +{ + struct wl_timer_params *timer_params = (struct wl_timer_params *)data; + + if (!timer_params) { + TIMER_ERROR("wlan", "timer_params is not ready\n"); + return; + } + + TIMER_TRACE("wlan", "timer expired\n"); + wl_timer_kick_handler(timer_params); +} + +static s32 +wl_timer_create_handler(struct wl_timer_params *timer_params) +{ + int ret = 0; + + TIMER_TRACE("wlan", "Enter\n"); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (!timer_params->timer_workq) { + timer_params->timer_workq = alloc_workqueue("timerd", + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 0); + } + if (!timer_params->timer_workq) { + TIMER_ERROR("wlan", "timer_workq alloc_workqueue failed\n"); + ret = -ENOMEM; + } else { + INIT_WORK(&timer_params->timer_work, wl_timer_handler); + } +#else + PROC_START(wl_timer_handler, timer_params, &timer_params->thr_timer_ctl, 0, "timerd"); + if (timer_params->thr_timer_ctl.thr_pid < 0) { + ret = -ENOMEM; + } +#endif + + return ret; +} + +static void +wl_timer_destroy_handler(struct wl_timer_params *timer_params) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (timer_params && timer_params->timer_workq) { + cancel_work_sync(&timer_params->timer_work); + destroy_workqueue(timer_params->timer_workq); + timer_params->timer_workq = NULL; + } +#else + if (timer_params->thr_timer_ctl.thr_pid >= 0) { + PROC_STOP(&timer_params->thr_timer_ctl); + } +#endif +} + +static void +wl_timer_free(struct wl_timer_params *timer_params) +{ + timer_handler_list_t *node, *next; + + list_for_each_entry_safe(node, next, &timer_params->timer_list, list) { + TIMER_TRACE(node->net->name, "Free timer\n"); + list_del(&node->list); + kfree(node); + } +} + +void +wl_timer_mod(dhd_pub_t *dhd, timer_list_compat_t *timer, uint32 tmo_ms) +{ + wl_timer_params_t *timer_params = dhd->timer_params; + timer_handler_list_t *node, *next; + bool found = FALSE; + + list_for_each_entry_safe(node, next, &timer_params->timer_list, list) { + if (node->timer == timer) { + node->tmo_ms = tmo_ms; + if (tmo_ms) { + TIMER_TRACE(node->net->name, "update timer %dms\n", tmo_ms); + node->tmo_jiffies = jiffies + msecs_to_jiffies(tmo_ms); + wl_timer_kick_handler(timer_params); + } + found = TRUE; + break; + } + } + if (!found) + TIMER_ERROR("wlan", "timer not found\n"); +} + +void +wl_timer_register(struct net_device *net, timer_list_compat_t *timer, void *cb_func) +{ + dhd_pub_t *dhd = dhd_get_pub(net); + wl_timer_params_t *timer_params = dhd->timer_params; + timer_handler_list_t *node, *next, *leaf; + + list_for_each_entry_safe(node, next, &timer_params->timer_list, list) { + if (node->timer == timer) { + TIMER_TRACE(net->name, "timer already registered\n"); + return; + } + } + + leaf = kmalloc(sizeof(timer_handler_list_t), GFP_KERNEL); + if (!leaf) { + TIMER_ERROR(net->name, "Memory alloc failure %d\n", + (int)sizeof(timer_handler_list_t)); + return; + } + memset(leaf, 0, sizeof(timer_handler_list_t)); + leaf->net = net; + leaf->timer = timer; + leaf->cb_func = cb_func; + leaf->cb_argu = net; + TIMER_ERROR(net->name, "timer registered tmo=%d\n", leaf->tmo_ms); + list_add_tail(&leaf->list, &timer_params->timer_list); + + return; +} + +void +wl_timer_deregister(struct net_device *net, timer_list_compat_t *timer) +{ + dhd_pub_t *dhd = dhd_get_pub(net); + wl_timer_params_t *timer_params = dhd->timer_params; + timer_handler_list_t *node, *next; + + list_for_each_entry_safe(node, next, &timer_params->timer_list, list) { + if (node->timer == timer) { + TIMER_TRACE(net->name, "timer deregistered\n"); + list_del(&node->list); + kfree(node); + } + } + return; +} + +static s32 +wl_timer_init_priv(struct wl_timer_params *timer_params) +{ + s32 err = 0; + + INIT_LIST_HEAD(&timer_params->timer_list); + if (wl_timer_create_handler(timer_params)) + return -ENOMEM; + wl_func_init_eq(timer_params); + if (wl_func_create_handler(timer_params)) + return -ENOMEM; + + return err; +} + +static void +wl_timer_deinit_priv(struct wl_timer_params *timer_params) +{ + wl_timer_free(timer_params); + wl_func_destroy_handler(timer_params); + wl_func_flush_eq(timer_params); + wl_timer_destroy_handler(timer_params); +} + +void +wl_timer_dettach(dhd_pub_t *dhdp) +{ + struct wl_timer_params *timer_params = dhdp->timer_params; + + if (timer_params) { + if (timer_pending(&timer_params->timer)) + del_timer_sync(&timer_params->timer); + wl_timer_deinit_priv(timer_params); + kfree(timer_params); + dhdp->timer_params = NULL; + } +} + +s32 +wl_timer_attach(struct net_device *net) +{ + struct dhd_pub *dhdp = dhd_get_pub(net); + struct wl_timer_params *timer_params = NULL; + s32 err = 0; + + timer_params = kmalloc(sizeof(wl_timer_params_t), GFP_KERNEL); + if (!timer_params) { + TIMER_ERROR(net->name, "Failed to allocate memory (%zu)\n", + sizeof(wl_timer_params_t)); + return -ENOMEM; + } + dhdp->timer_params = timer_params; + memset(timer_params, 0, sizeof(wl_timer_params_t)); + timer_params->pub = dhdp; + + err = wl_timer_init_priv(timer_params); + if (err) { + TIMER_ERROR(net->name, "Failed to wl_timer_init_priv (%d)\n", err); + goto exit; + } + init_timer_compat(&timer_params->timer, wl_timer_timeout, timer_params); + +exit: + if (err) + wl_timer_dettach(dhdp); + return err; +} +#else +void +wl_timer_mod(dhd_pub_t *dhd, timer_list_compat_t *timer, uint32 tmo_ms) +{ + if (timer_pending(timer)) + del_timer_sync(timer); + if (tmo_ms) + mod_timer(timer, jiffies + msecs_to_jiffies(tmo_ms)); +} + +void +wl_timer_register(struct net_device *net, timer_list_compat_t *timer, void *cb_func) +{ + init_timer_compat(timer, cb_func, net); +} + +void +wl_timer_deregister(struct net_device *net, timer_list_compat_t *timer) +{ + if (timer_pending(timer)) + del_timer_sync(timer); +} +#endif diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_timer.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_timer.h new file mode 100644 index 000000000000..6b43384682b7 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_timer.h @@ -0,0 +1,8 @@ +#ifndef _wl_timer_ +#define _wl_timer_ +s32 wl_timer_attach(struct net_device *net); +void wl_timer_dettach(dhd_pub_t *dhdp); +void wl_timer_register(struct net_device *net, timer_list_compat_t *timer, void *cb_func); +void wl_timer_deregister(struct net_device *net, timer_list_compat_t *timer); +void wl_timer_mod(dhd_pub_t *dhd, timer_list_compat_t *timer, uint32 tmo_ms); +#endif diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wlc_types.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wlc_types.h deleted file mode 100755 index fd98363b68ef..000000000000 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wlc_types.h +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Forward declarations for commonly used wl driver structs - * - * Copyright (C) 2020, Broadcom. - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * - * <> - * - * $Id$ - */ - -#ifndef _wlc_types_h_ -#define _wlc_types_h_ -#include - -/* Version of WLC interface to be returned as a part of wl_wlc_version structure. - */ - -#define WLC_API_VERSION_MAJOR 14 -#define WLC_API_VERSION_MINOR 0 - -/* forward declarations */ - -typedef struct wlc_info wlc_info_t; -typedef struct join_pref join_pref_t; -typedef struct wlcband wlcband_t; -typedef struct wlc_cmn_info wlc_cmn_info_t; -typedef struct wlc_assoc_info wlc_assoc_info_t; -typedef struct wlc_pm_info wlc_pm_info_t; - -typedef struct wlc_bsscfg wlc_bsscfg_t; -typedef struct wlc_mbss_info wlc_mbss_info_t; -typedef struct wlc_spt wlc_spt_t; -typedef struct scb scb_t; -typedef struct scb_iter scb_iter_t; -typedef struct vndr_ie_listel vndr_ie_listel_t; -typedef struct wlc_if wlc_if_t; -typedef struct wl_if wl_if_t; -typedef struct led_info led_info_t; -typedef struct bmac_led bmac_led_t; -typedef struct bmac_led_info bmac_led_info_t; -typedef struct seq_cmds_info wlc_seq_cmds_info_t; -typedef struct ota_test_info ota_test_info_t; -typedef struct apps_wlc_psinfo apps_wlc_psinfo_t; -typedef struct scb_module scb_module_t; -typedef struct hscb_module hscb_module_t; -typedef struct wlc_scb_handle wlc_scbh_t; -typedef struct ba_info ba_info_t; -typedef struct wlc_frminfo wlc_frminfo_t; -typedef struct amsdu_info amsdu_info_t; -typedef struct txq_info txq_info_t; -typedef struct wlc_mux_info wlc_mux_info_t; -typedef struct wlc_scbq_info wlc_scbq_info_t; -typedef struct txq txq_t; -typedef struct flow_ctx_info wlc_flow_ctx_info_t; -typedef struct cram_info cram_info_t; -typedef struct wlc_txq_info wlc_txq_info_t; -typedef struct wlc_hrt_info wlc_hrt_info_t; -typedef struct wlc_hrt_to wlc_hrt_to_t; -typedef struct wlc_cac wlc_cac_t; -typedef struct ampdu_tx_info ampdu_tx_info_t; -typedef struct ampdu_rx_info ampdu_rx_info_t; -typedef struct scb_ampdu_tx scb_ampdu_tx_t; -typedef struct scb_ampdu_tid_ini scb_ampdu_tid_ini_t; -typedef struct wlc_ratesel_info wlc_ratesel_info_t; -typedef struct ratesel_info ratesel_info_t; -#ifdef WLFIPS -typedef struct wl_fips_info wl_fips_info_t; -#endif -typedef struct wlc_ap_info wlc_ap_info_t; -typedef struct cs_info cs_info_t; -typedef struct wlc_scan_info wlc_scan_info_t; -typedef struct wlc_scan_cmn_info wlc_scan_cmn_t; -typedef struct wlc_slotted_bss_info wlc_slotted_bss_info_t; -typedef struct wl_bcn_report_cfg wl_bcn_report_cfg_t; -#ifdef WLAWDL -typedef struct wlc_awdl_info wlc_awdl_info_t; -#endif -#ifdef BCMPCIE_HP2P -typedef struct wlc_hp2p_info wlc_hp2p_info_t; -typedef struct wlc_hp2p_cmn wlc_hp2p_cmn_t; -#endif -#ifdef WLDFSP -typedef struct wlc_dfsp_info wlc_dfsp_info_t; -#endif /* WLDFSP */ -typedef struct tdls_info tdls_info_t; -typedef struct dls_info dls_info_t; -typedef struct l2_filter_info l2_filter_info_t; -typedef struct wlc_auth_info wlc_auth_info_t; -typedef struct wlc_sup_info wlc_sup_info_t; -typedef struct wlc_fbt_info wlc_fbt_info_t; -typedef struct wlc_assoc_mgr_info wlc_assoc_mgr_info_t; -typedef struct wlc_psta_info wlc_psta_info_t; -typedef struct wlc_mcnx_info wlc_mcnx_info_t; -typedef struct wlc_p2p_info wlc_p2p_info_t; -typedef struct wlc_cxnoa_info wlc_cxnoa_info_t; -typedef struct mchan_info mchan_info_t; -typedef struct wlc_mchan_context wlc_mchan_context_t; -typedef struct bta_info bta_info_t; -typedef struct wowlpf_info wowlpf_info_t; -typedef struct wlc_plt_info wlc_plt_pub_t; -typedef struct antsel_info antsel_info_t; -typedef struct bmac_pmq bmac_pmq_t; -typedef struct wmf_info wmf_info_t; -typedef struct wlc_rrm_info wlc_rrm_info_t; -typedef struct rm_info rm_info_t; - -typedef struct wlc_dpc_info wlc_dpc_info_t; - -typedef struct wlc_11h_info wlc_11h_info_t; -typedef struct wlc_tpc_info wlc_tpc_info_t; -typedef struct wlc_csa_info wlc_csa_info_t; -typedef struct wlc_quiet_info wlc_quiet_info_t; -typedef struct cca_info cca_info_t; -typedef struct itfr_info itfr_info_t; -typedef struct wlc_wbtext_info wlc_wbtext_info_t; -typedef struct wlc_wnm_info wlc_wnm_info_t; -typedef struct wlc_wnm_pdt_info wlc_wnm_pdt_info_t; -typedef struct wlc_wnm_roamscan_complete_data wlc_wnm_roamscan_complete_data_t; -typedef struct wlc_wnm_roamscan_complete_res wlc_wnm_roamscan_complete_res_t; -typedef struct wlc_11d_info wlc_11d_info_t; -typedef struct wlc_cntry_info wlc_cntry_info_t; - -typedef struct wlc_dfs_info wlc_dfs_info_t; - -typedef struct bsscfg_module bsscfg_module_t; - -typedef struct wlc_prot_info wlc_prot_info_t; -typedef struct wlc_prot_g_info wlc_prot_g_info_t; -typedef struct wlc_prot_n_info wlc_prot_n_info_t; -typedef struct wlc_prot_obss_info wlc_prot_obss_info_t; -typedef struct wlc_obss_dynbw wlc_obss_dynbw_t; -typedef struct wlc_11u_info wlc_11u_info_t; -typedef struct wlc_probresp_info wlc_probresp_info_t; -typedef struct wlc_wapi_info wlc_wapi_info_t; - -typedef struct wlc_tbtt_info wlc_tbtt_info_t; -typedef struct wlc_nic_info wlc_nic_info_t; - -typedef struct wlc_bssload_info wlc_bssload_info_t; - -typedef struct wlc_pcb_info wlc_pcb_info_t; -typedef struct wlc_txc_info wlc_txc_info_t; - -typedef struct wlc_trf_mgmt_ctxt wlc_trf_mgmt_ctxt_t; -typedef struct wlc_trf_mgmt_info wlc_trf_mgmt_info_t; - -typedef struct wlc_net_detect_ctxt wlc_net_detect_ctxt_t; - -typedef struct wlc_powersel_info wlc_powersel_info_t; -typedef struct powersel_info powersel_info_t; - -typedef struct wlc_lpc_info wlc_lpc_info_t; -typedef struct lpc_info lpc_info_t; -typedef struct rate_lcb_info rate_lcb_info_t; -typedef struct wlc_txbf_info wlc_txbf_info_t; -typedef struct wlc_mutx_info wlc_mutx_info_t; -typedef struct wlc_murx_info wlc_murx_info_t; - -typedef struct wlc_olpc_eng_info_t wlc_olpc_eng_info_t; -/* used by olpc to register for callbacks from stf */ -typedef void (*wlc_stf_txchain_evt_notify)(wlc_info_t *wlc); - -typedef struct wlc_rfc wlc_rfc_t; -typedef struct wlc_pktc_info wlc_pktc_info_t; - -typedef struct wlc_mfp_info wlc_mfp_info_t; - -typedef struct wlc_mdns_info wlc_mdns_info_t; - -typedef struct wlc_macfltr_info wlc_macfltr_info_t; - -typedef struct wlc_bs_data_info wlc_bs_data_info_t; - -typedef struct wlc_keymgmt wlc_keymgmt_t; -typedef struct wlc_key wlc_key_t; -typedef struct wlc_key_info wlc_key_info_t; - -typedef struct wlc_hw wlc_hw_t; -typedef struct wlc_hw_info wlc_hw_info_t; -typedef struct wlc_hwband wlc_hwband_t; - -typedef struct wlc_rx_stall_info wlc_rx_stall_info_t; -typedef struct wlc_txs_hist wlc_txs_hist_t; - -typedef struct wlc_tx_stall_info wlc_tx_stall_info_t; -typedef struct wlc_tx_stall_counters wlc_tx_stall_counters_t; - -typedef struct wlc_rmc_info wlc_rmc_info_t; - -typedef struct wlc_iem_info wlc_iem_info_t; - -typedef struct wlc_ier_info wlc_ier_info_t; -typedef struct wlc_ier_reg wlc_ier_reg_t; -typedef struct wlc_ier_reg_data wlc_ier_reg_data_t; -typedef struct wlc_ier_reg_cmn wlc_ier_reg_cmn_t; - -typedef struct wlc_filter_ie_info wlc_filter_ie_info_t; - -typedef struct wlc_ht_info wlc_ht_info_t; -typedef struct wlc_obss_info wlc_obss_info_t; -typedef struct wlc_vht_info wlc_vht_info_t; -typedef struct wlc_akm_info wlc_akm_info_t; - -typedef struct wlc_bss_info wlc_bss_info_t; - -typedef struct wlc_hs20_info wlc_hs20_info_t; -typedef struct wlc_hs20_cmn wlc_hs20_cmn_t; -typedef struct wlc_pmkid_info wlc_pmkid_info_t; -typedef struct wlc_btc_info wlc_btc_info_t; -typedef struct wlc_btc_hw_info wlc_btc_hw_info_t; - -typedef struct wlc_txh_info wlc_txh_info_t; - -typedef struct wlc_staprio_info wlc_staprio_info_t; -typedef struct wlc_stamon_info wlc_stamon_info_t; -typedef struct wlc_monitor_info wlc_monitor_info_t; -typedef struct monitor_info monitor_info_t; - -typedef struct wlc_debug_crash_info wlc_debug_crash_info_t; - -typedef struct wlc_nan_info wlc_nan_info_t; -typedef struct wlc_edv_info wlc_edv_info_t; -typedef struct wlc_tsmap_info wlc_tsmap_info_t; - -typedef struct wlc_wds_info wlc_wds_info_t; -typedef struct okc_info okc_info_t; -typedef struct wlc_aibss_info wlc_aibss_info_t; -typedef struct wlc_ipfo_info wlc_ipfo_info_t; -typedef struct wlc_stats_info wlc_stats_info_t; - -typedef struct wlc_pps_info wlc_pps_info_t; - -typedef struct duration_info duration_info_t; - -typedef struct wlc_pdsvc_info wlc_pdsvc_info_t; - -typedef struct wlc_swdiv_info wlc_swdiv_info_t; -typedef struct lqcm_stats lqcm_stats_t; - -/* For LTE Coex */ -typedef struct wlc_ltecx_info wlc_ltecx_info_t; - -typedef struct mws_scanreq_bms mws_scanreq_bms_t; - -typedef struct wlc_probresp_mac_filter_info wlc_probresp_mac_filter_info_t; - -typedef struct wlc_ltr_info wlc_ltr_info_t; - -typedef struct bwte_info bwte_info_t; - -typedef struct tbow_info tbow_info_t; - -typedef struct wlc_modesw_info wlc_modesw_info_t; - -typedef struct wlc_pm_mute_tx_info wlc_pm_mute_tx_t; - -typedef struct wlc_nr5gcx_info wlc_nr5gcx_info_t; - -typedef struct wlc_bcntrim_info wlc_bcntrim_info_t; -typedef wl_bcntrim_cfg_v1_t wl_bcntrim_cfg_t; -typedef wl_bcntrim_status_query_v1_t wl_bcntrim_status_query_t; -typedef wl_bcntrim_status_v1_t wl_bcntrim_status_t; -#define WL_BCNTRIM_STATUS_VERSION WL_BCNTRIM_STATUS_VERSION_1 -#define WL_BCNTRIM_CFG_VERSION WL_BCNTRIM_CFG_VERSION_1 - -typedef struct wlc_ops_info wlc_ops_info_t; -typedef wl_ops_cfg_v1_t wl_ops_cfg_t; -typedef wl_ops_status_v1_t wl_ops_status_t; -#define WL_OPS_STATUS_VERSION WL_OPS_STATUS_VERSION_1 -#define WL_OPS_CFG_VERSION WL_OPS_CFG_VERSION_1 - -typedef struct wlc_psbw_info wlc_psbw_info_t; -typedef wl_psbw_cfg_v1_t wl_psbw_cfg_t; -typedef wl_psbw_status_v1_t wl_psbw_status_t; -#define WL_PSBW_STATUS_VERSION WL_PSBW_STATUS_VERSION_1 -#define WL_PSBW_CFG_VERSION WL_PSBW_CFG_VERSION_1 - -typedef struct wlc_smfs_info wlc_smfs_info_t; -typedef struct wlc_misc_info wlc_misc_info_t; - -typedef struct wlc_eventq wlc_eventq_t; -typedef struct wlc_event wlc_event_t; - -typedef struct wlc_bsscfg_psq_info wlc_bsscfg_psq_info_t; -typedef struct wlc_bsscfg_viel_info wlc_bsscfg_viel_info_t; - -typedef struct wlc_txmod_info wlc_txmod_info_t; -typedef struct tx_path_node tx_path_node_t; - -typedef struct wlc_linkstats_info wlc_linkstats_info_t; - -typedef struct wl_shub_info wl_shub_info_t; - -typedef struct wlc_lq_info wlc_lq_info_t; -typedef struct chanim_info chanim_info_t; - -typedef struct wlc_mesh_info wlc_mesh_info_t; -typedef struct wlc_wlfc_info wlc_wlfc_info_t; - -typedef struct wlc_frag_info wlc_frag_info_t; -typedef struct wlc_bss_list wlc_bss_list_t; - -typedef struct wlc_msch_info wlc_msch_info_t; -typedef struct wlc_msch_req_handle wlc_msch_req_handle_t; - -typedef struct wlc_randmac_info wlc_randmac_info_t; - -typedef struct wlc_chanctxt wlc_chanctxt_t; -typedef struct wlc_chanctxt_info wlc_chanctxt_info_t; -typedef struct wlc_sta_info wlc_sta_info_t; - -typedef struct health_check_info health_check_info_t; -typedef struct wlc_act_frame_info wlc_act_frame_info_t; -typedef struct nan_sched_req_handle nan_sched_req_handle_t; - -typedef struct wlc_qos_info wlc_qos_info_t; - -typedef struct wlc_assoc wlc_assoc_t; -typedef struct wlc_roam wlc_roam_t; -typedef struct wlc_pm_st wlc_pm_st_t; -typedef struct wlc_pm_timers wlc_pm_timers_t; -typedef struct wlc_wme wlc_wme_t; - -typedef struct wlc_link_qual wlc_link_qual_t; - -typedef struct wlc_rsdb_info wlc_rsdb_info_t; - -typedef struct wlc_asdb wlc_asdb_t; - -typedef struct rsdb_common_info rsdb_cmn_info_t; -typedef struct rsdb_chan_sw_info rsdb_chan_sw_info_t; - -typedef struct wlc_macdbg_info wlc_macdbg_info_t; -typedef struct wlc_rspec_info wlc_rspec_info_t; -typedef struct wlc_ndis_info wlc_ndis_info_t; - -typedef struct wlc_join_pref wlc_join_pref_t; - -typedef struct wlc_scan_utils wlc_scan_utils_t; -#ifdef ACKSUPR_MAC_FILTER -typedef struct wlc_addrmatch_info wlc_addrmatch_info_t; -#endif /* ACKSUPR_MAC_FILTER */ - -typedef struct cca_ucode_counts cca_ucode_counts_t; -typedef struct cca_chan_qual cca_chan_qual_t; - -typedef struct wlc_perf_utils wlc_perf_utils_t; -typedef struct wlc_test_info wlc_test_info_t; - -typedef struct chanswitch_times chanswitch_times_t; -typedef struct wlc_dump_info wlc_dump_info_t; - -typedef struct wlc_stf wlc_stf_t; -typedef struct wlc_rsdb_policymgr_info wlc_rsdb_policymgr_info_t; - -typedef struct wlc_he_info wlc_he_info_t; -typedef struct wlc_twt_info wlc_twt_info_t; - -/* TWT_STATS */ -typedef wl_twt_peer_stats_v1_t wl_twt_peer_stats_t; -typedef wl_twt_stats_v1_t wl_twt_stats_t; -typedef wl_twt_stats_cmd_v1_t wl_twt_stats_cmd_t; - -typedef struct wlc_heb_info wlc_heb_info_t; - -typedef struct resv_info resv_info_t; - -typedef struct wl_scan_summary wl_scan_summary_t; - -typedef struct wlc_stf_arb wlc_stf_arb_t; - -typedef struct wlc_stf_nss_request_st wlc_stf_nss_request_t; - -typedef struct wlc_stf_nss_request_q_st wlc_stf_nss_request_q_t; - -typedef struct wl_mimo_siso_stats wl_mimo_siso_stats_t; - -typedef struct wlc_mimo_ps_cfg wlc_mimo_ps_cfg_t; - -typedef struct wlc_hw_config wlc_hw_config_t; - -typedef struct wlc_stf_arb_mps_info wlc_stf_arb_mps_info_t; - -typedef struct wlc_tsync wlc_tsync_t; - -typedef struct wlc_fragdur_info wlc_fragdur_info_t; - -typedef struct wlc_mbo_info wlc_mbo_info_t; - -typedef struct wlc_rx_hc wlc_rx_hc_t; - -typedef struct wlc_oce_info wlc_oce_info_t; - -typedef struct wlc_fils_info wlc_fils_info_t; - -typedef struct wlc_sfd_cache wlc_sfd_cache_t; - -typedef struct wlc_ifstats_info wlc_ifstats_info_t; - -typedef struct wlc_mbo_oce_info wlc_mbo_oce_info_t; - -typedef struct wlc_esp_info wlc_esp_info_t; - -/* sta_info_v6 uses rateset_v2 which supported only when RATESET_VERSION_ENABLED */ -#ifdef RATESET_VERSION_ENABLED -typedef sta_info_v6_t sta_info_t; -#else -typedef sta_info_v5_t sta_info_t; -#endif /* RATESET_VERSION_ENABLED */ - -typedef struct wl_roam_prof_band_v3 wl_roam_prof_band_t; -typedef struct wl_roam_prof_v3 wl_roam_prof_t; - -typedef struct wlc_swdiv_stats_v2 wlc_swdiv_stats_t; -typedef struct wl_dfs_ap_move_status_v2 wl_dfs_ap_move_status_t; - -typedef struct wl_utrace_capture_args_v2 wl_utrace_capture_args_t; -typedef struct wl_pmalert_ucode_dbg_v2 wl_pmalert_ucode_dbg_t; - -typedef struct wl_proxd_collect_data_v3 wl_proxd_collect_data_t; -typedef struct wl_proxd_collect_event_data_v3 wl_proxd_collect_event_data_t; - -typedef struct wlc_leakyapstats_info_v1 wlc_leakyapstats_info_t; - -typedef struct wlc_chctx_info wlc_chctx_info_t; - -typedef struct wlc_rpsnoa_info wlc_rpsnoa_info_t; - -/* Inteface version mapping for versioned pfn structures */ -#undef PFN_SCANRESULT_VERSION -#define PFN_SCANRESULT_VERSION PFN_SCANRESULT_VERSION_V2 -#define PFN_SCANRESULTS_VERSION PFN_SCANRESULTS_VERSION_V2 -#define PFN_LBEST_SCAN_RESULT_VERSION PFN_LBEST_SCAN_RESULT_VERSION_V2 -typedef wl_pfn_subnet_info_v2_t wl_pfn_subnet_info_t; -typedef wl_pfn_net_info_v2_t wl_pfn_net_info_t; -typedef wl_pfn_lnet_info_v2_t wl_pfn_lnet_info_t; -typedef wl_pfn_lscanresults_v2_t wl_pfn_lscanresults_t; -typedef wl_pfn_scanresults_v2_t wl_pfn_scanresults_t; -typedef wl_pfn_scanresult_v2_1_t wl_pfn_scanresult_t; - -/* XXX: 13_10 uses interface_create_v3 */ -#define WL_INTERFACE_CREATE_VER WL_INTERFACE_CREATE_VER_3 -typedef wl_interface_create_v3_t wl_interface_create_t; - -#define WL_INTERFACE_INFO_VER WL_INTERFACE_INFO_VER_2 -typedef wl_interface_info_v2_t wl_interface_info_t; - -#define WL_PKTENG_RU_FILL_CURRENT_VER WL_PKTENG_RU_FILL_VER_2 - -#ifdef WLAWDL -typedef awdl_stats_core_v3_t awdl_stats_core_t; -typedef awdl_stats_cmn_v3_t awdl_stats_cmn_t; -typedef awdl_stats_v3_t awdl_stats_t; -#endif -typedef struct wlc_hwa_info wlc_hwa_info_t; -#define UCM_PROFILE_VERSION UCM_PROFILE_VERSION_1 -typedef wlc_btcx_profile_v1_t wlc_btcx_profile_t; - -#ifndef WL_BTCXSTATS -#define BTCX_STATS_VER BTCX_STATS_VER_3 -typedef wlc_btc_stats_v3_t wlc_btc_stats_t; -#else -#define BTCX_STATS_VER BTCX_STATS_VER_4 -typedef wlc_btc_stats_v4_t wlc_btc_stats_t; -#endif - -#define WL_BTC_WIFI_PROT_VER WL_BTC_WIFI_PROT_VER_1 -typedef wl_btc_wifi_prot_v1_t wl_btc_wifi_prot_t; - -/* TXQ MUX Broadcast/Multicast module and cubby structure definition */ -typedef struct wlc_bcmcq_info wlc_bcmcq_info_t; -typedef struct bcmc_cubby bcmc_cubby_t; - -typedef struct wlc_ratelinkmem_info wlc_ratelinkmem_info_t; - -typedef wl_proxd_params_tof_tune_v3_t wl_proxd_params_tof_tune_t; - -/* ranging context */ -typedef struct wlc_ftm_ranging_ctx wlc_ftm_ranging_ctx_t; - -#define ETD_DATA_VERSION ETD_DATA_VERSION_V1 -typedef etd_data_v1_t etd_data_t; -typedef etd_tag_data_v1_t etd_tag_data_t; -typedef join_classification_info_v1_t join_classification_info_t; -typedef join_target_classification_info_v1_t join_target_classification_info_t; -typedef join_assoc_state_v1_t join_assoc_state_t; -typedef join_channel_v1_t join_channel_t; -typedef join_total_attempts_num_v1_t join_total_attempts_num_t; - -typedef rmc_bss_info_v1_t rmc_bss_info_t; -typedef rmc_candidate_info_v1_t rmc_candidate_info_t; - -typedef struct wlc_adps_info wlc_adps_info_t; -typedef event_ecounters_config_request_v2_t ecounters_event_based_config_t; - -#define WL_BAM_CMD_ENABLE WL_BAM_CMD_ENABLE_V1 -#define WL_BAM_CMD_DISABLE WL_BAM_CMD_DISABLE_V1 -#define WL_BAM_CMD_CONFIG WL_BAM_CMD_CONFIG_V1 -#define WL_BAM_CMD_DUMP WL_BAM_CMD_DUMP_V1 -typedef struct wlc_bam_info wlc_bam_info_t; -typedef struct wl_bam_iov_enable_v1 wl_bam_iov_enable_type; -typedef struct wl_bam_iov_enable_v1 wl_bam_iov_disable_type; -typedef struct wl_bam_iov_config_v1 wl_bam_iov_config_type; -typedef struct wl_bam_iov_dump_v1 wl_bam_iov_dump_type; -typedef struct wl_bam_iov_bcn_config_v1 wl_bam_iov_bcn_config_type; -typedef struct wl_bam_iov_dump_bcn_elem_v1 wl_bam_iov_dump_bcn_elem_type; - -typedef struct chanswitch_hist_info wl_chsw_hist_info_t; -typedef struct wlc_tdm_tx_info wlc_tdm_tx_info_t; -#ifdef WL_TDMTX_TYPEDEF_HAS_ALIAS -typedef tdmtx_cnt_v2_t tdmtx_cnt_t; -typedef tdmtx_cnt_shm_v2_t tdmtx_cnt_shm_t; -typedef wl_tdmtx_ecounters_v2_t wl_tdmtx_ecounters_t; -#define WL_CNT_TDMTX_STRUCT_SZ (sizeof(tdmtx_cnt_t)) -#define WL_CNT_TDMTX_SHM_SZ (sizeof(tdmtx_cnt_shm_t)) -#endif -typedef struct wlc_tvpm_info wlc_tvpm_info_t; - -#define WL_HEB_CURRENT_VER WL_HEB_VER_1 - -typedef wl_heb_cnt_v1_t wl_heb_cnt_t; -typedef wl_config_heb_fill_v1_t wl_config_heb_fill_t; -typedef wl_heb_blk_params_v1_t wl_heb_blk_params_t; -typedef wl_heb_reg_status_v1_t wl_heb_reg_status_t; -typedef wl_heb_status_v1_t wl_heb_status_t; -typedef wl_heb_int_cnt_v1_t wl_heb_int_cnt_t; - -typedef struct wl_proxd_rtt_sample_v2 wl_proxd_rtt_sample_t; -typedef struct wl_proxd_rtt_result_v2 wl_proxd_rtt_result_t; - -#ifdef RATESET_VERSION_ENABLED -/* all rateset_args structures and version updates will come here */ -#define RATESET_ARGS_VERSION (RATESET_ARGS_V2) -typedef wl_rateset_args_v2_t wl_rateset_args_t; -#endif /* RATESET_VERSION_ENABLED */ - -#ifdef WL_PKTENG_STATS_TYPEDEF_HAS_ALIAS -typedef wl_pkteng_stats_v2_t wl_pkteng_stats_t; -#endif /* WL_PKTENG_STATS_TYPEDEF_HAS_ALIAS */ - -#ifdef WL_BSS_INFO_TYPEDEF_HAS_ALIAS -typedef wl_bss_info_v109_2_t wl_bss_info_t; - -typedef wl_gscan_bss_info_v3_t wl_gscan_bss_info_t; -#define WL_GSCAN_INFO_FIXED_FIELD_SIZE (OFFSETOF(wl_gscan_bss_info_t, info)) - -typedef wl_scan_results_v2_t wl_scan_results_t; -/** size of wl_scan_results not including variable length array */ -#define WL_SCAN_RESULTS_FIXED_SIZE (OFFSETOF(wl_scan_results_t, bss_info)) - -typedef wl_escan_result_v2_t wl_escan_result_t; -#define WL_ESCAN_RESULTS_FIXED_SIZE (OFFSETOF(wl_escan_result_t, bss_info)) - -typedef wl_iscan_results_v2_t wl_iscan_results_t; -/** size of wl_iscan_results not including variable length array */ -#define WL_ISCAN_RESULTS_FIXED_SIZE \ - (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results)) - -typedef wl_gscan_result_v2_1_t wl_gscan_result_t; -#define WL_GSCAN_RESULTS_FIXED_SIZE (OFFSETOF(wl_gscan_result_t, bss_info)) -#endif /* WL_BSS_INFO_TYPEDEF_HAS_ALIAS */ - -#define WLC_ALLOCMEM_POSTREV80 - -typedef uint8 wlc_mbsp_sel_t; -typedef uint8 dot11_mbsp_sel_t; - -#ifdef WL_PKTENG_RU_VER -typedef wl_pkteng_ru_v2_t wl_pkteng_ru_fill_t; -#endif - -typedef wl_msglevel_v1_t wl_msglevel_t; -#define WL_MSGLEVEL_STRUCT_VERSION WL_MSGLEVEL_STRUCT_VERSION_1 - -typedef struct wlc_tpa_info wlc_tpa_info_t; - -typedef struct wl_event_mbo wl_event_mbo_t; -typedef struct wl_event_mbo_cell_nw_switch wl_event_mbo_cell_nw_switch_t; -typedef struct wbrq_process_data wbrq_process_data_t; -typedef struct wbrq_process_res wbrq_process_res_t; -typedef struct wlc_lphs_info wlc_lphs_info_t; - -typedef struct wlc_obj_registry wlc_obj_registry_t; - -#ifdef WL_EVENT_RX_FRAME_DATA_ALIAS -#define BCM_RX_FRAME_DATA_VERSION BCM_RX_FRAME_DATA_VERSION_2 -typedef wl_event_rx_frame_data_v2_t wl_event_rx_frame_data_t; -#endif - -#ifdef ECOUNTERS_COMPACT -typedef wl_periodic_compact_cntrs_v3_t wl_periodic_compact_cntrs_t; -typedef wl_periodic_txbf_cntrs_v1_t wl_periodic_txbf_cntrs_t; -typedef wl_event_based_statistics_v3_t wl_event_based_statistics_t; -#endif /* ECOUNTERS_COMPACT */ - -typedef struct wlc_sae_cubby wlc_sae_cubby_t; -typedef struct wlc_sae_info wlc_sae_info_t; - -typedef struct wlc_owe_info wlc_owe_info_t; - -#ifdef PMKID_VERSION_ENABLED -#define PMKID_VERSION (PMKID_LIST_VER_3) -typedef pmkid_v3_t pmkid_t; -typedef pmkid_list_v3_t pmkid_list_t; -#endif /* PMKID_VERSION_ENABLED */ - -typedef struct wlc_txdc_info wlc_txdc_info_t; -/* PHY health check */ -typedef wl_hc_desense_stats_v1_t wl_hc_desense_stats_t; -typedef wl_hc_temp_stats_v2_t wl_hc_temp_stats_t; -typedef wl_hc_vcocal_stats_v1_t wl_hc_vcocal_stats_t; -typedef wl_hc_txpwr_stats_v2_t wl_hc_txpwr_stats_t; - -typedef wl_scb_ecounters_v2_t wl_scb_ecounters_t; -typedef wl_nan_slot_ecounters_v1_t wl_nan_slot_ecounters_t; -typedef wlc_scb_stats_v1_t wlc_scb_stats_t; - -typedef struct wlc_hw_cmn_info wlc_hw_cmn_info_t; -typedef struct wlc_hw_tunables wlc_hw_tunables_t; - -typedef struct wlc_rxsig_info wlc_rxsig_info_t; -typedef struct wlc_rxsig_hw_info wlc_rxsig_hw_info_t; - -typedef struct wlc_hw_macint_regs wlc_hw_macint_regs_t; - -#ifdef WL_SAE -typedef struct wlc_sae_info wlc_sae_info_t; -#endif -#if defined(BCM_EWP) || defined (BCM_SDC) -typedef wl_hist_compact_toss_stats_v2_t wl_hist_compact_toss_stats_t; -#endif /* BCM_EWP */ -typedef struct wlc_ewp_info wlc_ewp_info_t; -typedef struct wlc_ewp_htr_db wlc_ewp_htr_db_t; - -typedef struct wl_sc_info wl_sc_info_t; - -typedef struct wlc_swdiv_hw_info wlc_swdiv_hw_info_t; -typedef struct wlc_ltecx_hw_info wlc_ltecx_hw_info_t; -typedef struct wlc_stf_hw_info wlc_stf_hw_info_t; - -typedef struct wlc_macdbg_hw_info wlc_macdbg_hw_info_t; -typedef struct wlc_perf_stats wlc_perf_stats_t; - -typedef wl_cnt_ge80mcst_v1_t wl_cnt_ge80mcst_t; -typedef wl_cnt_ge40mcst_v1_t wl_cnt_ge40mcst_t; - -#ifdef HE_COUNTERS_VERSION_ENABLED -#define HE_COUNTERS_VERSION (HE_COUNTERS_V2) -typedef wl_he_cnt_wlc_v2_t wl_he_cnt_wlc_t; -#endif /* HE_COUNTERS_VERSION_ENABLED */ -typedef wl_compact_he_cnt_wlc_v2_t wl_compact_he_cnt_wlc_t; - -typedef struct wlc_cm_info wlc_cm_info_t; -typedef struct wlc_cm_data wlc_cm_data_t; - -typedef struct wlc_calload_info wlc_calload_info_t; -typedef struct wlc_reinit_st wlc_reinit_st_t; -typedef wl_prio_roam_prof_v1_t wl_prio_roam_prof_t; - -#ifdef WL_ANQPO_PEER_LIST_TYPEDEF_HAS_ALIAS -#define WL_ANQPO_PEER_LIST_VERSION WL_ANQPO_PEER_LIST_VERSION_2 -typedef wl_anqpo_peer_list_v2_t wl_anqpo_peer_list_t; -typedef wl_anqpo_peer_v2_t wl_anqpo_peer_t; -#endif /* WL_ANQPO_PEER_LIST_VERSION */ - -typedef roamstats_counter_info_v1_t roamstats_counter_info_t; -typedef roamstats_prev_roam_events_v1_t roamstats_prev_roam_events_t; -typedef roamstats_reason_info_v1_t roamstats_reason_info_t; -#undef SSSR_REG_INFO_VER -#define SSSR_REG_INFO_VER SSSR_REG_INFO_VER_2 - -typedef struct tdls_bss_info tdls_bss_info_t; -typedef wl_bsstrans_rssi_rate_map_v2_t wl_bsstrans_rssi_rate_map_ext_t; - -#ifdef ETD -#define MAX_DMAFIFO_DESC_ENTRIES MAX_DMAFIFO_DESC_ENTRIES_V1 -#define MAX_DMAFIFO_ENTRIES MAX_DMAFIFO_ENTRIES_V1 -typedef struct hnd_ext_trap_desc_entry_v1 dma_dentry_t; -typedef struct hnd_ext_trap_dma_fifo_v1 dma_fifo_t; -typedef struct hnd_ext_trap_axi_error_v1 hnd_ext_trap_axi_error_t; -#else -typedef void hnd_ext_trap_axi_error_t; -#endif /* ETD */ - -typedef struct wl_btm_event_type_data wl_btm_event_type_data_t; -typedef struct wl_bssid_prune_evt_info wl_bssid_pruned_evt_info_t; - -#ifdef ETD -typedef struct hnd_ext_trap_phydbg_v3 hnd_etd_phydbg_t; -typedef struct hnd_ext_trap_wlc_mem_err_v3 hnd_ext_trap_wlc_mem_err_info_t; -#define HND_EXT_TRAP_WLC_MEM_ERR_VER HND_EXT_TRAP_WLC_MEM_ERR_VER_V3 -#endif -typedef key_update_info_v1_t key_update_info_t; -typedef wl_omi_req_v1_t wl_omi_req_t; -typedef wl_omi_status_v1_t wl_omi_status_t; -#define WL_OMI_STATUS_VERSION WL_OMI_STATUS_VERSION_1 -#define WL_OMI_CONFIG_VERSION WL_OMI_CONFIG_VERSION_1 - -#endif /* _wlc_types_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wldev_common.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wldev_common.c old mode 100755 new mode 100644 index 9cf13d2f0f62..5da6be126460 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wldev_common.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wldev_common.c @@ -1,7 +1,7 @@ /* * Common function shared by Linux WEXT, cfg80211 and p2p drivers * - * Copyright (C) 2020, Broadcom. + * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -31,6 +32,8 @@ #ifdef WL_CFG80211 #include #include +#else +#define WL_DBG_PRINT_SYSTEM_TIME #endif /* WL_CFG80211 */ #include @@ -101,14 +104,13 @@ s32 wldev_ioctl( strlcpy(ifr.ifr_name, dev->name, sizeof(ifr.ifr_name)); ifr.ifr_data = (caddr_t)&ioc; - fs = get_fs(); - set_fs(get_ds()); + GETFS_AND_SETFS_TO_KERNEL_DS(fs); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); #else ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - set_fs(fs); + SETFS(fs); ret = 0; #endif /* defined(BCMDONGLEHOST) */ @@ -359,6 +361,76 @@ s32 wldev_iovar_getint_bsscfg( return err; } +#if defined(BCMDONGLEHOST) && defined(WL_CFG80211) +s32 wldev_iovar_setint_no_wl(struct net_device *dev, s8 *iovar, s32 val) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + s32 ifidx = dhd_net2idx(dhd->info, dev); + + if (ifidx == DHD_BAD_IF) { + WLDEV_ERROR(("wldev_iovar_setint_no_wl: bad ifidx for ndev:%s\n", dev->name)); + return BCME_ERROR; + } + + val = htod32(val); + return dhd_iovar(dhd, ifidx, iovar, + (char *)&val, sizeof(val), NULL, 0, TRUE); +} + +s32 wldev_iovar_getint_no_wl(struct net_device *dev, s8 *iovar, s32 *val) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + s32 ifidx = dhd_net2idx(dhd->info, dev); + u8 iovar_buf[WLC_IOCTL_SMLEN]; + s32 err; + + if (ifidx == DHD_BAD_IF) { + WLDEV_ERROR(("wldev_iovar_getint_no_wl: bad ifidx for ndev:%s\n", dev->name)); + return BCME_ERROR; + } + + val = htod32(val); + bzero(iovar_buf, sizeof(iovar_buf)); + err = dhd_iovar(dhd, ifidx, iovar, (char *)val, sizeof(*val), + iovar_buf, sizeof(iovar_buf), FALSE); + if (err == BCME_OK) { + (void)memcpy_s(val, sizeof(*val), iovar_buf, sizeof(*val)); + *val = dtoh32(*val); + } + return err; +} + +s32 wldev_iovar_no_wl(struct net_device *dev, s8 *iovar, + s8 *param_buf, uint param_len, s8 *res_buf, u32 res_len, bool set) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + s32 ifidx = dhd_net2idx(dhd->info, dev); + + if (ifidx == DHD_BAD_IF) { + WLDEV_ERROR(("wldev_iovar_no_wl: bad ifidx for ndev:%s\n", dev->name)); + return BCME_ERROR; + } + + return dhd_iovar(dhd, ifidx, iovar, param_buf, param_len, res_buf, res_len, set); +} + +s32 wldev_ioctl_no_wl(struct net_device *dev, u32 cmd, s8 *buf, u32 len, bool set) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + s32 ifidx = dhd_net2idx(dhd->info, dev); + + if (ifidx == DHD_BAD_IF) { + WLDEV_ERROR(("wldev_ioctl_no_wl: bad ifidx for ndev:%s\n", dev->name)); + return BCME_ERROR; + } + return dhd_wl_ioctl_cmd(dhd, cmd, buf, len, set, ifidx); +} +#endif /* BCMDONGLEHOST && WL_CFG80211 */ + int wldev_get_link_speed( struct net_device *dev, int *plink_speed) { @@ -428,6 +500,7 @@ int wldev_set_band( } return error; } + int wldev_get_datarate(struct net_device *dev, int *datarate) { int error = 0; @@ -453,7 +526,7 @@ int wldev_get_mode( int chanspec = 0; uint16 band = 0; uint16 bandwidth = 0; - wl_bss_info_t *bss = NULL; + wl_bss_info_v109_t *bss = NULL; char* buf = NULL; buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); @@ -470,7 +543,7 @@ int wldev_get_mode( buf = NULL; return error; } - bss = (wl_bss_info_t*)(buf + 4); + bss = (wl_bss_info_v109_t*)(buf + 4); chanspec = wl_chspec_driver_to_host(bss->chanspec); band = chanspec & WL_CHANSPEC_BAND_MASK; @@ -508,30 +581,16 @@ int wldev_get_mode( int wldev_set_country( struct net_device *dev, char *country_code, bool notify, int revinfo) { + int error = 0; #if defined(BCMDONGLEHOST) - int error = -1; - wl_country_t cspec = {{0}, 0, {0}}; + struct dhd_pub *dhd = dhd_get_pub(dev); if (!country_code) - return error; - - cspec.rev = revinfo; - strlcpy(cspec.country_abbrev, country_code, WL_CCODE_LEN + 1); - strlcpy(cspec.ccode, country_code, WL_CCODE_LEN + 1); - error = dhd_conf_map_country_list(dhd_get_pub(dev), &cspec); - if (error) - dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec); - error = dhd_conf_set_country(dhd_get_pub(dev), &cspec); - if (error < 0) { - WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n", - __FUNCTION__, country_code, cspec.ccode, cspec.rev)); - return error; - } - dhd_conf_fix_country(dhd_get_pub(dev)); - dhd_conf_get_country(dhd_get_pub(dev), &cspec); - dhd_bus_country_set(dev, &cspec, notify); + return -1; + error = dhd_conf_country(dhd, "country", country_code); + dhd_bus_country_set(dev, &dhd->dhd_cspec, notify); printf("%s: set country for %s as %s rev %d\n", - __FUNCTION__, country_code, cspec.ccode, cspec.rev); + __FUNCTION__, country_code, dhd->dhd_cspec.ccode, dhd->dhd_cspec.rev); #endif /* defined(BCMDONGLEHOST) */ - return 0; + return error; }